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.

777 lines
18 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. dhcp.c
  5. Abstract:
  6. This file contains utility functions.
  7. Author:
  8. Madan Appiah (madana) 7-Dec-1993.
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #include "dhcpglobal.h"
  15. #include <dhcploc.h>
  16. #include <dhcppro.h>
  17. #define MESSAGE_BOX_WIDTH_IN_CHARS 65
  18. typedef struct _POPUP_THREAD_PARAM {
  19. LPWSTR Title;
  20. LPWSTR Message;
  21. ULONG Flags;
  22. } POPUP_THREAD_PARAM, *LPPOPUP_THREAD_PARAM;
  23. POPUP_THREAD_PARAM PopupThreadParam = { NULL, NULL, 0 };
  24. DWORD
  25. DoPopup(
  26. PVOID Buffer
  27. )
  28. /*++
  29. Routine Description:
  30. This function pops up a message to the user. It must run it's own
  31. thread. When the user acknowledge the popup, the thread
  32. deallocates the message buffer and returns.
  33. Arguments:
  34. Buffer - A pointer to a NULL terminated message buffer.
  35. Return Values:
  36. Always returns 0
  37. --*/
  38. {
  39. DWORD Result;
  40. LPPOPUP_THREAD_PARAM Params = Buffer;
  41. Result = MessageBox(
  42. NULL, // no owner
  43. Params->Message,
  44. Params->Title,
  45. ( MB_OK | Params->Flags |
  46. MB_SERVICE_NOTIFICATION |
  47. MB_SYSTEMMODAL |
  48. MB_SETFOREGROUND |
  49. MB_DEFAULT_DESKTOP_ONLY
  50. )
  51. );
  52. LOCK_POPUP();
  53. if( Params->Message != NULL ) {
  54. LocalFree( Params->Message );
  55. Params->Message = NULL;
  56. }
  57. if( Params->Title != NULL ) {
  58. LocalFree( Params->Title );
  59. Params->Title = NULL;
  60. }
  61. //
  62. // close the global handle, so that we will not consume this
  63. // thread resource until another popup.
  64. //
  65. CloseHandle( DhcpGlobalMsgPopupThreadHandle );
  66. DhcpGlobalMsgPopupThreadHandle = NULL;
  67. UNLOCK_POPUP();
  68. //
  69. // Always return 0
  70. //
  71. return 0;
  72. }
  73. DWORD
  74. DisplayUserMessage(
  75. IN PDHCP_CONTEXT DhcpContext,
  76. IN DWORD MessageId,
  77. IN DHCP_IP_ADDRESS IpAddress
  78. )
  79. /*++
  80. Routine Description:
  81. This function starts a new thread to display a message box.
  82. N.B. If a thread already exists which is waiting for user input
  83. on a message box, then this routine does not create another
  84. thread.
  85. Arguments:
  86. DhcpContext -- the context to display messages for
  87. MessageId - The ID of the message to display.
  88. (The actual message string is obtained from the dhcp module).
  89. IpAddress - Ip address involved.
  90. --*/
  91. {
  92. DWORD ThreadID, TitleLength, MsgLength, Flags;
  93. LPWSTR Title = NULL, Message = NULL;
  94. switch(MessageId) {
  95. case MESSAGE_FAILED_TO_OBTAIN_LEASE:
  96. Flags = MB_ICONSTOP;
  97. break;
  98. case MESSAGE_SUCCESSFUL_LEASE :
  99. Flags = MB_ICONINFORMATION;
  100. break;
  101. default:
  102. DhcpAssert(FALSE);
  103. Flags = MB_ICONSTOP;
  104. break;
  105. }
  106. LOCK_POPUP();
  107. //
  108. // if we are asked to display no message popup, simply return.
  109. //
  110. if ( DhcpGlobalDisplayPopup == FALSE ) {
  111. goto Cleanup;
  112. }
  113. //
  114. // if the message popup thread handle is non-null, check to see
  115. // the thread is still running, if so don't display another popup,
  116. // otherwise close the last popup handle and create another popup
  117. // thread for new message.
  118. //
  119. if( DhcpGlobalMsgPopupThreadHandle != NULL ) {
  120. DWORD WaitStatus;
  121. //
  122. // Time out immediately if the thread is still running.
  123. //
  124. WaitStatus = WaitForSingleObject(
  125. DhcpGlobalMsgPopupThreadHandle,
  126. 0 );
  127. if ( WaitStatus == WAIT_TIMEOUT ) {
  128. goto Cleanup;
  129. } else if ( WaitStatus == 0 ) {
  130. //
  131. // This shouldn't be a case, because we close this handle at
  132. // the end of popup thread.
  133. //
  134. DhcpAssert( WaitStatus == 0 );
  135. CloseHandle( DhcpGlobalMsgPopupThreadHandle );
  136. DhcpGlobalMsgPopupThreadHandle = NULL;
  137. } else {
  138. DhcpPrint((
  139. DEBUG_ERRORS,
  140. "Cannot WaitFor message popup thread: %ld\n",
  141. WaitStatus ));
  142. goto Cleanup;
  143. }
  144. }
  145. MsgLength = FormatMessage(
  146. FORMAT_MESSAGE_FROM_HMODULE
  147. | FORMAT_MESSAGE_ARGUMENT_ARRAY
  148. | FORMAT_MESSAGE_ALLOCATE_BUFFER
  149. | MESSAGE_BOX_WIDTH_IN_CHARS,
  150. (LPVOID)DhcpGlobalMessageFileHandle,
  151. MessageId,
  152. 0, // language id.
  153. (LPWSTR)&Message, // return buffer place holder.
  154. 0, // minimum buffer size to allocate.
  155. NULL // No Params
  156. );
  157. if ( MsgLength == 0) {
  158. DhcpPrint(( DEBUG_ERRORS,
  159. "FormatMessage failed, err = %ld.\n", GetLastError()));
  160. goto Cleanup;
  161. }
  162. DhcpAssert( Message != NULL );
  163. DhcpAssert( (wcslen(Message)) == MsgLength );
  164. //
  165. // get message box title.
  166. //
  167. TitleLength = FormatMessage(
  168. FORMAT_MESSAGE_FROM_HMODULE |
  169. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  170. (LPVOID)DhcpGlobalMessageFileHandle,
  171. MESSAGE_POPUP_TITLE,
  172. 0, // language id.
  173. (LPWSTR)&Title, // return buffer place holder.
  174. 0, // minimum buffer size to allocate.
  175. NULL // insert strings.
  176. );
  177. if ( TitleLength == 0) {
  178. DhcpPrint(( DEBUG_ERRORS,
  179. "FormatMessage to Message box Title failed, err = %ld.\n",
  180. GetLastError()));
  181. goto Cleanup;
  182. }
  183. DhcpAssert( Title != NULL );
  184. DhcpAssert( (wcslen(Title)) == TitleLength );
  185. PopupThreadParam.Title = Title;
  186. PopupThreadParam.Message = Message;
  187. PopupThreadParam.Flags = Flags;
  188. //
  189. // Create a thread, to display a message box to the user. We need
  190. // a new thread because MessageBox() blocks until the user clicks
  191. // on the OK button, and we can't block this thread.
  192. //
  193. // DoPopup frees the buffer.
  194. //
  195. DhcpGlobalMsgPopupThreadHandle = CreateThread(
  196. NULL, // no security.
  197. 0, // default stack size.
  198. DoPopup, // entry point.
  199. (PVOID)&PopupThreadParam,
  200. 0,
  201. &ThreadID
  202. );
  203. if ( DhcpGlobalMsgPopupThreadHandle == NULL ) {
  204. DhcpPrint((
  205. DEBUG_ERRORS,
  206. "DisplayUserMessage: Could not create thread, err = %ld.\n",
  207. GetLastError() ));
  208. }
  209. Cleanup:
  210. UNLOCK_POPUP();
  211. return 0;
  212. }
  213. VOID
  214. DhcpLogEvent(
  215. IN PDHCP_CONTEXT DhcpContext, OPTIONAL
  216. IN DWORD EventNumber,
  217. IN DWORD ErrorCode OPTIONAL
  218. )
  219. /*++
  220. Routine Description:
  221. This functions formats and writes an event log entry.
  222. Arguments:
  223. DhcpContext - The context for the event. Optional parameter.
  224. EventNumber - The event to log.
  225. ErrorCode - Windows Error code to record. Optional parameter.
  226. --*/
  227. {
  228. LPWSTR HWAddressBuffer = NULL;
  229. LPWSTR IPAddressBuffer = NULL;
  230. LPWSTR IPAddressBuffer2 = NULL;
  231. CHAR ErrorCodeOemStringBuf[32 + 1];
  232. WCHAR ErrorCodeStringBuf[32 + 1];
  233. LPWSTR ErrorCodeString = NULL;
  234. LPWSTR Strings[10];
  235. DHCP_IP_ADDRESS IpAddr;
  236. if( DhcpContext != NULL ) {
  237. if( EVENT_NACK_LEASE == EventNumber ) {
  238. IpAddr = DhcpContext->NackedIpAddress;
  239. } if( EVENT_ADDRESS_CONFLICT == EventNumber ) {
  240. IpAddr = DhcpContext->ConflictAddress;
  241. } else {
  242. IpAddr = DhcpContext->IpAddress;
  243. }
  244. HWAddressBuffer = DhcpAllocateMemory(
  245. (DhcpContext->HardwareAddressLength * 2 + 1) *
  246. sizeof(WCHAR)
  247. );
  248. if( HWAddressBuffer == NULL ) {
  249. DhcpPrint(( DEBUG_MISC, "Out of memory." ));
  250. goto Cleanup;
  251. }
  252. DhcpHexToString(
  253. HWAddressBuffer,
  254. DhcpContext->HardwareAddress,
  255. DhcpContext->HardwareAddressLength
  256. );
  257. HWAddressBuffer[DhcpContext->HardwareAddressLength * 2] = '\0';
  258. IPAddressBuffer = DhcpOemToUnicode(
  259. inet_ntoa( *(struct in_addr *)&IpAddr ),
  260. NULL
  261. );
  262. if( IPAddressBuffer == NULL ) {
  263. DhcpPrint(( DEBUG_MISC, "Out of memory." ));
  264. goto Cleanup;
  265. }
  266. if( EVENT_NACK_LEASE == EventNumber ) {
  267. IPAddressBuffer2 = DhcpOemToUnicode(
  268. inet_ntoa( *(struct in_addr *)&DhcpContext->DhcpServerAddress ),
  269. NULL
  270. );
  271. if( NULL == IPAddressBuffer2 ) goto Cleanup;
  272. }
  273. }
  274. strcpy( ErrorCodeOemStringBuf, "%%" );
  275. _ultoa( ErrorCode, ErrorCodeOemStringBuf + 2, 10 );
  276. ErrorCodeString = DhcpOemToUnicode(
  277. ErrorCodeOemStringBuf,
  278. ErrorCodeStringBuf );
  279. //
  280. // Log an event
  281. //
  282. switch ( EventNumber ) {
  283. case EVENT_LEASE_TERMINATED:
  284. DhcpAssert( HWAddressBuffer != NULL );
  285. DhcpAssert( IPAddressBuffer != NULL );
  286. Strings[0] = HWAddressBuffer;
  287. Strings[1] = IPAddressBuffer;
  288. DhcpReportEventW(
  289. DHCP_EVENT_CLIENT,
  290. EVENT_LEASE_TERMINATED,
  291. EVENTLOG_ERROR_TYPE,
  292. 2,
  293. 0,
  294. Strings,
  295. NULL );
  296. break;
  297. case EVENT_FAILED_TO_OBTAIN_LEASE:
  298. DhcpAssert( HWAddressBuffer != NULL );
  299. DhcpAssert( ErrorCodeString != NULL );
  300. Strings[0] = HWAddressBuffer;
  301. Strings[1] = ErrorCodeString;
  302. DhcpReportEventW(
  303. DHCP_EVENT_CLIENT,
  304. EVENT_FAILED_TO_OBTAIN_LEASE,
  305. EVENTLOG_ERROR_TYPE,
  306. 2,
  307. sizeof(ErrorCode),
  308. Strings,
  309. &ErrorCode );
  310. break;
  311. case EVENT_NACK_LEASE:
  312. DhcpAssert( HWAddressBuffer != NULL );
  313. DhcpAssert( IPAddressBuffer != NULL );
  314. DhcpAssert( IPAddressBuffer2 != NULL );
  315. Strings[0] = IPAddressBuffer;
  316. Strings[1] = HWAddressBuffer;
  317. Strings[2] = IPAddressBuffer2;
  318. DhcpReportEventW(
  319. DHCP_EVENT_CLIENT,
  320. EVENT_NACK_LEASE,
  321. EVENTLOG_ERROR_TYPE,
  322. 3,
  323. 0,
  324. Strings,
  325. NULL );
  326. break;
  327. case EVENT_ADDRESS_CONFLICT:
  328. DhcpAssert( IPAddressBuffer != NULL );
  329. DhcpAssert( HWAddressBuffer != NULL );
  330. Strings[0] = IPAddressBuffer;
  331. Strings[1] = HWAddressBuffer;
  332. DhcpReportEventW(
  333. DHCP_EVENT_CLIENT,
  334. EVENT_ADDRESS_CONFLICT,
  335. EVENTLOG_WARNING_TYPE,
  336. 2,
  337. 0,
  338. Strings,
  339. NULL );
  340. break;
  341. case EVENT_IPAUTOCONFIGURATION_FAILED:
  342. DhcpAssert( HWAddressBuffer != NULL );
  343. DhcpAssert( ErrorCodeString != NULL );
  344. Strings[0] = HWAddressBuffer;
  345. Strings[1] = ErrorCodeString;
  346. DhcpReportEventW(
  347. DHCP_EVENT_CLIENT,
  348. EVENT_IPAUTOCONFIGURATION_FAILED,
  349. EVENTLOG_WARNING_TYPE,
  350. 2,
  351. sizeof(ErrorCode),
  352. Strings,
  353. &ErrorCode );
  354. break;
  355. case EVENT_FAILED_TO_RENEW:
  356. // The 'timeout' event should be logged only if there is no PPP
  357. // adapter up. It is so because having a PPP adapter means the
  358. // routes are hijacked, hence renewals up to T2 are expected to
  359. // fail.
  360. if (ErrorCode != ERROR_SEM_TIMEOUT ||
  361. DhcpGlobalNdisWanAdaptersCount == 0 ||
  362. time(NULL) >= DhcpContext->T2Time)
  363. {
  364. DhcpAssert( HWAddressBuffer != NULL );
  365. DhcpAssert( ErrorCodeString != NULL );
  366. Strings[0] = HWAddressBuffer;
  367. Strings[1] = ErrorCodeString;
  368. DhcpReportEventW(
  369. DHCP_EVENT_CLIENT,
  370. EVENT_FAILED_TO_RENEW,
  371. EVENTLOG_WARNING_TYPE,
  372. 2,
  373. sizeof(ErrorCode),
  374. Strings,
  375. &ErrorCode );
  376. }
  377. break;
  378. case EVENT_DHCP_SHUTDOWN:
  379. DhcpAssert( ErrorCodeString != NULL );
  380. Strings[0] = ErrorCodeString;
  381. DhcpReportEventW(
  382. DHCP_EVENT_CLIENT,
  383. EVENT_DHCP_SHUTDOWN,
  384. EVENTLOG_WARNING_TYPE,
  385. 1,
  386. sizeof(ErrorCode),
  387. Strings,
  388. &ErrorCode );
  389. break;
  390. case EVENT_IPAUTOCONFIGURATION_SUCCEEDED :
  391. Strings[0] = HWAddressBuffer;
  392. Strings[1] = IPAddressBuffer;
  393. DhcpReportEventW(
  394. DHCP_EVENT_CLIENT,
  395. EVENT_IPAUTOCONFIGURATION_SUCCEEDED,
  396. EVENTLOG_WARNING_TYPE,
  397. 2,
  398. sizeof(ErrorCode),
  399. Strings,
  400. &ErrorCode
  401. );
  402. break;
  403. case EVENT_COULD_NOT_INITIALISE_INTERFACE :
  404. DhcpAssert( NULL != ErrorCodeString);
  405. Strings[0] = ErrorCodeString;
  406. DhcpReportEventW(
  407. DHCP_EVENT_CLIENT,
  408. EVENT_COULD_NOT_INITIALISE_INTERFACE,
  409. EVENTLOG_ERROR_TYPE,
  410. 1,
  411. sizeof(ErrorCode),
  412. Strings,
  413. &ErrorCode
  414. );
  415. break;
  416. case EVENT_NET_ERROR:
  417. DhcpAssert( NULL != ErrorCodeString);
  418. Strings[0] = ErrorCodeString;
  419. DhcpReportEventW(
  420. DHCP_EVENT_CLIENT,
  421. EVENT_NET_ERROR,
  422. EVENTLOG_WARNING_TYPE,
  423. 1,
  424. sizeof(ErrorCode),
  425. Strings,
  426. &ErrorCode
  427. );
  428. break;
  429. default:
  430. DhcpPrint(( DEBUG_MISC, "Unknown event." ));
  431. break;
  432. }
  433. Cleanup:
  434. if( HWAddressBuffer != NULL ) {
  435. DhcpFreeMemory( HWAddressBuffer );
  436. }
  437. if( IPAddressBuffer != NULL ) {
  438. DhcpFreeMemory( IPAddressBuffer );
  439. }
  440. if( IPAddressBuffer2 != NULL ) {
  441. DhcpFreeMemory( IPAddressBuffer2 );
  442. }
  443. }
  444. #if DBG
  445. VOID
  446. DhcpPrintRoutine(
  447. IN DWORD DebugFlag,
  448. IN LPSTR Format,
  449. ...
  450. )
  451. {
  452. #define MAX_PRINTF_LEN 1024 // Arbitrary.
  453. va_list arglist;
  454. char OutputBuffer[MAX_PRINTF_LEN];
  455. ULONG length;
  456. static BeginningOfLine = TRUE;
  457. LPSTR Text;
  458. //
  459. // If we aren't debugging this functionality, just return.
  460. //
  461. if ( DebugFlag != 0 && (DhcpGlobalDebugFlag & DebugFlag) == 0 ) {
  462. return;
  463. }
  464. //
  465. // vsprintf isn't multithreaded + we don't want to intermingle output
  466. // from different threads.
  467. //
  468. // EnterCriticalSection( &DhcpGlobalDebugFileCritSect );
  469. length = 0;
  470. //
  471. // Handle the beginning of a new line.
  472. //
  473. //
  474. if ( BeginningOfLine ) {
  475. length += (ULONG) sprintf( &OutputBuffer[length], "[Dhcp] " );
  476. //
  477. // Put the timestamp at the begining of the line.
  478. //
  479. IF_DEBUG( TIMESTAMP ) {
  480. SYSTEMTIME SystemTime;
  481. GetLocalTime( &SystemTime );
  482. length += (ULONG) sprintf( &OutputBuffer[length],
  483. "%02u/%02u %02u:%02u:%02u ",
  484. SystemTime.wMonth,
  485. SystemTime.wDay,
  486. SystemTime.wHour,
  487. SystemTime.wMinute,
  488. SystemTime.wSecond );
  489. }
  490. //
  491. // Indicate the type of message on the line
  492. //
  493. switch (DebugFlag) {
  494. case DEBUG_ERRORS:
  495. Text = "ERRR";
  496. break;
  497. case DEBUG_PROTOCOL:
  498. Text = "PROT";
  499. break;
  500. case DEBUG_LEASE:
  501. Text = "LEAS";
  502. break;
  503. case DEBUG_PROTOCOL_DUMP:
  504. Text = "DUMP";
  505. break;
  506. case DEBUG_MISC:
  507. Text = "MISC";
  508. break;
  509. default:
  510. Text = "DHCP";
  511. break;
  512. }
  513. if ( Text != NULL ) {
  514. length += (ULONG) sprintf( &OutputBuffer[length], "[%s] ", Text );
  515. }
  516. }
  517. //
  518. // Put a the information requested by the caller onto the line
  519. //
  520. va_start(arglist, Format);
  521. length += (ULONG) vsprintf(&OutputBuffer[length], Format, arglist);
  522. BeginningOfLine = (length > 0 && OutputBuffer[length-1] == '\n' );
  523. va_end(arglist);
  524. DhcpAssert(length <= MAX_PRINTF_LEN);
  525. //
  526. // Output to the debug terminal,
  527. //
  528. if (NULL == DhcpGlobalDebugFile) {
  529. (void) DbgPrint( (PCH) OutputBuffer);
  530. } else {
  531. //
  532. // Note: other process can still write to the log file. This should be OK since
  533. // only the Dhcp client service is supposed to write to the log file.
  534. //
  535. EnterCriticalSection( &DhcpGlobalDebugFileCritSect );
  536. SetFilePointer(DhcpGlobalDebugFile, 0, NULL, FILE_END);
  537. WriteFile(DhcpGlobalDebugFile, OutputBuffer, length, &length, NULL);
  538. LeaveCriticalSection( &DhcpGlobalDebugFileCritSect );
  539. }
  540. // LeaveCriticalSection( &DhcpGlobalDebugFileCritSect );
  541. }
  542. #endif // DBG
  543. PDHCP_CONTEXT
  544. FindDhcpContextOnNicList(
  545. IN LPCWSTR AdapterName, OPTIONAL
  546. IN DWORD InterfaceContext
  547. )
  548. /*++
  549. Routine Description:
  550. This function finds the DHCP_CONTEXT for the specified
  551. adapter name on the Nic list.
  552. This function must be called with LOCK_RENEW_LIST().
  553. Arguments:
  554. AdapterName - name of the adapter.
  555. HardwareAddress - The hardware address to look for.
  556. Return Value:
  557. A pointer to the desired DHCP work context.
  558. NULL - If the specified work context block cannot be found.
  559. --*/
  560. {
  561. PLIST_ENTRY listEntry;
  562. PDHCP_CONTEXT dhcpContext;
  563. PLOCAL_CONTEXT_INFO LocalInfo;
  564. listEntry = DhcpGlobalNICList.Flink;
  565. while ( listEntry != &DhcpGlobalNICList ) {
  566. dhcpContext = CONTAINING_RECORD( listEntry, DHCP_CONTEXT, NicListEntry );
  567. LocalInfo = dhcpContext->LocalInformation;
  568. if ( AdapterName ) {
  569. if( _wcsicmp( LocalInfo->AdapterName, AdapterName ) == 0 ) {
  570. return( dhcpContext );
  571. }
  572. } else {
  573. if( LocalInfo->IpInterfaceContext == InterfaceContext ) {
  574. return( dhcpContext );
  575. }
  576. }
  577. listEntry = listEntry->Flink;
  578. }
  579. return( NULL );
  580. }
  581. //
  582. // End of file
  583. //