From 18b2885f6977be65ad387ce2c89cc1596c1ff92b Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Fri, 28 Dec 2007 00:38:27 +0000 Subject: [PATCH] allow to customize the error code in case of constraint violation --- doc/man/man5/slapo-memberof.5 | 38 +++++++++----- servers/slapd/config.c | 86 +++++++++++++++++++++++++++++++ servers/slapd/config.h | 2 + servers/slapd/overlays/memberof.c | 64 +++++++++++++++++++---- 4 files changed, 167 insertions(+), 23 deletions(-) diff --git a/doc/man/man5/slapo-memberof.5 b/doc/man/man5/slapo-memberof.5 index b9f6e06761..b5cf27d4bc 100644 --- a/doc/man/man5/slapo-memberof.5 +++ b/doc/man/man5/slapo-memberof.5 @@ -36,59 +36,69 @@ The following configuration options are defined for the memberofoverlay. .TP -.B memberof-group-oc +.BI memberof-group-oc \ The value -.B +.I is the name of the objectClass that triggers the reverse group membership update. It defaults to \fIgroupOfNames\fP. .TP -.B memberof-member-ad +.BI memberof-member-ad \ The value -.B +.I 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 +.BI memberof-memberof-ad \ The value -.B +.I 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 +.BI memberof-dn \ The value -.B +.I 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 \ +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. diff --git a/servers/slapd/config.c b/servers/slapd/config.c index 93fdf1dc5f..6e20e6a09c 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -1007,6 +1007,92 @@ enum_to_verb(slap_verbmasks *v, slap_mask_t m, struct berval *bv) { 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 }, diff --git a/servers/slapd/config.h b/servers/slapd/config.h index 5964b8df9a..c6b9794565 100644 --- a/servers/slapd/config.h +++ b/servers/slapd/config.h @@ -196,4 +196,6 @@ int config_shadow( ConfigArgs *c, int flag ); #define SLAP_X_ORDERED_FMT "{%d}" +extern slap_verbmasks *slap_ldap_response_code; + #endif /* CONFIG_H */ diff --git a/servers/slapd/overlays/memberof.c b/servers/slapd/overlays/memberof.c index 45c388650d..df834c88b0 100644 --- a/servers/slapd/overlays/memberof.c +++ b/servers/slapd/overlays/memberof.c @@ -155,6 +155,8 @@ typedef struct memberof_t { #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) \ @@ -571,7 +573,7 @@ memberof_op_add( Operation *op, SlapReply *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 ); @@ -649,7 +651,7 @@ memberof_op_add( Operation *op, SlapReply *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 ); @@ -836,7 +838,7 @@ memberof_op_modify( Operation *op, SlapReply *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 ); @@ -933,7 +935,7 @@ memberof_op_modify( Operation *op, SlapReply *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 ); @@ -1044,7 +1046,7 @@ memberof_op_modify( Operation *op, SlapReply *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 ); @@ -1490,6 +1492,10 @@ memberof_db_init( 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; @@ -1499,12 +1505,16 @@ enum { 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; @@ -1570,6 +1580,13 @@ static ConfigTable mo_cfg[] = { 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 } }; @@ -1581,6 +1598,7 @@ static ConfigOCs mo_ocs[] = { "MAY ( " "olcMemberOfDN " "$ olcMemberOfDangling " + "$ olcMemberOfDanglingError" "$ olcMemberOfRefInt " "$ olcMemberOfGroupOC " "$ olcMemberOfMemberAD " @@ -1683,6 +1701,25 @@ mo_cf_gen( ConfigArgs *c ) } 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; @@ -1742,6 +1779,15 @@ mo_cf_gen( ConfigArgs *c ) 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; @@ -1880,7 +1926,7 @@ memberof_db_open( } } - 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,