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