cl5_config.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  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. /* cl5_config.c - functions to process changelog configuration
  13. */
  14. #include <string.h>
  15. #include <prio.h>
  16. #include "repl5.h"
  17. #include "cl5.h"
  18. #include "cl5_clcache.h" /* To configure the Changelog Cache */
  19. #include "intrinsics.h" /* JCMREPL - Is this bad? */
  20. #ifdef TEST_CL5
  21. #include "cl5_test.h"
  22. #endif
  23. #include "nspr.h"
  24. #include "plstr.h"
  25. #define CONFIG_BASE "cn=changelog5,cn=config" /*"cn=changelog,cn=supplier,cn=replication5.0,cn=replication,cn=config"*/
  26. #define CONFIG_FILTER "(objectclass=*)"
  27. static Slapi_RWLock *s_configLock; /* guarantees that only on thread at a time
  28. modifies changelog configuration */
  29. /* Forward Declartions */
  30. static int changelog5_config_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg);
  31. static int changelog5_config_modify(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg);
  32. static int changelog5_config_delete(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg);
  33. static int dont_allow_that(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *e, int *returncode, char *returntext, void *arg);
  34. static void changelog5_extract_config(Slapi_Entry *entry, changelog5Config *config);
  35. static changelog5Config *changelog5_dup_config(changelog5Config *config);
  36. static void replace_bslash(char *dir);
  37. static int notify_replica(Replica *r, void *arg);
  38. static int _is_absolutepath(char *dir);
  39. int
  40. changelog5_config_init()
  41. {
  42. /* The FE DSE *must* be initialised before we get here */
  43. /* create the configuration lock, if not yet created. */
  44. if (!s_configLock) {
  45. s_configLock = slapi_new_rwlock();
  46. }
  47. if (s_configLock == NULL) {
  48. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
  49. "changelog5_config_init - Failed to create configuration lock; "
  50. "NSPR error - %d\n",
  51. PR_GetError());
  52. return 1;
  53. }
  54. slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_BASE,
  55. CONFIG_FILTER, changelog5_config_add, NULL);
  56. slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_BASE,
  57. CONFIG_FILTER, changelog5_config_modify, NULL);
  58. slapi_config_register_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_BASE,
  59. CONFIG_FILTER, dont_allow_that, NULL);
  60. slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_BASE,
  61. CONFIG_FILTER, changelog5_config_delete, NULL);
  62. return 0;
  63. }
  64. void
  65. changelog5_config_cleanup()
  66. {
  67. slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_BASE,
  68. CONFIG_FILTER, changelog5_config_add);
  69. slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_BASE,
  70. CONFIG_FILTER, changelog5_config_modify);
  71. slapi_config_remove_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_BASE,
  72. CONFIG_FILTER, dont_allow_that);
  73. slapi_config_remove_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_BASE,
  74. CONFIG_FILTER, changelog5_config_delete);
  75. if (s_configLock) {
  76. slapi_destroy_rwlock(s_configLock);
  77. s_configLock = NULL;
  78. }
  79. }
  80. int
  81. changelog5_read_config(changelog5Config *config)
  82. {
  83. int rc = LDAP_SUCCESS;
  84. Slapi_PBlock *pb;
  85. pb = slapi_pblock_new();
  86. slapi_search_internal_set_pb(pb, CONFIG_BASE, LDAP_SCOPE_BASE,
  87. CONFIG_FILTER, NULL, 0, NULL, NULL,
  88. repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
  89. slapi_search_internal_pb(pb);
  90. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  91. if (LDAP_SUCCESS == rc) {
  92. Slapi_Entry **entries = NULL;
  93. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  94. if (NULL != entries && NULL != entries[0]) {
  95. /* Extract the config info from the changelog entry */
  96. changelog5_extract_config(entries[0], config);
  97. } else {
  98. memset(config, 0, sizeof(*config));
  99. rc = LDAP_SUCCESS;
  100. }
  101. } else {
  102. memset(config, 0, sizeof(*config));
  103. rc = LDAP_SUCCESS;
  104. }
  105. slapi_free_search_results_internal(pb);
  106. slapi_pblock_destroy(pb);
  107. return rc;
  108. }
  109. void
  110. changelog5_config_done(changelog5Config *config)
  111. {
  112. if (config) {
  113. /* slapi_ch_free_string accepts NULL pointer */
  114. slapi_ch_free_string(&config->maxAge);
  115. slapi_ch_free_string(&config->dir);
  116. }
  117. }
  118. void
  119. changelog5_config_free(changelog5Config **config)
  120. {
  121. changelog5_config_done(*config);
  122. slapi_ch_free((void **)config);
  123. }
  124. static int
  125. changelog5_config_add(Slapi_PBlock *pb __attribute__((unused)),
  126. Slapi_Entry *e,
  127. Slapi_Entry *entryAfter __attribute__((unused)),
  128. int *returncode,
  129. char *returntext,
  130. void *arg __attribute__((unused)))
  131. {
  132. int rc;
  133. changelog5Config config;
  134. *returncode = LDAP_SUCCESS;
  135. slapi_rwlock_wrlock(s_configLock);
  136. /* we already have a configured changelog - don't need to do anything
  137. since add operation will fail */
  138. if (cl5GetState() == CL5_STATE_OPEN) {
  139. *returncode = 1;
  140. if (returntext) {
  141. strcpy(returntext, "attempt to add changelog when it already exists");
  142. }
  143. slapi_log_err(SLAPI_LOG_NOTICE, repl_plugin_name_cl,
  144. "changelog5_config_add - Changelog already exist; "
  145. "request ignored\n");
  146. goto done;
  147. }
  148. changelog5_extract_config(e, &config);
  149. if (config.dir == NULL) {
  150. *returncode = 1;
  151. if (returntext) {
  152. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "NULL changelog directory");
  153. }
  154. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
  155. "changelog5_config_add - NULL changelog directory\n");
  156. goto done;
  157. }
  158. if (!cl5DbDirIsEmpty(config.dir)) {
  159. *returncode = 1;
  160. if (returntext) {
  161. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  162. "The changelog directory [%s] already exists and is not empty. "
  163. "Please choose a directory that does not exist or is empty.\n",
  164. config.dir);
  165. }
  166. goto done;
  167. }
  168. /* start the changelog */
  169. rc = cl5Open(config.dir, &config.dbconfig);
  170. if (rc != CL5_SUCCESS) {
  171. *returncode = 1;
  172. if (returntext) {
  173. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Failed to start changelog; error - %d", rc);
  174. }
  175. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
  176. "changelog5_config_add - Failed to start changelog\n");
  177. goto done;
  178. }
  179. /* set trimming parameters */
  180. rc = cl5ConfigTrimming(config.maxEntries, config.maxAge, config.compactInterval, config.trimInterval);
  181. if (rc != CL5_SUCCESS) {
  182. *returncode = 1;
  183. if (returntext) {
  184. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "failed to configure changelog trimming; error - %d", rc);
  185. }
  186. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
  187. "changelog5_config_add - Failed to configure changelog trimming\n");
  188. goto done;
  189. }
  190. /* notify all the replicas that the changelog is configured
  191. so that the can log dummy changes if necessary. */
  192. replica_enumerate_replicas(notify_replica, NULL);
  193. #ifdef TEST_CL5
  194. testChangelog(TEST_ITERATION);
  195. #endif
  196. done:;
  197. slapi_rwlock_unlock(s_configLock);
  198. changelog5_config_done(&config);
  199. if (*returncode == LDAP_SUCCESS) {
  200. if (returntext) {
  201. returntext[0] = '\0';
  202. }
  203. return SLAPI_DSE_CALLBACK_OK;
  204. }
  205. return SLAPI_DSE_CALLBACK_ERROR;
  206. }
  207. static int
  208. changelog5_config_modify(Slapi_PBlock *pb,
  209. Slapi_Entry *entryBefore __attribute__((unused)),
  210. Slapi_Entry *e,
  211. int *returncode,
  212. char *returntext,
  213. void *arg __attribute__((unused)))
  214. {
  215. int rc = 0;
  216. LDAPMod **mods;
  217. int i;
  218. changelog5Config config;
  219. changelog5Config *originalConfig = NULL;
  220. char *currentDir = NULL;
  221. *returncode = LDAP_SUCCESS;
  222. /* changelog must be open before its parameters can be modified */
  223. if (cl5GetState() != CL5_STATE_OPEN) {
  224. if (returntext) {
  225. strcpy(returntext, "changelog is not configured");
  226. }
  227. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
  228. "changelog5_config_modify - Changelog is not configured\n");
  229. return SLAPI_DSE_CALLBACK_ERROR;
  230. }
  231. slapi_rwlock_wrlock(s_configLock);
  232. /* changelog must be open before its parameters can be modified */
  233. if (cl5GetState() != CL5_STATE_OPEN) {
  234. *returncode = 1;
  235. if (returntext) {
  236. strcpy(returntext, "changelog is not configured");
  237. }
  238. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
  239. "changelog5_config_modify - Changelog is not configured\n");
  240. goto done;
  241. }
  242. /*
  243. * Extract all the original configuration: This is needed to ensure that the configuration
  244. * is trully reloaded. This was not needed before 091401 because the changelog configuration
  245. * was always hardcoded (NULL was being passed to cl5Open). Now we need to ensure we pass to
  246. * cl5Open the proper configuration...
  247. */
  248. changelog5_extract_config(e, &config);
  249. originalConfig = changelog5_dup_config(&config);
  250. /* Reset all the attributes that have been potentially modified by the current MODIFY operation */
  251. slapi_ch_free_string(&config.dir);
  252. config.dir = NULL;
  253. config.maxEntries = CL5_NUM_IGNORE;
  254. config.compactInterval = CL5_NUM_IGNORE;
  255. slapi_ch_free_string(&config.maxAge);
  256. config.maxAge = slapi_ch_strdup(CL5_STR_IGNORE);
  257. config.trimInterval = CL5_NUM_IGNORE;
  258. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  259. for (i = 0; mods && mods[i] != NULL; i++) {
  260. if (mods[i]->mod_op & LDAP_MOD_DELETE) {
  261. /* We don't support deleting changelog attributes */
  262. } else {
  263. int j;
  264. for (j = 0; ((mods[i]->mod_values[j]) && (LDAP_SUCCESS == rc)); j++) {
  265. char *config_attr, *config_attr_value;
  266. config_attr = (char *)mods[i]->mod_type;
  267. config_attr_value = (char *)mods[i]->mod_bvalues[j]->bv_val;
  268. if (slapi_attr_is_last_mod(config_attr)) {
  269. continue;
  270. }
  271. /* replace existing value */
  272. if (strcasecmp(config_attr, CONFIG_CHANGELOG_DIR_ATTRIBUTE) == 0) {
  273. if (config_attr_value && config_attr_value[0] != '\0') {
  274. slapi_ch_free_string(&config.dir);
  275. config.dir = slapi_ch_strdup(config_attr_value);
  276. replace_bslash(config.dir);
  277. } else {
  278. *returncode = 1;
  279. if (returntext) {
  280. strcpy(returntext, "null changelog directory");
  281. }
  282. goto done;
  283. }
  284. } else if (strcasecmp(config_attr, CONFIG_CHANGELOG_MAXENTRIES_ATTRIBUTE) == 0) {
  285. if (config_attr_value && config_attr_value[0] != '\0') {
  286. config.maxEntries = atoi(config_attr_value);
  287. } else {
  288. config.maxEntries = 0;
  289. }
  290. } else if (strcasecmp(config_attr, CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE) == 0) {
  291. if (slapi_is_duration_valid(config_attr_value)) {
  292. slapi_ch_free_string(&config.maxAge);
  293. config.maxAge = slapi_ch_strdup(config_attr_value);
  294. } else {
  295. if (returntext) {
  296. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  297. "%s: invalid value \"%s\", %s must range from 0 to %lld or digit[sSmMhHdD]",
  298. CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE, config_attr_value ? config_attr_value : "null",
  299. CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE,
  300. (long long int)LONG_MAX);
  301. }
  302. *returncode = LDAP_UNWILLING_TO_PERFORM;
  303. goto done;
  304. }
  305. } else if (strcasecmp(config_attr, CONFIG_CHANGELOG_COMPACTDB_ATTRIBUTE) == 0) {
  306. if (slapi_is_duration_valid(config_attr_value)) {
  307. config.compactInterval = (long)slapi_parse_duration(config_attr_value);
  308. } else {
  309. if (returntext) {
  310. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  311. "%s: invalid value \"%s\", %s must range from 0 to %lld or digit[sSmMhHdD]",
  312. CONFIG_CHANGELOG_COMPACTDB_ATTRIBUTE, config_attr_value,
  313. CONFIG_CHANGELOG_COMPACTDB_ATTRIBUTE,
  314. (long long int)LONG_MAX);
  315. }
  316. *returncode = LDAP_UNWILLING_TO_PERFORM;
  317. goto done;
  318. }
  319. } else if (strcasecmp(config_attr, CONFIG_CHANGELOG_TRIM_ATTRIBUTE) == 0) {
  320. if (slapi_is_duration_valid(config_attr_value)) {
  321. config.trimInterval = (long)slapi_parse_duration(config_attr_value);
  322. } else {
  323. if (returntext) {
  324. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  325. "%s: invalid value \"%s\", %s must range from 0 to %lld or digit[sSmMhHdD]",
  326. CONFIG_CHANGELOG_TRIM_ATTRIBUTE, config_attr_value,
  327. CONFIG_CHANGELOG_TRIM_ATTRIBUTE,
  328. (long long int)LONG_MAX);
  329. }
  330. *returncode = LDAP_UNWILLING_TO_PERFORM;
  331. goto done;
  332. }
  333. } else if (strcasecmp(config_attr, CONFIG_CHANGELOG_SYMMETRIC_KEY) == 0) {
  334. slapi_ch_free_string(&config.symmetricKey);
  335. config.symmetricKey = slapi_ch_strdup(config_attr_value);
  336. /* Storing the encryption symmetric key */
  337. /* no need to change any changelog configuration */
  338. goto done;
  339. } else {
  340. *returncode = LDAP_UNWILLING_TO_PERFORM;
  341. if (returntext) {
  342. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  343. "Unwilling to apply %s mods while the server is running", config_attr);
  344. }
  345. goto done;
  346. }
  347. }
  348. }
  349. }
  350. /* Undo the reset above for all the modifiable attributes that were not modified
  351. * except config.dir */
  352. if (config.maxEntries == CL5_NUM_IGNORE)
  353. config.maxEntries = originalConfig->maxEntries;
  354. if (config.compactInterval == CL5_NUM_IGNORE)
  355. config.compactInterval = originalConfig->compactInterval;
  356. if (config.trimInterval == CL5_NUM_IGNORE)
  357. config.trimInterval = originalConfig->trimInterval;
  358. if (strcmp(config.maxAge, CL5_STR_IGNORE) == 0) {
  359. slapi_ch_free_string(&config.maxAge);
  360. if (originalConfig->maxAge)
  361. config.maxAge = slapi_ch_strdup(originalConfig->maxAge);
  362. }
  363. /* attempt to change chagelog dir */
  364. if (config.dir) {
  365. currentDir = cl5GetDir();
  366. if (currentDir == NULL) {
  367. /* something is wrong: we should never be here */
  368. *returncode = 1;
  369. if (returntext) {
  370. strcpy(returntext, "internal failure");
  371. }
  372. goto done;
  373. }
  374. if (strcmp(currentDir, config.dir) != 0) {
  375. if (!cl5DbDirIsEmpty(config.dir)) {
  376. *returncode = 1;
  377. if (returntext) {
  378. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  379. "The changelog directory [%s] already exists and is not empty. "
  380. "Please choose a directory that does not exist or is empty.\n",
  381. config.dir);
  382. }
  383. goto done;
  384. }
  385. if (!_is_absolutepath(config.dir) || (CL5_SUCCESS != cl5CreateDirIfNeeded(config.dir))) {
  386. *returncode = 1;
  387. if (returntext) {
  388. PL_strncpyz(returntext, "invalid changelog directory or insufficient access", SLAPI_DSE_RETURNTEXT_SIZE);
  389. }
  390. goto done;
  391. }
  392. /* changelog directory changed - need to remove the
  393. previous changelog and create new one */
  394. slapi_log_err(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
  395. "changelog5_config_modify - Changelog directory changed; "
  396. "old dir - %s, new dir - %s; recreating changelog.\n",
  397. currentDir, config.dir);
  398. rc = cl5Close();
  399. if (rc != CL5_SUCCESS) {
  400. *returncode = 1;
  401. if (returntext) {
  402. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Failed to close changelog; error - %d", rc);
  403. }
  404. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
  405. "changelog5_config_modify - Failed to close changelog\n");
  406. goto done;
  407. } else {
  408. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name_cl,
  409. "changelog5_config_modif - Closed the changelog\n");
  410. }
  411. rc = cl5Delete(currentDir);
  412. if (rc != CL5_SUCCESS) {
  413. *returncode = 1;
  414. if (returntext) {
  415. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "failed to remove changelog; error - %d", rc);
  416. }
  417. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
  418. "changelog5_config_modify - Failed to remove changelog\n");
  419. goto done;
  420. } else {
  421. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name_cl,
  422. "changelog5_config_modify - Deleted the changelog at %s\n", currentDir);
  423. }
  424. rc = cl5Open(config.dir, &config.dbconfig);
  425. if (rc != CL5_SUCCESS) {
  426. *returncode = 1;
  427. if (returntext) {
  428. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Failed to restart changelog; error - %d", rc);
  429. }
  430. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
  431. "changelog5_config_modify - Failed to restart changelog\n");
  432. /* before finishing, let's try to do some error recovery */
  433. if (CL5_SUCCESS != cl5Open(currentDir, &config.dbconfig)) {
  434. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
  435. "changelog5_config_modify - Failed to restore previous changelog\n");
  436. }
  437. goto done;
  438. } else {
  439. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name_cl,
  440. "changelog5_config_modify - Opened the changelog at %s\n", config.dir);
  441. }
  442. }
  443. }
  444. /* one of the changelog parameters is modified */
  445. if (config.maxEntries != CL5_NUM_IGNORE ||
  446. config.trimInterval != CL5_NUM_IGNORE ||
  447. strcmp(config.maxAge, CL5_STR_IGNORE) != 0) {
  448. rc = cl5ConfigTrimming(config.maxEntries, config.maxAge, config.compactInterval, config.trimInterval);
  449. if (rc != CL5_SUCCESS) {
  450. *returncode = 1;
  451. if (returntext) {
  452. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "failed to configure changelog trimming; error - %d", rc);
  453. }
  454. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
  455. "changelog5_config_modify - Failed to configure changelog trimming\n");
  456. goto done;
  457. }
  458. }
  459. done:;
  460. slapi_rwlock_unlock(s_configLock);
  461. changelog5_config_done(&config);
  462. changelog5_config_free(&originalConfig);
  463. /* slapi_ch_free accepts NULL pointer */
  464. slapi_ch_free((void **)&currentDir);
  465. if (*returncode == LDAP_SUCCESS) {
  466. if (returntext) {
  467. returntext[0] = '\0';
  468. }
  469. return SLAPI_DSE_CALLBACK_OK;
  470. }
  471. return SLAPI_DSE_CALLBACK_ERROR;
  472. }
  473. static int
  474. changelog5_config_delete(Slapi_PBlock *pb __attribute__((unused)),
  475. Slapi_Entry *e __attribute__((unused)),
  476. Slapi_Entry *entryAfter __attribute__((unused)),
  477. int *returncode,
  478. char *returntext,
  479. void *arg __attribute__((unused)))
  480. {
  481. int rc;
  482. char *currentDir = NULL;
  483. *returncode = LDAP_SUCCESS;
  484. /* changelog must be open before it can be deleted */
  485. if (cl5GetState() != CL5_STATE_OPEN) {
  486. *returncode = 1;
  487. if (returntext) {
  488. PL_strncpyz(returntext, "changelog is not configured", SLAPI_DSE_RETURNTEXT_SIZE);
  489. }
  490. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
  491. "changelog5_config_delete - Chagelog is not configured\n");
  492. return SLAPI_DSE_CALLBACK_ERROR;
  493. }
  494. slapi_rwlock_wrlock(s_configLock);
  495. /* changelog must be open before it can be deleted */
  496. if (cl5GetState() != CL5_STATE_OPEN) {
  497. *returncode = 1;
  498. if (returntext) {
  499. PL_strncpyz(returntext, "changelog is not configured", SLAPI_DSE_RETURNTEXT_SIZE);
  500. }
  501. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
  502. "changelog5_config_delete - Changelog is not configured\n");
  503. goto done;
  504. }
  505. currentDir = cl5GetDir();
  506. if (currentDir == NULL) {
  507. /* something is wrong: we should never be here */
  508. *returncode = 1;
  509. if (returntext) {
  510. PL_strncpyz(returntext, "internal failure", SLAPI_DSE_RETURNTEXT_SIZE);
  511. }
  512. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
  513. "changelog5_config_delete - NULL directory\n");
  514. goto done;
  515. }
  516. /* this call will block until all threads using changelog
  517. release changelog by calling cl5RemoveThread () */
  518. rc = cl5Close();
  519. if (rc != CL5_SUCCESS) {
  520. *returncode = 1;
  521. if (returntext) {
  522. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "failed to close changelog; error - %d", rc);
  523. }
  524. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
  525. "changelog5_config_delete - Failed to close changelog\n");
  526. goto done;
  527. }
  528. rc = cl5Delete(currentDir);
  529. if (rc != CL5_SUCCESS) {
  530. *returncode = 1;
  531. if (returntext) {
  532. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "failed to remove changelog; error - %d", rc);
  533. }
  534. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
  535. "changelog5_config_delete - Failed to remove changelog\n");
  536. goto done;
  537. }
  538. done:;
  539. slapi_rwlock_unlock(s_configLock);
  540. /* slapi_ch_free accepts NULL pointer */
  541. slapi_ch_free((void **)&currentDir);
  542. if (*returncode == LDAP_SUCCESS) {
  543. if (returntext) {
  544. returntext[0] = '\0';
  545. }
  546. return SLAPI_DSE_CALLBACK_OK;
  547. }
  548. return SLAPI_DSE_CALLBACK_ERROR;
  549. }
  550. static int
  551. dont_allow_that(Slapi_PBlock *pb __attribute__((unused)),
  552. Slapi_Entry *entryBefore __attribute__((unused)),
  553. Slapi_Entry *e __attribute__((unused)),
  554. int *returncode,
  555. char *returntext __attribute__((unused)),
  556. void *arg __attribute__((unused)))
  557. {
  558. *returncode = LDAP_UNWILLING_TO_PERFORM;
  559. return SLAPI_DSE_CALLBACK_ERROR;
  560. }
  561. static changelog5Config *
  562. changelog5_dup_config(changelog5Config *config)
  563. {
  564. changelog5Config *dup = (changelog5Config *)slapi_ch_calloc(1, sizeof(changelog5Config));
  565. if (config->dir)
  566. dup->dir = slapi_ch_strdup(config->dir);
  567. if (config->maxAge)
  568. dup->maxAge = slapi_ch_strdup(config->maxAge);
  569. dup->maxEntries = config->maxEntries;
  570. dup->compactInterval = config->compactInterval;
  571. dup->trimInterval = config->trimInterval;
  572. dup->dbconfig.pageSize = config->dbconfig.pageSize;
  573. dup->dbconfig.fileMode = config->dbconfig.fileMode;
  574. return dup;
  575. }
  576. /*
  577. * Given the changelog configuration entry, extract the configuration directives.
  578. */
  579. static void
  580. changelog5_extract_config(Slapi_Entry *entry, changelog5Config *config)
  581. {
  582. char *arg;
  583. memset(config, 0, sizeof(*config));
  584. config->dir = slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_DIR_ATTRIBUTE);
  585. replace_bslash(config->dir);
  586. arg = slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_MAXENTRIES_ATTRIBUTE);
  587. if (arg) {
  588. config->maxEntries = atoi(arg);
  589. slapi_ch_free_string(&arg);
  590. }
  591. arg = slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_COMPACTDB_ATTRIBUTE);
  592. if (arg) {
  593. if (slapi_is_duration_valid(arg)) {
  594. config->compactInterval = (long)slapi_parse_duration(arg);
  595. } else {
  596. slapi_log_err(SLAPI_LOG_NOTICE, repl_plugin_name_cl,
  597. "changelog5_extract_config - %s: invalid value \"%s\", ignoring the change.\n",
  598. CONFIG_CHANGELOG_COMPACTDB_ATTRIBUTE, arg);
  599. }
  600. slapi_ch_free_string(&arg);
  601. } else {
  602. config->compactInterval = CHANGELOGDB_COMPACT_INTERVAL;
  603. }
  604. arg = slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_TRIM_ATTRIBUTE);
  605. if (arg) {
  606. if (slapi_is_duration_valid(arg)) {
  607. config->trimInterval = (long)slapi_parse_duration(arg);
  608. } else {
  609. slapi_log_err(SLAPI_LOG_NOTICE, repl_plugin_name_cl,
  610. "changelog5_extract_config - %s: invalid value \"%s\", ignoring the change.\n",
  611. CONFIG_CHANGELOG_TRIM_ATTRIBUTE, arg);
  612. config->trimInterval = CHANGELOGDB_TRIM_INTERVAL;
  613. }
  614. slapi_ch_free_string(&arg);
  615. } else {
  616. config->trimInterval = CHANGELOGDB_TRIM_INTERVAL;
  617. }
  618. arg = slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE);
  619. if (arg) {
  620. if (slapi_is_duration_valid(arg)) {
  621. config->maxAge = arg;
  622. } else {
  623. slapi_log_err(SLAPI_LOG_NOTICE, repl_plugin_name_cl,
  624. "changelog5_extract_config - %s: invalid value \"%s\", ignoring the change.\n",
  625. CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE, arg);
  626. slapi_ch_free_string(&arg);
  627. config->maxAge = slapi_ch_strdup(CL5_STR_IGNORE);
  628. }
  629. } else {
  630. config->maxAge = slapi_ch_strdup(CL5_STR_IGNORE);
  631. }
  632. /*
  633. * changelog encryption
  634. */
  635. arg = slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_ENCRYPTION_ALGORITHM);
  636. if (arg) {
  637. config->dbconfig.encryptionAlgorithm = slapi_ch_strdup(arg);
  638. slapi_ch_free_string(&arg);
  639. } else {
  640. config->dbconfig.encryptionAlgorithm = NULL; /* no encryption */
  641. }
  642. /*
  643. * symmetric key
  644. */
  645. arg = slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_SYMMETRIC_KEY);
  646. if (arg) {
  647. config->dbconfig.symmetricKey = slapi_ch_strdup(arg);
  648. slapi_ch_free_string(&arg);
  649. } else {
  650. config->dbconfig.symmetricKey = NULL; /* no symmetric key */
  651. }
  652. }
  653. static void
  654. replace_bslash(char *dir)
  655. {
  656. char *bslash;
  657. if (dir == NULL)
  658. return;
  659. bslash = strchr(dir, '\\');
  660. while (bslash) {
  661. *bslash = '/';
  662. bslash = strchr(bslash, '\\');
  663. }
  664. }
  665. static int
  666. notify_replica(Replica *r, void *arg __attribute__((unused)))
  667. {
  668. return replica_log_ruv_elements(r);
  669. }
  670. static int
  671. _is_absolutepath(char *dir)
  672. {
  673. if (dir[0] == '/')
  674. return 1;
  675. return 0;
  676. }