]> git.sur5r.net Git - openldap/blob - servers/ldapd/syntax.c
005fb78d6bb2336e4c9f206ddde407e32433fb19
[openldap] / servers / ldapd / syntax.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright (c) 1990 Regents of the University of Michigan.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms are permitted
7  * provided that this notice is preserved and that due credit is given
8  * to the University of Michigan at Ann Arbor. The name of the University
9  * may not be used to endorse or promote products derived from this
10  * software without specific prior written permission. This software
11  * is provided ``as is'' without express or implied warranty.
12  */
13
14 #include "portable.h"
15
16 #include <stdio.h>
17
18 #include <ac/ctype.h>
19 #include <ac/socket.h>
20 #include <ac/string.h>
21
22 #include <quipu/commonarg.h>
23 #include <quipu/attrvalue.h>
24 #include <quipu/ds_error.h>
25 #include <quipu/ds_search.h>
26 #include <quipu/dap2.h>
27 #include <quipu/dua.h>
28 extern oid_table_attr *name2attr( char * );
29 /*extern AttributeValue str_at2AttrV( char *, IF_AttributeType * );*/
30
31 #include "lber.h"
32 #include "../../libraries/liblber/lber-int.h"   /* get struct berelement */
33 #include "ldap.h"
34 #include "common.h"
35
36 short   ldap_photo_syntax;
37 short   ldap_jpeg_syntax;
38 short   ldap_jpeg_nonfile_syntax;
39 short   ldap_audio_syntax;
40 short   ldap_dn_syntax;
41 short   ldap_postaladdress_syntax;
42 short   ldap_acl_syntax;
43 short   ldap_mtai_syntax;
44 short   ldap_rts_cred_syntax;
45 short   ldap_rtl_syntax;
46 short   ldap_mailbox_syntax;
47 short   ldap_caseignorelist_syntax;
48 short   ldap_caseexactstring_syntax;
49 short   ldap_certif_syntax;
50 short   ldap_iattr_syntax;
51 short   ldap_telex_syntax;
52 short   ldap_octetstring_syntax;
53 short   ldap_deliverymethod_syntax;
54 short   ldap_facsimileTelephoneNumber_syntax;
55 short   ldap_presentationAddress_syntax;
56 short   ldap_teletexTerminalIdentifier_syntax;
57 short   ldap_searchGuide_syntax;
58 short   ldap_dLSubmitPermission_syntax;
59
60 static void     de_t61( char *s, int t61mark );
61 static int      syntax_is_string( short syntax );
62
63 static int
64 get_one_syntax( char *attrib, int required )
65 {
66         oid_table_attr  *p;
67
68         if ( (p = name2attr( attrib )) != (oid_table_attr *) 0 )
69             return( p->oa_syntax );
70
71         if ( !required )
72             return( -1 );
73
74         Debug( LDAP_DEBUG_ANY, "name2attr (%s) failed - exiting\n", attrib,
75             0, 0 );
76
77         log_and_exit( 1 );
78 }
79
80 void
81 get_syntaxes( void )
82 {
83         Debug( LDAP_DEBUG_TRACE, "get_syntaxes\n", 0, 0, 0 );
84
85         ldap_photo_syntax = get_one_syntax( "photo", 0 );
86         ldap_jpeg_syntax = get_one_syntax( "jpegPhoto", 0 );
87         ldap_jpeg_nonfile_syntax = str2syntax( "jpeg" );
88         ldap_audio_syntax = get_one_syntax( "audio", 0 );
89         ldap_postaladdress_syntax = get_one_syntax( "postaladdress", 0 );
90         ldap_dn_syntax = get_one_syntax( "aliasedObjectName", 1 );
91         ldap_acl_syntax = get_one_syntax( "acl", 0 );
92         ldap_mtai_syntax = get_one_syntax( "mTAInfo", 0 );
93         ldap_rts_cred_syntax= get_one_syntax( "initiatingRTSCredentials", 0 );
94         ldap_rtl_syntax= get_one_syntax( "routingTreeList", 0 );
95         ldap_mailbox_syntax = get_one_syntax( "otherMailbox", 0 );
96         ldap_caseignorelist_syntax = str2syntax( "CaseIgnoreList" );
97         ldap_caseexactstring_syntax = str2syntax( "caseexactstring" );
98         ldap_octetstring_syntax = str2syntax( "OctetString" );
99         ldap_deliverymethod_syntax = str2syntax( "DeliveryMethod" );
100         ldap_iattr_syntax = get_one_syntax( "inheritedAttribute", 0 );
101         ldap_certif_syntax = get_one_syntax( "userCertificate", 0 );
102         ldap_telex_syntax = get_one_syntax( "telexNumber", 0 );
103         ldap_facsimileTelephoneNumber_syntax =
104             get_one_syntax( "facsimileTelephoneNumber", 0 );
105         ldap_presentationAddress_syntax =
106             get_one_syntax( "presentationAddress", 0 );
107         ldap_teletexTerminalIdentifier_syntax =
108             get_one_syntax( "teletexTerminalIdentifier", 0 );
109         ldap_searchGuide_syntax = get_one_syntax( "searchGuide", 0 );
110         ldap_dLSubmitPermission_syntax =
111             get_one_syntax( "mhsDLSubmitPermissions", 0 );
112
113         certif_init();  /* initialize certificate syntax handler */
114 }
115
116 /*
117  *  From RFC 1779 "A String Representation of Distinguished Names"
118  *
119  *                       Key     Attribute (X.520 keys)
120  *                       ------------------------------
121  *                       CN      CommonName
122  *                       L       LocalityName
123  *                       ST      StateOrProvinceName
124  *                       O       OrganizationName
125  *                       OU      OrganizationalUnitName
126  *                       C       CountryName
127  *                       STREET  StreetAddress
128  *
129  *
130  *                      Table 1:  Standardised Keywords
131  *
132  *   There is an escape mechanism from the normal user oriented form, so
133  *   that this syntax may be used to print any valid distinguished name.
134  *
135  *   1.  Attributes types are represented in a (big-endian) dotted
136  *       notation.  (e.g., OID.2.6.53).
137  *
138  */
139 static void
140 attr_key_rfc1779(
141     AttributeType   at,
142     char            *key    /* return key, caller allocated */
143 )
144 {
145     char    *x;
146
147     x = attr2name_aux ( at );
148
149     if ( x == NULL ) {
150         x = "?";
151     } else if ( isdigit ( (unsigned char) *x ) ) {
152         sprintf ( key, "OID.%s", x );
153         return;
154     } else if (strcasecmp(x,"commonName")==0) {
155         x = "CN";
156     } else if (strcasecmp(x,"localityName")==0) {
157         x = "l";
158     } else if (strcasecmp(x,"stateOrProvinceName")==0) {
159         x = "st";
160     } else if (strcasecmp(x,"organizationName")==0) {
161         x = "o";
162     } else if (strcasecmp(x,"organizationalUnitName")==0) {
163         x = "ou";
164     } else if (strcasecmp(x,"countryName")==0) {
165         x = "c";
166     } else if (strcasecmp(x,"streetAddress")==0) {
167         x = "street";
168     }
169
170     strcpy ( key, x );
171 }
172
173 #define SEPARATOR(c)    ((c) == ',' || (c) == ';')
174 #define SPACE(c)        ((c) == ' ' || (c) == '\n')
175
176 int
177 dn_print_real(
178     PS  ps,
179     DN  dn,
180     int format
181 )
182 {
183         RDN     rdn;
184         int     firstrdn;
185         char    *value;
186         PS      rps;
187         char    key[512];
188
189         if ( dn == NULLDN )
190                 return( 0 );
191
192         if ( dn->dn_parent != NULLDN ) {
193                 dn_print_real( ps, dn->dn_parent, format );
194                 ps_print( ps, ", " );
195         }
196
197         if ( (rps = ps_alloc( str_open )) == NULLPS )
198                 return( -1 );
199         if ( str_setup( rps, NULLCP, 0, 0 ) == NOTOK )
200                 return( -1 );
201
202         firstrdn = 1;
203         for ( rdn = dn->dn_rdn; rdn != NULLRDN; rdn = rdn->rdn_next ) {
204                 if ( firstrdn )
205                         firstrdn = 0;
206                 else
207                         ps_print( ps, " + " );
208
209                 attr_key_rfc1779 ( rdn->rdn_at, key );
210
211                 ps_print ( ps, key );
212                 ps_print( ps, "=" );
213
214                 if ( rdn->rdn_at->oa_syntax == ldap_dn_syntax ) {
215                         dn_print_real( rps, (DN) rdn->rdn_av.av_struct,
216                             format );
217                         *rps->ps_ptr = '\0';
218                         value = rps->ps_base;
219                 } else {
220                         AttrV_print( rps, &rdn->rdn_av, EDBOUT );
221                         *rps->ps_ptr = '\0';
222                         if ( rps->ps_ptr - rps->ps_base >= 5 &&
223                             strncmp( rps->ps_base, "{ASN}", 5 ) == 0 ) {
224                                 *rps->ps_base = '#';
225                                 SAFEMEMCPY( rps->ps_base + 1, rps->ps_base + 5,
226                                         rps->ps_ptr - rps->ps_base - 4 );
227                         }
228                         value = rps->ps_base;
229                         de_t61( value, 0 );
230                 }
231
232                 /*
233                  * ,+="\\\n all go in quotes.  " and \\ need to
234                  * be preceeded by \\.
235                  */
236
237                 if ( strpbrk( value, ",+=\"\\\n" ) != NULL || SPACE( value[0] )
238                     || SPACE( value[max( strlen(value) - 1, (size_t) 0 )] ) ) {
239                         char    *p, *t, *tmp;
240                         int     specialcount;
241
242                         ps_print( ps, "\"" );
243
244                         specialcount = 0;
245                         for ( p = value; *p != '\0'; p++ ) {
246                                 if ( *p == '"' || *p == '\\' ) {
247                                         specialcount++;
248                                 }
249                         }
250                         if ( specialcount > 0 ) {
251                                 tmp = smalloc( strlen( value ) + specialcount
252                                     + 1 );
253                                 for ( p = value, t = tmp; *p != '\0'; p++ ) {
254                                         switch ( *p ) {
255                                         case '"':
256                                         case '\\':
257                                                 *t++ = '\\';
258                                                 /* FALL THROUGH */
259                                         default:
260                                                 *t++ = *p;
261                                         }
262                                 }
263                                 *t = '\0';
264                                 ps_print( ps, tmp );
265                                 free( tmp );
266                         } else {
267                                 ps_print( ps, value );
268                         }
269
270                         ps_print( ps, "\"" );
271                 } else {
272                         ps_print( ps, value );
273                 }
274
275                 rps->ps_ptr = rps->ps_base;
276         }
277
278         ps_free( rps );
279
280         return( 0 );
281 }
282
283 void
284 ldap_dn_print(
285     PS  ps,
286     DN  dn,
287     DN  base,   /* if non-NULL, subsitute '*' for base (for CLDAP) */
288     int format
289 )
290 {
291         DN      tmpdn;
292         int     addstar;
293
294         Debug( LDAP_DEBUG_TRACE, "ldap_dn_print\n", 0, 0, 0 );
295
296         addstar = 0;
297         if ( base != NULLDN && dn != NULL ) {
298                 for ( tmpdn = dn; base != NULLDN && tmpdn != NULLDN;
299                     base = base->dn_parent, tmpdn = tmpdn->dn_parent ) {
300                         if ( dn_comp_cmp( base, tmpdn ) == NOTOK ) {
301                                 break;
302                         }
303                 }
304                 if (( addstar = ( base == NULLDN && tmpdn != NULL ))) {
305                         dn = tmpdn;
306                 }
307         }
308
309         dn_print_real( ps, dn, format );
310         if ( addstar ) {
311             ps_print( ps, ", *" );
312         }
313 }
314
315 int
316 encode_dn(
317     BerElement  *ber,
318     DN          dn,
319     DN          base    /* if non-NULL, subsitute '*' for base (for CLDAP) */
320 )
321 {
322         PS      ps;
323         int     rc;
324
325         Debug( LDAP_DEBUG_TRACE, "encode_dn\n", 0, 0, 0 );
326
327         if ( (ps = ps_alloc( str_open )) == NULLPS )
328                 return( -1 );
329         if ( str_setup( ps, NULLCP, 0, 0 ) == NOTOK )
330                 return( -1 );
331
332         ldap_dn_print( ps, dn, base, EDBOUT );
333         *ps->ps_ptr = '\0';
334
335         rc = ber_printf( ber, "s", ps->ps_base );
336
337         ps_free( ps );
338
339         return( rc );
340 }
341
342 static int
343 put_jpeg_value( BerElement *ber, AttributeValue av )
344 {
345         PE      pe;
346         int     len;
347
348         Debug( LDAP_DEBUG_TRACE, "put_jpeg_value\n", 0, 0, 0 );
349
350         if (av->av_syntax == AV_FILE)
351                 pe = (PE) (((struct file_syntax *) av->av_struct)->
352                     fs_attr->av_struct);
353         else
354                 pe = (PE) av->av_struct;
355
356         Debug( LDAP_DEBUG_ARGS,
357             "put_jpeg_value: pe_class %x, pe_form %x, pe_id %x\n",
358             pe->pe_class, pe->pe_form, pe->pe_id );
359
360         if ( (pe->pe_class != PE_CLASS_UNIV && pe->pe_class != PE_CLASS_CONT)
361             || pe->pe_form != PE_FORM_PRIM || pe->pe_id != PE_PRIM_OCTS ) {
362                 Debug( LDAP_DEBUG_ANY, "put_jpeg_value: unknown type\n", 0,
363                     0, 0 );
364                 return( -1 );
365         }
366
367         if ( pe_pullup( pe ) == NOTOK ) {
368                 Debug( LDAP_DEBUG_ANY, "put_jpeg_value: cannot pullup\n", 0,
369                     0, 0 );
370                 return( -1 );
371         }
372
373         len = ps_get_abs( pe );
374
375         Debug( LDAP_DEBUG_ARGS, "put_jeg_value: ber_printf %d bytes\n",
376             len, 0, 0 );
377         if ( ber_printf( ber, "o", (char *) pe->pe_prim, len ) == -1 ) {
378                 Debug( LDAP_DEBUG_ANY, "put_jpeg_value: ber_printf failed\n",
379                     0, 0, 0 );
380                 return( -1 );
381         }
382
383         return( 0 );
384 }
385
386 static int
387 put_audio_value( BerElement *ber, AttributeValue av )
388 {
389         struct qbuf     *qb, *p;
390         int             rc, len;
391         char            *buf;
392
393         Debug( LDAP_DEBUG_TRACE, "put_audio_value\n", 0, 0, 0 );
394
395         qb = (struct qbuf *) (((struct file_syntax *)
396             av->av_struct)->fs_attr->av_struct);
397
398         len = 0;
399         for ( p = qb->qb_forw; p != qb; p = p->qb_forw ) {
400                 len += p->qb_len;
401         }
402
403         if ( (buf = (char *) malloc( len )) == NULL )
404                 return( -1 );
405
406         len = 0;
407         for ( p = qb->qb_forw; p != qb; p = p->qb_forw ) {
408                 SAFEMEMCPY( buf + len, p->qb_data, p->qb_len );
409                 len += p->qb_len;
410         }
411
412         Debug( LDAP_DEBUG_ARGS, "put_audio_value: ber_printf %d bytes\n",
413             len, 0, 0 );
414
415         if ( (rc = ber_printf( ber, "o", buf, len )) == -1 )
416                 Debug( LDAP_DEBUG_ANY, "put_audio_value: ber_printf failed\n",
417                     0, 0, 0 );
418
419         free( buf );
420
421         return( rc );
422 }
423
424 static int
425 put_photo_value( BerElement *ber, AttributeValue av )
426 {
427         PE              pe;
428         PS              ps;
429         int             len;
430         char            *faxparamset = "\000\300\000\000";
431         BerElement      *phber;
432
433         Debug( LDAP_DEBUG_TRACE, "put_photo_value\n", 0, 0, 0 );
434
435         pe = (PE) (((struct file_syntax *) av->av_struct)->fs_attr->av_struct);
436
437         /* old bit string-like format - only handle this for now */
438         if ( pe->pe_class == PE_CLASS_UNIV && pe->pe_form == PE_FORM_PRIM
439             && pe->pe_id == PE_PRIM_BITS ) {
440                 len = ps_get_abs( pe );
441                 Debug( LDAP_DEBUG_ARGS, "put_photo_val: ber_printf %d bytes\n",
442                     len, 0, 0 );
443                 if (( phber = der_alloc()) == NULL ) {
444                         Debug( LDAP_DEBUG_ANY, "der_alloc failed\n", 0, 0, 0 );
445                         return( -1 );
446                 }
447                 if ( ber_printf( phber, "t{[tB]{B}}", 0xA3, 0x81, faxparamset,
448                     31, (char *)pe->pe_prim, len * 8 ) == -1 ) {
449                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
450                         ber_free( phber, 1 );
451                         return( -1 );
452                 }
453                 if ( ber_printf( ber, "o", phber->ber_buf, phber->ber_ptr
454                     - phber->ber_buf ) == -1 ) {
455                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
456                         ber_free( phber, 1 );
457                         return( -1 );
458                 }
459                 ber_free( phber, 1 );
460         } else {
461                 /*
462                  * try just writing this into a PS and sending it along
463                  */
464                 ps_len_strategy = PS_LEN_LONG;
465                 if ( (ps = ps_alloc( str_open )) == NULLPS )
466                         return( -1 );
467                 if ( str_setup( ps, NULLCP, 0, 0 ) == NOTOK ||
468                     pe2ps( ps, pe ) == NOTOK ) {
469                         ps_free( ps );
470                         return( -1 );
471                 }
472
473                 len = ps->ps_ptr - ps->ps_base;
474                 Debug( LDAP_DEBUG_ARGS, "put_photo_val: ber_printf %d bytes\n",
475                     len, 0, 0 );
476                 if ( ber_printf( ber, "o", (char *) ps->ps_base, len ) == -1 ) {
477                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
478                         ps_free( ps );
479                         return( -1 );
480                 }
481                 ps_free( ps );
482         }
483
484         return( 0 );
485 }
486
487 static int
488 put_values(
489     BerElement  *ber,
490     PS          ps,
491     short       syntax,
492     AV_Sequence vals
493 )
494 {
495         AV_Sequence     av;
496         char            *strvalue;
497
498         Debug( LDAP_DEBUG_TRACE, "put_values\n", 0, 0, 0 );
499
500         for ( av = vals; av != NULLAV; av = av->avseq_next ) {
501                 if ( syntax == ldap_jpeg_syntax ||
502                     syntax == ldap_jpeg_nonfile_syntax ) {
503                         if ( put_jpeg_value( ber, &av->avseq_av ) == -1 )
504                                 return( -1 );
505                 } else if ( syntax == ldap_photo_syntax ) {
506                         if ( put_photo_value( ber, &av->avseq_av ) == -1 )
507                                 return( -1 );
508                 } else if ( syntax == ldap_audio_syntax ) {
509                         if ( put_audio_value( ber, &av->avseq_av ) == -1 )
510                                 return( -1 );
511                 } else if ( syntax == ldap_dn_syntax ) {
512                         if ( encode_dn( ber, (DN) av->avseq_av.av_struct,
513                             NULLDN ) == -1 )
514                                 return( -1 );
515                 } else if ( syntax > AV_WRITE_FILE ) {
516                         struct file_syntax      *fsyntax;
517
518                         fsyntax = (struct file_syntax *) av->avseq_av.av_struct;
519
520                         ps->ps_ptr = ps->ps_base;
521                         AttrV_print( ps, fsyntax->fs_attr, EDBOUT );
522                         *ps->ps_ptr = '\0';
523
524                         if ( ber_printf( ber, "o", ps->ps_base,
525                             ps->ps_ptr - ps->ps_base ) == -1 )
526                                 return( -1 );
527                 } else {
528                         ps->ps_ptr = ps->ps_base;
529                         AttrV_print( ps, &av->avseq_av, EDBOUT );
530                         *ps->ps_ptr = '\0';
531                         de_t61( ps->ps_base, 0 );
532
533                         if ( syntax_is_string( av->avseq_av.av_syntax ) &&
534                                 *ps->ps_base == '\0' ) {
535                             /*
536                              * If this is a zero-length string, make it
537                              * a single blank (this is gross, but it works
538                              * around a dsap library bug).
539                              */
540                             Debug( LDAP_DEBUG_ANY,
541                                     "put_values: replaced zero-length string with single blank\n", 0, 0, 0 );
542                             strvalue = " ";
543                         } else {
544                             strvalue = ps->ps_base;
545                         }
546                         if ( ber_printf( ber, "s", strvalue ) == -1 )
547                                 return( -1 );
548                 }
549         }
550
551         return( 0 );
552 }
553
554 int
555 encode_attrs( BerElement *ber, Attr_Sequence as )
556 {
557         PS              ps;
558
559         Debug( LDAP_DEBUG_TRACE, "encode_attrs\n", 0, 0, 0 );
560
561         if ( (ps = ps_alloc( str_open )) == NULLPS )
562                 return( -1 );
563         if ( str_setup( ps, NULLCP, 0, 0 ) == NOTOK )
564                 return( -1 );
565
566 #ifdef LDAP_COMPAT20
567         if ( ber_printf( ber, "t{", ldap_compat == 20 ? OLD_LBER_SEQUENCE :
568             LBER_SEQUENCE ) == -1 ) {
569 #else
570         if ( ber_printf( ber, "{" ) == -1 ) {
571 #endif
572                 ps_free( ps );
573                 return( -1 );
574         }
575
576         while ( as != NULLATTR ) {
577                 ps->ps_ptr = ps->ps_base;
578                 AttrT_print( ps, as->attr_type, EDBOUT );
579                 *ps->ps_ptr = '\0';
580
581 #ifdef LDAP_COMPAT20
582                 if ( ber_printf( ber, "t{st[", ldap_compat == 20 ?
583                     OLD_LBER_SEQUENCE : LBER_SEQUENCE, ps->ps_base,
584                     ldap_compat == 20 ? OLD_LBER_SET : LBER_SET ) == -1 ) {
585 #else
586                 if ( ber_printf( ber, "{s[", ps->ps_base ) == -1 ) {
587 #endif
588                         ps_free( ps );
589                         return( -1 );
590                 }
591
592                 put_values( ber, ps, as->attr_type->oa_syntax, as->attr_value );
593
594                 if ( ber_printf( ber, "]}" ) == -1 ) {
595                         ps_free( ps );
596                         return( -1 );
597                 }
598
599                 as = as->attr_link;
600         }
601         ps_free( ps );
602
603         if ( ber_printf( ber, "}" ) == -1 )
604                 return( -1 );
605
606         return( 0 );
607 }
608
609 static void
610 trim_trailing_spaces( char *s )
611 {
612         char    *t;
613
614         t = s + strlen( s );
615         while ( --t > s ) {
616                 if ( SPACE( *t ) ) {
617                         *t = '\0';
618                 } else {
619                         break;
620                 }
621         }
622 }
623
624 DN
625 ldap_str2dn( char *str )
626 {
627         DN              dn, save;
628         RDN             rdn, newrdn, tmprdn;
629         AttributeType   at;
630         AttributeValue  av;
631         char            *type, *value, *savestr;
632         int             morerdncomps;
633
634         Debug( LDAP_DEBUG_TRACE, "ldap_str2dn\n", 0, 0, 0 );
635
636         savestr = str = strdup( str );
637         dn = NULLDN;
638         do {
639                 char    *r;
640                 int     state;
641
642                 rdn = NULLRDN;
643                 morerdncomps = 1;
644                 do {
645                         /* get the type */
646                         while ( *str == ' ' || *str == '\n' )
647                                 str++;
648                         type = str;
649                         while ( *str != '\0' && *str != '=' )
650                                 str++;
651                         if ( *str == '\0' ) {
652                                 free( savestr );
653                                 Debug( LDAP_DEBUG_ARGS, "no =\n", 0, 0, 0 );
654                                 return( NULLDN );
655                         }
656                         *str++ = '\0';
657                         if ( strncmp( type, "OID.", 4 ) == 0 )
658                                 type += 4;
659
660 #define BEGINVALUE      1
661 #define INVALUE         2
662 #define INQUOTE         3
663 #define ENDVALUE        4
664                         if ( *str == '#' ) {
665                                 ++str;
666                         }
667                         r = value = str;
668                         state = BEGINVALUE;
669                         /* break or return out */
670                         while ( state != ENDVALUE ) {
671                                 switch ( *str ) {
672                                 case '"':
673                                         if ( state == BEGINVALUE ) {
674                                                 state = INQUOTE;
675                                                 str++;
676                                         } else if ( state == INQUOTE ) {
677                                                 state = ENDVALUE;
678                                                 str++;
679                                         } else {
680                                                 free( savestr );
681                                                 Debug( LDAP_DEBUG_ARGS,
682                                                     "quote state %d\n", state,
683                                                     0, 0 );
684                                                 return( NULLDN );
685                                         }
686                                         break;
687
688                                 case ',':
689                                 case ';':
690                                 case '+':
691                                         if ( state == INVALUE ) {
692                                                 state = ENDVALUE;
693                                         } else if ( state == INQUOTE ) {
694                                                 *r++ = *str++;
695                                         } else {
696                                                 free( savestr );
697                                                 Debug( LDAP_DEBUG_ARGS,
698                                                     "comma state %d\n", state,
699                                                     0, 0 );
700                                                 return( NULLDN );
701                                         }
702                                         break;
703
704                                 case ' ':
705                                 case '\n':
706                                         if ( state == BEGINVALUE ) {
707                                                 str++;
708                                         } else {
709                                                 *r++ = *str++;
710                                         }
711                                         break;
712
713                                 case '\\':
714                                         str++;
715                                         *r++ = *str++;
716                                         break;
717
718                                 case '\0':
719                                         state = ENDVALUE;
720                                         break;
721
722                                 default:
723                                         if ( state == BEGINVALUE )
724                                                 state = INVALUE;
725                                         *r++ = *str++;
726                                         break;
727                                 }
728                         }
729
730                         while ( SPACE( *str ) )
731                                 str++;
732                         if ( *str == '+' ) {
733                                 morerdncomps = 1;
734                                 str++;
735                         } else {
736                                 morerdncomps = 0;
737                                 if ( SEPARATOR( *str ) )
738                                         str++;
739                         }
740                         *r = '\0';
741
742                         /* type */
743                         trim_trailing_spaces( type );
744                         if ( (at = str2AttrT( type )) == NULLAttrT ) {
745                                 dn_free( dn );
746                                 free( savestr );
747                                 Debug( LDAP_DEBUG_ARGS, "bad type (%s)\n",
748                                     type, 0, 0 );
749                                 return( NULLDN ); /* LDAP_UNDEFINED_TYPE */
750                         }
751                         /* value */
752                         if ( (av = ldap_str2AttrV( value, at->oa_syntax ))
753                             == NULLAttrV ) {
754                                 dn_free( dn );
755                                 free( savestr );
756                                 Debug( LDAP_DEBUG_ARGS, "bad val\n", 0, 0, 0 );
757                                 return( NULLDN ); /* LDAP_INVALID_SYNTAX */
758                         }
759                         /* make the rdn */
760                         newrdn = rdn_comp_new( at, av );
761
762                         /* add it to the list */
763                         for ( tmprdn = rdn; tmprdn != NULLRDN &&
764                             tmprdn->rdn_next != NULLRDN;
765                             tmprdn = tmprdn->rdn_next )
766                                 ;       /* NULL */
767                         if ( tmprdn != NULLRDN )
768                                 tmprdn->rdn_next = newrdn;
769                         else
770                                 rdn = newrdn;
771
772                         AttrV_free( av );
773                 } while ( morerdncomps );
774
775                 save = dn;
776                 dn = dn_comp_new( rdn );
777                 dn->dn_parent = save;
778         } while ( str != NULL && *str != '\0' );
779
780         free( savestr );
781         Debug( LDAP_DEBUG_TRACE, "ldap_str2dn OK\n", 0, 0, 0 );
782         return( dn );
783 }
784
785 #define T61     "{T.61}"
786 #define T61LEN  6
787
788 static void
789 de_t61( char *s, int t61mark )
790 {
791         char    *next = s;
792         unsigned char   c;
793         unsigned int    hex;
794
795         while ( *s ) {
796                 switch ( *s ) {
797                 case '{' :
798                         if ( strncasecmp( s, T61, T61LEN) == 0 ) {
799                                 s += T61LEN;
800                                 if ( t61mark )
801                                         *next++ = '@';
802                         } else {
803                                 *next++ = *s++;
804                         }
805                         break;
806
807                 case '\\':
808                         c = *(s + 1);
809                         if ( c == '\n' ) {
810                                 s += 2;
811                                 if ( *s == '\t' )
812                                         s++;
813                                 break;
814                         }
815                         if ( c == '\\' ) {
816                             /* reverse solidus character itself */
817                             s += 2;
818                             *next++ = c;
819                             break;
820                         }
821                         if ( isdigit( c ) )
822                                 hex = c - '0';
823                         else if ( c >= 'A' && c <= 'F' )
824                                 hex = c - 'A' + 10;
825                         else if ( c >= 'a' && c <= 'f' )
826                                 hex = c - 'a' + 10;
827                         else {
828                                 *next++ = *s++;
829                                 break;
830                         }
831                         hex <<= 4;
832                         c = *(s + 2);
833                         if ( isdigit( c ) )
834                                 hex += c - '0';
835                         else if ( c >= 'A' && c <= 'F' )
836                                 hex += c - 'A' + 10;
837                         else if ( c >= 'a' && c <= 'f' )
838                                 hex += c - 'a' + 10;
839                         else {
840                                 *next++ = *s++;
841                                 *next++ = *s++;
842                                 break;
843                         }
844
845                         *next++ = hex;
846                         s += 3;
847                         break;
848
849                 default:
850                         *next++ = *s++;
851                         break;
852                 }
853         }
854         *next = '\0';
855 }
856
857
858 static PE
859 bv_asn2pe( struct berval *bv )
860 {
861         PS      ps;
862         PE      pe;
863
864         if (( ps = ps_alloc(str_open)) == NULLPS || str_setup( ps, bv->bv_val,
865             bv->bv_len, 0 ) == NOTOK ) {
866                 Debug( LDAP_DEBUG_TRACE, "bv_asn2pe: ps_alloc failed\n",
867                     0, 0, 0 );
868                 return( NULLPE );
869         }
870
871         pe = ps2pe( ps );
872         if ( ps->ps_errno != PS_ERR_NONE ) {
873                 Debug( LDAP_DEBUG_TRACE, "bv_asn2pe: ps2pe failed %s\n",
874                     ps_error(ps->ps_errno), 0, 0 );
875                 if ( pe != NULLPE ) {
876                         pe_free( pe );
877                 }
878                 return( NULLPE );
879         }
880
881         return( pe );
882 }
883
884
885 AttributeValue
886 bv_octet2AttrV( struct berval *bv )
887 {
888         AttributeValue  av;
889
890         av = AttrV_alloc();
891         if ( av == NULLAttrV ) {
892                 return( NULLAttrV );
893         }
894
895         if (( av->av_struct = (caddr_t) str2prim( bv->bv_val, bv->bv_len,
896             PE_CLASS_UNIV, PE_PRIM_OCTS )) == NULL ) {
897                 free((char *)av );
898                 return( NULLAttrV );
899         }
900
901         av->av_syntax = 0;
902         return( av );
903 }
904
905
906 AttributeValue
907 bv_asn2AttrV( struct berval *bv )
908 {
909         AttributeValue  av;
910
911         av = AttrV_alloc();
912         if ( av == NULLAttrV ) {
913                 return( NULLAttrV );
914         }
915
916         if (( av->av_struct = (caddr_t) bv_asn2pe( bv )) == NULL ) {
917                 free((char *)av );
918                 return( NULLAttrV );
919         }
920
921         av->av_syntax = 0;
922         return( av );
923 }
924
925
926 AttributeValue
927 ldap_strdn2AttrV( char *dnstr )
928 {
929         DN              dn;
930         AttributeValue  av;
931
932         if (( dn = ldap_str2dn( dnstr )) == NULL ) {
933                 return( NULLAttrV );
934         }
935
936         av = AttrV_alloc();
937         if ( av == NULLAttrV ) {
938                 dn_free( dn );
939                 return( NULLAttrV );
940         }
941
942         av->av_struct = (caddr_t)dn; 
943         av->av_syntax = ldap_dn_syntax;
944         return( av );
945 }
946
947 RDN
948 ldap_str2rdn( char *rdnstr )
949 {
950         DN      dn;
951         RDN     rdn;
952
953         if ( (dn = ldap_str2dn( rdnstr )) == NULL ) {
954                 return( NULL );
955         }
956
957         if ( (rdn = rdn_cpy( dn->dn_rdn )) == NULL ) {
958                 return( NULL );
959         }
960
961         dn_free( dn );
962
963         return( rdn );
964 }
965
966 AttributeValue
967 ldap_str_at2AttrV( char *str, AttributeType type )
968 {
969         char            *s, *res, *r;
970
971         Debug( LDAP_DEBUG_TRACE, "ldap_str_at2AttrV str (%s) type (%s)\n", str,
972             type->oa_ot.ot_name, 0 );
973
974         if ( type->oa_syntax == ldap_rts_cred_syntax ||
975             type->oa_syntax == ldap_mtai_syntax ||
976             type->oa_syntax == ldap_acl_syntax ||
977             type->oa_syntax == ldap_mailbox_syntax ||
978             type->oa_syntax == ldap_caseignorelist_syntax ||
979             type->oa_syntax == ldap_certif_syntax ||
980             type->oa_syntax == ldap_iattr_syntax ||
981             type->oa_syntax == ldap_telex_syntax ||
982             type->oa_syntax == ldap_deliverymethod_syntax ||
983             type->oa_syntax == ldap_facsimileTelephoneNumber_syntax ||
984             type->oa_syntax == ldap_presentationAddress_syntax ||
985             type->oa_syntax == ldap_teletexTerminalIdentifier_syntax ||
986             type->oa_syntax == ldap_searchGuide_syntax ||
987             type->oa_syntax == ldap_dLSubmitPermission_syntax ||
988             type->oa_syntax == ldap_rtl_syntax ) {
989                 res = str;
990         } else {
991                 res = (char *) malloc( max( 2 * strlen( str ), (size_t) 10 ) );
992
993                 r = res;
994                 for ( s = str; *s; s++ ) {
995                         switch ( *s ) {
996                         case '&':
997                         case '#':
998                         case '$':
999                         case '%':
1000                         case '@':
1001                         case '\\':
1002                                 sprintf( r, "\\%02x", *s & 0xff );
1003                                 r += 3;
1004                                 break;
1005
1006                         default:
1007                                 *r++ = *s;
1008                         }
1009                 }
1010                 *r = '\0';
1011         }
1012
1013         Debug( LDAP_DEBUG_TRACE, "ldap_str_at2AttrV returning (%s)\n", res,
1014             0, 0 );
1015
1016         return( str_at2AttrV( res, type ) );
1017 }
1018
1019 AttributeValue
1020 ldap_str2AttrV( char *value, short syntax )
1021 {
1022         if ( syntax == ldap_dn_syntax ) {
1023                 return( ldap_strdn2AttrV( value ) );
1024         } else {
1025                 return( str2AttrV( value, syntax ) );
1026         }
1027 }
1028
1029
1030 static int
1031 syntax_is_string( short syntax )
1032 {
1033 /*
1034  * this code depends on the order and nunber of strings that are in
1035  * the ISODE file lib/syntax/x500/string.c 
1036  */
1037     return ( syntax >= ldap_caseexactstring_syntax &&
1038             syntax <= ldap_caseexactstring_syntax + 8 );
1039 }