Annotation of src/usr.bin/ssh/misc.c, Revision 1.59
1.59 ! stevesk 1: /* $OpenBSD: misc.c,v 1.58 2006/07/11 20:07:25 stevesk Exp $ */
1.1 markus 2: /*
3: * Copyright (c) 2000 Markus Friedl. All rights reserved.
1.52 djm 4: * Copyright (c) 2005,2006 Damien Miller. All rights reserved.
1.1 markus 5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
27: #include "includes.h"
1.45 stevesk 28:
29: #include <sys/ioctl.h>
1.54 stevesk 30: #include <sys/types.h>
1.53 stevesk 31: #include <sys/socket.h>
1.38 stevesk 32:
33: #include <net/if.h>
1.53 stevesk 34: #include <netinet/in.h>
1.44 stevesk 35: #include <netinet/tcp.h>
1.43 stevesk 36:
1.58 stevesk 37: #include <errno.h>
1.55 stevesk 38: #include <fcntl.h>
1.43 stevesk 39: #include <paths.h>
1.54 stevesk 40: #include <pwd.h>
1.57 stevesk 41: #include <stdarg.h>
1.59 ! stevesk 42: #include <unistd.h>
1.1 markus 43:
44: #include "misc.h"
45: #include "log.h"
1.3 deraadt 46: #include "xmalloc.h"
1.56 dtucker 47: #include "ssh.h"
1.1 markus 48:
1.12 markus 49: /* remove newline at end of string */
1.1 markus 50: char *
51: chop(char *s)
52: {
53: char *t = s;
54: while (*t) {
1.13 deraadt 55: if (*t == '\n' || *t == '\r') {
1.1 markus 56: *t = '\0';
57: return s;
58: }
59: t++;
60: }
61: return s;
62:
63: }
64:
1.12 markus 65: /* set/unset filedescriptor to non-blocking */
1.24 djm 66: int
1.1 markus 67: set_nonblock(int fd)
68: {
69: int val;
1.8 markus 70:
1.1 markus 71: val = fcntl(fd, F_GETFL, 0);
72: if (val < 0) {
73: error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
1.24 djm 74: return (-1);
1.1 markus 75: }
76: if (val & O_NONBLOCK) {
1.24 djm 77: debug3("fd %d is O_NONBLOCK", fd);
78: return (0);
1.1 markus 79: }
1.21 markus 80: debug2("fd %d setting O_NONBLOCK", fd);
1.1 markus 81: val |= O_NONBLOCK;
1.24 djm 82: if (fcntl(fd, F_SETFL, val) == -1) {
83: debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd,
84: strerror(errno));
85: return (-1);
86: }
87: return (0);
1.8 markus 88: }
89:
1.24 djm 90: int
1.8 markus 91: unset_nonblock(int fd)
92: {
93: int val;
94:
95: val = fcntl(fd, F_GETFL, 0);
96: if (val < 0) {
97: error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
1.24 djm 98: return (-1);
1.8 markus 99: }
100: if (!(val & O_NONBLOCK)) {
1.24 djm 101: debug3("fd %d is not O_NONBLOCK", fd);
102: return (0);
1.8 markus 103: }
1.10 markus 104: debug("fd %d clearing O_NONBLOCK", fd);
1.8 markus 105: val &= ~O_NONBLOCK;
1.24 djm 106: if (fcntl(fd, F_SETFL, val) == -1) {
107: debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s",
1.18 markus 108: fd, strerror(errno));
1.24 djm 109: return (-1);
110: }
111: return (0);
1.15 stevesk 112: }
113:
114: /* disable nagle on socket */
115: void
116: set_nodelay(int fd)
117: {
1.17 stevesk 118: int opt;
119: socklen_t optlen;
1.15 stevesk 120:
1.16 stevesk 121: optlen = sizeof opt;
122: if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
1.23 markus 123: debug("getsockopt TCP_NODELAY: %.100s", strerror(errno));
1.16 stevesk 124: return;
125: }
126: if (opt == 1) {
127: debug2("fd %d is TCP_NODELAY", fd);
128: return;
129: }
130: opt = 1;
1.20 markus 131: debug2("fd %d setting TCP_NODELAY", fd);
1.16 stevesk 132: if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
1.15 stevesk 133: error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
1.1 markus 134: }
135:
136: /* Characters considered whitespace in strsep calls. */
137: #define WHITESPACE " \t\r\n"
1.46 dtucker 138: #define QUOTE "\""
1.1 markus 139:
1.12 markus 140: /* return next token in configuration line */
1.1 markus 141: char *
142: strdelim(char **s)
143: {
144: char *old;
145: int wspace = 0;
146:
147: if (*s == NULL)
148: return NULL;
149:
150: old = *s;
151:
1.46 dtucker 152: *s = strpbrk(*s, WHITESPACE QUOTE "=");
1.1 markus 153: if (*s == NULL)
154: return (old);
155:
1.46 dtucker 156: if (*s[0] == '\"') {
157: memmove(*s, *s + 1, strlen(*s)); /* move nul too */
158: /* Find matching quote */
159: if ((*s = strpbrk(*s, QUOTE)) == NULL) {
160: return (NULL); /* no matching quote */
161: } else {
162: *s[0] = '\0';
163: return (old);
164: }
165: }
166:
1.1 markus 167: /* Allow only one '=' to be skipped */
168: if (*s[0] == '=')
169: wspace = 1;
170: *s[0] = '\0';
171:
1.46 dtucker 172: /* Skip any extra whitespace after first token */
1.1 markus 173: *s += strspn(*s + 1, WHITESPACE) + 1;
174: if (*s[0] == '=' && !wspace)
175: *s += strspn(*s + 1, WHITESPACE) + 1;
176:
177: return (old);
1.2 markus 178: }
179:
180: struct passwd *
181: pwcopy(struct passwd *pw)
182: {
1.49 djm 183: struct passwd *copy = xcalloc(1, sizeof(*copy));
1.4 deraadt 184:
1.2 markus 185: copy->pw_name = xstrdup(pw->pw_name);
186: copy->pw_passwd = xstrdup(pw->pw_passwd);
1.4 deraadt 187: copy->pw_gecos = xstrdup(pw->pw_gecos);
1.2 markus 188: copy->pw_uid = pw->pw_uid;
189: copy->pw_gid = pw->pw_gid;
1.11 markus 190: copy->pw_expire = pw->pw_expire;
191: copy->pw_change = pw->pw_change;
1.2 markus 192: copy->pw_class = xstrdup(pw->pw_class);
193: copy->pw_dir = xstrdup(pw->pw_dir);
194: copy->pw_shell = xstrdup(pw->pw_shell);
195: return copy;
1.5 stevesk 196: }
197:
1.12 markus 198: /*
199: * Convert ASCII string to TCP/IP port number.
200: * Port must be >0 and <=65535.
201: * Return 0 if invalid.
202: */
203: int
204: a2port(const char *s)
1.5 stevesk 205: {
206: long port;
207: char *endp;
208:
209: errno = 0;
210: port = strtol(s, &endp, 0);
211: if (s == endp || *endp != '\0' ||
212: (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) ||
213: port <= 0 || port > 65535)
214: return 0;
215:
216: return port;
1.9 stevesk 217: }
218:
1.36 reyk 219: int
220: a2tun(const char *s, int *remote)
221: {
222: const char *errstr = NULL;
223: char *sp, *ep;
224: int tun;
225:
226: if (remote != NULL) {
1.37 reyk 227: *remote = SSH_TUNID_ANY;
1.36 reyk 228: sp = xstrdup(s);
229: if ((ep = strchr(sp, ':')) == NULL) {
230: xfree(sp);
231: return (a2tun(s, NULL));
232: }
233: ep[0] = '\0'; ep++;
234: *remote = a2tun(ep, NULL);
235: tun = a2tun(sp, NULL);
236: xfree(sp);
1.37 reyk 237: return (*remote == SSH_TUNID_ERR ? *remote : tun);
1.36 reyk 238: }
239:
240: if (strcasecmp(s, "any") == 0)
1.37 reyk 241: return (SSH_TUNID_ANY);
1.36 reyk 242:
1.37 reyk 243: tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr);
244: if (errstr != NULL)
245: return (SSH_TUNID_ERR);
1.36 reyk 246:
247: return (tun);
248: }
249:
1.9 stevesk 250: #define SECONDS 1
251: #define MINUTES (SECONDS * 60)
252: #define HOURS (MINUTES * 60)
253: #define DAYS (HOURS * 24)
254: #define WEEKS (DAYS * 7)
255:
1.12 markus 256: /*
257: * Convert a time string into seconds; format is
258: * a sequence of:
259: * time[qualifier]
260: *
261: * Valid time qualifiers are:
262: * <none> seconds
263: * s|S seconds
264: * m|M minutes
265: * h|H hours
266: * d|D days
267: * w|W weeks
268: *
269: * Examples:
270: * 90m 90 minutes
271: * 1h30m 90 minutes
272: * 2d 2 days
273: * 1w 1 week
274: *
275: * Return -1 if time string is invalid.
276: */
277: long
278: convtime(const char *s)
1.9 stevesk 279: {
280: long total, secs;
281: const char *p;
282: char *endp;
283:
284: errno = 0;
285: total = 0;
286: p = s;
287:
288: if (p == NULL || *p == '\0')
289: return -1;
290:
291: while (*p) {
292: secs = strtol(p, &endp, 10);
293: if (p == endp ||
294: (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
295: secs < 0)
296: return -1;
297:
298: switch (*endp++) {
299: case '\0':
300: endp--;
1.48 deraadt 301: break;
1.9 stevesk 302: case 's':
303: case 'S':
304: break;
305: case 'm':
306: case 'M':
307: secs *= MINUTES;
308: break;
309: case 'h':
310: case 'H':
311: secs *= HOURS;
312: break;
313: case 'd':
314: case 'D':
315: secs *= DAYS;
316: break;
317: case 'w':
318: case 'W':
319: secs *= WEEKS;
320: break;
321: default:
322: return -1;
323: }
324: total += secs;
325: if (total < 0)
326: return -1;
327: p = endp;
328: }
329:
330: return total;
1.56 dtucker 331: }
332:
333: /*
334: * Returns a standardized host+port identifier string.
335: * Caller must free returned string.
336: */
337: char *
338: put_host_port(const char *host, u_short port)
339: {
340: char *hoststr;
341:
342: if (port == 0 || port == SSH_DEFAULT_PORT)
343: return(xstrdup(host));
344: if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0)
345: fatal("put_host_port: asprintf: %s", strerror(errno));
346: debug3("put_host_port: %s", hoststr);
347: return hoststr;
1.28 djm 348: }
349:
350: /*
351: * Search for next delimiter between hostnames/addresses and ports.
352: * Argument may be modified (for termination).
353: * Returns *cp if parsing succeeds.
354: * *cp is set to the start of the next delimiter, if one was found.
355: * If this is the last field, *cp is set to NULL.
356: */
357: char *
358: hpdelim(char **cp)
359: {
360: char *s, *old;
361:
362: if (cp == NULL || *cp == NULL)
363: return NULL;
364:
365: old = s = *cp;
366: if (*s == '[') {
367: if ((s = strchr(s, ']')) == NULL)
368: return NULL;
369: else
370: s++;
371: } else if ((s = strpbrk(s, ":/")) == NULL)
372: s = *cp + strlen(*cp); /* skip to end (see first case below) */
373:
374: switch (*s) {
375: case '\0':
376: *cp = NULL; /* no more fields*/
377: break;
1.29 deraadt 378:
1.28 djm 379: case ':':
380: case '/':
381: *s = '\0'; /* terminate */
382: *cp = s + 1;
383: break;
1.29 deraadt 384:
1.28 djm 385: default:
386: return NULL;
387: }
388:
389: return old;
1.6 mouring 390: }
391:
392: char *
393: cleanhostname(char *host)
394: {
395: if (*host == '[' && host[strlen(host) - 1] == ']') {
396: host[strlen(host) - 1] = '\0';
397: return (host + 1);
398: } else
399: return host;
400: }
401:
402: char *
403: colon(char *cp)
404: {
405: int flag = 0;
406:
407: if (*cp == ':') /* Leading colon is part of file name. */
408: return (0);
409: if (*cp == '[')
410: flag = 1;
411:
412: for (; *cp; ++cp) {
413: if (*cp == '@' && *(cp+1) == '[')
414: flag = 1;
415: if (*cp == ']' && *(cp+1) == ':' && flag)
416: return (cp+1);
417: if (*cp == ':' && !flag)
418: return (cp);
419: if (*cp == '/')
420: return (0);
421: }
422: return (0);
1.7 mouring 423: }
424:
1.12 markus 425: /* function to assist building execv() arguments */
1.7 mouring 426: void
427: addargs(arglist *args, char *fmt, ...)
428: {
429: va_list ap;
1.42 djm 430: char *cp;
1.25 avsm 431: u_int nalloc;
1.42 djm 432: int r;
1.7 mouring 433:
434: va_start(ap, fmt);
1.42 djm 435: r = vasprintf(&cp, fmt, ap);
1.7 mouring 436: va_end(ap);
1.42 djm 437: if (r == -1)
438: fatal("addargs: argument too long");
1.7 mouring 439:
1.22 markus 440: nalloc = args->nalloc;
1.7 mouring 441: if (args->list == NULL) {
1.22 markus 442: nalloc = 32;
1.7 mouring 443: args->num = 0;
1.22 markus 444: } else if (args->num+2 >= nalloc)
445: nalloc *= 2;
1.7 mouring 446:
1.50 djm 447: args->list = xrealloc(args->list, nalloc, sizeof(char *));
1.22 markus 448: args->nalloc = nalloc;
1.42 djm 449: args->list[args->num++] = cp;
1.7 mouring 450: args->list[args->num] = NULL;
1.42 djm 451: }
452:
453: void
454: replacearg(arglist *args, u_int which, char *fmt, ...)
455: {
456: va_list ap;
457: char *cp;
458: int r;
459:
460: va_start(ap, fmt);
461: r = vasprintf(&cp, fmt, ap);
462: va_end(ap);
463: if (r == -1)
464: fatal("replacearg: argument too long");
465:
466: if (which >= args->num)
467: fatal("replacearg: tried to replace invalid arg %d >= %d",
468: which, args->num);
469: xfree(args->list[which]);
470: args->list[which] = cp;
471: }
472:
473: void
474: freeargs(arglist *args)
475: {
476: u_int i;
477:
478: if (args->list != NULL) {
479: for (i = 0; i < args->num; i++)
480: xfree(args->list[i]);
481: xfree(args->list);
482: args->nalloc = args->num = 0;
483: args->list = NULL;
484: }
1.30 djm 485: }
486:
487: /*
488: * Expands tildes in the file name. Returns data allocated by xmalloc.
489: * Warning: this calls getpw*.
490: */
491: char *
492: tilde_expand_filename(const char *filename, uid_t uid)
493: {
494: const char *path;
495: char user[128], ret[MAXPATHLEN];
496: struct passwd *pw;
1.32 djm 497: u_int len, slash;
1.30 djm 498:
499: if (*filename != '~')
500: return (xstrdup(filename));
501: filename++;
502:
503: path = strchr(filename, '/');
504: if (path != NULL && path > filename) { /* ~user/path */
1.32 djm 505: slash = path - filename;
506: if (slash > sizeof(user) - 1)
1.30 djm 507: fatal("tilde_expand_filename: ~username too long");
1.32 djm 508: memcpy(user, filename, slash);
509: user[slash] = '\0';
1.30 djm 510: if ((pw = getpwnam(user)) == NULL)
511: fatal("tilde_expand_filename: No such user %s", user);
512: } else if ((pw = getpwuid(uid)) == NULL) /* ~/path */
513: fatal("tilde_expand_filename: No such uid %d", uid);
514:
515: if (strlcpy(ret, pw->pw_dir, sizeof(ret)) >= sizeof(ret))
516: fatal("tilde_expand_filename: Path too long");
517:
518: /* Make sure directory has a trailing '/' */
519: len = strlen(pw->pw_dir);
520: if ((len == 0 || pw->pw_dir[len - 1] != '/') &&
521: strlcat(ret, "/", sizeof(ret)) >= sizeof(ret))
522: fatal("tilde_expand_filename: Path too long");
523:
524: /* Skip leading '/' from specified path */
525: if (path != NULL)
526: filename = path + 1;
527: if (strlcat(ret, filename, sizeof(ret)) >= sizeof(ret))
528: fatal("tilde_expand_filename: Path too long");
529:
530: return (xstrdup(ret));
1.31 djm 531: }
532:
533: /*
534: * Expand a string with a set of %[char] escapes. A number of escapes may be
535: * specified as (char *escape_chars, char *replacement) pairs. The list must
1.34 dtucker 536: * be terminated by a NULL escape_char. Returns replaced string in memory
1.31 djm 537: * allocated by xmalloc.
538: */
539: char *
540: percent_expand(const char *string, ...)
541: {
542: #define EXPAND_MAX_KEYS 16
543: struct {
544: const char *key;
545: const char *repl;
546: } keys[EXPAND_MAX_KEYS];
1.32 djm 547: u_int num_keys, i, j;
1.31 djm 548: char buf[4096];
549: va_list ap;
550:
551: /* Gather keys */
552: va_start(ap, string);
553: for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
554: keys[num_keys].key = va_arg(ap, char *);
555: if (keys[num_keys].key == NULL)
556: break;
557: keys[num_keys].repl = va_arg(ap, char *);
558: if (keys[num_keys].repl == NULL)
559: fatal("percent_expand: NULL replacement");
560: }
561: va_end(ap);
562:
563: if (num_keys >= EXPAND_MAX_KEYS)
564: fatal("percent_expand: too many keys");
565:
566: /* Expand string */
567: *buf = '\0';
568: for (i = 0; *string != '\0'; string++) {
569: if (*string != '%') {
570: append:
571: buf[i++] = *string;
572: if (i >= sizeof(buf))
573: fatal("percent_expand: string too long");
574: buf[i] = '\0';
575: continue;
576: }
577: string++;
578: if (*string == '%')
579: goto append;
580: for (j = 0; j < num_keys; j++) {
581: if (strchr(keys[j].key, *string) != NULL) {
582: i = strlcat(buf, keys[j].repl, sizeof(buf));
583: if (i >= sizeof(buf))
584: fatal("percent_expand: string too long");
585: break;
586: }
587: }
588: if (j >= num_keys)
589: fatal("percent_expand: unknown key %%%c", *string);
590: }
591: return (xstrdup(buf));
592: #undef EXPAND_MAX_KEYS
1.26 dtucker 593: }
594:
595: /*
596: * Read an entire line from a public key file into a static buffer, discarding
597: * lines that exceed the buffer size. Returns 0 on success, -1 on failure.
598: */
599: int
600: read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
1.27 dtucker 601: u_long *lineno)
1.26 dtucker 602: {
603: while (fgets(buf, bufsz, f) != NULL) {
604: (*lineno)++;
605: if (buf[strlen(buf) - 1] == '\n' || feof(f)) {
606: return 0;
607: } else {
1.27 dtucker 608: debug("%s: %s line %lu exceeds size limit", __func__,
609: filename, *lineno);
1.26 dtucker 610: /* discard remainder of line */
1.29 deraadt 611: while (fgetc(f) != '\n' && !feof(f))
1.26 dtucker 612: ; /* nothing */
613: }
614: }
615: return -1;
1.36 reyk 616: }
617:
618: int
1.37 reyk 619: tun_open(int tun, int mode)
1.36 reyk 620: {
1.37 reyk 621: struct ifreq ifr;
1.36 reyk 622: char name[100];
1.37 reyk 623: int fd = -1, sock;
1.36 reyk 624:
1.37 reyk 625: /* Open the tunnel device */
626: if (tun <= SSH_TUNID_MAX) {
1.36 reyk 627: snprintf(name, sizeof(name), "/dev/tun%d", tun);
1.37 reyk 628: fd = open(name, O_RDWR);
629: } else if (tun == SSH_TUNID_ANY) {
630: for (tun = 100; tun >= 0; tun--) {
631: snprintf(name, sizeof(name), "/dev/tun%d", tun);
632: if ((fd = open(name, O_RDWR)) >= 0)
633: break;
1.36 reyk 634: }
635: } else {
1.39 stevesk 636: debug("%s: invalid tunnel %u", __func__, tun);
1.37 reyk 637: return (-1);
638: }
639:
640: if (fd < 0) {
641: debug("%s: %s open failed: %s", __func__, name, strerror(errno));
642: return (-1);
1.36 reyk 643: }
1.37 reyk 644:
645: debug("%s: %s mode %d fd %d", __func__, name, mode, fd);
646:
647: /* Set the tunnel device operation mode */
648: snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tun%d", tun);
649: if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
650: goto failed;
651:
652: if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
653: goto failed;
1.40 reyk 654:
655: /* Set interface mode */
656: ifr.ifr_flags &= ~IFF_UP;
657: if (mode == SSH_TUNMODE_ETHERNET)
1.37 reyk 658: ifr.ifr_flags |= IFF_LINK0;
1.40 reyk 659: else
660: ifr.ifr_flags &= ~IFF_LINK0;
661: if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
662: goto failed;
663:
664: /* Bring interface up */
1.37 reyk 665: ifr.ifr_flags |= IFF_UP;
666: if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
667: goto failed;
668:
669: close(sock);
670: return (fd);
671:
672: failed:
673: if (fd >= 0)
674: close(fd);
675: if (sock >= 0)
676: close(sock);
677: debug("%s: failed to set %s mode %d: %s", __func__, name,
678: mode, strerror(errno));
1.36 reyk 679: return (-1);
1.35 djm 680: }
681:
682: void
683: sanitise_stdfd(void)
684: {
1.41 djm 685: int nullfd, dupfd;
1.35 djm 686:
1.41 djm 687: if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
1.35 djm 688: fprintf(stderr, "Couldn't open /dev/null: %s", strerror(errno));
689: exit(1);
690: }
1.41 djm 691: while (++dupfd <= 2) {
692: /* Only clobber closed fds */
693: if (fcntl(dupfd, F_GETFL, 0) >= 0)
694: continue;
695: if (dup2(nullfd, dupfd) == -1) {
1.35 djm 696: fprintf(stderr, "dup2: %s", strerror(errno));
697: exit(1);
698: }
699: }
700: if (nullfd > 2)
701: close(nullfd);
1.1 markus 702: }
1.33 djm 703:
704: char *
1.52 djm 705: tohex(const void *vp, size_t l)
1.33 djm 706: {
1.52 djm 707: const u_char *p = (const u_char *)vp;
1.33 djm 708: char b[3], *r;
1.52 djm 709: size_t i, hl;
710:
711: if (l > 65536)
712: return xstrdup("tohex: length > 65536");
1.33 djm 713:
714: hl = l * 2 + 1;
1.49 djm 715: r = xcalloc(1, hl);
1.33 djm 716: for (i = 0; i < l; i++) {
1.52 djm 717: snprintf(b, sizeof(b), "%02x", p[i]);
1.33 djm 718: strlcat(r, b, hl);
719: }
720: return (r);
721: }
722:
1.52 djm 723: u_int64_t
724: get_u64(const void *vp)
725: {
726: const u_char *p = (const u_char *)vp;
727: u_int64_t v;
728:
729: v = (u_int64_t)p[0] << 56;
730: v |= (u_int64_t)p[1] << 48;
731: v |= (u_int64_t)p[2] << 40;
732: v |= (u_int64_t)p[3] << 32;
733: v |= (u_int64_t)p[4] << 24;
734: v |= (u_int64_t)p[5] << 16;
735: v |= (u_int64_t)p[6] << 8;
736: v |= (u_int64_t)p[7];
737:
738: return (v);
739: }
740:
741: u_int32_t
742: get_u32(const void *vp)
743: {
744: const u_char *p = (const u_char *)vp;
745: u_int32_t v;
746:
747: v = (u_int32_t)p[0] << 24;
748: v |= (u_int32_t)p[1] << 16;
749: v |= (u_int32_t)p[2] << 8;
750: v |= (u_int32_t)p[3];
751:
752: return (v);
753: }
754:
755: u_int16_t
756: get_u16(const void *vp)
757: {
758: const u_char *p = (const u_char *)vp;
759: u_int16_t v;
760:
761: v = (u_int16_t)p[0] << 8;
762: v |= (u_int16_t)p[1];
763:
764: return (v);
765: }
766:
767: void
768: put_u64(void *vp, u_int64_t v)
769: {
770: u_char *p = (u_char *)vp;
771:
772: p[0] = (u_char)(v >> 56) & 0xff;
773: p[1] = (u_char)(v >> 48) & 0xff;
774: p[2] = (u_char)(v >> 40) & 0xff;
775: p[3] = (u_char)(v >> 32) & 0xff;
776: p[4] = (u_char)(v >> 24) & 0xff;
777: p[5] = (u_char)(v >> 16) & 0xff;
778: p[6] = (u_char)(v >> 8) & 0xff;
779: p[7] = (u_char)v & 0xff;
780: }
781:
782: void
783: put_u32(void *vp, u_int32_t v)
784: {
785: u_char *p = (u_char *)vp;
786:
787: p[0] = (u_char)(v >> 24) & 0xff;
788: p[1] = (u_char)(v >> 16) & 0xff;
789: p[2] = (u_char)(v >> 8) & 0xff;
790: p[3] = (u_char)v & 0xff;
791: }
792:
793:
794: void
795: put_u16(void *vp, u_int16_t v)
796: {
797: u_char *p = (u_char *)vp;
798:
799: p[0] = (u_char)(v >> 8) & 0xff;
800: p[1] = (u_char)v & 0xff;
801: }