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