From ce4f5abb6e6b5f3891f03c8eb277e05760d7132c Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Thu, 30 Dec 2010 21:41:36 +0000 Subject: [PATCH] should also work for SASL binds (whenever supported) --- contrib/slapd-modules/vc/vc.c | 258 ++++++++++++++++++++++++++++++---- 1 file changed, 230 insertions(+), 28 deletions(-) diff --git a/contrib/slapd-modules/vc/vc.c b/contrib/slapd-modules/vc/vc.c index 7179bb5357..a5f41bfd74 100644 --- a/contrib/slapd-modules/vc/vc.c +++ b/contrib/slapd-modules/vc/vc.c @@ -28,7 +28,98 @@ #include "slap.h" #include "ac/string.h" +typedef struct vc_conn_t { + struct vc_conn_t *conn; + Connection connbuf; + OperationBuffer opbuf; + Operation *op; + int refcnt; +} vc_conn_t; + static const struct berval vc_exop_oid_bv = BER_BVC(LDAP_EXOP_VERIFY_CREDENTIALS); +static ldap_pvt_thread_mutex_t vc_mutex; +static Avlnode *vc_tree; + +static int +vc_conn_cmp( const void *c1, const void *c2 ) +{ + const vc_conn_t *vc1 = (const vc_conn_t *)c1; + const vc_conn_t *vc2 = (const vc_conn_t *)c2; + + return SLAP_PTRCMP( vc1->conn, vc2->conn ); +} + +static int +vc_conn_dup( void *c1, void *c2 ) +{ + vc_conn_t *vc1 = (vc_conn_t *)c1; + vc_conn_t *vc2 = (vc_conn_t *)c2; + + if ( vc1->conn == vc2->conn ) { + return -1; + } + + return 0; +} + +static int +vc_create_response( + void *conn, + struct berval *servercred, + struct berval *authzid, + struct berval **val ) +{ + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + struct berval bv; + int rc; + + assert( val != NULL ); + + ber_init2( ber, NULL, LBER_USE_DER ); + + ber_printf( ber, "{" /*}*/ ); + + if ( conn ) { + struct berval cookie; + + cookie.bv_len = sizeof( conn ); + cookie.bv_val = (char *)&conn; + ber_printf( ber, "tO", 0, LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE, &cookie ); + } + + if ( servercred ) { + ber_printf( ber, "tO", LDAP_TAG_EXOP_VERIFY_CREDENTIALS_SCREDS, servercred ); + } + + if ( authzid ) { + ber_printf( ber, "tO", LDAP_TAG_EXOP_VERIFY_CREDENTIALS_AUTHZID, authzid ); + } + + ber_printf( ber, /*{*/ "}" ); + + rc = ber_flatten2( ber, &bv, 0 ); + + *val = ber_bvdup( &bv ); + + ber_free_buf( ber ); + + return rc; +} + +static int +vc_exop_sasl_cb( + Operation *op, + SlapReply *rs ) +{ + struct berval *sasldata = (struct berval *)op->o_callback->sc_private; + + if ( rs->sr_tag == LDAP_REQ_BIND && sasldata != NULL && rs->sr_sasldata != NULL ) { + ber_dupbv( sasldata, rs->sr_sasldata ); + } + + return 0; +} static int vc_exop( @@ -42,11 +133,26 @@ vc_exop( BerElement *ber = (BerElement *)&berbuf; struct berval reqdata = BER_BVNULL; + struct berval cookie = BER_BVNULL; + struct berval bdn = BER_BVNULL; + ber_tag_t authtag; + struct berval cred = BER_BVNULL; + struct berval ndn = BER_BVNULL; + struct berval mechanism = BER_BVNULL; + + vc_conn_t *conn = NULL; + slap_callback sc = { 0 }; + SlapReply rs2 = { 0 }; + struct berval sasldata = BER_BVNULL; + if ( op->ore_reqdata == NULL || op->ore_reqdata->bv_len == 0 ) { rs->sr_text = "empty request data field in VerifyCredentials exop"; return LDAP_PROTOCOL_ERROR; } + /* optimistic */ + rs->sr_err = LDAP_SUCCESS; + ber_dupbv_x( &reqdata, op->ore_reqdata, op->o_tmpmemctx ); /* ber_init2 uses reqdata directly, doesn't allocate new buffers */ @@ -61,11 +167,6 @@ vc_exop( tag = ber_peek_tag( ber, &len ); if ( tag == LBER_INTEGER ) { ber_int_t version; - struct berval bdn; - ber_tag_t authtag; - struct berval cred; - struct berval ndn; - Attribute a = { 0 }; /* simple */ @@ -89,34 +190,39 @@ vc_exop( goto done; } - a.a_desc = slap_schema.si_ad_userPassword; - rc = backend_attribute( op, NULL, &ndn, a.a_desc, &a.a_vals, ACL_AUTH ); - if ( rc != LDAP_SUCCESS || a.a_vals == NULL ) { - rs->sr_err = LDAP_INVALID_CREDENTIALS; + } else { + /* SASL */ + if ( tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE ) { + /* + * cookie: the pointer to the connection + * of this operation + */ - } else { - a.a_nvals = a.a_vals; - for ( a.a_numvals = 0; !BER_BVISNULL( &a.a_nvals[a.a_numvals] ); a.a_numvals++ ) - ; - - rc = slap_passwd_check( op, NULL, &a, &cred, &rs->sr_text ); - if ( rc != 0 ) { - rs->sr_err = LDAP_INVALID_CREDENTIALS; - - } else { - rs->sr_err = LDAP_SUCCESS; - rs->sr_rspoid = NULL; - rs->sr_rspdata = NULL; + ber_scanf( ber, "m", &cookie ); + if ( cookie.bv_len != sizeof(Connection *) ) { + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto done; } + } - op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx ); - op->o_tmpfree( a.a_vals, op->o_tmpmemctx ); + tag = ber_scanf( ber, "mt{s", &bdn, &authtag, &mechanism ); + if ( tag == LBER_ERROR || authtag != LDAP_AUTH_SASL || + BER_BVISNULL( &mechanism ) || BER_BVISEMPTY( &mechanism) ) + { + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto done; + } - } else { - /* SASL */ - if ( tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE ) { - } else { + tag = ber_peek_tag( ber, &len ); + if ( tag == LBER_OCTETSTRING ) { + ber_scanf( ber, "m", &cred ); + } + + rc = dnNormalize( 0, NULL, NULL, &bdn, &ndn, op->o_tmpmemctx ); + if ( rc != LDAP_SUCCESS ) { + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto done; } } @@ -126,7 +232,101 @@ vc_exop( goto done; } + if ( !BER_BVISNULL( &cookie ) ) { + vc_conn_t tmp = { 0 }; + + AC_MEMCPY( (char *)&tmp.conn, (const char *)cookie.bv_val, cookie.bv_len ); + ldap_pvt_mutex_lock( &vc_mutex ); + conn = (vc_conn_t *)avl_find( vc_tree, (caddr_t)&tmp, vc_conn_cmp ); + if ( conn == NULL || ( conn != NULL && conn->refcnt != 0 ) ) { + ldap_pvt_mutex_unlock( &vc_mutex ); + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto done; + } + conn->refcnt++; + ldap_pvt_mutex_unlock( &vc_mutex ); + + } else { + void *thrctx; + + conn = (vc_conn_t *)SLAP_MALLOC( sizeof( vc_conn_t ) ); + conn->refcnt = 1; + + thrctx = ldap_pvt_thread_pool_context(); + connection_fake_init2( &conn->connbuf, &conn->opbuf, thrctx, 1 ); + conn->op = &conn->opbuf.ob_op; + } + + conn->op->o_tag = LDAP_REQ_BIND; + memset( &conn->op->oq_bind, 0, sizeof( conn->op->oq_bind ) ); + conn->op->o_req_dn = ndn; + conn->op->o_req_ndn = ndn; + conn->op->o_protocol = LDAP_VERSION3; + conn->op->orb_method = authtag; + conn->op->o_callback = ≻ + + switch ( authtag ) { + case LDAP_AUTH_SIMPLE: + sc.sc_response = slap_null_cb; + break; + + case LDAP_AUTH_SASL: + conn->op->orb_mech = mechanism; + sc.sc_response = vc_exop_sasl_cb; + sc.sc_private = &sasldata; + break; + } + conn->op->orb_cred = cred; + + conn->op->o_bd = frontendDB; + rs->sr_err = frontendDB->be_bind( conn->op, &rs2 ); + + if ( conn->op->o_conn->c_sasl_bind_in_progress ) { + vc_create_response( conn, + !BER_BVISEMPTY( &sasldata ) ? &sasldata : NULL, + NULL, &rs->sr_rspdata ); + } else { + vc_create_response( NULL, NULL, + &conn->op->o_conn->c_dn, &rs->sr_rspdata ); + } + + if ( !BER_BVISNULL( &conn->op->o_conn->c_dn ) && + conn->op->o_conn->c_dn.bv_val != conn->op->o_conn->c_ndn.bv_val ) + ber_memfree( conn->op->o_conn->c_dn.bv_val ); + if ( !BER_BVISNULL( &conn->op->o_conn->c_ndn ) ) + ber_memfree( conn->op->o_conn->c_ndn.bv_val ); + + if ( conn->op->o_conn->c_sasl_bind_in_progress ) { + if ( conn->conn == NULL ) { + conn->conn = conn; + conn->refcnt--; + ldap_pvt_mutex_lock( &vc_mutex ); + rc = avl_insert( &vc_tree, (caddr_t)conn, + vc_conn_cmp, vc_conn_dup ); + ldap_pvt_mutex_unlock( &vc_mutex ); + assert( rc == 0 ); + + } else { + ldap_pvt_mutex_lock( &vc_mutex ); + conn->refcnt--; + ldap_pvt_mutex_unlock( &vc_mutex ); + } + + } else { + if ( conn->conn != NULL ) { + vc_conn_t *tmp; + + ldap_pvt_mutex_lock( &vc_mutex ); + tmp = avl_delete( &vc_tree, (caddr_t)conn, vc_conn_cmp ); + ldap_pvt_mutex_unlock( &vc_mutex ); + } + SLAP_FREE( conn ); + } + done:; + if ( !BER_BVISNULL( &ndn ) ) { + op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx ); + } op->o_tmpfree( reqdata.bv_val, op->o_tmpmemctx ); return rs->sr_err; @@ -145,6 +345,8 @@ vc_initialize( void ) rc, 0, 0 ); } + ldap_pvt_thread_mutex_init( &vc_mutex ); + return rc; } -- 2.39.5