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