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