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