uid.c 28 KB

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