]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/acl.c
check for NULL backend (ITS#6490)
[openldap] / servers / slapd / acl.c
index 6243a3edf68210d9333a2be111c227fc5707581d..bbd89fbd3812edaddc6b3c644ae21bb4d33d7f73 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1998-2008 The OpenLDAP Foundation.
+ * Copyright 1998-2009 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -53,6 +53,7 @@ static AccessControl * slap_acl_get(
        AttributeDescription *desc,
        struct berval *val,
        AclRegexMatches *matches,
+       slap_mask_t *mask,
        AccessControlState *state );
 
 static slap_control_t slap_acl_mask(
@@ -66,7 +67,8 @@ static slap_control_t slap_acl_mask(
        slap_access_t access );
 
 static int     regex_matches(
-       struct berval *pat, char *str, char *buf,
+       struct berval *pat, char *str,
+       struct berval *dn_matches, struct berval *val_matches,
        AclRegexMatches *matches);
 
 typedef        struct AclSetCookie {
@@ -150,6 +152,7 @@ slap_access_allowed(
        const char                      *attr;
        AclRegexMatches                 matches;
        AccessControlState              acl_state = ACL_STATE_INIT;
+       static AccessControlState       state_init = ACL_STATE_INIT;
 
        assert( op != NULL );
        assert( e != NULL );
@@ -215,25 +218,27 @@ slap_access_allowed(
 
        if ( state == NULL )
                state = &acl_state;
-       if ( state->as_vd_ad == desc ) {
+       if ( state->as_desc == desc &&
+               state->as_access == access &&
+               state->as_vd_acl != NULL )
+       {
                a = state->as_vd_acl;
                count = state->as_vd_acl_count;
                if ( state->as_fe_done )
                        state->as_fe_done--;
+               ACL_PRIV_ASSIGN( mask, state->as_vd_mask );
        } else {
-               state->as_vi_acl = NULL;
+               *state = state_init;
 
                a = NULL;
                count = 0;
+               ACL_PRIV_ASSIGN( mask, *maskp );
        }
-       if ( a == NULL )
-               state->as_fe_done = 0;
 
-       ACL_PRIV_ASSIGN( mask, *maskp );
        MATCHES_MEMSET( &matches );
 
        while ( ( a = slap_acl_get( a, &count, op, e, desc, val,
-               &matches, state ) ) != NULL )
+               &matches, &mask, state ) ) != NULL )
        {
                int i; 
                int dnmaxcount = MATCHES_DNMAXCOUNT( &matches );
@@ -243,10 +248,9 @@ slap_access_allowed(
 
                /* DN matches */
                for ( i = 0; i < dnmaxcount && dn_data[i].rm_eo > 0; i++ ) {
-                       char *debugmsg = "=> match[dn%d]: %d %d ";
                        char *data = e->e_ndn;
 
-                       Debug( LDAP_DEBUG_ACL, debugmsg, i,
+                       Debug( LDAP_DEBUG_ACL, "=> match[dn%d]: %d %d ", i,
                                (int)dn_data[i].rm_so, 
                                (int)dn_data[i].rm_eo );
                        if ( dn_data[i].rm_so <= dn_data[0].rm_eo ) {
@@ -262,10 +266,9 @@ slap_access_allowed(
 
                /* val matches */
                for ( i = 0; i < valmaxcount && val_data[i].rm_eo > 0; i++ ) {
-                       char *debugmsg = "=> match[val%d]: %d %d ";
                        char *data = val->bv_val;
 
-                       Debug( LDAP_DEBUG_ACL, debugmsg, i,
+                       Debug( LDAP_DEBUG_ACL, "=> match[val%d]: %d %d ", i,
                                (int)val_data[i].rm_so, 
                                (int)val_data[i].rm_eo );
                        if ( val_data[i].rm_so <= val_data[0].rm_eo ) {
@@ -279,22 +282,6 @@ slap_access_allowed(
                        Debug( LDAP_DEBUG_ACL, "\n", 0, 0, 0 );
                }
 
-               if ( state ) {
-                       if ( state->as_vi_acl == a &&
-                               ( state->as_recorded & ACL_STATE_RECORDED_NV ) )
-                       {
-                               Debug( LDAP_DEBUG_ACL,
-                                       "=> slap_access_allowed: result was in cache (%s)\n",
-                                       attr, 0, 0 );
-                               ret = state->as_result;
-                               goto done;
-                       } else {
-                               Debug( LDAP_DEBUG_ACL,
-                                       "=> slap_access_allowed: result not in cache (%s)\n",
-                                       attr, 0, 0 );
-                       }
-               }
-
                control = slap_acl_mask( a, &mask, op,
                        e, desc, val, &matches, count, state, access );
 
@@ -375,7 +362,6 @@ access_allowed_mask(
        slap_mask_t             *maskp )
 {
        int                             ret = 1;
-       AccessControl                   *a = NULL;
        int                             be_null = 0;
 
 #ifdef LDAP_DEBUG
@@ -384,7 +370,6 @@ access_allowed_mask(
        slap_mask_t                     mask;
        slap_access_t                   access_level;
        const char                      *attr;
-       static AccessControlState       state_init = ACL_STATE_INIT;
 
        assert( e != NULL );
        assert( desc != NULL );
@@ -416,16 +401,20 @@ access_allowed_mask(
                }
        }
 
-       if ( state ) {
-               if ( state->as_vd_ad == desc ) {
-                       if ( ( state->as_recorded & ACL_STATE_RECORDED_NV ) &&
-                               val == NULL )
+       if ( state != NULL ) {
+               if ( state->as_desc == desc &&
+                       state->as_access == access &&
+                       state->as_result != -1 &&
+                       state->as_vd_acl == NULL )
                        {
+                       Debug( LDAP_DEBUG_ACL,
+                               "=> access_allowed: result was in cache (%s)\n",
+                               attr, 0, 0 );
                                return state->as_result;
-
-                       }
                } else {
-                       *state = state_init;
+                       Debug( LDAP_DEBUG_ACL,
+                               "=> access_allowed: result not in cache (%s)\n",
+                               attr, 0, 0 );
                }
        }
 
@@ -486,13 +475,9 @@ access_allowed_mask(
 
 done:
        if ( state != NULL ) {
-               /* If not value-dependent, save ACL in case of more attrs */
-               if ( !( state->as_recorded & ACL_STATE_RECORDED_VD ) ) {
-                       state->as_vi_acl = a;
+               state->as_access = access;
                        state->as_result = ret;
-               }
-               state->as_recorded |= ACL_STATE_RECORDED;
-               state->as_vd_ad = desc;
+               state->as_desc = desc;
        }
        if ( be_null ) op->o_bd = NULL;
        if ( maskp ) ACL_PRIV_ASSIGN( *maskp, mask );
@@ -515,10 +500,11 @@ slap_acl_get(
        AttributeDescription *desc,
        struct berval   *val,
        AclRegexMatches *matches,
+       slap_mask_t *mask,
        AccessControlState *state )
 {
        const char *attr;
-       int dnlen, patlen;
+       ber_len_t dnlen;
        AccessControl *prev;
 
        assert( e != NULL );
@@ -566,6 +552,8 @@ slap_acl_get(
                                        continue;
 
                        } else {
+                               ber_len_t patlen;
+
                                Debug( LDAP_DEBUG_ACL, "=> dn: [%d] %s\n", 
                                        *count, a->acl_dn_pat.bv_val, 0 );
                                patlen = a->acl_dn_pat.bv_len;
@@ -579,7 +567,7 @@ slap_acl_get(
 
                                } else if ( a->acl_dn_style == ACL_STYLE_ONE ) {
                                        ber_len_t       rdnlen = 0;
-                                       int             sep = 0;
+                                       ber_len_t       sep = 0;
 
                                        if ( dnlen <= patlen )
                                                continue;
@@ -591,7 +579,7 @@ slap_acl_get(
                                        }
 
                                        rdnlen = dn_rdnlen( NULL, &e->e_nname );
-                                       if ( rdnlen != dnlen - patlen - sep )
+                                       if ( rdnlen + patlen + sep != dnlen )
                                                continue;
 
                                } else if ( a->acl_dn_style == ACL_STYLE_SUBTREE ) {
@@ -627,19 +615,17 @@ slap_acl_get(
                                continue;
                        }
 
-                       if( !( state->as_recorded & ACL_STATE_RECORDED_VD )) {
-                               state->as_recorded |= ACL_STATE_RECORDED_VD;
+                       if ( state->as_vd_acl == NULL ) {
                                state->as_vd_acl = prev;
                                state->as_vd_acl_count = *count - 1;
+                               ACL_PRIV_ASSIGN ( state->as_vd_mask, *mask );
                        }
 
                        if ( a->acl_attrval_style == ACL_STYLE_REGEX ) {
-                               int rc;
-
                                Debug( LDAP_DEBUG_ACL,
                                        "acl_get: valpat %s\n",
                                        a->acl_attrval.bv_val, 0, 0 );
-                               if ( rc = regexec ( &a->acl_attrval_re, 
+                               if ( regexec ( &a->acl_attrval_re, 
                                                    val->bv_val, 
                                                    matches->val_count, 
                                                    matches->val_data, 0 ) )
@@ -662,7 +648,7 @@ slap_acl_get(
                                                continue;
                                        
                                } else {
-                                       int             patlen, vdnlen;
+                                       ber_len_t       patlen, vdnlen;
        
                                        patlen = a->acl_attrval.bv_len;
                                        vdnlen = val->bv_len;
@@ -681,7 +667,7 @@ slap_acl_get(
                                                        continue;
        
                                                rdnlen = dn_rdnlen( NULL, val );
-                                               if ( rdnlen != vdnlen - patlen - 1 )
+                                               if ( rdnlen + patlen + 1 != vdnlen )
                                                        continue;
        
                                        } else if ( a->acl_attrval_style == ACL_STYLE_SUBTREE ) {
@@ -728,10 +714,10 @@ slap_acl_get(
  * Record value-dependent access control state
  */
 #define ACL_RECORD_VALUE_STATE do { \
-               if( state && !( state->as_recorded & ACL_STATE_RECORDED_VD )) { \
-                       state->as_recorded |= ACL_STATE_RECORDED_VD; \
+               if( state && state->as_vd_acl == NULL ) { \
                        state->as_vd_acl = a; \
                        state->as_vd_acl_count = count; \
+                       ACL_PRIV_ASSIGN( state->as_vd_mask, *mask ); \
                } \
        } while( 0 )
 
@@ -739,7 +725,6 @@ static int
 acl_mask_dn(
        Operation               *op,
        Entry                   *e,
-       AttributeDescription    *desc,
        struct berval           *val,
        AccessControl           *a,
        AclRegexMatches         *matches,
@@ -804,7 +789,6 @@ acl_mask_dn(
                        AclRegexMatches tmp_matches,
                                        *tmp_matchesp = &tmp_matches;
                        int             rc = 0;
-                       int             dnoffset;
                        regmatch_t      *tmp_data;
 
                        MATCHES_MEMSET( &tmp_matches );
@@ -847,7 +831,7 @@ acl_mask_dn(
                        }
 
                        if ( !regex_matches( &bdn->a_pat, opndn->bv_val,
-                               e->e_ndn, tmp_matchesp ) )
+                               &e->e_nname, NULL, tmp_matchesp ) )
                        {
                                return 1;
                        }
@@ -914,8 +898,8 @@ acl_mask_dn(
                        }
 
                        if ( acl_string_expand( &bv, &bdn->a_pat, 
-                                               e->e_nname.bv_val
-                                               val->bv_val, tmp_matchesp ) )
+                                               &e->e_nname
+                                               val, tmp_matchesp ) )
                        {
                                return 1;
                        }
@@ -1025,11 +1009,9 @@ acl_mask_dnattr(
        Entry                   *e,
        struct berval           *val,
        AccessControl           *a,
-       Access                  *b,
-       int                     i,
-       AclRegexMatches         *matches,
        int                     count,
        AccessControlState      *state,
+       slap_mask_t                     *mask,
        slap_dn_access          *bdn,
        struct berval           *opndn )
 {
@@ -1140,7 +1122,9 @@ slap_acl_mask(
        char            accessmaskbuf[ACCESSMASK_MAXLEN];
 #endif /* DEBUG */
        const char      *attr;
+#ifdef SLAP_DYNACL
        slap_mask_t     a2pmask = ACL_ACCESS2PRIV( access );
+#endif /* SLAP_DYNACL */
 
        assert( a != NULL );
        assert( mask != NULL );
@@ -1185,7 +1169,7 @@ slap_acl_mask(
                         * is maintained in a_dn_pat.
                         */
 
-                       if ( acl_mask_dn( op, e, desc, val, a, matches,
+                       if ( acl_mask_dn( op, e, val, a, matches,
                                &b->a_dn, &op->o_ndn ) )
                        {
                                continue;
@@ -1216,7 +1200,7 @@ slap_acl_mask(
                                ndn = op->o_ndn;
                        }
 
-                       if ( acl_mask_dn( op, e, desc, val, a, matches,
+                       if ( acl_mask_dn( op, e, val, a, matches,
                                &b->a_realdn, &ndn ) )
                        {
                                continue;
@@ -1232,8 +1216,8 @@ slap_acl_mask(
 
                        if ( !ber_bvccmp( &b->a_sockurl_pat, '*' ) ) {
                                if ( b->a_sockurl_style == ACL_STYLE_REGEX) {
-                                       if (!regex_matches( &b->a_sockurl_pat, op->o_conn->c_listener_url.bv_val,
-                                                       e->e_ndn, matches ) ) 
+                                       if ( !regex_matches( &b->a_sockurl_pat, op->o_conn->c_listener_url.bv_val,
+                                                       &e->e_nname, val, matches ) ) 
                                        {
                                                continue;
                                        }
@@ -1244,7 +1228,7 @@ slap_acl_mask(
 
                                        bv.bv_len = sizeof( buf ) - 1;
                                        bv.bv_val = buf;
-                                       if ( acl_string_expand( &bv, &b->a_sockurl_pat, e->e_ndn, val->bv_val, matches ) )
+                                       if ( acl_string_expand( &bv, &b->a_sockurl_pat, &e->e_nname, val, matches ) )
                                        {
                                                continue;
                                        }
@@ -1271,8 +1255,8 @@ slap_acl_mask(
                                b->a_domain_pat.bv_val, 0, 0 );
                        if ( !ber_bvccmp( &b->a_domain_pat, '*' ) ) {
                                if ( b->a_domain_style == ACL_STYLE_REGEX) {
-                                       if (!regex_matches( &b->a_domain_pat, op->o_conn->c_peer_domain.bv_val,
-                                                       e->e_ndn, matches ) ) 
+                                       if ( !regex_matches( &b->a_domain_pat, op->o_conn->c_peer_domain.bv_val,
+                                                       &e->e_nname, val, matches ) ) 
                                        {
                                                continue;
                                        }
@@ -1288,7 +1272,7 @@ slap_acl_mask(
                                                bv.bv_len = sizeof(buf) - 1;
                                                bv.bv_val = buf;
 
-                                               if ( acl_string_expand(&bv, &b->a_domain_pat, e->e_ndn, val->bv_val, matches) )
+                                               if ( acl_string_expand(&bv, &b->a_domain_pat, &e->e_nname, val, matches) )
                                                {
                                                        continue;
                                                }
@@ -1325,8 +1309,8 @@ slap_acl_mask(
                                b->a_peername_pat.bv_val, 0, 0 );
                        if ( !ber_bvccmp( &b->a_peername_pat, '*' ) ) {
                                if ( b->a_peername_style == ACL_STYLE_REGEX ) {
-                                       if (!regex_matches( &b->a_peername_pat, op->o_conn->c_peer_name.bv_val,
-                                                       e->e_ndn, matches ) ) 
+                                       if ( !regex_matches( &b->a_peername_pat, op->o_conn->c_peer_name.bv_val,
+                                                       &e->e_nname, val, matches ) ) 
                                        {
                                                continue;
                                        }
@@ -1344,7 +1328,7 @@ slap_acl_mask(
 
                                                bv.bv_len = sizeof( buf ) - 1;
                                                bv.bv_val = buf;
-                                               if ( acl_string_expand( &bv, &b->a_peername_pat, e->e_ndn, val->bv_val, matches ) )
+                                               if ( acl_string_expand( &bv, &b->a_peername_pat, &e->e_nname, val, matches ) )
                                                {
                                                        continue;
                                                }
@@ -1477,8 +1461,8 @@ slap_acl_mask(
                                b->a_sockname_pat.bv_val, 0, 0 );
                        if ( !ber_bvccmp( &b->a_sockname_pat, '*' ) ) {
                                if ( b->a_sockname_style == ACL_STYLE_REGEX) {
-                                       if (!regex_matches( &b->a_sockname_pat, op->o_conn->c_sock_name.bv_val,
-                                                       e->e_ndn, matches ) ) 
+                                       if ( !regex_matches( &b->a_sockname_pat, op->o_conn->c_sock_name.bv_val,
+                                                       &e->e_nname, val, matches ) ) 
                                        {
                                                continue;
                                        }
@@ -1489,7 +1473,7 @@ slap_acl_mask(
 
                                        bv.bv_len = sizeof( buf ) - 1;
                                        bv.bv_val = buf;
-                                       if ( acl_string_expand( &bv, &b->a_sockname_pat, e->e_ndn, val->bv_val, matches ) )
+                                       if ( acl_string_expand( &bv, &b->a_sockname_pat, &e->e_nname, val, matches ) )
                                        {
                                                continue;
                                        }
@@ -1507,8 +1491,8 @@ slap_acl_mask(
                }
 
                if ( b->a_dn_at != NULL ) {
-                       if ( acl_mask_dnattr( op, e, val, a, b, i,
-                                       matches, count, state,
+                       if ( acl_mask_dnattr( op, e, val, a,
+                                       count, state, mask,
                                        &b->a_dn, &op->o_ndn ) )
                        {
                                continue;
@@ -1525,8 +1509,8 @@ slap_acl_mask(
                                ndn = op->o_ndn;
                        }
 
-                       if ( acl_mask_dnattr( op, e, val, a, b, i,
-                                       matches, count, state,
+                       if ( acl_mask_dnattr( op, e, val, a,
+                                       count, state, mask,
                                        &b->a_realdn, &ndn ) )
                        {
                                continue;
@@ -1602,7 +1586,7 @@ slap_acl_mask(
                                }
                                
                                if ( acl_string_expand( &bv, &b->a_group_pat,
-                                               e->e_nname.bv_val, val->bv_val,
+                                               &e->e_nname, val,
                                                tmp_matchesp ) )
                                {
                                        continue;
@@ -1690,7 +1674,7 @@ slap_acl_mask(
                                }
                                
                                if ( acl_string_expand( &bv, &b->a_set_pat,
-                                               e->e_nname.bv_val, val->bv_val,
+                                               &e->e_nname, val,
                                                tmp_matchesp ) )
                                {
                                        continue;
@@ -2023,7 +2007,7 @@ acl_check_modlist(
                                if ( ! access_allowed( op, e,
                                        mlist->sml_desc, NULL,
                                        ( mlist->sml_flags & SLAP_MOD_MANAGING ) ? ACL_MANAGE : ACL_WDEL,
-                                       NULL ) )
+                                       &state ) )
                                {
                                        ret = 0;
                                        goto done;
@@ -2513,8 +2497,8 @@ int
 acl_string_expand(
        struct berval   *bv,
        struct berval   *pat,
-       char            *dn_match,
-       char            *val_match,
+       struct berval   *dn_matches,
+       struct berval   *val_matches,
        AclRegexMatches *matches)
 {
        ber_len_t       size;
@@ -2576,13 +2560,15 @@ acl_string_expand(
                                case DN_FLAG:
                                        nm = matches->dn_count;
                                        m = matches->dn_data;
-                                       data = dn_match;
+                                       data = dn_matches ? dn_matches->bv_val : NULL;
                                        break;
                                case VAL_FLAG:
                                        nm = matches->val_count;
                                        m = matches->val_data;
-                                       data = val_match;
+                                       data = val_matches ? val_matches->bv_val : NULL;
                                        break;
+                               default:
+                                       assert( 0 );
                                }
                                if ( n >= nm ) {
                                        /* FIXME: error */
@@ -2634,7 +2620,8 @@ static int
 regex_matches(
        struct berval   *pat,           /* pattern to expand and match against */
        char            *str,           /* string to match against pattern */
-       char            *buf,           /* buffer with $N expansion variables */
+       struct berval   *dn_matches,    /* buffer with $N expansion variables from DN */
+       struct berval   *val_matches,   /* buffer with $N expansion variables from val */
        AclRegexMatches *matches        /* offsets in buffer for $N expansion variables */
 )
 {
@@ -2650,7 +2637,7 @@ regex_matches(
                str = "";
        };
 
-       acl_string_expand( &bv, pat, buf, NULL, matches );
+       acl_string_expand( &bv, pat, dn_matches, val_matches, matches );
        rc = regcomp( &re, newbuf, REG_EXTENDED|REG_ICASE );
        if ( rc ) {
                char error[ACL_BUF_SIZE];