uid.c 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright 2001 Sun Microsystems, Inc.
  3. * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
  4. * All rights reserved.
  5. * END COPYRIGHT BLOCK **/
  6. /*
  7. * uid.c
  8. *
  9. * Implements a directory server pre-operation plugin to test
  10. * attributes for uniqueness within a defined subtree in the
  11. * directory.
  12. *
  13. * Called uid.c since the original purpose of the plugin was to
  14. * check the uid attribute in user entries.
  15. */
  16. #include <slapi-plugin.h>
  17. #include <portable.h>
  18. #include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
  19. #include <string.h>
  20. #include "dirver.h"
  21. #include "plugin-utils.h"
  22. #if defined( LDAP_DEBUG ) && !defined( DEBUG )
  23. #define DEBUG
  24. #endif
  25. #define UNTAGGED_PARAMETER 12
  26. /* Quoting routine - this should be in a library somewhere (slapi?) */
  27. int ldap_quote_filter_value(
  28. char *value, int len,
  29. char *out, int maxLen,
  30. int *outLen);
  31. static int search_one_berval(const char *baseDN, const char *attrName,
  32. const struct berval *value, const char *target);
  33. /*
  34. * ISSUES:
  35. * How should this plugin handle ACL issues? It seems wrong to reject
  36. * adds and modifies because there is already a conflicting UID, when
  37. * the request would have failed because of an ACL check anyway.
  38. *
  39. * This code currently defines a maximum filter string size of 512. Is
  40. * this large enough?
  41. *
  42. * This code currently does not quote the value portion of the filter as
  43. * it is created. This is a bug.
  44. */
  45. /* */
  46. #define BEGIN do {
  47. #define END } while(0);
  48. /*
  49. * Slapi plugin descriptor
  50. */
  51. static char *plugin_name = "NSUniqueAttr";
  52. static Slapi_PluginDesc
  53. pluginDesc = {
  54. "NSUniqueAttr", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
  55. "Enforce unique attribute values"
  56. };
  57. static void* plugin_identity = NULL;
  58. /*
  59. * More information about constraint failure
  60. */
  61. static char *moreInfo =
  62. "Another entry with the same attribute value already exists";
  63. static void
  64. freePblock( Slapi_PBlock *spb ) {
  65. if ( spb )
  66. {
  67. slapi_free_search_results_internal( spb );
  68. slapi_pblock_destroy( spb );
  69. }
  70. }
  71. /* ------------------------------------------------------------ */
  72. /*
  73. * op_error - Record (and report) an operational error.
  74. * name changed to uid_op_error so as not to conflict with the external function
  75. * of the same name thereby preventing compiler warnings.
  76. */
  77. static int
  78. uid_op_error(int internal_error)
  79. {
  80. slapi_log_error(
  81. SLAPI_LOG_PLUGIN,
  82. plugin_name,
  83. "Internal error: %d\n",
  84. internal_error);
  85. return LDAP_OPERATIONS_ERROR;
  86. }
  87. /* ------------------------------------------------------------ */
  88. /*
  89. * Create an LDAP search filter from the attribute
  90. * name and value supplied.
  91. */
  92. static char *
  93. create_filter(const char *attribute, const struct berval *value)
  94. {
  95. char *filter;
  96. char *fp;
  97. char *max;
  98. int attrLen;
  99. int valueLen;
  100. int filterLen;
  101. /* Compute the length of the required buffer */
  102. attrLen = strlen(attribute);
  103. if (ldap_quote_filter_value(value->bv_val,
  104. value->bv_len, 0, 0, &valueLen))
  105. return 0;
  106. filterLen = attrLen + 1 + valueLen + 1;
  107. /* Allocate the buffer */
  108. filter = slapi_ch_malloc(filterLen);
  109. fp = filter;
  110. max = &filter[filterLen];
  111. /* Place attribute name in filter */
  112. strcpy(fp, attribute);
  113. fp += attrLen;
  114. /* Place comparison operator */
  115. *fp++ = '=';
  116. /* Place value in filter */
  117. if (ldap_quote_filter_value(value->bv_val, value->bv_len,
  118. fp, max-fp, &valueLen)) { slapi_ch_free((void**)&filter); return 0; }
  119. fp += valueLen;
  120. /* Terminate */
  121. *fp = 0;
  122. return filter;
  123. }
  124. /* ------------------------------------------------------------ */
  125. /*
  126. * search - search a subtree for entries with a named attribute matching
  127. * the list of values. An entry matching the 'target' DN is
  128. * not considered in the search.
  129. *
  130. * If 'attr' is NULL, the values are taken from 'values'.
  131. * If 'attr' is non-NULL, the values are taken from 'attr'.
  132. *
  133. * Return:
  134. * LDAP_SUCCESS - no matches, or the attribute matches the
  135. * target dn.
  136. * LDAP_CONSTRAINT_VIOLATION - an entry was found that already
  137. * contains the attribute value.
  138. * LDAP_OPERATIONS_ERROR - a server failure.
  139. */
  140. static int
  141. search(const char *baseDN, const char *attrName, Slapi_Attr *attr,
  142. struct berval **values, const char *target)
  143. {
  144. int result;
  145. #ifdef DEBUG
  146. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  147. "SEARCH baseDN=%s attr=%s target=%s\n", baseDN, attrName,
  148. target?target:"None");
  149. #endif
  150. result = LDAP_SUCCESS;
  151. /* If no values, can't possibly be a conflict */
  152. if ( (Slapi_Attr *)NULL == attr && (struct berval **)NULL == values )
  153. return result;
  154. /*
  155. * Perform the search for each value provided
  156. *
  157. * Another possibility would be to search for all the values at once.
  158. * However, this is more complex (for filter creation) and unique
  159. * attributes values are probably only changed one at a time anyway.
  160. */
  161. if ( (Slapi_Attr *)NULL != attr )
  162. {
  163. Slapi_Value *v = NULL;
  164. int vhint = -1;
  165. for ( vhint = slapi_attr_first_value( attr, &v );
  166. vhint != -1 && LDAP_SUCCESS == result;
  167. vhint = slapi_attr_next_value( attr, vhint, &v ))
  168. {
  169. result = search_one_berval(baseDN,attrName,
  170. slapi_value_get_berval(v),target);
  171. }
  172. }
  173. else
  174. {
  175. for (;*values != NULL && LDAP_SUCCESS == result; values++)
  176. {
  177. result = search_one_berval(baseDN,attrName,*values,target);
  178. }
  179. }
  180. #ifdef DEBUG
  181. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  182. "SEARCH result = %d\n", result);
  183. #endif
  184. return( result );
  185. }
  186. static int
  187. search_one_berval(const char *baseDN, const char *attrName,
  188. const struct berval *value, const char *target)
  189. {
  190. int result;
  191. char *filter;
  192. Slapi_PBlock *spb;
  193. result = LDAP_SUCCESS;
  194. /* If no value, can't possibly be a conflict */
  195. if ( (struct berval *)NULL == value )
  196. return result;
  197. filter = 0;
  198. spb = 0;
  199. BEGIN
  200. int err;
  201. int sres;
  202. Slapi_Entry **entries;
  203. static char *attrs[] = { "1.1", 0 };
  204. /* Create the filter - this needs to be freed */
  205. filter = create_filter(attrName, value);
  206. #ifdef DEBUG
  207. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  208. "SEARCH filter=%s\n", filter);
  209. #endif
  210. /* Perform the search using the new internal API */
  211. spb = slapi_pblock_new();
  212. if (!spb) { result = uid_op_error(2); break; }
  213. slapi_search_internal_set_pb(spb, baseDN, LDAP_SCOPE_SUBTREE,
  214. filter, attrs, 0 /* attrs only */, NULL, NULL, plugin_identity, 0 /* actions */);
  215. slapi_search_internal_pb(spb);
  216. err = slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_RESULT, &sres);
  217. if (err) { result = uid_op_error(3); break; }
  218. /* Allow search to report that there is nothing in the subtree */
  219. if (sres == LDAP_NO_SUCH_OBJECT) break;
  220. /* Other errors are bad */
  221. if (sres) { result = uid_op_error(3); break; }
  222. err = slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
  223. &entries);
  224. if (err) { result = uid_op_error(4); break; }
  225. /*
  226. * Look at entries returned. Any entry found must be the
  227. * target entry or the constraint fails.
  228. */
  229. for(;*entries;entries++)
  230. {
  231. char *dn = slapi_entry_get_dn(*entries);
  232. /*
  233. * DNs are returned in the original value used to insert
  234. * the entry. This must be "normalized" for comparison.
  235. *
  236. * This normalization is done "in-place" (modifying the value
  237. * in the entry). This is OK, since this is the only user
  238. * of this copy of the entry.
  239. */
  240. slapi_dn_normalize_case(dn);
  241. #ifdef DEBUG
  242. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  243. "SEARCH entry dn=%s\n", dn);
  244. #endif
  245. /*
  246. * It is a Constraint Violation if any entry is found, unless
  247. * the entry is the target entry (if any).
  248. */
  249. if (!target || strcmp(dn, target) != 0)
  250. {
  251. result = LDAP_CONSTRAINT_VIOLATION;
  252. break;
  253. }
  254. }
  255. #ifdef DEBUG
  256. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  257. "SEARCH complete result=%d\n", result);
  258. #endif
  259. END
  260. /* Clean-up */
  261. if (spb) {
  262. slapi_free_search_results_internal(spb);
  263. slapi_pblock_destroy(spb);
  264. }
  265. slapi_ch_free((void**)&filter);
  266. return result;
  267. }
  268. /* ------------------------------------------------------------ */
  269. /*
  270. * searchAllSubtrees - search all subtrees in argv for entries
  271. * with a named attribute matching the list of values, by
  272. * calling search for each one.
  273. *
  274. * If 'attr' is NULL, the values are taken from 'values'.
  275. * If 'attr' is non-NULL, the values are taken from 'attr'.
  276. *
  277. * Return:
  278. * LDAP_SUCCESS - no matches, or the attribute matches the
  279. * target dn.
  280. * LDAP_CONSTRAINT_VIOLATION - an entry was found that already
  281. * contains the attribute value.
  282. * LDAP_OPERATIONS_ERROR - a server failure.
  283. */
  284. static int
  285. searchAllSubtrees(int argc, char *argv[], const char *attrName,
  286. Slapi_Attr *attr, struct berval **values, const char *dn)
  287. {
  288. int result = LDAP_SUCCESS;
  289. /*
  290. * For each DN in the managed list, do uniqueness checking if
  291. * the target DN is a subnode in the tree.
  292. */
  293. for(;argc > 0;argc--,argv++)
  294. {
  295. result = search(*argv, attrName, attr, values, dn);
  296. if (result) break;
  297. }
  298. return result;
  299. }
  300. /* ------------------------------------------------------------ */
  301. /*
  302. * getArguments - parse invocation parameters
  303. * Return:
  304. * 0 - success
  305. * >0 - error parsing parameters
  306. */
  307. static int
  308. getArguments(Slapi_PBlock *pb, char **attrName, char **markerObjectClass,
  309. char **requiredObjectClass)
  310. {
  311. int argc;
  312. char **argv;
  313. /*
  314. * Get the arguments
  315. */
  316. if (slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc))
  317. {
  318. return uid_op_error(10);
  319. }
  320. if (slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv))
  321. {
  322. return uid_op_error(11);
  323. }
  324. /*
  325. * Required arguments: attribute and markerObjectClass
  326. * Optional argument: requiredObjectClass
  327. */
  328. for(;argc > 0;argc--,argv++)
  329. {
  330. char *param = *argv;
  331. char *delimiter = strchr(param, '=');
  332. if (NULL == delimiter)
  333. {
  334. /* Old style untagged parameter */
  335. *attrName = *argv;
  336. return UNTAGGED_PARAMETER;
  337. }
  338. if (strncasecmp(param, "attribute", delimiter-param) == 0)
  339. {
  340. /* It's OK to set a pointer here, because ultimately it points
  341. * inside the argv array of the pblock, which will be staying
  342. * arround.
  343. */
  344. *attrName = delimiter+1;
  345. } else if (strncasecmp(param, "markerobjectclass", delimiter-param) == 0)
  346. {
  347. *markerObjectClass = delimiter+1;
  348. } else if (strncasecmp(param, "requiredobjectclass", delimiter-param) == 0)
  349. {
  350. *requiredObjectClass = delimiter+1;
  351. }
  352. }
  353. if (!*attrName || !*markerObjectClass)
  354. {
  355. return uid_op_error(13);
  356. }
  357. return 0;
  358. }
  359. /* ------------------------------------------------------------ */
  360. /*
  361. * findSubtreeAndSearch - walk up the tree to find an entry with
  362. * the marker object class; if found, call search from there and
  363. * return the result it returns
  364. *
  365. * If 'attr' is NULL, the values are taken from 'values'.
  366. * If 'attr' is non-NULL, the values are taken from 'attr'.
  367. *
  368. * Return:
  369. * LDAP_SUCCESS - no matches, or the attribute matches the
  370. * target dn.
  371. * LDAP_CONSTRAINT_VIOLATION - an entry was found that already
  372. * contains the attribute value.
  373. * LDAP_OPERATIONS_ERROR - a server failure.
  374. */
  375. static int
  376. findSubtreeAndSearch(char *parentDN, const char *attrName, Slapi_Attr *attr,
  377. struct berval **values, const char *target, const char *markerObjectClass)
  378. {
  379. int result = LDAP_SUCCESS;
  380. Slapi_PBlock *spb = NULL;
  381. while (NULL != (parentDN = slapi_dn_parent(parentDN)))
  382. {
  383. if (spb = dnHasObjectClass(parentDN, markerObjectClass))
  384. {
  385. freePblock(spb);
  386. /*
  387. * Do the search. There is no entry that is allowed
  388. * to have the attribute already.
  389. */
  390. result = search(parentDN, attrName, attr, values, target);
  391. break;
  392. }
  393. }
  394. return result;
  395. }
  396. /* ------------------------------------------------------------ */
  397. /*
  398. * preop_add - pre-operation plug-in for add
  399. */
  400. static int
  401. preop_add(Slapi_PBlock *pb)
  402. {
  403. int result;
  404. #ifdef DEBUG
  405. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "ADD begin\n");
  406. #endif
  407. result = LDAP_SUCCESS;
  408. /*
  409. * Do constraint check on the added entry. Set result.
  410. */
  411. BEGIN
  412. int err;
  413. char *attrName = NULL;
  414. char *markerObjectClass = NULL;
  415. char *requiredObjectClass = NULL;
  416. char *dn;
  417. int isupdatedn;
  418. Slapi_Entry *e;
  419. Slapi_Attr *attr;
  420. int argc;
  421. char **argv = NULL;
  422. /*
  423. * If this is a replication update, just be a noop.
  424. */
  425. err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &isupdatedn);
  426. if (err) { result = uid_op_error(50); break; }
  427. if (isupdatedn)
  428. {
  429. break;
  430. }
  431. /*
  432. * Get the arguments
  433. */
  434. result = getArguments(pb, &attrName, &markerObjectClass,
  435. &requiredObjectClass);
  436. if (UNTAGGED_PARAMETER == result)
  437. {
  438. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  439. "ADD parameter untagged: %s\n", attrName);
  440. result = LDAP_SUCCESS;
  441. /* Statically defined subtrees to monitor */
  442. err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
  443. if (err) { result = uid_op_error(53); break; }
  444. err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
  445. if (err) { result = uid_op_error(54); break; }
  446. argc--; argv++; /* First argument was attribute name */
  447. } else if (0 != result)
  448. {
  449. break;
  450. }
  451. /*
  452. * Get the target DN for this add operation
  453. */
  454. err = slapi_pblock_get(pb, SLAPI_ADD_TARGET, &dn);
  455. if (err) { result = uid_op_error(51); break; }
  456. #ifdef DEBUG
  457. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "ADD target=%s\n", dn);
  458. #endif
  459. /*
  460. * Get the entry data for this add. Check whether it
  461. * contains a value for the unique attribute
  462. */
  463. err = slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e);
  464. if (err) { result = uid_op_error(52); break; }
  465. err = slapi_entry_attr_find(e, attrName, &attr);
  466. if (err) break; /* no unique attribute */
  467. /*
  468. * Check if it contains the required object class
  469. */
  470. if (NULL != requiredObjectClass)
  471. {
  472. if (!entryHasObjectClass(pb, e, requiredObjectClass))
  473. {
  474. /* No, so we don't have to do anything */
  475. break;
  476. }
  477. }
  478. /*
  479. * Passed all the requirements - this is an operation we
  480. * need to enforce uniqueness on. Now find all parent entries
  481. * with the marker object class, and do a search for each one.
  482. */
  483. if (NULL != markerObjectClass)
  484. {
  485. /* Subtree defined by location of marker object class */
  486. result = findSubtreeAndSearch(dn, attrName, attr, NULL,
  487. dn, markerObjectClass);
  488. } else
  489. {
  490. /* Subtrees listed on invocation line */
  491. result = searchAllSubtrees(argc, argv, attrName, attr, NULL, dn);
  492. }
  493. END
  494. if (result)
  495. {
  496. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  497. "ADD result %d\n", result);
  498. /* Send failure to the client */
  499. slapi_send_ldap_result(pb, result, 0, moreInfo, 0, 0);
  500. }
  501. return (result==LDAP_SUCCESS)?0:-1;
  502. }
  503. static void
  504. addMod(LDAPMod ***modary, int *capacity, int *nmods, LDAPMod *toadd)
  505. {
  506. if (*nmods == *capacity) {
  507. *capacity += 4;
  508. if (*modary) {
  509. *modary = (LDAPMod **)slapi_ch_realloc((char *)*modary, *capacity * sizeof(LDAPMod *));
  510. } else {
  511. *modary = (LDAPMod **)slapi_ch_malloc(*capacity * sizeof(LDAPMod *));
  512. }
  513. }
  514. *modary[*nmods] = toadd;
  515. (*nmods)++;
  516. }
  517. /* ------------------------------------------------------------ */
  518. /*
  519. * preop_modify - pre-operation plug-in for modify
  520. */
  521. static int
  522. preop_modify(Slapi_PBlock *pb)
  523. {
  524. int result = LDAP_SUCCESS;
  525. Slapi_PBlock *spb = NULL;
  526. LDAPMod **checkmods = NULL;
  527. int checkmodsCapacity = 0;
  528. #ifdef DEBUG
  529. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  530. "MODIFY begin\n");
  531. #endif
  532. BEGIN
  533. int err;
  534. char *attrName;
  535. char *markerObjectClass=NULL;
  536. char *requiredObjectClass=NULL;
  537. LDAPMod **mods;
  538. int modcount = 0;
  539. int ii;
  540. LDAPMod *mod;
  541. char *dn;
  542. int isupdatedn;
  543. int argc;
  544. char **argv = NULL;
  545. /*
  546. * If this is a replication update, just be a noop.
  547. */
  548. err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &isupdatedn);
  549. if (err) { result = uid_op_error(60); break; }
  550. if (isupdatedn)
  551. {
  552. break;
  553. }
  554. /*
  555. * Get the arguments
  556. */
  557. result = getArguments(pb, &attrName, &markerObjectClass,
  558. &requiredObjectClass);
  559. if (UNTAGGED_PARAMETER == result)
  560. {
  561. result = LDAP_SUCCESS;
  562. /* Statically defined subtrees to monitor */
  563. err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
  564. if (err) { result = uid_op_error(53); break; }
  565. err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
  566. if (err) { result = uid_op_error(54); break; }
  567. argc--; /* First argument was attribute name */
  568. argv++;
  569. } else if (0 != result)
  570. {
  571. break;
  572. }
  573. err = slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  574. if (err) { result = uid_op_error(61); break; }
  575. /* There may be more than one mod that matches e.g.
  576. changetype: modify
  577. delete: uid
  578. uid: balster1950
  579. -
  580. add: uid
  581. uid: scottg
  582. So, we need to first find all mods that contain the attribute
  583. which are add or replace ops and are bvalue encoded
  584. */
  585. /* find out how many mods meet this criteria */
  586. for(;*mods;mods++)
  587. {
  588. mod = *mods;
  589. if ((slapi_attr_type_cmp(mod->mod_type, attrName, 1) == 0) && /* mod contains target attr */
  590. (mod->mod_op & LDAP_MOD_BVALUES) && /* mod is bval encoded (not string val) */
  591. (mod->mod_bvalues && mod->mod_bvalues[0]) && /* mod actually contains some values */
  592. (((mod->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) || /* mod is add */
  593. (mod->mod_op & LDAP_MOD_REPLACE))) /* mod is replace */
  594. {
  595. addMod(&checkmods, &checkmodsCapacity, &modcount, mod);
  596. }
  597. }
  598. if (modcount == 0) {
  599. break; /* no mods to check, we are done */
  600. }
  601. /* Get the target DN */
  602. err = slapi_pblock_get(pb, SLAPI_MODIFY_TARGET, &dn);
  603. if (err) { result = uid_op_error(11); break; }
  604. if (requiredObjectClass &&
  605. !(spb = dnHasObjectClass(dn, requiredObjectClass))) { break; }
  606. /*
  607. * Passed all the requirements - this is an operation we
  608. * need to enforce uniqueness on. Now find all parent entries
  609. * with the marker object class, and do a search for each one.
  610. */
  611. /*
  612. * stop checking at first mod that fails the check
  613. */
  614. for (ii = 0; (result == 0) && (ii < modcount); ++ii)
  615. {
  616. mod = checkmods[ii];
  617. if (NULL != markerObjectClass)
  618. {
  619. /* Subtree defined by location of marker object class */
  620. result = findSubtreeAndSearch(dn, attrName, NULL,
  621. mod->mod_bvalues, dn,
  622. markerObjectClass);
  623. } else
  624. {
  625. /* Subtrees listed on invocation line */
  626. result = searchAllSubtrees(argc, argv, attrName, NULL,
  627. mod->mod_bvalues, dn);
  628. }
  629. }
  630. END
  631. slapi_ch_free((void **)&checkmods);
  632. freePblock(spb);
  633. if (result)
  634. {
  635. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  636. "MODIFY result %d\n", result);
  637. slapi_send_ldap_result(pb, result, 0, moreInfo, 0, 0);
  638. }
  639. return (result==LDAP_SUCCESS)?0:-1;
  640. }
  641. /* ------------------------------------------------------------ */
  642. /*
  643. * preop_modrdn - Pre-operation call for modify RDN
  644. *
  645. * Check that the new RDN does not include attributes that
  646. * cause a constraint violation
  647. */
  648. static int
  649. preop_modrdn(Slapi_PBlock *pb)
  650. {
  651. int result;
  652. Slapi_Entry *e;
  653. #ifdef DEBUG
  654. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  655. "MODRDN begin\n");
  656. #endif
  657. /* Init */
  658. result = LDAP_SUCCESS;
  659. e = 0;
  660. BEGIN
  661. int err;
  662. char *attrName;
  663. char *markerObjectClass=NULL;
  664. char *requiredObjectClass=NULL;
  665. char *dn;
  666. char *superior;
  667. char *rdn;
  668. int isupdatedn;
  669. Slapi_Attr *attr;
  670. int argc;
  671. char **argv = NULL;
  672. /*
  673. * If this is a replication update, just be a noop.
  674. */
  675. err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &isupdatedn);
  676. if (err) { result = uid_op_error(30); break; }
  677. if (isupdatedn)
  678. {
  679. break;
  680. }
  681. /*
  682. * Get the arguments
  683. */
  684. result = getArguments(pb, &attrName, &markerObjectClass,
  685. &requiredObjectClass);
  686. if (UNTAGGED_PARAMETER == result)
  687. {
  688. result = LDAP_SUCCESS;
  689. /* Statically defined subtrees to monitor */
  690. err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
  691. if (err) { result = uid_op_error(53); break; }
  692. err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
  693. if (err) { result = uid_op_error(54); break; }
  694. argc--; /* First argument was attribute name */
  695. argv++;
  696. } else if (0 != result)
  697. {
  698. break;
  699. }
  700. /* Get the DN of the entry being renamed */
  701. err = slapi_pblock_get(pb, SLAPI_MODRDN_TARGET, &dn);
  702. if (err) { result = uid_op_error(31); break; }
  703. /* Get superior value - unimplemented in 3.0/4.0/5.0 DS */
  704. err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR, &superior);
  705. if (err) { result = uid_op_error(32); break; }
  706. /*
  707. * No superior means the entry is just renamed at
  708. * its current level in the tree. Use the target DN for
  709. * determining which managed tree this belongs to
  710. */
  711. if (!superior) superior = dn;
  712. /* Get the new RDN - this has the attribute values */
  713. err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &rdn);
  714. if (err) { result = uid_op_error(33); break; }
  715. #ifdef DEBUG
  716. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  717. "MODRDN newrdn=%s\n", rdn);
  718. #endif
  719. /*
  720. * Parse the RDN into attributes by creating a "dummy" entry
  721. * and setting the attributes from the RDN.
  722. *
  723. * The new entry must be freed.
  724. */
  725. e = slapi_entry_alloc();
  726. if (!e) { result = uid_op_error(34); break; }
  727. /* NOTE: strdup on the rdn, since it will be freed when
  728. * the entry is freed */
  729. slapi_entry_set_dn(e, slapi_ch_strdup(rdn));
  730. err = slapi_entry_add_rdn_values(e);
  731. if (err)
  732. {
  733. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  734. "MODRDN bad rdn value=%s\n", rdn);
  735. break; /* Bad DN */
  736. }
  737. /*
  738. * Find any unique attribute data in the new RDN
  739. */
  740. err = slapi_entry_attr_find(e, attrName, &attr);
  741. if (err) break; /* no UID attribute */
  742. /*
  743. * Passed all the requirements - this is an operation we
  744. * need to enforce uniqueness on. Now find all parent entries
  745. * with the marker object class, and do a search for each one.
  746. */
  747. if (NULL != markerObjectClass)
  748. {
  749. /* Subtree defined by location of marker object class */
  750. result = findSubtreeAndSearch(dn, attrName, attr, NULL, dn,
  751. markerObjectClass);
  752. } else
  753. {
  754. /* Subtrees listed on invocation line */
  755. result = searchAllSubtrees(argc, argv, attrName, attr, NULL, dn);
  756. }
  757. END
  758. /* Clean-up */
  759. if (e) slapi_entry_free(e);
  760. if (result)
  761. {
  762. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  763. "MODRDN result %d\n", result);
  764. slapi_send_ldap_result(pb, result, 0, moreInfo, 0, 0);
  765. }
  766. return (result==LDAP_SUCCESS)?0:-1;
  767. }
  768. /* ------------------------------------------------------------ */
  769. /*
  770. * Initialize the plugin
  771. *
  772. * uidunique_init (the old name) is deprecated
  773. */
  774. int
  775. NSUniqueAttr_Init(Slapi_PBlock *pb)
  776. {
  777. int err = 0;
  778. BEGIN
  779. int err;
  780. int argc;
  781. char **argv;
  782. /* Declare plugin version */
  783. err = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
  784. SLAPI_PLUGIN_VERSION_01);
  785. if (err) break;
  786. /*
  787. * Get plugin identity and store it for later use
  788. * Used for internal operations
  789. */
  790. slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
  791. /* PR_ASSERT (plugin_identity); */
  792. /*
  793. * Get and normalize arguments
  794. */
  795. err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
  796. if (err) break;
  797. err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
  798. if (err) break;
  799. /* First argument is the unique attribute name */
  800. if (argc < 1) { err = -1; break; }
  801. argv++; argc--;
  802. for(;argc > 0;argc--, argv++)
  803. slapi_dn_normalize_case(*argv);
  804. /* Provide descriptive information */
  805. err = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
  806. (void*)&pluginDesc);
  807. if (err) break;
  808. /* Register functions */
  809. err = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_ADD_FN,
  810. (void*)preop_add);
  811. if (err) break;
  812. err = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODIFY_FN,
  813. (void*)preop_modify);
  814. if (err) break;
  815. err = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODRDN_FN,
  816. (void*)preop_modrdn);
  817. if (err) break;
  818. END
  819. if (err) {
  820. slapi_log_error(SLAPI_LOG_PLUGIN, "NSUniqueAttr_Init",
  821. "Error: %d\n", err);
  822. err = -1;
  823. }
  824. else
  825. slapi_log_error(SLAPI_LOG_PLUGIN, "NSUniqueAttr_Init",
  826. "plugin loaded\n");
  827. return err;
  828. }
  829. int
  830. uidunique_init(Slapi_PBlock *pb)
  831. {
  832. return NSUniqueAttr_Init(pb);
  833. }
  834. /* ------------------------------------------------------------ */
  835. /*
  836. * ldap_quote_filter_value
  837. *
  838. * Quote the filter value according to RFC 2254 (Dec 1997)
  839. *
  840. * value - a UTF8 string containing the value. It may contain
  841. * any of the chars needing quotes ( '(' ')' '*' '/' and NUL ).
  842. * len - the length of the UTF8 value
  843. * out - a buffer to recieve the converted value. May be NULL, in
  844. * which case, only the length of the output is computed (and placed in
  845. * outLen).
  846. * maxLen - the size of the output buffer. It is an error if this length
  847. * is exceeded. Ignored if out is NULL.
  848. * outLen - recieves the size of the output. If an error occurs, this
  849. * result is not available.
  850. *
  851. * Returns
  852. * 0 - success
  853. * -1 - failure (usually a buffer overflow)
  854. */
  855. int /* Error value */
  856. ldap_quote_filter_value(
  857. char *value, int len,
  858. char *out, int maxLen,
  859. int *outLen)
  860. {
  861. int err;
  862. char *eValue;
  863. int resLen;
  864. #ifdef SLAPI_SUPPORTS_V3_ESCAPING
  865. static char hexchars[16] = "0123456789abcdef";
  866. #endif
  867. err = 0;
  868. eValue = &value[len];
  869. resLen = 0;
  870. /*
  871. * Convert each character in the input string
  872. */
  873. while(value < eValue)
  874. {
  875. switch(*value)
  876. {
  877. case '(':
  878. case ')':
  879. case '*':
  880. case '\\':
  881. #ifdef SLAPI_SUPPORTS_V3_ESCAPING
  882. case 0:
  883. #endif
  884. /* Handle characters needing special escape sequences */
  885. /* Compute size of output */
  886. #ifdef SLAPI_SUPPORTS_V3_ESCAPING
  887. resLen += 3;
  888. #else
  889. resLen += 2;
  890. #endif
  891. /* Generate output if requested */
  892. if (out)
  893. {
  894. /* Check for overflow */
  895. if (resLen > maxLen) { err = -1; break; }
  896. *out++ = '\\';
  897. #ifdef SLAPI_SUPPORTS_V3_ESCAPING
  898. *out++ = hexchars[(*value >> 4) & 0xF];
  899. *out++ = hexchars[*value & 0xF];
  900. #else
  901. *out++ = *value;
  902. #endif
  903. }
  904. break;
  905. default:
  906. /* Compute size of output */
  907. resLen += 1;
  908. /* Generate output if requested */
  909. if (out)
  910. {
  911. if (resLen > maxLen) { err = -1; break; }
  912. *out++ = *value;
  913. }
  914. break;
  915. }
  916. if (err) break;
  917. value++;
  918. }
  919. if (!err) *outLen = resLen;
  920. return err;
  921. }