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