xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/ldif.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
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