ldif.c 14.5 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
311
 * which it updates and must be supplied on subsequent calls.
 */

char *
312
ldif_getline( char **next )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
313
{
314
	char *line;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
315

316
317
318
319
320
321
	do {
		if ( *next == NULL || **next == '\n' || **next == '\0' ) {
			return( NULL );
		}

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

323
		while ( (*next = strchr( *next, '\n' )) != NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
324
325
326
327
328
#if CONTINUED_LINE_MARKER != '\r'
			if ( (*next)[-1] == '\r' ) {
				(*next)[-1] = CONTINUED_LINE_MARKER;
			}
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
329

Kurt Zeilenga's avatar
Kurt Zeilenga committed
330
331
			if ( (*next)[1] != ' ' ) {
				if ( (*next)[1] == '\r' && (*next)[2] == '\n' ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
332
333
334
335
					*(*next)++ = '\0';
				}
				*(*next)++ = '\0';
				break;
336
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
337
338

			**next = CONTINUED_LINE_MARKER;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
339
			(*next)[1] = CONTINUED_LINE_MARKER;
340
			(*next)++;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
341
		}
342
	} while( *line == '#' );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
343

344
	return( line );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
345
346
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
347
348
349
/* compatibility with U-Mich off by one bug */
#define LDIF_KLUDGE 1

Kurt Zeilenga's avatar
Kurt Zeilenga committed
350
void
Kurt Zeilenga's avatar
Kurt Zeilenga committed
351
ldif_sput(
Kurt Zeilenga's avatar
Kurt Zeilenga committed
352
	char **out,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
353
354
	int type,
	LDAP_CONST char *name,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
355
	LDAP_CONST char *val,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
356
	ber_len_t vlen )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
357
{
358
	const unsigned char *byte, *stop;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
359
360
361
	unsigned char	buf[3];
	unsigned long	bits;
	char		*save;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
362
	int		pad;
Howard Chu's avatar
Howard Chu committed
363
	int		namelen = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379

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

380
		break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
381

Kurt Zeilenga's avatar
Kurt Zeilenga committed
382
383
384
	case LDIF_PUT_SEP:
		*(*out)++ = '\n';
		return;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
385
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
386
387
388
389

	/* name (attribute type) */
	if( name != NULL ) {
		/* put the name + ":" */
Howard Chu's avatar
Howard Chu committed
390
391
392
393
		namelen = strlen(name);
		strcpy(*out, name);
		*out += namelen;
		len += namelen;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
394
395
396
397
398
399

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

Hallvard Furuseth's avatar
Hallvard Furuseth committed
400
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
401
#ifdef LDAP_DEBUG
Hallvard Furuseth's avatar
Hallvard Furuseth committed
402
	else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
403
404
		assert( type == LDIF_PUT_COMMENT );
	}
Hallvard Furuseth's avatar
Hallvard Furuseth committed
405
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
406

407
408
409
410
411
	if( vlen == 0 ) {
		*(*out)++ = '\n';
		return;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
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
	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
452
453
	save = *out;
	savelen = len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
454

Kurt Zeilenga's avatar
Kurt Zeilenga committed
455
	*(*out)++ = ' ';
Kurt Zeilenga's avatar
Kurt Zeilenga committed
456
457
	len++;

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
460
	if ( type == LDIF_PUT_VALUE
461
462
		&& isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<'
		&& isgraph( (unsigned char) val[vlen-1] )
463
464
465
#ifndef LDAP_BINARY_DEBUG
		&& strstr( name, ";binary" ) == NULL
#endif
466
#ifndef LDAP_PASSWD_DEBUG
Howard Chu's avatar
Howard Chu committed
467
468
469
470
		&& (namelen != (sizeof("userPassword")-1)
		|| strcasecmp( name, "userPassword" ) != 0)	/* encode userPassword */
		&& (namelen != (sizeof("2.5.4.35")-1) 
		|| strcasecmp( name, "2.5.4.35" ) != 0)		/* encode userPassword */
471
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
472
	) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
473
474
		int b64 = 0;

475
		for ( byte = (const unsigned char *) val; byte < stop;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
476
477
		    byte++, len++ )
		{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
478
479
480
481
			if ( !isascii( *byte ) || !isprint( *byte ) ) {
				b64 = 1;
				break;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
482
			if ( len > LDIF_LINE_WIDTH+LDIF_KLUDGE ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
483
484
485
486
487
488
				*(*out)++ = '\n';
				*(*out)++ = ' ';
				len = 1;
			}
			*(*out)++ = *byte;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
489
490
491
492
493

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
496
497
498
499
500
501
	*out = save;
	*(*out)++ = ':';
	*(*out)++ = ' ';
	len = savelen + 2;

	/* convert to base 64 (3 bytes => 4 base 64 digits) */
502
	for ( byte = (const unsigned char *) val;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
503
504
505
506
507
508
509
510
511
512
513
514
		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
515
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
516
517
518

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
	/* 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
540
541
			}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
542
543
544
545
546
			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
547
548
549
550
551
552
553
554
			}
		}
	}
	*(*out)++ = '\n';
}


/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
555
 * ldif_type_and_value return BER malloc'd, zero-terminated LDIF line
Kurt Zeilenga's avatar
Kurt Zeilenga committed
556
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
557
558
559
560
561
562
char *
ldif_put(
	int type,
	LDAP_CONST char *name,
	LDAP_CONST char *val,
	ber_len_t vlen )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
563
564
{
    char	*buf, *p;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
565
    ber_len_t nlen;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
566

Kurt Zeilenga's avatar
Kurt Zeilenga committed
567
568
569
570
571
    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
572
		ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
573
			_("ldif_type_and_value: malloc failed!"));
574
		return NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
575
576
577
    }

    p = buf;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
578
    ldif_sput( &p, type, name, val, vlen );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
579
580
581
582
    *p = '\0';

    return( buf );
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
583
584
585
586
587
588
589
590
591

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

592
593
	if( isgraph( (unsigned char) val[0] ) && val[0] != ':' && val[0] != '<' &&
		isgraph( (unsigned char) val[vlen-1] ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
594
595
596
597
598
599
600
601
602
603
604
605
606
607
	{
		ber_len_t i;

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

		return 0;
	}

	return 1;
}
608
609
610
611
612
613
614
615
616
617
618

/*
 * 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
619
	char        linebuf[BUFSIZ], *line, *nbufp;
620
	ber_len_t   lcur = 0, len, linesize;
621
	int         last_ch = '\n', found_entry = 0, stop, top_comment = 0;
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637

	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' ) {
638
639
640
				if ( !found_entry ) {
					lcur = 0;
					top_comment = 0;
641
					continue;
642
				}
643
644
645
646
				break;
			}

			if ( !found_entry ) {
647
648
649
650
651
652
653
654
655
656
				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;
					}
657
658
659
660
661
				}
			}			
		}

		if ( *buflenp - lcur <= len ) {
Hallvard Furuseth's avatar
Hallvard Furuseth committed
662
663
			*buflenp += len + BUFSIZ;
			nbufp = ber_memrealloc( *bufp, *buflenp );
664
665
666
667
668
669
670
671
672
673
			if( nbufp == NULL ) {
				return 0;
			}
			*bufp = nbufp;
		}
		strcpy( *bufp + lcur, line );
		lcur += len;
	}

	return( found_entry );
674
}