Home | History | Annotate | Line # | Download | only in slapd
saslauthz.c revision 1.2
      1  1.2  christos /*	$NetBSD: saslauthz.c,v 1.2 2020/08/11 13:15:39 christos Exp $	*/
      2  1.2  christos 
      3  1.2  christos /* $OpenLDAP$ */
      4  1.1     lukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5  1.1     lukem  *
      6  1.2  christos  * Copyright 1998-2020 The OpenLDAP Foundation.
      7  1.1     lukem  * Portions Copyright 2000 Mark Adamson, Carnegie Mellon.
      8  1.1     lukem  * All rights reserved.
      9  1.1     lukem  *
     10  1.1     lukem  * Redistribution and use in source and binary forms, with or without
     11  1.1     lukem  * modification, are permitted only as authorized by the OpenLDAP
     12  1.1     lukem  * Public License.
     13  1.1     lukem  *
     14  1.1     lukem  * A copy of this license is available in the file LICENSE in the
     15  1.1     lukem  * top-level directory of the distribution or, alternatively, at
     16  1.1     lukem  * <http://www.OpenLDAP.org/license.html>.
     17  1.1     lukem  */
     18  1.1     lukem 
     19  1.2  christos #include <sys/cdefs.h>
     20  1.2  christos __RCSID("$NetBSD: saslauthz.c,v 1.2 2020/08/11 13:15:39 christos Exp $");
     21  1.2  christos 
     22  1.1     lukem #include "portable.h"
     23  1.1     lukem 
     24  1.1     lukem #include <stdio.h>
     25  1.1     lukem #ifdef HAVE_LIMITS_H
     26  1.1     lukem #include <limits.h>
     27  1.1     lukem #endif
     28  1.1     lukem 
     29  1.1     lukem #include <ac/stdlib.h>
     30  1.1     lukem #include <ac/string.h>
     31  1.1     lukem #include <ac/ctype.h>
     32  1.1     lukem 
     33  1.1     lukem #include "slap.h"
     34  1.1     lukem 
     35  1.1     lukem #include "lutil.h"
     36  1.1     lukem 
     37  1.1     lukem #define SASLREGEX_REPLACE 10
     38  1.1     lukem 
     39  1.1     lukem #define LDAP_X_SCOPE_EXACT	((ber_int_t) 0x0010)
     40  1.1     lukem #define LDAP_X_SCOPE_REGEX	((ber_int_t) 0x0020)
     41  1.1     lukem #define LDAP_X_SCOPE_CHILDREN	((ber_int_t) 0x0030)
     42  1.1     lukem #define LDAP_X_SCOPE_SUBTREE	((ber_int_t) 0x0040)
     43  1.1     lukem #define LDAP_X_SCOPE_ONELEVEL	((ber_int_t) 0x0050)
     44  1.1     lukem #define LDAP_X_SCOPE_GROUP	((ber_int_t) 0x0060)
     45  1.1     lukem #define LDAP_X_SCOPE_USERS	((ber_int_t) 0x0070)
     46  1.1     lukem 
     47  1.1     lukem /*
     48  1.1     lukem  * IDs in DNauthzid form can now have a type specifier, that
     49  1.1     lukem  * influences how they are used in related operations.
     50  1.1     lukem  *
     51  1.1     lukem  * syntax: dn[.{exact|regex}]:<val>
     52  1.1     lukem  *
     53  1.1     lukem  * dn.exact:	the value must pass normalization and is used
     54  1.1     lukem  *		in exact DN match.
     55  1.1     lukem  * dn.regex:	the value is treated as a regular expression
     56  1.1     lukem  *		in matching DN values in authz{To|From}
     57  1.1     lukem  *		attributes.
     58  1.1     lukem  * dn:		for backwards compatibility reasons, the value
     59  1.1     lukem  *		is treated as a regular expression, and thus
     60  1.1     lukem  *		it is not normalized nor validated; it is used
     61  1.1     lukem  *		in exact or regex comparisons based on the
     62  1.1     lukem  *		context.
     63  1.1     lukem  *
     64  1.1     lukem  * IDs in DNauthzid form can now have a type specifier, that
     65  1.1     lukem  * influences how they are used in related operations.
     66  1.1     lukem  *
     67  1.1     lukem  * syntax: u[.mech[/realm]]:<val>
     68  1.1     lukem  *
     69  1.1     lukem  * where mech is a SIMPLE, AUTHZ, or a SASL mechanism name
     70  1.1     lukem  * and realm is mechanism specific realm (separate to those
     71  1.1     lukem  * which are representable as part of the principal).
     72  1.1     lukem  */
     73  1.1     lukem 
     74  1.1     lukem typedef struct sasl_regexp {
     75  1.1     lukem   char *sr_match;						/* regexp match pattern */
     76  1.1     lukem   char *sr_replace; 					/* regexp replace pattern */
     77  1.1     lukem   regex_t sr_workspace;					/* workspace for regexp engine */
     78  1.1     lukem   int sr_offset[SASLREGEX_REPLACE+2];	/* offsets of $1,$2... in *replace */
     79  1.1     lukem } SaslRegexp_t;
     80  1.1     lukem 
     81  1.1     lukem static int nSaslRegexp = 0;
     82  1.1     lukem static SaslRegexp_t *SaslRegexp = NULL;
     83  1.1     lukem 
     84  1.1     lukem #ifdef SLAP_AUTH_REWRITE
     85  1.1     lukem #include "rewrite.h"
     86  1.1     lukem struct rewrite_info	*sasl_rwinfo = NULL;
     87  1.1     lukem #define AUTHID_CONTEXT	"authid"
     88  1.1     lukem #endif /* SLAP_AUTH_REWRITE */
     89  1.1     lukem 
     90  1.1     lukem /* What SASL proxy authorization policies are allowed? */
     91  1.1     lukem #define	SASL_AUTHZ_NONE	0x00
     92  1.1     lukem #define	SASL_AUTHZ_FROM	0x01
     93  1.1     lukem #define	SASL_AUTHZ_TO	0x02
     94  1.1     lukem #define SASL_AUTHZ_AND	0x10
     95  1.1     lukem 
     96  1.1     lukem static const char *policy_txt[] = {
     97  1.1     lukem 	"none", "from", "to", "any"
     98  1.1     lukem };
     99  1.1     lukem 
    100  1.1     lukem static int authz_policy = SASL_AUTHZ_NONE;
    101  1.1     lukem 
    102  1.1     lukem static int
    103  1.1     lukem slap_sasl_match( Operation *opx, struct berval *rule,
    104  1.1     lukem 	struct berval *assertDN, struct berval *authc );
    105  1.1     lukem 
    106  1.1     lukem int slap_sasl_setpolicy( const char *arg )
    107  1.1     lukem {
    108  1.1     lukem 	int rc = LDAP_SUCCESS;
    109  1.1     lukem 
    110  1.1     lukem 	if ( strcasecmp( arg, "none" ) == 0 ) {
    111  1.1     lukem 		authz_policy = SASL_AUTHZ_NONE;
    112  1.1     lukem 	} else if ( strcasecmp( arg, "from" ) == 0 ) {
    113  1.1     lukem 		authz_policy = SASL_AUTHZ_FROM;
    114  1.1     lukem 	} else if ( strcasecmp( arg, "to" ) == 0 ) {
    115  1.1     lukem 		authz_policy = SASL_AUTHZ_TO;
    116  1.1     lukem 	} else if ( strcasecmp( arg, "both" ) == 0 || strcasecmp( arg, "any" ) == 0 ) {
    117  1.1     lukem 		authz_policy = SASL_AUTHZ_FROM | SASL_AUTHZ_TO;
    118  1.1     lukem 	} else if ( strcasecmp( arg, "all" ) == 0 ) {
    119  1.1     lukem 		authz_policy = SASL_AUTHZ_FROM | SASL_AUTHZ_TO | SASL_AUTHZ_AND;
    120  1.1     lukem 	} else {
    121  1.1     lukem 		rc = LDAP_OTHER;
    122  1.1     lukem 	}
    123  1.1     lukem 	return rc;
    124  1.1     lukem }
    125  1.1     lukem 
    126  1.1     lukem const char * slap_sasl_getpolicy()
    127  1.1     lukem {
    128  1.1     lukem 	if ( authz_policy == (SASL_AUTHZ_FROM | SASL_AUTHZ_TO | SASL_AUTHZ_AND) )
    129  1.1     lukem 		return "all";
    130  1.1     lukem 	else
    131  1.1     lukem 		return policy_txt[authz_policy];
    132  1.1     lukem }
    133  1.1     lukem 
    134  1.1     lukem int slap_parse_user( struct berval *id, struct berval *user,
    135  1.1     lukem 		struct berval *realm, struct berval *mech )
    136  1.1     lukem {
    137  1.1     lukem 	char	u;
    138  1.1     lukem 
    139  1.1     lukem 	assert( id != NULL );
    140  1.1     lukem 	assert( !BER_BVISNULL( id ) );
    141  1.1     lukem 	assert( user != NULL );
    142  1.1     lukem 	assert( realm != NULL );
    143  1.1     lukem 	assert( mech != NULL );
    144  1.1     lukem 
    145  1.1     lukem 	u = id->bv_val[ 0 ];
    146  1.1     lukem 
    147  1.1     lukem 	if ( u != 'u' && u != 'U' ) {
    148  1.1     lukem 		/* called with something other than u: */
    149  1.1     lukem 		return LDAP_PROTOCOL_ERROR;
    150  1.1     lukem 	}
    151  1.1     lukem 
    152  1.1     lukem 	/* uauthzid form:
    153  1.1     lukem 	 *		u[.mech[/realm]]:user
    154  1.1     lukem 	 */
    155  1.1     lukem 
    156  1.1     lukem 	user->bv_val = ber_bvchr( id, ':' );
    157  1.1     lukem 	if ( BER_BVISNULL( user ) ) {
    158  1.1     lukem 		return LDAP_PROTOCOL_ERROR;
    159  1.1     lukem 	}
    160  1.1     lukem 	user->bv_val[ 0 ] = '\0';
    161  1.1     lukem 	user->bv_val++;
    162  1.1     lukem 	user->bv_len = id->bv_len - ( user->bv_val - id->bv_val );
    163  1.1     lukem 
    164  1.1     lukem 	mech->bv_val = ber_bvchr( id, '.' );
    165  1.1     lukem 	if ( !BER_BVISNULL( mech ) ) {
    166  1.1     lukem 		mech->bv_val[ 0 ] = '\0';
    167  1.1     lukem 		mech->bv_val++;
    168  1.1     lukem 		mech->bv_len = user->bv_val - mech->bv_val - 1;
    169  1.1     lukem 
    170  1.1     lukem 		realm->bv_val = ber_bvchr( mech, '/' );
    171  1.1     lukem 
    172  1.1     lukem 		if ( !BER_BVISNULL( realm ) ) {
    173  1.1     lukem 			realm->bv_val[ 0 ] = '\0';
    174  1.1     lukem 			realm->bv_val++;
    175  1.1     lukem 			mech->bv_len = realm->bv_val - mech->bv_val - 1;
    176  1.1     lukem 			realm->bv_len = user->bv_val - realm->bv_val - 1;
    177  1.1     lukem 		}
    178  1.1     lukem 
    179  1.1     lukem 	} else {
    180  1.1     lukem 		BER_BVZERO( realm );
    181  1.1     lukem 	}
    182  1.1     lukem 
    183  1.1     lukem 	if ( id->bv_val[ 1 ] != '\0' ) {
    184  1.1     lukem 		return LDAP_PROTOCOL_ERROR;
    185  1.1     lukem 	}
    186  1.1     lukem 
    187  1.1     lukem 	if ( !BER_BVISNULL( mech ) ) {
    188  1.1     lukem 		assert( mech->bv_val == id->bv_val + 2 );
    189  1.1     lukem 
    190  1.1     lukem 		AC_MEMCPY( mech->bv_val - 2, mech->bv_val, mech->bv_len + 1 );
    191  1.1     lukem 		mech->bv_val -= 2;
    192  1.1     lukem 	}
    193  1.1     lukem 
    194  1.1     lukem 	if ( !BER_BVISNULL( realm ) ) {
    195  1.1     lukem 		assert( realm->bv_val >= id->bv_val + 2 );
    196  1.1     lukem 
    197  1.1     lukem 		AC_MEMCPY( realm->bv_val - 2, realm->bv_val, realm->bv_len + 1 );
    198  1.1     lukem 		realm->bv_val -= 2;
    199  1.1     lukem 	}
    200  1.1     lukem 
    201  1.1     lukem 	/* leave "u:" before user */
    202  1.1     lukem 	user->bv_val -= 2;
    203  1.1     lukem 	user->bv_len += 2;
    204  1.1     lukem 	user->bv_val[ 0 ] = u;
    205  1.1     lukem 	user->bv_val[ 1 ] = ':';
    206  1.1     lukem 
    207  1.1     lukem 	return LDAP_SUCCESS;
    208  1.1     lukem }
    209  1.1     lukem 
    210  1.1     lukem int
    211  1.1     lukem authzValidate(
    212  1.1     lukem 	Syntax *syntax,
    213  1.1     lukem 	struct berval *in )
    214  1.1     lukem {
    215  1.1     lukem 	struct berval	bv;
    216  1.1     lukem 	int		rc = LDAP_INVALID_SYNTAX;
    217  1.1     lukem 	LDAPURLDesc	*ludp = NULL;
    218  1.1     lukem 	int		scope = -1;
    219  1.1     lukem 
    220  1.1     lukem 	/*
    221  1.1     lukem 	 * 1) <DN>
    222  1.1     lukem 	 * 2) dn[.{exact|children|subtree|onelevel}]:{*|<DN>}
    223  1.1     lukem 	 * 3) dn.regex:<pattern>
    224  1.1     lukem 	 * 4) u[.mech[/realm]]:<ID>
    225  1.1     lukem 	 * 5) group[/<groupClass>[/<memberAttr>]]:<DN>
    226  1.1     lukem 	 * 6) <URL>
    227  1.1     lukem 	 */
    228  1.1     lukem 
    229  1.1     lukem 	assert( in != NULL );
    230  1.1     lukem 	assert( !BER_BVISNULL( in ) );
    231  1.1     lukem 
    232  1.1     lukem 	Debug( LDAP_DEBUG_TRACE,
    233  1.1     lukem 		"authzValidate: parsing %s\n", in->bv_val, 0, 0 );
    234  1.1     lukem 
    235  1.1     lukem 	/*
    236  1.1     lukem 	 * 2) dn[.{exact|children|subtree|onelevel}]:{*|<DN>}
    237  1.1     lukem 	 * 3) dn.regex:<pattern>
    238  1.1     lukem 	 *
    239  1.1     lukem 	 * <DN> must pass DN normalization
    240  1.1     lukem 	 */
    241  1.1     lukem 	if ( !strncasecmp( in->bv_val, "dn", STRLENOF( "dn" ) ) ) {
    242  1.1     lukem 		bv.bv_val = in->bv_val + STRLENOF( "dn" );
    243  1.1     lukem 
    244  1.1     lukem 		if ( bv.bv_val[ 0 ] == '.' ) {
    245  1.1     lukem 			bv.bv_val++;
    246  1.1     lukem 
    247  1.1     lukem 			if ( !strncasecmp( bv.bv_val, "exact:", STRLENOF( "exact:" ) ) ) {
    248  1.1     lukem 				bv.bv_val += STRLENOF( "exact:" );
    249  1.1     lukem 				scope = LDAP_X_SCOPE_EXACT;
    250  1.1     lukem 
    251  1.1     lukem 			} else if ( !strncasecmp( bv.bv_val, "regex:", STRLENOF( "regex:" ) ) ) {
    252  1.1     lukem 				bv.bv_val += STRLENOF( "regex:" );
    253  1.1     lukem 				scope = LDAP_X_SCOPE_REGEX;
    254  1.1     lukem 
    255  1.1     lukem 			} else if ( !strncasecmp( bv.bv_val, "children:", STRLENOF( "children:" ) ) ) {
    256  1.1     lukem 				bv.bv_val += STRLENOF( "children:" );
    257  1.1     lukem 				scope = LDAP_X_SCOPE_CHILDREN;
    258  1.1     lukem 
    259  1.1     lukem 			} else if ( !strncasecmp( bv.bv_val, "subtree:", STRLENOF( "subtree:" ) ) ) {
    260  1.1     lukem 				bv.bv_val += STRLENOF( "subtree:" );
    261  1.1     lukem 				scope = LDAP_X_SCOPE_SUBTREE;
    262  1.1     lukem 
    263  1.1     lukem 			} else if ( !strncasecmp( bv.bv_val, "onelevel:", STRLENOF( "onelevel:" ) ) ) {
    264  1.1     lukem 				bv.bv_val += STRLENOF( "onelevel:" );
    265  1.1     lukem 				scope = LDAP_X_SCOPE_ONELEVEL;
    266  1.1     lukem 
    267  1.1     lukem 			} else {
    268  1.1     lukem 				return LDAP_INVALID_SYNTAX;
    269  1.1     lukem 			}
    270  1.1     lukem 
    271  1.1     lukem 		} else {
    272  1.1     lukem 			if ( bv.bv_val[ 0 ] != ':' ) {
    273  1.1     lukem 				return LDAP_INVALID_SYNTAX;
    274  1.1     lukem 			}
    275  1.1     lukem 			scope = LDAP_X_SCOPE_EXACT;
    276  1.1     lukem 			bv.bv_val++;
    277  1.1     lukem 		}
    278  1.1     lukem 
    279  1.1     lukem 		bv.bv_val += strspn( bv.bv_val, " " );
    280  1.1     lukem 		/* jump here in case no type specification was present
    281  1.1     lukem 		 * and uri was not an URI... HEADS-UP: assuming EXACT */
    282  1.1     lukem is_dn:		bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
    283  1.1     lukem 
    284  1.1     lukem 		/* a single '*' means any DN without using regexes */
    285  1.1     lukem 		if ( ber_bvccmp( &bv, '*' ) ) {
    286  1.1     lukem 			/* LDAP_X_SCOPE_USERS */
    287  1.1     lukem 			return LDAP_SUCCESS;
    288  1.1     lukem 		}
    289  1.1     lukem 
    290  1.1     lukem 		switch ( scope ) {
    291  1.1     lukem 		case LDAP_X_SCOPE_EXACT:
    292  1.1     lukem 		case LDAP_X_SCOPE_CHILDREN:
    293  1.1     lukem 		case LDAP_X_SCOPE_SUBTREE:
    294  1.1     lukem 		case LDAP_X_SCOPE_ONELEVEL:
    295  1.1     lukem 			return dnValidate( NULL, &bv );
    296  1.1     lukem 
    297  1.1     lukem 		case LDAP_X_SCOPE_REGEX:
    298  1.1     lukem 			return LDAP_SUCCESS;
    299  1.1     lukem 		}
    300  1.1     lukem 
    301  1.1     lukem 		return rc;
    302  1.1     lukem 
    303  1.1     lukem 	/*
    304  1.1     lukem 	 * 4) u[.mech[/realm]]:<ID>
    305  1.1     lukem 	 */
    306  1.1     lukem 	} else if ( ( in->bv_val[ 0 ] == 'u' || in->bv_val[ 0 ] == 'U' )
    307  1.1     lukem 			&& ( in->bv_val[ 1 ] == ':'
    308  1.1     lukem 				|| in->bv_val[ 1 ] == '/'
    309  1.1     lukem 				|| in->bv_val[ 1 ] == '.' ) )
    310  1.1     lukem 	{
    311  1.1     lukem 		char		buf[ SLAP_LDAPDN_MAXLEN ];
    312  1.1     lukem 		struct berval	id,
    313  1.1     lukem 				user = BER_BVNULL,
    314  1.1     lukem 				realm = BER_BVNULL,
    315  1.1     lukem 				mech = BER_BVNULL;
    316  1.1     lukem 
    317  1.1     lukem 		if ( sizeof( buf ) <= in->bv_len ) {
    318  1.1     lukem 			return LDAP_INVALID_SYNTAX;
    319  1.1     lukem 		}
    320  1.1     lukem 
    321  1.1     lukem 		id.bv_len = in->bv_len;
    322  1.1     lukem 		id.bv_val = buf;
    323  1.1     lukem 		strncpy( buf, in->bv_val, sizeof( buf ) );
    324  1.1     lukem 
    325  1.1     lukem 		rc = slap_parse_user( &id, &user, &realm, &mech );
    326  1.1     lukem 		if ( rc != LDAP_SUCCESS ) {
    327  1.1     lukem 			return LDAP_INVALID_SYNTAX;
    328  1.1     lukem 		}
    329  1.1     lukem 
    330  1.1     lukem 		return rc;
    331  1.1     lukem 
    332  1.1     lukem 	/*
    333  1.1     lukem 	 * 5) group[/groupClass[/memberAttr]]:<DN>
    334  1.1     lukem 	 *
    335  1.1     lukem 	 * <groupClass> defaults to "groupOfNames"
    336  1.1     lukem 	 * <memberAttr> defaults to "member"
    337  1.1     lukem 	 *
    338  1.1     lukem 	 * <DN> must pass DN normalization
    339  1.1     lukem 	 */
    340  1.1     lukem 	} else if ( strncasecmp( in->bv_val, "group", STRLENOF( "group" ) ) == 0 )
    341  1.1     lukem 	{
    342  1.1     lukem 		struct berval	group_dn = BER_BVNULL,
    343  1.1     lukem 				group_oc = BER_BVNULL,
    344  1.1     lukem 				member_at = BER_BVNULL;
    345  1.1     lukem 
    346  1.1     lukem 		bv.bv_val = in->bv_val + STRLENOF( "group" );
    347  1.1     lukem 		bv.bv_len = in->bv_len - STRLENOF( "group" );
    348  1.1     lukem 		group_dn.bv_val = ber_bvchr( &bv, ':' );
    349  1.1     lukem 		if ( group_dn.bv_val == NULL ) {
    350  1.1     lukem 			/* last chance: assume it's a(n exact) DN ... */
    351  1.1     lukem 			bv.bv_val = in->bv_val;
    352  1.1     lukem 			scope = LDAP_X_SCOPE_EXACT;
    353  1.1     lukem 			goto is_dn;
    354  1.1     lukem 		}
    355  1.1     lukem 
    356  1.1     lukem 		/*
    357  1.1     lukem 		 * FIXME: we assume that "member" and "groupOfNames"
    358  1.1     lukem 		 * are present in schema...
    359  1.1     lukem 		 */
    360  1.1     lukem 		if ( bv.bv_val[ 0 ] == '/' ) {
    361  1.1     lukem 			group_oc.bv_val = &bv.bv_val[ 1 ];
    362  1.1     lukem 			group_oc.bv_len = group_dn.bv_val - group_oc.bv_val;
    363  1.1     lukem 
    364  1.1     lukem 			member_at.bv_val = ber_bvchr( &group_oc, '/' );
    365  1.1     lukem 			if ( member_at.bv_val ) {
    366  1.1     lukem 				AttributeDescription	*ad = NULL;
    367  1.1     lukem 				const char		*text = NULL;
    368  1.1     lukem 
    369  1.1     lukem 				group_oc.bv_len = member_at.bv_val - group_oc.bv_val;
    370  1.1     lukem 				member_at.bv_val++;
    371  1.1     lukem 				member_at.bv_len = group_dn.bv_val - member_at.bv_val;
    372  1.1     lukem 				rc = slap_bv2ad( &member_at, &ad, &text );
    373  1.1     lukem 				if ( rc != LDAP_SUCCESS ) {
    374  1.1     lukem 					return rc;
    375  1.1     lukem 				}
    376  1.1     lukem 			}
    377  1.1     lukem 
    378  1.1     lukem 			if ( oc_bvfind( &group_oc ) == NULL ) {
    379  1.1     lukem 				return LDAP_INVALID_SYNTAX;
    380  1.1     lukem 			}
    381  1.1     lukem 		}
    382  1.1     lukem 
    383  1.1     lukem 		group_dn.bv_val++;
    384  1.1     lukem 		group_dn.bv_len = in->bv_len - ( group_dn.bv_val - in->bv_val );
    385  1.1     lukem 
    386  1.1     lukem 		rc = dnValidate( NULL, &group_dn );
    387  1.1     lukem 		if ( rc != LDAP_SUCCESS ) {
    388  1.1     lukem 			return rc;
    389  1.1     lukem 		}
    390  1.1     lukem 
    391  1.1     lukem 		return rc;
    392  1.1     lukem 	}
    393  1.1     lukem 
    394  1.1     lukem 	/*
    395  1.1     lukem 	 * ldap:///<base>??<scope>?<filter>
    396  1.1     lukem 	 * <scope> ::= {base|one|subtree}
    397  1.1     lukem 	 *
    398  1.1     lukem 	 * <scope> defaults to "base"
    399  1.1     lukem 	 * <base> must pass DN normalization
    400  1.1     lukem 	 * <filter> must pass str2filter()
    401  1.1     lukem 	 */
    402  1.1     lukem 	rc = ldap_url_parse( in->bv_val, &ludp );
    403  1.1     lukem 	switch ( rc ) {
    404  1.1     lukem 	case LDAP_URL_SUCCESS:
    405  1.1     lukem 		/* FIXME: the check is pedantic, but I think it's necessary,
    406  1.1     lukem 		 * because people tend to use things like ldaps:// which
    407  1.1     lukem 		 * gives the idea SSL is being used.  Maybe we could
    408  1.1     lukem 		 * accept ldapi:// as well, but the point is that we use
    409  1.1     lukem 		 * an URL as an easy means to define bits of a search with
    410  1.1     lukem 		 * little parsing.
    411  1.1     lukem 		 */
    412  1.1     lukem 		if ( strcasecmp( ludp->lud_scheme, "ldap" ) != 0 ) {
    413  1.1     lukem 			/*
    414  1.1     lukem 			 * must be ldap:///
    415  1.1     lukem 			 */
    416  1.1     lukem 			rc = LDAP_INVALID_SYNTAX;
    417  1.1     lukem 			goto done;
    418  1.1     lukem 		}
    419  1.1     lukem 		break;
    420  1.1     lukem 
    421  1.1     lukem 	case LDAP_URL_ERR_BADSCHEME:
    422  1.1     lukem 		/*
    423  1.1     lukem 		 * last chance: assume it's a(n exact) DN ...
    424  1.1     lukem 		 *
    425  1.1     lukem 		 * NOTE: must pass DN normalization
    426  1.1     lukem 		 */
    427  1.1     lukem 		ldap_free_urldesc( ludp );
    428  1.1     lukem 		bv.bv_val = in->bv_val;
    429  1.1     lukem 		scope = LDAP_X_SCOPE_EXACT;
    430  1.1     lukem 		goto is_dn;
    431  1.1     lukem 
    432  1.1     lukem 	default:
    433  1.1     lukem 		rc = LDAP_INVALID_SYNTAX;
    434  1.1     lukem 		goto done;
    435  1.1     lukem 	}
    436  1.1     lukem 
    437  1.1     lukem 	if ( ( ludp->lud_host && *ludp->lud_host )
    438  1.1     lukem 		|| ludp->lud_attrs || ludp->lud_exts )
    439  1.1     lukem 	{
    440  1.1     lukem 		/* host part must be empty */
    441  1.1     lukem 		/* attrs and extensions parts must be empty */
    442  1.1     lukem 		rc = LDAP_INVALID_SYNTAX;
    443  1.1     lukem 		goto done;
    444  1.1     lukem 	}
    445  1.1     lukem 
    446  1.1     lukem 	/* Grab the filter */
    447  1.1     lukem 	if ( ludp->lud_filter ) {
    448  1.1     lukem 		Filter	*f = str2filter( ludp->lud_filter );
    449  1.1     lukem 		if ( f == NULL ) {
    450  1.1     lukem 			rc = LDAP_INVALID_SYNTAX;
    451  1.1     lukem 			goto done;
    452  1.1     lukem 		}
    453  1.1     lukem 		filter_free( f );
    454  1.1     lukem 	}
    455  1.1     lukem 
    456  1.1     lukem 	/* Grab the searchbase */
    457  1.1     lukem 	assert( ludp->lud_dn != NULL );
    458  1.1     lukem 	ber_str2bv( ludp->lud_dn, 0, 0, &bv );
    459  1.1     lukem 	rc = dnValidate( NULL, &bv );
    460  1.1     lukem 
    461  1.1     lukem done:
    462  1.1     lukem 	ldap_free_urldesc( ludp );
    463  1.1     lukem 	return( rc );
    464  1.1     lukem }
    465  1.1     lukem 
    466  1.1     lukem static int
    467  1.1     lukem authzPrettyNormal(
    468  1.1     lukem 	struct berval	*val,
    469  1.1     lukem 	struct berval	*normalized,
    470  1.1     lukem 	void		*ctx,
    471  1.1     lukem 	int		normalize )
    472  1.1     lukem {
    473  1.1     lukem 	struct berval	bv;
    474  1.1     lukem 	int		rc = LDAP_INVALID_SYNTAX;
    475  1.1     lukem 	LDAPURLDesc	*ludp = NULL;
    476  1.1     lukem 	char		*lud_dn = NULL,
    477  1.1     lukem 			*lud_filter = NULL;
    478  1.1     lukem 	int		scope = -1;
    479  1.1     lukem 
    480  1.1     lukem 	/*
    481  1.1     lukem 	 * 1) <DN>
    482  1.1     lukem 	 * 2) dn[.{exact|children|subtree|onelevel}]:{*|<DN>}
    483  1.1     lukem 	 * 3) dn.regex:<pattern>
    484  1.1     lukem 	 * 4) u[.mech[/realm]]:<ID>
    485  1.1     lukem 	 * 5) group[/<groupClass>[/<memberAttr>]]:<DN>
    486  1.1     lukem 	 * 6) <URL>
    487  1.1     lukem 	 */
    488  1.1     lukem 
    489  1.1     lukem 	assert( val != NULL );
    490  1.1     lukem 	assert( !BER_BVISNULL( val ) );
    491  1.1     lukem 
    492  1.1     lukem 	/*
    493  1.1     lukem 	 * 2) dn[.{exact|children|subtree|onelevel}]:{*|<DN>}
    494  1.1     lukem 	 * 3) dn.regex:<pattern>
    495  1.1     lukem 	 *
    496  1.1     lukem 	 * <DN> must pass DN normalization
    497  1.1     lukem 	 */
    498  1.1     lukem 	if ( !strncasecmp( val->bv_val, "dn", STRLENOF( "dn" ) ) ) {
    499  1.1     lukem 		struct berval	out = BER_BVNULL,
    500  1.1     lukem 				prefix = BER_BVNULL;
    501  1.1     lukem 		char		*ptr;
    502  1.1     lukem 
    503  1.1     lukem 		bv.bv_val = val->bv_val + STRLENOF( "dn" );
    504  1.1     lukem 
    505  1.1     lukem 		if ( bv.bv_val[ 0 ] == '.' ) {
    506  1.1     lukem 			bv.bv_val++;
    507  1.1     lukem 
    508  1.1     lukem 			if ( !strncasecmp( bv.bv_val, "exact:", STRLENOF( "exact:" ) ) ) {
    509  1.1     lukem 				bv.bv_val += STRLENOF( "exact:" );
    510  1.1     lukem 				scope = LDAP_X_SCOPE_EXACT;
    511  1.1     lukem 
    512  1.1     lukem 			} else if ( !strncasecmp( bv.bv_val, "regex:", STRLENOF( "regex:" ) ) ) {
    513  1.1     lukem 				bv.bv_val += STRLENOF( "regex:" );
    514  1.1     lukem 				scope = LDAP_X_SCOPE_REGEX;
    515  1.1     lukem 
    516  1.1     lukem 			} else if ( !strncasecmp( bv.bv_val, "children:", STRLENOF( "children:" ) ) ) {
    517  1.1     lukem 				bv.bv_val += STRLENOF( "children:" );
    518  1.1     lukem 				scope = LDAP_X_SCOPE_CHILDREN;
    519  1.1     lukem 
    520  1.1     lukem 			} else if ( !strncasecmp( bv.bv_val, "subtree:", STRLENOF( "subtree:" ) ) ) {
    521  1.1     lukem 				bv.bv_val += STRLENOF( "subtree:" );
    522  1.1     lukem 				scope = LDAP_X_SCOPE_SUBTREE;
    523  1.1     lukem 
    524  1.1     lukem 			} else if ( !strncasecmp( bv.bv_val, "onelevel:", STRLENOF( "onelevel:" ) ) ) {
    525  1.1     lukem 				bv.bv_val += STRLENOF( "onelevel:" );
    526  1.1     lukem 				scope = LDAP_X_SCOPE_ONELEVEL;
    527  1.1     lukem 
    528  1.1     lukem 			} else {
    529  1.1     lukem 				return LDAP_INVALID_SYNTAX;
    530  1.1     lukem 			}
    531  1.1     lukem 
    532  1.1     lukem 		} else {
    533  1.1     lukem 			if ( bv.bv_val[ 0 ] != ':' ) {
    534  1.1     lukem 				return LDAP_INVALID_SYNTAX;
    535  1.1     lukem 			}
    536  1.1     lukem 			scope = LDAP_X_SCOPE_EXACT;
    537  1.1     lukem 			bv.bv_val++;
    538  1.1     lukem 		}
    539  1.1     lukem 
    540  1.1     lukem 		bv.bv_val += strspn( bv.bv_val, " " );
    541  1.1     lukem 		/* jump here in case no type specification was present
    542  1.1     lukem 		 * and uri was not an URI... HEADS-UP: assuming EXACT */
    543  1.1     lukem is_dn:		bv.bv_len = val->bv_len - ( bv.bv_val - val->bv_val );
    544  1.1     lukem 
    545  1.1     lukem 		/* a single '*' means any DN without using regexes */
    546  1.1     lukem 		if ( ber_bvccmp( &bv, '*' ) ) {
    547  1.1     lukem 			ber_str2bv_x( "dn:*", STRLENOF( "dn:*" ), 1, normalized, ctx );
    548  1.1     lukem 			return LDAP_SUCCESS;
    549  1.1     lukem 		}
    550  1.1     lukem 
    551  1.1     lukem 		switch ( scope ) {
    552  1.1     lukem 		case LDAP_X_SCOPE_EXACT:
    553  1.1     lukem 		case LDAP_X_SCOPE_CHILDREN:
    554  1.1     lukem 		case LDAP_X_SCOPE_SUBTREE:
    555  1.1     lukem 		case LDAP_X_SCOPE_ONELEVEL:
    556  1.1     lukem 			if ( normalize ) {
    557  1.1     lukem 				rc = dnNormalize( 0, NULL, NULL, &bv, &out, ctx );
    558  1.1     lukem 			} else {
    559  1.1     lukem 				rc = dnPretty( NULL, &bv, &out, ctx );
    560  1.1     lukem 			}
    561  1.1     lukem 			if( rc != LDAP_SUCCESS ) {
    562  1.1     lukem 				return LDAP_INVALID_SYNTAX;
    563  1.1     lukem 			}
    564  1.1     lukem 			break;
    565  1.1     lukem 
    566  1.1     lukem 		case LDAP_X_SCOPE_REGEX:
    567  1.1     lukem 			normalized->bv_len = STRLENOF( "dn.regex:" ) + bv.bv_len;
    568  1.1     lukem 			normalized->bv_val = ber_memalloc_x( normalized->bv_len + 1, ctx );
    569  1.1     lukem 			ptr = lutil_strcopy( normalized->bv_val, "dn.regex:" );
    570  1.1     lukem 			ptr = lutil_strncopy( ptr, bv.bv_val, bv.bv_len );
    571  1.1     lukem 			ptr[ 0 ] = '\0';
    572  1.1     lukem 			return LDAP_SUCCESS;
    573  1.1     lukem 
    574  1.1     lukem 		default:
    575  1.1     lukem 			return LDAP_INVALID_SYNTAX;
    576  1.1     lukem 		}
    577  1.1     lukem 
    578  1.1     lukem 		/* prepare prefix */
    579  1.1     lukem 		switch ( scope ) {
    580  1.1     lukem 		case LDAP_X_SCOPE_EXACT:
    581  1.1     lukem 			BER_BVSTR( &prefix, "dn:" );
    582  1.1     lukem 			break;
    583  1.1     lukem 
    584  1.1     lukem 		case LDAP_X_SCOPE_CHILDREN:
    585  1.1     lukem 			BER_BVSTR( &prefix, "dn.children:" );
    586  1.1     lukem 			break;
    587  1.1     lukem 
    588  1.1     lukem 		case LDAP_X_SCOPE_SUBTREE:
    589  1.1     lukem 			BER_BVSTR( &prefix, "dn.subtree:" );
    590  1.1     lukem 			break;
    591  1.1     lukem 
    592  1.1     lukem 		case LDAP_X_SCOPE_ONELEVEL:
    593  1.1     lukem 			BER_BVSTR( &prefix, "dn.onelevel:" );
    594  1.1     lukem 			break;
    595  1.1     lukem 
    596  1.1     lukem 		default:
    597  1.1     lukem 			assert( 0 );
    598  1.1     lukem 			break;
    599  1.1     lukem 		}
    600  1.1     lukem 
    601  1.1     lukem 		normalized->bv_len = prefix.bv_len + out.bv_len;
    602  1.1     lukem 		normalized->bv_val = ber_memalloc_x( normalized->bv_len + 1, ctx );
    603  1.1     lukem 
    604  1.1     lukem 		ptr = lutil_strcopy( normalized->bv_val, prefix.bv_val );
    605  1.1     lukem 		ptr = lutil_strncopy( ptr, out.bv_val, out.bv_len );
    606  1.1     lukem 		ptr[ 0 ] = '\0';
    607  1.1     lukem 		ber_memfree_x( out.bv_val, ctx );
    608  1.1     lukem 
    609  1.1     lukem 		return LDAP_SUCCESS;
    610  1.1     lukem 
    611  1.1     lukem 	/*
    612  1.1     lukem 	 * 4) u[.mech[/realm]]:<ID>
    613  1.1     lukem 	 */
    614  1.1     lukem 	} else if ( ( val->bv_val[ 0 ] == 'u' || val->bv_val[ 0 ] == 'U' )
    615  1.1     lukem 			&& ( val->bv_val[ 1 ] == ':'
    616  1.1     lukem 				|| val->bv_val[ 1 ] == '/'
    617  1.1     lukem 				|| val->bv_val[ 1 ] == '.' ) )
    618  1.1     lukem 	{
    619  1.1     lukem 		char		buf[ SLAP_LDAPDN_MAXLEN ];
    620  1.1     lukem 		struct berval	id,
    621  1.1     lukem 				user = BER_BVNULL,
    622  1.1     lukem 				realm = BER_BVNULL,
    623  1.1     lukem 				mech = BER_BVNULL;
    624  1.1     lukem 
    625  1.1     lukem 		if ( sizeof( buf ) <= val->bv_len ) {
    626  1.1     lukem 			return LDAP_INVALID_SYNTAX;
    627  1.1     lukem 		}
    628  1.1     lukem 
    629  1.1     lukem 		id.bv_len = val->bv_len;
    630  1.1     lukem 		id.bv_val = buf;
    631  1.1     lukem 		strncpy( buf, val->bv_val, sizeof( buf ) );
    632  1.1     lukem 
    633  1.1     lukem 		rc = slap_parse_user( &id, &user, &realm, &mech );
    634  1.1     lukem 		if ( rc != LDAP_SUCCESS ) {
    635  1.1     lukem 			return LDAP_INVALID_SYNTAX;
    636  1.1     lukem 		}
    637  1.1     lukem 
    638  1.1     lukem 		ber_dupbv_x( normalized, val, ctx );
    639  1.1     lukem 
    640  1.1     lukem 		return rc;
    641  1.1     lukem 
    642  1.1     lukem 	/*
    643  1.1     lukem 	 * 5) group[/groupClass[/memberAttr]]:<DN>
    644  1.1     lukem 	 *
    645  1.1     lukem 	 * <groupClass> defaults to "groupOfNames"
    646  1.1     lukem 	 * <memberAttr> defaults to "member"
    647  1.1     lukem 	 *
    648  1.1     lukem 	 * <DN> must pass DN normalization
    649  1.1     lukem 	 */
    650  1.1     lukem 	} else if ( strncasecmp( val->bv_val, "group", STRLENOF( "group" ) ) == 0 )
    651  1.1     lukem 	{
    652  1.1     lukem 		struct berval	group_dn = BER_BVNULL,
    653  1.1     lukem 				group_oc = BER_BVNULL,
    654  1.1     lukem 				member_at = BER_BVNULL,
    655  1.1     lukem 				out = BER_BVNULL;
    656  1.1     lukem 		char		*ptr;
    657  1.1     lukem 
    658  1.1     lukem 		bv.bv_val = val->bv_val + STRLENOF( "group" );
    659  1.1     lukem 		bv.bv_len = val->bv_len - STRLENOF( "group" );
    660  1.1     lukem 		group_dn.bv_val = ber_bvchr( &bv, ':' );
    661  1.1     lukem 		if ( group_dn.bv_val == NULL ) {
    662  1.1     lukem 			/* last chance: assume it's a(n exact) DN ... */
    663  1.1     lukem 			bv.bv_val = val->bv_val;
    664  1.1     lukem 			scope = LDAP_X_SCOPE_EXACT;
    665  1.1     lukem 			goto is_dn;
    666  1.1     lukem 		}
    667  1.1     lukem 
    668  1.1     lukem 		/*
    669  1.1     lukem 		 * FIXME: we assume that "member" and "groupOfNames"
    670  1.1     lukem 		 * are present in schema...
    671  1.1     lukem 		 */
    672  1.1     lukem 		if ( bv.bv_val[ 0 ] == '/' ) {
    673  1.1     lukem 			ObjectClass		*oc = NULL;
    674  1.1     lukem 
    675  1.1     lukem 			group_oc.bv_val = &bv.bv_val[ 1 ];
    676  1.1     lukem 			group_oc.bv_len = group_dn.bv_val - group_oc.bv_val;
    677  1.1     lukem 
    678  1.1     lukem 			member_at.bv_val = ber_bvchr( &group_oc, '/' );
    679  1.1     lukem 			if ( member_at.bv_val ) {
    680  1.1     lukem 				AttributeDescription	*ad = NULL;
    681  1.1     lukem 				const char		*text = NULL;
    682  1.1     lukem 
    683  1.1     lukem 				group_oc.bv_len = member_at.bv_val - group_oc.bv_val;
    684  1.1     lukem 				member_at.bv_val++;
    685  1.1     lukem 				member_at.bv_len = group_dn.bv_val - member_at.bv_val;
    686  1.1     lukem 				rc = slap_bv2ad( &member_at, &ad, &text );
    687  1.1     lukem 				if ( rc != LDAP_SUCCESS ) {
    688  1.1     lukem 					return rc;
    689  1.1     lukem 				}
    690  1.1     lukem 
    691  1.1     lukem 				member_at = ad->ad_cname;
    692  1.1     lukem 
    693  1.1     lukem 			}
    694  1.1     lukem 
    695  1.1     lukem 			oc = oc_bvfind( &group_oc );
    696  1.1     lukem 			if ( oc == NULL ) {
    697  1.1     lukem 				return LDAP_INVALID_SYNTAX;
    698  1.1     lukem 			}
    699  1.1     lukem 
    700  1.1     lukem 			group_oc = oc->soc_cname;
    701  1.1     lukem 		}
    702  1.1     lukem 
    703  1.1     lukem 		group_dn.bv_val++;
    704  1.1     lukem 		group_dn.bv_len = val->bv_len - ( group_dn.bv_val - val->bv_val );
    705  1.1     lukem 
    706  1.1     lukem 		if ( normalize ) {
    707  1.1     lukem 			rc = dnNormalize( 0, NULL, NULL, &group_dn, &out, ctx );
    708  1.1     lukem 		} else {
    709  1.1     lukem 			rc = dnPretty( NULL, &group_dn, &out, ctx );
    710  1.1     lukem 		}
    711  1.1     lukem 		if ( rc != LDAP_SUCCESS ) {
    712  1.1     lukem 			return rc;
    713  1.1     lukem 		}
    714  1.1     lukem 
    715  1.1     lukem 		normalized->bv_len = STRLENOF( "group" ":" ) + out.bv_len;
    716  1.1     lukem 		if ( !BER_BVISNULL( &group_oc ) ) {
    717  1.1     lukem 			normalized->bv_len += STRLENOF( "/" ) + group_oc.bv_len;
    718  1.1     lukem 			if ( !BER_BVISNULL( &member_at ) ) {
    719  1.1     lukem 				normalized->bv_len += STRLENOF( "/" ) + member_at.bv_len;
    720  1.1     lukem 			}
    721  1.1     lukem 		}
    722  1.1     lukem 
    723  1.1     lukem 		normalized->bv_val = ber_memalloc_x( normalized->bv_len + 1, ctx );
    724  1.1     lukem 		ptr = lutil_strcopy( normalized->bv_val, "group" );
    725  1.1     lukem 		if ( !BER_BVISNULL( &group_oc ) ) {
    726  1.1     lukem 			ptr[ 0 ] = '/';
    727  1.1     lukem 			ptr++;
    728  1.1     lukem 			ptr = lutil_strncopy( ptr, group_oc.bv_val, group_oc.bv_len );
    729  1.1     lukem 			if ( !BER_BVISNULL( &member_at ) ) {
    730  1.1     lukem 				ptr[ 0 ] = '/';
    731  1.1     lukem 				ptr++;
    732  1.1     lukem 				ptr = lutil_strncopy( ptr, member_at.bv_val, member_at.bv_len );
    733  1.1     lukem 			}
    734  1.1     lukem 		}
    735  1.1     lukem 		ptr[ 0 ] = ':';
    736  1.1     lukem 		ptr++;
    737  1.1     lukem 		ptr = lutil_strncopy( ptr, out.bv_val, out.bv_len );
    738  1.1     lukem 		ptr[ 0 ] = '\0';
    739  1.1     lukem 		ber_memfree_x( out.bv_val, ctx );
    740  1.1     lukem 
    741  1.1     lukem 		return rc;
    742  1.1     lukem 	}
    743  1.1     lukem 
    744  1.1     lukem 	/*
    745  1.1     lukem 	 * ldap:///<base>??<scope>?<filter>
    746  1.1     lukem 	 * <scope> ::= {base|one|subtree}
    747  1.1     lukem 	 *
    748  1.1     lukem 	 * <scope> defaults to "base"
    749  1.1     lukem 	 * <base> must pass DN normalization
    750  1.1     lukem 	 * <filter> must pass str2filter()
    751  1.1     lukem 	 */
    752  1.1     lukem 	rc = ldap_url_parse( val->bv_val, &ludp );
    753  1.1     lukem 	switch ( rc ) {
    754  1.1     lukem 	case LDAP_URL_SUCCESS:
    755  1.1     lukem 		/* FIXME: the check is pedantic, but I think it's necessary,
    756  1.1     lukem 		 * because people tend to use things like ldaps:// which
    757  1.1     lukem 		 * gives the idea SSL is being used.  Maybe we could
    758  1.1     lukem 		 * accept ldapi:// as well, but the point is that we use
    759  1.1     lukem 		 * an URL as an easy means to define bits of a search with
    760  1.1     lukem 		 * little parsing.
    761  1.1     lukem 		 */
    762  1.1     lukem 		if ( strcasecmp( ludp->lud_scheme, "ldap" ) != 0 ) {
    763  1.1     lukem 			/*
    764  1.1     lukem 			 * must be ldap:///
    765  1.1     lukem 			 */
    766  1.1     lukem 			rc = LDAP_INVALID_SYNTAX;
    767  1.1     lukem 			goto done;
    768  1.1     lukem 		}
    769  1.1     lukem 
    770  1.1     lukem 		AC_MEMCPY( ludp->lud_scheme, "ldap", STRLENOF( "ldap" ) );
    771  1.1     lukem 		break;
    772  1.1     lukem 
    773  1.1     lukem 	case LDAP_URL_ERR_BADSCHEME:
    774  1.1     lukem 		/*
    775  1.1     lukem 		 * last chance: assume it's a(n exact) DN ...
    776  1.1     lukem 		 *
    777  1.1     lukem 		 * NOTE: must pass DN normalization
    778  1.1     lukem 		 */
    779  1.1     lukem 		ldap_free_urldesc( ludp );
    780  1.1     lukem 		bv.bv_val = val->bv_val;
    781  1.1     lukem 		scope = LDAP_X_SCOPE_EXACT;
    782  1.1     lukem 		goto is_dn;
    783  1.1     lukem 
    784  1.1     lukem 	default:
    785  1.1     lukem 		rc = LDAP_INVALID_SYNTAX;
    786  1.1     lukem 		goto done;
    787  1.1     lukem 	}
    788  1.1     lukem 
    789  1.1     lukem 	if ( ( ludp->lud_host && *ludp->lud_host )
    790  1.1     lukem 		|| ludp->lud_attrs || ludp->lud_exts )
    791  1.1     lukem 	{
    792  1.1     lukem 		/* host part must be empty */
    793  1.1     lukem 		/* attrs and extensions parts must be empty */
    794  1.1     lukem 		rc = LDAP_INVALID_SYNTAX;
    795  1.1     lukem 		goto done;
    796  1.1     lukem 	}
    797  1.1     lukem 
    798  1.1     lukem 	/* Grab the filter */
    799  1.1     lukem 	if ( ludp->lud_filter ) {
    800  1.1     lukem 		struct berval	filterstr;
    801  1.1     lukem 		Filter		*f;
    802  1.1     lukem 
    803  1.1     lukem 		lud_filter = ludp->lud_filter;
    804  1.1     lukem 
    805  1.1     lukem 		f = str2filter( lud_filter );
    806  1.1     lukem 		if ( f == NULL ) {
    807  1.1     lukem 			rc = LDAP_INVALID_SYNTAX;
    808  1.1     lukem 			goto done;
    809  1.1     lukem 		}
    810  1.1     lukem 		filter2bv( f, &filterstr );
    811  1.1     lukem 		filter_free( f );
    812  1.1     lukem 		if ( BER_BVISNULL( &filterstr ) ) {
    813  1.1     lukem 			rc = LDAP_INVALID_SYNTAX;
    814  1.1     lukem 			goto done;
    815  1.1     lukem 		}
    816  1.1     lukem 
    817  1.1     lukem 		ludp->lud_filter = filterstr.bv_val;
    818  1.1     lukem 	}
    819  1.1     lukem 
    820  1.1     lukem 	/* Grab the searchbase */
    821  1.1     lukem 	assert( ludp->lud_dn != NULL );
    822  1.1     lukem 	if ( ludp->lud_dn ) {
    823  1.1     lukem 		struct berval	out = BER_BVNULL;
    824  1.1     lukem 
    825  1.1     lukem 		lud_dn = ludp->lud_dn;
    826  1.1     lukem 
    827  1.1     lukem 		ber_str2bv( lud_dn, 0, 0, &bv );
    828  1.1     lukem 		if ( normalize ) {
    829  1.1     lukem 			rc = dnNormalize( 0, NULL, NULL, &bv, &out, ctx );
    830  1.1     lukem 		} else {
    831  1.1     lukem 			rc = dnPretty( NULL, &bv, &out, ctx );
    832  1.1     lukem 		}
    833  1.1     lukem 
    834  1.1     lukem 		if ( rc != LDAP_SUCCESS ) {
    835  1.1     lukem 			goto done;
    836  1.1     lukem 		}
    837  1.1     lukem 
    838  1.1     lukem 		ludp->lud_dn = out.bv_val;
    839  1.1     lukem 	}
    840  1.1     lukem 
    841  1.1     lukem 	ludp->lud_port = 0;
    842  1.1     lukem 	normalized->bv_val = ldap_url_desc2str( ludp );
    843  1.1     lukem 	if ( normalized->bv_val ) {
    844  1.1     lukem 		normalized->bv_len = strlen( normalized->bv_val );
    845  1.1     lukem 
    846  1.1     lukem 	} else {
    847  1.1     lukem 		rc = LDAP_INVALID_SYNTAX;
    848  1.1     lukem 	}
    849  1.1     lukem 
    850  1.1     lukem done:
    851  1.1     lukem 	if ( lud_filter ) {
    852  1.1     lukem 		if ( ludp->lud_filter != lud_filter ) {
    853  1.1     lukem 			ber_memfree( ludp->lud_filter );
    854  1.1     lukem 		}
    855  1.1     lukem 		ludp->lud_filter = lud_filter;
    856  1.1     lukem 	}
    857  1.1     lukem 
    858  1.1     lukem 	if ( lud_dn ) {
    859  1.1     lukem 		if ( ludp->lud_dn != lud_dn ) {
    860  1.1     lukem 			ber_memfree( ludp->lud_dn );
    861  1.1     lukem 		}
    862  1.1     lukem 		ludp->lud_dn = lud_dn;
    863  1.1     lukem 	}
    864  1.1     lukem 
    865  1.1     lukem 	ldap_free_urldesc( ludp );
    866  1.1     lukem 
    867  1.1     lukem 	return( rc );
    868  1.1     lukem }
    869  1.1     lukem 
    870  1.1     lukem int
    871  1.1     lukem authzNormalize(
    872  1.1     lukem 	slap_mask_t	usage,
    873  1.1     lukem 	Syntax		*syntax,
    874  1.1     lukem 	MatchingRule	*mr,
    875  1.1     lukem 	struct berval	*val,
    876  1.1     lukem 	struct berval	*normalized,
    877  1.1     lukem 	void		*ctx )
    878  1.1     lukem {
    879  1.1     lukem 	int		rc;
    880  1.1     lukem 
    881  1.1     lukem 	Debug( LDAP_DEBUG_TRACE, ">>> authzNormalize: <%s>\n",
    882  1.1     lukem 		val->bv_val, 0, 0 );
    883  1.1     lukem 
    884  1.1     lukem 	rc = authzPrettyNormal( val, normalized, ctx, 1 );
    885  1.1     lukem 
    886  1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "<<< authzNormalize: <%s> (%d)\n",
    887  1.1     lukem 		normalized->bv_val, rc, 0 );
    888  1.1     lukem 
    889  1.1     lukem 	return rc;
    890  1.1     lukem }
    891  1.1     lukem 
    892  1.1     lukem int
    893  1.1     lukem authzPretty(
    894  1.1     lukem 	Syntax *syntax,
    895  1.1     lukem 	struct berval *val,
    896  1.1     lukem 	struct berval *out,
    897  1.1     lukem 	void *ctx)
    898  1.1     lukem {
    899  1.1     lukem 	int		rc;
    900  1.1     lukem 
    901  1.1     lukem 	Debug( LDAP_DEBUG_TRACE, ">>> authzPretty: <%s>\n",
    902  1.1     lukem 		val->bv_val, 0, 0 );
    903  1.1     lukem 
    904  1.1     lukem 	rc = authzPrettyNormal( val, out, ctx, 0 );
    905  1.1     lukem 
    906  1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "<<< authzPretty: <%s> (%d)\n",
    907  1.1     lukem 		out->bv_val, rc, 0 );
    908  1.1     lukem 
    909  1.1     lukem 	return rc;
    910  1.1     lukem }
    911  1.1     lukem 
    912  1.1     lukem 
    913  1.1     lukem static int
    914  1.1     lukem slap_parseURI(
    915  1.1     lukem 	Operation	*op,
    916  1.1     lukem 	struct berval	*uri,
    917  1.1     lukem 	struct berval	*base,
    918  1.1     lukem 	struct berval	*nbase,
    919  1.1     lukem 	int		*scope,
    920  1.1     lukem 	Filter		**filter,
    921  1.1     lukem 	struct berval	*fstr,
    922  1.1     lukem 	int		normalize )
    923  1.1     lukem {
    924  1.1     lukem 	struct berval	bv;
    925  1.1     lukem 	int		rc;
    926  1.1     lukem 	LDAPURLDesc	*ludp;
    927  1.1     lukem 
    928  1.1     lukem 	struct berval	idx;
    929  1.1     lukem 
    930  1.1     lukem 	assert( uri != NULL && !BER_BVISNULL( uri ) );
    931  1.1     lukem 	BER_BVZERO( base );
    932  1.1     lukem 	BER_BVZERO( nbase );
    933  1.1     lukem 	BER_BVZERO( fstr );
    934  1.1     lukem 	*scope = -1;
    935  1.1     lukem 	*filter = NULL;
    936  1.1     lukem 
    937  1.1     lukem 	Debug( LDAP_DEBUG_TRACE,
    938  1.1     lukem 		"slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
    939  1.1     lukem 
    940  1.1     lukem 	rc = LDAP_PROTOCOL_ERROR;
    941  1.1     lukem 
    942  1.1     lukem 	idx = *uri;
    943  1.1     lukem 	if ( idx.bv_val[ 0 ] == '{' ) {
    944  1.1     lukem 		char	*ptr;
    945  1.1     lukem 
    946  1.1     lukem 		ptr = ber_bvchr( &idx, '}' ) + 1;
    947  1.1     lukem 
    948  1.1     lukem 		assert( ptr != (void *)1 );
    949  1.1     lukem 
    950  1.1     lukem 		idx.bv_len -= ptr - idx.bv_val;
    951  1.1     lukem 		idx.bv_val = ptr;
    952  1.1     lukem 		uri = &idx;
    953  1.1     lukem 	}
    954  1.1     lukem 
    955  1.1     lukem 	/*
    956  1.1     lukem 	 * dn[.<dnstyle>]:<dnpattern>
    957  1.1     lukem 	 * <dnstyle> ::= {exact|regex|children|subtree|onelevel}
    958  1.1     lukem 	 *
    959  1.1     lukem 	 * <dnstyle> defaults to "exact"
    960  1.1     lukem 	 * if <dnstyle> is not "regex", <dnpattern> must pass DN normalization
    961  1.1     lukem 	 */
    962  1.1     lukem 	if ( !strncasecmp( uri->bv_val, "dn", STRLENOF( "dn" ) ) ) {
    963  1.1     lukem 		bv.bv_val = uri->bv_val + STRLENOF( "dn" );
    964  1.1     lukem 
    965  1.1     lukem 		if ( bv.bv_val[ 0 ] == '.' ) {
    966  1.1     lukem 			bv.bv_val++;
    967  1.1     lukem 
    968  1.1     lukem 			if ( !strncasecmp( bv.bv_val, "exact:", STRLENOF( "exact:" ) ) ) {
    969  1.1     lukem 				bv.bv_val += STRLENOF( "exact:" );
    970  1.1     lukem 				*scope = LDAP_X_SCOPE_EXACT;
    971  1.1     lukem 
    972  1.1     lukem 			} else if ( !strncasecmp( bv.bv_val, "regex:", STRLENOF( "regex:" ) ) ) {
    973  1.1     lukem 				bv.bv_val += STRLENOF( "regex:" );
    974  1.1     lukem 				*scope = LDAP_X_SCOPE_REGEX;
    975  1.1     lukem 
    976  1.1     lukem 			} else if ( !strncasecmp( bv.bv_val, "children:", STRLENOF( "children:" ) ) ) {
    977  1.1     lukem 				bv.bv_val += STRLENOF( "children:" );
    978  1.1     lukem 				*scope = LDAP_X_SCOPE_CHILDREN;
    979  1.1     lukem 
    980  1.1     lukem 			} else if ( !strncasecmp( bv.bv_val, "subtree:", STRLENOF( "subtree:" ) ) ) {
    981  1.1     lukem 				bv.bv_val += STRLENOF( "subtree:" );
    982  1.1     lukem 				*scope = LDAP_X_SCOPE_SUBTREE;
    983  1.1     lukem 
    984  1.1     lukem 			} else if ( !strncasecmp( bv.bv_val, "onelevel:", STRLENOF( "onelevel:" ) ) ) {
    985  1.1     lukem 				bv.bv_val += STRLENOF( "onelevel:" );
    986  1.1     lukem 				*scope = LDAP_X_SCOPE_ONELEVEL;
    987  1.1     lukem 
    988  1.1     lukem 			} else {
    989  1.1     lukem 				return LDAP_PROTOCOL_ERROR;
    990  1.1     lukem 			}
    991  1.1     lukem 
    992  1.1     lukem 		} else {
    993  1.1     lukem 			if ( bv.bv_val[ 0 ] != ':' ) {
    994  1.1     lukem 				return LDAP_PROTOCOL_ERROR;
    995  1.1     lukem 			}
    996  1.1     lukem 			*scope = LDAP_X_SCOPE_EXACT;
    997  1.1     lukem 			bv.bv_val++;
    998  1.1     lukem 		}
    999  1.1     lukem 
   1000  1.1     lukem 		bv.bv_val += strspn( bv.bv_val, " " );
   1001  1.1     lukem 		/* jump here in case no type specification was present
   1002  1.1     lukem 		 * and uri was not an URI... HEADS-UP: assuming EXACT */
   1003  1.1     lukem is_dn:		bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
   1004  1.1     lukem 
   1005  1.1     lukem 		/* a single '*' means any DN without using regexes */
   1006  1.1     lukem 		if ( ber_bvccmp( &bv, '*' ) ) {
   1007  1.1     lukem 			*scope = LDAP_X_SCOPE_USERS;
   1008  1.1     lukem 		}
   1009  1.1     lukem 
   1010  1.1     lukem 		switch ( *scope ) {
   1011  1.1     lukem 		case LDAP_X_SCOPE_EXACT:
   1012  1.1     lukem 		case LDAP_X_SCOPE_CHILDREN:
   1013  1.1     lukem 		case LDAP_X_SCOPE_SUBTREE:
   1014  1.1     lukem 		case LDAP_X_SCOPE_ONELEVEL:
   1015  1.1     lukem 			if ( normalize ) {
   1016  1.1     lukem 				rc = dnNormalize( 0, NULL, NULL, &bv, nbase, op->o_tmpmemctx );
   1017  1.1     lukem 				if( rc != LDAP_SUCCESS ) {
   1018  1.1     lukem 					*scope = -1;
   1019  1.1     lukem 				}
   1020  1.1     lukem 			} else {
   1021  1.1     lukem 				ber_dupbv_x( nbase, &bv, op->o_tmpmemctx );
   1022  1.1     lukem 				rc = LDAP_SUCCESS;
   1023  1.1     lukem 			}
   1024  1.1     lukem 			break;
   1025  1.1     lukem 
   1026  1.1     lukem 		case LDAP_X_SCOPE_REGEX:
   1027  1.1     lukem 			ber_dupbv_x( nbase, &bv, op->o_tmpmemctx );
   1028  1.1     lukem 
   1029  1.1     lukem 		case LDAP_X_SCOPE_USERS:
   1030  1.1     lukem 			rc = LDAP_SUCCESS;
   1031  1.1     lukem 			break;
   1032  1.1     lukem 
   1033  1.1     lukem 		default:
   1034  1.1     lukem 			*scope = -1;
   1035  1.1     lukem 			break;
   1036  1.1     lukem 		}
   1037  1.1     lukem 
   1038  1.1     lukem 		return rc;
   1039  1.1     lukem 
   1040  1.1     lukem 	/*
   1041  1.1     lukem 	 * u:<uid>
   1042  1.1     lukem 	 */
   1043  1.1     lukem 	} else if ( ( uri->bv_val[ 0 ] == 'u' || uri->bv_val[ 0 ] == 'U' )
   1044  1.1     lukem 			&& ( uri->bv_val[ 1 ] == ':'
   1045  1.1     lukem 				|| uri->bv_val[ 1 ] == '/'
   1046  1.1     lukem 				|| uri->bv_val[ 1 ] == '.' ) )
   1047  1.1     lukem 	{
   1048  1.1     lukem 		Connection	c = *op->o_conn;
   1049  1.1     lukem 		char		buf[ SLAP_LDAPDN_MAXLEN ];
   1050  1.1     lukem 		struct berval	id,
   1051  1.1     lukem 				user = BER_BVNULL,
   1052  1.1     lukem 				realm = BER_BVNULL,
   1053  1.1     lukem 				mech = BER_BVNULL;
   1054  1.1     lukem 
   1055  1.1     lukem 		if ( sizeof( buf ) <= uri->bv_len ) {
   1056  1.1     lukem 			return LDAP_INVALID_SYNTAX;
   1057  1.1     lukem 		}
   1058  1.1     lukem 
   1059  1.1     lukem 		id.bv_len = uri->bv_len;
   1060  1.1     lukem 		id.bv_val = buf;
   1061  1.1     lukem 		strncpy( buf, uri->bv_val, sizeof( buf ) );
   1062  1.1     lukem 
   1063  1.1     lukem 		rc = slap_parse_user( &id, &user, &realm, &mech );
   1064  1.1     lukem 		if ( rc != LDAP_SUCCESS ) {
   1065  1.1     lukem 			return rc;
   1066  1.1     lukem 		}
   1067  1.1     lukem 
   1068  1.1     lukem 		if ( !BER_BVISNULL( &mech ) ) {
   1069  1.1     lukem 			c.c_sasl_bind_mech = mech;
   1070  1.1     lukem 		} else {
   1071  1.1     lukem 			BER_BVSTR( &c.c_sasl_bind_mech, "AUTHZ" );
   1072  1.1     lukem 		}
   1073  1.1     lukem 
   1074  1.1     lukem 		rc = slap_sasl_getdn( &c, op, &user,
   1075  1.1     lukem 				realm.bv_val, nbase, SLAP_GETDN_AUTHZID );
   1076  1.1     lukem 
   1077  1.1     lukem 		if ( rc == LDAP_SUCCESS ) {
   1078  1.1     lukem 			*scope = LDAP_X_SCOPE_EXACT;
   1079  1.1     lukem 		}
   1080  1.1     lukem 
   1081  1.1     lukem 		return rc;
   1082  1.1     lukem 
   1083  1.1     lukem 	/*
   1084  1.1     lukem 	 * group[/<groupoc>[/<groupat>]]:<groupdn>
   1085  1.1     lukem 	 *
   1086  1.1     lukem 	 * groupoc defaults to "groupOfNames"
   1087  1.1     lukem 	 * groupat defaults to "member"
   1088  1.1     lukem 	 *
   1089  1.1     lukem 	 * <groupdn> must pass DN normalization
   1090  1.1     lukem 	 */
   1091  1.1     lukem 	} else if ( strncasecmp( uri->bv_val, "group", STRLENOF( "group" ) ) == 0 )
   1092  1.1     lukem 	{
   1093  1.1     lukem 		struct berval	group_dn = BER_BVNULL,
   1094  1.1     lukem 				group_oc = BER_BVNULL,
   1095  1.1     lukem 				member_at = BER_BVNULL;
   1096  1.1     lukem 		char		*tmp;
   1097  1.1     lukem 
   1098  1.1     lukem 		bv.bv_val = uri->bv_val + STRLENOF( "group" );
   1099  1.1     lukem 		bv.bv_len = uri->bv_len - STRLENOF( "group" );
   1100  1.1     lukem 		group_dn.bv_val = ber_bvchr( &bv, ':' );
   1101  1.1     lukem 		if ( group_dn.bv_val == NULL ) {
   1102  1.1     lukem 			/* last chance: assume it's a(n exact) DN ... */
   1103  1.1     lukem 			bv.bv_val = uri->bv_val;
   1104  1.1     lukem 			*scope = LDAP_X_SCOPE_EXACT;
   1105  1.1     lukem 			goto is_dn;
   1106  1.1     lukem 		}
   1107  1.1     lukem 
   1108  1.1     lukem 		if ( bv.bv_val[ 0 ] == '/' ) {
   1109  1.1     lukem 			group_oc.bv_val = &bv.bv_val[ 1 ];
   1110  1.1     lukem 			group_oc.bv_len = group_dn.bv_val - group_oc.bv_val;
   1111  1.1     lukem 
   1112  1.1     lukem 			member_at.bv_val = ber_bvchr( &group_oc, '/' );
   1113  1.1     lukem 			if ( member_at.bv_val ) {
   1114  1.1     lukem 				group_oc.bv_len = member_at.bv_val - group_oc.bv_val;
   1115  1.1     lukem 				member_at.bv_val++;
   1116  1.1     lukem 				member_at.bv_len = group_dn.bv_val - member_at.bv_val;
   1117  1.1     lukem 
   1118  1.1     lukem 			} else {
   1119  1.1     lukem 				BER_BVSTR( &member_at, SLAPD_GROUP_ATTR );
   1120  1.1     lukem 			}
   1121  1.1     lukem 
   1122  1.1     lukem 		} else {
   1123  1.1     lukem 			BER_BVSTR( &group_oc, SLAPD_GROUP_CLASS );
   1124  1.1     lukem 			BER_BVSTR( &member_at, SLAPD_GROUP_ATTR );
   1125  1.1     lukem 		}
   1126  1.1     lukem 		group_dn.bv_val++;
   1127  1.1     lukem 		group_dn.bv_len = uri->bv_len - ( group_dn.bv_val - uri->bv_val );
   1128  1.1     lukem 
   1129  1.1     lukem 		if ( normalize ) {
   1130  1.1     lukem 			rc = dnNormalize( 0, NULL, NULL, &group_dn, nbase, op->o_tmpmemctx );
   1131  1.1     lukem 			if ( rc != LDAP_SUCCESS ) {
   1132  1.1     lukem 				*scope = -1;
   1133  1.1     lukem 				return rc;
   1134  1.1     lukem 			}
   1135  1.1     lukem 		} else {
   1136  1.1     lukem 			ber_dupbv_x( nbase, &group_dn, op->o_tmpmemctx );
   1137  1.1     lukem 			rc = LDAP_SUCCESS;
   1138  1.1     lukem 		}
   1139  1.1     lukem 		*scope = LDAP_X_SCOPE_GROUP;
   1140  1.1     lukem 
   1141  1.1     lukem 		/* FIXME: caller needs to add value of member attribute
   1142  1.1     lukem 		 * and close brackets twice */
   1143  1.1     lukem 		fstr->bv_len = STRLENOF( "(&(objectClass=)(=" /* )) */ )
   1144  1.1     lukem 			+ group_oc.bv_len + member_at.bv_len;
   1145  1.1     lukem 		fstr->bv_val = ch_malloc( fstr->bv_len + 1 );
   1146  1.1     lukem 
   1147  1.1     lukem 		tmp = lutil_strncopy( fstr->bv_val, "(&(objectClass=" /* )) */ ,
   1148  1.1     lukem 				STRLENOF( "(&(objectClass=" /* )) */ ) );
   1149  1.1     lukem 		tmp = lutil_strncopy( tmp, group_oc.bv_val, group_oc.bv_len );
   1150  1.1     lukem 		tmp = lutil_strncopy( tmp, /* ( */ ")(" /* ) */ ,
   1151  1.1     lukem 				STRLENOF( /* ( */ ")(" /* ) */ ) );
   1152  1.1     lukem 		tmp = lutil_strncopy( tmp, member_at.bv_val, member_at.bv_len );
   1153  1.1     lukem 		tmp = lutil_strncopy( tmp, "=", STRLENOF( "=" ) );
   1154  1.1     lukem 
   1155  1.1     lukem 		return rc;
   1156  1.1     lukem 	}
   1157  1.1     lukem 
   1158  1.1     lukem 	/*
   1159  1.1     lukem 	 * ldap:///<base>??<scope>?<filter>
   1160  1.1     lukem 	 * <scope> ::= {base|one|subtree}
   1161  1.1     lukem 	 *
   1162  1.1     lukem 	 * <scope> defaults to "base"
   1163  1.1     lukem 	 * <base> must pass DN normalization
   1164  1.1     lukem 	 * <filter> must pass str2filter()
   1165  1.1     lukem 	 */
   1166  1.1     lukem 	rc = ldap_url_parse( uri->bv_val, &ludp );
   1167  1.1     lukem 	switch ( rc ) {
   1168  1.1     lukem 	case LDAP_URL_SUCCESS:
   1169  1.1     lukem 		/* FIXME: the check is pedantic, but I think it's necessary,
   1170  1.1     lukem 		 * because people tend to use things like ldaps:// which
   1171  1.1     lukem 		 * gives the idea SSL is being used.  Maybe we could
   1172  1.1     lukem 		 * accept ldapi:// as well, but the point is that we use
   1173  1.1     lukem 		 * an URL as an easy means to define bits of a search with
   1174  1.1     lukem 		 * little parsing.
   1175  1.1     lukem 		 */
   1176  1.1     lukem 		if ( strcasecmp( ludp->lud_scheme, "ldap" ) != 0 ) {
   1177  1.1     lukem 			/*
   1178  1.1     lukem 			 * must be ldap:///
   1179  1.1     lukem 			 */
   1180  1.1     lukem 			rc = LDAP_PROTOCOL_ERROR;
   1181  1.1     lukem 			goto done;
   1182  1.1     lukem 		}
   1183  1.1     lukem 		break;
   1184  1.1     lukem 
   1185  1.1     lukem 	case LDAP_URL_ERR_BADSCHEME:
   1186  1.1     lukem 		/*
   1187  1.1     lukem 		 * last chance: assume it's a(n exact) DN ...
   1188  1.1     lukem 		 *
   1189  1.1     lukem 		 * NOTE: must pass DN normalization
   1190  1.1     lukem 		 */
   1191  1.1     lukem 		ldap_free_urldesc( ludp );
   1192  1.1     lukem 		bv.bv_val = uri->bv_val;
   1193  1.1     lukem 		*scope = LDAP_X_SCOPE_EXACT;
   1194  1.1     lukem 		goto is_dn;
   1195  1.1     lukem 
   1196  1.1     lukem 	default:
   1197  1.1     lukem 		rc = LDAP_PROTOCOL_ERROR;
   1198  1.1     lukem 		goto done;
   1199  1.1     lukem 	}
   1200  1.1     lukem 
   1201  1.1     lukem 	if ( ( ludp->lud_host && *ludp->lud_host )
   1202  1.1     lukem 		|| ludp->lud_attrs || ludp->lud_exts )
   1203  1.1     lukem 	{
   1204  1.1     lukem 		/* host part must be empty */
   1205  1.1     lukem 		/* attrs and extensions parts must be empty */
   1206  1.1     lukem 		rc = LDAP_PROTOCOL_ERROR;
   1207  1.1     lukem 		goto done;
   1208  1.1     lukem 	}
   1209  1.1     lukem 
   1210  1.1     lukem 	/* Grab the scope */
   1211  1.1     lukem 	*scope = ludp->lud_scope;
   1212  1.1     lukem 
   1213  1.1     lukem 	/* Grab the filter */
   1214  1.1     lukem 	if ( ludp->lud_filter ) {
   1215  1.1     lukem 		*filter = str2filter_x( op, ludp->lud_filter );
   1216  1.1     lukem 		if ( *filter == NULL ) {
   1217  1.1     lukem 			rc = LDAP_PROTOCOL_ERROR;
   1218  1.1     lukem 			goto done;
   1219  1.1     lukem 		}
   1220  1.1     lukem 		ber_str2bv( ludp->lud_filter, 0, 0, fstr );
   1221  1.1     lukem 	}
   1222  1.1     lukem 
   1223  1.1     lukem 	/* Grab the searchbase */
   1224  1.1     lukem 	ber_str2bv( ludp->lud_dn, 0, 0, base );
   1225  1.1     lukem 	if ( normalize ) {
   1226  1.1     lukem 		rc = dnNormalize( 0, NULL, NULL, base, nbase, op->o_tmpmemctx );
   1227  1.1     lukem 	} else {
   1228  1.1     lukem 		ber_dupbv_x( nbase, base, op->o_tmpmemctx );
   1229  1.1     lukem 		rc = LDAP_SUCCESS;
   1230  1.1     lukem 	}
   1231  1.1     lukem 
   1232  1.1     lukem done:
   1233  1.1     lukem 	if( rc != LDAP_SUCCESS ) {
   1234  1.2  christos 		if( *filter ) {
   1235  1.2  christos 			filter_free_x( op, *filter, 1 );
   1236  1.2  christos 			*filter = NULL;
   1237  1.2  christos 		}
   1238  1.1     lukem 		BER_BVZERO( base );
   1239  1.1     lukem 		BER_BVZERO( fstr );
   1240  1.1     lukem 	} else {
   1241  1.1     lukem 		/* Don't free these, return them to caller */
   1242  1.1     lukem 		ludp->lud_filter = NULL;
   1243  1.1     lukem 		ludp->lud_dn = NULL;
   1244  1.1     lukem 	}
   1245  1.1     lukem 
   1246  1.1     lukem 	ldap_free_urldesc( ludp );
   1247  1.1     lukem 	return( rc );
   1248  1.1     lukem }
   1249  1.1     lukem 
   1250  1.1     lukem #ifndef SLAP_AUTH_REWRITE
   1251  1.1     lukem static int slap_sasl_rx_off(char *rep, int *off)
   1252  1.1     lukem {
   1253  1.1     lukem 	const char *c;
   1254  1.1     lukem 	int n;
   1255  1.1     lukem 
   1256  1.1     lukem 	/* Precompile replace pattern. Find the $<n> placeholders */
   1257  1.1     lukem 	off[0] = -2;
   1258  1.1     lukem 	n = 1;
   1259  1.1     lukem 	for ( c = rep;	 *c;  c++ ) {
   1260  1.1     lukem 		if ( *c == '\\' && c[1] ) {
   1261  1.1     lukem 			c++;
   1262  1.1     lukem 			continue;
   1263  1.1     lukem 		}
   1264  1.1     lukem 		if ( *c == '$' ) {
   1265  1.1     lukem 			if ( n == SASLREGEX_REPLACE ) {
   1266  1.1     lukem 				Debug( LDAP_DEBUG_ANY,
   1267  1.1     lukem 					"SASL replace pattern %s has too many $n "
   1268  1.1     lukem 						"placeholders (max %d)\n",
   1269  1.1     lukem 					rep, SASLREGEX_REPLACE, 0 );
   1270  1.1     lukem 
   1271  1.1     lukem 				return( LDAP_OTHER );
   1272  1.1     lukem 			}
   1273  1.1     lukem 			off[n] = c - rep;
   1274  1.1     lukem 			n++;
   1275  1.1     lukem 		}
   1276  1.1     lukem 	}
   1277  1.1     lukem 
   1278  1.1     lukem 	/* Final placeholder, after the last $n */
   1279  1.1     lukem 	off[n] = c - rep;
   1280  1.1     lukem 	n++;
   1281  1.1     lukem 	off[n] = -1;
   1282  1.1     lukem 	return( LDAP_SUCCESS );
   1283  1.1     lukem }
   1284  1.1     lukem #endif /* ! SLAP_AUTH_REWRITE */
   1285  1.1     lukem 
   1286  1.1     lukem #ifdef SLAP_AUTH_REWRITE
   1287  1.1     lukem int slap_sasl_rewrite_config(
   1288  1.1     lukem 		const char	*fname,
   1289  1.1     lukem 		int		lineno,
   1290  1.1     lukem 		int		argc,
   1291  1.1     lukem 		char		**argv
   1292  1.1     lukem )
   1293  1.1     lukem {
   1294  1.1     lukem 	int	rc;
   1295  1.1     lukem 	char	*savearg0;
   1296  1.1     lukem 
   1297  1.1     lukem 	/* init at first call */
   1298  1.1     lukem 	if ( sasl_rwinfo == NULL ) {
   1299  1.1     lukem  		sasl_rwinfo = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
   1300  1.1     lukem 	}
   1301  1.1     lukem 
   1302  1.1     lukem 	/* strip "authid-" prefix for parsing */
   1303  1.1     lukem 	savearg0 = argv[0];
   1304  1.1     lukem 	argv[0] += STRLENOF( "authid-" );
   1305  1.1     lukem  	rc = rewrite_parse( sasl_rwinfo, fname, lineno, argc, argv );
   1306  1.1     lukem 	argv[0] = savearg0;
   1307  1.1     lukem 
   1308  1.1     lukem 	return rc;
   1309  1.1     lukem }
   1310  1.1     lukem 
   1311  1.1     lukem static int
   1312  1.1     lukem slap_sasl_rewrite_destroy( void )
   1313  1.1     lukem {
   1314  1.1     lukem 	if ( sasl_rwinfo ) {
   1315  1.1     lukem 		rewrite_info_delete( &sasl_rwinfo );
   1316  1.1     lukem 		sasl_rwinfo = NULL;
   1317  1.1     lukem 	}
   1318  1.1     lukem 
   1319  1.1     lukem 	return 0;
   1320  1.1     lukem }
   1321  1.1     lukem 
   1322  1.1     lukem int slap_sasl_regexp_rewrite_config(
   1323  1.1     lukem 		const char	*fname,
   1324  1.1     lukem 		int		lineno,
   1325  1.1     lukem 		const char	*match,
   1326  1.1     lukem 		const char	*replace,
   1327  1.1     lukem 		const char	*context )
   1328  1.1     lukem {
   1329  1.1     lukem 	int	rc;
   1330  1.1     lukem 	char	*argvRule[] = { "rewriteRule", NULL, NULL, ":@", NULL };
   1331  1.1     lukem 
   1332  1.1     lukem 	/* init at first call */
   1333  1.1     lukem 	if ( sasl_rwinfo == NULL ) {
   1334  1.1     lukem 		char *argvEngine[] = { "rewriteEngine", "on", NULL };
   1335  1.1     lukem 		char *argvContext[] = { "rewriteContext", NULL, NULL };
   1336  1.1     lukem 
   1337  1.1     lukem 		/* initialize rewrite engine */
   1338  1.1     lukem  		sasl_rwinfo = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
   1339  1.1     lukem 
   1340  1.1     lukem 		/* switch on rewrite engine */
   1341  1.1     lukem  		rc = rewrite_parse( sasl_rwinfo, fname, lineno, 2, argvEngine );
   1342  1.1     lukem  		if (rc != LDAP_SUCCESS) {
   1343  1.1     lukem 			return rc;
   1344  1.1     lukem 		}
   1345  1.1     lukem 
   1346  1.1     lukem 		/* create generic authid context */
   1347  1.1     lukem 		argvContext[1] = AUTHID_CONTEXT;
   1348  1.1     lukem  		rc = rewrite_parse( sasl_rwinfo, fname, lineno, 2, argvContext );
   1349  1.1     lukem  		if (rc != LDAP_SUCCESS) {
   1350  1.1     lukem 			return rc;
   1351  1.1     lukem 		}
   1352  1.1     lukem 	}
   1353  1.1     lukem 
   1354  1.1     lukem 	argvRule[1] = (char *)match;
   1355  1.1     lukem 	argvRule[2] = (char *)replace;
   1356  1.1     lukem  	rc = rewrite_parse( sasl_rwinfo, fname, lineno, 4, argvRule );
   1357  1.1     lukem 
   1358  1.1     lukem 	return rc;
   1359  1.1     lukem }
   1360  1.1     lukem #endif /* SLAP_AUTH_REWRITE */
   1361  1.1     lukem 
   1362  1.1     lukem int slap_sasl_regexp_config( const char *match, const char *replace )
   1363  1.1     lukem {
   1364  1.1     lukem 	int rc;
   1365  1.1     lukem 	SaslRegexp_t *reg;
   1366  1.1     lukem 
   1367  1.1     lukem 	SaslRegexp = (SaslRegexp_t *) ch_realloc( (char *) SaslRegexp,
   1368  1.1     lukem 	  (nSaslRegexp + 1) * sizeof(SaslRegexp_t) );
   1369  1.1     lukem 
   1370  1.1     lukem 	reg = &SaslRegexp[nSaslRegexp];
   1371  1.1     lukem 
   1372  1.1     lukem #ifdef SLAP_AUTH_REWRITE
   1373  1.1     lukem 	rc = slap_sasl_regexp_rewrite_config( "sasl-regexp", 0,
   1374  1.1     lukem 			match, replace, AUTHID_CONTEXT );
   1375  1.1     lukem #else /* ! SLAP_AUTH_REWRITE */
   1376  1.1     lukem 
   1377  1.1     lukem 	/* Precompile matching pattern */
   1378  1.1     lukem 	rc = regcomp( &reg->sr_workspace, match, REG_EXTENDED|REG_ICASE );
   1379  1.1     lukem 	if ( rc ) {
   1380  1.1     lukem 		Debug( LDAP_DEBUG_ANY,
   1381  1.1     lukem 			"SASL match pattern %s could not be compiled by regexp engine\n",
   1382  1.1     lukem 			match, 0, 0 );
   1383  1.1     lukem 
   1384  1.1     lukem #ifdef ENABLE_REWRITE
   1385  1.1     lukem 		/* Dummy block to force symbol references in librewrite */
   1386  1.1     lukem 		if ( slapMode == ( SLAP_SERVER_MODE|SLAP_TOOL_MODE )) {
   1387  1.1     lukem 			rewrite_info_init( 0 );
   1388  1.1     lukem 		}
   1389  1.1     lukem #endif
   1390  1.1     lukem 		return( LDAP_OTHER );
   1391  1.1     lukem 	}
   1392  1.1     lukem 
   1393  1.1     lukem 	rc = slap_sasl_rx_off( replace, reg->sr_offset );
   1394  1.1     lukem #endif /* ! SLAP_AUTH_REWRITE */
   1395  1.1     lukem 	if ( rc == LDAP_SUCCESS ) {
   1396  1.1     lukem 		reg->sr_match = ch_strdup( match );
   1397  1.1     lukem 		reg->sr_replace = ch_strdup( replace );
   1398  1.1     lukem 
   1399  1.1     lukem 		nSaslRegexp++;
   1400  1.1     lukem 	}
   1401  1.1     lukem 
   1402  1.1     lukem 	return rc;
   1403  1.1     lukem }
   1404  1.1     lukem 
   1405  1.1     lukem void
   1406  1.1     lukem slap_sasl_regexp_destroy( void )
   1407  1.1     lukem {
   1408  1.1     lukem 	if ( SaslRegexp ) {
   1409  1.1     lukem 		int	n;
   1410  1.1     lukem 
   1411  1.1     lukem 		for ( n = 0; n < nSaslRegexp; n++ ) {
   1412  1.1     lukem 			ch_free( SaslRegexp[ n ].sr_match );
   1413  1.1     lukem 			ch_free( SaslRegexp[ n ].sr_replace );
   1414  1.1     lukem #ifndef SLAP_AUTH_REWRITE
   1415  1.1     lukem 			regfree( &SaslRegexp[ n ].sr_workspace );
   1416  1.1     lukem #endif /* SLAP_AUTH_REWRITE */
   1417  1.1     lukem 		}
   1418  1.1     lukem 
   1419  1.1     lukem 		ch_free( SaslRegexp );
   1420  1.1     lukem 	}
   1421  1.1     lukem 
   1422  1.1     lukem #ifdef SLAP_AUTH_REWRITE
   1423  1.1     lukem 	slap_sasl_rewrite_destroy();
   1424  1.1     lukem #endif /* SLAP_AUTH_REWRITE */
   1425  1.1     lukem }
   1426  1.1     lukem 
   1427  1.1     lukem void slap_sasl_regexp_unparse( BerVarray *out )
   1428  1.1     lukem {
   1429  1.1     lukem 	int i;
   1430  1.1     lukem 	BerVarray bva = NULL;
   1431  1.1     lukem 	char ibuf[32], *ptr;
   1432  1.1     lukem 	struct berval idx;
   1433  1.1     lukem 
   1434  1.1     lukem 	if ( !nSaslRegexp ) return;
   1435  1.1     lukem 
   1436  1.1     lukem 	idx.bv_val = ibuf;
   1437  1.1     lukem 	bva = ch_malloc( (nSaslRegexp+1) * sizeof(struct berval) );
   1438  1.1     lukem 	BER_BVZERO(bva+nSaslRegexp);
   1439  1.1     lukem 	for ( i=0; i<nSaslRegexp; i++ ) {
   1440  1.1     lukem 		idx.bv_len = sprintf( idx.bv_val, "{%d}", i);
   1441  1.1     lukem 		bva[i].bv_len = idx.bv_len + strlen( SaslRegexp[i].sr_match ) +
   1442  1.1     lukem 			strlen( SaslRegexp[i].sr_replace ) + 5;
   1443  1.1     lukem 		bva[i].bv_val = ch_malloc( bva[i].bv_len+1 );
   1444  1.1     lukem 		ptr = lutil_strcopy( bva[i].bv_val, ibuf );
   1445  1.1     lukem 		*ptr++ = '"';
   1446  1.1     lukem 		ptr = lutil_strcopy( ptr, SaslRegexp[i].sr_match );
   1447  1.1     lukem 		ptr = lutil_strcopy( ptr, "\" \"" );
   1448  1.1     lukem 		ptr = lutil_strcopy( ptr, SaslRegexp[i].sr_replace );
   1449  1.1     lukem 		*ptr++ = '"';
   1450  1.1     lukem 		*ptr = '\0';
   1451  1.1     lukem 	}
   1452  1.1     lukem 	*out = bva;
   1453  1.1     lukem }
   1454  1.1     lukem 
   1455  1.1     lukem #ifndef SLAP_AUTH_REWRITE
   1456  1.1     lukem /* Perform replacement on regexp matches */
   1457  1.1     lukem static void slap_sasl_rx_exp(
   1458  1.1     lukem 	const char *rep,
   1459  1.1     lukem 	const int *off,
   1460  1.1     lukem 	regmatch_t *str,
   1461  1.1     lukem 	const char *saslname,
   1462  1.1     lukem 	struct berval *out,
   1463  1.1     lukem 	void *ctx )
   1464  1.1     lukem {
   1465  1.1     lukem 	int i, n, len, insert;
   1466  1.1     lukem 
   1467  1.1     lukem 	/* Get the total length of the final URI */
   1468  1.1     lukem 
   1469  1.1     lukem 	n=1;
   1470  1.1     lukem 	len = 0;
   1471  1.1     lukem 	while( off[n] >= 0 ) {
   1472  1.1     lukem 		/* Len of next section from replacement string (x,y,z above) */
   1473  1.1     lukem 		len += off[n] - off[n-1] - 2;
   1474  1.1     lukem 		if( off[n+1] < 0)
   1475  1.1     lukem 			break;
   1476  1.1     lukem 
   1477  1.1     lukem 		/* Len of string from saslname that matched next $i  (b,d above) */
   1478  1.1     lukem 		i = rep[ off[n] + 1 ]	- '0';
   1479  1.1     lukem 		len += str[i].rm_eo - str[i].rm_so;
   1480  1.1     lukem 		n++;
   1481  1.1     lukem 	}
   1482  1.1     lukem 	out->bv_val = slap_sl_malloc( len + 1, ctx );
   1483  1.1     lukem 	out->bv_len = len;
   1484  1.1     lukem 
   1485  1.1     lukem 	/* Fill in URI with replace string, replacing $i as we go */
   1486  1.1     lukem 	n=1;
   1487  1.1     lukem 	insert = 0;
   1488  1.1     lukem 	while( off[n] >= 0) {
   1489  1.1     lukem 		/* Paste in next section from replacement string (x,y,z above) */
   1490  1.1     lukem 		len = off[n] - off[n-1] - 2;
   1491  1.1     lukem 		strncpy( out->bv_val+insert, rep + off[n-1] + 2, len);
   1492  1.1     lukem 		insert += len;
   1493  1.1     lukem 		if( off[n+1] < 0)
   1494  1.1     lukem 			break;
   1495  1.1     lukem 
   1496  1.1     lukem 		/* Paste in string from saslname that matched next $i  (b,d above) */
   1497  1.1     lukem 		i = rep[ off[n] + 1 ]	- '0';
   1498  1.1     lukem 		len = str[i].rm_eo - str[i].rm_so;
   1499  1.1     lukem 		strncpy( out->bv_val+insert, saslname + str[i].rm_so, len );
   1500  1.1     lukem 		insert += len;
   1501  1.1     lukem 
   1502  1.1     lukem 		n++;
   1503  1.1     lukem 	}
   1504  1.1     lukem 
   1505  1.1     lukem 	out->bv_val[insert] = '\0';
   1506  1.1     lukem }
   1507  1.1     lukem #endif /* ! SLAP_AUTH_REWRITE */
   1508  1.1     lukem 
   1509  1.1     lukem /* Take the passed in SASL name and attempt to convert it into an
   1510  1.1     lukem    LDAP URI to find the matching LDAP entry, using the pattern matching
   1511  1.1     lukem    strings given in the saslregexp config file directive(s) */
   1512  1.1     lukem 
   1513  1.1     lukem static int slap_authz_regexp( struct berval *in, struct berval *out,
   1514  1.1     lukem 		int flags, void *ctx )
   1515  1.1     lukem {
   1516  1.1     lukem #ifdef SLAP_AUTH_REWRITE
   1517  1.1     lukem 	const char	*context = AUTHID_CONTEXT;
   1518  1.1     lukem 
   1519  1.1     lukem 	if ( sasl_rwinfo == NULL || BER_BVISNULL( in ) ) {
   1520  1.1     lukem 		return 0;
   1521  1.1     lukem 	}
   1522  1.1     lukem 
   1523  1.1     lukem 	/* FIXME: if aware of authc/authz mapping,
   1524  1.1     lukem 	 * we could use different contexts ... */
   1525  1.1     lukem 	switch ( rewrite_session( sasl_rwinfo, context, in->bv_val, NULL,
   1526  1.1     lukem 				&out->bv_val ) )
   1527  1.1     lukem 	{
   1528  1.1     lukem 	case REWRITE_REGEXEC_OK:
   1529  1.1     lukem 		if ( !BER_BVISNULL( out ) ) {
   1530  1.1     lukem 			char *val = out->bv_val;
   1531  1.1     lukem 			ber_str2bv_x( val, 0, 1, out, ctx );
   1532  1.1     lukem 			if ( val != in->bv_val ) {
   1533  1.1     lukem 				free( val );
   1534  1.1     lukem 			}
   1535  1.1     lukem 		} else {
   1536  1.1     lukem 			ber_dupbv_x( out, in, ctx );
   1537  1.1     lukem 		}
   1538  1.1     lukem 		Debug( LDAP_DEBUG_ARGS,
   1539  1.1     lukem 			"[rw] %s: \"%s\" -> \"%s\"\n",
   1540  1.1     lukem 			context, in->bv_val, out->bv_val );
   1541  1.1     lukem 		return 1;
   1542  1.1     lukem 
   1543  1.1     lukem  	case REWRITE_REGEXEC_UNWILLING:
   1544  1.1     lukem 	case REWRITE_REGEXEC_ERR:
   1545  1.1     lukem 	default:
   1546  1.1     lukem 		return 0;
   1547  1.1     lukem 	}
   1548  1.1     lukem 
   1549  1.1     lukem #else /* ! SLAP_AUTH_REWRITE */
   1550  1.1     lukem 	char *saslname = in->bv_val;
   1551  1.1     lukem 	SaslRegexp_t *reg;
   1552  1.1     lukem   	regmatch_t sr_strings[SASLREGEX_REPLACE];	/* strings matching $1,$2 ... */
   1553  1.1     lukem 	int i;
   1554  1.1     lukem 
   1555  1.1     lukem 	memset( out, 0, sizeof( *out ) );
   1556  1.1     lukem 
   1557  1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "slap_authz_regexp: converting SASL name %s\n",
   1558  1.1     lukem 	   saslname, 0, 0 );
   1559  1.1     lukem 
   1560  1.1     lukem 	if (( saslname == NULL ) || ( nSaslRegexp == 0 )) {
   1561  1.1     lukem 		return( 0 );
   1562  1.1     lukem 	}
   1563  1.1     lukem 
   1564  1.1     lukem 	/* Match the normalized SASL name to the saslregexp patterns */
   1565  1.1     lukem 	for( reg = SaslRegexp,i=0;  i<nSaslRegexp;  i++,reg++ ) {
   1566  1.1     lukem 		if ( regexec( &reg->sr_workspace, saslname, SASLREGEX_REPLACE,
   1567  1.1     lukem 		  sr_strings, 0)  == 0 )
   1568  1.1     lukem 			break;
   1569  1.1     lukem 	}
   1570  1.1     lukem 
   1571  1.1     lukem 	if( i >= nSaslRegexp ) return( 0 );
   1572  1.1     lukem 
   1573  1.1     lukem 	/*
   1574  1.1     lukem 	 * The match pattern may have been of the form "a(b.*)c(d.*)e" and the
   1575  1.1     lukem 	 * replace pattern of the form "x$1y$2z". The returned string needs
   1576  1.1     lukem 	 * to replace the $1,$2 with the strings that matched (b.*) and (d.*)
   1577  1.1     lukem 	 */
   1578  1.1     lukem 	slap_sasl_rx_exp( reg->sr_replace, reg->sr_offset,
   1579  1.1     lukem 		sr_strings, saslname, out, ctx );
   1580  1.1     lukem 
   1581  1.1     lukem 	Debug( LDAP_DEBUG_TRACE,
   1582  1.1     lukem 		"slap_authz_regexp: converted SASL name to %s\n",
   1583  1.1     lukem 		BER_BVISEMPTY( out ) ? "" : out->bv_val, 0, 0 );
   1584  1.1     lukem 
   1585  1.1     lukem 	return( 1 );
   1586  1.1     lukem #endif /* ! SLAP_AUTH_REWRITE */
   1587  1.1     lukem }
   1588  1.1     lukem 
   1589  1.1     lukem /* This callback actually does some work...*/
   1590  1.1     lukem static int sasl_sc_sasl2dn( Operation *op, SlapReply *rs )
   1591  1.1     lukem {
   1592  1.1     lukem 	struct berval *ndn = op->o_callback->sc_private;
   1593  1.1     lukem 
   1594  1.1     lukem 	if ( rs->sr_type != REP_SEARCH ) return LDAP_SUCCESS;
   1595  1.1     lukem 
   1596  1.1     lukem 	/* We only want to be called once */
   1597  1.1     lukem 	if ( !BER_BVISNULL( ndn ) ) {
   1598  1.1     lukem 		op->o_tmpfree( ndn->bv_val, op->o_tmpmemctx );
   1599  1.1     lukem 		BER_BVZERO( ndn );
   1600  1.1     lukem 
   1601  1.1     lukem 		Debug( LDAP_DEBUG_TRACE,
   1602  1.1     lukem 			"%s: slap_sc_sasl2dn: search DN returned more than 1 entry\n",
   1603  1.1     lukem 			op->o_log_prefix, 0, 0 );
   1604  1.1     lukem 		return LDAP_UNAVAILABLE; /* short-circuit the search */
   1605  1.1     lukem 	}
   1606  1.1     lukem 
   1607  1.1     lukem 	ber_dupbv_x( ndn, &rs->sr_entry->e_nname, op->o_tmpmemctx );
   1608  1.1     lukem 	return LDAP_SUCCESS;
   1609  1.1     lukem }
   1610  1.1     lukem 
   1611  1.1     lukem 
   1612  1.1     lukem typedef struct smatch_info {
   1613  1.1     lukem 	struct berval *dn;
   1614  1.1     lukem 	int match;
   1615  1.1     lukem } smatch_info;
   1616  1.1     lukem 
   1617  1.1     lukem static int sasl_sc_smatch( Operation *o, SlapReply *rs )
   1618  1.1     lukem {
   1619  1.1     lukem 	smatch_info *sm = o->o_callback->sc_private;
   1620  1.1     lukem 
   1621  1.1     lukem 	if (rs->sr_type != REP_SEARCH) return 0;
   1622  1.1     lukem 
   1623  1.1     lukem 	if (dn_match(sm->dn, &rs->sr_entry->e_nname)) {
   1624  1.1     lukem 		sm->match = 1;
   1625  1.1     lukem 		return LDAP_UNAVAILABLE;	/* short-circuit the search */
   1626  1.1     lukem 	}
   1627  1.1     lukem 
   1628  1.1     lukem 	return 0;
   1629  1.1     lukem }
   1630  1.1     lukem 
   1631  1.1     lukem int
   1632  1.1     lukem slap_sasl_matches( Operation *op, BerVarray rules,
   1633  1.1     lukem 		struct berval *assertDN, struct berval *authc )
   1634  1.1     lukem {
   1635  1.1     lukem 	int	rc = LDAP_INAPPROPRIATE_AUTH;
   1636  1.1     lukem 
   1637  1.1     lukem 	if ( rules != NULL ) {
   1638  1.1     lukem 		int	i;
   1639  1.1     lukem 
   1640  1.1     lukem 		for( i = 0; !BER_BVISNULL( &rules[i] ); i++ ) {
   1641  1.1     lukem 			rc = slap_sasl_match( op, &rules[i], assertDN, authc );
   1642  1.1     lukem 			if ( rc == LDAP_SUCCESS ) break;
   1643  1.1     lukem 		}
   1644  1.1     lukem 	}
   1645  1.1     lukem 
   1646  1.1     lukem 	return rc;
   1647  1.1     lukem }
   1648  1.1     lukem 
   1649  1.1     lukem /*
   1650  1.1     lukem  * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
   1651  1.1     lukem  * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
   1652  1.1     lukem  * the rule must be used as an internal search for entries. If that search
   1653  1.1     lukem  * returns the *assertDN entry, the match is successful.
   1654  1.1     lukem  *
   1655  1.1     lukem  * The assertDN should not have the dn: prefix
   1656  1.1     lukem  */
   1657  1.1     lukem 
   1658  1.1     lukem static int
   1659  1.1     lukem slap_sasl_match( Operation *opx, struct berval *rule,
   1660  1.1     lukem 	struct berval *assertDN, struct berval *authc )
   1661  1.1     lukem {
   1662  1.1     lukem 	int rc;
   1663  1.1     lukem 	regex_t reg;
   1664  1.1     lukem 	smatch_info sm;
   1665  1.1     lukem 	slap_callback cb = { NULL, sasl_sc_smatch, NULL, NULL };
   1666  1.1     lukem 	Operation op = {0};
   1667  1.1     lukem 	SlapReply rs = {REP_RESULT};
   1668  1.1     lukem 	struct berval base = BER_BVNULL;
   1669  1.1     lukem 
   1670  1.1     lukem 	sm.dn = assertDN;
   1671  1.1     lukem 	sm.match = 0;
   1672  1.1     lukem 	cb.sc_private = &sm;
   1673  1.1     lukem 
   1674  1.1     lukem 	Debug( LDAP_DEBUG_TRACE,
   1675  1.1     lukem 	   "===>slap_sasl_match: comparing DN %s to rule %s\n",
   1676  1.1     lukem 		assertDN->bv_len ? assertDN->bv_val : "(null)", rule->bv_val, 0 );
   1677  1.1     lukem 
   1678  1.1     lukem 	/* NOTE: don't normalize rule if authz syntax is enabled */
   1679  1.1     lukem 	rc = slap_parseURI( opx, rule, &base, &op.o_req_ndn,
   1680  1.1     lukem 		&op.ors_scope, &op.ors_filter, &op.ors_filterstr, 0 );
   1681  1.1     lukem 
   1682  1.1     lukem 	if( rc != LDAP_SUCCESS ) goto CONCLUDED;
   1683  1.1     lukem 
   1684  1.1     lukem 	switch ( op.ors_scope ) {
   1685  1.1     lukem 	case LDAP_X_SCOPE_EXACT:
   1686  1.1     lukem exact_match:
   1687  1.1     lukem 		if ( dn_match( &op.o_req_ndn, assertDN ) ) {
   1688  1.1     lukem 			rc = LDAP_SUCCESS;
   1689  1.1     lukem 		} else {
   1690  1.1     lukem 			rc = LDAP_INAPPROPRIATE_AUTH;
   1691  1.1     lukem 		}
   1692  1.1     lukem 		goto CONCLUDED;
   1693  1.1     lukem 
   1694  1.1     lukem 	case LDAP_X_SCOPE_CHILDREN:
   1695  1.1     lukem 	case LDAP_X_SCOPE_SUBTREE:
   1696  1.1     lukem 	case LDAP_X_SCOPE_ONELEVEL:
   1697  1.1     lukem 	{
   1698  1.1     lukem 		int	d = assertDN->bv_len - op.o_req_ndn.bv_len;
   1699  1.1     lukem 
   1700  1.1     lukem 		rc = LDAP_INAPPROPRIATE_AUTH;
   1701  1.1     lukem 
   1702  1.1     lukem 		if ( d == 0 && op.ors_scope == LDAP_X_SCOPE_SUBTREE ) {
   1703  1.1     lukem 			goto exact_match;
   1704  1.1     lukem 
   1705  1.1     lukem 		} else if ( d > 0 ) {
   1706  1.1     lukem 			struct berval bv;
   1707  1.1     lukem 
   1708  1.1     lukem 			/* leave room for at least one char of attributeType,
   1709  1.1     lukem 			 * one for '=' and one for ',' */
   1710  1.2  christos 			if ( d < (int) STRLENOF( "x=,") ) {
   1711  1.1     lukem 				goto CONCLUDED;
   1712  1.1     lukem 			}
   1713  1.1     lukem 
   1714  1.1     lukem 			bv.bv_len = op.o_req_ndn.bv_len;
   1715  1.1     lukem 			bv.bv_val = assertDN->bv_val + d;
   1716  1.1     lukem 
   1717  1.1     lukem 			if ( bv.bv_val[ -1 ] == ',' && dn_match( &op.o_req_ndn, &bv ) ) {
   1718  1.1     lukem 				switch ( op.ors_scope ) {
   1719  1.1     lukem 				case LDAP_X_SCOPE_SUBTREE:
   1720  1.1     lukem 				case LDAP_X_SCOPE_CHILDREN:
   1721  1.1     lukem 					rc = LDAP_SUCCESS;
   1722  1.1     lukem 					break;
   1723  1.1     lukem 
   1724  1.1     lukem 				case LDAP_X_SCOPE_ONELEVEL:
   1725  1.1     lukem 				{
   1726  1.1     lukem 					struct berval	pdn;
   1727  1.1     lukem 
   1728  1.1     lukem 					dnParent( assertDN, &pdn );
   1729  1.1     lukem 					/* the common portion of the DN
   1730  1.1     lukem 					 * already matches, so only check
   1731  1.1     lukem 					 * if parent DN of assertedDN
   1732  1.1     lukem 					 * is all the pattern */
   1733  1.1     lukem 					if ( pdn.bv_len == op.o_req_ndn.bv_len ) {
   1734  1.1     lukem 						rc = LDAP_SUCCESS;
   1735  1.1     lukem 					}
   1736  1.1     lukem 					break;
   1737  1.1     lukem 				}
   1738  1.1     lukem 				default:
   1739  1.1     lukem 					/* at present, impossible */
   1740  1.1     lukem 					assert( 0 );
   1741  1.1     lukem 				}
   1742  1.1     lukem 			}
   1743  1.1     lukem 		}
   1744  1.1     lukem 		goto CONCLUDED;
   1745  1.1     lukem 	}
   1746  1.1     lukem 
   1747  1.1     lukem 	case LDAP_X_SCOPE_REGEX:
   1748  1.1     lukem 		rc = regcomp(&reg, op.o_req_ndn.bv_val,
   1749  1.1     lukem 			REG_EXTENDED|REG_ICASE|REG_NOSUB);
   1750  1.1     lukem 		if ( rc == 0 ) {
   1751  1.1     lukem 			rc = regexec(&reg, assertDN->bv_val, 0, NULL, 0);
   1752  1.1     lukem 			regfree( &reg );
   1753  1.1     lukem 		}
   1754  1.1     lukem 		if ( rc == 0 ) {
   1755  1.1     lukem 			rc = LDAP_SUCCESS;
   1756  1.1     lukem 		} else {
   1757  1.1     lukem 			rc = LDAP_INAPPROPRIATE_AUTH;
   1758  1.1     lukem 		}
   1759  1.1     lukem 		goto CONCLUDED;
   1760  1.1     lukem 
   1761  1.1     lukem 	case LDAP_X_SCOPE_GROUP: {
   1762  1.1     lukem 		char	*tmp;
   1763  1.1     lukem 
   1764  1.1     lukem 		/* Now filterstr looks like "(&(objectClass=<group_oc>)(<member_at>="
   1765  1.1     lukem 		 * we need to append the <assertDN> so that the <group_dn> is searched
   1766  1.1     lukem 		 * with scope "base", and the filter ensures that <assertDN> is
   1767  1.1     lukem 		 * member of the group */
   1768  1.1     lukem 		tmp = ch_realloc( op.ors_filterstr.bv_val, op.ors_filterstr.bv_len +
   1769  1.1     lukem 			assertDN->bv_len + STRLENOF( /*"(("*/ "))" ) + 1 );
   1770  1.1     lukem 		if ( tmp == NULL ) {
   1771  1.1     lukem 			rc = LDAP_NO_MEMORY;
   1772  1.1     lukem 			goto CONCLUDED;
   1773  1.1     lukem 		}
   1774  1.1     lukem 		op.ors_filterstr.bv_val = tmp;
   1775  1.1     lukem 
   1776  1.1     lukem 		tmp = lutil_strcopy( &tmp[op.ors_filterstr.bv_len], assertDN->bv_val );
   1777  1.1     lukem 		tmp = lutil_strcopy( tmp, /*"(("*/ "))" );
   1778  1.1     lukem 
   1779  1.1     lukem 		/* pass opx because str2filter_x may (and does) use o_tmpmfuncs */
   1780  1.1     lukem 		op.ors_filter = str2filter_x( opx, op.ors_filterstr.bv_val );
   1781  1.1     lukem 		if ( op.ors_filter == NULL ) {
   1782  1.1     lukem 			rc = LDAP_PROTOCOL_ERROR;
   1783  1.1     lukem 			goto CONCLUDED;
   1784  1.1     lukem 		}
   1785  1.1     lukem 		op.ors_scope = LDAP_SCOPE_BASE;
   1786  1.1     lukem 
   1787  1.1     lukem 		/* hijack match DN: use that of the group instead of the assertDN;
   1788  1.1     lukem 		 * assertDN is now in the filter */
   1789  1.1     lukem 		sm.dn = &op.o_req_ndn;
   1790  1.1     lukem 
   1791  1.1     lukem 		/* do the search */
   1792  1.1     lukem 		break;
   1793  1.1     lukem 		}
   1794  1.1     lukem 
   1795  1.1     lukem 	case LDAP_X_SCOPE_USERS:
   1796  1.1     lukem 		if ( !BER_BVISEMPTY( assertDN ) ) {
   1797  1.1     lukem 			rc = LDAP_SUCCESS;
   1798  1.1     lukem 		} else {
   1799  1.1     lukem 			rc = LDAP_INAPPROPRIATE_AUTH;
   1800  1.1     lukem 		}
   1801  1.1     lukem 		goto CONCLUDED;
   1802  1.1     lukem 
   1803  1.1     lukem 	default:
   1804  1.1     lukem 		break;
   1805  1.1     lukem 	}
   1806  1.1     lukem 
   1807  1.1     lukem 	/* Must run an internal search. */
   1808  1.1     lukem 	if ( op.ors_filter == NULL ) {
   1809  1.1     lukem 		rc = LDAP_FILTER_ERROR;
   1810  1.1     lukem 		goto CONCLUDED;
   1811  1.1     lukem 	}
   1812  1.1     lukem 
   1813  1.1     lukem 	Debug( LDAP_DEBUG_TRACE,
   1814  1.1     lukem 	   "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
   1815  1.1     lukem 	   op.o_req_ndn.bv_val, op.ors_scope, 0 );
   1816  1.1     lukem 
   1817  1.1     lukem 	op.o_bd = select_backend( &op.o_req_ndn, 1 );
   1818  1.1     lukem 	if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
   1819  1.1     lukem 		rc = LDAP_INAPPROPRIATE_AUTH;
   1820  1.1     lukem 		goto CONCLUDED;
   1821  1.1     lukem 	}
   1822  1.1     lukem 
   1823  1.1     lukem 	op.o_hdr = opx->o_hdr;
   1824  1.1     lukem 	op.o_tag = LDAP_REQ_SEARCH;
   1825  1.1     lukem 	op.o_ndn = *authc;
   1826  1.1     lukem 	op.o_callback = &cb;
   1827  1.1     lukem 	slap_op_time( &op.o_time, &op.o_tincr );
   1828  1.1     lukem 	op.o_do_not_cache = 1;
   1829  1.1     lukem 	op.o_is_auth_check = 1;
   1830  1.1     lukem 	/* use req_ndn as req_dn instead of non-pretty base of uri */
   1831  1.1     lukem 	if( !BER_BVISNULL( &base ) ) {
   1832  1.1     lukem 		ch_free( base.bv_val );
   1833  1.1     lukem 		/* just in case... */
   1834  1.1     lukem 		BER_BVZERO( &base );
   1835  1.1     lukem 	}
   1836  1.1     lukem 	ber_dupbv_x( &op.o_req_dn, &op.o_req_ndn, op.o_tmpmemctx );
   1837  1.1     lukem 	op.ors_deref = LDAP_DEREF_NEVER;
   1838  1.1     lukem 	op.ors_slimit = 1;
   1839  1.1     lukem 	op.ors_tlimit = SLAP_NO_LIMIT;
   1840  1.1     lukem 	op.ors_attrs = slap_anlist_no_attrs;
   1841  1.1     lukem 	op.ors_attrsonly = 1;
   1842  1.1     lukem 
   1843  1.1     lukem 	op.o_bd->be_search( &op, &rs );
   1844  1.1     lukem 
   1845  1.1     lukem 	if (sm.match) {
   1846  1.1     lukem 		rc = LDAP_SUCCESS;
   1847  1.1     lukem 	} else {
   1848  1.1     lukem 		rc = LDAP_INAPPROPRIATE_AUTH;
   1849  1.1     lukem 	}
   1850  1.1     lukem 
   1851  1.1     lukem CONCLUDED:
   1852  1.1     lukem 	if( !BER_BVISNULL( &op.o_req_dn ) ) slap_sl_free( op.o_req_dn.bv_val, opx->o_tmpmemctx );
   1853  1.1     lukem 	if( !BER_BVISNULL( &op.o_req_ndn ) ) slap_sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
   1854  1.2  christos 	if( op.ors_filter ) filter_free_x( opx, op.ors_filter, 1 );
   1855  1.1     lukem 	if( !BER_BVISNULL( &op.ors_filterstr ) ) ch_free( op.ors_filterstr.bv_val );
   1856  1.1     lukem 
   1857  1.1     lukem 	Debug( LDAP_DEBUG_TRACE,
   1858  1.1     lukem 	   "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
   1859  1.1     lukem 
   1860  1.1     lukem 	return( rc );
   1861  1.1     lukem }
   1862  1.1     lukem 
   1863  1.1     lukem 
   1864  1.1     lukem /*
   1865  1.1     lukem  * This function answers the question, "Can this ID authorize to that ID?",
   1866  1.1     lukem  * based on authorization rules. The rules are stored in the *searchDN, in the
   1867  1.1     lukem  * attribute named by *attr. If any of those rules map to the *assertDN, the
   1868  1.1     lukem  * authorization is approved.
   1869  1.1     lukem  *
   1870  1.1     lukem  * The DNs should not have the dn: prefix
   1871  1.1     lukem  */
   1872  1.1     lukem static int
   1873  1.1     lukem slap_sasl_check_authz( Operation *op,
   1874  1.1     lukem 	struct berval *searchDN,
   1875  1.1     lukem 	struct berval *assertDN,
   1876  1.1     lukem 	AttributeDescription *ad,
   1877  1.1     lukem 	struct berval *authc )
   1878  1.1     lukem {
   1879  1.1     lukem 	int		rc,
   1880  1.1     lukem 			do_not_cache = op->o_do_not_cache;
   1881  1.1     lukem 	BerVarray	vals = NULL;
   1882  1.1     lukem 
   1883  1.1     lukem 	Debug( LDAP_DEBUG_TRACE,
   1884  1.1     lukem 	   "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
   1885  1.1     lukem 	   assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
   1886  1.1     lukem 
   1887  1.1     lukem 	/* ITS#4760: don't cache group access */
   1888  1.1     lukem 	op->o_do_not_cache = 1;
   1889  1.1     lukem 	rc = backend_attribute( op, NULL, searchDN, ad, &vals, ACL_AUTH );
   1890  1.1     lukem 	op->o_do_not_cache = do_not_cache;
   1891  1.1     lukem 	if( rc != LDAP_SUCCESS ) goto COMPLETE;
   1892  1.1     lukem 
   1893  1.1     lukem 	/* Check if the *assertDN matches any *vals */
   1894  1.1     lukem 	rc = slap_sasl_matches( op, vals, assertDN, authc );
   1895  1.1     lukem 
   1896  1.1     lukem COMPLETE:
   1897  1.1     lukem 	if( vals ) ber_bvarray_free_x( vals, op->o_tmpmemctx );
   1898  1.1     lukem 
   1899  1.1     lukem 	Debug( LDAP_DEBUG_TRACE,
   1900  1.1     lukem 	   "<==slap_sasl_check_authz: %s check returning %d\n",
   1901  1.1     lukem 		ad->ad_cname.bv_val, rc, 0);
   1902  1.1     lukem 
   1903  1.1     lukem 	return( rc );
   1904  1.1     lukem }
   1905  1.1     lukem 
   1906  1.1     lukem /*
   1907  1.1     lukem  * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
   1908  1.1     lukem  * return the LDAP DN to which it matches. The SASL regexp rules in the config
   1909  1.1     lukem  * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
   1910  1.1     lukem  * search with scope=base), just return the URI (or its searchbase). Otherwise
   1911  1.1     lukem  * an internal search must be done, and if that search returns exactly one
   1912  1.1     lukem  * entry, return the DN of that one entry.
   1913  1.1     lukem  */
   1914  1.1     lukem void
   1915  1.1     lukem slap_sasl2dn(
   1916  1.1     lukem 	Operation	*opx,
   1917  1.1     lukem 	struct berval	*saslname,
   1918  1.1     lukem 	struct berval	*sasldn,
   1919  1.1     lukem 	int		flags )
   1920  1.1     lukem {
   1921  1.1     lukem 	int rc;
   1922  1.1     lukem 	slap_callback cb = { NULL, sasl_sc_sasl2dn, NULL, NULL };
   1923  1.1     lukem 	Operation op = {0};
   1924  1.1     lukem 	SlapReply rs = {REP_RESULT};
   1925  1.1     lukem 	struct berval regout = BER_BVNULL;
   1926  1.1     lukem 	struct berval base = BER_BVNULL;
   1927  1.1     lukem 
   1928  1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
   1929  1.1     lukem 		"converting SASL name %s to a DN\n",
   1930  1.1     lukem 		saslname->bv_val, 0,0 );
   1931  1.1     lukem 
   1932  1.1     lukem 	BER_BVZERO( sasldn );
   1933  1.1     lukem 	cb.sc_private = sasldn;
   1934  1.1     lukem 
   1935  1.1     lukem 	/* Convert the SASL name into a minimal URI */
   1936  1.1     lukem 	if( !slap_authz_regexp( saslname, &regout, flags, opx->o_tmpmemctx ) ) {
   1937  1.1     lukem 		goto FINISHED;
   1938  1.1     lukem 	}
   1939  1.1     lukem 
   1940  1.1     lukem 	/* NOTE: always normalize regout because it results
   1941  1.1     lukem 	 * from string submatch expansion */
   1942  1.1     lukem 	rc = slap_parseURI( opx, &regout, &base, &op.o_req_ndn,
   1943  1.1     lukem 		&op.ors_scope, &op.ors_filter, &op.ors_filterstr, 1 );
   1944  1.1     lukem 	if ( !BER_BVISNULL( &regout ) ) slap_sl_free( regout.bv_val, opx->o_tmpmemctx );
   1945  1.1     lukem 	if ( rc != LDAP_SUCCESS ) {
   1946  1.1     lukem 		goto FINISHED;
   1947  1.1     lukem 	}
   1948  1.1     lukem 
   1949  1.1     lukem 	/* Must do an internal search */
   1950  1.1     lukem 	op.o_bd = select_backend( &op.o_req_ndn, 1 );
   1951  1.1     lukem 
   1952  1.1     lukem 	switch ( op.ors_scope ) {
   1953  1.1     lukem 	case LDAP_X_SCOPE_EXACT:
   1954  1.1     lukem 		*sasldn = op.o_req_ndn;
   1955  1.1     lukem 		BER_BVZERO( &op.o_req_ndn );
   1956  1.1     lukem 		/* intentionally continue to next case */
   1957  1.1     lukem 
   1958  1.1     lukem 	case LDAP_X_SCOPE_REGEX:
   1959  1.1     lukem 	case LDAP_X_SCOPE_SUBTREE:
   1960  1.1     lukem 	case LDAP_X_SCOPE_CHILDREN:
   1961  1.1     lukem 	case LDAP_X_SCOPE_ONELEVEL:
   1962  1.1     lukem 	case LDAP_X_SCOPE_GROUP:
   1963  1.1     lukem 	case LDAP_X_SCOPE_USERS:
   1964  1.1     lukem 		/* correctly parsed, but illegal */
   1965  1.1     lukem 		goto FINISHED;
   1966  1.1     lukem 
   1967  1.1     lukem 	case LDAP_SCOPE_BASE:
   1968  1.1     lukem 	case LDAP_SCOPE_ONELEVEL:
   1969  1.1     lukem 	case LDAP_SCOPE_SUBTREE:
   1970  1.1     lukem 	case LDAP_SCOPE_SUBORDINATE:
   1971  1.1     lukem 		/* do a search */
   1972  1.1     lukem 		break;
   1973  1.1     lukem 
   1974  1.1     lukem 	default:
   1975  1.1     lukem 		/* catch unhandled cases (there shouldn't be) */
   1976  1.1     lukem 		assert( 0 );
   1977  1.1     lukem 	}
   1978  1.1     lukem 
   1979  1.1     lukem 	Debug( LDAP_DEBUG_TRACE,
   1980  1.1     lukem 		"slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
   1981  1.1     lukem 		op.o_req_ndn.bv_val, op.ors_scope, 0 );
   1982  1.1     lukem 
   1983  1.1     lukem 	if ( ( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL) ) {
   1984  1.1     lukem 		goto FINISHED;
   1985  1.1     lukem 	}
   1986  1.1     lukem 
   1987  1.1     lukem 	/* Must run an internal search. */
   1988  1.1     lukem 	if ( op.ors_filter == NULL ) {
   1989  1.1     lukem 		rc = LDAP_FILTER_ERROR;
   1990  1.1     lukem 		goto FINISHED;
   1991  1.1     lukem 	}
   1992  1.1     lukem 
   1993  1.1     lukem 	op.o_hdr = opx->o_hdr;
   1994  1.1     lukem 	op.o_tag = LDAP_REQ_SEARCH;
   1995  1.1     lukem 	op.o_ndn = opx->o_conn->c_ndn;
   1996  1.1     lukem 	op.o_callback = &cb;
   1997  1.1     lukem 	slap_op_time( &op.o_time, &op.o_tincr );
   1998  1.1     lukem 	op.o_do_not_cache = 1;
   1999  1.1     lukem 	op.o_is_auth_check = 1;
   2000  1.1     lukem 	op.ors_deref = LDAP_DEREF_NEVER;
   2001  1.1     lukem 	op.ors_slimit = 1;
   2002  1.1     lukem 	op.ors_tlimit = SLAP_NO_LIMIT;
   2003  1.1     lukem 	op.ors_attrs = slap_anlist_no_attrs;
   2004  1.1     lukem 	op.ors_attrsonly = 1;
   2005  1.1     lukem 	/* use req_ndn as req_dn instead of non-pretty base of uri */
   2006  1.1     lukem 	if( !BER_BVISNULL( &base ) ) {
   2007  1.1     lukem 		ch_free( base.bv_val );
   2008  1.1     lukem 		/* just in case... */
   2009  1.1     lukem 		BER_BVZERO( &base );
   2010  1.1     lukem 	}
   2011  1.1     lukem 	ber_dupbv_x( &op.o_req_dn, &op.o_req_ndn, op.o_tmpmemctx );
   2012  1.1     lukem 
   2013  1.1     lukem 	op.o_bd->be_search( &op, &rs );
   2014  1.1     lukem 
   2015  1.1     lukem FINISHED:
   2016  1.2  christos 	if( opx == opx->o_conn->c_sasl_bindop && !BER_BVISEMPTY( sasldn ) ) {
   2017  1.1     lukem 		opx->o_conn->c_authz_backend = op.o_bd;
   2018  1.1     lukem 	}
   2019  1.1     lukem 	if( !BER_BVISNULL( &op.o_req_dn ) ) {
   2020  1.1     lukem 		slap_sl_free( op.o_req_dn.bv_val, opx->o_tmpmemctx );
   2021  1.1     lukem 	}
   2022  1.1     lukem 	if( !BER_BVISNULL( &op.o_req_ndn ) ) {
   2023  1.1     lukem 		slap_sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
   2024  1.1     lukem 	}
   2025  1.1     lukem 	if( op.ors_filter ) {
   2026  1.2  christos 		filter_free_x( opx, op.ors_filter, 1 );
   2027  1.1     lukem 	}
   2028  1.1     lukem 	if( !BER_BVISNULL( &op.ors_filterstr ) ) {
   2029  1.1     lukem 		ch_free( op.ors_filterstr.bv_val );
   2030  1.1     lukem 	}
   2031  1.1     lukem 
   2032  1.1     lukem 	Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
   2033  1.1     lukem 		!BER_BVISEMPTY( sasldn ) ? sasldn->bv_val : "<nothing>", 0, 0 );
   2034  1.1     lukem 
   2035  1.1     lukem 	return;
   2036  1.1     lukem }
   2037  1.1     lukem 
   2038  1.1     lukem 
   2039  1.1     lukem /* Check if a bind can SASL authorize to another identity.
   2040  1.1     lukem  * The DNs should not have the dn: prefix
   2041  1.1     lukem  */
   2042  1.1     lukem 
   2043  1.1     lukem int slap_sasl_authorized( Operation *op,
   2044  1.1     lukem 	struct berval *authcDN, struct berval *authzDN )
   2045  1.1     lukem {
   2046  1.1     lukem 	int rc = LDAP_INAPPROPRIATE_AUTH;
   2047  1.1     lukem 
   2048  1.1     lukem 	/* User binding as anonymous */
   2049  1.1     lukem 	if ( !authzDN || !authzDN->bv_len || !authzDN->bv_val ) {
   2050  1.1     lukem 		rc = LDAP_SUCCESS;
   2051  1.1     lukem 		goto DONE;
   2052  1.1     lukem 	}
   2053  1.1     lukem 
   2054  1.1     lukem 	/* User is anonymous */
   2055  1.1     lukem 	if ( !authcDN || !authcDN->bv_len || !authcDN->bv_val ) {
   2056  1.1     lukem 		goto DONE;
   2057  1.1     lukem 	}
   2058  1.1     lukem 
   2059  1.1     lukem 	Debug( LDAP_DEBUG_TRACE,
   2060  1.1     lukem 	   "==>slap_sasl_authorized: can %s become %s?\n",
   2061  1.1     lukem 		authcDN->bv_len ? authcDN->bv_val : "(null)",
   2062  1.1     lukem 		authzDN->bv_len ? authzDN->bv_val : "(null)",  0 );
   2063  1.1     lukem 
   2064  1.1     lukem 	/* If person is authorizing to self, succeed */
   2065  1.1     lukem 	if ( dn_match( authcDN, authzDN ) ) {
   2066  1.1     lukem 		rc = LDAP_SUCCESS;
   2067  1.1     lukem 		goto DONE;
   2068  1.1     lukem 	}
   2069  1.1     lukem 
   2070  1.2  christos 	/* Allow the manager to authorize as any DN in its own DBs. */
   2071  1.1     lukem 	{
   2072  1.2  christos 		Backend *zbe = select_backend( authzDN, 1 );
   2073  1.2  christos 		if ( zbe && be_isroot_dn( zbe, authcDN )) {
   2074  1.2  christos 			rc = LDAP_SUCCESS;
   2075  1.2  christos 			goto DONE;
   2076  1.2  christos 		}
   2077  1.1     lukem 	}
   2078  1.1     lukem 
   2079  1.1     lukem 	/* Check source rules */
   2080  1.1     lukem 	if( authz_policy & SASL_AUTHZ_TO ) {
   2081  1.1     lukem 		rc = slap_sasl_check_authz( op, authcDN, authzDN,
   2082  1.1     lukem 			slap_schema.si_ad_saslAuthzTo, authcDN );
   2083  1.2  christos 		if(( rc == LDAP_SUCCESS ) ^ (( authz_policy & SASL_AUTHZ_AND) != 0)) {
   2084  1.2  christos 			if( rc != LDAP_SUCCESS )
   2085  1.2  christos 				rc = LDAP_INAPPROPRIATE_AUTH;
   2086  1.1     lukem 			goto DONE;
   2087  1.1     lukem 		}
   2088  1.1     lukem 	}
   2089  1.1     lukem 
   2090  1.1     lukem 	/* Check destination rules */
   2091  1.1     lukem 	if( authz_policy & SASL_AUTHZ_FROM ) {
   2092  1.1     lukem 		rc = slap_sasl_check_authz( op, authzDN, authcDN,
   2093  1.1     lukem 			slap_schema.si_ad_saslAuthzFrom, authcDN );
   2094  1.1     lukem 		if( rc == LDAP_SUCCESS ) {
   2095  1.1     lukem 			goto DONE;
   2096  1.1     lukem 		}
   2097  1.1     lukem 	}
   2098  1.1     lukem 
   2099  1.1     lukem 	rc = LDAP_INAPPROPRIATE_AUTH;
   2100  1.1     lukem 
   2101  1.1     lukem DONE:
   2102  1.1     lukem 
   2103  1.1     lukem 	Debug( LDAP_DEBUG_TRACE,
   2104  1.1     lukem 		"<== slap_sasl_authorized: return %d\n", rc, 0, 0 );
   2105  1.1     lukem 
   2106  1.1     lukem 	return( rc );
   2107  1.1     lukem }
   2108