ldif.c 17.3 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-2005 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"),
150
			type );
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
				_("ldif_parse_line: %s missing base64 value\n"), type );
194
			if ( !freeval ) ber_memfree( line );
195
			return( -1 );
196
197
		}

198
		byte = value->bv_val = s;
199

200
		for ( p = s, value->bv_len = 0; p < d; p += 4, value->bv_len += 3 ) {
201
			int i;
202
			for ( i = 0; i < 4; i++ ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
203
204
				if ( p[i] != '=' && (p[i] & 0x80 ||
				    b642nib[ p[i] & 0x7f ] > 0x3f) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
205
					ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
206
207
						_("ldif_parse_line: %s: invalid base64 encoding"
						" char (%c) 0x%x\n"),
208
					    type, p[i], p[i] );
209
					if ( !freeval ) ber_memfree( line );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
210
211
212
213
214
215
216
217
218
219
220
221
222
					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] == '=' ) {
223
				value->bv_len += 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
224
225
226
227
228
229
230
				break;
			}
			nib = b642nib[ p[2] & 0x7f ];
			byte[1] |= nib >> 2;
			byte[2] = (nib & RIGHT2) << 6;
			/* fourth digit */
			if ( p[3] == '=' ) {
231
				value->bv_len += 2;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
232
233
234
235
236
237
238
				break;
			}
			nib = b642nib[ p[3] & 0x7f ];
			byte[2] |= nib;

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

	} else if ( url ) {
242
243
244
		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
245
				_("ldif_parse_line: %s missing URL value\n"), type );
246
			if ( !freeval ) ber_memfree( line );
247
			return( -1 );
248
249
		}

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

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

264
265
266
267
	if ( !freeval ) {
		struct berval bv = *type;

		ber_dupbv( type, &bv );
268

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

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

		ber_memfree( line );
	}
291

Kurt Zeilenga's avatar
Kurt Zeilenga committed
292
293
294
295
	return( 0 );
}

/*
296
 * ldif_getline - return the next "line" (minus newline) of input from a
Kurt Zeilenga's avatar
Kurt Zeilenga committed
297
298
299
300
301
302
 * 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
303
 * ldif_parse_line() routine above.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
304
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
305
306
307
 * 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
308
309
310
 * which it updates and must be supplied on subsequent calls.
 */

Howard Chu's avatar
Howard Chu committed
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
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
326
char *
327
ldif_getline( char **next )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
328
{
329
	char *line;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
330

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

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

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

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

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

359
	return( line );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
360
361
}

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
392
393
394
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
447
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
473
474
475
476
477
478
479
480
481
482
483
484
485
486
/*
 * 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;

	assert( must_b64_encode );
	assert( name );
	assert( oid );

	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;

	assert( must_b64_encode );

	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;

	assert( must_b64_encode );
	assert( s );

	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
				|| ber_bvstrcasecmp( &must_b64_encode[i].oid, &bv ) == 0 )
		{
			return 1;
		}
	}

	return 0;
}

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

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

	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++;
		}

520
		break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
521

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

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

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

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

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
552
553
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
	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
592
593
	save = *out;
	savelen = len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
594

Kurt Zeilenga's avatar
Kurt Zeilenga committed
595
	*(*out)++ = ' ';
Kurt Zeilenga's avatar
Kurt Zeilenga committed
596
597
	len++;

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

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

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

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

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

	/* convert to base 64 (3 bytes => 4 base 64 digits) */
639
	for ( byte = (const unsigned char *) val;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
640
641
642
643
644
645
646
647
648
649
650
651
		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
652
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
653
654
655

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
	/* 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
677
678
			}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
679
680
681
682
683
			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
684
685
686
687
688
689
690
691
			}
		}
	}
	*(*out)++ = '\n';
}


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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
704
705
706
707
708
    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
709
		ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
710
			_("ldif_type_and_value: malloc failed!"));
711
		return NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
712
713
714
    }

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

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

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

729
730
	if( isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<' &&
		isgraph( (unsigned char) val[vlen-1] ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
731
732
733
734
735
736
737
738
739
740
741
742
743
744
	{
		ber_len_t i;

		for ( i = 0; val[i]; i++ ) {
			if ( !isascii( val[i] ) || !isprint( val[i] ) ) {
				return 1;
			}
		}

		return 0;
	}

	return 1;
}
745
746
747
748
749
750
751
752
753
754
755

/*
 * slap_read_ldif - read an ldif record.  Return 1 for success, 0 for EOF.
 */
int
ldif_read_record(
	FILE        *fp,
	int         *lno,		/* ptr to line number counter              */
	char        **bufp,     /* ptr to malloced output buffer           */
	int         *buflenp )  /* ptr to length of *bufp                  */
{
Hallvard Furuseth's avatar
Hallvard Furuseth committed
756
	char        linebuf[BUFSIZ], *line, *nbufp;
757
	ber_len_t   lcur = 0, len, linesize;
758
	int         last_ch = '\n', found_entry = 0, stop, top_comment = 0;
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774

	line     = linebuf;
	linesize = sizeof( linebuf );

	for ( stop = feof( fp );  !stop;  last_ch = line[len-1] ) {
		if ( fgets( line, linesize, fp ) == NULL ) {
			stop = 1;
			/* Add \n in case the file does not end with newline */
			line = "\n";
		}
		len = strlen( line );

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

			if ( line[0] == '\n' ) {
775
776
777
				if ( !found_entry ) {
					lcur = 0;
					top_comment = 0;
778
					continue;
779
				}
780
781
782
783
				break;
			}

			if ( !found_entry ) {
784
785
786
787
788
789
790
791
792
793
				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;
					}
794
795
796
797
798
				}
			}			
		}

		if ( *buflenp - lcur <= len ) {
Hallvard Furuseth's avatar
Hallvard Furuseth committed
799
800
			*buflenp += len + BUFSIZ;
			nbufp = ber_memrealloc( *bufp, *buflenp );
801
802
803
804
805
806
807
808
809
810
			if( nbufp == NULL ) {
				return 0;
			}
			*bufp = nbufp;
		}
		strcpy( *bufp + lcur, line );
		lcur += len;
	}

	return( found_entry );
811
}