add administrative bind and proxyAuthz control to enable bound operations in distributed directories (need to manually #define LDAP_BACK_PROXY_AUTHZ and patches from ITS#2851 and ITS#2852)

This commit is contained in:
Pierangelo Masarati 2003-12-01 08:04:51 +00:00
parent 2c68cb41f6
commit cdb11fc5eb
9 changed files with 376 additions and 33 deletions

View File

@ -73,6 +73,10 @@ ldap_back_add(
struct berval mdn = { 0, NULL };
ber_int_t msgid;
dncookie dc;
#ifdef LDAP_BACK_PROXY_AUTHZ
LDAPControl **ctrls = NULL;
int rc = LDAP_SUCCESS;
#endif /* LDAP_BACK_PROXY_AUTHZ */
#ifdef NEW_LOGGING
LDAP_LOG( BACK_LDAP, ENTRY, "ldap_back_add: %s\n", op->o_req_dn.bv_val, 0, 0 );
@ -149,8 +153,29 @@ ldap_back_add(
}
attrs[i] = NULL;
#ifdef LDAP_BACK_PROXY_AUTHZ
rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
if ( rc != LDAP_SUCCESS ) {
goto cleanup;
}
#endif /* LDAP_BACK_PROXY_AUTHZ */
rs->sr_err = ldap_add_ext(lc->ld, mdn.bv_val, attrs,
op->o_ctrls, NULL, &msgid);
#ifdef LDAP_BACK_PROXY_AUTHZ
ctrls,
#else /* ! LDAP_BACK_PROXY_AUTHZ */
op->o_ctrls,
#endif /* ! LDAP_BACK_PROXY_AUTHZ */
NULL, &msgid);
#ifdef LDAP_BACK_PROXY_AUTHZ
cleanup:
if ( ctrls && ctrls != op->o_ctrls ) {
free( ctrls[ 0 ] );
free( ctrls );
}
#endif /* LDAP_BACK_PROXY_AUTHZ */
for (--i; i>= 0; --i) {
ch_free(attrs[i]->mod_vals.modv_bvals);
ch_free(attrs[i]);
@ -159,7 +184,12 @@ ldap_back_add(
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val );
}
#ifdef LDAP_BACK_PROXY_AUTHZ
if ( rc != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
return -1;
}
#endif /* LDAP_BACK_PROXY_AUTHZ */
return ldap_back_op_result( lc, op, rs, msgid, 1 ) != LDAP_SUCCESS;
}

View File

@ -210,6 +210,15 @@ extern int ldap_dnattr_result_rewrite( dncookie *dc, BerVarray a_vals );
extern int ldap_chain_setup();
#ifdef LDAP_BACK_PROXY_AUTHZ
extern int
ldap_back_proxy_authz_ctrl(
struct ldapconn *lc,
Operation *op,
SlapReply *rs,
LDAPControl ***pctrls );
#endif /* LDAP_BACK_PROXY_AUTHZ */
LDAP_END_DECL
#endif /* SLAPD_LDAP_H */

View File

@ -404,13 +404,52 @@ ldap_back_getconn(Operation *op, SlapReply *rs)
int
ldap_back_dobind( struct ldapconn *lc, Operation *op, SlapReply *rs )
{
struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private;
int rc;
ber_int_t msgid;
ldap_pvt_thread_mutex_lock( &lc->lc_mutex );
if ( !lc->bound ) {
rs->sr_err = ldap_sasl_bind(lc->ld, lc->bound_dn.bv_val,
LDAP_SASL_SIMPLE, &lc->cred, NULL, NULL, &msgid);
#ifdef LDAP_BACK_PROXY_AUTHZ
int gotit = 0;
#if 0
int i;
/*
* FIXME: we need to let clients use proxyAuthz
* otherwise we cannot do symmetric pools of servers;
* we have to live with the fact that a user can
* authorize itself as any ID that is allowed
* by the saslAuthzTo directive of the "binddn".
*/
for ( i = 0; op->o_ctrls && op->o_ctrls[ i ]; i++ ) {
if ( strcmp( op->o_ctrls[i]->ldctl_oid, LDAP_CONTROL_PROXY_AUTHZ ) == 0 ) {
gotit = 1;
break;
}
}
#endif
/*
* if no bind took place yet, but the connection is bound
* and the binddn is set, then bind with binddn and
* explicitly add proxyAuthz control to every operation
* with the dn bound to the connection as control value.
*/
if ( ( lc->bound_dn.bv_val == NULL || lc->bound_dn.bv_len == 0 )
&& ( op->o_conn && op->o_conn->c_dn.bv_val != NULL && op->o_conn->c_dn.bv_len != 0 )
&& ( li->binddn.bv_val != NULL && li->binddn.bv_len != 0 )
&& ! gotit ) {
rs->sr_err = ldap_sasl_bind(lc->ld, li->binddn.bv_val,
LDAP_SASL_SIMPLE, &li->bindpw, NULL, NULL, &msgid);
} else
#endif /* LDAP_BACK_PROXY_AUTHZ */
{
rs->sr_err = ldap_sasl_bind(lc->ld, lc->bound_dn.bv_val,
LDAP_SASL_SIMPLE, &lc->cred, NULL, NULL, &msgid);
}
rc = ldap_back_op_result( lc, op, rs, msgid, 0 );
if (rc == LDAP_SUCCESS) {
lc->bound = 1;
@ -550,3 +589,98 @@ ldap_back_op_result(struct ldapconn *lc, Operation *op, SlapReply *rs,
return( (rs->sr_err == LDAP_SUCCESS) ? 0 : -1 );
}
#ifdef LDAP_BACK_PROXY_AUTHZ
/*
* ldap_back_proxy_authz_ctrl() prepends a proxyAuthz control
* to existing server-side controls if required; if not,
* the existing server-side controls are placed in *pctrls.
* The caller, after using the controls in client API
* operations, if ( *pctrls != op->o_ctrls ), should
* free( (*pctrls)[ 0 ] ) and free( *pctrls ).
* The function returns success if the control could
* be added if required, or if it did nothing; in the future,
* it might return some error if it failed.
*
* if no bind took place yet, but the connection is bound
* and the binddn is set, then bind with binddn and
* explicitly add proxyAuthz control to every operation
* with the dn bound to the connection as control value.
*
* If no server-side controls are defined for the operation,
* simply add the proxyAuthz control; otherwise, if the
* proxyAuthz control is not already set, add it as
* the first one (FIXME: is controls order significant
* for security?).
*/
int
ldap_back_proxy_authz_ctrl(
struct ldapconn *lc,
Operation *op,
SlapReply *rs,
LDAPControl ***pctrls )
{
struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private;
LDAPControl **ctrls = NULL;
*pctrls = NULL;
if ( ( lc->bound_dn.bv_val == NULL || lc->bound_dn.bv_len == 0 )
&& ( op->o_conn && op->o_conn->c_dn.bv_val != NULL && op->o_conn->c_dn.bv_len != 0 )
&& ( li->binddn.bv_val != NULL && li->binddn.bv_len != 0 ) ) {
int i = 0, gotit = 0;
if ( op->o_ctrls ) {
for ( i = 0; op->o_ctrls[i]; i++ ) {
if ( strcmp( op->o_ctrls[i]->ldctl_oid, LDAP_CONTROL_PROXY_AUTHZ ) == 0 ) {
gotit = 1;
break;
}
}
}
if ( ! gotit ) {
ctrls = ch_malloc( sizeof( LDAPControl * ) * (i + 2) );
ctrls[ 0 ] = ch_malloc( sizeof( LDAPControl ) );
ctrls[ 0 ]->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
ctrls[ 0 ]->ldctl_iscritical = 1;
ctrls[ 0 ]->ldctl_value.bv_len = op->o_conn->c_dn.bv_len + 3;
ctrls[ 0 ]->ldctl_value.bv_val = ch_malloc( ctrls[ 0 ]->ldctl_value.bv_len + 1 );
AC_MEMCPY( ctrls[ 0 ]->ldctl_value.bv_val, "dn:", sizeof( "dn:" ) - 1 );
AC_MEMCPY( ctrls[ 0 ]->ldctl_value.bv_val + sizeof( "dn:") - 1,
op->o_conn->c_dn.bv_val, op->o_conn->c_dn.bv_len + 1 );
if ( op->o_ctrls ) {
for ( i = 0; op->o_ctrls[ i ]; i++ ) {
ctrls[ i + 1 ] = op->o_ctrls[ i ];
}
}
ctrls[ i + 1 ] = NULL;
} else {
/*
* FIXME: we do not want to perform proxyAuthz
* on behalf of the client, because this would
* be performed with "binddn" privileges.
*
* This might actually be too strict, since
* the "binddn" saslAuthzTo, and each entry's
* saslAuthzFrom attributes may be crafted
* to avoid unwanted proxyAuthz to take place.
*/
#if 0
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
rs->sr_text = "proxyAuthz not allowed within namingContext";
#endif
}
}
if ( ctrls == NULL ) {
ctrls = op->o_ctrls;
}
*pctrls = ctrls;
return rs->sr_err;
}
#endif /* LDAP_BACK_PROXY_AUTHZ */

View File

@ -66,11 +66,15 @@ ldap_back_compare(
{
struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private;
struct ldapconn *lc;
struct berval mapped_at, mapped_val;
struct berval mapped_at = { 0, NULL }, mapped_val = { 0, NULL };
struct berval mdn = { 0, NULL };
ber_int_t msgid;
int freeval = 0;
dncookie dc;
#ifdef LDAP_BACK_PROXY_AUTHZ
LDAPControl **ctrls = NULL;
int rc = LDAP_SUCCESS;
#endif /* LDAP_BACK_PROXY_AUTHZ */
lc = ldap_back_getconn(op, rs);
if (!lc || !ldap_back_dobind( lc, op, rs ) ) {
@ -119,18 +123,47 @@ ldap_back_compare(
} else if (mapped_val.bv_val != op->orc_ava->aa_value.bv_val) {
freeval = 1;
}
} else {
mapped_val = op->orc_ava->aa_value;
}
}
rs->sr_err = ldap_compare_ext( lc->ld, mdn.bv_val, mapped_at.bv_val,
&mapped_val, op->o_ctrls, NULL, &msgid );
#ifdef LDAP_BACK_PROXY_AUTHZ
rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
if ( rc != LDAP_SUCCESS ) {
goto cleanup;
}
#endif /* LDAP_BACK_PROXY_AUTHZ */
rs->sr_err = ldap_compare_ext( lc->ld, mdn.bv_val,
mapped_at.bv_val, &mapped_val,
#ifdef LDAP_BACK_PROXY_AUTHZ
ctrls,
#else /* ! LDAP_BACK_PROXY_AUTHZ */
op->o_ctrls,
#endif /* ! LDAP_BACK_PROXY_AUTHZ */
NULL, &msgid );
#ifdef LDAP_BACK_PROXY_AUTHZ
cleanup:
if ( ctrls && ctrls != op->o_ctrls ) {
free( ctrls[ 0 ] );
free( ctrls );
}
#endif /* LDAP_BACK_PROXY_AUTHZ */
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val );
}
if ( freeval ) {
free( mapped_val.bv_val );
}
#ifdef LDAP_BACK_PROXY_AUTHZ
if ( rc != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
return -1;
}
#endif /* LDAP_BACK_PROXY_AUTHZ */
return( ldap_back_op_result( lc, op, rs, msgid, 1 ) );
}

View File

@ -68,6 +68,10 @@ ldap_back_delete(
struct ldapconn *lc;
ber_int_t msgid;
dncookie dc;
#ifdef LDAP_BACK_PROXY_AUTHZ
LDAPControl **ctrls = NULL;
int rc = LDAP_SUCCESS;
#endif /* LDAP_BACK_PROXY_AUTHZ */
struct berval mdn = { 0, NULL };
@ -93,13 +97,40 @@ ldap_back_delete(
send_ldap_result( op, rs );
return -1;
}
rs->sr_err = ldap_delete_ext( lc->ld, mdn.bv_val, op->o_ctrls,
#ifdef LDAP_BACK_PROXY_AUTHZ
rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
if ( rc != LDAP_SUCCESS ) {
goto cleanup;
}
#endif /* LDAP_BACK_PROXY_AUTHZ */
rs->sr_err = ldap_delete_ext( lc->ld, mdn.bv_val,
#ifdef LDAP_BACK_PROXY_AUTHZ
ctrls,
#else /* ! LDAP_BACK_PROXY_AUTHZ */
op->o_ctrls,
#endif /* ! LDAP_BACK_PROXY_AUTHZ */
NULL, &msgid );
#ifdef LDAP_BACK_PROXY_AUTHZ
cleanup:
if ( ctrls && ctrls != op->o_ctrls ) {
free( ctrls[ 0 ] );
free( ctrls );
}
#endif /* LDAP_BACK_PROXY_AUTHZ */
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val );
}
#ifdef LDAP_BACK_PROXY_AUTHZ
if ( rc != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
return -1;
}
#endif /* LDAP_BACK_PROXY_AUTHZ */
return( ldap_back_op_result( lc, op, rs, msgid, 1 ) );
}

View File

@ -48,7 +48,40 @@ ldap_back_extended(
for( i=0; exop_table[i].extended != NULL; i++ ) {
if( ber_bvcmp( exop_table[i].oid, &op->oq_extended.rs_reqoid ) == 0 ) {
#ifdef LDAP_BACK_PROXY_AUTHZ
struct ldapconn *lc;
LDAPControl **oldctrls = NULL;
int rc;
/* FIXME: this needs to be called here, so it is
* called twice; maybe we could avoid the
* ldap_back_dobind() call inside each extended()
* call ... */
lc = ldap_back_getconn(op, rs);
if (!lc || !ldap_back_dobind(lc, op, rs) ) {
return -1;
}
oldctrls = op->o_ctrls;
if ( ldap_back_proxy_authz_ctrl( lc, op, rs, &op->o_ctrls ) ) {
op->o_ctrls = oldctrls;
send_ldap_result( op, rs );
rs->sr_text = NULL;
return rs->sr_err;
}
rc = (exop_table[i].extended)( op, rs );
if ( op->o_ctrls && op->o_ctrls != oldctrls ) {
free( op->o_ctrls[ 0 ] );
free( op->o_ctrls );
}
op->o_ctrls = oldctrls;
return rc;
#else /* ! LDAP_BACK_PROXY_AUTHZ */
return (exop_table[i].extended)( op, rs );
#endif /* ! LDAP_BACK_PROXY_AUTHZ */
}
}

View File

@ -74,6 +74,9 @@ ldap_back_modify(
struct berval mdn = { 0, NULL };
ber_int_t msgid;
dncookie dc;
#ifdef LDAP_BACK_PROXY_AUTHZ
LDAPControl **ctrls = NULL;
#endif /* LDAP_BACK_PROXY_AUTHZ */
lc = ldap_back_getconn(op, rs);
if ( !lc || !ldap_back_dobind( lc, op, rs ) ) {
@ -181,10 +184,29 @@ ldap_back_modify(
}
modv[i] = 0;
#ifdef LDAP_BACK_PROXY_AUTHZ
rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
if ( rc != LDAP_SUCCESS ) {
goto cleanup;
}
#endif /* LDAP_BACK_PROXY_AUTHZ */
rs->sr_err = ldap_modify_ext( lc->ld, mdn.bv_val, modv,
op->o_ctrls, NULL, &msgid );
#ifdef LDAP_BACK_PROXY_AUTHZ
ctrls,
#else /* ! LDAP_BACK_PROXY_AUTHZ */
op->o_ctrls,
#endif /* ! LDAP_BACK_PROXY_AUTHZ */
NULL, &msgid );
cleanup:;
#ifdef LDAP_BACK_PROXY_AUTHZ
if ( ctrls && ctrls != op->o_ctrls ) {
free( ctrls[ 0 ] );
free( ctrls );
}
#endif /* LDAP_BACK_PROXY_AUTHZ */
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val );
}
@ -194,6 +216,13 @@ cleanup:;
ch_free( mods );
ch_free( modv );
#ifdef LDAP_BACK_PROXY_AUTHZ
if ( rc != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
return -1;
}
#endif /* LDAP_BACK_PROXY_AUTHZ */
return ldap_back_op_result( lc, op, rs, msgid, 1 );
}

View File

@ -68,6 +68,10 @@ ldap_back_modrdn(
struct ldapconn *lc;
ber_int_t msgid;
dncookie dc;
#ifdef LDAP_BACK_PROXY_AUTHZ
LDAPControl **ctrls = NULL;
int rc = LDAP_SUCCESS;
#endif /* LDAP_BACK_PROXY_AUTHZ */
struct berval mdn = { 0, NULL }, mnewSuperior = { 0, NULL };
@ -112,11 +116,31 @@ ldap_back_modrdn(
return -1;
}
#ifdef LDAP_BACK_PROXY_AUTHZ
rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
if ( rc != LDAP_SUCCESS ) {
goto cleanup;
}
#endif /* LDAP_BACK_PROXY_AUTHZ */
rs->sr_err = ldap_rename( lc->ld, mdn.bv_val,
op->orr_newrdn.bv_val, mnewSuperior.bv_val,
op->orr_deleteoldrdn, op->o_ctrls,
op->orr_deleteoldrdn,
#ifdef LDAP_BACK_PROXY_AUTHZ
ctrls,
#else /* ! LDAP_BACK_PROXY_AUTHZ */
op->o_ctrls,
#endif /* ! LDAP_BACK_PROXY_AUTHZ */
NULL, &msgid );
#ifdef LDAP_BACK_PROXY_AUTHZ
cleanup:
if ( ctrls && ctrls != op->o_ctrls ) {
free( ctrls[ 0 ] );
free( ctrls );
}
#endif /* LDAP_BACK_PROXY_AUTHZ */
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val );
}
@ -124,7 +148,14 @@ ldap_back_modrdn(
&& mnewSuperior.bv_val != op->oq_modrdn.rs_newSup->bv_val ) {
free( mnewSuperior.bv_val );
}
#ifdef LDAP_BACK_PROXY_AUTHZ
if ( rc != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
return -1;
}
#endif /* LDAP_BACK_PROXY_AUTHZ */
return( ldap_back_op_result( lc, op, rs, msgid, 1 ) );
}

View File

@ -88,7 +88,11 @@ ldap_back_search(
struct berval mfilter = { 0, NULL };
struct slap_limits_set *limit = NULL;
int isroot = 0;
int dontfreetext = 0;
dncookie dc;
#ifdef LDAP_BACK_PROXY_AUTHZ
LDAPControl **ctrls = NULL;
#endif /* LDAP_BACK_PROXY_AUTHZ */
lc = ldap_back_getconn(op, rs);
if ( !lc ) {
@ -181,6 +185,7 @@ ldap_back_search(
if ( rc ) {
rs->sr_err = LDAP_OTHER;
rs->sr_text = "Rewrite error";
dontfreetext = 1;
rc = -1;
goto finish;
}
@ -193,27 +198,26 @@ ldap_back_search(
goto finish;
}
#if 0
if ( mapped_attrs == NULL && op->oq_search.rs_attrs) {
int count;
/* this can happen only if ch_calloc() fails
* in ldap_back_map_attrs() */
for (count=0; op->oq_search.rs_attrs[count].an_name.bv_val; count++);
mapped_attrs = ch_malloc( (count+1) * sizeof(char *));
for (count=0; op->oq_search.rs_attrs[count].an_name.bv_val; count++) {
mapped_attrs[count] = op->oq_search.rs_attrs[count].an_name.bv_val;
}
mapped_attrs[count] = NULL;
#ifdef LDAP_BACK_PROXY_AUTHZ
rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls );
if ( rc != LDAP_SUCCESS ) {
dontfreetext = 1;
goto finish;
}
#endif
#endif /* LDAP_BACK_PROXY_AUTHZ */
rs->sr_err = ldap_search_ext(lc->ld, mbase.bv_val,
op->oq_search.rs_scope, mfilter.bv_val,
mapped_attrs, op->oq_search.rs_attrsonly,
op->o_ctrls, NULL,
#ifdef LDAP_BACK_PROXY_AUTHZ
ctrls,
#else /* ! LDAP_BACK_PROXY_AUTHZ */
op->o_ctrls,
#endif /* ! LDAP_BACK_PROXY_AUTHZ */
NULL,
tv.tv_sec ? &tv : NULL, op->oq_search.rs_slimit,
&msgid);
&msgid );
if ( rs->sr_err != LDAP_SUCCESS ) {
fail:;
rc = ldap_back_op_result(lc, op, rs, msgid, 0);
@ -347,6 +351,13 @@ fail:;
finish:;
send_ldap_result( op, rs );
#ifdef LDAP_BACK_PROXY_AUTHZ
if ( ctrls && ctrls != op->o_ctrls ) {
free( ctrls[ 0 ] );
free( ctrls );
}
#endif /* LDAP_BACK_PROXY_AUTHZ */
if ( match.bv_val ) {
if ( rs->sr_matched != match.bv_val ) {
free( (char *)rs->sr_matched );
@ -355,7 +366,9 @@ finish:;
LDAP_FREE( match.bv_val );
}
if ( rs->sr_text ) {
LDAP_FREE( (char *)rs->sr_text );
if ( !dontfreetext ) {
LDAP_FREE( (char *)rs->sr_text );
}
rs->sr_text = NULL;
}
if ( mapped_attrs ) {
@ -536,7 +549,6 @@ ldap_build_entry(
} else if ( attr->a_desc->ad_type->sat_syntax ==
slap_schema.si_syn_distinguishedName ) {
ldap_dnattr_result_rewrite( &dc, attr->a_vals );
}
if ( normalize && last && attr->a_desc->ad_type->sat_equality &&
@ -560,6 +572,7 @@ ldap_build_entry(
*attrp = attr;
attrp = &attr->a_next;
}
/* make sure it's free'able */
if (!private && ent->e_name.bv_val == bdn->bv_val)
ber_dupbv( &ent->e_name, bdn );
@ -646,7 +659,7 @@ ldap_back_entry_get(
*ptr++ = ')';
*ptr++ = '\0';
}
if (ldap_search_ext_s(lc->ld, mdn.bv_val, LDAP_SCOPE_BASE, filter,
gattr, 0, NULL, NULL, LDAP_NO_LIMIT,
LDAP_NO_LIMIT, &result) != LDAP_SUCCESS)