From 5c63fd55b5886e0b0ed7b3e28871d73aed260c4e Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga Date: Wed, 25 Aug 1999 06:44:08 +0000 Subject: [PATCH] Implement ldap_dn_normalize and friends. Should be used by clients to validate input dn's BEFORE sending dn's to server. Also fixed getfilter to use REG_EXTENDED|REG_NOSUB. (and fixed one case where REG_BASIC was still used). s/strdup/LDAP_STRDUP/ Added ldap_pvt_str2lower/upper --- clients/ud/auth.c | 15 +- include/ldap_pvt.h | 28 +++ libraries/libldap/dn.c | 333 ++++++++++++++++++++++++++++++++++ libraries/libldap/getdn.c | 13 +- libraries/libldap/getfilter.c | 6 +- libraries/libldap/libldap.dsp | 4 + libraries/libldap/string.c | 27 +++ libraries/libldap/tls.c | 18 +- servers/slapd/attr.c | 3 +- servers/slapd/config.c | 3 +- servers/slapd/daemon.c | 3 +- servers/slapd/dn.c | 33 +--- servers/slapd/main.c | 18 +- servers/slapd/proto-slap.h | 2 - 14 files changed, 436 insertions(+), 70 deletions(-) create mode 100644 libraries/libldap/dn.c diff --git a/clients/ud/auth.c b/clients/ud/auth.c index 89580347bb..378c1b78ac 100644 --- a/clients/ud/auth.c +++ b/clients/ud/auth.c @@ -294,17 +294,6 @@ auth( char *who, int implicit ) #define FIVEMINS ( 5 * 60 ) #define TGT "krbtgt" -static void -str2upper( char *s ) -{ - char *p; - - for ( p = s; *p != '\0'; ++p ) { - *p = TOUPPER( (unsigned char) *p ); - } -} - - static int valid_tgt( char **names ) { @@ -324,7 +313,7 @@ valid_tgt( char **names ) /* * realm must be uppercase for krb_ routines */ - str2upper( realm ); + ldap_pvt_str2upper( realm ); #endif /* HAVE_AFS_KERBEROS */ /* @@ -395,7 +384,7 @@ kinit( char *kname ) /* * realm must be uppercase for krb_ routines */ - str2upper( realm ); + ldap_pvt_str2upper( realm ); #endif /* HAVE_AFS_KERBEROS */ rc = krb_get_in_tkt( name, inst, realm, TGT, realm, diff --git a/include/ldap_pvt.h b/include/ldap_pvt.h index 3014e217ee..b7340b041b 100644 --- a/include/ldap_pvt.h +++ b/include/ldap_pvt.h @@ -77,6 +77,34 @@ ldap_str2charray LDAP_P(( void ldap_pvt_hex_unescape LDAP_P(( char *s )); int ldap_pvt_unhex( int c ); +/* these macros assume 'x' is an ASCII x */ +#define LDAP_DNSEPARATOR(c) ((c) == ',' || (c) == ';') +#define LDAP_SEPARATOR(c) ((c) == ',' || (c) == ';' || (c) == '+') +#define LDAP_SPACE(c) ((c) == ' ' || (c) == '\n') + +#define LDAP_LOWER(c) ( (c) >= 'a' && (c) <= 'z' ) +#define LDAP_UPPER(c) ( (c) >= 'A' && (c) <= 'Z' ) +#define LDAP_ALPHA(c) ( LDAP_LOWER(c) || LDAP_UPPER(c) ) +#define LDAP_DIGIT(c) ( (c) >= '0' && (c) <= '9' ) +#define LDAP_ALNUM(c) ( LDAP_ALPHA(c) || LDAP_DIGIT(c) ) + +#define LDAP_LEADKEYCHAR(c) ( LDAP_ALPHA(c) ) +#define LDAP_KEYCHAR(c) ( LDAP_ALNUM(c) || (c) == '-' ) +#define LDAP_LEADOIDCHAR(c) ( LDAP_DIGIT(c) ) +#define LDAP_OIDCHAR(c) ( LDAP_DIGIT(c) || (c) == '.' ) + +#define LDAP_LEADATTRCHAR(c) ( LDAP_LEADKEYCHAR(c) || LDAP_LEADOIDCHAR(c) ) +#define LDAP_ATTRCHAR(c) ( LDAP_KEYCHAR((c)) || (c) == '.' ) + +#define LDAP_NEEDSESCAPE(c) ((c) == '\\' || (c) == '"') + +/* string.c */ +LDAP_F( char * ) +ldap_pvt_str2upper LDAP_P(( char *str )); + +LDAP_F( char * ) +ldap_pvt_str2lower LDAP_P(( char *str )); + LDAP_END_DECL #endif diff --git a/libraries/libldap/dn.c b/libraries/libldap/dn.c new file mode 100644 index 0000000000..7e77493806 --- /dev/null +++ b/libraries/libldap/dn.c @@ -0,0 +1,333 @@ +/* dn.c - routines for dealing with distinguished names */ +/* + * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include + +#include +#include +#include +#include + +#include "ldap-int.h" + +#define B4LEADTYPE 0 +#define B4TYPE 1 +#define INOIDTYPE 2 +#define INKEYTYPE 3 +#define B4EQUAL 4 +#define B4VALUE 5 +#define INVALUE 6 +#define INQUOTEDVALUE 7 +#define B4SEPARATOR 8 + +/* + * ldap_dn_normalize - put dn into a canonical format + * and return it. + */ + +char * +ldap_dn_normalize( const char *dn ) +{ + char *d, *s; + int state, gotesc; + char *ndn; + + if( dn == NULL ) { + return NULL; + } + + ndn = LDAP_STRDUP( dn ); + + if( ndn == NULL ) { + return NULL; + } + + gotesc = 0; + state = B4LEADTYPE; + for ( d = s = ndn; *s; s++ ) { + switch ( state ) { + case B4LEADTYPE: + case B4TYPE: + if ( LDAP_LEADOIDCHAR(*s) ) { + state = INOIDTYPE; + *d++ = *s; + } else if ( LDAP_LEADKEYCHAR(*s) ) { + state = INKEYTYPE; + *d++ = *s; + } else if ( ! LDAP_SPACE( *s ) ) { + dn = NULL; + state = INKEYTYPE; + *d++ = *s; + } + break; + + case INOIDTYPE: + if ( LDAP_OIDCHAR(*s) ) { + *d++ = *s; + } else if ( *s == '=' ) { + state = B4VALUE; + *d++ = *s; + } else if ( LDAP_SPACE( *s ) ) { + state = B4EQUAL; + } else { + dn = NULL; + *d++ = *s; + } + break; + + case INKEYTYPE: + if ( LDAP_KEYCHAR(*s) ) { + *d++ = *s; + } else if ( *s == '=' ) { + state = B4VALUE; + *d++ = *s; + } else if ( LDAP_SPACE( *s ) ) { + state = B4EQUAL; + } else { + dn = NULL; + *d++ = *s; + } + break; + + case B4EQUAL: + if ( *s == '=' ) { + state = B4VALUE; + *d++ = *s; + } else if ( ! LDAP_SPACE( *s ) ) { + /* not a valid dn - but what can we do here? */ + *d++ = *s; + dn = NULL; + } + break; + + case B4VALUE: + if ( *s == '"' ) { + state = INQUOTEDVALUE; + *d++ = *s; + } else if ( ! LDAP_SPACE( *s ) ) { + state = INVALUE; + *d++ = *s; + } + break; + + case INVALUE: + if ( !gotesc && LDAP_SEPARATOR( *s ) ) { + while ( LDAP_SPACE( *(d - 1) ) ) + d--; + state = B4TYPE; + if ( *s == '+' ) { + *d++ = *s; + } else { + *d++ = ','; + } + } else if ( gotesc && !LDAP_NEEDSESCAPE( *s ) && + !LDAP_SEPARATOR( *s ) ) { + *--d = *s; + d++; + } else { + *d++ = *s; + } + break; + + case INQUOTEDVALUE: + if ( !gotesc && *s == '"' ) { + state = B4SEPARATOR; + *d++ = *s; + } else if ( gotesc && !LDAP_NEEDSESCAPE( *s ) ) { + *--d = *s; + d++; + } else { + *d++ = *s; + } + break; + case B4SEPARATOR: + if ( LDAP_SEPARATOR( *s ) ) { + state = B4TYPE; + *d++ = *s; + } + break; + default: + dn = NULL; + Debug( LDAP_DEBUG_ANY, + "dn_normalize - unknown state %d\n", state, 0, 0 ); + break; + } + if ( *s == '\\' ) { + gotesc = 1; + } else { + gotesc = 0; + } + } + *d = '\0'; + + if( gotesc ) { + /* shouldn't be left in escape */ + dn = NULL; + } + + /* check end state */ + switch( state ) { + case B4LEADTYPE: /* looking for first type */ + case B4SEPARATOR: /* looking for separator */ + case INVALUE: /* inside value */ + break; + default: + dn = NULL; + } + + if( dn == NULL ) { + return( ndn ); + ndn = NULL; + } + + return( ndn ); +} + +/* + * ldap_dn_parent - return a copy of the dn of dn's parent + */ + +char * +ldap_dn_parent( + const char *dn +) +{ + const char *s; + int inquote; + + if( dn == NULL ) { + return NULL; + } + + while(*dn && LDAP_SPACE(*dn)) { + dn++; + } + + if( *dn == '\0' ) { + return( NULL ); + } + + /* + * no =, assume it is a dns name, like blah@some.domain.name + * if the blah@ part is there, return some.domain.name. if + * it's just some.domain.name, return domain.name. + */ + if ( strchr( dn, '=' ) == NULL ) { + if ( (s = strchr( dn, '@' )) == NULL ) { + if ( (s = strchr( dn, '.' )) == NULL ) { + return( NULL ); + } + } + if ( *(s + 1) == '\0' ) { + return( NULL ); + } else { + return( LDAP_STRDUP( &s[1] ) ); + } + } + + /* + * else assume it is an X.500-style name, which looks like + * foo=bar,sha=baz,... + */ + + inquote = 0; + for ( s = dn; *s; s++ ) { + if ( *s == '\\' ) { + if ( *(s + 1) ) { + s++; + } + continue; + } + if ( inquote ) { + if ( *s == '"' ) { + inquote = 0; + } + } else { + if ( *s == '"' ) { + inquote = 1; + } else if ( LDAP_DNSEPARATOR( *s ) ) { + return( LDAP_STRDUP( &s[1] ) ); + } + } + } + + return( LDAP_STRDUP( "" ) ); +} + +char * ldap_dn_rdn( + const char *dn ) +{ + char *s; + char *rdn; + int inquote; + + if( dn == NULL ) { + return NULL; + } + + while(*dn && LDAP_SPACE(*dn)) { + dn++; + } + + if( *dn == '\0' ) { + return( NULL ); + } + + rdn = LDAP_STRDUP( dn ); + + if( rdn == NULL ) { + return NULL; + } + +#ifdef DNS_DN + /* + * no =, assume it is a dns name, like blah@some.domain.name + * if the blah@ part is there, return some.domain.name. if + * it's just some.domain.name, return domain.name. + */ + if ( strchr( rdn, '=' ) == NULL ) { + if ( (s = strchr( rdn, '@' )) == NULL ) { + if ( (s = strchr( rdn, '.' )) == NULL ) { + return( rdn ); + } + } + *s = '\0'; + return( rdn ); + } +#endif + + /* + * else assume it is an X.500-style name, which looks like + * foo=bar,sha=baz,... + */ + + inquote = 0; + + for ( s = rdn; *s; s++ ) { + if ( *s == '\\' ) { + if ( *(s + 1) ) { + s++; + } + continue; + } + if ( inquote ) { + if ( *s == '"' ) { + inquote = 0; + } + } else { + if ( *s == '"' ) { + inquote = 1; + } else if ( LDAP_DNSEPARATOR( *s ) ) { + *s = '\0'; + return( rdn ); + } + } + } + + return( rdn ); +} diff --git a/libraries/libldap/getdn.c b/libraries/libldap/getdn.c index c69b0b3e45..cf0af94749 100644 --- a/libraries/libldap/getdn.c +++ b/libraries/libldap/getdn.c @@ -54,8 +54,13 @@ ldap_dn2ufn( LDAP_CONST char *dn ) Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 ); - if ( ldap_is_dns_dn( dn ) || ( p = strchr( dn, '=' )) == NULL ) + if( dn == NULL ) { + return NULL; + } + + if ( ldap_is_dns_dn( dn ) ) { return( LDAP_STRDUP( dn ) ); + } ufn = LDAP_STRDUP( ++p ); @@ -279,7 +284,9 @@ explode_name( const char *name, int notypes, int is_dn ) int ldap_is_dns_dn( LDAP_CONST char *dn ) { - return( dn[ 0 ] != '\0' && strchr( dn, '=' ) == NULL && - strchr( dn, ',' ) == NULL ); + return( dn[ 0 ] != '\0' + && strchr( dn, '=' ) == NULL + && strchr( dn, ',' ) == NULL + && strchr( dn, ';' ) == NULL ); } diff --git a/libraries/libldap/getfilter.c b/libraries/libldap/getfilter.c index 2c06810ab6..eac26d998b 100644 --- a/libraries/libldap/getfilter.c +++ b/libraries/libldap/getfilter.c @@ -243,17 +243,17 @@ ldap_getfirstfilter( for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = flp->lfl_next ) { /* compile tagpat, continue if we fail */ - if (regcomp(&re, tagpat, 0) != 0) + if (regcomp(&re, tagpat, REG_EXTENDED|REG_NOSUB) != 0) continue; - /* match tagpatern and tag, continue if we fail */ + /* match tagpattern and tag, continue if we fail */ rc = regexec(&re, flp->lfl_tag, 0, NULL, 0); regfree(&re); if (rc != 0) continue; /* compile flp->ifl_pattern, continue if we fail */ - if (regcomp(&re, flp->lfl_pattern, REG_EXTENDED) != 0) + if (regcomp(&re, flp->lfl_pattern, REG_EXTENDED|REG_NOSUB) != 0) continue; /* match ifl_pattern and lfd_curval, continue if we fail */ diff --git a/libraries/libldap/libldap.dsp b/libraries/libldap/libldap.dsp index 081c82e4df..48692feb92 100644 --- a/libraries/libldap/libldap.dsp +++ b/libraries/libldap/libldap.dsp @@ -179,6 +179,10 @@ SOURCE=..\..\include\disptmpl.h # End Source File # Begin Source File +SOURCE=.\dn.c +# End Source File +# Begin Source File + SOURCE=.\dsparse.c # End Source File # Begin Source File diff --git a/libraries/libldap/string.c b/libraries/libldap/string.c index 494248531e..d785f8d3bb 100644 --- a/libraries/libldap/string.c +++ b/libraries/libldap/string.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "ldap-int.h" @@ -103,3 +104,29 @@ char * memcpy( p, s, len ); return( p ); } + +char * +ldap_pvt_str2upper( char *str ) +{ + char *s; + + /* to upper */ + for ( s = str; *s; s++ ) { + *s = TOUPPER( (unsigned char) *s ); + } + + return( str ); +} + +char * +ldap_pvt_str2lower( char *str ) +{ + char *s; + + /* to lower */ + for ( s = str; *s; s++ ) { + *s = TOLOWER( (unsigned char) *s ); + } + + return( str ); +} diff --git a/libraries/libldap/tls.c b/libraries/libldap/tls.c index 1ac30e5496..c633ac084e 100644 --- a/libraries/libldap/tls.c +++ b/libraries/libldap/tls.c @@ -414,19 +414,19 @@ ldap_pvt_tls_get_option( struct ldapoptions *lo, int option, void *arg ) break; case LDAP_OPT_X_TLS_CACERTFILE: *(char **)arg = tls_opt_cacertfile ? - strdup( tls_opt_cacertfile ) : NULL; + LDAP_STRDUP( tls_opt_cacertfile ) : NULL; break; case LDAP_OPT_X_TLS_CACERTDIR: *(char **)arg = tls_opt_cacertdir ? - strdup( tls_opt_cacertdir ) : NULL; + LDAP_STRDUP( tls_opt_cacertdir ) : NULL; break; case LDAP_OPT_X_TLS_CERTFILE: *(char **)arg = tls_opt_certfile ? - strdup( tls_opt_certfile ) : NULL; + LDAP_STRDUP( tls_opt_certfile ) : NULL; break; case LDAP_OPT_X_TLS_KEYFILE: *(char **)arg = tls_opt_keyfile ? - strdup( tls_opt_keyfile ) : NULL; + LDAP_STRDUP( tls_opt_keyfile ) : NULL; break; case LDAP_OPT_X_TLS_REQUIRE_CERT: *(int *)arg = tls_opt_require_cert; @@ -466,26 +466,26 @@ ldap_pvt_tls_set_option( struct ldapoptions *lo, int option, void *arg ) switch( option ) { case LDAP_OPT_X_TLS_CACERTFILE: if ( tls_opt_cacertfile ) free( tls_opt_cacertfile ); - tls_opt_cacertfile = arg ? strdup( (char *) arg ) : NULL; + tls_opt_cacertfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; break; case LDAP_OPT_X_TLS_CACERTDIR: if ( tls_opt_cacertdir ) free( tls_opt_cacertdir ); - tls_opt_cacertdir = arg ? strdup( (char *) arg ) : NULL; + tls_opt_cacertdir = arg ? LDAP_STRDUP( (char *) arg ) : NULL; break; case LDAP_OPT_X_TLS_CERTFILE: if ( tls_opt_certfile ) free( tls_opt_certfile ); - tls_opt_certfile = arg ? strdup( (char *) arg ) : NULL; + tls_opt_certfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; break; case LDAP_OPT_X_TLS_KEYFILE: if ( tls_opt_keyfile ) free( tls_opt_keyfile ); - tls_opt_keyfile = arg ? strdup( (char *) arg ) : NULL; + tls_opt_keyfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; break; case LDAP_OPT_X_TLS_REQUIRE_CERT: tls_opt_require_cert = * (int *) arg; break; case LDAP_OPT_X_TLS_CIPHER_SUITE: if ( tls_opt_ciphersuite ) free( tls_opt_ciphersuite ); - tls_opt_ciphersuite = arg ? strdup( (char *) arg ) : NULL; + tls_opt_ciphersuite = arg ? LDAP_STRDUP( (char *) arg ) : NULL; break; default: return -1; diff --git a/servers/slapd/attr.c b/servers/slapd/attr.c index 9bde8bc6b7..2ebf99a013 100644 --- a/servers/slapd/attr.c +++ b/servers/slapd/attr.c @@ -22,6 +22,7 @@ #include #endif +#include "ldap_pvt.h" #include "ldap_defaults.h" #include "slap.h" @@ -111,7 +112,7 @@ attr_normalize( char *s ) { assert( s != NULL ); - return( str2lower( s ) ); + return( ldap_pvt_str2lower( s ) ); } /* diff --git a/servers/slapd/config.c b/servers/slapd/config.c index f669e359d6..4d7d999c61 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -15,6 +15,7 @@ #include #include +#include "ldap_pvt.h" #include "ldap_defaults.h" #include "slap.h" @@ -235,7 +236,7 @@ read_config( const char *fname ) char *dn = ch_strdup( cargv[1] ); (void) dn_normalize( dn ); charray_add( &be->be_suffix, dn ); - (void) str2upper( dn ); + (void) ldap_pvt_str2upper( dn ); charray_add( &be->be_nsuffix, dn ); free( dn ); } diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c index 666b6cf20d..d1ddd2a59d 100644 --- a/servers/slapd/daemon.c +++ b/servers/slapd/daemon.c @@ -15,6 +15,7 @@ #include #include +#include "ldap_pvt.h" #include "ldap_defaults.h" #include "slap.h" @@ -708,7 +709,7 @@ slapd_daemon_task( sizeof(from.sin_addr.s_addr), AF_INET ); if(hp) { - dnsname = str2lower( hp->h_name ); + dnsname = ldap_pvt_str2lower( hp->h_name ); } else { dnsname = NULL; diff --git a/servers/slapd/dn.c b/servers/slapd/dn.c index be724852e0..35fb84c5d5 100644 --- a/servers/slapd/dn.c +++ b/servers/slapd/dn.c @@ -13,6 +13,8 @@ #include #include +#include "ldap_pvt.h" + #include "slap.h" #define B4LEADTYPE 0 @@ -181,7 +183,7 @@ dn_normalize( char *dn ) char * dn_normalize_case( char *dn ) { - str2upper( dn ); + ldap_pvt_str2upper( dn ); /* normalize format */ dn = dn_normalize( dn ); @@ -219,6 +221,7 @@ dn_parent( return( NULL ); } +#ifdef DNS_DN /* * no =, assume it is a dns name, like blah@some.domain.name * if the blah@ part is there, return some.domain.name. if @@ -236,6 +239,7 @@ dn_parent( return( ch_strdup( &s[1] ) ); } } +#endif /* * else assume it is an X.500-style name, which looks like @@ -407,33 +411,6 @@ dn_type( char *dn ) } #endif -char * -str2upper( char *str ) -{ - char *s; - - /* normalize case */ - for ( s = str; *s; s++ ) { - *s = TOUPPER( (unsigned char) *s ); - } - - return( str ); -} - -char * -str2lower( char *str ) -{ - char *s; - - /* normalize case */ - for ( s = str; *s; s++ ) { - *s = TOLOWER( (unsigned char) *s ); - } - - return( str ); -} - - /* * get_next_substring(), rdn_attr_type(), rdn_attr_value(), and * build_new_dn(). diff --git a/servers/slapd/main.c b/servers/slapd/main.c index e70186bb70..a54e4a64ad 100644 --- a/servers/slapd/main.c +++ b/servers/slapd/main.c @@ -75,15 +75,15 @@ typedef struct _str2intDispatch { /* table to compute syslog-options to integer */ static STRDISP syslog_types[] = { - { "LOCAL0", 6, LOG_LOCAL0 }, - { "LOCAL1", 6, LOG_LOCAL1 }, - { "LOCAL2", 6, LOG_LOCAL2 }, - { "LOCAL3", 6, LOG_LOCAL3 }, - { "LOCAL4", 6, LOG_LOCAL4 }, - { "LOCAL5", 6, LOG_LOCAL5 }, - { "LOCAL6", 6, LOG_LOCAL6 }, - { "LOCAL7", 6, LOG_LOCAL7 }, - { NULL } + { "LOCAL0", sizeof("LOCAL0"), LOG_LOCAL0 }, + { "LOCAL1", sizeof("LOCAL1"), LOG_LOCAL1 }, + { "LOCAL2", sizeof("LOCAL2"), LOG_LOCAL2 }, + { "LOCAL3", sizeof("LOCAL3"), LOG_LOCAL3 }, + { "LOCAL4", sizeof("LOCAL4"), LOG_LOCAL4 }, + { "LOCAL5", sizeof("LOCAL5"), LOG_LOCAL5 }, + { "LOCAL6", sizeof("LOCAL6"), LOG_LOCAL6 }, + { "LOCAL7", sizeof("LOCAL7"), LOG_LOCAL7 }, + { NULL } }; static int cnvt_str2int( char *, STRDISP_P, int ); diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 57c47f10f9..01b39c7243 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -213,8 +213,6 @@ int dn_issuffix LDAP_P(( char *dn, char *suffix )); #ifdef DNS_DN int dn_type LDAP_P(( char *dn )); #endif -char * str2upper LDAP_P(( char *str )); -char * str2lower LDAP_P(( char *str )); int rdn_validate LDAP_P(( const char* str )); char * rdn_attr_value LDAP_P(( char * rdn )); char * rdn_attr_type LDAP_P(( char * rdn )); -- 2.39.5