mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-04-12 15:10:31 +08:00
ITS#10167 slapo-memberof: add addcheck option
Check memberships of newly added entries.
This commit is contained in:
parent
fe7ee15016
commit
e992b8972d
@ -107,6 +107,23 @@ If set to
|
||||
when an entry containing values of the "is member of" attribute is modified,
|
||||
the corresponding groups are modified as well.
|
||||
|
||||
.TP
|
||||
.BI "memberof\-addcheck {" true "|" FALSE "}"
|
||||
This option determines whether the overlay will check newly added
|
||||
entries for membership in any existing groups. This check is useful
|
||||
if populated groups are created in the directory before the entries
|
||||
they reference. The situation often occurs during replication, which
|
||||
may replicate entries in random order.
|
||||
If set to
|
||||
.IR TRUE ,
|
||||
every Add operation will search for groups referencing the added
|
||||
entry and populate its memberof attribute with the group DNs. Note
|
||||
that
|
||||
.BR memberof\-dangling
|
||||
must be left on its default setting of
|
||||
.I ignore
|
||||
for this option to work.
|
||||
|
||||
.LP
|
||||
The memberof overlay may be used with any backend that provides full
|
||||
read-write functionality, but it is mainly intended for use
|
||||
@ -114,10 +131,7 @@ with local storage backends. The maintenance operations it performs
|
||||
are internal to the server on which the overlay is configured and
|
||||
are never replicated. Consumer servers should be configured with their
|
||||
own instances of the memberOf overlay if it is desired to maintain
|
||||
these memberOf attributes on the consumers. Note that slapo-memberOf
|
||||
is not compatible with syncrepl based replication, and should not be
|
||||
used in a replicated environment. An alternative is to use slapo-dynlist
|
||||
to emulate slapo-memberOf behavior.
|
||||
these memberOf attributes on the consumers.
|
||||
|
||||
.SH FILES
|
||||
.TP
|
||||
|
@ -159,6 +159,7 @@ typedef struct memberof_t {
|
||||
#define MEMBEROF_FDANGLING_MASK (MEMBEROF_FDANGLING_DROP|MEMBEROF_FDANGLING_ERROR)
|
||||
#define MEMBEROF_FREFINT 0x04U
|
||||
#define MEMBEROF_FREVERSE 0x08U
|
||||
#define MEMBEROF_FADDCHECK 0x10U
|
||||
|
||||
ber_int_t mo_dangling_err;
|
||||
|
||||
@ -174,6 +175,8 @@ typedef struct memberof_t {
|
||||
MEMBEROF_CHK((mo),MEMBEROF_FREFINT)
|
||||
#define MEMBEROF_REVERSE(mo) \
|
||||
MEMBEROF_CHK((mo),MEMBEROF_FREVERSE)
|
||||
#define MEMBEROF_ADDCHECK(mo) \
|
||||
MEMBEROF_CHK((mo),MEMBEROF_FADDCHECK)
|
||||
} memberof_t;
|
||||
|
||||
typedef enum memberof_is_t {
|
||||
@ -521,6 +524,87 @@ static int memberof_res_delete( Operation *op, SlapReply *rs );
|
||||
static int memberof_res_modify( Operation *op, SlapReply *rs );
|
||||
static int memberof_res_modrdn( Operation *op, SlapReply *rs );
|
||||
|
||||
typedef struct mo_addcheck_t {
|
||||
memberof_t *ma_mo;
|
||||
Entry *ma_e;
|
||||
Attribute *ma_a;
|
||||
} mo_addcheck_t;
|
||||
|
||||
static int memberof_res_addcheck( Operation *op, SlapReply *rs )
|
||||
{
|
||||
mo_addcheck_t *ma = op->o_callback->sc_private;
|
||||
if ( rs->sr_type == REP_SEARCH ) {
|
||||
if ( !ma->ma_a ) {
|
||||
attr_merge_one( ma->ma_e, ma->ma_mo->mo_ad_memberof,
|
||||
&rs->sr_entry->e_name, &rs->sr_entry->e_nname );
|
||||
ma->ma_a = attr_find( ma->ma_e->e_attrs, ma->ma_mo->mo_ad_memberof );
|
||||
} else {
|
||||
if ( attr_valfind( ma->ma_a, SLAP_MR_EQUALITY | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
|
||||
SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, &rs->sr_entry->e_nname, NULL, NULL )) {
|
||||
attr_valadd( ma->ma_a, &rs->sr_entry->e_name, &rs->sr_entry->e_nname, 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if an entry being added is already a member of existing groups;
|
||||
* add those groups to the entry's memberof if any.
|
||||
*/
|
||||
static void
|
||||
memberof_addcheck( Operation *op )
|
||||
{
|
||||
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
||||
memberof_t *mo = (memberof_t *)on->on_bi.bi_private;
|
||||
Operation o = *op;
|
||||
Filter mf;
|
||||
AttributeAssertion mava;
|
||||
slap_callback sc = {0};
|
||||
mo_addcheck_t ma;
|
||||
SlapReply rs = {REP_SEARCH};
|
||||
|
||||
o.o_dn = op->o_bd->be_rootdn;
|
||||
o.o_ndn = op->o_bd->be_rootndn;
|
||||
o.o_bd->bd_info = (BackendInfo *)on->on_info;
|
||||
o.o_tag = LDAP_REQ_SEARCH;
|
||||
o.o_req_dn = op->o_bd->be_suffix[0];
|
||||
o.o_req_ndn = op->o_bd->be_nsuffix[0];
|
||||
o.o_do_not_cache = 1;
|
||||
o.ors_scope = LDAP_SCOPE_SUBTREE;
|
||||
o.ors_slimit = SLAP_NO_LIMIT;
|
||||
o.ors_tlimit = SLAP_NO_LIMIT;
|
||||
o.ors_limit = NULL;
|
||||
o.ors_attrsonly = 1;
|
||||
o.ors_attrs = slap_anlist_no_attrs;
|
||||
mf.f_choice = LDAP_FILTER_EQUALITY;
|
||||
mf.f_ava = &mava;
|
||||
mf.f_next = NULL;
|
||||
mf.f_av_desc = mo->mo_ad_member;
|
||||
mf.f_av_value = op->o_req_ndn;
|
||||
o.ors_filter = &mf;
|
||||
o.ors_filterstr.bv_val = op->o_tmpalloc( mo->mo_ad_member->ad_cname.bv_len + 2
|
||||
+ op->o_req_ndn.bv_len + 2, op->o_tmpmemctx );
|
||||
{
|
||||
char *ptr = o.ors_filterstr.bv_val;
|
||||
*ptr++ = '(';
|
||||
ptr = lutil_strcopy( ptr, mo->mo_ad_member->ad_cname.bv_val );
|
||||
*ptr++ = '=';
|
||||
ptr = lutil_strcopy( ptr, op->o_req_ndn.bv_val );
|
||||
*ptr++ = ')';
|
||||
*ptr = '\0';
|
||||
}
|
||||
sc.sc_private = &ma;
|
||||
sc.sc_response = memberof_res_addcheck;
|
||||
ma.ma_mo = mo;
|
||||
ma.ma_e = op->ora_e;
|
||||
ma.ma_a = attr_find( op->ora_e->e_attrs, mo->mo_ad_memberof );
|
||||
o.o_callback = ≻
|
||||
|
||||
o.o_bd->be_search( &o, &rs );
|
||||
o.o_bd->bd_info = (BackendInfo *)on;
|
||||
op->o_tmpfree( o.ors_filterstr.bv_val, op->o_tmpmemctx );
|
||||
}
|
||||
|
||||
static int
|
||||
memberof_op_add( Operation *op, SlapReply *rs )
|
||||
{
|
||||
@ -549,6 +633,10 @@ memberof_op_add( Operation *op, SlapReply *rs )
|
||||
return SLAP_CB_CONTINUE;
|
||||
}
|
||||
|
||||
if ( MEMBEROF_ADDCHECK( mo )) {
|
||||
memberof_addcheck( op );
|
||||
}
|
||||
|
||||
if ( MEMBEROF_REVERSE( mo ) ) {
|
||||
for ( ap = &op->ora_e->e_attrs; *ap; ap = &(*ap)->a_next ) {
|
||||
Attribute *a = *ap;
|
||||
@ -1649,6 +1737,7 @@ enum {
|
||||
#endif
|
||||
|
||||
MO_DANGLING_ERROR,
|
||||
MO_ADDCHECK,
|
||||
|
||||
MO_LAST
|
||||
};
|
||||
@ -1730,6 +1819,14 @@ static ConfigTable mo_cfg[] = {
|
||||
"SYNTAX OMsDirectoryString SINGLE-VALUE )",
|
||||
NULL, NULL },
|
||||
|
||||
{ "memberof-addcheck", "true|FALSE",
|
||||
2, 2, 0, ARG_MAGIC|ARG_ON_OFF|MO_ADDCHECK, mo_cf_gen,
|
||||
"( OLcfgOvAt:18.8 NAME 'olcMemberOfAddCheck' "
|
||||
"DESC 'Check for memberships on added entries' "
|
||||
"EQUALITY booleanMatch "
|
||||
"SYNTAX OMsBoolean SINGLE-VALUE )",
|
||||
NULL, NULL },
|
||||
|
||||
{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
|
||||
};
|
||||
|
||||
@ -1749,6 +1846,7 @@ static ConfigOCs mo_ocs[] = {
|
||||
#if 0
|
||||
"$ olcMemberOfReverse "
|
||||
#endif
|
||||
"$ olcMemberOfAddCheck "
|
||||
") "
|
||||
")",
|
||||
Cft_Overlay, mo_cfg, NULL, NULL },
|
||||
@ -1887,6 +1985,10 @@ mo_cf_gen( ConfigArgs *c )
|
||||
c->value_ad = mo->mo_ad_memberof;
|
||||
break;
|
||||
|
||||
case MO_ADDCHECK:
|
||||
c->value_int = MEMBEROF_ADDCHECK( mo );
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( 0 );
|
||||
return 1;
|
||||
@ -1937,6 +2039,10 @@ mo_cf_gen( ConfigArgs *c )
|
||||
memberof_make_member_filter( mo );
|
||||
break;
|
||||
|
||||
case MO_ADDCHECK:
|
||||
mo->mo_flags &= ~MEMBEROF_FADDCHECK;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( 0 );
|
||||
return 1;
|
||||
@ -2046,6 +2152,15 @@ mo_cf_gen( ConfigArgs *c )
|
||||
memberof_make_member_filter( mo );
|
||||
} break;
|
||||
|
||||
case MO_ADDCHECK:
|
||||
if ( c->value_int ) {
|
||||
mo->mo_flags |= MEMBEROF_FADDCHECK;
|
||||
|
||||
} else {
|
||||
mo->mo_flags &= ~MEMBEROF_FADDCHECK;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( 0 );
|
||||
return 1;
|
||||
|
@ -339,3 +339,67 @@ sn: person2
|
||||
memberOfB: cn=group2,ou=Groups,dc=example,dc=com
|
||||
memberOfC: cn=group1,ou=Groups,dc=example,dc=com
|
||||
|
||||
# Re-search the entire database after adding out-of-order groups/users...
|
||||
dn: dc=example,dc=com
|
||||
objectClass: organization
|
||||
objectClass: dcObject
|
||||
o: Example, Inc.
|
||||
dc: example
|
||||
|
||||
dn: cn=group1,ou=Groups,dc=example,dc=com
|
||||
objectClass: groupA
|
||||
cn: group1
|
||||
memberA: cn=person1,ou=People,dc=example,dc=com
|
||||
memberA: cn=person2,ou=People,dc=example,dc=com
|
||||
|
||||
dn: cn=group2,ou=Groups,dc=example,dc=com
|
||||
objectClass: groupB
|
||||
cn: group2
|
||||
memberB: cn=person1,ou=People,dc=example,dc=com
|
||||
memberB: cn=person2,ou=People,dc=example,dc=com
|
||||
|
||||
dn: cn=group3,ou=Groups,dc=example,dc=com
|
||||
objectClass: groupOfNames
|
||||
cn: group3
|
||||
member: cn=New Person,ou=People,dc=example,dc=com
|
||||
member: cn=New Group,ou=Groups,dc=example,dc=com
|
||||
|
||||
dn: ou=Groups,dc=example,dc=com
|
||||
objectClass: organizationalUnit
|
||||
ou: Groups
|
||||
|
||||
dn: cn=New Group,ou=Groups,dc=example,dc=com
|
||||
objectClass: groupOfNames
|
||||
cn: New Group
|
||||
member: cn=New Person,ou=People,dc=example,dc=com
|
||||
memberOf: cn=group3,ou=Groups,dc=example,dc=com
|
||||
|
||||
dn: cn=New Person,ou=People,dc=example,dc=com
|
||||
objectClass: person
|
||||
cn: New Person
|
||||
sn: Person
|
||||
memberOf: cn=group3,ou=Groups,dc=example,dc=com
|
||||
memberOf: cn=New Group,ou=Groups,dc=example,dc=com
|
||||
|
||||
dn: ou=People,dc=example,dc=com
|
||||
objectClass: organizationalUnit
|
||||
ou: People
|
||||
|
||||
dn: cn=person1,ou=People,dc=example,dc=com
|
||||
objectClass: person
|
||||
objectClass: groupMemberA
|
||||
objectClass: groupMemberB
|
||||
cn: person1
|
||||
sn: person1
|
||||
memberOfB: cn=group2,ou=Groups,dc=example,dc=com
|
||||
memberOfC: cn=group1,ou=Groups,dc=example,dc=com
|
||||
|
||||
dn: cn=person2,ou=People,dc=example,dc=com
|
||||
objectClass: person
|
||||
objectClass: groupMemberA
|
||||
objectClass: groupMemberB
|
||||
cn: person2
|
||||
sn: person2
|
||||
memberOfB: cn=group2,ou=Groups,dc=example,dc=com
|
||||
memberOfC: cn=group1,ou=Groups,dc=example,dc=com
|
||||
|
||||
|
@ -441,6 +441,61 @@ if test $RC != 0 ; then
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
echo "Running ldapmodify to enable add checking..."
|
||||
$LDAPMODIFY -H $URI1 -D 'cn=config' -w `cat $CONFIGPWF` \
|
||||
>> $TESTOUT 2>&1 <<EOF
|
||||
dn: olcOverlay={0}memberof,olcDatabase={1}$BACKEND,cn=config
|
||||
changetype: modify
|
||||
replace: olcMemberOfAddCheck
|
||||
olcMemberOfAddCheck: TRUE
|
||||
|
||||
EOF
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapmodify failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
echo "Adding group and users out of order..."
|
||||
$LDAPADD -H $URI1 \
|
||||
-D "cn=Manager,$BASEDN" -w secret \
|
||||
>> $TESTOUT 2>&1 <<EOF
|
||||
dn: cn=group3,ou=Groups,$BASEDN
|
||||
objectclass: groupOfNames
|
||||
cn: group3
|
||||
member: cn=New Person,ou=People,$BASEDN
|
||||
member: cn=New Group,ou=Groups,$BASEDN
|
||||
|
||||
dn: cn=New Group,ou=Groups,$BASEDN
|
||||
objectclass: groupOfNames
|
||||
cn: New Group
|
||||
member: cn=New Person,ou=People,$BASEDN
|
||||
|
||||
dn: cn=New Person,ou=People,$BASEDN
|
||||
objectclass: person
|
||||
cn: New Person
|
||||
sn: Person
|
||||
|
||||
EOF
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapadd failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
echo "Re-search the entire database..."
|
||||
echo "# Re-search the entire database after adding out-of-order groups/users..." >> $SEARCHOUT
|
||||
$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \
|
||||
'(objectClass=*)' '*' memberOf >> $SEARCHOUT 2>&1
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapsearch failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
test $KILLSERVERS != no && kill -HUP $KILLPIDS
|
||||
|
||||
LDIF=$MEMBEROFOUT
|
||||
|
Loading…
x
Reference in New Issue
Block a user