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.

1183 lines
27 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. uasp.c
  5. Abstract:
  6. Private functions shared by the UAS API routines.
  7. Author:
  8. Cliff Van Dyke (cliffv) 20-Feb-1991
  9. Environment:
  10. User mode only.
  11. Contains NT-specific code.
  12. Requires ANSI C extensions: slash-slash comments, long external names.
  13. Revision History:
  14. 17-Apr-1991 (cliffv)
  15. Incorporated review comments.
  16. --*/
  17. #include <nt.h>
  18. #include <ntrtl.h>
  19. #include <nturtl.h>
  20. #undef DOMAIN_ALL_ACCESS // defined in both ntsam.h and ntwinapi.h
  21. #include <ntsam.h>
  22. #include <ntlsa.h>
  23. #include <windef.h>
  24. #include <winbase.h>
  25. #include <lmcons.h>
  26. #include <accessp.h>
  27. #include <dsgetdc.h>
  28. #include <icanon.h>
  29. #include <lmerr.h>
  30. #include <lmwksta.h>
  31. #include <lmaccess.h>
  32. #include <lmapibuf.h>
  33. #include <lmremutl.h> // NetpRemoteComputerSupports(), SUPPORTS_ stuff
  34. #include <lmsvc.h> // SERVICE_WORKSTATION.
  35. #include <names.h>
  36. #include <netdebug.h>
  37. #include <netlib.h>
  38. #include <netlibnt.h>
  39. #include <stddef.h>
  40. #include <stdlib.h>
  41. #include <uasp.h>
  42. #include <tstring.h> // NetAllocWStrFromWStr
  43. SID_IDENTIFIER_AUTHORITY UaspBuiltinAuthority = SECURITY_NT_AUTHORITY;
  44. #ifdef UAS_DEBUG
  45. DWORD UasTrace = 0;
  46. #endif // UAS_DEBUG
  47. NET_API_STATUS
  48. UaspOpenSam(
  49. IN LPCWSTR ServerName OPTIONAL,
  50. IN BOOL AllowNullSession,
  51. OUT PSAM_HANDLE SamServerHandle
  52. )
  53. /*++
  54. Routine Description:
  55. Open a handle to a Sam server.
  56. Arguments:
  57. ServerName - A pointer to a string containing the name of the
  58. Domain Controller (DC) to query. A NULL pointer
  59. or string specifies the local machine.
  60. AllowNullSession - TRUE if we should fall back to the NULL session if
  61. we cannot connect using current credentials
  62. SamServerHandle - Returns the SAM connection handle if the caller wants it.
  63. Close this handle by calling SamCloseHandle
  64. Return Value:
  65. Error code for the operation.
  66. --*/
  67. {
  68. NET_API_STATUS NetStatus;
  69. NTSTATUS Status;
  70. BOOLEAN ImpersonatingAnonymous = FALSE;
  71. HANDLE CurrentToken = NULL;
  72. UNICODE_STRING ServerNameString;
  73. //
  74. // Sanity check the server name
  75. //
  76. if ( ServerName == NULL ) {
  77. ServerName = L"";
  78. }
  79. #ifdef notdef
  80. if ( *ServerName != L'\0' &&
  81. (ServerName[0] != L'\\' || ServerName[1] != L'\\') ) {
  82. return NERR_InvalidComputer;
  83. }
  84. #endif // notdef
  85. //
  86. // Connect to the SAM server
  87. //
  88. RtlInitUnicodeString( &ServerNameString, ServerName );
  89. Status = SamConnect(
  90. &ServerNameString,
  91. SamServerHandle,
  92. SAM_SERVER_LOOKUP_DOMAIN | SAM_SERVER_ENUMERATE_DOMAINS,
  93. NULL);
  94. //
  95. // If the caller would rather use the null session than fail,
  96. // impersonate the anonymous token.
  97. //
  98. if ( AllowNullSession && Status == STATUS_ACCESS_DENIED ) {
  99. *SamServerHandle = NULL;
  100. //
  101. // Check to see if we're already impsonating
  102. //
  103. Status = NtOpenThreadToken(
  104. NtCurrentThread(),
  105. TOKEN_IMPERSONATE,
  106. TRUE, // as self to ensure we never fail
  107. &CurrentToken
  108. );
  109. if ( Status == STATUS_NO_TOKEN ) {
  110. //
  111. // We're not already impersonating
  112. CurrentToken = NULL;
  113. } else if ( !NT_SUCCESS(Status) ) {
  114. IF_DEBUG( UAS_DEBUG_UASP ) {
  115. NetpKdPrint(( "UaspOpenSam: cannot NtOpenThreadToken: 0x%lx\n",
  116. Status ));
  117. }
  118. NetStatus = NetpNtStatusToApiStatus( Status );
  119. goto Cleanup;
  120. }
  121. //
  122. // Impersonate the anonymous token
  123. //
  124. Status = NtImpersonateAnonymousToken( NtCurrentThread() );
  125. if ( !NT_SUCCESS( Status)) {
  126. IF_DEBUG( UAS_DEBUG_UASP ) {
  127. NetpKdPrint(( "UaspOpenSam: cannot NtImpersonateAnonymousToken: 0x%lx\n",
  128. Status ));
  129. }
  130. NetStatus = NetpNtStatusToApiStatus( Status );
  131. goto Cleanup;
  132. }
  133. ImpersonatingAnonymous = TRUE;
  134. //
  135. // Connect again now that we're impersonating anonymous
  136. //
  137. Status = SamConnect(
  138. &ServerNameString,
  139. SamServerHandle,
  140. SAM_SERVER_LOOKUP_DOMAIN | SAM_SERVER_ENUMERATE_DOMAINS,
  141. NULL);
  142. }
  143. if ( !NT_SUCCESS(Status)) {
  144. IF_DEBUG( UAS_DEBUG_UASP ) {
  145. NetpKdPrint(( "UaspOpenSam: Cannot connect to Sam %lX\n",
  146. Status ));
  147. }
  148. *SamServerHandle = NULL;
  149. NetStatus = NetpNtStatusToApiStatus( Status );
  150. goto Cleanup;
  151. }
  152. NetStatus = NERR_Success;
  153. //
  154. // Cleanup locally used resources
  155. //
  156. Cleanup:
  157. if ( ImpersonatingAnonymous ) {
  158. Status = NtSetInformationThread(
  159. NtCurrentThread(),
  160. ThreadImpersonationToken,
  161. &CurrentToken,
  162. sizeof(HANDLE) );
  163. if ( !NT_SUCCESS( Status)) {
  164. IF_DEBUG( UAS_DEBUG_UASP ) {
  165. NetpKdPrint(( "UaspOpenSam: cannot NtSetInformationThread: 0x%lx\n",
  166. Status ));
  167. }
  168. }
  169. }
  170. if ( CurrentToken != NULL ) {
  171. NtClose( CurrentToken );
  172. }
  173. return NetStatus;
  174. }
  175. NET_API_STATUS
  176. UaspGetDomainId(
  177. IN SAM_HANDLE SamServerHandle,
  178. OUT PSID *DomainId
  179. )
  180. /*++
  181. Routine Description:
  182. Return a domain ID of the account domain of a server.
  183. Arguments:
  184. SamServerHandle - A handle to the SAM server to open the domain on
  185. DomainId - Receives a pointer to the domain ID.
  186. Caller must deallocate buffer using NetpMemoryFree.
  187. Return Value:
  188. Error code for the operation.
  189. --*/
  190. {
  191. NET_API_STATUS NetStatus;
  192. NTSTATUS Status;
  193. SAM_ENUMERATE_HANDLE EnumContext;
  194. PSAM_RID_ENUMERATION EnumBuffer = NULL;
  195. DWORD CountReturned = 0;
  196. PSID LocalDomainId = NULL;
  197. DWORD LocalBuiltinDomainSid[sizeof(SID)/sizeof(DWORD) + SID_MAX_SUB_AUTHORITIES ];
  198. BOOL AllDone = FALSE;
  199. ULONG i;
  200. //
  201. // Compute the builtin domain sid.
  202. //
  203. RtlInitializeSid( (PSID) LocalBuiltinDomainSid, &UaspBuiltinAuthority, 1 );
  204. *(RtlSubAuthoritySid( (PSID)LocalBuiltinDomainSid, 0 )) = SECURITY_BUILTIN_DOMAIN_RID;
  205. //
  206. // Loop getting the list of domain ids from SAM
  207. //
  208. EnumContext = 0;
  209. do {
  210. //
  211. // Get several domain names.
  212. //
  213. Status = SamEnumerateDomainsInSamServer(
  214. SamServerHandle,
  215. &EnumContext,
  216. &EnumBuffer,
  217. 8192, // PrefMaxLen
  218. &CountReturned );
  219. if ( !NT_SUCCESS( Status ) ) {
  220. IF_DEBUG( UAS_DEBUG_UASP ) {
  221. NetpKdPrint(( "UaspGetDomainId: Cannot SamEnumerateDomainsInSamServer %lX\n",
  222. Status ));
  223. }
  224. NetStatus = NetpNtStatusToApiStatus( Status );
  225. goto Cleanup;
  226. }
  227. if( Status != STATUS_MORE_ENTRIES ) {
  228. AllDone = TRUE;
  229. }
  230. //
  231. // Lookup the domain ids for the domains
  232. //
  233. for( i = 0; i < CountReturned; i++ ) {
  234. IF_DEBUG( UAS_DEBUG_UASP ) {
  235. NetpKdPrint(( "UaspGetDomainId: %wZ: domain name\n",
  236. &EnumBuffer[i].Name ));
  237. }
  238. //
  239. // Free the sid from the previous iteration.
  240. //
  241. if ( LocalDomainId != NULL ) {
  242. SamFreeMemory( LocalDomainId );
  243. LocalDomainId = NULL;
  244. }
  245. //
  246. // Lookup the domain id
  247. //
  248. Status = SamLookupDomainInSamServer(
  249. SamServerHandle,
  250. &EnumBuffer[i].Name,
  251. &LocalDomainId );
  252. if ( !NT_SUCCESS( Status ) ) {
  253. IF_DEBUG( UAS_DEBUG_UASP ) {
  254. NetpKdPrint(( "UaspGetDomainId: Cannot SamLookupDomainInSamServer %lX\n",
  255. Status ));
  256. }
  257. NetStatus = NetpNtStatusToApiStatus( Status );
  258. goto Cleanup;
  259. }
  260. //
  261. // If this is the builtin domain,
  262. // ignore it.
  263. //
  264. if ( RtlEqualSid( (PSID)LocalBuiltinDomainSid, LocalDomainId ) ) {
  265. continue;
  266. }
  267. //
  268. // Found it.
  269. //
  270. *DomainId = LocalDomainId;
  271. LocalDomainId = NULL;
  272. NetStatus = NO_ERROR;
  273. goto Cleanup;
  274. }
  275. //
  276. // free up current EnumBuffer and get another EnumBuffer.
  277. //
  278. Status = SamFreeMemory( EnumBuffer );
  279. NetpAssert( NT_SUCCESS(Status) );
  280. EnumBuffer = NULL;
  281. } while ( !AllDone );
  282. NetStatus = ERROR_NO_SUCH_DOMAIN;
  283. //
  284. // Cleanup locally used resources
  285. //
  286. Cleanup:
  287. if ( EnumBuffer != NULL ) {
  288. Status = SamFreeMemory( EnumBuffer );
  289. NetpAssert( NT_SUCCESS(Status) );
  290. }
  291. return NetStatus;
  292. } // UaspGetDomainId
  293. NET_API_STATUS
  294. UaspOpenDomain(
  295. IN SAM_HANDLE SamServerHandle,
  296. IN ULONG DesiredAccess,
  297. IN BOOL AccountDomain,
  298. OUT PSAM_HANDLE DomainHandle,
  299. OUT PSID *DomainId OPTIONAL
  300. )
  301. /*++
  302. Routine Description:
  303. Return a domain handle given the server name and the access desired to the domain.
  304. Arguments:
  305. SamServerHandle - A handle to the SAM server to open the domain on
  306. DesiredAccess - Supplies the access mask indicating which access types
  307. are desired to the domain. This routine always requests DOMAIN_LOOKUP
  308. access in addition to those specified.
  309. AccountDomain - TRUE to open the Account domain. FALSE to open the
  310. builtin domain.
  311. DomainHandle - Receives the Domain handle to be used on future calls
  312. to the SAM server.
  313. DomainId - Recieves a pointer to the Sid of the domain. This domain ID
  314. must be freed using NetpMemoryFree.
  315. Return Value:
  316. Error code for the operation. NULL means initialization was successful.
  317. --*/
  318. {
  319. NET_API_STATUS NetStatus;
  320. NTSTATUS Status;
  321. PSID LocalDomainId;
  322. PSID AccountDomainId = NULL;
  323. DWORD LocalBuiltinDomainSid[sizeof(SID)/sizeof(DWORD) + SID_MAX_SUB_AUTHORITIES ];
  324. //
  325. // Give everyone DOMAIN_LOOKUP access.
  326. //
  327. DesiredAccess |= DOMAIN_LOOKUP;
  328. //
  329. // Choose the domain ID for the right SAM domain.
  330. //
  331. if ( AccountDomain ) {
  332. NetStatus = UaspGetDomainId( SamServerHandle, &AccountDomainId );
  333. if ( NetStatus != NO_ERROR ) {
  334. goto Cleanup;
  335. }
  336. LocalDomainId = AccountDomainId;
  337. } else {
  338. RtlInitializeSid( (PSID) LocalBuiltinDomainSid, &UaspBuiltinAuthority, 1 );
  339. *(RtlSubAuthoritySid( (PSID)LocalBuiltinDomainSid, 0 )) = SECURITY_BUILTIN_DOMAIN_RID;
  340. LocalDomainId = (PSID) LocalBuiltinDomainSid;
  341. }
  342. //
  343. // Open the domain.
  344. //
  345. Status = SamOpenDomain( SamServerHandle,
  346. DesiredAccess,
  347. LocalDomainId,
  348. DomainHandle );
  349. if ( !NT_SUCCESS( Status ) ) {
  350. IF_DEBUG( UAS_DEBUG_UASP ) {
  351. NetpKdPrint(( "UaspOpenDomain: Cannot SamOpenDomain %lX\n",
  352. Status ));
  353. }
  354. *DomainHandle = NULL;
  355. NetStatus = NetpNtStatusToApiStatus( Status );
  356. goto Cleanup;
  357. }
  358. //
  359. // Return the DomainId to the caller in an allocated buffer
  360. //
  361. if (ARGUMENT_PRESENT( DomainId ) ) {
  362. //
  363. // If we've already allocated the sid,
  364. // just return it.
  365. //
  366. if ( AccountDomainId != NULL ) {
  367. *DomainId = AccountDomainId;
  368. AccountDomainId = NULL;
  369. //
  370. // Otherwise make a copy.
  371. //
  372. } else {
  373. ULONG SidSize;
  374. SidSize = RtlLengthSid( LocalDomainId );
  375. *DomainId = NetpMemoryAllocate( SidSize );
  376. if ( *DomainId == NULL ) {
  377. (VOID) SamCloseHandle( *DomainHandle );
  378. *DomainHandle = NULL;
  379. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  380. goto Cleanup;
  381. }
  382. if ( !NT_SUCCESS( RtlCopySid( SidSize, *DomainId, LocalDomainId) ) ) {
  383. (VOID) SamCloseHandle( *DomainHandle );
  384. *DomainHandle = NULL;
  385. NetpMemoryFree( *DomainId );
  386. *DomainId = NULL;
  387. NetStatus = NERR_InternalError;
  388. goto Cleanup;
  389. }
  390. }
  391. }
  392. NetStatus = NERR_Success;
  393. Cleanup:
  394. if ( AccountDomainId != NULL ) {
  395. NetpMemoryFree( AccountDomainId );
  396. }
  397. return NetStatus;
  398. }
  399. NET_API_STATUS
  400. UaspOpenDomainWithDomainName(
  401. IN LPCWSTR DomainName,
  402. IN ULONG DesiredAccess,
  403. IN BOOL AccountDomain,
  404. OUT PSAM_HANDLE DomainHandle,
  405. OUT PSID *DomainId OPTIONAL
  406. )
  407. /*++
  408. Routine Description:
  409. Returns the name of a DC in the specified domain. The Server is guaranteed
  410. to be up at the instance of this call.
  411. Arguments:
  412. DoaminName - A pointer to a string containing the name of the remote
  413. domain containing the SAM database. A NULL pointer
  414. or string specifies the local machine.
  415. DesiredAccess - Supplies the access mask indicating which access types
  416. are desired to the domain. This routine always requests DOMAIN_LOOKUP
  417. access in addition to those specified.
  418. AccountDomain - TRUE to open the Account domain. FALSE to open the
  419. builtin domain.
  420. DomainHandle - Receives the Domain handle to be used on future calls
  421. to the SAM server.
  422. DomainId - Recieves a pointer to the Sid of the domain. This domain ID
  423. must be freed using NetpMemoryFree.
  424. Return Value:
  425. NERR_Success - Operation completed successfully
  426. NERR_DCNotFound - DC for the specified domain could not be found.
  427. etc.
  428. --*/
  429. {
  430. NET_API_STATUS NetStatus;
  431. NT_PRODUCT_TYPE NtProductType;
  432. LPWSTR ServerName;
  433. LPWSTR MyDomainName = NULL;
  434. ULONG Flags;
  435. ULONG i;
  436. PDOMAIN_CONTROLLER_INFOW DcInfo = NULL;
  437. SAM_HANDLE SamServerHandle = NULL;
  438. //
  439. // Check to see if the domain specified refers to this machine.
  440. //
  441. if ( DomainName == NULL || *DomainName == L'\0' ) {
  442. //
  443. // Connect to the SAM server
  444. //
  445. NetStatus = UaspOpenSam( NULL,
  446. FALSE, // Don't try null session
  447. &SamServerHandle );
  448. if ( NetStatus != NERR_Success ) {
  449. IF_DEBUG( UAS_DEBUG_UASP ) {
  450. NetpKdPrint(( "UaspOpenDomainWithDomainName: Cannot UaspOpenSam %ld\n", NetStatus ));
  451. }
  452. }
  453. goto Cleanup;
  454. }
  455. //
  456. // Validate the DomainName
  457. //
  458. if ( !NetpIsDomainNameValid( (LPWSTR)DomainName) ) {
  459. NetStatus = NERR_DCNotFound;
  460. IF_DEBUG( UAS_DEBUG_UASP ) {
  461. NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws: Cannot SamOpenDomain %ld\n",
  462. DomainName,
  463. NetStatus ));
  464. }
  465. goto Cleanup;
  466. }
  467. //
  468. // Grab the product type once.
  469. //
  470. if ( !RtlGetNtProductType( &NtProductType ) ) {
  471. NtProductType = NtProductWinNt;
  472. }
  473. //
  474. // If this machine is a DC, this machine is refered to by domain name.
  475. //
  476. if ( NtProductType == NtProductLanManNt ) {
  477. NetStatus = NetpGetDomainName( &MyDomainName );
  478. if ( NetStatus != NERR_Success ) {
  479. IF_DEBUG( UAS_DEBUG_UASP ) {
  480. NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws: Cannot NetpGetDomainName %ld\n",
  481. DomainName,
  482. NetStatus ));
  483. }
  484. goto Cleanup;
  485. }
  486. //
  487. // If this machine is not a DC, this machine is refered to by computer name.
  488. //
  489. } else {
  490. NetStatus = NetpGetComputerName( &MyDomainName );
  491. if ( NetStatus != NERR_Success ) {
  492. IF_DEBUG( UAS_DEBUG_UASP ) {
  493. NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws: Cannot NetpGetComputerName %ld\n",
  494. DomainName,
  495. NetStatus ));
  496. }
  497. goto Cleanup;
  498. }
  499. }
  500. if ( UaspNameCompare( MyDomainName, (LPWSTR) DomainName, NAMETYPE_DOMAIN ) == 0 ) {
  501. //
  502. // Connect to the SAM server
  503. //
  504. NetStatus = UaspOpenSam( NULL,
  505. FALSE, // Don't try null session
  506. &SamServerHandle );
  507. if ( NetStatus != NERR_Success ) {
  508. IF_DEBUG( UAS_DEBUG_UASP ) {
  509. NetpKdPrint(( "UaspOpenDomainWithDomainName: Cannot UaspOpenSam %ld\n", NetStatus ));
  510. }
  511. }
  512. goto Cleanup;
  513. }
  514. //
  515. // Try at least twice to find a DC.
  516. //
  517. Flags = 0;
  518. for ( i=0; i<2; i++ ) {
  519. //
  520. // Get the name of a DC in the domain.
  521. //
  522. NetStatus = DsGetDcNameW( NULL,
  523. DomainName,
  524. NULL, // No domain GUID
  525. NULL, // No site name
  526. Flags |
  527. DS_IS_FLAT_NAME |
  528. DS_RETURN_FLAT_NAME,
  529. &DcInfo );
  530. if ( NetStatus != NO_ERROR ) {
  531. IF_DEBUG( UAS_DEBUG_UASP ) {
  532. NetpKdPrint(( "UaspOpenDomainWithDomainName: %ws: Cannot DsGetDcName %ld\n",
  533. DomainName,
  534. NetStatus ));
  535. }
  536. goto Cleanup;
  537. }
  538. //
  539. // Connect to the SAM server on that DC
  540. //
  541. NetStatus = UaspOpenSam( DcInfo->DomainControllerName,
  542. TRUE, // Try null session
  543. &SamServerHandle );
  544. if ( NetStatus != NERR_Success ) {
  545. IF_DEBUG( UAS_DEBUG_UASP ) {
  546. NetpKdPrint(( "UaspOpenDomainWithDomainName: Cannot UaspOpenSam %ld\n", NetStatus ));
  547. }
  548. }
  549. //
  550. // If we got a definitive answer back from this DC,
  551. // use it.
  552. //
  553. switch ( NetStatus ) {
  554. case NO_ERROR:
  555. case ERROR_ACCESS_DENIED:
  556. case ERROR_NOT_ENOUGH_MEMORY:
  557. case NERR_InvalidComputer:
  558. goto Cleanup;
  559. }
  560. //
  561. // Otherwise, force rediscovery of a new DC.
  562. //
  563. Flags |= DS_FORCE_REDISCOVERY;
  564. }
  565. //
  566. // Delete locally used resources
  567. //
  568. Cleanup:
  569. //
  570. // If we've successfully gotten this far,
  571. // we have a SamServer handle.
  572. //
  573. // Just open the domain.
  574. //
  575. if ( NetStatus == NO_ERROR && SamServerHandle != NULL ) {
  576. NetStatus = UaspOpenDomain(
  577. SamServerHandle,
  578. DesiredAccess,
  579. AccountDomain,
  580. DomainHandle,
  581. DomainId );
  582. }
  583. //
  584. // The SamServerHandle has outlived its usefulness
  585. //
  586. if ( SamServerHandle != NULL ) {
  587. (VOID) SamCloseHandle( SamServerHandle );
  588. }
  589. if ( MyDomainName != NULL ) {
  590. NetApiBufferFree( MyDomainName );
  591. }
  592. if ( DcInfo != NULL) {
  593. NetApiBufferFree( DcInfo );
  594. }
  595. if ( NetStatus != NERR_Success ) {
  596. *DomainHandle = NULL;
  597. }
  598. return NetStatus;
  599. } // UaspOpenDomainWithDomainName
  600. VOID
  601. UaspCloseDomain(
  602. IN SAM_HANDLE DomainHandle OPTIONAL
  603. )
  604. /*++
  605. Routine Description:
  606. Close a Domain handle opened by UaspOpenDomain.
  607. Arguments:
  608. DomainHandle - Supplies the Domain Handle to close.
  609. Return Value:
  610. None.
  611. --*/
  612. {
  613. //
  614. // Close the Domain Handle
  615. //
  616. if ( DomainHandle != NULL ) {
  617. (VOID) SamCloseHandle( DomainHandle );
  618. }
  619. return;
  620. } // UaspCloseDomain
  621. NET_API_STATUS
  622. UaspDownlevel(
  623. IN LPCWSTR ServerName OPTIONAL,
  624. IN NET_API_STATUS OriginalError,
  625. OUT LPBOOL TryDownLevel
  626. )
  627. /*++
  628. Routine Description:
  629. This routine is based on NetpHandleRpcFailure (courtesy of JohnRo).
  630. It is different in that it doesn't handle RPC failures. Rather,
  631. it tries to determine if a Sam call should go downlevel simply by
  632. calling using the specified ServerName.
  633. Arguments:
  634. ServerName - The server name to handle the call.
  635. OriginalError - Error gotten from RPC attempt.
  636. TryDownLevel - Returns TRUE if we should try down-level.
  637. Return Value:
  638. NERR_Success - Use SAM to handle the call.
  639. Other - Return the error to the caller.
  640. --*/
  641. {
  642. NET_API_STATUS NetStatus;
  643. DWORD OptionsSupported = 0;
  644. *TryDownLevel = FALSE;
  645. //
  646. // Learn about the machine. This is fairly easy since the
  647. // NetRemoteComputerSupports also handles the local machine (whether
  648. // or not a server name is given).
  649. //
  650. NetStatus = NetRemoteComputerSupports(
  651. (LPWSTR) ServerName,
  652. SUPPORTS_RPC | SUPPORTS_LOCAL | SUPPORTS_SAM_PROTOCOL,
  653. &OptionsSupported);
  654. if (NetStatus != NERR_Success) {
  655. // This is where machine not found gets handled.
  656. return NetStatus;
  657. }
  658. //
  659. // If the machine supports SAM,
  660. // just return now.
  661. //
  662. if (OptionsSupported & SUPPORTS_SAM_PROTOCOL) {
  663. // SAM is only supported over RPC
  664. NetpAssert((OptionsSupported & SUPPORTS_RPC) == SUPPORTS_RPC );
  665. return OriginalError;
  666. }
  667. // The local system should always support SAM
  668. NetpAssert((OptionsSupported & SUPPORTS_LOCAL) == 0 );
  669. //
  670. // Local workstation is not started? (It must be in order to
  671. // remote APIs to the other system.)
  672. //
  673. if ( ! NetpIsServiceStarted(SERVICE_WORKSTATION) ) {
  674. return (NERR_WkstaNotStarted);
  675. }
  676. //
  677. // Tell the caller to try the RxNet routine.
  678. //
  679. *TryDownLevel = TRUE;
  680. return OriginalError;
  681. } // UaspDownlevel
  682. NET_API_STATUS
  683. UaspLSASetServerRole(
  684. IN LPCWSTR ServerName,
  685. IN PDOMAIN_SERVER_ROLE_INFORMATION DomainServerRole
  686. )
  687. /*++
  688. Routine Description:
  689. This function sets the server role in LSA.
  690. Arguments:
  691. ServerName - The server name to handle the call.
  692. ServerRole - The server role information.
  693. Return Value:
  694. NERR_Success - if the server role is successfully set in LSA.
  695. Error code for the operation - if the operation was unsuccessful.
  696. --*/
  697. {
  698. NTSTATUS Status;
  699. NET_API_STATUS NetStatus;
  700. UNICODE_STRING UnicodeStringServerName;
  701. ACCESS_MASK LSADesiredAccess;
  702. LSA_HANDLE LSAPolicyHandle = NULL;
  703. OBJECT_ATTRIBUTES LSAObjectAttributes;
  704. POLICY_LSA_SERVER_ROLE_INFO PolicyLsaServerRoleInfo;
  705. RtlInitUnicodeString( &UnicodeStringServerName, ServerName );
  706. //
  707. // set desired access mask.
  708. //
  709. LSADesiredAccess = POLICY_SERVER_ADMIN;
  710. InitializeObjectAttributes( &LSAObjectAttributes,
  711. NULL, // Name
  712. 0, // Attributes
  713. NULL, // Root
  714. NULL ); // Security Descriptor
  715. Status = LsaOpenPolicy( &UnicodeStringServerName,
  716. &LSAObjectAttributes,
  717. LSADesiredAccess,
  718. &LSAPolicyHandle );
  719. if( !NT_SUCCESS(Status) ) {
  720. IF_DEBUG( UAS_DEBUG_UASP ) {
  721. NetpKdPrint(( "UaspLSASetServerRole: "
  722. "Cannot open LSA Policy %lX\n", Status ));
  723. }
  724. NetStatus = NetpNtStatusToApiStatus( Status );
  725. goto Cleanup;
  726. }
  727. //
  728. // make PolicyLsaServerRoleInfo
  729. //
  730. switch( DomainServerRole->DomainServerRole ) {
  731. case DomainServerRoleBackup :
  732. PolicyLsaServerRoleInfo.LsaServerRole = PolicyServerRoleBackup;
  733. break;
  734. case DomainServerRolePrimary :
  735. PolicyLsaServerRoleInfo.LsaServerRole = PolicyServerRolePrimary;
  736. break;
  737. default:
  738. IF_DEBUG( UAS_DEBUG_UASP ) {
  739. NetpKdPrint(( "UaspLSASetServerRole: "
  740. "Unknown Server Role %lX\n",
  741. DomainServerRole->DomainServerRole ));
  742. }
  743. NetStatus = NERR_InternalError;
  744. goto Cleanup;
  745. }
  746. //
  747. // now set PolicyLsaServerRoleInformation
  748. //
  749. Status = LsaSetInformationPolicy(
  750. LSAPolicyHandle,
  751. PolicyLsaServerRoleInformation,
  752. (PVOID) &PolicyLsaServerRoleInfo );
  753. if( !NT_SUCCESS(Status) ) {
  754. IF_DEBUG( UAS_DEBUG_UASP ) {
  755. NetpKdPrint(( "UaspLSASetServerRole: "
  756. "Cannot set Information Policy %lX\n", Status ));
  757. }
  758. NetStatus = NetpNtStatusToApiStatus( Status );
  759. goto Cleanup;
  760. }
  761. //
  762. // Successfully done
  763. //
  764. NetStatus = NERR_Success;
  765. Cleanup:
  766. if( LSAPolicyHandle != NULL ) {
  767. Status = LsaClose( LSAPolicyHandle );
  768. NetpAssert( NT_SUCCESS( Status ) );
  769. }
  770. return NetStatus;
  771. }
  772. NET_API_STATUS
  773. UaspBuiltinDomainSetServerRole(
  774. IN SAM_HANDLE SamServerHandle,
  775. IN PDOMAIN_SERVER_ROLE_INFORMATION DomainServerRole
  776. )
  777. /*++
  778. Routine Description:
  779. This function sets the server role in builtin domain.
  780. Arguments:
  781. SamServerHandle - A handle to the SAM server to set the role on
  782. ServerRole - The server role information.
  783. Return Value:
  784. NERR_Success - if the server role is successfully set in LSA.
  785. Error code for the operation - if the operation was unsuccessful.
  786. --*/
  787. {
  788. NTSTATUS Status;
  789. NET_API_STATUS NetStatus;
  790. SAM_HANDLE BuiltinDomainHandle = NULL;
  791. //
  792. // Open the domain asking for accumulated desired access
  793. //
  794. NetStatus = UaspOpenDomain( SamServerHandle,
  795. DOMAIN_ADMINISTER_SERVER,
  796. FALSE, // Builtin Domain
  797. &BuiltinDomainHandle,
  798. NULL ); // DomainId
  799. if ( NetStatus != NERR_Success ) {
  800. IF_DEBUG( UAS_DEBUG_UASP ) {
  801. NetpKdPrint(( "UaspBuiltinSetServerRole: "
  802. "Cannot UaspOpenDomain [Builtin] %ld\n",
  803. NetStatus ));
  804. }
  805. goto Cleanup;
  806. }
  807. //
  808. // now we have open the builtin domain, update server role.
  809. //
  810. Status = SamSetInformationDomain(
  811. BuiltinDomainHandle,
  812. DomainServerRoleInformation,
  813. DomainServerRole );
  814. if ( !NT_SUCCESS( Status ) ) {
  815. IF_DEBUG( UAS_DEBUG_UASP ) {
  816. NetpKdPrint(( "UaspBuiltinSetServerRole: "
  817. "Cannot SamSetInformationDomain %lX\n",
  818. Status ));
  819. }
  820. NetStatus = NetpNtStatusToApiStatus( Status );
  821. goto Cleanup;
  822. }
  823. NetStatus = NERR_Success;
  824. Cleanup:
  825. //
  826. // Close DomainHandle.
  827. //
  828. if ( BuiltinDomainHandle != NULL ) {
  829. (VOID) SamCloseHandle( BuiltinDomainHandle );
  830. }
  831. return NetStatus;
  832. }