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.

1914 lines
52 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. dsobject.cpp
  5. Abstract:
  6. Routines to configure/analyze security of DS objects
  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. #include <ntldap.h>
  17. #pragma hdrstop
  18. //#define SCEDS_DBG 1
  19. //
  20. // NT-Security-Descriptor attribute's LDAP name.
  21. //
  22. #define ACTRL_SD_PROP_NAME L"nTSecurityDescriptor"
  23. //
  24. // LDAP handle
  25. //
  26. PLDAP Thread pLDAP = NULL;
  27. BOOL Thread StartDsCheck=FALSE;
  28. DWORD
  29. ScepConvertObjectTreeToLdap(
  30. IN PSCE_OBJECT_TREE pObject
  31. );
  32. SCESTATUS
  33. ScepConfigureDsObjectTree(
  34. IN PSCE_OBJECT_TREE ThisNode
  35. );
  36. DWORD
  37. ScepSetDsSecurityOverwrite(
  38. PWSTR ObjectName,
  39. PSECURITY_DESCRIPTOR pSecurityDescriptor OPTIONAL,
  40. SECURITY_INFORMATION SeInfo,
  41. PSCE_OBJECT_CHILD_LIST pNextLevel OPTIONAL
  42. );
  43. BOOL
  44. ScepIsMatchingSchemaObject(
  45. PWSTR Class,
  46. PWSTR ClassDn
  47. );
  48. DWORD
  49. ScepAnalyzeDsObjectTree(
  50. IN PSCE_OBJECT_TREE ThisNode
  51. );
  52. DWORD
  53. ScepAnalyzeDsObject(
  54. IN PWSTR ObjectFullName,
  55. IN PSECURITY_DESCRIPTOR ProfileSD,
  56. IN SECURITY_INFORMATION ProfileSeInfo
  57. );
  58. DWORD
  59. ScepAnalyzeDsObjectAndChildren(
  60. IN PWSTR ObjectName,
  61. IN BYTE Status,
  62. IN SECURITY_INFORMATION SeInfo,
  63. IN PSCE_OBJECT_CHILD_LIST pNextLevel
  64. );
  65. PSECURITY_DESCRIPTOR
  66. ScepMakeNullSD();
  67. DWORD
  68. ScepChangeSecurityOnObject(
  69. PWSTR ObjectName,
  70. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  71. SECURITY_INFORMATION SeInfo
  72. );
  73. DWORD
  74. ScepReadDsObjSecurity(
  75. IN PWSTR pwszObject,
  76. IN SECURITY_INFORMATION SeInfo,
  77. OUT PSECURITY_DESCRIPTOR *ppSD
  78. );
  79. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  80. //
  81. // Functions to configure DS object security
  82. //
  83. //
  84. //
  85. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  86. SCESTATUS
  87. ScepConfigureDsSecurity(
  88. IN PSCE_OBJECT_TREE pObject
  89. )
  90. /* ++
  91. Routine Description:
  92. Configure the ds object security as specified in pObject tree.
  93. This routine should only be executed on a domain controller.
  94. Arguments:
  95. pObject - The ds object tree. The objects in the tree are in
  96. the format of Jet index (o=,dc=,...cn=), need to convert before
  97. calls to ldap
  98. Return value:
  99. SCESTATUS error codes
  100. ++ */
  101. {
  102. SCESTATUS rc;
  103. DWORD Win32rc;
  104. //
  105. // open the Ldap server
  106. //
  107. rc = ScepLdapOpen(NULL);
  108. if ( rc == SCESTATUS_SUCCESS ) {
  109. //
  110. // process the tree node format to ldap format
  111. //
  112. Win32rc = ScepConvertObjectTreeToLdap(pObject);
  113. if ( Win32rc == ERROR_SUCCESS ) {
  114. //
  115. // do not need bind because ConvertObjectTreeToLadp already does that
  116. //
  117. //
  118. // configure the object tree
  119. //
  120. rc = ScepConfigureDsObjectTree(pObject);
  121. } else {
  122. ScepLogOutput3(1, Win32rc,
  123. SCEDLL_ERROR_CONVERT_LDAP,
  124. pObject->ObjectFullName);
  125. rc = ScepDosErrorToSceStatus(Win32rc);
  126. }
  127. ScepLdapClose(NULL);
  128. }
  129. return(rc);
  130. }
  131. SCESTATUS
  132. ScepConfigureDsObjectTree(
  133. IN PSCE_OBJECT_TREE ThisNode
  134. )
  135. /* ++
  136. Routine Description:
  137. This routine set security information to each DS object in the tree. DS
  138. objects are configured separately from file/registry objects because the
  139. logic behind ds objects is different.
  140. Arguments:
  141. ThisNode - one node in the tree
  142. Return value:
  143. SCESTATUS
  144. -- */
  145. {
  146. if ( ThisNode == NULL )
  147. return(SCESTATUS_SUCCESS);
  148. SCESTATUS rc=SCESTATUS_SUCCESS;
  149. //
  150. // if IGNORE is set, skip this node
  151. //
  152. if ( ThisNode->Status != SCE_STATUS_CHECK &&
  153. ThisNode->Status != SCE_STATUS_OVERWRITE &&
  154. ThisNode->Status != SCE_STATUS_NO_AUTO_INHERIT )
  155. goto SkipNode;
  156. if ( ThisNode->pSecurityDescriptor != NULL ) {
  157. ScepLogOutput3(2, 0, SCEDLL_SCP_CONFIGURE, ThisNode->ObjectFullName);
  158. //
  159. // notify the progress bar if there is any
  160. //
  161. ScepPostProgress(1, AREA_DS_OBJECTS, ThisNode->ObjectFullName);
  162. }
  163. //
  164. // Process this node first
  165. //
  166. if ( ThisNode->pSecurityDescriptor != NULL ||
  167. ThisNode->Status == SCE_STATUS_OVERWRITE ) {
  168. ScepLogOutput3(1, 0, SCEDLL_SCP_CONFIGURE, ThisNode->ObjectFullName);
  169. DWORD Win32Rc;
  170. //
  171. // set security to the ds object and all children
  172. // because the OVERWRITE flag.
  173. //
  174. if ( ThisNode->Status == SCE_STATUS_OVERWRITE ) {
  175. //
  176. // prepare for next level nodes
  177. //
  178. for ( PSCE_OBJECT_CHILD_LIST pTemp = ThisNode->ChildList;
  179. pTemp != NULL;
  180. pTemp = pTemp->Next ) {
  181. if ( pTemp->Node->pSecurityDescriptor == NULL &&
  182. pTemp->Node->Status != SCE_STATUS_IGNORE )
  183. pTemp->Node->Status = SCE_STATUS_OVERWRITE;
  184. }
  185. //
  186. // recursive set objects under the node, exclude nodes in the tree
  187. //
  188. Win32Rc = ScepSetDsSecurityOverwrite(
  189. ThisNode->ObjectFullName,
  190. ThisNode->pSecurityDescriptor,
  191. ThisNode->SeInfo,
  192. ThisNode->ChildList
  193. );
  194. } else {
  195. Win32Rc = ScepChangeSecurityOnObject(
  196. ThisNode->ObjectFullName,
  197. ThisNode->pSecurityDescriptor,
  198. ThisNode->SeInfo
  199. );
  200. }
  201. //
  202. // ignore the following error codes
  203. //
  204. if ( Win32Rc == ERROR_FILE_NOT_FOUND ||
  205. Win32Rc == ERROR_PATH_NOT_FOUND ||
  206. Win32Rc == ERROR_ACCESS_DENIED ||
  207. Win32Rc == ERROR_SHARING_VIOLATION ||
  208. Win32Rc == ERROR_INVALID_OWNER ||
  209. Win32Rc == ERROR_INVALID_PRIMARY_GROUP) {
  210. gWarningCode = Win32Rc;
  211. rc = SCESTATUS_SUCCESS;
  212. goto SkipNode;
  213. }
  214. if ( Win32Rc != ERROR_SUCCESS )
  215. return(ScepDosErrorToSceStatus(Win32Rc));
  216. }
  217. //
  218. // then process children
  219. //
  220. for ( PSCE_OBJECT_CHILD_LIST pTemp = ThisNode->ChildList;
  221. pTemp != NULL;
  222. pTemp = pTemp->Next ) {
  223. if ( pTemp->Node == NULL ) continue;
  224. rc = ScepConfigureDsObjectTree(
  225. pTemp->Node
  226. );
  227. }
  228. SkipNode:
  229. return(rc);
  230. }
  231. DWORD
  232. ScepSetDsSecurityOverwrite(
  233. PWSTR ObjectName,
  234. PSECURITY_DESCRIPTOR pSecurityDescriptor OPTIONAL,
  235. SECURITY_INFORMATION SeInfo,
  236. PSCE_OBJECT_CHILD_LIST pNextLevel OPTIONAL
  237. )
  238. {
  239. DWORD retErr=ERROR_SUCCESS;
  240. //
  241. // set security on the object first
  242. //
  243. /*
  244. retErr = ScepSetSecurityWin32(
  245. ObjectName,
  246. SeInfo,
  247. pSecurityDescriptor,
  248. SE_DS_OBJECT
  249. );
  250. */
  251. retErr = ScepChangeSecurityOnObject(
  252. ObjectName,
  253. pSecurityDescriptor,
  254. SeInfo
  255. );
  256. if ( retErr == ERROR_SUCCESS ) {
  257. //
  258. // enumerate one level nodes under the current object
  259. //
  260. LDAPMessage *Message = NULL;
  261. PWSTR Attribs[2];
  262. WCHAR dn[] = L"distinguishedName";
  263. Attribs[0] = dn;
  264. Attribs[1] = NULL;
  265. retErr = ldap_search_s( pLDAP,
  266. ObjectName,
  267. LDAP_SCOPE_ONELEVEL,
  268. L"(objectClass=*)",
  269. Attribs,
  270. 0,
  271. &Message);
  272. if( Message ) {
  273. retErr = ERROR_SUCCESS;
  274. LDAPMessage *Entry = NULL;
  275. //
  276. // How many entries ?
  277. //
  278. ULONG nChildren = ldap_count_entries(pLDAP, Message);
  279. //
  280. // get the first one.
  281. //
  282. Entry = ldap_first_entry(pLDAP, Message);
  283. //
  284. // now loop through the entries and recursively fix the
  285. // security on the subtree.
  286. //
  287. PWSTR *Values;
  288. PWSTR SubObjectName;
  289. INT cmpFlag;
  290. PSCE_OBJECT_CHILD_LIST pTemp;
  291. PSECURITY_DESCRIPTOR pNullSD = ScepMakeNullSD();
  292. for(ULONG i = 0; i<nChildren; i++) {
  293. if(Entry != NULL) {
  294. Values = ldap_get_values(pLDAP, Entry, Attribs[0]);
  295. if(Values != NULL) {
  296. //
  297. // Save the sub object DN for recursion.
  298. //
  299. SubObjectName = (PWSTR)LocalAlloc(0,(wcslen(Values[0]) + 1)*sizeof(WCHAR));
  300. if ( SubObjectName != NULL ) {
  301. wcscpy(SubObjectName, Values[0]);
  302. #ifdef SCEDS_DBG
  303. printf("%ws\n", SubObjectName);
  304. #endif
  305. ldap_value_free(Values);
  306. //
  307. // check if the SubObjectName is in the object tree already
  308. // SubObjectName should not contain extra spaces and comma is used as the delimiter
  309. // if not, need a convert routine to handle it.
  310. //
  311. for ( pTemp = pNextLevel; pTemp != NULL; pTemp=pTemp->Next ) {
  312. cmpFlag = _wcsicmp(pTemp->Node->ObjectFullName, SubObjectName);
  313. if ( cmpFlag >= 0 )
  314. break;
  315. }
  316. if ( pTemp == NULL || cmpFlag > 0 ) {
  317. //
  318. // did not find in the object tree, so resurse it
  319. //
  320. retErr = ScepSetDsSecurityOverwrite(
  321. SubObjectName,
  322. pNullSD,
  323. (SeInfo & ( DACL_SECURITY_INFORMATION |
  324. SACL_SECURITY_INFORMATION)),
  325. NULL
  326. );
  327. } // else find it, skip the subnode
  328. LocalFree(SubObjectName);
  329. } else {
  330. ldap_value_free(Values);
  331. retErr = ERROR_NOT_ENOUGH_MEMORY;
  332. }
  333. } else {
  334. retErr = LdapMapErrorToWin32(pLDAP->ld_errno);
  335. }
  336. } else {
  337. retErr = LdapMapErrorToWin32(pLDAP->ld_errno);
  338. }
  339. if ( retErr != ERROR_SUCCESS ) {
  340. break;
  341. }
  342. if ( i < nChildren-1 ) {
  343. Entry = ldap_next_entry(pLDAP, Entry);
  344. }
  345. } // end for loop
  346. //
  347. // free the NULL security descriptor
  348. //
  349. if ( pNullSD ) {
  350. ScepFree(pNullSD);
  351. }
  352. ldap_msgfree(Message);
  353. }
  354. }
  355. return(retErr);
  356. }
  357. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  358. //
  359. // Functions to analyze DS object security
  360. //
  361. //
  362. //
  363. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  364. BOOL
  365. ScepIsMatchingSchemaObject(
  366. PWSTR Class,
  367. PWSTR ClassDn
  368. )
  369. {
  370. //
  371. // Note: Class and ClassDn can't be NULL
  372. //
  373. ULONG len = lstrlen(Class);
  374. ULONG i;
  375. //
  376. // if the first component is not CN=, then no point continuing
  377. //
  378. if(*ClassDn != L'C') return FALSE;
  379. //
  380. // we need to match the name exactly.
  381. //
  382. for(i=0;i<len;i++)
  383. {
  384. if(ClassDn[i+3] != Class[i]) return FALSE;
  385. }
  386. //
  387. // things are good, but ensure that this is not just a prefix match!
  388. //
  389. if(ClassDn[i+3] == L',' || ClassDn[i+3] == L';')
  390. return TRUE;
  391. else
  392. return FALSE;
  393. }
  394. DWORD
  395. ScepAnalyzeDsSecurity(
  396. IN PSCE_OBJECT_TREE pObject
  397. )
  398. /* ++
  399. Routine Description:
  400. Analyze the ds object security as specified in pObject tree.
  401. This routine should only be executed on a domain controller.
  402. Arguments:
  403. pObject - The ds object tree
  404. Return value:
  405. SCESTATUS error codes
  406. ++ */
  407. {
  408. DWORD Win32rc;
  409. //
  410. // open the Ldap server
  411. //
  412. Win32rc = ScepSceStatusToDosError( ScepLdapOpen(NULL) );
  413. if( Win32rc == ERROR_SUCCESS ) {
  414. //
  415. // process the tree node format to ldap format
  416. //
  417. Win32rc = ScepConvertObjectTreeToLdap(pObject);
  418. if ( Win32rc == ERROR_SUCCESS ) {
  419. //
  420. // analyze all ds objects to the level that NOT_CONFIGURED
  421. // status is raised for the node
  422. // no matter if the node is specified in the tree
  423. //
  424. StartDsCheck=FALSE;
  425. Win32rc = ScepAnalyzeDsObjectTree(pObject);
  426. } else {
  427. ScepLogOutput3(1, Win32rc,
  428. SCEDLL_ERROR_CONVERT_LDAP, pObject->ObjectFullName);
  429. }
  430. ScepLdapClose(NULL);
  431. }
  432. return(Win32rc);
  433. }
  434. DWORD
  435. ScepAnalyzeDsObjectTree(
  436. IN PSCE_OBJECT_TREE ThisNode
  437. )
  438. /* ++
  439. Routine Description:
  440. This routine analyze security information of each DS object in the tree. DS
  441. objects are analyzed separately from file/registry objects because the
  442. logic behind ds objects is different.
  443. Arguments:
  444. ThisNode - one node in the tree
  445. Return value:
  446. Win32 error codes
  447. -- */
  448. {
  449. if ( ThisNode == NULL )
  450. return(ERROR_SUCCESS);
  451. DWORD Win32Rc=ERROR_SUCCESS;
  452. //
  453. // if IGNORE is set, log a SAP and skip this node
  454. //
  455. if ( ThisNode->Status != SCE_STATUS_CHECK &&
  456. ThisNode->Status != SCE_STATUS_OVERWRITE &&
  457. ThisNode->Status != SCE_STATUS_NO_AUTO_INHERIT ) {
  458. //
  459. // Log a point in SAP
  460. //
  461. Win32Rc = ScepSaveDsStatusToSection(
  462. ThisNode->ObjectFullName,
  463. ThisNode->IsContainer,
  464. SCE_STATUS_NOT_CONFIGURED,
  465. NULL,
  466. 0
  467. );
  468. goto SkipNode;
  469. }
  470. if ( NULL != ThisNode->pSecurityDescriptor ) {
  471. //
  472. // notify the progress bar if there is any
  473. //
  474. ScepPostProgress(1, AREA_DS_OBJECTS, ThisNode->ObjectFullName);
  475. StartDsCheck = TRUE;
  476. ScepLogOutput3(1, 0, SCEDLL_SAP_ANALYZE, ThisNode->ObjectFullName);
  477. //
  478. // only analyze objects with explicit aces specified
  479. //
  480. Win32Rc = ScepAnalyzeDsObject(
  481. ThisNode->ObjectFullName,
  482. ThisNode->pSecurityDescriptor,
  483. ThisNode->SeInfo
  484. );
  485. //
  486. // if the object denies access, skip it.
  487. //
  488. if ( Win32Rc == ERROR_ACCESS_DENIED ||
  489. Win32Rc == ERROR_SHARING_VIOLATION) {
  490. //
  491. // log a point in SAP for skipping
  492. //
  493. Win32Rc = ScepSaveDsStatusToSection(
  494. ThisNode->ObjectFullName,
  495. ThisNode->IsContainer,
  496. SCE_STATUS_ERROR_NOT_AVAILABLE,
  497. NULL,
  498. 0
  499. );
  500. if ( Win32Rc == ERROR_SUCCESS)
  501. goto ProcChild;
  502. }
  503. //
  504. // if the object specified in the profile does not exist, skip it and children
  505. //
  506. if ( Win32Rc == ERROR_FILE_NOT_FOUND ||
  507. Win32Rc == ERROR_PATH_NOT_FOUND ) {
  508. gWarningCode = Win32Rc;
  509. Win32Rc = ERROR_SUCCESS;
  510. goto SkipNode;
  511. }
  512. } else {
  513. //
  514. // log a point in SAP for not analyzing
  515. //
  516. Win32Rc = ScepSaveDsStatusToSection(
  517. ThisNode->ObjectFullName,
  518. ThisNode->IsContainer,
  519. SCE_STATUS_CHILDREN_CONFIGURED,
  520. NULL,
  521. 0
  522. );
  523. }
  524. if ( Win32Rc != ERROR_SUCCESS )
  525. return(Win32Rc);
  526. //
  527. // if the status is NO_AUTO_INHERIT then all children except specified are N.C.ed
  528. // if status is overwrite, analyze everyone under
  529. // if status is check (auto inherit), everyone except specified should be "good" so don't go down
  530. //
  531. if ( (StartDsCheck && ThisNode->Status != SCE_STATUS_CHECK) ||
  532. (!StartDsCheck && NULL != ThisNode->ChildList ) ) {
  533. if ( ThisNode->Status == SCE_STATUS_OVERWRITE ) {
  534. //
  535. // prepare for next level nodes
  536. //
  537. for ( PSCE_OBJECT_CHILD_LIST pTemp = ThisNode->ChildList;
  538. pTemp != NULL;
  539. pTemp = pTemp->Next ) {
  540. if ( pTemp->Node->pSecurityDescriptor == NULL &&
  541. pTemp->Node->Status != SCE_STATUS_IGNORE )
  542. pTemp->Node->Status = SCE_STATUS_OVERWRITE;
  543. }
  544. }
  545. //
  546. // make a SD which represents a NULL DACL and SACL
  547. //
  548. Win32Rc = ScepAnalyzeDsObjectAndChildren(
  549. ThisNode->ObjectFullName,
  550. ThisNode->Status,
  551. (ThisNode->SeInfo &
  552. (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)),
  553. ThisNode->ChildList
  554. );
  555. //
  556. // ignore the following errors
  557. //
  558. if ( Win32Rc == ERROR_FILE_NOT_FOUND ||
  559. Win32Rc == ERROR_PATH_NOT_FOUND ||
  560. Win32Rc == ERROR_ACCESS_DENIED ||
  561. Win32Rc == ERROR_SHARING_VIOLATION ||
  562. Win32Rc == ERROR_INVALID_OWNER ||
  563. Win32Rc == ERROR_INVALID_PRIMARY_GROUP) {
  564. gWarningCode = Win32Rc;
  565. Win32Rc = ERROR_SUCCESS;
  566. }
  567. if ( Win32Rc != ERROR_SUCCESS )
  568. return(Win32Rc);
  569. }
  570. ProcChild:
  571. //
  572. // then process children
  573. //
  574. for (PSCE_OBJECT_CHILD_LIST pTemp = ThisNode->ChildList;
  575. pTemp != NULL; pTemp = pTemp->Next ) {
  576. Win32Rc = ScepAnalyzeDsObjectTree(
  577. pTemp->Node
  578. );
  579. if ( Win32Rc != ERROR_SUCCESS ) {
  580. break;
  581. }
  582. }
  583. SkipNode:
  584. return(Win32Rc);
  585. }
  586. DWORD
  587. ScepAnalyzeDsObject(
  588. IN PWSTR ObjectFullName,
  589. IN PSECURITY_DESCRIPTOR ProfileSD,
  590. IN SECURITY_INFORMATION ProfileSeInfo
  591. )
  592. /* ++
  593. Routine Description:
  594. Get security setting for the current object and compare it with the profile
  595. setting. This routine analyzes the current object only. If there is
  596. difference in the security setting, the object will be added to the
  597. analysis database
  598. Arguments:
  599. ObjectFullName - The object's full path name
  600. ProfileSD - security descriptor specified in the INF profile
  601. ProfileSeInfo - security information specified in the INF profile
  602. Return value:
  603. SCESTATUS error codes
  604. ++ */
  605. {
  606. DWORD Win32rc=NO_ERROR;
  607. PSECURITY_DESCRIPTOR pSecurityDescriptor=NULL;
  608. //
  609. // get security information for this object
  610. //
  611. /*
  612. Win32rc = GetNamedSecurityInfo(
  613. ObjectFullName,
  614. SE_DS_OBJECT,
  615. ProfileSeInfo,
  616. NULL,
  617. NULL,
  618. NULL,
  619. NULL,
  620. &pSecurityDescriptor
  621. );
  622. */
  623. Win32rc = ScepReadDsObjSecurity(
  624. ObjectFullName,
  625. ProfileSeInfo,
  626. &pSecurityDescriptor
  627. );
  628. if ( Win32rc != ERROR_SUCCESS ) {
  629. ScepLogOutput3(1, Win32rc, SCEDLL_ERROR_QUERY_SECURITY, ObjectFullName );
  630. return(Win32rc);
  631. }
  632. // printf("\n\n\nDs Obj Sec. for %ws\n", ObjectFullName);
  633. // ScepPrintSecurityDescriptor(pSecurityDescriptor, TRUE);
  634. //
  635. // Compare the analysis security descriptor with the profile
  636. //
  637. Win32rc = ScepCompareAndAddObject(
  638. ObjectFullName,
  639. SE_DS_OBJECT,
  640. TRUE,
  641. pSecurityDescriptor,
  642. ProfileSD,
  643. ProfileSeInfo,
  644. TRUE,
  645. NULL
  646. );
  647. if ( Win32rc != ERROR_SUCCESS ) {
  648. ScepLogOutput3(1, Win32rc, SCEDLL_SAP_ERROR_ANALYZE, ObjectFullName);
  649. }
  650. ScepFree(pSecurityDescriptor);
  651. return(Win32rc);
  652. }
  653. DWORD
  654. ScepAnalyzeDsObjectAndChildren(
  655. IN PWSTR ObjectName,
  656. IN BYTE Status,
  657. IN SECURITY_INFORMATION SeInfo,
  658. IN PSCE_OBJECT_CHILD_LIST pNextLevel
  659. )
  660. /* ++
  661. Routine Description:
  662. Analyze current object and all subkeys/files/directories under the object.
  663. If there is difference in security setting for any object, the object will
  664. be added to the analysis database.
  665. Arguments:
  666. ObjectFullName - The object's full path name
  667. ProfileSD - security descriptor specified in the INF profile
  668. ProfileSeInfo - security information specified in the INF profile
  669. Return value:
  670. SCESTATUS error codes
  671. ++ */
  672. {
  673. DWORD retErr=ERROR_SUCCESS;
  674. //
  675. // enumerate one level nodes under the current object
  676. //
  677. LDAPMessage *Message = NULL;
  678. PWSTR Attribs[2];
  679. WCHAR dn[] = L"distinguishedName";
  680. Attribs[0] = dn;
  681. Attribs[1] = NULL;
  682. retErr = ldap_search_s( pLDAP,
  683. ObjectName,
  684. LDAP_SCOPE_ONELEVEL,
  685. L"(objectClass=*)",
  686. Attribs,
  687. 0,
  688. &Message);
  689. if( Message ) {
  690. retErr = ERROR_SUCCESS;
  691. LDAPMessage *Entry = NULL;
  692. //
  693. // How many entries ?
  694. //
  695. ULONG nChildren = ldap_count_entries(pLDAP, Message);
  696. //
  697. // get the first one.
  698. //
  699. Entry = ldap_first_entry(pLDAP, Message);
  700. //
  701. // now loop through the entries and recursively fix the
  702. // security on the subtree.
  703. //
  704. PWSTR *Values;
  705. PWSTR SubObjectName;
  706. INT cmpFlag;
  707. PSCE_OBJECT_CHILD_LIST pTemp;
  708. for(ULONG i = 0; i<nChildren; i++) {
  709. if(Entry != NULL) {
  710. Values = ldap_get_values(pLDAP, Entry, Attribs[0]);
  711. if(Values != NULL) {
  712. //
  713. // Save the sub object DN for recursion.
  714. //
  715. SubObjectName = (PWSTR)LocalAlloc(0,(wcslen(Values[0]) + 1)*sizeof(WCHAR));
  716. if ( SubObjectName != NULL ) {
  717. wcscpy(SubObjectName, Values[0]);
  718. ldap_value_free(Values);
  719. #ifdef SCEDS_DBG
  720. printf("%ws\n", SubObjectName);
  721. #endif
  722. //
  723. // check if the SubObjectName is in the object tree already
  724. //
  725. for ( pTemp = pNextLevel; pTemp != NULL; pTemp=pTemp->Next ) {
  726. cmpFlag = _wcsicmp(pTemp->Node->ObjectFullName, SubObjectName);
  727. if ( cmpFlag >= 0 )
  728. break;
  729. }
  730. if ( pTemp == NULL || cmpFlag > 0 ) {
  731. //
  732. // did not find in the object tree, so anayze it or recursive it
  733. //
  734. if ( Status == SCE_STATUS_OVERWRITE ) {
  735. //
  736. // analyze this file/key first
  737. //
  738. retErr = ScepAnalyzeDsObject(
  739. SubObjectName,
  740. NULL,
  741. SeInfo
  742. );
  743. //
  744. // if the object does not exist (impossible), skip all children
  745. //
  746. if ( retErr == ERROR_ACCESS_DENIED ||
  747. retErr == ERROR_SHARING_VIOLATION ) {
  748. gWarningCode = retErr;
  749. retErr = ScepSaveDsStatusToSection(
  750. SubObjectName,
  751. TRUE,
  752. SCE_STATUS_ERROR_NOT_AVAILABLE,
  753. NULL,
  754. 0
  755. );
  756. retErr = ERROR_SUCCESS;
  757. }
  758. if ( retErr == ERROR_FILE_NOT_FOUND ||
  759. retErr == ERROR_PATH_NOT_FOUND ) {
  760. gWarningCode = retErr;
  761. retErr = ERROR_SUCCESS;
  762. } else if ( retErr == SCESTATUS_SUCCESS ) {
  763. //
  764. // recursive to next level
  765. //
  766. retErr = ScepAnalyzeDsObjectAndChildren(
  767. SubObjectName,
  768. Status,
  769. SeInfo,
  770. NULL
  771. );
  772. }
  773. } else {
  774. //
  775. // status is check, just raise a NOT_CONFIGURED status
  776. //
  777. retErr = ScepSaveDsStatusToSection(
  778. SubObjectName,
  779. TRUE,
  780. SCE_STATUS_NOT_CONFIGURED,
  781. NULL,
  782. 0
  783. );
  784. }
  785. } // else find it, skip the subnode
  786. LocalFree(SubObjectName);
  787. } else {
  788. ldap_value_free(Values);
  789. retErr = ERROR_NOT_ENOUGH_MEMORY;
  790. }
  791. } else {
  792. retErr = LdapMapErrorToWin32(pLDAP->ld_errno);
  793. }
  794. } else {
  795. retErr = LdapMapErrorToWin32(pLDAP->ld_errno);
  796. }
  797. if ( retErr != ERROR_SUCCESS ) {
  798. break;
  799. }
  800. if ( i < nChildren-1 ) {
  801. Entry = ldap_next_entry(pLDAP, Entry);
  802. }
  803. } // end for loop
  804. ldap_msgfree(Message);
  805. }
  806. return(retErr);
  807. }
  808. DWORD
  809. ScepConvertObjectTreeToLdap(
  810. IN PSCE_OBJECT_TREE pObject
  811. )
  812. {
  813. DWORD Win32rc;
  814. PWSTR NewName=NULL;
  815. if ( pObject == NULL ) {
  816. return(ERROR_SUCCESS);
  817. }
  818. //
  819. // this node
  820. //
  821. Win32rc = ScepConvertJetNameToLdapCase(
  822. pObject->ObjectFullName,
  823. FALSE,
  824. SCE_CASE_DONT_CARE,
  825. &NewName
  826. );
  827. if ( Win32rc == ERROR_SUCCESS && NewName != NULL ) {
  828. ScepFree(pObject->ObjectFullName);
  829. pObject->ObjectFullName = NewName;
  830. //
  831. // child
  832. //
  833. for ( PSCE_OBJECT_CHILD_LIST pTemp = pObject->ChildList;
  834. pTemp != NULL; pTemp = pTemp->Next ) {
  835. Win32rc = ScepConvertObjectTreeToLdap(
  836. pTemp->Node
  837. );
  838. if ( Win32rc != ERROR_SUCCESS ) {
  839. break;
  840. }
  841. }
  842. }
  843. return(Win32rc);
  844. }
  845. DWORD
  846. ScepConvertJetNameToLdapCase(
  847. IN PWSTR JetName,
  848. IN BOOL bLastComponent,
  849. IN BYTE bCase,
  850. OUT PWSTR *LdapName
  851. )
  852. {
  853. if ( JetName == NULL || LdapName == NULL ) {
  854. return(ERROR_INVALID_PARAMETER);
  855. }
  856. DWORD retErr;
  857. PWSTR pTempName=NULL;
  858. //
  859. // reserve the components
  860. //
  861. retErr = ScepSceStatusToDosError(
  862. ScepConvertLdapToJetIndexName(
  863. JetName,
  864. &pTempName
  865. ) );
  866. if ( retErr == ERROR_SUCCESS && pTempName == NULL ) {
  867. return(ERROR_INVALID_PARAMETER);
  868. }
  869. if ( retErr == ERROR_SUCCESS ) {
  870. if ( bCase == SCE_CASE_REQUIRED ||
  871. bCase == SCE_CASE_PREFERED ) {
  872. if ( pLDAP == NULL ) {
  873. //
  874. // ldap is not available
  875. //
  876. retErr = ERROR_NOT_SUPPORTED;
  877. } else {
  878. //
  879. // go search in the DS tree
  880. //
  881. LDAPMessage *Message = NULL; // for LDAP calls.
  882. PWSTR Attribs[2]; // for LDAP calls.
  883. Attribs[0] = L"distinguishedName";
  884. Attribs[1] = NULL;
  885. retErr = ldap_search_s( pLDAP,
  886. pTempName,
  887. LDAP_SCOPE_BASE,
  888. L"(objectClass=*)",
  889. Attribs,
  890. 0,
  891. &Message);
  892. if( Message ) {
  893. retErr = ERROR_SUCCESS;
  894. LDAPMessage *Entry = NULL;
  895. Entry = ldap_first_entry(pLDAP, Message);
  896. if(Entry != NULL) {
  897. //
  898. // Values here is a new scope pointer
  899. //
  900. PWSTR *Values = ldap_get_values(pLDAP, Entry, Attribs[0]);
  901. if(Values != NULL) {
  902. //
  903. // Values[0] is the DN.
  904. // save it in pTempName
  905. //
  906. PWSTR pTemp2 = (PWSTR)ScepAlloc(0, (wcslen(Values[0])+1)*sizeof(WCHAR));
  907. if ( pTemp2 != NULL ) {
  908. wcscpy(pTemp2, Values[0]);
  909. ScepFree(pTempName);
  910. pTempName = pTemp2;
  911. } else
  912. retErr = ERROR_NOT_ENOUGH_MEMORY;
  913. ldap_value_free(Values);
  914. } else
  915. retErr = LdapMapErrorToWin32(pLDAP->ld_errno);
  916. } else
  917. retErr = LdapMapErrorToWin32(pLDAP->ld_errno);
  918. ldap_msgfree(Message);
  919. }
  920. }
  921. if ( (retErr != ERROR_SUCCESS && bCase == SCE_CASE_REQUIRED) ||
  922. retErr == ERROR_NOT_ENOUGH_MEMORY ) {
  923. ScepFree(pTempName);
  924. return(retErr);
  925. }
  926. }
  927. if ( pTempName == NULL ) {
  928. // ???
  929. return(ERROR_NOT_ENOUGH_MEMORY);
  930. }
  931. //
  932. // ignore other errors for CASE_PREFERED
  933. //
  934. retErr = ERROR_SUCCESS;
  935. if ( bLastComponent ) {
  936. //
  937. // only return the first component
  938. // pTempName must not be NULL. it shouldn't be NULL
  939. //
  940. PWSTR pStart = wcschr(pTempName, L',');
  941. if ( pStart == NULL ) {
  942. *LdapName = pTempName;
  943. } else {
  944. *LdapName = (PWSTR)ScepAlloc(0, ((UINT)(pStart-pTempName+1))*sizeof(WCHAR));
  945. if ( *LdapName == NULL ) {
  946. retErr = ERROR_NOT_ENOUGH_MEMORY;
  947. } else {
  948. wcsncpy(*LdapName, pTempName, (size_t)(pStart-pTempName));
  949. *(*LdapName+(pStart-pTempName)) = L'\0';
  950. }
  951. ScepFree(pTempName);
  952. }
  953. } else {
  954. //
  955. // return the whole name
  956. //
  957. *LdapName = pTempName;
  958. }
  959. }
  960. return(retErr);
  961. }
  962. SCESTATUS
  963. ScepDsObjectExist(
  964. IN PWSTR ObjectName
  965. )
  966. // ObjectName must be in Ldap format
  967. {
  968. DWORD retErr;
  969. LDAPMessage *Message = NULL; // for LDAP calls.
  970. PWSTR Attribs[2]; // for LDAP calls.
  971. Attribs[0] = L"distinguishedName";
  972. Attribs[1] = NULL;
  973. retErr = ldap_search_s( pLDAP,
  974. ObjectName,
  975. LDAP_SCOPE_BASE,
  976. L"(objectClass=*)",
  977. Attribs,
  978. 0,
  979. &Message);
  980. if( Message ) {
  981. retErr = ERROR_SUCCESS;
  982. LDAPMessage *Entry = NULL;
  983. Entry = ldap_first_entry(pLDAP, Message);
  984. if(Entry != NULL) {
  985. //
  986. // Values here is a new scope pointer
  987. //
  988. PWSTR *Values = ldap_get_values(pLDAP, Entry, Attribs[0]);
  989. if(Values != NULL) {
  990. ldap_value_free(Values);
  991. } else
  992. retErr = LdapMapErrorToWin32(pLDAP->ld_errno);
  993. } else
  994. retErr = LdapMapErrorToWin32(pLDAP->ld_errno);
  995. ldap_msgfree(Message);
  996. }
  997. return(ScepDosErrorToSceStatus(retErr));
  998. }
  999. SCESTATUS
  1000. ScepEnumerateDsOneLevel(
  1001. IN PWSTR ObjectName,
  1002. OUT PSCE_NAME_LIST *pNameList
  1003. )
  1004. {
  1005. if ( ObjectName == NULL || pNameList == NULL ) {
  1006. return(SCESTATUS_INVALID_PARAMETER);
  1007. }
  1008. DWORD retErr=ERROR_SUCCESS;
  1009. //
  1010. // enumerate one level nodes under the current object
  1011. //
  1012. LDAPMessage *Message = NULL;
  1013. PWSTR Attribs[2];
  1014. WCHAR dn[] = L"distinguishedName";
  1015. Attribs[0] = dn;
  1016. Attribs[1] = NULL;
  1017. retErr = ldap_search_s( pLDAP,
  1018. ObjectName,
  1019. LDAP_SCOPE_ONELEVEL,
  1020. L"(objectClass=*)",
  1021. Attribs,
  1022. 0,
  1023. &Message);
  1024. if( Message ) {
  1025. retErr = ERROR_SUCCESS;
  1026. LDAPMessage *Entry = NULL;
  1027. //
  1028. // How many entries ?
  1029. //
  1030. ULONG nChildren = ldap_count_entries(pLDAP, Message);
  1031. //
  1032. // get the first one.
  1033. //
  1034. Entry = ldap_first_entry(pLDAP, Message);
  1035. //
  1036. // now loop through the entries and recursively fix the
  1037. // security on the subtree.
  1038. //
  1039. PWSTR *Values;
  1040. for(ULONG i = 0; i<nChildren; i++) {
  1041. if(Entry != NULL) {
  1042. Values = ldap_get_values(pLDAP, Entry, Attribs[0]);
  1043. if(Values != NULL) {
  1044. //
  1045. // Save the sub object DN for recursion.
  1046. //
  1047. retErr = ScepAddToNameList(
  1048. pNameList,
  1049. Values[0],
  1050. wcslen(Values[0])
  1051. );
  1052. ldap_value_free(Values);
  1053. } else {
  1054. retErr = LdapMapErrorToWin32(pLDAP->ld_errno);
  1055. }
  1056. } else {
  1057. retErr = LdapMapErrorToWin32(pLDAP->ld_errno);
  1058. }
  1059. if ( retErr != ERROR_SUCCESS ) {
  1060. break;
  1061. }
  1062. if ( i < nChildren-1 ) {
  1063. Entry = ldap_next_entry(pLDAP, Entry);
  1064. }
  1065. } // end for loop
  1066. ldap_msgfree(Message);
  1067. }
  1068. if ( retErr != ERROR_SUCCESS ) {
  1069. //
  1070. // free the object list
  1071. //
  1072. ScepFreeNameList(*pNameList);
  1073. *pNameList = NULL;
  1074. }
  1075. return(ScepDosErrorToSceStatus(retErr));
  1076. }
  1077. DWORD
  1078. ScepChangeSecurityOnObject(
  1079. PWSTR ObjectName,
  1080. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  1081. SECURITY_INFORMATION SeInfo
  1082. )
  1083. {
  1084. PLDAPMod rgMods[2];
  1085. PLDAP_BERVAL pBVals[2];
  1086. LDAPMod Mod;
  1087. LDAP_BERVAL BVal;
  1088. DWORD retErr;
  1089. BYTE berValue[8];
  1090. //
  1091. // JohnsonA The BER encoding is current hardcoded. Change this to use
  1092. // AndyHe's BER_printf package once it's done.
  1093. //
  1094. berValue[0] = 0x30;
  1095. berValue[1] = 0x03;
  1096. berValue[2] = 0x02;
  1097. berValue[3] = 0x01;
  1098. berValue[4] = (BYTE)((ULONG)SeInfo & 0xF);
  1099. LDAPControl SeInfoControl =
  1100. {
  1101. LDAP_SERVER_SD_FLAGS_OID_W,
  1102. {
  1103. 5, (PCHAR)berValue
  1104. },
  1105. TRUE
  1106. };
  1107. PLDAPControl ServerControls[2] =
  1108. {
  1109. &SeInfoControl,
  1110. NULL
  1111. };
  1112. rgMods[0] = &Mod;
  1113. rgMods[1] = NULL;
  1114. pBVals[0] = &BVal;
  1115. pBVals[1] = NULL;
  1116. //
  1117. // lets set object security (whack NT-Security-Descriptor)
  1118. //
  1119. Mod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
  1120. Mod.mod_type = ACTRL_SD_PROP_NAME;
  1121. Mod.mod_values = (PWSTR *)pBVals;
  1122. //
  1123. // calculate the length of the security descriptor
  1124. //
  1125. if ( pSecurityDescriptor == NULL )
  1126. BVal.bv_len = 0;
  1127. else {
  1128. BVal.bv_len = RtlLengthSecurityDescriptor(pSecurityDescriptor);
  1129. }
  1130. BVal.bv_val = (PCHAR)(pSecurityDescriptor);
  1131. //
  1132. // Now, we'll do the write...
  1133. //
  1134. retErr = ldap_modify_ext_s(pLDAP,
  1135. ObjectName,
  1136. rgMods,
  1137. ServerControls,
  1138. NULL);
  1139. return(retErr);
  1140. }
  1141. DWORD
  1142. ScepReadDsObjSecurity(
  1143. IN PWSTR pwszObject,
  1144. IN SECURITY_INFORMATION SeInfo,
  1145. OUT PSECURITY_DESCRIPTOR *ppSD
  1146. )
  1147. {
  1148. DWORD dwErr;
  1149. PLDAPMessage pMessage = NULL;
  1150. PWSTR rgAttribs[2];
  1151. BYTE berValue[8];
  1152. //
  1153. // JohnsonA The BER encoding is current hardcoded. Change this to use
  1154. // AndyHe's BER_printf package once it's done.
  1155. //
  1156. berValue[0] = 0x30;
  1157. berValue[1] = 0x03;
  1158. berValue[2] = 0x02;
  1159. berValue[3] = 0x01;
  1160. berValue[4] = (BYTE)((ULONG)SeInfo & 0xF);
  1161. LDAPControl SeInfoControl =
  1162. {
  1163. LDAP_SERVER_SD_FLAGS_OID_W,
  1164. {
  1165. 5, (PCHAR)berValue
  1166. },
  1167. TRUE
  1168. };
  1169. PLDAPControl ServerControls[2] =
  1170. {
  1171. &SeInfoControl,
  1172. NULL
  1173. };
  1174. rgAttribs[0] = ACTRL_SD_PROP_NAME;
  1175. rgAttribs[1] = NULL;
  1176. dwErr = ldap_search_ext_s(pLDAP,
  1177. pwszObject,
  1178. LDAP_SCOPE_BASE,
  1179. L"(objectClass=*)",
  1180. rgAttribs,
  1181. 0,
  1182. ServerControls,
  1183. NULL,
  1184. NULL,
  1185. 10000,
  1186. &pMessage);
  1187. if( pMessage ) {
  1188. dwErr = ERROR_SUCCESS;
  1189. LDAPMessage *pEntry = NULL;
  1190. pEntry = ldap_first_entry(pLDAP,
  1191. pMessage);
  1192. if(pEntry == NULL) {
  1193. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1194. } else {
  1195. //
  1196. // Now, we'll have to get the values
  1197. //
  1198. PWSTR *ppwszValues = ldap_get_values(pLDAP,
  1199. pEntry,
  1200. rgAttribs[0]);
  1201. if(ppwszValues == NULL) {
  1202. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1203. } else {
  1204. PLDAP_BERVAL *pSize = ldap_get_values_len(pLDAP,
  1205. pMessage,
  1206. rgAttribs[0]);
  1207. if(pSize == NULL) {
  1208. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1209. } else {
  1210. //
  1211. // Allocate the security descriptor to return
  1212. //
  1213. *ppSD = (PSECURITY_DESCRIPTOR)ScepAlloc(0, (*pSize)->bv_len);
  1214. if(*ppSD == NULL) {
  1215. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1216. } else {
  1217. memcpy(*ppSD,
  1218. (PBYTE)(*pSize)->bv_val,
  1219. (*pSize)->bv_len);
  1220. }
  1221. ldap_value_free_len(pSize);
  1222. }
  1223. ldap_value_free(ppwszValues);
  1224. }
  1225. }
  1226. ldap_msgfree(pMessage);
  1227. }
  1228. return(dwErr);
  1229. }
  1230. PSECURITY_DESCRIPTOR
  1231. ScepMakeNullSD()
  1232. {
  1233. PSECURITY_DESCRIPTOR pNullSD = NULL;
  1234. DWORD dwErr=ERROR_SUCCESS;
  1235. #if 0
  1236. pNullSD = (PSECURITY_DESCRIPTOR)ScepAlloc(0, sizeof(SECURITY_DESCRIPTOR));
  1237. if(pNullSD == NULL) {
  1238. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1239. SetLastError(dwErr);
  1240. } else {
  1241. //
  1242. // build the SD
  1243. //
  1244. if(InitializeSecurityDescriptor(pNullSD,
  1245. SECURITY_DESCRIPTOR_REVISION
  1246. ) == FALSE ) {
  1247. dwErr = GetLastError();
  1248. } else {
  1249. if(SetSecurityDescriptorDacl(pNullSD,
  1250. TRUE,
  1251. NULL,
  1252. FALSE) == FALSE) {
  1253. dwErr = GetLastError();
  1254. } else {
  1255. if(SetSecurityDescriptorSacl(pNullSD,
  1256. TRUE,
  1257. NULL,
  1258. FALSE) == FALSE) {
  1259. dwErr = GetLastError();
  1260. }
  1261. }
  1262. }
  1263. if ( dwErr != ERROR_SUCCESS ) {
  1264. ScepFree(pNullSD);
  1265. pNullSD = NULL;
  1266. SetLastError(dwErr);
  1267. }
  1268. }
  1269. #endif
  1270. return(pNullSD);
  1271. }
  1272. SCESTATUS
  1273. ScepEnumerateDsObjectRoots(
  1274. IN PLDAP pLdap OPTIONAL,
  1275. OUT PSCE_OBJECT_LIST *pRoots
  1276. )
  1277. {
  1278. DWORD retErr;
  1279. SCESTATUS rc=SCESTATUS_SUCCESS;
  1280. LDAPMessage *Message = NULL; // for LDAP calls.
  1281. PWSTR Attribs[2]; // for LDAP calls.
  1282. Attribs[0] = LDAP_OPATT_DEFAULT_NAMING_CONTEXT_W; // ntldap.h
  1283. Attribs[1] = NULL;
  1284. PLDAP pTempLdap;
  1285. if ( pLdap == NULL )
  1286. pTempLdap = pLDAP;
  1287. else
  1288. pTempLdap = pLdap;
  1289. retErr = ldap_search_s(pTempLdap,
  1290. L"",
  1291. LDAP_SCOPE_BASE,
  1292. L"(objectClass=*)",
  1293. Attribs,
  1294. 0,
  1295. &Message);
  1296. if( Message ) { // should not check for error code
  1297. retErr = ERROR_SUCCESS;
  1298. LDAPMessage *Entry = NULL;
  1299. //
  1300. // read the first entry.
  1301. // we did base level search, we have only one entry.
  1302. // Entry does not need to be freed (it is freed with the message)
  1303. //
  1304. Entry = ldap_first_entry(pTempLdap, Message);
  1305. if(Entry != NULL) {
  1306. PWSTR *Values = ldap_get_values(pTempLdap, Entry, Attribs[0]);
  1307. if(Values != NULL) {
  1308. //
  1309. // should only get one value for the default naming context
  1310. // Values[0] here is the DN.
  1311. //
  1312. if ( Values[0] == NULL ) {
  1313. //
  1314. // unknown error.
  1315. //
  1316. rc = SCESTATUS_OTHER_ERROR;
  1317. } else {
  1318. //
  1319. // add the full name to the object list
  1320. // search for base, only one value should be returned
  1321. //
  1322. rc = ScepAddToObjectList(
  1323. pRoots,
  1324. Values[0],
  1325. wcslen(Values[0]),
  1326. TRUE,
  1327. SCE_STATUS_IGNORE,
  1328. 0,
  1329. SCE_CHECK_DUP //TRUE // check for duplicate
  1330. );
  1331. }
  1332. ldap_value_free(Values);
  1333. } else
  1334. retErr = LdapMapErrorToWin32(pTempLdap->ld_errno);
  1335. } else
  1336. retErr = LdapMapErrorToWin32(pTempLdap->ld_errno);
  1337. ldap_msgfree(Message);
  1338. Message = NULL;
  1339. }
  1340. if ( retErr != ERROR_SUCCESS ) {
  1341. rc = ScepDosErrorToSceStatus(retErr);
  1342. }
  1343. return(rc);
  1344. }
  1345. /*
  1346. SCESTATUS
  1347. ScepEnumerateDsObjectRoots(
  1348. IN PLDAP pLdap OPTIONAL,
  1349. OUT PSCE_OBJECT_LIST *pRoots
  1350. )
  1351. {
  1352. DWORD retErr;
  1353. SCESTATUS rc;
  1354. LDAPMessage *Message = NULL; // for LDAP calls.
  1355. PWSTR Attribs[2]; // for LDAP calls.
  1356. Attribs[0] = LDAP_OPATT_NAMING_CONTEXTS_W;
  1357. Attribs[1] = NULL;
  1358. PLDAP pTempLdap;
  1359. if ( pLdap == NULL )
  1360. pTempLdap = pLDAP;
  1361. else
  1362. pTempLdap = pLdap;
  1363. retErr = ldap_search_s(pTempLdap,
  1364. L"",
  1365. LDAP_SCOPE_BASE,
  1366. L"(objectClass=*)",
  1367. Attribs,
  1368. 0,
  1369. &Message);
  1370. if(retErr == ERROR_SUCCESS) {
  1371. LDAPMessage *Entry = NULL;
  1372. //
  1373. // read the first entry.
  1374. // we did base level search, we have only one entry.
  1375. // Entry does not need to be freed (it is freed with the message)
  1376. //
  1377. Entry = ldap_first_entry(pTempLdap, Message);
  1378. if(Entry != NULL) {
  1379. PWSTR *Values = ldap_get_values(pTempLdap, Entry, Attribs[0]);
  1380. if(Values != NULL) {
  1381. ULONG ValCount = ldap_count_values(Values);
  1382. ULONG index;
  1383. PWSTR ObjectName;
  1384. Attribs[0] = L"distinguishedName";
  1385. Attribs[1] = NULL;
  1386. //
  1387. // process each NC
  1388. //
  1389. for(index = 0; index < ValCount; index++) {
  1390. if ( Values[index] == NULL ) {
  1391. continue;
  1392. }
  1393. if( ScepIsMatchingSchemaObject(L"Configuration", Values[index]) ||
  1394. ScepIsMatchingSchemaObject(L"Schema", Values[index]) ) {
  1395. //
  1396. // If it is the Configuration or Schema, skip it
  1397. // because it is under the domain node
  1398. // only the domain node is returned
  1399. //
  1400. continue;
  1401. }
  1402. //
  1403. // free the message so it can be reused
  1404. //
  1405. ldap_msgfree(Message);
  1406. Message = NULL;
  1407. //
  1408. // The root object of the NC
  1409. //
  1410. retErr = ldap_search_s( pTempLdap,
  1411. Values[index],
  1412. LDAP_SCOPE_BASE,
  1413. L"(objectClass=*)",
  1414. Attribs,
  1415. 0,
  1416. &Message);
  1417. if(retErr == ERROR_SUCCESS) {
  1418. Entry = ldap_first_entry(pTempLdap, Message);
  1419. if(Entry != NULL) {
  1420. //
  1421. // Values here is a new scope pointer
  1422. //
  1423. PWSTR *Values = ldap_get_values(pTempLdap, Entry, Attribs[0]);
  1424. if(Values != NULL) {
  1425. //
  1426. // Values[0] is the DN.
  1427. //
  1428. if ( Values[0] == NULL ) {
  1429. //
  1430. // unknown error.
  1431. //
  1432. rc = SCESTATUS_OTHER_ERROR;
  1433. } else {
  1434. //
  1435. // add the full name to the object list
  1436. // search for base, only one value should be returned
  1437. //
  1438. rc = ScepAddToObjectList(
  1439. pRoots,
  1440. Values[0],
  1441. wcslen(Values[0]),
  1442. TRUE,
  1443. SCE_STATUS_IGNORE,
  1444. 0,
  1445. SCE_CHECK_DUP //TRUE // check for duplicate
  1446. );
  1447. }
  1448. ldap_value_free(Values);
  1449. } else
  1450. retErr = LdapMapErrorToWin32(pTempLdap->ld_errno);
  1451. } else
  1452. retErr = LdapMapErrorToWin32(pTempLdap->ld_errno);
  1453. if ( retErr != ERROR_SUCCESS ) {
  1454. break;
  1455. }
  1456. }
  1457. } // end for loop
  1458. //
  1459. // outer scope Values
  1460. //
  1461. ldap_value_free(Values);
  1462. } else
  1463. retErr = LdapMapErrorToWin32(pTempLdap->ld_errno);
  1464. } else
  1465. retErr = LdapMapErrorToWin32(pTempLdap->ld_errno);
  1466. ldap_msgfree(Message);
  1467. Message = NULL;
  1468. }
  1469. if ( retErr != ERROR_SUCCESS ) {
  1470. rc = ScepDosErrorToSceStatus(retErr);
  1471. }
  1472. return(rc);
  1473. }
  1474. */
  1475. SCESTATUS
  1476. ScepLdapOpen(
  1477. OUT PLDAP *pLdap OPTIONAL
  1478. )
  1479. {
  1480. #if _WIN32_WINNT<0x0500
  1481. return SCESTATUS_SERVICE_NOT_SUPPORT;
  1482. #else
  1483. DWORD Win32rc;
  1484. //
  1485. // bind to ldap
  1486. //
  1487. PLDAP pTempLdap;
  1488. pTempLdap = ldap_open(NULL, LDAP_PORT);
  1489. if ( pTempLdap == NULL ) {
  1490. Win32rc = ERROR_FILE_NOT_FOUND;
  1491. } else {
  1492. Win32rc = ldap_bind_s(pTempLdap,
  1493. NULL,
  1494. NULL,
  1495. LDAP_AUTH_SSPI);
  1496. }
  1497. if ( pLdap == NULL ) {
  1498. pLDAP = pTempLdap;
  1499. } else {
  1500. *pLdap = pTempLdap;
  1501. }
  1502. pTempLdap = NULL;
  1503. if ( Win32rc != ERROR_SUCCESS ) {
  1504. ScepLogOutput3(0, Win32rc, SCEDLL_ERROR_OPEN, L"Ldap server.");
  1505. }
  1506. return(ScepDosErrorToSceStatus(Win32rc));
  1507. #endif
  1508. }
  1509. SCESTATUS
  1510. ScepLdapClose(
  1511. IN PLDAP *pLdap OPTIONAL
  1512. )
  1513. {
  1514. if ( pLdap == NULL ) {
  1515. if ( pLDAP != NULL )
  1516. ldap_unbind(pLDAP);
  1517. pLDAP = NULL;
  1518. return(SCESTATUS_SUCCESS );
  1519. }
  1520. //
  1521. // unbind pLDAP
  1522. //
  1523. if ( *pLdap != NULL )
  1524. ldap_unbind(*pLdap);
  1525. *pLdap = NULL;
  1526. return(SCESTATUS_SUCCESS);
  1527. }