xref: /onnv-gate/usr/src/lib/libldap4/common/url.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*0Sstevel@tonic-gate 
8*0Sstevel@tonic-gate /*
9*0Sstevel@tonic-gate  *  Copyright (c) 1996 Regents of the University of Michigan.
10*0Sstevel@tonic-gate  *  All rights reserved.
11*0Sstevel@tonic-gate  *
12*0Sstevel@tonic-gate  *  LIBLDAP url.c -- LDAP URL related routines
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  *  LDAP URLs look like this:
15*0Sstevel@tonic-gate  *    l d a p : / / hostport / dn [ ? attributes [ ? scope [ ? filter [ ? extensions ] ] ] ]
16*0Sstevel@tonic-gate  *
17*0Sstevel@tonic-gate  *  where:
18*0Sstevel@tonic-gate  *   attributes is a comma separated list
19*0Sstevel@tonic-gate  *   scope is one of these three strings:  base one sub (default=base)
20*0Sstevel@tonic-gate  *   filter is an string-represented filter as in RFC 1558
21*0Sstevel@tonic-gate  *	 extensions is a comma separated list of extension
22*0Sstevel@tonic-gate  *   and extension is like this: [ ! ] oid/x-oid [ = value ]
23*0Sstevel@tonic-gate  *
24*0Sstevel@tonic-gate  *  e.g.,  ldap://ldap.itd.umich.edu/c=US?o,description?one?o=umich
25*0Sstevel@tonic-gate  *
26*0Sstevel@tonic-gate  *  We also tolerate URLs that look like: <ldapurl> and <URL:ldapurl>
27*0Sstevel@tonic-gate  */
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #ifndef lint
30*0Sstevel@tonic-gate static char copyright[] = "@(#) Copyright (c) 1996 Regents of the University of Michigan.\nAll rights reserved.\n";
31*0Sstevel@tonic-gate #endif
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <stdio.h>
34*0Sstevel@tonic-gate #include <string.h>
35*0Sstevel@tonic-gate #include <ctype.h>
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate #ifdef MACOS
38*0Sstevel@tonic-gate #include <stdlib.h>
39*0Sstevel@tonic-gate #include "macos.h"
40*0Sstevel@tonic-gate #endif /* MACOS */
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate #if defined( DOS ) || defined( _WIN32 )
43*0Sstevel@tonic-gate #include <stdlib.h>
44*0Sstevel@tonic-gate #include <malloc.h>
45*0Sstevel@tonic-gate #include "msdos.h"
46*0Sstevel@tonic-gate #endif /* DOS || _WIN32 */
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #if !defined(MACOS) && !defined(DOS) && !defined( _WIN32 )
49*0Sstevel@tonic-gate #include <sys/time.h>
50*0Sstevel@tonic-gate #include <sys/types.h>
51*0Sstevel@tonic-gate #include <sys/socket.h>
52*0Sstevel@tonic-gate #endif /* !MACOS && !DOS && !_WIN32 */
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate #include "lber.h"
55*0Sstevel@tonic-gate #include "ldap.h"
56*0Sstevel@tonic-gate #include "ldap-private.h"
57*0Sstevel@tonic-gate #include "ldap-int.h"
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate #ifdef NEEDPROTOS
61*0Sstevel@tonic-gate static int skip_url_prefix( char **urlp, int *enclosedp );
62*0Sstevel@tonic-gate static void hex_unescape( char *s );
63*0Sstevel@tonic-gate static int unhex( char c );
64*0Sstevel@tonic-gate #else /* NEEDPROTOS */
65*0Sstevel@tonic-gate static int skip_url_prefix();
66*0Sstevel@tonic-gate static void hex_unescape();
67*0Sstevel@tonic-gate static int unhex();
68*0Sstevel@tonic-gate #endif /* NEEDPROTOS */
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate int
ldap_is_ldap_url(char * url)72*0Sstevel@tonic-gate ldap_is_ldap_url( char *url )
73*0Sstevel@tonic-gate {
74*0Sstevel@tonic-gate 	int	enclosed;
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate 	return( url != NULL && skip_url_prefix( &url, &enclosed ));
77*0Sstevel@tonic-gate }
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate static int
skip_url_prefix(char ** urlp,int * enclosedp)81*0Sstevel@tonic-gate skip_url_prefix( char **urlp, int *enclosedp )
82*0Sstevel@tonic-gate {
83*0Sstevel@tonic-gate /*
84*0Sstevel@tonic-gate  * return non-zero if this looks like a LDAP URL; zero if not
85*0Sstevel@tonic-gate  * if non-zero returned, *urlp will be moved past "ldap://" part of URL
86*0Sstevel@tonic-gate  */
87*0Sstevel@tonic-gate 	if ( *urlp == NULL ) {
88*0Sstevel@tonic-gate 		return( 0 );
89*0Sstevel@tonic-gate 	}
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 	/* skip leading '<' (if any) */
92*0Sstevel@tonic-gate 	if ( **urlp == '<' ) {
93*0Sstevel@tonic-gate 		*enclosedp = 1;
94*0Sstevel@tonic-gate 		++*urlp;
95*0Sstevel@tonic-gate 	} else {
96*0Sstevel@tonic-gate 		*enclosedp = 0;
97*0Sstevel@tonic-gate 	}
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate 	/* skip leading "URL:" (if any) */
100*0Sstevel@tonic-gate 	if ( strlen( *urlp ) >= LDAP_URL_URLCOLON_LEN && strncasecmp(
101*0Sstevel@tonic-gate 	    *urlp, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) {
102*0Sstevel@tonic-gate 		*urlp += LDAP_URL_URLCOLON_LEN;
103*0Sstevel@tonic-gate 	}
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate 	/* check for missing "ldap://" prefix */
106*0Sstevel@tonic-gate 	if ( strlen( *urlp ) < LDAP_URL_PREFIX_LEN ||
107*0Sstevel@tonic-gate 	    strncasecmp( *urlp, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) != 0 ) {
108*0Sstevel@tonic-gate 		return( 0 );
109*0Sstevel@tonic-gate 	}
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 	/* skip over "ldap://" prefix and return success */
112*0Sstevel@tonic-gate 	*urlp += LDAP_URL_PREFIX_LEN;
113*0Sstevel@tonic-gate 	return( 1 );
114*0Sstevel@tonic-gate }
115*0Sstevel@tonic-gate 
ldap_url_extension_parse(char * exts,LDAPURLExt *** lueppp)116*0Sstevel@tonic-gate int ldap_url_extension_parse( char *exts, LDAPURLExt *** lueppp)
117*0Sstevel@tonic-gate {
118*0Sstevel@tonic-gate 	/* Pick apart the pieces of an LDAP URL Extensions */
119*0Sstevel@tonic-gate 	/* No copy of exts is made, LDAPURLExt's points to exts string */
120*0Sstevel@tonic-gate 	LDAPURLExt ** lues;
121*0Sstevel@tonic-gate 	LDAPURLExt *luep;
122*0Sstevel@tonic-gate 	int i = 0;
123*0Sstevel@tonic-gate 	char *p = exts;
124*0Sstevel@tonic-gate 	char *ptr, *ptr2;
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 	*lueppp = NULL;
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	/* Count the number of , in extensions */
129*0Sstevel@tonic-gate 	while ( (p = strchr (p, ',')) != NULL){
130*0Sstevel@tonic-gate 		i++;
131*0Sstevel@tonic-gate 	}
132*0Sstevel@tonic-gate 	/* There are at most i+1 extensions */
133*0Sstevel@tonic-gate 	if ((lues = (LDAPURLExt **)calloc(i+2, sizeof(LDAPURLExt *))) == NULL){
134*0Sstevel@tonic-gate 		return (LDAP_URL_ERR_MEM);
135*0Sstevel@tonic-gate 	}
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 	p = exts;
138*0Sstevel@tonic-gate 	i = 0;
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 	while ( p ) {
141*0Sstevel@tonic-gate 		if ((ptr = strchr(p, ',')) != NULL)
142*0Sstevel@tonic-gate 			*ptr++ = '\0';
143*0Sstevel@tonic-gate 		else
144*0Sstevel@tonic-gate 			ptr = NULL;
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate 		if ((luep = (LDAPURLExt *)calloc(1, sizeof(LDAPURLExt))) == NULL){
147*0Sstevel@tonic-gate 			ldap_free_urlexts(lues);
148*0Sstevel@tonic-gate 			return (LDAP_URL_ERR_MEM);
149*0Sstevel@tonic-gate 		}
150*0Sstevel@tonic-gate 		lues[i] = luep;
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 		if (*p == '!'){
153*0Sstevel@tonic-gate 			luep->lue_iscritical = 1;
154*0Sstevel@tonic-gate 			p++;
155*0Sstevel@tonic-gate 		}
156*0Sstevel@tonic-gate 		luep->lue_type = p;
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 		if (( ptr2 = strchr(p, '=')) != NULL) {
159*0Sstevel@tonic-gate 			*ptr2++ = '\0';
160*0Sstevel@tonic-gate 			luep->lue_value = ptr2;
161*0Sstevel@tonic-gate 			hex_unescape(ptr2);
162*0Sstevel@tonic-gate 		}
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate 		i++;
165*0Sstevel@tonic-gate 		p = ptr;
166*0Sstevel@tonic-gate 	}
167*0Sstevel@tonic-gate 	*lueppp = lues;
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	return( 0 );
170*0Sstevel@tonic-gate }
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate int
ldap_url_parse(char * url,LDAPURLDesc ** ludpp)174*0Sstevel@tonic-gate ldap_url_parse( char *url, LDAPURLDesc **ludpp )
175*0Sstevel@tonic-gate {
176*0Sstevel@tonic-gate /*
177*0Sstevel@tonic-gate  *  Pick apart the pieces of an LDAP URL.
178*0Sstevel@tonic-gate  */
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	LDAPURLDesc	*ludp;
181*0Sstevel@tonic-gate 	char  *attrs = NULL;
182*0Sstevel@tonic-gate 	char  *p = NULL;
183*0Sstevel@tonic-gate 	char  *q = NULL;
184*0Sstevel@tonic-gate 	char  *x = NULL;
185*0Sstevel@tonic-gate 	int	  enclosed, i, nattrs, errcode;
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 262, "ldap_url_parse(%s)\n"), url, 0, 0 );
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	*ludpp = NULL;	/* pessimistic */
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate 	if ( !skip_url_prefix( &url, &enclosed )) {
192*0Sstevel@tonic-gate 		return( LDAP_URL_ERR_NOTLDAP );
193*0Sstevel@tonic-gate 	}
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	/* allocate return struct */
196*0Sstevel@tonic-gate 	if (( ludp = (LDAPURLDesc *)calloc( 1, sizeof( LDAPURLDesc )))
197*0Sstevel@tonic-gate 	    == NULLLDAPURLDESC ) {
198*0Sstevel@tonic-gate 		return( LDAP_URL_ERR_MEM );
199*0Sstevel@tonic-gate 	}
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 	ludp->lud_port = LDAP_PORT;
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 	/* make working copy of the remainder of the URL */
204*0Sstevel@tonic-gate 	if (( url = strdup( url )) == NULL ) {
205*0Sstevel@tonic-gate 		ldap_free_urldesc( ludp );
206*0Sstevel@tonic-gate 		return( LDAP_URL_ERR_MEM );
207*0Sstevel@tonic-gate 	}
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	if ( enclosed && *((p = url + strlen( url ) - 1)) == '>' ) {
210*0Sstevel@tonic-gate 		*p = '\0';
211*0Sstevel@tonic-gate 	}
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 	/* set defaults */
214*0Sstevel@tonic-gate 	/* LP By default don't set them... Then we can check if they are present or not in URL */
215*0Sstevel@tonic-gate 	ludp->lud_scope = LDAP_SCOPE_UNKNOWN;
216*0Sstevel@tonic-gate 	ludp->lud_filter = NULL;
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate 	/* lud_string is the only malloc'd string space we use */
220*0Sstevel@tonic-gate 	ludp->lud_string = url;
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 	/* scan forward for '/' that marks end of hostport and begin. of dn */
223*0Sstevel@tonic-gate 	if (( ludp->lud_dn = strchr( url, '/' )) != NULL ) {
224*0Sstevel@tonic-gate 		*ludp->lud_dn++ = '\0';
225*0Sstevel@tonic-gate 	}
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	/* terminate hostport; point to start of dn */
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	if (( p = strchr( url, ':' )) != NULL ) {
230*0Sstevel@tonic-gate 		*p++ = '\0';
231*0Sstevel@tonic-gate 		ludp->lud_port = atoi( p );
232*0Sstevel@tonic-gate 	}
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 	if ( *url == '\0' ) {
235*0Sstevel@tonic-gate 		ludp->lud_host = NULL;
236*0Sstevel@tonic-gate 	} else {
237*0Sstevel@tonic-gate 		ludp->lud_host = url;
238*0Sstevel@tonic-gate 		hex_unescape( ludp->lud_host );
239*0Sstevel@tonic-gate 	}
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 	if (ludp->lud_dn != NULL){
242*0Sstevel@tonic-gate 		/* scan for '?' that marks end of dn and beginning of attributes */
243*0Sstevel@tonic-gate 		if (( attrs = strchr( ludp->lud_dn, '?' )) != NULL ) {
244*0Sstevel@tonic-gate 			/* terminate dn; point to start of attrs. */
245*0Sstevel@tonic-gate 			*attrs++ = '\0';
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate 			/* scan for '?' that marks end of attrs and begin. of scope */
248*0Sstevel@tonic-gate 			if (( p = strchr( attrs, '?' )) != NULL ) {
249*0Sstevel@tonic-gate 				/*
250*0Sstevel@tonic-gate 				 * terminate attrs; point to start of scope and scan for
251*0Sstevel@tonic-gate 				 * '?' that marks end of scope and begin. of filter
252*0Sstevel@tonic-gate 				 */
253*0Sstevel@tonic-gate 				*p++ = '\0';
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate 				if (( q = strchr( p, '?' )) != NULL ) {
256*0Sstevel@tonic-gate 					/* terminate scope; point to start of filter */
257*0Sstevel@tonic-gate 					*q++ = '\0';
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate 					if (( x = strchr(q, '?')) != NULL ) {
260*0Sstevel@tonic-gate 						/* terminate filter; point to start of extension */
261*0Sstevel@tonic-gate 						*x++ = '\0';
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 						if (*x != '\0'){
264*0Sstevel@tonic-gate 							/* parse extensions */
265*0Sstevel@tonic-gate 						}
266*0Sstevel@tonic-gate 					}
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 					if ( *q != '\0' ) {
269*0Sstevel@tonic-gate 						ludp->lud_filter = q;
270*0Sstevel@tonic-gate 						hex_unescape( ludp->lud_filter );
271*0Sstevel@tonic-gate 					}
272*0Sstevel@tonic-gate 			}
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 				if ( strcasecmp( p, "one" ) == 0 ) {
275*0Sstevel@tonic-gate 					ludp->lud_scope = LDAP_SCOPE_ONELEVEL;
276*0Sstevel@tonic-gate 				} else if ( strcasecmp( p, "base" ) == 0 ) {
277*0Sstevel@tonic-gate 					ludp->lud_scope = LDAP_SCOPE_BASE;
278*0Sstevel@tonic-gate 				} else if ( strcasecmp( p, "sub" ) == 0 ) {
279*0Sstevel@tonic-gate 					ludp->lud_scope = LDAP_SCOPE_SUBTREE;
280*0Sstevel@tonic-gate 				} else if ( *p != '\0' ) {
281*0Sstevel@tonic-gate 					ldap_free_urldesc( ludp );
282*0Sstevel@tonic-gate 					return( LDAP_URL_ERR_BADSCOPE );
283*0Sstevel@tonic-gate 				}
284*0Sstevel@tonic-gate 			}
285*0Sstevel@tonic-gate 		}
286*0Sstevel@tonic-gate 		if ( *ludp->lud_dn == '\0' ) {
287*0Sstevel@tonic-gate 			ludp->lud_dn = NULL;
288*0Sstevel@tonic-gate 		} else {
289*0Sstevel@tonic-gate 			hex_unescape( ludp->lud_dn );
290*0Sstevel@tonic-gate 		}
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 		/*
293*0Sstevel@tonic-gate 		 * if attrs list was included, turn it into a null-terminated array
294*0Sstevel@tonic-gate 		 */
295*0Sstevel@tonic-gate 		if ( attrs != NULL && *attrs != '\0' ) {
296*0Sstevel@tonic-gate 			for ( nattrs = 1, p = attrs; *p != '\0'; ++p ) {
297*0Sstevel@tonic-gate 				if ( *p == ',' ) {
298*0Sstevel@tonic-gate 					++nattrs;
299*0Sstevel@tonic-gate 				}
300*0Sstevel@tonic-gate 		}
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 			if (( ludp->lud_attrs = (char **)calloc( nattrs + 1,
303*0Sstevel@tonic-gate 													 sizeof( char * ))) == NULL ) {
304*0Sstevel@tonic-gate 				ldap_free_urldesc( ludp );
305*0Sstevel@tonic-gate 				return( LDAP_URL_ERR_MEM );
306*0Sstevel@tonic-gate 			}
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 			for ( i = 0, p = attrs; i < nattrs; ++i ) {
309*0Sstevel@tonic-gate 				ludp->lud_attrs[ i ] = p;
310*0Sstevel@tonic-gate 				if (( p = strchr( p, ',' )) != NULL ) {
311*0Sstevel@tonic-gate 				*p++ ='\0';
312*0Sstevel@tonic-gate 				}
313*0Sstevel@tonic-gate 				hex_unescape( ludp->lud_attrs[ i ] );
314*0Sstevel@tonic-gate 			}
315*0Sstevel@tonic-gate 		}
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 		if (x != NULL && *x != '\0'){
318*0Sstevel@tonic-gate 			if (errcode = ldap_url_extension_parse(x, &ludp->lud_extensions)){
319*0Sstevel@tonic-gate 				ldap_free_urldesc(ludp);
320*0Sstevel@tonic-gate 				return ( errcode );
321*0Sstevel@tonic-gate 			}
322*0Sstevel@tonic-gate 		}
323*0Sstevel@tonic-gate 	}
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	*ludpp = ludp;
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	return( 0 );
328*0Sstevel@tonic-gate }
329*0Sstevel@tonic-gate 
ldap_free_urlexts(LDAPURLExt ** lues)330*0Sstevel@tonic-gate void ldap_free_urlexts( LDAPURLExt ** lues)
331*0Sstevel@tonic-gate {
332*0Sstevel@tonic-gate 	int i;
333*0Sstevel@tonic-gate 	for (i = 0; lues[i] != NULL; i++){
334*0Sstevel@tonic-gate 		free(lues[i]);
335*0Sstevel@tonic-gate 	}
336*0Sstevel@tonic-gate 	free(lues);
337*0Sstevel@tonic-gate }
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate void
ldap_free_urldesc(LDAPURLDesc * ludp)341*0Sstevel@tonic-gate ldap_free_urldesc( LDAPURLDesc *ludp )
342*0Sstevel@tonic-gate {
343*0Sstevel@tonic-gate 	if ( ludp != NULLLDAPURLDESC ) {
344*0Sstevel@tonic-gate 		if ( ludp->lud_string != NULL ) {
345*0Sstevel@tonic-gate 			free( ludp->lud_string );
346*0Sstevel@tonic-gate 		}
347*0Sstevel@tonic-gate 		if ( ludp->lud_attrs != NULL ) {
348*0Sstevel@tonic-gate 			free( ludp->lud_attrs );
349*0Sstevel@tonic-gate 		}
350*0Sstevel@tonic-gate 		if (ludp->lud_extensions != NULL) {
351*0Sstevel@tonic-gate 			ldap_free_urlexts(ludp->lud_extensions);
352*0Sstevel@tonic-gate 		}
353*0Sstevel@tonic-gate 		free( ludp );
354*0Sstevel@tonic-gate 	}
355*0Sstevel@tonic-gate }
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate int
ldap_url_search(LDAP * ld,char * url,int attrsonly)360*0Sstevel@tonic-gate ldap_url_search( LDAP *ld, char *url, int attrsonly )
361*0Sstevel@tonic-gate {
362*0Sstevel@tonic-gate 	int		err;
363*0Sstevel@tonic-gate 	LDAPURLDesc	*ludp;
364*0Sstevel@tonic-gate 	BerElement	*ber;
365*0Sstevel@tonic-gate 	LDAPServer	*srv = NULL;
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate #ifdef _REENTRANT
368*0Sstevel@tonic-gate         LOCK_LDAP(ld);
369*0Sstevel@tonic-gate #endif
370*0Sstevel@tonic-gate 	if ( ldap_url_parse( url, &ludp ) != 0 ) {
371*0Sstevel@tonic-gate 		ld->ld_errno = LDAP_PARAM_ERROR;
372*0Sstevel@tonic-gate #ifdef _REENTRANT
373*0Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
374*0Sstevel@tonic-gate #endif
375*0Sstevel@tonic-gate 		return( -1 );
376*0Sstevel@tonic-gate 	}
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	if (( ber = ldap_build_search_req( ld, ludp->lud_dn,
379*0Sstevel@tonic-gate 									   ludp->lud_scope == LDAP_SCOPE_UNKNOWN ? LDAP_SCOPE_BASE : ludp->lud_scope,
380*0Sstevel@tonic-gate 									   ludp->lud_filter ? ludp->lud_filter : "(objectclass=*)",
381*0Sstevel@tonic-gate 									   ludp->lud_attrs, attrsonly, NULL, NULL, -1 )) == NULLBER ) {
382*0Sstevel@tonic-gate #ifdef _REENTRANT
383*0Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
384*0Sstevel@tonic-gate #endif
385*0Sstevel@tonic-gate 		return( -1 );
386*0Sstevel@tonic-gate 	}
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	err = 0;
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 	if ( ludp->lud_host != NULL || ludp->lud_port != 0 ) {
391*0Sstevel@tonic-gate 		if (( srv = (LDAPServer *)calloc( 1, sizeof( LDAPServer )))
392*0Sstevel@tonic-gate 		    == NULL || ( srv->lsrv_host = strdup( ludp->lud_host ==
393*0Sstevel@tonic-gate 		    NULL ? ld->ld_defhost : ludp->lud_host )) == NULL ) {
394*0Sstevel@tonic-gate 			if ( srv != NULL ) {
395*0Sstevel@tonic-gate 				free( srv );
396*0Sstevel@tonic-gate 			}
397*0Sstevel@tonic-gate 			ld->ld_errno = LDAP_NO_MEMORY;
398*0Sstevel@tonic-gate 			err = -1;
399*0Sstevel@tonic-gate 		} else {
400*0Sstevel@tonic-gate 			if ( ludp->lud_port == 0 ) {
401*0Sstevel@tonic-gate 				srv->lsrv_port = LDAP_PORT;
402*0Sstevel@tonic-gate 			} else {
403*0Sstevel@tonic-gate 				 srv->lsrv_port = ludp->lud_port;
404*0Sstevel@tonic-gate 			}
405*0Sstevel@tonic-gate 		}
406*0Sstevel@tonic-gate 	}
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 	if ( err != 0 ) {
409*0Sstevel@tonic-gate 		ber_free( ber, 1 );
410*0Sstevel@tonic-gate 	} else {
411*0Sstevel@tonic-gate 		err = send_server_request( ld, ber, ld->ld_msgid, NULL, srv, NULL, 1 );
412*0Sstevel@tonic-gate 	}
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	ldap_free_urldesc( ludp );
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate #ifdef _REENTRANT
417*0Sstevel@tonic-gate         UNLOCK_LDAP(ld);
418*0Sstevel@tonic-gate #endif
419*0Sstevel@tonic-gate 	return( err );
420*0Sstevel@tonic-gate }
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate int
ldap_url_search_st(LDAP * ld,char * url,int attrsonly,struct timeval * timeout,LDAPMessage ** res)424*0Sstevel@tonic-gate ldap_url_search_st( LDAP *ld, char *url, int attrsonly,
425*0Sstevel@tonic-gate 	struct timeval *timeout, LDAPMessage **res )
426*0Sstevel@tonic-gate {
427*0Sstevel@tonic-gate 	int	msgid;
428*0Sstevel@tonic-gate 	int retcode = LDAP_SUCCESS;
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 	if (( msgid = ldap_url_search( ld, url, attrsonly )) == -1 ) {
431*0Sstevel@tonic-gate 		return( ld->ld_errno );
432*0Sstevel@tonic-gate 	}
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 	if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 ) {
435*0Sstevel@tonic-gate 		return( ld->ld_errno );
436*0Sstevel@tonic-gate 	}
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate 	if ( ld->ld_errno == LDAP_TIMEOUT ) {
439*0Sstevel@tonic-gate 		(void) ldap_abandon( ld, msgid );
440*0Sstevel@tonic-gate 		ld->ld_errno = LDAP_TIMEOUT;
441*0Sstevel@tonic-gate 		return( ld->ld_errno );
442*0Sstevel@tonic-gate 	}
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate #ifdef  _REENTRANT
445*0Sstevel@tonic-gate 	LOCK_LDAP(ld);
446*0Sstevel@tonic-gate #endif
447*0Sstevel@tonic-gate 	retcode = ldap_parse_result(ld, *res, &ld->ld_errno, &ld->ld_matched, &ld->ld_error,
448*0Sstevel@tonic-gate 								&ld->ld_referrals, &ld->ld_ret_ctrls, 0);
449*0Sstevel@tonic-gate 	if (retcode == LDAP_SUCCESS)
450*0Sstevel@tonic-gate 		retcode = ld->ld_errno;
451*0Sstevel@tonic-gate #ifdef  _REENTRANT
452*0Sstevel@tonic-gate 	UNLOCK_LDAP(ld);
453*0Sstevel@tonic-gate #endif
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 	return (retcode);
456*0Sstevel@tonic-gate }
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate int
ldap_url_search_s(LDAP * ld,char * url,int attrsonly,LDAPMessage ** res)460*0Sstevel@tonic-gate ldap_url_search_s( LDAP *ld, char *url, int attrsonly, LDAPMessage **res )
461*0Sstevel@tonic-gate {
462*0Sstevel@tonic-gate 	int	msgid;
463*0Sstevel@tonic-gate 	int retcode = LDAP_SUCCESS;
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	if (( msgid = ldap_url_search( ld, url, attrsonly )) == -1 ) {
466*0Sstevel@tonic-gate 		return( ld->ld_errno );
467*0Sstevel@tonic-gate 	}
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate 	if ( ldap_result( ld, msgid, 1, (struct timeval *)NULL, res ) == -1 ) {
470*0Sstevel@tonic-gate 		return( ld->ld_errno );
471*0Sstevel@tonic-gate 	}
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate #ifdef  _REENTRANT
474*0Sstevel@tonic-gate 	LOCK_LDAP(ld);
475*0Sstevel@tonic-gate #endif
476*0Sstevel@tonic-gate 	retcode = ldap_parse_result(ld, *res, &ld->ld_errno, &ld->ld_matched, &ld->ld_error,
477*0Sstevel@tonic-gate 								&ld->ld_referrals, &ld->ld_ret_ctrls, 0);
478*0Sstevel@tonic-gate 	if (retcode == LDAP_SUCCESS)
479*0Sstevel@tonic-gate 		retcode = ld->ld_errno;
480*0Sstevel@tonic-gate #ifdef  _REENTRANT
481*0Sstevel@tonic-gate 	UNLOCK_LDAP(ld);
482*0Sstevel@tonic-gate #endif
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 	return (retcode);
485*0Sstevel@tonic-gate }
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate static void
hex_unescape(char * s)489*0Sstevel@tonic-gate hex_unescape( char *s )
490*0Sstevel@tonic-gate {
491*0Sstevel@tonic-gate /*
492*0Sstevel@tonic-gate  * Remove URL hex escapes from s... done in place.  The basic concept for
493*0Sstevel@tonic-gate  * this routine is borrowed from the WWW library HTUnEscape() routine.
494*0Sstevel@tonic-gate  */
495*0Sstevel@tonic-gate 	char	*p;
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 	for ( p = s; *s != '\0'; ++s ) {
498*0Sstevel@tonic-gate 		if ( *s == '%' ) {
499*0Sstevel@tonic-gate 			if ( *++s != '\0' ) {
500*0Sstevel@tonic-gate 				*p = unhex( *s ) << 4;
501*0Sstevel@tonic-gate 			}
502*0Sstevel@tonic-gate 			if ( *++s != '\0' ) {
503*0Sstevel@tonic-gate 				*p++ += unhex( *s );
504*0Sstevel@tonic-gate 			}
505*0Sstevel@tonic-gate 		} else {
506*0Sstevel@tonic-gate 			*p++ = *s;
507*0Sstevel@tonic-gate 		}
508*0Sstevel@tonic-gate 	}
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 	*p = '\0';
511*0Sstevel@tonic-gate }
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate static int
unhex(char c)515*0Sstevel@tonic-gate unhex( char c )
516*0Sstevel@tonic-gate {
517*0Sstevel@tonic-gate 	return( c >= '0' && c <= '9' ? c - '0'
518*0Sstevel@tonic-gate 	    : c >= 'A' && c <= 'F' ? c - 'A' + 10
519*0Sstevel@tonic-gate 	    : c - 'a' + 10 );
520*0Sstevel@tonic-gate }
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate /*
524*0Sstevel@tonic-gate  * Locate the LDAP URL associated with a DNS domain name.
525*0Sstevel@tonic-gate  *
526*0Sstevel@tonic-gate  * The supplied DNS domain name is converted into a distinguished
527*0Sstevel@tonic-gate  * name. The directory entry specified by that distinguished name
528*0Sstevel@tonic-gate  * is searched for a labeledURI attribute. If successful then the
529*0Sstevel@tonic-gate  * LDAP URL is returned. If unsuccessful then that entry's parent
530*0Sstevel@tonic-gate  * is searched and so on until the target distinguished name is
531*0Sstevel@tonic-gate  * reduced to only two nameparts.
532*0Sstevel@tonic-gate  *
533*0Sstevel@tonic-gate  * For example, if 'ny.eng.wiz.com' is the DNS domain then the
534*0Sstevel@tonic-gate  * following entries are searched until one succeeds:
535*0Sstevel@tonic-gate  * 		dc=ny,dc=eng,dc=wiz,dc=com
536*0Sstevel@tonic-gate  * 		dc=eng,dc=wiz,dc=com
537*0Sstevel@tonic-gate  * 		dc=wiz,dc=com
538*0Sstevel@tonic-gate  *
539*0Sstevel@tonic-gate  * If dns_name is NULL then the environment variable LOCALDOMAIN is used.
540*0Sstevel@tonic-gate  * If attrs is not NULL then it is appended to the URL's attribute list.
541*0Sstevel@tonic-gate  * If scope is not NULL then it overrides the URL's scope.
542*0Sstevel@tonic-gate  * If filter is not NULL then it is merged with the URL's filter.
543*0Sstevel@tonic-gate  *
544*0Sstevel@tonic-gate  * If an error is encountered then zero is returned, otherwise a string
545*0Sstevel@tonic-gate  * URL is returned. The caller should free the returned string if it is
546*0Sstevel@tonic-gate  * non-zero.
547*0Sstevel@tonic-gate  */
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate char *
ldap_dns_to_url(LDAP * ld,char * dns_name,char * attrs,char * scope,char * filter)550*0Sstevel@tonic-gate ldap_dns_to_url(
551*0Sstevel@tonic-gate 	LDAP	*ld,
552*0Sstevel@tonic-gate 	char	*dns_name,
553*0Sstevel@tonic-gate 	char	*attrs,
554*0Sstevel@tonic-gate 	char	*scope,
555*0Sstevel@tonic-gate 	char	*filter
556*0Sstevel@tonic-gate )
557*0Sstevel@tonic-gate {
558*0Sstevel@tonic-gate 	char		*dn;
559*0Sstevel@tonic-gate 	char		*url = 0;
560*0Sstevel@tonic-gate 	char		*url2 = 0;
561*0Sstevel@tonic-gate 	LDAPURLDesc	*urldesc;
562*0Sstevel@tonic-gate 	char		*cp;
563*0Sstevel@tonic-gate 	char		*cp2;
564*0Sstevel@tonic-gate 	size_t		attrs_len = 0;
565*0Sstevel@tonic-gate 	size_t		scope_len = 0;
566*0Sstevel@tonic-gate 	size_t		filter_len = 0;
567*0Sstevel@tonic-gate 	int		nameparts;
568*0Sstevel@tonic-gate 	int		no_attrs = 0;
569*0Sstevel@tonic-gate 	int		no_scope = 0;
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 	if (dns_name == 0) {
572*0Sstevel@tonic-gate 		dns_name = (char *)getenv("LOCALDOMAIN");
573*0Sstevel@tonic-gate 	}
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate 	if ((ld == NULL) || ((dn = ldap_dns_to_dn(dns_name, &nameparts)) ==
576*0Sstevel@tonic-gate 	    NULL))
577*0Sstevel@tonic-gate 		return (0);
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate 	if ((url = ldap_dn_to_url(ld, dn, nameparts)) == NULL) {
580*0Sstevel@tonic-gate 		free(dn);
581*0Sstevel@tonic-gate 		return (0);
582*0Sstevel@tonic-gate 	}
583*0Sstevel@tonic-gate 	free(dn);
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 	/* merge filter and/or scope and/or attributes with URL */
586*0Sstevel@tonic-gate 	if (attrs || scope || filter) {
587*0Sstevel@tonic-gate 
588*0Sstevel@tonic-gate 		if (attrs)
589*0Sstevel@tonic-gate 			attrs_len = strlen(attrs) + 2; /* for comma and NULL */
590*0Sstevel@tonic-gate 
591*0Sstevel@tonic-gate 		if (scope)
592*0Sstevel@tonic-gate 			scope_len = strlen(scope) + 1; /* for NULL */
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate 		if (filter)
595*0Sstevel@tonic-gate 			filter_len = strlen(filter) + 4;
596*0Sstevel@tonic-gate 			    /* for ampersand, parentheses and NULL */
597*0Sstevel@tonic-gate 
598*0Sstevel@tonic-gate 		if (ldap_is_ldap_url(url)) {
599*0Sstevel@tonic-gate 
600*0Sstevel@tonic-gate 			if ((url2 = (char *)malloc(attrs_len + scope_len +
601*0Sstevel@tonic-gate 			    filter_len + strlen(url) + 1)) == NULL) {
602*0Sstevel@tonic-gate 				return (0);
603*0Sstevel@tonic-gate 			}
604*0Sstevel@tonic-gate 			cp = url;
605*0Sstevel@tonic-gate 			cp2 = url2;
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate 			/* copy URL scheme, hostname, port number and DN */
608*0Sstevel@tonic-gate 			while (*cp && (*cp != '?')) {
609*0Sstevel@tonic-gate 				*cp2++ = *cp++;
610*0Sstevel@tonic-gate 			}
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate 			/* handle URL attributes */
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate 			if (*cp == '?') {	/* test first '?' */
615*0Sstevel@tonic-gate 				*cp2++ = *cp++; /* copy first '?' */
616*0Sstevel@tonic-gate 
617*0Sstevel@tonic-gate 				if (*cp == '?') {	/* test second '?' */
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 					/* insert supplied attributes */
620*0Sstevel@tonic-gate 					if (attrs) {
621*0Sstevel@tonic-gate 						while (*attrs) {
622*0Sstevel@tonic-gate 							*cp2++ = *attrs++;
623*0Sstevel@tonic-gate 						}
624*0Sstevel@tonic-gate 					} else {
625*0Sstevel@tonic-gate 						no_attrs = 1;
626*0Sstevel@tonic-gate 					}
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate 				} else {
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate 					/* copy URL attributes */
631*0Sstevel@tonic-gate 					while (*cp && (*cp != '?')) {
632*0Sstevel@tonic-gate 						*cp2++ = *cp++;
633*0Sstevel@tonic-gate 					}
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 					/* append supplied attributes */
636*0Sstevel@tonic-gate 					if (attrs) {
637*0Sstevel@tonic-gate 						*cp2++ = ',';
638*0Sstevel@tonic-gate 						while (*attrs) {
639*0Sstevel@tonic-gate 							*cp2++ = *attrs++;
640*0Sstevel@tonic-gate 						}
641*0Sstevel@tonic-gate 					}
642*0Sstevel@tonic-gate 				}
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate 			} else {
645*0Sstevel@tonic-gate 				/* append supplied attributes */
646*0Sstevel@tonic-gate 				if (attrs) {
647*0Sstevel@tonic-gate 					*cp2++ = '?';
648*0Sstevel@tonic-gate 					while (*attrs) {
649*0Sstevel@tonic-gate 						*cp2++ = *attrs++;
650*0Sstevel@tonic-gate 					}
651*0Sstevel@tonic-gate 				} else {
652*0Sstevel@tonic-gate 					no_attrs = 1;
653*0Sstevel@tonic-gate 				}
654*0Sstevel@tonic-gate 			}
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 			/* handle URL scope */
657*0Sstevel@tonic-gate 
658*0Sstevel@tonic-gate 			if (*cp == '?') {	/* test second '?' */
659*0Sstevel@tonic-gate 				*cp2++ = *cp++; /* copy second '?' */
660*0Sstevel@tonic-gate 
661*0Sstevel@tonic-gate 				if (*cp == '?') {	/* test third '?' */
662*0Sstevel@tonic-gate 
663*0Sstevel@tonic-gate 					/* insert supplied scope */
664*0Sstevel@tonic-gate 					if (scope) {
665*0Sstevel@tonic-gate 						while (*scope) {
666*0Sstevel@tonic-gate 							*cp2++ = *scope++;
667*0Sstevel@tonic-gate 						}
668*0Sstevel@tonic-gate 					} else {
669*0Sstevel@tonic-gate 						no_scope = 1;
670*0Sstevel@tonic-gate 					}
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 				} else {
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate 					if (scope) {
675*0Sstevel@tonic-gate 						/* skip over URL scope */
676*0Sstevel@tonic-gate 						while (*cp && (*cp != '?')) {
677*0Sstevel@tonic-gate 							*cp++;
678*0Sstevel@tonic-gate 						}
679*0Sstevel@tonic-gate 						/* insert supplied scope */
680*0Sstevel@tonic-gate 						while (*scope) {
681*0Sstevel@tonic-gate 							*cp2++ = *scope++;
682*0Sstevel@tonic-gate 						}
683*0Sstevel@tonic-gate 					} else {
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 						/* copy URL scope */
686*0Sstevel@tonic-gate 						while (*cp && (*cp != '?')) {
687*0Sstevel@tonic-gate 							*cp2++ = *cp++;
688*0Sstevel@tonic-gate 						}
689*0Sstevel@tonic-gate 					}
690*0Sstevel@tonic-gate 				}
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate 			} else {
693*0Sstevel@tonic-gate 				/* append supplied scope */
694*0Sstevel@tonic-gate 				if (scope) {
695*0Sstevel@tonic-gate 					if (no_attrs) {
696*0Sstevel@tonic-gate 						*cp2++ = '?';
697*0Sstevel@tonic-gate 					}
698*0Sstevel@tonic-gate 					*cp2++ = '?';
699*0Sstevel@tonic-gate 					while (*scope) {
700*0Sstevel@tonic-gate 						*cp2++ = *scope++;
701*0Sstevel@tonic-gate 					}
702*0Sstevel@tonic-gate 				} else {
703*0Sstevel@tonic-gate 					no_scope = 1;
704*0Sstevel@tonic-gate 				}
705*0Sstevel@tonic-gate 			}
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate 			/* handle URL filter */
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate 			if (*cp == '?') {	/* test third '?' */
710*0Sstevel@tonic-gate 				*cp2++ = *cp++; /* copy third '?' */
711*0Sstevel@tonic-gate 
712*0Sstevel@tonic-gate 				if (filter) {
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate 					/* merge URL and supplied filters */
715*0Sstevel@tonic-gate 
716*0Sstevel@tonic-gate 					*cp2++ = '(';
717*0Sstevel@tonic-gate 					*cp2++ = '&';
718*0Sstevel@tonic-gate 					/* copy URL filter */
719*0Sstevel@tonic-gate 					while (*cp) {
720*0Sstevel@tonic-gate 						*cp2++ = *cp++;
721*0Sstevel@tonic-gate 					}
722*0Sstevel@tonic-gate 					/* append supplied filter */
723*0Sstevel@tonic-gate 					while (*filter) {
724*0Sstevel@tonic-gate 						*cp2++ = *filter++;
725*0Sstevel@tonic-gate 					}
726*0Sstevel@tonic-gate 					*cp2++ = ')';
727*0Sstevel@tonic-gate 				} else {
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate 					/* copy URL filter */
730*0Sstevel@tonic-gate 					while (*cp) {
731*0Sstevel@tonic-gate 						*cp2++ = *cp++;
732*0Sstevel@tonic-gate 					}
733*0Sstevel@tonic-gate 				}
734*0Sstevel@tonic-gate 
735*0Sstevel@tonic-gate 			} else {
736*0Sstevel@tonic-gate 				/* append supplied filter */
737*0Sstevel@tonic-gate 				if (filter) {
738*0Sstevel@tonic-gate 					if (no_scope) {
739*0Sstevel@tonic-gate 						if (no_attrs) {
740*0Sstevel@tonic-gate 							*cp2++ = '?';
741*0Sstevel@tonic-gate 						}
742*0Sstevel@tonic-gate 						*cp2++ = '?';
743*0Sstevel@tonic-gate 					}
744*0Sstevel@tonic-gate 					*cp2++ = '?';
745*0Sstevel@tonic-gate 					while (*filter) {
746*0Sstevel@tonic-gate 						*cp2++ = *filter++;
747*0Sstevel@tonic-gate 					}
748*0Sstevel@tonic-gate 				}
749*0Sstevel@tonic-gate 			}
750*0Sstevel@tonic-gate 
751*0Sstevel@tonic-gate 			*cp2++ = '\0';
752*0Sstevel@tonic-gate 			free (url);
753*0Sstevel@tonic-gate 			url = url2;
754*0Sstevel@tonic-gate 
755*0Sstevel@tonic-gate 		} else {
756*0Sstevel@tonic-gate 			return (0);	/* not an LDAP URL */
757*0Sstevel@tonic-gate 		}
758*0Sstevel@tonic-gate 	}
759*0Sstevel@tonic-gate 	return (url);
760*0Sstevel@tonic-gate }
761*0Sstevel@tonic-gate 
762*0Sstevel@tonic-gate 
763*0Sstevel@tonic-gate /*
764*0Sstevel@tonic-gate  * Locate the LDAP URL associated with a distinguished name.
765*0Sstevel@tonic-gate  *
766*0Sstevel@tonic-gate  * The number of nameparts in the supplied distinguished name must be
767*0Sstevel@tonic-gate  * provided. The specified directory entry is searched for a labeledURI
768*0Sstevel@tonic-gate  * attribute. If successful then the LDAP URL is returned. If unsuccessful
769*0Sstevel@tonic-gate  * then that entry's parent is searched and so on until the target
770*0Sstevel@tonic-gate  * distinguished name is reduced to only two nameparts.
771*0Sstevel@tonic-gate  *
772*0Sstevel@tonic-gate  * For example, if 'l=ny,ou=eng,o=wiz,c=us' is the distinguished name
773*0Sstevel@tonic-gate  * then the following entries are searched until one succeeds:
774*0Sstevel@tonic-gate  * 		l=ny,ou=eng,o=wiz,c=us
775*0Sstevel@tonic-gate  * 		ou=eng,o=wiz,c=us
776*0Sstevel@tonic-gate  * 		o=wiz,c=us
777*0Sstevel@tonic-gate  *
778*0Sstevel@tonic-gate  * If an error is encountered then zero is returned, otherwise a string
779*0Sstevel@tonic-gate  * URL is returned. The caller should free the returned string if it is
780*0Sstevel@tonic-gate  * non-zero.
781*0Sstevel@tonic-gate  */
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate char *
ldap_dn_to_url(LDAP * ld,char * dn,int nameparts)784*0Sstevel@tonic-gate ldap_dn_to_url(
785*0Sstevel@tonic-gate 	LDAP	*ld,
786*0Sstevel@tonic-gate 	char	*dn,
787*0Sstevel@tonic-gate 	int	nameparts
788*0Sstevel@tonic-gate )
789*0Sstevel@tonic-gate {
790*0Sstevel@tonic-gate 	char		*next_dn = dn;
791*0Sstevel@tonic-gate 	char		*url = 0;
792*0Sstevel@tonic-gate 	char		*attrs[2] = {"labeledURI", 0};
793*0Sstevel@tonic-gate 	LDAPMessage	*res, *e;
794*0Sstevel@tonic-gate 	char		**vals;
795*0Sstevel@tonic-gate 
796*0Sstevel@tonic-gate 	/*
797*0Sstevel@tonic-gate 	 * Search for a URL in the named entry or its parent entry.
798*0Sstevel@tonic-gate 	 * Continue until only 2 nameparts remain.
799*0Sstevel@tonic-gate 	 */
800*0Sstevel@tonic-gate 	while (dn && (nameparts > 1) && (! url)) {
801*0Sstevel@tonic-gate 
802*0Sstevel@tonic-gate 		/* search for the labeledURI attribute */
803*0Sstevel@tonic-gate 		if (ldap_search_s(ld, dn, LDAP_SCOPE_BASE,
804*0Sstevel@tonic-gate 		    "(objectClass=*)", attrs, 0, &res) == LDAP_SUCCESS) {
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate 			/* locate the first entry returned */
807*0Sstevel@tonic-gate 			if ((e = ldap_first_entry(ld, res)) != NULL) {
808*0Sstevel@tonic-gate 
809*0Sstevel@tonic-gate 				/* locate the labeledURI attribute */
810*0Sstevel@tonic-gate 				if ((vals =
811*0Sstevel@tonic-gate 				    ldap_get_values(ld, e, "labeledURI")) !=
812*0Sstevel@tonic-gate 				    NULL) {
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate 					/* copy the attribute value */
815*0Sstevel@tonic-gate 					if ((url = strdup((char *)vals[0])) !=
816*0Sstevel@tonic-gate 					    NULL) {
817*0Sstevel@tonic-gate 						ldap_value_free(vals);
818*0Sstevel@tonic-gate 					}
819*0Sstevel@tonic-gate 				}
820*0Sstevel@tonic-gate 			}
821*0Sstevel@tonic-gate 			/* free the search results */
822*0Sstevel@tonic-gate 			ldap_msgfree(res);
823*0Sstevel@tonic-gate 		}
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 		if (! url) {
826*0Sstevel@tonic-gate 			/* advance along the DN by one namepart */
827*0Sstevel@tonic-gate 			if (next_dn = strchr(dn, ',')) {
828*0Sstevel@tonic-gate 				next_dn++;
829*0Sstevel@tonic-gate 				dn = next_dn;
830*0Sstevel@tonic-gate 				nameparts--;
831*0Sstevel@tonic-gate 			}
832*0Sstevel@tonic-gate 		}
833*0Sstevel@tonic-gate 	}
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	return (url);
836*0Sstevel@tonic-gate }
837