utils.c revision 1.5 1 /* $NetBSD: utils.c,v 1.5 2004/08/13 15:03:57 tv Exp $ */
2
3 /*-
4 * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Roland C. Dowdeswell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 #ifndef lint
41 __RCSID("$NetBSD: utils.c,v 1.5 2004/08/13 15:03:57 tv Exp $");
42 #endif
43
44 #include <sys/param.h>
45
46 #include <stdlib.h>
47 #include <string.h>
48
49 /* include the resolver gunk in order that we can use b64 routines */
50 #include <netinet/in.h>
51 #include <arpa/nameser.h>
52 #include <resolv.h>
53
54 #include "utils.h"
55
56 /* just strsep(3), but skips empty fields. */
57
58 static char *
59 strsep_getnext(char **stringp, const char *delim)
60 {
61 char *ret;
62
63 ret = strsep(stringp, delim);
64 while (ret && index(delim, *ret))
65 ret = strsep(stringp, delim);
66 return ret;
67 }
68
69 /*
70 * this function returns a dynamically sized char ** of the words
71 * in the line. the caller is responsible for both free(3)ing
72 * each word and the superstructure by calling words_free().
73 */
74 char **
75 words(const char *line, int *num)
76 {
77 int i = 0;
78 int nwords = 0;
79 char *cur;
80 char **ret;
81 char *tmp;
82 char *tmp1;
83
84 *num = 0;
85 tmp = (char *)line;
86 if (tmp[0] == '\0')
87 return NULL;
88 while (tmp[0]) {
89 if ((tmp[1] == ' ' || tmp[1] == '\t' || tmp[1] == '\0') &&
90 (tmp[0] != ' ' && tmp[0] != '\t'))
91 nwords++;
92 tmp++;
93 }
94 ret = malloc((nwords+1) * sizeof(char *));
95 tmp1 = tmp = strdup(line);
96 while ((cur = strsep_getnext(&tmp, " \t")) != NULL)
97 ret[i++] = strdup(cur);
98 ret[i] = NULL;
99 free(tmp1);
100 *num = nwords;
101 return ret;
102 }
103
104 void
105 words_free(char **w, int num)
106 {
107 int i;
108
109 for (i=0; i < num; i++)
110 free(w[i]);
111 }
112
113 /*
114 * this is a simple xor that has the same calling conventions as
115 * memcpy(3).
116 */
117
118 void
119 memxor(void *res, const void *src, size_t len)
120 {
121 int i;
122 char *r;
123 const char *s;
124
125 r = res;
126 s = src;
127 for (i=0; i < len; i++)
128 r[i] ^= s[i];
129 }
130
131 /*
132 * well, a very simple set of string functions...
133 *
134 * The goal here is basically to manage length encoded strings,
135 * but just for safety we nul terminate them anyway.
136 */
137
138 /* for now we use a very simple encoding */
139
140 struct string {
141 int length;
142 char *text;
143 };
144
145 string_t *
146 string_new(const char *intext, int inlength)
147 {
148 string_t *out;
149
150 out = malloc(sizeof(*out));
151 out->length = inlength;
152 out->text = malloc(out->length + 1);
153 memcpy(out->text, intext, out->length);
154 out->text[out->length] = '\0';
155 return out;
156 }
157
158 string_t *
159 string_dup(const string_t *in)
160 {
161
162 return string_new(in->text, in->length);
163 }
164
165 void
166 string_free(string_t *s)
167 {
168
169 if (!s)
170 return;
171 free_notnull(s->text);
172 free(s);
173 }
174
175 void
176 string_assign(string_t **lhs, string_t *rhs)
177 {
178
179 string_free(*lhs);
180 *lhs = rhs;
181 }
182
183 string_t *
184 string_add(const string_t *a1, const string_t *a2)
185 {
186 string_t *sum;
187
188 sum = malloc(sizeof(*sum));
189 sum->length = a1->length + a2->length;
190 sum->text = malloc(sum->length + 1);
191 memcpy(sum->text, a1->text, a1->length);
192 memcpy(sum->text + a1->length, a2->text, a2->length);
193 sum->text[sum->length] = '\0';
194 return sum;
195 }
196
197 string_t *
198 string_add_d(string_t *a1, string_t *a2)
199 {
200 string_t *sum;
201
202 sum = string_add(a1, a2);
203 string_free(a1);
204 string_free(a2);
205 return sum;
206 }
207
208 string_t *
209 string_fromcharstar(const char *in)
210 {
211
212 return string_new(in, strlen(in));
213 }
214
215 const char *
216 string_tocharstar(const string_t *in)
217 {
218
219 return in->text;
220 }
221
222 string_t *
223 string_fromint(int in)
224 {
225 string_t *ret;
226
227 ret = malloc(sizeof(*ret));
228 if (!ret)
229 return NULL;
230 ret->length = asprintf(&ret->text, "%d", in);
231 if (ret->length == -1) {
232 free(ret);
233 ret = NULL;
234 }
235 return ret;
236 }
237
238 void
239 string_fprint(FILE *f, const string_t *s)
240 {
241
242 fwrite(s->text, s->length, 1, f);
243 }
244
245 struct bits {
246 int length;
247 char *text;
248 };
249
250 bits_t *
251 bits_new(const void *buf, int len)
252 {
253 bits_t *b;
254
255 /* XXX do some level of error checking here */
256 b = malloc(sizeof(*b));
257 b->length = len;
258 b->text = malloc(BITS2BYTES(b->length));
259 memcpy(b->text, buf, BITS2BYTES(b->length));
260 return b;
261 }
262
263 bits_t *
264 bits_dup(const bits_t *in)
265 {
266
267 return bits_new(in->text, in->length);
268 }
269
270 void
271 bits_free(bits_t *b)
272 {
273
274 if (!b)
275 return;
276 free_notnull(b->text);
277 free(b);
278 }
279
280 void
281 bits_assign(bits_t **lhs, bits_t *rhs)
282 {
283
284 bits_free(*lhs);
285 *lhs = rhs;
286 }
287
288 const void *
289 bits_getbuf(bits_t *in)
290 {
291
292 return in->text;
293 }
294
295 int
296 bits_len(bits_t *in)
297 {
298
299 return in->length;
300 }
301
302 int
303 bits_match(const bits_t *b1, const bits_t *b2)
304 {
305 int i;
306
307 if (b1->length != b2->length)
308 return 0;
309
310 for (i = 0; i < BITS2BYTES(b1->length); i++)
311 if (b1->text[i] != b2->text[i])
312 return 0;
313
314 return 1;
315 }
316
317 bits_t *
318 bits_xor(const bits_t *x1, const bits_t *x2)
319 {
320 bits_t *b;
321 int i;
322
323 /* XXX do some level of error checking here */
324 b = malloc(sizeof(*b));
325 b->length = MAX(x1->length, x2->length);
326 b->text = calloc(1, BITS2BYTES(b->length));
327 for (i=0; i < BITS2BYTES(MIN(x1->length, x2->length)); i++)
328 b->text[i] = x1->text[i] ^ x2->text[i];
329 return b;
330 }
331
332 bits_t *
333 bits_xor_d(bits_t *x1, bits_t *x2)
334 {
335 bits_t *ret;
336
337 ret = bits_xor(x1, x2);
338 bits_free(x1);
339 bits_free(x2);
340 return ret;
341 }
342
343 /*
344 * bits_decode() reads an encoded base64 stream. We interpret
345 * the first 32 bits as an unsigned integer in network byte order
346 * specifying the number of bits in the stream to give a little
347 * resilience.
348 */
349
350 bits_t *
351 bits_decode(const string_t *in)
352 {
353 bits_t *ret;
354 int len;
355 int nbits;
356 char *tmp;
357
358 len = in->length;
359 tmp = malloc(len);
360 if (!tmp)
361 return NULL;
362
363 len = __b64_pton(in->text, tmp, len);
364
365 if (len == -1) {
366 fprintf(stderr, "bits_decode: mangled base64 stream\n");
367 fprintf(stderr, " %s\n", in->text);
368 return NULL;
369 }
370
371 nbits = ntohl(*((u_int32_t *)tmp));
372 if (nbits > (len - 4) * 8) {
373 fprintf(stderr, "bits_decode: encoded bits claim to be "
374 "longer than they are (nbits=%u, stream len=%u bytes)\n",
375 (unsigned)nbits, (unsigned)len);
376 return NULL;
377 }
378
379 ret = bits_new(tmp+4, nbits);
380 free(tmp);
381 return ret;
382 }
383
384 bits_t *
385 bits_decode_d(string_t *in)
386 {
387 bits_t *ret;
388
389 ret = bits_decode(in);
390 string_free(in);
391 return ret;
392 }
393
394 string_t *
395 bits_encode(const bits_t *in)
396 {
397 string_t *ret;
398 int len;
399 char *out;
400 char *tmp;
401
402 if (!in)
403 return NULL;
404
405 /* compute the total size of the input stream */
406 len = BITS2BYTES(in->length) + 4;
407
408 tmp = malloc(len);
409 out = malloc(len * 2);
410 if (!tmp || !out) {
411 free_notnull(tmp);
412 free_notnull(out);
413 return NULL;
414 }
415
416 /* stuff the length up front */
417 *((u_int32_t *)tmp) = htonl(in->length);
418 memcpy(tmp + 4, in->text, len - 4);
419
420 len = __b64_ntop(tmp, len, out, len * 2);
421 ret = string_new(out, len);
422 free(tmp);
423 free(out);
424 return ret;
425 }
426
427 string_t *
428 bits_encode_d(bits_t *in)
429 {
430 string_t *ret;
431
432 ret = bits_encode(in);
433 bits_free(in);
434 return ret;
435 }
436
437 bits_t *
438 bits_fget(FILE *f, int len)
439 {
440 bits_t *bits;
441 int ret;
442
443 bits = malloc(sizeof(*bits));
444 if (!bits)
445 return NULL;
446 bits->length = len;
447 bits->text = malloc(BITS2BYTES(bits->length));
448 if (!bits->text) {
449 free(bits);
450 return NULL;
451 }
452 ret = fread(bits->text, BITS2BYTES(bits->length), 1, f);
453 if (ret != 1) {
454 bits_free(bits);
455 return NULL;
456 }
457 return bits;
458 }
459
460 bits_t *
461 bits_cget(const char *fn, int len)
462 {
463 bits_t *bits;
464 FILE *f;
465
466 f = fopen(fn, "r");
467 if (!f) {
468 free(bits->text);
469 free(bits);
470 return NULL;
471 }
472
473 bits = bits_fget(f, len);
474 fclose(f);
475 return bits;
476 }
477
478 bits_t *
479 bits_getrandombits(int len, int hard)
480 {
481
482 return bits_cget((hard ? "/dev/random" : "/dev/urandom"), len);
483 }
484
485 void
486 bits_fprint(FILE *f, const bits_t *bits)
487 {
488 string_t *s;
489
490 s = bits_encode(bits);
491 string_fprint(f, s);
492 free(s);
493 }
494
495 void
496 free_notnull(void *b)
497 {
498
499 if (b)
500 free(b);
501 }
502