Leaked source code of windows server 2003
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.

763 lines
19 KiB

  1. /*++
  2. Copyright (c) 1987-1999 Microsoft Corporation
  3. Module Name:
  4. nlcommon.c
  5. Abstract:
  6. Routines shared by logonsrv\server and logonsrv\common
  7. Author:
  8. Cliff Van Dyke (cliffv) 20-July-1996
  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. --*/
  15. //
  16. // Common include files.
  17. //
  18. #ifndef _NETLOGON_SERVER
  19. #include <nt.h>
  20. #include <ntrtl.h>
  21. #include <nturtl.h>
  22. #include <ntlsa.h>
  23. #include <rpc.h> // RPC_STATUS
  24. #include <windef.h>
  25. #include <winsock2.h>
  26. #include <lmcons.h> // General net defines
  27. #include <dsgetdc.h> // DsGetDcName()
  28. #include <align.h> // ROUND_UP_COUNT()
  29. #include <lmerr.h> // System Error Log definitions
  30. #include <lmapibuf.h> // NetapipBufferAllocate
  31. #include <netlib.h> // NetpMemoryAllcate(
  32. #include <netlibnt.h> // NetpApiStatusToNtStatus();
  33. #include <netlogon.h> // Definition of mailslot messages
  34. #include <ntddbrow.h> // Needed by nlcommon.h
  35. #include <ntrpcp.h>
  36. #if DBG
  37. #define NETLOGONDBG 1
  38. #endif // DBG
  39. #include <nldebug.h> // NlPrint()
  40. #include <nlbind.h> // Definitions shared with netlogon
  41. #include <nlcommon.h> // Definitions shared with netlogon
  42. #include <stdlib.h> // C library functions (rand, etc)
  43. #endif // _NETLOGON_SERVER
  44. //
  45. // Include nlcommon.h again allocating the actual variables
  46. // this time around.
  47. //
  48. // #define NLCOMMON_ALLOCATE
  49. // #include "nlcommon.h"
  50. // #undef NLCOMMON_ALLOCATE
  51. #ifndef WIN32_CHICAGO
  52. VOID
  53. NlForestRelocationRoutine(
  54. IN DWORD Level,
  55. IN OUT PBUFFER_DESCRIPTOR BufferDescriptor,
  56. IN PTRDIFF_T Offset
  57. )
  58. /*++
  59. Routine Description:
  60. Routine to relocate the pointers from the fixed portion of a NetGroupEnum
  61. enumeration
  62. buffer to the string portion of an enumeration buffer. It is called
  63. as a callback routine from NetpAllocateEnumBuffer when it re-allocates
  64. such a buffer. NetpAllocateEnumBuffer copied the fixed portion and
  65. string portion into the new buffer before calling this routine.
  66. Arguments:
  67. Level - Level of information in the buffer.
  68. BufferDescriptor - Description of the new buffer.
  69. Offset - Offset to add to each pointer in the fixed portion.
  70. Return Value:
  71. Returns the error code for the operation.
  72. --*/
  73. {
  74. DWORD EntryCount;
  75. DWORD EntryNumber;
  76. DWORD FixedSize;
  77. //
  78. // Local macro to add a byte offset to a pointer.
  79. //
  80. #define RELOCATE_ONE( _fieldname, _offset ) \
  81. if ( (_fieldname) != NULL ) { \
  82. _fieldname = (PVOID) ((LPBYTE)(_fieldname) + (_offset)); \
  83. }
  84. //
  85. // Compute the number of fixed size entries
  86. //
  87. FixedSize = sizeof(DS_DOMAIN_TRUSTSW);
  88. EntryCount =
  89. ((DWORD)(BufferDescriptor->FixedDataEnd - BufferDescriptor->Buffer)) /
  90. FixedSize;
  91. //
  92. // Loop relocating each field in each fixed size structure
  93. //
  94. for ( EntryNumber=0; EntryNumber<EntryCount; EntryNumber++ ) {
  95. LPBYTE TheStruct = BufferDescriptor->Buffer + FixedSize * EntryNumber;
  96. RELOCATE_ONE( ((PDS_DOMAIN_TRUSTSW)TheStruct)->NetbiosDomainName, Offset );
  97. RELOCATE_ONE( ((PDS_DOMAIN_TRUSTSW)TheStruct)->DnsDomainName, Offset );
  98. RELOCATE_ONE( ((PDS_DOMAIN_TRUSTSW)TheStruct)->DomainSid, Offset );
  99. }
  100. return;
  101. UNREFERENCED_PARAMETER( Level );
  102. }
  103. NTSTATUS
  104. NlAllocateForestTrustListEntry (
  105. IN PBUFFER_DESCRIPTOR BufferDescriptor,
  106. IN PUNICODE_STRING InNetbiosDomainName OPTIONAL,
  107. IN PUNICODE_STRING InDnsDomainName OPTIONAL,
  108. IN ULONG Flags,
  109. IN ULONG ParentIndex,
  110. IN ULONG TrustType,
  111. IN ULONG TrustAttributes,
  112. IN PSID DomainSid OPTIONAL,
  113. IN GUID *DomainGuid,
  114. OUT PULONG RetSize,
  115. OUT PDS_DOMAIN_TRUSTSW *RetTrustedDomain
  116. )
  117. /*++
  118. Routine Description:
  119. Add a DS_DOMAIN_TRUSTSW structure to the buffer described by BufferDescriptor.
  120. Arguments:
  121. BufferDescriptor - Buffer entry is to be added to.
  122. NetbiosDomainName, DnsDomainName, Flags, ParentIndex, TrustType,
  123. TrustAttributes, DomainSid, DomainGuid - Fields to fill into
  124. the DS_DOMAIN_TRUSTSW structure
  125. RetSize - Returns the size in bytes of the allocated entry
  126. RetTrustedDomain - Returns a pointer to the newly allocated structure
  127. Return Value:
  128. Status of the operation.
  129. --*/
  130. {
  131. NTSTATUS Status;
  132. NET_API_STATUS NetStatus;
  133. PDS_DOMAIN_TRUSTSW TrustedDomain = NULL;
  134. UNICODE_STRING NetbiosDomainName;
  135. UNICODE_STRING DnsDomainName;
  136. ULONG Size;
  137. ULONG VariableSize;
  138. //
  139. // Initialization
  140. //
  141. if ( InNetbiosDomainName == NULL ) {
  142. RtlInitUnicodeString( &NetbiosDomainName, NULL );
  143. } else {
  144. NetbiosDomainName = *InNetbiosDomainName;
  145. }
  146. if ( InDnsDomainName == NULL ) {
  147. RtlInitUnicodeString( &DnsDomainName, NULL );
  148. } else {
  149. DnsDomainName = *InDnsDomainName;
  150. }
  151. //
  152. // Determine the size of this entry
  153. //
  154. Size = sizeof(DS_DOMAIN_TRUSTSW);
  155. VariableSize = 0;
  156. if ( DnsDomainName.Length != 0 ) {
  157. VariableSize += DnsDomainName.Length + sizeof(WCHAR);
  158. }
  159. if ( NetbiosDomainName.Length != 0 ) {
  160. VariableSize += NetbiosDomainName.Length + sizeof(WCHAR);
  161. }
  162. if ( DomainSid != NULL ) {
  163. VariableSize += RtlLengthSid( DomainSid );
  164. }
  165. VariableSize = ROUND_UP_COUNT( VariableSize, ALIGN_DWORD );
  166. *RetSize = Size + VariableSize;
  167. Size += VariableSize;
  168. Size += sizeof(DWORD); // Size is really a function of alignment of EndOfVariableData
  169. NetStatus = NetpAllocateEnumBufferEx(
  170. BufferDescriptor,
  171. FALSE, // Not a 'get' operation
  172. 0xFFFFFFFF, // PrefMaxLen,
  173. Size,
  174. NlForestRelocationRoutine,
  175. 0,
  176. 512 ); // Grow by at most 512 bytes more than Size
  177. if (NetStatus != NERR_Success) {
  178. Status = NetpApiStatusToNtStatus( NetStatus );
  179. goto Cleanup;
  180. }
  181. //
  182. // Copy this entry into the buffer
  183. //
  184. TrustedDomain = (PDS_DOMAIN_TRUSTSW)(BufferDescriptor->FixedDataEnd);
  185. *RetTrustedDomain = TrustedDomain;
  186. BufferDescriptor->FixedDataEnd += sizeof(DS_DOMAIN_TRUSTSW);
  187. //
  188. // Copy the fixed size data
  189. //
  190. TrustedDomain->Flags = Flags;
  191. TrustedDomain->ParentIndex = ParentIndex;
  192. TrustedDomain->TrustType = TrustType;
  193. TrustedDomain->TrustAttributes = TrustAttributes;
  194. if ( DomainGuid == NULL ) {
  195. RtlZeroMemory( &TrustedDomain->DomainGuid, sizeof(GUID) );
  196. } else {
  197. TrustedDomain->DomainGuid = *DomainGuid;
  198. }
  199. //
  200. // Copy the information into the buffer.
  201. //
  202. //
  203. // Copy the DWORD aligned data
  204. //
  205. if ( DomainSid != NULL ) {
  206. if ( !NetpCopyDataToBuffer (
  207. (LPBYTE)DomainSid,
  208. RtlLengthSid( DomainSid ),
  209. BufferDescriptor->FixedDataEnd,
  210. &BufferDescriptor->EndOfVariableData,
  211. (LPBYTE *)&TrustedDomain->DomainSid,
  212. sizeof(DWORD) ) ) {
  213. Status = STATUS_INTERNAL_ERROR;
  214. goto Cleanup;
  215. }
  216. } else {
  217. TrustedDomain->DomainSid = NULL;
  218. }
  219. //
  220. // Copy the WCHAR aligned data.
  221. //
  222. if ( NetbiosDomainName.Length != 0 ) {
  223. if ( !NetpCopyStringToBuffer(
  224. NetbiosDomainName.Buffer,
  225. NetbiosDomainName.Length/sizeof(WCHAR),
  226. BufferDescriptor->FixedDataEnd,
  227. (LPWSTR *)&BufferDescriptor->EndOfVariableData,
  228. &TrustedDomain->NetbiosDomainName ) ) {
  229. Status = STATUS_INTERNAL_ERROR;
  230. goto Cleanup;
  231. }
  232. } else {
  233. TrustedDomain->NetbiosDomainName = NULL;
  234. }
  235. if ( DnsDomainName.Length != 0 ) {
  236. if ( !NetpCopyStringToBuffer(
  237. DnsDomainName.Buffer,
  238. DnsDomainName.Length/sizeof(WCHAR),
  239. BufferDescriptor->FixedDataEnd,
  240. (LPWSTR *)&BufferDescriptor->EndOfVariableData,
  241. &TrustedDomain->DnsDomainName ) ) {
  242. Status = STATUS_INTERNAL_ERROR;
  243. goto Cleanup;
  244. }
  245. } else {
  246. TrustedDomain->DnsDomainName = NULL;
  247. }
  248. Status = STATUS_SUCCESS;
  249. //
  250. //
  251. Cleanup:
  252. return Status;
  253. }
  254. NTSTATUS
  255. NlGetNt4TrustedDomainList (
  256. IN LPWSTR UncDcName,
  257. IN PUNICODE_STRING InNetbiosDomainName OPTIONAL,
  258. IN PUNICODE_STRING InDnsDomainName OPTIONAL,
  259. IN PSID DomainSid OPTIONAL,
  260. IN GUID *DomainGuid OPTIONAL,
  261. OUT PDS_DOMAIN_TRUSTSW *ForestTrustList,
  262. OUT PULONG ForestTrustListSize,
  263. OUT PULONG ForestTrustListCount
  264. )
  265. /*++
  266. Routine Description:
  267. Get the list of trusted domains from the specified DC using NT 4 protocols.
  268. Arguments:
  269. UncDcName - Specifies the name of a DC in the domain.
  270. InNetbiosDomainName - Netbios domain of the domain Dc is in.
  271. InDnsDomainName - Dns domain of the domain Dc is in.
  272. DomainSid - Sid of the domain Dc is in.
  273. DomainGuid - Guid of the domain Dc is in.
  274. ForestTrustList - Returns a list of trusted domains.
  275. Must be freed using NetApiBufferFree
  276. ForestTrustListSize - Size (in bytes) of ForestTrustList
  277. ForestTrustListCount - Number of entries in ForestTrustList
  278. Return Value:
  279. STATUS_SUCCESS - if the trust list was successfully returned
  280. --*/
  281. {
  282. NTSTATUS Status;
  283. NET_API_STATUS NetStatus;
  284. LSA_HANDLE LsaHandle = NULL;
  285. UNICODE_STRING UncDcNameString;
  286. OBJECT_ATTRIBUTES ObjectAttributes;
  287. LSA_ENUMERATION_HANDLE EnumerationContext;
  288. BOOLEAN AllDone = FALSE;
  289. PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomainInfo = NULL;
  290. PLSA_TRUST_INFORMATION TrustList = NULL;
  291. BUFFER_DESCRIPTOR BufferDescriptor;
  292. PDS_DOMAIN_TRUSTSW TrustedDomain;
  293. DWORD Size;
  294. //
  295. // Initialization
  296. //
  297. *ForestTrustListCount = 0;
  298. *ForestTrustListSize = 0;
  299. *ForestTrustList = NULL;
  300. BufferDescriptor.Buffer = NULL;
  301. //
  302. // Open the policy database on the DC
  303. //
  304. RtlInitUnicodeString( &UncDcNameString, UncDcName );
  305. InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
  306. Status = LsaOpenPolicy( &UncDcNameString,
  307. &ObjectAttributes,
  308. POLICY_VIEW_LOCAL_INFORMATION,
  309. &LsaHandle );
  310. if ( !NT_SUCCESS(Status) ) {
  311. NlPrint((NL_CRITICAL,
  312. "NlGetNt4TrustedDomainList: %ws: LsaOpenPolicy failed: %lx\n",
  313. UncDcName,
  314. Status ));
  315. LsaHandle = NULL;
  316. goto Cleanup;
  317. }
  318. //
  319. // If the caller didn't specify primary domain information,
  320. // get it from the DC
  321. //
  322. if ( InNetbiosDomainName == NULL ) {
  323. //
  324. // Get the name of the primary domain from LSA
  325. //
  326. Status = LsaQueryInformationPolicy(
  327. LsaHandle,
  328. PolicyPrimaryDomainInformation,
  329. (PVOID *) &PrimaryDomainInfo
  330. );
  331. if (! NT_SUCCESS(Status)) {
  332. NlPrint(( NL_CRITICAL,
  333. "NlGetNt4TrustedDomainList: LsaQueryInformationPolicy failed %lx\n",
  334. Status));
  335. goto Cleanup;
  336. }
  337. //
  338. // Grab the returned information
  339. //
  340. InNetbiosDomainName = &PrimaryDomainInfo->Name;
  341. InDnsDomainName = NULL;
  342. DomainSid = PrimaryDomainInfo->Sid;
  343. DomainGuid = NULL;
  344. }
  345. //
  346. // The LsaEnumerateTrustedDomain doesn't have the PrimaryDomain in the trust list.
  347. // Add it to our list here.
  348. //
  349. Status = NlAllocateForestTrustListEntry (
  350. &BufferDescriptor,
  351. InNetbiosDomainName,
  352. InDnsDomainName,
  353. DS_DOMAIN_PRIMARY,
  354. 0, // No ParentIndex
  355. TRUST_TYPE_DOWNLEVEL,
  356. 0, // No TrustAttributes
  357. DomainSid,
  358. DomainGuid,
  359. &Size,
  360. &TrustedDomain );
  361. if ( !NT_SUCCESS(Status) ) {
  362. goto Cleanup;
  363. }
  364. *ForestTrustListSize += Size;
  365. (*ForestTrustListCount) ++;
  366. //
  367. // Loop getting a list of trusted domains
  368. //
  369. EnumerationContext = 0;
  370. do {
  371. ULONG i;
  372. ULONG CountReturned;
  373. //
  374. // Free any buffers from a previous iteration.
  375. //
  376. if ( TrustList != NULL ) {
  377. (VOID) LsaFreeMemory( TrustList );
  378. }
  379. //
  380. // Get more trusted domains names
  381. //
  382. Status = LsaEnumerateTrustedDomains(
  383. LsaHandle,
  384. &EnumerationContext,
  385. (PVOID *) &TrustList,
  386. 0xFFFFFFFF,
  387. &CountReturned );
  388. if ( Status == STATUS_NO_MORE_ENTRIES ) {
  389. AllDone = TRUE;
  390. Status = STATUS_SUCCESS;
  391. }
  392. if ( !NT_SUCCESS(Status) ) {
  393. NlPrint((NL_CRITICAL,
  394. "NlGetNt4TrustedDomainList: %ws: LsaEnumerateTrustedDomains failed: %lx\n",
  395. UncDcName,
  396. Status ));
  397. TrustList = NULL;
  398. goto Cleanup;
  399. }
  400. //
  401. // Handle each trusted domain.
  402. //
  403. for ( i=0; i<CountReturned; i++ ) {
  404. Status = NlAllocateForestTrustListEntry (
  405. &BufferDescriptor,
  406. &TrustList[i].Name,
  407. NULL, // No DNS domain name
  408. DS_DOMAIN_DIRECT_OUTBOUND,
  409. 0, // No ParentIndex
  410. TRUST_TYPE_DOWNLEVEL,
  411. 0, // No TrustAttributes
  412. TrustList[i].Sid,
  413. NULL, // No DomainGuid
  414. &Size,
  415. &TrustedDomain );
  416. if ( !NT_SUCCESS(Status) ) {
  417. goto Cleanup;
  418. }
  419. //
  420. // Account for the newly allocated entry
  421. //
  422. *ForestTrustListSize += Size;
  423. (*ForestTrustListCount) ++;
  424. }
  425. } while ( !AllDone );
  426. *ForestTrustList = (PDS_DOMAIN_TRUSTSW) BufferDescriptor.Buffer;
  427. BufferDescriptor.Buffer = NULL;
  428. Status = STATUS_SUCCESS;
  429. //
  430. // Free any locally used resources.
  431. //
  432. Cleanup:
  433. if ( LsaHandle != NULL ) {
  434. (VOID) LsaClose( LsaHandle );
  435. }
  436. if ( TrustList != NULL ) {
  437. (VOID) LsaFreeMemory( TrustList );
  438. }
  439. if ( BufferDescriptor.Buffer != NULL ) {
  440. NetApiBufferFree( BufferDescriptor.Buffer );
  441. }
  442. if ( PrimaryDomainInfo != NULL ) {
  443. (void) LsaFreeMemory( PrimaryDomainInfo );
  444. }
  445. return Status;
  446. }
  447. NTSTATUS
  448. NlRpcpBindRpc(
  449. IN LPWSTR ServerName,
  450. IN LPWSTR ServiceName,
  451. IN LPWSTR NetworkOptions,
  452. IN NL_RPC_BINDING RpcBindingType,
  453. OUT RPC_BINDING_HANDLE *pBindingHandle
  454. )
  455. /*++
  456. Routine Description:
  457. Binds to the RPC server if possible.
  458. Arguments:
  459. ServerName - Name of server to bind with.
  460. ServiceName - Name of service to bind with.
  461. RpcBindingType - Determines whether to use unauthenticated TCP/IP transport instead of
  462. a named pipe.
  463. pBindingHandle - Location where binding handle is to be placed
  464. Return Value:
  465. STATUS_SUCCESS - The binding has been successfully completed.
  466. STATUS_INVALID_COMPUTER_NAME - The ServerName syntax is invalid.
  467. STATUS_NO_MEMORY - There is not sufficient memory available to the
  468. caller to perform the binding.
  469. --*/
  470. {
  471. RPC_STATUS RpcStatus;
  472. LPWSTR StringBinding;
  473. WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  474. LPWSTR NewServerName = NULL;
  475. DWORD bufLen = MAX_COMPUTERNAME_LENGTH + 1;
  476. //
  477. // If we're supposed to use named pipes,
  478. // call the standard routine.
  479. //
  480. if ( RpcBindingType == UseNamedPipe ) {
  481. return RpcpBindRpc( ServerName, ServiceName, NetworkOptions, pBindingHandle );
  482. }
  483. //
  484. // Otherwise, use TCP/IP directly.
  485. //
  486. *pBindingHandle = NULL;
  487. if (ServerName != NULL) {
  488. if (GetComputerNameW(ComputerName,&bufLen)) {
  489. if ((_wcsicmp(ComputerName,ServerName) == 0) ||
  490. ((ServerName[0] == '\\') &&
  491. (ServerName[1] == '\\') &&
  492. (_wcsicmp(ComputerName,&(ServerName[2]))==0))) {
  493. NewServerName = NULL;
  494. }
  495. else {
  496. NewServerName = ServerName;
  497. }
  498. }
  499. }
  500. //
  501. // Ditch the \\
  502. //
  503. if ( NewServerName != NULL &&
  504. NewServerName[0] == '\\' &&
  505. NewServerName[1] == '\\' ) {
  506. NewServerName += 2;
  507. }
  508. //
  509. // Enpoint isn't known.
  510. // Rpc will contact the endpoint mapper for it.
  511. //
  512. RpcStatus = RpcStringBindingComposeW(0, L"ncacn_ip_tcp", NewServerName,
  513. NULL, NetworkOptions, &StringBinding);
  514. if ( RpcStatus != RPC_S_OK ) {
  515. return( STATUS_NO_MEMORY );
  516. }
  517. RpcStatus = RpcBindingFromStringBindingW(StringBinding, pBindingHandle);
  518. RpcStringFreeW(&StringBinding);
  519. if ( RpcStatus != RPC_S_OK ) {
  520. *pBindingHandle = NULL;
  521. if ( RpcStatus == RPC_S_INVALID_ENDPOINT_FORMAT ||
  522. RpcStatus == RPC_S_INVALID_NET_ADDR ) {
  523. return( STATUS_INVALID_COMPUTER_NAME );
  524. }
  525. if ( RpcStatus == RPC_S_PROTSEQ_NOT_SUPPORTED ) {
  526. return RPC_NT_PROTSEQ_NOT_SUPPORTED;
  527. }
  528. return(STATUS_NO_MEMORY);
  529. }
  530. return(STATUS_SUCCESS);
  531. }
  532. BOOLEAN
  533. NlDoingSetup(
  534. VOID
  535. )
  536. /*++
  537. Routine Description:
  538. Returns TRUE if we're running setup.
  539. Arguments:
  540. NONE.
  541. Return Status:
  542. TRUE - We're currently running setup
  543. FALSE - We're not running setup or aren't sure.
  544. --*/
  545. {
  546. DWORD Value;
  547. if ( !NlReadDwordHklmRegValue( "SYSTEM\\Setup",
  548. "SystemSetupInProgress",
  549. &Value ) ) {
  550. return FALSE;
  551. }
  552. if ( Value != 1 ) {
  553. // NlPrint(( 0, "NlDoingSetup: not doing setup\n" ));
  554. return FALSE;
  555. }
  556. NlPrint(( 0, "NlDoingSetup: doing setup\n" ));
  557. return TRUE;
  558. }
  559. #endif // WIN32_CHICAGO