X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Furl.c;h=e6cf9e07532cf7798a6ad2f0675c6c5768df8e3c;hb=49d73e12a720cfe052a335d82e67994ff261d21c;hp=b15b1dc7e50258865d8f69e875f759e419013366;hpb=878466d375d375e243ba9dbe9ff8b7e3ba918cf5;p=openldap diff --git a/libraries/libldap/url.c b/libraries/libldap/url.c index b15b1dc7e5..e6cf9e0753 100644 --- a/libraries/libldap/url.c +++ b/libraries/libldap/url.c @@ -1,6 +1,6 @@ /* $OpenLDAP$ */ /* - * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved. + * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved. * COPYING RESTRICTIONS APPLY, see COPYRIGHT file */ /* Portions @@ -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, &properties, &protocol) == NULL ) { + if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) { return 0; } - return (properties & LDAP_URL_USE_SSL); + 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, &scheme ) == NULL ) { + return 0; + } + + 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 @@ -112,13 +158,11 @@ skip_url_prefix( 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 +170,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 +178,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 ); } @@ -182,9 +216,9 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) */ 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; @@ -192,19 +226,29 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) return LDAP_URL_ERR_PARAM; } +#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(%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 ) { @@ -232,13 +276,12 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) 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_filter = 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; @@ -252,7 +295,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 +323,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 +333,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; @@ -454,8 +543,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) { @@ -572,7 +675,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) ); @@ -586,18 +690,41 @@ ldap_url_parsehosts (LDAPURLDesc **ludlist, const char *hosts ) 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 +743,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 +754,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 +771,8 @@ ldap_url_list2hosts (LDAPURLDesc *ludlist) } char * -ldap_url_list2urls (LDAPURLDesc *ludlist) +ldap_url_list2urls( + LDAPURLDesc *ludlist ) { LDAPURLDesc *ludp; int size; @@ -650,17 +784,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 +833,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,6 +868,7 @@ ldap_url_search( LDAP *ld, LDAP_CONST char *url, int attrsonly ) int err; LDAPURLDesc *ludp; BerElement *ber; + LDAPreqinfo bind; if ( ldap_url_parse( url, &ludp ) != 0 ) { ld->ld_errno = LDAP_PARAM_ERROR; @@ -734,11 +882,14 @@ 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, &bind ); } ldap_free_urldesc( ludp );