1255767Sdes/* $OpenBSD: misc.c,v 1.91 2013/07/12 00:43:50 djm Exp $ */
2224638Sbrooks/* $FreeBSD$ */
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{
131255767Sdes	if (gaierr == EAI_SYSTEM && errno != 0)
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);
210255767Sdes#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
21176259Sgreen	copy->pw_gecos = xstrdup(pw->pw_gecos);
212255767Sdes#endif
21376259Sgreen	copy->pw_uid = pw->pw_uid;
21476259Sgreen	copy->pw_gid = pw->pw_gid;
215255767Sdes#ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
21692555Sdes	copy->pw_expire = pw->pw_expire;
21798937Sdes#endif
218255767Sdes#ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
21992555Sdes	copy->pw_change = pw->pw_change;
22098937Sdes#endif
221255767Sdes#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
22276259Sgreen	copy->pw_class = xstrdup(pw->pw_class);
22398937Sdes#endif
22476259Sgreen	copy->pw_dir = xstrdup(pw->pw_dir);
22576259Sgreen	copy->pw_shell = xstrdup(pw->pw_shell);
22676259Sgreen	return copy;
22776259Sgreen}
22876259Sgreen
22992555Sdes/*
23092555Sdes * Convert ASCII string to TCP/IP port number.
231192595Sdes * Port must be >=0 and <=65535.
232192595Sdes * Return -1 if invalid.
23392555Sdes */
23492555Sdesint
23592555Sdesa2port(const char *s)
23676259Sgreen{
237192595Sdes	long long port;
238192595Sdes	const char *errstr;
23976259Sgreen
240192595Sdes	port = strtonum(s, 0, 65535, &errstr);
241192595Sdes	if (errstr != NULL)
242192595Sdes		return -1;
243192595Sdes	return (int)port;
24476259Sgreen}
24592555Sdes
246157016Sdesint
247157016Sdesa2tun(const char *s, int *remote)
248157016Sdes{
249157016Sdes	const char *errstr = NULL;
250157016Sdes	char *sp, *ep;
251157016Sdes	int tun;
252157016Sdes
253157016Sdes	if (remote != NULL) {
254157016Sdes		*remote = SSH_TUNID_ANY;
255157016Sdes		sp = xstrdup(s);
256157016Sdes		if ((ep = strchr(sp, ':')) == NULL) {
257255767Sdes			free(sp);
258157016Sdes			return (a2tun(s, NULL));
259157016Sdes		}
260157016Sdes		ep[0] = '\0'; ep++;
261157016Sdes		*remote = a2tun(ep, NULL);
262157016Sdes		tun = a2tun(sp, NULL);
263255767Sdes		free(sp);
264157016Sdes		return (*remote == SSH_TUNID_ERR ? *remote : tun);
265157016Sdes	}
266157016Sdes
267157016Sdes	if (strcasecmp(s, "any") == 0)
268157016Sdes		return (SSH_TUNID_ANY);
269157016Sdes
270157016Sdes	tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr);
271157016Sdes	if (errstr != NULL)
272157016Sdes		return (SSH_TUNID_ERR);
273157016Sdes
274157016Sdes	return (tun);
275157016Sdes}
276157016Sdes
27792555Sdes#define SECONDS		1
27892555Sdes#define MINUTES		(SECONDS * 60)
27992555Sdes#define HOURS		(MINUTES * 60)
28092555Sdes#define DAYS		(HOURS * 24)
28192555Sdes#define WEEKS		(DAYS * 7)
28292555Sdes
28392555Sdes/*
28492555Sdes * Convert a time string into seconds; format is
28592555Sdes * a sequence of:
28692555Sdes *      time[qualifier]
28792555Sdes *
28892555Sdes * Valid time qualifiers are:
28992555Sdes *      <none>  seconds
29092555Sdes *      s|S     seconds
29192555Sdes *      m|M     minutes
29292555Sdes *      h|H     hours
29392555Sdes *      d|D     days
29492555Sdes *      w|W     weeks
29592555Sdes *
29692555Sdes * Examples:
29792555Sdes *      90m     90 minutes
29892555Sdes *      1h30m   90 minutes
29992555Sdes *      2d      2 days
30092555Sdes *      1w      1 week
30192555Sdes *
30292555Sdes * Return -1 if time string is invalid.
30392555Sdes */
30492555Sdeslong
30592555Sdesconvtime(const char *s)
30692555Sdes{
30792555Sdes	long total, secs;
30892555Sdes	const char *p;
30992555Sdes	char *endp;
31092555Sdes
31192555Sdes	errno = 0;
31292555Sdes	total = 0;
31392555Sdes	p = s;
31492555Sdes
31592555Sdes	if (p == NULL || *p == '\0')
31692555Sdes		return -1;
31792555Sdes
31892555Sdes	while (*p) {
31992555Sdes		secs = strtol(p, &endp, 10);
32092555Sdes		if (p == endp ||
32192555Sdes		    (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
32292555Sdes		    secs < 0)
32392555Sdes			return -1;
32492555Sdes
32592555Sdes		switch (*endp++) {
32692555Sdes		case '\0':
32792555Sdes			endp--;
328162852Sdes			break;
32992555Sdes		case 's':
33092555Sdes		case 'S':
33192555Sdes			break;
33292555Sdes		case 'm':
33392555Sdes		case 'M':
33492555Sdes			secs *= MINUTES;
33592555Sdes			break;
33692555Sdes		case 'h':
33792555Sdes		case 'H':
33892555Sdes			secs *= HOURS;
33992555Sdes			break;
34092555Sdes		case 'd':
34192555Sdes		case 'D':
34292555Sdes			secs *= DAYS;
34392555Sdes			break;
34492555Sdes		case 'w':
34592555Sdes		case 'W':
34692555Sdes			secs *= WEEKS;
34792555Sdes			break;
34892555Sdes		default:
34992555Sdes			return -1;
35092555Sdes		}
35192555Sdes		total += secs;
35292555Sdes		if (total < 0)
35392555Sdes			return -1;
35492555Sdes		p = endp;
35592555Sdes	}
35692555Sdes
35792555Sdes	return total;
35892555Sdes}
35992555Sdes
360146998Sdes/*
361162852Sdes * Returns a standardized host+port identifier string.
362162852Sdes * Caller must free returned string.
363162852Sdes */
364162852Sdeschar *
365162852Sdesput_host_port(const char *host, u_short port)
366162852Sdes{
367162852Sdes	char *hoststr;
368162852Sdes
369162852Sdes	if (port == 0 || port == SSH_DEFAULT_PORT)
370162852Sdes		return(xstrdup(host));
371162852Sdes	if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0)
372162852Sdes		fatal("put_host_port: asprintf: %s", strerror(errno));
373162852Sdes	debug3("put_host_port: %s", hoststr);
374162852Sdes	return hoststr;
375162852Sdes}
376162852Sdes
377162852Sdes/*
378146998Sdes * Search for next delimiter between hostnames/addresses and ports.
379146998Sdes * Argument may be modified (for termination).
380146998Sdes * Returns *cp if parsing succeeds.
381146998Sdes * *cp is set to the start of the next delimiter, if one was found.
382146998Sdes * If this is the last field, *cp is set to NULL.
383146998Sdes */
38492555Sdeschar *
385146998Sdeshpdelim(char **cp)
386146998Sdes{
387146998Sdes	char *s, *old;
388146998Sdes
389146998Sdes	if (cp == NULL || *cp == NULL)
390146998Sdes		return NULL;
391146998Sdes
392146998Sdes	old = s = *cp;
393146998Sdes	if (*s == '[') {
394146998Sdes		if ((s = strchr(s, ']')) == NULL)
395146998Sdes			return NULL;
396146998Sdes		else
397146998Sdes			s++;
398146998Sdes	} else if ((s = strpbrk(s, ":/")) == NULL)
399146998Sdes		s = *cp + strlen(*cp); /* skip to end (see first case below) */
400146998Sdes
401146998Sdes	switch (*s) {
402146998Sdes	case '\0':
403146998Sdes		*cp = NULL;	/* no more fields*/
404146998Sdes		break;
405147001Sdes
406146998Sdes	case ':':
407146998Sdes	case '/':
408146998Sdes		*s = '\0';	/* terminate */
409146998Sdes		*cp = s + 1;
410146998Sdes		break;
411147001Sdes
412146998Sdes	default:
413146998Sdes		return NULL;
414146998Sdes	}
415146998Sdes
416146998Sdes	return old;
417146998Sdes}
418146998Sdes
419146998Sdeschar *
42092555Sdescleanhostname(char *host)
42192555Sdes{
42292555Sdes	if (*host == '[' && host[strlen(host) - 1] == ']') {
42392555Sdes		host[strlen(host) - 1] = '\0';
42492555Sdes		return (host + 1);
42592555Sdes	} else
42692555Sdes		return host;
42792555Sdes}
42892555Sdes
42992555Sdeschar *
43092555Sdescolon(char *cp)
43192555Sdes{
43292555Sdes	int flag = 0;
43392555Sdes
43492555Sdes	if (*cp == ':')		/* Leading colon is part of file name. */
435215116Sdes		return NULL;
43692555Sdes	if (*cp == '[')
43792555Sdes		flag = 1;
43892555Sdes
43992555Sdes	for (; *cp; ++cp) {
44092555Sdes		if (*cp == '@' && *(cp+1) == '[')
44192555Sdes			flag = 1;
44292555Sdes		if (*cp == ']' && *(cp+1) == ':' && flag)
44392555Sdes			return (cp+1);
44492555Sdes		if (*cp == ':' && !flag)
44592555Sdes			return (cp);
44692555Sdes		if (*cp == '/')
447215116Sdes			return NULL;
44892555Sdes	}
449215116Sdes	return NULL;
45092555Sdes}
45192555Sdes
45292555Sdes/* function to assist building execv() arguments */
45392555Sdesvoid
45492555Sdesaddargs(arglist *args, char *fmt, ...)
45592555Sdes{
45692555Sdes	va_list ap;
457157016Sdes	char *cp;
458137015Sdes	u_int nalloc;
459157016Sdes	int r;
46092555Sdes
46192555Sdes	va_start(ap, fmt);
462157016Sdes	r = vasprintf(&cp, fmt, ap);
46392555Sdes	va_end(ap);
464157016Sdes	if (r == -1)
465157016Sdes		fatal("addargs: argument too long");
46692555Sdes
467120161Snectar	nalloc = args->nalloc;
46892555Sdes	if (args->list == NULL) {
469120161Snectar		nalloc = 32;
47092555Sdes		args->num = 0;
471120161Snectar	} else if (args->num+2 >= nalloc)
472120161Snectar		nalloc *= 2;
47392555Sdes
474162852Sdes	args->list = xrealloc(args->list, nalloc, sizeof(char *));
475120161Snectar	args->nalloc = nalloc;
476157016Sdes	args->list[args->num++] = cp;
47792555Sdes	args->list[args->num] = NULL;
47892555Sdes}
479146998Sdes
480157016Sdesvoid
481157016Sdesreplacearg(arglist *args, u_int which, char *fmt, ...)
482157016Sdes{
483157016Sdes	va_list ap;
484157016Sdes	char *cp;
485157016Sdes	int r;
486157016Sdes
487157016Sdes	va_start(ap, fmt);
488157016Sdes	r = vasprintf(&cp, fmt, ap);
489157016Sdes	va_end(ap);
490157016Sdes	if (r == -1)
491157016Sdes		fatal("replacearg: argument too long");
492157016Sdes
493157016Sdes	if (which >= args->num)
494157016Sdes		fatal("replacearg: tried to replace invalid arg %d >= %d",
495157016Sdes		    which, args->num);
496255767Sdes	free(args->list[which]);
497157016Sdes	args->list[which] = cp;
498157016Sdes}
499157016Sdes
500157016Sdesvoid
501157016Sdesfreeargs(arglist *args)
502157016Sdes{
503157016Sdes	u_int i;
504157016Sdes
505157016Sdes	if (args->list != NULL) {
506157016Sdes		for (i = 0; i < args->num; i++)
507255767Sdes			free(args->list[i]);
508255767Sdes		free(args->list);
509157016Sdes		args->nalloc = args->num = 0;
510157016Sdes		args->list = NULL;
511157016Sdes	}
512157016Sdes}
513157016Sdes
514146998Sdes/*
515149749Sdes * Expands tildes in the file name.  Returns data allocated by xmalloc.
516149749Sdes * Warning: this calls getpw*.
517149749Sdes */
518149749Sdeschar *
519149749Sdestilde_expand_filename(const char *filename, uid_t uid)
520149749Sdes{
521255767Sdes	const char *path, *sep;
522255767Sdes	char user[128], *ret;
523149749Sdes	struct passwd *pw;
524149749Sdes	u_int len, slash;
525149749Sdes
526149749Sdes	if (*filename != '~')
527149749Sdes		return (xstrdup(filename));
528149749Sdes	filename++;
529149749Sdes
530149749Sdes	path = strchr(filename, '/');
531149749Sdes	if (path != NULL && path > filename) {		/* ~user/path */
532149749Sdes		slash = path - filename;
533149749Sdes		if (slash > sizeof(user) - 1)
534149749Sdes			fatal("tilde_expand_filename: ~username too long");
535149749Sdes		memcpy(user, filename, slash);
536149749Sdes		user[slash] = '\0';
537149749Sdes		if ((pw = getpwnam(user)) == NULL)
538149749Sdes			fatal("tilde_expand_filename: No such user %s", user);
539149749Sdes	} else if ((pw = getpwuid(uid)) == NULL)	/* ~/path */
540181111Sdes		fatal("tilde_expand_filename: No such uid %ld", (long)uid);
541149749Sdes
542149749Sdes	/* Make sure directory has a trailing '/' */
543149749Sdes	len = strlen(pw->pw_dir);
544255767Sdes	if (len == 0 || pw->pw_dir[len - 1] != '/')
545255767Sdes		sep = "/";
546255767Sdes	else
547255767Sdes		sep = "";
548149749Sdes
549149749Sdes	/* Skip leading '/' from specified path */
550149749Sdes	if (path != NULL)
551149749Sdes		filename = path + 1;
552255767Sdes
553255767Sdes	if (xasprintf(&ret, "%s%s%s", pw->pw_dir, sep, filename) >= MAXPATHLEN)
554149749Sdes		fatal("tilde_expand_filename: Path too long");
555149749Sdes
556255767Sdes	return (ret);
557149749Sdes}
558149749Sdes
559149749Sdes/*
560149749Sdes * Expand a string with a set of %[char] escapes. A number of escapes may be
561149749Sdes * specified as (char *escape_chars, char *replacement) pairs. The list must
562149749Sdes * be terminated by a NULL escape_char. Returns replaced string in memory
563149749Sdes * allocated by xmalloc.
564149749Sdes */
565149749Sdeschar *
566149749Sdespercent_expand(const char *string, ...)
567149749Sdes{
568149749Sdes#define EXPAND_MAX_KEYS	16
569204917Sdes	u_int num_keys, i, j;
570149749Sdes	struct {
571149749Sdes		const char *key;
572149749Sdes		const char *repl;
573149749Sdes	} keys[EXPAND_MAX_KEYS];
574149749Sdes	char buf[4096];
575149749Sdes	va_list ap;
576149749Sdes
577149749Sdes	/* Gather keys */
578149749Sdes	va_start(ap, string);
579149749Sdes	for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
580149749Sdes		keys[num_keys].key = va_arg(ap, char *);
581149749Sdes		if (keys[num_keys].key == NULL)
582149749Sdes			break;
583149749Sdes		keys[num_keys].repl = va_arg(ap, char *);
584149749Sdes		if (keys[num_keys].repl == NULL)
585204917Sdes			fatal("%s: NULL replacement", __func__);
586149749Sdes	}
587204917Sdes	if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
588204917Sdes		fatal("%s: too many keys", __func__);
589149749Sdes	va_end(ap);
590149749Sdes
591149749Sdes	/* Expand string */
592149749Sdes	*buf = '\0';
593149749Sdes	for (i = 0; *string != '\0'; string++) {
594149749Sdes		if (*string != '%') {
595149749Sdes append:
596149749Sdes			buf[i++] = *string;
597149749Sdes			if (i >= sizeof(buf))
598204917Sdes				fatal("%s: string too long", __func__);
599149749Sdes			buf[i] = '\0';
600149749Sdes			continue;
601149749Sdes		}
602149749Sdes		string++;
603204917Sdes		/* %% case */
604149749Sdes		if (*string == '%')
605149749Sdes			goto append;
606149749Sdes		for (j = 0; j < num_keys; j++) {
607149749Sdes			if (strchr(keys[j].key, *string) != NULL) {
608149749Sdes				i = strlcat(buf, keys[j].repl, sizeof(buf));
609149749Sdes				if (i >= sizeof(buf))
610204917Sdes					fatal("%s: string too long", __func__);
611149749Sdes				break;
612149749Sdes			}
613149749Sdes		}
614149749Sdes		if (j >= num_keys)
615204917Sdes			fatal("%s: unknown key %%%c", __func__, *string);
616149749Sdes	}
617149749Sdes	return (xstrdup(buf));
618149749Sdes#undef EXPAND_MAX_KEYS
619149749Sdes}
620149749Sdes
621149749Sdes/*
622146998Sdes * Read an entire line from a public key file into a static buffer, discarding
623146998Sdes * lines that exceed the buffer size.  Returns 0 on success, -1 on failure.
624146998Sdes */
625146998Sdesint
626146998Sdesread_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
627146998Sdes   u_long *lineno)
628146998Sdes{
629146998Sdes	while (fgets(buf, bufsz, f) != NULL) {
630181111Sdes		if (buf[0] == '\0')
631181111Sdes			continue;
632146998Sdes		(*lineno)++;
633146998Sdes		if (buf[strlen(buf) - 1] == '\n' || feof(f)) {
634146998Sdes			return 0;
635146998Sdes		} else {
636146998Sdes			debug("%s: %s line %lu exceeds size limit", __func__,
637146998Sdes			    filename, *lineno);
638146998Sdes			/* discard remainder of line */
639147001Sdes			while (fgetc(f) != '\n' && !feof(f))
640146998Sdes				;	/* nothing */
641146998Sdes		}
642146998Sdes	}
643146998Sdes	return -1;
644146998Sdes}
645149749Sdes
646157016Sdesint
647157016Sdestun_open(int tun, int mode)
648157016Sdes{
649157016Sdes#if defined(CUSTOM_SYS_TUN_OPEN)
650157016Sdes	return (sys_tun_open(tun, mode));
651157016Sdes#elif defined(SSH_TUN_OPENBSD)
652157016Sdes	struct ifreq ifr;
653157016Sdes	char name[100];
654157016Sdes	int fd = -1, sock;
655157016Sdes
656157016Sdes	/* Open the tunnel device */
657157016Sdes	if (tun <= SSH_TUNID_MAX) {
658157016Sdes		snprintf(name, sizeof(name), "/dev/tun%d", tun);
659157016Sdes		fd = open(name, O_RDWR);
660157016Sdes	} else if (tun == SSH_TUNID_ANY) {
661157016Sdes		for (tun = 100; tun >= 0; tun--) {
662157016Sdes			snprintf(name, sizeof(name), "/dev/tun%d", tun);
663157016Sdes			if ((fd = open(name, O_RDWR)) >= 0)
664157016Sdes				break;
665157016Sdes		}
666157016Sdes	} else {
667157016Sdes		debug("%s: invalid tunnel %u", __func__, tun);
668157016Sdes		return (-1);
669157016Sdes	}
670157016Sdes
671157016Sdes	if (fd < 0) {
672157016Sdes		debug("%s: %s open failed: %s", __func__, name, strerror(errno));
673157016Sdes		return (-1);
674157016Sdes	}
675157016Sdes
676157016Sdes	debug("%s: %s mode %d fd %d", __func__, name, mode, fd);
677157016Sdes
678157016Sdes	/* Set the tunnel device operation mode */
679157016Sdes	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tun%d", tun);
680157016Sdes	if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
681157016Sdes		goto failed;
682157016Sdes
683157016Sdes	if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
684157016Sdes		goto failed;
685157016Sdes
686157016Sdes	/* Set interface mode */
687157016Sdes	ifr.ifr_flags &= ~IFF_UP;
688157016Sdes	if (mode == SSH_TUNMODE_ETHERNET)
689157016Sdes		ifr.ifr_flags |= IFF_LINK0;
690157016Sdes	else
691157016Sdes		ifr.ifr_flags &= ~IFF_LINK0;
692157016Sdes	if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
693157016Sdes		goto failed;
694157016Sdes
695157016Sdes	/* Bring interface up */
696157016Sdes	ifr.ifr_flags |= IFF_UP;
697157016Sdes	if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
698157016Sdes		goto failed;
699157016Sdes
700157016Sdes	close(sock);
701157016Sdes	return (fd);
702157016Sdes
703157016Sdes failed:
704157016Sdes	if (fd >= 0)
705157016Sdes		close(fd);
706157016Sdes	if (sock >= 0)
707157016Sdes		close(sock);
708157016Sdes	debug("%s: failed to set %s mode %d: %s", __func__, name,
709157016Sdes	    mode, strerror(errno));
710157016Sdes	return (-1);
711157016Sdes#else
712157016Sdes	error("Tunnel interfaces are not supported on this platform");
713157016Sdes	return (-1);
714157016Sdes#endif
715157016Sdes}
716157016Sdes
717157016Sdesvoid
718157016Sdessanitise_stdfd(void)
719157016Sdes{
720157016Sdes	int nullfd, dupfd;
721157016Sdes
722157016Sdes	if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
723192595Sdes		fprintf(stderr, "Couldn't open /dev/null: %s\n",
724192595Sdes		    strerror(errno));
725157016Sdes		exit(1);
726157016Sdes	}
727157016Sdes	while (++dupfd <= 2) {
728157016Sdes		/* Only clobber closed fds */
729157016Sdes		if (fcntl(dupfd, F_GETFL, 0) >= 0)
730157016Sdes			continue;
731157016Sdes		if (dup2(nullfd, dupfd) == -1) {
732192595Sdes			fprintf(stderr, "dup2: %s\n", strerror(errno));
733157016Sdes			exit(1);
734157016Sdes		}
735157016Sdes	}
736157016Sdes	if (nullfd > 2)
737157016Sdes		close(nullfd);
738157016Sdes}
739157016Sdes
740149749Sdeschar *
741162852Sdestohex(const void *vp, size_t l)
742149749Sdes{
743162852Sdes	const u_char *p = (const u_char *)vp;
744149749Sdes	char b[3], *r;
745162852Sdes	size_t i, hl;
746149749Sdes
747162852Sdes	if (l > 65536)
748162852Sdes		return xstrdup("tohex: length > 65536");
749162852Sdes
750149749Sdes	hl = l * 2 + 1;
751162852Sdes	r = xcalloc(1, hl);
752149749Sdes	for (i = 0; i < l; i++) {
753162852Sdes		snprintf(b, sizeof(b), "%02x", p[i]);
754149749Sdes		strlcat(r, b, hl);
755149749Sdes	}
756149749Sdes	return (r);
757149749Sdes}
758149749Sdes
759162852Sdesu_int64_t
760162852Sdesget_u64(const void *vp)
761162852Sdes{
762162852Sdes	const u_char *p = (const u_char *)vp;
763162852Sdes	u_int64_t v;
764162852Sdes
765162852Sdes	v  = (u_int64_t)p[0] << 56;
766162852Sdes	v |= (u_int64_t)p[1] << 48;
767162852Sdes	v |= (u_int64_t)p[2] << 40;
768162852Sdes	v |= (u_int64_t)p[3] << 32;
769162852Sdes	v |= (u_int64_t)p[4] << 24;
770162852Sdes	v |= (u_int64_t)p[5] << 16;
771162852Sdes	v |= (u_int64_t)p[6] << 8;
772162852Sdes	v |= (u_int64_t)p[7];
773162852Sdes
774162852Sdes	return (v);
775162852Sdes}
776162852Sdes
777162852Sdesu_int32_t
778162852Sdesget_u32(const void *vp)
779162852Sdes{
780162852Sdes	const u_char *p = (const u_char *)vp;
781162852Sdes	u_int32_t v;
782162852Sdes
783162852Sdes	v  = (u_int32_t)p[0] << 24;
784162852Sdes	v |= (u_int32_t)p[1] << 16;
785162852Sdes	v |= (u_int32_t)p[2] << 8;
786162852Sdes	v |= (u_int32_t)p[3];
787162852Sdes
788162852Sdes	return (v);
789162852Sdes}
790162852Sdes
791162852Sdesu_int16_t
792162852Sdesget_u16(const void *vp)
793162852Sdes{
794162852Sdes	const u_char *p = (const u_char *)vp;
795162852Sdes	u_int16_t v;
796162852Sdes
797162852Sdes	v  = (u_int16_t)p[0] << 8;
798162852Sdes	v |= (u_int16_t)p[1];
799162852Sdes
800162852Sdes	return (v);
801162852Sdes}
802162852Sdes
803162852Sdesvoid
804162852Sdesput_u64(void *vp, u_int64_t v)
805162852Sdes{
806162852Sdes	u_char *p = (u_char *)vp;
807162852Sdes
808162852Sdes	p[0] = (u_char)(v >> 56) & 0xff;
809162852Sdes	p[1] = (u_char)(v >> 48) & 0xff;
810162852Sdes	p[2] = (u_char)(v >> 40) & 0xff;
811162852Sdes	p[3] = (u_char)(v >> 32) & 0xff;
812162852Sdes	p[4] = (u_char)(v >> 24) & 0xff;
813162852Sdes	p[5] = (u_char)(v >> 16) & 0xff;
814162852Sdes	p[6] = (u_char)(v >> 8) & 0xff;
815162852Sdes	p[7] = (u_char)v & 0xff;
816162852Sdes}
817162852Sdes
818162852Sdesvoid
819162852Sdesput_u32(void *vp, u_int32_t v)
820162852Sdes{
821162852Sdes	u_char *p = (u_char *)vp;
822162852Sdes
823162852Sdes	p[0] = (u_char)(v >> 24) & 0xff;
824162852Sdes	p[1] = (u_char)(v >> 16) & 0xff;
825162852Sdes	p[2] = (u_char)(v >> 8) & 0xff;
826162852Sdes	p[3] = (u_char)v & 0xff;
827162852Sdes}
828162852Sdes
829162852Sdes
830162852Sdesvoid
831162852Sdesput_u16(void *vp, u_int16_t v)
832162852Sdes{
833162852Sdes	u_char *p = (u_char *)vp;
834162852Sdes
835162852Sdes	p[0] = (u_char)(v >> 8) & 0xff;
836162852Sdes	p[1] = (u_char)v & 0xff;
837162852Sdes}
838181111Sdes
839181111Sdesvoid
840181111Sdesms_subtract_diff(struct timeval *start, int *ms)
841181111Sdes{
842181111Sdes	struct timeval diff, finish;
843181111Sdes
844181111Sdes	gettimeofday(&finish, NULL);
845181111Sdes	timersub(&finish, start, &diff);
846181111Sdes	*ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
847181111Sdes}
848181111Sdes
849181111Sdesvoid
850181111Sdesms_to_timeval(struct timeval *tv, int ms)
851181111Sdes{
852181111Sdes	if (ms < 0)
853181111Sdes		ms = 0;
854181111Sdes	tv->tv_sec = ms / 1000;
855181111Sdes	tv->tv_usec = (ms % 1000) * 1000;
856181111Sdes}
857181111Sdes
858255767Sdestime_t
859255767Sdesmonotime(void)
860255767Sdes{
861255767Sdes#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
862255767Sdes	struct timespec ts;
863255767Sdes	static int gettime_failed = 0;
864255767Sdes
865255767Sdes	if (!gettime_failed) {
866255767Sdes		if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
867255767Sdes			return (ts.tv_sec);
868255767Sdes		debug3("clock_gettime: %s", strerror(errno));
869255767Sdes		gettime_failed = 1;
870255767Sdes	}
871255767Sdes#endif
872255767Sdes
873255767Sdes	return time(NULL);
874255767Sdes}
875255767Sdes
876221420Sdesvoid
877221420Sdesbandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen)
878221420Sdes{
879221420Sdes	bw->buflen = buflen;
880221420Sdes	bw->rate = kbps;
881221420Sdes	bw->thresh = bw->rate;
882221420Sdes	bw->lamt = 0;
883221420Sdes	timerclear(&bw->bwstart);
884221420Sdes	timerclear(&bw->bwend);
885221420Sdes}
886221420Sdes
887221420Sdes/* Callback from read/write loop to insert bandwidth-limiting delays */
888221420Sdesvoid
889221420Sdesbandwidth_limit(struct bwlimit *bw, size_t read_len)
890221420Sdes{
891221420Sdes	u_int64_t waitlen;
892221420Sdes	struct timespec ts, rm;
893221420Sdes
894221420Sdes	if (!timerisset(&bw->bwstart)) {
895221420Sdes		gettimeofday(&bw->bwstart, NULL);
896221420Sdes		return;
897221420Sdes	}
898221420Sdes
899221420Sdes	bw->lamt += read_len;
900221420Sdes	if (bw->lamt < bw->thresh)
901221420Sdes		return;
902221420Sdes
903221420Sdes	gettimeofday(&bw->bwend, NULL);
904221420Sdes	timersub(&bw->bwend, &bw->bwstart, &bw->bwend);
905221420Sdes	if (!timerisset(&bw->bwend))
906221420Sdes		return;
907221420Sdes
908221420Sdes	bw->lamt *= 8;
909221420Sdes	waitlen = (double)1000000L * bw->lamt / bw->rate;
910221420Sdes
911221420Sdes	bw->bwstart.tv_sec = waitlen / 1000000L;
912221420Sdes	bw->bwstart.tv_usec = waitlen % 1000000L;
913221420Sdes
914221420Sdes	if (timercmp(&bw->bwstart, &bw->bwend, >)) {
915221420Sdes		timersub(&bw->bwstart, &bw->bwend, &bw->bwend);
916221420Sdes
917221420Sdes		/* Adjust the wait time */
918221420Sdes		if (bw->bwend.tv_sec) {
919221420Sdes			bw->thresh /= 2;
920221420Sdes			if (bw->thresh < bw->buflen / 4)
921221420Sdes				bw->thresh = bw->buflen / 4;
922221420Sdes		} else if (bw->bwend.tv_usec < 10000) {
923221420Sdes			bw->thresh *= 2;
924221420Sdes			if (bw->thresh > bw->buflen * 8)
925221420Sdes				bw->thresh = bw->buflen * 8;
926221420Sdes		}
927221420Sdes
928221420Sdes		TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts);
929221420Sdes		while (nanosleep(&ts, &rm) == -1) {
930221420Sdes			if (errno != EINTR)
931221420Sdes				break;
932221420Sdes			ts = rm;
933221420Sdes		}
934221420Sdes	}
935221420Sdes
936221420Sdes	bw->lamt = 0;
937221420Sdes	gettimeofday(&bw->bwstart, NULL);
938221420Sdes}
939221420Sdes
940221420Sdes/* Make a template filename for mk[sd]temp() */
941221420Sdesvoid
942221420Sdesmktemp_proto(char *s, size_t len)
943221420Sdes{
944221420Sdes	const char *tmpdir;
945221420Sdes	int r;
946221420Sdes
947221420Sdes	if ((tmpdir = getenv("TMPDIR")) != NULL) {
948221420Sdes		r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir);
949221420Sdes		if (r > 0 && (size_t)r < len)
950221420Sdes			return;
951221420Sdes	}
952221420Sdes	r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX");
953221420Sdes	if (r < 0 || (size_t)r >= len)
954221420Sdes		fatal("%s: template string too short", __func__);
955221420Sdes}
956221420Sdes
957221420Sdesstatic const struct {
958221420Sdes	const char *name;
959221420Sdes	int value;
960221420Sdes} ipqos[] = {
961221420Sdes	{ "af11", IPTOS_DSCP_AF11 },
962221420Sdes	{ "af12", IPTOS_DSCP_AF12 },
963221420Sdes	{ "af13", IPTOS_DSCP_AF13 },
964240075Sdes	{ "af21", IPTOS_DSCP_AF21 },
965221420Sdes	{ "af22", IPTOS_DSCP_AF22 },
966221420Sdes	{ "af23", IPTOS_DSCP_AF23 },
967221420Sdes	{ "af31", IPTOS_DSCP_AF31 },
968221420Sdes	{ "af32", IPTOS_DSCP_AF32 },
969221420Sdes	{ "af33", IPTOS_DSCP_AF33 },
970221420Sdes	{ "af41", IPTOS_DSCP_AF41 },
971221420Sdes	{ "af42", IPTOS_DSCP_AF42 },
972221420Sdes	{ "af43", IPTOS_DSCP_AF43 },
973221420Sdes	{ "cs0", IPTOS_DSCP_CS0 },
974221420Sdes	{ "cs1", IPTOS_DSCP_CS1 },
975221420Sdes	{ "cs2", IPTOS_DSCP_CS2 },
976221420Sdes	{ "cs3", IPTOS_DSCP_CS3 },
977221420Sdes	{ "cs4", IPTOS_DSCP_CS4 },
978221420Sdes	{ "cs5", IPTOS_DSCP_CS5 },
979221420Sdes	{ "cs6", IPTOS_DSCP_CS6 },
980221420Sdes	{ "cs7", IPTOS_DSCP_CS7 },
981221420Sdes	{ "ef", IPTOS_DSCP_EF },
982221420Sdes	{ "lowdelay", IPTOS_LOWDELAY },
983221420Sdes	{ "throughput", IPTOS_THROUGHPUT },
984221420Sdes	{ "reliability", IPTOS_RELIABILITY },
985221420Sdes	{ NULL, -1 }
986221420Sdes};
987221420Sdes
988215116Sdesint
989221420Sdesparse_ipqos(const char *cp)
990215116Sdes{
991221420Sdes	u_int i;
992221420Sdes	char *ep;
993221420Sdes	long val;
994215116Sdes
995221420Sdes	if (cp == NULL)
996221420Sdes		return -1;
997221420Sdes	for (i = 0; ipqos[i].name != NULL; i++) {
998221420Sdes		if (strcasecmp(cp, ipqos[i].name) == 0)
999221420Sdes			return ipqos[i].value;
1000221420Sdes	}
1001221420Sdes	/* Try parsing as an integer */
1002221420Sdes	val = strtol(cp, &ep, 0);
1003221420Sdes	if (*cp == '\0' || *ep != '\0' || val < 0 || val > 255)
1004221420Sdes		return -1;
1005221420Sdes	return val;
1006215116Sdes}
1007221420Sdes
1008226046Sdesconst char *
1009226046Sdesiptos2str(int iptos)
1010226046Sdes{
1011226046Sdes	int i;
1012226046Sdes	static char iptos_str[sizeof "0xff"];
1013226046Sdes
1014226046Sdes	for (i = 0; ipqos[i].name != NULL; i++) {
1015226046Sdes		if (ipqos[i].value == iptos)
1016226046Sdes			return ipqos[i].name;
1017226046Sdes	}
1018226046Sdes	snprintf(iptos_str, sizeof iptos_str, "0x%02x", iptos);
1019226046Sdes	return iptos_str;
1020226046Sdes}
1021204917Sdesvoid
1022204917Sdessock_set_v6only(int s)
1023204917Sdes{
1024204917Sdes#ifdef IPV6_V6ONLY
1025204917Sdes	int on = 1;
1026204917Sdes
1027204917Sdes	debug3("%s: set socket %d IPV6_V6ONLY", __func__, s);
1028204917Sdes	if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1)
1029204917Sdes		error("setsockopt IPV6_V6ONLY: %s", strerror(errno));
1030204917Sdes#endif
1031204917Sdes}
1032224638Sbrooks
1033224638Sbrooksvoid
1034224638Sbrookssock_get_rcvbuf(int *size, int rcvbuf)
1035224638Sbrooks{
1036224638Sbrooks	int sock, socksize;
1037224638Sbrooks	socklen_t socksizelen = sizeof(socksize);
1038224638Sbrooks
1039224638Sbrooks	/*
1040224638Sbrooks	 * Create a socket but do not connect it.  We use it
1041224638Sbrooks	 * only to get the rcv socket size.
1042224638Sbrooks	 */
1043224638Sbrooks	sock = socket(AF_INET6, SOCK_STREAM, 0);
1044224638Sbrooks	if (sock < 0)
1045224638Sbrooks		sock = socket(AF_INET, SOCK_STREAM, 0);
1046224638Sbrooks	if (sock < 0)
1047224638Sbrooks		return;
1048224638Sbrooks
1049224638Sbrooks	/*
1050224638Sbrooks	 * If the tcp_rcv_buf option is set and passed in, attempt to set the
1051224638Sbrooks	 *  buffer size to its value.
1052224638Sbrooks	 */
1053224638Sbrooks	if (rcvbuf)
1054224638Sbrooks		setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&rcvbuf,
1055224638Sbrooks		    sizeof(rcvbuf));
1056224638Sbrooks
1057224638Sbrooks	if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF,
1058224638Sbrooks	    &socksize, &socksizelen) == 0)
1059224638Sbrooks		if (size != NULL)
1060224638Sbrooks			*size = socksize;
1061224638Sbrooks	close(sock);
1062224638Sbrooks}
1063