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