misc.c revision 240075
1240075Sdes/* $OpenBSD: misc.c,v 1.86 2011/09/05 05:59:08 djm Exp $ */
2224638Sbrooks/* $FreeBSD: head/crypto/openssh/misc.c 240075 2012-09-03 16:51:41Z des $ */
376259Sgreen/*
476259Sgreen * Copyright (c) 2000 Markus Friedl.  All rights reserved.
5162852Sdes * Copyright (c) 2005,2006 Damien Miller.  All rights reserved.
676259Sgreen *
776259Sgreen * Redistribution and use in source and binary forms, with or without
876259Sgreen * modification, are permitted provided that the following conditions
976259Sgreen * are met:
1076259Sgreen * 1. Redistributions of source code must retain the above copyright
1176259Sgreen *    notice, this list of conditions and the following disclaimer.
1276259Sgreen * 2. Redistributions in binary form must reproduce the above copyright
1376259Sgreen *    notice, this list of conditions and the following disclaimer in the
1476259Sgreen *    documentation and/or other materials provided with the distribution.
1576259Sgreen *
1676259Sgreen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1776259Sgreen * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1876259Sgreen * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1976259Sgreen * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2076259Sgreen * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2176259Sgreen * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2276259Sgreen * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2376259Sgreen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2476259Sgreen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2576259Sgreen * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2676259Sgreen */
2776259Sgreen
2876259Sgreen#include "includes.h"
2976259Sgreen
30162852Sdes#include <sys/types.h>
31162852Sdes#include <sys/ioctl.h>
32162852Sdes#include <sys/socket.h>
33162852Sdes#include <sys/param.h>
34162852Sdes
35162852Sdes#include <stdarg.h>
36162852Sdes#include <stdio.h>
37162852Sdes#include <stdlib.h>
38162852Sdes#include <string.h>
39221420Sdes#include <time.h>
40162852Sdes#include <unistd.h>
41162852Sdes
42162852Sdes#include <netinet/in.h>
43221420Sdes#include <netinet/in_systm.h>
44221420Sdes#include <netinet/ip.h>
45162852Sdes#include <netinet/tcp.h>
46162852Sdes
47162852Sdes#include <errno.h>
48162852Sdes#include <fcntl.h>
49181111Sdes#include <netdb.h>
50162852Sdes#ifdef HAVE_PATHS_H
51162852Sdes# include <paths.h>
52162852Sdes#include <pwd.h>
53162852Sdes#endif
54157016Sdes#ifdef SSH_TUN_OPENBSD
55157016Sdes#include <net/if.h>
56157016Sdes#endif
57157016Sdes
58162852Sdes#include "xmalloc.h"
5976259Sgreen#include "misc.h"
6076259Sgreen#include "log.h"
61162852Sdes#include "ssh.h"
6276259Sgreen
6392555Sdes/* remove newline at end of string */
6476259Sgreenchar *
6576259Sgreenchop(char *s)
6676259Sgreen{
6776259Sgreen	char *t = s;
6876259Sgreen	while (*t) {
6992555Sdes		if (*t == '\n' || *t == '\r') {
7076259Sgreen			*t = '\0';
7176259Sgreen			return s;
7276259Sgreen		}
7376259Sgreen		t++;
7476259Sgreen	}
7576259Sgreen	return s;
7676259Sgreen
7776259Sgreen}
7876259Sgreen
7992555Sdes/* set/unset filedescriptor to non-blocking */
80137015Sdesint
8176259Sgreenset_nonblock(int fd)
8276259Sgreen{
8376259Sgreen	int val;
8492555Sdes
8576259Sgreen	val = fcntl(fd, F_GETFL, 0);
8676259Sgreen	if (val < 0) {
8776259Sgreen		error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
88137015Sdes		return (-1);
8976259Sgreen	}
9076259Sgreen	if (val & O_NONBLOCK) {
91137015Sdes		debug3("fd %d is O_NONBLOCK", fd);
92137015Sdes		return (0);
9376259Sgreen	}
94124208Sdes	debug2("fd %d setting O_NONBLOCK", fd);
9576259Sgreen	val |= O_NONBLOCK;
96137015Sdes	if (fcntl(fd, F_SETFL, val) == -1) {
97137015Sdes		debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd,
98137015Sdes		    strerror(errno));
99137015Sdes		return (-1);
100137015Sdes	}
101137015Sdes	return (0);
10276259Sgreen}
10376259Sgreen
104137015Sdesint
10592555Sdesunset_nonblock(int fd)
10692555Sdes{
10792555Sdes	int val;
10892555Sdes
10992555Sdes	val = fcntl(fd, F_GETFL, 0);
11092555Sdes	if (val < 0) {
11192555Sdes		error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
112137015Sdes		return (-1);
11392555Sdes	}
11492555Sdes	if (!(val & O_NONBLOCK)) {
115137015Sdes		debug3("fd %d is not O_NONBLOCK", fd);
116137015Sdes		return (0);
11792555Sdes	}
11892555Sdes	debug("fd %d clearing O_NONBLOCK", fd);
11992555Sdes	val &= ~O_NONBLOCK;
120137015Sdes	if (fcntl(fd, F_SETFL, val) == -1) {
121137015Sdes		debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s",
12292555Sdes		    fd, strerror(errno));
123137015Sdes		return (-1);
124137015Sdes	}
125137015Sdes	return (0);
12692555Sdes}
12792555Sdes
128181111Sdesconst char *
129181111Sdesssh_gai_strerror(int gaierr)
130181111Sdes{
131181111Sdes	if (gaierr == EAI_SYSTEM)
132181111Sdes		return strerror(errno);
133181111Sdes	return gai_strerror(gaierr);
134181111Sdes}
135181111Sdes
13692555Sdes/* disable nagle on socket */
13792555Sdesvoid
13892555Sdesset_nodelay(int fd)
13992555Sdes{
14092555Sdes	int opt;
14192555Sdes	socklen_t optlen;
14292555Sdes
14392555Sdes	optlen = sizeof opt;
14492555Sdes	if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
145126274Sdes		debug("getsockopt TCP_NODELAY: %.100s", strerror(errno));
14692555Sdes		return;
14792555Sdes	}
14892555Sdes	if (opt == 1) {
14992555Sdes		debug2("fd %d is TCP_NODELAY", fd);
15092555Sdes		return;
15192555Sdes	}
15292555Sdes	opt = 1;
153113908Sdes	debug2("fd %d setting TCP_NODELAY", fd);
15492555Sdes	if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
15592555Sdes		error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
15692555Sdes}
15792555Sdes
15876259Sgreen/* Characters considered whitespace in strsep calls. */
15976259Sgreen#define WHITESPACE " \t\r\n"
160162852Sdes#define QUOTE	"\""
16176259Sgreen
16292555Sdes/* return next token in configuration line */
16376259Sgreenchar *
16476259Sgreenstrdelim(char **s)
16576259Sgreen{
16676259Sgreen	char *old;
16776259Sgreen	int wspace = 0;
16876259Sgreen
16976259Sgreen	if (*s == NULL)
17076259Sgreen		return NULL;
17176259Sgreen
17276259Sgreen	old = *s;
17376259Sgreen
174162852Sdes	*s = strpbrk(*s, WHITESPACE QUOTE "=");
17576259Sgreen	if (*s == NULL)
17676259Sgreen		return (old);
17776259Sgreen
178162852Sdes	if (*s[0] == '\"') {
179162852Sdes		memmove(*s, *s + 1, strlen(*s)); /* move nul too */
180162852Sdes		/* Find matching quote */
181162852Sdes		if ((*s = strpbrk(*s, QUOTE)) == NULL) {
182162852Sdes			return (NULL);		/* no matching quote */
183162852Sdes		} else {
184162852Sdes			*s[0] = '\0';
185215116Sdes			*s += strspn(*s + 1, WHITESPACE) + 1;
186162852Sdes			return (old);
187162852Sdes		}
188162852Sdes	}
189162852Sdes
19076259Sgreen	/* Allow only one '=' to be skipped */
19176259Sgreen	if (*s[0] == '=')
19276259Sgreen		wspace = 1;
19376259Sgreen	*s[0] = '\0';
19476259Sgreen
195162852Sdes	/* Skip any extra whitespace after first token */
19676259Sgreen	*s += strspn(*s + 1, WHITESPACE) + 1;
19776259Sgreen	if (*s[0] == '=' && !wspace)
19876259Sgreen		*s += strspn(*s + 1, WHITESPACE) + 1;
19976259Sgreen
20076259Sgreen	return (old);
20176259Sgreen}
20276259Sgreen
20376259Sgreenstruct passwd *
20476259Sgreenpwcopy(struct passwd *pw)
20576259Sgreen{
206162852Sdes	struct passwd *copy = xcalloc(1, sizeof(*copy));
20776259Sgreen
20876259Sgreen	copy->pw_name = xstrdup(pw->pw_name);
20976259Sgreen	copy->pw_passwd = xstrdup(pw->pw_passwd);
21076259Sgreen	copy->pw_gecos = xstrdup(pw->pw_gecos);
21176259Sgreen	copy->pw_uid = pw->pw_uid;
21276259Sgreen	copy->pw_gid = pw->pw_gid;
21398937Sdes#ifdef HAVE_PW_EXPIRE_IN_PASSWD
21492555Sdes	copy->pw_expire = pw->pw_expire;
21598937Sdes#endif
21698937Sdes#ifdef HAVE_PW_CHANGE_IN_PASSWD
21792555Sdes	copy->pw_change = pw->pw_change;
21898937Sdes#endif
21998937Sdes#ifdef HAVE_PW_CLASS_IN_PASSWD
22076259Sgreen	copy->pw_class = xstrdup(pw->pw_class);
22198937Sdes#endif
22276259Sgreen	copy->pw_dir = xstrdup(pw->pw_dir);
22376259Sgreen	copy->pw_shell = xstrdup(pw->pw_shell);
22476259Sgreen	return copy;
22576259Sgreen}
22676259Sgreen
22792555Sdes/*
22892555Sdes * Convert ASCII string to TCP/IP port number.
229192595Sdes * Port must be >=0 and <=65535.
230192595Sdes * Return -1 if invalid.
23192555Sdes */
23292555Sdesint
23392555Sdesa2port(const char *s)
23476259Sgreen{
235192595Sdes	long long port;
236192595Sdes	const char *errstr;
23776259Sgreen
238192595Sdes	port = strtonum(s, 0, 65535, &errstr);
239192595Sdes	if (errstr != NULL)
240192595Sdes		return -1;
241192595Sdes	return (int)port;
24276259Sgreen}
24392555Sdes
244157016Sdesint
245157016Sdesa2tun(const char *s, int *remote)
246157016Sdes{
247157016Sdes	const char *errstr = NULL;
248157016Sdes	char *sp, *ep;
249157016Sdes	int tun;
250157016Sdes
251157016Sdes	if (remote != NULL) {
252157016Sdes		*remote = SSH_TUNID_ANY;
253157016Sdes		sp = xstrdup(s);
254157016Sdes		if ((ep = strchr(sp, ':')) == NULL) {
255157016Sdes			xfree(sp);
256157016Sdes			return (a2tun(s, NULL));
257157016Sdes		}
258157016Sdes		ep[0] = '\0'; ep++;
259157016Sdes		*remote = a2tun(ep, NULL);
260157016Sdes		tun = a2tun(sp, NULL);
261157016Sdes		xfree(sp);
262157016Sdes		return (*remote == SSH_TUNID_ERR ? *remote : tun);
263157016Sdes	}
264157016Sdes
265157016Sdes	if (strcasecmp(s, "any") == 0)
266157016Sdes		return (SSH_TUNID_ANY);
267157016Sdes
268157016Sdes	tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr);
269157016Sdes	if (errstr != NULL)
270157016Sdes		return (SSH_TUNID_ERR);
271157016Sdes
272157016Sdes	return (tun);
273157016Sdes}
274157016Sdes
27592555Sdes#define SECONDS		1
27692555Sdes#define MINUTES		(SECONDS * 60)
27792555Sdes#define HOURS		(MINUTES * 60)
27892555Sdes#define DAYS		(HOURS * 24)
27992555Sdes#define WEEKS		(DAYS * 7)
28092555Sdes
28192555Sdes/*
28292555Sdes * Convert a time string into seconds; format is
28392555Sdes * a sequence of:
28492555Sdes *      time[qualifier]
28592555Sdes *
28692555Sdes * Valid time qualifiers are:
28792555Sdes *      <none>  seconds
28892555Sdes *      s|S     seconds
28992555Sdes *      m|M     minutes
29092555Sdes *      h|H     hours
29192555Sdes *      d|D     days
29292555Sdes *      w|W     weeks
29392555Sdes *
29492555Sdes * Examples:
29592555Sdes *      90m     90 minutes
29692555Sdes *      1h30m   90 minutes
29792555Sdes *      2d      2 days
29892555Sdes *      1w      1 week
29992555Sdes *
30092555Sdes * Return -1 if time string is invalid.
30192555Sdes */
30292555Sdeslong
30392555Sdesconvtime(const char *s)
30492555Sdes{
30592555Sdes	long total, secs;
30692555Sdes	const char *p;
30792555Sdes	char *endp;
30892555Sdes
30992555Sdes	errno = 0;
31092555Sdes	total = 0;
31192555Sdes	p = s;
31292555Sdes
31392555Sdes	if (p == NULL || *p == '\0')
31492555Sdes		return -1;
31592555Sdes
31692555Sdes	while (*p) {
31792555Sdes		secs = strtol(p, &endp, 10);
31892555Sdes		if (p == endp ||
31992555Sdes		    (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
32092555Sdes		    secs < 0)
32192555Sdes			return -1;
32292555Sdes
32392555Sdes		switch (*endp++) {
32492555Sdes		case '\0':
32592555Sdes			endp--;
326162852Sdes			break;
32792555Sdes		case 's':
32892555Sdes		case 'S':
32992555Sdes			break;
33092555Sdes		case 'm':
33192555Sdes		case 'M':
33292555Sdes			secs *= MINUTES;
33392555Sdes			break;
33492555Sdes		case 'h':
33592555Sdes		case 'H':
33692555Sdes			secs *= HOURS;
33792555Sdes			break;
33892555Sdes		case 'd':
33992555Sdes		case 'D':
34092555Sdes			secs *= DAYS;
34192555Sdes			break;
34292555Sdes		case 'w':
34392555Sdes		case 'W':
34492555Sdes			secs *= WEEKS;
34592555Sdes			break;
34692555Sdes		default:
34792555Sdes			return -1;
34892555Sdes		}
34992555Sdes		total += secs;
35092555Sdes		if (total < 0)
35192555Sdes			return -1;
35292555Sdes		p = endp;
35392555Sdes	}
35492555Sdes
35592555Sdes	return total;
35692555Sdes}
35792555Sdes
358146998Sdes/*
359162852Sdes * Returns a standardized host+port identifier string.
360162852Sdes * Caller must free returned string.
361162852Sdes */
362162852Sdeschar *
363162852Sdesput_host_port(const char *host, u_short port)
364162852Sdes{
365162852Sdes	char *hoststr;
366162852Sdes
367162852Sdes	if (port == 0 || port == SSH_DEFAULT_PORT)
368162852Sdes		return(xstrdup(host));
369162852Sdes	if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0)
370162852Sdes		fatal("put_host_port: asprintf: %s", strerror(errno));
371162852Sdes	debug3("put_host_port: %s", hoststr);
372162852Sdes	return hoststr;
373162852Sdes}
374162852Sdes
375162852Sdes/*
376146998Sdes * Search for next delimiter between hostnames/addresses and ports.
377146998Sdes * Argument may be modified (for termination).
378146998Sdes * Returns *cp if parsing succeeds.
379146998Sdes * *cp is set to the start of the next delimiter, if one was found.
380146998Sdes * If this is the last field, *cp is set to NULL.
381146998Sdes */
38292555Sdeschar *
383146998Sdeshpdelim(char **cp)
384146998Sdes{
385146998Sdes	char *s, *old;
386146998Sdes
387146998Sdes	if (cp == NULL || *cp == NULL)
388146998Sdes		return NULL;
389146998Sdes
390146998Sdes	old = s = *cp;
391146998Sdes	if (*s == '[') {
392146998Sdes		if ((s = strchr(s, ']')) == NULL)
393146998Sdes			return NULL;
394146998Sdes		else
395146998Sdes			s++;
396146998Sdes	} else if ((s = strpbrk(s, ":/")) == NULL)
397146998Sdes		s = *cp + strlen(*cp); /* skip to end (see first case below) */
398146998Sdes
399146998Sdes	switch (*s) {
400146998Sdes	case '\0':
401146998Sdes		*cp = NULL;	/* no more fields*/
402146998Sdes		break;
403147001Sdes
404146998Sdes	case ':':
405146998Sdes	case '/':
406146998Sdes		*s = '\0';	/* terminate */
407146998Sdes		*cp = s + 1;
408146998Sdes		break;
409147001Sdes
410146998Sdes	default:
411146998Sdes		return NULL;
412146998Sdes	}
413146998Sdes
414146998Sdes	return old;
415146998Sdes}
416146998Sdes
417146998Sdeschar *
41892555Sdescleanhostname(char *host)
41992555Sdes{
42092555Sdes	if (*host == '[' && host[strlen(host) - 1] == ']') {
42192555Sdes		host[strlen(host) - 1] = '\0';
42292555Sdes		return (host + 1);
42392555Sdes	} else
42492555Sdes		return host;
42592555Sdes}
42692555Sdes
42792555Sdeschar *
42892555Sdescolon(char *cp)
42992555Sdes{
43092555Sdes	int flag = 0;
43192555Sdes
43292555Sdes	if (*cp == ':')		/* Leading colon is part of file name. */
433215116Sdes		return NULL;
43492555Sdes	if (*cp == '[')
43592555Sdes		flag = 1;
43692555Sdes
43792555Sdes	for (; *cp; ++cp) {
43892555Sdes		if (*cp == '@' && *(cp+1) == '[')
43992555Sdes			flag = 1;
44092555Sdes		if (*cp == ']' && *(cp+1) == ':' && flag)
44192555Sdes			return (cp+1);
44292555Sdes		if (*cp == ':' && !flag)
44392555Sdes			return (cp);
44492555Sdes		if (*cp == '/')
445215116Sdes			return NULL;
44692555Sdes	}
447215116Sdes	return NULL;
44892555Sdes}
44992555Sdes
45092555Sdes/* function to assist building execv() arguments */
45192555Sdesvoid
45292555Sdesaddargs(arglist *args, char *fmt, ...)
45392555Sdes{
45492555Sdes	va_list ap;
455157016Sdes	char *cp;
456137015Sdes	u_int nalloc;
457157016Sdes	int r;
45892555Sdes
45992555Sdes	va_start(ap, fmt);
460157016Sdes	r = vasprintf(&cp, fmt, ap);
46192555Sdes	va_end(ap);
462157016Sdes	if (r == -1)
463157016Sdes		fatal("addargs: argument too long");
46492555Sdes
465120161Snectar	nalloc = args->nalloc;
46692555Sdes	if (args->list == NULL) {
467120161Snectar		nalloc = 32;
46892555Sdes		args->num = 0;
469120161Snectar	} else if (args->num+2 >= nalloc)
470120161Snectar		nalloc *= 2;
47192555Sdes
472162852Sdes	args->list = xrealloc(args->list, nalloc, sizeof(char *));
473120161Snectar	args->nalloc = nalloc;
474157016Sdes	args->list[args->num++] = cp;
47592555Sdes	args->list[args->num] = NULL;
47692555Sdes}
477146998Sdes
478157016Sdesvoid
479157016Sdesreplacearg(arglist *args, u_int which, char *fmt, ...)
480157016Sdes{
481157016Sdes	va_list ap;
482157016Sdes	char *cp;
483157016Sdes	int r;
484157016Sdes
485157016Sdes	va_start(ap, fmt);
486157016Sdes	r = vasprintf(&cp, fmt, ap);
487157016Sdes	va_end(ap);
488157016Sdes	if (r == -1)
489157016Sdes		fatal("replacearg: argument too long");
490157016Sdes
491157016Sdes	if (which >= args->num)
492157016Sdes		fatal("replacearg: tried to replace invalid arg %d >= %d",
493157016Sdes		    which, args->num);
494157016Sdes	xfree(args->list[which]);
495157016Sdes	args->list[which] = cp;
496157016Sdes}
497157016Sdes
498157016Sdesvoid
499157016Sdesfreeargs(arglist *args)
500157016Sdes{
501157016Sdes	u_int i;
502157016Sdes
503157016Sdes	if (args->list != NULL) {
504157016Sdes		for (i = 0; i < args->num; i++)
505157016Sdes			xfree(args->list[i]);
506157016Sdes		xfree(args->list);
507157016Sdes		args->nalloc = args->num = 0;
508157016Sdes		args->list = NULL;
509157016Sdes	}
510157016Sdes}
511157016Sdes
512146998Sdes/*
513149749Sdes * Expands tildes in the file name.  Returns data allocated by xmalloc.
514149749Sdes * Warning: this calls getpw*.
515149749Sdes */
516149749Sdeschar *
517149749Sdestilde_expand_filename(const char *filename, uid_t uid)
518149749Sdes{
519149749Sdes	const char *path;
520149749Sdes	char user[128], ret[MAXPATHLEN];
521149749Sdes	struct passwd *pw;
522149749Sdes	u_int len, slash;
523149749Sdes
524149749Sdes	if (*filename != '~')
525149749Sdes		return (xstrdup(filename));
526149749Sdes	filename++;
527149749Sdes
528149749Sdes	path = strchr(filename, '/');
529149749Sdes	if (path != NULL && path > filename) {		/* ~user/path */
530149749Sdes		slash = path - filename;
531149749Sdes		if (slash > sizeof(user) - 1)
532149749Sdes			fatal("tilde_expand_filename: ~username too long");
533149749Sdes		memcpy(user, filename, slash);
534149749Sdes		user[slash] = '\0';
535149749Sdes		if ((pw = getpwnam(user)) == NULL)
536149749Sdes			fatal("tilde_expand_filename: No such user %s", user);
537149749Sdes	} else if ((pw = getpwuid(uid)) == NULL)	/* ~/path */
538181111Sdes		fatal("tilde_expand_filename: No such uid %ld", (long)uid);
539149749Sdes
540149749Sdes	if (strlcpy(ret, pw->pw_dir, sizeof(ret)) >= sizeof(ret))
541149749Sdes		fatal("tilde_expand_filename: Path too long");
542149749Sdes
543149749Sdes	/* Make sure directory has a trailing '/' */
544149749Sdes	len = strlen(pw->pw_dir);
545149749Sdes	if ((len == 0 || pw->pw_dir[len - 1] != '/') &&
546149749Sdes	    strlcat(ret, "/", sizeof(ret)) >= sizeof(ret))
547149749Sdes		fatal("tilde_expand_filename: Path too long");
548149749Sdes
549149749Sdes	/* Skip leading '/' from specified path */
550149749Sdes	if (path != NULL)
551149749Sdes		filename = path + 1;
552149749Sdes	if (strlcat(ret, filename, sizeof(ret)) >= sizeof(ret))
553149749Sdes		fatal("tilde_expand_filename: Path too long");
554149749Sdes
555149749Sdes	return (xstrdup(ret));
556149749Sdes}
557149749Sdes
558149749Sdes/*
559149749Sdes * Expand a string with a set of %[char] escapes. A number of escapes may be
560149749Sdes * specified as (char *escape_chars, char *replacement) pairs. The list must
561149749Sdes * be terminated by a NULL escape_char. Returns replaced string in memory
562149749Sdes * allocated by xmalloc.
563149749Sdes */
564149749Sdeschar *
565149749Sdespercent_expand(const char *string, ...)
566149749Sdes{
567149749Sdes#define EXPAND_MAX_KEYS	16
568204917Sdes	u_int num_keys, i, j;
569149749Sdes	struct {
570149749Sdes		const char *key;
571149749Sdes		const char *repl;
572149749Sdes	} keys[EXPAND_MAX_KEYS];
573149749Sdes	char buf[4096];
574149749Sdes	va_list ap;
575149749Sdes
576149749Sdes	/* Gather keys */
577149749Sdes	va_start(ap, string);
578149749Sdes	for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
579149749Sdes		keys[num_keys].key = va_arg(ap, char *);
580149749Sdes		if (keys[num_keys].key == NULL)
581149749Sdes			break;
582149749Sdes		keys[num_keys].repl = va_arg(ap, char *);
583149749Sdes		if (keys[num_keys].repl == NULL)
584204917Sdes			fatal("%s: NULL replacement", __func__);
585149749Sdes	}
586204917Sdes	if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
587204917Sdes		fatal("%s: too many keys", __func__);
588149749Sdes	va_end(ap);
589149749Sdes
590149749Sdes	/* Expand string */
591149749Sdes	*buf = '\0';
592149749Sdes	for (i = 0; *string != '\0'; string++) {
593149749Sdes		if (*string != '%') {
594149749Sdes append:
595149749Sdes			buf[i++] = *string;
596149749Sdes			if (i >= sizeof(buf))
597204917Sdes				fatal("%s: string too long", __func__);
598149749Sdes			buf[i] = '\0';
599149749Sdes			continue;
600149749Sdes		}
601149749Sdes		string++;
602204917Sdes		/* %% case */
603149749Sdes		if (*string == '%')
604149749Sdes			goto append;
605149749Sdes		for (j = 0; j < num_keys; j++) {
606149749Sdes			if (strchr(keys[j].key, *string) != NULL) {
607149749Sdes				i = strlcat(buf, keys[j].repl, sizeof(buf));
608149749Sdes				if (i >= sizeof(buf))
609204917Sdes					fatal("%s: string too long", __func__);
610149749Sdes				break;
611149749Sdes			}
612149749Sdes		}
613149749Sdes		if (j >= num_keys)
614204917Sdes			fatal("%s: unknown key %%%c", __func__, *string);
615149749Sdes	}
616149749Sdes	return (xstrdup(buf));
617149749Sdes#undef EXPAND_MAX_KEYS
618149749Sdes}
619149749Sdes
620149749Sdes/*
621146998Sdes * Read an entire line from a public key file into a static buffer, discarding
622146998Sdes * lines that exceed the buffer size.  Returns 0 on success, -1 on failure.
623146998Sdes */
624146998Sdesint
625146998Sdesread_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
626146998Sdes   u_long *lineno)
627146998Sdes{
628146998Sdes	while (fgets(buf, bufsz, f) != NULL) {
629181111Sdes		if (buf[0] == '\0')
630181111Sdes			continue;
631146998Sdes		(*lineno)++;
632146998Sdes		if (buf[strlen(buf) - 1] == '\n' || feof(f)) {
633146998Sdes			return 0;
634146998Sdes		} else {
635146998Sdes			debug("%s: %s line %lu exceeds size limit", __func__,
636146998Sdes			    filename, *lineno);
637146998Sdes			/* discard remainder of line */
638147001Sdes			while (fgetc(f) != '\n' && !feof(f))
639146998Sdes				;	/* nothing */
640146998Sdes		}
641146998Sdes	}
642146998Sdes	return -1;
643146998Sdes}
644149749Sdes
645157016Sdesint
646157016Sdestun_open(int tun, int mode)
647157016Sdes{
648157016Sdes#if defined(CUSTOM_SYS_TUN_OPEN)
649157016Sdes	return (sys_tun_open(tun, mode));
650157016Sdes#elif defined(SSH_TUN_OPENBSD)
651157016Sdes	struct ifreq ifr;
652157016Sdes	char name[100];
653157016Sdes	int fd = -1, sock;
654157016Sdes
655157016Sdes	/* Open the tunnel device */
656157016Sdes	if (tun <= SSH_TUNID_MAX) {
657157016Sdes		snprintf(name, sizeof(name), "/dev/tun%d", tun);
658157016Sdes		fd = open(name, O_RDWR);
659157016Sdes	} else if (tun == SSH_TUNID_ANY) {
660157016Sdes		for (tun = 100; tun >= 0; tun--) {
661157016Sdes			snprintf(name, sizeof(name), "/dev/tun%d", tun);
662157016Sdes			if ((fd = open(name, O_RDWR)) >= 0)
663157016Sdes				break;
664157016Sdes		}
665157016Sdes	} else {
666157016Sdes		debug("%s: invalid tunnel %u", __func__, tun);
667157016Sdes		return (-1);
668157016Sdes	}
669157016Sdes
670157016Sdes	if (fd < 0) {
671157016Sdes		debug("%s: %s open failed: %s", __func__, name, strerror(errno));
672157016Sdes		return (-1);
673157016Sdes	}
674157016Sdes
675157016Sdes	debug("%s: %s mode %d fd %d", __func__, name, mode, fd);
676157016Sdes
677157016Sdes	/* Set the tunnel device operation mode */
678157016Sdes	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tun%d", tun);
679157016Sdes	if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
680157016Sdes		goto failed;
681157016Sdes
682157016Sdes	if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
683157016Sdes		goto failed;
684157016Sdes
685157016Sdes	/* Set interface mode */
686157016Sdes	ifr.ifr_flags &= ~IFF_UP;
687157016Sdes	if (mode == SSH_TUNMODE_ETHERNET)
688157016Sdes		ifr.ifr_flags |= IFF_LINK0;
689157016Sdes	else
690157016Sdes		ifr.ifr_flags &= ~IFF_LINK0;
691157016Sdes	if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
692157016Sdes		goto failed;
693157016Sdes
694157016Sdes	/* Bring interface up */
695157016Sdes	ifr.ifr_flags |= IFF_UP;
696157016Sdes	if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
697157016Sdes		goto failed;
698157016Sdes
699157016Sdes	close(sock);
700157016Sdes	return (fd);
701157016Sdes
702157016Sdes failed:
703157016Sdes	if (fd >= 0)
704157016Sdes		close(fd);
705157016Sdes	if (sock >= 0)
706157016Sdes		close(sock);
707157016Sdes	debug("%s: failed to set %s mode %d: %s", __func__, name,
708157016Sdes	    mode, strerror(errno));
709157016Sdes	return (-1);
710157016Sdes#else
711157016Sdes	error("Tunnel interfaces are not supported on this platform");
712157016Sdes	return (-1);
713157016Sdes#endif
714157016Sdes}
715157016Sdes
716157016Sdesvoid
717157016Sdessanitise_stdfd(void)
718157016Sdes{
719157016Sdes	int nullfd, dupfd;
720157016Sdes
721157016Sdes	if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
722192595Sdes		fprintf(stderr, "Couldn't open /dev/null: %s\n",
723192595Sdes		    strerror(errno));
724157016Sdes		exit(1);
725157016Sdes	}
726157016Sdes	while (++dupfd <= 2) {
727157016Sdes		/* Only clobber closed fds */
728157016Sdes		if (fcntl(dupfd, F_GETFL, 0) >= 0)
729157016Sdes			continue;
730157016Sdes		if (dup2(nullfd, dupfd) == -1) {
731192595Sdes			fprintf(stderr, "dup2: %s\n", strerror(errno));
732157016Sdes			exit(1);
733157016Sdes		}
734157016Sdes	}
735157016Sdes	if (nullfd > 2)
736157016Sdes		close(nullfd);
737157016Sdes}
738157016Sdes
739149749Sdeschar *
740162852Sdestohex(const void *vp, size_t l)
741149749Sdes{
742162852Sdes	const u_char *p = (const u_char *)vp;
743149749Sdes	char b[3], *r;
744162852Sdes	size_t i, hl;
745149749Sdes
746162852Sdes	if (l > 65536)
747162852Sdes		return xstrdup("tohex: length > 65536");
748162852Sdes
749149749Sdes	hl = l * 2 + 1;
750162852Sdes	r = xcalloc(1, hl);
751149749Sdes	for (i = 0; i < l; i++) {
752162852Sdes		snprintf(b, sizeof(b), "%02x", p[i]);
753149749Sdes		strlcat(r, b, hl);
754149749Sdes	}
755149749Sdes	return (r);
756149749Sdes}
757149749Sdes
758162852Sdesu_int64_t
759162852Sdesget_u64(const void *vp)
760162852Sdes{
761162852Sdes	const u_char *p = (const u_char *)vp;
762162852Sdes	u_int64_t v;
763162852Sdes
764162852Sdes	v  = (u_int64_t)p[0] << 56;
765162852Sdes	v |= (u_int64_t)p[1] << 48;
766162852Sdes	v |= (u_int64_t)p[2] << 40;
767162852Sdes	v |= (u_int64_t)p[3] << 32;
768162852Sdes	v |= (u_int64_t)p[4] << 24;
769162852Sdes	v |= (u_int64_t)p[5] << 16;
770162852Sdes	v |= (u_int64_t)p[6] << 8;
771162852Sdes	v |= (u_int64_t)p[7];
772162852Sdes
773162852Sdes	return (v);
774162852Sdes}
775162852Sdes
776162852Sdesu_int32_t
777162852Sdesget_u32(const void *vp)
778162852Sdes{
779162852Sdes	const u_char *p = (const u_char *)vp;
780162852Sdes	u_int32_t v;
781162852Sdes
782162852Sdes	v  = (u_int32_t)p[0] << 24;
783162852Sdes	v |= (u_int32_t)p[1] << 16;
784162852Sdes	v |= (u_int32_t)p[2] << 8;
785162852Sdes	v |= (u_int32_t)p[3];
786162852Sdes
787162852Sdes	return (v);
788162852Sdes}
789162852Sdes
790162852Sdesu_int16_t
791162852Sdesget_u16(const void *vp)
792162852Sdes{
793162852Sdes	const u_char *p = (const u_char *)vp;
794162852Sdes	u_int16_t v;
795162852Sdes
796162852Sdes	v  = (u_int16_t)p[0] << 8;
797162852Sdes	v |= (u_int16_t)p[1];
798162852Sdes
799162852Sdes	return (v);
800162852Sdes}
801162852Sdes
802162852Sdesvoid
803162852Sdesput_u64(void *vp, u_int64_t v)
804162852Sdes{
805162852Sdes	u_char *p = (u_char *)vp;
806162852Sdes
807162852Sdes	p[0] = (u_char)(v >> 56) & 0xff;
808162852Sdes	p[1] = (u_char)(v >> 48) & 0xff;
809162852Sdes	p[2] = (u_char)(v >> 40) & 0xff;
810162852Sdes	p[3] = (u_char)(v >> 32) & 0xff;
811162852Sdes	p[4] = (u_char)(v >> 24) & 0xff;
812162852Sdes	p[5] = (u_char)(v >> 16) & 0xff;
813162852Sdes	p[6] = (u_char)(v >> 8) & 0xff;
814162852Sdes	p[7] = (u_char)v & 0xff;
815162852Sdes}
816162852Sdes
817162852Sdesvoid
818162852Sdesput_u32(void *vp, u_int32_t v)
819162852Sdes{
820162852Sdes	u_char *p = (u_char *)vp;
821162852Sdes
822162852Sdes	p[0] = (u_char)(v >> 24) & 0xff;
823162852Sdes	p[1] = (u_char)(v >> 16) & 0xff;
824162852Sdes	p[2] = (u_char)(v >> 8) & 0xff;
825162852Sdes	p[3] = (u_char)v & 0xff;
826162852Sdes}
827162852Sdes
828162852Sdes
829162852Sdesvoid
830162852Sdesput_u16(void *vp, u_int16_t v)
831162852Sdes{
832162852Sdes	u_char *p = (u_char *)vp;
833162852Sdes
834162852Sdes	p[0] = (u_char)(v >> 8) & 0xff;
835162852Sdes	p[1] = (u_char)v & 0xff;
836162852Sdes}
837181111Sdes
838181111Sdesvoid
839181111Sdesms_subtract_diff(struct timeval *start, int *ms)
840181111Sdes{
841181111Sdes	struct timeval diff, finish;
842181111Sdes
843181111Sdes	gettimeofday(&finish, NULL);
844181111Sdes	timersub(&finish, start, &diff);
845181111Sdes	*ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
846181111Sdes}
847181111Sdes
848181111Sdesvoid
849181111Sdesms_to_timeval(struct timeval *tv, int ms)
850181111Sdes{
851181111Sdes	if (ms < 0)
852181111Sdes		ms = 0;
853181111Sdes	tv->tv_sec = ms / 1000;
854181111Sdes	tv->tv_usec = (ms % 1000) * 1000;
855181111Sdes}
856181111Sdes
857221420Sdesvoid
858221420Sdesbandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen)
859221420Sdes{
860221420Sdes	bw->buflen = buflen;
861221420Sdes	bw->rate = kbps;
862221420Sdes	bw->thresh = bw->rate;
863221420Sdes	bw->lamt = 0;
864221420Sdes	timerclear(&bw->bwstart);
865221420Sdes	timerclear(&bw->bwend);
866221420Sdes}
867221420Sdes
868221420Sdes/* Callback from read/write loop to insert bandwidth-limiting delays */
869221420Sdesvoid
870221420Sdesbandwidth_limit(struct bwlimit *bw, size_t read_len)
871221420Sdes{
872221420Sdes	u_int64_t waitlen;
873221420Sdes	struct timespec ts, rm;
874221420Sdes
875221420Sdes	if (!timerisset(&bw->bwstart)) {
876221420Sdes		gettimeofday(&bw->bwstart, NULL);
877221420Sdes		return;
878221420Sdes	}
879221420Sdes
880221420Sdes	bw->lamt += read_len;
881221420Sdes	if (bw->lamt < bw->thresh)
882221420Sdes		return;
883221420Sdes
884221420Sdes	gettimeofday(&bw->bwend, NULL);
885221420Sdes	timersub(&bw->bwend, &bw->bwstart, &bw->bwend);
886221420Sdes	if (!timerisset(&bw->bwend))
887221420Sdes		return;
888221420Sdes
889221420Sdes	bw->lamt *= 8;
890221420Sdes	waitlen = (double)1000000L * bw->lamt / bw->rate;
891221420Sdes
892221420Sdes	bw->bwstart.tv_sec = waitlen / 1000000L;
893221420Sdes	bw->bwstart.tv_usec = waitlen % 1000000L;
894221420Sdes
895221420Sdes	if (timercmp(&bw->bwstart, &bw->bwend, >)) {
896221420Sdes		timersub(&bw->bwstart, &bw->bwend, &bw->bwend);
897221420Sdes
898221420Sdes		/* Adjust the wait time */
899221420Sdes		if (bw->bwend.tv_sec) {
900221420Sdes			bw->thresh /= 2;
901221420Sdes			if (bw->thresh < bw->buflen / 4)
902221420Sdes				bw->thresh = bw->buflen / 4;
903221420Sdes		} else if (bw->bwend.tv_usec < 10000) {
904221420Sdes			bw->thresh *= 2;
905221420Sdes			if (bw->thresh > bw->buflen * 8)
906221420Sdes				bw->thresh = bw->buflen * 8;
907221420Sdes		}
908221420Sdes
909221420Sdes		TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts);
910221420Sdes		while (nanosleep(&ts, &rm) == -1) {
911221420Sdes			if (errno != EINTR)
912221420Sdes				break;
913221420Sdes			ts = rm;
914221420Sdes		}
915221420Sdes	}
916221420Sdes
917221420Sdes	bw->lamt = 0;
918221420Sdes	gettimeofday(&bw->bwstart, NULL);
919221420Sdes}
920221420Sdes
921221420Sdes/* Make a template filename for mk[sd]temp() */
922221420Sdesvoid
923221420Sdesmktemp_proto(char *s, size_t len)
924221420Sdes{
925221420Sdes	const char *tmpdir;
926221420Sdes	int r;
927221420Sdes
928221420Sdes	if ((tmpdir = getenv("TMPDIR")) != NULL) {
929221420Sdes		r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir);
930221420Sdes		if (r > 0 && (size_t)r < len)
931221420Sdes			return;
932221420Sdes	}
933221420Sdes	r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX");
934221420Sdes	if (r < 0 || (size_t)r >= len)
935221420Sdes		fatal("%s: template string too short", __func__);
936221420Sdes}
937221420Sdes
938221420Sdesstatic const struct {
939221420Sdes	const char *name;
940221420Sdes	int value;
941221420Sdes} ipqos[] = {
942221420Sdes	{ "af11", IPTOS_DSCP_AF11 },
943221420Sdes	{ "af12", IPTOS_DSCP_AF12 },
944221420Sdes	{ "af13", IPTOS_DSCP_AF13 },
945240075Sdes	{ "af21", IPTOS_DSCP_AF21 },
946221420Sdes	{ "af22", IPTOS_DSCP_AF22 },
947221420Sdes	{ "af23", IPTOS_DSCP_AF23 },
948221420Sdes	{ "af31", IPTOS_DSCP_AF31 },
949221420Sdes	{ "af32", IPTOS_DSCP_AF32 },
950221420Sdes	{ "af33", IPTOS_DSCP_AF33 },
951221420Sdes	{ "af41", IPTOS_DSCP_AF41 },
952221420Sdes	{ "af42", IPTOS_DSCP_AF42 },
953221420Sdes	{ "af43", IPTOS_DSCP_AF43 },
954221420Sdes	{ "cs0", IPTOS_DSCP_CS0 },
955221420Sdes	{ "cs1", IPTOS_DSCP_CS1 },
956221420Sdes	{ "cs2", IPTOS_DSCP_CS2 },
957221420Sdes	{ "cs3", IPTOS_DSCP_CS3 },
958221420Sdes	{ "cs4", IPTOS_DSCP_CS4 },
959221420Sdes	{ "cs5", IPTOS_DSCP_CS5 },
960221420Sdes	{ "cs6", IPTOS_DSCP_CS6 },
961221420Sdes	{ "cs7", IPTOS_DSCP_CS7 },
962221420Sdes	{ "ef", IPTOS_DSCP_EF },
963221420Sdes	{ "lowdelay", IPTOS_LOWDELAY },
964221420Sdes	{ "throughput", IPTOS_THROUGHPUT },
965221420Sdes	{ "reliability", IPTOS_RELIABILITY },
966221420Sdes	{ NULL, -1 }
967221420Sdes};
968221420Sdes
969215116Sdesint
970221420Sdesparse_ipqos(const char *cp)
971215116Sdes{
972221420Sdes	u_int i;
973221420Sdes	char *ep;
974221420Sdes	long val;
975215116Sdes
976221420Sdes	if (cp == NULL)
977221420Sdes		return -1;
978221420Sdes	for (i = 0; ipqos[i].name != NULL; i++) {
979221420Sdes		if (strcasecmp(cp, ipqos[i].name) == 0)
980221420Sdes			return ipqos[i].value;
981221420Sdes	}
982221420Sdes	/* Try parsing as an integer */
983221420Sdes	val = strtol(cp, &ep, 0);
984221420Sdes	if (*cp == '\0' || *ep != '\0' || val < 0 || val > 255)
985221420Sdes		return -1;
986221420Sdes	return val;
987215116Sdes}
988221420Sdes
989226046Sdesconst char *
990226046Sdesiptos2str(int iptos)
991226046Sdes{
992226046Sdes	int i;
993226046Sdes	static char iptos_str[sizeof "0xff"];
994226046Sdes
995226046Sdes	for (i = 0; ipqos[i].name != NULL; i++) {
996226046Sdes		if (ipqos[i].value == iptos)
997226046Sdes			return ipqos[i].name;
998226046Sdes	}
999226046Sdes	snprintf(iptos_str, sizeof iptos_str, "0x%02x", iptos);
1000226046Sdes	return iptos_str;
1001226046Sdes}
1002204917Sdesvoid
1003204917Sdessock_set_v6only(int s)
1004204917Sdes{
1005204917Sdes#ifdef IPV6_V6ONLY
1006204917Sdes	int on = 1;
1007204917Sdes
1008204917Sdes	debug3("%s: set socket %d IPV6_V6ONLY", __func__, s);
1009204917Sdes	if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1)
1010204917Sdes		error("setsockopt IPV6_V6ONLY: %s", strerror(errno));
1011204917Sdes#endif
1012204917Sdes}
1013224638Sbrooks
1014224638Sbrooksvoid
1015224638Sbrookssock_get_rcvbuf(int *size, int rcvbuf)
1016224638Sbrooks{
1017224638Sbrooks	int sock, socksize;
1018224638Sbrooks	socklen_t socksizelen = sizeof(socksize);
1019224638Sbrooks
1020224638Sbrooks	/*
1021224638Sbrooks	 * Create a socket but do not connect it.  We use it
1022224638Sbrooks	 * only to get the rcv socket size.
1023224638Sbrooks	 */
1024224638Sbrooks	sock = socket(AF_INET6, SOCK_STREAM, 0);
1025224638Sbrooks	if (sock < 0)
1026224638Sbrooks		sock = socket(AF_INET, SOCK_STREAM, 0);
1027224638Sbrooks	if (sock < 0)
1028224638Sbrooks		return;
1029224638Sbrooks
1030224638Sbrooks	/*
1031224638Sbrooks	 * If the tcp_rcv_buf option is set and passed in, attempt to set the
1032224638Sbrooks	 *  buffer size to its value.
1033224638Sbrooks	 */
1034224638Sbrooks	if (rcvbuf)
1035224638Sbrooks		setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&rcvbuf,
1036224638Sbrooks		    sizeof(rcvbuf));
1037224638Sbrooks
1038224638Sbrooks	if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF,
1039224638Sbrooks	    &socksize, &socksizelen) == 0)
1040224638Sbrooks		if (size != NULL)
1041224638Sbrooks			*size = socksize;
1042224638Sbrooks	close(sock);
1043224638Sbrooks}
1044