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