From 1bbd51da77ca71260dfe164efbd47b0b830ca296 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Tue, 16 Apr 2002 08:46:25 +0000 Subject: [PATCH] ITS#1712, rewritten dn_openssl2ldap(). Added dnDCEnormalize(), used by dn_openssl2ldap() and sasl_external_x509dn_convert. Fixed realm handling for foreign Kerberos realms embedded in usernames. --- servers/slapd/dn.c | 37 +++++++++ servers/slapd/proto-slap.h | 2 + servers/slapd/sasl.c | 73 ++++++++++++------ servers/slapd/schema_init.c | 147 ++++++++++++++---------------------- 4 files changed, 147 insertions(+), 112 deletions(-) diff --git a/servers/slapd/dn.c b/servers/slapd/dn.c index 450691d326..40064a47fa 100644 --- a/servers/slapd/dn.c +++ b/servers/slapd/dn.c @@ -829,3 +829,40 @@ dnIsSuffix( /* compare */ return( strcmp( dn->bv_val + d, suffix->bv_val ) == 0 ); } + +/* + * Convert a DN from X.500 format into a normalized DN + */ +int +dnDCEnormalize( char *dce, struct berval *out ) +{ + int rc; + LDAPDN *dn = NULL; + + out->bv_val = NULL; + out->bv_len = 0; + + rc = ldap_str2dn( dce, &dn, LDAP_DN_FORMAT_DCE ); + if ( rc != LDAP_SUCCESS ) + return rc; + + /* + * Schema-aware rewrite + */ + if ( LDAPDN_rewrite( dn, 0 ) != LDAP_SUCCESS ) { + ldap_dnfree( dn ); + return LDAP_INVALID_SYNTAX; + } + + /* + * Back to string representation + */ + rc = ldap_dn2bv( dn, out, LDAP_DN_FORMAT_LDAPV3 ); + + ldap_dnfree( dn ); + + if ( rc != LDAP_SUCCESS ) { + rc = LDAP_INVALID_SYNTAX; + } + return rc; +} diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index f3d6a8b0b3..0e0939eac9 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -404,6 +404,8 @@ LDAP_SLAPD_F (void) build_new_dn LDAP_P(( LDAP_SLAPD_F (void) dnParent LDAP_P(( struct berval *dn, struct berval *pdn )); +LDAP_SLAPD_F (int) dnDCEnormalize LDAP_P(( char *dce, struct berval *out )); + /* * entry.c */ diff --git a/servers/slapd/sasl.c b/servers/slapd/sasl.c index 4876c076f8..bc5de313ba 100644 --- a/servers/slapd/sasl.c +++ b/servers/slapd/sasl.c @@ -137,11 +137,11 @@ slap_sasl_log( static struct berval ext_bv = { sizeof("EXTERNAL")-1, "EXTERNAL" }; -int slap_sasl_getdn( Connection *conn, char *id, +int slap_sasl_getdn( Connection *conn, char *id, int len, char *user_realm, struct berval *dn, int flags ) { char *c1; - int rc, len, is_dn = 0; + int rc, is_dn = 0; sasl_conn_t *ctx; struct berval dn2; @@ -166,7 +166,7 @@ int slap_sasl_getdn( Connection *conn, char *id, return( LDAP_SUCCESS ); } ctx = conn->c_sasl_context; - len = strlen( id ); + if ( len == 0 ) len = strlen( id ); /* An authcID needs to be converted to authzID form */ if( flags & FLAG_GETDN_AUTHCID ) { @@ -177,8 +177,7 @@ int slap_sasl_getdn( Connection *conn, char *id, { /* check SASL external for X.509 style DN and */ /* convert to dn: form */ - dn->bv_val = ldap_dcedn2dn( id ); - dn->bv_len = strlen(dn->bv_val); + dnDCEnormalize( id, dn ); is_dn = SET_DN; } else { @@ -309,7 +308,7 @@ slap_sasl_checkpass( /* XXX do we need to check sasldb as well? */ /* XXX can we do both steps at once? */ - rc = slap_sasl_getdn( conn, (char *)username, NULL, &dn, + rc = slap_sasl_getdn( conn, (char *)username, 0, NULL, &dn, FLAG_GETDN_AUTHCID | FLAG_GETDN_FINAL ); if ( rc != LDAP_SUCCESS ) { sasl_seterror( sconn, 0, ldap_err2string( rc ) ); @@ -388,7 +387,7 @@ slap_sasl_canonicalize( in ? in : "" ); #endif - rc = slap_sasl_getdn( conn, (char *)in, (char *)user_realm, &dn, + rc = slap_sasl_getdn( conn, (char *)in, inlen, (char *)user_realm, &dn, (flags == SASL_CU_AUTHID) ? FLAG_GETDN_AUTHCID : FLAG_GETDN_AUTHZID ); if ( rc != LDAP_SUCCESS ) { sasl_seterror( sconn, 0, ldap_err2string( rc ) ); @@ -441,7 +440,7 @@ slap_sasl_authorize( Connection *conn = (Connection *)context; struct berval authcDN, authzDN; char *realm; - int rc, equal = 1; + int rc, equal = 1, ext = 0; #ifdef NEW_LOGGING LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY, @@ -456,11 +455,19 @@ slap_sasl_authorize( if ( requested_user ) equal = !strcmp( auth_identity, requested_user ); - realm = strchr( auth_identity, '@' ); - if ( realm ) - *realm++ = '\0'; + /* If using SASL-EXTERNAL, don't modify the ID in any way */ + if ( conn->c_sasl_bind_mech.bv_len == ext_bv.bv_len + && ( strcasecmp( ext_bv.bv_val, conn->c_sasl_bind_mech.bv_val ) == 0 ) + && auth_identity[0] == '/' ) { + ext = 1; + realm = NULL; + } else { + /* Else look for an embedded realm in the name */ + realm = strchr( auth_identity, '@' ); + if ( realm ) *realm++ = '\0'; + } - rc = slap_sasl_getdn( conn, auth_identity, realm ? realm : (char *)def_realm, + rc = slap_sasl_getdn( conn, auth_identity, alen, realm ? realm : (char *)def_realm, &authcDN, FLAG_GETDN_AUTHCID ); if ( realm ) realm[-1] = '@'; @@ -480,11 +487,14 @@ slap_sasl_authorize( return SASL_OK; } - realm = strchr( requested_user, '@' ); - if ( realm ) - *realm++ = '\0'; + if ( ext ) { + realm = NULL; + } else { + realm = strchr( requested_user, '@' ); + if ( realm ) *realm++ = '\0'; + } - rc = slap_sasl_getdn( conn, requested_user, realm ? realm : (char *)def_realm, + rc = slap_sasl_getdn( conn, requested_user, rlen, realm ? realm : (char *)def_realm, &authzDN, FLAG_GETDN_AUTHZID ); if ( realm ) realm[-1] = '@'; @@ -537,15 +547,15 @@ slap_sasl_authorize( static int slap_sasl_authorize( void *context, - const char *authcid, - const char *authzid, + char *authcid, + char *authzid, const char **user, const char **errstr) { struct berval authcDN, authzDN; - int rc; + int rc, ext = 0; Connection *conn = context; - char *realm; + char *realm, *xrealm; *user = NULL; @@ -579,7 +589,17 @@ slap_sasl_authorize( /* Convert the identities to DN's. If no authzid was given, client will be bound as the DN matching their username */ - rc = slap_sasl_getdn( conn, (char *)authcid, realm, &authcDN, FLAG_GETDN_AUTHCID ); + if ( conn->c_sasl_bind_mech.bv_len == ext_bv.bv_len + && ( strcasecmp( ext_bv.bv_val, conn->c_sasl_bind_mech.bv_val ) == 0 ) + && authcid[0] == '/' ) { + ext = 1; + xrealm = NULL; + } else { + xrealm = strchr( authcid, '@' ); + if ( xrealm ) *xrealm++ = '\0'; + } + rc = slap_sasl_getdn( conn, (char *)authcid, 0, xrealm ? xrealm : realm, &authcDN, FLAG_GETDN_AUTHCID ); + if ( xrealm ) xrealm[-1] = '@'; if( rc != LDAP_SUCCESS ) { *errstr = ldap_err2string( rc ); return SASL_NOAUTHZ; @@ -598,7 +618,14 @@ slap_sasl_authorize( *errstr = NULL; return SASL_OK; } - rc = slap_sasl_getdn( conn, (char *)authzid, realm, &authzDN, FLAG_GETDN_AUTHZID ); + if ( ext ) { + xrealm = NULL; + } else { + xrealm = strchr( authzid, '@' ); + if ( xrealm ) *xrealm++ = '\0'; + } + rc = slap_sasl_getdn( conn, (char *)authzid, 0, xrealm ? xrealm : realm, &authzDN, FLAG_GETDN_AUTHZID ); + if ( xrealm ) xrealm[-1] = '@'; if( rc != LDAP_SUCCESS ) { ch_free( authcDN.bv_val ); *errstr = ldap_err2string( rc ); @@ -1088,7 +1115,7 @@ int slap_sasl_bind( NULL, "no SASL username", NULL, NULL ); } else { - rc = slap_sasl_getdn( conn, username, realm, edn, FLAG_GETDN_FINAL ); + rc = slap_sasl_getdn( conn, username, 0, realm, edn, FLAG_GETDN_FINAL ); if( rc == LDAP_SUCCESS ) { sasl_ssf_t *ssf = NULL; diff --git a/servers/slapd/schema_init.c b/servers/slapd/schema_init.c index fb82f181b3..85e9f2526f 100644 --- a/servers/slapd/schema_init.c +++ b/servers/slapd/schema_init.c @@ -3421,7 +3421,7 @@ char digit[] = "0123456789"; */ static struct berval * -asn1_integer2str(ASN1_INTEGER *a) +asn1_integer2str(ASN1_INTEGER *a, struct berval *bv) { char buf[256]; char *p; @@ -3477,35 +3477,17 @@ asn1_integer2str(ASN1_INTEGER *a) *--p = '-'; } - return ber_bvstrdup(p); + return ber_str2bv( p, 0, 1, bv ); } /* Get a DN in RFC2253 format from a X509_NAME internal struct */ -static struct berval * -dn_openssl2ldap(X509_NAME *name) +int +dn_openssl2ldap(X509_NAME *name, struct berval *out) { - char issuer_dn[1024]; - BIO *bio; - - bio = BIO_new(BIO_s_mem()); - if ( !bio ) { -#ifdef NEW_LOGGING - LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY, - "dn_openssl2ldap: error creating BIO_s_mem: %s\n", - ERR_error_string(ERR_get_error(),NULL))); -#else - Debug( LDAP_DEBUG_ARGS, "dn_openssl2ldap: " - "error creating BIO: %s\n", - ERR_error_string(ERR_get_error(),NULL), NULL, NULL ); -#endif - return NULL; - } - X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253); - - BIO_gets(bio, issuer_dn, 1024); + char buf[2048], *p; - BIO_free(bio); - return ber_bvstrdup(issuer_dn); + p = X509_NAME_oneline( name, buf, sizeof( buf ) ); + return dnDCEnormalize( p, out ); } /* @@ -3519,9 +3501,8 @@ certificateExactConvert( { X509 *xcert; unsigned char *p = in->bv_val; - struct berval *serial; - struct berval *issuer_dn; - struct berval *bv_tmp; + struct berval serial; + struct berval issuer_dn; xcert = d2i_X509(NULL, &p, in->bv_len); if ( !xcert ) { @@ -3537,39 +3518,27 @@ certificateExactConvert( return LDAP_INVALID_SYNTAX; } - serial = asn1_integer2str(xcert->cert_info->serialNumber); - if ( !serial ) { + if ( !asn1_integer2str(xcert->cert_info->serialNumber, &serial) ) { X509_free(xcert); return LDAP_INVALID_SYNTAX; } - issuer_dn = dn_openssl2ldap(X509_get_issuer_name(xcert)); - if ( !issuer_dn ) { + if ( dn_openssl2ldap(X509_get_issuer_name(xcert), &issuer_dn ) != LDAP_SUCCESS ) { X509_free(xcert); - ber_bvfree(serial); + ber_memfree(serial.bv_val); return LDAP_INVALID_SYNTAX; } - /* Actually, dn_openssl2ldap returns in a normalized format, but - it is different from our normalized format */ - bv_tmp = issuer_dn; - if ( dnNormalize(NULL, bv_tmp, &issuer_dn) != LDAP_SUCCESS ) { - X509_free(xcert); - ber_bvfree(serial); - ber_bvfree(bv_tmp); - return LDAP_INVALID_SYNTAX; - } - ber_bvfree(bv_tmp); X509_free(xcert); - out->bv_len = serial->bv_len + issuer_dn->bv_len + sizeof(" $ "); + out->bv_len = serial.bv_len + issuer_dn.bv_len + sizeof(" $ "); out->bv_val = ch_malloc(out->bv_len); p = out->bv_val; - AC_MEMCPY(p, serial->bv_val, serial->bv_len); - p += serial->bv_len; + AC_MEMCPY(p, serial.bv_val, serial.bv_len); + p += serial.bv_len; AC_MEMCPY(p, " $ ", sizeof(" $ ")-1); p += 3; - AC_MEMCPY(p, issuer_dn->bv_val, issuer_dn->bv_len); - p += issuer_dn->bv_len; + AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len); + p += issuer_dn.bv_len; *p++ = '\0'; #ifdef NEW_LOGGING @@ -3582,8 +3551,8 @@ certificateExactConvert( out->bv_val, NULL, NULL ); #endif - ber_bvfree(serial); - ber_bvfree(issuer_dn); + ber_memfree(serial.bv_val); + ber_memfree(issuer_dn.bv_val); return LDAP_SUCCESS; } @@ -3591,8 +3560,8 @@ certificateExactConvert( static int serial_and_issuer_parse( struct berval *assertion, - struct berval **serial, - struct berval **issuer_dn + struct berval *serial, + struct berval *issuer_dn ) { char *begin; @@ -3617,18 +3586,20 @@ serial_and_issuer_parse( bv.bv_len = end-begin+1; bv.bv_val = begin; - *serial = ber_dupbv(NULL, &bv); + ber_dupbv(serial, &bv); /* now extract the issuer, remember p was at the dollar sign */ - begin = p+1; - end = assertion->bv_val+assertion->bv_len-1; - while (ASCII_SPACE(*begin)) - begin++; - /* should we trim spaces at the end too? is it safe always? */ + if ( issuer_dn ) { + begin = p+1; + end = assertion->bv_val+assertion->bv_len-1; + while (ASCII_SPACE(*begin)) + begin++; + /* should we trim spaces at the end too? is it safe always? */ - bv.bv_len = end-begin+1; - bv.bv_val = begin; - dnNormalize( NULL, &bv, issuer_dn ); + bv.bv_len = end-begin+1; + bv.bv_val = begin; + dnNormalize2( NULL, &bv, issuer_dn ); + } return LDAP_SUCCESS; } @@ -3644,10 +3615,10 @@ certificateExactMatch( { X509 *xcert; unsigned char *p = value->bv_val; - struct berval *serial; - struct berval *issuer_dn; - struct berval *asserted_serial; - struct berval *asserted_issuer_dn; + struct berval serial; + struct berval issuer_dn; + struct berval asserted_serial; + struct berval asserted_issuer_dn; int ret; xcert = d2i_X509(NULL, &p, value->bv_len); @@ -3664,8 +3635,8 @@ certificateExactMatch( return LDAP_INVALID_SYNTAX; } - serial = asn1_integer2str(xcert->cert_info->serialNumber); - issuer_dn = dn_openssl2ldap(X509_get_issuer_name(xcert)); + asn1_integer2str(xcert->cert_info->serialNumber, &serial); + dn_openssl2ldap(X509_get_issuer_name(xcert), &issuer_dn); X509_free(xcert); @@ -3678,8 +3649,8 @@ certificateExactMatch( flags, slap_schema.si_syn_integer, slap_schema.si_mr_integerMatch, - serial, - asserted_serial); + &serial, + &asserted_serial); if ( ret == LDAP_SUCCESS ) { if ( *matchp == 0 ) { /* We need to normalize everything for dnMatch */ @@ -3688,29 +3659,29 @@ certificateExactMatch( flags, slap_schema.si_syn_distinguishedName, slap_schema.si_mr_distinguishedNameMatch, - issuer_dn, - asserted_issuer_dn); + &issuer_dn, + &asserted_issuer_dn); } } #ifdef NEW_LOGGING LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY, "certificateExactMatch: %d\n %s $ %s\n %s $ %s\n", - *matchp, serial->bv_val, issuer_dn->bv_val, - asserted_serial->bv_val, asserted_issuer_dn->bv_val)); + *matchp, serial.bv_val, issuer_dn.bv_val, + asserted_serial.bv_val, asserted_issuer_dn.bv_val)); #else Debug( LDAP_DEBUG_ARGS, "certificateExactMatch " "%d\n\t\"%s $ %s\"\n", - *matchp, serial->bv_val, issuer_dn->bv_val ); + *matchp, serial.bv_val, issuer_dn.bv_val ); Debug( LDAP_DEBUG_ARGS, "\t\"%s $ %s\"\n", - asserted_serial->bv_val, asserted_issuer_dn->bv_val, + asserted_serial.bv_val, asserted_issuer_dn.bv_val, NULL ); #endif - ber_bvfree(serial); - ber_bvfree(issuer_dn); - ber_bvfree(asserted_serial); - ber_bvfree(asserted_issuer_dn); + ber_memfree(serial.bv_val); + ber_memfree(issuer_dn.bv_val); + ber_memfree(asserted_serial.bv_val); + ber_memfree(asserted_issuer_dn.bv_val); return ret; } @@ -3733,7 +3704,7 @@ static int certificateExactIndexer( BerVarray keys; X509 *xcert; unsigned char *p; - struct berval * serial; + struct berval serial; /* we should have at least one value at this point */ assert( values != NULL && values[0].bv_val != NULL ); @@ -3762,12 +3733,12 @@ static int certificateExactIndexer( return LDAP_INVALID_SYNTAX; } - serial = asn1_integer2str(xcert->cert_info->serialNumber); + asn1_integer2str(xcert->cert_info->serialNumber, &serial); X509_free(xcert); integerNormalize( slap_schema.si_syn_integer, - serial, + &serial, &keys[i] ); - ber_bvfree(serial); + ber_memfree(serial.bv_val); #ifdef NEW_LOGGING LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY, "certificateExactIndexer: returning: %s\n", @@ -3797,20 +3768,18 @@ static int certificateExactFilter( BerVarray *keysp ) { BerVarray keys; - struct berval *asserted_serial; - struct berval *asserted_issuer_dn; + struct berval asserted_serial; serial_and_issuer_parse(assertValue, &asserted_serial, - &asserted_issuer_dn); + NULL); keys = ch_malloc( sizeof( struct berval ) * 2 ); - integerNormalize( syntax, asserted_serial, &keys[0] ); + integerNormalize( syntax, &asserted_serial, &keys[0] ); keys[1].bv_val = NULL; *keysp = keys; - ber_bvfree(asserted_serial); - ber_bvfree(asserted_issuer_dn); + ber_memfree(asserted_serial.bv_val); return LDAP_SUCCESS; } #endif -- 2.39.5