1 /* $NetBSD: utils.c,v 1.17 2007/11/06 02:50:49 christos 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.17 2007/11/06 02:50:49 christos Exp $"); 42 #endif 43 44 #include <sys/param.h> 45 46 #include <stdlib.h> 47 #include <string.h> 48 #include <err.h> 49 #include <util.h> 50 51 /* include the resolver gunk in order that we can use b64 routines */ 52 #include <netinet/in.h> 53 #include <arpa/nameser.h> 54 #include <resolv.h> 55 56 #include "utils.h" 57 58 59 /* just strsep(3), but skips empty fields. */ 60 61 static char * 62 strsep_getnext(char **stringp, const char *delim) 63 { 64 char *ret; 65 66 ret = strsep(stringp, delim); 67 while (ret && index(delim, *ret)) 68 ret = strsep(stringp, delim); 69 return ret; 70 } 71 72 /* 73 * this function returns a dynamically sized char ** of the words 74 * in the line. the caller is responsible for both free(3)ing 75 * each word and the superstructure by calling words_free(). 76 */ 77 char ** 78 words(const char *line, int *num) 79 { 80 int i = 0; 81 int nwords = 0; 82 char *cur; 83 char **ret; 84 const char *tmp; 85 char *tmp1, *tmpf; 86 87 *num = 0; 88 tmp = line; 89 if (tmp[0] == '\0') 90 return NULL; 91 while (tmp[0]) { 92 if ((tmp[1] == ' ' || tmp[1] == '\t' || tmp[1] == '\0') && 93 (tmp[0] != ' ' && tmp[0] != '\t')) 94 nwords++; 95 tmp++; 96 } 97 ret = emalloc((nwords+1) * sizeof(char *)); 98 tmp1 = tmpf = estrdup(line); 99 while ((cur = strsep_getnext(&tmpf, " \t")) != NULL) 100 ret[i++] = estrdup(cur); 101 ret[i] = NULL; 102 free(tmp1); 103 *num = nwords; 104 return ret; 105 } 106 107 void 108 words_free(char **w, int num) 109 { 110 int i; 111 112 for (i=0; i < num; i++) 113 free(w[i]); 114 } 115 116 /* 117 * this is a simple xor that has the same calling conventions as 118 * memcpy(3). 119 */ 120 121 void 122 memxor(void *res, const void *src, size_t len) 123 { 124 char *r; 125 const char *s; 126 size_t i; 127 128 r = res; 129 s = src; 130 for (i = 0; i < len; i++) 131 r[i] ^= s[i]; 132 } 133 134 /* 135 * well, a very simple set of string functions... 136 * 137 * The goal here is basically to manage length encoded strings, 138 * but just for safety we nul terminate them anyway. 139 */ 140 141 /* for now we use a very simple encoding */ 142 143 struct string { 144 char *text; 145 size_t length; 146 }; 147 148 string_t * 149 string_new(const char *intext, size_t inlength) 150 { 151 string_t *out; 152 153 out = emalloc(sizeof(*out)); 154 out->length = inlength; 155 out->text = emalloc(out->length + 1); 156 (void)memcpy(out->text, intext, out->length); 157 out->text[out->length] = '\0'; 158 return out; 159 } 160 161 string_t * 162 string_dup(const string_t *in) 163 { 164 165 return string_new(in->text, in->length); 166 } 167 168 void 169 string_free(string_t *s) 170 { 171 172 if (!s) 173 return; 174 free(s->text); 175 free(s); 176 } 177 178 void 179 string_assign(string_t **lhs, string_t *rhs) 180 { 181 182 string_free(*lhs); 183 *lhs = rhs; 184 } 185 186 string_t * 187 string_add(const string_t *a1, const string_t *a2) 188 { 189 string_t *sum; 190 191 sum = emalloc(sizeof(*sum)); 192 sum->length = a1->length + a2->length; 193 sum->text = emalloc(sum->length + 1); 194 (void)memcpy(sum->text, a1->text, a1->length); 195 (void)memcpy(sum->text + a1->length, a2->text, a2->length); 196 sum->text[sum->length] = '\0'; 197 return sum; 198 } 199 200 string_t * 201 string_add_d(string_t *a1, string_t *a2) 202 { 203 string_t *sum; 204 205 sum = string_add(a1, a2); 206 string_free(a1); 207 string_free(a2); 208 return sum; 209 } 210 211 string_t * 212 string_fromcharstar(const char *in) 213 { 214 215 return string_new(in, strlen(in)); 216 } 217 218 const char * 219 string_tocharstar(const string_t *in) 220 { 221 222 return in->text; 223 } 224 225 string_t * 226 string_fromint(int in) 227 { 228 string_t *ret; 229 230 ret = emalloc(sizeof(*ret)); 231 ret->length = asprintf(&ret->text, "%d", in); 232 if (ret->text == NULL) 233 err(1, NULL); 234 return ret; 235 } 236 237 void 238 string_fprint(FILE *f, const string_t *s) 239 { 240 (void)fwrite(s->text, s->length, 1, f); 241 } 242 243 struct bits { 244 size_t length; 245 char *text; 246 }; 247 248 bits_t * 249 bits_new(const void *buf, size_t len) 250 { 251 bits_t *b; 252 253 b = emalloc(sizeof(*b)); 254 b->length = len; 255 b->text = emalloc(BITS2BYTES(b->length)); 256 (void)memcpy(b->text, buf, BITS2BYTES(b->length)); 257 return b; 258 } 259 260 bits_t * 261 bits_dup(const bits_t *in) 262 { 263 264 return bits_new(in->text, in->length); 265 } 266 267 void 268 bits_free(bits_t *b) 269 { 270 271 if (!b) 272 return; 273 free(b->text); 274 free(b); 275 } 276 277 void 278 bits_assign(bits_t **lhs, bits_t *rhs) 279 { 280 281 bits_free(*lhs); 282 *lhs = rhs; 283 } 284 285 const void * 286 bits_getbuf(bits_t *in) 287 { 288 289 return in->text; 290 } 291 292 size_t 293 bits_len(bits_t *in) 294 { 295 296 return in->length; 297 } 298 299 int 300 bits_match(const bits_t *b1, const bits_t *b2) 301 { 302 int i; 303 304 if (b1->length != b2->length) 305 return 0; 306 307 for (i = 0; i < BITS2BYTES(b1->length); i++) 308 if (b1->text[i] != b2->text[i]) 309 return 0; 310 311 return 1; 312 } 313 314 bits_t * 315 bits_xor(const bits_t *x1, const bits_t *x2) 316 { 317 bits_t *b; 318 int i; 319 320 b = emalloc(sizeof(*b)); 321 b->length = MAX(x1->length, x2->length); 322 b->text = ecalloc(1, BITS2BYTES(b->length)); 323 for (i=0; i < BITS2BYTES(MIN(x1->length, x2->length)); i++) 324 b->text[i] = x1->text[i] ^ x2->text[i]; 325 return b; 326 } 327 328 bits_t * 329 bits_xor_d(bits_t *x1, bits_t *x2) 330 { 331 bits_t *ret; 332 333 ret = bits_xor(x1, x2); 334 bits_free(x1); 335 bits_free(x2); 336 return ret; 337 } 338 339 /* 340 * bits_decode() reads an encoded base64 stream. We interpret 341 * the first 32 bits as an unsigned integer in network byte order 342 * specifying the number of bits in the stream to give a little 343 * resilience. 344 */ 345 346 bits_t * 347 bits_decode(const string_t *in) 348 { 349 bits_t *ret; 350 size_t len; 351 size_t nbits; 352 u_int32_t *tmp; 353 354 len = in->length; 355 tmp = emalloc(len); 356 357 len = __b64_pton(in->text, (void *)tmp, len); 358 359 if (len == (size_t)-1) { 360 warnx("bits_decode: mangled base64 stream"); 361 warnx(" %s", in->text); 362 free(tmp); 363 return NULL; 364 } 365 366 nbits = ntohl(*tmp); 367 if (nbits > (len - sizeof(*tmp)) * NBBY) { 368 warnx("bits_decode: encoded bits claim to be " 369 "longer than they are (nbits=%zu, stream len=%zu bytes)", 370 nbits, len); 371 free(tmp); 372 return NULL; 373 } 374 375 ret = bits_new(tmp + 1, nbits); 376 free(tmp); 377 return ret; 378 } 379 380 bits_t * 381 bits_decode_d(string_t *in) 382 { 383 bits_t *ret; 384 385 ret = bits_decode(in); 386 string_free(in); 387 return ret; 388 } 389 390 string_t * 391 bits_encode(const bits_t *in) 392 { 393 string_t *ret; 394 size_t len; 395 char *out; 396 u_int32_t *tmp; 397 398 if (!in) 399 return NULL; 400 401 /* compute the total size of the input stream */ 402 len = BITS2BYTES(in->length) + sizeof(*tmp); 403 404 tmp = emalloc(len); 405 out = emalloc(len * 2); 406 /* stuff the length up front */ 407 *tmp = htonl(in->length); 408 (void)memcpy(tmp + 1, in->text, len - sizeof(*tmp)); 409 410 if ((len = __b64_ntop((void *)tmp, len, out, len * 2)) == (size_t)-1) { 411 free(out); 412 free(tmp); 413 return NULL; 414 } 415 ret = string_new(out, len); 416 free(tmp); 417 free(out); 418 return ret; 419 } 420 421 string_t * 422 bits_encode_d(bits_t *in) 423 { 424 string_t *ret; 425 426 ret = bits_encode(in); 427 bits_free(in); 428 return ret; 429 } 430 431 bits_t * 432 bits_fget(FILE *f, size_t len) 433 { 434 bits_t *bits; 435 int ret; 436 437 bits = emalloc(sizeof(*bits)); 438 bits->length = len; 439 bits->text = emalloc(BITS2BYTES(bits->length)); 440 ret = fread(bits->text, BITS2BYTES(bits->length), 1, f); 441 if (ret != 1) { 442 bits_free(bits); 443 return NULL; 444 } 445 return bits; 446 } 447 448 bits_t * 449 bits_cget(const char *fn, size_t len) 450 { 451 bits_t *bits; 452 FILE *f; 453 454 f = fopen(fn, "r"); 455 if (!f) 456 return NULL; 457 458 bits = bits_fget(f, len); 459 (void)fclose(f); 460 return bits; 461 } 462 463 bits_t * 464 bits_getrandombits(size_t len, int hard) 465 { 466 467 return bits_cget((hard ? "/dev/random" : "/dev/urandom"), 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