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