]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/aci.c
use slab memory for proxyauthz
[openldap] / servers / slapd / aci.c
index 012d829fcff25b82a75b8ac329f8a81ce62f10ff..28b99388ea2381f791e423411a116c095f774b8f 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1998-2005 The OpenLDAP Foundation.
+ * Copyright 1998-2006 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include "lber_pvt.h"
 #include "lutil.h"
 
-#define ACI_BUF_SIZE   1024    /* use most appropriate size */
+/* use most appropriate size */
+#define ACI_BUF_SIZE                   1024
 
-#ifdef SLAP_DYNACL
-static
-#endif /* SLAP_DYNACL */
-AttributeDescription *slap_ad_aci;
+/* move to "stable" when no longer experimental */
+#define SLAPD_ACI_SYNTAX               "1.3.6.1.4.1.4203.666.2.1"
+
+/* change this to "OpenLDAPset" */
+#define SLAPD_ACI_SET_ATTR             "template"
+
+typedef enum slap_aci_scope_t {
+       SLAP_ACI_SCOPE_ENTRY            = 0x1,
+       SLAP_ACI_SCOPE_CHILDREN         = 0x2,
+       SLAP_ACI_SCOPE_SUBTREE          = ( SLAP_ACI_SCOPE_ENTRY | SLAP_ACI_SCOPE_CHILDREN )
+} slap_aci_scope_t;
+
+enum {
+       ACI_BV_ENTRY,
+       ACI_BV_CHILDREN,
+       ACI_BV_ONELEVEL,
+       ACI_BV_SUBTREE,
+
+       ACI_BV_BR_ENTRY,
+       ACI_BV_BR_ALL,
+
+       ACI_BV_ACCESS_ID,
+       ACI_BV_PUBLIC,
+       ACI_BV_USERS,
+       ACI_BV_SELF,
+       ACI_BV_DNATTR,
+       ACI_BV_GROUP,
+       ACI_BV_ROLE,
+       ACI_BV_SET,
+       ACI_BV_SET_REF,
+
+       ACI_BV_GRANT,
+       ACI_BV_DENY,
+
+       ACI_BV_GROUP_CLASS,
+       ACI_BV_GROUP_ATTR,
+       ACI_BV_ROLE_CLASS,
+       ACI_BV_ROLE_ATTR,
+
+       ACI_BV_SET_ATTR,
+
+       ACI_BV_LAST
+};
+
+static const struct berval     aci_bv[] = {
+       /* scope */
+       BER_BVC("entry"),
+       BER_BVC("children"),
+       BER_BVC("onelevel"),
+       BER_BVC("subtree"),
+
+       /* */
+       BER_BVC("[entry]"),
+       BER_BVC("[all]"),
+
+       /* type */
+       BER_BVC("access-id"),
+       BER_BVC("public"),
+       BER_BVC("users"),
+       BER_BVC("self"),
+       BER_BVC("dnattr"),
+       BER_BVC("group"),
+       BER_BVC("role"),
+       BER_BVC("set"),
+       BER_BVC("set-ref"),
+
+       /* actions */
+       BER_BVC("grant"),
+       BER_BVC("deny"),
+
+       /* schema */
+       BER_BVC(SLAPD_GROUP_CLASS),
+       BER_BVC(SLAPD_GROUP_ATTR),
+       BER_BVC(SLAPD_ROLE_CLASS),
+       BER_BVC(SLAPD_ROLE_ATTR),
+
+       BER_BVC(SLAPD_ACI_SET_ATTR),
+
+       BER_BVNULL
+};
+
+static AttributeDescription    *slap_ad_aci;
 
 static int
 OpenLDAPaciValidate(
@@ -85,6 +164,20 @@ aci_list_map_rights(
                }
 
                switch ( *bv.bv_val ) {
+               case 'x':
+                       /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt does not 
+                        * define any equivalent to the AUTH right, so I've just used
+                        * 'x' for now.
+                        */
+                       ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
+                       break;
+               case 'd':
+                       /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt defines
+                        * the right 'd' to mean "delete"; we hijack it to mean
+                        * "disclose" for consistency wuith the rest of slapd.
+                        */
+                       ACL_PRIV_SET(mask, ACL_PRIV_DISCLOSE);
+                       break;
                case 'c':
                        ACL_PRIV_SET(mask, ACL_PRIV_COMPARE);
                        break;
@@ -102,13 +195,6 @@ aci_list_map_rights(
                case 'w':
                        ACL_PRIV_SET(mask, ACL_PRIV_WRITE);
                        break;
-               case 'x':
-                       /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt does not 
-                        * define any equivalent to the AUTH right, so I've just used
-                        * 'x' for now.
-                        */
-                       ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
-                       break;
                default:
                        break;
                }
@@ -267,7 +353,7 @@ aci_group_member (
        const char              *text;
        int                     rc;
 
-       /* format of string is "group/objectClassValue/groupAttrName" */
+       /* format of string is "{group|role}/objectClassValue/groupAttrName" */
        if ( acl_get_part( subj, 0, '/', &subjdn ) < 0 ) {
                return 0;
        }
@@ -314,7 +400,7 @@ done:
        return rc;
 }
 
-int
+static int
 aci_mask(
        Operation               *op,
        Entry                   *e,
@@ -327,7 +413,12 @@ aci_mask(
        slap_access_t           *deny,
        slap_aci_scope_t        asserted_scope )
 {
-       struct berval           bv, scope, perms, type, sdn;
+       struct berval           bv,
+                               scope,
+                               perms,
+                               type,
+                               opts,
+                               sdn;
        int                     rc;
                
 
@@ -441,6 +532,15 @@ aci_mask(
        sdn.bv_val = type.bv_val + type.bv_len + STRLENOF( "#" );
        sdn.bv_len = aci->bv_len - ( sdn.bv_val - aci->bv_val );
 
+       /* get the type options, if any */
+       if ( acl_get_part( &type, 1, '/', &opts ) > 0 ) {
+               opts.bv_len = type.bv_len - ( opts.bv_val - type.bv_val );
+               type.bv_len = opts.bv_val - type.bv_val - 1;
+
+       } else {
+               BER_BVZERO( &opts );
+       }
+
        if ( ber_bvcmp( &aci_bv[ ACI_BV_ACCESS_ID ], &type ) == 0 ) {
                return dn_match( &op->o_ndn, &sdn );
 
@@ -487,37 +587,73 @@ aci_mask(
                return rc;
 
        } else if ( ber_bvcmp( &aci_bv[ ACI_BV_GROUP ], &type ) == 0 ) {
-               if ( aci_group_member( &sdn, &aci_bv[ ACI_BV_GROUP_CLASS ],
-                               &aci_bv[ ACI_BV_GROUP_ATTR ], op, e, nmatch, matches ) )
+               struct berval   oc,
+                               at;
+
+               if ( BER_BVISNULL( &opts ) ) {
+                       oc = aci_bv[ ACI_BV_GROUP_CLASS ];
+                       at = aci_bv[ ACI_BV_GROUP_ATTR ];
+
+               } else {
+                       if ( acl_get_part( &opts, 0, '/', &oc ) < 0 ) {
+                               assert( 0 );
+                       }
+
+                       if ( acl_get_part( &opts, 1, '/', &at ) < 0 ) {
+                               at = aci_bv[ ACI_BV_GROUP_ATTR ];
+                       }
+               }
+
+               if ( aci_group_member( &sdn, &oc, &at, op, e, nmatch, matches ) )
                {
                        return 1;
                }
 
        } else if ( ber_bvcmp( &aci_bv[ ACI_BV_ROLE ], &type ) == 0 ) {
-               if ( aci_group_member( &sdn, &aci_bv[ ACI_BV_ROLE_CLASS ],
-                               &aci_bv[ ACI_BV_ROLE_ATTR ], op, e, nmatch, matches ) )
+               struct berval   oc,
+                               at;
+
+               if ( BER_BVISNULL( &opts ) ) {
+                       oc = aci_bv[ ACI_BV_ROLE_CLASS ];
+                       at = aci_bv[ ACI_BV_ROLE_ATTR ];
+
+               } else {
+                       if ( acl_get_part( &opts, 0, '/', &oc ) < 0 ) {
+                               assert( 0 );
+                       }
+
+                       if ( acl_get_part( &opts, 1, '/', &at ) < 0 ) {
+                               at = aci_bv[ ACI_BV_ROLE_ATTR ];
+                       }
+               }
+
+               if ( aci_group_member( &sdn, &oc, &at, op, e, nmatch, matches ) )
                {
                        return 1;
                }
 
        } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SET ], &type ) == 0 ) {
-               if ( acl_match_set( &sdn, op, e, 0 ) ) {
+               if ( acl_match_set( &sdn, op, e, NULL ) ) {
                        return 1;
                }
 
        } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SET_REF ], &type ) == 0 ) {
-               if ( acl_match_set( &sdn, op, e, 1 ) ) {
+               if ( acl_match_set( &sdn, op, e, (struct berval *)&aci_bv[ ACI_BV_SET_ATTR ] ) ) {
                        return 1;
                }
+
+       } else {
+               /* it passed normalization! */
+               assert( 0 );
        }
 
        return 0;
 }
 
-int
+static int
 aci_init( void )
 {
-       /* OpenLDAP Experimental Syntax */
+       /* OpenLDAP eXperimental Syntax */
        static slap_syntax_defs_rec aci_syntax_def = {
                "( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
                        SLAP_SYNTAX_HIDE,
@@ -570,7 +706,7 @@ aci_init( void )
                &rc, &text, LDAP_SCHEMA_ALLOW_ALL );
        if ( !at ) {
                Debug( LDAP_DEBUG_ANY,
-                       "%s AttributeType load failed: %s %s\n",
+                       "aci_init: AttributeType \"%s\" parse failed: %s %s\n",
                        aci_at.name, ldap_scherr2str( rc ), text );
                return rc;
        }
@@ -578,9 +714,9 @@ aci_init( void )
        rc = at_add( at, 0, &sat, &text );
        if ( rc != LDAP_SUCCESS ) {
                ldap_attributetype_free( at );
-               fprintf( stderr, "iMUX_monitor_schema_init: "
-                       "AttributeType load failed: %s %s\n",
-                       scherr2str( rc ), text );
+               Debug( LDAP_DEBUG_ANY,
+                       "aci_init: AttributeType \"%s\" load failed: %s %s\n",
+                       aci_at.name, scherr2str( rc ), text );
                return rc;
        }
        ldap_memfree( at );
@@ -589,7 +725,7 @@ aci_init( void )
                        aci_at.ad, &text );
        if ( rc != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_ANY,
-                       "unable to find AttributeDescription "
+                       "aci_init: unable to find AttributeDescription "
                        "\"%s\": %d (%s)\n",
                        aci_at.name, rc, text );
                return 1;
@@ -601,12 +737,6 @@ aci_init( void )
        return rc;
 }
 
-#ifdef SLAP_DYNACL
-/*
- * FIXME: there is a silly dependence that makes it difficult
- * to move ACIs in a run-time loadable module under the "dynacl" 
- * umbrella, because sets share some helpers with ACIs.
- */
 static int
 dynacl_aci_parse(
        const char *fname,
@@ -687,6 +817,11 @@ dynacl_aci_mask(
        char                    accessmaskbuf1[ACCESSMASK_MAXLEN];
 #endif /* LDAP_DEBUG */
 
+       if ( BER_BVISEMPTY( &e->e_nname ) ) {
+               /* no ACIs in the root DSE */
+               return -1;
+       }
+
        /* start out with nothing granted, nothing denied */
        ACL_INIT(tgrant);
        ACL_INIT(tdeny);
@@ -710,7 +845,7 @@ dynacl_aci_mask(
                        }
                }
                
-               Debug( LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
+               Debug( LDAP_DEBUG_ACL, "        <= aci_mask grant %s deny %s\n",
                          accessmask2str( tgrant, accessmaskbuf, 1 ), 
                          accessmask2str( tdeny, accessmaskbuf1, 1 ), 0 );
        }
@@ -722,35 +857,41 @@ dynacl_aci_mask(
        if ( tgrant == ACL_PRIV_NONE && tdeny == ACL_PRIV_NONE ) {
                struct berval   parent_ndn;
 
-#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 ( !BER_BVISEMPTY( &parent_ndn ) ){
                        int             i;
                        BerVarray       bvals = NULL;
                        int             ret, stop;
 
-                       Debug( LDAP_DEBUG_ACL, "checking ACI of \"%s\"\n", parent_ndn.bv_val, 0, 0 );
-                       ret = backend_attribute( &op2, NULL, &parent_ndn, ad, &bvals, ACL_AUTH );
+                       /* 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. */
+                       struct berval   save_o_dn, save_o_ndn;
+       
+                       if ( !BER_BVISNULL( &op->o_bd->be_rootndn ) ) {
+                               save_o_dn = op->o_dn;
+                               save_o_ndn = op->o_ndn;
+
+                               op->o_dn = op->o_bd->be_rootdn;
+                               op->o_ndn = op->o_bd->be_rootndn;
+                       }
+
+                       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 );
+
+                       if ( !BER_BVISNULL( &op->o_bd->be_rootndn ) ) {
+                               op->o_dn = save_o_dn;
+                               op->o_ndn = save_o_ndn;
+                       }
 
                        switch ( ret ) {
                        case LDAP_SUCCESS :
@@ -838,7 +979,6 @@ dynacl_aci_init( void )
        return rc;
 }
 
-#endif /* SLAP_DYNACL */
 
 /* ACI syntax validation */
 
@@ -907,11 +1047,12 @@ OpenLDAPaciValidatePerms(
 
        for ( i = 0; i < perms->bv_len; ) {
                switch ( perms->bv_val[ i ] ) {
+               case 'x':
+               case 'd':
                case 'c':
                case 's':
                case 'r':
                case 'w':
-               case 'x':
                        break;
 
                default:
@@ -1261,11 +1402,13 @@ OpenLDAPaciValidate(
                struct berval   ocbv = BER_BVNULL,
                                atbv = BER_BVNULL;
 
-               ocbv.bv_val = strchr( type.bv_val, '/' );
+               ocbv.bv_val = ber_bvchr( &type, '/' );
                if ( ocbv.bv_val != NULL ) {
                        ocbv.bv_val++;
+                       ocbv.bv_len = type.bv_len
+                                       - ( ocbv.bv_val - type.bv_val );
 
-                       atbv.bv_val = strchr( ocbv.bv_val, '/' );
+                       atbv.bv_val = ber_bvchr( &ocbv, '/' );
                        if ( atbv.bv_val != NULL ) {
                                AttributeDescription    *ad = NULL;
                                const char              *text = NULL;
@@ -1280,10 +1423,6 @@ OpenLDAPaciValidate(
                                if ( rc != LDAP_SUCCESS ) {
                                        return LDAP_INVALID_SYNTAX;
                                }
-                               
-                       } else {
-                               ocbv.bv_len = type.bv_len
-                                       - ( ocbv.bv_val - type.bv_val );
                        }
 
                        if ( oc_bvfind( &ocbv ) == NULL ) {
@@ -1320,7 +1459,7 @@ OpenLDAPaciPrettyNormal(
                        subject = BER_BVNULL,
                        nsubject = BER_BVNULL;
        int             idx,
-                       rc,
+                       rc = LDAP_SUCCESS,
                        freesubject = 0,
                        freetype = 0;
        char            *ptr;
@@ -1412,7 +1551,7 @@ OpenLDAPaciPrettyNormal(
                        struct berval   ocbv = BER_BVNULL,
                                        atbv = BER_BVNULL;
 
-                       ocbv.bv_val = strchr( type.bv_val, '/' );
+                       ocbv.bv_val = ber_bvchr( &type, '/' );
                        if ( ocbv.bv_val != NULL ) {
                                ObjectClass             *oc = NULL;
                                AttributeDescription    *ad = NULL;
@@ -1423,8 +1562,9 @@ OpenLDAPaciPrettyNormal(
                                bv.bv_len = ntype.bv_len;
 
                                ocbv.bv_val++;
+                               ocbv.bv_len = type.bv_len - ( ocbv.bv_val - type.bv_val );
 
-                               atbv.bv_val = strchr( ocbv.bv_val, '/' );
+                               atbv.bv_val = ber_bvchr( &ocbv, '/' );
                                if ( atbv.bv_val != NULL ) {
                                        atbv.bv_val++;
                                        atbv.bv_len = type.bv_len
@@ -1438,13 +1578,10 @@ OpenLDAPaciPrettyNormal(
                                        }
 
                                        bv.bv_len += STRLENOF( "/" ) + ad->ad_cname.bv_len;
-                                       
-                               } else {
-                                       ocbv.bv_len = type.bv_len
-                                               - ( ocbv.bv_val - type.bv_val );
                                }
 
-                               if ( oc_bvfind( &ocbv ) == NULL ) {
+                               oc = oc_bvfind( &ocbv );
+                               if ( oc == NULL ) {
                                        rc = LDAP_INVALID_SYNTAX;
                                        goto cleanup;
                                }
@@ -1557,5 +1694,17 @@ OpenLDAPaciNormalize(
        return OpenLDAPaciPrettyNormal( val, out, ctx, 1 );
 }
 
+#if SLAPD_ACI_ENABLED == SLAPD_MOD_DYNAMIC
+/*
+ * FIXME: need config and Makefile.am code to ease building
+ * as dynamic module
+ */
+int
+init_module( int argc, char *argv[] )
+{
+       return dynacl_aci_init();
+}
+#endif /* SLAPD_ACI_ENABLED == SLAPD_MOD_DYNAMIC */
+
 #endif /* SLAPD_ACI_ENABLED */