1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
3*0Sstevel@tonic-gate * Use is subject to license terms.
4*0Sstevel@tonic-gate */
5*0Sstevel@tonic-gate
6*0Sstevel@tonic-gate
7*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
8*0Sstevel@tonic-gate
9*0Sstevel@tonic-gate /*
10*0Sstevel@tonic-gate * The contents of this file are subject to the Netscape Public
11*0Sstevel@tonic-gate * License Version 1.1 (the "License"); you may not use this file
12*0Sstevel@tonic-gate * except in compliance with the License. You may obtain a copy of
13*0Sstevel@tonic-gate * the License at http://www.mozilla.org/NPL/
14*0Sstevel@tonic-gate *
15*0Sstevel@tonic-gate * Software distributed under the License is distributed on an "AS
16*0Sstevel@tonic-gate * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
17*0Sstevel@tonic-gate * implied. See the License for the specific language governing
18*0Sstevel@tonic-gate * rights and limitations under the License.
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * The Original Code is Mozilla Communicator client code, released
21*0Sstevel@tonic-gate * March 31, 1998.
22*0Sstevel@tonic-gate *
23*0Sstevel@tonic-gate * The Initial Developer of the Original Code is Netscape
24*0Sstevel@tonic-gate * Communications Corporation. Portions created by Netscape are
25*0Sstevel@tonic-gate * Copyright (C) 1998-1999 Netscape Communications Corporation. All
26*0Sstevel@tonic-gate * Rights Reserved.
27*0Sstevel@tonic-gate *
28*0Sstevel@tonic-gate * Contributor(s):
29*0Sstevel@tonic-gate */
30*0Sstevel@tonic-gate
31*0Sstevel@tonic-gate /* line64.c - routines for dealing with the slapd line format */
32*0Sstevel@tonic-gate
33*0Sstevel@tonic-gate #include <stdio.h>
34*0Sstevel@tonic-gate #include <string.h>
35*0Sstevel@tonic-gate #include <stdlib.h>
36*0Sstevel@tonic-gate #include <ctype.h>
37*0Sstevel@tonic-gate #ifndef macintosh
38*0Sstevel@tonic-gate #include <sys/types.h>
39*0Sstevel@tonic-gate #endif
40*0Sstevel@tonic-gate #ifdef _WIN32
41*0Sstevel@tonic-gate #include <windows.h>
42*0Sstevel@tonic-gate #elif !defined( macintosh )
43*0Sstevel@tonic-gate #include <sys/socket.h>
44*0Sstevel@tonic-gate #endif
45*0Sstevel@tonic-gate #include "ldaplog.h"
46*0Sstevel@tonic-gate #include "ldif.h"
47*0Sstevel@tonic-gate
48*0Sstevel@tonic-gate #ifndef isascii
49*0Sstevel@tonic-gate #define isascii( c ) (!((c) & ~0177))
50*0Sstevel@tonic-gate #endif
51*0Sstevel@tonic-gate
52*0Sstevel@tonic-gate #define RIGHT2 0x03
53*0Sstevel@tonic-gate #define RIGHT4 0x0f
54*0Sstevel@tonic-gate #define CONTINUED_LINE_MARKER '\001'
55*0Sstevel@tonic-gate
56*0Sstevel@tonic-gate #define ISBLANK(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') /* not "\r\v\f" */
57*0Sstevel@tonic-gate
58*0Sstevel@tonic-gate #define LDIF_OPT_ISSET( value, opt ) (((value) & (opt)) != 0 )
59*0Sstevel@tonic-gate
60*0Sstevel@tonic-gate static char nib2b64[0x40] =
61*0Sstevel@tonic-gate "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
62*0Sstevel@tonic-gate
63*0Sstevel@tonic-gate static unsigned char b642nib[0x80] = {
64*0Sstevel@tonic-gate 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
65*0Sstevel@tonic-gate 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66*0Sstevel@tonic-gate 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
67*0Sstevel@tonic-gate 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
68*0Sstevel@tonic-gate 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
69*0Sstevel@tonic-gate 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
70*0Sstevel@tonic-gate 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
71*0Sstevel@tonic-gate 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
72*0Sstevel@tonic-gate 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
73*0Sstevel@tonic-gate 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
74*0Sstevel@tonic-gate 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
75*0Sstevel@tonic-gate 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
76*0Sstevel@tonic-gate 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
77*0Sstevel@tonic-gate 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
78*0Sstevel@tonic-gate 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
79*0Sstevel@tonic-gate 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
80*0Sstevel@tonic-gate };
81*0Sstevel@tonic-gate
82*0Sstevel@tonic-gate static int ldif_base64_encode_internal( unsigned char *src, char *dst, int srclen,
83*0Sstevel@tonic-gate int lenused, int wraplen );
84*0Sstevel@tonic-gate
85*0Sstevel@tonic-gate /*
86*0Sstevel@tonic-gate * str_parse_line - takes a line of the form "type:[:] value" and splits it
87*0Sstevel@tonic-gate * into components "type" and "value". if a double colon separates type from
88*0Sstevel@tonic-gate * value, then value is encoded in base 64, and parse_line un-decodes it
89*0Sstevel@tonic-gate * (in place) before returning.
90*0Sstevel@tonic-gate */
91*0Sstevel@tonic-gate
92*0Sstevel@tonic-gate int
str_parse_line(char * line,char ** type,char ** value,int * vlen)93*0Sstevel@tonic-gate str_parse_line(
94*0Sstevel@tonic-gate char *line,
95*0Sstevel@tonic-gate char **type,
96*0Sstevel@tonic-gate char **value,
97*0Sstevel@tonic-gate int *vlen
98*0Sstevel@tonic-gate )
99*0Sstevel@tonic-gate {
100*0Sstevel@tonic-gate char *p, *s, *d;
101*0Sstevel@tonic-gate int b64;
102*0Sstevel@tonic-gate
103*0Sstevel@tonic-gate /* skip any leading space */
104*0Sstevel@tonic-gate while ( ISBLANK( *line ) ) {
105*0Sstevel@tonic-gate line++;
106*0Sstevel@tonic-gate }
107*0Sstevel@tonic-gate *type = line;
108*0Sstevel@tonic-gate
109*0Sstevel@tonic-gate for ( s = line; *s && *s != ':'; s++ )
110*0Sstevel@tonic-gate ; /* NULL */
111*0Sstevel@tonic-gate if ( *s == '\0' ) {
112*0Sstevel@tonic-gate
113*0Sstevel@tonic-gate /* Comment-out while we address calling libldif from ns-back-ldbm
114*0Sstevel@tonic-gate on NT. 1 of 3 */
115*0Sstevel@tonic-gate #if defined( _WIN32 )
116*0Sstevel@tonic-gate /*
117*0Sstevel@tonic-gate #endif
118*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_PARSE, "str_parse_line: missing ':' "
119*0Sstevel@tonic-gate "on line \"%s\"\n", line, 0, 0 );
120*0Sstevel@tonic-gate #if defined( _WIN32 )
121*0Sstevel@tonic-gate */
122*0Sstevel@tonic-gate #endif
123*0Sstevel@tonic-gate return( -1 );
124*0Sstevel@tonic-gate }
125*0Sstevel@tonic-gate
126*0Sstevel@tonic-gate /* trim any space between type and : */
127*0Sstevel@tonic-gate for ( p = s - 1; p > line && ISBLANK( *p ); p-- ) {
128*0Sstevel@tonic-gate *p = '\0';
129*0Sstevel@tonic-gate }
130*0Sstevel@tonic-gate *s++ = '\0';
131*0Sstevel@tonic-gate
132*0Sstevel@tonic-gate /* check for double : - indicates base 64 encoded value */
133*0Sstevel@tonic-gate if ( *s == ':' ) {
134*0Sstevel@tonic-gate s++;
135*0Sstevel@tonic-gate b64 = 1;
136*0Sstevel@tonic-gate
137*0Sstevel@tonic-gate /* single : - normally encoded value */
138*0Sstevel@tonic-gate } else {
139*0Sstevel@tonic-gate b64 = 0;
140*0Sstevel@tonic-gate }
141*0Sstevel@tonic-gate
142*0Sstevel@tonic-gate /* skip space between : and value */
143*0Sstevel@tonic-gate while ( ISBLANK( *s ) ) {
144*0Sstevel@tonic-gate s++;
145*0Sstevel@tonic-gate }
146*0Sstevel@tonic-gate
147*0Sstevel@tonic-gate /*
148*0Sstevel@tonic-gate * If no value is present, return a zero-length string for
149*0Sstevel@tonic-gate * *value, with *vlen set to zero.
150*0Sstevel@tonic-gate */
151*0Sstevel@tonic-gate if ( *s == '\0' ) {
152*0Sstevel@tonic-gate *value = s;
153*0Sstevel@tonic-gate *vlen = 0;
154*0Sstevel@tonic-gate return( 0 );
155*0Sstevel@tonic-gate }
156*0Sstevel@tonic-gate
157*0Sstevel@tonic-gate /* check for continued line markers that should be deleted */
158*0Sstevel@tonic-gate for ( p = s, d = s; *p; p++ ) {
159*0Sstevel@tonic-gate if ( *p != CONTINUED_LINE_MARKER )
160*0Sstevel@tonic-gate *d++ = *p;
161*0Sstevel@tonic-gate }
162*0Sstevel@tonic-gate *d = '\0';
163*0Sstevel@tonic-gate
164*0Sstevel@tonic-gate *value = s;
165*0Sstevel@tonic-gate if ( b64 ) {
166*0Sstevel@tonic-gate if (( *vlen = ldif_base64_decode( s, (unsigned char *)s ))
167*0Sstevel@tonic-gate < 0 ) {
168*0Sstevel@tonic-gate /* Comment-out while we address calling libldif from ns-back-ldbm
169*0Sstevel@tonic-gate on NT. 3 of 3 */
170*0Sstevel@tonic-gate #if defined( _WIN32 )
171*0Sstevel@tonic-gate /*
172*0Sstevel@tonic-gate #endif
173*0Sstevel@tonic-gate LDAPDebug( LDAP_DEBUG_ANY,
174*0Sstevel@tonic-gate "str_parse_line: invalid base 64 char on line \"%s\"\n",
175*0Sstevel@tonic-gate line, 0, 0 );
176*0Sstevel@tonic-gate #if defined( _WIN32 )
177*0Sstevel@tonic-gate */
178*0Sstevel@tonic-gate #endif
179*0Sstevel@tonic-gate return( -1 );
180*0Sstevel@tonic-gate }
181*0Sstevel@tonic-gate s[ *vlen ] = '\0';
182*0Sstevel@tonic-gate } else {
183*0Sstevel@tonic-gate *vlen = (int) (d - s);
184*0Sstevel@tonic-gate }
185*0Sstevel@tonic-gate
186*0Sstevel@tonic-gate return( 0 );
187*0Sstevel@tonic-gate }
188*0Sstevel@tonic-gate
189*0Sstevel@tonic-gate
190*0Sstevel@tonic-gate /*
191*0Sstevel@tonic-gate * ldif_base64_decode - take the BASE64-encoded characters in "src"
192*0Sstevel@tonic-gate * (a zero-terminated string) and decode them into the the buffer "dst".
193*0Sstevel@tonic-gate * "src" and "dst" can be the same if in-place decoding is desired.
194*0Sstevel@tonic-gate * "dst" must be large enough to hold the decoded octets. No more than
195*0Sstevel@tonic-gate * 3 * strlen( src ) / 4 bytes will be produced.
196*0Sstevel@tonic-gate * "dst" may contain zero octets anywhere within it, but it is not
197*0Sstevel@tonic-gate * zero-terminated by this function.
198*0Sstevel@tonic-gate *
199*0Sstevel@tonic-gate * The number of bytes copied to "dst" is returned if all goes well.
200*0Sstevel@tonic-gate * -1 is returned if the BASE64 encoding in "src" is invalid.
201*0Sstevel@tonic-gate */
202*0Sstevel@tonic-gate
203*0Sstevel@tonic-gate int
ldif_base64_decode(char * src,unsigned char * dst)204*0Sstevel@tonic-gate ldif_base64_decode( char *src, unsigned char *dst )
205*0Sstevel@tonic-gate {
206*0Sstevel@tonic-gate char *p, *stop;
207*0Sstevel@tonic-gate unsigned char nib, *byte;
208*0Sstevel@tonic-gate int i, len;
209*0Sstevel@tonic-gate
210*0Sstevel@tonic-gate stop = strchr( src, '\0' );
211*0Sstevel@tonic-gate byte = dst;
212*0Sstevel@tonic-gate for ( p = src, len = 0; p < stop; p += 4, len += 3 ) {
213*0Sstevel@tonic-gate for ( i = 0; i < 4; i++ ) {
214*0Sstevel@tonic-gate if ( p[i] != '=' && (p[i] & 0x80 ||
215*0Sstevel@tonic-gate b642nib[ p[i] & 0x7f ] > 0x3f) ) {
216*0Sstevel@tonic-gate return( -1 );
217*0Sstevel@tonic-gate }
218*0Sstevel@tonic-gate }
219*0Sstevel@tonic-gate
220*0Sstevel@tonic-gate /* first digit */
221*0Sstevel@tonic-gate nib = b642nib[ p[0] & 0x7f ];
222*0Sstevel@tonic-gate byte[0] = nib << 2;
223*0Sstevel@tonic-gate
224*0Sstevel@tonic-gate /* second digit */
225*0Sstevel@tonic-gate nib = b642nib[ p[1] & 0x7f ];
226*0Sstevel@tonic-gate byte[0] |= nib >> 4;
227*0Sstevel@tonic-gate
228*0Sstevel@tonic-gate /* third digit */
229*0Sstevel@tonic-gate if ( p[2] == '=' ) {
230*0Sstevel@tonic-gate len += 1;
231*0Sstevel@tonic-gate break;
232*0Sstevel@tonic-gate }
233*0Sstevel@tonic-gate byte[1] = (nib & RIGHT4) << 4;
234*0Sstevel@tonic-gate nib = b642nib[ p[2] & 0x7f ];
235*0Sstevel@tonic-gate byte[1] |= nib >> 2;
236*0Sstevel@tonic-gate
237*0Sstevel@tonic-gate /* fourth digit */
238*0Sstevel@tonic-gate if ( p[3] == '=' ) {
239*0Sstevel@tonic-gate len += 2;
240*0Sstevel@tonic-gate break;
241*0Sstevel@tonic-gate }
242*0Sstevel@tonic-gate byte[2] = (nib & RIGHT2) << 6;
243*0Sstevel@tonic-gate nib = b642nib[ p[3] & 0x7f ];
244*0Sstevel@tonic-gate byte[2] |= nib;
245*0Sstevel@tonic-gate
246*0Sstevel@tonic-gate byte += 3;
247*0Sstevel@tonic-gate }
248*0Sstevel@tonic-gate
249*0Sstevel@tonic-gate return( len );
250*0Sstevel@tonic-gate }
251*0Sstevel@tonic-gate
252*0Sstevel@tonic-gate /*
253*0Sstevel@tonic-gate * str_getline - return the next "line" (minus newline) of input from a
254*0Sstevel@tonic-gate * string buffer of lines separated by newlines, terminated by \n\n
255*0Sstevel@tonic-gate * or \0. this routine handles continued lines, bundling them into
256*0Sstevel@tonic-gate * a single big line before returning. if a line begins with a white
257*0Sstevel@tonic-gate * space character, it is a continuation of the previous line. the white
258*0Sstevel@tonic-gate * space character (nb: only one char), and preceeding newline are changed
259*0Sstevel@tonic-gate * into CONTINUED_LINE_MARKER chars, to be deleted later by the
260*0Sstevel@tonic-gate * str_parse_line() routine above.
261*0Sstevel@tonic-gate *
262*0Sstevel@tonic-gate * it takes a pointer to a pointer to the buffer on the first call,
263*0Sstevel@tonic-gate * which it updates and must be supplied on subsequent calls.
264*0Sstevel@tonic-gate *
265*0Sstevel@tonic-gate * XXX need to update this function to also support <CR><LF> as EOL.
266*0Sstevel@tonic-gate * XXX supports <CR><LF> as of 07/29/1998 (richm)
267*0Sstevel@tonic-gate */
268*0Sstevel@tonic-gate
269*0Sstevel@tonic-gate char *
str_getline(char ** next)270*0Sstevel@tonic-gate str_getline( char **next )
271*0Sstevel@tonic-gate {
272*0Sstevel@tonic-gate char *l;
273*0Sstevel@tonic-gate char c;
274*0Sstevel@tonic-gate char *p;
275*0Sstevel@tonic-gate
276*0Sstevel@tonic-gate if ( *next == NULL || **next == '\n' || **next == '\0' ) {
277*0Sstevel@tonic-gate return( NULL );
278*0Sstevel@tonic-gate }
279*0Sstevel@tonic-gate
280*0Sstevel@tonic-gate while ( **next == '#' ) { /* skip comment lines */
281*0Sstevel@tonic-gate if (( *next = strchr( *next, '\n' )) == NULL ) {
282*0Sstevel@tonic-gate return( NULL );
283*0Sstevel@tonic-gate }
284*0Sstevel@tonic-gate (*next)++;
285*0Sstevel@tonic-gate }
286*0Sstevel@tonic-gate
287*0Sstevel@tonic-gate l = *next;
288*0Sstevel@tonic-gate while ( (*next = strchr( *next, '\n' )) != NULL ) {
289*0Sstevel@tonic-gate p = *next - 1; /* pointer to character previous to the newline */
290*0Sstevel@tonic-gate c = *(*next + 1); /* character after the newline */
291*0Sstevel@tonic-gate if ( ISBLANK( c ) && c != '\n' ) {
292*0Sstevel@tonic-gate /* DOS EOL is \r\n, so if the character before */
293*0Sstevel@tonic-gate /* the \n is \r, continue it too */
294*0Sstevel@tonic-gate if (*p == '\r')
295*0Sstevel@tonic-gate *p = CONTINUED_LINE_MARKER;
296*0Sstevel@tonic-gate **next = CONTINUED_LINE_MARKER;
297*0Sstevel@tonic-gate *(*next+1) = CONTINUED_LINE_MARKER;
298*0Sstevel@tonic-gate } else {
299*0Sstevel@tonic-gate /* DOS EOL is \r\n, so if the character before */
300*0Sstevel@tonic-gate /* the \n is \r, null it too */
301*0Sstevel@tonic-gate if (*p == '\r')
302*0Sstevel@tonic-gate *p = '\0';
303*0Sstevel@tonic-gate *(*next)++ = '\0';
304*0Sstevel@tonic-gate break;
305*0Sstevel@tonic-gate }
306*0Sstevel@tonic-gate (*next)++;
307*0Sstevel@tonic-gate }
308*0Sstevel@tonic-gate
309*0Sstevel@tonic-gate return( l );
310*0Sstevel@tonic-gate }
311*0Sstevel@tonic-gate
312*0Sstevel@tonic-gate
313*0Sstevel@tonic-gate #define LDIF_SAFE_CHAR( c ) ( (c) != '\r' && (c) != '\n' )
314*0Sstevel@tonic-gate #define LDIF_CONSERVATIVE_CHAR( c ) ( LDIF_SAFE_CHAR(c) && isascii((c)) \
315*0Sstevel@tonic-gate && ( isprint((c)) || (c) == '\t' ))
316*0Sstevel@tonic-gate #define LDIF_SAFE_INITCHAR( c ) ( LDIF_SAFE_CHAR(c) && (c) != ':' \
317*0Sstevel@tonic-gate && (c) != ' ' && (c) != '<' )
318*0Sstevel@tonic-gate #define LDIF_CONSERVATIVE_INITCHAR( c ) ( LDIF_SAFE_INITCHAR( c ) && \
319*0Sstevel@tonic-gate ! ( isascii((c)) && isspace((c))))
320*0Sstevel@tonic-gate #define LDIF_CONSERVATIVE_FINALCHAR( c ) ( (c) != ' ' )
321*0Sstevel@tonic-gate
322*0Sstevel@tonic-gate
323*0Sstevel@tonic-gate void
ldif_put_type_and_value_with_options(char ** out,char * t,char * val,int vlen,unsigned long options)324*0Sstevel@tonic-gate ldif_put_type_and_value_with_options( char **out, char *t, char *val,
325*0Sstevel@tonic-gate int vlen, unsigned long options )
326*0Sstevel@tonic-gate {
327*0Sstevel@tonic-gate unsigned char *p, *byte, *stop;
328*0Sstevel@tonic-gate char *save;
329*0Sstevel@tonic-gate int b64, len, savelen, wraplen;
330*0Sstevel@tonic-gate len = 0;
331*0Sstevel@tonic-gate
332*0Sstevel@tonic-gate if ( LDIF_OPT_ISSET( options, LDIF_OPT_NOWRAP )) {
333*0Sstevel@tonic-gate wraplen = -1;
334*0Sstevel@tonic-gate } else {
335*0Sstevel@tonic-gate wraplen = LDIF_MAX_LINE_WIDTH;
336*0Sstevel@tonic-gate }
337*0Sstevel@tonic-gate
338*0Sstevel@tonic-gate /* put the type + ": " */
339*0Sstevel@tonic-gate for ( p = (unsigned char *) t; *p; p++, len++ ) {
340*0Sstevel@tonic-gate *(*out)++ = *p;
341*0Sstevel@tonic-gate }
342*0Sstevel@tonic-gate *(*out)++ = ':';
343*0Sstevel@tonic-gate len++;
344*0Sstevel@tonic-gate if ( LDIF_OPT_ISSET( options, LDIF_OPT_VALUE_IS_URL )) {
345*0Sstevel@tonic-gate *(*out)++ = '<'; /* add '<' for URLs */
346*0Sstevel@tonic-gate len++;
347*0Sstevel@tonic-gate }
348*0Sstevel@tonic-gate save = *out;
349*0Sstevel@tonic-gate savelen = len;
350*0Sstevel@tonic-gate b64 = 0;
351*0Sstevel@tonic-gate
352*0Sstevel@tonic-gate stop = (unsigned char *)val;
353*0Sstevel@tonic-gate if ( val && vlen > 0 ) {
354*0Sstevel@tonic-gate *(*out)++ = ' ';
355*0Sstevel@tonic-gate stop = (unsigned char *) (val + vlen);
356*0Sstevel@tonic-gate if ( LDIF_OPT_ISSET( options, LDIF_OPT_MINIMAL_ENCODING )) {
357*0Sstevel@tonic-gate if ( !LDIF_SAFE_INITCHAR( val[0] )) {
358*0Sstevel@tonic-gate b64 = 1;
359*0Sstevel@tonic-gate }
360*0Sstevel@tonic-gate } else {
361*0Sstevel@tonic-gate if ( !LDIF_CONSERVATIVE_INITCHAR( val[0] ) ||
362*0Sstevel@tonic-gate !LDIF_CONSERVATIVE_FINALCHAR( val[vlen-1] )) {
363*0Sstevel@tonic-gate b64 = 1;
364*0Sstevel@tonic-gate }
365*0Sstevel@tonic-gate }
366*0Sstevel@tonic-gate }
367*0Sstevel@tonic-gate
368*0Sstevel@tonic-gate if ( !b64 ) {
369*0Sstevel@tonic-gate for ( byte = (unsigned char *) val; byte < stop;
370*0Sstevel@tonic-gate byte++, len++ ) {
371*0Sstevel@tonic-gate if ( LDIF_OPT_ISSET( options,
372*0Sstevel@tonic-gate LDIF_OPT_MINIMAL_ENCODING )) {
373*0Sstevel@tonic-gate if ( !LDIF_SAFE_CHAR( *byte )) {
374*0Sstevel@tonic-gate b64 = 1;
375*0Sstevel@tonic-gate break;
376*0Sstevel@tonic-gate }
377*0Sstevel@tonic-gate } else if ( !LDIF_CONSERVATIVE_CHAR( *byte )) {
378*0Sstevel@tonic-gate b64 = 1;
379*0Sstevel@tonic-gate break;
380*0Sstevel@tonic-gate }
381*0Sstevel@tonic-gate
382*0Sstevel@tonic-gate if ( wraplen != -1 && len > wraplen ) {
383*0Sstevel@tonic-gate *(*out)++ = '\n';
384*0Sstevel@tonic-gate *(*out)++ = ' ';
385*0Sstevel@tonic-gate len = 1;
386*0Sstevel@tonic-gate }
387*0Sstevel@tonic-gate *(*out)++ = *byte;
388*0Sstevel@tonic-gate }
389*0Sstevel@tonic-gate }
390*0Sstevel@tonic-gate
391*0Sstevel@tonic-gate if ( b64 ) {
392*0Sstevel@tonic-gate *out = save;
393*0Sstevel@tonic-gate *(*out)++ = ':';
394*0Sstevel@tonic-gate *(*out)++ = ' ';
395*0Sstevel@tonic-gate len = ldif_base64_encode_internal( (unsigned char *)val, *out, vlen,
396*0Sstevel@tonic-gate savelen + 2, wraplen );
397*0Sstevel@tonic-gate *out += len;
398*0Sstevel@tonic-gate }
399*0Sstevel@tonic-gate
400*0Sstevel@tonic-gate *(*out)++ = '\n';
401*0Sstevel@tonic-gate }
402*0Sstevel@tonic-gate
403*0Sstevel@tonic-gate void
ldif_put_type_and_value(char ** out,char * t,char * val,int vlen)404*0Sstevel@tonic-gate ldif_put_type_and_value( char **out, char *t, char *val, int vlen )
405*0Sstevel@tonic-gate {
406*0Sstevel@tonic-gate ldif_put_type_and_value_with_options( out, t, val, vlen, 0 );
407*0Sstevel@tonic-gate }
408*0Sstevel@tonic-gate
409*0Sstevel@tonic-gate void
ldif_put_type_and_value_nowrap(char ** out,char * t,char * val,int vlen)410*0Sstevel@tonic-gate ldif_put_type_and_value_nowrap( char **out, char *t, char *val, int vlen )
411*0Sstevel@tonic-gate {
412*0Sstevel@tonic-gate ldif_put_type_and_value_with_options( out, t, val, vlen, LDIF_OPT_NOWRAP );
413*0Sstevel@tonic-gate }
414*0Sstevel@tonic-gate
415*0Sstevel@tonic-gate /*
416*0Sstevel@tonic-gate * ldif_base64_encode_internal - encode "srclen" bytes in "src", place BASE64
417*0Sstevel@tonic-gate * encoded bytes in "dst" and return the length of the BASE64
418*0Sstevel@tonic-gate * encoded string. "dst" is also zero-terminated by this function.
419*0Sstevel@tonic-gate *
420*0Sstevel@tonic-gate * If "lenused" >= 0, newlines will be included in "dst" and "lenused" if
421*0Sstevel@tonic-gate * appropriate. "lenused" should be a count of characters already used
422*0Sstevel@tonic-gate * on the current line. The LDIF lines we create will contain at most
423*0Sstevel@tonic-gate * "wraplen" characters on each line, unless "wraplen" is -1, in which
424*0Sstevel@tonic-gate * case output line length is unlimited.
425*0Sstevel@tonic-gate *
426*0Sstevel@tonic-gate * If "lenused" < 0, no newlines will be included, and the LDIF_BASE64_LEN()
427*0Sstevel@tonic-gate * macro can be used to determine how many bytes will be placed in "dst."
428*0Sstevel@tonic-gate */
429*0Sstevel@tonic-gate
430*0Sstevel@tonic-gate static int
ldif_base64_encode_internal(unsigned char * src,char * dst,int srclen,int lenused,int wraplen)431*0Sstevel@tonic-gate ldif_base64_encode_internal( unsigned char *src, char *dst, int srclen, int lenused, int wraplen )
432*0Sstevel@tonic-gate {
433*0Sstevel@tonic-gate unsigned char *byte, *stop;
434*0Sstevel@tonic-gate unsigned char buf[3];
435*0Sstevel@tonic-gate char *out;
436*0Sstevel@tonic-gate unsigned long bits;
437*0Sstevel@tonic-gate int i, pad, len;
438*0Sstevel@tonic-gate
439*0Sstevel@tonic-gate len = 0;
440*0Sstevel@tonic-gate out = dst;
441*0Sstevel@tonic-gate stop = src + srclen;
442*0Sstevel@tonic-gate
443*0Sstevel@tonic-gate /* convert to base 64 (3 bytes => 4 base 64 digits) */
444*0Sstevel@tonic-gate for ( byte = src; byte < stop - 2; byte += 3 ) {
445*0Sstevel@tonic-gate bits = (byte[0] & 0xff) << 16;
446*0Sstevel@tonic-gate bits |= (byte[1] & 0xff) << 8;
447*0Sstevel@tonic-gate bits |= (byte[2] & 0xff);
448*0Sstevel@tonic-gate
449*0Sstevel@tonic-gate for ( i = 0; i < 4; i++, bits <<= 6 ) {
450*0Sstevel@tonic-gate if ( wraplen != -1 && lenused >= 0 && lenused++ > wraplen ) {
451*0Sstevel@tonic-gate *out++ = '\n';
452*0Sstevel@tonic-gate *out++ = ' ';
453*0Sstevel@tonic-gate lenused = 2;
454*0Sstevel@tonic-gate }
455*0Sstevel@tonic-gate
456*0Sstevel@tonic-gate /* get b64 digit from high order 6 bits */
457*0Sstevel@tonic-gate *out++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
458*0Sstevel@tonic-gate }
459*0Sstevel@tonic-gate }
460*0Sstevel@tonic-gate
461*0Sstevel@tonic-gate /* add padding if necessary */
462*0Sstevel@tonic-gate if ( byte < stop ) {
463*0Sstevel@tonic-gate for ( i = 0; byte + i < stop; i++ ) {
464*0Sstevel@tonic-gate buf[i] = byte[i];
465*0Sstevel@tonic-gate }
466*0Sstevel@tonic-gate for ( pad = 0; i < 3; i++, pad++ ) {
467*0Sstevel@tonic-gate buf[i] = '\0';
468*0Sstevel@tonic-gate }
469*0Sstevel@tonic-gate byte = buf;
470*0Sstevel@tonic-gate bits = (byte[0] & 0xff) << 16;
471*0Sstevel@tonic-gate bits |= (byte[1] & 0xff) << 8;
472*0Sstevel@tonic-gate bits |= (byte[2] & 0xff);
473*0Sstevel@tonic-gate
474*0Sstevel@tonic-gate for ( i = 0; i < 4; i++, bits <<= 6 ) {
475*0Sstevel@tonic-gate if ( wraplen != -1 && lenused >= 0 && lenused++ > wraplen ) {
476*0Sstevel@tonic-gate *out++ = '\n';
477*0Sstevel@tonic-gate *out++ = ' ';
478*0Sstevel@tonic-gate lenused = 2;
479*0Sstevel@tonic-gate }
480*0Sstevel@tonic-gate
481*0Sstevel@tonic-gate if (( i == 3 && pad > 0 ) || ( i == 2 && pad == 2 )) {
482*0Sstevel@tonic-gate /* Pad as appropriate */
483*0Sstevel@tonic-gate *out++ = '=';
484*0Sstevel@tonic-gate } else {
485*0Sstevel@tonic-gate /* get b64 digit from low order 6 bits */
486*0Sstevel@tonic-gate *out++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
487*0Sstevel@tonic-gate }
488*0Sstevel@tonic-gate }
489*0Sstevel@tonic-gate }
490*0Sstevel@tonic-gate
491*0Sstevel@tonic-gate *out = '\0';
492*0Sstevel@tonic-gate
493*0Sstevel@tonic-gate return( out - dst );
494*0Sstevel@tonic-gate }
495*0Sstevel@tonic-gate
496*0Sstevel@tonic-gate int
ldif_base64_encode(unsigned char * src,char * dst,int srclen,int lenused)497*0Sstevel@tonic-gate ldif_base64_encode( unsigned char *src, char *dst, int srclen, int lenused )
498*0Sstevel@tonic-gate {
499*0Sstevel@tonic-gate return ldif_base64_encode_internal( src, dst, srclen, lenused, LDIF_MAX_LINE_WIDTH );
500*0Sstevel@tonic-gate }
501*0Sstevel@tonic-gate
502*0Sstevel@tonic-gate int
ldif_base64_encode_nowrap(unsigned char * src,char * dst,int srclen,int lenused)503*0Sstevel@tonic-gate ldif_base64_encode_nowrap( unsigned char *src, char *dst, int srclen, int lenused )
504*0Sstevel@tonic-gate {
505*0Sstevel@tonic-gate return ldif_base64_encode_internal( src, dst, srclen, lenused, -1 );
506*0Sstevel@tonic-gate }
507*0Sstevel@tonic-gate
508*0Sstevel@tonic-gate
509*0Sstevel@tonic-gate /*
510*0Sstevel@tonic-gate * return malloc'd, zero-terminated LDIF line
511*0Sstevel@tonic-gate */
512*0Sstevel@tonic-gate char *
ldif_type_and_value_with_options(char * type,char * val,int vlen,unsigned long options)513*0Sstevel@tonic-gate ldif_type_and_value_with_options( char *type, char *val, int vlen,
514*0Sstevel@tonic-gate unsigned long options )
515*0Sstevel@tonic-gate {
516*0Sstevel@tonic-gate char *buf, *p;
517*0Sstevel@tonic-gate int tlen;
518*0Sstevel@tonic-gate
519*0Sstevel@tonic-gate tlen = strlen( type );
520*0Sstevel@tonic-gate if (( buf = (char *)malloc( LDIF_SIZE_NEEDED( tlen, vlen ) + 1 )) !=
521*0Sstevel@tonic-gate NULL ) {
522*0Sstevel@tonic-gate p = buf;
523*0Sstevel@tonic-gate ldif_put_type_and_value_with_options( &p, type, val, vlen, options );
524*0Sstevel@tonic-gate *p = '\0';
525*0Sstevel@tonic-gate }
526*0Sstevel@tonic-gate
527*0Sstevel@tonic-gate return( buf );
528*0Sstevel@tonic-gate }
529*0Sstevel@tonic-gate
530*0Sstevel@tonic-gate char *
ldif_type_and_value(char * type,char * val,int vlen)531*0Sstevel@tonic-gate ldif_type_and_value( char *type, char *val, int vlen )
532*0Sstevel@tonic-gate {
533*0Sstevel@tonic-gate return ldif_type_and_value_with_options( type, val, vlen, 0 );
534*0Sstevel@tonic-gate }
535*0Sstevel@tonic-gate
536*0Sstevel@tonic-gate char *
ldif_type_and_value_nowrap(char * type,char * val,int vlen)537*0Sstevel@tonic-gate ldif_type_and_value_nowrap( char *type, char *val, int vlen )
538*0Sstevel@tonic-gate {
539*0Sstevel@tonic-gate return ldif_type_and_value_with_options( type, val, vlen, LDIF_OPT_NOWRAP );
540*0Sstevel@tonic-gate }
541*0Sstevel@tonic-gate
542*0Sstevel@tonic-gate /*
543*0Sstevel@tonic-gate * ldif_get_entry - read the next ldif entry from the FILE referenced
544*0Sstevel@tonic-gate * by fp. return a pointer to a malloc'd, null-terminated buffer. also
545*0Sstevel@tonic-gate * returned is the last line number read, in *lineno.
546*0Sstevel@tonic-gate */
547*0Sstevel@tonic-gate char *
ldif_get_entry(FILE * fp,int * lineno)548*0Sstevel@tonic-gate ldif_get_entry( FILE *fp, int *lineno )
549*0Sstevel@tonic-gate {
550*0Sstevel@tonic-gate char line[BUFSIZ];
551*0Sstevel@tonic-gate char *buf;
552*0Sstevel@tonic-gate int max, cur, len, gotsome;
553*0Sstevel@tonic-gate
554*0Sstevel@tonic-gate buf = NULL;
555*0Sstevel@tonic-gate max = cur = gotsome = 0;
556*0Sstevel@tonic-gate while ( fgets( line, sizeof(line), fp ) != NULL ) {
557*0Sstevel@tonic-gate if ( lineno != NULL ) {
558*0Sstevel@tonic-gate (*lineno)++;
559*0Sstevel@tonic-gate }
560*0Sstevel@tonic-gate /* ldif entries are terminated by a \n on a line by itself */
561*0Sstevel@tonic-gate if ( line[0] == '\0' || line[0] == '\n'
562*0Sstevel@tonic-gate #if !defined( XP_WIN32 )
563*0Sstevel@tonic-gate || ( line[0] == '\r' && line[1] == '\n' ) /* DOS format */
564*0Sstevel@tonic-gate #endif
565*0Sstevel@tonic-gate ) {
566*0Sstevel@tonic-gate if ( gotsome ) {
567*0Sstevel@tonic-gate break;
568*0Sstevel@tonic-gate } else {
569*0Sstevel@tonic-gate continue;
570*0Sstevel@tonic-gate }
571*0Sstevel@tonic-gate } else if ( line[0] == '#' ) {
572*0Sstevel@tonic-gate continue;
573*0Sstevel@tonic-gate }
574*0Sstevel@tonic-gate gotsome = 1;
575*0Sstevel@tonic-gate len = strlen( line );
576*0Sstevel@tonic-gate #if !defined( XP_WIN32 )
577*0Sstevel@tonic-gate /* DOS format */
578*0Sstevel@tonic-gate if ( len > 0 && line[len-1] == '\r' ) {
579*0Sstevel@tonic-gate --len;
580*0Sstevel@tonic-gate line[len] = '\0';
581*0Sstevel@tonic-gate } else if ( len > 1 && line[len-2] == '\r' && line[len-1] == '\n' ) {
582*0Sstevel@tonic-gate --len;
583*0Sstevel@tonic-gate line[len-1] = line[len];
584*0Sstevel@tonic-gate line[len] = '\0';
585*0Sstevel@tonic-gate }
586*0Sstevel@tonic-gate #endif
587*0Sstevel@tonic-gate while ( cur + (len + 1) > max ) {
588*0Sstevel@tonic-gate if ( buf == NULL ) {
589*0Sstevel@tonic-gate max += BUFSIZ;
590*0Sstevel@tonic-gate buf = (char *) malloc( max );
591*0Sstevel@tonic-gate } else {
592*0Sstevel@tonic-gate max *= 2;
593*0Sstevel@tonic-gate buf = (char *) realloc( buf, max );
594*0Sstevel@tonic-gate }
595*0Sstevel@tonic-gate if ( buf == NULL ) {
596*0Sstevel@tonic-gate return( NULL );
597*0Sstevel@tonic-gate }
598*0Sstevel@tonic-gate }
599*0Sstevel@tonic-gate
600*0Sstevel@tonic-gate memcpy( buf + cur, line, len + 1 );
601*0Sstevel@tonic-gate cur += len;
602*0Sstevel@tonic-gate }
603*0Sstevel@tonic-gate
604*0Sstevel@tonic-gate return( buf );
605*0Sstevel@tonic-gate }
606