]> git.sur5r.net Git - openldap/blob - libraries/liblutil/ldif.c
Added ldif_parse_line2 to parse in-place
[openldap] / libraries / liblutil / ldif.c
1 /* ldif.c - routines for dealing with LDIF files */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2005 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* Portions Copyright (c) 1992-1996 Regents of the University of Michigan.
17  * All rights reserved.
18  *
19  * Redistribution and use in source and binary forms are permitted
20  * provided that this notice is preserved and that due credit is given
21  * to the University of Michigan at Ann Arbor.  The name of the
22  * University may not be used to endorse or promote products derived
23  * from this software without specific prior written permission.  This
24  * software is provided ``as is'' without express or implied warranty.
25  */
26 /* This work was originally developed by the University of Michigan
27  * and distributed as part of U-MICH LDAP.
28  */
29
30 #include "portable.h"
31
32 #include <stdio.h>
33
34 #include <ac/stdlib.h>
35 #include <ac/ctype.h>
36
37 #include <ac/string.h>
38 #include <ac/socket.h>
39 #include <ac/time.h>
40
41 int ldif_debug = 0;
42
43 #include "ldap_log.h"
44 #include "lber_pvt.h"
45 #include "ldif.h"
46
47 #define RIGHT2                  0x03
48 #define RIGHT4                  0x0f
49 #define CONTINUED_LINE_MARKER   '\r'
50
51 #ifdef CSRIMALLOC
52 #define ber_memalloc malloc
53 #define ber_memcalloc calloc
54 #define ber_memrealloc realloc
55 #define ber_strdup strdup
56 #endif
57
58 static const char nib2b64[0x40] =
59         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
60
61 static const unsigned char b642nib[0x80] = {
62         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
63         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
64         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
65         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
67         0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
68         0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
69         0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
70         0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
71         0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
72         0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
73         0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
74         0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
75         0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
76         0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
77         0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
78 };
79
80 /*
81  * ldif_parse_line - takes a line of the form "type:[:] value" and splits it
82  * into components "type" and "value".  if a double colon separates type from
83  * value, then value is encoded in base 64, and parse_line un-decodes it
84  * (in place) before returning. The type and value are stored in malloc'd
85  * memory which must be freed by the caller.
86  *
87  * ldif_parse_line2 - operates in-place on input buffer, returning type
88  * in-place. Will return value in-place if possible, (must malloc for
89  * fetched URLs).
90  */
91
92 int
93 ldif_parse_line(
94     LDAP_CONST char     *line,
95     char        **typep,
96     char        **valuep,
97     ber_len_t *vlenp
98 )
99 {
100         return ldif_parse_line2( line, typep, valuep, vlenp, NULL );
101 }
102
103 int
104 ldif_parse_line2(
105     LDAP_CONST char     *line,
106     char        **typep,
107     char        **valuep,
108     ber_len_t *vlenp,
109         int             *alloc
110 )
111 {
112         char    *s, *p, *d; 
113         char    nib;
114         int     b64, url;
115         char    *type, *value;
116         ber_len_t vlen;
117
118         *typep = NULL;
119         *valuep = NULL;
120         *vlenp = 0;
121
122         /* skip any leading space */
123         while ( isspace( (unsigned char) *line ) ) {
124                 line++;
125         }
126
127         if ( alloc ) {
128                 *alloc = 0;
129         } else {
130                 line = ber_strdup( line );
131
132                 if( line == NULL ) {
133                         ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
134                                 _("ldif_parse_line: line malloc failed\n"));
135                         return( -1 );
136                 }
137         }
138
139         type = line;
140
141         s = strchr( type, ':' );
142
143         if ( s == NULL ) {
144                 ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
145                         _("ldif_parse_line: missing ':' after %s\n"),
146                         type );
147                 if ( !alloc ) ber_memfree( line );
148                 return( -1 );
149         }
150
151         /* trim any space between type and : */
152         for ( p = &s[-1]; p > type && isspace( * (unsigned char *) p ); p-- ) {
153                 *p = '\0';
154         }
155         *s++ = '\0';
156
157         url = 0;
158         b64 = 0;
159
160         if ( *s == '<' ) {
161                 s++;
162                 url = 1;
163
164         } else if ( *s == ':' ) {
165                 /* base 64 encoded value */
166                 s++;
167                 b64 = 1;
168         }
169
170         /* skip space between : and value */
171         while ( isspace( (unsigned char) *s ) ) {
172                 s++;
173         }
174
175         /* check for continued line markers that should be deleted */
176         for ( p = s, d = s; *p; p++ ) {
177                 if ( *p != CONTINUED_LINE_MARKER )
178                         *d++ = *p;
179         }
180         *d = '\0';
181
182         if ( b64 ) {
183                 char *byte = s;
184
185                 if ( *s == '\0' ) {
186                         /* no value is present, error out */
187                         ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
188                                 _("ldif_parse_line: %s missing base64 value\n"), type );
189                         if ( !alloc ) ber_memfree( line );
190                         return( -1 );
191                 }
192
193                 byte = value = s;
194
195                 for ( p = s, vlen = 0; p < d; p += 4, vlen += 3 ) {
196                         int i;
197                         for ( i = 0; i < 4; i++ ) {
198                                 if ( p[i] != '=' && (p[i] & 0x80 ||
199                                     b642nib[ p[i] & 0x7f ] > 0x3f) ) {
200                                         ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
201                                                 _("ldif_parse_line: %s: invalid base64 encoding"
202                                                 " char (%c) 0x%x\n"),
203                                             type, p[i], p[i] );
204                                         if ( !alloc ) ber_memfree( line );
205                                         return( -1 );
206                                 }
207                         }
208
209                         /* first digit */
210                         nib = b642nib[ p[0] & 0x7f ];
211                         byte[0] = nib << 2;
212                         /* second digit */
213                         nib = b642nib[ p[1] & 0x7f ];
214                         byte[0] |= nib >> 4;
215                         byte[1] = (nib & RIGHT4) << 4;
216                         /* third digit */
217                         if ( p[2] == '=' ) {
218                                 vlen += 1;
219                                 break;
220                         }
221                         nib = b642nib[ p[2] & 0x7f ];
222                         byte[1] |= nib >> 2;
223                         byte[2] = (nib & RIGHT2) << 6;
224                         /* fourth digit */
225                         if ( p[3] == '=' ) {
226                                 vlen += 2;
227                                 break;
228                         }
229                         nib = b642nib[ p[3] & 0x7f ];
230                         byte[2] |= nib;
231
232                         byte += 3;
233                 }
234                 s[ vlen ] = '\0';
235
236         } else if ( url ) {
237                 if ( *s == '\0' ) {
238                         /* no value is present, error out */
239                         ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
240                                 _("ldif_parse_line: %s missing URL value\n"), type );
241                         if ( !alloc ) ber_memfree( line );
242                         return( -1 );
243                 }
244
245                 if( ldif_fetch_url( s, &value, &vlen ) ) {
246                         ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
247                                 _("ldif_parse_line: %s: URL \"%s\" fetch failed\n"),
248                                 type, s );
249                         if ( !alloc ) ber_memfree( line );
250                         return( -1 );
251                 }
252                 if ( alloc ) *alloc = 1;
253
254         } else {
255                 value = s;
256                 vlen = (int) (d - s);
257         }
258
259         if ( !alloc ) {
260                 type = ber_strdup( type );
261
262                 if( type == NULL ) {
263                         ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
264                                 _("ldif_parse_line: type malloc failed\n"));
265                         if( url ) ber_memfree( value );
266                         ber_memfree( line );
267                         return( -1 );
268                 }
269
270                 if( !url ) {
271                         p = ber_memalloc( vlen + 1 );
272                         if( p == NULL ) {
273                                 ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
274                                         _("ldif_parse_line: value malloc failed\n"));
275                                 ber_memfree( type );
276                                 ber_memfree( line );
277                                 return( -1 );
278                         }
279                         AC_MEMCPY( p, value, vlen );
280                         p[vlen] = '\0';
281                         value = p;
282                 }
283
284                 ber_memfree( line );
285         }
286
287         *typep = type;
288         *valuep = value;
289         *vlenp = vlen;
290
291         return( 0 );
292 }
293
294 /*
295  * ldif_getline - return the next "line" (minus newline) of input from a
296  * string buffer of lines separated by newlines, terminated by \n\n
297  * or \0.  this routine handles continued lines, bundling them into
298  * a single big line before returning.  if a line begins with a white
299  * space character, it is a continuation of the previous line. the white
300  * space character (nb: only one char), and preceeding newline are changed
301  * into CONTINUED_LINE_MARKER chars, to be deleted later by the
302  * ldif_parse_line() routine above.
303  *
304  * ldif_getline will skip over any line which starts '#'.
305  *
306  * ldif_getline takes a pointer to a pointer to the buffer on the first call,
307  * which it updates and must be supplied on subsequent calls.
308  */
309
310 char *
311 ldif_getline( char **next )
312 {
313         char *line;
314
315         do {
316                 if ( *next == NULL || **next == '\n' || **next == '\0' ) {
317                         return( NULL );
318                 }
319
320                 line = *next;
321
322                 while ( (*next = strchr( *next, '\n' )) != NULL ) {
323 #if CONTINUED_LINE_MARKER != '\r'
324                         if ( (*next)[-1] == '\r' ) {
325                                 (*next)[-1] = CONTINUED_LINE_MARKER;
326                         }
327 #endif
328
329                         if ( (*next)[1] != ' ' ) {
330                                 if ( (*next)[1] == '\r' && (*next)[2] == '\n' ) {
331                                         *(*next)++ = '\0';
332                                 }
333                                 *(*next)++ = '\0';
334                                 break;
335                         }
336
337                         **next = CONTINUED_LINE_MARKER;
338                         (*next)[1] = CONTINUED_LINE_MARKER;
339                         (*next)++;
340                 }
341         } while( *line == '#' );
342
343         return( line );
344 }
345
346 /* compatibility with U-Mich off by one bug */
347 #define LDIF_KLUDGE 1
348
349 void
350 ldif_sput(
351         char **out,
352         int type,
353         LDAP_CONST char *name,
354         LDAP_CONST char *val,
355         ber_len_t vlen )
356 {
357         const unsigned char *byte, *stop;
358         unsigned char   buf[3];
359         unsigned long   bits;
360         char            *save;
361         int             pad;
362         int             namelen = 0;
363
364         ber_len_t savelen;
365         ber_len_t len=0;
366         ber_len_t i;
367
368         /* prefix */
369         switch( type ) {
370         case LDIF_PUT_COMMENT:
371                 *(*out)++ = '#';
372                 len++;
373
374                 if( vlen ) {
375                         *(*out)++ = ' ';
376                         len++;
377                 }
378
379                 break;
380
381         case LDIF_PUT_SEP:
382                 *(*out)++ = '\n';
383                 return;
384         }
385
386         /* name (attribute type) */
387         if( name != NULL ) {
388                 /* put the name + ":" */
389                 namelen = strlen(name);
390                 strcpy(*out, name);
391                 *out += namelen;
392                 len += namelen;
393
394                 if( type != LDIF_PUT_COMMENT ) {
395                         *(*out)++ = ':';
396                         len++;
397                 }
398
399         }
400 #ifdef LDAP_DEBUG
401         else {
402                 assert( type == LDIF_PUT_COMMENT );
403         }
404 #endif
405
406         if( vlen == 0 ) {
407                 *(*out)++ = '\n';
408                 return;
409         }
410
411         switch( type ) {
412         case LDIF_PUT_NOVALUE:
413                 *(*out)++ = '\n';
414                 return;
415
416         case LDIF_PUT_URL: /* url value */
417                 *(*out)++ = '<';
418                 len++;
419                 break;
420
421         case LDIF_PUT_B64: /* base64 value */
422                 *(*out)++ = ':';
423                 len++;
424                 break;
425         }
426
427         switch( type ) {
428         case LDIF_PUT_TEXT:
429         case LDIF_PUT_URL:
430         case LDIF_PUT_B64:
431                 *(*out)++ = ' ';
432                 len++;
433                 /* fall-thru */
434
435         case LDIF_PUT_COMMENT:
436                 /* pre-encoded names */
437                 for ( i=0; i < vlen; i++ ) {
438                         if ( len > LDIF_LINE_WIDTH ) {
439                                 *(*out)++ = '\n';
440                                 *(*out)++ = ' ';
441                                 len = 1;
442                         }
443
444                         *(*out)++ = val[i];
445                         len++;
446                 }
447                 *(*out)++ = '\n';
448                 return;
449         }
450
451         save = *out;
452         savelen = len;
453
454         *(*out)++ = ' ';
455         len++;
456
457         stop = (const unsigned char *) (val + vlen);
458
459         if ( type == LDIF_PUT_VALUE
460                 && isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<'
461                 && isgraph( (unsigned char) val[vlen-1] )
462 #ifndef LDAP_BINARY_DEBUG
463                 && strstr( name, ";binary" ) == NULL
464 #endif
465 #ifndef LDAP_PASSWD_DEBUG
466                 && (namelen != (sizeof("userPassword")-1)
467                 || strcasecmp( name, "userPassword" ) != 0)     /* encode userPassword */
468                 && (namelen != (sizeof("2.5.4.35")-1) 
469                 || strcasecmp( name, "2.5.4.35" ) != 0)         /* encode userPassword */
470 #endif
471         ) {
472                 int b64 = 0;
473
474                 for ( byte = (const unsigned char *) val; byte < stop;
475                     byte++, len++ )
476                 {
477                         if ( !isascii( *byte ) || !isprint( *byte ) ) {
478                                 b64 = 1;
479                                 break;
480                         }
481                         if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
482                                 *(*out)++ = '\n';
483                                 *(*out)++ = ' ';
484                                 len = 1;
485                         }
486                         *(*out)++ = *byte;
487                 }
488
489                 if( !b64 ) {
490                         *(*out)++ = '\n';
491                         return;
492                 }
493         }
494
495         *out = save;
496         *(*out)++ = ':';
497         *(*out)++ = ' ';
498         len = savelen + 2;
499
500         /* convert to base 64 (3 bytes => 4 base 64 digits) */
501         for ( byte = (const unsigned char *) val;
502                 byte < stop - 2;
503             byte += 3 )
504         {
505                 bits = (byte[0] & 0xff) << 16;
506                 bits |= (byte[1] & 0xff) << 8;
507                 bits |= (byte[2] & 0xff);
508
509                 for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
510                         if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
511                                 *(*out)++ = '\n';
512                                 *(*out)++ = ' ';
513                                 len = 1;
514                         }
515
516                         /* get b64 digit from high order 6 bits */
517                         *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
518                 }
519         }
520
521         /* add padding if necessary */
522         if ( byte < stop ) {
523                 for ( i = 0; byte + i < stop; i++ ) {
524                         buf[i] = byte[i];
525                 }
526                 for ( pad = 0; i < 3; i++, pad++ ) {
527                         buf[i] = '\0';
528                 }
529                 byte = buf;
530                 bits = (byte[0] & 0xff) << 16;
531                 bits |= (byte[1] & 0xff) << 8;
532                 bits |= (byte[2] & 0xff);
533
534                 for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
535                         if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
536                                 *(*out)++ = '\n';
537                                 *(*out)++ = ' ';
538                                 len = 1;
539                         }
540
541                         if( i + pad < 4 ) {
542                                 /* get b64 digit from low order 6 bits */
543                                 *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
544                         } else {
545                                 *(*out)++ = '=';
546                         }
547                 }
548         }
549         *(*out)++ = '\n';
550 }
551
552
553 /*
554  * ldif_type_and_value return BER malloc'd, zero-terminated LDIF line
555  */
556 char *
557 ldif_put(
558         int type,
559         LDAP_CONST char *name,
560         LDAP_CONST char *val,
561         ber_len_t vlen )
562 {
563     char        *buf, *p;
564     ber_len_t nlen;
565
566     nlen = ( name != NULL ) ? strlen( name ) : 0;
567
568         buf = (char *) ber_memalloc( LDIF_SIZE_NEEDED( nlen, vlen ) + 1 );
569
570     if ( buf == NULL ) {
571                 ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
572                         _("ldif_type_and_value: malloc failed!"));
573                 return NULL;
574     }
575
576     p = buf;
577     ldif_sput( &p, type, name, val, vlen );
578     *p = '\0';
579
580     return( buf );
581 }
582
583 int ldif_is_not_printable(
584         LDAP_CONST char *val,
585         ber_len_t vlen )
586 {
587         if( vlen == 0 || val == NULL  ) {
588                 return -1;
589         }
590
591         if( isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<' &&
592                 isgraph( (unsigned char) val[vlen-1] ) )
593         {
594                 ber_len_t i;
595
596                 for ( i = 0; val[i]; i++ ) {
597                         if ( !isascii( val[i] ) || !isprint( val[i] ) ) {
598                                 return 1;
599                         }
600                 }
601
602                 return 0;
603         }
604
605         return 1;
606 }
607
608 /*
609  * slap_read_ldif - read an ldif record.  Return 1 for success, 0 for EOF.
610  */
611 int
612 ldif_read_record(
613         FILE        *fp,
614         int         *lno,               /* ptr to line number counter              */
615         char        **bufp,     /* ptr to malloced output buffer           */
616         int         *buflenp )  /* ptr to length of *bufp                  */
617 {
618         char        linebuf[BUFSIZ], *line, *nbufp;
619         ber_len_t   lcur = 0, len, linesize;
620         int         last_ch = '\n', found_entry = 0, stop, top_comment = 0;
621
622         line     = linebuf;
623         linesize = sizeof( linebuf );
624
625         for ( stop = feof( fp );  !stop;  last_ch = line[len-1] ) {
626                 if ( fgets( line, linesize, fp ) == NULL ) {
627                         stop = 1;
628                         /* Add \n in case the file does not end with newline */
629                         line = "\n";
630                 }
631                 len = strlen( line );
632
633                 if ( last_ch == '\n' ) {
634                         (*lno)++;
635
636                         if ( line[0] == '\n' ) {
637                                 if ( !found_entry ) {
638                                         lcur = 0;
639                                         top_comment = 0;
640                                         continue;
641                                 }
642                                 break;
643                         }
644
645                         if ( !found_entry ) {
646                                 if ( line[0] == '#' ) {
647                                         top_comment = 1;
648                                 } else if ( ! ( top_comment && line[0] == ' ' ) ) {
649                                         /* Found a new entry */
650                                         found_entry = 1;
651
652                                         if ( isdigit( (unsigned char) line[0] ) ) {
653                                                 /* skip index */
654                                                 continue;
655                                         }
656                                 }
657                         }                       
658                 }
659
660                 if ( *buflenp - lcur <= len ) {
661                         *buflenp += len + BUFSIZ;
662                         nbufp = ber_memrealloc( *bufp, *buflenp );
663                         if( nbufp == NULL ) {
664                                 return 0;
665                         }
666                         *bufp = nbufp;
667                 }
668                 strcpy( *bufp + lcur, line );
669                 lcur += len;
670         }
671
672         return( found_entry );
673 }