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