X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-ldap%2Fbind.c;h=cfecc0362f26c71747460936b1696b54065b7c02;hb=1a9bc6655ddf9a1d08ee4f5e6e4ef6a7707ca5f7;hp=141c8db487537283a70c3c4a279a690108ad0edf;hpb=ab3ab80ecdb4e09087172125eda62b7dca9ead59;p=openldap diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c index 141c8db487..cfecc0362f 100644 --- a/servers/slapd/back-ldap/bind.c +++ b/servers/slapd/back-ldap/bind.c @@ -1,38 +1,24 @@ /* bind.c - ldap backend bind function */ /* $OpenLDAP$ */ -/* - * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved. - * COPYING RESTRICTIONS APPLY, see COPYRIGHT file - */ -/* This is an altered version */ -/* - * Copyright 1999, Howard Chu, All rights reserved. - * - * Permission is granted to anyone to use this software for any purpose - * on any computer system, and to alter it and redistribute it, subject - * to the following restrictions: - * - * 1. The author is not responsible for the consequences of use of this - * software, no matter how awful, even if they arise from flaws in it. - * - * 2. The origin of this software must not be misrepresented, either by - * explicit claim or by omission. Since few users ever read sources, - * credits should appear in the documentation. - * - * 3. Altered versions must be plainly marked as such, and must not be - * misrepresented as being the original software. Since few users - * ever read sources, credits should appear in the documentation. - * - * 4. This notice may not be removed or altered. +/* This work is part of OpenLDAP Software . * + * Copyright 1999-2004 The OpenLDAP Foundation. + * Portions Copyright 2000-2003 Pierangelo Masarati. + * Portions Copyright 1999-2003 Howard Chu. + * All rights reserved. * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. * - * Copyright 2000, Pierangelo Masarati, All rights reserved. - * - * This software is being modified by Pierangelo Masarati. - * The previously reported conditions apply to the modified code as well. - * Changes in the original code are highlighted where required. - * Credits for the original code go to the author, Howard Chu. + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by the Howard Chu for inclusion + * in OpenLDAP Software and subsequently enhanced by Pierangelo + * Masarati. */ #include "portable.h" @@ -62,6 +48,7 @@ ldap_back_bind( struct berval mdn = { 0, NULL }; int rc = 0; ber_int_t msgid; + dncookie dc; lc = ldap_back_getconn(op, rs); if ( !lc ) { @@ -71,40 +58,19 @@ ldap_back_bind( /* * Rewrite the bind dn if needed */ + dc.rwmap = &li->rwmap; #ifdef ENABLE_REWRITE - switch ( rewrite_session( li->rwinfo, "bindDn", - op->o_req_dn.bv_val, - op->o_conn, &mdn.bv_val ) ) { - case REWRITE_REGEXEC_OK: - if ( mdn.bv_val == NULL ) { - mdn = op->o_req_dn; - } else { - mdn.bv_len = strlen( mdn.bv_val ); - } - -#ifdef NEW_LOGGING - LDAP_LOG( BACK_LDAP, DETAIL1, - "[rw] bindDn: \"%s\" -> \"%s\"\n", - op->o_req_dn.bv_val, mdn.bv_val, 0 ); -#else /* !NEW_LOGGING */ - Debug( LDAP_DEBUG_ARGS, "rw> bindDn: \"%s\" -> \"%s\"\n", - op->o_req_dn.bv_val, mdn.bv_val, 0 ); -#endif /* !NEW_LOGGING */ - break; - - case REWRITE_REGEXEC_UNWILLING: - send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, - "Operation not allowed" ); - return( -1 ); - - case REWRITE_REGEXEC_ERR: - send_ldap_error( op, rs, LDAP_OTHER, - "Rewrite error" ); - return( -1 ); + dc.conn = op->o_conn; + dc.rs = rs; + dc.ctx = "bindDn"; +#else + dc.tofrom = 1; + dc.normalized = 0; +#endif + if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { + send_ldap_result( op, rs ); + return -1; } -#else /* !ENABLE_REWRITE */ - ldap_back_dn_massage( li, &op->o_req_dn, &mdn, 0, 1 ); -#endif /* !ENABLE_REWRITE */ if ( lc->bound_dn.bv_val ) { ch_free( lc->bound_dn.bv_val ); @@ -123,9 +89,13 @@ ldap_back_bind( } else { ber_dupbv( &lc->bound_dn, &op->o_req_dn ); } + mdn.bv_val = NULL; + if ( li->savecred ) { - if ( lc->cred.bv_val ) + if ( lc->cred.bv_val ) { + memset( lc->cred.bv_val, 0, lc->cred.bv_len ); ch_free( lc->cred.bv_val ); + } ber_dupbv( &lc->cred, &op->oq_bind.rb_cred ); ldap_set_rebind_proc( lc->ld, ldap_back_rebind, lc ); } @@ -149,6 +119,10 @@ ldap_back_bind( } } + if ( mdn.bv_val && mdn.bv_val != op->o_req_dn.bv_val ) { + free( mdn.bv_val ); + } + return( rc ); } @@ -175,7 +149,7 @@ ldap_back_conn_cmp( /* For shared sessions, conn is NULL. Only explicitly * bound sessions will have non-NULL conn. */ - return lc1->conn - lc2->conn; + return SLAP_PTRCMP(lc1->conn, lc2->conn); } /* @@ -262,6 +236,7 @@ ldap_back_getconn(Operation *op, SlapReply *rs) } else { lc_curr.local_dn = op->o_ndn; } + ldap_pvt_thread_mutex_lock( &li->conn_mutex ); lc = (struct ldapconn *)avl_find( li->conntree, (caddr_t)&lc_curr, ldap_back_conn_cmp ); @@ -269,7 +244,7 @@ ldap_back_getconn(Operation *op, SlapReply *rs) /* Looks like we didn't get a bind. Open a new session... */ if (!lc) { - int vers = op->o_conn->c_protocol; + int vers = op->o_protocol; rs->sr_err = ldap_initialize(&ld, li->url); if (rs->sr_err != LDAP_SUCCESS) { @@ -277,7 +252,8 @@ ldap_back_getconn(Operation *op, SlapReply *rs) if (rs->sr_text == NULL) { rs->sr_text = "ldap_initialize() failed"; } - send_ldap_result( op, rs ); + if (op->o_conn) send_ldap_result( op, rs ); + rs->sr_text = NULL; return( NULL ); } /* Set LDAP version. This will always succeed: If the client @@ -301,7 +277,7 @@ ldap_back_getconn(Operation *op, SlapReply *rs) * since we may have different entries * for the same connection */ - ( void )rewrite_session_init( li->rwinfo, op->o_conn ); + ( void )rewrite_session_init( li->rwmap.rwm_rw, op->o_conn ); #endif /* ENABLE_REWRITE */ ldap_pvt_thread_mutex_init( &lc->lc_mutex ); @@ -312,66 +288,37 @@ ldap_back_getconn(Operation *op, SlapReply *rs) } else { lc->cred.bv_len = 0; lc->cred.bv_val = NULL; - if ( op->o_conn->c_dn.bv_len != 0 ) { + lc->bound_dn.bv_val = NULL; + lc->bound_dn.bv_len = 0; + if ( op->o_conn && op->o_conn->c_dn.bv_len != 0 + && ( op->o_bd == op->o_conn->c_authz_backend ) ) { + dncookie dc; + struct berval bv; + /* * Rewrite the bind dn if needed */ -#ifdef ENABLE_REWRITE - lc->bound_dn.bv_val = NULL; - lc->bound_dn.bv_len = 0; - switch ( rewrite_session( li->rwinfo, "bindDn", - op->o_conn->c_dn.bv_val, - op->o_conn, - &lc->bound_dn.bv_val ) ) { - case REWRITE_REGEXEC_OK: - if ( lc->bound_dn.bv_val == NULL ) { - ber_dupbv( &lc->bound_dn, - &op->o_conn->c_dn ); - } else { - lc->bound_dn.bv_len = strlen( lc->bound_dn.bv_val ); - } -#ifdef NEW_LOGGING - LDAP_LOG( BACK_LDAP, DETAIL1, - "[rw] bindDn: \"%s\" ->" - " \"%s\"\n", - op->o_conn->c_dn.bv_val, - lc->bound_dn.bv_val, 0 ); -#else /* !NEW_LOGGING */ - Debug( LDAP_DEBUG_ARGS, - "rw> bindDn: \"%s\" ->" - " \"%s\"\n", - op->o_conn->c_dn.bv_val, - lc->bound_dn.bv_val, 0 ); -#endif /* !NEW_LOGGING */ - break; - - case REWRITE_REGEXEC_UNWILLING: - send_ldap_error( op, rs, - LDAP_UNWILLING_TO_PERFORM, - "Operation not allowed" ); - return( NULL ); - - case REWRITE_REGEXEC_ERR: - send_ldap_error( op, rs, - LDAP_OTHER, - "Rewrite error" ); - return( NULL ); + dc.rwmap = &li->rwmap; +#ifdef ENABLE_REWRITE + dc.conn = op->o_conn; + dc.rs = rs; + dc.ctx = "bindDn"; +#else + dc.tofrom = 1; + dc.normalized = 0; +#endif + + if ( ldap_back_dn_massage( &dc, &op->o_conn->c_dn, &bv ) ) { + send_ldap_result( op, rs ); + return NULL; } -#else /* !ENABLE_REWRITE */ - struct berval bv; - ldap_back_dn_massage( li, &op->o_conn->c_dn, &bv, 0, 1 ); if ( bv.bv_val == op->o_conn->c_dn.bv_val ) { ber_dupbv( &lc->bound_dn, &bv ); } else { lc->bound_dn = bv; } -#endif /* !ENABLE_REWRITE */ - - } else { - lc->bound_dn.bv_val = NULL; - lc->bound_dn.bv_len = 0; } } @@ -390,27 +337,29 @@ ldap_back_getconn(Operation *op, SlapReply *rs) #ifdef NEW_LOGGING LDAP_LOG( BACK_LDAP, INFO, - "ldap_back_getconn: conn %lx inserted\n", lc, 0, 0); + "ldap_back_getconn: conn %p inserted\n", (void *) lc, 0, 0); #else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_TRACE, - "=>ldap_back_getconn: conn %lx inserted\n", lc, 0, 0 ); + "=>ldap_back_getconn: conn %p inserted\n", (void *) lc, 0, 0 ); #endif /* !NEW_LOGGING */ /* Err could be -1 in case a duplicate ldapconn is inserted */ if ( rs->sr_err != 0 ) { ldap_back_conn_free( lc ); - send_ldap_error( op, rs, LDAP_OTHER, - "internal server error" ); + if (op->o_conn) { + send_ldap_error( op, rs, LDAP_OTHER, + "internal server error" ); + } return( NULL ); } } else { #ifdef NEW_LOGGING LDAP_LOG( BACK_LDAP, INFO, - "ldap_back_getconn: conn %lx fetched\n", - lc, 0, 0 ); + "ldap_back_getconn: conn %p fetched\n", + (void *) lc, 0, 0 ); #else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_TRACE, - "=>ldap_back_getconn: conn %lx fetched\n", lc, 0, 0 ); + "=>ldap_back_getconn: conn %p fetched\n", (void *) lc, 0, 0 ); #endif /* !NEW_LOGGING */ } @@ -427,13 +376,51 @@ 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 + /* + * 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 "proxyauthzdn". + */ + /* + * NOTE: current Proxy Authorization specification + * and implementation do not allow proxy authorization + * control to be provided with Bind requests + */ + gotit = op->o_proxy_authz; +#endif + + /* + * if no bind took place yet, but the connection is bound + * and the "proxyauthzdn" is set, then bind as + * "proxyauthzdn" and explicitly add the 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->proxyauthzdn.bv_val != NULL && li->proxyauthzdn.bv_len != 0 ) + && ! gotit ) { + rs->sr_err = ldap_sasl_bind(lc->ld, li->proxyauthzdn.bv_val, + LDAP_SASL_SIMPLE, &li->proxyauthzpw, 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; @@ -516,7 +503,6 @@ ldap_back_op_result(struct ldapconn *lc, Operation *op, SlapReply *rs, struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private; char *match = NULL; LDAPMessage *res; - int rc; char *text = NULL; rs->sr_text = NULL; @@ -527,8 +513,8 @@ ldap_back_op_result(struct ldapconn *lc, Operation *op, SlapReply *rs, ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err); } else { - rc = ldap_parse_result(lc->ld, res, &rs->sr_err, &match, - &text, NULL, NULL, 1); + int rc = ldap_parse_result(lc->ld, res, &rs->sr_err, + &match, &text, NULL, NULL, 1); rs->sr_text = text; if (rc != LDAP_SUCCESS) rs->sr_err = rc; } @@ -538,35 +524,35 @@ ldap_back_op_result(struct ldapconn *lc, Operation *op, SlapReply *rs, rs->sr_err = ldap_back_map_result(rs); /* internal ops must not reply to client */ - if ( op->o_conn && !op->o_do_not_cache ) { + if ( op->o_conn && !op->o_do_not_cache && match ) { + struct berval dn, mdn; + dncookie dc; + + dc.rwmap = &li->rwmap; #ifdef ENABLE_REWRITE - if (match) { - - switch(rewrite_session(li->rwinfo, "matchedDn", match, op->o_conn, - (char **)&rs->sr_matched)) { - case REWRITE_REGEXEC_OK: - if (!rs->sr_matched) rs->sr_matched = match; break; - case REWRITE_REGEXEC_UNWILLING: - case REWRITE_REGEXEC_ERR: - break; - } - } + dc.conn = op->o_conn; + dc.rs = rs; + dc.ctx = "matchedDn"; #else - struct berval dn, mdn; - if (match) { - ber_str2bv(match, 0, 0, &dn); - ldap_back_dn_massage(li, &dn, &mdn, 0, 0); - rs->sr_matched = mdn.bv_val; - } + dc.tofrom = 0; + dc.normalized = 0; #endif + ber_str2bv(match, 0, 0, &dn); + ldap_back_dn_massage(&dc, &dn, &mdn); + rs->sr_matched = mdn.bv_val; + } } if (op->o_conn && (sendok || rs->sr_err != LDAP_SUCCESS)) { send_ldap_result( op, rs ); } - if (rs->sr_matched != match) free((char *)rs->sr_matched); - rs->sr_matched = NULL; - if ( match ) ldap_memfree( match ); + if ( match ) { + if ( rs->sr_matched != match ) { + free( (char *)rs->sr_matched ); + } + rs->sr_matched = NULL; + ldap_memfree( match ); + } if ( text ) { ldap_memfree( text ); } @@ -574,3 +560,89 @@ 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 "proxyauthzdn" is set, then bind as "proxyauthzdn" + * and explicitly add proxyAuthz the 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->proxyauthzdn.bv_val != NULL && li->proxyauthzdn.bv_len != 0 ) ) { + int i = 0; + + if ( !op->o_proxy_authz ) { + 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 "proxyauthzdn" privileges. + * + * This might actually be too strict, since + * the "proxyauthzdn" 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 */