]> git.sur5r.net Git - openldap/commitdiff
should also work for SASL binds (whenever supported)
authorPierangelo Masarati <ando@openldap.org>
Thu, 30 Dec 2010 21:41:36 +0000 (21:41 +0000)
committerPierangelo Masarati <ando@openldap.org>
Thu, 30 Dec 2010 21:41:36 +0000 (21:41 +0000)
contrib/slapd-modules/vc/vc.c

index 7179bb5357eae125f764d4f3452ce5e4463c79e9..a5f41bfd74a04b3b39ddde03a7b86e47de545985 100644 (file)
 #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 = &sc;
+
+       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;
 }