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.

2370 lines
59 KiB

  1. /*++
  2. Copyright (c) 1987-1996 Microsoft Corporation
  3. Module Name:
  4. nlp.c
  5. Abstract:
  6. Private Netlogon service utility routines.
  7. Author:
  8. Cliff Van Dyke (cliffv) 7-Jun-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. 08-May-1992 JohnRo
  15. Use net config helpers for NetLogon.
  16. Use <prefix.h> equates.
  17. --*/
  18. //
  19. // Common include files.
  20. //
  21. #include "logonsrv.h" // Include files common to entire service
  22. #include <rpcasync.h>
  23. #pragma hdrstop
  24. // Include this again to declare the globals
  25. #define DEBUG_ALLOCATE
  26. #include <nldebug.h> // Netlogon debugging
  27. #undef DEBUG_ALLOCATE
  28. //
  29. // Include files specific to this .c file
  30. //
  31. #include <winerror.h> // NO_ERROR
  32. #include <prefix.h> // PREFIX_ equates.
  33. #include <stdarg.h> // va_list, etc.
  34. #include <stdio.h> // vsprintf().
  35. #include <tstr.h> // TCHAR_ equates.
  36. LPWSTR
  37. NlStringToLpwstr(
  38. IN PUNICODE_STRING String
  39. )
  40. /*++
  41. Routine Description:
  42. Convert a Unicode String to an LPWSTR.
  43. Arguments:
  44. String - Unicode String to copy
  45. Return Value:
  46. LPWSTR in a NetpMemoryAllocate'd buffer.
  47. NULL is returned if there is no memory.
  48. --*/
  49. {
  50. LPWSTR Buffer;
  51. Buffer = NetpMemoryAllocate( String->Length + sizeof(WCHAR) );
  52. if ( Buffer != NULL ) {
  53. RtlCopyMemory( Buffer, String->Buffer, String->Length );
  54. Buffer[ String->Length / sizeof(WCHAR) ] = L'\0';
  55. }
  56. return Buffer;
  57. }
  58. BOOLEAN
  59. NlAllocStringFromWStr(
  60. IN LPWSTR InString,
  61. OUT PUNICODE_STRING OutString
  62. )
  63. /*++
  64. Routine Description:
  65. Convert a zero terminated string into an allocated UNICODE_STRING structure.
  66. Arguments:
  67. InString - String to copy
  68. OutString - String to copy into.
  69. OutString->Buffer should be freed using MIDL_user_free
  70. Return Value:
  71. TRUE - success
  72. FALSE - couldn't allocate memory
  73. --*/
  74. {
  75. if ( InString == NULL ) {
  76. OutString->Length = 0;
  77. OutString->MaximumLength = 0;
  78. OutString->Buffer = NULL;
  79. } else {
  80. OutString->Length = wcslen(InString) * sizeof(WCHAR);
  81. OutString->MaximumLength = OutString->Length + sizeof(WCHAR);
  82. OutString->Buffer = MIDL_user_allocate( OutString->MaximumLength );
  83. if ( OutString->Buffer == NULL ) {
  84. return FALSE;
  85. }
  86. RtlCopyMemory( OutString->Buffer,
  87. InString,
  88. OutString->MaximumLength );
  89. }
  90. return TRUE;
  91. }
  92. BOOLEAN
  93. NlDuplicateUnicodeString(
  94. IN PUNICODE_STRING InString OPTIONAL,
  95. OUT PUNICODE_STRING OutString
  96. )
  97. /*++
  98. Routine Description:
  99. Convert a UNICODE_STRING string into an allocated UNICODE_STRING structure.
  100. Arguments:
  101. InString - String to copy
  102. OutString - String to copy into.
  103. OutString should be freed using NlFreeUnicodeString
  104. Return Value:
  105. TRUE - success
  106. FALSE - couldn't allocate memory
  107. --*/
  108. {
  109. if ( InString == NULL || InString->Length == 0 ) {
  110. OutString->Length = 0;
  111. OutString->MaximumLength = 0;
  112. OutString->Buffer = NULL;
  113. } else {
  114. OutString->Length = InString->Length;
  115. OutString->MaximumLength = OutString->Length + sizeof(WCHAR);
  116. OutString->Buffer = MIDL_user_allocate( OutString->MaximumLength );
  117. if ( OutString->Buffer == NULL ) {
  118. return FALSE;
  119. }
  120. RtlCopyMemory( OutString->Buffer,
  121. InString->Buffer,
  122. OutString->Length );
  123. OutString->Buffer[OutString->Length/sizeof(WCHAR)] = L'\0';
  124. }
  125. return TRUE;
  126. }
  127. VOID
  128. NlFreeUnicodeString(
  129. IN PUNICODE_STRING InString OPTIONAL
  130. )
  131. /*++
  132. Routine Description:
  133. Free the UNICODE_STRING structure allocated by NlDuplicateUnicodeString.
  134. Arguments:
  135. InString - String to free
  136. Return Value:
  137. None.
  138. --*/
  139. {
  140. if ( InString != NULL ) {
  141. if ( InString->Buffer != NULL ) {
  142. MIDL_user_free( InString->Buffer );
  143. }
  144. InString->Length = 0;
  145. InString->MaximumLength = 0;
  146. InString->Buffer = NULL;
  147. }
  148. }
  149. LPSTR
  150. NlStringToLpstr(
  151. IN PUNICODE_STRING String
  152. )
  153. /*++
  154. Routine Description:
  155. Convert a Unicode String to an LPSTR.
  156. Arguments:
  157. String - Unicode String to copy
  158. Return Value:
  159. LPWSTR in a NetpMemoryAllocate'd buffer.
  160. NULL is returned if there is no memory.
  161. --*/
  162. {
  163. NTSTATUS Status;
  164. STRING OemString;
  165. OemString.MaximumLength = (USHORT) RtlUnicodeStringToOemSize( String );
  166. OemString.Buffer = NetpMemoryAllocate( OemString.MaximumLength );
  167. if ( OemString.Buffer != NULL ) {
  168. Status = RtlUnicodeStringToOemString( &OemString,
  169. String,
  170. (BOOLEAN) FALSE );
  171. if ( !NT_SUCCESS( Status ) ) {
  172. NetpMemoryFree( OemString.Buffer );
  173. return NULL;
  174. }
  175. }
  176. return OemString.Buffer;
  177. }
  178. VOID
  179. NlpPutString(
  180. IN PUNICODE_STRING OutString,
  181. IN PUNICODE_STRING InString,
  182. IN PUCHAR *Where
  183. )
  184. /*++
  185. Routine Description:
  186. This routine copies the InString string to the memory pointed to by
  187. the Where parameter, and fixes the OutString string to point to that
  188. new copy.
  189. Parameters:
  190. OutString - A pointer to a destination NT string
  191. InString - A pointer to an NT string to be copied
  192. Where - A pointer to space to put the actual string for the
  193. OutString. The pointer is adjusted to point to the first byte
  194. following the copied string.
  195. Return Values:
  196. None.
  197. --*/
  198. {
  199. NlAssert( OutString != NULL );
  200. NlAssert( InString != NULL );
  201. NlAssert( Where != NULL && *Where != NULL);
  202. NlAssert( *Where == ROUND_UP_POINTER( *Where, sizeof(WCHAR) ) );
  203. #ifdef notdef
  204. KdPrint(("NlpPutString: %ld %Z\n", InString->Length, InString ));
  205. KdPrint((" InString: %lx %lx OutString: %lx Where: %lx\n", InString,
  206. InString->Buffer, OutString, *Where ));
  207. #endif
  208. if ( InString->Length > 0 ) {
  209. OutString->Buffer = (PWCH) *Where;
  210. OutString->MaximumLength = (USHORT)(InString->Length + sizeof(WCHAR));
  211. RtlCopyUnicodeString( OutString, InString );
  212. *Where += InString->Length;
  213. // *((WCHAR *)(*Where)) = L'\0';
  214. *(*Where) = '\0';
  215. *(*Where + 1) = '\0';
  216. *Where += 2;
  217. } else {
  218. RtlInitUnicodeString(OutString, NULL);
  219. }
  220. #ifdef notdef
  221. KdPrint((" OutString: %ld %lx\n", OutString->Length, OutString->Buffer));
  222. #endif
  223. return;
  224. }
  225. VOID
  226. NlpWriteEventlogEx (
  227. IN DWORD EventId,
  228. IN DWORD EventType,
  229. IN LPBYTE RawDataBuffer OPTIONAL,
  230. IN DWORD RawDataSize,
  231. IN LPWSTR *StringArray,
  232. IN DWORD StringCount,
  233. IN DWORD StatusMessageIndex
  234. )
  235. /*++
  236. Routine Description:
  237. Stub routine for calling Event Log.
  238. Arguments:
  239. EventId - event log ID.
  240. EventType - Type of event.
  241. RawDataBuffer - Data to be logged with the error.
  242. numbyte - Size in bytes of "RawDataBuffer"
  243. StringArray - array of null-terminated strings.
  244. StringCount - number of zero terminated strings in "StringArray". The following
  245. flags can be OR'd in to the count:
  246. LAST_MESSAGE_IS_NTSTATUS
  247. LAST_MESSAGE_IS_NETSTATUS
  248. ALLOW_DUPLICATE_EVENTS
  249. RAISE_ALERT_TOO
  250. StatusMessageIndex - Specifies the index of the message that is
  251. a Net or NT status in the StringArray. Used only if
  252. NETP_LAST_MESSAGE_IS_NETSTATUS or NETP_LAST_MESSAGE_IS_NTSTATUS
  253. are set in StringCount. If this parameter is MAXULONG and either
  254. of these flags is set, the default is assumed which is the last
  255. message in the list.
  256. Return Value:
  257. TRUE: The message was written.
  258. --*/
  259. {
  260. DWORD ErrorCode;
  261. DWORD ActualStringCount = StringCount & NETP_STRING_COUNT_MASK;
  262. DWORD LocalStatusMessageIndex = StatusMessageIndex;
  263. BOOLEAN StatusPresent = FALSE;
  264. //
  265. // Check if the status message index in the list
  266. // should be assigned the default value
  267. //
  268. if ( (StringCount & NETP_LAST_MESSAGE_IS_NETSTATUS) != 0 ||
  269. (StringCount & NETP_LAST_MESSAGE_IS_NTSTATUS) != 0 ) {
  270. StatusPresent = TRUE;
  271. if ( LocalStatusMessageIndex == MAXULONG ) {
  272. LocalStatusMessageIndex = ActualStringCount - 1;
  273. }
  274. }
  275. //
  276. // If an NT status code was passed in,
  277. // convert it to a net status code.
  278. //
  279. if ( StringCount & NETP_LAST_MESSAGE_IS_NTSTATUS ) {
  280. //
  281. // Do the "better" error mapping when eventviewer ParameterMessageFile
  282. // can be a list of files. Then, add netmsg.dll to the list.
  283. //
  284. // StringArray[ActualStringCount-1] = (LPWSTR) NetpNtStatusToApiStatus( (NTSTATUS) StringArray[ActualStringCount-1] );
  285. if ( (NTSTATUS)(ULONG_PTR)StringArray[LocalStatusMessageIndex] == STATUS_SYNCHRONIZATION_REQUIRED ) {
  286. StringArray[LocalStatusMessageIndex] = (LPWSTR) NERR_SyncRequired;
  287. StringCount &= ~NETP_LAST_MESSAGE_IS_NTSTATUS;
  288. StringCount |= NETP_LAST_MESSAGE_IS_NETSTATUS;
  289. }
  290. }
  291. //
  292. // Dump the event to the debug file.
  293. //
  294. #if NETLOGONDBG
  295. IF_NL_DEBUG( MISC ) {
  296. DWORD i;
  297. NlPrint((NL_MISC, "Eventlog: %ld (%ld) ",
  298. EventId,
  299. EventType ));
  300. for (i = 0; i < ActualStringCount ; i++ ) {
  301. if ( StatusPresent && i == LocalStatusMessageIndex ) {
  302. if ( StringCount & NETP_LAST_MESSAGE_IS_NTSTATUS ) {
  303. NlPrint((NL_MISC, "0x%lx ", StringArray[i] ));
  304. } else if ( StringCount & NETP_LAST_MESSAGE_IS_NETSTATUS ) {
  305. NlPrint((NL_MISC, "%ld ", StringArray[i] ));
  306. } else {
  307. NlPrint((NL_MISC, "\"%ws\" ", StringArray[i] ));
  308. }
  309. } else {
  310. NlPrint((NL_MISC, "\"%ws\" ", StringArray[i] ));
  311. }
  312. }
  313. if( RawDataSize ) {
  314. if ( RawDataSize > 16 ) {
  315. NlPrint((NL_MISC, "\n" ));
  316. }
  317. NlpDumpBuffer( NL_MISC, RawDataBuffer, RawDataSize );
  318. } else {
  319. NlPrint((NL_MISC, "\n" ));
  320. }
  321. }
  322. #endif // NETLOGONDBG
  323. //
  324. // Write the event and avoid duplicates
  325. //
  326. ErrorCode = NetpEventlogWriteEx2 (
  327. NlGlobalEventlogHandle,
  328. EventType,
  329. 0, // event category
  330. EventId,
  331. StringCount,
  332. StatusMessageIndex,
  333. RawDataSize,
  334. StringArray,
  335. RawDataBuffer );
  336. if( ErrorCode != NO_ERROR ) {
  337. if ( ErrorCode == ERROR_ALREADY_EXISTS ) {
  338. NlPrint((NL_MISC,
  339. "Didn't log event since it was already logged.\n" ));
  340. } else {
  341. NlPrint((NL_CRITICAL,
  342. "Error writing this event in the eventlog, Status = %ld\n",
  343. ErrorCode ));
  344. }
  345. goto Cleanup;
  346. }
  347. Cleanup:
  348. return;
  349. }
  350. VOID
  351. NlpWriteEventlog (
  352. IN DWORD EventId,
  353. IN DWORD EventType,
  354. IN LPBYTE RawDataBuffer OPTIONAL,
  355. IN DWORD RawDataSize,
  356. IN LPWSTR *StringArray,
  357. IN DWORD StringCount
  358. )
  359. /*++
  360. Routine Description:
  361. Stub routine for calling Event Log.
  362. Arguments:
  363. Same as NlpWriteEventlogEx except that the status message
  364. index is defaulted to the last message index in the
  365. passed list.
  366. Return Value:
  367. None
  368. --*/
  369. {
  370. NlpWriteEventlogEx ( EventId,
  371. EventType,
  372. RawDataBuffer,
  373. RawDataSize,
  374. StringArray,
  375. StringCount,
  376. MAXULONG ); // default status message index
  377. }
  378. #if NETLOGONDBG
  379. VOID
  380. NlpDumpBuffer(
  381. IN DWORD DebugFlag,
  382. PVOID Buffer,
  383. DWORD BufferSize
  384. )
  385. /*++
  386. Routine Description:
  387. Dumps the buffer content on to the debugger output.
  388. Arguments:
  389. DebugFlag: Debug flag to pass on to NlPrintRoutine
  390. Buffer: buffer pointer.
  391. BufferSize: size of the buffer.
  392. Return Value:
  393. none
  394. --*/
  395. {
  396. #define NUM_CHARS 16
  397. DWORD i, limit;
  398. CHAR TextBuffer[NUM_CHARS + 1];
  399. LPBYTE BufferPtr = Buffer;
  400. BOOLEAN DumpDwords = FALSE;
  401. //
  402. // If we aren't debugging this functionality, just return.
  403. //
  404. if ( (NlGlobalParameters.DbFlag & DebugFlag) == 0 ) {
  405. return;
  406. }
  407. //
  408. // Don't want to intermingle output from different threads.
  409. //
  410. EnterCriticalSection( &NlGlobalLogFileCritSect );
  411. if ( BufferSize > NUM_CHARS ) {
  412. NlPrint((0,"\n")); // Ensure this starts on a new line
  413. NlPrint((0,"------------------------------------\n"));
  414. } else {
  415. if ( BufferSize % sizeof(DWORD) == 0 ) {
  416. DumpDwords = TRUE;
  417. }
  418. }
  419. //
  420. // Hex dump of the bytes
  421. //
  422. limit = ((BufferSize - 1) / NUM_CHARS + 1) * NUM_CHARS;
  423. for (i = 0; i < limit; i++) {
  424. if (i < BufferSize) {
  425. if ( DumpDwords ) {
  426. if ( i % sizeof(DWORD) == 0 ) {
  427. DWORD ADword;
  428. RtlCopyMemory( &ADword, &BufferPtr[i], sizeof(DWORD) );
  429. NlPrint((0,"%08x ", ADword));
  430. }
  431. } else {
  432. NlPrint((0,"%02x ", BufferPtr[i]));
  433. }
  434. if ( isprint(BufferPtr[i]) ) {
  435. TextBuffer[i % NUM_CHARS] = (CHAR) BufferPtr[i];
  436. } else {
  437. TextBuffer[i % NUM_CHARS] = '.';
  438. }
  439. } else {
  440. if ( DumpDwords ) {
  441. TextBuffer[i % NUM_CHARS] = '\0';
  442. } else {
  443. if ( BufferSize > NUM_CHARS ) {
  444. NlPrint((0," "));
  445. TextBuffer[i % NUM_CHARS] = ' ';
  446. } else {
  447. TextBuffer[i % NUM_CHARS] = '\0';
  448. }
  449. }
  450. }
  451. if ((i + 1) % NUM_CHARS == 0) {
  452. TextBuffer[NUM_CHARS] = 0;
  453. NlPrint((0," %s\n", TextBuffer));
  454. }
  455. }
  456. if ( BufferSize > NUM_CHARS ) {
  457. NlPrint((0,"------------------------------------\n"));
  458. } else if ( BufferSize < NUM_CHARS ) {
  459. NlPrint((0,"\n"));
  460. }
  461. LeaveCriticalSection( &NlGlobalLogFileCritSect );
  462. }
  463. VOID
  464. NlpDumpGuid(
  465. IN DWORD DebugFlag,
  466. IN GUID *Guid OPTIONAL
  467. )
  468. /*++
  469. Routine Description:
  470. Dumps a GUID to the debugger output.
  471. Arguments:
  472. DebugFlag: Debug flag to pass on to NlPrintRoutine
  473. Guid: Guid to print
  474. Return Value:
  475. none
  476. --*/
  477. {
  478. RPC_STATUS RpcStatus;
  479. char *StringGuid;
  480. //
  481. // If we aren't debugging this functionality, just return.
  482. //
  483. if ( (NlGlobalParameters.DbFlag & DebugFlag) == 0 ) {
  484. return;
  485. }
  486. if ( Guid == NULL ) {
  487. NlPrint(( DebugFlag, "(null)" ));
  488. } else {
  489. RpcStatus = UuidToStringA( Guid, &StringGuid );
  490. if ( RpcStatus != RPC_S_OK ) {
  491. return;
  492. }
  493. NlPrint(( DebugFlag, "%s", StringGuid ));
  494. RpcStringFreeA( &StringGuid );
  495. }
  496. }
  497. VOID
  498. NlpDumpPeriod(
  499. IN DWORD DebugFlag,
  500. IN LPSTR Comment,
  501. IN ULONG Period
  502. )
  503. /*++
  504. Routine Description:
  505. Print an elapsed time (in milliseconds)
  506. Arguments:
  507. DebugFlag - Debug flag to pass on to NlPrintRoutine
  508. Comment - Comment to print in front of the time
  509. Period - Time period (in milliseconds)
  510. Return Value:
  511. None
  512. --*/
  513. {
  514. //
  515. // Convert the period to something easily readable
  516. //
  517. if ( Period == MAILSLOT_WAIT_FOREVER ) {
  518. NlPrint(( DebugFlag,
  519. "%s 'never' (0x%lx)\n",
  520. Comment,
  521. Period ));
  522. } else if ( (Period / NL_MILLISECONDS_PER_DAY) != 0 ) {
  523. NlPrint(( DebugFlag,
  524. "%s %ld days (0x%lx)\n",
  525. Comment,
  526. Period / NL_MILLISECONDS_PER_DAY,
  527. Period ));
  528. } else if ( (Period / NL_MILLISECONDS_PER_HOUR) != 0 ) {
  529. NlPrint(( DebugFlag,
  530. "%s %ld hours (0x%lx)\n",
  531. Comment,
  532. Period / NL_MILLISECONDS_PER_HOUR,
  533. Period ));
  534. } else if ( (Period / NL_MILLISECONDS_PER_MINUTE) != 0 ) {
  535. NlPrint(( DebugFlag,
  536. "%s %ld minutes (0x%lx)\n",
  537. Comment,
  538. Period / NL_MILLISECONDS_PER_MINUTE,
  539. Period ));
  540. } else {
  541. NlPrint(( DebugFlag,
  542. "%s %ld seconds (0x%lx)\n",
  543. Comment,
  544. Period / NL_MILLISECONDS_PER_SECOND,
  545. Period ));
  546. }
  547. }
  548. VOID
  549. NlpDumpTime(
  550. IN DWORD DebugFlag,
  551. IN LPSTR Comment,
  552. IN LARGE_INTEGER ConvertTime
  553. )
  554. /*++
  555. Routine Description:
  556. Print the specified time
  557. Arguments:
  558. DebugFlag - Debug flag to pass on to NlPrintRoutine
  559. Comment - Comment to print in front of the time
  560. Time - GMT time to print (Nothing is printed if this is zero)
  561. Return Value:
  562. None
  563. --*/
  564. {
  565. //
  566. // If we aren't debugging this functionality, just return.
  567. //
  568. if ( (NlGlobalParameters.DbFlag & DebugFlag) == 0 ) {
  569. return;
  570. }
  571. //
  572. // Convert an NT GMT time to ascii,
  573. // Do so
  574. //
  575. if ( ConvertTime.QuadPart != 0 ) {
  576. LARGE_INTEGER LocalTime;
  577. TIME_FIELDS TimeFields;
  578. NTSTATUS Status;
  579. Status = RtlSystemTimeToLocalTime( &ConvertTime, &LocalTime );
  580. if ( !NT_SUCCESS( Status )) {
  581. NlPrint(( NL_CRITICAL, "Can't convert time from GMT to Local time\n" ));
  582. LocalTime = ConvertTime;
  583. }
  584. RtlTimeToTimeFields( &LocalTime, &TimeFields );
  585. NlPrint(( DebugFlag, "%s%8.8lx %8.8lx = %ld/%ld/%ld %ld:%2.2ld:%2.2ld\n",
  586. Comment,
  587. ConvertTime.LowPart,
  588. ConvertTime.HighPart,
  589. TimeFields.Month,
  590. TimeFields.Day,
  591. TimeFields.Year,
  592. TimeFields.Hour,
  593. TimeFields.Minute,
  594. TimeFields.Second ));
  595. }
  596. }
  597. VOID
  598. NlpDumpSid(
  599. IN DWORD DebugFlag,
  600. IN PSID Sid OPTIONAL
  601. )
  602. /*++
  603. Routine Description:
  604. Dumps a SID to the debugger output
  605. Arguments:
  606. DebugFlag - Debug flag to pass on to NlPrintRoutine
  607. Sid - SID to output
  608. Return Value:
  609. none
  610. --*/
  611. {
  612. //
  613. // If we aren't debugging this functionality, just return.
  614. //
  615. if ( (NlGlobalParameters.DbFlag & DebugFlag) == 0 ) {
  616. return;
  617. }
  618. //
  619. // Output the SID
  620. //
  621. if ( Sid == NULL ) {
  622. NlPrint((0, "(null)\n"));
  623. } else {
  624. UNICODE_STRING SidString;
  625. NTSTATUS Status;
  626. Status = RtlConvertSidToUnicodeString( &SidString, Sid, TRUE );
  627. if ( !NT_SUCCESS(Status) ) {
  628. NlPrint((0, "Invalid 0x%lX\n", Status ));
  629. } else {
  630. NlPrint((0, "%wZ\n", &SidString ));
  631. RtlFreeUnicodeString( &SidString );
  632. }
  633. }
  634. }
  635. #endif // NETLOGONDBG
  636. DWORD
  637. NlpAtoX(
  638. IN LPWSTR String
  639. )
  640. /*++
  641. Routine Description:
  642. Converts hexadecimal string to DWORD integer.
  643. Accepts the following form of hex string
  644. 0[x-X][0-9, a-f, A-F]*
  645. Arguments:
  646. String: hexadecimal string.
  647. Return Value:
  648. Decimal value of the hex string.
  649. --*/
  650. {
  651. DWORD Value = 0;
  652. if( String == NULL )
  653. return 0;
  654. if( *String != TEXT('0') )
  655. return 0;
  656. String++;
  657. if( *String == TCHAR_EOS )
  658. return 0;
  659. if( ( *String != TEXT('x') ) && ( *String != TEXT('X') ) )
  660. return 0;
  661. String++;
  662. while(*String != TCHAR_EOS ) {
  663. if( (*String >= TEXT('0')) && (*String <= TEXT('9')) ) {
  664. Value = Value * 16 + ( *String - '0');
  665. } else if( (*String >= TEXT('a')) && (*String <= TEXT('f')) ) {
  666. Value = Value * 16 + ( 10 + *String - TEXT('a'));
  667. } else if( (*String >= TEXT('A')) && (*String <= TEXT('F')) ) {
  668. Value = Value * 16 + ( 10 + *String - TEXT('A'));
  669. } else {
  670. break;
  671. }
  672. String++;
  673. }
  674. return Value;
  675. }
  676. VOID
  677. NlWaitForSingleObject(
  678. IN LPSTR WaitReason,
  679. IN HANDLE WaitHandle
  680. )
  681. /*++
  682. Routine Description:
  683. Waits an infinite amount of time for the specified handle.
  684. Arguments:
  685. WaitReason - Text describing what we're waiting on
  686. WaitHandle - Handle to wait on
  687. Return Value:
  688. None
  689. --*/
  690. {
  691. DWORD WaitStatus;
  692. //
  693. // Loop waiting.
  694. //
  695. for (;;) {
  696. WaitStatus = WaitForSingleObject( WaitHandle,
  697. 2*60*1000 ); // Two minutes
  698. if ( WaitStatus == WAIT_TIMEOUT ) {
  699. NlPrint((NL_CRITICAL,
  700. "WaitForSingleObject 2-minute timeout (Rewaiting): %s\n",
  701. WaitReason ));
  702. continue;
  703. } else if ( WaitStatus == WAIT_OBJECT_0 ) {
  704. break;
  705. } else {
  706. NlPrint((NL_CRITICAL,
  707. "WaitForSingleObject error: %ld %ld %s\n",
  708. WaitStatus,
  709. GetLastError(),
  710. WaitReason ));
  711. UNREFERENCED_PARAMETER(WaitReason);
  712. break;
  713. }
  714. }
  715. }
  716. BOOLEAN
  717. NlWaitForSamService(
  718. BOOLEAN NetlogonServiceCalling
  719. )
  720. /*++
  721. Routine Description:
  722. This procedure waits for the SAM service to start and to complete
  723. all its initialization.
  724. Arguments:
  725. NetlogonServiceCalling:
  726. TRUE if this is the netlogon service proper calling
  727. FALSE if this is the changelog worker thread calling
  728. Return Value:
  729. TRUE : if the SAM service is successfully starts.
  730. FALSE : if the SAM service can't start.
  731. --*/
  732. {
  733. NTSTATUS Status;
  734. DWORD WaitStatus;
  735. UNICODE_STRING EventName;
  736. HANDLE EventHandle;
  737. OBJECT_ATTRIBUTES EventAttributes;
  738. //
  739. // open SAM event
  740. //
  741. RtlInitUnicodeString( &EventName, L"\\SAM_SERVICE_STARTED");
  742. InitializeObjectAttributes( &EventAttributes, &EventName, 0, 0, NULL );
  743. Status = NtOpenEvent( &EventHandle,
  744. SYNCHRONIZE|EVENT_MODIFY_STATE,
  745. &EventAttributes );
  746. if ( !NT_SUCCESS(Status)) {
  747. if( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  748. //
  749. // SAM hasn't created this event yet, let us create it now.
  750. // SAM opens this event to set it.
  751. //
  752. Status = NtCreateEvent(
  753. &EventHandle,
  754. SYNCHRONIZE|EVENT_MODIFY_STATE,
  755. &EventAttributes,
  756. NotificationEvent,
  757. FALSE // The event is initially not signaled
  758. );
  759. if( Status == STATUS_OBJECT_NAME_EXISTS ||
  760. Status == STATUS_OBJECT_NAME_COLLISION ) {
  761. //
  762. // second change, if the SAM created the event before we
  763. // do.
  764. //
  765. Status = NtOpenEvent( &EventHandle,
  766. SYNCHRONIZE|EVENT_MODIFY_STATE,
  767. &EventAttributes );
  768. }
  769. }
  770. if ( !NT_SUCCESS(Status)) {
  771. //
  772. // could not make the event handle
  773. //
  774. NlPrint((NL_CRITICAL,
  775. "NlWaitForSamService couldn't make the event handle : "
  776. "%lx\n", Status));
  777. return( FALSE );
  778. }
  779. }
  780. //
  781. // Loop waiting.
  782. //
  783. for (;;) {
  784. WaitStatus = WaitForSingleObject( EventHandle,
  785. 5*1000 ); // 5 Seconds
  786. if ( WaitStatus == WAIT_TIMEOUT ) {
  787. if ( NetlogonServiceCalling ) {
  788. NlPrint((NL_CRITICAL,
  789. "NlWaitForSamService 5-second timeout (Rewaiting)\n" ));
  790. if (!GiveInstallHints( FALSE )) {
  791. (VOID) NtClose( EventHandle );
  792. return FALSE;
  793. }
  794. }
  795. continue;
  796. } else if ( WaitStatus == WAIT_OBJECT_0 ) {
  797. break;
  798. } else {
  799. NlPrint((NL_CRITICAL,
  800. "NlWaitForSamService: error %ld %ld\n",
  801. GetLastError(),
  802. WaitStatus ));
  803. (VOID) NtClose( EventHandle );
  804. return FALSE;
  805. }
  806. }
  807. (VOID) NtClose( EventHandle );
  808. return TRUE;
  809. }
  810. NET_API_STATUS
  811. NlReadBinaryLog(
  812. IN LPWSTR FileSuffix,
  813. IN BOOL DeleteName,
  814. OUT LPBYTE *Buffer,
  815. OUT PULONG BufferSize
  816. )
  817. /*++
  818. Routine Description:
  819. Read a file into a buffer.
  820. Arguments:
  821. FileSuffix - Specifies the name of the file to write (relative to the
  822. Windows directory)
  823. DeleteName - If true the file will be deleted
  824. Buffer - Returns an allocated buffer containing the file.
  825. Buffer should be freed using LocalFree.
  826. If the file doesn't exist, NULL will be returned (and NO_ERROR)
  827. BufferSize - Returns size (in bytes) of buffer
  828. Return Value:
  829. Status of the operation.
  830. --*/
  831. {
  832. NET_API_STATUS NetStatus;
  833. LPWSTR FileName = NULL;
  834. UINT WindowsDirectoryLength;
  835. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  836. BOOLEAN FileNameKnown = FALSE;
  837. ULONG BytesRead;
  838. //
  839. // Initialization
  840. //
  841. *Buffer = NULL;
  842. *BufferSize = 0;
  843. //
  844. // Allocate a block to build the file name in
  845. // (Don't put it on the stack since we don't want to commit a huge stack.)
  846. //
  847. FileName = LocalAlloc( LMEM_ZEROINIT, sizeof(WCHAR) * (MAX_PATH+1) );
  848. if ( FileName == NULL ) {
  849. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  850. goto Cleanup;
  851. }
  852. //
  853. // Build the name of the log file
  854. //
  855. WindowsDirectoryLength = GetSystemWindowsDirectoryW(
  856. FileName,
  857. sizeof(WCHAR) * (MAX_PATH+1) );
  858. if ( WindowsDirectoryLength == 0 ) {
  859. NetStatus = GetLastError();
  860. NlPrint(( NL_CRITICAL,
  861. "NlWriteBinaryLog: Unable to GetSystemWindowsDirectoryW (%ld)\n",
  862. NetStatus ));
  863. goto Cleanup;
  864. }
  865. if ( WindowsDirectoryLength + wcslen( FileSuffix ) + 1 >= MAX_PATH ) {
  866. NlPrint((NL_CRITICAL,
  867. "NlWriteBinaryLog: file name length is too long \n" ));
  868. NetStatus = ERROR_INVALID_NAME;
  869. goto Cleanup;
  870. }
  871. wcscat( FileName, FileSuffix );
  872. FileNameKnown = TRUE;
  873. //
  874. // Open binary log file if exists
  875. //
  876. FileHandle = CreateFileW(
  877. FileName,
  878. GENERIC_READ,
  879. FILE_SHARE_READ | FILE_SHARE_WRITE,
  880. NULL, // Supply better security ??
  881. OPEN_EXISTING, // Only open it if it exists
  882. FILE_ATTRIBUTE_NORMAL,
  883. NULL ); // No template
  884. if ( FileHandle == INVALID_HANDLE_VALUE) {
  885. NlPrint(( NL_CRITICAL,
  886. FORMAT_LPWSTR ": Unable to open. %ld\n",
  887. FileName,
  888. GetLastError() ));
  889. // This isn't fatal
  890. NetStatus = NO_ERROR;
  891. goto Cleanup;
  892. }
  893. //
  894. // Get the size of the file.
  895. //
  896. *BufferSize = GetFileSize( FileHandle, NULL );
  897. if ( *BufferSize == 0xFFFFFFFF ) {
  898. NetStatus = GetLastError();
  899. NlPrint((NL_CRITICAL,
  900. "%ws: Unable to GetFileSize: %ld \n",
  901. FileName,
  902. NetStatus ));
  903. *BufferSize = 0;
  904. goto Cleanup;
  905. }
  906. if ( *BufferSize < 1 ) {
  907. NlPrint(( NL_CRITICAL,
  908. "NlReadBinaryLog: %ws: size too small: %ld.\n",
  909. FileName,
  910. *BufferSize ));
  911. *BufferSize = 0;
  912. NetStatus = NO_ERROR;
  913. goto Cleanup;
  914. }
  915. //
  916. // Allocate a buffer to read the file into.
  917. //
  918. *Buffer = LocalAlloc( 0, *BufferSize );
  919. if ( *Buffer == NULL ) {
  920. *BufferSize = 0;
  921. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  922. goto Cleanup;
  923. }
  924. //
  925. // Read the file into the buffer.
  926. //
  927. if ( !ReadFile( FileHandle,
  928. *Buffer,
  929. *BufferSize,
  930. &BytesRead,
  931. NULL ) ) { // Not Overlapped
  932. NetStatus = GetLastError();
  933. if ( NetStatus != ERROR_FILE_NOT_FOUND ) {
  934. NlPrint(( NL_CRITICAL,
  935. "NlReadBinaryLog: %ws: Cannot ReadFile: %ld.\n",
  936. FileName,
  937. NetStatus ));
  938. }
  939. LocalFree( *Buffer );
  940. *Buffer = NULL;
  941. *BufferSize = 0;
  942. NetStatus = NO_ERROR;
  943. goto Cleanup;
  944. }
  945. if ( BytesRead != *BufferSize ) {
  946. NlPrint(( NL_CRITICAL,
  947. "NlReadBinaryLog: %ws: Cannot read entire File: %ld %ld.\n",
  948. FileName,
  949. BytesRead,
  950. *BufferSize ));
  951. LocalFree( *Buffer );
  952. *Buffer = NULL;
  953. *BufferSize = 0;
  954. NetStatus = NO_ERROR;
  955. goto Cleanup;
  956. }
  957. NetStatus = NO_ERROR;
  958. //
  959. // Be tidy.
  960. //
  961. Cleanup:
  962. if ( FileHandle != INVALID_HANDLE_VALUE ) {
  963. CloseHandle( FileHandle );
  964. }
  965. //
  966. // If the caller asked us to delete the file,
  967. // do so now
  968. //
  969. if (DeleteName && FileNameKnown) {
  970. if ( !DeleteFile( FileName ) ) {
  971. DWORD WinError;
  972. WinError = GetLastError();
  973. if ( WinError != ERROR_FILE_NOT_FOUND ) {
  974. NlPrint((NL_CRITICAL,
  975. "Cannot delete %ws (%ld)\n",
  976. FileName,
  977. WinError ));
  978. }
  979. // This isn't fatal
  980. }
  981. }
  982. if ( FileName != NULL ) {
  983. LocalFree( FileName );
  984. }
  985. return NetStatus;
  986. }
  987. #if NETLOGONDBG
  988. VOID
  989. NlOpenDebugFile(
  990. IN BOOL ReopenFlag
  991. )
  992. /*++
  993. Routine Description:
  994. Opens or re-opens the debug file
  995. Arguments:
  996. ReopenFlag - TRUE to indicate the debug file is to be closed, renamed,
  997. and recreated.
  998. Return Value:
  999. None
  1000. --*/
  1001. {
  1002. LPWSTR AllocatedBuffer = NULL;
  1003. LPWSTR LogFileName;
  1004. LPWSTR BakFileName;
  1005. DWORD FileAttributes;
  1006. DWORD PathLength;
  1007. DWORD WinError;
  1008. //
  1009. // Allocate a buffer for storage local to this procedure.
  1010. // (Don't put it on the stack since we don't want to commit a huge stack.)
  1011. //
  1012. AllocatedBuffer = LocalAlloc( 0, sizeof(WCHAR) *
  1013. (MAX_PATH+1 +
  1014. MAX_PATH+1 ) );
  1015. if ( AllocatedBuffer == NULL ) {
  1016. goto ErrorReturn;
  1017. }
  1018. LogFileName = AllocatedBuffer;
  1019. BakFileName = &LogFileName[MAX_PATH+1];
  1020. //
  1021. // Close the handle to the debug file, if it is currently open
  1022. //
  1023. EnterCriticalSection( &NlGlobalLogFileCritSect );
  1024. if ( NlGlobalLogFile != INVALID_HANDLE_VALUE ) {
  1025. CloseHandle( NlGlobalLogFile );
  1026. NlGlobalLogFile = INVALID_HANDLE_VALUE;
  1027. }
  1028. LeaveCriticalSection( &NlGlobalLogFileCritSect );
  1029. //
  1030. // make debug directory path first, if it is not made before.
  1031. //
  1032. if( NlGlobalDebugSharePath == NULL ) {
  1033. if ( !GetSystemWindowsDirectoryW( LogFileName, MAX_PATH+1 ) ) {
  1034. NlPrint((NL_CRITICAL, "Window Directory Path can't be retrieved, %lu.\n",
  1035. GetLastError() ));
  1036. goto ErrorReturn;
  1037. }
  1038. //
  1039. // check debug path length.
  1040. //
  1041. PathLength = wcslen(LogFileName) * sizeof(WCHAR) +
  1042. sizeof(DEBUG_DIR) + sizeof(WCHAR);
  1043. if( (PathLength + sizeof(DEBUG_FILE) > MAX_PATH+1 ) ||
  1044. (PathLength + sizeof(DEBUG_BAK_FILE) > MAX_PATH+1 ) ) {
  1045. NlPrint((NL_CRITICAL, "Debug directory path (%ws) length is too long.\n",
  1046. LogFileName));
  1047. goto ErrorReturn;
  1048. }
  1049. wcscat(LogFileName, DEBUG_DIR);
  1050. //
  1051. // copy debug directory name to global var.
  1052. //
  1053. NlGlobalDebugSharePath =
  1054. NetpMemoryAllocate( (wcslen(LogFileName) + 1) * sizeof(WCHAR) );
  1055. if( NlGlobalDebugSharePath == NULL ) {
  1056. NlPrint((NL_CRITICAL, "Can't allocated memory for debug share "
  1057. "(%ws).\n", LogFileName));
  1058. goto ErrorReturn;
  1059. }
  1060. wcscpy(NlGlobalDebugSharePath, LogFileName);
  1061. }
  1062. else {
  1063. wcscpy(LogFileName, NlGlobalDebugSharePath);
  1064. }
  1065. //
  1066. // Check this path exists.
  1067. //
  1068. FileAttributes = GetFileAttributesW( LogFileName );
  1069. if( FileAttributes == 0xFFFFFFFF ) {
  1070. WinError = GetLastError();
  1071. if( WinError == ERROR_FILE_NOT_FOUND ) {
  1072. //
  1073. // Create debug directory.
  1074. //
  1075. if( !CreateDirectoryW( LogFileName, NULL) ) {
  1076. NlPrint((NL_CRITICAL, "Can't create Debug directory (%ws), %lu.\n",
  1077. LogFileName, GetLastError() ));
  1078. goto ErrorReturn;
  1079. }
  1080. }
  1081. else {
  1082. NlPrint((NL_CRITICAL, "Can't Get File attributes(%ws), %lu.\n",
  1083. LogFileName, WinError ));
  1084. goto ErrorReturn;
  1085. }
  1086. }
  1087. else {
  1088. //
  1089. // if this is not a directory.
  1090. //
  1091. if(!(FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  1092. NlPrint((NL_CRITICAL, "Debug directory path (%ws) exists as file.\n",
  1093. LogFileName));
  1094. goto ErrorReturn;
  1095. }
  1096. }
  1097. //
  1098. // Create the name of the old and new log file names
  1099. //
  1100. (VOID) wcscpy( BakFileName, LogFileName );
  1101. (VOID) wcscat( LogFileName, L"\\Netlogon.log" );
  1102. (VOID) wcscat( BakFileName, L"\\Netlogon.bak" );
  1103. //
  1104. // If this is a re-open,
  1105. // delete the backup file,
  1106. // rename the current file to the backup file.
  1107. //
  1108. if ( ReopenFlag ) {
  1109. if ( !DeleteFile( BakFileName ) ) {
  1110. WinError = GetLastError();
  1111. if ( WinError != ERROR_FILE_NOT_FOUND ) {
  1112. NlPrint((NL_CRITICAL,
  1113. "Cannot delete " FORMAT_LPWSTR "(%ld)\n",
  1114. BakFileName,
  1115. WinError ));
  1116. NlPrint((NL_CRITICAL, " Try to re-open the file.\n"));
  1117. ReopenFlag = FALSE; // Don't truncate the file
  1118. }
  1119. }
  1120. }
  1121. if ( ReopenFlag ) {
  1122. if ( !MoveFile( LogFileName, BakFileName ) ) {
  1123. NlPrint((NL_CRITICAL,
  1124. "Cannot rename " FORMAT_LPWSTR " to " FORMAT_LPWSTR
  1125. " (%ld)\n",
  1126. LogFileName,
  1127. BakFileName,
  1128. GetLastError() ));
  1129. NlPrint((NL_CRITICAL,
  1130. " Try to re-open the file.\n"));
  1131. ReopenFlag = FALSE; // Don't truncate the file
  1132. }
  1133. }
  1134. //
  1135. // Open the file.
  1136. //
  1137. EnterCriticalSection( &NlGlobalLogFileCritSect );
  1138. NlGlobalLogFile = CreateFileW( LogFileName,
  1139. GENERIC_WRITE|GENERIC_WRITE,
  1140. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1141. NULL,
  1142. ReopenFlag ? CREATE_ALWAYS : OPEN_ALWAYS,
  1143. FILE_ATTRIBUTE_NORMAL,
  1144. NULL );
  1145. if ( NlGlobalLogFile == INVALID_HANDLE_VALUE ) {
  1146. NlPrint((NL_CRITICAL, "cannot open " FORMAT_LPWSTR ",\n",
  1147. LogFileName ));
  1148. LeaveCriticalSection( &NlGlobalLogFileCritSect );
  1149. goto ErrorReturn;
  1150. } else {
  1151. // Position the log file at the end
  1152. (VOID) SetFilePointer( NlGlobalLogFile,
  1153. 0,
  1154. NULL,
  1155. FILE_END );
  1156. }
  1157. LeaveCriticalSection( &NlGlobalLogFileCritSect );
  1158. Cleanup:
  1159. if ( AllocatedBuffer != NULL ) {
  1160. LocalFree( AllocatedBuffer );
  1161. }
  1162. return;
  1163. ErrorReturn:
  1164. NlPrint((NL_CRITICAL,
  1165. " Debug output will be written to debug terminal.\n"));
  1166. goto Cleanup;
  1167. }
  1168. #define MAX_PRINTF_LEN 1024 // Arbitrary.
  1169. VOID
  1170. NlPrintRoutineV(
  1171. IN DWORD DebugFlag,
  1172. IN LPSTR Format,
  1173. va_list arglist
  1174. )
  1175. // Must be called with NlGlobalLogFileCritSect locked
  1176. {
  1177. static LPSTR NlGlobalLogFileOutputBuffer = NULL;
  1178. ULONG length;
  1179. int lengthTmp;
  1180. DWORD BytesWritten;
  1181. static BeginningOfLine = TRUE;
  1182. static LineCount = 0;
  1183. static TruncateLogFileInProgress = FALSE;
  1184. static LogProblemWarned = FALSE;
  1185. //
  1186. // If we aren't debugging this functionality, just return.
  1187. //
  1188. if ( DebugFlag != 0 && (NlGlobalParameters.DbFlag & DebugFlag) == 0 ) {
  1189. return;
  1190. }
  1191. //
  1192. // Allocate a buffer to build the line in.
  1193. // If there isn't already one.
  1194. //
  1195. length = 0;
  1196. if ( NlGlobalLogFileOutputBuffer == NULL ) {
  1197. NlGlobalLogFileOutputBuffer = LocalAlloc( 0, MAX_PRINTF_LEN + 1 );
  1198. if ( NlGlobalLogFileOutputBuffer == NULL ) {
  1199. return;
  1200. }
  1201. }
  1202. //
  1203. // Handle the beginning of a new line.
  1204. //
  1205. //
  1206. if ( BeginningOfLine ) {
  1207. //
  1208. // Never print empty lines.
  1209. //
  1210. if ( Format[0] == '\n' && Format[1] == '\0' ) {
  1211. return;
  1212. }
  1213. //
  1214. // If the log file is getting huge,
  1215. // truncate it.
  1216. //
  1217. if ( NlGlobalLogFile != INVALID_HANDLE_VALUE &&
  1218. !TruncateLogFileInProgress ) {
  1219. //
  1220. // Only check every 50 lines,
  1221. //
  1222. LineCount++;
  1223. if ( LineCount >= 50 ) {
  1224. DWORD FileSize;
  1225. LineCount = 0;
  1226. //
  1227. // Is the log file too big?
  1228. //
  1229. FileSize = GetFileSize( NlGlobalLogFile, NULL );
  1230. if ( FileSize == 0xFFFFFFFF ) {
  1231. (void) DbgPrint( "[NETLOGON] Cannot GetFileSize %ld\n",
  1232. GetLastError );
  1233. } else if ( FileSize > NlGlobalParameters.LogFileMaxSize ) {
  1234. TruncateLogFileInProgress = TRUE;
  1235. LeaveCriticalSection( &NlGlobalLogFileCritSect );
  1236. NlOpenDebugFile( TRUE );
  1237. NlPrint(( NL_MISC,
  1238. "Logfile truncated because it was larger than %ld bytes\n",
  1239. NlGlobalParameters.LogFileMaxSize ));
  1240. EnterCriticalSection( &NlGlobalLogFileCritSect );
  1241. TruncateLogFileInProgress = FALSE;
  1242. }
  1243. }
  1244. }
  1245. //
  1246. // If we're writing to the debug terminal,
  1247. // indicate this is a Netlogon message.
  1248. //
  1249. if ( NlGlobalLogFile == INVALID_HANDLE_VALUE ) {
  1250. length += (ULONG) sprintf( &NlGlobalLogFileOutputBuffer[length], "[NETLOGON] " );
  1251. }
  1252. //
  1253. // Put the timestamp at the begining of the line.
  1254. //
  1255. {
  1256. SYSTEMTIME SystemTime;
  1257. GetLocalTime( &SystemTime );
  1258. length += (ULONG) sprintf( &NlGlobalLogFileOutputBuffer[length],
  1259. "%02u/%02u %02u:%02u:%02u ",
  1260. SystemTime.wMonth,
  1261. SystemTime.wDay,
  1262. SystemTime.wHour,
  1263. SystemTime.wMinute,
  1264. SystemTime.wSecond );
  1265. }
  1266. //
  1267. // Indicate the type of message on the line
  1268. //
  1269. {
  1270. char *Text;
  1271. switch (DebugFlag) {
  1272. case NL_INIT:
  1273. Text = "INIT"; break;
  1274. case NL_MISC:
  1275. Text = "MISC"; break;
  1276. case NL_LOGON:
  1277. Text = "LOGON"; break;
  1278. case NL_SYNC:
  1279. case NL_PACK_VERBOSE:
  1280. case NL_REPL_TIME:
  1281. case NL_REPL_OBJ_TIME:
  1282. case NL_SYNC_MORE:
  1283. Text = "SYNC"; break;
  1284. case NL_ENCRYPT:
  1285. Text = "ENCRYPT"; break;
  1286. case NL_MAILSLOT:
  1287. case NL_MAILSLOT_TEXT:
  1288. Text = "MAILSLOT"; break;
  1289. case NL_SITE:
  1290. case NL_SITE_MORE:
  1291. Text = "SITE"; break;
  1292. case NL_CRITICAL:
  1293. Text = "CRITICAL"; break;
  1294. case NL_SESSION_SETUP:
  1295. case NL_SESSION_MORE:
  1296. case NL_CHALLENGE_RES:
  1297. case NL_INHIBIT_CANCEL:
  1298. case NL_SERVER_SESS:
  1299. Text = "SESSION"; break;
  1300. case NL_CHANGELOG:
  1301. Text = "CHANGELOG"; break;
  1302. case NL_PULSE_MORE:
  1303. Text = "PULSE"; break;
  1304. case NL_DOMAIN:
  1305. Text = "DOMAIN"; break;
  1306. case NL_DNS:
  1307. case NL_DNS_MORE:
  1308. Text = "DNS"; break;
  1309. case NL_WORKER:
  1310. Text = "WORKER"; break;
  1311. case NL_TIMESTAMP:
  1312. case NL_BREAKPOINT:
  1313. default:
  1314. Text = "UNKNOWN"; break;
  1315. case 0:
  1316. Text = NULL;
  1317. }
  1318. if ( Text != NULL ) {
  1319. length += (ULONG) sprintf( &NlGlobalLogFileOutputBuffer[length], "[%s] ", Text );
  1320. }
  1321. }
  1322. }
  1323. //
  1324. // Put a the information requested by the caller onto the line
  1325. //
  1326. lengthTmp = _vsnprintf( &NlGlobalLogFileOutputBuffer[length],
  1327. MAX_PRINTF_LEN - length - 1,
  1328. Format,
  1329. arglist );
  1330. if ( lengthTmp < 0 ) {
  1331. length = MAX_PRINTF_LEN - 1;
  1332. // always end the line which cannot fit into the buffer
  1333. NlGlobalLogFileOutputBuffer[length-1] = '\n';
  1334. } else {
  1335. length += lengthTmp;
  1336. }
  1337. BeginningOfLine = (length > 0 && NlGlobalLogFileOutputBuffer[length-1] == '\n' );
  1338. if ( BeginningOfLine ) {
  1339. NlGlobalLogFileOutputBuffer[length-1] = '\r';
  1340. NlGlobalLogFileOutputBuffer[length] = '\n';
  1341. NlGlobalLogFileOutputBuffer[length+1] = '\0';
  1342. length++;
  1343. }
  1344. //
  1345. // If the log file isn't open,
  1346. // just output to the debug terminal
  1347. //
  1348. if ( NlGlobalLogFile == INVALID_HANDLE_VALUE ) {
  1349. #if DBG
  1350. if ( !LogProblemWarned ) {
  1351. (void) DbgPrint( "[NETLOGON] Cannot write to log file - file not open\n" );
  1352. LogProblemWarned = TRUE;
  1353. }
  1354. #endif // DBG
  1355. //
  1356. // Write the debug info to the log file.
  1357. //
  1358. } else {
  1359. if ( !WriteFile( NlGlobalLogFile,
  1360. NlGlobalLogFileOutputBuffer,
  1361. length,
  1362. &BytesWritten,
  1363. NULL ) ) {
  1364. #if DBG
  1365. if ( !LogProblemWarned ) {
  1366. (void) DbgPrint( "[NETLOGON] Cannot write to log file %ld\n", GetLastError() );
  1367. LogProblemWarned = TRUE;
  1368. }
  1369. #endif // DBG
  1370. }
  1371. }
  1372. } // NlPrintRoutineV
  1373. VOID
  1374. NlPrintRoutine(
  1375. IN DWORD DebugFlag,
  1376. IN LPSTR Format,
  1377. ...
  1378. )
  1379. {
  1380. va_list arglist;
  1381. //
  1382. // If we aren't debugging this functionality, just return.
  1383. //
  1384. if ( DebugFlag != 0 && (NlGlobalParameters.DbFlag & DebugFlag) == 0 ) {
  1385. return;
  1386. }
  1387. //
  1388. // vsprintf isn't multithreaded + we don't want to intermingle output
  1389. // from different threads.
  1390. //
  1391. EnterCriticalSection( &NlGlobalLogFileCritSect );
  1392. //
  1393. // Simply change arguments to va_list form and call NlPrintRoutineV
  1394. //
  1395. va_start(arglist, Format);
  1396. NlPrintRoutineV( DebugFlag, Format, arglist );
  1397. va_end(arglist);
  1398. LeaveCriticalSection( &NlGlobalLogFileCritSect );
  1399. } // NlPrintRoutine
  1400. VOID
  1401. NlPrintDomRoutine(
  1402. IN DWORD DebugFlag,
  1403. IN PDOMAIN_INFO DomainInfo OPTIONAL,
  1404. IN LPSTR Format,
  1405. ...
  1406. )
  1407. {
  1408. va_list arglist;
  1409. //
  1410. // If we aren't debugging this functionality, just return.
  1411. //
  1412. if ( DebugFlag != 0 && (NlGlobalParameters.DbFlag & DebugFlag) == 0 ) {
  1413. return;
  1414. }
  1415. //
  1416. // vsprintf isn't multithreaded + we don't want to intermingle output
  1417. // from different threads.
  1418. //
  1419. EnterCriticalSection( &NlGlobalLogFileCritSect );
  1420. //
  1421. // Prefix the printed line with the domain name
  1422. //
  1423. if ( NlGlobalServicedDomainCount > 1 ) {
  1424. if ( DomainInfo == NULL ) {
  1425. NlPrint(( DebugFlag, "%ws: ", L"[Unknown]" ));
  1426. } else if ( DomainInfo->DomUnicodeDomainName != NULL &&
  1427. *(DomainInfo->DomUnicodeDomainName) != UNICODE_NULL ) {
  1428. NlPrint(( DebugFlag, "%ws: ", DomainInfo->DomUnicodeDomainName ));
  1429. } else {
  1430. NlPrint(( DebugFlag, "%ws: ", DomainInfo->DomUnicodeDnsDomainName ));
  1431. }
  1432. }
  1433. //
  1434. // Simply change arguments to va_list form and call NlPrintRoutineV
  1435. //
  1436. va_start(arglist, Format);
  1437. NlPrintRoutineV( DebugFlag, Format, arglist );
  1438. va_end(arglist);
  1439. LeaveCriticalSection( &NlGlobalLogFileCritSect );
  1440. } // NlPrintDomRoutine
  1441. VOID
  1442. NlPrintCsRoutine(
  1443. IN DWORD DebugFlag,
  1444. IN PCLIENT_SESSION ClientSession,
  1445. IN LPSTR Format,
  1446. ...
  1447. )
  1448. {
  1449. va_list arglist;
  1450. //
  1451. // If we aren't debugging this functionality, just return.
  1452. //
  1453. if ( DebugFlag != 0 && (NlGlobalParameters.DbFlag & DebugFlag) == 0 ) {
  1454. return;
  1455. }
  1456. //
  1457. // vsprintf isn't multithreaded + we don't want to intermingle output
  1458. // from different threads.
  1459. //
  1460. EnterCriticalSection( &NlGlobalLogFileCritSect );
  1461. //
  1462. // If a ClientSession was actually passed,
  1463. // print information specific to the session.
  1464. //
  1465. if ( ClientSession != NULL ) {
  1466. //
  1467. // Prefix the printed line with the hosted domain name
  1468. //
  1469. if ( NlGlobalServicedDomainCount > 1 ) {
  1470. NlPrint(( DebugFlag,
  1471. "%ws: ",
  1472. ClientSession->CsDomainInfo == NULL ? L"[Unknown]" : ClientSession->CsDomainInfo->DomUnicodeDomainName ));
  1473. }
  1474. //
  1475. // Prefix the printed line with the name of the trusted domain
  1476. //
  1477. NlPrint(( DebugFlag,
  1478. "%ws: ",
  1479. ClientSession->CsDebugDomainName == NULL ? L"[Unknown]" : ClientSession->CsDebugDomainName ));
  1480. }
  1481. //
  1482. // Simply change arguments to va_list form and call NlPrintRoutineV
  1483. //
  1484. va_start(arglist, Format);
  1485. NlPrintRoutineV( DebugFlag, Format, arglist );
  1486. va_end(arglist);
  1487. LeaveCriticalSection( &NlGlobalLogFileCritSect );
  1488. } // NlPrintCsRoutine
  1489. VOID
  1490. NlPrintRpcDebug(
  1491. IN LPCSTR RpcRoutineName,
  1492. IN NTSTATUS StatusIn
  1493. )
  1494. /*++
  1495. Routine Description:
  1496. This routine prints RPC extended error information
  1497. relevant to the error specified.
  1498. This code comes directly from the "RPC Debugging.doc" spec.
  1499. Arguments:
  1500. RpcRoutineName - The name of the failed RPC routine for
  1501. which we print the extended info.
  1502. StatusIn - NT error status code returned by the failed
  1503. RPC routine for which we print the extended error.
  1504. Return Value:
  1505. None.
  1506. --*/
  1507. {
  1508. RPC_STATUS Status2;
  1509. RPC_ERROR_ENUM_HANDLE EnumHandle;
  1510. ULONG EntryIndex = 0;
  1511. BOOLEAN LoggingEnabled = FALSE;
  1512. BOOLEAN FirstRecordCheck = TRUE;
  1513. //
  1514. // If the call didn't fail, there is nothing to debug
  1515. //
  1516. if ( NT_SUCCESS(StatusIn) ) {
  1517. return;
  1518. }
  1519. //
  1520. // Don't bother if netlogon's critical logging is turned off
  1521. //
  1522. IF_NL_DEBUG( CRITICAL ) {
  1523. LoggingEnabled = TRUE;
  1524. }
  1525. if ( !LoggingEnabled ) {
  1526. return;
  1527. }
  1528. //
  1529. // Get the info from RPC
  1530. //
  1531. Status2 = RpcErrorStartEnumeration(&EnumHandle);
  1532. if ( Status2 != RPC_S_OK ) {
  1533. NlPrint(( NL_CRITICAL,
  1534. "NlPrintRpcDebug: Couldn't get EEInfo for %s: %lu (may be legitimate for 0x%lx)\n",
  1535. RpcRoutineName,
  1536. Status2,
  1537. StatusIn ));
  1538. //
  1539. // Loop through the records and log the info for each record
  1540. //
  1541. } else {
  1542. RPC_EXTENDED_ERROR_INFO ErrorInfo;
  1543. int Records;
  1544. BOOL Result;
  1545. BOOL CopyStrings = TRUE;
  1546. BOOL fUseFileTime = TRUE;
  1547. SYSTEMTIME *SystemTimeToUse;
  1548. SYSTEMTIME SystemTimeBuffer;
  1549. EnterCriticalSection( &NlGlobalLogFileCritSect );
  1550. while (Status2 == RPC_S_OK) {
  1551. ErrorInfo.Version = RPC_EEINFO_VERSION;
  1552. ErrorInfo.Flags = 0;
  1553. ErrorInfo.NumberOfParameters = 4;
  1554. if (fUseFileTime) {
  1555. ErrorInfo.Flags |= EEInfoUseFileTime;
  1556. }
  1557. Status2 = RpcErrorGetNextRecord(&EnumHandle, CopyStrings, &ErrorInfo);
  1558. if (Status2 == RPC_S_ENTRY_NOT_FOUND) {
  1559. break;
  1560. } else if (Status2 != RPC_S_OK) {
  1561. NlPrint(( NL_CRITICAL,
  1562. "NlPrintRpcDebug: Couldn't finish enumeration for %s: %lu\n",
  1563. RpcRoutineName,
  1564. Status2 ));
  1565. break;
  1566. } else {
  1567. int i;
  1568. //
  1569. // The first record must have the NT/WIN32 status field equal/equivalent
  1570. // to the passed API error code. Otherwise, this error info was generated
  1571. // for some other failure and is not relevant for our debugging purposes.
  1572. //
  1573. if ( FirstRecordCheck ) {
  1574. FirstRecordCheck = FALSE;
  1575. if ( StatusIn != ErrorInfo.Status &&
  1576. StatusIn != I_RpcMapWin32Status(ErrorInfo.Status) ) {
  1577. break;
  1578. }
  1579. NlPrint(( NL_CRITICAL,
  1580. "NlPrintRpcDebug: Dumping extended error for %s with 0x%lx\n",
  1581. RpcRoutineName,
  1582. StatusIn ));
  1583. }
  1584. if (ErrorInfo.ComputerName) {
  1585. NlPrint(( NL_CRITICAL, " [%lu] ComputerName is %S\n",
  1586. EntryIndex,
  1587. ErrorInfo.ComputerName ));
  1588. if (CopyStrings) {
  1589. Result = HeapFree(GetProcessHeap(), 0, ErrorInfo.ComputerName);
  1590. ASSERT(Result);
  1591. }
  1592. }
  1593. NlPrint(( NL_CRITICAL, " [%lu] ProcessID is %d\n",
  1594. EntryIndex,
  1595. ErrorInfo.ProcessID ));
  1596. if (fUseFileTime) {
  1597. Result = FileTimeToSystemTime(&ErrorInfo.u.FileTime,
  1598. &SystemTimeBuffer);
  1599. ASSERT(Result);
  1600. SystemTimeToUse = &SystemTimeBuffer;
  1601. } else {
  1602. SystemTimeToUse = &ErrorInfo.u.SystemTime;
  1603. }
  1604. NlPrint(( NL_CRITICAL, " [%lu] System Time is: %d/%d/%d %d:%d:%d:%d\n",
  1605. EntryIndex,
  1606. SystemTimeToUse->wMonth,
  1607. SystemTimeToUse->wDay,
  1608. SystemTimeToUse->wYear,
  1609. SystemTimeToUse->wHour,
  1610. SystemTimeToUse->wMinute,
  1611. SystemTimeToUse->wSecond,
  1612. SystemTimeToUse->wMilliseconds ));
  1613. NlPrint(( NL_CRITICAL, " [%lu] Generating component is %d\n",
  1614. EntryIndex,
  1615. ErrorInfo.GeneratingComponent ));
  1616. NlPrint(( NL_CRITICAL, " [%lu] Status is %lu\n",
  1617. EntryIndex,
  1618. ErrorInfo.Status ));
  1619. NlPrint(( NL_CRITICAL, " [%lu] Detection location is %d\n",
  1620. EntryIndex,
  1621. (int)ErrorInfo.DetectionLocation ));
  1622. NlPrint(( NL_CRITICAL, " [%lu] Flags is %d\n",
  1623. EntryIndex,
  1624. ErrorInfo.Flags ));
  1625. NlPrint(( NL_CRITICAL, " [%lu] NumberOfParameters is %d\n",
  1626. EntryIndex,
  1627. ErrorInfo.NumberOfParameters ));
  1628. for (i = 0; i < ErrorInfo.NumberOfParameters; i ++) {
  1629. switch(ErrorInfo.Parameters[i].ParameterType) {
  1630. case eeptAnsiString:
  1631. NlPrint(( NL_CRITICAL, " Ansi string: %s\n",
  1632. ErrorInfo.Parameters[i].u.AnsiString ));
  1633. if (CopyStrings) {
  1634. Result = HeapFree(GetProcessHeap(), 0,
  1635. ErrorInfo.Parameters[i].u.AnsiString);
  1636. ASSERT(Result);
  1637. }
  1638. break;
  1639. case eeptUnicodeString:
  1640. NlPrint(( NL_CRITICAL, " Unicode string: %S\n",
  1641. ErrorInfo.Parameters[i].u.UnicodeString ));
  1642. if (CopyStrings) {
  1643. Result = HeapFree(GetProcessHeap(), 0,
  1644. ErrorInfo.Parameters[i].u.UnicodeString);
  1645. ASSERT(Result);
  1646. }
  1647. break;
  1648. case eeptLongVal:
  1649. NlPrint(( NL_CRITICAL, " Long val: %d\n",
  1650. ErrorInfo.Parameters[i].u.LVal ));
  1651. break;
  1652. case eeptShortVal:
  1653. NlPrint(( NL_CRITICAL, " Short val: %d\n",
  1654. (int)ErrorInfo.Parameters[i].u.SVal ));
  1655. break;
  1656. case eeptPointerVal:
  1657. NlPrint(( NL_CRITICAL, " Pointer val: %d\n",
  1658. ErrorInfo.Parameters[i].u.PVal ));
  1659. break;
  1660. case eeptNone:
  1661. NlPrint(( NL_CRITICAL, " Truncated\n" ));
  1662. break;
  1663. default:
  1664. NlPrint(( NL_CRITICAL, " Invalid type: %d\n",
  1665. ErrorInfo.Parameters[i].ParameterType ));
  1666. }
  1667. }
  1668. EntryIndex ++;
  1669. }
  1670. }
  1671. LeaveCriticalSection( &NlGlobalLogFileCritSect );
  1672. RpcErrorEndEnumeration(&EnumHandle);
  1673. }
  1674. }
  1675. //
  1676. // Have my own version of RtlAssert so debug versions of netlogon really assert on
  1677. // free builds.
  1678. //
  1679. VOID
  1680. NlAssertFailed(
  1681. IN PVOID FailedAssertion,
  1682. IN PVOID FileName,
  1683. IN ULONG LineNumber,
  1684. IN PCHAR Message OPTIONAL
  1685. )
  1686. {
  1687. char Response[ 2 ];
  1688. #if DBG
  1689. while (TRUE) {
  1690. #endif // DBG
  1691. NlPrint(( NL_CRITICAL, "Assertion failed: %s%s (Source File: %s, line %ld)\n",
  1692. Message ? Message : "",
  1693. FailedAssertion,
  1694. FileName,
  1695. LineNumber
  1696. ));
  1697. #if DBG
  1698. DbgPrint( "\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n",
  1699. Message ? Message : "",
  1700. FailedAssertion,
  1701. FileName,
  1702. LineNumber
  1703. );
  1704. DbgPrompt( "Break, Ignore, Terminate Process or Terminate Thread (bipt)? ",
  1705. Response,
  1706. sizeof( Response )
  1707. );
  1708. switch (Response[0]) {
  1709. case 'B':
  1710. case 'b':
  1711. DbgBreakPoint();
  1712. break;
  1713. case 'I':
  1714. case 'i':
  1715. return;
  1716. case 'P':
  1717. case 'p':
  1718. NtTerminateProcess( NtCurrentProcess(), STATUS_UNSUCCESSFUL );
  1719. break;
  1720. case 'T':
  1721. case 't':
  1722. NtTerminateThread( NtCurrentThread(), STATUS_UNSUCCESSFUL );
  1723. break;
  1724. }
  1725. }
  1726. DbgBreakPoint();
  1727. NtTerminateProcess( NtCurrentProcess(), STATUS_UNSUCCESSFUL );
  1728. #endif // DBG
  1729. }
  1730. #endif // NETLOGONDBG
  1731. BOOLEAN
  1732. NlpIsNtStatusResourceError(
  1733. NTSTATUS Status
  1734. )
  1735. /*++
  1736. Routine Description:
  1737. Returns TRUE if the passed in status is a resource error.
  1738. Arguments:
  1739. Status - NT status code to check
  1740. Return Value:
  1741. TRUE - if the status indicates a lack of resources
  1742. --*/
  1743. {
  1744. switch ( Status ) {
  1745. case STATUS_NO_MEMORY:
  1746. case STATUS_INSUFFICIENT_RESOURCES:
  1747. case STATUS_DISK_FULL:
  1748. return TRUE;
  1749. default:
  1750. return FALSE;
  1751. }
  1752. }
  1753. BOOLEAN
  1754. NlpDidDcFail(
  1755. NTSTATUS Status
  1756. )
  1757. /*++
  1758. Routine Description:
  1759. Call this routine with the Status code returned from a secure channel API.
  1760. This routine checks the status code to determine if it specifically is one
  1761. that indicates the DC is having problems. The caller should respond by
  1762. dropping the secure channel and picking another DC.
  1763. Arguments:
  1764. Status - NT status code to check
  1765. Return Value:
  1766. TRUE - if the status indicates the DC failed
  1767. --*/
  1768. {
  1769. //
  1770. // ???: we might consider adding the communications errors here
  1771. // (e.g., RPC_NT_CALL_FAILED and RPC_NT_SERVER_UNAVAILABLE).
  1772. // However, all current callers already handle this issue using a more generic
  1773. // mechanism. For instance, those secure channel API that take an authenticator
  1774. // will have the authenticator wrong for communications errors. The other secure
  1775. // channel API rely on the RPC exception differentiating between comm errors
  1776. // and status codes from the DC.
  1777. //
  1778. //
  1779. // Handle the "original recipe" status code indicating a secure channel problem
  1780. //
  1781. switch ( Status ) {
  1782. case STATUS_ACCESS_DENIED:
  1783. return TRUE;
  1784. default:
  1785. return NlpIsNtStatusResourceError( Status );
  1786. }
  1787. return FALSE;
  1788. }