Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

675 lines
16 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. SrvInfo.c
  5. Abstract:
  6. This module contains support for the server get and set info APIs
  7. in the server service.
  8. Author:
  9. David Treadwell (davidtr) 7-Mar-1991
  10. Revision History:
  11. --*/
  12. #include "srvsvcp.h"
  13. #include "ssreg.h"
  14. #include <netlibnt.h>
  15. #include <tstr.h>
  16. #include <lmerr.h>
  17. NET_API_STATUS NET_API_FUNCTION
  18. NetrServerGetInfo (
  19. IN LPWSTR ServerName,
  20. IN DWORD Level,
  21. OUT LPSERVER_INFO InfoStruct
  22. )
  23. /*++
  24. Routine Description:
  25. This routine uses the server parameters stored in the server service
  26. to return the server information.
  27. Arguments:
  28. None.
  29. Return Value:
  30. NET_API_STATUS - NO_ERROR or reason for failure.
  31. --*/
  32. {
  33. ULONG outputBufferLength;
  34. NET_API_STATUS error;
  35. ACCESS_MASK desiredAccess;
  36. LPWSTR DomainName;
  37. PNAME_LIST_ENTRY service;
  38. PTRANSPORT_LIST_ENTRY transport;
  39. UCHAR serverNameBuf[ MAX_PATH ];
  40. UNICODE_STRING ServerNameUnicode;
  41. NTSTATUS status;
  42. ULONG namelen;
  43. //
  44. // Determine the access required for the requested level of
  45. // information.
  46. //
  47. switch ( Level ) {
  48. case 100:
  49. case 101:
  50. desiredAccess = SRVSVC_CONFIG_USER_INFO_GET;
  51. break;
  52. case 102:
  53. case 502:
  54. desiredAccess = SRVSVC_CONFIG_POWER_INFO_GET;
  55. break;
  56. case 503:
  57. desiredAccess = SRVSVC_CONFIG_ADMIN_INFO_GET;
  58. break;
  59. default:
  60. return ERROR_INVALID_LEVEL;
  61. }
  62. //
  63. // Make sure that the caller has that level of access.
  64. //
  65. error = SsCheckAccess(
  66. &SsConfigInfoSecurityObject,
  67. desiredAccess
  68. );
  69. if ( error != NO_ERROR ) {
  70. return ERROR_ACCESS_DENIED;
  71. }
  72. //
  73. // Acquire the resource that protects server information. Since
  74. // we'll only read the information, get shared access to the
  75. // resource.
  76. //
  77. (VOID)RtlAcquireResourceShared( &SsData.SsServerInfoResource, TRUE );
  78. if( ServerName == NULL ) {
  79. ServerName = SsData.ServerNameBuffer;
  80. }
  81. //
  82. // Convert the server name
  83. //
  84. if( ServerName[0] == L'\\' && ServerName[1] == L'\\' ) {
  85. ServerName += 2;
  86. }
  87. RtlInitUnicodeString( &ServerNameUnicode, ServerName );
  88. error = ConvertStringToTransportAddress( &ServerNameUnicode, serverNameBuf, &namelen );
  89. if( error != NERR_Success ) {
  90. RtlReleaseResource( &SsData.SsServerInfoResource );
  91. return error;
  92. }
  93. //
  94. // Look for the NAME_LIST_ENTRY entry that represents the name of the server
  95. // the client referred to.
  96. //
  97. DomainName = SsData.DomainNameBuffer;
  98. for( service = SsData.SsServerNameList; service != NULL; service = service->Next ) {
  99. if( service->TransportAddressLength != namelen ) {
  100. continue;
  101. }
  102. if( RtlEqualMemory( serverNameBuf, service->TransportAddress, namelen ) ) {
  103. DomainName = service->DomainName;
  104. break;
  105. }
  106. }
  107. //
  108. // If we didn't find an entry, find and use the primary entry
  109. //
  110. if( service == NULL ) {
  111. for( service = SsData.SsServerNameList; service != NULL; service = service->Next ) {
  112. if( service->PrimaryName ) {
  113. DomainName = service->DomainName;
  114. break;
  115. }
  116. }
  117. }
  118. //
  119. // Use the level parameter to determine how much space to allocate
  120. // and how to fill it in.
  121. //
  122. switch ( Level ) {
  123. case 100: {
  124. PSERVER_INFO_100 sv100;
  125. //
  126. // All we copy is the server name.
  127. //
  128. outputBufferLength = sizeof(SERVER_INFO_100) +
  129. STRSIZE( ServerName);
  130. sv100 = MIDL_user_allocate( outputBufferLength );
  131. if ( sv100 == NULL ) {
  132. RtlReleaseResource( &SsData.SsServerInfoResource );
  133. return ERROR_NOT_ENOUGH_MEMORY;
  134. }
  135. //
  136. // Copy over the fixed portion of the buffer.
  137. //
  138. RtlCopyMemory( sv100, &SsData.ServerInfo102, sizeof(SERVER_INFO_100) );
  139. //
  140. // Set up the name string.
  141. //
  142. sv100->sv100_name = (LPWSTR)( sv100 + 1 );
  143. STRCPY( sv100->sv100_name, ServerName );
  144. //
  145. // Set up the output buffer pointer.
  146. //
  147. InfoStruct->ServerInfo100 = sv100;
  148. break;
  149. }
  150. case 101: {
  151. PSERVER_INFO_101 sv101;
  152. //
  153. // All we copy is the server name.
  154. //
  155. outputBufferLength = sizeof(SERVER_INFO_101) +
  156. STRSIZE( ServerName ) +
  157. STRSIZE( SsData.ServerCommentBuffer ) ;
  158. sv101 = MIDL_user_allocate( outputBufferLength );
  159. if ( sv101 == NULL ) {
  160. RtlReleaseResource( &SsData.SsServerInfoResource );
  161. return ERROR_NOT_ENOUGH_MEMORY;
  162. }
  163. //
  164. // Copy over the fixed portion of the buffer.
  165. //
  166. RtlCopyMemory( sv101, &SsData.ServerInfo102, sizeof(SERVER_INFO_101) );
  167. if( service != NULL ) {
  168. sv101->sv101_type = service->ServiceBits;
  169. for( transport = service->Transports; transport; transport = transport->Next ) {
  170. sv101->sv101_type |= transport->ServiceBits;
  171. }
  172. } else {
  173. //
  174. // If there are no transports,
  175. // return the global information.
  176. //
  177. sv101->sv101_type = SsGetServerType();
  178. }
  179. //
  180. // Set up the variable portion of the buffer.
  181. //
  182. sv101->sv101_name = (LPWSTR)( sv101 + 1 );
  183. STRCPY( sv101->sv101_name, ServerName );
  184. sv101->sv101_comment = (LPWSTR)( (PCHAR)sv101->sv101_name +
  185. STRSIZE( ServerName ));
  186. STRCPY( sv101->sv101_comment, SsData.ServerCommentBuffer );
  187. //
  188. // Set up the output buffer pointer.
  189. //
  190. InfoStruct->ServerInfo101 = sv101;
  191. break;
  192. }
  193. case 102: {
  194. PSERVER_INFO_102 sv102;
  195. //
  196. // We copy the server name, server comment, and user path
  197. // buffer.
  198. //
  199. outputBufferLength = sizeof(SERVER_INFO_102) +
  200. STRSIZE( ServerName ) +
  201. STRSIZE( SsData.ServerCommentBuffer ) +
  202. STRSIZE( SsData.UserPathBuffer ) ;
  203. sv102 = MIDL_user_allocate( outputBufferLength );
  204. if ( sv102 == NULL ) {
  205. RtlReleaseResource( &SsData.SsServerInfoResource );
  206. return ERROR_NOT_ENOUGH_MEMORY;
  207. }
  208. //
  209. // Copy over the fixed portion of the buffer.
  210. //
  211. RtlCopyMemory( sv102, &SsData.ServerInfo102, sizeof(SERVER_INFO_102) );
  212. if( service != NULL ) {
  213. sv102->sv102_type = service->ServiceBits;
  214. for( transport = service->Transports; transport; transport = transport->Next ) {
  215. sv102->sv102_type |= transport->ServiceBits;
  216. }
  217. } else {
  218. //
  219. // If there are no transports,
  220. // return the global information.
  221. //
  222. sv102->sv102_type = SsGetServerType();
  223. }
  224. //
  225. // Set up the server name.
  226. //
  227. sv102->sv102_name = (LPWSTR)( sv102 + 1 );
  228. STRCPY( sv102->sv102_name, ServerName );
  229. //
  230. // Set up the server comment.
  231. //
  232. sv102->sv102_comment = (LPWSTR)( (PCHAR)sv102->sv102_name + STRSIZE( ServerName ));
  233. STRCPY( sv102->sv102_comment, SsData.ServerCommentBuffer );
  234. //
  235. // Set up the user path.
  236. //
  237. sv102->sv102_userpath = (LPWSTR)( (PCHAR)sv102->sv102_comment +
  238. STRSIZE( sv102->sv102_comment ) );
  239. STRCPY( sv102->sv102_userpath, SsData.UserPathBuffer );
  240. //
  241. // Set up the output buffer pointer.
  242. //
  243. InfoStruct->ServerInfo102 = sv102;
  244. break;
  245. }
  246. case 502:
  247. //
  248. // Allocate enough space to hold the fixed structure. This level has
  249. // no variable structure.
  250. //
  251. InfoStruct->ServerInfo502 = MIDL_user_allocate( sizeof(SERVER_INFO_502) );
  252. if ( InfoStruct->ServerInfo502 == NULL ) {
  253. RtlReleaseResource( &SsData.SsServerInfoResource );
  254. return ERROR_NOT_ENOUGH_MEMORY;
  255. }
  256. //
  257. // Copy the data from the server service buffer to the user buffer.
  258. //
  259. RtlCopyMemory(
  260. InfoStruct->ServerInfo502,
  261. &SsData.ServerInfo599,
  262. sizeof(SERVER_INFO_502)
  263. );
  264. break;
  265. case 503: {
  266. PSERVER_INFO_503 sv503;
  267. outputBufferLength = sizeof( *sv503 ) + STRSIZE( DomainName );
  268. sv503 = MIDL_user_allocate( outputBufferLength );
  269. if ( sv503 == NULL ) {
  270. RtlReleaseResource( &SsData.SsServerInfoResource );
  271. return ERROR_NOT_ENOUGH_MEMORY;
  272. }
  273. //
  274. // Copy the data from the server service buffer to the user buffer.
  275. //
  276. RtlCopyMemory( sv503, &SsData.ServerInfo599, sizeof( *sv503 ) );
  277. //
  278. // Copy the domain name
  279. //
  280. sv503->sv503_domain = (LPWSTR)( sv503 + 1 );
  281. STRCPY( sv503->sv503_domain, DomainName );
  282. InfoStruct->ServerInfo503 = sv503;
  283. break;
  284. }
  285. default:
  286. RtlReleaseResource( &SsData.SsServerInfoResource );
  287. return ERROR_INVALID_LEVEL;
  288. }
  289. RtlReleaseResource( &SsData.SsServerInfoResource );
  290. return NO_ERROR;
  291. } // NetrServerGetInfo
  292. NET_API_STATUS NET_API_FUNCTION
  293. NetrServerSetInfo (
  294. IN LPWSTR ServerName,
  295. IN DWORD Level,
  296. IN LPSERVER_INFO InfoStruct,
  297. OUT LPDWORD ErrorParameter OPTIONAL
  298. )
  299. /*++
  300. Routine Description:
  301. This routine sets information in the server service and server.
  302. Arguments:
  303. None.
  304. Return Value:
  305. NET_API_STATUS - NO_ERROR or reason for failure.
  306. --*/
  307. {
  308. NET_API_STATUS error;
  309. ULONG i;
  310. LONG parmnum;
  311. BOOLEAN validLevel = FALSE;
  312. PSERVER_REQUEST_PACKET srp;
  313. LPBYTE buffer = (LPBYTE)InfoStruct->ServerInfo100;
  314. BOOLEAN announcementInformationChanged = FALSE;
  315. ServerName;
  316. //
  317. // Check that user input buffer is not NULL
  318. //
  319. if (buffer == NULL) {
  320. if ( ARGUMENT_PRESENT( ErrorParameter ) ) {
  321. *ErrorParameter = PARM_ERROR_UNKNOWN;
  322. }
  323. return ERROR_INVALID_PARAMETER;
  324. }
  325. parmnum = (LONG)(Level - PARMNUM_BASE_INFOLEVEL);
  326. if ( ARGUMENT_PRESENT( ErrorParameter ) ) {
  327. *ErrorParameter = parmnum;
  328. }
  329. //
  330. // Make sure that the caller is allowed to set information in the
  331. // server.
  332. //
  333. error = SsCheckAccess(
  334. &SsConfigInfoSecurityObject,
  335. SRVSVC_CONFIG_INFO_SET
  336. );
  337. if ( error != NO_ERROR ) {
  338. return ERROR_ACCESS_DENIED;
  339. }
  340. //
  341. // Acquire the resource that protects server information. Since
  342. // we're going to be writing to the information, we need exclusive
  343. // access to the reqource.
  344. //
  345. //
  346. // If a parameter number was specified, set that one field.
  347. //
  348. if ( parmnum >= 0 ) {
  349. //
  350. // Walk through the field descriptors looking for an
  351. // equivalent parameter number.
  352. //
  353. for ( i = 0; SsServerInfoFields[i].FieldName != NULL; i++ ) {
  354. if ( (ULONG)parmnum == SsServerInfoFields[i].ParameterNumber ) {
  355. //
  356. // Verify that the field is settable.
  357. //
  358. // !!! We should also reject levels above 502?
  359. //
  360. if ( SsServerInfoFields[i].Settable != ALWAYS_SETTABLE ) {
  361. return ERROR_INVALID_LEVEL;
  362. }
  363. (VOID)RtlAcquireResourceExclusive( &SsData.SsServerInfoResource, TRUE );
  364. //
  365. // Set the field.
  366. //
  367. error = SsSetField(
  368. &SsServerInfoFields[i],
  369. buffer,
  370. TRUE,
  371. &announcementInformationChanged
  372. );
  373. RtlReleaseResource( &SsData.SsServerInfoResource );
  374. //
  375. // If a relevant parameter changed, call
  376. // SsSetExportedServerType. This will cause an
  377. // announcement to be sent.
  378. //
  379. if ( announcementInformationChanged ) {
  380. SsSetExportedServerType( NULL, TRUE, TRUE );
  381. }
  382. return error;
  383. }
  384. }
  385. //
  386. // If a match had been found we would have returned by now.
  387. // Indicate that the parameter number was illegal.
  388. //
  389. return ERROR_INVALID_LEVEL;
  390. }
  391. //
  392. // A full input structure was specified. Walk through all the
  393. // server data field descriptors, looking for fields that should be
  394. // set.
  395. //
  396. for ( i = 0; SsServerInfoFields[i].FieldName != NULL; i++ ) {
  397. ULONG fieldLevel;
  398. //
  399. // We need to set this field if:
  400. //
  401. // o the level specified on input is the same order as the
  402. // level of the field. They have the same order if
  403. // they are in the same century (e.g. 101 and 102 are
  404. // in the same order); AND
  405. //
  406. // o the specified level is greater than or equal to the
  407. // level of the field. For example, if the input
  408. // level is 101 and the field level is 102, don't set
  409. // the field. If the input level is 102 and the field
  410. // level is 101, set it; AND
  411. //
  412. // o the field is settable. If the field is not settable
  413. // by NetServerSetInfo, just ignore the value in the
  414. // input structure.
  415. //
  416. // Note that level 598 doesn't follow the first rule above. It
  417. // is NOT a superset of 50x, and it is NOT a subset of 599.
  418. //
  419. fieldLevel = SsServerInfoFields[i].Level;
  420. if ( Level / 100 == fieldLevel / 100 &&
  421. ((fieldLevel != 598) && (Level >= fieldLevel) ||
  422. (fieldLevel == 598) && (Level == 598)) &&
  423. SsServerInfoFields[i].Settable == ALWAYS_SETTABLE ) {
  424. //
  425. // We found a match, so the specified level number must have
  426. // been valid.
  427. //
  428. // !!! Reject levels above 502?
  429. validLevel = TRUE;
  430. //
  431. // Set this field.
  432. //
  433. (VOID)RtlAcquireResourceExclusive( &SsData.SsServerInfoResource, TRUE );
  434. error = SsSetField(
  435. &SsServerInfoFields[i],
  436. buffer + SsServerInfoFields[i].FieldOffset,
  437. TRUE,
  438. &announcementInformationChanged
  439. );
  440. RtlReleaseResource( &SsData.SsServerInfoResource );
  441. if ( error != NO_ERROR ) {
  442. //
  443. // Set the parameter in error if we need to.
  444. //
  445. if ( ARGUMENT_PRESENT(ErrorParameter) ) {
  446. *ErrorParameter = SsServerInfoFields[i].ParameterNumber;
  447. }
  448. return error;
  449. }
  450. }
  451. }
  452. //
  453. // If no match was ever found, then an invalid level was passed in.
  454. //
  455. if ( !validLevel ) {
  456. return ERROR_INVALID_LEVEL;
  457. }
  458. //
  459. // Get an SRP and set it up with the appropriate level.
  460. //
  461. srp = SsAllocateSrp( );
  462. if ( srp == NULL ) {
  463. return ERROR_NOT_ENOUGH_MEMORY;
  464. }
  465. srp->Level = 0xFFFFFFFF;
  466. (VOID)RtlAcquireResourceShared( &SsData.SsServerInfoResource, TRUE );
  467. //
  468. // Send the request on to the server.
  469. //
  470. error = SsServerFsControl(
  471. FSCTL_SRV_NET_SERVER_SET_INFO,
  472. srp,
  473. &SsData.ServerInfo102,
  474. sizeof(SERVER_INFO_102) + sizeof(SERVER_INFO_599) +
  475. sizeof(SERVER_INFO_598)
  476. );
  477. //
  478. // Release the resource and free the SRP.
  479. //
  480. RtlReleaseResource( &SsData.SsServerInfoResource );
  481. SsFreeSrp( srp );
  482. //
  483. // If a relevant parameter changed, call SsSetExportedServerType.
  484. // This will cause an announcement to be sent.
  485. //
  486. if ( announcementInformationChanged ) {
  487. SsSetExportedServerType( NULL, TRUE, TRUE );
  488. }
  489. return error;
  490. } // NetrServerSetInfo