7bit.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright 2001 Sun Microsystems, Inc.
  3. * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
  4. * All rights reserved.
  5. * END COPYRIGHT BLOCK **/
  6. /*
  7. * 7bit.c
  8. *
  9. * Implements a directory server pre-operation plugin to test
  10. * attributes for 7 bit clean within a defined subtree in the
  11. * directory.
  12. *
  13. */
  14. #include <stdio.h>
  15. #include <slapi-plugin.h>
  16. #include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
  17. #include <string.h>
  18. #include "dirver.h"
  19. /* DBDB this should be pulled from a common header file */
  20. #ifdef _WIN32
  21. #ifndef strcasecmp
  22. #define strcasecmp(x,y) strcmpi(x,y)
  23. #endif
  24. #endif
  25. #if defined( LDAP_DEBUG ) && !defined( DEBUG )
  26. #define DEBUG
  27. #endif
  28. /*
  29. * ISSUES:
  30. * How should this plugin handle ACL issues? It seems wrong to reject
  31. * adds and modifies because there is already a conflicting UID, when
  32. * the request would have failed because of an ACL check anyway.
  33. *
  34. * This code currently defines a maximum filter string size of 512. Is
  35. * this large enough?
  36. *
  37. * This code currently does not quote the value portion of the filter as
  38. * it is created. This is a bug.
  39. */
  40. /* */
  41. #define BEGIN do {
  42. #define END } while(0);
  43. /*
  44. * Slapi plugin descriptor
  45. */
  46. static char *plugin_name = "NS7bitAttr";
  47. static Slapi_PluginDesc
  48. pluginDesc = { "NS7bitAttr", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
  49. "Enforce 7-bit clean attribute values" };
  50. /*
  51. * More information about constraint failure
  52. */
  53. static char *moreInfo =
  54. "The value is not 7-bit clean: ";
  55. /* ------------------------------------------------------------ */
  56. /*
  57. * op_error - Record (and report) an operational error.
  58. */
  59. static int
  60. op_error(int internal_error)
  61. {
  62. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  63. "Internal error: %d\n", internal_error);
  64. return LDAP_OPERATIONS_ERROR;
  65. }
  66. static void
  67. issue_error(Slapi_PBlock *pb, int result, char *type, char *value)
  68. {
  69. char *moreinfop;
  70. int sz;
  71. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  72. "%s result %d\n", type, result);
  73. if (value == NULL) {
  74. value = "unknown";
  75. }
  76. sz = strlen(moreInfo) + strlen(value) + 1;
  77. moreinfop = (char *)slapi_ch_malloc(sz);
  78. sprintf(moreinfop, "%s%s", moreInfo, value);
  79. /* Send failure to the client */
  80. slapi_send_ldap_result(pb, result, 0, moreinfop, 0, 0);
  81. slapi_ch_free((void **)&moreinfop);
  82. return;
  83. }
  84. /*
  85. * Check 'value' for 7-bit cleanliness.
  86. */
  87. static int
  88. bit_check_one_berval(const struct berval *value, char **violated)
  89. {
  90. int result;
  91. char *ch;
  92. int i;
  93. #ifdef DEBUG
  94. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "7-bit checking begin\n");
  95. #endif
  96. result = LDAP_SUCCESS;
  97. /* If no value, can't possibly be a conflict */
  98. if ( (struct berval *)NULL == value )
  99. return result;
  100. for(i=0, ch=value->bv_val; ch && i < (int)(value->bv_len) ;
  101. ch++, i++)
  102. {
  103. if (( 0x80 & *ch ) != 0 )
  104. {
  105. result = LDAP_CONSTRAINT_VIOLATION;
  106. *violated = value->bv_val;
  107. break;
  108. }
  109. }
  110. return result;
  111. }
  112. /*
  113. * Check a set of values for 7-bit cleanliness.
  114. *
  115. * If 'attr' is NULL, the values are taken from 'values'.
  116. * If 'attr' is non-NULL, the values are taken from 'attr'.
  117. */
  118. static int
  119. bit_check(Slapi_Attr *attr, struct berval **values, char **violated)
  120. {
  121. int result = LDAP_SUCCESS;
  122. *violated = NULL;
  123. /* If no values, can't possibly be a conflict */
  124. if ( (Slapi_Attr *)NULL == attr && (struct berval **)NULL == values )
  125. return result;
  126. if ( (Slapi_Attr *)NULL != attr )
  127. {
  128. Slapi_Value *v = NULL;
  129. int vhint = -1;
  130. for ( vhint = slapi_attr_first_value( attr, &v );
  131. vhint != -1 && LDAP_SUCCESS == result;
  132. vhint = slapi_attr_next_value( attr, vhint, &v ))
  133. {
  134. result = bit_check_one_berval(slapi_value_get_berval(v), violated);
  135. }
  136. }
  137. else
  138. {
  139. for (;*values != NULL && LDAP_SUCCESS == result; values++)
  140. {
  141. result = bit_check_one_berval(*values, violated);
  142. }
  143. }
  144. #ifdef DEBUG
  145. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  146. "7 bit check result = %d\n", result);
  147. #endif
  148. return result;
  149. }
  150. /* ------------------------------------------------------------ */
  151. /*
  152. * preop_add - pre-operation plug-in for add
  153. */
  154. static int
  155. preop_add(Slapi_PBlock *pb)
  156. {
  157. int result;
  158. char *violated;
  159. #ifdef DEBUG
  160. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "ADD begin\n");
  161. #endif
  162. result = LDAP_SUCCESS;
  163. /*
  164. * Do constraint check on the added entry. Set result.
  165. */
  166. BEGIN
  167. int err;
  168. int argc;
  169. char **argv;
  170. char **attrName;
  171. char *dn;
  172. Slapi_Entry *e;
  173. Slapi_Attr *attr;
  174. char **firstSubtree;
  175. char **subtreeDN;
  176. int subtreeCnt;
  177. int is_replicated_operation;
  178. /*
  179. * Get the arguments
  180. */
  181. err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
  182. if (err) { result = op_error(53); break; }
  183. err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
  184. if (err) { result = op_error(54); break; }
  185. /*
  186. * If this is a replication update, just be a noop.
  187. */
  188. err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
  189. if (err) { result = op_error(56); break; }
  190. if (is_replicated_operation)
  191. {
  192. break;
  193. }
  194. /*
  195. * Get the target DN for this add operation
  196. */
  197. err = slapi_pblock_get(pb, SLAPI_ADD_TARGET, &dn);
  198. if (err) { result = op_error(50); break; }
  199. #ifdef DEBUG
  200. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "ADD target=%s\n", dn);
  201. #endif
  202. /*
  203. * Get the entry data for this add. Check whether it
  204. * contains a value for the unique attribute
  205. */
  206. err = slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e);
  207. if (err) { result = op_error(51); break; }
  208. for ( firstSubtree = argv; strcmp(*firstSubtree, ",") != 0;
  209. firstSubtree++, argc--) {}
  210. firstSubtree++;
  211. argc--;
  212. for (attrName = argv; strcmp(*attrName, ",") != 0; attrName++ )
  213. {
  214. /*
  215. * if the attribute is userpassword, check unhashed#user#password
  216. * instead. "userpassword" is encoded; it will always pass the 7bit
  217. * check.
  218. */
  219. char *attr_name;
  220. if ( strcasecmp(*attrName, "userpassword") == 0 )
  221. {
  222. attr_name = "unhashed#user#password";
  223. } else {
  224. attr_name = *attrName;
  225. }
  226. err = slapi_entry_attr_find(e, attr_name, &attr);
  227. if (err) continue; /* break;*/ /* no 7-bit attribute */
  228. /*
  229. * For each DN in the managed list, do 7-bit checking if
  230. * the target DN is a subnode in the tree.
  231. */
  232. for( subtreeDN=firstSubtree, subtreeCnt=argc ;subtreeCnt > 0;
  233. subtreeCnt--,subtreeDN++)
  234. {
  235. /*
  236. * issuffix determines whether the target is under the
  237. * subtree *subtreeDN
  238. */
  239. if (slapi_dn_issuffix(dn, *subtreeDN))
  240. {
  241. #ifdef DEBUG
  242. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  243. "ADD subtree=%s\n", *subtreeDN);
  244. #endif
  245. /*
  246. * Check if the value is 7-bit clean
  247. */
  248. result = bit_check(attr, NULL, &violated);
  249. if (result) break;
  250. }
  251. }
  252. /* don't have to go on if there is a value not 7-bit clean */
  253. if (result) break;
  254. }
  255. END
  256. if (result) {
  257. issue_error(pb, result, "ADD", violated);
  258. }
  259. return (result==LDAP_SUCCESS)?0:-1;
  260. }
  261. static void
  262. addMod(LDAPMod ***modary, int *capacity, int *nmods, LDAPMod *toadd)
  263. {
  264. if (*nmods == *capacity) {
  265. *capacity += 4;
  266. if (*modary) {
  267. *modary = (LDAPMod **)slapi_ch_realloc((char *)*modary, *capacity * sizeof(LDAPMod *));
  268. } else {
  269. *modary = (LDAPMod **)slapi_ch_malloc(*capacity * sizeof(LDAPMod *));
  270. }
  271. }
  272. *modary[*nmods] = toadd;
  273. (*nmods)++;
  274. }
  275. /* ------------------------------------------------------------ */
  276. /*
  277. * preop_modify - pre-operation plug-in for modify
  278. */
  279. static int
  280. preop_modify(Slapi_PBlock *pb)
  281. {
  282. int result;
  283. char *violated;
  284. LDAPMod **checkmods = NULL; /* holds mods to check */
  285. int checkmodsCapacity = 0; /* max capacity of checkmods */
  286. #ifdef DEBUG
  287. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  288. "MODIFY begin\n");
  289. #endif
  290. result = LDAP_SUCCESS;
  291. BEGIN
  292. int err;
  293. int argc;
  294. char **argv;
  295. char **attrName;
  296. LDAPMod **mods;
  297. LDAPMod **firstMods;
  298. LDAPMod *mod;
  299. char *target;
  300. char **firstSubtree;
  301. char **subtreeDN;
  302. int subtreeCnt;
  303. int is_replicated_operation;
  304. /*
  305. * Get the arguments
  306. */
  307. err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
  308. if (err) { result = op_error(13); break; }
  309. err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
  310. if (err) { result = op_error(14); break; }
  311. /*
  312. * If this is a replication update, just be a noop.
  313. */
  314. err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
  315. if (err) { result = op_error(16); break; }
  316. if (is_replicated_operation)
  317. {
  318. break;
  319. }
  320. err = slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &firstMods);
  321. if (err) { result = op_error(10); break; }
  322. /* Get the target DN */
  323. err = slapi_pblock_get(pb, SLAPI_MODIFY_TARGET, &target);
  324. if (err) { result = op_error(11); break; }
  325. /*
  326. * Look for managed trees that include the target
  327. * Arguments before "," are the 7-bit clean attribute names. Arguemnts
  328. * after "," are subtreeDN's.
  329. */
  330. for ( firstSubtree = argv; strcmp(*firstSubtree, ",") != 0;
  331. firstSubtree++, argc--) {}
  332. firstSubtree++;
  333. argc--;
  334. for (attrName = argv; strcmp(*attrName, ",") != 0; attrName++ )
  335. {
  336. int modcount = 0;
  337. int ii = 0;
  338. /*
  339. * if the attribute is userpassword, check unhashed#user#password
  340. * instead. "userpassword" is encoded; it will always pass the 7bit
  341. * check.
  342. */
  343. char *attr_name;
  344. if ( strcasecmp(*attrName, "userpassword") == 0 )
  345. {
  346. attr_name = "unhashed#user#password";
  347. } else {
  348. attr_name = *attrName;
  349. }
  350. /* There may be more than one mod that matches e.g.
  351. changetype: modify
  352. delete: uid
  353. uid: balster1950
  354. -
  355. add: uid
  356. uid: scottg
  357. So, we need to first find all mods that contain the attribute
  358. which are add or replace ops and are bvalue encoded
  359. */
  360. /* find out how many mods meet this criteria */
  361. for(mods=firstMods;*mods;mods++)
  362. {
  363. mod = *mods;
  364. if ((slapi_attr_type_cmp(mod->mod_type, attr_name, 1) == 0) && /* mod contains target attr */
  365. (mod->mod_op & LDAP_MOD_BVALUES) && /* mod is bval encoded (not string val) */
  366. (mod->mod_bvalues && mod->mod_bvalues[0]) && /* mod actually contains some values */
  367. (((mod->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) || /* mod is add */
  368. (mod->mod_op & LDAP_MOD_REPLACE))) /* mod is replace */
  369. {
  370. addMod(&checkmods, &checkmodsCapacity, &modcount, mod);
  371. }
  372. }
  373. if (modcount == 0) {
  374. continue; /* no mods to check, go to next attr */
  375. }
  376. /*
  377. * stop checking at first mod that fails the check
  378. */
  379. for (ii = 0; (result == 0) && (ii < modcount); ++ii)
  380. {
  381. mod = checkmods[ii];
  382. /*
  383. * For each DN in the managed list, do 7-bit checking if
  384. * the target DN is a subnode in the tree.
  385. */
  386. for( subtreeDN=firstSubtree, subtreeCnt=argc ;subtreeCnt > 0;
  387. subtreeCnt--,subtreeDN++)
  388. {
  389. /*
  390. * issuffix determines whether the target is under the
  391. * subtree *subtreeDN
  392. */
  393. if (slapi_dn_issuffix(target, *subtreeDN))
  394. {
  395. #ifdef DEBUG
  396. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  397. "MODIFY subtree=%s\n", *subtreeDN);
  398. #endif
  399. /*
  400. * Check if the value is 7-bit clean
  401. */
  402. result = bit_check(NULL, mod->mod_bvalues, &violated);
  403. if (result) break;
  404. }
  405. }
  406. }
  407. /* don't have to go on if there is a value not 7-bit clean */
  408. if (result) break;
  409. }
  410. END
  411. slapi_ch_free((void **)&checkmods);
  412. if (result) {
  413. issue_error(pb, result, "MODIFY", violated);
  414. }
  415. return (result==LDAP_SUCCESS)?0:-1;
  416. }
  417. /* ------------------------------------------------------------ */
  418. /*
  419. * preop_modrdn - Pre-operation call for modify RDN
  420. *
  421. * Check that the new RDN does not include attributes that
  422. * cause a constraint violation
  423. */
  424. static int
  425. preop_modrdn(Slapi_PBlock *pb)
  426. {
  427. int result;
  428. Slapi_Entry *e;
  429. char *violated;
  430. #ifdef DEBUG
  431. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  432. "MODRDN begin\n");
  433. #endif
  434. /* Init */
  435. result = LDAP_SUCCESS;
  436. e = 0;
  437. BEGIN
  438. int err;
  439. int argc;
  440. char **argv;
  441. char **attrName;
  442. char *target;
  443. char *superior;
  444. char *rdn;
  445. Slapi_Attr *attr;
  446. char **firstSubtree;
  447. char **subtreeDN;
  448. int subtreeCnt;
  449. int is_replicated_operation;
  450. /*
  451. * Get the arguments
  452. */
  453. err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
  454. if (err) { result = op_error(30); break; }
  455. err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
  456. if (err) { result = op_error(31); break; }
  457. /*
  458. * If this is a replication update, just be a noop.
  459. */
  460. err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
  461. if (err) { result = op_error(16); break; }
  462. if (is_replicated_operation)
  463. {
  464. break;
  465. }
  466. /* Get the DN of the entry being renamed */
  467. err = slapi_pblock_get(pb, SLAPI_MODRDN_TARGET, &target);
  468. if (err) { result = op_error(22); break; }
  469. /* Get superior value - unimplemented in 3.0 DS */
  470. err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR, &superior);
  471. if (err) { result = op_error(20); break; }
  472. /*
  473. * No superior means the entry is just renamed at
  474. * its current level in the tree. Use the target DN for
  475. * determining which managed tree this belongs to
  476. */
  477. if (!superior) superior = target;
  478. /* Get the new RDN - this has the attribute values */
  479. err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &rdn);
  480. if (err) { result = op_error(33); break; }
  481. #ifdef DEBUG
  482. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  483. "MODRDN newrdn=%s\n", rdn);
  484. #endif
  485. /*
  486. * Parse the RDN into attributes by creating a "dummy" entry
  487. * and setting the attributes from the RDN.
  488. *
  489. * The new entry must be freed.
  490. */
  491. e = slapi_entry_alloc();
  492. if (!e) { result = op_error(32); break; }
  493. /* NOTE: strdup on the rdn, since it will be freed when
  494. * the entry is freed */
  495. slapi_entry_set_dn(e, slapi_ch_strdup(rdn));
  496. err = slapi_entry_add_rdn_values(e);
  497. if (err)
  498. {
  499. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  500. "MODRDN bad rdn value=%s\n", rdn);
  501. break; /* Bad DN */
  502. }
  503. /*
  504. * arguments before "," are the 7-bit clean attribute names. Arguemnts
  505. * after "," are subtreeDN's.
  506. */
  507. for ( firstSubtree = argv; strcmp(*firstSubtree, ",") != 0;
  508. firstSubtree++, argc--) {}
  509. firstSubtree++;
  510. argc--;
  511. /*
  512. * Find out if the node is being moved into one of
  513. * the managed subtrees
  514. */
  515. for (attrName = argv; strcmp(*attrName, ",") != 0; attrName++ )
  516. {
  517. /*
  518. * If the attribut type is userpassword, do not replace it by
  519. * unhashed#user#password because unhashed#user#password does not exist
  520. * in this case.
  521. */
  522. /*
  523. * Find any 7-bit attribute data in the new RDN
  524. */
  525. err = slapi_entry_attr_find(e, *attrName, &attr);
  526. if (err) continue; /* break;*/ /* no 7-bit attribute */
  527. /*
  528. * For each DN in the managed list, do 7-bit checking if
  529. * the target DN is a subnode in the tree.
  530. */
  531. for( subtreeDN=firstSubtree, subtreeCnt=argc ;subtreeCnt > 0;
  532. subtreeCnt--,subtreeDN++)
  533. {
  534. /*
  535. * issuffix determines whether the target is under the
  536. * subtree *subtreeDN
  537. */
  538. if (slapi_dn_issuffix(superior, *subtreeDN))
  539. {
  540. #ifdef DEBUG
  541. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
  542. "MODRDN subtree=%s\n", *subtreeDN);
  543. #endif
  544. /*
  545. * Check if the value is 7-bit clean
  546. */
  547. result = bit_check(attr, NULL, &violated);
  548. if (result) break;
  549. }
  550. }
  551. /* don't have to go on if there is a value not 7-bit clean */
  552. if (result) break;
  553. }
  554. END
  555. /* Clean-up */
  556. if (e) slapi_entry_free(e);
  557. if (result) {
  558. issue_error(pb, result, "MODRDN", violated);
  559. }
  560. return (result==LDAP_SUCCESS)?0:-1;
  561. }
  562. /* ------------------------------------------------------------ */
  563. /*
  564. * Initialize the plugin
  565. *
  566. */
  567. int
  568. NS7bitAttr_Init(Slapi_PBlock *pb)
  569. {
  570. int err = 0;
  571. BEGIN
  572. int err;
  573. int argc;
  574. char **argv;
  575. /* Declare plugin version */
  576. err = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
  577. SLAPI_PLUGIN_VERSION_01);
  578. if (err) break;
  579. /*
  580. * Get and normalize arguments
  581. */
  582. err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
  583. if (err) break;
  584. err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
  585. if (err) break;
  586. /*
  587. * Arguments before "," are the 7-bit attribute names. Arguments after
  588. * "," are the subtree DN's.
  589. */
  590. if (argc < 1) { err = -1; break; }
  591. for(;strcmp(*argv, ",") != 0 && argc > 0; argc--, argv++)
  592. {};
  593. if (argc == 0) { err = -1; break; }
  594. argv++; argc--;
  595. for(;argc > 0;argc--, argv++)
  596. slapi_dn_normalize_case(*argv);
  597. /* Provide descriptive information */
  598. err = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
  599. (void*)&pluginDesc);
  600. if (err) break;
  601. /* Register functions */
  602. err = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_ADD_FN,
  603. (void*)preop_add);
  604. if (err) break;
  605. err = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODIFY_FN,
  606. (void*)preop_modify);
  607. if (err) break;
  608. err = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODRDN_FN,
  609. (void*)preop_modrdn);
  610. if (err) break;
  611. END
  612. if (err) {
  613. slapi_log_error(SLAPI_LOG_PLUGIN, "NS7bitAttr_Init",
  614. "Error: %d\n", err);
  615. err = -1;
  616. }
  617. else
  618. slapi_log_error(SLAPI_LOG_PLUGIN, "NS7bitAttr_Init",
  619. "plugin loaded\n");
  620. return err;
  621. }