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.

4120 lines
124 KiB

  1. /*++
  2. Copyright (c) 1997-1998 Microsoft Corporation
  3. Module Name:
  4. message.c
  5. Abstract:
  6. This module contains the code to process a BINL request message
  7. for the BINL server.
  8. Author:
  9. Colin Watson (colinw) 2-May-1997
  10. Environment:
  11. User Mode - Win32
  12. Revision History:
  13. --*/
  14. #include "binl.h"
  15. #pragma hdrstop
  16. #if DBG
  17. DWORD BinlRepeatSleep;
  18. #endif
  19. const WCHAR IntelOSChooser[] = L"OSChooser\\i386\\startrom.com";
  20. const WCHAR IA64OSChooser[] = L"OSChooser\\ia64\\oschoice.efi";
  21. WCHAR DefaultNamingContext[] = L"defaultNamingContext";
  22. // Connection information to a DC in our domain
  23. PLDAP DCLdapHandle = NULL;
  24. PWCHAR * DCBase = NULL;
  25. // Connection information to the Global Catalog for our enterprise
  26. PLDAP GCLdapHandle = NULL;
  27. PWCHAR * GCBase = NULL;
  28. DWORD
  29. GetGuidFromPacket(
  30. LPDHCP_MESSAGE DhcpReceiveMessage,
  31. LPDHCP_SERVER_OPTIONS DhcpOptions,
  32. OUT PUCHAR Guid,
  33. OUT PDWORD GuidLength OPTIONAL,
  34. OUT PMACHINE_INFO *MachineInfo
  35. );
  36. LPOPTION
  37. AppendClientRequestedParameters(
  38. DHCP_IP_ADDRESS IpAddress,
  39. DHCP_IP_ADDRESS SubnetMask,
  40. LPBYTE RequestedList,
  41. DWORD ListLength,
  42. LPOPTION Option,
  43. LPBYTE OptionEnd,
  44. CHAR *ClassIdentifier,
  45. DWORD ClassIdentifierLength,
  46. BOOL fSwitchedSubnet
  47. );
  48. DWORD
  49. RecognizeClient(
  50. PUCHAR pGuid,
  51. PMACHINE_INFO * pMachineInfo,
  52. DWORD dwRequestedInfo,
  53. ULONG SecondsSinceBoot,
  54. USHORT SystemArchitecture
  55. );
  56. DWORD
  57. GetBootParametersExt(
  58. PMACHINE_INFO pMachineInfo,
  59. DWORD dwRequestedInfo,
  60. USHORT SystemArchitecture,
  61. BOOL fGlobal);
  62. VOID
  63. FreeConnection(
  64. PLDAP * LdapHandle,
  65. PWCHAR ** Base
  66. );
  67. DWORD
  68. ProcessMessage(
  69. LPBINL_REQUEST_CONTEXT RequestContext
  70. )
  71. /*++
  72. Routine Description:
  73. This function dispatches the processing of a received BINL message.
  74. The handler functions will create the response message if necessary.
  75. Arguments:
  76. RequestContext - A pointer to the BinlRequestContext block for
  77. this request.
  78. Return Value:
  79. Windows Error.
  80. --*/
  81. {
  82. DWORD Error;
  83. BOOL fSendResponse,
  84. fSubnetsListEmpty,
  85. fReadyToTerminate,
  86. fAllThreadsBusy;
  87. DHCP_SERVER_OPTIONS dhcpOptions;
  88. LPDHCP_MESSAGE binlReceiveMessage;
  89. TraceFunc("ProcessMessage( )\n" );
  90. //
  91. // Simply ignore messages when the service is paused.
  92. //
  93. if( BinlGlobalServiceStatus.dwCurrentState == SERVICE_PAUSED )
  94. {
  95. Error = ERROR_BINL_SERVICE_PAUSED;
  96. goto t_done;
  97. }
  98. binlReceiveMessage = (LPDHCP_MESSAGE)RequestContext->ReceiveBuffer;
  99. //
  100. // If it is an OSChooser message, then process that separately
  101. // since they don't conform to the DHCP layout. This will send
  102. // any messages that it needs to.
  103. //
  104. if (binlReceiveMessage->Operation == OSC_REQUEST)
  105. {
  106. Error = OscProcessMessage(RequestContext);
  107. goto t_done;
  108. }
  109. RtlZeroMemory( &dhcpOptions, sizeof( dhcpOptions ) );
  110. //BinlDumpMessage(DEBUG_MESSAGE, binlReceiveMessage);
  111. Error = ExtractOptions(
  112. binlReceiveMessage,
  113. &dhcpOptions,
  114. RequestContext->ReceiveMessageSize );
  115. if( Error != ERROR_SUCCESS ) {
  116. goto t_done;
  117. }
  118. if (!dhcpOptions.MessageType) {
  119. goto t_done; // BOOTP request
  120. }
  121. #if 0
  122. if (dhcpOptions.SystemArchitecture
  123. != DHCP_OPTION_CLIENT_ARCHITECTURE_X86) {
  124. BinlPrintDbg((
  125. DEBUG_OPTIONS,
  126. "ProcessMessage: Client ignored - unsupported architecture type %d \n",
  127. dhcpOptions.SystemArchitecture ) );
  128. goto t_done;
  129. }
  130. #endif
  131. if ( ( !AnswerRequests ) &&
  132. ( RequestContext->ActiveEndpoint->Port == DHCP_SERVR_PORT )) {
  133. //
  134. // this is not the 4011 port, therefore it must be the DHCP port.
  135. // We're configured to not answer requests on this port right now
  136. // therefore we'll toss this packet.
  137. //
  138. BinlPrint((DEBUG_OPTIONS, "Client ignored - Not answering requests (AnswerRequests == FALSE)\n" ));
  139. goto t_done;
  140. }
  141. if (BinlGlobalAuthorized == FALSE) {
  142. BinlPrint((DEBUG_ROGUE, "BINL has not passed rogue detection. Ignoring packet.\n" ));
  143. //
  144. // We'll possibly log an event here since we don't log an event
  145. // at startup saying what our rogue state is.
  146. //
  147. LogCurrentRogueState( TRUE );
  148. goto t_done;
  149. }
  150. //
  151. // Dispatch based on Message Type
  152. //
  153. RequestContext->MessageType = *dhcpOptions.MessageType;
  154. switch( *dhcpOptions.MessageType ) {
  155. case DHCP_DISCOVER_MESSAGE:
  156. Error = ProcessBinlDiscover( RequestContext, &dhcpOptions );
  157. fSendResponse = TRUE;
  158. break;
  159. case DHCP_INFORM_MESSAGE:
  160. Error = ProcessBinlInform( RequestContext, &dhcpOptions );
  161. fSendResponse = TRUE;
  162. break;
  163. case DHCP_REQUEST_MESSAGE:
  164. Error = ProcessBinlRequest( RequestContext, &dhcpOptions );
  165. fSendResponse = TRUE;
  166. break;
  167. default:
  168. BinlPrintDbg(( DEBUG_STOC,
  169. "Received a invalid message type, %ld.\n",
  170. *dhcpOptions.MessageType ));
  171. Error = ERROR_BINL_INVALID_BINL_MESSAGE;
  172. break;
  173. }
  174. if ( ERROR_SUCCESS == Error && fSendResponse )
  175. {
  176. /*
  177. BinlDumpMessage(
  178. DEBUG_MESSAGE,
  179. (LPDHCP_MESSAGE)RequestContext->SendBuffer
  180. );
  181. */
  182. BinlSendMessage( RequestContext );
  183. }
  184. t_done:
  185. //
  186. // delete the context structure for this thread
  187. //
  188. BinlFreeMemory( RequestContext->ReceiveBuffer );
  189. BinlFreeMemory( RequestContext->SendBuffer );
  190. BinlFreeMemory( RequestContext );
  191. EnterCriticalSection( &g_ProcessMessageCritSect );
  192. //
  193. // Check to see if all worker threads were busy
  194. //
  195. fAllThreadsBusy = ( g_cProcessMessageThreads ==
  196. g_cMaxProcessingThreads );
  197. --g_cProcessMessageThreads;
  198. //
  199. // Check to see if this is the last worker thread
  200. //
  201. fReadyToTerminate = !g_cProcessMessageThreads;
  202. LeaveCriticalSection( &g_ProcessMessageCritSect );
  203. //
  204. // If all the worker threads were busy, then BinlProcessingLoop
  205. // is waiting for a thread to complete. Set BinlGlobalRecvEvent
  206. // so BinlProcessingLoop can continue.
  207. //
  208. if ( fAllThreadsBusy )
  209. {
  210. BinlPrintDbg( ( DEBUG_STOC,
  211. "ProcessMessage: Alerting BinlProcessingLoop\n" )
  212. );
  213. SetEvent( BinlGlobalRecvEvent );
  214. }
  215. if ( fReadyToTerminate &&
  216. WaitForSingleObject( BinlGlobalProcessTerminationEvent,
  217. 0 ) == WAIT_OBJECT_0 )
  218. {
  219. //
  220. // there are no other ProcessMessage threads running, and
  221. // the service is waiting to shutdown.
  222. //
  223. BinlPrintDbg( (DEBUG_MISC,
  224. "ProcessMessage: shutdown complete.\n" )
  225. );
  226. BinlAssert( g_hevtProcessMessageComplete );
  227. SetEvent( g_hevtProcessMessageComplete );
  228. }
  229. //
  230. // thread exit
  231. //
  232. BinlPrintDbg( ( DEBUG_STOC,
  233. "ProcessMessage exited\n" )
  234. );
  235. return Error;
  236. }
  237. DWORD
  238. GetGuidFromPacket(
  239. LPDHCP_MESSAGE DhcpReceiveMessage,
  240. LPDHCP_SERVER_OPTIONS DhcpOptions,
  241. OUT PUCHAR Guid,
  242. OUT PDWORD GuidLength OPTIONAL,
  243. OUT PMACHINE_INFO *MachineInfo
  244. )
  245. /*++
  246. Routine Description:
  247. This routine reads the guid from the client's packet (they send
  248. us their guid). After obtaining their guid, we attempt to
  249. recognize the client by querying the DS with the guid. If
  250. found, MachineInfo will be returned with the information
  251. requested, otherwise if we are accepting new clients we
  252. may create the entry ourselves. otherwise, we just fail.
  253. Arguments:
  254. DhcpReceiveMessage - a pointer to the message received from the client
  255. DhcpOptions - a pointer to the DHCP options gotton from the end of the
  256. message the client sent
  257. Guid - a pointer to memory for the guid to be copied to
  258. GuidLength - a pointer to a dword to copy the guid length to
  259. MachineInfo - a pointer to memory for us to client machine
  260. information to. if we fail, this could be
  261. returned as null.
  262. Return Value:
  263. Windows Error.
  264. --*/
  265. {
  266. DWORD gLength = BINL_GUID_LENGTH;
  267. const LONG AllFs[] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
  268. const LONG AllZeros[] = { 0x0, 0x0, 0x0, 0x0 };
  269. DWORD err;
  270. ULONG SecondsSinceBoot;
  271. DWORD bytesToCopy = 0;
  272. TraceFunc("GetGuidFromPacket( )\n" );
  273. BinlAssert(sizeof(AllZeros) == BINL_GUID_LENGTH );
  274. BinlAssert(sizeof(AllFs) == BINL_GUID_LENGTH);
  275. if (DhcpOptions->GuidLength == 0) {
  276. useNicAddress:
  277. memset(Guid, 0x0, BINL_GUID_LENGTH);
  278. if (DhcpReceiveMessage->HardwareAddressLength > BINL_GUID_LENGTH) {
  279. bytesToCopy = BINL_GUID_LENGTH;
  280. } else {
  281. bytesToCopy = DhcpReceiveMessage->HardwareAddressLength;
  282. }
  283. memcpy(Guid + BINL_GUID_LENGTH - bytesToCopy,
  284. DhcpReceiveMessage->HardwareAddress,
  285. bytesToCopy
  286. );
  287. } else {
  288. if (DhcpOptions->GuidLength > BINL_GUID_LENGTH) {
  289. memcpy(Guid, DhcpOptions->Guid + DhcpOptions->GuidLength - BINL_GUID_LENGTH, BINL_GUID_LENGTH);
  290. } else {
  291. gLength = DhcpOptions->GuidLength;
  292. memcpy(Guid, DhcpOptions->Guid, gLength);
  293. }
  294. if (!memcmp(Guid, (PUCHAR)AllFs, BINL_GUID_LENGTH) ||
  295. !memcmp(Guid, (PUCHAR)AllZeros, BINL_GUID_LENGTH)) {
  296. //
  297. // if they specified all 00s or all FFs, use the NIC address.
  298. //
  299. goto useNicAddress;
  300. }
  301. }
  302. if (GuidLength) {
  303. *GuidLength = (bytesToCopy) ? bytesToCopy : gLength;
  304. }
  305. //
  306. // we return STATUS_SUCCESS if we can handle this client.
  307. //
  308. // If a cache entry is found here, then it will be marked as InProgress as
  309. // a side effect of finding it. We need to call BinlDoneWithCacheEntry
  310. // when we're done with the entry.
  311. //
  312. // SecondsSinceBoot may have been sent on the network in network order.
  313. // To correct this we assume the lower of the two bytes is the high byte.
  314. // So if the high byte is more than the low one, we flip them.
  315. //
  316. SecondsSinceBoot = DhcpReceiveMessage->SecondsSinceBoot;
  317. if ((SecondsSinceBoot >> 8) > (SecondsSinceBoot % 256)) {
  318. SecondsSinceBoot = (SecondsSinceBoot >> 8) +
  319. ((SecondsSinceBoot % 256) << 8);
  320. }
  321. err = RecognizeClient( Guid,
  322. MachineInfo,
  323. MI_HOSTNAME | MI_BOOTFILENAME,
  324. SecondsSinceBoot,
  325. DhcpOptions->SystemArchitecture );
  326. if ( err == ERROR_BINL_INVALID_GUID ) {
  327. PWCHAR pwch;
  328. WCHAR Buffer[6];
  329. //
  330. // Log an event with the hardware address of the offending client
  331. //
  332. pwch = (PWCHAR)BinlAllocateMemory( (( (sizeof(Buffer)/sizeof(Buffer[0])) - 1 ) *
  333. DhcpReceiveMessage->HardwareAddressLength + 1 ) *
  334. sizeof(WCHAR));
  335. if (pwch != NULL) {
  336. INT i;
  337. *pwch = UNICODE_NULL;
  338. for (i=0 ; i < DhcpReceiveMessage->HardwareAddressLength; i++) {
  339. swprintf(Buffer, L" 0x%2x", (ULONG)(DhcpReceiveMessage->HardwareAddress[i]));
  340. wcscat(pwch, Buffer);
  341. }
  342. BinlReportEventW(EVENT_SERVER_CLIENT_WITHOUT_GUID,
  343. EVENTLOG_INFORMATION_TYPE,
  344. 1,
  345. 0,
  346. &pwch,
  347. NULL
  348. );
  349. BinlFreeMemory( pwch );
  350. }
  351. }
  352. return err;
  353. }
  354. DWORD
  355. ProcessBinlDiscoverInDhcp(
  356. LPDHCP_MESSAGE DhcpReceiveMessage,
  357. LPDHCP_SERVER_OPTIONS DhcpOptions
  358. )
  359. /*++
  360. Routine Description:
  361. this is a callback routine for a binl discover
  362. will call GetGuidFromPacket which is start the
  363. discovery process for the client.
  364. Arguments:
  365. DhcpReceiveMessage - a pointer to the packet received from
  366. the client.
  367. dhcpOptions - options extracted from the end of the request
  368. Return Value:
  369. Windows Error.
  370. --*/
  371. {
  372. DWORD Error;
  373. UCHAR Guid[BINL_GUID_LENGTH];
  374. PMACHINE_INFO machineInfo = NULL;
  375. TraceFunc("ProcessBinlDiscoverInDhcp( )\n" );
  376. if ( !AnswerRequests ) {
  377. BinlPrint((DEBUG_OPTIONS, "Client ignored - Not answering requests (AnswerRequests == FALSE)\n" ));
  378. return ERROR_BINL_INVALID_BINL_CLIENT;
  379. }
  380. if (BinlGlobalAuthorized == FALSE) {
  381. BinlPrint((DEBUG_ROGUE, "BINL has not passed rogue detection. Ignoring packet.\n" ));
  382. //
  383. // We'll possibly log an event here since we don't log an event
  384. // at startup saying what our rogue state is.
  385. //
  386. LogCurrentRogueState( TRUE );
  387. return ERROR_BINL_INVALID_BINL_CLIENT;
  388. }
  389. //
  390. // If a cacheEntry is found here, then it will be marked as InProgress as
  391. // a side effect of finding it. We need to call BinlDoneWithCacheEntry
  392. // when we're done with the entry.
  393. //
  394. Error = GetGuidFromPacket( DhcpReceiveMessage,
  395. DhcpOptions,
  396. Guid,
  397. NULL,
  398. &machineInfo
  399. );
  400. if (machineInfo != NULL) {
  401. BinlDoneWithCacheEntry( machineInfo, FALSE );
  402. }
  403. if( Error != ERROR_SUCCESS ) {
  404. BinlPrint(( DEBUG_STOC, "BinlDiscover failed with Dhcp server, 0x%x\n", Error ));
  405. }
  406. return( Error );
  407. }
  408. DWORD
  409. ProcessBinlDiscover(
  410. LPBINL_REQUEST_CONTEXT RequestContext,
  411. LPDHCP_SERVER_OPTIONS DhcpOptions
  412. )
  413. /*++
  414. Routine Description:
  415. This function will create the response message if necessary.
  416. Arguments:
  417. RequestContext - A pointer to the BinlRequestContext block for
  418. this request.
  419. dhcpOptions - Interesting options extracted from the request.
  420. Return Value:
  421. Windows Error.
  422. --*/
  423. {
  424. DWORD Error;
  425. LPDHCP_MESSAGE dhcpReceiveMessage;
  426. LPDHCP_MESSAGE dhcpSendMessage;
  427. BYTE messageType;
  428. LPOPTION Option;
  429. LPBYTE OptionEnd;
  430. PMACHINE_INFO pMachineInfo = NULL;
  431. UCHAR Guid[ BINL_GUID_LENGTH ];
  432. DHCP_IP_ADDRESS ipaddr;
  433. TraceFunc("ProcessBinlDiscover( )\n" );
  434. dhcpReceiveMessage = (LPDHCP_MESSAGE) RequestContext->ReceiveBuffer;
  435. //
  436. // get our ip address. later we will append this to the sender's
  437. // message, that way all communication after this is unicast.
  438. //
  439. ipaddr = BinlGetMyNetworkAddress( RequestContext );
  440. if ( ipaddr == 0 ) {
  441. Error = ERROR_BINL_INVALID_BINL_CLIENT;
  442. goto Cleanup;
  443. }
  444. //
  445. // If the client specified a server identifier option, we should
  446. // drop this packet unless the identified server is this one.
  447. //
  448. if ( DhcpOptions->Server != NULL ) {
  449. if (*DhcpOptions->Server != ipaddr) {
  450. Error = ERROR_BINL_INVALID_BINL_CLIENT;
  451. goto Cleanup;
  452. }
  453. }
  454. //
  455. // If a cacheEntry is found here, then it will be marked as InProgress as
  456. // a side effect of finding it. We need to call BinlDoneWithCacheEntry
  457. // when we're done with the entry.
  458. //
  459. Error = GetGuidFromPacket( dhcpReceiveMessage,
  460. DhcpOptions,
  461. Guid,
  462. NULL,
  463. &pMachineInfo
  464. );
  465. if (Error != ERROR_SUCCESS) {
  466. goto Cleanup;
  467. }
  468. //
  469. // Generate and send a reply.
  470. //
  471. dhcpReceiveMessage->BootFileName[ BOOT_FILE_SIZE - 1 ] = '\0';
  472. dhcpSendMessage = (LPDHCP_MESSAGE) RequestContext->SendBuffer;
  473. RtlZeroMemory( RequestContext->SendBuffer, DHCP_SEND_MESSAGE_SIZE );
  474. dhcpSendMessage->Operation = BOOT_REPLY;
  475. dhcpSendMessage->TransactionID = dhcpReceiveMessage->TransactionID;
  476. dhcpSendMessage->ClientIpAddress = dhcpReceiveMessage->ClientIpAddress;
  477. dhcpSendMessage->YourIpAddress = dhcpReceiveMessage->YourIpAddress;
  478. if (pMachineInfo != NULL && pMachineInfo->HostAddress != 0) {
  479. dhcpSendMessage->BootstrapServerAddress = pMachineInfo->HostAddress;
  480. } else {
  481. dhcpSendMessage->BootstrapServerAddress = ipaddr;
  482. }
  483. dhcpSendMessage->RelayAgentIpAddress = dhcpReceiveMessage->RelayAgentIpAddress;
  484. dhcpSendMessage->Reserved = dhcpReceiveMessage->Reserved;
  485. dhcpSendMessage->HardwareAddressType = dhcpReceiveMessage->HardwareAddressType;
  486. dhcpSendMessage->HardwareAddressLength = dhcpReceiveMessage->HardwareAddressLength;
  487. RtlCopyMemory(dhcpSendMessage->HardwareAddress,
  488. dhcpReceiveMessage->HardwareAddress,
  489. dhcpReceiveMessage->HardwareAddressLength );
  490. Option = &dhcpSendMessage->Option;
  491. OptionEnd = (LPBYTE)dhcpSendMessage + DHCP_SEND_MESSAGE_SIZE;
  492. Option = (LPOPTION) DhcpAppendMagicCookie( (LPBYTE) Option, OptionEnd );
  493. //
  494. // Append OPTIONS.
  495. //
  496. messageType = DHCP_OFFER_MESSAGE;
  497. Option = DhcpAppendOption(
  498. Option,
  499. OPTION_MESSAGE_TYPE,
  500. &messageType,
  501. 1,
  502. OptionEnd
  503. );
  504. Option = DhcpAppendOption(
  505. Option,
  506. OPTION_SERVER_IDENTIFIER,
  507. &ipaddr,
  508. sizeof(ipaddr),
  509. OptionEnd );
  510. Option = DhcpAppendOption(
  511. Option,
  512. OPTION_CLIENT_CLASS_INFO,
  513. "PXEClient",
  514. 9,
  515. OptionEnd
  516. );
  517. //
  518. // Finally, add client requested parameters.
  519. //
  520. if ( DhcpOptions->ParameterRequestList != NULL ) {
  521. Option = AppendClientRequestedParameters(
  522. 0,
  523. 0,
  524. DhcpOptions->ParameterRequestList,
  525. DhcpOptions->ParameterRequestListLength,
  526. Option,
  527. OptionEnd,
  528. DhcpOptions->ClassIdentifier,
  529. DhcpOptions->ClassIdentifierLength,
  530. FALSE
  531. );
  532. }
  533. Option = DhcpAppendOption(
  534. Option,
  535. OPTION_END,
  536. NULL,
  537. 0,
  538. OptionEnd
  539. );
  540. RequestContext->SendMessageSize = (DWORD)((LPBYTE)Option - (LPBYTE)dhcpSendMessage);
  541. BinlAssert( RequestContext->SendMessageSize <= DHCP_SEND_MESSAGE_SIZE );
  542. Error = ERROR_SUCCESS;
  543. Cleanup:
  544. if ( pMachineInfo ) {
  545. BinlDoneWithCacheEntry( pMachineInfo, FALSE );
  546. }
  547. if( Error != ERROR_SUCCESS ) {
  548. BinlPrintDbg(( DEBUG_STOC, "!! Error 0x%08x - DhcpDiscover failed.\n", Error ));
  549. }
  550. return( Error );
  551. }
  552. DWORD
  553. ProcessBinlRequestInDhcp(
  554. LPDHCP_MESSAGE DhcpReceiveMessage,
  555. LPDHCP_SERVER_OPTIONS DhcpOptions,
  556. PCHAR HostName,
  557. PCHAR BootFileName,
  558. DHCP_IP_ADDRESS *BootstrapServerAddress,
  559. LPOPTION *Option,
  560. PBYTE OptionEnd
  561. )
  562. /*++
  563. Routine Description:
  564. This function will create the response message if necessary.
  565. Arguments:
  566. dhcpOptions - Interesting options extracted from the request.
  567. Return Value:
  568. Windows Error.
  569. --*/
  570. {
  571. DWORD Error;
  572. PMACHINE_INFO pMachineInfo = NULL;
  573. BOOLEAN includePXE = TRUE;
  574. DHCP_IP_ADDRESS ipaddr;
  575. UCHAR Guid[BINL_GUID_LENGTH];
  576. DWORD GuidLength;
  577. TraceFunc("ProcessBinlRequestInDhcp( )\n" );
  578. if ( !AnswerRequests ) {
  579. BinlPrint((DEBUG_OPTIONS, "Client ignored - Not answering requests (AnswerRequests == FALSE)\n" ));
  580. return ERROR_BINL_INVALID_BINL_CLIENT;
  581. }
  582. if (BinlGlobalAuthorized == FALSE) {
  583. BinlPrint((DEBUG_ROGUE, "BINL has not passed rogue detection. Ignoring packet.\n" ));
  584. //
  585. // We'll possibly log an event here since we don't log an event
  586. // at startup saying what our rogue state is.
  587. //
  588. LogCurrentRogueState( TRUE );
  589. return ERROR_BINL_INVALID_BINL_CLIENT;
  590. }
  591. //
  592. // If a cache entry is found here, then it will be marked as InProgress as
  593. // a side effect of finding it. We need to call BinlDoneWithCacheEntry
  594. // when we're done with the entry.
  595. //
  596. Error = GetGuidFromPacket( DhcpReceiveMessage,
  597. DhcpOptions,
  598. Guid,
  599. &GuidLength,
  600. &pMachineInfo
  601. );
  602. if (Error != ERROR_SUCCESS) {
  603. goto Cleanup;
  604. }
  605. if (pMachineInfo->HostName == NULL) {
  606. Error = ERROR_BINL_INVALID_BINL_CLIENT;
  607. goto Cleanup;
  608. }
  609. if (!BinlUnicodeToAnsi(pMachineInfo->HostName,HostName,BOOT_SERVER_SIZE)) {
  610. Error = ERROR_BINL_INVALID_BINL_CLIENT;
  611. goto Cleanup;
  612. }
  613. if (!BinlUnicodeToAnsi(pMachineInfo->BootFileName,BootFileName,BOOT_FILE_SIZE)) {
  614. Error = ERROR_BINL_INVALID_BINL_CLIENT;
  615. goto Cleanup;
  616. }
  617. BinlPrintDbg(( DEBUG_MISC, "HostName: %s\n", HostName ));
  618. BinlPrintDbg(( DEBUG_MISC, "BootFileName: %s\n", BootFileName ));
  619. //
  620. // if the server is our own, then the machineInfo->HostAddress will be
  621. // 0 and the DHCP server will fill in the correct one for us so long as
  622. // we return success.
  623. //
  624. memcpy( BootstrapServerAddress,
  625. &pMachineInfo->HostAddress,
  626. sizeof( DHCP_IP_ADDRESS ) );
  627. if (DhcpOptions->GuidLength != 0) {
  628. *Option = DhcpAppendOption(
  629. *Option,
  630. OPTION_CLIENT_GUID,
  631. DhcpOptions->Guid,
  632. DhcpOptions->GuidLength,
  633. OptionEnd );
  634. } else {
  635. UCHAR TmpBuffer[17];
  636. TmpBuffer[0] = '\0';
  637. memcpy(TmpBuffer + 1, Guid, GuidLength);
  638. *Option = DhcpAppendOption(
  639. *Option,
  640. OPTION_CLIENT_GUID,
  641. TmpBuffer,
  642. 17,
  643. OptionEnd );
  644. }
  645. //
  646. // check if OPTION_CLIENT_CLASS_INFO is already specified, if so, then
  647. // don't put PXEClient in again
  648. //
  649. if (DhcpOptions->ParameterRequestList != NULL) {
  650. LPBYTE requestList = DhcpOptions->ParameterRequestList;
  651. ULONG listLength = DhcpOptions->ParameterRequestListLength;
  652. while (listLength > 0) {
  653. if (*requestList == OPTION_CLIENT_CLASS_INFO) {
  654. includePXE = FALSE;
  655. break;
  656. }
  657. listLength--;
  658. requestList++;
  659. }
  660. }
  661. if (includePXE) {
  662. *Option = DhcpAppendOption(
  663. *Option,
  664. OPTION_CLIENT_CLASS_INFO,
  665. "PXEClient",
  666. 9,
  667. OptionEnd
  668. );
  669. }
  670. Error = ERROR_SUCCESS;
  671. Cleanup:
  672. if (pMachineInfo != NULL) {
  673. BinlDoneWithCacheEntry( pMachineInfo, FALSE );
  674. }
  675. if( Error != ERROR_SUCCESS ) {
  676. BinlPrintDbg(( DEBUG_STOC, "!! Error 0x%08x - BINL Request failed.\n", Error ));
  677. }
  678. return( Error );
  679. }
  680. DWORD
  681. ProcessBinlRequest(
  682. LPBINL_REQUEST_CONTEXT RequestContext,
  683. LPDHCP_SERVER_OPTIONS DhcpOptions
  684. )
  685. /*++
  686. Routine Description:
  687. This function will create the response message if necessary.
  688. Arguments:
  689. RequestContext - A pointer to the BinlRequestContext block for
  690. this request.
  691. dhcpOptions - Interesting options extracted from the request.
  692. Return Value:
  693. Windows Error.
  694. --*/
  695. {
  696. DWORD Error;
  697. LPDHCP_MESSAGE dhcpReceiveMessage;
  698. LPDHCP_MESSAGE dhcpSendMessage;
  699. BYTE messageType;
  700. LPOPTION Option;
  701. LPBYTE OptionEnd;
  702. PMACHINE_INFO pMachineInfo = NULL;
  703. UCHAR Guid[ BINL_GUID_LENGTH ];
  704. DHCP_IP_ADDRESS ipaddr;
  705. DHCP_IP_ADDRESS boostrapIpAddr;
  706. TraceFunc("ProcessBinlRequest( )\n" );
  707. #if DBG
  708. if ( BinlRepeatSleep )
  709. {
  710. BinlPrintDbg((DEBUG_STOC, "Delay response %u milliseconds.\n", BinlRepeatSleep ));
  711. Sleep( BinlRepeatSleep );
  712. BinlPrintDbg((DEBUG_STOC, "Awakening from sleep...\n" ));
  713. }
  714. #endif // DBG
  715. dhcpReceiveMessage = (LPDHCP_MESSAGE) RequestContext->ReceiveBuffer;
  716. //
  717. // If the client specified a server identifier option, we should
  718. // drop this packet unless the identified server is this one.
  719. //
  720. ipaddr = BinlGetMyNetworkAddress( RequestContext );
  721. if ( ipaddr == 0 ) {
  722. Error = ERROR_BINL_INVALID_BINL_CLIENT;
  723. goto Cleanup;
  724. }
  725. if ( DhcpOptions->Server != NULL ) {
  726. if ( *DhcpOptions->Server != ipaddr ) {
  727. Error = ERROR_BINL_INVALID_BINL_CLIENT;
  728. goto Cleanup;
  729. }
  730. }
  731. //
  732. // If a cacheEntry is found here, then it will be marked as InProgress as
  733. // a side effect of finding it. We need to call BinlDoneWithCacheEntry
  734. // when we're done with the entry.
  735. //
  736. Error = GetGuidFromPacket( dhcpReceiveMessage,
  737. DhcpOptions,
  738. Guid,
  739. NULL,
  740. &pMachineInfo
  741. );
  742. if (Error != ERROR_SUCCESS) {
  743. goto Cleanup;
  744. }
  745. //
  746. // Generate and send a reply.
  747. //
  748. dhcpReceiveMessage->BootFileName[ BOOT_FILE_SIZE - 1 ] = '\0';
  749. dhcpSendMessage = (LPDHCP_MESSAGE) RequestContext->SendBuffer;
  750. RtlZeroMemory( RequestContext->SendBuffer, DHCP_SEND_MESSAGE_SIZE );
  751. dhcpSendMessage->Operation = BOOT_REPLY;
  752. dhcpSendMessage->TransactionID = dhcpReceiveMessage->TransactionID;
  753. dhcpSendMessage->ClientIpAddress = dhcpReceiveMessage->ClientIpAddress;
  754. dhcpSendMessage->YourIpAddress = dhcpReceiveMessage->YourIpAddress;
  755. dhcpSendMessage->RelayAgentIpAddress = dhcpReceiveMessage->RelayAgentIpAddress;
  756. dhcpSendMessage->Reserved = dhcpReceiveMessage->Reserved;
  757. dhcpSendMessage->HardwareAddressType = dhcpReceiveMessage->HardwareAddressType;
  758. dhcpSendMessage->HardwareAddressLength = dhcpReceiveMessage->HardwareAddressLength;
  759. RtlCopyMemory(dhcpSendMessage->HardwareAddress,
  760. dhcpReceiveMessage->HardwareAddress,
  761. min(dhcpReceiveMessage->HardwareAddressLength, sizeof(dhcpSendMessage->HardwareAddress)) );
  762. if (pMachineInfo->HostName == NULL) {
  763. Error = ERROR_BINL_INVALID_BINL_CLIENT;
  764. goto Cleanup;
  765. }
  766. // Comparing BYTE count to CHAR count
  767. BinlAssert( sizeof( dhcpSendMessage->HostName ) >= wcslen( pMachineInfo->HostName ) );
  768. BinlAssert( sizeof( dhcpSendMessage->BootFileName ) >= wcslen( pMachineInfo->BootFileName ) );
  769. if (!BinlUnicodeToAnsi(pMachineInfo->HostName,dhcpSendMessage->HostName,BOOT_SERVER_SIZE)) {
  770. Error = ERROR_BINL_INVALID_BINL_CLIENT;
  771. goto Cleanup;
  772. }
  773. if (!BinlUnicodeToAnsi(pMachineInfo->BootFileName,dhcpSendMessage->BootFileName,BOOT_FILE_SIZE)) {
  774. Error = ERROR_BINL_INVALID_BINL_CLIENT;
  775. goto Cleanup;
  776. }
  777. //
  778. // if the machineinfo->HostAddress is zero, then that means the hostname
  779. // is the same as ours. we therefore slap in our own ipaddress in.
  780. //
  781. boostrapIpAddr = pMachineInfo->HostAddress;
  782. if (boostrapIpAddr == 0) {
  783. boostrapIpAddr = ipaddr;
  784. }
  785. dhcpSendMessage->BootstrapServerAddress = boostrapIpAddr;
  786. BinlPrintDbg(( DEBUG_MISC, "HostName: %s\n", dhcpSendMessage->HostName ));
  787. BinlPrintDbg(( DEBUG_MISC, "HostAddress: %u.%u.%u.%u\n",
  788. dhcpSendMessage->BootstrapServerAddress & 0xFF,
  789. (dhcpSendMessage->BootstrapServerAddress >> 8) & 0xFF,
  790. (dhcpSendMessage->BootstrapServerAddress >> 16) & 0xFF,
  791. (dhcpSendMessage->BootstrapServerAddress >> 24) & 0xFF ));
  792. BinlPrintDbg(( DEBUG_MISC, "BootFileName: %s\n", dhcpSendMessage->BootFileName ));
  793. Option = &dhcpSendMessage->Option;
  794. OptionEnd = (LPBYTE)dhcpSendMessage + DHCP_SEND_MESSAGE_SIZE;
  795. Option = (LPOPTION) DhcpAppendMagicCookie( (LPBYTE) Option, OptionEnd );
  796. //
  797. // Append OPTIONS.
  798. //
  799. messageType = DHCP_ACK_MESSAGE;
  800. Option = DhcpAppendOption(
  801. Option,
  802. OPTION_MESSAGE_TYPE,
  803. &messageType,
  804. 1,
  805. OptionEnd
  806. );
  807. Option = DhcpAppendOption(
  808. Option,
  809. OPTION_SERVER_IDENTIFIER,
  810. &ipaddr,
  811. sizeof(ipaddr),
  812. OptionEnd );
  813. if (DhcpOptions->GuidLength != 0) {
  814. Option = DhcpAppendOption(
  815. Option,
  816. OPTION_CLIENT_GUID,
  817. DhcpOptions->Guid,
  818. (UCHAR)DhcpOptions->GuidLength,
  819. OptionEnd );
  820. } else {
  821. UCHAR TmpBuffer[BINL_GUID_LENGTH + 1];
  822. TmpBuffer[0] = '\0';
  823. memcpy(TmpBuffer + 1, pMachineInfo->Guid, BINL_GUID_LENGTH);
  824. Option = DhcpAppendOption(
  825. Option,
  826. OPTION_CLIENT_GUID,
  827. TmpBuffer,
  828. sizeof(TmpBuffer),
  829. OptionEnd );
  830. }
  831. Option = DhcpAppendOption(
  832. Option,
  833. OPTION_CLIENT_CLASS_INFO,
  834. "PXEClient",
  835. 9,
  836. OptionEnd
  837. );
  838. //
  839. // Finally, add client requested parameters.
  840. //
  841. if ( DhcpOptions->ParameterRequestList != NULL ) {
  842. Option = AppendClientRequestedParameters(
  843. 0,
  844. 0,
  845. DhcpOptions->ParameterRequestList,
  846. DhcpOptions->ParameterRequestListLength,
  847. Option,
  848. OptionEnd,
  849. DhcpOptions->ClassIdentifier,
  850. DhcpOptions->ClassIdentifierLength,
  851. FALSE
  852. );
  853. }
  854. Option = DhcpAppendOption(
  855. Option,
  856. OPTION_END,
  857. NULL,
  858. 0,
  859. OptionEnd
  860. );
  861. RequestContext->SendMessageSize = (DWORD)((LPBYTE)Option - (LPBYTE)dhcpSendMessage);
  862. BinlAssert( RequestContext->SendMessageSize <= DHCP_SEND_MESSAGE_SIZE );
  863. Error = ERROR_SUCCESS;
  864. Cleanup:
  865. if ( pMachineInfo ) {
  866. BinlDoneWithCacheEntry( pMachineInfo, FALSE );
  867. }
  868. if( Error != ERROR_SUCCESS ) {
  869. BinlPrintDbg(( DEBUG_STOC, "!! Error 0x%08x - BINL Request failed.\n", Error ));
  870. }
  871. return( Error );
  872. }
  873. DWORD
  874. ProcessBinlInform(
  875. IN LPBINL_REQUEST_CONTEXT RequestContext,
  876. IN LPDHCP_SERVER_OPTIONS DhcpOptions
  877. )
  878. /*++
  879. Routine Description:
  880. This function will create the response message to the inform packet iff
  881. the query is asking for our domain name.
  882. Arguments:
  883. RequestContext - A pointer to the BinlRequestContext block for
  884. this request.
  885. dhcpOptions - Interesting options extracted from the request.
  886. Return Value:
  887. Windows Error.
  888. --*/
  889. {
  890. DWORD Error;
  891. LPDHCP_MESSAGE dhcpReceiveMessage;
  892. LPDHCP_MESSAGE dhcpSendMessage;
  893. LPOPTION Option;
  894. LPBYTE OptionEnd;
  895. PCHAR domain = NULL;
  896. DHCP_IP_ADDRESS ipaddr;
  897. TraceFunc("ProcessBinlInform( )\n" );
  898. dhcpReceiveMessage = (LPDHCP_MESSAGE)RequestContext->ReceiveBuffer;
  899. dhcpSendMessage = (LPDHCP_MESSAGE)RequestContext->SendBuffer;
  900. ipaddr = BinlGetMyNetworkAddress( RequestContext );
  901. if ( ipaddr == 0 ) {
  902. Error = ERROR_BINL_INVALID_BINL_CLIENT;
  903. goto exit_inform;
  904. }
  905. if ( ! DhcpOptions->DSDomainNameRequested ) {
  906. BinlPrintDbg((DEBUG_STOC, "Ignoring inform as no domain name option present.\n"));
  907. Error = ERROR_BINL_INVALID_BINL_CLIENT;
  908. goto exit_inform;
  909. }
  910. domain = GetDhcpDomainName();
  911. if (domain == NULL) {
  912. BinlPrintDbg((DEBUG_STOC, "Couldn't get domain name!\n"));
  913. Error = ERROR_BINL_INVALID_BINL_CLIENT;
  914. goto exit_inform;
  915. }
  916. // if the client IP address is not zero, we may AV in dhcpssvc because
  917. // it updates a global counter tracking informs. Always have this as 0.
  918. Option = FormatDhcpInformAck( // Here come the actual formatting of the ack!
  919. dhcpReceiveMessage,
  920. dhcpSendMessage,
  921. 0, // on a ack to an inform query for name, IP address not needed.
  922. ipaddr
  923. );
  924. OptionEnd = (LPBYTE)dhcpSendMessage + DHCP_SEND_MESSAGE_SIZE;
  925. // our enterprise name was requested, append it
  926. Option = DhcpAppendEnterpriseName(
  927. Option,
  928. domain,
  929. OptionEnd
  930. );
  931. // also, make the server send out a broadcast: if someone is using a bad
  932. // ipaddr, we should make sure we reach him
  933. dhcpSendMessage->Reserved = dhcpReceiveMessage->Reserved = htons(DHCP_BROADCAST);
  934. //
  935. // Finally, add client requested parameters.
  936. //
  937. if ( DhcpOptions->ParameterRequestList != NULL ) {
  938. Option = AppendClientRequestedParameters(
  939. 0,
  940. 0,
  941. DhcpOptions->ParameterRequestList,
  942. DhcpOptions->ParameterRequestListLength,
  943. Option,
  944. OptionEnd,
  945. DhcpOptions->ClassIdentifier,
  946. DhcpOptions->ClassIdentifierLength,
  947. FALSE
  948. );
  949. }
  950. Option = DhcpAppendOption(
  951. Option,
  952. OPTION_END,
  953. NULL,
  954. 0,
  955. OptionEnd
  956. );
  957. RequestContext->SendMessageSize = (DWORD)((LPBYTE)Option - (LPBYTE)dhcpSendMessage);
  958. BinlAssert( RequestContext->SendMessageSize <= DHCP_SEND_MESSAGE_SIZE );
  959. Error = ERROR_SUCCESS;
  960. exit_inform:
  961. if (domain != NULL) {
  962. LocalFree( domain );
  963. }
  964. return Error;
  965. }
  966. LPOPTION
  967. ConsiderAppendingOption(
  968. DHCP_IP_ADDRESS IpAddress,
  969. DHCP_IP_ADDRESS SubnetMask,
  970. LPOPTION Option,
  971. BYTE OptionType,
  972. LPBYTE OptionEnd,
  973. CHAR *ClassIdentifier,
  974. DWORD ClassIdentifierLength,
  975. BOOL fSwitchedSubnet
  976. )
  977. /*++
  978. Routine Description:
  979. This function conditionally appends an option value to a response
  980. message. The option is appended if the server has a valid value
  981. to append.
  982. Arguments:
  983. IpAddress - The IP address of the client.
  984. SubnetMask - The subnet mask of the client.
  985. Option - A pointer to the place in the message buffer to append the
  986. option.
  987. OptionType - The option number to consider appending.
  988. OptionEnd - End of Option Buffer
  989. Return Value:
  990. A pointer to end of the appended data.
  991. --*/
  992. {
  993. LPBYTE optionValue = NULL;
  994. DWORD optionSize;
  995. DWORD status;
  996. DWORD dwUnused;
  997. TraceFunc( "ConsiderAppendingOption( )\n" );
  998. switch ( OptionType ) {
  999. //
  1000. // Options already handled.
  1001. //
  1002. case OPTION_SUBNET_MASK:
  1003. case OPTION_REQUESTED_ADDRESS:
  1004. case OPTION_LEASE_TIME:
  1005. case OPTION_OK_TO_OVERLAY:
  1006. case OPTION_MESSAGE_TYPE:
  1007. case OPTION_RENEWAL_TIME:
  1008. case OPTION_REBIND_TIME:
  1009. case OPTION_CLIENT_CLASS_INFO:
  1010. case OPTION_VENDOR_SPEC_INFO:
  1011. //
  1012. // Options it is illegal to ask for.
  1013. //
  1014. case OPTION_PAD:
  1015. case OPTION_PARAMETER_REQUEST_LIST:
  1016. case OPTION_END:
  1017. // Options for DHCP server, not for BINL
  1018. case OPTION_ROUTER_ADDRESS:
  1019. BinlPrintDbg(( DEBUG_ERRORS,
  1020. "Unrecognized option %d\n", OptionType));
  1021. break;
  1022. default:
  1023. break;
  1024. }
  1025. return Option;
  1026. }
  1027. LPOPTION
  1028. AppendClientRequestedParameters(
  1029. DHCP_IP_ADDRESS IpAddress,
  1030. DHCP_IP_ADDRESS SubnetMask,
  1031. LPBYTE RequestedList,
  1032. DWORD ListLength,
  1033. LPOPTION Option,
  1034. LPBYTE OptionEnd,
  1035. CHAR *ClassIdentifier,
  1036. DWORD ClassIdentifierLength,
  1037. BOOL fSwitchedSubnet
  1038. )
  1039. /*++
  1040. Routine Description:
  1041. Arguments:
  1042. Return Value:
  1043. A pointer to the end of appended data.
  1044. --*/
  1045. {
  1046. while ( ListLength > 0) {
  1047. Option = ConsiderAppendingOption(
  1048. IpAddress,
  1049. SubnetMask,
  1050. Option,
  1051. *RequestedList,
  1052. OptionEnd,
  1053. ClassIdentifier,
  1054. ClassIdentifierLength,
  1055. fSwitchedSubnet
  1056. );
  1057. ListLength--;
  1058. RequestedList++;
  1059. }
  1060. return Option;
  1061. }
  1062. DWORD
  1063. RecognizeClient(
  1064. PUCHAR pGuid,
  1065. PMACHINE_INFO * ppMachineInfo,
  1066. DWORD dwRequestedInfo,
  1067. ULONG SecondsSinceBoot,
  1068. USHORT SystemArchitecture
  1069. )
  1070. /*++
  1071. Routine Description:
  1072. This function only return ERROR_SUCCESS if we need to process the message
  1073. from this client. It may optionally return a cache entry if we actually
  1074. go off to the DS to get the entry.
  1075. Arguments:
  1076. Guid - Client identifier, sent to us by them.
  1077. SecondsSinceBoot - from the client. If we don't know this client and
  1078. this value is small then maybe this client is owned by another BINL
  1079. server. Give the other server time to respond before we send
  1080. OSChooser.
  1081. This gets around the problem (mostly) of two BINL servers that are
  1082. talking to two different DCs with a replication delay between them
  1083. where the client gets sent OSCHOOSER multiple times.
  1084. Alas, if DHCP is running on the same box and we're multihomed, we
  1085. can't delay as that will force the client to go to 4011. If the
  1086. client does that, then we'll probably return the wrong address.
  1087. ppMachineInfo - what we found. May be null if we didn't actually go off to
  1088. the DS.
  1089. SystemArchitecture - architecture for the client
  1090. Return Value:
  1091. --*/
  1092. {
  1093. HKEY KeyHandle;
  1094. DWORD Error;
  1095. BinlAssertMsg(dwRequestedInfo == (MI_HOSTNAME | MI_BOOTFILENAME),
  1096. "!! You must modify RecognizeClient() to generate new data\n" );
  1097. BinlAssert(ppMachineInfo);
  1098. TraceFunc( "RecognizeClient( )\n" );
  1099. //
  1100. // Attempt to get the boot parameters. This might fail if
  1101. // the server can't handle any more clients.
  1102. //
  1103. if ( AnswerOnlyValidClients ) {
  1104. //
  1105. // if we're only responding to existing clients, then call off to
  1106. // the DS to get the info.
  1107. //
  1108. Error = GetBootParameters( pGuid,
  1109. ppMachineInfo,
  1110. dwRequestedInfo,
  1111. SystemArchitecture,
  1112. FALSE );
  1113. } else {
  1114. //
  1115. // if we are answering new clients but only if it's after a
  1116. // certain timeout, then call off to the DS to get the info.
  1117. //
  1118. // Allow OSCHOOSER as a valid response, since AnswerOnlyValidClients is FALSE
  1119. //
  1120. Error = GetBootParameters( pGuid,
  1121. ppMachineInfo,
  1122. dwRequestedInfo,
  1123. SystemArchitecture,
  1124. (BOOLEAN) (SecondsSinceBoot >= BinlMinDelayResponseForNewClients) );
  1125. }
  1126. if ( Error == ERROR_SUCCESS ) {
  1127. BinlPrint((DEBUG_OPTIONS, "Recognizing client.\n" ));
  1128. BinlAssert( *ppMachineInfo != NULL );
  1129. if ( (*ppMachineInfo)->MyClient == FALSE ) {
  1130. //
  1131. // the cache entry is telling us not to handle this client.
  1132. //
  1133. BinlPrint((DEBUG_OPTIONS, "Binl cache entry says not to respond.\n" ));
  1134. Error = ERROR_BINL_INVALID_BINL_CLIENT;
  1135. BinlDoneWithCacheEntry( *ppMachineInfo, FALSE );
  1136. *ppMachineInfo = NULL;
  1137. }
  1138. } else {
  1139. if ( AnswerOnlyValidClients ) {
  1140. BinlPrint((DEBUG_OPTIONS, "Client ignored - Not answering for unknown clients (AnswerOnlyValid TRUE)\n" ));
  1141. } else {
  1142. BinlPrint((DEBUG_OPTIONS, "Client ignored - Not answering requests from boot %u < %u\n",
  1143. SecondsSinceBoot,
  1144. BinlMinDelayResponseForNewClients
  1145. ));
  1146. }
  1147. }
  1148. return Error;
  1149. }
  1150. DWORD
  1151. UpdateAccount(
  1152. PCLIENT_STATE ClientState,
  1153. PMACHINE_INFO pMachineInfo,
  1154. BOOL fCreate
  1155. )
  1156. /*++
  1157. Routine Description:
  1158. Create a new computer object. BINL must impersonate the client so that the
  1159. appropriate access checks are performed on the DS.
  1160. Arguments:
  1161. LdapHandle - User credentially created LDAP connection
  1162. pMachineInfo - Information to be used to populate the new MAO
  1163. Return Value:
  1164. Win32 error code or ERROR_SUCCESS.
  1165. --*/
  1166. {
  1167. WCHAR BootFilePath[MAX_PATH];
  1168. ULONG LdapError = LDAP_SUCCESS; // not returned
  1169. DWORD Error = ERROR_SUCCESS; // this is the returned ERROR_BINL code
  1170. ULONG iModCount, i,q;
  1171. ULONG LdapMessageId;
  1172. ULONG LdapMessageType;
  1173. PLDAPMessage LdapMessage = NULL;
  1174. BOOLEAN Impersonating = FALSE;
  1175. LDAP_BERVAL guid_attr_value;
  1176. PLDAP_BERVAL guid_attr_values[2];
  1177. LDAP_BERVAL password_attr_value;
  1178. PLDAP_BERVAL password_attr_values[2];
  1179. DWORD dwRequiredFlags = MI_SAMNAME
  1180. | MI_BOOTFILENAME
  1181. | MI_HOSTNAME
  1182. | MI_SETUPPATH
  1183. | MI_PASSWORD;
  1184. PWCHAR attr_values[6][2];
  1185. PLDAPMod ldap_mods[6];
  1186. LDAPMod SamAccountName;
  1187. LDAPMod ObjectTypeComputer;
  1188. LDAPMod FilePath;
  1189. LDAPMod SetupPathMod;
  1190. LDAPMod UserAccountControl;
  1191. LDAPMod UnicodePwd;
  1192. LDAPMod NicGuid;
  1193. BOOLEAN invalidateCache = FALSE;
  1194. BOOLEAN updateCache = FALSE;
  1195. TraceFunc( "UpdateAccount( )\n" );
  1196. //
  1197. // First impersonate the client.
  1198. //
  1199. Error = OscImpersonate(ClientState);
  1200. if (Error != ERROR_SUCCESS) {
  1201. BinlPrintDbg((DEBUG_ERRORS,
  1202. "UpdateAccount: OscImpersonate failed %lx\n", Error));
  1203. goto Cleanup;
  1204. }
  1205. tryagain:
  1206. Impersonating = TRUE;
  1207. //
  1208. // now initialize all of the properties we want to set on the MAO.
  1209. //
  1210. // Make sure we have all the information we need.
  1211. if ( ! (pMachineInfo->dwFlags & MI_MACHINEDN) || pMachineInfo->MachineDN == NULL ) {
  1212. BinlAssertMsg( 0, "Missing the Machine's DN" );
  1213. OscAddVariableA( ClientState, "SUBERROR", "MACHINEDN" );
  1214. Error = ERROR_BINL_MISSING_VARIABLE;
  1215. goto Cleanup;
  1216. }
  1217. BinlAssert( !fCreate || (( pMachineInfo->dwFlags & dwRequiredFlags ) == dwRequiredFlags ) );
  1218. #if DBG
  1219. // We must have both of these or none of these.
  1220. // meant to have the !!. casts the value twice, so it will be a 0 or a 1
  1221. BinlAssert( !(pMachineInfo->dwFlags & MI_HOSTNAME) == !(pMachineInfo->dwFlags & MI_BOOTFILENAME) );
  1222. #endif
  1223. iModCount = 0;
  1224. if ( AssignNewClientsToServer &&
  1225. (pMachineInfo->dwFlags & (MI_HOSTNAME | MI_BOOTFILENAME)) )
  1226. {
  1227. if ( _snwprintf( BootFilePath,
  1228. sizeof(BootFilePath) / sizeof(BootFilePath[0]),
  1229. L"%ws\\%ws",
  1230. pMachineInfo->HostName,
  1231. pMachineInfo->BootFileName
  1232. ) < 0 ) {
  1233. Error = ERROR_BAD_PATHNAME;
  1234. goto Cleanup;
  1235. }
  1236. BootFilePath[MAX_PATH-1] = L'\0'; // throw in terminating null just to be safe
  1237. attr_values[2][0] = BootFilePath;
  1238. attr_values[2][1] = NULL;
  1239. FilePath.mod_op = 0;
  1240. FilePath.mod_type = L"netbootMachineFilePath";
  1241. FilePath.mod_values = attr_values[2];
  1242. ldap_mods[iModCount++] = &FilePath;
  1243. }
  1244. if ( pMachineInfo->dwFlags & MI_SETUPPATH ) {
  1245. attr_values[3][0] = pMachineInfo->SetupPath;
  1246. attr_values[3][1] = NULL;
  1247. SetupPathMod.mod_op = 0;
  1248. SetupPathMod.mod_type = L"netbootInitialization";
  1249. SetupPathMod.mod_values = attr_values[3];
  1250. ldap_mods[iModCount++] = &SetupPathMod;
  1251. }
  1252. if ( pMachineInfo->dwFlags & MI_GUID ) {
  1253. guid_attr_values[0] = &guid_attr_value;
  1254. guid_attr_values[1] = NULL;
  1255. guid_attr_value.bv_val = pMachineInfo->Guid;
  1256. guid_attr_value.bv_len = BINL_GUID_LENGTH;
  1257. NicGuid.mod_op = LDAP_MOD_BVALUES;
  1258. NicGuid.mod_type = L"netbootGUID";
  1259. NicGuid.mod_bvalues = guid_attr_values;
  1260. ldap_mods[iModCount++] = &NicGuid;
  1261. }
  1262. if ( fCreate && ( pMachineInfo->dwFlags & MI_SAMNAME ) ) {
  1263. attr_values[0][0] = pMachineInfo->SamName;
  1264. attr_values[0][1] = NULL;
  1265. SamAccountName.mod_op = 0;
  1266. SamAccountName.mod_type = L"sAMAccountName";
  1267. SamAccountName.mod_values = attr_values[0];
  1268. ldap_mods[iModCount++] = &SamAccountName;
  1269. }
  1270. attr_values[4][0] = L"4096"; // 0x1000 -- workstation trust account, enabled
  1271. attr_values[4][1] = NULL;
  1272. UserAccountControl.mod_op = 0;
  1273. UserAccountControl.mod_type = L"userAccountControl";
  1274. UserAccountControl.mod_values = attr_values[4];
  1275. ldap_mods[iModCount++] = &UserAccountControl;
  1276. //
  1277. // if we're creating the MAO, then we need to specify the object type
  1278. // as a computer object
  1279. //
  1280. if ( fCreate ) {
  1281. attr_values[1][0] = L"Computer";
  1282. attr_values[1][1] = NULL;
  1283. ObjectTypeComputer.mod_op = 0;
  1284. ObjectTypeComputer.mod_type = L"objectClass";
  1285. ObjectTypeComputer.mod_values = attr_values[1];
  1286. ldap_mods[iModCount++] = &ObjectTypeComputer;
  1287. }
  1288. //
  1289. // Set the operation type depending on the create or modify flag
  1290. //
  1291. for ( i = 0 ; i < iModCount; i++ )
  1292. {
  1293. if ( fCreate ) {
  1294. ldap_mods[i]->mod_op |= LDAP_MOD_ADD;
  1295. } else {
  1296. ldap_mods[i]->mod_op |= LDAP_MOD_REPLACE;
  1297. }
  1298. }
  1299. ldap_mods[iModCount] = NULL; // terminate list
  1300. //
  1301. // The properties are initialized, so now either create or modify the MAO.
  1302. //
  1303. if ( fCreate || iModCount ) {
  1304. if ( fCreate ) {
  1305. BinlPrintDbg((DEBUG_OSC, "UpdateAccount() Creating a new MAO\n" ));
  1306. #if DBG
  1307. for (q = 0;q < iModCount; q++) {
  1308. BinlPrintDbg(( DEBUG_OSC, "LDAP Prop %x: Type: %S Value: %S",
  1309. q,
  1310. ldap_mods[q]->mod_type,
  1311. *ldap_mods[q]->mod_vals.modv_strvals ));
  1312. }
  1313. #endif
  1314. //
  1315. // synchronously Create the object.
  1316. //
  1317. LdapMessageId = ldap_add( ClientState->AuthenticatedDCLdapHandle, pMachineInfo->MachineDN, ldap_mods );
  1318. if (LdapMessageId == -1) {
  1319. Error = ERROR_BINL_FAILED_TO_CREATE_CLIENT;
  1320. LdapError = LdapGetLastError();
  1321. LogLdapError( EVENT_WARNING_LDAP_ADD_ERROR,
  1322. LdapError,
  1323. ClientState->AuthenticatedDCLdapHandle
  1324. );
  1325. BinlPrintDbg(( DEBUG_ERRORS,
  1326. "CreateAccount ldap_add failed %x\n", LdapError));
  1327. goto Cleanup;
  1328. }
  1329. LdapMessageType = ldap_result(
  1330. ClientState->AuthenticatedDCLdapHandle,
  1331. LdapMessageId,
  1332. LDAP_MSG_ALL,
  1333. &BinlLdapSearchTimeout,
  1334. &LdapMessage);
  1335. if (LdapMessageType != LDAP_RES_ADD) {
  1336. BinlPrintDbg(( DEBUG_ERRORS,
  1337. "CreateAccount ldap_result returned type %lx\n", LdapMessageType));
  1338. OscAddVariableA( ClientState, "SUBERROR", "Unexpected LDAP error" );
  1339. Error = ERROR_BINL_FAILED_TO_CREATE_CLIENT;
  1340. goto Cleanup;
  1341. }
  1342. LdapError = ldap_result2error(
  1343. ClientState->AuthenticatedDCLdapHandle,
  1344. LdapMessage,
  1345. 0);
  1346. if (LdapError != LDAP_SUCCESS) {
  1347. if ((LdapError != LDAP_ALREADY_EXISTS) && (LdapError != LDAP_INSUFFICIENT_RIGHTS)) {
  1348. Error = ERROR_BINL_FAILED_TO_CREATE_CLIENT;
  1349. LogLdapError( EVENT_WARNING_LDAP_ADD_ERROR,
  1350. LdapError,
  1351. ClientState->AuthenticatedDCLdapHandle
  1352. );
  1353. BinlPrintDbg(( DEBUG_ERRORS, "!!LdapError 0x%08x - UpdateAccount ldap_add_s( ) failed\n", LdapError));
  1354. goto Cleanup;
  1355. } else {
  1356. BinlPrintDbg((DEBUG_OSC, "UpdateAccount() tried to create an existing account. Try again, but modify existing MAO.\n" ));
  1357. fCreate = FALSE;
  1358. goto tryagain;
  1359. }
  1360. }
  1361. updateCache = TRUE;
  1362. } else {
  1363. //
  1364. // We don't strictly need to reset the properties below, as the
  1365. // content under the MAO should be static. But it won't really
  1366. // hurt things to try to reset in case something does change.
  1367. //
  1368. // Note that the reset of these properties may not succeed because
  1369. // the user may not have permissions to modify the MAO, depending
  1370. // on how the admin locks things down. (The admin can use GPO to
  1371. // allow the user to create MAOs but not modify the objects.)
  1372. //
  1373. //
  1374. // asynchronously reset the properties
  1375. //
  1376. BinlPrintDbg((DEBUG_OSC, "UpdateAccount() updating existing MAO\n" ));
  1377. LdapMessageId = ldap_modify( ClientState->AuthenticatedDCLdapHandle, pMachineInfo->MachineDN, ldap_mods );
  1378. if (LdapMessageId == -1) {
  1379. Error = ERROR_BINL_FAILED_TO_CREATE_CLIENT;
  1380. LdapError = LdapGetLastError();
  1381. LogLdapError( EVENT_WARNING_LDAP_MODIFY_ERROR,
  1382. LdapError,
  1383. ClientState->AuthenticatedDCLdapHandle
  1384. );
  1385. BinlPrintDbg(( DEBUG_ERRORS,
  1386. "UpdateAccount ldap_modify(userAccountControl) failed %x\n", LdapError));
  1387. goto Cleanup;
  1388. }
  1389. LdapMessageType = ldap_result(
  1390. ClientState->AuthenticatedDCLdapHandle,
  1391. LdapMessageId,
  1392. LDAP_MSG_ALL,
  1393. &BinlLdapSearchTimeout,
  1394. &LdapMessage);
  1395. if (LdapMessageType != LDAP_RES_MODIFY) {
  1396. BinlPrintDbg(( DEBUG_ERRORS,
  1397. "CreateAccount ldap_result returned type %lx\n", LdapMessageType));
  1398. OscAddVariableA( ClientState, "SUBERROR", "Unexpected LDAP error" );
  1399. Error = ERROR_BINL_FAILED_TO_CREATE_CLIENT;
  1400. goto Cleanup;
  1401. }
  1402. LdapError = ldap_result2error(
  1403. ClientState->AuthenticatedDCLdapHandle,
  1404. LdapMessage,
  1405. 0);
  1406. if (LdapError != LDAP_SUCCESS) {
  1407. LogLdapError( EVENT_WARNING_LDAP_MODIFY_ERROR,
  1408. LdapError,
  1409. ClientState->AuthenticatedDCLdapHandle
  1410. );
  1411. BinlPrintDbg(( DEBUG_ERRORS, "CreateAccount ldap_result2error failed %x\n", LdapError));
  1412. // if the user doesn't have the rights to change
  1413. // the properties then we'll just silently ignore the error
  1414. // (though we did just log an error for it).
  1415. if ( LdapError != LDAP_INSUFFICIENT_RIGHTS) {
  1416. Error = ERROR_BINL_FAILED_TO_CREATE_CLIENT;
  1417. goto Cleanup;
  1418. }
  1419. LdapError = LDAP_SUCCESS;
  1420. }
  1421. updateCache = TRUE;
  1422. }
  1423. }
  1424. //
  1425. // if we've made it this far, we've got a MAO that's setup properly.
  1426. // Now we need to reset the account password so the domain join is
  1427. // somewhat secure.
  1428. //
  1429. if ( pMachineInfo->dwFlags & MI_PASSWORD ) {
  1430. #ifdef SET_PASSWORD_WITH_LDAP
  1431. iModCount = 0;
  1432. password_attr_values[0] = &password_attr_value;
  1433. password_attr_values[1] = NULL;
  1434. password_attr_value.bv_val = (PUCHAR) pMachineInfo->Password;
  1435. password_attr_value.bv_len = pMachineInfo->PasswordLength;
  1436. UnicodePwd.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES; // you always "Add" the "unicodePwd"
  1437. UnicodePwd.mod_type = L"unicodePwd";
  1438. UnicodePwd.mod_bvalues = password_attr_values;
  1439. ldap_mods[iModCount++] = &UnicodePwd;
  1440. ldap_mods[iModCount] = NULL; // terminate list
  1441. LdapError = ldap_modify_s( ClientState->AuthenticatedDCLdapHandle, pMachineInfo->MachineDN, ldap_mods );
  1442. if (LdapError != LDAP_SUCCESS) {
  1443. LogLdapError( EVENT_WARNING_LDAP_MODIFY_ERROR,
  1444. LdapError,
  1445. ClientState->AuthenticatedDCLdapHandle
  1446. );
  1447. BinlPrintDbg(( DEBUG_ERRORS, "!!LdapError 0x%08x - UpdateAccount ldap_modify_s( ) failed\n", LdapError));
  1448. goto Cleanup;
  1449. }
  1450. #else
  1451. //
  1452. // At this point we depend on LdapMessage being valid, which will
  1453. // *not* be the case if we are only setting the password. This
  1454. // breaks machine replacement for the moment.
  1455. //
  1456. BinlAssert( LdapMessage != NULL );
  1457. Error = OscUpdatePassword(
  1458. ClientState,
  1459. pMachineInfo->SamName,
  1460. pMachineInfo->Password,
  1461. ClientState->AuthenticatedDCLdapHandle,
  1462. LdapMessage);
  1463. if (Error != ERROR_SUCCESS) {
  1464. goto Cleanup;
  1465. }
  1466. #endif
  1467. }
  1468. Cleanup:
  1469. //
  1470. // if the machine name was generated,
  1471. // then attempt to remove it from the queue
  1472. //
  1473. if (ClientState->fAutomaticMachineName) {
  1474. BinlPrintDbg((DEBUG_OSC, "UpdateAccount: removing generated name from Queued DS Names list\n" ));
  1475. Error = RemoveQueuedDSName(pMachineInfo->Name);
  1476. if (Error != ERROR_SUCCESS) {
  1477. BinlPrintDbg(( DEBUG_ERRORS, "RemoveQueuedDSName failed: 0x%x\n", Error));
  1478. if (Error == ERROR_NOT_FOUND) {
  1479. //
  1480. // TODO: RIS currently has no way to deal with this error
  1481. // so make it succeed
  1482. //
  1483. Error = ERROR_SUCCESS;
  1484. }
  1485. }
  1486. }
  1487. //
  1488. // Convert the LdapError to a ERROR_BINL and put the LdapError
  1489. // into SUBERROR.
  1490. //
  1491. if ( LdapError != LDAP_SUCCESS )
  1492. {
  1493. OscCreateLDAPSubError( ClientState, LdapError );
  1494. switch ( LdapError )
  1495. {
  1496. case LDAP_ALREADY_EXISTS:
  1497. Error = ERROR_BINL_DUPLICATE_MACHINE_NAME_FOUND;
  1498. break;
  1499. case LDAP_INVALID_DN_SYNTAX:
  1500. Error = ERROR_BINL_INVALID_OR_MISSING_OU;
  1501. break;
  1502. default:
  1503. Error = ERROR_BINL_FAILED_TO_CREATE_CLIENT;
  1504. break;
  1505. }
  1506. }
  1507. if ( updateCache && ( pMachineInfo->dwFlags & MI_GUID ) ) {
  1508. //
  1509. // update the cached DS information so that it is current. We do
  1510. // this because if the account is created in a child domain, we still
  1511. // have the info cached (even if it hasn't replicated to the GC yet).
  1512. //
  1513. PMACHINE_INFO pCacheEntry = NULL;
  1514. BinlCreateOrFindCacheEntry( pMachineInfo->Guid, TRUE, &pCacheEntry );
  1515. invalidateCache = FALSE;
  1516. // we don't care about the error coming back, only if a record was found.
  1517. if (pCacheEntry != NULL) {
  1518. pCacheEntry->TimeCreated = GetTickCount();
  1519. pCacheEntry->MyClient = TRUE;
  1520. pCacheEntry->EntryExists = TRUE;
  1521. if (pCacheEntry != pMachineInfo) {
  1522. memcpy( &pCacheEntry->HostAddress,
  1523. &pMachineInfo->HostAddress,
  1524. sizeof(pMachineInfo->HostAddress));
  1525. if ( pMachineInfo->Name ) {
  1526. pCacheEntry->Name = BinlStrDup( pMachineInfo->Name );
  1527. if (!pCacheEntry->Name) {
  1528. goto noMemory;
  1529. }
  1530. pCacheEntry->dwFlags |= MI_NAME_ALLOC | MI_NAME;
  1531. }
  1532. if ( pMachineInfo->MachineDN ) {
  1533. pCacheEntry->MachineDN = BinlStrDup( pMachineInfo->MachineDN );
  1534. if (!pCacheEntry->MachineDN) {
  1535. goto noMemory;
  1536. }
  1537. pCacheEntry->dwFlags |= MI_MACHINEDN_ALLOC | MI_MACHINEDN;
  1538. }
  1539. if ( pMachineInfo->SetupPath ) {
  1540. pCacheEntry->SetupPath = BinlStrDup( pMachineInfo->SetupPath );
  1541. if (!pCacheEntry->SetupPath) {
  1542. goto noMemory;
  1543. }
  1544. pCacheEntry->dwFlags |= MI_SETUPPATH_ALLOC | MI_SETUPPATH;
  1545. }
  1546. if ( pMachineInfo->HostName ) {
  1547. pCacheEntry->HostName = BinlStrDup( pMachineInfo->HostName );
  1548. if (!pCacheEntry->HostName) {
  1549. goto noMemory;
  1550. }
  1551. pCacheEntry->dwFlags |= MI_HOSTNAME_ALLOC | MI_HOSTNAME;
  1552. }
  1553. if ( pMachineInfo->SamName ) {
  1554. pCacheEntry->SamName = BinlStrDup( pMachineInfo->SamName );
  1555. if (!pCacheEntry->SamName) {
  1556. goto noMemory;
  1557. }
  1558. pCacheEntry->dwFlags |= MI_SAMNAME_ALLOC | MI_SAMNAME;
  1559. }
  1560. if ( pMachineInfo->Domain ) {
  1561. pCacheEntry->Domain = BinlStrDup( pMachineInfo->Domain );
  1562. if (!pCacheEntry->Domain) {
  1563. noMemory:
  1564. invalidateCache = TRUE;
  1565. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1566. } else {
  1567. pCacheEntry->dwFlags |= MI_DOMAIN_ALLOC | MI_DOMAIN;
  1568. }
  1569. }
  1570. }
  1571. BinlDoneWithCacheEntry( pCacheEntry, invalidateCache );
  1572. }
  1573. }
  1574. if ( invalidateCache && ( pMachineInfo->dwFlags & MI_GUID ) ) {
  1575. //
  1576. // invalidate the cached DS information if we failed because it's stale.
  1577. //
  1578. PMACHINE_INFO pCacheEntry = NULL;
  1579. BinlCreateOrFindCacheEntry( pMachineInfo->Guid, FALSE, &pCacheEntry );
  1580. // we don't care about the error coming back, only if a record was found.
  1581. if ((pCacheEntry != NULL) &&
  1582. (pCacheEntry != pMachineInfo)) {
  1583. BinlDoneWithCacheEntry( pCacheEntry, TRUE );
  1584. }
  1585. }
  1586. if (LdapMessage != NULL) {
  1587. ldap_msgfree(LdapMessage);
  1588. }
  1589. if (Impersonating) {
  1590. OscRevert(ClientState);
  1591. }
  1592. return Error;
  1593. }
  1594. DWORD
  1595. BinlGenerateNewEntry(
  1596. DWORD dwRequestedInfo,
  1597. USHORT SystemArchitecture,
  1598. PMACHINE_INFO * ppMachineInfo )
  1599. /*++
  1600. Routine Description:
  1601. fills in ppMachineInfo for a new entry if we are currently
  1602. allowing new clients.
  1603. Arguments:
  1604. dwRequestedInfo - a bitmask telling us what parameters we're looking for
  1605. SystemArchitecture - architecture of the client
  1606. ppMachineInfo - gets filled in with information requested information
  1607. Return Value:
  1608. ERROR_SUCCESS when we succeed.
  1609. otherwise ERROR_BINL_INVALID_BINL_CLIENT if we are not allowing new clients
  1610. or ERROR_NO_MEMORY if a memory allocation failed
  1611. or ERROR_BINL_FAILED_TO_INITIALIZE_CLIENT if we did not fill in
  1612. all the information requested.
  1613. --*/
  1614. {
  1615. DWORD Error = ERROR_BINL_INVALID_BINL_CLIENT;
  1616. TraceFunc( "BinlGenerateNewEntry( ... )\n" );
  1617. if ( AllowNewClients ) {
  1618. BinlPrint(( DEBUG_OPTIONS, "Server allows new clients" ));
  1619. if ( ( LimitClients == FALSE ) ||
  1620. ( CurrentClientCount < BinlMaxClients ) ) {
  1621. BinlPrint(( DEBUG_OPTIONS, " and the Server is generating the OS Chooser path response.\n" ));
  1622. if ( dwRequestedInfo & MI_HOSTNAME ) {
  1623. if ( (*ppMachineInfo)->dwFlags & MI_HOSTNAME_ALLOC ) {
  1624. BinlFreeMemory( (*ppMachineInfo)->HostName );
  1625. (*ppMachineInfo)->HostName = NULL;
  1626. (*ppMachineInfo)->dwFlags &= ~MI_HOSTNAME_ALLOC;
  1627. }
  1628. EnterCriticalSection( &gcsParameters );
  1629. (*ppMachineInfo)->HostName = BinlStrDup( BinlGlobalOurDnsName );
  1630. LeaveCriticalSection( &gcsParameters );
  1631. if (!(*ppMachineInfo)->HostName) {
  1632. return (ERROR_OUTOFMEMORY);
  1633. }
  1634. (*ppMachineInfo)->dwFlags |= MI_HOSTNAME_ALLOC;
  1635. (*ppMachineInfo)->dwFlags |= MI_HOSTNAME;
  1636. }
  1637. if ( dwRequestedInfo & MI_BOOTFILENAME ) {
  1638. ULONG ulSize;
  1639. PCWSTR OsChooserName = NULL;
  1640. switch ( SystemArchitecture ) {
  1641. case DHCP_OPTION_CLIENT_ARCHITECTURE_X86:
  1642. OsChooserName = IntelOSChooser;
  1643. ulSize = (wcslen(OsChooserName)+1)*sizeof(WCHAR);
  1644. break;
  1645. case DHCP_OPTION_CLIENT_ARCHITECTURE_IA64:
  1646. OsChooserName = IA64OSChooser;
  1647. ulSize = (wcslen(OsChooserName)+1)*sizeof(WCHAR);
  1648. break;
  1649. default:
  1650. BinlAssertMsg( FALSE, "UnsupportedArchitecture" );
  1651. }
  1652. if (OsChooserName) {
  1653. if ( (*ppMachineInfo)->dwFlags & MI_BOOTFILENAME_ALLOC ) {
  1654. BinlFreeMemory( (*ppMachineInfo)->BootFileName );
  1655. (*ppMachineInfo)->dwFlags &= ~MI_BOOTFILENAME_ALLOC;
  1656. }
  1657. (*ppMachineInfo)->BootFileName = BinlAllocateMemory( ulSize );
  1658. if ( !(*ppMachineInfo)->BootFileName ) {
  1659. return (ERROR_OUTOFMEMORY);
  1660. }
  1661. RtlZeroMemory((*ppMachineInfo)->BootFileName, ulSize);
  1662. wcscpy((*ppMachineInfo)->BootFileName, OsChooserName);
  1663. (*ppMachineInfo)->dwFlags |= MI_BOOTFILENAME | MI_BOOTFILENAME_ALLOC;
  1664. }
  1665. }
  1666. Error = ( ((*ppMachineInfo)->dwFlags & dwRequestedInfo ) == dwRequestedInfo ?
  1667. ERROR_SUCCESS :
  1668. ERROR_BINL_FAILED_TO_INITIALIZE_CLIENT );
  1669. } else {
  1670. BinlPrint(( DEBUG_OPTIONS, "... BUT the server has reached MaxClients (%u)\n", BinlMaxClients ));
  1671. }
  1672. } else {
  1673. BinlPrint((DEBUG_OPTIONS, "Server does not allow new clients (AllowNewClients == FALSE )\n" ));
  1674. }
  1675. return Error;
  1676. }
  1677. DWORD
  1678. GetBootParameters(
  1679. PUCHAR pGuid,
  1680. PMACHINE_INFO * ppMachineInfo,
  1681. DWORD dwRequestedInfo,
  1682. USHORT SystemArchitecture,
  1683. BOOL AllowOSChooser
  1684. )
  1685. /*++
  1686. Routine Description:
  1687. Use the Directory Service to lookup an entry for this machine using Guid as
  1688. the value to lookup.
  1689. If there is no entry for this machine then return oschooser, but only
  1690. if the AllowOSChooser flag is set.
  1691. If a cache entry is returned, then the cache entry has been marked
  1692. InProgress so we have to call BinlDoneWithCacheEntry when the caller
  1693. is done with it.
  1694. Arguments:
  1695. pGuid - Supplies the machine GUID
  1696. ppMachineInfo - gets filled in with what we discovered
  1697. dwRequestedInfo - a bitmask telling us what parameters we're looking for
  1698. SystemArchitecture - architecture of the client
  1699. AllowOSChooser - signifies that we're allowed to respond to the client with
  1700. the oschooser
  1701. Return Value:
  1702. ERROR_SUCCESS or ERROR_BINL_INVALID_BINL_CLIENT or other error.
  1703. --*/
  1704. {
  1705. DWORD Error = ERROR_SUCCESS;
  1706. BOOLEAN myClient = TRUE;
  1707. BOOLEAN entryExists = FALSE;
  1708. TraceFunc( "GetBootParameters( )\n" );
  1709. BinlAssert( ppMachineInfo );
  1710. {
  1711. LPGUID GuidPtr = (LPGUID) pGuid;
  1712. BinlPrint((DEBUG_MISC, "Client Guid: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
  1713. GuidPtr->Data1, GuidPtr->Data2, GuidPtr->Data3,
  1714. GuidPtr->Data4[0], GuidPtr->Data4[1], GuidPtr->Data4[2], GuidPtr->Data4[3],
  1715. GuidPtr->Data4[4], GuidPtr->Data4[5], GuidPtr->Data4[6], GuidPtr->Data4[7] ));
  1716. }
  1717. if ( ppMachineInfo == NULL ) {
  1718. return E_OUTOFMEMORY;
  1719. }
  1720. if (*ppMachineInfo == NULL) {
  1721. //
  1722. // See if we have any entries in the cache.
  1723. // This also mark any entry found as being used.
  1724. //
  1725. Error = BinlCreateOrFindCacheEntry( pGuid, TRUE, ppMachineInfo );
  1726. if ( Error != ERROR_SUCCESS ) {
  1727. //
  1728. // if some bizarre error occurred OR if the client simply wasn't
  1729. // found and we're not sending down OS Chooser, then return the
  1730. // error here as there's no reason to query the DS.
  1731. //
  1732. if ( (Error != ERROR_BINL_INVALID_BINL_CLIENT ) ||
  1733. (AllowOSChooser == FALSE) ) {
  1734. return Error;
  1735. }
  1736. }
  1737. }
  1738. // Do we have everything we need?
  1739. if ( ( Error == ERROR_SUCCESS ) &&
  1740. (((*ppMachineInfo)->dwFlags & dwRequestedInfo) == dwRequestedInfo )) {
  1741. BinlPrint((DEBUG_MISC, "cache hit: returning success without querying ds DS\n"));
  1742. return Error; // Yes, no need to hit the DS.
  1743. }
  1744. //
  1745. // Initially search for the Computer object in the same domain as ourselves.
  1746. // This should be quick (because we are probably on a DC) and likely to work
  1747. // most of the time because the network topology will usually match the domain
  1748. // structure. If that fails then we fall back to looking at the global catalog.
  1749. //
  1750. if ( Error != ERROR_BINL_INVALID_BINL_CLIENT ) {
  1751. Error = GetBootParametersExt(
  1752. *ppMachineInfo,
  1753. dwRequestedInfo,
  1754. SystemArchitecture,
  1755. FALSE);
  1756. if ( Error == ERROR_BINL_INVALID_BINL_CLIENT ) {
  1757. Error = GetBootParametersExt(
  1758. *ppMachineInfo,
  1759. dwRequestedInfo,
  1760. SystemArchitecture,
  1761. TRUE );
  1762. }
  1763. }
  1764. if ( Error == ERROR_BINL_INVALID_BINL_CLIENT ) {
  1765. //
  1766. // Backdoor for testing/overiding the DS.
  1767. //
  1768. // If the registry has the GUID of the client, it
  1769. // overrides all the DS settings and answers anyways.
  1770. //
  1771. // NOTE: AllowNewClients must be turned on for OSChooser to
  1772. // be sent down.
  1773. //
  1774. HKEY KeyHandle;
  1775. if (AllowOSChooser == TRUE) {
  1776. //
  1777. // if the client is not found in the DS and we're allowed to
  1778. // answer new clients, then send down OSCHOOSER to get the new
  1779. // client going.
  1780. //
  1781. BinlPrint((DEBUG_MISC, "generating a new entry because AllowOSChooser is TRUE...\n"));
  1782. Error = BinlGenerateNewEntry( dwRequestedInfo, SystemArchitecture, ppMachineInfo );
  1783. if ( Error != ERROR_SUCCESS ) {
  1784. myClient = FALSE;
  1785. }
  1786. } else {
  1787. //
  1788. // We're not answering because we didn't find the client
  1789. // record but the client's SecondsSinceBoot is less than
  1790. // BinlMinDelayResponseForNewClients.
  1791. //
  1792. myClient = FALSE;
  1793. BinlPrint((DEBUG_OPTIONS, "... OS Chooser is not an option at this time... waiting...\n" ));
  1794. }
  1795. }
  1796. //
  1797. // Determine the host servers IP address iff it's not our own machine.
  1798. //
  1799. if ((Error == ERROR_SUCCESS) &&
  1800. ( (*ppMachineInfo)->dwFlags & MI_HOSTNAME )
  1801. && ( (*ppMachineInfo)->HostAddress == 0 )
  1802. && ( (*ppMachineInfo)->HostName )) {
  1803. EnterCriticalSection( &gcsParameters );
  1804. if ( (BinlGlobalOurDnsName != NULL) &&
  1805. (_wcsicmp( BinlGlobalOurDnsName, (*ppMachineInfo)->HostName ) != 0 )) {
  1806. PCHAR machineName;
  1807. PHOSTENT host;
  1808. ULONG myMachineNameLength;
  1809. PCHAR myMachineName;
  1810. ULONG machineNameLength;
  1811. myMachineNameLength = wcslen( BinlGlobalOurDnsName ) + 1;
  1812. myMachineName = BinlAllocateMemory ( myMachineNameLength );
  1813. if ( myMachineName != NULL ) {
  1814. if (!BinlUnicodeToAnsi(BinlGlobalOurDnsName,myMachineName,(USHORT)myMachineNameLength)) {
  1815. BinlFreeMemory(myMachineName);
  1816. myMachineName = NULL;
  1817. }
  1818. }
  1819. LeaveCriticalSection( &gcsParameters );
  1820. machineNameLength = wcslen((*ppMachineInfo)->HostName) + 1;
  1821. machineName = BinlAllocateMemory( machineNameLength );
  1822. //
  1823. // Only fill in the IP address if the server is different from our
  1824. // own machine. If we fail for any reason, we'll just end up using
  1825. // our own IP address.
  1826. //
  1827. if ((machineName != NULL) &&
  1828. BinlUnicodeToAnsi((*ppMachineInfo)->HostName, machineName, (USHORT)machineNameLength)) {
  1829. host = gethostbyname( machineName );
  1830. if (host != NULL) {
  1831. (*ppMachineInfo)->HostAddress = *(PDHCP_IP_ADDRESS)host->h_addr;
  1832. // Adding stuff for multi-home NIC
  1833. if (myMachineName != NULL) {
  1834. PHOSTENT myhost;
  1835. int i;
  1836. myhost = gethostbyname( myMachineName );
  1837. if (myhost != NULL) {
  1838. i=0;
  1839. while (((myhost->h_addr_list)[i]) != NULL) {
  1840. if ((*((PDHCP_IP_ADDRESS)((myhost->h_addr_list)[i])))
  1841. == (*ppMachineInfo)->HostAddress) {
  1842. //
  1843. // this is us, leave it as 0
  1844. //
  1845. (*ppMachineInfo)->HostAddress = (DHCP_IP_ADDRESS)0;
  1846. break;
  1847. }
  1848. i++;
  1849. }
  1850. }
  1851. }
  1852. } else {
  1853. Error = ERROR_HOST_UNREACHABLE;
  1854. myClient = FALSE;
  1855. entryExists = TRUE;
  1856. }
  1857. BinlFreeMemory( machineName );
  1858. } else {
  1859. if (machineName) {
  1860. BinlFreeMemory( machineName );
  1861. }
  1862. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1863. myClient = FALSE;
  1864. entryExists = TRUE;
  1865. }
  1866. if ( myMachineName != NULL ) {
  1867. BinlFreeMemory( myMachineName );
  1868. }
  1869. } else {
  1870. LeaveCriticalSection( &gcsParameters );
  1871. }
  1872. }
  1873. if (Error != ERROR_SUCCESS) {
  1874. //
  1875. // If we didn't find the record, then we mark it that we don't need
  1876. // to respond and it doesn't exist. We then mark that we're done with
  1877. // the entry since we're not passing it back to the caller.
  1878. //
  1879. (*ppMachineInfo)->MyClient = myClient;
  1880. (*ppMachineInfo)->EntryExists = entryExists;
  1881. BinlDoneWithCacheEntry( *ppMachineInfo, FALSE );
  1882. *ppMachineInfo = NULL;
  1883. } else {
  1884. //
  1885. // we've filled in the interesting fields, therefore mark that the
  1886. // entry has valid data.
  1887. //
  1888. (*ppMachineInfo)->MyClient = TRUE;
  1889. (*ppMachineInfo)->EntryExists = TRUE;
  1890. }
  1891. return Error;
  1892. }
  1893. DWORD
  1894. GetBootParametersExt(
  1895. PMACHINE_INFO pMachineInfo,
  1896. DWORD dwRequestedInfo,
  1897. USHORT SystemArchitecture,
  1898. BOOL fGlobalSearch)
  1899. /*++
  1900. Routine Description:
  1901. Use the Directory Service to lookup an entry for this machine using Guid as
  1902. the value to lookup.
  1903. If there is no entry for this machine then return oschooser
  1904. Arguments:
  1905. pMachineInfo - identifies the machine in the DS.
  1906. dwRequestedInfo - mask telling what information we should query
  1907. SystemArchitecture - architecture of the client
  1908. GlobalSearch - TRUE if GC should be used
  1909. Return Value:
  1910. ERROR_SUCCESS or ERROR_BINL_INVALID_BINL_CLIENT
  1911. --*/
  1912. {
  1913. DWORD dwErr = ERROR_BINL_INVALID_BINL_CLIENT;
  1914. PLDAP LdapHandle = NULL;
  1915. PWCHAR * Base;
  1916. DWORD LdapError;
  1917. DWORD entryCount;
  1918. DWORD ldapRetryLimit = 0;
  1919. PLDAPMessage LdapMessage = NULL;
  1920. PWCHAR * FilePath;
  1921. PWCHAR * FilePath2;
  1922. PLDAPMessage CurrentEntry;
  1923. WCHAR Filter[128];
  1924. WCHAR EscapedGuid[64];
  1925. // Paramters we want from the Computer Object
  1926. PWCHAR ComputerAttrs[7];
  1927. PDUP_GUID_DN dupDN;
  1928. TraceFunc( "GetBootParametersExt( )\n" );
  1929. pMachineInfo->dwFlags &= MI_ALL_ALLOC; // clear all but the ALLOC bits
  1930. // we get all the info, regardless of what was requested.
  1931. ComputerAttrs[0] = L"netbootMachineFilePath";
  1932. ComputerAttrs[1] = L"netbootInitialization";
  1933. ComputerAttrs[2] = L"sAMAccountName";
  1934. ComputerAttrs[3] = L"dnsHostName";
  1935. ComputerAttrs[4] = L"distinguishedName";
  1936. ComputerAttrs[5] = L"netbootSIFFile";
  1937. ComputerAttrs[6] = NULL;
  1938. BinlAssertMsg( !(dwRequestedInfo & MI_PASSWORD), "Can't get the machine's password!" );
  1939. // Build the filter to find the Computer object with this GUID
  1940. ldap_escape_filter_element(pMachineInfo->Guid, BINL_GUID_LENGTH, EscapedGuid, sizeof(EscapedGuid) );
  1941. //
  1942. // Dont' use ';binary' because win2k Active Directory isn't compatible with the
  1943. // binary tag.
  1944. //
  1945. wsprintf( Filter, L"(&(objectClass=computer)(netbootGUID=%ws))", EscapedGuid );
  1946. #if 0 && DBG
  1947. {
  1948. LPGUID GuidPtr = (LPGUID) &pMachineInfo->Guid;
  1949. BinlPrint((DEBUG_MISC, "Client Guid: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
  1950. GuidPtr->Data1, GuidPtr->Data2, GuidPtr->Data3,
  1951. GuidPtr->Data4[0], GuidPtr->Data4[1], GuidPtr->Data4[2], GuidPtr->Data4[3],
  1952. GuidPtr->Data4[4], GuidPtr->Data4[5], GuidPtr->Data4[6], GuidPtr->Data4[7] ));
  1953. }
  1954. #endif
  1955. RetryConnection:
  1956. dwErr = InitializeConnection( fGlobalSearch, &LdapHandle, &Base );
  1957. if ( dwErr != LDAP_SUCCESS ) {
  1958. BinlPrint((DEBUG_ERRORS,
  1959. "InitializeConnection failed, ec = %x\n",dwErr));
  1960. SetLastError( dwErr );
  1961. dwErr = ERROR_BINL_INITIALIZE_LDAP_CONNECTION_FAILED;
  1962. goto e0;
  1963. }
  1964. LdapError = ldap_search_ext_sW(LdapHandle,
  1965. *Base,
  1966. LDAP_SCOPE_SUBTREE,
  1967. Filter,
  1968. ComputerAttrs,
  1969. FALSE,
  1970. NULL,
  1971. NULL,
  1972. &BinlLdapSearchTimeout,
  1973. 0,
  1974. &LdapMessage);
  1975. if ( LdapError != LDAP_SUCCESS ) {
  1976. HandleLdapFailure( LdapError,
  1977. EVENT_WARNING_LDAP_SEARCH_ERROR,
  1978. fGlobalSearch,
  1979. &LdapHandle,
  1980. FALSE ); // don't have lock
  1981. if (LdapHandle == NULL) {
  1982. if (++ldapRetryLimit < LDAP_SERVER_DOWN_LIMIT) {
  1983. goto RetryConnection;
  1984. }
  1985. dwErr = ERROR_BINL_INITIALIZE_LDAP_CONNECTION_FAILED;
  1986. SetLastError( dwErr );
  1987. goto e1;
  1988. }
  1989. BinlPrint((DEBUG_MISC,
  1990. "ldap_search_ext_s %ws failed, ec = %x\n",
  1991. Filter,
  1992. LdapError));
  1993. goto e1;
  1994. }
  1995. // Did we get a Computer Object?
  1996. entryCount = ldap_count_entries( LdapHandle, LdapMessage );
  1997. if ( entryCount == 0 ) {
  1998. BinlPrint((DEBUG_MISC,
  1999. "ldap_count_entries %ws returned 0 entries\n",
  2000. Filter ));
  2001. dwErr = ERROR_BINL_INVALID_BINL_CLIENT;
  2002. goto e1; // nope
  2003. }
  2004. else if ( entryCount == -1 ) {
  2005. //
  2006. // catch any errors
  2007. //
  2008. dwErr = LdapGetLastError();
  2009. HandleLdapFailure( dwErr,
  2010. EVENT_WARNING_LDAP_COUNT_ENTRIES_ERROR,
  2011. fGlobalSearch,
  2012. &LdapHandle,
  2013. FALSE ); // don't have the lock
  2014. if (LdapHandle == NULL) {
  2015. if (++ldapRetryLimit < LDAP_SERVER_DOWN_LIMIT) {
  2016. goto RetryConnection;
  2017. }
  2018. SetLastError( dwErr );
  2019. }
  2020. BinlPrint((DEBUG_MISC, "ldap_count_entries %ws failed with error 0x%x\n",
  2021. Filter,
  2022. dwErr ));
  2023. goto e1;
  2024. }
  2025. // if we get more than more entry back, we will use only the
  2026. // first one.
  2027. CurrentEntry = ldap_first_entry( LdapHandle, LdapMessage );
  2028. if (entryCount > 1) {
  2029. BinlLogDuplicateDsRecords( (LPGUID)&pMachineInfo->Guid, LdapHandle, LdapMessage, CurrentEntry );
  2030. }
  2031. FilePath = ldap_get_values( LdapHandle, CurrentEntry, L"distinguishedName");
  2032. if ( FilePath ) {
  2033. if ( pMachineInfo->dwFlags & MI_MACHINEDN_ALLOC ) {
  2034. BinlFreeMemory( pMachineInfo->MachineDN );
  2035. pMachineInfo->dwFlags &= ~MI_MACHINEDN_ALLOC;
  2036. }
  2037. pMachineInfo->MachineDN = BinlStrDup( *FilePath );
  2038. if ( pMachineInfo->MachineDN ) {
  2039. pMachineInfo->dwFlags |= MI_MACHINEDN | MI_MACHINEDN_ALLOC;
  2040. }
  2041. BinlPrint(( DEBUG_MISC, "MachineDN = %ws\n", pMachineInfo->MachineDN ));
  2042. ldap_value_free( FilePath );
  2043. } else {
  2044. BinlPrint((DEBUG_MISC,
  2045. "couldn't get distinguishedName for %ws\n",
  2046. Filter ));
  2047. }
  2048. FilePath = ldap_get_values( LdapHandle, CurrentEntry, L"netbootInitialization" );
  2049. if ( FilePath ) {
  2050. if ( pMachineInfo->dwFlags & MI_SETUPPATH_ALLOC ) {
  2051. BinlFreeMemory( pMachineInfo->SetupPath );
  2052. pMachineInfo->dwFlags &= ~MI_SETUPPATH_ALLOC;
  2053. }
  2054. pMachineInfo->SetupPath = BinlStrDup( *FilePath );
  2055. if ( pMachineInfo->SetupPath ) {
  2056. pMachineInfo->dwFlags |= MI_SETUPPATH | MI_SETUPPATH_ALLOC;
  2057. BinlPrintDbg(( DEBUG_MISC, "SetupPath = %ws\n", pMachineInfo->SetupPath ));
  2058. }
  2059. ldap_value_free( FilePath );
  2060. }
  2061. FilePath = ldap_get_values( LdapHandle, CurrentEntry, L"netbootMachineFilePath" );
  2062. if ( FilePath ) {
  2063. PWCHAR psz = wcschr( *FilePath, L'\\' );
  2064. if ( psz ) {
  2065. *psz = L'\0'; // terminate
  2066. }
  2067. if (pMachineInfo->dwFlags & MI_HOSTNAME_ALLOC) {
  2068. BinlFreeMemory( pMachineInfo->HostName );
  2069. pMachineInfo->dwFlags &= ~MI_HOSTNAME_ALLOC;
  2070. }
  2071. pMachineInfo->HostName = BinlStrDup( *FilePath );
  2072. if (pMachineInfo->HostName) {
  2073. BinlPrint(( DEBUG_MISC, "HostName = %ws\n", pMachineInfo->HostName ));
  2074. pMachineInfo->dwFlags |= MI_HOSTNAME | MI_HOSTNAME_ALLOC;
  2075. }
  2076. if ( psz ) {
  2077. *psz = L'\\'; // let's put it back to what it started as.
  2078. psz++;
  2079. if (pMachineInfo->dwFlags & MI_BOOTFILENAME_ALLOC) {
  2080. BinlFreeMemory( pMachineInfo->BootFileName );
  2081. pMachineInfo->dwFlags &= ~MI_BOOTFILENAME_ALLOC;
  2082. }
  2083. pMachineInfo->BootFileName = BinlStrDup( psz );
  2084. if ( pMachineInfo->BootFileName ) {
  2085. pMachineInfo->dwFlags |= MI_BOOTFILENAME | MI_BOOTFILENAME_ALLOC;
  2086. BinlPrintDbg(( DEBUG_MISC, "BootFileName = %ws\n", pMachineInfo->BootFileName ));
  2087. }
  2088. }
  2089. ldap_value_free( FilePath );
  2090. }
  2091. FilePath = ldap_get_values( LdapHandle, CurrentEntry, L"netbootSIFFile" );
  2092. if ( FilePath ) {
  2093. PWSTR ForcedSifFilePath;
  2094. DWORD ForcedSifFileLength;
  2095. if (pMachineInfo->dwFlags & MI_SIFFILENAME_ALLOC) {
  2096. BinlFreeMemory( pMachineInfo->ForcedSifFileName );
  2097. pMachineInfo->dwFlags &= ~MI_SIFFILENAME_ALLOC;
  2098. }
  2099. ForcedSifFileLength = wcslen(*FilePath);
  2100. // d:\remoteinstall + '\' + NULL terminator
  2101. ForcedSifFileLength = ForcedSifFileLength + 1 + wcslen(IntelliMirrorPathW) + 1;
  2102. ForcedSifFileLength = ForcedSifFileLength * sizeof(WCHAR);
  2103. pMachineInfo->ForcedSifFileName = BinlAllocateMemory(ForcedSifFileLength);
  2104. if ( pMachineInfo->ForcedSifFileName ) {
  2105. if (_snwprintf( pMachineInfo->ForcedSifFileName,
  2106. ForcedSifFileLength/sizeof(WCHAR),
  2107. L"%ws\\%ws",
  2108. IntelliMirrorPathW,
  2109. *FilePath) >= 0) {
  2110. pMachineInfo->dwFlags |= MI_SIFFILENAME_ALLOC;
  2111. BinlPrintDbg(( DEBUG_MISC, "ForcedSifFileName = %ws\n", pMachineInfo->ForcedSifFileName ));
  2112. } else {
  2113. BinlPrintDbg(( DEBUG_MISC, "ForcedSifFileName _snwprintf failed\n" ));
  2114. BinlFreeMemory( pMachineInfo->ForcedSifFileName );
  2115. pMachineInfo->ForcedSifFileName = NULL;
  2116. }
  2117. }
  2118. ldap_value_free( FilePath );
  2119. }
  2120. if ( !(pMachineInfo->dwFlags & MI_HOSTNAME )
  2121. || ( !pMachineInfo->HostName )
  2122. || ( pMachineInfo->HostName[0] == L'\0') ) {
  2123. if ( pMachineInfo->dwFlags & MI_HOSTNAME_ALLOC ) {
  2124. BinlFreeMemory( pMachineInfo->HostName );
  2125. pMachineInfo->dwFlags &= ~MI_HOSTNAME_ALLOC;
  2126. pMachineInfo->HostName = NULL;
  2127. }
  2128. dwErr = BinlGenerateNewEntry( MI_HOSTNAME, SystemArchitecture, &pMachineInfo );
  2129. if ( dwErr != ERROR_SUCCESS ) {
  2130. goto e1;
  2131. }
  2132. }
  2133. if ( !(pMachineInfo->dwFlags & MI_BOOTFILENAME)
  2134. || ( !pMachineInfo->BootFileName )
  2135. || ( pMachineInfo->BootFileName[0] == L'\0') ) {
  2136. if (pMachineInfo->dwFlags & MI_BOOTFILENAME_ALLOC) {
  2137. BinlFreeMemory( pMachineInfo->BootFileName );
  2138. pMachineInfo->BootFileName = NULL;
  2139. pMachineInfo->dwFlags &= ~MI_BOOTFILENAME_ALLOC;
  2140. }
  2141. dwErr = BinlGenerateNewEntry( MI_BOOTFILENAME, SystemArchitecture, &pMachineInfo );
  2142. if ( dwErr != ERROR_SUCCESS ) {
  2143. goto e1;
  2144. }
  2145. }
  2146. FilePath = ldap_get_values( LdapHandle, CurrentEntry, L"sAMAccountName" );
  2147. if ( FilePath ) {
  2148. if (pMachineInfo->dwFlags & MI_SAMNAME_ALLOC) {
  2149. BinlFreeMemory( pMachineInfo->SamName );
  2150. pMachineInfo->dwFlags &= ~MI_SAMNAME_ALLOC;
  2151. }
  2152. pMachineInfo->SamName = BinlStrDup( *FilePath );
  2153. if ( pMachineInfo->SamName ) {
  2154. pMachineInfo->dwFlags |= MI_SAMNAME | MI_SAMNAME_ALLOC;
  2155. BinlPrint(( DEBUG_MISC, "SamName = %ws\n", pMachineInfo->SamName ));
  2156. }
  2157. //
  2158. // For now, the pMachineInfo Name and SamName are the same values,
  2159. // therefore we won't look them up twice in the ldap message.
  2160. //
  2161. #if 0
  2162. ldap_value_free( FilePath );
  2163. }
  2164. FilePath = ldap_get_values( LdapHandle, CurrentEntry, L"sAMAccountName" );
  2165. if ( FilePath ) {
  2166. #endif
  2167. if ( pMachineInfo->dwFlags & MI_NAME_ALLOC ) {
  2168. BinlFreeMemory( pMachineInfo->Name );
  2169. pMachineInfo->dwFlags &= ~MI_NAME_ALLOC;
  2170. }
  2171. pMachineInfo->Name = BinlStrDup( *FilePath );
  2172. if ( pMachineInfo->Name ) {
  2173. if( pMachineInfo->Name[ wcslen(pMachineInfo->Name) - 1 ] == L'$' ) {
  2174. pMachineInfo->Name[ wcslen(pMachineInfo->Name) - 1 ] = L'\0'; // remove '$'
  2175. }
  2176. pMachineInfo->dwFlags |= MI_NAME | MI_NAME_ALLOC;
  2177. BinlPrint(( DEBUG_MISC, "Name = %ws\n", pMachineInfo->Name ));
  2178. }
  2179. ldap_value_free( FilePath );
  2180. }
  2181. FilePath = ldap_get_values( LdapHandle, CurrentEntry, L"dnsHostName" );
  2182. if ( FilePath ) {
  2183. BOOL fEndofString = FALSE;
  2184. PWCHAR psz = *FilePath;
  2185. // skip host name, we get that from the samName
  2186. while ( *psz && *psz!=L'.' ) {
  2187. psz++;
  2188. }
  2189. if ( !(*psz) ) {
  2190. fEndofString = TRUE;
  2191. }
  2192. *psz = L'\0'; // terminate
  2193. if ( fEndofString == FALSE ) {
  2194. psz++;
  2195. if (pMachineInfo->Domain) {
  2196. BinlFreeMemory( pMachineInfo->Domain );
  2197. }
  2198. pMachineInfo->Domain = BinlStrDup( psz );
  2199. if ( pMachineInfo->Domain )
  2200. {
  2201. pMachineInfo->dwFlags |= MI_DOMAIN;
  2202. BinlPrint(( DEBUG_MISC, "Domain = %ws\n", pMachineInfo->Domain ));
  2203. }
  2204. }
  2205. ldap_value_free(FilePath);
  2206. }
  2207. //
  2208. // track duplicates that we get back
  2209. //
  2210. // first we free all duplicates we have already allocated.
  2211. //
  2212. while (!IsListEmpty(&pMachineInfo->DNsWithSameGuid)) {
  2213. PLIST_ENTRY p = RemoveHeadList(&pMachineInfo->DNsWithSameGuid);
  2214. dupDN = CONTAINING_RECORD(p, DUP_GUID_DN, ListEntry);
  2215. BinlFreeMemory( dupDN );
  2216. }
  2217. while (--entryCount > 0) {
  2218. CurrentEntry = ldap_next_entry( LdapHandle, CurrentEntry );
  2219. if (CurrentEntry == NULL) {
  2220. break;
  2221. }
  2222. FilePath = ldap_get_values( LdapHandle, CurrentEntry, L"dnsHostName" );
  2223. if (!FilePath) {
  2224. FilePath = ldap_get_values( LdapHandle, CurrentEntry, L"sAMAccountName");
  2225. }
  2226. if ( FilePath ) {
  2227. ULONG dupLength, dupLength2;
  2228. BinlPrint(( DEBUG_OSC, "Found duplicate DN in %ws\n", *FilePath ));
  2229. FilePath2 = ldap_get_values( LdapHandle, CurrentEntry, L"distinguishedName");
  2230. dupLength = wcslen( *FilePath ) + 1;
  2231. if (FilePath2) {
  2232. dupLength2 = wcslen( *FilePath2 ) + 1;
  2233. } else {
  2234. dupLength2 = 1;
  2235. }
  2236. dupDN = BinlAllocateMemory( FIELD_OFFSET(DUP_GUID_DN, DuplicateName[0]) +
  2237. ( (dupLength + dupLength2) * sizeof(WCHAR) ) );
  2238. if ( dupDN ) {
  2239. dupDN->DuplicateDNOffset = dupLength;
  2240. wcscpy( &dupDN->DuplicateName[0], *FilePath );
  2241. if (FilePath2) {
  2242. wcscpy( &dupDN->DuplicateName[dupLength], *FilePath2 );
  2243. } else {
  2244. dupDN->DuplicateName[dupLength] = L'\0';
  2245. }
  2246. //
  2247. // if the last character is a $, then slam in a NULL to end it.
  2248. //
  2249. if (( dupLength > 1 ) &&
  2250. ( dupDN->DuplicateName[dupLength-2] == L'$' )) {
  2251. dupDN->DuplicateName[dupLength-2] = L'\0';
  2252. }
  2253. InsertTailList( &pMachineInfo->DNsWithSameGuid, &dupDN->ListEntry );
  2254. }
  2255. ldap_value_free( FilePath );
  2256. if (FilePath2) {
  2257. ldap_value_free( FilePath2 );
  2258. }
  2259. }
  2260. }
  2261. e1:
  2262. if (LdapMessage) {
  2263. ldap_msgfree( LdapMessage );
  2264. }
  2265. e0:
  2266. return dwErr;
  2267. }
  2268. DWORD
  2269. InitializeConnection(
  2270. BOOL Global,
  2271. PLDAP * LdapHandle,
  2272. PWCHAR ** Base )
  2273. /*++
  2274. Routine Description:
  2275. Initialize the ldap connection for operating on either the domain or the
  2276. global catalog.
  2277. Arguments:
  2278. Global - TRUE if GC should be used
  2279. LdapHandle - Returns the handle for further operations
  2280. OperationalAttributeLdapMessage - Returns message containing Base so that it can be freed later
  2281. Base - DN of where to start searches for computer objects.
  2282. Return Value:
  2283. ldap error
  2284. --*/
  2285. {
  2286. PLDAPMessage OperationalAttributeLdapMessage = NULL;
  2287. PWCHAR Attrs[2];
  2288. PLDAPMessage CurrentEntry;
  2289. PWCHAR *LdapValue;
  2290. DWORD LdapError = ERROR_SUCCESS;
  2291. PLDAP *LdapHandleCurrent;
  2292. PWCHAR ** LdapBaseCurrent;
  2293. ULONG temp;
  2294. TraceFunc( "InitializeConnection( )\n" );
  2295. // Use critical section to avoid two threads initialising the same parameters
  2296. EnterCriticalSection(&gcsDHCPBINL);
  2297. if ( !Global ) {
  2298. LdapHandleCurrent = &DCLdapHandle;
  2299. LdapBaseCurrent = &DCBase;
  2300. } else {
  2301. LdapHandleCurrent = &GCLdapHandle;
  2302. LdapBaseCurrent = &GCBase;
  2303. }
  2304. if ( !(*LdapHandleCurrent) ) {
  2305. if (Global) {
  2306. *LdapHandleCurrent = ldap_initW( BinlGlobalDefaultGC, LDAP_GC_PORT);
  2307. temp = DS_DIRECTORY_SERVICE_REQUIRED |
  2308. DS_IP_REQUIRED |
  2309. DS_GC_SERVER_REQUIRED;
  2310. } else {
  2311. *LdapHandleCurrent = ldap_initW( BinlGlobalDefaultDS, LDAP_PORT);
  2312. temp = DS_DIRECTORY_SERVICE_REQUIRED |
  2313. DS_IP_REQUIRED;
  2314. }
  2315. if (!*LdapHandleCurrent) {
  2316. BinlPrint(( DEBUG_ERRORS, "Failed to initialize LDAP connection.\n" ));
  2317. LdapError = LDAP_CONNECT_ERROR;
  2318. LogLdapError( (Global ? EVENT_WARNING_LDAP_INIT_ERROR_GC :
  2319. EVENT_WARNING_LDAP_INIT_ERROR_DC),
  2320. GetLastError(),
  2321. NULL
  2322. );
  2323. goto e0;
  2324. }
  2325. LdapError = ldap_set_option(*LdapHandleCurrent, LDAP_OPT_GETDSNAME_FLAGS, &temp );
  2326. if ( LdapError != LDAP_SUCCESS ) {
  2327. //
  2328. // something went wrong setting the option.
  2329. // do not continue, because we don't know
  2330. // what will happen with other settings
  2331. //
  2332. BinlPrint(( DEBUG_ERRORS, "Failed to set LDAP_OPT_GETDSNAME_FLAGS.\n"));
  2333. LogLdapError( EVENT_WARNING_LDAP_INIT_OPTIONS_ERROR,
  2334. LdapError,
  2335. *LdapHandleCurrent
  2336. );
  2337. goto e1;
  2338. }
  2339. if (Global == FALSE) {
  2340. temp = BinlLdapOptReferrals;
  2341. } else {
  2342. //
  2343. // At some future time, the GC is going to return referrals to
  2344. // authoritative DCs when the GC doesn't contain all the
  2345. // attributes. We'll enable referrals so that it "just works".
  2346. //
  2347. temp = (ULONG)((ULONG_PTR)LDAP_OPT_ON);
  2348. }
  2349. ldap_set_option(*LdapHandleCurrent, LDAP_OPT_REFERRALS, (void *) &temp );
  2350. if ( LdapError != LDAP_SUCCESS ) {
  2351. //
  2352. // something went wrong setting the option.
  2353. // do not continue, because we don't know
  2354. // what will happen with other settings
  2355. //
  2356. BinlPrint(( DEBUG_ERRORS, "Failed to set LDAP_OPT_REFERRALS.\n"));
  2357. LogLdapError( EVENT_WARNING_LDAP_INIT_OPTIONS_ERROR,
  2358. LdapError,
  2359. *LdapHandleCurrent
  2360. );
  2361. goto e1;
  2362. }
  2363. temp = LDAP_VERSION3;
  2364. ldap_set_option(*LdapHandleCurrent, LDAP_OPT_VERSION, &temp );
  2365. if ( LdapError != LDAP_SUCCESS ) {
  2366. //
  2367. // something went wrong setting the option.
  2368. // do not continue, because we don't know
  2369. // what will happen with other settings
  2370. //
  2371. BinlPrint(( DEBUG_ERRORS, "Failed to set LDAP_OPT_VERSION.\n"));
  2372. LogLdapError( EVENT_WARNING_LDAP_INIT_OPTIONS_ERROR,
  2373. LdapError,
  2374. *LdapHandleCurrent
  2375. );
  2376. goto e1;
  2377. }
  2378. LdapError = ldap_connect(*LdapHandleCurrent,0);
  2379. if (LdapError != LDAP_SUCCESS) {
  2380. LogLdapError( (Global ? EVENT_WARNING_LDAP_INIT_ERROR_GC :
  2381. EVENT_WARNING_LDAP_INIT_ERROR_DC),
  2382. LdapError,
  2383. *LdapHandleCurrent
  2384. );
  2385. BinlPrint(( DEBUG_ERRORS, "ldap_connect failed: %lx\n", LdapError ));
  2386. goto e1;
  2387. }
  2388. LdapError = ldap_bind_s(*LdapHandleCurrent, NULL, NULL, LDAP_AUTH_SSPI);
  2389. if (LdapError != LDAP_SUCCESS) {
  2390. BinlPrint(( DEBUG_ERRORS, "ldap_bind_s failed: %lx\n", LdapError ));
  2391. LogLdapError( EVENT_WARNING_LDAP_BIND_ERROR,
  2392. LdapError,
  2393. *LdapHandleCurrent
  2394. );
  2395. goto e1;
  2396. }
  2397. }
  2398. //
  2399. // Connected to Directory Service. Find out where in the DS we
  2400. // should start looking for the computer.
  2401. //
  2402. if ( !(*LdapBaseCurrent) )
  2403. {
  2404. DWORD count;
  2405. Attrs[0] = DefaultNamingContext;
  2406. Attrs[1] = NULL;
  2407. LdapError = ldap_search_ext_sW(*LdapHandleCurrent,
  2408. NULL, // base
  2409. LDAP_SCOPE_BASE,
  2410. L"objectClass=*",// filter
  2411. Attrs,
  2412. FALSE,
  2413. NULL,
  2414. NULL,
  2415. &BinlLdapSearchTimeout,
  2416. 0,
  2417. &OperationalAttributeLdapMessage);
  2418. if ( LdapError != LDAP_SUCCESS ) {
  2419. BinlPrint(( DEBUG_ERRORS, "ldap_search_ext_s failed: %x\n", LdapError ));
  2420. HandleLdapFailure( LdapError,
  2421. EVENT_WARNING_LDAP_SEARCH_ERROR,
  2422. Global,
  2423. LdapHandleCurrent,
  2424. TRUE ); // we have lock
  2425. if (*LdapHandleCurrent == NULL) {
  2426. goto e1;
  2427. }
  2428. goto e2;
  2429. }
  2430. count = ldap_count_entries( *LdapHandleCurrent, OperationalAttributeLdapMessage );
  2431. if ( count == 0 ) {
  2432. BinlPrint(( DEBUG_ERRORS, "Failed to find the defaultNamingContext.\n" ));
  2433. LdapError = LDAP_NO_RESULTS_RETURNED;
  2434. LogLdapError( EVENT_WARNING_LDAP_SEARCH_ERROR,
  2435. LdapError,
  2436. *LdapHandleCurrent
  2437. );
  2438. goto e2;
  2439. }
  2440. if ( count == -1 ) {
  2441. //
  2442. // get the failing case as well
  2443. //
  2444. BinlPrint(( DEBUG_ERRORS, "ldap_count_entries failed.\n" ));
  2445. LdapError = LdapGetLastError();
  2446. HandleLdapFailure( LdapError,
  2447. EVENT_WARNING_LDAP_COUNT_ENTRIES_ERROR,
  2448. Global,
  2449. LdapHandleCurrent,
  2450. TRUE ); // we have lock
  2451. if (*LdapHandleCurrent == NULL) {
  2452. goto e1;
  2453. }
  2454. goto e2;
  2455. }
  2456. //
  2457. // the DS should always only return us a single root DSE record.
  2458. // It would be completely broken if it returned more than one.
  2459. //
  2460. BinlAssert( count == 1 );
  2461. CurrentEntry = ldap_first_entry( *LdapHandleCurrent, OperationalAttributeLdapMessage );
  2462. LdapValue = ldap_get_values( *LdapHandleCurrent, CurrentEntry, Attrs[0] );
  2463. if (LdapValue == NULL) {
  2464. BinlPrint(( DEBUG_ERRORS, "Failed to find the defaultNamingContext.\n" ));
  2465. LdapError = LDAP_NO_RESULTS_RETURNED;
  2466. goto e2;
  2467. }
  2468. *LdapBaseCurrent = LdapValue;
  2469. }
  2470. e2:
  2471. if (OperationalAttributeLdapMessage) {
  2472. ldap_msgfree( OperationalAttributeLdapMessage );
  2473. }
  2474. e0:
  2475. if ( LdapHandle ) {
  2476. *LdapHandle = *LdapHandleCurrent;
  2477. }
  2478. if ( Base ) {
  2479. *Base = *LdapBaseCurrent;
  2480. }
  2481. LeaveCriticalSection(&gcsDHCPBINL);
  2482. return LdapError;
  2483. e1:
  2484. BinlPrint(( DEBUG_ERRORS, "Failed to connect to LDAP server.\n" ));
  2485. if (*LdapHandleCurrent != NULL) {
  2486. ldap_unbind(*LdapHandleCurrent);
  2487. *LdapHandleCurrent = NULL;
  2488. }
  2489. goto e0;
  2490. }
  2491. VOID
  2492. HandleLdapFailure(
  2493. DWORD LdapError,
  2494. DWORD EventId,
  2495. BOOL GlobalCatalog,
  2496. PLDAP *LdapHandle,
  2497. BOOL HaveLock
  2498. )
  2499. /*++
  2500. Routine Description:
  2501. This routine will recycle an ldap handle. Call this routine when one
  2502. of our global ldap handles becomes suspect because ldap calls start
  2503. failing.
  2504. Arguments:
  2505. LdapError - error code from ldap call that failed.
  2506. EventId - eventlog error that we should log on failure.
  2507. GlobalCatalog - set to TRUE if we were searching hte global catalog
  2508. and should therefore be cleaning up the GCLdapHandle.
  2509. LdapHandle - ldap handle pointer. it can be reset to null to indicate
  2510. that the handle was cleaned up and is no longer valid.
  2511. HaveLock - flag indicating if we are holding gcsDHCPBINL (required to free
  2512. a global structure like our handles).
  2513. Return Value:
  2514. None.
  2515. --*/
  2516. {
  2517. PLDAP *LdapHandleCurrent;
  2518. PWCHAR ** LdapBaseCurrent;
  2519. //
  2520. // it used to be that we'd only recycle the handle on certain failures, but
  2521. // it seems like we're likely to get any failure code on an invalid handle.
  2522. // therefore we always recycle the handle regardless of the error code.
  2523. //
  2524. if (LdapError == LDAP_SUCCESS) {
  2525. BinlAssert( FALSE );
  2526. }
  2527. if (!HaveLock) {
  2528. EnterCriticalSection(&gcsDHCPBINL);
  2529. }
  2530. LdapHandleCurrent = GlobalCatalog ? &GCLdapHandle : &DCLdapHandle;
  2531. LdapBaseCurrent = GlobalCatalog ? &GCBase : &DCBase;
  2532. if (EventId) {
  2533. LogLdapError( EventId,
  2534. LdapError,
  2535. (LdapHandle != NULL ? *LdapHandle : *LdapHandleCurrent)
  2536. );
  2537. }
  2538. if (LdapHandle) {
  2539. ASSERT( *LdapHandle == *LdapHandleCurrent );
  2540. *LdapHandle = NULL;
  2541. }
  2542. FreeConnection( LdapHandleCurrent, LdapBaseCurrent );
  2543. if (!HaveLock) {
  2544. LeaveCriticalSection(&gcsDHCPBINL);
  2545. }
  2546. return;
  2547. }
  2548. VOID
  2549. FreeConnection(
  2550. PLDAP * LdapHandle,
  2551. PWCHAR ** Base)
  2552. /*++
  2553. Routine Description:
  2554. Free the ldap connection for operating on either the domain or the
  2555. global catalog.
  2556. Arguments:
  2557. LdapHandle - The handle for further operations
  2558. Base - DN of where to start searches for computer objects to be freed.
  2559. Return Value:
  2560. None.
  2561. --*/
  2562. {
  2563. TraceFunc( "FreeConnection( )\n" );
  2564. if (*LdapHandle) {
  2565. ldap_unbind( *LdapHandle );
  2566. *LdapHandle = NULL;
  2567. }
  2568. if (*Base) {
  2569. ldap_value_free(*Base);
  2570. *Base = NULL;
  2571. }
  2572. }
  2573. VOID
  2574. FreeConnections
  2575. (
  2576. VOID
  2577. )
  2578. /*++
  2579. Routine Description:
  2580. Terminate any LDAP requests because we are stopping immediately. We
  2581. wait until all threads are stopped because the threads may have pointers
  2582. to the values we're going to free.
  2583. Arguments:
  2584. None.
  2585. Return Value:
  2586. None.
  2587. --*/
  2588. {
  2589. //
  2590. // clear out the cache, wait until all are marked as not being
  2591. // processed. We do this because the threads have pointers to DCBase,
  2592. // GCBase, etc and if we just blow them away, they may AV.
  2593. //
  2594. BinlCloseCache();
  2595. TraceFunc( "FreeConnections( )\n" );
  2596. FreeConnection( &DCLdapHandle, &DCBase);
  2597. FreeConnection( &GCLdapHandle, &GCBase);
  2598. }
  2599. DWORD
  2600. FindSCPForBinlServer(
  2601. PWCHAR * ResultPath,
  2602. PWCHAR * MachinePath,
  2603. BOOL GlobalSearch)
  2604. /*++
  2605. Routine Description:
  2606. Use the Directory Service to lookup the settings for this service.
  2607. Arguments:
  2608. GlobalSearch - TRUE if GC should be used
  2609. Return Value:
  2610. ERROR_SUCCESS or BINL_CANT_FIND_SERVER_MAO or ERROR_OUTOFMEMORY
  2611. --*/
  2612. {
  2613. DWORD Error = ERROR_SUCCESS;
  2614. PLDAP LdapHandle;
  2615. DWORD LdapError;
  2616. DWORD count;
  2617. ULONG ldapRetryLimit = 0;
  2618. PWCHAR * DsPath;
  2619. PLDAPMessage CurrentEntry;
  2620. PLDAPMessage LdapMessage = NULL;
  2621. PWCHAR ServerDN = NULL;
  2622. BOOL retryDN = TRUE;
  2623. // Paramters we want from the Computer Object
  2624. PWCHAR ComputerAttrs[2];
  2625. ComputerAttrs[0] = &L"netbootSCPBL";
  2626. ComputerAttrs[1] = NULL;
  2627. TraceFunc( "FindSCPForBinlServer( )\n" );
  2628. RetryGetDN:
  2629. //
  2630. // get ServerDN
  2631. //
  2632. // It should be something like this:
  2633. // ServerDN = "cn=server,cn=computers,dc=microsoft,dc=com"
  2634. //
  2635. EnterCriticalSection( &gcsParameters );
  2636. if (!BinlGlobalOurFQDNName) {
  2637. Error = ERROR_BINL_INITIALIZE_LDAP_CONNECTION_FAILED;
  2638. }
  2639. ServerDN = StrDupW( BinlGlobalOurFQDNName );
  2640. LeaveCriticalSection( &gcsParameters );
  2641. if (!ServerDN ) {
  2642. if (Error == ERROR_SUCCESS) {
  2643. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  2644. }
  2645. goto e0;
  2646. }
  2647. Error = InitializeConnection(GlobalSearch, &LdapHandle, NULL);
  2648. if ( Error != ERROR_SUCCESS ) {
  2649. BinlPrintDbg(( DEBUG_ERRORS, "!!Error 0x%08x - Ldap Connection Failed.\n", Error ));
  2650. SetLastError( Error );
  2651. Error = ERROR_BINL_INITIALIZE_LDAP_CONNECTION_FAILED;
  2652. goto e0;
  2653. }
  2654. RetrySearch:
  2655. LdapError = ldap_search_ext_sW(LdapHandle,
  2656. ServerDN,
  2657. LDAP_SCOPE_BASE,
  2658. L"objectClass=*",
  2659. ComputerAttrs,
  2660. FALSE,
  2661. NULL,
  2662. NULL,
  2663. &BinlLdapSearchTimeout,
  2664. 0,
  2665. &LdapMessage);
  2666. //
  2667. // if the object isn't found, then something is amiss.. go grab the DN
  2668. // again.
  2669. //
  2670. if ((LdapError == LDAP_NO_SUCH_OBJECT) && retryDN) {
  2671. retryDN = FALSE;
  2672. // if we didn't find an entry or it was busy, retry
  2673. GetOurServerInfo();
  2674. BinlFreeMemory( ServerDN );
  2675. ServerDN = NULL;
  2676. goto RetryGetDN;
  2677. }
  2678. if (((LdapError == LDAP_BUSY) || (LdapError == LDAP_NO_SUCH_OBJECT)) &&
  2679. (++ldapRetryLimit < LDAP_BUSY_LIMIT)) {
  2680. Sleep( LDAP_BUSY_DELAY );
  2681. goto RetrySearch;
  2682. }
  2683. if (LdapError != LDAP_SUCCESS) {
  2684. //
  2685. // something is screwed up with our handle, get rid of it.
  2686. //
  2687. HandleLdapFailure(
  2688. LdapError,
  2689. EVENT_WARNING_LDAP_SEARCH_ERROR,
  2690. GlobalSearch,
  2691. &LdapHandle,
  2692. FALSE); // don't have lock
  2693. goto e1;
  2694. }
  2695. count = ldap_count_entries( LdapHandle, LdapMessage );
  2696. if (count == 0) {
  2697. if (LdapError == LDAP_SUCCESS) {
  2698. LdapError = LDAP_TIMELIMIT_EXCEEDED;
  2699. }
  2700. BinlPrintDbg(( DEBUG_ERRORS, "!!LdapError 0x%08x - LDAP search failed... will retry later.\n", LdapError ));
  2701. BinlReportEventW( EVENT_ERROR_LOCATING_SCP,
  2702. EVENTLOG_ERROR_TYPE,
  2703. 0,
  2704. sizeof(LdapError),
  2705. NULL,
  2706. &LdapError
  2707. );
  2708. Error = ERROR_BINL_INITIALIZE_LDAP_CONNECTION_FAILED;
  2709. goto e1;
  2710. }
  2711. BinlAssertMsg( count == 1, "Count should have been 1." );
  2712. if ( count != 1 ) {
  2713. BinlPrintDbg(( DEBUG_ERRORS, "!!Error - LDAP search returned more than one SCP record for us.\n" ));
  2714. BinlReportEventW( BINL_DUPLICATE_MAO_RECORD,
  2715. EVENTLOG_ERROR_TYPE,
  2716. 0,
  2717. sizeof(count),
  2718. NULL,
  2719. &count
  2720. );
  2721. Error = ERROR_BINL_CANT_FIND_SERVER_MAO;
  2722. goto e1;
  2723. }
  2724. //
  2725. // Get the SCP
  2726. //
  2727. CurrentEntry = ldap_first_entry( LdapHandle, LdapMessage );
  2728. DsPath = ldap_get_values( LdapHandle, CurrentEntry, L"netbootSCPBL" );
  2729. if ( !DsPath ) {
  2730. BinlPrintDbg(( DEBUG_ERRORS, "!!Error - Could not get 'netbootSCPBL' from the server's MAO\n" ))
  2731. Error = ERROR_BINL_CANT_FIND_SERVER_MAO;
  2732. goto e1;
  2733. }
  2734. *ResultPath = (PWCHAR) BinlAllocateMemory( (wcslen(*DsPath) + 1) * sizeof(WCHAR) );
  2735. if ( *ResultPath == NULL ) {
  2736. BinlPrintDbg(( DEBUG_ERRORS, "!!Error - Out of memory.\n" ));
  2737. Error = ERROR_OUTOFMEMORY;
  2738. goto e2;
  2739. }
  2740. wcscpy( *ResultPath, *DsPath );
  2741. *MachinePath = ServerDN;
  2742. ServerDN = NULL; // prevent freeing
  2743. Error = ERROR_SUCCESS;
  2744. e2:
  2745. ldap_value_free(DsPath);
  2746. e1:
  2747. if (LdapMessage) {
  2748. ldap_msgfree( LdapMessage );
  2749. }
  2750. e0:
  2751. if ( ServerDN )
  2752. BinlFreeMemory( ServerDN );
  2753. return Error;
  2754. }
  2755. DWORD
  2756. UpdateSettingsUsingResults(
  2757. PLDAP LdapHandle,
  2758. PLDAPMessage LdapMessage,
  2759. LPWSTR ComputerAttrs[],
  2760. PDWORD NumberOfAttributesFound OPTIONAL
  2761. )
  2762. {
  2763. PLDAPMessage CurrentEntry;
  2764. DWORD LdapError = LDAP_SUCCESS;
  2765. DWORD count;
  2766. DWORD countFound = 0;
  2767. TraceFunc( "UpdateSettingsUsingResults( ... )\n" );
  2768. CurrentEntry = ldap_first_entry( LdapHandle, LdapMessage );
  2769. for ( count = 0; ComputerAttrs[count] != NULL; count++ ) {
  2770. PWCHAR * Attribute;
  2771. Attribute = ldap_get_values( LdapHandle, CurrentEntry, ComputerAttrs[count] );
  2772. if (Attribute == NULL) {
  2773. #if DBG
  2774. CHAR Temp[MAX_PATH];
  2775. if (BinlUnicodeToAnsi(ComputerAttrs[count],Temp,MAX_PATH)) {
  2776. BinlPrintDbg(( DEBUG_OPTIONS, "Did not find attribute '%s'... skipping\n", Temp ));
  2777. }
  2778. #endif
  2779. if (count != 1) { // NewMachineOU
  2780. continue; // skip and use default
  2781. }
  2782. } else {
  2783. //
  2784. // Increment the count of attributes found.
  2785. //
  2786. countFound++;
  2787. }
  2788. switch( count )
  2789. {
  2790. case 0: // NewMachineNamingPolicy
  2791. {
  2792. DWORD Length = wcslen( *Attribute ) + 1;
  2793. PWCHAR psz = (PWCHAR) BinlAllocateMemory( Length * sizeof(WCHAR) );
  2794. BinlAssert( _wcsicmp( ComputerAttrs[0], L"netbootNewMachineNamingPolicy" ) == 0 );
  2795. if ( psz )
  2796. {
  2797. wcscpy( psz, *Attribute );
  2798. EnterCriticalSection(&gcsParameters);
  2799. if ( NewMachineNamingPolicy != NULL )
  2800. {
  2801. BinlFreeMemory( NewMachineNamingPolicy );
  2802. }
  2803. NewMachineNamingPolicy = psz;
  2804. LeaveCriticalSection(&gcsParameters);
  2805. }
  2806. BinlPrint(( DEBUG_OPTIONS, "NewMachineNamingPolicy = '%ws'\n", NewMachineNamingPolicy ));
  2807. }
  2808. break;
  2809. case 1: // NewMachineOU
  2810. {
  2811. LPWSTR psz;
  2812. DWORD Length;
  2813. BOOL getServerInfo;
  2814. BinlAssert( _wcsicmp( ComputerAttrs[1], L"netbootNewMachineOU" ) == 0 );
  2815. if (Attribute == NULL || *Attribute == NULL) {
  2816. Length = 1;
  2817. } else {
  2818. Length = wcslen( *Attribute ) + 1;
  2819. }
  2820. psz = (LPWSTR) BinlAllocateMemory( Length * sizeof(WCHAR) );
  2821. if (psz == NULL) {
  2822. LdapError = LDAP_NO_MEMORY;
  2823. break;
  2824. }
  2825. if (Length == 1) {
  2826. *psz = L'\0';
  2827. } else {
  2828. wcscpy( psz, *Attribute );
  2829. }
  2830. EnterCriticalSection(&gcsParameters);
  2831. getServerInfo = (BOOL)( (BinlGlobalDefaultContainer == NULL) ||
  2832. (_wcsicmp(BinlGlobalDefaultContainer, psz) != 0) );
  2833. if ( BinlGlobalDefaultContainer != NULL )
  2834. {
  2835. BinlFreeMemory( BinlGlobalDefaultContainer );
  2836. }
  2837. BinlGlobalDefaultContainer = psz;
  2838. LeaveCriticalSection(&gcsParameters);
  2839. if ( getServerInfo ) {
  2840. ULONG Error = GetOurServerInfo();
  2841. if (Error != ERROR_SUCCESS) {
  2842. BinlPrintDbg(( DEBUG_ERRORS, "GetOurServerInfo returned 0x%x, we had a new default container.\n", Error ));
  2843. }
  2844. }
  2845. BinlPrint(( DEBUG_OPTIONS, "DefaultContainer = %ws\n", BinlGlobalDefaultContainer ));
  2846. }
  2847. break;
  2848. case 2: // MaxClients
  2849. {
  2850. CHAR Temp[10];
  2851. BinlAssert( _wcsicmp( ComputerAttrs[2], L"netbootMaxClients" ) == 0 );
  2852. if (!BinlUnicodeToAnsi(*Attribute,Temp,sizeof(Temp))) {
  2853. BinlMaxClients = atoi( Temp );
  2854. BinlPrint(( DEBUG_OPTIONS, "BinlMaxClients = %u\n", BinlMaxClients ));
  2855. }
  2856. }
  2857. break;
  2858. case 3: // CurrentClientCount
  2859. {
  2860. CHAR Temp[10];
  2861. BinlAssert( _wcsicmp( ComputerAttrs[3], L"netbootCurrentClientCount" ) == 0 );
  2862. if (!BinlUnicodeToAnsi(*Attribute,Temp,sizeof(Temp))) {
  2863. CurrentClientCount = atoi( Temp );
  2864. BinlPrint(( DEBUG_OPTIONS, "(Last) CurrentClientCount = %u\n", CurrentClientCount ));
  2865. }
  2866. }
  2867. break;
  2868. case 4: // AnswerRequest
  2869. BinlAssert( _wcsicmp ( ComputerAttrs[4], L"netbootAnswerRequests" ) == 0 );
  2870. if ( wcscmp( *Attribute, L"TRUE" ) == 0 )
  2871. {
  2872. AnswerRequests = TRUE;
  2873. }
  2874. else
  2875. {
  2876. AnswerRequests = FALSE;
  2877. }
  2878. BinlPrint(( DEBUG_OPTIONS, "AnswerRequests = %s\n", BOOLTOSTRING( AnswerRequests ) ));
  2879. break;
  2880. case 5: // AnswerOnlyValidClients
  2881. BinlAssert( _wcsicmp( ComputerAttrs[5], L"netbootAnswerOnlyValidClients" ) == 0 );
  2882. if ( wcscmp( *Attribute, L"TRUE" ) == 0 ) {
  2883. AnswerOnlyValidClients = TRUE;
  2884. } else {
  2885. AnswerOnlyValidClients = FALSE;
  2886. }
  2887. BinlPrint(( DEBUG_OPTIONS, "AnswerOnlyValidClients = %s\n", BOOLTOSTRING( AnswerOnlyValidClients ) ));
  2888. break;
  2889. case 6: // AllowNewClients
  2890. BinlAssert( _wcsicmp( ComputerAttrs[6], L"netbootAllowNewClients" ) == 0 );
  2891. if ( wcscmp( *Attribute, L"TRUE" ) == 0 )
  2892. {
  2893. AllowNewClients = TRUE;
  2894. }
  2895. else
  2896. {
  2897. AllowNewClients = FALSE;
  2898. }
  2899. BinlPrint(( DEBUG_OPTIONS, "AllowNewClients = %s\n", BOOLTOSTRING( AllowNewClients ) ));
  2900. break;
  2901. case 7: // LimitClients
  2902. BinlAssert( _wcsicmp( ComputerAttrs[7], L"netbootLimitClients" ) == 0 );
  2903. if ( wcscmp( *Attribute, L"TRUE" ) == 0 )
  2904. {
  2905. LimitClients = TRUE;
  2906. }
  2907. else
  2908. {
  2909. LimitClients = FALSE;
  2910. }
  2911. BinlPrint(( DEBUG_OPTIONS, "LimitClients = %s\n", BOOLTOSTRING( LimitClients ) ));
  2912. break;
  2913. case 8: // IntellimirrorOSes
  2914. case 9: // Tools
  2915. case 10: // LocalInstallOSes
  2916. BinlAssert( _wcsicmp( ComputerAttrs[8], L"netbootIntellimirrorOSes" ) == 0 );
  2917. BinlAssert( _wcsicmp( ComputerAttrs[9], L"netbootTools" ) == 0 );
  2918. BinlAssert( _wcsicmp( ComputerAttrs[10], L"netbootLocalInstallOSes" ) == 0 );
  2919. //
  2920. // TODO: Tie these in with OS Chooser - this is still TBD.
  2921. //
  2922. break;
  2923. default:
  2924. // Somethings wrong
  2925. BinlAssert( 0 );
  2926. }
  2927. if (Attribute != NULL) {
  2928. ldap_value_free(Attribute);
  2929. }
  2930. }
  2931. if ( ARGUMENT_PRESENT(NumberOfAttributesFound) ) {
  2932. *NumberOfAttributesFound = countFound;
  2933. }
  2934. return LdapError;
  2935. }
  2936. DWORD
  2937. GetBinlServerParameters(
  2938. BOOL GlobalSearch)
  2939. /*++
  2940. Routine Description:
  2941. Use the Directory Service to lookup the settings for this service.
  2942. Arguments:
  2943. GlobalSearch - TRUE if GC should be used
  2944. Return Value:
  2945. ERROR_SUCCESS or BINL_CANT_FIND_SERVER_MAO
  2946. --*/
  2947. {
  2948. DWORD Error;
  2949. PLDAP LdapHandle;
  2950. DWORD LdapError;
  2951. DWORD count;
  2952. ULONG ldapRetryLimit = 0;
  2953. PLDAPMessage LdapMessage = NULL;
  2954. // Paramters we want from the IntelliMirror-SCP
  2955. // NOTE: These must be the same ordinals as those used in
  2956. // UpdateSettingsUsingResults( ).
  2957. PWCHAR ComputerAttrs[12];
  2958. ComputerAttrs[0] = &L"netbootNewMachineNamingPolicy";
  2959. ComputerAttrs[1] = &L"netbootNewMachineOU";
  2960. ComputerAttrs[2] = &L"netbootMaxClients";
  2961. ComputerAttrs[3] = &L"netbootCurrentClientCount";
  2962. ComputerAttrs[4] = &L"netbootAnswerRequests";
  2963. ComputerAttrs[5] = &L"netbootAnswerOnlyValidClients";
  2964. ComputerAttrs[6] = &L"netbootAllowNewClients";
  2965. ComputerAttrs[7] = &L"netbootLimitClients";
  2966. ComputerAttrs[8] = &L"netbootIntellimirrorOSes";
  2967. ComputerAttrs[9] = &L"netbootTools";
  2968. ComputerAttrs[10] = &L"netbootLocalInstallOSes";
  2969. ComputerAttrs[11] = NULL;
  2970. TraceFunc( "GetBinlServerParameters( )\n" );
  2971. Error = FindSCPForBinlServer( &BinlGlobalSCPPath, &BinlGlobalServerDN, GlobalSearch );
  2972. if ( Error != ERROR_SUCCESS ) {
  2973. BinlPrint(( DEBUG_ERRORS, "!!Error 0x%08x - SCP not found. Default settings being used.\n", Error ));
  2974. goto e0;
  2975. }
  2976. BinlPrint(( DEBUG_OPTIONS, "ServerDN = '%ws'\n", BinlGlobalServerDN ));
  2977. BinlPrint(( DEBUG_OPTIONS, "SCPDN = '%ws'\n", BinlGlobalSCPPath ));
  2978. RetryConnection:
  2979. Error = InitializeConnection( GlobalSearch, &LdapHandle, NULL );
  2980. if ( Error != ERROR_SUCCESS ) {
  2981. SetLastError( Error );
  2982. Error = ERROR_BINL_INITIALIZE_LDAP_CONNECTION_FAILED;
  2983. goto e0;
  2984. }
  2985. Retry:
  2986. LdapError = ldap_search_ext_sW(LdapHandle,
  2987. BinlGlobalSCPPath,
  2988. LDAP_SCOPE_BASE,
  2989. L"objectClass=*",
  2990. ComputerAttrs,
  2991. FALSE,
  2992. NULL,
  2993. NULL,
  2994. NULL,
  2995. 0,
  2996. &LdapMessage);
  2997. if ((LdapError == LDAP_BUSY) && (++ldapRetryLimit < LDAP_BUSY_LIMIT)) {
  2998. Sleep( LDAP_BUSY_DELAY );
  2999. goto Retry;
  3000. }
  3001. if (LdapError != LDAP_SUCCESS) {
  3002. HandleLdapFailure( LdapError,
  3003. EVENT_WARNING_LDAP_SEARCH_ERROR,
  3004. GlobalSearch,
  3005. &LdapHandle,
  3006. FALSE ); // don't have lock
  3007. if (LdapHandle == NULL) {
  3008. if (++ldapRetryLimit < LDAP_SERVER_DOWN_LIMIT) {
  3009. goto RetryConnection;
  3010. }
  3011. goto e0;
  3012. }
  3013. goto e1;
  3014. }
  3015. count = ldap_count_entries( LdapHandle, LdapMessage );
  3016. if (count == 0) {
  3017. if (LdapError == LDAP_SUCCESS) {
  3018. LdapError = LDAP_TIMELIMIT_EXCEEDED;
  3019. }
  3020. BinlPrintDbg(( DEBUG_ERRORS, "!!LdapError 0x%08x - Failed to retrieve parameters... will retry later.\n", LdapError ));
  3021. BinlReportEventW( EVENT_ERROR_LOCATING_SCP,
  3022. EVENTLOG_ERROR_TYPE,
  3023. 0,
  3024. sizeof(LdapError),
  3025. NULL,
  3026. &LdapError
  3027. );
  3028. Error = ERROR_BINL_INITIALIZE_LDAP_CONNECTION_FAILED;
  3029. goto e1;
  3030. }
  3031. BinlAssertMsg( count == 1, "Count should have been one. Is the SCP missing?" );
  3032. // We did a base level search, we better only have gotten one record back.
  3033. BinlAssert( count == 1 );
  3034. // Retrieve the results into the settings
  3035. LdapError = UpdateSettingsUsingResults( LdapHandle, LdapMessage, ComputerAttrs, &count );
  3036. if ( LdapError == LDAP_SUCCESS )
  3037. {
  3038. BinlReportEventW( count != 0 ? EVENT_SCP_READ_SUCCESSFULLY :
  3039. EVENT_SCP_READ_SUCCESSFULLY_EMPTY,
  3040. count != 0 ? EVENTLOG_INFORMATION_TYPE :
  3041. EVENTLOG_WARNING_TYPE,
  3042. 0,
  3043. 0,
  3044. NULL,
  3045. NULL
  3046. );
  3047. }
  3048. e1:
  3049. if (LdapMessage) {
  3050. ldap_msgfree( LdapMessage );
  3051. }
  3052. e0:
  3053. return Error;
  3054. }
  3055. VOID
  3056. BinlLogDuplicateDsRecords (
  3057. LPGUID Guid,
  3058. LDAP *LdapHandle,
  3059. LDAPMessage *LdapMessage,
  3060. LDAPMessage *CurrentEntry
  3061. )
  3062. //
  3063. // Log an error that we've received duplicate records for a client when
  3064. // we looked them up by GUID.
  3065. //
  3066. // We log the DNs so that the administrator can look them up.
  3067. //
  3068. {
  3069. LPWSTR strings[4];
  3070. LPWSTR dn1;
  3071. LPWSTR dn2;
  3072. ULONG strCount = 0; // up to two strings to log
  3073. PLDAPMessage nextEntry = ldap_next_entry( LdapHandle, LdapMessage );
  3074. LPWSTR GuidString;
  3075. if (SUCCEEDED(StringFromIID( (REFIID)Guid, &GuidString ))) {
  3076. strCount += 1;
  3077. }
  3078. dn1 = ldap_get_dnW( LdapHandle, CurrentEntry );
  3079. if (nextEntry != NULL) {
  3080. dn2 = ldap_get_dnW( LdapHandle, nextEntry );
  3081. } else {
  3082. dn2 = NULL;
  3083. }
  3084. if (dn2 != NULL) {
  3085. if (dn1 == NULL) {
  3086. dn1 = dn2;
  3087. dn2 = NULL;
  3088. } else {
  3089. strCount += 1;
  3090. }
  3091. }
  3092. if (dn1 != NULL) {
  3093. strCount += 1;
  3094. }
  3095. BinlPrint(( DEBUG_ERRORS, "Warning - BINL received multiple records for a single GUID.\n" ));
  3096. strings[0] = GuidString;
  3097. strings[1] = dn1;
  3098. strings[2] = dn2;
  3099. strings[3] = NULL;
  3100. BinlReportEventW( BINL_DUPLICATE_DS_RECORD,
  3101. EVENTLOG_WARNING_TYPE,
  3102. strCount,
  3103. 0,
  3104. strings,
  3105. NULL
  3106. );
  3107. ldap_memfree( dn1 ); // it's ok to call ldap_memfree with null
  3108. ldap_memfree( dn2 );
  3109. CoTaskMemFree( GuidString );
  3110. }
  3111. #ifndef DSCRACKNAMES_DNS
  3112. DWORD
  3113. BinlDNStoFQDN(
  3114. PWCHAR pMachineDNS,
  3115. PWCHAR * ppMachineDN )
  3116. {
  3117. DWORD Error;
  3118. DWORD LdapError;
  3119. WCHAR FilterTemplate[] = L"dnsHostName=%ws";
  3120. PWCHAR Filter = NULL;
  3121. PWCHAR ComputerAttrs[2];
  3122. PLDAPMessage CurrentEntry;
  3123. PLDAPMessage LdapMessage = NULL;
  3124. LDAP *LdapHandle;
  3125. PWCHAR * Base;
  3126. PWCHAR * MachineDN;
  3127. DWORD count;
  3128. DWORD uSize;
  3129. ULONG ldapRetryLimit = 0;
  3130. TraceFunc( "BinlDNStoFQDN( )\n" );
  3131. BinlAssert( ppMachineDN );
  3132. BinlAssert( pMachineDNS );
  3133. ComputerAttrs[0] = &L"distinguishedName";
  3134. ComputerAttrs[1] = NULL;
  3135. // Build the filter to find the Computer object
  3136. uSize = sizeof(FilterTemplate) // include NULL terminater
  3137. + (wcslen( pMachineDNS ) * sizeof(WCHAR));
  3138. Filter = (LPWSTR) BinlAllocateMemory( uSize );
  3139. if ( !Filter ) {
  3140. Error = E_OUTOFMEMORY;
  3141. goto e0;
  3142. }
  3143. wsprintf( Filter, FilterTemplate, pMachineDNS );
  3144. BinlPrintDbg(( DEBUG_MISC, "Searching for %ws...\n", Filter ));
  3145. RetryConnection:
  3146. Error = InitializeConnection( FALSE, &LdapHandle, &Base );
  3147. if ( Error != ERROR_SUCCESS ) {
  3148. SetLastError( Error );
  3149. Error = ERROR_BINL_INITIALIZE_LDAP_CONNECTION_FAILED;
  3150. goto e0;
  3151. }
  3152. Retry:
  3153. LdapError = ldap_search_ext_sW( LdapHandle,
  3154. *Base,
  3155. LDAP_SCOPE_SUBTREE,
  3156. Filter,
  3157. ComputerAttrs,
  3158. FALSE,
  3159. NULL,
  3160. NULL,
  3161. NULL,
  3162. 0,
  3163. &LdapMessage);
  3164. switch (LdapError)
  3165. {
  3166. case LDAP_SUCCESS:
  3167. break;
  3168. case LDAP_BUSY:
  3169. if (++ldapRetryLimit < LDAP_BUSY_LIMIT) {
  3170. Sleep( LDAP_BUSY_DELAY );
  3171. goto Retry;
  3172. }
  3173. // lack of break is on purpose.
  3174. default:
  3175. BinlPrintDbg(( DEBUG_ERRORS, "!!LdapError 0x%08x - Search failed in DNStoFQDN.\n", LdapError ));
  3176. HandleLdapFailure( LdapError,
  3177. EVENT_WARNING_LDAP_SEARCH_ERROR,
  3178. FALSE,
  3179. &LdapHandle,
  3180. FALSE ); // don't have lock
  3181. if (LdapHandle == NULL) {
  3182. if (++ldapRetryLimit < LDAP_SERVER_DOWN_LIMIT) {
  3183. goto RetryConnection;
  3184. }
  3185. }
  3186. goto e1;
  3187. }
  3188. // Did we get a Computer Object?
  3189. count = ldap_count_entries( LdapHandle, LdapMessage );
  3190. if ( count == 0 ) {
  3191. Error = ERROR_BINL_UNABLE_TO_CONVERT;
  3192. goto e1; // nope
  3193. }
  3194. // if we get more than more entry back, we will use only the
  3195. // first one.
  3196. CurrentEntry = ldap_first_entry( LdapHandle, LdapMessage );
  3197. MachineDN = ldap_get_values( LdapHandle, CurrentEntry, ComputerAttrs[0] );
  3198. if ( !MachineDN ) {
  3199. Error = ERROR_BINL_UNABLE_TO_CONVERT;
  3200. goto e1;
  3201. }
  3202. *ppMachineDN = BinlStrDup( *MachineDN );
  3203. Error = ERROR_SUCCESS;
  3204. ldap_value_free( MachineDN );
  3205. e1:
  3206. if (LdapMessage) {
  3207. ldap_msgfree( LdapMessage );
  3208. }
  3209. e0:
  3210. return Error;
  3211. }
  3212. #endif // DSCRACKNAMES_DNS
  3213. // message.c eof