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

2046 lines
54 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. dsgroups.cpp
  5. Abstract:
  6. Routines to configure/analyze groups in DS
  7. Author:
  8. Jin Huang (jinhuang) 7-Nov-1996
  9. --*/
  10. #include "headers.h"
  11. #include "serverp.h"
  12. #include <io.h>
  13. #include <lm.h>
  14. #include <lmcons.h>
  15. #include <lmapibuf.h>
  16. #pragma hdrstop
  17. //
  18. // LDAP handle
  19. //
  20. PLDAP Thread pGrpLDAP = NULL;
  21. HANDLE Thread hDS = NULL;
  22. HINSTANCE Thread hNtdsApi = NULL;
  23. #define SCEGRP_MEMBERS 1
  24. #define SCEGRP_MEMBERSHIP 2
  25. #if _WIN32_WINNT>=0x0500
  26. typedef DWORD (WINAPI *PFNDSBIND) (TCHAR *, TCHAR *, HANDLE *);
  27. typedef DWORD (WINAPI *PFNDSUNBIND) (HANDLE *);
  28. typedef DWORD (WINAPI *PFNDSCRACKNAMES) ( HANDLE, DS_NAME_FLAGS, DS_NAME_FORMAT, \
  29. DS_NAME_FORMAT, DWORD, LPTSTR *, PDS_NAME_RESULT *);
  30. typedef void (WINAPI *PFNDSFREENAMERESULT) (DS_NAME_RESULT *);
  31. DWORD
  32. ScepDsConfigGroupMembers(
  33. IN PSCE_OBJECT_LIST pRoots,
  34. IN PWSTR GroupName,
  35. IN OUT DWORD *pStatus,
  36. IN PSCE_NAME_LIST pMembers,
  37. IN PSCE_NAME_LIST pMemberOf,
  38. IN OUT DWORD *nGroupCount
  39. );
  40. DWORD
  41. ScepDsGetDsNameList(
  42. IN PSCE_NAME_LIST pNameList,
  43. OUT PSCE_NAME_LIST *pRealNames
  44. );
  45. DWORD
  46. ScepDsCompareNames(
  47. IN PWSTR *Values,
  48. IN OUT PSCE_NAME_LIST *pAddList,
  49. OUT PSCE_NAME_LIST *pDeleteList OPTIONAL
  50. );
  51. DWORD
  52. ScepDsChangeMembers(
  53. IN ULONG Flag,
  54. IN PWSTR RealGroupName,
  55. IN PSCE_NAME_LIST pAddList OPTIONAL,
  56. IN PSCE_NAME_LIST pDeleteList OPTIONAL
  57. );
  58. DWORD
  59. ScepDsAnalyzeGroupMembers(
  60. IN LSA_HANDLE LsaPolicy,
  61. IN PSCE_OBJECT_LIST pRoots,
  62. IN PWSTR GroupName,
  63. IN PWSTR KeyName,
  64. IN DWORD KeyLen,
  65. IN OUT DWORD *pStatus,
  66. IN PSCE_NAME_LIST pMembers,
  67. IN PSCE_NAME_LIST pMemberOf,
  68. IN OUT DWORD *nGroupCount
  69. );
  70. DWORD
  71. ScepDsMembersDifferent(
  72. IN ULONG Flag,
  73. IN PWSTR *Values,
  74. IN OUT PSCE_NAME_LIST *pNameList,
  75. OUT PSCE_NAME_LIST *pCurrentList,
  76. OUT PBOOL pbDifferent
  77. );
  78. PWSTR
  79. ScepGetLocalAdminsName();
  80. DWORD
  81. ScepDsConvertDsNameList(
  82. IN OUT PSCE_NAME_LIST pDsNameList
  83. );
  84. //
  85. // helpers
  86. //
  87. SCESTATUS
  88. ScepCrackOpen(
  89. OUT HANDLE *phDS
  90. )
  91. {
  92. if ( !phDS ) {
  93. return(SCESTATUS_INVALID_PARAMETER);
  94. }
  95. DWORD Win32rc;
  96. *phDS = NULL;
  97. hNtdsApi = LoadLibrary(TEXT("ntdsapi.dll"));
  98. if ( hNtdsApi == NULL ) {
  99. return (SCESTATUS_MOD_NOT_FOUND);
  100. }
  101. PFNDSBIND pfnDsBind;
  102. PFNDSUNBIND pfnDsUnBind;
  103. #if defined(UNICODE)
  104. pfnDsBind = (PFNDSBIND)GetProcAddress(hNtdsApi, "DsBindW");
  105. pfnDsUnBind = (PFNDSUNBIND)GetProcAddress(hNtdsApi, "DsUnBindW");
  106. #else
  107. pfnDsBind = (PFNDSBIND)GetProcAddress(hNtdsApi, "DsBindA");
  108. pfnDsUnBind = (PFNDSUNBIND)GetProcAddress(hNtdsApi, "DsUnBindA");
  109. #endif
  110. if ( pfnDsBind == NULL || pfnDsUnBind == NULL ) {
  111. return(SCESTATUS_MOD_NOT_FOUND);
  112. }
  113. Win32rc = (*pfnDsBind) (
  114. NULL,
  115. NULL,
  116. phDS);
  117. if ( Win32rc != ERROR_SUCCESS ) {
  118. ScepLogOutput3(3, Win32rc, IDS_ERROR_BIND, L"the GC");
  119. }
  120. return(ScepDosErrorToSceStatus(Win32rc));
  121. }
  122. SCESTATUS
  123. ScepCrackClose(
  124. IN HANDLE *phDS
  125. )
  126. {
  127. if ( hNtdsApi ) {
  128. if ( phDS ) {
  129. PFNDSUNBIND pfnDsUnBind;
  130. #if defined(UNICODE)
  131. pfnDsUnBind = (PFNDSUNBIND)GetProcAddress(hNtdsApi, "DsUnBindW");
  132. #else
  133. pfnDsUnBind = (PFNDSUNBIND)GetProcAddress(hNtdsApi, "DsUnBindA");
  134. #endif
  135. if ( pfnDsUnBind ) {
  136. (*pfnDsUnBind) (phDS);
  137. }
  138. }
  139. FreeLibrary(hNtdsApi);
  140. hNtdsApi = NULL;
  141. }
  142. return(SCESTATUS_SUCCESS);
  143. }
  144. #endif
  145. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  146. //
  147. // Functions to configure group membership in DS
  148. //
  149. //
  150. //
  151. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  152. SCESTATUS
  153. ScepConfigDsGroups(
  154. IN OUT PSCE_GROUP_MEMBERSHIP pGroupMembership,
  155. IN DWORD ConfigOptions
  156. )
  157. /* ++
  158. Routine Description:
  159. Configure the ds group membership. The main difference of ds groups
  160. from NT4 groups is that now group can be a member of another group.
  161. Members in the group are configured exactly as the pMembers list in
  162. the restricted group. The group is only validated (added) as a member
  163. of the MemberOf group list. Other existing members in those groups
  164. won't be removed.
  165. The restricted groups are specified in the SCP profile by group name.
  166. It could be a global group, or a alias (no difference in NT5 DS),
  167. but must be defined in the local domain.
  168. Arguments:
  169. pGroupMembership - The restricted group list with members/memberof info to configure
  170. ConfigOptions - options passed in for the configuration
  171. Return value:
  172. SCESTATUS error codes
  173. ++ */
  174. {
  175. #if _WIN32_WINNT<0x0500
  176. return(SCESTATUS_SUCCESS);
  177. #else
  178. if ( pGroupMembership == NULL ) {
  179. ScepPostProgress(TICKS_GROUPS,
  180. AREA_GROUP_MEMBERSHIP,
  181. NULL);
  182. return(SCESTATUS_SUCCESS);
  183. }
  184. SCESTATUS rc;
  185. //
  186. // open the Ldap server, should open two ldap server, one for the local domain
  187. // the other is for the global search (for members, membership)
  188. //
  189. rc = ScepLdapOpen(&pGrpLDAP);
  190. if ( rc == SCESTATUS_SUCCESS ) {
  191. rc = ScepCrackOpen(&hDS);
  192. }
  193. if ( rc == SCESTATUS_SUCCESS ) {
  194. //
  195. // get the root of the domain
  196. //
  197. PSCE_OBJECT_LIST pRoots=NULL;
  198. rc = ScepEnumerateDsObjectRoots(
  199. pGrpLDAP,
  200. &pRoots
  201. );
  202. if ( rc == SCESTATUS_SUCCESS ) {
  203. PSCE_GROUP_MEMBERSHIP pGroup;
  204. DWORD Win32rc;
  205. DWORD rc32=NO_ERROR; // the saved status
  206. BOOL bAdminFound=FALSE;
  207. DWORD nGroupCount=0;
  208. //
  209. // configure each group
  210. //
  211. for ( pGroup=pGroupMembership; pGroup != NULL; pGroup=pGroup->Next ) {
  212. //
  213. // if both members and memberof are not defined for the group
  214. // we don't need to do anything for the group
  215. //
  216. if ( ( pGroup->Status & SCE_GROUP_STATUS_NC_MEMBERS ) &&
  217. ( pGroup->Status & SCE_GROUP_STATUS_NC_MEMBEROF ) ) {
  218. continue;
  219. }
  220. //
  221. // if within policy propagation and a system shutdown
  222. // is requested, we need to quit as soon as possible
  223. //
  224. if ( (ConfigOptions & SCE_POLICY_TEMPLATE) &&
  225. ScepIsSystemShutDown() ) {
  226. rc = SCESTATUS_SERVICE_NOT_SUPPORT;
  227. break;
  228. }
  229. LPTSTR pTemp = wcschr(pGroup->GroupName, L'\\');
  230. if ( pTemp ) {
  231. //
  232. // there is a domain name, check it with computer name
  233. // to determine if the account is local
  234. //
  235. UNICODE_STRING uName;
  236. uName.Buffer = pGroup->GroupName;
  237. uName.Length = ((USHORT)(pTemp-pGroup->GroupName))*sizeof(TCHAR);
  238. if ( !ScepIsDomainLocal(&uName) ) {
  239. //
  240. // non local groups are not supported for the configuration
  241. //
  242. ScepLogOutput3(1, 0, SCEDLL_NO_MAPPINGS, pGroup->GroupName);
  243. rc = SCESTATUS_INVALID_DATA;
  244. pGroup->Status |= SCE_GROUP_STATUS_DONE_IN_DS;
  245. continue;
  246. }
  247. pTemp++;
  248. } else {
  249. pTemp = pGroup->GroupName;
  250. }
  251. //
  252. // local groups will be handled outside (in SAM)
  253. // find the group (validate) in this domain
  254. //
  255. Win32rc = ScepDsConfigGroupMembers(
  256. pRoots,
  257. pTemp, // pGroup->GroupName,
  258. &(pGroup->Status),
  259. pGroup->pMembers,
  260. pGroup->pMemberOf,
  261. &nGroupCount
  262. );
  263. if ( Win32rc != ERROR_SUCCESS &&
  264. (pGroup->Status & SCE_GROUP_STATUS_DONE_IN_DS) ) {
  265. //
  266. // the group should be handled by the DS function
  267. // but it failed.
  268. //
  269. ScepLogOutput3(1,Win32rc, SCEDLL_SCP_ERROR_CONFIGURE, pGroup->GroupName);
  270. rc32 = Win32rc;
  271. if ( Win32rc == ERROR_FILE_NOT_FOUND ||
  272. Win32rc == ERROR_SHARING_VIOLATION ||
  273. Win32rc == ERROR_ACCESS_DENIED ) {
  274. Win32rc = ERROR_SUCCESS;
  275. } else
  276. break;
  277. }
  278. }
  279. if ( rc32 != NO_ERROR ) {
  280. rc = ScepDosErrorToSceStatus(rc32);
  281. }
  282. //
  283. // free the root DN buffer
  284. //
  285. ScepFreeObjectList(pRoots);
  286. }
  287. }
  288. if ( pGrpLDAP ) {
  289. ScepLdapClose(&pGrpLDAP);
  290. pGrpLDAP = NULL;
  291. }
  292. ScepCrackClose(&hDS);
  293. hDS = NULL;
  294. //
  295. // ticks will be called within ConfigureGroupMembership, so ignore it here
  296. //
  297. return(rc);
  298. #endif
  299. }
  300. #if _WIN32_WINNT>=0x0500
  301. DWORD
  302. ScepDsConfigGroupMembers(
  303. IN PSCE_OBJECT_LIST pRoots,
  304. IN PWSTR GroupName,
  305. IN OUT DWORD *pStatus,
  306. IN PSCE_NAME_LIST pMembers,
  307. IN PSCE_NAME_LIST pMemberOf,
  308. IN OUT DWORD *nGroupCount
  309. )
  310. /*
  311. Description:
  312. Configure group membership (members and Memberof) of a group, specified by
  313. GroupName.
  314. The group membership is configured using ldap based on info stored in DS.
  315. Since foreign wellknown principals may not be present in the Active
  316. Directory, this function cannot configure membership with well known
  317. principals.
  318. Global groups and Universal groups cannot have wellknown pricipals as
  319. members (or memberof) but local groups (such as builtin groups) can. In
  320. order to solve this problem, local groups are configured using the old
  321. SAM apis outside of this function. This function only configures global
  322. and Universal group defined in the local domain. If the group is a
  323. global or universal group, the pStatus parameter will be marked to
  324. indicate the group is processed by this function (SCE_GROUP_STATUS_DONE_IN_DS)
  325. so the old SAM function can skip it.
  326. Arguments:
  327. pRoots - contains the local domain's base DN
  328. GroupName - the group name to configure
  329. pStatus - the status of the group (such as member defined, memberof defined, etc)
  330. pMembers - the list of members to configure
  331. pMemberOf - the list of memberOf to configure
  332. nGroupCount - the count maintained for progress indication only. If the group is
  333. processed in this function, the count will be incremented.
  334. Return:
  335. WIN32 error code.
  336. */
  337. {
  338. if ( GroupName == NULL ) {
  339. return(ERROR_SUCCESS);
  340. }
  341. if ( pRoots == NULL ) {
  342. return(ERROR_INVALID_PARAMETER);
  343. }
  344. DWORD retErr = ERROR_SUCCESS;
  345. DWORD retSave = ERROR_SUCCESS;
  346. //
  347. // search for the group name, if find it, get members and memberof attributes
  348. //
  349. LDAPMessage *Message = NULL;
  350. PWSTR Attribs[4];
  351. Attribs[0] = L"distinguishedName";
  352. Attribs[1] = L"member";
  353. Attribs[2] = L"memberOf";
  354. Attribs[3] = NULL;
  355. WCHAR tmpBuf[128];
  356. //
  357. // define a filter for global or universal group only
  358. //
  359. wcscpy(tmpBuf, L"( &(&(|");
  360. swprintf(tmpBuf+wcslen(L"( &(&(|"), L"(groupType=%d)(groupType=%d))(objectClass=group))(samAccountName=\0",
  361. GROUP_TYPE_ACCOUNT_GROUP | GROUP_TYPE_SECURITY_ENABLED, GROUP_TYPE_UNIVERSAL_GROUP | GROUP_TYPE_SECURITY_ENABLED);
  362. PWSTR Filter;
  363. Filter = (PWSTR)LocalAlloc(LMEM_ZEROINIT,
  364. (wcslen(tmpBuf)+wcslen(GroupName)+4)*sizeof(WCHAR));
  365. if ( Filter == NULL ) {
  366. return(SCESTATUS_NOT_ENOUGH_RESOURCE);
  367. }
  368. swprintf(Filter, L"%s%s) )", tmpBuf, GroupName);
  369. //
  370. // no chased referrel search because the group must be defined locally
  371. // on the domain
  372. //
  373. pGrpLDAP->ld_options = 0;
  374. retErr = ldap_search_s(
  375. pGrpLDAP,
  376. pRoots->Name,
  377. LDAP_SCOPE_SUBTREE,
  378. Filter,
  379. Attribs,
  380. 0,
  381. &Message);
  382. retErr = LdapMapErrorToWin32(retErr);
  383. if(retErr == ERROR_SUCCESS) {
  384. LDAPMessage *Entry = NULL;
  385. //
  386. // find the group, should have only one entry, unless there are duplicate
  387. // groups within the domain, in which case, we only care the first entry anyway
  388. //
  389. Entry = ldap_first_entry(pGrpLDAP, Message);
  390. if(Entry != NULL) {
  391. //
  392. // get the values of requested attributes
  393. // Note, Value pointer returned must be freed
  394. //
  395. PWSTR *Values;
  396. PWSTR RealGroupName;
  397. //
  398. // the DN name
  399. //
  400. Values = ldap_get_values(pGrpLDAP, Entry, Attribs[0]);
  401. if(Values != NULL) {
  402. ScepLogOutput3(1,0, SCEDLL_SCP_CONFIGURE, GroupName);
  403. if ( *nGroupCount < TICKS_GROUPS ) {
  404. ScepPostProgress(1,
  405. AREA_GROUP_MEMBERSHIP,
  406. GroupName);
  407. *nGroupCount++;
  408. }
  409. //
  410. // Save the real group name for add/remove members later.
  411. //
  412. RealGroupName = (PWSTR)LocalAlloc(0,(wcslen(Values[0]) + 1)*sizeof(WCHAR));
  413. if ( RealGroupName != NULL ) {
  414. wcscpy(RealGroupName, Values[0]);
  415. ldap_value_free(Values);
  416. ScepLogOutput3(3, 0, SCEDLL_SCP_CONFIGURE, RealGroupName);
  417. PSCE_NAME_LIST pRealNames=NULL;
  418. PSCE_NAME_LIST pDeleteNames=NULL;
  419. //
  420. // translate each name in the pMembers list to real ds names (search)
  421. //
  422. if ( !( *pStatus & SCE_GROUP_STATUS_NC_MEMBERS) ) {
  423. retErr = ScepDsGetDsNameList(pMembers, &pRealNames);
  424. retSave = retErr;
  425. //
  426. // continue to configure group membership even if
  427. // there are some members not resolved
  428. //
  429. // BUT if no member is resolved, do not proceed to remove
  430. // all members
  431. //
  432. if ( retErr == ERROR_SUCCESS ||
  433. (retErr == ERROR_FILE_NOT_FOUND && pRealNames) ) {
  434. //
  435. // get members attribute
  436. //
  437. Values = ldap_get_values(pGrpLDAP, Entry, Attribs[1]);
  438. if ( Values != NULL ) {
  439. //
  440. // process each member
  441. //
  442. retErr = ScepDsCompareNames(Values, &pRealNames, &pDeleteNames);
  443. ldap_value_free(Values);
  444. } else {
  445. //
  446. // it is OK if no members are found
  447. //
  448. ScepLogOutput3(3, 0, SCEDLL_EMPTY_MEMBERSHIP);
  449. retErr = ERROR_SUCCESS;
  450. }
  451. if ( NO_ERROR == retErr ) {
  452. //
  453. // add/remove members of the group
  454. //
  455. retErr = ScepDsChangeMembers(SCEGRP_MEMBERS,
  456. RealGroupName,
  457. pRealNames,
  458. pDeleteNames);
  459. }
  460. if ( ERROR_SUCCESS == retSave ) {
  461. retSave = retErr;
  462. }
  463. }
  464. //
  465. // free buffers
  466. //
  467. ScepFreeNameList(pRealNames);
  468. ScepFreeNameList(pDeleteNames);
  469. pRealNames = NULL;
  470. pDeleteNames = NULL;
  471. }
  472. if ( !( *pStatus & SCE_GROUP_STATUS_NC_MEMBEROF) ) {
  473. //
  474. // memberof is also defined for the group
  475. // crack the memberof list first
  476. //
  477. retErr = ScepDsGetDsNameList(pMemberOf, &pRealNames);
  478. if ( ERROR_SUCCESS == retSave ) {
  479. retSave = retErr;
  480. }
  481. if ( ( ERROR_SUCCESS == retErr ||
  482. ERROR_FILE_NOT_FOUND == retErr ) && pRealNames ) {
  483. //
  484. // get memberof attribute of the group
  485. //
  486. Values = ldap_get_values(pGrpLDAP, Entry, Attribs[2]);
  487. if ( Values != NULL ) {
  488. //
  489. // process each membership
  490. //
  491. retErr = ScepDsCompareNames(Values, &pRealNames, NULL);
  492. ldap_value_free(Values);
  493. } else {
  494. //
  495. // it is OK if no membership is defined
  496. //
  497. ScepLogOutput3(3, 0, SCEDLL_EMPTY_MEMBERSHIP);
  498. retErr = NO_ERROR;
  499. }
  500. if ( retErr == NO_ERROR ) {
  501. //
  502. // add the group to the defined membership
  503. // Note, other existing membership is not removed
  504. //
  505. retErr = ScepDsChangeMembers(SCEGRP_MEMBERSHIP,
  506. RealGroupName,
  507. pRealNames,
  508. NULL);
  509. }
  510. ScepFreeNameList(pRealNames);
  511. pRealNames = NULL;
  512. //
  513. // remember the error
  514. //
  515. if ( ERROR_SUCCESS == retSave ) {
  516. retSave = retErr;
  517. }
  518. }
  519. }
  520. LocalFree(RealGroupName);
  521. } else {
  522. ldap_value_free(Values);
  523. retErr = ERROR_NOT_ENOUGH_MEMORY;
  524. }
  525. //
  526. // regardless success or failure, this group has been
  527. // processed by this function. Mark it so that it will
  528. // be skipped by the old SAM API
  529. //
  530. *pStatus |= SCE_GROUP_STATUS_DONE_IN_DS;
  531. } else {
  532. //
  533. // Value[0] (group name) can not be empty
  534. //
  535. retErr = LdapMapErrorToWin32(pGrpLDAP->ld_errno);
  536. ScepLogOutput3(3,retErr, SCEDLL_CANNOT_FIND, GroupName);
  537. }
  538. } else {
  539. //
  540. // the group is not found
  541. //
  542. retErr = ERROR_FILE_NOT_FOUND;
  543. ScepLogOutput3(3,retErr, SCEDLL_CANNOT_FIND, GroupName);
  544. }
  545. } else {
  546. //
  547. // error finding the group (with the filter defined)
  548. //
  549. ScepLogOutput3(3,retErr, SCEDLL_CANNOT_FIND, Filter);
  550. }
  551. //
  552. // free Filter
  553. //
  554. if ( Message )
  555. ldap_msgfree(Message);
  556. LocalFree(Filter);
  557. //
  558. // return the error
  559. //
  560. if ( ERROR_SUCCESS == retSave ) {
  561. retSave = retErr;
  562. }
  563. return(retSave);
  564. }
  565. DWORD
  566. ScepDsGetDsNameList(
  567. IN PSCE_NAME_LIST pNameList,
  568. OUT PSCE_NAME_LIST *pRealNames
  569. )
  570. /*
  571. Description:
  572. Translate account names in the list to FQDN format (CN=<account>,DC=<domain>,...).
  573. The output list pRealNames can be filled up even if the function returns
  574. error, to handle valid accounts while there are invalid accounts defined in
  575. the list.
  576. Arguments:
  577. pNameList - the link list for accounts in name format to convert
  578. pRealNames - the output link list for converted FQDN format accounts
  579. Return:
  580. WIN32 error code.
  581. If ERROR_FILE_NOT_FOUND is returned, it means that some accounts in the
  582. input list cannot be cracked.
  583. */
  584. {
  585. if ( pNameList == NULL ) {
  586. return(ERROR_SUCCESS);
  587. }
  588. if ( pRealNames == NULL ) {
  589. return(ERROR_INVALID_PARAMETER);
  590. }
  591. //
  592. // find the procedure address of DsCrackNames and DsFreeNameResult
  593. // ntdsapi.dll is dynamically loaded in ScepCrackOpen
  594. //
  595. PFNDSCRACKNAMES pfnDsCrackNames=NULL;
  596. PFNDSFREENAMERESULT pfnDsFreeNameResult=NULL;
  597. if ( hNtdsApi ) {
  598. #if defined(UNICODE)
  599. pfnDsCrackNames = (PFNDSCRACKNAMES)GetProcAddress(hNtdsApi, "DsCrackNamesW");
  600. pfnDsFreeNameResult = (PFNDSFREENAMERESULT)GetProcAddress(hNtdsApi, "DsFreeNameResultW");
  601. #else
  602. pfnDsCrackNames = (PFNDSCRACKNAMES)GetProcAddress(hNtdsApi, "DsCrackNamesA");
  603. pfnDsFreeNameResult = (PFNDSFREENAMERESULT)GetProcAddress(hNtdsApi, "DsFreeNameResultA");
  604. #endif
  605. }
  606. //
  607. // the two entry points must exist before continue
  608. //
  609. if ( pfnDsCrackNames == NULL || pfnDsFreeNameResult == NULL ) {
  610. return(ERROR_PROC_NOT_FOUND);
  611. }
  612. DWORD retErr=ERROR_SUCCESS;
  613. DWORD retSave=ERROR_SUCCESS;
  614. PWSTR pTemp;
  615. DS_NAME_RESULT *pDsResult=NULL;
  616. //
  617. // loop through each name in the list to crack
  618. //
  619. for ( PSCE_NAME_LIST pName = pNameList; pName != NULL; pName = pName->Next ) {
  620. //
  621. // Crack the name from NT4 account name to FQDN. Note, hDS is bound to
  622. // the GC in order to crack foreign domain accounts
  623. //
  624. retErr = (*pfnDsCrackNames) (
  625. hDS, // in
  626. DS_NAME_FLAG_TRUST_REFERRAL, // in
  627. DS_NT4_ACCOUNT_NAME,// in
  628. DS_FQDN_1779_NAME, // in
  629. 1, // in
  630. &(pName->Name), // in
  631. &pDsResult); // out
  632. if(retErr == ERROR_SUCCESS && pDsResult &&
  633. pDsResult->cItems > 0 && pDsResult->rItems ) {
  634. if ( pDsResult->rItems[0].pName ) {
  635. //
  636. // find the member
  637. // Save the real group name for add/remove members later.
  638. //
  639. ScepLogOutput3(3,0, SCEDLL_PROCESS, pDsResult->rItems[0].pName);
  640. retErr = ScepAddToNameList(pRealNames, pDsResult->rItems[0].pName, 0);
  641. } else {
  642. //
  643. // this name cannot be cracked.
  644. //
  645. retErr = pDsResult->rItems[0].status;
  646. ScepLogOutput3(1,retErr, SCEDLL_CANNOT_FIND_INDS, pName->Name);
  647. }
  648. } else {
  649. //
  650. // no match is found
  651. //
  652. retErr = ERROR_FILE_NOT_FOUND;
  653. ScepLogOutput3(1,retErr, SCEDLL_CANNOT_FIND_INDS, pName->Name);
  654. }
  655. if ( pDsResult ) {
  656. (*pfnDsFreeNameResult) (pDsResult);
  657. pDsResult = NULL;
  658. }
  659. //
  660. // remember the error to return
  661. //
  662. if ( ERROR_SUCCESS != retErr )
  663. retSave = retErr;
  664. }
  665. return(retSave);
  666. }
  667. DWORD
  668. ScepDsCompareNames(
  669. IN PWSTR *Values,
  670. IN OUT PSCE_NAME_LIST *pAddList,
  671. OUT PSCE_NAME_LIST *pDeleteList OPTIONAL
  672. )
  673. /*
  674. Description:
  675. Arguments:
  676. Values
  677. pAddList
  678. pDeleteList
  679. Return Value:
  680. WIN32 error
  681. */
  682. {
  683. if ( Values == NULL || pAddList == NULL ) {
  684. return(ERROR_INVALID_PARAMETER);
  685. }
  686. //
  687. // count how many existing members (memberof)
  688. //
  689. ULONG ValCount = ldap_count_values(Values);
  690. DWORD rc=NO_ERROR;
  691. PSCE_NAME_LIST pTemp;
  692. //
  693. // loop through each existing value to compare with the ones defined
  694. // for configuration to determine which one should be added and which
  695. // one should be removed from the membership
  696. //
  697. for(ULONG index = 0; index < ValCount; index++) {
  698. if ( Values[index] == NULL ) {
  699. continue;
  700. }
  701. pTemp = *pAddList;
  702. PSCE_NAME_LIST pParent = NULL, pTemp2;
  703. BOOL bFound=FALSE;
  704. while (pTemp != NULL ) {
  705. if ( _wcsicmp(Values[index], pTemp->Name) == 0 ) {
  706. //
  707. // find this member in both place, no need to add or remove
  708. // from the membership so take this one out of the list
  709. //
  710. if ( pParent == NULL ) {
  711. *pAddList = pTemp->Next;
  712. } else
  713. pParent->Next = pTemp->Next;
  714. pTemp2 = pTemp;
  715. pTemp = pTemp->Next;
  716. pTemp2->Next = NULL;
  717. ScepFreeNameList(pTemp2);
  718. bFound=TRUE;
  719. break;
  720. } else {
  721. //
  722. // move to the next one
  723. //
  724. pParent = pTemp;
  725. pTemp = pTemp->Next;
  726. }
  727. }
  728. if ( !bFound && pDeleteList != NULL ) {
  729. //
  730. // did not find in the real name list, should be deleted
  731. // if the remove buffer is passed in
  732. //
  733. rc = ScepAddToNameList(pDeleteList, Values[index], 0);
  734. if ( rc != ERROR_SUCCESS ) {
  735. ScepLogOutput3(1,rc, SCEDLL_SCP_ERROR_ADD, Values[index]);
  736. }
  737. }
  738. if ( rc != NO_ERROR ) {
  739. //
  740. // pDeleteList will be freed outside
  741. //
  742. break;
  743. }
  744. }
  745. return(rc);
  746. }
  747. DWORD
  748. ScepDsChangeMembers(
  749. IN ULONG Flag,
  750. IN PWSTR RealGroupName,
  751. IN PSCE_NAME_LIST pAddList OPTIONAL,
  752. IN PSCE_NAME_LIST pDeleteList OPTIONAL
  753. )
  754. {
  755. if ( RealGroupName == NULL ) {
  756. return(ERROR_INVALID_PARAMETER);
  757. }
  758. if ( pAddList == NULL && pDeleteList == NULL ) {
  759. //
  760. // nothing to do
  761. //
  762. return(ERROR_SUCCESS);
  763. }
  764. PLDAP pSrhLDAP = NULL;
  765. SCESTATUS rc = ScepLdapOpen(&pSrhLDAP);
  766. if ( rc != SCESTATUS_SUCCESS ) {
  767. return(ScepSceStatusToDosError(rc));
  768. }
  769. PLDAPMod rgMods[2];
  770. LDAPMod Mod;
  771. DWORD retErr=NO_ERROR;
  772. DWORD retSave=NO_ERROR;
  773. PWSTR rgpszVals[2];
  774. PSCE_NAME_LIST pName;
  775. rgMods[0] = &Mod;
  776. rgMods[1] = NULL;
  777. rgpszVals[1] = NULL;
  778. //
  779. // need to do one at a time because individual members/memberof may fail
  780. //
  781. Mod.mod_op = LDAP_MOD_ADD;
  782. Mod.mod_values = rgpszVals;
  783. if ( Flag == SCEGRP_MEMBERS )
  784. Mod.mod_type = L"member";
  785. else
  786. Mod.mod_type = L"memberOf";
  787. for ( pName=pAddList; pName != NULL; pName = pName->Next ) {
  788. ScepLogOutput3(2,0, SCEDLL_SCP_ADD, pName->Name);
  789. rgpszVals[0] = pName->Name;
  790. //
  791. // Now, we'll do the write for members...
  792. //
  793. retErr = ldap_modify_s(pSrhLDAP,
  794. RealGroupName,
  795. rgMods
  796. );
  797. retErr = LdapMapErrorToWin32(retErr);
  798. //
  799. // if the same member already exist, do not consider it as an error
  800. //
  801. if ( retErr == ERROR_ALREADY_EXISTS )
  802. retErr = ERROR_SUCCESS;
  803. if ( retErr != ERROR_SUCCESS ) {
  804. ScepLogOutput3(1,retErr, SCEDLL_SCP_ERROR_ADDTO, RealGroupName);
  805. retSave = retErr;
  806. }
  807. }
  808. if ( Flag == SCEGRP_MEMBERS && pDeleteList ) {
  809. //
  810. // remove existing members. Note, memberof won't be removed
  811. //
  812. if ( NO_ERROR == retSave ) {
  813. //
  814. // only remove existing members if all members are added successfully
  815. //
  816. Mod.mod_op = LDAP_MOD_DELETE;
  817. Mod.mod_type = L"member";
  818. Mod.mod_values = rgpszVals;
  819. for ( pName=pDeleteList; pName != NULL; pName = pName->Next ) {
  820. ScepLogOutput3(2,0, SCEDLL_SCP_REMOVE, pName->Name);
  821. rgpszVals[0] = pName->Name;
  822. //
  823. // Now, we'll do the write for members...
  824. //
  825. retErr = ldap_modify_s(pSrhLDAP,
  826. RealGroupName,
  827. rgMods
  828. );
  829. retErr = LdapMapErrorToWin32(retErr);
  830. //
  831. // if the member doesn't exist in the group, ignore
  832. //
  833. if ( retErr == ERROR_FILE_NOT_FOUND ) {
  834. retErr = ERROR_SUCCESS;
  835. }
  836. if ( retErr != ERROR_SUCCESS) {
  837. ScepLogOutput3(1,retErr, SCEDLL_SCP_ERROR_REMOVE, RealGroupName);
  838. retSave = retErr;
  839. }
  840. }
  841. } else {
  842. //
  843. // something is wrong when adding new members
  844. // so existing members won't be removed
  845. //
  846. ScepLogOutput3(1,retSave, SCEDLL_SCP_ERROR_NOREMOVE);
  847. }
  848. }
  849. if ( pSrhLDAP ) {
  850. ScepLdapClose(&pSrhLDAP);
  851. pSrhLDAP = NULL;
  852. }
  853. return(retSave);
  854. }
  855. #endif
  856. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  857. //
  858. // Functions to analyze group membership in DS
  859. //
  860. //
  861. //
  862. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  863. SCESTATUS
  864. ScepAnalyzeDsGroups(
  865. IN PSCE_GROUP_MEMBERSHIP pGroupMembership
  866. )
  867. /* ++
  868. Routine Description:
  869. Analyze the ds group membership. The main difference of ds groups
  870. from NT4 groups is that now group can be a member of another group.
  871. Members in the group are configured exactly as the pMembers list in
  872. the restricted group. The group is only validated (added) as a member
  873. of the MemberOf group list. Other existing members in those groups
  874. won't be removed.
  875. The restricted groups are specified in the SCP profile by group name.
  876. It could be a global group, or a alias (no difference in NT5 DS),
  877. but must be defined in the local domain.
  878. Arguments:
  879. pGroupMembership - The restricted group list with members/memberof info to configure
  880. Return value:
  881. SCESTATUS error codes
  882. ++ */
  883. {
  884. #if _WIN32_WINNT<0x0500
  885. return(SCESTATUS_SUCCESS);
  886. #else
  887. if ( pGroupMembership == NULL ) {
  888. ScepPostProgress(TICKS_GROUPS,
  889. AREA_GROUP_MEMBERSHIP,
  890. NULL);
  891. return(SCESTATUS_SUCCESS);
  892. }
  893. SCESTATUS rc;
  894. DWORD nGroupCount=0;
  895. PSCE_GROUP_MEMBERSHIP pGroup=pGroupMembership;
  896. PWSTR KeyName=NULL;
  897. DWORD GroupLen;
  898. //
  899. // open local policy
  900. //
  901. LSA_HANDLE PolicyHandle=NULL;
  902. rc = RtlNtStatusToDosError(
  903. ScepOpenLsaPolicy(
  904. POLICY_LOOKUP_NAMES,
  905. &PolicyHandle,
  906. TRUE
  907. ));
  908. if (ERROR_SUCCESS != rc ) {
  909. ScepLogOutput3(1, rc, SCEDLL_LSA_POLICY);
  910. return(ScepDosErrorToSceStatus(rc));
  911. }
  912. //
  913. // open the Ldap server, should open two ldap server, one for the local domain only
  914. // the other is for the global search (for members, membership)
  915. //
  916. rc = ScepLdapOpen(&pGrpLDAP);
  917. if ( rc == SCESTATUS_SUCCESS ) {
  918. ScepCrackOpen(&hDS);
  919. }
  920. if ( rc == SCESTATUS_SUCCESS ) {
  921. //
  922. // get the root of the domain
  923. //
  924. PSCE_OBJECT_LIST pRoots=NULL;
  925. rc = ScepEnumerateDsObjectRoots(
  926. pGrpLDAP,
  927. &pRoots
  928. );
  929. if ( rc == SCESTATUS_SUCCESS ) {
  930. //
  931. // configure each group
  932. //
  933. DWORD Win32rc;
  934. DWORD rc32=NO_ERROR; // saved status
  935. BOOL bAdminFound=FALSE;
  936. //
  937. // get the local administratos group name
  938. //
  939. for ( pGroup=pGroupMembership; pGroup != NULL; pGroup=pGroup->Next ) {
  940. if ( KeyName ) {
  941. LocalFree(KeyName);
  942. KeyName = NULL;
  943. }
  944. LPTSTR pTemp = wcschr(pGroup->GroupName, L'\\');
  945. if ( pTemp ) {
  946. //
  947. // there is a domain name, check it with computer name
  948. //
  949. UNICODE_STRING uName;
  950. uName.Buffer = pGroup->GroupName;
  951. uName.Length = ((USHORT)(pTemp-pGroup->GroupName))*sizeof(TCHAR);
  952. if ( !ScepIsDomainLocal(&uName) ) {
  953. ScepLogOutput3(1, 0, SCEDLL_NO_MAPPINGS, pGroup->GroupName);
  954. rc = SCESTATUS_INVALID_DATA;
  955. ScepRaiseErrorString(
  956. NULL,
  957. KeyName ? KeyName : pGroup->GroupName,
  958. szMembers
  959. );
  960. pGroup->Status |= SCE_GROUP_STATUS_DONE_IN_DS;
  961. continue;
  962. }
  963. ScepConvertNameToSidString(
  964. PolicyHandle,
  965. pGroup->GroupName,
  966. FALSE,
  967. &KeyName,
  968. &GroupLen
  969. );
  970. pTemp++;
  971. } else {
  972. pTemp = pGroup->GroupName;
  973. GroupLen = wcslen(pTemp);
  974. }
  975. //
  976. // find the group (validate) in this domain
  977. //
  978. Win32rc = ScepDsAnalyzeGroupMembers(
  979. PolicyHandle,
  980. pRoots,
  981. pTemp, // pGroup->GroupName,
  982. KeyName ? KeyName : pGroup->GroupName,
  983. GroupLen,
  984. &(pGroup->Status),
  985. pGroup->pMembers,
  986. pGroup->pMemberOf,
  987. &nGroupCount
  988. );
  989. if ( (Win32rc != ERROR_SUCCESS) &&
  990. (pGroup->Status & SCE_GROUP_STATUS_DONE_IN_DS) ) {
  991. ScepLogOutput3(1, Win32rc, SCEDLL_SAP_ERROR_ANALYZE, pGroup->GroupName);
  992. rc32 = Win32rc;
  993. if ( Win32rc == ERROR_FILE_NOT_FOUND ||
  994. Win32rc == ERROR_SHARING_VIOLATION ||
  995. Win32rc == ERROR_ACCESS_DENIED ) {
  996. ScepRaiseErrorString(
  997. NULL,
  998. KeyName ? KeyName : pGroup->GroupName,
  999. szMembers
  1000. );
  1001. Win32rc = ERROR_SUCCESS;
  1002. } else
  1003. break;
  1004. }
  1005. }
  1006. if ( rc32 != NO_ERROR ) {
  1007. rc = ScepDosErrorToSceStatus(rc32);
  1008. }
  1009. //
  1010. // free pRoots
  1011. //
  1012. ScepFreeObjectList(pRoots);
  1013. }
  1014. }
  1015. if ( KeyName ) {
  1016. LocalFree(KeyName);
  1017. }
  1018. if ( pGrpLDAP ) {
  1019. ScepLdapClose(&pGrpLDAP);
  1020. pGrpLDAP = NULL;
  1021. }
  1022. ScepCrackClose(&hDS);
  1023. hDS = NULL;
  1024. /*
  1025. // this will be handled in the analysis into SAM
  1026. //
  1027. // raise groups that are errored
  1028. //
  1029. for ( PSCE_GROUP_MEMBERSHIP pTmpGrp=pGroup;
  1030. pTmpGrp != NULL; pTmpGrp = pTmpGrp->Next ) {
  1031. if ( pTmpGrp->GroupName == NULL )
  1032. continue;
  1033. if ( wcschr(pGroup->GroupName, L'\\') ) {
  1034. ScepConvertNameToSidString(
  1035. PolicyHandle,
  1036. pGroup->GroupName,
  1037. FALSE,
  1038. &KeyName,
  1039. &GroupLen
  1040. );
  1041. }
  1042. ScepRaiseErrorString(
  1043. NULL,
  1044. KeyName ? KeyName : pTmpGrp->GroupName,
  1045. szMembers
  1046. );
  1047. if ( KeyName ) {
  1048. LocalFree(KeyName);
  1049. KeyName = NULL;
  1050. }
  1051. }
  1052. if ( rc != SCESTATUS_SERVICE_NOT_SUPPORT &&
  1053. nGroupCount < TICKS_GROUPS ) {
  1054. ScepPostProgress(TICKS_GROUPS-nGroupCount,
  1055. AREA_GROUP_MEMBERSHIP,
  1056. NULL);
  1057. }
  1058. */
  1059. if ( PolicyHandle ) {
  1060. LsaClose(PolicyHandle);
  1061. }
  1062. return(rc);
  1063. #endif
  1064. }
  1065. #if _WIN32_WINNT>=0x0500
  1066. DWORD
  1067. ScepDsAnalyzeGroupMembers(
  1068. IN LSA_HANDLE LsaPolicy,
  1069. IN PSCE_OBJECT_LIST pRoots,
  1070. IN PWSTR GroupName,
  1071. IN PWSTR KeyName,
  1072. IN DWORD KeyLen,
  1073. IN OUT DWORD *pStatus,
  1074. IN PSCE_NAME_LIST pMembers,
  1075. IN PSCE_NAME_LIST pMemberOf,
  1076. IN DWORD *nGroupCount
  1077. )
  1078. {
  1079. if ( GroupName == NULL ) {
  1080. return(ERROR_SUCCESS);
  1081. }
  1082. if ( pRoots == NULL ) {
  1083. return(ERROR_INVALID_PARAMETER);
  1084. }
  1085. DWORD retErr=ERROR_SUCCESS;
  1086. //
  1087. // search for the name, if find it, get members and memberof
  1088. //
  1089. LDAPMessage *Message = NULL;
  1090. PWSTR Attribs[4];
  1091. Attribs[0] = L"distinguishedName";
  1092. Attribs[1] = L"member";
  1093. Attribs[2] = L"memberOf";
  1094. Attribs[3] = NULL;
  1095. WCHAR tmpBuf[128];
  1096. // wcscpy(tmpBuf, L"( &(|(objectClass=localGroup)(objectClass=group))(cn=");
  1097. // wcscpy(tmpBuf, L"( &(|(objectClass=localGroup)(objectClass=group))(samAccountName=");
  1098. wcscpy(tmpBuf, L"( &(&(|");
  1099. swprintf(tmpBuf+wcslen(L"( &(&(|"), L"(groupType=%d)(groupType=%d))(objectClass=group))(samAccountName=\0",
  1100. GROUP_TYPE_ACCOUNT_GROUP | GROUP_TYPE_SECURITY_ENABLED, GROUP_TYPE_UNIVERSAL_GROUP | GROUP_TYPE_SECURITY_ENABLED);
  1101. PWSTR Filter;
  1102. DWORD Len=wcslen(GroupName);
  1103. Filter = (PWSTR)LocalAlloc(LMEM_ZEROINIT, (wcslen(tmpBuf)+Len+4)*sizeof(WCHAR));
  1104. if ( Filter == NULL ) {
  1105. return(SCESTATUS_NOT_ENOUGH_RESOURCE);
  1106. }
  1107. swprintf(Filter, L"%s%s) )", tmpBuf, GroupName);
  1108. pGrpLDAP->ld_options = 0; // no chased referrel
  1109. retErr = ldap_search_s(
  1110. pGrpLDAP,
  1111. pRoots->Name,
  1112. LDAP_SCOPE_SUBTREE,
  1113. Filter,
  1114. Attribs,
  1115. 0,
  1116. &Message);
  1117. retErr = LdapMapErrorToWin32(retErr);
  1118. if(retErr == ERROR_SUCCESS) {
  1119. //
  1120. // find the group
  1121. //
  1122. LDAPMessage *Entry = NULL;
  1123. //
  1124. // should only have one entry, unless there are duplicate groups
  1125. // within the domain, in which case, we only care the first entry anyway
  1126. //
  1127. //
  1128. // get the first one.
  1129. //
  1130. Entry = ldap_first_entry(pGrpLDAP, Message);
  1131. if(Entry != NULL) {
  1132. PWSTR *Values;
  1133. Values = ldap_get_values(pGrpLDAP, Entry, Attribs[0]);
  1134. if(Values != NULL) {
  1135. ScepLogOutput3(1,0, SCEDLL_SAP_ANALYZE, GroupName);
  1136. if ( *nGroupCount < TICKS_GROUPS ) {
  1137. ScepPostProgress(1,
  1138. AREA_GROUP_MEMBERSHIP,
  1139. GroupName);
  1140. *nGroupCount++;
  1141. }
  1142. ScepLogOutput2(3,0, L"\t\t%s", Values[0]);
  1143. ldap_value_free(Values);
  1144. PSCE_NAME_LIST pRealNames=NULL;
  1145. PSCE_NAME_LIST pCurrentList=NULL;
  1146. BOOL bDifferent;
  1147. DWORD retErr2, rc;
  1148. //
  1149. // translate each name in the pMembers list to real ds names (search)
  1150. //
  1151. retErr = ScepDsGetDsNameList(pMembers, &pRealNames);
  1152. if ( ERROR_SUCCESS == retErr ||
  1153. ERROR_FILE_NOT_FOUND == retErr ) {
  1154. //
  1155. // analyze members
  1156. //
  1157. Values = ldap_get_values(pGrpLDAP, Entry, Attribs[1]);
  1158. rc = ScepDsMembersDifferent(SCEGRP_MEMBERS,
  1159. Values,
  1160. &pRealNames,
  1161. &pCurrentList,
  1162. &bDifferent);
  1163. if ( Values != NULL )
  1164. ldap_value_free(Values);
  1165. //
  1166. // if there are some names unresolvable, this should be
  1167. // treated as mismatch
  1168. //
  1169. if ( ERROR_FILE_NOT_FOUND == retErr )
  1170. bDifferent = TRUE;
  1171. retErr = rc;
  1172. if ( ( ERROR_SUCCESS == retErr ) &&
  1173. ( bDifferent ||
  1174. (*pStatus & SCE_GROUP_STATUS_NC_MEMBERS) ) ) {
  1175. //
  1176. // save to the database
  1177. //
  1178. retErr = ScepDsConvertDsNameList(pCurrentList);
  1179. if ( retErr == NO_ERROR ) {
  1180. retErr = ScepSaveMemberMembershipList(
  1181. LsaPolicy,
  1182. szMembers,
  1183. KeyName,
  1184. KeyLen,
  1185. pCurrentList,
  1186. (*pStatus & SCE_GROUP_STATUS_NC_MEMBERS) ? 2: 1);
  1187. }
  1188. if ( retErr != ERROR_SUCCESS ) {
  1189. ScepLogOutput3(1,retErr, SCEDLL_SAP_ERROR_SAVE, GroupName);
  1190. }
  1191. }
  1192. ScepFreeNameList(pCurrentList);
  1193. pCurrentList = NULL;
  1194. ScepFreeNameList(pRealNames);
  1195. pRealNames = NULL;
  1196. }
  1197. retErr2 = ScepDsGetDsNameList(pMemberOf, &pRealNames);
  1198. if ( ( ERROR_SUCCESS == retErr2 ||
  1199. ERROR_FILE_NOT_FOUND == retErr2 ) && pRealNames ) {
  1200. //
  1201. // analyze membership
  1202. //
  1203. Values = ldap_get_values(pGrpLDAP, Entry, Attribs[2]);
  1204. rc = ScepDsMembersDifferent(SCEGRP_MEMBERSHIP,
  1205. Values,
  1206. &pRealNames,
  1207. &pCurrentList,
  1208. &bDifferent);
  1209. if ( Values != NULL )
  1210. ldap_value_free(Values);
  1211. //
  1212. // if there are some names unresolvable, this should be
  1213. // treated as mismatch
  1214. //
  1215. if ( ERROR_FILE_NOT_FOUND == retErr )
  1216. bDifferent = TRUE;
  1217. retErr2 = rc;
  1218. if ( (retErr2 == NO_ERROR) &&
  1219. ( bDifferent ||
  1220. (*pStatus & SCE_GROUP_STATUS_NC_MEMBEROF) ) ) {
  1221. //
  1222. // save to the database
  1223. //
  1224. retErr2 = ScepDsConvertDsNameList(pCurrentList);
  1225. if ( retErr2 == NO_ERROR ) {
  1226. retErr2 = ScepSaveMemberMembershipList(
  1227. LsaPolicy,
  1228. szMemberof,
  1229. KeyName,
  1230. KeyLen,
  1231. pCurrentList,
  1232. (*pStatus & SCE_GROUP_STATUS_NC_MEMBEROF) ? 2 : 1);
  1233. }
  1234. if ( retErr2 != ERROR_SUCCESS ) {
  1235. ScepLogOutput3(1,retErr2, SCEDLL_SAP_ERROR_SAVE, GroupName);
  1236. }
  1237. }
  1238. ScepFreeNameList(pCurrentList);
  1239. pCurrentList = NULL;
  1240. ScepFreeNameList(pRealNames);
  1241. pRealNames = NULL;
  1242. }
  1243. *pStatus |= SCE_GROUP_STATUS_DONE_IN_DS;
  1244. //
  1245. // remember the error
  1246. //
  1247. if ( retErr == NO_ERROR ) {
  1248. retErr = retErr2;
  1249. }
  1250. } else {
  1251. //
  1252. // Value[0] (group name) may not be empty
  1253. //
  1254. retErr = LdapMapErrorToWin32(pGrpLDAP->ld_errno);
  1255. ScepLogOutput3(3,retErr, SCEDLL_CANNOT_FIND, GroupName);
  1256. }
  1257. } else {
  1258. retErr = ERROR_FILE_NOT_FOUND; // the group is not found
  1259. ScepLogOutput3(3,retErr, SCEDLL_CANNOT_FIND, GroupName);
  1260. }
  1261. } else {
  1262. ScepLogOutput3(3,retErr, SCEDLL_CANNOT_FIND, Filter);
  1263. }
  1264. if ( Message )
  1265. ldap_msgfree(Message);
  1266. //
  1267. // free Filter
  1268. //
  1269. LocalFree(Filter);
  1270. return(retErr);
  1271. }
  1272. DWORD
  1273. ScepDsMembersDifferent(
  1274. IN ULONG Flag,
  1275. IN PWSTR *Values,
  1276. IN OUT PSCE_NAME_LIST *pNameList,
  1277. OUT PSCE_NAME_LIST *pCurrentList,
  1278. OUT PBOOL pbDifferent
  1279. )
  1280. {
  1281. if ( pCurrentList == NULL || pbDifferent == NULL ) {
  1282. return(ERROR_INVALID_PARAMETER);
  1283. }
  1284. if ( Values == NULL ) {
  1285. if ( pNameList == NULL || *pNameList == NULL )
  1286. *pbDifferent = FALSE;
  1287. else
  1288. *pbDifferent = TRUE;
  1289. return(ERROR_SUCCESS);
  1290. }
  1291. ULONG ValCount = ldap_count_values(Values);
  1292. DWORD rc=NO_ERROR;
  1293. *pbDifferent = FALSE;
  1294. for(ULONG index = 0; index < ValCount; index++) {
  1295. if ( Values[index] == NULL ) {
  1296. continue;
  1297. }
  1298. if ( !(*pbDifferent) ) {
  1299. PSCE_NAME_LIST pTemp = *pNameList, pTemp2;
  1300. PSCE_NAME_LIST pParent = NULL;
  1301. INT i;
  1302. while ( pTemp != NULL ) {
  1303. if ( (i = _wcsicmp(Values[index], pTemp->Name)) == 0 ) {
  1304. //
  1305. // find this member
  1306. //
  1307. if ( pParent == NULL ) {
  1308. *pNameList = pTemp->Next;
  1309. } else
  1310. pParent->Next = pTemp->Next;
  1311. pTemp2 = pTemp;
  1312. pTemp = pTemp->Next;
  1313. pTemp2->Next = NULL;
  1314. ScepFreeNameList(pTemp2);
  1315. break;
  1316. } else {
  1317. pParent = pTemp;
  1318. pTemp = pTemp->Next;
  1319. }
  1320. }
  1321. if ( pTemp == NULL && i != 0 )
  1322. *pbDifferent = TRUE;
  1323. }
  1324. //
  1325. // build the current list
  1326. //
  1327. rc = ScepAddToNameList(pCurrentList, Values[index], 0);
  1328. if ( rc != NO_ERROR ) {
  1329. ScepLogOutput3(1,rc, SCEDLL_SCP_ERROR_ADD, Values[index]);
  1330. break;
  1331. }
  1332. }
  1333. if ( rc == NO_ERROR && Flag == SCEGRP_MEMBERS &&
  1334. *pbDifferent == FALSE ) {
  1335. //
  1336. // still same so far, only continue to compare for members
  1337. // because membership is not one to one configuring
  1338. //
  1339. if ( *pNameList != NULL )
  1340. *pbDifferent = TRUE;
  1341. } // pCurrentList will be freed outside
  1342. return(rc);
  1343. }
  1344. PWSTR
  1345. ScepGetLocalAdminsName()
  1346. {
  1347. NTSTATUS NtStatus;
  1348. SAM_HANDLE AccountDomain=NULL;
  1349. SAM_HANDLE AliasHandle=NULL;
  1350. SAM_HANDLE ServerHandle=NULL;
  1351. PSID DomainSid=NULL;
  1352. SAM_HANDLE theBuiltinHandle=NULL;
  1353. PSID theBuiltinSid=NULL;
  1354. ALIAS_NAME_INFORMATION *BufName=NULL;
  1355. PWSTR pAdminsName=NULL;
  1356. //
  1357. // open the sam account domain
  1358. //
  1359. NtStatus = ScepOpenSamDomain(
  1360. SAM_SERVER_ALL_ACCESS,
  1361. MAXIMUM_ALLOWED,
  1362. &ServerHandle,
  1363. &AccountDomain,
  1364. &DomainSid,
  1365. &theBuiltinHandle,
  1366. &theBuiltinSid
  1367. );
  1368. if ( !NT_SUCCESS(NtStatus) ) {
  1369. ScepLogOutput3(1, RtlNtStatusToDosError(NtStatus),
  1370. SCEDLL_ERROR_OPEN, L"SAM");
  1371. return(NULL);
  1372. }
  1373. NtStatus = SamOpenAlias(
  1374. theBuiltinHandle,
  1375. MAXIMUM_ALLOWED,
  1376. DOMAIN_ALIAS_RID_ADMINS,
  1377. &AliasHandle
  1378. );
  1379. if ( NT_SUCCESS( NtStatus ) ) {
  1380. NtStatus = SamQueryInformationAlias(
  1381. AliasHandle,
  1382. AliasNameInformation,
  1383. (PVOID *)&BufName
  1384. );
  1385. if ( NT_SUCCESS( NtStatus ) && BufName &&
  1386. BufName->Name.Length > 0 && BufName->Name.Buffer ) {
  1387. //
  1388. // allocate buffer to return
  1389. //
  1390. pAdminsName = (PWSTR)ScepAlloc(0, BufName->Name.Length+2);
  1391. if ( pAdminsName ) {
  1392. wcsncpy(pAdminsName, BufName->Name.Buffer,
  1393. BufName->Name.Length/2);
  1394. pAdminsName[BufName->Name.Length/2] = L'\0';
  1395. } else {
  1396. NtStatus = STATUS_NO_MEMORY;
  1397. }
  1398. }
  1399. if ( BufName ) {
  1400. SamFreeMemory(BufName);
  1401. BufName = NULL;
  1402. }
  1403. //
  1404. // close the user handle
  1405. //
  1406. SamCloseHandle(AliasHandle);
  1407. }
  1408. SamCloseHandle(AccountDomain);
  1409. SamCloseHandle( ServerHandle );
  1410. if ( DomainSid != NULL )
  1411. SamFreeMemory(DomainSid);
  1412. SamCloseHandle( theBuiltinHandle );
  1413. if ( theBuiltinSid != NULL )
  1414. SamFreeMemory(theBuiltinSid);
  1415. return pAdminsName;
  1416. }
  1417. DWORD
  1418. ScepDsConvertDsNameList(
  1419. IN OUT PSCE_NAME_LIST pDsNameList
  1420. )
  1421. /*
  1422. Routine:
  1423. The input list is in the LDAP format (CN=<>,...DC=<>, ...). When the routine
  1424. returns, the list will be in NT4 account name format (domain\account)
  1425. */
  1426. {
  1427. if ( pDsNameList == NULL ) {
  1428. return(ERROR_SUCCESS);
  1429. }
  1430. PFNDSCRACKNAMES pfnDsCrackNames=NULL;
  1431. PFNDSFREENAMERESULT pfnDsFreeNameResult=NULL;
  1432. if ( hNtdsApi ) {
  1433. #if defined(UNICODE)
  1434. pfnDsCrackNames = (PFNDSCRACKNAMES)GetProcAddress(hNtdsApi, "DsCrackNamesW");
  1435. pfnDsFreeNameResult = (PFNDSFREENAMERESULT)GetProcAddress(hNtdsApi, "DsFreeNameResultW");
  1436. #else
  1437. pfnDsCrackNames = (PFNDSCRACKNAMES)GetProcAddress(hNtdsApi, "DsCrackNamesA");
  1438. pfnDsFreeNameResult = (PFNDSFREENAMERESULT)GetProcAddress(hNtdsApi, "DsFreeNameResultA");
  1439. #endif
  1440. }
  1441. if ( pfnDsCrackNames == NULL || pfnDsFreeNameResult == NULL ) {
  1442. return(ERROR_PROC_NOT_FOUND);
  1443. }
  1444. DWORD retErr=ERROR_SUCCESS;
  1445. PWSTR pTemp;
  1446. DS_NAME_RESULT *pDsResult=NULL;
  1447. DWORD DomLen;
  1448. DWORD SidLen;
  1449. CHAR SidBuf[MAX_PATH];
  1450. PWSTR RefDom[MAX_PATH];
  1451. SID_NAME_USE SidUse;
  1452. for ( PSCE_NAME_LIST pName = pDsNameList; pName != NULL; pName = pName->Next ) {
  1453. if ( pName->Name == NULL ) {
  1454. continue;
  1455. }
  1456. retErr = (*pfnDsCrackNames) (
  1457. hDS, // in
  1458. DS_NAME_NO_FLAGS, // in
  1459. DS_FQDN_1779_NAME, // in
  1460. DS_NT4_ACCOUNT_NAME,// in
  1461. 1, // in
  1462. &(pName->Name), // in
  1463. &pDsResult); // out
  1464. if(retErr == ERROR_SUCCESS && pDsResult && pDsResult->rItems &&
  1465. pDsResult->rItems[0].pName ) {
  1466. //
  1467. // NT4 account name format is returned, should check if the
  1468. // domain is not a acccount domain
  1469. //
  1470. pTemp = wcschr(pDsResult->rItems[0].pName, L'\\');
  1471. if ( pTemp ) {
  1472. DomLen=MAX_PATH;
  1473. SidLen=MAX_PATH;
  1474. if ( LookupAccountName(
  1475. NULL,
  1476. pDsResult->rItems[0].pName,
  1477. (PSID)SidBuf,
  1478. &SidLen,
  1479. (PWSTR)RefDom,
  1480. &DomLen,
  1481. &SidUse
  1482. ) ) {
  1483. if ( !ScepIsSidFromAccountDomain( (PSID)SidBuf) ) {
  1484. //
  1485. // add name only
  1486. //
  1487. pTemp++;
  1488. } else {
  1489. pTemp = pDsResult->rItems[0].pName;
  1490. }
  1491. } else {
  1492. pTemp = pDsResult->rItems[0].pName;
  1493. }
  1494. } else {
  1495. pTemp = pDsResult->rItems[0].pName;
  1496. }
  1497. PWSTR pNewName = (PWSTR)ScepAlloc(0, (wcslen(pTemp)+1)*sizeof(WCHAR));
  1498. if ( pNewName ) {
  1499. wcscpy(pNewName, pTemp);
  1500. ScepFree(pName->Name);
  1501. pName->Name = pNewName;
  1502. } else {
  1503. retErr = ERROR_NOT_ENOUGH_MEMORY;
  1504. }
  1505. } else {
  1506. // no match is found
  1507. retErr = ERROR_FILE_NOT_FOUND;
  1508. ScepLogOutput3(1,retErr, SCEDLL_CANNOT_FIND, pName->Name);
  1509. }
  1510. if ( pDsResult ) {
  1511. (*pfnDsFreeNameResult) (pDsResult);
  1512. pDsResult = NULL;
  1513. }
  1514. if ( retErr != ERROR_SUCCESS ) {
  1515. break;
  1516. }
  1517. }
  1518. return(retErr);
  1519. }
  1520. #endif