retrocl.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /*
  42. * Requires that create_instance.c have added a plugin entry similar to:
  43. dn: cn=Retrocl Plugin,cn=plugins,cn=config
  44. objectclass: top
  45. objectclass: nsSlapdPlugin
  46. objectclass: extensibleObject
  47. cn: RetroCL Plugin
  48. nsslapd-pluginpath: /export2/servers/Hydra-supplier/lib/retrocl-plugin.so
  49. nsslapd-plugininitfunc: retrocl_plugin_init
  50. nsslapd-plugintype: object
  51. nsslapd-pluginenabled: on
  52. nsslapd-plugin-depends-on-type: database
  53. nsslapd-pluginid: retrocl
  54. nsslapd-pluginversion: 5.0b2
  55. nsslapd-pluginvendor: Sun Microsystems, Inc.
  56. nsslapd-plugindescription: Retrocl Plugin
  57. *
  58. */
  59. #include "retrocl.h"
  60. #ifdef _WIN32
  61. int *module_ldap_debug = 0;
  62. void plugin_init_debug_level(int *level_ptr)
  63. {
  64. module_ldap_debug = level_ptr;
  65. }
  66. #endif
  67. void* g_plg_identity [PLUGIN_MAX];
  68. Slapi_Backend *retrocl_be_changelog = NULL;
  69. PRLock *retrocl_internal_lock = NULL;
  70. Slapi_RWLock *retrocl_cn_lock;
  71. int retrocl_nattributes = 0;
  72. char **retrocl_attributes = NULL;
  73. char **retrocl_aliases = NULL;
  74. int retrocl_log_deleted = 0;
  75. /* ----------------------------- Retrocl Plugin */
  76. static Slapi_PluginDesc retrocldesc = {"retrocl", VENDOR, DS_PACKAGE_VERSION, "Retrocl Plugin"};
  77. static Slapi_PluginDesc retroclpostopdesc = {"retrocl-postop", VENDOR, DS_PACKAGE_VERSION, "retrocl post-operation plugin"};
  78. static Slapi_PluginDesc retroclinternalpostopdesc = {"retrocl-internalpostop", VENDOR, DS_PACKAGE_VERSION, "retrocl internal post-operation plugin"};
  79. static int legacy_initialised= 0;
  80. /*
  81. * Function: retrocl_*
  82. *
  83. * Returns: LDAP_
  84. *
  85. * Arguments: Pb of operation
  86. *
  87. * Description: wrappers around retrocl_postob registered as callback
  88. *
  89. */
  90. int retrocl_postop_add (Slapi_PBlock *pb) { return retrocl_postob(pb,OP_ADD);}
  91. int retrocl_postop_delete (Slapi_PBlock *pb) { return retrocl_postob(pb,OP_DELETE);}
  92. int retrocl_postop_modify (Slapi_PBlock *pb) { return retrocl_postob(pb,OP_MODIFY);}
  93. int retrocl_postop_modrdn (Slapi_PBlock *pb) { return retrocl_postob(pb,OP_MODRDN);}
  94. /*
  95. * Function: retrocl_postop_init
  96. *
  97. * Returns: 0/-1
  98. *
  99. * Arguments: Pb
  100. *
  101. * Description: callback function
  102. *
  103. */
  104. int
  105. retrocl_postop_init( Slapi_PBlock *pb )
  106. {
  107. int rc= 0; /* OK */
  108. Slapi_Entry *plugin_entry = NULL;
  109. char *plugin_type = NULL;
  110. int postadd = SLAPI_PLUGIN_POST_ADD_FN;
  111. int postmod = SLAPI_PLUGIN_POST_MODIFY_FN;
  112. int postmdn = SLAPI_PLUGIN_POST_MODRDN_FN;
  113. int postdel = SLAPI_PLUGIN_POST_DELETE_FN;
  114. if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
  115. plugin_entry &&
  116. (plugin_type = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-plugintype")) &&
  117. plugin_type && strstr(plugin_type, "betxn")) {
  118. postadd = SLAPI_PLUGIN_BE_TXN_POST_ADD_FN;
  119. postmod = SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN;
  120. postmdn = SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN;
  121. postdel = SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN;
  122. }
  123. slapi_ch_free_string(&plugin_type);
  124. if( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
  125. slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&retroclpostopdesc ) != 0 ||
  126. slapi_pblock_set( pb, postadd, (void *) retrocl_postop_add ) != 0 ||
  127. slapi_pblock_set( pb, postdel, (void *) retrocl_postop_delete ) != 0 ||
  128. slapi_pblock_set( pb, postmod, (void *) retrocl_postop_modify ) != 0 ||
  129. slapi_pblock_set( pb, postmdn, (void *) retrocl_postop_modrdn ) != 0 )
  130. {
  131. slapi_log_error( SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, "retrocl_postop_init failed\n" );
  132. rc= -1;
  133. }
  134. return rc;
  135. }
  136. /*
  137. * Function: retrocl_internalpostop_init
  138. *
  139. * Returns: 0/-1
  140. *
  141. * Arguments: Pb
  142. *
  143. * Description: callback function
  144. *
  145. */
  146. int
  147. retrocl_internalpostop_init( Slapi_PBlock *pb )
  148. {
  149. int rc= 0; /* OK */
  150. if( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
  151. slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&retroclinternalpostopdesc ) != 0 ||
  152. slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, (void *) retrocl_postop_add ) != 0 ||
  153. slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, (void *) retrocl_postop_delete ) != 0 ||
  154. slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, (void *) retrocl_postop_modify ) != 0 ||
  155. slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, (void *) retrocl_postop_modrdn ) != 0 )
  156. {
  157. slapi_log_error( SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, "retrocl_internalpostop_init failed\n" );
  158. rc= -1;
  159. }
  160. return rc;
  161. }
  162. /*
  163. * Function: retrocl_rootdse_init
  164. *
  165. * Returns: LDAP_SUCCESS
  166. *
  167. * Arguments: Slapi_PBlock
  168. *
  169. * Description: The FE DSE *must* be initialised before we get here.
  170. *
  171. */
  172. static int retrocl_rootdse_init(Slapi_PBlock *pb)
  173. {
  174. int return_value= LDAP_SUCCESS;
  175. slapi_config_register_callback_plugin(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP | DSE_FLAG_PLUGIN, "",
  176. LDAP_SCOPE_BASE,"(objectclass=*)",
  177. retrocl_rootdse_search, NULL, pb);
  178. return return_value;
  179. }
  180. /*
  181. * Function: retrocl_select_backend
  182. *
  183. * Returns: LDAP_
  184. *
  185. * Arguments: none
  186. *
  187. * Description: simulates an add of the changelog to see if it exists. If not,
  188. * creates it. Then reads the changenumbers. This function should be called
  189. * exactly once at startup.
  190. *
  191. */
  192. static int retrocl_select_backend(void)
  193. {
  194. int err;
  195. Slapi_PBlock *pb;
  196. Slapi_Backend *be = NULL;
  197. Slapi_Entry *referral = NULL;
  198. Slapi_Operation *op = NULL;
  199. char errbuf[BUFSIZ];
  200. pb = slapi_pblock_new();
  201. slapi_pblock_set (pb, SLAPI_PLUGIN_IDENTITY, g_plg_identity[PLUGIN_RETROCL]);
  202. /* This is a simulated operation; no actual add is performed */
  203. op = operation_new(OP_FLAG_INTERNAL);
  204. operation_set_type(op,SLAPI_OPERATION_ADD); /* Ensure be not readonly */
  205. operation_set_target_spec_str(op,RETROCL_CHANGELOG_DN);
  206. slapi_pblock_set(pb,SLAPI_OPERATION, op);
  207. err = slapi_mapping_tree_select(pb,&be,&referral,errbuf);
  208. slapi_entry_free(referral);
  209. if (err != LDAP_SUCCESS || be == NULL || be == defbackend_get_backend()) {
  210. LDAPDebug2Args(LDAP_DEBUG_TRACE,"Mapping tree select failed (%d) %s.\n",
  211. err,errbuf);
  212. /* could not find the backend for cn=changelog, either because
  213. * it doesn't exist
  214. * mapping tree not registered.
  215. */
  216. err = retrocl_create_config();
  217. if (err != LDAP_SUCCESS) return err;
  218. } else {
  219. retrocl_be_changelog = be;
  220. }
  221. retrocl_create_cle();
  222. slapi_pblock_destroy(pb);
  223. if (be)
  224. slapi_be_Unlock(be);
  225. return retrocl_get_changenumbers();
  226. }
  227. /*
  228. * Function: retrocl_get_config_str
  229. *
  230. * Returns: malloc'ed string which must be freed.
  231. *
  232. * Arguments: attribute type name
  233. *
  234. * Description: reads a single-valued string attr from the plugins' own DSE.
  235. * This is called twice: to obtain the trim max age during startup, and to
  236. * obtain the change log directory. No callback is registered; you cannot
  237. * change the trim max age without restarting the server.
  238. *
  239. */
  240. char *retrocl_get_config_str(const char *attrt)
  241. {
  242. Slapi_Entry **entries;
  243. Slapi_PBlock *pb = NULL;
  244. char *ma;
  245. int rc = 0;
  246. char *dn;
  247. /* RETROCL_PLUGIN_DN is no need to be normalized. */
  248. dn = RETROCL_PLUGIN_DN;
  249. pb = slapi_pblock_new();
  250. slapi_search_internal_set_pb (pb, dn, LDAP_SCOPE_BASE, "objectclass=*", NULL, 0, NULL,
  251. NULL, g_plg_identity[PLUGIN_RETROCL] , 0);
  252. slapi_search_internal_pb (pb);
  253. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  254. if (rc != 0) {
  255. slapi_pblock_destroy(pb);
  256. return NULL;
  257. }
  258. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  259. ma = slapi_entry_attr_get_charptr(entries[0],attrt);
  260. slapi_free_search_results_internal(pb);
  261. slapi_pblock_destroy(pb);
  262. return ma;
  263. }
  264. /*
  265. * Function: retrocl_start
  266. *
  267. * Returns: 0 on success
  268. *
  269. * Arguments: Pb
  270. *
  271. * Description:
  272. *
  273. */
  274. static int retrocl_start (Slapi_PBlock *pb)
  275. {
  276. int rc = 0;
  277. Slapi_Entry *e = NULL;
  278. char **values = NULL;
  279. retrocl_rootdse_init(pb);
  280. rc = retrocl_select_backend();
  281. if (rc != 0) {
  282. LDAPDebug1Arg(LDAP_DEBUG_TRACE,"Couldnt find backend, not trimming retro changelog (%d).\n",rc);
  283. return rc;
  284. }
  285. retrocl_init_trimming();
  286. if (slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e) != 0) {
  287. slapi_log_error(SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "Missing config entry.\n");
  288. return -1;
  289. }
  290. values = slapi_entry_attr_get_charray(e, "nsslapd-attribute");
  291. if (values != NULL) {
  292. int n = 0;
  293. int i = 0;
  294. slapi_log_error(SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, "nsslapd-attribute:\n");
  295. for (n=0; values && values[n]; n++) {
  296. slapi_log_error(SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, " - %s\n", values[n]);
  297. }
  298. retrocl_nattributes = n;
  299. retrocl_attributes = (char **)slapi_ch_calloc(n, sizeof(char *));
  300. retrocl_aliases = (char **)slapi_ch_calloc(n, sizeof(char *));
  301. slapi_log_error(SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, "Attributes:\n");
  302. for (i=0; i<n; i++) {
  303. char *value = values[i];
  304. size_t length = strlen(value);
  305. char *pos = strchr(value, ':');
  306. if (pos == NULL) {
  307. retrocl_attributes[i] = slapi_ch_strdup(value);
  308. retrocl_aliases[i] = NULL;
  309. slapi_log_error(SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, " - %s\n",
  310. retrocl_attributes[i]);
  311. } else {
  312. retrocl_attributes[i] = slapi_ch_malloc(pos-value+1);
  313. strncpy(retrocl_attributes[i], value, pos-value);
  314. retrocl_attributes[i][pos-value] = '\0';
  315. retrocl_aliases[i] = slapi_ch_malloc(value+length-pos);
  316. strcpy(retrocl_aliases[i], pos+1);
  317. slapi_log_error(SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, " - %s [%s]\n",
  318. retrocl_attributes[i], retrocl_aliases[i]);
  319. }
  320. }
  321. slapi_ch_array_free(values);
  322. }
  323. retrocl_log_deleted = 0;
  324. values = slapi_entry_attr_get_charray(e, "nsslapd-log-deleted");
  325. if (values != NULL) {
  326. if (values[1] != NULL) {
  327. slapi_log_error(SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME,
  328. "Multiple values specified for attribute: nsslapd-log-deleted\n");
  329. } else if ( 0 == strcasecmp(values[0], "on")) {
  330. retrocl_log_deleted = 1;
  331. } else if (strcasecmp(values[0], "off")) {
  332. slapi_log_error(SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME,
  333. "Invalid value (%s) specified for attribute: nsslapd-log-deleted\n", values[0]);
  334. }
  335. slapi_ch_array_free(values);
  336. }
  337. return 0;
  338. }
  339. /*
  340. * Function: retrocl_stop
  341. *
  342. * Returns: 0
  343. *
  344. * Arguments: Pb
  345. *
  346. * Description: called when the server is shutting down
  347. *
  348. */
  349. static int retrocl_stop (Slapi_PBlock *pb)
  350. {
  351. int rc = 0;
  352. slapi_ch_array_free(retrocl_attributes);
  353. retrocl_attributes = NULL;
  354. slapi_ch_array_free(retrocl_aliases);
  355. retrocl_aliases = NULL;
  356. retrocl_stop_trimming();
  357. retrocl_be_changelog = NULL;
  358. retrocl_forget_changenumbers();
  359. PR_DestroyLock(retrocl_internal_lock);
  360. retrocl_internal_lock = NULL;
  361. slapi_destroy_rwlock(retrocl_cn_lock);
  362. retrocl_cn_lock = NULL;
  363. legacy_initialised = 0;
  364. slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, "",
  365. LDAP_SCOPE_BASE,"(objectclass=*)", retrocl_rootdse_search);
  366. return rc;
  367. }
  368. /*
  369. * Function: retrocl_plugin_init
  370. *
  371. * Returns: 0 on successs
  372. *
  373. * Arguments: Pb
  374. *
  375. * Description: main entry point for retrocl
  376. *
  377. */
  378. int
  379. retrocl_plugin_init(Slapi_PBlock *pb)
  380. {
  381. int rc = 0;
  382. int precedence = 0;
  383. void *identity = NULL;
  384. Slapi_Entry *plugin_entry = NULL;
  385. int is_betxn = 0;
  386. const char *plugintype = "postoperation";
  387. slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
  388. PR_ASSERT (identity);
  389. g_plg_identity[PLUGIN_RETROCL] = identity;
  390. slapi_pblock_get( pb, SLAPI_PLUGIN_PRECEDENCE, &precedence );
  391. if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
  392. plugin_entry) {
  393. is_betxn = slapi_entry_attr_get_bool(plugin_entry, "nsslapd-pluginbetxn");
  394. }
  395. if (!legacy_initialised) {
  396. rc= slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 );
  397. rc= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&retrocldesc );
  398. rc= slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN, (void *) retrocl_start );
  399. rc= slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN, (void *) retrocl_stop );
  400. if (is_betxn) {
  401. plugintype = "betxnpostoperation";
  402. }
  403. rc= slapi_register_plugin_ext(plugintype, 1 /* Enabled */, "retrocl_postop_init", retrocl_postop_init, "Retrocl postoperation plugin", NULL, identity, precedence);
  404. if (!is_betxn) {
  405. rc= slapi_register_plugin_ext("internalpostoperation", 1 /* Enabled */, "retrocl_internalpostop_init", retrocl_internalpostop_init, "Retrocl internal postoperation plugin", NULL, identity, precedence);
  406. }
  407. retrocl_cn_lock = slapi_new_rwlock();
  408. if(retrocl_cn_lock == NULL) return -1;
  409. retrocl_internal_lock = PR_NewLock();
  410. if (retrocl_internal_lock == NULL) return -1;
  411. }
  412. legacy_initialised = 1;
  413. return rc;
  414. }