1/* $NetBSD: utils.c,v 1.19 2008/05/11 03:15:21 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 *
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.19 2008/05/11 03:15:21 elric 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
54static char *
55strsep_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 */
70char **
71words(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
100void
101words_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
114void
115memxor(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
136struct string {
137	char	*text;
138	size_t	 length;
139};
140
141string_t *
142string_zero()
143{
144	string_t *out;
145
146	out = emalloc(sizeof(*out));
147	out->length = 0;
148	out->text = NULL;
149	return out;
150}
151
152string_t *
153string_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
165string_t *
166string_dup(const string_t *in)
167{
168
169	return string_new(in->text, in->length);
170}
171
172void
173string_free(string_t *s)
174{
175
176	if (!s)
177		return;
178	free(s->text);
179	free(s);
180}
181
182void
183string_assign(string_t **lhs, string_t *rhs)
184{
185
186	string_free(*lhs);
187	*lhs = rhs;
188}
189
190string_t *
191string_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
204string_t *
205string_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
215string_t *
216string_fromcharstar(const char *in)
217{
218
219	return string_new(in, strlen(in));
220}
221
222const char *
223string_tocharstar(const string_t *in)
224{
225
226	return in->text;
227}
228
229string_t *
230string_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
241void
242string_fprint(FILE *f, const string_t *s)
243{
244	(void)fwrite(s->text, s->length, 1, f);
245}
246
247struct bits {
248	size_t	 length;
249	char	*text;
250};
251
252bits_t *
253bits_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
264bits_t *
265bits_dup(const bits_t *in)
266{
267
268	return bits_new(in->text, in->length);
269}
270
271void
272bits_free(bits_t *b)
273{
274
275	if (!b)
276		return;
277	free(b->text);
278	free(b);
279}
280
281void
282bits_assign(bits_t **lhs, bits_t *rhs)
283{
284
285	bits_free(*lhs);
286	*lhs = rhs;
287}
288
289const void *
290bits_getbuf(bits_t *in)
291{
292
293	return in->text;
294}
295
296size_t
297bits_len(bits_t *in)
298{
299
300	return in->length;
301}
302
303int
304bits_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
318bits_t *
319bits_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
332bits_t *
333bits_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
350bits_t *
351bits_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
384bits_t *
385bits_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
394string_t *
395bits_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
425string_t *
426bits_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
435bits_t *
436bits_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
452bits_t *
453bits_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
467bits_t *
468bits_getrandombits(size_t len, int hard)
469{
470
471	return bits_cget((hard ? "/dev/random" : "/dev/urandom"), len);
472}
473
474void
475bits_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