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

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