]> git.sur5r.net Git - openldap/blob - libraries/liblutil/ldif.c
Move LDIF routines liblutil
[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-2003 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.
85  */
86
87 int
88 ldif_parse_line(
89     LDAP_CONST char     *line,
90     char        **typep,
91     char        **valuep,
92     ber_len_t *vlenp
93 )
94 {
95         char    *s, *p, *d; 
96         char    nib;
97         int     b64, url;
98         char    *freeme, *type, *value;
99         ber_len_t vlen;
100
101         *typep = NULL;
102         *valuep = NULL;
103         *vlenp = 0;
104
105         /* skip any leading space */
106         while ( isspace( (unsigned char) *line ) ) {
107                 line++;
108         }
109
110         freeme = ber_strdup( line );
111
112         if( freeme == NULL ) {
113                 ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
114                         _("ldif_parse_line: line malloc failed\n"));
115                 return( -1 );
116         }
117
118         type = freeme;
119
120         s = strchr( type, ':' );
121
122         if ( s == NULL ) {
123                 ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
124                         _("ldif_parse_line: missing ':' after %s\n"),
125                         type );
126                 ber_memfree( freeme );
127                 return( -1 );
128         }
129
130         /* trim any space between type and : */
131         for ( p = &s[-1]; p > type && isspace( * (unsigned char *) p ); p-- ) {
132                 *p = '\0';
133         }
134         *s++ = '\0';
135
136         url = 0;
137         b64 = 0;
138
139         if ( *s == '<' ) {
140                 s++;
141                 url = 1;
142
143         } else if ( *s == ':' ) {
144                 /* base 64 encoded value */
145                 s++;
146                 b64 = 1;
147         }
148
149         /* skip space between : and value */
150         while ( isspace( (unsigned char) *s ) ) {
151                 s++;
152         }
153
154         /* check for continued line markers that should be deleted */
155         for ( p = s, d = s; *p; p++ ) {
156                 if ( *p != CONTINUED_LINE_MARKER )
157                         *d++ = *p;
158         }
159         *d = '\0';
160
161         if ( b64 ) {
162                 char *byte = s;
163
164                 if ( *s == '\0' ) {
165                         /* no value is present, error out */
166                         ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
167                                 _("ldif_parse_line: %s missing base64 value\n"), type );
168                         ber_memfree( freeme );
169                         return( -1 );
170                 }
171
172                 byte = value = s;
173
174                 for ( p = s, vlen = 0; p < d; p += 4, vlen += 3 ) {
175                         int i;
176                         for ( i = 0; i < 4; i++ ) {
177                                 if ( p[i] != '=' && (p[i] & 0x80 ||
178                                     b642nib[ p[i] & 0x7f ] > 0x3f) ) {
179                                         ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
180                                                 _("ldif_parse_line: %s: invalid base64 encoding"
181                                                 " char (%c) 0x%x\n"),
182                                             type, p[i], p[i] );
183                                         ber_memfree( freeme );
184                                         return( -1 );
185                                 }
186                         }
187
188                         /* first digit */
189                         nib = b642nib[ p[0] & 0x7f ];
190                         byte[0] = nib << 2;
191                         /* second digit */
192                         nib = b642nib[ p[1] & 0x7f ];
193                         byte[0] |= nib >> 4;
194                         byte[1] = (nib & RIGHT4) << 4;
195                         /* third digit */
196                         if ( p[2] == '=' ) {
197                                 vlen += 1;
198                                 break;
199                         }
200                         nib = b642nib[ p[2] & 0x7f ];
201                         byte[1] |= nib >> 2;
202                         byte[2] = (nib & RIGHT2) << 6;
203                         /* fourth digit */
204                         if ( p[3] == '=' ) {
205                                 vlen += 2;
206                                 break;
207                         }
208                         nib = b642nib[ p[3] & 0x7f ];
209                         byte[2] |= nib;
210
211                         byte += 3;
212                 }
213                 s[ vlen ] = '\0';
214
215         } else if ( url ) {
216                 if ( *s == '\0' ) {
217                         /* no value is present, error out */
218                         ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
219                                 _("ldif_parse_line: %s missing URL value\n"), type );
220                         ber_memfree( freeme );
221                         return( -1 );
222                 }
223
224                 if( ldif_fetch_url( s, &value, &vlen ) ) {
225                         ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
226                                 _("ldif_parse_line: %s: URL \"%s\" fetch failed\n"),
227                                 type, s );
228                         ber_memfree( freeme );
229                         return( -1 );
230                 }
231
232         } else {
233                 value = s;
234                 vlen = (int) (d - s);
235         }
236
237         type = ber_strdup( type );
238
239         if( type == NULL ) {
240                 ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
241                         _("ldif_parse_line: type malloc failed\n"));
242                 if( url ) ber_memfree( value );
243                 ber_memfree( freeme );
244                 return( -1 );
245         }
246
247         if( !url ) {
248                 p = ber_memalloc( vlen + 1 );
249                 if( p == NULL ) {
250                         ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
251                                 _("ldif_parse_line: value malloc failed\n"));
252                         ber_memfree( type );
253                         ber_memfree( freeme );
254                         return( -1 );
255                 }
256                 AC_MEMCPY( p, value, vlen );
257                 p[vlen] = '\0';
258                 value = p;
259         }
260
261         ber_memfree( freeme );
262
263         *typep = type;
264         *valuep = value;
265         *vlenp = vlen;
266
267         return( 0 );
268 }
269
270 /*
271  * ldif_getline - return the next "line" (minus newline) of input from a
272  * string buffer of lines separated by newlines, terminated by \n\n
273  * or \0.  this routine handles continued lines, bundling them into
274  * a single big line before returning.  if a line begins with a white
275  * space character, it is a continuation of the previous line. the white
276  * space character (nb: only one char), and preceeding newline are changed
277  * into CONTINUED_LINE_MARKER chars, to be deleted later by the
278  * ldif_parse_line() routine above.
279  *
280  * ldif_getline will skip over any line which starts '#'.
281  *
282  * ldif_getline takes a pointer to a pointer to the buffer on the first call,
283  * which it updates and must be supplied on subsequent calls.
284  */
285
286 char *
287 ldif_getline( char **next )
288 {
289         char *line;
290
291         do {
292                 if ( *next == NULL || **next == '\n' || **next == '\0' ) {
293                         return( NULL );
294                 }
295
296                 line = *next;
297
298                 while ( (*next = strchr( *next, '\n' )) != NULL ) {
299 #if CONTINUED_LINE_MARKER != '\r'
300                         if ( (*next)[-1] == '\r' ) {
301                                 (*next)[-1] = CONTINUED_LINE_MARKER;
302                         }
303 #endif
304
305                         if ( (*next)[1] != ' ' ) {
306                                 if ( (*next)[1] == '\r' && (*next)[2] == '\n' ) {
307                                         *(*next)++ = '\0';
308                                 }
309                                 *(*next)++ = '\0';
310                                 break;
311                         }
312
313                         **next = CONTINUED_LINE_MARKER;
314                         (*next)[1] = CONTINUED_LINE_MARKER;
315                         (*next)++;
316                 }
317         } while( *line == '#' );
318
319         return( line );
320 }
321
322 /* compatibility with U-Mich off by one bug */
323 #define LDIF_KLUDGE 1
324
325 void
326 ldif_sput(
327         char **out,
328         int type,
329         LDAP_CONST char *name,
330         LDAP_CONST char *val,
331         ber_len_t vlen )
332 {
333         const unsigned char *byte, *stop;
334         unsigned char   buf[3];
335         unsigned long   bits;
336         char            *save;
337         int             pad;
338         int             namelen = 0;
339
340         ber_len_t savelen;
341         ber_len_t len=0;
342         ber_len_t i;
343
344         /* prefix */
345         switch( type ) {
346         case LDIF_PUT_COMMENT:
347                 *(*out)++ = '#';
348                 len++;
349
350                 if( vlen ) {
351                         *(*out)++ = ' ';
352                         len++;
353                 }
354
355                 break;
356
357         case LDIF_PUT_SEP:
358                 *(*out)++ = '\n';
359                 return;
360         }
361
362         /* name (attribute type) */
363         if( name != NULL ) {
364                 /* put the name + ":" */
365                 namelen = strlen(name);
366                 strcpy(*out, name);
367                 *out += namelen;
368                 len += namelen;
369
370                 if( type != LDIF_PUT_COMMENT ) {
371                         *(*out)++ = ':';
372                         len++;
373                 }
374
375         }
376 #ifdef LDAP_DEBUG
377         else {
378                 assert( type == LDIF_PUT_COMMENT );
379         }
380 #endif
381
382         if( vlen == 0 ) {
383                 *(*out)++ = '\n';
384                 return;
385         }
386
387         switch( type ) {
388         case LDIF_PUT_NOVALUE:
389                 *(*out)++ = '\n';
390                 return;
391
392         case LDIF_PUT_URL: /* url value */
393                 *(*out)++ = '<';
394                 len++;
395                 break;
396
397         case LDIF_PUT_B64: /* base64 value */
398                 *(*out)++ = ':';
399                 len++;
400                 break;
401         }
402
403         switch( type ) {
404         case LDIF_PUT_TEXT:
405         case LDIF_PUT_URL:
406         case LDIF_PUT_B64:
407                 *(*out)++ = ' ';
408                 len++;
409                 /* fall-thru */
410
411         case LDIF_PUT_COMMENT:
412                 /* pre-encoded names */
413                 for ( i=0; i < vlen; i++ ) {
414                         if ( len > LDIF_LINE_WIDTH ) {
415                                 *(*out)++ = '\n';
416                                 *(*out)++ = ' ';
417                                 len = 1;
418                         }
419
420                         *(*out)++ = val[i];
421                         len++;
422                 }
423                 *(*out)++ = '\n';
424                 return;
425         }
426
427         save = *out;
428         savelen = len;
429
430         *(*out)++ = ' ';
431         len++;
432
433         stop = (const unsigned char *) (val + vlen);
434
435         if ( type == LDIF_PUT_VALUE
436                 && isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<'
437                 && isgraph( (unsigned char) val[vlen-1] )
438 #ifndef LDAP_BINARY_DEBUG
439                 && strstr( name, ";binary" ) == NULL
440 #endif
441 #ifndef LDAP_PASSWD_DEBUG
442                 && (namelen != (sizeof("userPassword")-1)
443                 || strcasecmp( name, "userPassword" ) != 0)     /* encode userPassword */
444                 && (namelen != (sizeof("2.5.4.35")-1) 
445                 || strcasecmp( name, "2.5.4.35" ) != 0)         /* encode userPassword */
446 #endif
447         ) {
448                 int b64 = 0;
449
450                 for ( byte = (const unsigned char *) val; byte < stop;
451                     byte++, len++ )
452                 {
453                         if ( !isascii( *byte ) || !isprint( *byte ) ) {
454                                 b64 = 1;
455                                 break;
456                         }
457                         if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
458                                 *(*out)++ = '\n';
459                                 *(*out)++ = ' ';
460                                 len = 1;
461                         }
462                         *(*out)++ = *byte;
463                 }
464
465                 if( !b64 ) {
466                         *(*out)++ = '\n';
467                         return;
468                 }
469         }
470
471         *out = save;
472         *(*out)++ = ':';
473         *(*out)++ = ' ';
474         len = savelen + 2;
475
476         /* convert to base 64 (3 bytes => 4 base 64 digits) */
477         for ( byte = (const unsigned char *) val;
478                 byte < stop - 2;
479             byte += 3 )
480         {
481                 bits = (byte[0] & 0xff) << 16;
482                 bits |= (byte[1] & 0xff) << 8;
483                 bits |= (byte[2] & 0xff);
484
485                 for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
486                         if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
487                                 *(*out)++ = '\n';
488                                 *(*out)++ = ' ';
489                                 len = 1;
490                         }
491
492                         /* get b64 digit from high order 6 bits */
493                         *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
494                 }
495         }
496
497         /* add padding if necessary */
498         if ( byte < stop ) {
499                 for ( i = 0; byte + i < stop; i++ ) {
500                         buf[i] = byte[i];
501                 }
502                 for ( pad = 0; i < 3; i++, pad++ ) {
503                         buf[i] = '\0';
504                 }
505                 byte = buf;
506                 bits = (byte[0] & 0xff) << 16;
507                 bits |= (byte[1] & 0xff) << 8;
508                 bits |= (byte[2] & 0xff);
509
510                 for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
511                         if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
512                                 *(*out)++ = '\n';
513                                 *(*out)++ = ' ';
514                                 len = 1;
515                         }
516
517                         if( i + pad < 4 ) {
518                                 /* get b64 digit from low order 6 bits */
519                                 *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
520                         } else {
521                                 *(*out)++ = '=';
522                         }
523                 }
524         }
525         *(*out)++ = '\n';
526 }
527
528
529 /*
530  * ldif_type_and_value return BER malloc'd, zero-terminated LDIF line
531  */
532 char *
533 ldif_put(
534         int type,
535         LDAP_CONST char *name,
536         LDAP_CONST char *val,
537         ber_len_t vlen )
538 {
539     char        *buf, *p;
540     ber_len_t nlen;
541
542     nlen = ( name != NULL ) ? strlen( name ) : 0;
543
544         buf = (char *) ber_memalloc( LDIF_SIZE_NEEDED( nlen, vlen ) + 1 );
545
546     if ( buf == NULL ) {
547                 ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
548                         _("ldif_type_and_value: malloc failed!"));
549                 return NULL;
550     }
551
552     p = buf;
553     ldif_sput( &p, type, name, val, vlen );
554     *p = '\0';
555
556     return( buf );
557 }
558
559 int ldif_is_not_printable(
560         LDAP_CONST char *val,
561         ber_len_t vlen )
562 {
563         if( vlen == 0 || val == NULL  ) {
564                 return -1;
565         }
566
567         if( isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<' &&
568                 isgraph( (unsigned char) val[vlen-1] ) )
569         {
570                 ber_len_t i;
571
572                 for ( i = 0; val[i]; i++ ) {
573                         if ( !isascii( val[i] ) || !isprint( val[i] ) ) {
574                                 return 1;
575                         }
576                 }
577
578                 return 0;
579         }
580
581         return 1;
582 }
583
584 /*
585  * slap_read_ldif - read an ldif record.  Return 1 for success, 0 for EOF.
586  */
587 int
588 ldif_read_record(
589         FILE        *fp,
590         int         *lno,               /* ptr to line number counter              */
591         char        **bufp,     /* ptr to malloced output buffer           */
592         int         *buflenp )  /* ptr to length of *bufp                  */
593 {
594         char        linebuf[BUFSIZ], *line, *nbufp;
595         ber_len_t   lcur = 0, len, linesize;
596         int         last_ch = '\n', found_entry = 0, stop, top_comment = 0;
597
598         line     = linebuf;
599         linesize = sizeof( linebuf );
600
601         for ( stop = feof( fp );  !stop;  last_ch = line[len-1] ) {
602                 if ( fgets( line, linesize, fp ) == NULL ) {
603                         stop = 1;
604                         /* Add \n in case the file does not end with newline */
605                         line = "\n";
606                 }
607                 len = strlen( line );
608
609                 if ( last_ch == '\n' ) {
610                         (*lno)++;
611
612                         if ( line[0] == '\n' ) {
613                                 if ( !found_entry ) {
614                                         lcur = 0;
615                                         top_comment = 0;
616                                         continue;
617                                 }
618                                 break;
619                         }
620
621                         if ( !found_entry ) {
622                                 if ( line[0] == '#' ) {
623                                         top_comment = 1;
624                                 } else if ( ! ( top_comment && line[0] == ' ' ) ) {
625                                         /* Found a new entry */
626                                         found_entry = 1;
627
628                                         if ( isdigit( (unsigned char) line[0] ) ) {
629                                                 /* skip index */
630                                                 continue;
631                                         }
632                                 }
633                         }                       
634                 }
635
636                 if ( *buflenp - lcur <= len ) {
637                         *buflenp += len + BUFSIZ;
638                         nbufp = ber_memrealloc( *bufp, *buflenp );
639                         if( nbufp == NULL ) {
640                                 return 0;
641                         }
642                         *bufp = nbufp;
643                 }
644                 strcpy( *bufp + lcur, line );
645                 lcur += len;
646         }
647
648         return( found_entry );
649 }