ldif.c 19.1 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
/* ldif.c - routines for dealing with LDIF files */
2
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
4
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Copyright 1998-2007 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */
/* Portions Copyright (c) 1992-1996 Regents of the University of Michigan.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that this notice is preserved and that due credit is given
 * to the University of Michigan at Ann Arbor.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.  This
 * software is provided ``as is'' without express or implied warranty.
 */
/* This work was originally developed by the University of Michigan
 * and distributed as part of U-MICH LDAP.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
28
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
29

30
31
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
32
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
33
34
35

#include <ac/stdlib.h>
#include <ac/ctype.h>
36
37
38
39
40

#include <ac/string.h>
#include <ac/socket.h>
#include <ac/time.h>

41
42
int ldif_debug = 0;

43
#include "ldap_log.h"
44
#include "lber_pvt.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
45
46
47
48
#include "ldif.h"

#define RIGHT2			0x03
#define RIGHT4			0x0f
Kurt Zeilenga's avatar
Kurt Zeilenga committed
49
#define CONTINUED_LINE_MARKER	'\r'
Kurt Zeilenga's avatar
Kurt Zeilenga committed
50

51
52
53
54
55
56
57
#ifdef CSRIMALLOC
#define ber_memalloc malloc
#define ber_memcalloc calloc
#define ber_memrealloc realloc
#define ber_strdup strdup
#endif

58
static const char nib2b64[0x40] =
Kurt Zeilenga's avatar
Kurt Zeilenga committed
59
60
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

61
static const unsigned char b642nib[0x80] = {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
	0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
	0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
	0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
	0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
	0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
	0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
	0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
	0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
};

/*
81
 * ldif_parse_line - takes a line of the form "type:[:] value" and splits it
Kurt Zeilenga's avatar
Kurt Zeilenga committed
82
83
 * into components "type" and "value".  if a double colon separates type from
 * value, then value is encoded in base 64, and parse_line un-decodes it
84
85
86
87
88
 * (in place) before returning. The type and value are stored in malloc'd
 * memory which must be freed by the caller.
 *
 * ldif_parse_line2 - operates in-place on input buffer, returning type
 * in-place. Will return value in-place if possible, (must malloc for
89
90
91
 * fetched URLs). If freeval is NULL, all return data will be malloc'd
 * and the input line will be unmodified. Otherwise freeval is set to
 * True if the value was malloc'd.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
92
93
94
 */

int
95
ldif_parse_line(
Kurt Zeilenga's avatar
Kurt Zeilenga committed
96
    LDAP_CONST char	*line,
97
98
99
    char	**typep,
    char	**valuep,
    ber_len_t *vlenp
Kurt Zeilenga's avatar
Kurt Zeilenga committed
100
)
101
{
102
103
104
105
106
107
108
	struct berval type, value;
	int rc = ldif_parse_line2( (char *)line, &type, &value, NULL );

	*typep = type.bv_val;
	*valuep = value.bv_val;
	*vlenp = value.bv_len;
	return rc;
109
110
111
112
}

int
ldif_parse_line2(
113
114
115
116
    char	*line,
	struct berval *type,
	struct berval *value,
	int		*freeval
117
)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
118
{
119
	char	*s, *p, *d; 
Kurt Zeilenga's avatar
Kurt Zeilenga committed
120
	char	nib;
121
122
	int	b64, url;

123
124
	BER_BVZERO( type );
	BER_BVZERO( value );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
125
126

	/* skip any leading space */
127
	while ( isspace( (unsigned char) *line ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
128
129
130
		line++;
	}

131
132
	if ( freeval ) {
		*freeval = 0;
133
134
	} else {
		line = ber_strdup( line );
135

136
137
138
139
140
		if( line == NULL ) {
			ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
				_("ldif_parse_line: line malloc failed\n"));
			return( -1 );
		}
141
142
	}

143
	type->bv_val = line;
144

145
	s = strchr( type->bv_val, ':' );
146
147

	if ( s == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
148
		ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
149
			_("ldif_parse_line: missing ':' after %s\n"),
Kurt Zeilenga's avatar
Kurt Zeilenga committed
150
			type->bv_val );
151
		if ( !freeval ) ber_memfree( line );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
152
153
154
155
		return( -1 );
	}

	/* trim any space between type and : */
156
	for ( p = &s[-1]; p > type->bv_val && isspace( * (unsigned char *) p ); p-- ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
157
158
159
		*p = '\0';
	}
	*s++ = '\0';
160
	type->bv_len = s - type->bv_val - 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
161

162
163
164
	url = 0;
	b64 = 0;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
165
	if ( *s == '<' ) {
166
167
		s++;
		url = 1;
168

169
170
	} else if ( *s == ':' ) {
		/* base 64 encoded value */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
171
172
173
174
175
		s++;
		b64 = 1;
	}

	/* skip space between : and value */
176
	while ( isspace( (unsigned char) *s ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
177
178
179
		s++;
	}

180
181
182
183
184
185
186
	/* check for continued line markers that should be deleted */
	for ( p = s, d = s; *p; p++ ) {
		if ( *p != CONTINUED_LINE_MARKER )
			*d++ = *p;
	}
	*d = '\0';

Kurt Zeilenga's avatar
Kurt Zeilenga committed
187
	if ( b64 ) {
188
189
		char *byte = s;

190
191
192
		if ( *s == '\0' ) {
			/* no value is present, error out */
			ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
193
194
				_("ldif_parse_line: %s missing base64 value\n"),
				type->bv_val );
195
			if ( !freeval ) ber_memfree( line );
196
			return( -1 );
197
198
		}

199
		byte = value->bv_val = s;
200

201
		for ( p = s, value->bv_len = 0; p < d; p += 4, value->bv_len += 3 ) {
202
			int i;
203
			for ( i = 0; i < 4; i++ ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
204
205
				if ( p[i] != '=' && (p[i] & 0x80 ||
				    b642nib[ p[i] & 0x7f ] > 0x3f) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
206
					ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
207
208
						_("ldif_parse_line: %s: invalid base64 encoding"
						" char (%c) 0x%x\n"),
Kurt Zeilenga's avatar
Kurt Zeilenga committed
209
					    type->bv_val, p[i], p[i] );
210
					if ( !freeval ) ber_memfree( line );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
211
212
213
214
215
216
217
218
219
220
221
222
223
					return( -1 );
				}
			}

			/* first digit */
			nib = b642nib[ p[0] & 0x7f ];
			byte[0] = nib << 2;
			/* second digit */
			nib = b642nib[ p[1] & 0x7f ];
			byte[0] |= nib >> 4;
			byte[1] = (nib & RIGHT4) << 4;
			/* third digit */
			if ( p[2] == '=' ) {
224
				value->bv_len += 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
225
226
227
228
229
230
231
				break;
			}
			nib = b642nib[ p[2] & 0x7f ];
			byte[1] |= nib >> 2;
			byte[2] = (nib & RIGHT2) << 6;
			/* fourth digit */
			if ( p[3] == '=' ) {
232
				value->bv_len += 2;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
233
234
235
236
237
238
239
				break;
			}
			nib = b642nib[ p[3] & 0x7f ];
			byte[2] |= nib;

			byte += 3;
		}
240
		s[ value->bv_len ] = '\0';
241
242

	} else if ( url ) {
243
244
245
		if ( *s == '\0' ) {
			/* no value is present, error out */
			ber_pvt_log_printf( LDAP_DEBUG_PARSE, ldif_debug,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
246
247
				_("ldif_parse_line: %s missing URL value\n"),
				type->bv_val );
248
			if ( !freeval ) ber_memfree( line );
249
			return( -1 );
250
251
		}

252
		if( ldif_fetch_url( s, &value->bv_val, &value->bv_len ) ) {
253
			ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
254
				_("ldif_parse_line: %s: URL \"%s\" fetch failed\n"),
Kurt Zeilenga's avatar
Kurt Zeilenga committed
255
				type->bv_val, s );
256
			if ( !freeval ) ber_memfree( line );
257
258
			return( -1 );
		}
259
		if ( freeval ) *freeval = 1;
260

Kurt Zeilenga's avatar
Kurt Zeilenga committed
261
	} else {
262
263
		value->bv_val = s;
		value->bv_len = (int) (d - s);
264
265
	}

266
267
268
269
	if ( !freeval ) {
		struct berval bv = *type;

		ber_dupbv( type, &bv );
270

271
		if( BER_BVISNULL( type )) {
272
			ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
273
				_("ldif_parse_line: type malloc failed\n"));
274
			if( url ) ber_memfree( value->bv_val );
275
			ber_memfree( line );
276
277
			return( -1 );
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
278

279
		if( !url ) {
280
281
282
			bv = *value;
			ber_dupbv( value, &bv );
			if( BER_BVISNULL( value )) {
283
284
				ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
					_("ldif_parse_line: value malloc failed\n"));
285
				ber_memfree( type->bv_val );
286
287
288
289
290
291
292
				ber_memfree( line );
				return( -1 );
			}
		}

		ber_memfree( line );
	}
293

Kurt Zeilenga's avatar
Kurt Zeilenga committed
294
295
296
297
	return( 0 );
}

/*
298
 * ldif_getline - return the next "line" (minus newline) of input from a
Kurt Zeilenga's avatar
Kurt Zeilenga committed
299
300
301
302
303
304
 * string buffer of lines separated by newlines, terminated by \n\n
 * or \0.  this routine handles continued lines, bundling them into
 * a single big line before returning.  if a line begins with a white
 * space character, it is a continuation of the previous line. the white
 * space character (nb: only one char), and preceeding newline are changed
 * into CONTINUED_LINE_MARKER chars, to be deleted later by the
Kurt Zeilenga's avatar
Kurt Zeilenga committed
305
 * ldif_parse_line() routine above.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
306
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
307
308
309
 * ldif_getline will skip over any line which starts '#'.
 *
 * ldif_getline takes a pointer to a pointer to the buffer on the first call,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
310
311
312
 * which it updates and must be supplied on subsequent calls.
 */

Howard Chu's avatar
Howard Chu committed
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
int
ldif_countlines( LDAP_CONST char *buf )
{
	char *nl;
	int ret = 0;

	if ( !buf ) return ret;

	for ( nl = strchr(buf, '\n'); nl; nl = strchr(nl, '\n') ) {
		nl++;
		if ( *nl != ' ' ) ret++;
	}
	return ret;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
328
char *
329
ldif_getline( char **next )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
330
{
331
	char *line;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
332

333
334
335
336
337
338
	do {
		if ( *next == NULL || **next == '\n' || **next == '\0' ) {
			return( NULL );
		}

		line = *next;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
339

340
		while ( (*next = strchr( *next, '\n' )) != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
341
342
343
344
345
#if CONTINUED_LINE_MARKER != '\r'
			if ( (*next)[-1] == '\r' ) {
				(*next)[-1] = CONTINUED_LINE_MARKER;
			}
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
346

Kurt Zeilenga's avatar
Kurt Zeilenga committed
347
348
			if ( (*next)[1] != ' ' ) {
				if ( (*next)[1] == '\r' && (*next)[2] == '\n' ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
349
350
351
352
					*(*next)++ = '\0';
				}
				*(*next)++ = '\0';
				break;
353
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
354
355

			**next = CONTINUED_LINE_MARKER;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
356
			(*next)[1] = CONTINUED_LINE_MARKER;
357
			(*next)++;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
358
		}
359
	} while( *line == '#' );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
360

361
	return( line );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
362
363
}

364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
/*
 * name and OID of attributeTypes that must be base64 encoded in any case
 */
typedef struct must_b64_encode_s {
	struct berval	name;
	struct berval	oid;
} must_b64_encode_s;

static must_b64_encode_s	default_must_b64_encode[] = {
	{ BER_BVC( "userPassword" ), BER_BVC( "2.5.4.35" ) },
	{ BER_BVNULL, BER_BVNULL }
};

static must_b64_encode_s	*must_b64_encode = default_must_b64_encode;

/*
 * register name and OID of attributeTypes that must always be base64 
 * encoded
 *
 * NOTE: this routine mallocs memory in a static struct which must 
 * be explicitly freed when no longer required
 */
int
ldif_must_b64_encode_register( LDAP_CONST char *name, LDAP_CONST char *oid )
{
	int		i;
	ber_len_t	len;

392
393
394
	assert( must_b64_encode != NULL );
	assert( name != NULL );
	assert( oid != NULL );
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446

	len = strlen( name );

	for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ ) {
		if ( len != must_b64_encode[i].name.bv_len ) {
			continue;
		}

		if ( strcasecmp( name, must_b64_encode[i].name.bv_val ) == 0 ) {
			break;
		}
	}

	if ( !BER_BVISNULL( &must_b64_encode[i].name ) ) {
		return 1;
	}

	for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ )
		/* just count */ ;

	if ( must_b64_encode == default_must_b64_encode ) {
		must_b64_encode = ber_memalloc( sizeof( must_b64_encode_s ) * ( i + 2 ) );

		for ( i = 0; !BER_BVISNULL( &default_must_b64_encode[i].name ); i++ ) {
			ber_dupbv( &must_b64_encode[i].name, &default_must_b64_encode[i].name );
			ber_dupbv( &must_b64_encode[i].oid, &default_must_b64_encode[i].oid );
		}

	} else {
		must_b64_encode_s	*tmp;

		tmp = ber_memrealloc( must_b64_encode,
			sizeof( must_b64_encode_s ) * ( i + 2 ) );
		if ( tmp == NULL ) {
			return 1;
		}
		must_b64_encode = tmp;
	}

	ber_str2bv( name, len, 1, &must_b64_encode[i].name );
	ber_str2bv( oid, 0, 1, &must_b64_encode[i].oid );

	BER_BVZERO( &must_b64_encode[i + 1].name );

	return 0;
}

void
ldif_must_b64_encode_release( void )
{
	int	i;

447
	assert( must_b64_encode != NULL );
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472

	if ( must_b64_encode == default_must_b64_encode ) {
		return;
	}

	for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ ) {
		ber_memfree( must_b64_encode[i].name.bv_val );
		ber_memfree( must_b64_encode[i].oid.bv_val );
	}

	ber_memfree( must_b64_encode );

	must_b64_encode = default_must_b64_encode;
}

/*
 * returns 1 iff the string corresponds to the name or the OID of any 
 * of the attributeTypes listed in must_b64_encode
 */
static int
ldif_must_b64_encode( LDAP_CONST char *s )
{
	int		i;
	struct berval	bv;

473
474
	assert( must_b64_encode != NULL );
	assert( s != NULL );
475
476
477
478
479

	ber_str2bv( s, 0, 0, &bv );

	for ( i = 0; !BER_BVISNULL( &must_b64_encode[i].name ); i++ ) {
		if ( ber_bvstrcasecmp( &must_b64_encode[i].name, &bv ) == 0
480
			|| ber_bvcmp( &must_b64_encode[i].oid, &bv ) == 0 )
481
482
483
484
485
486
487
488
		{
			return 1;
		}
	}

	return 0;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
489
490
491
/* compatibility with U-Mich off by one bug */
#define LDIF_KLUDGE 1

Kurt Zeilenga's avatar
Kurt Zeilenga committed
492
void
Kurt Zeilenga's avatar
Kurt Zeilenga committed
493
ldif_sput(
Kurt Zeilenga's avatar
Kurt Zeilenga committed
494
	char **out,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
495
496
	int type,
	LDAP_CONST char *name,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
497
	LDAP_CONST char *val,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
498
	ber_len_t vlen )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
499
{
500
	const unsigned char *byte, *stop;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
501
502
503
	unsigned char	buf[3];
	unsigned long	bits;
	char		*save;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
504
	int		pad;
Howard Chu's avatar
Howard Chu committed
505
	int		namelen = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521

	ber_len_t savelen;
	ber_len_t len=0;
	ber_len_t i;

	/* prefix */
	switch( type ) {
	case LDIF_PUT_COMMENT:
		*(*out)++ = '#';
		len++;

		if( vlen ) {
			*(*out)++ = ' ';
			len++;
		}

522
		break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
523

Kurt Zeilenga's avatar
Kurt Zeilenga committed
524
525
526
	case LDIF_PUT_SEP:
		*(*out)++ = '\n';
		return;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
527
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
528
529
530
531

	/* name (attribute type) */
	if( name != NULL ) {
		/* put the name + ":" */
Howard Chu's avatar
Howard Chu committed
532
533
534
535
		namelen = strlen(name);
		strcpy(*out, name);
		*out += namelen;
		len += namelen;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
536
537
538
539
540
541

		if( type != LDIF_PUT_COMMENT ) {
			*(*out)++ = ':';
			len++;
		}

Hallvard Furuseth's avatar
Hallvard Furuseth committed
542
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
543
#ifdef LDAP_DEBUG
Hallvard Furuseth's avatar
Hallvard Furuseth committed
544
	else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
545
546
		assert( type == LDIF_PUT_COMMENT );
	}
Hallvard Furuseth's avatar
Hallvard Furuseth committed
547
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
548

549
550
551
552
553
	if( vlen == 0 ) {
		*(*out)++ = '\n';
		return;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
	switch( type ) {
	case LDIF_PUT_NOVALUE:
		*(*out)++ = '\n';
		return;

	case LDIF_PUT_URL: /* url value */
		*(*out)++ = '<';
		len++;
		break;

	case LDIF_PUT_B64: /* base64 value */
		*(*out)++ = ':';
		len++;
		break;
	}

	switch( type ) {
	case LDIF_PUT_TEXT:
	case LDIF_PUT_URL:
	case LDIF_PUT_B64:
		*(*out)++ = ' ';
		len++;
		/* fall-thru */

	case LDIF_PUT_COMMENT:
		/* pre-encoded names */
		for ( i=0; i < vlen; i++ ) {
			if ( len > LDIF_LINE_WIDTH ) {
				*(*out)++ = '\n';
				*(*out)++ = ' ';
				len = 1;
			}

			*(*out)++ = val[i];
			len++;
		}
		*(*out)++ = '\n';
		return;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
594
595
	save = *out;
	savelen = len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
596

Kurt Zeilenga's avatar
Kurt Zeilenga committed
597
	*(*out)++ = ' ';
Kurt Zeilenga's avatar
Kurt Zeilenga committed
598
599
	len++;

600
	stop = (const unsigned char *) (val + vlen);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
601

Kurt Zeilenga's avatar
Kurt Zeilenga committed
602
	if ( type == LDIF_PUT_VALUE
603
604
		&& isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<'
		&& isgraph( (unsigned char) val[vlen-1] )
605
606
607
#ifndef LDAP_BINARY_DEBUG
		&& strstr( name, ";binary" ) == NULL
#endif
608
#ifndef LDAP_PASSWD_DEBUG
609
		&& !ldif_must_b64_encode( name )
610
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
611
	) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
612
613
		int b64 = 0;

614
		for ( byte = (const unsigned char *) val; byte < stop;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
615
616
		    byte++, len++ )
		{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
617
618
619
620
			if ( !isascii( *byte ) || !isprint( *byte ) ) {
				b64 = 1;
				break;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
621
			if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
622
623
624
625
626
627
				*(*out)++ = '\n';
				*(*out)++ = ' ';
				len = 1;
			}
			*(*out)++ = *byte;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
628
629
630
631
632

		if( !b64 ) {
			*(*out)++ = '\n';
			return;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
633
634
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
635
636
637
638
639
640
	*out = save;
	*(*out)++ = ':';
	*(*out)++ = ' ';
	len = savelen + 2;

	/* convert to base 64 (3 bytes => 4 base 64 digits) */
641
	for ( byte = (const unsigned char *) val;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
642
643
644
645
646
647
648
649
650
651
652
653
		byte < stop - 2;
	    byte += 3 )
	{
		bits = (byte[0] & 0xff) << 16;
		bits |= (byte[1] & 0xff) << 8;
		bits |= (byte[2] & 0xff);

		for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
			if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
				*(*out)++ = '\n';
				*(*out)++ = ' ';
				len = 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
654
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
655
656
657

			/* get b64 digit from high order 6 bits */
			*(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
Kurt Zeilenga's avatar
Kurt Zeilenga committed
658
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
659
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
660

Kurt Zeilenga's avatar
Kurt Zeilenga committed
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
	/* add padding if necessary */
	if ( byte < stop ) {
		for ( i = 0; byte + i < stop; i++ ) {
			buf[i] = byte[i];
		}
		for ( pad = 0; i < 3; i++, pad++ ) {
			buf[i] = '\0';
		}
		byte = buf;
		bits = (byte[0] & 0xff) << 16;
		bits |= (byte[1] & 0xff) << 8;
		bits |= (byte[2] & 0xff);

		for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
			if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
				*(*out)++ = '\n';
				*(*out)++ = ' ';
				len = 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
679
680
			}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
681
682
683
684
685
			if( i + pad < 4 ) {
				/* get b64 digit from low order 6 bits */
				*(*out)++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
			} else {
				*(*out)++ = '=';
Kurt Zeilenga's avatar
Kurt Zeilenga committed
686
687
688
689
690
691
692
693
			}
		}
	}
	*(*out)++ = '\n';
}


/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
694
 * ldif_type_and_value return BER malloc'd, zero-terminated LDIF line
Kurt Zeilenga's avatar
Kurt Zeilenga committed
695
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
696
697
698
699
700
701
char *
ldif_put(
	int type,
	LDAP_CONST char *name,
	LDAP_CONST char *val,
	ber_len_t vlen )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
702
703
{
    char	*buf, *p;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
704
    ber_len_t nlen;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
705

Kurt Zeilenga's avatar
Kurt Zeilenga committed
706
707
708
709
710
    nlen = ( name != NULL ) ? strlen( name ) : 0;

	buf = (char *) ber_memalloc( LDIF_SIZE_NEEDED( nlen, vlen ) + 1 );

    if ( buf == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
711
		ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
712
			_("ldif_type_and_value: malloc failed!"));
713
		return NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
714
715
716
    }

    p = buf;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
717
    ldif_sput( &p, type, name, val, vlen );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
718
719
720
721
    *p = '\0';

    return( buf );
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
722
723
724
725
726
727
728
729
730

int ldif_is_not_printable(
	LDAP_CONST char *val,
	ber_len_t vlen )
{
	if( vlen == 0 || val == NULL  ) {
		return -1;
	}

731
732
	if( isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<' &&
		isgraph( (unsigned char) val[vlen-1] ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
733
734
735
736
	{
		ber_len_t i;

		for ( i = 0; val[i]; i++ ) {
737
			if ( !isascii( val[i] ) || !isprint( (unsigned char) val[i] ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
738
739
740
741
742
743
744
745
746
				return 1;
			}
		}

		return 0;
	}

	return 1;
}
747

748
749
LDIFFP *
ldif_open(
Hallvard Furuseth's avatar
Hallvard Furuseth committed
750
751
	LDAP_CONST char *file,
	LDAP_CONST char *mode
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
)
{
	FILE *fp = fopen( file, mode );
	LDIFFP *lfp = NULL;

	if ( fp ) {
		lfp = ber_memalloc( sizeof( LDIFFP ));
		lfp->fp = fp;
		lfp->prev = NULL;
	}
	return lfp;
}

void
ldif_close(
	LDIFFP *lfp
)
{
	LDIFFP *prev;

	while ( lfp ) {
		fclose( lfp->fp );
		prev = lfp->prev;
		ber_memfree( lfp );
		lfp = prev;
	}
}

780
781
#define	LDIF_MAXLINE	4096

782
/*
783
 * ldif_read_record - read an ldif record.  Return 1 for success, 0 for EOF.
784
785
786
 */
int
ldif_read_record(
787
	LDIFFP      *lfp,
788
789
790
791
	int         *lno,		/* ptr to line number counter              */
	char        **bufp,     /* ptr to malloced output buffer           */
	int         *buflenp )  /* ptr to length of *bufp                  */
{
792
	char        linebuf[LDIF_MAXLINE], *line, *nbufp;
793
	ber_len_t   lcur = 0, len, linesize;
794
	int         last_ch = '\n', found_entry = 0, stop, top_comment = 0;
795
796
797
798

	line     = linebuf;
	linesize = sizeof( linebuf );

799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
	for ( stop = 0;  !stop;  last_ch = line[len-1] ) {
		/* If we're at the end of this file, see if we should pop
		 * back to a previous file. (return from an include)
		 */
		while ( feof( lfp->fp )) {
			if ( lfp->prev ) {
				LDIFFP *tmp = lfp->prev;
				fclose( lfp->fp );
				*lfp = *tmp;
				ber_memfree( tmp );
			} else {
				stop = 1;
				break;
			}
		}
		if ( stop )
			break;

		if ( fgets( line, linesize, lfp->fp ) == NULL ) {
818
819
820
821
822
823
824
825
826
			stop = 1;
			/* Add \n in case the file does not end with newline */
			line = "\n";
		}
		len = strlen( line );

		if ( last_ch == '\n' ) {
			(*lno)++;

827
828
			if ( line[0] == '\n' ||
				( line[0] == '\r' && line[1] == '\n' )) {
829
830
831
				if ( !found_entry ) {
					lcur = 0;
					top_comment = 0;
832
					continue;
833
				}
834
835
836
837
				break;
			}

			if ( !found_entry ) {
838
839
840
841
842
843
844
845
846
847
				if ( line[0] == '#' ) {
					top_comment = 1;
				} else if ( ! ( top_comment && line[0] == ' ' ) ) {
					/* Found a new entry */
					found_entry = 1;

					if ( isdigit( (unsigned char) line[0] ) ) {
						/* skip index */
						continue;
					}
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
					if ( !strncasecmp( line, "include:",
						STRLENOF("include:"))) {
						FILE *fp2;
						char *ptr;
						found_entry = 0;

						if ( line[len-1] == '\n' ) {
							len--;
							line[len] = '\0';
						}
						if ( line[len-1] == '\r' ) {
							len--;
							line[len] = '\0';
						}

						ptr = line + STRLENOF("include:");
864
						while (isspace((unsigned char) *ptr)) ptr++;
865
866
867
						fp2 = ldif_open_url( ptr );
						if ( fp2 ) {
							LDIFFP *lnew = ber_memalloc( sizeof( LDIFFP ));
868
869
870
							if ( lnew == NULL ) {
								return 0;
							}
871
872
873
874
							lnew->prev = lfp->prev;
							lnew->fp = lfp->fp;
							lfp->prev = lnew;
							lfp->fp = fp2;
Howard Chu's avatar
Howard Chu committed
875
876
							line[len] = '\n';
							len++;
877
878
879
880
881
							continue;
						} else {
							/* We failed to open the file, this should
							 * be reported as an error somehow.
							 */
882
883
884
							ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
								_("ldif_read_record: include %s failed\n"), ptr );
							return 0;
885
886
						}
					}
887
888
889
890
891
				}
			}			
		}

		if ( *buflenp - lcur <= len ) {
892
			*buflenp += len + LDIF_MAXLINE;
Hallvard Furuseth's avatar
Hallvard Furuseth committed
893
			nbufp = ber_memrealloc( *bufp, *buflenp );
894
895
896
897
898
899
900
901
902
903
			if( nbufp == NULL ) {
				return 0;
			}
			*bufp = nbufp;
		}
		strcpy( *bufp + lcur, line );
		lcur += len;
	}

	return( found_entry );
904
}