X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Furl.c;h=6098bb8910cbaa2b088dc29abb19e317c8628bd2;hb=c23536faa9bebfed42ee17b693f780e160a801ad;hp=874affc0f6f902dc2a1ab4dd2ff16a1f0b336128;hpb=5fea91c3ecffeb5e711051a3d943d8bbb65571dc;p=openldap diff --git a/libraries/libldap/url.c b/libraries/libldap/url.c index 874affc0f6..6098bb8910 100644 --- a/libraries/libldap/url.c +++ b/libraries/libldap/url.c @@ -1,12 +1,13 @@ +/* $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 * 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: * ldap[s]://host:port[/[dn[?[attributes][?[scope][?[filter][?exts]]]]]] @@ -14,7 +15,7 @@ * 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://host:port/dc=com?o,cn?base?o=openldap?extension * @@ -39,62 +40,63 @@ static const char* skip_url_prefix LDAP_P(( const char *url, int *enclosedp, - int *ldaps )); -static void hex_unescape LDAP_P(( char *s )); -static int unhex( char c ); + unsigned long *properties, + int *protocol)); int ldap_is_ldap_url( LDAP_CONST char *url ) { - int enclosed; - int ldaps; + int enclosed, protocol; + unsigned long properties; if( url == NULL ) { return 0; } - if( skip_url_prefix( url, &enclosed, &ldaps) == NULL ) { + if( skip_url_prefix( url, &enclosed, &properties, &protocol) == NULL ) { return 0; } - return !ldaps; + return !(properties & LDAP_URL_USE_SSL); } int ldap_is_ldaps_url( LDAP_CONST char *url ) { - int enclosed; - int ldaps; + int enclosed, protocol; + unsigned long properties; if( url == NULL ) { return 0; } - if( skip_url_prefix( url, &enclosed, &ldaps) == NULL ) { + if( skip_url_prefix( url, &enclosed, &properties, &protocol) == NULL ) { return 0; } - return ldaps; + return (properties & LDAP_URL_USE_SSL); } static const char* skip_url_prefix( const char *url, int *enclosedp, - int *ldaps ) + unsigned long *properties, + int *protocol + ) { /* * 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 */ - char* p; + const char *p; if ( url == NULL ) { return( NULL ); } - p = (char *) url; + p = url; /* skip leading '<' (if any) */ if ( *p == '<' ) { @@ -110,11 +112,13 @@ 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; - *ldaps = 0; + *protocol = LDAP_PROTO_TCP; return( p ); } @@ -122,7 +126,25 @@ 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; - *ldaps = 1; + *protocol = LDAP_PROTO_TCP; + *properties |= LDAP_URL_USE_SSL; + return( p ); + } + + /* check for "ldapi://" 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; return( p ); } @@ -161,7 +183,8 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) LDAPURLDesc *ludp; char *p, *q; - int i, enclosed, ldaps; + int i, enclosed, protocol; + unsigned long properties; const char *url_tmp; char *url; @@ -173,7 +196,7 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) *ludpp = NULL; /* pessimistic */ - url_tmp = skip_url_prefix( url_in, &enclosed, &ldaps ); + url_tmp = skip_url_prefix( url_in, &enclosed, &properties, &protocol ); if ( url_tmp == NULL ) { return LDAP_URL_ERR_NOTLDAP; @@ -203,13 +226,16 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) return LDAP_URL_ERR_MEM; } + ludp->lud_next = NULL; 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_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 = LDAP_STRDUP("(objectClass=*)"); if( ludp->lud_filter == NULL ) { @@ -228,7 +254,7 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) if (( q = strchr( url, ':' )) != NULL ) { *q++ = '\0'; - hex_unescape( q ); + ldap_pvt_hex_unescape( q ); if( *q == '\0' ) { LDAP_FREE( url ); @@ -239,7 +265,7 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) ludp->lud_port = atoi( q ); } - hex_unescape( url ); + ldap_pvt_hex_unescape( url ); ludp->lud_host = LDAP_STRDUP( url ); if( ludp->lud_host == NULL ) { @@ -248,6 +274,36 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) return LDAP_URL_ERR_MEM; } + /* + * Kluge. 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 = 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; @@ -264,7 +320,7 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) if( *p != '\0' ) { /* parse dn part */ - hex_unescape( p ); + ldap_pvt_hex_unescape( p ); ludp->lud_dn = LDAP_STRDUP( p ); } else { ludp->lud_dn = LDAP_STRDUP( "" ); @@ -294,7 +350,7 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) if( *p != '\0' ) { /* parse attributes */ - hex_unescape( p ); + ldap_pvt_hex_unescape( p ); ludp->lud_attrs = ldap_str2charray( p, "," ); if( ludp->lud_attrs == NULL ) { @@ -322,7 +378,7 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) if( *p != '\0' ) { /* parse the scope */ - hex_unescape( p ); + ldap_pvt_hex_unescape( p ); ludp->lud_scope = str2scope( p ); if( ludp->lud_scope == -1 ) { @@ -350,7 +406,7 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) if( *p != '\0' ) { /* parse the filter */ - hex_unescape( p ); + ldap_pvt_hex_unescape( p ); if( ! *p ) { /* missing filter */ @@ -359,6 +415,7 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) return LDAP_URL_ERR_BADFILTER; } + LDAP_FREE( ludp->lud_filter ); ludp->lud_filter = LDAP_STRDUP( p ); if( ludp->lud_filter == NULL ) { @@ -396,7 +453,7 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) } for( i=0; ludp->lud_exts[i] != NULL; i++ ) { - hex_unescape( ludp->lud_exts[i] ); + ldap_pvt_hex_unescape( ludp->lud_exts[i] ); } if( i == 0 ) { @@ -413,6 +470,248 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) return LDAP_URL_SUCCESS; } +LDAPURLDesc * +ldap_url_dup ( LDAPURLDesc *ludp ) +{ + LDAPURLDesc *dest; + + if ( ludp == NULL ) { + return NULL; + } + + dest = LDAP_MALLOC( sizeof(LDAPURLDesc) ); + if (dest == NULL) + return NULL; + + *dest = *ludp; + dest->lud_next = NULL; + + if ( ludp->lud_host != NULL ) { + dest->lud_host = LDAP_STRDUP( ludp->lud_host ); + if (dest->lud_host == NULL) { + ldap_free_urldesc(dest); + return NULL; + } + } + + if ( ludp->lud_dn != NULL ) { + dest->lud_dn = LDAP_STRDUP( ludp->lud_dn ); + if (dest->lud_dn == NULL) { + ldap_free_urldesc(dest); + return NULL; + } + } + + if ( ludp->lud_filter != NULL ) { + dest->lud_filter = LDAP_STRDUP( ludp->lud_filter ); + if (dest->lud_filter == NULL) { + ldap_free_urldesc(dest); + return NULL; + } + } + + if ( ludp->lud_attrs != NULL ) { + dest->lud_attrs = ldap_charray_dup( ludp->lud_attrs ); + if (dest->lud_attrs == NULL) { + ldap_free_urldesc(dest); + return NULL; + } + } + + if ( ludp->lud_exts != NULL ) { + dest->lud_exts = ldap_charray_dup( ludp->lud_exts ); + if (dest->lud_exts == NULL) { + ldap_free_urldesc(dest); + return NULL; + } + } + + return dest; +} + +LDAPURLDesc * +ldap_url_duplist (LDAPURLDesc *ludlist) +{ + LDAPURLDesc *dest, *tail, *ludp, *newludp; + + dest = NULL; + tail = NULL; + for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { + newludp = ldap_url_dup(ludp); + if (newludp == NULL) { + ldap_free_urllist(dest); + return NULL; + } + if (tail == NULL) + dest = newludp; + else + tail->lud_next = newludp; + tail = newludp; + } + return dest; +} + +int +ldap_url_parselist (LDAPURLDesc **ludlist, const char *url ) +{ + int i, rc; + LDAPURLDesc *ludp; + char **urls; + + *ludlist = NULL; + + if (url == NULL) + return LDAP_PARAM_ERROR; + + urls = ldap_str2charray((char *)url, ", "); + if (urls == NULL) + return LDAP_NO_MEMORY; + + /* count the URLs... */ + for (i = 0; urls[i] != NULL; i++) ; + /* ...and put them in the "stack" backward */ + while (--i >= 0) { + rc = ldap_url_parse( urls[i], &ludp ); + if ( rc != 0 ) { + ldap_charray_free(urls); + ldap_free_urllist(*ludlist); + *ludlist = NULL; + return rc; + } + ludp->lud_next = *ludlist; + *ludlist = ludp; + } + ldap_charray_free(urls); + return LDAP_SUCCESS; +} + +int +ldap_url_parsehosts (LDAPURLDesc **ludlist, const char *hosts ) +{ + int i; + LDAPURLDesc *ludp; + char **specs, *p; + + *ludlist = NULL; + + if (hosts == NULL) + return LDAP_PARAM_ERROR; + + specs = ldap_str2charray((char *)hosts, ", "); + if (specs == NULL) + return LDAP_NO_MEMORY; + + /* count the URLs... */ + for (i = 0; specs[i] != NULL; i++) ; + /* ...and put them in the "stack" backward */ + while (--i >= 0) { + ludp = LDAP_CALLOC( 1, sizeof(LDAPURLDesc) ); + if (ludp == NULL) { + ldap_charray_free(specs); + ldap_free_urllist(*ludlist); + *ludlist = NULL; + return LDAP_NO_MEMORY; + } + 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); + } + ldap_pvt_hex_unescape(ludp->lud_host); + ludp->lud_protocol = LDAP_PROTO_TCP; + ludp->lud_properties = 0; + ludp->lud_next = *ludlist; + *ludlist = ludp; + } + + /* this should be an array of NULLs now */ + ldap_charray_free(specs); + return LDAP_SUCCESS; +} + +char * +ldap_url_list2hosts (LDAPURLDesc *ludlist) +{ + LDAPURLDesc *ludp; + int size; + char *s, *p, buf[32]; /* big enough to hold a long decimal # (overkill) */ + + if (ludlist == NULL) + return NULL; + + /* 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; /* host and space */ + if (ludp->lud_port != 0) + size += sprintf(buf, ":%d", ludp->lud_port); + } + s = LDAP_MALLOC(size); + if (s == NULL) + return NULL; + + p = s; + for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { + strcpy(p, ludp->lud_host); + p += strlen(ludp->lud_host); + if (ludp->lud_port != 0) + p += sprintf(p, ":%d", ludp->lud_port); + *p++ = ' '; + } + if (p != s) + p--; /* nuke that extra space */ + *p = 0; + return s; +} + +char * +ldap_url_list2urls (LDAPURLDesc *ludlist) +{ + LDAPURLDesc *ludp; + int size; + char *s, *p, buf[32]; /* big enough to hold a long decimal # (overkill) */ + + if (ludlist == NULL) + return NULL; + + /* 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 += sprintf(buf, ":%d", ludp->lud_port); + } + s = LDAP_MALLOC(size); + 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); + if (ludp->lud_port != 0) + p += sprintf(p, ":%d", ludp->lud_port); + *p++ = '/'; + *p++ = ' '; + } + if (p != s) + p--; /* nuke that extra space */ + *p = 0; + return s; +} + +void +ldap_free_urllist( LDAPURLDesc *ludlist ) +{ + LDAPURLDesc *ludp, *next; + + for (ludp = ludlist; ludp != NULL; ludp = next) { + next = ludp->lud_next; + ldap_free_urldesc(ludp); + } +} void ldap_free_urldesc( LDAPURLDesc *ludp ) @@ -452,7 +751,7 @@ ldap_url_search( LDAP *ld, LDAP_CONST char *url, int attrsonly ) int err; LDAPURLDesc *ludp; BerElement *ber; - LDAPServer *srv = NULL; + LDAPreqinfo bind; if ( ldap_url_parse( url, &ludp ) != 0 ) { ld->ld_errno = LDAP_PARAM_ERROR; @@ -464,38 +763,19 @@ ldap_url_search( LDAP *ld, LDAP_CONST char *url, int attrsonly ) -1, -1 ); if ( ber == NULL ) { - return( -1 ); - } - - err = 0; - - if ( ludp->lud_host != NULL || ludp->lud_port != 0 ) { - 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 ) { - LDAP_FREE( srv ); - } - ld->ld_errno = LDAP_NO_MEMORY; - err = -1; - } else { - if ( ludp->lud_port == 0 ) { - srv->lsrv_port = ldap_int_global_options.ldo_defport; - } else { - srv->lsrv_port = ludp->lud_port; - } - } - } - - if ( err != 0 ) { - ber_free( ber, 1 ); + err = -1; } else { - err = ldap_send_server_request( ld, ber, ld->ld_msgid, NULL, srv, - NULL, 1 ); + 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, &bind ); } ldap_free_urldesc( ludp ); - return( err ); } @@ -542,22 +822,22 @@ ldap_url_search_s( } -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 - * 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 ) { 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; @@ -568,8 +848,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