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