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