xref: /netbsd/sbin/cgdconfig/utils.c (revision a82baf23)
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