retrocl_po.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  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. #include "retrocl.h"
  7. static int
  8. entry2reple( Slapi_Entry *e, Slapi_Entry *oe );
  9. static int
  10. mods2reple( Slapi_Entry *e, LDAPMod **ldm );
  11. static int
  12. modrdn2reple( Slapi_Entry *e, const char *newrdn, int deloldrdn,
  13. LDAPMod **ldm, const char *newsup );
  14. /******************************/
  15. const char *attr_changenumber = "changenumber";
  16. const char *attr_targetdn = "targetdn";
  17. const char *attr_changetype = "changetype";
  18. const char *attr_newrdn = "newrdn";
  19. const char *attr_deleteoldrdn = "deleteoldrdn";
  20. const char *attr_changes = "changes";
  21. const char *attr_newsuperior = "newsuperior";
  22. const char *attr_changetime = "changetime";
  23. const char *attr_objectclass = "objectclass";
  24. /*
  25. * Function: make_changes_string
  26. *
  27. * Returns:
  28. *
  29. * Arguments:
  30. *
  31. * Description:
  32. * loop through the LDAPMod struct and construct the changes attribute/
  33. *
  34. */
  35. static lenstr *make_changes_string(LDAPMod **ldm, const char **includeattrs)
  36. {
  37. lenstr *l;
  38. int i, j, len;
  39. int skip;
  40. l = lenstr_new();
  41. for ( i = 0; ldm[ i ] != NULL; i++ ) {
  42. /* If a list of explicit attributes was given, only add those */
  43. if ( NULL != includeattrs ) {
  44. skip = 1;
  45. for ( j = 0; includeattrs[ j ] != NULL; j++ ) {
  46. if ( strcasecmp( includeattrs[ j ], ldm[ i ]->mod_type ) == 0 ) {
  47. skip = 0;
  48. break;
  49. }
  50. }
  51. if ( skip ) {
  52. continue;
  53. }
  54. }
  55. switch ( ldm[ i ]->mod_op & ~LDAP_MOD_BVALUES ) {
  56. case LDAP_MOD_ADD:
  57. addlenstr( l, "add: " );
  58. addlenstr( l, ldm[ i ]->mod_type );
  59. addlenstr( l, "\n" );
  60. break;
  61. case LDAP_MOD_DELETE:
  62. addlenstr( l, "delete: " );
  63. addlenstr( l, ldm[ i ]->mod_type );
  64. addlenstr( l, "\n" );
  65. break;
  66. case LDAP_MOD_REPLACE:
  67. addlenstr( l, "replace: " );
  68. addlenstr( l, ldm[ i ]->mod_type );
  69. addlenstr( l, "\n" );
  70. break;
  71. }
  72. for ( j = 0; ldm[ i ]->mod_bvalues != NULL &&
  73. ldm[ i ]->mod_bvalues[ j ] != NULL; j++ ) {
  74. char *buf = NULL;
  75. char *bufp = NULL;
  76. len = strlen( ldm[ i ]->mod_type );
  77. len = LDIF_SIZE_NEEDED( len,
  78. ldm[ i ]->mod_bvalues[ j ]->bv_len ) + 1;
  79. buf = slapi_ch_malloc( len );
  80. bufp = buf;
  81. ldif_put_type_and_value( &bufp, ldm[ i ]->mod_type,
  82. ldm[ i ]->mod_bvalues[ j ]->bv_val,
  83. ldm[ i ]->mod_bvalues[ j ]->bv_len );
  84. *bufp = '\0';
  85. addlenstr( l, buf );
  86. free( buf );
  87. }
  88. addlenstr( l, "-\n" );
  89. }
  90. return l;
  91. }
  92. /*
  93. * Function: write_replog_db
  94. * Arguments: be - backend to which this change is being applied
  95. * optype - type of LDAP operation being logged
  96. * dn - distinguished name of entry being changed
  97. * log_m - pointer to the actual change operation on a modify
  98. * flag - only used by modrdn operations - value of deleteoldrdn
  99. * curtime - the current time
  100. * Returns: nothing
  101. * Description: Given a change, construct an entry which is to be added to the
  102. * changelog database.
  103. */
  104. static void
  105. write_replog_db(
  106. int optype,
  107. char *dn,
  108. LDAPMod **log_m,
  109. int flag,
  110. time_t curtime,
  111. Slapi_Entry *log_e,
  112. const char *newrdn,
  113. LDAPMod **modrdn_mods,
  114. const char *newsuperior
  115. )
  116. {
  117. char *edn;
  118. struct berval *vals[ 2 ];
  119. struct berval val;
  120. Slapi_Entry *e;
  121. char chnobuf[ 20 ];
  122. int err;
  123. Slapi_PBlock *pb = NULL;
  124. changeNumber changenum;
  125. PR_Lock(retrocl_internal_lock);
  126. changenum = retrocl_assign_changenumber();
  127. PR_ASSERT( changenum > 0UL );
  128. slapi_log_error( SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME,
  129. "write_replog_db: write change record %d for dn: \"%s\"\n",
  130. changenum, ( dn == NULL ) ? "NULL" : dn );
  131. /* Construct the dn of this change record */
  132. edn = slapi_ch_smprintf( "%s=%lu,%s", attr_changenumber, changenum, RETROCL_CHANGELOG_DN);
  133. /*
  134. * Create the entry struct, and fill in fields common to all types
  135. * of change records.
  136. */
  137. vals[ 0 ] = &val;
  138. vals[ 1 ] = NULL;
  139. e = slapi_entry_alloc();
  140. slapi_entry_set_dn( e, slapi_ch_strdup( edn ));
  141. /* Set the objectclass attribute */
  142. val.bv_val = "top";
  143. val.bv_len = 3;
  144. slapi_entry_add_values( e, "objectclass", vals );
  145. val.bv_val = "changelogentry";
  146. val.bv_len = 14;
  147. slapi_entry_add_values( e, "objectclass", vals );
  148. /* Set the changeNumber attribute */
  149. sprintf( chnobuf, "%lu", changenum );
  150. val.bv_val = chnobuf;
  151. val.bv_len = strlen( chnobuf );
  152. slapi_entry_add_values( e, attr_changenumber, vals );
  153. /* Set the targetentrydn attribute */
  154. val.bv_val = dn;
  155. val.bv_len = strlen( dn );
  156. slapi_entry_add_values( e, attr_targetdn, vals );
  157. /* Set the changeTime attribute */
  158. val.bv_val = format_genTime (curtime);
  159. val.bv_len = strlen( val.bv_val );
  160. slapi_entry_add_values( e, attr_changetime, vals );
  161. free( val.bv_val );
  162. /*
  163. * Finish constructing the entry. How to do it depends on the type
  164. * of modification being logged.
  165. */
  166. err = 0;
  167. switch ( optype ) {
  168. case OP_ADD:
  169. if ( entry2reple( e, log_e ) != 0 ) {
  170. err = 1;
  171. }
  172. break;
  173. case OP_MODIFY:
  174. if ( mods2reple( e, log_m ) != 0 ) {
  175. err = 1;
  176. }
  177. break;
  178. case OP_MODRDN:
  179. if ( modrdn2reple( e, newrdn, flag, modrdn_mods, newsuperior ) != 0 ) {
  180. err = 1;
  181. }
  182. break;
  183. case OP_DELETE:
  184. /* Set the changetype attribute */
  185. val.bv_val = "delete";
  186. val.bv_len = 6;
  187. slapi_entry_add_values( e, attr_changetype, vals );
  188. break;
  189. default:
  190. slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "replog: Unknown LDAP operation type "
  191. "%d.\n", optype );
  192. err = 1;
  193. }
  194. /* Call the repl backend to add this entry */
  195. if ( 0 == err ) {
  196. int rc;
  197. pb = slapi_pblock_new ();
  198. slapi_add_entry_internal_set_pb( pb, e, NULL /* controls */,
  199. g_plg_identity[PLUGIN_RETROCL],
  200. 0 /* actions */ );
  201. slapi_add_internal_pb (pb);
  202. slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &rc );
  203. slapi_pblock_destroy(pb);
  204. if ( 0 != rc ) {
  205. slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
  206. "replog: an error occured while adding change "
  207. "number %d, dn = %s: %s. \n",
  208. changenum, edn, ldap_err2string( rc ));
  209. retrocl_release_changenumber();
  210. } else {
  211. /* Tell the change numbering system this one's committed to disk */
  212. retrocl_commit_changenumber( );
  213. }
  214. } else {
  215. slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
  216. "An error occurred while constructing "
  217. "change record number %ld.\n", changenum );
  218. retrocl_release_changenumber();
  219. }
  220. PR_Unlock(retrocl_internal_lock);
  221. if ( NULL != edn ) {
  222. slapi_ch_free((void **) &edn);
  223. }
  224. }
  225. /*
  226. * Function: entry2reple
  227. * Arguments: e - a partially-constructed Slapi_Entry structure
  228. * oe - the original entry (an entry being added by a client).
  229. * Returns: 0 on success.
  230. * Description: Given an Slapi_Entry struct, construct a changelog entry which will be
  231. * added to the replication database. It is assumed that e points
  232. * to an entry obtained from slapi_entry_alloc().
  233. */
  234. static int
  235. entry2reple( Slapi_Entry *e, Slapi_Entry *oe )
  236. {
  237. char *p, *estr;
  238. struct berval *vals[ 2 ];
  239. struct berval val;
  240. int len;
  241. vals[ 0 ] = &val;
  242. vals[ 1 ] = NULL;
  243. /* Set the changetype attribute */
  244. val.bv_val = "add";
  245. val.bv_len = 3;
  246. slapi_entry_add_values( e, attr_changetype, vals );
  247. estr = slapi_entry2str( oe, &len );
  248. p = estr;
  249. /* Skip over the dn: line */
  250. while (( p = strchr( p, '\n' )) != NULL ) {
  251. p++;
  252. if ( !ldap_utf8isspace( p )) {
  253. break;
  254. }
  255. }
  256. val.bv_val = p;
  257. val.bv_len = len - ( p - estr ); /* length + terminating \0 */
  258. slapi_entry_add_values( e, attr_changes, vals );
  259. free( estr );
  260. return 0;
  261. }
  262. /*
  263. * Function: mods2reple
  264. * Arguments: e - a partially-constructed Slapi_Entry structure
  265. * ldm - an array of pointers to LDAPMod structures describing the
  266. * change applied.
  267. * Returns: 0 on success.
  268. * Description: Given a pointer to an LDAPMod struct and a dn, construct
  269. * a new entry which will be added to the replication database.
  270. * It is assumed that e points to an entry obtained from
  271. * slapi_entry_alloc().
  272. */
  273. static int
  274. mods2reple( Slapi_Entry *e, LDAPMod **ldm )
  275. {
  276. struct berval val;
  277. struct berval *vals[ 2 ];
  278. lenstr *l;
  279. vals[ 0 ] = &val;
  280. vals[ 1 ] = NULL;
  281. /* Set the changetype attribute */
  282. val.bv_val = "modify";
  283. val.bv_len = 6;
  284. slapi_entry_add_values( e, "changetype", vals );
  285. if (NULL != ldm) {
  286. l = make_changes_string( ldm, NULL );
  287. if ( NULL != l ) {
  288. val.bv_val = l->ls_buf;
  289. val.bv_len = l->ls_len + 1; /* string + terminating \0 */
  290. slapi_entry_add_values( e, attr_changes, vals );
  291. lenstr_free( &l );
  292. }
  293. }
  294. return 0;
  295. }
  296. /*
  297. * Function: modrdn2reple
  298. * Arguments: e - a partially-constructed Slapi_Entry structure
  299. * newrdn - the new relative distinguished name for the entry
  300. * deloldrdn - the "deleteoldrdn" flag provided by the client
  301. * ldm - any modifications applied as a side-effect of the modrdn
  302. * Returns: 0 on success
  303. * Description: Given a dn, a new rdn, and a deleteoldrdn flag, construct
  304. * a new entry which will be added to the replication database reflecting a
  305. * completed modrdn operation. The entry has the same form as above.
  306. * It is assumed that e points to an entry obtained from slapi_entry_alloc().
  307. */
  308. static int
  309. modrdn2reple(
  310. Slapi_Entry *e,
  311. const char *newrdn,
  312. int deloldrdn,
  313. LDAPMod **ldm,
  314. const char *newsuperior
  315. )
  316. {
  317. struct berval val;
  318. struct berval *vals[ 2 ];
  319. lenstr *l;
  320. static const char *lastmodattrs[] = {"modifiersname", "modifytimestamp",
  321. "creatorsname", "createtimestamp",
  322. NULL };
  323. vals[ 0 ] = &val;
  324. vals[ 1 ] = NULL;
  325. val.bv_val = "modrdn";
  326. val.bv_len = 6;
  327. slapi_entry_add_values( e, attr_changetype, vals );
  328. if (newrdn) {
  329. val.bv_val = (char *)newrdn; /* cast away const */
  330. val.bv_len = strlen( newrdn );
  331. slapi_entry_add_values( e, attr_newrdn, vals );
  332. }
  333. if ( deloldrdn == 0 ) {
  334. val.bv_val = "FALSE";
  335. val.bv_len = 5;
  336. } else {
  337. val.bv_val = "TRUE";
  338. val.bv_len = 4;
  339. }
  340. slapi_entry_add_values( e, attr_deleteoldrdn, vals );
  341. if (newsuperior) {
  342. val.bv_val = (char *)newsuperior; /* cast away const */
  343. val.bv_len = strlen(newsuperior);
  344. slapi_entry_add_values(e, attr_newsuperior,vals);
  345. }
  346. if (NULL != ldm) {
  347. l = make_changes_string( ldm, lastmodattrs );
  348. if ( NULL != l ) {
  349. val.bv_val = l->ls_buf;
  350. val.bv_len = l->ls_len + 1; /* string + terminating \0 */
  351. slapi_entry_add_values( e, attr_changes, vals );
  352. lenstr_free( &l );
  353. }
  354. }
  355. return 0;
  356. }
  357. /*
  358. * Function: retrocl_postob
  359. *
  360. * Returns: 0 on success
  361. *
  362. * Arguments: pblock, optype (add, del, modify etc)
  363. *
  364. * Description: called from retrocl.c op-specific plugins.
  365. *
  366. * Please be aware that operation threads may be scheduled out between their
  367. * being performed inside of the LDBM database and the changelog plugin
  368. * running. For example, suppose MA and MB are two modify operations on the
  369. * same entry. MA may be performed on the LDBM database, and then block
  370. * before the changelog runs. MB then runs against the LDBM database and then
  371. * is written to the changelog. MA starts running. In the changelog, MB will
  372. * appear to have been performed before MA, but in the LDBM database the
  373. * opposite will have occured.
  374. *
  375. *
  376. */
  377. int retrocl_postob (Slapi_PBlock *pb,int optype)
  378. {
  379. char *dn;
  380. LDAPMod **log_m = NULL;
  381. int flag = 0;
  382. Slapi_Entry *te = NULL;
  383. Slapi_Operation *op = NULL;
  384. LDAPMod **modrdn_mods = NULL;
  385. char *newrdn = NULL;
  386. char *newsuperior = NULL;
  387. Slapi_Backend *be = NULL;
  388. time_t curtime;
  389. int rc;
  390. /*
  391. * Check to see if the change was made to the replication backend db.
  392. * If so, don't try to log it to the db (otherwise, we'd get in a loop).
  393. */
  394. (void)slapi_pblock_get( pb, SLAPI_BACKEND, &be );
  395. if (slapi_be_logchanges(be) == 0) {
  396. LDAPDebug(LDAP_DEBUG_TRACE,"not applying change if not logging\n",
  397. 0,0,0);
  398. return 0;
  399. }
  400. if (retrocl_be_changelog == NULL || be == retrocl_be_changelog) {
  401. LDAPDebug(LDAP_DEBUG_TRACE,"not applying change if no/cl be\n",0,0,0);
  402. return 0;
  403. }
  404. slapi_pblock_get(pb, SLAPI_RESULT_CODE, &rc);
  405. if (rc != LDAP_SUCCESS) {
  406. LDAPDebug(LDAP_DEBUG_TRACE,"not applying change if op failed %d\n",rc,
  407. 0,0);
  408. return 0;
  409. }
  410. if (slapi_op_abandoned(pb)) {
  411. LDAPDebug(LDAP_DEBUG_PLUGIN,"not applying change if op abandoned\n",
  412. 0,0,0);
  413. return 0;
  414. }
  415. curtime = current_time();
  416. (void)slapi_pblock_get( pb, SLAPI_ORIGINAL_TARGET_DN, &dn );
  417. /* change number could be retrieved from Operation extension stored in
  418. * the pblock, or else it needs to be made dynamically. */
  419. /* get the operation extension and retrieve the change number */
  420. slapi_pblock_get( pb, SLAPI_OPERATION, &op );
  421. if (op == NULL) {
  422. LDAPDebug(LDAP_DEBUG_TRACE,"not applying change if no op\n",0,0,0);
  423. return 0;
  424. }
  425. if (operation_is_flag_set(op, OP_FLAG_TOMBSTONE_ENTRY)){
  426. LDAPDebug(LDAP_DEBUG_TRACE,"not applying change for nsTombstone entries\n",0,0,0);
  427. return 0;
  428. }
  429. switch ( optype ) {
  430. case OP_MODIFY:
  431. (void)slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &log_m );
  432. break;
  433. case OP_ADD:
  434. /*
  435. * For adds, we want the unnormalized dn, so we can preserve
  436. * spacing, case, when replicating it.
  437. */
  438. (void)slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &te );
  439. if ( NULL != te ) {
  440. dn = slapi_entry_get_dn( te );
  441. }
  442. break;
  443. case OP_DELETE:
  444. break;
  445. case OP_MODRDN:
  446. (void)slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn );
  447. (void)slapi_pblock_get( pb, SLAPI_MODRDN_DELOLDRDN, &flag );
  448. (void)slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &modrdn_mods );
  449. (void)slapi_pblock_get( pb, SLAPI_MODRDN_NEWSUPERIOR, &newsuperior);
  450. break;
  451. }
  452. /* check if we should log change to retro changelog, and
  453. * if so, do it here */
  454. write_replog_db( optype, dn, log_m, flag, curtime, te,
  455. newrdn, modrdn_mods, newsuperior );
  456. return 0;
  457. }