xref: /dflybsd-src/crypto/openssh/readconf.c (revision 0cbfa66cdb87e23928a110d9b02839f403e32c11)
1*0cbfa66cSDaniel Fojt /* $OpenBSD: readconf.c,v 1.329 2020/04/24 03:33:21 dtucker Exp $ */
218de8d7fSPeter Avalos /*
318de8d7fSPeter Avalos  * Author: Tatu Ylonen <ylo@cs.hut.fi>
418de8d7fSPeter Avalos  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
518de8d7fSPeter Avalos  *                    All rights reserved
618de8d7fSPeter Avalos  * Functions for reading the configuration files.
718de8d7fSPeter Avalos  *
818de8d7fSPeter Avalos  * As far as I am concerned, the code I have written for this software
918de8d7fSPeter Avalos  * can be used freely for any purpose.  Any derived versions of this
1018de8d7fSPeter Avalos  * software must be clearly marked as such, and if the derived work is
1118de8d7fSPeter Avalos  * incompatible with the protocol description in the RFC file, it must be
1218de8d7fSPeter Avalos  * called by a name other than "ssh" or "Secure Shell".
1318de8d7fSPeter Avalos  */
1418de8d7fSPeter Avalos 
1518de8d7fSPeter Avalos #include "includes.h"
1618de8d7fSPeter Avalos 
1718de8d7fSPeter Avalos #include <sys/types.h>
1818de8d7fSPeter Avalos #include <sys/stat.h>
1918de8d7fSPeter Avalos #include <sys/socket.h>
2036e94dc5SPeter Avalos #include <sys/wait.h>
2136e94dc5SPeter Avalos #include <sys/un.h>
2218de8d7fSPeter Avalos 
2318de8d7fSPeter Avalos #include <netinet/in.h>
249f304aafSPeter Avalos #include <netinet/in_systm.h>
259f304aafSPeter Avalos #include <netinet/ip.h>
2636e94dc5SPeter Avalos #include <arpa/inet.h>
2718de8d7fSPeter Avalos 
2818de8d7fSPeter Avalos #include <ctype.h>
2918de8d7fSPeter Avalos #include <errno.h>
3036e94dc5SPeter Avalos #include <fcntl.h>
31e9778795SPeter Avalos #include <limits.h>
3218de8d7fSPeter Avalos #include <netdb.h>
3336e94dc5SPeter Avalos #ifdef HAVE_PATHS_H
3436e94dc5SPeter Avalos # include <paths.h>
3536e94dc5SPeter Avalos #endif
3636e94dc5SPeter Avalos #include <pwd.h>
3718de8d7fSPeter Avalos #include <signal.h>
3818de8d7fSPeter Avalos #include <stdio.h>
3918de8d7fSPeter Avalos #include <string.h>
40*0cbfa66cSDaniel Fojt #include <stdarg.h>
4118de8d7fSPeter Avalos #include <unistd.h>
42e9778795SPeter Avalos #ifdef USE_SYSTEM_GLOB
43e9778795SPeter Avalos # include <glob.h>
44e9778795SPeter Avalos #else
45e9778795SPeter Avalos # include "openbsd-compat/glob.h"
46e9778795SPeter Avalos #endif
4736e94dc5SPeter Avalos #ifdef HAVE_UTIL_H
4836e94dc5SPeter Avalos #include <util.h>
4936e94dc5SPeter Avalos #endif
50e9778795SPeter Avalos #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
51e9778795SPeter Avalos # include <vis.h>
52e9778795SPeter Avalos #endif
5318de8d7fSPeter Avalos 
5418de8d7fSPeter Avalos #include "xmalloc.h"
5518de8d7fSPeter Avalos #include "ssh.h"
56664f4763Szrj #include "ssherr.h"
5718de8d7fSPeter Avalos #include "compat.h"
5818de8d7fSPeter Avalos #include "cipher.h"
5918de8d7fSPeter Avalos #include "pathnames.h"
6018de8d7fSPeter Avalos #include "log.h"
61e9778795SPeter Avalos #include "sshkey.h"
6236e94dc5SPeter Avalos #include "misc.h"
6318de8d7fSPeter Avalos #include "readconf.h"
6418de8d7fSPeter Avalos #include "match.h"
6518de8d7fSPeter Avalos #include "kex.h"
6618de8d7fSPeter Avalos #include "mac.h"
6736e94dc5SPeter Avalos #include "uidswap.h"
68e9778795SPeter Avalos #include "myproposal.h"
69e9778795SPeter Avalos #include "digest.h"
7018de8d7fSPeter Avalos 
7118de8d7fSPeter Avalos /* Format of the configuration file:
7218de8d7fSPeter Avalos 
7318de8d7fSPeter Avalos    # Configuration data is parsed as follows:
7418de8d7fSPeter Avalos    #  1. command line options
7518de8d7fSPeter Avalos    #  2. user-specific file
7618de8d7fSPeter Avalos    #  3. system-wide file
7718de8d7fSPeter Avalos    # Any configuration value is only changed the first time it is set.
7818de8d7fSPeter Avalos    # Thus, host-specific definitions should be at the beginning of the
7918de8d7fSPeter Avalos    # configuration file, and defaults at the end.
8018de8d7fSPeter Avalos 
8118de8d7fSPeter Avalos    # Host-specific declarations.  These may override anything above.  A single
8218de8d7fSPeter Avalos    # host may match multiple declarations; these are processed in the order
8318de8d7fSPeter Avalos    # that they are given in.
8418de8d7fSPeter Avalos 
8518de8d7fSPeter Avalos    Host *.ngs.fi ngs.fi
8618de8d7fSPeter Avalos      User foo
8718de8d7fSPeter Avalos 
8818de8d7fSPeter Avalos    Host fake.com
89*0cbfa66cSDaniel Fojt      Hostname another.host.name.real.org
9018de8d7fSPeter Avalos      User blaah
9118de8d7fSPeter Avalos      Port 34289
9218de8d7fSPeter Avalos      ForwardX11 no
9318de8d7fSPeter Avalos      ForwardAgent no
9418de8d7fSPeter Avalos 
9518de8d7fSPeter Avalos    Host books.com
9618de8d7fSPeter Avalos      RemoteForward 9999 shadows.cs.hut.fi:9999
97ce74bacaSMatthew Dillon      Ciphers 3des-cbc
9818de8d7fSPeter Avalos 
9918de8d7fSPeter Avalos    Host fascist.blob.com
10018de8d7fSPeter Avalos      Port 23123
10118de8d7fSPeter Avalos      User tylonen
10218de8d7fSPeter Avalos      PasswordAuthentication no
10318de8d7fSPeter Avalos 
10418de8d7fSPeter Avalos    Host puukko.hut.fi
10518de8d7fSPeter Avalos      User t35124p
10618de8d7fSPeter Avalos      ProxyCommand ssh-proxy %h %p
10718de8d7fSPeter Avalos 
10818de8d7fSPeter Avalos    Host *.fr
10918de8d7fSPeter Avalos      PublicKeyAuthentication no
11018de8d7fSPeter Avalos 
11118de8d7fSPeter Avalos    Host *.su
112ce74bacaSMatthew Dillon      Ciphers aes128-ctr
11318de8d7fSPeter Avalos      PasswordAuthentication no
11418de8d7fSPeter Avalos 
11518de8d7fSPeter Avalos    Host vpn.fake.com
11618de8d7fSPeter Avalos      Tunnel yes
11718de8d7fSPeter Avalos      TunnelDevice 3
11818de8d7fSPeter Avalos 
11918de8d7fSPeter Avalos    # Defaults for various options
12018de8d7fSPeter Avalos    Host *
12118de8d7fSPeter Avalos      ForwardAgent no
12218de8d7fSPeter Avalos      ForwardX11 no
12318de8d7fSPeter Avalos      PasswordAuthentication yes
12418de8d7fSPeter Avalos      StrictHostKeyChecking yes
12518de8d7fSPeter Avalos      TcpKeepAlive no
12618de8d7fSPeter Avalos      IdentityFile ~/.ssh/identity
12718de8d7fSPeter Avalos      Port 22
12818de8d7fSPeter Avalos      EscapeChar ~
12918de8d7fSPeter Avalos 
13018de8d7fSPeter Avalos */
13118de8d7fSPeter Avalos 
132e9778795SPeter Avalos static int read_config_file_depth(const char *filename, struct passwd *pw,
133e9778795SPeter Avalos     const char *host, const char *original_host, Options *options,
134664f4763Szrj     int flags, int *activep, int *want_final_pass, int depth);
135e9778795SPeter Avalos static int process_config_line_depth(Options *options, struct passwd *pw,
136e9778795SPeter Avalos     const char *host, const char *original_host, char *line,
137664f4763Szrj     const char *filename, int linenum, int *activep, int flags,
138664f4763Szrj     int *want_final_pass, int depth);
139e9778795SPeter Avalos 
14018de8d7fSPeter Avalos /* Keyword tokens. */
14118de8d7fSPeter Avalos 
14218de8d7fSPeter Avalos typedef enum {
14318de8d7fSPeter Avalos 	oBadOption,
144e9778795SPeter Avalos 	oHost, oMatch, oInclude,
145856ea928SPeter Avalos 	oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
146856ea928SPeter Avalos 	oGatewayPorts, oExitOnForwardFailure,
147*0cbfa66cSDaniel Fojt 	oPasswordAuthentication,
14818de8d7fSPeter Avalos 	oChallengeResponseAuthentication, oXAuthLocation,
149*0cbfa66cSDaniel Fojt 	oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward,
150e9778795SPeter Avalos 	oCertificateFile, oAddKeysToAgent, oIdentityAgent,
151*0cbfa66cSDaniel Fojt 	oUser, oEscapeChar, oProxyCommand,
15218de8d7fSPeter Avalos 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
15318de8d7fSPeter Avalos 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
154*0cbfa66cSDaniel Fojt 	oTCPKeepAlive, oNumberOfPasswordPrompts,
155*0cbfa66cSDaniel Fojt 	oLogFacility, oLogLevel, oCiphers, oMacs,
156e9778795SPeter Avalos 	oPubkeyAuthentication,
15718de8d7fSPeter Avalos 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
15818de8d7fSPeter Avalos 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
159664f4763Szrj 	oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider,
16018de8d7fSPeter Avalos 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
16118de8d7fSPeter Avalos 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
16218de8d7fSPeter Avalos 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
16318de8d7fSPeter Avalos 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
164664f4763Szrj 	oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
165856ea928SPeter Avalos 	oHashKnownHosts,
166ce74bacaSMatthew Dillon 	oTunnel, oTunnelDevice,
167ce74bacaSMatthew Dillon 	oLocalCommand, oPermitLocalCommand, oRemoteCommand,
168e9778795SPeter Avalos 	oVisualHostKey,
16936e94dc5SPeter Avalos 	oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
17036e94dc5SPeter Avalos 	oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
17136e94dc5SPeter Avalos 	oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
172e9778795SPeter Avalos 	oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
173e9778795SPeter Avalos 	oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
174664f4763Szrj 	oPubkeyAcceptedKeyTypes, oCASignatureAlgorithms, oProxyJump,
175*0cbfa66cSDaniel Fojt 	oSecurityKeyProvider,
176ce74bacaSMatthew Dillon 	oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
17718de8d7fSPeter Avalos } OpCodes;
17818de8d7fSPeter Avalos 
17918de8d7fSPeter Avalos /* Textual representations of the tokens. */
18018de8d7fSPeter Avalos 
18118de8d7fSPeter Avalos static struct {
18218de8d7fSPeter Avalos 	const char *name;
18318de8d7fSPeter Avalos 	OpCodes opcode;
18418de8d7fSPeter Avalos } keywords[] = {
185ce74bacaSMatthew Dillon 	/* Deprecated options */
186ce74bacaSMatthew Dillon 	{ "protocol", oIgnore }, /* NB. silently ignored */
187ce74bacaSMatthew Dillon 	{ "cipher", oDeprecated },
188ce74bacaSMatthew Dillon 	{ "fallbacktorsh", oDeprecated },
189ce74bacaSMatthew Dillon 	{ "globalknownhostsfile2", oDeprecated },
190ce74bacaSMatthew Dillon 	{ "rhostsauthentication", oDeprecated },
191ce74bacaSMatthew Dillon 	{ "userknownhostsfile2", oDeprecated },
192ce74bacaSMatthew Dillon 	{ "useroaming", oDeprecated },
193ce74bacaSMatthew Dillon 	{ "usersh", oDeprecated },
194664f4763Szrj 	{ "useprivilegedport", oDeprecated },
195ce74bacaSMatthew Dillon 
196ce74bacaSMatthew Dillon 	/* Unsupported options */
197ce74bacaSMatthew Dillon 	{ "afstokenpassing", oUnsupported },
198ce74bacaSMatthew Dillon 	{ "kerberosauthentication", oUnsupported },
199ce74bacaSMatthew Dillon 	{ "kerberostgtpassing", oUnsupported },
200*0cbfa66cSDaniel Fojt 	{ "rsaauthentication", oUnsupported },
201*0cbfa66cSDaniel Fojt 	{ "rhostsrsaauthentication", oUnsupported },
202*0cbfa66cSDaniel Fojt 	{ "compressionlevel", oUnsupported },
203ce74bacaSMatthew Dillon 
204ce74bacaSMatthew Dillon 	/* Sometimes-unsupported options */
205ce74bacaSMatthew Dillon #if defined(GSSAPI)
206ce74bacaSMatthew Dillon 	{ "gssapiauthentication", oGssAuthentication },
207ce74bacaSMatthew Dillon 	{ "gssapidelegatecredentials", oGssDelegateCreds },
208ce74bacaSMatthew Dillon # else
209ce74bacaSMatthew Dillon 	{ "gssapiauthentication", oUnsupported },
210ce74bacaSMatthew Dillon 	{ "gssapidelegatecredentials", oUnsupported },
211ce74bacaSMatthew Dillon #endif
212ce74bacaSMatthew Dillon #ifdef ENABLE_PKCS11
213ce74bacaSMatthew Dillon 	{ "pkcs11provider", oPKCS11Provider },
214664f4763Szrj 	{ "smartcarddevice", oPKCS11Provider },
215ce74bacaSMatthew Dillon # else
216ce74bacaSMatthew Dillon 	{ "smartcarddevice", oUnsupported },
217ce74bacaSMatthew Dillon 	{ "pkcs11provider", oUnsupported },
218ce74bacaSMatthew Dillon #endif
219ce74bacaSMatthew Dillon 
22018de8d7fSPeter Avalos 	{ "forwardagent", oForwardAgent },
22118de8d7fSPeter Avalos 	{ "forwardx11", oForwardX11 },
22218de8d7fSPeter Avalos 	{ "forwardx11trusted", oForwardX11Trusted },
223856ea928SPeter Avalos 	{ "forwardx11timeout", oForwardX11Timeout },
22418de8d7fSPeter Avalos 	{ "exitonforwardfailure", oExitOnForwardFailure },
22518de8d7fSPeter Avalos 	{ "xauthlocation", oXAuthLocation },
22618de8d7fSPeter Avalos 	{ "gatewayports", oGatewayPorts },
22718de8d7fSPeter Avalos 	{ "passwordauthentication", oPasswordAuthentication },
22818de8d7fSPeter Avalos 	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
22918de8d7fSPeter Avalos 	{ "kbdinteractivedevices", oKbdInteractiveDevices },
23018de8d7fSPeter Avalos 	{ "pubkeyauthentication", oPubkeyAuthentication },
23118de8d7fSPeter Avalos 	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
23218de8d7fSPeter Avalos 	{ "hostbasedauthentication", oHostbasedAuthentication },
23318de8d7fSPeter Avalos 	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
234664f4763Szrj 	{ "skeyauthentication", oUnsupported },
23518de8d7fSPeter Avalos 	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
23618de8d7fSPeter Avalos 	{ "identityfile", oIdentityFile },
237cb5eb4f1SPeter Avalos 	{ "identityfile2", oIdentityFile },			/* obsolete */
23818de8d7fSPeter Avalos 	{ "identitiesonly", oIdentitiesOnly },
239e9778795SPeter Avalos 	{ "certificatefile", oCertificateFile },
240e9778795SPeter Avalos 	{ "addkeystoagent", oAddKeysToAgent },
241e9778795SPeter Avalos 	{ "identityagent", oIdentityAgent },
242*0cbfa66cSDaniel Fojt 	{ "hostname", oHostname },
24318de8d7fSPeter Avalos 	{ "hostkeyalias", oHostKeyAlias },
24418de8d7fSPeter Avalos 	{ "proxycommand", oProxyCommand },
24518de8d7fSPeter Avalos 	{ "port", oPort },
24618de8d7fSPeter Avalos 	{ "ciphers", oCiphers },
24718de8d7fSPeter Avalos 	{ "macs", oMacs },
24818de8d7fSPeter Avalos 	{ "remoteforward", oRemoteForward },
24918de8d7fSPeter Avalos 	{ "localforward", oLocalForward },
25018de8d7fSPeter Avalos 	{ "user", oUser },
25118de8d7fSPeter Avalos 	{ "host", oHost },
25236e94dc5SPeter Avalos 	{ "match", oMatch },
25318de8d7fSPeter Avalos 	{ "escapechar", oEscapeChar },
25418de8d7fSPeter Avalos 	{ "globalknownhostsfile", oGlobalKnownHostsFile },
255cb5eb4f1SPeter Avalos 	{ "userknownhostsfile", oUserKnownHostsFile },
25618de8d7fSPeter Avalos 	{ "connectionattempts", oConnectionAttempts },
25718de8d7fSPeter Avalos 	{ "batchmode", oBatchMode },
25818de8d7fSPeter Avalos 	{ "checkhostip", oCheckHostIP },
25918de8d7fSPeter Avalos 	{ "stricthostkeychecking", oStrictHostKeyChecking },
26018de8d7fSPeter Avalos 	{ "compression", oCompression },
26118de8d7fSPeter Avalos 	{ "tcpkeepalive", oTCPKeepAlive },
26218de8d7fSPeter Avalos 	{ "keepalive", oTCPKeepAlive },				/* obsolete */
26318de8d7fSPeter Avalos 	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
264ce74bacaSMatthew Dillon 	{ "syslogfacility", oLogFacility },
26518de8d7fSPeter Avalos 	{ "loglevel", oLogLevel },
26618de8d7fSPeter Avalos 	{ "dynamicforward", oDynamicForward },
26718de8d7fSPeter Avalos 	{ "preferredauthentications", oPreferredAuthentications },
26818de8d7fSPeter Avalos 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
269664f4763Szrj 	{ "casignaturealgorithms", oCASignatureAlgorithms },
27018de8d7fSPeter Avalos 	{ "bindaddress", oBindAddress },
271664f4763Szrj 	{ "bindinterface", oBindInterface },
27218de8d7fSPeter Avalos 	{ "clearallforwardings", oClearAllForwardings },
27318de8d7fSPeter Avalos 	{ "enablesshkeysign", oEnableSSHKeysign },
27418de8d7fSPeter Avalos 	{ "verifyhostkeydns", oVerifyHostKeyDNS },
27518de8d7fSPeter Avalos 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
27618de8d7fSPeter Avalos 	{ "rekeylimit", oRekeyLimit },
27718de8d7fSPeter Avalos 	{ "connecttimeout", oConnectTimeout },
27818de8d7fSPeter Avalos 	{ "addressfamily", oAddressFamily },
27918de8d7fSPeter Avalos 	{ "serveraliveinterval", oServerAliveInterval },
28018de8d7fSPeter Avalos 	{ "serveralivecountmax", oServerAliveCountMax },
28118de8d7fSPeter Avalos 	{ "sendenv", oSendEnv },
282664f4763Szrj 	{ "setenv", oSetEnv },
28318de8d7fSPeter Avalos 	{ "controlpath", oControlPath },
28418de8d7fSPeter Avalos 	{ "controlmaster", oControlMaster },
285856ea928SPeter Avalos 	{ "controlpersist", oControlPersist },
28618de8d7fSPeter Avalos 	{ "hashknownhosts", oHashKnownHosts },
287e9778795SPeter Avalos 	{ "include", oInclude },
28818de8d7fSPeter Avalos 	{ "tunnel", oTunnel },
28918de8d7fSPeter Avalos 	{ "tunneldevice", oTunnelDevice },
29018de8d7fSPeter Avalos 	{ "localcommand", oLocalCommand },
29118de8d7fSPeter Avalos 	{ "permitlocalcommand", oPermitLocalCommand },
292ce74bacaSMatthew Dillon 	{ "remotecommand", oRemoteCommand },
29318de8d7fSPeter Avalos 	{ "visualhostkey", oVisualHostKey },
2949f304aafSPeter Avalos 	{ "kexalgorithms", oKexAlgorithms },
2959f304aafSPeter Avalos 	{ "ipqos", oIPQoS },
2961c188a7fSPeter Avalos 	{ "requesttty", oRequestTTY },
29736e94dc5SPeter Avalos 	{ "proxyusefdpass", oProxyUseFdpass },
29836e94dc5SPeter Avalos 	{ "canonicaldomains", oCanonicalDomains },
29936e94dc5SPeter Avalos 	{ "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
30036e94dc5SPeter Avalos 	{ "canonicalizehostname", oCanonicalizeHostname },
30136e94dc5SPeter Avalos 	{ "canonicalizemaxdots", oCanonicalizeMaxDots },
30236e94dc5SPeter Avalos 	{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
30336e94dc5SPeter Avalos 	{ "streamlocalbindmask", oStreamLocalBindMask },
30436e94dc5SPeter Avalos 	{ "streamlocalbindunlink", oStreamLocalBindUnlink },
305e9778795SPeter Avalos 	{ "revokedhostkeys", oRevokedHostKeys },
306e9778795SPeter Avalos 	{ "fingerprinthash", oFingerprintHash },
307e9778795SPeter Avalos 	{ "updatehostkeys", oUpdateHostkeys },
308e9778795SPeter Avalos 	{ "hostbasedkeytypes", oHostbasedKeyTypes },
309e9778795SPeter Avalos 	{ "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
31036e94dc5SPeter Avalos 	{ "ignoreunknown", oIgnoreUnknown },
311e9778795SPeter Avalos 	{ "proxyjump", oProxyJump },
312*0cbfa66cSDaniel Fojt 	{ "securitykeyprovider", oSecurityKeyProvider },
313cb5eb4f1SPeter Avalos 
31418de8d7fSPeter Avalos 	{ NULL, oBadOption }
31518de8d7fSPeter Avalos };
31618de8d7fSPeter Avalos 
317*0cbfa66cSDaniel Fojt static char *kex_default_pk_alg_filtered;
318*0cbfa66cSDaniel Fojt 
319*0cbfa66cSDaniel Fojt const char *
320*0cbfa66cSDaniel Fojt kex_default_pk_alg(void)
321*0cbfa66cSDaniel Fojt {
322*0cbfa66cSDaniel Fojt 	if (kex_default_pk_alg_filtered == NULL)
323*0cbfa66cSDaniel Fojt 		fatal("kex_default_pk_alg not initialized.");
324*0cbfa66cSDaniel Fojt 	return kex_default_pk_alg_filtered;
325*0cbfa66cSDaniel Fojt }
326*0cbfa66cSDaniel Fojt 
327*0cbfa66cSDaniel Fojt char *
328*0cbfa66cSDaniel Fojt ssh_connection_hash(const char *thishost, const char *host, const char *portstr,
329*0cbfa66cSDaniel Fojt     const char *user)
330*0cbfa66cSDaniel Fojt {
331*0cbfa66cSDaniel Fojt 	struct ssh_digest_ctx *md;
332*0cbfa66cSDaniel Fojt 	u_char conn_hash[SSH_DIGEST_MAX_LENGTH];
333*0cbfa66cSDaniel Fojt 
334*0cbfa66cSDaniel Fojt 	if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL ||
335*0cbfa66cSDaniel Fojt 	    ssh_digest_update(md, thishost, strlen(thishost)) < 0 ||
336*0cbfa66cSDaniel Fojt 	    ssh_digest_update(md, host, strlen(host)) < 0 ||
337*0cbfa66cSDaniel Fojt 	    ssh_digest_update(md, portstr, strlen(portstr)) < 0 ||
338*0cbfa66cSDaniel Fojt 	    ssh_digest_update(md, user, strlen(user)) < 0 ||
339*0cbfa66cSDaniel Fojt 	    ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0)
340*0cbfa66cSDaniel Fojt 		fatal("%s: mux digest failed", __func__);
341*0cbfa66cSDaniel Fojt 	ssh_digest_free(md);
342*0cbfa66cSDaniel Fojt 	return tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1));
343*0cbfa66cSDaniel Fojt }
344*0cbfa66cSDaniel Fojt 
34518de8d7fSPeter Avalos /*
34618de8d7fSPeter Avalos  * Adds a local TCP/IP port forward to options.  Never returns if there is an
34718de8d7fSPeter Avalos  * error.
34818de8d7fSPeter Avalos  */
34918de8d7fSPeter Avalos 
35018de8d7fSPeter Avalos void
35136e94dc5SPeter Avalos add_local_forward(Options *options, const struct Forward *newfwd)
35218de8d7fSPeter Avalos {
35336e94dc5SPeter Avalos 	struct Forward *fwd;
354e9778795SPeter Avalos 	int i;
355e9778795SPeter Avalos 
356e9778795SPeter Avalos 	/* Don't add duplicates */
357e9778795SPeter Avalos 	for (i = 0; i < options->num_local_forwards; i++) {
358e9778795SPeter Avalos 		if (forward_equals(newfwd, options->local_forwards + i))
359e9778795SPeter Avalos 			return;
360e9778795SPeter Avalos 	}
361e9778795SPeter Avalos 	options->local_forwards = xreallocarray(options->local_forwards,
362856ea928SPeter Avalos 	    options->num_local_forwards + 1,
363856ea928SPeter Avalos 	    sizeof(*options->local_forwards));
36418de8d7fSPeter Avalos 	fwd = &options->local_forwards[options->num_local_forwards++];
36518de8d7fSPeter Avalos 
366cb5eb4f1SPeter Avalos 	fwd->listen_host = newfwd->listen_host;
36718de8d7fSPeter Avalos 	fwd->listen_port = newfwd->listen_port;
36836e94dc5SPeter Avalos 	fwd->listen_path = newfwd->listen_path;
369cb5eb4f1SPeter Avalos 	fwd->connect_host = newfwd->connect_host;
37018de8d7fSPeter Avalos 	fwd->connect_port = newfwd->connect_port;
37136e94dc5SPeter Avalos 	fwd->connect_path = newfwd->connect_path;
37218de8d7fSPeter Avalos }
37318de8d7fSPeter Avalos 
37418de8d7fSPeter Avalos /*
37518de8d7fSPeter Avalos  * Adds a remote TCP/IP port forward to options.  Never returns if there is
37618de8d7fSPeter Avalos  * an error.
37718de8d7fSPeter Avalos  */
37818de8d7fSPeter Avalos 
37918de8d7fSPeter Avalos void
38036e94dc5SPeter Avalos add_remote_forward(Options *options, const struct Forward *newfwd)
38118de8d7fSPeter Avalos {
38236e94dc5SPeter Avalos 	struct Forward *fwd;
383e9778795SPeter Avalos 	int i;
384856ea928SPeter Avalos 
385e9778795SPeter Avalos 	/* Don't add duplicates */
386e9778795SPeter Avalos 	for (i = 0; i < options->num_remote_forwards; i++) {
387e9778795SPeter Avalos 		if (forward_equals(newfwd, options->remote_forwards + i))
388e9778795SPeter Avalos 			return;
389e9778795SPeter Avalos 	}
390e9778795SPeter Avalos 	options->remote_forwards = xreallocarray(options->remote_forwards,
391856ea928SPeter Avalos 	    options->num_remote_forwards + 1,
392856ea928SPeter Avalos 	    sizeof(*options->remote_forwards));
39318de8d7fSPeter Avalos 	fwd = &options->remote_forwards[options->num_remote_forwards++];
39418de8d7fSPeter Avalos 
395cb5eb4f1SPeter Avalos 	fwd->listen_host = newfwd->listen_host;
39618de8d7fSPeter Avalos 	fwd->listen_port = newfwd->listen_port;
39736e94dc5SPeter Avalos 	fwd->listen_path = newfwd->listen_path;
398cb5eb4f1SPeter Avalos 	fwd->connect_host = newfwd->connect_host;
39918de8d7fSPeter Avalos 	fwd->connect_port = newfwd->connect_port;
40036e94dc5SPeter Avalos 	fwd->connect_path = newfwd->connect_path;
40199e85e0dSPeter Avalos 	fwd->handle = newfwd->handle;
402856ea928SPeter Avalos 	fwd->allocated_port = 0;
40318de8d7fSPeter Avalos }
40418de8d7fSPeter Avalos 
40518de8d7fSPeter Avalos static void
40618de8d7fSPeter Avalos clear_forwardings(Options *options)
40718de8d7fSPeter Avalos {
40818de8d7fSPeter Avalos 	int i;
40918de8d7fSPeter Avalos 
41018de8d7fSPeter Avalos 	for (i = 0; i < options->num_local_forwards; i++) {
41136e94dc5SPeter Avalos 		free(options->local_forwards[i].listen_host);
41236e94dc5SPeter Avalos 		free(options->local_forwards[i].listen_path);
41336e94dc5SPeter Avalos 		free(options->local_forwards[i].connect_host);
41436e94dc5SPeter Avalos 		free(options->local_forwards[i].connect_path);
41518de8d7fSPeter Avalos 	}
416856ea928SPeter Avalos 	if (options->num_local_forwards > 0) {
41736e94dc5SPeter Avalos 		free(options->local_forwards);
418856ea928SPeter Avalos 		options->local_forwards = NULL;
419856ea928SPeter Avalos 	}
42018de8d7fSPeter Avalos 	options->num_local_forwards = 0;
42118de8d7fSPeter Avalos 	for (i = 0; i < options->num_remote_forwards; i++) {
42236e94dc5SPeter Avalos 		free(options->remote_forwards[i].listen_host);
42336e94dc5SPeter Avalos 		free(options->remote_forwards[i].listen_path);
42436e94dc5SPeter Avalos 		free(options->remote_forwards[i].connect_host);
42536e94dc5SPeter Avalos 		free(options->remote_forwards[i].connect_path);
42618de8d7fSPeter Avalos 	}
427856ea928SPeter Avalos 	if (options->num_remote_forwards > 0) {
42836e94dc5SPeter Avalos 		free(options->remote_forwards);
429856ea928SPeter Avalos 		options->remote_forwards = NULL;
430856ea928SPeter Avalos 	}
43118de8d7fSPeter Avalos 	options->num_remote_forwards = 0;
43218de8d7fSPeter Avalos 	options->tun_open = SSH_TUNMODE_NO;
43318de8d7fSPeter Avalos }
43418de8d7fSPeter Avalos 
43536e94dc5SPeter Avalos void
436e9778795SPeter Avalos add_certificate_file(Options *options, const char *path, int userprovided)
437e9778795SPeter Avalos {
438e9778795SPeter Avalos 	int i;
439e9778795SPeter Avalos 
440e9778795SPeter Avalos 	if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
441e9778795SPeter Avalos 		fatal("Too many certificate files specified (max %d)",
442e9778795SPeter Avalos 		    SSH_MAX_CERTIFICATE_FILES);
443e9778795SPeter Avalos 
444e9778795SPeter Avalos 	/* Avoid registering duplicates */
445e9778795SPeter Avalos 	for (i = 0; i < options->num_certificate_files; i++) {
446e9778795SPeter Avalos 		if (options->certificate_file_userprovided[i] == userprovided &&
447e9778795SPeter Avalos 		    strcmp(options->certificate_files[i], path) == 0) {
448e9778795SPeter Avalos 			debug2("%s: ignoring duplicate key %s", __func__, path);
449e9778795SPeter Avalos 			return;
450e9778795SPeter Avalos 		}
451e9778795SPeter Avalos 	}
452e9778795SPeter Avalos 
453e9778795SPeter Avalos 	options->certificate_file_userprovided[options->num_certificate_files] =
454e9778795SPeter Avalos 	    userprovided;
455e9778795SPeter Avalos 	options->certificate_files[options->num_certificate_files++] =
456e9778795SPeter Avalos 	    xstrdup(path);
457e9778795SPeter Avalos }
458e9778795SPeter Avalos 
459e9778795SPeter Avalos void
46036e94dc5SPeter Avalos add_identity_file(Options *options, const char *dir, const char *filename,
46136e94dc5SPeter Avalos     int userprovided)
46236e94dc5SPeter Avalos {
46336e94dc5SPeter Avalos 	char *path;
46436e94dc5SPeter Avalos 	int i;
46536e94dc5SPeter Avalos 
46636e94dc5SPeter Avalos 	if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
46736e94dc5SPeter Avalos 		fatal("Too many identity files specified (max %d)",
46836e94dc5SPeter Avalos 		    SSH_MAX_IDENTITY_FILES);
46936e94dc5SPeter Avalos 
47036e94dc5SPeter Avalos 	if (dir == NULL) /* no dir, filename is absolute */
47136e94dc5SPeter Avalos 		path = xstrdup(filename);
472ce74bacaSMatthew Dillon 	else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX)
473ce74bacaSMatthew Dillon 		fatal("Identity file path %s too long", path);
47436e94dc5SPeter Avalos 
47536e94dc5SPeter Avalos 	/* Avoid registering duplicates */
47636e94dc5SPeter Avalos 	for (i = 0; i < options->num_identity_files; i++) {
47736e94dc5SPeter Avalos 		if (options->identity_file_userprovided[i] == userprovided &&
47836e94dc5SPeter Avalos 		    strcmp(options->identity_files[i], path) == 0) {
47936e94dc5SPeter Avalos 			debug2("%s: ignoring duplicate key %s", __func__, path);
48036e94dc5SPeter Avalos 			free(path);
48136e94dc5SPeter Avalos 			return;
48236e94dc5SPeter Avalos 		}
48336e94dc5SPeter Avalos 	}
48436e94dc5SPeter Avalos 
48536e94dc5SPeter Avalos 	options->identity_file_userprovided[options->num_identity_files] =
48636e94dc5SPeter Avalos 	    userprovided;
48736e94dc5SPeter Avalos 	options->identity_files[options->num_identity_files++] = path;
48836e94dc5SPeter Avalos }
48936e94dc5SPeter Avalos 
49036e94dc5SPeter Avalos int
49136e94dc5SPeter Avalos default_ssh_port(void)
49236e94dc5SPeter Avalos {
49336e94dc5SPeter Avalos 	static int port;
49436e94dc5SPeter Avalos 	struct servent *sp;
49536e94dc5SPeter Avalos 
49636e94dc5SPeter Avalos 	if (port == 0) {
49736e94dc5SPeter Avalos 		sp = getservbyname(SSH_SERVICE_NAME, "tcp");
49836e94dc5SPeter Avalos 		port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
49936e94dc5SPeter Avalos 	}
50036e94dc5SPeter Avalos 	return port;
50136e94dc5SPeter Avalos }
50236e94dc5SPeter Avalos 
50336e94dc5SPeter Avalos /*
50436e94dc5SPeter Avalos  * Execute a command in a shell.
50536e94dc5SPeter Avalos  * Return its exit status or -1 on abnormal exit.
50636e94dc5SPeter Avalos  */
50736e94dc5SPeter Avalos static int
50836e94dc5SPeter Avalos execute_in_shell(const char *cmd)
50936e94dc5SPeter Avalos {
510e9778795SPeter Avalos 	char *shell;
51136e94dc5SPeter Avalos 	pid_t pid;
51236e94dc5SPeter Avalos 	int devnull, status;
51336e94dc5SPeter Avalos 
51436e94dc5SPeter Avalos 	if ((shell = getenv("SHELL")) == NULL)
51536e94dc5SPeter Avalos 		shell = _PATH_BSHELL;
51636e94dc5SPeter Avalos 
517*0cbfa66cSDaniel Fojt 	if (access(shell, X_OK) == -1) {
518*0cbfa66cSDaniel Fojt 		fatal("Shell \"%s\" is not executable: %s",
519*0cbfa66cSDaniel Fojt 		    shell, strerror(errno));
520*0cbfa66cSDaniel Fojt 	}
521*0cbfa66cSDaniel Fojt 
52236e94dc5SPeter Avalos 	/* Need this to redirect subprocess stdin/out */
52336e94dc5SPeter Avalos 	if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
52436e94dc5SPeter Avalos 		fatal("open(/dev/null): %s", strerror(errno));
52536e94dc5SPeter Avalos 
52636e94dc5SPeter Avalos 	debug("Executing command: '%.500s'", cmd);
52736e94dc5SPeter Avalos 
52836e94dc5SPeter Avalos 	/* Fork and execute the command. */
52936e94dc5SPeter Avalos 	if ((pid = fork()) == 0) {
53036e94dc5SPeter Avalos 		char *argv[4];
53136e94dc5SPeter Avalos 
53236e94dc5SPeter Avalos 		/* Redirect child stdin and stdout. Leave stderr */
53336e94dc5SPeter Avalos 		if (dup2(devnull, STDIN_FILENO) == -1)
53436e94dc5SPeter Avalos 			fatal("dup2: %s", strerror(errno));
53536e94dc5SPeter Avalos 		if (dup2(devnull, STDOUT_FILENO) == -1)
53636e94dc5SPeter Avalos 			fatal("dup2: %s", strerror(errno));
53736e94dc5SPeter Avalos 		if (devnull > STDERR_FILENO)
53836e94dc5SPeter Avalos 			close(devnull);
53936e94dc5SPeter Avalos 		closefrom(STDERR_FILENO + 1);
54036e94dc5SPeter Avalos 
54136e94dc5SPeter Avalos 		argv[0] = shell;
54236e94dc5SPeter Avalos 		argv[1] = "-c";
543e9778795SPeter Avalos 		argv[2] = xstrdup(cmd);
54436e94dc5SPeter Avalos 		argv[3] = NULL;
54536e94dc5SPeter Avalos 
54636e94dc5SPeter Avalos 		execv(argv[0], argv);
54736e94dc5SPeter Avalos 		error("Unable to execute '%.100s': %s", cmd, strerror(errno));
54836e94dc5SPeter Avalos 		/* Die with signal to make this error apparent to parent. */
549*0cbfa66cSDaniel Fojt 		ssh_signal(SIGTERM, SIG_DFL);
55036e94dc5SPeter Avalos 		kill(getpid(), SIGTERM);
55136e94dc5SPeter Avalos 		_exit(1);
55236e94dc5SPeter Avalos 	}
55336e94dc5SPeter Avalos 	/* Parent. */
554*0cbfa66cSDaniel Fojt 	if (pid == -1)
55536e94dc5SPeter Avalos 		fatal("%s: fork: %.100s", __func__, strerror(errno));
55636e94dc5SPeter Avalos 
55736e94dc5SPeter Avalos 	close(devnull);
55836e94dc5SPeter Avalos 
55936e94dc5SPeter Avalos 	while (waitpid(pid, &status, 0) == -1) {
56036e94dc5SPeter Avalos 		if (errno != EINTR && errno != EAGAIN)
56136e94dc5SPeter Avalos 			fatal("%s: waitpid: %s", __func__, strerror(errno));
56236e94dc5SPeter Avalos 	}
56336e94dc5SPeter Avalos 	if (!WIFEXITED(status)) {
56436e94dc5SPeter Avalos 		error("command '%.100s' exited abnormally", cmd);
56536e94dc5SPeter Avalos 		return -1;
56636e94dc5SPeter Avalos 	}
56736e94dc5SPeter Avalos 	debug3("command returned status %d", WEXITSTATUS(status));
56836e94dc5SPeter Avalos 	return WEXITSTATUS(status);
56936e94dc5SPeter Avalos }
57036e94dc5SPeter Avalos 
57136e94dc5SPeter Avalos /*
57236e94dc5SPeter Avalos  * Parse and execute a Match directive.
57336e94dc5SPeter Avalos  */
57436e94dc5SPeter Avalos static int
57536e94dc5SPeter Avalos match_cfg_line(Options *options, char **condition, struct passwd *pw,
576664f4763Szrj     const char *host_arg, const char *original_host, int final_pass,
577664f4763Szrj     int *want_final_pass, const char *filename, int linenum)
57836e94dc5SPeter Avalos {
579e9778795SPeter Avalos 	char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
58036e94dc5SPeter Avalos 	const char *ruser;
581e9778795SPeter Avalos 	int r, port, this_result, result = 1, attributes = 0, negate;
58236e94dc5SPeter Avalos 	char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
583664f4763Szrj 	char uidstr[32];
58436e94dc5SPeter Avalos 
58536e94dc5SPeter Avalos 	/*
58636e94dc5SPeter Avalos 	 * Configuration is likely to be incomplete at this point so we
58736e94dc5SPeter Avalos 	 * must be prepared to use default values.
58836e94dc5SPeter Avalos 	 */
58936e94dc5SPeter Avalos 	port = options->port <= 0 ? default_ssh_port() : options->port;
59036e94dc5SPeter Avalos 	ruser = options->user == NULL ? pw->pw_name : options->user;
591664f4763Szrj 	if (final_pass) {
592e9778795SPeter Avalos 		host = xstrdup(options->hostname);
593e9778795SPeter Avalos 	} else if (options->hostname != NULL) {
59436e94dc5SPeter Avalos 		/* NB. Please keep in sync with ssh.c:main() */
59536e94dc5SPeter Avalos 		host = percent_expand(options->hostname,
59636e94dc5SPeter Avalos 		    "h", host_arg, (char *)NULL);
597e9778795SPeter Avalos 	} else {
59836e94dc5SPeter Avalos 		host = xstrdup(host_arg);
599e9778795SPeter Avalos 	}
60036e94dc5SPeter Avalos 
601e9778795SPeter Avalos 	debug2("checking match for '%s' host %s originally %s",
602e9778795SPeter Avalos 	    cp, host, original_host);
603e9778795SPeter Avalos 	while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
604e9778795SPeter Avalos 		criteria = NULL;
605e9778795SPeter Avalos 		this_result = 1;
606e9778795SPeter Avalos 		if ((negate = attrib[0] == '!'))
607e9778795SPeter Avalos 			attrib++;
608e9778795SPeter Avalos 		/* criteria "all" and "canonical" have no argument */
60936e94dc5SPeter Avalos 		if (strcasecmp(attrib, "all") == 0) {
610e9778795SPeter Avalos 			if (attributes > 1 ||
61136e94dc5SPeter Avalos 			    ((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
612e9778795SPeter Avalos 				error("%.200s line %d: '%s' cannot be combined "
613e9778795SPeter Avalos 				    "with other Match attributes",
614e9778795SPeter Avalos 				    filename, linenum, oattrib);
61536e94dc5SPeter Avalos 				result = -1;
61636e94dc5SPeter Avalos 				goto out;
61736e94dc5SPeter Avalos 			}
618e9778795SPeter Avalos 			if (result)
619e9778795SPeter Avalos 				result = negate ? 0 : 1;
62036e94dc5SPeter Avalos 			goto out;
62136e94dc5SPeter Avalos 		}
622e9778795SPeter Avalos 		attributes++;
623664f4763Szrj 		if (strcasecmp(attrib, "canonical") == 0 ||
624664f4763Szrj 		    strcasecmp(attrib, "final") == 0) {
625664f4763Szrj 			/*
626664f4763Szrj 			 * If the config requests "Match final" then remember
627664f4763Szrj 			 * this so we can perform a second pass later.
628664f4763Szrj 			 */
629664f4763Szrj 			if (strcasecmp(attrib, "final") == 0 &&
630664f4763Szrj 			    want_final_pass != NULL)
631664f4763Szrj 				*want_final_pass = 1;
632664f4763Szrj 			r = !!final_pass;  /* force bitmask member to boolean */
633e9778795SPeter Avalos 			if (r == (negate ? 1 : 0))
634e9778795SPeter Avalos 				this_result = result = 0;
635e9778795SPeter Avalos 			debug3("%.200s line %d: %smatched '%s'",
636e9778795SPeter Avalos 			    filename, linenum,
637e9778795SPeter Avalos 			    this_result ? "" : "not ", oattrib);
638e9778795SPeter Avalos 			continue;
639e9778795SPeter Avalos 		}
640e9778795SPeter Avalos 		/* All other criteria require an argument */
64136e94dc5SPeter Avalos 		if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
64236e94dc5SPeter Avalos 			error("Missing Match criteria for %s", attrib);
64336e94dc5SPeter Avalos 			result = -1;
64436e94dc5SPeter Avalos 			goto out;
64536e94dc5SPeter Avalos 		}
64636e94dc5SPeter Avalos 		if (strcasecmp(attrib, "host") == 0) {
647e9778795SPeter Avalos 			criteria = xstrdup(host);
648e9778795SPeter Avalos 			r = match_hostname(host, arg) == 1;
649e9778795SPeter Avalos 			if (r == (negate ? 1 : 0))
650e9778795SPeter Avalos 				this_result = result = 0;
65136e94dc5SPeter Avalos 		} else if (strcasecmp(attrib, "originalhost") == 0) {
652e9778795SPeter Avalos 			criteria = xstrdup(original_host);
653e9778795SPeter Avalos 			r = match_hostname(original_host, arg) == 1;
654e9778795SPeter Avalos 			if (r == (negate ? 1 : 0))
655e9778795SPeter Avalos 				this_result = result = 0;
65636e94dc5SPeter Avalos 		} else if (strcasecmp(attrib, "user") == 0) {
657e9778795SPeter Avalos 			criteria = xstrdup(ruser);
658e9778795SPeter Avalos 			r = match_pattern_list(ruser, arg, 0) == 1;
659e9778795SPeter Avalos 			if (r == (negate ? 1 : 0))
660e9778795SPeter Avalos 				this_result = result = 0;
66136e94dc5SPeter Avalos 		} else if (strcasecmp(attrib, "localuser") == 0) {
662e9778795SPeter Avalos 			criteria = xstrdup(pw->pw_name);
663e9778795SPeter Avalos 			r = match_pattern_list(pw->pw_name, arg, 0) == 1;
664e9778795SPeter Avalos 			if (r == (negate ? 1 : 0))
665e9778795SPeter Avalos 				this_result = result = 0;
66636e94dc5SPeter Avalos 		} else if (strcasecmp(attrib, "exec") == 0) {
667*0cbfa66cSDaniel Fojt 			char *conn_hash_hex;
668*0cbfa66cSDaniel Fojt 
66936e94dc5SPeter Avalos 			if (gethostname(thishost, sizeof(thishost)) == -1)
67036e94dc5SPeter Avalos 				fatal("gethostname: %s", strerror(errno));
67136e94dc5SPeter Avalos 			strlcpy(shorthost, thishost, sizeof(shorthost));
67236e94dc5SPeter Avalos 			shorthost[strcspn(thishost, ".")] = '\0';
67336e94dc5SPeter Avalos 			snprintf(portstr, sizeof(portstr), "%d", port);
674664f4763Szrj 			snprintf(uidstr, sizeof(uidstr), "%llu",
675664f4763Szrj 			    (unsigned long long)pw->pw_uid);
676*0cbfa66cSDaniel Fojt 			conn_hash_hex = ssh_connection_hash(thishost, host,
677*0cbfa66cSDaniel Fojt 			   portstr, ruser);
67836e94dc5SPeter Avalos 
67936e94dc5SPeter Avalos 			cmd = percent_expand(arg,
680*0cbfa66cSDaniel Fojt 			    "C", conn_hash_hex,
68136e94dc5SPeter Avalos 			    "L", shorthost,
68236e94dc5SPeter Avalos 			    "d", pw->pw_dir,
68336e94dc5SPeter Avalos 			    "h", host,
68436e94dc5SPeter Avalos 			    "l", thishost,
685e9778795SPeter Avalos 			    "n", original_host,
68636e94dc5SPeter Avalos 			    "p", portstr,
68736e94dc5SPeter Avalos 			    "r", ruser,
68836e94dc5SPeter Avalos 			    "u", pw->pw_name,
689664f4763Szrj 			    "i", uidstr,
69036e94dc5SPeter Avalos 			    (char *)NULL);
691*0cbfa66cSDaniel Fojt 			free(conn_hash_hex);
69236e94dc5SPeter Avalos 			if (result != 1) {
69336e94dc5SPeter Avalos 				/* skip execution if prior predicate failed */
694e9778795SPeter Avalos 				debug3("%.200s line %d: skipped exec "
695e9778795SPeter Avalos 				    "\"%.100s\"", filename, linenum, cmd);
696e9778795SPeter Avalos 				free(cmd);
697e9778795SPeter Avalos 				continue;
698e9778795SPeter Avalos 			}
69936e94dc5SPeter Avalos 			r = execute_in_shell(cmd);
70036e94dc5SPeter Avalos 			if (r == -1) {
70136e94dc5SPeter Avalos 				fatal("%.200s line %d: match exec "
70236e94dc5SPeter Avalos 				    "'%.100s' error", filename,
70336e94dc5SPeter Avalos 				    linenum, cmd);
70436e94dc5SPeter Avalos 			}
705e9778795SPeter Avalos 			criteria = xstrdup(cmd);
70636e94dc5SPeter Avalos 			free(cmd);
707e9778795SPeter Avalos 			/* Force exit status to boolean */
708e9778795SPeter Avalos 			r = r == 0;
709e9778795SPeter Avalos 			if (r == (negate ? 1 : 0))
710e9778795SPeter Avalos 				this_result = result = 0;
71136e94dc5SPeter Avalos 		} else {
71236e94dc5SPeter Avalos 			error("Unsupported Match attribute %s", attrib);
71336e94dc5SPeter Avalos 			result = -1;
71436e94dc5SPeter Avalos 			goto out;
71536e94dc5SPeter Avalos 		}
716e9778795SPeter Avalos 		debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
717e9778795SPeter Avalos 		    filename, linenum, this_result ? "": "not ",
718e9778795SPeter Avalos 		    oattrib, criteria);
719e9778795SPeter Avalos 		free(criteria);
72036e94dc5SPeter Avalos 	}
72136e94dc5SPeter Avalos 	if (attributes == 0) {
72236e94dc5SPeter Avalos 		error("One or more attributes required for Match");
72336e94dc5SPeter Avalos 		result = -1;
72436e94dc5SPeter Avalos 		goto out;
72536e94dc5SPeter Avalos 	}
72636e94dc5SPeter Avalos  out:
727e9778795SPeter Avalos 	if (result != -1)
728e9778795SPeter Avalos 		debug2("match %sfound", result ? "" : "not ");
729e9778795SPeter Avalos 	*condition = cp;
73036e94dc5SPeter Avalos 	free(host);
73136e94dc5SPeter Avalos 	return result;
73236e94dc5SPeter Avalos }
73336e94dc5SPeter Avalos 
734664f4763Szrj /* Remove environment variable by pattern */
73536e94dc5SPeter Avalos static void
736664f4763Szrj rm_env(Options *options, const char *arg, const char *filename, int linenum)
73736e94dc5SPeter Avalos {
738664f4763Szrj 	int i, j;
739664f4763Szrj 	char *cp;
74036e94dc5SPeter Avalos 
741664f4763Szrj 	/* Remove an environment variable */
742664f4763Szrj 	for (i = 0; i < options->num_send_env; ) {
743664f4763Szrj 		cp = xstrdup(options->send_env[i]);
744664f4763Szrj 		if (!match_pattern(cp, arg + 1)) {
745664f4763Szrj 			free(cp);
746664f4763Szrj 			i++;
747664f4763Szrj 			continue;
74836e94dc5SPeter Avalos 		}
749664f4763Szrj 		debug3("%s line %d: removing environment %s",
750664f4763Szrj 		    filename, linenum, cp);
751664f4763Szrj 		free(cp);
752664f4763Szrj 		free(options->send_env[i]);
753664f4763Szrj 		options->send_env[i] = NULL;
754664f4763Szrj 		for (j = i; j < options->num_send_env - 1; j++) {
755664f4763Szrj 			options->send_env[j] = options->send_env[j + 1];
756664f4763Szrj 			options->send_env[j + 1] = NULL;
757664f4763Szrj 		}
758664f4763Szrj 		options->num_send_env--;
759664f4763Szrj 		/* NB. don't increment i */
760664f4763Szrj 	}
76136e94dc5SPeter Avalos }
76236e94dc5SPeter Avalos 
76318de8d7fSPeter Avalos /*
76418de8d7fSPeter Avalos  * Returns the number of the token pointed to by cp or oBadOption.
76518de8d7fSPeter Avalos  */
76618de8d7fSPeter Avalos static OpCodes
76736e94dc5SPeter Avalos parse_token(const char *cp, const char *filename, int linenum,
76836e94dc5SPeter Avalos     const char *ignored_unknown)
76918de8d7fSPeter Avalos {
77036e94dc5SPeter Avalos 	int i;
77118de8d7fSPeter Avalos 
77218de8d7fSPeter Avalos 	for (i = 0; keywords[i].name; i++)
77336e94dc5SPeter Avalos 		if (strcmp(cp, keywords[i].name) == 0)
77418de8d7fSPeter Avalos 			return keywords[i].opcode;
775e9778795SPeter Avalos 	if (ignored_unknown != NULL &&
776e9778795SPeter Avalos 	    match_pattern_list(cp, ignored_unknown, 1) == 1)
77736e94dc5SPeter Avalos 		return oIgnoredUnknownOption;
77818de8d7fSPeter Avalos 	error("%s: line %d: Bad configuration option: %s",
77918de8d7fSPeter Avalos 	    filename, linenum, cp);
78018de8d7fSPeter Avalos 	return oBadOption;
78118de8d7fSPeter Avalos }
78218de8d7fSPeter Avalos 
78336e94dc5SPeter Avalos /* Multistate option parsing */
78436e94dc5SPeter Avalos struct multistate {
78536e94dc5SPeter Avalos 	char *key;
78636e94dc5SPeter Avalos 	int value;
78736e94dc5SPeter Avalos };
78836e94dc5SPeter Avalos static const struct multistate multistate_flag[] = {
78936e94dc5SPeter Avalos 	{ "true",			1 },
79036e94dc5SPeter Avalos 	{ "false",			0 },
79136e94dc5SPeter Avalos 	{ "yes",			1 },
79236e94dc5SPeter Avalos 	{ "no",				0 },
79336e94dc5SPeter Avalos 	{ NULL, -1 }
79436e94dc5SPeter Avalos };
79536e94dc5SPeter Avalos static const struct multistate multistate_yesnoask[] = {
79636e94dc5SPeter Avalos 	{ "true",			1 },
79736e94dc5SPeter Avalos 	{ "false",			0 },
79836e94dc5SPeter Avalos 	{ "yes",			1 },
79936e94dc5SPeter Avalos 	{ "no",				0 },
80036e94dc5SPeter Avalos 	{ "ask",			2 },
80136e94dc5SPeter Avalos 	{ NULL, -1 }
80236e94dc5SPeter Avalos };
803ce74bacaSMatthew Dillon static const struct multistate multistate_strict_hostkey[] = {
804ce74bacaSMatthew Dillon 	{ "true",			SSH_STRICT_HOSTKEY_YES },
805ce74bacaSMatthew Dillon 	{ "false",			SSH_STRICT_HOSTKEY_OFF },
806ce74bacaSMatthew Dillon 	{ "yes",			SSH_STRICT_HOSTKEY_YES },
807ce74bacaSMatthew Dillon 	{ "no",				SSH_STRICT_HOSTKEY_OFF },
808ce74bacaSMatthew Dillon 	{ "ask",			SSH_STRICT_HOSTKEY_ASK },
809ce74bacaSMatthew Dillon 	{ "off",			SSH_STRICT_HOSTKEY_OFF },
810ce74bacaSMatthew Dillon 	{ "accept-new",			SSH_STRICT_HOSTKEY_NEW },
811ce74bacaSMatthew Dillon 	{ NULL, -1 }
812ce74bacaSMatthew Dillon };
813e9778795SPeter Avalos static const struct multistate multistate_yesnoaskconfirm[] = {
814e9778795SPeter Avalos 	{ "true",			1 },
815e9778795SPeter Avalos 	{ "false",			0 },
816e9778795SPeter Avalos 	{ "yes",			1 },
817e9778795SPeter Avalos 	{ "no",				0 },
818e9778795SPeter Avalos 	{ "ask",			2 },
819e9778795SPeter Avalos 	{ "confirm",			3 },
820e9778795SPeter Avalos 	{ NULL, -1 }
821e9778795SPeter Avalos };
82236e94dc5SPeter Avalos static const struct multistate multistate_addressfamily[] = {
82336e94dc5SPeter Avalos 	{ "inet",			AF_INET },
82436e94dc5SPeter Avalos 	{ "inet6",			AF_INET6 },
82536e94dc5SPeter Avalos 	{ "any",			AF_UNSPEC },
82636e94dc5SPeter Avalos 	{ NULL, -1 }
82736e94dc5SPeter Avalos };
82836e94dc5SPeter Avalos static const struct multistate multistate_controlmaster[] = {
82936e94dc5SPeter Avalos 	{ "true",			SSHCTL_MASTER_YES },
83036e94dc5SPeter Avalos 	{ "yes",			SSHCTL_MASTER_YES },
83136e94dc5SPeter Avalos 	{ "false",			SSHCTL_MASTER_NO },
83236e94dc5SPeter Avalos 	{ "no",				SSHCTL_MASTER_NO },
83336e94dc5SPeter Avalos 	{ "auto",			SSHCTL_MASTER_AUTO },
83436e94dc5SPeter Avalos 	{ "ask",			SSHCTL_MASTER_ASK },
83536e94dc5SPeter Avalos 	{ "autoask",			SSHCTL_MASTER_AUTO_ASK },
83636e94dc5SPeter Avalos 	{ NULL, -1 }
83736e94dc5SPeter Avalos };
83836e94dc5SPeter Avalos static const struct multistate multistate_tunnel[] = {
83936e94dc5SPeter Avalos 	{ "ethernet",			SSH_TUNMODE_ETHERNET },
84036e94dc5SPeter Avalos 	{ "point-to-point",		SSH_TUNMODE_POINTOPOINT },
84136e94dc5SPeter Avalos 	{ "true",			SSH_TUNMODE_DEFAULT },
84236e94dc5SPeter Avalos 	{ "yes",			SSH_TUNMODE_DEFAULT },
84336e94dc5SPeter Avalos 	{ "false",			SSH_TUNMODE_NO },
84436e94dc5SPeter Avalos 	{ "no",				SSH_TUNMODE_NO },
84536e94dc5SPeter Avalos 	{ NULL, -1 }
84636e94dc5SPeter Avalos };
84736e94dc5SPeter Avalos static const struct multistate multistate_requesttty[] = {
84836e94dc5SPeter Avalos 	{ "true",			REQUEST_TTY_YES },
84936e94dc5SPeter Avalos 	{ "yes",			REQUEST_TTY_YES },
85036e94dc5SPeter Avalos 	{ "false",			REQUEST_TTY_NO },
85136e94dc5SPeter Avalos 	{ "no",				REQUEST_TTY_NO },
85236e94dc5SPeter Avalos 	{ "force",			REQUEST_TTY_FORCE },
85336e94dc5SPeter Avalos 	{ "auto",			REQUEST_TTY_AUTO },
85436e94dc5SPeter Avalos 	{ NULL, -1 }
85536e94dc5SPeter Avalos };
85636e94dc5SPeter Avalos static const struct multistate multistate_canonicalizehostname[] = {
85736e94dc5SPeter Avalos 	{ "true",			SSH_CANONICALISE_YES },
85836e94dc5SPeter Avalos 	{ "false",			SSH_CANONICALISE_NO },
85936e94dc5SPeter Avalos 	{ "yes",			SSH_CANONICALISE_YES },
86036e94dc5SPeter Avalos 	{ "no",				SSH_CANONICALISE_NO },
86136e94dc5SPeter Avalos 	{ "always",			SSH_CANONICALISE_ALWAYS },
86236e94dc5SPeter Avalos 	{ NULL, -1 }
86336e94dc5SPeter Avalos };
864*0cbfa66cSDaniel Fojt static const struct multistate multistate_compression[] = {
865*0cbfa66cSDaniel Fojt #ifdef WITH_ZLIB
866*0cbfa66cSDaniel Fojt 	{ "yes",			COMP_ZLIB },
867*0cbfa66cSDaniel Fojt #endif
868*0cbfa66cSDaniel Fojt 	{ "no",				COMP_NONE },
869*0cbfa66cSDaniel Fojt 	{ NULL, -1 }
870*0cbfa66cSDaniel Fojt };
87136e94dc5SPeter Avalos 
87218de8d7fSPeter Avalos /*
87318de8d7fSPeter Avalos  * Processes a single option line as used in the configuration files. This
87418de8d7fSPeter Avalos  * only sets those values that have not already been set.
87518de8d7fSPeter Avalos  */
87618de8d7fSPeter Avalos int
87736e94dc5SPeter Avalos process_config_line(Options *options, struct passwd *pw, const char *host,
878e9778795SPeter Avalos     const char *original_host, char *line, const char *filename,
879e9778795SPeter Avalos     int linenum, int *activep, int flags)
880e9778795SPeter Avalos {
881e9778795SPeter Avalos 	return process_config_line_depth(options, pw, host, original_host,
882664f4763Szrj 	    line, filename, linenum, activep, flags, NULL, 0);
883e9778795SPeter Avalos }
884e9778795SPeter Avalos 
885e9778795SPeter Avalos #define WHITESPACE " \t\r\n"
886e9778795SPeter Avalos static int
887e9778795SPeter Avalos process_config_line_depth(Options *options, struct passwd *pw, const char *host,
888e9778795SPeter Avalos     const char *original_host, char *line, const char *filename,
889664f4763Szrj     int linenum, int *activep, int flags, int *want_final_pass, int depth)
89018de8d7fSPeter Avalos {
8911c188a7fSPeter Avalos 	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
8921c188a7fSPeter Avalos 	char **cpptr, fwdarg[256];
89336e94dc5SPeter Avalos 	u_int i, *uintptr, max_entries = 0;
894e9778795SPeter Avalos 	int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
895ce74bacaSMatthew Dillon 	int remotefwd, dynamicfwd;
89618de8d7fSPeter Avalos 	LogLevel *log_level_ptr;
897ce74bacaSMatthew Dillon 	SyslogFacility *log_facility_ptr;
89836e94dc5SPeter Avalos 	long long val64;
89918de8d7fSPeter Avalos 	size_t len;
90036e94dc5SPeter Avalos 	struct Forward fwd;
90136e94dc5SPeter Avalos 	const struct multistate *multistate_ptr;
90236e94dc5SPeter Avalos 	struct allowed_cname *cname;
903e9778795SPeter Avalos 	glob_t gl;
904664f4763Szrj 	const char *errstr;
90536e94dc5SPeter Avalos 
90636e94dc5SPeter Avalos 	if (activep == NULL) { /* We are processing a command line directive */
90736e94dc5SPeter Avalos 		cmdline = 1;
90836e94dc5SPeter Avalos 		activep = &cmdline;
90936e94dc5SPeter Avalos 	}
91018de8d7fSPeter Avalos 
911ce74bacaSMatthew Dillon 	/* Strip trailing whitespace. Allow \f (form feed) at EOL only */
912e9778795SPeter Avalos 	if ((len = strlen(line)) == 0)
913e9778795SPeter Avalos 		return 0;
914e9778795SPeter Avalos 	for (len--; len > 0; len--) {
915ce74bacaSMatthew Dillon 		if (strchr(WHITESPACE "\f", line[len]) == NULL)
91618de8d7fSPeter Avalos 			break;
91718de8d7fSPeter Avalos 		line[len] = '\0';
91818de8d7fSPeter Avalos 	}
91918de8d7fSPeter Avalos 
92018de8d7fSPeter Avalos 	s = line;
92118de8d7fSPeter Avalos 	/* Get the keyword. (Each line is supposed to begin with a keyword). */
92218de8d7fSPeter Avalos 	if ((keyword = strdelim(&s)) == NULL)
92318de8d7fSPeter Avalos 		return 0;
92418de8d7fSPeter Avalos 	/* Ignore leading whitespace. */
92518de8d7fSPeter Avalos 	if (*keyword == '\0')
92618de8d7fSPeter Avalos 		keyword = strdelim(&s);
92718de8d7fSPeter Avalos 	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
92818de8d7fSPeter Avalos 		return 0;
92936e94dc5SPeter Avalos 	/* Match lowercase keyword */
93036e94dc5SPeter Avalos 	lowercase(keyword);
93118de8d7fSPeter Avalos 
93236e94dc5SPeter Avalos 	opcode = parse_token(keyword, filename, linenum,
93336e94dc5SPeter Avalos 	    options->ignored_unknown);
93418de8d7fSPeter Avalos 
93518de8d7fSPeter Avalos 	switch (opcode) {
93618de8d7fSPeter Avalos 	case oBadOption:
93718de8d7fSPeter Avalos 		/* don't panic, but count bad options */
93818de8d7fSPeter Avalos 		return -1;
939ce74bacaSMatthew Dillon 	case oIgnore:
940ce74bacaSMatthew Dillon 		return 0;
94136e94dc5SPeter Avalos 	case oIgnoredUnknownOption:
94236e94dc5SPeter Avalos 		debug("%s line %d: Ignored unknown option \"%s\"",
94336e94dc5SPeter Avalos 		    filename, linenum, keyword);
94436e94dc5SPeter Avalos 		return 0;
94518de8d7fSPeter Avalos 	case oConnectTimeout:
94618de8d7fSPeter Avalos 		intptr = &options->connection_timeout;
94718de8d7fSPeter Avalos parse_time:
94818de8d7fSPeter Avalos 		arg = strdelim(&s);
94918de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
95018de8d7fSPeter Avalos 			fatal("%s line %d: missing time value.",
95118de8d7fSPeter Avalos 			    filename, linenum);
952e9778795SPeter Avalos 		if (strcmp(arg, "none") == 0)
953e9778795SPeter Avalos 			value = -1;
954e9778795SPeter Avalos 		else if ((value = convtime(arg)) == -1)
95518de8d7fSPeter Avalos 			fatal("%s line %d: invalid time value.",
95618de8d7fSPeter Avalos 			    filename, linenum);
95718de8d7fSPeter Avalos 		if (*activep && *intptr == -1)
95818de8d7fSPeter Avalos 			*intptr = value;
95918de8d7fSPeter Avalos 		break;
96018de8d7fSPeter Avalos 
96118de8d7fSPeter Avalos 	case oForwardAgent:
96218de8d7fSPeter Avalos 		intptr = &options->forward_agent;
963*0cbfa66cSDaniel Fojt 
964*0cbfa66cSDaniel Fojt 		arg = strdelim(&s);
965*0cbfa66cSDaniel Fojt 		if (!arg || *arg == '\0')
966*0cbfa66cSDaniel Fojt 			fatal("%s line %d: missing argument.",
967*0cbfa66cSDaniel Fojt 			    filename, linenum);
968*0cbfa66cSDaniel Fojt 
969*0cbfa66cSDaniel Fojt 		value = -1;
970*0cbfa66cSDaniel Fojt 		multistate_ptr = multistate_flag;
971*0cbfa66cSDaniel Fojt 		for (i = 0; multistate_ptr[i].key != NULL; i++) {
972*0cbfa66cSDaniel Fojt 			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
973*0cbfa66cSDaniel Fojt 				value = multistate_ptr[i].value;
974*0cbfa66cSDaniel Fojt 				break;
975*0cbfa66cSDaniel Fojt 			}
976*0cbfa66cSDaniel Fojt 		}
977*0cbfa66cSDaniel Fojt 		if (value != -1) {
978*0cbfa66cSDaniel Fojt 			if (*activep && *intptr == -1)
979*0cbfa66cSDaniel Fojt 				*intptr = value;
980*0cbfa66cSDaniel Fojt 			break;
981*0cbfa66cSDaniel Fojt 		}
982*0cbfa66cSDaniel Fojt 		/* ForwardAgent wasn't 'yes' or 'no', assume a path */
983*0cbfa66cSDaniel Fojt 		if (*activep && *intptr == -1)
984*0cbfa66cSDaniel Fojt 			*intptr = 1;
985*0cbfa66cSDaniel Fojt 
986*0cbfa66cSDaniel Fojt 		charptr = &options->forward_agent_sock_path;
987*0cbfa66cSDaniel Fojt 		goto parse_agent_path;
988*0cbfa66cSDaniel Fojt 
989*0cbfa66cSDaniel Fojt 	case oForwardX11:
990*0cbfa66cSDaniel Fojt 		intptr = &options->forward_x11;
99118de8d7fSPeter Avalos  parse_flag:
99236e94dc5SPeter Avalos 		multistate_ptr = multistate_flag;
99336e94dc5SPeter Avalos  parse_multistate:
99418de8d7fSPeter Avalos 		arg = strdelim(&s);
99518de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
99636e94dc5SPeter Avalos 			fatal("%s line %d: missing argument.",
99736e94dc5SPeter Avalos 			    filename, linenum);
99836e94dc5SPeter Avalos 		value = -1;
99936e94dc5SPeter Avalos 		for (i = 0; multistate_ptr[i].key != NULL; i++) {
100036e94dc5SPeter Avalos 			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
100136e94dc5SPeter Avalos 				value = multistate_ptr[i].value;
100236e94dc5SPeter Avalos 				break;
100336e94dc5SPeter Avalos 			}
100436e94dc5SPeter Avalos 		}
100536e94dc5SPeter Avalos 		if (value == -1)
100636e94dc5SPeter Avalos 			fatal("%s line %d: unsupported option \"%s\".",
100736e94dc5SPeter Avalos 			    filename, linenum, arg);
100818de8d7fSPeter Avalos 		if (*activep && *intptr == -1)
100918de8d7fSPeter Avalos 			*intptr = value;
101018de8d7fSPeter Avalos 		break;
101118de8d7fSPeter Avalos 
101218de8d7fSPeter Avalos 	case oForwardX11Trusted:
101318de8d7fSPeter Avalos 		intptr = &options->forward_x11_trusted;
101418de8d7fSPeter Avalos 		goto parse_flag;
101518de8d7fSPeter Avalos 
1016856ea928SPeter Avalos 	case oForwardX11Timeout:
1017856ea928SPeter Avalos 		intptr = &options->forward_x11_timeout;
1018856ea928SPeter Avalos 		goto parse_time;
1019856ea928SPeter Avalos 
102018de8d7fSPeter Avalos 	case oGatewayPorts:
102136e94dc5SPeter Avalos 		intptr = &options->fwd_opts.gateway_ports;
102218de8d7fSPeter Avalos 		goto parse_flag;
102318de8d7fSPeter Avalos 
102418de8d7fSPeter Avalos 	case oExitOnForwardFailure:
102518de8d7fSPeter Avalos 		intptr = &options->exit_on_forward_failure;
102618de8d7fSPeter Avalos 		goto parse_flag;
102718de8d7fSPeter Avalos 
102818de8d7fSPeter Avalos 	case oPasswordAuthentication:
102918de8d7fSPeter Avalos 		intptr = &options->password_authentication;
103018de8d7fSPeter Avalos 		goto parse_flag;
103118de8d7fSPeter Avalos 
103218de8d7fSPeter Avalos 	case oKbdInteractiveAuthentication:
103318de8d7fSPeter Avalos 		intptr = &options->kbd_interactive_authentication;
103418de8d7fSPeter Avalos 		goto parse_flag;
103518de8d7fSPeter Avalos 
103618de8d7fSPeter Avalos 	case oKbdInteractiveDevices:
103718de8d7fSPeter Avalos 		charptr = &options->kbd_interactive_devices;
103818de8d7fSPeter Avalos 		goto parse_string;
103918de8d7fSPeter Avalos 
104018de8d7fSPeter Avalos 	case oPubkeyAuthentication:
104118de8d7fSPeter Avalos 		intptr = &options->pubkey_authentication;
104218de8d7fSPeter Avalos 		goto parse_flag;
104318de8d7fSPeter Avalos 
104418de8d7fSPeter Avalos 	case oHostbasedAuthentication:
104518de8d7fSPeter Avalos 		intptr = &options->hostbased_authentication;
104618de8d7fSPeter Avalos 		goto parse_flag;
104718de8d7fSPeter Avalos 
104818de8d7fSPeter Avalos 	case oChallengeResponseAuthentication:
104918de8d7fSPeter Avalos 		intptr = &options->challenge_response_authentication;
105018de8d7fSPeter Avalos 		goto parse_flag;
105118de8d7fSPeter Avalos 
105218de8d7fSPeter Avalos 	case oGssAuthentication:
105318de8d7fSPeter Avalos 		intptr = &options->gss_authentication;
105418de8d7fSPeter Avalos 		goto parse_flag;
105518de8d7fSPeter Avalos 
105618de8d7fSPeter Avalos 	case oGssDelegateCreds:
105718de8d7fSPeter Avalos 		intptr = &options->gss_deleg_creds;
105818de8d7fSPeter Avalos 		goto parse_flag;
105918de8d7fSPeter Avalos 
106018de8d7fSPeter Avalos 	case oBatchMode:
106118de8d7fSPeter Avalos 		intptr = &options->batch_mode;
106218de8d7fSPeter Avalos 		goto parse_flag;
106318de8d7fSPeter Avalos 
106418de8d7fSPeter Avalos 	case oCheckHostIP:
106518de8d7fSPeter Avalos 		intptr = &options->check_host_ip;
106618de8d7fSPeter Avalos 		goto parse_flag;
106718de8d7fSPeter Avalos 
106818de8d7fSPeter Avalos 	case oVerifyHostKeyDNS:
106918de8d7fSPeter Avalos 		intptr = &options->verify_host_key_dns;
107036e94dc5SPeter Avalos 		multistate_ptr = multistate_yesnoask;
107136e94dc5SPeter Avalos 		goto parse_multistate;
107218de8d7fSPeter Avalos 
107318de8d7fSPeter Avalos 	case oStrictHostKeyChecking:
107418de8d7fSPeter Avalos 		intptr = &options->strict_host_key_checking;
1075ce74bacaSMatthew Dillon 		multistate_ptr = multistate_strict_hostkey;
107636e94dc5SPeter Avalos 		goto parse_multistate;
107718de8d7fSPeter Avalos 
107818de8d7fSPeter Avalos 	case oCompression:
107918de8d7fSPeter Avalos 		intptr = &options->compression;
1080*0cbfa66cSDaniel Fojt 		multistate_ptr = multistate_compression;
1081*0cbfa66cSDaniel Fojt 		goto parse_multistate;
108218de8d7fSPeter Avalos 
108318de8d7fSPeter Avalos 	case oTCPKeepAlive:
108418de8d7fSPeter Avalos 		intptr = &options->tcp_keep_alive;
108518de8d7fSPeter Avalos 		goto parse_flag;
108618de8d7fSPeter Avalos 
108718de8d7fSPeter Avalos 	case oNoHostAuthenticationForLocalhost:
108818de8d7fSPeter Avalos 		intptr = &options->no_host_authentication_for_localhost;
108918de8d7fSPeter Avalos 		goto parse_flag;
109018de8d7fSPeter Avalos 
109118de8d7fSPeter Avalos 	case oNumberOfPasswordPrompts:
109218de8d7fSPeter Avalos 		intptr = &options->number_of_password_prompts;
109318de8d7fSPeter Avalos 		goto parse_int;
109418de8d7fSPeter Avalos 
109518de8d7fSPeter Avalos 	case oRekeyLimit:
109618de8d7fSPeter Avalos 		arg = strdelim(&s);
109718de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
109836e94dc5SPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename,
109936e94dc5SPeter Avalos 			    linenum);
110036e94dc5SPeter Avalos 		if (strcmp(arg, "default") == 0) {
110136e94dc5SPeter Avalos 			val64 = 0;
110236e94dc5SPeter Avalos 		} else {
110336e94dc5SPeter Avalos 			if (scan_scaled(arg, &val64) == -1)
110436e94dc5SPeter Avalos 				fatal("%.200s line %d: Bad number '%s': %s",
110536e94dc5SPeter Avalos 				    filename, linenum, arg, strerror(errno));
110636e94dc5SPeter Avalos 			if (val64 != 0 && val64 < 16)
110718de8d7fSPeter Avalos 				fatal("%.200s line %d: RekeyLimit too small",
110818de8d7fSPeter Avalos 				    filename, linenum);
110936e94dc5SPeter Avalos 		}
111018de8d7fSPeter Avalos 		if (*activep && options->rekey_limit == -1)
1111e9778795SPeter Avalos 			options->rekey_limit = val64;
111236e94dc5SPeter Avalos 		if (s != NULL) { /* optional rekey interval present */
111336e94dc5SPeter Avalos 			if (strcmp(s, "none") == 0) {
111436e94dc5SPeter Avalos 				(void)strdelim(&s);	/* discard */
111536e94dc5SPeter Avalos 				break;
111636e94dc5SPeter Avalos 			}
111736e94dc5SPeter Avalos 			intptr = &options->rekey_interval;
111836e94dc5SPeter Avalos 			goto parse_time;
111936e94dc5SPeter Avalos 		}
112018de8d7fSPeter Avalos 		break;
112118de8d7fSPeter Avalos 
112218de8d7fSPeter Avalos 	case oIdentityFile:
112318de8d7fSPeter Avalos 		arg = strdelim(&s);
112418de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
112518de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
112618de8d7fSPeter Avalos 		if (*activep) {
112718de8d7fSPeter Avalos 			intptr = &options->num_identity_files;
112818de8d7fSPeter Avalos 			if (*intptr >= SSH_MAX_IDENTITY_FILES)
112918de8d7fSPeter Avalos 				fatal("%.200s line %d: Too many identity files specified (max %d).",
113018de8d7fSPeter Avalos 				    filename, linenum, SSH_MAX_IDENTITY_FILES);
1131e9778795SPeter Avalos 			add_identity_file(options, NULL,
1132e9778795SPeter Avalos 			    arg, flags & SSHCONF_USERCONF);
1133e9778795SPeter Avalos 		}
1134e9778795SPeter Avalos 		break;
1135e9778795SPeter Avalos 
1136e9778795SPeter Avalos 	case oCertificateFile:
1137e9778795SPeter Avalos 		arg = strdelim(&s);
1138e9778795SPeter Avalos 		if (!arg || *arg == '\0')
1139e9778795SPeter Avalos 			fatal("%.200s line %d: Missing argument.",
1140e9778795SPeter Avalos 			    filename, linenum);
1141e9778795SPeter Avalos 		if (*activep) {
1142e9778795SPeter Avalos 			intptr = &options->num_certificate_files;
1143e9778795SPeter Avalos 			if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
1144e9778795SPeter Avalos 				fatal("%.200s line %d: Too many certificate "
1145e9778795SPeter Avalos 				    "files specified (max %d).",
1146e9778795SPeter Avalos 				    filename, linenum,
1147e9778795SPeter Avalos 				    SSH_MAX_CERTIFICATE_FILES);
1148e9778795SPeter Avalos 			}
1149e9778795SPeter Avalos 			add_certificate_file(options, arg,
1150e9778795SPeter Avalos 			    flags & SSHCONF_USERCONF);
115118de8d7fSPeter Avalos 		}
115218de8d7fSPeter Avalos 		break;
115318de8d7fSPeter Avalos 
115418de8d7fSPeter Avalos 	case oXAuthLocation:
115518de8d7fSPeter Avalos 		charptr=&options->xauth_location;
115618de8d7fSPeter Avalos 		goto parse_string;
115718de8d7fSPeter Avalos 
115818de8d7fSPeter Avalos 	case oUser:
115918de8d7fSPeter Avalos 		charptr = &options->user;
116018de8d7fSPeter Avalos parse_string:
116118de8d7fSPeter Avalos 		arg = strdelim(&s);
116218de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
11631c188a7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.",
11641c188a7fSPeter Avalos 			    filename, linenum);
116518de8d7fSPeter Avalos 		if (*activep && *charptr == NULL)
116618de8d7fSPeter Avalos 			*charptr = xstrdup(arg);
116718de8d7fSPeter Avalos 		break;
116818de8d7fSPeter Avalos 
116918de8d7fSPeter Avalos 	case oGlobalKnownHostsFile:
11701c188a7fSPeter Avalos 		cpptr = (char **)&options->system_hostfiles;
11711c188a7fSPeter Avalos 		uintptr = &options->num_system_hostfiles;
11721c188a7fSPeter Avalos 		max_entries = SSH_MAX_HOSTS_FILES;
11731c188a7fSPeter Avalos parse_char_array:
11741c188a7fSPeter Avalos 		if (*activep && *uintptr == 0) {
11751c188a7fSPeter Avalos 			while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
11761c188a7fSPeter Avalos 				if ((*uintptr) >= max_entries)
11771c188a7fSPeter Avalos 					fatal("%s line %d: "
1178*0cbfa66cSDaniel Fojt 					    "too many known hosts files.",
11791c188a7fSPeter Avalos 					    filename, linenum);
11801c188a7fSPeter Avalos 				cpptr[(*uintptr)++] = xstrdup(arg);
11811c188a7fSPeter Avalos 			}
11821c188a7fSPeter Avalos 		}
11831c188a7fSPeter Avalos 		return 0;
118418de8d7fSPeter Avalos 
118518de8d7fSPeter Avalos 	case oUserKnownHostsFile:
11861c188a7fSPeter Avalos 		cpptr = (char **)&options->user_hostfiles;
11871c188a7fSPeter Avalos 		uintptr = &options->num_user_hostfiles;
11881c188a7fSPeter Avalos 		max_entries = SSH_MAX_HOSTS_FILES;
11891c188a7fSPeter Avalos 		goto parse_char_array;
119018de8d7fSPeter Avalos 
1191*0cbfa66cSDaniel Fojt 	case oHostname:
119218de8d7fSPeter Avalos 		charptr = &options->hostname;
119318de8d7fSPeter Avalos 		goto parse_string;
119418de8d7fSPeter Avalos 
119518de8d7fSPeter Avalos 	case oHostKeyAlias:
119618de8d7fSPeter Avalos 		charptr = &options->host_key_alias;
119718de8d7fSPeter Avalos 		goto parse_string;
119818de8d7fSPeter Avalos 
119918de8d7fSPeter Avalos 	case oPreferredAuthentications:
120018de8d7fSPeter Avalos 		charptr = &options->preferred_authentications;
120118de8d7fSPeter Avalos 		goto parse_string;
120218de8d7fSPeter Avalos 
120318de8d7fSPeter Avalos 	case oBindAddress:
120418de8d7fSPeter Avalos 		charptr = &options->bind_address;
120518de8d7fSPeter Avalos 		goto parse_string;
120618de8d7fSPeter Avalos 
1207664f4763Szrj 	case oBindInterface:
1208664f4763Szrj 		charptr = &options->bind_interface;
1209664f4763Szrj 		goto parse_string;
1210664f4763Szrj 
1211856ea928SPeter Avalos 	case oPKCS11Provider:
1212856ea928SPeter Avalos 		charptr = &options->pkcs11_provider;
121318de8d7fSPeter Avalos 		goto parse_string;
121418de8d7fSPeter Avalos 
1215*0cbfa66cSDaniel Fojt 	case oSecurityKeyProvider:
1216*0cbfa66cSDaniel Fojt 		charptr = &options->sk_provider;
1217*0cbfa66cSDaniel Fojt 		goto parse_string;
1218*0cbfa66cSDaniel Fojt 
121918de8d7fSPeter Avalos 	case oProxyCommand:
122018de8d7fSPeter Avalos 		charptr = &options->proxy_command;
1221e9778795SPeter Avalos 		/* Ignore ProxyCommand if ProxyJump already specified */
1222e9778795SPeter Avalos 		if (options->jump_host != NULL)
1223e9778795SPeter Avalos 			charptr = &options->jump_host; /* Skip below */
122418de8d7fSPeter Avalos parse_command:
122518de8d7fSPeter Avalos 		if (s == NULL)
122618de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
122718de8d7fSPeter Avalos 		len = strspn(s, WHITESPACE "=");
122818de8d7fSPeter Avalos 		if (*activep && *charptr == NULL)
122918de8d7fSPeter Avalos 			*charptr = xstrdup(s + len);
123018de8d7fSPeter Avalos 		return 0;
123118de8d7fSPeter Avalos 
1232e9778795SPeter Avalos 	case oProxyJump:
1233e9778795SPeter Avalos 		if (s == NULL) {
1234e9778795SPeter Avalos 			fatal("%.200s line %d: Missing argument.",
1235e9778795SPeter Avalos 			    filename, linenum);
1236e9778795SPeter Avalos 		}
1237e9778795SPeter Avalos 		len = strspn(s, WHITESPACE "=");
1238e9778795SPeter Avalos 		if (parse_jump(s + len, options, *activep) == -1) {
1239e9778795SPeter Avalos 			fatal("%.200s line %d: Invalid ProxyJump \"%s\"",
1240e9778795SPeter Avalos 			    filename, linenum, s + len);
1241e9778795SPeter Avalos 		}
1242e9778795SPeter Avalos 		return 0;
1243e9778795SPeter Avalos 
124418de8d7fSPeter Avalos 	case oPort:
124518de8d7fSPeter Avalos 		arg = strdelim(&s);
124618de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
1247664f4763Szrj 			fatal("%.200s line %d: Missing argument.",
1248664f4763Szrj 			    filename, linenum);
1249664f4763Szrj 		value = a2port(arg);
1250664f4763Szrj 		if (value <= 0)
1251664f4763Szrj 			fatal("%.200s line %d: Bad port '%s'.",
1252664f4763Szrj 			    filename, linenum, arg);
1253664f4763Szrj 		if (*activep && options->port == -1)
1254664f4763Szrj 			options->port = value;
125518de8d7fSPeter Avalos 		break;
125618de8d7fSPeter Avalos 
125718de8d7fSPeter Avalos 	case oConnectionAttempts:
125818de8d7fSPeter Avalos 		intptr = &options->connection_attempts;
1259664f4763Szrj parse_int:
1260664f4763Szrj 		arg = strdelim(&s);
1261664f4763Szrj 		if ((errstr = atoi_err(arg, &value)) != NULL)
1262664f4763Szrj 			fatal("%s line %d: integer value %s.",
1263664f4763Szrj 			    filename, linenum, errstr);
1264664f4763Szrj 		if (*activep && *intptr == -1)
1265664f4763Szrj 			*intptr = value;
1266664f4763Szrj 		break;
126718de8d7fSPeter Avalos 
126818de8d7fSPeter Avalos 	case oCiphers:
126918de8d7fSPeter Avalos 		arg = strdelim(&s);
127018de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
127118de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1272*0cbfa66cSDaniel Fojt 		if (*arg != '-' &&
1273*0cbfa66cSDaniel Fojt 		    !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
127418de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
127518de8d7fSPeter Avalos 			    filename, linenum, arg ? arg : "<NONE>");
127618de8d7fSPeter Avalos 		if (*activep && options->ciphers == NULL)
127718de8d7fSPeter Avalos 			options->ciphers = xstrdup(arg);
127818de8d7fSPeter Avalos 		break;
127918de8d7fSPeter Avalos 
128018de8d7fSPeter Avalos 	case oMacs:
128118de8d7fSPeter Avalos 		arg = strdelim(&s);
128218de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
128318de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1284*0cbfa66cSDaniel Fojt 		if (*arg != '-' &&
1285*0cbfa66cSDaniel Fojt 		    !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
1286*0cbfa66cSDaniel Fojt 			fatal("%.200s line %d: Bad SSH2 MAC spec '%s'.",
128718de8d7fSPeter Avalos 			    filename, linenum, arg ? arg : "<NONE>");
128818de8d7fSPeter Avalos 		if (*activep && options->macs == NULL)
128918de8d7fSPeter Avalos 			options->macs = xstrdup(arg);
129018de8d7fSPeter Avalos 		break;
129118de8d7fSPeter Avalos 
12929f304aafSPeter Avalos 	case oKexAlgorithms:
12939f304aafSPeter Avalos 		arg = strdelim(&s);
12949f304aafSPeter Avalos 		if (!arg || *arg == '\0')
12959f304aafSPeter Avalos 			fatal("%.200s line %d: Missing argument.",
12969f304aafSPeter Avalos 			    filename, linenum);
1297ce74bacaSMatthew Dillon 		if (*arg != '-' &&
1298*0cbfa66cSDaniel Fojt 		    !kex_names_valid(*arg == '+' || *arg == '^' ?
1299*0cbfa66cSDaniel Fojt 		    arg + 1 : arg))
13009f304aafSPeter Avalos 			fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
13019f304aafSPeter Avalos 			    filename, linenum, arg ? arg : "<NONE>");
13029f304aafSPeter Avalos 		if (*activep && options->kex_algorithms == NULL)
13039f304aafSPeter Avalos 			options->kex_algorithms = xstrdup(arg);
13049f304aafSPeter Avalos 		break;
13059f304aafSPeter Avalos 
130618de8d7fSPeter Avalos 	case oHostKeyAlgorithms:
1307e9778795SPeter Avalos 		charptr = &options->hostkeyalgorithms;
1308e9778795SPeter Avalos parse_keytypes:
130918de8d7fSPeter Avalos 		arg = strdelim(&s);
131018de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
1311e9778795SPeter Avalos 			fatal("%.200s line %d: Missing argument.",
1312e9778795SPeter Avalos 			    filename, linenum);
1313ce74bacaSMatthew Dillon 		if (*arg != '-' &&
1314*0cbfa66cSDaniel Fojt 		    !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
1315*0cbfa66cSDaniel Fojt 		    arg + 1 : arg, 1))
1316e9778795SPeter Avalos 			fatal("%s line %d: Bad key types '%s'.",
131718de8d7fSPeter Avalos 				filename, linenum, arg ? arg : "<NONE>");
1318e9778795SPeter Avalos 		if (*activep && *charptr == NULL)
1319e9778795SPeter Avalos 			*charptr = xstrdup(arg);
132018de8d7fSPeter Avalos 		break;
132118de8d7fSPeter Avalos 
1322664f4763Szrj 	case oCASignatureAlgorithms:
1323664f4763Szrj 		charptr = &options->ca_sign_algorithms;
1324664f4763Szrj 		goto parse_keytypes;
1325664f4763Szrj 
132618de8d7fSPeter Avalos 	case oLogLevel:
132718de8d7fSPeter Avalos 		log_level_ptr = &options->log_level;
132818de8d7fSPeter Avalos 		arg = strdelim(&s);
132918de8d7fSPeter Avalos 		value = log_level_number(arg);
133018de8d7fSPeter Avalos 		if (value == SYSLOG_LEVEL_NOT_SET)
133118de8d7fSPeter Avalos 			fatal("%.200s line %d: unsupported log level '%s'",
133218de8d7fSPeter Avalos 			    filename, linenum, arg ? arg : "<NONE>");
133318de8d7fSPeter Avalos 		if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
133418de8d7fSPeter Avalos 			*log_level_ptr = (LogLevel) value;
133518de8d7fSPeter Avalos 		break;
133618de8d7fSPeter Avalos 
1337ce74bacaSMatthew Dillon 	case oLogFacility:
1338ce74bacaSMatthew Dillon 		log_facility_ptr = &options->log_facility;
1339ce74bacaSMatthew Dillon 		arg = strdelim(&s);
1340ce74bacaSMatthew Dillon 		value = log_facility_number(arg);
1341ce74bacaSMatthew Dillon 		if (value == SYSLOG_FACILITY_NOT_SET)
1342ce74bacaSMatthew Dillon 			fatal("%.200s line %d: unsupported log facility '%s'",
1343ce74bacaSMatthew Dillon 			    filename, linenum, arg ? arg : "<NONE>");
1344ce74bacaSMatthew Dillon 		if (*log_facility_ptr == -1)
1345ce74bacaSMatthew Dillon 			*log_facility_ptr = (SyslogFacility) value;
1346ce74bacaSMatthew Dillon 		break;
1347ce74bacaSMatthew Dillon 
134818de8d7fSPeter Avalos 	case oLocalForward:
134918de8d7fSPeter Avalos 	case oRemoteForward:
1350cb5eb4f1SPeter Avalos 	case oDynamicForward:
135118de8d7fSPeter Avalos 		arg = strdelim(&s);
135218de8d7fSPeter Avalos 		if (arg == NULL || *arg == '\0')
135318de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing port argument.",
135418de8d7fSPeter Avalos 			    filename, linenum);
1355cb5eb4f1SPeter Avalos 
1356ce74bacaSMatthew Dillon 		remotefwd = (opcode == oRemoteForward);
1357ce74bacaSMatthew Dillon 		dynamicfwd = (opcode == oDynamicForward);
1358ce74bacaSMatthew Dillon 
1359ce74bacaSMatthew Dillon 		if (!dynamicfwd) {
136018de8d7fSPeter Avalos 			arg2 = strdelim(&s);
1361ce74bacaSMatthew Dillon 			if (arg2 == NULL || *arg2 == '\0') {
1362ce74bacaSMatthew Dillon 				if (remotefwd)
1363ce74bacaSMatthew Dillon 					dynamicfwd = 1;
1364ce74bacaSMatthew Dillon 				else
1365ce74bacaSMatthew Dillon 					fatal("%.200s line %d: Missing target "
1366ce74bacaSMatthew Dillon 					    "argument.", filename, linenum);
1367ce74bacaSMatthew Dillon 			} else {
136818de8d7fSPeter Avalos 				/* construct a string for parse_forward */
1369ce74bacaSMatthew Dillon 				snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg,
1370ce74bacaSMatthew Dillon 				    arg2);
1371cb5eb4f1SPeter Avalos 			}
1372ce74bacaSMatthew Dillon 		}
1373ce74bacaSMatthew Dillon 		if (dynamicfwd)
1374ce74bacaSMatthew Dillon 			strlcpy(fwdarg, arg, sizeof(fwdarg));
137518de8d7fSPeter Avalos 
1376ce74bacaSMatthew Dillon 		if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0)
137718de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad forwarding specification.",
137818de8d7fSPeter Avalos 			    filename, linenum);
137918de8d7fSPeter Avalos 
138018de8d7fSPeter Avalos 		if (*activep) {
1381ce74bacaSMatthew Dillon 			if (remotefwd) {
138218de8d7fSPeter Avalos 				add_remote_forward(options, &fwd);
1383ce74bacaSMatthew Dillon 			} else {
1384ce74bacaSMatthew Dillon 				add_local_forward(options, &fwd);
1385ce74bacaSMatthew Dillon 			}
138618de8d7fSPeter Avalos 		}
138718de8d7fSPeter Avalos 		break;
138818de8d7fSPeter Avalos 
138918de8d7fSPeter Avalos 	case oClearAllForwardings:
139018de8d7fSPeter Avalos 		intptr = &options->clear_forwardings;
139118de8d7fSPeter Avalos 		goto parse_flag;
139218de8d7fSPeter Avalos 
139318de8d7fSPeter Avalos 	case oHost:
139436e94dc5SPeter Avalos 		if (cmdline)
139536e94dc5SPeter Avalos 			fatal("Host directive not supported as a command-line "
139636e94dc5SPeter Avalos 			    "option");
139718de8d7fSPeter Avalos 		*activep = 0;
13981c188a7fSPeter Avalos 		arg2 = NULL;
13991c188a7fSPeter Avalos 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1400e9778795SPeter Avalos 			if ((flags & SSHCONF_NEVERMATCH) != 0)
1401e9778795SPeter Avalos 				break;
14021c188a7fSPeter Avalos 			negated = *arg == '!';
14031c188a7fSPeter Avalos 			if (negated)
14041c188a7fSPeter Avalos 				arg++;
140518de8d7fSPeter Avalos 			if (match_pattern(host, arg)) {
14061c188a7fSPeter Avalos 				if (negated) {
14071c188a7fSPeter Avalos 					debug("%.200s line %d: Skipping Host "
14081c188a7fSPeter Avalos 					    "block because of negated match "
14091c188a7fSPeter Avalos 					    "for %.100s", filename, linenum,
14101c188a7fSPeter Avalos 					    arg);
14111c188a7fSPeter Avalos 					*activep = 0;
141218de8d7fSPeter Avalos 					break;
141318de8d7fSPeter Avalos 				}
14141c188a7fSPeter Avalos 				if (!*activep)
14151c188a7fSPeter Avalos 					arg2 = arg; /* logged below */
14161c188a7fSPeter Avalos 				*activep = 1;
14171c188a7fSPeter Avalos 			}
14181c188a7fSPeter Avalos 		}
14191c188a7fSPeter Avalos 		if (*activep)
14201c188a7fSPeter Avalos 			debug("%.200s line %d: Applying options for %.100s",
14211c188a7fSPeter Avalos 			    filename, linenum, arg2);
142218de8d7fSPeter Avalos 		/* Avoid garbage check below, as strdelim is done. */
142318de8d7fSPeter Avalos 		return 0;
142418de8d7fSPeter Avalos 
142536e94dc5SPeter Avalos 	case oMatch:
142636e94dc5SPeter Avalos 		if (cmdline)
142736e94dc5SPeter Avalos 			fatal("Host directive not supported as a command-line "
142836e94dc5SPeter Avalos 			    "option");
1429e9778795SPeter Avalos 		value = match_cfg_line(options, &s, pw, host, original_host,
1430664f4763Szrj 		    flags & SSHCONF_FINAL, want_final_pass,
1431664f4763Szrj 		    filename, linenum);
143236e94dc5SPeter Avalos 		if (value < 0)
143336e94dc5SPeter Avalos 			fatal("%.200s line %d: Bad Match condition", filename,
143436e94dc5SPeter Avalos 			    linenum);
1435e9778795SPeter Avalos 		*activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
143636e94dc5SPeter Avalos 		break;
143736e94dc5SPeter Avalos 
143818de8d7fSPeter Avalos 	case oEscapeChar:
143918de8d7fSPeter Avalos 		intptr = &options->escape_char;
144018de8d7fSPeter Avalos 		arg = strdelim(&s);
144118de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
144218de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1443e9778795SPeter Avalos 		if (strcmp(arg, "none") == 0)
1444e9778795SPeter Avalos 			value = SSH_ESCAPECHAR_NONE;
1445e9778795SPeter Avalos 		else if (arg[1] == '\0')
1446e9778795SPeter Avalos 			value = (u_char) arg[0];
1447e9778795SPeter Avalos 		else if (arg[0] == '^' && arg[2] == 0 &&
144818de8d7fSPeter Avalos 		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
144918de8d7fSPeter Avalos 			value = (u_char) arg[1] & 31;
145018de8d7fSPeter Avalos 		else {
145118de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad escape character.",
145218de8d7fSPeter Avalos 			    filename, linenum);
145318de8d7fSPeter Avalos 			/* NOTREACHED */
145418de8d7fSPeter Avalos 			value = 0;	/* Avoid compiler warning. */
145518de8d7fSPeter Avalos 		}
145618de8d7fSPeter Avalos 		if (*activep && *intptr == -1)
145718de8d7fSPeter Avalos 			*intptr = value;
145818de8d7fSPeter Avalos 		break;
145918de8d7fSPeter Avalos 
146018de8d7fSPeter Avalos 	case oAddressFamily:
146118de8d7fSPeter Avalos 		intptr = &options->address_family;
146236e94dc5SPeter Avalos 		multistate_ptr = multistate_addressfamily;
146336e94dc5SPeter Avalos 		goto parse_multistate;
146418de8d7fSPeter Avalos 
146518de8d7fSPeter Avalos 	case oEnableSSHKeysign:
146618de8d7fSPeter Avalos 		intptr = &options->enable_ssh_keysign;
146718de8d7fSPeter Avalos 		goto parse_flag;
146818de8d7fSPeter Avalos 
146918de8d7fSPeter Avalos 	case oIdentitiesOnly:
147018de8d7fSPeter Avalos 		intptr = &options->identities_only;
147118de8d7fSPeter Avalos 		goto parse_flag;
147218de8d7fSPeter Avalos 
147318de8d7fSPeter Avalos 	case oServerAliveInterval:
147418de8d7fSPeter Avalos 		intptr = &options->server_alive_interval;
147518de8d7fSPeter Avalos 		goto parse_time;
147618de8d7fSPeter Avalos 
147718de8d7fSPeter Avalos 	case oServerAliveCountMax:
147818de8d7fSPeter Avalos 		intptr = &options->server_alive_count_max;
147918de8d7fSPeter Avalos 		goto parse_int;
148018de8d7fSPeter Avalos 
148118de8d7fSPeter Avalos 	case oSendEnv:
148218de8d7fSPeter Avalos 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
148318de8d7fSPeter Avalos 			if (strchr(arg, '=') != NULL)
148418de8d7fSPeter Avalos 				fatal("%s line %d: Invalid environment name.",
148518de8d7fSPeter Avalos 				    filename, linenum);
148618de8d7fSPeter Avalos 			if (!*activep)
148718de8d7fSPeter Avalos 				continue;
1488664f4763Szrj 			if (*arg == '-') {
1489664f4763Szrj 				/* Removing an env var */
1490664f4763Szrj 				rm_env(options, arg, filename, linenum);
1491664f4763Szrj 				continue;
1492664f4763Szrj 			} else {
1493664f4763Szrj 				/* Adding an env var */
1494664f4763Szrj 				if (options->num_send_env >= INT_MAX)
149518de8d7fSPeter Avalos 					fatal("%s line %d: too many send env.",
149618de8d7fSPeter Avalos 					    filename, linenum);
1497664f4763Szrj 				options->send_env = xrecallocarray(
1498664f4763Szrj 				    options->send_env, options->num_send_env,
1499664f4763Szrj 				    options->num_send_env + 1,
1500664f4763Szrj 				    sizeof(*options->send_env));
150118de8d7fSPeter Avalos 				options->send_env[options->num_send_env++] =
150218de8d7fSPeter Avalos 				    xstrdup(arg);
150318de8d7fSPeter Avalos 			}
1504664f4763Szrj 		}
1505664f4763Szrj 		break;
1506664f4763Szrj 
1507664f4763Szrj 	case oSetEnv:
1508664f4763Szrj 		value = options->num_setenv;
1509664f4763Szrj 		while ((arg = strdelimw(&s)) != NULL && *arg != '\0') {
1510664f4763Szrj 			if (strchr(arg, '=') == NULL)
1511664f4763Szrj 				fatal("%s line %d: Invalid SetEnv.",
1512664f4763Szrj 				    filename, linenum);
1513664f4763Szrj 			if (!*activep || value != 0)
1514664f4763Szrj 				continue;
1515664f4763Szrj 			/* Adding a setenv var */
1516664f4763Szrj 			if (options->num_setenv >= INT_MAX)
1517664f4763Szrj 				fatal("%s line %d: too many SetEnv.",
1518664f4763Szrj 				    filename, linenum);
1519664f4763Szrj 			options->setenv = xrecallocarray(
1520664f4763Szrj 			    options->setenv, options->num_setenv,
1521664f4763Szrj 			    options->num_setenv + 1, sizeof(*options->setenv));
1522664f4763Szrj 			options->setenv[options->num_setenv++] = xstrdup(arg);
1523664f4763Szrj 		}
152418de8d7fSPeter Avalos 		break;
152518de8d7fSPeter Avalos 
152618de8d7fSPeter Avalos 	case oControlPath:
152718de8d7fSPeter Avalos 		charptr = &options->control_path;
152818de8d7fSPeter Avalos 		goto parse_string;
152918de8d7fSPeter Avalos 
153018de8d7fSPeter Avalos 	case oControlMaster:
153118de8d7fSPeter Avalos 		intptr = &options->control_master;
153236e94dc5SPeter Avalos 		multistate_ptr = multistate_controlmaster;
153336e94dc5SPeter Avalos 		goto parse_multistate;
153418de8d7fSPeter Avalos 
1535856ea928SPeter Avalos 	case oControlPersist:
1536856ea928SPeter Avalos 		/* no/false/yes/true, or a time spec */
1537856ea928SPeter Avalos 		intptr = &options->control_persist;
1538856ea928SPeter Avalos 		arg = strdelim(&s);
1539856ea928SPeter Avalos 		if (!arg || *arg == '\0')
1540856ea928SPeter Avalos 			fatal("%.200s line %d: Missing ControlPersist"
1541856ea928SPeter Avalos 			    " argument.", filename, linenum);
1542856ea928SPeter Avalos 		value = 0;
1543856ea928SPeter Avalos 		value2 = 0;	/* timeout */
1544856ea928SPeter Avalos 		if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1545856ea928SPeter Avalos 			value = 0;
1546856ea928SPeter Avalos 		else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1547856ea928SPeter Avalos 			value = 1;
1548856ea928SPeter Avalos 		else if ((value2 = convtime(arg)) >= 0)
1549856ea928SPeter Avalos 			value = 1;
1550856ea928SPeter Avalos 		else
1551856ea928SPeter Avalos 			fatal("%.200s line %d: Bad ControlPersist argument.",
1552856ea928SPeter Avalos 			    filename, linenum);
1553856ea928SPeter Avalos 		if (*activep && *intptr == -1) {
1554856ea928SPeter Avalos 			*intptr = value;
1555856ea928SPeter Avalos 			options->control_persist_timeout = value2;
1556856ea928SPeter Avalos 		}
1557856ea928SPeter Avalos 		break;
1558856ea928SPeter Avalos 
155918de8d7fSPeter Avalos 	case oHashKnownHosts:
156018de8d7fSPeter Avalos 		intptr = &options->hash_known_hosts;
156118de8d7fSPeter Avalos 		goto parse_flag;
156218de8d7fSPeter Avalos 
156318de8d7fSPeter Avalos 	case oTunnel:
156418de8d7fSPeter Avalos 		intptr = &options->tun_open;
156536e94dc5SPeter Avalos 		multistate_ptr = multistate_tunnel;
156636e94dc5SPeter Avalos 		goto parse_multistate;
156718de8d7fSPeter Avalos 
156818de8d7fSPeter Avalos 	case oTunnelDevice:
156918de8d7fSPeter Avalos 		arg = strdelim(&s);
157018de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
157118de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
157218de8d7fSPeter Avalos 		value = a2tun(arg, &value2);
157318de8d7fSPeter Avalos 		if (value == SSH_TUNID_ERR)
157418de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad tun device.", filename, linenum);
157518de8d7fSPeter Avalos 		if (*activep) {
157618de8d7fSPeter Avalos 			options->tun_local = value;
157718de8d7fSPeter Avalos 			options->tun_remote = value2;
157818de8d7fSPeter Avalos 		}
157918de8d7fSPeter Avalos 		break;
158018de8d7fSPeter Avalos 
158118de8d7fSPeter Avalos 	case oLocalCommand:
158218de8d7fSPeter Avalos 		charptr = &options->local_command;
158318de8d7fSPeter Avalos 		goto parse_command;
158418de8d7fSPeter Avalos 
158518de8d7fSPeter Avalos 	case oPermitLocalCommand:
158618de8d7fSPeter Avalos 		intptr = &options->permit_local_command;
158718de8d7fSPeter Avalos 		goto parse_flag;
158818de8d7fSPeter Avalos 
1589ce74bacaSMatthew Dillon 	case oRemoteCommand:
1590ce74bacaSMatthew Dillon 		charptr = &options->remote_command;
1591ce74bacaSMatthew Dillon 		goto parse_command;
1592ce74bacaSMatthew Dillon 
159318de8d7fSPeter Avalos 	case oVisualHostKey:
159418de8d7fSPeter Avalos 		intptr = &options->visual_host_key;
159518de8d7fSPeter Avalos 		goto parse_flag;
159618de8d7fSPeter Avalos 
1597e9778795SPeter Avalos 	case oInclude:
1598e9778795SPeter Avalos 		if (cmdline)
1599e9778795SPeter Avalos 			fatal("Include directive not supported as a "
1600e9778795SPeter Avalos 			    "command-line option");
1601e9778795SPeter Avalos 		value = 0;
1602e9778795SPeter Avalos 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1603e9778795SPeter Avalos 			/*
1604e9778795SPeter Avalos 			 * Ensure all paths are anchored. User configuration
1605e9778795SPeter Avalos 			 * files may begin with '~/' but system configurations
1606e9778795SPeter Avalos 			 * must not. If the path is relative, then treat it
1607e9778795SPeter Avalos 			 * as living in ~/.ssh for user configurations or
1608e9778795SPeter Avalos 			 * /etc/ssh for system ones.
1609e9778795SPeter Avalos 			 */
1610e9778795SPeter Avalos 			if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0)
1611e9778795SPeter Avalos 				fatal("%.200s line %d: bad include path %s.",
1612e9778795SPeter Avalos 				    filename, linenum, arg);
1613664f4763Szrj 			if (!path_absolute(arg) && *arg != '~') {
1614e9778795SPeter Avalos 				xasprintf(&arg2, "%s/%s",
1615e9778795SPeter Avalos 				    (flags & SSHCONF_USERCONF) ?
1616e9778795SPeter Avalos 				    "~/" _PATH_SSH_USER_DIR : SSHDIR, arg);
1617e9778795SPeter Avalos 			} else
1618e9778795SPeter Avalos 				arg2 = xstrdup(arg);
1619e9778795SPeter Avalos 			memset(&gl, 0, sizeof(gl));
1620e9778795SPeter Avalos 			r = glob(arg2, GLOB_TILDE, NULL, &gl);
1621e9778795SPeter Avalos 			if (r == GLOB_NOMATCH) {
1622e9778795SPeter Avalos 				debug("%.200s line %d: include %s matched no "
1623e9778795SPeter Avalos 				    "files",filename, linenum, arg2);
1624ce74bacaSMatthew Dillon 				free(arg2);
1625e9778795SPeter Avalos 				continue;
1626*0cbfa66cSDaniel Fojt 			} else if (r != 0)
1627e9778795SPeter Avalos 				fatal("%.200s line %d: glob failed for %s.",
1628e9778795SPeter Avalos 				    filename, linenum, arg2);
1629e9778795SPeter Avalos 			free(arg2);
1630e9778795SPeter Avalos 			oactive = *activep;
1631*0cbfa66cSDaniel Fojt 			for (i = 0; i < gl.gl_pathc; i++) {
1632e9778795SPeter Avalos 				debug3("%.200s line %d: Including file %s "
1633e9778795SPeter Avalos 				    "depth %d%s", filename, linenum,
1634e9778795SPeter Avalos 				    gl.gl_pathv[i], depth,
1635e9778795SPeter Avalos 				    oactive ? "" : " (parse only)");
1636e9778795SPeter Avalos 				r = read_config_file_depth(gl.gl_pathv[i],
1637e9778795SPeter Avalos 				    pw, host, original_host, options,
1638e9778795SPeter Avalos 				    flags | SSHCONF_CHECKPERM |
1639e9778795SPeter Avalos 				    (oactive ? 0 : SSHCONF_NEVERMATCH),
1640664f4763Szrj 				    activep, want_final_pass, depth + 1);
1641ce74bacaSMatthew Dillon 				if (r != 1 && errno != ENOENT) {
1642ce74bacaSMatthew Dillon 					fatal("Can't open user config file "
1643ce74bacaSMatthew Dillon 					    "%.100s: %.100s", gl.gl_pathv[i],
1644ce74bacaSMatthew Dillon 					    strerror(errno));
1645ce74bacaSMatthew Dillon 				}
1646e9778795SPeter Avalos 				/*
1647e9778795SPeter Avalos 				 * don't let Match in includes clobber the
1648e9778795SPeter Avalos 				 * containing file's Match state.
1649e9778795SPeter Avalos 				 */
1650e9778795SPeter Avalos 				*activep = oactive;
1651e9778795SPeter Avalos 				if (r != 1)
1652e9778795SPeter Avalos 					value = -1;
1653e9778795SPeter Avalos 			}
1654e9778795SPeter Avalos 			globfree(&gl);
1655e9778795SPeter Avalos 		}
1656e9778795SPeter Avalos 		if (value != 0)
1657e9778795SPeter Avalos 			return value;
1658e9778795SPeter Avalos 		break;
1659e9778795SPeter Avalos 
16609f304aafSPeter Avalos 	case oIPQoS:
16619f304aafSPeter Avalos 		arg = strdelim(&s);
16629f304aafSPeter Avalos 		if ((value = parse_ipqos(arg)) == -1)
16639f304aafSPeter Avalos 			fatal("%s line %d: Bad IPQoS value: %s",
16649f304aafSPeter Avalos 			    filename, linenum, arg);
16659f304aafSPeter Avalos 		arg = strdelim(&s);
16669f304aafSPeter Avalos 		if (arg == NULL)
16679f304aafSPeter Avalos 			value2 = value;
16689f304aafSPeter Avalos 		else if ((value2 = parse_ipqos(arg)) == -1)
16699f304aafSPeter Avalos 			fatal("%s line %d: Bad IPQoS value: %s",
16709f304aafSPeter Avalos 			    filename, linenum, arg);
16719f304aafSPeter Avalos 		if (*activep) {
16729f304aafSPeter Avalos 			options->ip_qos_interactive = value;
16739f304aafSPeter Avalos 			options->ip_qos_bulk = value2;
16749f304aafSPeter Avalos 		}
16759f304aafSPeter Avalos 		break;
16769f304aafSPeter Avalos 
16771c188a7fSPeter Avalos 	case oRequestTTY:
167836e94dc5SPeter Avalos 		intptr = &options->request_tty;
167936e94dc5SPeter Avalos 		multistate_ptr = multistate_requesttty;
168036e94dc5SPeter Avalos 		goto parse_multistate;
168136e94dc5SPeter Avalos 
168236e94dc5SPeter Avalos 	case oIgnoreUnknown:
168336e94dc5SPeter Avalos 		charptr = &options->ignored_unknown;
168436e94dc5SPeter Avalos 		goto parse_string;
168536e94dc5SPeter Avalos 
168636e94dc5SPeter Avalos 	case oProxyUseFdpass:
168736e94dc5SPeter Avalos 		intptr = &options->proxy_use_fdpass;
168836e94dc5SPeter Avalos 		goto parse_flag;
168936e94dc5SPeter Avalos 
169036e94dc5SPeter Avalos 	case oCanonicalDomains:
169136e94dc5SPeter Avalos 		value = options->num_canonical_domains != 0;
169236e94dc5SPeter Avalos 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1693664f4763Szrj 			if (!valid_domain(arg, 1, &errstr)) {
1694664f4763Szrj 				fatal("%s line %d: %s", filename, linenum,
1695664f4763Szrj 				    errstr);
1696664f4763Szrj 			}
169736e94dc5SPeter Avalos 			if (!*activep || value)
169836e94dc5SPeter Avalos 				continue;
169936e94dc5SPeter Avalos 			if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
170036e94dc5SPeter Avalos 				fatal("%s line %d: too many hostname suffixes.",
170136e94dc5SPeter Avalos 				    filename, linenum);
170236e94dc5SPeter Avalos 			options->canonical_domains[
170336e94dc5SPeter Avalos 			    options->num_canonical_domains++] = xstrdup(arg);
170436e94dc5SPeter Avalos 		}
170536e94dc5SPeter Avalos 		break;
170636e94dc5SPeter Avalos 
170736e94dc5SPeter Avalos 	case oCanonicalizePermittedCNAMEs:
170836e94dc5SPeter Avalos 		value = options->num_permitted_cnames != 0;
170936e94dc5SPeter Avalos 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
171036e94dc5SPeter Avalos 			/* Either '*' for everything or 'list:list' */
171136e94dc5SPeter Avalos 			if (strcmp(arg, "*") == 0)
171236e94dc5SPeter Avalos 				arg2 = arg;
171336e94dc5SPeter Avalos 			else {
171436e94dc5SPeter Avalos 				lowercase(arg);
171536e94dc5SPeter Avalos 				if ((arg2 = strchr(arg, ':')) == NULL ||
171636e94dc5SPeter Avalos 				    arg2[1] == '\0') {
171736e94dc5SPeter Avalos 					fatal("%s line %d: "
171836e94dc5SPeter Avalos 					    "Invalid permitted CNAME \"%s\"",
171936e94dc5SPeter Avalos 					    filename, linenum, arg);
172036e94dc5SPeter Avalos 				}
172136e94dc5SPeter Avalos 				*arg2 = '\0';
172236e94dc5SPeter Avalos 				arg2++;
172336e94dc5SPeter Avalos 			}
172436e94dc5SPeter Avalos 			if (!*activep || value)
172536e94dc5SPeter Avalos 				continue;
172636e94dc5SPeter Avalos 			if (options->num_permitted_cnames >= MAX_CANON_DOMAINS)
172736e94dc5SPeter Avalos 				fatal("%s line %d: too many permitted CNAMEs.",
172836e94dc5SPeter Avalos 				    filename, linenum);
172936e94dc5SPeter Avalos 			cname = options->permitted_cnames +
173036e94dc5SPeter Avalos 			    options->num_permitted_cnames++;
173136e94dc5SPeter Avalos 			cname->source_list = xstrdup(arg);
173236e94dc5SPeter Avalos 			cname->target_list = xstrdup(arg2);
173336e94dc5SPeter Avalos 		}
173436e94dc5SPeter Avalos 		break;
173536e94dc5SPeter Avalos 
173636e94dc5SPeter Avalos 	case oCanonicalizeHostname:
173736e94dc5SPeter Avalos 		intptr = &options->canonicalize_hostname;
173836e94dc5SPeter Avalos 		multistate_ptr = multistate_canonicalizehostname;
173936e94dc5SPeter Avalos 		goto parse_multistate;
174036e94dc5SPeter Avalos 
174136e94dc5SPeter Avalos 	case oCanonicalizeMaxDots:
174236e94dc5SPeter Avalos 		intptr = &options->canonicalize_max_dots;
174336e94dc5SPeter Avalos 		goto parse_int;
174436e94dc5SPeter Avalos 
174536e94dc5SPeter Avalos 	case oCanonicalizeFallbackLocal:
174636e94dc5SPeter Avalos 		intptr = &options->canonicalize_fallback_local;
174736e94dc5SPeter Avalos 		goto parse_flag;
174836e94dc5SPeter Avalos 
174936e94dc5SPeter Avalos 	case oStreamLocalBindMask:
17501c188a7fSPeter Avalos 		arg = strdelim(&s);
17511c188a7fSPeter Avalos 		if (!arg || *arg == '\0')
175236e94dc5SPeter Avalos 			fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum);
175336e94dc5SPeter Avalos 		/* Parse mode in octal format */
175436e94dc5SPeter Avalos 		value = strtol(arg, &endofnumber, 8);
175536e94dc5SPeter Avalos 		if (arg == endofnumber || value < 0 || value > 0777)
175636e94dc5SPeter Avalos 			fatal("%.200s line %d: Bad mask.", filename, linenum);
175736e94dc5SPeter Avalos 		options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
17581c188a7fSPeter Avalos 		break;
17591c188a7fSPeter Avalos 
176036e94dc5SPeter Avalos 	case oStreamLocalBindUnlink:
176136e94dc5SPeter Avalos 		intptr = &options->fwd_opts.streamlocal_bind_unlink;
176236e94dc5SPeter Avalos 		goto parse_flag;
176336e94dc5SPeter Avalos 
1764e9778795SPeter Avalos 	case oRevokedHostKeys:
1765e9778795SPeter Avalos 		charptr = &options->revoked_host_keys;
1766e9778795SPeter Avalos 		goto parse_string;
1767e9778795SPeter Avalos 
1768e9778795SPeter Avalos 	case oFingerprintHash:
1769e9778795SPeter Avalos 		intptr = &options->fingerprint_hash;
1770e9778795SPeter Avalos 		arg = strdelim(&s);
1771e9778795SPeter Avalos 		if (!arg || *arg == '\0')
1772e9778795SPeter Avalos 			fatal("%.200s line %d: Missing argument.",
1773e9778795SPeter Avalos 			    filename, linenum);
1774e9778795SPeter Avalos 		if ((value = ssh_digest_alg_by_name(arg)) == -1)
1775e9778795SPeter Avalos 			fatal("%.200s line %d: Invalid hash algorithm \"%s\".",
1776e9778795SPeter Avalos 			    filename, linenum, arg);
1777e9778795SPeter Avalos 		if (*activep && *intptr == -1)
1778e9778795SPeter Avalos 			*intptr = value;
1779e9778795SPeter Avalos 		break;
1780e9778795SPeter Avalos 
1781e9778795SPeter Avalos 	case oUpdateHostkeys:
1782e9778795SPeter Avalos 		intptr = &options->update_hostkeys;
1783e9778795SPeter Avalos 		multistate_ptr = multistate_yesnoask;
1784e9778795SPeter Avalos 		goto parse_multistate;
1785e9778795SPeter Avalos 
1786e9778795SPeter Avalos 	case oHostbasedKeyTypes:
1787e9778795SPeter Avalos 		charptr = &options->hostbased_key_types;
1788e9778795SPeter Avalos 		goto parse_keytypes;
1789e9778795SPeter Avalos 
1790e9778795SPeter Avalos 	case oPubkeyAcceptedKeyTypes:
1791e9778795SPeter Avalos 		charptr = &options->pubkey_key_types;
1792e9778795SPeter Avalos 		goto parse_keytypes;
1793e9778795SPeter Avalos 
1794e9778795SPeter Avalos 	case oAddKeysToAgent:
1795e9778795SPeter Avalos 		intptr = &options->add_keys_to_agent;
1796e9778795SPeter Avalos 		multistate_ptr = multistate_yesnoaskconfirm;
1797e9778795SPeter Avalos 		goto parse_multistate;
1798e9778795SPeter Avalos 
1799e9778795SPeter Avalos 	case oIdentityAgent:
1800e9778795SPeter Avalos 		charptr = &options->identity_agent;
1801664f4763Szrj 		arg = strdelim(&s);
1802664f4763Szrj 		if (!arg || *arg == '\0')
1803664f4763Szrj 			fatal("%.200s line %d: Missing argument.",
1804664f4763Szrj 			    filename, linenum);
1805*0cbfa66cSDaniel Fojt   parse_agent_path:
1806664f4763Szrj 		/* Extra validation if the string represents an env var. */
1807664f4763Szrj 		if (arg[0] == '$' && !valid_env_name(arg + 1)) {
1808664f4763Szrj 			fatal("%.200s line %d: Invalid environment name %s.",
1809664f4763Szrj 			    filename, linenum, arg);
1810664f4763Szrj 		}
1811664f4763Szrj 		if (*activep && *charptr == NULL)
1812664f4763Szrj 			*charptr = xstrdup(arg);
1813664f4763Szrj 		break;
1814e9778795SPeter Avalos 
181518de8d7fSPeter Avalos 	case oDeprecated:
181618de8d7fSPeter Avalos 		debug("%s line %d: Deprecated option \"%s\"",
181718de8d7fSPeter Avalos 		    filename, linenum, keyword);
181818de8d7fSPeter Avalos 		return 0;
181918de8d7fSPeter Avalos 
182018de8d7fSPeter Avalos 	case oUnsupported:
182118de8d7fSPeter Avalos 		error("%s line %d: Unsupported option \"%s\"",
182218de8d7fSPeter Avalos 		    filename, linenum, keyword);
182318de8d7fSPeter Avalos 		return 0;
182418de8d7fSPeter Avalos 
182518de8d7fSPeter Avalos 	default:
1826e9778795SPeter Avalos 		fatal("%s: Unimplemented opcode %d", __func__, opcode);
182718de8d7fSPeter Avalos 	}
182818de8d7fSPeter Avalos 
182918de8d7fSPeter Avalos 	/* Check that there is no garbage at end of line. */
183018de8d7fSPeter Avalos 	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
183118de8d7fSPeter Avalos 		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
183218de8d7fSPeter Avalos 		    filename, linenum, arg);
183318de8d7fSPeter Avalos 	}
183418de8d7fSPeter Avalos 	return 0;
183518de8d7fSPeter Avalos }
183618de8d7fSPeter Avalos 
183718de8d7fSPeter Avalos /*
183818de8d7fSPeter Avalos  * Reads the config file and modifies the options accordingly.  Options
183918de8d7fSPeter Avalos  * should already be initialized before this call.  This never returns if
184018de8d7fSPeter Avalos  * there is an error.  If the file does not exist, this returns 0.
184118de8d7fSPeter Avalos  */
184218de8d7fSPeter Avalos int
184336e94dc5SPeter Avalos read_config_file(const char *filename, struct passwd *pw, const char *host,
1844664f4763Szrj     const char *original_host, Options *options, int flags,
1845664f4763Szrj     int *want_final_pass)
1846e9778795SPeter Avalos {
1847e9778795SPeter Avalos 	int active = 1;
1848e9778795SPeter Avalos 
1849e9778795SPeter Avalos 	return read_config_file_depth(filename, pw, host, original_host,
1850664f4763Szrj 	    options, flags, &active, want_final_pass, 0);
1851e9778795SPeter Avalos }
1852e9778795SPeter Avalos 
1853e9778795SPeter Avalos #define READCONF_MAX_DEPTH	16
1854e9778795SPeter Avalos static int
1855e9778795SPeter Avalos read_config_file_depth(const char *filename, struct passwd *pw,
1856e9778795SPeter Avalos     const char *host, const char *original_host, Options *options,
1857664f4763Szrj     int flags, int *activep, int *want_final_pass, int depth)
185818de8d7fSPeter Avalos {
185918de8d7fSPeter Avalos 	FILE *f;
1860664f4763Szrj 	char *line = NULL;
1861664f4763Szrj 	size_t linesize = 0;
1862e9778795SPeter Avalos 	int linenum;
186318de8d7fSPeter Avalos 	int bad_options = 0;
186418de8d7fSPeter Avalos 
1865e9778795SPeter Avalos 	if (depth < 0 || depth > READCONF_MAX_DEPTH)
1866e9778795SPeter Avalos 		fatal("Too many recursive configuration includes");
1867e9778795SPeter Avalos 
186818de8d7fSPeter Avalos 	if ((f = fopen(filename, "r")) == NULL)
186918de8d7fSPeter Avalos 		return 0;
187018de8d7fSPeter Avalos 
187136e94dc5SPeter Avalos 	if (flags & SSHCONF_CHECKPERM) {
187218de8d7fSPeter Avalos 		struct stat sb;
187318de8d7fSPeter Avalos 
187418de8d7fSPeter Avalos 		if (fstat(fileno(f), &sb) == -1)
187518de8d7fSPeter Avalos 			fatal("fstat %s: %s", filename, strerror(errno));
187618de8d7fSPeter Avalos 		if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
187718de8d7fSPeter Avalos 		    (sb.st_mode & 022) != 0))
187818de8d7fSPeter Avalos 			fatal("Bad owner or permissions on %s", filename);
187918de8d7fSPeter Avalos 	}
188018de8d7fSPeter Avalos 
188118de8d7fSPeter Avalos 	debug("Reading configuration data %.200s", filename);
188218de8d7fSPeter Avalos 
188318de8d7fSPeter Avalos 	/*
188418de8d7fSPeter Avalos 	 * Mark that we are now processing the options.  This flag is turned
188518de8d7fSPeter Avalos 	 * on/off by Host specifications.
188618de8d7fSPeter Avalos 	 */
188718de8d7fSPeter Avalos 	linenum = 0;
1888664f4763Szrj 	while (getline(&line, &linesize, f) != -1) {
188918de8d7fSPeter Avalos 		/* Update line number counter. */
189018de8d7fSPeter Avalos 		linenum++;
1891e9778795SPeter Avalos 		if (process_config_line_depth(options, pw, host, original_host,
1892664f4763Szrj 		    line, filename, linenum, activep, flags, want_final_pass,
1893664f4763Szrj 		    depth) != 0)
189418de8d7fSPeter Avalos 			bad_options++;
189518de8d7fSPeter Avalos 	}
1896664f4763Szrj 	free(line);
189718de8d7fSPeter Avalos 	fclose(f);
189818de8d7fSPeter Avalos 	if (bad_options > 0)
189918de8d7fSPeter Avalos 		fatal("%s: terminating, %d bad configuration options",
190018de8d7fSPeter Avalos 		    filename, bad_options);
190118de8d7fSPeter Avalos 	return 1;
190218de8d7fSPeter Avalos }
190318de8d7fSPeter Avalos 
190436e94dc5SPeter Avalos /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
190536e94dc5SPeter Avalos int
190636e94dc5SPeter Avalos option_clear_or_none(const char *o)
190736e94dc5SPeter Avalos {
190836e94dc5SPeter Avalos 	return o == NULL || strcasecmp(o, "none") == 0;
190936e94dc5SPeter Avalos }
191036e94dc5SPeter Avalos 
191118de8d7fSPeter Avalos /*
191218de8d7fSPeter Avalos  * Initializes options to special values that indicate that they have not yet
191318de8d7fSPeter Avalos  * been set.  Read_config_file will only set options with this value. Options
191418de8d7fSPeter Avalos  * are processed in the following order: command line, user config file,
191518de8d7fSPeter Avalos  * system config file.  Last, fill_default_options is called.
191618de8d7fSPeter Avalos  */
191718de8d7fSPeter Avalos 
191818de8d7fSPeter Avalos void
191918de8d7fSPeter Avalos initialize_options(Options * options)
192018de8d7fSPeter Avalos {
192118de8d7fSPeter Avalos 	memset(options, 'X', sizeof(*options));
192218de8d7fSPeter Avalos 	options->forward_agent = -1;
1923*0cbfa66cSDaniel Fojt 	options->forward_agent_sock_path = NULL;
192418de8d7fSPeter Avalos 	options->forward_x11 = -1;
192518de8d7fSPeter Avalos 	options->forward_x11_trusted = -1;
1926856ea928SPeter Avalos 	options->forward_x11_timeout = -1;
1927e9778795SPeter Avalos 	options->stdio_forward_host = NULL;
1928e9778795SPeter Avalos 	options->stdio_forward_port = 0;
1929e9778795SPeter Avalos 	options->clear_forwardings = -1;
193018de8d7fSPeter Avalos 	options->exit_on_forward_failure = -1;
193118de8d7fSPeter Avalos 	options->xauth_location = NULL;
193236e94dc5SPeter Avalos 	options->fwd_opts.gateway_ports = -1;
193336e94dc5SPeter Avalos 	options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
193436e94dc5SPeter Avalos 	options->fwd_opts.streamlocal_bind_unlink = -1;
193518de8d7fSPeter Avalos 	options->pubkey_authentication = -1;
193618de8d7fSPeter Avalos 	options->challenge_response_authentication = -1;
193718de8d7fSPeter Avalos 	options->gss_authentication = -1;
193818de8d7fSPeter Avalos 	options->gss_deleg_creds = -1;
193918de8d7fSPeter Avalos 	options->password_authentication = -1;
194018de8d7fSPeter Avalos 	options->kbd_interactive_authentication = -1;
194118de8d7fSPeter Avalos 	options->kbd_interactive_devices = NULL;
194218de8d7fSPeter Avalos 	options->hostbased_authentication = -1;
194318de8d7fSPeter Avalos 	options->batch_mode = -1;
194418de8d7fSPeter Avalos 	options->check_host_ip = -1;
194518de8d7fSPeter Avalos 	options->strict_host_key_checking = -1;
194618de8d7fSPeter Avalos 	options->compression = -1;
194718de8d7fSPeter Avalos 	options->tcp_keep_alive = -1;
194818de8d7fSPeter Avalos 	options->port = -1;
194918de8d7fSPeter Avalos 	options->address_family = -1;
195018de8d7fSPeter Avalos 	options->connection_attempts = -1;
195118de8d7fSPeter Avalos 	options->connection_timeout = -1;
195218de8d7fSPeter Avalos 	options->number_of_password_prompts = -1;
195318de8d7fSPeter Avalos 	options->ciphers = NULL;
195418de8d7fSPeter Avalos 	options->macs = NULL;
19559f304aafSPeter Avalos 	options->kex_algorithms = NULL;
195618de8d7fSPeter Avalos 	options->hostkeyalgorithms = NULL;
1957664f4763Szrj 	options->ca_sign_algorithms = NULL;
195818de8d7fSPeter Avalos 	options->num_identity_files = 0;
1959e9778795SPeter Avalos 	options->num_certificate_files = 0;
196018de8d7fSPeter Avalos 	options->hostname = NULL;
196118de8d7fSPeter Avalos 	options->host_key_alias = NULL;
196218de8d7fSPeter Avalos 	options->proxy_command = NULL;
1963e9778795SPeter Avalos 	options->jump_user = NULL;
1964e9778795SPeter Avalos 	options->jump_host = NULL;
1965e9778795SPeter Avalos 	options->jump_port = -1;
1966e9778795SPeter Avalos 	options->jump_extra = NULL;
196718de8d7fSPeter Avalos 	options->user = NULL;
196818de8d7fSPeter Avalos 	options->escape_char = -1;
19691c188a7fSPeter Avalos 	options->num_system_hostfiles = 0;
19701c188a7fSPeter Avalos 	options->num_user_hostfiles = 0;
1971856ea928SPeter Avalos 	options->local_forwards = NULL;
197218de8d7fSPeter Avalos 	options->num_local_forwards = 0;
1973856ea928SPeter Avalos 	options->remote_forwards = NULL;
197418de8d7fSPeter Avalos 	options->num_remote_forwards = 0;
1975ce74bacaSMatthew Dillon 	options->log_facility = SYSLOG_FACILITY_NOT_SET;
197618de8d7fSPeter Avalos 	options->log_level = SYSLOG_LEVEL_NOT_SET;
197718de8d7fSPeter Avalos 	options->preferred_authentications = NULL;
197818de8d7fSPeter Avalos 	options->bind_address = NULL;
1979664f4763Szrj 	options->bind_interface = NULL;
1980856ea928SPeter Avalos 	options->pkcs11_provider = NULL;
1981*0cbfa66cSDaniel Fojt 	options->sk_provider = NULL;
198218de8d7fSPeter Avalos 	options->enable_ssh_keysign = - 1;
198318de8d7fSPeter Avalos 	options->no_host_authentication_for_localhost = - 1;
198418de8d7fSPeter Avalos 	options->identities_only = - 1;
198518de8d7fSPeter Avalos 	options->rekey_limit = - 1;
198636e94dc5SPeter Avalos 	options->rekey_interval = -1;
198718de8d7fSPeter Avalos 	options->verify_host_key_dns = -1;
198818de8d7fSPeter Avalos 	options->server_alive_interval = -1;
198918de8d7fSPeter Avalos 	options->server_alive_count_max = -1;
1990664f4763Szrj 	options->send_env = NULL;
199118de8d7fSPeter Avalos 	options->num_send_env = 0;
1992664f4763Szrj 	options->setenv = NULL;
1993664f4763Szrj 	options->num_setenv = 0;
199418de8d7fSPeter Avalos 	options->control_path = NULL;
199518de8d7fSPeter Avalos 	options->control_master = -1;
1996856ea928SPeter Avalos 	options->control_persist = -1;
1997856ea928SPeter Avalos 	options->control_persist_timeout = 0;
199818de8d7fSPeter Avalos 	options->hash_known_hosts = -1;
199918de8d7fSPeter Avalos 	options->tun_open = -1;
200018de8d7fSPeter Avalos 	options->tun_local = -1;
200118de8d7fSPeter Avalos 	options->tun_remote = -1;
200218de8d7fSPeter Avalos 	options->local_command = NULL;
200318de8d7fSPeter Avalos 	options->permit_local_command = -1;
2004ce74bacaSMatthew Dillon 	options->remote_command = NULL;
2005e9778795SPeter Avalos 	options->add_keys_to_agent = -1;
2006e9778795SPeter Avalos 	options->identity_agent = NULL;
200718de8d7fSPeter Avalos 	options->visual_host_key = -1;
20089f304aafSPeter Avalos 	options->ip_qos_interactive = -1;
20099f304aafSPeter Avalos 	options->ip_qos_bulk = -1;
20101c188a7fSPeter Avalos 	options->request_tty = -1;
201136e94dc5SPeter Avalos 	options->proxy_use_fdpass = -1;
201236e94dc5SPeter Avalos 	options->ignored_unknown = NULL;
201336e94dc5SPeter Avalos 	options->num_canonical_domains = 0;
201436e94dc5SPeter Avalos 	options->num_permitted_cnames = 0;
201536e94dc5SPeter Avalos 	options->canonicalize_max_dots = -1;
201636e94dc5SPeter Avalos 	options->canonicalize_fallback_local = -1;
201736e94dc5SPeter Avalos 	options->canonicalize_hostname = -1;
2018e9778795SPeter Avalos 	options->revoked_host_keys = NULL;
2019e9778795SPeter Avalos 	options->fingerprint_hash = -1;
2020e9778795SPeter Avalos 	options->update_hostkeys = -1;
2021e9778795SPeter Avalos 	options->hostbased_key_types = NULL;
2022e9778795SPeter Avalos 	options->pubkey_key_types = NULL;
202336e94dc5SPeter Avalos }
202436e94dc5SPeter Avalos 
202536e94dc5SPeter Avalos /*
202636e94dc5SPeter Avalos  * A petite version of fill_default_options() that just fills the options
202736e94dc5SPeter Avalos  * needed for hostname canonicalization to proceed.
202836e94dc5SPeter Avalos  */
202936e94dc5SPeter Avalos void
203036e94dc5SPeter Avalos fill_default_options_for_canonicalization(Options *options)
203136e94dc5SPeter Avalos {
203236e94dc5SPeter Avalos 	if (options->canonicalize_max_dots == -1)
203336e94dc5SPeter Avalos 		options->canonicalize_max_dots = 1;
203436e94dc5SPeter Avalos 	if (options->canonicalize_fallback_local == -1)
203536e94dc5SPeter Avalos 		options->canonicalize_fallback_local = 1;
203636e94dc5SPeter Avalos 	if (options->canonicalize_hostname == -1)
203736e94dc5SPeter Avalos 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
203818de8d7fSPeter Avalos }
203918de8d7fSPeter Avalos 
204018de8d7fSPeter Avalos /*
204118de8d7fSPeter Avalos  * Called after processing other sources of option data, this fills those
204218de8d7fSPeter Avalos  * options for which no value has been specified with their default values.
204318de8d7fSPeter Avalos  */
204418de8d7fSPeter Avalos void
204518de8d7fSPeter Avalos fill_default_options(Options * options)
204618de8d7fSPeter Avalos {
2047664f4763Szrj 	char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
2048*0cbfa66cSDaniel Fojt 	char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
2049664f4763Szrj 	int r;
2050664f4763Szrj 
205118de8d7fSPeter Avalos 	if (options->forward_agent == -1)
205218de8d7fSPeter Avalos 		options->forward_agent = 0;
205318de8d7fSPeter Avalos 	if (options->forward_x11 == -1)
205418de8d7fSPeter Avalos 		options->forward_x11 = 0;
205518de8d7fSPeter Avalos 	if (options->forward_x11_trusted == -1)
205618de8d7fSPeter Avalos 		options->forward_x11_trusted = 0;
2057856ea928SPeter Avalos 	if (options->forward_x11_timeout == -1)
2058856ea928SPeter Avalos 		options->forward_x11_timeout = 1200;
2059e9778795SPeter Avalos 	/*
2060e9778795SPeter Avalos 	 * stdio forwarding (-W) changes the default for these but we defer
2061e9778795SPeter Avalos 	 * setting the values so they can be overridden.
2062e9778795SPeter Avalos 	 */
206318de8d7fSPeter Avalos 	if (options->exit_on_forward_failure == -1)
2064e9778795SPeter Avalos 		options->exit_on_forward_failure =
2065e9778795SPeter Avalos 		    options->stdio_forward_host != NULL ? 1 : 0;
2066e9778795SPeter Avalos 	if (options->clear_forwardings == -1)
2067e9778795SPeter Avalos 		options->clear_forwardings =
2068e9778795SPeter Avalos 		    options->stdio_forward_host != NULL ? 1 : 0;
2069e9778795SPeter Avalos 	if (options->clear_forwardings == 1)
2070e9778795SPeter Avalos 		clear_forwardings(options);
2071e9778795SPeter Avalos 
207218de8d7fSPeter Avalos 	if (options->xauth_location == NULL)
207318de8d7fSPeter Avalos 		options->xauth_location = _PATH_XAUTH;
207436e94dc5SPeter Avalos 	if (options->fwd_opts.gateway_ports == -1)
207536e94dc5SPeter Avalos 		options->fwd_opts.gateway_ports = 0;
207636e94dc5SPeter Avalos 	if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
207736e94dc5SPeter Avalos 		options->fwd_opts.streamlocal_bind_mask = 0177;
207836e94dc5SPeter Avalos 	if (options->fwd_opts.streamlocal_bind_unlink == -1)
207936e94dc5SPeter Avalos 		options->fwd_opts.streamlocal_bind_unlink = 0;
208018de8d7fSPeter Avalos 	if (options->pubkey_authentication == -1)
208118de8d7fSPeter Avalos 		options->pubkey_authentication = 1;
208218de8d7fSPeter Avalos 	if (options->challenge_response_authentication == -1)
208318de8d7fSPeter Avalos 		options->challenge_response_authentication = 1;
208418de8d7fSPeter Avalos 	if (options->gss_authentication == -1)
208518de8d7fSPeter Avalos 		options->gss_authentication = 0;
208618de8d7fSPeter Avalos 	if (options->gss_deleg_creds == -1)
208718de8d7fSPeter Avalos 		options->gss_deleg_creds = 0;
208818de8d7fSPeter Avalos 	if (options->password_authentication == -1)
208918de8d7fSPeter Avalos 		options->password_authentication = 1;
209018de8d7fSPeter Avalos 	if (options->kbd_interactive_authentication == -1)
209118de8d7fSPeter Avalos 		options->kbd_interactive_authentication = 1;
209218de8d7fSPeter Avalos 	if (options->hostbased_authentication == -1)
209318de8d7fSPeter Avalos 		options->hostbased_authentication = 0;
209418de8d7fSPeter Avalos 	if (options->batch_mode == -1)
209518de8d7fSPeter Avalos 		options->batch_mode = 0;
209618de8d7fSPeter Avalos 	if (options->check_host_ip == -1)
209718de8d7fSPeter Avalos 		options->check_host_ip = 1;
209818de8d7fSPeter Avalos 	if (options->strict_host_key_checking == -1)
2099ce74bacaSMatthew Dillon 		options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK;
210018de8d7fSPeter Avalos 	if (options->compression == -1)
210118de8d7fSPeter Avalos 		options->compression = 0;
210218de8d7fSPeter Avalos 	if (options->tcp_keep_alive == -1)
210318de8d7fSPeter Avalos 		options->tcp_keep_alive = 1;
210418de8d7fSPeter Avalos 	if (options->port == -1)
210518de8d7fSPeter Avalos 		options->port = 0;	/* Filled in ssh_connect. */
210618de8d7fSPeter Avalos 	if (options->address_family == -1)
210718de8d7fSPeter Avalos 		options->address_family = AF_UNSPEC;
210818de8d7fSPeter Avalos 	if (options->connection_attempts == -1)
210918de8d7fSPeter Avalos 		options->connection_attempts = 1;
211018de8d7fSPeter Avalos 	if (options->number_of_password_prompts == -1)
211118de8d7fSPeter Avalos 		options->number_of_password_prompts = 3;
211218de8d7fSPeter Avalos 	/* options->hostkeyalgorithms, default set in myproposals.h */
2113e9778795SPeter Avalos 	if (options->add_keys_to_agent == -1)
2114e9778795SPeter Avalos 		options->add_keys_to_agent = 0;
211518de8d7fSPeter Avalos 	if (options->num_identity_files == 0) {
2116ce74bacaSMatthew Dillon 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0);
2117ce74bacaSMatthew Dillon 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0);
21189f304aafSPeter Avalos #ifdef OPENSSL_HAS_ECC
2119ce74bacaSMatthew Dillon 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
2120*0cbfa66cSDaniel Fojt 		add_identity_file(options, "~/",
2121*0cbfa66cSDaniel Fojt 		    _PATH_SSH_CLIENT_ID_ECDSA_SK, 0);
21229f304aafSPeter Avalos #endif
212336e94dc5SPeter Avalos 		add_identity_file(options, "~/",
212436e94dc5SPeter Avalos 		    _PATH_SSH_CLIENT_ID_ED25519, 0);
2125*0cbfa66cSDaniel Fojt 		add_identity_file(options, "~/",
2126*0cbfa66cSDaniel Fojt 		    _PATH_SSH_CLIENT_ID_ED25519_SK, 0);
2127664f4763Szrj 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0);
212818de8d7fSPeter Avalos 	}
212918de8d7fSPeter Avalos 	if (options->escape_char == -1)
213018de8d7fSPeter Avalos 		options->escape_char = '~';
21311c188a7fSPeter Avalos 	if (options->num_system_hostfiles == 0) {
21321c188a7fSPeter Avalos 		options->system_hostfiles[options->num_system_hostfiles++] =
21331c188a7fSPeter Avalos 		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
21341c188a7fSPeter Avalos 		options->system_hostfiles[options->num_system_hostfiles++] =
21351c188a7fSPeter Avalos 		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
21361c188a7fSPeter Avalos 	}
2137*0cbfa66cSDaniel Fojt 	if (options->update_hostkeys == -1)
2138*0cbfa66cSDaniel Fojt 			options->update_hostkeys = SSH_UPDATE_HOSTKEYS_NO;
21391c188a7fSPeter Avalos 	if (options->num_user_hostfiles == 0) {
21401c188a7fSPeter Avalos 		options->user_hostfiles[options->num_user_hostfiles++] =
21411c188a7fSPeter Avalos 		    xstrdup(_PATH_SSH_USER_HOSTFILE);
21421c188a7fSPeter Avalos 		options->user_hostfiles[options->num_user_hostfiles++] =
21431c188a7fSPeter Avalos 		    xstrdup(_PATH_SSH_USER_HOSTFILE2);
21441c188a7fSPeter Avalos 	}
214518de8d7fSPeter Avalos 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
214618de8d7fSPeter Avalos 		options->log_level = SYSLOG_LEVEL_INFO;
2147ce74bacaSMatthew Dillon 	if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
2148ce74bacaSMatthew Dillon 		options->log_facility = SYSLOG_FACILITY_USER;
214918de8d7fSPeter Avalos 	if (options->no_host_authentication_for_localhost == - 1)
215018de8d7fSPeter Avalos 		options->no_host_authentication_for_localhost = 0;
215118de8d7fSPeter Avalos 	if (options->identities_only == -1)
215218de8d7fSPeter Avalos 		options->identities_only = 0;
215318de8d7fSPeter Avalos 	if (options->enable_ssh_keysign == -1)
215418de8d7fSPeter Avalos 		options->enable_ssh_keysign = 0;
215518de8d7fSPeter Avalos 	if (options->rekey_limit == -1)
215618de8d7fSPeter Avalos 		options->rekey_limit = 0;
215736e94dc5SPeter Avalos 	if (options->rekey_interval == -1)
215836e94dc5SPeter Avalos 		options->rekey_interval = 0;
215918de8d7fSPeter Avalos 	if (options->verify_host_key_dns == -1)
216018de8d7fSPeter Avalos 		options->verify_host_key_dns = 0;
216118de8d7fSPeter Avalos 	if (options->server_alive_interval == -1)
216218de8d7fSPeter Avalos 		options->server_alive_interval = 0;
216318de8d7fSPeter Avalos 	if (options->server_alive_count_max == -1)
216418de8d7fSPeter Avalos 		options->server_alive_count_max = 3;
216518de8d7fSPeter Avalos 	if (options->control_master == -1)
216618de8d7fSPeter Avalos 		options->control_master = 0;
2167856ea928SPeter Avalos 	if (options->control_persist == -1) {
2168856ea928SPeter Avalos 		options->control_persist = 0;
2169856ea928SPeter Avalos 		options->control_persist_timeout = 0;
2170856ea928SPeter Avalos 	}
217118de8d7fSPeter Avalos 	if (options->hash_known_hosts == -1)
217218de8d7fSPeter Avalos 		options->hash_known_hosts = 0;
217318de8d7fSPeter Avalos 	if (options->tun_open == -1)
217418de8d7fSPeter Avalos 		options->tun_open = SSH_TUNMODE_NO;
217518de8d7fSPeter Avalos 	if (options->tun_local == -1)
217618de8d7fSPeter Avalos 		options->tun_local = SSH_TUNID_ANY;
217718de8d7fSPeter Avalos 	if (options->tun_remote == -1)
217818de8d7fSPeter Avalos 		options->tun_remote = SSH_TUNID_ANY;
217918de8d7fSPeter Avalos 	if (options->permit_local_command == -1)
218018de8d7fSPeter Avalos 		options->permit_local_command = 0;
218118de8d7fSPeter Avalos 	if (options->visual_host_key == -1)
218218de8d7fSPeter Avalos 		options->visual_host_key = 0;
21839f304aafSPeter Avalos 	if (options->ip_qos_interactive == -1)
2184664f4763Szrj 		options->ip_qos_interactive = IPTOS_DSCP_AF21;
21859f304aafSPeter Avalos 	if (options->ip_qos_bulk == -1)
2186664f4763Szrj 		options->ip_qos_bulk = IPTOS_DSCP_CS1;
21871c188a7fSPeter Avalos 	if (options->request_tty == -1)
21881c188a7fSPeter Avalos 		options->request_tty = REQUEST_TTY_AUTO;
218936e94dc5SPeter Avalos 	if (options->proxy_use_fdpass == -1)
219036e94dc5SPeter Avalos 		options->proxy_use_fdpass = 0;
219136e94dc5SPeter Avalos 	if (options->canonicalize_max_dots == -1)
219236e94dc5SPeter Avalos 		options->canonicalize_max_dots = 1;
219336e94dc5SPeter Avalos 	if (options->canonicalize_fallback_local == -1)
219436e94dc5SPeter Avalos 		options->canonicalize_fallback_local = 1;
219536e94dc5SPeter Avalos 	if (options->canonicalize_hostname == -1)
219636e94dc5SPeter Avalos 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
2197e9778795SPeter Avalos 	if (options->fingerprint_hash == -1)
2198e9778795SPeter Avalos 		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
2199*0cbfa66cSDaniel Fojt #ifdef ENABLE_SK_INTERNAL
2200*0cbfa66cSDaniel Fojt 	if (options->sk_provider == NULL)
2201*0cbfa66cSDaniel Fojt 		options->sk_provider = xstrdup("internal");
2202*0cbfa66cSDaniel Fojt #else
2203*0cbfa66cSDaniel Fojt 	if (options->sk_provider == NULL)
2204*0cbfa66cSDaniel Fojt 		options->sk_provider = xstrdup("$SSH_SK_PROVIDER");
2205*0cbfa66cSDaniel Fojt #endif
2206664f4763Szrj 
2207664f4763Szrj 	/* Expand KEX name lists */
2208664f4763Szrj 	all_cipher = cipher_alg_list(',', 0);
2209664f4763Szrj 	all_mac = mac_alg_list(',');
2210664f4763Szrj 	all_kex = kex_alg_list(',');
2211664f4763Szrj 	all_key = sshkey_alg_list(0, 0, 1, ',');
2212664f4763Szrj 	all_sig = sshkey_alg_list(0, 1, 1, ',');
2213*0cbfa66cSDaniel Fojt 	/* remove unsupported algos from default lists */
2214*0cbfa66cSDaniel Fojt 	def_cipher = match_filter_whitelist(KEX_CLIENT_ENCRYPT, all_cipher);
2215*0cbfa66cSDaniel Fojt 	def_mac = match_filter_whitelist(KEX_CLIENT_MAC, all_mac);
2216*0cbfa66cSDaniel Fojt 	def_kex = match_filter_whitelist(KEX_CLIENT_KEX, all_kex);
2217*0cbfa66cSDaniel Fojt 	def_key = match_filter_whitelist(KEX_DEFAULT_PK_ALG, all_key);
2218*0cbfa66cSDaniel Fojt 	def_sig = match_filter_whitelist(SSH_ALLOWED_CA_SIGALGS, all_sig);
2219664f4763Szrj #define ASSEMBLE(what, defaults, all) \
2220664f4763Szrj 	do { \
2221664f4763Szrj 		if ((r = kex_assemble_names(&options->what, \
2222664f4763Szrj 		    defaults, all)) != 0) \
2223664f4763Szrj 			fatal("%s: %s: %s", __func__, #what, ssh_err(r)); \
2224664f4763Szrj 	} while (0)
2225*0cbfa66cSDaniel Fojt 	ASSEMBLE(ciphers, def_cipher, all_cipher);
2226*0cbfa66cSDaniel Fojt 	ASSEMBLE(macs, def_mac, all_mac);
2227*0cbfa66cSDaniel Fojt 	ASSEMBLE(kex_algorithms, def_kex, all_kex);
2228*0cbfa66cSDaniel Fojt 	ASSEMBLE(hostbased_key_types, def_key, all_key);
2229*0cbfa66cSDaniel Fojt 	ASSEMBLE(pubkey_key_types, def_key, all_key);
2230*0cbfa66cSDaniel Fojt 	ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
2231664f4763Szrj #undef ASSEMBLE
2232664f4763Szrj 	free(all_cipher);
2233664f4763Szrj 	free(all_mac);
2234664f4763Szrj 	free(all_kex);
2235664f4763Szrj 	free(all_key);
2236664f4763Szrj 	free(all_sig);
2237*0cbfa66cSDaniel Fojt 	free(def_cipher);
2238*0cbfa66cSDaniel Fojt 	free(def_mac);
2239*0cbfa66cSDaniel Fojt 	free(def_kex);
2240*0cbfa66cSDaniel Fojt 	kex_default_pk_alg_filtered = def_key; /* save for later use */
2241*0cbfa66cSDaniel Fojt 	free(def_sig);
2242e9778795SPeter Avalos 
224336e94dc5SPeter Avalos #define CLEAR_ON_NONE(v) \
224436e94dc5SPeter Avalos 	do { \
224536e94dc5SPeter Avalos 		if (option_clear_or_none(v)) { \
224636e94dc5SPeter Avalos 			free(v); \
224736e94dc5SPeter Avalos 			v = NULL; \
224836e94dc5SPeter Avalos 		} \
224936e94dc5SPeter Avalos 	} while(0)
225036e94dc5SPeter Avalos 	CLEAR_ON_NONE(options->local_command);
2251ce74bacaSMatthew Dillon 	CLEAR_ON_NONE(options->remote_command);
225236e94dc5SPeter Avalos 	CLEAR_ON_NONE(options->proxy_command);
225336e94dc5SPeter Avalos 	CLEAR_ON_NONE(options->control_path);
2254e9778795SPeter Avalos 	CLEAR_ON_NONE(options->revoked_host_keys);
2255664f4763Szrj 	CLEAR_ON_NONE(options->pkcs11_provider);
2256*0cbfa66cSDaniel Fojt 	CLEAR_ON_NONE(options->sk_provider);
2257664f4763Szrj 	if (options->jump_host != NULL &&
2258664f4763Szrj 	    strcmp(options->jump_host, "none") == 0 &&
2259664f4763Szrj 	    options->jump_port == 0 && options->jump_user == NULL) {
2260664f4763Szrj 		free(options->jump_host);
2261664f4763Szrj 		options->jump_host = NULL;
2262664f4763Szrj 	}
2263e9778795SPeter Avalos 	/* options->identity_agent distinguishes NULL from 'none' */
226418de8d7fSPeter Avalos 	/* options->user will be set in the main program if appropriate */
226518de8d7fSPeter Avalos 	/* options->hostname will be set in the main program if appropriate */
226618de8d7fSPeter Avalos 	/* options->host_key_alias should not be set by default */
226718de8d7fSPeter Avalos 	/* options->preferred_authentications will be set in ssh */
226818de8d7fSPeter Avalos }
226918de8d7fSPeter Avalos 
227036e94dc5SPeter Avalos struct fwdarg {
227136e94dc5SPeter Avalos 	char *arg;
227236e94dc5SPeter Avalos 	int ispath;
227336e94dc5SPeter Avalos };
227436e94dc5SPeter Avalos 
227536e94dc5SPeter Avalos /*
227636e94dc5SPeter Avalos  * parse_fwd_field
227736e94dc5SPeter Avalos  * parses the next field in a port forwarding specification.
227836e94dc5SPeter Avalos  * sets fwd to the parsed field and advances p past the colon
227936e94dc5SPeter Avalos  * or sets it to NULL at end of string.
228036e94dc5SPeter Avalos  * returns 0 on success, else non-zero.
228136e94dc5SPeter Avalos  */
228236e94dc5SPeter Avalos static int
228336e94dc5SPeter Avalos parse_fwd_field(char **p, struct fwdarg *fwd)
228436e94dc5SPeter Avalos {
228536e94dc5SPeter Avalos 	char *ep, *cp = *p;
228636e94dc5SPeter Avalos 	int ispath = 0;
228736e94dc5SPeter Avalos 
228836e94dc5SPeter Avalos 	if (*cp == '\0') {
228936e94dc5SPeter Avalos 		*p = NULL;
229036e94dc5SPeter Avalos 		return -1;	/* end of string */
229136e94dc5SPeter Avalos 	}
229236e94dc5SPeter Avalos 
229336e94dc5SPeter Avalos 	/*
229436e94dc5SPeter Avalos 	 * A field escaped with square brackets is used literally.
229536e94dc5SPeter Avalos 	 * XXX - allow ']' to be escaped via backslash?
229636e94dc5SPeter Avalos 	 */
229736e94dc5SPeter Avalos 	if (*cp == '[') {
229836e94dc5SPeter Avalos 		/* find matching ']' */
229936e94dc5SPeter Avalos 		for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
230036e94dc5SPeter Avalos 			if (*ep == '/')
230136e94dc5SPeter Avalos 				ispath = 1;
230236e94dc5SPeter Avalos 		}
230336e94dc5SPeter Avalos 		/* no matching ']' or not at end of field. */
230436e94dc5SPeter Avalos 		if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
230536e94dc5SPeter Avalos 			return -1;
230636e94dc5SPeter Avalos 		/* NUL terminate the field and advance p past the colon */
230736e94dc5SPeter Avalos 		*ep++ = '\0';
230836e94dc5SPeter Avalos 		if (*ep != '\0')
230936e94dc5SPeter Avalos 			*ep++ = '\0';
231036e94dc5SPeter Avalos 		fwd->arg = cp + 1;
231136e94dc5SPeter Avalos 		fwd->ispath = ispath;
231236e94dc5SPeter Avalos 		*p = ep;
231336e94dc5SPeter Avalos 		return 0;
231436e94dc5SPeter Avalos 	}
231536e94dc5SPeter Avalos 
231636e94dc5SPeter Avalos 	for (cp = *p; *cp != '\0'; cp++) {
231736e94dc5SPeter Avalos 		switch (*cp) {
231836e94dc5SPeter Avalos 		case '\\':
231936e94dc5SPeter Avalos 			memmove(cp, cp + 1, strlen(cp + 1) + 1);
2320e9778795SPeter Avalos 			if (*cp == '\0')
2321e9778795SPeter Avalos 				return -1;
232236e94dc5SPeter Avalos 			break;
232336e94dc5SPeter Avalos 		case '/':
232436e94dc5SPeter Avalos 			ispath = 1;
232536e94dc5SPeter Avalos 			break;
232636e94dc5SPeter Avalos 		case ':':
232736e94dc5SPeter Avalos 			*cp++ = '\0';
232836e94dc5SPeter Avalos 			goto done;
232936e94dc5SPeter Avalos 		}
233036e94dc5SPeter Avalos 	}
233136e94dc5SPeter Avalos done:
233236e94dc5SPeter Avalos 	fwd->arg = *p;
233336e94dc5SPeter Avalos 	fwd->ispath = ispath;
233436e94dc5SPeter Avalos 	*p = cp;
233536e94dc5SPeter Avalos 	return 0;
233636e94dc5SPeter Avalos }
233736e94dc5SPeter Avalos 
233818de8d7fSPeter Avalos /*
233918de8d7fSPeter Avalos  * parse_forward
234018de8d7fSPeter Avalos  * parses a string containing a port forwarding specification of the form:
2341cb5eb4f1SPeter Avalos  *   dynamicfwd == 0
234236e94dc5SPeter Avalos  *	[listenhost:]listenport|listenpath:connecthost:connectport|connectpath
234336e94dc5SPeter Avalos  *	listenpath:connectpath
2344cb5eb4f1SPeter Avalos  *   dynamicfwd == 1
2345cb5eb4f1SPeter Avalos  *	[listenhost:]listenport
234618de8d7fSPeter Avalos  * returns number of arguments parsed or zero on error
234718de8d7fSPeter Avalos  */
234818de8d7fSPeter Avalos int
234936e94dc5SPeter Avalos parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
235018de8d7fSPeter Avalos {
235136e94dc5SPeter Avalos 	struct fwdarg fwdargs[4];
235236e94dc5SPeter Avalos 	char *p, *cp;
235318de8d7fSPeter Avalos 	int i;
235418de8d7fSPeter Avalos 
235536e94dc5SPeter Avalos 	memset(fwd, 0, sizeof(*fwd));
235636e94dc5SPeter Avalos 	memset(fwdargs, 0, sizeof(fwdargs));
235718de8d7fSPeter Avalos 
235818de8d7fSPeter Avalos 	cp = p = xstrdup(fwdspec);
235918de8d7fSPeter Avalos 
236018de8d7fSPeter Avalos 	/* skip leading spaces */
236136e94dc5SPeter Avalos 	while (isspace((u_char)*cp))
236218de8d7fSPeter Avalos 		cp++;
236318de8d7fSPeter Avalos 
236436e94dc5SPeter Avalos 	for (i = 0; i < 4; ++i) {
236536e94dc5SPeter Avalos 		if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
236618de8d7fSPeter Avalos 			break;
236736e94dc5SPeter Avalos 	}
236818de8d7fSPeter Avalos 
2369cb5eb4f1SPeter Avalos 	/* Check for trailing garbage */
237036e94dc5SPeter Avalos 	if (cp != NULL && *cp != '\0') {
237118de8d7fSPeter Avalos 		i = 0;	/* failure */
237236e94dc5SPeter Avalos 	}
237318de8d7fSPeter Avalos 
237418de8d7fSPeter Avalos 	switch (i) {
2375cb5eb4f1SPeter Avalos 	case 1:
237636e94dc5SPeter Avalos 		if (fwdargs[0].ispath) {
237736e94dc5SPeter Avalos 			fwd->listen_path = xstrdup(fwdargs[0].arg);
237836e94dc5SPeter Avalos 			fwd->listen_port = PORT_STREAMLOCAL;
237936e94dc5SPeter Avalos 		} else {
2380cb5eb4f1SPeter Avalos 			fwd->listen_host = NULL;
238136e94dc5SPeter Avalos 			fwd->listen_port = a2port(fwdargs[0].arg);
238236e94dc5SPeter Avalos 		}
2383cb5eb4f1SPeter Avalos 		fwd->connect_host = xstrdup("socks");
2384cb5eb4f1SPeter Avalos 		break;
2385cb5eb4f1SPeter Avalos 
2386cb5eb4f1SPeter Avalos 	case 2:
238736e94dc5SPeter Avalos 		if (fwdargs[0].ispath && fwdargs[1].ispath) {
238836e94dc5SPeter Avalos 			fwd->listen_path = xstrdup(fwdargs[0].arg);
238936e94dc5SPeter Avalos 			fwd->listen_port = PORT_STREAMLOCAL;
239036e94dc5SPeter Avalos 			fwd->connect_path = xstrdup(fwdargs[1].arg);
239136e94dc5SPeter Avalos 			fwd->connect_port = PORT_STREAMLOCAL;
239236e94dc5SPeter Avalos 		} else if (fwdargs[1].ispath) {
239336e94dc5SPeter Avalos 			fwd->listen_host = NULL;
239436e94dc5SPeter Avalos 			fwd->listen_port = a2port(fwdargs[0].arg);
239536e94dc5SPeter Avalos 			fwd->connect_path = xstrdup(fwdargs[1].arg);
239636e94dc5SPeter Avalos 			fwd->connect_port = PORT_STREAMLOCAL;
239736e94dc5SPeter Avalos 		} else {
239836e94dc5SPeter Avalos 			fwd->listen_host = xstrdup(fwdargs[0].arg);
239936e94dc5SPeter Avalos 			fwd->listen_port = a2port(fwdargs[1].arg);
2400cb5eb4f1SPeter Avalos 			fwd->connect_host = xstrdup("socks");
240136e94dc5SPeter Avalos 		}
2402cb5eb4f1SPeter Avalos 		break;
2403cb5eb4f1SPeter Avalos 
240418de8d7fSPeter Avalos 	case 3:
240536e94dc5SPeter Avalos 		if (fwdargs[0].ispath) {
240636e94dc5SPeter Avalos 			fwd->listen_path = xstrdup(fwdargs[0].arg);
240736e94dc5SPeter Avalos 			fwd->listen_port = PORT_STREAMLOCAL;
240836e94dc5SPeter Avalos 			fwd->connect_host = xstrdup(fwdargs[1].arg);
240936e94dc5SPeter Avalos 			fwd->connect_port = a2port(fwdargs[2].arg);
241036e94dc5SPeter Avalos 		} else if (fwdargs[2].ispath) {
241136e94dc5SPeter Avalos 			fwd->listen_host = xstrdup(fwdargs[0].arg);
241236e94dc5SPeter Avalos 			fwd->listen_port = a2port(fwdargs[1].arg);
241336e94dc5SPeter Avalos 			fwd->connect_path = xstrdup(fwdargs[2].arg);
241436e94dc5SPeter Avalos 			fwd->connect_port = PORT_STREAMLOCAL;
241536e94dc5SPeter Avalos 		} else {
241618de8d7fSPeter Avalos 			fwd->listen_host = NULL;
241736e94dc5SPeter Avalos 			fwd->listen_port = a2port(fwdargs[0].arg);
241836e94dc5SPeter Avalos 			fwd->connect_host = xstrdup(fwdargs[1].arg);
241936e94dc5SPeter Avalos 			fwd->connect_port = a2port(fwdargs[2].arg);
242036e94dc5SPeter Avalos 		}
242118de8d7fSPeter Avalos 		break;
242218de8d7fSPeter Avalos 
242318de8d7fSPeter Avalos 	case 4:
242436e94dc5SPeter Avalos 		fwd->listen_host = xstrdup(fwdargs[0].arg);
242536e94dc5SPeter Avalos 		fwd->listen_port = a2port(fwdargs[1].arg);
242636e94dc5SPeter Avalos 		fwd->connect_host = xstrdup(fwdargs[2].arg);
242736e94dc5SPeter Avalos 		fwd->connect_port = a2port(fwdargs[3].arg);
242818de8d7fSPeter Avalos 		break;
242918de8d7fSPeter Avalos 	default:
243018de8d7fSPeter Avalos 		i = 0; /* failure */
243118de8d7fSPeter Avalos 	}
243218de8d7fSPeter Avalos 
243336e94dc5SPeter Avalos 	free(p);
243418de8d7fSPeter Avalos 
2435cb5eb4f1SPeter Avalos 	if (dynamicfwd) {
2436cb5eb4f1SPeter Avalos 		if (!(i == 1 || i == 2))
2437cb5eb4f1SPeter Avalos 			goto fail_free;
2438cb5eb4f1SPeter Avalos 	} else {
243936e94dc5SPeter Avalos 		if (!(i == 3 || i == 4)) {
244036e94dc5SPeter Avalos 			if (fwd->connect_path == NULL &&
244136e94dc5SPeter Avalos 			    fwd->listen_path == NULL)
2442cb5eb4f1SPeter Avalos 				goto fail_free;
244336e94dc5SPeter Avalos 		}
244436e94dc5SPeter Avalos 		if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
2445cb5eb4f1SPeter Avalos 			goto fail_free;
2446cb5eb4f1SPeter Avalos 	}
2447cb5eb4f1SPeter Avalos 
244836e94dc5SPeter Avalos 	if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
244936e94dc5SPeter Avalos 	    (!remotefwd && fwd->listen_port == 0))
245018de8d7fSPeter Avalos 		goto fail_free;
245118de8d7fSPeter Avalos 	if (fwd->connect_host != NULL &&
245218de8d7fSPeter Avalos 	    strlen(fwd->connect_host) >= NI_MAXHOST)
245318de8d7fSPeter Avalos 		goto fail_free;
245436e94dc5SPeter Avalos 	/* XXX - if connecting to a remote socket, max sun len may not match this host */
245536e94dc5SPeter Avalos 	if (fwd->connect_path != NULL &&
245636e94dc5SPeter Avalos 	    strlen(fwd->connect_path) >= PATH_MAX_SUN)
245736e94dc5SPeter Avalos 		goto fail_free;
2458cb5eb4f1SPeter Avalos 	if (fwd->listen_host != NULL &&
2459cb5eb4f1SPeter Avalos 	    strlen(fwd->listen_host) >= NI_MAXHOST)
2460cb5eb4f1SPeter Avalos 		goto fail_free;
246136e94dc5SPeter Avalos 	if (fwd->listen_path != NULL &&
246236e94dc5SPeter Avalos 	    strlen(fwd->listen_path) >= PATH_MAX_SUN)
246336e94dc5SPeter Avalos 		goto fail_free;
246418de8d7fSPeter Avalos 
246518de8d7fSPeter Avalos 	return (i);
246618de8d7fSPeter Avalos 
246718de8d7fSPeter Avalos  fail_free:
246836e94dc5SPeter Avalos 	free(fwd->connect_host);
2469cb5eb4f1SPeter Avalos 	fwd->connect_host = NULL;
247036e94dc5SPeter Avalos 	free(fwd->connect_path);
247136e94dc5SPeter Avalos 	fwd->connect_path = NULL;
247236e94dc5SPeter Avalos 	free(fwd->listen_host);
2473cb5eb4f1SPeter Avalos 	fwd->listen_host = NULL;
247436e94dc5SPeter Avalos 	free(fwd->listen_path);
247536e94dc5SPeter Avalos 	fwd->listen_path = NULL;
247618de8d7fSPeter Avalos 	return (0);
247718de8d7fSPeter Avalos }
2478e9778795SPeter Avalos 
2479e9778795SPeter Avalos int
2480e9778795SPeter Avalos parse_jump(const char *s, Options *o, int active)
2481e9778795SPeter Avalos {
2482e9778795SPeter Avalos 	char *orig, *sdup, *cp;
2483e9778795SPeter Avalos 	char *host = NULL, *user = NULL;
2484e9778795SPeter Avalos 	int ret = -1, port = -1, first;
2485e9778795SPeter Avalos 
2486e9778795SPeter Avalos 	active &= o->proxy_command == NULL && o->jump_host == NULL;
2487e9778795SPeter Avalos 
2488e9778795SPeter Avalos 	orig = sdup = xstrdup(s);
2489e9778795SPeter Avalos 	first = active;
2490e9778795SPeter Avalos 	do {
2491664f4763Szrj 		if (strcasecmp(s, "none") == 0)
2492664f4763Szrj 			break;
2493e9778795SPeter Avalos 		if ((cp = strrchr(sdup, ',')) == NULL)
2494e9778795SPeter Avalos 			cp = sdup; /* last */
2495e9778795SPeter Avalos 		else
2496e9778795SPeter Avalos 			*cp++ = '\0';
2497e9778795SPeter Avalos 
2498e9778795SPeter Avalos 		if (first) {
2499e9778795SPeter Avalos 			/* First argument and configuration is active */
2500664f4763Szrj 			if (parse_ssh_uri(cp, &user, &host, &port) == -1 ||
2501664f4763Szrj 			    parse_user_host_port(cp, &user, &host, &port) != 0)
2502e9778795SPeter Avalos 				goto out;
2503e9778795SPeter Avalos 		} else {
2504e9778795SPeter Avalos 			/* Subsequent argument or inactive configuration */
2505664f4763Szrj 			if (parse_ssh_uri(cp, NULL, NULL, NULL) == -1 ||
2506664f4763Szrj 			    parse_user_host_port(cp, NULL, NULL, NULL) != 0)
2507e9778795SPeter Avalos 				goto out;
2508e9778795SPeter Avalos 		}
2509e9778795SPeter Avalos 		first = 0; /* only check syntax for subsequent hosts */
2510e9778795SPeter Avalos 	} while (cp != sdup);
2511e9778795SPeter Avalos 	/* success */
2512e9778795SPeter Avalos 	if (active) {
2513664f4763Szrj 		if (strcasecmp(s, "none") == 0) {
2514664f4763Szrj 			o->jump_host = xstrdup("none");
2515664f4763Szrj 			o->jump_port = 0;
2516664f4763Szrj 		} else {
2517e9778795SPeter Avalos 			o->jump_user = user;
2518e9778795SPeter Avalos 			o->jump_host = host;
2519e9778795SPeter Avalos 			o->jump_port = port;
2520e9778795SPeter Avalos 			o->proxy_command = xstrdup("none");
2521e9778795SPeter Avalos 			user = host = NULL;
2522e9778795SPeter Avalos 			if ((cp = strrchr(s, ',')) != NULL && cp != s) {
2523e9778795SPeter Avalos 				o->jump_extra = xstrdup(s);
2524e9778795SPeter Avalos 				o->jump_extra[cp - s] = '\0';
2525e9778795SPeter Avalos 			}
2526e9778795SPeter Avalos 		}
2527664f4763Szrj 	}
2528e9778795SPeter Avalos 	ret = 0;
2529e9778795SPeter Avalos  out:
2530e9778795SPeter Avalos 	free(orig);
2531e9778795SPeter Avalos 	free(user);
2532e9778795SPeter Avalos 	free(host);
2533e9778795SPeter Avalos 	return ret;
2534e9778795SPeter Avalos }
2535e9778795SPeter Avalos 
2536664f4763Szrj int
2537664f4763Szrj parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
2538664f4763Szrj {
2539664f4763Szrj 	char *path;
2540664f4763Szrj 	int r;
2541664f4763Szrj 
2542664f4763Szrj 	r = parse_uri("ssh", uri, userp, hostp, portp, &path);
2543664f4763Szrj 	if (r == 0 && path != NULL)
2544664f4763Szrj 		r = -1;		/* path not allowed */
2545664f4763Szrj 	return r;
2546664f4763Szrj }
2547664f4763Szrj 
2548e9778795SPeter Avalos /* XXX the following is a near-vebatim copy from servconf.c; refactor */
2549e9778795SPeter Avalos static const char *
2550e9778795SPeter Avalos fmt_multistate_int(int val, const struct multistate *m)
2551e9778795SPeter Avalos {
2552e9778795SPeter Avalos 	u_int i;
2553e9778795SPeter Avalos 
2554e9778795SPeter Avalos 	for (i = 0; m[i].key != NULL; i++) {
2555e9778795SPeter Avalos 		if (m[i].value == val)
2556e9778795SPeter Avalos 			return m[i].key;
2557e9778795SPeter Avalos 	}
2558e9778795SPeter Avalos 	return "UNKNOWN";
2559e9778795SPeter Avalos }
2560e9778795SPeter Avalos 
2561e9778795SPeter Avalos static const char *
2562e9778795SPeter Avalos fmt_intarg(OpCodes code, int val)
2563e9778795SPeter Avalos {
2564e9778795SPeter Avalos 	if (val == -1)
2565e9778795SPeter Avalos 		return "unset";
2566e9778795SPeter Avalos 	switch (code) {
2567e9778795SPeter Avalos 	case oAddressFamily:
2568e9778795SPeter Avalos 		return fmt_multistate_int(val, multistate_addressfamily);
2569e9778795SPeter Avalos 	case oVerifyHostKeyDNS:
2570e9778795SPeter Avalos 	case oUpdateHostkeys:
2571e9778795SPeter Avalos 		return fmt_multistate_int(val, multistate_yesnoask);
2572ce74bacaSMatthew Dillon 	case oStrictHostKeyChecking:
2573ce74bacaSMatthew Dillon 		return fmt_multistate_int(val, multistate_strict_hostkey);
2574e9778795SPeter Avalos 	case oControlMaster:
2575e9778795SPeter Avalos 		return fmt_multistate_int(val, multistate_controlmaster);
2576e9778795SPeter Avalos 	case oTunnel:
2577e9778795SPeter Avalos 		return fmt_multistate_int(val, multistate_tunnel);
2578e9778795SPeter Avalos 	case oRequestTTY:
2579e9778795SPeter Avalos 		return fmt_multistate_int(val, multistate_requesttty);
2580e9778795SPeter Avalos 	case oCanonicalizeHostname:
2581e9778795SPeter Avalos 		return fmt_multistate_int(val, multistate_canonicalizehostname);
2582664f4763Szrj 	case oAddKeysToAgent:
2583664f4763Szrj 		return fmt_multistate_int(val, multistate_yesnoaskconfirm);
2584e9778795SPeter Avalos 	case oFingerprintHash:
2585e9778795SPeter Avalos 		return ssh_digest_alg_name(val);
2586e9778795SPeter Avalos 	default:
2587e9778795SPeter Avalos 		switch (val) {
2588e9778795SPeter Avalos 		case 0:
2589e9778795SPeter Avalos 			return "no";
2590e9778795SPeter Avalos 		case 1:
2591e9778795SPeter Avalos 			return "yes";
2592e9778795SPeter Avalos 		default:
2593e9778795SPeter Avalos 			return "UNKNOWN";
2594e9778795SPeter Avalos 		}
2595e9778795SPeter Avalos 	}
2596e9778795SPeter Avalos }
2597e9778795SPeter Avalos 
2598e9778795SPeter Avalos static const char *
2599e9778795SPeter Avalos lookup_opcode_name(OpCodes code)
2600e9778795SPeter Avalos {
2601e9778795SPeter Avalos 	u_int i;
2602e9778795SPeter Avalos 
2603e9778795SPeter Avalos 	for (i = 0; keywords[i].name != NULL; i++)
2604e9778795SPeter Avalos 		if (keywords[i].opcode == code)
2605e9778795SPeter Avalos 			return(keywords[i].name);
2606e9778795SPeter Avalos 	return "UNKNOWN";
2607e9778795SPeter Avalos }
2608e9778795SPeter Avalos 
2609e9778795SPeter Avalos static void
2610e9778795SPeter Avalos dump_cfg_int(OpCodes code, int val)
2611e9778795SPeter Avalos {
2612e9778795SPeter Avalos 	printf("%s %d\n", lookup_opcode_name(code), val);
2613e9778795SPeter Avalos }
2614e9778795SPeter Avalos 
2615e9778795SPeter Avalos static void
2616e9778795SPeter Avalos dump_cfg_fmtint(OpCodes code, int val)
2617e9778795SPeter Avalos {
2618e9778795SPeter Avalos 	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
2619e9778795SPeter Avalos }
2620e9778795SPeter Avalos 
2621e9778795SPeter Avalos static void
2622e9778795SPeter Avalos dump_cfg_string(OpCodes code, const char *val)
2623e9778795SPeter Avalos {
2624e9778795SPeter Avalos 	if (val == NULL)
2625e9778795SPeter Avalos 		return;
2626e9778795SPeter Avalos 	printf("%s %s\n", lookup_opcode_name(code), val);
2627e9778795SPeter Avalos }
2628e9778795SPeter Avalos 
2629e9778795SPeter Avalos static void
2630e9778795SPeter Avalos dump_cfg_strarray(OpCodes code, u_int count, char **vals)
2631e9778795SPeter Avalos {
2632e9778795SPeter Avalos 	u_int i;
2633e9778795SPeter Avalos 
2634e9778795SPeter Avalos 	for (i = 0; i < count; i++)
2635e9778795SPeter Avalos 		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
2636e9778795SPeter Avalos }
2637e9778795SPeter Avalos 
2638e9778795SPeter Avalos static void
2639e9778795SPeter Avalos dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
2640e9778795SPeter Avalos {
2641e9778795SPeter Avalos 	u_int i;
2642e9778795SPeter Avalos 
2643e9778795SPeter Avalos 	printf("%s", lookup_opcode_name(code));
2644e9778795SPeter Avalos 	for (i = 0; i < count; i++)
2645e9778795SPeter Avalos 		printf(" %s",  vals[i]);
2646e9778795SPeter Avalos 	printf("\n");
2647e9778795SPeter Avalos }
2648e9778795SPeter Avalos 
2649e9778795SPeter Avalos static void
2650e9778795SPeter Avalos dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
2651e9778795SPeter Avalos {
2652e9778795SPeter Avalos 	const struct Forward *fwd;
2653e9778795SPeter Avalos 	u_int i;
2654e9778795SPeter Avalos 
2655e9778795SPeter Avalos 	/* oDynamicForward */
2656e9778795SPeter Avalos 	for (i = 0; i < count; i++) {
2657e9778795SPeter Avalos 		fwd = &fwds[i];
2658ce74bacaSMatthew Dillon 		if (code == oDynamicForward && fwd->connect_host != NULL &&
2659e9778795SPeter Avalos 		    strcmp(fwd->connect_host, "socks") != 0)
2660e9778795SPeter Avalos 			continue;
2661ce74bacaSMatthew Dillon 		if (code == oLocalForward && fwd->connect_host != NULL &&
2662e9778795SPeter Avalos 		    strcmp(fwd->connect_host, "socks") == 0)
2663e9778795SPeter Avalos 			continue;
2664e9778795SPeter Avalos 		printf("%s", lookup_opcode_name(code));
2665e9778795SPeter Avalos 		if (fwd->listen_port == PORT_STREAMLOCAL)
2666e9778795SPeter Avalos 			printf(" %s", fwd->listen_path);
2667e9778795SPeter Avalos 		else if (fwd->listen_host == NULL)
2668e9778795SPeter Avalos 			printf(" %d", fwd->listen_port);
2669e9778795SPeter Avalos 		else {
2670e9778795SPeter Avalos 			printf(" [%s]:%d",
2671e9778795SPeter Avalos 			    fwd->listen_host, fwd->listen_port);
2672e9778795SPeter Avalos 		}
2673e9778795SPeter Avalos 		if (code != oDynamicForward) {
2674e9778795SPeter Avalos 			if (fwd->connect_port == PORT_STREAMLOCAL)
2675e9778795SPeter Avalos 				printf(" %s", fwd->connect_path);
2676e9778795SPeter Avalos 			else if (fwd->connect_host == NULL)
2677e9778795SPeter Avalos 				printf(" %d", fwd->connect_port);
2678e9778795SPeter Avalos 			else {
2679e9778795SPeter Avalos 				printf(" [%s]:%d",
2680e9778795SPeter Avalos 				    fwd->connect_host, fwd->connect_port);
2681e9778795SPeter Avalos 			}
2682e9778795SPeter Avalos 		}
2683e9778795SPeter Avalos 		printf("\n");
2684e9778795SPeter Avalos 	}
2685e9778795SPeter Avalos }
2686e9778795SPeter Avalos 
2687e9778795SPeter Avalos void
2688e9778795SPeter Avalos dump_client_config(Options *o, const char *host)
2689e9778795SPeter Avalos {
2690*0cbfa66cSDaniel Fojt 	int i, r;
2691664f4763Szrj 	char buf[8], *all_key;
2692e9778795SPeter Avalos 
2693*0cbfa66cSDaniel Fojt 	/*
2694*0cbfa66cSDaniel Fojt 	 * Expand HostKeyAlgorithms name lists. This isn't handled in
2695*0cbfa66cSDaniel Fojt 	 * fill_default_options() like the other algorithm lists because
2696*0cbfa66cSDaniel Fojt 	 * the host key algorithms are by default dynamically chosen based
2697*0cbfa66cSDaniel Fojt 	 * on the host's keys found in known_hosts.
2698*0cbfa66cSDaniel Fojt 	 */
2699664f4763Szrj 	all_key = sshkey_alg_list(0, 0, 1, ',');
2700*0cbfa66cSDaniel Fojt 	if ((r = kex_assemble_names(&o->hostkeyalgorithms, kex_default_pk_alg(),
2701*0cbfa66cSDaniel Fojt 	    all_key)) != 0)
2702*0cbfa66cSDaniel Fojt 		fatal("%s: expand HostKeyAlgorithms: %s", __func__, ssh_err(r));
2703664f4763Szrj 	free(all_key);
2704e9778795SPeter Avalos 
2705e9778795SPeter Avalos 	/* Most interesting options first: user, host, port */
2706e9778795SPeter Avalos 	dump_cfg_string(oUser, o->user);
2707*0cbfa66cSDaniel Fojt 	dump_cfg_string(oHostname, host);
2708e9778795SPeter Avalos 	dump_cfg_int(oPort, o->port);
2709e9778795SPeter Avalos 
2710e9778795SPeter Avalos 	/* Flag options */
2711664f4763Szrj 	dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent);
2712e9778795SPeter Avalos 	dump_cfg_fmtint(oAddressFamily, o->address_family);
2713e9778795SPeter Avalos 	dump_cfg_fmtint(oBatchMode, o->batch_mode);
2714e9778795SPeter Avalos 	dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
2715e9778795SPeter Avalos 	dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
2716e9778795SPeter Avalos 	dump_cfg_fmtint(oChallengeResponseAuthentication, o->challenge_response_authentication);
2717e9778795SPeter Avalos 	dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
2718e9778795SPeter Avalos 	dump_cfg_fmtint(oCompression, o->compression);
2719e9778795SPeter Avalos 	dump_cfg_fmtint(oControlMaster, o->control_master);
2720e9778795SPeter Avalos 	dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
2721e9778795SPeter Avalos 	dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
2722e9778795SPeter Avalos 	dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
2723e9778795SPeter Avalos 	dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
2724e9778795SPeter Avalos 	dump_cfg_fmtint(oForwardX11, o->forward_x11);
2725e9778795SPeter Avalos 	dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
2726e9778795SPeter Avalos 	dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
2727e9778795SPeter Avalos #ifdef GSSAPI
2728e9778795SPeter Avalos 	dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
2729e9778795SPeter Avalos 	dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
2730e9778795SPeter Avalos #endif /* GSSAPI */
2731e9778795SPeter Avalos 	dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
2732e9778795SPeter Avalos 	dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
2733e9778795SPeter Avalos 	dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
2734e9778795SPeter Avalos 	dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
2735e9778795SPeter Avalos 	dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
2736e9778795SPeter Avalos 	dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
2737e9778795SPeter Avalos 	dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
2738e9778795SPeter Avalos 	dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
2739e9778795SPeter Avalos 	dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
2740e9778795SPeter Avalos 	dump_cfg_fmtint(oRequestTTY, o->request_tty);
2741e9778795SPeter Avalos 	dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
2742e9778795SPeter Avalos 	dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
2743e9778795SPeter Avalos 	dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
2744e9778795SPeter Avalos 	dump_cfg_fmtint(oTunnel, o->tun_open);
2745e9778795SPeter Avalos 	dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
2746e9778795SPeter Avalos 	dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
2747e9778795SPeter Avalos 	dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
2748e9778795SPeter Avalos 
2749e9778795SPeter Avalos 	/* Integer options */
2750e9778795SPeter Avalos 	dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
2751e9778795SPeter Avalos 	dump_cfg_int(oConnectionAttempts, o->connection_attempts);
2752e9778795SPeter Avalos 	dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
2753e9778795SPeter Avalos 	dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
2754e9778795SPeter Avalos 	dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
2755e9778795SPeter Avalos 	dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
2756e9778795SPeter Avalos 
2757e9778795SPeter Avalos 	/* String options */
2758e9778795SPeter Avalos 	dump_cfg_string(oBindAddress, o->bind_address);
2759664f4763Szrj 	dump_cfg_string(oBindInterface, o->bind_interface);
2760*0cbfa66cSDaniel Fojt 	dump_cfg_string(oCiphers, o->ciphers);
2761e9778795SPeter Avalos 	dump_cfg_string(oControlPath, o->control_path);
2762e9778795SPeter Avalos 	dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
2763e9778795SPeter Avalos 	dump_cfg_string(oHostKeyAlias, o->host_key_alias);
2764e9778795SPeter Avalos 	dump_cfg_string(oHostbasedKeyTypes, o->hostbased_key_types);
2765e9778795SPeter Avalos 	dump_cfg_string(oIdentityAgent, o->identity_agent);
2766664f4763Szrj 	dump_cfg_string(oIgnoreUnknown, o->ignored_unknown);
2767e9778795SPeter Avalos 	dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
2768*0cbfa66cSDaniel Fojt 	dump_cfg_string(oKexAlgorithms, o->kex_algorithms);
2769*0cbfa66cSDaniel Fojt 	dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms);
2770e9778795SPeter Avalos 	dump_cfg_string(oLocalCommand, o->local_command);
2771ce74bacaSMatthew Dillon 	dump_cfg_string(oRemoteCommand, o->remote_command);
2772e9778795SPeter Avalos 	dump_cfg_string(oLogLevel, log_level_name(o->log_level));
2773*0cbfa66cSDaniel Fojt 	dump_cfg_string(oMacs, o->macs);
2774ce74bacaSMatthew Dillon #ifdef ENABLE_PKCS11
2775e9778795SPeter Avalos 	dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
2776ce74bacaSMatthew Dillon #endif
2777*0cbfa66cSDaniel Fojt 	dump_cfg_string(oSecurityKeyProvider, o->sk_provider);
2778e9778795SPeter Avalos 	dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
2779e9778795SPeter Avalos 	dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types);
2780e9778795SPeter Avalos 	dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
2781e9778795SPeter Avalos 	dump_cfg_string(oXAuthLocation, o->xauth_location);
2782e9778795SPeter Avalos 
2783e9778795SPeter Avalos 	/* Forwards */
2784e9778795SPeter Avalos 	dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
2785e9778795SPeter Avalos 	dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
2786e9778795SPeter Avalos 	dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
2787e9778795SPeter Avalos 
2788e9778795SPeter Avalos 	/* String array options */
2789e9778795SPeter Avalos 	dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
2790e9778795SPeter Avalos 	dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
2791664f4763Szrj 	dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files);
2792e9778795SPeter Avalos 	dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
2793e9778795SPeter Avalos 	dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
2794e9778795SPeter Avalos 	dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
2795664f4763Szrj 	dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
2796e9778795SPeter Avalos 
2797e9778795SPeter Avalos 	/* Special cases */
2798e9778795SPeter Avalos 
2799*0cbfa66cSDaniel Fojt 	/* oForwardAgent */
2800*0cbfa66cSDaniel Fojt 	if (o->forward_agent_sock_path == NULL)
2801*0cbfa66cSDaniel Fojt 		dump_cfg_fmtint(oForwardAgent, o->forward_agent);
2802*0cbfa66cSDaniel Fojt 	else
2803*0cbfa66cSDaniel Fojt 		dump_cfg_string(oForwardAgent, o->forward_agent_sock_path);
2804*0cbfa66cSDaniel Fojt 
2805e9778795SPeter Avalos 	/* oConnectTimeout */
2806e9778795SPeter Avalos 	if (o->connection_timeout == -1)
2807e9778795SPeter Avalos 		printf("connecttimeout none\n");
2808e9778795SPeter Avalos 	else
2809e9778795SPeter Avalos 		dump_cfg_int(oConnectTimeout, o->connection_timeout);
2810e9778795SPeter Avalos 
2811e9778795SPeter Avalos 	/* oTunnelDevice */
2812e9778795SPeter Avalos 	printf("tunneldevice");
2813e9778795SPeter Avalos 	if (o->tun_local == SSH_TUNID_ANY)
2814e9778795SPeter Avalos 		printf(" any");
2815e9778795SPeter Avalos 	else
2816e9778795SPeter Avalos 		printf(" %d", o->tun_local);
2817e9778795SPeter Avalos 	if (o->tun_remote == SSH_TUNID_ANY)
2818e9778795SPeter Avalos 		printf(":any");
2819e9778795SPeter Avalos 	else
2820e9778795SPeter Avalos 		printf(":%d", o->tun_remote);
2821e9778795SPeter Avalos 	printf("\n");
2822e9778795SPeter Avalos 
2823e9778795SPeter Avalos 	/* oCanonicalizePermittedCNAMEs */
2824e9778795SPeter Avalos 	if ( o->num_permitted_cnames > 0) {
2825e9778795SPeter Avalos 		printf("canonicalizePermittedcnames");
2826e9778795SPeter Avalos 		for (i = 0; i < o->num_permitted_cnames; i++) {
2827e9778795SPeter Avalos 			printf(" %s:%s", o->permitted_cnames[i].source_list,
2828e9778795SPeter Avalos 			    o->permitted_cnames[i].target_list);
2829e9778795SPeter Avalos 		}
2830e9778795SPeter Avalos 		printf("\n");
2831e9778795SPeter Avalos 	}
2832e9778795SPeter Avalos 
2833e9778795SPeter Avalos 	/* oControlPersist */
2834e9778795SPeter Avalos 	if (o->control_persist == 0 || o->control_persist_timeout == 0)
2835e9778795SPeter Avalos 		dump_cfg_fmtint(oControlPersist, o->control_persist);
2836e9778795SPeter Avalos 	else
2837e9778795SPeter Avalos 		dump_cfg_int(oControlPersist, o->control_persist_timeout);
2838e9778795SPeter Avalos 
2839e9778795SPeter Avalos 	/* oEscapeChar */
2840e9778795SPeter Avalos 	if (o->escape_char == SSH_ESCAPECHAR_NONE)
2841e9778795SPeter Avalos 		printf("escapechar none\n");
2842e9778795SPeter Avalos 	else {
2843e9778795SPeter Avalos 		vis(buf, o->escape_char, VIS_WHITE, 0);
2844e9778795SPeter Avalos 		printf("escapechar %s\n", buf);
2845e9778795SPeter Avalos 	}
2846e9778795SPeter Avalos 
2847e9778795SPeter Avalos 	/* oIPQoS */
2848e9778795SPeter Avalos 	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
2849e9778795SPeter Avalos 	printf("%s\n", iptos2str(o->ip_qos_bulk));
2850e9778795SPeter Avalos 
2851e9778795SPeter Avalos 	/* oRekeyLimit */
2852e9778795SPeter Avalos 	printf("rekeylimit %llu %d\n",
2853e9778795SPeter Avalos 	    (unsigned long long)o->rekey_limit, o->rekey_interval);
2854e9778795SPeter Avalos 
2855e9778795SPeter Avalos 	/* oStreamLocalBindMask */
2856e9778795SPeter Avalos 	printf("streamlocalbindmask 0%o\n",
2857e9778795SPeter Avalos 	    o->fwd_opts.streamlocal_bind_mask);
2858e9778795SPeter Avalos 
2859664f4763Szrj 	/* oLogFacility */
2860664f4763Szrj 	printf("syslogfacility %s\n", log_facility_name(o->log_facility));
2861664f4763Szrj 
2862e9778795SPeter Avalos 	/* oProxyCommand / oProxyJump */
2863e9778795SPeter Avalos 	if (o->jump_host == NULL)
2864e9778795SPeter Avalos 		dump_cfg_string(oProxyCommand, o->proxy_command);
2865e9778795SPeter Avalos 	else {
2866e9778795SPeter Avalos 		/* Check for numeric addresses */
2867e9778795SPeter Avalos 		i = strchr(o->jump_host, ':') != NULL ||
2868e9778795SPeter Avalos 		    strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
2869e9778795SPeter Avalos 		snprintf(buf, sizeof(buf), "%d", o->jump_port);
2870e9778795SPeter Avalos 		printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
2871e9778795SPeter Avalos 		    /* optional additional jump spec */
2872e9778795SPeter Avalos 		    o->jump_extra == NULL ? "" : o->jump_extra,
2873e9778795SPeter Avalos 		    o->jump_extra == NULL ? "" : ",",
2874e9778795SPeter Avalos 		    /* optional user */
2875e9778795SPeter Avalos 		    o->jump_user == NULL ? "" : o->jump_user,
2876e9778795SPeter Avalos 		    o->jump_user == NULL ? "" : "@",
2877e9778795SPeter Avalos 		    /* opening [ if hostname is numeric */
2878e9778795SPeter Avalos 		    i ? "[" : "",
2879e9778795SPeter Avalos 		    /* mandatory hostname */
2880e9778795SPeter Avalos 		    o->jump_host,
2881e9778795SPeter Avalos 		    /* closing ] if hostname is numeric */
2882e9778795SPeter Avalos 		    i ? "]" : "",
2883e9778795SPeter Avalos 		    /* optional port number */
2884e9778795SPeter Avalos 		    o->jump_port <= 0 ? "" : ":",
2885e9778795SPeter Avalos 		    o->jump_port <= 0 ? "" : buf);
2886e9778795SPeter Avalos 	}
2887e9778795SPeter Avalos }
2888