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.

2274 lines
69 KiB

  1. /*++
  2. Copyright (c) 1997-1998 Microsoft Corporation
  3. Module Name:
  4. ds.c
  5. Abstract:
  6. This module contains the code to process OS Chooser message
  7. for the BINL server.
  8. Author:
  9. Adam Barr (adamba) 9-Jul-1997
  10. Geoff Pease (gpease) 10-Nov-1997
  11. Environment:
  12. User Mode - Win32
  13. Revision History:
  14. --*/
  15. #include "binl.h"
  16. #pragma hdrstop
  17. #include <math.h> // pow() function
  18. #include <riname.h>
  19. #include <riname.c>
  20. DWORD
  21. OscGetUserDetails (
  22. PCLIENT_STATE clientState
  23. )
  24. //
  25. // This function fills in USERDOMAIN, USERFIRSTNAME, USERLASTNAME, USEROU in
  26. // the client state. Also fills in ROOTDOMAIN for root of enterprise.
  27. //
  28. {
  29. DWORD Error = ERROR_SUCCESS;
  30. DWORD Count;
  31. LPWSTR pszUserName = OscFindVariableW( clientState, "USERNAME" );
  32. LPWSTR pUserDomain = OscFindVariableW( clientState, "USERDOMAIN" );
  33. LPWSTR pUserOU = OscFindVariableW( clientState, "USEROU" );
  34. LPWSTR pUserFullName = OscFindVariableW( clientState, "USERFULLNAME" );
  35. PLDAP LdapHandle;
  36. PLDAPMessage LdapMessage = NULL;
  37. PWSTR Filter = NULL;
  38. PWCHAR ldapAttributes[5];
  39. BOOLEAN impersonating = FALSE;
  40. PLDAPMessage ldapEntry;
  41. PWCHAR *ldapConfigContainer = NULL;
  42. PWCHAR *ldapDomain = NULL;
  43. PWCHAR *ldapFirstName = NULL;
  44. PWCHAR *ldapLastName = NULL;
  45. PWCHAR *ldapDisplayName = NULL;
  46. PWCHAR *ldapAccountName = NULL;
  47. BOOLEAN allocatedContainer = FALSE;
  48. PWCHAR configContainer = NULL;
  49. BOOLEAN firstNameValid = FALSE;
  50. BOOLEAN lastNameValid = FALSE;
  51. BOOLEAN userFullNameSet = FALSE;
  52. PLDAPControlW controlArray[2];
  53. LDAPControlW controlNoReferrals;
  54. ULONG noReferralsPlease;
  55. PWCHAR ldapUserDN = NULL;
  56. PWCHAR *explodedDN = NULL;
  57. PWCHAR dnUsersOU = NULL;
  58. TraceFunc( "OscGetUserDetails( )\n" );
  59. if ( pszUserName[0] == L'\0' ) {
  60. OscAddVariableA( clientState, "SUBERROR", "USERNAME" );
  61. return ERROR_BINL_MISSING_VARIABLE;
  62. }
  63. //
  64. // If the USERFULLNAME variable already exists, we won't change it below.
  65. // But if it came back as an empty string, that might actually mean
  66. // that the variable doesn't exist. In such a case, when SearchAndReplace
  67. // processes the .SIF file for the client, it will leave occurrences of
  68. // "%USERFULLNAME%" alone -- it won't replace them with "". We don't want
  69. // "%USERFULLNAME% to hang around, so we explicitly set it to an empty
  70. // string if it doesn't already exist or is an empty string. We do the
  71. // same thing with USERFIRSTNAME, USERLASTNAME, and USERDISPLAYNAME.
  72. //
  73. if (pUserFullName[0] != L'\0') {
  74. userFullNameSet = TRUE;
  75. } else {
  76. OscAddVariableW( clientState, "USERFULLNAME", L"" );
  77. }
  78. {
  79. LPWSTR name;
  80. name = OscFindVariableW( clientState, "USERFIRSTNAME" );
  81. if (name[0] == L'\0') {
  82. OscAddVariableW( clientState, "USERFIRSTNAME", L"" );
  83. }
  84. name = OscFindVariableW( clientState, "USERLASTNAME" );
  85. if (name[0] == L'\0') {
  86. OscAddVariableW( clientState, "USERLASTNAME", L"" );
  87. }
  88. name = OscFindVariableW( clientState, "USERDISPLAYNAME" );
  89. if (name[0] == L'\0') {
  90. OscAddVariableW( clientState, "USERDISPLAYNAME", L"" );
  91. }
  92. }
  93. if ( pUserOU[0] != L'\0' ) {
  94. //
  95. // if we've already found this user's info, bail here with success.
  96. //
  97. return ERROR_SUCCESS;
  98. }
  99. //
  100. // if the users domain and the servers domain don't match,
  101. // then try connecting to the DC for the new domain. If we
  102. // don't do this, then we won't necessarily be able to get
  103. // the correct information about the user. By connecting to
  104. // the new DC, we get the clientState to cache some information
  105. // about the new domain.
  106. //
  107. if (pUserDomain[0] != L'\0' ) {
  108. PWSTR CrossDC = OscFindVariableW( clientState, "DCNAME" );
  109. if ( (CrossDC[0] == L'\0') &&
  110. (_wcsicmp(pUserDomain, BinlGlobalOurDomainName) != 0)) {
  111. HANDLE hDC;
  112. PSTR pUserDomainA = OscFindVariableA( clientState, "USERDOMAIN" );
  113. Error = MyGetDcHandle(clientState, pUserDomainA,&hDC);
  114. if (Error == ERROR_SUCCESS) {
  115. DsUnBindA(&hDC);
  116. }
  117. }
  118. }
  119. Error = OscImpersonate(clientState);
  120. if (Error != ERROR_SUCCESS) {
  121. BinlPrintDbg((DEBUG_ERRORS,
  122. "OscGetUserDetails: OscImpersonate failed %lx\n", Error));
  123. return Error;
  124. }
  125. impersonating = TRUE;
  126. BinlAssert( clientState->AuthenticatedDCLdapHandle != NULL );
  127. LdapHandle = clientState->AuthenticatedDCLdapHandle;
  128. //
  129. // we first look up the configuration and default container, we'll need
  130. // one or the other, based on whether we have a domain name or not.
  131. //
  132. ldapAttributes[0] = L"configurationNamingContext";
  133. ldapAttributes[1] = L"rootDomainNamingContext";
  134. ldapAttributes[2] = NULL;
  135. Error = ldap_search_ext_sW(LdapHandle,
  136. NULL,
  137. LDAP_SCOPE_BASE,
  138. L"(objectClass=*)",
  139. ldapAttributes,
  140. FALSE,
  141. NULL,
  142. NULL,
  143. 0,
  144. 0,
  145. &LdapMessage);
  146. if (Error == LDAP_SUCCESS) {
  147. Count = ldap_count_entries( LdapHandle, LdapMessage );
  148. if (Count > 0) {
  149. ldapEntry = ldap_first_entry( LdapHandle, LdapMessage );
  150. if (ldapEntry != NULL) {
  151. ldapConfigContainer = ldap_get_valuesW( LdapHandle,
  152. ldapEntry,
  153. L"configurationNamingContext" );
  154. ldapDomain = ldap_get_valuesW( LdapHandle,
  155. ldapEntry,
  156. L"rootDomainNamingContext" );
  157. if (ldapDomain != NULL &&
  158. *ldapDomain != NULL &&
  159. **ldapDomain != L'\0') {
  160. OscAddVariableW( clientState, "ROOTDOMAIN", *ldapDomain );
  161. }
  162. }
  163. } else {
  164. LogLdapError( EVENT_WARNING_LDAP_SEARCH_ERROR,
  165. LdapGetLastError(),
  166. LdapHandle
  167. );
  168. }
  169. } else {
  170. LogLdapError( EVENT_WARNING_LDAP_SEARCH_ERROR,
  171. LdapGetLastError(),
  172. LdapHandle
  173. );
  174. }
  175. if (LdapMessage) {
  176. ldap_msgfree( LdapMessage );
  177. LdapMessage = NULL;
  178. }
  179. //
  180. // we either have the config container or the default domain DN. If
  181. // we only have the config container, go get the correct domain DN.
  182. //
  183. if ( pUserDomain[0] != L'\0' ) {
  184. //
  185. // Since the user specified a domain, remove the defaulting to the same domain
  186. // as the RIS server.
  187. //
  188. ldapDomain = NULL;
  189. //
  190. // if a domain was specified, then we look it up to find the baseDN
  191. //
  192. // we fail if we didn't get the config container
  193. //
  194. if (ldapConfigContainer == NULL ||
  195. *ldapConfigContainer == NULL ||
  196. **ldapConfigContainer == L'\0') {
  197. if (Error == LDAP_SUCCESS) {
  198. Error = LDAP_NO_SUCH_ATTRIBUTE;
  199. }
  200. BinlPrintDbg((DEBUG_ERRORS,
  201. "OscGetUserDetails: get config container failed %lx\n", Error));
  202. Error = LdapMapErrorToWin32( Error );
  203. goto exitGetUserDetails;
  204. }
  205. //
  206. // we then tack on "CN=Partitions," to search the partitions container
  207. //
  208. // sizeof contains the \0 in it.
  209. //
  210. Count = wcslen( *ldapConfigContainer ) + (sizeof( L"CN=Partitions,")/sizeof(WCHAR));
  211. configContainer = BinlAllocateMemory( Count * sizeof(WCHAR) );
  212. if (configContainer == NULL) {
  213. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  214. goto exitGetUserDetails;
  215. }
  216. if (_snwprintf(configContainer,
  217. Count,
  218. L"CN=Partitions,%ws",
  219. *ldapConfigContainer) < 0) {
  220. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  221. goto exitGetUserDetails; // this frees configContainer
  222. }
  223. configContainer[Count-1] = L'\0';
  224. //
  225. // then we find the correct partition, we ignore the enterprise and
  226. // enterprise schema entries by specifying a non-empty netbios name.
  227. //
  228. ldapAttributes[0] = L"NCName";
  229. ldapAttributes[1] = NULL;
  230. Filter = BinlAllocateMemory(
  231. ((wcslen(pUserDomain) * 2) +
  232. (sizeof(L"(&(objectClass=CrossRef)(netbiosName=*)(|(dnsRoot=)(cn=)))")/sizeof(WCHAR)))
  233. * sizeof(WCHAR) );
  234. if (!Filter) {
  235. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  236. goto exitGetUserDetails;
  237. }
  238. wsprintf(Filter,
  239. L"(&(objectClass=CrossRef)(netbiosName=*)(|(dnsRoot=%s)(cn=%s)))",
  240. pUserDomain,
  241. pUserDomain);
  242. Error = ldap_search_ext_sW(LdapHandle,
  243. configContainer,
  244. LDAP_SCOPE_ONELEVEL,
  245. Filter,
  246. ldapAttributes,
  247. FALSE,
  248. NULL,
  249. NULL,
  250. 0,
  251. 0,
  252. &LdapMessage);
  253. if (Error == LDAP_SUCCESS) {
  254. Count = ldap_count_entries( LdapHandle, LdapMessage );
  255. if (Count > 0) {
  256. PWCHAR *ldapDomainFromPartition = NULL;
  257. ldapEntry = ldap_first_entry( LdapHandle,
  258. LdapMessage );
  259. if (ldapEntry != NULL) {
  260. ldapDomainFromPartition = ldap_get_valuesW( LdapHandle,
  261. ldapEntry,
  262. L"NCName" );
  263. if (ldapDomainFromPartition != NULL) {
  264. //
  265. // if we read a valid DN from the partitions container,
  266. // we free the default one and switch over to the
  267. // one we just found.
  268. //
  269. if (*ldapDomainFromPartition != NULL &&
  270. **ldapDomainFromPartition != L'\0') {
  271. ldap_value_free( ldapDomain );
  272. ldapDomain = ldapDomainFromPartition;
  273. } else {
  274. ldap_value_free( ldapDomainFromPartition );
  275. }
  276. }
  277. }
  278. } else {
  279. LogLdapError( EVENT_WARNING_LDAP_SEARCH_ERROR, LdapGetLastError(), LdapHandle);
  280. }
  281. } else {
  282. LogLdapError( EVENT_WARNING_LDAP_SEARCH_ERROR, LdapGetLastError(), LdapHandle);
  283. }
  284. if (LdapMessage) {
  285. ldap_msgfree( LdapMessage );
  286. LdapMessage = NULL;
  287. }
  288. } else if ((ldapDomain != NULL) && (*ldapDomain != NULL) && (**ldapDomain != L'\0')) {
  289. //
  290. // Add the user's domain as a variable to the client state.
  291. //
  292. OscAddVariableW( clientState, "USERDOMAIN", *ldapDomain );
  293. pUserDomain = OscFindVariableW( clientState, "USERDOMAIN" );
  294. }
  295. if (ldapDomain == NULL ||
  296. *ldapDomain == NULL ||
  297. **ldapDomain == L'\0') {
  298. if (Error == LDAP_SUCCESS) {
  299. Error = LDAP_NO_SUCH_ATTRIBUTE;
  300. }
  301. BinlPrintDbg((DEBUG_ERRORS,
  302. "OscGetUserDetails: get default domain failed %lx\n", Error));
  303. Error = LdapMapErrorToWin32( Error );
  304. goto exitGetUserDetails;
  305. }
  306. //
  307. // go find the user's first name, last name, display name,
  308. // and account name from the DS.
  309. //
  310. ldapAttributes[0] = &L"givenName";
  311. ldapAttributes[1] = &L"sn";
  312. ldapAttributes[2] = &L"displayName";
  313. ldapAttributes[3] = &L"cn";
  314. ldapAttributes[4] = NULL;
  315. BinlFreeMemory( Filter );
  316. Filter = BinlAllocateMemory(
  317. (wcslen( pszUserName ) + (sizeof(L"(&(objectClass=user)(samAccountName=))")/sizeof(WCHAR)))
  318. * sizeof(WCHAR));
  319. if (!Filter) {
  320. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  321. goto exitGetUserDetails;
  322. }
  323. wsprintf( Filter, L"(&(objectClass=user)(samAccountName=%s))", pszUserName );
  324. //
  325. // we really don't want it to go chasing referrals over the entire
  326. // enterprise since we know what the domain is but we do want to chase
  327. // externals.
  328. //
  329. noReferralsPlease = (ULONG)((ULONG_PTR)LDAP_CHASE_EXTERNAL_REFERRALS);
  330. controlNoReferrals.ldctl_oid = LDAP_CONTROL_REFERRALS_W;
  331. controlNoReferrals.ldctl_value.bv_len = sizeof(ULONG);
  332. controlNoReferrals.ldctl_value.bv_val = (PCHAR) &noReferralsPlease;
  333. controlNoReferrals.ldctl_iscritical = FALSE;
  334. controlArray[0] = &controlNoReferrals;
  335. controlArray[1] = NULL;
  336. Error = ldap_search_ext_sW(LdapHandle,
  337. *ldapDomain,
  338. LDAP_SCOPE_SUBTREE,
  339. Filter,
  340. ldapAttributes,
  341. FALSE,
  342. NULL,
  343. &controlArray[0],
  344. 0,
  345. 1,
  346. &LdapMessage);
  347. if (Error == LDAP_SUCCESS) {
  348. Count = ldap_count_entries( LdapHandle, LdapMessage );
  349. if (Count > 0) {
  350. ldapEntry = ldap_first_entry( LdapHandle, LdapMessage );
  351. if (ldapEntry != NULL) {
  352. ldapFirstName = ldap_get_valuesW( LdapHandle,
  353. ldapEntry,
  354. L"givenName" );
  355. if (ldapFirstName != NULL &&
  356. *ldapFirstName != NULL &&
  357. **ldapFirstName != L'\0') {
  358. OscAddVariableW( clientState, "USERFIRSTNAME", *ldapFirstName );
  359. firstNameValid = TRUE;
  360. }
  361. ldapLastName = ldap_get_valuesW( LdapHandle,
  362. ldapEntry,
  363. L"sn" );
  364. if (ldapLastName != NULL &&
  365. *ldapLastName != NULL &&
  366. **ldapLastName != L'\0') {
  367. OscAddVariableW( clientState, "USERLASTNAME", *ldapLastName );
  368. lastNameValid = TRUE;
  369. }
  370. //
  371. // Now that we have first and last name, set the USERFULLNAME
  372. // if either is not empty.
  373. //
  374. if ((firstNameValid || lastNameValid) && (userFullNameSet == FALSE)) {
  375. ULONG userFullNameLength = 0;
  376. PWCHAR userFullName;
  377. if (firstNameValid) {
  378. userFullNameLength = (wcslen(*ldapFirstName) + 1) * sizeof(WCHAR);
  379. }
  380. if (lastNameValid) {
  381. if (firstNameValid) {
  382. userFullNameLength += sizeof(WCHAR); // for the space
  383. }
  384. userFullNameLength += (wcslen(*ldapLastName) + 1) * sizeof(WCHAR);
  385. }
  386. userFullName = BinlAllocateMemory(userFullNameLength);
  387. if (userFullName != NULL) {
  388. userFullName[0] = L'\0';
  389. if (firstNameValid) {
  390. wcscat(userFullName, *ldapFirstName);
  391. }
  392. if (lastNameValid) {
  393. if (firstNameValid) {
  394. wcscat(userFullName, L" ");
  395. }
  396. wcscat(userFullName, *ldapLastName);
  397. }
  398. OscAddVariableW( clientState, "USERFULLNAME", userFullName);
  399. BinlFreeMemory(userFullName);
  400. userFullNameSet = TRUE;
  401. }
  402. }
  403. ldapDisplayName = ldap_get_valuesW( LdapHandle,
  404. ldapEntry,
  405. L"displayName" );
  406. if (ldapDisplayName != NULL &&
  407. *ldapDisplayName != NULL &&
  408. **ldapDisplayName != L'\0') {
  409. OscAddVariableW( clientState, "USERDISPLAYNAME", *ldapDisplayName );
  410. if (!userFullNameSet) {
  411. OscAddVariableW( clientState, "USERFULLNAME", *ldapDisplayName );
  412. userFullNameSet = TRUE;
  413. }
  414. }
  415. ldapAccountName = ldap_get_valuesW( LdapHandle,
  416. ldapEntry,
  417. L"cn" );
  418. if (ldapAccountName != NULL &&
  419. *ldapAccountName != NULL &&
  420. **ldapAccountName != L'\0') {
  421. OscAddVariableW( clientState, "USERACCOUNTNAME", *ldapAccountName );
  422. if (!userFullNameSet) {
  423. OscAddVariableW( clientState, "USERFULLNAME", *ldapAccountName );
  424. userFullNameSet = TRUE;
  425. }
  426. }
  427. ldapUserDN = ldap_get_dnW( LdapHandle, ldapEntry );
  428. if (ldapUserDN != NULL) {
  429. explodedDN = ldap_explode_dnW( ldapUserDN, 0);
  430. if (explodedDN != NULL &&
  431. *explodedDN != NULL &&
  432. *(explodedDN+1) != NULL ) {
  433. //
  434. // if there's less than two components, we can't do
  435. // anything with this DN.
  436. //
  437. PWCHAR component;
  438. ULONG requiredSize = 1; // 1 for null terminator
  439. //
  440. // we now have an array of strings, each of which
  441. // is a component of the DN. This is the safe and
  442. // correct way to chop off the first element.
  443. //
  444. Count = 1;
  445. while ((component = explodedDN[Count++]) != NULL) {
  446. requiredSize += wcslen( component ) + 1; // 1 for the comma
  447. }
  448. dnUsersOU = BinlAllocateMemory( requiredSize * sizeof(WCHAR) );
  449. if (dnUsersOU != NULL) {
  450. wcscpy( dnUsersOU, explodedDN[1] );
  451. Count = 2;
  452. while ((component = explodedDN[Count++]) != NULL) {
  453. wcscat( dnUsersOU, L"," );
  454. wcscat( dnUsersOU, component );
  455. }
  456. OscAddVariableW( clientState, "USEROU", dnUsersOU );
  457. } else {
  458. BinlPrintDbg((DEBUG_ERRORS,
  459. "OscGetUserDetails: unable to allocate %lx for user OU\n",
  460. requiredSize * sizeof(WCHAR)));
  461. }
  462. }
  463. }
  464. }
  465. } else {
  466. LogLdapError( EVENT_WARNING_LDAP_SEARCH_ERROR,
  467. LdapGetLastError(),
  468. LdapHandle
  469. );
  470. }
  471. } else {
  472. LogLdapError( EVENT_WARNING_LDAP_SEARCH_ERROR,
  473. LdapGetLastError(),
  474. LdapHandle
  475. );
  476. }
  477. if (LdapMessage) {
  478. ldap_msgfree( LdapMessage );
  479. LdapMessage = NULL;
  480. }
  481. Error = ERROR_SUCCESS;
  482. exitGetUserDetails:
  483. if (dnUsersOU != NULL) {
  484. BinlFreeMemory( dnUsersOU );
  485. }
  486. if (explodedDN != NULL) {
  487. ldap_value_free( explodedDN );
  488. }
  489. if (ldapUserDN != NULL) {
  490. ldap_memfree( ldapUserDN );
  491. }
  492. if (ldapConfigContainer != NULL) {
  493. ldap_value_free( ldapConfigContainer );
  494. }
  495. if (ldapDomain != NULL) {
  496. ldap_value_free( ldapDomain );
  497. }
  498. if (ldapFirstName != NULL) {
  499. ldap_value_free( ldapFirstName );
  500. }
  501. if (ldapLastName != NULL) {
  502. ldap_value_free( ldapLastName );
  503. }
  504. if (ldapDisplayName != NULL) {
  505. ldap_value_free( ldapDisplayName );
  506. }
  507. if (ldapAccountName != NULL) {
  508. ldap_value_free( ldapAccountName );
  509. }
  510. if (impersonating) {
  511. OscRevert( clientState );
  512. }
  513. if (Filter != NULL) {
  514. BinlFreeMemory( Filter );
  515. }
  516. if (configContainer != NULL) {
  517. BinlFreeMemory( configContainer );
  518. }
  519. return Error;
  520. }
  521. DWORD
  522. OscCreateAccount(
  523. PCLIENT_STATE clientState,
  524. PCREATE_DATA CreateData
  525. )
  526. /*++
  527. Routine Description:
  528. This function creates an account for the client specified by
  529. RequestContext and writes the response in CreateData, which
  530. will be sent down to the client.
  531. It also creates the client's base image directory.
  532. Arguments:
  533. clientState - client state information
  534. CreateData - The block of data that will be sent down to the
  535. client if the account is successfully created.
  536. Return Value:
  537. None.
  538. --*/
  539. {
  540. DWORD Error;
  541. PWSTR pMachineName;
  542. PWSTR pMachineDN = NULL;
  543. PWSTR pMachineOU;
  544. PWSTR pServerName;
  545. PWSTR pInstallPath;
  546. WCHAR SetupPath[MAX_PATH];
  547. PWSTR pNameDollarSign;
  548. ULONG HostNameSize;
  549. UINT uSize;
  550. LPSTR pGuid;
  551. PWCHAR pStrings[3];
  552. MACHINE_INFO MachineInfo = { 0 };
  553. TraceFunc("OscCreateAccount( )\n");
  554. pMachineName = OscFindVariableW( clientState, "MACHINENAME" );
  555. pNameDollarSign = OscFindVariableW( clientState, "NETBIOSNAME" );
  556. //
  557. // Convert the GUID
  558. //
  559. pGuid = OscFindVariableA( clientState, "GUID" );
  560. Error = OscGuidToBytes( pGuid, MachineInfo.Guid );
  561. if ( Error != ERROR_SUCCESS )
  562. goto e0;
  563. if (clientState->fCreateNewAccount) {
  564. //
  565. // Create client's FQDN(DS)
  566. //
  567. pMachineOU = OscFindVariableW( clientState, "MACHINEOU" );
  568. BinlAssert( pMachineOU[0] != L'\0' );
  569. uSize = wcslen( pMachineName ) * sizeof(WCHAR)
  570. + wcslen( pMachineOU ) * sizeof(WCHAR)
  571. + sizeof(L"CN=,"); // includes terminating NULL char
  572. pMachineDN = (PWCHAR) BinlAllocateMemory( uSize );
  573. if ( !pMachineDN ) {
  574. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  575. goto e0;
  576. }
  577. wsprintf( pMachineDN, L"CN=%ws,%ws", pMachineName, pMachineOU );
  578. OscAddVariableW( clientState, "MACHINEDN", pMachineDN );
  579. } else {
  580. pMachineDN = OscFindVariableW( clientState, "MACHINEDN" );
  581. }
  582. //
  583. // Create the full setup path
  584. //
  585. pServerName = OscFindVariableW( clientState, "SERVERNAME");
  586. pInstallPath = OscFindVariableW( clientState, "INSTALLPATH");
  587. if (!pServerName || !pInstallPath ||
  588. (_snwprintf(SetupPath,
  589. MAX_PATH,
  590. L"\\\\%ws\\REMINST\\%ws",
  591. pServerName ,
  592. pInstallPath) < 0 )) {
  593. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  594. goto e0;
  595. }
  596. SetupPath[MAX_PATH-1] = L'\0';
  597. EnterCriticalSection( &gcsParameters );
  598. MachineInfo.HostName = BinlStrDupW(BinlGlobalOurDnsName );
  599. LeaveCriticalSection( &gcsParameters );
  600. if ( !MachineInfo.HostName ) {
  601. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  602. goto e0;
  603. }
  604. //
  605. // Fill in the rest of the MachineInfo structure
  606. //
  607. MachineInfo.Name = pMachineName;
  608. MachineInfo.MachineDN = pMachineDN;
  609. #if 1
  610. //
  611. // Don't store BOOTFILE in the cache/DS, since BOOTFILE points to setupldr
  612. // and we want the cache entry to point to oschooser. If we store an
  613. // empty string in the cache/DS, then GetBootParametersExt() will replace
  614. // that with the path to oschooser.
  615. //
  616. MachineInfo.BootFileName = L"";
  617. #else
  618. MachineInfo.BootFileName = OscFindVariableW( clientState, "BOOTFILE" );
  619. #endif
  620. MachineInfo.SetupPath = SetupPath;
  621. MachineInfo.SamName = pNameDollarSign;
  622. MachineInfo.Password = clientState->MachineAccountPassword;
  623. MachineInfo.PasswordLength = clientState->MachineAccountPasswordLength;
  624. MachineInfo.dwFlags = MI_NAME
  625. | MI_HOSTNAME
  626. | MI_BOOTFILENAME
  627. | MI_SETUPPATH
  628. | MI_SAMNAME
  629. | MI_PASSWORD
  630. | MI_MACHINEDN
  631. | MI_GUID;
  632. //
  633. // Create the MAO in the DS
  634. //
  635. Error = UpdateAccount( clientState,
  636. &MachineInfo,
  637. clientState->fCreateNewAccount ); // create it
  638. if ( Error ) {
  639. goto e0;
  640. }
  641. //
  642. // Create the response to the client
  643. //
  644. Error = OscConstructSecret(
  645. clientState,
  646. clientState->MachineAccountPassword,
  647. clientState->MachineAccountPasswordLength,
  648. CreateData );
  649. if ( Error != ERROR_SUCCESS ) {
  650. OscCreateWin32SubError( clientState, Error );
  651. Error = ERROR_BINL_FAILED_TO_INITIALIZE_CLIENT;
  652. goto e0;
  653. }
  654. BinlPrint(( DEBUG_OSC, "Successfully created account for <%ws>\n", pMachineName ));
  655. pStrings[0] = pMachineName;
  656. pStrings[1] = OscFindVariableW( clientState, "USERNAME" );
  657. BinlReportEventW( EVENT_COMPUTER_ACCOUNT_CREATED_SUCCESSFULLY,
  658. EVENTLOG_INFORMATION_TYPE,
  659. 2,
  660. 0,
  661. pStrings,
  662. 0 );
  663. e0:
  664. // No need to call FreeMachineInfo() since all the information
  665. // in it is either allocated on the stack or is referenced
  666. // by the clientState, but we do need to free the HostName
  667. // since it is allocated above.
  668. if ( MachineInfo.HostName ) {
  669. BinlFreeMemory( MachineInfo.HostName );
  670. }
  671. if ( pMachineDN && clientState->fCreateNewAccount ) {
  672. BinlFreeMemory( pMachineDN );
  673. }
  674. return Error;
  675. }
  676. //
  677. // CheckForDuplicateMachineName( )
  678. //
  679. DWORD
  680. CheckForDuplicateMachineName(
  681. PCLIENT_STATE clientState,
  682. LPWSTR pszMachineName )
  683. {
  684. DWORD Error = ERROR_SUCCESS;
  685. PLDAPMessage LdapMessage = NULL;
  686. WCHAR Filter[128];
  687. DWORD count;
  688. PWCHAR ComputerAttrs[2];
  689. LPWSTR pDomain = OscFindVariableW( clientState, "MACHINEOU" );
  690. PWCHAR BaseDN;
  691. PLDAP LdapHandle;
  692. ULONG ldapRetryLimit = 0;
  693. PWCHAR *gcBase;
  694. PLDAPControlW controlArray[2];
  695. LDAPControlW controlNoReferrals;
  696. ULONG noReferralsPlease;
  697. //
  698. // see if binl is already in the process of registering the name with the DS
  699. //
  700. if (IsQueuedDSName(pszMachineName)) {
  701. Error = -1; // signal multiple accounts
  702. goto exitCheck;
  703. }
  704. ComputerAttrs[0] = &L"cn";
  705. ComputerAttrs[1] = NULL;
  706. TraceFunc( "CheckForDuplicateMachineName( )\n" );
  707. if (pDomain[0] == L'\0') {
  708. pDomain = OscFindVariableW( clientState, "USERDOMAIN" );
  709. BinlPrintDbg((DEBUG_ERRORS, "CheckforDupMachine: couldn't find root domain, using user's domain %ws\n.", pDomain));
  710. }
  711. BaseDN = StrStrIW( pDomain, L"DC=" );
  712. if (BaseDN == NULL) {
  713. BaseDN = pDomain;
  714. }
  715. LdapHandle = clientState->AuthenticatedDCLdapHandle;
  716. BinlAssert( LdapHandle != NULL );
  717. //
  718. // According to the DS guys, it's not necessarily the case that CN is
  719. // equal to SamAccountName and the latter is the important one. It has
  720. // a dollar sign at the end, so we'll tack that on.
  721. //
  722. if (_snwprintf( Filter,
  723. sizeof(Filter)/sizeof(Filter[0]),
  724. L"(&(objectClass=Computer)(samAccountName=%ws$))",
  725. pszMachineName) < 0) {
  726. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  727. goto exitCheck;
  728. }
  729. Filter[(sizeof(Filter)/sizeof(Filter[0]))-1] = L'\0';
  730. //
  731. // we really don't want it to go chasing subordinate referrals over
  732. // the entire enterprise since we know what the domain is, therefore
  733. // limit it to only external referrals (for child domains).
  734. //
  735. noReferralsPlease = (ULONG)((ULONG_PTR) LDAP_CHASE_EXTERNAL_REFERRALS);
  736. controlNoReferrals.ldctl_oid = LDAP_CONTROL_REFERRALS_W;
  737. controlNoReferrals.ldctl_value.bv_len = sizeof(ULONG);
  738. controlNoReferrals.ldctl_value.bv_val = (PCHAR) &noReferralsPlease;
  739. controlNoReferrals.ldctl_iscritical = FALSE;
  740. controlArray[0] = &controlNoReferrals;
  741. controlArray[1] = NULL;
  742. Retry:
  743. Error = ldap_search_ext_s(LdapHandle,
  744. BaseDN,
  745. LDAP_SCOPE_SUBTREE,
  746. Filter,
  747. ComputerAttrs,
  748. FALSE,
  749. NULL,
  750. &controlArray[0],
  751. 0,
  752. 1,
  753. &LdapMessage);
  754. switch ( Error )
  755. {
  756. case LDAP_SUCCESS:
  757. break;
  758. case LDAP_BUSY:
  759. if (++ldapRetryLimit < LDAP_BUSY_LIMIT) {
  760. Sleep( LDAP_BUSY_DELAY );
  761. goto Retry;
  762. }
  763. // lack of break is on purpose.
  764. default:
  765. OscCreateLDAPSubError( clientState, Error );
  766. LogLdapError( EVENT_WARNING_LDAP_SEARCH_ERROR,
  767. Error,
  768. LdapHandle
  769. );
  770. BinlPrintDbg(( DEBUG_OSC_ERROR, "!!LdapError 0x%08x - Failed search to create machine name.\n", Error ));
  771. goto exitCheck;
  772. }
  773. count = ldap_count_entries( LdapHandle, LdapMessage );
  774. if ( count != 0 ) {
  775. Error = -1; // signal multiple accounts
  776. goto exitCheck;
  777. }
  778. ldap_msgfree( LdapMessage );
  779. LdapMessage = NULL;
  780. //
  781. // now we go check the GC.
  782. //
  783. gcBase = NULL;
  784. Error = InitializeConnection( TRUE, &LdapHandle, &gcBase );
  785. if ( Error != ERROR_SUCCESS ) {
  786. //
  787. // if no GC is present or available, we'll let this call succeed.
  788. // Reasoning here is GCs can be flaky creatures.
  789. //
  790. Error = ERROR_SUCCESS;
  791. goto exitCheck;
  792. }
  793. ldapRetryLimit = 0;
  794. RetryGC:
  795. Error = ldap_search_ext_s(LdapHandle,
  796. *gcBase,
  797. LDAP_SCOPE_SUBTREE,
  798. Filter,
  799. ComputerAttrs,
  800. FALSE,
  801. NULL,
  802. NULL,
  803. 0,
  804. 1,
  805. &LdapMessage);
  806. switch ( Error )
  807. {
  808. case LDAP_SUCCESS:
  809. break;
  810. case LDAP_BUSY:
  811. if (++ldapRetryLimit < LDAP_BUSY_LIMIT) {
  812. Sleep( LDAP_BUSY_DELAY );
  813. goto RetryGC;
  814. }
  815. // lack of break is on purpose.
  816. default:
  817. OscCreateLDAPSubError( clientState, Error );
  818. HandleLdapFailure( Error,
  819. EVENT_WARNING_LDAP_SEARCH_ERROR,
  820. TRUE,
  821. &LdapHandle,
  822. FALSE ); // don't have the lock
  823. BinlPrintDbg(( DEBUG_OSC_ERROR, "!!LdapError 0x%08x - Failed search to create machine name.\n", Error ));
  824. goto exitCheck;
  825. }
  826. count = ldap_count_entries( LdapHandle, LdapMessage );
  827. if ( count != 0 ) {
  828. Error = -1; // signal multiple accounts
  829. } else {
  830. Error = ERROR_SUCCESS;
  831. }
  832. exitCheck:
  833. if (LdapMessage) {
  834. ldap_msgfree( LdapMessage );
  835. }
  836. return Error;
  837. }
  838. //
  839. // GenerateMachineName( )
  840. //
  841. DWORD
  842. GenerateMachineName(
  843. PCLIENT_STATE clientState
  844. )
  845. {
  846. DWORD Error = ERROR_SUCCESS;
  847. GENNAME_VARIABLES variables;
  848. WCHAR szMachineName[ DNS_MAX_LABEL_BUFFER_LENGTH ];
  849. DWORD Count = 1;
  850. LPWSTR missingVariable;
  851. BOOL usedCounter;
  852. LPWSTR pszUserName;
  853. LPWSTR pszFirstName;
  854. LPWSTR pszLastName;
  855. LPWSTR pUserOU;
  856. LPWSTR pszMAC;
  857. TraceFunc( "GenerateMachineName( )\n" );
  858. pszUserName = OscFindVariableW( clientState, "USERNAME" );
  859. if ( pszUserName[0] == L'\0' ) {
  860. OscAddVariableA( clientState, "SUBERROR", "USERNAME" );
  861. return ERROR_BINL_MISSING_VARIABLE;
  862. }
  863. Error = OscGetUserDetails( clientState );
  864. if (Error != ERROR_SUCCESS) {
  865. BinlPrintDbg((DEBUG_OSC_ERROR,
  866. "GenerateMachineName: OscGetUserDetails failed %lx\n", Error));
  867. return Error;
  868. }
  869. pszFirstName = OscFindVariableW( clientState, "USERFIRSTNAME" );
  870. pszLastName = OscFindVariableW( clientState, "USERLASTNAME" );
  871. pUserOU = OscFindVariableW( clientState, "USEROU" );
  872. pszMAC = OscFindVariableW( clientState, "MAC" );
  873. variables.UserName = pszUserName;
  874. variables.FirstName = pszFirstName;
  875. variables.LastName = pszLastName;
  876. variables.MacAddress = pszMAC;
  877. variables.AllowCounterTruncation = FALSE;
  878. TryAgain:
  879. variables.Counter = ++clientState->nCreateAccountCounter;
  880. EnterCriticalSection( &gcsParameters );
  881. Error = GenerateNameFromTemplate(
  882. NewMachineNamingPolicy,
  883. &variables,
  884. szMachineName,
  885. DNS_MAX_LABEL_BUFFER_LENGTH,
  886. &missingVariable,
  887. &usedCounter,
  888. NULL
  889. );
  890. LeaveCriticalSection( &gcsParameters );
  891. if ( (Error != GENNAME_NO_ERROR) && (Error != GENNAME_NAME_TOO_LONG) ) {
  892. if ( Error == GENNAME_VARIABLE_MISSING ) {
  893. OscAddVariableW( clientState, "SUBERROR", missingVariable );
  894. clientState->nCreateAccountCounter = 0;
  895. return ERROR_BINL_MISSING_VARIABLE;
  896. }
  897. BinlAssert( (Error == GENNAME_COUNTER_TOO_HIGH) || (Error == GENNAME_TEMPLATE_INVALID) );
  898. clientState->nCreateAccountCounter = 0;
  899. return ERROR_BINL_UNABLE_TO_GENERATE_MACHINE_NAME;
  900. }
  901. BinlPrint(( DEBUG_OSC, "Generated MachineName = %ws\n", szMachineName ));
  902. //
  903. // grab the global lock so that we can synchronously find a unique name.
  904. // once we find a unique name, we then add it to the queued DS name list
  905. // to prevent another thread from attempting to register the same name
  906. //
  907. EnterCriticalSection( &gcsParameters );
  908. Error = CheckForDuplicateMachineName( clientState, szMachineName );
  909. if ( Error == -1 ) {
  910. if ( usedCounter ) {
  911. LeaveCriticalSection( &gcsParameters );
  912. goto TryAgain;
  913. }
  914. Error = ERROR_BINL_DUPLICATE_MACHINE_NAME_FOUND;
  915. LeaveCriticalSection( &gcsParameters );
  916. } else if ( Error == LDAP_SIZELIMIT_EXCEEDED ) {
  917. BinlPrint(( DEBUG_OSC, "MachineName '%s' has mutliple accounts already.\n", szMachineName ));
  918. if ( usedCounter ) {
  919. LeaveCriticalSection( &gcsParameters );
  920. goto TryAgain;
  921. }
  922. LeaveCriticalSection( &gcsParameters );
  923. } else if ( Error != LDAP_SUCCESS ) {
  924. Error = ERROR_BINL_UNABLE_TO_GENERATE_MACHINE_NAME;
  925. LeaveCriticalSection( &gcsParameters );
  926. } else {
  927. //
  928. // insert name into queued name list so another thread
  929. // fails the CheckForDuplicateMachineName if they try
  930. // to use the same name
  931. //
  932. Error = AddQueuedDSName(szMachineName);
  933. LeaveCriticalSection( &gcsParameters );
  934. if (Error == ERROR_SUCCESS) {
  935. BinlPrintDbg(( DEBUG_OSC, "MachineName: '%ws'\n", szMachineName ));
  936. Error = OscAddVariableW( clientState, "MACHINENAME", szMachineName );
  937. if ( Error == ERROR_SUCCESS ) {
  938. WCHAR NameDollarSign[17]; // MACHINENAME(15)+'$'+'\0'
  939. UINT uSize;
  940. clientState->fAutomaticMachineName = TRUE;
  941. uSize = sizeof(NameDollarSign);
  942. // DnsHostnameToComputerNameW takes BYTEs in and returns the # of WCHARs out.
  943. if ( !DnsHostnameToComputerNameW( szMachineName, NameDollarSign, &uSize ) ) {
  944. // if this fails(?), default to truncating machine name and
  945. // add '$' to the end
  946. BinlPrintDbg((DEBUG_OSC_ERROR, "!! Error 0x%08x - DnsHostnameToComputerNameW failed.\n", GetLastError() ));
  947. BinlPrintDbg((DEBUG_OSC, "WARNING: Truncating machine name to 15 characters to generated NETBIOS name.\n" ));
  948. memset( NameDollarSign, 0, sizeof(NameDollarSign) );
  949. wcsncpy( NameDollarSign, szMachineName, 15 );
  950. }
  951. wcscat( NameDollarSign, L"$");
  952. Error = OscAddVariableW( clientState, "NETBIOSNAME", NameDollarSign );
  953. }
  954. }
  955. }
  956. clientState->nCreateAccountCounter = 0;
  957. return Error;
  958. }
  959. DWORD
  960. OscCheckMachineDN(
  961. PCLIENT_STATE clientState
  962. )
  963. //
  964. // Ensure that the client name, OU, and domain are setup correctly. If there
  965. // are duplicate records in the DS with this same guid, we'll return
  966. // ERROR_BINL_DUPLICATE_MACHINE_NAME_FOUND and set %SUBERROR% string to
  967. // those DNs and return an error.
  968. //
  969. {
  970. DWORD dwErr = ERROR_SUCCESS;
  971. PWCHAR pwc; // parsing pointer
  972. WCHAR wch; // temp wide char
  973. PWCHAR pMachineName; // Pointer to Machine Name variable value
  974. PWCHAR pMachineOU; // Pointer to where the MAO will be created
  975. PWCHAR pDomain; // Pointer to Domain variable name
  976. PCHAR pGuid; // Pointer to Guid variable name
  977. WCHAR NameDollarSign[17]; // MACHINENAME(15)+'$'+'\0'
  978. WCHAR Path[MAX_PATH]; // general purpose path buffer
  979. ULONG i; // general counter
  980. BOOL b; // general purpose BOOLean.
  981. UINT uSize;
  982. UCHAR Guid[ BINL_GUID_LENGTH ];
  983. PMACHINE_INFO pMachineInfo = NULL;
  984. USHORT SystemArchitecture;
  985. DWORD DupRecordCount;
  986. TraceFunc("OscCheckMachineDN( )\n");
  987. if ( clientState->fHaveSetupMachineDN ) {
  988. // we've been through this logic before, just exit here with success.
  989. dwErr = ERROR_SUCCESS;
  990. goto e0;
  991. }
  992. dwErr = OscGetUserDetails( clientState );
  993. if (dwErr != ERROR_SUCCESS) {
  994. BinlPrintDbg((DEBUG_OSC_ERROR,
  995. "OscCheckMachineDN: OscGetUserDetails failed %lx\n", dwErr));
  996. goto e0;
  997. }
  998. pGuid = OscFindVariableA( clientState, "GUID" );
  999. if ( pGuid[0] == '\0' ) {
  1000. OscAddVariableA( clientState, "SUBERROR", "GUID" );
  1001. dwErr = ERROR_BINL_MISSING_VARIABLE;
  1002. goto e0;
  1003. }
  1004. dwErr = OscGuidToBytes( pGuid, Guid );
  1005. if ( dwErr != ERROR_SUCCESS ) {
  1006. goto e0;
  1007. }
  1008. // Do we have a machine name yet?
  1009. clientState->fCreateNewAccount = TRUE;
  1010. pMachineName = OscFindVariableW( clientState, "MACHINENAME" );
  1011. if ( pMachineName[0] == L'\0' ) {
  1012. clientState->CustomInstall = FALSE;
  1013. } else {
  1014. clientState->CustomInstall = TRUE;
  1015. }
  1016. clientState->fHaveSetupMachineDN = TRUE;
  1017. SystemArchitecture = OscPlatformToArchitecture(clientState);
  1018. //
  1019. // See if the client already has an account with a matching GUID
  1020. //
  1021. dwErr = GetBootParameters( Guid,
  1022. &pMachineInfo,
  1023. MI_NAME | MI_DOMAIN | MI_MACHINEDN,
  1024. SystemArchitecture,
  1025. FALSE );
  1026. if (( dwErr == ERROR_SUCCESS ) &&
  1027. ( !clientState->CustomInstall )) {
  1028. PWCHAR pszOU;
  1029. //
  1030. // Since we asked for these, they should be set.
  1031. //
  1032. ASSERT ( pMachineInfo->dwFlags & MI_NAME );
  1033. ASSERT ( pMachineInfo->dwFlags & MI_MACHINEDN );
  1034. //
  1035. // if this is an automatic install, then we simply set the
  1036. // account info to the account we found.
  1037. //
  1038. // skip the comma
  1039. pszOU = wcschr( pMachineInfo->MachineDN, L',' );
  1040. if (pszOU) {
  1041. pszOU++;
  1042. OscAddVariableW( clientState, "MACHINEOU", pszOU );
  1043. }
  1044. OscAddVariableW( clientState, "MACHINEDN", pMachineInfo->MachineDN );
  1045. dwErr = OscAddVariableW( clientState, "MACHINENAME", pMachineInfo->Name );
  1046. if ( dwErr != ERROR_SUCCESS ) {
  1047. BinlPrintDbg((DEBUG_OSC_ERROR,
  1048. "!!Error 0x%08x - OscCheckMachineDN: Unable to add MACHINENAME variable\n", dwErr ));
  1049. goto e0;
  1050. }
  1051. clientState->fCreateNewAccount = FALSE;
  1052. if ( pMachineInfo->dwFlags & MI_DOMAIN ) {
  1053. OscAddVariableW( clientState, "MACHINEDOMAIN", pMachineInfo->Domain );
  1054. }
  1055. }
  1056. //
  1057. // Do we have an OU yet?
  1058. //
  1059. pMachineOU = OscFindVariableW( clientState, "MACHINEOU" );
  1060. if ( pMachineOU[0] == L'\0' ) {
  1061. //
  1062. // Here's how we determine the OU...
  1063. //
  1064. // if this is an auto, then MACHINEOU shouldn't already have
  1065. // been set by now. If it's custom, then MACHINEOU may be empty
  1066. // or it may be set to what the user wants it set to.
  1067. //
  1068. // if it's not already set, then we look at BinlGlobalDefaultContainer.
  1069. //
  1070. // if this value is equal to the server's DN, then we set it to the
  1071. // default for this domain.
  1072. //
  1073. // if BinlGlobalDefaultContainer is empty, then we set it to the
  1074. // user's OU.
  1075. //
  1076. if ( BinlGlobalServerDN == NULL ) {
  1077. dwErr = ERROR_BINL_NO_DN_AVAILABLE_FOR_SERVER;
  1078. BinlPrintDbg((DEBUG_OSC_ERROR,
  1079. "!!Error - OscCheckMachineDN: BinlGlobalServerDN is null\n", dwErr ));
  1080. goto e0;
  1081. }
  1082. EnterCriticalSection( &gcsParameters );
  1083. if ( BinlGlobalServerDN &&
  1084. _wcsicmp( BinlGlobalDefaultContainer, BinlGlobalServerDN ) == 0) {
  1085. //
  1086. // If the machine's OU is the same as this server's OU, then we set
  1087. // it to the default for this server's domain.
  1088. //
  1089. PWCHAR pDomainDefault = StrStrIW( BinlGlobalServerDN, L"DC=" );
  1090. ULONG dwErrGetDefault;
  1091. if ( pDomainDefault ) {
  1092. dwErrGetDefault = OscGetDefaultContainerForDomain( clientState, pDomainDefault );
  1093. //
  1094. // spit out an error but keep going, we'll try the user's OU in a bit.
  1095. //
  1096. if (dwErrGetDefault != ERROR_SUCCESS) {
  1097. BinlPrintDbg(( DEBUG_OSC_ERROR, "Could not get default MACHINEOU, 0x%x\n",dwErrGetDefault));
  1098. }
  1099. }
  1100. } else {
  1101. dwErr = OscAddVariableW( clientState, "MACHINEOU", BinlGlobalDefaultContainer );
  1102. if ( dwErr != ERROR_SUCCESS ) {
  1103. LeaveCriticalSection( &gcsParameters );
  1104. BinlPrintDbg(( DEBUG_OSC_ERROR, "!!Error 0x%08x - Could not add MACHINEOU\n", dwErr ));
  1105. goto e0;
  1106. }
  1107. }
  1108. LeaveCriticalSection( &gcsParameters );
  1109. pMachineOU = OscFindVariableW( clientState, "MACHINEOU" );
  1110. if ( pMachineOU[0] == L'\0' ) {
  1111. LPWSTR pUserOU = OscFindVariableW( clientState, "USEROU" );
  1112. //
  1113. // the machine OU isn't already specified, that means we set it to
  1114. // the same as the user's OU.
  1115. //
  1116. if ( pUserOU[0] == L'\0' ) {
  1117. BinlPrintDbg(( DEBUG_OSC_ERROR, "Missing UserOU variable\n" ));
  1118. OscAddVariableA( clientState, "SUBERROR", "USEROU" );
  1119. dwErr = ERROR_BINL_MISSING_VARIABLE;
  1120. goto e0;
  1121. }
  1122. dwErr = OscAddVariableW( clientState, "MACHINEOU", pUserOU );
  1123. if ( dwErr != ERROR_SUCCESS ) {
  1124. BinlPrintDbg(( DEBUG_OSC_ERROR, "!!Error 0x%08x - Could not add MACHINEOU\n", dwErr ));
  1125. goto e0;
  1126. }
  1127. pMachineOU = OscFindVariableW( clientState, "MACHINEOU" );
  1128. }
  1129. }
  1130. //
  1131. // We need to generate the MACHINENAME after MACHINEOU because we need
  1132. // to know MACHINEOU to know which domain to check for duplicate
  1133. // machine names.
  1134. //
  1135. pMachineName = OscFindVariableW( clientState, "MACHINENAME" );
  1136. if ( pMachineName[0] == L'\0' ) {
  1137. dwErr = GenerateMachineName( clientState );
  1138. if ( dwErr != ERROR_SUCCESS ) {
  1139. BinlPrintDbg(( DEBUG_OSC_ERROR, "!!Error 0x%08x - Failed to generate machine name\n" ));
  1140. goto e0;
  1141. }
  1142. // now we should have one
  1143. pMachineName = OscFindVariableW( clientState, "MACHINENAME" );
  1144. }
  1145. BinlAssertMsg( pMachineName[0] != L'\0', "Missing MACHINENAME" );
  1146. uSize = sizeof(NameDollarSign);
  1147. // DnsHostnameToComputerNameW takes BYTEs in and returns the # of WCHARs out.
  1148. if ( !DnsHostnameToComputerNameW( pMachineName, NameDollarSign, &uSize ) )
  1149. {
  1150. // if this fails(?), default to truncating machine name and
  1151. // add '$' to the end
  1152. BinlPrintDbg((DEBUG_OSC_ERROR, "!! Error 0x%08x - DnsHostnameToComputerNameW failed.\n", GetLastError( ) ));
  1153. BinlPrintDbg((DEBUG_OSC, "WARNING: Truncating machine name to 15 characters to generated NETBIOS name.\n" ));
  1154. memset( NameDollarSign, 0, sizeof(NameDollarSign) );
  1155. wcsncpy( NameDollarSign, pMachineName, 15 );
  1156. // don't return the error...
  1157. }
  1158. wcscat( NameDollarSign, L"$");
  1159. OscAddVariableW( clientState, "NETBIOSNAME", NameDollarSign );
  1160. // Do we have a domain yet?
  1161. pDomain = OscFindVariableW( clientState, "MACHINEDOMAIN" );
  1162. if ( pDomain[0] == L'\0' ) {
  1163. // skip to the first "DC="
  1164. pDomain = StrStrIW( pMachineOU, L"DC=" );
  1165. if ( pDomain ) {
  1166. PDS_NAME_RESULTW pResults;
  1167. dwErr = DsCrackNames( INVALID_HANDLE_VALUE,
  1168. DS_NAME_FLAG_SYNTACTICAL_ONLY,
  1169. DS_FQDN_1779_NAME,
  1170. DS_CANONICAL_NAME,
  1171. 1,
  1172. &pDomain,
  1173. &pResults );
  1174. BinlAssertMsg( dwErr == ERROR_SUCCESS, "Error in DsCrackNames" );
  1175. if ( dwErr == ERROR_SUCCESS ) {
  1176. if ( pResults->cItems == 1
  1177. && pResults->rItems[0].status == DS_NAME_NO_ERROR
  1178. && pResults->rItems[0].pName ) { // paranoid
  1179. pResults->rItems[0].pName[wcslen(pResults->rItems[0].pName)-1] = L'\0';
  1180. OscAddVariableW( clientState, "MACHINEDOMAIN", pResults->rItems[0].pName );
  1181. }
  1182. DsFreeNameResult( pResults );
  1183. pDomain = OscFindVariableW( clientState, "MACHINEDOMAIN" );
  1184. } else {
  1185. pDomain = NULL;
  1186. }
  1187. }
  1188. }
  1189. // All else fails default to the servers
  1190. if ( !pDomain || pDomain[0] == '\0' )
  1191. {
  1192. OscAddVariableW( clientState,
  1193. "MACHINEDOMAIN",
  1194. OscFindVariableW( clientState, "SERVERDOMAIN" ) );
  1195. }
  1196. //
  1197. // check for duplicate accounts in the ds. fail if we find any, though
  1198. // we only fail after we have everything setup in case the user on
  1199. // custom install wants to ignore the error. For automatic, it's
  1200. // currently a fatal error but this could be changed in the osc screens.
  1201. //
  1202. if (( pMachineInfo != NULL ) &&
  1203. ( pMachineInfo->dwFlags & MI_MACHINEDN )) {
  1204. PDUP_GUID_DN dupDN;
  1205. PLIST_ENTRY listEntry;
  1206. if (( pMachineInfo->dwFlags & MI_NAME ) &&
  1207. ( clientState->CustomInstall )) {
  1208. //
  1209. // if this is a custom install, then we compare the account
  1210. // the user entered with all the existing accounts we found.
  1211. // We want to match both machine namd and OU (this is really
  1212. // just the DN but we have not necessarily constructed that
  1213. // yet).
  1214. //
  1215. // First we try the main entry in the cache, then all of
  1216. // the rest in the DNsWithSameGuid list.
  1217. //
  1218. // skip the comma
  1219. ULONG err;
  1220. PWCHAR MachineDNToUse;
  1221. PWCHAR pszOU = wcschr( pMachineInfo->MachineDN, L',' );
  1222. if (pszOU) {
  1223. pszOU++;
  1224. }
  1225. //
  1226. // See if the main machine name and OU in the cache
  1227. // entry match.
  1228. //
  1229. if ((CompareStringW(
  1230. LOCALE_SYSTEM_DEFAULT,
  1231. NORM_IGNORECASE,
  1232. pMachineName,
  1233. -1,
  1234. pMachineInfo->Name,
  1235. -1
  1236. ) != 2)
  1237. ||
  1238. ((pszOU == NULL) && (pMachineOU[0] != L'\0'))
  1239. ||
  1240. ((pszOU != NULL) &&
  1241. (CompareStringW(
  1242. LOCALE_SYSTEM_DEFAULT,
  1243. NORM_IGNORECASE,
  1244. pMachineOU,
  1245. -1,
  1246. pszOU,
  1247. -1
  1248. ) != 2))) {
  1249. //
  1250. // We did not match the main entry in the cache, so
  1251. // keep looking.
  1252. //
  1253. for (listEntry = pMachineInfo->DNsWithSameGuid.Flink;
  1254. listEntry != &pMachineInfo->DNsWithSameGuid;
  1255. listEntry = listEntry->Flink) {
  1256. dupDN = CONTAINING_RECORD(listEntry, DUP_GUID_DN, ListEntry);
  1257. pszOU = wcschr( &dupDN->DuplicateName[dupDN->DuplicateDNOffset], L',' );
  1258. if (pszOU) {
  1259. pszOU++;
  1260. }
  1261. if ((CompareStringW(
  1262. LOCALE_SYSTEM_DEFAULT,
  1263. NORM_IGNORECASE,
  1264. pMachineName,
  1265. -1,
  1266. dupDN->DuplicateName,
  1267. -1
  1268. ) != 2)
  1269. ||
  1270. ((pszOU == NULL) && (pMachineOU[0] != L'\0'))
  1271. ||
  1272. ((pszOU != NULL) &&
  1273. (CompareStringW(
  1274. LOCALE_SYSTEM_DEFAULT,
  1275. NORM_IGNORECASE,
  1276. pMachineOU,
  1277. -1,
  1278. pszOU,
  1279. -1
  1280. ) != 2))) {
  1281. //
  1282. // No match on this one.
  1283. //
  1284. continue;
  1285. } else {
  1286. //
  1287. // We found a match. Note which DN to use for
  1288. // this account.
  1289. //
  1290. MachineDNToUse = &dupDN->DuplicateName[dupDN->DuplicateDNOffset];
  1291. break;
  1292. }
  1293. }
  1294. //
  1295. // If we got to the end of our list with no match, jump to
  1296. // the error case.
  1297. //
  1298. if (listEntry == &pMachineInfo->DNsWithSameGuid) {
  1299. goto exitWithDupError;
  1300. }
  1301. } else {
  1302. //
  1303. // The main cache entry matched.
  1304. //
  1305. MachineDNToUse = pMachineInfo->MachineDN;
  1306. }
  1307. //
  1308. // We didn't jump to exitWithDupError above, so we found a match.
  1309. // we know that the client is using an existing account, let's
  1310. // mark the client state as such. this is the custom case.
  1311. //
  1312. clientState->fCreateNewAccount = FALSE;
  1313. OscAddVariableW( clientState, "MACHINEDN", MachineDNToUse );
  1314. if ( pMachineInfo->dwFlags & MI_DOMAIN ) {
  1315. OscAddVariableW( clientState, "MACHINEDOMAIN", pMachineInfo->Domain );
  1316. }
  1317. }
  1318. if (!IsListEmpty(&pMachineInfo->DNsWithSameGuid)) {
  1319. //
  1320. // if there's more than one account, we fill in SUBERROR
  1321. // with a list of the duplicates and return an error.
  1322. //
  1323. PWCHAR dnList;
  1324. ULONG requiredSize = 1; // 1 for null terminator
  1325. BOOL FreeDnList;
  1326. exitWithDupError:
  1327. //
  1328. // since we tack a <BR> to the end of each string, we'll account
  1329. // for it when we allocate the string as +4 from what we need.
  1330. //
  1331. #define MAX_DUPLICATE_RECORDS_TO_DISPLAY 4
  1332. requiredSize += wcslen( pMachineInfo->Name ) + (sizeof(L"<BR>")/sizeof(WCHAR));
  1333. listEntry = pMachineInfo->DNsWithSameGuid.Flink;
  1334. DupRecordCount = 0;
  1335. while (listEntry != &pMachineInfo->DNsWithSameGuid) {
  1336. dupDN = CONTAINING_RECORD(listEntry, DUP_GUID_DN, ListEntry);
  1337. listEntry = listEntry->Flink;
  1338. DupRecordCount += 1;
  1339. if (DupRecordCount <= MAX_DUPLICATE_RECORDS_TO_DISPLAY) {
  1340. requiredSize += wcslen( &dupDN->DuplicateName[0] ) + sizeof("<BR>");
  1341. } else if (DupRecordCount == MAX_DUPLICATE_RECORDS_TO_DISPLAY+1) {
  1342. requiredSize += sizeof( "..." ) + sizeof("<BR>");
  1343. }
  1344. }
  1345. dnList = BinlAllocateMemory( requiredSize * sizeof(WCHAR) );
  1346. DupRecordCount = 0;
  1347. if (dnList != NULL) {
  1348. ULONG nameLength;
  1349. nameLength = wcslen(pMachineInfo->Name);
  1350. FreeDnList = TRUE;
  1351. //
  1352. // The Name field should not end in a '$'.
  1353. //
  1354. ASSERT (!((nameLength > 1) && (pMachineInfo->Name[nameLength-1] == L'$')));
  1355. wcscpy( dnList, pMachineInfo->Name );
  1356. wcscat( dnList, L"<BR>" );
  1357. listEntry = pMachineInfo->DNsWithSameGuid.Flink;
  1358. while (listEntry != &pMachineInfo->DNsWithSameGuid) {
  1359. dupDN = CONTAINING_RECORD(listEntry, DUP_GUID_DN, ListEntry);
  1360. listEntry = listEntry->Flink;
  1361. DupRecordCount += 1;
  1362. if (DupRecordCount <= MAX_DUPLICATE_RECORDS_TO_DISPLAY) {
  1363. nameLength = wcslen(dupDN->DuplicateName);
  1364. //
  1365. // The DuplicateName field should not have the '$' either
  1366. //
  1367. ASSERT (!((nameLength > 1) && (dupDN->DuplicateName[nameLength-1] == L'$')));
  1368. wcscat( dnList, dupDN->DuplicateName );
  1369. wcscat( dnList, L"<BR>" );
  1370. } else if (DupRecordCount == MAX_DUPLICATE_RECORDS_TO_DISPLAY + 1) {
  1371. wcscat( dnList, L"..." );
  1372. wcscat( dnList, L"<BR>" );
  1373. }
  1374. }
  1375. } else {
  1376. FreeDnList = FALSE;
  1377. dnList = pMachineInfo->MachineDN;
  1378. }
  1379. OscAddVariableW( clientState, "SUBERROR", dnList );
  1380. if (FreeDnList) {
  1381. BinlFreeMemory( dnList );
  1382. }
  1383. dwErr = ERROR_BINL_DUPLICATE_MACHINE_NAME_FOUND;
  1384. }
  1385. } else {
  1386. //
  1387. // We must not exist in the DS yet so there cannot be a duplicate.
  1388. // set the error to successand return.
  1389. //
  1390. dwErr = ERROR_SUCCESS;
  1391. }
  1392. e0:
  1393. if ( pMachineInfo ) {
  1394. BinlDoneWithCacheEntry( pMachineInfo, FALSE );
  1395. }
  1396. return dwErr;
  1397. }
  1398. DWORD
  1399. OscGetDefaultContainerForDomain (
  1400. PCLIENT_STATE clientState,
  1401. PWCHAR DomainDN
  1402. )
  1403. {
  1404. PLDAP LdapHandle;
  1405. PLDAPMessage LdapMessage = NULL;
  1406. PWCHAR ldapAttributes[2];
  1407. BOOLEAN impersonating = FALSE;
  1408. PLDAPMessage ldapEntry;
  1409. PWCHAR *ldapWellKnownObjectValues = NULL;
  1410. PWCHAR objectValue;
  1411. PWCHAR guidEnd;
  1412. WCHAR savedChar;
  1413. ULONG Error = LDAP_NO_SUCH_ATTRIBUTE;
  1414. ULONG Count;
  1415. if (clientState->AuthenticatedDCLdapHandle == NULL) {
  1416. Error = OscImpersonate(clientState);
  1417. if (Error != ERROR_SUCCESS) {
  1418. BinlPrintDbg((DEBUG_ERRORS,
  1419. "OscGetDefaultContainer: OscImpersonate failed %lx\n", Error));
  1420. return Error;
  1421. }
  1422. impersonating = TRUE;
  1423. BinlAssert( clientState->AuthenticatedDCLdapHandle != NULL );
  1424. }
  1425. LdapHandle = clientState->AuthenticatedDCLdapHandle;
  1426. //
  1427. // we look up the wellKnownObjects in the root of the domain
  1428. //
  1429. ldapAttributes[0] = L"wellKnownObjects";
  1430. ldapAttributes[1] = NULL;
  1431. Error = ldap_search_ext_sW(LdapHandle,
  1432. DomainDN,
  1433. LDAP_SCOPE_BASE,
  1434. L"objectclass=*",
  1435. ldapAttributes,
  1436. FALSE,
  1437. NULL,
  1438. NULL,
  1439. 0,
  1440. 0,
  1441. &LdapMessage);
  1442. if (Error == LDAP_SUCCESS) {
  1443. Count = ldap_count_entries( LdapHandle, LdapMessage );
  1444. } else {
  1445. Count = 0;
  1446. }
  1447. Error = LDAP_NO_SUCH_ATTRIBUTE;
  1448. if (Count == 0) {
  1449. BinlPrintDbg((DEBUG_ERRORS,
  1450. "OscGetDefaultContainer: get default domain failed with no records found\n"));
  1451. LogLdapError( EVENT_WARNING_LDAP_SEARCH_ERROR,
  1452. Error,
  1453. LdapHandle
  1454. );
  1455. goto exitGetDefaultContainer;
  1456. }
  1457. ldapEntry = ldap_first_entry( LdapHandle, LdapMessage );
  1458. if (ldapEntry == NULL) {
  1459. BinlPrintDbg((DEBUG_ERRORS,
  1460. "OscGetDefaultContainer: get first entry failed\n"));
  1461. goto exitGetDefaultContainer;
  1462. }
  1463. ldapWellKnownObjectValues = ldap_get_valuesW( LdapHandle,
  1464. ldapEntry,
  1465. L"wellKnownObjects" );
  1466. if (ldapWellKnownObjectValues == NULL) {
  1467. BinlPrintDbg((DEBUG_ERRORS,"OscGetDefaultContainer: get value failed\n"));
  1468. goto exitGetDefaultContainer;
  1469. }
  1470. Count = 0;
  1471. objectValue = NULL;
  1472. while (1) {
  1473. objectValue = ldapWellKnownObjectValues[Count++];
  1474. if (objectValue == NULL) {
  1475. break;
  1476. }
  1477. //
  1478. // the structure of this particular field is :
  1479. // L"B:32:GUID:DN" where GUID is AA312825768811D1ADED00C04FD8D5CD
  1480. //
  1481. if (wcslen( objectValue ) <
  1482. (sizeof( COMPUTER_DEFAULT_CONTAINER_IN_B32_FORM )/sizeof(WCHAR)) -1 ) {
  1483. continue;
  1484. }
  1485. //
  1486. // see if it matches "B:32:specialGuid:" then DN follows
  1487. //
  1488. guidEnd = objectValue + (sizeof( COMPUTER_DEFAULT_CONTAINER_IN_B32_FORM )/sizeof(WCHAR))-1;
  1489. savedChar = *guidEnd;
  1490. *guidEnd = L'\0';
  1491. if (_wcsicmp( objectValue, COMPUTER_DEFAULT_CONTAINER_IN_B32_FORM) != 0) {
  1492. *guidEnd = savedChar;
  1493. continue;
  1494. }
  1495. *guidEnd = savedChar; // this is the first character of the DN
  1496. //
  1497. // we have our value, now copy it off.
  1498. //
  1499. OscAddVariableW( clientState, "MACHINEOU", guidEnd );
  1500. Error = ERROR_SUCCESS;
  1501. break;
  1502. }
  1503. exitGetDefaultContainer:
  1504. if (ldapWellKnownObjectValues) {
  1505. ldap_value_free( ldapWellKnownObjectValues );
  1506. }
  1507. if (LdapMessage) {
  1508. ldap_msgfree( LdapMessage );
  1509. }
  1510. if (impersonating) {
  1511. OscRevert( clientState );
  1512. }
  1513. return Error;
  1514. }
  1515. VOID
  1516. LogLdapError (
  1517. ULONG LdapEvent,
  1518. ULONG LdapError,
  1519. PLDAP LdapHandle OPTIONAL
  1520. )
  1521. {
  1522. PWCHAR Server = NULL;
  1523. if (LdapError != LDAP_SUCCESS) {
  1524. if (LdapHandle != NULL) {
  1525. ldap_get_option( LdapHandle, LDAP_OPT_HOST_NAME, &Server );
  1526. }
  1527. if (++BinlGlobalLdapErrorCount <= BinlGlobalMaxLdapErrorsLogged) {
  1528. PWCHAR strings[2];
  1529. if (Server) {
  1530. strings[0] = Server;
  1531. } else {
  1532. strings[0] = L"?";
  1533. }
  1534. strings[1] = NULL;
  1535. BinlReportEventW( LdapEvent,
  1536. EVENTLOG_WARNING_TYPE,
  1537. (Server != NULL) ? 1 : 0,
  1538. sizeof(LdapError),
  1539. (Server != NULL) ? strings : NULL,
  1540. &LdapError
  1541. );
  1542. }
  1543. }
  1544. return;
  1545. }
  1546. DWORD
  1547. MyGetDcHandle(
  1548. PCLIENT_STATE clientState,
  1549. PCSTR DomainName,
  1550. PHANDLE Handle
  1551. )
  1552. {
  1553. DWORD Error;
  1554. HANDLE hDC;
  1555. PDOMAIN_CONTROLLER_INFOA DCI = NULL;
  1556. DWORD impersonateError = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1557. BinlPrintDbg((
  1558. DEBUG_OSC,
  1559. "Attempting discovery of DC in %s domain.\n",
  1560. DomainName ));
  1561. Error = DsGetDcNameA(
  1562. NULL,
  1563. DomainName,
  1564. NULL,
  1565. NULL,
  1566. DS_IS_DNS_NAME | DS_RETURN_DNS_NAME,
  1567. &DCI);
  1568. if (Error == ERROR_SUCCESS) {
  1569. BinlPrintDbg((
  1570. DEBUG_OSC,
  1571. "DC is %s, attempting bind.\n",
  1572. DCI->DomainControllerName ));
  1573. impersonateError = OscImpersonate(clientState);
  1574. Error = DsBindA(DCI->DomainControllerName, NULL, &hDC);
  1575. if (Error != ERROR_SUCCESS) {
  1576. BinlPrintDbg((
  1577. DEBUG_OSC_ERROR,
  1578. "DsBind failed, ec = %d.\n",
  1579. Error ));
  1580. } else {
  1581. PSTR p = DCI->DomainControllerName;
  1582. *Handle = hDC;
  1583. //
  1584. // if it's got '\\' in the front, then strip those
  1585. // off because ldap_init hates them
  1586. //
  1587. while (*p == '\\') {
  1588. p = p + 1;
  1589. }
  1590. OscAddVariableA( clientState, "DCNAME", p );
  1591. }
  1592. NetApiBufferFree(DCI);
  1593. } else {
  1594. BinlPrintDbg((
  1595. DEBUG_OSC_ERROR,
  1596. "DsGetDcNameA failed, ec = %d.\n",
  1597. Error ));
  1598. }
  1599. if (impersonateError == ERROR_SUCCESS) {
  1600. OscRevert(clientState);
  1601. }
  1602. return(Error);
  1603. }
  1604. DWORD
  1605. AddQueuedDSName(
  1606. PWCHAR Name
  1607. )
  1608. /*++
  1609. description:
  1610. this routine ADDS a name to the queued ds name list.
  1611. args:
  1612. Name - queued DS Name to add
  1613. return:
  1614. status
  1615. --*/
  1616. {
  1617. DWORD Error = ERROR_SUCCESS;
  1618. PQUEUED_DS_NAME_NODE queuedDSName;
  1619. PLIST_ENTRY ListEntry;
  1620. ULONG ListEntrySize;
  1621. do {
  1622. //
  1623. //
  1624. //
  1625. ListEntrySize = sizeof(QUEUED_DS_NAME_NODE);
  1626. ListEntrySize += (wcslen(Name) + 1) * sizeof(WCHAR);
  1627. ListEntry = BinlAllocateMemory( ListEntrySize );
  1628. if (ListEntry == NULL) {
  1629. Error = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1630. break;
  1631. }
  1632. queuedDSName = CONTAINING_RECORD(ListEntry, QUEUED_DS_NAME_NODE, ListEntry);
  1633. wcscpy(queuedDSName->Name, Name);
  1634. //
  1635. //
  1636. //
  1637. EnterCriticalSection( &QueuedDSNamesCriticalSection );
  1638. InsertTailList(&QueuedDSNamesList, ListEntry);
  1639. LeaveCriticalSection( &QueuedDSNamesCriticalSection );
  1640. } while ( FALSE );
  1641. if (Error != ERROR_SUCCESS) {
  1642. if (ListEntry) {
  1643. BinlFreeMemory(ListEntry);
  1644. }
  1645. }
  1646. return Error;
  1647. }
  1648. PLIST_ENTRY
  1649. FindQueuedDSName(
  1650. PWCHAR Name
  1651. )
  1652. /*++
  1653. description:
  1654. this routine attempts to find a name in the queued ds name list.
  1655. note: this routine assumes that the global list lock is held
  1656. by the caller
  1657. args:
  1658. Name - queued DS Name to find
  1659. return:
  1660. if found, pointer to listEntry is returned.
  1661. else NULL
  1662. --*/
  1663. {
  1664. PQUEUED_DS_NAME_NODE queuedDSName;
  1665. PLIST_ENTRY listEntry;
  1666. int compare;
  1667. BOOL found;
  1668. found = FALSE;
  1669. for (listEntry = QueuedDSNamesList.Flink;
  1670. listEntry != &QueuedDSNamesList;
  1671. listEntry = listEntry->Flink) {
  1672. queuedDSName = CONTAINING_RECORD(listEntry, QUEUED_DS_NAME_NODE, ListEntry);
  1673. compare = CompareStringW(
  1674. LOCALE_SYSTEM_DEFAULT,
  1675. NORM_IGNORECASE,
  1676. Name,
  1677. -1,
  1678. queuedDSName->Name,
  1679. -1
  1680. );
  1681. if (compare == CSTR_EQUAL) {
  1682. found = TRUE;
  1683. break;
  1684. }
  1685. }
  1686. if (!found) {
  1687. listEntry = NULL;
  1688. }
  1689. return listEntry;
  1690. }
  1691. DWORD
  1692. RemoveQueuedDSName(
  1693. PWCHAR Name
  1694. )
  1695. /*++
  1696. description:
  1697. this routine REMOVES a name to the queued ds name list.
  1698. args:
  1699. Name - queued DS Name to remove
  1700. return:
  1701. status
  1702. --*/
  1703. {
  1704. DWORD Error = ERROR_SUCCESS;
  1705. PLIST_ENTRY ListEntry;
  1706. do {
  1707. //
  1708. //
  1709. //
  1710. EnterCriticalSection( &QueuedDSNamesCriticalSection );
  1711. ListEntry = FindQueuedDSName(Name);
  1712. if (ListEntry == NULL) {
  1713. Error = ERROR_NOT_FOUND;
  1714. break;
  1715. }
  1716. //
  1717. //
  1718. //
  1719. RemoveEntryList(ListEntry);
  1720. } while ( FALSE );
  1721. LeaveCriticalSection( &QueuedDSNamesCriticalSection );
  1722. //
  1723. //
  1724. //
  1725. if (Error == ERROR_SUCCESS) {
  1726. BinlAssert( ListEntry != NULL );
  1727. BinlFreeMemory(ListEntry);
  1728. }
  1729. return Error;
  1730. }
  1731. BOOL
  1732. IsQueuedDSName(
  1733. PWCHAR Name
  1734. )
  1735. /*++
  1736. description:
  1737. this routine determines if a name exits in the queued ds name list.
  1738. args:
  1739. Name - queued DS Name to find
  1740. return:
  1741. status
  1742. --*/
  1743. {
  1744. BOOL bFound;
  1745. PLIST_ENTRY ListEntry;
  1746. bFound = FALSE;
  1747. //
  1748. //
  1749. //
  1750. EnterCriticalSection( &QueuedDSNamesCriticalSection );
  1751. ListEntry = FindQueuedDSName(Name);
  1752. if (ListEntry != NULL) {
  1753. bFound = TRUE;
  1754. }
  1755. LeaveCriticalSection( &QueuedDSNamesCriticalSection );
  1756. return bFound;
  1757. }
  1758. VOID
  1759. FreeQueuedDSNameList(
  1760. VOID
  1761. )
  1762. /*++
  1763. description:
  1764. this routine any entries in the Queued DS Name list
  1765. args:
  1766. None
  1767. return:
  1768. None
  1769. --*/
  1770. {
  1771. PLIST_ENTRY listEntry;
  1772. EnterCriticalSection( &QueuedDSNamesCriticalSection );
  1773. while(! IsListEmpty(&QueuedDSNamesList)) {
  1774. listEntry = RemoveHeadList(&QueuedDSNamesList);
  1775. BinlFreeMemory(listEntry);
  1776. }
  1777. BinlAssert(IsListEmpty(&QueuedDSNamesList));
  1778. LeaveCriticalSection( &QueuedDSNamesCriticalSection );
  1779. }