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