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