]> git.sur5r.net Git - openldap/blob - libraries/libldap/url.c
Remove DEFS variables from Makefiles, remove bridge.h.
[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 #ifndef lint 
21 static char copyright[] = "@(#) Copyright (c) 1996 Regents of the University of Michigan.\nAll rights reserved.\n";
22 #endif
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <stdlib.h>
28
29 #ifdef MACOS
30 #include "macos.h"
31 #endif /* MACOS */
32
33 #if defined( DOS ) || defined( _WIN32 )
34 #include <malloc.h>
35 #include "msdos.h"
36 #endif /* DOS || _WIN32 */
37
38 #if !defined(MACOS) && !defined(DOS) && !defined( _WIN32 )
39 #include <sys/time.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #endif /* !MACOS && !DOS && !_WIN32 */
43
44 #include "lber.h"
45 #include "ldap.h"
46 #include "ldap-int.h"
47
48
49 static int skip_url_prefix LDAP_P(( char **urlp, int *enclosedp ));
50 static void hex_unescape LDAP_P(( char *s ));
51 static int unhex LDAP_P(( char c ));
52
53
54 int
55 ldap_is_ldap_url( char *url )
56 {
57         int     enclosed;
58
59         return( url != NULL && skip_url_prefix( &url, &enclosed ));
60 }
61
62
63 static int
64 skip_url_prefix( char **urlp, int *enclosedp )
65 {
66 /*
67  * return non-zero if this looks like a LDAP URL; zero if not
68  * if non-zero returned, *urlp will be moved past "ldap://" part of URL
69  */
70         if ( *urlp == NULL ) {
71                 return( 0 );
72         }
73
74         /* skip leading '<' (if any) */
75         if ( **urlp == '<' ) {
76                 *enclosedp = 1;
77                 ++*urlp;
78         } else {
79                 *enclosedp = 0;
80         }
81
82         /* skip leading "URL:" (if any) */
83         if ( strlen( *urlp ) >= LDAP_URL_URLCOLON_LEN && strncasecmp(
84             *urlp, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) {
85                 *urlp += LDAP_URL_URLCOLON_LEN;
86         }
87
88         /* check for missing "ldap://" prefix */
89         if ( strlen( *urlp ) < LDAP_URL_PREFIX_LEN ||
90             strncasecmp( *urlp, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) != 0 ) {
91                 return( 0 );
92         }
93
94         /* skip over "ldap://" prefix and return success */
95         *urlp += LDAP_URL_PREFIX_LEN;
96         return( 1 );
97 }
98
99
100
101 int
102 ldap_url_parse( char *url, LDAPURLDesc **ludpp )
103 {
104 /*
105  *  Pick apart the pieces of an LDAP URL.
106  */
107
108         LDAPURLDesc     *ludp;
109         char            *attrs, *p, *q;
110         int             enclosed, i, nattrs;
111
112         Debug( LDAP_DEBUG_TRACE, "ldap_url_parse(%s)\n", url, 0, 0 );
113
114         *ludpp = NULL;  /* pessimistic */
115
116         if ( !skip_url_prefix( &url, &enclosed )) {
117                 return( LDAP_URL_ERR_NOTLDAP );
118         }
119
120         /* allocate return struct */
121         if (( ludp = (LDAPURLDesc *)calloc( 1, sizeof( LDAPURLDesc )))
122             == NULLLDAPURLDESC ) {
123                 return( LDAP_URL_ERR_MEM );
124         }
125
126         /* make working copy of the remainder of the URL */
127         if (( url = strdup( url )) == NULL ) {
128                 ldap_free_urldesc( ludp );
129                 return( LDAP_URL_ERR_MEM );
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, char *url, int attrsonly )
254 {
255         int             err;
256         LDAPURLDesc     *ludp;
257         BerElement      *ber;
258 #ifdef LDAP_REFERRALS
259         LDAPServer      *srv = NULL;
260 #endif /* LDAP_REFERRALS */
261
262         if ( ldap_url_parse( url, &ludp ) != 0 ) {
263                 ld->ld_errno = LDAP_PARAM_ERROR;
264                 return( -1 );
265         }
266
267         if (( ber = ldap_build_search_req( ld, ludp->lud_dn, ludp->lud_scope,
268             ludp->lud_filter, ludp->lud_attrs, attrsonly )) == NULLBER ) {
269                 return( -1 );
270         }
271
272         err = 0;
273
274         if ( ludp->lud_host != NULL || ludp->lud_port != 0 ) {
275 #ifdef LDAP_REFERRALS
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_PORT;
287                         } else {
288                                  srv->lsrv_port = ludp->lud_port;
289                         }
290                 }
291 #else /* LDAP_REFERRALS */
292                 ld->ld_errno = LDAP_LOCAL_ERROR;
293                 err = -1;
294 #endif /* LDAP_REFERRALS */
295         }
296
297         if ( err != 0 ) {
298                 ber_free( ber, 1 );
299         } else {
300 #ifdef LDAP_REFERRALS
301                 err = ldap_send_server_request( ld, ber, ld->ld_msgid, NULL, srv,
302                     NULL, 1 );
303 #else /* LDAP_REFERRALS */
304                 err = ldap_send_initial_request( ld, LDAP_REQ_SEARCH,
305                     ludp->lud_dn, ber );
306 #endif /* LDAP_REFERRALS */
307         }
308
309         ldap_free_urldesc( ludp );
310
311         return( err );
312 }
313
314
315 int
316 ldap_url_search_st( LDAP *ld, char *url, int attrsonly,
317         struct timeval *timeout, LDAPMessage **res )
318 {
319         int     msgid;
320
321         if (( msgid = ldap_url_search( ld, url, attrsonly )) == -1 ) {
322                 return( ld->ld_errno );
323         }
324
325         if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 ) {
326                 return( ld->ld_errno );
327         }
328
329         if ( ld->ld_errno == LDAP_TIMEOUT ) {
330                 (void) ldap_abandon( ld, msgid );
331                 ld->ld_errno = LDAP_TIMEOUT;
332                 return( ld->ld_errno );
333         }
334
335         return( ldap_result2error( ld, *res, 0 ));
336 }
337
338
339 int
340 ldap_url_search_s( LDAP *ld, char *url, int attrsonly, LDAPMessage **res )
341 {
342         int     msgid;
343
344         if (( msgid = ldap_url_search( ld, url, attrsonly )) == -1 ) {
345                 return( ld->ld_errno );
346         }
347
348         if ( ldap_result( ld, msgid, 1, (struct timeval *)NULL, res ) == -1 ) {
349                 return( ld->ld_errno );
350         }
351
352         return( ldap_result2error( ld, *res, 0 ));
353 }
354
355
356 static void
357 hex_unescape( char *s )
358 {
359 /*
360  * Remove URL hex escapes from s... done in place.  The basic concept for
361  * this routine is borrowed from the WWW library HTUnEscape() routine.
362  */
363         char    *p;
364
365         for ( p = s; *s != '\0'; ++s ) {
366                 if ( *s == '%' ) {
367                         if ( *++s != '\0' ) {
368                                 *p = unhex( *s ) << 4;
369                         }
370                         if ( *++s != '\0' ) {
371                                 *p++ += unhex( *s );
372                         }
373                 } else {
374                         *p++ = *s;
375                 }
376         }
377
378         *p = '\0';
379 }
380
381
382 static int
383 unhex( char c )
384 {
385         return( c >= '0' && c <= '9' ? c - '0'
386             : c >= 'A' && c <= 'F' ? c - 'A' + 10
387             : c - 'a' + 10 );
388 }