configuration options are defined for the memberofoverlay.
.TP
-.B memberof-group-oc <group-oc>
+.BI memberof-group-oc \ <group-oc>
The value
-.B <group-oc>
+.I <group-oc>
is the name of the objectClass that triggers the reverse group membership
update.
It defaults to \fIgroupOfNames\fP.
.TP
-.B memberof-member-ad <member-ad>
+.BI memberof-member-ad \ <member-ad>
The value
-.B <member-ad>
+.I <member-ad>
is the name of the attribute that contains the names of the members
in the group objects; it must be DN-valued.
It defaults to \fImember\fP.
.TP
-.B memberof-memberof-ad <memberof-ad>
+.BI memberof-memberof-ad \ <memberof-ad>
The value
-.B <memberof-ad>
+.I <memberof-ad>
is the name of the attribute that contains the names of the groups
an entry is member of; it must be DN-valued. Its contents are
automatically updated by the overlay.
It defaults to \fImemberOf\fP.
.TP
-.B memberof-dn <dn>
+.BI memberof-dn \ <dn>
The value
-.B <dn>
+.I <dn>
contains the DN that is used as \fImodifiersName\fP for internal
modifications performed to update the reverse group membership.
It defaults to the \fIrootdn\fP of the underlying database.
.TP
-.B memberof-dangling {ignore, drop, error}
+.BI "memberof-dangling {" ignore ", " drop ", " error "}"
This option determines the behavior of the overlay when, during
a modification, it encounters dangling references.
The default is
-.BR ignore ,
+.IR ignore ,
which may leave dangling references.
Other options are
-.BR drop ,
+.IR drop ,
which discards those modifications that would result in dangling
references, and
-.BR error ,
+.IR error ,
which causes modifications that would result in dangling references
to fail.
.TP
-.B memberof-refint {true|FALSE}
+.BI memberof-dangling-error \ <error-code>
+If
+.BR memberof-dangling
+is set to
+.IR error ,
+this configuration parameter can be used to modify the response code
+returned in case of violation. It defaults to "constraint violation",
+but other implementations are known to return "no such object" instead.
+
+.TP
+.BI "memberof-refint {" true "|" FALSE "}"
This option determines whether the overlay will try to preserve
referential integrity or not.
If set to
-.BR TRUE ,
+.IR TRUE ,
when an entry containing values of the "is member of" attribute is modified,
the corresponding groups are modified as well.
return -1;
}
+static slap_verbmasks slap_ldap_response_code_[] = {
+ { BER_BVC("success"), LDAP_SUCCESS },
+
+ { BER_BVC("operationsError"), LDAP_OPERATIONS_ERROR },
+ { BER_BVC("protocolError"), LDAP_PROTOCOL_ERROR },
+ { BER_BVC("timelimitExceeded"), LDAP_TIMELIMIT_EXCEEDED },
+ { BER_BVC("sizelimitExceeded"), LDAP_SIZELIMIT_EXCEEDED },
+ { BER_BVC("compareFalse"), LDAP_COMPARE_FALSE },
+ { BER_BVC("compareTrue"), LDAP_COMPARE_TRUE },
+
+ { BER_BVC("authMethodNotSupported"), LDAP_AUTH_METHOD_NOT_SUPPORTED },
+ { BER_BVC("strongAuthNotSupported"), LDAP_STRONG_AUTH_NOT_SUPPORTED },
+ { BER_BVC("strongAuthRequired"), LDAP_STRONG_AUTH_REQUIRED },
+ { BER_BVC("strongerAuthRequired"), LDAP_STRONGER_AUTH_REQUIRED },
+#if 0 /* not LDAPv3 */
+ { BER_BVC("partialResults"), LDAP_PARTIAL_RESULTS },
+#endif
+
+ { BER_BVC("referral"), LDAP_REFERRAL },
+ { BER_BVC("adminlimitExceeded"), LDAP_ADMINLIMIT_EXCEEDED },
+ { BER_BVC("unavailableCriticalExtension"), LDAP_UNAVAILABLE_CRITICAL_EXTENSION },
+ { BER_BVC("confidentialityRequired"), LDAP_CONFIDENTIALITY_REQUIRED },
+ { BER_BVC("saslBindInProgress"), LDAP_SASL_BIND_IN_PROGRESS },
+
+ { BER_BVC("noSuchAttribute"), LDAP_NO_SUCH_ATTRIBUTE },
+ { BER_BVC("undefinedType"), LDAP_UNDEFINED_TYPE },
+ { BER_BVC("inappropriateMatching"), LDAP_INAPPROPRIATE_MATCHING },
+ { BER_BVC("constraintViolation"), LDAP_CONSTRAINT_VIOLATION },
+ { BER_BVC("typeOrValueExists"), LDAP_TYPE_OR_VALUE_EXISTS },
+ { BER_BVC("invalidSyntax"), LDAP_INVALID_SYNTAX },
+
+ { BER_BVC("noSuchObject"), LDAP_NO_SUCH_OBJECT },
+ { BER_BVC("aliasProblem"), LDAP_ALIAS_PROBLEM },
+ { BER_BVC("invalidDnSyntax"), LDAP_INVALID_DN_SYNTAX },
+#if 0 /* not LDAPv3 */
+ { BER_BVC("isLeaf"), LDAP_IS_LEAF },
+#endif
+ { BER_BVC("aliasDerefProblem"), LDAP_ALIAS_DEREF_PROBLEM },
+
+ { BER_BVC("proxyAuthzFailure"), LDAP_X_PROXY_AUTHZ_FAILURE },
+ { BER_BVC("inappropriateAuth"), LDAP_INAPPROPRIATE_AUTH },
+ { BER_BVC("invalidCredentials"), LDAP_INVALID_CREDENTIALS },
+ { BER_BVC("insufficientAccess"), LDAP_INSUFFICIENT_ACCESS },
+
+ { BER_BVC("busy"), LDAP_BUSY },
+ { BER_BVC("unavailable"), LDAP_UNAVAILABLE },
+ { BER_BVC("unwillingToPerform"), LDAP_UNWILLING_TO_PERFORM },
+ { BER_BVC("loopDetect"), LDAP_LOOP_DETECT },
+
+ { BER_BVC("namingViolation"), LDAP_NAMING_VIOLATION },
+ { BER_BVC("objectClassViolation"), LDAP_OBJECT_CLASS_VIOLATION },
+ { BER_BVC("notAllowedOnNonleaf"), LDAP_NOT_ALLOWED_ON_NONLEAF },
+ { BER_BVC("notAllowedOnRdn"), LDAP_NOT_ALLOWED_ON_RDN },
+ { BER_BVC("alreadyExists"), LDAP_ALREADY_EXISTS },
+ { BER_BVC("noObjectClassMods"), LDAP_NO_OBJECT_CLASS_MODS },
+ { BER_BVC("resultsTooLarge"), LDAP_RESULTS_TOO_LARGE },
+ { BER_BVC("affectsMultipleDsas"), LDAP_AFFECTS_MULTIPLE_DSAS },
+
+ { BER_BVC("other"), LDAP_OTHER },
+
+ /* extension-specific */
+
+ { BER_BVC("cupResourcesExhausted"), LDAP_CUP_RESOURCES_EXHAUSTED },
+ { BER_BVC("cupSecurityViolation"), LDAP_CUP_SECURITY_VIOLATION },
+ { BER_BVC("cupInvalidData"), LDAP_CUP_INVALID_DATA },
+ { BER_BVC("cupUnsupportedScheme"), LDAP_CUP_UNSUPPORTED_SCHEME },
+ { BER_BVC("cupReloadRequired"), LDAP_CUP_RELOAD_REQUIRED },
+
+ { BER_BVC("cancelled"), LDAP_CANCELLED },
+ { BER_BVC("noSuchOperation"), LDAP_NO_SUCH_OPERATION },
+ { BER_BVC("tooLate"), LDAP_TOO_LATE },
+ { BER_BVC("cannotCancel"), LDAP_CANNOT_CANCEL },
+
+ { BER_BVC("assertionFailed"), LDAP_ASSERTION_FAILED },
+
+ { BER_BVC("proxiedAuthorizationDenied"), LDAP_PROXIED_AUTHORIZATION_DENIED },
+
+ { BER_BVC("syncRefreshRequired"), LDAP_SYNC_REFRESH_REQUIRED },
+
+ { BER_BVC("noOperation"), LDAP_X_NO_OPERATION },
+
+ { BER_BVNULL, 0 }
+};
+
+slap_verbmasks *slap_ldap_response_code = slap_ldap_response_code_;
+
#ifdef HAVE_TLS
static slap_verbmasks tlskey[] = {
{ BER_BVC("no"), SB_TLS_OFF },
#define SLAP_X_ORDERED_FMT "{%d}"
+extern slap_verbmasks *slap_ldap_response_code;
+
#endif /* CONFIG_H */
#define MEMBEROF_FREFINT 0x04U
#define MEMBEROF_FREVERSE 0x08U
+ ber_int_t mo_dangling_err;
+
#define MEMBEROF_CHK(mo,f) \
(((mo)->mo_flags & (f)) == (f))
#define MEMBEROF_DANGLING_CHECK(mo) \
}
if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
- rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+ rc = rs->sr_err = mo->mo_dangling_err;
rs->sr_text = "adding non-existing object "
"as group member";
send_ldap_result( op, rs );
}
if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
- rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+ rc = rs->sr_err = mo->mo_dangling_err;
rs->sr_text = "adding non-existing object "
"as memberof";
send_ldap_result( op, rs );
}
if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
- rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+ rc = rs->sr_err = mo->mo_dangling_err;
rs->sr_text = "adding non-existing object "
"as group member";
send_ldap_result( op, rs );
}
if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
- rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+ rc = rs->sr_err = mo->mo_dangling_err;
rs->sr_text = "deleting non-existing object "
"as memberof";
send_ldap_result( op, rs );
op->o_bd->bd_info = (BackendInfo *)on;
if ( rc != LDAP_SUCCESS ) {
if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
- rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+ rc = rs->sr_err = mo->mo_dangling_err;
rs->sr_text = "adding non-existing object "
"as memberof";
send_ldap_result( op, rs );
memberof_t tmp_mo = { 0 }, *mo;
mo = (memberof_t *)ch_calloc( 1, sizeof( memberof_t ) );
+
+ /* safe default */
+ mo->mo_dangling_err = LDAP_CONSTRAINT_VIOLATION;
+
on->on_bi.bi_private = (void *)mo;
return 0;
MO_DN = 1,
MO_DANGLING,
MO_REFINT,
+ MO_GROUP_OC,
+ MO_MEMBER_AD,
+ MO_MEMBER_OF_AD,
#if 0
MO_REVERSE,
#endif
- MO_GROUP_OC,
- MO_MEMBER_AD,
- MO_MEMBER_OF_AD
+
+ MO_DANGLING_ERROR,
+
+ MO_LAST
};
static ConfigDriver mo_cf_gen;
NULL, NULL },
#endif
+ { "memberof-dangling-error", "error code",
+ 2, 2, 0, ARG_MAGIC|MO_DANGLING_ERROR, mo_cf_gen,
+ "( OLcfgOvAt:18.7 NAME 'olcMemberOfDanglingError' "
+ "DESC 'Error code returned in case of dangling back reference' "
+ "SYNTAX OMsDirectoryString SINGLE-VALUE )",
+ NULL, NULL },
+
{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
};
"MAY ( "
"olcMemberOfDN "
"$ olcMemberOfDangling "
+ "$ olcMemberOfDanglingError"
"$ olcMemberOfRefInt "
"$ olcMemberOfGroupOC "
"$ olcMemberOfMemberAD "
}
break;
+ case MO_DANGLING_ERROR:
+ if ( mo->mo_flags & MEMBEROF_FDANGLING_ERROR ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+ enum_to_verb( slap_ldap_response_code, mo->mo_dangling_err, &bv );
+ if ( BER_BVISNULL( &bv ) ) {
+ bv.bv_len = snprintf( buf, sizeof( buf ), "0x%x", mo->mo_dangling_err );
+ if ( bv.bv_len < sizeof( buf ) ) {
+ bv.bv_val = buf;
+ } else {
+ rc = 1;
+ break;
+ }
+ }
+ value_add_one( &c->rvalue_vals, &bv );
+ } else {
+ rc = 1;
+ }
+ break;
+
case MO_REFINT:
c->value_int = MEMBEROF_REFINT( mo );
break;
mo->mo_flags |= dangling_mode[ i ].mask;
break;
+ case MO_DANGLING_ERROR:
+ i = verb_to_mask( c->argv[ 1 ], slap_ldap_response_code );
+ if ( !BER_BVISNULL( &slap_ldap_response_code[ i ].word ) ) {
+ mo->mo_dangling_err = slap_ldap_response_code[ i ].mask;
+ } else if ( lutil_atoix( &mo->mo_dangling_err, c->argv[ 1 ], 0 ) ) {
+ return 1;
+ }
+ break;
+
case MO_REFINT:
if ( c->value_int ) {
mo->mo_flags |= MEMBEROF_FREFINT;
}
}
- if( ! mo->mo_oc_group ){
+ if( ! mo->mo_oc_group ){
mo->mo_oc_group = oc_find( SLAPD_GROUP_CLASS );
if ( mo->mo_oc_group == NULL ) {
Debug( LDAP_DEBUG_ANY,