]> git.sur5r.net Git - openldap/commitdiff
also works for multi-stage binds (ITS#6771; needs ITS#6773 patch)
authorPierangelo Masarati <ando@openldap.org>
Tue, 4 Jan 2011 16:19:51 +0000 (16:19 +0000)
committerPierangelo Masarati <ando@openldap.org>
Tue, 4 Jan 2011 16:19:51 +0000 (16:19 +0000)
contrib/slapd-modules/authzid/authzid.c

index ef9d6d87a6a3d2ceff96e91ea36b5252432e2c42..2a028ad0d6ad1e6efa4e8135a7cac79d2743854b 100644 (file)
 #include "lutil.h"
 #include "ac/string.h"
 
+typedef struct ConnExtraAuthzID {
+       ConnExtra ce;
+       char authzid_flag;
+} ConnExtraAuthzID;
+
 static int authzid_cid;
+static slap_overinst authzid;
+
+static ConnExtraAuthzID *
+authzid_extra_find( Connection *c )
+{
+       ConnExtra *cex;
+
+       LDAP_SLIST_FOREACH( cex, &c->c_extra, ce_next ) {
+               if ( cex->ce_key == (void *)&authzid_cid )
+                       break;
+       }
+
+       return (ConnExtraAuthzID *)cex;
+}
+
+static ConnExtraAuthzID *
+authzid_extra_insert( Connection *c )
+{
+       ConnExtraAuthzID *cex;
+
+       cex = SLAP_CALLOC( 1, sizeof( ConnExtraAuthzID ) );
+       cex->ce.ce_key = (void *)&authzid_cid;
+
+       LDAP_SLIST_INSERT_HEAD( &c->c_extra, &cex->ce, ce_next );
+
+       return cex;
+}
+
+static int
+authzid_extra_remove( Connection *c )
+{
+       ConnExtra *cex;
+       int found = 0;
+
+       cex = (ConnExtra *)authzid_extra_find( c );
+       if ( cex ) {
+               found = 1;
+               LDAP_SLIST_REMOVE( &c->c_extra, cex, ConnExtra, ce_next );
+               SLAP_FREE( cex );
+       }
+
+       return found;
+}
 
 static int
 authzid_response(
        Operation *op,
        SlapReply *rs )
 {
-       if ( rs->sr_tag == LDAP_RES_BIND ) {
-               LDAPControl **ctrls;
-               ber_len_t len = 0;
-               int n = 0;
+       ConnExtraAuthzID *cex;
+       LDAPControl **ctrls;
+       struct berval edn = BER_BVNULL;
+       ber_len_t len = 0;
+       int n = 0;
+
+       assert( rs->sr_tag = LDAP_RES_BIND );
+
+       cex = authzid_extra_find( op->o_conn );
+       if ( rs->sr_err == LDAP_SASL_BIND_IN_PROGRESS ) {
+               if ( !cex ) {
+                       cex = authzid_extra_insert( op->o_conn );
+                       cex->authzid_flag = op->o_ctrlflag[ authzid_cid ];
+               }
 
-               /* TEMPORARY! */
-               if ( rs->sr_err == LDAP_SASL_BIND_IN_PROGRESS ) {
-                       if ( op->o_ctrlflag[ authzid_cid ] == SLAP_CONTROL_CRITICAL ) {
-                               return rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
-                       }
+               return SLAP_CB_CONTINUE;
 
-                       op->o_ctrlflag[ authzid_cid ] = SLAP_CONTROL_IGNORED;
+       }
 
-                       return SLAP_CB_CONTINUE;
-               }
-               /* end of TEMPORARY! */
+       if ( cex ) {
+               authzid_extra_remove( op->o_conn );
+       }
 
-               if ( rs->sr_err != LDAP_SUCCESS ) {
-                       return SLAP_CB_CONTINUE;
-               }
+       if ( rs->sr_err != LDAP_SUCCESS ) {
+               return SLAP_CB_CONTINUE;
+       }
 
-               if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) ) {
-                       len = STRLENOF("dn:") + op->o_conn->c_dn.bv_len;
-               }
+       if ( !BER_BVISEMPTY( &op->orb_edn ) ) {
+               edn = op->orb_edn;
+       } else if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) ) {
+               edn = op->o_conn->c_dn;
+       }
 
-               /* save original controls in sc_private;
-                * will be restored by sc_cleanup
-                */
-               if ( rs->sr_ctrls != NULL ) {
-                       op->o_callback->sc_private = rs->sr_ctrls;
-                       for ( ; rs->sr_ctrls[n] != NULL; n++ )
-                               ;
-               }
+       if ( !BER_BVISEMPTY( &edn ) ) {
+               len = STRLENOF("dn:") + edn.bv_len;
+       }
 
-               ctrls = op->o_tmpalloc( sizeof( LDAPControl * )*( n + 2 ), op->o_tmpmemctx );
-               n = 0;
-               if ( rs->sr_ctrls ) {
-                       for ( ; rs->sr_ctrls[n] != NULL; n++ ) {
-                               ctrls[n] = rs->sr_ctrls[n];
-                       }
-               }
+       /* save original controls in sc_private;
+        * will be restored by sc_cleanup
+        */
+       if ( rs->sr_ctrls != NULL ) {
+               op->o_callback->sc_private = rs->sr_ctrls;
+               for ( ; rs->sr_ctrls[n] != NULL; n++ )
+                       ;
+       }
 
-               /* anonymous: "", otherwise "dn:<dn>" */
-               ctrls[n] = op->o_tmpalloc( sizeof( LDAPControl ) + len + 1, op->o_tmpmemctx );
-               ctrls[n]->ldctl_oid = LDAP_CONTROL_AUTHZID_RESPONSE;
-               ctrls[n]->ldctl_iscritical = 0;
-               ctrls[n]->ldctl_value.bv_len = len;
-               ctrls[n]->ldctl_value.bv_val = (char *)&ctrls[n][1];
-               if ( len ) {
-                       char *ptr;
-
-                       ptr = lutil_strcopy( ctrls[n]->ldctl_value.bv_val, "dn:" );
-                       ptr = lutil_strncopy( ptr, op->o_conn->c_dn.bv_val, op->o_conn->c_dn.bv_len );
+       ctrls = op->o_tmpalloc( sizeof( LDAPControl * )*( n + 2 ), op->o_tmpmemctx );
+       n = 0;
+       if ( rs->sr_ctrls ) {
+               for ( ; rs->sr_ctrls[n] != NULL; n++ ) {
+                       ctrls[n] = rs->sr_ctrls[n];
                }
-               ctrls[n]->ldctl_value.bv_val[len] = '\0';
-               ctrls[n + 1] = NULL;
+       }
 
-               rs->sr_ctrls = ctrls;
+       /* anonymous: "", otherwise "dn:<dn>" */
+       ctrls[n] = op->o_tmpalloc( sizeof( LDAPControl ) + len + 1, op->o_tmpmemctx );
+       ctrls[n]->ldctl_oid = LDAP_CONTROL_AUTHZID_RESPONSE;
+       ctrls[n]->ldctl_iscritical = 0;
+       ctrls[n]->ldctl_value.bv_len = len;
+       ctrls[n]->ldctl_value.bv_val = (char *)&ctrls[n][1];
+       if ( len ) {
+               char *ptr;
+
+               ptr = lutil_strcopy( ctrls[n]->ldctl_value.bv_val, "dn:" );
+               ptr = lutil_strncopy( ptr, edn.bv_val, edn.bv_len );
        }
+       ctrls[n]->ldctl_value.bv_val[len] = '\0';
+       ctrls[n + 1] = NULL;
+
+       rs->sr_ctrls = ctrls;
 
        return SLAP_CB_CONTINUE;
 }
@@ -125,14 +184,38 @@ authzid_cleanup(
        return SLAP_CB_CONTINUE;
 }
 
+static int
+authzid_op_bind(
+       Operation *op,
+       SlapReply *rs )
+{
+       slap_callback *sc;
+
+       if ( op->o_ctrlflag[ authzid_cid ] <= SLAP_CONTROL_IGNORED ) {
+               ConnExtraAuthzID *cex = authzid_extra_find( op->o_conn );
+               if ( cex ) {
+                       op->o_ctrlflag[ authzid_cid ] = cex->authzid_flag;
+               }
+       }
+
+       if ( op->o_ctrlflag[ authzid_cid ] > SLAP_CONTROL_IGNORED ) {
+               sc = op->o_callback;
+               op->o_callback = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx );
+               op->o_callback->sc_response = authzid_response;
+               op->o_callback->sc_cleanup = authzid_cleanup;
+               op->o_callback->sc_private = NULL;
+               op->o_callback->sc_next = sc;
+       }
+
+       return SLAP_CB_CONTINUE;
+}
+
 static int
 parse_authzid_ctrl(
        Operation       *op,
        SlapReply       *rs,
        LDAPControl     *ctrl )
 {
-       slap_callback *sc;
-
        if ( op->o_ctrlflag[ authzid_cid ] != SLAP_CONTROL_NONE ) {
                rs->sr_text = "authzid control specified multiple times";
                return LDAP_PROTOCOL_ERROR;
@@ -143,34 +226,62 @@ parse_authzid_ctrl(
                return LDAP_PROTOCOL_ERROR;
        }
 
+       /* drop ongoing requests */
+       (void)authzid_extra_remove( op->o_conn );
+
        op->o_ctrlflag[ authzid_cid ] = ctrl->ldctl_iscritical ?  SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
 
-       sc = op->o_callback;
-       op->o_callback = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx );
-       op->o_callback->sc_response = authzid_response;
-       op->o_callback->sc_cleanup = authzid_cleanup;
-       op->o_callback->sc_private = NULL;
-       op->o_callback->sc_next = sc;
+       return LDAP_SUCCESS;
+}
+
+static int authzid_cnt;
+
+static int
+authzid_db_init( BackendDB *be, ConfigReply *cr)
+{
+       if ( authzid_cnt++ == 0 ) {
+               int rc;
+
+               rc = register_supported_control( LDAP_CONTROL_AUTHZID_REQUEST,
+                       SLAP_CTRL_GLOBAL|SLAP_CTRL_BIND|SLAP_CTRL_HIDE, NULL,
+                       parse_authzid_ctrl, &authzid_cid );
+               if ( rc != LDAP_SUCCESS ) {
+                       Debug( LDAP_DEBUG_ANY,
+                               "authzid_initialize: Failed to register control '%s' (%d)\n",
+                               LDAP_CONTROL_AUTHZID_REQUEST, rc, 0 );
+                       return rc;
+               }
+       }
 
        return LDAP_SUCCESS;
 }
 
 static int
-authzid_initialize( void )
+authzid_db_destroy( BackendDB *be, ConfigReply *cr )
 {
-       int rc;
+       assert( authzid_cnt > 0 );
 
-       rc = register_supported_control( LDAP_CONTROL_AUTHZID_REQUEST,
-               SLAP_CTRL_GLOBAL|SLAP_CTRL_BIND|SLAP_CTRL_HIDE, NULL,
-               parse_authzid_ctrl, &authzid_cid );
-       if ( rc != LDAP_SUCCESS ) {
-               Debug( LDAP_DEBUG_ANY,
-                       "authzid_initialize: failed to register control %s (%d)\n",
-                       LDAP_CONTROL_AUTHZID_REQUEST, rc, 0 );
-               return rc;
+#ifdef SLAP_CONFIG_DELETE
+       overlay_unregister_control( be, LDAP_CONTROL_AUTHZID_REQUEST );
+#endif /* SLAP_CONFIG_DELETE */
+
+       if ( --authzid_cnt == 0 ) {
+               unregister_supported_control( LDAP_CONTROL_AUTHZID_REQUEST );
        }
 
-       return rc;
+       return 0;
+}
+
+static int
+authzid_initialize( void )
+{
+       authzid.on_bi.bi_type = "authzid";
+
+       authzid.on_bi.bi_db_init = authzid_db_init;
+       authzid.on_bi.bi_db_destroy = authzid_db_destroy;
+       authzid.on_bi.bi_op_bind = authzid_op_bind;
+
+       return overlay_register( &authzid );
 }
 
 int