uid.c 51 KB

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