diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index 8177fa38ea..1433e1fef0 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -699,8 +699,8 @@ static int parseProxyAuthz ( SlapReply *rs, LDAPControl *ctrl ) { - int rc; - struct berval dn = { 0, NULL }; + int rc; + struct berval dn = { 0, NULL }; if ( op->o_proxy_authz != SLAP_NO_CONTROL ) { rs->sr_text = "proxy authorization control specified multiple times"; @@ -748,16 +748,38 @@ static int parseProxyAuthz ( return LDAP_SUCCESS; } - rc = slap_sasl_getdn( op->o_conn, op, - ctrl->ldctl_value.bv_val, ctrl->ldctl_value.bv_len, - NULL, &dn, SLAP_GETDN_AUTHZID ); + /* FIXME: how can we get the realm? */ + { + int rc; + char buf[ SLAP_LDAPDN_MAXLEN ]; + struct berval id = { ctrl->ldctl_value.bv_len, (char *)buf }, + user = { 0, NULL }, + realm = { 0, NULL }, + mech = { 0, NULL }; - if( rc != LDAP_SUCCESS || !dn.bv_len ) { - if ( dn.bv_val ) { - ch_free( dn.bv_val ); + strncpy( buf, ctrl->ldctl_value.bv_val, sizeof( buf ) ); + + rc = slap_parse_user( &id, &user, &realm, &mech ); + if ( rc == LDAP_SUCCESS ) { + if ( mech.bv_len ) { + rs->sr_text = "mech not allowed in authzId"; + return LDAP_PROXY_AUTHZ_FAILURE; + } + } else { + user = ctrl->ldctl_value; + } + + rc = slap_sasl_getdn( op->o_conn, op, + user.bv_val, user.bv_len, + realm.bv_val, &dn, SLAP_GETDN_AUTHZID ); + + if( rc != LDAP_SUCCESS || !dn.bv_len ) { + if ( dn.bv_val ) { + ch_free( dn.bv_val ); + } + rs->sr_text = "authzId mapping failed"; + return LDAP_PROXY_AUTHZ_FAILURE; } - rs->sr_text = "authzId mapping failed"; - return LDAP_PROXY_AUTHZ_FAILURE; } #ifdef NEW_LOGGING diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 67e5d4986d..86078658ae 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -983,6 +983,9 @@ LDAP_SLAPD_F (int) slap_sasl_getdn( Connection *conn, Operation *op, /* * saslauthz.c */ +LDAP_SLAPD_F (int) slap_parse_user LDAP_P(( + struct berval *id, struct berval *user, + struct berval *realm, struct berval *mech )); LDAP_SLAPD_F (void) slap_sasl2dn LDAP_P(( Operation *op, struct berval *saslname, diff --git a/servers/slapd/sasl.c b/servers/slapd/sasl.c index 3575c80044..4613cee59f 100644 --- a/servers/slapd/sasl.c +++ b/servers/slapd/sasl.c @@ -1714,7 +1714,6 @@ static struct berval ext_bv = BER_BVC( "EXTERNAL" ); int slap_sasl_getdn( Connection *conn, Operation *op, char *id, int len, char *user_realm, struct berval *dn, int flags ) { - char *c1; int rc, is_dn = SET_NONE, do_norm = 1; struct berval dn2, *mech; @@ -1796,22 +1795,38 @@ int slap_sasl_getdn( Connection *conn, Operation *op, char *id, int len, /* Username strings */ if( is_dn == SET_U ) { - char *p, *realm; + char *p; + struct berval realm = { 0, NULL }, c1 = *dn; + len = dn->bv_len + sizeof("uid=")-1 + sizeof(",cn=auth")-1; +#if 0 /* username may have embedded realm name */ /* FIXME: - * 1) userids can legally have embedded '@' chars - * 2) we're mucking with memory we do not possess - * 3) this should not be required, since we're - * mostly doing strncpy's so we know how much - * memory to copy ... + * userids can legally have embedded '@' chars; + * the relm should be set by those mechanisms + * that support it by means of the user_realm + * variable */ - if( ( realm = strrchr( dn->bv_val, '@') ) ) { - *realm++ = '\0'; - len += sizeof(",cn=")-2; - } else if( user_realm && *user_realm ) { - len += strlen( user_realm ) + sizeof(",cn=")-1; + if( ( realm.bv_val = strrchr( dn->bv_val, '@') ) ) { + char *r = realm.bv_val; + + realm.bv_val++; + realm.bv_len = dn->bv_len - ( realm.bv_val - dn->bv_val ); + len += sizeof( ",cn=" ) - 2; + c1.bv_len -= realm.bv_len + 1; + + if ( strchr( dn->bv_val, '@') == r ) { + /* FIXME: ambiguity, is it the realm + * or something else? */ + } + + } else +#endif + if( user_realm && *user_realm ) { + realm.bv_val = user_realm; + realm.bv_len = strlen( user_realm ); + len += realm.bv_len + sizeof(",cn=") - 1; } if( mech->bv_len ) { @@ -1819,7 +1834,6 @@ int slap_sasl_getdn( Connection *conn, Operation *op, char *id, int len, } /* Build the new dn */ - c1 = dn->bv_val; dn->bv_val = sl_malloc( len+1, op->o_tmpmemctx ); if( dn->bv_val == NULL ) { #ifdef NEW_LOGGING @@ -1832,16 +1846,11 @@ int slap_sasl_getdn( Connection *conn, Operation *op, char *id, int len, return LDAP_OTHER; } p = lutil_strcopy( dn->bv_val, "uid=" ); - p = lutil_strncopy( p, c1, dn->bv_len ); + p = lutil_strncopy( p, c1.bv_val, c1.bv_len ); - if( realm ) { - int rlen = dn->bv_len - ( realm - c1 ); + if( realm.bv_len ) { p = lutil_strcopy( p, ",cn=" ); - p = lutil_strncopy( p, realm, rlen ); - realm[-1] = '@'; - } else if( user_realm && *user_realm ) { - p = lutil_strcopy( p, ",cn=" ); - p = lutil_strcopy( p, user_realm ); + p = lutil_strncopy( p, realm.bv_val, realm.bv_len ); } if( mech->bv_len ) { diff --git a/servers/slapd/saslauthz.c b/servers/slapd/saslauthz.c index 1c0ca2efab..76e79c458b 100644 --- a/servers/slapd/saslauthz.c +++ b/servers/slapd/saslauthz.c @@ -89,6 +89,75 @@ int slap_sasl_setpolicy( const char *arg ) return rc; } +int slap_parse_user( struct berval *id, struct berval *user, + struct berval *realm, struct berval *mech ) +{ + char u; + + assert( id ); + assert( id->bv_val ); + assert( user ); + assert( realm ); + assert( mech ); + + u = id->bv_val[ 0 ]; + + assert( u == 'u' || u == 'U' ); + + user->bv_val = strrchr( id->bv_val, ':' ); + if ( user->bv_val == NULL ) { + return LDAP_PROTOCOL_ERROR; + } + user->bv_val[ 0 ] = '\0'; + user->bv_val++; + user->bv_len = id->bv_len - ( user->bv_val - id->bv_val ); + + realm->bv_val = strchr( id->bv_val, '/' ); + if ( realm->bv_val != NULL ) { + realm->bv_val[ 0 ] = '\0'; + realm->bv_val++; + realm->bv_len = user->bv_val - realm->bv_val - 1; + } + + mech->bv_val = strchr( id->bv_val, '.' ); + if ( mech->bv_val != NULL ) { + mech->bv_val[ 0 ] = '\0'; + mech->bv_val++; + if ( realm->bv_val ) { + mech->bv_len = realm->bv_val - mech->bv_val - 1; + } else { + mech->bv_len = user->bv_val - mech->bv_val - 1; + } + } + + if ( id->bv_val[ 1 ] != '\0' ) { + return LDAP_PROTOCOL_ERROR; + } + + if ( mech->bv_val != NULL ) { + assert( mech->bv_val == id->bv_val + 2 ); + + memmove( mech->bv_val - 2, mech->bv_val, mech->bv_len + 1 ); + mech->bv_val -= 2; + } + + if ( realm->bv_val ) { + assert( realm->bv_val >= id->bv_val + 2 ); + + memmove( realm->bv_val - 2, realm->bv_val, realm->bv_len + 1 ); + realm->bv_val -= 2; + } + + if ( user->bv_val > id->bv_val + 2 ) { + user->bv_val -= 2; + user->bv_len += 2; + user->bv_val[ 0 ] = u; + user->bv_val[ 1 ] = ':'; + } + + 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 ) @@ -115,8 +184,8 @@ static int slap_parseURI( Operation *op, struct berval *uri, "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 ); #endif + rc = LDAP_PROTOCOL_ERROR; if ( !strncasecmp( uri->bv_val, "dn", sizeof( "dn" ) - 1 ) ) { - rc = LDAP_PROTOCOL_ERROR; bv.bv_val = uri->bv_val + sizeof( "dn" ) - 1; if ( bv.bv_val[ 0 ] == '.' ) { @@ -173,11 +242,46 @@ is_dn: bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val); break; } - return( rc ); + return rc; - } else if ( !strncasecmp( uri->bv_val, "u:", sizeof( "u:" ) - 1 ) ) { - /* FIXME: I'll handle this later ... */ - return LDAP_PROTOCOL_ERROR; + } else if ( ( uri->bv_val[ 0 ] == 'u' || uri->bv_val[ 0 ] == 'U' ) + && ( uri->bv_val[ 1 ] == ':' + || uri->bv_val[ 1 ] == '/' + || uri->bv_val[ 1 ] == '.' ) ) + { + Connection c = *op->o_conn; + char buf[ SLAP_LDAPDN_MAXLEN ]; + struct berval id = { uri->bv_len, (char *)buf }, + user = { 0, NULL }, + realm = { 0, NULL }, + mech = { 0, NULL }; + + if ( sizeof( buf ) <= uri->bv_len ) { + return LDAP_INVALID_SYNTAX; + } + + strncpy( buf, uri->bv_val, sizeof( buf ) ); + + rc = slap_parse_user( &id, &user, &realm, &mech ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + if ( mech.bv_val ) { + c.c_sasl_bind_mech = mech; + } else { + c.c_sasl_bind_mech.bv_val = "AUTHZ"; + c.c_sasl_bind_mech.bv_len = sizeof( "AUTHZ" ) - 1; + } + + rc = slap_sasl_getdn( &c, op, user.bv_val, user.bv_len, + realm.bv_val, nbase, SLAP_GETDN_AUTHZID ); + + if ( rc == LDAP_SUCCESS ) { + *scope = LDAP_X_SCOPE_EXACT; + } + + return rc; } rc = ldap_url_parse( uri->bv_val, &ludp ); @@ -433,10 +537,10 @@ static int sasl_sc_sasl2dn( Operation *o, SlapReply *rs ) #ifdef NEW_LOGGING LDAP_LOG( TRANSPORT, DETAIL1, - "slap_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 ); + "slap_sc_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 ); #else Debug( LDAP_DEBUG_TRACE, - "slap_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 ); + "slap_sc_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 ); #endif return -1; } diff --git a/servers/slapd/tools/mimic.c b/servers/slapd/tools/mimic.c index 387eef2988..2c9cd1c364 100644 --- a/servers/slapd/tools/mimic.c +++ b/servers/slapd/tools/mimic.c @@ -289,21 +289,26 @@ int slap_entry2mods( Entry *e, Modifications **mods, const char **text, volatile sig_atomic_t slapd_abrupt_shutdown; int slap_mods_check( Modifications *ml, int update, const char **text, - char *textbuf, size_t textlen, void *ctx ) + char *textbuf, size_t textlen, void *ctx ) { return -1; } int slap_mods2entry( Modifications *mods, Entry **e, int repl_user, - int dup, const char **text, char *textbuf, size_t textlen ) + int dup, const char **text, char *textbuf, size_t textlen ) { return -1; } int slap_mods_opattrs( Operation *op, Modifications *mods, - Modifications **modtail, const char **text, - char *textbuf, size_t textlen ) + Modifications **modtail, const char **text, + char *textbuf, size_t textlen ) { return -1; } +int slap_parse_user( struct berval *id, struct berval *user, + struct berval *realm, struct berval *mech ) +{ + return -1; +}