xref: /freebsd/crypto/openssh/readconf.c (revision 9e14b918f956c532d0b81c945160bd9bc85c5604)
12f513db7SEd Maste /* $OpenBSD: readconf.c,v 1.300 2018/10/05 14:26:09 naddy 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>
1977c2fe20SDag-Erling Smørgrav #ifdef VMWARE_GUEST_WORKAROUND
2077c2fe20SDag-Erling Smørgrav #include <sys/sysctl.h>
2177c2fe20SDag-Erling Smørgrav #endif
22333ee039SDag-Erling Smørgrav #include <sys/stat.h>
23333ee039SDag-Erling Smørgrav #include <sys/socket.h>
24f7167e0eSDag-Erling Smørgrav #include <sys/wait.h>
25a0ee8cc6SDag-Erling Smørgrav #include <sys/un.h>
26333ee039SDag-Erling Smørgrav 
27333ee039SDag-Erling Smørgrav #include <netinet/in.h>
284a421b63SDag-Erling Smørgrav #include <netinet/in_systm.h>
294a421b63SDag-Erling Smørgrav #include <netinet/ip.h>
30b83788ffSDag-Erling Smørgrav #include <arpa/inet.h>
31333ee039SDag-Erling Smørgrav 
32333ee039SDag-Erling Smørgrav #include <ctype.h>
33333ee039SDag-Erling Smørgrav #include <errno.h>
34f7167e0eSDag-Erling Smørgrav #include <fcntl.h>
35bc5531deSDag-Erling Smørgrav #include <limits.h>
36333ee039SDag-Erling Smørgrav #include <netdb.h>
37f7167e0eSDag-Erling Smørgrav #ifdef HAVE_PATHS_H
38f7167e0eSDag-Erling Smørgrav # include <paths.h>
39f7167e0eSDag-Erling Smørgrav #endif
40f7167e0eSDag-Erling Smørgrav #include <pwd.h>
41333ee039SDag-Erling Smørgrav #include <signal.h>
42333ee039SDag-Erling Smørgrav #include <stdarg.h>
43333ee039SDag-Erling Smørgrav #include <stdio.h>
44333ee039SDag-Erling Smørgrav #include <string.h>
45333ee039SDag-Erling Smørgrav #include <unistd.h>
46076ad2f8SDag-Erling Smørgrav #ifdef USE_SYSTEM_GLOB
47076ad2f8SDag-Erling Smørgrav # include <glob.h>
48076ad2f8SDag-Erling Smørgrav #else
49076ad2f8SDag-Erling Smørgrav # include "openbsd-compat/glob.h"
50076ad2f8SDag-Erling Smørgrav #endif
51e4a9863fSDag-Erling Smørgrav #ifdef HAVE_UTIL_H
52e4a9863fSDag-Erling Smørgrav #include <util.h>
53e4a9863fSDag-Erling Smørgrav #endif
54bc5531deSDag-Erling Smørgrav #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
55bc5531deSDag-Erling Smørgrav # include <vis.h>
56bc5531deSDag-Erling Smørgrav #endif
57333ee039SDag-Erling Smørgrav 
58511b41d2SMark Murray #include "xmalloc.h"
59333ee039SDag-Erling Smørgrav #include "ssh.h"
60190cef3dSDag-Erling Smørgrav #include "ssherr.h"
61e8aafc91SKris Kennaway #include "compat.h"
62ca3176e7SBrian Feldman #include "cipher.h"
63ca3176e7SBrian Feldman #include "pathnames.h"
64ca3176e7SBrian Feldman #include "log.h"
65bc5531deSDag-Erling Smørgrav #include "sshkey.h"
66a0ee8cc6SDag-Erling Smørgrav #include "misc.h"
67ca3176e7SBrian Feldman #include "readconf.h"
68ca3176e7SBrian Feldman #include "match.h"
69ca3176e7SBrian Feldman #include "kex.h"
70ca3176e7SBrian Feldman #include "mac.h"
71f7167e0eSDag-Erling Smørgrav #include "uidswap.h"
72bc5531deSDag-Erling Smørgrav #include "myproposal.h"
73bc5531deSDag-Erling Smørgrav #include "digest.h"
74cce7d346SDag-Erling Smørgrav #include "version.h"
75511b41d2SMark Murray 
76511b41d2SMark Murray /* Format of the configuration file:
77511b41d2SMark Murray 
78511b41d2SMark Murray    # Configuration data is parsed as follows:
79511b41d2SMark Murray    #  1. command line options
80511b41d2SMark Murray    #  2. user-specific file
81511b41d2SMark Murray    #  3. system-wide file
82511b41d2SMark Murray    # Any configuration value is only changed the first time it is set.
83511b41d2SMark Murray    # Thus, host-specific definitions should be at the beginning of the
84511b41d2SMark Murray    # configuration file, and defaults at the end.
85511b41d2SMark Murray 
86511b41d2SMark Murray    # Host-specific declarations.  These may override anything above.  A single
87511b41d2SMark Murray    # host may match multiple declarations; these are processed in the order
88511b41d2SMark Murray    # that they are given in.
89511b41d2SMark Murray 
90511b41d2SMark Murray    Host *.ngs.fi ngs.fi
9180628bacSDag-Erling Smørgrav      User foo
92511b41d2SMark Murray 
93511b41d2SMark Murray    Host fake.com
94511b41d2SMark Murray      HostName another.host.name.real.org
95511b41d2SMark Murray      User blaah
96511b41d2SMark Murray      Port 34289
97511b41d2SMark Murray      ForwardX11 no
98511b41d2SMark Murray      ForwardAgent no
99511b41d2SMark Murray 
100511b41d2SMark Murray    Host books.com
101511b41d2SMark Murray      RemoteForward 9999 shadows.cs.hut.fi:9999
102d93a896eSDag-Erling Smørgrav      Ciphers 3des-cbc
103511b41d2SMark Murray 
104511b41d2SMark Murray    Host fascist.blob.com
105511b41d2SMark Murray      Port 23123
106511b41d2SMark Murray      User tylonen
107511b41d2SMark Murray      PasswordAuthentication no
108511b41d2SMark Murray 
109511b41d2SMark Murray    Host puukko.hut.fi
110511b41d2SMark Murray      User t35124p
111511b41d2SMark Murray      ProxyCommand ssh-proxy %h %p
112511b41d2SMark Murray 
113511b41d2SMark Murray    Host *.fr
11480628bacSDag-Erling Smørgrav      PublicKeyAuthentication no
115511b41d2SMark Murray 
116511b41d2SMark Murray    Host *.su
117d93a896eSDag-Erling Smørgrav      Ciphers aes128-ctr
118511b41d2SMark Murray      PasswordAuthentication no
119511b41d2SMark Murray 
120b74df5b2SDag-Erling Smørgrav    Host vpn.fake.com
121b74df5b2SDag-Erling Smørgrav      Tunnel yes
122b74df5b2SDag-Erling Smørgrav      TunnelDevice 3
123b74df5b2SDag-Erling Smørgrav 
124511b41d2SMark Murray    # Defaults for various options
125511b41d2SMark Murray    Host *
126511b41d2SMark Murray      ForwardAgent no
127ca3176e7SBrian Feldman      ForwardX11 no
128511b41d2SMark Murray      PasswordAuthentication yes
129511b41d2SMark Murray      RSAAuthentication yes
130511b41d2SMark Murray      RhostsRSAAuthentication yes
131511b41d2SMark Murray      StrictHostKeyChecking yes
1321ec0d754SDag-Erling Smørgrav      TcpKeepAlive no
133511b41d2SMark Murray      IdentityFile ~/.ssh/identity
134511b41d2SMark Murray      Port 22
135511b41d2SMark Murray      EscapeChar ~
136511b41d2SMark Murray 
137511b41d2SMark Murray */
138511b41d2SMark Murray 
139076ad2f8SDag-Erling Smørgrav static int read_config_file_depth(const char *filename, struct passwd *pw,
140076ad2f8SDag-Erling Smørgrav     const char *host, const char *original_host, Options *options,
141076ad2f8SDag-Erling Smørgrav     int flags, int *activep, int depth);
142076ad2f8SDag-Erling Smørgrav static int process_config_line_depth(Options *options, struct passwd *pw,
143076ad2f8SDag-Erling Smørgrav     const char *host, const char *original_host, char *line,
144076ad2f8SDag-Erling Smørgrav     const char *filename, int linenum, int *activep, int flags, int depth);
145076ad2f8SDag-Erling Smørgrav 
146511b41d2SMark Murray /* Keyword tokens. */
147511b41d2SMark Murray 
148511b41d2SMark Murray typedef enum {
149511b41d2SMark Murray 	oBadOption,
150eccfee6eSDag-Erling Smørgrav 	oVersionAddendum,
151076ad2f8SDag-Erling Smørgrav 	oHost, oMatch, oInclude,
152e2f6069cSDag-Erling Smørgrav 	oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
153e2f6069cSDag-Erling Smørgrav 	oGatewayPorts, oExitOnForwardFailure,
15480628bacSDag-Erling Smørgrav 	oPasswordAuthentication, oRSAAuthentication,
155ca3176e7SBrian Feldman 	oChallengeResponseAuthentication, oXAuthLocation,
156511b41d2SMark Murray 	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
157076ad2f8SDag-Erling Smørgrav 	oCertificateFile, oAddKeysToAgent, oIdentityAgent,
158f7167e0eSDag-Erling Smørgrav 	oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
159511b41d2SMark Murray 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
160511b41d2SMark Murray 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
1611ec0d754SDag-Erling Smørgrav 	oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
1624f52dfbbSDag-Erling Smørgrav 	oUsePrivilegedPort, oLogFacility, oLogLevel, oCiphers, oMacs,
163bc5531deSDag-Erling Smørgrav 	oPubkeyAuthentication,
164ca3176e7SBrian Feldman 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
165ca3176e7SBrian Feldman 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
16647dd1d1bSDag-Erling Smørgrav 	oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider,
1679e2cbe04SDag-Erling Smørgrav 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
168cf2b5f3bSDag-Erling Smørgrav 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
169cf2b5f3bSDag-Erling Smørgrav 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
1705962c0e9SDag-Erling Smørgrav 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
171190cef3dSDag-Erling Smørgrav 	oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
172e2f6069cSDag-Erling Smørgrav 	oHashKnownHosts,
1734f52dfbbSDag-Erling Smørgrav 	oTunnel, oTunnelDevice,
1744f52dfbbSDag-Erling Smørgrav 	oLocalCommand, oPermitLocalCommand, oRemoteCommand,
175acc1a9efSDag-Erling Smørgrav 	oVisualHostKey,
176f7167e0eSDag-Erling Smørgrav 	oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
177f7167e0eSDag-Erling Smørgrav 	oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
178f7167e0eSDag-Erling Smørgrav 	oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
179bc5531deSDag-Erling Smørgrav 	oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
180bc5531deSDag-Erling Smørgrav 	oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
1812f513db7SEd Maste 	oPubkeyAcceptedKeyTypes, oCASignatureAlgorithms, oProxyJump,
1824f52dfbbSDag-Erling Smørgrav 	oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
183511b41d2SMark Murray } OpCodes;
184511b41d2SMark Murray 
185511b41d2SMark Murray /* Textual representations of the tokens. */
186511b41d2SMark Murray 
187511b41d2SMark Murray static struct {
188511b41d2SMark Murray 	const char *name;
189511b41d2SMark Murray 	OpCodes opcode;
190511b41d2SMark Murray } keywords[] = {
191d93a896eSDag-Erling Smørgrav 	/* Deprecated options */
1924f52dfbbSDag-Erling Smørgrav 	{ "protocol", oIgnore }, /* NB. silently ignored */
1934f52dfbbSDag-Erling Smørgrav 	{ "cipher", oDeprecated },
194d93a896eSDag-Erling Smørgrav 	{ "fallbacktorsh", oDeprecated },
195d93a896eSDag-Erling Smørgrav 	{ "globalknownhostsfile2", oDeprecated },
196d93a896eSDag-Erling Smørgrav 	{ "rhostsauthentication", oDeprecated },
197d93a896eSDag-Erling Smørgrav 	{ "userknownhostsfile2", oDeprecated },
198d93a896eSDag-Erling Smørgrav 	{ "useroaming", oDeprecated },
199d93a896eSDag-Erling Smørgrav 	{ "usersh", oDeprecated },
200190cef3dSDag-Erling Smørgrav 	{ "useprivilegedport", oDeprecated },
201d93a896eSDag-Erling Smørgrav 
202d93a896eSDag-Erling Smørgrav 	/* Unsupported options */
203d93a896eSDag-Erling Smørgrav 	{ "afstokenpassing", oUnsupported },
204d93a896eSDag-Erling Smørgrav 	{ "kerberosauthentication", oUnsupported },
205d93a896eSDag-Erling Smørgrav 	{ "kerberostgtpassing", oUnsupported },
206d93a896eSDag-Erling Smørgrav 
207d93a896eSDag-Erling Smørgrav 	/* Sometimes-unsupported options */
208d93a896eSDag-Erling Smørgrav #if defined(GSSAPI)
209d93a896eSDag-Erling Smørgrav 	{ "gssapiauthentication", oGssAuthentication },
210d93a896eSDag-Erling Smørgrav 	{ "gssapidelegatecredentials", oGssDelegateCreds },
211d93a896eSDag-Erling Smørgrav # else
212d93a896eSDag-Erling Smørgrav 	{ "gssapiauthentication", oUnsupported },
213d93a896eSDag-Erling Smørgrav 	{ "gssapidelegatecredentials", oUnsupported },
214d93a896eSDag-Erling Smørgrav #endif
215d93a896eSDag-Erling Smørgrav #ifdef ENABLE_PKCS11
216d93a896eSDag-Erling Smørgrav 	{ "smartcarddevice", oPKCS11Provider },
217d93a896eSDag-Erling Smørgrav 	{ "pkcs11provider", oPKCS11Provider },
218d93a896eSDag-Erling Smørgrav # else
219d93a896eSDag-Erling Smørgrav 	{ "smartcarddevice", oUnsupported },
220d93a896eSDag-Erling Smørgrav 	{ "pkcs11provider", oUnsupported },
221d93a896eSDag-Erling Smørgrav #endif
222d93a896eSDag-Erling Smørgrav 	{ "rsaauthentication", oUnsupported },
223d93a896eSDag-Erling Smørgrav 	{ "rhostsrsaauthentication", oUnsupported },
224d93a896eSDag-Erling Smørgrav 	{ "compressionlevel", oUnsupported },
225d93a896eSDag-Erling Smørgrav 
226511b41d2SMark Murray 	{ "forwardagent", oForwardAgent },
227511b41d2SMark Murray 	{ "forwardx11", oForwardX11 },
2281ec0d754SDag-Erling Smørgrav 	{ "forwardx11trusted", oForwardX11Trusted },
229e2f6069cSDag-Erling Smørgrav 	{ "forwardx11timeout", oForwardX11Timeout },
230333ee039SDag-Erling Smørgrav 	{ "exitonforwardfailure", oExitOnForwardFailure },
231c2d3a559SKris Kennaway 	{ "xauthlocation", oXAuthLocation },
232511b41d2SMark Murray 	{ "gatewayports", oGatewayPorts },
233511b41d2SMark Murray 	{ "passwordauthentication", oPasswordAuthentication },
23409958426SBrian Feldman 	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
23509958426SBrian Feldman 	{ "kbdinteractivedevices", oKbdInteractiveDevices },
236ca3176e7SBrian Feldman 	{ "pubkeyauthentication", oPubkeyAuthentication },
237ca3176e7SBrian Feldman 	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
238ca3176e7SBrian Feldman 	{ "hostbasedauthentication", oHostbasedAuthentication },
239ca3176e7SBrian Feldman 	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
240190cef3dSDag-Erling Smørgrav 	{ "skeyauthentication", oUnsupported },
241ca3176e7SBrian Feldman 	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
242511b41d2SMark Murray 	{ "identityfile", oIdentityFile },
243cce7d346SDag-Erling Smørgrav 	{ "identityfile2", oIdentityFile },			/* obsolete */
2445962c0e9SDag-Erling Smørgrav 	{ "identitiesonly", oIdentitiesOnly },
245acc1a9efSDag-Erling Smørgrav 	{ "certificatefile", oCertificateFile },
246acc1a9efSDag-Erling Smørgrav 	{ "addkeystoagent", oAddKeysToAgent },
247076ad2f8SDag-Erling Smørgrav 	{ "identityagent", oIdentityAgent },
248511b41d2SMark Murray 	{ "hostname", oHostName },
249ca3176e7SBrian Feldman 	{ "hostkeyalias", oHostKeyAlias },
250511b41d2SMark Murray 	{ "proxycommand", oProxyCommand },
251511b41d2SMark Murray 	{ "port", oPort },
252e8aafc91SKris Kennaway 	{ "ciphers", oCiphers },
253ca3176e7SBrian Feldman 	{ "macs", oMacs },
254511b41d2SMark Murray 	{ "remoteforward", oRemoteForward },
255511b41d2SMark Murray 	{ "localforward", oLocalForward },
256511b41d2SMark Murray 	{ "user", oUser },
257511b41d2SMark Murray 	{ "host", oHost },
258f7167e0eSDag-Erling Smørgrav 	{ "match", oMatch },
259511b41d2SMark Murray 	{ "escapechar", oEscapeChar },
260511b41d2SMark Murray 	{ "globalknownhostsfile", oGlobalKnownHostsFile },
261cce7d346SDag-Erling Smørgrav 	{ "userknownhostsfile", oUserKnownHostsFile },
262511b41d2SMark Murray 	{ "connectionattempts", oConnectionAttempts },
263511b41d2SMark Murray 	{ "batchmode", oBatchMode },
264511b41d2SMark Murray 	{ "checkhostip", oCheckHostIP },
265511b41d2SMark Murray 	{ "stricthostkeychecking", oStrictHostKeyChecking },
266511b41d2SMark Murray 	{ "compression", oCompression },
2671ec0d754SDag-Erling Smørgrav 	{ "tcpkeepalive", oTCPKeepAlive },
2681ec0d754SDag-Erling Smørgrav 	{ "keepalive", oTCPKeepAlive },				/* obsolete */
269511b41d2SMark Murray 	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
2704f52dfbbSDag-Erling Smørgrav 	{ "syslogfacility", oLogFacility },
271511b41d2SMark Murray 	{ "loglevel", oLogLevel },
272ca3176e7SBrian Feldman 	{ "dynamicforward", oDynamicForward },
273ca3176e7SBrian Feldman 	{ "preferredauthentications", oPreferredAuthentications },
274ca3176e7SBrian Feldman 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
2752f513db7SEd Maste 	{ "casignaturealgorithms", oCASignatureAlgorithms },
276af12a3e7SDag-Erling Smørgrav 	{ "bindaddress", oBindAddress },
27747dd1d1bSDag-Erling Smørgrav 	{ "bindinterface", oBindInterface },
278af12a3e7SDag-Erling Smørgrav 	{ "clearallforwardings", oClearAllForwardings },
279e73e9afaSDag-Erling Smørgrav 	{ "enablesshkeysign", oEnableSSHKeysign },
280cf2b5f3bSDag-Erling Smørgrav 	{ "verifyhostkeydns", oVerifyHostKeyDNS },
281af12a3e7SDag-Erling Smørgrav 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
282cf2b5f3bSDag-Erling Smørgrav 	{ "rekeylimit", oRekeyLimit },
283cf2b5f3bSDag-Erling Smørgrav 	{ "connecttimeout", oConnectTimeout },
284cf2b5f3bSDag-Erling Smørgrav 	{ "addressfamily", oAddressFamily },
2851ec0d754SDag-Erling Smørgrav 	{ "serveraliveinterval", oServerAliveInterval },
2861ec0d754SDag-Erling Smørgrav 	{ "serveralivecountmax", oServerAliveCountMax },
28721e764dfSDag-Erling Smørgrav 	{ "sendenv", oSendEnv },
288190cef3dSDag-Erling Smørgrav 	{ "setenv", oSetEnv },
28921e764dfSDag-Erling Smørgrav 	{ "controlpath", oControlPath },
29021e764dfSDag-Erling Smørgrav 	{ "controlmaster", oControlMaster },
291e2f6069cSDag-Erling Smørgrav 	{ "controlpersist", oControlPersist },
292aa49c926SDag-Erling Smørgrav 	{ "hashknownhosts", oHashKnownHosts },
293076ad2f8SDag-Erling Smørgrav 	{ "include", oInclude },
294b74df5b2SDag-Erling Smørgrav 	{ "tunnel", oTunnel },
295b74df5b2SDag-Erling Smørgrav 	{ "tunneldevice", oTunnelDevice },
296b74df5b2SDag-Erling Smørgrav 	{ "localcommand", oLocalCommand },
297b74df5b2SDag-Erling Smørgrav 	{ "permitlocalcommand", oPermitLocalCommand },
2984f52dfbbSDag-Erling Smørgrav 	{ "remotecommand", oRemoteCommand },
299d4af9e69SDag-Erling Smørgrav 	{ "visualhostkey", oVisualHostKey },
3004a421b63SDag-Erling Smørgrav 	{ "kexalgorithms", oKexAlgorithms },
3014a421b63SDag-Erling Smørgrav 	{ "ipqos", oIPQoS },
302e146993eSDag-Erling Smørgrav 	{ "requesttty", oRequestTTY },
303f7167e0eSDag-Erling Smørgrav 	{ "proxyusefdpass", oProxyUseFdpass },
304f7167e0eSDag-Erling Smørgrav 	{ "canonicaldomains", oCanonicalDomains },
305f7167e0eSDag-Erling Smørgrav 	{ "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
306f7167e0eSDag-Erling Smørgrav 	{ "canonicalizehostname", oCanonicalizeHostname },
307f7167e0eSDag-Erling Smørgrav 	{ "canonicalizemaxdots", oCanonicalizeMaxDots },
308f7167e0eSDag-Erling Smørgrav 	{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
309a0ee8cc6SDag-Erling Smørgrav 	{ "streamlocalbindmask", oStreamLocalBindMask },
310a0ee8cc6SDag-Erling Smørgrav 	{ "streamlocalbindunlink", oStreamLocalBindUnlink },
311bc5531deSDag-Erling Smørgrav 	{ "revokedhostkeys", oRevokedHostKeys },
312bc5531deSDag-Erling Smørgrav 	{ "fingerprinthash", oFingerprintHash },
313bc5531deSDag-Erling Smørgrav 	{ "updatehostkeys", oUpdateHostkeys },
314bc5531deSDag-Erling Smørgrav 	{ "hostbasedkeytypes", oHostbasedKeyTypes },
315eccfee6eSDag-Erling Smørgrav 	{ "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
316e4a9863fSDag-Erling Smørgrav 	{ "ignoreunknown", oIgnoreUnknown },
317076ad2f8SDag-Erling Smørgrav 	{ "proxyjump", oProxyJump },
318076ad2f8SDag-Erling Smørgrav 
3199860d96eSDag-Erling Smørgrav 	{ "hpndisabled", oDeprecated },
3209860d96eSDag-Erling Smørgrav 	{ "hpnbuffersize", oDeprecated },
3219860d96eSDag-Erling Smørgrav 	{ "tcprcvbufpoll", oDeprecated },
3229860d96eSDag-Erling Smørgrav 	{ "tcprcvbuf", oDeprecated },
32363620802SDag-Erling Smørgrav 	{ "noneenabled", oUnsupported },
32463620802SDag-Erling Smørgrav 	{ "noneswitch", oUnsupported },
325975616f0SDag-Erling Smørgrav 	{ "versionaddendum", oVersionAddendum },
32635762f59SEd Schouten 
327af12a3e7SDag-Erling Smørgrav 	{ NULL, oBadOption }
328511b41d2SMark Murray };
329511b41d2SMark Murray 
330511b41d2SMark Murray /*
331511b41d2SMark Murray  * Adds a local TCP/IP port forward to options.  Never returns if there is an
332511b41d2SMark Murray  * error.
333511b41d2SMark Murray  */
334511b41d2SMark Murray 
335511b41d2SMark Murray void
336a0ee8cc6SDag-Erling Smørgrav add_local_forward(Options *options, const struct Forward *newfwd)
337511b41d2SMark Murray {
338a0ee8cc6SDag-Erling Smørgrav 	struct Forward *fwd;
339*9e14b918SEd Maste 	int i;
34003f6c5cdSDag-Erling Smørgrav 
341076ad2f8SDag-Erling Smørgrav 	/* Don't add duplicates */
342076ad2f8SDag-Erling Smørgrav 	for (i = 0; i < options->num_local_forwards; i++) {
343076ad2f8SDag-Erling Smørgrav 		if (forward_equals(newfwd, options->local_forwards + i))
344076ad2f8SDag-Erling Smørgrav 			return;
345076ad2f8SDag-Erling Smørgrav 	}
346557f75e5SDag-Erling Smørgrav 	options->local_forwards = xreallocarray(options->local_forwards,
347e2f6069cSDag-Erling Smørgrav 	    options->num_local_forwards + 1,
348e2f6069cSDag-Erling Smørgrav 	    sizeof(*options->local_forwards));
349511b41d2SMark Murray 	fwd = &options->local_forwards[options->num_local_forwards++];
350aa49c926SDag-Erling Smørgrav 
351cce7d346SDag-Erling Smørgrav 	fwd->listen_host = newfwd->listen_host;
352aa49c926SDag-Erling Smørgrav 	fwd->listen_port = newfwd->listen_port;
353a0ee8cc6SDag-Erling Smørgrav 	fwd->listen_path = newfwd->listen_path;
354cce7d346SDag-Erling Smørgrav 	fwd->connect_host = newfwd->connect_host;
355aa49c926SDag-Erling Smørgrav 	fwd->connect_port = newfwd->connect_port;
356a0ee8cc6SDag-Erling Smørgrav 	fwd->connect_path = newfwd->connect_path;
357511b41d2SMark Murray }
358511b41d2SMark Murray 
359511b41d2SMark Murray /*
360511b41d2SMark Murray  * Adds a remote TCP/IP port forward to options.  Never returns if there is
361511b41d2SMark Murray  * an error.
362511b41d2SMark Murray  */
363511b41d2SMark Murray 
364511b41d2SMark Murray void
365a0ee8cc6SDag-Erling Smørgrav add_remote_forward(Options *options, const struct Forward *newfwd)
366511b41d2SMark Murray {
367a0ee8cc6SDag-Erling Smørgrav 	struct Forward *fwd;
368076ad2f8SDag-Erling Smørgrav 	int i;
369e2f6069cSDag-Erling Smørgrav 
370076ad2f8SDag-Erling Smørgrav 	/* Don't add duplicates */
371076ad2f8SDag-Erling Smørgrav 	for (i = 0; i < options->num_remote_forwards; i++) {
372076ad2f8SDag-Erling Smørgrav 		if (forward_equals(newfwd, options->remote_forwards + i))
373076ad2f8SDag-Erling Smørgrav 			return;
374076ad2f8SDag-Erling Smørgrav 	}
375557f75e5SDag-Erling Smørgrav 	options->remote_forwards = xreallocarray(options->remote_forwards,
376e2f6069cSDag-Erling Smørgrav 	    options->num_remote_forwards + 1,
377e2f6069cSDag-Erling Smørgrav 	    sizeof(*options->remote_forwards));
378511b41d2SMark Murray 	fwd = &options->remote_forwards[options->num_remote_forwards++];
379aa49c926SDag-Erling Smørgrav 
380cce7d346SDag-Erling Smørgrav 	fwd->listen_host = newfwd->listen_host;
381aa49c926SDag-Erling Smørgrav 	fwd->listen_port = newfwd->listen_port;
382a0ee8cc6SDag-Erling Smørgrav 	fwd->listen_path = newfwd->listen_path;
383cce7d346SDag-Erling Smørgrav 	fwd->connect_host = newfwd->connect_host;
384aa49c926SDag-Erling Smørgrav 	fwd->connect_port = newfwd->connect_port;
385a0ee8cc6SDag-Erling Smørgrav 	fwd->connect_path = newfwd->connect_path;
386462c32cbSDag-Erling Smørgrav 	fwd->handle = newfwd->handle;
387e2f6069cSDag-Erling Smørgrav 	fwd->allocated_port = 0;
388511b41d2SMark Murray }
389511b41d2SMark Murray 
390af12a3e7SDag-Erling Smørgrav static void
391af12a3e7SDag-Erling Smørgrav clear_forwardings(Options *options)
392af12a3e7SDag-Erling Smørgrav {
393af12a3e7SDag-Erling Smørgrav 	int i;
394af12a3e7SDag-Erling Smørgrav 
395aa49c926SDag-Erling Smørgrav 	for (i = 0; i < options->num_local_forwards; i++) {
396e4a9863fSDag-Erling Smørgrav 		free(options->local_forwards[i].listen_host);
397a0ee8cc6SDag-Erling Smørgrav 		free(options->local_forwards[i].listen_path);
398e4a9863fSDag-Erling Smørgrav 		free(options->local_forwards[i].connect_host);
399a0ee8cc6SDag-Erling Smørgrav 		free(options->local_forwards[i].connect_path);
400aa49c926SDag-Erling Smørgrav 	}
401e2f6069cSDag-Erling Smørgrav 	if (options->num_local_forwards > 0) {
402e4a9863fSDag-Erling Smørgrav 		free(options->local_forwards);
403e2f6069cSDag-Erling Smørgrav 		options->local_forwards = NULL;
404e2f6069cSDag-Erling Smørgrav 	}
405af12a3e7SDag-Erling Smørgrav 	options->num_local_forwards = 0;
406aa49c926SDag-Erling Smørgrav 	for (i = 0; i < options->num_remote_forwards; i++) {
407e4a9863fSDag-Erling Smørgrav 		free(options->remote_forwards[i].listen_host);
408a0ee8cc6SDag-Erling Smørgrav 		free(options->remote_forwards[i].listen_path);
409e4a9863fSDag-Erling Smørgrav 		free(options->remote_forwards[i].connect_host);
410a0ee8cc6SDag-Erling Smørgrav 		free(options->remote_forwards[i].connect_path);
411aa49c926SDag-Erling Smørgrav 	}
412e2f6069cSDag-Erling Smørgrav 	if (options->num_remote_forwards > 0) {
413e4a9863fSDag-Erling Smørgrav 		free(options->remote_forwards);
414e2f6069cSDag-Erling Smørgrav 		options->remote_forwards = NULL;
415e2f6069cSDag-Erling Smørgrav 	}
416af12a3e7SDag-Erling Smørgrav 	options->num_remote_forwards = 0;
417b74df5b2SDag-Erling Smørgrav 	options->tun_open = SSH_TUNMODE_NO;
418af12a3e7SDag-Erling Smørgrav }
419af12a3e7SDag-Erling Smørgrav 
420fa67e83cSDag-Erling Smørgrav void
421acc1a9efSDag-Erling Smørgrav add_certificate_file(Options *options, const char *path, int userprovided)
422acc1a9efSDag-Erling Smørgrav {
423acc1a9efSDag-Erling Smørgrav 	int i;
424acc1a9efSDag-Erling Smørgrav 
425acc1a9efSDag-Erling Smørgrav 	if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
426acc1a9efSDag-Erling Smørgrav 		fatal("Too many certificate files specified (max %d)",
427acc1a9efSDag-Erling Smørgrav 		    SSH_MAX_CERTIFICATE_FILES);
428acc1a9efSDag-Erling Smørgrav 
429acc1a9efSDag-Erling Smørgrav 	/* Avoid registering duplicates */
430acc1a9efSDag-Erling Smørgrav 	for (i = 0; i < options->num_certificate_files; i++) {
431acc1a9efSDag-Erling Smørgrav 		if (options->certificate_file_userprovided[i] == userprovided &&
432acc1a9efSDag-Erling Smørgrav 		    strcmp(options->certificate_files[i], path) == 0) {
433acc1a9efSDag-Erling Smørgrav 			debug2("%s: ignoring duplicate key %s", __func__, path);
434acc1a9efSDag-Erling Smørgrav 			return;
435acc1a9efSDag-Erling Smørgrav 		}
436acc1a9efSDag-Erling Smørgrav 	}
437acc1a9efSDag-Erling Smørgrav 
438acc1a9efSDag-Erling Smørgrav 	options->certificate_file_userprovided[options->num_certificate_files] =
439acc1a9efSDag-Erling Smørgrav 	    userprovided;
440acc1a9efSDag-Erling Smørgrav 	options->certificate_files[options->num_certificate_files++] =
441acc1a9efSDag-Erling Smørgrav 	    xstrdup(path);
442acc1a9efSDag-Erling Smørgrav }
443acc1a9efSDag-Erling Smørgrav 
444acc1a9efSDag-Erling Smørgrav void
445fa67e83cSDag-Erling Smørgrav add_identity_file(Options *options, const char *dir, const char *filename,
446fa67e83cSDag-Erling Smørgrav     int userprovided)
447fa67e83cSDag-Erling Smørgrav {
448fa67e83cSDag-Erling Smørgrav 	char *path;
449a0ee8cc6SDag-Erling Smørgrav 	int i;
450fa67e83cSDag-Erling Smørgrav 
451fa67e83cSDag-Erling Smørgrav 	if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
452fa67e83cSDag-Erling Smørgrav 		fatal("Too many identity files specified (max %d)",
453fa67e83cSDag-Erling Smørgrav 		    SSH_MAX_IDENTITY_FILES);
454fa67e83cSDag-Erling Smørgrav 
455fa67e83cSDag-Erling Smørgrav 	if (dir == NULL) /* no dir, filename is absolute */
456fa67e83cSDag-Erling Smørgrav 		path = xstrdup(filename);
4574f52dfbbSDag-Erling Smørgrav 	else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX)
4584f52dfbbSDag-Erling Smørgrav 		fatal("Identity file path %s too long", path);
459fa67e83cSDag-Erling Smørgrav 
460a0ee8cc6SDag-Erling Smørgrav 	/* Avoid registering duplicates */
461a0ee8cc6SDag-Erling Smørgrav 	for (i = 0; i < options->num_identity_files; i++) {
462a0ee8cc6SDag-Erling Smørgrav 		if (options->identity_file_userprovided[i] == userprovided &&
463a0ee8cc6SDag-Erling Smørgrav 		    strcmp(options->identity_files[i], path) == 0) {
464a0ee8cc6SDag-Erling Smørgrav 			debug2("%s: ignoring duplicate key %s", __func__, path);
465a0ee8cc6SDag-Erling Smørgrav 			free(path);
466a0ee8cc6SDag-Erling Smørgrav 			return;
467a0ee8cc6SDag-Erling Smørgrav 		}
468a0ee8cc6SDag-Erling Smørgrav 	}
469a0ee8cc6SDag-Erling Smørgrav 
470fa67e83cSDag-Erling Smørgrav 	options->identity_file_userprovided[options->num_identity_files] =
471fa67e83cSDag-Erling Smørgrav 	    userprovided;
472fa67e83cSDag-Erling Smørgrav 	options->identity_files[options->num_identity_files++] = path;
473fa67e83cSDag-Erling Smørgrav }
474fa67e83cSDag-Erling Smørgrav 
475f7167e0eSDag-Erling Smørgrav int
476f7167e0eSDag-Erling Smørgrav default_ssh_port(void)
477f7167e0eSDag-Erling Smørgrav {
478f7167e0eSDag-Erling Smørgrav 	static int port;
479f7167e0eSDag-Erling Smørgrav 	struct servent *sp;
480f7167e0eSDag-Erling Smørgrav 
481f7167e0eSDag-Erling Smørgrav 	if (port == 0) {
482f7167e0eSDag-Erling Smørgrav 		sp = getservbyname(SSH_SERVICE_NAME, "tcp");
483f7167e0eSDag-Erling Smørgrav 		port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
484f7167e0eSDag-Erling Smørgrav 	}
485f7167e0eSDag-Erling Smørgrav 	return port;
486f7167e0eSDag-Erling Smørgrav }
487f7167e0eSDag-Erling Smørgrav 
488f7167e0eSDag-Erling Smørgrav /*
489f7167e0eSDag-Erling Smørgrav  * Execute a command in a shell.
490f7167e0eSDag-Erling Smørgrav  * Return its exit status or -1 on abnormal exit.
491f7167e0eSDag-Erling Smørgrav  */
492f7167e0eSDag-Erling Smørgrav static int
493f7167e0eSDag-Erling Smørgrav execute_in_shell(const char *cmd)
494f7167e0eSDag-Erling Smørgrav {
495acc1a9efSDag-Erling Smørgrav 	char *shell;
496f7167e0eSDag-Erling Smørgrav 	pid_t pid;
497f7167e0eSDag-Erling Smørgrav 	int devnull, status;
498f7167e0eSDag-Erling Smørgrav 
499f7167e0eSDag-Erling Smørgrav 	if ((shell = getenv("SHELL")) == NULL)
500f7167e0eSDag-Erling Smørgrav 		shell = _PATH_BSHELL;
501f7167e0eSDag-Erling Smørgrav 
502f7167e0eSDag-Erling Smørgrav 	/* Need this to redirect subprocess stdin/out */
503f7167e0eSDag-Erling Smørgrav 	if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
504f7167e0eSDag-Erling Smørgrav 		fatal("open(/dev/null): %s", strerror(errno));
505f7167e0eSDag-Erling Smørgrav 
506f7167e0eSDag-Erling Smørgrav 	debug("Executing command: '%.500s'", cmd);
507f7167e0eSDag-Erling Smørgrav 
508f7167e0eSDag-Erling Smørgrav 	/* Fork and execute the command. */
509f7167e0eSDag-Erling Smørgrav 	if ((pid = fork()) == 0) {
510f7167e0eSDag-Erling Smørgrav 		char *argv[4];
511f7167e0eSDag-Erling Smørgrav 
512f7167e0eSDag-Erling Smørgrav 		/* Redirect child stdin and stdout. Leave stderr */
513f7167e0eSDag-Erling Smørgrav 		if (dup2(devnull, STDIN_FILENO) == -1)
514f7167e0eSDag-Erling Smørgrav 			fatal("dup2: %s", strerror(errno));
515f7167e0eSDag-Erling Smørgrav 		if (dup2(devnull, STDOUT_FILENO) == -1)
516f7167e0eSDag-Erling Smørgrav 			fatal("dup2: %s", strerror(errno));
517f7167e0eSDag-Erling Smørgrav 		if (devnull > STDERR_FILENO)
518f7167e0eSDag-Erling Smørgrav 			close(devnull);
519f7167e0eSDag-Erling Smørgrav 		closefrom(STDERR_FILENO + 1);
520f7167e0eSDag-Erling Smørgrav 
521f7167e0eSDag-Erling Smørgrav 		argv[0] = shell;
522f7167e0eSDag-Erling Smørgrav 		argv[1] = "-c";
523acc1a9efSDag-Erling Smørgrav 		argv[2] = xstrdup(cmd);
524f7167e0eSDag-Erling Smørgrav 		argv[3] = NULL;
525f7167e0eSDag-Erling Smørgrav 
526f7167e0eSDag-Erling Smørgrav 		execv(argv[0], argv);
527f7167e0eSDag-Erling Smørgrav 		error("Unable to execute '%.100s': %s", cmd, strerror(errno));
528f7167e0eSDag-Erling Smørgrav 		/* Die with signal to make this error apparent to parent. */
529f7167e0eSDag-Erling Smørgrav 		signal(SIGTERM, SIG_DFL);
530f7167e0eSDag-Erling Smørgrav 		kill(getpid(), SIGTERM);
531f7167e0eSDag-Erling Smørgrav 		_exit(1);
532f7167e0eSDag-Erling Smørgrav 	}
533f7167e0eSDag-Erling Smørgrav 	/* Parent. */
534f7167e0eSDag-Erling Smørgrav 	if (pid < 0)
535f7167e0eSDag-Erling Smørgrav 		fatal("%s: fork: %.100s", __func__, strerror(errno));
536f7167e0eSDag-Erling Smørgrav 
537f7167e0eSDag-Erling Smørgrav 	close(devnull);
538f7167e0eSDag-Erling Smørgrav 
539f7167e0eSDag-Erling Smørgrav 	while (waitpid(pid, &status, 0) == -1) {
540f7167e0eSDag-Erling Smørgrav 		if (errno != EINTR && errno != EAGAIN)
541f7167e0eSDag-Erling Smørgrav 			fatal("%s: waitpid: %s", __func__, strerror(errno));
542f7167e0eSDag-Erling Smørgrav 	}
543f7167e0eSDag-Erling Smørgrav 	if (!WIFEXITED(status)) {
544f7167e0eSDag-Erling Smørgrav 		error("command '%.100s' exited abnormally", cmd);
545f7167e0eSDag-Erling Smørgrav 		return -1;
546f7167e0eSDag-Erling Smørgrav 	}
547f7167e0eSDag-Erling Smørgrav 	debug3("command returned status %d", WEXITSTATUS(status));
548f7167e0eSDag-Erling Smørgrav 	return WEXITSTATUS(status);
549f7167e0eSDag-Erling Smørgrav }
550f7167e0eSDag-Erling Smørgrav 
551f7167e0eSDag-Erling Smørgrav /*
552f7167e0eSDag-Erling Smørgrav  * Parse and execute a Match directive.
553f7167e0eSDag-Erling Smørgrav  */
554f7167e0eSDag-Erling Smørgrav static int
555f7167e0eSDag-Erling Smørgrav match_cfg_line(Options *options, char **condition, struct passwd *pw,
556bc5531deSDag-Erling Smørgrav     const char *host_arg, const char *original_host, int post_canon,
557bc5531deSDag-Erling Smørgrav     const char *filename, int linenum)
558f7167e0eSDag-Erling Smørgrav {
559bc5531deSDag-Erling Smørgrav 	char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
560f7167e0eSDag-Erling Smørgrav 	const char *ruser;
561bc5531deSDag-Erling Smørgrav 	int r, port, this_result, result = 1, attributes = 0, negate;
562f7167e0eSDag-Erling Smørgrav 	char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
563190cef3dSDag-Erling Smørgrav 	char uidstr[32];
564f7167e0eSDag-Erling Smørgrav 
565f7167e0eSDag-Erling Smørgrav 	/*
566f7167e0eSDag-Erling Smørgrav 	 * Configuration is likely to be incomplete at this point so we
567f7167e0eSDag-Erling Smørgrav 	 * must be prepared to use default values.
568f7167e0eSDag-Erling Smørgrav 	 */
569f7167e0eSDag-Erling Smørgrav 	port = options->port <= 0 ? default_ssh_port() : options->port;
570f7167e0eSDag-Erling Smørgrav 	ruser = options->user == NULL ? pw->pw_name : options->user;
571acc1a9efSDag-Erling Smørgrav 	if (post_canon) {
572acc1a9efSDag-Erling Smørgrav 		host = xstrdup(options->hostname);
573acc1a9efSDag-Erling Smørgrav 	} else if (options->hostname != NULL) {
574f7167e0eSDag-Erling Smørgrav 		/* NB. Please keep in sync with ssh.c:main() */
575f7167e0eSDag-Erling Smørgrav 		host = percent_expand(options->hostname,
576f7167e0eSDag-Erling Smørgrav 		    "h", host_arg, (char *)NULL);
577acc1a9efSDag-Erling Smørgrav 	} else {
578f7167e0eSDag-Erling Smørgrav 		host = xstrdup(host_arg);
579acc1a9efSDag-Erling Smørgrav 	}
580f7167e0eSDag-Erling Smørgrav 
581bc5531deSDag-Erling Smørgrav 	debug2("checking match for '%s' host %s originally %s",
582bc5531deSDag-Erling Smørgrav 	    cp, host, original_host);
583bc5531deSDag-Erling Smørgrav 	while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
584bc5531deSDag-Erling Smørgrav 		criteria = NULL;
585bc5531deSDag-Erling Smørgrav 		this_result = 1;
586bc5531deSDag-Erling Smørgrav 		if ((negate = attrib[0] == '!'))
587bc5531deSDag-Erling Smørgrav 			attrib++;
588bc5531deSDag-Erling Smørgrav 		/* criteria "all" and "canonical" have no argument */
589f7167e0eSDag-Erling Smørgrav 		if (strcasecmp(attrib, "all") == 0) {
590bc5531deSDag-Erling Smørgrav 			if (attributes > 1 ||
591f7167e0eSDag-Erling Smørgrav 			    ((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
592bc5531deSDag-Erling Smørgrav 				error("%.200s line %d: '%s' cannot be combined "
593bc5531deSDag-Erling Smørgrav 				    "with other Match attributes",
594bc5531deSDag-Erling Smørgrav 				    filename, linenum, oattrib);
595f7167e0eSDag-Erling Smørgrav 				result = -1;
596f7167e0eSDag-Erling Smørgrav 				goto out;
597f7167e0eSDag-Erling Smørgrav 			}
598bc5531deSDag-Erling Smørgrav 			if (result)
599bc5531deSDag-Erling Smørgrav 				result = negate ? 0 : 1;
600f7167e0eSDag-Erling Smørgrav 			goto out;
601f7167e0eSDag-Erling Smørgrav 		}
602bc5531deSDag-Erling Smørgrav 		attributes++;
603bc5531deSDag-Erling Smørgrav 		if (strcasecmp(attrib, "canonical") == 0) {
604bc5531deSDag-Erling Smørgrav 			r = !!post_canon;  /* force bitmask member to boolean */
605bc5531deSDag-Erling Smørgrav 			if (r == (negate ? 1 : 0))
606bc5531deSDag-Erling Smørgrav 				this_result = result = 0;
607bc5531deSDag-Erling Smørgrav 			debug3("%.200s line %d: %smatched '%s'",
608bc5531deSDag-Erling Smørgrav 			    filename, linenum,
609bc5531deSDag-Erling Smørgrav 			    this_result ? "" : "not ", oattrib);
610bc5531deSDag-Erling Smørgrav 			continue;
611bc5531deSDag-Erling Smørgrav 		}
612bc5531deSDag-Erling Smørgrav 		/* All other criteria require an argument */
613f7167e0eSDag-Erling Smørgrav 		if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
614f7167e0eSDag-Erling Smørgrav 			error("Missing Match criteria for %s", attrib);
615f7167e0eSDag-Erling Smørgrav 			result = -1;
616f7167e0eSDag-Erling Smørgrav 			goto out;
617f7167e0eSDag-Erling Smørgrav 		}
618f7167e0eSDag-Erling Smørgrav 		if (strcasecmp(attrib, "host") == 0) {
619bc5531deSDag-Erling Smørgrav 			criteria = xstrdup(host);
620557f75e5SDag-Erling Smørgrav 			r = match_hostname(host, arg) == 1;
621bc5531deSDag-Erling Smørgrav 			if (r == (negate ? 1 : 0))
622bc5531deSDag-Erling Smørgrav 				this_result = result = 0;
623f7167e0eSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "originalhost") == 0) {
624bc5531deSDag-Erling Smørgrav 			criteria = xstrdup(original_host);
625557f75e5SDag-Erling Smørgrav 			r = match_hostname(original_host, arg) == 1;
626bc5531deSDag-Erling Smørgrav 			if (r == (negate ? 1 : 0))
627bc5531deSDag-Erling Smørgrav 				this_result = result = 0;
628f7167e0eSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "user") == 0) {
629bc5531deSDag-Erling Smørgrav 			criteria = xstrdup(ruser);
630557f75e5SDag-Erling Smørgrav 			r = match_pattern_list(ruser, arg, 0) == 1;
631bc5531deSDag-Erling Smørgrav 			if (r == (negate ? 1 : 0))
632bc5531deSDag-Erling Smørgrav 				this_result = result = 0;
633f7167e0eSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "localuser") == 0) {
634bc5531deSDag-Erling Smørgrav 			criteria = xstrdup(pw->pw_name);
635557f75e5SDag-Erling Smørgrav 			r = match_pattern_list(pw->pw_name, arg, 0) == 1;
636bc5531deSDag-Erling Smørgrav 			if (r == (negate ? 1 : 0))
637bc5531deSDag-Erling Smørgrav 				this_result = result = 0;
638f7167e0eSDag-Erling Smørgrav 		} else if (strcasecmp(attrib, "exec") == 0) {
639f7167e0eSDag-Erling Smørgrav 			if (gethostname(thishost, sizeof(thishost)) == -1)
640f7167e0eSDag-Erling Smørgrav 				fatal("gethostname: %s", strerror(errno));
641f7167e0eSDag-Erling Smørgrav 			strlcpy(shorthost, thishost, sizeof(shorthost));
642f7167e0eSDag-Erling Smørgrav 			shorthost[strcspn(thishost, ".")] = '\0';
643f7167e0eSDag-Erling Smørgrav 			snprintf(portstr, sizeof(portstr), "%d", port);
644190cef3dSDag-Erling Smørgrav 			snprintf(uidstr, sizeof(uidstr), "%llu",
645190cef3dSDag-Erling Smørgrav 			    (unsigned long long)pw->pw_uid);
646f7167e0eSDag-Erling Smørgrav 
647f7167e0eSDag-Erling Smørgrav 			cmd = percent_expand(arg,
648f7167e0eSDag-Erling Smørgrav 			    "L", shorthost,
649f7167e0eSDag-Erling Smørgrav 			    "d", pw->pw_dir,
650f7167e0eSDag-Erling Smørgrav 			    "h", host,
651f7167e0eSDag-Erling Smørgrav 			    "l", thishost,
652bc5531deSDag-Erling Smørgrav 			    "n", original_host,
653f7167e0eSDag-Erling Smørgrav 			    "p", portstr,
654f7167e0eSDag-Erling Smørgrav 			    "r", ruser,
655f7167e0eSDag-Erling Smørgrav 			    "u", pw->pw_name,
656190cef3dSDag-Erling Smørgrav 			    "i", uidstr,
657f7167e0eSDag-Erling Smørgrav 			    (char *)NULL);
658b83788ffSDag-Erling Smørgrav 			if (result != 1) {
659b83788ffSDag-Erling Smørgrav 				/* skip execution if prior predicate failed */
660bc5531deSDag-Erling Smørgrav 				debug3("%.200s line %d: skipped exec "
661bc5531deSDag-Erling Smørgrav 				    "\"%.100s\"", filename, linenum, cmd);
662bc5531deSDag-Erling Smørgrav 				free(cmd);
663bc5531deSDag-Erling Smørgrav 				continue;
664bc5531deSDag-Erling Smørgrav 			}
665f7167e0eSDag-Erling Smørgrav 			r = execute_in_shell(cmd);
666f7167e0eSDag-Erling Smørgrav 			if (r == -1) {
667b83788ffSDag-Erling Smørgrav 				fatal("%.200s line %d: match exec "
668b83788ffSDag-Erling Smørgrav 				    "'%.100s' error", filename,
669b83788ffSDag-Erling Smørgrav 				    linenum, cmd);
670b83788ffSDag-Erling Smørgrav 			}
671bc5531deSDag-Erling Smørgrav 			criteria = xstrdup(cmd);
672f7167e0eSDag-Erling Smørgrav 			free(cmd);
673bc5531deSDag-Erling Smørgrav 			/* Force exit status to boolean */
674bc5531deSDag-Erling Smørgrav 			r = r == 0;
675bc5531deSDag-Erling Smørgrav 			if (r == (negate ? 1 : 0))
676bc5531deSDag-Erling Smørgrav 				this_result = result = 0;
677f7167e0eSDag-Erling Smørgrav 		} else {
678f7167e0eSDag-Erling Smørgrav 			error("Unsupported Match attribute %s", attrib);
679f7167e0eSDag-Erling Smørgrav 			result = -1;
680f7167e0eSDag-Erling Smørgrav 			goto out;
681f7167e0eSDag-Erling Smørgrav 		}
682bc5531deSDag-Erling Smørgrav 		debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
683bc5531deSDag-Erling Smørgrav 		    filename, linenum, this_result ? "": "not ",
684bc5531deSDag-Erling Smørgrav 		    oattrib, criteria);
685bc5531deSDag-Erling Smørgrav 		free(criteria);
686f7167e0eSDag-Erling Smørgrav 	}
687f7167e0eSDag-Erling Smørgrav 	if (attributes == 0) {
688f7167e0eSDag-Erling Smørgrav 		error("One or more attributes required for Match");
689f7167e0eSDag-Erling Smørgrav 		result = -1;
690f7167e0eSDag-Erling Smørgrav 		goto out;
691f7167e0eSDag-Erling Smørgrav 	}
692f7167e0eSDag-Erling Smørgrav  out:
693bc5531deSDag-Erling Smørgrav 	if (result != -1)
694bc5531deSDag-Erling Smørgrav 		debug2("match %sfound", result ? "" : "not ");
695bc5531deSDag-Erling Smørgrav 	*condition = cp;
696f7167e0eSDag-Erling Smørgrav 	free(host);
697f7167e0eSDag-Erling Smørgrav 	return result;
698f7167e0eSDag-Erling Smørgrav }
699f7167e0eSDag-Erling Smørgrav 
700190cef3dSDag-Erling Smørgrav /* Remove environment variable by pattern */
701190cef3dSDag-Erling Smørgrav static void
702190cef3dSDag-Erling Smørgrav rm_env(Options *options, const char *arg, const char *filename, int linenum)
703190cef3dSDag-Erling Smørgrav {
704190cef3dSDag-Erling Smørgrav 	int i, j;
705190cef3dSDag-Erling Smørgrav 	char *cp;
706190cef3dSDag-Erling Smørgrav 
707190cef3dSDag-Erling Smørgrav 	/* Remove an environment variable */
708190cef3dSDag-Erling Smørgrav 	for (i = 0; i < options->num_send_env; ) {
709190cef3dSDag-Erling Smørgrav 		cp = xstrdup(options->send_env[i]);
710190cef3dSDag-Erling Smørgrav 		if (!match_pattern(cp, arg + 1)) {
711190cef3dSDag-Erling Smørgrav 			free(cp);
712190cef3dSDag-Erling Smørgrav 			i++;
713190cef3dSDag-Erling Smørgrav 			continue;
714190cef3dSDag-Erling Smørgrav 		}
715190cef3dSDag-Erling Smørgrav 		debug3("%s line %d: removing environment %s",
716190cef3dSDag-Erling Smørgrav 		    filename, linenum, cp);
717190cef3dSDag-Erling Smørgrav 		free(cp);
718190cef3dSDag-Erling Smørgrav 		free(options->send_env[i]);
719190cef3dSDag-Erling Smørgrav 		options->send_env[i] = NULL;
720190cef3dSDag-Erling Smørgrav 		for (j = i; j < options->num_send_env - 1; j++) {
721190cef3dSDag-Erling Smørgrav 			options->send_env[j] = options->send_env[j + 1];
722190cef3dSDag-Erling Smørgrav 			options->send_env[j + 1] = NULL;
723190cef3dSDag-Erling Smørgrav 		}
724190cef3dSDag-Erling Smørgrav 		options->num_send_env--;
725190cef3dSDag-Erling Smørgrav 		/* NB. don't increment i */
726190cef3dSDag-Erling Smørgrav 	}
727190cef3dSDag-Erling Smørgrav }
728190cef3dSDag-Erling Smørgrav 
729511b41d2SMark Murray /*
730ca3176e7SBrian Feldman  * Returns the number of the token pointed to by cp or oBadOption.
731511b41d2SMark Murray  */
732511b41d2SMark Murray static OpCodes
733e4a9863fSDag-Erling Smørgrav parse_token(const char *cp, const char *filename, int linenum,
734e4a9863fSDag-Erling Smørgrav     const char *ignored_unknown)
735511b41d2SMark Murray {
736e4a9863fSDag-Erling Smørgrav 	int i;
737511b41d2SMark Murray 
738511b41d2SMark Murray 	for (i = 0; keywords[i].name; i++)
739e4a9863fSDag-Erling Smørgrav 		if (strcmp(cp, keywords[i].name) == 0)
740511b41d2SMark Murray 			return keywords[i].opcode;
741557f75e5SDag-Erling Smørgrav 	if (ignored_unknown != NULL &&
742557f75e5SDag-Erling Smørgrav 	    match_pattern_list(cp, ignored_unknown, 1) == 1)
743e4a9863fSDag-Erling Smørgrav 		return oIgnoredUnknownOption;
744ca3176e7SBrian Feldman 	error("%s: line %d: Bad configuration option: %s",
745511b41d2SMark Murray 	    filename, linenum, cp);
746511b41d2SMark Murray 	return oBadOption;
747511b41d2SMark Murray }
748511b41d2SMark Murray 
749f7167e0eSDag-Erling Smørgrav /* Multistate option parsing */
750f7167e0eSDag-Erling Smørgrav struct multistate {
751f7167e0eSDag-Erling Smørgrav 	char *key;
752f7167e0eSDag-Erling Smørgrav 	int value;
753f7167e0eSDag-Erling Smørgrav };
754f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_flag[] = {
755f7167e0eSDag-Erling Smørgrav 	{ "true",			1 },
756f7167e0eSDag-Erling Smørgrav 	{ "false",			0 },
757f7167e0eSDag-Erling Smørgrav 	{ "yes",			1 },
758f7167e0eSDag-Erling Smørgrav 	{ "no",				0 },
759f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
760f7167e0eSDag-Erling Smørgrav };
761f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_yesnoask[] = {
762f7167e0eSDag-Erling Smørgrav 	{ "true",			1 },
763f7167e0eSDag-Erling Smørgrav 	{ "false",			0 },
764f7167e0eSDag-Erling Smørgrav 	{ "yes",			1 },
765f7167e0eSDag-Erling Smørgrav 	{ "no",				0 },
766f7167e0eSDag-Erling Smørgrav 	{ "ask",			2 },
767f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
768f7167e0eSDag-Erling Smørgrav };
7694f52dfbbSDag-Erling Smørgrav static const struct multistate multistate_strict_hostkey[] = {
7704f52dfbbSDag-Erling Smørgrav 	{ "true",			SSH_STRICT_HOSTKEY_YES },
7714f52dfbbSDag-Erling Smørgrav 	{ "false",			SSH_STRICT_HOSTKEY_OFF },
7724f52dfbbSDag-Erling Smørgrav 	{ "yes",			SSH_STRICT_HOSTKEY_YES },
7734f52dfbbSDag-Erling Smørgrav 	{ "no",				SSH_STRICT_HOSTKEY_OFF },
7744f52dfbbSDag-Erling Smørgrav 	{ "ask",			SSH_STRICT_HOSTKEY_ASK },
7754f52dfbbSDag-Erling Smørgrav 	{ "off",			SSH_STRICT_HOSTKEY_OFF },
7764f52dfbbSDag-Erling Smørgrav 	{ "accept-new",			SSH_STRICT_HOSTKEY_NEW },
7774f52dfbbSDag-Erling Smørgrav 	{ NULL, -1 }
7784f52dfbbSDag-Erling Smørgrav };
779acc1a9efSDag-Erling Smørgrav static const struct multistate multistate_yesnoaskconfirm[] = {
780acc1a9efSDag-Erling Smørgrav 	{ "true",			1 },
781acc1a9efSDag-Erling Smørgrav 	{ "false",			0 },
782acc1a9efSDag-Erling Smørgrav 	{ "yes",			1 },
783acc1a9efSDag-Erling Smørgrav 	{ "no",				0 },
784acc1a9efSDag-Erling Smørgrav 	{ "ask",			2 },
785acc1a9efSDag-Erling Smørgrav 	{ "confirm",			3 },
786acc1a9efSDag-Erling Smørgrav 	{ NULL, -1 }
787acc1a9efSDag-Erling Smørgrav };
788f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_addressfamily[] = {
789f7167e0eSDag-Erling Smørgrav 	{ "inet",			AF_INET },
790f7167e0eSDag-Erling Smørgrav 	{ "inet6",			AF_INET6 },
791f7167e0eSDag-Erling Smørgrav 	{ "any",			AF_UNSPEC },
792f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
793f7167e0eSDag-Erling Smørgrav };
794f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_controlmaster[] = {
795f7167e0eSDag-Erling Smørgrav 	{ "true",			SSHCTL_MASTER_YES },
796f7167e0eSDag-Erling Smørgrav 	{ "yes",			SSHCTL_MASTER_YES },
797f7167e0eSDag-Erling Smørgrav 	{ "false",			SSHCTL_MASTER_NO },
798f7167e0eSDag-Erling Smørgrav 	{ "no",				SSHCTL_MASTER_NO },
799f7167e0eSDag-Erling Smørgrav 	{ "auto",			SSHCTL_MASTER_AUTO },
800f7167e0eSDag-Erling Smørgrav 	{ "ask",			SSHCTL_MASTER_ASK },
801f7167e0eSDag-Erling Smørgrav 	{ "autoask",			SSHCTL_MASTER_AUTO_ASK },
802f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
803f7167e0eSDag-Erling Smørgrav };
804f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_tunnel[] = {
805f7167e0eSDag-Erling Smørgrav 	{ "ethernet",			SSH_TUNMODE_ETHERNET },
806f7167e0eSDag-Erling Smørgrav 	{ "point-to-point",		SSH_TUNMODE_POINTOPOINT },
807f7167e0eSDag-Erling Smørgrav 	{ "true",			SSH_TUNMODE_DEFAULT },
808f7167e0eSDag-Erling Smørgrav 	{ "yes",			SSH_TUNMODE_DEFAULT },
809f7167e0eSDag-Erling Smørgrav 	{ "false",			SSH_TUNMODE_NO },
810f7167e0eSDag-Erling Smørgrav 	{ "no",				SSH_TUNMODE_NO },
811f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
812f7167e0eSDag-Erling Smørgrav };
813f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_requesttty[] = {
814f7167e0eSDag-Erling Smørgrav 	{ "true",			REQUEST_TTY_YES },
815f7167e0eSDag-Erling Smørgrav 	{ "yes",			REQUEST_TTY_YES },
816f7167e0eSDag-Erling Smørgrav 	{ "false",			REQUEST_TTY_NO },
817f7167e0eSDag-Erling Smørgrav 	{ "no",				REQUEST_TTY_NO },
818f7167e0eSDag-Erling Smørgrav 	{ "force",			REQUEST_TTY_FORCE },
819f7167e0eSDag-Erling Smørgrav 	{ "auto",			REQUEST_TTY_AUTO },
820f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
821f7167e0eSDag-Erling Smørgrav };
822f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_canonicalizehostname[] = {
823f7167e0eSDag-Erling Smørgrav 	{ "true",			SSH_CANONICALISE_YES },
824f7167e0eSDag-Erling Smørgrav 	{ "false",			SSH_CANONICALISE_NO },
825f7167e0eSDag-Erling Smørgrav 	{ "yes",			SSH_CANONICALISE_YES },
826f7167e0eSDag-Erling Smørgrav 	{ "no",				SSH_CANONICALISE_NO },
827f7167e0eSDag-Erling Smørgrav 	{ "always",			SSH_CANONICALISE_ALWAYS },
828f7167e0eSDag-Erling Smørgrav 	{ NULL, -1 }
829f7167e0eSDag-Erling Smørgrav };
830f7167e0eSDag-Erling Smørgrav 
831511b41d2SMark Murray /*
832511b41d2SMark Murray  * Processes a single option line as used in the configuration files. This
833511b41d2SMark Murray  * only sets those values that have not already been set.
834511b41d2SMark Murray  */
835511b41d2SMark Murray int
836f7167e0eSDag-Erling Smørgrav process_config_line(Options *options, struct passwd *pw, const char *host,
837bc5531deSDag-Erling Smørgrav     const char *original_host, char *line, const char *filename,
838bc5531deSDag-Erling Smørgrav     int linenum, int *activep, int flags)
839511b41d2SMark Murray {
840076ad2f8SDag-Erling Smørgrav 	return process_config_line_depth(options, pw, host, original_host,
841076ad2f8SDag-Erling Smørgrav 	    line, filename, linenum, activep, flags, 0);
842076ad2f8SDag-Erling Smørgrav }
843076ad2f8SDag-Erling Smørgrav 
844076ad2f8SDag-Erling Smørgrav #define WHITESPACE " \t\r\n"
845076ad2f8SDag-Erling Smørgrav static int
846076ad2f8SDag-Erling Smørgrav process_config_line_depth(Options *options, struct passwd *pw, const char *host,
847076ad2f8SDag-Erling Smørgrav     const char *original_host, char *line, const char *filename,
848076ad2f8SDag-Erling Smørgrav     int linenum, int *activep, int flags, int depth)
849076ad2f8SDag-Erling Smørgrav {
850e146993eSDag-Erling Smørgrav 	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
851e146993eSDag-Erling Smørgrav 	char **cpptr, fwdarg[256];
852e4a9863fSDag-Erling Smørgrav 	u_int i, *uintptr, max_entries = 0;
853076ad2f8SDag-Erling Smørgrav 	int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
8544f52dfbbSDag-Erling Smørgrav 	int remotefwd, dynamicfwd;
855d4af9e69SDag-Erling Smørgrav 	LogLevel *log_level_ptr;
8564f52dfbbSDag-Erling Smørgrav 	SyslogFacility *log_facility_ptr;
857e4a9863fSDag-Erling Smørgrav 	long long val64;
858e73e9afaSDag-Erling Smørgrav 	size_t len;
859a0ee8cc6SDag-Erling Smørgrav 	struct Forward fwd;
860f7167e0eSDag-Erling Smørgrav 	const struct multistate *multistate_ptr;
861f7167e0eSDag-Erling Smørgrav 	struct allowed_cname *cname;
862076ad2f8SDag-Erling Smørgrav 	glob_t gl;
86347dd1d1bSDag-Erling Smørgrav 	const char *errstr;
864f7167e0eSDag-Erling Smørgrav 
865f7167e0eSDag-Erling Smørgrav 	if (activep == NULL) { /* We are processing a command line directive */
866f7167e0eSDag-Erling Smørgrav 		cmdline = 1;
867f7167e0eSDag-Erling Smørgrav 		activep = &cmdline;
868f7167e0eSDag-Erling Smørgrav 	}
869511b41d2SMark Murray 
870d93a896eSDag-Erling Smørgrav 	/* Strip trailing whitespace. Allow \f (form feed) at EOL only */
871557f75e5SDag-Erling Smørgrav 	if ((len = strlen(line)) == 0)
872557f75e5SDag-Erling Smørgrav 		return 0;
873557f75e5SDag-Erling Smørgrav 	for (len--; len > 0; len--) {
874d93a896eSDag-Erling Smørgrav 		if (strchr(WHITESPACE "\f", line[len]) == NULL)
875cf2b5f3bSDag-Erling Smørgrav 			break;
876cf2b5f3bSDag-Erling Smørgrav 		line[len] = '\0';
877cf2b5f3bSDag-Erling Smørgrav 	}
878cf2b5f3bSDag-Erling Smørgrav 
879c2d3a559SKris Kennaway 	s = line;
880c2d3a559SKris Kennaway 	/* Get the keyword. (Each line is supposed to begin with a keyword). */
881333ee039SDag-Erling Smørgrav 	if ((keyword = strdelim(&s)) == NULL)
882333ee039SDag-Erling Smørgrav 		return 0;
883c2d3a559SKris Kennaway 	/* Ignore leading whitespace. */
884c2d3a559SKris Kennaway 	if (*keyword == '\0')
885c2d3a559SKris Kennaway 		keyword = strdelim(&s);
886ca3176e7SBrian Feldman 	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
887511b41d2SMark Murray 		return 0;
888e4a9863fSDag-Erling Smørgrav 	/* Match lowercase keyword */
889f7167e0eSDag-Erling Smørgrav 	lowercase(keyword);
890511b41d2SMark Murray 
891e4a9863fSDag-Erling Smørgrav 	opcode = parse_token(keyword, filename, linenum,
892e4a9863fSDag-Erling Smørgrav 	    options->ignored_unknown);
893511b41d2SMark Murray 
894511b41d2SMark Murray 	switch (opcode) {
895511b41d2SMark Murray 	case oBadOption:
896511b41d2SMark Murray 		/* don't panic, but count bad options */
897511b41d2SMark Murray 		return -1;
8984f52dfbbSDag-Erling Smørgrav 	case oIgnore:
8994f52dfbbSDag-Erling Smørgrav 		return 0;
900e4a9863fSDag-Erling Smørgrav 	case oIgnoredUnknownOption:
901e4a9863fSDag-Erling Smørgrav 		debug("%s line %d: Ignored unknown option \"%s\"",
902e4a9863fSDag-Erling Smørgrav 		    filename, linenum, keyword);
903e4a9863fSDag-Erling Smørgrav 		return 0;
904cf2b5f3bSDag-Erling Smørgrav 	case oConnectTimeout:
905cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->connection_timeout;
9061ec0d754SDag-Erling Smørgrav parse_time:
907cf2b5f3bSDag-Erling Smørgrav 		arg = strdelim(&s);
908cf2b5f3bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
909cf2b5f3bSDag-Erling Smørgrav 			fatal("%s line %d: missing time value.",
910cf2b5f3bSDag-Erling Smørgrav 			    filename, linenum);
911bc5531deSDag-Erling Smørgrav 		if (strcmp(arg, "none") == 0)
912bc5531deSDag-Erling Smørgrav 			value = -1;
913bc5531deSDag-Erling Smørgrav 		else if ((value = convtime(arg)) == -1)
914cf2b5f3bSDag-Erling Smørgrav 			fatal("%s line %d: invalid time value.",
915cf2b5f3bSDag-Erling Smørgrav 			    filename, linenum);
916d4af9e69SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
917cf2b5f3bSDag-Erling Smørgrav 			*intptr = value;
918cf2b5f3bSDag-Erling Smørgrav 		break;
919cf2b5f3bSDag-Erling Smørgrav 
920511b41d2SMark Murray 	case oForwardAgent:
921511b41d2SMark Murray 		intptr = &options->forward_agent;
922511b41d2SMark Murray  parse_flag:
923f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_flag;
924f7167e0eSDag-Erling Smørgrav  parse_multistate:
925c2d3a559SKris Kennaway 		arg = strdelim(&s);
926c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
927f7167e0eSDag-Erling Smørgrav 			fatal("%s line %d: missing argument.",
928f7167e0eSDag-Erling Smørgrav 			    filename, linenum);
929f7167e0eSDag-Erling Smørgrav 		value = -1;
930f7167e0eSDag-Erling Smørgrav 		for (i = 0; multistate_ptr[i].key != NULL; i++) {
931f7167e0eSDag-Erling Smørgrav 			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
932f7167e0eSDag-Erling Smørgrav 				value = multistate_ptr[i].value;
933f7167e0eSDag-Erling Smørgrav 				break;
934f7167e0eSDag-Erling Smørgrav 			}
935f7167e0eSDag-Erling Smørgrav 		}
936f7167e0eSDag-Erling Smørgrav 		if (value == -1)
937f7167e0eSDag-Erling Smørgrav 			fatal("%s line %d: unsupported option \"%s\".",
938f7167e0eSDag-Erling Smørgrav 			    filename, linenum, arg);
939511b41d2SMark Murray 		if (*activep && *intptr == -1)
940511b41d2SMark Murray 			*intptr = value;
941511b41d2SMark Murray 		break;
942511b41d2SMark Murray 
943511b41d2SMark Murray 	case oForwardX11:
944511b41d2SMark Murray 		intptr = &options->forward_x11;
945511b41d2SMark Murray 		goto parse_flag;
946511b41d2SMark Murray 
9471ec0d754SDag-Erling Smørgrav 	case oForwardX11Trusted:
9481ec0d754SDag-Erling Smørgrav 		intptr = &options->forward_x11_trusted;
9491ec0d754SDag-Erling Smørgrav 		goto parse_flag;
9501ec0d754SDag-Erling Smørgrav 
951e2f6069cSDag-Erling Smørgrav 	case oForwardX11Timeout:
952e2f6069cSDag-Erling Smørgrav 		intptr = &options->forward_x11_timeout;
953e2f6069cSDag-Erling Smørgrav 		goto parse_time;
954e2f6069cSDag-Erling Smørgrav 
955511b41d2SMark Murray 	case oGatewayPorts:
956a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->fwd_opts.gateway_ports;
957511b41d2SMark Murray 		goto parse_flag;
958511b41d2SMark Murray 
959333ee039SDag-Erling Smørgrav 	case oExitOnForwardFailure:
960333ee039SDag-Erling Smørgrav 		intptr = &options->exit_on_forward_failure;
961333ee039SDag-Erling Smørgrav 		goto parse_flag;
962333ee039SDag-Erling Smørgrav 
963511b41d2SMark Murray 	case oPasswordAuthentication:
964511b41d2SMark Murray 		intptr = &options->password_authentication;
965511b41d2SMark Murray 		goto parse_flag;
966511b41d2SMark Murray 
96709958426SBrian Feldman 	case oKbdInteractiveAuthentication:
96809958426SBrian Feldman 		intptr = &options->kbd_interactive_authentication;
96909958426SBrian Feldman 		goto parse_flag;
97009958426SBrian Feldman 
97109958426SBrian Feldman 	case oKbdInteractiveDevices:
97209958426SBrian Feldman 		charptr = &options->kbd_interactive_devices;
97309958426SBrian Feldman 		goto parse_string;
97409958426SBrian Feldman 
975ca3176e7SBrian Feldman 	case oPubkeyAuthentication:
976ca3176e7SBrian Feldman 		intptr = &options->pubkey_authentication;
977e8aafc91SKris Kennaway 		goto parse_flag;
978e8aafc91SKris Kennaway 
979ca3176e7SBrian Feldman 	case oHostbasedAuthentication:
980ca3176e7SBrian Feldman 		intptr = &options->hostbased_authentication;
981511b41d2SMark Murray 		goto parse_flag;
982511b41d2SMark Murray 
983af12a3e7SDag-Erling Smørgrav 	case oChallengeResponseAuthentication:
984af12a3e7SDag-Erling Smørgrav 		intptr = &options->challenge_response_authentication;
985af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
986cf2b5f3bSDag-Erling Smørgrav 
987cf2b5f3bSDag-Erling Smørgrav 	case oGssAuthentication:
988cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_authentication;
989511b41d2SMark Murray 		goto parse_flag;
990cf2b5f3bSDag-Erling Smørgrav 
991cf2b5f3bSDag-Erling Smørgrav 	case oGssDelegateCreds:
992cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_deleg_creds;
993ca3176e7SBrian Feldman 		goto parse_flag;
994cf2b5f3bSDag-Erling Smørgrav 
995511b41d2SMark Murray 	case oBatchMode:
996511b41d2SMark Murray 		intptr = &options->batch_mode;
997511b41d2SMark Murray 		goto parse_flag;
998511b41d2SMark Murray 
999511b41d2SMark Murray 	case oCheckHostIP:
1000511b41d2SMark Murray 		intptr = &options->check_host_ip;
1001511b41d2SMark Murray 		goto parse_flag;
1002511b41d2SMark Murray 
1003cf2b5f3bSDag-Erling Smørgrav 	case oVerifyHostKeyDNS:
1004cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->verify_host_key_dns;
1005f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_yesnoask;
1006f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
1007cf2b5f3bSDag-Erling Smørgrav 
1008511b41d2SMark Murray 	case oStrictHostKeyChecking:
1009511b41d2SMark Murray 		intptr = &options->strict_host_key_checking;
10104f52dfbbSDag-Erling Smørgrav 		multistate_ptr = multistate_strict_hostkey;
1011f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
1012511b41d2SMark Murray 
1013511b41d2SMark Murray 	case oCompression:
1014511b41d2SMark Murray 		intptr = &options->compression;
1015511b41d2SMark Murray 		goto parse_flag;
1016511b41d2SMark Murray 
10171ec0d754SDag-Erling Smørgrav 	case oTCPKeepAlive:
10181ec0d754SDag-Erling Smørgrav 		intptr = &options->tcp_keep_alive;
1019511b41d2SMark Murray 		goto parse_flag;
1020511b41d2SMark Murray 
1021af12a3e7SDag-Erling Smørgrav 	case oNoHostAuthenticationForLocalhost:
1022af12a3e7SDag-Erling Smørgrav 		intptr = &options->no_host_authentication_for_localhost;
1023af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
1024af12a3e7SDag-Erling Smørgrav 
1025511b41d2SMark Murray 	case oNumberOfPasswordPrompts:
1026511b41d2SMark Murray 		intptr = &options->number_of_password_prompts;
1027511b41d2SMark Murray 		goto parse_int;
1028511b41d2SMark Murray 
1029cf2b5f3bSDag-Erling Smørgrav 	case oRekeyLimit:
1030cf2b5f3bSDag-Erling Smørgrav 		arg = strdelim(&s);
1031cf2b5f3bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1032e4a9863fSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename,
1033e4a9863fSDag-Erling Smørgrav 			    linenum);
1034e4a9863fSDag-Erling Smørgrav 		if (strcmp(arg, "default") == 0) {
1035e4a9863fSDag-Erling Smørgrav 			val64 = 0;
1036e4a9863fSDag-Erling Smørgrav 		} else {
1037e4a9863fSDag-Erling Smørgrav 			if (scan_scaled(arg, &val64) == -1)
1038e4a9863fSDag-Erling Smørgrav 				fatal("%.200s line %d: Bad number '%s': %s",
1039e4a9863fSDag-Erling Smørgrav 				    filename, linenum, arg, strerror(errno));
1040e4a9863fSDag-Erling Smørgrav 			if (val64 != 0 && val64 < 16)
1041333ee039SDag-Erling Smørgrav 				fatal("%.200s line %d: RekeyLimit too small",
1042333ee039SDag-Erling Smørgrav 				    filename, linenum);
1043e4a9863fSDag-Erling Smørgrav 		}
1044d4af9e69SDag-Erling Smørgrav 		if (*activep && options->rekey_limit == -1)
1045acc1a9efSDag-Erling Smørgrav 			options->rekey_limit = val64;
1046e4a9863fSDag-Erling Smørgrav 		if (s != NULL) { /* optional rekey interval present */
1047e4a9863fSDag-Erling Smørgrav 			if (strcmp(s, "none") == 0) {
1048e4a9863fSDag-Erling Smørgrav 				(void)strdelim(&s);	/* discard */
1049e4a9863fSDag-Erling Smørgrav 				break;
1050e4a9863fSDag-Erling Smørgrav 			}
1051e4a9863fSDag-Erling Smørgrav 			intptr = &options->rekey_interval;
1052e4a9863fSDag-Erling Smørgrav 			goto parse_time;
1053e4a9863fSDag-Erling Smørgrav 		}
1054cf2b5f3bSDag-Erling Smørgrav 		break;
1055cf2b5f3bSDag-Erling Smørgrav 
1056511b41d2SMark Murray 	case oIdentityFile:
1057c2d3a559SKris Kennaway 		arg = strdelim(&s);
1058c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1059511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1060511b41d2SMark Murray 		if (*activep) {
1061ca3176e7SBrian Feldman 			intptr = &options->num_identity_files;
1062e8aafc91SKris Kennaway 			if (*intptr >= SSH_MAX_IDENTITY_FILES)
1063511b41d2SMark Murray 				fatal("%.200s line %d: Too many identity files specified (max %d).",
1064511b41d2SMark Murray 				    filename, linenum, SSH_MAX_IDENTITY_FILES);
1065bc5531deSDag-Erling Smørgrav 			add_identity_file(options, NULL,
1066bc5531deSDag-Erling Smørgrav 			    arg, flags & SSHCONF_USERCONF);
1067511b41d2SMark Murray 		}
1068511b41d2SMark Murray 		break;
1069511b41d2SMark Murray 
1070acc1a9efSDag-Erling Smørgrav 	case oCertificateFile:
1071acc1a9efSDag-Erling Smørgrav 		arg = strdelim(&s);
1072acc1a9efSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1073acc1a9efSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.",
1074acc1a9efSDag-Erling Smørgrav 			    filename, linenum);
1075acc1a9efSDag-Erling Smørgrav 		if (*activep) {
1076acc1a9efSDag-Erling Smørgrav 			intptr = &options->num_certificate_files;
1077acc1a9efSDag-Erling Smørgrav 			if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
1078acc1a9efSDag-Erling Smørgrav 				fatal("%.200s line %d: Too many certificate "
1079acc1a9efSDag-Erling Smørgrav 				    "files specified (max %d).",
1080acc1a9efSDag-Erling Smørgrav 				    filename, linenum,
1081acc1a9efSDag-Erling Smørgrav 				    SSH_MAX_CERTIFICATE_FILES);
1082acc1a9efSDag-Erling Smørgrav 			}
1083acc1a9efSDag-Erling Smørgrav 			add_certificate_file(options, arg,
1084acc1a9efSDag-Erling Smørgrav 			    flags & SSHCONF_USERCONF);
1085acc1a9efSDag-Erling Smørgrav 		}
1086acc1a9efSDag-Erling Smørgrav 		break;
1087acc1a9efSDag-Erling Smørgrav 
1088c2d3a559SKris Kennaway 	case oXAuthLocation:
1089c2d3a559SKris Kennaway 		charptr=&options->xauth_location;
1090c2d3a559SKris Kennaway 		goto parse_string;
1091c2d3a559SKris Kennaway 
1092511b41d2SMark Murray 	case oUser:
1093511b41d2SMark Murray 		charptr = &options->user;
1094511b41d2SMark Murray parse_string:
1095c2d3a559SKris Kennaway 		arg = strdelim(&s);
1096c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1097e146993eSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.",
1098e146993eSDag-Erling Smørgrav 			    filename, linenum);
1099511b41d2SMark Murray 		if (*activep && *charptr == NULL)
1100c2d3a559SKris Kennaway 			*charptr = xstrdup(arg);
1101511b41d2SMark Murray 		break;
1102511b41d2SMark Murray 
1103511b41d2SMark Murray 	case oGlobalKnownHostsFile:
1104e146993eSDag-Erling Smørgrav 		cpptr = (char **)&options->system_hostfiles;
1105e146993eSDag-Erling Smørgrav 		uintptr = &options->num_system_hostfiles;
1106e146993eSDag-Erling Smørgrav 		max_entries = SSH_MAX_HOSTS_FILES;
1107e146993eSDag-Erling Smørgrav parse_char_array:
1108e146993eSDag-Erling Smørgrav 		if (*activep && *uintptr == 0) {
1109e146993eSDag-Erling Smørgrav 			while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1110e146993eSDag-Erling Smørgrav 				if ((*uintptr) >= max_entries)
1111e146993eSDag-Erling Smørgrav 					fatal("%s line %d: "
1112e146993eSDag-Erling Smørgrav 					    "too many authorized keys files.",
1113e146993eSDag-Erling Smørgrav 					    filename, linenum);
1114e146993eSDag-Erling Smørgrav 				cpptr[(*uintptr)++] = xstrdup(arg);
1115e146993eSDag-Erling Smørgrav 			}
1116e146993eSDag-Erling Smørgrav 		}
1117e146993eSDag-Erling Smørgrav 		return 0;
1118511b41d2SMark Murray 
1119511b41d2SMark Murray 	case oUserKnownHostsFile:
1120e146993eSDag-Erling Smørgrav 		cpptr = (char **)&options->user_hostfiles;
1121e146993eSDag-Erling Smørgrav 		uintptr = &options->num_user_hostfiles;
1122e146993eSDag-Erling Smørgrav 		max_entries = SSH_MAX_HOSTS_FILES;
1123e146993eSDag-Erling Smørgrav 		goto parse_char_array;
1124e8aafc91SKris Kennaway 
1125511b41d2SMark Murray 	case oHostName:
1126511b41d2SMark Murray 		charptr = &options->hostname;
1127511b41d2SMark Murray 		goto parse_string;
1128511b41d2SMark Murray 
1129ca3176e7SBrian Feldman 	case oHostKeyAlias:
1130ca3176e7SBrian Feldman 		charptr = &options->host_key_alias;
1131ca3176e7SBrian Feldman 		goto parse_string;
1132ca3176e7SBrian Feldman 
1133ca3176e7SBrian Feldman 	case oPreferredAuthentications:
1134ca3176e7SBrian Feldman 		charptr = &options->preferred_authentications;
1135ca3176e7SBrian Feldman 		goto parse_string;
1136ca3176e7SBrian Feldman 
1137af12a3e7SDag-Erling Smørgrav 	case oBindAddress:
1138af12a3e7SDag-Erling Smørgrav 		charptr = &options->bind_address;
1139af12a3e7SDag-Erling Smørgrav 		goto parse_string;
1140af12a3e7SDag-Erling Smørgrav 
114147dd1d1bSDag-Erling Smørgrav 	case oBindInterface:
114247dd1d1bSDag-Erling Smørgrav 		charptr = &options->bind_interface;
114347dd1d1bSDag-Erling Smørgrav 		goto parse_string;
114447dd1d1bSDag-Erling Smørgrav 
1145b15c8340SDag-Erling Smørgrav 	case oPKCS11Provider:
1146b15c8340SDag-Erling Smørgrav 		charptr = &options->pkcs11_provider;
1147af12a3e7SDag-Erling Smørgrav 		goto parse_string;
1148af12a3e7SDag-Erling Smørgrav 
1149511b41d2SMark Murray 	case oProxyCommand:
1150b74df5b2SDag-Erling Smørgrav 		charptr = &options->proxy_command;
1151076ad2f8SDag-Erling Smørgrav 		/* Ignore ProxyCommand if ProxyJump already specified */
1152076ad2f8SDag-Erling Smørgrav 		if (options->jump_host != NULL)
1153076ad2f8SDag-Erling Smørgrav 			charptr = &options->jump_host; /* Skip below */
1154b74df5b2SDag-Erling Smørgrav parse_command:
1155cf2b5f3bSDag-Erling Smørgrav 		if (s == NULL)
1156cf2b5f3bSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1157e73e9afaSDag-Erling Smørgrav 		len = strspn(s, WHITESPACE "=");
1158511b41d2SMark Murray 		if (*activep && *charptr == NULL)
1159e73e9afaSDag-Erling Smørgrav 			*charptr = xstrdup(s + len);
1160511b41d2SMark Murray 		return 0;
1161511b41d2SMark Murray 
1162076ad2f8SDag-Erling Smørgrav 	case oProxyJump:
1163076ad2f8SDag-Erling Smørgrav 		if (s == NULL) {
1164076ad2f8SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.",
1165076ad2f8SDag-Erling Smørgrav 			    filename, linenum);
1166076ad2f8SDag-Erling Smørgrav 		}
1167076ad2f8SDag-Erling Smørgrav 		len = strspn(s, WHITESPACE "=");
1168076ad2f8SDag-Erling Smørgrav 		if (parse_jump(s + len, options, *activep) == -1) {
1169076ad2f8SDag-Erling Smørgrav 			fatal("%.200s line %d: Invalid ProxyJump \"%s\"",
1170076ad2f8SDag-Erling Smørgrav 			    filename, linenum, s + len);
1171076ad2f8SDag-Erling Smørgrav 		}
1172076ad2f8SDag-Erling Smørgrav 		return 0;
1173076ad2f8SDag-Erling Smørgrav 
1174511b41d2SMark Murray 	case oPort:
11752f513db7SEd Maste 		arg = strdelim(&s);
11762f513db7SEd Maste 		if (!arg || *arg == '\0')
11772f513db7SEd Maste 			fatal("%.200s line %d: Missing argument.",
11782f513db7SEd Maste 			    filename, linenum);
11792f513db7SEd Maste 		value = a2port(arg);
11802f513db7SEd Maste 		if (value <= 0)
11812f513db7SEd Maste 			fatal("%.200s line %d: Bad port '%s'.",
11822f513db7SEd Maste 			    filename, linenum, arg);
11832f513db7SEd Maste 		if (*activep && options->port == -1)
11842f513db7SEd Maste 			options->port = value;
11852f513db7SEd Maste 		break;
11862f513db7SEd Maste 
11872f513db7SEd Maste 	case oConnectionAttempts:
11882f513db7SEd Maste 		intptr = &options->connection_attempts;
1189511b41d2SMark Murray parse_int:
1190c2d3a559SKris Kennaway 		arg = strdelim(&s);
119147dd1d1bSDag-Erling Smørgrav 		if ((errstr = atoi_err(arg, &value)) != NULL)
119247dd1d1bSDag-Erling Smørgrav 			fatal("%s line %d: integer value %s.",
119347dd1d1bSDag-Erling Smørgrav 			    filename, linenum, errstr);
1194511b41d2SMark Murray 		if (*activep && *intptr == -1)
1195511b41d2SMark Murray 			*intptr = value;
1196511b41d2SMark Murray 		break;
1197511b41d2SMark Murray 
1198e8aafc91SKris Kennaway 	case oCiphers:
1199c2d3a559SKris Kennaway 		arg = strdelim(&s);
1200c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1201db1cb46cSKris Kennaway 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1202d93a896eSDag-Erling Smørgrav 		if (*arg != '-' && !ciphers_valid(*arg == '+' ? arg + 1 : arg))
1203e8aafc91SKris Kennaway 			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1204c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1205e8aafc91SKris Kennaway 		if (*activep && options->ciphers == NULL)
1206c2d3a559SKris Kennaway 			options->ciphers = xstrdup(arg);
1207e8aafc91SKris Kennaway 		break;
1208e8aafc91SKris Kennaway 
1209ca3176e7SBrian Feldman 	case oMacs:
1210ca3176e7SBrian Feldman 		arg = strdelim(&s);
1211ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
1212ca3176e7SBrian Feldman 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1213d93a896eSDag-Erling Smørgrav 		if (*arg != '-' && !mac_valid(*arg == '+' ? arg + 1 : arg))
1214ca3176e7SBrian Feldman 			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
1215ca3176e7SBrian Feldman 			    filename, linenum, arg ? arg : "<NONE>");
1216ca3176e7SBrian Feldman 		if (*activep && options->macs == NULL)
1217ca3176e7SBrian Feldman 			options->macs = xstrdup(arg);
1218ca3176e7SBrian Feldman 		break;
1219ca3176e7SBrian Feldman 
12204a421b63SDag-Erling Smørgrav 	case oKexAlgorithms:
12214a421b63SDag-Erling Smørgrav 		arg = strdelim(&s);
12224a421b63SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
12234a421b63SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.",
12244a421b63SDag-Erling Smørgrav 			    filename, linenum);
1225d93a896eSDag-Erling Smørgrav 		if (*arg != '-' &&
1226d93a896eSDag-Erling Smørgrav 		    !kex_names_valid(*arg == '+' ? arg + 1 : arg))
12274a421b63SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
12284a421b63SDag-Erling Smørgrav 			    filename, linenum, arg ? arg : "<NONE>");
12294a421b63SDag-Erling Smørgrav 		if (*activep && options->kex_algorithms == NULL)
12304a421b63SDag-Erling Smørgrav 			options->kex_algorithms = xstrdup(arg);
12314a421b63SDag-Erling Smørgrav 		break;
12324a421b63SDag-Erling Smørgrav 
1233ca3176e7SBrian Feldman 	case oHostKeyAlgorithms:
1234eccfee6eSDag-Erling Smørgrav 		charptr = &options->hostkeyalgorithms;
1235eccfee6eSDag-Erling Smørgrav parse_keytypes:
1236ca3176e7SBrian Feldman 		arg = strdelim(&s);
1237ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
1238eccfee6eSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.",
1239eccfee6eSDag-Erling Smørgrav 			    filename, linenum);
1240d93a896eSDag-Erling Smørgrav 		if (*arg != '-' &&
1241d93a896eSDag-Erling Smørgrav 		    !sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1))
1242eccfee6eSDag-Erling Smørgrav 			fatal("%s line %d: Bad key types '%s'.",
1243ca3176e7SBrian Feldman 				filename, linenum, arg ? arg : "<NONE>");
1244eccfee6eSDag-Erling Smørgrav 		if (*activep && *charptr == NULL)
1245eccfee6eSDag-Erling Smørgrav 			*charptr = xstrdup(arg);
1246ca3176e7SBrian Feldman 		break;
1247ca3176e7SBrian Feldman 
12482f513db7SEd Maste 	case oCASignatureAlgorithms:
12492f513db7SEd Maste 		charptr = &options->ca_sign_algorithms;
12502f513db7SEd Maste 		goto parse_keytypes;
12512f513db7SEd Maste 
1252511b41d2SMark Murray 	case oLogLevel:
1253d4af9e69SDag-Erling Smørgrav 		log_level_ptr = &options->log_level;
1254c2d3a559SKris Kennaway 		arg = strdelim(&s);
1255c2d3a559SKris Kennaway 		value = log_level_number(arg);
1256af12a3e7SDag-Erling Smørgrav 		if (value == SYSLOG_LEVEL_NOT_SET)
1257ca3176e7SBrian Feldman 			fatal("%.200s line %d: unsupported log level '%s'",
1258c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
1259d4af9e69SDag-Erling Smørgrav 		if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1260d4af9e69SDag-Erling Smørgrav 			*log_level_ptr = (LogLevel) value;
1261511b41d2SMark Murray 		break;
1262511b41d2SMark Murray 
12634f52dfbbSDag-Erling Smørgrav 	case oLogFacility:
12644f52dfbbSDag-Erling Smørgrav 		log_facility_ptr = &options->log_facility;
12654f52dfbbSDag-Erling Smørgrav 		arg = strdelim(&s);
12664f52dfbbSDag-Erling Smørgrav 		value = log_facility_number(arg);
12674f52dfbbSDag-Erling Smørgrav 		if (value == SYSLOG_FACILITY_NOT_SET)
12684f52dfbbSDag-Erling Smørgrav 			fatal("%.200s line %d: unsupported log facility '%s'",
12694f52dfbbSDag-Erling Smørgrav 			    filename, linenum, arg ? arg : "<NONE>");
12704f52dfbbSDag-Erling Smørgrav 		if (*log_facility_ptr == -1)
12714f52dfbbSDag-Erling Smørgrav 			*log_facility_ptr = (SyslogFacility) value;
12724f52dfbbSDag-Erling Smørgrav 		break;
12734f52dfbbSDag-Erling Smørgrav 
1274af12a3e7SDag-Erling Smørgrav 	case oLocalForward:
1275511b41d2SMark Murray 	case oRemoteForward:
1276cce7d346SDag-Erling Smørgrav 	case oDynamicForward:
1277c2d3a559SKris Kennaway 		arg = strdelim(&s);
1278aa49c926SDag-Erling Smørgrav 		if (arg == NULL || *arg == '\0')
1279af12a3e7SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing port argument.",
1280af12a3e7SDag-Erling Smørgrav 			    filename, linenum);
1281cce7d346SDag-Erling Smørgrav 
12824f52dfbbSDag-Erling Smørgrav 		remotefwd = (opcode == oRemoteForward);
12834f52dfbbSDag-Erling Smørgrav 		dynamicfwd = (opcode == oDynamicForward);
12844f52dfbbSDag-Erling Smørgrav 
12854f52dfbbSDag-Erling Smørgrav 		if (!dynamicfwd) {
1286aa49c926SDag-Erling Smørgrav 			arg2 = strdelim(&s);
12874f52dfbbSDag-Erling Smørgrav 			if (arg2 == NULL || *arg2 == '\0') {
12884f52dfbbSDag-Erling Smørgrav 				if (remotefwd)
12894f52dfbbSDag-Erling Smørgrav 					dynamicfwd = 1;
12904f52dfbbSDag-Erling Smørgrav 				else
12914f52dfbbSDag-Erling Smørgrav 					fatal("%.200s line %d: Missing target "
12924f52dfbbSDag-Erling Smørgrav 					    "argument.", filename, linenum);
12934f52dfbbSDag-Erling Smørgrav 			} else {
1294aa49c926SDag-Erling Smørgrav 				/* construct a string for parse_forward */
12954f52dfbbSDag-Erling Smørgrav 				snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg,
12964f52dfbbSDag-Erling Smørgrav 				    arg2);
1297cce7d346SDag-Erling Smørgrav 			}
12984f52dfbbSDag-Erling Smørgrav 		}
12994f52dfbbSDag-Erling Smørgrav 		if (dynamicfwd)
13004f52dfbbSDag-Erling Smørgrav 			strlcpy(fwdarg, arg, sizeof(fwdarg));
1301aa49c926SDag-Erling Smørgrav 
13024f52dfbbSDag-Erling Smørgrav 		if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0)
1303af12a3e7SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad forwarding specification.",
1304511b41d2SMark Murray 			    filename, linenum);
1305aa49c926SDag-Erling Smørgrav 
1306af12a3e7SDag-Erling Smørgrav 		if (*activep) {
13074f52dfbbSDag-Erling Smørgrav 			if (remotefwd) {
1308aa49c926SDag-Erling Smørgrav 				add_remote_forward(options, &fwd);
13094f52dfbbSDag-Erling Smørgrav 			} else {
13104f52dfbbSDag-Erling Smørgrav 				add_local_forward(options, &fwd);
13114f52dfbbSDag-Erling Smørgrav 			}
1312af12a3e7SDag-Erling Smørgrav 		}
1313511b41d2SMark Murray 		break;
1314511b41d2SMark Murray 
1315af12a3e7SDag-Erling Smørgrav 	case oClearAllForwardings:
1316af12a3e7SDag-Erling Smørgrav 		intptr = &options->clear_forwardings;
1317af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
1318af12a3e7SDag-Erling Smørgrav 
1319511b41d2SMark Murray 	case oHost:
1320f7167e0eSDag-Erling Smørgrav 		if (cmdline)
1321f7167e0eSDag-Erling Smørgrav 			fatal("Host directive not supported as a command-line "
1322f7167e0eSDag-Erling Smørgrav 			    "option");
1323511b41d2SMark Murray 		*activep = 0;
1324e146993eSDag-Erling Smørgrav 		arg2 = NULL;
1325e146993eSDag-Erling Smørgrav 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1326076ad2f8SDag-Erling Smørgrav 			if ((flags & SSHCONF_NEVERMATCH) != 0)
1327076ad2f8SDag-Erling Smørgrav 				break;
1328e146993eSDag-Erling Smørgrav 			negated = *arg == '!';
1329e146993eSDag-Erling Smørgrav 			if (negated)
1330e146993eSDag-Erling Smørgrav 				arg++;
1331c2d3a559SKris Kennaway 			if (match_pattern(host, arg)) {
1332e146993eSDag-Erling Smørgrav 				if (negated) {
1333e146993eSDag-Erling Smørgrav 					debug("%.200s line %d: Skipping Host "
1334e146993eSDag-Erling Smørgrav 					    "block because of negated match "
1335e146993eSDag-Erling Smørgrav 					    "for %.100s", filename, linenum,
1336e146993eSDag-Erling Smørgrav 					    arg);
1337e146993eSDag-Erling Smørgrav 					*activep = 0;
1338511b41d2SMark Murray 					break;
1339511b41d2SMark Murray 				}
1340e146993eSDag-Erling Smørgrav 				if (!*activep)
1341e146993eSDag-Erling Smørgrav 					arg2 = arg; /* logged below */
1342e146993eSDag-Erling Smørgrav 				*activep = 1;
1343e146993eSDag-Erling Smørgrav 			}
1344e146993eSDag-Erling Smørgrav 		}
1345e146993eSDag-Erling Smørgrav 		if (*activep)
1346e146993eSDag-Erling Smørgrav 			debug("%.200s line %d: Applying options for %.100s",
1347e146993eSDag-Erling Smørgrav 			    filename, linenum, arg2);
1348c2d3a559SKris Kennaway 		/* Avoid garbage check below, as strdelim is done. */
1349511b41d2SMark Murray 		return 0;
1350511b41d2SMark Murray 
1351f7167e0eSDag-Erling Smørgrav 	case oMatch:
1352f7167e0eSDag-Erling Smørgrav 		if (cmdline)
1353f7167e0eSDag-Erling Smørgrav 			fatal("Host directive not supported as a command-line "
1354f7167e0eSDag-Erling Smørgrav 			    "option");
1355bc5531deSDag-Erling Smørgrav 		value = match_cfg_line(options, &s, pw, host, original_host,
1356bc5531deSDag-Erling Smørgrav 		    flags & SSHCONF_POSTCANON, filename, linenum);
1357f7167e0eSDag-Erling Smørgrav 		if (value < 0)
1358f7167e0eSDag-Erling Smørgrav 			fatal("%.200s line %d: Bad Match condition", filename,
1359f7167e0eSDag-Erling Smørgrav 			    linenum);
1360076ad2f8SDag-Erling Smørgrav 		*activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
1361f7167e0eSDag-Erling Smørgrav 		break;
1362f7167e0eSDag-Erling Smørgrav 
1363511b41d2SMark Murray 	case oEscapeChar:
1364511b41d2SMark Murray 		intptr = &options->escape_char;
1365c2d3a559SKris Kennaway 		arg = strdelim(&s);
1366c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
1367511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1368557f75e5SDag-Erling Smørgrav 		if (strcmp(arg, "none") == 0)
1369557f75e5SDag-Erling Smørgrav 			value = SSH_ESCAPECHAR_NONE;
1370557f75e5SDag-Erling Smørgrav 		else if (arg[1] == '\0')
1371557f75e5SDag-Erling Smørgrav 			value = (u_char) arg[0];
1372557f75e5SDag-Erling Smørgrav 		else if (arg[0] == '^' && arg[2] == 0 &&
1373ca3176e7SBrian Feldman 		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1374ca3176e7SBrian Feldman 			value = (u_char) arg[1] & 31;
1375511b41d2SMark Murray 		else {
1376511b41d2SMark Murray 			fatal("%.200s line %d: Bad escape character.",
1377511b41d2SMark Murray 			    filename, linenum);
1378511b41d2SMark Murray 			/* NOTREACHED */
1379511b41d2SMark Murray 			value = 0;	/* Avoid compiler warning. */
1380511b41d2SMark Murray 		}
1381511b41d2SMark Murray 		if (*activep && *intptr == -1)
1382511b41d2SMark Murray 			*intptr = value;
1383511b41d2SMark Murray 		break;
1384511b41d2SMark Murray 
1385cf2b5f3bSDag-Erling Smørgrav 	case oAddressFamily:
1386cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->address_family;
1387f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_addressfamily;
1388f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
1389cf2b5f3bSDag-Erling Smørgrav 
1390e73e9afaSDag-Erling Smørgrav 	case oEnableSSHKeysign:
1391e73e9afaSDag-Erling Smørgrav 		intptr = &options->enable_ssh_keysign;
1392e73e9afaSDag-Erling Smørgrav 		goto parse_flag;
1393e73e9afaSDag-Erling Smørgrav 
13945962c0e9SDag-Erling Smørgrav 	case oIdentitiesOnly:
13955962c0e9SDag-Erling Smørgrav 		intptr = &options->identities_only;
13965962c0e9SDag-Erling Smørgrav 		goto parse_flag;
13975962c0e9SDag-Erling Smørgrav 
13981ec0d754SDag-Erling Smørgrav 	case oServerAliveInterval:
13991ec0d754SDag-Erling Smørgrav 		intptr = &options->server_alive_interval;
14001ec0d754SDag-Erling Smørgrav 		goto parse_time;
14011ec0d754SDag-Erling Smørgrav 
14021ec0d754SDag-Erling Smørgrav 	case oServerAliveCountMax:
14031ec0d754SDag-Erling Smørgrav 		intptr = &options->server_alive_count_max;
14041ec0d754SDag-Erling Smørgrav 		goto parse_int;
14051ec0d754SDag-Erling Smørgrav 
140621e764dfSDag-Erling Smørgrav 	case oSendEnv:
140721e764dfSDag-Erling Smørgrav 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
140821e764dfSDag-Erling Smørgrav 			if (strchr(arg, '=') != NULL)
140921e764dfSDag-Erling Smørgrav 				fatal("%s line %d: Invalid environment name.",
141021e764dfSDag-Erling Smørgrav 				    filename, linenum);
1411aa49c926SDag-Erling Smørgrav 			if (!*activep)
1412aa49c926SDag-Erling Smørgrav 				continue;
1413190cef3dSDag-Erling Smørgrav 			if (*arg == '-') {
1414190cef3dSDag-Erling Smørgrav 				/* Removing an env var */
1415190cef3dSDag-Erling Smørgrav 				rm_env(options, arg, filename, linenum);
1416190cef3dSDag-Erling Smørgrav 				continue;
1417190cef3dSDag-Erling Smørgrav 			} else {
1418190cef3dSDag-Erling Smørgrav 				/* Adding an env var */
1419190cef3dSDag-Erling Smørgrav 				if (options->num_send_env >= INT_MAX)
142021e764dfSDag-Erling Smørgrav 					fatal("%s line %d: too many send env.",
142121e764dfSDag-Erling Smørgrav 					    filename, linenum);
1422190cef3dSDag-Erling Smørgrav 				options->send_env = xrecallocarray(
1423190cef3dSDag-Erling Smørgrav 				    options->send_env, options->num_send_env,
1424190cef3dSDag-Erling Smørgrav 				    options->num_send_env + 1,
1425190cef3dSDag-Erling Smørgrav 				    sizeof(*options->send_env));
142621e764dfSDag-Erling Smørgrav 				options->send_env[options->num_send_env++] =
142721e764dfSDag-Erling Smørgrav 				    xstrdup(arg);
142821e764dfSDag-Erling Smørgrav 			}
1429190cef3dSDag-Erling Smørgrav 		}
1430190cef3dSDag-Erling Smørgrav 		break;
1431190cef3dSDag-Erling Smørgrav 
1432190cef3dSDag-Erling Smørgrav 	case oSetEnv:
1433190cef3dSDag-Erling Smørgrav 		value = options->num_setenv;
1434190cef3dSDag-Erling Smørgrav 		while ((arg = strdelimw(&s)) != NULL && *arg != '\0') {
1435190cef3dSDag-Erling Smørgrav 			if (strchr(arg, '=') == NULL)
1436190cef3dSDag-Erling Smørgrav 				fatal("%s line %d: Invalid SetEnv.",
1437190cef3dSDag-Erling Smørgrav 				    filename, linenum);
1438190cef3dSDag-Erling Smørgrav 			if (!*activep || value != 0)
1439190cef3dSDag-Erling Smørgrav 				continue;
1440190cef3dSDag-Erling Smørgrav 			/* Adding a setenv var */
1441190cef3dSDag-Erling Smørgrav 			if (options->num_setenv >= INT_MAX)
1442190cef3dSDag-Erling Smørgrav 				fatal("%s line %d: too many SetEnv.",
1443190cef3dSDag-Erling Smørgrav 				    filename, linenum);
1444190cef3dSDag-Erling Smørgrav 			options->setenv = xrecallocarray(
1445190cef3dSDag-Erling Smørgrav 			    options->setenv, options->num_setenv,
1446190cef3dSDag-Erling Smørgrav 			    options->num_setenv + 1, sizeof(*options->setenv));
1447190cef3dSDag-Erling Smørgrav 			options->setenv[options->num_setenv++] = xstrdup(arg);
1448190cef3dSDag-Erling Smørgrav 		}
144921e764dfSDag-Erling Smørgrav 		break;
145021e764dfSDag-Erling Smørgrav 
145121e764dfSDag-Erling Smørgrav 	case oControlPath:
145221e764dfSDag-Erling Smørgrav 		charptr = &options->control_path;
145321e764dfSDag-Erling Smørgrav 		goto parse_string;
145421e764dfSDag-Erling Smørgrav 
145521e764dfSDag-Erling Smørgrav 	case oControlMaster:
145621e764dfSDag-Erling Smørgrav 		intptr = &options->control_master;
1457f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_controlmaster;
1458f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
145921e764dfSDag-Erling Smørgrav 
1460e2f6069cSDag-Erling Smørgrav 	case oControlPersist:
1461e2f6069cSDag-Erling Smørgrav 		/* no/false/yes/true, or a time spec */
1462e2f6069cSDag-Erling Smørgrav 		intptr = &options->control_persist;
1463e2f6069cSDag-Erling Smørgrav 		arg = strdelim(&s);
1464e2f6069cSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1465e2f6069cSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing ControlPersist"
1466e2f6069cSDag-Erling Smørgrav 			    " argument.", filename, linenum);
1467e2f6069cSDag-Erling Smørgrav 		value = 0;
1468e2f6069cSDag-Erling Smørgrav 		value2 = 0;	/* timeout */
1469e2f6069cSDag-Erling Smørgrav 		if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1470e2f6069cSDag-Erling Smørgrav 			value = 0;
1471e2f6069cSDag-Erling Smørgrav 		else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1472e2f6069cSDag-Erling Smørgrav 			value = 1;
1473e2f6069cSDag-Erling Smørgrav 		else if ((value2 = convtime(arg)) >= 0)
1474e2f6069cSDag-Erling Smørgrav 			value = 1;
1475e2f6069cSDag-Erling Smørgrav 		else
1476e2f6069cSDag-Erling Smørgrav 			fatal("%.200s line %d: Bad ControlPersist argument.",
1477e2f6069cSDag-Erling Smørgrav 			    filename, linenum);
1478e2f6069cSDag-Erling Smørgrav 		if (*activep && *intptr == -1) {
1479e2f6069cSDag-Erling Smørgrav 			*intptr = value;
1480e2f6069cSDag-Erling Smørgrav 			options->control_persist_timeout = value2;
1481e2f6069cSDag-Erling Smørgrav 		}
1482e2f6069cSDag-Erling Smørgrav 		break;
1483e2f6069cSDag-Erling Smørgrav 
1484aa49c926SDag-Erling Smørgrav 	case oHashKnownHosts:
1485aa49c926SDag-Erling Smørgrav 		intptr = &options->hash_known_hosts;
1486aa49c926SDag-Erling Smørgrav 		goto parse_flag;
1487aa49c926SDag-Erling Smørgrav 
1488b74df5b2SDag-Erling Smørgrav 	case oTunnel:
1489b74df5b2SDag-Erling Smørgrav 		intptr = &options->tun_open;
1490f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_tunnel;
1491f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
1492b74df5b2SDag-Erling Smørgrav 
1493b74df5b2SDag-Erling Smørgrav 	case oTunnelDevice:
1494b74df5b2SDag-Erling Smørgrav 		arg = strdelim(&s);
1495b74df5b2SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1496b74df5b2SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1497b74df5b2SDag-Erling Smørgrav 		value = a2tun(arg, &value2);
1498b74df5b2SDag-Erling Smørgrav 		if (value == SSH_TUNID_ERR)
1499b74df5b2SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad tun device.", filename, linenum);
1500b74df5b2SDag-Erling Smørgrav 		if (*activep) {
1501b74df5b2SDag-Erling Smørgrav 			options->tun_local = value;
1502b74df5b2SDag-Erling Smørgrav 			options->tun_remote = value2;
1503b74df5b2SDag-Erling Smørgrav 		}
1504b74df5b2SDag-Erling Smørgrav 		break;
1505b74df5b2SDag-Erling Smørgrav 
1506b74df5b2SDag-Erling Smørgrav 	case oLocalCommand:
1507b74df5b2SDag-Erling Smørgrav 		charptr = &options->local_command;
1508b74df5b2SDag-Erling Smørgrav 		goto parse_command;
1509b74df5b2SDag-Erling Smørgrav 
1510b74df5b2SDag-Erling Smørgrav 	case oPermitLocalCommand:
1511b74df5b2SDag-Erling Smørgrav 		intptr = &options->permit_local_command;
1512b74df5b2SDag-Erling Smørgrav 		goto parse_flag;
1513b74df5b2SDag-Erling Smørgrav 
15144f52dfbbSDag-Erling Smørgrav 	case oRemoteCommand:
15154f52dfbbSDag-Erling Smørgrav 		charptr = &options->remote_command;
15164f52dfbbSDag-Erling Smørgrav 		goto parse_command;
15174f52dfbbSDag-Erling Smørgrav 
1518d4af9e69SDag-Erling Smørgrav 	case oVisualHostKey:
1519d4af9e69SDag-Erling Smørgrav 		intptr = &options->visual_host_key;
1520d4af9e69SDag-Erling Smørgrav 		goto parse_flag;
1521d4af9e69SDag-Erling Smørgrav 
1522076ad2f8SDag-Erling Smørgrav 	case oInclude:
1523076ad2f8SDag-Erling Smørgrav 		if (cmdline)
1524076ad2f8SDag-Erling Smørgrav 			fatal("Include directive not supported as a "
1525076ad2f8SDag-Erling Smørgrav 			    "command-line option");
1526076ad2f8SDag-Erling Smørgrav 		value = 0;
1527076ad2f8SDag-Erling Smørgrav 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1528076ad2f8SDag-Erling Smørgrav 			/*
1529076ad2f8SDag-Erling Smørgrav 			 * Ensure all paths are anchored. User configuration
1530076ad2f8SDag-Erling Smørgrav 			 * files may begin with '~/' but system configurations
1531076ad2f8SDag-Erling Smørgrav 			 * must not. If the path is relative, then treat it
1532076ad2f8SDag-Erling Smørgrav 			 * as living in ~/.ssh for user configurations or
1533076ad2f8SDag-Erling Smørgrav 			 * /etc/ssh for system ones.
1534076ad2f8SDag-Erling Smørgrav 			 */
1535076ad2f8SDag-Erling Smørgrav 			if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0)
1536076ad2f8SDag-Erling Smørgrav 				fatal("%.200s line %d: bad include path %s.",
1537076ad2f8SDag-Erling Smørgrav 				    filename, linenum, arg);
1538076ad2f8SDag-Erling Smørgrav 			if (*arg != '/' && *arg != '~') {
1539076ad2f8SDag-Erling Smørgrav 				xasprintf(&arg2, "%s/%s",
1540076ad2f8SDag-Erling Smørgrav 				    (flags & SSHCONF_USERCONF) ?
1541076ad2f8SDag-Erling Smørgrav 				    "~/" _PATH_SSH_USER_DIR : SSHDIR, arg);
1542076ad2f8SDag-Erling Smørgrav 			} else
1543076ad2f8SDag-Erling Smørgrav 				arg2 = xstrdup(arg);
1544076ad2f8SDag-Erling Smørgrav 			memset(&gl, 0, sizeof(gl));
1545076ad2f8SDag-Erling Smørgrav 			r = glob(arg2, GLOB_TILDE, NULL, &gl);
1546076ad2f8SDag-Erling Smørgrav 			if (r == GLOB_NOMATCH) {
1547076ad2f8SDag-Erling Smørgrav 				debug("%.200s line %d: include %s matched no "
1548076ad2f8SDag-Erling Smørgrav 				    "files",filename, linenum, arg2);
1549d93a896eSDag-Erling Smørgrav 				free(arg2);
1550076ad2f8SDag-Erling Smørgrav 				continue;
1551076ad2f8SDag-Erling Smørgrav 			} else if (r != 0 || gl.gl_pathc < 0)
1552076ad2f8SDag-Erling Smørgrav 				fatal("%.200s line %d: glob failed for %s.",
1553076ad2f8SDag-Erling Smørgrav 				    filename, linenum, arg2);
1554076ad2f8SDag-Erling Smørgrav 			free(arg2);
1555076ad2f8SDag-Erling Smørgrav 			oactive = *activep;
1556076ad2f8SDag-Erling Smørgrav 			for (i = 0; i < (u_int)gl.gl_pathc; i++) {
1557076ad2f8SDag-Erling Smørgrav 				debug3("%.200s line %d: Including file %s "
1558076ad2f8SDag-Erling Smørgrav 				    "depth %d%s", filename, linenum,
1559076ad2f8SDag-Erling Smørgrav 				    gl.gl_pathv[i], depth,
1560076ad2f8SDag-Erling Smørgrav 				    oactive ? "" : " (parse only)");
1561076ad2f8SDag-Erling Smørgrav 				r = read_config_file_depth(gl.gl_pathv[i],
1562076ad2f8SDag-Erling Smørgrav 				    pw, host, original_host, options,
1563076ad2f8SDag-Erling Smørgrav 				    flags | SSHCONF_CHECKPERM |
1564076ad2f8SDag-Erling Smørgrav 				    (oactive ? 0 : SSHCONF_NEVERMATCH),
1565076ad2f8SDag-Erling Smørgrav 				    activep, depth + 1);
1566d93a896eSDag-Erling Smørgrav 				if (r != 1 && errno != ENOENT) {
1567d93a896eSDag-Erling Smørgrav 					fatal("Can't open user config file "
1568d93a896eSDag-Erling Smørgrav 					    "%.100s: %.100s", gl.gl_pathv[i],
1569d93a896eSDag-Erling Smørgrav 					    strerror(errno));
1570d93a896eSDag-Erling Smørgrav 				}
1571076ad2f8SDag-Erling Smørgrav 				/*
1572076ad2f8SDag-Erling Smørgrav 				 * don't let Match in includes clobber the
1573076ad2f8SDag-Erling Smørgrav 				 * containing file's Match state.
1574076ad2f8SDag-Erling Smørgrav 				 */
1575076ad2f8SDag-Erling Smørgrav 				*activep = oactive;
1576076ad2f8SDag-Erling Smørgrav 				if (r != 1)
1577076ad2f8SDag-Erling Smørgrav 					value = -1;
1578076ad2f8SDag-Erling Smørgrav 			}
1579076ad2f8SDag-Erling Smørgrav 			globfree(&gl);
1580076ad2f8SDag-Erling Smørgrav 		}
1581076ad2f8SDag-Erling Smørgrav 		if (value != 0)
1582076ad2f8SDag-Erling Smørgrav 			return value;
1583076ad2f8SDag-Erling Smørgrav 		break;
1584076ad2f8SDag-Erling Smørgrav 
15854a421b63SDag-Erling Smørgrav 	case oIPQoS:
15864a421b63SDag-Erling Smørgrav 		arg = strdelim(&s);
15874a421b63SDag-Erling Smørgrav 		if ((value = parse_ipqos(arg)) == -1)
15884a421b63SDag-Erling Smørgrav 			fatal("%s line %d: Bad IPQoS value: %s",
15894a421b63SDag-Erling Smørgrav 			    filename, linenum, arg);
15904a421b63SDag-Erling Smørgrav 		arg = strdelim(&s);
15914a421b63SDag-Erling Smørgrav 		if (arg == NULL)
15924a421b63SDag-Erling Smørgrav 			value2 = value;
15934a421b63SDag-Erling Smørgrav 		else if ((value2 = parse_ipqos(arg)) == -1)
15944a421b63SDag-Erling Smørgrav 			fatal("%s line %d: Bad IPQoS value: %s",
15954a421b63SDag-Erling Smørgrav 			    filename, linenum, arg);
15964a421b63SDag-Erling Smørgrav 		if (*activep) {
15974a421b63SDag-Erling Smørgrav 			options->ip_qos_interactive = value;
15984a421b63SDag-Erling Smørgrav 			options->ip_qos_bulk = value2;
15994a421b63SDag-Erling Smørgrav 		}
16004a421b63SDag-Erling Smørgrav 		break;
16014a421b63SDag-Erling Smørgrav 
1602e146993eSDag-Erling Smørgrav 	case oRequestTTY:
1603e146993eSDag-Erling Smørgrav 		intptr = &options->request_tty;
1604f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_requesttty;
1605f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
1606975616f0SDag-Erling Smørgrav 
1607e146993eSDag-Erling Smørgrav 	case oVersionAddendum:
1608462c32cbSDag-Erling Smørgrav 		if (s == NULL)
1609462c32cbSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename,
1610462c32cbSDag-Erling Smørgrav 			    linenum);
1611462c32cbSDag-Erling Smørgrav 		len = strspn(s, WHITESPACE);
1612462c32cbSDag-Erling Smørgrav 		if (*activep && options->version_addendum == NULL) {
1613462c32cbSDag-Erling Smørgrav 			if (strcasecmp(s + len, "none") == 0)
1614462c32cbSDag-Erling Smørgrav 				options->version_addendum = xstrdup("");
1615462c32cbSDag-Erling Smørgrav 			else if (strchr(s + len, '\r') != NULL)
1616462c32cbSDag-Erling Smørgrav 				fatal("%.200s line %d: Invalid argument",
1617462c32cbSDag-Erling Smørgrav 				    filename, linenum);
1618462c32cbSDag-Erling Smørgrav 			else
1619462c32cbSDag-Erling Smørgrav 				options->version_addendum = xstrdup(s + len);
1620462c32cbSDag-Erling Smørgrav 		}
1621462c32cbSDag-Erling Smørgrav 		return 0;
1622e146993eSDag-Erling Smørgrav 
1623e4a9863fSDag-Erling Smørgrav 	case oIgnoreUnknown:
1624e4a9863fSDag-Erling Smørgrav 		charptr = &options->ignored_unknown;
1625e4a9863fSDag-Erling Smørgrav 		goto parse_string;
1626e4a9863fSDag-Erling Smørgrav 
1627f7167e0eSDag-Erling Smørgrav 	case oProxyUseFdpass:
1628f7167e0eSDag-Erling Smørgrav 		intptr = &options->proxy_use_fdpass;
1629f7167e0eSDag-Erling Smørgrav 		goto parse_flag;
1630f7167e0eSDag-Erling Smørgrav 
1631f7167e0eSDag-Erling Smørgrav 	case oCanonicalDomains:
1632f7167e0eSDag-Erling Smørgrav 		value = options->num_canonical_domains != 0;
1633f7167e0eSDag-Erling Smørgrav 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
163447dd1d1bSDag-Erling Smørgrav 			if (!valid_domain(arg, 1, &errstr)) {
163547dd1d1bSDag-Erling Smørgrav 				fatal("%s line %d: %s", filename, linenum,
163647dd1d1bSDag-Erling Smørgrav 				    errstr);
163747dd1d1bSDag-Erling Smørgrav 			}
1638f7167e0eSDag-Erling Smørgrav 			if (!*activep || value)
1639f7167e0eSDag-Erling Smørgrav 				continue;
1640f7167e0eSDag-Erling Smørgrav 			if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
1641f7167e0eSDag-Erling Smørgrav 				fatal("%s line %d: too many hostname suffixes.",
1642f7167e0eSDag-Erling Smørgrav 				    filename, linenum);
1643f7167e0eSDag-Erling Smørgrav 			options->canonical_domains[
1644f7167e0eSDag-Erling Smørgrav 			    options->num_canonical_domains++] = xstrdup(arg);
1645f7167e0eSDag-Erling Smørgrav 		}
1646f7167e0eSDag-Erling Smørgrav 		break;
1647f7167e0eSDag-Erling Smørgrav 
1648f7167e0eSDag-Erling Smørgrav 	case oCanonicalizePermittedCNAMEs:
1649f7167e0eSDag-Erling Smørgrav 		value = options->num_permitted_cnames != 0;
1650f7167e0eSDag-Erling Smørgrav 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1651f7167e0eSDag-Erling Smørgrav 			/* Either '*' for everything or 'list:list' */
1652f7167e0eSDag-Erling Smørgrav 			if (strcmp(arg, "*") == 0)
1653f7167e0eSDag-Erling Smørgrav 				arg2 = arg;
1654f7167e0eSDag-Erling Smørgrav 			else {
1655f7167e0eSDag-Erling Smørgrav 				lowercase(arg);
1656f7167e0eSDag-Erling Smørgrav 				if ((arg2 = strchr(arg, ':')) == NULL ||
1657f7167e0eSDag-Erling Smørgrav 				    arg2[1] == '\0') {
1658f7167e0eSDag-Erling Smørgrav 					fatal("%s line %d: "
1659f7167e0eSDag-Erling Smørgrav 					    "Invalid permitted CNAME \"%s\"",
1660f7167e0eSDag-Erling Smørgrav 					    filename, linenum, arg);
1661f7167e0eSDag-Erling Smørgrav 				}
1662f7167e0eSDag-Erling Smørgrav 				*arg2 = '\0';
1663f7167e0eSDag-Erling Smørgrav 				arg2++;
1664f7167e0eSDag-Erling Smørgrav 			}
1665f7167e0eSDag-Erling Smørgrav 			if (!*activep || value)
1666f7167e0eSDag-Erling Smørgrav 				continue;
1667f7167e0eSDag-Erling Smørgrav 			if (options->num_permitted_cnames >= MAX_CANON_DOMAINS)
1668f7167e0eSDag-Erling Smørgrav 				fatal("%s line %d: too many permitted CNAMEs.",
1669f7167e0eSDag-Erling Smørgrav 				    filename, linenum);
1670f7167e0eSDag-Erling Smørgrav 			cname = options->permitted_cnames +
1671f7167e0eSDag-Erling Smørgrav 			    options->num_permitted_cnames++;
1672f7167e0eSDag-Erling Smørgrav 			cname->source_list = xstrdup(arg);
1673f7167e0eSDag-Erling Smørgrav 			cname->target_list = xstrdup(arg2);
1674f7167e0eSDag-Erling Smørgrav 		}
1675f7167e0eSDag-Erling Smørgrav 		break;
1676f7167e0eSDag-Erling Smørgrav 
1677f7167e0eSDag-Erling Smørgrav 	case oCanonicalizeHostname:
1678f7167e0eSDag-Erling Smørgrav 		intptr = &options->canonicalize_hostname;
1679f7167e0eSDag-Erling Smørgrav 		multistate_ptr = multistate_canonicalizehostname;
1680f7167e0eSDag-Erling Smørgrav 		goto parse_multistate;
1681f7167e0eSDag-Erling Smørgrav 
1682f7167e0eSDag-Erling Smørgrav 	case oCanonicalizeMaxDots:
1683f7167e0eSDag-Erling Smørgrav 		intptr = &options->canonicalize_max_dots;
1684f7167e0eSDag-Erling Smørgrav 		goto parse_int;
1685f7167e0eSDag-Erling Smørgrav 
1686f7167e0eSDag-Erling Smørgrav 	case oCanonicalizeFallbackLocal:
1687f7167e0eSDag-Erling Smørgrav 		intptr = &options->canonicalize_fallback_local;
1688f7167e0eSDag-Erling Smørgrav 		goto parse_flag;
1689f7167e0eSDag-Erling Smørgrav 
1690a0ee8cc6SDag-Erling Smørgrav 	case oStreamLocalBindMask:
1691a0ee8cc6SDag-Erling Smørgrav 		arg = strdelim(&s);
1692a0ee8cc6SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1693a0ee8cc6SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum);
1694a0ee8cc6SDag-Erling Smørgrav 		/* Parse mode in octal format */
1695a0ee8cc6SDag-Erling Smørgrav 		value = strtol(arg, &endofnumber, 8);
1696a0ee8cc6SDag-Erling Smørgrav 		if (arg == endofnumber || value < 0 || value > 0777)
1697a0ee8cc6SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad mask.", filename, linenum);
1698a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
1699a0ee8cc6SDag-Erling Smørgrav 		break;
1700a0ee8cc6SDag-Erling Smørgrav 
1701a0ee8cc6SDag-Erling Smørgrav 	case oStreamLocalBindUnlink:
1702a0ee8cc6SDag-Erling Smørgrav 		intptr = &options->fwd_opts.streamlocal_bind_unlink;
1703a0ee8cc6SDag-Erling Smørgrav 		goto parse_flag;
1704a0ee8cc6SDag-Erling Smørgrav 
1705bc5531deSDag-Erling Smørgrav 	case oRevokedHostKeys:
1706bc5531deSDag-Erling Smørgrav 		charptr = &options->revoked_host_keys;
1707bc5531deSDag-Erling Smørgrav 		goto parse_string;
1708bc5531deSDag-Erling Smørgrav 
1709bc5531deSDag-Erling Smørgrav 	case oFingerprintHash:
1710bc5531deSDag-Erling Smørgrav 		intptr = &options->fingerprint_hash;
1711bc5531deSDag-Erling Smørgrav 		arg = strdelim(&s);
1712bc5531deSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
1713bc5531deSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.",
1714bc5531deSDag-Erling Smørgrav 			    filename, linenum);
1715bc5531deSDag-Erling Smørgrav 		if ((value = ssh_digest_alg_by_name(arg)) == -1)
1716bc5531deSDag-Erling Smørgrav 			fatal("%.200s line %d: Invalid hash algorithm \"%s\".",
1717bc5531deSDag-Erling Smørgrav 			    filename, linenum, arg);
1718bc5531deSDag-Erling Smørgrav 		if (*activep && *intptr == -1)
1719bc5531deSDag-Erling Smørgrav 			*intptr = value;
1720bc5531deSDag-Erling Smørgrav 		break;
1721bc5531deSDag-Erling Smørgrav 
1722bc5531deSDag-Erling Smørgrav 	case oUpdateHostkeys:
1723bc5531deSDag-Erling Smørgrav 		intptr = &options->update_hostkeys;
1724bc5531deSDag-Erling Smørgrav 		multistate_ptr = multistate_yesnoask;
1725bc5531deSDag-Erling Smørgrav 		goto parse_multistate;
1726bc5531deSDag-Erling Smørgrav 
1727bc5531deSDag-Erling Smørgrav 	case oHostbasedKeyTypes:
1728bc5531deSDag-Erling Smørgrav 		charptr = &options->hostbased_key_types;
1729eccfee6eSDag-Erling Smørgrav 		goto parse_keytypes;
1730eccfee6eSDag-Erling Smørgrav 
1731eccfee6eSDag-Erling Smørgrav 	case oPubkeyAcceptedKeyTypes:
1732eccfee6eSDag-Erling Smørgrav 		charptr = &options->pubkey_key_types;
1733eccfee6eSDag-Erling Smørgrav 		goto parse_keytypes;
1734bc5531deSDag-Erling Smørgrav 
1735acc1a9efSDag-Erling Smørgrav 	case oAddKeysToAgent:
1736acc1a9efSDag-Erling Smørgrav 		intptr = &options->add_keys_to_agent;
1737acc1a9efSDag-Erling Smørgrav 		multistate_ptr = multistate_yesnoaskconfirm;
1738acc1a9efSDag-Erling Smørgrav 		goto parse_multistate;
1739acc1a9efSDag-Erling Smørgrav 
1740076ad2f8SDag-Erling Smørgrav 	case oIdentityAgent:
1741076ad2f8SDag-Erling Smørgrav 		charptr = &options->identity_agent;
17422f513db7SEd Maste 		arg = strdelim(&s);
17432f513db7SEd Maste 		if (!arg || *arg == '\0')
17442f513db7SEd Maste 			fatal("%.200s line %d: Missing argument.",
17452f513db7SEd Maste 			    filename, linenum);
17462f513db7SEd Maste 		/* Extra validation if the string represents an env var. */
17472f513db7SEd Maste 		if (arg[0] == '$' && !valid_env_name(arg + 1)) {
17482f513db7SEd Maste 			fatal("%.200s line %d: Invalid environment name %s.",
17492f513db7SEd Maste 			    filename, linenum, arg);
17502f513db7SEd Maste 		}
17512f513db7SEd Maste 		if (*activep && *charptr == NULL)
17522f513db7SEd Maste 			*charptr = xstrdup(arg);
17532f513db7SEd Maste 		break;
1754076ad2f8SDag-Erling Smørgrav 
175580628bacSDag-Erling Smørgrav 	case oDeprecated:
175680628bacSDag-Erling Smørgrav 		debug("%s line %d: Deprecated option \"%s\"",
175780628bacSDag-Erling Smørgrav 		    filename, linenum, keyword);
175880628bacSDag-Erling Smørgrav 		return 0;
175980628bacSDag-Erling Smørgrav 
1760cf2b5f3bSDag-Erling Smørgrav 	case oUnsupported:
1761cf2b5f3bSDag-Erling Smørgrav 		error("%s line %d: Unsupported option \"%s\"",
1762cf2b5f3bSDag-Erling Smørgrav 		    filename, linenum, keyword);
1763cf2b5f3bSDag-Erling Smørgrav 		return 0;
1764cf2b5f3bSDag-Erling Smørgrav 
1765511b41d2SMark Murray 	default:
1766bc5531deSDag-Erling Smørgrav 		fatal("%s: Unimplemented opcode %d", __func__, opcode);
1767511b41d2SMark Murray 	}
1768511b41d2SMark Murray 
1769511b41d2SMark Murray 	/* Check that there is no garbage at end of line. */
1770ca3176e7SBrian Feldman 	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1771c2d3a559SKris Kennaway 		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
1772c2d3a559SKris Kennaway 		    filename, linenum, arg);
1773c2d3a559SKris Kennaway 	}
1774511b41d2SMark Murray 	return 0;
1775511b41d2SMark Murray }
1776511b41d2SMark Murray 
1777511b41d2SMark Murray /*
1778511b41d2SMark Murray  * Reads the config file and modifies the options accordingly.  Options
1779511b41d2SMark Murray  * should already be initialized before this call.  This never returns if
1780af12a3e7SDag-Erling Smørgrav  * there is an error.  If the file does not exist, this returns 0.
1781511b41d2SMark Murray  */
1782af12a3e7SDag-Erling Smørgrav int
1783f7167e0eSDag-Erling Smørgrav read_config_file(const char *filename, struct passwd *pw, const char *host,
1784bc5531deSDag-Erling Smørgrav     const char *original_host, Options *options, int flags)
1785511b41d2SMark Murray {
1786076ad2f8SDag-Erling Smørgrav 	int active = 1;
1787076ad2f8SDag-Erling Smørgrav 
1788076ad2f8SDag-Erling Smørgrav 	return read_config_file_depth(filename, pw, host, original_host,
1789076ad2f8SDag-Erling Smørgrav 	    options, flags, &active, 0);
1790076ad2f8SDag-Erling Smørgrav }
1791076ad2f8SDag-Erling Smørgrav 
1792076ad2f8SDag-Erling Smørgrav #define READCONF_MAX_DEPTH	16
1793076ad2f8SDag-Erling Smørgrav static int
1794076ad2f8SDag-Erling Smørgrav read_config_file_depth(const char *filename, struct passwd *pw,
1795076ad2f8SDag-Erling Smørgrav     const char *host, const char *original_host, Options *options,
1796076ad2f8SDag-Erling Smørgrav     int flags, int *activep, int depth)
1797076ad2f8SDag-Erling Smørgrav {
1798511b41d2SMark Murray 	FILE *f;
1799190cef3dSDag-Erling Smørgrav 	char *line = NULL;
1800190cef3dSDag-Erling Smørgrav 	size_t linesize = 0;
1801076ad2f8SDag-Erling Smørgrav 	int linenum;
1802511b41d2SMark Murray 	int bad_options = 0;
1803511b41d2SMark Murray 
1804076ad2f8SDag-Erling Smørgrav 	if (depth < 0 || depth > READCONF_MAX_DEPTH)
1805076ad2f8SDag-Erling Smørgrav 		fatal("Too many recursive configuration includes");
1806076ad2f8SDag-Erling Smørgrav 
180721e764dfSDag-Erling Smørgrav 	if ((f = fopen(filename, "r")) == NULL)
1808af12a3e7SDag-Erling Smørgrav 		return 0;
1809511b41d2SMark Murray 
181073370613SDag-Erling Smørgrav 	if (flags & SSHCONF_CHECKPERM) {
181121e764dfSDag-Erling Smørgrav 		struct stat sb;
181221e764dfSDag-Erling Smørgrav 
181321e764dfSDag-Erling Smørgrav 		if (fstat(fileno(f), &sb) == -1)
181421e764dfSDag-Erling Smørgrav 			fatal("fstat %s: %s", filename, strerror(errno));
181521e764dfSDag-Erling Smørgrav 		if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
181621e764dfSDag-Erling Smørgrav 		    (sb.st_mode & 022) != 0))
181721e764dfSDag-Erling Smørgrav 			fatal("Bad owner or permissions on %s", filename);
181821e764dfSDag-Erling Smørgrav 	}
181921e764dfSDag-Erling Smørgrav 
1820511b41d2SMark Murray 	debug("Reading configuration data %.200s", filename);
1821511b41d2SMark Murray 
1822511b41d2SMark Murray 	/*
1823511b41d2SMark Murray 	 * Mark that we are now processing the options.  This flag is turned
1824511b41d2SMark Murray 	 * on/off by Host specifications.
1825511b41d2SMark Murray 	 */
1826511b41d2SMark Murray 	linenum = 0;
1827190cef3dSDag-Erling Smørgrav 	while (getline(&line, &linesize, f) != -1) {
1828511b41d2SMark Murray 		/* Update line number counter. */
1829511b41d2SMark Murray 		linenum++;
1830076ad2f8SDag-Erling Smørgrav 		if (process_config_line_depth(options, pw, host, original_host,
1831076ad2f8SDag-Erling Smørgrav 		    line, filename, linenum, activep, flags, depth) != 0)
1832511b41d2SMark Murray 			bad_options++;
1833511b41d2SMark Murray 	}
1834190cef3dSDag-Erling Smørgrav 	free(line);
1835511b41d2SMark Murray 	fclose(f);
1836511b41d2SMark Murray 	if (bad_options > 0)
1837ca3176e7SBrian Feldman 		fatal("%s: terminating, %d bad configuration options",
1838511b41d2SMark Murray 		    filename, bad_options);
1839af12a3e7SDag-Erling Smørgrav 	return 1;
1840511b41d2SMark Murray }
1841511b41d2SMark Murray 
1842b83788ffSDag-Erling Smørgrav /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
1843b83788ffSDag-Erling Smørgrav int
1844b83788ffSDag-Erling Smørgrav option_clear_or_none(const char *o)
1845b83788ffSDag-Erling Smørgrav {
1846b83788ffSDag-Erling Smørgrav 	return o == NULL || strcasecmp(o, "none") == 0;
1847b83788ffSDag-Erling Smørgrav }
1848b83788ffSDag-Erling Smørgrav 
1849511b41d2SMark Murray /*
1850511b41d2SMark Murray  * Initializes options to special values that indicate that they have not yet
1851511b41d2SMark Murray  * been set.  Read_config_file will only set options with this value. Options
1852511b41d2SMark Murray  * are processed in the following order: command line, user config file,
1853511b41d2SMark Murray  * system config file.  Last, fill_default_options is called.
1854511b41d2SMark Murray  */
1855511b41d2SMark Murray 
1856511b41d2SMark Murray void
1857511b41d2SMark Murray initialize_options(Options * options)
1858511b41d2SMark Murray {
1859511b41d2SMark Murray 	memset(options, 'X', sizeof(*options));
1860eccfee6eSDag-Erling Smørgrav 	options->version_addendum = NULL;
1861511b41d2SMark Murray 	options->forward_agent = -1;
1862511b41d2SMark Murray 	options->forward_x11 = -1;
18631ec0d754SDag-Erling Smørgrav 	options->forward_x11_trusted = -1;
1864e2f6069cSDag-Erling Smørgrav 	options->forward_x11_timeout = -1;
1865076ad2f8SDag-Erling Smørgrav 	options->stdio_forward_host = NULL;
1866076ad2f8SDag-Erling Smørgrav 	options->stdio_forward_port = 0;
1867076ad2f8SDag-Erling Smørgrav 	options->clear_forwardings = -1;
1868333ee039SDag-Erling Smørgrav 	options->exit_on_forward_failure = -1;
1869c2d3a559SKris Kennaway 	options->xauth_location = NULL;
1870a0ee8cc6SDag-Erling Smørgrav 	options->fwd_opts.gateway_ports = -1;
1871a0ee8cc6SDag-Erling Smørgrav 	options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
1872a0ee8cc6SDag-Erling Smørgrav 	options->fwd_opts.streamlocal_bind_unlink = -1;
1873ca3176e7SBrian Feldman 	options->pubkey_authentication = -1;
1874af12a3e7SDag-Erling Smørgrav 	options->challenge_response_authentication = -1;
1875cf2b5f3bSDag-Erling Smørgrav 	options->gss_authentication = -1;
1876cf2b5f3bSDag-Erling Smørgrav 	options->gss_deleg_creds = -1;
1877511b41d2SMark Murray 	options->password_authentication = -1;
187809958426SBrian Feldman 	options->kbd_interactive_authentication = -1;
187909958426SBrian Feldman 	options->kbd_interactive_devices = NULL;
1880ca3176e7SBrian Feldman 	options->hostbased_authentication = -1;
1881511b41d2SMark Murray 	options->batch_mode = -1;
1882511b41d2SMark Murray 	options->check_host_ip = -1;
1883511b41d2SMark Murray 	options->strict_host_key_checking = -1;
1884511b41d2SMark Murray 	options->compression = -1;
18851ec0d754SDag-Erling Smørgrav 	options->tcp_keep_alive = -1;
1886511b41d2SMark Murray 	options->port = -1;
1887cf2b5f3bSDag-Erling Smørgrav 	options->address_family = -1;
1888511b41d2SMark Murray 	options->connection_attempts = -1;
1889cf2b5f3bSDag-Erling Smørgrav 	options->connection_timeout = -1;
1890511b41d2SMark Murray 	options->number_of_password_prompts = -1;
1891e8aafc91SKris Kennaway 	options->ciphers = NULL;
1892ca3176e7SBrian Feldman 	options->macs = NULL;
18934a421b63SDag-Erling Smørgrav 	options->kex_algorithms = NULL;
1894ca3176e7SBrian Feldman 	options->hostkeyalgorithms = NULL;
18952f513db7SEd Maste 	options->ca_sign_algorithms = NULL;
1896511b41d2SMark Murray 	options->num_identity_files = 0;
1897acc1a9efSDag-Erling Smørgrav 	options->num_certificate_files = 0;
1898511b41d2SMark Murray 	options->hostname = NULL;
1899ca3176e7SBrian Feldman 	options->host_key_alias = NULL;
1900511b41d2SMark Murray 	options->proxy_command = NULL;
1901076ad2f8SDag-Erling Smørgrav 	options->jump_user = NULL;
1902076ad2f8SDag-Erling Smørgrav 	options->jump_host = NULL;
1903076ad2f8SDag-Erling Smørgrav 	options->jump_port = -1;
1904076ad2f8SDag-Erling Smørgrav 	options->jump_extra = NULL;
1905511b41d2SMark Murray 	options->user = NULL;
1906511b41d2SMark Murray 	options->escape_char = -1;
1907e146993eSDag-Erling Smørgrav 	options->num_system_hostfiles = 0;
1908e146993eSDag-Erling Smørgrav 	options->num_user_hostfiles = 0;
1909e2f6069cSDag-Erling Smørgrav 	options->local_forwards = NULL;
1910511b41d2SMark Murray 	options->num_local_forwards = 0;
1911e2f6069cSDag-Erling Smørgrav 	options->remote_forwards = NULL;
1912511b41d2SMark Murray 	options->num_remote_forwards = 0;
19134f52dfbbSDag-Erling Smørgrav 	options->log_facility = SYSLOG_FACILITY_NOT_SET;
1914af12a3e7SDag-Erling Smørgrav 	options->log_level = SYSLOG_LEVEL_NOT_SET;
1915ca3176e7SBrian Feldman 	options->preferred_authentications = NULL;
1916af12a3e7SDag-Erling Smørgrav 	options->bind_address = NULL;
191747dd1d1bSDag-Erling Smørgrav 	options->bind_interface = NULL;
1918b15c8340SDag-Erling Smørgrav 	options->pkcs11_provider = NULL;
1919e73e9afaSDag-Erling Smørgrav 	options->enable_ssh_keysign = - 1;
1920af12a3e7SDag-Erling Smørgrav 	options->no_host_authentication_for_localhost = - 1;
19215962c0e9SDag-Erling Smørgrav 	options->identities_only = - 1;
1922cf2b5f3bSDag-Erling Smørgrav 	options->rekey_limit = - 1;
1923e4a9863fSDag-Erling Smørgrav 	options->rekey_interval = -1;
1924cf2b5f3bSDag-Erling Smørgrav 	options->verify_host_key_dns = -1;
19251ec0d754SDag-Erling Smørgrav 	options->server_alive_interval = -1;
19261ec0d754SDag-Erling Smørgrav 	options->server_alive_count_max = -1;
1927190cef3dSDag-Erling Smørgrav 	options->send_env = NULL;
192821e764dfSDag-Erling Smørgrav 	options->num_send_env = 0;
1929190cef3dSDag-Erling Smørgrav 	options->setenv = NULL;
1930190cef3dSDag-Erling Smørgrav 	options->num_setenv = 0;
193121e764dfSDag-Erling Smørgrav 	options->control_path = NULL;
193221e764dfSDag-Erling Smørgrav 	options->control_master = -1;
1933e2f6069cSDag-Erling Smørgrav 	options->control_persist = -1;
1934e2f6069cSDag-Erling Smørgrav 	options->control_persist_timeout = 0;
1935aa49c926SDag-Erling Smørgrav 	options->hash_known_hosts = -1;
1936b74df5b2SDag-Erling Smørgrav 	options->tun_open = -1;
1937b74df5b2SDag-Erling Smørgrav 	options->tun_local = -1;
1938b74df5b2SDag-Erling Smørgrav 	options->tun_remote = -1;
1939b74df5b2SDag-Erling Smørgrav 	options->local_command = NULL;
1940b74df5b2SDag-Erling Smørgrav 	options->permit_local_command = -1;
19414f52dfbbSDag-Erling Smørgrav 	options->remote_command = NULL;
1942acc1a9efSDag-Erling Smørgrav 	options->add_keys_to_agent = -1;
1943076ad2f8SDag-Erling Smørgrav 	options->identity_agent = NULL;
1944d4af9e69SDag-Erling Smørgrav 	options->visual_host_key = -1;
19454a421b63SDag-Erling Smørgrav 	options->ip_qos_interactive = -1;
19464a421b63SDag-Erling Smørgrav 	options->ip_qos_bulk = -1;
1947e146993eSDag-Erling Smørgrav 	options->request_tty = -1;
1948f7167e0eSDag-Erling Smørgrav 	options->proxy_use_fdpass = -1;
1949e4a9863fSDag-Erling Smørgrav 	options->ignored_unknown = NULL;
1950f7167e0eSDag-Erling Smørgrav 	options->num_canonical_domains = 0;
1951f7167e0eSDag-Erling Smørgrav 	options->num_permitted_cnames = 0;
1952f7167e0eSDag-Erling Smørgrav 	options->canonicalize_max_dots = -1;
1953f7167e0eSDag-Erling Smørgrav 	options->canonicalize_fallback_local = -1;
1954f7167e0eSDag-Erling Smørgrav 	options->canonicalize_hostname = -1;
1955bc5531deSDag-Erling Smørgrav 	options->revoked_host_keys = NULL;
1956bc5531deSDag-Erling Smørgrav 	options->fingerprint_hash = -1;
1957bc5531deSDag-Erling Smørgrav 	options->update_hostkeys = -1;
1958bc5531deSDag-Erling Smørgrav 	options->hostbased_key_types = NULL;
1959eccfee6eSDag-Erling Smørgrav 	options->pubkey_key_types = NULL;
1960511b41d2SMark Murray }
1961511b41d2SMark Murray 
1962511b41d2SMark Murray /*
1963b83788ffSDag-Erling Smørgrav  * A petite version of fill_default_options() that just fills the options
1964b83788ffSDag-Erling Smørgrav  * needed for hostname canonicalization to proceed.
1965b83788ffSDag-Erling Smørgrav  */
1966b83788ffSDag-Erling Smørgrav void
1967b83788ffSDag-Erling Smørgrav fill_default_options_for_canonicalization(Options *options)
1968b83788ffSDag-Erling Smørgrav {
1969b83788ffSDag-Erling Smørgrav 	if (options->canonicalize_max_dots == -1)
1970b83788ffSDag-Erling Smørgrav 		options->canonicalize_max_dots = 1;
1971b83788ffSDag-Erling Smørgrav 	if (options->canonicalize_fallback_local == -1)
1972b83788ffSDag-Erling Smørgrav 		options->canonicalize_fallback_local = 1;
1973b83788ffSDag-Erling Smørgrav 	if (options->canonicalize_hostname == -1)
1974b83788ffSDag-Erling Smørgrav 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
1975b83788ffSDag-Erling Smørgrav }
1976b83788ffSDag-Erling Smørgrav 
1977b83788ffSDag-Erling Smørgrav /*
1978511b41d2SMark Murray  * Called after processing other sources of option data, this fills those
1979511b41d2SMark Murray  * options for which no value has been specified with their default values.
1980511b41d2SMark Murray  */
1981511b41d2SMark Murray void
1982511b41d2SMark Murray fill_default_options(Options * options)
1983511b41d2SMark Murray {
19842f513db7SEd Maste 	char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
1985190cef3dSDag-Erling Smørgrav 	int r;
198677c2fe20SDag-Erling Smørgrav #ifdef VMWARE_GUEST_WORKAROUND
198777c2fe20SDag-Erling Smørgrav 	char scval[7];	/* "vmware\0" */
198877c2fe20SDag-Erling Smørgrav 	size_t scsiz = sizeof(scval);
198977c2fe20SDag-Erling Smørgrav 	int vmwguest = 0;
199077c2fe20SDag-Erling Smørgrav 
199177c2fe20SDag-Erling Smørgrav 	if (sysctlbyname("kern.vm_guest", scval, &scsiz, NULL, 0) == 0 &&
199277c2fe20SDag-Erling Smørgrav 	    strcmp(scval, "vmware") == 0)
199377c2fe20SDag-Erling Smørgrav 		vmwguest = 1;
199477c2fe20SDag-Erling Smørgrav #endif
1995190cef3dSDag-Erling Smørgrav 
1996511b41d2SMark Murray 	if (options->forward_agent == -1)
1997db1cb46cSKris Kennaway 		options->forward_agent = 0;
1998511b41d2SMark Murray 	if (options->forward_x11 == -1)
19995dc73ebeSBrian Feldman 		options->forward_x11 = 0;
20001ec0d754SDag-Erling Smørgrav 	if (options->forward_x11_trusted == -1)
20011ec0d754SDag-Erling Smørgrav 		options->forward_x11_trusted = 0;
2002e2f6069cSDag-Erling Smørgrav 	if (options->forward_x11_timeout == -1)
2003e2f6069cSDag-Erling Smørgrav 		options->forward_x11_timeout = 1200;
2004076ad2f8SDag-Erling Smørgrav 	/*
2005076ad2f8SDag-Erling Smørgrav 	 * stdio forwarding (-W) changes the default for these but we defer
2006076ad2f8SDag-Erling Smørgrav 	 * setting the values so they can be overridden.
2007076ad2f8SDag-Erling Smørgrav 	 */
2008333ee039SDag-Erling Smørgrav 	if (options->exit_on_forward_failure == -1)
2009076ad2f8SDag-Erling Smørgrav 		options->exit_on_forward_failure =
2010076ad2f8SDag-Erling Smørgrav 		    options->stdio_forward_host != NULL ? 1 : 0;
2011076ad2f8SDag-Erling Smørgrav 	if (options->clear_forwardings == -1)
2012076ad2f8SDag-Erling Smørgrav 		options->clear_forwardings =
2013076ad2f8SDag-Erling Smørgrav 		    options->stdio_forward_host != NULL ? 1 : 0;
2014076ad2f8SDag-Erling Smørgrav 	if (options->clear_forwardings == 1)
2015076ad2f8SDag-Erling Smørgrav 		clear_forwardings(options);
2016076ad2f8SDag-Erling Smørgrav 
2017c2d3a559SKris Kennaway 	if (options->xauth_location == NULL)
2018af12a3e7SDag-Erling Smørgrav 		options->xauth_location = _PATH_XAUTH;
2019a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.gateway_ports == -1)
2020a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.gateway_ports = 0;
2021a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
2022a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.streamlocal_bind_mask = 0177;
2023a0ee8cc6SDag-Erling Smørgrav 	if (options->fwd_opts.streamlocal_bind_unlink == -1)
2024a0ee8cc6SDag-Erling Smørgrav 		options->fwd_opts.streamlocal_bind_unlink = 0;
2025ca3176e7SBrian Feldman 	if (options->pubkey_authentication == -1)
2026ca3176e7SBrian Feldman 		options->pubkey_authentication = 1;
2027af12a3e7SDag-Erling Smørgrav 	if (options->challenge_response_authentication == -1)
2028af12a3e7SDag-Erling Smørgrav 		options->challenge_response_authentication = 1;
2029cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_authentication == -1)
20301ec0d754SDag-Erling Smørgrav 		options->gss_authentication = 0;
2031cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_deleg_creds == -1)
2032cf2b5f3bSDag-Erling Smørgrav 		options->gss_deleg_creds = 0;
2033511b41d2SMark Murray 	if (options->password_authentication == -1)
2034511b41d2SMark Murray 		options->password_authentication = 1;
203509958426SBrian Feldman 	if (options->kbd_interactive_authentication == -1)
2036ca3176e7SBrian Feldman 		options->kbd_interactive_authentication = 1;
2037ca3176e7SBrian Feldman 	if (options->hostbased_authentication == -1)
2038ca3176e7SBrian Feldman 		options->hostbased_authentication = 0;
2039511b41d2SMark Murray 	if (options->batch_mode == -1)
2040511b41d2SMark Murray 		options->batch_mode = 0;
2041511b41d2SMark Murray 	if (options->check_host_ip == -1)
2042975616f0SDag-Erling Smørgrav 		options->check_host_ip = 0;
2043511b41d2SMark Murray 	if (options->strict_host_key_checking == -1)
20444f52dfbbSDag-Erling Smørgrav 		options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK;
2045511b41d2SMark Murray 	if (options->compression == -1)
2046511b41d2SMark Murray 		options->compression = 0;
20471ec0d754SDag-Erling Smørgrav 	if (options->tcp_keep_alive == -1)
20481ec0d754SDag-Erling Smørgrav 		options->tcp_keep_alive = 1;
2049511b41d2SMark Murray 	if (options->port == -1)
2050511b41d2SMark Murray 		options->port = 0;	/* Filled in ssh_connect. */
2051cf2b5f3bSDag-Erling Smørgrav 	if (options->address_family == -1)
2052cf2b5f3bSDag-Erling Smørgrav 		options->address_family = AF_UNSPEC;
2053511b41d2SMark Murray 	if (options->connection_attempts == -1)
2054af12a3e7SDag-Erling Smørgrav 		options->connection_attempts = 1;
2055511b41d2SMark Murray 	if (options->number_of_password_prompts == -1)
2056511b41d2SMark Murray 		options->number_of_password_prompts = 3;
2057ca3176e7SBrian Feldman 	/* options->hostkeyalgorithms, default set in myproposals.h */
2058acc1a9efSDag-Erling Smørgrav 	if (options->add_keys_to_agent == -1)
2059acc1a9efSDag-Erling Smørgrav 		options->add_keys_to_agent = 0;
2060511b41d2SMark Murray 	if (options->num_identity_files == 0) {
20614f52dfbbSDag-Erling Smørgrav 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0);
20624f52dfbbSDag-Erling Smørgrav 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0);
20634a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
20644f52dfbbSDag-Erling Smørgrav 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
20654a421b63SDag-Erling Smørgrav #endif
2066f7167e0eSDag-Erling Smørgrav 		add_identity_file(options, "~/",
2067f7167e0eSDag-Erling Smørgrav 		    _PATH_SSH_CLIENT_ID_ED25519, 0);
206847dd1d1bSDag-Erling Smørgrav 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0);
2069ca3176e7SBrian Feldman 	}
2070511b41d2SMark Murray 	if (options->escape_char == -1)
2071511b41d2SMark Murray 		options->escape_char = '~';
2072e146993eSDag-Erling Smørgrav 	if (options->num_system_hostfiles == 0) {
2073e146993eSDag-Erling Smørgrav 		options->system_hostfiles[options->num_system_hostfiles++] =
2074e146993eSDag-Erling Smørgrav 		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
2075e146993eSDag-Erling Smørgrav 		options->system_hostfiles[options->num_system_hostfiles++] =
2076e146993eSDag-Erling Smørgrav 		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
2077e146993eSDag-Erling Smørgrav 	}
2078e146993eSDag-Erling Smørgrav 	if (options->num_user_hostfiles == 0) {
2079e146993eSDag-Erling Smørgrav 		options->user_hostfiles[options->num_user_hostfiles++] =
2080e146993eSDag-Erling Smørgrav 		    xstrdup(_PATH_SSH_USER_HOSTFILE);
2081e146993eSDag-Erling Smørgrav 		options->user_hostfiles[options->num_user_hostfiles++] =
2082e146993eSDag-Erling Smørgrav 		    xstrdup(_PATH_SSH_USER_HOSTFILE2);
2083e146993eSDag-Erling Smørgrav 	}
2084af12a3e7SDag-Erling Smørgrav 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
2085511b41d2SMark Murray 		options->log_level = SYSLOG_LEVEL_INFO;
20864f52dfbbSDag-Erling Smørgrav 	if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
20874f52dfbbSDag-Erling Smørgrav 		options->log_facility = SYSLOG_FACILITY_USER;
2088af12a3e7SDag-Erling Smørgrav 	if (options->no_host_authentication_for_localhost == - 1)
2089af12a3e7SDag-Erling Smørgrav 		options->no_host_authentication_for_localhost = 0;
20905962c0e9SDag-Erling Smørgrav 	if (options->identities_only == -1)
20915962c0e9SDag-Erling Smørgrav 		options->identities_only = 0;
2092e73e9afaSDag-Erling Smørgrav 	if (options->enable_ssh_keysign == -1)
2093e73e9afaSDag-Erling Smørgrav 		options->enable_ssh_keysign = 0;
2094cf2b5f3bSDag-Erling Smørgrav 	if (options->rekey_limit == -1)
2095cf2b5f3bSDag-Erling Smørgrav 		options->rekey_limit = 0;
2096e4a9863fSDag-Erling Smørgrav 	if (options->rekey_interval == -1)
2097e4a9863fSDag-Erling Smørgrav 		options->rekey_interval = 0;
209883c6a524SDag-Erling Smørgrav #if HAVE_LDNS
209983c6a524SDag-Erling Smørgrav 	if (options->verify_host_key_dns == -1)
210083c6a524SDag-Erling Smørgrav 		/* automatically trust a verified SSHFP record */
210183c6a524SDag-Erling Smørgrav 		options->verify_host_key_dns = 1;
210283c6a524SDag-Erling Smørgrav #else
2103cf2b5f3bSDag-Erling Smørgrav 	if (options->verify_host_key_dns == -1)
2104cf2b5f3bSDag-Erling Smørgrav 		options->verify_host_key_dns = 0;
210583c6a524SDag-Erling Smørgrav #endif
21061ec0d754SDag-Erling Smørgrav 	if (options->server_alive_interval == -1)
21071ec0d754SDag-Erling Smørgrav 		options->server_alive_interval = 0;
21081ec0d754SDag-Erling Smørgrav 	if (options->server_alive_count_max == -1)
21091ec0d754SDag-Erling Smørgrav 		options->server_alive_count_max = 3;
211021e764dfSDag-Erling Smørgrav 	if (options->control_master == -1)
211121e764dfSDag-Erling Smørgrav 		options->control_master = 0;
2112e2f6069cSDag-Erling Smørgrav 	if (options->control_persist == -1) {
2113e2f6069cSDag-Erling Smørgrav 		options->control_persist = 0;
2114e2f6069cSDag-Erling Smørgrav 		options->control_persist_timeout = 0;
2115e2f6069cSDag-Erling Smørgrav 	}
2116aa49c926SDag-Erling Smørgrav 	if (options->hash_known_hosts == -1)
2117aa49c926SDag-Erling Smørgrav 		options->hash_known_hosts = 0;
2118b74df5b2SDag-Erling Smørgrav 	if (options->tun_open == -1)
2119b74df5b2SDag-Erling Smørgrav 		options->tun_open = SSH_TUNMODE_NO;
2120b74df5b2SDag-Erling Smørgrav 	if (options->tun_local == -1)
2121b74df5b2SDag-Erling Smørgrav 		options->tun_local = SSH_TUNID_ANY;
2122b74df5b2SDag-Erling Smørgrav 	if (options->tun_remote == -1)
2123b74df5b2SDag-Erling Smørgrav 		options->tun_remote = SSH_TUNID_ANY;
2124b74df5b2SDag-Erling Smørgrav 	if (options->permit_local_command == -1)
2125b74df5b2SDag-Erling Smørgrav 		options->permit_local_command = 0;
2126d4af9e69SDag-Erling Smørgrav 	if (options->visual_host_key == -1)
2127d4af9e69SDag-Erling Smørgrav 		options->visual_host_key = 0;
21284a421b63SDag-Erling Smørgrav 	if (options->ip_qos_interactive == -1)
212977c2fe20SDag-Erling Smørgrav #ifdef VMWARE_GUEST_WORKAROUND
213077c2fe20SDag-Erling Smørgrav 		if (vmwguest)
213177c2fe20SDag-Erling Smørgrav 			options->ip_qos_interactive = IPTOS_LOWDELAY;
213277c2fe20SDag-Erling Smørgrav 		else
213377c2fe20SDag-Erling Smørgrav #endif
2134190cef3dSDag-Erling Smørgrav 		options->ip_qos_interactive = IPTOS_DSCP_AF21;
21354a421b63SDag-Erling Smørgrav 	if (options->ip_qos_bulk == -1)
213677c2fe20SDag-Erling Smørgrav #ifdef VMWARE_GUEST_WORKAROUND
213777c2fe20SDag-Erling Smørgrav 		if (vmwguest)
213877c2fe20SDag-Erling Smørgrav 			options->ip_qos_bulk = IPTOS_THROUGHPUT;
213977c2fe20SDag-Erling Smørgrav 		else
214077c2fe20SDag-Erling Smørgrav #endif
2141190cef3dSDag-Erling Smørgrav 		options->ip_qos_bulk = IPTOS_DSCP_CS1;
2142e146993eSDag-Erling Smørgrav 	if (options->request_tty == -1)
2143e146993eSDag-Erling Smørgrav 		options->request_tty = REQUEST_TTY_AUTO;
2144f7167e0eSDag-Erling Smørgrav 	if (options->proxy_use_fdpass == -1)
2145f7167e0eSDag-Erling Smørgrav 		options->proxy_use_fdpass = 0;
2146f7167e0eSDag-Erling Smørgrav 	if (options->canonicalize_max_dots == -1)
2147f7167e0eSDag-Erling Smørgrav 		options->canonicalize_max_dots = 1;
2148f7167e0eSDag-Erling Smørgrav 	if (options->canonicalize_fallback_local == -1)
2149f7167e0eSDag-Erling Smørgrav 		options->canonicalize_fallback_local = 1;
2150f7167e0eSDag-Erling Smørgrav 	if (options->canonicalize_hostname == -1)
2151f7167e0eSDag-Erling Smørgrav 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
2152bc5531deSDag-Erling Smørgrav 	if (options->fingerprint_hash == -1)
2153bc5531deSDag-Erling Smørgrav 		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
2154bc5531deSDag-Erling Smørgrav 	if (options->update_hostkeys == -1)
2155bc5531deSDag-Erling Smørgrav 		options->update_hostkeys = 0;
2156190cef3dSDag-Erling Smørgrav 
2157190cef3dSDag-Erling Smørgrav 	/* Expand KEX name lists */
2158190cef3dSDag-Erling Smørgrav 	all_cipher = cipher_alg_list(',', 0);
2159190cef3dSDag-Erling Smørgrav 	all_mac = mac_alg_list(',');
2160190cef3dSDag-Erling Smørgrav 	all_kex = kex_alg_list(',');
2161190cef3dSDag-Erling Smørgrav 	all_key = sshkey_alg_list(0, 0, 1, ',');
21622f513db7SEd Maste 	all_sig = sshkey_alg_list(0, 1, 1, ',');
2163190cef3dSDag-Erling Smørgrav #define ASSEMBLE(what, defaults, all) \
2164190cef3dSDag-Erling Smørgrav 	do { \
2165190cef3dSDag-Erling Smørgrav 		if ((r = kex_assemble_names(&options->what, \
2166190cef3dSDag-Erling Smørgrav 		    defaults, all)) != 0) \
2167190cef3dSDag-Erling Smørgrav 			fatal("%s: %s: %s", __func__, #what, ssh_err(r)); \
2168190cef3dSDag-Erling Smørgrav 	} while (0)
2169190cef3dSDag-Erling Smørgrav 	ASSEMBLE(ciphers, KEX_SERVER_ENCRYPT, all_cipher);
2170190cef3dSDag-Erling Smørgrav 	ASSEMBLE(macs, KEX_SERVER_MAC, all_mac);
2171190cef3dSDag-Erling Smørgrav 	ASSEMBLE(kex_algorithms, KEX_SERVER_KEX, all_kex);
2172190cef3dSDag-Erling Smørgrav 	ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, all_key);
2173190cef3dSDag-Erling Smørgrav 	ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, all_key);
21742f513db7SEd Maste 	ASSEMBLE(ca_sign_algorithms, SSH_ALLOWED_CA_SIGALGS, all_sig);
2175190cef3dSDag-Erling Smørgrav #undef ASSEMBLE
2176190cef3dSDag-Erling Smørgrav 	free(all_cipher);
2177190cef3dSDag-Erling Smørgrav 	free(all_mac);
2178190cef3dSDag-Erling Smørgrav 	free(all_kex);
2179190cef3dSDag-Erling Smørgrav 	free(all_key);
21802f513db7SEd Maste 	free(all_sig);
2181bc5531deSDag-Erling Smørgrav 
2182f7167e0eSDag-Erling Smørgrav #define CLEAR_ON_NONE(v) \
2183f7167e0eSDag-Erling Smørgrav 	do { \
2184b83788ffSDag-Erling Smørgrav 		if (option_clear_or_none(v)) { \
2185f7167e0eSDag-Erling Smørgrav 			free(v); \
2186f7167e0eSDag-Erling Smørgrav 			v = NULL; \
2187f7167e0eSDag-Erling Smørgrav 		} \
2188f7167e0eSDag-Erling Smørgrav 	} while(0)
2189f7167e0eSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->local_command);
21904f52dfbbSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->remote_command);
2191f7167e0eSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->proxy_command);
2192f7167e0eSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->control_path);
2193bc5531deSDag-Erling Smørgrav 	CLEAR_ON_NONE(options->revoked_host_keys);
2194190cef3dSDag-Erling Smørgrav 	if (options->jump_host != NULL &&
2195190cef3dSDag-Erling Smørgrav 	    strcmp(options->jump_host, "none") == 0 &&
2196190cef3dSDag-Erling Smørgrav 	    options->jump_port == 0 && options->jump_user == NULL) {
2197190cef3dSDag-Erling Smørgrav 		free(options->jump_host);
2198190cef3dSDag-Erling Smørgrav 		options->jump_host = NULL;
2199190cef3dSDag-Erling Smørgrav 	}
2200076ad2f8SDag-Erling Smørgrav 	/* options->identity_agent distinguishes NULL from 'none' */
2201511b41d2SMark Murray 	/* options->user will be set in the main program if appropriate */
2202511b41d2SMark Murray 	/* options->hostname will be set in the main program if appropriate */
2203ca3176e7SBrian Feldman 	/* options->host_key_alias should not be set by default */
2204ca3176e7SBrian Feldman 	/* options->preferred_authentications will be set in ssh */
2205462c32cbSDag-Erling Smørgrav 	if (options->version_addendum == NULL)
2206462c32cbSDag-Erling Smørgrav 		options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
2207511b41d2SMark Murray }
2208aa49c926SDag-Erling Smørgrav 
2209a0ee8cc6SDag-Erling Smørgrav struct fwdarg {
2210a0ee8cc6SDag-Erling Smørgrav 	char *arg;
2211a0ee8cc6SDag-Erling Smørgrav 	int ispath;
2212a0ee8cc6SDag-Erling Smørgrav };
2213a0ee8cc6SDag-Erling Smørgrav 
2214a0ee8cc6SDag-Erling Smørgrav /*
2215a0ee8cc6SDag-Erling Smørgrav  * parse_fwd_field
2216a0ee8cc6SDag-Erling Smørgrav  * parses the next field in a port forwarding specification.
2217a0ee8cc6SDag-Erling Smørgrav  * sets fwd to the parsed field and advances p past the colon
2218a0ee8cc6SDag-Erling Smørgrav  * or sets it to NULL at end of string.
2219a0ee8cc6SDag-Erling Smørgrav  * returns 0 on success, else non-zero.
2220a0ee8cc6SDag-Erling Smørgrav  */
2221a0ee8cc6SDag-Erling Smørgrav static int
2222a0ee8cc6SDag-Erling Smørgrav parse_fwd_field(char **p, struct fwdarg *fwd)
2223a0ee8cc6SDag-Erling Smørgrav {
2224a0ee8cc6SDag-Erling Smørgrav 	char *ep, *cp = *p;
2225a0ee8cc6SDag-Erling Smørgrav 	int ispath = 0;
2226a0ee8cc6SDag-Erling Smørgrav 
2227a0ee8cc6SDag-Erling Smørgrav 	if (*cp == '\0') {
2228a0ee8cc6SDag-Erling Smørgrav 		*p = NULL;
2229a0ee8cc6SDag-Erling Smørgrav 		return -1;	/* end of string */
2230a0ee8cc6SDag-Erling Smørgrav 	}
2231a0ee8cc6SDag-Erling Smørgrav 
2232a0ee8cc6SDag-Erling Smørgrav 	/*
2233a0ee8cc6SDag-Erling Smørgrav 	 * A field escaped with square brackets is used literally.
2234a0ee8cc6SDag-Erling Smørgrav 	 * XXX - allow ']' to be escaped via backslash?
2235a0ee8cc6SDag-Erling Smørgrav 	 */
2236a0ee8cc6SDag-Erling Smørgrav 	if (*cp == '[') {
2237a0ee8cc6SDag-Erling Smørgrav 		/* find matching ']' */
2238a0ee8cc6SDag-Erling Smørgrav 		for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
2239a0ee8cc6SDag-Erling Smørgrav 			if (*ep == '/')
2240a0ee8cc6SDag-Erling Smørgrav 				ispath = 1;
2241a0ee8cc6SDag-Erling Smørgrav 		}
2242a0ee8cc6SDag-Erling Smørgrav 		/* no matching ']' or not at end of field. */
2243a0ee8cc6SDag-Erling Smørgrav 		if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
2244a0ee8cc6SDag-Erling Smørgrav 			return -1;
2245a0ee8cc6SDag-Erling Smørgrav 		/* NUL terminate the field and advance p past the colon */
2246a0ee8cc6SDag-Erling Smørgrav 		*ep++ = '\0';
2247a0ee8cc6SDag-Erling Smørgrav 		if (*ep != '\0')
2248a0ee8cc6SDag-Erling Smørgrav 			*ep++ = '\0';
2249a0ee8cc6SDag-Erling Smørgrav 		fwd->arg = cp + 1;
2250a0ee8cc6SDag-Erling Smørgrav 		fwd->ispath = ispath;
2251a0ee8cc6SDag-Erling Smørgrav 		*p = ep;
2252a0ee8cc6SDag-Erling Smørgrav 		return 0;
2253a0ee8cc6SDag-Erling Smørgrav 	}
2254a0ee8cc6SDag-Erling Smørgrav 
2255a0ee8cc6SDag-Erling Smørgrav 	for (cp = *p; *cp != '\0'; cp++) {
2256a0ee8cc6SDag-Erling Smørgrav 		switch (*cp) {
2257a0ee8cc6SDag-Erling Smørgrav 		case '\\':
2258a0ee8cc6SDag-Erling Smørgrav 			memmove(cp, cp + 1, strlen(cp + 1) + 1);
2259557f75e5SDag-Erling Smørgrav 			if (*cp == '\0')
2260557f75e5SDag-Erling Smørgrav 				return -1;
2261a0ee8cc6SDag-Erling Smørgrav 			break;
2262a0ee8cc6SDag-Erling Smørgrav 		case '/':
2263a0ee8cc6SDag-Erling Smørgrav 			ispath = 1;
2264a0ee8cc6SDag-Erling Smørgrav 			break;
2265a0ee8cc6SDag-Erling Smørgrav 		case ':':
2266a0ee8cc6SDag-Erling Smørgrav 			*cp++ = '\0';
2267a0ee8cc6SDag-Erling Smørgrav 			goto done;
2268a0ee8cc6SDag-Erling Smørgrav 		}
2269a0ee8cc6SDag-Erling Smørgrav 	}
2270a0ee8cc6SDag-Erling Smørgrav done:
2271a0ee8cc6SDag-Erling Smørgrav 	fwd->arg = *p;
2272a0ee8cc6SDag-Erling Smørgrav 	fwd->ispath = ispath;
2273a0ee8cc6SDag-Erling Smørgrav 	*p = cp;
2274a0ee8cc6SDag-Erling Smørgrav 	return 0;
2275a0ee8cc6SDag-Erling Smørgrav }
2276a0ee8cc6SDag-Erling Smørgrav 
2277aa49c926SDag-Erling Smørgrav /*
2278aa49c926SDag-Erling Smørgrav  * parse_forward
2279aa49c926SDag-Erling Smørgrav  * parses a string containing a port forwarding specification of the form:
2280cce7d346SDag-Erling Smørgrav  *   dynamicfwd == 0
2281a0ee8cc6SDag-Erling Smørgrav  *	[listenhost:]listenport|listenpath:connecthost:connectport|connectpath
2282a0ee8cc6SDag-Erling Smørgrav  *	listenpath:connectpath
2283cce7d346SDag-Erling Smørgrav  *   dynamicfwd == 1
2284cce7d346SDag-Erling Smørgrav  *	[listenhost:]listenport
2285aa49c926SDag-Erling Smørgrav  * returns number of arguments parsed or zero on error
2286aa49c926SDag-Erling Smørgrav  */
2287aa49c926SDag-Erling Smørgrav int
2288a0ee8cc6SDag-Erling Smørgrav parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
2289aa49c926SDag-Erling Smørgrav {
2290a0ee8cc6SDag-Erling Smørgrav 	struct fwdarg fwdargs[4];
2291a0ee8cc6SDag-Erling Smørgrav 	char *p, *cp;
2292aa49c926SDag-Erling Smørgrav 	int i;
2293aa49c926SDag-Erling Smørgrav 
2294a0ee8cc6SDag-Erling Smørgrav 	memset(fwd, 0, sizeof(*fwd));
2295a0ee8cc6SDag-Erling Smørgrav 	memset(fwdargs, 0, sizeof(fwdargs));
2296aa49c926SDag-Erling Smørgrav 
2297aa49c926SDag-Erling Smørgrav 	cp = p = xstrdup(fwdspec);
2298aa49c926SDag-Erling Smørgrav 
2299aa49c926SDag-Erling Smørgrav 	/* skip leading spaces */
2300f7167e0eSDag-Erling Smørgrav 	while (isspace((u_char)*cp))
2301aa49c926SDag-Erling Smørgrav 		cp++;
2302aa49c926SDag-Erling Smørgrav 
2303a0ee8cc6SDag-Erling Smørgrav 	for (i = 0; i < 4; ++i) {
2304a0ee8cc6SDag-Erling Smørgrav 		if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
2305aa49c926SDag-Erling Smørgrav 			break;
2306a0ee8cc6SDag-Erling Smørgrav 	}
2307aa49c926SDag-Erling Smørgrav 
2308cce7d346SDag-Erling Smørgrav 	/* Check for trailing garbage */
2309a0ee8cc6SDag-Erling Smørgrav 	if (cp != NULL && *cp != '\0') {
2310aa49c926SDag-Erling Smørgrav 		i = 0;	/* failure */
2311a0ee8cc6SDag-Erling Smørgrav 	}
2312aa49c926SDag-Erling Smørgrav 
2313aa49c926SDag-Erling Smørgrav 	switch (i) {
2314cce7d346SDag-Erling Smørgrav 	case 1:
2315a0ee8cc6SDag-Erling Smørgrav 		if (fwdargs[0].ispath) {
2316a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_path = xstrdup(fwdargs[0].arg);
2317a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_port = PORT_STREAMLOCAL;
2318a0ee8cc6SDag-Erling Smørgrav 		} else {
2319cce7d346SDag-Erling Smørgrav 			fwd->listen_host = NULL;
2320a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_port = a2port(fwdargs[0].arg);
2321a0ee8cc6SDag-Erling Smørgrav 		}
2322cce7d346SDag-Erling Smørgrav 		fwd->connect_host = xstrdup("socks");
2323cce7d346SDag-Erling Smørgrav 		break;
2324cce7d346SDag-Erling Smørgrav 
2325cce7d346SDag-Erling Smørgrav 	case 2:
2326a0ee8cc6SDag-Erling Smørgrav 		if (fwdargs[0].ispath && fwdargs[1].ispath) {
2327a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_path = xstrdup(fwdargs[0].arg);
2328a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_port = PORT_STREAMLOCAL;
2329a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_path = xstrdup(fwdargs[1].arg);
2330a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_port = PORT_STREAMLOCAL;
2331a0ee8cc6SDag-Erling Smørgrav 		} else if (fwdargs[1].ispath) {
2332a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_host = NULL;
2333a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_port = a2port(fwdargs[0].arg);
2334a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_path = xstrdup(fwdargs[1].arg);
2335a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_port = PORT_STREAMLOCAL;
2336a0ee8cc6SDag-Erling Smørgrav 		} else {
2337a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_host = xstrdup(fwdargs[0].arg);
2338a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_port = a2port(fwdargs[1].arg);
2339cce7d346SDag-Erling Smørgrav 			fwd->connect_host = xstrdup("socks");
2340a0ee8cc6SDag-Erling Smørgrav 		}
2341cce7d346SDag-Erling Smørgrav 		break;
2342cce7d346SDag-Erling Smørgrav 
2343aa49c926SDag-Erling Smørgrav 	case 3:
2344a0ee8cc6SDag-Erling Smørgrav 		if (fwdargs[0].ispath) {
2345a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_path = xstrdup(fwdargs[0].arg);
2346a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_port = PORT_STREAMLOCAL;
2347a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_host = xstrdup(fwdargs[1].arg);
2348a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_port = a2port(fwdargs[2].arg);
2349a0ee8cc6SDag-Erling Smørgrav 		} else if (fwdargs[2].ispath) {
2350a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_host = xstrdup(fwdargs[0].arg);
2351a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_port = a2port(fwdargs[1].arg);
2352a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_path = xstrdup(fwdargs[2].arg);
2353a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_port = PORT_STREAMLOCAL;
2354a0ee8cc6SDag-Erling Smørgrav 		} else {
2355aa49c926SDag-Erling Smørgrav 			fwd->listen_host = NULL;
2356a0ee8cc6SDag-Erling Smørgrav 			fwd->listen_port = a2port(fwdargs[0].arg);
2357a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_host = xstrdup(fwdargs[1].arg);
2358a0ee8cc6SDag-Erling Smørgrav 			fwd->connect_port = a2port(fwdargs[2].arg);
2359a0ee8cc6SDag-Erling Smørgrav 		}
2360aa49c926SDag-Erling Smørgrav 		break;
2361aa49c926SDag-Erling Smørgrav 
2362aa49c926SDag-Erling Smørgrav 	case 4:
2363a0ee8cc6SDag-Erling Smørgrav 		fwd->listen_host = xstrdup(fwdargs[0].arg);
2364a0ee8cc6SDag-Erling Smørgrav 		fwd->listen_port = a2port(fwdargs[1].arg);
2365a0ee8cc6SDag-Erling Smørgrav 		fwd->connect_host = xstrdup(fwdargs[2].arg);
2366a0ee8cc6SDag-Erling Smørgrav 		fwd->connect_port = a2port(fwdargs[3].arg);
2367aa49c926SDag-Erling Smørgrav 		break;
2368aa49c926SDag-Erling Smørgrav 	default:
2369aa49c926SDag-Erling Smørgrav 		i = 0; /* failure */
2370aa49c926SDag-Erling Smørgrav 	}
2371aa49c926SDag-Erling Smørgrav 
2372e4a9863fSDag-Erling Smørgrav 	free(p);
2373aa49c926SDag-Erling Smørgrav 
2374cce7d346SDag-Erling Smørgrav 	if (dynamicfwd) {
2375cce7d346SDag-Erling Smørgrav 		if (!(i == 1 || i == 2))
2376cce7d346SDag-Erling Smørgrav 			goto fail_free;
2377cce7d346SDag-Erling Smørgrav 	} else {
2378a0ee8cc6SDag-Erling Smørgrav 		if (!(i == 3 || i == 4)) {
2379a0ee8cc6SDag-Erling Smørgrav 			if (fwd->connect_path == NULL &&
2380a0ee8cc6SDag-Erling Smørgrav 			    fwd->listen_path == NULL)
2381cce7d346SDag-Erling Smørgrav 				goto fail_free;
2382a0ee8cc6SDag-Erling Smørgrav 		}
2383a0ee8cc6SDag-Erling Smørgrav 		if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
2384cce7d346SDag-Erling Smørgrav 			goto fail_free;
2385cce7d346SDag-Erling Smørgrav 	}
2386cce7d346SDag-Erling Smørgrav 
2387a0ee8cc6SDag-Erling Smørgrav 	if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
2388a0ee8cc6SDag-Erling Smørgrav 	    (!remotefwd && fwd->listen_port == 0))
2389aa49c926SDag-Erling Smørgrav 		goto fail_free;
2390aa49c926SDag-Erling Smørgrav 	if (fwd->connect_host != NULL &&
2391aa49c926SDag-Erling Smørgrav 	    strlen(fwd->connect_host) >= NI_MAXHOST)
2392aa49c926SDag-Erling Smørgrav 		goto fail_free;
2393a0ee8cc6SDag-Erling Smørgrav 	/* XXX - if connecting to a remote socket, max sun len may not match this host */
2394a0ee8cc6SDag-Erling Smørgrav 	if (fwd->connect_path != NULL &&
2395a0ee8cc6SDag-Erling Smørgrav 	    strlen(fwd->connect_path) >= PATH_MAX_SUN)
2396a0ee8cc6SDag-Erling Smørgrav 		goto fail_free;
2397cce7d346SDag-Erling Smørgrav 	if (fwd->listen_host != NULL &&
2398cce7d346SDag-Erling Smørgrav 	    strlen(fwd->listen_host) >= NI_MAXHOST)
2399cce7d346SDag-Erling Smørgrav 		goto fail_free;
2400a0ee8cc6SDag-Erling Smørgrav 	if (fwd->listen_path != NULL &&
2401a0ee8cc6SDag-Erling Smørgrav 	    strlen(fwd->listen_path) >= PATH_MAX_SUN)
2402a0ee8cc6SDag-Erling Smørgrav 		goto fail_free;
2403aa49c926SDag-Erling Smørgrav 
2404aa49c926SDag-Erling Smørgrav 	return (i);
2405aa49c926SDag-Erling Smørgrav 
2406aa49c926SDag-Erling Smørgrav  fail_free:
2407e4a9863fSDag-Erling Smørgrav 	free(fwd->connect_host);
2408cce7d346SDag-Erling Smørgrav 	fwd->connect_host = NULL;
2409a0ee8cc6SDag-Erling Smørgrav 	free(fwd->connect_path);
2410a0ee8cc6SDag-Erling Smørgrav 	fwd->connect_path = NULL;
2411e4a9863fSDag-Erling Smørgrav 	free(fwd->listen_host);
2412cce7d346SDag-Erling Smørgrav 	fwd->listen_host = NULL;
2413a0ee8cc6SDag-Erling Smørgrav 	free(fwd->listen_path);
2414a0ee8cc6SDag-Erling Smørgrav 	fwd->listen_path = NULL;
2415aa49c926SDag-Erling Smørgrav 	return (0);
2416aa49c926SDag-Erling Smørgrav }
2417bc5531deSDag-Erling Smørgrav 
2418076ad2f8SDag-Erling Smørgrav int
2419076ad2f8SDag-Erling Smørgrav parse_jump(const char *s, Options *o, int active)
2420076ad2f8SDag-Erling Smørgrav {
2421076ad2f8SDag-Erling Smørgrav 	char *orig, *sdup, *cp;
2422076ad2f8SDag-Erling Smørgrav 	char *host = NULL, *user = NULL;
2423076ad2f8SDag-Erling Smørgrav 	int ret = -1, port = -1, first;
2424076ad2f8SDag-Erling Smørgrav 
2425076ad2f8SDag-Erling Smørgrav 	active &= o->proxy_command == NULL && o->jump_host == NULL;
2426076ad2f8SDag-Erling Smørgrav 
2427076ad2f8SDag-Erling Smørgrav 	orig = sdup = xstrdup(s);
2428076ad2f8SDag-Erling Smørgrav 	first = active;
2429076ad2f8SDag-Erling Smørgrav 	do {
2430190cef3dSDag-Erling Smørgrav 		if (strcasecmp(s, "none") == 0)
2431190cef3dSDag-Erling Smørgrav 			break;
2432076ad2f8SDag-Erling Smørgrav 		if ((cp = strrchr(sdup, ',')) == NULL)
2433076ad2f8SDag-Erling Smørgrav 			cp = sdup; /* last */
2434076ad2f8SDag-Erling Smørgrav 		else
2435076ad2f8SDag-Erling Smørgrav 			*cp++ = '\0';
2436076ad2f8SDag-Erling Smørgrav 
2437076ad2f8SDag-Erling Smørgrav 		if (first) {
2438076ad2f8SDag-Erling Smørgrav 			/* First argument and configuration is active */
243947dd1d1bSDag-Erling Smørgrav 			if (parse_ssh_uri(cp, &user, &host, &port) == -1 ||
244047dd1d1bSDag-Erling Smørgrav 			    parse_user_host_port(cp, &user, &host, &port) != 0)
2441076ad2f8SDag-Erling Smørgrav 				goto out;
2442076ad2f8SDag-Erling Smørgrav 		} else {
2443076ad2f8SDag-Erling Smørgrav 			/* Subsequent argument or inactive configuration */
244447dd1d1bSDag-Erling Smørgrav 			if (parse_ssh_uri(cp, NULL, NULL, NULL) == -1 ||
244547dd1d1bSDag-Erling Smørgrav 			    parse_user_host_port(cp, NULL, NULL, NULL) != 0)
2446076ad2f8SDag-Erling Smørgrav 				goto out;
2447076ad2f8SDag-Erling Smørgrav 		}
2448076ad2f8SDag-Erling Smørgrav 		first = 0; /* only check syntax for subsequent hosts */
2449076ad2f8SDag-Erling Smørgrav 	} while (cp != sdup);
2450076ad2f8SDag-Erling Smørgrav 	/* success */
2451076ad2f8SDag-Erling Smørgrav 	if (active) {
2452190cef3dSDag-Erling Smørgrav 		if (strcasecmp(s, "none") == 0) {
2453190cef3dSDag-Erling Smørgrav 			o->jump_host = xstrdup("none");
2454190cef3dSDag-Erling Smørgrav 			o->jump_port = 0;
2455190cef3dSDag-Erling Smørgrav 		} else {
2456076ad2f8SDag-Erling Smørgrav 			o->jump_user = user;
2457076ad2f8SDag-Erling Smørgrav 			o->jump_host = host;
2458076ad2f8SDag-Erling Smørgrav 			o->jump_port = port;
2459076ad2f8SDag-Erling Smørgrav 			o->proxy_command = xstrdup("none");
2460076ad2f8SDag-Erling Smørgrav 			user = host = NULL;
2461076ad2f8SDag-Erling Smørgrav 			if ((cp = strrchr(s, ',')) != NULL && cp != s) {
2462076ad2f8SDag-Erling Smørgrav 				o->jump_extra = xstrdup(s);
2463076ad2f8SDag-Erling Smørgrav 				o->jump_extra[cp - s] = '\0';
2464076ad2f8SDag-Erling Smørgrav 			}
2465076ad2f8SDag-Erling Smørgrav 		}
2466190cef3dSDag-Erling Smørgrav 	}
2467076ad2f8SDag-Erling Smørgrav 	ret = 0;
2468076ad2f8SDag-Erling Smørgrav  out:
2469076ad2f8SDag-Erling Smørgrav 	free(orig);
2470076ad2f8SDag-Erling Smørgrav 	free(user);
2471076ad2f8SDag-Erling Smørgrav 	free(host);
2472076ad2f8SDag-Erling Smørgrav 	return ret;
2473076ad2f8SDag-Erling Smørgrav }
2474076ad2f8SDag-Erling Smørgrav 
247547dd1d1bSDag-Erling Smørgrav int
247647dd1d1bSDag-Erling Smørgrav parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
247747dd1d1bSDag-Erling Smørgrav {
247847dd1d1bSDag-Erling Smørgrav 	char *path;
247947dd1d1bSDag-Erling Smørgrav 	int r;
248047dd1d1bSDag-Erling Smørgrav 
248147dd1d1bSDag-Erling Smørgrav 	r = parse_uri("ssh", uri, userp, hostp, portp, &path);
248247dd1d1bSDag-Erling Smørgrav 	if (r == 0 && path != NULL)
248347dd1d1bSDag-Erling Smørgrav 		r = -1;		/* path not allowed */
248447dd1d1bSDag-Erling Smørgrav 	return r;
248547dd1d1bSDag-Erling Smørgrav }
248647dd1d1bSDag-Erling Smørgrav 
2487bc5531deSDag-Erling Smørgrav /* XXX the following is a near-vebatim copy from servconf.c; refactor */
2488bc5531deSDag-Erling Smørgrav static const char *
2489bc5531deSDag-Erling Smørgrav fmt_multistate_int(int val, const struct multistate *m)
2490bc5531deSDag-Erling Smørgrav {
2491bc5531deSDag-Erling Smørgrav 	u_int i;
2492bc5531deSDag-Erling Smørgrav 
2493bc5531deSDag-Erling Smørgrav 	for (i = 0; m[i].key != NULL; i++) {
2494bc5531deSDag-Erling Smørgrav 		if (m[i].value == val)
2495bc5531deSDag-Erling Smørgrav 			return m[i].key;
2496bc5531deSDag-Erling Smørgrav 	}
2497bc5531deSDag-Erling Smørgrav 	return "UNKNOWN";
2498bc5531deSDag-Erling Smørgrav }
2499bc5531deSDag-Erling Smørgrav 
2500bc5531deSDag-Erling Smørgrav static const char *
2501bc5531deSDag-Erling Smørgrav fmt_intarg(OpCodes code, int val)
2502bc5531deSDag-Erling Smørgrav {
2503bc5531deSDag-Erling Smørgrav 	if (val == -1)
2504bc5531deSDag-Erling Smørgrav 		return "unset";
2505bc5531deSDag-Erling Smørgrav 	switch (code) {
2506bc5531deSDag-Erling Smørgrav 	case oAddressFamily:
2507bc5531deSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_addressfamily);
2508bc5531deSDag-Erling Smørgrav 	case oVerifyHostKeyDNS:
2509bc5531deSDag-Erling Smørgrav 	case oUpdateHostkeys:
2510bc5531deSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_yesnoask);
25114f52dfbbSDag-Erling Smørgrav 	case oStrictHostKeyChecking:
25124f52dfbbSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_strict_hostkey);
2513bc5531deSDag-Erling Smørgrav 	case oControlMaster:
2514bc5531deSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_controlmaster);
2515bc5531deSDag-Erling Smørgrav 	case oTunnel:
2516bc5531deSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_tunnel);
2517bc5531deSDag-Erling Smørgrav 	case oRequestTTY:
2518bc5531deSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_requesttty);
2519bc5531deSDag-Erling Smørgrav 	case oCanonicalizeHostname:
2520bc5531deSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_canonicalizehostname);
2521190cef3dSDag-Erling Smørgrav 	case oAddKeysToAgent:
2522190cef3dSDag-Erling Smørgrav 		return fmt_multistate_int(val, multistate_yesnoaskconfirm);
2523bc5531deSDag-Erling Smørgrav 	case oFingerprintHash:
2524bc5531deSDag-Erling Smørgrav 		return ssh_digest_alg_name(val);
2525bc5531deSDag-Erling Smørgrav 	default:
2526bc5531deSDag-Erling Smørgrav 		switch (val) {
2527bc5531deSDag-Erling Smørgrav 		case 0:
2528bc5531deSDag-Erling Smørgrav 			return "no";
2529bc5531deSDag-Erling Smørgrav 		case 1:
2530bc5531deSDag-Erling Smørgrav 			return "yes";
2531bc5531deSDag-Erling Smørgrav 		default:
2532bc5531deSDag-Erling Smørgrav 			return "UNKNOWN";
2533bc5531deSDag-Erling Smørgrav 		}
2534bc5531deSDag-Erling Smørgrav 	}
2535bc5531deSDag-Erling Smørgrav }
2536bc5531deSDag-Erling Smørgrav 
2537bc5531deSDag-Erling Smørgrav static const char *
2538bc5531deSDag-Erling Smørgrav lookup_opcode_name(OpCodes code)
2539bc5531deSDag-Erling Smørgrav {
2540bc5531deSDag-Erling Smørgrav 	u_int i;
2541bc5531deSDag-Erling Smørgrav 
2542bc5531deSDag-Erling Smørgrav 	for (i = 0; keywords[i].name != NULL; i++)
2543bc5531deSDag-Erling Smørgrav 		if (keywords[i].opcode == code)
2544bc5531deSDag-Erling Smørgrav 			return(keywords[i].name);
2545bc5531deSDag-Erling Smørgrav 	return "UNKNOWN";
2546bc5531deSDag-Erling Smørgrav }
2547bc5531deSDag-Erling Smørgrav 
2548bc5531deSDag-Erling Smørgrav static void
2549bc5531deSDag-Erling Smørgrav dump_cfg_int(OpCodes code, int val)
2550bc5531deSDag-Erling Smørgrav {
2551bc5531deSDag-Erling Smørgrav 	printf("%s %d\n", lookup_opcode_name(code), val);
2552bc5531deSDag-Erling Smørgrav }
2553bc5531deSDag-Erling Smørgrav 
2554bc5531deSDag-Erling Smørgrav static void
2555bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(OpCodes code, int val)
2556bc5531deSDag-Erling Smørgrav {
2557bc5531deSDag-Erling Smørgrav 	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
2558bc5531deSDag-Erling Smørgrav }
2559bc5531deSDag-Erling Smørgrav 
2560bc5531deSDag-Erling Smørgrav static void
2561bc5531deSDag-Erling Smørgrav dump_cfg_string(OpCodes code, const char *val)
2562bc5531deSDag-Erling Smørgrav {
2563bc5531deSDag-Erling Smørgrav 	if (val == NULL)
2564bc5531deSDag-Erling Smørgrav 		return;
2565bc5531deSDag-Erling Smørgrav 	printf("%s %s\n", lookup_opcode_name(code), val);
2566bc5531deSDag-Erling Smørgrav }
2567bc5531deSDag-Erling Smørgrav 
2568bc5531deSDag-Erling Smørgrav static void
2569bc5531deSDag-Erling Smørgrav dump_cfg_strarray(OpCodes code, u_int count, char **vals)
2570bc5531deSDag-Erling Smørgrav {
2571bc5531deSDag-Erling Smørgrav 	u_int i;
2572bc5531deSDag-Erling Smørgrav 
2573bc5531deSDag-Erling Smørgrav 	for (i = 0; i < count; i++)
2574bc5531deSDag-Erling Smørgrav 		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
2575bc5531deSDag-Erling Smørgrav }
2576bc5531deSDag-Erling Smørgrav 
2577bc5531deSDag-Erling Smørgrav static void
2578bc5531deSDag-Erling Smørgrav dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
2579bc5531deSDag-Erling Smørgrav {
2580bc5531deSDag-Erling Smørgrav 	u_int i;
2581bc5531deSDag-Erling Smørgrav 
2582bc5531deSDag-Erling Smørgrav 	printf("%s", lookup_opcode_name(code));
2583bc5531deSDag-Erling Smørgrav 	for (i = 0; i < count; i++)
2584bc5531deSDag-Erling Smørgrav 		printf(" %s",  vals[i]);
2585bc5531deSDag-Erling Smørgrav 	printf("\n");
2586bc5531deSDag-Erling Smørgrav }
2587bc5531deSDag-Erling Smørgrav 
2588bc5531deSDag-Erling Smørgrav static void
2589bc5531deSDag-Erling Smørgrav dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
2590bc5531deSDag-Erling Smørgrav {
2591bc5531deSDag-Erling Smørgrav 	const struct Forward *fwd;
2592bc5531deSDag-Erling Smørgrav 	u_int i;
2593bc5531deSDag-Erling Smørgrav 
2594bc5531deSDag-Erling Smørgrav 	/* oDynamicForward */
2595bc5531deSDag-Erling Smørgrav 	for (i = 0; i < count; i++) {
2596bc5531deSDag-Erling Smørgrav 		fwd = &fwds[i];
2597d93a896eSDag-Erling Smørgrav 		if (code == oDynamicForward && fwd->connect_host != NULL &&
2598bc5531deSDag-Erling Smørgrav 		    strcmp(fwd->connect_host, "socks") != 0)
2599bc5531deSDag-Erling Smørgrav 			continue;
2600d93a896eSDag-Erling Smørgrav 		if (code == oLocalForward && fwd->connect_host != NULL &&
2601bc5531deSDag-Erling Smørgrav 		    strcmp(fwd->connect_host, "socks") == 0)
2602bc5531deSDag-Erling Smørgrav 			continue;
2603bc5531deSDag-Erling Smørgrav 		printf("%s", lookup_opcode_name(code));
2604bc5531deSDag-Erling Smørgrav 		if (fwd->listen_port == PORT_STREAMLOCAL)
2605bc5531deSDag-Erling Smørgrav 			printf(" %s", fwd->listen_path);
2606bc5531deSDag-Erling Smørgrav 		else if (fwd->listen_host == NULL)
2607bc5531deSDag-Erling Smørgrav 			printf(" %d", fwd->listen_port);
2608bc5531deSDag-Erling Smørgrav 		else {
2609bc5531deSDag-Erling Smørgrav 			printf(" [%s]:%d",
2610bc5531deSDag-Erling Smørgrav 			    fwd->listen_host, fwd->listen_port);
2611bc5531deSDag-Erling Smørgrav 		}
2612bc5531deSDag-Erling Smørgrav 		if (code != oDynamicForward) {
2613bc5531deSDag-Erling Smørgrav 			if (fwd->connect_port == PORT_STREAMLOCAL)
2614bc5531deSDag-Erling Smørgrav 				printf(" %s", fwd->connect_path);
2615bc5531deSDag-Erling Smørgrav 			else if (fwd->connect_host == NULL)
2616bc5531deSDag-Erling Smørgrav 				printf(" %d", fwd->connect_port);
2617bc5531deSDag-Erling Smørgrav 			else {
2618bc5531deSDag-Erling Smørgrav 				printf(" [%s]:%d",
2619bc5531deSDag-Erling Smørgrav 				    fwd->connect_host, fwd->connect_port);
2620bc5531deSDag-Erling Smørgrav 			}
2621bc5531deSDag-Erling Smørgrav 		}
2622bc5531deSDag-Erling Smørgrav 		printf("\n");
2623bc5531deSDag-Erling Smørgrav 	}
2624bc5531deSDag-Erling Smørgrav }
2625bc5531deSDag-Erling Smørgrav 
2626bc5531deSDag-Erling Smørgrav void
2627bc5531deSDag-Erling Smørgrav dump_client_config(Options *o, const char *host)
2628bc5531deSDag-Erling Smørgrav {
2629bc5531deSDag-Erling Smørgrav 	int i;
2630190cef3dSDag-Erling Smørgrav 	char buf[8], *all_key;
2631bc5531deSDag-Erling Smørgrav 
2632acc1a9efSDag-Erling Smørgrav 	/* This is normally prepared in ssh_kex2 */
2633190cef3dSDag-Erling Smørgrav 	all_key = sshkey_alg_list(0, 0, 1, ',');
2634190cef3dSDag-Erling Smørgrav 	if (kex_assemble_names( &o->hostkeyalgorithms,
2635190cef3dSDag-Erling Smørgrav 	    KEX_DEFAULT_PK_ALG, all_key) != 0)
2636acc1a9efSDag-Erling Smørgrav 		fatal("%s: kex_assemble_names failed", __func__);
2637190cef3dSDag-Erling Smørgrav 	free(all_key);
2638acc1a9efSDag-Erling Smørgrav 
2639bc5531deSDag-Erling Smørgrav 	/* Most interesting options first: user, host, port */
2640bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oUser, o->user);
2641bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oHostName, host);
2642bc5531deSDag-Erling Smørgrav 	dump_cfg_int(oPort, o->port);
2643bc5531deSDag-Erling Smørgrav 
2644bc5531deSDag-Erling Smørgrav 	/* Flag options */
2645190cef3dSDag-Erling Smørgrav 	dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent);
2646bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oAddressFamily, o->address_family);
2647bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oBatchMode, o->batch_mode);
2648bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
2649bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
2650bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oChallengeResponseAuthentication, o->challenge_response_authentication);
2651bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
2652bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oCompression, o->compression);
2653bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oControlMaster, o->control_master);
2654bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
2655076ad2f8SDag-Erling Smørgrav 	dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
2656bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
2657bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
2658bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oForwardAgent, o->forward_agent);
2659bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oForwardX11, o->forward_x11);
2660bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
2661bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
2662bc5531deSDag-Erling Smørgrav #ifdef GSSAPI
2663bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
2664bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
2665bc5531deSDag-Erling Smørgrav #endif /* GSSAPI */
2666bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
2667bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
2668bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
2669bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
2670bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
2671bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
2672bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
2673bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
2674bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
2675bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oRequestTTY, o->request_tty);
2676bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
2677bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
2678bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
2679bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oTunnel, o->tun_open);
2680bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
2681bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
2682bc5531deSDag-Erling Smørgrav 	dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
2683bc5531deSDag-Erling Smørgrav 
2684bc5531deSDag-Erling Smørgrav 	/* Integer options */
2685bc5531deSDag-Erling Smørgrav 	dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
2686bc5531deSDag-Erling Smørgrav 	dump_cfg_int(oConnectionAttempts, o->connection_attempts);
2687bc5531deSDag-Erling Smørgrav 	dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
2688bc5531deSDag-Erling Smørgrav 	dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
2689bc5531deSDag-Erling Smørgrav 	dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
2690bc5531deSDag-Erling Smørgrav 	dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
2691bc5531deSDag-Erling Smørgrav 
2692bc5531deSDag-Erling Smørgrav 	/* String options */
2693bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oBindAddress, o->bind_address);
269447dd1d1bSDag-Erling Smørgrav 	dump_cfg_string(oBindInterface, o->bind_interface);
2695bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oCiphers, o->ciphers ? o->ciphers : KEX_CLIENT_ENCRYPT);
2696bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oControlPath, o->control_path);
2697acc1a9efSDag-Erling Smørgrav 	dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
2698bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oHostKeyAlias, o->host_key_alias);
2699bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oHostbasedKeyTypes, o->hostbased_key_types);
2700076ad2f8SDag-Erling Smørgrav 	dump_cfg_string(oIdentityAgent, o->identity_agent);
2701190cef3dSDag-Erling Smørgrav 	dump_cfg_string(oIgnoreUnknown, o->ignored_unknown);
2702bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
2703bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX);
27042f513db7SEd Maste 	dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms ? o->ca_sign_algorithms : SSH_ALLOWED_CA_SIGALGS);
2705bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oLocalCommand, o->local_command);
27064f52dfbbSDag-Erling Smørgrav 	dump_cfg_string(oRemoteCommand, o->remote_command);
2707bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oLogLevel, log_level_name(o->log_level));
2708bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
2709d93a896eSDag-Erling Smørgrav #ifdef ENABLE_PKCS11
2710bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
2711d93a896eSDag-Erling Smørgrav #endif
2712bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
2713acc1a9efSDag-Erling Smørgrav 	dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types);
2714bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
2715bc5531deSDag-Erling Smørgrav 	dump_cfg_string(oXAuthLocation, o->xauth_location);
2716bc5531deSDag-Erling Smørgrav 
2717bc5531deSDag-Erling Smørgrav 	/* Forwards */
2718bc5531deSDag-Erling Smørgrav 	dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
2719bc5531deSDag-Erling Smørgrav 	dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
2720bc5531deSDag-Erling Smørgrav 	dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
2721bc5531deSDag-Erling Smørgrav 
2722bc5531deSDag-Erling Smørgrav 	/* String array options */
2723bc5531deSDag-Erling Smørgrav 	dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
2724bc5531deSDag-Erling Smørgrav 	dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
2725190cef3dSDag-Erling Smørgrav 	dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files);
2726bc5531deSDag-Erling Smørgrav 	dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
2727bc5531deSDag-Erling Smørgrav 	dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
2728bc5531deSDag-Erling Smørgrav 	dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
2729190cef3dSDag-Erling Smørgrav 	dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
2730bc5531deSDag-Erling Smørgrav 
2731bc5531deSDag-Erling Smørgrav 	/* Special cases */
2732bc5531deSDag-Erling Smørgrav 
2733bc5531deSDag-Erling Smørgrav 	/* oConnectTimeout */
2734bc5531deSDag-Erling Smørgrav 	if (o->connection_timeout == -1)
2735bc5531deSDag-Erling Smørgrav 		printf("connecttimeout none\n");
2736bc5531deSDag-Erling Smørgrav 	else
2737bc5531deSDag-Erling Smørgrav 		dump_cfg_int(oConnectTimeout, o->connection_timeout);
2738bc5531deSDag-Erling Smørgrav 
2739bc5531deSDag-Erling Smørgrav 	/* oTunnelDevice */
2740bc5531deSDag-Erling Smørgrav 	printf("tunneldevice");
2741bc5531deSDag-Erling Smørgrav 	if (o->tun_local == SSH_TUNID_ANY)
2742bc5531deSDag-Erling Smørgrav 		printf(" any");
2743bc5531deSDag-Erling Smørgrav 	else
2744bc5531deSDag-Erling Smørgrav 		printf(" %d", o->tun_local);
2745bc5531deSDag-Erling Smørgrav 	if (o->tun_remote == SSH_TUNID_ANY)
2746bc5531deSDag-Erling Smørgrav 		printf(":any");
2747bc5531deSDag-Erling Smørgrav 	else
2748bc5531deSDag-Erling Smørgrav 		printf(":%d", o->tun_remote);
2749bc5531deSDag-Erling Smørgrav 	printf("\n");
2750bc5531deSDag-Erling Smørgrav 
2751bc5531deSDag-Erling Smørgrav 	/* oCanonicalizePermittedCNAMEs */
2752bc5531deSDag-Erling Smørgrav 	if ( o->num_permitted_cnames > 0) {
2753bc5531deSDag-Erling Smørgrav 		printf("canonicalizePermittedcnames");
2754bc5531deSDag-Erling Smørgrav 		for (i = 0; i < o->num_permitted_cnames; i++) {
2755bc5531deSDag-Erling Smørgrav 			printf(" %s:%s", o->permitted_cnames[i].source_list,
2756bc5531deSDag-Erling Smørgrav 			    o->permitted_cnames[i].target_list);
2757bc5531deSDag-Erling Smørgrav 		}
2758bc5531deSDag-Erling Smørgrav 		printf("\n");
2759bc5531deSDag-Erling Smørgrav 	}
2760bc5531deSDag-Erling Smørgrav 
2761bc5531deSDag-Erling Smørgrav 	/* oControlPersist */
2762bc5531deSDag-Erling Smørgrav 	if (o->control_persist == 0 || o->control_persist_timeout == 0)
2763bc5531deSDag-Erling Smørgrav 		dump_cfg_fmtint(oControlPersist, o->control_persist);
2764bc5531deSDag-Erling Smørgrav 	else
2765bc5531deSDag-Erling Smørgrav 		dump_cfg_int(oControlPersist, o->control_persist_timeout);
2766bc5531deSDag-Erling Smørgrav 
2767bc5531deSDag-Erling Smørgrav 	/* oEscapeChar */
2768bc5531deSDag-Erling Smørgrav 	if (o->escape_char == SSH_ESCAPECHAR_NONE)
2769bc5531deSDag-Erling Smørgrav 		printf("escapechar none\n");
2770bc5531deSDag-Erling Smørgrav 	else {
2771076ad2f8SDag-Erling Smørgrav 		vis(buf, o->escape_char, VIS_WHITE, 0);
2772076ad2f8SDag-Erling Smørgrav 		printf("escapechar %s\n", buf);
2773bc5531deSDag-Erling Smørgrav 	}
2774bc5531deSDag-Erling Smørgrav 
2775bc5531deSDag-Erling Smørgrav 	/* oIPQoS */
2776bc5531deSDag-Erling Smørgrav 	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
2777bc5531deSDag-Erling Smørgrav 	printf("%s\n", iptos2str(o->ip_qos_bulk));
2778bc5531deSDag-Erling Smørgrav 
2779bc5531deSDag-Erling Smørgrav 	/* oRekeyLimit */
2780acc1a9efSDag-Erling Smørgrav 	printf("rekeylimit %llu %d\n",
2781acc1a9efSDag-Erling Smørgrav 	    (unsigned long long)o->rekey_limit, o->rekey_interval);
2782bc5531deSDag-Erling Smørgrav 
2783bc5531deSDag-Erling Smørgrav 	/* oStreamLocalBindMask */
2784bc5531deSDag-Erling Smørgrav 	printf("streamlocalbindmask 0%o\n",
2785bc5531deSDag-Erling Smørgrav 	    o->fwd_opts.streamlocal_bind_mask);
2786076ad2f8SDag-Erling Smørgrav 
2787190cef3dSDag-Erling Smørgrav 	/* oLogFacility */
2788190cef3dSDag-Erling Smørgrav 	printf("syslogfacility %s\n", log_facility_name(o->log_facility));
2789190cef3dSDag-Erling Smørgrav 
2790076ad2f8SDag-Erling Smørgrav 	/* oProxyCommand / oProxyJump */
2791076ad2f8SDag-Erling Smørgrav 	if (o->jump_host == NULL)
2792076ad2f8SDag-Erling Smørgrav 		dump_cfg_string(oProxyCommand, o->proxy_command);
2793076ad2f8SDag-Erling Smørgrav 	else {
2794076ad2f8SDag-Erling Smørgrav 		/* Check for numeric addresses */
2795076ad2f8SDag-Erling Smørgrav 		i = strchr(o->jump_host, ':') != NULL ||
2796076ad2f8SDag-Erling Smørgrav 		    strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
2797076ad2f8SDag-Erling Smørgrav 		snprintf(buf, sizeof(buf), "%d", o->jump_port);
2798076ad2f8SDag-Erling Smørgrav 		printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
2799076ad2f8SDag-Erling Smørgrav 		    /* optional additional jump spec */
2800076ad2f8SDag-Erling Smørgrav 		    o->jump_extra == NULL ? "" : o->jump_extra,
2801076ad2f8SDag-Erling Smørgrav 		    o->jump_extra == NULL ? "" : ",",
2802076ad2f8SDag-Erling Smørgrav 		    /* optional user */
2803076ad2f8SDag-Erling Smørgrav 		    o->jump_user == NULL ? "" : o->jump_user,
2804076ad2f8SDag-Erling Smørgrav 		    o->jump_user == NULL ? "" : "@",
2805076ad2f8SDag-Erling Smørgrav 		    /* opening [ if hostname is numeric */
2806076ad2f8SDag-Erling Smørgrav 		    i ? "[" : "",
2807076ad2f8SDag-Erling Smørgrav 		    /* mandatory hostname */
2808076ad2f8SDag-Erling Smørgrav 		    o->jump_host,
2809076ad2f8SDag-Erling Smørgrav 		    /* closing ] if hostname is numeric */
2810076ad2f8SDag-Erling Smørgrav 		    i ? "]" : "",
2811076ad2f8SDag-Erling Smørgrav 		    /* optional port number */
2812076ad2f8SDag-Erling Smørgrav 		    o->jump_port <= 0 ? "" : ":",
2813076ad2f8SDag-Erling Smørgrav 		    o->jump_port <= 0 ? "" : buf);
2814076ad2f8SDag-Erling Smørgrav 	}
2815bc5531deSDag-Erling Smørgrav }
2816