1 /*        $NetBSD: ldif.c,v 1.3 2021/08/14 16:14:56 christos Exp $    */
2 
3 /* ldif.c - routines for dealing with LDIF files */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2021 The OpenLDAP Foundation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 /* Portions Copyright (c) 1992-1996 Regents of the University of Michigan.
19  * All rights reserved.
20  *
21  * Redistribution and use in source and binary forms are permitted
22  * provided that this notice is preserved and that due credit is given
23  * to the University of Michigan at Ann Arbor.  The name of the
24  * University may not be used to endorse or promote products derived
25  * from this software without specific prior written permission.  This
26  * software is provided ``as is'' without express or implied warranty.
27  */
28 /* This work was originally developed by the University of Michigan
29  * and distributed as part of U-MICH LDAP.
30  */
31 
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: ldif.c,v 1.3 2021/08/14 16:14:56 christos Exp $");
34 
35 #include "portable.h"
36 
37 #include <stdio.h>
38 
39 #include <ac/stdlib.h>
40 #include <ac/ctype.h>
41 
42 #include <ac/string.h>
43 #include <ac/socket.h>
44 #include <ac/time.h>
45 
46 int ldif_debug = 0;
47 
48 #include "ldap-int.h"
49 #include "ldif.h"
50 
51 #define CONTINUED_LINE_MARKER '\r'
52 
53 #ifdef CSRIMALLOC
54 #define ber_memalloc malloc
55 #define ber_memcalloc calloc
56 #define ber_memrealloc realloc
57 #define ber_strdup strdup
58 #endif
59 
60 static const char nib2b64[0x40] =
61         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
62 
63 /*
64  * ldif_parse_line - takes a line of the form "type:[:] value" and splits it
65  * into components "type" and "value".  if a double colon separates type from
66  * value, then value is encoded in base 64, and parse_line un-decodes it
67  * (in place) before returning. The type and value are stored in malloc'd
68  * memory which must be freed by the caller.
69  *
70  * ldif_parse_line2 - operates in-place on input buffer, returning type
71  * in-place. Will return value in-place if possible, (must malloc for
72  * fetched URLs). If freeval is NULL, all return data will be malloc'd
73  * and the input line will be unmodified. Otherwise freeval is set to
74  * True if the value was malloc'd.
75  */
76 
77 int
ldif_parse_line(LDAP_CONST char * line,char ** typep,char ** valuep,ber_len_t * vlenp)78 ldif_parse_line(
79     LDAP_CONST char *line,
80     char  **typep,
81     char  **valuep,
82     ber_len_t *vlenp
83 )
84 {
85           struct berval type, value;
86           int rc = ldif_parse_line2( (char *)line, &type, &value, NULL );
87 
88           *typep = type.bv_val;
89           *valuep = value.bv_val;
90           *vlenp = value.bv_len;
91           return rc;
92 }
93 
94 int
ldif_parse_line2(char * line,struct berval * type,struct berval * value,int * freeval)95 ldif_parse_line2(
96     char  *line,
97           struct berval *type,
98           struct berval *value,
99           int                 *freeval
100 )
101 {
102           char      *s, *p, *d;
103           int       b64, url;
104 
105           BER_BVZERO( type );
106           BER_BVZERO( value );
107 
108           /* skip any leading space */
109           while ( isspace( (unsigned char) *line ) ) {
110                     line++;
111           }
112 
113           if ( freeval ) {
114                     *freeval = 0;
115           } else {
116                     line = ber_strdup( line );
117 
118                     if( line == NULL ) {
119                               ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
120                                         _("ldif_parse_line: line malloc failed\n"));
121                               return( -1 );
122                     }
123           }
124 
125           type->bv_val = line;
126 
127           s = strchr( type->bv_val, ':' );
128 
129           if ( s == NULL ) {
130                     ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
131                               _("ldif_parse_line: missing ':' after %s\n"),
132                               type->bv_val );
133                     if ( !freeval ) ber_memfree( line );
134                     return( -1 );
135           }
136 
137           /* trim any space between type and : */
138           for ( p = &s[-1]; p > type->bv_val && isspace( * (unsigned char *) p ); p-- ) {
139                     *p = '\0';
140           }
141           *s++ = '\0';
142           type->bv_len = s - type->bv_val - 1;
143 
144           url = 0;
145           b64 = 0;
146 
147           if ( *s == '<' ) {
148                     s++;
149                     url = 1;
150 
151           } else if ( *s == ':' ) {
152                     /* base 64 encoded value */
153                     s++;
154                     b64 = 1;
155           }
156 
157           /* skip space between : and value */
158           while ( isspace( (unsigned char) *s ) ) {
159                     s++;
160           }
161 
162           /* check for continued line markers that should be deleted */
163           for ( p = s, d = s; *p; p++ ) {
164                     if ( *p != CONTINUED_LINE_MARKER )
165                               *d++ = *p;
166           }
167           *d = '\0';
168 
169           if ( b64 ) {
170                     char *byte = s;
171 
172                     if ( *s == '\0' ) {
173                               /* no value is present, error out */
174                               ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
175                                         _("ldif_parse_line: %s missing base64 value\n"),
176                                         type->bv_val );
177                               if ( !freeval ) ber_memfree( line );
178                               return( -1 );
179                     }
180 
181                     value->bv_val = s;
182                     value->bv_len = d - s;
183                     if ( ldap_int_decode_b64_inplace( value ) != LDAP_SUCCESS ) {
184                               ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
185                                         _("ldif_parse_line: %s base64 decode failed\n"),
186                                         type->bv_val );
187                               if ( !freeval ) ber_memfree( line );
188                               return( -1 );
189                     }
190           } else if ( url ) {
191                     if ( *s == '\0' ) {
192                               /* no value is present, error out */
193                               ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
194                                         _("ldif_parse_line: %s missing URL value\n"),
195                                         type->bv_val );
196                               if ( !freeval ) ber_memfree( line );
197                               return( -1 );
198                     }
199 
200                     if( ldif_fetch_url( s, &value->bv_val, &value->bv_len ) ) {
201                               ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
202                                         _("ldif_parse_line: %s: URL \"%s\" fetch failed\n"),
203                                         type->bv_val, s );
204                               if ( !freeval ) ber_memfree( line );
205                               return( -1 );
206                     }
207                     if ( freeval ) *freeval = 1;
208 
209           } else {
210                     value->bv_val = s;
211                     value->bv_len = (int) (d - s);
212           }
213 
214           if ( !freeval ) {
215                     struct berval bv = *type;
216 
217                     ber_dupbv( type, &bv );
218 
219                     if( BER_BVISNULL( type )) {
220                               ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
221                                         _("ldif_parse_line: type malloc failed\n"));
222                               if( url ) ber_memfree( value->bv_val );
223                               ber_memfree( line );
224                               return( -1 );
225                     }
226 
227                     if( !url ) {
228                               bv = *value;
229                               ber_dupbv( value, &bv );
230                               if( BER_BVISNULL( value )) {
231                                         ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
232                                                   _("ldif_parse_line: value malloc failed\n"));
233                                         ber_memfree( type->bv_val );
234                                         ber_memfree( line );
235                                         return( -1 );
236                               }
237                     }
238 
239                     ber_memfree( line );
240           }
241 
242           return( 0 );
243 }
244 
245 /*
246  * ldif_getline - return the next "line" (minus newline) of input from a
247  * string buffer of lines separated by newlines, terminated by \n\n
248  * or \0.  this routine handles continued lines, bundling them into
249  * a single big line before returning.  if a line begins with a white
250  * space character, it is a continuation of the previous line. the white
251  * space character (nb: only one char), and preceding newline are changed
252  * into CONTINUED_LINE_MARKER chars, to be deleted later by the
253  * ldif_parse_line() routine above.
254  *
255  * ldif_getline will skip over any line which starts '#'.
256  *
257  * ldif_getline takes a pointer to a pointer to the buffer on the first call,
258  * which it updates and must be supplied on subsequent calls.
259  */
260 
261 int
ldif_countlines(LDAP_CONST char * buf)262 ldif_countlines( LDAP_CONST char *buf )
263 {
264           char *nl;
265           int ret = 0;
266 
267           if ( !buf ) return ret;
268 
269           for ( nl = strchr(buf, '\n'); nl; nl = strchr(nl, '\n') ) {
270                     nl++;
271                     if ( *nl != ' ' ) ret++;
272           }
273           return ret;
274 }
275 
276 char *
ldif_getline(char ** next)277 ldif_getline( char **next )
278 {
279           char *line;
280 
281           do {
282                     if ( *next == NULL || **next == '\n' || **next == '\0' ) {
283                               return( NULL );
284                     }
285 
286                     line = *next;
287 
288                     while ( (*next = strchr( *next, '\n' )) != NULL ) {
289 #if CONTINUED_LINE_MARKER != '\r'
290                               if ( (*next)[-1] == '\r' ) {
291                                         (*next)[-1] = CONTINUED_LINE_MARKER;
292                               }
293 #endif
294 
295                               if ( (*next)[1] != ' ' ) {
296                                         if ( (*next)[1] == '\r' && (*next)[2] == '\n' ) {
297                                                   *(*next)++ = '\0';
298                                         }
299                                         *(*next)++ = '\0';
300                                         break;
301                               }
302 
303                               **next = CONTINUED_LINE_MARKER;
304                               (*next)[1] = CONTINUED_LINE_MARKER;
305                               (*next)++;
306                     }
307           } while( *line == '#' );
308 
309           return( line );
310 }
311 
312 /*
313  * name and OID of attributeTypes that must be base64 encoded in any case
314  */
315 typedef struct must_b64_encode_s {
316           struct berval       name;
317           struct berval       oid;
318 } must_b64_encode_s;
319 
320 static must_b64_encode_s      default_must_b64_encode[] = {
321           { BER_BVC( "userPassword" ), BER_BVC( "2.5.4.35" ) },
322           { BER_BVNULL, BER_BVNULL }
323 };
324 
325 static must_b64_encode_s      *must_b64_encode = default_must_b64_encode;
326 
327 /*
328  * register name and OID of attributeTypes that must always be base64
329  * encoded
330  *
331  * NOTE: this routine mallocs memory in a static struct which must
332  * be explicitly freed when no longer required
333  */
334 int
ldif_must_b64_encode_register(LDAP_CONST char * name,LDAP_CONST char * oid)335 ldif_must_b64_encode_register( LDAP_CONST char *name, LDAP_CONST char *oid )
336 {
337           int                 i;
338           ber_len_t len;
339 
340           assert( must_b64_encode != NULL );
341           assert( name != NULL );
342           assert( oid != NULL );
343 
344           len = strlen( name );
345 
346           for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ ) {
347                     if ( len != must_b64_encode[i].name.bv_len ) {
348                               continue;
349                     }
350 
351                     if ( strcasecmp( name, must_b64_encode[i].name.bv_val ) == 0 ) {
352                               break;
353                     }
354           }
355 
356           if ( !BER_BVISNULL( &must_b64_encode[i].name ) ) {
357                     return 1;
358           }
359 
360           for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ )
361                     /* just count */ ;
362 
363           if ( must_b64_encode == default_must_b64_encode ) {
364                     must_b64_encode = ber_memalloc( sizeof( must_b64_encode_s ) * ( i + 2 ) );
365                     if ( must_b64_encode == NULL ) {
366                         return 1;
367                     }
368 
369                     for ( i = 0; !BER_BVISNULL( &default_must_b64_encode[i].name ); i++ ) {
370                               ber_dupbv( &must_b64_encode[i].name, &default_must_b64_encode[i].name );
371                               ber_dupbv( &must_b64_encode[i].oid, &default_must_b64_encode[i].oid );
372                     }
373 
374           } else {
375                     must_b64_encode_s   *tmp;
376 
377                     tmp = ber_memrealloc( must_b64_encode,
378                               sizeof( must_b64_encode_s ) * ( i + 2 ) );
379                     if ( tmp == NULL ) {
380                               return 1;
381                     }
382                     must_b64_encode = tmp;
383           }
384 
385           ber_str2bv( name, len, 1, &must_b64_encode[i].name );
386           ber_str2bv( oid, 0, 1, &must_b64_encode[i].oid );
387 
388           BER_BVZERO( &must_b64_encode[i + 1].name );
389 
390           return 0;
391 }
392 
393 void
ldif_must_b64_encode_release(void)394 ldif_must_b64_encode_release( void )
395 {
396           int       i;
397 
398           assert( must_b64_encode != NULL );
399 
400           if ( must_b64_encode == default_must_b64_encode ) {
401                     return;
402           }
403 
404           for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ ) {
405                     ber_memfree( must_b64_encode[i].name.bv_val );
406                     ber_memfree( must_b64_encode[i].oid.bv_val );
407           }
408 
409           ber_memfree( must_b64_encode );
410 
411           must_b64_encode = default_must_b64_encode;
412 }
413 
414 /*
415  * returns 1 iff the string corresponds to the name or the OID of any
416  * of the attributeTypes listed in must_b64_encode
417  */
418 static int
ldif_must_b64_encode(LDAP_CONST char * s)419 ldif_must_b64_encode( LDAP_CONST char *s )
420 {
421           int                 i;
422           struct berval       bv;
423 
424           assert( must_b64_encode != NULL );
425           assert( s != NULL );
426 
427           ber_str2bv( s, 0, 0, &bv );
428 
429           for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ ) {
430                     if ( ber_bvstrcasecmp( &must_b64_encode[i].name, &bv ) == 0
431                               || ber_bvcmp( &must_b64_encode[i].oid, &bv ) == 0 )
432                     {
433                               return 1;
434                     }
435           }
436 
437           return 0;
438 }
439 
440 /* NOTE: only preserved for binary compatibility */
441 void
ldif_sput(char ** out,int type,LDAP_CONST char * name,LDAP_CONST char * val,ber_len_t vlen)442 ldif_sput(
443           char **out,
444           int type,
445           LDAP_CONST char *name,
446           LDAP_CONST char *val,
447           ber_len_t vlen )
448 {
449           ldif_sput_wrap( out, type, name, val, vlen, 0 );
450 }
451 
452 void
ldif_sput_wrap(char ** out,int type,LDAP_CONST char * name,LDAP_CONST char * val,ber_len_t vlen,ber_len_t wrap)453 ldif_sput_wrap(
454           char **out,
455           int type,
456           LDAP_CONST char *name,
457           LDAP_CONST char *val,
458           ber_len_t vlen,
459         ber_len_t wrap )
460 {
461           const unsigned char *byte, *stop;
462           unsigned char       buf[3];
463           unsigned long       bits;
464           char                *save;
465           int                 pad;
466           int                 namelen = 0;
467 
468           ber_len_t savelen;
469           ber_len_t len=0;
470           ber_len_t i;
471 
472           if ( !wrap )
473                     wrap = LDIF_LINE_WIDTH;
474 
475           /* prefix */
476           switch( type ) {
477           case LDIF_PUT_COMMENT:
478                     *(*out)++ = '#';
479                     len++;
480 
481                     if( vlen ) {
482                               *(*out)++ = ' ';
483                               len++;
484                     }
485 
486                     break;
487 
488           case LDIF_PUT_SEP:
489                     *(*out)++ = '\n';
490                     return;
491           }
492 
493           /* name (attribute type) */
494           if( name != NULL ) {
495                     /* put the name + ":" */
496                     namelen = strlen(name);
497                     strcpy(*out, name);
498                     *out += namelen;
499                     len += namelen;
500 
501                     if( type != LDIF_PUT_COMMENT ) {
502                               *(*out)++ = ':';
503                               len++;
504                     }
505 
506           }
507 #ifdef LDAP_DEBUG
508           else {
509                     assert( type == LDIF_PUT_COMMENT );
510           }
511 #endif
512 
513           if( vlen == 0 ) {
514                     *(*out)++ = '\n';
515                     return;
516           }
517 
518           switch( type ) {
519           case LDIF_PUT_NOVALUE:
520                     *(*out)++ = '\n';
521                     return;
522 
523           case LDIF_PUT_URL: /* url value */
524                     *(*out)++ = '<';
525                     len++;
526                     break;
527 
528           case LDIF_PUT_B64: /* base64 value */
529                     *(*out)++ = ':';
530                     len++;
531                     break;
532           }
533 
534           switch( type ) {
535           case LDIF_PUT_TEXT:
536           case LDIF_PUT_URL:
537           case LDIF_PUT_B64:
538                     *(*out)++ = ' ';
539                     len++;
540                     /* fall-thru */
541 
542           case LDIF_PUT_COMMENT:
543                     /* pre-encoded names */
544                     for ( i=0; i < vlen; i++ ) {
545                               if ( len > wrap ) {
546                                         *(*out)++ = '\n';
547                                         *(*out)++ = ' ';
548                                         len = 1;
549                               }
550 
551                               *(*out)++ = val[i];
552                               len++;
553                     }
554                     *(*out)++ = '\n';
555                     return;
556           }
557 
558           save = *out;
559           savelen = len;
560 
561           *(*out)++ = ' ';
562           len++;
563 
564           stop = (const unsigned char *) (val + vlen);
565 
566           if ( type == LDIF_PUT_VALUE
567                     && isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<'
568                     && isgraph( (unsigned char) val[vlen-1] )
569 #ifndef LDAP_BINARY_DEBUG
570                     && strstr( name, ";binary" ) == NULL
571 #endif
572 #ifndef LDAP_PASSWD_DEBUG
573                     && !ldif_must_b64_encode( name )
574 #endif
575           ) {
576                     int b64 = 0;
577 
578                     for ( byte = (const unsigned char *) val; byte < stop;
579                         byte++, len++ )
580                     {
581                               if ( !isascii( *byte ) || !isprint( *byte ) ) {
582                                         b64 = 1;
583                                         break;
584                               }
585                               if ( len >= wrap ) {
586                                         *(*out)++ = '\n';
587                                         *(*out)++ = ' ';
588                                         len = 1;
589                               }
590                               *(*out)++ = *byte;
591                     }
592 
593                     if( !b64 ) {
594                               *(*out)++ = '\n';
595                               return;
596                     }
597           }
598 
599           *out = save;
600           *(*out)++ = ':';
601           *(*out)++ = ' ';
602           len = savelen + 2;
603 
604           /* convert to base 64 (3 bytes => 4 base 64 digits) */
605           for ( byte = (const unsigned char *) val;
606                     byte < stop - 2;
607               byte += 3 )
608           {
609                     bits = (byte[0] & 0xff) << 16;
610                     bits |= (byte[1] & 0xff) << 8;
611                     bits |= (byte[2] & 0xff);
612 
613                     for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
614                               if ( len >= wrap ) {
615                                         *(*out)++ = '\n';
616                                         *(*out)++ = ' ';
617                                         len = 1;
618                               }
619 
620                               /* get b64 digit from high order 6 bits */
621                               *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
622                     }
623           }
624 
625           /* add padding if necessary */
626           if ( byte < stop ) {
627                     for ( i = 0; byte + i < stop; i++ ) {
628                               buf[i] = byte[i];
629                     }
630                     for ( pad = 0; i < 3; i++, pad++ ) {
631                               buf[i] = '\0';
632                     }
633                     byte = buf;
634                     bits = (byte[0] & 0xff) << 16;
635                     bits |= (byte[1] & 0xff) << 8;
636                     bits |= (byte[2] & 0xff);
637 
638                     for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
639                               if ( len >= wrap ) {
640                                         *(*out)++ = '\n';
641                                         *(*out)++ = ' ';
642                                         len = 1;
643                               }
644 
645                               if( i + pad < 4 ) {
646                                         /* get b64 digit from low order 6 bits */
647                                         *(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
648                               } else {
649                                         *(*out)++ = '=';
650                               }
651                     }
652           }
653           *(*out)++ = '\n';
654 }
655 
656 
657 /*
658  * ldif_type_and_value return BER malloc'd, zero-terminated LDIF line
659  */
660 
661 /* NOTE: only preserved for binary compatibility */
662 char *
ldif_put(int type,LDAP_CONST char * name,LDAP_CONST char * val,ber_len_t vlen)663 ldif_put(
664           int type,
665           LDAP_CONST char *name,
666           LDAP_CONST char *val,
667           ber_len_t vlen )
668 {
669           return ldif_put_wrap( type, name, val, vlen, 0 );
670 }
671 
672 char *
ldif_put_wrap(int type,LDAP_CONST char * name,LDAP_CONST char * val,ber_len_t vlen,ber_len_t wrap)673 ldif_put_wrap(
674           int type,
675           LDAP_CONST char *name,
676           LDAP_CONST char *val,
677           ber_len_t vlen,
678           ber_len_t wrap )
679 {
680     char  *buf, *p;
681     ber_len_t nlen;
682 
683     nlen = ( name != NULL ) ? strlen( name ) : 0;
684 
685           buf = (char *) ber_memalloc( LDIF_SIZE_NEEDED_WRAP( nlen, vlen, wrap ) + 1 );
686 
687     if ( buf == NULL ) {
688                     ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
689                               _("ldif_type_and_value: malloc failed!"));
690                     return NULL;
691     }
692 
693     p = buf;
694     ldif_sput_wrap( &p, type, name, val, vlen, wrap );
695     *p = '\0';
696 
697     return( buf );
698 }
699 
ldif_is_not_printable(LDAP_CONST char * val,ber_len_t vlen)700 int ldif_is_not_printable(
701           LDAP_CONST char *val,
702           ber_len_t vlen )
703 {
704           if( vlen == 0 || val == NULL  ) {
705                     return -1;
706           }
707 
708           if( isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<' &&
709                     isgraph( (unsigned char) val[vlen-1] ) )
710           {
711                     ber_len_t i;
712 
713                     for ( i = 0; val[i]; i++ ) {
714                               if ( !isascii( val[i] ) || !isprint( (unsigned char) val[i] ) ) {
715                                         return 1;
716                               }
717                     }
718 
719                     return 0;
720           }
721 
722           return 1;
723 }
724 
725 LDIFFP *
ldif_open(LDAP_CONST char * file,LDAP_CONST char * mode)726 ldif_open(
727           LDAP_CONST char *file,
728           LDAP_CONST char *mode
729 )
730 {
731           FILE *fp = fopen( file, mode );
732           LDIFFP *lfp = NULL;
733 
734           if ( fp ) {
735                     lfp = ber_memalloc( sizeof( LDIFFP ));
736                     if ( lfp == NULL ) {
737                         return NULL;
738                     }
739                     lfp->fp = fp;
740                     lfp->prev = NULL;
741           }
742           return lfp;
743 }
744 
745 LDIFFP *
ldif_open_mem(char * ldif,size_t size,LDAP_CONST char * mode)746 ldif_open_mem(
747           char *ldif,
748           size_t size,
749           LDAP_CONST char *mode
750 )
751 {
752 #ifdef HAVE_FMEMOPEN
753           FILE *fp = fmemopen( ldif, size, mode );
754           LDIFFP *lfp = NULL;
755 
756           if ( fp ) {
757                     lfp = ber_memalloc( sizeof( LDIFFP ));
758                     lfp->fp = fp;
759                     lfp->prev = NULL;
760           }
761           return lfp;
762 #else /* !HAVE_FMEMOPEN */
763           return NULL;
764 #endif /* !HAVE_FMEMOPEN */
765 }
766 
767 void
ldif_close(LDIFFP * lfp)768 ldif_close(
769           LDIFFP *lfp
770 )
771 {
772           LDIFFP *prev;
773 
774           while ( lfp ) {
775                     fclose( lfp->fp );
776                     prev = lfp->prev;
777                     ber_memfree( lfp );
778                     lfp = prev;
779           }
780 }
781 
782 #define   LDIF_MAXLINE        4096
783 
784 /*
785  * ldif_read_record - read an ldif record.  Return 1 for success, 0 for EOF,
786  * -1 for error.
787  */
788 int
ldif_read_record(LDIFFP * lfp,unsigned long * lno,char ** bufp,int * buflenp)789 ldif_read_record(
790           LDIFFP      *lfp,
791           unsigned long *lno,           /* ptr to line number counter              */
792           char        **bufp,     /* ptr to malloced output buffer           */
793           int         *buflenp )  /* ptr to length of *bufp                  */
794 {
795           char        line[LDIF_MAXLINE], *nbufp;
796           ber_len_t   lcur = 0, len;
797           int         last_ch = '\n', found_entry = 0, stop, top_comment = 0;
798 
799           for ( stop = 0;  !stop;  last_ch = line[len-1] ) {
800                     /* If we're at the end of this file, see if we should pop
801                      * back to a previous file. (return from an include)
802                      */
803                     while ( feof( lfp->fp )) {
804                               if ( lfp->prev ) {
805                                         LDIFFP *tmp = lfp->prev;
806                                         fclose( lfp->fp );
807                                         *lfp = *tmp;
808                                         ber_memfree( tmp );
809                               } else {
810                                         stop = 1;
811                                         break;
812                               }
813                     }
814                     if ( !stop ) {
815                               if ( fgets( line, sizeof( line ), lfp->fp ) == NULL ) {
816                                         stop = 1;
817                                         len = 0;
818                               } else {
819                                         len = strlen( line );
820                               }
821                     }
822 
823                     if ( stop ) {
824                               /* Add \n in case the file does not end with newline */
825                               if (last_ch != '\n') {
826                                         len = 1;
827                                         line[0] = '\n';
828                                         line[1] = '\0';
829                                         goto last;
830                               }
831                               break;
832                     }
833 
834                     /* Squash \r\n to \n */
835                     if ( len > 1 && line[len-2] == '\r' ) {
836                               len--;
837                               line[len]   = '\0';
838                               line[len-1] = '\n';
839                     }
840 
841                     if ( last_ch == '\n' ) {
842                               (*lno)++;
843 
844                               if ( line[0] == '\n' ) {
845                                         if ( !found_entry ) {
846                                                   lcur = 0;
847                                                   top_comment = 0;
848                                                   continue;
849                                         }
850                                         break;
851                               }
852 
853                               if ( !found_entry ) {
854                                         if ( line[0] == '#' ) {
855                                                   top_comment = 1;
856                                         } else if ( ! ( top_comment && line[0] == ' ' ) ) {
857                                                   /* Found a new entry */
858                                                   found_entry = 1;
859 
860                                                   if ( isdigit( (unsigned char) line[0] ) ) {
861                                                             /* skip index */
862                                                             continue;
863                                                   }
864                                                   if ( !strncasecmp( line, "include:",
865                                                             STRLENOF("include:"))) {
866                                                             FILE *fp2;
867                                                             char *ptr;
868                                                             found_entry = 0;
869 
870                                                             if ( line[len-1] == '\n' ) {
871                                                                       len--;
872                                                                       line[len] = '\0';
873                                                             }
874 
875                                                             ptr = line + STRLENOF("include:");
876                                                             while (isspace((unsigned char) *ptr)) ptr++;
877                                                             fp2 = ldif_open_url( ptr );
878                                                             if ( fp2 ) {
879                                                                       LDIFFP *lnew = ber_memalloc( sizeof( LDIFFP ));
880                                                                       if ( lnew == NULL ) {
881                                                                                 fclose( fp2 );
882                                                                                 return 0;
883                                                                       }
884                                                                       lnew->prev = lfp->prev;
885                                                                       lnew->fp = lfp->fp;
886                                                                       lfp->prev = lnew;
887                                                                       lfp->fp = fp2;
888                                                                       line[len] = '\n';
889                                                                       len++;
890                                                                       continue;
891                                                             } else {
892                                                                       /* We failed to open the file, this should
893                                                                        * be reported as an error somehow.
894                                                                        */
895                                                                       ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
896                                                                                 _("ldif_read_record: include %s failed\n"), ptr );
897                                                                       return -1;
898                                                             }
899                                                   }
900                                         }
901                               }
902                     }
903 
904 last:
905                     if ( *buflenp - lcur <= len ) {
906                               *buflenp += len + LDIF_MAXLINE;
907                               nbufp = ber_memrealloc( *bufp, *buflenp );
908                               if( nbufp == NULL ) {
909                                         return 0;
910                               }
911                               *bufp = nbufp;
912                     }
913                     strcpy( *bufp + lcur, line );
914                     lcur += len;
915           }
916 
917           return( found_entry );
918 }
919