1323136Sdes/* $OpenBSD: misc.c,v 1.109 2017/03/14 00:55:37 dtucker Exp $ */
276259Sgreen/*
376259Sgreen * Copyright (c) 2000 Markus Friedl.  All rights reserved.
4162852Sdes * Copyright (c) 2005,2006 Damien Miller.  All rights reserved.
576259Sgreen *
676259Sgreen * Redistribution and use in source and binary forms, with or without
776259Sgreen * modification, are permitted provided that the following conditions
876259Sgreen * are met:
976259Sgreen * 1. Redistributions of source code must retain the above copyright
1076259Sgreen *    notice, this list of conditions and the following disclaimer.
1176259Sgreen * 2. Redistributions in binary form must reproduce the above copyright
1276259Sgreen *    notice, this list of conditions and the following disclaimer in the
1376259Sgreen *    documentation and/or other materials provided with the distribution.
1476259Sgreen *
1576259Sgreen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1676259Sgreen * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1776259Sgreen * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1876259Sgreen * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1976259Sgreen * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2076259Sgreen * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2176259Sgreen * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2276259Sgreen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2376259Sgreen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2476259Sgreen * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2576259Sgreen */
2676259Sgreen
2776259Sgreen#include "includes.h"
2876259Sgreen
29162852Sdes#include <sys/types.h>
30162852Sdes#include <sys/ioctl.h>
31162852Sdes#include <sys/socket.h>
32323134Sdes#include <sys/sysctl.h>
33296633Sdes#include <sys/time.h>
34294328Sdes#include <sys/un.h>
35162852Sdes
36294332Sdes#include <limits.h>
37162852Sdes#include <stdarg.h>
38162852Sdes#include <stdio.h>
39162852Sdes#include <stdlib.h>
40162852Sdes#include <string.h>
41221420Sdes#include <time.h>
42162852Sdes#include <unistd.h>
43162852Sdes
44162852Sdes#include <netinet/in.h>
45221420Sdes#include <netinet/in_systm.h>
46221420Sdes#include <netinet/ip.h>
47162852Sdes#include <netinet/tcp.h>
48162852Sdes
49261320Sdes#include <ctype.h>
50162852Sdes#include <errno.h>
51162852Sdes#include <fcntl.h>
52181111Sdes#include <netdb.h>
53162852Sdes#ifdef HAVE_PATHS_H
54162852Sdes# include <paths.h>
55162852Sdes#include <pwd.h>
56162852Sdes#endif
57157016Sdes#ifdef SSH_TUN_OPENBSD
58157016Sdes#include <net/if.h>
59157016Sdes#endif
60157016Sdes
61162852Sdes#include "xmalloc.h"
6276259Sgreen#include "misc.h"
6376259Sgreen#include "log.h"
64162852Sdes#include "ssh.h"
6576259Sgreen
6692555Sdes/* remove newline at end of string */
6776259Sgreenchar *
6876259Sgreenchop(char *s)
6976259Sgreen{
7076259Sgreen	char *t = s;
7176259Sgreen	while (*t) {
7292555Sdes		if (*t == '\n' || *t == '\r') {
7376259Sgreen			*t = '\0';
7476259Sgreen			return s;
7576259Sgreen		}
7676259Sgreen		t++;
7776259Sgreen	}
7876259Sgreen	return s;
7976259Sgreen
8076259Sgreen}
8176259Sgreen
8292555Sdes/* set/unset filedescriptor to non-blocking */
83137015Sdesint
8476259Sgreenset_nonblock(int fd)
8576259Sgreen{
8676259Sgreen	int val;
8792555Sdes
88323129Sdes	val = fcntl(fd, F_GETFL);
8976259Sgreen	if (val < 0) {
90323129Sdes		error("fcntl(%d, F_GETFL): %s", fd, strerror(errno));
91137015Sdes		return (-1);
9276259Sgreen	}
9376259Sgreen	if (val & O_NONBLOCK) {
94137015Sdes		debug3("fd %d is O_NONBLOCK", fd);
95137015Sdes		return (0);
9676259Sgreen	}
97124208Sdes	debug2("fd %d setting O_NONBLOCK", fd);
9876259Sgreen	val |= O_NONBLOCK;
99137015Sdes	if (fcntl(fd, F_SETFL, val) == -1) {
100137015Sdes		debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd,
101137015Sdes		    strerror(errno));
102137015Sdes		return (-1);
103137015Sdes	}
104137015Sdes	return (0);
10576259Sgreen}
10676259Sgreen
107137015Sdesint
10892555Sdesunset_nonblock(int fd)
10992555Sdes{
11092555Sdes	int val;
11192555Sdes
112323129Sdes	val = fcntl(fd, F_GETFL);
11392555Sdes	if (val < 0) {
114323129Sdes		error("fcntl(%d, F_GETFL): %s", fd, strerror(errno));
115137015Sdes		return (-1);
11692555Sdes	}
11792555Sdes	if (!(val & O_NONBLOCK)) {
118137015Sdes		debug3("fd %d is not O_NONBLOCK", fd);
119137015Sdes		return (0);
12092555Sdes	}
12192555Sdes	debug("fd %d clearing O_NONBLOCK", fd);
12292555Sdes	val &= ~O_NONBLOCK;
123137015Sdes	if (fcntl(fd, F_SETFL, val) == -1) {
124137015Sdes		debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s",
12592555Sdes		    fd, strerror(errno));
126137015Sdes		return (-1);
127137015Sdes	}
128137015Sdes	return (0);
12992555Sdes}
13092555Sdes
131181111Sdesconst char *
132181111Sdesssh_gai_strerror(int gaierr)
133181111Sdes{
134255767Sdes	if (gaierr == EAI_SYSTEM && errno != 0)
135181111Sdes		return strerror(errno);
136181111Sdes	return gai_strerror(gaierr);
137181111Sdes}
138181111Sdes
13992555Sdes/* disable nagle on socket */
14092555Sdesvoid
14192555Sdesset_nodelay(int fd)
14292555Sdes{
14392555Sdes	int opt;
14492555Sdes	socklen_t optlen;
14592555Sdes
14692555Sdes	optlen = sizeof opt;
14792555Sdes	if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
148126274Sdes		debug("getsockopt TCP_NODELAY: %.100s", strerror(errno));
14992555Sdes		return;
15092555Sdes	}
15192555Sdes	if (opt == 1) {
15292555Sdes		debug2("fd %d is TCP_NODELAY", fd);
15392555Sdes		return;
15492555Sdes	}
15592555Sdes	opt = 1;
156113908Sdes	debug2("fd %d setting TCP_NODELAY", fd);
15792555Sdes	if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
15892555Sdes		error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
15992555Sdes}
16092555Sdes
16176259Sgreen/* Characters considered whitespace in strsep calls. */
16276259Sgreen#define WHITESPACE " \t\r\n"
163162852Sdes#define QUOTE	"\""
16476259Sgreen
16592555Sdes/* return next token in configuration line */
16676259Sgreenchar *
16776259Sgreenstrdelim(char **s)
16876259Sgreen{
16976259Sgreen	char *old;
17076259Sgreen	int wspace = 0;
17176259Sgreen
17276259Sgreen	if (*s == NULL)
17376259Sgreen		return NULL;
17476259Sgreen
17576259Sgreen	old = *s;
17676259Sgreen
177162852Sdes	*s = strpbrk(*s, WHITESPACE QUOTE "=");
17876259Sgreen	if (*s == NULL)
17976259Sgreen		return (old);
18076259Sgreen
181162852Sdes	if (*s[0] == '\"') {
182162852Sdes		memmove(*s, *s + 1, strlen(*s)); /* move nul too */
183162852Sdes		/* Find matching quote */
184162852Sdes		if ((*s = strpbrk(*s, QUOTE)) == NULL) {
185162852Sdes			return (NULL);		/* no matching quote */
186162852Sdes		} else {
187162852Sdes			*s[0] = '\0';
188215116Sdes			*s += strspn(*s + 1, WHITESPACE) + 1;
189162852Sdes			return (old);
190162852Sdes		}
191162852Sdes	}
192162852Sdes
19376259Sgreen	/* Allow only one '=' to be skipped */
19476259Sgreen	if (*s[0] == '=')
19576259Sgreen		wspace = 1;
19676259Sgreen	*s[0] = '\0';
19776259Sgreen
198162852Sdes	/* Skip any extra whitespace after first token */
19976259Sgreen	*s += strspn(*s + 1, WHITESPACE) + 1;
20076259Sgreen	if (*s[0] == '=' && !wspace)
20176259Sgreen		*s += strspn(*s + 1, WHITESPACE) + 1;
20276259Sgreen
20376259Sgreen	return (old);
20476259Sgreen}
20576259Sgreen
20676259Sgreenstruct passwd *
20776259Sgreenpwcopy(struct passwd *pw)
20876259Sgreen{
209162852Sdes	struct passwd *copy = xcalloc(1, sizeof(*copy));
21076259Sgreen
21176259Sgreen	copy->pw_name = xstrdup(pw->pw_name);
21276259Sgreen	copy->pw_passwd = xstrdup(pw->pw_passwd);
213255767Sdes#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
21476259Sgreen	copy->pw_gecos = xstrdup(pw->pw_gecos);
215255767Sdes#endif
21676259Sgreen	copy->pw_uid = pw->pw_uid;
21776259Sgreen	copy->pw_gid = pw->pw_gid;
218255767Sdes#ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
21992555Sdes	copy->pw_expire = pw->pw_expire;
22098937Sdes#endif
221255767Sdes#ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
22292555Sdes	copy->pw_change = pw->pw_change;
22398937Sdes#endif
224255767Sdes#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
22576259Sgreen	copy->pw_class = xstrdup(pw->pw_class);
22698937Sdes#endif
22776259Sgreen	copy->pw_dir = xstrdup(pw->pw_dir);
22876259Sgreen	copy->pw_shell = xstrdup(pw->pw_shell);
22976259Sgreen	return copy;
23076259Sgreen}
23176259Sgreen
23292555Sdes/*
23392555Sdes * Convert ASCII string to TCP/IP port number.
234192595Sdes * Port must be >=0 and <=65535.
235192595Sdes * Return -1 if invalid.
23692555Sdes */
23792555Sdesint
23892555Sdesa2port(const char *s)
23976259Sgreen{
240192595Sdes	long long port;
241192595Sdes	const char *errstr;
24276259Sgreen
243192595Sdes	port = strtonum(s, 0, 65535, &errstr);
244192595Sdes	if (errstr != NULL)
245192595Sdes		return -1;
246192595Sdes	return (int)port;
24776259Sgreen}
24892555Sdes
249157016Sdesint
250157016Sdesa2tun(const char *s, int *remote)
251157016Sdes{
252157016Sdes	const char *errstr = NULL;
253157016Sdes	char *sp, *ep;
254157016Sdes	int tun;
255157016Sdes
256157016Sdes	if (remote != NULL) {
257157016Sdes		*remote = SSH_TUNID_ANY;
258157016Sdes		sp = xstrdup(s);
259157016Sdes		if ((ep = strchr(sp, ':')) == NULL) {
260255767Sdes			free(sp);
261157016Sdes			return (a2tun(s, NULL));
262157016Sdes		}
263157016Sdes		ep[0] = '\0'; ep++;
264157016Sdes		*remote = a2tun(ep, NULL);
265157016Sdes		tun = a2tun(sp, NULL);
266255767Sdes		free(sp);
267157016Sdes		return (*remote == SSH_TUNID_ERR ? *remote : tun);
268157016Sdes	}
269157016Sdes
270157016Sdes	if (strcasecmp(s, "any") == 0)
271157016Sdes		return (SSH_TUNID_ANY);
272157016Sdes
273157016Sdes	tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr);
274157016Sdes	if (errstr != NULL)
275157016Sdes		return (SSH_TUNID_ERR);
276157016Sdes
277157016Sdes	return (tun);
278157016Sdes}
279157016Sdes
28092555Sdes#define SECONDS		1
28192555Sdes#define MINUTES		(SECONDS * 60)
28292555Sdes#define HOURS		(MINUTES * 60)
28392555Sdes#define DAYS		(HOURS * 24)
28492555Sdes#define WEEKS		(DAYS * 7)
28592555Sdes
28692555Sdes/*
28792555Sdes * Convert a time string into seconds; format is
28892555Sdes * a sequence of:
28992555Sdes *      time[qualifier]
29092555Sdes *
29192555Sdes * Valid time qualifiers are:
29292555Sdes *      <none>  seconds
29392555Sdes *      s|S     seconds
29492555Sdes *      m|M     minutes
29592555Sdes *      h|H     hours
29692555Sdes *      d|D     days
29792555Sdes *      w|W     weeks
29892555Sdes *
29992555Sdes * Examples:
30092555Sdes *      90m     90 minutes
30192555Sdes *      1h30m   90 minutes
30292555Sdes *      2d      2 days
30392555Sdes *      1w      1 week
30492555Sdes *
30592555Sdes * Return -1 if time string is invalid.
30692555Sdes */
30792555Sdeslong
30892555Sdesconvtime(const char *s)
30992555Sdes{
310323136Sdes	long total, secs, multiplier = 1;
31192555Sdes	const char *p;
31292555Sdes	char *endp;
31392555Sdes
31492555Sdes	errno = 0;
31592555Sdes	total = 0;
31692555Sdes	p = s;
31792555Sdes
31892555Sdes	if (p == NULL || *p == '\0')
31992555Sdes		return -1;
32092555Sdes
32192555Sdes	while (*p) {
32292555Sdes		secs = strtol(p, &endp, 10);
32392555Sdes		if (p == endp ||
32492555Sdes		    (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
32592555Sdes		    secs < 0)
32692555Sdes			return -1;
32792555Sdes
32892555Sdes		switch (*endp++) {
32992555Sdes		case '\0':
33092555Sdes			endp--;
331162852Sdes			break;
33292555Sdes		case 's':
33392555Sdes		case 'S':
33492555Sdes			break;
33592555Sdes		case 'm':
33692555Sdes		case 'M':
337323136Sdes			multiplier = MINUTES;
33892555Sdes			break;
33992555Sdes		case 'h':
34092555Sdes		case 'H':
341323136Sdes			multiplier = HOURS;
34292555Sdes			break;
34392555Sdes		case 'd':
34492555Sdes		case 'D':
345323136Sdes			multiplier = DAYS;
34692555Sdes			break;
34792555Sdes		case 'w':
34892555Sdes		case 'W':
349323136Sdes			multiplier = WEEKS;
35092555Sdes			break;
35192555Sdes		default:
35292555Sdes			return -1;
35392555Sdes		}
354323136Sdes		if (secs >= LONG_MAX / multiplier)
355323136Sdes			return -1;
356323136Sdes		secs *= multiplier;
357323136Sdes		if  (total >= LONG_MAX - secs)
358323136Sdes			return -1;
35992555Sdes		total += secs;
36092555Sdes		if (total < 0)
36192555Sdes			return -1;
36292555Sdes		p = endp;
36392555Sdes	}
36492555Sdes
36592555Sdes	return total;
36692555Sdes}
36792555Sdes
368146998Sdes/*
369162852Sdes * Returns a standardized host+port identifier string.
370162852Sdes * Caller must free returned string.
371162852Sdes */
372162852Sdeschar *
373162852Sdesput_host_port(const char *host, u_short port)
374162852Sdes{
375162852Sdes	char *hoststr;
376162852Sdes
377162852Sdes	if (port == 0 || port == SSH_DEFAULT_PORT)
378162852Sdes		return(xstrdup(host));
379162852Sdes	if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0)
380162852Sdes		fatal("put_host_port: asprintf: %s", strerror(errno));
381162852Sdes	debug3("put_host_port: %s", hoststr);
382162852Sdes	return hoststr;
383162852Sdes}
384162852Sdes
385162852Sdes/*
386146998Sdes * Search for next delimiter between hostnames/addresses and ports.
387146998Sdes * Argument may be modified (for termination).
388146998Sdes * Returns *cp if parsing succeeds.
389146998Sdes * *cp is set to the start of the next delimiter, if one was found.
390146998Sdes * If this is the last field, *cp is set to NULL.
391146998Sdes */
39292555Sdeschar *
393146998Sdeshpdelim(char **cp)
394146998Sdes{
395146998Sdes	char *s, *old;
396146998Sdes
397146998Sdes	if (cp == NULL || *cp == NULL)
398146998Sdes		return NULL;
399146998Sdes
400146998Sdes	old = s = *cp;
401146998Sdes	if (*s == '[') {
402146998Sdes		if ((s = strchr(s, ']')) == NULL)
403146998Sdes			return NULL;
404146998Sdes		else
405146998Sdes			s++;
406146998Sdes	} else if ((s = strpbrk(s, ":/")) == NULL)
407146998Sdes		s = *cp + strlen(*cp); /* skip to end (see first case below) */
408146998Sdes
409146998Sdes	switch (*s) {
410146998Sdes	case '\0':
411146998Sdes		*cp = NULL;	/* no more fields*/
412146998Sdes		break;
413147001Sdes
414146998Sdes	case ':':
415146998Sdes	case '/':
416146998Sdes		*s = '\0';	/* terminate */
417146998Sdes		*cp = s + 1;
418146998Sdes		break;
419147001Sdes
420146998Sdes	default:
421146998Sdes		return NULL;
422146998Sdes	}
423146998Sdes
424146998Sdes	return old;
425146998Sdes}
426146998Sdes
427146998Sdeschar *
42892555Sdescleanhostname(char *host)
42992555Sdes{
43092555Sdes	if (*host == '[' && host[strlen(host) - 1] == ']') {
43192555Sdes		host[strlen(host) - 1] = '\0';
43292555Sdes		return (host + 1);
43392555Sdes	} else
43492555Sdes		return host;
43592555Sdes}
43692555Sdes
43792555Sdeschar *
43892555Sdescolon(char *cp)
43992555Sdes{
44092555Sdes	int flag = 0;
44192555Sdes
44292555Sdes	if (*cp == ':')		/* Leading colon is part of file name. */
443215116Sdes		return NULL;
44492555Sdes	if (*cp == '[')
44592555Sdes		flag = 1;
44692555Sdes
44792555Sdes	for (; *cp; ++cp) {
44892555Sdes		if (*cp == '@' && *(cp+1) == '[')
44992555Sdes			flag = 1;
45092555Sdes		if (*cp == ']' && *(cp+1) == ':' && flag)
45192555Sdes			return (cp+1);
45292555Sdes		if (*cp == ':' && !flag)
45392555Sdes			return (cp);
45492555Sdes		if (*cp == '/')
455215116Sdes			return NULL;
45692555Sdes	}
457215116Sdes	return NULL;
45892555Sdes}
45992555Sdes
460323129Sdes/*
461323129Sdes * Parse a [user@]host[:port] string.
462323129Sdes * Caller must free returned user and host.
463323129Sdes * Any of the pointer return arguments may be NULL (useful for syntax checking).
464323129Sdes * If user was not specified then *userp will be set to NULL.
465323129Sdes * If port was not specified then *portp will be -1.
466323129Sdes * Returns 0 on success, -1 on failure.
467323129Sdes */
468323129Sdesint
469323129Sdesparse_user_host_port(const char *s, char **userp, char **hostp, int *portp)
470323129Sdes{
471323129Sdes	char *sdup, *cp, *tmp;
472323129Sdes	char *user = NULL, *host = NULL;
473323129Sdes	int port = -1, ret = -1;
474323129Sdes
475323129Sdes	if (userp != NULL)
476323129Sdes		*userp = NULL;
477323129Sdes	if (hostp != NULL)
478323129Sdes		*hostp = NULL;
479323129Sdes	if (portp != NULL)
480323129Sdes		*portp = -1;
481323129Sdes
482323129Sdes	if ((sdup = tmp = strdup(s)) == NULL)
483323129Sdes		return -1;
484323129Sdes	/* Extract optional username */
485323129Sdes	if ((cp = strchr(tmp, '@')) != NULL) {
486323129Sdes		*cp = '\0';
487323129Sdes		if (*tmp == '\0')
488323129Sdes			goto out;
489323129Sdes		if ((user = strdup(tmp)) == NULL)
490323129Sdes			goto out;
491323129Sdes		tmp = cp + 1;
492323129Sdes	}
493323129Sdes	/* Extract mandatory hostname */
494323129Sdes	if ((cp = hpdelim(&tmp)) == NULL || *cp == '\0')
495323129Sdes		goto out;
496323129Sdes	host = xstrdup(cleanhostname(cp));
497323129Sdes	/* Convert and verify optional port */
498323129Sdes	if (tmp != NULL && *tmp != '\0') {
499323129Sdes		if ((port = a2port(tmp)) <= 0)
500323129Sdes			goto out;
501323129Sdes	}
502323129Sdes	/* Success */
503323129Sdes	if (userp != NULL) {
504323129Sdes		*userp = user;
505323129Sdes		user = NULL;
506323129Sdes	}
507323129Sdes	if (hostp != NULL) {
508323129Sdes		*hostp = host;
509323129Sdes		host = NULL;
510323129Sdes	}
511323129Sdes	if (portp != NULL)
512323129Sdes		*portp = port;
513323129Sdes	ret = 0;
514323129Sdes out:
515323129Sdes	free(sdup);
516323129Sdes	free(user);
517323129Sdes	free(host);
518323129Sdes	return ret;
519323129Sdes}
520323129Sdes
52192555Sdes/* function to assist building execv() arguments */
52292555Sdesvoid
52392555Sdesaddargs(arglist *args, char *fmt, ...)
52492555Sdes{
52592555Sdes	va_list ap;
526157016Sdes	char *cp;
527137015Sdes	u_int nalloc;
528157016Sdes	int r;
52992555Sdes
53092555Sdes	va_start(ap, fmt);
531157016Sdes	r = vasprintf(&cp, fmt, ap);
53292555Sdes	va_end(ap);
533157016Sdes	if (r == -1)
534157016Sdes		fatal("addargs: argument too long");
53592555Sdes
536120161Snectar	nalloc = args->nalloc;
53792555Sdes	if (args->list == NULL) {
538120161Snectar		nalloc = 32;
53992555Sdes		args->num = 0;
540120161Snectar	} else if (args->num+2 >= nalloc)
541120161Snectar		nalloc *= 2;
54292555Sdes
543294336Sdes	args->list = xreallocarray(args->list, nalloc, sizeof(char *));
544120161Snectar	args->nalloc = nalloc;
545157016Sdes	args->list[args->num++] = cp;
54692555Sdes	args->list[args->num] = NULL;
54792555Sdes}
548146998Sdes
549157016Sdesvoid
550157016Sdesreplacearg(arglist *args, u_int which, char *fmt, ...)
551157016Sdes{
552157016Sdes	va_list ap;
553157016Sdes	char *cp;
554157016Sdes	int r;
555157016Sdes
556157016Sdes	va_start(ap, fmt);
557157016Sdes	r = vasprintf(&cp, fmt, ap);
558157016Sdes	va_end(ap);
559157016Sdes	if (r == -1)
560157016Sdes		fatal("replacearg: argument too long");
561157016Sdes
562157016Sdes	if (which >= args->num)
563157016Sdes		fatal("replacearg: tried to replace invalid arg %d >= %d",
564157016Sdes		    which, args->num);
565255767Sdes	free(args->list[which]);
566157016Sdes	args->list[which] = cp;
567157016Sdes}
568157016Sdes
569157016Sdesvoid
570157016Sdesfreeargs(arglist *args)
571157016Sdes{
572157016Sdes	u_int i;
573157016Sdes
574157016Sdes	if (args->list != NULL) {
575157016Sdes		for (i = 0; i < args->num; i++)
576255767Sdes			free(args->list[i]);
577255767Sdes		free(args->list);
578157016Sdes		args->nalloc = args->num = 0;
579157016Sdes		args->list = NULL;
580157016Sdes	}
581157016Sdes}
582157016Sdes
583146998Sdes/*
584149749Sdes * Expands tildes in the file name.  Returns data allocated by xmalloc.
585149749Sdes * Warning: this calls getpw*.
586149749Sdes */
587149749Sdeschar *
588149749Sdestilde_expand_filename(const char *filename, uid_t uid)
589149749Sdes{
590255767Sdes	const char *path, *sep;
591255767Sdes	char user[128], *ret;
592149749Sdes	struct passwd *pw;
593149749Sdes	u_int len, slash;
594149749Sdes
595149749Sdes	if (*filename != '~')
596149749Sdes		return (xstrdup(filename));
597149749Sdes	filename++;
598149749Sdes
599149749Sdes	path = strchr(filename, '/');
600149749Sdes	if (path != NULL && path > filename) {		/* ~user/path */
601149749Sdes		slash = path - filename;
602149749Sdes		if (slash > sizeof(user) - 1)
603149749Sdes			fatal("tilde_expand_filename: ~username too long");
604149749Sdes		memcpy(user, filename, slash);
605149749Sdes		user[slash] = '\0';
606149749Sdes		if ((pw = getpwnam(user)) == NULL)
607149749Sdes			fatal("tilde_expand_filename: No such user %s", user);
608149749Sdes	} else if ((pw = getpwuid(uid)) == NULL)	/* ~/path */
609181111Sdes		fatal("tilde_expand_filename: No such uid %ld", (long)uid);
610149749Sdes
611149749Sdes	/* Make sure directory has a trailing '/' */
612149749Sdes	len = strlen(pw->pw_dir);
613255767Sdes	if (len == 0 || pw->pw_dir[len - 1] != '/')
614255767Sdes		sep = "/";
615255767Sdes	else
616255767Sdes		sep = "";
617149749Sdes
618149749Sdes	/* Skip leading '/' from specified path */
619149749Sdes	if (path != NULL)
620149749Sdes		filename = path + 1;
621255767Sdes
622294332Sdes	if (xasprintf(&ret, "%s%s%s", pw->pw_dir, sep, filename) >= PATH_MAX)
623149749Sdes		fatal("tilde_expand_filename: Path too long");
624149749Sdes
625255767Sdes	return (ret);
626149749Sdes}
627149749Sdes
628149749Sdes/*
629149749Sdes * Expand a string with a set of %[char] escapes. A number of escapes may be
630149749Sdes * specified as (char *escape_chars, char *replacement) pairs. The list must
631149749Sdes * be terminated by a NULL escape_char. Returns replaced string in memory
632149749Sdes * allocated by xmalloc.
633149749Sdes */
634149749Sdeschar *
635149749Sdespercent_expand(const char *string, ...)
636149749Sdes{
637149749Sdes#define EXPAND_MAX_KEYS	16
638204917Sdes	u_int num_keys, i, j;
639149749Sdes	struct {
640149749Sdes		const char *key;
641149749Sdes		const char *repl;
642149749Sdes	} keys[EXPAND_MAX_KEYS];
643149749Sdes	char buf[4096];
644149749Sdes	va_list ap;
645149749Sdes
646149749Sdes	/* Gather keys */
647149749Sdes	va_start(ap, string);
648149749Sdes	for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
649149749Sdes		keys[num_keys].key = va_arg(ap, char *);
650149749Sdes		if (keys[num_keys].key == NULL)
651149749Sdes			break;
652149749Sdes		keys[num_keys].repl = va_arg(ap, char *);
653149749Sdes		if (keys[num_keys].repl == NULL)
654204917Sdes			fatal("%s: NULL replacement", __func__);
655149749Sdes	}
656204917Sdes	if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
657204917Sdes		fatal("%s: too many keys", __func__);
658149749Sdes	va_end(ap);
659149749Sdes
660149749Sdes	/* Expand string */
661149749Sdes	*buf = '\0';
662149749Sdes	for (i = 0; *string != '\0'; string++) {
663149749Sdes		if (*string != '%') {
664149749Sdes append:
665149749Sdes			buf[i++] = *string;
666149749Sdes			if (i >= sizeof(buf))
667204917Sdes				fatal("%s: string too long", __func__);
668149749Sdes			buf[i] = '\0';
669149749Sdes			continue;
670149749Sdes		}
671149749Sdes		string++;
672204917Sdes		/* %% case */
673149749Sdes		if (*string == '%')
674149749Sdes			goto append;
675296633Sdes		if (*string == '\0')
676296633Sdes			fatal("%s: invalid format", __func__);
677149749Sdes		for (j = 0; j < num_keys; j++) {
678149749Sdes			if (strchr(keys[j].key, *string) != NULL) {
679149749Sdes				i = strlcat(buf, keys[j].repl, sizeof(buf));
680149749Sdes				if (i >= sizeof(buf))
681204917Sdes					fatal("%s: string too long", __func__);
682149749Sdes				break;
683149749Sdes			}
684149749Sdes		}
685149749Sdes		if (j >= num_keys)
686204917Sdes			fatal("%s: unknown key %%%c", __func__, *string);
687149749Sdes	}
688149749Sdes	return (xstrdup(buf));
689149749Sdes#undef EXPAND_MAX_KEYS
690149749Sdes}
691149749Sdes
692149749Sdes/*
693146998Sdes * Read an entire line from a public key file into a static buffer, discarding
694146998Sdes * lines that exceed the buffer size.  Returns 0 on success, -1 on failure.
695146998Sdes */
696146998Sdesint
697146998Sdesread_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
698146998Sdes   u_long *lineno)
699146998Sdes{
700146998Sdes	while (fgets(buf, bufsz, f) != NULL) {
701181111Sdes		if (buf[0] == '\0')
702181111Sdes			continue;
703146998Sdes		(*lineno)++;
704146998Sdes		if (buf[strlen(buf) - 1] == '\n' || feof(f)) {
705146998Sdes			return 0;
706146998Sdes		} else {
707146998Sdes			debug("%s: %s line %lu exceeds size limit", __func__,
708146998Sdes			    filename, *lineno);
709146998Sdes			/* discard remainder of line */
710147001Sdes			while (fgetc(f) != '\n' && !feof(f))
711146998Sdes				;	/* nothing */
712146998Sdes		}
713146998Sdes	}
714146998Sdes	return -1;
715146998Sdes}
716149749Sdes
717157016Sdesint
718157016Sdestun_open(int tun, int mode)
719157016Sdes{
720157016Sdes#if defined(CUSTOM_SYS_TUN_OPEN)
721157016Sdes	return (sys_tun_open(tun, mode));
722157016Sdes#elif defined(SSH_TUN_OPENBSD)
723157016Sdes	struct ifreq ifr;
724157016Sdes	char name[100];
725157016Sdes	int fd = -1, sock;
726296633Sdes	const char *tunbase = "tun";
727157016Sdes
728296633Sdes	if (mode == SSH_TUNMODE_ETHERNET)
729296633Sdes		tunbase = "tap";
730296633Sdes
731157016Sdes	/* Open the tunnel device */
732157016Sdes	if (tun <= SSH_TUNID_MAX) {
733296633Sdes		snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun);
734157016Sdes		fd = open(name, O_RDWR);
735157016Sdes	} else if (tun == SSH_TUNID_ANY) {
736157016Sdes		for (tun = 100; tun >= 0; tun--) {
737296633Sdes			snprintf(name, sizeof(name), "/dev/%s%d",
738296633Sdes			    tunbase, tun);
739157016Sdes			if ((fd = open(name, O_RDWR)) >= 0)
740157016Sdes				break;
741157016Sdes		}
742157016Sdes	} else {
743157016Sdes		debug("%s: invalid tunnel %u", __func__, tun);
744296633Sdes		return -1;
745157016Sdes	}
746157016Sdes
747157016Sdes	if (fd < 0) {
748296633Sdes		debug("%s: %s open: %s", __func__, name, strerror(errno));
749296633Sdes		return -1;
750157016Sdes	}
751157016Sdes
752157016Sdes	debug("%s: %s mode %d fd %d", __func__, name, mode, fd);
753157016Sdes
754296633Sdes	/* Bring interface up if it is not already */
755296633Sdes	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun);
756157016Sdes	if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
757157016Sdes		goto failed;
758157016Sdes
759296633Sdes	if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) {
760296633Sdes		debug("%s: get interface %s flags: %s", __func__,
761296633Sdes		    ifr.ifr_name, strerror(errno));
762157016Sdes		goto failed;
763296633Sdes	}
764157016Sdes
765296633Sdes	if (!(ifr.ifr_flags & IFF_UP)) {
766296633Sdes		ifr.ifr_flags |= IFF_UP;
767296633Sdes		if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) {
768296633Sdes			debug("%s: activate interface %s: %s", __func__,
769296633Sdes			    ifr.ifr_name, strerror(errno));
770296633Sdes			goto failed;
771296633Sdes		}
772296633Sdes	}
773157016Sdes
774157016Sdes	close(sock);
775296633Sdes	return fd;
776157016Sdes
777157016Sdes failed:
778157016Sdes	if (fd >= 0)
779157016Sdes		close(fd);
780157016Sdes	if (sock >= 0)
781157016Sdes		close(sock);
782296633Sdes	return -1;
783157016Sdes#else
784157016Sdes	error("Tunnel interfaces are not supported on this platform");
785157016Sdes	return (-1);
786157016Sdes#endif
787157016Sdes}
788157016Sdes
789157016Sdesvoid
790157016Sdessanitise_stdfd(void)
791157016Sdes{
792157016Sdes	int nullfd, dupfd;
793157016Sdes
794157016Sdes	if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
795192595Sdes		fprintf(stderr, "Couldn't open /dev/null: %s\n",
796192595Sdes		    strerror(errno));
797157016Sdes		exit(1);
798157016Sdes	}
799323129Sdes	while (++dupfd <= STDERR_FILENO) {
800323129Sdes		/* Only populate closed fds. */
801323129Sdes		if (fcntl(dupfd, F_GETFL) == -1 && errno == EBADF) {
802323129Sdes			if (dup2(nullfd, dupfd) == -1) {
803323129Sdes				fprintf(stderr, "dup2: %s\n", strerror(errno));
804323129Sdes				exit(1);
805323129Sdes			}
806157016Sdes		}
807157016Sdes	}
808323129Sdes	if (nullfd > STDERR_FILENO)
809157016Sdes		close(nullfd);
810157016Sdes}
811157016Sdes
812149749Sdeschar *
813162852Sdestohex(const void *vp, size_t l)
814149749Sdes{
815162852Sdes	const u_char *p = (const u_char *)vp;
816149749Sdes	char b[3], *r;
817162852Sdes	size_t i, hl;
818149749Sdes
819162852Sdes	if (l > 65536)
820162852Sdes		return xstrdup("tohex: length > 65536");
821162852Sdes
822149749Sdes	hl = l * 2 + 1;
823162852Sdes	r = xcalloc(1, hl);
824149749Sdes	for (i = 0; i < l; i++) {
825162852Sdes		snprintf(b, sizeof(b), "%02x", p[i]);
826149749Sdes		strlcat(r, b, hl);
827149749Sdes	}
828149749Sdes	return (r);
829149749Sdes}
830149749Sdes
831162852Sdesu_int64_t
832162852Sdesget_u64(const void *vp)
833162852Sdes{
834162852Sdes	const u_char *p = (const u_char *)vp;
835162852Sdes	u_int64_t v;
836162852Sdes
837162852Sdes	v  = (u_int64_t)p[0] << 56;
838162852Sdes	v |= (u_int64_t)p[1] << 48;
839162852Sdes	v |= (u_int64_t)p[2] << 40;
840162852Sdes	v |= (u_int64_t)p[3] << 32;
841162852Sdes	v |= (u_int64_t)p[4] << 24;
842162852Sdes	v |= (u_int64_t)p[5] << 16;
843162852Sdes	v |= (u_int64_t)p[6] << 8;
844162852Sdes	v |= (u_int64_t)p[7];
845162852Sdes
846162852Sdes	return (v);
847162852Sdes}
848162852Sdes
849162852Sdesu_int32_t
850162852Sdesget_u32(const void *vp)
851162852Sdes{
852162852Sdes	const u_char *p = (const u_char *)vp;
853162852Sdes	u_int32_t v;
854162852Sdes
855162852Sdes	v  = (u_int32_t)p[0] << 24;
856162852Sdes	v |= (u_int32_t)p[1] << 16;
857162852Sdes	v |= (u_int32_t)p[2] << 8;
858162852Sdes	v |= (u_int32_t)p[3];
859162852Sdes
860162852Sdes	return (v);
861162852Sdes}
862162852Sdes
863294328Sdesu_int32_t
864294328Sdesget_u32_le(const void *vp)
865294328Sdes{
866294328Sdes	const u_char *p = (const u_char *)vp;
867294328Sdes	u_int32_t v;
868294328Sdes
869294328Sdes	v  = (u_int32_t)p[0];
870294328Sdes	v |= (u_int32_t)p[1] << 8;
871294328Sdes	v |= (u_int32_t)p[2] << 16;
872294328Sdes	v |= (u_int32_t)p[3] << 24;
873294328Sdes
874294328Sdes	return (v);
875294328Sdes}
876294328Sdes
877162852Sdesu_int16_t
878162852Sdesget_u16(const void *vp)
879162852Sdes{
880162852Sdes	const u_char *p = (const u_char *)vp;
881162852Sdes	u_int16_t v;
882162852Sdes
883162852Sdes	v  = (u_int16_t)p[0] << 8;
884162852Sdes	v |= (u_int16_t)p[1];
885162852Sdes
886162852Sdes	return (v);
887162852Sdes}
888162852Sdes
889162852Sdesvoid
890162852Sdesput_u64(void *vp, u_int64_t v)
891162852Sdes{
892162852Sdes	u_char *p = (u_char *)vp;
893162852Sdes
894162852Sdes	p[0] = (u_char)(v >> 56) & 0xff;
895162852Sdes	p[1] = (u_char)(v >> 48) & 0xff;
896162852Sdes	p[2] = (u_char)(v >> 40) & 0xff;
897162852Sdes	p[3] = (u_char)(v >> 32) & 0xff;
898162852Sdes	p[4] = (u_char)(v >> 24) & 0xff;
899162852Sdes	p[5] = (u_char)(v >> 16) & 0xff;
900162852Sdes	p[6] = (u_char)(v >> 8) & 0xff;
901162852Sdes	p[7] = (u_char)v & 0xff;
902162852Sdes}
903162852Sdes
904162852Sdesvoid
905162852Sdesput_u32(void *vp, u_int32_t v)
906162852Sdes{
907162852Sdes	u_char *p = (u_char *)vp;
908162852Sdes
909162852Sdes	p[0] = (u_char)(v >> 24) & 0xff;
910162852Sdes	p[1] = (u_char)(v >> 16) & 0xff;
911162852Sdes	p[2] = (u_char)(v >> 8) & 0xff;
912162852Sdes	p[3] = (u_char)v & 0xff;
913162852Sdes}
914162852Sdes
915294328Sdesvoid
916294328Sdesput_u32_le(void *vp, u_int32_t v)
917294328Sdes{
918294328Sdes	u_char *p = (u_char *)vp;
919162852Sdes
920294328Sdes	p[0] = (u_char)v & 0xff;
921294328Sdes	p[1] = (u_char)(v >> 8) & 0xff;
922294328Sdes	p[2] = (u_char)(v >> 16) & 0xff;
923294328Sdes	p[3] = (u_char)(v >> 24) & 0xff;
924294328Sdes}
925294328Sdes
926162852Sdesvoid
927162852Sdesput_u16(void *vp, u_int16_t v)
928162852Sdes{
929162852Sdes	u_char *p = (u_char *)vp;
930162852Sdes
931162852Sdes	p[0] = (u_char)(v >> 8) & 0xff;
932162852Sdes	p[1] = (u_char)v & 0xff;
933162852Sdes}
934181111Sdes
935181111Sdesvoid
936181111Sdesms_subtract_diff(struct timeval *start, int *ms)
937181111Sdes{
938181111Sdes	struct timeval diff, finish;
939181111Sdes
940181111Sdes	gettimeofday(&finish, NULL);
941181111Sdes	timersub(&finish, start, &diff);
942181111Sdes	*ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
943181111Sdes}
944181111Sdes
945181111Sdesvoid
946181111Sdesms_to_timeval(struct timeval *tv, int ms)
947181111Sdes{
948181111Sdes	if (ms < 0)
949181111Sdes		ms = 0;
950181111Sdes	tv->tv_sec = ms / 1000;
951181111Sdes	tv->tv_usec = (ms % 1000) * 1000;
952181111Sdes}
953181111Sdes
954255767Sdestime_t
955255767Sdesmonotime(void)
956255767Sdes{
957294328Sdes#if defined(HAVE_CLOCK_GETTIME) && \
958294328Sdes    (defined(CLOCK_MONOTONIC) || defined(CLOCK_BOOTTIME))
959255767Sdes	struct timespec ts;
960255767Sdes	static int gettime_failed = 0;
961255767Sdes
962255767Sdes	if (!gettime_failed) {
963294328Sdes#if defined(CLOCK_BOOTTIME)
964294328Sdes		if (clock_gettime(CLOCK_BOOTTIME, &ts) == 0)
965294328Sdes			return (ts.tv_sec);
966294328Sdes#endif
967294328Sdes#if defined(CLOCK_MONOTONIC)
968255767Sdes		if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
969255767Sdes			return (ts.tv_sec);
970294328Sdes#endif
971255767Sdes		debug3("clock_gettime: %s", strerror(errno));
972255767Sdes		gettime_failed = 1;
973255767Sdes	}
974294328Sdes#endif /* HAVE_CLOCK_GETTIME && (CLOCK_MONOTONIC || CLOCK_BOOTTIME */
975255767Sdes
976255767Sdes	return time(NULL);
977255767Sdes}
978255767Sdes
979323129Sdesdouble
980323129Sdesmonotime_double(void)
981323129Sdes{
982323129Sdes#if defined(HAVE_CLOCK_GETTIME) && \
983323129Sdes    (defined(CLOCK_MONOTONIC) || defined(CLOCK_BOOTTIME))
984323129Sdes	struct timespec ts;
985323129Sdes	static int gettime_failed = 0;
986323129Sdes
987323129Sdes	if (!gettime_failed) {
988323129Sdes#if defined(CLOCK_BOOTTIME)
989323129Sdes		if (clock_gettime(CLOCK_BOOTTIME, &ts) == 0)
990323129Sdes			return (ts.tv_sec + (double)ts.tv_nsec / 1000000000);
991323129Sdes#endif
992323129Sdes#if defined(CLOCK_MONOTONIC)
993323129Sdes		if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
994323129Sdes			return (ts.tv_sec + (double)ts.tv_nsec / 1000000000);
995323129Sdes#endif
996323129Sdes		debug3("clock_gettime: %s", strerror(errno));
997323129Sdes		gettime_failed = 1;
998323129Sdes	}
999323129Sdes#endif /* HAVE_CLOCK_GETTIME && (CLOCK_MONOTONIC || CLOCK_BOOTTIME */
1000323129Sdes
1001323129Sdes	return (double)time(NULL);
1002323129Sdes}
1003323129Sdes
1004221420Sdesvoid
1005221420Sdesbandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen)
1006221420Sdes{
1007221420Sdes	bw->buflen = buflen;
1008221420Sdes	bw->rate = kbps;
1009221420Sdes	bw->thresh = bw->rate;
1010221420Sdes	bw->lamt = 0;
1011221420Sdes	timerclear(&bw->bwstart);
1012221420Sdes	timerclear(&bw->bwend);
1013221420Sdes}
1014221420Sdes
1015221420Sdes/* Callback from read/write loop to insert bandwidth-limiting delays */
1016221420Sdesvoid
1017221420Sdesbandwidth_limit(struct bwlimit *bw, size_t read_len)
1018221420Sdes{
1019221420Sdes	u_int64_t waitlen;
1020221420Sdes	struct timespec ts, rm;
1021221420Sdes
1022221420Sdes	if (!timerisset(&bw->bwstart)) {
1023221420Sdes		gettimeofday(&bw->bwstart, NULL);
1024221420Sdes		return;
1025221420Sdes	}
1026221420Sdes
1027221420Sdes	bw->lamt += read_len;
1028221420Sdes	if (bw->lamt < bw->thresh)
1029221420Sdes		return;
1030221420Sdes
1031221420Sdes	gettimeofday(&bw->bwend, NULL);
1032221420Sdes	timersub(&bw->bwend, &bw->bwstart, &bw->bwend);
1033221420Sdes	if (!timerisset(&bw->bwend))
1034221420Sdes		return;
1035221420Sdes
1036221420Sdes	bw->lamt *= 8;
1037221420Sdes	waitlen = (double)1000000L * bw->lamt / bw->rate;
1038221420Sdes
1039221420Sdes	bw->bwstart.tv_sec = waitlen / 1000000L;
1040221420Sdes	bw->bwstart.tv_usec = waitlen % 1000000L;
1041221420Sdes
1042221420Sdes	if (timercmp(&bw->bwstart, &bw->bwend, >)) {
1043221420Sdes		timersub(&bw->bwstart, &bw->bwend, &bw->bwend);
1044221420Sdes
1045221420Sdes		/* Adjust the wait time */
1046221420Sdes		if (bw->bwend.tv_sec) {
1047221420Sdes			bw->thresh /= 2;
1048221420Sdes			if (bw->thresh < bw->buflen / 4)
1049221420Sdes				bw->thresh = bw->buflen / 4;
1050221420Sdes		} else if (bw->bwend.tv_usec < 10000) {
1051221420Sdes			bw->thresh *= 2;
1052221420Sdes			if (bw->thresh > bw->buflen * 8)
1053221420Sdes				bw->thresh = bw->buflen * 8;
1054221420Sdes		}
1055221420Sdes
1056221420Sdes		TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts);
1057221420Sdes		while (nanosleep(&ts, &rm) == -1) {
1058221420Sdes			if (errno != EINTR)
1059221420Sdes				break;
1060221420Sdes			ts = rm;
1061221420Sdes		}
1062221420Sdes	}
1063221420Sdes
1064221420Sdes	bw->lamt = 0;
1065221420Sdes	gettimeofday(&bw->bwstart, NULL);
1066221420Sdes}
1067221420Sdes
1068221420Sdes/* Make a template filename for mk[sd]temp() */
1069221420Sdesvoid
1070221420Sdesmktemp_proto(char *s, size_t len)
1071221420Sdes{
1072221420Sdes	const char *tmpdir;
1073221420Sdes	int r;
1074221420Sdes
1075221420Sdes	if ((tmpdir = getenv("TMPDIR")) != NULL) {
1076221420Sdes		r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir);
1077221420Sdes		if (r > 0 && (size_t)r < len)
1078221420Sdes			return;
1079221420Sdes	}
1080221420Sdes	r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX");
1081221420Sdes	if (r < 0 || (size_t)r >= len)
1082221420Sdes		fatal("%s: template string too short", __func__);
1083221420Sdes}
1084221420Sdes
1085221420Sdesstatic const struct {
1086221420Sdes	const char *name;
1087221420Sdes	int value;
1088221420Sdes} ipqos[] = {
1089221420Sdes	{ "af11", IPTOS_DSCP_AF11 },
1090221420Sdes	{ "af12", IPTOS_DSCP_AF12 },
1091221420Sdes	{ "af13", IPTOS_DSCP_AF13 },
1092240075Sdes	{ "af21", IPTOS_DSCP_AF21 },
1093221420Sdes	{ "af22", IPTOS_DSCP_AF22 },
1094221420Sdes	{ "af23", IPTOS_DSCP_AF23 },
1095221420Sdes	{ "af31", IPTOS_DSCP_AF31 },
1096221420Sdes	{ "af32", IPTOS_DSCP_AF32 },
1097221420Sdes	{ "af33", IPTOS_DSCP_AF33 },
1098221420Sdes	{ "af41", IPTOS_DSCP_AF41 },
1099221420Sdes	{ "af42", IPTOS_DSCP_AF42 },
1100221420Sdes	{ "af43", IPTOS_DSCP_AF43 },
1101221420Sdes	{ "cs0", IPTOS_DSCP_CS0 },
1102221420Sdes	{ "cs1", IPTOS_DSCP_CS1 },
1103221420Sdes	{ "cs2", IPTOS_DSCP_CS2 },
1104221420Sdes	{ "cs3", IPTOS_DSCP_CS3 },
1105221420Sdes	{ "cs4", IPTOS_DSCP_CS4 },
1106221420Sdes	{ "cs5", IPTOS_DSCP_CS5 },
1107221420Sdes	{ "cs6", IPTOS_DSCP_CS6 },
1108221420Sdes	{ "cs7", IPTOS_DSCP_CS7 },
1109221420Sdes	{ "ef", IPTOS_DSCP_EF },
1110221420Sdes	{ "lowdelay", IPTOS_LOWDELAY },
1111221420Sdes	{ "throughput", IPTOS_THROUGHPUT },
1112221420Sdes	{ "reliability", IPTOS_RELIABILITY },
1113221420Sdes	{ NULL, -1 }
1114221420Sdes};
1115221420Sdes
1116215116Sdesint
1117221420Sdesparse_ipqos(const char *cp)
1118215116Sdes{
1119221420Sdes	u_int i;
1120221420Sdes	char *ep;
1121221420Sdes	long val;
1122215116Sdes
1123221420Sdes	if (cp == NULL)
1124221420Sdes		return -1;
1125221420Sdes	for (i = 0; ipqos[i].name != NULL; i++) {
1126221420Sdes		if (strcasecmp(cp, ipqos[i].name) == 0)
1127221420Sdes			return ipqos[i].value;
1128221420Sdes	}
1129221420Sdes	/* Try parsing as an integer */
1130221420Sdes	val = strtol(cp, &ep, 0);
1131221420Sdes	if (*cp == '\0' || *ep != '\0' || val < 0 || val > 255)
1132221420Sdes		return -1;
1133221420Sdes	return val;
1134215116Sdes}
1135221420Sdes
1136226046Sdesconst char *
1137226046Sdesiptos2str(int iptos)
1138226046Sdes{
1139226046Sdes	int i;
1140226046Sdes	static char iptos_str[sizeof "0xff"];
1141226046Sdes
1142226046Sdes	for (i = 0; ipqos[i].name != NULL; i++) {
1143226046Sdes		if (ipqos[i].value == iptos)
1144226046Sdes			return ipqos[i].name;
1145226046Sdes	}
1146226046Sdes	snprintf(iptos_str, sizeof iptos_str, "0x%02x", iptos);
1147226046Sdes	return iptos_str;
1148226046Sdes}
1149261320Sdes
1150204917Sdesvoid
1151261320Sdeslowercase(char *s)
1152261320Sdes{
1153261320Sdes	for (; *s; s++)
1154261320Sdes		*s = tolower((u_char)*s);
1155261320Sdes}
1156294328Sdes
1157294328Sdesint
1158294328Sdesunix_listener(const char *path, int backlog, int unlink_first)
1159294328Sdes{
1160294328Sdes	struct sockaddr_un sunaddr;
1161294328Sdes	int saved_errno, sock;
1162294328Sdes
1163294328Sdes	memset(&sunaddr, 0, sizeof(sunaddr));
1164294328Sdes	sunaddr.sun_family = AF_UNIX;
1165294328Sdes	if (strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) {
1166294328Sdes		error("%s: \"%s\" too long for Unix domain socket", __func__,
1167294328Sdes		    path);
1168294328Sdes		errno = ENAMETOOLONG;
1169294328Sdes		return -1;
1170294328Sdes	}
1171294328Sdes
1172294328Sdes	sock = socket(PF_UNIX, SOCK_STREAM, 0);
1173294328Sdes	if (sock < 0) {
1174294328Sdes		saved_errno = errno;
1175294328Sdes		error("socket: %.100s", strerror(errno));
1176294328Sdes		errno = saved_errno;
1177294328Sdes		return -1;
1178294328Sdes	}
1179294328Sdes	if (unlink_first == 1) {
1180294328Sdes		if (unlink(path) != 0 && errno != ENOENT)
1181294328Sdes			error("unlink(%s): %.100s", path, strerror(errno));
1182294328Sdes	}
1183294328Sdes	if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
1184294328Sdes		saved_errno = errno;
1185294328Sdes		error("bind: %.100s", strerror(errno));
1186294328Sdes		close(sock);
1187294328Sdes		error("%s: cannot bind to path: %s", __func__, path);
1188294328Sdes		errno = saved_errno;
1189294328Sdes		return -1;
1190294328Sdes	}
1191294328Sdes	if (listen(sock, backlog) < 0) {
1192294328Sdes		saved_errno = errno;
1193294328Sdes		error("listen: %.100s", strerror(errno));
1194294328Sdes		close(sock);
1195294328Sdes		unlink(path);
1196294328Sdes		error("%s: cannot listen on path: %s", __func__, path);
1197294328Sdes		errno = saved_errno;
1198294328Sdes		return -1;
1199294328Sdes	}
1200294328Sdes	return sock;
1201294328Sdes}
1202294328Sdes
1203261320Sdesvoid
1204204917Sdessock_set_v6only(int s)
1205204917Sdes{
1206296633Sdes#if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
1207204917Sdes	int on = 1;
1208204917Sdes
1209204917Sdes	debug3("%s: set socket %d IPV6_V6ONLY", __func__, s);
1210204917Sdes	if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1)
1211204917Sdes		error("setsockopt IPV6_V6ONLY: %s", strerror(errno));
1212204917Sdes#endif
1213204917Sdes}
1214323129Sdes
1215323129Sdes/*
1216323129Sdes * Compares two strings that maybe be NULL. Returns non-zero if strings
1217323129Sdes * are both NULL or are identical, returns zero otherwise.
1218323129Sdes */
1219323129Sdesstatic int
1220323129Sdesstrcmp_maybe_null(const char *a, const char *b)
1221323129Sdes{
1222323129Sdes	if ((a == NULL && b != NULL) || (a != NULL && b == NULL))
1223323129Sdes		return 0;
1224323129Sdes	if (a != NULL && strcmp(a, b) != 0)
1225323129Sdes		return 0;
1226323129Sdes	return 1;
1227323129Sdes}
1228323129Sdes
1229323129Sdes/*
1230323129Sdes * Compare two forwards, returning non-zero if they are identical or
1231323129Sdes * zero otherwise.
1232323129Sdes */
1233323129Sdesint
1234323129Sdesforward_equals(const struct Forward *a, const struct Forward *b)
1235323129Sdes{
1236323129Sdes	if (strcmp_maybe_null(a->listen_host, b->listen_host) == 0)
1237323129Sdes		return 0;
1238323129Sdes	if (a->listen_port != b->listen_port)
1239323129Sdes		return 0;
1240323129Sdes	if (strcmp_maybe_null(a->listen_path, b->listen_path) == 0)
1241323129Sdes		return 0;
1242323129Sdes	if (strcmp_maybe_null(a->connect_host, b->connect_host) == 0)
1243323129Sdes		return 0;
1244323129Sdes	if (a->connect_port != b->connect_port)
1245323129Sdes		return 0;
1246323129Sdes	if (strcmp_maybe_null(a->connect_path, b->connect_path) == 0)
1247323129Sdes		return 0;
1248323129Sdes	/* allocated_port and handle are not checked */
1249323129Sdes	return 1;
1250323129Sdes}
1251323129Sdes
1252323134Sdesstatic int
1253323134Sdesipport_reserved(void)
1254323134Sdes{
1255323134Sdes#if __FreeBSD__
1256323134Sdes	int old, ret;
1257323134Sdes	size_t len = sizeof(old);
1258323134Sdes
1259323134Sdes	ret = sysctlbyname("net.inet.ip.portrange.reservedhigh",
1260323134Sdes	    &old, &len, NULL, 0);
1261323134Sdes	if (ret == 0)
1262323134Sdes		return (old + 1);
1263323134Sdes#endif
1264323134Sdes	return (IPPORT_RESERVED);
1265323134Sdes}
1266323134Sdes
1267323134Sdes/* returns 1 if bind to specified port by specified user is permitted */
1268323134Sdesint
1269323134Sdesbind_permitted(int port, uid_t uid)
1270323134Sdes{
1271323134Sdes
1272323134Sdes	if (port < ipport_reserved() && uid != 0)
1273323134Sdes		return 0;
1274323134Sdes	return 1;
1275323134Sdes}
1276323134Sdes
1277323134Sdes/* returns 1 if process is already daemonized, 0 otherwise */
1278323134Sdesint
1279323134Sdesdaemonized(void)
1280323134Sdes{
1281323134Sdes	int fd;
1282323134Sdes
1283323134Sdes	if ((fd = open(_PATH_TTY, O_RDONLY | O_NOCTTY)) >= 0) {
1284323134Sdes		close(fd);
1285323134Sdes		return 0;	/* have controlling terminal */
1286323134Sdes	}
1287323134Sdes	if (getppid() != 1)
1288323134Sdes		return 0;	/* parent is not init */
1289323134Sdes	if (getsid(0) != getpid())
1290323134Sdes		return 0;	/* not session leader */
1291323134Sdes	debug3("already daemonized");
1292323134Sdes	return 1;
1293323134Sdes}
1294