X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fsaslauthz.c;h=42bb8a136810b99e193f7fd7f0f886832b6fe215;hb=93d0ef91e65c6d11991b1c36faba67f212f43a34;hp=3faedc8ff1e75cdcbdc55e8132edcec83f45d3c3;hpb=3a5bde98ba61a853f4305d6c844f4aad439c8a4a;p=openldap
diff --git a/servers/slapd/saslauthz.c b/servers/slapd/saslauthz.c
index 3faedc8ff1..42bb8a1368 100644
--- a/servers/slapd/saslauthz.c
+++ b/servers/slapd/saslauthz.c
@@ -1,7 +1,7 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software .
*
- * Copyright 1998-2004 The OpenLDAP Foundation.
+ * Copyright 1998-2005 The OpenLDAP Foundation.
* Portions Copyright 2000 Mark Adamson, Carnegie Mellon.
* All rights reserved.
*
@@ -17,6 +17,9 @@
#include "portable.h"
#include
+#ifdef HAVE_LIMITS_H
+#include
+#endif
#include
#include
@@ -24,8 +27,6 @@
#include "slap.h"
-#include
-
#include "lutil.h"
#define SASLREGEX_REPLACE 10
@@ -87,10 +88,14 @@ struct rewrite_info *sasl_rwinfo = NULL;
#define SASL_AUTHZ_TO 0x02
#define SASL_AUTHZ_AND 0x10
+static const char *policy_txt[] = {
+ "none", "from", "to", "any"
+};
+
static int authz_policy = SASL_AUTHZ_NONE;
-static
-int slap_sasl_match( Operation *opx, struct berval *rule,
+static int
+slap_sasl_match( Operation *opx, struct berval *rule,
struct berval *assertDN, struct berval *authc );
int slap_sasl_setpolicy( const char *arg )
@@ -113,16 +118,24 @@ int slap_sasl_setpolicy( const char *arg )
return rc;
}
+const char * slap_sasl_getpolicy()
+{
+ if ( authz_policy == (SASL_AUTHZ_FROM | SASL_AUTHZ_TO | SASL_AUTHZ_AND) )
+ return "all";
+ else
+ return policy_txt[authz_policy];
+}
+
int slap_parse_user( struct berval *id, struct berval *user,
struct berval *realm, struct berval *mech )
{
char u;
- assert( id );
+ assert( id != NULL );
assert( !BER_BVISNULL( id ) );
- assert( user );
- assert( realm );
- assert( mech );
+ assert( user != NULL );
+ assert( realm != NULL );
+ assert( mech != NULL );
u = id->bv_val[ 0 ];
@@ -135,7 +148,7 @@ int slap_parse_user( struct berval *id, struct berval *user,
* u[.mech[/realm]]:user
*/
- user->bv_val = strchr( id->bv_val, ':' );
+ user->bv_val = ber_bvchr( id, ':' );
if ( BER_BVISNULL( user ) ) {
return LDAP_PROTOCOL_ERROR;
}
@@ -143,20 +156,19 @@ int slap_parse_user( struct berval *id, struct berval *user,
user->bv_val++;
user->bv_len = id->bv_len - ( user->bv_val - id->bv_val );
- mech->bv_val = strchr( id->bv_val, '.' );
+ mech->bv_val = ber_bvchr( id, '.' );
if ( !BER_BVISNULL( mech ) ) {
mech->bv_val[ 0 ] = '\0';
mech->bv_val++;
+ mech->bv_len = user->bv_val - mech->bv_val - 1;
- realm->bv_val = strchr( mech->bv_val, '/' );
+ realm->bv_val = ber_bvchr( mech, '/' );
if ( !BER_BVISNULL( realm ) ) {
realm->bv_val[ 0 ] = '\0';
realm->bv_val++;
mech->bv_len = realm->bv_val - mech->bv_val - 1;
realm->bv_len = user->bv_val - realm->bv_val - 1;
- } else {
- mech->bv_len = user->bv_val - mech->bv_val - 1;
}
} else {
@@ -190,13 +202,743 @@ int slap_parse_user( struct berval *id, struct berval *user,
return LDAP_SUCCESS;
}
-static int slap_parseURI( Operation *op, struct berval *uri,
- struct berval *base, struct berval *nbase,
- int *scope, Filter **filter, struct berval *fstr )
+#ifdef SLAP_AUTHZ_SYNTAX
+int
+authzValidate(
+ Syntax *syntax,
+ struct berval *in )
{
- struct berval bv;
- int rc;
- LDAPURLDesc *ludp;
+ struct berval bv;
+ int rc = LDAP_INVALID_SYNTAX;
+ LDAPURLDesc *ludp = NULL;
+ int scope = -1;
+
+ /*
+ * 1)
+ * 2) dn[.{exact|children|subtree|onelevel}]:{*|}
+ * 3) dn.regex:
+ * 4) u[.mech[/realm]]:
+ * 5) group[/[/]]:
+ * 6)
+ */
+
+ assert( in != NULL );
+ assert( !BER_BVISNULL( in ) );
+
+ Debug( LDAP_DEBUG_TRACE,
+ "authzValidate: parsing %s\n", in->bv_val, 0, 0 );
+
+ /*
+ * 2) dn[.{exact|children|subtree|onelevel}]:{*|}
+ * 3) dn.regex:
+ *
+ * must pass DN normalization
+ */
+ if ( !strncasecmp( in->bv_val, "dn", STRLENOF( "dn" ) ) ) {
+ bv.bv_val = in->bv_val + STRLENOF( "dn" );
+
+ if ( bv.bv_val[ 0 ] == '.' ) {
+ bv.bv_val++;
+
+ if ( !strncasecmp( bv.bv_val, "exact:", STRLENOF( "exact:" ) ) ) {
+ bv.bv_val += STRLENOF( "exact:" );
+ scope = LDAP_X_SCOPE_EXACT;
+
+ } else if ( !strncasecmp( bv.bv_val, "regex:", STRLENOF( "regex:" ) ) ) {
+ bv.bv_val += STRLENOF( "regex:" );
+ scope = LDAP_X_SCOPE_REGEX;
+
+ } else if ( !strncasecmp( bv.bv_val, "children:", STRLENOF( "children:" ) ) ) {
+ bv.bv_val += STRLENOF( "children:" );
+ scope = LDAP_X_SCOPE_CHILDREN;
+
+ } else if ( !strncasecmp( bv.bv_val, "subtree:", STRLENOF( "subtree:" ) ) ) {
+ bv.bv_val += STRLENOF( "subtree:" );
+ scope = LDAP_X_SCOPE_SUBTREE;
+
+ } else if ( !strncasecmp( bv.bv_val, "onelevel:", STRLENOF( "onelevel:" ) ) ) {
+ bv.bv_val += STRLENOF( "onelevel:" );
+ scope = LDAP_X_SCOPE_ONELEVEL;
+
+ } else {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ } else {
+ if ( bv.bv_val[ 0 ] != ':' ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ scope = LDAP_X_SCOPE_EXACT;
+ bv.bv_val++;
+ }
+
+ bv.bv_val += strspn( bv.bv_val, " " );
+ /* jump here in case no type specification was present
+ * and uri was not an URI... HEADS-UP: assuming EXACT */
+is_dn: bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
+
+ /* a single '*' means any DN without using regexes */
+ if ( ber_bvccmp( &bv, '*' ) ) {
+ /* LDAP_X_SCOPE_USERS */
+ return LDAP_SUCCESS;
+ }
+
+ switch ( scope ) {
+ case LDAP_X_SCOPE_EXACT:
+ case LDAP_X_SCOPE_CHILDREN:
+ case LDAP_X_SCOPE_SUBTREE:
+ case LDAP_X_SCOPE_ONELEVEL:
+ return dnValidate( NULL, &bv );
+
+ case LDAP_X_SCOPE_REGEX:
+ return LDAP_SUCCESS;
+ }
+
+ return rc;
+
+ /*
+ * 4) u[.mech[/realm]]:
+ */
+ } else if ( ( in->bv_val[ 0 ] == 'u' || in->bv_val[ 0 ] == 'U' )
+ && ( in->bv_val[ 1 ] == ':'
+ || in->bv_val[ 1 ] == '/'
+ || in->bv_val[ 1 ] == '.' ) )
+ {
+ char buf[ SLAP_LDAPDN_MAXLEN ];
+ struct berval id,
+ user = BER_BVNULL,
+ realm = BER_BVNULL,
+ mech = BER_BVNULL;
+
+ if ( sizeof( buf ) <= in->bv_len ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ id.bv_len = in->bv_len;
+ id.bv_val = buf;
+ strncpy( buf, in->bv_val, sizeof( buf ) );
+
+ rc = slap_parse_user( &id, &user, &realm, &mech );
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ return rc;
+
+ /*
+ * 5) group[/groupClass[/memberAttr]]:
+ *
+ * defaults to "groupOfNames"
+ * defaults to "member"
+ *
+ * must pass DN normalization
+ */
+ } else if ( strncasecmp( in->bv_val, "group", STRLENOF( "group" ) ) == 0 )
+ {
+ struct berval group_dn = BER_BVNULL,
+ group_oc = BER_BVNULL,
+ member_at = BER_BVNULL;
+
+ bv.bv_val = in->bv_val + STRLENOF( "group" );
+ bv.bv_len = in->bv_len - STRLENOF( "group" );
+ group_dn.bv_val = ber_bvchr( &bv, ':' );
+ if ( group_dn.bv_val == NULL ) {
+ /* last chance: assume it's a(n exact) DN ... */
+ bv.bv_val = in->bv_val;
+ scope = LDAP_X_SCOPE_EXACT;
+ goto is_dn;
+ }
+
+ /*
+ * FIXME: we assume that "member" and "groupOfNames"
+ * are present in schema...
+ */
+ if ( bv.bv_val[ 0 ] == '/' ) {
+ group_oc.bv_val = &bv.bv_val[ 1 ];
+ group_oc.bv_len = group_dn.bv_val - group_oc.bv_val;
+
+ member_at.bv_val = ber_bvchr( &group_oc, '/' );
+ if ( member_at.bv_val ) {
+ AttributeDescription *ad = NULL;
+ const char *text = NULL;
+
+ group_oc.bv_len = member_at.bv_val - group_oc.bv_val;
+ member_at.bv_val++;
+ member_at.bv_len = group_dn.bv_val - member_at.bv_val;
+ rc = slap_bv2ad( &member_at, &ad, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ return rc;
+ }
+ }
+
+ if ( oc_bvfind( &group_oc ) == NULL ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ group_dn.bv_val++;
+ group_dn.bv_len = in->bv_len - ( group_dn.bv_val - in->bv_val );
+
+ rc = dnValidate( NULL, &group_dn );
+ if ( rc != LDAP_SUCCESS ) {
+ return rc;
+ }
+
+ return rc;
+ }
+
+ /*
+ * ldap:///???
+ * ::= {base|one|subtree}
+ *
+ * defaults to "base"
+ * must pass DN normalization
+ * must pass str2filter()
+ */
+ rc = ldap_url_parse( in->bv_val, &ludp );
+ switch ( rc ) {
+ case LDAP_URL_SUCCESS:
+ /* FIXME: the check is pedantic, but I think it's necessary,
+ * because people tend to use things like ldaps:// which
+ * gives the idea SSL is being used. Maybe we could
+ * accept ldapi:// as well, but the point is that we use
+ * an URL as an easy means to define bits of a search with
+ * little parsing.
+ */
+ if ( strcasecmp( ludp->lud_scheme, "ldap" ) != 0 ) {
+ /*
+ * must be ldap:///
+ */
+ rc = LDAP_INVALID_SYNTAX;
+ goto done;
+ }
+ break;
+
+ case LDAP_URL_ERR_BADSCHEME:
+ /*
+ * last chance: assume it's a(n exact) DN ...
+ *
+ * NOTE: must pass DN normalization
+ */
+ ldap_free_urldesc( ludp );
+ bv.bv_val = in->bv_val;
+ scope = LDAP_X_SCOPE_EXACT;
+ goto is_dn;
+
+ default:
+ rc = LDAP_INVALID_SYNTAX;
+ goto done;
+ }
+
+ if ( ( ludp->lud_host && *ludp->lud_host )
+ || ludp->lud_attrs || ludp->lud_exts )
+ {
+ /* host part must be empty */
+ /* attrs and extensions parts must be empty */
+ rc = LDAP_INVALID_SYNTAX;
+ goto done;
+ }
+
+ /* Grab the filter */
+ if ( ludp->lud_filter ) {
+ Filter *f = str2filter( ludp->lud_filter );
+ if ( f == NULL ) {
+ rc = LDAP_INVALID_SYNTAX;
+ goto done;
+ }
+ filter_free( f );
+ }
+
+ /* Grab the searchbase */
+ assert( ludp->lud_dn != NULL );
+ ber_str2bv( ludp->lud_dn, 0, 0, &bv );
+ rc = dnValidate( NULL, &bv );
+
+done:
+ ldap_free_urldesc( ludp );
+ return( rc );
+}
+
+#if 0
+int
+authzMatch(
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue )
+{
+ return octetStringMatch( matchp, flags, syntax, mr, value, assertedValue );
+}
+#endif
+
+static int
+authzPrettyNormal(
+ struct berval *val,
+ struct berval *normalized,
+ void *ctx,
+ int normalize )
+{
+ struct berval bv;
+ int rc = LDAP_INVALID_SYNTAX;
+ LDAPURLDesc *ludp = NULL;
+ char *lud_dn = NULL,
+ *lud_filter = NULL;
+ int scope = -1;
+
+ /*
+ * 1)
+ * 2) dn[.{exact|children|subtree|onelevel}]:{*|}
+ * 3) dn.regex:
+ * 4) u[.mech[/realm]]:
+ * 5) group[/[/]]:
+ * 6)
+ */
+
+ assert( val != NULL );
+ assert( !BER_BVISNULL( val ) );
+
+ /*
+ * 2) dn[.{exact|children|subtree|onelevel}]:{*|}
+ * 3) dn.regex:
+ *
+ * must pass DN normalization
+ */
+ if ( !strncasecmp( val->bv_val, "dn", STRLENOF( "dn" ) ) ) {
+ struct berval out = BER_BVNULL,
+ prefix = BER_BVNULL;
+ char *ptr;
+
+ bv.bv_val = val->bv_val + STRLENOF( "dn" );
+
+ if ( bv.bv_val[ 0 ] == '.' ) {
+ bv.bv_val++;
+
+ if ( !strncasecmp( bv.bv_val, "exact:", STRLENOF( "exact:" ) ) ) {
+ bv.bv_val += STRLENOF( "exact:" );
+ scope = LDAP_X_SCOPE_EXACT;
+
+ } else if ( !strncasecmp( bv.bv_val, "regex:", STRLENOF( "regex:" ) ) ) {
+ bv.bv_val += STRLENOF( "regex:" );
+ scope = LDAP_X_SCOPE_REGEX;
+
+ } else if ( !strncasecmp( bv.bv_val, "children:", STRLENOF( "children:" ) ) ) {
+ bv.bv_val += STRLENOF( "children:" );
+ scope = LDAP_X_SCOPE_CHILDREN;
+
+ } else if ( !strncasecmp( bv.bv_val, "subtree:", STRLENOF( "subtree:" ) ) ) {
+ bv.bv_val += STRLENOF( "subtree:" );
+ scope = LDAP_X_SCOPE_SUBTREE;
+
+ } else if ( !strncasecmp( bv.bv_val, "onelevel:", STRLENOF( "onelevel:" ) ) ) {
+ bv.bv_val += STRLENOF( "onelevel:" );
+ scope = LDAP_X_SCOPE_ONELEVEL;
+
+ } else {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ } else {
+ if ( bv.bv_val[ 0 ] != ':' ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ scope = LDAP_X_SCOPE_EXACT;
+ bv.bv_val++;
+ }
+
+ bv.bv_val += strspn( bv.bv_val, " " );
+ /* jump here in case no type specification was present
+ * and uri was not an URI... HEADS-UP: assuming EXACT */
+is_dn: bv.bv_len = val->bv_len - ( bv.bv_val - val->bv_val );
+
+ /* a single '*' means any DN without using regexes */
+ if ( ber_bvccmp( &bv, '*' ) ) {
+ ber_str2bv_x( "dn:*", STRLENOF( "dn:*" ), 1, normalized, ctx );
+ return LDAP_SUCCESS;
+ }
+
+ switch ( scope ) {
+ case LDAP_X_SCOPE_EXACT:
+ case LDAP_X_SCOPE_CHILDREN:
+ case LDAP_X_SCOPE_SUBTREE:
+ case LDAP_X_SCOPE_ONELEVEL:
+ if ( normalize ) {
+ rc = dnNormalize( 0, NULL, NULL, &bv, &out, ctx );
+ } else {
+ rc = dnPretty( NULL, &bv, &out, ctx );
+ }
+ if( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ break;
+
+ case LDAP_X_SCOPE_REGEX:
+ normalized->bv_len = STRLENOF( "dn.regex:" ) + bv.bv_len;
+ normalized->bv_val = ber_memalloc_x( normalized->bv_len + 1, ctx );
+ ptr = lutil_strcopy( normalized->bv_val, "dn.regex:" );
+ ptr = lutil_strncopy( ptr, bv.bv_val, bv.bv_len );
+ ptr[ 0 ] = '\0';
+ return LDAP_SUCCESS;
+
+ default:
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ /* prepare prefix */
+ switch ( scope ) {
+ case LDAP_X_SCOPE_EXACT:
+ BER_BVSTR( &prefix, "dn:" );
+ break;
+
+ case LDAP_X_SCOPE_CHILDREN:
+ BER_BVSTR( &prefix, "dn.children:" );
+ break;
+
+ case LDAP_X_SCOPE_SUBTREE:
+ BER_BVSTR( &prefix, "dn.subtree:" );
+ break;
+
+ case LDAP_X_SCOPE_ONELEVEL:
+ BER_BVSTR( &prefix, "dn.onelevel:" );
+ break;
+
+ default:
+ assert( 0 );
+ break;
+ }
+
+ normalized->bv_len = prefix.bv_len + out.bv_len;
+ normalized->bv_val = ber_memalloc_x( normalized->bv_len + 1, ctx );
+
+ ptr = lutil_strcopy( normalized->bv_val, prefix.bv_val );
+ ptr = lutil_strncopy( ptr, out.bv_val, out.bv_len );
+ ptr[ 0 ] = '\0';
+ ber_memfree_x( out.bv_val, ctx );
+
+ return LDAP_SUCCESS;
+
+ /*
+ * 4) u[.mech[/realm]]:
+ */
+ } else if ( ( val->bv_val[ 0 ] == 'u' || val->bv_val[ 0 ] == 'U' )
+ && ( val->bv_val[ 1 ] == ':'
+ || val->bv_val[ 1 ] == '/'
+ || val->bv_val[ 1 ] == '.' ) )
+ {
+ char buf[ SLAP_LDAPDN_MAXLEN ];
+ struct berval id,
+ user = BER_BVNULL,
+ realm = BER_BVNULL,
+ mech = BER_BVNULL;
+
+ if ( sizeof( buf ) <= val->bv_len ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ id.bv_len = val->bv_len;
+ id.bv_val = buf;
+ strncpy( buf, val->bv_val, sizeof( buf ) );
+
+ rc = slap_parse_user( &id, &user, &realm, &mech );
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ ber_dupbv_x( normalized, val, ctx );
+
+ return rc;
+
+ /*
+ * 5) group[/groupClass[/memberAttr]]:
+ *
+ * defaults to "groupOfNames"
+ * defaults to "member"
+ *
+ * must pass DN normalization
+ */
+ } else if ( strncasecmp( val->bv_val, "group", STRLENOF( "group" ) ) == 0 )
+ {
+ struct berval group_dn = BER_BVNULL,
+ group_oc = BER_BVNULL,
+ member_at = BER_BVNULL,
+ out = BER_BVNULL;
+ char *ptr;
+
+ bv.bv_val = val->bv_val + STRLENOF( "group" );
+ bv.bv_len = val->bv_len - STRLENOF( "group" );
+ group_dn.bv_val = ber_bvchr( &bv, ':' );
+ if ( group_dn.bv_val == NULL ) {
+ /* last chance: assume it's a(n exact) DN ... */
+ bv.bv_val = val->bv_val;
+ scope = LDAP_X_SCOPE_EXACT;
+ goto is_dn;
+ }
+
+ /*
+ * FIXME: we assume that "member" and "groupOfNames"
+ * are present in schema...
+ */
+ if ( bv.bv_val[ 0 ] == '/' ) {
+ ObjectClass *oc = NULL;
+
+ group_oc.bv_val = &bv.bv_val[ 1 ];
+ group_oc.bv_len = group_dn.bv_val - group_oc.bv_val;
+
+ member_at.bv_val = ber_bvchr( &group_oc, '/' );
+ if ( member_at.bv_val ) {
+ AttributeDescription *ad = NULL;
+ const char *text = NULL;
+
+ group_oc.bv_len = member_at.bv_val - group_oc.bv_val;
+ member_at.bv_val++;
+ member_at.bv_len = group_dn.bv_val - member_at.bv_val;
+ rc = slap_bv2ad( &member_at, &ad, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ return rc;
+ }
+
+ member_at = ad->ad_cname;
+
+ }
+
+ oc = oc_bvfind( &group_oc );
+ if ( oc == NULL ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ group_oc = oc->soc_cname;
+ }
+
+ group_dn.bv_val++;
+ group_dn.bv_len = val->bv_len - ( group_dn.bv_val - val->bv_val );
+
+ if ( normalize ) {
+ rc = dnNormalize( 0, NULL, NULL, &group_dn, &out, ctx );
+ } else {
+ rc = dnPretty( NULL, &group_dn, &out, ctx );
+ }
+ if ( rc != LDAP_SUCCESS ) {
+ return rc;
+ }
+
+ normalized->bv_len = STRLENOF( "group" ":" ) + out.bv_len;
+ if ( !BER_BVISNULL( &group_oc ) ) {
+ normalized->bv_len += STRLENOF( "/" ) + group_oc.bv_len;
+ if ( !BER_BVISNULL( &member_at ) ) {
+ normalized->bv_len += STRLENOF( "/" ) + member_at.bv_len;
+ }
+ }
+
+ normalized->bv_val = ber_memalloc_x( normalized->bv_len + 1, ctx );
+ ptr = lutil_strcopy( normalized->bv_val, "group" );
+ if ( !BER_BVISNULL( &group_oc ) ) {
+ ptr[ 0 ] = '/';
+ ptr++;
+ ptr = lutil_strncopy( ptr, group_oc.bv_val, group_oc.bv_len );
+ if ( !BER_BVISNULL( &member_at ) ) {
+ ptr[ 0 ] = '/';
+ ptr++;
+ ptr = lutil_strncopy( ptr, member_at.bv_val, member_at.bv_len );
+ }
+ }
+ ptr[ 0 ] = ':';
+ ptr++;
+ ptr = lutil_strncopy( ptr, out.bv_val, out.bv_len );
+ ptr[ 0 ] = '\0';
+ ber_memfree_x( out.bv_val, ctx );
+
+ return rc;
+ }
+
+ /*
+ * ldap:///???
+ * ::= {base|one|subtree}
+ *
+ * defaults to "base"
+ * must pass DN normalization
+ * must pass str2filter()
+ */
+ rc = ldap_url_parse( val->bv_val, &ludp );
+ switch ( rc ) {
+ case LDAP_URL_SUCCESS:
+ /* FIXME: the check is pedantic, but I think it's necessary,
+ * because people tend to use things like ldaps:// which
+ * gives the idea SSL is being used. Maybe we could
+ * accept ldapi:// as well, but the point is that we use
+ * an URL as an easy means to define bits of a search with
+ * little parsing.
+ */
+ if ( strcasecmp( ludp->lud_scheme, "ldap" ) != 0 ) {
+ /*
+ * must be ldap:///
+ */
+ rc = LDAP_INVALID_SYNTAX;
+ goto done;
+ }
+
+ AC_MEMCPY( ludp->lud_scheme, "ldap", STRLENOF( "ldap" ) );
+ break;
+
+ case LDAP_URL_ERR_BADSCHEME:
+ /*
+ * last chance: assume it's a(n exact) DN ...
+ *
+ * NOTE: must pass DN normalization
+ */
+ ldap_free_urldesc( ludp );
+ bv.bv_val = val->bv_val;
+ scope = LDAP_X_SCOPE_EXACT;
+ goto is_dn;
+
+ default:
+ rc = LDAP_INVALID_SYNTAX;
+ goto done;
+ }
+
+ if ( ( ludp->lud_host && *ludp->lud_host )
+ || ludp->lud_attrs || ludp->lud_exts )
+ {
+ /* host part must be empty */
+ /* attrs and extensions parts must be empty */
+ rc = LDAP_INVALID_SYNTAX;
+ goto done;
+ }
+
+ /* Grab the filter */
+ if ( ludp->lud_filter ) {
+ struct berval filterstr;
+ Filter *f;
+
+ lud_filter = ludp->lud_filter;
+
+ f = str2filter( lud_filter );
+ if ( f == NULL ) {
+ rc = LDAP_INVALID_SYNTAX;
+ goto done;
+ }
+ filter2bv( f, &filterstr );
+ filter_free( f );
+ if ( BER_BVISNULL( &filterstr ) ) {
+ rc = LDAP_INVALID_SYNTAX;
+ goto done;
+ }
+
+ ludp->lud_filter = filterstr.bv_val;
+ }
+
+ /* Grab the searchbase */
+ assert( ludp->lud_dn != NULL );
+ if ( ludp->lud_dn ) {
+ struct berval out = BER_BVNULL;
+
+ lud_dn = ludp->lud_dn;
+
+ ber_str2bv( lud_dn, 0, 0, &bv );
+ if ( normalize ) {
+ rc = dnNormalize( 0, NULL, NULL, &bv, &out, ctx );
+ } else {
+ rc = dnPretty( NULL, &bv, &out, ctx );
+ }
+
+ if ( rc != LDAP_SUCCESS ) {
+ goto done;
+ }
+
+ ludp->lud_dn = out.bv_val;
+ }
+
+ ludp->lud_port = 0;
+ normalized->bv_val = ldap_url_desc2str( ludp );
+ if ( normalized->bv_val ) {
+ normalized->bv_len = strlen( normalized->bv_val );
+
+ } else {
+ rc = LDAP_INVALID_SYNTAX;
+ }
+
+done:
+ if ( lud_filter ) {
+ if ( ludp->lud_filter != lud_filter ) {
+ ber_memfree( ludp->lud_filter );
+ }
+ ludp->lud_filter = lud_filter;
+ }
+
+ if ( lud_dn ) {
+ if ( ludp->lud_dn != lud_dn ) {
+ ber_memfree( ludp->lud_dn );
+ }
+ ludp->lud_dn = lud_dn;
+ }
+
+ ldap_free_urldesc( ludp );
+
+ return( rc );
+}
+
+int
+authzNormalize(
+ slap_mask_t usage,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *val,
+ struct berval *normalized,
+ void *ctx )
+{
+ int rc;
+
+ Debug( LDAP_DEBUG_TRACE, ">>> authzNormalize: <%s>\n",
+ val->bv_val, 0, 0 );
+
+ rc = authzPrettyNormal( val, normalized, ctx, 1 );
+
+ Debug( LDAP_DEBUG_TRACE, "<<< authzNormalize: <%s> (%d)\n",
+ normalized->bv_val, rc, 0 );
+
+ return rc;
+}
+
+int
+authzPretty(
+ Syntax *syntax,
+ struct berval *val,
+ struct berval *out,
+ void *ctx)
+{
+ int rc;
+
+ Debug( LDAP_DEBUG_TRACE, ">>> authzPretty: <%s>\n",
+ val->bv_val, 0, 0 );
+
+ rc = authzPrettyNormal( val, out, ctx, 0 );
+
+ Debug( LDAP_DEBUG_TRACE, "<<< authzPretty: <%s> (%d)\n",
+ out->bv_val, rc, 0 );
+
+ return rc;
+}
+
+#endif /* SLAP_AUTHZ_SYNTAX */
+
+static int
+slap_parseURI(
+ Operation *op,
+ struct berval *uri,
+ struct berval *base,
+ struct berval *nbase,
+ int *scope,
+ Filter **filter,
+ struct berval *fstr,
+ int normalize )
+{
+ struct berval bv;
+ int rc;
+ LDAPURLDesc *ludp;
+
+#ifdef SLAP_ORDERED_PRETTYNORM
+ struct berval idx;
+#endif /* SLAP_ORDERED_PRETTYNORM */
assert( uri != NULL && !BER_BVISNULL( uri ) );
BER_BVZERO( base );
@@ -209,6 +951,22 @@ static int slap_parseURI( Operation *op, struct berval *uri,
"slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
rc = LDAP_PROTOCOL_ERROR;
+
+#ifdef SLAP_ORDERED_PRETTYNORM
+ idx = *uri;
+ if ( idx.bv_val[ 0 ] == '{' ) {
+ char *ptr;
+
+ ptr = ber_bvchr( &idx, '}' ) + 1;
+
+ assert( ptr != (void *)1 );
+
+ idx.bv_len -= ptr - idx.bv_val;
+ idx.bv_val = ptr;
+ uri = &idx;
+ }
+#endif /* SLAP_ORDERED_PRETTYNORM */
+
/*
* dn[.]:
* ::= {exact|regex|children|subtree|onelevel}
@@ -269,9 +1027,14 @@ is_dn: bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
case LDAP_X_SCOPE_CHILDREN:
case LDAP_X_SCOPE_SUBTREE:
case LDAP_X_SCOPE_ONELEVEL:
- rc = dnNormalize( 0, NULL, NULL, &bv, nbase, op->o_tmpmemctx );
- if( rc != LDAP_SUCCESS ) {
- *scope = -1;
+ if ( normalize ) {
+ rc = dnNormalize( 0, NULL, NULL, &bv, nbase, op->o_tmpmemctx );
+ if( rc != LDAP_SUCCESS ) {
+ *scope = -1;
+ }
+ } else {
+ ber_dupbv_x( nbase, &bv, op->o_tmpmemctx );
+ rc = LDAP_SUCCESS;
}
break;
@@ -348,7 +1111,8 @@ is_dn: bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
char *tmp;
bv.bv_val = uri->bv_val + STRLENOF( "group" );
- group_dn.bv_val = strchr( bv.bv_val, ':' );
+ bv.bv_len = uri->bv_len - STRLENOF( "group" );
+ group_dn.bv_val = ber_bvchr( &bv, ':' );
if ( group_dn.bv_val == NULL ) {
/* last chance: assume it's a(n exact) DN ... */
bv.bv_val = uri->bv_val;
@@ -358,28 +1122,33 @@ is_dn: bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
if ( bv.bv_val[ 0 ] == '/' ) {
group_oc.bv_val = &bv.bv_val[ 1 ];
+ group_oc.bv_len = group_dn.bv_val - group_oc.bv_val;
- member_at.bv_val = strchr( group_oc.bv_val, '/' );
+ member_at.bv_val = ber_bvchr( &group_oc, '/' );
if ( member_at.bv_val ) {
group_oc.bv_len = member_at.bv_val - group_oc.bv_val;
member_at.bv_val++;
member_at.bv_len = group_dn.bv_val - member_at.bv_val;
} else {
- group_oc.bv_len = group_dn.bv_val - group_oc.bv_val;
- BER_BVSTR( &member_at, "member" );
+ BER_BVSTR( &member_at, SLAPD_GROUP_ATTR );
}
} else {
- BER_BVSTR( &group_oc, "groupOfNames" );
+ BER_BVSTR( &group_oc, SLAPD_GROUP_CLASS );
}
group_dn.bv_val++;
group_dn.bv_len = uri->bv_len - ( group_dn.bv_val - uri->bv_val );
- rc = dnNormalize( 0, NULL, NULL, &group_dn, nbase, op->o_tmpmemctx );
- if ( rc != LDAP_SUCCESS ) {
- *scope = -1;
- return rc;
+ if ( normalize ) {
+ rc = dnNormalize( 0, NULL, NULL, &group_dn, nbase, op->o_tmpmemctx );
+ if ( rc != LDAP_SUCCESS ) {
+ *scope = -1;
+ return rc;
+ }
+ } else {
+ ber_dupbv_x( nbase, &group_dn, op->o_tmpmemctx );
+ rc = LDAP_SUCCESS;
}
*scope = LDAP_X_SCOPE_GROUP;
@@ -411,11 +1180,19 @@ is_dn: bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
rc = ldap_url_parse( uri->bv_val, &ludp );
switch ( rc ) {
case LDAP_URL_SUCCESS:
+ /* FIXME: the check is pedantic, but I think it's necessary,
+ * because people tend to use things like ldaps:// which
+ * gives the idea SSL is being used. Maybe we could
+ * accept ldapi:// as well, but the point is that we use
+ * an URL as an easy means to define bits of a search with
+ * little parsing.
+ */
if ( strcasecmp( ludp->lud_scheme, "ldap" ) != 0 ) {
/*
* must be ldap:///
*/
- return LDAP_PROTOCOL_ERROR;
+ rc = LDAP_PROTOCOL_ERROR;
+ goto done;
}
break;
@@ -425,12 +1202,14 @@ is_dn: bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
*
* NOTE: must pass DN normalization
*/
+ ldap_free_urldesc( ludp );
bv.bv_val = uri->bv_val;
*scope = LDAP_X_SCOPE_EXACT;
goto is_dn;
default:
- return LDAP_PROTOCOL_ERROR;
+ rc = LDAP_PROTOCOL_ERROR;
+ goto done;
}
if ( ( ludp->lud_host && *ludp->lud_host )
@@ -457,7 +1236,12 @@ is_dn: bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
/* Grab the searchbase */
ber_str2bv( ludp->lud_dn, 0, 0, base );
- rc = dnNormalize( 0, NULL, NULL, base, nbase, op->o_tmpmemctx );
+ if ( normalize ) {
+ rc = dnNormalize( 0, NULL, NULL, base, nbase, op->o_tmpmemctx );
+ } else {
+ ber_dupbv_x( nbase, base, op->o_tmpmemctx );
+ rc = LDAP_SUCCESS;
+ }
done:
if( rc != LDAP_SUCCESS ) {
@@ -474,6 +1258,7 @@ done:
return( rc );
}
+#ifndef SLAP_AUTH_REWRITE
static int slap_sasl_rx_off(char *rep, int *off)
{
const char *c;
@@ -507,6 +1292,7 @@ static int slap_sasl_rx_off(char *rep, int *off)
off[n] = -1;
return( LDAP_SUCCESS );
}
+#endif /* ! SLAP_AUTH_REWRITE */
#ifdef SLAP_AUTH_REWRITE
int slap_sasl_rewrite_config(
@@ -585,10 +1371,6 @@ int slap_sasl_regexp_rewrite_config(
int slap_sasl_regexp_config( const char *match, const char *replace )
{
-#ifdef SLAP_AUTH_REWRITE
- return slap_sasl_regexp_rewrite_config( "sasl-regexp", 0,
- match, replace, AUTHID_CONTEXT );
-#else /* ! SLAP_AUTH_REWRITE */
int rc;
SaslRegexp_t *reg;
@@ -600,6 +1382,13 @@ int slap_sasl_regexp_config( const char *match, const char *replace )
reg->sr_match = ch_strdup( match );
reg->sr_replace = ch_strdup( replace );
+#ifdef SLAP_AUTH_REWRITE
+ rc = slap_sasl_regexp_rewrite_config( "sasl-regexp", 0,
+ match, replace, AUTHID_CONTEXT );
+ if ( rc == LDAP_SUCCESS ) nSaslRegexp++;
+ return rc;
+#else /* ! SLAP_AUTH_REWRITE */
+
/* Precompile matching pattern */
rc = regcomp( ®->sr_workspace, reg->sr_match, REG_EXTENDED|REG_ICASE );
if ( rc ) {
@@ -607,6 +1396,12 @@ int slap_sasl_regexp_config( const char *match, const char *replace )
"SASL match pattern %s could not be compiled by regexp engine\n",
reg->sr_match, 0, 0 );
+#ifdef ENABLE_REWRITE
+ /* Dummy block to force symbol references in librewrite */
+ if ( slapMode == ( SLAP_SERVER_MODE|SLAP_TOOL_MODE )) {
+ rewrite_info_init( 0 );
+ }
+#endif
return( LDAP_OTHER );
}
@@ -618,6 +1413,35 @@ int slap_sasl_regexp_config( const char *match, const char *replace )
#endif /* ! SLAP_AUTH_REWRITE */
}
+void slap_sasl_regexp_unparse( BerVarray *out )
+{
+ int i;
+ BerVarray bva = NULL;
+ char ibuf[32], *ptr;
+ struct berval idx;
+
+ if ( !nSaslRegexp ) return;
+
+ idx.bv_val = ibuf;
+ bva = ch_malloc( (nSaslRegexp+1) * sizeof(struct berval) );
+ BER_BVZERO(bva+nSaslRegexp);
+ for ( i=0; ibv_val[insert] = '\0';
}
+#endif /* ! SLAP_AUTH_REWRITE */
/* Take the passed in SASL name and attempt to convert it into an
LDAP URI to find the matching LDAP entry, using the pattern matching
@@ -693,7 +1518,9 @@ static int slap_authz_regexp( struct berval *in, struct berval *out,
if ( !BER_BVISNULL( out ) ) {
char *val = out->bv_val;
ber_str2bv_x( val, 0, 1, out, ctx );
- free( val );
+ if ( val != in->bv_val ) {
+ free( val );
+ }
} else {
ber_dupbv_x( out, in, ctx );
}
@@ -828,8 +1655,8 @@ slap_sasl_matches( Operation *op, BerVarray rules,
* The assertDN should not have the dn: prefix
*/
-static
-int slap_sasl_match( Operation *opx, struct berval *rule,
+static int
+slap_sasl_match( Operation *opx, struct berval *rule,
struct berval *assertDN, struct berval *authc )
{
int rc;
@@ -848,9 +1675,16 @@ int slap_sasl_match( Operation *opx, struct berval *rule,
"===>slap_sasl_match: comparing DN %s to rule %s\n",
assertDN->bv_val, rule->bv_val, 0 );
- rc = slap_parseURI( opx, rule, &base,
- &op.o_req_ndn, &op.ors_scope, &op.ors_filter,
- &op.ors_filterstr );
+ /* NOTE: don't normalize rule if authz syntax is enabled */
+ rc = slap_parseURI( opx, rule, &base, &op.o_req_ndn,
+ &op.ors_scope, &op.ors_filter, &op.ors_filterstr,
+#ifdef SLAP_AUTHZ_SYNTAX
+ 0
+#else /* ! SLAP_AUTHZ_SYNTAX */
+ 1
+#endif /* ! SLAP_AUTHZ_SYNTAX */
+ );
+
if( rc != LDAP_SUCCESS ) goto CONCLUDED;
switch ( op.ors_scope ) {
@@ -992,21 +1826,13 @@ exact_match:
goto CONCLUDED;
}
+ op.o_hdr = opx->o_hdr;
op.o_tag = LDAP_REQ_SEARCH;
- op.o_protocol = LDAP_VERSION3;
op.o_ndn = *authc;
op.o_callback = &cb;
- op.o_time = slap_get_time();
+ slap_op_time( &op.o_time, &op.o_tincr );
op.o_do_not_cache = 1;
op.o_is_auth_check = 1;
- op.o_threadctx = opx->o_threadctx;
- op.o_tmpmemctx = opx->o_tmpmemctx;
- op.o_tmpmfuncs = opx->o_tmpmfuncs;
-#ifdef LDAP_SLAPI
- op.o_pb = opx->o_pb;
-#endif
- op.o_conn = opx->o_conn;
- op.o_connid = opx->o_connid;
/* use req_ndn as req_dn instead of non-pretty base of uri */
if( !BER_BVISNULL( &base ) ) {
ch_free( base.bv_val );
@@ -1014,6 +1840,7 @@ exact_match:
BER_BVZERO( &base );
}
ber_dupbv_x( &op.o_req_dn, &op.o_req_ndn, op.o_tmpmemctx );
+ op.ors_deref = LDAP_DEREF_NEVER;
op.ors_slimit = 1;
op.ors_tlimit = SLAP_NO_LIMIT;
op.ors_attrs = slap_anlist_no_attrs;
@@ -1055,7 +1882,7 @@ slap_sasl_check_authz( Operation *op,
AttributeDescription *ad,
struct berval *authc )
{
- int i, rc;
+ int rc;
BerVarray vals = NULL;
Debug( LDAP_DEBUG_TRACE,
@@ -1086,8 +1913,12 @@ COMPLETE:
* an internal search must be done, and if that search returns exactly one
* entry, return the DN of that one entry.
*/
-void slap_sasl2dn( Operation *opx,
- struct berval *saslname, struct berval *sasldn, int flags )
+void
+slap_sasl2dn(
+ Operation *opx,
+ struct berval *saslname,
+ struct berval *sasldn,
+ int flags )
{
int rc;
slap_callback cb = { NULL, sasl_sc_sasl2dn, NULL, NULL };
@@ -1100,8 +1931,7 @@ void slap_sasl2dn( Operation *opx,
"converting SASL name %s to a DN\n",
saslname->bv_val, 0,0 );
- sasldn->bv_val = NULL;
- sasldn->bv_len = 0;
+ BER_BVZERO( sasldn );
cb.sc_private = sasldn;
/* Convert the SASL name into a minimal URI */
@@ -1109,9 +1939,10 @@ void slap_sasl2dn( Operation *opx,
goto FINISHED;
}
- rc = slap_parseURI( opx, ®out, &base,
- &op.o_req_ndn, &op.ors_scope, &op.ors_filter,
- &op.ors_filterstr );
+ /* NOTE: always normalize regout because it results
+ * from string submatch expansion */
+ rc = slap_parseURI( opx, ®out, &base, &op.o_req_ndn,
+ &op.ors_scope, &op.ors_filter, &op.ors_filterstr, 1 );
if ( !BER_BVISNULL( ®out ) ) slap_sl_free( regout.bv_val, opx->o_tmpmemctx );
if ( rc != LDAP_SUCCESS ) {
goto FINISHED;
@@ -1138,9 +1969,7 @@ void slap_sasl2dn( Operation *opx,
case LDAP_SCOPE_BASE:
case LDAP_SCOPE_ONELEVEL:
case LDAP_SCOPE_SUBTREE:
-#ifdef LDAP_SCOPE_SUBORDINATE
case LDAP_SCOPE_SUBORDINATE:
-#endif
/* do a search */
break;
@@ -1163,21 +1992,13 @@ void slap_sasl2dn( Operation *opx,
goto FINISHED;
}
- op.o_conn = opx->o_conn;
- op.o_connid = opx->o_connid;
+ op.o_hdr = opx->o_hdr;
op.o_tag = LDAP_REQ_SEARCH;
- op.o_protocol = LDAP_VERSION3;
op.o_ndn = opx->o_conn->c_ndn;
op.o_callback = &cb;
- op.o_time = slap_get_time();
+ slap_op_time( &op.o_time, &op.o_tincr );
op.o_do_not_cache = 1;
op.o_is_auth_check = 1;
- op.o_threadctx = opx->o_threadctx;
- op.o_tmpmemctx = opx->o_tmpmemctx;
- op.o_tmpmfuncs = opx->o_tmpmfuncs;
-#ifdef LDAP_SLAPI
- op.o_pb = opx->o_pb;
-#endif
op.ors_deref = LDAP_DEREF_NEVER;
op.ors_slimit = 1;
op.ors_tlimit = SLAP_NO_LIMIT;