X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=libraries%2Flibldap%2Furl.c;h=adc08c9b48951ee2fc7f9791ce58b00064f1ef8d;hb=966616b274d24c45b1f3a71ff35ddd502153b4a1;hp=bb2cfcdb7df92e0aa006173f91c25c268506e1ce;hpb=29d9fa20a2823c827f098d78f1ea8539d86bf4cf;p=openldap diff --git a/libraries/libldap/url.c b/libraries/libldap/url.c index bb2cfcdb7d..adc08c9b48 100644 --- a/libraries/libldap/url.c +++ b/libraries/libldap/url.c @@ -10,7 +10,7 @@ * LIBLDAP url.c -- LDAP URL (RFC 2255) related routines * * LDAP URLs look like this: - * ldap[s]://host:port[/[dn[?[attributes][?[scope][?[filter][?exts]]]]]] + * ldap[is]://host:port[/[dn[?[attributes][?[scope][?[filter][?exts]]]]]] * * where: * attributes is a comma separated list @@ -28,7 +28,6 @@ #include -#include #include #include #include @@ -40,51 +39,98 @@ static const char* skip_url_prefix LDAP_P(( const char *url, int *enclosedp, - unsigned long *properties, - int *protocol)); + const char **scheme )); +int ldap_pvt_url_scheme2proto( const char *scheme ) +{ + assert( scheme ); + + if( scheme == NULL ) { + return -1; + } + + if( strcmp("ldap", scheme) == 0 ) { + return LDAP_PROTO_TCP; + } + + if( strcmp("ldapi", scheme) == 0 ) { + return LDAP_PROTO_IPC; + } + + if( strcmp("ldaps", scheme) == 0 ) { + return LDAP_PROTO_TCP; + } + + return -1; +} + +int ldap_pvt_url_scheme2tls( const char *scheme ) +{ + assert( scheme ); + + if( scheme == NULL ) { + return -1; + } + + return strcmp("ldaps", scheme) == 0; +} int ldap_is_ldap_url( LDAP_CONST char *url ) { - int enclosed, protocol; - unsigned long properties; + int enclosed; + const char * scheme; if( url == NULL ) { return 0; } - if( skip_url_prefix( url, &enclosed, &properties, &protocol) == NULL ) { + if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) { return 0; } - return !(properties & LDAP_URL_USE_SSL); + return 1; } int ldap_is_ldaps_url( LDAP_CONST char *url ) { - int enclosed, protocol; - unsigned long properties; + int enclosed; + const char * scheme; + + if( url == NULL ) { + return 0; + } + + if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) { + return 0; + } + + return strcmp(scheme, "ldaps") == 0; +} + +int +ldap_is_ldapi_url( LDAP_CONST char *url ) +{ + int enclosed; + const char * scheme; if( url == NULL ) { return 0; } - if( skip_url_prefix( url, &enclosed, &properties, &protocol) == NULL ) { + if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) { return 0; } - return (properties & LDAP_URL_USE_SSL); + return strcmp(scheme, "ldapi") == 0; } static const char* skip_url_prefix( const char *url, int *enclosedp, - unsigned long *properties, - int *protocol - ) + const char **scheme ) { /* * return non-zero if this looks like a LDAP URL; zero if not @@ -107,18 +153,15 @@ skip_url_prefix( } /* skip leading "URL:" (if any) */ - if ( strncasecmp( p, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) - { + if ( strncasecmp( p, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) { p += LDAP_URL_URLCOLON_LEN; } - *properties = 0; - /* 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; - *protocol = LDAP_PROTO_TCP; + *scheme = "ldap"; return( p ); } @@ -126,8 +169,7 @@ skip_url_prefix( if ( strncasecmp( p, LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) { /* skip over "ldaps://" prefix and return success */ p += LDAPS_URL_PREFIX_LEN; - *protocol = LDAP_PROTO_TCP; - *properties |= LDAP_URL_USE_SSL; + *scheme = "ldaps"; return( p ); } @@ -135,16 +177,7 @@ skip_url_prefix( if ( strncasecmp( p, LDAPI_URL_PREFIX, LDAPI_URL_PREFIX_LEN ) == 0 ) { /* skip over "ldapi://" prefix and return success */ p += LDAPI_URL_PREFIX_LEN; - *protocol = LDAP_PROTO_LOCAL; - return( p ); - } - - /* check for "ldapis://" prefix: should this be legal? */ - if ( strncasecmp( p, LDAPIS_URL_PREFIX, LDAPIS_URL_PREFIX_LEN ) == 0 ) { - /* skip over "ldapis://" prefix and return success */ - p += LDAPIS_URL_PREFIX_LEN; - *protocol = LDAP_PROTO_LOCAL; - *properties |= LDAP_URL_USE_SSL; + *scheme = "ldapi"; return( p ); } @@ -175,36 +208,46 @@ static int str2scope( const char *p ) int -ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) +ldap_url_parse_ext( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) { /* * Pick apart the pieces of an LDAP URL. */ LDAPURLDesc *ludp; - char *p, *q; - int i, enclosed, protocol; - unsigned long properties; + char *p, *q, *r; + int i, enclosed; + const char *scheme = NULL; const char *url_tmp; char *url; - if( url_in == NULL && ludpp == NULL ) { + if( url_in == NULL || ludpp == NULL ) { return LDAP_URL_ERR_PARAM; } - Debug( LDAP_DEBUG_TRACE, "ldap_url_parse(%s)\n", url_in, 0, 0 ); +#ifndef LDAP_INT_IN_KERNEL + /* Global options may not be created yet + * We can't test if the global options are initialized + * because a call to LDAP_INT_GLOBAL_OPT() will try to allocate + * the options and cause infinite recursion + */ + Debug( LDAP_DEBUG_TRACE, "ldap_url_parse_ext(%s)\n", url_in, 0, 0 ); +#endif *ludpp = NULL; /* pessimistic */ - url_tmp = skip_url_prefix( url_in, &enclosed, &properties, &protocol ); + url_tmp = skip_url_prefix( url_in, &enclosed, &scheme ); if ( url_tmp == NULL ) { - return LDAP_URL_ERR_NOTLDAP; + return LDAP_URL_ERR_BADSCHEME; } + assert( scheme ); + /* make working copy of the remainder of the URL */ - if (( url = LDAP_STRDUP( url_tmp )) == NULL ) { - return( LDAP_URL_ERR_MEM ); + url = LDAP_STRDUP( url_tmp ); + if ( url == NULL ) { + return LDAP_URL_ERR_MEM; } if ( enclosed ) { @@ -228,22 +271,26 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) ludp->lud_next = NULL; ludp->lud_host = NULL; - ludp->lud_port = 0; + ludp->lud_port = LDAP_PORT; ludp->lud_dn = NULL; ludp->lud_attrs = NULL; ludp->lud_filter = NULL; - ludp->lud_properties = properties; - ludp->lud_protocol = protocol; - ludp->lud_scope = LDAP_SCOPE_BASE; + ludp->lud_scope = LDAP_SCOPE_DEFAULT; + ludp->lud_filter = NULL; + ludp->lud_exts = NULL; - ludp->lud_filter = LDAP_STRDUP("(objectClass=*)"); + ludp->lud_scheme = LDAP_STRDUP( scheme ); - if( ludp->lud_filter == NULL ) { + if ( ludp->lud_scheme == NULL ) { LDAP_FREE( url ); ldap_free_urldesc( ludp ); return LDAP_URL_ERR_MEM; } + if( strcasecmp( ludp->lud_scheme, "ldaps" ) == 0 ) { + ludp->lud_port = LDAPS_PORT; + } + /* scan forward for '/' that marks end of hostport and begin. of dn */ p = strchr( url, '/' ); @@ -252,7 +299,21 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) *p++ = '\0'; } - if (( q = strchr( url, ':' )) != NULL ) { + /* IPv6 syntax with [ip address]:port */ + if ( *url == '[' ) { + r = strchr( url, ']' ); + if ( r == NULL ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADURL; + } + *r++ = '\0'; + q = strchr( r, ':' ); + } else { + q = strchr( url, ':' ); + } + + if ( q != NULL ) { *q++ = '\0'; ldap_pvt_hex_unescape( q ); @@ -266,7 +327,9 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) } ldap_pvt_hex_unescape( url ); - ludp->lud_host = LDAP_STRDUP( url ); + + /* If [ip address]:port syntax, url is [ip and we skip the [ */ + ludp->lud_host = LDAP_STRDUP( url + ( *url == '[' ) ); if( ludp->lud_host == NULL ) { LDAP_FREE( url ); @@ -274,6 +337,36 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) return LDAP_URL_ERR_MEM; } + /* + * Kludge. ldap://111.222.333.444:389??cn=abc,o=company + * + * On early Novell releases, search references/referrals were returned + * in this format, i.e., the dn was kind of in the scope position, + * but the required slash is missing. The whole thing is illegal syntax, + * but we need to account for it. Fortunately it can't be confused with + * anything real. + */ + if( (p == NULL) && (q != NULL) && ((q = strchr( q, '?')) != NULL)) { + q++; + /* ? immediately followed by question */ + if( *q == '?') { + q++; + if( *q != '\0' ) { + /* parse dn part */ + ldap_pvt_hex_unescape( q ); + ludp->lud_dn = LDAP_STRDUP( q ); + } else { + ludp->lud_dn = LDAP_STRDUP( "" ); + } + + if( ludp->lud_dn == NULL ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_MEM; + } + } + } + if( p == NULL ) { LDAP_FREE( url ); *ludpp = ludp; @@ -424,11 +517,15 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) for( i=0; ludp->lud_exts[i] != NULL; i++ ) { ldap_pvt_hex_unescape( ludp->lud_exts[i] ); + + if( *ludp->lud_exts[i] == '!' ) { + /* count the number of critical extensions */ + ludp->lud_crit_exts++; + } } 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; @@ -440,6 +537,27 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) return LDAP_URL_SUCCESS; } +int +ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) +{ + int rc = ldap_url_parse_ext( url_in, ludpp ); + + if( rc != LDAP_URL_SUCCESS ) { + return rc; + } + + if ((*ludpp)->lud_scope == LDAP_SCOPE_DEFAULT) { + (*ludpp)->lud_scope = LDAP_SCOPE_BASE; + } + + if ((*ludpp)->lud_host != NULL && *(*ludpp)->lud_host == '\0') { + LDAP_FREE( (*ludpp)->lud_host ); + (*ludpp)->lud_host = NULL; + } + + return rc; +} + LDAPURLDesc * ldap_url_dup ( LDAPURLDesc *ludp ) { @@ -454,8 +572,22 @@ ldap_url_dup ( LDAPURLDesc *ludp ) return NULL; *dest = *ludp; + dest->lud_scheme = NULL; + dest->lud_host = NULL; + dest->lud_dn = NULL; + dest->lud_filter = NULL; + dest->lud_attrs = NULL; + dest->lud_exts = NULL; dest->lud_next = NULL; + if ( ludp->lud_scheme != NULL ) { + dest->lud_scheme = LDAP_STRDUP( ludp->lud_scheme ); + if (dest->lud_scheme == NULL) { + ldap_free_urldesc(dest); + return NULL; + } + } + if ( ludp->lud_host != NULL ) { dest->lud_host = LDAP_STRDUP( ludp->lud_host ); if (dest->lud_host == NULL) { @@ -556,7 +688,10 @@ ldap_url_parselist (LDAPURLDesc **ludlist, const char *url ) } int -ldap_url_parsehosts (LDAPURLDesc **ludlist, const char *hosts ) +ldap_url_parsehosts( + LDAPURLDesc **ludlist, + const char *hosts, + int port ) { int i; LDAPURLDesc *ludp; @@ -572,7 +707,8 @@ ldap_url_parsehosts (LDAPURLDesc **ludlist, const char *hosts ) return LDAP_NO_MEMORY; /* count the URLs... */ - for (i = 0; specs[i] != NULL; i++) ; + for (i = 0; specs[i] != NULL; i++) /* EMPTY */; + /* ...and put them in the "stack" backward */ while (--i >= 0) { ludp = LDAP_CALLOC( 1, sizeof(LDAPURLDesc) ); @@ -582,22 +718,46 @@ ldap_url_parsehosts (LDAPURLDesc **ludlist, const char *hosts ) *ludlist = NULL; return LDAP_NO_MEMORY; } + ludp->lud_port = port; ludp->lud_host = specs[i]; specs[i] = NULL; p = strchr(ludp->lud_host, ':'); if (p != NULL) { - *p++ = 0; - ldap_pvt_hex_unescape(p); - ludp->lud_port = atoi(p); + /* more than one :, IPv6 address */ + if ( strchr(p+1, ':') != NULL ) { + /* allow [address] and [address]:port */ + if ( *ludp->lud_host == '[' ) { + p = LDAP_STRDUP(ludp->lud_host+1); + /* copied, make sure we free source later */ + specs[i] = ludp->lud_host; + ludp->lud_host = p; + p = strchr( ludp->lud_host, ']' ); + if ( p == NULL ) + return LDAP_PARAM_ERROR; + *p++ = '\0'; + if ( *p != ':' ) { + if ( *p != '\0' ) + return LDAP_PARAM_ERROR; + p = NULL; + } + } else { + p = NULL; + } + } + if (p != NULL) { + *p++ = 0; + ldap_pvt_hex_unescape(p); + ludp->lud_port = atoi(p); + } } ldap_pvt_hex_unescape(ludp->lud_host); - ludp->lud_protocol = LDAP_PROTO_TCP; - ludp->lud_properties = 0; + ludp->lud_scheme = LDAP_STRDUP("ldap"); ludp->lud_next = *ludlist; *ludlist = ludp; } /* this should be an array of NULLs now */ + /* except entries starting with [ */ ldap_charray_free(specs); return LDAP_SUCCESS; } @@ -616,6 +776,8 @@ ldap_url_list2hosts (LDAPURLDesc *ludlist) size = 1; /* nul-term */ for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { size += strlen(ludp->lud_host) + 1; /* host and space */ + if (strchr(ludp->lud_host, ':')) /* will add [ ] below */ + size += 2; if (ludp->lud_port != 0) size += sprintf(buf, ":%d", ludp->lud_port); } @@ -625,8 +787,12 @@ ldap_url_list2hosts (LDAPURLDesc *ludlist) p = s; for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { - strcpy(p, ludp->lud_host); - p += strlen(ludp->lud_host); + if (strchr(ludp->lud_host, ':')) { + p += sprintf(p, "[%s]", ludp->lud_host); + } else { + strcpy(p, ludp->lud_host); + p += strlen(ludp->lud_host); + } if (ludp->lud_port != 0) p += sprintf(p, ":%d", ludp->lud_port); *p++ = ' '; @@ -638,7 +804,8 @@ ldap_url_list2hosts (LDAPURLDesc *ludlist) } char * -ldap_url_list2urls (LDAPURLDesc *ludlist) +ldap_url_list2urls( + LDAPURLDesc *ludlist ) { LDAPURLDesc *ludp; int size; @@ -650,17 +817,26 @@ ldap_url_list2urls (LDAPURLDesc *ludlist) /* figure out how big the string is */ size = 1; /* nul-term */ for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { - size += strlen(ludp->lud_host) + 1 + sizeof("ldapis:///"); /* prefix, host, /, and space */ - if (ludp->lud_port != 0) + size += strlen(ludp->lud_scheme) + strlen(ludp->lud_host); + if (strchr(ludp->lud_host, ':')) /* will add [ ] below */ + size += 2; + size += sizeof(":/// "); + + if (ludp->lud_port != 0) { size += sprintf(buf, ":%d", ludp->lud_port); + } } + s = LDAP_MALLOC(size); - if (s == NULL) + if (s == NULL) { return NULL; + } p = s; for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { - p += sprintf(p, "ldap%s://%s", (ludp->lud_properties & LDAP_URL_USE_SSL) ? "s" : "", ludp->lud_host); + p += sprintf(p, + strchr(ludp->lud_host, ':') ? "%s://[%s]" : "%s://%s", + ludp->lud_scheme, ludp->lud_host); if (ludp->lud_port != 0) p += sprintf(p, ":%d", ludp->lud_port); *p++ = '/'; @@ -690,6 +866,10 @@ ldap_free_urldesc( LDAPURLDesc *ludp ) return; } + if ( ludp->lud_scheme != NULL ) { + LDAP_FREE( ludp->lud_scheme ); + } + if ( ludp->lud_host != NULL ) { LDAP_FREE( ludp->lud_host ); } @@ -721,12 +901,22 @@ ldap_url_search( LDAP *ld, LDAP_CONST char *url, int attrsonly ) int err; LDAPURLDesc *ludp; BerElement *ber; + LDAPreqinfo bind; + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); if ( ldap_url_parse( url, &ludp ) != 0 ) { ld->ld_errno = LDAP_PARAM_ERROR; return( -1 ); } + if( ludp->lud_crit_exts ) { + /* we don't support any extension (yet) */ + ld->ld_errno = LDAP_NOT_SUPPORTED; + return( -1 ); + } + ber = ldap_build_search_req( ld, ludp->lud_dn, ludp->lud_scope, ludp->lud_filter, ludp->lud_attrs, attrsonly, NULL, NULL, -1, -1 ); @@ -734,11 +924,12 @@ ldap_url_search( LDAP *ld, LDAP_CONST char *url, int attrsonly ) if ( ber == NULL ) { err = -1; } else { + bind.ri_request = LDAP_REQ_SEARCH; + bind.ri_msgid = ld->ld_msgid; + bind.ri_url = (char *)url; err = ldap_send_server_request( ld, ber, ld->ld_msgid, NULL, - (ludp->lud_host != NULL || ludp->lud_port != 0) - ? ludp : NULL, - NULL, 1 ); + NULL, NULL, &bind ); } ldap_free_urldesc( ludp ); @@ -791,10 +982,10 @@ ldap_url_search_s( void ldap_pvt_hex_unescape( char *s ) { -/* -* Remove URL hex escapes from s... done in place. The basic concept for -* this routine is borrowed from the WWW library HTUnEscape() routine. -*/ + /* + * Remove URL hex escapes from s... done in place. The basic concept for + * this routine is borrowed from the WWW library HTUnEscape() routine. + */ char *p; for ( p = s; *s != '\0'; ++s ) {