xref: /freebsd/crypto/openssh/readconf.c (revision acc1a9ef8333c798c210fa94be6af4d5fe2dd794)
1*acc1a9efSDag-Erling Smørgrav /* $OpenBSD: readconf.c,v 1.250 2016/02/08 23:40:12 djm Exp $ */
2511b41d2SMark Murray /*
3511b41d2SMark Murray  * Author: Tatu Ylonen <ylo@cs.hut.fi>
4511b41d2SMark Murray  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5511b41d2SMark Murray  *                    All rights reserved
6511b41d2SMark Murray  * Functions for reading the configuration files.
7511b41d2SMark Murray  *
8c2d3a559SKris Kennaway  * As far as I am concerned, the code I have written for this software
9c2d3a559SKris Kennaway  * can be used freely for any purpose.  Any derived versions of this
10c2d3a559SKris Kennaway  * software must be clearly marked as such, and if the derived work is
11c2d3a559SKris Kennaway  * incompatible with the protocol description in the RFC file, it must be
12c2d3a559SKris Kennaway  * called by a name other than "ssh" or "Secure Shell".
13511b41d2SMark Murray  */
14511b41d2SMark Murray 
15511b41d2SMark Murray #include "includes.h"
16333ee039SDag-Erling Smørgrav __RCSID("$FreeBSD$");
17511b41d2SMark Murray 
18333ee039SDag-Erling Smørgrav #include <sys/types.h>
19333ee039SDag-Erling Smørgrav #include <sys/stat.h>
20333ee039SDag-Erling Smørgrav #include <sys/socket.h>
2103f6c5cdSDag-Erling Smørgrav #include <sys/sysctl.h>
22f7167e0eSDag-Erling Smørgrav #include <sys/wait.h>
23a0ee8cc6SDag-Erling Smørgrav #include <sys/un.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>
28b83788ffSDag-Erling Smørgrav #include <arpa/inet.h>
29333ee039SDag-Erling Smørgrav 
30333ee039SDag-Erling Smørgrav #include <ctype.h>
31333ee039SDag-Erling Smørgrav #include <errno.h>
32f7167e0eSDag-Erling Smørgrav #include <fcntl.h>
33bc5531deSDag-Erling Smørgrav #include <limits.h>
34333ee039SDag-Erling Smørgrav #include <netdb.h>
35f7167e0eSDag-Erling Smørgrav #ifdef HAVE_PATHS_H
36f7167e0eSDag-Erling Smørgrav # include <paths.h>
37f7167e0eSDag-Erling Smørgrav #endif
38f7167e0eSDag-Erling Smørgrav #include <pwd.h>
39333ee039SDag-Erling Smørgrav #include <signal.h>
40333ee039SDag-Erling Smørgrav #include <stdarg.h>
41333ee039SDag-Erling Smørgrav #include <stdio.h>
42333ee039SDag-Erling Smørgrav #include <string.h>
43333ee039SDag-Erling Smørgrav #include <unistd.h>
44e4a9863fSDag-Erling Smørgrav #ifdef HAVE_UTIL_H
45e4a9863fSDag-Erling Smørgrav #include <util.h>
46e4a9863fSDag-Erling Smørgrav #endif
47bc5531deSDag-Erling Smørgrav #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
48bc5531deSDag-Erling Smørgrav # include <vis.h>
49bc5531deSDag-Erling Smørgrav #endif
50333ee039SDag-Erling Smørgrav 
51511b41d2SMark Murray #include "xmalloc.h"
52333ee039SDag-Erling Smørgrav #include "ssh.h"
53e8aafc91SKris Kennaway #include "compat.h"
54ca3176e7SBrian Feldman #include "cipher.h"
55ca3176e7SBrian Feldman #include "pathnames.h"
56ca3176e7SBrian Feldman #include "log.h"
57bc5531deSDag-Erling Smørgrav #include "sshkey.h"
58a0ee8cc6SDag-Erling Smørgrav #include "misc.h"
59ca3176e7SBrian Feldman #include "readconf.h"
60ca3176e7SBrian Feldman #include "match.h"
61ca3176e7SBrian Feldman #include "kex.h"
62ca3176e7SBrian Feldman #include "mac.h"
63f7167e0eSDag-Erling Smørgrav #include "uidswap.h"
64bc5531deSDag-Erling Smørgrav #include "myproposal.h"
65bc5531deSDag-Erling Smørgrav #include "digest.h"
66cce7d346SDag-Erling Smørgrav #include "version.h"
67511b41d2SMark Murray 
68511b41d2SMark Murray /* Format of the configuration file:
69511b41d2SMark Murray 
70511b41d2SMark Murray    # Configuration data is parsed as follows:
71511b41d2SMark Murray    #  1. command line options
72511b41d2SMark Murray    #  2. user-specific file
73511b41d2SMark Murray    #  3. system-wide file
74511b41d2SMark Murray    # Any configuration value is only changed the first time it is set.
75511b41d2SMark Murray    # Thus, host-specific definitions should be at the beginning of the
76511b41d2SMark Murray    # configuration file, and defaults at the end.
77511b41d2SMark Murray 
78511b41d2SMark Murray    # Host-specific declarations.  These may override anything above.  A single
79511b41d2SMark Murray    # host may match multiple declarations; these are processed in the order
80511b41d2SMark Murray    # that they are given in.
81511b41d2SMark Murray 
82511b41d2SMark Murray    Host *.ngs.fi ngs.fi
8380628bacSDag-Erling Smørgrav      User foo
84511b41d2SMark Murray 
85511b41d2SMark Murray    Host fake.com
86511b41d2SMark Murray      HostName another.host.name.real.org
87511b41d2SMark Murray      User blaah
88511b41d2SMark Murray      Port 34289
89511b41d2SMark Murray      ForwardX11 no
90511b41d2SMark Murray      ForwardAgent no
91511b41d2SMark Murray 
92511b41d2SMark Murray    Host books.com
93511b41d2SMark Murray      RemoteForward 9999 shadows.cs.hut.fi:9999
94511b41d2SMark Murray      Cipher 3des
95511b41d2SMark Murray 
96511b41d2SMark Murray    Host fascist.blob.com
97511b41d2SMark Murray      Port 23123
98511b41d2SMark Murray      User tylonen
99511b41d2SMark Murray      PasswordAuthentication no
100511b41d2SMark Murray 
101511b41d2SMark Murray    Host puukko.hut.fi
102511b41d2SMark Murray      User t35124p
103511b41d2SMark Murray      ProxyCommand ssh-proxy %h %p
104511b41d2SMark Murray 
105511b41d2SMark Murray    Host *.fr
10680628bacSDag-Erling Smørgrav      PublicKeyAuthentication no
107511b41d2SMark Murray 
108511b41d2SMark Murray    Host *.su
109511b41d2SMark Murray      Cipher none
110511b41d2SMark Murray      PasswordAuthentication no
111511b41d2SMark Murray 
112b74df5b2SDag-Erling Smørgrav    Host vpn.fake.com
113b74df5b2SDag-Erling Smørgrav      Tunnel yes
114b74df5b2SDag-Erling Smørgrav      TunnelDevice 3
115b74df5b2SDag-Erling Smørgrav 
116511b41d2SMark Murray    # Defaults for various options
117511b41d2SMark Murray    Host *
118511b41d2SMark Murray      ForwardAgent no
119ca3176e7SBrian Feldman      ForwardX11 no
120511b41d2SMark Murray      PasswordAuthentication yes
121511b41d2SMark Murray      RSAAuthentication yes
122511b41d2SMark Murray      RhostsRSAAuthentication yes
123511b41d2SMark Murray      StrictHostKeyChecking yes
1241ec0d754SDag-Erling Smørgrav      TcpKeepAlive no
125511b41d2SMark Murray      IdentityFile ~/.ssh/identity
126511b41d2SMark Murray      Port 22
127511b41d2SMark Murray      EscapeChar ~
128511b41d2SMark Murray 
129511b41d2SMark Murray */
130511b41d2SMark Murray 
131511b41d2SMark Murray /* Keyword tokens. */
132511b41d2SMark Murray 
133511b41d2SMark Murray typedef enum {
134511b41d2SMark Murray 	oBadOption,
135eccfee6eSDag-Erling Smørgrav 	oVersionAddendum,
136f7167e0eSDag-Erling Smørgrav 	oHost, oMatch,
137e2f6069cSDag-Erling Smørgrav 	oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
138e2f6069cSDag-Erling Smørgrav 	oGatewayPorts, oExitOnForwardFailure,
13980628bacSDag-Erling Smørgrav 	oPasswordAuthentication, oRSAAuthentication,
140ca3176e7SBrian Feldman 	oChallengeResponseAuthentication, oXAuthLocation,
141511b41d2SMark Murray 	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
142*acc1a9efSDag-Erling Smørgrav 	oCertificateFile, oAddKeysToAgent,
143f7167e0eSDag-Erling Smørgrav 	oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
144511b41d2SMark Murray 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
145511b41d2SMark Murray 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
1461ec0d754SDag-Erling Smørgrav 	oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
147ca3176e7SBrian Feldman 	oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
148bc5531deSDag-Erling Smørgrav 	oPubkeyAuthentication,
149ca3176e7SBrian Feldman 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
150ca3176e7SBrian Feldman 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
151b15c8340SDag-Erling Smørgrav 	oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
1529e2cbe04SDag-Erling Smørgrav 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
153cf2b5f3bSDag-Erling Smørgrav 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
154cf2b5f3bSDag-Erling Smørgrav 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
1555962c0e9SDag-Erling Smørgrav 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
156e2f6069cSDag-Erling Smørgrav 	oSendEnv, oControlPath, oControlMaster, oControlPersist,
157e2f6069cSDag-Erling Smørgrav 	oHashKnownHosts,
158b74df5b2SDag-Erling Smørgrav 	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
159*acc1a9efSDag-Erling Smørgrav 	oVisualHostKey,
160f7167e0eSDag-Erling Smørgrav 	oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
161f7167e0eSDag-Erling Smørgrav 	oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
162f7167e0eSDag-Erling Smørgrav 	oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
163bc5531deSDag-Erling Smørgrav 	oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
164bc5531deSDag-Erling Smørgrav 	oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
165eccfee6eSDag-Erling Smørgrav 	oPubkeyAcceptedKeyTypes,
16660c59fadSDag-Erling Smørgrav 	oIgnoredUnknownOption, oDeprecated, oUnsupported
167511b41d2SMark Murray } OpCodes;
168511b41d2SMark Murray 
169511b41d2SMark Murray /* Textual representations of the tokens. */
170511b41d2SMark Murray 
171511b41d2SMark Murray static struct {
172511b41d2SMark Murray 	const char *name;
173511b41d2SMark Murray 	OpCodes opcode;
174511b41d2SMark Murray } keywords[] = {
175511b41d2SMark Murray 	{ "forwardagent", oForwardAgent },
176511b41d2SMark Murray 	{ "forwardx11", oForwardX11 },
1771ec0d754SDag-Erling Smørgrav 	{ "forwardx11trusted", oForwardX11Trusted },
178e2f6069cSDag-Erling Smørgrav 	{ "forwardx11timeout", oForwardX11Timeout },
179333ee039SDag-Erling Smørgrav 	{ "exitonforwardfailure", oExitOnForwardFailure },
180c2d3a559SKris Kennaway 	{ "xauthlocation", oXAuthLocation },
181511b41d2SMark Murray 	{ "gatewayports", oGatewayPorts },
182511b41d2SMark Murray 	{ "useprivilegedport", oUsePrivilegedPort },
183cf2b5f3bSDag-Erling Smørgrav 	{ "rhostsauthentication", oDeprecated },
184511b41d2SMark Murray 	{ "passwordauthentication", oPasswordAuthentication },
18509958426SBrian Feldman 	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
18609958426SBrian Feldman 	{ "kbdinteractivedevices", oKbdInteractiveDevices },
187511b41d2SMark Murray 	{ "rsaauthentication", oRSAAuthentication },
188ca3176e7SBrian Feldman 	{ "pubkeyauthentication", oPubkeyAuthentication },
189ca3176e7SBrian Feldman 	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
190ca3176e7SBrian Feldman 	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
191ca3176e7SBrian Feldman 	{ "hostbasedauthentication", oHostbasedAuthentication },
192ca3176e7SBrian Feldman 	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
193ca3176e7SBrian Feldman 	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
194ca3176e7SBrian Feldman 	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
195cf2b5f3bSDag-Erling Smørgrav 	{ "kerberosauthentication", oUnsupported },
196cf2b5f3bSDag-Erling Smørgrav 	{ "kerberostgtpassing", oUnsupported },
197cf2b5f3bSDag-Erling Smørgrav 	{ "afstokenpassing", oUnsupported },
198cf2b5f3bSDag-Erling Smørgrav #if defined(GSSAPI)
199cf2b5f3bSDag-Erling Smørgrav 	{ "gssapiauthentication", oGssAuthentication },
200cf2b5f3bSDag-Erling Smørgrav 	{ "gssapidelegatecredentials", oGssDelegateCreds },
201cf2b5f3bSDag-Erling Smørgrav #else
202cf2b5f3bSDag-Erling Smørgrav 	{ "gssapiauthentication", oUnsupported },
203cf2b5f3bSDag-Erling Smørgrav 	{ "gssapidelegatecredentials", oUnsupported },
204511b41d2SMark Murray #endif
20580628bacSDag-Erling Smørgrav 	{ "fallbacktorsh", oDeprecated },
20680628bacSDag-Erling Smørgrav 	{ "usersh", oDeprecated },
207511b41d2SMark Murray 	{ "identityfile", oIdentityFile },
208cce7d346SDag-Erling Smørgrav 	{ "identityfile2", oIdentityFile },			/* obsolete */
2095962c0e9SDag-Erling Smørgrav 	{ "identitiesonly", oIdentitiesOnly },
210*acc1a9efSDag-Erling Smørgrav 	{ "certificatefile", oCertificateFile },
211*acc1a9efSDag-Erling Smørgrav 	{ "addkeystoagent", oAddKeysToAgent },
212511b41d2SMark Murray 	{ "hostname", oHostName },
213ca3176e7SBrian Feldman 	{ "hostkeyalias", oHostKeyAlias },
214511b41d2SMark Murray 	{ "proxycommand", oProxyCommand },
215511b41d2SMark Murray 	{ "port", oPort },
216511b41d2SMark Murray 	{ "cipher", oCipher },
217e8aafc91SKris Kennaway 	{ "ciphers", oCiphers },
218ca3176e7SBrian Feldman 	{ "macs", oMacs },
219e8aafc91SKris Kennaway 	{ "protocol", oProtocol },
220511b41d2SMark Murray 	{ "remoteforward", oRemoteForward },
221511b41d2SMark Murray 	{ "localforward", oLocalForward },
222511b41d2SMark Murray 	{ "user", oUser },
223511b41d2SMark Murray 	{ "host", oHost },
224f7167e0eSDag-Erling Smørgrav 	{ "match", oMatch },
225511b41d2SMark Murray 	{ "escapechar", oEscapeChar },
226511b41d2SMark Murray 	{ "globalknownhostsfile", oGlobalKnownHostsFile },
227e146993eSDag-Erling Smørgrav 	{ "globalknownhostsfile2", oDeprecated },
228cce7d346SDag-Erling Smørgrav 	{ "userknownhostsfile", oUserKnownHostsFile },
229e146993eSDag-Erling Smørgrav 	{ "userknownhostsfile2", oDeprecated },
230511b41d2SMark Murray 	{ "connectionattempts", oConnectionAttempts },
231511b41d2SMark Murray 	{ "batchmode", oBatchMode },
232511b41d2SMark Murray 	{ "checkhostip", oCheckHostIP },
233511b41d2SMark Murray 	{ "stricthostkeychecking", oStrictHostKeyChecking },
234511b41d2SMark Murray 	{ "compression", oCompression },
235511b41d2SMark Murray 	{ "compressionlevel", oCompressionLevel },
2361ec0d754SDag-Erling Smørgrav 	{ "tcpkeepalive", oTCPKeepAlive },
2371ec0d754SDag-Erling Smørgrav 	{ "keepalive", oTCPKeepAlive },				/* obsolete */
238511b41d2SMark Murray 	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
239511b41d2SMark Murray 	{ "loglevel", oLogLevel },
240ca3176e7SBrian Feldman 	{ "dynamicforward", oDynamicForward },
241ca3176e7SBrian Feldman 	{ "preferredauthentications", oPreferredAuthentications },
242ca3176e7SBrian Feldman 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
243af12a3e7SDag-Erling Smørgrav 	{ "bindaddress", oBindAddress },
244b15c8340SDag-Erling Smørgrav #ifdef ENABLE_PKCS11
245b15c8340SDag-Erling Smørgrav 	{ "smartcarddevice", oPKCS11Provider },
246b15c8340SDag-Erling Smørgrav 	{ "pkcs11provider", oPKCS11Provider },
247cf2b5f3bSDag-Erling Smørgrav #else
248cf2b5f3bSDag-Erling Smørgrav 	{ "smartcarddevice", oUnsupported },
249b15c8340SDag-Erling Smørgrav 	{ "pkcs11provider", oUnsupported },
250cf2b5f3bSDag-Erling Smørgrav #endif
251af12a3e7SDag-Erling Smørgrav 	{ "clearallforwardings", oClearAllForwardings },
252e73e9afaSDag-Erling Smørgrav 	{ "enablesshkeysign", oEnableSSHKeysign },
253cf2b5f3bSDag-Erling Smørgrav 	{ "verifyhostkeydns", oVerifyHostKeyDNS },
254af12a3e7SDag-Erling Smørgrav 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
255cf2b5f3bSDag-Erling Smørgrav 	{ "rekeylimit", oRekeyLimit },
256cf2b5f3bSDag-Erling Smørgrav 	{ "connecttimeout", oConnectTimeout },
257cf2b5f3bSDag-Erling Smørgrav 	{ "addressfamily", oAddressFamily },
2581ec0d754SDag-Erling Smørgrav 	{ "serveraliveinterval", oServerAliveInterval },
2591ec0d754SDag-Erling Smørgrav 	{ "serveralivecountmax", oServerAliveCountMax },
26021e764dfSDag-Erling Smørgrav 	{ "sendenv", oSendEnv },
26121e764dfSDag-Erling Smørgrav 	{ "controlpath", oControlPath },
26221e764dfSDag-Erling Smørgrav 	{ "controlmaster", oControlMaster },
263e2f6069cSDag-Erling Smørgrav 	{ "controlpersist", oControlPersist },
264aa49c926SDag-Erling Smørgrav 	{ "hashknownhosts", oHashKnownHosts },
265b74df5b2SDag-Erling Smørgrav 	{ "tunnel", oTunnel },
266b74df5b2SDag-Erling Smørgrav 	{ "tunneldevice", oTunnelDevice },
267b74df5b2SDag-Erling Smørgrav 	{ "localcommand", oLocalCommand },
268b74df5b2SDag-Erling Smørgrav 	{ "permitlocalcommand", oPermitLocalCommand },
269d4af9e69SDag-Erling Smørgrav 	{ "visualhostkey", oVisualHostKey },
270*acc1a9efSDag-Erling Smørgrav 	{ "useroaming", oDeprecated },
2714a421b63SDag-Erling Smørgrav 	{ "kexalgorithms", oKexAlgorithms },
2724a421b63SDag-Erling Smørgrav 	{ "ipqos", oIPQoS },
273e146993eSDag-Erling Smørgrav 	{ "requesttty", oRequestTTY },
274f7167e0eSDag-Erling Smørgrav 	{ "proxyusefdpass", oProxyUseFdpass },
275f7167e0eSDag-Erling Smørgrav 	{ "canonicaldomains", oCanonicalDomains },
276f7167e0eSDag-Erling Smørgrav 	{ "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
277f7167e0eSDag-Erling Smørgrav 	{ "canonicalizehostname", oCanonicalizeHostname },
278f7167e0eSDag-Erling Smørgrav 	{ "canonicalizemaxdots", oCanonicalizeMaxDots },
279f7167e0eSDag-Erling Smørgrav 	{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
280a0ee8cc6SDag-Erling Smørgrav 	{ "streamlocalbindmask", oStreamLocalBindMask },
281a0ee8cc6SDag-Erling Smørgrav 	{ "streamlocalbindunlink", oStreamLocalBindUnlink },
282bc5531deSDag-Erling Smørgrav 	{ "revokedhostkeys", oRevokedHostKeys },
283bc5531deSDag-Erling Smørgrav 	{ "fingerprinthash", oFingerprintHash },
284bc5531deSDag-Erling Smørgrav 	{ "updatehostkeys", oUpdateHostkeys },
285bc5531deSDag-Erling Smørgrav 	{ "hostbasedkeytypes", oHostbasedKeyTypes },
286eccfee6eSDag-Erling Smørgrav 	{ "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
287e4a9863fSDag-Erling Smørgrav 	{ "ignoreunknown", oIgnoreUnknown },
2889860d96eSDag-Erling Smørgrav 	{ "hpndisabled", oDeprecated },
2899860d96eSDag-Erling Smørgrav 	{ "hpnbuffersize", oDeprecated },
2909860d96eSDag-Erling Smørgrav 	{ "tcprcvbufpoll", oDeprecated },
2919860d96eSDag-Erling Smørgrav 	{ "tcprcvbuf", oDeprecated },
29263620802SDag-Erling Smørgrav 	{ "noneenabled", oUnsupported },
29363620802SDag-Erling Smørgrav 	{ "noneswitch", oUnsupported },
294975616f0SDag-Erling Smørgrav 	{ "versionaddendum", oVersionAddendum },
29535762f59SEd Schouten 
296af12a3e7SDag-Erling Smørgrav 	{ NULL, oBadOption }
297511b41d2SMark Murray };
298511b41d2SMark Murray 
299511b41d2SMark Murray /*
300511b41d2SMark Murray  * Adds a local TCP/IP port forward to options.  Never returns if there is an
301511b41d2SMark Murray  * error.
302511b41d2SMark Murray  */
303511b41d2SMark Murray 
304511b41d2SMark Murray void
305a0ee8cc6SDag-Erling Smørgrav add_local_forward(Options *options, const struct Forward *newfwd)
306511b41d2SMark Murray {
307a0ee8cc6SDag-Erling Smørgrav 	struct Forward *fwd;
308f388f5efSDag-Erling Smørgrav #ifndef NO_IPPORT_RESERVED_CONCEPT
309511b41d2SMark Murray 	extern uid_t original_real_uid;
31003f6c5cdSDag-Erling Smørgrav 	int ipport_reserved;
31103f6c5cdSDag-Erling Smørgrav #ifdef __FreeBSD__
31203f6c5cdSDag-Erling Smørgrav 	size_t len_ipport_reserved = sizeof(ipport_reserved);
31303f6c5cdSDag-Erling Smørgrav 
31403f6c5cdSDag-Erling Smørgrav 	if (sysctlbyname("net.inet.ip.portrange.reservedhigh",
31503f6c5cdSDag-Erling Smørgrav 	    &ipport_reserved, &len_ipport_reserved, NULL, 0) != 0)
31603f6c5cdSDag-Erling Smørgrav 		ipport_reserved = IPPORT_RESERVED;
31703f6c5cdSDag-Erling Smørgrav 	else
31803f6c5cdSDag-Erling Smørgrav 		ipport_reserved++;
31903f6c5cdSDag-Erling Smørgrav #else
32003f6c5cdSDag-Erling Smørgrav 	ipport_reserved = IPPORT_RESERVED;
32103f6c5cdSDag-Erling Smørgrav #endif
32203f6c5cdSDag-Erling Smørgrav 	if (newfwd->listen_port < ipport_reserved && original_real_uid != 0)
323a0ee8cc6SDag-Erling Smørgrav 	if (newfwd->listen_port < ipport_reserved && original_real_uid != 0 &&
324a0ee8cc6SDag-Erling Smørgrav 	    newfwd->listen_path == NULL)
325ca3176e7SBrian Feldman 		fatal("Privileged ports can only be forwarded by root.");
326989dd127SDag-Erling Smørgrav #endif
327557f75e5SDag-Erling Smørgrav 	options->local_forwards = xreallocarray(options->local_forwards,
328e2f6069cSDag-Erling Smørgrav 	    options->num_local_forwards + 1,
329e2f6069cSDag-Erling Smørgrav 	    sizeof(*options->local_forwards));
330511b41d2SMark Murray 	fwd = &options->local_forwards[options->num_local_forwards++];
331aa49c926SDag-Erling Smørgrav 
332cce7d346SDag-Erling Smørgrav 	fwd->listen_host = newfwd->listen_host;
333aa49c926SDag-Erling Smørgrav 	fwd->listen_port = newfwd->listen_port;
334a0ee8cc6SDag-Erling Smørgrav 	fwd->listen_path = newfwd->listen_path;
335cce7d346SDag-Erling Smørgrav 	fwd->connect_host = newfwd->connect_host;
336aa49c926SDag-Erling Smørgrav 	fwd->connect_port = newfwd->connect_port;
337a0ee8cc6SDag-Erling Smørgrav 	fwd->connect_path = newfwd->connect_path;
338511b41d2SMark Murray }
339511b41d2SMark Murray 
340511b41d2SMark Murray /*
341511b41d2SMark Murray  * Adds a remote TCP/IP port forward to options.  Never returns if there is
342511b41d2SMark Murray  * an error.
343511b41d2SMark Murray  */
344511b41d2SMark Murray 
345511b41d2SMark Murray void
346a0ee8cc6SDag-Erling Smørgrav add_remote_forward(Options *options, const struct Forward *newfwd)
347511b41d2SMark Murray {
348a0ee8cc6SDag-Erling Smørgrav 	struct Forward *fwd;
349e2f6069cSDag-Erling Smørgrav 
350557f75e5SDag-Erling Smørgrav 	options->remote_forwards = xreallocarray(options->remote_forwards,
351e2f6069cSDag-Erling Smørgrav 	    options->num_remote_forwards + 1,
352e2f6069cSDag-Erling Smørgrav 	    sizeof(*options->remote_forwards));
353511b41d2SMark Murray 	fwd = &options->remote_forwards[options->num_remote_forwards++];
354aa49c926SDag-Erling Smørgrav 
355cce7d346SDag-Erling Smørgrav 	fwd->listen_host = newfwd->listen_host;
356aa49c926SDag-Erling Smørgrav 	fwd->listen_port = newfwd->listen_port;
357a0ee8cc6SDag-Erling Smørgrav 	fwd->listen_path = newfwd->listen_path;
358cce7d346SDag-Erling Smørgrav 	fwd->connect_host = newfwd->connect_host;
359aa49c926SDag-Erling Smørgrav 	fwd->connect_port = newfwd->connect_port;
360a0ee8cc6SDag-Erling Smørgrav 	fwd->connect_path = newfwd->connect_path;
361462c32cbSDag-Erling Smørgrav 	fwd->handle = newfwd->handle;
362e2f6069cSDag-Erling Smørgrav 	fwd->allocated_port = 0;
363511b41d2SMark Murray }
364511b41d2SMark Murray 
365af12a3e7SDag-Erling Smørgrav static void
366af12a3e7SDag-Erling Smørgrav clear_forwardings(Options *options)
367af12a3e7SDag-Erling Smørgrav {
368af12a3e7SDag-Erling Smørgrav 	int i;
369af12a3e7SDag-Erling Smørgrav 
370aa49c926SDag-Erling Smørgrav 	for (i = 0; i < options->num_local_forwards; i++) {
371e4a9863fSDag-Erling Smørgrav 		free(options->local_forwards[i].listen_host);
372a0ee8cc6SDag-Erling Smørgrav 		free(options->local_forwards[i].listen_path);
373e4a9863fSDag-Erling Smørgrav 		free(options->local_forwards[i].connect_host);
374a0ee8cc6SDag-Erling Smørgrav 		free(options->local_forwards[i].connect_path);
375aa49c926SDag-Erling Smørgrav 	}
376e2f6069cSDag-Erling Smørgrav 	if (options->num_local_forwards > 0) {
377e4a9863fSDag-Erling Smørgrav 		free(options->local_forwards);
378e2f6069cSDag-Erling Smørgrav 		options->local_forwards = NULL;
379e2f6069cSDag-Erling Smørgrav 	}
380af12a3e7SDag-Erling Smørgrav 	options->num_local_forwards = 0;
381aa49c926SDag-Erling Smørgrav 	for (i = 0; i < options->num_remote_forwards; i++) {
382e4a9863fSDag-Erling Smørgrav 		free(options->remote_forwards[i].listen_host);
383a0ee8cc6SDag-Erling Smørgrav 		free(options->remote_forwards[i].listen_path);
384e4a9863fSDag-Erling Smørgrav 		free(options->remote_forwards[i].connect_host);
385a0ee8cc6SDag-Erling Smørgrav 		free(options->remote_forwards[i].connect_path);
386aa49c926SDag-Erling Smørgrav 	}
387e2f6069cSDag-Erling Smørgrav 	if (options->num_remote_forwards > 0) {
388e4a9863fSDag-Erling Smørgrav 		free(options->remote_forwards);
389e2f6069cSDag-Erling Smørgrav 		options->remote_forwards = NULL;
390e2f6069cSDag-Erling Smørgrav 	}
391af12a3e7SDag-Erling Smørgrav 	options->num_remote_forwards = 0;
392b74df5b2SDag-Erling Smørgrav 	options->tun_open = SSH_TUNMODE_NO;
393af12a3e7SDag-Erling Smørgrav }
394af12a3e7SDag-Erling Smørgrav 
395fa67e83cSDag-Erling Smørgrav void
396*acc1a9efSDag-Erling Smørgrav add_certificate_file(Options *options, const char *path, int userprovided)
397*acc1a9efSDag-Erling Smørgrav {
398*acc1a9efSDag-Erling Smørgrav 	int i;
399*acc1a9efSDag-Erling Smørgrav 
400*acc1a9efSDag-Erling Smørgrav 	if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
401*acc1a9efSDag-Erling Smørgrav 		fatal("Too many certificate files specified (max %d)",
402*acc1a9efSDag-Erling Smørgrav 		    SSH_MAX_CERTIFICATE_FILES);
403*acc1a9efSDag-Erling Smørgrav 
404*acc1a9efSDag-Erling Smørgrav 	/* Avoid registering duplicates */
405*acc1a9efSDag-Erling Smørgrav 	for (i = 0; i < options->num_certificate_files; i++) {
406*acc1a9efSDag-Erling Smørgrav 		if (options->certificate_file_userprovided[i] == userprovided &&
407*acc1a9efSDag-Erling Smørgrav 		    strcmp(options->certificate_files[i], path) == 0) {
408*acc1a9efSDag-Erling Smørgrav 			debug2("%s: ignoring duplicate key %s", __func__, path);
409*acc1a9efSDag-Erling Smørgrav 			return;
410*acc1a9efSDag-Erling Smørgrav 		}
411*acc1a9efSDag-Erling Smørgrav 	}
412*acc1a9efSDag-Erling Smørgrav 
413*acc1a9efSDag-Erling Smørgrav 	options->certificate_file_userprovided[options->num_certificate_files] =
414*acc1a9efSDag-Erling Smørgrav 	    userprovided;
415*acc1a9efSDag-Erling Smørgrav 	options->certificate_files[options->num_certificate_files++] =
416*acc1a9efSDag-Erling Smørgrav 	    xstrdup(path);
417*acc1a9efSDag-Erling Smørgrav }
418*acc1a9efSDag-Erling Smørgrav 
419*acc1a9efSDag-Erling Smørgrav void
420fa67e83cSDag-Erling Smørgrav add_identity_file(Options *options, const char *dir, const char *filename,
421fa67e83cSDag-Erling Smørgrav     int userprovided)
422fa67e83cSDag-Erling Smørgrav {
423fa67e83cSDag-Erling Smørgrav 	char *path;
424a0ee8cc6SDag-Erling Smørgrav 	int i;
425fa67e83cSDag-Erling Smørgrav 
426fa67e83cSDag-Erling Smørgrav 	if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
427fa67e83cSDag-Erling Smørgrav 		fatal("Too many identity files specified (max %d)",
428fa67e83cSDag-Erling Smørgrav 		    SSH_MAX_IDENTITY_FILES);
429fa67e83cSDag-Erling Smørgrav 
430fa67e83cSDag-Erling Smørgrav 	if (dir == NULL) /* no dir, filename is absolute */
431fa67e83cSDag-Erling Smørgrav 		path = xstrdup(filename);
432fa67e83cSDag-Erling Smørgrav 	else
433fa67e83cSDag-Erling Smørgrav 		(void)xasprintf(&path, "%.100s%.100s", dir, filename);
434fa67e83cSDag-Erling Smørgrav 
435a0ee8cc6SDag-Erling Smørgrav 	/* Avoid registering duplicates */
436a0ee8cc6SDag-Erling Smørgrav 	for (i = 0; i < options->num_identity_files; i++) {
437a0ee8cc6SDag-Erling Smørgrav 		if (options->identity_file_userprovided[i] == userprovided &&
438a0ee8cc6SDag-Erling Smørgrav 		    strcmp(options->identity_files[i], path) == 0) {
439a0ee8cc6SDag-Erling Smørgrav 			debug2("%s: ignoring duplicate key %s", __func__, path);
440a0ee8cc6SDag-Erling Smørgrav 			free(path);
441a0ee8cc6SDag-Erling Smørgrav 			return;
442a0ee8cc6SDag-Erling Smørgrav 		}
443a0ee8cc6SDag-Erling Smørgrav 	}
444a0ee8cc6SDag-Erling Smørgrav 
445fa67e83cSDag-Erling Smørgrav 	options->identity_file_userprovided[options->num_identity_files] =
446fa67e83cSDag-Erling Smørgrav 	    userprovided;
447fa67e83cSDag-Erling Smørgrav 	options->identity_files[options->num_identity_files++] = path;
448fa67e83cSDag-Erling Smørgrav }
449fa67e83cSDag-Erling Smørgrav 
450f7167e0eSDag-Erling Smørgrav int
451f7167e0eSDag-Erling Smørgrav default_ssh_port(void)
452f7167e0eSDag-Erling Smørgrav {
453f7167e0eSDag-Erling Smørgrav 	static int port;
454f7167e0eSDag-Erling Smørgrav 	struct servent *sp;
455f7167e0eSDag-Erling Smørgrav 
456f7167e0eSDag-Erling Smørgrav 	if (port == 0) {
457f7167e0eSDag-Erling Smørgrav 		sp = getservbyname(SSH_SERVICE_NAME, "tcp");
458f7167e0eSDag-Erling Smørgrav 		port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
459f7167e0eSDag-Erling Smørgrav 	}
460f7167e0eSDag-Erling Smørgrav 	return port;
461f7167e0eSDag-Erling Smørgrav }
462f7167e0eSDag-Erling Smørgrav 
463f7167e0eSDag-Erling Smørgrav /*
464f7167e0eSDag-Erling Smørgrav  * Execute a command in a shell.
465f7167e0eSDag-Erling Smørgrav  * Return its exit status or -1 on abnormal exit.
466f7167e0eSDag-Erling Smørgrav  */
467f7167e0eSDag-Erling Smørgrav static int
468f7167e0eSDag-Erling Smørgrav execute_in_shell(const char *cmd)
469f7167e0eSDag-Erling Smørgrav {
470*acc1a9efSDag-Erling Smørgrav 	char *shell;
471f7167e0eSDag-Erling Smørgrav 	pid_t pid;
472f7167e0eSDag-Erling Smørgrav 	int devnull, status;
473f7167e0eSDag-Erling Smørgrav 	extern uid_t original_real_uid;
474f7167e0eSDag-Erling Smørgrav 
475f7167e0eSDag-Erling Smørgrav 	if ((shell = getenv("SHELL")) == NULL)
476f7167e0eSDag-Erling Smørgrav 		shell = _PATH_BSHELL;
477f7167e0eSDag-Erling Smørgrav 
478f7167e0eSDag-Erling Smørgrav 	/* Need this to redirect subprocess stdin/out */
479f7167e0eSDag-Erling Smørgrav 	if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
480f7167e0eSDag-Erling Smørgrav 		fatal("open(/dev/null): %s", strerror(errno));
481f7167e0eSDag-Erling Smørgrav 
482f7167e0eSDag-Erling Smørgrav 	debug("Executing command: '%.500s'", cmd);
483f7167e0eSDag-Erling Smørgrav 
484f7167e0eSDag-Erling Smørgrav 	/* Fork and execute the command. */
485f7167e0eSDag-Erling Smørgrav 	if ((pid = fork()) == 0) {
486f7167e0eSDag-Erling Smørgrav 		char *argv[4];
487f7167e0eSDag-Erling Smørgrav 
488f7167e0eSDag-Erling Smørgrav 		/* Child.  Permanently give up superuser privileges. */
489f7167e0eSDag-Erling Smørgrav 		permanently_drop_suid(original_real_uid);
490f7167e0eSDag-Erling Smørgrav 
491f7167e0eSDag-Erling Smørgrav 		/* Redirect child stdin and stdout. Leave stderr */
492f7167e0eSDag-Erling Smørgrav 		if (dup2(devnull, STDIN_FILENO) == -1)
493f7167e0eSDag-Erling Smørgrav 			fatal("dup2: %s", strerror(errno));
494f7167e0eSDag-Erling Smørgrav 		if (dup2(devnull, STDOUT_FILENO) == -1)
495f7167e0eSDag-Erling Smørgrav 			fatal("dup2: %s", strerror(errno));
496f7167e0eSDag-Erling Smørgrav 		if (devnull > STDERR_FILENO)
497f7167e0eSDag-Erling Smørgrav 			close(devnull);
498f7167e0eSDag-Erling Smørgrav 		closefrom(STDERR_FILENO + 1);
499f7167e0eSDag-Erling Smørgrav 
500f7167e0eSDag-Erling Smørgrav 		argv[0] = shell;
501f7167e0eSDag-Erling Smørgrav 		argv[1] = "-c";
502*acc1a9efSDag-Erling Smørgrav 		argv[2] = xstrdup(cmd);
503f7167e0eSDag-Erling Smørgrav 		argv[3] = NULL;
504f7167e0eSDag-Erling Smørgrav 
505f7167e0eSDag-Erling Smørgrav 		execv(argv[0], argv);
506f7167e0eSDag-Erling Smørgrav 		error("Unable to execute '%.100s': %s", cmd, strerror(errno));
507f7167e0eSDag-Erling Smørgrav 		/* Die with signal to make this error apparent to parent. */
508f7167e0eSDag-Erling Smørgrav 		signal(SIGTERM, SIG_DFL);
509f7167e0eSDag-Erling Smørgrav 		kill(getpid(), SIGTERM);
510f7167e0eSDag-Erling Smørgrav 		_exit(1);
511f7167e0eSDag-Erling Smørgrav 	}
512f7167e0eSDag-Erling Smørgrav 	/* Parent. */
513f7167e0eSDag-Erling Smørgrav 	if (pid < 0)
514f7167e0eSDag-Erling Smørgrav 		fatal("%s: fork: %.100s", __func__, strerror(errno));
515f7167e0eSDag-Erling Smørgrav 
516f7167e0eSDag-Erling Smørgrav 	close(devnull);
517f7167e0eSDag-Erling Smørgrav 
518f7167e0eSDag-Erling Smørgrav 	while (waitpid(pid, &status, 0) == -1) {
519f7167e0eSDag-Erling Smørgrav 		if (errno != EINTR && errno != EAGAIN)
520f7167e0eSDag-Erling Smørgrav 			fatal("%s: waitpid: %s", __func__, strerror(errno));
521f7167e0eSDag-Erling Smørgrav 	}
522f7167e0eSDag-Erling Smørgrav 	if (!WIFEXITED(status)) {
523f7167e0eSDag-Erling Smørgrav 		error("command '%.100s' exited abnormally", cmd);
524f7167e0eSDag-Erling Smørgrav 		return -1;
525f7167e0eSDag-Erling Smørgrav 	}
526f7167e0eSDag-Erling Smørgrav 	debug3("command returned status %d", WEXITSTATUS(status));
527f7167e0eSDag-Erling Smørgrav 	return WEXITSTATUS(status);
528f7167e0eSDag-Erling Smørgrav }
529f7167e0eSDag-Erling Smørgrav 
530f7167e0eSDag-Erling Smørgrav /*
531f7167e0eSDag-Erling Smørgrav  * Parse and execute a Match directive.
532f7167e0eSDag-Erling Smørgrav  */
533f7167e0eSDag-Erling Smørgrav static int
534f7167e0eSDag-Erling Smørgrav match_cfg_line(Options *options, char **condition, struct passwd *pw,
535bc5531deSDag-Erling Smørgrav     const char *host_arg, const char *original_host, int post_canon,
536bc5531deSDag-Erling Smørgrav     const char *filename, int linenum)
537f7167e0eSDag-Erling Smørgrav {
538bc5531deSDag-Erling Smørgrav 	char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
539f7167e0eSDag-Erling Smørgrav 	const char *ruser;
540bc5531deSDag-Erling Smørgrav 	int r, port, this_result, result = 1, attributes = 0, negate;
541f7167e0eSDag-Erling Smørgrav 	char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
542f7167e0eSDag-Erling Smørgrav 
543f7167e0eSDag-Erling Smørgrav 	/*
544f7167e0eSDag-Erling Smørgrav 	 * Configuration is likely to be incomplete at this point so we
545f7167e0eSDag-Erling Smørgrav 	 * must be prepared to use default values.
546f7167e0eSDag-Erling Smørgrav 	 */
547f7167e0eSDag-Erling Smørgrav 	port = options->port <= 0 ? default_ssh_port() : options->port;
548f7167e0eSDag-Erling Smørgrav 	ruser = options->user == NULL ? pw->pw_name : options->user;
549*acc1a9efSDag-Erling Smørgrav 	if (post_canon) {
550*acc1a9efSDag-Erling Smørgrav 		host = xstrdup(options->hostname);
551*acc1a9efSDag-Erling Smørgrav 	} else if (options->hostname != NULL) {
552f7167e0eSDag-Erling Smørgrav 		/* NB. Please keep in sync with ssh.c:main() */
553f7167e0eSDag-Erling Smørgrav 		host = percent_expand(options->hostname,
554f7167e0eSDag-Erling Smørgrav 		    "h", host_arg, (char *)NULL);
555*acc1a9efSDag-Erling Smørgrav 	} else {
556f7167e0eSDag-Erling Smørgrav 		host = xstrdup(host_arg);
557*acc1a9efSDag-Erling Smørgrav 	}
558f7167e0eSDag-Erling Smørgrav 
559bc5531deSDag-Erling Smørgrav 	debug2("checking match for '%s' host %s originally %s",
560bc5531deSDag-Erling Smørgrav 	    cp, host, original_host);
561bc5531deSDag-Erling Smørgrav 	while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
562bc5531deSDag-Erling Smørgrav 		criteria = NULL;
563bc5531deSDag-Erling Smørgrav 		this_result = 1;
564bc5531deSDag-Erling Smørgrav 		if ((negate = attrib[0] == '!'))
565bc5531deSDag-Erling Smørgrav 			attrib++;
566bc5531deSDag-Erling Smørgrav 		/* criteria "all" and "canonical" have no argument */
567f7167e0eSDag-Erling Smørgrav 		if (strcasecmp(attrib, "all") == 0) {
568bc5531deSDag-Erling Smørgrav 			if (attributes > 1 ||
569f7167e0eSDag-Erling Smørgrav 			    ((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
570bc5531deSDag-Erling Smørgrav 				error("%.200s line %d: '%s' cannot be combined "
571bc5531deSDag-Erling Smørgrav 				    "with other Match attributes",
572bc5531deSDag-Erling Smørgrav 				    filename, linenum, oattrib);
573f7167e0eSDag-Erling Smørgrav 				result = -1;
574f7167e0eSDag-Erling Smørgrav 				goto out;
575f7167e0eSDag-Erling Smørgrav 			}
576bc5531deSDag-Erling Smørgrav 			if (result)
577bc5531deSDag-Erling Smørgrav 				result = negate ? 0 : 1;
578f7167e0eSDag-Erling Smørgrav 			goto out;
579f7167e0eSDag-Erling Smørgrav 		}
580bc5531deSDag-Erling Smørgrav 		attributes++;
581bc5531deSDag-Erling Smørgrav 		if (strcasecmp(attrib, "canonical") == 0) {
582bc5531deSDag-Erling Smørgrav 			r = !!post_canon;  /* force bitmask member to boolean */
583bc5531deSDag-Erling Smørgrav 			if (r == (negate ? 1 : 0))
584bc5531deSDag-Erling Smørgrav 				this_result = result = 0;
585bc5531deSDag-Erling Smørgrav 			debug3("%.200s line %d: %smatched '%s'",
586bc5531deSDag-Erling Smørgrav 			    filename, linenum,
587bc5531deSDag-Erling Smørgrav 			    this_result ? "" : "not ", oattrib);
588bc5531deSDag-Erling Smørgrav 			continue;
589bc5531deSDag-Erling Smørgrav 		}
590bc5531deSDag-Erling Smørgrav 		/* All other criteria require an argument */
591f7167e0eSDag-Erling Smørgrav 		if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
592f7167e0eSDag-Erling Smørgrav 			error("Missing Match criteria for %s", attrib);
593f7167e0eSDag-Erling Smørgrav 			result = -1;
594f7167e0eSDag-Erling Smørgrav 			goto out;
595f7167e0eSDag-Erling Smørgrav 		}
596f7167e0eSDag-Erling Smørgrav 		if (strcasecmp(attrib, "host") == 0) {
597bc5531deSDag-Erling Smørgrav 			criteria = xstrdup(host);
598557f75e5SDag-Erling Smørgrav 			r = match_hostname(host, arg) == 1;
599bc5531deSDag-Erling Smørgrav 			if (r == (negate ? 1 : 0))
600bc5531deSDag-Erling Smørgrav 				this_result = result = 0;
601f7167e0eSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "originalhost") == 0) {
602bc5531deSDag-Erling Smørgrav 			criteria = xstrdup(original_host);
603557f75e5SDag-Erling Smørgrav 			r = match_hostname(original_host, arg) == 1;
604bc5531deSDag-Erling Smørgrav 			if (r == (negate ? 1 : 0))
605bc5531deSDag-Erling Smørgrav 				this_result = result = 0;
606f7167e0eSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "user") == 0) {
607bc5531deSDag-Erling Smørgrav 			criteria = xstrdup(ruser);
608557f75e5SDag-Erling Smørgrav 			r = match_pattern_list(ruser, arg, 0) == 1;
609bc5531deSDag-Erling Smørgrav 			if (r == (negate ? 1 : 0))
610bc5531deSDag-Erling Smørgrav 				this_result = result = 0;
611f7167e0eSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "localuser") == 0) {
612bc5531deSDag-Erling Smørgrav 			criteria = xstrdup(pw->pw_name);
613557f75e5SDag-Erling Smørgrav 			r = match_pattern_list(pw->pw_name, arg, 0) == 1;
614bc5531deSDag-Erling Smørgrav 			if (r == (negate ? 1 : 0))
615bc5531deSDag-Erling Smørgrav 				this_result = result = 0;
616f7167e0eSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "exec") == 0) {
617f7167e0eSDag-Erling Smørgrav 			if (gethostname(thishost, sizeof(thishost)) == -1)
618f7167e0eSDag-Erling Smørgrav 				fatal("gethostname: %s", strerror(errno));
619f7167e0eSDag-Erling Smørgrav 			strlcpy(shorthost, thishost, sizeof(shorthost));
620f7167e0eSDag-Erling Smørgrav 			shorthost[strcspn(thishost, ".")] = '\0';
621f7167e0eSDag-Erling Smørgrav 			snprintf(portstr, sizeof(portstr), "%d", port);
622f7167e0eSDag-Erling Smørgrav 
623f7167e0eSDag-Erling Smørgrav 			cmd = percent_expand(arg,
624f7167e0eSDag-Erling Smørgrav 			    "L", shorthost,
625f7167e0eSDag-Erling Smørgrav 			    "d", pw->pw_dir,
626f7167e0eSDag-Erling Smørgrav 			    "h", host,
627f7167e0eSDag-Erling Smørgrav 			    "l", thishost,
628bc5531deSDag-Erling Smørgrav 			    "n", original_host,
629f7167e0eSDag-Erling Smørgrav 			    "p", portstr,
630f7167e0eSDag-Erling Smørgrav 			    "r", ruser,
631f7167e0eSDag-Erling Smørgrav 			    "u", pw->pw_name,
632f7167e0eSDag-Erling Smørgrav 			    (char *)NULL);
633b83788ffSDag-Erling Smørgrav 			if (result != 1) {
634b83788ffSDag-Erling Smørgrav 				/* skip execution if prior predicate failed */
635bc5531deSDag-Erling Smørgrav 				debug3("%.200s line %d: skipped exec "
636bc5531deSDag-Erling Smørgrav 				    "\"%.100s\"", filename, linenum, cmd);
637bc5531deSDag-Erling Smørgrav 				free(cmd);
638bc5531deSDag-Erling Smørgrav 				continue;
639bc5531deSDag-Erling Smørgrav 			}
640f7167e0eSDag-Erling Smørgrav 			r = execute_in_shell(cmd);
641f7167e0eSDag-Erling Smørgrav 			if (r == -1) {
642b83788ffSDag-Erling Smørgrav 				fatal("%.200s line %d: match exec "
643b83788ffSDag-Erling Smørgrav 				    "'%.100s' error", filename,
644b83788ffSDag-Erling Smørgrav 				    linenum, cmd);
645b83788ffSDag-Erling Smørgrav 			}
646bc5531deSDag-Erling Smørgrav 			criteria = xstrdup(cmd);
647f7167e0eSDag-Erling Smørgrav 			free(cmd);
648bc5531deSDag-Erling Smørgrav 			/* Force exit status to boolean */
649bc5531deSDag-Erling Smørgrav 			r = r == 0;
650bc5531deSDag-Erling Smørgrav 			if (r == (negate ? 1 : 0))
651bc5531deSDag-Erling Smørgrav 				this_result = result = 0;
652f7167e0eSDag-Erling Smørgrav 		} else {
653f7167e0eSDag-Erling Smørgrav 			error("Unsupported Match attribute %s", attrib);
654f7167e0eSDag-Erling Smørgrav 			result = -1;
655f7167e0eSDag-Erling Smørgrav 			goto out;
656f7167e0eSDag-Erling Smørgrav 		}
657bc5531deSDag-Erling Smørgrav 		debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
658bc5531deSDag-Erling Smørgrav 		    filename, linenum, this_result ? "": "not ",
659bc5531deSDag-Erling Smørgrav 		    oattrib, criteria);
660bc5531deSDag-Erling Smørgrav 		free(criteria);
661f7167e0eSDag-Erling Smørgrav 	}
662f7167e0eSDag-Erling Smørgrav 	if (attributes == 0) {
663f7167e0eSDag-Erling Smørgrav 		error("One or more attributes required for Match");
664f7167e0eSDag-Erling Smørgrav 		result = -1;
665f7167e0eSDag-Erling Smørgrav 		goto out;
666f7167e0eSDag-Erling Smørgrav 	}
667f7167e0eSDag-Erling Smørgrav  out:
668bc5531deSDag-Erling Smørgrav 	if (result != -1)
669bc5531deSDag-Erling Smørgrav 		debug2("match %sfound", result ? "" : "not ");
670bc5531deSDag-Erling Smørgrav 	*condition = cp;
671f7167e0eSDag-Erling Smørgrav 	free(host);
672f7167e0eSDag-Erling Smørgrav 	return result;
673f7167e0eSDag-Erling Smørgrav }
674f7167e0eSDag-Erling Smørgrav 
675f7167e0eSDag-Erling Smørgrav /* Check and prepare a domain name: removes trailing '.' and lowercases */
676f7167e0eSDag-Erling Smørgrav static void
677f7167e0eSDag-Erling Smørgrav valid_domain(char *name, const char *filename, int linenum)
678f7167e0eSDag-Erling Smørgrav {
679f7167e0eSDag-Erling Smørgrav 	size_t i, l = strlen(name);
680f7167e0eSDag-Erling Smørgrav 	u_char c, last = '\0';
681f7167e0eSDag-Erling Smørgrav 
682f7167e0eSDag-Erling Smørgrav 	if (l == 0)
683f7167e0eSDag-Erling Smørgrav 		fatal("%s line %d: empty hostname suffix", filename, linenum);
684f7167e0eSDag-Erling Smørgrav 	if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0]))
685f7167e0eSDag-Erling Smørgrav 		fatal("%s line %d: hostname suffix \"%.100s\" "
686f7167e0eSDag-Erling Smørgrav 		    "starts with invalid character", filename, linenum, name);
687f7167e0eSDag-Erling Smørgrav 	for (i = 0; i < l; i++) {
688f7167e0eSDag-Erling Smørgrav 		c = tolower((u_char)name[i]);
689f7167e0eSDag-Erling Smørgrav 		name[i] = (char)c;
690f7167e0eSDag-Erling Smørgrav 		if (last == '.' && c == '.')
691f7167e0eSDag-Erling Smørgrav 			fatal("%s line %d: hostname suffix \"%.100s\" contains "
692f7167e0eSDag-Erling Smørgrav 			    "consecutive separators", filename, linenum, name);
693f7167e0eSDag-Erling Smørgrav 		if (c != '.' && c != '-' && !isalnum(c) &&
694f7167e0eSDag-Erling Smørgrav 		    c != '_') /* technically invalid, but common */
695f7167e0eSDag-Erling Smørgrav 			fatal("%s line %d: hostname suffix \"%.100s\" contains "
696f7167e0eSDag-Erling Smørgrav 			    "invalid characters", filename, linenum, name);
697f7167e0eSDag-Erling Smørgrav 		last = c;
698f7167e0eSDag-Erling Smørgrav 	}
699f7167e0eSDag-Erling Smørgrav 	if (name[l - 1] == '.')
700f7167e0eSDag-Erling Smørgrav 		name[l - 1] = '\0';
701f7167e0eSDag-Erling Smørgrav }
702f7167e0eSDag-Erling Smørgrav 
703511b41d2SMark Murray /*
704ca3176e7SBrian Feldman  * Returns the number of the token pointed to by cp or oBadOption.
705511b41d2SMark Murray  */
706511b41d2SMark Murray static OpCodes
707e4a9863fSDag-Erling Smørgrav parse_token(const char *cp, const char *filename, int linenum,
708e4a9863fSDag-Erling Smørgrav     const char *ignored_unknown)
709511b41d2SMark Murray {
710e4a9863fSDag-Erling Smørgrav 	int i;
711511b41d2SMark Murray 
712511b41d2SMark Murray 	for (i = 0; keywords[i].name; i++)
713e4a9863fSDag-Erling Smørgrav 		if (strcmp(cp, keywords[i].name) == 0)
714511b41d2SMark Murray 			return keywords[i].opcode;
715557f75e5SDag-Erling Smørgrav 	if (ignored_unknown != NULL &&
716557f75e5SDag-Erling Smørgrav 	    match_pattern_list(cp, ignored_unknown, 1) == 1)
717e4a9863fSDag-Erling Smørgrav 		return oIgnoredUnknownOption;
718ca3176e7SBrian Feldman 	error("%s: line %d: Bad configuration option: %s",
719511b41d2SMark Murray 	    filename, linenum, cp);
720511b41d2SMark Murray 	return oBadOption;
721511b41d2SMark Murray }
722511b41d2SMark Murray 
723f7167e0eSDag-Erling Smørgrav /* Multistate option parsing */
724f7167e0eSDag-Erling Smørgrav struct multistate {
725f7167e0eSDag-Erling Smørgrav 	char *key;
726f7167e0eSDag-Erling Smørgrav 	int value;
727f7167e0eSDag-Erling Smørgrav };
728f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_flag[] = {
729f7167e0eSDag-Erling Smørgrav 	{ "true",			1 },
730f7167e0eSDag-Erling Smørgrav 	{ "false",			0 },
731f7167e0eSDag-Erling Smørgrav 	{ "yes",			1 },
732f7167e0eSDag-Erling Smørgrav 	{ "no",				0 },
733f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
734f7167e0eSDag-Erling Smørgrav };
735f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_yesnoask[] = {
736f7167e0eSDag-Erling Smørgrav 	{ "true",			1 },
737f7167e0eSDag-Erling Smørgrav 	{ "false",			0 },
738f7167e0eSDag-Erling Smørgrav 	{ "yes",			1 },
739f7167e0eSDag-Erling Smørgrav 	{ "no",				0 },
740f7167e0eSDag-Erling Smørgrav 	{ "ask",			2 },
741f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
742f7167e0eSDag-Erling Smørgrav };
743*acc1a9efSDag-Erling Smørgrav static const struct multistate multistate_yesnoaskconfirm[] = {
744*acc1a9efSDag-Erling Smørgrav 	{ "true",			1 },
745*acc1a9efSDag-Erling Smørgrav 	{ "false",			0 },
746*acc1a9efSDag-Erling Smørgrav 	{ "yes",			1 },
747*acc1a9efSDag-Erling Smørgrav 	{ "no",				0 },
748*acc1a9efSDag-Erling Smørgrav 	{ "ask",			2 },
749*acc1a9efSDag-Erling Smørgrav 	{ "confirm",			3 },
750*acc1a9efSDag-Erling Smørgrav 	{ NULL, -1 }
751*acc1a9efSDag-Erling Smørgrav };
752f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_addressfamily[] = {
753f7167e0eSDag-Erling Smørgrav 	{ "inet",			AF_INET },
754f7167e0eSDag-Erling Smørgrav 	{ "inet6",			AF_INET6 },
755f7167e0eSDag-Erling Smørgrav 	{ "any",			AF_UNSPEC },
756f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
757f7167e0eSDag-Erling Smørgrav };
758f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_controlmaster[] = {
759f7167e0eSDag-Erling Smørgrav 	{ "true",			SSHCTL_MASTER_YES },
760f7167e0eSDag-Erling Smørgrav 	{ "yes",			SSHCTL_MASTER_YES },
761f7167e0eSDag-Erling Smørgrav 	{ "false",			SSHCTL_MASTER_NO },
762f7167e0eSDag-Erling Smørgrav 	{ "no",				SSHCTL_MASTER_NO },
763f7167e0eSDag-Erling Smørgrav 	{ "auto",			SSHCTL_MASTER_AUTO },
764f7167e0eSDag-Erling Smørgrav 	{ "ask",			SSHCTL_MASTER_ASK },
765f7167e0eSDag-Erling Smørgrav 	{ "autoask",			SSHCTL_MASTER_AUTO_ASK },
766f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
767f7167e0eSDag-Erling Smørgrav };
768f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_tunnel[] = {
769f7167e0eSDag-Erling Smørgrav 	{ "ethernet",			SSH_TUNMODE_ETHERNET },
770f7167e0eSDag-Erling Smørgrav 	{ "point-to-point",		SSH_TUNMODE_POINTOPOINT },
771f7167e0eSDag-Erling Smørgrav 	{ "true",			SSH_TUNMODE_DEFAULT },
772f7167e0eSDag-Erling Smørgrav 	{ "yes",			SSH_TUNMODE_DEFAULT },
773f7167e0eSDag-Erling Smørgrav 	{ "false",			SSH_TUNMODE_NO },
774f7167e0eSDag-Erling Smørgrav 	{ "no",				SSH_TUNMODE_NO },
775f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
776f7167e0eSDag-Erling Smørgrav };
777f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_requesttty[] = {
778f7167e0eSDag-Erling Smørgrav 	{ "true",			REQUEST_TTY_YES },
779f7167e0eSDag-Erling Smørgrav 	{ "yes",			REQUEST_TTY_YES },
780f7167e0eSDag-Erling Smørgrav 	{ "false",			REQUEST_TTY_NO },
781f7167e0eSDag-Erling Smørgrav 	{ "no",				REQUEST_TTY_NO },
782f7167e0eSDag-Erling Smørgrav 	{ "force",			REQUEST_TTY_FORCE },
783f7167e0eSDag-Erling Smørgrav 	{ "auto",			REQUEST_TTY_AUTO },
784f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
785f7167e0eSDag-Erling Smørgrav };
786f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_canonicalizehostname[] = {
787f7167e0eSDag-Erling Smørgrav 	{ "true",			SSH_CANONICALISE_YES },
788f7167e0eSDag-Erling Smørgrav 	{ "false",			SSH_CANONICALISE_NO },
789f7167e0eSDag-Erling Smørgrav 	{ "yes",			SSH_CANONICALISE_YES },
790f7167e0eSDag-Erling Smørgrav 	{ "no",				SSH_CANONICALISE_NO },
791f7167e0eSDag-Erling Smørgrav 	{ "always",			SSH_CANONICALISE_ALWAYS },
792f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
793f7167e0eSDag-Erling Smørgrav };
794f7167e0eSDag-Erling Smørgrav 
795511b41d2SMark Murray /*
796511b41d2SMark Murray  * Processes a single option line as used in the configuration files. This
797511b41d2SMark Murray  * only sets those values that have not already been set.
798511b41d2SMark Murray  */
799e73e9afaSDag-Erling Smørgrav #define WHITESPACE " \t\r\n"
800511b41d2SMark Murray int
801f7167e0eSDag-Erling Smørgrav process_config_line(Options *options, struct passwd *pw, const char *host,
802bc5531deSDag-Erling Smørgrav     const char *original_host, char *line, const char *filename,
803bc5531deSDag-Erling Smørgrav     int linenum, int *activep, int flags)
804511b41d2SMark Murray {
805e146993eSDag-Erling Smørgrav 	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
806e146993eSDag-Erling Smørgrav 	char **cpptr, fwdarg[256];
807e4a9863fSDag-Erling Smørgrav 	u_int i, *uintptr, max_entries = 0;
808f7167e0eSDag-Erling Smørgrav 	int negated, opcode, *intptr, value, value2, cmdline = 0;
809d4af9e69SDag-Erling Smørgrav 	LogLevel *log_level_ptr;
810e4a9863fSDag-Erling Smørgrav 	long long val64;
811e73e9afaSDag-Erling Smørgrav 	size_t len;
812a0ee8cc6SDag-Erling Smørgrav 	struct Forward fwd;
813f7167e0eSDag-Erling Smørgrav 	const struct multistate *multistate_ptr;
814f7167e0eSDag-Erling Smørgrav 	struct allowed_cname *cname;
815f7167e0eSDag-Erling Smørgrav 
816f7167e0eSDag-Erling Smørgrav 	if (activep == NULL) { /* We are processing a command line directive */
817f7167e0eSDag-Erling Smørgrav 		cmdline = 1;
818f7167e0eSDag-Erling Smørgrav 		activep = &cmdline;
819f7167e0eSDag-Erling Smørgrav 	}
820511b41d2SMark Murray 
821cf2b5f3bSDag-Erling Smørgrav 	/* Strip trailing whitespace */
822557f75e5SDag-Erling Smørgrav 	if ((len = strlen(line)) == 0)
823557f75e5SDag-Erling Smørgrav 		return 0;
824557f75e5SDag-Erling Smørgrav 	for (len--; len > 0; len--) {
825cf2b5f3bSDag-Erling Smørgrav 		if (strchr(WHITESPACE, line[len]) == NULL)
826cf2b5f3bSDag-Erling Smørgrav 			break;
827cf2b5f3bSDag-Erling Smørgrav 		line[len] = '\0';
828cf2b5f3bSDag-Erling Smørgrav 	}
829cf2b5f3bSDag-Erling Smørgrav 
830c2d3a559SKris Kennaway 	s = line;
831c2d3a559SKris Kennaway 	/* Get the keyword. (Each line is supposed to begin with a keyword). */
832333ee039SDag-Erling Smørgrav 	if ((keyword = strdelim(&s)) == NULL)
833333ee039SDag-Erling Smørgrav 		return 0;
834c2d3a559SKris Kennaway 	/* Ignore leading whitespace. */
835c2d3a559SKris Kennaway 	if (*keyword == '\0')
836c2d3a559SKris Kennaway 		keyword = strdelim(&s);
837ca3176e7SBrian Feldman 	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
838511b41d2SMark Murray 		return 0;
839e4a9863fSDag-Erling Smørgrav 	/* Match lowercase keyword */
840f7167e0eSDag-Erling Smørgrav 	lowercase(keyword);
841511b41d2SMark Murray 
842e4a9863fSDag-Erling Smørgrav 	opcode = parse_token(keyword, filename, linenum,
843e4a9863fSDag-Erling Smørgrav 	    options->ignored_unknown);
844511b41d2SMark Murray 
845511b41d2SMark Murray 	switch (opcode) {
846511b41d2SMark Murray 	case oBadOption:
847511b41d2SMark Murray 		/* don't panic, but count bad options */
848511b41d2SMark Murray 		return -1;
849511b41d2SMark Murray 		/* NOTREACHED */
850e4a9863fSDag-Erling Smørgrav 	case oIgnoredUnknownOption:
851e4a9863fSDag-Erling Smørgrav 		debug("%s line %d: Ignored unknown option \"%s\"",
852e4a9863fSDag-Erling Smørgrav 		    filename, linenum, keyword);
853e4a9863fSDag-Erling Smørgrav 		return 0;
854cf2b5f3bSDag-Erling Smørgrav 	case oConnectTimeout:
855cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->connection_timeout;
8561ec0d754SDag-Erling Smørgrav parse_time:
857cf2b5f3bSDag-Erling Smørgrav 		arg = strdelim(&s);
858cf2b5f3bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
859cf2b5f3bSDag-Erling Smørgrav 			fatal("%s line %d: missing time value.",
860cf2b5f3bSDag-Erling Smørgrav 			    filename, linenum);
861bc5531deSDag-Erling Smørgrav 		if (strcmp(arg, "none") == 0)
862bc5531deSDag-Erling Smørgrav 			value = -1;
863bc5531deSDag-Erling Smørgrav 		else if ((value = convtime(arg)) == -1)
864cf2b5f3bSDag-Erling Smørgrav 			fatal("%s line %d: invalid time value.",
865cf2b5f3bSDag-Erling Smørgrav 			    filename, linenum);
866d4af9e69SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
867cf2b5f3bSDag-Erling Smørgrav 			*intptr = value;
868cf2b5f3bSDag-Erling Smørgrav 		break;
869cf2b5f3bSDag-Erling Smørgrav 
870511b41d2SMark Murray 	case oForwardAgent:
871511b41d2SMark Murray 		intptr = &options->forward_agent;
872511b41d2SMark Murray  parse_flag:
873f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_flag;
874f7167e0eSDag-Erling Smørgrav  parse_multistate:
875c2d3a559SKris Kennaway 		arg = strdelim(&s);
876c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
877f7167e0eSDag-Erling Smørgrav 			fatal("%s line %d: missing argument.",
878f7167e0eSDag-Erling Smørgrav 			    filename, linenum);
879f7167e0eSDag-Erling Smørgrav 		value = -1;
880f7167e0eSDag-Erling Smørgrav 		for (i = 0; multistate_ptr[i].key != NULL; i++) {
881f7167e0eSDag-Erling Smørgrav 			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
882f7167e0eSDag-Erling Smørgrav 				value = multistate_ptr[i].value;
883f7167e0eSDag-Erling Smørgrav 				break;
884f7167e0eSDag-Erling Smørgrav 			}
885f7167e0eSDag-Erling Smørgrav 		}
886f7167e0eSDag-Erling Smørgrav 		if (value == -1)
887f7167e0eSDag-Erling Smørgrav 			fatal("%s line %d: unsupported option \"%s\".",
888f7167e0eSDag-Erling Smørgrav 			    filename, linenum, arg);
889511b41d2SMark Murray 		if (*activep && *intptr == -1)
890511b41d2SMark Murray 			*intptr = value;
891511b41d2SMark Murray 		break;
892511b41d2SMark Murray 
893511b41d2SMark Murray 	case oForwardX11:
894511b41d2SMark Murray 		intptr = &options->forward_x11;
895511b41d2SMark Murray 		goto parse_flag;
896511b41d2SMark Murray 
8971ec0d754SDag-Erling Smørgrav 	case oForwardX11Trusted:
8981ec0d754SDag-Erling Smørgrav 		intptr = &options->forward_x11_trusted;
8991ec0d754SDag-Erling Smørgrav 		goto parse_flag;
9001ec0d754SDag-Erling Smørgrav 
901e2f6069cSDag-Erling Smørgrav 	case oForwardX11Timeout:
902e2f6069cSDag-Erling Smørgrav 		intptr = &options->forward_x11_timeout;
903e2f6069cSDag-Erling Smørgrav 		goto parse_time;
904e2f6069cSDag-Erling Smørgrav 
905511b41d2SMark Murray 	case oGatewayPorts:
906a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->fwd_opts.gateway_ports;
907511b41d2SMark Murray 		goto parse_flag;
908511b41d2SMark Murray 
909333ee039SDag-Erling Smørgrav 	case oExitOnForwardFailure:
910333ee039SDag-Erling Smørgrav 		intptr = &options->exit_on_forward_failure;
911333ee039SDag-Erling Smørgrav 		goto parse_flag;
912333ee039SDag-Erling Smørgrav 
913511b41d2SMark Murray 	case oUsePrivilegedPort:
914511b41d2SMark Murray 		intptr = &options->use_privileged_port;
915511b41d2SMark Murray 		goto parse_flag;
916511b41d2SMark Murray 
917511b41d2SMark Murray 	case oPasswordAuthentication:
918511b41d2SMark Murray 		intptr = &options->password_authentication;
919511b41d2SMark Murray 		goto parse_flag;
920511b41d2SMark Murray 
92109958426SBrian Feldman 	case oKbdInteractiveAuthentication:
92209958426SBrian Feldman 		intptr = &options->kbd_interactive_authentication;
92309958426SBrian Feldman 		goto parse_flag;
92409958426SBrian Feldman 
92509958426SBrian Feldman 	case oKbdInteractiveDevices:
92609958426SBrian Feldman 		charptr = &options->kbd_interactive_devices;
92709958426SBrian Feldman 		goto parse_string;
92809958426SBrian Feldman 
929ca3176e7SBrian Feldman 	case oPubkeyAuthentication:
930ca3176e7SBrian Feldman 		intptr = &options->pubkey_authentication;
931e8aafc91SKris Kennaway 		goto parse_flag;
932e8aafc91SKris Kennaway 
933511b41d2SMark Murray 	case oRSAAuthentication:
934511b41d2SMark Murray 		intptr = &options->rsa_authentication;
935511b41d2SMark Murray 		goto parse_flag;
936511b41d2SMark Murray 
937511b41d2SMark Murray 	case oRhostsRSAAuthentication:
938511b41d2SMark Murray 		intptr = &options->rhosts_rsa_authentication;
939511b41d2SMark Murray 		goto parse_flag;
940511b41d2SMark Murray 
941ca3176e7SBrian Feldman 	case oHostbasedAuthentication:
942ca3176e7SBrian Feldman 		intptr = &options->hostbased_authentication;
943511b41d2SMark Murray 		goto parse_flag;
944511b41d2SMark Murray 
945af12a3e7SDag-Erling Smørgrav 	case oChallengeResponseAuthentication:
946af12a3e7SDag-Erling Smørgrav 		intptr = &options->challenge_response_authentication;
947af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
948cf2b5f3bSDag-Erling Smørgrav 
949cf2b5f3bSDag-Erling Smørgrav 	case oGssAuthentication:
950cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_authentication;
951511b41d2SMark Murray 		goto parse_flag;
952cf2b5f3bSDag-Erling Smørgrav 
953cf2b5f3bSDag-Erling Smørgrav 	case oGssDelegateCreds:
954cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_deleg_creds;
955ca3176e7SBrian Feldman 		goto parse_flag;
956cf2b5f3bSDag-Erling Smørgrav 
957511b41d2SMark Murray 	case oBatchMode:
958511b41d2SMark Murray 		intptr = &options->batch_mode;
959511b41d2SMark Murray 		goto parse_flag;
960511b41d2SMark Murray 
961511b41d2SMark Murray 	case oCheckHostIP:
962511b41d2SMark Murray 		intptr = &options->check_host_ip;
963511b41d2SMark Murray 		goto parse_flag;
964511b41d2SMark Murray 
965cf2b5f3bSDag-Erling Smørgrav 	case oVerifyHostKeyDNS:
966cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->verify_host_key_dns;
967f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_yesnoask;
968f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
969cf2b5f3bSDag-Erling Smørgrav 
970511b41d2SMark Murray 	case oStrictHostKeyChecking:
971511b41d2SMark Murray 		intptr = &options->strict_host_key_checking;
972f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_yesnoask;
973f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
974511b41d2SMark Murray 
975511b41d2SMark Murray 	case oCompression:
976511b41d2SMark Murray 		intptr = &options->compression;
977511b41d2SMark Murray 		goto parse_flag;
978511b41d2SMark Murray 
9791ec0d754SDag-Erling Smørgrav 	case oTCPKeepAlive:
9801ec0d754SDag-Erling Smørgrav 		intptr = &options->tcp_keep_alive;
981511b41d2SMark Murray 		goto parse_flag;
982511b41d2SMark Murray 
983af12a3e7SDag-Erling Smørgrav 	case oNoHostAuthenticationForLocalhost:
984af12a3e7SDag-Erling Smørgrav 		intptr = &options->no_host_authentication_for_localhost;
985af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
986af12a3e7SDag-Erling Smørgrav 
987511b41d2SMark Murray 	case oNumberOfPasswordPrompts:
988511b41d2SMark Murray 		intptr = &options->number_of_password_prompts;
989511b41d2SMark Murray 		goto parse_int;
990511b41d2SMark Murray 
991511b41d2SMark Murray 	case oCompressionLevel:
992511b41d2SMark Murray 		intptr = &options->compression_level;
993511b41d2SMark Murray 		goto parse_int;
994511b41d2SMark Murray 
995cf2b5f3bSDag-Erling Smørgrav 	case oRekeyLimit:
996cf2b5f3bSDag-Erling Smørgrav 		arg = strdelim(&s);
997cf2b5f3bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
998e4a9863fSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename,
999e4a9863fSDag-Erling Smørgrav 			    linenum);
1000e4a9863fSDag-Erling Smørgrav 		if (strcmp(arg, "default") == 0) {
1001e4a9863fSDag-Erling Smørgrav 			val64 = 0;
1002e4a9863fSDag-Erling Smørgrav 		} else {
1003e4a9863fSDag-Erling Smørgrav 			if (scan_scaled(arg, &val64) == -1)
1004e4a9863fSDag-Erling Smørgrav 				fatal("%.200s line %d: Bad number '%s': %s",
1005e4a9863fSDag-Erling Smørgrav 				    filename, linenum, arg, strerror(errno));
1006e4a9863fSDag-Erling Smørgrav 			if (val64 != 0 && val64 < 16)
1007333ee039SDag-Erling Smørgrav 				fatal("%.200s line %d: RekeyLimit too small",
1008333ee039SDag-Erling Smørgrav 				    filename, linenum);
1009e4a9863fSDag-Erling Smørgrav 		}
1010d4af9e69SDag-Erling Smørgrav 		if (*activep && options->rekey_limit == -1)
1011*acc1a9efSDag-Erling Smørgrav 			options->rekey_limit = val64;
1012e4a9863fSDag-Erling Smørgrav 		if (s != NULL) { /* optional rekey interval present */
1013e4a9863fSDag-Erling Smørgrav 			if (strcmp(s, "none") == 0) {
1014e4a9863fSDag-Erling Smørgrav 				(void)strdelim(&s);	/* discard */
1015e4a9863fSDag-Erling Smørgrav 				break;
1016e4a9863fSDag-Erling Smørgrav 			}
1017e4a9863fSDag-Erling Smørgrav 			intptr = &options->rekey_interval;
1018e4a9863fSDag-Erling Smørgrav 			goto parse_time;
1019e4a9863fSDag-Erling Smørgrav 		}
1020cf2b5f3bSDag-Erling Smørgrav 		break;
1021cf2b5f3bSDag-Erling Smørgrav 
1022511b41d2SMark Murray 	case oIdentityFile:
1023c2d3a559SKris Kennaway 		arg = strdelim(&s);
1024c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1025511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1026511b41d2SMark Murray 		if (*activep) {
1027ca3176e7SBrian Feldman 			intptr = &options->num_identity_files;
1028e8aafc91SKris Kennaway 			if (*intptr >= SSH_MAX_IDENTITY_FILES)
1029511b41d2SMark Murray 				fatal("%.200s line %d: Too many identity files specified (max %d).",
1030511b41d2SMark Murray 				    filename, linenum, SSH_MAX_IDENTITY_FILES);
1031bc5531deSDag-Erling Smørgrav 			add_identity_file(options, NULL,
1032bc5531deSDag-Erling Smørgrav 			    arg, flags & SSHCONF_USERCONF);
1033511b41d2SMark Murray 		}
1034511b41d2SMark Murray 		break;
1035511b41d2SMark Murray 
1036*acc1a9efSDag-Erling Smørgrav 	case oCertificateFile:
1037*acc1a9efSDag-Erling Smørgrav 		arg = strdelim(&s);
1038*acc1a9efSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1039*acc1a9efSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.",
1040*acc1a9efSDag-Erling Smørgrav 			    filename, linenum);
1041*acc1a9efSDag-Erling Smørgrav 		if (*activep) {
1042*acc1a9efSDag-Erling Smørgrav 			intptr = &options->num_certificate_files;
1043*acc1a9efSDag-Erling Smørgrav 			if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
1044*acc1a9efSDag-Erling Smørgrav 				fatal("%.200s line %d: Too many certificate "
1045*acc1a9efSDag-Erling Smørgrav 				    "files specified (max %d).",
1046*acc1a9efSDag-Erling Smørgrav 				    filename, linenum,
1047*acc1a9efSDag-Erling Smørgrav 				    SSH_MAX_CERTIFICATE_FILES);
1048*acc1a9efSDag-Erling Smørgrav 			}
1049*acc1a9efSDag-Erling Smørgrav 			add_certificate_file(options, arg,
1050*acc1a9efSDag-Erling Smørgrav 			    flags & SSHCONF_USERCONF);
1051*acc1a9efSDag-Erling Smørgrav 		}
1052*acc1a9efSDag-Erling Smørgrav 		break;
1053*acc1a9efSDag-Erling Smørgrav 
1054c2d3a559SKris Kennaway 	case oXAuthLocation:
1055c2d3a559SKris Kennaway 		charptr=&options->xauth_location;
1056c2d3a559SKris Kennaway 		goto parse_string;
1057c2d3a559SKris Kennaway 
1058511b41d2SMark Murray 	case oUser:
1059511b41d2SMark Murray 		charptr = &options->user;
1060511b41d2SMark Murray parse_string:
1061c2d3a559SKris Kennaway 		arg = strdelim(&s);
1062c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1063e146993eSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.",
1064e146993eSDag-Erling Smørgrav 			    filename, linenum);
1065511b41d2SMark Murray 		if (*activep && *charptr == NULL)
1066c2d3a559SKris Kennaway 			*charptr = xstrdup(arg);
1067511b41d2SMark Murray 		break;
1068511b41d2SMark Murray 
1069511b41d2SMark Murray 	case oGlobalKnownHostsFile:
1070e146993eSDag-Erling Smørgrav 		cpptr = (char **)&options->system_hostfiles;
1071e146993eSDag-Erling Smørgrav 		uintptr = &options->num_system_hostfiles;
1072e146993eSDag-Erling Smørgrav 		max_entries = SSH_MAX_HOSTS_FILES;
1073e146993eSDag-Erling Smørgrav parse_char_array:
1074e146993eSDag-Erling Smørgrav 		if (*activep && *uintptr == 0) {
1075e146993eSDag-Erling Smørgrav 			while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1076e146993eSDag-Erling Smørgrav 				if ((*uintptr) >= max_entries)
1077e146993eSDag-Erling Smørgrav 					fatal("%s line %d: "
1078e146993eSDag-Erling Smørgrav 					    "too many authorized keys files.",
1079e146993eSDag-Erling Smørgrav 					    filename, linenum);
1080e146993eSDag-Erling Smørgrav 				cpptr[(*uintptr)++] = xstrdup(arg);
1081e146993eSDag-Erling Smørgrav 			}
1082e146993eSDag-Erling Smørgrav 		}
1083e146993eSDag-Erling Smørgrav 		return 0;
1084511b41d2SMark Murray 
1085511b41d2SMark Murray 	case oUserKnownHostsFile:
1086e146993eSDag-Erling Smørgrav 		cpptr = (char **)&options->user_hostfiles;
1087e146993eSDag-Erling Smørgrav 		uintptr = &options->num_user_hostfiles;
1088e146993eSDag-Erling Smørgrav 		max_entries = SSH_MAX_HOSTS_FILES;
1089e146993eSDag-Erling Smørgrav 		goto parse_char_array;
1090e8aafc91SKris Kennaway 
1091511b41d2SMark Murray 	case oHostName:
1092511b41d2SMark Murray 		charptr = &options->hostname;
1093511b41d2SMark Murray 		goto parse_string;
1094511b41d2SMark Murray 
1095ca3176e7SBrian Feldman 	case oHostKeyAlias:
1096ca3176e7SBrian Feldman 		charptr = &options->host_key_alias;
1097ca3176e7SBrian Feldman 		goto parse_string;
1098ca3176e7SBrian Feldman 
1099ca3176e7SBrian Feldman 	case oPreferredAuthentications:
1100ca3176e7SBrian Feldman 		charptr = &options->preferred_authentications;
1101ca3176e7SBrian Feldman 		goto parse_string;
1102ca3176e7SBrian Feldman 
1103af12a3e7SDag-Erling Smørgrav 	case oBindAddress:
1104af12a3e7SDag-Erling Smørgrav 		charptr = &options->bind_address;
1105af12a3e7SDag-Erling Smørgrav 		goto parse_string;
1106af12a3e7SDag-Erling Smørgrav 
1107b15c8340SDag-Erling Smørgrav 	case oPKCS11Provider:
1108b15c8340SDag-Erling Smørgrav 		charptr = &options->pkcs11_provider;
1109af12a3e7SDag-Erling Smørgrav 		goto parse_string;
1110af12a3e7SDag-Erling Smørgrav 
1111511b41d2SMark Murray 	case oProxyCommand:
1112b74df5b2SDag-Erling Smørgrav 		charptr = &options->proxy_command;
1113b74df5b2SDag-Erling Smørgrav parse_command:
1114cf2b5f3bSDag-Erling Smørgrav 		if (s == NULL)
1115cf2b5f3bSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1116e73e9afaSDag-Erling Smørgrav 		len = strspn(s, WHITESPACE "=");
1117511b41d2SMark Murray 		if (*activep && *charptr == NULL)
1118e73e9afaSDag-Erling Smørgrav 			*charptr = xstrdup(s + len);
1119511b41d2SMark Murray 		return 0;
1120511b41d2SMark Murray 
1121511b41d2SMark Murray 	case oPort:
1122511b41d2SMark Murray 		intptr = &options->port;
1123511b41d2SMark Murray parse_int:
1124c2d3a559SKris Kennaway 		arg = strdelim(&s);
1125c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1126511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1127c2d3a559SKris Kennaway 		if (arg[0] < '0' || arg[0] > '9')
1128511b41d2SMark Murray 			fatal("%.200s line %d: Bad number.", filename, linenum);
1129511b41d2SMark Murray 
1130511b41d2SMark Murray 		/* Octal, decimal, or hex format? */
1131c2d3a559SKris Kennaway 		value = strtol(arg, &endofnumber, 0);
1132c2d3a559SKris Kennaway 		if (arg == endofnumber)
1133511b41d2SMark Murray 			fatal("%.200s line %d: Bad number.", filename, linenum);
1134511b41d2SMark Murray 		if (*activep && *intptr == -1)
1135511b41d2SMark Murray 			*intptr = value;
1136511b41d2SMark Murray 		break;
1137511b41d2SMark Murray 
1138511b41d2SMark Murray 	case oConnectionAttempts:
1139511b41d2SMark Murray 		intptr = &options->connection_attempts;
1140511b41d2SMark Murray 		goto parse_int;
1141511b41d2SMark Murray 
1142511b41d2SMark Murray 	case oCipher:
1143511b41d2SMark Murray 		intptr = &options->cipher;
1144c2d3a559SKris Kennaway 		arg = strdelim(&s);
1145c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1146db1cb46cSKris Kennaway 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1147c2d3a559SKris Kennaway 		value = cipher_number(arg);
1148511b41d2SMark Murray 		if (value == -1)
1149511b41d2SMark Murray 			fatal("%.200s line %d: Bad cipher '%s'.",
1150c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1151511b41d2SMark Murray 		if (*activep && *intptr == -1)
1152511b41d2SMark Murray 			*intptr = value;
1153511b41d2SMark Murray 		break;
1154511b41d2SMark Murray 
1155e8aafc91SKris Kennaway 	case oCiphers:
1156c2d3a559SKris Kennaway 		arg = strdelim(&s);
1157c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1158db1cb46cSKris Kennaway 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1159eccfee6eSDag-Erling Smørgrav 		if (!ciphers_valid(*arg == '+' ? arg + 1 : arg))
1160e8aafc91SKris Kennaway 			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1161c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1162e8aafc91SKris Kennaway 		if (*activep && options->ciphers == NULL)
1163c2d3a559SKris Kennaway 			options->ciphers = xstrdup(arg);
1164e8aafc91SKris Kennaway 		break;
1165e8aafc91SKris Kennaway 
1166ca3176e7SBrian Feldman 	case oMacs:
1167ca3176e7SBrian Feldman 		arg = strdelim(&s);
1168ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
1169ca3176e7SBrian Feldman 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1170eccfee6eSDag-Erling Smørgrav 		if (!mac_valid(*arg == '+' ? arg + 1 : arg))
1171ca3176e7SBrian Feldman 			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
1172ca3176e7SBrian Feldman 			    filename, linenum, arg ? arg : "<NONE>");
1173ca3176e7SBrian Feldman 		if (*activep && options->macs == NULL)
1174ca3176e7SBrian Feldman 			options->macs = xstrdup(arg);
1175ca3176e7SBrian Feldman 		break;
1176ca3176e7SBrian Feldman 
11774a421b63SDag-Erling Smørgrav 	case oKexAlgorithms:
11784a421b63SDag-Erling Smørgrav 		arg = strdelim(&s);
11794a421b63SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
11804a421b63SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.",
11814a421b63SDag-Erling Smørgrav 			    filename, linenum);
1182eccfee6eSDag-Erling Smørgrav 		if (!kex_names_valid(*arg == '+' ? arg + 1 : arg))
11834a421b63SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
11844a421b63SDag-Erling Smørgrav 			    filename, linenum, arg ? arg : "<NONE>");
11854a421b63SDag-Erling Smørgrav 		if (*activep && options->kex_algorithms == NULL)
11864a421b63SDag-Erling Smørgrav 			options->kex_algorithms = xstrdup(arg);
11874a421b63SDag-Erling Smørgrav 		break;
11884a421b63SDag-Erling Smørgrav 
1189ca3176e7SBrian Feldman 	case oHostKeyAlgorithms:
1190eccfee6eSDag-Erling Smørgrav 		charptr = &options->hostkeyalgorithms;
1191eccfee6eSDag-Erling Smørgrav parse_keytypes:
1192ca3176e7SBrian Feldman 		arg = strdelim(&s);
1193ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
1194eccfee6eSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.",
1195eccfee6eSDag-Erling Smørgrav 			    filename, linenum);
1196eccfee6eSDag-Erling Smørgrav 		if (!sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1))
1197eccfee6eSDag-Erling Smørgrav 			fatal("%s line %d: Bad key types '%s'.",
1198ca3176e7SBrian Feldman 				filename, linenum, arg ? arg : "<NONE>");
1199eccfee6eSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
1200eccfee6eSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
1201ca3176e7SBrian Feldman 		break;
1202ca3176e7SBrian Feldman 
1203e8aafc91SKris Kennaway 	case oProtocol:
1204e8aafc91SKris Kennaway 		intptr = &options->protocol;
1205c2d3a559SKris Kennaway 		arg = strdelim(&s);
1206c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1207db1cb46cSKris Kennaway 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1208c2d3a559SKris Kennaway 		value = proto_spec(arg);
1209e8aafc91SKris Kennaway 		if (value == SSH_PROTO_UNKNOWN)
1210e8aafc91SKris Kennaway 			fatal("%.200s line %d: Bad protocol spec '%s'.",
1211c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1212e8aafc91SKris Kennaway 		if (*activep && *intptr == SSH_PROTO_UNKNOWN)
1213e8aafc91SKris Kennaway 			*intptr = value;
1214e8aafc91SKris Kennaway 		break;
1215e8aafc91SKris Kennaway 
1216511b41d2SMark Murray 	case oLogLevel:
1217d4af9e69SDag-Erling Smørgrav 		log_level_ptr = &options->log_level;
1218c2d3a559SKris Kennaway 		arg = strdelim(&s);
1219c2d3a559SKris Kennaway 		value = log_level_number(arg);
1220af12a3e7SDag-Erling Smørgrav 		if (value == SYSLOG_LEVEL_NOT_SET)
1221ca3176e7SBrian Feldman 			fatal("%.200s line %d: unsupported log level '%s'",
1222c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1223d4af9e69SDag-Erling Smørgrav 		if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1224d4af9e69SDag-Erling Smørgrav 			*log_level_ptr = (LogLevel) value;
1225511b41d2SMark Murray 		break;
1226511b41d2SMark Murray 
1227af12a3e7SDag-Erling Smørgrav 	case oLocalForward:
1228511b41d2SMark Murray 	case oRemoteForward:
1229cce7d346SDag-Erling Smørgrav 	case oDynamicForward:
1230c2d3a559SKris Kennaway 		arg = strdelim(&s);
1231aa49c926SDag-Erling Smørgrav 		if (arg == NULL || *arg == '\0')
1232af12a3e7SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing port argument.",
1233af12a3e7SDag-Erling Smørgrav 			    filename, linenum);
1234cce7d346SDag-Erling Smørgrav 
1235cce7d346SDag-Erling Smørgrav 		if (opcode == oLocalForward ||
1236cce7d346SDag-Erling Smørgrav 		    opcode == oRemoteForward) {
1237aa49c926SDag-Erling Smørgrav 			arg2 = strdelim(&s);
1238aa49c926SDag-Erling Smørgrav 			if (arg2 == NULL || *arg2 == '\0')
1239aa49c926SDag-Erling Smørgrav 				fatal("%.200s line %d: Missing target argument.",
1240511b41d2SMark Murray 				    filename, linenum);
1241aa49c926SDag-Erling Smørgrav 
1242aa49c926SDag-Erling Smørgrav 			/* construct a string for parse_forward */
1243aa49c926SDag-Erling Smørgrav 			snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
1244cce7d346SDag-Erling Smørgrav 		} else if (opcode == oDynamicForward) {
1245cce7d346SDag-Erling Smørgrav 			strlcpy(fwdarg, arg, sizeof(fwdarg));
1246cce7d346SDag-Erling Smørgrav 		}
1247aa49c926SDag-Erling Smørgrav 
1248cce7d346SDag-Erling Smørgrav 		if (parse_forward(&fwd, fwdarg,
1249cce7d346SDag-Erling Smørgrav 		    opcode == oDynamicForward ? 1 : 0,
1250cce7d346SDag-Erling Smørgrav 		    opcode == oRemoteForward ? 1 : 0) == 0)
1251af12a3e7SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad forwarding specification.",
1252511b41d2SMark Murray 			    filename, linenum);
1253aa49c926SDag-Erling Smørgrav 
1254af12a3e7SDag-Erling Smørgrav 		if (*activep) {
1255cce7d346SDag-Erling Smørgrav 			if (opcode == oLocalForward ||
1256cce7d346SDag-Erling Smørgrav 			    opcode == oDynamicForward)
1257aa49c926SDag-Erling Smørgrav 				add_local_forward(options, &fwd);
1258af12a3e7SDag-Erling Smørgrav 			else if (opcode == oRemoteForward)
1259aa49c926SDag-Erling Smørgrav 				add_remote_forward(options, &fwd);
1260af12a3e7SDag-Erling Smørgrav 		}
1261511b41d2SMark Murray 		break;
1262511b41d2SMark Murray 
1263af12a3e7SDag-Erling Smørgrav 	case oClearAllForwardings:
1264af12a3e7SDag-Erling Smørgrav 		intptr = &options->clear_forwardings;
1265af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
1266af12a3e7SDag-Erling Smørgrav 
1267511b41d2SMark Murray 	case oHost:
1268f7167e0eSDag-Erling Smørgrav 		if (cmdline)
1269f7167e0eSDag-Erling Smørgrav 			fatal("Host directive not supported as a command-line "
1270f7167e0eSDag-Erling Smørgrav 			    "option");
1271511b41d2SMark Murray 		*activep = 0;
1272e146993eSDag-Erling Smørgrav 		arg2 = NULL;
1273e146993eSDag-Erling Smørgrav 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1274e146993eSDag-Erling Smørgrav 			negated = *arg == '!';
1275e146993eSDag-Erling Smørgrav 			if (negated)
1276e146993eSDag-Erling Smørgrav 				arg++;
1277c2d3a559SKris Kennaway 			if (match_pattern(host, arg)) {
1278e146993eSDag-Erling Smørgrav 				if (negated) {
1279e146993eSDag-Erling Smørgrav 					debug("%.200s line %d: Skipping Host "
1280e146993eSDag-Erling Smørgrav 					    "block because of negated match "
1281e146993eSDag-Erling Smørgrav 					    "for %.100s", filename, linenum,
1282e146993eSDag-Erling Smørgrav 					    arg);
1283e146993eSDag-Erling Smørgrav 					*activep = 0;
1284511b41d2SMark Murray 					break;
1285511b41d2SMark Murray 				}
1286e146993eSDag-Erling Smørgrav 				if (!*activep)
1287e146993eSDag-Erling Smørgrav 					arg2 = arg; /* logged below */
1288e146993eSDag-Erling Smørgrav 				*activep = 1;
1289e146993eSDag-Erling Smørgrav 			}
1290e146993eSDag-Erling Smørgrav 		}
1291e146993eSDag-Erling Smørgrav 		if (*activep)
1292e146993eSDag-Erling Smørgrav 			debug("%.200s line %d: Applying options for %.100s",
1293e146993eSDag-Erling Smørgrav 			    filename, linenum, arg2);
1294c2d3a559SKris Kennaway 		/* Avoid garbage check below, as strdelim is done. */
1295511b41d2SMark Murray 		return 0;
1296511b41d2SMark Murray 
1297f7167e0eSDag-Erling Smørgrav 	case oMatch:
1298f7167e0eSDag-Erling Smørgrav 		if (cmdline)
1299f7167e0eSDag-Erling Smørgrav 			fatal("Host directive not supported as a command-line "
1300f7167e0eSDag-Erling Smørgrav 			    "option");
1301bc5531deSDag-Erling Smørgrav 		value = match_cfg_line(options, &s, pw, host, original_host,
1302bc5531deSDag-Erling Smørgrav 		    flags & SSHCONF_POSTCANON, filename, linenum);
1303f7167e0eSDag-Erling Smørgrav 		if (value < 0)
1304f7167e0eSDag-Erling Smørgrav 			fatal("%.200s line %d: Bad Match condition", filename,
1305f7167e0eSDag-Erling Smørgrav 			    linenum);
1306f7167e0eSDag-Erling Smørgrav 		*activep = value;
1307f7167e0eSDag-Erling Smørgrav 		break;
1308f7167e0eSDag-Erling Smørgrav 
1309511b41d2SMark Murray 	case oEscapeChar:
1310511b41d2SMark Murray 		intptr = &options->escape_char;
1311c2d3a559SKris Kennaway 		arg = strdelim(&s);
1312c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1313511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1314557f75e5SDag-Erling Smørgrav 		if (strcmp(arg, "none") == 0)
1315557f75e5SDag-Erling Smørgrav 			value = SSH_ESCAPECHAR_NONE;
1316557f75e5SDag-Erling Smørgrav 		else if (arg[1] == '\0')
1317557f75e5SDag-Erling Smørgrav 			value = (u_char) arg[0];
1318557f75e5SDag-Erling Smørgrav 		else if (arg[0] == '^' && arg[2] == 0 &&
1319ca3176e7SBrian Feldman 		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1320ca3176e7SBrian Feldman 			value = (u_char) arg[1] & 31;
1321511b41d2SMark Murray 		else {
1322511b41d2SMark Murray 			fatal("%.200s line %d: Bad escape character.",
1323511b41d2SMark Murray 			    filename, linenum);
1324511b41d2SMark Murray 			/* NOTREACHED */
1325511b41d2SMark Murray 			value = 0;	/* Avoid compiler warning. */
1326511b41d2SMark Murray 		}
1327511b41d2SMark Murray 		if (*activep && *intptr == -1)
1328511b41d2SMark Murray 			*intptr = value;
1329511b41d2SMark Murray 		break;
1330511b41d2SMark Murray 
1331cf2b5f3bSDag-Erling Smørgrav 	case oAddressFamily:
1332cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->address_family;
1333f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_addressfamily;
1334f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
1335cf2b5f3bSDag-Erling Smørgrav 
1336e73e9afaSDag-Erling Smørgrav 	case oEnableSSHKeysign:
1337e73e9afaSDag-Erling Smørgrav 		intptr = &options->enable_ssh_keysign;
1338e73e9afaSDag-Erling Smørgrav 		goto parse_flag;
1339e73e9afaSDag-Erling Smørgrav 
13405962c0e9SDag-Erling Smørgrav 	case oIdentitiesOnly:
13415962c0e9SDag-Erling Smørgrav 		intptr = &options->identities_only;
13425962c0e9SDag-Erling Smørgrav 		goto parse_flag;
13435962c0e9SDag-Erling Smørgrav 
13441ec0d754SDag-Erling Smørgrav 	case oServerAliveInterval:
13451ec0d754SDag-Erling Smørgrav 		intptr = &options->server_alive_interval;
13461ec0d754SDag-Erling Smørgrav 		goto parse_time;
13471ec0d754SDag-Erling Smørgrav 
13481ec0d754SDag-Erling Smørgrav 	case oServerAliveCountMax:
13491ec0d754SDag-Erling Smørgrav 		intptr = &options->server_alive_count_max;
13501ec0d754SDag-Erling Smørgrav 		goto parse_int;
13511ec0d754SDag-Erling Smørgrav 
135221e764dfSDag-Erling Smørgrav 	case oSendEnv:
135321e764dfSDag-Erling Smørgrav 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
135421e764dfSDag-Erling Smørgrav 			if (strchr(arg, '=') != NULL)
135521e764dfSDag-Erling Smørgrav 				fatal("%s line %d: Invalid environment name.",
135621e764dfSDag-Erling Smørgrav 				    filename, linenum);
1357aa49c926SDag-Erling Smørgrav 			if (!*activep)
1358aa49c926SDag-Erling Smørgrav 				continue;
135921e764dfSDag-Erling Smørgrav 			if (options->num_send_env >= MAX_SEND_ENV)
136021e764dfSDag-Erling Smørgrav 				fatal("%s line %d: too many send env.",
136121e764dfSDag-Erling Smørgrav 				    filename, linenum);
136221e764dfSDag-Erling Smørgrav 			options->send_env[options->num_send_env++] =
136321e764dfSDag-Erling Smørgrav 			    xstrdup(arg);
136421e764dfSDag-Erling Smørgrav 		}
136521e764dfSDag-Erling Smørgrav 		break;
136621e764dfSDag-Erling Smørgrav 
136721e764dfSDag-Erling Smørgrav 	case oControlPath:
136821e764dfSDag-Erling Smørgrav 		charptr = &options->control_path;
136921e764dfSDag-Erling Smørgrav 		goto parse_string;
137021e764dfSDag-Erling Smørgrav 
137121e764dfSDag-Erling Smørgrav 	case oControlMaster:
137221e764dfSDag-Erling Smørgrav 		intptr = &options->control_master;
1373f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_controlmaster;
1374f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
137521e764dfSDag-Erling Smørgrav 
1376e2f6069cSDag-Erling Smørgrav 	case oControlPersist:
1377e2f6069cSDag-Erling Smørgrav 		/* no/false/yes/true, or a time spec */
1378e2f6069cSDag-Erling Smørgrav 		intptr = &options->control_persist;
1379e2f6069cSDag-Erling Smørgrav 		arg = strdelim(&s);
1380e2f6069cSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1381e2f6069cSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing ControlPersist"
1382e2f6069cSDag-Erling Smørgrav 			    " argument.", filename, linenum);
1383e2f6069cSDag-Erling Smørgrav 		value = 0;
1384e2f6069cSDag-Erling Smørgrav 		value2 = 0;	/* timeout */
1385e2f6069cSDag-Erling Smørgrav 		if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1386e2f6069cSDag-Erling Smørgrav 			value = 0;
1387e2f6069cSDag-Erling Smørgrav 		else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1388e2f6069cSDag-Erling Smørgrav 			value = 1;
1389e2f6069cSDag-Erling Smørgrav 		else if ((value2 = convtime(arg)) >= 0)
1390e2f6069cSDag-Erling Smørgrav 			value = 1;
1391e2f6069cSDag-Erling Smørgrav 		else
1392e2f6069cSDag-Erling Smørgrav 			fatal("%.200s line %d: Bad ControlPersist argument.",
1393e2f6069cSDag-Erling Smørgrav 			    filename, linenum);
1394e2f6069cSDag-Erling Smørgrav 		if (*activep && *intptr == -1) {
1395e2f6069cSDag-Erling Smørgrav 			*intptr = value;
1396e2f6069cSDag-Erling Smørgrav 			options->control_persist_timeout = value2;
1397e2f6069cSDag-Erling Smørgrav 		}
1398e2f6069cSDag-Erling Smørgrav 		break;
1399e2f6069cSDag-Erling Smørgrav 
1400aa49c926SDag-Erling Smørgrav 	case oHashKnownHosts:
1401aa49c926SDag-Erling Smørgrav 		intptr = &options->hash_known_hosts;
1402aa49c926SDag-Erling Smørgrav 		goto parse_flag;
1403aa49c926SDag-Erling Smørgrav 
1404b74df5b2SDag-Erling Smørgrav 	case oTunnel:
1405b74df5b2SDag-Erling Smørgrav 		intptr = &options->tun_open;
1406f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_tunnel;
1407f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
1408b74df5b2SDag-Erling Smørgrav 
1409b74df5b2SDag-Erling Smørgrav 	case oTunnelDevice:
1410b74df5b2SDag-Erling Smørgrav 		arg = strdelim(&s);
1411b74df5b2SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1412b74df5b2SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1413b74df5b2SDag-Erling Smørgrav 		value = a2tun(arg, &value2);
1414b74df5b2SDag-Erling Smørgrav 		if (value == SSH_TUNID_ERR)
1415b74df5b2SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad tun device.", filename, linenum);
1416b74df5b2SDag-Erling Smørgrav 		if (*activep) {
1417b74df5b2SDag-Erling Smørgrav 			options->tun_local = value;
1418b74df5b2SDag-Erling Smørgrav 			options->tun_remote = value2;
1419b74df5b2SDag-Erling Smørgrav 		}
1420b74df5b2SDag-Erling Smørgrav 		break;
1421b74df5b2SDag-Erling Smørgrav 
1422b74df5b2SDag-Erling Smørgrav 	case oLocalCommand:
1423b74df5b2SDag-Erling Smørgrav 		charptr = &options->local_command;
1424b74df5b2SDag-Erling Smørgrav 		goto parse_command;
1425b74df5b2SDag-Erling Smørgrav 
1426b74df5b2SDag-Erling Smørgrav 	case oPermitLocalCommand:
1427b74df5b2SDag-Erling Smørgrav 		intptr = &options->permit_local_command;
1428b74df5b2SDag-Erling Smørgrav 		goto parse_flag;
1429b74df5b2SDag-Erling Smørgrav 
1430d4af9e69SDag-Erling Smørgrav 	case oVisualHostKey:
1431d4af9e69SDag-Erling Smørgrav 		intptr = &options->visual_host_key;
1432d4af9e69SDag-Erling Smørgrav 		goto parse_flag;
1433d4af9e69SDag-Erling Smørgrav 
14344a421b63SDag-Erling Smørgrav 	case oIPQoS:
14354a421b63SDag-Erling Smørgrav 		arg = strdelim(&s);
14364a421b63SDag-Erling Smørgrav 		if ((value = parse_ipqos(arg)) == -1)
14374a421b63SDag-Erling Smørgrav 			fatal("%s line %d: Bad IPQoS value: %s",
14384a421b63SDag-Erling Smørgrav 			    filename, linenum, arg);
14394a421b63SDag-Erling Smørgrav 		arg = strdelim(&s);
14404a421b63SDag-Erling Smørgrav 		if (arg == NULL)
14414a421b63SDag-Erling Smørgrav 			value2 = value;
14424a421b63SDag-Erling Smørgrav 		else if ((value2 = parse_ipqos(arg)) == -1)
14434a421b63SDag-Erling Smørgrav 			fatal("%s line %d: Bad IPQoS value: %s",
14444a421b63SDag-Erling Smørgrav 			    filename, linenum, arg);
14454a421b63SDag-Erling Smørgrav 		if (*activep) {
14464a421b63SDag-Erling Smørgrav 			options->ip_qos_interactive = value;
14474a421b63SDag-Erling Smørgrav 			options->ip_qos_bulk = value2;
14484a421b63SDag-Erling Smørgrav 		}
14494a421b63SDag-Erling Smørgrav 		break;
14504a421b63SDag-Erling Smørgrav 
1451e146993eSDag-Erling Smørgrav 	case oRequestTTY:
1452e146993eSDag-Erling Smørgrav 		intptr = &options->request_tty;
1453f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_requesttty;
1454f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
1455975616f0SDag-Erling Smørgrav 
1456e146993eSDag-Erling Smørgrav 	case oVersionAddendum:
1457462c32cbSDag-Erling Smørgrav 		if (s == NULL)
1458462c32cbSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename,
1459462c32cbSDag-Erling Smørgrav 			    linenum);
1460462c32cbSDag-Erling Smørgrav 		len = strspn(s, WHITESPACE);
1461462c32cbSDag-Erling Smørgrav 		if (*activep && options->version_addendum == NULL) {
1462462c32cbSDag-Erling Smørgrav 			if (strcasecmp(s + len, "none") == 0)
1463462c32cbSDag-Erling Smørgrav 				options->version_addendum = xstrdup("");
1464462c32cbSDag-Erling Smørgrav 			else if (strchr(s + len, '\r') != NULL)
1465462c32cbSDag-Erling Smørgrav 				fatal("%.200s line %d: Invalid argument",
1466462c32cbSDag-Erling Smørgrav 				    filename, linenum);
1467462c32cbSDag-Erling Smørgrav 			else
1468462c32cbSDag-Erling Smørgrav 				options->version_addendum = xstrdup(s + len);
1469462c32cbSDag-Erling Smørgrav 		}
1470462c32cbSDag-Erling Smørgrav 		return 0;
1471e146993eSDag-Erling Smørgrav 
1472e4a9863fSDag-Erling Smørgrav 	case oIgnoreUnknown:
1473e4a9863fSDag-Erling Smørgrav 		charptr = &options->ignored_unknown;
1474e4a9863fSDag-Erling Smørgrav 		goto parse_string;
1475e4a9863fSDag-Erling Smørgrav 
1476f7167e0eSDag-Erling Smørgrav 	case oProxyUseFdpass:
1477f7167e0eSDag-Erling Smørgrav 		intptr = &options->proxy_use_fdpass;
1478f7167e0eSDag-Erling Smørgrav 		goto parse_flag;
1479f7167e0eSDag-Erling Smørgrav 
1480f7167e0eSDag-Erling Smørgrav 	case oCanonicalDomains:
1481f7167e0eSDag-Erling Smørgrav 		value = options->num_canonical_domains != 0;
1482f7167e0eSDag-Erling Smørgrav 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1483f7167e0eSDag-Erling Smørgrav 			valid_domain(arg, filename, linenum);
1484f7167e0eSDag-Erling Smørgrav 			if (!*activep || value)
1485f7167e0eSDag-Erling Smørgrav 				continue;
1486f7167e0eSDag-Erling Smørgrav 			if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
1487f7167e0eSDag-Erling Smørgrav 				fatal("%s line %d: too many hostname suffixes.",
1488f7167e0eSDag-Erling Smørgrav 				    filename, linenum);
1489f7167e0eSDag-Erling Smørgrav 			options->canonical_domains[
1490f7167e0eSDag-Erling Smørgrav 			    options->num_canonical_domains++] = xstrdup(arg);
1491f7167e0eSDag-Erling Smørgrav 		}
1492f7167e0eSDag-Erling Smørgrav 		break;
1493f7167e0eSDag-Erling Smørgrav 
1494f7167e0eSDag-Erling Smørgrav 	case oCanonicalizePermittedCNAMEs:
1495f7167e0eSDag-Erling Smørgrav 		value = options->num_permitted_cnames != 0;
1496f7167e0eSDag-Erling Smørgrav 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1497f7167e0eSDag-Erling Smørgrav 			/* Either '*' for everything or 'list:list' */
1498f7167e0eSDag-Erling Smørgrav 			if (strcmp(arg, "*") == 0)
1499f7167e0eSDag-Erling Smørgrav 				arg2 = arg;
1500f7167e0eSDag-Erling Smørgrav 			else {
1501f7167e0eSDag-Erling Smørgrav 				lowercase(arg);
1502f7167e0eSDag-Erling Smørgrav 				if ((arg2 = strchr(arg, ':')) == NULL ||
1503f7167e0eSDag-Erling Smørgrav 				    arg2[1] == '\0') {
1504f7167e0eSDag-Erling Smørgrav 					fatal("%s line %d: "
1505f7167e0eSDag-Erling Smørgrav 					    "Invalid permitted CNAME \"%s\"",
1506f7167e0eSDag-Erling Smørgrav 					    filename, linenum, arg);
1507f7167e0eSDag-Erling Smørgrav 				}
1508f7167e0eSDag-Erling Smørgrav 				*arg2 = '\0';
1509f7167e0eSDag-Erling Smørgrav 				arg2++;
1510f7167e0eSDag-Erling Smørgrav 			}
1511f7167e0eSDag-Erling Smørgrav 			if (!*activep || value)
1512f7167e0eSDag-Erling Smørgrav 				continue;
1513f7167e0eSDag-Erling Smørgrav 			if (options->num_permitted_cnames >= MAX_CANON_DOMAINS)
1514f7167e0eSDag-Erling Smørgrav 				fatal("%s line %d: too many permitted CNAMEs.",
1515f7167e0eSDag-Erling Smørgrav 				    filename, linenum);
1516f7167e0eSDag-Erling Smørgrav 			cname = options->permitted_cnames +
1517f7167e0eSDag-Erling Smørgrav 			    options->num_permitted_cnames++;
1518f7167e0eSDag-Erling Smørgrav 			cname->source_list = xstrdup(arg);
1519f7167e0eSDag-Erling Smørgrav 			cname->target_list = xstrdup(arg2);
1520f7167e0eSDag-Erling Smørgrav 		}
1521f7167e0eSDag-Erling Smørgrav 		break;
1522f7167e0eSDag-Erling Smørgrav 
1523f7167e0eSDag-Erling Smørgrav 	case oCanonicalizeHostname:
1524f7167e0eSDag-Erling Smørgrav 		intptr = &options->canonicalize_hostname;
1525f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_canonicalizehostname;
1526f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
1527f7167e0eSDag-Erling Smørgrav 
1528f7167e0eSDag-Erling Smørgrav 	case oCanonicalizeMaxDots:
1529f7167e0eSDag-Erling Smørgrav 		intptr = &options->canonicalize_max_dots;
1530f7167e0eSDag-Erling Smørgrav 		goto parse_int;
1531f7167e0eSDag-Erling Smørgrav 
1532f7167e0eSDag-Erling Smørgrav 	case oCanonicalizeFallbackLocal:
1533f7167e0eSDag-Erling Smørgrav 		intptr = &options->canonicalize_fallback_local;
1534f7167e0eSDag-Erling Smørgrav 		goto parse_flag;
1535f7167e0eSDag-Erling Smørgrav 
1536a0ee8cc6SDag-Erling Smørgrav 	case oStreamLocalBindMask:
1537a0ee8cc6SDag-Erling Smørgrav 		arg = strdelim(&s);
1538a0ee8cc6SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1539a0ee8cc6SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum);
1540a0ee8cc6SDag-Erling Smørgrav 		/* Parse mode in octal format */
1541a0ee8cc6SDag-Erling Smørgrav 		value = strtol(arg, &endofnumber, 8);
1542a0ee8cc6SDag-Erling Smørgrav 		if (arg == endofnumber || value < 0 || value > 0777)
1543a0ee8cc6SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad mask.", filename, linenum);
1544a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
1545a0ee8cc6SDag-Erling Smørgrav 		break;
1546a0ee8cc6SDag-Erling Smørgrav 
1547a0ee8cc6SDag-Erling Smørgrav 	case oStreamLocalBindUnlink:
1548a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->fwd_opts.streamlocal_bind_unlink;
1549a0ee8cc6SDag-Erling Smørgrav 		goto parse_flag;
1550a0ee8cc6SDag-Erling Smørgrav 
1551bc5531deSDag-Erling Smørgrav 	case oRevokedHostKeys:
1552bc5531deSDag-Erling Smørgrav 		charptr = &options->revoked_host_keys;
1553bc5531deSDag-Erling Smørgrav 		goto parse_string;
1554bc5531deSDag-Erling Smørgrav 
1555bc5531deSDag-Erling Smørgrav 	case oFingerprintHash:
1556bc5531deSDag-Erling Smørgrav 		intptr = &options->fingerprint_hash;
1557bc5531deSDag-Erling Smørgrav 		arg = strdelim(&s);
1558bc5531deSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1559bc5531deSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.",
1560bc5531deSDag-Erling Smørgrav 			    filename, linenum);
1561bc5531deSDag-Erling Smørgrav 		if ((value = ssh_digest_alg_by_name(arg)) == -1)
1562bc5531deSDag-Erling Smørgrav 			fatal("%.200s line %d: Invalid hash algorithm \"%s\".",
1563bc5531deSDag-Erling Smørgrav 			    filename, linenum, arg);
1564bc5531deSDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1565bc5531deSDag-Erling Smørgrav 			*intptr = value;
1566bc5531deSDag-Erling Smørgrav 		break;
1567bc5531deSDag-Erling Smørgrav 
1568bc5531deSDag-Erling Smørgrav 	case oUpdateHostkeys:
1569bc5531deSDag-Erling Smørgrav 		intptr = &options->update_hostkeys;
1570bc5531deSDag-Erling Smørgrav 		multistate_ptr = multistate_yesnoask;
1571bc5531deSDag-Erling Smørgrav 		goto parse_multistate;
1572bc5531deSDag-Erling Smørgrav 
1573bc5531deSDag-Erling Smørgrav 	case oHostbasedKeyTypes:
1574bc5531deSDag-Erling Smørgrav 		charptr = &options->hostbased_key_types;
1575eccfee6eSDag-Erling Smørgrav 		goto parse_keytypes;
1576eccfee6eSDag-Erling Smørgrav 
1577eccfee6eSDag-Erling Smørgrav 	case oPubkeyAcceptedKeyTypes:
1578eccfee6eSDag-Erling Smørgrav 		charptr = &options->pubkey_key_types;
1579eccfee6eSDag-Erling Smørgrav 		goto parse_keytypes;
1580bc5531deSDag-Erling Smørgrav 
1581*acc1a9efSDag-Erling Smørgrav 	case oAddKeysToAgent:
1582*acc1a9efSDag-Erling Smørgrav 		intptr = &options->add_keys_to_agent;
1583*acc1a9efSDag-Erling Smørgrav 		multistate_ptr = multistate_yesnoaskconfirm;
1584*acc1a9efSDag-Erling Smørgrav 		goto parse_multistate;
1585*acc1a9efSDag-Erling Smørgrav 
158680628bacSDag-Erling Smørgrav 	case oDeprecated:
158780628bacSDag-Erling Smørgrav 		debug("%s line %d: Deprecated option \"%s\"",
158880628bacSDag-Erling Smørgrav 		    filename, linenum, keyword);
158980628bacSDag-Erling Smørgrav 		return 0;
159080628bacSDag-Erling Smørgrav 
1591cf2b5f3bSDag-Erling Smørgrav 	case oUnsupported:
1592cf2b5f3bSDag-Erling Smørgrav 		error("%s line %d: Unsupported option \"%s\"",
1593cf2b5f3bSDag-Erling Smørgrav 		    filename, linenum, keyword);
1594cf2b5f3bSDag-Erling Smørgrav 		return 0;
1595cf2b5f3bSDag-Erling Smørgrav 
1596511b41d2SMark Murray 	default:
1597bc5531deSDag-Erling Smørgrav 		fatal("%s: Unimplemented opcode %d", __func__, opcode);
1598511b41d2SMark Murray 	}
1599511b41d2SMark Murray 
1600511b41d2SMark Murray 	/* Check that there is no garbage at end of line. */
1601ca3176e7SBrian Feldman 	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1602c2d3a559SKris Kennaway 		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
1603c2d3a559SKris Kennaway 		    filename, linenum, arg);
1604c2d3a559SKris Kennaway 	}
1605511b41d2SMark Murray 	return 0;
1606511b41d2SMark Murray }
1607511b41d2SMark Murray 
1608511b41d2SMark Murray 
1609511b41d2SMark Murray /*
1610511b41d2SMark Murray  * Reads the config file and modifies the options accordingly.  Options
1611511b41d2SMark Murray  * should already be initialized before this call.  This never returns if
1612af12a3e7SDag-Erling Smørgrav  * there is an error.  If the file does not exist, this returns 0.
1613511b41d2SMark Murray  */
1614511b41d2SMark Murray 
1615af12a3e7SDag-Erling Smørgrav int
1616f7167e0eSDag-Erling Smørgrav read_config_file(const char *filename, struct passwd *pw, const char *host,
1617bc5531deSDag-Erling Smørgrav     const char *original_host, Options *options, int flags)
1618511b41d2SMark Murray {
1619511b41d2SMark Murray 	FILE *f;
1620511b41d2SMark Murray 	char line[1024];
1621511b41d2SMark Murray 	int active, linenum;
1622511b41d2SMark Murray 	int bad_options = 0;
1623511b41d2SMark Murray 
162421e764dfSDag-Erling Smørgrav 	if ((f = fopen(filename, "r")) == NULL)
1625af12a3e7SDag-Erling Smørgrav 		return 0;
1626511b41d2SMark Murray 
162773370613SDag-Erling Smørgrav 	if (flags & SSHCONF_CHECKPERM) {
162821e764dfSDag-Erling Smørgrav 		struct stat sb;
162921e764dfSDag-Erling Smørgrav 
163021e764dfSDag-Erling Smørgrav 		if (fstat(fileno(f), &sb) == -1)
163121e764dfSDag-Erling Smørgrav 			fatal("fstat %s: %s", filename, strerror(errno));
163221e764dfSDag-Erling Smørgrav 		if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
163321e764dfSDag-Erling Smørgrav 		    (sb.st_mode & 022) != 0))
163421e764dfSDag-Erling Smørgrav 			fatal("Bad owner or permissions on %s", filename);
163521e764dfSDag-Erling Smørgrav 	}
163621e764dfSDag-Erling Smørgrav 
1637511b41d2SMark Murray 	debug("Reading configuration data %.200s", filename);
1638511b41d2SMark Murray 
1639511b41d2SMark Murray 	/*
1640511b41d2SMark Murray 	 * Mark that we are now processing the options.  This flag is turned
1641511b41d2SMark Murray 	 * on/off by Host specifications.
1642511b41d2SMark Murray 	 */
1643511b41d2SMark Murray 	active = 1;
1644511b41d2SMark Murray 	linenum = 0;
1645511b41d2SMark Murray 	while (fgets(line, sizeof(line), f)) {
1646511b41d2SMark Murray 		/* Update line number counter. */
1647511b41d2SMark Murray 		linenum++;
1648bc5531deSDag-Erling Smørgrav 		if (process_config_line(options, pw, host, original_host,
1649bc5531deSDag-Erling Smørgrav 		    line, filename, linenum, &active, flags) != 0)
1650511b41d2SMark Murray 			bad_options++;
1651511b41d2SMark Murray 	}
1652511b41d2SMark Murray 	fclose(f);
1653511b41d2SMark Murray 	if (bad_options > 0)
1654ca3176e7SBrian Feldman 		fatal("%s: terminating, %d bad configuration options",
1655511b41d2SMark Murray 		    filename, bad_options);
1656af12a3e7SDag-Erling Smørgrav 	return 1;
1657511b41d2SMark Murray }
1658511b41d2SMark Murray 
1659b83788ffSDag-Erling Smørgrav /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
1660b83788ffSDag-Erling Smørgrav int
1661b83788ffSDag-Erling Smørgrav option_clear_or_none(const char *o)
1662b83788ffSDag-Erling Smørgrav {
1663b83788ffSDag-Erling Smørgrav 	return o == NULL || strcasecmp(o, "none") == 0;
1664b83788ffSDag-Erling Smørgrav }
1665b83788ffSDag-Erling Smørgrav 
1666511b41d2SMark Murray /*
1667511b41d2SMark Murray  * Initializes options to special values that indicate that they have not yet
1668511b41d2SMark Murray  * been set.  Read_config_file will only set options with this value. Options
1669511b41d2SMark Murray  * are processed in the following order: command line, user config file,
1670511b41d2SMark Murray  * system config file.  Last, fill_default_options is called.
1671511b41d2SMark Murray  */
1672511b41d2SMark Murray 
1673511b41d2SMark Murray void
1674511b41d2SMark Murray initialize_options(Options * options)
1675511b41d2SMark Murray {
1676511b41d2SMark Murray 	memset(options, 'X', sizeof(*options));
1677eccfee6eSDag-Erling Smørgrav 	options->version_addendum = NULL;
1678511b41d2SMark Murray 	options->forward_agent = -1;
1679511b41d2SMark Murray 	options->forward_x11 = -1;
16801ec0d754SDag-Erling Smørgrav 	options->forward_x11_trusted = -1;
1681e2f6069cSDag-Erling Smørgrav 	options->forward_x11_timeout = -1;
1682333ee039SDag-Erling Smørgrav 	options->exit_on_forward_failure = -1;
1683c2d3a559SKris Kennaway 	options->xauth_location = NULL;
1684a0ee8cc6SDag-Erling Smørgrav 	options->fwd_opts.gateway_ports = -1;
1685a0ee8cc6SDag-Erling Smørgrav 	options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
1686a0ee8cc6SDag-Erling Smørgrav 	options->fwd_opts.streamlocal_bind_unlink = -1;
1687511b41d2SMark Murray 	options->use_privileged_port = -1;
1688511b41d2SMark Murray 	options->rsa_authentication = -1;
1689ca3176e7SBrian Feldman 	options->pubkey_authentication = -1;
1690af12a3e7SDag-Erling Smørgrav 	options->challenge_response_authentication = -1;
1691cf2b5f3bSDag-Erling Smørgrav 	options->gss_authentication = -1;
1692cf2b5f3bSDag-Erling Smørgrav 	options->gss_deleg_creds = -1;
1693511b41d2SMark Murray 	options->password_authentication = -1;
169409958426SBrian Feldman 	options->kbd_interactive_authentication = -1;
169509958426SBrian Feldman 	options->kbd_interactive_devices = NULL;
1696511b41d2SMark Murray 	options->rhosts_rsa_authentication = -1;
1697ca3176e7SBrian Feldman 	options->hostbased_authentication = -1;
1698511b41d2SMark Murray 	options->batch_mode = -1;
1699511b41d2SMark Murray 	options->check_host_ip = -1;
1700511b41d2SMark Murray 	options->strict_host_key_checking = -1;
1701511b41d2SMark Murray 	options->compression = -1;
17021ec0d754SDag-Erling Smørgrav 	options->tcp_keep_alive = -1;
1703511b41d2SMark Murray 	options->compression_level = -1;
1704511b41d2SMark Murray 	options->port = -1;
1705cf2b5f3bSDag-Erling Smørgrav 	options->address_family = -1;
1706511b41d2SMark Murray 	options->connection_attempts = -1;
1707cf2b5f3bSDag-Erling Smørgrav 	options->connection_timeout = -1;
1708511b41d2SMark Murray 	options->number_of_password_prompts = -1;
1709511b41d2SMark Murray 	options->cipher = -1;
1710e8aafc91SKris Kennaway 	options->ciphers = NULL;
1711ca3176e7SBrian Feldman 	options->macs = NULL;
17124a421b63SDag-Erling Smørgrav 	options->kex_algorithms = NULL;
1713ca3176e7SBrian Feldman 	options->hostkeyalgorithms = NULL;
1714e8aafc91SKris Kennaway 	options->protocol = SSH_PROTO_UNKNOWN;
1715511b41d2SMark Murray 	options->num_identity_files = 0;
1716*acc1a9efSDag-Erling Smørgrav 	options->num_certificate_files = 0;
1717511b41d2SMark Murray 	options->hostname = NULL;
1718ca3176e7SBrian Feldman 	options->host_key_alias = NULL;
1719511b41d2SMark Murray 	options->proxy_command = NULL;
1720511b41d2SMark Murray 	options->user = NULL;
1721511b41d2SMark Murray 	options->escape_char = -1;
1722e146993eSDag-Erling Smørgrav 	options->num_system_hostfiles = 0;
1723e146993eSDag-Erling Smørgrav 	options->num_user_hostfiles = 0;
1724e2f6069cSDag-Erling Smørgrav 	options->local_forwards = NULL;
1725511b41d2SMark Murray 	options->num_local_forwards = 0;
1726e2f6069cSDag-Erling Smørgrav 	options->remote_forwards = NULL;
1727511b41d2SMark Murray 	options->num_remote_forwards = 0;
1728af12a3e7SDag-Erling Smørgrav 	options->clear_forwardings = -1;
1729af12a3e7SDag-Erling Smørgrav 	options->log_level = SYSLOG_LEVEL_NOT_SET;
1730ca3176e7SBrian Feldman 	options->preferred_authentications = NULL;
1731af12a3e7SDag-Erling Smørgrav 	options->bind_address = NULL;
1732b15c8340SDag-Erling Smørgrav 	options->pkcs11_provider = NULL;
1733e73e9afaSDag-Erling Smørgrav 	options->enable_ssh_keysign = - 1;
1734af12a3e7SDag-Erling Smørgrav 	options->no_host_authentication_for_localhost = - 1;
17355962c0e9SDag-Erling Smørgrav 	options->identities_only = - 1;
1736cf2b5f3bSDag-Erling Smørgrav 	options->rekey_limit = - 1;
1737e4a9863fSDag-Erling Smørgrav 	options->rekey_interval = -1;
1738cf2b5f3bSDag-Erling Smørgrav 	options->verify_host_key_dns = -1;
17391ec0d754SDag-Erling Smørgrav 	options->server_alive_interval = -1;
17401ec0d754SDag-Erling Smørgrav 	options->server_alive_count_max = -1;
174121e764dfSDag-Erling Smørgrav 	options->num_send_env = 0;
174221e764dfSDag-Erling Smørgrav 	options->control_path = NULL;
174321e764dfSDag-Erling Smørgrav 	options->control_master = -1;
1744e2f6069cSDag-Erling Smørgrav 	options->control_persist = -1;
1745e2f6069cSDag-Erling Smørgrav 	options->control_persist_timeout = 0;
1746aa49c926SDag-Erling Smørgrav 	options->hash_known_hosts = -1;
1747b74df5b2SDag-Erling Smørgrav 	options->tun_open = -1;
1748b74df5b2SDag-Erling Smørgrav 	options->tun_local = -1;
1749b74df5b2SDag-Erling Smørgrav 	options->tun_remote = -1;
1750b74df5b2SDag-Erling Smørgrav 	options->local_command = NULL;
1751b74df5b2SDag-Erling Smørgrav 	options->permit_local_command = -1;
1752*acc1a9efSDag-Erling Smørgrav 	options->add_keys_to_agent = -1;
1753d4af9e69SDag-Erling Smørgrav 	options->visual_host_key = -1;
17544a421b63SDag-Erling Smørgrav 	options->ip_qos_interactive = -1;
17554a421b63SDag-Erling Smørgrav 	options->ip_qos_bulk = -1;
1756e146993eSDag-Erling Smørgrav 	options->request_tty = -1;
1757f7167e0eSDag-Erling Smørgrav 	options->proxy_use_fdpass = -1;
1758e4a9863fSDag-Erling Smørgrav 	options->ignored_unknown = NULL;
1759f7167e0eSDag-Erling Smørgrav 	options->num_canonical_domains = 0;
1760f7167e0eSDag-Erling Smørgrav 	options->num_permitted_cnames = 0;
1761f7167e0eSDag-Erling Smørgrav 	options->canonicalize_max_dots = -1;
1762f7167e0eSDag-Erling Smørgrav 	options->canonicalize_fallback_local = -1;
1763f7167e0eSDag-Erling Smørgrav 	options->canonicalize_hostname = -1;
1764bc5531deSDag-Erling Smørgrav 	options->revoked_host_keys = NULL;
1765bc5531deSDag-Erling Smørgrav 	options->fingerprint_hash = -1;
1766bc5531deSDag-Erling Smørgrav 	options->update_hostkeys = -1;
1767bc5531deSDag-Erling Smørgrav 	options->hostbased_key_types = NULL;
1768eccfee6eSDag-Erling Smørgrav 	options->pubkey_key_types = NULL;
1769511b41d2SMark Murray }
1770511b41d2SMark Murray 
1771511b41d2SMark Murray /*
1772b83788ffSDag-Erling Smørgrav  * A petite version of fill_default_options() that just fills the options
1773b83788ffSDag-Erling Smørgrav  * needed for hostname canonicalization to proceed.
1774b83788ffSDag-Erling Smørgrav  */
1775b83788ffSDag-Erling Smørgrav void
1776b83788ffSDag-Erling Smørgrav fill_default_options_for_canonicalization(Options *options)
1777b83788ffSDag-Erling Smørgrav {
1778b83788ffSDag-Erling Smørgrav 	if (options->canonicalize_max_dots == -1)
1779b83788ffSDag-Erling Smørgrav 		options->canonicalize_max_dots = 1;
1780b83788ffSDag-Erling Smørgrav 	if (options->canonicalize_fallback_local == -1)
1781b83788ffSDag-Erling Smørgrav 		options->canonicalize_fallback_local = 1;
1782b83788ffSDag-Erling Smørgrav 	if (options->canonicalize_hostname == -1)
1783b83788ffSDag-Erling Smørgrav 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
1784b83788ffSDag-Erling Smørgrav }
1785b83788ffSDag-Erling Smørgrav 
1786b83788ffSDag-Erling Smørgrav /*
1787511b41d2SMark Murray  * Called after processing other sources of option data, this fills those
1788511b41d2SMark Murray  * options for which no value has been specified with their default values.
1789511b41d2SMark Murray  */
1790511b41d2SMark Murray void
1791511b41d2SMark Murray fill_default_options(Options * options)
1792511b41d2SMark Murray {
1793511b41d2SMark Murray 	if (options->forward_agent == -1)
1794db1cb46cSKris Kennaway 		options->forward_agent = 0;
1795511b41d2SMark Murray 	if (options->forward_x11 == -1)
17965dc73ebeSBrian Feldman 		options->forward_x11 = 0;
17971ec0d754SDag-Erling Smørgrav 	if (options->forward_x11_trusted == -1)
17981ec0d754SDag-Erling Smørgrav 		options->forward_x11_trusted = 0;
1799e2f6069cSDag-Erling Smørgrav 	if (options->forward_x11_timeout == -1)
1800e2f6069cSDag-Erling Smørgrav 		options->forward_x11_timeout = 1200;
1801333ee039SDag-Erling Smørgrav 	if (options->exit_on_forward_failure == -1)
1802333ee039SDag-Erling Smørgrav 		options->exit_on_forward_failure = 0;
1803c2d3a559SKris Kennaway 	if (options->xauth_location == NULL)
1804af12a3e7SDag-Erling Smørgrav 		options->xauth_location = _PATH_XAUTH;
1805a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.gateway_ports == -1)
1806a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.gateway_ports = 0;
1807a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
1808a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.streamlocal_bind_mask = 0177;
1809a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.streamlocal_bind_unlink == -1)
1810a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.streamlocal_bind_unlink = 0;
1811511b41d2SMark Murray 	if (options->use_privileged_port == -1)
1812ca3176e7SBrian Feldman 		options->use_privileged_port = 0;
1813511b41d2SMark Murray 	if (options->rsa_authentication == -1)
1814511b41d2SMark Murray 		options->rsa_authentication = 1;
1815ca3176e7SBrian Feldman 	if (options->pubkey_authentication == -1)
1816ca3176e7SBrian Feldman 		options->pubkey_authentication = 1;
1817af12a3e7SDag-Erling Smørgrav 	if (options->challenge_response_authentication == -1)
1818af12a3e7SDag-Erling Smørgrav 		options->challenge_response_authentication = 1;
1819cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_authentication == -1)
18201ec0d754SDag-Erling Smørgrav 		options->gss_authentication = 0;
1821cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_deleg_creds == -1)
1822cf2b5f3bSDag-Erling Smørgrav 		options->gss_deleg_creds = 0;
1823511b41d2SMark Murray 	if (options->password_authentication == -1)
1824511b41d2SMark Murray 		options->password_authentication = 1;
182509958426SBrian Feldman 	if (options->kbd_interactive_authentication == -1)
1826ca3176e7SBrian Feldman 		options->kbd_interactive_authentication = 1;
1827511b41d2SMark Murray 	if (options->rhosts_rsa_authentication == -1)
182880628bacSDag-Erling Smørgrav 		options->rhosts_rsa_authentication = 0;
1829ca3176e7SBrian Feldman 	if (options->hostbased_authentication == -1)
1830ca3176e7SBrian Feldman 		options->hostbased_authentication = 0;
1831511b41d2SMark Murray 	if (options->batch_mode == -1)
1832511b41d2SMark Murray 		options->batch_mode = 0;
1833511b41d2SMark Murray 	if (options->check_host_ip == -1)
1834975616f0SDag-Erling Smørgrav 		options->check_host_ip = 0;
1835511b41d2SMark Murray 	if (options->strict_host_key_checking == -1)
1836511b41d2SMark Murray 		options->strict_host_key_checking = 2;	/* 2 is default */
1837511b41d2SMark Murray 	if (options->compression == -1)
1838511b41d2SMark Murray 		options->compression = 0;
18391ec0d754SDag-Erling Smørgrav 	if (options->tcp_keep_alive == -1)
18401ec0d754SDag-Erling Smørgrav 		options->tcp_keep_alive = 1;
1841511b41d2SMark Murray 	if (options->compression_level == -1)
1842511b41d2SMark Murray 		options->compression_level = 6;
1843511b41d2SMark Murray 	if (options->port == -1)
1844511b41d2SMark Murray 		options->port = 0;	/* Filled in ssh_connect. */
1845cf2b5f3bSDag-Erling Smørgrav 	if (options->address_family == -1)
1846cf2b5f3bSDag-Erling Smørgrav 		options->address_family = AF_UNSPEC;
1847511b41d2SMark Murray 	if (options->connection_attempts == -1)
1848af12a3e7SDag-Erling Smørgrav 		options->connection_attempts = 1;
1849511b41d2SMark Murray 	if (options->number_of_password_prompts == -1)
1850511b41d2SMark Murray 		options->number_of_password_prompts = 3;
1851511b41d2SMark Murray 	/* Selected in ssh_login(). */
1852511b41d2SMark Murray 	if (options->cipher == -1)
1853511b41d2SMark Murray 		options->cipher = SSH_CIPHER_NOT_SET;
1854ca3176e7SBrian Feldman 	/* options->hostkeyalgorithms, default set in myproposals.h */
1855e8aafc91SKris Kennaway 	if (options->protocol == SSH_PROTO_UNKNOWN)
1856b15c8340SDag-Erling Smørgrav 		options->protocol = SSH_PROTO_2;
1857*acc1a9efSDag-Erling Smørgrav 	if (options->add_keys_to_agent == -1)
1858*acc1a9efSDag-Erling Smørgrav 		options->add_keys_to_agent = 0;
1859511b41d2SMark Murray 	if (options->num_identity_files == 0) {
1860ca3176e7SBrian Feldman 		if (options->protocol & SSH_PROTO_1) {
186173370613SDag-Erling Smørgrav 			add_identity_file(options, "~/",
186273370613SDag-Erling Smørgrav 			    _PATH_SSH_CLIENT_IDENTITY, 0);
1863511b41d2SMark Murray 		}
1864ca3176e7SBrian Feldman 		if (options->protocol & SSH_PROTO_2) {
186573370613SDag-Erling Smørgrav 			add_identity_file(options, "~/",
186673370613SDag-Erling Smørgrav 			    _PATH_SSH_CLIENT_ID_RSA, 0);
186773370613SDag-Erling Smørgrav 			add_identity_file(options, "~/",
186873370613SDag-Erling Smørgrav 			    _PATH_SSH_CLIENT_ID_DSA, 0);
18694a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
187073370613SDag-Erling Smørgrav 			add_identity_file(options, "~/",
187173370613SDag-Erling Smørgrav 			    _PATH_SSH_CLIENT_ID_ECDSA, 0);
18724a421b63SDag-Erling Smørgrav #endif
1873f7167e0eSDag-Erling Smørgrav 			add_identity_file(options, "~/",
1874f7167e0eSDag-Erling Smørgrav 			    _PATH_SSH_CLIENT_ID_ED25519, 0);
1875ca3176e7SBrian Feldman 		}
1876e8aafc91SKris Kennaway 	}
1877511b41d2SMark Murray 	if (options->escape_char == -1)
1878511b41d2SMark Murray 		options->escape_char = '~';
1879e146993eSDag-Erling Smørgrav 	if (options->num_system_hostfiles == 0) {
1880e146993eSDag-Erling Smørgrav 		options->system_hostfiles[options->num_system_hostfiles++] =
1881e146993eSDag-Erling Smørgrav 		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
1882e146993eSDag-Erling Smørgrav 		options->system_hostfiles[options->num_system_hostfiles++] =
1883e146993eSDag-Erling Smørgrav 		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
1884e146993eSDag-Erling Smørgrav 	}
1885e146993eSDag-Erling Smørgrav 	if (options->num_user_hostfiles == 0) {
1886e146993eSDag-Erling Smørgrav 		options->user_hostfiles[options->num_user_hostfiles++] =
1887e146993eSDag-Erling Smørgrav 		    xstrdup(_PATH_SSH_USER_HOSTFILE);
1888e146993eSDag-Erling Smørgrav 		options->user_hostfiles[options->num_user_hostfiles++] =
1889e146993eSDag-Erling Smørgrav 		    xstrdup(_PATH_SSH_USER_HOSTFILE2);
1890e146993eSDag-Erling Smørgrav 	}
1891af12a3e7SDag-Erling Smørgrav 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
1892511b41d2SMark Murray 		options->log_level = SYSLOG_LEVEL_INFO;
1893af12a3e7SDag-Erling Smørgrav 	if (options->clear_forwardings == 1)
1894af12a3e7SDag-Erling Smørgrav 		clear_forwardings(options);
1895af12a3e7SDag-Erling Smørgrav 	if (options->no_host_authentication_for_localhost == - 1)
1896af12a3e7SDag-Erling Smørgrav 		options->no_host_authentication_for_localhost = 0;
18975962c0e9SDag-Erling Smørgrav 	if (options->identities_only == -1)
18985962c0e9SDag-Erling Smørgrav 		options->identities_only = 0;
1899e73e9afaSDag-Erling Smørgrav 	if (options->enable_ssh_keysign == -1)
1900e73e9afaSDag-Erling Smørgrav 		options->enable_ssh_keysign = 0;
1901cf2b5f3bSDag-Erling Smørgrav 	if (options->rekey_limit == -1)
1902cf2b5f3bSDag-Erling Smørgrav 		options->rekey_limit = 0;
1903e4a9863fSDag-Erling Smørgrav 	if (options->rekey_interval == -1)
1904e4a9863fSDag-Erling Smørgrav 		options->rekey_interval = 0;
190583c6a524SDag-Erling Smørgrav #if HAVE_LDNS
190683c6a524SDag-Erling Smørgrav 	if (options->verify_host_key_dns == -1)
190783c6a524SDag-Erling Smørgrav 		/* automatically trust a verified SSHFP record */
190883c6a524SDag-Erling Smørgrav 		options->verify_host_key_dns = 1;
190983c6a524SDag-Erling Smørgrav #else
1910cf2b5f3bSDag-Erling Smørgrav 	if (options->verify_host_key_dns == -1)
1911cf2b5f3bSDag-Erling Smørgrav 		options->verify_host_key_dns = 0;
191283c6a524SDag-Erling Smørgrav #endif
19131ec0d754SDag-Erling Smørgrav 	if (options->server_alive_interval == -1)
19141ec0d754SDag-Erling Smørgrav 		options->server_alive_interval = 0;
19151ec0d754SDag-Erling Smørgrav 	if (options->server_alive_count_max == -1)
19161ec0d754SDag-Erling Smørgrav 		options->server_alive_count_max = 3;
191721e764dfSDag-Erling Smørgrav 	if (options->control_master == -1)
191821e764dfSDag-Erling Smørgrav 		options->control_master = 0;
1919e2f6069cSDag-Erling Smørgrav 	if (options->control_persist == -1) {
1920e2f6069cSDag-Erling Smørgrav 		options->control_persist = 0;
1921e2f6069cSDag-Erling Smørgrav 		options->control_persist_timeout = 0;
1922e2f6069cSDag-Erling Smørgrav 	}
1923aa49c926SDag-Erling Smørgrav 	if (options->hash_known_hosts == -1)
1924aa49c926SDag-Erling Smørgrav 		options->hash_known_hosts = 0;
1925b74df5b2SDag-Erling Smørgrav 	if (options->tun_open == -1)
1926b74df5b2SDag-Erling Smørgrav 		options->tun_open = SSH_TUNMODE_NO;
1927b74df5b2SDag-Erling Smørgrav 	if (options->tun_local == -1)
1928b74df5b2SDag-Erling Smørgrav 		options->tun_local = SSH_TUNID_ANY;
1929b74df5b2SDag-Erling Smørgrav 	if (options->tun_remote == -1)
1930b74df5b2SDag-Erling Smørgrav 		options->tun_remote = SSH_TUNID_ANY;
1931b74df5b2SDag-Erling Smørgrav 	if (options->permit_local_command == -1)
1932b74df5b2SDag-Erling Smørgrav 		options->permit_local_command = 0;
1933d4af9e69SDag-Erling Smørgrav 	if (options->visual_host_key == -1)
1934d4af9e69SDag-Erling Smørgrav 		options->visual_host_key = 0;
19354a421b63SDag-Erling Smørgrav 	if (options->ip_qos_interactive == -1)
19364a421b63SDag-Erling Smørgrav 		options->ip_qos_interactive = IPTOS_LOWDELAY;
19374a421b63SDag-Erling Smørgrav 	if (options->ip_qos_bulk == -1)
19384a421b63SDag-Erling Smørgrav 		options->ip_qos_bulk = IPTOS_THROUGHPUT;
1939e146993eSDag-Erling Smørgrav 	if (options->request_tty == -1)
1940e146993eSDag-Erling Smørgrav 		options->request_tty = REQUEST_TTY_AUTO;
1941f7167e0eSDag-Erling Smørgrav 	if (options->proxy_use_fdpass == -1)
1942f7167e0eSDag-Erling Smørgrav 		options->proxy_use_fdpass = 0;
1943f7167e0eSDag-Erling Smørgrav 	if (options->canonicalize_max_dots == -1)
1944f7167e0eSDag-Erling Smørgrav 		options->canonicalize_max_dots = 1;
1945f7167e0eSDag-Erling Smørgrav 	if (options->canonicalize_fallback_local == -1)
1946f7167e0eSDag-Erling Smørgrav 		options->canonicalize_fallback_local = 1;
1947f7167e0eSDag-Erling Smørgrav 	if (options->canonicalize_hostname == -1)
1948f7167e0eSDag-Erling Smørgrav 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
1949bc5531deSDag-Erling Smørgrav 	if (options->fingerprint_hash == -1)
1950bc5531deSDag-Erling Smørgrav 		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
1951bc5531deSDag-Erling Smørgrav 	if (options->update_hostkeys == -1)
1952bc5531deSDag-Erling Smørgrav 		options->update_hostkeys = 0;
1953eccfee6eSDag-Erling Smørgrav 	if (kex_assemble_names(KEX_CLIENT_ENCRYPT, &options->ciphers) != 0 ||
1954eccfee6eSDag-Erling Smørgrav 	    kex_assemble_names(KEX_CLIENT_MAC, &options->macs) != 0 ||
1955eccfee6eSDag-Erling Smørgrav 	    kex_assemble_names(KEX_CLIENT_KEX, &options->kex_algorithms) != 0 ||
1956eccfee6eSDag-Erling Smørgrav 	    kex_assemble_names(KEX_DEFAULT_PK_ALG,
1957eccfee6eSDag-Erling Smørgrav 	    &options->hostbased_key_types) != 0 ||
1958eccfee6eSDag-Erling Smørgrav 	    kex_assemble_names(KEX_DEFAULT_PK_ALG,
1959eccfee6eSDag-Erling Smørgrav 	    &options->pubkey_key_types) != 0)
1960eccfee6eSDag-Erling Smørgrav 		fatal("%s: kex_assemble_names failed", __func__);
1961bc5531deSDag-Erling Smørgrav 
1962f7167e0eSDag-Erling Smørgrav #define CLEAR_ON_NONE(v) \
1963f7167e0eSDag-Erling Smørgrav 	do { \
1964b83788ffSDag-Erling Smørgrav 		if (option_clear_or_none(v)) { \
1965f7167e0eSDag-Erling Smørgrav 			free(v); \
1966f7167e0eSDag-Erling Smørgrav 			v = NULL; \
1967f7167e0eSDag-Erling Smørgrav 		} \
1968f7167e0eSDag-Erling Smørgrav 	} while(0)
1969f7167e0eSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->local_command);
1970f7167e0eSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->proxy_command);
1971f7167e0eSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->control_path);
1972bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->revoked_host_keys);
1973511b41d2SMark Murray 	/* options->user will be set in the main program if appropriate */
1974511b41d2SMark Murray 	/* options->hostname will be set in the main program if appropriate */
1975ca3176e7SBrian Feldman 	/* options->host_key_alias should not be set by default */
1976ca3176e7SBrian Feldman 	/* options->preferred_authentications will be set in ssh */
1977462c32cbSDag-Erling Smørgrav 	if (options->version_addendum == NULL)
1978462c32cbSDag-Erling Smørgrav 		options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
1979511b41d2SMark Murray }
1980aa49c926SDag-Erling Smørgrav 
1981a0ee8cc6SDag-Erling Smørgrav struct fwdarg {
1982a0ee8cc6SDag-Erling Smørgrav 	char *arg;
1983a0ee8cc6SDag-Erling Smørgrav 	int ispath;
1984a0ee8cc6SDag-Erling Smørgrav };
1985a0ee8cc6SDag-Erling Smørgrav 
1986a0ee8cc6SDag-Erling Smørgrav /*
1987a0ee8cc6SDag-Erling Smørgrav  * parse_fwd_field
1988a0ee8cc6SDag-Erling Smørgrav  * parses the next field in a port forwarding specification.
1989a0ee8cc6SDag-Erling Smørgrav  * sets fwd to the parsed field and advances p past the colon
1990a0ee8cc6SDag-Erling Smørgrav  * or sets it to NULL at end of string.
1991a0ee8cc6SDag-Erling Smørgrav  * returns 0 on success, else non-zero.
1992a0ee8cc6SDag-Erling Smørgrav  */
1993a0ee8cc6SDag-Erling Smørgrav static int
1994a0ee8cc6SDag-Erling Smørgrav parse_fwd_field(char **p, struct fwdarg *fwd)
1995a0ee8cc6SDag-Erling Smørgrav {
1996a0ee8cc6SDag-Erling Smørgrav 	char *ep, *cp = *p;
1997a0ee8cc6SDag-Erling Smørgrav 	int ispath = 0;
1998a0ee8cc6SDag-Erling Smørgrav 
1999a0ee8cc6SDag-Erling Smørgrav 	if (*cp == '\0') {
2000a0ee8cc6SDag-Erling Smørgrav 		*p = NULL;
2001a0ee8cc6SDag-Erling Smørgrav 		return -1;	/* end of string */
2002a0ee8cc6SDag-Erling Smørgrav 	}
2003a0ee8cc6SDag-Erling Smørgrav 
2004a0ee8cc6SDag-Erling Smørgrav 	/*
2005a0ee8cc6SDag-Erling Smørgrav 	 * A field escaped with square brackets is used literally.
2006a0ee8cc6SDag-Erling Smørgrav 	 * XXX - allow ']' to be escaped via backslash?
2007a0ee8cc6SDag-Erling Smørgrav 	 */
2008a0ee8cc6SDag-Erling Smørgrav 	if (*cp == '[') {
2009a0ee8cc6SDag-Erling Smørgrav 		/* find matching ']' */
2010a0ee8cc6SDag-Erling Smørgrav 		for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
2011a0ee8cc6SDag-Erling Smørgrav 			if (*ep == '/')
2012a0ee8cc6SDag-Erling Smørgrav 				ispath = 1;
2013a0ee8cc6SDag-Erling Smørgrav 		}
2014a0ee8cc6SDag-Erling Smørgrav 		/* no matching ']' or not at end of field. */
2015a0ee8cc6SDag-Erling Smørgrav 		if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
2016a0ee8cc6SDag-Erling Smørgrav 			return -1;
2017a0ee8cc6SDag-Erling Smørgrav 		/* NUL terminate the field and advance p past the colon */
2018a0ee8cc6SDag-Erling Smørgrav 		*ep++ = '\0';
2019a0ee8cc6SDag-Erling Smørgrav 		if (*ep != '\0')
2020a0ee8cc6SDag-Erling Smørgrav 			*ep++ = '\0';
2021a0ee8cc6SDag-Erling Smørgrav 		fwd->arg = cp + 1;
2022a0ee8cc6SDag-Erling Smørgrav 		fwd->ispath = ispath;
2023a0ee8cc6SDag-Erling Smørgrav 		*p = ep;
2024a0ee8cc6SDag-Erling Smørgrav 		return 0;
2025a0ee8cc6SDag-Erling Smørgrav 	}
2026a0ee8cc6SDag-Erling Smørgrav 
2027a0ee8cc6SDag-Erling Smørgrav 	for (cp = *p; *cp != '\0'; cp++) {
2028a0ee8cc6SDag-Erling Smørgrav 		switch (*cp) {
2029a0ee8cc6SDag-Erling Smørgrav 		case '\\':
2030a0ee8cc6SDag-Erling Smørgrav 			memmove(cp, cp + 1, strlen(cp + 1) + 1);
2031557f75e5SDag-Erling Smørgrav 			if (*cp == '\0')
2032557f75e5SDag-Erling Smørgrav 				return -1;
2033a0ee8cc6SDag-Erling Smørgrav 			break;
2034a0ee8cc6SDag-Erling Smørgrav 		case '/':
2035a0ee8cc6SDag-Erling Smørgrav 			ispath = 1;
2036a0ee8cc6SDag-Erling Smørgrav 			break;
2037a0ee8cc6SDag-Erling Smørgrav 		case ':':
2038a0ee8cc6SDag-Erling Smørgrav 			*cp++ = '\0';
2039a0ee8cc6SDag-Erling Smørgrav 			goto done;
2040a0ee8cc6SDag-Erling Smørgrav 		}
2041a0ee8cc6SDag-Erling Smørgrav 	}
2042a0ee8cc6SDag-Erling Smørgrav done:
2043a0ee8cc6SDag-Erling Smørgrav 	fwd->arg = *p;
2044a0ee8cc6SDag-Erling Smørgrav 	fwd->ispath = ispath;
2045a0ee8cc6SDag-Erling Smørgrav 	*p = cp;
2046a0ee8cc6SDag-Erling Smørgrav 	return 0;
2047a0ee8cc6SDag-Erling Smørgrav }
2048a0ee8cc6SDag-Erling Smørgrav 
2049aa49c926SDag-Erling Smørgrav /*
2050aa49c926SDag-Erling Smørgrav  * parse_forward
2051aa49c926SDag-Erling Smørgrav  * parses a string containing a port forwarding specification of the form:
2052cce7d346SDag-Erling Smørgrav  *   dynamicfwd == 0
2053a0ee8cc6SDag-Erling Smørgrav  *	[listenhost:]listenport|listenpath:connecthost:connectport|connectpath
2054a0ee8cc6SDag-Erling Smørgrav  *	listenpath:connectpath
2055cce7d346SDag-Erling Smørgrav  *   dynamicfwd == 1
2056cce7d346SDag-Erling Smørgrav  *	[listenhost:]listenport
2057aa49c926SDag-Erling Smørgrav  * returns number of arguments parsed or zero on error
2058aa49c926SDag-Erling Smørgrav  */
2059aa49c926SDag-Erling Smørgrav int
2060a0ee8cc6SDag-Erling Smørgrav parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
2061aa49c926SDag-Erling Smørgrav {
2062a0ee8cc6SDag-Erling Smørgrav 	struct fwdarg fwdargs[4];
2063a0ee8cc6SDag-Erling Smørgrav 	char *p, *cp;
2064aa49c926SDag-Erling Smørgrav 	int i;
2065aa49c926SDag-Erling Smørgrav 
2066a0ee8cc6SDag-Erling Smørgrav 	memset(fwd, 0, sizeof(*fwd));
2067a0ee8cc6SDag-Erling Smørgrav 	memset(fwdargs, 0, sizeof(fwdargs));
2068aa49c926SDag-Erling Smørgrav 
2069aa49c926SDag-Erling Smørgrav 	cp = p = xstrdup(fwdspec);
2070aa49c926SDag-Erling Smørgrav 
2071aa49c926SDag-Erling Smørgrav 	/* skip leading spaces */
2072f7167e0eSDag-Erling Smørgrav 	while (isspace((u_char)*cp))
2073aa49c926SDag-Erling Smørgrav 		cp++;
2074aa49c926SDag-Erling Smørgrav 
2075a0ee8cc6SDag-Erling Smørgrav 	for (i = 0; i < 4; ++i) {
2076a0ee8cc6SDag-Erling Smørgrav 		if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
2077aa49c926SDag-Erling Smørgrav 			break;
2078a0ee8cc6SDag-Erling Smørgrav 	}
2079aa49c926SDag-Erling Smørgrav 
2080cce7d346SDag-Erling Smørgrav 	/* Check for trailing garbage */
2081a0ee8cc6SDag-Erling Smørgrav 	if (cp != NULL && *cp != '\0') {
2082aa49c926SDag-Erling Smørgrav 		i = 0;	/* failure */
2083a0ee8cc6SDag-Erling Smørgrav 	}
2084aa49c926SDag-Erling Smørgrav 
2085aa49c926SDag-Erling Smørgrav 	switch (i) {
2086cce7d346SDag-Erling Smørgrav 	case 1:
2087a0ee8cc6SDag-Erling Smørgrav 		if (fwdargs[0].ispath) {
2088a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_path = xstrdup(fwdargs[0].arg);
2089a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_port = PORT_STREAMLOCAL;
2090a0ee8cc6SDag-Erling Smørgrav 		} else {
2091cce7d346SDag-Erling Smørgrav 			fwd->listen_host = NULL;
2092a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_port = a2port(fwdargs[0].arg);
2093a0ee8cc6SDag-Erling Smørgrav 		}
2094cce7d346SDag-Erling Smørgrav 		fwd->connect_host = xstrdup("socks");
2095cce7d346SDag-Erling Smørgrav 		break;
2096cce7d346SDag-Erling Smørgrav 
2097cce7d346SDag-Erling Smørgrav 	case 2:
2098a0ee8cc6SDag-Erling Smørgrav 		if (fwdargs[0].ispath && fwdargs[1].ispath) {
2099a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_path = xstrdup(fwdargs[0].arg);
2100a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_port = PORT_STREAMLOCAL;
2101a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_path = xstrdup(fwdargs[1].arg);
2102a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_port = PORT_STREAMLOCAL;
2103a0ee8cc6SDag-Erling Smørgrav 		} else if (fwdargs[1].ispath) {
2104a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_host = NULL;
2105a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_port = a2port(fwdargs[0].arg);
2106a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_path = xstrdup(fwdargs[1].arg);
2107a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_port = PORT_STREAMLOCAL;
2108a0ee8cc6SDag-Erling Smørgrav 		} else {
2109a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_host = xstrdup(fwdargs[0].arg);
2110a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_port = a2port(fwdargs[1].arg);
2111cce7d346SDag-Erling Smørgrav 			fwd->connect_host = xstrdup("socks");
2112a0ee8cc6SDag-Erling Smørgrav 		}
2113cce7d346SDag-Erling Smørgrav 		break;
2114cce7d346SDag-Erling Smørgrav 
2115aa49c926SDag-Erling Smørgrav 	case 3:
2116a0ee8cc6SDag-Erling Smørgrav 		if (fwdargs[0].ispath) {
2117a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_path = xstrdup(fwdargs[0].arg);
2118a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_port = PORT_STREAMLOCAL;
2119a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_host = xstrdup(fwdargs[1].arg);
2120a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_port = a2port(fwdargs[2].arg);
2121a0ee8cc6SDag-Erling Smørgrav 		} else if (fwdargs[2].ispath) {
2122a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_host = xstrdup(fwdargs[0].arg);
2123a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_port = a2port(fwdargs[1].arg);
2124a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_path = xstrdup(fwdargs[2].arg);
2125a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_port = PORT_STREAMLOCAL;
2126a0ee8cc6SDag-Erling Smørgrav 		} else {
2127aa49c926SDag-Erling Smørgrav 			fwd->listen_host = NULL;
2128a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_port = a2port(fwdargs[0].arg);
2129a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_host = xstrdup(fwdargs[1].arg);
2130a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_port = a2port(fwdargs[2].arg);
2131a0ee8cc6SDag-Erling Smørgrav 		}
2132aa49c926SDag-Erling Smørgrav 		break;
2133aa49c926SDag-Erling Smørgrav 
2134aa49c926SDag-Erling Smørgrav 	case 4:
2135a0ee8cc6SDag-Erling Smørgrav 		fwd->listen_host = xstrdup(fwdargs[0].arg);
2136a0ee8cc6SDag-Erling Smørgrav 		fwd->listen_port = a2port(fwdargs[1].arg);
2137a0ee8cc6SDag-Erling Smørgrav 		fwd->connect_host = xstrdup(fwdargs[2].arg);
2138a0ee8cc6SDag-Erling Smørgrav 		fwd->connect_port = a2port(fwdargs[3].arg);
2139aa49c926SDag-Erling Smørgrav 		break;
2140aa49c926SDag-Erling Smørgrav 	default:
2141aa49c926SDag-Erling Smørgrav 		i = 0; /* failure */
2142aa49c926SDag-Erling Smørgrav 	}
2143aa49c926SDag-Erling Smørgrav 
2144e4a9863fSDag-Erling Smørgrav 	free(p);
2145aa49c926SDag-Erling Smørgrav 
2146cce7d346SDag-Erling Smørgrav 	if (dynamicfwd) {
2147cce7d346SDag-Erling Smørgrav 		if (!(i == 1 || i == 2))
2148cce7d346SDag-Erling Smørgrav 			goto fail_free;
2149cce7d346SDag-Erling Smørgrav 	} else {
2150a0ee8cc6SDag-Erling Smørgrav 		if (!(i == 3 || i == 4)) {
2151a0ee8cc6SDag-Erling Smørgrav 			if (fwd->connect_path == NULL &&
2152a0ee8cc6SDag-Erling Smørgrav 			    fwd->listen_path == NULL)
2153cce7d346SDag-Erling Smørgrav 				goto fail_free;
2154a0ee8cc6SDag-Erling Smørgrav 		}
2155a0ee8cc6SDag-Erling Smørgrav 		if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
2156cce7d346SDag-Erling Smørgrav 			goto fail_free;
2157cce7d346SDag-Erling Smørgrav 	}
2158cce7d346SDag-Erling Smørgrav 
2159a0ee8cc6SDag-Erling Smørgrav 	if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
2160a0ee8cc6SDag-Erling Smørgrav 	    (!remotefwd && fwd->listen_port == 0))
2161aa49c926SDag-Erling Smørgrav 		goto fail_free;
2162aa49c926SDag-Erling Smørgrav 	if (fwd->connect_host != NULL &&
2163aa49c926SDag-Erling Smørgrav 	    strlen(fwd->connect_host) >= NI_MAXHOST)
2164aa49c926SDag-Erling Smørgrav 		goto fail_free;
2165a0ee8cc6SDag-Erling Smørgrav 	/* XXX - if connecting to a remote socket, max sun len may not match this host */
2166a0ee8cc6SDag-Erling Smørgrav 	if (fwd->connect_path != NULL &&
2167a0ee8cc6SDag-Erling Smørgrav 	    strlen(fwd->connect_path) >= PATH_MAX_SUN)
2168a0ee8cc6SDag-Erling Smørgrav 		goto fail_free;
2169cce7d346SDag-Erling Smørgrav 	if (fwd->listen_host != NULL &&
2170cce7d346SDag-Erling Smørgrav 	    strlen(fwd->listen_host) >= NI_MAXHOST)
2171cce7d346SDag-Erling Smørgrav 		goto fail_free;
2172a0ee8cc6SDag-Erling Smørgrav 	if (fwd->listen_path != NULL &&
2173a0ee8cc6SDag-Erling Smørgrav 	    strlen(fwd->listen_path) >= PATH_MAX_SUN)
2174a0ee8cc6SDag-Erling Smørgrav 		goto fail_free;
2175aa49c926SDag-Erling Smørgrav 
2176aa49c926SDag-Erling Smørgrav 	return (i);
2177aa49c926SDag-Erling Smørgrav 
2178aa49c926SDag-Erling Smørgrav  fail_free:
2179e4a9863fSDag-Erling Smørgrav 	free(fwd->connect_host);
2180cce7d346SDag-Erling Smørgrav 	fwd->connect_host = NULL;
2181a0ee8cc6SDag-Erling Smørgrav 	free(fwd->connect_path);
2182a0ee8cc6SDag-Erling Smørgrav 	fwd->connect_path = NULL;
2183e4a9863fSDag-Erling Smørgrav 	free(fwd->listen_host);
2184cce7d346SDag-Erling Smørgrav 	fwd->listen_host = NULL;
2185a0ee8cc6SDag-Erling Smørgrav 	free(fwd->listen_path);
2186a0ee8cc6SDag-Erling Smørgrav 	fwd->listen_path = NULL;
2187aa49c926SDag-Erling Smørgrav 	return (0);
2188aa49c926SDag-Erling Smørgrav }
2189bc5531deSDag-Erling Smørgrav 
2190bc5531deSDag-Erling Smørgrav /* XXX the following is a near-vebatim copy from servconf.c; refactor */
2191bc5531deSDag-Erling Smørgrav static const char *
2192bc5531deSDag-Erling Smørgrav fmt_multistate_int(int val, const struct multistate *m)
2193bc5531deSDag-Erling Smørgrav {
2194bc5531deSDag-Erling Smørgrav 	u_int i;
2195bc5531deSDag-Erling Smørgrav 
2196bc5531deSDag-Erling Smørgrav 	for (i = 0; m[i].key != NULL; i++) {
2197bc5531deSDag-Erling Smørgrav 		if (m[i].value == val)
2198bc5531deSDag-Erling Smørgrav 			return m[i].key;
2199bc5531deSDag-Erling Smørgrav 	}
2200bc5531deSDag-Erling Smørgrav 	return "UNKNOWN";
2201bc5531deSDag-Erling Smørgrav }
2202bc5531deSDag-Erling Smørgrav 
2203bc5531deSDag-Erling Smørgrav static const char *
2204bc5531deSDag-Erling Smørgrav fmt_intarg(OpCodes code, int val)
2205bc5531deSDag-Erling Smørgrav {
2206bc5531deSDag-Erling Smørgrav 	if (val == -1)
2207bc5531deSDag-Erling Smørgrav 		return "unset";
2208bc5531deSDag-Erling Smørgrav 	switch (code) {
2209bc5531deSDag-Erling Smørgrav 	case oAddressFamily:
2210bc5531deSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_addressfamily);
2211bc5531deSDag-Erling Smørgrav 	case oVerifyHostKeyDNS:
2212bc5531deSDag-Erling Smørgrav 	case oStrictHostKeyChecking:
2213bc5531deSDag-Erling Smørgrav 	case oUpdateHostkeys:
2214bc5531deSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_yesnoask);
2215bc5531deSDag-Erling Smørgrav 	case oControlMaster:
2216bc5531deSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_controlmaster);
2217bc5531deSDag-Erling Smørgrav 	case oTunnel:
2218bc5531deSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_tunnel);
2219bc5531deSDag-Erling Smørgrav 	case oRequestTTY:
2220bc5531deSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_requesttty);
2221bc5531deSDag-Erling Smørgrav 	case oCanonicalizeHostname:
2222bc5531deSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_canonicalizehostname);
2223bc5531deSDag-Erling Smørgrav 	case oFingerprintHash:
2224bc5531deSDag-Erling Smørgrav 		return ssh_digest_alg_name(val);
2225bc5531deSDag-Erling Smørgrav 	case oProtocol:
2226bc5531deSDag-Erling Smørgrav 		switch (val) {
2227bc5531deSDag-Erling Smørgrav 		case SSH_PROTO_1:
2228bc5531deSDag-Erling Smørgrav 			return "1";
2229bc5531deSDag-Erling Smørgrav 		case SSH_PROTO_2:
2230bc5531deSDag-Erling Smørgrav 			return "2";
2231bc5531deSDag-Erling Smørgrav 		case (SSH_PROTO_1|SSH_PROTO_2):
2232bc5531deSDag-Erling Smørgrav 			return "2,1";
2233bc5531deSDag-Erling Smørgrav 		default:
2234bc5531deSDag-Erling Smørgrav 			return "UNKNOWN";
2235bc5531deSDag-Erling Smørgrav 		}
2236bc5531deSDag-Erling Smørgrav 	default:
2237bc5531deSDag-Erling Smørgrav 		switch (val) {
2238bc5531deSDag-Erling Smørgrav 		case 0:
2239bc5531deSDag-Erling Smørgrav 			return "no";
2240bc5531deSDag-Erling Smørgrav 		case 1:
2241bc5531deSDag-Erling Smørgrav 			return "yes";
2242bc5531deSDag-Erling Smørgrav 		default:
2243bc5531deSDag-Erling Smørgrav 			return "UNKNOWN";
2244bc5531deSDag-Erling Smørgrav 		}
2245bc5531deSDag-Erling Smørgrav 	}
2246bc5531deSDag-Erling Smørgrav }
2247bc5531deSDag-Erling Smørgrav 
2248bc5531deSDag-Erling Smørgrav static const char *
2249bc5531deSDag-Erling Smørgrav lookup_opcode_name(OpCodes code)
2250bc5531deSDag-Erling Smørgrav {
2251bc5531deSDag-Erling Smørgrav 	u_int i;
2252bc5531deSDag-Erling Smørgrav 
2253bc5531deSDag-Erling Smørgrav 	for (i = 0; keywords[i].name != NULL; i++)
2254bc5531deSDag-Erling Smørgrav 		if (keywords[i].opcode == code)
2255bc5531deSDag-Erling Smørgrav 			return(keywords[i].name);
2256bc5531deSDag-Erling Smørgrav 	return "UNKNOWN";
2257bc5531deSDag-Erling Smørgrav }
2258bc5531deSDag-Erling Smørgrav 
2259bc5531deSDag-Erling Smørgrav static void
2260bc5531deSDag-Erling Smørgrav dump_cfg_int(OpCodes code, int val)
2261bc5531deSDag-Erling Smørgrav {
2262bc5531deSDag-Erling Smørgrav 	printf("%s %d\n", lookup_opcode_name(code), val);
2263bc5531deSDag-Erling Smørgrav }
2264bc5531deSDag-Erling Smørgrav 
2265bc5531deSDag-Erling Smørgrav static void
2266bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(OpCodes code, int val)
2267bc5531deSDag-Erling Smørgrav {
2268bc5531deSDag-Erling Smørgrav 	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
2269bc5531deSDag-Erling Smørgrav }
2270bc5531deSDag-Erling Smørgrav 
2271bc5531deSDag-Erling Smørgrav static void
2272bc5531deSDag-Erling Smørgrav dump_cfg_string(OpCodes code, const char *val)
2273bc5531deSDag-Erling Smørgrav {
2274bc5531deSDag-Erling Smørgrav 	if (val == NULL)
2275bc5531deSDag-Erling Smørgrav 		return;
2276bc5531deSDag-Erling Smørgrav 	printf("%s %s\n", lookup_opcode_name(code), val);
2277bc5531deSDag-Erling Smørgrav }
2278bc5531deSDag-Erling Smørgrav 
2279bc5531deSDag-Erling Smørgrav static void
2280bc5531deSDag-Erling Smørgrav dump_cfg_strarray(OpCodes code, u_int count, char **vals)
2281bc5531deSDag-Erling Smørgrav {
2282bc5531deSDag-Erling Smørgrav 	u_int i;
2283bc5531deSDag-Erling Smørgrav 
2284bc5531deSDag-Erling Smørgrav 	for (i = 0; i < count; i++)
2285bc5531deSDag-Erling Smørgrav 		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
2286bc5531deSDag-Erling Smørgrav }
2287bc5531deSDag-Erling Smørgrav 
2288bc5531deSDag-Erling Smørgrav static void
2289bc5531deSDag-Erling Smørgrav dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
2290bc5531deSDag-Erling Smørgrav {
2291bc5531deSDag-Erling Smørgrav 	u_int i;
2292bc5531deSDag-Erling Smørgrav 
2293bc5531deSDag-Erling Smørgrav 	printf("%s", lookup_opcode_name(code));
2294bc5531deSDag-Erling Smørgrav 	for (i = 0; i < count; i++)
2295bc5531deSDag-Erling Smørgrav 		printf(" %s",  vals[i]);
2296bc5531deSDag-Erling Smørgrav 	printf("\n");
2297bc5531deSDag-Erling Smørgrav }
2298bc5531deSDag-Erling Smørgrav 
2299bc5531deSDag-Erling Smørgrav static void
2300bc5531deSDag-Erling Smørgrav dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
2301bc5531deSDag-Erling Smørgrav {
2302bc5531deSDag-Erling Smørgrav 	const struct Forward *fwd;
2303bc5531deSDag-Erling Smørgrav 	u_int i;
2304bc5531deSDag-Erling Smørgrav 
2305bc5531deSDag-Erling Smørgrav 	/* oDynamicForward */
2306bc5531deSDag-Erling Smørgrav 	for (i = 0; i < count; i++) {
2307bc5531deSDag-Erling Smørgrav 		fwd = &fwds[i];
2308bc5531deSDag-Erling Smørgrav 		if (code == oDynamicForward &&
2309bc5531deSDag-Erling Smørgrav 		    strcmp(fwd->connect_host, "socks") != 0)
2310bc5531deSDag-Erling Smørgrav 			continue;
2311bc5531deSDag-Erling Smørgrav 		if (code == oLocalForward &&
2312bc5531deSDag-Erling Smørgrav 		    strcmp(fwd->connect_host, "socks") == 0)
2313bc5531deSDag-Erling Smørgrav 			continue;
2314bc5531deSDag-Erling Smørgrav 		printf("%s", lookup_opcode_name(code));
2315bc5531deSDag-Erling Smørgrav 		if (fwd->listen_port == PORT_STREAMLOCAL)
2316bc5531deSDag-Erling Smørgrav 			printf(" %s", fwd->listen_path);
2317bc5531deSDag-Erling Smørgrav 		else if (fwd->listen_host == NULL)
2318bc5531deSDag-Erling Smørgrav 			printf(" %d", fwd->listen_port);
2319bc5531deSDag-Erling Smørgrav 		else {
2320bc5531deSDag-Erling Smørgrav 			printf(" [%s]:%d",
2321bc5531deSDag-Erling Smørgrav 			    fwd->listen_host, fwd->listen_port);
2322bc5531deSDag-Erling Smørgrav 		}
2323bc5531deSDag-Erling Smørgrav 		if (code != oDynamicForward) {
2324bc5531deSDag-Erling Smørgrav 			if (fwd->connect_port == PORT_STREAMLOCAL)
2325bc5531deSDag-Erling Smørgrav 				printf(" %s", fwd->connect_path);
2326bc5531deSDag-Erling Smørgrav 			else if (fwd->connect_host == NULL)
2327bc5531deSDag-Erling Smørgrav 				printf(" %d", fwd->connect_port);
2328bc5531deSDag-Erling Smørgrav 			else {
2329bc5531deSDag-Erling Smørgrav 				printf(" [%s]:%d",
2330bc5531deSDag-Erling Smørgrav 				    fwd->connect_host, fwd->connect_port);
2331bc5531deSDag-Erling Smørgrav 			}
2332bc5531deSDag-Erling Smørgrav 		}
2333bc5531deSDag-Erling Smørgrav 		printf("\n");
2334bc5531deSDag-Erling Smørgrav 	}
2335bc5531deSDag-Erling Smørgrav }
2336bc5531deSDag-Erling Smørgrav 
2337bc5531deSDag-Erling Smørgrav void
2338bc5531deSDag-Erling Smørgrav dump_client_config(Options *o, const char *host)
2339bc5531deSDag-Erling Smørgrav {
2340bc5531deSDag-Erling Smørgrav 	int i;
2341bc5531deSDag-Erling Smørgrav 	char vbuf[5];
2342bc5531deSDag-Erling Smørgrav 
2343*acc1a9efSDag-Erling Smørgrav 	/* This is normally prepared in ssh_kex2 */
2344*acc1a9efSDag-Erling Smørgrav 	if (kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->hostkeyalgorithms) != 0)
2345*acc1a9efSDag-Erling Smørgrav 		fatal("%s: kex_assemble_names failed", __func__);
2346*acc1a9efSDag-Erling Smørgrav 
2347bc5531deSDag-Erling Smørgrav 	/* Most interesting options first: user, host, port */
2348bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oUser, o->user);
2349bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oHostName, host);
2350bc5531deSDag-Erling Smørgrav 	dump_cfg_int(oPort, o->port);
2351bc5531deSDag-Erling Smørgrav 
2352bc5531deSDag-Erling Smørgrav 	/* Flag options */
2353bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oAddressFamily, o->address_family);
2354bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oBatchMode, o->batch_mode);
2355bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
2356bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
2357bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oChallengeResponseAuthentication, o->challenge_response_authentication);
2358bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
2359bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oCompression, o->compression);
2360bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oControlMaster, o->control_master);
2361bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
2362bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
2363bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
2364bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oForwardAgent, o->forward_agent);
2365bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oForwardX11, o->forward_x11);
2366bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
2367bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
2368bc5531deSDag-Erling Smørgrav #ifdef GSSAPI
2369bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
2370bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
2371bc5531deSDag-Erling Smørgrav #endif /* GSSAPI */
2372bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
2373bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
2374bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
2375bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
2376bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
2377bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
2378bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
2379bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oProtocol, o->protocol);
2380bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
2381bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
2382bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oRequestTTY, o->request_tty);
2383bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oRhostsRSAAuthentication, o->rhosts_rsa_authentication);
2384bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oRSAAuthentication, o->rsa_authentication);
2385bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
2386bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
2387bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
2388bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oTunnel, o->tun_open);
2389bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oUsePrivilegedPort, o->use_privileged_port);
2390bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
2391bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
2392bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
2393bc5531deSDag-Erling Smørgrav 
2394bc5531deSDag-Erling Smørgrav 	/* Integer options */
2395bc5531deSDag-Erling Smørgrav 	dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
2396bc5531deSDag-Erling Smørgrav 	dump_cfg_int(oCompressionLevel, o->compression_level);
2397bc5531deSDag-Erling Smørgrav 	dump_cfg_int(oConnectionAttempts, o->connection_attempts);
2398bc5531deSDag-Erling Smørgrav 	dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
2399bc5531deSDag-Erling Smørgrav 	dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
2400bc5531deSDag-Erling Smørgrav 	dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
2401bc5531deSDag-Erling Smørgrav 	dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
2402bc5531deSDag-Erling Smørgrav 
2403bc5531deSDag-Erling Smørgrav 	/* String options */
2404bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oBindAddress, o->bind_address);
2405bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oCiphers, o->ciphers ? o->ciphers : KEX_CLIENT_ENCRYPT);
2406bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oControlPath, o->control_path);
2407*acc1a9efSDag-Erling Smørgrav 	dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
2408bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oHostKeyAlias, o->host_key_alias);
2409bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oHostbasedKeyTypes, o->hostbased_key_types);
2410bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
2411bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX);
2412bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oLocalCommand, o->local_command);
2413bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oLogLevel, log_level_name(o->log_level));
2414bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
2415bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
2416bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
2417bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oProxyCommand, o->proxy_command);
2418*acc1a9efSDag-Erling Smørgrav 	dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types);
2419bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
2420bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oXAuthLocation, o->xauth_location);
2421bc5531deSDag-Erling Smørgrav 
2422bc5531deSDag-Erling Smørgrav 	/* Forwards */
2423bc5531deSDag-Erling Smørgrav 	dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
2424bc5531deSDag-Erling Smørgrav 	dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
2425bc5531deSDag-Erling Smørgrav 	dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
2426bc5531deSDag-Erling Smørgrav 
2427bc5531deSDag-Erling Smørgrav 	/* String array options */
2428bc5531deSDag-Erling Smørgrav 	dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
2429bc5531deSDag-Erling Smørgrav 	dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
2430bc5531deSDag-Erling Smørgrav 	dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
2431bc5531deSDag-Erling Smørgrav 	dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
2432bc5531deSDag-Erling Smørgrav 	dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
2433bc5531deSDag-Erling Smørgrav 
2434bc5531deSDag-Erling Smørgrav 	/* Special cases */
2435bc5531deSDag-Erling Smørgrav 
2436bc5531deSDag-Erling Smørgrav 	/* oConnectTimeout */
2437bc5531deSDag-Erling Smørgrav 	if (o->connection_timeout == -1)
2438bc5531deSDag-Erling Smørgrav 		printf("connecttimeout none\n");
2439bc5531deSDag-Erling Smørgrav 	else
2440bc5531deSDag-Erling Smørgrav 		dump_cfg_int(oConnectTimeout, o->connection_timeout);
2441bc5531deSDag-Erling Smørgrav 
2442bc5531deSDag-Erling Smørgrav 	/* oTunnelDevice */
2443bc5531deSDag-Erling Smørgrav 	printf("tunneldevice");
2444bc5531deSDag-Erling Smørgrav 	if (o->tun_local == SSH_TUNID_ANY)
2445bc5531deSDag-Erling Smørgrav 		printf(" any");
2446bc5531deSDag-Erling Smørgrav 	else
2447bc5531deSDag-Erling Smørgrav 		printf(" %d", o->tun_local);
2448bc5531deSDag-Erling Smørgrav 	if (o->tun_remote == SSH_TUNID_ANY)
2449bc5531deSDag-Erling Smørgrav 		printf(":any");
2450bc5531deSDag-Erling Smørgrav 	else
2451bc5531deSDag-Erling Smørgrav 		printf(":%d", o->tun_remote);
2452bc5531deSDag-Erling Smørgrav 	printf("\n");
2453bc5531deSDag-Erling Smørgrav 
2454bc5531deSDag-Erling Smørgrav 	/* oCanonicalizePermittedCNAMEs */
2455bc5531deSDag-Erling Smørgrav 	if ( o->num_permitted_cnames > 0) {
2456bc5531deSDag-Erling Smørgrav 		printf("canonicalizePermittedcnames");
2457bc5531deSDag-Erling Smørgrav 		for (i = 0; i < o->num_permitted_cnames; i++) {
2458bc5531deSDag-Erling Smørgrav 			printf(" %s:%s", o->permitted_cnames[i].source_list,
2459bc5531deSDag-Erling Smørgrav 			    o->permitted_cnames[i].target_list);
2460bc5531deSDag-Erling Smørgrav 		}
2461bc5531deSDag-Erling Smørgrav 		printf("\n");
2462bc5531deSDag-Erling Smørgrav 	}
2463bc5531deSDag-Erling Smørgrav 
2464bc5531deSDag-Erling Smørgrav 	/* oCipher */
2465bc5531deSDag-Erling Smørgrav 	if (o->cipher != SSH_CIPHER_NOT_SET)
2466bc5531deSDag-Erling Smørgrav 		printf("Cipher %s\n", cipher_name(o->cipher));
2467bc5531deSDag-Erling Smørgrav 
2468bc5531deSDag-Erling Smørgrav 	/* oControlPersist */
2469bc5531deSDag-Erling Smørgrav 	if (o->control_persist == 0 || o->control_persist_timeout == 0)
2470bc5531deSDag-Erling Smørgrav 		dump_cfg_fmtint(oControlPersist, o->control_persist);
2471bc5531deSDag-Erling Smørgrav 	else
2472bc5531deSDag-Erling Smørgrav 		dump_cfg_int(oControlPersist, o->control_persist_timeout);
2473bc5531deSDag-Erling Smørgrav 
2474bc5531deSDag-Erling Smørgrav 	/* oEscapeChar */
2475bc5531deSDag-Erling Smørgrav 	if (o->escape_char == SSH_ESCAPECHAR_NONE)
2476bc5531deSDag-Erling Smørgrav 		printf("escapechar none\n");
2477bc5531deSDag-Erling Smørgrav 	else {
2478bc5531deSDag-Erling Smørgrav 		vis(vbuf, o->escape_char, VIS_WHITE, 0);
2479bc5531deSDag-Erling Smørgrav 		printf("escapechar %s\n", vbuf);
2480bc5531deSDag-Erling Smørgrav 	}
2481bc5531deSDag-Erling Smørgrav 
2482bc5531deSDag-Erling Smørgrav 	/* oIPQoS */
2483bc5531deSDag-Erling Smørgrav 	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
2484bc5531deSDag-Erling Smørgrav 	printf("%s\n", iptos2str(o->ip_qos_bulk));
2485bc5531deSDag-Erling Smørgrav 
2486bc5531deSDag-Erling Smørgrav 	/* oRekeyLimit */
2487*acc1a9efSDag-Erling Smørgrav 	printf("rekeylimit %llu %d\n",
2488*acc1a9efSDag-Erling Smørgrav 	    (unsigned long long)o->rekey_limit, o->rekey_interval);
2489bc5531deSDag-Erling Smørgrav 
2490bc5531deSDag-Erling Smørgrav 	/* oStreamLocalBindMask */
2491bc5531deSDag-Erling Smørgrav 	printf("streamlocalbindmask 0%o\n",
2492bc5531deSDag-Erling Smørgrav 	    o->fwd_opts.streamlocal_bind_mask);
2493bc5531deSDag-Erling Smørgrav }
2494