]> git.sur5r.net Git - openldap/blob - servers/slapd/dn.c
Added the suffix=<dn> parameter to replica config directive
[openldap] / servers / slapd / dn.c
1 /* dn.c - routines for dealing with distinguished names */
2 /* $OpenLDAP$ */
3 /*
4  * The functions normalize_unicode(), get_hexpair(), write_hex_pair(),
5  * get_next_byte(), get_next_char(), get_ber_length(),
6  * ber_parse_primitive_string(), ber_parse_string(), String_normalize(),
7  * DirectoryString_normalize(), PrintableString_normalize(),
8  * IA5String_normalize(), ber_parse_primitive_bitstring(),
9  * ber_parse_bitstring(), getNext8bits(), bitString_normalize(), match_oid(),
10  * match_key(), get_validated_av_in_dn(), get_validated_rdn_in_dn(),
11  * and get_validated_dn() in this file were developed at the National Institute
12  * of Standards and Technology by employees of the Federal Government in the
13  * course of their official duties. Pursuant to title 17 Section 105 of the
14  * United States Code the code in these functions is not subject to copyright
15  * protection and is in the public domain. The copyright for all other code in
16  * this file is as specified below.
17  */
18 /*
19  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
20  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
21  */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26
27 #include <ac/ctype.h>
28 #include <ac/socket.h>
29 #include <ac/string.h>
30 #include <ac/time.h>
31
32 #include "ldap_pvt.h"
33
34 #include "slap.h"
35
36 #define B4LEADTYPE              0
37 #define B4TYPE                  1
38 #define INOIDTYPE               2
39 #define INKEYTYPE               3
40 #define B4EQUAL                 4
41 #define B4VALUE                 5
42 #define INVALUE                 6
43 #define INQUOTEDVALUE   7
44 #define B4SEPARATOR             8
45 #define INBERENCODEDVALUE       9
46
47 #define UTF8DN 1
48
49 typedef int (*av_normalize_type)(char **, char **, int *, int, int, int, unsigned long *);
50
51 #define PRINTABLE_STRING        1
52 #define IA5_STRING              2
53 #define TELETEX_STRING          3
54 #define BMP_STRING              4
55 #define UNIVERSAL_STRING        5
56 #define UTF8_STRING             6
57 #define DIRECTORY_STRING        7
58
59 /* unnormalized_unicode contains a string of ucs4 encoded unicode characters of length
60  * len. Place in *d a normalized UTF8 encoded version of unnormalized_unicode. If firstchar is
61  * true, then the first character output by uccanoncomp is the first character of the
62  * attribute value. If successful, return 1 and advance *d to the end of the UTF8 encoded string.
63  * Otherwise, return 0.
64  */
65 static int
66 normalize_unicode(unsigned long *unnormalized_unicode, int len, char **d, int *av_length) {
67         unsigned long *normalized_unicode;
68         int i, normalized_len, char_len;
69         char tmp;
70
71 #ifdef UTF8DN
72         i = uccanondecomp(unnormalized_unicode, len, &normalized_unicode, &normalized_len);
73         if ( (i == -1) || (normalized_unicode == NULL) )
74                 return 0;
75         normalized_len = uccanoncomp(normalized_unicode, normalized_len);
76
77         char_len = ldap_ucs4_to_utf8(normalized_unicode[0], *d);
78         *d += char_len;
79
80         for(i=1; i < normalized_len; i++) {
81                 char_len = ldap_ucs4_to_utf8(normalized_unicode[i], *d);
82                 tmp = **d;
83                 if ( RDN_NEEDSESCAPE( tmp ) || RDN_SPECIAL( tmp ) ) {
84                         **d = '\\';
85                         *d += 1;
86                         **d = tmp;
87                         *d+= 1;
88                 } else if ( ASCII_WHITESPACE( tmp ) && ASCII_SPACE( *(*d - 1) ) ) {
89                          /* There should not be two consequtive space characters in the
90                           * normalized string. */
91                         normalized_len--;
92                 } else {
93                         *d += char_len;
94                 }
95         }
96         *av_length += normalized_len;
97
98         ch_free(normalized_unicode);
99 #endif
100
101         return 1;
102 }
103
104 /* The next two bytes in the string beginning at *sec should be
105  * a pair of hexadecimal characters. If they are, the value of that
106  * hexpair is placed in *out and 1 is returned. Otherwise, 0 is returned.
107  */
108 static int
109 get_hexpair(char **src, unsigned char *out)
110 {
111         unsigned char ch;
112
113         ch = **src;
114
115         if ( !ASCII_XDIGIT(ch) ) {
116                 return 0;
117         }
118
119         if ( ASCII_DIGIT(ch) ) {
120                 *out = ch - '0';
121         } else if ( ch >= 'A' && ch <= 'F' ) {
122                 *out = ch - 'A' + 10;
123         } else {
124                 *out = ch - 'a' + 10;
125         }
126
127         *src += 1;
128
129         ch = **src;
130
131         if ( !ASCII_XDIGIT(ch) ) {
132                 return 0;
133         }
134
135         *out = *out << 4;
136
137         if ( ASCII_DIGIT(ch) ) {
138                 *out += ch - '0';
139         } else if ( ch >= 'A' && ch <= 'F' ) {
140                 *out += ch - 'A' + 10;
141         } else {
142                 *out += ch - 'a' + 10;
143         }
144
145         *src += 1;
146
147         return 1;
148 }
149
150
151 /* output in as a hexadecimal pair to the string pointed to be *d and advance *d to the end
152  * of the hexpair.
153  */
154 static void
155 write_hex_pair(char **d, unsigned char in) {
156         unsigned char upper_nibble, lower_nibble;
157
158         upper_nibble = (in & 0xF0) >> 4;
159         lower_nibble = in & 0x0F;
160
161         if (upper_nibble < 10)
162                 **d = upper_nibble + '0';
163         else
164                 **d = upper_nibble - 10 + 'A';
165
166         *d += 1;
167
168         if (lower_nibble < 10)
169                 **d = lower_nibble + '0';
170         else
171                 **d = lower_nibble - 10 + 'A';
172
173         *d += 1;
174 }
175
176
177 /* The string beginning at *src represents a octet.
178  * The octet is either represented by a single byte or
179  * a '\' followed by a 2-byte hexpair or a single byte.
180  * Place the octet in *out, increment *src to the beginning
181  * of the next character. If the representation of the octet
182  * began with a '\' then *is_escaped is set to 1. Otherwise,
183  * *is_escaped is set to 0. If the string beginning at *src
184  * does not represent a well formed octet, then 0 is returned.
185  * Otherwise 1 is returned.
186  */
187 static int
188 get_next_byte(char **src, unsigned char *out, int *is_escaped)
189 {
190         unsigned char tmp;
191         unsigned char s1, s2;
192
193         s1 = **src;
194         if (s1 == '\0')
195                 return 0;
196
197         *src += 1;
198
199         if ( s1 != '\\' ) {
200                 *out = s1;
201                 *is_escaped = 0;
202                 return 1;
203         }
204
205         *is_escaped = 1;
206
207         s1 = **src;
208         if ( s1 == '\0' )
209                 return 0;
210
211         if ( !ASCII_XDIGIT( s1 ) ) {
212                 *src += 1;
213                 *out = s1;
214                 return 1;
215         } else {
216                 if ( get_hexpair(src, &s2) ) {
217                         *out = s2;
218                         return 1;
219                 } else {
220                         return 0;
221                 }
222         }
223 }
224
225
226 /* If the string beginning at *src is a well formed UTF8 character,
227  * then the value of that character is placed in *out and 1 is returned.
228  * If the string is not a well formed UTF8 character, 0 is returned.
229  * If the character is an ASCII character, and its representation began
230  * with a '\', then *is_escaped is set to 1. Otherwise *is_escaped is set to 0.
231  * When the function returns, *src points to the first byte after the character.
232  */
233 static int
234 get_next_char(char **src, unsigned long int *out, int *is_escaped)
235 {
236         unsigned char tmp;
237         int i, res, len;
238         unsigned long int ch;
239
240         static unsigned char mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
241
242         res = get_next_byte( src, &tmp, is_escaped );
243
244         *out = tmp;
245
246 #ifndef UTF8DN
247         return res;
248 #else
249         if ( ( res == 0 ) || ( tmp < 128 ) ) {
250                 return res;
251         }
252
253         /* This is a UTF8 encoded, non-ASCII character */
254         len = ldap_utf8_charlen( &tmp );
255
256         if ( len == 0 )
257                 return 0;
258
259         ch = tmp & mask[len];
260
261         for(i=1; i < len; i++) {
262                 res = get_next_byte( src, &tmp, is_escaped );
263                 if ( ( res == 0) || ( ( tmp & 0xc0 ) != 0x80 ) ) return 0;
264
265                 ch <<= 6;
266                 ch |= tmp & 0x3f;
267         }
268
269         *is_escaped = 0;
270         *out = ch;
271 #endif
272 }
273
274
275 /* The string beginning at *s should be an ASCII-hex encoding of BER encoded
276  * length data. If so, place the length in *length, add the length of the
277  * length encoding to *encoded_length, advance *s to next byte after the end
278  * of the length encoding, and return 1. Otherwise, return 0.
279  */
280 static int
281 get_ber_length(
282         char **s,
283         unsigned int *encoded_length,
284         unsigned long int *length
285 )
286 {
287         int res;
288         unsigned char ch, ch2;
289
290         res = get_hexpair(s, &ch);
291         if (res == 0)
292                 return 0;
293
294         *encoded_length += 1;
295
296         if ( (ch & 0x80) == 0) {
297                 /* Bit 8 is 0, so this byte gives the length */
298                 *length = ch;
299         } else {
300                 /* This byte specifies the number of remaining length octets */
301                 ch = ch & 0x7F;
302
303                 if (ch > 4) {
304                         /* This assumes that length can hold up to a 32-bit
305                          * integer and that bit strings will always be shorter
306                          * than 2**32 bytes.
307                          */
308                         return 0;
309                 }
310
311                 *length = 0;
312                 while (ch > 0) {
313                         *length = *length << 8;
314
315                         res = get_hexpair(s, &ch2);
316                         if (res == 0)
317                                 return 0;
318
319                         *encoded_length += 1;
320                         *length = *length | ch2;
321
322                         ch--;
323                 }
324         }
325
326         return 1;
327 }
328
329
330 /* The string beginning at *s should be an ASCII-hex encoding of a BER
331  * encoded string of type string_type (minus the "tag" octet) in which the
332  * encoding is primitive, definite length. If it is, write a UTF8 encoding
333  * of the string, according to RFC 2253, to *d, advance *s to one byte after
334  * the end of the BER encoded string, advance *d to one byte after the UTF8
335  * encoded string, add to *encoded_length the length of the BER encoding, add
336  * to *av_length the number of UTF8 characters written to *d, set *firstchar
337  * to 0 if any characters are written to *d, and return 1. Otherwise, return
338  * 0. If make_uppercase is 1, write all of the characters in uppercase. If
339  * not, write the characters as they occur in the BER encoding. If
340  * normalize is 1, remove all leading and trailing whitespace, and
341  * compress all whitespace between words to a single space. If not, transfer
342  * whitespace from the BER encoding to the UTF8 encoding unchanged.
343  */
344 static int
345 ber_parse_primitive_string(
346         char **s,
347         char **d,
348         int *av_length,
349         int make_uppercase,
350         int normalize,
351         int string_type,
352         unsigned int *encoded_length,
353         int *firstchar,
354         unsigned long *unnormalized_unicode,
355         int *unnormalized_unicode_len
356 )
357 {
358         int i, len, res;
359         unsigned char ch;
360         unsigned long int uch;
361         unsigned long int length;
362         char tmp;
363
364         static unsigned char mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
365
366         res = get_ber_length(s, encoded_length, &length);
367         if (res == 0)
368                 return 0;
369
370         while (length > 0) {
371                 /* read in next character */
372                 if (string_type == PRINTABLE_STRING) {
373                         /* each character is one byte */
374                         res = get_hexpair(s, &ch);
375                         if (res == 0)
376                                 return 0;
377
378                         *encoded_length += 1;
379                         length -= 1;
380
381                         if ( !SLAP_PRINTABLE(ch) )
382                                 return 0;
383
384                         uch = ch;
385
386                 } else if (string_type == IA5_STRING) {
387                         /* each character is one byte */
388                         res = get_hexpair(s, &ch);
389                         if (res == 0)
390                                 return 0;
391
392                         *encoded_length += 1;
393                         length -= 1;
394
395                         if ( !SLAP_IA5(ch) )
396                                 return 0;
397
398                         uch = ch;
399
400                 } else if (string_type == TELETEX_STRING) {
401                         /* This code is not correct. Each character is one byte.
402                          * However, the enocodings need to be transliterated to
403                          * unicode.
404                          */
405                         res = get_hexpair(s, &ch);
406                         if (res == 0)
407                                 return 0;
408
409                         *encoded_length += 1;
410                         length -= 1;
411
412                         uch = ch;
413
414                 } else if (string_type == BMP_STRING) {
415                         /* This is a 2-byte unicode character */
416                         if (length < 2)
417                                 return 0;
418
419                         uch = 0;
420
421                         for(i=0; i < 2; i++) {
422                                 res = get_hexpair(s, &ch);
423                                 if (res == 0)
424                                         return 0;
425
426                                 uch = uch << 8;
427                                 uch = uch | ch;
428                         }
429
430                         *encoded_length += 2;
431                         length -= 2;
432                 } else if (string_type == UNIVERSAL_STRING) {
433                         /* This is a 4-byte unicode character */
434                         if (length < 4)
435                                 return 0;
436
437                         uch = 0;
438
439                         for(i=0; i < 4; i++) {
440                                 res = get_hexpair(s, &ch);
441                                 if (res == 0)
442                                         return 0;
443
444                                 uch = uch << 8;
445                                 uch = uch | ch;
446                         }
447
448                         *encoded_length += 4;
449                         length -= 4;
450                 } else if (string_type == UTF8_STRING) {
451                         res = get_hexpair(s, &ch);
452                         if (res == 0)
453                                 return 0;
454
455                         *encoded_length += 1;
456
457                         #ifndef UTF8DN
458                                 /* Not sure what to do here */
459                                 uch = ch;
460                                 length -= 1;
461                         #else
462                                 len = ldap_utf8_charlen( &ch );
463                                 if ( ( len == 0) || ( length < len ) )
464                                         return 0;
465
466                                 uch = ch & mask[len];
467
468                                 for(i=1; i < len; i++) {
469                                         res = get_hexpair(s, &ch);
470                                         if ( ( res == 0) || ( ( ch & 0xc0 ) != 0x80 ) ) return 0;
471
472                                         *encoded_length += 1;
473
474                                         uch <<= 6;
475                                         uch |= ch & 0x3f;
476                                 }
477
478                                 length -= len;
479                         #endif
480                 } else {
481                         /* Unknown string type */
482                         return 0;
483                 }
484
485                 /* Now add character to *d */
486
487                 #ifdef UTF8DN
488                         if (make_uppercase) {
489                                 uch = uctoupper( uch );
490                         }
491
492                         if ( (uch < 128) && (*unnormalized_unicode_len > 0) ) {
493                                 res = normalize_unicode(unnormalized_unicode, *unnormalized_unicode_len, d, av_length);
494                                 if (res == 0)
495                                         return 0;
496                                 *unnormalized_unicode_len = 0;
497                         }
498
499                         if ( !normalize || !ASCII_WHITESPACE(uch) ) {
500                                 if ( (*firstchar) && ASCII_SPACE(uch) ) {
501                                         **d = '\\';
502                                         *d += 1;
503                                         **d = '2';
504                                         *d += 1;
505                                         **d = '0';
506                                         *d += 1;
507                                         *av_length += 1;
508                                 } else {
509                                         if ( normalize && (uch > 127) ) {
510                                                 if (*unnormalized_unicode_len == 0) {
511                                                         /* The previous output character must be ASCII
512                                                          * and it should be normalized.
513                                                          */
514                                                         *d -= 1;
515                                                         unnormalized_unicode[0] = **d;
516                                                         *unnormalized_unicode_len = 1;
517                                                         *av_length -= 1;
518                                                 }
519                                                 unnormalized_unicode[*unnormalized_unicode_len] = uch;
520                                                 *unnormalized_unicode_len += 1;
521                                         } else {
522                                                 len = ldap_ucs4_to_utf8( uch, *d );
523                                                 tmp = **d;
524                                                 if ( RDN_NEEDSESCAPE( tmp ) || RDN_SPECIAL( tmp ) ) {
525                                                         **d = '\\';
526                                                         *d += 1;
527                                                         **d = tmp;
528                                                         *d += 1;
529                                                 } else if ( (*firstchar) && ( uch == '#' ) ) {
530                                                         **d = '\\';
531                                                         *d += 1;
532                                                         **d = tmp;
533                                                         *d += 1;
534                                                 } else {
535                                                         *d += len;
536                                                 }
537                                                 *av_length += 1;
538                                         }
539                                 }
540                                 *firstchar = 0;
541                         } else if ( !(*firstchar) && !ASCII_SPACE( *(*d - 1) ) ) {
542                                 **d = ' ';
543                                 *d += 1;
544                                 *av_length += 1;
545                         }
546                 #else
547                         /* Not sure what to do here either */
548                         if (uch > 127)
549                                 return 0;
550
551                         if (make_uppercase) {
552                                 uch = TOUPPER( uch );
553                         }
554
555                         if ( !normalize || !ASCII_WHITESPACE(uch) ) {
556                                 if ( (*firstchar) && ASCII_SPACE(uch) ) {
557                                         **d = '\\';
558                                         *d += 1;
559                                         **d = '2';
560                                         *d += 1;
561                                         **d = '0';
562                                         *d += 1;
563                                 } else {
564                                         if ( RDN_NEEDSESCAPE( uch ) || RDN_SPECIAL( uch ) ) {
565                                                 **d = '\\';
566                                                 *d += 1;
567                                         } else if ( (*firstchar) && ( uch == '#' ) ) {
568                                                 **d = '\\';
569                                                 *d += 1;
570                                         }
571                                         **d = uch;
572                                         *d += 1;
573                                 }
574                                 *firstchar = 0;
575                                 *av_length += 1;
576                         } else if ( !(*firstchar) && !ASCII_SPACE( *(*d - 1) ) ) {
577                                 **d = ' ';
578                                 *d += 1;
579                                 *av_length += 1;
580                         }
581                 #endif
582         }
583
584         return 1;
585 }
586
587
588 /* The string beginning at *s should be an ASCII-hex encoding of a BER
589  * encoded string of type string_type. If it is, write a UTF8 encoding
590  * of the string, according to RFC 2253, to *d, advance *s to one byte after
591  * the end of the BER encoded string, advance *d to one byte after the UTF8
592  * encoded string, add to *encoded_length the length of the BER encoding, add
593  * to *av_length the number of UTF8 characters written to *d, set *firstchar
594  * to 0 if any characters are written to *d, and return 1. Otherwise, return
595  * 0. If make_uppercase is 1, write all of the characters in uppercase. If
596  * not, write the characters as they occur in the BER encoding. If
597  * normalize is 1, remove all leading and trailing whitespace, and
598  * compress all whitespace between words to a single space. If not, transfer
599  * whitespace from the BER encoding to the UTF8 encoding unchanged.
600  */
601 static int
602 ber_parse_string(
603         char **s,
604         char **d,
605         int *av_length,
606         int make_uppercase,
607         int normalize,
608         int string_type,
609         unsigned int *encoded_length,
610         int *firstchar,
611         unsigned long *unnormalized_unicode,
612         int *unnormalized_unicode_len
613 )
614 {
615         int res;
616         unsigned char ch, tag, encoding_method;
617         int ber_string_type;
618         unsigned long int length;
619         unsigned int component_encoded_length;
620
621         res = get_hexpair(s, &ch);
622         if (res == 0)
623                 return 0;
624
625         *encoded_length = 1;
626
627         /* zero out bit 5 */
628         tag = ch & 0xDF;
629
630         if (tag == 12)
631                 ber_string_type = UTF8_STRING;
632         else if (tag == 19)
633                 ber_string_type = PRINTABLE_STRING;
634         else if (tag == 20)
635                 ber_string_type = TELETEX_STRING;
636         else if (tag == 22)
637                 ber_string_type = IA5_STRING;
638         else if (tag == 28)
639                 ber_string_type = UNIVERSAL_STRING;
640         else if (tag == 30)
641                 ber_string_type = BMP_STRING;
642         else {
643                 /* Unknown string type or not a string type */
644                 return 0;
645         }
646
647         /* Check that this is an acceptable string type */
648         if ( ber_string_type == string_type ) {
649                 /* OK */
650         } else if ( ( string_type == DIRECTORY_STRING ) &&
651                         ( ( ber_string_type == PRINTABLE_STRING ) ||
652                           ( ber_string_type == TELETEX_STRING ) ||
653                           ( ber_string_type == BMP_STRING ) ||
654                           ( ber_string_type == UNIVERSAL_STRING ) ||
655                           ( ber_string_type == UTF8_STRING ) ) ) {
656                 /* OK */
657         } else {
658                 /* Bad string type */
659                 return 0;
660         }
661
662         /* Bit 5 specifies the encoding method */
663         encoding_method = ch & 0x20;
664
665         if (encoding_method == 0) {
666                 /* Primitive, definite-length encoding */
667                 res = ber_parse_primitive_string(s, d, av_length, make_uppercase, normalize, ber_string_type, encoded_length, firstchar, unnormalized_unicode, unnormalized_unicode_len);
668                 if (res == 0)
669                         return 0;
670         } else {
671                 /* Constructed encoding */
672
673                 res = get_hexpair(s, &ch);
674                 if (res == 0)
675                         return 0;
676
677                 if (ch == 128) {
678                         /* Constructed, indefinite-length */
679                         *encoded_length += 1;
680
681                         while (ch != 0) {
682                                 res = ber_parse_string(s, d, av_length, make_uppercase, normalize, ber_string_type, &component_encoded_length, firstchar, unnormalized_unicode, unnormalized_unicode_len);
683                                 if (res == 0)
684                                         return 0;
685
686                                 *encoded_length += component_encoded_length;
687
688                                 /* Must end in "0000" */
689                                 res = get_hexpair(s, &ch);
690                                 if (res == 0)
691                                         return 0;
692
693                                 if (ch == 0) {
694                                         res = get_hexpair(s, &ch);
695                                         if ( (res == 0) || (ch != 0) )
696                                                 return 0;
697
698                                         *encoded_length += 2;
699                                 } else {
700                                         *s -= 2;
701                                 }
702                         }
703                 } else {
704                         /* Constructed, definite-length */
705                         *s -= 2;
706                         res = get_ber_length(s, encoded_length, &length);
707                         if (res == 0)
708                                 return 0;
709
710                         while (length > 0) {
711                                 res = ber_parse_string(s, d, av_length, make_uppercase, normalize, ber_string_type, &component_encoded_length, firstchar, unnormalized_unicode, unnormalized_unicode_len);
712                                 if ( (res == 0) || (component_encoded_length > length) )
713                                         return 0;
714
715                                 length -= component_encoded_length;
716                                 *encoded_length += component_encoded_length;
717                         }
718                 }
719         }
720 }
721
722
723 /* The string beginning at *s should be a string of type string_type encoded
724  * as described in RFC 2253. If it is, write a UTF8 encoding
725  * of the string, according to RFC 2253, to *d, advance *s to one byte after
726  * the end of the BER encoded string, advance *d to one byte after the UTF8
727  * encoded string, set *av_length the number of UTF8 characters written to *d,
728  * and return 1. Otherwise, return 0. If make_uppercase is 1, write all of the
729  * characters in uppercase. If not, write the characters as they occur. If
730  * normalize is 1, remove all leading and trailing whitespace, and
731  * compress all whitespace between words to a single space. If not, transfer
732  * whitespace from the BER encoding to the UTF8 encoding unchanged.
733  * representation specifies whether the string is encoding as ASCII-hex BER,
734  * within quotation marks, or as a plain string.
735  */
736 static int
737 String_normalize(
738         char **s,
739         char **d,
740         int *av_length,
741         int make_uppercase,
742         int normalize,
743         int representation,
744         int string_type,
745         unsigned long *unnormalized_unicode
746 )
747 {
748         int done = 0;
749         int firstchar = 1;
750         int first_dstchar = 0;
751         char *lastchar;
752         unsigned long int tmp;
753         int res, len;
754         int is_escaped;
755         unsigned int encoded_length;
756         int unnormalized_unicode_len = 0;
757
758         *av_length = 0;
759         lastchar = *d;
760
761         switch ( representation ) {
762
763         case INVALUE:
764         case INQUOTEDVALUE:
765                 if ( representation == INQUOTEDVALUE ) {
766                         *s += 1;
767                         if ( !normalize )
768                                 firstchar = 0;
769                 }
770
771                 while( !done ) {
772                         if ( **s == '\0' ) {
773                                 if (unnormalized_unicode_len > 0) {
774                                         res = normalize_unicode(unnormalized_unicode, unnormalized_unicode_len, d, av_length);
775                                         if (res == 0)
776                                                 return 0;
777                                 } else {
778                                         *av_length -= (*d - lastchar);
779                                         if ( !normalize && ( ASCII_SPACE(*(lastchar - 1)) ) ) {
780                                                 /* a space at the end of the string must be escaped */
781                                                 *(lastchar - 1) = '\\';
782                                                 *lastchar++ = '2';
783                                                 *lastchar++ = '0';
784                                         }
785                                         *d = lastchar;
786                                 }
787                                 
788                                 if (representation == INQUOTEDVALUE) {
789                                         /* Missing end quote */
790                                         return 0;
791                                 }
792                                 done = 1;
793                         } else if ( representation == INVALUE && RDN_SEPARATOR( **s ) ) {
794                                 if (unnormalized_unicode_len > 0) {
795                                         res = normalize_unicode(unnormalized_unicode, unnormalized_unicode_len, d, av_length);
796                                         if (res == 0)
797                                                 return 0;
798                                 } else {
799                                         *av_length -= (*d - lastchar);
800                                         if ( !normalize && ( ASCII_SPACE(*(lastchar - 1)) ) ) {
801                                                 /* a space at the end of the string must be escaped */
802                                                 *(lastchar - 1) = '\\';
803                                                 *lastchar++ = '2';
804                                                 *lastchar++ = '0';
805                                         }
806                                         *d = lastchar;
807                                 }
808                                 done = 1;
809                         } else if ( representation == INQUOTEDVALUE  && **s == '"' ) {
810                                 if (unnormalized_unicode_len > 0) {
811                                         res = normalize_unicode(unnormalized_unicode, unnormalized_unicode_len, d, av_length);
812                                         if (res == 0)
813                                                 return 0;
814                                 } else {
815                                         *av_length -= (*d - lastchar);
816                                         if ( !normalize && ( ASCII_SPACE(*(lastchar - 1)) ) ) {
817                                                 /* a space at the end of the string must be escaped */
818                                                 *(lastchar - 1) = '\\';
819                                                 *lastchar++ = '2';
820                                                 *lastchar++ = '0';
821                                         }
822                                         *d = lastchar;
823                                 }
824                                 *s += 1;
825                                 done = 1;
826                         } else {
827                                 if ( !normalize && !ASCII_SPACE( **s ) )
828                                         firstchar = 0;
829
830                                 res = get_next_char( s, &tmp, &is_escaped );
831                                 if (res == 0)
832                                         return 0;
833
834                                 if ( string_type == PRINTABLE_STRING ) {
835                                         if ( !SLAP_PRINTABLE(tmp) )
836                                                 return 0;
837                                 } else if (string_type == IA5_STRING ) {
838                                         if ( !SLAP_IA5(tmp) )
839                                                 return 0;
840                                 }
841
842                                 if ( !ASCII_WHITESPACE( tmp ) )
843                                         firstchar = 0;
844
845                                 if ( (tmp < 128) && (unnormalized_unicode_len > 0) ) {
846                                         res = normalize_unicode(unnormalized_unicode, unnormalized_unicode_len, d, av_length);
847                                         if (res == 0)
848                                                 return 0;
849                                         unnormalized_unicode_len = 0;
850                                         lastchar = *d;
851                                 }
852
853                                 if ( RDN_NEEDSESCAPE( tmp ) ||
854                                             RDN_SPECIAL( tmp ) ) {
855                                                 if ( ( representation == INVALUE ) && !is_escaped ) {
856                                                         /* This character should have been escaped according to
857                                                          * RFC 2253, but was not */
858                                                         return 0;
859                                                 }
860                                                 /* This must be an ASCII character */
861                                                 **d = '\\';
862                                                 *d += 1;
863                                                 **d = tmp;
864                                                 *d += 1;
865                                                 *av_length += 1;
866                                                 lastchar = *d;
867                                                 first_dstchar = 1;
868                                 } else if ( tmp == 0 ) {
869                                         strncpy(*d, "\\00", 3);
870                                         *d += 3;
871                                         *av_length += 1;
872                                         lastchar = *d;
873                                         first_dstchar = 1;
874                                 } else if ( !first_dstchar && (tmp == '#') ) {
875                                         **d = '\\';
876                                         *d += 1;
877                                         **d = tmp;
878                                         *d += 1;
879                                         *av_length += 1;
880                                         lastchar = *d;
881                                         first_dstchar = 1;
882                                 } else if ( !normalize && !ASCII_SPACE( tmp ) ) {
883                                         #ifdef UTF8DN
884                                                 if (make_uppercase) {
885                                                         tmp = uctoupper( tmp );
886                                                 }
887                                                 len = ldap_ucs4_to_utf8( tmp, *d );
888                                                 *d += len;
889                                         #else
890                                                 if (make_uppercase) {
891                                                         **d = TOUPPER( tmp );
892                                                 } else {
893                                                         **d = tmp;
894                                                 }
895                                                 *d += 1;
896                                         #endif
897                                         *av_length += 1;
898                                         lastchar = *d;
899                                         first_dstchar = 1;
900                                 } else if ( !ASCII_WHITESPACE( tmp ) ) {
901                                         #ifdef UTF8DN
902                                                 if (make_uppercase) {
903                                                         tmp = uctoupper( tmp );
904                                                 }
905                                                 if ( normalize && (tmp > 127) ) {
906                                                         if ( (unnormalized_unicode_len == 0) && first_dstchar ) {
907                                                                 /* The previous output character must be ASCII
908                                                                  * and it should be normalized.
909                                                                  */
910                                                                 *d -= 1;
911                                                                 unnormalized_unicode[unnormalized_unicode_len++] = **d;
912                                                                 *av_length -= 1;
913                                                         }
914                                                         unnormalized_unicode[unnormalized_unicode_len++] = tmp;
915                                                 } else {
916                                                         len = ldap_ucs4_to_utf8( tmp, *d );
917                                                         *d += len;
918                                                         *av_length += 1;
919                                                 }
920                                         #else
921                                                 if (make_uppercase) {
922                                                         **d = TOUPPER( tmp );
923                                                 } else {
924                                                         **d = tmp;
925                                                 }
926                                                 *d += 1;
927                                                 *av_length += 1;
928                                         #endif
929                                         lastchar = *d;
930                                         first_dstchar = 1;
931                                 } else if ( !firstchar && ( !normalize || !ASCII_SPACE( *(*d - 1) ) ) ) {
932                                         if ( !first_dstchar ) {
933                                                 **d = '\\';
934                                                 *d += 1;
935                                                 **d = '2';
936                                                 *d += 1;
937                                                 **d = '0';
938                                                 *d += 1;
939                                                 first_dstchar = 1;
940                                         } else {
941                                                 **d = ' ';
942                                                 *d +=1;
943                                         }
944                                         *av_length += 1;
945                                         if ( !normalize && ( is_escaped || representation == INQUOTEDVALUE ) )
946                                                 lastchar = *d;
947                                 }
948                         }
949                 }
950                 break;
951
952         case INBERENCODEDVALUE:
953                 /* Skip over the '#' */
954                 *s += 1;
955                 
956                 encoded_length = 0;
957
958                 res = ber_parse_string(s, d, av_length, make_uppercase, normalize, string_type, &encoded_length, &firstchar, unnormalized_unicode, &unnormalized_unicode_len);
959                 if (res == 0)
960                         return 0;
961
962                 if (unnormalized_unicode_len > 0) {
963                         res = normalize_unicode(unnormalized_unicode, unnormalized_unicode_len, d, av_length);
964                         if (res == 0)
965                                 return 0;
966                 } else if ( ASCII_SPACE( *(*d - 1) ) ) {
967                         if ( normalize ) {
968                                 *d -= 1;
969                                 *av_length -= 1;
970                         } else {
971                                 *(*d - 1) = '\\';
972                                 **d = '2';
973                                 *d += 1;
974                                 **d = '0';
975                                 *d += 1;
976                         }
977                 }
978
979                 break;
980
981         default:
982                 /* Something must be wrong, representation shouldn't
983                  * have any other value.
984                  */
985                 return 0;
986                 break;
987         }
988
989         return 1;
990 }
991
992
993 /* Normalize a directory string */
994 static int
995 DirectoryString_normalize(
996         char **s,
997         char **d,
998         int *av_length,
999         int make_uppercase,
1000         int normalize,
1001         int representation,
1002         unsigned long *unnormalized_unicode
1003 )
1004 {
1005         return String_normalize(s, d, av_length, make_uppercase, normalize, representation, DIRECTORY_STRING, unnormalized_unicode);
1006 }
1007
1008
1009 /* Normalize a printable string */
1010 static int
1011 PrintableString_normalize(
1012         char **s,
1013         char **d,
1014         int *av_length,
1015         int make_uppercase,
1016         int normalize,
1017         int representation,
1018         unsigned long *unnormalized_unicode
1019 )
1020 {
1021         return String_normalize(s, d, av_length, make_uppercase, normalize, representation, PRINTABLE_STRING, unnormalized_unicode);
1022 }
1023
1024
1025 /* Normalize an IA5 string */
1026 static int
1027 IA5String_normalize(
1028         char **s,
1029         char **d,
1030         int *av_length,
1031         int make_uppercase,
1032         int normalize,
1033         int representation,
1034         unsigned long *unnormalized_unicode
1035 )
1036 {
1037         return String_normalize(s, d, av_length, make_uppercase, normalize, representation, IA5_STRING, unnormalized_unicode);
1038 }
1039
1040
1041
1042 /* The string beginning at *s represents an ASCII-hex encoding of a BER
1043  * encoded bitstring, where the encoding is primitive, definite-length.
1044  * If the string is properly encoded, place the string in *d, advance *s
1045  * and *d, add the number of bits in the string to *av_length, add
1046  * the length of the BER encoding to *encoded_length, and return 1. Otherwise,
1047  * return 0.
1048  */
1049 static int
1050 ber_parse_primitive_bitstring(
1051         char **s,
1052         char **d,
1053         int *av_length,
1054         unsigned int *encoded_length
1055 )
1056 {
1057         int res;
1058         unsigned char ch;
1059         unsigned long int length;
1060         unsigned char unused;
1061         int bit_pos;
1062
1063         static unsigned char mask[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
1064
1065         res = get_ber_length(s, encoded_length, &length);
1066         if (res == 0)
1067                 return 0;
1068
1069         if (length < 1) {
1070                 /* There must be a least one byte containing the number of
1071                  * unused bits.
1072                  */
1073                 return 0;
1074         }
1075
1076         /* get number of unused bits */
1077         res = get_hexpair(s, &unused);
1078         if ( ( res == 0 ) || ( unused > 7 ) )
1079                 return 0;
1080
1081         if ( (length == 0) && (unused != 0) ) {
1082                 /* If there are no content bits, there can be no unused bits */
1083                 return 0;
1084         }
1085
1086         *encoded_length += 1;
1087         length--;
1088
1089         while( length > 1 ) {
1090                 res = get_hexpair(s, &ch);
1091                 if (res == 0)
1092                         return 0;
1093
1094                 *encoded_length += 1;
1095                 length--;
1096
1097                 for(bit_pos = 7; bit_pos >= 0; bit_pos--) {
1098                         if ( (ch & mask[bit_pos]) == 0 ) {
1099                                 **d = '0';
1100                         } else {
1101                                 **d = '1';
1102                         }
1103                         *d += 1;
1104                         *av_length += 1;
1105                 }
1106         }
1107
1108         if ( length == 1) {
1109                 res = get_hexpair(s, &ch);
1110                 if (res == 0)
1111                         return 0;
1112
1113                 *encoded_length += 1;
1114
1115                 for(bit_pos = 7; bit_pos >= unused; bit_pos--) {
1116                         if ( (ch & mask[bit_pos]) == 0 ) {
1117                                 **d = '0';
1118                         } else {
1119                                 **d = '1';
1120                         }
1121                         *d += 1;
1122                         *av_length += 1;
1123                 }
1124         }
1125
1126         return 1;
1127 }
1128
1129
1130 /* The string beginning at *s represents an ASCII-hex encoding of a BER
1131  * encoded bitstring. If the string is properly encoded, place the string
1132  * in *d, advance *s and *d, add the number of bits in the string to
1133  * *av_length, add the length of the BER encoding to *encoded_length, and
1134  * return 1. Otherwise, return 0.
1135  */
1136 static int
1137 ber_parse_bitstring(
1138         char **s,
1139         char **d,
1140         int *av_length,
1141         unsigned int *encoded_length
1142 )
1143 {
1144         int res;
1145         unsigned char ch;
1146         unsigned long int length;
1147         unsigned int component_encoded_length;
1148
1149         res = get_hexpair(s, &ch);
1150         if (res == 0)
1151                 return 0;
1152
1153         *encoded_length = 1;
1154
1155         if (ch == '\x03') {
1156                 /* Primitive, definite-length encoding */
1157                 res = ber_parse_primitive_bitstring(s, d, av_length, encoded_length);
1158                 if (res == 0)
1159                         return 0;
1160         } else if ( ch == '\x23' ) {
1161                 /* Constructed encoding */
1162
1163                 res = get_hexpair(s, &ch);
1164                 if (res == 0)
1165                         return 0;
1166
1167                 if ( ch == 128 ) {
1168                         /* Constructed, indefinite-length */
1169                         *encoded_length += 1;
1170
1171                         while ( ch != 0 ) {
1172                                 res = ber_parse_bitstring(s, d, av_length, &component_encoded_length);
1173                                 if (res == 0)
1174                                         return 0;
1175
1176                                 *encoded_length += component_encoded_length;
1177
1178                                 /* Must end in "0000" */
1179                                 res = get_hexpair(s, &ch);
1180                                 if (res == 0)
1181                                         return 0;
1182
1183                                 if (ch == 0) {
1184                                         res = get_hexpair(s, &ch);
1185                                         if ( (res == 0) || (ch != 0) )
1186                                                 return 0;
1187
1188                                         *encoded_length += 2;
1189                                 } else {
1190                                         *s -= 2;
1191                                 }
1192                         }
1193                 } else {
1194                         /* Constructed, definite-length */
1195                         *s -= 2;
1196                         res = get_ber_length(s, encoded_length, &length);
1197                         if (res == 0)
1198                                 return 0;
1199
1200                         while (length > 0) {
1201                                 res = ber_parse_bitstring(s, d, av_length, &component_encoded_length);
1202                                 if ( (res == 0) || (component_encoded_length > length) )
1203                                         return 0;
1204
1205                                 length -= component_encoded_length;
1206                                 *encoded_length += component_encoded_length;
1207                         }
1208                 }
1209         } else {
1210                 /* Not a valid bitstring */
1211                 return 0;
1212         }
1213 }
1214
1215
1216 /* *s is a pointer to a string of zero or more 0's and 1's. Return a binary encoding of the next 8 bits of *s and advance
1217  * *s to the end of the parsed sub-string. If the string is less than 8-bytes long, pad the binary encoding with 0's.
1218  */
1219 static unsigned char
1220 getNext8bits(
1221         char **s
1222 )
1223 {
1224         static unsigned char mask[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
1225         int pos;
1226         unsigned char output;
1227
1228         output = 0;
1229         pos = 8;
1230
1231         while ( ( pos > 0 ) && ( ( **s == '0' ) || ( **s == '1' ) ) ) {
1232                 pos--;
1233
1234                 if ( **s == '1' ) {
1235                         output = output | mask[pos];
1236                 }
1237
1238                 *s += 1;
1239         }
1240
1241         return output;
1242 }
1243
1244
1245 /* The string beginning at *s represents a bitstring encoded according to
1246  * RFC 2253. If the string is properly encoded, place the string
1247  * in *d, advance *s and *d, place the length of the string representation of
1248  * the bitstring in *av_length, and return 1. Otherwise, return 0.
1249  * representation specifies whether the string is encoding as ASCII-hex BER,
1250  * within quotation marks, or as a plain string.
1251  *
1252  *   According to RFC 2252, the string representation for
1253  *   bit strings is described by the following BNF:
1254  *
1255  *    bitstring = "'" *binary-digit "'B"
1256  *
1257  *    binary-digit = "0" / "1"
1258  */
1259 static int
1260 bitString_normalize(
1261         char **s,
1262         char **d,
1263         int *av_length,
1264         int make_uppercase,
1265         int normalize,
1266         int representation,
1267         unsigned long *unnormalized_unicode /* not used in this function */
1268 )
1269 {
1270         int res;
1271         int is_escaped;
1272         unsigned char ch;
1273         unsigned int encoded_length;
1274
1275         int DER_length;
1276         unsigned char unused_bits;
1277         unsigned char byte1, byte2, temp;
1278         char *src, *start_of_output;
1279         
1280         *av_length = 0;
1281         start_of_output = *d;
1282
1283         switch ( representation ) {
1284
1285         case INVALUE:
1286         case INQUOTEDVALUE:
1287                 if ( representation == INQUOTEDVALUE ) {
1288                         /* Skip over quotation mark */
1289                         *s += 1;
1290                 }
1291
1292                 /* First non-space character must be a "'" */
1293                 res = get_next_byte(s, &ch, &is_escaped);
1294                 if ( (res == 0) || (ch != '\'') )
1295                         return 0;
1296
1297                 **d = '\'';
1298                 *d += 1;
1299                 *av_length += 1;
1300
1301                 /* Next should be a sequence of 0's and 1's followed by a "'" */
1302                 res = get_next_byte(s, &ch, &is_escaped);
1303                 if (res == 0)
1304                         return 0;
1305                 
1306                 while ( ( ch == '0' ) || ( ch == '1' ) ) {
1307                         **d = ch;
1308                         *d += 1;
1309                         *av_length += 1;
1310
1311                         res = get_next_byte(s, &ch, &is_escaped);
1312                         if (res == 0)
1313                                 return 0;
1314                 }
1315
1316                 if ( ch != '\'' )
1317                         return 0;
1318
1319                 **d = '\'';
1320                 *d += 1;
1321                 *av_length += 1;
1322
1323                 /* The last character should be a 'B' */
1324                 res = get_next_byte(s, &ch, &is_escaped);
1325                 if ( (res == 0) || ( TOUPPER(ch) != 'B' ) )
1326                         return 0;
1327
1328                 **d = 'B';
1329                 *d += 1;
1330                 *av_length += 1;
1331
1332                 if ( representation == INQUOTEDVALUE ) {
1333                         if ( **s != '\"' )
1334                                 return 0;
1335                         else
1336                                 *s += 1;
1337                 }
1338                 break;
1339
1340         case INBERENCODEDVALUE:
1341                 /* Skip over the '#' */
1342                 *s += 1;
1343                 
1344                 **d = '\'';
1345                 *d += 1;
1346                 *av_length +=1;
1347
1348                 encoded_length = 0;
1349
1350                 ber_parse_bitstring(s, d, av_length, &encoded_length);
1351                 if (res == 0)
1352                         return 0;
1353
1354                 **d = '\'';
1355                 *d += 1;
1356                 **d = 'B';
1357                 *d += 1;
1358                 *av_length += 2;
1359
1360                 break;
1361
1362         default:
1363                 /* Something must be wrong, representation shouldn't
1364                  * have any other value.
1365                  */
1366                 return 0;
1367                 break;
1368         }
1369
1370         if ( !normalize && (representation != INBERENCODEDVALUE) )
1371                 return 1;
1372
1373         *av_length -= 3;
1374
1375         unused_bits = *av_length % 8;
1376         if ( unused_bits == 0 ) {
1377                 DER_length = (*av_length / 8) + 1;
1378         } else {
1379                 DER_length = (*av_length / 8) + 2;
1380                 unused_bits = 8 - unused_bits;
1381         }
1382
1383         *d = start_of_output;
1384         src = start_of_output + 1;
1385
1386         if (DER_length > 1)
1387                 byte1 = getNext8bits( &src );
1388         if (DER_length > 2)
1389                 byte2 = getNext8bits( &src );
1390
1391         **d = '#';
1392         *d += 1;
1393         **d = '0';
1394         *d += 1;
1395         **d = '3';
1396         *d += 1;
1397
1398         /* Insert length into string */
1399         if (DER_length < 128) {
1400                 temp = DER_length;
1401                 write_hex_pair(d, temp);
1402                 *av_length = 7 + 2 * DER_length;
1403         } else if (DER_length < 256) {
1404                 **d = '8';
1405                 *d += 1;
1406                 **d = '1';
1407                 *d += 1;
1408                 temp = DER_length;
1409                 write_hex_pair(d, temp);
1410                 *av_length = 9 + 2 * DER_length;
1411         } else if (DER_length < 65536) {
1412                 **d = '8';
1413                 *d += 1;
1414                 **d = '2';
1415                 *d += 1;
1416                 temp = (DER_length >> 8) & 0xFF;
1417                 write_hex_pair(d, temp);
1418                 temp = DER_length & 0xFF;
1419                 write_hex_pair(d, temp);
1420                 *av_length = 11 + 2 * DER_length;
1421         } else if (DER_length < 16777216) {
1422                 **d = '8';
1423                 *d += 1;
1424                 **d = '3';
1425                 *d += 1;
1426                 temp = (DER_length >> 16) & 0xFF;
1427                 write_hex_pair(d, temp);
1428                 temp = (DER_length >> 8) & 0xFF;
1429                 write_hex_pair(d, temp);
1430                 temp = DER_length & 0xFF;
1431                 write_hex_pair(d, temp);
1432                 *av_length = 13 + 2 * DER_length;
1433         } else {
1434                 /* NOTE: I am assuming that the length will always fit in 4 octets */
1435                 **d = '8';
1436                 *d += 1;
1437                 **d = '4';
1438                 *d += 1;
1439                 temp = (DER_length >> 24) & 0xFF;
1440                 write_hex_pair(d, temp);
1441                 temp = (DER_length >> 16) & 0xFF;
1442                 write_hex_pair(d, temp);
1443                 temp = (DER_length >> 8) & 0xFF;
1444                 write_hex_pair(d, temp);
1445                 temp = DER_length & 0xFF;
1446                 write_hex_pair(d, temp);
1447                 *av_length = 15 + 2 * DER_length;
1448         }
1449
1450         /* Insert number of unused bits into string */
1451         write_hex_pair(d, unused_bits);
1452
1453         if (DER_length > 1)
1454                 write_hex_pair(d, byte1);
1455         if (DER_length > 2)
1456                 write_hex_pair(d, byte2);
1457
1458         if (DER_length > 3) {
1459                 DER_length -= 3;
1460
1461                 while (DER_length > 0) {
1462                         byte1 = getNext8bits( &src );
1463                         write_hex_pair(d, byte1);
1464                         DER_length--;
1465                 }
1466         }
1467
1468         return 1;
1469 }
1470
1471
1472 /*
1473  * match_oid - determine if the OID represented by the string beginning
1474  * at *src and of length len is a known attribute type. If so, copy the
1475  * string representation to *dst and return a pointer to the normalization
1476  * function for the attribute value. If the attribute type places an
1477  * upper bound on the length of the attribute value, make *ub that
1478  * upper bound, otherwise set *ub to -1.
1479  * If the OID is unknown, copy the OID to *dst and return NULL.
1480  */
1481 static av_normalize_type
1482 match_oid(char **src, char **dst, int *ub, int len, int make_uppercase)
1483 {
1484         int i;
1485         int dst_len = 0;
1486         av_normalize_type normalize_function = NULL;
1487
1488         *ub = -1;
1489
1490         switch( len ) {
1491                 case 7:
1492                         if (strncmp(*src, "2.5.4.6", len) == 0) {
1493                                 /* Country */
1494                                 **dst = 'c';
1495                                 dst_len = 1;
1496                                 *ub = 2;
1497                                 normalize_function = PrintableString_normalize;
1498                         } else if (strncmp(*src, "2.5.4.3", len) == 0) {
1499                                 /* Common Name */
1500                                 strncpy(*dst, "cn", 2);
1501                                 dst_len = 2;
1502                                 *ub = 64;
1503                                 normalize_function = DirectoryString_normalize;
1504                         } else if (strncmp(*src, "2.5.4.8", len) == 0) {
1505                                 /* State or Province Name */
1506                                 strncpy(*dst, "st", 2);
1507                                 dst_len = 2;
1508                                 *ub = 128;
1509                                 normalize_function = DirectoryString_normalize;
1510                         } else if (strncmp(*src, "2.5.4.7", len) == 0) {
1511                                 /* locality */
1512                                 **dst = 'l';
1513                                 dst_len = 1;
1514                                 *ub = 128;
1515                                 normalize_function = DirectoryString_normalize;
1516                         } else if (strncmp(*src, "2.5.4.5", len) == 0) {
1517                                 /* serial number */
1518                                 strncpy(*dst, "snu", 3);
1519                                 dst_len = 3;
1520                                 *ub = 64;
1521                                 normalize_function = PrintableString_normalize;
1522                         } else if (strncmp(*src, "2.5.4.4", len) == 0) {
1523                                 /* surname */
1524                                 strncpy(*dst, "sn", 2);
1525                                 dst_len = 2;
1526                                 *ub = 64;
1527                                 normalize_function = DirectoryString_normalize;
1528                         } else if (strncmp(*src, "2.5.4.9", len) == 0) {
1529                                 /* street address */
1530                                 strncpy(*dst, "street", 6);
1531                                 dst_len = 6;
1532                                 *ub = 128;
1533                                 normalize_function = DirectoryString_normalize;
1534                         } else {
1535                                 /* Unknown attributeType */
1536                                 strncpy(*dst, *src, len);
1537                                 dst_len = len;
1538                                 *ub = -1;
1539                                 normalize_function = NULL;
1540                         }
1541                         break;
1542
1543                 case 8:
1544                         if (strncmp(*src, "2.5.4.10", len) == 0) {
1545                                 /* Organization */
1546                                 **dst = 'o';
1547                                 dst_len = 1;
1548                                 *ub = 64;
1549                                 normalize_function = DirectoryString_normalize;
1550                         } else if (strncmp(*src, "2.5.4.11", len) == 0) {
1551                                 /* Organizational Unit */
1552                                 strncpy(*dst, "ou", 2);
1553                                 dst_len = 2;
1554                                 *ub = 64;
1555                                 normalize_function = DirectoryString_normalize;
1556                         } else if (strncmp(*src, "2.5.4.12", len) == 0) {
1557                                 /* title */
1558                                 strncpy(*dst, "title", 5);
1559                                 dst_len = 5;
1560                                 *ub = 64;
1561                                 normalize_function = DirectoryString_normalize;
1562                         } else if (strncmp(*src, "2.5.4.42", len) == 0) {
1563                                 /* givenName */
1564                                 strncpy(*dst, "givenName", 9);
1565                                 dst_len = 9;
1566                                 *ub = -1;
1567                                 normalize_function = DirectoryString_normalize;
1568                         } else if (strncmp(*src, "2.5.4.43", len) == 0) {
1569                                 /* initials */
1570                                 strncpy(*dst, "initials", 8);
1571                                 dst_len = 8;
1572                                 *ub = -1;
1573                                 normalize_function = DirectoryString_normalize;
1574                         } else if (strncmp(*src, "2.5.4.44", len) == 0) {
1575                                 /* generationQualifier */
1576                                 strncpy(*dst, "generationQualifier", 19);
1577                                 dst_len = 19;
1578                                 *ub = -1;
1579                                 normalize_function = DirectoryString_normalize;
1580                         } else if (strncmp(*src, "2.5.4.45", len) == 0) {
1581                                 /* uniqueIdentifier */
1582                                 strncpy(*dst, "uniqueIdentifier", 16);
1583                                 dst_len = 16;
1584                                 *ub = -1;
1585                                 normalize_function = bitString_normalize;
1586                         } else if (strncmp(*src, "2.5.4.46", len) == 0) {
1587                                 /* dnQualifier */
1588                                 strncpy(*dst, "dnQualifier", 11);
1589                                 dst_len = 11;
1590                                 *ub = -1;
1591                                 normalize_function = PrintableString_normalize;
1592                         } else if (strncmp(*src, "2.5.4.65", len) == 0) {
1593                                 /* Pseudonym */
1594                                 strncpy(*dst, "Pseudonym", 9);
1595                                 dst_len = 9;
1596                                 *ub = 64;
1597                                 normalize_function = DirectoryString_normalize;
1598                         } else {
1599                                 /* Unknown attributeType */
1600                                 strncpy(*dst, *src, len);
1601                                 dst_len = len;
1602                                 *ub = -1;
1603                                 normalize_function = NULL;
1604                         }
1605                         break;
1606
1607                 case 20:
1608                         if (strncmp(*src, "1.2.840.113549.1.9.1", len) == 0) {
1609                                 /* email */
1610                                 **dst = 'e';
1611                                 dst_len = 1;
1612                                 *ub = 128;
1613                                 normalize_function = IA5String_normalize;
1614                         } else {
1615                                 /* Unknown attributeType */
1616                                 strncpy(*dst, *src, len);
1617                                 dst_len = len;
1618                                 *ub = -1;
1619                                 normalize_function = NULL;
1620                         }
1621                         break;
1622
1623                 case 17:
1624                         if (strncmp(*src, "0.2.262.1.10.7.20", len) == 0) {
1625                                 /* name distinguisher */
1626                                 strncpy(*dst, "nameDistinguisher", 17);
1627                                 dst_len = 17;
1628                                 *ub = -1;
1629                                 normalize_function = DirectoryString_normalize;
1630                         } else {
1631                                 /* Unknown attributeType */
1632                                 strncpy(*dst, *src, len);
1633                                 dst_len = len;
1634                                 *ub = -1;
1635                                 normalize_function = NULL;
1636                         }
1637                         break;
1638
1639                 case 25:
1640                         if (strncmp(*src, "0.9.2342.19200300.100.1.1", len) == 0) {
1641                                 /* userID */
1642                                 strncpy(*dst, "uid", 3);
1643                                 dst_len = 3;
1644                                 *ub = 256;
1645                                 normalize_function = DirectoryString_normalize;
1646                         } else {
1647                                 /* Unknown attributeType */
1648                                 strncpy(*dst, *src, len);
1649                                 dst_len = len;
1650                                 *ub = -1;
1651                                 normalize_function = NULL;
1652                         }
1653                         break;
1654
1655                 case 26:
1656                         if (strncmp(*src, "0.9.2342.19200300.100.1.25", len) == 0) {
1657                                 /* domainComponent */
1658                                 strncpy(*dst, "dc", 2);
1659                                 dst_len = 2;
1660                                 *ub = -1;
1661                                 normalize_function = IA5String_normalize;
1662                         } else {
1663                                 /* Unknown attributeType */
1664                                 strncpy(*dst, *src, len);
1665                                 dst_len = len;
1666                                 *ub = -1;
1667                                 normalize_function = NULL;
1668                         }
1669                         break;
1670
1671                 default:
1672                         /* Unknown attributeType */
1673                         strncpy(*dst, *src, len);
1674                         dst_len = len;
1675                                 *ub = -1;
1676                         normalize_function = NULL;
1677                         break;
1678         }
1679
1680         if (make_uppercase) {
1681                 for(i=0; i < dst_len; i++) {
1682                         **dst = TOUPPER( **dst );
1683                         *dst += 1;
1684                 }
1685         } else {
1686                 *dst += dst_len;
1687         }
1688         *src += len;
1689         return normalize_function;
1690 }
1691
1692
1693 /*
1694  * match_key - determine if the attribute type represented by the string
1695  * beginning at *src and of length len is a known attribute type. If so,
1696  * copy the string representation to *dst and return a pointer to the
1697  * normalization function for the attribute value. If the attribute type
1698  * places an upper bound on the length of the attribute value, make *ub that
1699  * upper bound, otherwise set *ub to -1.
1700  * If the attribute type is unknown, copy the string representation of the
1701  * attribute type to *dst and return NULL.
1702  */
1703 static av_normalize_type
1704 match_key(char **src, char **dst, int *ub, int len, int make_uppercase)
1705 {
1706         int i;
1707         int dst_len = 0;
1708         av_normalize_type normalize_function = NULL;
1709
1710         *ub = -1;
1711
1712         switch( len ) {
1713                 case 1:
1714                         if (strncasecmp(*src, "C", len) == 0) {
1715                                 /* country */
1716                                 **dst = 'c';
1717                                 dst_len = 1;
1718                                 *ub = 2;
1719                                 normalize_function = PrintableString_normalize;
1720                         } else if (strncasecmp(*src, "O", len) == 0) {
1721                                 /* organization */
1722                                 **dst = 'o';
1723                                 dst_len = 1;
1724                                 *ub = 64;
1725                                 normalize_function = DirectoryString_normalize;
1726                         } else if (strncasecmp(*src, "T", len) == 0) {
1727                                 /* title */
1728                                 strncpy(*dst, "title", 5);
1729                                 dst_len = 5;
1730                                 *ub = 64;
1731                                 normalize_function = DirectoryString_normalize;
1732                         } else if (strncasecmp(*src, "S", len) == 0) {
1733                                 /* state or province */
1734                                 strncpy(*dst, "st", 2);
1735                                 dst_len = 2;
1736                                 *ub = 128;
1737                                 normalize_function = DirectoryString_normalize;
1738                         } else if (strncasecmp(*src, "L", len) == 0) {
1739                                 /* locality */
1740                                 **dst = 'l';
1741                                 dst_len = 1;
1742                                 *ub = 128;
1743                                 normalize_function = DirectoryString_normalize;
1744                         } else if (strncasecmp(*src, "E", len) == 0) {
1745                                 /* e-mail */
1746                                 **dst = 'e';
1747                                 dst_len = 1;
1748                                 *ub = 255;
1749                                 normalize_function = IA5String_normalize;
1750                         } else {
1751                                 /* Unknown attributeType */
1752                                 strncpy(*dst, *src, len);
1753                                 dst_len = len;
1754                                 *ub = -1;
1755                                 normalize_function = NULL;
1756                         }
1757                         break;
1758
1759                 case 2:
1760                         if (strncasecmp(*src, "CN", len) == 0) {
1761                                 /* common name */
1762                                 strncpy(*dst, "cn", 2);
1763                                 dst_len = 2;
1764                                 *ub = 64;
1765                                 normalize_function = DirectoryString_normalize;
1766                         } else if (strncasecmp(*src, "OU", len) == 0) {
1767                                 /* organizational unit */
1768                                 strncpy(*dst, "ou", 2);
1769                                 dst_len = 2;
1770                                 *ub = 64;
1771                                 normalize_function = DirectoryString_normalize;
1772                         } else if (strncasecmp(*src, "DC", len) == 0) {
1773                                 /* domainComponent */
1774                                 strncpy(*dst, "dc", 2);
1775                                 dst_len = 2;
1776                                 *ub = -1;
1777                                 normalize_function = IA5String_normalize;
1778                         } else if (strncasecmp(*src, "SN", len) == 0) {
1779                                 /* surname */
1780                                 strncpy(*dst, "sn", 2);
1781                                 dst_len = 2;
1782                                 *ub = 64;
1783                                 normalize_function = DirectoryString_normalize;
1784                         } else if (strncasecmp(*src, "ST", len) == 0) {
1785                                 /* state or province */
1786                                 strncpy(*dst, "st", 2);
1787                                 dst_len = 2;
1788                                 *ub = 128;
1789                                 normalize_function = DirectoryString_normalize;
1790                         } else {
1791                                 /* Unknown attributeType */
1792                                 strncpy(*dst, *src, len);
1793                                 dst_len = len;
1794                                 *ub = -1;
1795                                 normalize_function = NULL;
1796                         }
1797                         break;
1798
1799                 case 3:
1800                         if (strncasecmp(*src, "SNU", len) == 0) {
1801                                 /* serial number */
1802                                 strncpy(*dst, "snu", 3);
1803                                 dst_len = 3;
1804                                 *ub = 64;
1805                                 normalize_function = PrintableString_normalize;
1806                         } else if (strncasecmp(*src, "UID", len) == 0) {
1807                                 /* userID */
1808                                 strncpy(*dst, "uid", 3);
1809                                 dst_len = 3;
1810                                 *ub = 256;
1811                                 normalize_function = DirectoryString_normalize;
1812                         } else {
1813                                 /* Unknown attributeType */
1814                                 strncpy(*dst, *src, len);
1815                                 dst_len = len;
1816                                 *ub = -1;
1817                                 normalize_function = NULL;
1818                         }
1819                         break;
1820
1821                 case 5:
1822                         if (strncasecmp(*src, "TITLE", len) == 0) {
1823                                 /* title */
1824                                 strncpy(*dst, "title", 5);
1825                                 dst_len = 5;
1826                                 *ub = 64;
1827                                 normalize_function = DirectoryString_normalize;
1828                         } else if (strncasecmp(*src, "STATE", len) == 0) {
1829                                 /* state or province */
1830                                 strncpy(*dst, "st", 2);
1831                                 dst_len = 2;
1832                                 *ub = 128;
1833                                 normalize_function = DirectoryString_normalize;
1834                         } else {
1835                                 /* Unknown attributeType */
1836                                 strncpy(*dst, *src, len);
1837                                 dst_len = len;
1838                                 *ub = -1;
1839                                 normalize_function = NULL;
1840                         }
1841                         break;
1842
1843                 case 6:
1844                         if (strncasecmp(*src, "USERID", len) == 0) {
1845                                 /* userID */
1846                                 strncpy(*dst, "uid", 3);
1847                                 dst_len = 3;
1848                                 *ub = 256;
1849                                 normalize_function = DirectoryString_normalize;
1850                         } else if (strncasecmp(*src, "STREET", len) == 0) {
1851                                 /* street address */
1852                                 strncpy(*dst, "street", 6);
1853                                 dst_len = 6;
1854                                 *ub = 128;
1855                                 normalize_function = DirectoryString_normalize;
1856                         } else {
1857                                 /* Unknown attributeType */
1858                                 strncpy(*dst, *src, len);
1859                                 dst_len = len;
1860                                 *ub = -1;
1861                                 normalize_function = NULL;
1862                         }
1863                         break;
1864
1865                 case 7:
1866                         if (strncasecmp(*src, "SURNAME", len) == 0) {
1867                                 /* surname */
1868                                 strncpy(*dst, "sn", 2);
1869                                 dst_len = 2;
1870                                 *ub = 64;
1871                                 normalize_function = DirectoryString_normalize;
1872                         } else {
1873                                 /* Unknown attributeType */
1874                                 strncpy(*dst, *src, len);
1875                                 dst_len = len;
1876                                 *ub = -1;
1877                                 normalize_function = NULL;
1878                         }
1879                         break;
1880
1881                 case 8:
1882                         if (strncasecmp(*src, "INITIALS", len) == 0) {
1883                                 /* initials */
1884                                 strncpy(*dst, "initials", 8);
1885                                 dst_len = 8;
1886                                 *ub = -1;
1887                                 normalize_function = DirectoryString_normalize;
1888                         } else if (strncasecmp(*src, "PROVINCE", len) == 0) {
1889                                 /* state or province */
1890                                 strncpy(*dst, "st", 2);
1891                                 dst_len = 2;
1892                                 *ub = 128;
1893                                 normalize_function = DirectoryString_normalize;
1894                         } else {
1895                                 /* Unknown attributeType */
1896                                 strncpy(*dst, *src, len);
1897                                 dst_len = len;
1898                                 *ub = -1;
1899                                 normalize_function = NULL;
1900                         }
1901                         break;
1902
1903                 case 9:
1904                         if (strncasecmp(*src, "GIVENNAME", len) == 0) {
1905                                 /* givenName */
1906                                 strncpy(*dst, "givenName", 9);
1907                                 dst_len = 9;
1908                                 *ub = -1;
1909                                 normalize_function = DirectoryString_normalize;
1910                         } else if (strncasecmp(*src, "PSEUDONYM", len) == 0) {
1911                                 /* Pseudonym */
1912                                 strncpy(*dst, "Pseudonym", 9);
1913                                 dst_len = 9;
1914                                 *ub = 64;
1915                                 normalize_function = DirectoryString_normalize;
1916                         } else {
1917                                 /* Unknown attributeType */
1918                                 strncpy(*dst, *src, len);
1919                                 dst_len = len;
1920                                 *ub = -1;
1921                                 normalize_function = NULL;
1922                         }
1923                         break;
1924
1925                 case 10:
1926                         if (strncasecmp(*src, "COMMONNAME", len) == 0) {
1927                                 /* common name */
1928                                 strncpy(*dst, "cn", 2);
1929                                 dst_len = 2;
1930                                 *ub = 64;
1931                                 normalize_function = DirectoryString_normalize;
1932                         } else {
1933                                 /* Unknown attributeType */
1934                                 strncpy(*dst, *src, len);
1935                                 dst_len = len;
1936                                 *ub = -1;
1937                                 normalize_function = NULL;
1938                         }
1939                         break;
1940
1941                 case 11:
1942                         if (strncasecmp(*src, "DNQUALIFIER", len) == 0) {
1943                                 /* Distinguished Name Quailifier */
1944                                 strncpy(*dst, "dnQualifier", 11);
1945                                 dst_len = 11;
1946                                 *ub = -1;
1947                                 normalize_function = DirectoryString_normalize;
1948                         } else if (strncasecmp(*src, "COUNTRYNAME", len) == 0) {
1949                                 /* country */
1950                                 **dst = 'c';
1951                                 dst_len = 1;
1952                                 *ub = 2;
1953                                 normalize_function = PrintableString_normalize;
1954                         } else {
1955                                 /* Unknown attributeType */
1956                                 strncpy(*dst, *src, len);
1957                                 dst_len = len;
1958                                 *ub = -1;
1959                                 normalize_function = NULL;
1960                         }
1961                         break;
1962                         
1963                 case 12:
1964                         if (strncasecmp(*src, "SERIALNUMBER", len) == 0) {
1965                                 /* serial number */
1966                                 strncpy(*dst, "snu", 3);
1967                                 dst_len = 3;
1968                                 *ub = 64;
1969                                 normalize_function = PrintableString_normalize;
1970                         } else if (strncasecmp(*src, "LOCALITYNAME", len) == 0) {
1971                                 /* locality */
1972                                 **dst = 'l';
1973                                 dst_len = 1;
1974                                 *ub = 128;
1975                                 normalize_function = DirectoryString_normalize;
1976                         } else if (strncasecmp(*src, "EMAILADDRESS", len) == 0) {
1977                                 /* e-mail */
1978                                 **dst = 'e';
1979                                 dst_len = 1;
1980                                 *ub = 255;
1981                                 normalize_function = IA5String_normalize;
1982                         } else {
1983                                 /* Unknown attributeType */
1984                                 strncpy(*dst, *src, len);
1985                                 dst_len = len;
1986                                 *ub = -1;
1987                                 normalize_function = NULL;
1988                         }
1989                         break;
1990                         
1991                 case 13:
1992                         if (strncasecmp(*src, "STREETADDRESS", len) == 0) {
1993                                 /* street address */
1994                                 strncpy(*dst, "street", 6);
1995                                 dst_len = 6;
1996                                 *ub = 128;
1997                                 normalize_function = DirectoryString_normalize;
1998                         } else {
1999                                 /* Unknown attributeType */
2000                                 strncpy(*dst, *src, len);
2001                                 dst_len = len;
2002                                 *ub = -1;
2003                                 normalize_function = NULL;
2004                         }
2005                         break;
2006                         
2007                 case 15:
2008                         if (strncasecmp(*src, "DOMAINCOMPONENT", len) == 0) {
2009                                 /* domainComponent */
2010                                 strncpy(*dst, "dc", 2);
2011                                 dst_len = 2;
2012                                 *ub = -1;
2013                                 normalize_function = IA5String_normalize;
2014                         } else {
2015                                 /* Unknown attributeType */
2016                                 strncpy(*dst, *src, len);
2017                                 dst_len = len;
2018                                 *ub = -1;
2019                                 normalize_function = NULL;
2020                         }
2021                         break;
2022
2023                 case 16:
2024                         if (strncasecmp(*src, "UNIQUEIDENTIFIER", len) == 0) {
2025                                 /* uniqueIdentifier */
2026                                 strncpy(*dst, "uniqueIdentifier", 16);
2027                                 dst_len = 16;
2028                                 *ub = -1;
2029                                 normalize_function = bitString_normalize;
2030                         } else if (strncasecmp(*src, "ORGANIZATIONNAME", len) == 0) {
2031                                 /* organization */
2032                                 **dst = 'o';
2033                                 dst_len = 1;
2034                                 *ub = 64;
2035                                 normalize_function = DirectoryString_normalize;
2036                         } else {
2037                                 /* Unknown attributeType */
2038                                 strncpy(*dst, *src, len);
2039                                 dst_len = len;
2040                                 *ub = -1;
2041                                 normalize_function = NULL;
2042                         }
2043                         break;
2044                         
2045                 case 17:
2046                         if (strncasecmp(*src, "NAMEDISTINGUISHER", len) == 0) {
2047                                 /* name distinguisher */
2048                                 strncpy(*dst, "nameDistinguisher", 17);
2049                                 dst_len = 17;
2050                                 *ub = -1;
2051                                 normalize_function = DirectoryString_normalize;
2052                         } else {
2053                                 /* Unknown attributeType */
2054                                 strncpy(*dst, *src, len);
2055                                 dst_len = len;
2056                                 *ub = -1;
2057                                 normalize_function = NULL;
2058                         }
2059                         break;
2060
2061                 case 19:
2062                         if (strncasecmp(*src, "GENERATIONQUALIFIER", len) == 0) {
2063                                 /* Distinguished Name Quailifier */
2064                                 strncpy(*dst, "generationQualifier", 19);
2065                                 dst_len = 19;
2066                                 *ub = -1;
2067                                 normalize_function = DirectoryString_normalize;
2068                         } else if (strncasecmp(*src, "STATEORPROVINCENAME", len) == 0) {
2069                                 /* state or province */
2070                                 strncpy(*dst, "st", 2);
2071                                 dst_len = 2;
2072                                 *ub = 128;
2073                                 normalize_function = DirectoryString_normalize;
2074                         } else {
2075                                 /* Unknown attributeType */
2076                                 strncpy(*dst, *src, len);
2077                                 dst_len = len;
2078                                 *ub = -1;
2079                                 normalize_function = NULL;
2080                         }
2081                         break;
2082                         
2083
2084                 case 22:
2085                         if (strncasecmp(*src, "ORGANIZATIONALUNITNAME", len) == 0) {
2086                                 /* organizational unit */
2087                                 strncpy(*dst, "ou", 2);
2088                                 dst_len = 2;
2089                                 *ub = 64;
2090                                 normalize_function = DirectoryString_normalize;
2091                         } else {
2092                                 /* Unknown attributeType */
2093                                 strncpy(*dst, *src, len);
2094                                 dst_len = len;
2095                                 *ub = -1;
2096                                 normalize_function = NULL;
2097                         }
2098                         break;
2099                         
2100                 default:
2101                         /* Unknown attributeType */
2102                         strncpy(*dst, *src, len);
2103                         dst_len = len;
2104                         *ub = -1;
2105                         normalize_function = NULL;
2106                         break;
2107         }
2108
2109         if (make_uppercase) {
2110                 for(i=0; i < dst_len; i++) {
2111                         **dst = TOUPPER( **dst );
2112                         *dst += 1;
2113                 }
2114         } else {
2115                 *dst += dst_len;
2116         }
2117         *src += len;
2118         return normalize_function;
2119 }
2120
2121
2122 static int
2123 get_validated_av_in_dn(char **s, char **d, int make_uppercase, int normalize, unsigned long *unnormalized_unicode) {
2124         char *i;
2125         int status, av_ub, len, av_length;
2126         av_normalize_type av_normalize;
2127
2128         /* First skip over any leading spaces */
2129         while ( ASCII_SPACE( **s ) )
2130                 *s += 1;
2131
2132         /* Next get the attribute type */
2133         if ( OID_LEADCHAR(**s) ) {
2134                 i = *s;
2135                 while ( *i != '\0' && OID_CHAR(*i) )
2136                         i++;
2137                 if ( *i == '\0' )
2138                         return 0;
2139
2140                 len = i - *s;
2141                 av_normalize = match_oid(s, d, &av_ub, len, make_uppercase);
2142         } else if ( DESC_LEADCHAR(**s) ) {
2143                 if ( TOUPPER ( **s ) == 'O' &&
2144                      TOUPPER ( *(*s+1) ) == 'I' &&
2145                      TOUPPER ( *(*s+2) ) == 'D' &&
2146                      *(*s+3) == '.' ) {
2147                         *s += 4;
2148                         if ( !OID_LEADCHAR(**s) )
2149                                 return 0;
2150
2151                         i = *s;
2152                         while ( *i != '\0' && OID_CHAR(*i) )
2153                                 i++;
2154                         if ( *i == '\0' )
2155                                 return 0;
2156
2157                         len = i - *s;
2158                         av_normalize = match_oid(s, d, &av_ub, len, make_uppercase);
2159                 } else {
2160                         i = *s;
2161                         while ( *i != '\0' && DESC_CHAR(*i) )
2162                                 i++;
2163                         if ( *i == '\0' )
2164                                 return 0;
2165
2166                         len = i - *s;
2167                         av_normalize = match_key(s, d, &av_ub, len, make_uppercase);
2168                 }
2169         } else {
2170                 return 0;
2171         }
2172
2173
2174         /* Next should be the equal sign */
2175
2176         while ( (**s != '=') && (**s != '\0') ) {
2177                 if ( !ASCII_SPACE(**s) )
2178                         return 0;
2179
2180                 *s += 1;
2181         }
2182
2183         if (**s != '=')
2184                 return 0;
2185
2186         *s += 1;
2187         **d = '=';
2188         *d += 1;
2189
2190         while ( ASCII_SPACE(**s) )
2191                 *s += 1;
2192
2193         /* The final part is the attribute value */
2194         if ( **s == '"' ) {
2195                 if (av_normalize == NULL) {
2196                         av_ub = -1;
2197                         av_normalize = DirectoryString_normalize;
2198                 }
2199                 status = (*av_normalize)(s, d, &av_length, make_uppercase, normalize, INQUOTEDVALUE, unnormalized_unicode);
2200                 if (status == 0)
2201                         return 0;
2202                 if ( ( av_ub != -1 ) && ( av_length > av_ub ) ) {
2203                         /* attribute value too long */
2204                         return 0;
2205                 }
2206         } else if ( **s == '#' ) {
2207                 if (av_normalize == NULL) {
2208                         /* Unknown attribute type. Since we don't know its string representation,
2209                          * just leave it as a BER encoded value.
2210                          */
2211                         **d = **s;
2212                         *s += 1; *d += 1;
2213                         av_length = 1;
2214                         while ( ASCII_XDIGIT(**s) ) {
2215                                 **d = TOUPPER(**s);
2216                                 *s += 1; *d += 1;
2217                                 av_length++;
2218                         }
2219
2220                         /* The length must be odd, since there must be an even number of
2221                          * hexadecimal charaters after the '#'.
2222                          */
2223                         if ( (av_length & 1) == 0)
2224                                 return 0;
2225                 } else {
2226                         status = (*av_normalize)(s, d, &av_length, make_uppercase, normalize, INBERENCODEDVALUE, unnormalized_unicode);
2227                         if (status == 0)
2228                                 return 0;
2229                         if ( ( av_ub != -1 ) && ( av_length > av_ub ) ) {
2230                                 /* attribute value too long */
2231                                 return 0;
2232                         }
2233                 }
2234         } else {
2235                 if (av_normalize == NULL) {
2236                         av_ub = -1;
2237                         av_normalize = DirectoryString_normalize;
2238                 }
2239                 status = (*av_normalize)(s, d, &av_length, make_uppercase, normalize, INVALUE, unnormalized_unicode);
2240                 if (status == 0)
2241                         return 0;
2242                 if ( ( av_ub != -1 ) && ( av_length > av_ub ) ) {
2243                         /* attribute value too long */
2244                         return 0;
2245                 }
2246         }
2247
2248         return 1;
2249 }
2250
2251 /* The string *s is a distinguished name encoded according to RFC 2253.
2252  * If the first RDN in *s is properly encoded, place in *d a normalized
2253  * version of the first RDN in *s, advance *d to the end of the normalized
2254  * RDN, advance *s to the end of the input string, and return 1.
2255  * If *s is not properly encoded, return 0.
2256  */
2257 static int
2258 get_validated_rdn_in_dn(char **s, char **d, int make_uppercase, int normalize, unsigned long *unnormalized_unicode) {
2259         char *av_pair[1001];    /* Assume there are less than 1000 attribute value pairs per RDN */
2260         int av_pair_len[1001];
2261         char *temp, *work_space;
2262         int i, j, num_av_pairs, status, state, len;
2263
2264         /* An RDN is a set of 1 or more attribute/value pairs. Get the first AV pair */
2265         av_pair[0] = *d;
2266         status = get_validated_av_in_dn(s, d, make_uppercase, normalize, unnormalized_unicode);
2267         if (status == 0)
2268                 return 0;
2269
2270         num_av_pairs = 1;
2271
2272         state = B4SEPARATOR;
2273
2274         while ( ASCII_SPACE( **s ) ) {
2275                 *s += 1;
2276         }
2277
2278         if ( **s != '+') {
2279                 /* This RDN contains only 1 attribute value pair */
2280                 return 1;
2281         }
2282
2283         /* Since RDNs with more than one attribute value pair are
2284          * rare, the above code was optimized for the case of an
2285          * RDN with only one AV pair. This RDN, however, contains
2286          * two or more AV pairs and they must be sorted to ensure
2287          * consistency when performing matches. The ordering does
2288          * not matter as long as it is consistent.
2289          */
2290
2291         /* Create temporary space to hold the AV pairs before sorting */
2292         **d = '\0';
2293
2294         /* Compute the length of the first AV pair */
2295         av_pair_len[0] = *d - av_pair[0];
2296
2297         work_space = (char *)ch_malloc(4 * strlen( *s ) + av_pair_len[0] + 1000);
2298
2299         /* Move *d back so that the whole RDN can be written in the proper order */
2300         *d = av_pair[0];
2301
2302         av_pair[0] = work_space;
2303         bcopy(*d, av_pair[0], av_pair_len[0]+1);
2304
2305         av_pair[1] = av_pair[0] + av_pair_len[0] + 1;
2306         while ( (num_av_pairs < 1000) && (**s != ',') && (**s != ';') && (**s != '\0') ) {
2307                 if ( **s != '+' ) {
2308                         ch_free(work_space);
2309                         return 0;
2310                 }
2311                 *s += 1;
2312                         
2313                 temp = av_pair[num_av_pairs];
2314                 status = get_validated_av_in_dn(s, &temp, make_uppercase, normalize, unnormalized_unicode);
2315                 if (status == 0) {
2316                         ch_free(work_space);
2317                         return 0;
2318                 }
2319                 av_pair_len[num_av_pairs] = temp - av_pair[num_av_pairs];
2320
2321                 *temp++ = '\0';
2322                 num_av_pairs++;
2323                 av_pair[num_av_pairs] = temp;
2324
2325                 while ( ASCII_SPACE(**s) )
2326                         *s += 1;
2327         }
2328
2329         if (num_av_pairs == 1000) {
2330                 ch_free(work_space);
2331                 return 0;
2332         }
2333
2334         if ( normalize ) {
2335                 /* Sort the AV pairs. Since the number of AV pairs in an RDN should always
2336                  * be very small, bubblesort is used.
2337                  */
2338                 for(i = 0; i < num_av_pairs; i++) {
2339                         for(j = 1; j < num_av_pairs; j++) {
2340                                 if (strcasecmp(av_pair[j-1], av_pair[j]) > 0) {
2341                                         temp = av_pair[j-1];
2342                                         av_pair[j-1] = av_pair[j];
2343                                         av_pair[j] = temp;
2344
2345                                         len = av_pair_len[j-1];
2346                                         av_pair_len[j-1] = av_pair_len[j];
2347                                         av_pair_len[j] = len;
2348                                 }
2349                         }
2350                 }
2351         }
2352
2353         /* place the AV pairs in *d, separated by commas */
2354         for(i=0; i < num_av_pairs; i++) {
2355                 bcopy(av_pair[i], *d, av_pair_len[i]);
2356                 *d += av_pair_len[i];
2357                 **d = '+';
2358                 *d += 1;
2359         }
2360         *d -= 1;
2361
2362         ch_free(work_space);
2363
2364         return 1;
2365 }
2366
2367 /* The string dn is a distinguished name encoded according to RFC 2253.
2368  * If dn is properly encoded, return a normalized version of the string.
2369  * If not, return NULL. If make_uppercase is 0, do not change the case of
2370  * characters in attribute values, otherwise make all characters in attribute
2371  * values uppercase. If normalize is 0, do not compress whitespace
2372  * within attribute values, otherwise remove any leading and trailing
2373  * whitespace characters from attribute values and replace any strings of
2374  * whitespace characters between "words" with a single space character.
2375  */
2376 char *
2377 get_validated_dn( char *dn, int make_uppercase, int normalize)
2378 {
2379         char *ret_val, *s, *d;
2380         unsigned long *unnormalized_unicode;
2381         int dn_len, status, state;
2382
2383         state = B4LEADTYPE;
2384
2385         dn_len = strlen(dn);
2386         d = ret_val = (char *)ch_malloc(4 * dn_len + 1);
2387         s = dn;
2388
2389         /* Create temporary workspace to hold unicode characters before
2390          * they have been normalized.
2391          */
2392         if ( normalize )
2393                 unnormalized_unicode = (unsigned long *)ch_malloc(dn_len * sizeof(unsigned long));
2394         else
2395                 unnormalized_unicode = NULL;
2396
2397         /* A DN consists of a sequence of 0 or more RDNs */
2398
2399         while ( ret_val != NULL && *s != '\0' ) {
2400                 if ( ASCII_SPACE( *s ) ) {
2401                         s++;
2402                 } else if ( (state == B4SEPARATOR) && ( (*s == ',') || (*s == ';') ) ) {
2403                         *d++ = ',';
2404                         s++;
2405                         state = B4VALUE;
2406                 } else {
2407                         status = get_validated_rdn_in_dn(&s, &d, make_uppercase, normalize, unnormalized_unicode);
2408                         if (status == 0) {
2409                                 /* not a valid RDN */
2410                                 ch_free(ret_val);
2411                                 ret_val = NULL;
2412                         }
2413                         state = B4SEPARATOR;
2414                 }
2415         }
2416
2417         if (state == B4VALUE) {
2418                 /* not a valid DN */
2419                 ch_free(ret_val);
2420                 ret_val = NULL;
2421         }
2422
2423         *d = '\0';
2424         return ret_val;
2425 }
2426
2427 /*
2428  * dn_validate - validate and compress dn.  the dn is
2429  * compressed in place are returned if valid.
2430  */
2431
2432 char *
2433 dn_validate( char *dn_in )
2434 {
2435         char *dn_out;
2436         int len;
2437  
2438         len = strlen(dn_in);
2439  
2440         if (len != 0) {
2441                 dn_out = get_validated_dn(dn_in, 0, 0);
2442                 if (dn_out == NULL) {
2443                         return NULL;
2444                 } else if (strlen(dn_out) <= len) {
2445                         strcpy(dn_in, dn_out);
2446                         ch_free(dn_out);
2447                 } else {
2448                         ch_free(dn_out);
2449                         return NULL;
2450                 }
2451         }
2452         return( dn_in );
2453 }
2454
2455 /*
2456  * dn_normalize - put dn into a canonical form suitable for storing
2457  * in a hash database.  this involves normalizing the case as well as
2458  * the format.  the dn is normalized in place as well as returned if valid.
2459  */
2460
2461 char *
2462 dn_normalize( char *dn )
2463 {
2464         char *dn_out;
2465         int len;
2466  
2467         len = strlen(dn);
2468  
2469         if (len != 0) {
2470                 dn_out = get_validated_dn(dn, 1, 1);
2471                 if (dn_out == NULL) {
2472                         return NULL;
2473                 } else if (strlen(dn_out) <= len) {
2474                         strcpy(dn, dn_out);
2475                         ch_free(dn_out);
2476                 } else {
2477                         ch_free(dn_out);
2478                         return NULL;
2479                 }
2480         }
2481         return( dn );
2482 }
2483
2484 /*
2485  * dn_parent - return a copy of the dn of dn's parent
2486  */
2487
2488 char *
2489 dn_parent(
2490     Backend     *be,
2491     const char  *dn
2492 )
2493 {
2494         const char      *s;
2495         int     inquote;
2496
2497         if( dn == NULL ) {
2498                 return NULL;
2499         }
2500
2501         while(*dn != '\0' && ASCII_SPACE(*dn)) {
2502                 dn++;
2503         }
2504
2505         if( *dn == '\0' ) {
2506                 return NULL;
2507         }
2508
2509         if ( be != NULL && be_issuffix( be, dn ) ) {
2510                 return NULL;
2511         }
2512
2513         /*
2514          * assume it is an X.500-style name, which looks like
2515          * foo=bar,sha=baz,...
2516          */
2517
2518         inquote = 0;
2519         for ( s = dn; *s; s++ ) {
2520                 if ( *s == '\\' ) {
2521                         if ( *(s + 1) ) {
2522                                 s++;
2523                         }
2524                         continue;
2525                 }
2526                 if ( inquote ) {
2527                         if ( *s == '"' ) {
2528                                 inquote = 0;
2529                         }
2530                 } else {
2531                         if ( *s == '"' ) {
2532                                 inquote = 1;
2533                         } else if ( DN_SEPARATOR( *s ) ) {
2534                                 return ch_strdup( &s[1] );
2535                         }
2536                 }
2537         }
2538
2539         return ch_strdup( "" );
2540 }
2541
2542 char * dn_rdn( 
2543     Backend     *be,
2544     const char  *dn_in )
2545 {
2546         char    *dn, *s;
2547         int     inquote;
2548
2549         if( dn_in == NULL ) {
2550                 return NULL;
2551         }
2552
2553         while(*dn_in && ASCII_SPACE(*dn_in)) {
2554                 dn_in++;
2555         }
2556
2557         if( *dn_in == '\0' ) {
2558                 return( NULL );
2559         }
2560
2561         if ( be != NULL && be_issuffix( be, dn_in ) ) {
2562                 return( NULL );
2563         }
2564
2565         dn = ch_strdup( dn_in );
2566
2567         inquote = 0;
2568
2569         for ( s = dn; *s; s++ ) {
2570                 if ( *s == '\\' ) {
2571                         if ( *(s + 1) ) {
2572                                 s++;
2573                         }
2574                         continue;
2575                 }
2576                 if ( inquote ) {
2577                         if ( *s == '"' ) {
2578                                 inquote = 0;
2579                         }
2580                 } else {
2581                         if ( *s == '"' ) {
2582                                 inquote = 1;
2583                         } else if ( DN_SEPARATOR( *s ) ) {
2584                                 *s = '\0';
2585                                 return( dn );
2586                         }
2587                 }
2588         }
2589
2590         return( dn );
2591 }
2592
2593
2594 /*
2595  * return a charray of all subtrees to which the DN resides in
2596  */
2597 char **dn_subtree(
2598         Backend *be,
2599     const char  *dn )
2600 {
2601         char *child, *parent;
2602         char **subtree = NULL;
2603         
2604         child = ch_strdup( dn );
2605
2606         do {
2607                 charray_add( &subtree, child );
2608
2609                 parent = dn_parent( be, child );
2610
2611                 free( child );
2612
2613                 child = parent;
2614         } while ( child != NULL );
2615
2616         return subtree;
2617 }
2618
2619
2620 /*
2621  * dn_issuffix - tells whether suffix is a suffix of dn.  both dn
2622  * and suffix must be normalized.
2623  */
2624
2625 int
2626 dn_issuffix(
2627     const char  *dn,
2628     const char  *suffix
2629 )
2630 {
2631         int     dnlen, suffixlen;
2632
2633         if ( dn == NULL ) {
2634                 return( 0 );
2635         }
2636
2637         suffixlen = strlen( suffix );
2638         dnlen = strlen( dn );
2639
2640         if ( suffixlen > dnlen ) {
2641                 return( 0 );
2642         }
2643
2644         return( strcmp( dn + dnlen - suffixlen, suffix ) == 0 );
2645 }
2646
2647 /*
2648  * get_next_substring(), rdn_attr_type(), rdn_attr_value(), and
2649  * build_new_dn().
2650  * 
2651  * Copyright 1999, Juan C. Gomez, All rights reserved.
2652  * This software is not subject to any license of Silicon Graphics 
2653  * Inc. or Purdue University.
2654  *
2655  * Redistribution and use in source and binary forms are permitted
2656  * without restriction or fee of any kind as long as this notice
2657  * is preserved.
2658  *
2659  */
2660
2661 /* get_next_substring:
2662  *
2663  * Gets next substring in s, using d (or the end of the string '\0') as a 
2664  * string delimiter, and places it in a duplicated memory space. Leading 
2665  * spaces are ignored. String s **must** be null-terminated.
2666  */ 
2667
2668 static char * 
2669 get_next_substring( const char * s, char d )
2670 {
2671
2672         char    *str, *r;
2673
2674         r = str = ch_malloc( strlen(s) + 1 );
2675
2676         /* Skip leading spaces */
2677         
2678         while ( *s && ASCII_SPACE(*s) ) {
2679                 s++;
2680         }
2681         
2682         /* Copy word */
2683
2684         while ( *s && (*s != d) ) {
2685
2686                 /* Don't stop when you see trailing spaces may be a multi-word
2687                 * string, i.e. name=John Doe!
2688                 */
2689
2690                 *str++ = *s++;
2691             
2692         }
2693         
2694         *str = '\0';
2695         
2696         return r;
2697         
2698 }
2699
2700
2701 /* rdn_attr_type:
2702  *
2703  * Given a string (i.e. an rdn) of the form:
2704  *       "attribute_type = attribute_value"
2705  * this function returns the type of an attribute, that is the 
2706  * string "attribute_type" which is placed in newly allocated 
2707  * memory. The returned string will be null-terminated.
2708  */
2709
2710 char * rdn_attr_type( const char * s )
2711 {
2712         return get_next_substring( s, '=' );
2713 }
2714
2715
2716 /* rdn_attr_value:
2717  *
2718  * Given a string (i.e. an rdn) of the form:
2719  *       "attribute_type = attribute_value"
2720  * this function returns "attribute_type" which is placed in newly allocated 
2721  * memory. The returned string will be null-terminated and may contain 
2722  * spaces (i.e. "John Doe\0").
2723  */
2724
2725 char * 
2726 rdn_attr_value( const char * rdn )
2727 {
2728
2729         const char      *str;
2730
2731         if ( (str = strchr( rdn, '=' )) != NULL ) {
2732                 return get_next_substring(++str, '\0');
2733         }
2734
2735         return NULL;
2736
2737 }
2738
2739
2740 /* rdn_attrs:
2741  *
2742  * Given a string (i.e. an rdn) of the form:
2743  *       "attribute_type=attribute_value[+attribute_type=attribute_value[...]]"
2744  * this function stores the types of the attributes in ptypes, that is the 
2745  * array of strings "attribute_type" which is placed in newly allocated 
2746  * memory, and the values of the attributes in pvalues, that is the
2747  * array of strings "attribute_value" which is placed in newly allocated
2748  * memory. Returns 0 on success, -1 on failure.
2749  *
2750  * note: got part of the code from dn_validate
2751  */
2752
2753 int
2754 rdn_attrs( const char * rdn_in, char ***ptypes, char ***pvalues)
2755 {
2756         char **parts, **p;
2757
2758         *ptypes = NULL;
2759         *pvalues = NULL;
2760
2761         /*
2762          * explode the rdn in parts
2763          */
2764         parts = ldap_explode_rdn( rdn_in, 0 );
2765
2766         if ( parts == NULL ) {
2767                 return( -1 );
2768         }
2769
2770         for ( p = parts; p[0]; p++ ) {
2771                 char *s, *e, *d;
2772                 
2773                 /* split each rdn part in type value */
2774                 s = strchr( p[0], '=' );
2775                 if ( s == NULL ) {
2776                         charray_free( *ptypes );
2777                         charray_free( *pvalues );
2778                         charray_free( parts );
2779                         return( -1 );
2780                 }
2781                 
2782                 /* type should be fine */
2783                 charray_add_n( ptypes, p[0], ( s-p[0] ) );
2784
2785                 /* value needs to be unescaped 
2786                  * (maybe this should be moved to ldap_explode_rdn?) */
2787                 for ( e = d = s + 1; e[0]; e++ ) {
2788                         if ( *e != '\\' ) {
2789                                 *d++ = *e;
2790                         }
2791                 }
2792                 d[0] = '\0';
2793                 charray_add( pvalues, s + 1 );
2794         }
2795
2796         /* free array */
2797         charray_free( parts );
2798
2799         return( 0 );
2800 }
2801
2802
2803 /* rdn_validate:
2804  * 
2805  * 1 if rdn is a legal rdn; 
2806  * 0 otherwise (including a sequence of rdns)
2807  *
2808  * note: got it from dn_rdn; it should be rewritten 
2809  * according to dn_validate
2810  */
2811 int
2812 rdn_validate( const char * rdn )
2813 {
2814         int     inquote;
2815
2816         if ( rdn == NULL ) {
2817                 return( 0 );
2818         }
2819
2820         if ( strchr( rdn, '=' ) == NULL ) {
2821                 return( 0 );
2822         }
2823
2824         while ( *rdn && ASCII_SPACE( *rdn ) ) {
2825                 rdn++;
2826         }
2827
2828         if( *rdn == '\0' ) {
2829                 return( 0 );
2830         }
2831
2832         inquote = 0;
2833
2834         for ( ; *rdn; rdn++ ) {
2835                 if ( *rdn == '\\' ) {
2836                         if ( *(rdn + 1) ) {
2837                                 rdn++;
2838                         }
2839                         continue;
2840                 }
2841                 if ( inquote ) {
2842                         if ( *rdn == '"' ) {
2843                                 inquote = 0;
2844                         }
2845                 } else {
2846                         if ( *rdn == '"' ) {
2847                                 inquote = 1;
2848                         } else if ( DN_SEPARATOR( *rdn ) ) {
2849                                 return( 0 );
2850                         }
2851                 }
2852         }
2853
2854         return( 1 );
2855 }
2856
2857
2858 /* build_new_dn:
2859  *
2860  * Used by ldbm/bdb2_back_modrdn to create the new dn of entries being
2861  * renamed.
2862  *
2863  * new_dn = parent (p_dn)  + separator(s) + rdn (newrdn) + null.
2864  */
2865
2866 void
2867 build_new_dn( char ** new_dn,
2868         const char *e_dn,
2869         const char * p_dn,
2870         const char * newrdn )
2871 {
2872
2873     if ( p_dn == NULL ) {
2874         *new_dn = ch_strdup( newrdn );
2875         return;
2876     }
2877     
2878     *new_dn = (char *) ch_malloc( strlen( p_dn ) + strlen( newrdn ) + 3 );
2879
2880         strcpy( *new_dn, newrdn );
2881         strcat( *new_dn, "," );
2882         strcat( *new_dn, p_dn );
2883 }