]> git.sur5r.net Git - openldap/commitdiff
fix potential deadlock; improve idassert in case of authzFrom rules (new flag values...
authorPierangelo Masarati <ando@openldap.org>
Sun, 3 Jul 2005 23:27:56 +0000 (23:27 +0000)
committerPierangelo Masarati <ando@openldap.org>
Sun, 3 Jul 2005 23:27:56 +0000 (23:27 +0000)
servers/slapd/back-ldap/back-ldap.h
servers/slapd/back-ldap/bind.c
servers/slapd/back-ldap/config.c
servers/slapd/back-ldap/init.c
servers/slapd/back-ldap/unbind.c

index ba965d5d853dc7d94e54fc11f23f2fffe98d3fd8..d33ea3c1830f28e2bfbb14e443babba5cfb3843f 100644 (file)
@@ -85,6 +85,7 @@ struct ldapinfo {
 #define LDAP_BACK_AUTH_NONE            0x00U
 #define        LDAP_BACK_AUTH_NATIVE_AUTHZ     0x01U
 #define        LDAP_BACK_AUTH_OVERRIDE         0x02U
+#define        LDAP_BACK_AUTH_PRESCRIPTIVE     0x04U
 
        BerVarray       idassert_authz;
        /* end of ID assert stuff */
index 75124c07b7227b2e29e6e36e8833822a79f28f6d..281fd9a987c000e168c4d82f43e190830e213d44 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <stdio.h>
 
+#include <ac/errno.h>
 #include <ac/socket.h>
 #include <ac/string.h>
 
@@ -103,13 +104,23 @@ done:;
        if ( lc->lc_bound && !dn_match( &op->o_req_ndn, &lc->lc_local_ndn ) ) {
                int             lerr;
 
-               ldap_pvt_thread_mutex_lock( &li->conn_mutex );
                /* wait for all other ops to release the connection */
-               while ( lc->lc_refcnt > 1 ) {
-                       ldap_pvt_thread_mutex_unlock( &li->conn_mutex );
+retry_lock:;
+               switch ( ldap_pvt_thread_mutex_trylock( &li->conn_mutex ) ) {
+               case LDAP_PVT_THREAD_EBUSY:
+               default:
                        ldap_pvt_thread_yield();
-                       ldap_pvt_thread_mutex_lock( &li->conn_mutex );
+                       goto retry_lock;
+
+               case 0:
+                       if ( lc->lc_refcnt > 1 ) {
+                               ldap_pvt_thread_mutex_unlock( &li->conn_mutex );
+                               ldap_pvt_thread_yield();
+                               goto retry_lock;
+                       }
+                       break;
                }
+
                assert( lc->lc_refcnt == 1 );
                lc = avl_delete( &li->conntree, (caddr_t)lc,
                                ldap_back_conn_cmp );
@@ -229,7 +240,17 @@ ldap_back_freeconn( Operation *op, struct ldapconn *lc )
        struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private;
        int             rc = 0;
 
-       ldap_pvt_thread_mutex_lock( &li->conn_mutex );
+retry_lock:;
+       switch ( ldap_pvt_thread_mutex_trylock( &li->conn_mutex ) ) {
+       case LDAP_PVT_THREAD_EBUSY:
+       default:
+               ldap_pvt_thread_yield();
+               goto retry_lock;
+
+       case 0:
+               break;
+       }
+
        assert( lc->lc_refcnt > 0 );
        if ( --lc->lc_refcnt == 0 ) {
                lc = avl_delete( &li->conntree, (caddr_t)lc,
@@ -411,7 +432,17 @@ ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok )
                lc_curr.lc_local_ndn = op->o_ndn;
        }
 
-       ldap_pvt_thread_mutex_lock( &li->conn_mutex );
+retry_lock:;
+       switch ( ldap_pvt_thread_mutex_trylock( &li->conn_mutex ) ) {
+       case LDAP_PVT_THREAD_EBUSY:
+       default:
+               ldap_pvt_thread_yield();
+               goto retry_lock;
+
+       case 0:
+               break;
+       }
+
        lc = (struct ldapconn *)avl_find( li->conntree, 
                        (caddr_t)&lc_curr, ldap_back_conn_cmp );
        if ( lc != NULL ) {
@@ -449,7 +480,17 @@ ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok )
                lc->lc_bound = 0;
 
                /* Inserts the newly created ldapconn in the avl tree */
-               ldap_pvt_thread_mutex_lock( &li->conn_mutex );
+retry_lock2:;
+               switch ( ldap_pvt_thread_mutex_trylock( &li->conn_mutex ) ) {
+               case LDAP_PVT_THREAD_EBUSY:
+               default:
+                       ldap_pvt_thread_yield();
+                       goto retry_lock2;
+
+               case 0:
+                       break;
+               }
+
                assert( lc->lc_refcnt == 1 );
                rs->sr_err = avl_insert( &li->conntree, (caddr_t)lc,
                        ldap_back_conn_cmp, ldap_back_conn_dup );
@@ -470,10 +511,11 @@ ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok )
                        rs->sr_err = LDAP_OTHER;
                        if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
                                send_ldap_error( op, rs, LDAP_OTHER,
-                               "internal server error" );
+                                       "internal server error" );
                        }
                        return NULL;
                }
+
        } else {
                Debug( LDAP_DEBUG_TRACE,
                        "=>ldap_back_getconn: conn %p fetched (refcnt=%u)\n",
@@ -490,8 +532,18 @@ ldap_back_release_conn(
        struct ldapconn         *lc )
 {
        struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private;
-       
-       ldap_pvt_thread_mutex_lock( &li->conn_mutex );
+
+retry_lock:;
+       switch ( ldap_pvt_thread_mutex_trylock( &li->conn_mutex ) ) {
+       case LDAP_PVT_THREAD_EBUSY:
+       default:
+               ldap_pvt_thread_yield();
+               goto retry_lock;
+
+       case 0:
+               break;
+       }
+
        assert( lc->lc_refcnt > 0 );
        lc->lc_refcnt--;
        ldap_pvt_thread_mutex_unlock( &li->conn_mutex );
@@ -544,7 +596,6 @@ ldap_back_dobind_int(
                 */
                if ( op->o_conn != NULL &&
                                !op->o_do_not_cache &&
-                               !be_isroot( op ) &&
                                ( BER_BVISNULL( &lc->lc_bound_ndn ) ||
                                  ( li->idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
                {
@@ -605,7 +656,17 @@ retry:;
 
                if ( rs->sr_err == LDAP_SERVER_DOWN ) {
                        if ( retries > 0 ) {
-                               ldap_pvt_thread_mutex_lock( &li->conn_mutex );
+retry_lock:;
+                               switch ( ldap_pvt_thread_mutex_trylock( &li->conn_mutex ) ) {
+                               case LDAP_PVT_THREAD_EBUSY:
+                               default:
+                                       ldap_pvt_thread_yield();
+                                       goto retry_lock;
+
+                               case 0:
+                                       break;
+                               }
+
                                assert( lc->lc_refcnt > 0 );
                                if ( lc->lc_refcnt == 1 ) {
                                        ldap_unbind_ext_s( lc->lc_ld, NULL, NULL );
@@ -763,7 +824,16 @@ ldap_back_retry( struct ldapconn *lc, Operation *op, SlapReply *rs, ldap_back_se
        int             rc = 0;
        struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private;
        
-       ldap_pvt_thread_mutex_lock( &li->conn_mutex );
+retry_lock:;
+       switch ( ldap_pvt_thread_mutex_trylock( &li->conn_mutex ) ) {
+       case LDAP_PVT_THREAD_EBUSY:
+       default:
+               ldap_pvt_thread_yield();
+               goto retry_lock;
+
+       case 0:
+               break;
+       }
 
        if ( lc->lc_refcnt == 1 ) {
                ldap_pvt_thread_mutex_lock( &lc->lc_mutex );
@@ -830,19 +900,30 @@ ldap_back_proxy_authz_bind( struct ldapconn *lc, Operation *op, SlapReply *rs )
                break;
 
        default:
-               if ( li->idassert_authz ) {
+               /* NOTE: rootdn can always idassert */
+               if ( li->idassert_authz && !be_isroot( op ) ) {
                        struct berval authcDN;
 
                        if ( BER_BVISNULL( &op->o_conn->c_ndn ) ) {
                                authcDN = slap_empty_bv;
+
                        } else {
                                authcDN = op->o_conn->c_ndn;
                        }       
                        rs->sr_err = slap_sasl_matches( op, li->idassert_authz,
                                        &authcDN, &authcDN );
                        if ( rs->sr_err != LDAP_SUCCESS ) {
-                               send_ldap_result( op, rs );
-                               lc->lc_bound = 0;
+                               if ( li->idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
+                                       send_ldap_result( op, rs );
+                                       lc->lc_bound = 0;
+
+                               } else {
+                                       rs->sr_err = LDAP_SUCCESS;
+                                       binddn = slap_empty_bv;
+                                       bindcred = slap_empty_bv;
+                                       break;
+                               }
+
                                goto done;
                        }
                }
@@ -1055,7 +1136,7 @@ ldap_back_proxy_authz_ctrl(
                        goto done;
                }
 
-       } else if ( li->idassert_authz ) {
+       } else if ( li->idassert_authz && !be_isroot( op ) ) {
                int             rc;
                struct berval authcDN;
 
@@ -1067,9 +1148,12 @@ ldap_back_proxy_authz_ctrl(
                rc = slap_sasl_matches( op, li->idassert_authz,
                                &authcDN, & authcDN );
                if ( rc != LDAP_SUCCESS ) {
-                       /* op->o_conn->c_ndn is not authorized
-                        * to use idassert */
-                       return rc;
+                       if ( li->idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
+                               /* op->o_conn->c_ndn is not authorized
+                                * to use idassert */
+                               return rc;
+                       }
+                       return rs->sr_err;
                }
        }
 
index 27876cbfecf8001349479edeeec074ae36519c1c..16e1cd0a5c3674f57cedfba9ed86ac6d2db742f9 100644 (file)
@@ -362,6 +362,9 @@ ldap_back_cf_gen( ConfigArgs *c )
                        char            *ptr;
 
                        if ( li->idassert_authmethod != LDAP_AUTH_NONE ) {
+                               ber_len_t       len = bv.bv_len
+                                       + STRLENOF( "flags=override,non-prescriptive" );
+
                                switch ( li->idassert_mode ) {
                                case LDAP_BACK_IDASSERT_OTHERID:
                                case LDAP_BACK_IDASSERT_OTHERDN:
@@ -405,26 +408,34 @@ ldap_back_cf_gen( ConfigArgs *c )
                                        (void)lutil_strcopy( ptr, "authz=native" );
                                }
 
-                               if ( li->idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
-                                       ber_len_t       len = bv.bv_len + STRLENOF( "flags=override" );
+                               /* flags */
+                               if ( !BER_BVISEMPTY( &bv ) ) {
+                                       len += STRLENOF( " " );
+                               }
 
-                                       if ( !BER_BVISEMPTY( &bv ) ) {
-                                               len += STRLENOF( " " );
-                                       }
+                               bv.bv_val = ch_realloc( bv.bv_val, len + 1 );
 
-                                       bv.bv_val = ch_realloc( bv.bv_val, len + 1 );
+                               ptr = &bv.bv_val[ bv.bv_len ];
 
-                                       ptr = bv.bv_val + bv.bv_len;
+                               if ( !BER_BVISEMPTY( &bv ) ) {
+                                       ptr = lutil_strcopy( ptr, " " );
+                               }
 
-                                       if ( !BER_BVISEMPTY( &bv ) ) {
-                                               ptr = lutil_strcopy( ptr, " " );
-                                       }
+                               ptr = lutil_strcopy( ptr, "flags=" );
 
-                                       (void)lutil_strcopy( ptr, "flags=override" );
+                               if ( li->idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
+                                       ptr = lutil_strcopy( ptr, "prescriptive" );
+                               } else {
+                                       ptr = lutil_strcopy( ptr, "non-prescriptive" );
                                }
-                       }
 
+                               if ( li->idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
+                                       ptr = lutil_strcopy( ptr, ",override" );
+                               }
 
+                               bv.bv_len = ( ptr - bv.bv_val );
+                               /* end-of-flags */
+                       }
 
                        bindconf_unparse( &li->idassert_sb, &bc );
 
@@ -824,6 +835,12 @@ ldap_back_cf_gen( ConfigArgs *c )
                                if ( strcasecmp( c->argv[ i ], "override" ) == 0 ) {
                                        li->idassert_flags |= LDAP_BACK_AUTH_OVERRIDE;
 
+                               } else if ( strcasecmp( c->argv[ i ], "prescriptive" ) == 0 ) {
+                                       li->idassert_flags |= LDAP_BACK_AUTH_PRESCRIPTIVE;
+
+                               } else if ( strcasecmp( c->argv[ i ], "non-prescriptive" ) == 0 ) {
+                                       li->idassert_flags &= ( ~LDAP_BACK_AUTH_PRESCRIPTIVE );
+
                                } else {
                                        Debug( LDAP_DEBUG_ANY,
                                                "%s: line %d: unknown flag #%d "
@@ -951,6 +968,12 @@ ldap_back_cf_gen( ConfigArgs *c )
                                        if ( strcasecmp( flags[ j ], "override" ) == 0 ) {
                                                li->idassert_flags |= LDAP_BACK_AUTH_OVERRIDE;
 
+                                       } else if ( strcasecmp( flags[ j ], "prescriptive" ) == 0 ) {
+                                               li->idassert_flags |= LDAP_BACK_AUTH_PRESCRIPTIVE;
+
+                                       } else if ( strcasecmp( flags[ j ], "non-prescriptive" ) == 0 ) {
+                                               li->idassert_flags &= ( ~LDAP_BACK_AUTH_PRESCRIPTIVE );
+
                                        } else {
                                                fprintf( stderr, "%s: %d: "
                                                        "\"idassert-bind <args>\": "
index b572c36936b73c214ec4970cb00382d7d0b85617..49837a167f62d8b6334e5295d2b108dbac3d2916 100644 (file)
@@ -108,7 +108,7 @@ ldap_back_db_init( Backend *be )
        li->idassert_sb.sb_tls = SB_TLS_DEFAULT;
 
        /* by default, use proxyAuthz control on each operation */
-       li->idassert_flags = LDAP_BACK_AUTH_NONE;
+       li->idassert_flags = LDAP_BACK_AUTH_PRESCRIPTIVE;
 
        li->idassert_authz = NULL;
 
index c35d2834c295b0bdfbca6fe0fa328c3e99340d89..aa699342b6aa97f41f4dd4514d50bf38146d7316 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <stdio.h>
 
+#include <ac/errno.h>
 #include <ac/socket.h>
 #include <ac/string.h>
 
@@ -47,7 +48,17 @@ ldap_back_conn_destroy(
        lc_curr.lc_conn = conn;
        lc_curr.lc_local_ndn = conn->c_ndn;
        
-       ldap_pvt_thread_mutex_lock( &li->conn_mutex );
+retry_lock:;
+       switch ( ldap_pvt_thread_mutex_trylock( &li->conn_mutex ) ) {
+       case LDAP_PVT_THREAD_EBUSY:
+       default:
+               ldap_pvt_thread_yield();
+               goto retry_lock;
+
+       case 0:
+               break;
+       }
+
        lc = avl_delete( &li->conntree, (caddr_t)&lc_curr, ldap_back_conn_cmp );
        ldap_pvt_thread_mutex_unlock( &li->conn_mutex );