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