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