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