~ubuntu-branches/ubuntu/oneiric/likewise-open/oneiric

« back to all changes in this revision

Viewing changes to openldap/libraries/libldap/url.c

  • Committer: Bazaar Package Importer
  • Author(s): Scott Salley
  • Date: 2010-11-22 12:06:00 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20101122120600-8lba1fpceot71wlb
Tags: 6.0.0.53010-1
Likewise Open 6.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* LIBLDAP url.c -- LDAP URL (RFC 4516) related routines */
 
2
/* $OpenLDAP: pkg/ldap/libraries/libldap/url.c,v 1.94.2.10 2009/01/22 00:00:56 kurt Exp $ */
 
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
4
 *
 
5
 * Copyright 1998-2009 The OpenLDAP Foundation.
 
6
 * All rights reserved.
 
7
 *
 
8
 * Redistribution and use in source and binary forms, with or without
 
9
 * modification, are permitted only as authorized by the OpenLDAP
 
10
 * Public License.
 
11
 *
 
12
 * A copy of this license is available in the file LICENSE in the
 
13
 * top-level directory of the distribution or, alternatively, at
 
14
 * <http://www.OpenLDAP.org/license.html>.
 
15
 */
 
16
/* Portions Copyright (c) 1996 Regents of the University of Michigan.
 
17
 * All rights reserved.
 
18
 */
 
19
 
 
20
 
 
21
/*
 
22
 *  LDAP URLs look like this:
 
23
 *    ldap[is]://host[:port][/[dn[?[attributes][?[scope][?[filter][?exts]]]]]]
 
24
 *
 
25
 *  where:
 
26
 *   attributes is a comma separated list
 
27
 *   scope is one of these three strings:  base one sub (default=base)
 
28
 *   filter is an string-represented filter as in RFC 4515
 
29
 *
 
30
 *  e.g.,  ldap://host:port/dc=com?o,cn?base?(o=openldap)?extension
 
31
 *
 
32
 *  We also tolerate URLs that look like: <ldapurl> and <URL:ldapurl>
 
33
 */
 
34
 
 
35
#include "portable.h"
 
36
 
 
37
#include <stdio.h>
 
38
 
 
39
#include <ac/stdlib.h>
 
40
#include <ac/ctype.h>
 
41
 
 
42
#include <ac/socket.h>
 
43
#include <ac/string.h>
 
44
#include <ac/time.h>
 
45
 
 
46
#include "ldap-int.h"
 
47
 
 
48
/* local functions */
 
49
static const char* skip_url_prefix LDAP_P((
 
50
        const char *url,
 
51
        int *enclosedp,
 
52
        const char **scheme ));
 
53
 
 
54
int ldap_pvt_url_scheme2proto( const char *scheme )
 
55
{
 
56
        assert( scheme != NULL );
 
57
 
 
58
        if( scheme == NULL ) {
 
59
                return -1;
 
60
        }
 
61
 
 
62
        if( strcmp("ldap", scheme) == 0 ) {
 
63
                return LDAP_PROTO_TCP;
 
64
        }
 
65
 
 
66
        if( strcmp("ldapi", scheme) == 0 ) {
 
67
                return LDAP_PROTO_IPC;
 
68
        }
 
69
 
 
70
        if( strcmp("ldaps", scheme) == 0 ) {
 
71
                return LDAP_PROTO_TCP;
 
72
        }
 
73
#ifdef LDAP_CONNECTIONLESS
 
74
        if( strcmp("cldap", scheme) == 0 ) {
 
75
                return LDAP_PROTO_UDP;
 
76
        }
 
77
#endif
 
78
 
 
79
        return -1;
 
80
}
 
81
 
 
82
int ldap_pvt_url_scheme_port( const char *scheme, int port )
 
83
{
 
84
        assert( scheme != NULL );
 
85
 
 
86
        if( port ) return port;
 
87
        if( scheme == NULL ) return port;
 
88
 
 
89
        if( strcmp("ldap", scheme) == 0 ) {
 
90
                return LDAP_PORT;
 
91
        }
 
92
 
 
93
        if( strcmp("ldapi", scheme) == 0 ) {
 
94
                return -1;
 
95
        }
 
96
 
 
97
        if( strcmp("ldaps", scheme) == 0 ) {
 
98
                return LDAPS_PORT;
 
99
        }
 
100
 
 
101
#ifdef LDAP_CONNECTIONLESS
 
102
        if( strcmp("cldap", scheme) == 0 ) {
 
103
                return LDAP_PORT;
 
104
        }
 
105
#endif
 
106
 
 
107
        return -1;
 
108
}
 
109
 
 
110
int
 
111
ldap_pvt_url_scheme2tls( const char *scheme )
 
112
{
 
113
        assert( scheme != NULL );
 
114
 
 
115
        if( scheme == NULL ) {
 
116
                return -1;
 
117
        }
 
118
 
 
119
        return strcmp("ldaps", scheme) == 0;
 
120
}
 
121
 
 
122
int
 
123
ldap_is_ldap_url( LDAP_CONST char *url )
 
124
{
 
125
        int     enclosed;
 
126
        const char * scheme;
 
127
 
 
128
        if( url == NULL ) {
 
129
                return 0;
 
130
        }
 
131
 
 
132
        if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) {
 
133
                return 0;
 
134
        }
 
135
 
 
136
        return 1;
 
137
}
 
138
 
 
139
int
 
140
ldap_is_ldaps_url( LDAP_CONST char *url )
 
141
{
 
142
        int     enclosed;
 
143
        const char * scheme;
 
144
 
 
145
        if( url == NULL ) {
 
146
                return 0;
 
147
        }
 
148
 
 
149
        if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) {
 
150
                return 0;
 
151
        }
 
152
 
 
153
        return strcmp(scheme, "ldaps") == 0;
 
154
}
 
155
 
 
156
int
 
157
ldap_is_ldapi_url( LDAP_CONST char *url )
 
158
{
 
159
        int     enclosed;
 
160
        const char * scheme;
 
161
 
 
162
        if( url == NULL ) {
 
163
                return 0;
 
164
        }
 
165
 
 
166
        if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) {
 
167
                return 0;
 
168
        }
 
169
 
 
170
        return strcmp(scheme, "ldapi") == 0;
 
171
}
 
172
 
 
173
#ifdef LDAP_CONNECTIONLESS
 
174
int
 
175
ldap_is_ldapc_url( LDAP_CONST char *url )
 
176
{
 
177
        int     enclosed;
 
178
        const char * scheme;
 
179
 
 
180
        if( url == NULL ) {
 
181
                return 0;
 
182
        }
 
183
 
 
184
        if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) {
 
185
                return 0;
 
186
        }
 
187
 
 
188
        return strcmp(scheme, "cldap") == 0;
 
189
}
 
190
#endif
 
191
 
 
192
static const char*
 
193
skip_url_prefix(
 
194
        const char *url,
 
195
        int *enclosedp,
 
196
        const char **scheme )
 
197
{
 
198
        /*
 
199
         * return non-zero if this looks like a LDAP URL; zero if not
 
200
         * if non-zero returned, *urlp will be moved past "ldap://" part of URL
 
201
         */
 
202
        const char *p;
 
203
 
 
204
        if ( url == NULL ) {
 
205
                return( NULL );
 
206
        }
 
207
 
 
208
        p = url;
 
209
 
 
210
        /* skip leading '<' (if any) */
 
211
        if ( *p == '<' ) {
 
212
                *enclosedp = 1;
 
213
                ++p;
 
214
        } else {
 
215
                *enclosedp = 0;
 
216
        }
 
217
 
 
218
        /* skip leading "URL:" (if any) */
 
219
        if ( strncasecmp( p, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) {
 
220
                p += LDAP_URL_URLCOLON_LEN;
 
221
        }
 
222
 
 
223
        /* check for "ldap://" prefix */
 
224
        if ( strncasecmp( p, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) == 0 ) {
 
225
                /* skip over "ldap://" prefix and return success */
 
226
                p += LDAP_URL_PREFIX_LEN;
 
227
                *scheme = "ldap";
 
228
                return( p );
 
229
        }
 
230
 
 
231
        /* check for "ldaps://" prefix */
 
232
        if ( strncasecmp( p, LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) {
 
233
                /* skip over "ldaps://" prefix and return success */
 
234
                p += LDAPS_URL_PREFIX_LEN;
 
235
                *scheme = "ldaps";
 
236
                return( p );
 
237
        }
 
238
 
 
239
        /* check for "ldapi://" prefix */
 
240
        if ( strncasecmp( p, LDAPI_URL_PREFIX, LDAPI_URL_PREFIX_LEN ) == 0 ) {
 
241
                /* skip over "ldapi://" prefix and return success */
 
242
                p += LDAPI_URL_PREFIX_LEN;
 
243
                *scheme = "ldapi";
 
244
                return( p );
 
245
        }
 
246
 
 
247
#ifdef LDAP_CONNECTIONLESS
 
248
        /* check for "cldap://" prefix */
 
249
        if ( strncasecmp( p, LDAPC_URL_PREFIX, LDAPC_URL_PREFIX_LEN ) == 0 ) {
 
250
                /* skip over "cldap://" prefix and return success */
 
251
                p += LDAPC_URL_PREFIX_LEN;
 
252
                *scheme = "cldap";
 
253
                return( p );
 
254
        }
 
255
#endif
 
256
 
 
257
        return( NULL );
 
258
}
 
259
 
 
260
int
 
261
ldap_pvt_scope2bv( int scope, struct berval *bv )
 
262
{
 
263
        switch ( scope ) {
 
264
        case LDAP_SCOPE_BASE:
 
265
                BER_BVSTR( bv, "base" );
 
266
                break;
 
267
 
 
268
        case LDAP_SCOPE_ONELEVEL:
 
269
                BER_BVSTR( bv, "one" );
 
270
                break;
 
271
 
 
272
        case LDAP_SCOPE_SUBTREE:
 
273
                BER_BVSTR( bv, "sub" );
 
274
                break;
 
275
 
 
276
        case LDAP_SCOPE_SUBORDINATE:
 
277
                BER_BVSTR( bv, "subordinate" );
 
278
                break;
 
279
 
 
280
        default:
 
281
                return LDAP_OTHER;
 
282
        }
 
283
 
 
284
        return LDAP_SUCCESS;
 
285
}
 
286
 
 
287
const char *
 
288
ldap_pvt_scope2str( int scope )
 
289
{
 
290
        struct berval   bv;
 
291
 
 
292
        if ( ldap_pvt_scope2bv( scope, &bv ) == LDAP_SUCCESS ) {
 
293
                return bv.bv_val;
 
294
        }
 
295
 
 
296
        return NULL;
 
297
}
 
298
 
 
299
int
 
300
ldap_pvt_bv2scope( struct berval *bv )
 
301
{
 
302
        static struct {
 
303
                struct berval   bv;
 
304
                int             scope;
 
305
        }       v[] = {
 
306
                { BER_BVC( "one" ),             LDAP_SCOPE_ONELEVEL },
 
307
                { BER_BVC( "onelevel" ),        LDAP_SCOPE_ONELEVEL },
 
308
                { BER_BVC( "base" ),            LDAP_SCOPE_BASE },
 
309
                { BER_BVC( "sub" ),             LDAP_SCOPE_SUBTREE },
 
310
                { BER_BVC( "subtree" ),         LDAP_SCOPE_SUBTREE },
 
311
                { BER_BVC( "subord" ),          LDAP_SCOPE_SUBORDINATE },
 
312
                { BER_BVC( "subordinate" ),     LDAP_SCOPE_SUBORDINATE },
 
313
                { BER_BVC( "children" ),        LDAP_SCOPE_SUBORDINATE },
 
314
                { BER_BVNULL,                   -1 }
 
315
        };
 
316
        int     i;
 
317
 
 
318
        for ( i = 0; v[ i ].scope != -1; i++ ) {
 
319
                if ( ber_bvstrcasecmp( bv, &v[ i ].bv ) == 0 ) {
 
320
                        return v[ i ].scope;
 
321
                }
 
322
        }
 
323
 
 
324
        return( -1 );
 
325
}
 
326
 
 
327
int
 
328
ldap_pvt_str2scope( const char *p )
 
329
{
 
330
        struct berval   bv;
 
331
 
 
332
        ber_str2bv( p, 0, 0, &bv );
 
333
 
 
334
        return ldap_pvt_bv2scope( &bv );
 
335
}
 
336
 
 
337
static const char       hex[] = "0123456789ABCDEF";
 
338
 
 
339
#define URLESC_NONE     0x0000U
 
340
#define URLESC_COMMA    0x0001U
 
341
#define URLESC_SLASH    0x0002U
 
342
 
 
343
static int
 
344
hex_escape_len( const char *s, unsigned list )
 
345
{
 
346
        int     len;
 
347
 
 
348
        if ( s == NULL ) {
 
349
                return 0;
 
350
        }
 
351
 
 
352
        for ( len = 0; s[0]; s++ ) {
 
353
                switch ( s[0] ) {
 
354
                /* RFC 2396: reserved */
 
355
                case '?':
 
356
                        len += 3;
 
357
                        break;
 
358
 
 
359
                case ',':
 
360
                        if ( list & URLESC_COMMA ) {
 
361
                                len += 3;
 
362
                        } else {
 
363
                                len++;
 
364
                        }
 
365
                        break;
 
366
 
 
367
                case '/':
 
368
                        if ( list & URLESC_SLASH ) {
 
369
                                len += 3;
 
370
                        } else {
 
371
                                len++;
 
372
                        }
 
373
                        break;
 
374
 
 
375
                case ';':
 
376
                case ':':
 
377
                case '@':
 
378
                case '&':
 
379
                case '=':
 
380
                case '+':
 
381
                case '$':
 
382
 
 
383
                /* RFC 2396: unreserved mark */
 
384
                case '-':
 
385
                case '_':
 
386
                case '.':
 
387
                case '!':
 
388
                case '~':
 
389
                case '*':
 
390
                case '\'':
 
391
                case '(':
 
392
                case ')':
 
393
                        len++;
 
394
                        break;
 
395
                        
 
396
                /* RFC 2396: unreserved alphanum */
 
397
                default:
 
398
                        if ( !isalnum( (unsigned char) s[0] ) ) {
 
399
                                len += 3;
 
400
                        } else {
 
401
                                len++;
 
402
                        }
 
403
                        break;
 
404
                }
 
405
        }
 
406
 
 
407
        return len;
 
408
}
 
409
 
 
410
static int
 
411
hex_escape( char *buf, int len, const char *s, unsigned list )
 
412
{
 
413
        int     i;
 
414
        int     pos;
 
415
 
 
416
        if ( s == NULL ) {
 
417
                return 0;
 
418
        }
 
419
 
 
420
        for ( pos = 0, i = 0; s[i] && pos < len; i++ ) {
 
421
                int     escape = 0;
 
422
 
 
423
                switch ( s[i] ) {
 
424
                /* RFC 2396: reserved */
 
425
                case '?':
 
426
                        escape = 1;
 
427
                        break;
 
428
 
 
429
                case ',':
 
430
                        if ( list & URLESC_COMMA ) {
 
431
                                escape = 1;
 
432
                        }
 
433
                        break;
 
434
 
 
435
                case '/':
 
436
                        if ( list & URLESC_SLASH ) {
 
437
                                escape = 1;
 
438
                        }
 
439
                        break;
 
440
 
 
441
                case ';':
 
442
                case ':':
 
443
                case '@':
 
444
                case '&':
 
445
                case '=':
 
446
                case '+':
 
447
                case '$':
 
448
 
 
449
                /* RFC 2396: unreserved mark */
 
450
                case '-':
 
451
                case '_':
 
452
                case '.':
 
453
                case '!':
 
454
                case '~':
 
455
                case '*':
 
456
                case '\'':
 
457
                case '(':
 
458
                case ')':
 
459
                        break;
 
460
                        
 
461
                /* RFC 2396: unreserved alphanum */
 
462
                default:
 
463
                        if ( !isalnum( (unsigned char) s[i] ) ) {
 
464
                                escape = 1;
 
465
                        }
 
466
                        break;
 
467
                }
 
468
 
 
469
                if ( escape ) {
 
470
                        buf[pos++] = '%';
 
471
                        buf[pos++] = hex[ (s[i] >> 4) & 0x0f ];
 
472
                        buf[pos++] = hex[ s[i] & 0x0f ];
 
473
 
 
474
                } else {
 
475
                        buf[pos++] = s[i];
 
476
                }
 
477
        }
 
478
 
 
479
        buf[pos] = '\0';
 
480
 
 
481
        return pos;
 
482
}
 
483
 
 
484
static int
 
485
hex_escape_len_list( char **s, unsigned flags )
 
486
{
 
487
        int     len;
 
488
        int     i;
 
489
 
 
490
        if ( s == NULL ) {
 
491
                return 0;
 
492
        }
 
493
 
 
494
        len = 0;
 
495
        for ( i = 0; s[i] != NULL; i++ ) {
 
496
                if ( len ) {
 
497
                        len++;
 
498
                }
 
499
                len += hex_escape_len( s[i], flags );
 
500
        }
 
501
 
 
502
        return len;
 
503
}
 
504
 
 
505
static int
 
506
hex_escape_list( char *buf, int len, char **s, unsigned flags )
 
507
{
 
508
        int     pos;
 
509
        int     i;
 
510
 
 
511
        if ( s == NULL ) {
 
512
                return 0;
 
513
        }
 
514
 
 
515
        pos = 0;
 
516
        for ( i = 0; s[i] != NULL; i++ ) {
 
517
                int     curlen;
 
518
 
 
519
                if ( pos ) {
 
520
                        buf[pos++] = ',';
 
521
                        len--;
 
522
                }
 
523
                curlen = hex_escape( &buf[pos], len, s[i], flags );
 
524
                len -= curlen;
 
525
                pos += curlen;
 
526
        }
 
527
 
 
528
        return pos;
 
529
}
 
530
 
 
531
static int
 
532
desc2str_len( LDAPURLDesc *u )
 
533
{
 
534
        int             sep = 0;
 
535
        int             len = 0;
 
536
        int             is_ipc = 0;
 
537
        struct berval   scope;
 
538
 
 
539
        if ( u == NULL || u->lud_scheme == NULL ) {
 
540
                return -1;
 
541
        }
 
542
 
 
543
        if ( !strcmp( "ldapi", u->lud_scheme )) {
 
544
                is_ipc = 1;
 
545
        }
 
546
 
 
547
        if ( u->lud_exts ) {
 
548
                len += hex_escape_len_list( u->lud_exts, URLESC_COMMA );
 
549
                if ( !sep ) {
 
550
                        sep = 5;
 
551
                }
 
552
        }
 
553
 
 
554
        if ( u->lud_filter ) {
 
555
                len += hex_escape_len( u->lud_filter, URLESC_NONE );
 
556
                if ( !sep ) {
 
557
                        sep = 4;
 
558
                }
 
559
        }
 
560
 
 
561
        if ( ldap_pvt_scope2bv( u->lud_scope, &scope ) == LDAP_SUCCESS ) {
 
562
                len += scope.bv_len;
 
563
                if ( !sep ) {
 
564
                        sep = 3;
 
565
                }
 
566
        }
 
567
 
 
568
        if ( u->lud_attrs ) {
 
569
                len += hex_escape_len_list( u->lud_attrs, URLESC_NONE );
 
570
                if ( !sep ) {
 
571
                        sep = 2;
 
572
                }
 
573
        }
 
574
 
 
575
        if ( u->lud_dn && u->lud_dn[0] ) {
 
576
                len += hex_escape_len( u->lud_dn, URLESC_NONE );
 
577
                if ( !sep ) {
 
578
                        sep = 1;
 
579
                }
 
580
        };
 
581
 
 
582
        len += sep;
 
583
 
 
584
        if ( u->lud_port ) {
 
585
                unsigned p = u->lud_port;
 
586
                if ( p > 65535 )
 
587
                        return -1;
 
588
 
 
589
                len += (p > 999 ? 5 + (p > 9999) : p > 99 ? 4 : 2 + (p > 9));
 
590
        }
 
591
 
 
592
        if ( u->lud_host && u->lud_host[0] ) {
 
593
                char *ptr;
 
594
                len += hex_escape_len( u->lud_host, URLESC_SLASH );
 
595
                if ( !is_ipc && ( ptr = strchr( u->lud_host, ':' ))) {
 
596
                        if ( strchr( ptr+1, ':' ))
 
597
                                len += 2;       /* IPv6, [] */
 
598
                }
 
599
        }
 
600
 
 
601
        len += strlen( u->lud_scheme ) + STRLENOF( "://" );
 
602
 
 
603
        return len;
 
604
}
 
605
 
 
606
static int
 
607
desc2str( LDAPURLDesc *u, char *s, int len )
 
608
{
 
609
        int             i;
 
610
        int             sep = 0;
 
611
        int             sofar = 0;
 
612
        int             is_v6 = 0;
 
613
        int             is_ipc = 0;
 
614
        struct berval   scope = BER_BVNULL;
 
615
        char            *ptr;
 
616
 
 
617
        if ( u == NULL ) {
 
618
                return -1;
 
619
        }
 
620
 
 
621
        if ( s == NULL ) {
 
622
                return -1;
 
623
        }
 
624
 
 
625
        if ( u->lud_scheme && !strcmp( "ldapi", u->lud_scheme )) {
 
626
                is_ipc = 1;
 
627
        }
 
628
 
 
629
        ldap_pvt_scope2bv( u->lud_scope, &scope );
 
630
 
 
631
        if ( u->lud_exts ) {
 
632
                sep = 5;
 
633
        } else if ( u->lud_filter ) {
 
634
                sep = 4;
 
635
        } else if ( !BER_BVISEMPTY( &scope ) ) {
 
636
                sep = 3;
 
637
        } else if ( u->lud_attrs ) {
 
638
                sep = 2;
 
639
        } else if ( u->lud_dn && u->lud_dn[0] ) {
 
640
                sep = 1;
 
641
        }
 
642
 
 
643
        if ( !is_ipc && u->lud_host && ( ptr = strchr( u->lud_host, ':' ))) {
 
644
                if ( strchr( ptr+1, ':' ))
 
645
                        is_v6 = 1;
 
646
        }
 
647
 
 
648
        if ( u->lud_port ) {
 
649
                sofar = sprintf( s, "%s://%s%s%s:%d", u->lud_scheme,
 
650
                                is_v6 ? "[" : "",
 
651
                                u->lud_host ? u->lud_host : "",
 
652
                                is_v6 ? "]" : "",
 
653
                                u->lud_port );
 
654
                len -= sofar;
 
655
 
 
656
        } else {
 
657
                sofar = sprintf( s, "%s://", u->lud_scheme );
 
658
                len -= sofar;
 
659
                if ( u->lud_host && u->lud_host[0] ) {
 
660
                        if ( is_v6 ) {
 
661
                                s[sofar++] = '[';
 
662
                                len--;
 
663
                        }
 
664
                        i = hex_escape( &s[sofar], len, u->lud_host, URLESC_SLASH );
 
665
                        sofar += i;
 
666
                        len -= i;
 
667
                        if ( is_v6 ) {
 
668
                                s[sofar++] = ']';
 
669
                                len--;
 
670
                        }
 
671
                }
 
672
        }
 
673
 
 
674
        assert( len >= 0 );
 
675
 
 
676
        if ( sep < 1 ) {
 
677
                goto done;
 
678
        }
 
679
 
 
680
        s[sofar++] = '/';
 
681
        len--;
 
682
 
 
683
        assert( len >= 0 );
 
684
 
 
685
        if ( u->lud_dn && u->lud_dn[0] ) {
 
686
                i = hex_escape( &s[sofar], len, u->lud_dn, URLESC_NONE );
 
687
                sofar += i;
 
688
                len -= i;
 
689
 
 
690
                assert( len >= 0 );
 
691
        }
 
692
 
 
693
        if ( sep < 2 ) {
 
694
                goto done;
 
695
        }
 
696
        s[sofar++] = '?';
 
697
        len--;
 
698
 
 
699
        assert( len >= 0 );
 
700
 
 
701
        i = hex_escape_list( &s[sofar], len, u->lud_attrs, URLESC_NONE );
 
702
        sofar += i;
 
703
        len -= i;
 
704
 
 
705
        assert( len >= 0 );
 
706
 
 
707
        if ( sep < 3 ) {
 
708
                goto done;
 
709
        }
 
710
        s[sofar++] = '?';
 
711
        len--;
 
712
 
 
713
        assert( len >= 0 );
 
714
 
 
715
        if ( !BER_BVISNULL( &scope ) ) {
 
716
                strcpy( &s[sofar], scope.bv_val );
 
717
                sofar += scope.bv_len;
 
718
                len -= scope.bv_len;
 
719
        }
 
720
 
 
721
        assert( len >= 0 );
 
722
 
 
723
        if ( sep < 4 ) {
 
724
                goto done;
 
725
        }
 
726
        s[sofar++] = '?';
 
727
        len--;
 
728
 
 
729
        assert( len >= 0 );
 
730
 
 
731
        i = hex_escape( &s[sofar], len, u->lud_filter, URLESC_NONE );
 
732
        sofar += i;
 
733
        len -= i;
 
734
 
 
735
        assert( len >= 0 );
 
736
 
 
737
        if ( sep < 5 ) {
 
738
                goto done;
 
739
        }
 
740
        s[sofar++] = '?';
 
741
        len--;
 
742
 
 
743
        assert( len >= 0 );
 
744
 
 
745
        i = hex_escape_list( &s[sofar], len, u->lud_exts, URLESC_COMMA );
 
746
        sofar += i;
 
747
        len -= i;
 
748
 
 
749
        assert( len >= 0 );
 
750
 
 
751
done:
 
752
        if ( len < 0 ) {
 
753
                return -1;
 
754
        }
 
755
 
 
756
        return sofar;
 
757
}
 
758
 
 
759
char *
 
760
ldap_url_desc2str( LDAPURLDesc *u )
 
761
{
 
762
        int     len;
 
763
        char    *s;
 
764
 
 
765
        if ( u == NULL ) {
 
766
                return NULL;
 
767
        }
 
768
 
 
769
        len = desc2str_len( u );
 
770
        if ( len < 0 ) {
 
771
                return NULL;
 
772
        }
 
773
        
 
774
        /* allocate enough to hex escape everything -- overkill */
 
775
        s = LDAP_MALLOC( len + 1 );
 
776
 
 
777
        if ( s == NULL ) {
 
778
                return NULL;
 
779
        }
 
780
 
 
781
        if ( desc2str( u, s, len ) != len ) {
 
782
                LDAP_FREE( s );
 
783
                return NULL;
 
784
        }
 
785
 
 
786
        s[len] = '\0';
 
787
 
 
788
        return s;
 
789
}
 
790
 
 
791
int
 
792
ldap_url_parse_ext( LDAP_CONST char *url_in, LDAPURLDesc **ludpp, unsigned flags )
 
793
{
 
794
/*
 
795
 *  Pick apart the pieces of an LDAP URL.
 
796
 */
 
797
 
 
798
        LDAPURLDesc     *ludp;
 
799
        char    *p, *q, *r;
 
800
        int             i, enclosed, proto, is_v6 = 0;
 
801
        const char *scheme = NULL;
 
802
        const char *url_tmp;
 
803
        char *url;
 
804
 
 
805
        int     check_dn = 1;
 
806
 
 
807
        if( url_in == NULL || ludpp == NULL ) {
 
808
                return LDAP_URL_ERR_PARAM;
 
809
        }
 
810
 
 
811
#ifndef LDAP_INT_IN_KERNEL
 
812
        /* Global options may not be created yet
 
813
         * We can't test if the global options are initialized
 
814
         * because a call to LDAP_INT_GLOBAL_OPT() will try to allocate
 
815
         * the options and cause infinite recursion
 
816
         */
 
817
        Debug( LDAP_DEBUG_TRACE, "ldap_url_parse_ext(%s)\n", url_in, 0, 0 );
 
818
#endif
 
819
 
 
820
        *ludpp = NULL;  /* pessimistic */
 
821
 
 
822
        url_tmp = skip_url_prefix( url_in, &enclosed, &scheme );
 
823
 
 
824
        if ( url_tmp == NULL ) {
 
825
                return LDAP_URL_ERR_BADSCHEME;
 
826
        }
 
827
 
 
828
        assert( scheme != NULL );
 
829
 
 
830
        proto = ldap_pvt_url_scheme2proto( scheme );
 
831
        if ( proto == -1 ) {
 
832
                return LDAP_URL_ERR_BADSCHEME;
 
833
        }
 
834
 
 
835
        /* make working copy of the remainder of the URL */
 
836
        url = LDAP_STRDUP( url_tmp );
 
837
        if ( url == NULL ) {
 
838
                return LDAP_URL_ERR_MEM;
 
839
        }
 
840
 
 
841
        if ( enclosed ) {
 
842
                p = &url[strlen(url)-1];
 
843
 
 
844
                if( *p != '>' ) {
 
845
                        LDAP_FREE( url );
 
846
                        return LDAP_URL_ERR_BADENCLOSURE;
 
847
                }
 
848
 
 
849
                *p = '\0';
 
850
        }
 
851
 
 
852
        /* allocate return struct */
 
853
        ludp = (LDAPURLDesc *)LDAP_CALLOC( 1, sizeof( LDAPURLDesc ));
 
854
 
 
855
        if ( ludp == NULL ) {
 
856
                LDAP_FREE( url );
 
857
                return LDAP_URL_ERR_MEM;
 
858
        }
 
859
 
 
860
        ludp->lud_next = NULL;
 
861
        ludp->lud_host = NULL;
 
862
        ludp->lud_port = 0;
 
863
        ludp->lud_dn = NULL;
 
864
        ludp->lud_attrs = NULL;
 
865
        ludp->lud_scope = ( flags & LDAP_PVT_URL_PARSE_NODEF_SCOPE ) ? LDAP_SCOPE_BASE : LDAP_SCOPE_DEFAULT;
 
866
        ludp->lud_filter = NULL;
 
867
        ludp->lud_exts = NULL;
 
868
 
 
869
        ludp->lud_scheme = LDAP_STRDUP( scheme );
 
870
 
 
871
        if ( ludp->lud_scheme == NULL ) {
 
872
                LDAP_FREE( url );
 
873
                ldap_free_urldesc( ludp );
 
874
                return LDAP_URL_ERR_MEM;
 
875
        }
 
876
 
 
877
        /* scan forward for '/' that marks end of hostport and begin. of dn */
 
878
        p = strchr( url, '/' );
 
879
        q = NULL;
 
880
 
 
881
        if( p != NULL ) {
 
882
                /* terminate hostport; point to start of dn */
 
883
                *p++ = '\0';
 
884
        } else {
 
885
                /* check for Novell kludge, see below */
 
886
                p = strchr( url, '?' );
 
887
                if ( p ) {
 
888
                        *p++ = '\0';
 
889
                        q = p;
 
890
                        p = NULL;
 
891
                }
 
892
        }
 
893
 
 
894
        if ( proto != LDAP_PROTO_IPC ) {
 
895
                /* IPv6 syntax with [ip address]:port */
 
896
                if ( *url == '[' ) {
 
897
                        r = strchr( url, ']' );
 
898
                        if ( r == NULL ) {
 
899
                                LDAP_FREE( url );
 
900
                                ldap_free_urldesc( ludp );
 
901
                                return LDAP_URL_ERR_BADURL;
 
902
                        }
 
903
                        *r++ = '\0';
 
904
                        q = strchr( r, ':' );
 
905
                        if ( q && q != r ) {
 
906
                                LDAP_FREE( url );
 
907
                                ldap_free_urldesc( ludp );
 
908
                                return LDAP_URL_ERR_BADURL;
 
909
                        }
 
910
                        is_v6 = 1;
 
911
                } else {
 
912
                        q = strchr( url, ':' );
 
913
                }
 
914
 
 
915
                if ( q != NULL ) {
 
916
                        char    *next;
 
917
 
 
918
                        *q++ = '\0';
 
919
                        ldap_pvt_hex_unescape( q );
 
920
 
 
921
                        if( *q == '\0' ) {
 
922
                                LDAP_FREE( url );
 
923
                                ldap_free_urldesc( ludp );
 
924
                                return LDAP_URL_ERR_BADURL;
 
925
                        }
 
926
 
 
927
                        ludp->lud_port = strtol( q, &next, 10 );
 
928
                        if ( next == q || next[0] != '\0' ) {
 
929
                                LDAP_FREE( url );
 
930
                                ldap_free_urldesc( ludp );
 
931
                                return LDAP_URL_ERR_BADURL;
 
932
                        }
 
933
                        /* check for Novell kludge */
 
934
                        if ( !p ) {
 
935
                                if ( *next != '\0' ) {
 
936
                                        q = &next[1];
 
937
                                } else {
 
938
                                        q = NULL;
 
939
                                }
 
940
                        }
 
941
                }
 
942
 
 
943
                if ( ( flags & LDAP_PVT_URL_PARSE_DEF_PORT ) && ludp->lud_port == 0 ) {
 
944
                        if ( strcmp( ludp->lud_scheme, "ldaps" ) == 0 ) {
 
945
                                ludp->lud_port = LDAPS_PORT;
 
946
                        } else {
 
947
                                ludp->lud_port = LDAP_PORT;
 
948
                        }
 
949
                }
 
950
        }
 
951
 
 
952
        ldap_pvt_hex_unescape( url );
 
953
 
 
954
        /* If [ip address]:port syntax, url is [ip and we skip the [ */
 
955
        ludp->lud_host = LDAP_STRDUP( url + is_v6 );
 
956
 
 
957
        if( ludp->lud_host == NULL ) {
 
958
                LDAP_FREE( url );
 
959
                ldap_free_urldesc( ludp );
 
960
                return LDAP_URL_ERR_MEM;
 
961
        }
 
962
 
 
963
        if ( ( flags & LDAP_PVT_URL_PARSE_NOEMPTY_HOST )
 
964
                && ludp->lud_host != NULL
 
965
                && *ludp->lud_host == '\0' )
 
966
        {
 
967
                LDAP_FREE( ludp->lud_host );
 
968
                ludp->lud_host = NULL;
 
969
        }
 
970
 
 
971
        /*
 
972
         * Kludge.  ldap://111.222.333.444:389??cn=abc,o=company
 
973
         *
 
974
         * On early Novell releases, search references/referrals were returned
 
975
         * in this format, i.e., the dn was kind of in the scope position,
 
976
         * but the required slash is missing. The whole thing is illegal syntax,
 
977
         * but we need to account for it. Fortunately it can't be confused with
 
978
         * anything real.
 
979
         */
 
980
        if( (p == NULL) && (q != NULL) && (*q == '?') ) {
 
981
                /* ? immediately followed by question */
 
982
                q++;
 
983
                if( *q != '\0' ) {
 
984
                        /* parse dn part */
 
985
                        ldap_pvt_hex_unescape( q );
 
986
                        ludp->lud_dn = LDAP_STRDUP( q );
 
987
 
 
988
                } else if ( !( flags & LDAP_PVT_URL_PARSE_NOEMPTY_DN ) ) {
 
989
                        ludp->lud_dn = LDAP_STRDUP( "" );
 
990
 
 
991
                } else {
 
992
                        check_dn = 0;
 
993
                }
 
994
 
 
995
                if ( check_dn && ludp->lud_dn == NULL ) {
 
996
                        LDAP_FREE( url );
 
997
                        ldap_free_urldesc( ludp );
 
998
                        return LDAP_URL_ERR_MEM;
 
999
                }
 
1000
        }
 
1001
 
 
1002
        if( p == NULL ) {
 
1003
                LDAP_FREE( url );
 
1004
                *ludpp = ludp;
 
1005
                return LDAP_URL_SUCCESS;
 
1006
        }
 
1007
 
 
1008
        /* scan forward for '?' that may marks end of dn */
 
1009
        q = strchr( p, '?' );
 
1010
 
 
1011
        if( q != NULL ) {
 
1012
                /* terminate dn part */
 
1013
                *q++ = '\0';
 
1014
        }
 
1015
 
 
1016
        if( *p != '\0' ) {
 
1017
                /* parse dn part */
 
1018
                ldap_pvt_hex_unescape( p );
 
1019
                ludp->lud_dn = LDAP_STRDUP( p );
 
1020
 
 
1021
        } else if ( !( flags & LDAP_PVT_URL_PARSE_NOEMPTY_DN ) ) {
 
1022
                ludp->lud_dn = LDAP_STRDUP( "" );
 
1023
 
 
1024
        } else {
 
1025
                check_dn = 0;
 
1026
        }
 
1027
 
 
1028
        if( check_dn && ludp->lud_dn == NULL ) {
 
1029
                LDAP_FREE( url );
 
1030
                ldap_free_urldesc( ludp );
 
1031
                return LDAP_URL_ERR_MEM;
 
1032
        }
 
1033
 
 
1034
        if( q == NULL ) {
 
1035
                /* no more */
 
1036
                LDAP_FREE( url );
 
1037
                *ludpp = ludp;
 
1038
                return LDAP_URL_SUCCESS;
 
1039
        }
 
1040
 
 
1041
        /* scan forward for '?' that may marks end of attributes */
 
1042
        p = q;
 
1043
        q = strchr( p, '?' );
 
1044
 
 
1045
        if( q != NULL ) {
 
1046
                /* terminate attributes part */
 
1047
                *q++ = '\0';
 
1048
        }
 
1049
 
 
1050
        if( *p != '\0' ) {
 
1051
                /* parse attributes */
 
1052
                ldap_pvt_hex_unescape( p );
 
1053
                ludp->lud_attrs = ldap_str2charray( p, "," );
 
1054
 
 
1055
                if( ludp->lud_attrs == NULL ) {
 
1056
                        LDAP_FREE( url );
 
1057
                        ldap_free_urldesc( ludp );
 
1058
                        return LDAP_URL_ERR_BADATTRS;
 
1059
                }
 
1060
        }
 
1061
 
 
1062
        if ( q == NULL ) {
 
1063
                /* no more */
 
1064
                LDAP_FREE( url );
 
1065
                *ludpp = ludp;
 
1066
                return LDAP_URL_SUCCESS;
 
1067
        }
 
1068
 
 
1069
        /* scan forward for '?' that may marks end of scope */
 
1070
        p = q;
 
1071
        q = strchr( p, '?' );
 
1072
 
 
1073
        if( q != NULL ) {
 
1074
                /* terminate the scope part */
 
1075
                *q++ = '\0';
 
1076
        }
 
1077
 
 
1078
        if( *p != '\0' ) {
 
1079
                /* parse the scope */
 
1080
                ldap_pvt_hex_unescape( p );
 
1081
                ludp->lud_scope = ldap_pvt_str2scope( p );
 
1082
 
 
1083
                if( ludp->lud_scope == -1 ) {
 
1084
                        LDAP_FREE( url );
 
1085
                        ldap_free_urldesc( ludp );
 
1086
                        return LDAP_URL_ERR_BADSCOPE;
 
1087
                }
 
1088
        }
 
1089
 
 
1090
        if ( q == NULL ) {
 
1091
                /* no more */
 
1092
                LDAP_FREE( url );
 
1093
                *ludpp = ludp;
 
1094
                return LDAP_URL_SUCCESS;
 
1095
        }
 
1096
 
 
1097
        /* scan forward for '?' that may marks end of filter */
 
1098
        p = q;
 
1099
        q = strchr( p, '?' );
 
1100
 
 
1101
        if( q != NULL ) {
 
1102
                /* terminate the filter part */
 
1103
                *q++ = '\0';
 
1104
        }
 
1105
 
 
1106
        if( *p != '\0' ) {
 
1107
                /* parse the filter */
 
1108
                ldap_pvt_hex_unescape( p );
 
1109
 
 
1110
                if( ! *p ) {
 
1111
                        /* missing filter */
 
1112
                        LDAP_FREE( url );
 
1113
                        ldap_free_urldesc( ludp );
 
1114
                        return LDAP_URL_ERR_BADFILTER;
 
1115
                }
 
1116
 
 
1117
                ludp->lud_filter = LDAP_STRDUP( p );
 
1118
 
 
1119
                if( ludp->lud_filter == NULL ) {
 
1120
                        LDAP_FREE( url );
 
1121
                        ldap_free_urldesc( ludp );
 
1122
                        return LDAP_URL_ERR_MEM;
 
1123
                }
 
1124
        }
 
1125
 
 
1126
        if ( q == NULL ) {
 
1127
                /* no more */
 
1128
                LDAP_FREE( url );
 
1129
                *ludpp = ludp;
 
1130
                return LDAP_URL_SUCCESS;
 
1131
        }
 
1132
 
 
1133
        /* scan forward for '?' that may marks end of extensions */
 
1134
        p = q;
 
1135
        q = strchr( p, '?' );
 
1136
 
 
1137
        if( q != NULL ) {
 
1138
                /* extra '?' */
 
1139
                LDAP_FREE( url );
 
1140
                ldap_free_urldesc( ludp );
 
1141
                return LDAP_URL_ERR_BADURL;
 
1142
        }
 
1143
 
 
1144
        /* parse the extensions */
 
1145
        ludp->lud_exts = ldap_str2charray( p, "," );
 
1146
 
 
1147
        if( ludp->lud_exts == NULL ) {
 
1148
                LDAP_FREE( url );
 
1149
                ldap_free_urldesc( ludp );
 
1150
                return LDAP_URL_ERR_BADEXTS;
 
1151
        }
 
1152
 
 
1153
        for( i=0; ludp->lud_exts[i] != NULL; i++ ) {
 
1154
                ldap_pvt_hex_unescape( ludp->lud_exts[i] );
 
1155
 
 
1156
                if( *ludp->lud_exts[i] == '!' ) {
 
1157
                        /* count the number of critical extensions */
 
1158
                        ludp->lud_crit_exts++;
 
1159
                }
 
1160
        }
 
1161
 
 
1162
        if( i == 0 ) {
 
1163
                /* must have 1 or more */
 
1164
                LDAP_FREE( url );
 
1165
                ldap_free_urldesc( ludp );
 
1166
                return LDAP_URL_ERR_BADEXTS;
 
1167
        }
 
1168
 
 
1169
        /* no more */
 
1170
        *ludpp = ludp;
 
1171
        LDAP_FREE( url );
 
1172
        return LDAP_URL_SUCCESS;
 
1173
}
 
1174
 
 
1175
int
 
1176
ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp )
 
1177
{
 
1178
        return ldap_url_parse_ext( url_in, ludpp, LDAP_PVT_URL_PARSE_HISTORIC );
 
1179
}
 
1180
 
 
1181
LDAPURLDesc *
 
1182
ldap_url_dup ( LDAPURLDesc *ludp )
 
1183
{
 
1184
        LDAPURLDesc *dest;
 
1185
 
 
1186
        if ( ludp == NULL ) {
 
1187
                return NULL;
 
1188
        }
 
1189
 
 
1190
        dest = LDAP_MALLOC( sizeof(LDAPURLDesc) );
 
1191
        if (dest == NULL)
 
1192
                return NULL;
 
1193
        
 
1194
        *dest = *ludp;
 
1195
        dest->lud_scheme = NULL;
 
1196
        dest->lud_host = NULL;
 
1197
        dest->lud_dn = NULL;
 
1198
        dest->lud_filter = NULL;
 
1199
        dest->lud_attrs = NULL;
 
1200
        dest->lud_exts = NULL;
 
1201
        dest->lud_next = NULL;
 
1202
 
 
1203
        if ( ludp->lud_scheme != NULL ) {
 
1204
                dest->lud_scheme = LDAP_STRDUP( ludp->lud_scheme );
 
1205
                if (dest->lud_scheme == NULL) {
 
1206
                        ldap_free_urldesc(dest);
 
1207
                        return NULL;
 
1208
                }
 
1209
        }
 
1210
 
 
1211
        if ( ludp->lud_host != NULL ) {
 
1212
                dest->lud_host = LDAP_STRDUP( ludp->lud_host );
 
1213
                if (dest->lud_host == NULL) {
 
1214
                        ldap_free_urldesc(dest);
 
1215
                        return NULL;
 
1216
                }
 
1217
        }
 
1218
 
 
1219
        if ( ludp->lud_dn != NULL ) {
 
1220
                dest->lud_dn = LDAP_STRDUP( ludp->lud_dn );
 
1221
                if (dest->lud_dn == NULL) {
 
1222
                        ldap_free_urldesc(dest);
 
1223
                        return NULL;
 
1224
                }
 
1225
        }
 
1226
 
 
1227
        if ( ludp->lud_filter != NULL ) {
 
1228
                dest->lud_filter = LDAP_STRDUP( ludp->lud_filter );
 
1229
                if (dest->lud_filter == NULL) {
 
1230
                        ldap_free_urldesc(dest);
 
1231
                        return NULL;
 
1232
                }
 
1233
        }
 
1234
 
 
1235
        if ( ludp->lud_attrs != NULL ) {
 
1236
                dest->lud_attrs = ldap_charray_dup( ludp->lud_attrs );
 
1237
                if (dest->lud_attrs == NULL) {
 
1238
                        ldap_free_urldesc(dest);
 
1239
                        return NULL;
 
1240
                }
 
1241
        }
 
1242
 
 
1243
        if ( ludp->lud_exts != NULL ) {
 
1244
                dest->lud_exts = ldap_charray_dup( ludp->lud_exts );
 
1245
                if (dest->lud_exts == NULL) {
 
1246
                        ldap_free_urldesc(dest);
 
1247
                        return NULL;
 
1248
                }
 
1249
        }
 
1250
 
 
1251
        return dest;
 
1252
}
 
1253
 
 
1254
LDAPURLDesc *
 
1255
ldap_url_duplist (LDAPURLDesc *ludlist)
 
1256
{
 
1257
        LDAPURLDesc *dest, *tail, *ludp, *newludp;
 
1258
 
 
1259
        dest = NULL;
 
1260
        tail = NULL;
 
1261
        for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
 
1262
                newludp = ldap_url_dup(ludp);
 
1263
                if (newludp == NULL) {
 
1264
                        ldap_free_urllist(dest);
 
1265
                        return NULL;
 
1266
                }
 
1267
                if (tail == NULL)
 
1268
                        dest = newludp;
 
1269
                else
 
1270
                        tail->lud_next = newludp;
 
1271
                tail = newludp;
 
1272
        }
 
1273
        return dest;
 
1274
}
 
1275
 
 
1276
static int
 
1277
ldap_url_parselist_int (LDAPURLDesc **ludlist, const char *url, const char *sep, unsigned flags )
 
1278
 
 
1279
{
 
1280
        int i, rc;
 
1281
        LDAPURLDesc *ludp;
 
1282
        char **urls;
 
1283
 
 
1284
        assert( ludlist != NULL );
 
1285
        assert( url != NULL );
 
1286
 
 
1287
        *ludlist = NULL;
 
1288
 
 
1289
        if ( sep == NULL ) {
 
1290
                sep = ", ";
 
1291
        }
 
1292
 
 
1293
        urls = ldap_str2charray( url, sep );
 
1294
        if (urls == NULL)
 
1295
                return LDAP_URL_ERR_MEM;
 
1296
 
 
1297
        /* count the URLs... */
 
1298
        for (i = 0; urls[i] != NULL; i++) ;
 
1299
        /* ...and put them in the "stack" backward */
 
1300
        while (--i >= 0) {
 
1301
                rc = ldap_url_parse_ext( urls[i], &ludp, flags );
 
1302
                if ( rc != 0 ) {
 
1303
                        ldap_charray_free( urls );
 
1304
                        ldap_free_urllist( *ludlist );
 
1305
                        *ludlist = NULL;
 
1306
                        return rc;
 
1307
                }
 
1308
                ludp->lud_next = *ludlist;
 
1309
                *ludlist = ludp;
 
1310
        }
 
1311
        ldap_charray_free( urls );
 
1312
        return LDAP_URL_SUCCESS;
 
1313
}
 
1314
 
 
1315
int
 
1316
ldap_url_parselist (LDAPURLDesc **ludlist, const char *url )
 
1317
{
 
1318
        return ldap_url_parselist_int( ludlist, url, ", ", LDAP_PVT_URL_PARSE_HISTORIC );
 
1319
}
 
1320
 
 
1321
int
 
1322
ldap_url_parselist_ext (LDAPURLDesc **ludlist, const char *url, const char *sep, unsigned flags )
 
1323
{
 
1324
        return ldap_url_parselist_int( ludlist, url, sep, flags );
 
1325
}
 
1326
 
 
1327
int
 
1328
ldap_url_parsehosts(
 
1329
        LDAPURLDesc **ludlist,
 
1330
        const char *hosts,
 
1331
        int port )
 
1332
{
 
1333
        int i;
 
1334
        LDAPURLDesc *ludp;
 
1335
        char **specs, *p;
 
1336
 
 
1337
        assert( ludlist != NULL );
 
1338
        assert( hosts != NULL );
 
1339
 
 
1340
        *ludlist = NULL;
 
1341
 
 
1342
        specs = ldap_str2charray(hosts, ", ");
 
1343
        if (specs == NULL)
 
1344
                return LDAP_NO_MEMORY;
 
1345
 
 
1346
        /* count the URLs... */
 
1347
        for (i = 0; specs[i] != NULL; i++) /* EMPTY */;
 
1348
 
 
1349
        /* ...and put them in the "stack" backward */
 
1350
        while (--i >= 0) {
 
1351
                ludp = LDAP_CALLOC( 1, sizeof(LDAPURLDesc) );
 
1352
                if (ludp == NULL) {
 
1353
                        ldap_charray_free(specs);
 
1354
                        ldap_free_urllist(*ludlist);
 
1355
                        *ludlist = NULL;
 
1356
                        return LDAP_NO_MEMORY;
 
1357
                }
 
1358
                ludp->lud_port = port;
 
1359
                ludp->lud_host = specs[i];
 
1360
                specs[i] = NULL;
 
1361
                p = strchr(ludp->lud_host, ':');
 
1362
                if (p != NULL) {
 
1363
                        /* more than one :, IPv6 address */
 
1364
                        if ( strchr(p+1, ':') != NULL ) {
 
1365
                                /* allow [address] and [address]:port */
 
1366
                                if ( *ludp->lud_host == '[' ) {
 
1367
                                        p = LDAP_STRDUP(ludp->lud_host+1);
 
1368
                                        /* copied, make sure we free source later */
 
1369
                                        specs[i] = ludp->lud_host;
 
1370
                                        ludp->lud_host = p;
 
1371
                                        p = strchr( ludp->lud_host, ']' );
 
1372
                                        if ( p == NULL ) {
 
1373
                                                LDAP_FREE(ludp);
 
1374
                                                ldap_charray_free(specs);
 
1375
                                                return LDAP_PARAM_ERROR;
 
1376
                                        }
 
1377
                                        *p++ = '\0';
 
1378
                                        if ( *p != ':' ) {
 
1379
                                                if ( *p != '\0' ) {
 
1380
                                                        LDAP_FREE(ludp);
 
1381
                                                        ldap_charray_free(specs);
 
1382
                                                        return LDAP_PARAM_ERROR;
 
1383
                                                }
 
1384
                                                p = NULL;
 
1385
                                        }
 
1386
                                } else {
 
1387
                                        p = NULL;
 
1388
                                }
 
1389
                        }
 
1390
                        if (p != NULL) {
 
1391
                                char    *next;
 
1392
 
 
1393
                                *p++ = 0;
 
1394
                                ldap_pvt_hex_unescape(p);
 
1395
                                ludp->lud_port = strtol( p, &next, 10 );
 
1396
                                if ( next == p || next[0] != '\0' ) {
 
1397
                                        LDAP_FREE(ludp);
 
1398
                                        ldap_charray_free(specs);
 
1399
                                        return LDAP_PARAM_ERROR;
 
1400
                                }
 
1401
                        }
 
1402
                }
 
1403
                ldap_pvt_hex_unescape(ludp->lud_host);
 
1404
                ludp->lud_scheme = LDAP_STRDUP("ldap");
 
1405
                ludp->lud_next = *ludlist;
 
1406
                *ludlist = ludp;
 
1407
        }
 
1408
 
 
1409
        /* this should be an array of NULLs now */
 
1410
        /* except entries starting with [ */
 
1411
        ldap_charray_free(specs);
 
1412
        return LDAP_SUCCESS;
 
1413
}
 
1414
 
 
1415
char *
 
1416
ldap_url_list2hosts (LDAPURLDesc *ludlist)
 
1417
{
 
1418
        LDAPURLDesc *ludp;
 
1419
        int size;
 
1420
        char *s, *p, buf[32];   /* big enough to hold a long decimal # (overkill) */
 
1421
 
 
1422
        if (ludlist == NULL)
 
1423
                return NULL;
 
1424
 
 
1425
        /* figure out how big the string is */
 
1426
        size = 1;       /* nul-term */
 
1427
        for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
 
1428
                size += strlen(ludp->lud_host) + 1;             /* host and space */
 
1429
                if (strchr(ludp->lud_host, ':'))        /* will add [ ] below */
 
1430
                        size += 2;
 
1431
                if (ludp->lud_port != 0)
 
1432
                        size += sprintf(buf, ":%d", ludp->lud_port);
 
1433
        }
 
1434
        s = LDAP_MALLOC(size);
 
1435
        if (s == NULL)
 
1436
                return NULL;
 
1437
 
 
1438
        p = s;
 
1439
        for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
 
1440
                if (strchr(ludp->lud_host, ':')) {
 
1441
                        p += sprintf(p, "[%s]", ludp->lud_host);
 
1442
                } else {
 
1443
                        strcpy(p, ludp->lud_host);
 
1444
                        p += strlen(ludp->lud_host);
 
1445
                }
 
1446
                if (ludp->lud_port != 0)
 
1447
                        p += sprintf(p, ":%d", ludp->lud_port);
 
1448
                *p++ = ' ';
 
1449
        }
 
1450
        if (p != s)
 
1451
                p--;    /* nuke that extra space */
 
1452
        *p = 0;
 
1453
        return s;
 
1454
}
 
1455
 
 
1456
char *
 
1457
ldap_url_list2urls(
 
1458
        LDAPURLDesc *ludlist )
 
1459
{
 
1460
        LDAPURLDesc     *ludp;
 
1461
        int             size, sofar;
 
1462
        char            *s;
 
1463
 
 
1464
        if ( ludlist == NULL ) {
 
1465
                return NULL;
 
1466
        }
 
1467
 
 
1468
        /* figure out how big the string is */
 
1469
        for ( size = 0, ludp = ludlist; ludp != NULL; ludp = ludp->lud_next ) {
 
1470
                int     len = desc2str_len( ludp );
 
1471
                if ( len < 0 ) {
 
1472
                        return NULL;
 
1473
                }
 
1474
                size += len + 1;
 
1475
        }
 
1476
        
 
1477
        s = LDAP_MALLOC( size );
 
1478
 
 
1479
        if ( s == NULL ) {
 
1480
                return NULL;
 
1481
        }
 
1482
 
 
1483
        for ( sofar = 0, ludp = ludlist; ludp != NULL; ludp = ludp->lud_next ) {
 
1484
                int     len;
 
1485
 
 
1486
                len = desc2str( ludp, &s[sofar], size );
 
1487
                
 
1488
                if ( len < 0 ) {
 
1489
                        LDAP_FREE( s );
 
1490
                        return NULL;
 
1491
                }
 
1492
 
 
1493
                sofar += len;
 
1494
                size -= len;
 
1495
 
 
1496
                s[sofar++] = ' ';
 
1497
                size--;
 
1498
 
 
1499
                assert( size >= 0 );
 
1500
        }
 
1501
 
 
1502
        s[sofar - 1] = '\0';
 
1503
 
 
1504
        return s;
 
1505
}
 
1506
 
 
1507
void
 
1508
ldap_free_urllist( LDAPURLDesc *ludlist )
 
1509
{
 
1510
        LDAPURLDesc *ludp, *next;
 
1511
 
 
1512
        for (ludp = ludlist; ludp != NULL; ludp = next) {
 
1513
                next = ludp->lud_next;
 
1514
                ldap_free_urldesc(ludp);
 
1515
        }
 
1516
}
 
1517
 
 
1518
void
 
1519
ldap_free_urldesc( LDAPURLDesc *ludp )
 
1520
{
 
1521
        if ( ludp == NULL ) {
 
1522
                return;
 
1523
        }
 
1524
        
 
1525
        if ( ludp->lud_scheme != NULL ) {
 
1526
                LDAP_FREE( ludp->lud_scheme );
 
1527
        }
 
1528
 
 
1529
        if ( ludp->lud_host != NULL ) {
 
1530
                LDAP_FREE( ludp->lud_host );
 
1531
        }
 
1532
 
 
1533
        if ( ludp->lud_dn != NULL ) {
 
1534
                LDAP_FREE( ludp->lud_dn );
 
1535
        }
 
1536
 
 
1537
        if ( ludp->lud_filter != NULL ) {
 
1538
                LDAP_FREE( ludp->lud_filter);
 
1539
        }
 
1540
 
 
1541
        if ( ludp->lud_attrs != NULL ) {
 
1542
                LDAP_VFREE( ludp->lud_attrs );
 
1543
        }
 
1544
 
 
1545
        if ( ludp->lud_exts != NULL ) {
 
1546
                LDAP_VFREE( ludp->lud_exts );
 
1547
        }
 
1548
 
 
1549
        LDAP_FREE( ludp );
 
1550
}
 
1551
 
 
1552
static int
 
1553
ldap_int_is_hexpair( char *s )
 
1554
{
 
1555
        int     i;
 
1556
 
 
1557
        for ( i = 0; i < 2; i++ ) {
 
1558
                if ( s[i] >= '0' && s[i] <= '9' ) {
 
1559
                        continue;
 
1560
                }
 
1561
 
 
1562
                if ( s[i] >= 'A' && s[i] <= 'F' ) {
 
1563
                        continue;
 
1564
                }
 
1565
 
 
1566
                if ( s[i] >= 'a' && s[i] <= 'f' ) {
 
1567
                        continue;
 
1568
                }
 
1569
 
 
1570
                return 0;
 
1571
        }
 
1572
        
 
1573
        return 1;       
 
1574
}
 
1575
        
 
1576
static int
 
1577
ldap_int_unhex( int c )
 
1578
{
 
1579
        return( c >= '0' && c <= '9' ? c - '0'
 
1580
            : c >= 'A' && c <= 'F' ? c - 'A' + 10
 
1581
            : c - 'a' + 10 );
 
1582
}
 
1583
 
 
1584
void
 
1585
ldap_pvt_hex_unescape( char *s )
 
1586
{
 
1587
        /*
 
1588
         * Remove URL hex escapes from s... done in place.  The basic concept for
 
1589
         * this routine is borrowed from the WWW library HTUnEscape() routine.
 
1590
         */
 
1591
        char    *p,
 
1592
                *save_s = s;
 
1593
 
 
1594
        for ( p = s; *s != '\0'; ++s ) {
 
1595
                if ( *s == '%' ) {
 
1596
                        /*
 
1597
                         * FIXME: what if '%' is followed
 
1598
                         * by non-hexpair chars?
 
1599
                         */
 
1600
                        if ( !ldap_int_is_hexpair( s + 1 ) ) {
 
1601
                                p = save_s;
 
1602
                                break;
 
1603
                        }
 
1604
 
 
1605
                        if ( *++s == '\0' ) {
 
1606
                                break;
 
1607
                        }
 
1608
                        *p = ldap_int_unhex( *s ) << 4;
 
1609
                        if ( *++s == '\0' ) {
 
1610
                                break;
 
1611
                        }
 
1612
                        *p++ += ldap_int_unhex( *s );
 
1613
                } else {
 
1614
                        *p++ = *s;
 
1615
                }
 
1616
        }
 
1617
 
 
1618
        *p = '\0';
 
1619
}
 
1620