]> git.sur5r.net Git - openldap/blob - servers/slapd/tools/ldapsyntax.c
include portable.h
[openldap] / servers / slapd / tools / ldapsyntax.c
1 /*
2  * Copyright (c) 1995 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 #include <string.h>
17 #include <ctype.h>
18 #include <quipu/commonarg.h>
19 #include <quipu/attrvalue.h>
20 #include <quipu/ds_error.h>
21 #include <quipu/ds_search.h>
22 /* #include <quipu/dap2.h> */
23 #include <quipu/dua.h>
24 #include <sys/types.h>
25
26 #include "lber.h"
27 #include "ldap.h"
28 #include "ldif.h"
29 #include "ldapsyntax.h"
30
31 short   ldap_dn_syntax;
32 short   ldap_password_syntax;
33 short   ldap_photo_syntax;
34 short   ldap_jpeg_syntax;
35 short   ldap_audio_syntax;
36
37 static int      dn2ldif( PS ps, DN dn );
38 static int      jpeg2ldif( PS ps, AttributeValue av );
39 static int      audio2ldif( PS ps, AttributeValue av );
40 static int      photo2ldif( PS ps, AttributeValue av );
41 static int      fileattr2ldif( PS ps, AttributeValue av );
42 static void     de_t61( char *s, int t61mark );
43 static void     de_crypt( char *s );
44
45 extern char     *progname;
46
47 #define SEPARATOR(c)    (c == ',' || c == ';')
48 #define SPACE(c)        (c == ' ' || c == '\n')
49
50
51 int
52 init_syntaxes()
53 {
54     if (( ldap_dn_syntax = str2syntax( "DN" )) == 0 ) {
55         return( -1 );   /* must have this syntax handler */
56     }
57     ldap_password_syntax = str2syntax( "password" );
58     ldap_photo_syntax = str2syntax( "photo" );
59     ldap_jpeg_syntax = str2syntax( "jpeg" );
60     ldap_audio_syntax = str2syntax( "audio" );
61
62     return( 0 );
63 }
64
65
66 /*
67  * av2ldif:  convert attribute value contained in "av" to ldif format
68  * and write to "outfp".  If "dn" is not NULL, convert it instead of "av".
69  */
70 int
71 av2ldif( FILE *outfp, AV_Sequence av, DN dn, short syntax, char *attrname,
72     PS str_ps )
73 {
74     char                *buf;
75     int                 rc;
76     struct file_syntax  *fsyntax;
77
78     if ( av != NULLAV ) {
79         fsyntax = (struct file_syntax *) av->avseq_av.av_struct;
80     }
81
82     rc = 0;     /* optimistic */
83     str_ps->ps_ptr = str_ps->ps_base;   /* reset string PS */
84
85     if ( dn != NULL || syntax == ldap_dn_syntax ) {     /* DNs */
86         rc = dn2ldif( str_ps, ( dn != NULLDN ) ? dn :
87                 (DN)(av->avseq_av.av_struct));
88
89     } else if ( syntax == ldap_jpeg_syntax || ( syntax > AV_WRITE_FILE &&
90             fsyntax->fs_real_syntax == ldap_jpeg_syntax )) {
91         rc = jpeg2ldif( str_ps, &av->avseq_av );
92
93     } else if ( syntax == ldap_photo_syntax || ( syntax > AV_WRITE_FILE &&
94             fsyntax->fs_real_syntax == ldap_photo_syntax )) {
95         rc = photo2ldif( str_ps, &av->avseq_av );
96
97     } else if ( syntax == ldap_audio_syntax || ( syntax > AV_WRITE_FILE &&
98             fsyntax->fs_real_syntax == ldap_audio_syntax )) {
99         rc = audio2ldif( str_ps, &av->avseq_av );
100
101     } else if ( syntax > AV_WRITE_FILE ) {
102         rc = fileattr2ldif( str_ps, &av->avseq_av );
103
104     } else {
105         AttrV_print( str_ps, &av->avseq_av, EDBOUT );
106         *str_ps->ps_ptr = '\0';
107         de_t61( str_ps->ps_base, 0 );
108
109         if ( syntax == ldap_password_syntax ) {
110             de_crypt( str_ps->ps_base );
111         }
112
113         str_ps->ps_ptr = str_ps->ps_base + strlen( str_ps->ps_base );
114     }
115
116     if ( rc == 0 && str_ps->ps_ptr > str_ps->ps_base ) {
117         *str_ps->ps_ptr = '\0';
118         if (( buf = ldif_type_and_value( attrname, str_ps->ps_base,
119                 str_ps->ps_ptr - str_ps->ps_base )) == NULL ) {
120             rc = -1;
121         } else {
122             if ( fputs( buf, outfp ) == EOF ) {
123                 rc = -1;
124             }
125             free( buf );
126         }
127     }
128
129     if ( rc == -2 ) {
130         if ( syntax > AV_WRITE_FILE ) {
131             fprintf( stderr,
132                     "%s: attribute file '%s' not found (skipping value)\n",
133                      progname, fsyntax->fs_name );
134         }
135         rc = 0; /* treat as "soft" error -- keep going */
136     }
137
138     return( rc );
139 }
140
141
142 static int
143 dn2ldif( PS ps, DN dn )
144 {
145     RDN rdn;
146     int firstrdn, rc;
147     char        *value;
148     PS  rps;
149
150     if ( dn == NULLDN ) {
151         return( 0 );
152     }
153
154     if ( dn->dn_parent != NULLDN ) {
155         if (( rc = dn2ldif( ps, dn->dn_parent )) != 0 ) {
156             return( rc );
157         }
158         ps_print( ps, ", " );
159     }
160
161     if ( (rps = ps_alloc( str_open )) == NULLPS ||
162             str_setup( rps, NULLCP, 0, 0 ) == NOTOK ) {
163         return( -1 );
164     }
165
166     firstrdn = 1;
167     for ( rdn = dn->dn_rdn; rdn != NULLRDN; rdn = rdn->rdn_next ) {
168         if ( firstrdn ) {
169             firstrdn = 0;
170         } else {
171             ps_print( ps, " + " );
172         }
173
174         AttrT_print( ps, rdn->rdn_at, EDBOUT );
175         ps_print( ps, "=" );
176
177         if ( rdn->rdn_at->oa_syntax == ldap_dn_syntax ) {
178             if (( rc = dn2ldif( rps, (DN) rdn->rdn_av.av_struct )) != 0 ) {
179                 return( rc );
180             }
181             *rps->ps_ptr = '\0';
182             value = rps->ps_base;
183         } else {
184             AttrV_print( rps, &rdn->rdn_av, EDBOUT );
185             *rps->ps_ptr = '\0';
186             value = rps->ps_base;
187             de_t61( value, 0 );
188         }
189
190         /*
191          * ,+="\\\n all go in quotes.  " and \\ need to
192          * be preceeded by \\.
193          */
194
195         if ( strpbrk( value, ",+=\"\\\n" ) != NULL || SPACE( value[0] )
196                 || SPACE( value[max( strlen(value) - 1, 0 )] ) ) {
197             char        *p, *t, *tmp;
198             int specialcount;
199
200             ps_print( ps, "\"" );
201
202             specialcount = 0;
203             for ( p = value; *p != '\0'; p++ ) {
204                 if ( *p == '"' || *p == '\\' ) {
205                     specialcount++;
206                 }
207             }
208             if ( specialcount > 0 ) {
209                 tmp = smalloc( strlen( value ) + specialcount + 1 );
210                 for ( p = value, t = tmp; *p != '\0'; p++ ) {
211                     switch ( *p ) {
212                     case '"':
213                     case '\\':
214                             *t++ = '\\';
215                             /* FALL THROUGH */
216                     default:
217                             *t++ = *p;
218                     }
219                 }
220                 *t = '\0';
221                 ps_print( ps, tmp );
222                 free( tmp );
223             } else {
224                 ps_print( ps, value );
225             }
226
227             ps_print( ps, "\"" );
228         } else {
229             ps_print( ps, value );
230         }
231
232         rps->ps_ptr = rps->ps_base;
233     }
234
235     ps_free( rps );
236
237     return( 0 );
238 }
239
240 #define T61     "{T.61}"
241 #define T61LEN  6
242
243 static void
244 de_t61( s, t61mark )
245 char    *s;
246 int     t61mark;
247 {
248         char    *next = s;
249         int     c, hex;
250
251         while ( *s ) {
252                 switch ( *s ) {
253                 case '{' :
254                         if ( strncasecmp( s, T61, T61LEN) == 0 ) {
255                                 s += T61LEN;
256                                 if ( t61mark )
257                                         *next++ = '@';
258                         } else {
259                                 *next++ = *s++;
260                         }
261                         break;
262
263                 case '\\':
264                         c = *(s + 1);
265                         if ( c == '\n' ) {
266                                 s += 2;
267                                 if ( *s == '\t' )
268                                         s++;
269                                 break;
270                         }
271                         if ( isdigit( c ) )
272                                 hex = c - '0';
273                         else if ( c >= 'A' && c <= 'F' )
274                                 hex = c - 'A' + 10;
275                         else if ( c >= 'a' && c <= 'f' )
276                                 hex = c - 'a' + 10;
277                         else {
278                                 *next++ = *s++;
279                                 break;
280                         }
281                         hex <<= 4;
282                         c = *(s + 2);
283                         if ( isdigit( c ) )
284                                 hex += c - '0';
285                         else if ( c >= 'A' && c <= 'F' )
286                                 hex += c - 'A' + 10;
287                         else if ( c >= 'a' && c <= 'f' )
288                                 hex += c - 'a' + 10;
289                         else {
290                                 *next++ = *s++;
291                                 *next++ = *s++;
292                                 break;
293                         }
294
295                         *next++ = hex;
296                         s += 3;
297                         break;
298
299                 default:
300                         *next++ = *s++;
301                         break;
302                 }
303         }
304         *next = '\0';
305 }
306
307
308 #define CRYPT_MASK 0x23
309
310 static void
311 de_crypt( char *s )
312 {
313     char *p;
314
315     if ( strncmp( s, "{CRYPT}", 7 ) == 0 ) {
316         strcpy( s, s + 7 );                     /* strip off "{CRYPT}" */
317
318         for ( p = s; *p != '\0'; ++p) {         /* "decrypt" each byte */
319             if ( *p != CRYPT_MASK ) {
320                 *p ^= CRYPT_MASK;
321             }
322         }
323     }
324 }
325
326
327 static int
328 jpeg2ldif( PS ps, AttributeValue av )
329 {
330     PE  pe;
331     int len;
332
333     if (( pe = grab_pe( av )) == NULLPE || pe->pe_id == PE_PRIM_NULL ) {
334         return( -2 );   /* signal soft error */
335     }
336
337     if (( pe->pe_class != PE_CLASS_UNIV && pe->pe_class != PE_CLASS_CONT )
338             || pe->pe_form != PE_FORM_PRIM || pe->pe_id != PE_PRIM_OCTS ) {
339         return( -1 );
340     }
341
342     if ( pe_pullup( pe ) == NOTOK ) {
343         return( -1 );
344     }
345
346     len = ps_get_abs( pe );
347
348     if ( ps_write( ps, (PElementData)pe->pe_prim, len ) == NOTOK ) {
349         return( -1 );
350     }
351
352     return( 0 );
353 }
354
355
356 static int
357 audio2ldif( PS ps, AttributeValue av )
358 {
359     PE          pe;
360     struct qbuf *qb, *p;
361     int         rc, len;
362     char        *buf;
363
364     return( 0 );        /* for now */
365
366     if (( pe = grab_pe( av )) == NULLPE || pe->pe_id == PE_PRIM_NULL ) {
367         return( -2 );   /* signal soft error */
368     }
369
370     qb = (struct qbuf *)pe;
371
372     len = 0;
373     for ( p = qb->qb_forw; p != qb; p = p->qb_forw ) {
374         len += p->qb_len;
375     }
376
377     if (( buf = (char *) malloc( len )) == NULL ) {
378         return( -1 );
379     }
380
381     len = 0;
382     for ( p = qb->qb_forw; p != qb; p = p->qb_forw ) {
383         SAFEMEMCPY( buf + len, p->qb_data, p->qb_len );
384         len += p->qb_len;
385     }
386
387     if ( ps_write( ps, (PElementData)buf, len ) == NOTOK ) {
388         rc = -1;
389     } else {
390         rc = 0;
391     }
392
393     free( buf );
394
395     return( rc );
396 }
397
398
399 static int
400 photo2ldif( PS ps, AttributeValue av )
401 {
402     PE          pe;
403     int         len;
404     char        *faxparamset = "\000\300\000\000";
405     BerElement  *phber;
406
407     if (( pe = grab_pe( av )) == NULLPE || pe->pe_id == PE_PRIM_NULL ) {
408         return( -2 );   /* signal soft error */
409     }
410
411     /* old bit string-like format - only handle this for now */
412     if ( pe->pe_class == PE_CLASS_UNIV && pe->pe_form == PE_FORM_PRIM
413             && pe->pe_id == PE_PRIM_BITS ) {
414         len = ps_get_abs( pe );
415         if (( phber = der_alloc()) == NULLBER ) {
416             return( -1 );
417         }
418         if ( ber_printf( phber, "t{[tB]{B}}", 0xA3, 0x81, faxparamset,
419                 31, (char *)pe->pe_prim, len * 8 ) == -1 ) {
420             ber_free( phber, 1 );
421             return( -1 );
422         }
423         if ( ps_write( ps, (PElementData)phber->ber_buf,
424                 phber->ber_ptr - phber->ber_buf ) == NOTOK ) {
425             ber_free( phber, 1 );
426             return( -1 );
427         }
428         ber_free( phber, 1 );
429     } else {
430         /*
431          * try just writing this into a PS and sending it along
432          */
433         if ( pe2ps( ps, pe ) == NOTOK ) {
434             return( -1 );
435         }
436     }
437
438     return( 0 );
439 }
440
441
442 static int
443 fileattr2ldif( PS ps, AttributeValue av )
444 {
445     PE          pe;
446
447     if (( pe = grab_pe( av )) == NULLPE || pe->pe_id == PE_PRIM_NULL ) {
448         return( -2 );   /* signal soft error */
449     }
450
451     /*
452      * try just writing this into a PS and sending it along
453      */
454     if ( pe2ps( ps, pe ) == NOTOK ) {
455         return( -1 );
456     }
457
458     return( 0 );
459 }