xref: /onnv-gate/usr/src/lib/libldap4/util/line64.c (revision 0:68f95e015346)
1 /*
2  *
3  * Portions Copyright 07/23/97 Sun Microsystems, Inc. All Rights Reserved
4  *
5  */
6 /* line64.c - routines for dealing with the slapd line format */
7 
8 #pragma ident	"%Z%%M%	%I%	%E% SMI"
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include "lber.h"
18 #include "ldap.h"
19 #include "ldif.h"
20 
21 #define RIGHT2			0x03
22 #define RIGHT4			0x0f
23 #define CONTINUED_LINE_MARKER	'\001'
24 
25 static char nib2b64[0x40f] =
26         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
27 
28 static unsigned char b642nib[0x80] = {
29 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
30 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
31 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
32 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
33 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
34 	0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
35 	0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
36 	0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
37 	0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
38 	0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
39 	0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
40 	0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
41 	0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
42 	0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
43 	0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
44 	0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
45 };
46 
47 /*
48  * str_parse_line - takes a line of the form "type:[:] value" and splits it
49  * into components "type" and "value".  if a double colon separates type from
50  * value, then value is encoded in base 64, and parse_line un-decodes it
51  * (in place) before returning.
52  */
53 
54 int
str_parse_line(char * line,char ** type,char ** value,int * vlen)55 str_parse_line(
56     char	*line,
57     char	**type,
58     char	**value,
59     int		*vlen
60 )
61 {
62 	char	*p, *s, *d, *byte, *stop;
63 	char	nib;
64 	int	i = 0, b64 = 0;
65 
66 	int url = 0;
67 
68 	/* skip any leading space */
69 	while ( isspace( *line ) ) {
70 		line++;
71 	}
72 	*type = line;
73 
74 	for ( s = line; *s && *s != ':'; s++ )
75 		;	/* NULL */
76 	if ( *s == '\0' ) {
77 		Debug( LDAP_DEBUG_PARSE, catgets(slapdcat, 1, 263, "parse_line missing ':'\n"), 0, 0, 0 );
78 		return( -1 );
79 	}
80 
81 	/* trim any space between type and : */
82 	for ( p = s - 1; p > line && isspace( *p ); p-- ) {
83 		*p = '\0';
84 	}
85 	*s++ = '\0';
86 
87 	/* check for double : - indicates base 64 encoded value */
88 	if ( *s == ':' ) {
89 		s++;
90 		b64 = 1;
91 
92 	} else if ( *s == '<' ) { 		/* the value indicates an url */
93 		s++;
94 		url = 1;
95 
96 	} else { /* single : - normally encoded value */
97 		b64 = 0;
98 	}
99 
100 	/* skip space between : and value */
101 	while ( isspace( *s ) ) {
102 		s++;
103 	}
104 
105 	/* if no value is present, error out */
106 	if ( *s == '\0' ) {
107 		Debug( LDAP_DEBUG_PARSE, catgets(slapdcat, 1, 264, "parse_line missing value\n"), 0,0,0 );
108 		return( -1 );
109 	}
110 
111 	/* check for continued line markers that should be deleted */
112 	for ( p = s, d = s; *p; p++ ) {
113 		if ( *p != CONTINUED_LINE_MARKER )
114 			*d++ = *p;
115 	}
116 	*d = '\0';
117 
118 	if ( b64 ) {
119 		*value = s;
120 		stop = strchr( s, '\0' );
121 		byte = s;
122 		for ( p = s, *vlen = 0; p < stop; p += 4, *vlen += 3 ) {
123 			for ( i = 0; i < 3; i++ ) {
124 				if ( p[i] != '=' && (p[i] & 0x80 ||
125 				    b642nib[ p[i] & 0x7f ] > 0x3f) ) {
126 					Debug( LDAP_DEBUG_ANY,
127 				    catgets(slapdcat, 1, 265, "invalid base 64 encoding char (%1$c) 0x%2$x\n"),
128 					    p[i], p[i], 0 );
129 					return( -1 );
130 				}
131 			}
132 
133 			/* first digit */
134 			nib = b642nib[ p[0] & 0x7f ];
135 			byte[0] = nib << 2;
136 			/* second digit */
137 			nib = b642nib[ p[1] & 0x7f ];
138 			byte[0] |= nib >> 4;
139 			byte[1] = (nib & RIGHT4) << 4;
140 			/* third digit */
141 			if ( p[2] == '=' ) {
142 				*vlen += 1;
143 				break;
144 			}
145 			nib = b642nib[ p[2] & 0x7f ];
146 			byte[1] |= nib >> 2;
147 			byte[2] = (nib & RIGHT2) << 6;
148 			/* fourth digit */
149 			if ( p[3] == '=' ) {
150 				*vlen += 2;
151 				break;
152 			}
153 			nib = b642nib[ p[3] & 0x7f ];
154 			byte[2] |= nib;
155 
156 			byte += 3;
157 		}
158 		s[ *vlen ] = '\0';
159 	} else if ( url ) {		/* checks that the url is properly formed */
160 									/* file://[localhost]/<pathname> */
161 									/* value contains the content of the file */
162 		char * s2;
163 		char * filename;
164 
165 		FILE     *fp;
166 		int     rlen;
167 		int      eof;
168 
169 
170 		if ( strncmp(s, "file://localhost", 16) == 0 )
171 		{
172 			s = s+16;
173 		}
174 		else if ( strncmp(s, "file://", 7) == 0 )
175 		{
176 			s = s+7;
177 		}
178 		else
179 		{
180 			/* url badly formed */
181 			Debug( LDAP_DEBUG_ANY, catgets(slapdcat, 1, 1289, "invalid url %s\n"), s, 0, 0);
182 			return -1;
183 		}
184 
185 		filename = strdup(s);
186 
187 		/* now we have the filename, read its content and return the value */
188 		if (( fp = fopen( filename, "r" )) == NULL )
189 		{
190 			perror( filename );
191 			return( -1 );
192 		}
193 
194 		if ( fseek( fp, 0, SEEK_END ) != 0 )
195 		{
196 			perror( filename );
197 			fclose( fp );
198 			return( -1 );
199 		}
200 
201 		*vlen = ftell(fp);
202 		if ( (*value = (char *)malloc(*vlen)) == NULL )
203 		{
204 			perror("malloc");
205 			fclose(fp);
206 			return(-1);
207 		}
208 		if ( fseek( fp, 0, SEEK_SET ) != 0 )
209 		{
210 			perror( filename );
211 			fclose( fp );
212 			return( -1 );
213 		}
214 
215 		rlen = fread( *value, 1, *vlen, fp );
216 		eof = feof( fp );
217 		fclose( fp );
218 
219 		if ( rlen != *vlen )
220 		{
221 			perror( filename );
222 			return( -1 );
223 		}
224 
225 	} else {
226 		*value = s;
227 		*vlen = (int) (d - s);
228 	}
229 
230 	return( 0 );
231 }
232 
233 /*
234  * str_getline - return the next "line" (minus newline) of input from a
235  * string buffer of lines separated by newlines, terminated by \n\n
236  * or \0.  this routine handles continued lines, bundling them into
237  * a single big line before returning.  if a line begins with a white
238  * space character, it is a continuation of the previous line. the white
239  * space character (nb: only one char), and preceeding newline are changed
240  * into CONTINUED_LINE_MARKER chars, to be deleted later by the
241  * str_parse_line() routine above.
242  *
243  * it takes a pointer to a pointer to the buffer on the first call,
244  * which it updates and must be supplied on subsequent calls.
245  */
246 
247 char *
str_getline(char ** next)248 str_getline( char **next )
249 {
250 	char	*l;
251 	char	c;
252 
253 	if ( *next == NULL || **next == '\n' || **next == '\0' ) {
254 		return( NULL );
255 	}
256 
257 	l = *next;
258 	while ( (*next = strchr( *next, '\n' )) != NULL ) {
259 		c = *(*next + 1);
260 		if ( isspace( c ) && c != '\n' ) {
261 			**next = CONTINUED_LINE_MARKER;
262 			*(*next+1) = CONTINUED_LINE_MARKER;
263 		} else {
264 			*(*next)++ = '\0';
265 			break;
266 		}
267 		*(*next)++;
268 	}
269 
270 	return( l );
271 }
272 
273 void
put_type_and_value(char ** out,char * t,char * val,int vlen)274 put_type_and_value( char **out, char *t, char *val, int vlen )
275 {
276 	unsigned char	*byte, *p, *stop;
277 	unsigned char	buf[3];
278 	unsigned int	bits;
279 	char		*save;
280 	int		i, b64, pad, len, savelen;
281 	len = 0;
282 
283 	/* put the type + ": " */
284 	for ( p = (unsigned char *) t; *p; p++, len++ ) {
285 		*(*out)++ = *p;
286 	}
287 	*(*out)++ = ':';
288 	len++;
289 	save = *out;
290 	savelen = len;
291 	*(*out)++ = ' ';
292 	b64 = 0;
293 
294 	stop = (unsigned char *) (val + vlen);
295 	if ( isascii( val[0] ) && isspace( val[0] ) || val[0] == ':' ) {
296 		b64 = 1;
297 	} else {
298 		for ( byte = (unsigned char *) val; byte < stop;
299 		    byte++, len++ ) {
300 			if ( !isascii( *byte ) || !isprint( *byte ) ) {
301 				b64 = 1;
302 				break;
303 			}
304 			if ( len > LINE_WIDTH ) {
305 				*(*out)++ = '\n';
306 				*(*out)++ = ' ';
307 				len = 1;
308 			}
309 			*(*out)++ = *byte;
310 		}
311 	}
312 	if ( b64 ) {
313 		*out = save;
314 		*(*out)++ = ':';
315 		*(*out)++ = ' ';
316 		len = savelen + 2;
317 		/* convert to base 64 (3 bytes => 4 base 64 digits) */
318 		for ( byte = (unsigned char *) val; byte < stop - 2;
319 		    byte += 3 ) {
320 			bits = (byte[0] & 0xff) << 16;
321 			bits |= (byte[1] & 0xff) << 8;
322 			bits |= (byte[2] & 0xff);
323 
324 			for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
325 				if ( len > LINE_WIDTH ) {
326 					*(*out)++ = '\n';
327 					*(*out)++ = ' ';
328 					len = 1;
329 				}
330 
331 				/* get b64 digit from high order 6 bits */
332 				*(*out)++ = nib2b64[ (bits & 0xfc0000) >> 18 ];
333 			}
334 		}
335 
336 		/* add padding if necessary */
337 		if ( byte < stop ) {
338 			for ( i = 0; byte + i < stop; i++ ) {
339 				buf[i] = byte[i];
340 			}
341 			for ( pad = 0; i < 3; i++, pad++ ) {
342 				buf[i] = '\0';
343 			}
344 			byte = buf;
345 			bits = (byte[0] & 0xff) << 16;
346 			bits |= (byte[1] & 0xff) << 8;
347 			bits |= (byte[2] & 0xff);
348 
349 			for ( i = 0; i < 4; i++, len++, bits <<= 6 ) {
350 				if ( len > LINE_WIDTH ) {
351 					*(*out)++ = '\n';
352 					*(*out)++ = ' ';
353 					len = 1;
354 				}
355 
356 				/* get b64 digit from low order 6 bits */
357 				*(*out)++ = nib2b64[ (bits & 0xfc0000) >> 18 ];
358 			}
359 
360 			for ( ; pad > 0; pad-- ) {
361 				*(*out - pad) = '=';
362 			}
363 		}
364 	}
365 	*(*out)++ = '\n';
366 }
367 
368 
369 char *
ldif_type_and_value(char * type,char * val,int vlen)370 ldif_type_and_value( char *type, char *val, int vlen )
371 /*
372  * return malloc'd, zero-terminated LDIF line
373  */
374 {
375     char	*buf, *p;
376     int		tlen;
377 
378     buf=NULL;
379     tlen = strlen( type );
380     if (( buf = (char *)malloc( LDIF_SIZE_NEEDED( tlen, vlen ) + 1 )) !=
381 	    NULL ) {
382 
383        p = buf;
384        put_type_and_value( &p, type, val, vlen );
385        *p = '\0';
386     }
387     return( buf );
388 }
389