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.

1602 lines
39 KiB

  1. /*++
  2. Copyright (c) 1987-1992 Microsoft Corporation
  3. Module Name:
  4. logonp.c
  5. Abstract:
  6. Private Netlogon service routines useful by both the Netlogon service
  7. and others that pass mailslot messages to/from the Netlogon service.
  8. Author:
  9. Cliff Van Dyke (cliffv) 7-Jun-1991
  10. Environment:
  11. User mode only.
  12. Contains NT-specific code.
  13. Requires ANSI C extensions: slash-slash comments, long external names.
  14. Revision History:
  15. --*/
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <ntsam.h> // Needed by netlogon.h
  20. #include <windef.h>
  21. #include <winbase.h>
  22. #include <lmcons.h> // General net defines
  23. #include <align.h> // ROUND_UP_POINTER ...
  24. #include <debuglib.h> // IF_DEBUG()
  25. #include <lmerr.h> // System Error Log definitions
  26. #include <lmapibuf.h> // NetapipBufferAllocate
  27. #include <netdebug.h> // DBGSTATIC ...
  28. #include <netlib.h> // NetpMemoryAllcate(
  29. #include <netlogon.h> // Definition of mailslot messages
  30. #include <stdlib.h> // C library functions (rand, etc)
  31. #include <logonp.h> // These routines
  32. #include <time.h> // time() function from C runtime
  33. #ifdef WIN32_CHICAGO
  34. #include "ntcalls.h"
  35. #endif // WIN32_CHICAGO
  36. BOOLEAN SeedRandomGen = FALSE;
  37. VOID
  38. NetpLogonPutOemString(
  39. IN LPSTR String,
  40. IN DWORD MaxStringLength,
  41. IN OUT PCHAR * Where
  42. )
  43. /*++
  44. Routine Description:
  45. Put an ascii string into a mailslot buffer.
  46. Arguments:
  47. String - Zero terminated ASCII string to put into the buffer.
  48. MaxStringLength - Maximum number of bytes to copy to the buffer (including
  49. the zero byte). If the string is longer than this, it is silently
  50. truncated.
  51. Where - Indirectly points to the current location in the buffer. The
  52. 'String' is copied to the current location. This current location is
  53. updated to point to the byte following the zero byte.
  54. Return Value:
  55. None.
  56. --*/
  57. {
  58. while ( *String != '\0' && MaxStringLength-- > 0 ) {
  59. *((*Where)++) = *(String++);
  60. }
  61. *((*Where)++) = '\0';
  62. }
  63. VOID
  64. NetpLogonPutUnicodeString(
  65. IN LPWSTR String OPTIONAL,
  66. IN DWORD MaxStringLength,
  67. IN OUT PCHAR * Where
  68. )
  69. /*++
  70. Routine Description:
  71. Put a UNICODE string into a mailslot buffer.
  72. UNICODE strings always appear at a 2-byte boundary in the message.
  73. Arguments:
  74. String - Zero terminated UNICODE string to put into the buffer.
  75. If not specified, a zero length string will be put into the buffer.
  76. MaxStringLength - Maximum number of bytes to copy to the buffer (including
  77. the zero byte). If the string is longer than this, it is silently
  78. truncated.
  79. Where - Indirectly points to the current location in the buffer. The
  80. current location is first adjusted to a 2-byte boundary. The 'String'
  81. is then copied to the current location. This current location is
  82. updated to point to the byte following the zero character.
  83. Return Value:
  84. None.
  85. --*/
  86. {
  87. LPWSTR Uwhere;
  88. //
  89. // Convert NULL to a zero length string.
  90. //
  91. if ( String == NULL ) {
  92. String = L"";
  93. }
  94. //
  95. // Align the unicode string on a WCHAR boundary.
  96. // All message structure definitions account for this alignment.
  97. //
  98. Uwhere = ROUND_UP_POINTER( *Where, ALIGN_WCHAR );
  99. if ( (PCHAR)Uwhere != *Where ) {
  100. **Where = '\0';
  101. }
  102. while ( *String != '\0' && MaxStringLength-- > 0 ) {
  103. *(Uwhere++) = *(String++);
  104. }
  105. *(Uwhere++) = '\0';
  106. *Where = (PCHAR) Uwhere;
  107. }
  108. VOID
  109. NetpLogonPutDomainSID(
  110. IN PCHAR Sid,
  111. IN DWORD SidLength,
  112. IN OUT PCHAR * Where
  113. )
  114. /*++
  115. Routine Description:
  116. Put a Domain SID into a message buffer.
  117. Domain SID always appears at a 4-byte boundary in the message.
  118. Arguments:
  119. Sid - pointer to the sid to be placed in the buffer.
  120. SidLength - length of the SID.
  121. Where - Indirectly points to the current location in the buffer. The
  122. current location is first adjusted to a 4-byte boundary. The
  123. 'Sid' is then copied to the current location. This current location
  124. is updated to point to the location just following the Sid.
  125. Return Value:
  126. None.
  127. --*/
  128. {
  129. PCHAR Uwhere;
  130. //
  131. // Avoid aligning the data if there is no SID,
  132. //
  133. if ( SidLength == 0 ) {
  134. return;
  135. }
  136. //
  137. // Align the current location to point 4-byte boundary.
  138. //
  139. Uwhere = ROUND_UP_POINTER( *Where, ALIGN_DWORD );
  140. //
  141. // fill up void space.
  142. //
  143. while ( Uwhere > *Where ) {
  144. *(*Where)++ = '\0';
  145. }
  146. //
  147. // copy SID into the buffer
  148. //
  149. RtlMoveMemory( *Where, Sid, SidLength );
  150. *Where += SidLength;
  151. }
  152. VOID
  153. NetpLogonPutBytes(
  154. IN LPVOID Data,
  155. IN DWORD Size,
  156. IN OUT PCHAR * Where
  157. )
  158. /*++
  159. Routine Description:
  160. Put binary data into a mailslot buffer.
  161. Arguments:
  162. Data - Pointer to the data to be put into the buffer.
  163. Size - Number of bytes to copy to the buffer.
  164. Where - Indirectly points to the current location in the buffer. The
  165. 'Data' is copied to the current location. This current location is
  166. updated to point to the byte following the end of the data.
  167. Return Value:
  168. None.
  169. --*/
  170. {
  171. while ( Size-- > 0 ) {
  172. *((*Where)++) = *(((LPBYTE)(Data))++);
  173. }
  174. }
  175. DWORD
  176. NetpLogonGetMessageVersion(
  177. IN PVOID Message,
  178. IN PDWORD MessageSize,
  179. OUT PULONG Version
  180. )
  181. /*++
  182. Routine Description:
  183. Determine the version of the message.
  184. The last several bytes of the message are inspected for a LM 2.0 and LM NT
  185. token.
  186. Message size is reduced to remove the token from message after
  187. version check.
  188. Arguments:
  189. Message - Points to a buffer containing the message.
  190. MessageSize - When called this has the number of bytes in the
  191. message buffer including the token bytes. On return this size will
  192. be "Token bytes" less.
  193. Version - Returns the "version" bits from the message.
  194. Return Value:
  195. LMUNKNOWN_MESSAGE - Neither a LM 2.0 nor LM NT message of known
  196. version.
  197. LNNT_MESSAGE - Message is from LM NT.
  198. LM20_MESSAGE - Message is from LM 2.0.
  199. --*/
  200. {
  201. PUCHAR End = ((PUCHAR)Message) + *MessageSize - 1;
  202. ULONG VersionFlag;
  203. if ( (*MessageSize > 2) &&
  204. (*End == LM20_TOKENBYTE) &&
  205. (*(End-1) == LM20_TOKENBYTE) ) {
  206. if ( (*MessageSize > 4) &&
  207. (*(End-2) == LMNT_TOKENBYTE) &&
  208. (*(End-3) == LMNT_TOKENBYTE) ) {
  209. if ( *MessageSize < (4 + sizeof(ULONG)) ) {
  210. *MessageSize -= 4;
  211. *Version = 0;
  212. return LMUNKNOWNNT_MESSAGE;
  213. }
  214. *MessageSize -= 8;
  215. //
  216. // get the version flag from message
  217. //
  218. VersionFlag = SmbGetUlong( (End - 3 - sizeof(ULONG)) );
  219. *Version = VersionFlag;
  220. //
  221. // if NETLOGON_NT_VERSION_1 bit is set in the version flag
  222. // then this version of software can process this message.
  223. // otherwise it can't so return error.
  224. //
  225. if( VersionFlag & NETLOGON_NT_VERSION_1) {
  226. return LMNT_MESSAGE;
  227. }
  228. return LMUNKNOWNNT_MESSAGE;
  229. } else {
  230. *MessageSize -= 2;
  231. *Version = 0;
  232. return LM20_MESSAGE;
  233. }
  234. //
  235. // Detect the token placed in the next to last byte of the PRIMARY_QUERY
  236. // message from newer (8/8/94) WFW and Chicago clients. This byte (followed
  237. // by a LM20_TOKENBYTE) indicates the client is WAN-aware and sends the
  238. // PRIMARY_QUERY to the DOMAIN<1B> name. As such, BDC on the same subnet need
  239. // not respond to this query.
  240. //
  241. } else if ( (*MessageSize > 2) &&
  242. (*End == LM20_TOKENBYTE) &&
  243. (*(End-1) == LMWFW_TOKENBYTE) ) {
  244. *MessageSize -= 2;
  245. *Version = 0;
  246. return LMWFW_MESSAGE;
  247. }
  248. *Version = 0;
  249. return LMUNKNOWN_MESSAGE;
  250. }
  251. BOOL
  252. NetpLogonGetOemString(
  253. IN PVOID Message,
  254. IN DWORD MessageSize,
  255. IN OUT PCHAR *Where,
  256. IN DWORD MaxStringLength,
  257. OUT LPSTR *String
  258. )
  259. /*++
  260. Routine Description:
  261. Determine if an ASCII string in a message buffer is valid.
  262. Arguments:
  263. Message - Points to a buffer containing the message.
  264. MessageSize - The number of bytes in the message buffer.
  265. Where - Indirectly points to the current location in the buffer. The
  266. string at the current location is validated (i.e., checked to ensure
  267. its length is within the bounds of the message buffer and not too
  268. long). If the string is valid, this current location is updated
  269. to point to the byte following the zero byte in the message buffer.
  270. MaxStringLength - Maximum length (in bytes) of the string including
  271. the zero byte. If the string is longer than this, an error is returned.
  272. String - Returns a pointer to the validated string.
  273. Return Value:
  274. TRUE - the string is valid.
  275. FALSE - the string is invalid.
  276. --*/
  277. {
  278. //
  279. // Validate that the current location is within the buffer
  280. //
  281. if ( ((*Where) < (PCHAR)Message) ||
  282. (MessageSize <= (DWORD)((*Where) - (PCHAR)Message)) ) {
  283. return FALSE;
  284. }
  285. //
  286. // Limit the string to the number of bytes remaining in the message buffer.
  287. //
  288. if ( MessageSize - ((*Where) - (PCHAR)Message) < MaxStringLength ) {
  289. MaxStringLength = MessageSize - (DWORD)((*Where) - (PCHAR)Message);
  290. }
  291. //
  292. // Loop try to find the end of string.
  293. //
  294. *String = *Where;
  295. while ( MaxStringLength-- > 0 ) {
  296. if ( *((*Where)++) == '\0' ) {
  297. return TRUE;
  298. }
  299. }
  300. return FALSE;
  301. }
  302. BOOL
  303. NetpLogonGetUnicodeString(
  304. IN PVOID Message,
  305. IN DWORD MessageSize,
  306. IN OUT PCHAR *Where,
  307. IN DWORD MaxStringSize,
  308. OUT LPWSTR *String
  309. )
  310. /*++
  311. Routine Description:
  312. Determine if a UNICODE string in a message buffer is valid.
  313. UNICODE strings always appear at a 2-byte boundary in the message.
  314. Arguments:
  315. Message - Points to a buffer containing the message.
  316. MessageSize - The number of bytes in the message buffer.
  317. Where - Indirectly points to the current location in the buffer. The
  318. string at the current location is validated (i.e., checked to ensure
  319. its length is within the bounds of the message buffer and not too
  320. long). If the string is valid, this current location is updated
  321. to point to the byte following the zero byte in the message buffer.
  322. MaxStringSize - Maximum size (in bytes) of the string including
  323. the zero byte. If the string is longer than this, an error is
  324. returned.
  325. String - Returns a pointer to the validated string.
  326. Return Value:
  327. TRUE - the string is valid.
  328. FALSE - the string is invalid.
  329. --*/
  330. {
  331. LPWSTR Uwhere;
  332. DWORD MaxStringLength;
  333. //
  334. // Align the unicode string on a WCHAR boundary.
  335. //
  336. *Where = ROUND_UP_POINTER( *Where, ALIGN_WCHAR );
  337. //
  338. // Validate that the current location is within the buffer
  339. //
  340. if ( ((*Where) < (PCHAR)Message) ||
  341. (MessageSize <= (DWORD)((*Where) - (PCHAR)Message)) ) {
  342. return FALSE;
  343. }
  344. //
  345. // Limit the string to the number of bytes remaining in the message buffer.
  346. //
  347. if ( MessageSize - ((*Where) - (PCHAR)Message) < MaxStringSize ) {
  348. MaxStringSize = MessageSize - (DWORD)((*Where) - (PCHAR)Message);
  349. }
  350. //
  351. // Loop try to find the end of string.
  352. //
  353. Uwhere = (LPWSTR) *Where;
  354. MaxStringLength = MaxStringSize / sizeof(WCHAR);
  355. *String = Uwhere;
  356. while ( MaxStringLength-- > 0 ) {
  357. if ( *(Uwhere++) == '\0' ) {
  358. *Where = (PCHAR) Uwhere;
  359. return TRUE;
  360. }
  361. }
  362. return FALSE;
  363. }
  364. #ifndef WIN32_CHICAGO
  365. BOOL
  366. NetpLogonGetDomainSID(
  367. IN PVOID Message,
  368. IN DWORD MessageSize,
  369. IN OUT PCHAR *Where,
  370. IN DWORD SIDSize,
  371. OUT PCHAR *Sid
  372. )
  373. /*++
  374. Routine Description:
  375. Determine if a Domain SID in a message buffer is valid and return
  376. the pointer that is pointing to the SID.
  377. Domain SID always appears at a 4-byte boundary in the message.
  378. Arguments:
  379. Message - Points to a buffer containing the message.
  380. MessageSize - The number of bytes in the message buffer.
  381. Where - Indirectly points to the current location in the buffer. The
  382. string at the current location is validated (i.e., checked to ensure
  383. its length is within the bounds of the message buffer and not too
  384. long). If the string is valid, this current location is updated
  385. to point to the byte following the zero byte in the message buffer.
  386. SIDSize - size (in bytes) of the SID. If there is not
  387. enough bytes in the buffer remaining, an error is returned.
  388. SIDSize should be non-zero.
  389. String - Returns a pointer to the validated SID.
  390. Return Value:
  391. TRUE - the SID is valid.
  392. FALSE - the SID is invalid.
  393. --*/
  394. {
  395. DWORD LocalSIDSize;
  396. //
  397. // Align the current pointer to a DWORD boundary.
  398. //
  399. *Where = ROUND_UP_POINTER( *Where, ALIGN_DWORD );
  400. //
  401. // Validate that the current location is within the buffer
  402. //
  403. if ( ((*Where) < (PCHAR)Message) ||
  404. (MessageSize <= (DWORD)((*Where) - (PCHAR)Message)) ) {
  405. return FALSE;
  406. }
  407. //
  408. // If there are less bytes in the message buffer left than we
  409. // anticipate, return error.
  410. //
  411. if ( MessageSize - ((*Where) - (PCHAR)Message) < SIDSize ) {
  412. return(FALSE);
  413. }
  414. //
  415. // validate SID.
  416. //
  417. LocalSIDSize = RtlLengthSid( *Where );
  418. if( LocalSIDSize != SIDSize ) {
  419. return(FALSE);
  420. }
  421. *Sid = *Where;
  422. *Where += LocalSIDSize;
  423. return(TRUE);
  424. }
  425. #endif // WIN32_CHICAGO
  426. BOOL
  427. NetpLogonGetBytes(
  428. IN PVOID Message,
  429. IN DWORD MessageSize,
  430. IN OUT PCHAR *Where,
  431. IN DWORD DataSize,
  432. OUT LPVOID Data
  433. )
  434. /*++
  435. Routine Description:
  436. Copy binary data from a message buffer.
  437. Arguments:
  438. Message - Points to a buffer containing the message.
  439. MessageSize - The number of bytes in the message buffer.
  440. Where - Indirectly points to the current location in the buffer. The
  441. data at the current location is validated (i.e., checked to ensure
  442. its length is within the bounds of the message buffer and not too
  443. long). If the data is valid, this current location is updated
  444. to point to the byte following the data in the message buffer.
  445. DataSize - Size (in bytes) of the data.
  446. Data - Points to a location to return the valid data.
  447. Return Value:
  448. TRUE - the data is valid.
  449. FALSE - the data is invalid (e.g., DataSize is too big for the buffer.
  450. --*/
  451. {
  452. //
  453. // Validate that the current location is within the buffer
  454. //
  455. if ( ((*Where) < (PCHAR)Message) ||
  456. (MessageSize <= (DWORD)((*Where) - (PCHAR)Message)) ) {
  457. return FALSE;
  458. }
  459. //
  460. // Ensure the entire data fits in the byte remaining in the message buffer.
  461. //
  462. if ( MessageSize - ((*Where) - (PCHAR)Message) < DataSize ) {
  463. return FALSE;
  464. }
  465. //
  466. // Copy the data from the message to the caller's buffer.
  467. //
  468. while ( DataSize-- > 0 ) {
  469. *(((LPBYTE)(Data))++) = *((*Where)++);
  470. }
  471. return TRUE;
  472. }
  473. BOOL
  474. NetpLogonGetDBInfo(
  475. IN PVOID Message,
  476. IN DWORD MessageSize,
  477. IN OUT PCHAR *Where,
  478. OUT PDB_CHANGE_INFO Data
  479. )
  480. /*++
  481. Routine Description:
  482. Get Database info structure from mailsolt buffer.
  483. Arguments:
  484. Message - Points to a buffer containing the message.
  485. MessageSize - The number of bytes in the message buffer.
  486. Where - Indirectly points to the current location in the buffer. The
  487. data at the current location is validated (i.e., checked to ensure
  488. its length is within the bounds of the message buffer and not too
  489. long). If the data is valid, this current location is updated
  490. to point to the byte following the data in the message buffer.
  491. Data - Points to a location to return the database info structure.
  492. Return Value:
  493. TRUE - the data is valid.
  494. FALSE - the data is invalid (e.g., DataSize is too big for the buffer.
  495. --*/
  496. {
  497. //
  498. // Validate that the current location is within the buffer
  499. //
  500. if ( ((*Where) < (PCHAR)Message) ||
  501. (MessageSize <= (DWORD)((*Where) - (PCHAR)Message)) ) {
  502. return FALSE;
  503. }
  504. //
  505. // Ensure the entire data fits in the byte remaining in the message buffer.
  506. //
  507. if ( ( MessageSize - ((*Where) - (PCHAR)Message) ) <
  508. sizeof( DB_CHANGE_INFO ) ) {
  509. return FALSE;
  510. }
  511. if( NetpLogonGetBytes( Message,
  512. MessageSize,
  513. Where,
  514. sizeof(Data->DBIndex),
  515. &(Data->DBIndex) ) == FALSE ) {
  516. return FALSE;
  517. }
  518. if( NetpLogonGetBytes( Message,
  519. MessageSize,
  520. Where,
  521. sizeof(Data->LargeSerialNumber),
  522. &(Data->LargeSerialNumber) ) == FALSE ) {
  523. return FALSE;
  524. }
  525. return ( NetpLogonGetBytes( Message,
  526. MessageSize,
  527. Where,
  528. sizeof(Data->NtDateAndTime),
  529. &(Data->NtDateAndTime) ) );
  530. }
  531. #ifndef WIN32_CHICAGO
  532. LPWSTR
  533. NetpLogonOemToUnicode(
  534. IN LPSTR Ansi
  535. )
  536. /*++
  537. Routine Description:
  538. Convert an ASCII (zero terminated) string to the corresponding UNICODE
  539. string.
  540. Arguments:
  541. Ansi - Specifies the ASCII zero terminated string to convert.
  542. Return Value:
  543. NULL - There was some error in the conversion.
  544. Otherwise, it returns a pointer to the zero terminated UNICODE string in
  545. an allocated buffer. The buffer can be freed using NetpMemoryFree.
  546. --*/
  547. {
  548. OEM_STRING AnsiString;
  549. UNICODE_STRING UnicodeString;
  550. RtlInitString( &AnsiString, Ansi );
  551. UnicodeString.MaximumLength =
  552. (USHORT) RtlOemStringToUnicodeSize( &AnsiString );
  553. UnicodeString.Buffer = NetpMemoryAllocate( UnicodeString.MaximumLength );
  554. if ( UnicodeString.Buffer == NULL ) {
  555. return NULL;
  556. }
  557. if(!NT_SUCCESS( RtlOemStringToUnicodeString( &UnicodeString,
  558. &AnsiString,
  559. FALSE))){
  560. NetpMemoryFree( UnicodeString.Buffer );
  561. return NULL;
  562. }
  563. return UnicodeString.Buffer;
  564. }
  565. LPSTR
  566. NetpLogonUnicodeToOem(
  567. IN LPWSTR Unicode
  568. )
  569. /*++
  570. Routine Description:
  571. Convert an UNICODE (zero terminated) string to the corresponding ASCII
  572. string.
  573. Arguments:
  574. Unicode - Specifies the UNICODE zero terminated string to convert.
  575. Return Value:
  576. NULL - There was some error in the conversion.
  577. Otherwise, it returns a pointer to the zero terminated ASCII string in
  578. an allocated buffer. The buffer can be freed using NetpMemoryFree.
  579. --*/
  580. {
  581. OEM_STRING AnsiString;
  582. UNICODE_STRING UnicodeString;
  583. RtlInitUnicodeString( &UnicodeString, Unicode );
  584. AnsiString.MaximumLength =
  585. (USHORT) RtlUnicodeStringToOemSize( &UnicodeString );
  586. AnsiString.Buffer = NetpMemoryAllocate( AnsiString.MaximumLength );
  587. if ( AnsiString.Buffer == NULL ) {
  588. return NULL;
  589. }
  590. if(!NT_SUCCESS( RtlUpcaseUnicodeStringToOemString( &AnsiString,
  591. &UnicodeString,
  592. FALSE))){
  593. NetpMemoryFree( AnsiString.Buffer );
  594. return NULL;
  595. }
  596. return AnsiString.Buffer;
  597. }
  598. #endif // WIN32_CHICAGO
  599. NET_API_STATUS
  600. NetpLogonWriteMailslot(
  601. IN LPWSTR MailslotName,
  602. IN LPVOID Buffer,
  603. IN DWORD BufferSize
  604. )
  605. /*++
  606. Routine Description:
  607. Write a message to a named mailslot
  608. Arguments:
  609. MailslotName - Unicode name of the mailslot to write to.
  610. Buffer - Data to write to the mailslot.
  611. BufferSize - Number of bytes to write to the mailslot.
  612. Return Value:
  613. NT status code for the operation
  614. --*/
  615. {
  616. NET_API_STATUS NetStatus;
  617. HANDLE MsHandle;
  618. DWORD BytesWritten;
  619. #ifdef WIN32_CHICAGO
  620. UNICODE_STRING UnicodeName;
  621. ANSI_STRING AnsiName;
  622. NTSTATUS Status;
  623. #endif // WIN32_CHICAGO
  624. //
  625. // Open the mailslot
  626. //
  627. IF_DEBUG( LOGON ) {
  628. #ifndef WIN32_CHICAGO
  629. NetpKdPrint(( "[NetpLogonWriteMailslot] OpenFile of '%ws'\n",
  630. MailslotName ));
  631. #endif // WIN32_CHICAGO
  632. }
  633. //
  634. // make sure that the mailslot name is of the form \\server\mailslot ..
  635. //
  636. NetpAssert( (wcsncmp( MailslotName, L"\\\\", 2) == 0) );
  637. #ifndef WIN32_CHICAGO
  638. MsHandle = CreateFileW(
  639. MailslotName,
  640. GENERIC_WRITE,
  641. FILE_SHARE_WRITE | FILE_SHARE_READ,
  642. NULL, // Supply better security ??
  643. OPEN_ALWAYS, // Create if it doesn't exist
  644. FILE_ATTRIBUTE_NORMAL,
  645. NULL ); // No template
  646. #else // WIN32_CHICAGO
  647. MyRtlInitUnicodeString(&UnicodeName, MailslotName);
  648. AnsiName.Buffer = NULL;
  649. Status = MyRtlUnicodeStringToAnsiString(&AnsiName, &UnicodeName, TRUE);
  650. IF_DEBUG( LOGON ) {
  651. #ifdef WIN32_CHICAGO
  652. if ( Status == STATUS_SUCCESS ) {
  653. NlPrint(( NL_MAILSLOT, "[NetpLogonWriteMailslot] OpenFile of '%s'\n",
  654. AnsiName.Buffer));
  655. } else {
  656. NlPrint(( NL_MAILSLOT, "[NetpLogonWriteMailslot] Cannot create AnsiName\n" ));
  657. }
  658. #endif // WIN32_CHICAGO
  659. }
  660. if ( Status != STATUS_SUCCESS ) {
  661. return ERROR_NOT_ENOUGH_MEMORY;
  662. }
  663. MsHandle = CreateFile(
  664. AnsiName.Buffer,
  665. GENERIC_WRITE,
  666. FILE_SHARE_WRITE | FILE_SHARE_READ,
  667. NULL, // Supply better security ??
  668. OPEN_ALWAYS, // Create if it doesn't exist
  669. FILE_ATTRIBUTE_NORMAL,
  670. NULL ); // No template
  671. if ( AnsiName.Buffer != NULL ) {
  672. MyRtlFreeAnsiString( &AnsiName );
  673. }
  674. #endif // WIN32_CHICAGO
  675. if ( MsHandle == (HANDLE) -1 ) {
  676. NetStatus = GetLastError();
  677. IF_DEBUG( LOGON ) {
  678. #ifndef WIN32_CHICAGO
  679. NetpKdPrint(( "[NetpLogonWriteMailslot] OpenFile failed %ld\n",
  680. NetStatus ));
  681. #else // WIN32_CHICAGO
  682. NlPrint(( NL_MAILSLOT, "[NetpLogonWriteMailslot] OpenFile failed %ld\n",
  683. NetStatus ));
  684. #endif // WIN32_CHICAGO
  685. }
  686. //
  687. // Map the generic status code to something more reasonable.
  688. //
  689. if ( NetStatus == ERROR_FILE_NOT_FOUND ||
  690. NetStatus == ERROR_PATH_NOT_FOUND ) {
  691. NetStatus = NERR_NetNotStarted;
  692. }
  693. return NetStatus;
  694. }
  695. //
  696. // Write the message to it.
  697. //
  698. if ( !WriteFile( MsHandle, Buffer, BufferSize, &BytesWritten, NULL)){
  699. NetStatus = GetLastError();
  700. IF_DEBUG( LOGON ) {
  701. #ifndef WIN32_CHICAGO
  702. NetpKdPrint(( "[NetpLogonWriteMailslot] WriteFile failed %ld\n",
  703. NetStatus ));
  704. #else // WIN32_CHICAGO
  705. NlPrint(( NL_MAILSLOT, "[NetpLogonWriteMailslot] WriteFile failed %ld\n",
  706. NetStatus ));
  707. #endif // WIN32_CHICAGO
  708. }
  709. (VOID)CloseHandle( MsHandle );
  710. return NetStatus;
  711. }
  712. if (BytesWritten < BufferSize) {
  713. IF_DEBUG( LOGON ) {
  714. #ifndef WIN32_CHICAGO
  715. NetpKdPrint((
  716. "[NetpLogonWriteMailslot] WriteFile byte written %ld %ld\n",
  717. BytesWritten,
  718. BufferSize));
  719. #else // WIN32_CHICAGO
  720. NlPrint((
  721. NL_MAILSLOT, "[NetpLogonWriteMailslot] WriteFile byte written %ld %ld\n",
  722. BytesWritten,
  723. BufferSize));
  724. #endif // WIN32_CHICAGO
  725. }
  726. (VOID)CloseHandle( MsHandle );
  727. return ERROR_UNEXP_NET_ERR;
  728. }
  729. //
  730. // Close the handle
  731. //
  732. if ( !CloseHandle( MsHandle ) ) {
  733. NetStatus = GetLastError();
  734. IF_DEBUG( LOGON ) {
  735. #ifndef WIN32_CHICAGO
  736. NetpKdPrint(( "[NetpLogonWriteMailslot] CloseHandle failed %ld\n",
  737. NetStatus ));
  738. #else // WIN32_CHICAGO
  739. NlPrint(( NL_MAILSLOT, "[NetpLogonWriteMailslot] CloseHandle failed %ld\n",
  740. NetStatus ));
  741. #endif // WIN32_CHICAGO
  742. }
  743. return NetStatus;
  744. }
  745. return NERR_Success;
  746. }
  747. #define RESPONSE_MAILSLOT_PREFIX "\\MAILSLOT\\NET\\GETDCXXX"
  748. #define RESP_PRE_LEN sizeof(RESPONSE_MAILSLOT_PREFIX)
  749. // Amount of time to wait for a response
  750. #define READ_MAILSLOT_TIMEOUT 5000 // 5 seconds
  751. // number of broadcastings to get DC before reporting DC not found error
  752. #define MAX_DC_RETRIES 3
  753. NET_API_STATUS
  754. NetpLogonCreateRandomMailslot(
  755. IN LPSTR path,
  756. OUT PHANDLE MsHandle
  757. )
  758. /*++
  759. Routine Description:
  760. Create a unique mailslot and return the handle to it.
  761. Arguments:
  762. path - Returns the full path mailslot name
  763. MsHandle - Returns an open handle to the mailslot that was made.
  764. Return Value:
  765. NERR_SUCCESS - Success, path contains the path to a unique mailslot.
  766. otherwise, Unable to create a unique mailslot.
  767. --*/
  768. {
  769. DWORD i;
  770. DWORD play;
  771. char * ext_ptr;
  772. NET_API_STATUS NetStatus;
  773. CHAR LocalPath[RESP_PRE_LEN+4]; // 4 bytes for local mailslot prefix
  774. DWORD LastOneToTry;
  775. //
  776. // We are creating a name of the form \mailslot\net\getdcXXX,
  777. // where XXX are numbers that are "randomized" to allow
  778. // multiple mailslots to be opened.
  779. //
  780. lstrcpyA(path, RESPONSE_MAILSLOT_PREFIX);
  781. //
  782. // Compute the first number to use
  783. //
  784. if( SeedRandomGen == FALSE ) {
  785. //
  786. // SEED random generator
  787. //
  788. srand( (unsigned)time( NULL ) );
  789. SeedRandomGen = TRUE;
  790. }
  791. LastOneToTry = rand() % 1000;
  792. //
  793. // Now try and create a unique filename
  794. // Cannot use current_loc or back up from that and remain DBCS compat.
  795. //
  796. ext_ptr = path + lstrlenA(path) - 3;
  797. for ( i = LastOneToTry + 1; i != LastOneToTry ; i++) {
  798. //
  799. // Wrap back to zero if we reach 1000
  800. //
  801. if ( i == 1000 ) {
  802. i = 0;
  803. }
  804. //
  805. // Convert the number to ascii
  806. //
  807. play = i;
  808. ext_ptr[0] = (char)((play / 100) + '0');
  809. play -= (play / 100) * 100;
  810. ext_ptr[1] = (char)((play / 10) + '0');
  811. ext_ptr[2] = (char)((play % 10) + '0');
  812. //
  813. // Try to create the mailslot.
  814. // Fail the create if the mailslot already exists.
  815. //
  816. lstrcpyA( LocalPath, "\\\\." );
  817. lstrcatA( LocalPath, path );
  818. *MsHandle = CreateMailslotA( LocalPath,
  819. MAX_RANDOM_MAILSLOT_RESPONSE,
  820. READ_MAILSLOT_TIMEOUT,
  821. NULL ); // security attributes
  822. //
  823. // If success,
  824. // return the handle to the caller.
  825. //
  826. if ( *MsHandle != INVALID_HANDLE_VALUE ) {
  827. return(NERR_Success);
  828. }
  829. //
  830. // If there is any error other than the mailsloat already exists,
  831. // return that error to the caller.
  832. //
  833. NetStatus = GetLastError();
  834. if ( NetStatus != ERROR_ALREADY_EXISTS) {
  835. return(NetStatus);
  836. }
  837. }
  838. return(NERR_InternalError); // !!! All 999 mailslots exist
  839. }
  840. BOOLEAN
  841. NetpLogonTimeHasElapsed(
  842. IN LARGE_INTEGER StartTime,
  843. IN DWORD Timeout
  844. )
  845. /*++
  846. Routine Description:
  847. Determine if "Timeout" milliseconds has has elapsed since StartTime.
  848. Arguments:
  849. StartTime - Specifies an absolute time when the event started (100ns units).
  850. Timeout - Specifies a relative time in milliseconds. 0xFFFFFFFF indicates
  851. that the time will never expire.
  852. Return Value:
  853. TRUE -- iff Timeout milliseconds have elapsed since StartTime.
  854. --*/
  855. {
  856. LARGE_INTEGER TimeNow;
  857. LARGE_INTEGER ElapsedTime;
  858. LARGE_INTEGER Period;
  859. //
  860. // If the period to too large to handle (i.e., 0xffffffff is forever),
  861. // just indicate that the timer has not expired.
  862. //
  863. // (0xffffffff is a little over 48 days).
  864. //
  865. if ( Timeout == 0xffffffff ) {
  866. return FALSE;
  867. }
  868. //
  869. // Compute the elapsed time since we last authenticated
  870. //
  871. GetSystemTimeAsFileTime( (PFILETIME)&TimeNow );
  872. ElapsedTime.QuadPart = TimeNow.QuadPart - StartTime.QuadPart;
  873. //
  874. // Compute Period from milliseconds into 100ns units.
  875. //
  876. Period.QuadPart = UInt32x32To64( Timeout, 10000 );
  877. //
  878. // If the elapsed time is negative (totally bogus) or greater than the
  879. // maximum allowed, indicate that enough time has passed.
  880. //
  881. if ( ElapsedTime.QuadPart < 0 || ElapsedTime.QuadPart > Period.QuadPart ) {
  882. return TRUE;
  883. }
  884. return FALSE;
  885. }
  886. #ifndef WIN32_CHICAGO
  887. NET_API_STATUS
  888. NlWriteFileForestTrustList (
  889. IN LPWSTR FileSuffix,
  890. IN PDS_DOMAIN_TRUSTSW ForestTrustList,
  891. IN ULONG ForestTrustListCount
  892. )
  893. /*++
  894. Routine Description:
  895. Set the Forest Trust List into the binary file to save it across reboots.
  896. Arguments:
  897. FileSuffix - Specifies the name of the file to write (relative to the
  898. Windows directory)
  899. ForestTrustList - Specifies a list of trusted domains.
  900. ForestTrustListCount - Number of entries in ForestTrustList
  901. Return Value:
  902. Status of the operation.
  903. --*/
  904. {
  905. NET_API_STATUS NetStatus;
  906. PDS_DISK_TRUSTED_DOMAIN_HEADER RecordBuffer = NULL;
  907. PDS_DISK_TRUSTED_DOMAINS LogEntry;
  908. ULONG RecordBufferSize;
  909. ULONG Index;
  910. //
  911. // Determine the size of the file
  912. //
  913. RecordBufferSize = ROUND_UP_COUNT( sizeof(DS_DISK_TRUSTED_DOMAIN_HEADER), ALIGN_WORST );
  914. for ( Index=0; Index<ForestTrustListCount; Index++ ) {
  915. RecordBufferSize += sizeof( DS_DISK_TRUSTED_DOMAINS );
  916. if ( ForestTrustList[Index].DomainSid != NULL ) {
  917. RecordBufferSize += RtlLengthSid( ForestTrustList[Index].DomainSid );
  918. }
  919. if ( ForestTrustList[Index].NetbiosDomainName != NULL ) {
  920. RecordBufferSize += wcslen(ForestTrustList[Index].NetbiosDomainName) * sizeof(WCHAR) + sizeof(WCHAR);
  921. }
  922. if ( ForestTrustList[Index].DnsDomainName != NULL ) {
  923. RecordBufferSize += wcslen(ForestTrustList[Index].DnsDomainName) * sizeof(WCHAR) + sizeof(WCHAR);
  924. }
  925. RecordBufferSize = ROUND_UP_COUNT( RecordBufferSize, ALIGN_WORST );
  926. }
  927. //
  928. // Allocate a buffer
  929. //
  930. RecordBuffer = LocalAlloc( LMEM_ZEROINIT, RecordBufferSize );
  931. if ( RecordBuffer == NULL ) {
  932. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  933. goto Cleanup;
  934. }
  935. //
  936. // Copy the Forest Trust List to the buffer.
  937. //
  938. RecordBuffer->Version = DS_DISK_TRUSTED_DOMAIN_VERSION;
  939. LogEntry = (PDS_DISK_TRUSTED_DOMAINS)ROUND_UP_POINTER( (RecordBuffer + 1), ALIGN_WORST );
  940. for ( Index=0; Index<ForestTrustListCount; Index++ ) {
  941. ULONG CurrentSize;
  942. LPBYTE Where;
  943. ULONG DomainSidSize;
  944. ULONG NetbiosDomainNameSize;
  945. ULONG DnsDomainNameSize;
  946. //
  947. // Compute the size of this entry.
  948. //
  949. CurrentSize = sizeof( DS_DISK_TRUSTED_DOMAINS );
  950. if ( ForestTrustList[Index].DomainSid != NULL ) {
  951. DomainSidSize = RtlLengthSid( ForestTrustList[Index].DomainSid );
  952. CurrentSize += DomainSidSize;
  953. }
  954. if ( ForestTrustList[Index].NetbiosDomainName != NULL ) {
  955. NetbiosDomainNameSize = wcslen(ForestTrustList[Index].NetbiosDomainName) * sizeof(WCHAR) + sizeof(WCHAR);
  956. CurrentSize += NetbiosDomainNameSize;
  957. }
  958. if ( ForestTrustList[Index].DnsDomainName != NULL ) {
  959. DnsDomainNameSize = wcslen(ForestTrustList[Index].DnsDomainName) * sizeof(WCHAR) + sizeof(WCHAR);
  960. CurrentSize += DnsDomainNameSize;
  961. }
  962. CurrentSize = ROUND_UP_COUNT( CurrentSize, ALIGN_WORST );
  963. //
  964. // Put the constant size fields in the buffer.
  965. //
  966. LogEntry->EntrySize = CurrentSize;
  967. LogEntry->Flags = ForestTrustList[Index].Flags;
  968. LogEntry->ParentIndex = ForestTrustList[Index].ParentIndex;
  969. LogEntry->TrustType = ForestTrustList[Index].TrustType;
  970. LogEntry->TrustAttributes = ForestTrustList[Index].TrustAttributes;
  971. LogEntry->DomainGuid = ForestTrustList[Index].DomainGuid;
  972. //
  973. // Copy the variable length entries.
  974. //
  975. Where = (LPBYTE) (LogEntry+1);
  976. if ( ForestTrustList[Index].DomainSid != NULL ) {
  977. RtlCopyMemory( Where, ForestTrustList[Index].DomainSid, DomainSidSize );
  978. Where += DomainSidSize;
  979. LogEntry->DomainSidSize = DomainSidSize;
  980. }
  981. if ( ForestTrustList[Index].NetbiosDomainName != NULL ) {
  982. RtlCopyMemory( Where, ForestTrustList[Index].NetbiosDomainName, NetbiosDomainNameSize );
  983. Where += NetbiosDomainNameSize;
  984. LogEntry->NetbiosDomainNameSize = NetbiosDomainNameSize;
  985. }
  986. if ( ForestTrustList[Index].DnsDomainName != NULL ) {
  987. RtlCopyMemory( Where, ForestTrustList[Index].DnsDomainName, DnsDomainNameSize );
  988. Where += DnsDomainNameSize;
  989. LogEntry->DnsDomainNameSize = DnsDomainNameSize;
  990. }
  991. Where = ROUND_UP_POINTER( Where, ALIGN_WORST );
  992. ASSERT( (ULONG)(Where-(LPBYTE)LogEntry) == CurrentSize );
  993. ASSERT( (ULONG)(Where-(LPBYTE)RecordBuffer) <=RecordBufferSize );
  994. //
  995. // Move on to the next entry.
  996. //
  997. LogEntry = (PDS_DISK_TRUSTED_DOMAINS)Where;
  998. }
  999. //
  1000. // Write the buffer to the file.
  1001. //
  1002. NetStatus = NlWriteBinaryLog(
  1003. FileSuffix,
  1004. (LPBYTE) RecordBuffer,
  1005. RecordBufferSize );
  1006. if ( NetStatus != NO_ERROR ) {
  1007. #ifdef _NETLOGON_SERVER
  1008. LPWSTR MsgStrings[2];
  1009. MsgStrings[0] = FileSuffix,
  1010. MsgStrings[1] = (LPWSTR) NetStatus;
  1011. NlpWriteEventlog (NELOG_NetlogonFailedFileCreate,
  1012. EVENTLOG_ERROR_TYPE,
  1013. (LPBYTE) &NetStatus,
  1014. sizeof(NetStatus),
  1015. MsgStrings,
  1016. 2 | NETP_LAST_MESSAGE_IS_NETSTATUS );
  1017. #endif // _NETLOGON_SERVER
  1018. goto Cleanup;
  1019. }
  1020. //
  1021. // Be tidy.
  1022. //
  1023. Cleanup:
  1024. if ( RecordBuffer != NULL ) {
  1025. LocalFree( RecordBuffer );
  1026. }
  1027. return NetStatus;
  1028. }
  1029. NET_API_STATUS
  1030. NlWriteBinaryLog(
  1031. IN LPWSTR FileSuffix,
  1032. IN LPBYTE Buffer,
  1033. IN ULONG BufferSize
  1034. )
  1035. /*++
  1036. Routine Description:
  1037. Write a buffer to a file.
  1038. Arguments:
  1039. FileSuffix - Specifies the name of the file to write (relative to the
  1040. Windows directory)
  1041. Buffer - Buffer to write
  1042. BufferSize - Size (in bytes) of buffer
  1043. Return Value:
  1044. None.
  1045. --*/
  1046. {
  1047. NET_API_STATUS NetStatus;
  1048. LPWSTR FileName = NULL;
  1049. UINT WindowsDirectoryLength;
  1050. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  1051. ULONG BytesWritten;
  1052. ULONG CurrentSize;
  1053. //
  1054. // Allocate a block to build the file name in
  1055. //
  1056. FileName = LocalAlloc( LMEM_ZEROINIT, sizeof(WCHAR) * (MAX_PATH+1) );
  1057. if ( FileName == NULL ) {
  1058. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  1059. goto Cleanup;
  1060. }
  1061. //
  1062. // Build the name of the log file
  1063. //
  1064. WindowsDirectoryLength = GetSystemWindowsDirectoryW(
  1065. FileName,
  1066. sizeof(WCHAR) * (MAX_PATH+1) );
  1067. if ( WindowsDirectoryLength == 0 ) {
  1068. NetStatus = GetLastError();
  1069. NetpKdPrint(( "NlWriteBinaryLog: Unable to GetWindowsDirectoryW (%ld)\n",
  1070. NetStatus ));
  1071. goto Cleanup;
  1072. }
  1073. if ( WindowsDirectoryLength + wcslen( FileSuffix ) + 1 >= MAX_PATH ) {
  1074. NetpKdPrint(( "NlWriteBinaryLog: file name length is too long \n" ));
  1075. NetStatus = ERROR_INVALID_NAME;
  1076. goto Cleanup;
  1077. }
  1078. wcscat( FileName, FileSuffix );
  1079. //
  1080. // Create a file to write to.
  1081. // If it exists already then truncate it.
  1082. //
  1083. FileHandle = CreateFileW(
  1084. FileName,
  1085. GENERIC_READ | GENERIC_WRITE,
  1086. FILE_SHARE_READ, // allow backups and debugging
  1087. NULL, // Supply better security ??
  1088. CREATE_ALWAYS, // Overwrites always
  1089. FILE_ATTRIBUTE_NORMAL,
  1090. NULL ); // No template
  1091. if ( FileHandle == INVALID_HANDLE_VALUE) {
  1092. NetStatus = GetLastError();
  1093. NetpKdPrint(( "NlWriteBinaryLog: %ws: Unable to create file: %ld \n",
  1094. FileName,
  1095. NetStatus));
  1096. goto Cleanup;
  1097. }
  1098. if ( !WriteFile( FileHandle,
  1099. Buffer,
  1100. BufferSize,
  1101. &BytesWritten,
  1102. NULL ) ) { // Not Overlapped
  1103. NetStatus = GetLastError();
  1104. NetpKdPrint(( "NlWriteBinaryLog: %ws: Unable to WriteFile. %ld\n",
  1105. FileName,
  1106. NetStatus ));
  1107. goto Cleanup;
  1108. }
  1109. if ( BytesWritten != BufferSize) {
  1110. NetpKdPrint(( "NlWriteBinaryLog: %ws: Write bad byte count %ld s.b. %ld\n",
  1111. FileName,
  1112. BytesWritten,
  1113. BufferSize ));
  1114. NetStatus = ERROR_INSUFFICIENT_BUFFER;
  1115. goto Cleanup;
  1116. }
  1117. NetStatus = NO_ERROR;
  1118. //
  1119. // Be tidy.
  1120. //
  1121. Cleanup:
  1122. if ( FileName != NULL ) {
  1123. LocalFree( FileName );
  1124. }
  1125. if ( FileHandle != INVALID_HANDLE_VALUE ) {
  1126. CloseHandle( FileHandle );
  1127. }
  1128. return NetStatus;
  1129. }
  1130. #endif // WIN32_CHICAGO