7bit.c 18 KB

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