From 37ad7614de9d06c1c226b1b137cbfb1af989e6b9 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Wed, 14 Sep 2005 15:27:20 +0000 Subject: [PATCH] Add syncdata keyword, to select different sync data formats. Defaults to "default", can be set to "accesslog" or "changelog". changelog is not fully implemented yet. --- servers/slapd/syncrepl.c | 302 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 301 insertions(+), 1 deletion(-) diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index 2fdf30b3b4..a9d246e20e 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -41,6 +41,10 @@ struct nonpresent_entry { LDAP_LIST_ENTRY(nonpresent_entry) npe_link; }; +#define SYNCDATA_DEFAULT 0 /* entries are plain LDAP entries */ +#define SYNCDATA_ACCESSLOG 1 /* entries are accesslog format */ +#define SYNCDATA_CHANGELOG 2 /* entries are changelog format */ + typedef struct syncinfo_s { struct slap_backend_db *si_be; struct re_s *si_re; @@ -70,6 +74,7 @@ typedef struct syncinfo_s { int si_tlimit; int si_refreshDelete; int si_refreshPresent; + int si_syncdata; Avlnode *si_presentlist; LDAP *si_ld; LDAP_LIST_HEAD(np, nonpresent_entry) si_nonpresentlist; @@ -79,6 +84,8 @@ typedef struct syncinfo_s { static int syncuuid_cmp( const void *, const void * ); static void avl_ber_bvfree( void * ); static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray ); +static int syncrepl_message_to_op( + syncinfo_t *, Operation *, LDAPMessage * ); static int syncrepl_message_to_entry( syncinfo_t *, Operation *, LDAPMessage *, Modifications **, Entry **, int ); @@ -621,7 +628,14 @@ do_syncrep2( slap_parse_sync_cookie( &syncCookie, NULL ); } } - if ( syncrepl_message_to_entry( si, op, msg, + if ( si->si_syncdata ) { + entry = NULL; + modlist = NULL; + if ( syncrepl_message_to_op( si, op, msg ) == LDAP_SUCCESS && + !BER_BVISNULL( &syncCookie.octet_str ) ) { + syncrepl_updateCookie( si, op, psub, &syncCookie ); + } + } else if ( syncrepl_message_to_entry( si, op, msg, &modlist, &entry, syncstate ) == LDAP_SUCCESS ) { rc_efree = syncrepl_entry( si, op, entry, &modlist, syncstate, &syncUUID, &syncCookie_req, &syncCookie.ctxcsn ); @@ -1025,6 +1039,270 @@ do_syncrepl( return NULL; } +typedef struct logschema { + struct berval ls_dn; + struct berval ls_req; + struct berval ls_mod; + struct berval ls_newRdn; + struct berval ls_delRdn; + struct berval ls_newSup; +} logschema; + +static logschema changelog_sc = { + BER_BVC("targetDN"), + BER_BVC("changeType"), + BER_BVC("changes"), + BER_BVC("newRDN"), + BER_BVC("deleteOldRDN"), + BER_BVC("newSuperior") +}; + +static logschema accesslog_sc = { + BER_BVC("reqDN"), + BER_BVC("reqType"), + BER_BVC("reqMod"), + BER_BVC("reqNewRDN"), + BER_BVC("reqDeleteOldRDN"), + BER_BVC("reqNewSuperior") +}; + +static slap_verbmasks modops[] = { + { BER_BVC("add"), LDAP_REQ_ADD }, + { BER_BVC("delete"), LDAP_REQ_DELETE }, + { BER_BVC("modify"), LDAP_REQ_MODIFY }, + { BER_BVC("modrdn"), LDAP_REQ_MODRDN}, + { BER_BVNULL, 0 } +}; + +static Modifications * +syncrepl_accesslog_mods( + syncinfo_t *si, + struct berval *vals +) +{ + char *colon; + const char *text; + AttributeDescription *ad; + struct berval bv, bv2; + short op; + Modifications *mod = NULL, *modlist = NULL, **modtail; + int i; + + modtail = &modlist; + + for (i=0; !BER_BVISNULL( &vals[i] ); i++) { + ad = NULL; + bv = vals[i]; + + colon = strchr( bv.bv_val, ':' ); + if ( !colon ) + continue; /* invalid */ + bv.bv_len = colon - bv.bv_val; + if ( slap_bv2ad( &bv, &ad, &text )) { + /* Invalid */ + continue; + } + /* Ignore dynamically generated attrs */ + if ( ad->ad_type->sat_flags & SLAP_AT_DYNAMIC ) + continue; + /* Ignore excluded attrs */ + if ( ldap_charray_inlist( si->si_exattrs, + ad->ad_type->sat_cname.bv_val )) + continue; + + switch(colon[1]) { + case '+': op = LDAP_MOD_ADD; break; + case '-': op = LDAP_MOD_DELETE; break; + case '=': op = LDAP_MOD_REPLACE; break; + case '#': op = LDAP_MOD_INCREMENT; break; + default: continue; + } + + if ( !mod || ad != mod->sml_desc || op != mod->sml_op ) { + mod = (Modifications *) ch_malloc( sizeof( Modifications )); + mod->sml_flags = 0; + mod->sml_op = op; + mod->sml_next = NULL; + mod->sml_desc = ad; + mod->sml_type = ad->ad_cname; + mod->sml_values = NULL; + mod->sml_nvalues = NULL; + + *modtail = mod; + modtail = &mod->sml_next; + } + bv.bv_val = colon + 3; + bv.bv_len = vals[i].bv_len - ( bv.bv_val - vals[i].bv_val ); + ber_dupbv( &bv2, &bv ); + ber_bvarray_add( &mod->sml_values, &bv2 ); + } + return modlist; +} + +static Modifications * +syncrepl_changelog_mods( + syncinfo_t *si, + struct berval *vals +) +{ +} + +static int +syncrepl_message_to_op( + syncinfo_t *si, + Operation *op, + LDAPMessage *msg +) +{ + BerElement *ber = NULL; + Modifications *modlist = NULL; + logschema *ls; + SlapReply rs = { REP_RESULT }; + slap_callback cb = { NULL, null_callback, NULL, NULL }; + + const char *text; + char txtbuf[SLAP_TEXT_BUFLEN]; + size_t textlen = sizeof txtbuf; + + struct berval bdn, dn = BER_BVNULL, ndn; + struct berval bv, *bvals = NULL; + struct berval rdn = BER_BVNULL, sup = BER_BVNULL, + prdn = BER_BVNULL, nrdn = BER_BVNULL, + psup = BER_BVNULL, nsup = BER_BVNULL; + int rc, deleteOldRdn = 0; + + if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) { + Debug( LDAP_DEBUG_ANY, + "Message type should be entry (%d)", ldap_msgtype( msg ), 0, 0 ); + return -1; + } + + if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) + ls = &accesslog_sc; + else + ls = &changelog_sc; + + rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn ); + + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "syncrepl_message_to_op : dn get failed (%d)", rc, 0, 0 ); + return rc; + } + + op->o_tag = LBER_DEFAULT; + + while (( rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, &bvals )) + == LDAP_SUCCESS ) { + if ( bv.bv_val == NULL ) + break; + + if ( !ber_bvstrcasecmp( &bv, &ls->ls_dn )) { + bdn = bvals[0]; + dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx ); + ber_dupbv( &op->o_req_dn, &dn ); + ber_dupbv( &op->o_req_ndn, &ndn ); + slap_sl_free( ndn.bv_val, op->o_tmpmemctx ); + slap_sl_free( dn.bv_val, op->o_tmpmemctx ); + } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_req )) { + int i = verb_to_mask( bvals[0].bv_val, modops ); + if ( i < 0 ) { + Debug( LDAP_DEBUG_ANY, + "syncrepl_message_to_op : unknown op %s", + bvals[0].bv_val, 0, 0 ); + ch_free( bvals ); + goto done; + } + op->o_tag = modops[i].mask; + } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_mod )) { + /* Parse attribute into modlist */ + if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) + modlist = syncrepl_accesslog_mods( si, bvals ); + else + modlist = syncrepl_changelog_mods( si, bvals ); + } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newRdn )) { + rdn = bvals[0]; + } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_delRdn )) { + if ( !ber_bvstrcasecmp( &slap_true_bv, bvals )) + deleteOldRdn = 1; + } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newSup )) { + sup = bvals[0]; + } + ch_free( bvals ); + } + + /* If we didn't get a mod type or a target DN, bail out */ + if ( op->o_tag == LBER_DEFAULT || BER_BVISNULL( &dn )) + goto done; + + op->o_callback = &cb; + + switch( op->o_tag ) { + case LDAP_REQ_ADD: + case LDAP_REQ_MODIFY: + /* If we didn't get required data, bail */ + if ( !modlist ) goto done; + + rc = slap_mods_check( modlist, &text, txtbuf, textlen, NULL ); + + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: mods check (%s)\n", + text, 0, 0 ); + goto done; + } + + if ( op->o_tag == LDAP_REQ_ADD ) { + op->ora_e = ( Entry * ) ch_calloc( 1, sizeof( Entry ) ); + op->ora_e->e_name = op->o_req_dn; + op->ora_e->e_nname = op->o_req_ndn; + rc = slap_mods2entry( modlist, &op->ora_e, 1, 0, &text, txtbuf, textlen); + if( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: mods2entry (%s)\n", + text, 0, 0 ); + } else { + rc = op->o_bd->be_add( op, &rs ); + } + be_entry_release_w( op, op->ora_e ); + } else { + op->orm_modlist = modlist; + rc = op->o_bd->be_modify( op, &rs ); + } + break; + case LDAP_REQ_MODRDN: + if ( BER_BVISNULL( &rdn )) goto done; + + if ( rdnPretty( NULL, &rdn, &prdn, NULL )) + goto done; + if ( rdnNormalize( 0, NULL, NULL, &rdn, &nrdn, NULL )) + goto done; + if ( !BER_BVISNULL( &sup )) { + if ( dnPrettyNormal( NULL, &sup, &psup, &nsup, NULL )) + goto done; + op->orr_newSup = &psup; + op->orr_nnewSup = ⊅ + } + op->orr_newrdn = prdn; + op->orr_nnewrdn = nrdn; + op->orr_deleteoldrdn = deleteOldRdn; + rc = op->o_bd->be_modrdn( op, &rs ); + break; + } +done: + if ( modlist ) + slap_mods_free( modlist, op->o_tag != LDAP_REQ_ADD ); + if ( !BER_BVISNULL( &rdn )) { + if ( !BER_BVISNULL( &nsup )) + ch_free( nsup.bv_val ); + if ( !BER_BVISNULL( &psup )) + ch_free( psup.bv_val ); + if ( !BER_BVISNULL( &nrdn )) + ch_free( nrdn.bv_val ); + if ( !BER_BVISNULL( &prdn )) + ch_free( prdn.bv_val ); + } + ber_free ( ber, 0 ); +} + static int syncrepl_message_to_entry( syncinfo_t *si, @@ -2254,6 +2532,7 @@ syncinfo_free( syncinfo_t *sie ) #define RETRYSTR "retry" #define SLIMITSTR "sizelimit" #define TLIMITSTR "timelimit" +#define SYNCDATASTR "syncdata" /* FIXME: undocumented */ #define OLDAUTHCSTR "bindprincipal" @@ -2291,6 +2570,13 @@ static struct { { BER_BVNULL, 0 } }; +static slap_verbmasks datamodes[] = { + { BER_BVC("default"), SYNCDATA_DEFAULT }, + { BER_BVC("accesslog"), SYNCDATA_ACCESSLOG }, + { BER_BVC("changelog"), SYNCDATA_CHANGELOG }, + { BER_BVNULL, 0 } +}; + static int parse_syncrepl_line( char **cargv, @@ -2338,6 +2624,8 @@ parse_syncrepl_line( STRLENOF( FILTERSTR "=" ) ) ) { val = cargv[ i ] + STRLENOF( FILTERSTR "=" ); + if ( si->si_filterstr.bv_val ) + ch_free( si->si_filterstr.bv_val ); ber_str2bv( val, 0, 1, &si->si_filterstr ); } else if ( !strncasecmp( cargv[ i ], SEARCHBASESTR "=", STRLENOF( SEARCHBASESTR "=" ) ) ) @@ -2565,6 +2853,11 @@ parse_syncrepl_line( { val = cargv[ i ] + STRLENOF( TLIMITSTR "=" ); si->si_tlimit = atoi( val ); + } else if ( !strncasecmp( cargv[ i ], SYNCDATASTR "=", + STRLENOF( SYNCDATASTR "=" ) ) ) + { + val = cargv[ i ] + STRLENOF( SYNCDATASTR "=" ); + si->si_syncdata = verb_to_mask( val, datamodes ); } else if ( bindconf_parse( cargv[i], &si->si_bindconf )) { fprintf( stderr, "Error: parse_syncrepl_line: " "unknown keyword \"%s\"\n", cargv[ i ] ); @@ -2758,6 +3051,13 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv ) ptr = lutil_strcopy( ptr, " " TLIMITSTR "=" ); ptr += sprintf( ptr, "%d", si->si_tlimit ); } + + if ( si->si_syncdata ) { + if ( enum_to_verb( datamodes, si->si_syncdata, &bc ) >= 0 ) { + ptr = lutil_strcopy( ptr, " " SYNCDATASTR "=" ); + ptr = lutil_strcopy( ptr, bc.bv_val ); + } + } bc.bv_len = ptr - buf; bc.bv_val = buf; ber_dupbv( bv, &bc ); -- 2.39.5