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