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