1 /* $NetBSD: utils.c,v 1.21 2012/03/20 18:50:30 matt 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.21 2012/03/20 18:50:30 matt 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 *
strsep_getnext(char ** stringp,const char * delim)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 **
words(const char * line,int * num)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
words_free(char ** w,int num)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
memxor(void * res,const void * src,size_t len)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 *
string_zero(void)142 string_zero(void)
143 {
144 string_t *out;
145
146 out = emalloc(sizeof(*out));
147 out->length = 0;
148 out->text = NULL;
149 return out;
150 }
151
152 string_t *
string_new(const char * intext,size_t inlength)153 string_new(const char *intext, size_t inlength)
154 {
155 string_t *out;
156
157 out = emalloc(sizeof(*out));
158 out->length = inlength;
159 out->text = emalloc(out->length + 1);
160 (void)memcpy(out->text, intext, out->length);
161 out->text[out->length] = '\0';
162 return out;
163 }
164
165 string_t *
string_dup(const string_t * in)166 string_dup(const string_t *in)
167 {
168
169 return string_new(in->text, in->length);
170 }
171
172 void
string_free(string_t * s)173 string_free(string_t *s)
174 {
175
176 if (!s)
177 return;
178 free(s->text);
179 free(s);
180 }
181
182 void
string_assign(string_t ** lhs,string_t * rhs)183 string_assign(string_t **lhs, string_t *rhs)
184 {
185
186 string_free(*lhs);
187 *lhs = rhs;
188 }
189
190 string_t *
string_add(const string_t * a1,const string_t * a2)191 string_add(const string_t *a1, const string_t *a2)
192 {
193 string_t *sum;
194
195 sum = emalloc(sizeof(*sum));
196 sum->length = a1->length + a2->length;
197 sum->text = emalloc(sum->length + 1);
198 (void)memcpy(sum->text, a1->text, a1->length);
199 (void)memcpy(sum->text + a1->length, a2->text, a2->length);
200 sum->text[sum->length] = '\0';
201 return sum;
202 }
203
204 string_t *
string_add_d(string_t * a1,string_t * a2)205 string_add_d(string_t *a1, string_t *a2)
206 {
207 string_t *sum;
208
209 sum = string_add(a1, a2);
210 string_free(a1);
211 string_free(a2);
212 return sum;
213 }
214
215 string_t *
string_fromcharstar(const char * in)216 string_fromcharstar(const char *in)
217 {
218
219 return string_new(in, strlen(in));
220 }
221
222 const char *
string_tocharstar(const string_t * in)223 string_tocharstar(const string_t *in)
224 {
225
226 return in->text;
227 }
228
229 string_t *
string_fromint(int in)230 string_fromint(int in)
231 {
232 string_t *ret;
233
234 ret = emalloc(sizeof(*ret));
235 ret->length = asprintf(&ret->text, "%d", in);
236 if (ret->text == NULL)
237 err(1, NULL);
238 return ret;
239 }
240
241 void
string_fprint(FILE * f,const string_t * s)242 string_fprint(FILE *f, const string_t *s)
243 {
244 (void)fwrite(s->text, s->length, 1, f);
245 }
246
247 struct bits {
248 size_t length;
249 char *text;
250 };
251
252 bits_t *
bits_new(const void * buf,size_t len)253 bits_new(const void *buf, size_t len)
254 {
255 bits_t *b;
256
257 b = emalloc(sizeof(*b));
258 b->length = len;
259 b->text = emalloc(BITS2BYTES(b->length));
260 (void)memcpy(b->text, buf, BITS2BYTES(b->length));
261 return b;
262 }
263
264 bits_t *
bits_dup(const bits_t * in)265 bits_dup(const bits_t *in)
266 {
267
268 return bits_new(in->text, in->length);
269 }
270
271 void
bits_free(bits_t * b)272 bits_free(bits_t *b)
273 {
274
275 if (!b)
276 return;
277 free(b->text);
278 free(b);
279 }
280
281 void
bits_assign(bits_t ** lhs,bits_t * rhs)282 bits_assign(bits_t **lhs, bits_t *rhs)
283 {
284
285 bits_free(*lhs);
286 *lhs = rhs;
287 }
288
289 const void *
bits_getbuf(bits_t * in)290 bits_getbuf(bits_t *in)
291 {
292
293 return in->text;
294 }
295
296 size_t
bits_len(bits_t * in)297 bits_len(bits_t *in)
298 {
299
300 return in->length;
301 }
302
303 int
bits_match(const bits_t * b1,const bits_t * b2)304 bits_match(const bits_t *b1, const bits_t *b2)
305 {
306 size_t i;
307
308 if (b1->length != b2->length)
309 return 0;
310
311 for (i = 0; i < BITS2BYTES(b1->length); i++)
312 if (b1->text[i] != b2->text[i])
313 return 0;
314
315 return 1;
316 }
317
318 bits_t *
bits_xor(const bits_t * x1,const bits_t * x2)319 bits_xor(const bits_t *x1, const bits_t *x2)
320 {
321 bits_t *b;
322 size_t i;
323
324 b = emalloc(sizeof(*b));
325 b->length = MAX(x1->length, x2->length);
326 b->text = ecalloc(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 *
bits_xor_d(bits_t * x1,bits_t * x2)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 *
bits_decode(const string_t * in)351 bits_decode(const string_t *in)
352 {
353 bits_t *ret;
354 size_t len;
355 size_t nbits;
356 u_int32_t *tmp;
357
358 len = in->length;
359 tmp = emalloc(len);
360
361 len = __b64_pton(in->text, (void *)tmp, len);
362
363 if (len == (size_t)-1) {
364 warnx("bits_decode: mangled base64 stream");
365 warnx(" %s", in->text);
366 free(tmp);
367 return NULL;
368 }
369
370 nbits = ntohl(*tmp);
371 if (nbits > (len - sizeof(*tmp)) * NBBY) {
372 warnx("bits_decode: encoded bits claim to be "
373 "longer than they are (nbits=%zu, stream len=%zu bytes)",
374 nbits, len);
375 free(tmp);
376 return NULL;
377 }
378
379 ret = bits_new(tmp + 1, nbits);
380 free(tmp);
381 return ret;
382 }
383
384 bits_t *
bits_decode_d(string_t * in)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 *
bits_encode(const bits_t * in)395 bits_encode(const bits_t *in)
396 {
397 string_t *ret;
398 size_t len;
399 char *out;
400 u_int32_t *tmp;
401
402 if (!in)
403 return NULL;
404
405 /* compute the total size of the input stream */
406 len = BITS2BYTES(in->length) + sizeof(*tmp);
407
408 tmp = emalloc(len);
409 out = emalloc(len * 2);
410 /* stuff the length up front */
411 *tmp = htonl(in->length);
412 (void)memcpy(tmp + 1, in->text, len - sizeof(*tmp));
413
414 if ((len = __b64_ntop((void *)tmp, len, out, len * 2)) == (size_t)-1) {
415 free(out);
416 free(tmp);
417 return NULL;
418 }
419 ret = string_new(out, len);
420 free(tmp);
421 free(out);
422 return ret;
423 }
424
425 string_t *
bits_encode_d(bits_t * in)426 bits_encode_d(bits_t *in)
427 {
428 string_t *ret;
429
430 ret = bits_encode(in);
431 bits_free(in);
432 return ret;
433 }
434
435 bits_t *
bits_fget(FILE * f,size_t len)436 bits_fget(FILE *f, size_t len)
437 {
438 bits_t *bits;
439 int ret;
440
441 bits = emalloc(sizeof(*bits));
442 bits->length = len;
443 bits->text = emalloc(BITS2BYTES(bits->length));
444 ret = fread(bits->text, BITS2BYTES(bits->length), 1, f);
445 if (ret != 1) {
446 bits_free(bits);
447 return NULL;
448 }
449 return bits;
450 }
451
452 bits_t *
bits_cget(const char * fn,size_t len)453 bits_cget(const char *fn, size_t len)
454 {
455 bits_t *bits;
456 FILE *f;
457
458 f = fopen(fn, "r");
459 if (!f)
460 return NULL;
461
462 bits = bits_fget(f, len);
463 (void)fclose(f);
464 return bits;
465 }
466
467 bits_t *
bits_getrandombits(size_t len,int hard)468 bits_getrandombits(size_t len, int hard)
469 {
470
471 return bits_cget((hard ? "/dev/random" : "/dev/urandom"), len);
472 }
473
474 void
bits_fprint(FILE * f,const bits_t * bits)475 bits_fprint(FILE *f, const bits_t *bits)
476 {
477 string_t *s;
478
479 s = bits_encode(bits);
480 string_fprint(f, s);
481 free(s);
482 }
483