xref: /netbsd-src/sbin/cgdconfig/utils.c (revision 001c68bd94f75ce9270b69227c4199fbf34ee396)
1 /* $NetBSD: utils.c,v 1.2 2003/03/24 02:02:52 elric 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.2 2003/03/24 02:02:52 elric 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 bits_t *
303 bits_xor(const bits_t *x1, const bits_t *x2)
304 {
305 	bits_t	*b;
306 	int	 i;
307 
308 	/* XXX do some level of error checking here */
309 	b = malloc(sizeof(*b));
310 	b->length = MAX(x1->length, x2->length);
311 	b->text = calloc(1, BITS2BYTES(b->length));
312 	for (i=0; i < BITS2BYTES(MIN(x1->length, x2->length)); i++)
313 		b->text[i] = x1->text[i] ^ x2->text[i];
314 	return b;
315 }
316 
317 bits_t *
318 bits_xor_d(bits_t *x1, bits_t *x2)
319 {
320 	bits_t	*ret;
321 
322 	ret = bits_xor(x1, x2);
323 	bits_free(x1);
324 	bits_free(x2);
325 	return ret;
326 }
327 
328 /*
329  * bits_decode() reads an encoded base64 stream.  We interpret
330  * the first 32 bits as an unsigned integer in network byte order
331  * specifying the number of bits in the stream to give a little
332  * resilience.
333  */
334 
335 bits_t *
336 bits_decode(const string_t *in)
337 {
338 	bits_t	*ret;
339 	int	 len;
340 	int	 nbits;
341 	char	*tmp;
342 
343 	len = in->length;
344 	tmp = malloc(len);
345 	if (!tmp)
346 		return NULL;
347 
348 	len = __b64_pton(in->text, tmp, len);
349 
350 	if (len == -1) {
351 		fprintf(stderr, "bits_decode: mangled base64 stream\n");
352 		fprintf(stderr, "  %s\n", in->text);
353 		return NULL;
354 	}
355 
356 	nbits = ntohl(*((u_int32_t *)tmp));
357 	if (nbits > (len - 4) * 8) {
358 		fprintf(stderr, "bits_decode: encoded bits claim to be "
359 		    "longer than they are (nbits=%u, stream len=%u bytes)\n",
360 		    (unsigned)nbits, (unsigned)len);
361 		return NULL;
362 	}
363 
364 	ret = bits_new(tmp+4, nbits);
365 	free(tmp);
366 	return ret;
367 }
368 
369 bits_t *
370 bits_decode_d(string_t *in)
371 {
372 	bits_t *ret;
373 
374 	ret = bits_decode(in);
375 	string_free(in);
376 	return ret;
377 }
378 
379 string_t *
380 bits_encode(const bits_t *in)
381 {
382 	string_t *ret;
383 	int	 len;
384 	char	*out;
385 	char	*tmp;
386 
387 	if (!in)
388 		return NULL;
389 
390 	/* compute the total size of the input stream */
391 	len = BITS2BYTES(in->length) + 4;
392 
393 	tmp = malloc(len);
394 	out = malloc(len * 2);
395 	if (!tmp || !out) {
396 		free_notnull(tmp);
397 		free_notnull(out);
398 		return NULL;
399 	}
400 
401 	/* stuff the length up front */
402 	*((u_int32_t *)tmp) = htonl(in->length);
403 	memcpy(tmp + 4, in->text, len - 4);
404 
405 	len = __b64_ntop(tmp, len, out, len * 2);
406 	ret = string_new(out, len);
407 	free(tmp);
408 	free(out);
409 	return ret;
410 }
411 
412 string_t *
413 bits_encode_d(bits_t *in)
414 {
415 	string_t *ret;
416 
417 	ret = bits_encode(in);
418 	bits_free(in);
419 	return ret;
420 }
421 
422 bits_t *
423 bits_fget(FILE *f, int len)
424 {
425 	bits_t	*bits;
426 	int	 ret;
427 
428 	bits = malloc(sizeof(*bits));
429 	if (!bits)
430 		return NULL;
431 	bits->length = len;
432 	bits->text = malloc(BITS2BYTES(bits->length));
433 	if (!bits->text) {
434 		free(bits);
435 		return NULL;
436 	}
437 	ret = fread(bits->text, BITS2BYTES(bits->length), 1, f);
438 	if (ret != 1) {
439 		bits_free(bits);
440 		return NULL;
441 	}
442 	return bits;
443 }
444 
445 bits_t *
446 bits_cget(const char *fn, int len)
447 {
448 	bits_t	*bits;
449 	FILE	*f;
450 
451 	f = fopen(fn, "r");
452 	if (!f) {
453 		free(bits->text);
454 		free(bits);
455 		return NULL;
456 	}
457 
458 	bits = bits_fget(f, len);
459 	fclose(f);
460 	return bits;
461 }
462 
463 bits_t *
464 bits_getrandombits(int len)
465 {
466 
467 	return bits_cget("/dev/random", len);
468 }
469 
470 void
471 bits_fprint(FILE *f, const bits_t *bits)
472 {
473 	string_t *s;
474 
475 	s = bits_encode(bits);
476 	string_fprint(f, s);
477 	free(s);
478 }
479 
480 void
481 free_notnull(void *b)
482 {
483 
484 	if (b)
485 		free(b);
486 }
487