xref: /dflybsd-src/crypto/openssh/misc.c (revision ce74baca94b6dd2a80af6a625aba2cf14ab7fec8)
1*ce74bacaSMatthew Dillon /* $OpenBSD: misc.c,v 1.113 2017/08/18 05:48:04 djm Exp $ */
218de8d7fSPeter Avalos /*
318de8d7fSPeter Avalos  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
418de8d7fSPeter Avalos  * Copyright (c) 2005,2006 Damien Miller.  All rights reserved.
518de8d7fSPeter Avalos  *
618de8d7fSPeter Avalos  * Redistribution and use in source and binary forms, with or without
718de8d7fSPeter Avalos  * modification, are permitted provided that the following conditions
818de8d7fSPeter Avalos  * are met:
918de8d7fSPeter Avalos  * 1. Redistributions of source code must retain the above copyright
1018de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer.
1118de8d7fSPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
1218de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
1318de8d7fSPeter Avalos  *    documentation and/or other materials provided with the distribution.
1418de8d7fSPeter Avalos  *
1518de8d7fSPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1618de8d7fSPeter Avalos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1718de8d7fSPeter Avalos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1818de8d7fSPeter Avalos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1918de8d7fSPeter Avalos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2018de8d7fSPeter Avalos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2118de8d7fSPeter Avalos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2218de8d7fSPeter Avalos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2318de8d7fSPeter Avalos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2418de8d7fSPeter Avalos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2518de8d7fSPeter Avalos  */
2618de8d7fSPeter Avalos 
2718de8d7fSPeter Avalos #include "includes.h"
2818de8d7fSPeter Avalos 
2918de8d7fSPeter Avalos #include <sys/types.h>
3018de8d7fSPeter Avalos #include <sys/ioctl.h>
3118de8d7fSPeter Avalos #include <sys/socket.h>
32*ce74bacaSMatthew Dillon #include <sys/stat.h>
33e9778795SPeter Avalos #include <sys/time.h>
34*ce74bacaSMatthew Dillon #include <sys/wait.h>
3536e94dc5SPeter Avalos #include <sys/un.h>
3618de8d7fSPeter Avalos 
37e9778795SPeter Avalos #include <limits.h>
38*ce74bacaSMatthew Dillon #ifdef HAVE_LIBGEN_H
39*ce74bacaSMatthew Dillon # include <libgen.h>
40*ce74bacaSMatthew Dillon #endif
41*ce74bacaSMatthew Dillon #include <signal.h>
4218de8d7fSPeter Avalos #include <stdarg.h>
4318de8d7fSPeter Avalos #include <stdio.h>
4418de8d7fSPeter Avalos #include <stdlib.h>
4518de8d7fSPeter Avalos #include <string.h>
469f304aafSPeter Avalos #include <time.h>
4718de8d7fSPeter Avalos #include <unistd.h>
4818de8d7fSPeter Avalos 
4918de8d7fSPeter Avalos #include <netinet/in.h>
509f304aafSPeter Avalos #include <netinet/in_systm.h>
519f304aafSPeter Avalos #include <netinet/ip.h>
5218de8d7fSPeter Avalos #include <netinet/tcp.h>
5318de8d7fSPeter Avalos 
5436e94dc5SPeter Avalos #include <ctype.h>
5518de8d7fSPeter Avalos #include <errno.h>
5618de8d7fSPeter Avalos #include <fcntl.h>
5718de8d7fSPeter Avalos #include <netdb.h>
5818de8d7fSPeter Avalos #ifdef HAVE_PATHS_H
5918de8d7fSPeter Avalos # include <paths.h>
6018de8d7fSPeter Avalos #include <pwd.h>
6118de8d7fSPeter Avalos #endif
6218de8d7fSPeter Avalos #ifdef SSH_TUN_OPENBSD
6318de8d7fSPeter Avalos #include <net/if.h>
6418de8d7fSPeter Avalos #endif
6518de8d7fSPeter Avalos 
6618de8d7fSPeter Avalos #include "xmalloc.h"
6718de8d7fSPeter Avalos #include "misc.h"
6818de8d7fSPeter Avalos #include "log.h"
6918de8d7fSPeter Avalos #include "ssh.h"
70*ce74bacaSMatthew Dillon #include "sshbuf.h"
71*ce74bacaSMatthew Dillon #include "ssherr.h"
72*ce74bacaSMatthew Dillon #include "uidswap.h"
73*ce74bacaSMatthew Dillon #include "platform.h"
7418de8d7fSPeter Avalos 
7518de8d7fSPeter Avalos /* remove newline at end of string */
7618de8d7fSPeter Avalos char *
7718de8d7fSPeter Avalos chop(char *s)
7818de8d7fSPeter Avalos {
7918de8d7fSPeter Avalos 	char *t = s;
8018de8d7fSPeter Avalos 	while (*t) {
8118de8d7fSPeter Avalos 		if (*t == '\n' || *t == '\r') {
8218de8d7fSPeter Avalos 			*t = '\0';
8318de8d7fSPeter Avalos 			return s;
8418de8d7fSPeter Avalos 		}
8518de8d7fSPeter Avalos 		t++;
8618de8d7fSPeter Avalos 	}
8718de8d7fSPeter Avalos 	return s;
8818de8d7fSPeter Avalos 
8918de8d7fSPeter Avalos }
9018de8d7fSPeter Avalos 
9118de8d7fSPeter Avalos /* set/unset filedescriptor to non-blocking */
9218de8d7fSPeter Avalos int
9318de8d7fSPeter Avalos set_nonblock(int fd)
9418de8d7fSPeter Avalos {
9518de8d7fSPeter Avalos 	int val;
9618de8d7fSPeter Avalos 
97e9778795SPeter Avalos 	val = fcntl(fd, F_GETFL);
9818de8d7fSPeter Avalos 	if (val < 0) {
99e9778795SPeter Avalos 		error("fcntl(%d, F_GETFL): %s", fd, strerror(errno));
10018de8d7fSPeter Avalos 		return (-1);
10118de8d7fSPeter Avalos 	}
10218de8d7fSPeter Avalos 	if (val & O_NONBLOCK) {
10318de8d7fSPeter Avalos 		debug3("fd %d is O_NONBLOCK", fd);
10418de8d7fSPeter Avalos 		return (0);
10518de8d7fSPeter Avalos 	}
10618de8d7fSPeter Avalos 	debug2("fd %d setting O_NONBLOCK", fd);
10718de8d7fSPeter Avalos 	val |= O_NONBLOCK;
10818de8d7fSPeter Avalos 	if (fcntl(fd, F_SETFL, val) == -1) {
10918de8d7fSPeter Avalos 		debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd,
11018de8d7fSPeter Avalos 		    strerror(errno));
11118de8d7fSPeter Avalos 		return (-1);
11218de8d7fSPeter Avalos 	}
11318de8d7fSPeter Avalos 	return (0);
11418de8d7fSPeter Avalos }
11518de8d7fSPeter Avalos 
11618de8d7fSPeter Avalos int
11718de8d7fSPeter Avalos unset_nonblock(int fd)
11818de8d7fSPeter Avalos {
11918de8d7fSPeter Avalos 	int val;
12018de8d7fSPeter Avalos 
121e9778795SPeter Avalos 	val = fcntl(fd, F_GETFL);
12218de8d7fSPeter Avalos 	if (val < 0) {
123e9778795SPeter Avalos 		error("fcntl(%d, F_GETFL): %s", fd, strerror(errno));
12418de8d7fSPeter Avalos 		return (-1);
12518de8d7fSPeter Avalos 	}
12618de8d7fSPeter Avalos 	if (!(val & O_NONBLOCK)) {
12718de8d7fSPeter Avalos 		debug3("fd %d is not O_NONBLOCK", fd);
12818de8d7fSPeter Avalos 		return (0);
12918de8d7fSPeter Avalos 	}
13018de8d7fSPeter Avalos 	debug("fd %d clearing O_NONBLOCK", fd);
13118de8d7fSPeter Avalos 	val &= ~O_NONBLOCK;
13218de8d7fSPeter Avalos 	if (fcntl(fd, F_SETFL, val) == -1) {
13318de8d7fSPeter Avalos 		debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s",
13418de8d7fSPeter Avalos 		    fd, strerror(errno));
13518de8d7fSPeter Avalos 		return (-1);
13618de8d7fSPeter Avalos 	}
13718de8d7fSPeter Avalos 	return (0);
13818de8d7fSPeter Avalos }
13918de8d7fSPeter Avalos 
14018de8d7fSPeter Avalos const char *
14118de8d7fSPeter Avalos ssh_gai_strerror(int gaierr)
14218de8d7fSPeter Avalos {
14336e94dc5SPeter Avalos 	if (gaierr == EAI_SYSTEM && errno != 0)
14418de8d7fSPeter Avalos 		return strerror(errno);
14518de8d7fSPeter Avalos 	return gai_strerror(gaierr);
14618de8d7fSPeter Avalos }
14718de8d7fSPeter Avalos 
14818de8d7fSPeter Avalos /* disable nagle on socket */
14918de8d7fSPeter Avalos void
15018de8d7fSPeter Avalos set_nodelay(int fd)
15118de8d7fSPeter Avalos {
15218de8d7fSPeter Avalos 	int opt;
15318de8d7fSPeter Avalos 	socklen_t optlen;
15418de8d7fSPeter Avalos 
15518de8d7fSPeter Avalos 	optlen = sizeof opt;
15618de8d7fSPeter Avalos 	if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
15718de8d7fSPeter Avalos 		debug("getsockopt TCP_NODELAY: %.100s", strerror(errno));
15818de8d7fSPeter Avalos 		return;
15918de8d7fSPeter Avalos 	}
16018de8d7fSPeter Avalos 	if (opt == 1) {
16118de8d7fSPeter Avalos 		debug2("fd %d is TCP_NODELAY", fd);
16218de8d7fSPeter Avalos 		return;
16318de8d7fSPeter Avalos 	}
16418de8d7fSPeter Avalos 	opt = 1;
16518de8d7fSPeter Avalos 	debug2("fd %d setting TCP_NODELAY", fd);
16618de8d7fSPeter Avalos 	if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
16718de8d7fSPeter Avalos 		error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
16818de8d7fSPeter Avalos }
16918de8d7fSPeter Avalos 
17018de8d7fSPeter Avalos /* Characters considered whitespace in strsep calls. */
17118de8d7fSPeter Avalos #define WHITESPACE " \t\r\n"
17218de8d7fSPeter Avalos #define QUOTE	"\""
17318de8d7fSPeter Avalos 
17418de8d7fSPeter Avalos /* return next token in configuration line */
17518de8d7fSPeter Avalos char *
17618de8d7fSPeter Avalos strdelim(char **s)
17718de8d7fSPeter Avalos {
17818de8d7fSPeter Avalos 	char *old;
17918de8d7fSPeter Avalos 	int wspace = 0;
18018de8d7fSPeter Avalos 
18118de8d7fSPeter Avalos 	if (*s == NULL)
18218de8d7fSPeter Avalos 		return NULL;
18318de8d7fSPeter Avalos 
18418de8d7fSPeter Avalos 	old = *s;
18518de8d7fSPeter Avalos 
18618de8d7fSPeter Avalos 	*s = strpbrk(*s, WHITESPACE QUOTE "=");
18718de8d7fSPeter Avalos 	if (*s == NULL)
18818de8d7fSPeter Avalos 		return (old);
18918de8d7fSPeter Avalos 
19018de8d7fSPeter Avalos 	if (*s[0] == '\"') {
19118de8d7fSPeter Avalos 		memmove(*s, *s + 1, strlen(*s)); /* move nul too */
19218de8d7fSPeter Avalos 		/* Find matching quote */
19318de8d7fSPeter Avalos 		if ((*s = strpbrk(*s, QUOTE)) == NULL) {
19418de8d7fSPeter Avalos 			return (NULL);		/* no matching quote */
19518de8d7fSPeter Avalos 		} else {
19618de8d7fSPeter Avalos 			*s[0] = '\0';
197856ea928SPeter Avalos 			*s += strspn(*s + 1, WHITESPACE) + 1;
19818de8d7fSPeter Avalos 			return (old);
19918de8d7fSPeter Avalos 		}
20018de8d7fSPeter Avalos 	}
20118de8d7fSPeter Avalos 
20218de8d7fSPeter Avalos 	/* Allow only one '=' to be skipped */
20318de8d7fSPeter Avalos 	if (*s[0] == '=')
20418de8d7fSPeter Avalos 		wspace = 1;
20518de8d7fSPeter Avalos 	*s[0] = '\0';
20618de8d7fSPeter Avalos 
20718de8d7fSPeter Avalos 	/* Skip any extra whitespace after first token */
20818de8d7fSPeter Avalos 	*s += strspn(*s + 1, WHITESPACE) + 1;
20918de8d7fSPeter Avalos 	if (*s[0] == '=' && !wspace)
21018de8d7fSPeter Avalos 		*s += strspn(*s + 1, WHITESPACE) + 1;
21118de8d7fSPeter Avalos 
21218de8d7fSPeter Avalos 	return (old);
21318de8d7fSPeter Avalos }
21418de8d7fSPeter Avalos 
21518de8d7fSPeter Avalos struct passwd *
21618de8d7fSPeter Avalos pwcopy(struct passwd *pw)
21718de8d7fSPeter Avalos {
21818de8d7fSPeter Avalos 	struct passwd *copy = xcalloc(1, sizeof(*copy));
21918de8d7fSPeter Avalos 
22018de8d7fSPeter Avalos 	copy->pw_name = xstrdup(pw->pw_name);
22118de8d7fSPeter Avalos 	copy->pw_passwd = xstrdup(pw->pw_passwd);
22236e94dc5SPeter Avalos #ifdef HAVE_STRUCT_PASSWD_PW_GECOS
22318de8d7fSPeter Avalos 	copy->pw_gecos = xstrdup(pw->pw_gecos);
22436e94dc5SPeter Avalos #endif
22518de8d7fSPeter Avalos 	copy->pw_uid = pw->pw_uid;
22618de8d7fSPeter Avalos 	copy->pw_gid = pw->pw_gid;
22736e94dc5SPeter Avalos #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
22818de8d7fSPeter Avalos 	copy->pw_expire = pw->pw_expire;
22918de8d7fSPeter Avalos #endif
23036e94dc5SPeter Avalos #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
23118de8d7fSPeter Avalos 	copy->pw_change = pw->pw_change;
23218de8d7fSPeter Avalos #endif
23336e94dc5SPeter Avalos #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
23418de8d7fSPeter Avalos 	copy->pw_class = xstrdup(pw->pw_class);
23518de8d7fSPeter Avalos #endif
23618de8d7fSPeter Avalos 	copy->pw_dir = xstrdup(pw->pw_dir);
23718de8d7fSPeter Avalos 	copy->pw_shell = xstrdup(pw->pw_shell);
23818de8d7fSPeter Avalos 	return copy;
23918de8d7fSPeter Avalos }
24018de8d7fSPeter Avalos 
24118de8d7fSPeter Avalos /*
24218de8d7fSPeter Avalos  * Convert ASCII string to TCP/IP port number.
243cb5eb4f1SPeter Avalos  * Port must be >=0 and <=65535.
244cb5eb4f1SPeter Avalos  * Return -1 if invalid.
24518de8d7fSPeter Avalos  */
24618de8d7fSPeter Avalos int
24718de8d7fSPeter Avalos a2port(const char *s)
24818de8d7fSPeter Avalos {
249cb5eb4f1SPeter Avalos 	long long port;
250cb5eb4f1SPeter Avalos 	const char *errstr;
25118de8d7fSPeter Avalos 
252cb5eb4f1SPeter Avalos 	port = strtonum(s, 0, 65535, &errstr);
253cb5eb4f1SPeter Avalos 	if (errstr != NULL)
254cb5eb4f1SPeter Avalos 		return -1;
255cb5eb4f1SPeter Avalos 	return (int)port;
25618de8d7fSPeter Avalos }
25718de8d7fSPeter Avalos 
25818de8d7fSPeter Avalos int
25918de8d7fSPeter Avalos a2tun(const char *s, int *remote)
26018de8d7fSPeter Avalos {
26118de8d7fSPeter Avalos 	const char *errstr = NULL;
26218de8d7fSPeter Avalos 	char *sp, *ep;
26318de8d7fSPeter Avalos 	int tun;
26418de8d7fSPeter Avalos 
26518de8d7fSPeter Avalos 	if (remote != NULL) {
26618de8d7fSPeter Avalos 		*remote = SSH_TUNID_ANY;
26718de8d7fSPeter Avalos 		sp = xstrdup(s);
26818de8d7fSPeter Avalos 		if ((ep = strchr(sp, ':')) == NULL) {
26936e94dc5SPeter Avalos 			free(sp);
27018de8d7fSPeter Avalos 			return (a2tun(s, NULL));
27118de8d7fSPeter Avalos 		}
27218de8d7fSPeter Avalos 		ep[0] = '\0'; ep++;
27318de8d7fSPeter Avalos 		*remote = a2tun(ep, NULL);
27418de8d7fSPeter Avalos 		tun = a2tun(sp, NULL);
27536e94dc5SPeter Avalos 		free(sp);
27618de8d7fSPeter Avalos 		return (*remote == SSH_TUNID_ERR ? *remote : tun);
27718de8d7fSPeter Avalos 	}
27818de8d7fSPeter Avalos 
27918de8d7fSPeter Avalos 	if (strcasecmp(s, "any") == 0)
28018de8d7fSPeter Avalos 		return (SSH_TUNID_ANY);
28118de8d7fSPeter Avalos 
28218de8d7fSPeter Avalos 	tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr);
28318de8d7fSPeter Avalos 	if (errstr != NULL)
28418de8d7fSPeter Avalos 		return (SSH_TUNID_ERR);
28518de8d7fSPeter Avalos 
28618de8d7fSPeter Avalos 	return (tun);
28718de8d7fSPeter Avalos }
28818de8d7fSPeter Avalos 
28918de8d7fSPeter Avalos #define SECONDS		1
29018de8d7fSPeter Avalos #define MINUTES		(SECONDS * 60)
29118de8d7fSPeter Avalos #define HOURS		(MINUTES * 60)
29218de8d7fSPeter Avalos #define DAYS		(HOURS * 24)
29318de8d7fSPeter Avalos #define WEEKS		(DAYS * 7)
29418de8d7fSPeter Avalos 
29518de8d7fSPeter Avalos /*
29618de8d7fSPeter Avalos  * Convert a time string into seconds; format is
29718de8d7fSPeter Avalos  * a sequence of:
29818de8d7fSPeter Avalos  *      time[qualifier]
29918de8d7fSPeter Avalos  *
30018de8d7fSPeter Avalos  * Valid time qualifiers are:
30118de8d7fSPeter Avalos  *      <none>  seconds
30218de8d7fSPeter Avalos  *      s|S     seconds
30318de8d7fSPeter Avalos  *      m|M     minutes
30418de8d7fSPeter Avalos  *      h|H     hours
30518de8d7fSPeter Avalos  *      d|D     days
30618de8d7fSPeter Avalos  *      w|W     weeks
30718de8d7fSPeter Avalos  *
30818de8d7fSPeter Avalos  * Examples:
30918de8d7fSPeter Avalos  *      90m     90 minutes
31018de8d7fSPeter Avalos  *      1h30m   90 minutes
31118de8d7fSPeter Avalos  *      2d      2 days
31218de8d7fSPeter Avalos  *      1w      1 week
31318de8d7fSPeter Avalos  *
31418de8d7fSPeter Avalos  * Return -1 if time string is invalid.
31518de8d7fSPeter Avalos  */
31618de8d7fSPeter Avalos long
31718de8d7fSPeter Avalos convtime(const char *s)
31818de8d7fSPeter Avalos {
319*ce74bacaSMatthew Dillon 	long total, secs, multiplier = 1;
32018de8d7fSPeter Avalos 	const char *p;
32118de8d7fSPeter Avalos 	char *endp;
32218de8d7fSPeter Avalos 
32318de8d7fSPeter Avalos 	errno = 0;
32418de8d7fSPeter Avalos 	total = 0;
32518de8d7fSPeter Avalos 	p = s;
32618de8d7fSPeter Avalos 
32718de8d7fSPeter Avalos 	if (p == NULL || *p == '\0')
32818de8d7fSPeter Avalos 		return -1;
32918de8d7fSPeter Avalos 
33018de8d7fSPeter Avalos 	while (*p) {
33118de8d7fSPeter Avalos 		secs = strtol(p, &endp, 10);
33218de8d7fSPeter Avalos 		if (p == endp ||
33318de8d7fSPeter Avalos 		    (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
33418de8d7fSPeter Avalos 		    secs < 0)
33518de8d7fSPeter Avalos 			return -1;
33618de8d7fSPeter Avalos 
33718de8d7fSPeter Avalos 		switch (*endp++) {
33818de8d7fSPeter Avalos 		case '\0':
33918de8d7fSPeter Avalos 			endp--;
34018de8d7fSPeter Avalos 			break;
34118de8d7fSPeter Avalos 		case 's':
34218de8d7fSPeter Avalos 		case 'S':
34318de8d7fSPeter Avalos 			break;
34418de8d7fSPeter Avalos 		case 'm':
34518de8d7fSPeter Avalos 		case 'M':
346*ce74bacaSMatthew Dillon 			multiplier = MINUTES;
34718de8d7fSPeter Avalos 			break;
34818de8d7fSPeter Avalos 		case 'h':
34918de8d7fSPeter Avalos 		case 'H':
350*ce74bacaSMatthew Dillon 			multiplier = HOURS;
35118de8d7fSPeter Avalos 			break;
35218de8d7fSPeter Avalos 		case 'd':
35318de8d7fSPeter Avalos 		case 'D':
354*ce74bacaSMatthew Dillon 			multiplier = DAYS;
35518de8d7fSPeter Avalos 			break;
35618de8d7fSPeter Avalos 		case 'w':
35718de8d7fSPeter Avalos 		case 'W':
358*ce74bacaSMatthew Dillon 			multiplier = WEEKS;
35918de8d7fSPeter Avalos 			break;
36018de8d7fSPeter Avalos 		default:
36118de8d7fSPeter Avalos 			return -1;
36218de8d7fSPeter Avalos 		}
363*ce74bacaSMatthew Dillon 		if (secs >= LONG_MAX / multiplier)
364*ce74bacaSMatthew Dillon 			return -1;
365*ce74bacaSMatthew Dillon 		secs *= multiplier;
366*ce74bacaSMatthew Dillon 		if  (total >= LONG_MAX - secs)
367*ce74bacaSMatthew Dillon 			return -1;
36818de8d7fSPeter Avalos 		total += secs;
36918de8d7fSPeter Avalos 		if (total < 0)
37018de8d7fSPeter Avalos 			return -1;
37118de8d7fSPeter Avalos 		p = endp;
37218de8d7fSPeter Avalos 	}
37318de8d7fSPeter Avalos 
37418de8d7fSPeter Avalos 	return total;
37518de8d7fSPeter Avalos }
37618de8d7fSPeter Avalos 
37718de8d7fSPeter Avalos /*
37818de8d7fSPeter Avalos  * Returns a standardized host+port identifier string.
37918de8d7fSPeter Avalos  * Caller must free returned string.
38018de8d7fSPeter Avalos  */
38118de8d7fSPeter Avalos char *
38218de8d7fSPeter Avalos put_host_port(const char *host, u_short port)
38318de8d7fSPeter Avalos {
38418de8d7fSPeter Avalos 	char *hoststr;
38518de8d7fSPeter Avalos 
38618de8d7fSPeter Avalos 	if (port == 0 || port == SSH_DEFAULT_PORT)
38718de8d7fSPeter Avalos 		return(xstrdup(host));
38818de8d7fSPeter Avalos 	if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0)
38918de8d7fSPeter Avalos 		fatal("put_host_port: asprintf: %s", strerror(errno));
39018de8d7fSPeter Avalos 	debug3("put_host_port: %s", hoststr);
39118de8d7fSPeter Avalos 	return hoststr;
39218de8d7fSPeter Avalos }
39318de8d7fSPeter Avalos 
39418de8d7fSPeter Avalos /*
39518de8d7fSPeter Avalos  * Search for next delimiter between hostnames/addresses and ports.
39618de8d7fSPeter Avalos  * Argument may be modified (for termination).
39718de8d7fSPeter Avalos  * Returns *cp if parsing succeeds.
39818de8d7fSPeter Avalos  * *cp is set to the start of the next delimiter, if one was found.
39918de8d7fSPeter Avalos  * If this is the last field, *cp is set to NULL.
40018de8d7fSPeter Avalos  */
40118de8d7fSPeter Avalos char *
40218de8d7fSPeter Avalos hpdelim(char **cp)
40318de8d7fSPeter Avalos {
40418de8d7fSPeter Avalos 	char *s, *old;
40518de8d7fSPeter Avalos 
40618de8d7fSPeter Avalos 	if (cp == NULL || *cp == NULL)
40718de8d7fSPeter Avalos 		return NULL;
40818de8d7fSPeter Avalos 
40918de8d7fSPeter Avalos 	old = s = *cp;
41018de8d7fSPeter Avalos 	if (*s == '[') {
41118de8d7fSPeter Avalos 		if ((s = strchr(s, ']')) == NULL)
41218de8d7fSPeter Avalos 			return NULL;
41318de8d7fSPeter Avalos 		else
41418de8d7fSPeter Avalos 			s++;
41518de8d7fSPeter Avalos 	} else if ((s = strpbrk(s, ":/")) == NULL)
41618de8d7fSPeter Avalos 		s = *cp + strlen(*cp); /* skip to end (see first case below) */
41718de8d7fSPeter Avalos 
41818de8d7fSPeter Avalos 	switch (*s) {
41918de8d7fSPeter Avalos 	case '\0':
42018de8d7fSPeter Avalos 		*cp = NULL;	/* no more fields*/
42118de8d7fSPeter Avalos 		break;
42218de8d7fSPeter Avalos 
42318de8d7fSPeter Avalos 	case ':':
42418de8d7fSPeter Avalos 	case '/':
42518de8d7fSPeter Avalos 		*s = '\0';	/* terminate */
42618de8d7fSPeter Avalos 		*cp = s + 1;
42718de8d7fSPeter Avalos 		break;
42818de8d7fSPeter Avalos 
42918de8d7fSPeter Avalos 	default:
43018de8d7fSPeter Avalos 		return NULL;
43118de8d7fSPeter Avalos 	}
43218de8d7fSPeter Avalos 
43318de8d7fSPeter Avalos 	return old;
43418de8d7fSPeter Avalos }
43518de8d7fSPeter Avalos 
43618de8d7fSPeter Avalos char *
43718de8d7fSPeter Avalos cleanhostname(char *host)
43818de8d7fSPeter Avalos {
43918de8d7fSPeter Avalos 	if (*host == '[' && host[strlen(host) - 1] == ']') {
44018de8d7fSPeter Avalos 		host[strlen(host) - 1] = '\0';
44118de8d7fSPeter Avalos 		return (host + 1);
44218de8d7fSPeter Avalos 	} else
44318de8d7fSPeter Avalos 		return host;
44418de8d7fSPeter Avalos }
44518de8d7fSPeter Avalos 
44618de8d7fSPeter Avalos char *
44718de8d7fSPeter Avalos colon(char *cp)
44818de8d7fSPeter Avalos {
44918de8d7fSPeter Avalos 	int flag = 0;
45018de8d7fSPeter Avalos 
45118de8d7fSPeter Avalos 	if (*cp == ':')		/* Leading colon is part of file name. */
452856ea928SPeter Avalos 		return NULL;
45318de8d7fSPeter Avalos 	if (*cp == '[')
45418de8d7fSPeter Avalos 		flag = 1;
45518de8d7fSPeter Avalos 
45618de8d7fSPeter Avalos 	for (; *cp; ++cp) {
45718de8d7fSPeter Avalos 		if (*cp == '@' && *(cp+1) == '[')
45818de8d7fSPeter Avalos 			flag = 1;
45918de8d7fSPeter Avalos 		if (*cp == ']' && *(cp+1) == ':' && flag)
46018de8d7fSPeter Avalos 			return (cp+1);
46118de8d7fSPeter Avalos 		if (*cp == ':' && !flag)
46218de8d7fSPeter Avalos 			return (cp);
46318de8d7fSPeter Avalos 		if (*cp == '/')
464856ea928SPeter Avalos 			return NULL;
46518de8d7fSPeter Avalos 	}
466856ea928SPeter Avalos 	return NULL;
46718de8d7fSPeter Avalos }
46818de8d7fSPeter Avalos 
469e9778795SPeter Avalos /*
470e9778795SPeter Avalos  * Parse a [user@]host[:port] string.
471e9778795SPeter Avalos  * Caller must free returned user and host.
472e9778795SPeter Avalos  * Any of the pointer return arguments may be NULL (useful for syntax checking).
473e9778795SPeter Avalos  * If user was not specified then *userp will be set to NULL.
474e9778795SPeter Avalos  * If port was not specified then *portp will be -1.
475e9778795SPeter Avalos  * Returns 0 on success, -1 on failure.
476e9778795SPeter Avalos  */
477e9778795SPeter Avalos int
478e9778795SPeter Avalos parse_user_host_port(const char *s, char **userp, char **hostp, int *portp)
479e9778795SPeter Avalos {
480e9778795SPeter Avalos 	char *sdup, *cp, *tmp;
481e9778795SPeter Avalos 	char *user = NULL, *host = NULL;
482e9778795SPeter Avalos 	int port = -1, ret = -1;
483e9778795SPeter Avalos 
484e9778795SPeter Avalos 	if (userp != NULL)
485e9778795SPeter Avalos 		*userp = NULL;
486e9778795SPeter Avalos 	if (hostp != NULL)
487e9778795SPeter Avalos 		*hostp = NULL;
488e9778795SPeter Avalos 	if (portp != NULL)
489e9778795SPeter Avalos 		*portp = -1;
490e9778795SPeter Avalos 
491e9778795SPeter Avalos 	if ((sdup = tmp = strdup(s)) == NULL)
492e9778795SPeter Avalos 		return -1;
493e9778795SPeter Avalos 	/* Extract optional username */
494e9778795SPeter Avalos 	if ((cp = strchr(tmp, '@')) != NULL) {
495e9778795SPeter Avalos 		*cp = '\0';
496e9778795SPeter Avalos 		if (*tmp == '\0')
497e9778795SPeter Avalos 			goto out;
498e9778795SPeter Avalos 		if ((user = strdup(tmp)) == NULL)
499e9778795SPeter Avalos 			goto out;
500e9778795SPeter Avalos 		tmp = cp + 1;
501e9778795SPeter Avalos 	}
502e9778795SPeter Avalos 	/* Extract mandatory hostname */
503e9778795SPeter Avalos 	if ((cp = hpdelim(&tmp)) == NULL || *cp == '\0')
504e9778795SPeter Avalos 		goto out;
505e9778795SPeter Avalos 	host = xstrdup(cleanhostname(cp));
506e9778795SPeter Avalos 	/* Convert and verify optional port */
507e9778795SPeter Avalos 	if (tmp != NULL && *tmp != '\0') {
508e9778795SPeter Avalos 		if ((port = a2port(tmp)) <= 0)
509e9778795SPeter Avalos 			goto out;
510e9778795SPeter Avalos 	}
511e9778795SPeter Avalos 	/* Success */
512e9778795SPeter Avalos 	if (userp != NULL) {
513e9778795SPeter Avalos 		*userp = user;
514e9778795SPeter Avalos 		user = NULL;
515e9778795SPeter Avalos 	}
516e9778795SPeter Avalos 	if (hostp != NULL) {
517e9778795SPeter Avalos 		*hostp = host;
518e9778795SPeter Avalos 		host = NULL;
519e9778795SPeter Avalos 	}
520e9778795SPeter Avalos 	if (portp != NULL)
521e9778795SPeter Avalos 		*portp = port;
522e9778795SPeter Avalos 	ret = 0;
523e9778795SPeter Avalos  out:
524e9778795SPeter Avalos 	free(sdup);
525e9778795SPeter Avalos 	free(user);
526e9778795SPeter Avalos 	free(host);
527e9778795SPeter Avalos 	return ret;
528e9778795SPeter Avalos }
529e9778795SPeter Avalos 
53018de8d7fSPeter Avalos /* function to assist building execv() arguments */
53118de8d7fSPeter Avalos void
53218de8d7fSPeter Avalos addargs(arglist *args, char *fmt, ...)
53318de8d7fSPeter Avalos {
53418de8d7fSPeter Avalos 	va_list ap;
53518de8d7fSPeter Avalos 	char *cp;
53618de8d7fSPeter Avalos 	u_int nalloc;
53718de8d7fSPeter Avalos 	int r;
53818de8d7fSPeter Avalos 
53918de8d7fSPeter Avalos 	va_start(ap, fmt);
54018de8d7fSPeter Avalos 	r = vasprintf(&cp, fmt, ap);
54118de8d7fSPeter Avalos 	va_end(ap);
54218de8d7fSPeter Avalos 	if (r == -1)
54318de8d7fSPeter Avalos 		fatal("addargs: argument too long");
54418de8d7fSPeter Avalos 
54518de8d7fSPeter Avalos 	nalloc = args->nalloc;
54618de8d7fSPeter Avalos 	if (args->list == NULL) {
54718de8d7fSPeter Avalos 		nalloc = 32;
54818de8d7fSPeter Avalos 		args->num = 0;
54918de8d7fSPeter Avalos 	} else if (args->num+2 >= nalloc)
55018de8d7fSPeter Avalos 		nalloc *= 2;
55118de8d7fSPeter Avalos 
552*ce74bacaSMatthew Dillon 	args->list = xrecallocarray(args->list, args->nalloc, nalloc, sizeof(char *));
55318de8d7fSPeter Avalos 	args->nalloc = nalloc;
55418de8d7fSPeter Avalos 	args->list[args->num++] = cp;
55518de8d7fSPeter Avalos 	args->list[args->num] = NULL;
55618de8d7fSPeter Avalos }
55718de8d7fSPeter Avalos 
55818de8d7fSPeter Avalos void
55918de8d7fSPeter Avalos replacearg(arglist *args, u_int which, char *fmt, ...)
56018de8d7fSPeter Avalos {
56118de8d7fSPeter Avalos 	va_list ap;
56218de8d7fSPeter Avalos 	char *cp;
56318de8d7fSPeter Avalos 	int r;
56418de8d7fSPeter Avalos 
56518de8d7fSPeter Avalos 	va_start(ap, fmt);
56618de8d7fSPeter Avalos 	r = vasprintf(&cp, fmt, ap);
56718de8d7fSPeter Avalos 	va_end(ap);
56818de8d7fSPeter Avalos 	if (r == -1)
56918de8d7fSPeter Avalos 		fatal("replacearg: argument too long");
57018de8d7fSPeter Avalos 
57118de8d7fSPeter Avalos 	if (which >= args->num)
57218de8d7fSPeter Avalos 		fatal("replacearg: tried to replace invalid arg %d >= %d",
57318de8d7fSPeter Avalos 		    which, args->num);
57436e94dc5SPeter Avalos 	free(args->list[which]);
57518de8d7fSPeter Avalos 	args->list[which] = cp;
57618de8d7fSPeter Avalos }
57718de8d7fSPeter Avalos 
57818de8d7fSPeter Avalos void
57918de8d7fSPeter Avalos freeargs(arglist *args)
58018de8d7fSPeter Avalos {
58118de8d7fSPeter Avalos 	u_int i;
58218de8d7fSPeter Avalos 
58318de8d7fSPeter Avalos 	if (args->list != NULL) {
58418de8d7fSPeter Avalos 		for (i = 0; i < args->num; i++)
58536e94dc5SPeter Avalos 			free(args->list[i]);
58636e94dc5SPeter Avalos 		free(args->list);
58718de8d7fSPeter Avalos 		args->nalloc = args->num = 0;
58818de8d7fSPeter Avalos 		args->list = NULL;
58918de8d7fSPeter Avalos 	}
59018de8d7fSPeter Avalos }
59118de8d7fSPeter Avalos 
59218de8d7fSPeter Avalos /*
59318de8d7fSPeter Avalos  * Expands tildes in the file name.  Returns data allocated by xmalloc.
59418de8d7fSPeter Avalos  * Warning: this calls getpw*.
59518de8d7fSPeter Avalos  */
59618de8d7fSPeter Avalos char *
59718de8d7fSPeter Avalos tilde_expand_filename(const char *filename, uid_t uid)
59818de8d7fSPeter Avalos {
59936e94dc5SPeter Avalos 	const char *path, *sep;
60036e94dc5SPeter Avalos 	char user[128], *ret;
60118de8d7fSPeter Avalos 	struct passwd *pw;
60218de8d7fSPeter Avalos 	u_int len, slash;
60318de8d7fSPeter Avalos 
60418de8d7fSPeter Avalos 	if (*filename != '~')
60518de8d7fSPeter Avalos 		return (xstrdup(filename));
60618de8d7fSPeter Avalos 	filename++;
60718de8d7fSPeter Avalos 
60818de8d7fSPeter Avalos 	path = strchr(filename, '/');
60918de8d7fSPeter Avalos 	if (path != NULL && path > filename) {		/* ~user/path */
61018de8d7fSPeter Avalos 		slash = path - filename;
61118de8d7fSPeter Avalos 		if (slash > sizeof(user) - 1)
61218de8d7fSPeter Avalos 			fatal("tilde_expand_filename: ~username too long");
61318de8d7fSPeter Avalos 		memcpy(user, filename, slash);
61418de8d7fSPeter Avalos 		user[slash] = '\0';
61518de8d7fSPeter Avalos 		if ((pw = getpwnam(user)) == NULL)
61618de8d7fSPeter Avalos 			fatal("tilde_expand_filename: No such user %s", user);
61718de8d7fSPeter Avalos 	} else if ((pw = getpwuid(uid)) == NULL)	/* ~/path */
61818de8d7fSPeter Avalos 		fatal("tilde_expand_filename: No such uid %ld", (long)uid);
61918de8d7fSPeter Avalos 
62018de8d7fSPeter Avalos 	/* Make sure directory has a trailing '/' */
62118de8d7fSPeter Avalos 	len = strlen(pw->pw_dir);
62236e94dc5SPeter Avalos 	if (len == 0 || pw->pw_dir[len - 1] != '/')
62336e94dc5SPeter Avalos 		sep = "/";
62436e94dc5SPeter Avalos 	else
62536e94dc5SPeter Avalos 		sep = "";
62618de8d7fSPeter Avalos 
62718de8d7fSPeter Avalos 	/* Skip leading '/' from specified path */
62818de8d7fSPeter Avalos 	if (path != NULL)
62918de8d7fSPeter Avalos 		filename = path + 1;
63036e94dc5SPeter Avalos 
631e9778795SPeter Avalos 	if (xasprintf(&ret, "%s%s%s", pw->pw_dir, sep, filename) >= PATH_MAX)
63218de8d7fSPeter Avalos 		fatal("tilde_expand_filename: Path too long");
63318de8d7fSPeter Avalos 
63436e94dc5SPeter Avalos 	return (ret);
63518de8d7fSPeter Avalos }
63618de8d7fSPeter Avalos 
63718de8d7fSPeter Avalos /*
63818de8d7fSPeter Avalos  * Expand a string with a set of %[char] escapes. A number of escapes may be
63918de8d7fSPeter Avalos  * specified as (char *escape_chars, char *replacement) pairs. The list must
64018de8d7fSPeter Avalos  * be terminated by a NULL escape_char. Returns replaced string in memory
64118de8d7fSPeter Avalos  * allocated by xmalloc.
64218de8d7fSPeter Avalos  */
64318de8d7fSPeter Avalos char *
64418de8d7fSPeter Avalos percent_expand(const char *string, ...)
64518de8d7fSPeter Avalos {
64618de8d7fSPeter Avalos #define EXPAND_MAX_KEYS	16
647856ea928SPeter Avalos 	u_int num_keys, i, j;
64818de8d7fSPeter Avalos 	struct {
64918de8d7fSPeter Avalos 		const char *key;
65018de8d7fSPeter Avalos 		const char *repl;
65118de8d7fSPeter Avalos 	} keys[EXPAND_MAX_KEYS];
65218de8d7fSPeter Avalos 	char buf[4096];
65318de8d7fSPeter Avalos 	va_list ap;
65418de8d7fSPeter Avalos 
65518de8d7fSPeter Avalos 	/* Gather keys */
65618de8d7fSPeter Avalos 	va_start(ap, string);
65718de8d7fSPeter Avalos 	for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
65818de8d7fSPeter Avalos 		keys[num_keys].key = va_arg(ap, char *);
65918de8d7fSPeter Avalos 		if (keys[num_keys].key == NULL)
66018de8d7fSPeter Avalos 			break;
66118de8d7fSPeter Avalos 		keys[num_keys].repl = va_arg(ap, char *);
66218de8d7fSPeter Avalos 		if (keys[num_keys].repl == NULL)
663856ea928SPeter Avalos 			fatal("%s: NULL replacement", __func__);
66418de8d7fSPeter Avalos 	}
665856ea928SPeter Avalos 	if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
666856ea928SPeter Avalos 		fatal("%s: too many keys", __func__);
66718de8d7fSPeter Avalos 	va_end(ap);
66818de8d7fSPeter Avalos 
66918de8d7fSPeter Avalos 	/* Expand string */
67018de8d7fSPeter Avalos 	*buf = '\0';
67118de8d7fSPeter Avalos 	for (i = 0; *string != '\0'; string++) {
67218de8d7fSPeter Avalos 		if (*string != '%') {
67318de8d7fSPeter Avalos  append:
67418de8d7fSPeter Avalos 			buf[i++] = *string;
67518de8d7fSPeter Avalos 			if (i >= sizeof(buf))
676856ea928SPeter Avalos 				fatal("%s: string too long", __func__);
67718de8d7fSPeter Avalos 			buf[i] = '\0';
67818de8d7fSPeter Avalos 			continue;
67918de8d7fSPeter Avalos 		}
68018de8d7fSPeter Avalos 		string++;
681856ea928SPeter Avalos 		/* %% case */
68218de8d7fSPeter Avalos 		if (*string == '%')
68318de8d7fSPeter Avalos 			goto append;
684e9778795SPeter Avalos 		if (*string == '\0')
685e9778795SPeter Avalos 			fatal("%s: invalid format", __func__);
68618de8d7fSPeter Avalos 		for (j = 0; j < num_keys; j++) {
68718de8d7fSPeter Avalos 			if (strchr(keys[j].key, *string) != NULL) {
68818de8d7fSPeter Avalos 				i = strlcat(buf, keys[j].repl, sizeof(buf));
68918de8d7fSPeter Avalos 				if (i >= sizeof(buf))
690856ea928SPeter Avalos 					fatal("%s: string too long", __func__);
69118de8d7fSPeter Avalos 				break;
69218de8d7fSPeter Avalos 			}
69318de8d7fSPeter Avalos 		}
69418de8d7fSPeter Avalos 		if (j >= num_keys)
695856ea928SPeter Avalos 			fatal("%s: unknown key %%%c", __func__, *string);
69618de8d7fSPeter Avalos 	}
69718de8d7fSPeter Avalos 	return (xstrdup(buf));
69818de8d7fSPeter Avalos #undef EXPAND_MAX_KEYS
69918de8d7fSPeter Avalos }
70018de8d7fSPeter Avalos 
70118de8d7fSPeter Avalos /*
70218de8d7fSPeter Avalos  * Read an entire line from a public key file into a static buffer, discarding
70318de8d7fSPeter Avalos  * lines that exceed the buffer size.  Returns 0 on success, -1 on failure.
70418de8d7fSPeter Avalos  */
70518de8d7fSPeter Avalos int
70618de8d7fSPeter Avalos read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
70718de8d7fSPeter Avalos    u_long *lineno)
70818de8d7fSPeter Avalos {
70918de8d7fSPeter Avalos 	while (fgets(buf, bufsz, f) != NULL) {
71018de8d7fSPeter Avalos 		if (buf[0] == '\0')
71118de8d7fSPeter Avalos 			continue;
71218de8d7fSPeter Avalos 		(*lineno)++;
71318de8d7fSPeter Avalos 		if (buf[strlen(buf) - 1] == '\n' || feof(f)) {
71418de8d7fSPeter Avalos 			return 0;
71518de8d7fSPeter Avalos 		} else {
71618de8d7fSPeter Avalos 			debug("%s: %s line %lu exceeds size limit", __func__,
71718de8d7fSPeter Avalos 			    filename, *lineno);
71818de8d7fSPeter Avalos 			/* discard remainder of line */
71918de8d7fSPeter Avalos 			while (fgetc(f) != '\n' && !feof(f))
72018de8d7fSPeter Avalos 				;	/* nothing */
72118de8d7fSPeter Avalos 		}
72218de8d7fSPeter Avalos 	}
72318de8d7fSPeter Avalos 	return -1;
72418de8d7fSPeter Avalos }
72518de8d7fSPeter Avalos 
72618de8d7fSPeter Avalos int
72718de8d7fSPeter Avalos tun_open(int tun, int mode)
72818de8d7fSPeter Avalos {
72918de8d7fSPeter Avalos #if defined(CUSTOM_SYS_TUN_OPEN)
73018de8d7fSPeter Avalos 	return (sys_tun_open(tun, mode));
73118de8d7fSPeter Avalos #elif defined(SSH_TUN_OPENBSD)
73218de8d7fSPeter Avalos 	struct ifreq ifr;
73318de8d7fSPeter Avalos 	char name[100];
73418de8d7fSPeter Avalos 	int fd = -1, sock;
735e9778795SPeter Avalos 	const char *tunbase = "tun";
736e9778795SPeter Avalos 
737e9778795SPeter Avalos 	if (mode == SSH_TUNMODE_ETHERNET)
738e9778795SPeter Avalos 		tunbase = "tap";
73918de8d7fSPeter Avalos 
74018de8d7fSPeter Avalos 	/* Open the tunnel device */
74118de8d7fSPeter Avalos 	if (tun <= SSH_TUNID_MAX) {
742e9778795SPeter Avalos 		snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun);
74318de8d7fSPeter Avalos 		fd = open(name, O_RDWR);
74418de8d7fSPeter Avalos 	} else if (tun == SSH_TUNID_ANY) {
74518de8d7fSPeter Avalos 		for (tun = 100; tun >= 0; tun--) {
746e9778795SPeter Avalos 			snprintf(name, sizeof(name), "/dev/%s%d",
747e9778795SPeter Avalos 			    tunbase, tun);
74818de8d7fSPeter Avalos 			if ((fd = open(name, O_RDWR)) >= 0)
74918de8d7fSPeter Avalos 				break;
75018de8d7fSPeter Avalos 		}
75118de8d7fSPeter Avalos 	} else {
75218de8d7fSPeter Avalos 		debug("%s: invalid tunnel %u", __func__, tun);
753e9778795SPeter Avalos 		return -1;
75418de8d7fSPeter Avalos 	}
75518de8d7fSPeter Avalos 
75618de8d7fSPeter Avalos 	if (fd < 0) {
757e9778795SPeter Avalos 		debug("%s: %s open: %s", __func__, name, strerror(errno));
758e9778795SPeter Avalos 		return -1;
75918de8d7fSPeter Avalos 	}
76018de8d7fSPeter Avalos 
76118de8d7fSPeter Avalos 	debug("%s: %s mode %d fd %d", __func__, name, mode, fd);
76218de8d7fSPeter Avalos 
763e9778795SPeter Avalos 	/* Bring interface up if it is not already */
764e9778795SPeter Avalos 	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun);
76518de8d7fSPeter Avalos 	if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
76618de8d7fSPeter Avalos 		goto failed;
76718de8d7fSPeter Avalos 
768e9778795SPeter Avalos 	if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) {
769e9778795SPeter Avalos 		debug("%s: get interface %s flags: %s", __func__,
770e9778795SPeter Avalos 		    ifr.ifr_name, strerror(errno));
77118de8d7fSPeter Avalos 		goto failed;
772e9778795SPeter Avalos 	}
77318de8d7fSPeter Avalos 
774e9778795SPeter Avalos 	if (!(ifr.ifr_flags & IFF_UP)) {
77518de8d7fSPeter Avalos 		ifr.ifr_flags |= IFF_UP;
776e9778795SPeter Avalos 		if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) {
777e9778795SPeter Avalos 			debug("%s: activate interface %s: %s", __func__,
778e9778795SPeter Avalos 			    ifr.ifr_name, strerror(errno));
77918de8d7fSPeter Avalos 			goto failed;
780e9778795SPeter Avalos 		}
781e9778795SPeter Avalos 	}
78218de8d7fSPeter Avalos 
78318de8d7fSPeter Avalos 	close(sock);
784e9778795SPeter Avalos 	return fd;
78518de8d7fSPeter Avalos 
78618de8d7fSPeter Avalos  failed:
78718de8d7fSPeter Avalos 	if (fd >= 0)
78818de8d7fSPeter Avalos 		close(fd);
78918de8d7fSPeter Avalos 	if (sock >= 0)
79018de8d7fSPeter Avalos 		close(sock);
791e9778795SPeter Avalos 	return -1;
79218de8d7fSPeter Avalos #else
79318de8d7fSPeter Avalos 	error("Tunnel interfaces are not supported on this platform");
79418de8d7fSPeter Avalos 	return (-1);
79518de8d7fSPeter Avalos #endif
79618de8d7fSPeter Avalos }
79718de8d7fSPeter Avalos 
79818de8d7fSPeter Avalos void
79918de8d7fSPeter Avalos sanitise_stdfd(void)
80018de8d7fSPeter Avalos {
80118de8d7fSPeter Avalos 	int nullfd, dupfd;
80218de8d7fSPeter Avalos 
80318de8d7fSPeter Avalos 	if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
804cb5eb4f1SPeter Avalos 		fprintf(stderr, "Couldn't open /dev/null: %s\n",
805cb5eb4f1SPeter Avalos 		    strerror(errno));
80618de8d7fSPeter Avalos 		exit(1);
80718de8d7fSPeter Avalos 	}
808e9778795SPeter Avalos 	while (++dupfd <= STDERR_FILENO) {
809e9778795SPeter Avalos 		/* Only populate closed fds. */
810e9778795SPeter Avalos 		if (fcntl(dupfd, F_GETFL) == -1 && errno == EBADF) {
81118de8d7fSPeter Avalos 			if (dup2(nullfd, dupfd) == -1) {
812cb5eb4f1SPeter Avalos 				fprintf(stderr, "dup2: %s\n", strerror(errno));
81318de8d7fSPeter Avalos 				exit(1);
81418de8d7fSPeter Avalos 			}
81518de8d7fSPeter Avalos 		}
816e9778795SPeter Avalos 	}
817e9778795SPeter Avalos 	if (nullfd > STDERR_FILENO)
81818de8d7fSPeter Avalos 		close(nullfd);
81918de8d7fSPeter Avalos }
82018de8d7fSPeter Avalos 
82118de8d7fSPeter Avalos char *
82218de8d7fSPeter Avalos tohex(const void *vp, size_t l)
82318de8d7fSPeter Avalos {
82418de8d7fSPeter Avalos 	const u_char *p = (const u_char *)vp;
82518de8d7fSPeter Avalos 	char b[3], *r;
82618de8d7fSPeter Avalos 	size_t i, hl;
82718de8d7fSPeter Avalos 
82818de8d7fSPeter Avalos 	if (l > 65536)
82918de8d7fSPeter Avalos 		return xstrdup("tohex: length > 65536");
83018de8d7fSPeter Avalos 
83118de8d7fSPeter Avalos 	hl = l * 2 + 1;
83218de8d7fSPeter Avalos 	r = xcalloc(1, hl);
83318de8d7fSPeter Avalos 	for (i = 0; i < l; i++) {
83418de8d7fSPeter Avalos 		snprintf(b, sizeof(b), "%02x", p[i]);
83518de8d7fSPeter Avalos 		strlcat(r, b, hl);
83618de8d7fSPeter Avalos 	}
83718de8d7fSPeter Avalos 	return (r);
83818de8d7fSPeter Avalos }
83918de8d7fSPeter Avalos 
84018de8d7fSPeter Avalos u_int64_t
84118de8d7fSPeter Avalos get_u64(const void *vp)
84218de8d7fSPeter Avalos {
84318de8d7fSPeter Avalos 	const u_char *p = (const u_char *)vp;
84418de8d7fSPeter Avalos 	u_int64_t v;
84518de8d7fSPeter Avalos 
84618de8d7fSPeter Avalos 	v  = (u_int64_t)p[0] << 56;
84718de8d7fSPeter Avalos 	v |= (u_int64_t)p[1] << 48;
84818de8d7fSPeter Avalos 	v |= (u_int64_t)p[2] << 40;
84918de8d7fSPeter Avalos 	v |= (u_int64_t)p[3] << 32;
85018de8d7fSPeter Avalos 	v |= (u_int64_t)p[4] << 24;
85118de8d7fSPeter Avalos 	v |= (u_int64_t)p[5] << 16;
85218de8d7fSPeter Avalos 	v |= (u_int64_t)p[6] << 8;
85318de8d7fSPeter Avalos 	v |= (u_int64_t)p[7];
85418de8d7fSPeter Avalos 
85518de8d7fSPeter Avalos 	return (v);
85618de8d7fSPeter Avalos }
85718de8d7fSPeter Avalos 
85818de8d7fSPeter Avalos u_int32_t
85918de8d7fSPeter Avalos get_u32(const void *vp)
86018de8d7fSPeter Avalos {
86118de8d7fSPeter Avalos 	const u_char *p = (const u_char *)vp;
86218de8d7fSPeter Avalos 	u_int32_t v;
86318de8d7fSPeter Avalos 
86418de8d7fSPeter Avalos 	v  = (u_int32_t)p[0] << 24;
86518de8d7fSPeter Avalos 	v |= (u_int32_t)p[1] << 16;
86618de8d7fSPeter Avalos 	v |= (u_int32_t)p[2] << 8;
86718de8d7fSPeter Avalos 	v |= (u_int32_t)p[3];
86818de8d7fSPeter Avalos 
86918de8d7fSPeter Avalos 	return (v);
87018de8d7fSPeter Avalos }
87118de8d7fSPeter Avalos 
87236e94dc5SPeter Avalos u_int32_t
87336e94dc5SPeter Avalos get_u32_le(const void *vp)
87436e94dc5SPeter Avalos {
87536e94dc5SPeter Avalos 	const u_char *p = (const u_char *)vp;
87636e94dc5SPeter Avalos 	u_int32_t v;
87736e94dc5SPeter Avalos 
87836e94dc5SPeter Avalos 	v  = (u_int32_t)p[0];
87936e94dc5SPeter Avalos 	v |= (u_int32_t)p[1] << 8;
88036e94dc5SPeter Avalos 	v |= (u_int32_t)p[2] << 16;
88136e94dc5SPeter Avalos 	v |= (u_int32_t)p[3] << 24;
88236e94dc5SPeter Avalos 
88336e94dc5SPeter Avalos 	return (v);
88436e94dc5SPeter Avalos }
88536e94dc5SPeter Avalos 
88618de8d7fSPeter Avalos u_int16_t
88718de8d7fSPeter Avalos get_u16(const void *vp)
88818de8d7fSPeter Avalos {
88918de8d7fSPeter Avalos 	const u_char *p = (const u_char *)vp;
89018de8d7fSPeter Avalos 	u_int16_t v;
89118de8d7fSPeter Avalos 
89218de8d7fSPeter Avalos 	v  = (u_int16_t)p[0] << 8;
89318de8d7fSPeter Avalos 	v |= (u_int16_t)p[1];
89418de8d7fSPeter Avalos 
89518de8d7fSPeter Avalos 	return (v);
89618de8d7fSPeter Avalos }
89718de8d7fSPeter Avalos 
89818de8d7fSPeter Avalos void
89918de8d7fSPeter Avalos put_u64(void *vp, u_int64_t v)
90018de8d7fSPeter Avalos {
90118de8d7fSPeter Avalos 	u_char *p = (u_char *)vp;
90218de8d7fSPeter Avalos 
90318de8d7fSPeter Avalos 	p[0] = (u_char)(v >> 56) & 0xff;
90418de8d7fSPeter Avalos 	p[1] = (u_char)(v >> 48) & 0xff;
90518de8d7fSPeter Avalos 	p[2] = (u_char)(v >> 40) & 0xff;
90618de8d7fSPeter Avalos 	p[3] = (u_char)(v >> 32) & 0xff;
90718de8d7fSPeter Avalos 	p[4] = (u_char)(v >> 24) & 0xff;
90818de8d7fSPeter Avalos 	p[5] = (u_char)(v >> 16) & 0xff;
90918de8d7fSPeter Avalos 	p[6] = (u_char)(v >> 8) & 0xff;
91018de8d7fSPeter Avalos 	p[7] = (u_char)v & 0xff;
91118de8d7fSPeter Avalos }
91218de8d7fSPeter Avalos 
91318de8d7fSPeter Avalos void
91418de8d7fSPeter Avalos put_u32(void *vp, u_int32_t v)
91518de8d7fSPeter Avalos {
91618de8d7fSPeter Avalos 	u_char *p = (u_char *)vp;
91718de8d7fSPeter Avalos 
91818de8d7fSPeter Avalos 	p[0] = (u_char)(v >> 24) & 0xff;
91918de8d7fSPeter Avalos 	p[1] = (u_char)(v >> 16) & 0xff;
92018de8d7fSPeter Avalos 	p[2] = (u_char)(v >> 8) & 0xff;
92118de8d7fSPeter Avalos 	p[3] = (u_char)v & 0xff;
92218de8d7fSPeter Avalos }
92318de8d7fSPeter Avalos 
92436e94dc5SPeter Avalos void
92536e94dc5SPeter Avalos put_u32_le(void *vp, u_int32_t v)
92636e94dc5SPeter Avalos {
92736e94dc5SPeter Avalos 	u_char *p = (u_char *)vp;
92836e94dc5SPeter Avalos 
92936e94dc5SPeter Avalos 	p[0] = (u_char)v & 0xff;
93036e94dc5SPeter Avalos 	p[1] = (u_char)(v >> 8) & 0xff;
93136e94dc5SPeter Avalos 	p[2] = (u_char)(v >> 16) & 0xff;
93236e94dc5SPeter Avalos 	p[3] = (u_char)(v >> 24) & 0xff;
93336e94dc5SPeter Avalos }
93418de8d7fSPeter Avalos 
93518de8d7fSPeter Avalos void
93618de8d7fSPeter Avalos put_u16(void *vp, u_int16_t v)
93718de8d7fSPeter Avalos {
93818de8d7fSPeter Avalos 	u_char *p = (u_char *)vp;
93918de8d7fSPeter Avalos 
94018de8d7fSPeter Avalos 	p[0] = (u_char)(v >> 8) & 0xff;
94118de8d7fSPeter Avalos 	p[1] = (u_char)v & 0xff;
94218de8d7fSPeter Avalos }
94318de8d7fSPeter Avalos 
94418de8d7fSPeter Avalos void
94518de8d7fSPeter Avalos ms_subtract_diff(struct timeval *start, int *ms)
94618de8d7fSPeter Avalos {
94718de8d7fSPeter Avalos 	struct timeval diff, finish;
94818de8d7fSPeter Avalos 
94918de8d7fSPeter Avalos 	gettimeofday(&finish, NULL);
95018de8d7fSPeter Avalos 	timersub(&finish, start, &diff);
95118de8d7fSPeter Avalos 	*ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
95218de8d7fSPeter Avalos }
95318de8d7fSPeter Avalos 
95418de8d7fSPeter Avalos void
95518de8d7fSPeter Avalos ms_to_timeval(struct timeval *tv, int ms)
95618de8d7fSPeter Avalos {
95718de8d7fSPeter Avalos 	if (ms < 0)
95818de8d7fSPeter Avalos 		ms = 0;
95918de8d7fSPeter Avalos 	tv->tv_sec = ms / 1000;
96018de8d7fSPeter Avalos 	tv->tv_usec = (ms % 1000) * 1000;
96118de8d7fSPeter Avalos }
96218de8d7fSPeter Avalos 
96336e94dc5SPeter Avalos time_t
96436e94dc5SPeter Avalos monotime(void)
96536e94dc5SPeter Avalos {
96636e94dc5SPeter Avalos #if defined(HAVE_CLOCK_GETTIME) && \
96736e94dc5SPeter Avalos     (defined(CLOCK_MONOTONIC) || defined(CLOCK_BOOTTIME))
96836e94dc5SPeter Avalos 	struct timespec ts;
96936e94dc5SPeter Avalos 	static int gettime_failed = 0;
97036e94dc5SPeter Avalos 
97136e94dc5SPeter Avalos 	if (!gettime_failed) {
97236e94dc5SPeter Avalos #if defined(CLOCK_BOOTTIME)
97336e94dc5SPeter Avalos 		if (clock_gettime(CLOCK_BOOTTIME, &ts) == 0)
97436e94dc5SPeter Avalos 			return (ts.tv_sec);
97536e94dc5SPeter Avalos #endif
97636e94dc5SPeter Avalos #if defined(CLOCK_MONOTONIC)
97736e94dc5SPeter Avalos 		if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
97836e94dc5SPeter Avalos 			return (ts.tv_sec);
97936e94dc5SPeter Avalos #endif
98036e94dc5SPeter Avalos 		debug3("clock_gettime: %s", strerror(errno));
98136e94dc5SPeter Avalos 		gettime_failed = 1;
98236e94dc5SPeter Avalos 	}
98336e94dc5SPeter Avalos #endif /* HAVE_CLOCK_GETTIME && (CLOCK_MONOTONIC || CLOCK_BOOTTIME */
98436e94dc5SPeter Avalos 
98536e94dc5SPeter Avalos 	return time(NULL);
98636e94dc5SPeter Avalos }
98736e94dc5SPeter Avalos 
988e9778795SPeter Avalos double
989e9778795SPeter Avalos monotime_double(void)
990e9778795SPeter Avalos {
991e9778795SPeter Avalos #if defined(HAVE_CLOCK_GETTIME) && \
992e9778795SPeter Avalos     (defined(CLOCK_MONOTONIC) || defined(CLOCK_BOOTTIME))
993e9778795SPeter Avalos 	struct timespec ts;
994e9778795SPeter Avalos 	static int gettime_failed = 0;
995e9778795SPeter Avalos 
996e9778795SPeter Avalos 	if (!gettime_failed) {
997e9778795SPeter Avalos #if defined(CLOCK_BOOTTIME)
998e9778795SPeter Avalos 		if (clock_gettime(CLOCK_BOOTTIME, &ts) == 0)
999e9778795SPeter Avalos 			return (ts.tv_sec + (double)ts.tv_nsec / 1000000000);
1000e9778795SPeter Avalos #endif
1001e9778795SPeter Avalos #if defined(CLOCK_MONOTONIC)
1002e9778795SPeter Avalos 		if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
1003e9778795SPeter Avalos 			return (ts.tv_sec + (double)ts.tv_nsec / 1000000000);
1004e9778795SPeter Avalos #endif
1005e9778795SPeter Avalos 		debug3("clock_gettime: %s", strerror(errno));
1006e9778795SPeter Avalos 		gettime_failed = 1;
1007e9778795SPeter Avalos 	}
1008e9778795SPeter Avalos #endif /* HAVE_CLOCK_GETTIME && (CLOCK_MONOTONIC || CLOCK_BOOTTIME */
1009e9778795SPeter Avalos 
1010e9778795SPeter Avalos 	return (double)time(NULL);
1011e9778795SPeter Avalos }
1012e9778795SPeter Avalos 
10139f304aafSPeter Avalos void
10149f304aafSPeter Avalos bandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen)
1015856ea928SPeter Avalos {
10169f304aafSPeter Avalos 	bw->buflen = buflen;
10179f304aafSPeter Avalos 	bw->rate = kbps;
10189f304aafSPeter Avalos 	bw->thresh = bw->rate;
10199f304aafSPeter Avalos 	bw->lamt = 0;
10209f304aafSPeter Avalos 	timerclear(&bw->bwstart);
10219f304aafSPeter Avalos 	timerclear(&bw->bwend);
1022856ea928SPeter Avalos }
10239f304aafSPeter Avalos 
10249f304aafSPeter Avalos /* Callback from read/write loop to insert bandwidth-limiting delays */
10259f304aafSPeter Avalos void
10269f304aafSPeter Avalos bandwidth_limit(struct bwlimit *bw, size_t read_len)
10279f304aafSPeter Avalos {
10289f304aafSPeter Avalos 	u_int64_t waitlen;
10299f304aafSPeter Avalos 	struct timespec ts, rm;
10309f304aafSPeter Avalos 
10319f304aafSPeter Avalos 	if (!timerisset(&bw->bwstart)) {
10329f304aafSPeter Avalos 		gettimeofday(&bw->bwstart, NULL);
10339f304aafSPeter Avalos 		return;
10349f304aafSPeter Avalos 	}
10359f304aafSPeter Avalos 
10369f304aafSPeter Avalos 	bw->lamt += read_len;
10379f304aafSPeter Avalos 	if (bw->lamt < bw->thresh)
10389f304aafSPeter Avalos 		return;
10399f304aafSPeter Avalos 
10409f304aafSPeter Avalos 	gettimeofday(&bw->bwend, NULL);
10419f304aafSPeter Avalos 	timersub(&bw->bwend, &bw->bwstart, &bw->bwend);
10429f304aafSPeter Avalos 	if (!timerisset(&bw->bwend))
10439f304aafSPeter Avalos 		return;
10449f304aafSPeter Avalos 
10459f304aafSPeter Avalos 	bw->lamt *= 8;
10469f304aafSPeter Avalos 	waitlen = (double)1000000L * bw->lamt / bw->rate;
10479f304aafSPeter Avalos 
10489f304aafSPeter Avalos 	bw->bwstart.tv_sec = waitlen / 1000000L;
10499f304aafSPeter Avalos 	bw->bwstart.tv_usec = waitlen % 1000000L;
10509f304aafSPeter Avalos 
10519f304aafSPeter Avalos 	if (timercmp(&bw->bwstart, &bw->bwend, >)) {
10529f304aafSPeter Avalos 		timersub(&bw->bwstart, &bw->bwend, &bw->bwend);
10539f304aafSPeter Avalos 
10549f304aafSPeter Avalos 		/* Adjust the wait time */
10559f304aafSPeter Avalos 		if (bw->bwend.tv_sec) {
10569f304aafSPeter Avalos 			bw->thresh /= 2;
10579f304aafSPeter Avalos 			if (bw->thresh < bw->buflen / 4)
10589f304aafSPeter Avalos 				bw->thresh = bw->buflen / 4;
10599f304aafSPeter Avalos 		} else if (bw->bwend.tv_usec < 10000) {
10609f304aafSPeter Avalos 			bw->thresh *= 2;
10619f304aafSPeter Avalos 			if (bw->thresh > bw->buflen * 8)
10629f304aafSPeter Avalos 				bw->thresh = bw->buflen * 8;
10639f304aafSPeter Avalos 		}
10649f304aafSPeter Avalos 
10659f304aafSPeter Avalos 		TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts);
10669f304aafSPeter Avalos 		while (nanosleep(&ts, &rm) == -1) {
10679f304aafSPeter Avalos 			if (errno != EINTR)
10689f304aafSPeter Avalos 				break;
10699f304aafSPeter Avalos 			ts = rm;
10709f304aafSPeter Avalos 		}
10719f304aafSPeter Avalos 	}
10729f304aafSPeter Avalos 
10739f304aafSPeter Avalos 	bw->lamt = 0;
10749f304aafSPeter Avalos 	gettimeofday(&bw->bwstart, NULL);
10759f304aafSPeter Avalos }
10769f304aafSPeter Avalos 
10779f304aafSPeter Avalos /* Make a template filename for mk[sd]temp() */
10789f304aafSPeter Avalos void
10799f304aafSPeter Avalos mktemp_proto(char *s, size_t len)
10809f304aafSPeter Avalos {
10819f304aafSPeter Avalos 	const char *tmpdir;
10829f304aafSPeter Avalos 	int r;
10839f304aafSPeter Avalos 
10849f304aafSPeter Avalos 	if ((tmpdir = getenv("TMPDIR")) != NULL) {
10859f304aafSPeter Avalos 		r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir);
10869f304aafSPeter Avalos 		if (r > 0 && (size_t)r < len)
10879f304aafSPeter Avalos 			return;
10889f304aafSPeter Avalos 	}
10899f304aafSPeter Avalos 	r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX");
10909f304aafSPeter Avalos 	if (r < 0 || (size_t)r >= len)
10919f304aafSPeter Avalos 		fatal("%s: template string too short", __func__);
10929f304aafSPeter Avalos }
10939f304aafSPeter Avalos 
10949f304aafSPeter Avalos static const struct {
10959f304aafSPeter Avalos 	const char *name;
10969f304aafSPeter Avalos 	int value;
10979f304aafSPeter Avalos } ipqos[] = {
1098*ce74bacaSMatthew Dillon 	{ "none", INT_MAX },		/* can't use 0 here; that's CS0 */
10999f304aafSPeter Avalos 	{ "af11", IPTOS_DSCP_AF11 },
11009f304aafSPeter Avalos 	{ "af12", IPTOS_DSCP_AF12 },
11019f304aafSPeter Avalos 	{ "af13", IPTOS_DSCP_AF13 },
110299e85e0dSPeter Avalos 	{ "af21", IPTOS_DSCP_AF21 },
11039f304aafSPeter Avalos 	{ "af22", IPTOS_DSCP_AF22 },
11049f304aafSPeter Avalos 	{ "af23", IPTOS_DSCP_AF23 },
11059f304aafSPeter Avalos 	{ "af31", IPTOS_DSCP_AF31 },
11069f304aafSPeter Avalos 	{ "af32", IPTOS_DSCP_AF32 },
11079f304aafSPeter Avalos 	{ "af33", IPTOS_DSCP_AF33 },
11089f304aafSPeter Avalos 	{ "af41", IPTOS_DSCP_AF41 },
11099f304aafSPeter Avalos 	{ "af42", IPTOS_DSCP_AF42 },
11109f304aafSPeter Avalos 	{ "af43", IPTOS_DSCP_AF43 },
11119f304aafSPeter Avalos 	{ "cs0", IPTOS_DSCP_CS0 },
11129f304aafSPeter Avalos 	{ "cs1", IPTOS_DSCP_CS1 },
11139f304aafSPeter Avalos 	{ "cs2", IPTOS_DSCP_CS2 },
11149f304aafSPeter Avalos 	{ "cs3", IPTOS_DSCP_CS3 },
11159f304aafSPeter Avalos 	{ "cs4", IPTOS_DSCP_CS4 },
11169f304aafSPeter Avalos 	{ "cs5", IPTOS_DSCP_CS5 },
11179f304aafSPeter Avalos 	{ "cs6", IPTOS_DSCP_CS6 },
11189f304aafSPeter Avalos 	{ "cs7", IPTOS_DSCP_CS7 },
11199f304aafSPeter Avalos 	{ "ef", IPTOS_DSCP_EF },
11209f304aafSPeter Avalos 	{ "lowdelay", IPTOS_LOWDELAY },
11219f304aafSPeter Avalos 	{ "throughput", IPTOS_THROUGHPUT },
11229f304aafSPeter Avalos 	{ "reliability", IPTOS_RELIABILITY },
11239f304aafSPeter Avalos 	{ NULL, -1 }
11249f304aafSPeter Avalos };
11259f304aafSPeter Avalos 
11269f304aafSPeter Avalos int
11279f304aafSPeter Avalos parse_ipqos(const char *cp)
11289f304aafSPeter Avalos {
11299f304aafSPeter Avalos 	u_int i;
11309f304aafSPeter Avalos 	char *ep;
11319f304aafSPeter Avalos 	long val;
11329f304aafSPeter Avalos 
11339f304aafSPeter Avalos 	if (cp == NULL)
11349f304aafSPeter Avalos 		return -1;
11359f304aafSPeter Avalos 	for (i = 0; ipqos[i].name != NULL; i++) {
11369f304aafSPeter Avalos 		if (strcasecmp(cp, ipqos[i].name) == 0)
11379f304aafSPeter Avalos 			return ipqos[i].value;
11389f304aafSPeter Avalos 	}
11399f304aafSPeter Avalos 	/* Try parsing as an integer */
11409f304aafSPeter Avalos 	val = strtol(cp, &ep, 0);
11419f304aafSPeter Avalos 	if (*cp == '\0' || *ep != '\0' || val < 0 || val > 255)
11429f304aafSPeter Avalos 		return -1;
11439f304aafSPeter Avalos 	return val;
11449f304aafSPeter Avalos }
11459f304aafSPeter Avalos 
11461c188a7fSPeter Avalos const char *
11471c188a7fSPeter Avalos iptos2str(int iptos)
11481c188a7fSPeter Avalos {
11491c188a7fSPeter Avalos 	int i;
11501c188a7fSPeter Avalos 	static char iptos_str[sizeof "0xff"];
11511c188a7fSPeter Avalos 
11521c188a7fSPeter Avalos 	for (i = 0; ipqos[i].name != NULL; i++) {
11531c188a7fSPeter Avalos 		if (ipqos[i].value == iptos)
11541c188a7fSPeter Avalos 			return ipqos[i].name;
11551c188a7fSPeter Avalos 	}
11561c188a7fSPeter Avalos 	snprintf(iptos_str, sizeof iptos_str, "0x%02x", iptos);
11571c188a7fSPeter Avalos 	return iptos_str;
11581c188a7fSPeter Avalos }
115936e94dc5SPeter Avalos 
116036e94dc5SPeter Avalos void
116136e94dc5SPeter Avalos lowercase(char *s)
116236e94dc5SPeter Avalos {
116336e94dc5SPeter Avalos 	for (; *s; s++)
116436e94dc5SPeter Avalos 		*s = tolower((u_char)*s);
116536e94dc5SPeter Avalos }
116636e94dc5SPeter Avalos 
116736e94dc5SPeter Avalos int
116836e94dc5SPeter Avalos unix_listener(const char *path, int backlog, int unlink_first)
116936e94dc5SPeter Avalos {
117036e94dc5SPeter Avalos 	struct sockaddr_un sunaddr;
117136e94dc5SPeter Avalos 	int saved_errno, sock;
117236e94dc5SPeter Avalos 
117336e94dc5SPeter Avalos 	memset(&sunaddr, 0, sizeof(sunaddr));
117436e94dc5SPeter Avalos 	sunaddr.sun_family = AF_UNIX;
117536e94dc5SPeter Avalos 	if (strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) {
117636e94dc5SPeter Avalos 		error("%s: \"%s\" too long for Unix domain socket", __func__,
117736e94dc5SPeter Avalos 		    path);
117836e94dc5SPeter Avalos 		errno = ENAMETOOLONG;
117936e94dc5SPeter Avalos 		return -1;
118036e94dc5SPeter Avalos 	}
118136e94dc5SPeter Avalos 
118236e94dc5SPeter Avalos 	sock = socket(PF_UNIX, SOCK_STREAM, 0);
118336e94dc5SPeter Avalos 	if (sock < 0) {
118436e94dc5SPeter Avalos 		saved_errno = errno;
118536e94dc5SPeter Avalos 		error("socket: %.100s", strerror(errno));
118636e94dc5SPeter Avalos 		errno = saved_errno;
118736e94dc5SPeter Avalos 		return -1;
118836e94dc5SPeter Avalos 	}
118936e94dc5SPeter Avalos 	if (unlink_first == 1) {
119036e94dc5SPeter Avalos 		if (unlink(path) != 0 && errno != ENOENT)
119136e94dc5SPeter Avalos 			error("unlink(%s): %.100s", path, strerror(errno));
119236e94dc5SPeter Avalos 	}
119336e94dc5SPeter Avalos 	if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
119436e94dc5SPeter Avalos 		saved_errno = errno;
119536e94dc5SPeter Avalos 		error("bind: %.100s", strerror(errno));
119636e94dc5SPeter Avalos 		close(sock);
119736e94dc5SPeter Avalos 		error("%s: cannot bind to path: %s", __func__, path);
119836e94dc5SPeter Avalos 		errno = saved_errno;
119936e94dc5SPeter Avalos 		return -1;
120036e94dc5SPeter Avalos 	}
120136e94dc5SPeter Avalos 	if (listen(sock, backlog) < 0) {
120236e94dc5SPeter Avalos 		saved_errno = errno;
120336e94dc5SPeter Avalos 		error("listen: %.100s", strerror(errno));
120436e94dc5SPeter Avalos 		close(sock);
120536e94dc5SPeter Avalos 		unlink(path);
120636e94dc5SPeter Avalos 		error("%s: cannot listen on path: %s", __func__, path);
120736e94dc5SPeter Avalos 		errno = saved_errno;
120836e94dc5SPeter Avalos 		return -1;
120936e94dc5SPeter Avalos 	}
121036e94dc5SPeter Avalos 	return sock;
121136e94dc5SPeter Avalos }
121236e94dc5SPeter Avalos 
1213856ea928SPeter Avalos void
1214856ea928SPeter Avalos sock_set_v6only(int s)
1215856ea928SPeter Avalos {
1216e9778795SPeter Avalos #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
1217856ea928SPeter Avalos 	int on = 1;
1218856ea928SPeter Avalos 
1219856ea928SPeter Avalos 	debug3("%s: set socket %d IPV6_V6ONLY", __func__, s);
1220856ea928SPeter Avalos 	if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1)
1221856ea928SPeter Avalos 		error("setsockopt IPV6_V6ONLY: %s", strerror(errno));
1222856ea928SPeter Avalos #endif
1223856ea928SPeter Avalos }
1224e9778795SPeter Avalos 
1225e9778795SPeter Avalos /*
1226e9778795SPeter Avalos  * Compares two strings that maybe be NULL. Returns non-zero if strings
1227e9778795SPeter Avalos  * are both NULL or are identical, returns zero otherwise.
1228e9778795SPeter Avalos  */
1229e9778795SPeter Avalos static int
1230e9778795SPeter Avalos strcmp_maybe_null(const char *a, const char *b)
1231e9778795SPeter Avalos {
1232e9778795SPeter Avalos 	if ((a == NULL && b != NULL) || (a != NULL && b == NULL))
1233e9778795SPeter Avalos 		return 0;
1234e9778795SPeter Avalos 	if (a != NULL && strcmp(a, b) != 0)
1235e9778795SPeter Avalos 		return 0;
1236e9778795SPeter Avalos 	return 1;
1237e9778795SPeter Avalos }
1238e9778795SPeter Avalos 
1239e9778795SPeter Avalos /*
1240e9778795SPeter Avalos  * Compare two forwards, returning non-zero if they are identical or
1241e9778795SPeter Avalos  * zero otherwise.
1242e9778795SPeter Avalos  */
1243e9778795SPeter Avalos int
1244e9778795SPeter Avalos forward_equals(const struct Forward *a, const struct Forward *b)
1245e9778795SPeter Avalos {
1246e9778795SPeter Avalos 	if (strcmp_maybe_null(a->listen_host, b->listen_host) == 0)
1247e9778795SPeter Avalos 		return 0;
1248e9778795SPeter Avalos 	if (a->listen_port != b->listen_port)
1249e9778795SPeter Avalos 		return 0;
1250e9778795SPeter Avalos 	if (strcmp_maybe_null(a->listen_path, b->listen_path) == 0)
1251e9778795SPeter Avalos 		return 0;
1252e9778795SPeter Avalos 	if (strcmp_maybe_null(a->connect_host, b->connect_host) == 0)
1253e9778795SPeter Avalos 		return 0;
1254e9778795SPeter Avalos 	if (a->connect_port != b->connect_port)
1255e9778795SPeter Avalos 		return 0;
1256e9778795SPeter Avalos 	if (strcmp_maybe_null(a->connect_path, b->connect_path) == 0)
1257e9778795SPeter Avalos 		return 0;
1258e9778795SPeter Avalos 	/* allocated_port and handle are not checked */
1259e9778795SPeter Avalos 	return 1;
1260e9778795SPeter Avalos }
1261e9778795SPeter Avalos 
1262*ce74bacaSMatthew Dillon /* returns 1 if bind to specified port by specified user is permitted */
1263*ce74bacaSMatthew Dillon int
1264*ce74bacaSMatthew Dillon bind_permitted(int port, uid_t uid)
1265*ce74bacaSMatthew Dillon {
1266*ce74bacaSMatthew Dillon 	if (port < IPPORT_RESERVED && uid != 0)
1267*ce74bacaSMatthew Dillon 		return 0;
1268*ce74bacaSMatthew Dillon 	return 1;
1269*ce74bacaSMatthew Dillon }
1270*ce74bacaSMatthew Dillon 
1271*ce74bacaSMatthew Dillon /* returns 1 if process is already daemonized, 0 otherwise */
1272*ce74bacaSMatthew Dillon int
1273*ce74bacaSMatthew Dillon daemonized(void)
1274*ce74bacaSMatthew Dillon {
1275*ce74bacaSMatthew Dillon 	int fd;
1276*ce74bacaSMatthew Dillon 
1277*ce74bacaSMatthew Dillon 	if ((fd = open(_PATH_TTY, O_RDONLY | O_NOCTTY)) >= 0) {
1278*ce74bacaSMatthew Dillon 		close(fd);
1279*ce74bacaSMatthew Dillon 		return 0;	/* have controlling terminal */
1280*ce74bacaSMatthew Dillon 	}
1281*ce74bacaSMatthew Dillon 	if (getppid() != 1)
1282*ce74bacaSMatthew Dillon 		return 0;	/* parent is not init */
1283*ce74bacaSMatthew Dillon 	if (getsid(0) != getpid())
1284*ce74bacaSMatthew Dillon 		return 0;	/* not session leader */
1285*ce74bacaSMatthew Dillon 	debug3("already daemonized");
1286*ce74bacaSMatthew Dillon 	return 1;
1287*ce74bacaSMatthew Dillon }
1288*ce74bacaSMatthew Dillon 
1289*ce74bacaSMatthew Dillon 
1290*ce74bacaSMatthew Dillon /*
1291*ce74bacaSMatthew Dillon  * Splits 's' into an argument vector. Handles quoted string and basic
1292*ce74bacaSMatthew Dillon  * escape characters (\\, \", \'). Caller must free the argument vector
1293*ce74bacaSMatthew Dillon  * and its members.
1294*ce74bacaSMatthew Dillon  */
1295*ce74bacaSMatthew Dillon int
1296*ce74bacaSMatthew Dillon argv_split(const char *s, int *argcp, char ***argvp)
1297*ce74bacaSMatthew Dillon {
1298*ce74bacaSMatthew Dillon 	int r = SSH_ERR_INTERNAL_ERROR;
1299*ce74bacaSMatthew Dillon 	int argc = 0, quote, i, j;
1300*ce74bacaSMatthew Dillon 	char *arg, **argv = xcalloc(1, sizeof(*argv));
1301*ce74bacaSMatthew Dillon 
1302*ce74bacaSMatthew Dillon 	*argvp = NULL;
1303*ce74bacaSMatthew Dillon 	*argcp = 0;
1304*ce74bacaSMatthew Dillon 
1305*ce74bacaSMatthew Dillon 	for (i = 0; s[i] != '\0'; i++) {
1306*ce74bacaSMatthew Dillon 		/* Skip leading whitespace */
1307*ce74bacaSMatthew Dillon 		if (s[i] == ' ' || s[i] == '\t')
1308*ce74bacaSMatthew Dillon 			continue;
1309*ce74bacaSMatthew Dillon 
1310*ce74bacaSMatthew Dillon 		/* Start of a token */
1311*ce74bacaSMatthew Dillon 		quote = 0;
1312*ce74bacaSMatthew Dillon 		if (s[i] == '\\' &&
1313*ce74bacaSMatthew Dillon 		    (s[i + 1] == '\'' || s[i + 1] == '\"' || s[i + 1] == '\\'))
1314*ce74bacaSMatthew Dillon 			i++;
1315*ce74bacaSMatthew Dillon 		else if (s[i] == '\'' || s[i] == '"')
1316*ce74bacaSMatthew Dillon 			quote = s[i++];
1317*ce74bacaSMatthew Dillon 
1318*ce74bacaSMatthew Dillon 		argv = xreallocarray(argv, (argc + 2), sizeof(*argv));
1319*ce74bacaSMatthew Dillon 		arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1);
1320*ce74bacaSMatthew Dillon 		argv[argc] = NULL;
1321*ce74bacaSMatthew Dillon 
1322*ce74bacaSMatthew Dillon 		/* Copy the token in, removing escapes */
1323*ce74bacaSMatthew Dillon 		for (j = 0; s[i] != '\0'; i++) {
1324*ce74bacaSMatthew Dillon 			if (s[i] == '\\') {
1325*ce74bacaSMatthew Dillon 				if (s[i + 1] == '\'' ||
1326*ce74bacaSMatthew Dillon 				    s[i + 1] == '\"' ||
1327*ce74bacaSMatthew Dillon 				    s[i + 1] == '\\') {
1328*ce74bacaSMatthew Dillon 					i++; /* Skip '\' */
1329*ce74bacaSMatthew Dillon 					arg[j++] = s[i];
1330*ce74bacaSMatthew Dillon 				} else {
1331*ce74bacaSMatthew Dillon 					/* Unrecognised escape */
1332*ce74bacaSMatthew Dillon 					arg[j++] = s[i];
1333*ce74bacaSMatthew Dillon 				}
1334*ce74bacaSMatthew Dillon 			} else if (quote == 0 && (s[i] == ' ' || s[i] == '\t'))
1335*ce74bacaSMatthew Dillon 				break; /* done */
1336*ce74bacaSMatthew Dillon 			else if (quote != 0 && s[i] == quote)
1337*ce74bacaSMatthew Dillon 				break; /* done */
1338*ce74bacaSMatthew Dillon 			else
1339*ce74bacaSMatthew Dillon 				arg[j++] = s[i];
1340*ce74bacaSMatthew Dillon 		}
1341*ce74bacaSMatthew Dillon 		if (s[i] == '\0') {
1342*ce74bacaSMatthew Dillon 			if (quote != 0) {
1343*ce74bacaSMatthew Dillon 				/* Ran out of string looking for close quote */
1344*ce74bacaSMatthew Dillon 				r = SSH_ERR_INVALID_FORMAT;
1345*ce74bacaSMatthew Dillon 				goto out;
1346*ce74bacaSMatthew Dillon 			}
1347*ce74bacaSMatthew Dillon 			break;
1348*ce74bacaSMatthew Dillon 		}
1349*ce74bacaSMatthew Dillon 	}
1350*ce74bacaSMatthew Dillon 	/* Success */
1351*ce74bacaSMatthew Dillon 	*argcp = argc;
1352*ce74bacaSMatthew Dillon 	*argvp = argv;
1353*ce74bacaSMatthew Dillon 	argc = 0;
1354*ce74bacaSMatthew Dillon 	argv = NULL;
1355*ce74bacaSMatthew Dillon 	r = 0;
1356*ce74bacaSMatthew Dillon  out:
1357*ce74bacaSMatthew Dillon 	if (argc != 0 && argv != NULL) {
1358*ce74bacaSMatthew Dillon 		for (i = 0; i < argc; i++)
1359*ce74bacaSMatthew Dillon 			free(argv[i]);
1360*ce74bacaSMatthew Dillon 		free(argv);
1361*ce74bacaSMatthew Dillon 	}
1362*ce74bacaSMatthew Dillon 	return r;
1363*ce74bacaSMatthew Dillon }
1364*ce74bacaSMatthew Dillon 
1365*ce74bacaSMatthew Dillon /*
1366*ce74bacaSMatthew Dillon  * Reassemble an argument vector into a string, quoting and escaping as
1367*ce74bacaSMatthew Dillon  * necessary. Caller must free returned string.
1368*ce74bacaSMatthew Dillon  */
1369*ce74bacaSMatthew Dillon char *
1370*ce74bacaSMatthew Dillon argv_assemble(int argc, char **argv)
1371*ce74bacaSMatthew Dillon {
1372*ce74bacaSMatthew Dillon 	int i, j, ws, r;
1373*ce74bacaSMatthew Dillon 	char c, *ret;
1374*ce74bacaSMatthew Dillon 	struct sshbuf *buf, *arg;
1375*ce74bacaSMatthew Dillon 
1376*ce74bacaSMatthew Dillon 	if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL)
1377*ce74bacaSMatthew Dillon 		fatal("%s: sshbuf_new failed", __func__);
1378*ce74bacaSMatthew Dillon 
1379*ce74bacaSMatthew Dillon 	for (i = 0; i < argc; i++) {
1380*ce74bacaSMatthew Dillon 		ws = 0;
1381*ce74bacaSMatthew Dillon 		sshbuf_reset(arg);
1382*ce74bacaSMatthew Dillon 		for (j = 0; argv[i][j] != '\0'; j++) {
1383*ce74bacaSMatthew Dillon 			r = 0;
1384*ce74bacaSMatthew Dillon 			c = argv[i][j];
1385*ce74bacaSMatthew Dillon 			switch (c) {
1386*ce74bacaSMatthew Dillon 			case ' ':
1387*ce74bacaSMatthew Dillon 			case '\t':
1388*ce74bacaSMatthew Dillon 				ws = 1;
1389*ce74bacaSMatthew Dillon 				r = sshbuf_put_u8(arg, c);
1390*ce74bacaSMatthew Dillon 				break;
1391*ce74bacaSMatthew Dillon 			case '\\':
1392*ce74bacaSMatthew Dillon 			case '\'':
1393*ce74bacaSMatthew Dillon 			case '"':
1394*ce74bacaSMatthew Dillon 				if ((r = sshbuf_put_u8(arg, '\\')) != 0)
1395*ce74bacaSMatthew Dillon 					break;
1396*ce74bacaSMatthew Dillon 				/* FALLTHROUGH */
1397*ce74bacaSMatthew Dillon 			default:
1398*ce74bacaSMatthew Dillon 				r = sshbuf_put_u8(arg, c);
1399*ce74bacaSMatthew Dillon 				break;
1400*ce74bacaSMatthew Dillon 			}
1401*ce74bacaSMatthew Dillon 			if (r != 0)
1402*ce74bacaSMatthew Dillon 				fatal("%s: sshbuf_put_u8: %s",
1403*ce74bacaSMatthew Dillon 				    __func__, ssh_err(r));
1404*ce74bacaSMatthew Dillon 		}
1405*ce74bacaSMatthew Dillon 		if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) ||
1406*ce74bacaSMatthew Dillon 		    (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) ||
1407*ce74bacaSMatthew Dillon 		    (r = sshbuf_putb(buf, arg)) != 0 ||
1408*ce74bacaSMatthew Dillon 		    (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0))
1409*ce74bacaSMatthew Dillon 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
1410*ce74bacaSMatthew Dillon 	}
1411*ce74bacaSMatthew Dillon 	if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL)
1412*ce74bacaSMatthew Dillon 		fatal("%s: malloc failed", __func__);
1413*ce74bacaSMatthew Dillon 	memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf));
1414*ce74bacaSMatthew Dillon 	ret[sshbuf_len(buf)] = '\0';
1415*ce74bacaSMatthew Dillon 	sshbuf_free(buf);
1416*ce74bacaSMatthew Dillon 	sshbuf_free(arg);
1417*ce74bacaSMatthew Dillon 	return ret;
1418*ce74bacaSMatthew Dillon }
1419*ce74bacaSMatthew Dillon 
1420*ce74bacaSMatthew Dillon /*
1421*ce74bacaSMatthew Dillon  * Runs command in a subprocess wuth a minimal environment.
1422*ce74bacaSMatthew Dillon  * Returns pid on success, 0 on failure.
1423*ce74bacaSMatthew Dillon  * The child stdout and stderr maybe captured, left attached or sent to
1424*ce74bacaSMatthew Dillon  * /dev/null depending on the contents of flags.
1425*ce74bacaSMatthew Dillon  * "tag" is prepended to log messages.
1426*ce74bacaSMatthew Dillon  * NB. "command" is only used for logging; the actual command executed is
1427*ce74bacaSMatthew Dillon  * av[0].
1428*ce74bacaSMatthew Dillon  */
1429*ce74bacaSMatthew Dillon pid_t
1430*ce74bacaSMatthew Dillon subprocess(const char *tag, struct passwd *pw, const char *command,
1431*ce74bacaSMatthew Dillon     int ac, char **av, FILE **child, u_int flags)
1432*ce74bacaSMatthew Dillon {
1433*ce74bacaSMatthew Dillon 	FILE *f = NULL;
1434*ce74bacaSMatthew Dillon 	struct stat st;
1435*ce74bacaSMatthew Dillon 	int fd, devnull, p[2], i;
1436*ce74bacaSMatthew Dillon 	pid_t pid;
1437*ce74bacaSMatthew Dillon 	char *cp, errmsg[512];
1438*ce74bacaSMatthew Dillon 	u_int envsize;
1439*ce74bacaSMatthew Dillon 	char **child_env;
1440*ce74bacaSMatthew Dillon 
1441*ce74bacaSMatthew Dillon 	if (child != NULL)
1442*ce74bacaSMatthew Dillon 		*child = NULL;
1443*ce74bacaSMatthew Dillon 
1444*ce74bacaSMatthew Dillon 	debug3("%s: %s command \"%s\" running as %s (flags 0x%x)", __func__,
1445*ce74bacaSMatthew Dillon 	    tag, command, pw->pw_name, flags);
1446*ce74bacaSMatthew Dillon 
1447*ce74bacaSMatthew Dillon 	/* Check consistency */
1448*ce74bacaSMatthew Dillon 	if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 &&
1449*ce74bacaSMatthew Dillon 	    (flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) {
1450*ce74bacaSMatthew Dillon 		error("%s: inconsistent flags", __func__);
1451*ce74bacaSMatthew Dillon 		return 0;
1452*ce74bacaSMatthew Dillon 	}
1453*ce74bacaSMatthew Dillon 	if (((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) != (child == NULL)) {
1454*ce74bacaSMatthew Dillon 		error("%s: inconsistent flags/output", __func__);
1455*ce74bacaSMatthew Dillon 		return 0;
1456*ce74bacaSMatthew Dillon 	}
1457*ce74bacaSMatthew Dillon 
1458*ce74bacaSMatthew Dillon 	/*
1459*ce74bacaSMatthew Dillon 	 * If executing an explicit binary, then verify the it exists
1460*ce74bacaSMatthew Dillon 	 * and appears safe-ish to execute
1461*ce74bacaSMatthew Dillon 	 */
1462*ce74bacaSMatthew Dillon 	if (*av[0] != '/') {
1463*ce74bacaSMatthew Dillon 		error("%s path is not absolute", tag);
1464*ce74bacaSMatthew Dillon 		return 0;
1465*ce74bacaSMatthew Dillon 	}
1466*ce74bacaSMatthew Dillon 	temporarily_use_uid(pw);
1467*ce74bacaSMatthew Dillon 	if (stat(av[0], &st) < 0) {
1468*ce74bacaSMatthew Dillon 		error("Could not stat %s \"%s\": %s", tag,
1469*ce74bacaSMatthew Dillon 		    av[0], strerror(errno));
1470*ce74bacaSMatthew Dillon 		restore_uid();
1471*ce74bacaSMatthew Dillon 		return 0;
1472*ce74bacaSMatthew Dillon 	}
1473*ce74bacaSMatthew Dillon 	if (safe_path(av[0], &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) {
1474*ce74bacaSMatthew Dillon 		error("Unsafe %s \"%s\": %s", tag, av[0], errmsg);
1475*ce74bacaSMatthew Dillon 		restore_uid();
1476*ce74bacaSMatthew Dillon 		return 0;
1477*ce74bacaSMatthew Dillon 	}
1478*ce74bacaSMatthew Dillon 	/* Prepare to keep the child's stdout if requested */
1479*ce74bacaSMatthew Dillon 	if (pipe(p) != 0) {
1480*ce74bacaSMatthew Dillon 		error("%s: pipe: %s", tag, strerror(errno));
1481*ce74bacaSMatthew Dillon 		restore_uid();
1482*ce74bacaSMatthew Dillon 		return 0;
1483*ce74bacaSMatthew Dillon 	}
1484*ce74bacaSMatthew Dillon 	restore_uid();
1485*ce74bacaSMatthew Dillon 
1486*ce74bacaSMatthew Dillon 	switch ((pid = fork())) {
1487*ce74bacaSMatthew Dillon 	case -1: /* error */
1488*ce74bacaSMatthew Dillon 		error("%s: fork: %s", tag, strerror(errno));
1489*ce74bacaSMatthew Dillon 		close(p[0]);
1490*ce74bacaSMatthew Dillon 		close(p[1]);
1491*ce74bacaSMatthew Dillon 		return 0;
1492*ce74bacaSMatthew Dillon 	case 0: /* child */
1493*ce74bacaSMatthew Dillon 		/* Prepare a minimal environment for the child. */
1494*ce74bacaSMatthew Dillon 		envsize = 5;
1495*ce74bacaSMatthew Dillon 		child_env = xcalloc(sizeof(*child_env), envsize);
1496*ce74bacaSMatthew Dillon 		child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH);
1497*ce74bacaSMatthew Dillon 		child_set_env(&child_env, &envsize, "USER", pw->pw_name);
1498*ce74bacaSMatthew Dillon 		child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name);
1499*ce74bacaSMatthew Dillon 		child_set_env(&child_env, &envsize, "HOME", pw->pw_dir);
1500*ce74bacaSMatthew Dillon 		if ((cp = getenv("LANG")) != NULL)
1501*ce74bacaSMatthew Dillon 			child_set_env(&child_env, &envsize, "LANG", cp);
1502*ce74bacaSMatthew Dillon 
1503*ce74bacaSMatthew Dillon 		for (i = 0; i < NSIG; i++)
1504*ce74bacaSMatthew Dillon 			signal(i, SIG_DFL);
1505*ce74bacaSMatthew Dillon 
1506*ce74bacaSMatthew Dillon 		if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
1507*ce74bacaSMatthew Dillon 			error("%s: open %s: %s", tag, _PATH_DEVNULL,
1508*ce74bacaSMatthew Dillon 			    strerror(errno));
1509*ce74bacaSMatthew Dillon 			_exit(1);
1510*ce74bacaSMatthew Dillon 		}
1511*ce74bacaSMatthew Dillon 		if (dup2(devnull, STDIN_FILENO) == -1) {
1512*ce74bacaSMatthew Dillon 			error("%s: dup2: %s", tag, strerror(errno));
1513*ce74bacaSMatthew Dillon 			_exit(1);
1514*ce74bacaSMatthew Dillon 		}
1515*ce74bacaSMatthew Dillon 
1516*ce74bacaSMatthew Dillon 		/* Set up stdout as requested; leave stderr in place for now. */
1517*ce74bacaSMatthew Dillon 		fd = -1;
1518*ce74bacaSMatthew Dillon 		if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0)
1519*ce74bacaSMatthew Dillon 			fd = p[1];
1520*ce74bacaSMatthew Dillon 		else if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0)
1521*ce74bacaSMatthew Dillon 			fd = devnull;
1522*ce74bacaSMatthew Dillon 		if (fd != -1 && dup2(fd, STDOUT_FILENO) == -1) {
1523*ce74bacaSMatthew Dillon 			error("%s: dup2: %s", tag, strerror(errno));
1524*ce74bacaSMatthew Dillon 			_exit(1);
1525*ce74bacaSMatthew Dillon 		}
1526*ce74bacaSMatthew Dillon 		closefrom(STDERR_FILENO + 1);
1527*ce74bacaSMatthew Dillon 
1528*ce74bacaSMatthew Dillon 		/* Don't use permanently_set_uid() here to avoid fatal() */
1529*ce74bacaSMatthew Dillon 		if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
1530*ce74bacaSMatthew Dillon 			error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid,
1531*ce74bacaSMatthew Dillon 			    strerror(errno));
1532*ce74bacaSMatthew Dillon 			_exit(1);
1533*ce74bacaSMatthew Dillon 		}
1534*ce74bacaSMatthew Dillon 		if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
1535*ce74bacaSMatthew Dillon 			error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid,
1536*ce74bacaSMatthew Dillon 			    strerror(errno));
1537*ce74bacaSMatthew Dillon 			_exit(1);
1538*ce74bacaSMatthew Dillon 		}
1539*ce74bacaSMatthew Dillon 		/* stdin is pointed to /dev/null at this point */
1540*ce74bacaSMatthew Dillon 		if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 &&
1541*ce74bacaSMatthew Dillon 		    dup2(STDIN_FILENO, STDERR_FILENO) == -1) {
1542*ce74bacaSMatthew Dillon 			error("%s: dup2: %s", tag, strerror(errno));
1543*ce74bacaSMatthew Dillon 			_exit(1);
1544*ce74bacaSMatthew Dillon 		}
1545*ce74bacaSMatthew Dillon 
1546*ce74bacaSMatthew Dillon 		execve(av[0], av, child_env);
1547*ce74bacaSMatthew Dillon 		error("%s exec \"%s\": %s", tag, command, strerror(errno));
1548*ce74bacaSMatthew Dillon 		_exit(127);
1549*ce74bacaSMatthew Dillon 	default: /* parent */
1550*ce74bacaSMatthew Dillon 		break;
1551*ce74bacaSMatthew Dillon 	}
1552*ce74bacaSMatthew Dillon 
1553*ce74bacaSMatthew Dillon 	close(p[1]);
1554*ce74bacaSMatthew Dillon 	if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0)
1555*ce74bacaSMatthew Dillon 		close(p[0]);
1556*ce74bacaSMatthew Dillon 	else if ((f = fdopen(p[0], "r")) == NULL) {
1557*ce74bacaSMatthew Dillon 		error("%s: fdopen: %s", tag, strerror(errno));
1558*ce74bacaSMatthew Dillon 		close(p[0]);
1559*ce74bacaSMatthew Dillon 		/* Don't leave zombie child */
1560*ce74bacaSMatthew Dillon 		kill(pid, SIGTERM);
1561*ce74bacaSMatthew Dillon 		while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
1562*ce74bacaSMatthew Dillon 			;
1563*ce74bacaSMatthew Dillon 		return 0;
1564*ce74bacaSMatthew Dillon 	}
1565*ce74bacaSMatthew Dillon 	/* Success */
1566*ce74bacaSMatthew Dillon 	debug3("%s: %s pid %ld", __func__, tag, (long)pid);
1567*ce74bacaSMatthew Dillon 	if (child != NULL)
1568*ce74bacaSMatthew Dillon 		*child = f;
1569*ce74bacaSMatthew Dillon 	return pid;
1570*ce74bacaSMatthew Dillon }
1571*ce74bacaSMatthew Dillon 
1572*ce74bacaSMatthew Dillon /* Returns 0 if pid exited cleanly, non-zero otherwise */
1573*ce74bacaSMatthew Dillon int
1574*ce74bacaSMatthew Dillon exited_cleanly(pid_t pid, const char *tag, const char *cmd, int quiet)
1575*ce74bacaSMatthew Dillon {
1576*ce74bacaSMatthew Dillon 	int status;
1577*ce74bacaSMatthew Dillon 
1578*ce74bacaSMatthew Dillon 	while (waitpid(pid, &status, 0) == -1) {
1579*ce74bacaSMatthew Dillon 		if (errno != EINTR) {
1580*ce74bacaSMatthew Dillon 			error("%s: waitpid: %s", tag, strerror(errno));
1581*ce74bacaSMatthew Dillon 			return -1;
1582*ce74bacaSMatthew Dillon 		}
1583*ce74bacaSMatthew Dillon 	}
1584*ce74bacaSMatthew Dillon 	if (WIFSIGNALED(status)) {
1585*ce74bacaSMatthew Dillon 		error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status));
1586*ce74bacaSMatthew Dillon 		return -1;
1587*ce74bacaSMatthew Dillon 	} else if (WEXITSTATUS(status) != 0) {
1588*ce74bacaSMatthew Dillon 		do_log2(quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO,
1589*ce74bacaSMatthew Dillon 		    "%s %s failed, status %d", tag, cmd, WEXITSTATUS(status));
1590*ce74bacaSMatthew Dillon 		return -1;
1591*ce74bacaSMatthew Dillon 	}
1592*ce74bacaSMatthew Dillon 	return 0;
1593*ce74bacaSMatthew Dillon }
1594*ce74bacaSMatthew Dillon 
1595*ce74bacaSMatthew Dillon /*
1596*ce74bacaSMatthew Dillon  * Check a given path for security. This is defined as all components
1597*ce74bacaSMatthew Dillon  * of the path to the file must be owned by either the owner of
1598*ce74bacaSMatthew Dillon  * of the file or root and no directories must be group or world writable.
1599*ce74bacaSMatthew Dillon  *
1600*ce74bacaSMatthew Dillon  * XXX Should any specific check be done for sym links ?
1601*ce74bacaSMatthew Dillon  *
1602*ce74bacaSMatthew Dillon  * Takes a file name, its stat information (preferably from fstat() to
1603*ce74bacaSMatthew Dillon  * avoid races), the uid of the expected owner, their home directory and an
1604*ce74bacaSMatthew Dillon  * error buffer plus max size as arguments.
1605*ce74bacaSMatthew Dillon  *
1606*ce74bacaSMatthew Dillon  * Returns 0 on success and -1 on failure
1607*ce74bacaSMatthew Dillon  */
1608*ce74bacaSMatthew Dillon int
1609*ce74bacaSMatthew Dillon safe_path(const char *name, struct stat *stp, const char *pw_dir,
1610*ce74bacaSMatthew Dillon     uid_t uid, char *err, size_t errlen)
1611*ce74bacaSMatthew Dillon {
1612*ce74bacaSMatthew Dillon 	char buf[PATH_MAX], homedir[PATH_MAX];
1613*ce74bacaSMatthew Dillon 	char *cp;
1614*ce74bacaSMatthew Dillon 	int comparehome = 0;
1615*ce74bacaSMatthew Dillon 	struct stat st;
1616*ce74bacaSMatthew Dillon 
1617*ce74bacaSMatthew Dillon 	if (realpath(name, buf) == NULL) {
1618*ce74bacaSMatthew Dillon 		snprintf(err, errlen, "realpath %s failed: %s", name,
1619*ce74bacaSMatthew Dillon 		    strerror(errno));
1620*ce74bacaSMatthew Dillon 		return -1;
1621*ce74bacaSMatthew Dillon 	}
1622*ce74bacaSMatthew Dillon 	if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
1623*ce74bacaSMatthew Dillon 		comparehome = 1;
1624*ce74bacaSMatthew Dillon 
1625*ce74bacaSMatthew Dillon 	if (!S_ISREG(stp->st_mode)) {
1626*ce74bacaSMatthew Dillon 		snprintf(err, errlen, "%s is not a regular file", buf);
1627*ce74bacaSMatthew Dillon 		return -1;
1628*ce74bacaSMatthew Dillon 	}
1629*ce74bacaSMatthew Dillon 	if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
1630*ce74bacaSMatthew Dillon 	    (stp->st_mode & 022) != 0) {
1631*ce74bacaSMatthew Dillon 		snprintf(err, errlen, "bad ownership or modes for file %s",
1632*ce74bacaSMatthew Dillon 		    buf);
1633*ce74bacaSMatthew Dillon 		return -1;
1634*ce74bacaSMatthew Dillon 	}
1635*ce74bacaSMatthew Dillon 
1636*ce74bacaSMatthew Dillon 	/* for each component of the canonical path, walking upwards */
1637*ce74bacaSMatthew Dillon 	for (;;) {
1638*ce74bacaSMatthew Dillon 		if ((cp = dirname(buf)) == NULL) {
1639*ce74bacaSMatthew Dillon 			snprintf(err, errlen, "dirname() failed");
1640*ce74bacaSMatthew Dillon 			return -1;
1641*ce74bacaSMatthew Dillon 		}
1642*ce74bacaSMatthew Dillon 		strlcpy(buf, cp, sizeof(buf));
1643*ce74bacaSMatthew Dillon 
1644*ce74bacaSMatthew Dillon 		if (stat(buf, &st) < 0 ||
1645*ce74bacaSMatthew Dillon 		    (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) ||
1646*ce74bacaSMatthew Dillon 		    (st.st_mode & 022) != 0) {
1647*ce74bacaSMatthew Dillon 			snprintf(err, errlen,
1648*ce74bacaSMatthew Dillon 			    "bad ownership or modes for directory %s", buf);
1649*ce74bacaSMatthew Dillon 			return -1;
1650*ce74bacaSMatthew Dillon 		}
1651*ce74bacaSMatthew Dillon 
1652*ce74bacaSMatthew Dillon 		/* If are past the homedir then we can stop */
1653*ce74bacaSMatthew Dillon 		if (comparehome && strcmp(homedir, buf) == 0)
1654*ce74bacaSMatthew Dillon 			break;
1655*ce74bacaSMatthew Dillon 
1656*ce74bacaSMatthew Dillon 		/*
1657*ce74bacaSMatthew Dillon 		 * dirname should always complete with a "/" path,
1658*ce74bacaSMatthew Dillon 		 * but we can be paranoid and check for "." too
1659*ce74bacaSMatthew Dillon 		 */
1660*ce74bacaSMatthew Dillon 		if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
1661*ce74bacaSMatthew Dillon 			break;
1662*ce74bacaSMatthew Dillon 	}
1663*ce74bacaSMatthew Dillon 	return 0;
1664*ce74bacaSMatthew Dillon }
1665*ce74bacaSMatthew Dillon 
1666*ce74bacaSMatthew Dillon /*
1667*ce74bacaSMatthew Dillon  * Version of safe_path() that accepts an open file descriptor to
1668*ce74bacaSMatthew Dillon  * avoid races.
1669*ce74bacaSMatthew Dillon  *
1670*ce74bacaSMatthew Dillon  * Returns 0 on success and -1 on failure
1671*ce74bacaSMatthew Dillon  */
1672*ce74bacaSMatthew Dillon int
1673*ce74bacaSMatthew Dillon safe_path_fd(int fd, const char *file, struct passwd *pw,
1674*ce74bacaSMatthew Dillon     char *err, size_t errlen)
1675*ce74bacaSMatthew Dillon {
1676*ce74bacaSMatthew Dillon 	struct stat st;
1677*ce74bacaSMatthew Dillon 
1678*ce74bacaSMatthew Dillon 	/* check the open file to avoid races */
1679*ce74bacaSMatthew Dillon 	if (fstat(fd, &st) < 0) {
1680*ce74bacaSMatthew Dillon 		snprintf(err, errlen, "cannot stat file %s: %s",
1681*ce74bacaSMatthew Dillon 		    file, strerror(errno));
1682*ce74bacaSMatthew Dillon 		return -1;
1683*ce74bacaSMatthew Dillon 	}
1684*ce74bacaSMatthew Dillon 	return safe_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
1685*ce74bacaSMatthew Dillon }
1686*ce74bacaSMatthew Dillon 
1687*ce74bacaSMatthew Dillon /*
1688*ce74bacaSMatthew Dillon  * Sets the value of the given variable in the environment.  If the variable
1689*ce74bacaSMatthew Dillon  * already exists, its value is overridden.
1690*ce74bacaSMatthew Dillon  */
1691*ce74bacaSMatthew Dillon void
1692*ce74bacaSMatthew Dillon child_set_env(char ***envp, u_int *envsizep, const char *name,
1693*ce74bacaSMatthew Dillon 	const char *value)
1694*ce74bacaSMatthew Dillon {
1695*ce74bacaSMatthew Dillon 	char **env;
1696*ce74bacaSMatthew Dillon 	u_int envsize;
1697*ce74bacaSMatthew Dillon 	u_int i, namelen;
1698*ce74bacaSMatthew Dillon 
1699*ce74bacaSMatthew Dillon 	if (strchr(name, '=') != NULL) {
1700*ce74bacaSMatthew Dillon 		error("Invalid environment variable \"%.100s\"", name);
1701*ce74bacaSMatthew Dillon 		return;
1702*ce74bacaSMatthew Dillon 	}
1703*ce74bacaSMatthew Dillon 
1704*ce74bacaSMatthew Dillon 	/*
1705*ce74bacaSMatthew Dillon 	 * If we're passed an uninitialized list, allocate a single null
1706*ce74bacaSMatthew Dillon 	 * entry before continuing.
1707*ce74bacaSMatthew Dillon 	 */
1708*ce74bacaSMatthew Dillon 	if (*envp == NULL && *envsizep == 0) {
1709*ce74bacaSMatthew Dillon 		*envp = xmalloc(sizeof(char *));
1710*ce74bacaSMatthew Dillon 		*envp[0] = NULL;
1711*ce74bacaSMatthew Dillon 		*envsizep = 1;
1712*ce74bacaSMatthew Dillon 	}
1713*ce74bacaSMatthew Dillon 
1714*ce74bacaSMatthew Dillon 	/*
1715*ce74bacaSMatthew Dillon 	 * Find the slot where the value should be stored.  If the variable
1716*ce74bacaSMatthew Dillon 	 * already exists, we reuse the slot; otherwise we append a new slot
1717*ce74bacaSMatthew Dillon 	 * at the end of the array, expanding if necessary.
1718*ce74bacaSMatthew Dillon 	 */
1719*ce74bacaSMatthew Dillon 	env = *envp;
1720*ce74bacaSMatthew Dillon 	namelen = strlen(name);
1721*ce74bacaSMatthew Dillon 	for (i = 0; env[i]; i++)
1722*ce74bacaSMatthew Dillon 		if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
1723*ce74bacaSMatthew Dillon 			break;
1724*ce74bacaSMatthew Dillon 	if (env[i]) {
1725*ce74bacaSMatthew Dillon 		/* Reuse the slot. */
1726*ce74bacaSMatthew Dillon 		free(env[i]);
1727*ce74bacaSMatthew Dillon 	} else {
1728*ce74bacaSMatthew Dillon 		/* New variable.  Expand if necessary. */
1729*ce74bacaSMatthew Dillon 		envsize = *envsizep;
1730*ce74bacaSMatthew Dillon 		if (i >= envsize - 1) {
1731*ce74bacaSMatthew Dillon 			if (envsize >= 1000)
1732*ce74bacaSMatthew Dillon 				fatal("child_set_env: too many env vars");
1733*ce74bacaSMatthew Dillon 			envsize += 50;
1734*ce74bacaSMatthew Dillon 			env = (*envp) = xreallocarray(env, envsize, sizeof(char *));
1735*ce74bacaSMatthew Dillon 			*envsizep = envsize;
1736*ce74bacaSMatthew Dillon 		}
1737*ce74bacaSMatthew Dillon 		/* Need to set the NULL pointer at end of array beyond the new slot. */
1738*ce74bacaSMatthew Dillon 		env[i + 1] = NULL;
1739*ce74bacaSMatthew Dillon 	}
1740*ce74bacaSMatthew Dillon 
1741*ce74bacaSMatthew Dillon 	/* Allocate space and format the variable in the appropriate slot. */
1742*ce74bacaSMatthew Dillon 	env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
1743*ce74bacaSMatthew Dillon 	snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
1744*ce74bacaSMatthew Dillon }
1745*ce74bacaSMatthew Dillon 
1746