1 /* This is extracted from the OpenLDAP sources.
2 *
3 * Stuff that isn't used in e-book-backend-ldap.c was dropped, like
4 * the LDAPSchemaExtensionItem stuff.
5 *
6 * This file basically has three parts:
7 *
8 * - some general macros from OpenLDAP that work as such on all
9 * implementations.
10 *
11 * - ldap_str2objectclass()
12 *
13 * - ldap_url_parse()
14 */
15
16 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
17 *
18 * Copyright 1998-2005 The OpenLDAP Foundation.
19 * All rights reserved.
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted only as authorized by the OpenLDAP
23 * Public License.
24 *
25 * A copy of this license is available in file COPYING.OPENLDAP in
26 * the top-level directory of the distribution or, alternatively, at
27 * <http://www.OpenLDAP.org/license.html>.
28 */
29
30 #include <string.h>
31 #include <assert.h>
32
33 /* from various header files */
34
35 #define LDAP_CONST const
36
37 #define LDAP_PORT 389 /* ldap:/// default LDAP port */
38 #define LDAPS_PORT 636 /* ldaps:/// default LDAP over TLS port */
39
40 #define LDAP_ROOT_DSE ""
41
42 #define LDAP_SPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
43 #define LDAP_DIGIT(c) ((c) >= '0' && (c) <= '9')
44
45 #define LDAP_EXOP_START_TLS "1.3.6.1.4.1.1466.20037" /* RFC 2830 */
46
47 #define LDAP_MALLOC(n) malloc((n))
48 #define LDAP_CALLOC(n,s) calloc((n),(s))
49 #define LDAP_REALLOC(p,s) realloc((p),(s))
50 #define LDAP_FREE(p) free((p))
51 #define LDAP_VFREE(p) vfree((gpointer *)(p))
52 #define LDAP_STRDUP(s) strdup((s))
53
54 #define LDAP_RANGE(n,x,y) (((x) <= (n)) && ((n) <= (y)))
55 #define LDAP_NAME_ERROR(n) LDAP_RANGE((n),0x20,0x24) /* 32-34,36 */
56
57 #define ldap_msgtype(lm) (lm)->lm_msgtype
58 #define ldap_msgid(lm) (lm)->lm_msgid
59 #ifndef LDAP_TYPE_OR_VALUE_EXISTS
60 #define LDAP_TYPE_OR_VALUE_EXISTS 0x14
61 #endif
62 #ifndef LDAP_SCOPE_DEFAULT
63 #define LDAP_SCOPE_DEFAULT -1
64 #endif
65 #ifndef LDAP_OPT_SUCCESS
66 #define LDAP_OPT_SUCCESS 0x00
67 #endif
68 #ifndef LDAP_INSUFFICIENT_ACCESS
69 #define LDAP_INSUFFICIENT_ACCESS 0x32
70 #endif
71
72 #define LDAP_SCHERR_OUTOFMEM 1
73 #define LDAP_SCHERR_UNEXPTOKEN 2
74 #define LDAP_SCHERR_NOLEFTPAREN 3
75 #define LDAP_SCHERR_NORIGHTPAREN 4
76 #define LDAP_SCHERR_NODIGIT 5
77 #define LDAP_SCHERR_BADNAME 6
78 #define LDAP_SCHERR_BADDESC 7
79 #define LDAP_SCHERR_BADSUP 8
80 #define LDAP_SCHERR_DUPOPT 9
81 #define LDAP_SCHERR_EMPTY 10
82 #define LDAP_SCHERR_MISSING 11
83 #define LDAP_SCHERR_OUT_OF_ORDER 12
84
85 #define LDAP_SCHEMA_YES 1
86
87 #define LDAP_SCHEMA_ABSTRACT 0
88 #define LDAP_SCHEMA_STRUCTURAL 1
89 #define LDAP_SCHEMA_AUXILIARY 2
90
91 #define LDAP_SCHEMA_ALLOW_NONE 0x00U /* Strict parsing */
92 #define LDAP_SCHEMA_ALLOW_NO_OID 0x01U /* Allow missing oid */
93 #define LDAP_SCHEMA_ALLOW_QUOTED 0x02U /* Allow bogus extra quotes */
94 #define LDAP_SCHEMA_ALLOW_DESCR 0x04U /* Allow descr instead of OID */
95 #define LDAP_SCHEMA_ALLOW_DESCR_PREFIX 0x08U /* Allow descr as OID prefix */
96 #define LDAP_SCHEMA_ALLOW_OID_MACRO 0x10U /* Allow OID macros in slapd */
97 #define LDAP_SCHEMA_ALLOW_OUT_OF_ORDER_FIELDS 0x20U /* Allow fields in most any order */
98 #define LDAP_SCHEMA_ALLOW_ALL 0x3fU /* Be very liberal in parsing */
99 #define LDAP_SCHEMA_SKIP 0x80U /* Don't malloc any result */
100
101 typedef struct ldap_objectclass {
102 gchar *oc_oid; /* REQUIRED */
103 gchar **oc_names; /* OPTIONAL */
104 gchar *oc_desc; /* OPTIONAL */
105 gint oc_obsolete; /* 0=no, 1=yes */
106 gchar **oc_sup_oids; /* OPTIONAL */
107 gint oc_kind; /* 0=ABSTRACT, 1=STRUCTURAL, 2=AUXILIARY */
108 gchar **oc_at_oids_must; /* OPTIONAL */
109 gchar **oc_at_oids_may; /* OPTIONAL */
110 } LDAPObjectClass;
111
112 static void
vfree(gpointer * vec)113 vfree (gpointer *vec)
114 {
115 gint i;
116
117 for (i = 0; vec[i] != NULL; i++)
118 free (vec[i]);
119 }
120
121 /* from schema.c */
122
123 /*
124 * Now come the parsers. There is one parser for each entity type:
125 * objectclasses, attributetypes, etc.
126 *
127 * Each of them is written as a recursive-descent parser, except that
128 * none of them is really recursive. But the idea is kept: there
129 * is one routine per non-terminal that eithers gobbles lexical tokens
130 * or calls lower-level routines, etc.
131 *
132 * The scanner is implemented in the routine get_token. Actually,
133 * get_token is more than a scanner and will return tokens that are
134 * in fact non-terminals in the grammar. So you can see the whole
135 * approach as the combination of a low-level bottom-up recognizer
136 * combined with a scanner and a number of top-down parsers. Or just
137 * consider that the real grammars recognized by the parsers are not
138 * those of the standards. As a matter of fact, our parsers are more
139 * liberal than the spec when there is no ambiguity.
140 *
141 * The difference is pretty academic (modulo bugs or incorrect
142 * interpretation of the specs).
143 */
144
145 #define TK_NOENDQUOTE -2
146 #define TK_OUTOFMEM -1
147 #define TK_EOS 0
148 #define TK_UNEXPCHAR 1
149 #define TK_BAREWORD 2
150 #define TK_QDSTRING 3
151 #define TK_LEFTPAREN 4
152 #define TK_RIGHTPAREN 5
153 #define TK_DOLLAR 6
154 #define TK_QDESCR TK_QDSTRING
155
156 struct token {
157 gint type;
158 gchar *sval;
159 };
160
161 static gint
get_token(const gchar ** sp,gchar ** token_val)162 get_token (const gchar **sp,
163 gchar **token_val)
164 {
165 gint kind;
166 const gchar *p;
167 const gchar *q;
168 gchar *res;
169
170 *token_val = NULL;
171 switch (**sp) {
172 case '\0':
173 kind = TK_EOS;
174 (*sp)++;
175 break;
176 case '(':
177 kind = TK_LEFTPAREN;
178 (*sp)++;
179 break;
180 case ')':
181 kind = TK_RIGHTPAREN;
182 (*sp)++;
183 break;
184 case '$':
185 kind = TK_DOLLAR;
186 (*sp)++;
187 break;
188 case '\'':
189 kind = TK_QDSTRING;
190 (*sp)++;
191 p = *sp;
192 while (**sp != '\'' && **sp != '\0')
193 (*sp)++;
194 if (**sp == '\'') {
195 q = *sp;
196 res = LDAP_MALLOC (q - p + 1);
197 if (!res) {
198 kind = TK_OUTOFMEM;
199 } else {
200 strncpy (res,p,q - p);
201 res[q - p] = '\0';
202 *token_val = res;
203 }
204 (*sp)++;
205 } else {
206 kind = TK_NOENDQUOTE;
207 }
208 break;
209 default:
210 kind = TK_BAREWORD;
211 p = *sp;
212 while (!LDAP_SPACE (**sp) &&
213 **sp != '(' &&
214 **sp != ')' &&
215 **sp != '$' &&
216 **sp != '\'' &&
217 **sp != '\0')
218 (*sp)++;
219 q = *sp;
220 res = LDAP_MALLOC (q - p + 1);
221 if (!res) {
222 kind = TK_OUTOFMEM;
223 } else {
224 strncpy (res,p,q - p);
225 res[q - p] = '\0';
226 *token_val = res;
227 }
228 break;
229 /* kind = TK_UNEXPCHAR; */
230 /* break; */
231 }
232
233 return kind;
234 }
235
236 /* Gobble optional whitespace */
237 static void
parse_whsp(const gchar ** sp)238 parse_whsp (const gchar **sp)
239 {
240 while (LDAP_SPACE (**sp))
241 (*sp)++;
242 }
243
244 /* Parse a sequence of dot-separated decimal strings */
245 static gchar *
ldap_int_parse_numericoid(const gchar ** sp,gint * code,const gint flags)246 ldap_int_parse_numericoid (const gchar **sp, gint *code, const gint flags)
247 {
248 gchar *res = NULL;
249 const gchar *start = *sp;
250 gint len;
251 gint quoted = 0;
252
253 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
254 if (flags & LDAP_SCHEMA_ALLOW_QUOTED && **sp == '\'') {
255 quoted = 1;
256 (*sp)++;
257 start++;
258 }
259 /* Each iteration of this loop gets one decimal string */
260 while (**sp) {
261 if (!LDAP_DIGIT (**sp)) {
262 /*
263 * Initial gchar is not a digit or gchar after dot is
264 * not a digit
265 */
266 *code = LDAP_SCHERR_NODIGIT;
267 return NULL;
268 }
269 (*sp)++;
270 while (LDAP_DIGIT (**sp))
271 (*sp)++;
272 if (**sp != '.')
273 break;
274 /* Otherwise, gobble the dot and loop again */
275 (*sp)++;
276 }
277 /* Now *sp points at the gchar past the numericoid. Perfect. */
278 len = *sp - start;
279 if (flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted) {
280 if (**sp == '\'') {
281 (*sp)++;
282 } else {
283 *code = LDAP_SCHERR_UNEXPTOKEN;
284 return NULL;
285 }
286 }
287 if (flags & LDAP_SCHEMA_SKIP) {
288 res = (gchar *) start;
289 } else {
290 res = LDAP_MALLOC (len + 1);
291 if (!res) {
292 *code = LDAP_SCHERR_OUTOFMEM;
293 return (NULL);
294 }
295 strncpy (res,start,len);
296 res[len] = '\0';
297 }
298 return (res);
299 }
300
301 /* Parse a qdescr or a list of them enclosed in () */
302 static gchar **
parse_qdescrs(const gchar ** sp,gint * code)303 parse_qdescrs (const gchar **sp, gint *code)
304 {
305 gchar ** res;
306 gchar ** res1;
307 gint kind;
308 gchar *sval;
309 gint size;
310 gint pos;
311
312 parse_whsp (sp);
313 kind = get_token (sp,&sval);
314 if (kind == TK_LEFTPAREN) {
315 /* Let's presume there will be at least 2 entries */
316 size = 3;
317 res = LDAP_CALLOC (3,sizeof (gchar *));
318 if (!res) {
319 *code = LDAP_SCHERR_OUTOFMEM;
320 return NULL;
321 }
322 pos = 0;
323 while (1) {
324 parse_whsp (sp);
325 kind = get_token (sp,&sval);
326 if (kind == TK_RIGHTPAREN)
327 break;
328 if (kind == TK_QDESCR) {
329 if (pos == size - 2) {
330 size++;
331 res1 = LDAP_REALLOC (res,size * sizeof (gchar *));
332 if (!res1) {
333 LDAP_VFREE (res);
334 LDAP_FREE (sval);
335 *code = LDAP_SCHERR_OUTOFMEM;
336 return (NULL);
337 }
338 res = res1;
339 }
340 res[pos++] = sval;
341 res[pos] = NULL;
342 parse_whsp (sp);
343 } else {
344 LDAP_VFREE (res);
345 LDAP_FREE (sval);
346 *code = LDAP_SCHERR_UNEXPTOKEN;
347 return (NULL);
348 }
349 }
350 parse_whsp (sp);
351 return (res);
352 } else if (kind == TK_QDESCR) {
353 res = LDAP_CALLOC (2,sizeof (gchar *));
354 if (!res) {
355 *code = LDAP_SCHERR_OUTOFMEM;
356 return NULL;
357 }
358 res[0] = sval;
359 res[1] = NULL;
360 parse_whsp (sp);
361 return res;
362 } else {
363 LDAP_FREE (sval);
364 *code = LDAP_SCHERR_BADNAME;
365 return NULL;
366 }
367 }
368
369 /* Parse a woid or a $-separated list of them enclosed in () */
370 static gchar **
parse_oids(const gchar ** sp,gint * code,const gint allow_quoted)371 parse_oids (const gchar **sp, gint *code, const gint allow_quoted)
372 {
373 gchar ** res;
374 gchar ** res1;
375 gint kind;
376 gchar *sval;
377 gint size;
378 gint pos;
379
380 /*
381 * Strictly speaking, doing this here accepts whsp before the
382 * ( at the begining of an oidlist, but this is harmless. Also,
383 * we are very liberal in what we accept as an OID. Maybe
384 * refine later.
385 */
386 parse_whsp (sp);
387 kind = get_token (sp,&sval);
388 if (kind == TK_LEFTPAREN) {
389 /* Let's presume there will be at least 2 entries */
390 size = 3;
391 res = LDAP_CALLOC (3,sizeof (gchar *));
392 if (!res) {
393 *code = LDAP_SCHERR_OUTOFMEM;
394 return NULL;
395 }
396 pos = 0;
397 parse_whsp (sp);
398 kind = get_token (sp,&sval);
399 if (kind == TK_BAREWORD ||
400 (allow_quoted && kind == TK_QDSTRING)) {
401 res[pos++] = sval;
402 res[pos] = NULL;
403 } else {
404 *code = LDAP_SCHERR_UNEXPTOKEN;
405 LDAP_FREE (sval);
406 LDAP_VFREE (res);
407 /* cppcheck-suppress memleak */
408 return NULL;
409 }
410 parse_whsp (sp);
411 while (1) {
412 kind = get_token (sp,&sval);
413 if (kind == TK_RIGHTPAREN)
414 break;
415 if (kind == TK_DOLLAR) {
416 parse_whsp (sp);
417 kind = get_token (sp,&sval);
418 if (kind == TK_BAREWORD ||
419 (allow_quoted &&
420 kind == TK_QDSTRING)) {
421 if (pos == size - 2) {
422 size++;
423 res1 = LDAP_REALLOC (res,size * sizeof (gchar *));
424 if (!res1) {
425 LDAP_FREE (sval);
426 LDAP_VFREE (res);
427 *code = LDAP_SCHERR_OUTOFMEM;
428 return (NULL);
429 }
430 res = res1;
431 }
432 res[pos++] = sval;
433 res[pos] = NULL;
434 } else {
435 *code = LDAP_SCHERR_UNEXPTOKEN;
436 LDAP_FREE (sval);
437 LDAP_VFREE (res);
438 return NULL;
439 }
440 parse_whsp (sp);
441 } else {
442 *code = LDAP_SCHERR_UNEXPTOKEN;
443 LDAP_FREE (sval);
444 LDAP_VFREE (res);
445 return NULL;
446 }
447 }
448 parse_whsp (sp);
449 return (res);
450 } else if (kind == TK_BAREWORD ||
451 (allow_quoted && kind == TK_QDSTRING)) {
452 res = LDAP_CALLOC (2,sizeof (gchar *));
453 if (!res) {
454 LDAP_FREE (sval);
455 *code = LDAP_SCHERR_OUTOFMEM;
456 return NULL;
457 }
458 res[0] = sval;
459 res[1] = NULL;
460 parse_whsp (sp);
461 return res;
462 } else {
463 LDAP_FREE (sval);
464 *code = LDAP_SCHERR_BADNAME;
465 return NULL;
466 }
467 }
468
469 static void
ldap_objectclass_free(LDAPObjectClass * oc)470 ldap_objectclass_free (LDAPObjectClass *oc)
471 {
472 LDAP_FREE (oc->oc_oid);
473 if (oc->oc_names) LDAP_VFREE (oc->oc_names);
474 if (oc->oc_desc) LDAP_FREE (oc->oc_desc);
475 if (oc->oc_sup_oids) LDAP_VFREE (oc->oc_sup_oids);
476 if (oc->oc_at_oids_must) LDAP_VFREE (oc->oc_at_oids_must);
477 if (oc->oc_at_oids_may) LDAP_VFREE (oc->oc_at_oids_may);
478 LDAP_FREE (oc);
479 }
480
481 static LDAPObjectClass *
ldap_str2objectclass(LDAP_CONST gchar * s,gint * code,LDAP_CONST gchar ** errp,LDAP_CONST unsigned flags)482 ldap_str2objectclass (LDAP_CONST gchar *s,
483 gint *code,
484 LDAP_CONST gchar **errp,
485 LDAP_CONST unsigned flags)
486 {
487 gint kind;
488 const gchar *ss = s;
489 gchar *sval;
490 gint seen_name = 0;
491 gint seen_desc = 0;
492 gint seen_obsolete = 0;
493 gint seen_sup = 0;
494 gint seen_kind = 0;
495 gint seen_must = 0;
496 gint seen_may = 0;
497 LDAPObjectClass *oc;
498 gchar ** ext_vals;
499 const gchar *savepos;
500
501 if (!s) {
502 *code = LDAP_SCHERR_EMPTY;
503 *errp = "";
504 return NULL;
505 }
506
507 *errp = s;
508 oc = LDAP_CALLOC (1,sizeof (LDAPObjectClass));
509
510 if (!oc) {
511 *code = LDAP_SCHERR_OUTOFMEM;
512 return NULL;
513 }
514 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
515
516 kind = get_token (&ss,&sval);
517 if (kind != TK_LEFTPAREN) {
518 *code = LDAP_SCHERR_NOLEFTPAREN;
519 LDAP_FREE (sval);
520 ldap_objectclass_free (oc);
521 return NULL;
522 }
523
524 /*
525 * Definitions MUST begin with an OID in the numericoid format.
526 * However, this routine is used by clients to parse the response
527 * from servers and very well known servers will provide an OID
528 * in the wrong format or even no OID at all. We do our best to
529 * extract info from those servers.
530 */
531 parse_whsp (&ss);
532 savepos = ss;
533 oc->oc_oid = ldap_int_parse_numericoid (&ss,code,0);
534 if (!oc->oc_oid) {
535 if ((flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos)) {
536 /* Backtracking */
537 ss = savepos;
538 kind = get_token (&ss,&sval);
539 if (kind == TK_BAREWORD) {
540 if (!strcasecmp (sval, "NAME") ||
541 !strcasecmp (sval, "DESC") ||
542 !strcasecmp (sval, "OBSOLETE") ||
543 !strcasecmp (sval, "SUP") ||
544 !strcasecmp (sval, "ABSTRACT") ||
545 !strcasecmp (sval, "STRUCTURAL") ||
546 !strcasecmp (sval, "AUXILIARY") ||
547 !strcasecmp (sval, "MUST") ||
548 !strcasecmp (sval, "MAY") ||
549 !strncasecmp (sval, "X-", 2)) {
550 /* Missing OID, backtrack */
551 ss = savepos;
552 } else if (flags &
553 LDAP_SCHEMA_ALLOW_OID_MACRO) {
554 /* Non-numerical OID, ignore */
555 gint len = ss - savepos;
556 oc->oc_oid = LDAP_MALLOC (len + 1);
557 strncpy (oc->oc_oid, savepos, len);
558 oc->oc_oid[len] = 0;
559 }
560 }
561 LDAP_FREE (sval);
562 } else {
563 *errp = ss;
564 ldap_objectclass_free (oc);
565 return NULL;
566 }
567 }
568 parse_whsp (&ss);
569
570 /*
571 * Beyond this point we will be liberal an accept the items
572 * in any order.
573 */
574 while (1) {
575 kind = get_token (&ss,&sval);
576 switch (kind) {
577 case TK_EOS:
578 *code = LDAP_SCHERR_NORIGHTPAREN;
579 *errp = ss;
580 ldap_objectclass_free (oc);
581 return NULL;
582 case TK_RIGHTPAREN:
583 return oc;
584 case TK_BAREWORD:
585 if (!strcasecmp (sval,"NAME")) {
586 LDAP_FREE (sval);
587 if (seen_name) {
588 *code = LDAP_SCHERR_DUPOPT;
589 *errp = ss;
590 ldap_objectclass_free (oc);
591 return (NULL);
592 }
593 seen_name = 1;
594 oc->oc_names = parse_qdescrs (&ss,code);
595 if (!oc->oc_names) {
596 if (*code != LDAP_SCHERR_OUTOFMEM)
597 *code = LDAP_SCHERR_BADNAME;
598 *errp = ss;
599 ldap_objectclass_free (oc);
600 return NULL;
601 }
602 } else if (!strcasecmp (sval,"DESC")) {
603 LDAP_FREE (sval);
604 if (seen_desc) {
605 *code = LDAP_SCHERR_DUPOPT;
606 *errp = ss;
607 ldap_objectclass_free (oc);
608 return (NULL);
609 }
610 seen_desc = 1;
611 parse_whsp (&ss);
612 kind = get_token (&ss,&sval);
613 if (kind != TK_QDSTRING) {
614 *code = LDAP_SCHERR_UNEXPTOKEN;
615 *errp = ss;
616 LDAP_FREE (sval);
617 ldap_objectclass_free (oc);
618 return NULL;
619 }
620 oc->oc_desc = sval;
621 parse_whsp (&ss);
622 } else if (!strcasecmp (sval,"OBSOLETE")) {
623 LDAP_FREE (sval);
624 if (seen_obsolete) {
625 *code = LDAP_SCHERR_DUPOPT;
626 *errp = ss;
627 ldap_objectclass_free (oc);
628 return (NULL);
629 }
630 seen_obsolete = 1;
631 oc->oc_obsolete = LDAP_SCHEMA_YES;
632 parse_whsp (&ss);
633 } else if (!strcasecmp (sval,"SUP")) {
634 LDAP_FREE (sval);
635 if (seen_sup) {
636 *code = LDAP_SCHERR_DUPOPT;
637 *errp = ss;
638 ldap_objectclass_free (oc);
639 return (NULL);
640 }
641 seen_sup = 1;
642 oc->oc_sup_oids = parse_oids (&ss,
643 code,
644 flags);
645 if (!oc->oc_sup_oids) {
646 *errp = ss;
647 ldap_objectclass_free (oc);
648 return NULL;
649 }
650 } else if (!strcasecmp (sval,"ABSTRACT")) {
651 LDAP_FREE (sval);
652 if (seen_kind) {
653 *code = LDAP_SCHERR_DUPOPT;
654 *errp = ss;
655 ldap_objectclass_free (oc);
656 return (NULL);
657 }
658 seen_kind = 1;
659 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
660 parse_whsp (&ss);
661 } else if (!strcasecmp (sval,"STRUCTURAL")) {
662 LDAP_FREE (sval);
663 if (seen_kind) {
664 *code = LDAP_SCHERR_DUPOPT;
665 *errp = ss;
666 ldap_objectclass_free (oc);
667 return (NULL);
668 }
669 seen_kind = 1;
670 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
671 parse_whsp (&ss);
672 } else if (!strcasecmp (sval,"AUXILIARY")) {
673 LDAP_FREE (sval);
674 if (seen_kind) {
675 *code = LDAP_SCHERR_DUPOPT;
676 *errp = ss;
677 ldap_objectclass_free (oc);
678 return (NULL);
679 }
680 seen_kind = 1;
681 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
682 parse_whsp (&ss);
683 } else if (!strcasecmp (sval,"MUST")) {
684 LDAP_FREE (sval);
685 if (seen_must) {
686 *code = LDAP_SCHERR_DUPOPT;
687 *errp = ss;
688 ldap_objectclass_free (oc);
689 return (NULL);
690 }
691 seen_must = 1;
692 oc->oc_at_oids_must = parse_oids (&ss,code,0);
693 if (!oc->oc_at_oids_must) {
694 *errp = ss;
695 ldap_objectclass_free (oc);
696 return NULL;
697 }
698 parse_whsp (&ss);
699 } else if (!strcasecmp (sval,"MAY")) {
700 LDAP_FREE (sval);
701 if (seen_may) {
702 *code = LDAP_SCHERR_DUPOPT;
703 *errp = ss;
704 ldap_objectclass_free (oc);
705 return (NULL);
706 }
707 seen_may = 1;
708 oc->oc_at_oids_may = parse_oids (&ss,code,0);
709 if (!oc->oc_at_oids_may) {
710 *errp = ss;
711 ldap_objectclass_free (oc);
712 return NULL;
713 }
714 parse_whsp (&ss);
715 } else if (sval[0] == 'X' && sval[1] == '-') {
716 /* Should be parse_qdstrings */
717 ext_vals = parse_qdescrs (&ss, code);
718 if (!ext_vals) {
719 *errp = ss;
720 ldap_objectclass_free (oc);
721 return NULL;
722 }
723 #if 0
724 if (add_extension (&oc->oc_extensions,
725 sval, ext_vals)) {
726 *code = LDAP_SCHERR_OUTOFMEM;
727 *errp = ss;
728 LDAP_FREE (sval);
729 ldap_objectclass_free (oc);
730 return NULL;
731 }
732 #endif
733 } else {
734 *code = LDAP_SCHERR_UNEXPTOKEN;
735 *errp = ss;
736 LDAP_FREE (sval);
737 ldap_objectclass_free (oc);
738 return NULL;
739 }
740 break;
741 default:
742 *code = LDAP_SCHERR_UNEXPTOKEN;
743 *errp = ss;
744 LDAP_FREE (sval);
745 ldap_objectclass_free (oc);
746 return NULL;
747 }
748 }
749 }
750
751 /* from utf-8.c */
752
753 #define LDAP_UTF8_NEXT(p) g_utf8_next_char((p))
754 #define LDAP_UTF8_INCR(p) ((p)=LDAP_UTF8_NEXT((p)))
755 #define ldap_x_utf8_to_ucs4(str) g_utf8_get_char(str)
756
757 static gchar *
ldap_utf8_strchr(const gchar * str,const gchar * chr)758 ldap_utf8_strchr (const gchar *str,
759 const gchar *chr)
760 {
761 for (; *str != '\0'; LDAP_UTF8_INCR (str)) {
762 if (ldap_x_utf8_to_ucs4 (str) == ldap_x_utf8_to_ucs4 (chr)) {
763 return (gchar *) str;
764 }
765 }
766
767 return NULL;
768 }
769
770 static gsize
ldap_utf8_strcspn(const gchar * str,const gchar * set)771 ldap_utf8_strcspn (const gchar *str,
772 const gchar *set)
773 {
774 const gchar *cstr;
775 const gchar *cset;
776
777 for (cstr = str; *cstr != '\0'; LDAP_UTF8_INCR (cstr)) {
778 for (cset = set; *cset != '\0'; LDAP_UTF8_INCR (cset)) {
779 if (ldap_x_utf8_to_ucs4 (cstr) == ldap_x_utf8_to_ucs4 (cset)) {
780 return cstr - str;
781 }
782 }
783 }
784
785 return cstr - str;
786 }
787
788 static gsize
ldap_utf8_strspn(const gchar * str,const gchar * set)789 ldap_utf8_strspn (const gchar *str,
790 const gchar *set)
791 {
792 const gchar *cstr;
793 const gchar *cset;
794
795 for (cstr = str; *cstr != '\0'; LDAP_UTF8_INCR (cstr)) {
796 for (cset = set; ; LDAP_UTF8_INCR (cset)) {
797 if (*cset == '\0') {
798 return cstr - str;
799 }
800
801 if (ldap_x_utf8_to_ucs4 (cstr) == ldap_x_utf8_to_ucs4 (cset)) {
802 break;
803 }
804 }
805 }
806
807 return cstr - str;
808 }
809
ldap_utf8_strtok(gchar * str,const gchar * sep,gchar ** last)810 static gchar *ldap_utf8_strtok (gchar *str, const gchar *sep, gchar **last)
811 {
812 gchar *begin;
813 gchar *end;
814
815 if (last == NULL) return NULL;
816
817 begin = str ? str : *last;
818
819 begin += ldap_utf8_strspn (begin, sep);
820
821 if (*begin == '\0') {
822 *last = NULL;
823 return NULL;
824 }
825
826 end = &begin[ ldap_utf8_strcspn (begin, sep) ];
827
828 if (*end != '\0') {
829 gchar *next = LDAP_UTF8_NEXT (end);
830 *end = '\0';
831 end = next;
832 }
833
834 *last = end;
835 return begin;
836 }
837
838 /* from ldap.h */
839
840 #define LDAP_URL_SUCCESS 0x00 /* Success */
841 #define LDAP_URL_ERR_MEM 0x01 /* can't allocate memory space */
842 #define LDAP_URL_ERR_PARAM 0x02 /* parameter is bad */
843
844 #define LDAP_URL_ERR_BADSCHEME 0x03 /* URL doesn't begin with "ldap[si]://" */
845 #define LDAP_URL_ERR_BADENCLOSURE 0x04 /* URL is missing trailing ">" */
846 #define LDAP_URL_ERR_BADURL 0x05 /* URL is bad */
847 #define LDAP_URL_ERR_BADHOST 0x06 /* host port is bad */
848 #define LDAP_URL_ERR_BADATTRS 0x07 /* bad (or missing) attributes */
849 #define LDAP_URL_ERR_BADSCOPE 0x08 /* scope string is invalid (or missing) */
850 #define LDAP_URL_ERR_BADFILTER 0x09 /* bad or missing filter */
851 #define LDAP_URL_ERR_BADEXTS 0x0a /* bad or missing extensions */
852
853 #define LDAP_URL_PREFIX "ldap://"
854 #define LDAP_URL_PREFIX_LEN (sizeof(LDAP_URL_PREFIX)-1)
855 #define LDAPS_URL_PREFIX "ldaps://"
856 #define LDAPS_URL_PREFIX_LEN (sizeof(LDAPS_URL_PREFIX)-1)
857 #define LDAPI_URL_PREFIX "ldapi://"
858 #define LDAPI_URL_PREFIX_LEN (sizeof(LDAPI_URL_PREFIX)-1)
859
860 #define LDAP_URL_URLCOLON "URL:"
861 #define LDAP_URL_URLCOLON_LEN (sizeof(LDAP_URL_URLCOLON)-1)
862
863 typedef struct ldap_url_desc {
864 struct ldap_url_desc *lud_next;
865 gchar *lud_scheme;
866 gchar *lud_host;
867 gint lud_port;
868 gchar *lud_dn;
869 gchar **lud_attrs;
870 gint lud_scope;
871 gchar *lud_filter;
872 gchar **lud_exts;
873 gint lud_crit_exts;
874 } LDAPURLDesc;
875
876 /* from url.c */
877
878 static const gchar *
skip_url_prefix(const gchar * url,gint * enclosedp,const gchar ** scheme)879 skip_url_prefix (
880 const gchar *url,
881 gint *enclosedp,
882 const gchar **scheme)
883 {
884 /*
885 * return non-zero if this looks like a LDAP URL; zero if not
886 * if non-zero returned, *urlp will be moved past "ldap://" part of URL
887 */
888 const gchar *p;
889
890 if (url == NULL) {
891 return (NULL);
892 }
893
894 p = url;
895
896 /* skip leading '<' (if any) */
897 if (*p == '<') {
898 *enclosedp = 1;
899 ++p;
900 } else {
901 *enclosedp = 0;
902 }
903
904 /* skip leading "URL:" (if any) */
905 if (strncasecmp (p, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN) == 0) {
906 p += LDAP_URL_URLCOLON_LEN;
907 }
908
909 /* check for "ldap://" prefix */
910 if (strncasecmp (p, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN) == 0) {
911 /* skip over "ldap://" prefix and return success */
912 p += LDAP_URL_PREFIX_LEN;
913 *scheme = "ldap";
914 return (p);
915 }
916
917 /* check for "ldaps://" prefix */
918 if (strncasecmp (p, LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN) == 0) {
919 /* skip over "ldaps://" prefix and return success */
920 p += LDAPS_URL_PREFIX_LEN;
921 *scheme = "ldaps";
922 return (p);
923 }
924
925 /* check for "ldapi://" prefix */
926 if (strncasecmp (p, LDAPI_URL_PREFIX, LDAPI_URL_PREFIX_LEN) == 0) {
927 /* skip over "ldapi://" prefix and return success */
928 p += LDAPI_URL_PREFIX_LEN;
929 *scheme = "ldapi";
930 return (p);
931 }
932
933 #ifdef LDAP_CONNECTIONLESS
934 /* check for "cldap://" prefix */
935 if (strncasecmp (p, LDAPC_URL_PREFIX, LDAPC_URL_PREFIX_LEN) == 0) {
936 /* skip over "cldap://" prefix and return success */
937 p += LDAPC_URL_PREFIX_LEN;
938 *scheme = "cldap";
939 return (p);
940 }
941 #endif
942
943 return (NULL);
944 }
945
946 static gint
str2scope(const gchar * p)947 str2scope (const gchar *p)
948 {
949 if (strcasecmp (p, "one") == 0) {
950 return LDAP_SCOPE_ONELEVEL;
951
952 } else if (strcasecmp (p, "onelevel") == 0) {
953 return LDAP_SCOPE_ONELEVEL;
954
955 } else if (strcasecmp (p, "base") == 0) {
956 return LDAP_SCOPE_BASE;
957
958 } else if (strcasecmp (p, "sub") == 0) {
959 return LDAP_SCOPE_SUBTREE;
960
961 } else if (strcasecmp (p, "subtree") == 0) {
962 return LDAP_SCOPE_SUBTREE;
963 }
964
965 return (-1);
966 }
967
968 static void
ldap_free_urldesc(LDAPURLDesc * ludp)969 ldap_free_urldesc (LDAPURLDesc *ludp)
970 {
971 if (ludp == NULL) {
972 return;
973 }
974
975 if (ludp->lud_scheme != NULL) {
976 LDAP_FREE (ludp->lud_scheme);
977 }
978
979 if (ludp->lud_host != NULL) {
980 LDAP_FREE (ludp->lud_host);
981 }
982
983 if (ludp->lud_dn != NULL) {
984 LDAP_FREE (ludp->lud_dn);
985 }
986
987 if (ludp->lud_filter != NULL) {
988 LDAP_FREE (ludp->lud_filter);
989 }
990
991 if (ludp->lud_attrs != NULL) {
992 LDAP_VFREE (ludp->lud_attrs);
993 }
994
995 if (ludp->lud_exts != NULL) {
996 LDAP_VFREE (ludp->lud_exts);
997 }
998
999 LDAP_FREE (ludp);
1000 }
1001
1002 static gint
ldap_int_unhex(gint c)1003 ldap_int_unhex (gint c)
1004 {
1005 return (c >= '0' && c <= '9' ? c - '0'
1006 : c >= 'A' && c <= 'F' ? c - 'A' + 10
1007 : c - 'a' + 10);
1008 }
1009
1010 static void
ldap_pvt_hex_unescape(gchar * s)1011 ldap_pvt_hex_unescape (gchar *s)
1012 {
1013 /*
1014 * Remove URL hex escapes from s... done in place. The basic concept for
1015 * this routine is borrowed from the WWW library HTUnEscape() routine.
1016 */
1017 gchar *p;
1018
1019 for (p = s; *s != '\0'; ++s) {
1020 if (*s == '%') {
1021 if (*++s == '\0') {
1022 break;
1023 }
1024 *p = ldap_int_unhex(*s) << 4;
1025 if (*++s == '\0') {
1026 break;
1027 }
1028 *p++ += ldap_int_unhex(*s);
1029 } else {
1030 *p++ = *s;
1031 }
1032 }
1033
1034 *p = '\0';
1035 }
1036
1037 static gchar **
ldap_str2charray(const gchar * str_in,const gchar * brkstr)1038 ldap_str2charray (const gchar *str_in,
1039 const gchar *brkstr)
1040 {
1041 gchar **res;
1042 gchar *str, *s;
1043 gchar *lasts;
1044 gint i;
1045
1046 /* protect the input string from strtok */
1047 str = LDAP_STRDUP (str_in);
1048 if (str == NULL) {
1049 return NULL;
1050 }
1051
1052 i = 1;
1053 for (s = str; *s; s++) {
1054 if (ldap_utf8_strchr (brkstr, s) != NULL) {
1055 i++;
1056 }
1057 }
1058
1059 res = (gchar **) LDAP_MALLOC ((i + 1) * sizeof (gchar *));
1060
1061 if (res == NULL) {
1062 LDAP_FREE (str);
1063 return NULL;
1064 }
1065
1066 i = 0;
1067
1068 for (s = ldap_utf8_strtok (str, brkstr, &lasts);
1069 s != NULL;
1070 s = ldap_utf8_strtok (NULL, brkstr, &lasts))
1071 {
1072 res[i] = LDAP_STRDUP (s);
1073
1074 if (res[i] == NULL) {
1075 for (--i; i >= 0; i--) {
1076 LDAP_FREE (res[i]);
1077 }
1078 LDAP_FREE (res);
1079 LDAP_FREE (str);
1080 return NULL;
1081 }
1082
1083 i++;
1084 }
1085
1086 res[i] = NULL;
1087
1088 LDAP_FREE (str);
1089 return (res);
1090 }
1091
1092 static gint
ldap_url_parse_ext(LDAP_CONST gchar * url_in,LDAPURLDesc ** ludpp)1093 ldap_url_parse_ext (LDAP_CONST gchar *url_in,
1094 LDAPURLDesc **ludpp)
1095 {
1096 /*
1097 * Pick apart the pieces of an LDAP URL.
1098 */
1099
1100 LDAPURLDesc *ludp;
1101 gchar *p, *q, *r;
1102 gint i, enclosed;
1103 const gchar *scheme = NULL;
1104 const gchar *url_tmp;
1105 gchar *url;
1106
1107 if (url_in == NULL || ludpp == NULL) {
1108 return LDAP_URL_ERR_PARAM;
1109 }
1110
1111 *ludpp = NULL; /* pessimistic */
1112
1113 url_tmp = skip_url_prefix (url_in, &enclosed, &scheme);
1114
1115 if (url_tmp == NULL) {
1116 return LDAP_URL_ERR_BADSCHEME;
1117 }
1118
1119 assert (scheme);
1120
1121 /* make working copy of the remainder of the URL */
1122 url = LDAP_STRDUP (url_tmp);
1123 if (url == NULL) {
1124 return LDAP_URL_ERR_MEM;
1125 }
1126
1127 if (enclosed) {
1128 p = &url[strlen (url) - 1];
1129
1130 if (*p != '>') {
1131 LDAP_FREE (url);
1132 return LDAP_URL_ERR_BADENCLOSURE;
1133 }
1134
1135 *p = '\0';
1136 }
1137
1138 /* allocate return struct */
1139 ludp = (LDAPURLDesc *) LDAP_CALLOC (1, sizeof (LDAPURLDesc));
1140
1141 if (ludp == NULL) {
1142 LDAP_FREE (url);
1143 return LDAP_URL_ERR_MEM;
1144 }
1145
1146 ludp->lud_next = NULL;
1147 ludp->lud_host = NULL;
1148 ludp->lud_port = 0;
1149 ludp->lud_dn = NULL;
1150 ludp->lud_attrs = NULL;
1151 ludp->lud_filter = NULL;
1152 ludp->lud_scope = LDAP_SCOPE_DEFAULT;
1153 ludp->lud_filter = NULL;
1154 ludp->lud_exts = NULL;
1155
1156 ludp->lud_scheme = LDAP_STRDUP (scheme);
1157
1158 if (ludp->lud_scheme == NULL) {
1159 LDAP_FREE (url);
1160 ldap_free_urldesc (ludp);
1161 return LDAP_URL_ERR_MEM;
1162 }
1163
1164 /* scan forward for '/' that marks end of hostport and begin. of dn */
1165 p = strchr (url, '/');
1166
1167 if (p != NULL) {
1168 /* terminate hostport; point to start of dn */
1169 *p++ = '\0';
1170 }
1171
1172 /* IPv6 syntax with [ip address]:port */
1173 if (*url == '[') {
1174 r = strchr (url, ']');
1175 if (r == NULL) {
1176 LDAP_FREE (url);
1177 ldap_free_urldesc (ludp);
1178 return LDAP_URL_ERR_BADURL;
1179 }
1180 *r++ = '\0';
1181 q = strchr (r, ':');
1182 } else {
1183 q = strchr (url, ':');
1184 }
1185
1186 if (q != NULL) {
1187 gchar *next;
1188
1189 *q++ = '\0';
1190 ldap_pvt_hex_unescape (q);
1191
1192 if (*q == '\0') {
1193 LDAP_FREE (url);
1194 ldap_free_urldesc (ludp);
1195 return LDAP_URL_ERR_BADURL;
1196 }
1197
1198 ludp->lud_port = strtol (q, &next, 10);
1199 if (next == NULL || next[0] != '\0') {
1200 LDAP_FREE (url);
1201 ldap_free_urldesc (ludp);
1202 return LDAP_URL_ERR_BADURL;
1203 }
1204 }
1205
1206 ldap_pvt_hex_unescape (url);
1207
1208 /* If [ip address]:port syntax, url is [ip and we skip the [ */
1209 ludp->lud_host = LDAP_STRDUP (url + (*url == '['));
1210
1211 if (ludp->lud_host == NULL) {
1212 LDAP_FREE (url);
1213 ldap_free_urldesc (ludp);
1214 return LDAP_URL_ERR_MEM;
1215 }
1216
1217 /*
1218 * Kludge. ldap://111.222.333.444:389??cn=abc,o=company
1219 *
1220 * On early Novell releases, search references/referrals were returned
1221 * in this format, i.e., the dn was kind of in the scope position,
1222 * but the required slash is missing. The whole thing is illegal syntax,
1223 * but we need to account for it. Fortunately it can't be confused with
1224 * anything real.
1225 */
1226 if ((p == NULL) && (q != NULL) && ((q = strchr (q, '?')) != NULL)) {
1227 q++;
1228 /* ? immediately followed by question */
1229 if (*q == '?') {
1230 q++;
1231 if (*q != '\0') {
1232 /* parse dn part */
1233 ldap_pvt_hex_unescape (q);
1234 ludp->lud_dn = LDAP_STRDUP (q);
1235 } else {
1236 ludp->lud_dn = LDAP_STRDUP ("");
1237 }
1238
1239 if (ludp->lud_dn == NULL) {
1240 LDAP_FREE (url);
1241 ldap_free_urldesc (ludp);
1242 return LDAP_URL_ERR_MEM;
1243 }
1244 }
1245 }
1246
1247 if (p == NULL) {
1248 LDAP_FREE (url);
1249 *ludpp = ludp;
1250 return LDAP_URL_SUCCESS;
1251 }
1252
1253 /* scan forward for '?' that may marks end of dn */
1254 q = strchr (p, '?');
1255
1256 if (q != NULL) {
1257 /* terminate dn part */
1258 *q++ = '\0';
1259 }
1260
1261 if (*p != '\0') {
1262 /* parse dn part */
1263 ldap_pvt_hex_unescape (p);
1264 ludp->lud_dn = LDAP_STRDUP (p);
1265 } else {
1266 ludp->lud_dn = LDAP_STRDUP ("");
1267 }
1268
1269 if (ludp->lud_dn == NULL) {
1270 LDAP_FREE (url);
1271 ldap_free_urldesc (ludp);
1272 return LDAP_URL_ERR_MEM;
1273 }
1274
1275 if (q == NULL) {
1276 /* no more */
1277 LDAP_FREE (url);
1278 *ludpp = ludp;
1279 return LDAP_URL_SUCCESS;
1280 }
1281
1282 /* scan forward for '?' that may marks end of attributes */
1283 p = q;
1284 q = strchr (p, '?');
1285
1286 if (q != NULL) {
1287 /* terminate attributes part */
1288 *q++ = '\0';
1289 }
1290
1291 if (*p != '\0') {
1292 /* parse attributes */
1293 ldap_pvt_hex_unescape (p);
1294 ludp->lud_attrs = ldap_str2charray (p, ",");
1295
1296 if (ludp->lud_attrs == NULL) {
1297 LDAP_FREE (url);
1298 ldap_free_urldesc (ludp);
1299 return LDAP_URL_ERR_BADATTRS;
1300 }
1301 }
1302
1303 if (q == NULL) {
1304 /* no more */
1305 LDAP_FREE (url);
1306 *ludpp = ludp;
1307 return LDAP_URL_SUCCESS;
1308 }
1309
1310 /* scan forward for '?' that may marks end of scope */
1311 p = q;
1312 q = strchr (p, '?');
1313
1314 if (q != NULL) {
1315 /* terminate the scope part */
1316 *q++ = '\0';
1317 }
1318
1319 if (*p != '\0') {
1320 /* parse the scope */
1321 ldap_pvt_hex_unescape (p);
1322 ludp->lud_scope = str2scope (p);
1323
1324 if (ludp->lud_scope == -1) {
1325 LDAP_FREE (url);
1326 ldap_free_urldesc (ludp);
1327 return LDAP_URL_ERR_BADSCOPE;
1328 }
1329 }
1330
1331 if (q == NULL) {
1332 /* no more */
1333 LDAP_FREE (url);
1334 *ludpp = ludp;
1335 return LDAP_URL_SUCCESS;
1336 }
1337
1338 /* scan forward for '?' that may marks end of filter */
1339 p = q;
1340 q = strchr (p, '?');
1341
1342 if (q != NULL) {
1343 /* terminate the filter part */
1344 *q++ = '\0';
1345 }
1346
1347 if (*p != '\0') {
1348 /* parse the filter */
1349 ldap_pvt_hex_unescape (p);
1350
1351 if (!*p) {
1352 /* missing filter */
1353 LDAP_FREE (url);
1354 ldap_free_urldesc (ludp);
1355 return LDAP_URL_ERR_BADFILTER;
1356 }
1357
1358 LDAP_FREE (ludp->lud_filter);
1359 ludp->lud_filter = LDAP_STRDUP (p);
1360
1361 if (ludp->lud_filter == NULL) {
1362 LDAP_FREE (url);
1363 ldap_free_urldesc (ludp);
1364 return LDAP_URL_ERR_MEM;
1365 }
1366 }
1367
1368 if (q == NULL) {
1369 /* no more */
1370 LDAP_FREE (url);
1371 *ludpp = ludp;
1372 return LDAP_URL_SUCCESS;
1373 }
1374
1375 /* scan forward for '?' that may marks end of extensions */
1376 p = q;
1377 q = strchr (p, '?');
1378
1379 if (q != NULL) {
1380 /* extra '?' */
1381 LDAP_FREE (url);
1382 ldap_free_urldesc (ludp);
1383 return LDAP_URL_ERR_BADURL;
1384 }
1385
1386 /* parse the extensions */
1387 ludp->lud_exts = ldap_str2charray (p, ",");
1388
1389 if (ludp->lud_exts == NULL) {
1390 LDAP_FREE (url);
1391 ldap_free_urldesc (ludp);
1392 return LDAP_URL_ERR_BADEXTS;
1393 }
1394
1395 for (i = 0; ludp->lud_exts[i] != NULL; i++) {
1396 ldap_pvt_hex_unescape (ludp->lud_exts[i]);
1397
1398 if (*ludp->lud_exts[i] == '!') {
1399 /* count the number of critical extensions */
1400 ludp->lud_crit_exts++;
1401 }
1402 }
1403
1404 if (i == 0) {
1405 /* must have 1 or more */
1406 LDAP_FREE (url);
1407 ldap_free_urldesc (ludp);
1408 return LDAP_URL_ERR_BADEXTS;
1409 }
1410
1411 /* no more */
1412 *ludpp = ludp;
1413 LDAP_FREE (url);
1414 return LDAP_URL_SUCCESS;
1415 }
1416
1417 static gint
ldap_url_parse(LDAP_CONST gchar * url_in,LDAPURLDesc ** ludpp)1418 ldap_url_parse (LDAP_CONST gchar *url_in,
1419 LDAPURLDesc **ludpp)
1420 {
1421 gint rc = ldap_url_parse_ext (url_in, ludpp);
1422
1423 if (rc != LDAP_URL_SUCCESS) {
1424 return rc;
1425 }
1426
1427 if ((*ludpp)->lud_scope == LDAP_SCOPE_DEFAULT) {
1428 (*ludpp)->lud_scope = LDAP_SCOPE_BASE;
1429 }
1430
1431 if ((*ludpp)->lud_host != NULL && *(*ludpp)->lud_host == '\0') {
1432 LDAP_FREE ((*ludpp)->lud_host);
1433 (*ludpp)->lud_host = NULL;
1434 }
1435
1436 if ((*ludpp)->lud_port == 0) {
1437 if (strcmp ((*ludpp)->lud_scheme, "ldap") == 0) {
1438 (*ludpp)->lud_port = LDAP_PORT;
1439 #ifdef LDAP_CONNECTIONLESS
1440 } else if (strcmp ((*ludpp)->lud_scheme, "cldap") == 0) {
1441 (*ludpp)->lud_port = LDAP_PORT;
1442 #endif
1443 } else if (strcmp ((*ludpp)->lud_scheme, "ldaps") == 0) {
1444 (*ludpp)->lud_port = LDAPS_PORT;
1445 }
1446 }
1447
1448 return rc;
1449 }
1450
1451