uid.c 52 KB

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