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.

610 lines
14 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. ldap.c
  5. Abstract:
  6. This Module implements the utility LDAP functions to read information
  7. from the DS schema
  8. Author:
  9. Mac McLain (MacM) 10-02-96
  10. Environment:
  11. User Mode
  12. Revision History:
  13. --*/
  14. #define LDAP_UNICODE 0
  15. #include <delegate.h>
  16. #include <dsgetdc.h>
  17. #include <lmcons.h>
  18. #include <lmapibuf.h>
  19. DWORD
  20. LDAPBind (
  21. IN PSTR pszObject,
  22. OUT PLDAP *ppLDAP
  23. )
  24. /*++
  25. Routine Description:
  26. This routine will bind to the appropriate server for the path
  27. Arguments:
  28. pszObject - Object server to bind to
  29. ppLDAP - Where the ldap binding is returned
  30. Return Value:
  31. ERROR_SUCCESS - Success
  32. --*/
  33. {
  34. DWORD dwErr = ERROR_SUCCESS;
  35. PDOMAIN_CONTROLLER_INFOA pDCI;
  36. //
  37. // First, get the address of our server. Note that we are binding to
  38. // a machine in a local domain. Normally, a valid DNS domain name
  39. // would be passed in.
  40. //
  41. dwErr = DsGetDcNameA(NULL,
  42. NULL,
  43. NULL,
  44. NULL,
  45. DS_IP_REQUIRED,
  46. &pDCI);
  47. if(dwErr == ERROR_SUCCESS)
  48. {
  49. PSTR pszDomain = pDCI[0].DomainControllerAddress;
  50. if(*pszDomain == '\\')
  51. {
  52. pszDomain += 2;
  53. }
  54. *ppLDAP = ldap_open(pszDomain,
  55. LDAP_PORT);
  56. if(*ppLDAP == NULL)
  57. {
  58. dwErr = ERROR_PATH_NOT_FOUND;
  59. }
  60. else
  61. {
  62. //
  63. // Do a bind...
  64. //
  65. dwErr = ldap_bind(*ppLDAP,
  66. NULL,
  67. NULL,
  68. LDAP_AUTH_SSPI);
  69. }
  70. NetApiBufferFree(pDCI);
  71. }
  72. return(dwErr);
  73. }
  74. VOID
  75. LDAPUnbind (
  76. IN PLDAP pLDAP
  77. )
  78. /*++
  79. Routine Description:
  80. This routine will unbind a previously bound connection
  81. Arguments:
  82. pLDAP - LDAP connection to unbind
  83. Return Value:
  84. void
  85. --*/
  86. {
  87. if(pLDAP != NULL)
  88. {
  89. ldap_unbind(pLDAP);
  90. }
  91. }
  92. DWORD
  93. LDAPReadAttribute (
  94. IN PSTR pszBase,
  95. IN PSTR pszAttribute,
  96. IN PLDAP pLDAP,
  97. OUT PDWORD pcValues,
  98. OUT PSTR **pppszValues
  99. )
  100. /*++
  101. Routine Description:
  102. This routine will read the specified attribute from the base path
  103. Arguments:
  104. pszBase - Base object path to read from
  105. pszAttribute - Attribute to read
  106. pcValues - Where the count of read items is returned
  107. pppszValues - Where the list of items is returned
  108. ppLDAP - LDAP connection handle to use/initialize
  109. Return Value:
  110. ERROR_SUCCESS - Success
  111. ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
  112. ERROR_INVALID_PARAMETER - The LDAP connection that was given is not
  113. correct
  114. Notes:
  115. The returned values list should be freed via a call to LDAPFreeValues
  116. --*/
  117. {
  118. DWORD dwErr = ERROR_SUCCESS;
  119. PLDAPMessage pMessage = NULL;
  120. PSTR rgAttribs[2];
  121. rgAttribs[0] = NULL;
  122. //
  123. // Ensure that our LDAP connection is valid
  124. //
  125. if(pLDAP == NULL)
  126. {
  127. dwErr = ERROR_INVALID_PARAMETER;
  128. }
  129. //
  130. // Then, do the search...
  131. //
  132. if(dwErr == ERROR_SUCCESS)
  133. {
  134. rgAttribs[0] = pszAttribute;
  135. rgAttribs[1] = NULL;
  136. dwErr = ldap_search_s(pLDAP,
  137. pszBase,
  138. LDAP_SCOPE_BASE,
  139. "(objectClass=*)",
  140. rgAttribs,
  141. 0,
  142. &pMessage);
  143. }
  144. if(dwErr == ERROR_SUCCESS)
  145. {
  146. LDAPMessage *pEntry = NULL;
  147. pEntry = ldap_first_entry(pLDAP,
  148. pMessage);
  149. if(pEntry == NULL)
  150. {
  151. dwErr = pLDAP->ld_errno;
  152. }
  153. else
  154. {
  155. //
  156. // Now, we'll have to get the values
  157. //
  158. *pppszValues = ldap_get_values(pLDAP,
  159. pEntry,
  160. rgAttribs[0]);
  161. if(*pppszValues == NULL)
  162. {
  163. dwErr = pLDAP->ld_errno;
  164. }
  165. else
  166. {
  167. *pcValues = ldap_count_values(*pppszValues);
  168. }
  169. }
  170. ldap_msgfree(pMessage);
  171. }
  172. return(dwErr);
  173. }
  174. VOID
  175. LDAPFreeValues (
  176. IN PSTR *ppszValues
  177. )
  178. /*++
  179. Routine Description:
  180. Frees the results of an LDAPReadAttribute call
  181. Arguments:
  182. ppwszValues - List to be freed
  183. Return Value:
  184. Void
  185. --*/
  186. {
  187. ldap_value_free(ppszValues);
  188. }
  189. DWORD
  190. LDAPReadSchemaPath (
  191. IN PWSTR pwszOU,
  192. OUT PSTR *ppszSchemaPath,
  193. OUT PLDAP *ppLDAP
  194. )
  195. /*++
  196. Routine Description:
  197. Reads the path to the schema from the DS
  198. Arguments:
  199. pwszOU - OU path for which the schema path needs to be obtained
  200. ppszSchemaPath - Where the schema path is returned
  201. ppLDAP - LDAP connection to be returned following the successful
  202. completion of this routine
  203. Return Value:
  204. ERROR_SUCCESS - Success
  205. ERROR_INVALID_PARAMETER - The OU given was not correct
  206. ERROR_PATH_NOT_FOUND - The path to the schema could not be found
  207. ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
  208. Notes:
  209. The returned schema path should be free via a call to LocalFree.
  210. The LDAP connection should be freed via a call to LDAPUnbind
  211. --*/
  212. {
  213. DWORD dwErr = ERROR_SUCCESS;
  214. PSTR *ppszValues = NULL;
  215. ULONG cValues;
  216. PSTR pszOU = NULL;
  217. HANDLE hDS = NULL;
  218. PDS_NAME_RESULTW pNameRes = NULL;
  219. *ppLDAP = NULL;
  220. //
  221. // Get our OU name into a form we can recognize
  222. //
  223. dwErr = DsBindW(NULL,
  224. NULL,
  225. &hDS);
  226. if(dwErr == ERROR_SUCCESS)
  227. {
  228. dwErr = DsCrackNamesW(hDS,
  229. DS_NAME_NO_FLAGS,
  230. DS_UNKNOWN_NAME,
  231. DS_FQDN_1779_NAME,
  232. 1,
  233. &pwszOU,
  234. &pNameRes);
  235. }
  236. if(dwErr == ERROR_SUCCESS)
  237. {
  238. if(pNameRes->cItems == 0 || pNameRes->rItems[0].status != 0)
  239. {
  240. dwErr = ERROR_PATH_NOT_FOUND;
  241. }
  242. else
  243. {
  244. PSTR pszDomain = NULL;
  245. dwErr = ConvertStringWToStringA(pNameRes->rItems[0].pDomain,
  246. &pszDomain);
  247. if(dwErr == ERROR_SUCCESS)
  248. {
  249. //
  250. // Now, we'll bind to the object, and then do the read
  251. //
  252. dwErr = LDAPBind(pszDomain,
  253. ppLDAP);
  254. LocalFree(pszDomain);
  255. }
  256. }
  257. }
  258. if(hDS != NULL)
  259. {
  260. DsUnBindW(&hDS);
  261. }
  262. if(dwErr == ERROR_SUCCESS)
  263. {
  264. dwErr = ConvertStringWToStringA(pNameRes->rItems[0].pName,
  265. &pszOU);
  266. if(dwErr == ERROR_SUCCESS)
  267. {
  268. dwErr = LDAPReadAttribute(pszOU,
  269. "subschemaSubentry",
  270. *ppLDAP,
  271. &cValues,
  272. &ppszValues);
  273. }
  274. }
  275. if(dwErr == ERROR_SUCCESS)
  276. {
  277. PSTR pszSchemaPath = NULL;
  278. PWSTR pwszSchemaPath = NULL;
  279. pszSchemaPath = strstr(ppszValues[0],
  280. "CN=Schema");
  281. if(pszSchemaPath == NULL)
  282. {
  283. dwErr = ERROR_PATH_NOT_FOUND;
  284. }
  285. else
  286. {
  287. //
  288. // Now that we have the proper schema path, we'll return it
  289. //
  290. *ppszSchemaPath = (PSTR)LocalAlloc(LMEM_FIXED,
  291. strlen(pszSchemaPath) + 1);
  292. if(*ppszSchemaPath == NULL)
  293. {
  294. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  295. }
  296. else
  297. {
  298. strcpy(*ppszSchemaPath,
  299. pszSchemaPath);
  300. }
  301. }
  302. //
  303. // Don't need the LDAP returned schema path anymore...
  304. //
  305. LDAPFreeValues(ppszValues);
  306. }
  307. if(dwErr != ERROR_SUCCESS)
  308. {
  309. LDAPUnbind(*ppLDAP);
  310. *ppLDAP = NULL;
  311. }
  312. DsFreeNameResultW(pNameRes);
  313. return(dwErr);
  314. }
  315. DWORD
  316. LDAPReadSecAndObjIdAsString (
  317. IN PLDAP pLDAP,
  318. IN PSTR pszSchemaPath,
  319. IN PSTR pszObject,
  320. OUT PWSTR *ppwszObjIdAsString,
  321. OUT PACTRL_ACCESS *ppAccess
  322. )
  323. /*++
  324. Routine Description:
  325. Reads the schemaID off of the specified object type and converts it
  326. to a string
  327. Arguments:
  328. pLDAP - LDAP connection to use for attribute read
  329. pszSchemaPath - Path to the schema for this object
  330. pszObject - LDAP name of the object for which to get the GUID
  331. ppwszObjIdAsString - Where the string representation of the GUID
  332. is returned
  333. Return Value:
  334. ERROR_SUCCESS - Success
  335. ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
  336. Notes:
  337. The returned string should be freed via a call to RpcFreeString (or as
  338. part of the whole list, by FreeIdList)
  339. --*/
  340. {
  341. DWORD dwErr = ERROR_SUCCESS;
  342. //
  343. // Ok, first, build the new schema path...
  344. //
  345. PSTR pszBase = NULL;
  346. PSTR *ppszValues = NULL;
  347. ULONG cValues;
  348. DWORD i,j;
  349. pszBase = (PSTR)LocalAlloc(LMEM_FIXED,
  350. 3 + // strlen("CN=")
  351. strlen(pszObject) +
  352. 1 + // strlen(",")
  353. strlen(pszSchemaPath) +
  354. 1);
  355. if(pszBase == NULL)
  356. {
  357. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  358. }
  359. else
  360. {
  361. sprintf(pszBase,
  362. "CN=%s,%s",
  363. pszObject,
  364. pszSchemaPath);
  365. //
  366. // We may not always want the object name
  367. //
  368. if(ppwszObjIdAsString != NULL)
  369. {
  370. dwErr = LDAPReadAttribute(pszBase,
  371. "SchemaIdGUID",
  372. pLDAP,
  373. &cValues,
  374. &ppszValues);
  375. if(dwErr == ERROR_SUCCESS)
  376. {
  377. //
  378. // The object we get back is actually a GUID
  379. //
  380. GUID *pGuid = (GUID *)ppszValues[0];
  381. dwErr = UuidToStringW((GUID *)ppszValues[0],
  382. ppwszObjIdAsString);
  383. LDAPFreeValues(ppszValues);
  384. }
  385. }
  386. //
  387. // Then, if that worked, and we need to, we'll read the default
  388. // security
  389. //
  390. if(dwErr == ERROR_SUCCESS && ppAccess != NULL)
  391. {
  392. dwErr = LDAPReadAttribute(pszBase,
  393. "defaultSecurityDescriptor",
  394. pLDAP,
  395. &cValues,
  396. &ppszValues);
  397. if(dwErr == ERROR_SUCCESS)
  398. {
  399. //
  400. // Get it as a security descriptor
  401. //
  402. PSECURITY_DESCRIPTOR pSD =
  403. (PSECURITY_DESCRIPTOR)ppszValues[0];
  404. //
  405. // This is an NT5 security API
  406. //
  407. dwErr = ConvertSecurityDescriptorToAccessNamedW
  408. (NULL, // There is no object
  409. SE_DS_OBJECT,
  410. pSD,
  411. ppAccess,
  412. NULL,
  413. NULL,
  414. NULL);
  415. LDAPFreeValues(ppszValues);
  416. }
  417. else
  418. {
  419. //
  420. // If the attribute wasn't found, try looking up the chain
  421. //
  422. if(dwErr == LDAP_NO_SUCH_ATTRIBUTE)
  423. {
  424. dwErr = LDAPReadAttribute(pszBase,
  425. "subClassOf",
  426. pLDAP,
  427. &cValues,
  428. &ppszValues);
  429. //
  430. // Ok, if that worked, we'll call ourselves. Note that
  431. // we don't care about the object name
  432. //
  433. if(dwErr == ERROR_SUCCESS)
  434. {
  435. dwErr = LDAPReadSecAndObjIdAsString(pLDAP,
  436. ppszValues[0],
  437. pszSchemaPath,
  438. NULL,
  439. ppAccess);
  440. LDAPFreeValues(ppszValues);
  441. }
  442. }
  443. }
  444. //
  445. // If it worked in that we read the access, we'll go through
  446. // and create all these as inherit entries
  447. //
  448. if(dwErr == ERROR_SUCCESS)
  449. {
  450. for(i = 0; i < (DWORD)((*ppAccess)->cEntries); i++)
  451. {
  452. for(j = 0;
  453. j < (DWORD)((*ppAccess)->pPropertyAccessList[i].
  454. pAccessEntryList->cEntries);
  455. j++)
  456. {
  457. (*ppAccess)->pPropertyAccessList[i].
  458. pAccessEntryList->pAccessList[j].
  459. lpInheritProperty = *ppwszObjIdAsString;
  460. (*ppAccess)->pPropertyAccessList[i].
  461. pAccessEntryList->pAccessList[j].Inheritance |=
  462. SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  463. }
  464. }
  465. }
  466. //
  467. // If it failed, don't forget to deallocate our memory
  468. //
  469. if(dwErr != ERROR_SUCCESS && ppwszObjIdAsString != NULL)
  470. {
  471. RpcStringFree(ppwszObjIdAsString);
  472. }
  473. }
  474. //
  475. // Free our memory
  476. //
  477. LocalFree(pszBase);
  478. }
  479. return(dwErr);
  480. }