X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Furl.c;h=b632c688f8da78a9b5014bf506d60ab48bef76a9;hb=91e24173d0fa168bdd3e585af2d56f3299a20c00;hp=83ccbdc5460bf73e198985d0265b17dabb91816b;hpb=41a48b09dd6b49c27f67a238473401b18cc4c0a1;p=openldap diff --git a/libraries/libldap/url.c b/libraries/libldap/url.c index 83ccbdc546..b632c688f8 100644 --- a/libraries/libldap/url.c +++ b/libraries/libldap/url.c @@ -1,299 +1,498 @@ +/* $OpenLDAP$ */ /* + * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions * Copyright (c) 1996 Regents of the University of Michigan. * All rights reserved. * - * LIBLDAP url.c -- LDAP URL related routines + * LIBLDAP url.c -- LDAP URL (RFC 2255) related routines * * LDAP URLs look like this: - * l d a p : / / hostport / dn [ ? attributes [ ? scope [ ? filter ] ] ] + * ldap[s]://host:port[/[dn[?[attributes][?[scope][?[filter][?exts]]]]]] * * where: * attributes is a comma separated list * scope is one of these three strings: base one sub (default=base) - * filter is an string-represented filter as in RFC 1558 + * filter is an string-represented filter as in RFC 2254 * - * e.g., ldap://ldap.itd.umich.edu/c=US?o,description?one?o=umich + * e.g., ldap://host:port/dc=com?o,cn?base?o=openldap?extension * * We also tolerate URLs that look like: and */ #include "portable.h" -#ifndef lint -static char copyright[] = "@(#) Copyright (c) 1996 Regents of the University of Michigan.\nAll rights reserved.\n"; -#endif - #include -#include + +#include #include #include #include #include -#include "lber.h" -#include "ldap.h" #include "ldap-int.h" -static int skip_url_prefix LDAP_P(( char **urlp, int *enclosedp )); -static void hex_unescape LDAP_P(( char *s )); -static int unhex LDAP_P(( char c )); +/* local functions */ +static const char* skip_url_prefix LDAP_P(( + const char *url, + int *enclosedp, + int *ldaps )); int -ldap_is_ldap_url( char *url ) +ldap_is_ldap_url( LDAP_CONST char *url ) { int enclosed; + int ldaps; + + if( url == NULL ) { + return 0; + } + + if( skip_url_prefix( url, &enclosed, &ldaps) == NULL ) { + return 0; + } - return( url != NULL && skip_url_prefix( &url, &enclosed )); + return !ldaps; } +int +ldap_is_ldaps_url( LDAP_CONST char *url ) +{ + int enclosed; + int ldaps; + + if( url == NULL ) { + return 0; + } + + if( skip_url_prefix( url, &enclosed, &ldaps) == NULL ) { + return 0; + } + + return ldaps; +} -static int -skip_url_prefix( char **urlp, int *enclosedp ) +static const char* +skip_url_prefix( + const char *url, + int *enclosedp, + int *ldaps ) { /* * return non-zero if this looks like a LDAP URL; zero if not * if non-zero returned, *urlp will be moved past "ldap://" part of URL */ - if ( *urlp == NULL ) { - return( 0 ); + const char *p; + + if ( url == NULL ) { + return( NULL ); } + p = url; + /* skip leading '<' (if any) */ - if ( **urlp == '<' ) { + if ( *p == '<' ) { *enclosedp = 1; - ++*urlp; + ++p; } else { *enclosedp = 0; } /* skip leading "URL:" (if any) */ - if ( strlen( *urlp ) >= LDAP_URL_URLCOLON_LEN && strncasecmp( - *urlp, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) { - *urlp += LDAP_URL_URLCOLON_LEN; + if ( strncasecmp( p, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) + { + p += LDAP_URL_URLCOLON_LEN; + } + + /* check for "ldap://" prefix */ + if ( strncasecmp( p, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) == 0 ) { + /* skip over "ldap://" prefix and return success */ + p += LDAP_URL_PREFIX_LEN; + *ldaps = 0; + return( p ); } - /* check for missing "ldap://" prefix */ - if ( strlen( *urlp ) < LDAP_URL_PREFIX_LEN || - strncasecmp( *urlp, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) != 0 ) { - return( 0 ); + /* check for "ldaps://" prefix */ + if ( strncasecmp( p, LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) { + /* skip over "ldaps://" prefix and return success */ + p += LDAPS_URL_PREFIX_LEN; + *ldaps = 1; + return( p ); } - /* skip over "ldap://" prefix and return success */ - *urlp += LDAP_URL_PREFIX_LEN; - return( 1 ); + return( NULL ); } +static int str2scope( const char *p ) +{ + if ( strcasecmp( p, "one" ) == 0 ) { + return LDAP_SCOPE_ONELEVEL; + + } else if ( strcasecmp( p, "onetree" ) == 0 ) { + return LDAP_SCOPE_ONELEVEL; + + } else if ( strcasecmp( p, "base" ) == 0 ) { + return LDAP_SCOPE_BASE; + + } else if ( strcasecmp( p, "sub" ) == 0 ) { + return LDAP_SCOPE_SUBTREE; + + } else if ( strcasecmp( p, "subtree" ) == 0 ) { + return LDAP_SCOPE_SUBTREE; + } + + return( -1 ); +} + int -ldap_url_parse( char *url, LDAPURLDesc **ludpp ) +ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) { /* * Pick apart the pieces of an LDAP URL. */ LDAPURLDesc *ludp; - char *attrs, *p, *q; - int enclosed, i, nattrs; + char *p, *q; + int i, enclosed, ldaps; + const char *url_tmp; + char *url; + + if( url_in == NULL && ludpp == NULL ) { + return LDAP_URL_ERR_PARAM; + } - Debug( LDAP_DEBUG_TRACE, "ldap_url_parse(%s)\n", url, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "ldap_url_parse(%s)\n", url_in, 0, 0 ); *ludpp = NULL; /* pessimistic */ - if ( !skip_url_prefix( &url, &enclosed )) { - return( LDAP_URL_ERR_NOTLDAP ); - } + url_tmp = skip_url_prefix( url_in, &enclosed, &ldaps ); - /* allocate return struct */ - if (( ludp = (LDAPURLDesc *)calloc( 1, sizeof( LDAPURLDesc ))) - == NULLLDAPURLDESC ) { - return( LDAP_URL_ERR_MEM ); + if ( url_tmp == NULL ) { + return LDAP_URL_ERR_NOTLDAP; } /* make working copy of the remainder of the URL */ - if (( url = strdup( url )) == NULL ) { - ldap_free_urldesc( ludp ); + if (( url = LDAP_STRDUP( url_tmp )) == NULL ) { return( LDAP_URL_ERR_MEM ); } - if ( enclosed && *((p = url + strlen( url ) - 1)) == '>' ) { + if ( enclosed ) { + p = &url[strlen(url)-1]; + + if( *p != '>' ) { + LDAP_FREE( url ); + return LDAP_URL_ERR_BADENCLOSURE; + } + *p = '\0'; } - /* set defaults */ + /* allocate return struct */ + ludp = (LDAPURLDesc *)LDAP_CALLOC( 1, sizeof( LDAPURLDesc )); + + if ( ludp == NULL ) { + LDAP_FREE( url ); + return LDAP_URL_ERR_MEM; + } + + ludp->lud_host = NULL; + ludp->lud_port = 0; + ludp->lud_dn = NULL; + ludp->lud_attrs = NULL; + ludp->lud_filter = NULL; + ludp->lud_ldaps = ldaps; ludp->lud_scope = LDAP_SCOPE_BASE; - ludp->lud_filter = "(objectClass=*)"; - /* lud_string is the only malloc'd string space we use */ - ludp->lud_string = url; + ludp->lud_filter = LDAP_STRDUP("(objectClass=*)"); - /* scan forward for '/' that marks end of hostport and begin. of dn */ - if (( ludp->lud_dn = strchr( url, '/' )) == NULL ) { + if( ludp->lud_filter == NULL ) { + LDAP_FREE( url ); ldap_free_urldesc( ludp ); - return( LDAP_URL_ERR_NODN ); + return LDAP_URL_ERR_MEM; } - /* terminate hostport; point to start of dn */ - *ludp->lud_dn++ = '\0'; + /* scan forward for '/' that marks end of hostport and begin. of dn */ + p = strchr( url, '/' ); - if (( p = strchr( url, ':' )) != NULL ) { + if( p != NULL ) { + /* terminate hostport; point to start of dn */ *p++ = '\0'; - ludp->lud_port = atoi( p ); } - if ( *url == '\0' ) { - ludp->lud_host = NULL; - } else { - ludp->lud_host = url; - hex_unescape( ludp->lud_host ); - } - - /* scan for '?' that marks end of dn and beginning of attributes */ - if (( attrs = strchr( ludp->lud_dn, '?' )) != NULL ) { - /* terminate dn; point to start of attrs. */ - *attrs++ = '\0'; - - /* scan for '?' that marks end of attrs and begin. of scope */ - if (( p = strchr( attrs, '?' )) != NULL ) { - /* - * terminate attrs; point to start of scope and scan for - * '?' that marks end of scope and begin. of filter - */ - *p++ = '\0'; - - if (( q = strchr( p, '?' )) != NULL ) { - /* terminate scope; point to start of filter */ - *q++ = '\0'; - if ( *q != '\0' ) { - ludp->lud_filter = q; - hex_unescape( ludp->lud_filter ); - } - } + if (( q = strchr( url, ':' )) != NULL ) { + *q++ = '\0'; + ldap_pvt_hex_unescape( q ); - if ( strcasecmp( p, "one" ) == 0 ) { - ludp->lud_scope = LDAP_SCOPE_ONELEVEL; - } else if ( strcasecmp( p, "base" ) == 0 ) { - ludp->lud_scope = LDAP_SCOPE_BASE; - } else if ( strcasecmp( p, "sub" ) == 0 ) { - ludp->lud_scope = LDAP_SCOPE_SUBTREE; - } else if ( *p != '\0' ) { - ldap_free_urldesc( ludp ); - return( LDAP_URL_ERR_BADSCOPE ); - } + if( *q == '\0' ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADURL; } + + ludp->lud_port = atoi( q ); + } + + ldap_pvt_hex_unescape( url ); + ludp->lud_host = LDAP_STRDUP( url ); + + if( ludp->lud_host == NULL ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_MEM; } - if ( *ludp->lud_dn == '\0' ) { - ludp->lud_dn = NULL; + if( p == NULL ) { + LDAP_FREE( url ); + *ludpp = ludp; + return LDAP_URL_SUCCESS; + } + + /* scan forward for '?' that may marks end of dn */ + q = strchr( p, '?' ); + + if( q != NULL ) { + /* terminate dn part */ + *q++ = '\0'; + } + + if( *p != '\0' ) { + /* parse dn part */ + ldap_pvt_hex_unescape( p ); + ludp->lud_dn = LDAP_STRDUP( p ); } else { - hex_unescape( ludp->lud_dn ); + ludp->lud_dn = LDAP_STRDUP( "" ); } - /* - * if attrs list was included, turn it into a null-terminated array - */ - if ( attrs != NULL && *attrs != '\0' ) { - for ( nattrs = 1, p = attrs; *p != '\0'; ++p ) { - if ( *p == ',' ) { - ++nattrs; - } + if( ludp->lud_dn == NULL ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_MEM; + } + + if( q == NULL ) { + /* no more */ + LDAP_FREE( url ); + *ludpp = ludp; + return LDAP_URL_SUCCESS; + } + + /* scan forward for '?' that may marks end of attributes */ + p = q; + q = strchr( p, '?' ); + + if( q != NULL ) { + /* terminate attributes part */ + *q++ = '\0'; + } + + if( *p != '\0' ) { + /* parse attributes */ + ldap_pvt_hex_unescape( p ); + ludp->lud_attrs = ldap_str2charray( p, "," ); + + if( ludp->lud_attrs == NULL ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADATTRS; + } + } + + if ( q == NULL ) { + /* no more */ + LDAP_FREE( url ); + *ludpp = ludp; + return LDAP_URL_SUCCESS; + } + + /* scan forward for '?' that may marks end of scope */ + p = q; + q = strchr( p, '?' ); + + if( q != NULL ) { + /* terminate the scope part */ + *q++ = '\0'; + } + + if( *p != '\0' ) { + /* parse the scope */ + ldap_pvt_hex_unescape( p ); + ludp->lud_scope = str2scope( p ); + + if( ludp->lud_scope == -1 ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADSCOPE; } + } - if (( ludp->lud_attrs = (char **)calloc( nattrs + 1, - sizeof( char * ))) == NULL ) { + if ( q == NULL ) { + /* no more */ + LDAP_FREE( url ); + *ludpp = ludp; + return LDAP_URL_SUCCESS; + } + + /* scan forward for '?' that may marks end of filter */ + p = q; + q = strchr( p, '?' ); + + if( q != NULL ) { + /* terminate the filter part */ + *q++ = '\0'; + } + + if( *p != '\0' ) { + /* parse the filter */ + ldap_pvt_hex_unescape( p ); + + if( ! *p ) { + /* missing filter */ + LDAP_FREE( url ); ldap_free_urldesc( ludp ); - return( LDAP_URL_ERR_MEM ); + return LDAP_URL_ERR_BADFILTER; } - for ( i = 0, p = attrs; i < nattrs; ++i ) { - ludp->lud_attrs[ i ] = p; - if (( p = strchr( p, ',' )) != NULL ) { - *p++ ='\0'; - } - hex_unescape( ludp->lud_attrs[ i ] ); + LDAP_FREE( ludp->lud_filter ); + ludp->lud_filter = LDAP_STRDUP( p ); + + if( ludp->lud_filter == NULL ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_MEM; } } - *ludpp = ludp; + if ( q == NULL ) { + /* no more */ + LDAP_FREE( url ); + *ludpp = ludp; + return LDAP_URL_SUCCESS; + } - return( 0 ); + /* scan forward for '?' that may marks end of extensions */ + p = q; + q = strchr( p, '?' ); + + if( q != NULL ) { + /* extra '?' */ + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADURL; + } + + /* parse the extensions */ + ludp->lud_exts = ldap_str2charray( p, "," ); + + if( ludp->lud_exts == NULL ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADEXTS; + } + + for( i=0; ludp->lud_exts[i] != NULL; i++ ) { + ldap_pvt_hex_unescape( ludp->lud_exts[i] ); + } + + if( i == 0 ) { + /* must have 1 or more */ + ldap_charray_free( ludp->lud_exts ); + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADEXTS; + } + + /* no more */ + *ludpp = ludp; + LDAP_FREE( url ); + return LDAP_URL_SUCCESS; } void ldap_free_urldesc( LDAPURLDesc *ludp ) { - if ( ludp != NULLLDAPURLDESC ) { - if ( ludp->lud_string != NULL ) { - free( ludp->lud_string ); - } - if ( ludp->lud_attrs != NULL ) { - free( ludp->lud_attrs ); - } - free( ludp ); + if ( ludp == NULL ) { + return; + } + + if ( ludp->lud_host != NULL ) { + LDAP_FREE( ludp->lud_host ); + } + + if ( ludp->lud_dn != NULL ) { + LDAP_FREE( ludp->lud_dn ); + } + + if ( ludp->lud_filter != NULL ) { + LDAP_FREE( ludp->lud_filter); + } + + if ( ludp->lud_attrs != NULL ) { + LDAP_VFREE( ludp->lud_attrs ); + } + + if ( ludp->lud_exts != NULL ) { + LDAP_VFREE( ludp->lud_exts ); } + + LDAP_FREE( ludp ); } int -ldap_url_search( LDAP *ld, char *url, int attrsonly ) +ldap_url_search( LDAP *ld, LDAP_CONST char *url, int attrsonly ) { int err; LDAPURLDesc *ludp; BerElement *ber; -#ifdef LDAP_REFERRALS LDAPServer *srv = NULL; -#endif /* LDAP_REFERRALS */ if ( ldap_url_parse( url, &ludp ) != 0 ) { ld->ld_errno = LDAP_PARAM_ERROR; return( -1 ); } - if (( ber = ldap_build_search_req( ld, ludp->lud_dn, ludp->lud_scope, - ludp->lud_filter, ludp->lud_attrs, attrsonly )) == NULLBER ) { + ber = ldap_build_search_req( ld, ludp->lud_dn, ludp->lud_scope, + ludp->lud_filter, ludp->lud_attrs, attrsonly, NULL, NULL, + -1, -1 ); + + if ( ber == NULL ) { return( -1 ); } err = 0; if ( ludp->lud_host != NULL || ludp->lud_port != 0 ) { -#ifdef LDAP_REFERRALS - if (( srv = (LDAPServer *)calloc( 1, sizeof( LDAPServer ))) - == NULL || ( srv->lsrv_host = strdup( ludp->lud_host == + if (( srv = (LDAPServer *)LDAP_CALLOC( 1, sizeof( LDAPServer ))) + == NULL || ( srv->lsrv_host = LDAP_STRDUP( ludp->lud_host == NULL ? ld->ld_defhost : ludp->lud_host )) == NULL ) { if ( srv != NULL ) { - free( srv ); + LDAP_FREE( srv ); } ld->ld_errno = LDAP_NO_MEMORY; err = -1; } else { if ( ludp->lud_port == 0 ) { - srv->lsrv_port = LDAP_PORT; + srv->lsrv_port = ldap_int_global_options.ldo_defport; } else { - srv->lsrv_port = ludp->lud_port; + srv->lsrv_port = ludp->lud_port; } } -#else /* LDAP_REFERRALS */ - ld->ld_errno = LDAP_LOCAL_ERROR; - err = -1; -#endif /* LDAP_REFERRALS */ } if ( err != 0 ) { ber_free( ber, 1 ); } else { -#ifdef LDAP_REFERRALS err = ldap_send_server_request( ld, ber, ld->ld_msgid, NULL, srv, NULL, 1 ); -#else /* LDAP_REFERRALS */ - err = ldap_send_initial_request( ld, LDAP_REQ_SEARCH, - ludp->lud_dn, ber ); -#endif /* LDAP_REFERRALS */ } ldap_free_urldesc( ludp ); @@ -303,7 +502,7 @@ ldap_url_search( LDAP *ld, char *url, int attrsonly ) int -ldap_url_search_st( LDAP *ld, char *url, int attrsonly, +ldap_url_search_st( LDAP *ld, LDAP_CONST char *url, int attrsonly, struct timeval *timeout, LDAPMessage **res ) { int msgid; @@ -327,7 +526,8 @@ ldap_url_search_st( LDAP *ld, char *url, int attrsonly, int -ldap_url_search_s( LDAP *ld, char *url, int attrsonly, LDAPMessage **res ) +ldap_url_search_s( + LDAP *ld, LDAP_CONST char *url, int attrsonly, LDAPMessage **res ) { int msgid; @@ -343,8 +543,8 @@ ldap_url_search_s( LDAP *ld, char *url, int attrsonly, LDAPMessage **res ) } -static void -hex_unescape( char *s ) +void +ldap_pvt_hex_unescape( char *s ) { /* * Remove URL hex escapes from s... done in place. The basic concept for @@ -355,10 +555,10 @@ hex_unescape( char *s ) for ( p = s; *s != '\0'; ++s ) { if ( *s == '%' ) { if ( *++s != '\0' ) { - *p = unhex( *s ) << 4; + *p = ldap_pvt_unhex( *s ) << 4; } if ( *++s != '\0' ) { - *p++ += unhex( *s ); + *p++ += ldap_pvt_unhex( *s ); } } else { *p++ = *s; @@ -369,8 +569,8 @@ hex_unescape( char *s ) } -static int -unhex( char c ) +int +ldap_pvt_unhex( int c ) { return( c >= '0' && c <= '9' ? c - '0' : c >= 'A' && c <= 'F' ? c - 'A' + 10