xref: /freebsd/crypto/openssh/readconf.c (revision f7167e0ea0bf5aaabff9490453b3b71b3f1b4d51)
1*f7167e0eSDag-Erling Smørgrav /* $OpenBSD: readconf.c,v 1.215 2013/12/06 13:39:49 markus Exp $ */
289986192SBrooks Davis /* $FreeBSD$ */
3511b41d2SMark Murray /*
4511b41d2SMark Murray  * Author: Tatu Ylonen <ylo@cs.hut.fi>
5511b41d2SMark Murray  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
6511b41d2SMark Murray  *                    All rights reserved
7511b41d2SMark Murray  * Functions for reading the configuration files.
8511b41d2SMark Murray  *
9c2d3a559SKris Kennaway  * As far as I am concerned, the code I have written for this software
10c2d3a559SKris Kennaway  * can be used freely for any purpose.  Any derived versions of this
11c2d3a559SKris Kennaway  * software must be clearly marked as such, and if the derived work is
12c2d3a559SKris Kennaway  * incompatible with the protocol description in the RFC file, it must be
13c2d3a559SKris Kennaway  * called by a name other than "ssh" or "Secure Shell".
14511b41d2SMark Murray  */
15511b41d2SMark Murray 
16511b41d2SMark Murray #include "includes.h"
17333ee039SDag-Erling Smørgrav __RCSID("$FreeBSD$");
18511b41d2SMark Murray 
19333ee039SDag-Erling Smørgrav #include <sys/types.h>
20333ee039SDag-Erling Smørgrav #include <sys/stat.h>
21333ee039SDag-Erling Smørgrav #include <sys/socket.h>
2203f6c5cdSDag-Erling Smørgrav #include <sys/sysctl.h>
23*f7167e0eSDag-Erling Smørgrav #include <sys/wait.h>
24333ee039SDag-Erling Smørgrav 
25333ee039SDag-Erling Smørgrav #include <netinet/in.h>
264a421b63SDag-Erling Smørgrav #include <netinet/in_systm.h>
274a421b63SDag-Erling Smørgrav #include <netinet/ip.h>
28333ee039SDag-Erling Smørgrav 
29333ee039SDag-Erling Smørgrav #include <ctype.h>
30333ee039SDag-Erling Smørgrav #include <errno.h>
31*f7167e0eSDag-Erling Smørgrav #include <fcntl.h>
32333ee039SDag-Erling Smørgrav #include <netdb.h>
33*f7167e0eSDag-Erling Smørgrav #ifdef HAVE_PATHS_H
34*f7167e0eSDag-Erling Smørgrav # include <paths.h>
35*f7167e0eSDag-Erling Smørgrav #endif
36*f7167e0eSDag-Erling Smørgrav #include <pwd.h>
37333ee039SDag-Erling Smørgrav #include <signal.h>
38333ee039SDag-Erling Smørgrav #include <stdarg.h>
39333ee039SDag-Erling Smørgrav #include <stdio.h>
40333ee039SDag-Erling Smørgrav #include <string.h>
41333ee039SDag-Erling Smørgrav #include <unistd.h>
42e4a9863fSDag-Erling Smørgrav #ifdef HAVE_UTIL_H
43e4a9863fSDag-Erling Smørgrav #include <util.h>
44e4a9863fSDag-Erling Smørgrav #endif
45333ee039SDag-Erling Smørgrav 
46511b41d2SMark Murray #include "xmalloc.h"
47333ee039SDag-Erling Smørgrav #include "ssh.h"
48e8aafc91SKris Kennaway #include "compat.h"
49ca3176e7SBrian Feldman #include "cipher.h"
50ca3176e7SBrian Feldman #include "pathnames.h"
51ca3176e7SBrian Feldman #include "log.h"
52333ee039SDag-Erling Smørgrav #include "key.h"
53ca3176e7SBrian Feldman #include "readconf.h"
54ca3176e7SBrian Feldman #include "match.h"
55ca3176e7SBrian Feldman #include "misc.h"
56333ee039SDag-Erling Smørgrav #include "buffer.h"
57ca3176e7SBrian Feldman #include "kex.h"
58ca3176e7SBrian Feldman #include "mac.h"
59*f7167e0eSDag-Erling Smørgrav #include "uidswap.h"
60cce7d346SDag-Erling Smørgrav #include "version.h"
61511b41d2SMark Murray 
62511b41d2SMark Murray /* Format of the configuration file:
63511b41d2SMark Murray 
64511b41d2SMark Murray    # Configuration data is parsed as follows:
65511b41d2SMark Murray    #  1. command line options
66511b41d2SMark Murray    #  2. user-specific file
67511b41d2SMark Murray    #  3. system-wide file
68511b41d2SMark Murray    # Any configuration value is only changed the first time it is set.
69511b41d2SMark Murray    # Thus, host-specific definitions should be at the beginning of the
70511b41d2SMark Murray    # configuration file, and defaults at the end.
71511b41d2SMark Murray 
72511b41d2SMark Murray    # Host-specific declarations.  These may override anything above.  A single
73511b41d2SMark Murray    # host may match multiple declarations; these are processed in the order
74511b41d2SMark Murray    # that they are given in.
75511b41d2SMark Murray 
76511b41d2SMark Murray    Host *.ngs.fi ngs.fi
7780628bacSDag-Erling Smørgrav      User foo
78511b41d2SMark Murray 
79511b41d2SMark Murray    Host fake.com
80511b41d2SMark Murray      HostName another.host.name.real.org
81511b41d2SMark Murray      User blaah
82511b41d2SMark Murray      Port 34289
83511b41d2SMark Murray      ForwardX11 no
84511b41d2SMark Murray      ForwardAgent no
85511b41d2SMark Murray 
86511b41d2SMark Murray    Host books.com
87511b41d2SMark Murray      RemoteForward 9999 shadows.cs.hut.fi:9999
88511b41d2SMark Murray      Cipher 3des
89511b41d2SMark Murray 
90511b41d2SMark Murray    Host fascist.blob.com
91511b41d2SMark Murray      Port 23123
92511b41d2SMark Murray      User tylonen
93511b41d2SMark Murray      PasswordAuthentication no
94511b41d2SMark Murray 
95511b41d2SMark Murray    Host puukko.hut.fi
96511b41d2SMark Murray      User t35124p
97511b41d2SMark Murray      ProxyCommand ssh-proxy %h %p
98511b41d2SMark Murray 
99511b41d2SMark Murray    Host *.fr
10080628bacSDag-Erling Smørgrav      PublicKeyAuthentication no
101511b41d2SMark Murray 
102511b41d2SMark Murray    Host *.su
103511b41d2SMark Murray      Cipher none
104511b41d2SMark Murray      PasswordAuthentication no
105511b41d2SMark Murray 
106b74df5b2SDag-Erling Smørgrav    Host vpn.fake.com
107b74df5b2SDag-Erling Smørgrav      Tunnel yes
108b74df5b2SDag-Erling Smørgrav      TunnelDevice 3
109b74df5b2SDag-Erling Smørgrav 
110511b41d2SMark Murray    # Defaults for various options
111511b41d2SMark Murray    Host *
112511b41d2SMark Murray      ForwardAgent no
113ca3176e7SBrian Feldman      ForwardX11 no
114511b41d2SMark Murray      PasswordAuthentication yes
115511b41d2SMark Murray      RSAAuthentication yes
116511b41d2SMark Murray      RhostsRSAAuthentication yes
117511b41d2SMark Murray      StrictHostKeyChecking yes
1181ec0d754SDag-Erling Smørgrav      TcpKeepAlive no
119511b41d2SMark Murray      IdentityFile ~/.ssh/identity
120511b41d2SMark Murray      Port 22
121511b41d2SMark Murray      EscapeChar ~
122511b41d2SMark Murray 
123511b41d2SMark Murray */
124511b41d2SMark Murray 
125511b41d2SMark Murray /* Keyword tokens. */
126511b41d2SMark Murray 
127511b41d2SMark Murray typedef enum {
128511b41d2SMark Murray 	oBadOption,
129*f7167e0eSDag-Erling Smørgrav 	oHost, oMatch,
130e2f6069cSDag-Erling Smørgrav 	oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
131e2f6069cSDag-Erling Smørgrav 	oGatewayPorts, oExitOnForwardFailure,
13280628bacSDag-Erling Smørgrav 	oPasswordAuthentication, oRSAAuthentication,
133ca3176e7SBrian Feldman 	oChallengeResponseAuthentication, oXAuthLocation,
134511b41d2SMark Murray 	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
135*f7167e0eSDag-Erling Smørgrav 	oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
136511b41d2SMark Murray 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
137511b41d2SMark Murray 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
1381ec0d754SDag-Erling Smørgrav 	oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
139ca3176e7SBrian Feldman 	oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
140ca3176e7SBrian Feldman 	oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
141ca3176e7SBrian Feldman 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
142ca3176e7SBrian Feldman 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
143b15c8340SDag-Erling Smørgrav 	oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
1449e2cbe04SDag-Erling Smørgrav 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
145cf2b5f3bSDag-Erling Smørgrav 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
146cf2b5f3bSDag-Erling Smørgrav 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
1475962c0e9SDag-Erling Smørgrav 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
148e2f6069cSDag-Erling Smørgrav 	oSendEnv, oControlPath, oControlMaster, oControlPersist,
149e2f6069cSDag-Erling Smørgrav 	oHashKnownHosts,
150b74df5b2SDag-Erling Smørgrav 	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
1517aee6ffeSDag-Erling Smørgrav 	oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
152*f7167e0eSDag-Erling Smørgrav 	oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
153*f7167e0eSDag-Erling Smørgrav 	oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
154*f7167e0eSDag-Erling Smørgrav 	oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
155e4a9863fSDag-Erling Smørgrav 	oIgnoredUnknownOption,
15689986192SBrooks Davis 	oHPNDisabled, oHPNBufferSize, oTcpRcvBufPoll, oTcpRcvBuf,
15789986192SBrooks Davis #ifdef NONE_CIPHER_ENABLED
15889986192SBrooks Davis 	oNoneEnabled, oNoneSwitch,
15989986192SBrooks Davis #endif
160e4a9863fSDag-Erling Smørgrav 	oVersionAddendum, oDeprecated, oUnsupported
161511b41d2SMark Murray } OpCodes;
162511b41d2SMark Murray 
163511b41d2SMark Murray /* Textual representations of the tokens. */
164511b41d2SMark Murray 
165511b41d2SMark Murray static struct {
166511b41d2SMark Murray 	const char *name;
167511b41d2SMark Murray 	OpCodes opcode;
168511b41d2SMark Murray } keywords[] = {
169511b41d2SMark Murray 	{ "forwardagent", oForwardAgent },
170511b41d2SMark Murray 	{ "forwardx11", oForwardX11 },
1711ec0d754SDag-Erling Smørgrav 	{ "forwardx11trusted", oForwardX11Trusted },
172e2f6069cSDag-Erling Smørgrav 	{ "forwardx11timeout", oForwardX11Timeout },
173333ee039SDag-Erling Smørgrav 	{ "exitonforwardfailure", oExitOnForwardFailure },
174c2d3a559SKris Kennaway 	{ "xauthlocation", oXAuthLocation },
175511b41d2SMark Murray 	{ "gatewayports", oGatewayPorts },
176511b41d2SMark Murray 	{ "useprivilegedport", oUsePrivilegedPort },
177cf2b5f3bSDag-Erling Smørgrav 	{ "rhostsauthentication", oDeprecated },
178511b41d2SMark Murray 	{ "passwordauthentication", oPasswordAuthentication },
17909958426SBrian Feldman 	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
18009958426SBrian Feldman 	{ "kbdinteractivedevices", oKbdInteractiveDevices },
181511b41d2SMark Murray 	{ "rsaauthentication", oRSAAuthentication },
182ca3176e7SBrian Feldman 	{ "pubkeyauthentication", oPubkeyAuthentication },
183ca3176e7SBrian Feldman 	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
184ca3176e7SBrian Feldman 	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
185ca3176e7SBrian Feldman 	{ "hostbasedauthentication", oHostbasedAuthentication },
186ca3176e7SBrian Feldman 	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
187ca3176e7SBrian Feldman 	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
188ca3176e7SBrian Feldman 	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
189cf2b5f3bSDag-Erling Smørgrav 	{ "kerberosauthentication", oUnsupported },
190cf2b5f3bSDag-Erling Smørgrav 	{ "kerberostgtpassing", oUnsupported },
191cf2b5f3bSDag-Erling Smørgrav 	{ "afstokenpassing", oUnsupported },
192cf2b5f3bSDag-Erling Smørgrav #if defined(GSSAPI)
193cf2b5f3bSDag-Erling Smørgrav 	{ "gssapiauthentication", oGssAuthentication },
194cf2b5f3bSDag-Erling Smørgrav 	{ "gssapidelegatecredentials", oGssDelegateCreds },
195cf2b5f3bSDag-Erling Smørgrav #else
196cf2b5f3bSDag-Erling Smørgrav 	{ "gssapiauthentication", oUnsupported },
197cf2b5f3bSDag-Erling Smørgrav 	{ "gssapidelegatecredentials", oUnsupported },
198511b41d2SMark Murray #endif
19980628bacSDag-Erling Smørgrav 	{ "fallbacktorsh", oDeprecated },
20080628bacSDag-Erling Smørgrav 	{ "usersh", oDeprecated },
201511b41d2SMark Murray 	{ "identityfile", oIdentityFile },
202cce7d346SDag-Erling Smørgrav 	{ "identityfile2", oIdentityFile },			/* obsolete */
2035962c0e9SDag-Erling Smørgrav 	{ "identitiesonly", oIdentitiesOnly },
204511b41d2SMark Murray 	{ "hostname", oHostName },
205ca3176e7SBrian Feldman 	{ "hostkeyalias", oHostKeyAlias },
206511b41d2SMark Murray 	{ "proxycommand", oProxyCommand },
207511b41d2SMark Murray 	{ "port", oPort },
208511b41d2SMark Murray 	{ "cipher", oCipher },
209e8aafc91SKris Kennaway 	{ "ciphers", oCiphers },
210ca3176e7SBrian Feldman 	{ "macs", oMacs },
211e8aafc91SKris Kennaway 	{ "protocol", oProtocol },
212511b41d2SMark Murray 	{ "remoteforward", oRemoteForward },
213511b41d2SMark Murray 	{ "localforward", oLocalForward },
214511b41d2SMark Murray 	{ "user", oUser },
215511b41d2SMark Murray 	{ "host", oHost },
216*f7167e0eSDag-Erling Smørgrav 	{ "match", oMatch },
217511b41d2SMark Murray 	{ "escapechar", oEscapeChar },
218511b41d2SMark Murray 	{ "globalknownhostsfile", oGlobalKnownHostsFile },
219e146993eSDag-Erling Smørgrav 	{ "globalknownhostsfile2", oDeprecated },
220cce7d346SDag-Erling Smørgrav 	{ "userknownhostsfile", oUserKnownHostsFile },
221e146993eSDag-Erling Smørgrav 	{ "userknownhostsfile2", oDeprecated },
222511b41d2SMark Murray 	{ "connectionattempts", oConnectionAttempts },
223511b41d2SMark Murray 	{ "batchmode", oBatchMode },
224511b41d2SMark Murray 	{ "checkhostip", oCheckHostIP },
225511b41d2SMark Murray 	{ "stricthostkeychecking", oStrictHostKeyChecking },
226511b41d2SMark Murray 	{ "compression", oCompression },
227511b41d2SMark Murray 	{ "compressionlevel", oCompressionLevel },
2281ec0d754SDag-Erling Smørgrav 	{ "tcpkeepalive", oTCPKeepAlive },
2291ec0d754SDag-Erling Smørgrav 	{ "keepalive", oTCPKeepAlive },				/* obsolete */
230511b41d2SMark Murray 	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
231511b41d2SMark Murray 	{ "loglevel", oLogLevel },
232ca3176e7SBrian Feldman 	{ "dynamicforward", oDynamicForward },
233ca3176e7SBrian Feldman 	{ "preferredauthentications", oPreferredAuthentications },
234ca3176e7SBrian Feldman 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
235af12a3e7SDag-Erling Smørgrav 	{ "bindaddress", oBindAddress },
236b15c8340SDag-Erling Smørgrav #ifdef ENABLE_PKCS11
237b15c8340SDag-Erling Smørgrav 	{ "smartcarddevice", oPKCS11Provider },
238b15c8340SDag-Erling Smørgrav 	{ "pkcs11provider", oPKCS11Provider },
239cf2b5f3bSDag-Erling Smørgrav #else
240cf2b5f3bSDag-Erling Smørgrav 	{ "smartcarddevice", oUnsupported },
241b15c8340SDag-Erling Smørgrav 	{ "pkcs11provider", oUnsupported },
242cf2b5f3bSDag-Erling Smørgrav #endif
243af12a3e7SDag-Erling Smørgrav 	{ "clearallforwardings", oClearAllForwardings },
244e73e9afaSDag-Erling Smørgrav 	{ "enablesshkeysign", oEnableSSHKeysign },
245cf2b5f3bSDag-Erling Smørgrav 	{ "verifyhostkeydns", oVerifyHostKeyDNS },
246af12a3e7SDag-Erling Smørgrav 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
247cf2b5f3bSDag-Erling Smørgrav 	{ "rekeylimit", oRekeyLimit },
248cf2b5f3bSDag-Erling Smørgrav 	{ "connecttimeout", oConnectTimeout },
249cf2b5f3bSDag-Erling Smørgrav 	{ "addressfamily", oAddressFamily },
2501ec0d754SDag-Erling Smørgrav 	{ "serveraliveinterval", oServerAliveInterval },
2511ec0d754SDag-Erling Smørgrav 	{ "serveralivecountmax", oServerAliveCountMax },
25221e764dfSDag-Erling Smørgrav 	{ "sendenv", oSendEnv },
25321e764dfSDag-Erling Smørgrav 	{ "controlpath", oControlPath },
25421e764dfSDag-Erling Smørgrav 	{ "controlmaster", oControlMaster },
255e2f6069cSDag-Erling Smørgrav 	{ "controlpersist", oControlPersist },
256aa49c926SDag-Erling Smørgrav 	{ "hashknownhosts", oHashKnownHosts },
257b74df5b2SDag-Erling Smørgrav 	{ "tunnel", oTunnel },
258b74df5b2SDag-Erling Smørgrav 	{ "tunneldevice", oTunnelDevice },
259b74df5b2SDag-Erling Smørgrav 	{ "localcommand", oLocalCommand },
260b74df5b2SDag-Erling Smørgrav 	{ "permitlocalcommand", oPermitLocalCommand },
261d4af9e69SDag-Erling Smørgrav 	{ "visualhostkey", oVisualHostKey },
2627aee6ffeSDag-Erling Smørgrav 	{ "useroaming", oUseRoaming },
263cce7d346SDag-Erling Smørgrav #ifdef JPAKE
264cce7d346SDag-Erling Smørgrav 	{ "zeroknowledgepasswordauthentication",
265cce7d346SDag-Erling Smørgrav 	    oZeroKnowledgePasswordAuthentication },
266cce7d346SDag-Erling Smørgrav #else
267cce7d346SDag-Erling Smørgrav 	{ "zeroknowledgepasswordauthentication", oUnsupported },
268cce7d346SDag-Erling Smørgrav #endif
2694a421b63SDag-Erling Smørgrav 	{ "kexalgorithms", oKexAlgorithms },
2704a421b63SDag-Erling Smørgrav 	{ "ipqos", oIPQoS },
271e146993eSDag-Erling Smørgrav 	{ "requesttty", oRequestTTY },
272*f7167e0eSDag-Erling Smørgrav 	{ "proxyusefdpass", oProxyUseFdpass },
273*f7167e0eSDag-Erling Smørgrav 	{ "canonicaldomains", oCanonicalDomains },
274*f7167e0eSDag-Erling Smørgrav 	{ "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
275*f7167e0eSDag-Erling Smørgrav 	{ "canonicalizehostname", oCanonicalizeHostname },
276*f7167e0eSDag-Erling Smørgrav 	{ "canonicalizemaxdots", oCanonicalizeMaxDots },
277*f7167e0eSDag-Erling Smørgrav 	{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
278e4a9863fSDag-Erling Smørgrav 	{ "ignoreunknown", oIgnoreUnknown },
27989986192SBrooks Davis 	{ "hpndisabled", oHPNDisabled },
28089986192SBrooks Davis 	{ "hpnbuffersize", oHPNBufferSize },
28189986192SBrooks Davis 	{ "tcprcvbufpoll", oTcpRcvBufPoll },
28289986192SBrooks Davis 	{ "tcprcvbuf", oTcpRcvBuf },
28389986192SBrooks Davis #ifdef	NONE_CIPHER_ENABLED
28489986192SBrooks Davis 	{ "noneenabled", oNoneEnabled },
28589986192SBrooks Davis 	{ "noneswitch", oNoneSwitch },
28689986192SBrooks Davis #endif
287975616f0SDag-Erling Smørgrav 	{ "versionaddendum", oVersionAddendum },
28835762f59SEd Schouten 
289af12a3e7SDag-Erling Smørgrav 	{ NULL, oBadOption }
290511b41d2SMark Murray };
291511b41d2SMark Murray 
292511b41d2SMark Murray /*
293511b41d2SMark Murray  * Adds a local TCP/IP port forward to options.  Never returns if there is an
294511b41d2SMark Murray  * error.
295511b41d2SMark Murray  */
296511b41d2SMark Murray 
297511b41d2SMark Murray void
298aa49c926SDag-Erling Smørgrav add_local_forward(Options *options, const Forward *newfwd)
299511b41d2SMark Murray {
300511b41d2SMark Murray 	Forward *fwd;
301f388f5efSDag-Erling Smørgrav #ifndef NO_IPPORT_RESERVED_CONCEPT
302511b41d2SMark Murray 	extern uid_t original_real_uid;
30303f6c5cdSDag-Erling Smørgrav 	int ipport_reserved;
30403f6c5cdSDag-Erling Smørgrav #ifdef __FreeBSD__
30503f6c5cdSDag-Erling Smørgrav 	size_t len_ipport_reserved = sizeof(ipport_reserved);
30603f6c5cdSDag-Erling Smørgrav 
30703f6c5cdSDag-Erling Smørgrav 	if (sysctlbyname("net.inet.ip.portrange.reservedhigh",
30803f6c5cdSDag-Erling Smørgrav 	    &ipport_reserved, &len_ipport_reserved, NULL, 0) != 0)
30903f6c5cdSDag-Erling Smørgrav 		ipport_reserved = IPPORT_RESERVED;
31003f6c5cdSDag-Erling Smørgrav 	else
31103f6c5cdSDag-Erling Smørgrav 		ipport_reserved++;
31203f6c5cdSDag-Erling Smørgrav #else
31303f6c5cdSDag-Erling Smørgrav 	ipport_reserved = IPPORT_RESERVED;
31403f6c5cdSDag-Erling Smørgrav #endif
31503f6c5cdSDag-Erling Smørgrav 	if (newfwd->listen_port < ipport_reserved && original_real_uid != 0)
316ca3176e7SBrian Feldman 		fatal("Privileged ports can only be forwarded by root.");
317989dd127SDag-Erling Smørgrav #endif
318e2f6069cSDag-Erling Smørgrav 	options->local_forwards = xrealloc(options->local_forwards,
319e2f6069cSDag-Erling Smørgrav 	    options->num_local_forwards + 1,
320e2f6069cSDag-Erling Smørgrav 	    sizeof(*options->local_forwards));
321511b41d2SMark Murray 	fwd = &options->local_forwards[options->num_local_forwards++];
322aa49c926SDag-Erling Smørgrav 
323cce7d346SDag-Erling Smørgrav 	fwd->listen_host = newfwd->listen_host;
324aa49c926SDag-Erling Smørgrav 	fwd->listen_port = newfwd->listen_port;
325cce7d346SDag-Erling Smørgrav 	fwd->connect_host = newfwd->connect_host;
326aa49c926SDag-Erling Smørgrav 	fwd->connect_port = newfwd->connect_port;
327511b41d2SMark Murray }
328511b41d2SMark Murray 
329511b41d2SMark Murray /*
330511b41d2SMark Murray  * Adds a remote TCP/IP port forward to options.  Never returns if there is
331511b41d2SMark Murray  * an error.
332511b41d2SMark Murray  */
333511b41d2SMark Murray 
334511b41d2SMark Murray void
335aa49c926SDag-Erling Smørgrav add_remote_forward(Options *options, const Forward *newfwd)
336511b41d2SMark Murray {
337511b41d2SMark Murray 	Forward *fwd;
338e2f6069cSDag-Erling Smørgrav 
339e2f6069cSDag-Erling Smørgrav 	options->remote_forwards = xrealloc(options->remote_forwards,
340e2f6069cSDag-Erling Smørgrav 	    options->num_remote_forwards + 1,
341e2f6069cSDag-Erling Smørgrav 	    sizeof(*options->remote_forwards));
342511b41d2SMark Murray 	fwd = &options->remote_forwards[options->num_remote_forwards++];
343aa49c926SDag-Erling Smørgrav 
344cce7d346SDag-Erling Smørgrav 	fwd->listen_host = newfwd->listen_host;
345aa49c926SDag-Erling Smørgrav 	fwd->listen_port = newfwd->listen_port;
346cce7d346SDag-Erling Smørgrav 	fwd->connect_host = newfwd->connect_host;
347aa49c926SDag-Erling Smørgrav 	fwd->connect_port = newfwd->connect_port;
348462c32cbSDag-Erling Smørgrav 	fwd->handle = newfwd->handle;
349e2f6069cSDag-Erling Smørgrav 	fwd->allocated_port = 0;
350511b41d2SMark Murray }
351511b41d2SMark Murray 
352af12a3e7SDag-Erling Smørgrav static void
353af12a3e7SDag-Erling Smørgrav clear_forwardings(Options *options)
354af12a3e7SDag-Erling Smørgrav {
355af12a3e7SDag-Erling Smørgrav 	int i;
356af12a3e7SDag-Erling Smørgrav 
357aa49c926SDag-Erling Smørgrav 	for (i = 0; i < options->num_local_forwards; i++) {
358e4a9863fSDag-Erling Smørgrav 		free(options->local_forwards[i].listen_host);
359e4a9863fSDag-Erling Smørgrav 		free(options->local_forwards[i].connect_host);
360aa49c926SDag-Erling Smørgrav 	}
361e2f6069cSDag-Erling Smørgrav 	if (options->num_local_forwards > 0) {
362e4a9863fSDag-Erling Smørgrav 		free(options->local_forwards);
363e2f6069cSDag-Erling Smørgrav 		options->local_forwards = NULL;
364e2f6069cSDag-Erling Smørgrav 	}
365af12a3e7SDag-Erling Smørgrav 	options->num_local_forwards = 0;
366aa49c926SDag-Erling Smørgrav 	for (i = 0; i < options->num_remote_forwards; i++) {
367e4a9863fSDag-Erling Smørgrav 		free(options->remote_forwards[i].listen_host);
368e4a9863fSDag-Erling Smørgrav 		free(options->remote_forwards[i].connect_host);
369aa49c926SDag-Erling Smørgrav 	}
370e2f6069cSDag-Erling Smørgrav 	if (options->num_remote_forwards > 0) {
371e4a9863fSDag-Erling Smørgrav 		free(options->remote_forwards);
372e2f6069cSDag-Erling Smørgrav 		options->remote_forwards = NULL;
373e2f6069cSDag-Erling Smørgrav 	}
374af12a3e7SDag-Erling Smørgrav 	options->num_remote_forwards = 0;
375b74df5b2SDag-Erling Smørgrav 	options->tun_open = SSH_TUNMODE_NO;
376af12a3e7SDag-Erling Smørgrav }
377af12a3e7SDag-Erling Smørgrav 
378fa67e83cSDag-Erling Smørgrav void
379fa67e83cSDag-Erling Smørgrav add_identity_file(Options *options, const char *dir, const char *filename,
380fa67e83cSDag-Erling Smørgrav     int userprovided)
381fa67e83cSDag-Erling Smørgrav {
382fa67e83cSDag-Erling Smørgrav 	char *path;
383fa67e83cSDag-Erling Smørgrav 
384fa67e83cSDag-Erling Smørgrav 	if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
385fa67e83cSDag-Erling Smørgrav 		fatal("Too many identity files specified (max %d)",
386fa67e83cSDag-Erling Smørgrav 		    SSH_MAX_IDENTITY_FILES);
387fa67e83cSDag-Erling Smørgrav 
388fa67e83cSDag-Erling Smørgrav 	if (dir == NULL) /* no dir, filename is absolute */
389fa67e83cSDag-Erling Smørgrav 		path = xstrdup(filename);
390fa67e83cSDag-Erling Smørgrav 	else
391fa67e83cSDag-Erling Smørgrav 		(void)xasprintf(&path, "%.100s%.100s", dir, filename);
392fa67e83cSDag-Erling Smørgrav 
393fa67e83cSDag-Erling Smørgrav 	options->identity_file_userprovided[options->num_identity_files] =
394fa67e83cSDag-Erling Smørgrav 	    userprovided;
395fa67e83cSDag-Erling Smørgrav 	options->identity_files[options->num_identity_files++] = path;
396fa67e83cSDag-Erling Smørgrav }
397fa67e83cSDag-Erling Smørgrav 
398*f7167e0eSDag-Erling Smørgrav int
399*f7167e0eSDag-Erling Smørgrav default_ssh_port(void)
400*f7167e0eSDag-Erling Smørgrav {
401*f7167e0eSDag-Erling Smørgrav 	static int port;
402*f7167e0eSDag-Erling Smørgrav 	struct servent *sp;
403*f7167e0eSDag-Erling Smørgrav 
404*f7167e0eSDag-Erling Smørgrav 	if (port == 0) {
405*f7167e0eSDag-Erling Smørgrav 		sp = getservbyname(SSH_SERVICE_NAME, "tcp");
406*f7167e0eSDag-Erling Smørgrav 		port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
407*f7167e0eSDag-Erling Smørgrav 	}
408*f7167e0eSDag-Erling Smørgrav 	return port;
409*f7167e0eSDag-Erling Smørgrav }
410*f7167e0eSDag-Erling Smørgrav 
411*f7167e0eSDag-Erling Smørgrav /*
412*f7167e0eSDag-Erling Smørgrav  * Execute a command in a shell.
413*f7167e0eSDag-Erling Smørgrav  * Return its exit status or -1 on abnormal exit.
414*f7167e0eSDag-Erling Smørgrav  */
415*f7167e0eSDag-Erling Smørgrav static int
416*f7167e0eSDag-Erling Smørgrav execute_in_shell(const char *cmd)
417*f7167e0eSDag-Erling Smørgrav {
418*f7167e0eSDag-Erling Smørgrav 	char *shell, *command_string;
419*f7167e0eSDag-Erling Smørgrav 	pid_t pid;
420*f7167e0eSDag-Erling Smørgrav 	int devnull, status;
421*f7167e0eSDag-Erling Smørgrav 	extern uid_t original_real_uid;
422*f7167e0eSDag-Erling Smørgrav 
423*f7167e0eSDag-Erling Smørgrav 	if ((shell = getenv("SHELL")) == NULL)
424*f7167e0eSDag-Erling Smørgrav 		shell = _PATH_BSHELL;
425*f7167e0eSDag-Erling Smørgrav 
426*f7167e0eSDag-Erling Smørgrav 	/*
427*f7167e0eSDag-Erling Smørgrav 	 * Use "exec" to avoid "sh -c" processes on some platforms
428*f7167e0eSDag-Erling Smørgrav 	 * (e.g. Solaris)
429*f7167e0eSDag-Erling Smørgrav 	 */
430*f7167e0eSDag-Erling Smørgrav 	xasprintf(&command_string, "exec %s", cmd);
431*f7167e0eSDag-Erling Smørgrav 
432*f7167e0eSDag-Erling Smørgrav 	/* Need this to redirect subprocess stdin/out */
433*f7167e0eSDag-Erling Smørgrav 	if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
434*f7167e0eSDag-Erling Smørgrav 		fatal("open(/dev/null): %s", strerror(errno));
435*f7167e0eSDag-Erling Smørgrav 
436*f7167e0eSDag-Erling Smørgrav 	debug("Executing command: '%.500s'", cmd);
437*f7167e0eSDag-Erling Smørgrav 
438*f7167e0eSDag-Erling Smørgrav 	/* Fork and execute the command. */
439*f7167e0eSDag-Erling Smørgrav 	if ((pid = fork()) == 0) {
440*f7167e0eSDag-Erling Smørgrav 		char *argv[4];
441*f7167e0eSDag-Erling Smørgrav 
442*f7167e0eSDag-Erling Smørgrav 		/* Child.  Permanently give up superuser privileges. */
443*f7167e0eSDag-Erling Smørgrav 		permanently_drop_suid(original_real_uid);
444*f7167e0eSDag-Erling Smørgrav 
445*f7167e0eSDag-Erling Smørgrav 		/* Redirect child stdin and stdout. Leave stderr */
446*f7167e0eSDag-Erling Smørgrav 		if (dup2(devnull, STDIN_FILENO) == -1)
447*f7167e0eSDag-Erling Smørgrav 			fatal("dup2: %s", strerror(errno));
448*f7167e0eSDag-Erling Smørgrav 		if (dup2(devnull, STDOUT_FILENO) == -1)
449*f7167e0eSDag-Erling Smørgrav 			fatal("dup2: %s", strerror(errno));
450*f7167e0eSDag-Erling Smørgrav 		if (devnull > STDERR_FILENO)
451*f7167e0eSDag-Erling Smørgrav 			close(devnull);
452*f7167e0eSDag-Erling Smørgrav 		closefrom(STDERR_FILENO + 1);
453*f7167e0eSDag-Erling Smørgrav 
454*f7167e0eSDag-Erling Smørgrav 		argv[0] = shell;
455*f7167e0eSDag-Erling Smørgrav 		argv[1] = "-c";
456*f7167e0eSDag-Erling Smørgrav 		argv[2] = command_string;
457*f7167e0eSDag-Erling Smørgrav 		argv[3] = NULL;
458*f7167e0eSDag-Erling Smørgrav 
459*f7167e0eSDag-Erling Smørgrav 		execv(argv[0], argv);
460*f7167e0eSDag-Erling Smørgrav 		error("Unable to execute '%.100s': %s", cmd, strerror(errno));
461*f7167e0eSDag-Erling Smørgrav 		/* Die with signal to make this error apparent to parent. */
462*f7167e0eSDag-Erling Smørgrav 		signal(SIGTERM, SIG_DFL);
463*f7167e0eSDag-Erling Smørgrav 		kill(getpid(), SIGTERM);
464*f7167e0eSDag-Erling Smørgrav 		_exit(1);
465*f7167e0eSDag-Erling Smørgrav 	}
466*f7167e0eSDag-Erling Smørgrav 	/* Parent. */
467*f7167e0eSDag-Erling Smørgrav 	if (pid < 0)
468*f7167e0eSDag-Erling Smørgrav 		fatal("%s: fork: %.100s", __func__, strerror(errno));
469*f7167e0eSDag-Erling Smørgrav 
470*f7167e0eSDag-Erling Smørgrav 	close(devnull);
471*f7167e0eSDag-Erling Smørgrav 	free(command_string);
472*f7167e0eSDag-Erling Smørgrav 
473*f7167e0eSDag-Erling Smørgrav 	while (waitpid(pid, &status, 0) == -1) {
474*f7167e0eSDag-Erling Smørgrav 		if (errno != EINTR && errno != EAGAIN)
475*f7167e0eSDag-Erling Smørgrav 			fatal("%s: waitpid: %s", __func__, strerror(errno));
476*f7167e0eSDag-Erling Smørgrav 	}
477*f7167e0eSDag-Erling Smørgrav 	if (!WIFEXITED(status)) {
478*f7167e0eSDag-Erling Smørgrav 		error("command '%.100s' exited abnormally", cmd);
479*f7167e0eSDag-Erling Smørgrav 		return -1;
480*f7167e0eSDag-Erling Smørgrav 	}
481*f7167e0eSDag-Erling Smørgrav 	debug3("command returned status %d", WEXITSTATUS(status));
482*f7167e0eSDag-Erling Smørgrav 	return WEXITSTATUS(status);
483*f7167e0eSDag-Erling Smørgrav }
484*f7167e0eSDag-Erling Smørgrav 
485*f7167e0eSDag-Erling Smørgrav /*
486*f7167e0eSDag-Erling Smørgrav  * Parse and execute a Match directive.
487*f7167e0eSDag-Erling Smørgrav  */
488*f7167e0eSDag-Erling Smørgrav static int
489*f7167e0eSDag-Erling Smørgrav match_cfg_line(Options *options, char **condition, struct passwd *pw,
490*f7167e0eSDag-Erling Smørgrav     const char *host_arg, const char *filename, int linenum)
491*f7167e0eSDag-Erling Smørgrav {
492*f7167e0eSDag-Erling Smørgrav 	char *arg, *attrib, *cmd, *cp = *condition, *host;
493*f7167e0eSDag-Erling Smørgrav 	const char *ruser;
494*f7167e0eSDag-Erling Smørgrav 	int r, port, result = 1, attributes = 0;
495*f7167e0eSDag-Erling Smørgrav 	size_t len;
496*f7167e0eSDag-Erling Smørgrav 	char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
497*f7167e0eSDag-Erling Smørgrav 
498*f7167e0eSDag-Erling Smørgrav 	/*
499*f7167e0eSDag-Erling Smørgrav 	 * Configuration is likely to be incomplete at this point so we
500*f7167e0eSDag-Erling Smørgrav 	 * must be prepared to use default values.
501*f7167e0eSDag-Erling Smørgrav 	 */
502*f7167e0eSDag-Erling Smørgrav 	port = options->port <= 0 ? default_ssh_port() : options->port;
503*f7167e0eSDag-Erling Smørgrav 	ruser = options->user == NULL ? pw->pw_name : options->user;
504*f7167e0eSDag-Erling Smørgrav 	if (options->hostname != NULL) {
505*f7167e0eSDag-Erling Smørgrav 		/* NB. Please keep in sync with ssh.c:main() */
506*f7167e0eSDag-Erling Smørgrav 		host = percent_expand(options->hostname,
507*f7167e0eSDag-Erling Smørgrav 		    "h", host_arg, (char *)NULL);
508*f7167e0eSDag-Erling Smørgrav 	} else
509*f7167e0eSDag-Erling Smørgrav 		host = xstrdup(host_arg);
510*f7167e0eSDag-Erling Smørgrav 
511*f7167e0eSDag-Erling Smørgrav 	debug3("checking match for '%s' host %s", cp, host);
512*f7167e0eSDag-Erling Smørgrav 	while ((attrib = strdelim(&cp)) && *attrib != '\0') {
513*f7167e0eSDag-Erling Smørgrav 		attributes++;
514*f7167e0eSDag-Erling Smørgrav 		if (strcasecmp(attrib, "all") == 0) {
515*f7167e0eSDag-Erling Smørgrav 			if (attributes != 1 ||
516*f7167e0eSDag-Erling Smørgrav 			    ((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
517*f7167e0eSDag-Erling Smørgrav 				error("'all' cannot be combined with other "
518*f7167e0eSDag-Erling Smørgrav 				    "Match attributes");
519*f7167e0eSDag-Erling Smørgrav 				result = -1;
520*f7167e0eSDag-Erling Smørgrav 				goto out;
521*f7167e0eSDag-Erling Smørgrav 			}
522*f7167e0eSDag-Erling Smørgrav 			*condition = cp;
523*f7167e0eSDag-Erling Smørgrav 			result = 1;
524*f7167e0eSDag-Erling Smørgrav 			goto out;
525*f7167e0eSDag-Erling Smørgrav 		}
526*f7167e0eSDag-Erling Smørgrav 		if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
527*f7167e0eSDag-Erling Smørgrav 			error("Missing Match criteria for %s", attrib);
528*f7167e0eSDag-Erling Smørgrav 			result = -1;
529*f7167e0eSDag-Erling Smørgrav 			goto out;
530*f7167e0eSDag-Erling Smørgrav 		}
531*f7167e0eSDag-Erling Smørgrav 		len = strlen(arg);
532*f7167e0eSDag-Erling Smørgrav 		if (strcasecmp(attrib, "host") == 0) {
533*f7167e0eSDag-Erling Smørgrav 			if (match_hostname(host, arg, len) != 1)
534*f7167e0eSDag-Erling Smørgrav 				result = 0;
535*f7167e0eSDag-Erling Smørgrav 			else
536*f7167e0eSDag-Erling Smørgrav 				debug("%.200s line %d: matched 'Host %.100s' ",
537*f7167e0eSDag-Erling Smørgrav 				    filename, linenum, host);
538*f7167e0eSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "originalhost") == 0) {
539*f7167e0eSDag-Erling Smørgrav 			if (match_hostname(host_arg, arg, len) != 1)
540*f7167e0eSDag-Erling Smørgrav 				result = 0;
541*f7167e0eSDag-Erling Smørgrav 			else
542*f7167e0eSDag-Erling Smørgrav 				debug("%.200s line %d: matched "
543*f7167e0eSDag-Erling Smørgrav 				    "'OriginalHost %.100s' ",
544*f7167e0eSDag-Erling Smørgrav 				    filename, linenum, host_arg);
545*f7167e0eSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "user") == 0) {
546*f7167e0eSDag-Erling Smørgrav 			if (match_pattern_list(ruser, arg, len, 0) != 1)
547*f7167e0eSDag-Erling Smørgrav 				result = 0;
548*f7167e0eSDag-Erling Smørgrav 			else
549*f7167e0eSDag-Erling Smørgrav 				debug("%.200s line %d: matched 'User %.100s' ",
550*f7167e0eSDag-Erling Smørgrav 				    filename, linenum, ruser);
551*f7167e0eSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "localuser") == 0) {
552*f7167e0eSDag-Erling Smørgrav 			if (match_pattern_list(pw->pw_name, arg, len, 0) != 1)
553*f7167e0eSDag-Erling Smørgrav 				result = 0;
554*f7167e0eSDag-Erling Smørgrav 			else
555*f7167e0eSDag-Erling Smørgrav 				debug("%.200s line %d: matched "
556*f7167e0eSDag-Erling Smørgrav 				    "'LocalUser %.100s' ",
557*f7167e0eSDag-Erling Smørgrav 				    filename, linenum, pw->pw_name);
558*f7167e0eSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "exec") == 0) {
559*f7167e0eSDag-Erling Smørgrav 			if (gethostname(thishost, sizeof(thishost)) == -1)
560*f7167e0eSDag-Erling Smørgrav 				fatal("gethostname: %s", strerror(errno));
561*f7167e0eSDag-Erling Smørgrav 			strlcpy(shorthost, thishost, sizeof(shorthost));
562*f7167e0eSDag-Erling Smørgrav 			shorthost[strcspn(thishost, ".")] = '\0';
563*f7167e0eSDag-Erling Smørgrav 			snprintf(portstr, sizeof(portstr), "%d", port);
564*f7167e0eSDag-Erling Smørgrav 
565*f7167e0eSDag-Erling Smørgrav 			cmd = percent_expand(arg,
566*f7167e0eSDag-Erling Smørgrav 			    "L", shorthost,
567*f7167e0eSDag-Erling Smørgrav 			    "d", pw->pw_dir,
568*f7167e0eSDag-Erling Smørgrav 			    "h", host,
569*f7167e0eSDag-Erling Smørgrav 			    "l", thishost,
570*f7167e0eSDag-Erling Smørgrav 			    "n", host_arg,
571*f7167e0eSDag-Erling Smørgrav 			    "p", portstr,
572*f7167e0eSDag-Erling Smørgrav 			    "r", ruser,
573*f7167e0eSDag-Erling Smørgrav 			    "u", pw->pw_name,
574*f7167e0eSDag-Erling Smørgrav 			    (char *)NULL);
575*f7167e0eSDag-Erling Smørgrav 			r = execute_in_shell(cmd);
576*f7167e0eSDag-Erling Smørgrav 			if (r == -1) {
577*f7167e0eSDag-Erling Smørgrav 				fatal("%.200s line %d: match exec '%.100s' "
578*f7167e0eSDag-Erling Smørgrav 				    "error", filename, linenum, cmd);
579*f7167e0eSDag-Erling Smørgrav 			} else if (r == 0) {
580*f7167e0eSDag-Erling Smørgrav 				debug("%.200s line %d: matched "
581*f7167e0eSDag-Erling Smørgrav 				    "'exec \"%.100s\"' ",
582*f7167e0eSDag-Erling Smørgrav 				    filename, linenum, cmd);
583*f7167e0eSDag-Erling Smørgrav 			} else
584*f7167e0eSDag-Erling Smørgrav 				result = 0;
585*f7167e0eSDag-Erling Smørgrav 			free(cmd);
586*f7167e0eSDag-Erling Smørgrav 		} else {
587*f7167e0eSDag-Erling Smørgrav 			error("Unsupported Match attribute %s", attrib);
588*f7167e0eSDag-Erling Smørgrav 			result = -1;
589*f7167e0eSDag-Erling Smørgrav 			goto out;
590*f7167e0eSDag-Erling Smørgrav 		}
591*f7167e0eSDag-Erling Smørgrav 	}
592*f7167e0eSDag-Erling Smørgrav 	if (attributes == 0) {
593*f7167e0eSDag-Erling Smørgrav 		error("One or more attributes required for Match");
594*f7167e0eSDag-Erling Smørgrav 		result = -1;
595*f7167e0eSDag-Erling Smørgrav 		goto out;
596*f7167e0eSDag-Erling Smørgrav 	}
597*f7167e0eSDag-Erling Smørgrav 	debug3("match %sfound", result ? "" : "not ");
598*f7167e0eSDag-Erling Smørgrav 	*condition = cp;
599*f7167e0eSDag-Erling Smørgrav  out:
600*f7167e0eSDag-Erling Smørgrav 	free(host);
601*f7167e0eSDag-Erling Smørgrav 	return result;
602*f7167e0eSDag-Erling Smørgrav }
603*f7167e0eSDag-Erling Smørgrav 
604*f7167e0eSDag-Erling Smørgrav /* Check and prepare a domain name: removes trailing '.' and lowercases */
605*f7167e0eSDag-Erling Smørgrav static void
606*f7167e0eSDag-Erling Smørgrav valid_domain(char *name, const char *filename, int linenum)
607*f7167e0eSDag-Erling Smørgrav {
608*f7167e0eSDag-Erling Smørgrav 	size_t i, l = strlen(name);
609*f7167e0eSDag-Erling Smørgrav 	u_char c, last = '\0';
610*f7167e0eSDag-Erling Smørgrav 
611*f7167e0eSDag-Erling Smørgrav 	if (l == 0)
612*f7167e0eSDag-Erling Smørgrav 		fatal("%s line %d: empty hostname suffix", filename, linenum);
613*f7167e0eSDag-Erling Smørgrav 	if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0]))
614*f7167e0eSDag-Erling Smørgrav 		fatal("%s line %d: hostname suffix \"%.100s\" "
615*f7167e0eSDag-Erling Smørgrav 		    "starts with invalid character", filename, linenum, name);
616*f7167e0eSDag-Erling Smørgrav 	for (i = 0; i < l; i++) {
617*f7167e0eSDag-Erling Smørgrav 		c = tolower((u_char)name[i]);
618*f7167e0eSDag-Erling Smørgrav 		name[i] = (char)c;
619*f7167e0eSDag-Erling Smørgrav 		if (last == '.' && c == '.')
620*f7167e0eSDag-Erling Smørgrav 			fatal("%s line %d: hostname suffix \"%.100s\" contains "
621*f7167e0eSDag-Erling Smørgrav 			    "consecutive separators", filename, linenum, name);
622*f7167e0eSDag-Erling Smørgrav 		if (c != '.' && c != '-' && !isalnum(c) &&
623*f7167e0eSDag-Erling Smørgrav 		    c != '_') /* technically invalid, but common */
624*f7167e0eSDag-Erling Smørgrav 			fatal("%s line %d: hostname suffix \"%.100s\" contains "
625*f7167e0eSDag-Erling Smørgrav 			    "invalid characters", filename, linenum, name);
626*f7167e0eSDag-Erling Smørgrav 		last = c;
627*f7167e0eSDag-Erling Smørgrav 	}
628*f7167e0eSDag-Erling Smørgrav 	if (name[l - 1] == '.')
629*f7167e0eSDag-Erling Smørgrav 		name[l - 1] = '\0';
630*f7167e0eSDag-Erling Smørgrav }
631*f7167e0eSDag-Erling Smørgrav 
632511b41d2SMark Murray /*
633ca3176e7SBrian Feldman  * Returns the number of the token pointed to by cp or oBadOption.
634511b41d2SMark Murray  */
635511b41d2SMark Murray static OpCodes
636e4a9863fSDag-Erling Smørgrav parse_token(const char *cp, const char *filename, int linenum,
637e4a9863fSDag-Erling Smørgrav     const char *ignored_unknown)
638511b41d2SMark Murray {
639e4a9863fSDag-Erling Smørgrav 	int i;
640511b41d2SMark Murray 
641511b41d2SMark Murray 	for (i = 0; keywords[i].name; i++)
642e4a9863fSDag-Erling Smørgrav 		if (strcmp(cp, keywords[i].name) == 0)
643511b41d2SMark Murray 			return keywords[i].opcode;
644e4a9863fSDag-Erling Smørgrav 	if (ignored_unknown != NULL && match_pattern_list(cp, ignored_unknown,
645e4a9863fSDag-Erling Smørgrav 	    strlen(ignored_unknown), 1) == 1)
646e4a9863fSDag-Erling Smørgrav 		return oIgnoredUnknownOption;
647ca3176e7SBrian Feldman 	error("%s: line %d: Bad configuration option: %s",
648511b41d2SMark Murray 	    filename, linenum, cp);
649511b41d2SMark Murray 	return oBadOption;
650511b41d2SMark Murray }
651511b41d2SMark Murray 
652*f7167e0eSDag-Erling Smørgrav /* Multistate option parsing */
653*f7167e0eSDag-Erling Smørgrav struct multistate {
654*f7167e0eSDag-Erling Smørgrav 	char *key;
655*f7167e0eSDag-Erling Smørgrav 	int value;
656*f7167e0eSDag-Erling Smørgrav };
657*f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_flag[] = {
658*f7167e0eSDag-Erling Smørgrav 	{ "true",			1 },
659*f7167e0eSDag-Erling Smørgrav 	{ "false",			0 },
660*f7167e0eSDag-Erling Smørgrav 	{ "yes",			1 },
661*f7167e0eSDag-Erling Smørgrav 	{ "no",				0 },
662*f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
663*f7167e0eSDag-Erling Smørgrav };
664*f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_yesnoask[] = {
665*f7167e0eSDag-Erling Smørgrav 	{ "true",			1 },
666*f7167e0eSDag-Erling Smørgrav 	{ "false",			0 },
667*f7167e0eSDag-Erling Smørgrav 	{ "yes",			1 },
668*f7167e0eSDag-Erling Smørgrav 	{ "no",				0 },
669*f7167e0eSDag-Erling Smørgrav 	{ "ask",			2 },
670*f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
671*f7167e0eSDag-Erling Smørgrav };
672*f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_addressfamily[] = {
673*f7167e0eSDag-Erling Smørgrav 	{ "inet",			AF_INET },
674*f7167e0eSDag-Erling Smørgrav 	{ "inet6",			AF_INET6 },
675*f7167e0eSDag-Erling Smørgrav 	{ "any",			AF_UNSPEC },
676*f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
677*f7167e0eSDag-Erling Smørgrav };
678*f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_controlmaster[] = {
679*f7167e0eSDag-Erling Smørgrav 	{ "true",			SSHCTL_MASTER_YES },
680*f7167e0eSDag-Erling Smørgrav 	{ "yes",			SSHCTL_MASTER_YES },
681*f7167e0eSDag-Erling Smørgrav 	{ "false",			SSHCTL_MASTER_NO },
682*f7167e0eSDag-Erling Smørgrav 	{ "no",				SSHCTL_MASTER_NO },
683*f7167e0eSDag-Erling Smørgrav 	{ "auto",			SSHCTL_MASTER_AUTO },
684*f7167e0eSDag-Erling Smørgrav 	{ "ask",			SSHCTL_MASTER_ASK },
685*f7167e0eSDag-Erling Smørgrav 	{ "autoask",			SSHCTL_MASTER_AUTO_ASK },
686*f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
687*f7167e0eSDag-Erling Smørgrav };
688*f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_tunnel[] = {
689*f7167e0eSDag-Erling Smørgrav 	{ "ethernet",			SSH_TUNMODE_ETHERNET },
690*f7167e0eSDag-Erling Smørgrav 	{ "point-to-point",		SSH_TUNMODE_POINTOPOINT },
691*f7167e0eSDag-Erling Smørgrav 	{ "true",			SSH_TUNMODE_DEFAULT },
692*f7167e0eSDag-Erling Smørgrav 	{ "yes",			SSH_TUNMODE_DEFAULT },
693*f7167e0eSDag-Erling Smørgrav 	{ "false",			SSH_TUNMODE_NO },
694*f7167e0eSDag-Erling Smørgrav 	{ "no",				SSH_TUNMODE_NO },
695*f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
696*f7167e0eSDag-Erling Smørgrav };
697*f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_requesttty[] = {
698*f7167e0eSDag-Erling Smørgrav 	{ "true",			REQUEST_TTY_YES },
699*f7167e0eSDag-Erling Smørgrav 	{ "yes",			REQUEST_TTY_YES },
700*f7167e0eSDag-Erling Smørgrav 	{ "false",			REQUEST_TTY_NO },
701*f7167e0eSDag-Erling Smørgrav 	{ "no",				REQUEST_TTY_NO },
702*f7167e0eSDag-Erling Smørgrav 	{ "force",			REQUEST_TTY_FORCE },
703*f7167e0eSDag-Erling Smørgrav 	{ "auto",			REQUEST_TTY_AUTO },
704*f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
705*f7167e0eSDag-Erling Smørgrav };
706*f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_canonicalizehostname[] = {
707*f7167e0eSDag-Erling Smørgrav 	{ "true",			SSH_CANONICALISE_YES },
708*f7167e0eSDag-Erling Smørgrav 	{ "false",			SSH_CANONICALISE_NO },
709*f7167e0eSDag-Erling Smørgrav 	{ "yes",			SSH_CANONICALISE_YES },
710*f7167e0eSDag-Erling Smørgrav 	{ "no",				SSH_CANONICALISE_NO },
711*f7167e0eSDag-Erling Smørgrav 	{ "always",			SSH_CANONICALISE_ALWAYS },
712*f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
713*f7167e0eSDag-Erling Smørgrav };
714*f7167e0eSDag-Erling Smørgrav 
715511b41d2SMark Murray /*
716511b41d2SMark Murray  * Processes a single option line as used in the configuration files. This
717511b41d2SMark Murray  * only sets those values that have not already been set.
718511b41d2SMark Murray  */
719e73e9afaSDag-Erling Smørgrav #define WHITESPACE " \t\r\n"
720511b41d2SMark Murray int
721*f7167e0eSDag-Erling Smørgrav process_config_line(Options *options, struct passwd *pw, const char *host,
722*f7167e0eSDag-Erling Smørgrav     char *line, const char *filename, int linenum, int *activep, int userconfig)
723511b41d2SMark Murray {
724e146993eSDag-Erling Smørgrav 	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
725e146993eSDag-Erling Smørgrav 	char **cpptr, fwdarg[256];
726e4a9863fSDag-Erling Smørgrav 	u_int i, *uintptr, max_entries = 0;
727*f7167e0eSDag-Erling Smørgrav 	int negated, opcode, *intptr, value, value2, cmdline = 0;
728d4af9e69SDag-Erling Smørgrav 	LogLevel *log_level_ptr;
729e4a9863fSDag-Erling Smørgrav 	long long val64;
730e73e9afaSDag-Erling Smørgrav 	size_t len;
731aa49c926SDag-Erling Smørgrav 	Forward fwd;
732*f7167e0eSDag-Erling Smørgrav 	const struct multistate *multistate_ptr;
733*f7167e0eSDag-Erling Smørgrav 	struct allowed_cname *cname;
734*f7167e0eSDag-Erling Smørgrav 
735*f7167e0eSDag-Erling Smørgrav 	if (activep == NULL) { /* We are processing a command line directive */
736*f7167e0eSDag-Erling Smørgrav 		cmdline = 1;
737*f7167e0eSDag-Erling Smørgrav 		activep = &cmdline;
738*f7167e0eSDag-Erling Smørgrav 	}
739511b41d2SMark Murray 
740cf2b5f3bSDag-Erling Smørgrav 	/* Strip trailing whitespace */
741cf2b5f3bSDag-Erling Smørgrav 	for (len = strlen(line) - 1; len > 0; len--) {
742cf2b5f3bSDag-Erling Smørgrav 		if (strchr(WHITESPACE, line[len]) == NULL)
743cf2b5f3bSDag-Erling Smørgrav 			break;
744cf2b5f3bSDag-Erling Smørgrav 		line[len] = '\0';
745cf2b5f3bSDag-Erling Smørgrav 	}
746cf2b5f3bSDag-Erling Smørgrav 
747c2d3a559SKris Kennaway 	s = line;
748c2d3a559SKris Kennaway 	/* Get the keyword. (Each line is supposed to begin with a keyword). */
749333ee039SDag-Erling Smørgrav 	if ((keyword = strdelim(&s)) == NULL)
750333ee039SDag-Erling Smørgrav 		return 0;
751c2d3a559SKris Kennaway 	/* Ignore leading whitespace. */
752c2d3a559SKris Kennaway 	if (*keyword == '\0')
753c2d3a559SKris Kennaway 		keyword = strdelim(&s);
754ca3176e7SBrian Feldman 	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
755511b41d2SMark Murray 		return 0;
756e4a9863fSDag-Erling Smørgrav 	/* Match lowercase keyword */
757*f7167e0eSDag-Erling Smørgrav 	lowercase(keyword);
758511b41d2SMark Murray 
759e4a9863fSDag-Erling Smørgrav 	opcode = parse_token(keyword, filename, linenum,
760e4a9863fSDag-Erling Smørgrav 	    options->ignored_unknown);
761511b41d2SMark Murray 
762511b41d2SMark Murray 	switch (opcode) {
763511b41d2SMark Murray 	case oBadOption:
764511b41d2SMark Murray 		/* don't panic, but count bad options */
765511b41d2SMark Murray 		return -1;
766511b41d2SMark Murray 		/* NOTREACHED */
767e4a9863fSDag-Erling Smørgrav 	case oIgnoredUnknownOption:
768e4a9863fSDag-Erling Smørgrav 		debug("%s line %d: Ignored unknown option \"%s\"",
769e4a9863fSDag-Erling Smørgrav 		    filename, linenum, keyword);
770e4a9863fSDag-Erling Smørgrav 		return 0;
771cf2b5f3bSDag-Erling Smørgrav 	case oConnectTimeout:
772cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->connection_timeout;
7731ec0d754SDag-Erling Smørgrav parse_time:
774cf2b5f3bSDag-Erling Smørgrav 		arg = strdelim(&s);
775cf2b5f3bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
776cf2b5f3bSDag-Erling Smørgrav 			fatal("%s line %d: missing time value.",
777cf2b5f3bSDag-Erling Smørgrav 			    filename, linenum);
778cf2b5f3bSDag-Erling Smørgrav 		if ((value = convtime(arg)) == -1)
779cf2b5f3bSDag-Erling Smørgrav 			fatal("%s line %d: invalid time value.",
780cf2b5f3bSDag-Erling Smørgrav 			    filename, linenum);
781d4af9e69SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
782cf2b5f3bSDag-Erling Smørgrav 			*intptr = value;
783cf2b5f3bSDag-Erling Smørgrav 		break;
784cf2b5f3bSDag-Erling Smørgrav 
785511b41d2SMark Murray 	case oForwardAgent:
786511b41d2SMark Murray 		intptr = &options->forward_agent;
787511b41d2SMark Murray  parse_flag:
788*f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_flag;
789*f7167e0eSDag-Erling Smørgrav  parse_multistate:
790c2d3a559SKris Kennaway 		arg = strdelim(&s);
791c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
792*f7167e0eSDag-Erling Smørgrav 			fatal("%s line %d: missing argument.",
793*f7167e0eSDag-Erling Smørgrav 			    filename, linenum);
794*f7167e0eSDag-Erling Smørgrav 		value = -1;
795*f7167e0eSDag-Erling Smørgrav 		for (i = 0; multistate_ptr[i].key != NULL; i++) {
796*f7167e0eSDag-Erling Smørgrav 			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
797*f7167e0eSDag-Erling Smørgrav 				value = multistate_ptr[i].value;
798*f7167e0eSDag-Erling Smørgrav 				break;
799*f7167e0eSDag-Erling Smørgrav 			}
800*f7167e0eSDag-Erling Smørgrav 		}
801*f7167e0eSDag-Erling Smørgrav 		if (value == -1)
802*f7167e0eSDag-Erling Smørgrav 			fatal("%s line %d: unsupported option \"%s\".",
803*f7167e0eSDag-Erling Smørgrav 			    filename, linenum, arg);
804511b41d2SMark Murray 		if (*activep && *intptr == -1)
805511b41d2SMark Murray 			*intptr = value;
806511b41d2SMark Murray 		break;
807511b41d2SMark Murray 
808511b41d2SMark Murray 	case oForwardX11:
809511b41d2SMark Murray 		intptr = &options->forward_x11;
810511b41d2SMark Murray 		goto parse_flag;
811511b41d2SMark Murray 
8121ec0d754SDag-Erling Smørgrav 	case oForwardX11Trusted:
8131ec0d754SDag-Erling Smørgrav 		intptr = &options->forward_x11_trusted;
8141ec0d754SDag-Erling Smørgrav 		goto parse_flag;
8151ec0d754SDag-Erling Smørgrav 
816e2f6069cSDag-Erling Smørgrav 	case oForwardX11Timeout:
817e2f6069cSDag-Erling Smørgrav 		intptr = &options->forward_x11_timeout;
818e2f6069cSDag-Erling Smørgrav 		goto parse_time;
819e2f6069cSDag-Erling Smørgrav 
820511b41d2SMark Murray 	case oGatewayPorts:
821511b41d2SMark Murray 		intptr = &options->gateway_ports;
822511b41d2SMark Murray 		goto parse_flag;
823511b41d2SMark Murray 
824333ee039SDag-Erling Smørgrav 	case oExitOnForwardFailure:
825333ee039SDag-Erling Smørgrav 		intptr = &options->exit_on_forward_failure;
826333ee039SDag-Erling Smørgrav 		goto parse_flag;
827333ee039SDag-Erling Smørgrav 
828511b41d2SMark Murray 	case oUsePrivilegedPort:
829511b41d2SMark Murray 		intptr = &options->use_privileged_port;
830511b41d2SMark Murray 		goto parse_flag;
831511b41d2SMark Murray 
832511b41d2SMark Murray 	case oPasswordAuthentication:
833511b41d2SMark Murray 		intptr = &options->password_authentication;
834511b41d2SMark Murray 		goto parse_flag;
835511b41d2SMark Murray 
836cce7d346SDag-Erling Smørgrav 	case oZeroKnowledgePasswordAuthentication:
837cce7d346SDag-Erling Smørgrav 		intptr = &options->zero_knowledge_password_authentication;
838cce7d346SDag-Erling Smørgrav 		goto parse_flag;
839cce7d346SDag-Erling Smørgrav 
84009958426SBrian Feldman 	case oKbdInteractiveAuthentication:
84109958426SBrian Feldman 		intptr = &options->kbd_interactive_authentication;
84209958426SBrian Feldman 		goto parse_flag;
84309958426SBrian Feldman 
84409958426SBrian Feldman 	case oKbdInteractiveDevices:
84509958426SBrian Feldman 		charptr = &options->kbd_interactive_devices;
84609958426SBrian Feldman 		goto parse_string;
84709958426SBrian Feldman 
848ca3176e7SBrian Feldman 	case oPubkeyAuthentication:
849ca3176e7SBrian Feldman 		intptr = &options->pubkey_authentication;
850e8aafc91SKris Kennaway 		goto parse_flag;
851e8aafc91SKris Kennaway 
852511b41d2SMark Murray 	case oRSAAuthentication:
853511b41d2SMark Murray 		intptr = &options->rsa_authentication;
854511b41d2SMark Murray 		goto parse_flag;
855511b41d2SMark Murray 
856511b41d2SMark Murray 	case oRhostsRSAAuthentication:
857511b41d2SMark Murray 		intptr = &options->rhosts_rsa_authentication;
858511b41d2SMark Murray 		goto parse_flag;
859511b41d2SMark Murray 
860ca3176e7SBrian Feldman 	case oHostbasedAuthentication:
861ca3176e7SBrian Feldman 		intptr = &options->hostbased_authentication;
862511b41d2SMark Murray 		goto parse_flag;
863511b41d2SMark Murray 
864af12a3e7SDag-Erling Smørgrav 	case oChallengeResponseAuthentication:
865af12a3e7SDag-Erling Smørgrav 		intptr = &options->challenge_response_authentication;
866af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
867cf2b5f3bSDag-Erling Smørgrav 
868cf2b5f3bSDag-Erling Smørgrav 	case oGssAuthentication:
869cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_authentication;
870511b41d2SMark Murray 		goto parse_flag;
871cf2b5f3bSDag-Erling Smørgrav 
872cf2b5f3bSDag-Erling Smørgrav 	case oGssDelegateCreds:
873cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_deleg_creds;
874ca3176e7SBrian Feldman 		goto parse_flag;
875cf2b5f3bSDag-Erling Smørgrav 
876511b41d2SMark Murray 	case oBatchMode:
877511b41d2SMark Murray 		intptr = &options->batch_mode;
878511b41d2SMark Murray 		goto parse_flag;
879511b41d2SMark Murray 
880511b41d2SMark Murray 	case oCheckHostIP:
881511b41d2SMark Murray 		intptr = &options->check_host_ip;
882511b41d2SMark Murray 		goto parse_flag;
883511b41d2SMark Murray 
884cf2b5f3bSDag-Erling Smørgrav 	case oVerifyHostKeyDNS:
885cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->verify_host_key_dns;
886*f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_yesnoask;
887*f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
888cf2b5f3bSDag-Erling Smørgrav 
889511b41d2SMark Murray 	case oStrictHostKeyChecking:
890511b41d2SMark Murray 		intptr = &options->strict_host_key_checking;
891*f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_yesnoask;
892*f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
893511b41d2SMark Murray 
894511b41d2SMark Murray 	case oCompression:
895511b41d2SMark Murray 		intptr = &options->compression;
896511b41d2SMark Murray 		goto parse_flag;
897511b41d2SMark Murray 
8981ec0d754SDag-Erling Smørgrav 	case oTCPKeepAlive:
8991ec0d754SDag-Erling Smørgrav 		intptr = &options->tcp_keep_alive;
900511b41d2SMark Murray 		goto parse_flag;
901511b41d2SMark Murray 
902af12a3e7SDag-Erling Smørgrav 	case oNoHostAuthenticationForLocalhost:
903af12a3e7SDag-Erling Smørgrav 		intptr = &options->no_host_authentication_for_localhost;
904af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
905af12a3e7SDag-Erling Smørgrav 
906511b41d2SMark Murray 	case oNumberOfPasswordPrompts:
907511b41d2SMark Murray 		intptr = &options->number_of_password_prompts;
908511b41d2SMark Murray 		goto parse_int;
909511b41d2SMark Murray 
910511b41d2SMark Murray 	case oCompressionLevel:
911511b41d2SMark Murray 		intptr = &options->compression_level;
912511b41d2SMark Murray 		goto parse_int;
913511b41d2SMark Murray 
914cf2b5f3bSDag-Erling Smørgrav 	case oRekeyLimit:
915cf2b5f3bSDag-Erling Smørgrav 		arg = strdelim(&s);
916cf2b5f3bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
917e4a9863fSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename,
918e4a9863fSDag-Erling Smørgrav 			    linenum);
919e4a9863fSDag-Erling Smørgrav 		if (strcmp(arg, "default") == 0) {
920e4a9863fSDag-Erling Smørgrav 			val64 = 0;
921e4a9863fSDag-Erling Smørgrav 		} else {
922e4a9863fSDag-Erling Smørgrav 			if (scan_scaled(arg, &val64) == -1)
923e4a9863fSDag-Erling Smørgrav 				fatal("%.200s line %d: Bad number '%s': %s",
924e4a9863fSDag-Erling Smørgrav 				    filename, linenum, arg, strerror(errno));
925e4a9863fSDag-Erling Smørgrav 			/* check for too-large or too-small limits */
926e4a9863fSDag-Erling Smørgrav 			if (val64 > UINT_MAX)
927333ee039SDag-Erling Smørgrav 				fatal("%.200s line %d: RekeyLimit too large",
928333ee039SDag-Erling Smørgrav 				    filename, linenum);
929e4a9863fSDag-Erling Smørgrav 			if (val64 != 0 && val64 < 16)
930333ee039SDag-Erling Smørgrav 				fatal("%.200s line %d: RekeyLimit too small",
931333ee039SDag-Erling Smørgrav 				    filename, linenum);
932e4a9863fSDag-Erling Smørgrav 		}
933d4af9e69SDag-Erling Smørgrav 		if (*activep && options->rekey_limit == -1)
934d4af9e69SDag-Erling Smørgrav 			options->rekey_limit = (u_int32_t)val64;
935e4a9863fSDag-Erling Smørgrav 		if (s != NULL) { /* optional rekey interval present */
936e4a9863fSDag-Erling Smørgrav 			if (strcmp(s, "none") == 0) {
937e4a9863fSDag-Erling Smørgrav 				(void)strdelim(&s);	/* discard */
938e4a9863fSDag-Erling Smørgrav 				break;
939e4a9863fSDag-Erling Smørgrav 			}
940e4a9863fSDag-Erling Smørgrav 			intptr = &options->rekey_interval;
941e4a9863fSDag-Erling Smørgrav 			goto parse_time;
942e4a9863fSDag-Erling Smørgrav 		}
943cf2b5f3bSDag-Erling Smørgrav 		break;
944cf2b5f3bSDag-Erling Smørgrav 
945511b41d2SMark Murray 	case oIdentityFile:
946c2d3a559SKris Kennaway 		arg = strdelim(&s);
947c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
948511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
949511b41d2SMark Murray 		if (*activep) {
950ca3176e7SBrian Feldman 			intptr = &options->num_identity_files;
951e8aafc91SKris Kennaway 			if (*intptr >= SSH_MAX_IDENTITY_FILES)
952511b41d2SMark Murray 				fatal("%.200s line %d: Too many identity files specified (max %d).",
953511b41d2SMark Murray 				    filename, linenum, SSH_MAX_IDENTITY_FILES);
95473370613SDag-Erling Smørgrav 			add_identity_file(options, NULL, arg, userconfig);
955511b41d2SMark Murray 		}
956511b41d2SMark Murray 		break;
957511b41d2SMark Murray 
958c2d3a559SKris Kennaway 	case oXAuthLocation:
959c2d3a559SKris Kennaway 		charptr=&options->xauth_location;
960c2d3a559SKris Kennaway 		goto parse_string;
961c2d3a559SKris Kennaway 
962511b41d2SMark Murray 	case oUser:
963511b41d2SMark Murray 		charptr = &options->user;
964511b41d2SMark Murray parse_string:
965c2d3a559SKris Kennaway 		arg = strdelim(&s);
966c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
967e146993eSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.",
968e146993eSDag-Erling Smørgrav 			    filename, linenum);
969511b41d2SMark Murray 		if (*activep && *charptr == NULL)
970c2d3a559SKris Kennaway 			*charptr = xstrdup(arg);
971511b41d2SMark Murray 		break;
972511b41d2SMark Murray 
973511b41d2SMark Murray 	case oGlobalKnownHostsFile:
974e146993eSDag-Erling Smørgrav 		cpptr = (char **)&options->system_hostfiles;
975e146993eSDag-Erling Smørgrav 		uintptr = &options->num_system_hostfiles;
976e146993eSDag-Erling Smørgrav 		max_entries = SSH_MAX_HOSTS_FILES;
977e146993eSDag-Erling Smørgrav parse_char_array:
978e146993eSDag-Erling Smørgrav 		if (*activep && *uintptr == 0) {
979e146993eSDag-Erling Smørgrav 			while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
980e146993eSDag-Erling Smørgrav 				if ((*uintptr) >= max_entries)
981e146993eSDag-Erling Smørgrav 					fatal("%s line %d: "
982e146993eSDag-Erling Smørgrav 					    "too many authorized keys files.",
983e146993eSDag-Erling Smørgrav 					    filename, linenum);
984e146993eSDag-Erling Smørgrav 				cpptr[(*uintptr)++] = xstrdup(arg);
985e146993eSDag-Erling Smørgrav 			}
986e146993eSDag-Erling Smørgrav 		}
987e146993eSDag-Erling Smørgrav 		return 0;
988511b41d2SMark Murray 
989511b41d2SMark Murray 	case oUserKnownHostsFile:
990e146993eSDag-Erling Smørgrav 		cpptr = (char **)&options->user_hostfiles;
991e146993eSDag-Erling Smørgrav 		uintptr = &options->num_user_hostfiles;
992e146993eSDag-Erling Smørgrav 		max_entries = SSH_MAX_HOSTS_FILES;
993e146993eSDag-Erling Smørgrav 		goto parse_char_array;
994e8aafc91SKris Kennaway 
995511b41d2SMark Murray 	case oHostName:
996511b41d2SMark Murray 		charptr = &options->hostname;
997511b41d2SMark Murray 		goto parse_string;
998511b41d2SMark Murray 
999ca3176e7SBrian Feldman 	case oHostKeyAlias:
1000ca3176e7SBrian Feldman 		charptr = &options->host_key_alias;
1001ca3176e7SBrian Feldman 		goto parse_string;
1002ca3176e7SBrian Feldman 
1003ca3176e7SBrian Feldman 	case oPreferredAuthentications:
1004ca3176e7SBrian Feldman 		charptr = &options->preferred_authentications;
1005ca3176e7SBrian Feldman 		goto parse_string;
1006ca3176e7SBrian Feldman 
1007af12a3e7SDag-Erling Smørgrav 	case oBindAddress:
1008af12a3e7SDag-Erling Smørgrav 		charptr = &options->bind_address;
1009af12a3e7SDag-Erling Smørgrav 		goto parse_string;
1010af12a3e7SDag-Erling Smørgrav 
1011b15c8340SDag-Erling Smørgrav 	case oPKCS11Provider:
1012b15c8340SDag-Erling Smørgrav 		charptr = &options->pkcs11_provider;
1013af12a3e7SDag-Erling Smørgrav 		goto parse_string;
1014af12a3e7SDag-Erling Smørgrav 
1015511b41d2SMark Murray 	case oProxyCommand:
1016b74df5b2SDag-Erling Smørgrav 		charptr = &options->proxy_command;
1017b74df5b2SDag-Erling Smørgrav parse_command:
1018cf2b5f3bSDag-Erling Smørgrav 		if (s == NULL)
1019cf2b5f3bSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1020e73e9afaSDag-Erling Smørgrav 		len = strspn(s, WHITESPACE "=");
1021511b41d2SMark Murray 		if (*activep && *charptr == NULL)
1022e73e9afaSDag-Erling Smørgrav 			*charptr = xstrdup(s + len);
1023511b41d2SMark Murray 		return 0;
1024511b41d2SMark Murray 
1025511b41d2SMark Murray 	case oPort:
1026511b41d2SMark Murray 		intptr = &options->port;
1027511b41d2SMark Murray parse_int:
1028c2d3a559SKris Kennaway 		arg = strdelim(&s);
1029c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1030511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1031c2d3a559SKris Kennaway 		if (arg[0] < '0' || arg[0] > '9')
1032511b41d2SMark Murray 			fatal("%.200s line %d: Bad number.", filename, linenum);
1033511b41d2SMark Murray 
1034511b41d2SMark Murray 		/* Octal, decimal, or hex format? */
1035c2d3a559SKris Kennaway 		value = strtol(arg, &endofnumber, 0);
1036c2d3a559SKris Kennaway 		if (arg == endofnumber)
1037511b41d2SMark Murray 			fatal("%.200s line %d: Bad number.", filename, linenum);
1038511b41d2SMark Murray 		if (*activep && *intptr == -1)
1039511b41d2SMark Murray 			*intptr = value;
1040511b41d2SMark Murray 		break;
1041511b41d2SMark Murray 
1042511b41d2SMark Murray 	case oConnectionAttempts:
1043511b41d2SMark Murray 		intptr = &options->connection_attempts;
1044511b41d2SMark Murray 		goto parse_int;
1045511b41d2SMark Murray 
1046511b41d2SMark Murray 	case oCipher:
1047511b41d2SMark Murray 		intptr = &options->cipher;
1048c2d3a559SKris Kennaway 		arg = strdelim(&s);
1049c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1050db1cb46cSKris Kennaway 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1051c2d3a559SKris Kennaway 		value = cipher_number(arg);
1052511b41d2SMark Murray 		if (value == -1)
1053511b41d2SMark Murray 			fatal("%.200s line %d: Bad cipher '%s'.",
1054c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1055511b41d2SMark Murray 		if (*activep && *intptr == -1)
1056511b41d2SMark Murray 			*intptr = value;
1057511b41d2SMark Murray 		break;
1058511b41d2SMark Murray 
1059e8aafc91SKris Kennaway 	case oCiphers:
1060c2d3a559SKris Kennaway 		arg = strdelim(&s);
1061c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1062db1cb46cSKris Kennaway 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1063c2d3a559SKris Kennaway 		if (!ciphers_valid(arg))
1064e8aafc91SKris Kennaway 			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1065c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1066e8aafc91SKris Kennaway 		if (*activep && options->ciphers == NULL)
1067c2d3a559SKris Kennaway 			options->ciphers = xstrdup(arg);
1068e8aafc91SKris Kennaway 		break;
1069e8aafc91SKris Kennaway 
1070ca3176e7SBrian Feldman 	case oMacs:
1071ca3176e7SBrian Feldman 		arg = strdelim(&s);
1072ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
1073ca3176e7SBrian Feldman 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1074ca3176e7SBrian Feldman 		if (!mac_valid(arg))
1075ca3176e7SBrian Feldman 			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
1076ca3176e7SBrian Feldman 			    filename, linenum, arg ? arg : "<NONE>");
1077ca3176e7SBrian Feldman 		if (*activep && options->macs == NULL)
1078ca3176e7SBrian Feldman 			options->macs = xstrdup(arg);
1079ca3176e7SBrian Feldman 		break;
1080ca3176e7SBrian Feldman 
10814a421b63SDag-Erling Smørgrav 	case oKexAlgorithms:
10824a421b63SDag-Erling Smørgrav 		arg = strdelim(&s);
10834a421b63SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
10844a421b63SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.",
10854a421b63SDag-Erling Smørgrav 			    filename, linenum);
10864a421b63SDag-Erling Smørgrav 		if (!kex_names_valid(arg))
10874a421b63SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
10884a421b63SDag-Erling Smørgrav 			    filename, linenum, arg ? arg : "<NONE>");
10894a421b63SDag-Erling Smørgrav 		if (*activep && options->kex_algorithms == NULL)
10904a421b63SDag-Erling Smørgrav 			options->kex_algorithms = xstrdup(arg);
10914a421b63SDag-Erling Smørgrav 		break;
10924a421b63SDag-Erling Smørgrav 
1093ca3176e7SBrian Feldman 	case oHostKeyAlgorithms:
1094ca3176e7SBrian Feldman 		arg = strdelim(&s);
1095ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
1096ca3176e7SBrian Feldman 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1097ca3176e7SBrian Feldman 		if (!key_names_valid2(arg))
1098ca3176e7SBrian Feldman 			fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
1099ca3176e7SBrian Feldman 			    filename, linenum, arg ? arg : "<NONE>");
1100ca3176e7SBrian Feldman 		if (*activep && options->hostkeyalgorithms == NULL)
1101ca3176e7SBrian Feldman 			options->hostkeyalgorithms = xstrdup(arg);
1102ca3176e7SBrian Feldman 		break;
1103ca3176e7SBrian Feldman 
1104e8aafc91SKris Kennaway 	case oProtocol:
1105e8aafc91SKris Kennaway 		intptr = &options->protocol;
1106c2d3a559SKris Kennaway 		arg = strdelim(&s);
1107c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1108db1cb46cSKris Kennaway 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1109c2d3a559SKris Kennaway 		value = proto_spec(arg);
1110e8aafc91SKris Kennaway 		if (value == SSH_PROTO_UNKNOWN)
1111e8aafc91SKris Kennaway 			fatal("%.200s line %d: Bad protocol spec '%s'.",
1112c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1113e8aafc91SKris Kennaway 		if (*activep && *intptr == SSH_PROTO_UNKNOWN)
1114e8aafc91SKris Kennaway 			*intptr = value;
1115e8aafc91SKris Kennaway 		break;
1116e8aafc91SKris Kennaway 
1117511b41d2SMark Murray 	case oLogLevel:
1118d4af9e69SDag-Erling Smørgrav 		log_level_ptr = &options->log_level;
1119c2d3a559SKris Kennaway 		arg = strdelim(&s);
1120c2d3a559SKris Kennaway 		value = log_level_number(arg);
1121af12a3e7SDag-Erling Smørgrav 		if (value == SYSLOG_LEVEL_NOT_SET)
1122ca3176e7SBrian Feldman 			fatal("%.200s line %d: unsupported log level '%s'",
1123c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1124d4af9e69SDag-Erling Smørgrav 		if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1125d4af9e69SDag-Erling Smørgrav 			*log_level_ptr = (LogLevel) value;
1126511b41d2SMark Murray 		break;
1127511b41d2SMark Murray 
1128af12a3e7SDag-Erling Smørgrav 	case oLocalForward:
1129511b41d2SMark Murray 	case oRemoteForward:
1130cce7d346SDag-Erling Smørgrav 	case oDynamicForward:
1131c2d3a559SKris Kennaway 		arg = strdelim(&s);
1132aa49c926SDag-Erling Smørgrav 		if (arg == NULL || *arg == '\0')
1133af12a3e7SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing port argument.",
1134af12a3e7SDag-Erling Smørgrav 			    filename, linenum);
1135cce7d346SDag-Erling Smørgrav 
1136cce7d346SDag-Erling Smørgrav 		if (opcode == oLocalForward ||
1137cce7d346SDag-Erling Smørgrav 		    opcode == oRemoteForward) {
1138aa49c926SDag-Erling Smørgrav 			arg2 = strdelim(&s);
1139aa49c926SDag-Erling Smørgrav 			if (arg2 == NULL || *arg2 == '\0')
1140aa49c926SDag-Erling Smørgrav 				fatal("%.200s line %d: Missing target argument.",
1141511b41d2SMark Murray 				    filename, linenum);
1142aa49c926SDag-Erling Smørgrav 
1143aa49c926SDag-Erling Smørgrav 			/* construct a string for parse_forward */
1144aa49c926SDag-Erling Smørgrav 			snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
1145cce7d346SDag-Erling Smørgrav 		} else if (opcode == oDynamicForward) {
1146cce7d346SDag-Erling Smørgrav 			strlcpy(fwdarg, arg, sizeof(fwdarg));
1147cce7d346SDag-Erling Smørgrav 		}
1148aa49c926SDag-Erling Smørgrav 
1149cce7d346SDag-Erling Smørgrav 		if (parse_forward(&fwd, fwdarg,
1150cce7d346SDag-Erling Smørgrav 		    opcode == oDynamicForward ? 1 : 0,
1151cce7d346SDag-Erling Smørgrav 		    opcode == oRemoteForward ? 1 : 0) == 0)
1152af12a3e7SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad forwarding specification.",
1153511b41d2SMark Murray 			    filename, linenum);
1154aa49c926SDag-Erling Smørgrav 
1155af12a3e7SDag-Erling Smørgrav 		if (*activep) {
1156cce7d346SDag-Erling Smørgrav 			if (opcode == oLocalForward ||
1157cce7d346SDag-Erling Smørgrav 			    opcode == oDynamicForward)
1158aa49c926SDag-Erling Smørgrav 				add_local_forward(options, &fwd);
1159af12a3e7SDag-Erling Smørgrav 			else if (opcode == oRemoteForward)
1160aa49c926SDag-Erling Smørgrav 				add_remote_forward(options, &fwd);
1161af12a3e7SDag-Erling Smørgrav 		}
1162511b41d2SMark Murray 		break;
1163511b41d2SMark Murray 
1164af12a3e7SDag-Erling Smørgrav 	case oClearAllForwardings:
1165af12a3e7SDag-Erling Smørgrav 		intptr = &options->clear_forwardings;
1166af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
1167af12a3e7SDag-Erling Smørgrav 
1168511b41d2SMark Murray 	case oHost:
1169*f7167e0eSDag-Erling Smørgrav 		if (cmdline)
1170*f7167e0eSDag-Erling Smørgrav 			fatal("Host directive not supported as a command-line "
1171*f7167e0eSDag-Erling Smørgrav 			    "option");
1172511b41d2SMark Murray 		*activep = 0;
1173e146993eSDag-Erling Smørgrav 		arg2 = NULL;
1174e146993eSDag-Erling Smørgrav 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1175e146993eSDag-Erling Smørgrav 			negated = *arg == '!';
1176e146993eSDag-Erling Smørgrav 			if (negated)
1177e146993eSDag-Erling Smørgrav 				arg++;
1178c2d3a559SKris Kennaway 			if (match_pattern(host, arg)) {
1179e146993eSDag-Erling Smørgrav 				if (negated) {
1180e146993eSDag-Erling Smørgrav 					debug("%.200s line %d: Skipping Host "
1181e146993eSDag-Erling Smørgrav 					    "block because of negated match "
1182e146993eSDag-Erling Smørgrav 					    "for %.100s", filename, linenum,
1183e146993eSDag-Erling Smørgrav 					    arg);
1184e146993eSDag-Erling Smørgrav 					*activep = 0;
1185511b41d2SMark Murray 					break;
1186511b41d2SMark Murray 				}
1187e146993eSDag-Erling Smørgrav 				if (!*activep)
1188e146993eSDag-Erling Smørgrav 					arg2 = arg; /* logged below */
1189e146993eSDag-Erling Smørgrav 				*activep = 1;
1190e146993eSDag-Erling Smørgrav 			}
1191e146993eSDag-Erling Smørgrav 		}
1192e146993eSDag-Erling Smørgrav 		if (*activep)
1193e146993eSDag-Erling Smørgrav 			debug("%.200s line %d: Applying options for %.100s",
1194e146993eSDag-Erling Smørgrav 			    filename, linenum, arg2);
1195c2d3a559SKris Kennaway 		/* Avoid garbage check below, as strdelim is done. */
1196511b41d2SMark Murray 		return 0;
1197511b41d2SMark Murray 
1198*f7167e0eSDag-Erling Smørgrav 	case oMatch:
1199*f7167e0eSDag-Erling Smørgrav 		if (cmdline)
1200*f7167e0eSDag-Erling Smørgrav 			fatal("Host directive not supported as a command-line "
1201*f7167e0eSDag-Erling Smørgrav 			    "option");
1202*f7167e0eSDag-Erling Smørgrav 		value = match_cfg_line(options, &s, pw, host,
1203*f7167e0eSDag-Erling Smørgrav 		    filename, linenum);
1204*f7167e0eSDag-Erling Smørgrav 		if (value < 0)
1205*f7167e0eSDag-Erling Smørgrav 			fatal("%.200s line %d: Bad Match condition", filename,
1206*f7167e0eSDag-Erling Smørgrav 			    linenum);
1207*f7167e0eSDag-Erling Smørgrav 		*activep = value;
1208*f7167e0eSDag-Erling Smørgrav 		break;
1209*f7167e0eSDag-Erling Smørgrav 
1210511b41d2SMark Murray 	case oEscapeChar:
1211511b41d2SMark Murray 		intptr = &options->escape_char;
1212c2d3a559SKris Kennaway 		arg = strdelim(&s);
1213c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1214511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1215c2d3a559SKris Kennaway 		if (arg[0] == '^' && arg[2] == 0 &&
1216ca3176e7SBrian Feldman 		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1217ca3176e7SBrian Feldman 			value = (u_char) arg[1] & 31;
1218c2d3a559SKris Kennaway 		else if (strlen(arg) == 1)
1219ca3176e7SBrian Feldman 			value = (u_char) arg[0];
1220c2d3a559SKris Kennaway 		else if (strcmp(arg, "none") == 0)
1221af12a3e7SDag-Erling Smørgrav 			value = SSH_ESCAPECHAR_NONE;
1222511b41d2SMark Murray 		else {
1223511b41d2SMark Murray 			fatal("%.200s line %d: Bad escape character.",
1224511b41d2SMark Murray 			    filename, linenum);
1225511b41d2SMark Murray 			/* NOTREACHED */
1226511b41d2SMark Murray 			value = 0;	/* Avoid compiler warning. */
1227511b41d2SMark Murray 		}
1228511b41d2SMark Murray 		if (*activep && *intptr == -1)
1229511b41d2SMark Murray 			*intptr = value;
1230511b41d2SMark Murray 		break;
1231511b41d2SMark Murray 
1232cf2b5f3bSDag-Erling Smørgrav 	case oAddressFamily:
1233cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->address_family;
1234*f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_addressfamily;
1235*f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
1236cf2b5f3bSDag-Erling Smørgrav 
1237e73e9afaSDag-Erling Smørgrav 	case oEnableSSHKeysign:
1238e73e9afaSDag-Erling Smørgrav 		intptr = &options->enable_ssh_keysign;
1239e73e9afaSDag-Erling Smørgrav 		goto parse_flag;
1240e73e9afaSDag-Erling Smørgrav 
12415962c0e9SDag-Erling Smørgrav 	case oIdentitiesOnly:
12425962c0e9SDag-Erling Smørgrav 		intptr = &options->identities_only;
12435962c0e9SDag-Erling Smørgrav 		goto parse_flag;
12445962c0e9SDag-Erling Smørgrav 
12451ec0d754SDag-Erling Smørgrav 	case oServerAliveInterval:
12461ec0d754SDag-Erling Smørgrav 		intptr = &options->server_alive_interval;
12471ec0d754SDag-Erling Smørgrav 		goto parse_time;
12481ec0d754SDag-Erling Smørgrav 
12491ec0d754SDag-Erling Smørgrav 	case oServerAliveCountMax:
12501ec0d754SDag-Erling Smørgrav 		intptr = &options->server_alive_count_max;
12511ec0d754SDag-Erling Smørgrav 		goto parse_int;
12521ec0d754SDag-Erling Smørgrav 
125321e764dfSDag-Erling Smørgrav 	case oSendEnv:
125421e764dfSDag-Erling Smørgrav 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
125521e764dfSDag-Erling Smørgrav 			if (strchr(arg, '=') != NULL)
125621e764dfSDag-Erling Smørgrav 				fatal("%s line %d: Invalid environment name.",
125721e764dfSDag-Erling Smørgrav 				    filename, linenum);
1258aa49c926SDag-Erling Smørgrav 			if (!*activep)
1259aa49c926SDag-Erling Smørgrav 				continue;
126021e764dfSDag-Erling Smørgrav 			if (options->num_send_env >= MAX_SEND_ENV)
126121e764dfSDag-Erling Smørgrav 				fatal("%s line %d: too many send env.",
126221e764dfSDag-Erling Smørgrav 				    filename, linenum);
126321e764dfSDag-Erling Smørgrav 			options->send_env[options->num_send_env++] =
126421e764dfSDag-Erling Smørgrav 			    xstrdup(arg);
126521e764dfSDag-Erling Smørgrav 		}
126621e764dfSDag-Erling Smørgrav 		break;
126721e764dfSDag-Erling Smørgrav 
126821e764dfSDag-Erling Smørgrav 	case oControlPath:
126921e764dfSDag-Erling Smørgrav 		charptr = &options->control_path;
127021e764dfSDag-Erling Smørgrav 		goto parse_string;
127121e764dfSDag-Erling Smørgrav 
127221e764dfSDag-Erling Smørgrav 	case oControlMaster:
127321e764dfSDag-Erling Smørgrav 		intptr = &options->control_master;
1274*f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_controlmaster;
1275*f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
127621e764dfSDag-Erling Smørgrav 
1277e2f6069cSDag-Erling Smørgrav 	case oControlPersist:
1278e2f6069cSDag-Erling Smørgrav 		/* no/false/yes/true, or a time spec */
1279e2f6069cSDag-Erling Smørgrav 		intptr = &options->control_persist;
1280e2f6069cSDag-Erling Smørgrav 		arg = strdelim(&s);
1281e2f6069cSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1282e2f6069cSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing ControlPersist"
1283e2f6069cSDag-Erling Smørgrav 			    " argument.", filename, linenum);
1284e2f6069cSDag-Erling Smørgrav 		value = 0;
1285e2f6069cSDag-Erling Smørgrav 		value2 = 0;	/* timeout */
1286e2f6069cSDag-Erling Smørgrav 		if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1287e2f6069cSDag-Erling Smørgrav 			value = 0;
1288e2f6069cSDag-Erling Smørgrav 		else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1289e2f6069cSDag-Erling Smørgrav 			value = 1;
1290e2f6069cSDag-Erling Smørgrav 		else if ((value2 = convtime(arg)) >= 0)
1291e2f6069cSDag-Erling Smørgrav 			value = 1;
1292e2f6069cSDag-Erling Smørgrav 		else
1293e2f6069cSDag-Erling Smørgrav 			fatal("%.200s line %d: Bad ControlPersist argument.",
1294e2f6069cSDag-Erling Smørgrav 			    filename, linenum);
1295e2f6069cSDag-Erling Smørgrav 		if (*activep && *intptr == -1) {
1296e2f6069cSDag-Erling Smørgrav 			*intptr = value;
1297e2f6069cSDag-Erling Smørgrav 			options->control_persist_timeout = value2;
1298e2f6069cSDag-Erling Smørgrav 		}
1299e2f6069cSDag-Erling Smørgrav 		break;
1300e2f6069cSDag-Erling Smørgrav 
1301aa49c926SDag-Erling Smørgrav 	case oHashKnownHosts:
1302aa49c926SDag-Erling Smørgrav 		intptr = &options->hash_known_hosts;
1303aa49c926SDag-Erling Smørgrav 		goto parse_flag;
1304aa49c926SDag-Erling Smørgrav 
1305b74df5b2SDag-Erling Smørgrav 	case oTunnel:
1306b74df5b2SDag-Erling Smørgrav 		intptr = &options->tun_open;
1307*f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_tunnel;
1308*f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
1309b74df5b2SDag-Erling Smørgrav 
1310b74df5b2SDag-Erling Smørgrav 	case oTunnelDevice:
1311b74df5b2SDag-Erling Smørgrav 		arg = strdelim(&s);
1312b74df5b2SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1313b74df5b2SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1314b74df5b2SDag-Erling Smørgrav 		value = a2tun(arg, &value2);
1315b74df5b2SDag-Erling Smørgrav 		if (value == SSH_TUNID_ERR)
1316b74df5b2SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad tun device.", filename, linenum);
1317b74df5b2SDag-Erling Smørgrav 		if (*activep) {
1318b74df5b2SDag-Erling Smørgrav 			options->tun_local = value;
1319b74df5b2SDag-Erling Smørgrav 			options->tun_remote = value2;
1320b74df5b2SDag-Erling Smørgrav 		}
1321b74df5b2SDag-Erling Smørgrav 		break;
1322b74df5b2SDag-Erling Smørgrav 
1323b74df5b2SDag-Erling Smørgrav 	case oLocalCommand:
1324b74df5b2SDag-Erling Smørgrav 		charptr = &options->local_command;
1325b74df5b2SDag-Erling Smørgrav 		goto parse_command;
1326b74df5b2SDag-Erling Smørgrav 
1327b74df5b2SDag-Erling Smørgrav 	case oPermitLocalCommand:
1328b74df5b2SDag-Erling Smørgrav 		intptr = &options->permit_local_command;
1329b74df5b2SDag-Erling Smørgrav 		goto parse_flag;
1330b74df5b2SDag-Erling Smørgrav 
1331d4af9e69SDag-Erling Smørgrav 	case oVisualHostKey:
1332d4af9e69SDag-Erling Smørgrav 		intptr = &options->visual_host_key;
1333d4af9e69SDag-Erling Smørgrav 		goto parse_flag;
1334d4af9e69SDag-Erling Smørgrav 
13354a421b63SDag-Erling Smørgrav 	case oIPQoS:
13364a421b63SDag-Erling Smørgrav 		arg = strdelim(&s);
13374a421b63SDag-Erling Smørgrav 		if ((value = parse_ipqos(arg)) == -1)
13384a421b63SDag-Erling Smørgrav 			fatal("%s line %d: Bad IPQoS value: %s",
13394a421b63SDag-Erling Smørgrav 			    filename, linenum, arg);
13404a421b63SDag-Erling Smørgrav 		arg = strdelim(&s);
13414a421b63SDag-Erling Smørgrav 		if (arg == NULL)
13424a421b63SDag-Erling Smørgrav 			value2 = value;
13434a421b63SDag-Erling Smørgrav 		else if ((value2 = parse_ipqos(arg)) == -1)
13444a421b63SDag-Erling Smørgrav 			fatal("%s line %d: Bad IPQoS value: %s",
13454a421b63SDag-Erling Smørgrav 			    filename, linenum, arg);
13464a421b63SDag-Erling Smørgrav 		if (*activep) {
13474a421b63SDag-Erling Smørgrav 			options->ip_qos_interactive = value;
13484a421b63SDag-Erling Smørgrav 			options->ip_qos_bulk = value2;
13494a421b63SDag-Erling Smørgrav 		}
13504a421b63SDag-Erling Smørgrav 		break;
13514a421b63SDag-Erling Smørgrav 
13527aee6ffeSDag-Erling Smørgrav 	case oUseRoaming:
13537aee6ffeSDag-Erling Smørgrav 		intptr = &options->use_roaming;
13547aee6ffeSDag-Erling Smørgrav 		goto parse_flag;
13557aee6ffeSDag-Erling Smørgrav 
1356e146993eSDag-Erling Smørgrav 	case oRequestTTY:
1357e146993eSDag-Erling Smørgrav 		intptr = &options->request_tty;
1358*f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_requesttty;
1359*f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
1360975616f0SDag-Erling Smørgrav 
136189986192SBrooks Davis 	case oHPNDisabled:
136289986192SBrooks Davis 		intptr = &options->hpn_disabled;
136389986192SBrooks Davis 		goto parse_flag;
136489986192SBrooks Davis 
136589986192SBrooks Davis 	case oHPNBufferSize:
136689986192SBrooks Davis 		intptr = &options->hpn_buffer_size;
136789986192SBrooks Davis 		goto parse_int;
136889986192SBrooks Davis 
136989986192SBrooks Davis 	case oTcpRcvBufPoll:
137089986192SBrooks Davis 		intptr = &options->tcp_rcv_buf_poll;
137189986192SBrooks Davis 		goto parse_flag;
137289986192SBrooks Davis 
137389986192SBrooks Davis 	case oTcpRcvBuf:
137489986192SBrooks Davis 		intptr = &options->tcp_rcv_buf;
137589986192SBrooks Davis 		goto parse_int;
137689986192SBrooks Davis 
137789986192SBrooks Davis #ifdef	NONE_CIPHER_ENABLED
137889986192SBrooks Davis 	case oNoneEnabled:
137989986192SBrooks Davis 		intptr = &options->none_enabled;
138089986192SBrooks Davis 		goto parse_flag;
138189986192SBrooks Davis 
138289986192SBrooks Davis 	/*
138389986192SBrooks Davis 	 * We check to see if the command comes from the command line or not.
138489986192SBrooks Davis 	 * If it does then enable it otherwise fail.  NONE must never be a
138589986192SBrooks Davis 	 * default configuration.
138689986192SBrooks Davis 	 */
138789986192SBrooks Davis 	case oNoneSwitch:
138889986192SBrooks Davis 		if (strcmp(filename,"command-line") == 0) {
138989986192SBrooks Davis 			intptr = &options->none_switch;
139089986192SBrooks Davis 			goto parse_flag;
139189986192SBrooks Davis 		} else {
139289986192SBrooks Davis 			debug("NoneSwitch directive found in %.200s.",
139389986192SBrooks Davis 			    filename);
139489986192SBrooks Davis 			error("NoneSwitch is found in %.200s.\n"
139589986192SBrooks Davis 			    "You may only use this configuration option "
139689986192SBrooks Davis 			    "from the command line", filename);
139789986192SBrooks Davis 			error("Continuing...");
139889986192SBrooks Davis 			return 0;
139989986192SBrooks Davis 		}
140089986192SBrooks Davis #endif
140189986192SBrooks Davis 
1402e146993eSDag-Erling Smørgrav 	case oVersionAddendum:
1403462c32cbSDag-Erling Smørgrav 		if (s == NULL)
1404462c32cbSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename,
1405462c32cbSDag-Erling Smørgrav 			    linenum);
1406462c32cbSDag-Erling Smørgrav 		len = strspn(s, WHITESPACE);
1407462c32cbSDag-Erling Smørgrav 		if (*activep && options->version_addendum == NULL) {
1408462c32cbSDag-Erling Smørgrav 			if (strcasecmp(s + len, "none") == 0)
1409462c32cbSDag-Erling Smørgrav 				options->version_addendum = xstrdup("");
1410462c32cbSDag-Erling Smørgrav 			else if (strchr(s + len, '\r') != NULL)
1411462c32cbSDag-Erling Smørgrav 				fatal("%.200s line %d: Invalid argument",
1412462c32cbSDag-Erling Smørgrav 				    filename, linenum);
1413462c32cbSDag-Erling Smørgrav 			else
1414462c32cbSDag-Erling Smørgrav 				options->version_addendum = xstrdup(s + len);
1415462c32cbSDag-Erling Smørgrav 		}
1416462c32cbSDag-Erling Smørgrav 		return 0;
1417e146993eSDag-Erling Smørgrav 
1418e4a9863fSDag-Erling Smørgrav 	case oIgnoreUnknown:
1419e4a9863fSDag-Erling Smørgrav 		charptr = &options->ignored_unknown;
1420e4a9863fSDag-Erling Smørgrav 		goto parse_string;
1421e4a9863fSDag-Erling Smørgrav 
1422*f7167e0eSDag-Erling Smørgrav 	case oProxyUseFdpass:
1423*f7167e0eSDag-Erling Smørgrav 		intptr = &options->proxy_use_fdpass;
1424*f7167e0eSDag-Erling Smørgrav 		goto parse_flag;
1425*f7167e0eSDag-Erling Smørgrav 
1426*f7167e0eSDag-Erling Smørgrav 	case oCanonicalDomains:
1427*f7167e0eSDag-Erling Smørgrav 		value = options->num_canonical_domains != 0;
1428*f7167e0eSDag-Erling Smørgrav 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1429*f7167e0eSDag-Erling Smørgrav 			valid_domain(arg, filename, linenum);
1430*f7167e0eSDag-Erling Smørgrav 			if (!*activep || value)
1431*f7167e0eSDag-Erling Smørgrav 				continue;
1432*f7167e0eSDag-Erling Smørgrav 			if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
1433*f7167e0eSDag-Erling Smørgrav 				fatal("%s line %d: too many hostname suffixes.",
1434*f7167e0eSDag-Erling Smørgrav 				    filename, linenum);
1435*f7167e0eSDag-Erling Smørgrav 			options->canonical_domains[
1436*f7167e0eSDag-Erling Smørgrav 			    options->num_canonical_domains++] = xstrdup(arg);
1437*f7167e0eSDag-Erling Smørgrav 		}
1438*f7167e0eSDag-Erling Smørgrav 		break;
1439*f7167e0eSDag-Erling Smørgrav 
1440*f7167e0eSDag-Erling Smørgrav 	case oCanonicalizePermittedCNAMEs:
1441*f7167e0eSDag-Erling Smørgrav 		value = options->num_permitted_cnames != 0;
1442*f7167e0eSDag-Erling Smørgrav 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1443*f7167e0eSDag-Erling Smørgrav 			/* Either '*' for everything or 'list:list' */
1444*f7167e0eSDag-Erling Smørgrav 			if (strcmp(arg, "*") == 0)
1445*f7167e0eSDag-Erling Smørgrav 				arg2 = arg;
1446*f7167e0eSDag-Erling Smørgrav 			else {
1447*f7167e0eSDag-Erling Smørgrav 				lowercase(arg);
1448*f7167e0eSDag-Erling Smørgrav 				if ((arg2 = strchr(arg, ':')) == NULL ||
1449*f7167e0eSDag-Erling Smørgrav 				    arg2[1] == '\0') {
1450*f7167e0eSDag-Erling Smørgrav 					fatal("%s line %d: "
1451*f7167e0eSDag-Erling Smørgrav 					    "Invalid permitted CNAME \"%s\"",
1452*f7167e0eSDag-Erling Smørgrav 					    filename, linenum, arg);
1453*f7167e0eSDag-Erling Smørgrav 				}
1454*f7167e0eSDag-Erling Smørgrav 				*arg2 = '\0';
1455*f7167e0eSDag-Erling Smørgrav 				arg2++;
1456*f7167e0eSDag-Erling Smørgrav 			}
1457*f7167e0eSDag-Erling Smørgrav 			if (!*activep || value)
1458*f7167e0eSDag-Erling Smørgrav 				continue;
1459*f7167e0eSDag-Erling Smørgrav 			if (options->num_permitted_cnames >= MAX_CANON_DOMAINS)
1460*f7167e0eSDag-Erling Smørgrav 				fatal("%s line %d: too many permitted CNAMEs.",
1461*f7167e0eSDag-Erling Smørgrav 				    filename, linenum);
1462*f7167e0eSDag-Erling Smørgrav 			cname = options->permitted_cnames +
1463*f7167e0eSDag-Erling Smørgrav 			    options->num_permitted_cnames++;
1464*f7167e0eSDag-Erling Smørgrav 			cname->source_list = xstrdup(arg);
1465*f7167e0eSDag-Erling Smørgrav 			cname->target_list = xstrdup(arg2);
1466*f7167e0eSDag-Erling Smørgrav 		}
1467*f7167e0eSDag-Erling Smørgrav 		break;
1468*f7167e0eSDag-Erling Smørgrav 
1469*f7167e0eSDag-Erling Smørgrav 	case oCanonicalizeHostname:
1470*f7167e0eSDag-Erling Smørgrav 		intptr = &options->canonicalize_hostname;
1471*f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_canonicalizehostname;
1472*f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
1473*f7167e0eSDag-Erling Smørgrav 
1474*f7167e0eSDag-Erling Smørgrav 	case oCanonicalizeMaxDots:
1475*f7167e0eSDag-Erling Smørgrav 		intptr = &options->canonicalize_max_dots;
1476*f7167e0eSDag-Erling Smørgrav 		goto parse_int;
1477*f7167e0eSDag-Erling Smørgrav 
1478*f7167e0eSDag-Erling Smørgrav 	case oCanonicalizeFallbackLocal:
1479*f7167e0eSDag-Erling Smørgrav 		intptr = &options->canonicalize_fallback_local;
1480*f7167e0eSDag-Erling Smørgrav 		goto parse_flag;
1481*f7167e0eSDag-Erling Smørgrav 
148280628bacSDag-Erling Smørgrav 	case oDeprecated:
148380628bacSDag-Erling Smørgrav 		debug("%s line %d: Deprecated option \"%s\"",
148480628bacSDag-Erling Smørgrav 		    filename, linenum, keyword);
148580628bacSDag-Erling Smørgrav 		return 0;
148680628bacSDag-Erling Smørgrav 
1487cf2b5f3bSDag-Erling Smørgrav 	case oUnsupported:
1488cf2b5f3bSDag-Erling Smørgrav 		error("%s line %d: Unsupported option \"%s\"",
1489cf2b5f3bSDag-Erling Smørgrav 		    filename, linenum, keyword);
1490cf2b5f3bSDag-Erling Smørgrav 		return 0;
1491cf2b5f3bSDag-Erling Smørgrav 
1492511b41d2SMark Murray 	default:
1493511b41d2SMark Murray 		fatal("process_config_line: Unimplemented opcode %d", opcode);
1494511b41d2SMark Murray 	}
1495511b41d2SMark Murray 
1496511b41d2SMark Murray 	/* Check that there is no garbage at end of line. */
1497ca3176e7SBrian Feldman 	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1498c2d3a559SKris Kennaway 		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
1499c2d3a559SKris Kennaway 		    filename, linenum, arg);
1500c2d3a559SKris Kennaway 	}
1501511b41d2SMark Murray 	return 0;
1502511b41d2SMark Murray }
1503511b41d2SMark Murray 
1504511b41d2SMark Murray 
1505511b41d2SMark Murray /*
1506511b41d2SMark Murray  * Reads the config file and modifies the options accordingly.  Options
1507511b41d2SMark Murray  * should already be initialized before this call.  This never returns if
1508af12a3e7SDag-Erling Smørgrav  * there is an error.  If the file does not exist, this returns 0.
1509511b41d2SMark Murray  */
1510511b41d2SMark Murray 
1511af12a3e7SDag-Erling Smørgrav int
1512*f7167e0eSDag-Erling Smørgrav read_config_file(const char *filename, struct passwd *pw, const char *host,
1513*f7167e0eSDag-Erling Smørgrav     Options *options, int flags)
1514511b41d2SMark Murray {
1515511b41d2SMark Murray 	FILE *f;
1516511b41d2SMark Murray 	char line[1024];
1517511b41d2SMark Murray 	int active, linenum;
1518511b41d2SMark Murray 	int bad_options = 0;
1519511b41d2SMark Murray 
152021e764dfSDag-Erling Smørgrav 	if ((f = fopen(filename, "r")) == NULL)
1521af12a3e7SDag-Erling Smørgrav 		return 0;
1522511b41d2SMark Murray 
152373370613SDag-Erling Smørgrav 	if (flags & SSHCONF_CHECKPERM) {
152421e764dfSDag-Erling Smørgrav 		struct stat sb;
152521e764dfSDag-Erling Smørgrav 
152621e764dfSDag-Erling Smørgrav 		if (fstat(fileno(f), &sb) == -1)
152721e764dfSDag-Erling Smørgrav 			fatal("fstat %s: %s", filename, strerror(errno));
152821e764dfSDag-Erling Smørgrav 		if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
152921e764dfSDag-Erling Smørgrav 		    (sb.st_mode & 022) != 0))
153021e764dfSDag-Erling Smørgrav 			fatal("Bad owner or permissions on %s", filename);
153121e764dfSDag-Erling Smørgrav 	}
153221e764dfSDag-Erling Smørgrav 
1533511b41d2SMark Murray 	debug("Reading configuration data %.200s", filename);
1534511b41d2SMark Murray 
1535511b41d2SMark Murray 	/*
1536511b41d2SMark Murray 	 * Mark that we are now processing the options.  This flag is turned
1537511b41d2SMark Murray 	 * on/off by Host specifications.
1538511b41d2SMark Murray 	 */
1539511b41d2SMark Murray 	active = 1;
1540511b41d2SMark Murray 	linenum = 0;
1541511b41d2SMark Murray 	while (fgets(line, sizeof(line), f)) {
1542511b41d2SMark Murray 		/* Update line number counter. */
1543511b41d2SMark Murray 		linenum++;
1544*f7167e0eSDag-Erling Smørgrav 		if (process_config_line(options, pw, host, line, filename,
1545*f7167e0eSDag-Erling Smørgrav 		    linenum, &active, flags & SSHCONF_USERCONF) != 0)
1546511b41d2SMark Murray 			bad_options++;
1547511b41d2SMark Murray 	}
1548511b41d2SMark Murray 	fclose(f);
1549511b41d2SMark Murray 	if (bad_options > 0)
1550ca3176e7SBrian Feldman 		fatal("%s: terminating, %d bad configuration options",
1551511b41d2SMark Murray 		    filename, bad_options);
1552af12a3e7SDag-Erling Smørgrav 	return 1;
1553511b41d2SMark Murray }
1554511b41d2SMark Murray 
1555511b41d2SMark Murray /*
1556511b41d2SMark Murray  * Initializes options to special values that indicate that they have not yet
1557511b41d2SMark Murray  * been set.  Read_config_file will only set options with this value. Options
1558511b41d2SMark Murray  * are processed in the following order: command line, user config file,
1559511b41d2SMark Murray  * system config file.  Last, fill_default_options is called.
1560511b41d2SMark Murray  */
1561511b41d2SMark Murray 
1562511b41d2SMark Murray void
1563511b41d2SMark Murray initialize_options(Options * options)
1564511b41d2SMark Murray {
1565511b41d2SMark Murray 	memset(options, 'X', sizeof(*options));
1566511b41d2SMark Murray 	options->forward_agent = -1;
1567511b41d2SMark Murray 	options->forward_x11 = -1;
15681ec0d754SDag-Erling Smørgrav 	options->forward_x11_trusted = -1;
1569e2f6069cSDag-Erling Smørgrav 	options->forward_x11_timeout = -1;
1570333ee039SDag-Erling Smørgrav 	options->exit_on_forward_failure = -1;
1571c2d3a559SKris Kennaway 	options->xauth_location = NULL;
1572511b41d2SMark Murray 	options->gateway_ports = -1;
1573511b41d2SMark Murray 	options->use_privileged_port = -1;
1574511b41d2SMark Murray 	options->rsa_authentication = -1;
1575ca3176e7SBrian Feldman 	options->pubkey_authentication = -1;
1576af12a3e7SDag-Erling Smørgrav 	options->challenge_response_authentication = -1;
1577cf2b5f3bSDag-Erling Smørgrav 	options->gss_authentication = -1;
1578cf2b5f3bSDag-Erling Smørgrav 	options->gss_deleg_creds = -1;
1579511b41d2SMark Murray 	options->password_authentication = -1;
158009958426SBrian Feldman 	options->kbd_interactive_authentication = -1;
158109958426SBrian Feldman 	options->kbd_interactive_devices = NULL;
1582511b41d2SMark Murray 	options->rhosts_rsa_authentication = -1;
1583ca3176e7SBrian Feldman 	options->hostbased_authentication = -1;
1584511b41d2SMark Murray 	options->batch_mode = -1;
1585511b41d2SMark Murray 	options->check_host_ip = -1;
1586511b41d2SMark Murray 	options->strict_host_key_checking = -1;
1587511b41d2SMark Murray 	options->compression = -1;
15881ec0d754SDag-Erling Smørgrav 	options->tcp_keep_alive = -1;
1589511b41d2SMark Murray 	options->compression_level = -1;
1590511b41d2SMark Murray 	options->port = -1;
1591cf2b5f3bSDag-Erling Smørgrav 	options->address_family = -1;
1592511b41d2SMark Murray 	options->connection_attempts = -1;
1593cf2b5f3bSDag-Erling Smørgrav 	options->connection_timeout = -1;
1594511b41d2SMark Murray 	options->number_of_password_prompts = -1;
1595511b41d2SMark Murray 	options->cipher = -1;
1596e8aafc91SKris Kennaway 	options->ciphers = NULL;
1597ca3176e7SBrian Feldman 	options->macs = NULL;
15984a421b63SDag-Erling Smørgrav 	options->kex_algorithms = NULL;
1599ca3176e7SBrian Feldman 	options->hostkeyalgorithms = NULL;
1600e8aafc91SKris Kennaway 	options->protocol = SSH_PROTO_UNKNOWN;
1601511b41d2SMark Murray 	options->num_identity_files = 0;
1602511b41d2SMark Murray 	options->hostname = NULL;
1603ca3176e7SBrian Feldman 	options->host_key_alias = NULL;
1604511b41d2SMark Murray 	options->proxy_command = NULL;
1605511b41d2SMark Murray 	options->user = NULL;
1606511b41d2SMark Murray 	options->escape_char = -1;
1607e146993eSDag-Erling Smørgrav 	options->num_system_hostfiles = 0;
1608e146993eSDag-Erling Smørgrav 	options->num_user_hostfiles = 0;
1609e2f6069cSDag-Erling Smørgrav 	options->local_forwards = NULL;
1610511b41d2SMark Murray 	options->num_local_forwards = 0;
1611e2f6069cSDag-Erling Smørgrav 	options->remote_forwards = NULL;
1612511b41d2SMark Murray 	options->num_remote_forwards = 0;
1613af12a3e7SDag-Erling Smørgrav 	options->clear_forwardings = -1;
1614af12a3e7SDag-Erling Smørgrav 	options->log_level = SYSLOG_LEVEL_NOT_SET;
1615ca3176e7SBrian Feldman 	options->preferred_authentications = NULL;
1616af12a3e7SDag-Erling Smørgrav 	options->bind_address = NULL;
1617b15c8340SDag-Erling Smørgrav 	options->pkcs11_provider = NULL;
1618e73e9afaSDag-Erling Smørgrav 	options->enable_ssh_keysign = - 1;
1619af12a3e7SDag-Erling Smørgrav 	options->no_host_authentication_for_localhost = - 1;
16205962c0e9SDag-Erling Smørgrav 	options->identities_only = - 1;
1621cf2b5f3bSDag-Erling Smørgrav 	options->rekey_limit = - 1;
1622e4a9863fSDag-Erling Smørgrav 	options->rekey_interval = -1;
1623cf2b5f3bSDag-Erling Smørgrav 	options->verify_host_key_dns = -1;
16241ec0d754SDag-Erling Smørgrav 	options->server_alive_interval = -1;
16251ec0d754SDag-Erling Smørgrav 	options->server_alive_count_max = -1;
162621e764dfSDag-Erling Smørgrav 	options->num_send_env = 0;
162721e764dfSDag-Erling Smørgrav 	options->control_path = NULL;
162821e764dfSDag-Erling Smørgrav 	options->control_master = -1;
1629e2f6069cSDag-Erling Smørgrav 	options->control_persist = -1;
1630e2f6069cSDag-Erling Smørgrav 	options->control_persist_timeout = 0;
1631aa49c926SDag-Erling Smørgrav 	options->hash_known_hosts = -1;
1632b74df5b2SDag-Erling Smørgrav 	options->tun_open = -1;
1633b74df5b2SDag-Erling Smørgrav 	options->tun_local = -1;
1634b74df5b2SDag-Erling Smørgrav 	options->tun_remote = -1;
1635b74df5b2SDag-Erling Smørgrav 	options->local_command = NULL;
1636b74df5b2SDag-Erling Smørgrav 	options->permit_local_command = -1;
16377aee6ffeSDag-Erling Smørgrav 	options->use_roaming = -1;
1638d4af9e69SDag-Erling Smørgrav 	options->visual_host_key = -1;
1639cce7d346SDag-Erling Smørgrav 	options->zero_knowledge_password_authentication = -1;
16404a421b63SDag-Erling Smørgrav 	options->ip_qos_interactive = -1;
16414a421b63SDag-Erling Smørgrav 	options->ip_qos_bulk = -1;
1642e146993eSDag-Erling Smørgrav 	options->request_tty = -1;
1643*f7167e0eSDag-Erling Smørgrav 	options->proxy_use_fdpass = -1;
1644e4a9863fSDag-Erling Smørgrav 	options->ignored_unknown = NULL;
1645*f7167e0eSDag-Erling Smørgrav 	options->num_canonical_domains = 0;
1646*f7167e0eSDag-Erling Smørgrav 	options->num_permitted_cnames = 0;
1647*f7167e0eSDag-Erling Smørgrav 	options->canonicalize_max_dots = -1;
1648*f7167e0eSDag-Erling Smørgrav 	options->canonicalize_fallback_local = -1;
1649*f7167e0eSDag-Erling Smørgrav 	options->canonicalize_hostname = -1;
1650*f7167e0eSDag-Erling Smørgrav 	options->version_addendum = NULL;
165189986192SBrooks Davis 	options->hpn_disabled = -1;
165289986192SBrooks Davis 	options->hpn_buffer_size = -1;
165389986192SBrooks Davis 	options->tcp_rcv_buf_poll = -1;
165489986192SBrooks Davis 	options->tcp_rcv_buf = -1;
165589986192SBrooks Davis #ifdef NONE_CIPHER_ENABLED
165689986192SBrooks Davis 	options->none_enabled = -1;
165789986192SBrooks Davis 	options->none_switch = -1;
165889986192SBrooks Davis #endif
1659511b41d2SMark Murray }
1660511b41d2SMark Murray 
1661511b41d2SMark Murray /*
1662511b41d2SMark Murray  * Called after processing other sources of option data, this fills those
1663511b41d2SMark Murray  * options for which no value has been specified with their default values.
1664511b41d2SMark Murray  */
1665511b41d2SMark Murray 
1666511b41d2SMark Murray void
1667511b41d2SMark Murray fill_default_options(Options * options)
1668511b41d2SMark Murray {
1669511b41d2SMark Murray 	if (options->forward_agent == -1)
1670db1cb46cSKris Kennaway 		options->forward_agent = 0;
1671511b41d2SMark Murray 	if (options->forward_x11 == -1)
16725dc73ebeSBrian Feldman 		options->forward_x11 = 0;
16731ec0d754SDag-Erling Smørgrav 	if (options->forward_x11_trusted == -1)
16741ec0d754SDag-Erling Smørgrav 		options->forward_x11_trusted = 0;
1675e2f6069cSDag-Erling Smørgrav 	if (options->forward_x11_timeout == -1)
1676e2f6069cSDag-Erling Smørgrav 		options->forward_x11_timeout = 1200;
1677333ee039SDag-Erling Smørgrav 	if (options->exit_on_forward_failure == -1)
1678333ee039SDag-Erling Smørgrav 		options->exit_on_forward_failure = 0;
1679c2d3a559SKris Kennaway 	if (options->xauth_location == NULL)
1680af12a3e7SDag-Erling Smørgrav 		options->xauth_location = _PATH_XAUTH;
1681511b41d2SMark Murray 	if (options->gateway_ports == -1)
1682511b41d2SMark Murray 		options->gateway_ports = 0;
1683511b41d2SMark Murray 	if (options->use_privileged_port == -1)
1684ca3176e7SBrian Feldman 		options->use_privileged_port = 0;
1685511b41d2SMark Murray 	if (options->rsa_authentication == -1)
1686511b41d2SMark Murray 		options->rsa_authentication = 1;
1687ca3176e7SBrian Feldman 	if (options->pubkey_authentication == -1)
1688ca3176e7SBrian Feldman 		options->pubkey_authentication = 1;
1689af12a3e7SDag-Erling Smørgrav 	if (options->challenge_response_authentication == -1)
1690af12a3e7SDag-Erling Smørgrav 		options->challenge_response_authentication = 1;
1691cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_authentication == -1)
16921ec0d754SDag-Erling Smørgrav 		options->gss_authentication = 0;
1693cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_deleg_creds == -1)
1694cf2b5f3bSDag-Erling Smørgrav 		options->gss_deleg_creds = 0;
1695511b41d2SMark Murray 	if (options->password_authentication == -1)
1696511b41d2SMark Murray 		options->password_authentication = 1;
169709958426SBrian Feldman 	if (options->kbd_interactive_authentication == -1)
1698ca3176e7SBrian Feldman 		options->kbd_interactive_authentication = 1;
1699511b41d2SMark Murray 	if (options->rhosts_rsa_authentication == -1)
170080628bacSDag-Erling Smørgrav 		options->rhosts_rsa_authentication = 0;
1701ca3176e7SBrian Feldman 	if (options->hostbased_authentication == -1)
1702ca3176e7SBrian Feldman 		options->hostbased_authentication = 0;
1703511b41d2SMark Murray 	if (options->batch_mode == -1)
1704511b41d2SMark Murray 		options->batch_mode = 0;
1705511b41d2SMark Murray 	if (options->check_host_ip == -1)
1706975616f0SDag-Erling Smørgrav 		options->check_host_ip = 0;
1707511b41d2SMark Murray 	if (options->strict_host_key_checking == -1)
1708511b41d2SMark Murray 		options->strict_host_key_checking = 2;	/* 2 is default */
1709511b41d2SMark Murray 	if (options->compression == -1)
1710511b41d2SMark Murray 		options->compression = 0;
17111ec0d754SDag-Erling Smørgrav 	if (options->tcp_keep_alive == -1)
17121ec0d754SDag-Erling Smørgrav 		options->tcp_keep_alive = 1;
1713511b41d2SMark Murray 	if (options->compression_level == -1)
1714511b41d2SMark Murray 		options->compression_level = 6;
1715511b41d2SMark Murray 	if (options->port == -1)
1716511b41d2SMark Murray 		options->port = 0;	/* Filled in ssh_connect. */
1717cf2b5f3bSDag-Erling Smørgrav 	if (options->address_family == -1)
1718cf2b5f3bSDag-Erling Smørgrav 		options->address_family = AF_UNSPEC;
1719511b41d2SMark Murray 	if (options->connection_attempts == -1)
1720af12a3e7SDag-Erling Smørgrav 		options->connection_attempts = 1;
1721511b41d2SMark Murray 	if (options->number_of_password_prompts == -1)
1722511b41d2SMark Murray 		options->number_of_password_prompts = 3;
1723511b41d2SMark Murray 	/* Selected in ssh_login(). */
1724511b41d2SMark Murray 	if (options->cipher == -1)
1725511b41d2SMark Murray 		options->cipher = SSH_CIPHER_NOT_SET;
1726e8aafc91SKris Kennaway 	/* options->ciphers, default set in myproposals.h */
1727ca3176e7SBrian Feldman 	/* options->macs, default set in myproposals.h */
17284a421b63SDag-Erling Smørgrav 	/* options->kex_algorithms, default set in myproposals.h */
1729ca3176e7SBrian Feldman 	/* options->hostkeyalgorithms, default set in myproposals.h */
1730e8aafc91SKris Kennaway 	if (options->protocol == SSH_PROTO_UNKNOWN)
1731b15c8340SDag-Erling Smørgrav 		options->protocol = SSH_PROTO_2;
1732511b41d2SMark Murray 	if (options->num_identity_files == 0) {
1733ca3176e7SBrian Feldman 		if (options->protocol & SSH_PROTO_1) {
173473370613SDag-Erling Smørgrav 			add_identity_file(options, "~/",
173573370613SDag-Erling Smørgrav 			    _PATH_SSH_CLIENT_IDENTITY, 0);
1736511b41d2SMark Murray 		}
1737ca3176e7SBrian Feldman 		if (options->protocol & SSH_PROTO_2) {
173873370613SDag-Erling Smørgrav 			add_identity_file(options, "~/",
173973370613SDag-Erling Smørgrav 			    _PATH_SSH_CLIENT_ID_RSA, 0);
174073370613SDag-Erling Smørgrav 			add_identity_file(options, "~/",
174173370613SDag-Erling Smørgrav 			    _PATH_SSH_CLIENT_ID_DSA, 0);
17424a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
174373370613SDag-Erling Smørgrav 			add_identity_file(options, "~/",
174473370613SDag-Erling Smørgrav 			    _PATH_SSH_CLIENT_ID_ECDSA, 0);
17454a421b63SDag-Erling Smørgrav #endif
1746*f7167e0eSDag-Erling Smørgrav 			add_identity_file(options, "~/",
1747*f7167e0eSDag-Erling Smørgrav 			    _PATH_SSH_CLIENT_ID_ED25519, 0);
1748ca3176e7SBrian Feldman 		}
1749e8aafc91SKris Kennaway 	}
1750511b41d2SMark Murray 	if (options->escape_char == -1)
1751511b41d2SMark Murray 		options->escape_char = '~';
1752e146993eSDag-Erling Smørgrav 	if (options->num_system_hostfiles == 0) {
1753e146993eSDag-Erling Smørgrav 		options->system_hostfiles[options->num_system_hostfiles++] =
1754e146993eSDag-Erling Smørgrav 		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
1755e146993eSDag-Erling Smørgrav 		options->system_hostfiles[options->num_system_hostfiles++] =
1756e146993eSDag-Erling Smørgrav 		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
1757e146993eSDag-Erling Smørgrav 	}
1758e146993eSDag-Erling Smørgrav 	if (options->num_user_hostfiles == 0) {
1759e146993eSDag-Erling Smørgrav 		options->user_hostfiles[options->num_user_hostfiles++] =
1760e146993eSDag-Erling Smørgrav 		    xstrdup(_PATH_SSH_USER_HOSTFILE);
1761e146993eSDag-Erling Smørgrav 		options->user_hostfiles[options->num_user_hostfiles++] =
1762e146993eSDag-Erling Smørgrav 		    xstrdup(_PATH_SSH_USER_HOSTFILE2);
1763e146993eSDag-Erling Smørgrav 	}
1764af12a3e7SDag-Erling Smørgrav 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
1765511b41d2SMark Murray 		options->log_level = SYSLOG_LEVEL_INFO;
1766af12a3e7SDag-Erling Smørgrav 	if (options->clear_forwardings == 1)
1767af12a3e7SDag-Erling Smørgrav 		clear_forwardings(options);
1768af12a3e7SDag-Erling Smørgrav 	if (options->no_host_authentication_for_localhost == - 1)
1769af12a3e7SDag-Erling Smørgrav 		options->no_host_authentication_for_localhost = 0;
17705962c0e9SDag-Erling Smørgrav 	if (options->identities_only == -1)
17715962c0e9SDag-Erling Smørgrav 		options->identities_only = 0;
1772e73e9afaSDag-Erling Smørgrav 	if (options->enable_ssh_keysign == -1)
1773e73e9afaSDag-Erling Smørgrav 		options->enable_ssh_keysign = 0;
1774cf2b5f3bSDag-Erling Smørgrav 	if (options->rekey_limit == -1)
1775cf2b5f3bSDag-Erling Smørgrav 		options->rekey_limit = 0;
1776e4a9863fSDag-Erling Smørgrav 	if (options->rekey_interval == -1)
1777e4a9863fSDag-Erling Smørgrav 		options->rekey_interval = 0;
177883c6a524SDag-Erling Smørgrav #if HAVE_LDNS
177983c6a524SDag-Erling Smørgrav 	if (options->verify_host_key_dns == -1)
178083c6a524SDag-Erling Smørgrav 		/* automatically trust a verified SSHFP record */
178183c6a524SDag-Erling Smørgrav 		options->verify_host_key_dns = 1;
178283c6a524SDag-Erling Smørgrav #else
1783cf2b5f3bSDag-Erling Smørgrav 	if (options->verify_host_key_dns == -1)
1784cf2b5f3bSDag-Erling Smørgrav 		options->verify_host_key_dns = 0;
178583c6a524SDag-Erling Smørgrav #endif
17861ec0d754SDag-Erling Smørgrav 	if (options->server_alive_interval == -1)
17871ec0d754SDag-Erling Smørgrav 		options->server_alive_interval = 0;
17881ec0d754SDag-Erling Smørgrav 	if (options->server_alive_count_max == -1)
17891ec0d754SDag-Erling Smørgrav 		options->server_alive_count_max = 3;
179021e764dfSDag-Erling Smørgrav 	if (options->control_master == -1)
179121e764dfSDag-Erling Smørgrav 		options->control_master = 0;
1792e2f6069cSDag-Erling Smørgrav 	if (options->control_persist == -1) {
1793e2f6069cSDag-Erling Smørgrav 		options->control_persist = 0;
1794e2f6069cSDag-Erling Smørgrav 		options->control_persist_timeout = 0;
1795e2f6069cSDag-Erling Smørgrav 	}
1796aa49c926SDag-Erling Smørgrav 	if (options->hash_known_hosts == -1)
1797aa49c926SDag-Erling Smørgrav 		options->hash_known_hosts = 0;
1798b74df5b2SDag-Erling Smørgrav 	if (options->tun_open == -1)
1799b74df5b2SDag-Erling Smørgrav 		options->tun_open = SSH_TUNMODE_NO;
1800b74df5b2SDag-Erling Smørgrav 	if (options->tun_local == -1)
1801b74df5b2SDag-Erling Smørgrav 		options->tun_local = SSH_TUNID_ANY;
1802b74df5b2SDag-Erling Smørgrav 	if (options->tun_remote == -1)
1803b74df5b2SDag-Erling Smørgrav 		options->tun_remote = SSH_TUNID_ANY;
1804b74df5b2SDag-Erling Smørgrav 	if (options->permit_local_command == -1)
1805b74df5b2SDag-Erling Smørgrav 		options->permit_local_command = 0;
18067aee6ffeSDag-Erling Smørgrav 	if (options->use_roaming == -1)
18077aee6ffeSDag-Erling Smørgrav 		options->use_roaming = 1;
1808d4af9e69SDag-Erling Smørgrav 	if (options->visual_host_key == -1)
1809d4af9e69SDag-Erling Smørgrav 		options->visual_host_key = 0;
1810cce7d346SDag-Erling Smørgrav 	if (options->zero_knowledge_password_authentication == -1)
1811cce7d346SDag-Erling Smørgrav 		options->zero_knowledge_password_authentication = 0;
18124a421b63SDag-Erling Smørgrav 	if (options->ip_qos_interactive == -1)
18134a421b63SDag-Erling Smørgrav 		options->ip_qos_interactive = IPTOS_LOWDELAY;
18144a421b63SDag-Erling Smørgrav 	if (options->ip_qos_bulk == -1)
18154a421b63SDag-Erling Smørgrav 		options->ip_qos_bulk = IPTOS_THROUGHPUT;
1816e146993eSDag-Erling Smørgrav 	if (options->request_tty == -1)
1817e146993eSDag-Erling Smørgrav 		options->request_tty = REQUEST_TTY_AUTO;
1818*f7167e0eSDag-Erling Smørgrav 	if (options->proxy_use_fdpass == -1)
1819*f7167e0eSDag-Erling Smørgrav 		options->proxy_use_fdpass = 0;
1820*f7167e0eSDag-Erling Smørgrav 	if (options->canonicalize_max_dots == -1)
1821*f7167e0eSDag-Erling Smørgrav 		options->canonicalize_max_dots = 1;
1822*f7167e0eSDag-Erling Smørgrav 	if (options->canonicalize_fallback_local == -1)
1823*f7167e0eSDag-Erling Smørgrav 		options->canonicalize_fallback_local = 1;
1824*f7167e0eSDag-Erling Smørgrav 	if (options->canonicalize_hostname == -1)
1825*f7167e0eSDag-Erling Smørgrav 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
1826*f7167e0eSDag-Erling Smørgrav #define CLEAR_ON_NONE(v) \
1827*f7167e0eSDag-Erling Smørgrav 	do { \
1828*f7167e0eSDag-Erling Smørgrav 		if (v != NULL && strcasecmp(v, "none") == 0) { \
1829*f7167e0eSDag-Erling Smørgrav 			free(v); \
1830*f7167e0eSDag-Erling Smørgrav 			v = NULL; \
1831*f7167e0eSDag-Erling Smørgrav 		} \
1832*f7167e0eSDag-Erling Smørgrav 	} while(0)
1833*f7167e0eSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->local_command);
1834*f7167e0eSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->proxy_command);
1835*f7167e0eSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->control_path);
1836511b41d2SMark Murray 	/* options->user will be set in the main program if appropriate */
1837511b41d2SMark Murray 	/* options->hostname will be set in the main program if appropriate */
1838ca3176e7SBrian Feldman 	/* options->host_key_alias should not be set by default */
1839ca3176e7SBrian Feldman 	/* options->preferred_authentications will be set in ssh */
1840462c32cbSDag-Erling Smørgrav 	if (options->version_addendum == NULL)
1841462c32cbSDag-Erling Smørgrav 		options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
184289986192SBrooks Davis 	if (options->hpn_disabled == -1)
184389986192SBrooks Davis 		options->hpn_disabled = 0;
184489986192SBrooks Davis 	if (options->hpn_buffer_size > -1)
184589986192SBrooks Davis 	{
184689986192SBrooks Davis 		u_int maxlen;
184789986192SBrooks Davis 
184889986192SBrooks Davis 		/* If a user tries to set the size to 0 set it to 1KB. */
184989986192SBrooks Davis 		if (options->hpn_buffer_size == 0)
185089986192SBrooks Davis 			options->hpn_buffer_size = 1024;
185189986192SBrooks Davis 		/* Limit the buffer to BUFFER_MAX_LEN. */
185289986192SBrooks Davis 		maxlen = buffer_get_max_len();
185389986192SBrooks Davis 		if (options->hpn_buffer_size > (maxlen / 1024)) {
185489986192SBrooks Davis 			debug("User requested buffer larger than %ub: %ub. "
185589986192SBrooks Davis 			    "Request reverted to %ub", maxlen,
185689986192SBrooks Davis 			    options->hpn_buffer_size * 1024, maxlen);
185789986192SBrooks Davis 			options->hpn_buffer_size = maxlen;
185889986192SBrooks Davis 		}
185989986192SBrooks Davis 		debug("hpn_buffer_size set to %d", options->hpn_buffer_size);
186089986192SBrooks Davis 	}
186189986192SBrooks Davis 	if (options->tcp_rcv_buf == 0)
186289986192SBrooks Davis 		options->tcp_rcv_buf = 1;
186389986192SBrooks Davis 	if (options->tcp_rcv_buf > -1)
186489986192SBrooks Davis 		options->tcp_rcv_buf *= 1024;
186589986192SBrooks Davis 	if (options->tcp_rcv_buf_poll == -1)
186689986192SBrooks Davis 		options->tcp_rcv_buf_poll = 1;
186789986192SBrooks Davis #ifdef	NONE_CIPHER_ENABLED
186889986192SBrooks Davis 	/* options->none_enabled must not be set by default */
186989986192SBrooks Davis 	if (options->none_switch == -1)
187089986192SBrooks Davis 		options->none_switch = 0;
187189986192SBrooks Davis #endif
1872511b41d2SMark Murray }
1873aa49c926SDag-Erling Smørgrav 
1874aa49c926SDag-Erling Smørgrav /*
1875aa49c926SDag-Erling Smørgrav  * parse_forward
1876aa49c926SDag-Erling Smørgrav  * parses a string containing a port forwarding specification of the form:
1877cce7d346SDag-Erling Smørgrav  *   dynamicfwd == 0
1878aa49c926SDag-Erling Smørgrav  *	[listenhost:]listenport:connecthost:connectport
1879cce7d346SDag-Erling Smørgrav  *   dynamicfwd == 1
1880cce7d346SDag-Erling Smørgrav  *	[listenhost:]listenport
1881aa49c926SDag-Erling Smørgrav  * returns number of arguments parsed or zero on error
1882aa49c926SDag-Erling Smørgrav  */
1883aa49c926SDag-Erling Smørgrav int
1884cce7d346SDag-Erling Smørgrav parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1885aa49c926SDag-Erling Smørgrav {
1886aa49c926SDag-Erling Smørgrav 	int i;
1887aa49c926SDag-Erling Smørgrav 	char *p, *cp, *fwdarg[4];
1888aa49c926SDag-Erling Smørgrav 
1889aa49c926SDag-Erling Smørgrav 	memset(fwd, '\0', sizeof(*fwd));
1890aa49c926SDag-Erling Smørgrav 
1891aa49c926SDag-Erling Smørgrav 	cp = p = xstrdup(fwdspec);
1892aa49c926SDag-Erling Smørgrav 
1893aa49c926SDag-Erling Smørgrav 	/* skip leading spaces */
1894*f7167e0eSDag-Erling Smørgrav 	while (isspace((u_char)*cp))
1895aa49c926SDag-Erling Smørgrav 		cp++;
1896aa49c926SDag-Erling Smørgrav 
1897aa49c926SDag-Erling Smørgrav 	for (i = 0; i < 4; ++i)
1898aa49c926SDag-Erling Smørgrav 		if ((fwdarg[i] = hpdelim(&cp)) == NULL)
1899aa49c926SDag-Erling Smørgrav 			break;
1900aa49c926SDag-Erling Smørgrav 
1901cce7d346SDag-Erling Smørgrav 	/* Check for trailing garbage */
1902aa49c926SDag-Erling Smørgrav 	if (cp != NULL)
1903aa49c926SDag-Erling Smørgrav 		i = 0;	/* failure */
1904aa49c926SDag-Erling Smørgrav 
1905aa49c926SDag-Erling Smørgrav 	switch (i) {
1906cce7d346SDag-Erling Smørgrav 	case 1:
1907cce7d346SDag-Erling Smørgrav 		fwd->listen_host = NULL;
1908cce7d346SDag-Erling Smørgrav 		fwd->listen_port = a2port(fwdarg[0]);
1909cce7d346SDag-Erling Smørgrav 		fwd->connect_host = xstrdup("socks");
1910cce7d346SDag-Erling Smørgrav 		break;
1911cce7d346SDag-Erling Smørgrav 
1912cce7d346SDag-Erling Smørgrav 	case 2:
1913cce7d346SDag-Erling Smørgrav 		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1914cce7d346SDag-Erling Smørgrav 		fwd->listen_port = a2port(fwdarg[1]);
1915cce7d346SDag-Erling Smørgrav 		fwd->connect_host = xstrdup("socks");
1916cce7d346SDag-Erling Smørgrav 		break;
1917cce7d346SDag-Erling Smørgrav 
1918aa49c926SDag-Erling Smørgrav 	case 3:
1919aa49c926SDag-Erling Smørgrav 		fwd->listen_host = NULL;
1920aa49c926SDag-Erling Smørgrav 		fwd->listen_port = a2port(fwdarg[0]);
1921aa49c926SDag-Erling Smørgrav 		fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
1922aa49c926SDag-Erling Smørgrav 		fwd->connect_port = a2port(fwdarg[2]);
1923aa49c926SDag-Erling Smørgrav 		break;
1924aa49c926SDag-Erling Smørgrav 
1925aa49c926SDag-Erling Smørgrav 	case 4:
1926aa49c926SDag-Erling Smørgrav 		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1927aa49c926SDag-Erling Smørgrav 		fwd->listen_port = a2port(fwdarg[1]);
1928aa49c926SDag-Erling Smørgrav 		fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
1929aa49c926SDag-Erling Smørgrav 		fwd->connect_port = a2port(fwdarg[3]);
1930aa49c926SDag-Erling Smørgrav 		break;
1931aa49c926SDag-Erling Smørgrav 	default:
1932aa49c926SDag-Erling Smørgrav 		i = 0; /* failure */
1933aa49c926SDag-Erling Smørgrav 	}
1934aa49c926SDag-Erling Smørgrav 
1935e4a9863fSDag-Erling Smørgrav 	free(p);
1936aa49c926SDag-Erling Smørgrav 
1937cce7d346SDag-Erling Smørgrav 	if (dynamicfwd) {
1938cce7d346SDag-Erling Smørgrav 		if (!(i == 1 || i == 2))
1939cce7d346SDag-Erling Smørgrav 			goto fail_free;
1940cce7d346SDag-Erling Smørgrav 	} else {
1941cce7d346SDag-Erling Smørgrav 		if (!(i == 3 || i == 4))
1942cce7d346SDag-Erling Smørgrav 			goto fail_free;
1943cce7d346SDag-Erling Smørgrav 		if (fwd->connect_port <= 0)
1944cce7d346SDag-Erling Smørgrav 			goto fail_free;
1945cce7d346SDag-Erling Smørgrav 	}
1946cce7d346SDag-Erling Smørgrav 
1947cce7d346SDag-Erling Smørgrav 	if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0))
1948aa49c926SDag-Erling Smørgrav 		goto fail_free;
1949aa49c926SDag-Erling Smørgrav 
1950aa49c926SDag-Erling Smørgrav 	if (fwd->connect_host != NULL &&
1951aa49c926SDag-Erling Smørgrav 	    strlen(fwd->connect_host) >= NI_MAXHOST)
1952aa49c926SDag-Erling Smørgrav 		goto fail_free;
1953cce7d346SDag-Erling Smørgrav 	if (fwd->listen_host != NULL &&
1954cce7d346SDag-Erling Smørgrav 	    strlen(fwd->listen_host) >= NI_MAXHOST)
1955cce7d346SDag-Erling Smørgrav 		goto fail_free;
1956cce7d346SDag-Erling Smørgrav 
1957aa49c926SDag-Erling Smørgrav 
1958aa49c926SDag-Erling Smørgrav 	return (i);
1959aa49c926SDag-Erling Smørgrav 
1960aa49c926SDag-Erling Smørgrav  fail_free:
1961e4a9863fSDag-Erling Smørgrav 	free(fwd->connect_host);
1962cce7d346SDag-Erling Smørgrav 	fwd->connect_host = NULL;
1963e4a9863fSDag-Erling Smørgrav 	free(fwd->listen_host);
1964cce7d346SDag-Erling Smørgrav 	fwd->listen_host = NULL;
1965aa49c926SDag-Erling Smørgrav 	return (0);
1966aa49c926SDag-Erling Smørgrav }
1967