1 /* LIBLDAP url.c -- LDAP URL (RFC 2255) related routines */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2005 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 2254
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 static int str2scope( const char *p )
263 if ( strcasecmp( p, "one" ) == 0 ) {
264 return LDAP_SCOPE_ONELEVEL;
266 } else if ( strcasecmp( p, "onelevel" ) == 0 ) {
267 return LDAP_SCOPE_ONELEVEL;
269 } else if ( strcasecmp( p, "base" ) == 0 ) {
270 return LDAP_SCOPE_BASE;
272 } else if ( strcasecmp( p, "sub" ) == 0 ) {
273 return LDAP_SCOPE_SUBTREE;
275 } else if ( strcasecmp( p, "subtree" ) == 0 ) {
276 return LDAP_SCOPE_SUBTREE;
278 #ifdef LDAP_SCOPE_SUBORDINATE
279 } else if ( strcasecmp( p, "subordinate" ) == 0 ) {
280 return LDAP_SCOPE_SUBORDINATE;
282 } else if ( strcasecmp( p, "children" ) == 0 ) {
283 return LDAP_SCOPE_SUBORDINATE;
290 static const char hex[] = "0123456789ABCDEF";
292 #define URLESC_NONE 0x0000U
293 #define URLESC_COMMA 0x0001U
294 #define URLESC_SLASH 0x0002U
297 hex_escape_len( const char *s, unsigned list )
305 for ( len = 0; s[0]; s++ ) {
307 /* RFC 2396: reserved */
313 if ( list & URLESC_COMMA ) {
321 if ( list & URLESC_SLASH ) {
336 /* RFC 2396: unreserved mark */
349 /* RFC 2396: unreserved alphanum */
351 if ( !isalnum( s[0] ) ) {
364 hex_escape( char *buf, int len, const char *s, unsigned list )
373 for ( pos = 0, i = 0; s[i] && pos < len; i++ ) {
377 /* RFC 2396: reserved */
383 if ( list & URLESC_COMMA ) {
389 if ( list & URLESC_SLASH ) {
402 /* RFC 2396: unreserved mark */
414 /* RFC 2396: unreserved alphanum */
416 if ( !isalnum( s[i] ) ) {
424 buf[pos++] = hex[ (s[i] >> 4) & 0x0f ];
425 buf[pos++] = hex[ s[i] & 0x0f ];
438 hex_escape_len_list( char **s, unsigned flags )
448 for ( i = 0; s[i] != NULL; i++ ) {
452 len += hex_escape_len( s[i], flags );
459 hex_escape_list( char *buf, int len, char **s, unsigned flags )
469 for ( i = 0; s[i] != NULL; i++ ) {
476 curlen = hex_escape( &buf[pos], len, s[i], flags );
485 desc2str_len( LDAPURLDesc *u )
495 len += hex_escape_len_list( u->lud_exts, URLESC_COMMA );
501 if ( u->lud_filter ) {
502 len += hex_escape_len( u->lud_filter, URLESC_NONE );
508 switch ( u->lud_scope ) {
509 case LDAP_SCOPE_BASE:
510 case LDAP_SCOPE_ONELEVEL:
511 case LDAP_SCOPE_SUBTREE:
512 #ifdef LDAP_SCOPE_SUBORDINATE
513 case LDAP_SCOPE_SUBORDINATE:
515 switch ( u->lud_scope ) {
516 case LDAP_SCOPE_BASE:
517 len += STRLENOF( "base" );
520 case LDAP_SCOPE_ONELEVEL:
521 len += STRLENOF( "one" );
524 case LDAP_SCOPE_SUBTREE:
525 len += STRLENOF( "sub" );
528 #ifdef LDAP_SCOPE_SUBORDINATE
529 case LDAP_SCOPE_SUBORDINATE:
530 len += STRLENOF( "subordinate" );
545 if ( u->lud_attrs ) {
546 len += hex_escape_len_list( u->lud_attrs, URLESC_NONE );
552 if ( u->lud_dn && u->lud_dn[0] ) {
553 len += hex_escape_len( u->lud_dn, URLESC_NONE );
562 char buf[] = ":65535";
564 len += snprintf( buf, sizeof( buf ), ":%d", u->lud_port );
565 if ( u->lud_host && u->lud_host[0] ) {
566 len += strlen( u->lud_host );
570 if ( u->lud_host && u->lud_host[0] ) {
571 len += hex_escape_len( u->lud_host, URLESC_SLASH );
575 len += strlen( u->lud_scheme ) + STRLENOF( "://" );
581 desc2str( LDAPURLDesc *u, char *s, int len )
596 switch ( u->lud_scope ) {
597 case LDAP_SCOPE_BASE:
598 case LDAP_SCOPE_ONELEVEL:
599 case LDAP_SCOPE_SUBTREE:
600 #ifdef LDAP_SCOPE_SUBORDINATE
601 case LDAP_SCOPE_SUBORDINATE:
609 } else if ( u->lud_filter ) {
611 } else if ( gotscope ) {
613 } else if ( u->lud_attrs ) {
615 } else if ( u->lud_dn && u->lud_dn[0] ) {
620 len -= sprintf( s, "%s://%s:%d%n", u->lud_scheme,
621 u->lud_host ? u->lud_host : "",
622 u->lud_port, &sofar );
625 len -= sprintf( s, "%s://%n", u->lud_scheme, &sofar );
626 if ( u->lud_host && u->lud_host[0] ) {
627 i = hex_escape( &s[sofar], len, u->lud_host, URLESC_SLASH );
644 if ( u->lud_dn && u->lud_dn[0] ) {
645 i = hex_escape( &s[sofar], len, u->lud_dn, URLESC_NONE );
660 i = hex_escape_list( &s[sofar], len, u->lud_attrs, URLESC_NONE );
674 switch ( u->lud_scope ) {
675 case LDAP_SCOPE_BASE:
676 strcpy( &s[sofar], "base" );
677 sofar += STRLENOF("base");
678 len -= STRLENOF("base");
681 case LDAP_SCOPE_ONELEVEL:
682 strcpy( &s[sofar], "one" );
683 sofar += STRLENOF("one");
684 len -= STRLENOF("one");
687 case LDAP_SCOPE_SUBTREE:
688 strcpy( &s[sofar], "sub" );
689 sofar += STRLENOF("sub");
690 len -= STRLENOF("sub");
693 #ifdef LDAP_SCOPE_SUBORDINATE
694 case LDAP_SCOPE_SUBORDINATE:
695 strcpy( &s[sofar], "children" );
696 sofar += STRLENOF("children");
697 len -= STRLENOF("children");
712 i = hex_escape( &s[sofar], len, u->lud_filter, URLESC_NONE );
726 i = hex_escape_list( &s[sofar], len, u->lud_exts, URLESC_COMMA );
741 ldap_url_desc2str( LDAPURLDesc *u )
750 len = desc2str_len( u );
755 /* allocate enough to hex escape everything -- overkill */
756 s = LDAP_MALLOC( len + 1 );
762 if ( desc2str( u, s, len ) != len ) {
773 ldap_url_parse_ext( LDAP_CONST char *url_in, LDAPURLDesc **ludpp )
776 * Pick apart the pieces of an LDAP URL.
782 const char *scheme = NULL;
786 if( url_in == NULL || ludpp == NULL ) {
787 return LDAP_URL_ERR_PARAM;
790 #ifndef LDAP_INT_IN_KERNEL
791 /* Global options may not be created yet
792 * We can't test if the global options are initialized
793 * because a call to LDAP_INT_GLOBAL_OPT() will try to allocate
794 * the options and cause infinite recursion
796 Debug( LDAP_DEBUG_TRACE, "ldap_url_parse_ext(%s)\n", url_in, 0, 0 );
799 *ludpp = NULL; /* pessimistic */
801 url_tmp = skip_url_prefix( url_in, &enclosed, &scheme );
803 if ( url_tmp == NULL ) {
804 return LDAP_URL_ERR_BADSCHEME;
807 assert( scheme != NULL );
809 /* make working copy of the remainder of the URL */
810 url = LDAP_STRDUP( url_tmp );
812 return LDAP_URL_ERR_MEM;
816 p = &url[strlen(url)-1];
820 return LDAP_URL_ERR_BADENCLOSURE;
826 /* allocate return struct */
827 ludp = (LDAPURLDesc *)LDAP_CALLOC( 1, sizeof( LDAPURLDesc ));
829 if ( ludp == NULL ) {
831 return LDAP_URL_ERR_MEM;
834 ludp->lud_next = NULL;
835 ludp->lud_host = NULL;
838 ludp->lud_attrs = NULL;
839 ludp->lud_scope = LDAP_SCOPE_DEFAULT;
840 ludp->lud_filter = NULL;
841 ludp->lud_exts = NULL;
843 ludp->lud_scheme = LDAP_STRDUP( scheme );
845 if ( ludp->lud_scheme == NULL ) {
847 ldap_free_urldesc( ludp );
848 return LDAP_URL_ERR_MEM;
851 /* scan forward for '/' that marks end of hostport and begin. of dn */
852 p = strchr( url, '/' );
855 /* terminate hostport; point to start of dn */
859 /* IPv6 syntax with [ip address]:port */
861 r = strchr( url, ']' );
864 ldap_free_urldesc( ludp );
865 return LDAP_URL_ERR_BADURL;
868 q = strchr( r, ':' );
870 q = strchr( url, ':' );
877 ldap_pvt_hex_unescape( q );
881 ldap_free_urldesc( ludp );
882 return LDAP_URL_ERR_BADURL;
885 ludp->lud_port = strtol( q, &next, 10 );
886 if ( next == NULL || next[0] != '\0' ) {
888 ldap_free_urldesc( ludp );
889 return LDAP_URL_ERR_BADURL;
893 ldap_pvt_hex_unescape( url );
895 /* If [ip address]:port syntax, url is [ip and we skip the [ */
896 ludp->lud_host = LDAP_STRDUP( url + ( *url == '[' ) );
898 if( ludp->lud_host == NULL ) {
900 ldap_free_urldesc( ludp );
901 return LDAP_URL_ERR_MEM;
905 * Kludge. ldap://111.222.333.444:389??cn=abc,o=company
907 * On early Novell releases, search references/referrals were returned
908 * in this format, i.e., the dn was kind of in the scope position,
909 * but the required slash is missing. The whole thing is illegal syntax,
910 * but we need to account for it. Fortunately it can't be confused with
913 if( (p == NULL) && (q != NULL) && ((q = strchr( q, '?')) != NULL)) {
915 /* ? immediately followed by question */
920 ldap_pvt_hex_unescape( q );
921 ludp->lud_dn = LDAP_STRDUP( q );
923 ludp->lud_dn = LDAP_STRDUP( "" );
926 if( ludp->lud_dn == NULL ) {
928 ldap_free_urldesc( ludp );
929 return LDAP_URL_ERR_MEM;
937 return LDAP_URL_SUCCESS;
940 /* scan forward for '?' that may marks end of dn */
941 q = strchr( p, '?' );
944 /* terminate dn part */
950 ldap_pvt_hex_unescape( p );
951 ludp->lud_dn = LDAP_STRDUP( p );
953 ludp->lud_dn = LDAP_STRDUP( "" );
956 if( ludp->lud_dn == NULL ) {
958 ldap_free_urldesc( ludp );
959 return LDAP_URL_ERR_MEM;
966 return LDAP_URL_SUCCESS;
969 /* scan forward for '?' that may marks end of attributes */
971 q = strchr( p, '?' );
974 /* terminate attributes part */
979 /* parse attributes */
980 ldap_pvt_hex_unescape( p );
981 ludp->lud_attrs = ldap_str2charray( p, "," );
983 if( ludp->lud_attrs == NULL ) {
985 ldap_free_urldesc( ludp );
986 return LDAP_URL_ERR_BADATTRS;
994 return LDAP_URL_SUCCESS;
997 /* scan forward for '?' that may marks end of scope */
999 q = strchr( p, '?' );
1002 /* terminate the scope part */
1007 /* parse the scope */
1008 ldap_pvt_hex_unescape( p );
1009 ludp->lud_scope = str2scope( p );
1011 if( ludp->lud_scope == -1 ) {
1013 ldap_free_urldesc( ludp );
1014 return LDAP_URL_ERR_BADSCOPE;
1022 return LDAP_URL_SUCCESS;
1025 /* scan forward for '?' that may marks end of filter */
1027 q = strchr( p, '?' );
1030 /* terminate the filter part */
1035 /* parse the filter */
1036 ldap_pvt_hex_unescape( p );
1039 /* missing filter */
1041 ldap_free_urldesc( ludp );
1042 return LDAP_URL_ERR_BADFILTER;
1045 ludp->lud_filter = LDAP_STRDUP( p );
1047 if( ludp->lud_filter == NULL ) {
1049 ldap_free_urldesc( ludp );
1050 return LDAP_URL_ERR_MEM;
1058 return LDAP_URL_SUCCESS;
1061 /* scan forward for '?' that may marks end of extensions */
1063 q = strchr( p, '?' );
1068 ldap_free_urldesc( ludp );
1069 return LDAP_URL_ERR_BADURL;
1072 /* parse the extensions */
1073 ludp->lud_exts = ldap_str2charray( p, "," );
1075 if( ludp->lud_exts == NULL ) {
1077 ldap_free_urldesc( ludp );
1078 return LDAP_URL_ERR_BADEXTS;
1081 for( i=0; ludp->lud_exts[i] != NULL; i++ ) {
1082 ldap_pvt_hex_unescape( ludp->lud_exts[i] );
1084 if( *ludp->lud_exts[i] == '!' ) {
1085 /* count the number of critical extensions */
1086 ludp->lud_crit_exts++;
1091 /* must have 1 or more */
1093 ldap_free_urldesc( ludp );
1094 return LDAP_URL_ERR_BADEXTS;
1100 return LDAP_URL_SUCCESS;
1104 ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp )
1106 int rc = ldap_url_parse_ext( url_in, ludpp );
1108 if( rc != LDAP_URL_SUCCESS ) {
1112 if ((*ludpp)->lud_scope == LDAP_SCOPE_DEFAULT) {
1113 (*ludpp)->lud_scope = LDAP_SCOPE_BASE;
1116 if ((*ludpp)->lud_host != NULL && *(*ludpp)->lud_host == '\0') {
1117 LDAP_FREE( (*ludpp)->lud_host );
1118 (*ludpp)->lud_host = NULL;
1121 if ((*ludpp)->lud_port == 0) {
1122 if( strcmp((*ludpp)->lud_scheme, "ldap") == 0 ) {
1123 (*ludpp)->lud_port = LDAP_PORT;
1124 #ifdef LDAP_CONNECTIONLESS
1125 } else if( strcmp((*ludpp)->lud_scheme, "cldap") == 0 ) {
1126 (*ludpp)->lud_port = LDAP_PORT;
1128 } else if( strcmp((*ludpp)->lud_scheme, "ldaps") == 0 ) {
1129 (*ludpp)->lud_port = LDAPS_PORT;
1137 ldap_url_dup ( LDAPURLDesc *ludp )
1141 if ( ludp == NULL ) {
1145 dest = LDAP_MALLOC( sizeof(LDAPURLDesc) );
1150 dest->lud_scheme = NULL;
1151 dest->lud_host = NULL;
1152 dest->lud_dn = NULL;
1153 dest->lud_filter = NULL;
1154 dest->lud_attrs = NULL;
1155 dest->lud_exts = NULL;
1156 dest->lud_next = NULL;
1158 if ( ludp->lud_scheme != NULL ) {
1159 dest->lud_scheme = LDAP_STRDUP( ludp->lud_scheme );
1160 if (dest->lud_scheme == NULL) {
1161 ldap_free_urldesc(dest);
1166 if ( ludp->lud_host != NULL ) {
1167 dest->lud_host = LDAP_STRDUP( ludp->lud_host );
1168 if (dest->lud_host == NULL) {
1169 ldap_free_urldesc(dest);
1174 if ( ludp->lud_dn != NULL ) {
1175 dest->lud_dn = LDAP_STRDUP( ludp->lud_dn );
1176 if (dest->lud_dn == NULL) {
1177 ldap_free_urldesc(dest);
1182 if ( ludp->lud_filter != NULL ) {
1183 dest->lud_filter = LDAP_STRDUP( ludp->lud_filter );
1184 if (dest->lud_filter == NULL) {
1185 ldap_free_urldesc(dest);
1190 if ( ludp->lud_attrs != NULL ) {
1191 dest->lud_attrs = ldap_charray_dup( ludp->lud_attrs );
1192 if (dest->lud_attrs == NULL) {
1193 ldap_free_urldesc(dest);
1198 if ( ludp->lud_exts != NULL ) {
1199 dest->lud_exts = ldap_charray_dup( ludp->lud_exts );
1200 if (dest->lud_exts == NULL) {
1201 ldap_free_urldesc(dest);
1210 ldap_url_duplist (LDAPURLDesc *ludlist)
1212 LDAPURLDesc *dest, *tail, *ludp, *newludp;
1216 for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
1217 newludp = ldap_url_dup(ludp);
1218 if (newludp == NULL) {
1219 ldap_free_urllist(dest);
1225 tail->lud_next = newludp;
1232 ldap_url_parselist_int (LDAPURLDesc **ludlist, const char *url, const char *sep,
1233 int (*url_parse)( const char *, LDAPURLDesc ** ) )
1239 assert( ludlist != NULL );
1240 assert( url != NULL );
1244 urls = ldap_str2charray(url, sep);
1246 return LDAP_URL_ERR_MEM;
1248 /* count the URLs... */
1249 for (i = 0; urls[i] != NULL; i++) ;
1250 /* ...and put them in the "stack" backward */
1252 rc = url_parse( urls[i], &ludp );
1254 ldap_charray_free(urls);
1255 ldap_free_urllist(*ludlist);
1259 ludp->lud_next = *ludlist;
1262 ldap_charray_free(urls);
1263 return LDAP_URL_SUCCESS;
1267 ldap_url_parselist (LDAPURLDesc **ludlist, const char *url )
1269 return ldap_url_parselist_int( ludlist, url, ", ", ldap_url_parse );
1273 ldap_url_parselist_ext (LDAPURLDesc **ludlist, const char *url, const char *sep )
1275 return ldap_url_parselist_int( ludlist, url, sep, ldap_url_parse_ext );
1279 ldap_url_parsehosts(
1280 LDAPURLDesc **ludlist,
1288 assert( ludlist != NULL );
1289 assert( hosts != NULL );
1293 specs = ldap_str2charray(hosts, ", ");
1295 return LDAP_NO_MEMORY;
1297 /* count the URLs... */
1298 for (i = 0; specs[i] != NULL; i++) /* EMPTY */;
1300 /* ...and put them in the "stack" backward */
1302 ludp = LDAP_CALLOC( 1, sizeof(LDAPURLDesc) );
1304 ldap_charray_free(specs);
1305 ldap_free_urllist(*ludlist);
1307 return LDAP_NO_MEMORY;
1309 ludp->lud_port = port;
1310 ludp->lud_host = specs[i];
1312 p = strchr(ludp->lud_host, ':');
1314 /* more than one :, IPv6 address */
1315 if ( strchr(p+1, ':') != NULL ) {
1316 /* allow [address] and [address]:port */
1317 if ( *ludp->lud_host == '[' ) {
1318 p = LDAP_STRDUP(ludp->lud_host+1);
1319 /* copied, make sure we free source later */
1320 specs[i] = ludp->lud_host;
1322 p = strchr( ludp->lud_host, ']' );
1324 return LDAP_PARAM_ERROR;
1328 return LDAP_PARAM_ERROR;
1339 ldap_pvt_hex_unescape(p);
1340 ludp->lud_port = strtol( p, &next, 10 );
1341 if ( next == NULL || next[0] != '\0' ) {
1342 return LDAP_PARAM_ERROR;
1346 ldap_pvt_hex_unescape(ludp->lud_host);
1347 ludp->lud_scheme = LDAP_STRDUP("ldap");
1348 ludp->lud_next = *ludlist;
1352 /* this should be an array of NULLs now */
1353 /* except entries starting with [ */
1354 ldap_charray_free(specs);
1355 return LDAP_SUCCESS;
1359 ldap_url_list2hosts (LDAPURLDesc *ludlist)
1363 char *s, *p, buf[32]; /* big enough to hold a long decimal # (overkill) */
1365 if (ludlist == NULL)
1368 /* figure out how big the string is */
1369 size = 1; /* nul-term */
1370 for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
1371 size += strlen(ludp->lud_host) + 1; /* host and space */
1372 if (strchr(ludp->lud_host, ':')) /* will add [ ] below */
1374 if (ludp->lud_port != 0)
1375 size += sprintf(buf, ":%d", ludp->lud_port);
1377 s = LDAP_MALLOC(size);
1382 for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
1383 if (strchr(ludp->lud_host, ':')) {
1384 p += sprintf(p, "[%s]", ludp->lud_host);
1386 strcpy(p, ludp->lud_host);
1387 p += strlen(ludp->lud_host);
1389 if (ludp->lud_port != 0)
1390 p += sprintf(p, ":%d", ludp->lud_port);
1394 p--; /* nuke that extra space */
1401 LDAPURLDesc *ludlist )
1407 if ( ludlist == NULL ) {
1411 /* figure out how big the string is */
1412 for ( size = 0, ludp = ludlist; ludp != NULL; ludp = ludp->lud_next ) {
1413 int len = desc2str_len( ludp );
1420 s = LDAP_MALLOC( size );
1426 for ( sofar = 0, ludp = ludlist; ludp != NULL; ludp = ludp->lud_next ) {
1429 len = desc2str( ludp, &s[sofar], size );
1442 assert( size >= 0 );
1445 s[sofar - 1] = '\0';
1451 ldap_free_urllist( LDAPURLDesc *ludlist )
1453 LDAPURLDesc *ludp, *next;
1455 for (ludp = ludlist; ludp != NULL; ludp = next) {
1456 next = ludp->lud_next;
1457 ldap_free_urldesc(ludp);
1462 ldap_free_urldesc( LDAPURLDesc *ludp )
1464 if ( ludp == NULL ) {
1468 if ( ludp->lud_scheme != NULL ) {
1469 LDAP_FREE( ludp->lud_scheme );
1472 if ( ludp->lud_host != NULL ) {
1473 LDAP_FREE( ludp->lud_host );
1476 if ( ludp->lud_dn != NULL ) {
1477 LDAP_FREE( ludp->lud_dn );
1480 if ( ludp->lud_filter != NULL ) {
1481 LDAP_FREE( ludp->lud_filter);
1484 if ( ludp->lud_attrs != NULL ) {
1485 LDAP_VFREE( ludp->lud_attrs );
1488 if ( ludp->lud_exts != NULL ) {
1489 LDAP_VFREE( ludp->lud_exts );
1496 ldap_int_is_hexpair( char *s )
1500 for ( i = 0; i < 2; i++ ) {
1501 if ( s[i] >= '0' && s[i] <= '9' ) {
1505 if ( s[i] >= 'A' && s[i] <= 'F' ) {
1509 if ( s[i] >= 'a' && s[i] <= 'f' ) {
1520 ldap_int_unhex( int c )
1522 return( c >= '0' && c <= '9' ? c - '0'
1523 : c >= 'A' && c <= 'F' ? c - 'A' + 10
1528 ldap_pvt_hex_unescape( char *s )
1531 * Remove URL hex escapes from s... done in place. The basic concept for
1532 * this routine is borrowed from the WWW library HTUnEscape() routine.
1537 for ( p = s; *s != '\0'; ++s ) {
1540 * FIXME: what if '%' is followed
1541 * by non-hexpair chars?
1543 if ( !ldap_int_is_hexpair( s + 1 ) ) {
1548 if ( *++s == '\0' ) {
1551 *p = ldap_int_unhex( *s ) << 4;
1552 if ( *++s == '\0' ) {
1555 *p++ += ldap_int_unhex( *s );