-/* LIBLDAP url.c -- LDAP URL (RFC 2255) related routines */
+/* LIBLDAP url.c -- LDAP URL (RFC 4516) related routines */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 1998-2006 The OpenLDAP Foundation.
+ * Copyright 1998-2007 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
/*
* LDAP URLs look like this:
- * ldap[is]://host:port[/[dn[?[attributes][?[scope][?[filter][?exts]]]]]]
+ * ldap[is]://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 2254
+ * filter is an string-represented filter as in RFC 4515
*
* e.g., ldap://host:port/dc=com?o,cn?base?(o=openldap)?extension
*
return( NULL );
}
-
-static int str2scope( const char *p )
+int
+ldap_pvt_scope2bv( int scope, struct berval *bv )
{
- if ( strcasecmp( p, "one" ) == 0 ) {
- return LDAP_SCOPE_ONELEVEL;
+ switch ( scope ) {
+ case LDAP_SCOPE_BASE:
+ BER_BVSTR( bv, "base" );
+ break;
+
+ case LDAP_SCOPE_ONELEVEL:
+ BER_BVSTR( bv, "one" );
+ break;
+
+ case LDAP_SCOPE_SUBTREE:
+ BER_BVSTR( bv, "sub" );
+ break;
+
+ case LDAP_SCOPE_SUBORDINATE:
+ BER_BVSTR( bv, "subordinate" );
+ break;
+
+ default:
+ return LDAP_OTHER;
+ }
- } else if ( strcasecmp( p, "onelevel" ) == 0 ) {
- return LDAP_SCOPE_ONELEVEL;
+ return LDAP_SUCCESS;
+}
- } else if ( strcasecmp( p, "base" ) == 0 ) {
- return LDAP_SCOPE_BASE;
+const char *
+ldap_pvt_scope2str( int scope )
+{
+ struct berval bv;
- } else if ( strcasecmp( p, "sub" ) == 0 ) {
- return LDAP_SCOPE_SUBTREE;
+ if ( ldap_pvt_scope2bv( scope, &bv ) == LDAP_SUCCESS ) {
+ return bv.bv_val;
+ }
- } else if ( strcasecmp( p, "subtree" ) == 0 ) {
- return LDAP_SCOPE_SUBTREE;
+ return NULL;
+}
- } else if ( strcasecmp( p, "subordinate" ) == 0 ) {
- return LDAP_SCOPE_SUBORDINATE;
+int
+ldap_pvt_bv2scope( struct berval *bv )
+{
+ static struct {
+ struct berval bv;
+ int scope;
+ } v[] = {
+ { BER_BVC( "one" ), LDAP_SCOPE_ONELEVEL },
+ { BER_BVC( "onelevel" ), LDAP_SCOPE_ONELEVEL },
+ { BER_BVC( "base" ), LDAP_SCOPE_BASE },
+ { BER_BVC( "sub" ), LDAP_SCOPE_SUBTREE },
+ { BER_BVC( "subtree" ), LDAP_SCOPE_SUBTREE },
+ { BER_BVC( "subord" ), LDAP_SCOPE_SUBORDINATE },
+ { BER_BVC( "subordinate" ), LDAP_SCOPE_SUBORDINATE },
+ { BER_BVC( "children" ), LDAP_SCOPE_SUBORDINATE },
+ { BER_BVNULL, -1 }
+ };
+ int i;
- } else if ( strcasecmp( p, "children" ) == 0 ) {
- return LDAP_SCOPE_SUBORDINATE;
+ for ( i = 0; v[ i ].scope != -1; i++ ) {
+ if ( ber_bvstrcasecmp( bv, &v[ i ].bv ) == 0 ) {
+ return v[ i ].scope;
+ }
}
return( -1 );
}
+int
+ldap_pvt_str2scope( const char *p )
+{
+ struct berval bv;
+
+ ber_str2bv( p, 0, 0, &bv );
+
+ return ldap_pvt_bv2scope( &bv );
+}
+
static const char hex[] = "0123456789ABCDEF";
#define URLESC_NONE 0x0000U
static int
desc2str_len( LDAPURLDesc *u )
{
- int sep = 0;
- int len = 0;
+ int sep = 0;
+ int len = 0;
+ int is_ipc = 0;
+ struct berval scope;
- if ( u == NULL ) {
+ if ( u == NULL || u->lud_scheme == NULL ) {
return -1;
}
+ if ( !strcmp( "ldapi", u->lud_scheme )) {
+ is_ipc = 1;
+ }
+
if ( u->lud_exts ) {
len += hex_escape_len_list( u->lud_exts, URLESC_COMMA );
if ( !sep ) {
}
if ( u->lud_filter ) {
- len += hex_escape_len( u->lud_filter, URLESC_NONE );
+ len += hex_escape_len( u->lud_filter, URLESC_NONE );
if ( !sep ) {
sep = 4;
}
}
- switch ( u->lud_scope ) {
- case LDAP_SCOPE_BASE:
- case LDAP_SCOPE_ONELEVEL:
- case LDAP_SCOPE_SUBTREE:
- case LDAP_SCOPE_SUBORDINATE:
- switch ( u->lud_scope ) {
- case LDAP_SCOPE_BASE:
- len += STRLENOF( "base" );
- break;
-
- case LDAP_SCOPE_ONELEVEL:
- len += STRLENOF( "one" );
- break;
-
- case LDAP_SCOPE_SUBTREE:
- len += STRLENOF( "sub" );
- break;
-
- case LDAP_SCOPE_SUBORDINATE:
- len += STRLENOF( "subordinate" );
- break;
- }
-
+ if ( ldap_pvt_scope2bv( u->lud_scope, &scope ) == LDAP_SUCCESS ) {
+ len += scope.bv_len;
if ( !sep ) {
sep = 3;
}
- break;
-
- default:
- break;
}
if ( u->lud_attrs ) {
- len += hex_escape_len_list( u->lud_attrs, URLESC_NONE );
+ len += hex_escape_len_list( u->lud_attrs, URLESC_NONE );
if ( !sep ) {
sep = 2;
}
len += sep;
if ( u->lud_port ) {
- char buf[] = ":65535";
+ unsigned p = u->lud_port;
+ if ( p > 65535 )
+ return -1;
- len += snprintf( buf, sizeof( buf ), ":%d", u->lud_port );
- if ( u->lud_host && u->lud_host[0] ) {
- len += strlen( u->lud_host );
- }
+ len += (p > 999 ? 5 + (p > 9999) : p > 99 ? 4 : 2 + (p > 9));
+ }
- } else {
- if ( u->lud_host && u->lud_host[0] ) {
- len += hex_escape_len( u->lud_host, URLESC_SLASH );
+ if ( u->lud_host && u->lud_host[0] ) {
+ len += hex_escape_len( u->lud_host, URLESC_SLASH );
+ if ( !is_ipc && strchr( u->lud_host, ':' )) {
+ len += 2; /* IPv6, [] */
}
}
return len;
}
-int
+static int
desc2str( LDAPURLDesc *u, char *s, int len )
{
- int i;
- int sep = 0;
- int sofar = 0;
- int gotscope = 0;
+ int i;
+ int sep = 0;
+ int sofar = 0;
+ int is_v6 = 0;
+ int is_ipc = 0;
+ struct berval scope = BER_BVNULL;
if ( u == NULL ) {
return -1;
return -1;
}
- switch ( u->lud_scope ) {
- case LDAP_SCOPE_BASE:
- case LDAP_SCOPE_ONELEVEL:
- case LDAP_SCOPE_SUBTREE:
- case LDAP_SCOPE_SUBORDINATE:
- gotscope = 1;
- break;
+ if ( u->lud_scheme && !strcmp( "ldapi", u->lud_scheme )) {
+ is_ipc = 1;
}
+ ldap_pvt_scope2bv( u->lud_scope, &scope );
+
if ( u->lud_exts ) {
sep = 5;
} else if ( u->lud_filter ) {
sep = 4;
- } else if ( gotscope ) {
+ } else if ( !BER_BVISEMPTY( &scope ) ) {
sep = 3;
} else if ( u->lud_attrs ) {
sep = 2;
sep = 1;
}
+ if ( !is_ipc && u->lud_host && strchr( u->lud_host, ':' )) {
+ is_v6 = 1;
+ }
+
if ( u->lud_port ) {
- len -= sprintf( s, "%s://%s:%d%n", u->lud_scheme,
+ len -= sprintf( s, "%s://%s%s%s:%d%n", u->lud_scheme,
+ is_v6 ? "[" : "",
u->lud_host ? u->lud_host : "",
+ is_v6 ? "]" : "",
u->lud_port, &sofar );
} else {
len -= sprintf( s, "%s://%n", u->lud_scheme, &sofar );
if ( u->lud_host && u->lud_host[0] ) {
+ if ( is_v6 ) {
+ s[sofar++] = '[';
+ len--;
+ }
i = hex_escape( &s[sofar], len, u->lud_host, URLESC_SLASH );
sofar += i;
len -= i;
+ if ( is_v6 ) {
+ s[sofar++] = ']';
+ len--;
+ }
}
}
assert( len >= 0 );
- switch ( u->lud_scope ) {
- case LDAP_SCOPE_BASE:
- strcpy( &s[sofar], "base" );
- sofar += STRLENOF("base");
- len -= STRLENOF("base");
- break;
-
- case LDAP_SCOPE_ONELEVEL:
- strcpy( &s[sofar], "one" );
- sofar += STRLENOF("one");
- len -= STRLENOF("one");
- break;
-
- case LDAP_SCOPE_SUBTREE:
- strcpy( &s[sofar], "sub" );
- sofar += STRLENOF("sub");
- len -= STRLENOF("sub");
- break;
-
- case LDAP_SCOPE_SUBORDINATE:
- strcpy( &s[sofar], "children" );
- sofar += STRLENOF("children");
- len -= STRLENOF("children");
- break;
+ if ( !BER_BVISNULL( &scope ) ) {
+ strcpy( &s[sofar], scope.bv_val );
+ sofar += scope.bv_len;
+ len -= scope.bv_len;
}
assert( len >= 0 );
LDAPURLDesc *ludp;
char *p, *q, *r;
- int i, enclosed;
+ int i, enclosed, proto, is_v6 = 0;
const char *scheme = NULL;
const char *url_tmp;
char *url;
assert( scheme != NULL );
+ proto = ldap_pvt_url_scheme2proto( scheme );
+ if ( proto == -1 ) {
+ return LDAP_URL_ERR_BADSCHEME;
+ }
+
/* make working copy of the remainder of the URL */
url = LDAP_STRDUP( url_tmp );
if ( url == NULL ) {
/* scan forward for '/' that marks end of hostport and begin. of dn */
p = strchr( url, '/' );
+ q = NULL;
if( p != NULL ) {
/* terminate hostport; point to start of dn */
*p++ = '\0';
+ } else {
+ /* check for Novell kludge, see below */
+ p = strchr( url, '?' );
+ if ( p ) {
+ *p++ = '\0';
+ q = p;
+ p = 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;
+ if ( proto != LDAP_PROTO_IPC ) {
+ /* 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, ':' );
+ if ( q && q != r ) {
+ LDAP_FREE( url );
+ ldap_free_urldesc( ludp );
+ return LDAP_URL_ERR_BADURL;
+ }
+ is_v6 = 1;
+ } else {
+ q = strchr( url, ':' );
}
- *r++ = '\0';
- q = strchr( r, ':' );
- } else {
- q = strchr( url, ':' );
- }
- if ( q != NULL ) {
- char *next;
+ if ( q != NULL ) {
+ char *next;
- *q++ = '\0';
- ldap_pvt_hex_unescape( q );
+ *q++ = '\0';
+ ldap_pvt_hex_unescape( q );
- if( *q == '\0' ) {
- LDAP_FREE( url );
- ldap_free_urldesc( ludp );
- return LDAP_URL_ERR_BADURL;
- }
+ if( *q == '\0' ) {
+ LDAP_FREE( url );
+ ldap_free_urldesc( ludp );
+ return LDAP_URL_ERR_BADURL;
+ }
- ludp->lud_port = strtol( q, &next, 10 );
- if ( next == q || next[0] != '\0' ) {
- LDAP_FREE( url );
- ldap_free_urldesc( ludp );
- return LDAP_URL_ERR_BADURL;
+ ludp->lud_port = strtol( q, &next, 10 );
+ if ( next == q || next[0] != '\0' ) {
+ LDAP_FREE( url );
+ ldap_free_urldesc( ludp );
+ return LDAP_URL_ERR_BADURL;
+ }
+ /* check for Novell kludge */
+ if ( !p ) {
+ if ( *next != '\0' ) {
+ q = &next[1];
+ } else {
+ q = NULL;
+ }
+ }
}
- }
- if ( ( flags & LDAP_PVT_URL_PARSE_DEF_PORT ) && ludp->lud_port == 0 ) {
- if ( strcmp( ludp->lud_scheme, "ldap" ) == 0 ) {
- ludp->lud_port = LDAP_PORT;
-#ifdef LDAP_CONNECTIONLESS
- } else if ( strcmp( ludp->lud_scheme, "cldap" ) == 0 ) {
- ludp->lud_port = LDAP_PORT;
-#endif
- } else if ( strcmp( ludp->lud_scheme, "ldaps" ) == 0 ) {
- ludp->lud_port = LDAPS_PORT;
+ if ( ( flags & LDAP_PVT_URL_PARSE_DEF_PORT ) && ludp->lud_port == 0 ) {
+ if ( strcmp( ludp->lud_scheme, "ldaps" ) == 0 ) {
+ ludp->lud_port = LDAPS_PORT;
+ } else {
+ ludp->lud_port = LDAP_PORT;
+ }
}
}
ldap_pvt_hex_unescape( url );
/* If [ip address]:port syntax, url is [ip and we skip the [ */
- ludp->lud_host = LDAP_STRDUP( url + ( *url == '[' ) );
+ ludp->lud_host = LDAP_STRDUP( url + is_v6 );
if( ludp->lud_host == NULL ) {
LDAP_FREE( url );
* 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++;
+ if( (p == NULL) && (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 );
+ q++;
+ if( *q != '\0' ) {
+ /* parse dn part */
+ ldap_pvt_hex_unescape( q );
+ ludp->lud_dn = LDAP_STRDUP( q );
- } else if ( !( flags & LDAP_PVT_URL_PARSE_NOEMPTY_DN ) ) {
- ludp->lud_dn = LDAP_STRDUP( "" );
+ } else if ( !( flags & LDAP_PVT_URL_PARSE_NOEMPTY_DN ) ) {
+ ludp->lud_dn = LDAP_STRDUP( "" );
- } else {
- check_dn = 0;
- }
+ } else {
+ check_dn = 0;
+ }
- if ( check_dn && ludp->lud_dn == NULL ) {
- LDAP_FREE( url );
- ldap_free_urldesc( ludp );
- return LDAP_URL_ERR_MEM;
- }
+ if ( check_dn && ludp->lud_dn == NULL ) {
+ LDAP_FREE( url );
+ ldap_free_urldesc( ludp );
+ return LDAP_URL_ERR_MEM;
}
}
if( *p != '\0' ) {
/* parse the scope */
ldap_pvt_hex_unescape( p );
- ludp->lud_scope = str2scope( p );
+ ludp->lud_scope = ldap_pvt_str2scope( p );
if( ludp->lud_scope == -1 ) {
LDAP_FREE( url );