]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/acl.c
Another abandon check
[openldap] / servers / slapd / acl.c
index 073a1cafebc24980b38addfd6f6d119bf26e47c6..623f0b18a26b1fb76aedf1a97a34896e27d4a404 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1998-2004 The OpenLDAP Foundation.
+ * Copyright 1998-2005 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,6 +48,7 @@
 static struct berval 
        aci_bv_entry            = BER_BVC("entry"),
        aci_bv_children         = BER_BVC("children"),
+       aci_bv_onelevel         = BER_BVC("onelevel"),
        aci_bv_subtree          = BER_BVC("subtree"),
        aci_bv_br_entry         = BER_BVC("[entry]"),
        aci_bv_br_all           = BER_BVC("[all]"),
@@ -252,7 +253,7 @@ access_allowed_mask(
                    "<= root access granted\n",
                        0, 0, 0 );
                if ( maskp ) {
-                       mask = ACL_LVL_WRITE;
+                       mask = ACL_LVL_MANAGE;
                }
 
                goto done;
@@ -540,8 +541,11 @@ acl_get(
                                Debug( LDAP_DEBUG_ACL,
                                        "acl_get: valpat %s\n",
                                        a->acl_attrval.bv_val, 0, 0 );
-                               if (regexec(&a->acl_attrval_re, val->bv_val, 0, NULL, 0))
+                               if ( regexec( &a->acl_attrval_re, val->bv_val, 0, NULL, 0 ) )
+                               {
                                        continue;
+                               }
+
                        } else {
                                int match = 0;
                                const char *text;
@@ -704,21 +708,21 @@ acl_mask(
                         */
                        /*
                         * NOTE: styles "anonymous", "users" and "self" 
-                        * have been moved to an enumeration, * whose value
-                        * is set in a_dn_style; however, the string
+                        * have been moved to enum slap_style_t, whose 
+                        * value is set in a_dn_style; however, the string
                         * is maintaned in a_dn_pat.
                         */
-                       if ( b->a_dn_style == ACL_STYLE_ANONYMOUS /* bvmatch( &b->a_dn_pat, &aci_bv_anonymous ) */ ) {
+                       if ( b->a_dn_style == ACL_STYLE_ANONYMOUS ) {
                                if ( op->o_ndn.bv_len != 0 ) {
                                        continue;
                                }
 
-                       } else if ( b->a_dn_style == ACL_STYLE_USERS /* bvmatch( &b->a_dn_pat, &aci_bv_users ) */ ) {
+                       } else if ( b->a_dn_style == ACL_STYLE_USERS ) {
                                if ( op->o_ndn.bv_len == 0 ) {
                                        continue;
                                }
 
-                       } else if ( b->a_dn_style == ACL_STYLE_SELF /* bvmatch( &b->a_dn_pat, &aci_bv_self ) */ ) {
+                       } else if ( b->a_dn_style == ACL_STYLE_SELF ) {
                                if ( op->o_ndn.bv_len == 0 ) {
                                        continue;
                                }
@@ -1740,7 +1744,9 @@ acl_check_modlist(
                Debug( LDAP_DEBUG_ACL,
                        "=> access_allowed: backend default %s access %s to \"%s\"\n",
                        access2str( ACL_WRITE ),
-                       op->o_bd->be_dfltaccess >= ACL_WRITE ? "granted" : "denied", op->o_dn.bv_val );
+                       op->o_bd->be_dfltaccess >= ACL_WRITE
+                               ? "granted" : "denied",
+                       op->o_dn.bv_val );
                ret = (op->o_bd->be_dfltaccess >= ACL_WRITE);
                goto done;
        }
@@ -2024,27 +2030,18 @@ aci_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *de
        
        p.cookie = cookie;
        
+       op2.o_hdr = cp->op->o_hdr;
        op2.o_tag = LDAP_REQ_SEARCH;
-       op2.o_protocol = LDAP_VERSION3;
        op2.o_ndn = op2.o_bd->be_rootndn;
        op2.o_callback = &cb;
        op2.o_time = slap_get_time();
        op2.o_do_not_cache = 1;
        op2.o_is_auth_check = 0;
-       op2.o_threadctx = cp->op->o_threadctx;
-       op2.o_tmpmemctx = cp->op->o_tmpmemctx;
-       op2.o_tmpmfuncs = cp->op->o_tmpmfuncs;
-#ifdef LDAP_SLAPI
-       op2.o_pb = cp->op->o_pb;
-#endif
-       op2.o_conn = cp->op->o_conn;
-       op2.o_connid = cp->op->o_connid;
        ber_dupbv_x( &op2.o_req_dn, &op2.o_req_ndn, cp->op->o_tmpmemctx );
        op2.ors_slimit = SLAP_NO_LIMIT;
        op2.ors_tlimit = SLAP_NO_LIMIT;
        op2.ors_attrs = anlistp;
        op2.ors_attrsonly = 0;
-       op2.o_sync_slog_size = -1;
 
        cb.sc_private = &p;
 
@@ -2119,8 +2116,9 @@ aci_match_set (
        int             rc = 0;
        AciSetCookie    cookie;
 
-       if (setref == 0) {
+       if ( setref == 0 ) {
                ber_dupbv_x( &set, subj, op->o_tmpmemctx );
+
        } else {
                struct berval           subjdn, ndn = BER_BVNULL;
                struct berval           setat;
@@ -2130,7 +2128,7 @@ aci_match_set (
 
                /* format of string is "entry/setAttrName" */
                if ( aci_get_part( subj, 0, '/', &subjdn ) < 0 ) {
-                       return(0);
+                       return 0;
                }
 
                if ( aci_get_part( subj, 1, '/', &setat ) < 0 ) {
@@ -2412,15 +2410,27 @@ aci_mask(
        assert( !BER_BVISNULL( &desc->ad_cname ) );
 
        /* parse an aci of the form:
-               oid#scope#action;rights;attr;rights;attr$action;rights;attr;rights;attr#dnType#subjectDN
+               oid # scope # action;rights;attr;rights;attr 
+                       $ action;rights;attr;rights;attr # type # subject
+
+          [NOTE: the following comment is very outdated,
+          as the draft version it refers to (Ando, 2004-11-20)].
 
           See draft-ietf-ldapext-aci-model-04.txt section 9.1 for
           a full description of the format for this attribute.
           Differences: "this" in the draft is "self" here, and
-          "self" and "public" is in the position of dnType.
+          "self" and "public" is in the position of type.
+
+          <scope> = {entry|children|subtree}
+          <type> = {public|users|access-id|subtree|onelevel|children|
+                    self|dnattr|group|role|set|set-ref}
 
-          For now, this routine only supports scope=entry.
+          This routine now supports scope={ENTRY,CHILDREN}
+          with the semantics:
+            - ENTRY applies to "entry" and "subtree";
+            - CHILDREN aplies to "children" and "subtree"
         */
+
        /* check that the aci has all 5 components */
        if ( aci_get_part( aci, 4, '#', NULL ) < 0 ) {
                return 0;
@@ -2475,25 +2485,97 @@ aci_mask(
                return 0;
        }
 
+       /* see if we have a public (i.e. anonymous) access */
+       if ( ber_bvstrcasecmp( &aci_bv_public, &type ) == 0 ) {
+               return 1;
+       }
+       
+       /* otherwise require an identity */
+       if ( BER_BVISNULL( &op->o_ndn ) || BER_BVISEMPTY( &op->o_ndn ) ) {
+               return 0;
+       }
+
+       /* see if we have a users access */
+       if ( ber_bvstrcasecmp( &aci_bv_users, &type ) == 0 ) {
+               return 1;
+       }
+       
+       /* NOTE: this may fail if a DN contains a valid '#' (unescaped);
+        * just grab all the berval up to its end (ITS#3303).
+        * NOTE: the problem could be solved by providing the DN with
+        * the embedded '#' encoded as hexpairs: "cn=Foo#Bar" would 
+        * become "cn=Foo\23Bar" and be safely used by aci_mask(). */
+#if 0
        if ( aci_get_part( aci, 4, '#', &sdn ) < 0 ) {
                return 0;
        }
+#endif
+       sdn.bv_val = type.bv_val + type.bv_len + STRLENOF( "#" );
+       sdn.bv_len = aci->bv_len - ( sdn.bv_val - aci->bv_val );
 
        if ( ber_bvstrcasecmp( &aci_bv_access_id, &type ) == 0 ) {
                struct berval ndn;
                
-               rc = 0;
-               if ( dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx ) == LDAP_SUCCESS )
-               {
-                       if ( dn_match( &op->o_ndn, &ndn ) ) {
-                               rc = 1;
-                       }
-                       slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
+               rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
+               if ( rc != LDAP_SUCCESS ) {
+                       return 0;
+               }
+
+               if ( dn_match( &op->o_ndn, &ndn ) ) {
+                       rc = 1;
                }
+               slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
+
                return rc;
 
-       } else if ( ber_bvstrcasecmp( &aci_bv_public, &type ) == 0 ) {
-               return 1;
+       } else if ( ber_bvstrcasecmp( &aci_bv_subtree, &type ) == 0 ) {
+               struct berval ndn;
+               
+               rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
+               if ( rc != LDAP_SUCCESS ) {
+                       return 0;
+               }
+
+               if ( dnIsSuffix( &op->o_ndn, &ndn ) ) {
+                       rc = 1;
+               }
+               slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
+
+               return rc;
+
+       } else if ( ber_bvstrcasecmp( &aci_bv_onelevel, &type ) == 0 ) {
+               struct berval ndn, pndn;
+               
+               rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
+               if ( rc != LDAP_SUCCESS ) {
+                       return 0;
+               }
+
+               dnParent( &ndn, &pndn );
+
+               if ( dn_match( &op->o_ndn, &pndn ) ) {
+                       rc = 1;
+               }
+               slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
+
+               return rc;
+
+       } else if ( ber_bvstrcasecmp( &aci_bv_children, &type ) == 0 ) {
+               struct berval ndn;
+               
+               rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
+               if ( rc != LDAP_SUCCESS ) {
+                       return 0;
+               }
+
+               if ( !dn_match( &op->o_ndn, &ndn )
+                               && dnIsSuffix( &op->o_ndn, &ndn ) )
+               {
+                       rc = 1;
+               }
+               slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
+
+               return rc;
 
        } else if ( ber_bvstrcasecmp( &aci_bv_self, &type ) == 0 ) {
                if ( dn_match( &op->o_ndn, &e->e_nname ) ) {
@@ -2513,8 +2595,6 @@ aci_mask(
 
                rc = 0;
 
-               bv = op->o_ndn;
-
                for ( at = attrs_find( e->e_attrs, ad );
                                at != NULL;
                                at = attrs_find( at->a_next, ad ) )
@@ -2523,7 +2603,7 @@ aci_mask(
                                SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
                                        SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
                                at->a_nvals,
-                               &bv, op->o_tmpmemctx ) == 0 )
+                               &op->o_ndn, op->o_tmpmemctx ) == 0 )
                        {
                                rc = 1;
                                break;
@@ -2532,7 +2612,6 @@ aci_mask(
 
                return rc;
 
-
        } else if ( ber_bvstrcasecmp( &aci_bv_group, &type ) == 0 ) {
                if ( aci_group_member( &sdn, &aci_bv_group_class,
                                &aci_bv_group_attr, op, e, nmatch, matches ) )
@@ -2561,8 +2640,6 @@ aci_mask(
        return 0;
 }
 
-#endif /* SLAPD_ACI_ENABLED */
-
 #ifdef SLAP_DYNACL
 static int
 dynacl_aci_parse( const char *fname, int lineno, slap_style_t sty, const char *right, void **privp )
@@ -2671,6 +2748,27 @@ dynacl_aci_mask(
                struct berval   parent_ndn;
                struct berval   old_parent_ndn = BER_BVNULL;
 
+#if 1
+               /* to solve the chicken'n'egg problem of accessing
+                * the OpenLDAPaci attribute, the direct access
+                * to the entry's attribute is unchecked; however,
+                * further accesses to OpenLDAPaci values in the 
+                * ancestors occur through backend_attribute(), i.e.
+                * with the identity of the operation, requiring
+                * further access checking.  For uniformity, this
+                * makes further requests occur as the rootdn, if
+                * any, i.e. searching for the OpenLDAPaci attribute
+                * is considered an internal search.  If this is not
+                * acceptable, then the same check needs be performed
+                * when accessing the entry's attribute. */
+               Operation       op2 = *op;
+
+               if ( !BER_BVISNULL( &op->o_bd->be_rootndn ) ) {
+                       op2.o_dn = op->o_bd->be_rootdn;
+                       op2.o_ndn = op->o_bd->be_rootndn;
+               }
+#endif
+
                dnParent( &e->e_nname, &parent_ndn );
                while ( parent_ndn.bv_val != old_parent_ndn.bv_val ){
                        int             i;
@@ -2679,7 +2777,7 @@ dynacl_aci_mask(
 
                        old_parent_ndn = parent_ndn;
                        Debug( LDAP_DEBUG_ACL, "checking ACI of \"%s\"\n", parent_ndn.bv_val, 0, 0 );
-                       ret = backend_attribute( op, NULL, &parent_ndn, ad, &bvals, ACL_AUTH );
+                       ret = backend_attribute( &op2, NULL, &parent_ndn, ad, &bvals, ACL_AUTH );
 
                        switch ( ret ) {
                        case LDAP_SUCCESS :
@@ -2753,11 +2851,11 @@ static slap_dynacl_t    dynacl_aci = {
        NULL
 };
 
-int
-aci_init( void )
-{
-       return slap_dynacl_register( &dynacl_aci );
-}
+#endif /* SLAP_DYNACL */
+
+#endif /* SLAPD_ACI_ENABLED */
+
+#ifdef SLAP_DYNACL
 
 /*
  * dynamic ACL infrastructure
@@ -2817,23 +2915,26 @@ slap_dynacl_get( const char *name )
 int
 acl_init( void )
 {
+       int             i, rc;
 #ifdef SLAP_DYNACL
-       int             rc;
-
-       da_list = NULL;
-
+       slap_dynacl_t   *known_dynacl[] = {
 #ifdef SLAPD_ACI_ENABLED
-       rc = aci_init();
-       if ( rc ) {
-               return rc;
+               &dynacl_aci,
+#endif  /* SLAPD_ACI_ENABLED */
+               NULL
+       };
+
+       for ( i = 0; known_dynacl[ i ]; i++ ) {
+               rc = slap_dynacl_register( known_dynacl[ i ] ); 
+               if ( rc ) {
+                       return rc;
+               }
        }
-#endif /* SLAPD_ACI_ENABLED */
 #endif /* SLAP_DYNACL */
 
        return 0;
 }
 
-
 static int
 string_expand(
        struct berval   *bv,