1 /* The following code comes from the OpenLDAP project. The references
2 to the COPYRIGHT file below refer to the corresponding file in the
3 OpenLDAP distribution, which is reproduced here in full:
5 Copyright 1998-2004 The OpenLDAP Foundation
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted only as authorized by the OpenLDAP
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>.
16 OpenLDAP is a registered trademark of the OpenLDAP Foundation.
18 Individual files and/or contributed packages may be copyright by
19 other parties and subject to additional restrictions.
21 This work is derived from the University of Michigan LDAP v3.3
22 distribution. Information concerning this software is available
23 at <http://www.umich.edu/~dirsvcs/ldap/>.
25 This work also contains materials derived from public sources.
27 Additional information about OpenLDAP can be obtained at
28 <http://www.openldap.org/>.
32 Portions Copyright 1998-2004 Kurt D. Zeilenga.
33 Portions Copyright 1998-2004 Net Boolean Incorporated.
34 Portions Copyright 2001-2004 IBM Corporation.
37 Redistribution and use in source and binary forms, with or without
38 modification, are permitted only as authorized by the OpenLDAP
43 Portions Copyright 1999-2003 Howard Y.H. Chu.
44 Portions Copyright 1999-2003 Symas Corporation.
45 Portions Copyright 1998-2003 Hallvard B. Furuseth.
48 Redistribution and use in source and binary forms, with or without
49 modification, are permitted provided that this notice is preserved.
50 The names of the copyright holders may not be used to endorse or
51 promote products derived from this software without their specific
52 prior written permission. This software is provided `'as is''
53 without express or implied warranty.
57 Portions Copyright (c) 1992-1996 Regents of the University of Michigan.
60 Redistribution and use in source and binary forms are permitted
61 provided that this notice is preserved and that due credit is given
62 to the University of Michigan at Ann Arbor. The name of the
63 University may not be used to endorse or promote products derived
64 from this software without specific prior written permission. This
65 software is provided `'as is'' without express or implied warranty. */
78 #define LDAP_P(protos) protos
79 #define LDAP_URL_URLCOLON "URL:"
80 #define LDAP_URL_URLCOLON_LEN (sizeof(LDAP_URL_URLCOLON)-1)
81 #define LDAP_URL_PREFIX "ldap://"
82 #define LDAP_URL_PREFIX_LEN (sizeof(LDAP_URL_PREFIX)-1)
83 #define LDAPS_URL_PREFIX "ldaps://"
84 #define LDAPS_URL_PREFIX_LEN (sizeof(LDAPS_URL_PREFIX)-1)
85 #define LDAPI_URL_PREFIX "ldapi://"
86 #define LDAPI_URL_PREFIX_LEN (sizeof(LDAPI_URL_PREFIX)-1)
87 #define LDAP_VFREE(v) { int _i; for (_i = 0; (v)[_i]; _i++) free((v)[_i]); }
88 #define LDAP_FREE free
89 #define LDAP_STRDUP strdup
90 #define LDAP_CALLOC calloc
91 #define LDAP_MALLOC malloc
92 #define LDAP_REALLOC realloc
93 #define ldap_utf8_strchr strchr
94 #define ldap_utf8_strtok(n,d) strtok (n,d)
95 #define Debug(a,b,c,d,e)
96 void ldap_pvt_hex_unescape( char *s );
99 #ifndef LDAP_SCOPE_DEFAULT
100 # define LDAP_SCOPE_DEFAULT -1
105 /* $OpenLDAP: pkg/ldap/libraries/libldap/charray.c,v 1.9.2.2 2003/03/03 17:10:04 kurt Exp $ */
107 * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
108 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
110 /* charray.c - routines for dealing with char * arrays */
121 *a = (char **) LDAP_MALLOC( 2 * sizeof(char *) );
131 for ( n = 0; *a != NULL && (*a)[n] != NULL; n++ ) {
135 new = (char **) LDAP_REALLOC( (char *) *a,
136 (n + 2) * sizeof(char *) );
139 /* caller is required to call ldap_charray_free(*a) */
146 (*a)[n] = LDAP_STRDUP(s);
148 if( (*a)[n] == NULL ) {
166 for ( n = 0; *a != NULL && (*a)[n] != NULL; n++ ) {
169 for ( nn = 0; s[nn] != NULL; nn++ ) {
173 aa = (char **) LDAP_REALLOC( (char *) *a, (n + nn + 1) * sizeof(char *) );
181 for ( i = 0; i < nn; i++ ) {
182 (*a)[n + i] = LDAP_STRDUP(s[i]);
184 if( (*a)[n + i] == NULL ) {
185 for( --i ; i >= 0 ; i-- ) {
186 LDAP_FREE( (*a)[n + i] );
198 ldap_charray_free( char **a )
206 for ( p = a; *p != NULL; p++ ) {
212 LDAP_FREE( (char *) a );
223 if( a == NULL ) return 0;
225 for ( i=0; a[i] != NULL; i++ ) {
226 if ( strcasecmp( s, a[i] ) == 0 ) {
235 ldap_charray_dup( char **a )
240 for ( i = 0; a[i] != NULL; i++ )
243 new = (char **) LDAP_MALLOC( (i + 1) * sizeof(char *) );
249 for ( i = 0; a[i] != NULL; i++ ) {
250 new[i] = LDAP_STRDUP( a[i] );
252 if( new[i] == NULL ) {
253 for( --i ; i >= 0 ; i-- ) {
266 ldap_str2charray( const char *str_in, const char *brkstr )
272 /* protect the input string from strtok */
273 str = LDAP_STRDUP( str_in );
279 for ( s = str; *s; s++ ) {
280 if ( ldap_utf8_strchr( brkstr, *s ) != NULL ) {
285 res = (char **) LDAP_MALLOC( (i + 1) * sizeof(char *) );
294 for ( s = ldap_utf8_strtok( str, brkstr);
296 s = ldap_utf8_strtok( NULL, brkstr) )
298 res[i] = LDAP_STRDUP( s );
301 for( --i ; i >= 0 ; i-- ) {
318 char * ldap_charray2str( char **a, const char *sep )
324 if( sep == NULL ) sep = " ";
326 slen = strlen( sep );
329 for ( v = a; *v != NULL; v++ ) {
330 len += strlen( *v ) + slen;
337 /* trim extra sep len */
340 s = LDAP_MALLOC ( len + 1 );
347 for ( v = a; *v != NULL; v++ ) {
349 strncpy( p, sep, slen );
354 strncpy( p, *v, len );
364 /* $OpenLDAP: pkg/ldap/libraries/libldap/url.c,v 1.64.2.5 2003/03/03 17:10:05 kurt Exp $ */
366 * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
367 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
370 * Copyright (c) 1996 Regents of the University of Michigan.
371 * All rights reserved.
373 * LIBLDAP url.c -- LDAP URL (RFC 2255) related routines
375 * LDAP URLs look like this:
376 * ldap[is]://host:port[/[dn[?[attributes][?[scope][?[filter][?exts]]]]]]
379 * attributes is a comma separated list
380 * scope is one of these three strings: base one sub (default=base)
381 * filter is an string-represented filter as in RFC 2254
383 * e.g., ldap://host:port/dc=com?o,cn?base?(o=openldap)?extension
385 * We also tolerate URLs that look like: <ldapurl> and <URL:ldapurl>
388 /* local functions */
389 static const char* skip_url_prefix LDAP_P((
392 const char **scheme ));
395 ldap_is_ldap_url( LDAP_CONST char *url )
404 if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) {
416 const char **scheme )
419 * return non-zero if this looks like a LDAP URL; zero if not
420 * if non-zero returned, *urlp will be moved past "ldap://" part of URL
430 /* skip leading '<' (if any) */
438 /* skip leading "URL:" (if any) */
439 if ( strncasecmp( p, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) {
440 p += LDAP_URL_URLCOLON_LEN;
443 /* check for "ldap://" prefix */
444 if ( strncasecmp( p, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) == 0 ) {
445 /* skip over "ldap://" prefix and return success */
446 p += LDAP_URL_PREFIX_LEN;
451 /* check for "ldaps://" prefix */
452 if ( strncasecmp( p, LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) {
453 /* skip over "ldaps://" prefix and return success */
454 p += LDAPS_URL_PREFIX_LEN;
459 /* check for "ldapi://" prefix */
460 if ( strncasecmp( p, LDAPI_URL_PREFIX, LDAPI_URL_PREFIX_LEN ) == 0 ) {
461 /* skip over "ldapi://" prefix and return success */
462 p += LDAPI_URL_PREFIX_LEN;
467 #ifdef LDAP_CONNECTIONLESS
468 /* check for "cldap://" prefix */
469 if ( strncasecmp( p, LDAPC_URL_PREFIX, LDAPC_URL_PREFIX_LEN ) == 0 ) {
470 /* skip over "cldap://" prefix and return success */
471 p += LDAPC_URL_PREFIX_LEN;
481 static int str2scope( const char *p )
483 if ( strcasecmp( p, "one" ) == 0 ) {
484 return LDAP_SCOPE_ONELEVEL;
486 } else if ( strcasecmp( p, "onetree" ) == 0 ) {
487 return LDAP_SCOPE_ONELEVEL;
489 } else if ( strcasecmp( p, "base" ) == 0 ) {
490 return LDAP_SCOPE_BASE;
492 } else if ( strcasecmp( p, "sub" ) == 0 ) {
493 return LDAP_SCOPE_SUBTREE;
495 } else if ( strcasecmp( p, "subtree" ) == 0 ) {
496 return LDAP_SCOPE_SUBTREE;
504 ldap_url_parse_ext( LDAP_CONST char *url_in, LDAPURLDesc **ludpp )
507 * Pick apart the pieces of an LDAP URL.
513 const char *scheme = NULL;
517 if( url_in == NULL || ludpp == NULL ) {
518 return LDAP_URL_ERR_PARAM;
521 #ifndef LDAP_INT_IN_KERNEL
522 /* Global options may not be created yet
523 * We can't test if the global options are initialized
524 * because a call to LDAP_INT_GLOBAL_OPT() will try to allocate
525 * the options and cause infinite recursion
528 LDAP_LOG ( OPERATION, ENTRY, "ldap_url_parse_ext(%s)\n", url_in, 0, 0 );
530 Debug( LDAP_DEBUG_TRACE, "ldap_url_parse_ext(%s)\n", url_in, 0, 0 );
534 *ludpp = NULL; /* pessimistic */
536 url_tmp = skip_url_prefix( url_in, &enclosed, &scheme );
538 if ( url_tmp == NULL ) {
539 return LDAP_URL_ERR_BADSCHEME;
544 /* make working copy of the remainder of the URL */
545 url = LDAP_STRDUP( url_tmp );
547 return LDAP_URL_ERR_MEM;
551 p = &url[strlen(url)-1];
555 return LDAP_URL_ERR_BADENCLOSURE;
561 /* allocate return struct */
562 ludp = (LDAPURLDesc *)LDAP_CALLOC( 1, sizeof( LDAPURLDesc ));
564 if ( ludp == NULL ) {
566 return LDAP_URL_ERR_MEM;
569 ludp->lud_next = NULL;
570 ludp->lud_host = NULL;
573 ludp->lud_attrs = NULL;
574 ludp->lud_filter = NULL;
575 ludp->lud_scope = LDAP_SCOPE_DEFAULT;
576 ludp->lud_filter = NULL;
577 ludp->lud_exts = NULL;
579 ludp->lud_scheme = LDAP_STRDUP( scheme );
581 if ( ludp->lud_scheme == NULL ) {
583 ldap_free_urldesc( ludp );
584 return LDAP_URL_ERR_MEM;
587 /* scan forward for '/' that marks end of hostport and begin. of dn */
588 p = strchr( url, '/' );
591 /* terminate hostport; point to start of dn */
595 /* IPv6 syntax with [ip address]:port */
597 r = strchr( url, ']' );
600 ldap_free_urldesc( ludp );
601 return LDAP_URL_ERR_BADURL;
604 q = strchr( r, ':' );
606 q = strchr( url, ':' );
611 ldap_pvt_hex_unescape( q );
615 ldap_free_urldesc( ludp );
616 return LDAP_URL_ERR_BADURL;
619 ludp->lud_port = atoi( q );
622 ldap_pvt_hex_unescape( url );
624 /* If [ip address]:port syntax, url is [ip and we skip the [ */
625 ludp->lud_host = LDAP_STRDUP( url + ( *url == '[' ) );
627 if( ludp->lud_host == NULL ) {
629 ldap_free_urldesc( ludp );
630 return LDAP_URL_ERR_MEM;
634 * Kludge. ldap://111.222.333.444:389??cn=abc,o=company
636 * On early Novell releases, search references/referrals were returned
637 * in this format, i.e., the dn was kind of in the scope position,
638 * but the required slash is missing. The whole thing is illegal syntax,
639 * but we need to account for it. Fortunately it can't be confused with
642 if( (p == NULL) && (q != NULL) && ((q = strchr( q, '?')) != NULL)) {
644 /* ? immediately followed by question */
649 ldap_pvt_hex_unescape( q );
650 ludp->lud_dn = LDAP_STRDUP( q );
652 ludp->lud_dn = LDAP_STRDUP( "" );
655 if( ludp->lud_dn == NULL ) {
657 ldap_free_urldesc( ludp );
658 return LDAP_URL_ERR_MEM;
666 return LDAP_URL_SUCCESS;
669 /* scan forward for '?' that may marks end of dn */
670 q = strchr( p, '?' );
673 /* terminate dn part */
679 ldap_pvt_hex_unescape( p );
680 ludp->lud_dn = LDAP_STRDUP( p );
682 ludp->lud_dn = LDAP_STRDUP( "" );
685 if( ludp->lud_dn == NULL ) {
687 ldap_free_urldesc( ludp );
688 return LDAP_URL_ERR_MEM;
695 return LDAP_URL_SUCCESS;
698 /* scan forward for '?' that may marks end of attributes */
700 q = strchr( p, '?' );
703 /* terminate attributes part */
708 /* parse attributes */
709 ldap_pvt_hex_unescape( p );
710 ludp->lud_attrs = ldap_str2charray( p, "," );
712 if( ludp->lud_attrs == NULL ) {
714 ldap_free_urldesc( ludp );
715 return LDAP_URL_ERR_BADATTRS;
723 return LDAP_URL_SUCCESS;
726 /* scan forward for '?' that may marks end of scope */
728 q = strchr( p, '?' );
731 /* terminate the scope part */
736 /* parse the scope */
737 ldap_pvt_hex_unescape( p );
738 ludp->lud_scope = str2scope( p );
740 if( ludp->lud_scope == -1 ) {
742 ldap_free_urldesc( ludp );
743 return LDAP_URL_ERR_BADSCOPE;
751 return LDAP_URL_SUCCESS;
754 /* scan forward for '?' that may marks end of filter */
756 q = strchr( p, '?' );
759 /* terminate the filter part */
764 /* parse the filter */
765 ldap_pvt_hex_unescape( p );
770 ldap_free_urldesc( ludp );
771 return LDAP_URL_ERR_BADFILTER;
774 LDAP_FREE( ludp->lud_filter );
775 ludp->lud_filter = LDAP_STRDUP( p );
777 if( ludp->lud_filter == NULL ) {
779 ldap_free_urldesc( ludp );
780 return LDAP_URL_ERR_MEM;
788 return LDAP_URL_SUCCESS;
791 /* scan forward for '?' that may marks end of extensions */
793 q = strchr( p, '?' );
798 ldap_free_urldesc( ludp );
799 return LDAP_URL_ERR_BADURL;
802 /* parse the extensions */
803 ludp->lud_exts = ldap_str2charray( p, "," );
805 if( ludp->lud_exts == NULL ) {
807 ldap_free_urldesc( ludp );
808 return LDAP_URL_ERR_BADEXTS;
811 for( i=0; ludp->lud_exts[i] != NULL; i++ ) {
812 ldap_pvt_hex_unescape( ludp->lud_exts[i] );
814 if( *ludp->lud_exts[i] == '!' ) {
815 /* count the number of critical extensions */
816 ludp->lud_crit_exts++;
821 /* must have 1 or more */
823 ldap_free_urldesc( ludp );
824 return LDAP_URL_ERR_BADEXTS;
830 return LDAP_URL_SUCCESS;
834 ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp )
836 int rc = ldap_url_parse_ext( url_in, ludpp );
838 if( rc != LDAP_URL_SUCCESS ) {
842 if ((*ludpp)->lud_scope == LDAP_SCOPE_DEFAULT) {
843 (*ludpp)->lud_scope = LDAP_SCOPE_BASE;
846 if ((*ludpp)->lud_host != NULL && *(*ludpp)->lud_host == '\0') {
847 LDAP_FREE( (*ludpp)->lud_host );
848 (*ludpp)->lud_host = NULL;
851 if ((*ludpp)->lud_port == 0) {
852 if( strcmp((*ludpp)->lud_scheme, "ldap") == 0 ) {
853 (*ludpp)->lud_port = LDAP_PORT;
854 #ifdef LDAP_CONNECTIONLESS
855 } else if( strcmp((*ludpp)->lud_scheme, "cldap") == 0 ) {
856 (*ludpp)->lud_port = LDAP_PORT;
858 } else if( strcmp((*ludpp)->lud_scheme, "ldaps") == 0 ) {
859 (*ludpp)->lud_port = LDAPS_PORT;
868 ldap_free_urldesc( LDAPURLDesc *ludp )
870 if ( ludp == NULL ) {
874 if ( ludp->lud_scheme != NULL ) {
875 LDAP_FREE( ludp->lud_scheme );
878 if ( ludp->lud_host != NULL ) {
879 LDAP_FREE( ludp->lud_host );
882 if ( ludp->lud_dn != NULL ) {
883 LDAP_FREE( ludp->lud_dn );
886 if ( ludp->lud_filter != NULL ) {
887 LDAP_FREE( ludp->lud_filter);
890 if ( ludp->lud_attrs != NULL ) {
891 LDAP_VFREE( ludp->lud_attrs );
894 if ( ludp->lud_exts != NULL ) {
895 LDAP_VFREE( ludp->lud_exts );
903 ldap_int_unhex( int c )
905 return( c >= '0' && c <= '9' ? c - '0'
906 : c >= 'A' && c <= 'F' ? c - 'A' + 10
911 ldap_pvt_hex_unescape( char *s )
914 * Remove URL hex escapes from s... done in place. The basic concept for
915 * this routine is borrowed from the WWW library HTUnEscape() routine.
919 for ( p = s; *s != '\0'; ++s ) {
921 if ( *++s == '\0' ) {
924 *p = ldap_int_unhex( *s ) << 4;
925 if ( *++s == '\0' ) {
928 *p++ += ldap_int_unhex( *s );