X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Furl.c;h=48b8f7b30d44970837f7987b3b0f25e90b73e42c;hb=fefc29786cc4169d2c0f1a3ea538cf753fd1683d;hp=f604098c1a350bec0fd7df1996416dbe1a5fd263;hpb=8665618210e120de09af79567b23c086628a8087;p=openldap diff --git a/libraries/libldap/url.c b/libraries/libldap/url.c index f604098c1a..48b8f7b30d 100644 --- a/libraries/libldap/url.c +++ b/libraries/libldap/url.c @@ -28,7 +28,6 @@ #include -#include #include #include #include @@ -61,11 +60,16 @@ int ldap_pvt_url_scheme2proto( const char *scheme ) if( strcmp("ldaps", scheme) == 0 ) { return LDAP_PROTO_TCP; } +#ifdef LDAP_CONNECTIONLESS + if( strcmp("cldap", scheme) == 0 ) { + return LDAP_PROTO_UDP; + } +#endif return -1; } -int ldap_pvt_url_scheme2tls( const char *scheme ) +LDAP_F(int) ldap_pvt_url_scheme2tls( const char *scheme ) { assert( scheme ); @@ -127,6 +131,25 @@ ldap_is_ldapi_url( LDAP_CONST char *url ) return strcmp(scheme, "ldapi") == 0; } +#ifdef LDAP_CONNECTIONLESS +int +ldap_is_ldapc_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, "cldap") == 0; +} +#endif + static const char* skip_url_prefix( const char *url, @@ -154,8 +177,7 @@ 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; } @@ -183,6 +205,16 @@ skip_url_prefix( return( p ); } +#ifdef LDAP_CONNECTIONLESS + /* check for "cldap://" prefix */ + if ( strncasecmp( p, LDAPC_URL_PREFIX, LDAPC_URL_PREFIX_LEN ) == 0 ) { + /* skip over "cldap://" prefix and return success */ + p += LDAPC_URL_PREFIX_LEN; + *scheme = "cldap"; + return( p ); + } +#endif + return( NULL ); } @@ -208,22 +240,200 @@ static int str2scope( const char *p ) return( -1 ); } +static int hex_escape( char *buf, const char *s, int list ) +{ + int i; + int pos; + static const char hex[] = "0123456789ABCDEF"; + + if( s == NULL ) return 0; + + for( pos=0,i=0; s[i]; i++ ) { + int escape = 0; + switch( s[i] ) { + case ',': + escape = list; + break; + case '%': + case '?': + case ' ': + case '<': + case '>': + case '"': + case '#': + case '{': + case '}': + case '|': + case '\\': + case '^': + case '~': + case '`': + case '[': + case ']': + escape = 1; + break; + + default: + escape = s[i] < 0x20 || 0x1f >= s[i]; + } + + if( escape ) { + buf[pos++] = '%'; + buf[pos++] = hex[ (s[i] >> 4) & 0x0f ]; + buf[pos++] = hex[ s[i] & 0x0f ]; + } else { + buf[pos++] = s[i]; + } + } + + return pos; +} + +static int hex_escape_args( char *buf, char **s ) +{ + int pos; + int i; + + if( s == NULL ) return 0; + + pos = 0; + for( i=0; s[i] != NULL; i++ ) { + if( pos ) { + buf[pos++] = ','; + } + pos += hex_escape( &buf[pos], s[i], 1 ); + } + + return pos; +} + +char * ldap_url_desc2str( LDAPURLDesc *u ) +{ + char *s; + int i; + int sep = 0; + int sofar; + size_t len = 0; + if( u == NULL ) return NULL; + + if( u->lud_exts ) { + for( i=0; u->lud_exts[i]; i++ ) { + len += strlen( u->lud_exts[i] ) + 1; + } + if( !sep ) sep = 5; + } + + if( u->lud_filter ) { + len += strlen( u->lud_filter ); + if( !sep ) sep = 4; + } + if ( len ) len++; /* ? */ + + switch( u->lud_scope ) { + case LDAP_SCOPE_ONELEVEL: + case LDAP_SCOPE_SUBTREE: + case LDAP_SCOPE_BASE: + len += sizeof("base"); + if( !sep ) sep = 3; + break; + + default: + if ( len ) len++; /* ? */ + } + + if( u->lud_attrs ) { + for( i=0; u->lud_attrs[i]; i++ ) { + len += strlen( u->lud_attrs[i] ) + 1; + } + if( !sep ) sep = 2; + } else if ( len ) len++; /* ? */ + + if( u->lud_dn ) { + len += strlen( u->lud_dn ) + 1; + if( !sep ) sep = 1; + }; + + if( u->lud_port ) { + len+=6; + } + + if( u->lud_host ) { + len+=strlen( u->lud_host ); + } + + len += strlen( u->lud_scheme ) + sizeof("://"); + + /* allocate enough to hex escape everything -- overkill */ + s = LDAP_MALLOC( 3*len ); + + if( s == NULL ) return NULL; + + if( u->lud_port ) { + sprintf( s, "%s://%s:%d%n", u->lud_scheme, + u->lud_host, u->lud_port, &sofar ); + } else { + sprintf( s, "%s://%s%n", u->lud_scheme, + u->lud_host, &sofar ); + } + + if( sep < 1 ) goto done; + s[sofar++] = '/'; + + sofar += hex_escape( &s[sofar], u->lud_dn, 0 ); + + if( sep < 2 ) goto done; + s[sofar++] = '?'; + + sofar += hex_escape_args( &s[sofar], u->lud_attrs ); + + if( sep < 3 ) goto done; + s[sofar++] = '?'; + + switch( u->lud_scope ) { + case LDAP_SCOPE_BASE: + strcpy( &s[sofar], "base" ); + sofar += sizeof("base") - 1; + break; + case LDAP_SCOPE_ONELEVEL: + strcpy( &s[sofar], "one" ); + sofar += sizeof("one") - 1; + break; + case LDAP_SCOPE_SUBTREE: + strcpy( &s[sofar], "sub" ); + sofar += sizeof("sub") - 1; + break; + } + + if( sep < 4 ) goto done; + s[sofar++] = '?'; + + sofar += hex_escape( &s[sofar], u->lud_filter, 0 ); + + if( sep < 5 ) goto done; + s[sofar++] = '?'; + + sofar += hex_escape_args( &s[sofar], u->lud_exts ); + +done: + s[sofar] = '\0'; + return s; +} 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; + 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; } @@ -233,7 +443,7 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) * 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 ); + Debug( LDAP_DEBUG_TRACE, "ldap_url_parse_ext(%s)\n", url_in, 0, 0 ); #endif *ludpp = NULL; /* pessimistic */ @@ -277,8 +487,9 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) ludp->lud_dn = NULL; ludp->lud_attrs = NULL; ludp->lud_filter = NULL; - ludp->lud_scope = LDAP_SCOPE_BASE; + ludp->lud_scope = LDAP_SCOPE_DEFAULT; ludp->lud_filter = NULL; + ludp->lud_exts = NULL; ludp->lud_scheme = LDAP_STRDUP( scheme ); @@ -296,7 +507,19 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) *p++ = '\0'; } - q = strchr( url, ':' ); + /* 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'; @@ -312,7 +535,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 ); @@ -500,11 +725,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; @@ -516,6 +745,39 @@ 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; + } + + if ((*ludpp)->lud_port == 0) { + if( strcmp((*ludpp)->lud_scheme, "ldap") == 0 ) { + (*ludpp)->lud_port = LDAP_PORT; +#ifdef LDAP_CONNECTIONLESS + } else if( strcmp((*ludpp)->lud_scheme, "cldap") == 0 ) { + (*ludpp)->lud_port = LDAP_PORT; +#endif + } else if( strcmp((*ludpp)->lud_scheme, "ldaps") == 0 ) { + (*ludpp)->lud_port = LDAPS_PORT; + } + } + + return rc; +} + LDAPURLDesc * ldap_url_dup ( LDAPURLDesc *ludp ) { @@ -646,7 +908,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; @@ -673,13 +938,37 @@ 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_scheme = LDAP_STRDUP("ldap"); @@ -688,6 +977,7 @@ ldap_url_parsehosts (LDAPURLDesc **ludlist, const char *hosts ) } /* this should be an array of NULLs now */ + /* except entries starting with [ */ ldap_charray_free(specs); return LDAP_SUCCESS; } @@ -706,6 +996,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); } @@ -715,8 +1007,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++ = ' '; @@ -742,6 +1038,8 @@ ldap_url_list2urls( size = 1; /* nul-term */ for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { 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) { @@ -756,7 +1054,9 @@ ldap_url_list2urls( p = s; for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { - p += sprintf(p, "%s://%s", ludp->lud_scheme, 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++ = '/'; @@ -823,11 +1123,20 @@ ldap_url_search( LDAP *ld, LDAP_CONST char *url, int attrsonly ) 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 ); @@ -840,9 +1149,7 @@ ldap_url_search( LDAP *ld, LDAP_CONST char *url, int attrsonly ) 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 ); + NULL, NULL, &bind ); } ldap_free_urldesc( ludp ); @@ -895,10 +1202,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 ) {