From e2722b0c949f8e67a98e7b790c688682d7a34aa1 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Thu, 11 Sep 2008 00:29:56 +0000 Subject: [PATCH] ITS#5659 "collect" overlay enhancements --- configure.in | 16 ++ servers/slapd/overlays/Makefile.in | 4 + servers/slapd/overlays/collect.c | 232 ++++++++++++++++++++++++----- 3 files changed, 212 insertions(+), 40 deletions(-) diff --git a/configure.in b/configure.in index 1a715a8d6c..2ace75ce1a 100644 --- a/configure.in +++ b/configure.in @@ -333,6 +333,7 @@ dnl ---------------------------------------------------------------- dnl SLAPD Overlay Options Overlays="accesslog \ auditlog \ + collect \ constraint \ dds \ dyngroup \ @@ -358,6 +359,8 @@ OL_ARG_ENABLE(accesslog,[ --enable-accesslog In-Directory Access Logging ov no, [no yes mod], ol_enable_overlays) OL_ARG_ENABLE(auditlog,[ --enable-auditlog Audit Logging overlay], no, [no yes mod], ol_enable_overlays) +OL_ARG_ENABLE(collect,[ --enable-collect Collect overlay], + no, [no yes mod], ol_enable_overlays) OL_ARG_ENABLE(constraint,[ --enable-constraint Attribute Constraint overlay], no, [no yes mod], ol_enable_overlays) OL_ARG_ENABLE(dds,[ --enable-dds Dynamic Directory Services overlay], @@ -2758,6 +2761,18 @@ if test "$ol_enable_auditlog" != no ; then AC_DEFINE_UNQUOTED(SLAPD_OVER_AUDITLOG,$MFLAG,[define for Audit Logging overlay]) fi +if test "$ol_enable_collect" != no ; then + BUILD_COLLECT=$ol_enable_collect + if test "$ol_enable_collect" = mod ; then + MFLAG=SLAPD_MOD_DYNAMIC + SLAPD_DYNAMIC_OVERLAYS="$SLAPD_DYNAMIC_OVERLAYS collect.la" + else + MFLAG=SLAPD_MOD_STATIC + SLAPD_STATIC_OVERLAYS="$SLAPD_STATIC_OVERLAYS collect.o" + fi + AC_DEFINE_UNQUOTED(SLAPD_OVER_COLLECT,$MFLAG,[define for Collect overlay]) +fi + if test "$ol_enable_constraint" != no ; then BUILD_CONSTRAINT=$ol_enable_constraint if test "$ol_enable_constraint" = mod ; then @@ -2995,6 +3010,7 @@ dnl backends dnl overlays AC_SUBST(BUILD_ACCESSLOG) AC_SUBST(BUILD_AUDITLOG) + AC_SUBST(BUILD_COLLECT) AC_SUBST(BUILD_CONSTRAINT) AC_SUBST(BUILD_DDS) AC_SUBST(BUILD_DENYOP) diff --git a/servers/slapd/overlays/Makefile.in b/servers/slapd/overlays/Makefile.in index 63249e3846..07b4b1ebb4 100644 --- a/servers/slapd/overlays/Makefile.in +++ b/servers/slapd/overlays/Makefile.in @@ -22,6 +22,7 @@ SRCS = overlays.c \ dynlist.c \ memberof.c \ pcache.c \ + collect.c \ ppolicy.c \ refint.c \ retcode.c \ @@ -83,6 +84,9 @@ memberof.la : memberof.lo pcache.la : pcache.lo $(LTLINK_MOD) -module -o $@ pcache.lo version.lo $(LINK_LIBS) +collect.la : collect.lo + $(LTLINK_MOD) -module -o $@ collect.lo version.lo $(LINK_LIBS) + ppolicy.la : ppolicy.lo $(LTLINK_MOD) -module -o $@ ppolicy.lo version.lo $(LINK_LIBS) $(MODULES_LIBS) diff --git a/servers/slapd/overlays/collect.c b/servers/slapd/overlays/collect.c index fb8ef94f8e..00834d3c06 100644 --- a/servers/slapd/overlays/collect.c +++ b/servers/slapd/overlays/collect.c @@ -43,14 +43,58 @@ typedef struct collect_info { struct collect_info *ci_next; struct berval ci_dn; - AttributeDescription *ci_ad; + int ci_ad_num; + AttributeDescription *ci_ad[]; } collect_info; +/* + * inserts a collect_info into on->on_bi.bi_private taking into account + * order. this means longer dn's (i.e. more specific dn's) will be found + * first when searching, allowing some limited overlap of dn's + */ +static void +insert_ordered( slap_overinst *on, collect_info *ci ) { + collect_info *find = on->on_bi.bi_private; + collect_info *prev = NULL; + int found = 0; + + while (!found) { + if (find == NULL) { + if (prev == NULL) { + /* base case - empty list */ + on->on_bi.bi_private = ci; + ci->ci_next = NULL; + } else { + /* final case - end of list */ + prev->ci_next = ci; + ci->ci_next = NULL; + } + found = 1; + } else if (find->ci_dn.bv_len <= ci->ci_dn.bv_len) { + /* insert into list here */ + if (prev == NULL) { + /* entry is head of list */ + ci->ci_next = on->on_bi.bi_private; + on->on_bi.bi_private = ci; + } else { + /* entry is not head of list */ + prev->ci_next = ci; + ci->ci_next = find; + } + found = 1; + } else { + /* keep looking */ + prev = find; + find = find->ci_next; + } + } +} + static int collect_cf( ConfigArgs *c ) { slap_overinst *on = (slap_overinst *)c->bi; - int rc = 1; + int rc = 1, idx; switch( c->op ) { case SLAP_CONFIG_EMIT: @@ -58,14 +102,34 @@ collect_cf( ConfigArgs *c ) collect_info *ci; for ( ci = on->on_bi.bi_private; ci; ci = ci->ci_next ) { struct berval bv; + char *ptr; int len; - bv.bv_len = ci->ci_dn.bv_len + STRLENOF("\"\" ") + - ci->ci_ad->ad_cname.bv_len; + /* calculate the length & malloc memory */ + bv.bv_len = ci->ci_dn.bv_len + STRLENOF("\"\" "); + for (idx=0; idxci_ad_num; idx++) { + bv.bv_len += ci->ci_ad[idx]->ad_cname.bv_len; + if (idx<(ci->ci_ad_num-1)) { + bv.bv_len++; + } + } bv.bv_val = ch_malloc( bv.bv_len + 1 ); - len = snprintf( bv.bv_val, bv.bv_len + 1, "\"%s\" %s", - ci->ci_dn.bv_val, ci->ci_ad->ad_cname.bv_val ); - assert( len == bv.bv_len ); + + /* copy the value and update len */ + len = snprintf( bv.bv_val, bv.bv_len + 1, "\"%s\" ", + ci->ci_dn.bv_val); + ptr = bv.bv_val + len; + for (idx=0; idxci_ad_num; idx++) { + ptr = lutil_strncopy( ptr, + ci->ci_ad[idx]->ad_cname.bv_val, + ci->ci_ad[idx]->ad_cname.bv_len); + if (idx<(ci->ci_ad_num-1)) { + *ptr++ = ','; + } + } + *ptr = '\0'; + bv.bv_len = ptr - bv.bv_val; + ber_bvarray_add( &c->rvalue_vals, &bv ); rc = 0; } @@ -98,8 +162,21 @@ collect_cf( ConfigArgs *c ) collect_info *ci; struct berval bv, dn; const char *text; - AttributeDescription *ad = NULL; + int idx, count=0; + char *arg; + /* count delimiters in attribute argument */ + arg = strtok(c->argv[2], ","); + while (arg!=NULL) { + count++; + arg = strtok(NULL, ","); + } + + /* allocate config info with room for attribute array */ + ci = ch_malloc( sizeof( collect_info ) + + ( sizeof (AttributeDescription *) * (count + 1))); + + /* validate and normalize dn */ ber_str2bv( c->argv[1], 0, 0, &bv ); if ( dnNormalize( 0, NULL, NULL, &bv, &dn, NULL ) ) { snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s invalid DN: \"%s\"", @@ -108,22 +185,38 @@ collect_cf( ConfigArgs *c ) "%s: %s\n", c->log, c->cr_msg, 0 ); return ARG_BAD_CONF; } - if ( slap_str2ad( c->argv[2], &ad, &text ) ) { - snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s attribute description unknown: \"%s\"", - c->argv[0], c->argv[2] ); - Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, - "%s: %s\n", c->log, c->cr_msg, 0 ); - return ARG_BAD_CONF; + + /* load attribute description for attribute list */ + arg = c->argv[2]; + for( idx=0; idxci_ad[idx] = NULL; + + if ( slap_str2ad( arg, &ci->ci_ad[idx], &text ) ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "%s attribute description unknown: \"%s\"", + c->argv[0], arg); + Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, + "%s: %s\n", c->log, c->cr_msg, 0 ); + return ARG_BAD_CONF; + } + while(*arg!='\0') { + arg++; /* skip to end of argument */ + } + if (idxon_bi.bi_private pointer can be used for * anything this instance of the overlay needs. */ - ci = ch_malloc( sizeof( collect_info )); - ci->ci_ad = ad; + ci->ci_ad[count] = NULL; + ci->ci_ad_num = count; ci->ci_dn = dn; - ci->ci_next = on->on_bi.bi_private; - on->on_bi.bi_private = ci; + + /* creates list of ci's ordered by dn length */ + insert_ordered ( on, ci ); + rc = 0; } } @@ -166,6 +259,48 @@ collect_destroy( return 0; } +static int +collect_modify( Operation *op, SlapReply *rs) +{ + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + collect_info *ci = on->on_bi.bi_private; + Modifications *ml; + char errMsg[100]; + int rc, idx; + + for ( ml = op->orm_modlist; ml != NULL; ml = ml->sml_next) { + for (; ci; ci=ci->ci_next ) { + /* Is this entry an ancestor of this collectinfo ? */ + if (!dnIsSuffix(&op->o_req_ndn, &ci->ci_dn)) { + /* this collectinfo does not match */ + continue; + } + + /* Is this entry the same as the template DN ? */ + if ( dn_match(&op->o_req_ndn, &ci->ci_dn)) { + /* all changes in this ci are allowed */ + continue; + } + + /* check for collect attributes - disallow modify if present */ + for(idx=0; idxci_ad_num; idx++) { + if (ml->sml_desc == ci->ci_ad[idx]) { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + snprintf( errMsg, sizeof( errMsg ), + "cannot change virtual attribute '%s'", + ci->ci_ad[idx]->ad_cname.bv_val); + rs->sr_text = errMsg; + send_ldap_result( op, rs ); + return rs->sr_err; + } + } + } + + } + + return SLAP_CB_CONTINUE; +} + static int collect_response( Operation *op, SlapReply *rs ) { @@ -181,35 +316,51 @@ collect_response( Operation *op, SlapReply *rs ) op->o_bd->bd_info = (BackendInfo *)on->on_info; for (; ci; ci=ci->ci_next ) { - BerVarray vals = NULL; + int idx=0; + + /* Is this entry an ancestor of this collectinfo ? */ + if (!dnIsSuffix(&rs->sr_entry->e_nname, &ci->ci_dn)) { + /* collectinfo does not match */ + continue; + } - /* Is our configured entry an ancestor of this one? */ - if ( !dnIsSuffix( &rs->sr_entry->e_nname, &ci->ci_dn )) + /* Is this entry the same as the template DN ? */ + if ( dn_match(&rs->sr_entry->e_nname, &ci->ci_dn)) { + /* dont apply change to parent */ continue; + } + + /* The current entry may live in a cache, so + * don't modify it directly. Make a copy and + * work with that instead. + */ + if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE )) { + rs->sr_entry = entry_dup( rs->sr_entry ); + rs->sr_flags |= REP_ENTRY_MODIFIABLE | + REP_ENTRY_MUSTBEFREED; + } - /* Extract the values of the desired attribute from - * the ancestor entry - */ - rc = backend_attribute( op, NULL, &ci->ci_dn, ci->ci_ad, &vals, ACL_READ ); - - /* If there are any values, merge them into the - * current entry - */ - if ( vals ) { - /* The current entry may live in a cache, so - * don't modify it directly. Make a copy and - * work with that instead. - */ - if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE )) { - rs->sr_entry = entry_dup( rs->sr_entry ); - rs->sr_flags |= REP_ENTRY_MODIFIABLE | - REP_ENTRY_MUSTBEFREED; + /* Loop for each attribute in this collectinfo */ + for(idx=0; idxci_ad_num; idx++) { + BerVarray vals = NULL; + + /* Extract the values of the desired attribute from + * the ancestor entry */ + rc = backend_attribute( op, NULL, &ci->ci_dn, + ci->ci_ad[idx], &vals, ACL_READ ); + + /* If there are any values, merge them into the + * current search result + */ + if ( vals ) { + attr_merge( rs->sr_entry, ci->ci_ad[idx], + vals, NULL ); + ber_bvarray_free_x( vals, op->o_tmpmemctx ); } - attr_merge( rs->sr_entry, ci->ci_ad, vals, NULL ); - ber_bvarray_free_x( vals, op->o_tmpmemctx ); } } } + /* Default is to just fall through to the normal processing */ return SLAP_CB_CONTINUE; } @@ -221,6 +372,7 @@ int collect_initialize() { collect.on_bi.bi_type = "collect"; collect.on_bi.bi_db_destroy = collect_destroy; + collect.on_bi.bi_op_modify = collect_modify; collect.on_response = collect_response; collect.on_bi.bi_cf_ocs = collectocs; -- 2.39.5