1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657 |
- /* LIBLDAP url.c -- LDAP URL (RFC 4516) related routines */
- /* $OpenLDAP$ */
- /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
- *
- * Copyright 1998-2024 The OpenLDAP Foundation.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
- /* Portions Copyright (c) 1996 Regents of the University of Michigan.
- * All rights reserved.
- */
- /*
- * LDAP URLs look like this:
- * [p]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 4515
- *
- * e.g., ldap://host:port/dc=com?o,cn?base?(o=openldap)?extension
- *
- * We also tolerate URLs that look like: <ldapurl> and <URL:ldapurl>
- */
- #include "portable.h"
- #include <stdio.h>
- #include <ac/stdlib.h>
- #include <ac/ctype.h>
- #include <ac/socket.h>
- #include <ac/string.h>
- #include <ac/time.h>
- #include "ldap-int.h"
- /* local functions */
- static const char* skip_url_prefix LDAP_P((
- const char *url,
- int *enclosedp,
- const char **scheme ));
- int ldap_pvt_url_scheme2proto( const char *scheme )
- {
- assert( scheme != NULL );
- if( scheme == NULL ) {
- return -1;
- }
- if( strcmp("ldap", scheme) == 0 || strcmp("pldap", scheme) == 0 ) {
- return LDAP_PROTO_TCP;
- }
- if( strcmp("ldapi", scheme) == 0 ) {
- return LDAP_PROTO_IPC;
- }
- if( strcmp("ldaps", scheme) == 0 || strcmp("pldaps", 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_scheme_port( const char *scheme, int port )
- {
- assert( scheme != NULL );
- if( port ) return port;
- if( scheme == NULL ) return port;
- if( strcmp("ldap", scheme) == 0 || strcmp("pldap", scheme) == 0 ) {
- return LDAP_PORT;
- }
- if( strcmp("ldapi", scheme) == 0 ) {
- return -1;
- }
- if( strcmp("ldaps", scheme) == 0 || strcmp("pldaps", scheme) == 0 ) {
- return LDAPS_PORT;
- }
- #ifdef LDAP_CONNECTIONLESS
- if( strcmp("cldap", scheme) == 0 ) {
- return LDAP_PORT;
- }
- #endif
- return -1;
- }
- int
- ldap_pvt_url_scheme2tls( const char *scheme )
- {
- assert( scheme != NULL );
- if( scheme == NULL ) {
- return -1;
- }
- return strcmp("ldaps", scheme) == 0 || strcmp("pldaps", scheme) == 0;
- }
- int
- ldap_pvt_url_scheme2proxied( const char *scheme )
- {
- assert( scheme != NULL );
- if( scheme == NULL ) {
- return -1;
- }
- return strcmp("pldap", scheme) == 0 || strcmp("pldaps", scheme) == 0;
- }
- int
- ldap_is_ldap_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 1;
- }
- int
- ldap_is_ldaps_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, "ldaps") == 0 || strcmp(scheme, "pldaps") == 0;
- }
- int
- ldap_is_ldapi_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, "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,
- int *enclosedp,
- const char **scheme )
- {
- /*
- * 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
- */
- const char *p;
- if ( url == NULL ) {
- return( NULL );
- }
- p = url;
- /* skip leading '<' (if any) */
- if ( *p == '<' ) {
- *enclosedp = 1;
- ++p;
- } else {
- *enclosedp = 0;
- }
- /* skip leading "URL:" (if any) */
- if ( strncasecmp( p, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) {
- p += LDAP_URL_URLCOLON_LEN;
- }
- /* 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;
- *scheme = "ldap";
- return( p );
- }
- /* check for "pldap://" prefix */
- if ( strncasecmp( p, PLDAP_URL_PREFIX, PLDAP_URL_PREFIX_LEN ) == 0 ) {
- /* skip over "pldap://" prefix and return success */
- p += PLDAP_URL_PREFIX_LEN;
- *scheme = "pldap";
- return( p );
- }
- /* check for "ldaps://" prefix */
- if ( strncasecmp( p, LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) {
- /* skip over "ldaps://" prefix and return success */
- p += LDAPS_URL_PREFIX_LEN;
- *scheme = "ldaps";
- return( p );
- }
- /* check for "pldaps://" prefix */
- if ( strncasecmp( p, PLDAPS_URL_PREFIX, PLDAPS_URL_PREFIX_LEN ) == 0 ) {
- /* skip over "pldaps://" prefix and return success */
- p += PLDAPS_URL_PREFIX_LEN;
- *scheme = "pldaps";
- 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;
- *scheme = "ldapi";
- 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 );
- }
- int
- ldap_pvt_scope2bv( int scope, struct berval *bv )
- {
- 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;
- }
- return LDAP_SUCCESS;
- }
- const char *
- ldap_pvt_scope2str( int scope )
- {
- struct berval bv;
- if ( ldap_pvt_scope2bv( scope, &bv ) == LDAP_SUCCESS ) {
- return bv.bv_val;
- }
- return NULL;
- }
- 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;
- 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
- #define URLESC_COMMA 0x0001U
- #define URLESC_SLASH 0x0002U
- static int
- hex_escape_len( const char *s, unsigned list )
- {
- int len;
- if ( s == NULL ) {
- return 0;
- }
- for ( len = 0; s[0]; s++ ) {
- switch ( s[0] ) {
- /* RFC 2396: reserved */
- case '?':
- len += 3;
- break;
- case ',':
- if ( list & URLESC_COMMA ) {
- len += 3;
- } else {
- len++;
- }
- break;
- case '/':
- if ( list & URLESC_SLASH ) {
- len += 3;
- } else {
- len++;
- }
- break;
- case ';':
- case ':':
- case '@':
- case '&':
- case '=':
- case '+':
- case '$':
- /* RFC 2396: unreserved mark */
- case '-':
- case '_':
- case '.':
- case '!':
- case '~':
- case '*':
- case '\'':
- case '(':
- case ')':
- len++;
- break;
-
- /* RFC 2396: unreserved alphanum */
- default:
- if ( !isalnum( (unsigned char) s[0] ) ) {
- len += 3;
- } else {
- len++;
- }
- break;
- }
- }
- return len;
- }
- static int
- hex_escape( char *buf, int len, const char *s, unsigned list )
- {
- int i;
- int pos;
- if ( s == NULL ) {
- return 0;
- }
- for ( pos = 0, i = 0; s[i] && pos < len; i++ ) {
- int escape = 0;
- switch ( s[i] ) {
- /* RFC 2396: reserved */
- case '?':
- escape = 1;
- break;
- case ',':
- if ( list & URLESC_COMMA ) {
- escape = 1;
- }
- break;
- case '/':
- if ( list & URLESC_SLASH ) {
- escape = 1;
- }
- break;
- case ';':
- case ':':
- case '@':
- case '&':
- case '=':
- case '+':
- case '$':
- /* RFC 2396: unreserved mark */
- case '-':
- case '_':
- case '.':
- case '!':
- case '~':
- case '*':
- case '\'':
- case '(':
- case ')':
- break;
-
- /* RFC 2396: unreserved alphanum */
- default:
- if ( !isalnum( (unsigned char) s[i] ) ) {
- escape = 1;
- }
- break;
- }
- if ( escape ) {
- buf[pos++] = '%';
- buf[pos++] = hex[ (s[i] >> 4) & 0x0f ];
- buf[pos++] = hex[ s[i] & 0x0f ];
- } else {
- buf[pos++] = s[i];
- }
- }
- buf[pos] = '\0';
- return pos;
- }
- static int
- hex_escape_len_list( char **s, unsigned flags )
- {
- int len;
- int i;
- if ( s == NULL ) {
- return 0;
- }
- len = 0;
- for ( i = 0; s[i] != NULL; i++ ) {
- if ( len ) {
- len++;
- }
- len += hex_escape_len( s[i], flags );
- }
- return len;
- }
- static int
- hex_escape_list( char *buf, int len, char **s, unsigned flags )
- {
- int pos;
- int i;
- if ( s == NULL ) {
- return 0;
- }
- pos = 0;
- for ( i = 0; s[i] != NULL; i++ ) {
- int curlen;
- if ( pos ) {
- buf[pos++] = ',';
- len--;
- }
- curlen = hex_escape( &buf[pos], len, s[i], flags );
- len -= curlen;
- pos += curlen;
- }
- return pos;
- }
- static int
- desc2str_len( LDAPURLDesc *u )
- {
- int sep = 0;
- int len = 0;
- int is_ipc = 0;
- struct berval scope;
- 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 ) {
- sep = 5;
- }
- }
- if ( u->lud_filter ) {
- len += hex_escape_len( u->lud_filter, URLESC_NONE );
- if ( !sep ) {
- sep = 4;
- }
- }
- if ( ldap_pvt_scope2bv( u->lud_scope, &scope ) == LDAP_SUCCESS ) {
- len += scope.bv_len;
- if ( !sep ) {
- sep = 3;
- }
- }
- if ( u->lud_attrs ) {
- len += hex_escape_len_list( u->lud_attrs, URLESC_NONE );
- if ( !sep ) {
- sep = 2;
- }
- }
- if ( u->lud_dn && u->lud_dn[0] ) {
- len += hex_escape_len( u->lud_dn, URLESC_NONE );
- if ( !sep ) {
- sep = 1;
- }
- };
- len += sep;
- if ( u->lud_port ) {
- unsigned p = u->lud_port;
- if ( p > 65535 )
- return -1;
- len += (p > 999 ? 5 + (p > 9999) : p > 99 ? 4 : 2 + (p > 9));
- }
- if ( u->lud_host && u->lud_host[0] ) {
- char *ptr;
- len += hex_escape_len( u->lud_host, URLESC_SLASH );
- if ( !is_ipc && ( ptr = strchr( u->lud_host, ':' ))) {
- if ( strchr( ptr+1, ':' ))
- len += 2; /* IPv6, [] */
- }
- }
- len += strlen( u->lud_scheme ) + STRLENOF( "://" );
- return len;
- }
- static int
- desc2str( LDAPURLDesc *u, char *s, int len )
- {
- int i;
- int sep = 0;
- int sofar = 0;
- int is_v6 = 0;
- int is_ipc = 0;
- struct berval scope = BER_BVNULL;
- char *ptr;
- if ( u == NULL ) {
- return -1;
- }
- if ( s == NULL ) {
- return -1;
- }
- 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 ( !BER_BVISEMPTY( &scope ) ) {
- sep = 3;
- } else if ( u->lud_attrs ) {
- sep = 2;
- } else if ( u->lud_dn && u->lud_dn[0] ) {
- sep = 1;
- }
- if ( !is_ipc && u->lud_host && ( ptr = strchr( u->lud_host, ':' ))) {
- if ( strchr( ptr+1, ':' ))
- is_v6 = 1;
- }
- if ( u->lud_port ) {
- sofar = sprintf( s, "%s://%s%s%s:%d", u->lud_scheme,
- is_v6 ? "[" : "",
- u->lud_host ? u->lud_host : "",
- is_v6 ? "]" : "",
- u->lud_port );
- len -= sofar;
- } else {
- sofar = sprintf( s, "%s://", u->lud_scheme );
- len -= 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 );
- if ( sep < 1 ) {
- goto done;
- }
- s[sofar++] = '/';
- len--;
- assert( len >= 0 );
- if ( u->lud_dn && u->lud_dn[0] ) {
- i = hex_escape( &s[sofar], len, u->lud_dn, URLESC_NONE );
- sofar += i;
- len -= i;
- assert( len >= 0 );
- }
- if ( sep < 2 ) {
- goto done;
- }
- s[sofar++] = '?';
- len--;
- assert( len >= 0 );
- i = hex_escape_list( &s[sofar], len, u->lud_attrs, URLESC_NONE );
- sofar += i;
- len -= i;
- assert( len >= 0 );
- if ( sep < 3 ) {
- goto done;
- }
- s[sofar++] = '?';
- len--;
- assert( len >= 0 );
- if ( !BER_BVISNULL( &scope ) ) {
- strcpy( &s[sofar], scope.bv_val );
- sofar += scope.bv_len;
- len -= scope.bv_len;
- }
- assert( len >= 0 );
- if ( sep < 4 ) {
- goto done;
- }
- s[sofar++] = '?';
- len--;
- assert( len >= 0 );
- i = hex_escape( &s[sofar], len, u->lud_filter, URLESC_NONE );
- sofar += i;
- len -= i;
- assert( len >= 0 );
- if ( sep < 5 ) {
- goto done;
- }
- s[sofar++] = '?';
- len--;
- assert( len >= 0 );
- i = hex_escape_list( &s[sofar], len, u->lud_exts, URLESC_COMMA );
- sofar += i;
- len -= i;
- assert( len >= 0 );
- done:
- if ( len < 0 ) {
- return -1;
- }
- return sofar;
- }
- char *
- ldap_url_desc2str( LDAPURLDesc *u )
- {
- int len;
- char *s;
- if ( u == NULL ) {
- return NULL;
- }
- len = desc2str_len( u );
- if ( len < 0 ) {
- return NULL;
- }
-
- /* allocate enough to hex escape everything -- overkill */
- s = LDAP_MALLOC( len + 1 );
- if ( s == NULL ) {
- return NULL;
- }
- if ( desc2str( u, s, len ) != len ) {
- LDAP_FREE( s );
- return NULL;
- }
- s[len] = '\0';
- return s;
- }
- int
- ldap_url_parse_ext( LDAP_CONST char *url_in, LDAPURLDesc **ludpp, unsigned flags )
- {
- /*
- * Pick apart the pieces of an LDAP URL.
- */
- LDAPURLDesc *ludp;
- char *p, *q, *r;
- int i, enclosed, proto, is_v6 = 0;
- const char *scheme = NULL;
- const char *url_tmp;
- char *url;
- int check_dn = 1;
- if( url_in == NULL || ludpp == NULL ) {
- return LDAP_URL_ERR_PARAM;
- }
- #ifndef LDAP_INT_IN_KERNEL
- /* Global options may not be created yet
- * We can't test if the global options are initialized
- * because a call to LDAP_INT_GLOBAL_OPT() will try to allocate
- * the options and cause infinite recursion
- */
- Debug1( LDAP_DEBUG_TRACE, "ldap_url_parse_ext(%s)\n", url_in );
- #endif
- *ludpp = NULL; /* pessimistic */
- url_tmp = skip_url_prefix( url_in, &enclosed, &scheme );
- if ( url_tmp == NULL ) {
- return LDAP_URL_ERR_BADSCHEME;
- }
- 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 ) {
- return LDAP_URL_ERR_MEM;
- }
- if ( enclosed ) {
- if ( ! *url ) {
- LDAP_FREE( url );
- return LDAP_URL_ERR_BADENCLOSURE;
- }
- p = &url[strlen(url)-1];
- if( *p != '>' ) {
- LDAP_FREE( url );
- return LDAP_URL_ERR_BADENCLOSURE;
- }
- *p = '\0';
- }
- /* allocate return struct */
- ludp = (LDAPURLDesc *)LDAP_CALLOC( 1, sizeof( LDAPURLDesc ));
- if ( ludp == NULL ) {
- LDAP_FREE( url );
- 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_scope = ( flags & LDAP_PVT_URL_PARSE_NODEF_SCOPE ) ? LDAP_SCOPE_BASE : LDAP_SCOPE_DEFAULT;
- ludp->lud_filter = NULL;
- ludp->lud_exts = NULL;
- ludp->lud_scheme = LDAP_STRDUP( scheme );
- if ( ludp->lud_scheme == NULL ) {
- LDAP_FREE( url );
- ldap_free_urldesc( ludp );
- return LDAP_URL_ERR_MEM;
- }
- /* 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;
- }
- }
- 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, ':' );
- }
- if ( q != NULL ) {
- char *next;
- *q++ = '\0';
- ldap_pvt_hex_unescape( q );
- 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;
- }
- /* 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, "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 + is_v6 );
- if( ludp->lud_host == NULL ) {
- LDAP_FREE( url );
- ldap_free_urldesc( ludp );
- return LDAP_URL_ERR_MEM;
- }
- if ( ( flags & LDAP_PVT_URL_PARSE_NOEMPTY_HOST )
- && ludp->lud_host != NULL
- && *ludp->lud_host == '\0' )
- {
- LDAP_FREE( ludp->lud_host );
- ludp->lud_host = NULL;
- }
- /*
- * Kludge. 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 != NULL) && (*q == '?') ) {
- /* ? immediately followed by question */
- 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 {
- check_dn = 0;
- }
- if ( check_dn && ludp->lud_dn == NULL ) {
- LDAP_FREE( url );
- ldap_free_urldesc( ludp );
- return LDAP_URL_ERR_MEM;
- }
- }
- if( p == NULL ) {
- LDAP_FREE( url );
- *ludpp = ludp;
- return LDAP_URL_SUCCESS;
- }
- /* scan forward for '?' that may marks end of dn */
- q = strchr( p, '?' );
- if( q != NULL ) {
- /* terminate dn part */
- *q++ = '\0';
- }
- if( *p != '\0' ) {
- /* parse dn part */
- ldap_pvt_hex_unescape( p );
- ludp->lud_dn = LDAP_STRDUP( p );
- } else if ( !( flags & LDAP_PVT_URL_PARSE_NOEMPTY_DN ) ) {
- ludp->lud_dn = LDAP_STRDUP( "" );
- } else {
- check_dn = 0;
- }
- if( check_dn && ludp->lud_dn == NULL ) {
- LDAP_FREE( url );
- ldap_free_urldesc( ludp );
- return LDAP_URL_ERR_MEM;
- }
- if( q == NULL ) {
- /* no more */
- LDAP_FREE( url );
- *ludpp = ludp;
- return LDAP_URL_SUCCESS;
- }
- /* scan forward for '?' that may marks end of attributes */
- p = q;
- q = strchr( p, '?' );
- if( q != NULL ) {
- /* terminate attributes part */
- *q++ = '\0';
- }
- if( *p != '\0' ) {
- /* parse attributes */
- ldap_pvt_hex_unescape( p );
- ludp->lud_attrs = ldap_str2charray( p, "," );
- if( ludp->lud_attrs == NULL ) {
- LDAP_FREE( url );
- ldap_free_urldesc( ludp );
- return LDAP_URL_ERR_BADATTRS;
- }
- }
- if ( q == NULL ) {
- /* no more */
- LDAP_FREE( url );
- *ludpp = ludp;
- return LDAP_URL_SUCCESS;
- }
- /* scan forward for '?' that may marks end of scope */
- p = q;
- q = strchr( p, '?' );
- if( q != NULL ) {
- /* terminate the scope part */
- *q++ = '\0';
- }
- if( *p != '\0' ) {
- /* parse the scope */
- ldap_pvt_hex_unescape( p );
- ludp->lud_scope = ldap_pvt_str2scope( p );
- if( ludp->lud_scope == -1 ) {
- LDAP_FREE( url );
- ldap_free_urldesc( ludp );
- return LDAP_URL_ERR_BADSCOPE;
- }
- }
- if ( q == NULL ) {
- /* no more */
- LDAP_FREE( url );
- *ludpp = ludp;
- return LDAP_URL_SUCCESS;
- }
- /* scan forward for '?' that may marks end of filter */
- p = q;
- q = strchr( p, '?' );
- if( q != NULL ) {
- /* terminate the filter part */
- *q++ = '\0';
- }
- if( *p != '\0' ) {
- /* parse the filter */
- ldap_pvt_hex_unescape( p );
- if( ! *p ) {
- /* missing filter */
- LDAP_FREE( url );
- ldap_free_urldesc( ludp );
- return LDAP_URL_ERR_BADFILTER;
- }
- ludp->lud_filter = LDAP_STRDUP( p );
- if( ludp->lud_filter == NULL ) {
- LDAP_FREE( url );
- ldap_free_urldesc( ludp );
- return LDAP_URL_ERR_MEM;
- }
- }
- if ( q == NULL ) {
- /* no more */
- LDAP_FREE( url );
- *ludpp = ludp;
- return LDAP_URL_SUCCESS;
- }
- /* scan forward for '?' that may marks end of extensions */
- p = q;
- q = strchr( p, '?' );
- if( q != NULL ) {
- /* extra '?' */
- LDAP_FREE( url );
- ldap_free_urldesc( ludp );
- return LDAP_URL_ERR_BADURL;
- }
- /* parse the extensions */
- ludp->lud_exts = ldap_str2charray( p, "," );
- if( ludp->lud_exts == NULL ) {
- LDAP_FREE( url );
- ldap_free_urldesc( ludp );
- return LDAP_URL_ERR_BADEXTS;
- }
- 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_FREE( url );
- ldap_free_urldesc( ludp );
- return LDAP_URL_ERR_BADEXTS;
- }
- /* no more */
- *ludpp = ludp;
- LDAP_FREE( url );
- return LDAP_URL_SUCCESS;
- }
- int
- ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp )
- {
- return ldap_url_parse_ext( url_in, ludpp, LDAP_PVT_URL_PARSE_HISTORIC );
- }
- 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_scheme = NULL;
- dest->lud_host = NULL;
- dest->lud_dn = NULL;
- dest->lud_filter = NULL;
- dest->lud_attrs = NULL;
- dest->lud_exts = NULL;
- dest->lud_next = NULL;
- if ( ludp->lud_scheme != NULL ) {
- dest->lud_scheme = LDAP_STRDUP( ludp->lud_scheme );
- if (dest->lud_scheme == NULL) {
- ldap_free_urldesc(dest);
- return 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;
- }
- static int
- ldap_url_parselist_int (LDAPURLDesc **ludlist, const char *url, const char *sep, unsigned flags )
-
- {
- int i, rc;
- LDAPURLDesc *ludp;
- char **urls;
- assert( ludlist != NULL );
- assert( url != NULL );
- *ludlist = NULL;
- if ( sep == NULL ) {
- sep = ", ";
- }
- urls = ldap_str2charray( url, sep );
- if (urls == NULL)
- return LDAP_URL_ERR_MEM;
- /* count the URLs... */
- for (i = 0; urls[i] != NULL; i++) ;
- /* ...and put them in the "stack" backward */
- while (--i >= 0) {
- rc = ldap_url_parse_ext( urls[i], &ludp, flags );
- 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_URL_SUCCESS;
- }
- int
- ldap_url_parselist (LDAPURLDesc **ludlist, const char *url )
- {
- return ldap_url_parselist_int( ludlist, url, ", ", LDAP_PVT_URL_PARSE_HISTORIC );
- }
- int
- ldap_url_parselist_ext (LDAPURLDesc **ludlist, const char *url, const char *sep, unsigned flags )
- {
- return ldap_url_parselist_int( ludlist, url, sep, flags );
- }
- int
- ldap_url_parsehosts(
- LDAPURLDesc **ludlist,
- const char *hosts,
- int port )
- {
- int i;
- LDAPURLDesc *ludp;
- char **specs, *p;
- assert( ludlist != NULL );
- assert( hosts != NULL );
- *ludlist = NULL;
- specs = ldap_str2charray(hosts, ", ");
- if (specs == NULL)
- return LDAP_NO_MEMORY;
- /* count the URLs... */
- for (i = 0; specs[i] != NULL; i++) /* EMPTY */;
- /* ...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_port = port;
- ludp->lud_host = specs[i];
- p = strchr(ludp->lud_host, ':');
- if (p != NULL) {
- /* more than one :, IPv6 address */
- if ( strchr(p+1, ':') != NULL ) {
- /* allow [address] and [address]:port */
- if ( *ludp->lud_host == '[' ) {
- p = strchr( ludp->lud_host+1, ']' );
- if ( p == NULL ) {
- LDAP_FREE(ludp);
- ldap_charray_free(specs);
- return LDAP_PARAM_ERROR;
- }
- /* Truncate trailing ']' and shift hostname down 1 char */
- *p = '\0';
- AC_MEMCPY( ludp->lud_host, ludp->lud_host+1, p - ludp->lud_host );
- p++;
- if ( *p != ':' ) {
- if ( *p != '\0' ) {
- LDAP_FREE(ludp);
- ldap_charray_free(specs);
- return LDAP_PARAM_ERROR;
- }
- p = NULL;
- }
- } else {
- p = NULL;
- }
- }
- if (p != NULL) {
- char *next;
- *p++ = 0;
- ldap_pvt_hex_unescape(p);
- ludp->lud_port = strtol( p, &next, 10 );
- if ( next == p || next[0] != '\0' ) {
- LDAP_FREE(ludp);
- ldap_charray_free(specs);
- return LDAP_PARAM_ERROR;
- }
- }
- }
- ludp->lud_scheme = LDAP_STRDUP("ldap");
- if ( ludp->lud_scheme == NULL ) {
- LDAP_FREE(ludp);
- ldap_charray_free(specs);
- return LDAP_NO_MEMORY;
- }
- specs[i] = NULL;
- ldap_pvt_hex_unescape(ludp->lud_host);
- 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) {
- if ( ludp->lud_host == NULL ) continue;
- 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);
- }
- s = LDAP_MALLOC(size);
- if (s == NULL)
- return NULL;
- p = s;
- for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
- if ( ludp->lud_host == NULL ) continue;
- 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++ = ' ';
- }
- if (p != s)
- p--; /* nuke that extra space */
- *p = '\0';
- return s;
- }
- char *
- ldap_url_list2urls(
- LDAPURLDesc *ludlist )
- {
- LDAPURLDesc *ludp;
- int size, sofar;
- char *s;
- if ( ludlist == NULL ) {
- return NULL;
- }
- /* figure out how big the string is */
- for ( size = 0, ludp = ludlist; ludp != NULL; ludp = ludp->lud_next ) {
- int len = desc2str_len( ludp );
- if ( len < 0 ) {
- return NULL;
- }
- size += len + 1;
- }
-
- s = LDAP_MALLOC( size );
- if ( s == NULL ) {
- return NULL;
- }
- for ( sofar = 0, ludp = ludlist; ludp != NULL; ludp = ludp->lud_next ) {
- int len;
- len = desc2str( ludp, &s[sofar], size );
-
- if ( len < 0 ) {
- LDAP_FREE( s );
- return NULL;
- }
- sofar += len;
- size -= len;
- s[sofar++] = ' ';
- size--;
- assert( size >= 0 );
- }
- s[sofar - 1] = '\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 )
- {
- if ( ludp == NULL ) {
- return;
- }
-
- if ( ludp->lud_scheme != NULL ) {
- LDAP_FREE( ludp->lud_scheme );
- }
- if ( ludp->lud_host != NULL ) {
- LDAP_FREE( ludp->lud_host );
- }
- if ( ludp->lud_dn != NULL ) {
- LDAP_FREE( ludp->lud_dn );
- }
- if ( ludp->lud_filter != NULL ) {
- LDAP_FREE( ludp->lud_filter);
- }
- if ( ludp->lud_attrs != NULL ) {
- LDAP_VFREE( ludp->lud_attrs );
- }
- if ( ludp->lud_exts != NULL ) {
- LDAP_VFREE( ludp->lud_exts );
- }
- LDAP_FREE( ludp );
- }
- static int
- ldap_int_is_hexpair( char *s )
- {
- int i;
- for ( i = 0; i < 2; i++ ) {
- if ( s[i] >= '0' && s[i] <= '9' ) {
- continue;
- }
- if ( s[i] >= 'A' && s[i] <= 'F' ) {
- continue;
- }
- if ( s[i] >= 'a' && s[i] <= 'f' ) {
- continue;
- }
- return 0;
- }
-
- return 1;
- }
-
- static int
- ldap_int_unhex( int c )
- {
- return( c >= '0' && c <= '9' ? c - '0'
- : c >= 'A' && c <= 'F' ? c - 'A' + 10
- : c - 'a' + 10 );
- }
- 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.
- */
- char *p,
- *save_s = s;
- for ( p = s; *s != '\0'; ++s ) {
- if ( *s == '%' ) {
- /*
- * FIXME: what if '%' is followed
- * by non-hexpair chars?
- */
- if ( !ldap_int_is_hexpair( s + 1 ) ) {
- p = save_s;
- break;
- }
- if ( *++s == '\0' ) {
- break;
- }
- *p = ldap_int_unhex( *s ) << 4;
- if ( *++s == '\0' ) {
- break;
- }
- *p++ += ldap_int_unhex( *s );
- } else {
- *p++ = *s;
- }
- }
- *p = '\0';
- }
|