uid.c 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617
  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. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. /*
  13. * uid.c
  14. *
  15. * Implements a directory server pre-operation plugin to test
  16. * attributes for uniqueness within a defined subtree in the
  17. * directory.
  18. *
  19. * Called uid.c since the original purpose of the plugin was to
  20. * check the uid attribute in user entries.
  21. */
  22. #include <slapi-plugin.h>
  23. #include <portable.h>
  24. #include <slapi-private.h>
  25. #include <string.h>
  26. #include "plugin-utils.h"
  27. #include "nspr.h"
  28. #if defined( LDAP_ERROR_LOGGING ) && !defined( DEBUG )
  29. #define DEBUG
  30. #endif
  31. #define UNTAGGED_PARAMETER 12
  32. /* Quoting routine - this should be in a library somewhere (slapi?) */
  33. int ldap_quote_filter_value(
  34. char *value, int len,
  35. char *out, int maxLen,
  36. int *outLen);
  37. static int search_one_berval(Slapi_DN *baseDN, const char **attrNames,
  38. const struct berval *value, const char *requiredObjectClass, Slapi_DN *target, Slapi_DN **excludes);
  39. /*
  40. * ISSUES:
  41. * How should this plugin handle ACL issues? It seems wrong to reject
  42. * adds and modifies because there is already a conflicting UID, when
  43. * the request would have failed because of an ACL check anyway.
  44. *
  45. * This code currently defines a maximum filter string size of 512. Is
  46. * this large enough?
  47. *
  48. * This code currently does not quote the value portion of the filter as
  49. * it is created. This is a bug.
  50. */
  51. /* */
  52. #define BEGIN do {
  53. #define END } while(0);
  54. /*
  55. * Slapi plugin descriptor
  56. */
  57. static char *plugin_name = "NSUniqueAttr";
  58. static Slapi_PluginDesc
  59. pluginDesc = {
  60. "NSUniqueAttr", VENDOR, DS_PACKAGE_VERSION,
  61. "Enforce unique attribute values"
  62. };
  63. static void* plugin_identity = NULL;
  64. typedef struct attr_uniqueness_config {
  65. const char **attrs;
  66. char *attr_friendly;
  67. Slapi_DN **subtrees;
  68. Slapi_DN **exclude_subtrees;
  69. PRBool unique_in_all_subtrees;
  70. char *top_entry_oc;
  71. char *subtree_entries_oc;
  72. struct attr_uniqueness_config *next;
  73. } attr_uniqueness_config_t;
  74. #define ATTR_UNIQUENESS_ATTRIBUTE_NAME "uniqueness-attribute-name"
  75. #define ATTR_UNIQUENESS_SUBTREES "uniqueness-subtrees"
  76. #define ATTR_UNIQUENESS_EXCLUDE_SUBTREES "uniqueness-exclude-subtrees"
  77. #define ATTR_UNIQUENESS_ACROSS_ALL_SUBTREES "uniqueness-across-all-subtrees"
  78. #define ATTR_UNIQUENESS_TOP_ENTRY_OC "uniqueness-top-entry-oc"
  79. #define ATTR_UNIQUENESS_SUBTREE_ENTRIES_OC "uniqueness-subtree-entries-oc"
  80. static int getArguments(Slapi_PBlock *pb, char **attrName, char **markerObjectClass, char **requiredObjectClass);
  81. static struct attr_uniqueness_config *uniqueness_entry_to_config(Slapi_PBlock *pb, Slapi_Entry *config_entry);
  82. /*
  83. * More information about constraint failure
  84. */
  85. static char *moreInfo =
  86. "Another entry with the same attribute value already exists (attribute: \"%s\")";
  87. static void
  88. free_uniqueness_config(struct attr_uniqueness_config *config)
  89. {
  90. int i;
  91. for (i = 0; config->attrs && config->attrs[i]; i++) {
  92. slapi_ch_free_string((char **) &(config->attrs[i]));
  93. }
  94. for (i = 0; config->subtrees && config->subtrees[i]; i++) {
  95. slapi_sdn_free(&config->subtrees[i]);
  96. }
  97. for (i = 0; config->exclude_subtrees && config->exclude_subtrees[i]; i++) {
  98. slapi_sdn_free(&config->exclude_subtrees[i]);
  99. }
  100. slapi_ch_free((void **) &config->attrs);
  101. slapi_ch_free((void **) &config->subtrees);
  102. slapi_ch_free((void **) &config->exclude_subtrees);
  103. slapi_ch_free_string(&config->attr_friendly);
  104. slapi_ch_free_string((char **) &config->top_entry_oc);
  105. slapi_ch_free_string((char **) &config->subtree_entries_oc);
  106. }
  107. /*
  108. * New styles:
  109. * ----------
  110. *
  111. * uniqueness-attribute-name: uid
  112. * uniqueness-subtrees: dc=people,dc=example,dc=com
  113. * uniqueness-subtrees: dc=sales, dc=example,dc=com
  114. * uniqueness-exclude-subtrees: dc=machines, dc=examples, dc=com
  115. * uniqueness-across-all-subtrees: on
  116. *
  117. * or
  118. *
  119. * uniqueness-attribute-name: uid
  120. * uniqueness-top-entry-oc: organizationalUnit
  121. * uniqueness-subtree-entries-oc: person
  122. *
  123. * If both are present:
  124. * - uniqueness-subtrees
  125. * - uniqueness-top-entry-oc/uniqueness-subtree-entries-oc
  126. * Then uniqueness-subtrees has the priority
  127. *
  128. * Old styles:
  129. * ----------
  130. *
  131. * nsslapd-pluginarg0: uid
  132. * nsslapd-pluginarg1: dc=people,dc=example,dc=com
  133. * nsslapd-pluginarg2: dc=sales, dc=example,dc=com
  134. *
  135. * or
  136. *
  137. * nsslapd-pluginarg0: attribute=uid
  138. * nsslapd-pluginarg1: markerobjectclass=organizationalUnit
  139. * nsslapd-pluginarg2: requiredobjectclass=person
  140. *
  141. * From a Slapi_Entry of the config entry, it creates a attr_uniqueness_config.
  142. * It returns a (attr_uniqueness_config *) if the configuration is valid
  143. * Else it returns NULL
  144. */
  145. static struct attr_uniqueness_config *
  146. uniqueness_entry_to_config(Slapi_PBlock *pb, Slapi_Entry *config_entry)
  147. {
  148. attr_uniqueness_config_t *tmp_config = NULL;
  149. char **values = NULL;
  150. int argc;
  151. char **argv = NULL;
  152. int rc = SLAPI_PLUGIN_SUCCESS;
  153. int i;
  154. int attrLen = 0;
  155. char *fp;
  156. int nb_subtrees = 0;
  157. if (config_entry == NULL) {
  158. rc = SLAPI_PLUGIN_FAILURE;
  159. goto done;
  160. }
  161. /* We are going to fill tmp_config in a first phase */
  162. if ((tmp_config = (attr_uniqueness_config_t *) slapi_ch_calloc(1, sizeof (attr_uniqueness_config_t))) == NULL) {
  163. slapi_log_err(SLAPI_LOG_ERR, plugin_name, "uniqueness_entry_to_config - "
  164. "Failed to allocate configuration\n");
  165. rc = SLAPI_PLUGIN_FAILURE;
  166. goto done;
  167. } else {
  168. /* set these to -1 for config validation */
  169. }
  170. /* Check if this is new/old config style */
  171. slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
  172. if (argc == 0) {
  173. /* This is new config style
  174. * uniqueness-attribute-name: uid
  175. * uniqueness-subtrees: dc=people,dc=example,dc=com
  176. * uniqueness-subtrees: dc=sales, dc=example,dc=com
  177. * uniqueness-across-all-subtrees: on
  178. *
  179. * or
  180. *
  181. * uniqueness-attribute-name: uid
  182. * uniqueness-top-entry-oc: organizationalUnit
  183. * uniqueness-subtree-entries-oc: person
  184. */
  185. /* Attribute name of the attribute we are going to check value uniqueness */
  186. values = slapi_entry_attr_get_charray(config_entry, ATTR_UNIQUENESS_ATTRIBUTE_NAME);
  187. if (values) {
  188. for (i = 0; values && values[i]; i++);
  189. tmp_config->attrs = (const char **) slapi_ch_calloc(i + 1, sizeof(char *));
  190. for (i = 0; values && values[i]; i++) {
  191. tmp_config->attrs[i] = slapi_ch_strdup(values[i]);
  192. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name, "uniqueness_entry_to_config - "
  193. "Adding attribute %s to uniqueness set\n", tmp_config->attrs[i]);
  194. }
  195. slapi_ch_array_free(values);
  196. values = NULL;
  197. }
  198. /* Subtrees where uniqueness is tested */
  199. values = slapi_entry_attr_get_charray(config_entry, ATTR_UNIQUENESS_SUBTREES);
  200. if (values) {
  201. for (i = 0; values && values[i]; i++);
  202. /* slapi_ch_calloc never returns NULL unless the 2 args are 0 or negative. */
  203. tmp_config->subtrees = (Slapi_DN **) slapi_ch_calloc(i + 1, sizeof (Slapi_DN *));
  204. /* copy the valid subtree DN into the config */
  205. for (i = 0, nb_subtrees = 0; values && values[i]; i++) {
  206. if (slapi_dn_syntax_check(pb, values[i], 1)) { /* syntax check failed */
  207. slapi_log_err(SLAPI_LOG_ERR, plugin_name, "uniqueness_entry_to_config - "
  208. "Invalid DN (skipped): %s\n", values[i]);
  209. continue;
  210. }
  211. tmp_config->subtrees[nb_subtrees] = slapi_sdn_new_dn_byval(values[i]);
  212. nb_subtrees++;
  213. }
  214. slapi_ch_array_free(values);
  215. values = NULL;
  216. }
  217. /* Subtrees where uniqueness is explicitly ignored */
  218. values = slapi_entry_attr_get_charray(config_entry, ATTR_UNIQUENESS_EXCLUDE_SUBTREES);
  219. if (values) {
  220. for (i = 0; values && values[i]; i++);
  221. /* slapi_ch_calloc never returns NULL unless the 2 args are 0 or negative. */
  222. tmp_config->exclude_subtrees = (Slapi_DN **) slapi_ch_calloc(i + 1, sizeof (Slapi_DN *));
  223. /* copy the valid subtree DN into the config */
  224. for (i = 0, nb_subtrees = 0; values && values[i]; i++) {
  225. if (slapi_dn_syntax_check(pb, values[i], 1)) { /* syntax check failed */
  226. slapi_log_err(SLAPI_LOG_ERR, plugin_name, "uniqueness_entry_to_config - "
  227. "Invalid DN (skipped): %s\n", values[i]);
  228. continue;
  229. }
  230. tmp_config->exclude_subtrees[nb_subtrees] = slapi_sdn_new_dn_byval(values[i]);
  231. nb_subtrees++;
  232. }
  233. slapi_ch_array_free(values);
  234. values = NULL;
  235. }
  236. /* Uniqueness may be enforced accross all the subtrees, by default it is not */
  237. tmp_config->unique_in_all_subtrees = slapi_entry_attr_get_bool(config_entry, ATTR_UNIQUENESS_ACROSS_ALL_SUBTREES);
  238. /* enforce uniqueness only if the modified entry has this objectclass */
  239. tmp_config->top_entry_oc = slapi_entry_attr_get_charptr(config_entry, ATTR_UNIQUENESS_TOP_ENTRY_OC);
  240. /* enforce uniqueness, in the modified entry subtree, only to entries having this objectclass */
  241. tmp_config->subtree_entries_oc = slapi_entry_attr_get_charptr(config_entry, ATTR_UNIQUENESS_SUBTREE_ENTRIES_OC);
  242. } else {
  243. int result;
  244. char *attrName = NULL;
  245. char *markerObjectClass = NULL;
  246. char *requiredObjectClass = NULL;
  247. /* using the old style of configuration */
  248. result = getArguments(pb, &attrName, &markerObjectClass, &requiredObjectClass);
  249. if (LDAP_OPERATIONS_ERROR == result) {
  250. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name, "uniqueness_entry_to_config - "
  251. "Unable to parse old style\n");
  252. rc = SLAPI_PLUGIN_FAILURE;
  253. goto done;
  254. }
  255. if (UNTAGGED_PARAMETER == result) {
  256. /* This is
  257. * nsslapd-pluginarg0: uid
  258. * nsslapd-pluginarg1: dc=people,dc=example,dc=com
  259. * nsslapd-pluginarg2: dc=sales, dc=example,dc=com
  260. *
  261. * config attribute are in argc/argv
  262. *
  263. * attrName is set
  264. * markerObjectClass/requiredObjectClass are NOT set
  265. */
  266. if (slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc) || slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv)) {
  267. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name, "uniqueness_entry_to_config - "
  268. "Only attribute name is valid\n");
  269. rc = SLAPI_PLUGIN_FAILURE;
  270. goto done;
  271. }
  272. /* Store attrName in the config */
  273. tmp_config->attrs = (const char **) slapi_ch_calloc(2, sizeof(char *));
  274. tmp_config->attrs[0] = slapi_ch_strdup(attrName);
  275. argc--;
  276. argv++; /* First argument was attribute name and remaining are subtrees */
  277. /* Store the subtrees */
  278. nb_subtrees = 0;
  279. if ((tmp_config->subtrees = (Slapi_DN **) slapi_ch_calloc(argc + 1, sizeof (Slapi_DN *))) == NULL) {
  280. slapi_log_err(SLAPI_LOG_ERR, plugin_name, "uniqueness_entry_to_config - "
  281. "Fail to allocate subtree array\n");
  282. rc = SLAPI_PLUGIN_FAILURE;
  283. goto done;
  284. }
  285. for (; argc > 0; argc--, argv++) {
  286. if (slapi_dn_syntax_check(pb, *argv, 1)) { /* syntax check failed */
  287. slapi_log_err(SLAPI_LOG_ERR, plugin_name, "uniqueness_entry_to_config - "
  288. "Invalid DN (skipped): %s\n", *argv);
  289. continue;
  290. }
  291. tmp_config->subtrees[nb_subtrees] = slapi_sdn_new_dn_byval(*argv);
  292. nb_subtrees++;
  293. }
  294. /* this interface does not configure accross subtree uniqueness*/
  295. tmp_config->unique_in_all_subtrees = PR_FALSE;
  296. /* Not really usefull, but it clarifies the config */
  297. tmp_config->subtree_entries_oc = NULL;
  298. tmp_config->top_entry_oc = NULL;
  299. } else {
  300. /* This is
  301. * nsslapd-pluginarg0: attribute=uid
  302. * nsslapd-pluginarg1: markerobjectclass=organizationalUnit
  303. * nsslapd-pluginarg2: requiredobjectclass=person
  304. *
  305. * config attributes are in
  306. * - attrName
  307. * - markerObjectClass
  308. * - requiredObjectClass
  309. */
  310. /* Store attrName in the config */
  311. tmp_config->attrs = (const char **) slapi_ch_calloc(2, sizeof(char *));
  312. tmp_config->attrs[0] = slapi_ch_strdup(attrName);
  313. /* There is no subtrees */
  314. tmp_config->subtrees = NULL;
  315. /* this interface does not configure accross subtree uniqueness*/
  316. tmp_config->unique_in_all_subtrees = PR_FALSE;
  317. /* set the objectclasses retrieved by getArgument */
  318. tmp_config->subtree_entries_oc = slapi_ch_strdup(requiredObjectClass);
  319. tmp_config->top_entry_oc = slapi_ch_strdup(markerObjectClass);
  320. }
  321. }
  322. /* Time to check that the new configuration is valid */
  323. /* Check that we have 1 or more value */
  324. if (tmp_config->attrs == NULL) {
  325. slapi_log_err(SLAPI_LOG_ERR, plugin_name, "uniqueness_entry_to_config - Attribute name not defined \n");
  326. rc = SLAPI_PLUGIN_FAILURE;
  327. goto done;
  328. }
  329. /* If the config is valid, prepare the friendly string for error messages */
  330. for (i = 0; tmp_config->attrs && (tmp_config->attrs)[i]; i++) {
  331. attrLen += strlen((tmp_config->attrs)[i]) + 1;
  332. }
  333. tmp_config->attr_friendly = (char *) slapi_ch_calloc(attrLen + 1, sizeof(char));
  334. fp = tmp_config->attr_friendly;
  335. for (i = 0; tmp_config->attrs && (tmp_config->attrs)[i]; i++) {
  336. strcpy(fp, (tmp_config->attrs)[i] );
  337. fp += strlen((tmp_config->attrs)[i]);
  338. strcpy(fp, " ");
  339. fp++;
  340. }
  341. /* Only ensure subtrees are set, no need to check excluded subtrees as setting exclusion without actual subtrees make little sense */
  342. if (tmp_config->subtrees == NULL) {
  343. /* Uniqueness is enforced on entries matching objectclass */
  344. if (tmp_config->subtree_entries_oc == NULL) {
  345. slapi_log_err(SLAPI_LOG_ERR, plugin_name, "uniqueness_entry_to_config - Objectclass for subtree entries is not defined\n");
  346. rc = SLAPI_PLUGIN_FAILURE;
  347. goto done;
  348. }
  349. } else if (tmp_config->subtrees[0] == NULL) {
  350. /* Uniqueness is enforced on subtrees but none are defined */
  351. slapi_log_err(SLAPI_LOG_ERR, plugin_name, "uniqueness_entry_to_config - No valid subtree is defined \n");
  352. rc = SLAPI_PLUGIN_FAILURE;
  353. goto done;
  354. }
  355. done:
  356. if (rc != SLAPI_PLUGIN_SUCCESS) {
  357. if (tmp_config) {
  358. free_uniqueness_config(tmp_config);
  359. slapi_ch_free((void **) &tmp_config);
  360. }
  361. return NULL;
  362. } else {
  363. return tmp_config;
  364. }
  365. }
  366. static void
  367. freePblock( Slapi_PBlock *spb ) {
  368. if ( spb )
  369. {
  370. slapi_free_search_results_internal( spb );
  371. slapi_pblock_destroy( spb );
  372. }
  373. }
  374. /* ------------------------------------------------------------ */
  375. /*
  376. * op_error - Record (and report) an operational error.
  377. * name changed to uid_op_error so as not to conflict with the external function
  378. * of the same name thereby preventing compiler warnings.
  379. */
  380. static int
  381. uid_op_error(int internal_error)
  382. {
  383. slapi_log_err(
  384. SLAPI_LOG_PLUGIN,
  385. plugin_name,
  386. "Internal error: %d\n",
  387. internal_error);
  388. return LDAP_OPERATIONS_ERROR;
  389. }
  390. /* ------------------------------------------------------------ */
  391. /*
  392. * Create an LDAP search filter from the attribute
  393. * name and value supplied.
  394. */
  395. static char *
  396. create_filter(const char **attributes, const struct berval *value, const char *requiredObjectClass)
  397. {
  398. char *filter;
  399. char *fp;
  400. char *max;
  401. int *attrLen;
  402. int totalAttrLen = 0;
  403. int attrCount = 0;
  404. int valueLen;
  405. int classLen = 0;
  406. int filterLen;
  407. int i = 0;
  408. PR_ASSERT(attributes);
  409. /* Compute the length of the required buffer */
  410. for (attrCount = 0; attributes && attributes[attrCount]; attrCount++);
  411. attrCount++;
  412. attrLen = (int *) slapi_ch_calloc(attrCount, sizeof(int));
  413. for (i = 0; attributes && attributes[i]; i++) {
  414. attrLen[i] += strlen(attributes[i]);
  415. totalAttrLen += attrLen[i];
  416. }
  417. /* if attrCount is 1, attrLen is already corect for usage.*/
  418. if (attrCount > 1) {
  419. /* Filter will be (|(attr=value)(attr=value)) */
  420. /* 3 for the (| ) */
  421. /* 3 for each attr for (=) not in attr or value */
  422. totalAttrLen += 3 + (attrCount * 3);
  423. } else {
  424. totalAttrLen += 3;
  425. }
  426. if (ldap_quote_filter_value(value->bv_val,
  427. value->bv_len, 0, 0, &valueLen))
  428. return 0;
  429. if (requiredObjectClass) {
  430. classLen = strlen(requiredObjectClass);
  431. /* "(&(objectClass=)<Filter here>)" == 17 */
  432. filterLen = totalAttrLen + 1 + (valueLen * attrCount) + classLen + 17 + 1;
  433. } else {
  434. filterLen = totalAttrLen + 1 + (valueLen * attrCount) + 1;
  435. }
  436. /* Allocate the buffer */
  437. filter = slapi_ch_malloc(filterLen);
  438. fp = filter;
  439. max = &filter[filterLen];
  440. /* Place AND expression and objectClass in filter */
  441. if (requiredObjectClass) {
  442. strcpy(fp, "(&(objectClass=");
  443. fp += 15;
  444. strcpy(fp, requiredObjectClass);
  445. fp += classLen;
  446. *fp++ = ')';
  447. }
  448. if (attrCount == 1) {
  449. *fp++ = '(';
  450. /* Place attribute name in filter */
  451. strcpy(fp, attributes[0]);
  452. fp += attrLen[0];
  453. /* Place comparison operator */
  454. *fp++ = '=';
  455. /* Place value in filter */
  456. if (ldap_quote_filter_value(value->bv_val, value->bv_len,
  457. fp, max-fp, &valueLen)) { slapi_ch_free((void**)&filter); return 0; }
  458. fp += valueLen;
  459. *fp++ = ')';
  460. } else {
  461. strcpy(fp, "(|");
  462. fp += 2;
  463. for (i = 0; attributes && attributes[i]; i++) {
  464. strcpy(fp, "(");
  465. fp += 1;
  466. /* Place attribute name in filter */
  467. strcpy(fp, attributes[i]);
  468. fp += attrLen[i];
  469. /* Place comparison operator */
  470. *fp++ = '=';
  471. /* Place value in filter */
  472. if (ldap_quote_filter_value(value->bv_val, value->bv_len,
  473. fp, max-fp, &valueLen)) { slapi_ch_free((void**)&filter); return 0; }
  474. fp += valueLen;
  475. strcpy(fp, ")");
  476. fp += 1;
  477. }
  478. strcpy(fp, ")");
  479. fp += 1;
  480. }
  481. /* Close AND expression if a requiredObjectClass was set */
  482. if (requiredObjectClass) {
  483. *fp++ = ')';
  484. }
  485. /* Terminate */
  486. *fp = 0;
  487. slapi_ch_free((void **) &attrLen);
  488. return filter;
  489. }
  490. /* ------------------------------------------------------------ */
  491. /*
  492. * search - search a subtree for entries with a named attribute matching
  493. * the list of values. An entry matching the 'target' DN is
  494. * not considered in the search.
  495. *
  496. * If 'attr' is NULL, the values are taken from 'values'.
  497. * If 'attr' is non-NULL, the values are taken from 'attr'.
  498. *
  499. * Return:
  500. * LDAP_SUCCESS - no matches, or the attribute matches the
  501. * target dn.
  502. * LDAP_CONSTRAINT_VIOLATION - an entry was found that already
  503. * contains the attribute value.
  504. * LDAP_OPERATIONS_ERROR - a server failure.
  505. */
  506. static int
  507. search(Slapi_DN *baseDN, const char **attrNames, Slapi_Attr *attr,
  508. struct berval **values, const char *requiredObjectClass,
  509. Slapi_DN *target, Slapi_DN **excludes)
  510. {
  511. int result;
  512. #ifdef DEBUG
  513. /* Fix this later to print all the attr names */
  514. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name,
  515. "search - SEARCH baseDN=%s attr=%s target=%s\n", slapi_sdn_get_dn(baseDN), attrNames[0],
  516. target?slapi_sdn_get_dn(target):"None");
  517. #endif
  518. result = LDAP_SUCCESS;
  519. /* If no values, can't possibly be a conflict */
  520. if ( (Slapi_Attr *)NULL == attr && (struct berval **)NULL == values )
  521. return result;
  522. /*
  523. * Perform the search for each value provided
  524. *
  525. * Another possibility would be to search for all the values at once.
  526. * However, this is more complex (for filter creation) and unique
  527. * attributes values are probably only changed one at a time anyway.
  528. */
  529. if ( (Slapi_Attr *)NULL != attr )
  530. {
  531. Slapi_Value *v = NULL;
  532. int vhint = -1;
  533. for ( vhint = slapi_attr_first_value( attr, &v );
  534. vhint != -1 && LDAP_SUCCESS == result;
  535. vhint = slapi_attr_next_value( attr, vhint, &v ))
  536. {
  537. result = search_one_berval(baseDN, attrNames,
  538. slapi_value_get_berval(v),
  539. requiredObjectClass, target, excludes);
  540. }
  541. }
  542. else
  543. {
  544. for (;*values != NULL && LDAP_SUCCESS == result; values++)
  545. {
  546. result = search_one_berval(baseDN, attrNames, *values, requiredObjectClass,
  547. target, excludes);
  548. }
  549. }
  550. #ifdef DEBUG
  551. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name,
  552. "search - SEARCH result = %d\n", result);
  553. #endif
  554. return( result );
  555. }
  556. static int
  557. search_one_berval(Slapi_DN *baseDN, const char **attrNames,
  558. const struct berval *value, const char *requiredObjectClass,
  559. Slapi_DN *target, Slapi_DN **excludes)
  560. {
  561. int result;
  562. char *filter;
  563. Slapi_PBlock *spb;
  564. result = LDAP_SUCCESS;
  565. /* If no value, can't possibly be a conflict */
  566. if ( (struct berval *)NULL == value )
  567. return result;
  568. filter = 0;
  569. spb = 0;
  570. BEGIN
  571. int err;
  572. int sres;
  573. Slapi_Entry **entries;
  574. static char *attrs[] = { "1.1", 0 };
  575. /* Create the filter - this needs to be freed */
  576. filter = create_filter(attrNames, value, requiredObjectClass);
  577. #ifdef DEBUG
  578. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name,
  579. "search_one_berval - SEARCH filter=%s\n", filter);
  580. #endif
  581. /* Perform the search using the new internal API */
  582. spb = slapi_pblock_new();
  583. if (!spb) { result = uid_op_error(2); break; }
  584. slapi_search_internal_set_pb_ext(spb, baseDN, LDAP_SCOPE_SUBTREE,
  585. filter, attrs, 0 /* attrs only */, NULL, NULL, plugin_identity, 0 /* actions */);
  586. slapi_search_internal_pb(spb);
  587. err = slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_RESULT, &sres);
  588. if (err) { result = uid_op_error(3); break; }
  589. /* Allow search to report that there is nothing in the subtree */
  590. if (sres == LDAP_NO_SUCH_OBJECT) break;
  591. /* Other errors are bad */
  592. if (sres) { result = uid_op_error(3); break; }
  593. err = slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
  594. &entries);
  595. if (err) { result = uid_op_error(4); break; }
  596. /*
  597. * Look at entries returned. Any entry found must be the
  598. * target entry or the constraint fails.
  599. */
  600. for(;*entries;entries++)
  601. {
  602. #ifdef DEBUG
  603. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name,
  604. "search_one_berval - SEARCH entry dn=%s\n", slapi_entry_get_dn(*entries));
  605. #endif
  606. /*
  607. * It is a Constraint Violation if any entry is found, unless
  608. * the entry is the target entry (if any).
  609. */
  610. if (!target || slapi_sdn_compare(slapi_entry_get_sdn(*entries), target) != 0)
  611. {
  612. int i;
  613. result = LDAP_CONSTRAINT_VIOLATION;
  614. if (excludes == NULL || *excludes == NULL)
  615. {
  616. break;
  617. }
  618. /* Do the same check for excluded subtrees as resulted entries may have matched them */
  619. for (i = 0;excludes && excludes[i]; i++)
  620. {
  621. Slapi_DN *entry_dn = slapi_entry_get_sdn(*entries);
  622. if (slapi_sdn_issuffix(entry_dn, excludes[i]))
  623. {
  624. result = LDAP_SUCCESS;
  625. break;
  626. }
  627. }
  628. if (result == LDAP_CONSTRAINT_VIOLATION)
  629. {
  630. break;
  631. }
  632. }
  633. }
  634. #ifdef DEBUG
  635. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name,
  636. "search_one_berval - SEARCH complete result=%d\n", result);
  637. #endif
  638. END
  639. /* Clean-up */
  640. if (spb) {
  641. slapi_free_search_results_internal(spb);
  642. slapi_pblock_destroy(spb);
  643. }
  644. slapi_ch_free((void**)&filter);
  645. return result;
  646. }
  647. /* ------------------------------------------------------------ */
  648. /*
  649. * searchAllSubtrees - search all subtrees in argv for entries
  650. * with a named attribute matching the list of values, by
  651. * calling search for each one.
  652. *
  653. * If 'attr' is NULL, the values are taken from 'values'.
  654. * If 'attr' is non-NULL, the values are taken from 'attr'.
  655. *
  656. * Return:
  657. * LDAP_SUCCESS - no matches, or the attribute matches the
  658. * target dn.
  659. * LDAP_CONSTRAINT_VIOLATION - an entry was found that already
  660. * contains the attribute value.
  661. * LDAP_OPERATIONS_ERROR - a server failure.
  662. */
  663. static int
  664. searchAllSubtrees(Slapi_DN **subtrees, Slapi_DN **exclude_subtrees, const char **attrNames,
  665. Slapi_Attr *attr, struct berval **values, const char *requiredObjectClass,
  666. Slapi_DN *dn, PRBool unique_in_all_subtrees)
  667. {
  668. int result = LDAP_SUCCESS;
  669. int i;
  670. if (unique_in_all_subtrees) {
  671. PRBool in_a_subtree = PR_FALSE;
  672. /* we need to check that the added values of this attribute
  673. * are unique in all the monitored subtrees
  674. */
  675. /* First check the target entry is in one of
  676. * the monitored subtree, so adding 'values' would
  677. * violate constraint
  678. */
  679. for (i = 0;subtrees && subtrees[i]; i++) {
  680. if (slapi_sdn_issuffix(dn, subtrees[i])) {
  681. in_a_subtree = PR_TRUE;
  682. break;
  683. }
  684. }
  685. if (! in_a_subtree) {
  686. return result;
  687. }
  688. }
  689. /* If DN is in the excluded subtrees, we should ignore it in any case, not only
  690. * in the case of uniqueness in all subtrees. */
  691. if (exclude_subtrees != NULL)
  692. {
  693. PRBool in_a_subtree = PR_FALSE;
  694. for (i = 0;exclude_subtrees && exclude_subtrees[i]; i++) {
  695. if (slapi_sdn_issuffix(dn, exclude_subtrees[i])) {
  696. in_a_subtree = PR_TRUE;
  697. break;
  698. }
  699. }
  700. if (in_a_subtree) {
  701. return result;
  702. }
  703. }
  704. /*
  705. * For each DN in the managed list, do uniqueness checking if
  706. * the target DN is a subnode in the tree.
  707. */
  708. for(i = 0;subtrees && subtrees[i]; i++)
  709. {
  710. Slapi_DN *sufdn = subtrees[i];
  711. /*
  712. * The DN should already be normalized, so we don't have to
  713. * worry about that here.
  714. */
  715. if (unique_in_all_subtrees || slapi_sdn_issuffix(dn, sufdn)) {
  716. result = search(sufdn, attrNames, attr, values, requiredObjectClass, dn, exclude_subtrees);
  717. if (result) break;
  718. }
  719. }
  720. return result;
  721. }
  722. /* ------------------------------------------------------------ */
  723. /*
  724. * getArguments - parse invocation parameters
  725. * Return:
  726. * 0 - success
  727. * >0 - error parsing parameters
  728. */
  729. static int
  730. getArguments(Slapi_PBlock *pb, char **attrName, char **markerObjectClass,
  731. char **requiredObjectClass)
  732. {
  733. int argc;
  734. char **argv;
  735. /*
  736. * Get the arguments
  737. */
  738. if (slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc))
  739. {
  740. return uid_op_error(10);
  741. }
  742. if (slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv))
  743. {
  744. return uid_op_error(11);
  745. }
  746. /*
  747. * Required arguments: attribute and markerObjectClass
  748. * Optional argument: requiredObjectClass
  749. */
  750. for(;argc > 0;argc--,argv++)
  751. {
  752. char *param = *argv;
  753. char *delimiter = strchr(param, '=');
  754. if (NULL == delimiter)
  755. {
  756. /* Old style untagged parameter */
  757. *attrName = *argv;
  758. return UNTAGGED_PARAMETER;
  759. }
  760. if (strncasecmp(param, "attribute", delimiter-param) == 0)
  761. {
  762. /* It's OK to set a pointer here, because ultimately it points
  763. * inside the argv array of the pblock, which will be staying
  764. * arround.
  765. */
  766. *attrName = delimiter+1;
  767. } else if (strncasecmp(param, "markerobjectclass", delimiter-param) == 0)
  768. {
  769. *markerObjectClass = delimiter+1;
  770. } else if (strncasecmp(param, "requiredobjectclass", delimiter-param) == 0)
  771. {
  772. *requiredObjectClass = delimiter+1;
  773. }
  774. }
  775. if (!*attrName || !*markerObjectClass)
  776. {
  777. return uid_op_error(13);
  778. }
  779. return 0;
  780. }
  781. /* ------------------------------------------------------------ */
  782. /*
  783. * findSubtreeAndSearch - walk up the tree to find an entry with
  784. * the marker object class; if found, call search from there and
  785. * return the result it returns
  786. *
  787. * If 'attr' is NULL, the values are taken from 'values'.
  788. * If 'attr' is non-NULL, the values are taken from 'attr'.
  789. *
  790. * Return:
  791. * LDAP_SUCCESS - no matches, or the attribute matches the
  792. * target dn.
  793. * LDAP_CONSTRAINT_VIOLATION - an entry was found that already
  794. * contains the attribute value.
  795. * LDAP_OPERATIONS_ERROR - a server failure.
  796. */
  797. static int
  798. findSubtreeAndSearch(Slapi_DN *parentDN, const char **attrNames, Slapi_Attr *attr,
  799. struct berval **values, const char *requiredObjectClass, Slapi_DN *target,
  800. const char *markerObjectClass, Slapi_DN **excludes)
  801. {
  802. int result = LDAP_SUCCESS;
  803. Slapi_PBlock *spb = NULL;
  804. Slapi_DN *curpar = slapi_sdn_new();
  805. Slapi_DN *newpar = NULL;
  806. slapi_sdn_get_parent(parentDN, curpar);
  807. while (slapi_sdn_get_dn(curpar) != NULL)
  808. {
  809. if ((spb = dnHasObjectClass(curpar, markerObjectClass)))
  810. {
  811. freePblock(spb);
  812. /*
  813. * Do the search. There is no entry that is allowed
  814. * to have the attribute already.
  815. */
  816. result = search(curpar, attrNames, attr, values, requiredObjectClass,
  817. target, excludes);
  818. break;
  819. }
  820. newpar = slapi_sdn_new();
  821. slapi_sdn_copy(curpar, newpar);
  822. slapi_sdn_get_parent(newpar, curpar);
  823. slapi_sdn_free(&newpar);
  824. }
  825. slapi_sdn_free(&curpar);
  826. return result;
  827. }
  828. /* ------------------------------------------------------------ */
  829. /*
  830. * preop_add - pre-operation plug-in for add
  831. */
  832. static int
  833. preop_add(Slapi_PBlock *pb)
  834. {
  835. int result;
  836. char *errtext = NULL;
  837. const char **attrNames = NULL;
  838. char * attr_friendly = NULL;
  839. #ifdef DEBUG
  840. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name, "ADD begin\n");
  841. #endif
  842. result = LDAP_SUCCESS;
  843. /*
  844. * Do constraint check on the added entry. Set result.
  845. */
  846. BEGIN
  847. int err;
  848. char *markerObjectClass = NULL;
  849. char *requiredObjectClass = NULL;
  850. Slapi_DN *sdn = NULL;
  851. int isupdatedn;
  852. Slapi_Entry *e;
  853. Slapi_Attr *attr;
  854. struct attr_uniqueness_config *config = NULL;
  855. int i = 0;
  856. /*
  857. * If this is a replication update, just be a noop.
  858. */
  859. err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &isupdatedn);
  860. if (err) { result = uid_op_error(50); break; }
  861. if (isupdatedn)
  862. {
  863. break;
  864. }
  865. slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &config);
  866. if (config == NULL) {
  867. slapi_log_err(SLAPI_LOG_ERR, plugin_name, "preop_add - Failed to retrieve the config\n");
  868. result = LDAP_OPERATIONS_ERROR;
  869. break;
  870. }
  871. /*
  872. * Get the arguments
  873. */
  874. attrNames = config->attrs;
  875. markerObjectClass = config->top_entry_oc;
  876. requiredObjectClass = config->subtree_entries_oc;
  877. attr_friendly = config->attr_friendly;
  878. /*
  879. * Get the target DN for this add operation
  880. */
  881. err = slapi_pblock_get(pb, SLAPI_ADD_TARGET_SDN, &sdn);
  882. if (err) { result = uid_op_error(51); break; }
  883. #ifdef DEBUG
  884. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name, "preop_add - ADD target=%s\n", slapi_sdn_get_dn(sdn));
  885. #endif
  886. /*
  887. * Get the entry data for this add. Check whether it
  888. * contains a value for the unique attribute
  889. */
  890. err = slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e);
  891. if (err) { result = uid_op_error(52); break; }
  892. /*
  893. * Check if it contains the required object class
  894. */
  895. if (NULL != requiredObjectClass)
  896. {
  897. if (!entryHasObjectClass(pb, e, requiredObjectClass))
  898. {
  899. /* No, so we don't have to do anything */
  900. break;
  901. }
  902. }
  903. for (i = 0; attrNames && attrNames[i]; i++) {
  904. err = slapi_entry_attr_find(e, attrNames[i], &attr);
  905. if (!err) {
  906. /*
  907. * Passed all the requirements - this is an operation we
  908. * need to enforce uniqueness on. Now find all parent entries
  909. * with the marker object class, and do a search for each one.
  910. */
  911. if (NULL != markerObjectClass)
  912. {
  913. /* Subtree defined by location of marker object class */
  914. result = findSubtreeAndSearch(sdn, attrNames, attr, NULL,
  915. requiredObjectClass, sdn,
  916. markerObjectClass, config->exclude_subtrees);
  917. } else
  918. {
  919. /* Subtrees listed on invocation line */
  920. result = searchAllSubtrees(config->subtrees, config->exclude_subtrees, attrNames, attr, NULL,
  921. requiredObjectClass, sdn, config->unique_in_all_subtrees);
  922. }
  923. if (result != LDAP_SUCCESS) {
  924. break;
  925. }
  926. }
  927. }
  928. END
  929. if (result)
  930. {
  931. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name,
  932. "preop_add - ADD result %d\n", result);
  933. if (result == LDAP_CONSTRAINT_VIOLATION) {
  934. errtext = slapi_ch_smprintf(moreInfo, attr_friendly);
  935. } else {
  936. errtext = slapi_ch_strdup("Error checking for attribute uniqueness.");
  937. }
  938. /* Send failure to the client */
  939. slapi_send_ldap_result(pb, result, 0, errtext, 0, 0);
  940. slapi_ch_free_string(&errtext);
  941. }
  942. return (result==LDAP_SUCCESS)?0:-1;
  943. }
  944. static void
  945. addMod(LDAPMod ***modary, int *capacity, int *nmods, LDAPMod *toadd)
  946. {
  947. if (*nmods == *capacity) {
  948. *capacity += 4;
  949. if (*modary) {
  950. *modary = (LDAPMod **)slapi_ch_realloc((char *)*modary, *capacity * sizeof(LDAPMod *));
  951. } else {
  952. *modary = (LDAPMod **)slapi_ch_malloc(*capacity * sizeof(LDAPMod *));
  953. }
  954. }
  955. (*modary)[*nmods] = toadd;
  956. (*nmods)++;
  957. }
  958. /* ------------------------------------------------------------ */
  959. /*
  960. * preop_modify - pre-operation plug-in for modify
  961. */
  962. static int
  963. preop_modify(Slapi_PBlock *pb)
  964. {
  965. int result = LDAP_SUCCESS;
  966. Slapi_PBlock *spb = NULL;
  967. LDAPMod **checkmods = NULL;
  968. int checkmodsCapacity = 0;
  969. char *errtext = NULL;
  970. const char **attrNames = NULL;
  971. struct attr_uniqueness_config *config = NULL;
  972. char *attr_friendly = NULL;
  973. #ifdef DEBUG
  974. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name,
  975. "preop_modify - MODIFY begin\n");
  976. #endif
  977. BEGIN
  978. int err;
  979. char *markerObjectClass=NULL;
  980. char *requiredObjectClass=NULL;
  981. LDAPMod **mods;
  982. int modcount = 0;
  983. int ii;
  984. LDAPMod *mod;
  985. Slapi_DN *sdn = NULL;
  986. int isupdatedn;
  987. int i = 0;
  988. /*
  989. * If this is a replication update, just be a noop.
  990. */
  991. err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &isupdatedn);
  992. if (err) { result = uid_op_error(60); break; }
  993. if (isupdatedn)
  994. {
  995. break;
  996. }
  997. slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &config);
  998. if (config == NULL) {
  999. slapi_log_err(SLAPI_LOG_ERR, plugin_name, "preop_modify - Failed to retrieve the config\n");
  1000. result = LDAP_OPERATIONS_ERROR;
  1001. break;
  1002. }
  1003. /*
  1004. * Get the arguments
  1005. */
  1006. attrNames = config->attrs;
  1007. markerObjectClass = config->top_entry_oc;
  1008. requiredObjectClass = config->subtree_entries_oc;
  1009. attr_friendly = config->attr_friendly;
  1010. err = slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  1011. if (err) { result = uid_op_error(61); break; }
  1012. /* There may be more than one mod that matches e.g.
  1013. changetype: modify
  1014. delete: uid
  1015. uid: balster1950
  1016. -
  1017. add: uid
  1018. uid: scottg
  1019. So, we need to first find all mods that contain the attribute
  1020. which are add or replace ops and are bvalue encoded
  1021. */
  1022. /* find out how many mods meet this criteria */
  1023. for(;mods && *mods;mods++)
  1024. {
  1025. mod = *mods;
  1026. for (i = 0; attrNames && attrNames[i]; i++) {
  1027. if ((slapi_attr_type_cmp(mod->mod_type, attrNames[i], 1) == 0) && /* mod contains target attr */
  1028. (mod->mod_op & LDAP_MOD_BVALUES) && /* mod is bval encoded (not string val) */
  1029. (mod->mod_bvalues && mod->mod_bvalues[0]) && /* mod actually contains some values */
  1030. (SLAPI_IS_MOD_ADD(mod->mod_op) || /* mod is add */
  1031. SLAPI_IS_MOD_REPLACE(mod->mod_op))) /* mod is replace */
  1032. {
  1033. addMod(&checkmods, &checkmodsCapacity, &modcount, mod);
  1034. }
  1035. }
  1036. }
  1037. if (modcount == 0) {
  1038. break; /* no mods to check, we are done */
  1039. }
  1040. /* Get the target DN */
  1041. err = slapi_pblock_get(pb, SLAPI_MODIFY_TARGET_SDN, &sdn);
  1042. if (err) { result = uid_op_error(11); break; }
  1043. /*
  1044. * Check if it has the required object class
  1045. */
  1046. if (requiredObjectClass &&
  1047. !(spb = dnHasObjectClass(sdn, requiredObjectClass))) {
  1048. break;
  1049. }
  1050. /*
  1051. * Passed all the requirements - this is an operation we
  1052. * need to enforce uniqueness on. Now find all parent entries
  1053. * with the marker object class, and do a search for each one.
  1054. */
  1055. /*
  1056. * stop checking at first mod that fails the check
  1057. */
  1058. for (ii = 0; (result == 0) && (ii < modcount); ++ii)
  1059. {
  1060. mod = checkmods[ii];
  1061. if (NULL != markerObjectClass)
  1062. {
  1063. /* Subtree defined by location of marker object class */
  1064. result = findSubtreeAndSearch(sdn, attrNames, NULL,
  1065. mod->mod_bvalues, requiredObjectClass,
  1066. sdn, markerObjectClass, config->exclude_subtrees);
  1067. } else
  1068. {
  1069. /* Subtrees listed on invocation line */
  1070. result = searchAllSubtrees(config->subtrees, config->exclude_subtrees, attrNames, NULL,
  1071. mod->mod_bvalues, requiredObjectClass, sdn, config->unique_in_all_subtrees);
  1072. }
  1073. }
  1074. END
  1075. slapi_ch_free((void **)&checkmods);
  1076. freePblock(spb);
  1077. if (result)
  1078. {
  1079. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name,
  1080. "preop_modify - MODIFY result %d\n", result);
  1081. if (result == LDAP_CONSTRAINT_VIOLATION) {
  1082. errtext = slapi_ch_smprintf(moreInfo, attr_friendly);
  1083. } else {
  1084. errtext = slapi_ch_strdup("Error checking for attribute uniqueness.");
  1085. }
  1086. slapi_send_ldap_result(pb, result, 0, errtext, 0, 0);
  1087. slapi_ch_free_string(&errtext);
  1088. }
  1089. return (result==LDAP_SUCCESS)?0:-1;
  1090. }
  1091. /* ------------------------------------------------------------ */
  1092. /*
  1093. * preop_modrdn - Pre-operation call for modify RDN
  1094. *
  1095. * Check that the new RDN does not include attributes that
  1096. * cause a constraint violation
  1097. */
  1098. static int
  1099. preop_modrdn(Slapi_PBlock *pb)
  1100. {
  1101. int result = LDAP_SUCCESS;
  1102. Slapi_Entry *e = NULL;
  1103. Slapi_Value *sv_requiredObjectClass = NULL;
  1104. char *errtext = NULL;
  1105. const char **attrNames = NULL;
  1106. struct attr_uniqueness_config *config = NULL;
  1107. #ifdef DEBUG
  1108. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name,
  1109. "preop_modrdn - MODRDN begin\n");
  1110. #endif
  1111. BEGIN
  1112. int err;
  1113. char *markerObjectClass=NULL;
  1114. char *requiredObjectClass=NULL;
  1115. Slapi_DN *sdn = NULL;
  1116. Slapi_DN *superior;
  1117. char *rdn;
  1118. int deloldrdn = 0;
  1119. int isupdatedn;
  1120. Slapi_Attr *attr;
  1121. int i = 0;
  1122. /*
  1123. * If this is a replication update, just be a noop.
  1124. */
  1125. err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &isupdatedn);
  1126. if (err) { result = uid_op_error(30); break; }
  1127. if (isupdatedn)
  1128. {
  1129. break;
  1130. }
  1131. slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &config);
  1132. if (config == NULL) {
  1133. slapi_log_err(SLAPI_LOG_ERR, plugin_name, "preop_modrdn - Failed to retrieve the config\n");
  1134. result = LDAP_OPERATIONS_ERROR;
  1135. break;
  1136. }
  1137. /*
  1138. * Get the arguments
  1139. */
  1140. attrNames = config->attrs;
  1141. markerObjectClass = config->top_entry_oc;
  1142. requiredObjectClass = config->subtree_entries_oc;
  1143. /* Create a Slapi_Value for the requiredObjectClass to use
  1144. * for checking the entry. */
  1145. if (requiredObjectClass) {
  1146. sv_requiredObjectClass = slapi_value_new_string(requiredObjectClass);
  1147. }
  1148. /* Get the DN of the entry being renamed */
  1149. err = slapi_pblock_get(pb, SLAPI_MODRDN_TARGET_SDN, &sdn);
  1150. if (err) { result = uid_op_error(31); break; }
  1151. /* Get superior value - unimplemented in 3.0/4.0/5.0 DS */
  1152. err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &superior);
  1153. if (err) { result = uid_op_error(32); break; }
  1154. /*
  1155. * No superior means the entry is just renamed at
  1156. * its current level in the tree. Use the target DN for
  1157. * determining which managed tree this belongs to
  1158. */
  1159. if (!superior) superior = sdn;
  1160. /* Get the new RDN - this has the attribute values */
  1161. err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &rdn);
  1162. if (err) { result = uid_op_error(33); break; }
  1163. #ifdef DEBUG
  1164. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name,
  1165. "preop_modrdn - MODRDN newrdn=%s\n", rdn);
  1166. #endif
  1167. /* See if the old RDN value is being deleted. */
  1168. err = slapi_pblock_get(pb, SLAPI_MODRDN_DELOLDRDN, &deloldrdn);
  1169. if (err) { result = uid_op_error(34); break; }
  1170. /* Get the entry that is being renamed so we can make a dummy copy
  1171. * of what it will look like after the rename. */
  1172. err = slapi_search_internal_get_entry(sdn, NULL, &e, plugin_identity);
  1173. if (err != LDAP_SUCCESS) {
  1174. result = uid_op_error(35);
  1175. /* We want to return a no such object error if the target doesn't exist. */
  1176. if (err == LDAP_NO_SUCH_OBJECT) {
  1177. result = err;
  1178. }
  1179. break;
  1180. }
  1181. /* Apply the rename operation to the dummy entry. */
  1182. /* slapi_entry_rename does not expect rdn normalized */
  1183. err = slapi_entry_rename(e, rdn, deloldrdn, superior);
  1184. if (err != LDAP_SUCCESS) { result = uid_op_error(36); break; }
  1185. /*
  1186. * Check if it has the required object class
  1187. */
  1188. if (requiredObjectClass &&
  1189. !slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS, sv_requiredObjectClass)) { break; }
  1190. /*
  1191. * Find any unique attribute data in the new RDN
  1192. */
  1193. for (i = 0; attrNames && attrNames[i]; i++) {
  1194. err = slapi_entry_attr_find(e, attrNames[i], &attr);
  1195. if (!err) {
  1196. /*
  1197. * Passed all the requirements - this is an operation we
  1198. * need to enforce uniqueness on. Now find all parent entries
  1199. * with the marker object class, and do a search for each one.
  1200. */
  1201. if (NULL != markerObjectClass)
  1202. {
  1203. /* Subtree defined by location of marker object class */
  1204. result = findSubtreeAndSearch(slapi_entry_get_sdn(e), attrNames, attr, NULL,
  1205. requiredObjectClass, sdn,
  1206. markerObjectClass, config->exclude_subtrees);
  1207. } else
  1208. {
  1209. /* Subtrees listed on invocation line */
  1210. result = searchAllSubtrees(config->subtrees, config->exclude_subtrees, attrNames, attr, NULL,
  1211. requiredObjectClass, sdn, config->unique_in_all_subtrees);
  1212. }
  1213. if (result != LDAP_SUCCESS) {
  1214. break;
  1215. }
  1216. }
  1217. }
  1218. END
  1219. /* Clean-up */
  1220. slapi_value_free(&sv_requiredObjectClass);
  1221. if (e) slapi_entry_free(e);
  1222. if (result)
  1223. {
  1224. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name,
  1225. "preop_modrdn - MODRDN result %d\n", result);
  1226. if (result == LDAP_CONSTRAINT_VIOLATION) {
  1227. errtext = slapi_ch_smprintf(moreInfo, config->attr_friendly);
  1228. } else {
  1229. errtext = slapi_ch_strdup("Error checking for attribute uniqueness.");
  1230. }
  1231. slapi_send_ldap_result(pb, result, 0, errtext, 0, 0);
  1232. slapi_ch_free_string(&errtext);
  1233. }
  1234. return (result==LDAP_SUCCESS)?0:-1;
  1235. }
  1236. static int
  1237. uiduniq_start(Slapi_PBlock *pb)
  1238. {
  1239. Slapi_Entry *plugin_entry = NULL;
  1240. struct attr_uniqueness_config *config = NULL;
  1241. if (slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &plugin_entry) == 0){
  1242. /* load the config into the config list */
  1243. if ((config = uniqueness_entry_to_config(pb, plugin_entry)) == NULL) {
  1244. return SLAPI_PLUGIN_FAILURE;
  1245. }
  1246. slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, (void*) config);
  1247. }
  1248. return 0;
  1249. }
  1250. static int
  1251. uiduniq_close(Slapi_PBlock *pb)
  1252. {
  1253. struct attr_uniqueness_config *config = NULL;
  1254. slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &config);
  1255. if (config) {
  1256. slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, NULL);
  1257. free_uniqueness_config(config);
  1258. slapi_ch_free((void **) &config);
  1259. }
  1260. return 0;
  1261. }
  1262. /* ------------------------------------------------------------ */
  1263. /*
  1264. * Initialize the plugin
  1265. *
  1266. * uidunique_init (the old name) is deprecated
  1267. */
  1268. int
  1269. NSUniqueAttr_Init(Slapi_PBlock *pb)
  1270. {
  1271. int err = 0;
  1272. Slapi_Entry *plugin_entry = NULL;
  1273. char *plugin_type = NULL;
  1274. int preadd = SLAPI_PLUGIN_PRE_ADD_FN;
  1275. int premod = SLAPI_PLUGIN_PRE_MODIFY_FN;
  1276. int premdn = SLAPI_PLUGIN_PRE_MODRDN_FN;
  1277. BEGIN
  1278. /* Declare plugin version */
  1279. err = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
  1280. SLAPI_PLUGIN_VERSION_01);
  1281. if (err) break;
  1282. /*
  1283. * Get plugin identity and store it for later use
  1284. * Used for internal operations
  1285. */
  1286. slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
  1287. /* PR_ASSERT (plugin_identity); */
  1288. if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
  1289. plugin_entry &&
  1290. (plugin_type = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-plugintype")) &&
  1291. plugin_type && strstr(plugin_type, "betxn")) {
  1292. preadd = SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN;
  1293. premod = SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN;
  1294. premdn = SLAPI_PLUGIN_BE_TXN_PRE_MODRDN_FN;
  1295. }
  1296. slapi_ch_free_string(&plugin_type);
  1297. /* Provide descriptive information */
  1298. err = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
  1299. (void*)&pluginDesc);
  1300. if (err) break;
  1301. /* Register functions */
  1302. err = slapi_pblock_set(pb, preadd, (void*)preop_add);
  1303. if (err) break;
  1304. err = slapi_pblock_set(pb, premod, (void*)preop_modify);
  1305. if (err) break;
  1306. err = slapi_pblock_set(pb, premdn, (void*)preop_modrdn);
  1307. if (err) break;
  1308. err = slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, (void *) uiduniq_start);
  1309. if (err) break;
  1310. err = slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, (void *) uiduniq_close);
  1311. if (err) break;
  1312. END
  1313. if (err) {
  1314. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name, "NSUniqueAttr_Init - Error: %d\n", err);
  1315. err = -1;
  1316. }
  1317. else
  1318. slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name, "NSUniqueAttr_Init - plugin loaded\n");
  1319. return err;
  1320. }
  1321. /* ------------------------------------------------------------ */
  1322. /*
  1323. * ldap_quote_filter_value
  1324. *
  1325. * Quote the filter value according to RFC 2254 (Dec 1997)
  1326. *
  1327. * value - a UTF8 string containing the value. It may contain
  1328. * any of the chars needing quotes ( '(' ')' '*' '/' and NUL ).
  1329. * len - the length of the UTF8 value
  1330. * out - a buffer to recieve the converted value. May be NULL, in
  1331. * which case, only the length of the output is computed (and placed in
  1332. * outLen).
  1333. * maxLen - the size of the output buffer. It is an error if this length
  1334. * is exceeded. Ignored if out is NULL.
  1335. * outLen - recieves the size of the output. If an error occurs, this
  1336. * result is not available.
  1337. *
  1338. * Returns
  1339. * 0 - success
  1340. * -1 - failure (usually a buffer overflow)
  1341. */
  1342. int /* Error value */
  1343. ldap_quote_filter_value(
  1344. char *value, int len,
  1345. char *out, int maxLen,
  1346. int *outLen)
  1347. {
  1348. int err;
  1349. char *eValue;
  1350. int resLen;
  1351. #ifdef SLAPI_SUPPORTS_V3_ESCAPING
  1352. static char hexchars[16] = "0123456789abcdef";
  1353. #endif
  1354. err = 0;
  1355. eValue = &value[len];
  1356. resLen = 0;
  1357. /*
  1358. * Convert each character in the input string
  1359. */
  1360. while(value < eValue)
  1361. {
  1362. switch(*value)
  1363. {
  1364. case '(':
  1365. case ')':
  1366. case '*':
  1367. case '\\':
  1368. #ifdef SLAPI_SUPPORTS_V3_ESCAPING
  1369. case 0:
  1370. #endif
  1371. /* Handle characters needing special escape sequences */
  1372. /* Compute size of output */
  1373. #ifdef SLAPI_SUPPORTS_V3_ESCAPING
  1374. resLen += 3;
  1375. #else
  1376. resLen += 2;
  1377. #endif
  1378. /* Generate output if requested */
  1379. if (out)
  1380. {
  1381. /* Check for overflow */
  1382. if (resLen > maxLen) { err = -1; break; }
  1383. *out++ = '\\';
  1384. #ifdef SLAPI_SUPPORTS_V3_ESCAPING
  1385. *out++ = hexchars[(*value >> 4) & 0xF];
  1386. *out++ = hexchars[*value & 0xF];
  1387. #else
  1388. *out++ = *value;
  1389. #endif
  1390. }
  1391. break;
  1392. default:
  1393. /* Compute size of output */
  1394. resLen += 1;
  1395. /* Generate output if requested */
  1396. if (out)
  1397. {
  1398. if (resLen > maxLen) { err = -1; break; }
  1399. *out++ = *value;
  1400. }
  1401. break;
  1402. }
  1403. if (err) break;
  1404. value++;
  1405. }
  1406. if (!err) *outLen = resLen;
  1407. return err;
  1408. }