]> git.sur5r.net Git - openldap/blob - libraries/libldif/line64.c
s/*vlenp = NULL;/*vlenp = 0;/
[openldap] / libraries / libldif / line64.c
1 /* line64.c - routines for dealing with the slapd line format */
2
3 #include "portable.h"
4
5 #include <stdio.h>
6
7 #include <ac/stdlib.h>
8 #include <ac/ctype.h>
9
10 #include <ac/string.h>
11 #include <ac/socket.h>
12 #include <ac/time.h>
13
14 int ldif_debug = 0;
15
16 #include "ldap_log.h"
17 #include "lber_pvt.h"
18 #include "ldif.h"
19
20 #define RIGHT2                  0x03
21 #define RIGHT4                  0x0f
22 #define CONTINUED_LINE_MARKER   '\001'
23
24 static const char nib2b64[0x40] =
25         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
26
27 static const unsigned char b642nib[0x80] = {
28         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
29         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
30         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
31         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
32         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
33         0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
34         0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
35         0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
36         0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
37         0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
38         0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
39         0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
40         0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
41         0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
42         0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
43         0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
44 };
45
46 /*
47  * ldif_parse_line - takes a line of the form "type:[:] value" and splits it
48  * into components "type" and "value".  if a double colon separates type from
49  * value, then value is encoded in base 64, and parse_line un-decodes it
50  * (in place) before returning.
51  */
52
53 int
54 ldif_parse_line(
55     LDAP_CONST char     *line,
56     char        **typep,
57     char        **valuep,
58     ber_len_t *vlenp
59 )
60 {
61         char    *s, *p, *d; 
62         char    nib;
63         int     b64, url;
64         char    *freeme, *type, *value;
65         ber_len_t vlen;
66
67         *typep = NULL;
68         *valuep = NULL;
69         *vlenp = 0;
70
71         /* skip any leading space */
72         while ( isspace( (unsigned char) *line ) ) {
73                 line++;
74         }
75
76         freeme = ber_strdup( line );
77
78         if( freeme == NULL ) {
79                 ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
80                         "ldif_parse_line: line malloc failed\n");
81                 return( -1 );
82         }
83
84         type = freeme;
85
86         s = strchr( type, ':' );
87
88         if ( s == NULL ) {
89                 ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
90                         "ldif_parse_line: missing ':' after %s\n",
91                         type );
92                 ber_memfree( freeme );
93                 return( -1 );
94         }
95
96         /* trim any space between type and : */
97         for ( p = &s[-1]; p > type && isspace( * (unsigned char *) p ); p-- ) {
98                 *p = '\0';
99         }
100         *s++ = '\0';
101
102         if ( *s == '\0' ) {
103                 /* no value */
104                 value = NULL;
105                 vlen = 0;
106                 goto done;
107         }
108                 
109         url = 0;
110         b64 = 0;
111
112         if ( *s == '<' ) {
113                 s++;
114                 url = 1;
115         } else if ( *s == ':' ) {
116                 /* base 64 encoded value */
117                 s++;
118                 b64 = 1;
119         }
120
121         /* skip space between : and value */
122         while ( isspace( (unsigned char) *s ) ) {
123                 s++;
124         }
125
126         /* if no value is present, error out */
127         if ( *s == '\0' ) {
128                 ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
129                         "ldif_parse_line: %s missing %svalue\n", type,
130                                 url ? "URL " : b64 ? "base64 " : "" );
131                 value = NULL;
132                 vlen = 0;
133                 goto done;
134         }
135
136         /* check for continued line markers that should be deleted */
137         for ( p = s, d = s; *p; p++ ) {
138                 if ( *p != CONTINUED_LINE_MARKER )
139                         *d++ = *p;
140         }
141         *d = '\0';
142
143         if ( b64 ) {
144                 char *byte = s;
145
146                 value = s;
147
148                 for ( p = s, vlen = 0; p < d; p += 4, vlen += 3 ) {
149                         int i;
150                         for ( i = 0; i < 4; i++ ) {
151                                 if ( p[i] != '=' && (p[i] & 0x80 ||
152                                     b642nib[ p[i] & 0x7f ] > 0x3f) ) {
153                                         ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
154                                                 "ldif_parse_line: %s: invalid base64 encoding"
155                                                 " char (%c) 0x%x\n",
156                                             type, p[i], p[i] );
157                                         ber_memfree( freeme );
158                                         return( -1 );
159                                 }
160                         }
161
162                         /* first digit */
163                         nib = b642nib[ p[0] & 0x7f ];
164                         byte[0] = nib << 2;
165                         /* second digit */
166                         nib = b642nib[ p[1] & 0x7f ];
167                         byte[0] |= nib >> 4;
168                         byte[1] = (nib & RIGHT4) << 4;
169                         /* third digit */
170                         if ( p[2] == '=' ) {
171                                 vlen += 1;
172                                 break;
173                         }
174                         nib = b642nib[ p[2] & 0x7f ];
175                         byte[1] |= nib >> 2;
176                         byte[2] = (nib & RIGHT2) << 6;
177                         /* fourth digit */
178                         if ( p[3] == '=' ) {
179                                 vlen += 2;
180                                 break;
181                         }
182                         nib = b642nib[ p[3] & 0x7f ];
183                         byte[2] |= nib;
184
185                         byte += 3;
186                 }
187                 s[ vlen ] = '\0';
188
189         } else if ( url ) {
190                 if( ldif_fetch_url( s, &value, &vlen ) ) {
191                         ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
192                                 "ldif_parse_line: %s: URL \"%s\" fetch failed\n",
193                                 type, s );
194                         ber_memfree( freeme );
195                         return( -1 );
196                 }
197
198         } else {
199                 value = s;
200                 vlen = (int) (d - s);
201         }
202
203 done:
204         type = ber_strdup( type );
205
206         if( type == NULL ) {
207                 ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
208                         "ldif_parse_line: type malloc failed\n");
209                 ber_memfree( freeme );
210                 return( -1 );
211         }
212
213         if( !url && value != NULL ) {
214                 value = ber_strdup( value );
215                 if( value == NULL ) {
216                         ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
217                                 "ldif_parse_line: value malloc failed\n");
218                         ber_memfree( type );
219                         ber_memfree( freeme );
220                         return( -1 );
221                 }
222         }
223
224         ber_memfree( freeme );
225
226         *typep = type;
227         *valuep = value;
228         *vlenp = vlen;
229
230         return( 0 );
231 }
232
233 /*
234  * ldif_getline - return the next "line" (minus newline) of input from a
235  * string buffer of lines separated by newlines, terminated by \n\n
236  * or \0.  this routine handles continued lines, bundling them into
237  * a single big line before returning.  if a line begins with a white
238  * space character, it is a continuation of the previous line. the white
239  * space character (nb: only one char), and preceeding newline are changed
240  * into CONTINUED_LINE_MARKER chars, to be deleted later by the
241  * ldif_parse_line() routine above.
242  *
243  * ldif_getline will skip over any line which starts '#'.
244  *
245  * ldif_getline takes a pointer to a pointer to the buffer on the first call,
246  * which it updates and must be supplied on subsequent calls.
247  */
248
249 char *
250 ldif_getline( char **next )
251 {
252         char *line;
253
254         do {
255                 if ( *next == NULL || **next == '\n' || **next == '\0' ) {
256                         return( NULL );
257                 }
258
259                 line = *next;
260
261                 while ( (*next = strchr( *next, '\n' )) != NULL ) {
262                         unsigned char c = *(*next + 1);
263
264                         if ( !isspace( c ) || c == '\n' ) {
265                                 *(*next)++ = '\0';
266                                 break;
267                         }
268
269                         **next = CONTINUED_LINE_MARKER;
270                         *(*next+1) = CONTINUED_LINE_MARKER;
271                         (*next)++;
272                 }
273         } while( *line == '#' );
274
275         return( line );
276 }
277
278 /* compatibility with U-Mich off by one bug */
279 #define LDIF_KLUDGE 1
280
281 void
282 ldif_sput(
283         char **out,
284         int type,
285         LDAP_CONST char *name,
286         LDAP_CONST char *val,
287         ber_len_t vlen )
288 {
289         unsigned char   *byte, *stop;
290         unsigned char   buf[3];
291         unsigned long   bits;
292         char            *save;
293         int             pad;
294
295         ber_len_t savelen;
296         ber_len_t len=0;
297         ber_len_t i;
298
299         /* prefix */
300         switch( type ) {
301         case LDIF_PUT_COMMENT:
302                 if( name != NULL ) break;
303
304                 *(*out)++ = '#';
305                 len++;
306
307                 if( vlen ) {
308                         *(*out)++ = ' ';
309                         len++;
310                         break;
311                 }
312
313                 /* no value, fall-thru */
314
315         case LDIF_PUT_SEP:
316                 *(*out)++ = '\n';
317                 return;
318         }
319
320         /* name (attribute type) */
321         if( name != NULL ) {
322                 /* put the name + ":" */
323                 for ( i=0 ; name[i]; i++ ) {
324                         *(*out)++ = name[i];
325                         len++;
326                 }
327
328                 if( type != LDIF_PUT_COMMENT ) {
329                         *(*out)++ = ':';
330                         len++;
331                 }
332
333 #ifdef LDAP_DEBUG
334         } else {
335                 assert( type == LDIF_PUT_COMMENT );
336 #endif
337         }
338
339         switch( type ) {
340         case LDIF_PUT_NOVALUE:
341                 *(*out)++ = '\n';
342                 return;
343
344         case LDIF_PUT_URL: /* url value */
345                 *(*out)++ = '<';
346                 len++;
347                 break;
348
349         case LDIF_PUT_B64: /* base64 value */
350                 *(*out)++ = ':';
351                 len++;
352                 break;
353         }
354
355         switch( type ) {
356         case LDIF_PUT_TEXT:
357         case LDIF_PUT_URL:
358         case LDIF_PUT_B64:
359                 *(*out)++ = ' ';
360                 len++;
361                 /* fall-thru */
362
363         case LDIF_PUT_COMMENT:
364                 /* pre-encoded names */
365                 for ( i=0; i < vlen; i++ ) {
366                         if ( len > LDIF_LINE_WIDTH ) {
367                                 *(*out)++ = '\n';
368                                 *(*out)++ = ' ';
369                                 len = 1;
370                         }
371
372                         *(*out)++ = val[i];
373                         len++;
374                 }
375                 *(*out)++ = '\n';
376                 return;
377         }
378
379         save = *out;
380         savelen = len;
381
382         *(*out)++ = ' ';
383         len++;
384
385         if( vlen == 0 ) {
386                 *(*out)++ = '\n';
387                 return;
388         }
389
390         stop = (unsigned char *) (val + vlen);
391
392         if ( type == LDIF_PUT_VALUE &&
393                 isgraph( val[0] ) && val[0] != ':' && val[0] != '<' &&
394                 isgraph( val[vlen-1] ) )
395         {
396                 int b64 = 0;
397
398                 for ( byte = (unsigned char *) val; byte < stop;
399                     byte++, len++ )
400                 {
401                         if ( !isascii( *byte ) || !isprint( *byte ) ) {
402                                 b64 = 1;
403                                 break;
404                         }
405                         if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
406                                 *(*out)++ = '\n';
407                                 *(*out)++ = ' ';
408                                 len = 1;
409                         }
410                         *(*out)++ = *byte;
411                 }
412
413                 if( !b64 ) {
414                         *(*out)++ = '\n';
415                         return;
416                 }
417         }
418
419         *out = save;
420         *(*out)++ = ':';
421         *(*out)++ = ' ';
422         len = savelen + 2;
423
424         /* convert to base 64 (3 bytes => 4 base 64 digits) */
425         for ( byte = (unsigned char *) val;
426                 byte < stop - 2;
427             byte += 3 )
428         {
429                 bits = (byte[0] & 0xff) << 16;
430                 bits |= (byte[1] & 0xff) << 8;
431                 bits |= (byte[2] & 0xff);
432
433                 for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
434                         if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
435                                 *(*out)++ = '\n';
436                                 *(*out)++ = ' ';
437                                 len = 1;
438                         }
439
440                         /* get b64 digit from high order 6 bits */
441                         *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
442                 }
443         }
444
445         /* add padding if necessary */
446         if ( byte < stop ) {
447                 for ( i = 0; byte + i < stop; i++ ) {
448                         buf[i] = byte[i];
449                 }
450                 for ( pad = 0; i < 3; i++, pad++ ) {
451                         buf[i] = '\0';
452                 }
453                 byte = buf;
454                 bits = (byte[0] & 0xff) << 16;
455                 bits |= (byte[1] & 0xff) << 8;
456                 bits |= (byte[2] & 0xff);
457
458                 for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
459                         if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
460                                 *(*out)++ = '\n';
461                                 *(*out)++ = ' ';
462                                 len = 1;
463                         }
464
465                         if( i + pad < 4 ) {
466                                 /* get b64 digit from low order 6 bits */
467                                 *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
468                         } else {
469                                 *(*out)++ = '=';
470                         }
471                 }
472         }
473         *(*out)++ = '\n';
474 }
475
476
477 /*
478  * ldif_type_and_value return BER malloc'd, zero-terminated LDIF line
479  */
480 char *
481 ldif_put(
482         int type,
483         LDAP_CONST char *name,
484         LDAP_CONST char *val,
485         ber_len_t vlen )
486 {
487     char        *buf, *p;
488     ber_len_t nlen;
489
490     nlen = ( name != NULL ) ? strlen( name ) : 0;
491
492         buf = (char *) ber_memalloc( LDIF_SIZE_NEEDED( nlen, vlen ) + 1 );
493
494     if ( buf == NULL ) {
495                 ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
496                         "ldif_type_and_value: malloc failed!" );
497                 return NULL;
498     }
499
500     p = buf;
501     ldif_sput( &p, type, name, val, vlen );
502     *p = '\0';
503
504     return( buf );
505 }
506
507 int ldif_is_not_printable(
508         LDAP_CONST char *val,
509         ber_len_t vlen )
510 {
511         if( vlen == 0 || val == NULL  ) {
512                 return -1;
513         }
514
515         if( isgraph( val[0] ) && val[0] != ':' && val[0] != '<' &&
516                 isgraph( val[vlen-1] ) )
517         {
518                 ber_len_t i;
519
520                 for ( i = 0; val[i]; i++ ) {
521                         if ( !isascii( val[i] ) || !isprint( val[i] ) ) {
522                                 return 1;
523                         }
524                 }
525
526                 return 0;
527         }
528
529         return 1;
530 }