1
/* LIBLDAP url.c -- LDAP URL (RFC 4516) related routines */
2
/* $OpenLDAP: pkg/ldap/libraries/libldap/url.c,v 1.94.2.10 2009/01/22 00:00:56 kurt Exp $ */
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5
* Copyright 1998-2009 The OpenLDAP Foundation.
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted only as authorized by the OpenLDAP
12
* A copy of this license is available in the file LICENSE in the
13
* top-level directory of the distribution or, alternatively, at
14
* <http://www.OpenLDAP.org/license.html>.
16
/* Portions Copyright (c) 1996 Regents of the University of Michigan.
17
* All rights reserved.
22
* LDAP URLs look like this:
23
* ldap[is]://host[:port][/[dn[?[attributes][?[scope][?[filter][?exts]]]]]]
26
* attributes is a comma separated list
27
* scope is one of these three strings: base one sub (default=base)
28
* filter is an string-represented filter as in RFC 4515
30
* e.g., ldap://host:port/dc=com?o,cn?base?(o=openldap)?extension
32
* We also tolerate URLs that look like: <ldapurl> and <URL:ldapurl>
39
#include <ac/stdlib.h>
42
#include <ac/socket.h>
43
#include <ac/string.h>
49
static const char* skip_url_prefix LDAP_P((
52
const char **scheme ));
54
int ldap_pvt_url_scheme2proto( const char *scheme )
56
assert( scheme != NULL );
58
if( scheme == NULL ) {
62
if( strcmp("ldap", scheme) == 0 ) {
63
return LDAP_PROTO_TCP;
66
if( strcmp("ldapi", scheme) == 0 ) {
67
return LDAP_PROTO_IPC;
70
if( strcmp("ldaps", scheme) == 0 ) {
71
return LDAP_PROTO_TCP;
73
#ifdef LDAP_CONNECTIONLESS
74
if( strcmp("cldap", scheme) == 0 ) {
75
return LDAP_PROTO_UDP;
82
int ldap_pvt_url_scheme_port( const char *scheme, int port )
84
assert( scheme != NULL );
86
if( port ) return port;
87
if( scheme == NULL ) return port;
89
if( strcmp("ldap", scheme) == 0 ) {
93
if( strcmp("ldapi", scheme) == 0 ) {
97
if( strcmp("ldaps", scheme) == 0 ) {
101
#ifdef LDAP_CONNECTIONLESS
102
if( strcmp("cldap", scheme) == 0 ) {
111
ldap_pvt_url_scheme2tls( const char *scheme )
113
assert( scheme != NULL );
115
if( scheme == NULL ) {
119
return strcmp("ldaps", scheme) == 0;
123
ldap_is_ldap_url( LDAP_CONST char *url )
132
if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) {
140
ldap_is_ldaps_url( LDAP_CONST char *url )
149
if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) {
153
return strcmp(scheme, "ldaps") == 0;
157
ldap_is_ldapi_url( LDAP_CONST char *url )
166
if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) {
170
return strcmp(scheme, "ldapi") == 0;
173
#ifdef LDAP_CONNECTIONLESS
175
ldap_is_ldapc_url( LDAP_CONST char *url )
184
if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) {
188
return strcmp(scheme, "cldap") == 0;
196
const char **scheme )
199
* return non-zero if this looks like a LDAP URL; zero if not
200
* if non-zero returned, *urlp will be moved past "ldap://" part of URL
210
/* skip leading '<' (if any) */
218
/* skip leading "URL:" (if any) */
219
if ( strncasecmp( p, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) {
220
p += LDAP_URL_URLCOLON_LEN;
223
/* check for "ldap://" prefix */
224
if ( strncasecmp( p, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) == 0 ) {
225
/* skip over "ldap://" prefix and return success */
226
p += LDAP_URL_PREFIX_LEN;
231
/* check for "ldaps://" prefix */
232
if ( strncasecmp( p, LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) {
233
/* skip over "ldaps://" prefix and return success */
234
p += LDAPS_URL_PREFIX_LEN;
239
/* check for "ldapi://" prefix */
240
if ( strncasecmp( p, LDAPI_URL_PREFIX, LDAPI_URL_PREFIX_LEN ) == 0 ) {
241
/* skip over "ldapi://" prefix and return success */
242
p += LDAPI_URL_PREFIX_LEN;
247
#ifdef LDAP_CONNECTIONLESS
248
/* check for "cldap://" prefix */
249
if ( strncasecmp( p, LDAPC_URL_PREFIX, LDAPC_URL_PREFIX_LEN ) == 0 ) {
250
/* skip over "cldap://" prefix and return success */
251
p += LDAPC_URL_PREFIX_LEN;
261
ldap_pvt_scope2bv( int scope, struct berval *bv )
264
case LDAP_SCOPE_BASE:
265
BER_BVSTR( bv, "base" );
268
case LDAP_SCOPE_ONELEVEL:
269
BER_BVSTR( bv, "one" );
272
case LDAP_SCOPE_SUBTREE:
273
BER_BVSTR( bv, "sub" );
276
case LDAP_SCOPE_SUBORDINATE:
277
BER_BVSTR( bv, "subordinate" );
288
ldap_pvt_scope2str( int scope )
292
if ( ldap_pvt_scope2bv( scope, &bv ) == LDAP_SUCCESS ) {
300
ldap_pvt_bv2scope( struct berval *bv )
306
{ BER_BVC( "one" ), LDAP_SCOPE_ONELEVEL },
307
{ BER_BVC( "onelevel" ), LDAP_SCOPE_ONELEVEL },
308
{ BER_BVC( "base" ), LDAP_SCOPE_BASE },
309
{ BER_BVC( "sub" ), LDAP_SCOPE_SUBTREE },
310
{ BER_BVC( "subtree" ), LDAP_SCOPE_SUBTREE },
311
{ BER_BVC( "subord" ), LDAP_SCOPE_SUBORDINATE },
312
{ BER_BVC( "subordinate" ), LDAP_SCOPE_SUBORDINATE },
313
{ BER_BVC( "children" ), LDAP_SCOPE_SUBORDINATE },
318
for ( i = 0; v[ i ].scope != -1; i++ ) {
319
if ( ber_bvstrcasecmp( bv, &v[ i ].bv ) == 0 ) {
328
ldap_pvt_str2scope( const char *p )
332
ber_str2bv( p, 0, 0, &bv );
334
return ldap_pvt_bv2scope( &bv );
337
static const char hex[] = "0123456789ABCDEF";
339
#define URLESC_NONE 0x0000U
340
#define URLESC_COMMA 0x0001U
341
#define URLESC_SLASH 0x0002U
344
hex_escape_len( const char *s, unsigned list )
352
for ( len = 0; s[0]; s++ ) {
354
/* RFC 2396: reserved */
360
if ( list & URLESC_COMMA ) {
368
if ( list & URLESC_SLASH ) {
383
/* RFC 2396: unreserved mark */
396
/* RFC 2396: unreserved alphanum */
398
if ( !isalnum( (unsigned char) s[0] ) ) {
411
hex_escape( char *buf, int len, const char *s, unsigned list )
420
for ( pos = 0, i = 0; s[i] && pos < len; i++ ) {
424
/* RFC 2396: reserved */
430
if ( list & URLESC_COMMA ) {
436
if ( list & URLESC_SLASH ) {
449
/* RFC 2396: unreserved mark */
461
/* RFC 2396: unreserved alphanum */
463
if ( !isalnum( (unsigned char) s[i] ) ) {
471
buf[pos++] = hex[ (s[i] >> 4) & 0x0f ];
472
buf[pos++] = hex[ s[i] & 0x0f ];
485
hex_escape_len_list( char **s, unsigned flags )
495
for ( i = 0; s[i] != NULL; i++ ) {
499
len += hex_escape_len( s[i], flags );
506
hex_escape_list( char *buf, int len, char **s, unsigned flags )
516
for ( i = 0; s[i] != NULL; i++ ) {
523
curlen = hex_escape( &buf[pos], len, s[i], flags );
532
desc2str_len( LDAPURLDesc *u )
539
if ( u == NULL || u->lud_scheme == NULL ) {
543
if ( !strcmp( "ldapi", u->lud_scheme )) {
548
len += hex_escape_len_list( u->lud_exts, URLESC_COMMA );
554
if ( u->lud_filter ) {
555
len += hex_escape_len( u->lud_filter, URLESC_NONE );
561
if ( ldap_pvt_scope2bv( u->lud_scope, &scope ) == LDAP_SUCCESS ) {
568
if ( u->lud_attrs ) {
569
len += hex_escape_len_list( u->lud_attrs, URLESC_NONE );
575
if ( u->lud_dn && u->lud_dn[0] ) {
576
len += hex_escape_len( u->lud_dn, URLESC_NONE );
585
unsigned p = u->lud_port;
589
len += (p > 999 ? 5 + (p > 9999) : p > 99 ? 4 : 2 + (p > 9));
592
if ( u->lud_host && u->lud_host[0] ) {
594
len += hex_escape_len( u->lud_host, URLESC_SLASH );
595
if ( !is_ipc && ( ptr = strchr( u->lud_host, ':' ))) {
596
if ( strchr( ptr+1, ':' ))
597
len += 2; /* IPv6, [] */
601
len += strlen( u->lud_scheme ) + STRLENOF( "://" );
607
desc2str( LDAPURLDesc *u, char *s, int len )
614
struct berval scope = BER_BVNULL;
625
if ( u->lud_scheme && !strcmp( "ldapi", u->lud_scheme )) {
629
ldap_pvt_scope2bv( u->lud_scope, &scope );
633
} else if ( u->lud_filter ) {
635
} else if ( !BER_BVISEMPTY( &scope ) ) {
637
} else if ( u->lud_attrs ) {
639
} else if ( u->lud_dn && u->lud_dn[0] ) {
643
if ( !is_ipc && u->lud_host && ( ptr = strchr( u->lud_host, ':' ))) {
644
if ( strchr( ptr+1, ':' ))
649
sofar = sprintf( s, "%s://%s%s%s:%d", u->lud_scheme,
651
u->lud_host ? u->lud_host : "",
657
sofar = sprintf( s, "%s://", u->lud_scheme );
659
if ( u->lud_host && u->lud_host[0] ) {
664
i = hex_escape( &s[sofar], len, u->lud_host, URLESC_SLASH );
685
if ( u->lud_dn && u->lud_dn[0] ) {
686
i = hex_escape( &s[sofar], len, u->lud_dn, URLESC_NONE );
701
i = hex_escape_list( &s[sofar], len, u->lud_attrs, URLESC_NONE );
715
if ( !BER_BVISNULL( &scope ) ) {
716
strcpy( &s[sofar], scope.bv_val );
717
sofar += scope.bv_len;
731
i = hex_escape( &s[sofar], len, u->lud_filter, URLESC_NONE );
745
i = hex_escape_list( &s[sofar], len, u->lud_exts, URLESC_COMMA );
760
ldap_url_desc2str( LDAPURLDesc *u )
769
len = desc2str_len( u );
774
/* allocate enough to hex escape everything -- overkill */
775
s = LDAP_MALLOC( len + 1 );
781
if ( desc2str( u, s, len ) != len ) {
792
ldap_url_parse_ext( LDAP_CONST char *url_in, LDAPURLDesc **ludpp, unsigned flags )
795
* Pick apart the pieces of an LDAP URL.
800
int i, enclosed, proto, is_v6 = 0;
801
const char *scheme = NULL;
807
if( url_in == NULL || ludpp == NULL ) {
808
return LDAP_URL_ERR_PARAM;
811
#ifndef LDAP_INT_IN_KERNEL
812
/* Global options may not be created yet
813
* We can't test if the global options are initialized
814
* because a call to LDAP_INT_GLOBAL_OPT() will try to allocate
815
* the options and cause infinite recursion
817
Debug( LDAP_DEBUG_TRACE, "ldap_url_parse_ext(%s)\n", url_in, 0, 0 );
820
*ludpp = NULL; /* pessimistic */
822
url_tmp = skip_url_prefix( url_in, &enclosed, &scheme );
824
if ( url_tmp == NULL ) {
825
return LDAP_URL_ERR_BADSCHEME;
828
assert( scheme != NULL );
830
proto = ldap_pvt_url_scheme2proto( scheme );
832
return LDAP_URL_ERR_BADSCHEME;
835
/* make working copy of the remainder of the URL */
836
url = LDAP_STRDUP( url_tmp );
838
return LDAP_URL_ERR_MEM;
842
p = &url[strlen(url)-1];
846
return LDAP_URL_ERR_BADENCLOSURE;
852
/* allocate return struct */
853
ludp = (LDAPURLDesc *)LDAP_CALLOC( 1, sizeof( LDAPURLDesc ));
855
if ( ludp == NULL ) {
857
return LDAP_URL_ERR_MEM;
860
ludp->lud_next = NULL;
861
ludp->lud_host = NULL;
864
ludp->lud_attrs = NULL;
865
ludp->lud_scope = ( flags & LDAP_PVT_URL_PARSE_NODEF_SCOPE ) ? LDAP_SCOPE_BASE : LDAP_SCOPE_DEFAULT;
866
ludp->lud_filter = NULL;
867
ludp->lud_exts = NULL;
869
ludp->lud_scheme = LDAP_STRDUP( scheme );
871
if ( ludp->lud_scheme == NULL ) {
873
ldap_free_urldesc( ludp );
874
return LDAP_URL_ERR_MEM;
877
/* scan forward for '/' that marks end of hostport and begin. of dn */
878
p = strchr( url, '/' );
882
/* terminate hostport; point to start of dn */
885
/* check for Novell kludge, see below */
886
p = strchr( url, '?' );
894
if ( proto != LDAP_PROTO_IPC ) {
895
/* IPv6 syntax with [ip address]:port */
897
r = strchr( url, ']' );
900
ldap_free_urldesc( ludp );
901
return LDAP_URL_ERR_BADURL;
904
q = strchr( r, ':' );
907
ldap_free_urldesc( ludp );
908
return LDAP_URL_ERR_BADURL;
912
q = strchr( url, ':' );
919
ldap_pvt_hex_unescape( q );
923
ldap_free_urldesc( ludp );
924
return LDAP_URL_ERR_BADURL;
927
ludp->lud_port = strtol( q, &next, 10 );
928
if ( next == q || next[0] != '\0' ) {
930
ldap_free_urldesc( ludp );
931
return LDAP_URL_ERR_BADURL;
933
/* check for Novell kludge */
935
if ( *next != '\0' ) {
943
if ( ( flags & LDAP_PVT_URL_PARSE_DEF_PORT ) && ludp->lud_port == 0 ) {
944
if ( strcmp( ludp->lud_scheme, "ldaps" ) == 0 ) {
945
ludp->lud_port = LDAPS_PORT;
947
ludp->lud_port = LDAP_PORT;
952
ldap_pvt_hex_unescape( url );
954
/* If [ip address]:port syntax, url is [ip and we skip the [ */
955
ludp->lud_host = LDAP_STRDUP( url + is_v6 );
957
if( ludp->lud_host == NULL ) {
959
ldap_free_urldesc( ludp );
960
return LDAP_URL_ERR_MEM;
963
if ( ( flags & LDAP_PVT_URL_PARSE_NOEMPTY_HOST )
964
&& ludp->lud_host != NULL
965
&& *ludp->lud_host == '\0' )
967
LDAP_FREE( ludp->lud_host );
968
ludp->lud_host = NULL;
972
* Kludge. ldap://111.222.333.444:389??cn=abc,o=company
974
* On early Novell releases, search references/referrals were returned
975
* in this format, i.e., the dn was kind of in the scope position,
976
* but the required slash is missing. The whole thing is illegal syntax,
977
* but we need to account for it. Fortunately it can't be confused with
980
if( (p == NULL) && (q != NULL) && (*q == '?') ) {
981
/* ? immediately followed by question */
985
ldap_pvt_hex_unescape( q );
986
ludp->lud_dn = LDAP_STRDUP( q );
988
} else if ( !( flags & LDAP_PVT_URL_PARSE_NOEMPTY_DN ) ) {
989
ludp->lud_dn = LDAP_STRDUP( "" );
995
if ( check_dn && ludp->lud_dn == NULL ) {
997
ldap_free_urldesc( ludp );
998
return LDAP_URL_ERR_MEM;
1005
return LDAP_URL_SUCCESS;
1008
/* scan forward for '?' that may marks end of dn */
1009
q = strchr( p, '?' );
1012
/* terminate dn part */
1018
ldap_pvt_hex_unescape( p );
1019
ludp->lud_dn = LDAP_STRDUP( p );
1021
} else if ( !( flags & LDAP_PVT_URL_PARSE_NOEMPTY_DN ) ) {
1022
ludp->lud_dn = LDAP_STRDUP( "" );
1028
if( check_dn && ludp->lud_dn == NULL ) {
1030
ldap_free_urldesc( ludp );
1031
return LDAP_URL_ERR_MEM;
1038
return LDAP_URL_SUCCESS;
1041
/* scan forward for '?' that may marks end of attributes */
1043
q = strchr( p, '?' );
1046
/* terminate attributes part */
1051
/* parse attributes */
1052
ldap_pvt_hex_unescape( p );
1053
ludp->lud_attrs = ldap_str2charray( p, "," );
1055
if( ludp->lud_attrs == NULL ) {
1057
ldap_free_urldesc( ludp );
1058
return LDAP_URL_ERR_BADATTRS;
1066
return LDAP_URL_SUCCESS;
1069
/* scan forward for '?' that may marks end of scope */
1071
q = strchr( p, '?' );
1074
/* terminate the scope part */
1079
/* parse the scope */
1080
ldap_pvt_hex_unescape( p );
1081
ludp->lud_scope = ldap_pvt_str2scope( p );
1083
if( ludp->lud_scope == -1 ) {
1085
ldap_free_urldesc( ludp );
1086
return LDAP_URL_ERR_BADSCOPE;
1094
return LDAP_URL_SUCCESS;
1097
/* scan forward for '?' that may marks end of filter */
1099
q = strchr( p, '?' );
1102
/* terminate the filter part */
1107
/* parse the filter */
1108
ldap_pvt_hex_unescape( p );
1111
/* missing filter */
1113
ldap_free_urldesc( ludp );
1114
return LDAP_URL_ERR_BADFILTER;
1117
ludp->lud_filter = LDAP_STRDUP( p );
1119
if( ludp->lud_filter == NULL ) {
1121
ldap_free_urldesc( ludp );
1122
return LDAP_URL_ERR_MEM;
1130
return LDAP_URL_SUCCESS;
1133
/* scan forward for '?' that may marks end of extensions */
1135
q = strchr( p, '?' );
1140
ldap_free_urldesc( ludp );
1141
return LDAP_URL_ERR_BADURL;
1144
/* parse the extensions */
1145
ludp->lud_exts = ldap_str2charray( p, "," );
1147
if( ludp->lud_exts == NULL ) {
1149
ldap_free_urldesc( ludp );
1150
return LDAP_URL_ERR_BADEXTS;
1153
for( i=0; ludp->lud_exts[i] != NULL; i++ ) {
1154
ldap_pvt_hex_unescape( ludp->lud_exts[i] );
1156
if( *ludp->lud_exts[i] == '!' ) {
1157
/* count the number of critical extensions */
1158
ludp->lud_crit_exts++;
1163
/* must have 1 or more */
1165
ldap_free_urldesc( ludp );
1166
return LDAP_URL_ERR_BADEXTS;
1172
return LDAP_URL_SUCCESS;
1176
ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp )
1178
return ldap_url_parse_ext( url_in, ludpp, LDAP_PVT_URL_PARSE_HISTORIC );
1182
ldap_url_dup ( LDAPURLDesc *ludp )
1186
if ( ludp == NULL ) {
1190
dest = LDAP_MALLOC( sizeof(LDAPURLDesc) );
1195
dest->lud_scheme = NULL;
1196
dest->lud_host = NULL;
1197
dest->lud_dn = NULL;
1198
dest->lud_filter = NULL;
1199
dest->lud_attrs = NULL;
1200
dest->lud_exts = NULL;
1201
dest->lud_next = NULL;
1203
if ( ludp->lud_scheme != NULL ) {
1204
dest->lud_scheme = LDAP_STRDUP( ludp->lud_scheme );
1205
if (dest->lud_scheme == NULL) {
1206
ldap_free_urldesc(dest);
1211
if ( ludp->lud_host != NULL ) {
1212
dest->lud_host = LDAP_STRDUP( ludp->lud_host );
1213
if (dest->lud_host == NULL) {
1214
ldap_free_urldesc(dest);
1219
if ( ludp->lud_dn != NULL ) {
1220
dest->lud_dn = LDAP_STRDUP( ludp->lud_dn );
1221
if (dest->lud_dn == NULL) {
1222
ldap_free_urldesc(dest);
1227
if ( ludp->lud_filter != NULL ) {
1228
dest->lud_filter = LDAP_STRDUP( ludp->lud_filter );
1229
if (dest->lud_filter == NULL) {
1230
ldap_free_urldesc(dest);
1235
if ( ludp->lud_attrs != NULL ) {
1236
dest->lud_attrs = ldap_charray_dup( ludp->lud_attrs );
1237
if (dest->lud_attrs == NULL) {
1238
ldap_free_urldesc(dest);
1243
if ( ludp->lud_exts != NULL ) {
1244
dest->lud_exts = ldap_charray_dup( ludp->lud_exts );
1245
if (dest->lud_exts == NULL) {
1246
ldap_free_urldesc(dest);
1255
ldap_url_duplist (LDAPURLDesc *ludlist)
1257
LDAPURLDesc *dest, *tail, *ludp, *newludp;
1261
for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
1262
newludp = ldap_url_dup(ludp);
1263
if (newludp == NULL) {
1264
ldap_free_urllist(dest);
1270
tail->lud_next = newludp;
1277
ldap_url_parselist_int (LDAPURLDesc **ludlist, const char *url, const char *sep, unsigned flags )
1284
assert( ludlist != NULL );
1285
assert( url != NULL );
1289
if ( sep == NULL ) {
1293
urls = ldap_str2charray( url, sep );
1295
return LDAP_URL_ERR_MEM;
1297
/* count the URLs... */
1298
for (i = 0; urls[i] != NULL; i++) ;
1299
/* ...and put them in the "stack" backward */
1301
rc = ldap_url_parse_ext( urls[i], &ludp, flags );
1303
ldap_charray_free( urls );
1304
ldap_free_urllist( *ludlist );
1308
ludp->lud_next = *ludlist;
1311
ldap_charray_free( urls );
1312
return LDAP_URL_SUCCESS;
1316
ldap_url_parselist (LDAPURLDesc **ludlist, const char *url )
1318
return ldap_url_parselist_int( ludlist, url, ", ", LDAP_PVT_URL_PARSE_HISTORIC );
1322
ldap_url_parselist_ext (LDAPURLDesc **ludlist, const char *url, const char *sep, unsigned flags )
1324
return ldap_url_parselist_int( ludlist, url, sep, flags );
1328
ldap_url_parsehosts(
1329
LDAPURLDesc **ludlist,
1337
assert( ludlist != NULL );
1338
assert( hosts != NULL );
1342
specs = ldap_str2charray(hosts, ", ");
1344
return LDAP_NO_MEMORY;
1346
/* count the URLs... */
1347
for (i = 0; specs[i] != NULL; i++) /* EMPTY */;
1349
/* ...and put them in the "stack" backward */
1351
ludp = LDAP_CALLOC( 1, sizeof(LDAPURLDesc) );
1353
ldap_charray_free(specs);
1354
ldap_free_urllist(*ludlist);
1356
return LDAP_NO_MEMORY;
1358
ludp->lud_port = port;
1359
ludp->lud_host = specs[i];
1361
p = strchr(ludp->lud_host, ':');
1363
/* more than one :, IPv6 address */
1364
if ( strchr(p+1, ':') != NULL ) {
1365
/* allow [address] and [address]:port */
1366
if ( *ludp->lud_host == '[' ) {
1367
p = LDAP_STRDUP(ludp->lud_host+1);
1368
/* copied, make sure we free source later */
1369
specs[i] = ludp->lud_host;
1371
p = strchr( ludp->lud_host, ']' );
1374
ldap_charray_free(specs);
1375
return LDAP_PARAM_ERROR;
1381
ldap_charray_free(specs);
1382
return LDAP_PARAM_ERROR;
1394
ldap_pvt_hex_unescape(p);
1395
ludp->lud_port = strtol( p, &next, 10 );
1396
if ( next == p || next[0] != '\0' ) {
1398
ldap_charray_free(specs);
1399
return LDAP_PARAM_ERROR;
1403
ldap_pvt_hex_unescape(ludp->lud_host);
1404
ludp->lud_scheme = LDAP_STRDUP("ldap");
1405
ludp->lud_next = *ludlist;
1409
/* this should be an array of NULLs now */
1410
/* except entries starting with [ */
1411
ldap_charray_free(specs);
1412
return LDAP_SUCCESS;
1416
ldap_url_list2hosts (LDAPURLDesc *ludlist)
1420
char *s, *p, buf[32]; /* big enough to hold a long decimal # (overkill) */
1422
if (ludlist == NULL)
1425
/* figure out how big the string is */
1426
size = 1; /* nul-term */
1427
for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
1428
size += strlen(ludp->lud_host) + 1; /* host and space */
1429
if (strchr(ludp->lud_host, ':')) /* will add [ ] below */
1431
if (ludp->lud_port != 0)
1432
size += sprintf(buf, ":%d", ludp->lud_port);
1434
s = LDAP_MALLOC(size);
1439
for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
1440
if (strchr(ludp->lud_host, ':')) {
1441
p += sprintf(p, "[%s]", ludp->lud_host);
1443
strcpy(p, ludp->lud_host);
1444
p += strlen(ludp->lud_host);
1446
if (ludp->lud_port != 0)
1447
p += sprintf(p, ":%d", ludp->lud_port);
1451
p--; /* nuke that extra space */
1458
LDAPURLDesc *ludlist )
1464
if ( ludlist == NULL ) {
1468
/* figure out how big the string is */
1469
for ( size = 0, ludp = ludlist; ludp != NULL; ludp = ludp->lud_next ) {
1470
int len = desc2str_len( ludp );
1477
s = LDAP_MALLOC( size );
1483
for ( sofar = 0, ludp = ludlist; ludp != NULL; ludp = ludp->lud_next ) {
1486
len = desc2str( ludp, &s[sofar], size );
1499
assert( size >= 0 );
1502
s[sofar - 1] = '\0';
1508
ldap_free_urllist( LDAPURLDesc *ludlist )
1510
LDAPURLDesc *ludp, *next;
1512
for (ludp = ludlist; ludp != NULL; ludp = next) {
1513
next = ludp->lud_next;
1514
ldap_free_urldesc(ludp);
1519
ldap_free_urldesc( LDAPURLDesc *ludp )
1521
if ( ludp == NULL ) {
1525
if ( ludp->lud_scheme != NULL ) {
1526
LDAP_FREE( ludp->lud_scheme );
1529
if ( ludp->lud_host != NULL ) {
1530
LDAP_FREE( ludp->lud_host );
1533
if ( ludp->lud_dn != NULL ) {
1534
LDAP_FREE( ludp->lud_dn );
1537
if ( ludp->lud_filter != NULL ) {
1538
LDAP_FREE( ludp->lud_filter);
1541
if ( ludp->lud_attrs != NULL ) {
1542
LDAP_VFREE( ludp->lud_attrs );
1545
if ( ludp->lud_exts != NULL ) {
1546
LDAP_VFREE( ludp->lud_exts );
1553
ldap_int_is_hexpair( char *s )
1557
for ( i = 0; i < 2; i++ ) {
1558
if ( s[i] >= '0' && s[i] <= '9' ) {
1562
if ( s[i] >= 'A' && s[i] <= 'F' ) {
1566
if ( s[i] >= 'a' && s[i] <= 'f' ) {
1577
ldap_int_unhex( int c )
1579
return( c >= '0' && c <= '9' ? c - '0'
1580
: c >= 'A' && c <= 'F' ? c - 'A' + 10
1585
ldap_pvt_hex_unescape( char *s )
1588
* Remove URL hex escapes from s... done in place. The basic concept for
1589
* this routine is borrowed from the WWW library HTUnEscape() routine.
1594
for ( p = s; *s != '\0'; ++s ) {
1597
* FIXME: what if '%' is followed
1598
* by non-hexpair chars?
1600
if ( !ldap_int_is_hexpair( s + 1 ) ) {
1605
if ( *++s == '\0' ) {
1608
*p = ldap_int_unhex( *s ) << 4;
1609
if ( *++s == '\0' ) {
1612
*p++ += ldap_int_unhex( *s );