]> git.sur5r.net Git - openldap/blob - libraries/libldap/url.c
Changed lc_conn to be a pointer to a BerElement to aid in state management.
[openldap] / libraries / libldap / url.c
1 /*
2  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
3  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
4  */
5 /*  Portions
6  *  Copyright (c) 1996 Regents of the University of Michigan.
7  *  All rights reserved.
8  *
9  *  LIBLDAP url.c -- LDAP URL related routines
10  *
11  *  LDAP URLs look like this:
12  *    l d a p : / / hostport / dn [ ? attributes [ ? scope [ ? filter ] ] ]
13  *
14  *  where:
15  *   attributes is a comma separated list
16  *   scope is one of these three strings:  base one sub (default=base)
17  *   filter is an string-represented filter as in RFC 1558
18  *
19  *  e.g.,  ldap://ldap.itd.umich.edu/c=US?o,description?one?o=umich
20  *
21  *  We also tolerate URLs that look like: <ldapurl> and <URL:ldapurl>
22  */
23
24 #include "portable.h"
25
26 #include <stdio.h>
27 #include <stdlib.h>
28
29 #include <ac/ctype.h>
30 #include <ac/socket.h>
31 #include <ac/string.h>
32 #include <ac/time.h>
33
34 #include "ldap-int.h"
35
36
37 /* local functions */
38 static const char* skip_url_prefix LDAP_P(( const char *url, int *enclosedp ));
39 static void hex_unescape LDAP_P(( char *s ));
40 static int unhex( char c );
41
42
43 int
44 ldap_is_ldap_url( LDAP_CONST char *url )
45 {
46         int     enclosed;
47
48         return( url != NULL && skip_url_prefix( url, &enclosed ) != NULL );
49 }
50
51
52 static const char*
53 skip_url_prefix( const char *url, int *enclosedp )
54 {
55 /*
56  * return non-zero if this looks like a LDAP URL; zero if not
57  * if non-zero returned, *urlp will be moved past "ldap://" part of URL
58  */
59         char* p;
60
61         if ( url == NULL ) {
62                 return( NULL );
63         }
64
65         p = (char *) url;
66
67         /* skip leading '<' (if any) */
68         if ( *p == '<' ) {
69                 *enclosedp = 1;
70                 ++p;
71         } else {
72                 *enclosedp = 0;
73         }
74
75         /* skip leading "URL:" (if any) */
76         if ( strlen( p ) >= LDAP_URL_URLCOLON_LEN
77                 && strncasecmp( p, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 )
78         {
79                 p += LDAP_URL_URLCOLON_LEN;
80         }
81
82         /* check for missing "ldap://" prefix */
83         if ( strlen( p ) < LDAP_URL_PREFIX_LEN ||
84             strncasecmp( p, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) != 0 ) {
85                 return( NULL );
86         }
87
88         /* skip over "ldap://" prefix and return success */
89         p += LDAP_URL_PREFIX_LEN;
90         return( p );
91 }
92
93
94
95 int
96 ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp )
97 {
98 /*
99  *  Pick apart the pieces of an LDAP URL.
100  */
101
102         LDAPURLDesc     *ludp;
103         char            *attrs, *p, *q;
104         int             enclosed, i, nattrs;
105         const char *url_tmp;
106         char *url;
107
108         Debug( LDAP_DEBUG_TRACE, "ldap_url_parse(%s)\n", url_in, 0, 0 );
109
110         *ludpp = NULL;  /* pessimistic */
111
112         url_tmp = skip_url_prefix( url_in, &enclosed );
113
114         if ( url_tmp == NULL ) {
115                 return( LDAP_URL_ERR_NOTLDAP );
116         }
117
118         /* make working copy of the remainder of the URL */
119         if (( url = strdup( url_tmp )) == NULL ) {
120                 return( LDAP_URL_ERR_MEM );
121         }
122
123         /* allocate return struct */
124         if (( ludp = (LDAPURLDesc *)calloc( 1, sizeof( LDAPURLDesc )))
125             == NULLLDAPURLDESC )
126         {
127                 free( url );
128                 return( LDAP_URL_ERR_MEM );
129         }
130
131
132         if ( enclosed && *((p = url + strlen( url ) - 1)) == '>' ) {
133                 *p = '\0';
134         }
135
136         /* set defaults */
137         ludp->lud_scope = LDAP_SCOPE_BASE;
138         ludp->lud_filter = "(objectClass=*)";
139
140         /* lud_string is the only malloc'd string space we use */
141         ludp->lud_string = url;
142
143         /* scan forward for '/' that marks end of hostport and begin. of dn */
144         if (( ludp->lud_dn = strchr( url, '/' )) == NULL ) {
145                 ldap_free_urldesc( ludp );
146                 return( LDAP_URL_ERR_NODN );
147         }
148
149         /* terminate hostport; point to start of dn */
150         *ludp->lud_dn++ = '\0';
151
152         if (( p = strchr( url, ':' )) != NULL ) {
153                 *p++ = '\0';
154                 ludp->lud_port = atoi( p );
155         }
156
157         if ( *url == '\0' ) {
158                 ludp->lud_host = NULL;
159         } else {
160                 ludp->lud_host = url;
161                 hex_unescape( ludp->lud_host );
162         }
163
164         /* scan for '?' that marks end of dn and beginning of attributes */
165         if (( attrs = strchr( ludp->lud_dn, '?' )) != NULL ) {
166                 /* terminate dn; point to start of attrs. */
167                 *attrs++ = '\0';
168
169                 /* scan for '?' that marks end of attrs and begin. of scope */
170                 if (( p = strchr( attrs, '?' )) != NULL ) {
171                         /*
172                          * terminate attrs; point to start of scope and scan for
173                          * '?' that marks end of scope and begin. of filter
174                          */
175                         *p++ = '\0';
176
177                         if (( q = strchr( p, '?' )) != NULL ) {
178                                 /* terminate scope; point to start of filter */
179                                 *q++ = '\0';
180                                 if ( *q != '\0' ) {
181                                         ludp->lud_filter = q;
182                                         hex_unescape( ludp->lud_filter );
183                                 }
184                         }
185
186                         if ( strcasecmp( p, "one" ) == 0 ) {
187                                 ludp->lud_scope = LDAP_SCOPE_ONELEVEL;
188                         } else if ( strcasecmp( p, "base" ) == 0 ) {
189                                 ludp->lud_scope = LDAP_SCOPE_BASE;
190                         } else if ( strcasecmp( p, "sub" ) == 0 ) {
191                                 ludp->lud_scope = LDAP_SCOPE_SUBTREE;
192                         } else if ( *p != '\0' ) {
193                                 ldap_free_urldesc( ludp );
194                                 return( LDAP_URL_ERR_BADSCOPE );
195                         }
196                 }
197         }
198
199         if ( *ludp->lud_dn == '\0' ) {
200                 ludp->lud_dn = NULL;
201         } else {
202                 hex_unescape( ludp->lud_dn );
203         }
204
205         /*
206          * if attrs list was included, turn it into a null-terminated array
207          */
208         if ( attrs != NULL && *attrs != '\0' ) {
209                 for ( nattrs = 1, p = attrs; *p != '\0'; ++p ) {
210                     if ( *p == ',' ) {
211                             ++nattrs;
212                     }
213                 }
214
215                 if (( ludp->lud_attrs = (char **)calloc( nattrs + 1,
216                     sizeof( char * ))) == NULL ) {
217                         ldap_free_urldesc( ludp );
218                         return( LDAP_URL_ERR_MEM );
219                 }
220
221                 for ( i = 0, p = attrs; i < nattrs; ++i ) {
222                         ludp->lud_attrs[ i ] = p;
223                         if (( p = strchr( p, ',' )) != NULL ) {
224                                 *p++ ='\0';
225                         }
226                         hex_unescape( ludp->lud_attrs[ i ] );
227                 }
228         }
229
230         *ludpp = ludp;
231
232         return( 0 );
233 }
234
235
236 void
237 ldap_free_urldesc( LDAPURLDesc *ludp )
238 {
239         if ( ludp != NULLLDAPURLDESC ) {
240                 if ( ludp->lud_string != NULL ) {
241                         free( ludp->lud_string );
242                 }
243                 if ( ludp->lud_attrs != NULL ) {
244                         free( ludp->lud_attrs );
245                 }
246                 free( ludp );
247         }
248 }
249
250
251
252 int
253 ldap_url_search( LDAP *ld, LDAP_CONST char *url, int attrsonly )
254 {
255         int             err;
256         LDAPURLDesc     *ludp;
257         BerElement      *ber;
258         LDAPServer      *srv = NULL;
259
260         if ( ldap_url_parse( url, &ludp ) != 0 ) {
261                 ld->ld_errno = LDAP_PARAM_ERROR;
262                 return( -1 );
263         }
264
265         ber = ldap_build_search_req( ld, ludp->lud_dn, ludp->lud_scope,
266             ludp->lud_filter, ludp->lud_attrs, attrsonly, NULL, NULL,
267                 -1, -1 );
268
269         if ( ber == NULLBER ) {
270                 return( -1 );
271         }
272
273         err = 0;
274
275         if ( ludp->lud_host != NULL || ludp->lud_port != 0 ) {
276                 if (( srv = (LDAPServer *)calloc( 1, sizeof( LDAPServer )))
277                     == NULL || ( srv->lsrv_host = strdup( ludp->lud_host ==
278                     NULL ? ld->ld_defhost : ludp->lud_host )) == NULL ) {
279                         if ( srv != NULL ) {
280                                 free( srv );
281                         }
282                         ld->ld_errno = LDAP_NO_MEMORY;
283                         err = -1;
284                 } else {
285                         if ( ludp->lud_port == 0 ) {
286                                 srv->lsrv_port = ldap_int_global_options.ldo_defport;
287                         } else {
288                                 srv->lsrv_port = ludp->lud_port;
289                         }
290                 }
291         }
292
293         if ( err != 0 ) {
294                 ber_free( ber, 1 );
295         } else {
296                 err = ldap_send_server_request( ld, ber, ld->ld_msgid, NULL, srv,
297                     NULL, 1 );
298         }
299
300         ldap_free_urldesc( ludp );
301
302         return( err );
303 }
304
305
306 int
307 ldap_url_search_st( LDAP *ld, LDAP_CONST char *url, int attrsonly,
308         struct timeval *timeout, LDAPMessage **res )
309 {
310         int     msgid;
311
312         if (( msgid = ldap_url_search( ld, url, attrsonly )) == -1 ) {
313                 return( ld->ld_errno );
314         }
315
316         if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 ) {
317                 return( ld->ld_errno );
318         }
319
320         if ( ld->ld_errno == LDAP_TIMEOUT ) {
321                 (void) ldap_abandon( ld, msgid );
322                 ld->ld_errno = LDAP_TIMEOUT;
323                 return( ld->ld_errno );
324         }
325
326         return( ldap_result2error( ld, *res, 0 ));
327 }
328
329
330 int
331 ldap_url_search_s(
332         LDAP *ld, LDAP_CONST char *url, int attrsonly, LDAPMessage **res )
333 {
334         int     msgid;
335
336         if (( msgid = ldap_url_search( ld, url, attrsonly )) == -1 ) {
337                 return( ld->ld_errno );
338         }
339
340         if ( ldap_result( ld, msgid, 1, (struct timeval *)NULL, res ) == -1 ) {
341                 return( ld->ld_errno );
342         }
343
344         return( ldap_result2error( ld, *res, 0 ));
345 }
346
347
348 static void
349 hex_unescape( char *s )
350 {
351 /*
352  * Remove URL hex escapes from s... done in place.  The basic concept for
353  * this routine is borrowed from the WWW library HTUnEscape() routine.
354  */
355         char    *p;
356
357         for ( p = s; *s != '\0'; ++s ) {
358                 if ( *s == '%' ) {
359                         if ( *++s != '\0' ) {
360                                 *p = unhex( *s ) << 4;
361                         }
362                         if ( *++s != '\0' ) {
363                                 *p++ += unhex( *s );
364                         }
365                 } else {
366                         *p++ = *s;
367                 }
368         }
369
370         *p = '\0';
371 }
372
373
374 static int
375 unhex( char c )
376 {
377         return( c >= '0' && c <= '9' ? c - '0'
378             : c >= 'A' && c <= 'F' ? c - 'A' + 10
379             : c - 'a' + 10 );
380 }