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