Skip to content
Snippets Groups Projects
acl.c 56.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    /* acl.c - routines to parse and check acl's */
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
     *
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
     * Copyright 1998-2004 The OpenLDAP Foundation.
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted only as authorized by the OpenLDAP
     * Public License.
     *
     * A copy of this license is available in the file LICENSE in the
     * top-level directory of the distribution or, alternatively, at
     * <http://www.OpenLDAP.org/license.html>.
     */
    /* Portions Copyright (c) 1995 Regents of the University of Michigan.
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms are permitted
     * provided that this notice is preserved and that due credit is given
     * to the University of Michigan at Ann Arbor. The name of the University
     * may not be used to endorse or promote products derived from this
     * software without specific prior written permission. This software
     * is provided ``as is'' without express or implied warranty.
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
     */
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    
    
    #include "portable.h"
    
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    #include <stdio.h>
    
    
    #include <ac/regex.h>
    #include <ac/socket.h>
    #include <ac/string.h>
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    #include "slap.h"
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    
    
    #define ACL_BUF_SIZE 	1024	/* use most appropriate size */
    
    
    	aci_bv_children 	= BER_BVC("children"),
    
    	aci_bv_br_entry		= BER_BVC("[entry]"),
    	aci_bv_br_all		= BER_BVC("[all]"),
    	aci_bv_access_id 	= BER_BVC("access-id"),
    	aci_bv_anonymous	= BER_BVC("anonymous"),
    
    	aci_bv_public		= BER_BVC("public"),
    
    	aci_bv_users		= BER_BVC("users"),
    	aci_bv_self 		= BER_BVC("self"),
    	aci_bv_dnattr 		= BER_BVC("dnattr"),
    	aci_bv_group		= BER_BVC("group"),
    	aci_bv_role		= BER_BVC("role"),
    	aci_bv_set		= BER_BVC("set"),
    	aci_bv_set_ref		= BER_BVC("set-ref"),
    	aci_bv_grant		= BER_BVC("grant"),
    
    	aci_bv_deny		= BER_BVC("deny"),
    
    
    	aci_bv_ip_eq		= BER_BVC("IP="),
    #ifdef LDAP_PF_LOCAL
    	aci_bv_path_eq		= BER_BVC("PATH="),
    	aci_bv_dirsep		= BER_BVC(LDAP_DIRSEP),
    #endif /* LDAP_PF_LOCAL */
    
    	
    	aci_bv_group_class 	= BER_BVC(SLAPD_GROUP_CLASS),
    	aci_bv_group_attr 	= BER_BVC(SLAPD_GROUP_ATTR),
    	aci_bv_role_class	= BER_BVC(SLAPD_ROLE_CLASS),
    
    Pierangelo Masarati's avatar
    Pierangelo Masarati committed
    	aci_bv_role_attr	= BER_BVC(SLAPD_ROLE_ATTR),
    	aci_bv_set_attr		= BER_BVC(SLAPD_ACI_SET_ATTR);
    
    static AccessControl * acl_get(
    	AccessControl *ac, int *count,
    
    	AttributeDescription *desc,
    
    	struct berval *val,
    
    Howard Chu's avatar
    Howard Chu committed
    	int nmatches, regmatch_t *matches,
    	AccessControlState *state );
    
    	AccessControl *ac, slap_mask_t *mask,
    
    	AttributeDescription *desc,
    
    	regmatch_t *matches,
    	int count,
    	AccessControlState *state );
    
    #ifdef SLAPD_ACI_ENABLED
    
    	AttributeDescription *desc,
    
    	struct berval *val,
    	struct berval *aci,
    	regmatch_t *matches,
    	slap_access_t *grant,
    
    	slap_access_t *deny,
    	struct berval *scope);
    
    static int	regex_matches(
    
    	struct berval *pat, char *str, char *buf, regmatch_t *matches);
    
    static void	string_expand(
    
    	struct berval *newbuf, struct berval *pattern,
    
    	char *match, regmatch_t *matches);
    
    typedef	struct AciSetCookie {
    	Operation *op;
    
    SLAP_SET_GATHER aci_set_gather;
    
    static int aci_match_set ( struct berval *subj, Operation *op,
        Entry *e, int setref );
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    
    /*
    
     * access_allowed - check whether op->o_ndn is allowed the requested access
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
     * to entry e, attribute attr, value val.  if val is null, access to
    
     * the whole attribute is assumed (all values).
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
     *
    
     * This routine loops through all access controls and calls
     * acl_mask() on each applicable access control.
     * The loop exits when a definitive answer is reached or
     * or no more controls remain.
     *
     * returns:
     *		0	access denied
     *		1	access granted
    
     *
     * Notes:
     * - can be legally called with op == NULL
     * - can be legally called with op->o_bd == NULL
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
     */
    
    int
    
    Pierangelo Masarati's avatar
    Pierangelo Masarati committed
    access_allowed_mask(
    
    	AttributeDescription	*desc,
    
    	struct berval	*val,
    	slap_access_t	access,
    
    Pierangelo Masarati's avatar
    Pierangelo Masarati committed
    	AccessControlState *state,
    	slap_mask_t *maskp )
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    {
    
    	AccessControl			*a = NULL;
    
    	Backend *be;
    	int	be_null = 0;
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    
    
    	char accessmaskbuf[ACCESSMASK_MAXLEN];
    
    	slap_mask_t mask;
    
    	const char *attr;
    	regmatch_t matches[MAXREMATCHES];
    
    	int        st_same_attr = 0;
    	static AccessControlState state_init = ACL_STATE_INIT;
    
    	assert( e != NULL );
    	assert( desc != NULL );
    	assert( access > ACL_NONE );
    
    Pierangelo Masarati's avatar
    Pierangelo Masarati committed
    	if ( maskp ) ACL_INVALIDATE( *maskp );
    
    	attr = desc->ad_cname.bv_val;
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    	if( op && op->o_is_auth_check &&
    		( access == ACL_SEARCH || access == ACL_READ ))
    	{
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    
    
    	if( state ) {
    		if ( state->as_vd_ad==desc) {
    			if ( state->as_recorded ) {
    				if( state->as_recorded & ACL_STATE_RECORDED_NV &&
    					val == NULL )
    				{
    					return state->as_result;
    				} else if ( state->as_recorded & ACL_STATE_RECORDED_VD &&
    					val != NULL && state->as_vd_acl == NULL )
    				{
    					return state->as_result;
    				}
    			}
    			st_same_attr = 1;
    		} else {
    			*state = state_init;
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    
    
    		state->as_vd_ad=desc;
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    	LDAP_LOG( ACL, ENTRY, 
    		"access_allowed: %s access to \"%s\" \"%s\" requested\n",
    		access2str( access ), e->e_dn, attr );
    
    	Debug( LDAP_DEBUG_ACL,
    		"=> access_allowed: %s access to \"%s\" \"%s\" requested\n",
    
    	    access2str( access ), e->e_dn, attr );
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    
    
    	if ( op == NULL ) {
    		/* no-op call */
    
    	be = op->o_bd;
    
    	if ( be == NULL ) {
    		be = &backends[0];
    
    		be_null = 1;
    
    #ifdef LDAP_DEVEL
    		/*
    		 * FIXME: experimental; use first backend rules
    		 * iff there is no global_acl (ITS#3100) */
    		if ( global_acl == NULL ) 
    #endif
    		{
    			op->o_bd = be;
    		}
    
    Luke Howard's avatar
    Luke Howard committed
    #ifdef LDAP_SLAPI
    
    	if ( op->o_pb != NULL ) {
    		ret = slapi_int_access_allowed( op, e, desc, val, access, state );
    		if ( ret == 0 ) {
    			/* ACL plugin denied access */
    			goto done;
    		}
    
    Luke Howard's avatar
    Luke Howard committed
    	}
    #endif /* LDAP_SLAPI */
    
    
    	/* grant database root access */
    
    	if ( be != NULL && be_isroot( op ) ) {
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    		LDAP_LOG( ACL, INFO, 
    			"access_allowed: conn %lu root access granted\n", 
    
    		Debug( LDAP_DEBUG_ACL,
    		    "<= root access granted\n",
    			0, 0, 0 );
    
    Pierangelo Masarati's avatar
    Pierangelo Masarati committed
    		if ( maskp ) {
    			mask = ACL_LVL_WRITE;
    		}
    
    
    	/*
    	 * no-user-modification operational attributes are ignored
    	 * by ACL_WRITE checking as any found here are not provided
    	 * by the user
    	 */
    
    	if ( access >= ACL_WRITE && is_at_no_user_mod( desc->ad_type )
    		&& desc != slap_schema.si_ad_entry
    		&& desc != slap_schema.si_ad_children )
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    		LDAP_LOG( ACL, DETAIL1, 
    			"access_allowed: conn %lu NoUserMod Operational attribute: %s "
    
    			"access granted\n", op->o_connid, attr , 0 );
    
    Gary Williams's avatar
    Gary Williams committed
    		Debug( LDAP_DEBUG_ACL, "NoUserMod Operational attribute:"
    
    	}
    
    	/* use backend default access if no backend acls */
    
    	if( be != NULL && be->be_acl == NULL ) {
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    		LDAP_LOG( ACL, DETAIL1, 
    			"access_allowed: backend default %s access %s to \"%s\"\n",
    		    access2str( access ),
    
    		    be->be_dfltaccess >= access ? "granted" : "denied", 
    
    Howard Chu's avatar
    Howard Chu committed
    			op->o_dn.bv_val ? op->o_dn.bv_val : "(anonymous)" );
    
    		Debug( LDAP_DEBUG_ACL,
    			"=> access_allowed: backend default %s access %s to \"%s\"\n",
    			access2str( access ),
    
    			be->be_dfltaccess >= access ? "granted" : "denied",
    
    Howard Chu's avatar
    Howard Chu committed
    			op->o_dn.bv_val ? op->o_dn.bv_val : "(anonymous)" );
    
    		ret = be->be_dfltaccess >= access;
    
    Pierangelo Masarati's avatar
    Pierangelo Masarati committed
    
    		if ( maskp ) {
    			int	i;
    
    			mask = ACL_PRIV_LEVEL;
    
    			for ( i = ACL_NONE; i <= be->be_dfltaccess; i++ ) {
    
    Pierangelo Masarati's avatar
    Pierangelo Masarati committed
    				mask |= ACL_ACCESS2PRIV( i );
    			}
    		}
    
    
    
    #ifdef notdef
    	/* be is always non-NULL */
    	/* use global default access if no global acls */
    
    	} else if ( be == NULL && global_acl == NULL ) {
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    		LDAP_LOG( ACL, DETAIL1, 
    			"access_allowed: global default %s access %s to \"%s\"\n",
    		    access2str( access ),
    		    global_default_access >= access ? "granted" : "denied", 
    			op->o_dn.bv_val );
    
    		Debug( LDAP_DEBUG_ACL,
    			"=> access_allowed: global default %s access %s to \"%s\"\n",
    			access2str( access ),
    
    Pierangelo Masarati's avatar
    Pierangelo Masarati committed
    			global_default_access >= access ? "granted" : "denied", op->o_dn.bv_val );
    
    		ret = global_default_access >= access;
    
    Pierangelo Masarati's avatar
    Pierangelo Masarati committed
    
    		if ( maskp ) {
    			int	i;
    
    			mask = ACL_PRIV_LEVEL;
    			for ( i = ACL_NONE; i <= global_default_access; i++ ) {
    				mask |= ACL_ACCESS2PRIV( i );
    			}
    		}
    
    
    	if( st_same_attr ) {
    
    		assert( state->as_vd_acl != NULL );
    
    		a = state->as_vd_acl;
    		count = state->as_vd_acl_count;
    
    Howard Chu's avatar
    Howard Chu committed
    		if ( !ACL_IS_INVALID( state->as_vd_acl_mask )) {
    			mask = state->as_vd_acl_mask;
    			AC_MEMCPY( matches, state->as_vd_acl_matches, sizeof(matches) );
    			goto vd_access;
    		}
    
    		if ( state ) state->as_vi_acl = NULL;
    
    		a = NULL;
    		ACL_INIT(mask);
    		count = 0;
    		memset(matches, '\0', sizeof(matches));
    	}
    
    
    	while((a = acl_get( a, &count, op, e, desc, val,
    
    Howard Chu's avatar
    Howard Chu committed
    		MAXREMATCHES, matches, state )) != NULL)
    
    
    		for (i = 0; i < MAXREMATCHES && matches[i].rm_so > 0; i++) {
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    			LDAP_LOG( ACL, DETAIL1, 
    				"access_allowed: match[%d]:  %d %d ",
    			    i, (int)matches[i].rm_so, (int)matches[i].rm_eo );
    
    			Debug( LDAP_DEBUG_ACL, "=> match[%d]: %d %d ", i,
    
    			    (int)matches[i].rm_so, (int)matches[i].rm_eo );
    
    			if( matches[i].rm_so <= matches[0].rm_eo ) {
    
    				for ( n = matches[i].rm_so; n < matches[i].rm_eo; n++) {
    
    					Debug( LDAP_DEBUG_ACL, "%c", e->e_ndn[n], 0, 0 );
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    			LDAP_LOG( ACL, ARGS, "\n" , 0, 0, 0 );
    
    			Debug( LDAP_DEBUG_ARGS, "\n", 0, 0, 0 );
    
    		if (state) {
    			if (state->as_vi_acl == a && (state->as_recorded & ACL_STATE_RECORDED_NV)) {
    				Debug( LDAP_DEBUG_ACL, "access_allowed: result from state (%s)\n", attr, 0, 0 );
    
    				ret = state->as_result;
    				goto done;
    
    				Debug( LDAP_DEBUG_ACL, "access_allowed: no res from state (%s)\n", attr, 0, 0);
    			}
    		}
    
    
    		control = acl_mask( a, &mask, op,
    
    			e, desc, val, matches, count, state );
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    		memset(matches, '\0', sizeof(matches));
    
    	if ( ACL_IS_INVALID( mask ) ) {
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    		LDAP_LOG( ACL, DETAIL1, 
    			"access_allowed: conn %lu \"%s\" (%s) invalid!\n",
    
    		    op->o_connid, e->e_dn, attr );
    
    		Debug( LDAP_DEBUG_ACL,
    			"=> access_allowed: \"%s\" (%s) invalid!\n",
    			e->e_dn, attr, 0 );
    
    
    	} else if ( control == ACL_BREAK ) {
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    		LDAP_LOG( ACL, DETAIL1, 
    
    			"access_allowed: conn %lu	 no more rules\n", op->o_connid, 0,0 );
    
    		Debug( LDAP_DEBUG_ACL,
    			"=> access_allowed: no more rules\n", 0, 0, 0);
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    	LDAP_LOG( ACL, ENTRY, 
    		"access_allowed: %s access %s by %s\n", 
    		access2str( access ), ACL_GRANT( mask, access ) ? "granted" : "denied",
    		accessmask2str( mask, accessmaskbuf ) );
    
    		"=> access_allowed: %s access %s by %s\n",
    
    		ACL_GRANT(mask, access) ? "granted" : "denied",
    
    		accessmask2str( mask, accessmaskbuf ) );
    
    
    	ret = ACL_GRANT(mask, access);
    
    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_result = ret;
    		}
    
    		state->as_recorded |= ACL_STATE_RECORDED;
    	}
    
    	if (be_null) op->o_bd = NULL;
    
    Pierangelo Masarati's avatar
    Pierangelo Masarati committed
    	if ( maskp ) *maskp = mask;
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    }
    
    
    Howard Chu's avatar
    Howard Chu committed
    
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    /*
    
     * acl_get - return the acl applicable to entry e, attribute
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
     * attr.  the acl returned is suitable for use in subsequent calls to
     * acl_access_allowed().
     */
    
    
    static AccessControl *
    acl_get(
    	AccessControl *a,
    	int			*count,
    
    	AttributeDescription *desc,
    
    	struct berval	*val,
    
    Howard Chu's avatar
    Howard Chu committed
    	regmatch_t	*matches,
    	AccessControlState *state )
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    {
    
    	const char *attr;
    
    	AccessControl *prev;
    
    	assert( e != NULL );
    	assert( count != NULL );
    
    	attr = desc->ad_cname.bv_val;
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    		}
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    	}
    
    
    Howard Chu's avatar
    Howard Chu committed
    	dnlen = e->e_nname.bv_len;
    
    	for ( ; a != NULL; a = a->acl_next ) {
    		(*count) ++;
    
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    		if ( a->acl_dn_pat.bv_len || ( a->acl_dn_style != ACL_STYLE_REGEX )) {
    
    			if ( a->acl_dn_style == ACL_STYLE_REGEX ) {
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    				LDAP_LOG( ACL, DETAIL1, 
    					"acl_get: dnpat [%d] %s nsub: %d\n",
    					*count, a->acl_dn_pat.bv_val, 
    					(int) a->acl_dn_re.re_nsub );
    
    				Debug( LDAP_DEBUG_ACL, "=> dnpat: [%d] %s nsub: %d\n", 
    
    					*count, a->acl_dn_pat.bv_val, (int) a->acl_dn_re.re_nsub );
    
    				if (regexec(&a->acl_dn_re, e->e_ndn, nmatch, matches, 0))
    					continue;
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    				LDAP_LOG( ACL, DETAIL1, "acl_get: dn [%d] %s\n",
    					   *count, a->acl_dn_pat.bv_val, 0 );
    
    				Debug( LDAP_DEBUG_ACL, "=> dn: [%d] %s\n", 
    
    					*count, a->acl_dn_pat.bv_val, 0 );
    
    				if ( dnlen < patlen )
    					continue;
    
    				if ( a->acl_dn_style == ACL_STYLE_BASE ) {
    					/* base dn -- entire object DN must match */
    					if ( dnlen != patlen )
    						continue;
    
    				} else if ( a->acl_dn_style == ACL_STYLE_ONE ) {
    
    					int	rdnlen = -1, sep = 0;
    
    					if ( patlen > 0 ) {
    
    						if ( !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) )
    
    							continue;
    						sep = 1;
    					}
    
    					rdnlen = dn_rdnlen( NULL, &e->e_nname );
    
    					if ( rdnlen != dnlen - patlen - sep )
    
    						continue;
    
    				} else if ( a->acl_dn_style == ACL_STYLE_SUBTREE ) {
    
    					if ( dnlen > patlen && !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) )
    
    						continue;
    
    				} else if ( a->acl_dn_style == ACL_STYLE_CHILDREN ) {
    					if ( dnlen <= patlen )
    						continue;
    
    					if ( !DN_SEPARATOR( e->e_ndn[dnlen - patlen - 1] ) )
    
    				if ( strcmp( a->acl_dn_pat.bv_val, e->e_ndn + dnlen - patlen ) != 0 )
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    			}
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    			LDAP_LOG( ACL, DETAIL1, 
    				"acl_get: [%d] matched\n", *count, 0, 0 );
    
    			Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] matched\n",
    				*count, 0, 0 );
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    		}
    
    		if ( a->acl_attrs && !ad_inlist( desc, a->acl_attrs ) ) {
    			matches[0].rm_so = matches[0].rm_eo = -1;
    			continue;
    		}
    
    		/* Is this ACL only for a specific value? */
    		if ( a->acl_attrval.bv_len ) {
    			if ( val == NULL ) {
    				continue;
    			}
    
    Howard Chu's avatar
    Howard Chu committed
    
    			if( state && !( state->as_recorded & ACL_STATE_RECORDED_VD )) {
    				state->as_recorded |= ACL_STATE_RECORDED_VD;
    
    				state->as_vd_acl = prev;
    
    Howard Chu's avatar
    Howard Chu committed
    				state->as_vd_acl_count = *count;
    				state->as_vd_access = a->acl_access;
    				state->as_vd_access_count = 1;
    				ACL_INVALIDATE( state->as_vd_acl_mask );
    			}
    
    
    			if ( a->acl_attrval_style == ACL_STYLE_REGEX ) {
    #ifdef NEW_LOGGING
    				LDAP_LOG( ACL, DETAIL1, 
    					"acl_get: valpat %s\n",
    					a->acl_attrval.bv_val, 0, 0 );
    #else
    				Debug( LDAP_DEBUG_ACL,
    					"acl_get: valpat %s\n",
    					a->acl_attrval.bv_val, 0, 0 );
    #endif
    				if (regexec(&a->acl_attrval_re, val->bv_val, 0, NULL, 0))
    					continue;
    			} else {
    				int match = 0;
    				const char *text;
    #ifdef NEW_LOGGING
    				LDAP_LOG( ACL, DETAIL1, 
    					"acl_get: val %s\n",
    					a->acl_attrval.bv_val, 0, 0 );
    #else
    				Debug( LDAP_DEBUG_ACL,
    					"acl_get: val %s\n",
    					a->acl_attrval.bv_val, 0, 0 );
    #endif
    	
    				if ( a->acl_attrs[0].an_desc->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName ) {
    					if (value_match( &match, desc,
    						desc->ad_type->sat_equality, 0,
    						val, &a->acl_attrval, &text ) != LDAP_SUCCESS ||
    							match )
    						continue;
    					
    				} else {
    					int		patlen, vdnlen;
    	
    					patlen = a->acl_attrval.bv_len;
    					vdnlen = val->bv_len;
    	
    					if ( vdnlen < patlen )
    						continue;
    	
    					if ( a->acl_dn_style == ACL_STYLE_BASE ) {
    						if ( vdnlen > patlen )
    							continue;
    	
    					} else if ( a->acl_dn_style == ACL_STYLE_ONE ) {
    						int rdnlen = -1;
    	
    
    						if ( !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) )
    
    							continue;
    	
    						rdnlen = dn_rdnlen( NULL, val );
    						if ( rdnlen != vdnlen - patlen - 1 )
    							continue;
    	
    					} else if ( a->acl_dn_style == ACL_STYLE_SUBTREE ) {
    
    						if ( vdnlen > patlen && !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) )
    
    							continue;
    	
    					} else if ( a->acl_dn_style == ACL_STYLE_CHILDREN ) {
    						if ( vdnlen <= patlen )
    							continue;
    	
    
    						if ( !DN_SEPARATOR( val->bv_val[vdnlen - patlen - 1] ) )
    
    							continue;
    					}
    	
    					if ( strcmp( a->acl_attrval.bv_val, val->bv_val + vdnlen - patlen ))
    						continue;
    				}
    			}
    		}
    
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    		if ( a->acl_filter != NULL ) {
    
    			ber_int_t rc = test_filter( NULL, e, a->acl_filter );
    
    			if ( rc != LDAP_COMPARE_TRUE ) {
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    				continue;
    			}
    		}
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    		LDAP_LOG( ACL, DETAIL1, 
    
    			"acl_get: [%d] attr %s\n", *count, attr ,0 );
    
    		Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] attr %s\n",
    
    Gary Williams's avatar
    Gary Williams committed
    		       *count, attr, 0);
    
    		return a;
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    	}
    
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    	LDAP_LOG( ACL, RESULTS, "acl_get: done.\n", 0, 0, 0 );
    
    	Debug( LDAP_DEBUG_ACL, "<= acl_get: done.\n", 0, 0, 0 );
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    	return( NULL );
    }
    
    
    /*
     * 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; \
    			state->as_vd_acl = a; \
    			AC_MEMCPY( state->as_vd_acl_matches, matches, \
    				sizeof( state->as_vd_acl_matches )) ; \
    			state->as_vd_acl_count = count; \
    			state->as_vd_access = b; \
    			state->as_vd_access_count = i; \
    		} \
    	} while( 0 )
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    /*
    
     * acl_mask - modifies mask based upon the given acl and the
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
     * requested access to entry e, attribute attr, value val.  if val
     * is null, access to the whole attribute is assumed (all values).
     *
     * returns	0	access NOT allowed
     *		1	access allowed
     */
    
    
    	slap_mask_t *mask,
    
    	AttributeDescription *desc,
    
    	regmatch_t	*matches,
    	int	count,
    	AccessControlState *state )
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    {
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    	Access	*b;
    
    	char accessmaskbuf[ACCESSMASK_MAXLEN];
    
    	char accessmaskbuf1[ACCESSMASK_MAXLEN];
    
    
    	assert( a != NULL );
    	assert( mask != NULL );
    
    	attr = desc->ad_cname.bv_val;
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    	LDAP_LOG( ACL, ENTRY, 
    		"acl_mask: conn %lu  access to entry \"%s\", attr \"%s\" requested\n",
    
    		op->o_connid, e->e_dn, attr );
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    
    	LDAP_LOG( ACL, ARGS, 
    		" to %s by \"%s\", (%s) \n", val ? "value" : "all values",
    		op->o_ndn.bv_val ? op->o_ndn.bv_val : "",
    		accessmask2str( *mask, accessmaskbuf ) );
    
    		"=> acl_mask: access to entry \"%s\", attr \"%s\" requested\n",
    
    		"=> acl_mask: to %s by \"%s\", (%s) \n",
    		val ? "value" : "all values",
    
    		op->o_ndn.bv_val ?  op->o_ndn.bv_val : "",
    
    		accessmask2str( *mask, accessmaskbuf ) );
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    
    
    	if( state && ( state->as_recorded & ACL_STATE_RECORDED_VD )
    		&& state->as_vd_acl == a )
    	{
    		b = state->as_vd_access;
    		i = state->as_vd_access_count;
    
    	} else {
    		b = a->acl_access;
    		i = 1;
    	}
    
    	for ( ; b != NULL; b = b->a_next, i++ ) {
    
    		slap_mask_t oldmask, modmask;
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    		/* AND <who> clauses */
    
    		if ( b->a_dn_pat.bv_len != 0 ) {
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    			LDAP_LOG( ACL, DETAIL1, 
    				"acl_mask: conn %lu  check a_dn_pat: %s\n",
    
    				op->o_connid, b->a_dn_pat.bv_val ,0 );
    
    			Debug( LDAP_DEBUG_ACL, "<= check a_dn_pat: %s\n",
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    			/*
    			 * if access applies to the entry itself, and the
    			 * user is bound as somebody in the same namespace as
    			 * the entry, OR the given dn matches the dn pattern
    			 */
    
    			if ( bvmatch( &b->a_dn_pat, &aci_bv_anonymous ) ) {
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    					continue;
    				}
    
    
    			} else if ( bvmatch( &b->a_dn_pat, &aci_bv_users ) ) {
    
    			} else if ( bvmatch( &b->a_dn_pat, &aci_bv_self ) ) {
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    					continue;
    				}
    				
    
    				if ( e->e_dn == NULL || !dn_match( &e->e_nname, &op->o_ndn ) ) {
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    					continue;
    				}
    
    
    			} else if ( b->a_dn_style == ACL_STYLE_REGEX ) {
    
    					int ret = regex_matches( &b->a_dn_pat,
    
    						op->o_ndn.bv_val, e->e_ndn, matches );
    
    
    					bv.bv_len = sizeof( buf ) - 1;
    					bv.bv_val = buf;
    
    					string_expand(&bv, &b->a_dn_pat, 
    							e->e_ndn, matches);
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    					if ( dnNormalize(0, NULL, NULL, &bv, &pat, op->o_tmpmemctx ) != LDAP_SUCCESS ) {
    
    						/* did not expand to a valid dn */
    						continue;
    					}
    				} else {
    					pat = b->a_dn_pat;
    				}
    
    				patlen = pat.bv_len;
    
    
    				if ( b->a_dn_style == ACL_STYLE_BASE ) {
    					/* base dn -- entire object DN must match */
    
    					if ( odnlen != patlen ) {
    						goto dn_match_cleanup;
    					}
    
    
    				} else if ( b->a_dn_style == ACL_STYLE_ONE ) {
    					int rdnlen = -1;
    
    
    					if ( odnlen <= patlen ) {
    						goto dn_match_cleanup;
    					}
    
    					if ( !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) {
    
    					rdnlen = dn_rdnlen( NULL, &op->o_ndn );
    
    					if ( rdnlen != odnlen - patlen - 1 ) {
    						goto dn_match_cleanup;
    					}
    
    
    				} else if ( b->a_dn_style == ACL_STYLE_SUBTREE ) {
    
    					if ( odnlen > patlen && !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) {
    
    
    				} else if ( b->a_dn_style == ACL_STYLE_CHILDREN ) {
    
    					if ( !DN_SEPARATOR( op->o_ndn.bv_val[odnlen - patlen - 1] ) ) {
    
    				got_match = !strcmp( pat.bv_val, op->o_ndn.bv_val + odnlen - patlen );
    
    dn_match_cleanup:;
    				if ( pat.bv_val != b->a_dn_pat.bv_val ) {
    					free( pat.bv_val );
    				}
    
    				if ( !got_match ) {
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    			}
    		}
    
    		if ( b->a_sockurl_pat.bv_len ) {
    
    			if ( ! op->o_conn->c_listener ) {
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    			LDAP_LOG( ACL, DETAIL1, 
    
    				   "acl_mask: conn %lu  check a_sockurl_pat: %s\n",
    
    				   op->o_connid, b->a_sockurl_pat.bv_val , 0 );
    
    			Debug( LDAP_DEBUG_ACL, "<= check a_sockurl_pat: %s\n",
    
    				b->a_sockurl_pat.bv_val, 0, 0 );
    
    			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,
    
    
    				} else if ( b->a_sockurl_style == ACL_STYLE_EXPAND ) {
    					struct berval	bv;
    					char buf[ACL_BUF_SIZE];
    
    					bv.bv_len = sizeof( buf ) - 1;
    					bv.bv_val = buf;
    					string_expand( &bv, &b->a_sockurl_pat, e->e_ndn, matches );
    
    					if ( ber_bvstrcasecmp( &bv, &op->o_conn->c_listener_url ) != 0 ) {
    						continue;
    					}
    
    
    					if ( ber_bvstrcasecmp( &b->a_sockurl_pat, &op->o_conn->c_listener_url ) != 0 )
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    			}
    		}
    
    Kurt Zeilenga's avatar
    Kurt Zeilenga committed
    
    
    		if ( b->a_domain_pat.bv_len ) {
    
    			if ( !op->o_conn->c_peer_domain.bv_val ) {
    
    #ifdef NEW_LOGGING
    
    Julius Enarusai's avatar
     
    Julius Enarusai committed
    			LDAP_LOG( ACL, DETAIL1, 
    
    				   "acl_mask: conn %lu  check a_domain_pat: %s\n",
    
    				   op->o_connid, b->a_domain_pat.bv_val , 0 );
    
    			Debug( LDAP_DEBUG_ACL, "<= check a_domain_pat: %s\n",
    
    				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,
    
    					struct berval 	cmp = op->o_conn->c_peer_domain;
    
    					struct berval 	pat = b->a_domain_pat;
    
    					if ( b->a_domain_expand ) {
    						struct berval bv;
    
    
    						bv.bv_len = sizeof(buf) - 1;
    
    						bv.bv_val = buf;
    
    						string_expand(&bv, &b->a_domain_pat, e->e_ndn, matches);
    						pat = bv;
    					}
    
    					if ( b->a_domain_style == ACL_STYLE_SUBTREE ) {
    						int offset = cmp.bv_len - pat.bv_len;
    						if ( offset < 0 ) {
    							continue;
    						}