xref: /dragonfly/crypto/openssh/readconf.c (revision ee116499)
1*ee116499SAntonio Huete Jimenez /* $OpenBSD: readconf.c,v 1.369 2022/09/17 10:33:18 djm 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>
400cbfa66cSDaniel 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
890cbfa66cSDaniel 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,
1470cbfa66cSDaniel Fojt 	oPasswordAuthentication,
14850a69bb5SSascha Wildner 	oXAuthLocation,
1490cbfa66cSDaniel Fojt 	oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward,
15050a69bb5SSascha Wildner 	oPermitRemoteOpen,
151e9778795SPeter Avalos 	oCertificateFile, oAddKeysToAgent, oIdentityAgent,
1520cbfa66cSDaniel Fojt 	oUser, oEscapeChar, oProxyCommand,
15318de8d7fSPeter Avalos 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
15418de8d7fSPeter Avalos 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
1550cbfa66cSDaniel Fojt 	oTCPKeepAlive, oNumberOfPasswordPrompts,
15650a69bb5SSascha Wildner 	oLogFacility, oLogLevel, oLogVerbose, oCiphers, oMacs,
157e9778795SPeter Avalos 	oPubkeyAuthentication,
15818de8d7fSPeter Avalos 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
15918de8d7fSPeter Avalos 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
160664f4763Szrj 	oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider,
16118de8d7fSPeter Avalos 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
16218de8d7fSPeter Avalos 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
16318de8d7fSPeter Avalos 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
16418de8d7fSPeter Avalos 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
165664f4763Szrj 	oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
166856ea928SPeter Avalos 	oHashKnownHosts,
167ce74bacaSMatthew Dillon 	oTunnel, oTunnelDevice,
168ce74bacaSMatthew Dillon 	oLocalCommand, oPermitLocalCommand, oRemoteCommand,
169e9778795SPeter Avalos 	oVisualHostKey,
17050a69bb5SSascha Wildner 	oKexAlgorithms, oIPQoS, oRequestTTY, oSessionType, oStdinNull,
17150a69bb5SSascha Wildner 	oForkAfterAuthentication, oIgnoreUnknown, oProxyUseFdpass,
17236e94dc5SPeter Avalos 	oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
17336e94dc5SPeter Avalos 	oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
174e9778795SPeter Avalos 	oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
17550a69bb5SSascha Wildner 	oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
17650a69bb5SSascha Wildner 	oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
177*ee116499SAntonio Huete Jimenez 	oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize,
178ce74bacaSMatthew Dillon 	oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
17918de8d7fSPeter Avalos } OpCodes;
18018de8d7fSPeter Avalos 
18118de8d7fSPeter Avalos /* Textual representations of the tokens. */
18218de8d7fSPeter Avalos 
18318de8d7fSPeter Avalos static struct {
18418de8d7fSPeter Avalos 	const char *name;
18518de8d7fSPeter Avalos 	OpCodes opcode;
18618de8d7fSPeter Avalos } keywords[] = {
187ce74bacaSMatthew Dillon 	/* Deprecated options */
188ce74bacaSMatthew Dillon 	{ "protocol", oIgnore }, /* NB. silently ignored */
189ce74bacaSMatthew Dillon 	{ "cipher", oDeprecated },
190ce74bacaSMatthew Dillon 	{ "fallbacktorsh", oDeprecated },
191ce74bacaSMatthew Dillon 	{ "globalknownhostsfile2", oDeprecated },
192ce74bacaSMatthew Dillon 	{ "rhostsauthentication", oDeprecated },
193ce74bacaSMatthew Dillon 	{ "userknownhostsfile2", oDeprecated },
194ce74bacaSMatthew Dillon 	{ "useroaming", oDeprecated },
195ce74bacaSMatthew Dillon 	{ "usersh", oDeprecated },
196664f4763Szrj 	{ "useprivilegedport", oDeprecated },
197ce74bacaSMatthew Dillon 
198ce74bacaSMatthew Dillon 	/* Unsupported options */
199ce74bacaSMatthew Dillon 	{ "afstokenpassing", oUnsupported },
200ce74bacaSMatthew Dillon 	{ "kerberosauthentication", oUnsupported },
201ce74bacaSMatthew Dillon 	{ "kerberostgtpassing", oUnsupported },
2020cbfa66cSDaniel Fojt 	{ "rsaauthentication", oUnsupported },
2030cbfa66cSDaniel Fojt 	{ "rhostsrsaauthentication", oUnsupported },
2040cbfa66cSDaniel Fojt 	{ "compressionlevel", oUnsupported },
205ce74bacaSMatthew Dillon 
206ce74bacaSMatthew Dillon 	/* Sometimes-unsupported options */
207ce74bacaSMatthew Dillon #if defined(GSSAPI)
208ce74bacaSMatthew Dillon 	{ "gssapiauthentication", oGssAuthentication },
209ce74bacaSMatthew Dillon 	{ "gssapidelegatecredentials", oGssDelegateCreds },
210ce74bacaSMatthew Dillon # else
211ce74bacaSMatthew Dillon 	{ "gssapiauthentication", oUnsupported },
212ce74bacaSMatthew Dillon 	{ "gssapidelegatecredentials", oUnsupported },
213ce74bacaSMatthew Dillon #endif
214ce74bacaSMatthew Dillon #ifdef ENABLE_PKCS11
215ce74bacaSMatthew Dillon 	{ "pkcs11provider", oPKCS11Provider },
216664f4763Szrj 	{ "smartcarddevice", oPKCS11Provider },
217ce74bacaSMatthew Dillon # else
218ce74bacaSMatthew Dillon 	{ "smartcarddevice", oUnsupported },
219ce74bacaSMatthew Dillon 	{ "pkcs11provider", oUnsupported },
220ce74bacaSMatthew Dillon #endif
221ce74bacaSMatthew Dillon 
22218de8d7fSPeter Avalos 	{ "forwardagent", oForwardAgent },
22318de8d7fSPeter Avalos 	{ "forwardx11", oForwardX11 },
22418de8d7fSPeter Avalos 	{ "forwardx11trusted", oForwardX11Trusted },
225856ea928SPeter Avalos 	{ "forwardx11timeout", oForwardX11Timeout },
22618de8d7fSPeter Avalos 	{ "exitonforwardfailure", oExitOnForwardFailure },
22718de8d7fSPeter Avalos 	{ "xauthlocation", oXAuthLocation },
22818de8d7fSPeter Avalos 	{ "gatewayports", oGatewayPorts },
22918de8d7fSPeter Avalos 	{ "passwordauthentication", oPasswordAuthentication },
23018de8d7fSPeter Avalos 	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
23118de8d7fSPeter Avalos 	{ "kbdinteractivedevices", oKbdInteractiveDevices },
23250a69bb5SSascha Wildner 	{ "challengeresponseauthentication", oKbdInteractiveAuthentication }, /* alias */
23350a69bb5SSascha Wildner 	{ "skeyauthentication", oKbdInteractiveAuthentication }, /* alias */
23450a69bb5SSascha Wildner 	{ "tisauthentication", oKbdInteractiveAuthentication },  /* alias */
23518de8d7fSPeter Avalos 	{ "pubkeyauthentication", oPubkeyAuthentication },
23618de8d7fSPeter Avalos 	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
23718de8d7fSPeter Avalos 	{ "hostbasedauthentication", oHostbasedAuthentication },
23818de8d7fSPeter Avalos 	{ "identityfile", oIdentityFile },
239cb5eb4f1SPeter Avalos 	{ "identityfile2", oIdentityFile },			/* obsolete */
24018de8d7fSPeter Avalos 	{ "identitiesonly", oIdentitiesOnly },
241e9778795SPeter Avalos 	{ "certificatefile", oCertificateFile },
242e9778795SPeter Avalos 	{ "addkeystoagent", oAddKeysToAgent },
243e9778795SPeter Avalos 	{ "identityagent", oIdentityAgent },
2440cbfa66cSDaniel Fojt 	{ "hostname", oHostname },
24518de8d7fSPeter Avalos 	{ "hostkeyalias", oHostKeyAlias },
24618de8d7fSPeter Avalos 	{ "proxycommand", oProxyCommand },
24718de8d7fSPeter Avalos 	{ "port", oPort },
24818de8d7fSPeter Avalos 	{ "ciphers", oCiphers },
24918de8d7fSPeter Avalos 	{ "macs", oMacs },
25018de8d7fSPeter Avalos 	{ "remoteforward", oRemoteForward },
25118de8d7fSPeter Avalos 	{ "localforward", oLocalForward },
25250a69bb5SSascha Wildner 	{ "permitremoteopen", oPermitRemoteOpen },
25318de8d7fSPeter Avalos 	{ "user", oUser },
25418de8d7fSPeter Avalos 	{ "host", oHost },
25536e94dc5SPeter Avalos 	{ "match", oMatch },
25618de8d7fSPeter Avalos 	{ "escapechar", oEscapeChar },
25718de8d7fSPeter Avalos 	{ "globalknownhostsfile", oGlobalKnownHostsFile },
258cb5eb4f1SPeter Avalos 	{ "userknownhostsfile", oUserKnownHostsFile },
25918de8d7fSPeter Avalos 	{ "connectionattempts", oConnectionAttempts },
26018de8d7fSPeter Avalos 	{ "batchmode", oBatchMode },
26118de8d7fSPeter Avalos 	{ "checkhostip", oCheckHostIP },
26218de8d7fSPeter Avalos 	{ "stricthostkeychecking", oStrictHostKeyChecking },
26318de8d7fSPeter Avalos 	{ "compression", oCompression },
26418de8d7fSPeter Avalos 	{ "tcpkeepalive", oTCPKeepAlive },
26518de8d7fSPeter Avalos 	{ "keepalive", oTCPKeepAlive },				/* obsolete */
26618de8d7fSPeter Avalos 	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
267ce74bacaSMatthew Dillon 	{ "syslogfacility", oLogFacility },
26818de8d7fSPeter Avalos 	{ "loglevel", oLogLevel },
26950a69bb5SSascha Wildner 	{ "logverbose", oLogVerbose },
27018de8d7fSPeter Avalos 	{ "dynamicforward", oDynamicForward },
27118de8d7fSPeter Avalos 	{ "preferredauthentications", oPreferredAuthentications },
27218de8d7fSPeter Avalos 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
273664f4763Szrj 	{ "casignaturealgorithms", oCASignatureAlgorithms },
27418de8d7fSPeter Avalos 	{ "bindaddress", oBindAddress },
275664f4763Szrj 	{ "bindinterface", oBindInterface },
27618de8d7fSPeter Avalos 	{ "clearallforwardings", oClearAllForwardings },
27718de8d7fSPeter Avalos 	{ "enablesshkeysign", oEnableSSHKeysign },
27818de8d7fSPeter Avalos 	{ "verifyhostkeydns", oVerifyHostKeyDNS },
27918de8d7fSPeter Avalos 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
28018de8d7fSPeter Avalos 	{ "rekeylimit", oRekeyLimit },
28118de8d7fSPeter Avalos 	{ "connecttimeout", oConnectTimeout },
28218de8d7fSPeter Avalos 	{ "addressfamily", oAddressFamily },
28318de8d7fSPeter Avalos 	{ "serveraliveinterval", oServerAliveInterval },
28418de8d7fSPeter Avalos 	{ "serveralivecountmax", oServerAliveCountMax },
28518de8d7fSPeter Avalos 	{ "sendenv", oSendEnv },
286664f4763Szrj 	{ "setenv", oSetEnv },
28718de8d7fSPeter Avalos 	{ "controlpath", oControlPath },
28818de8d7fSPeter Avalos 	{ "controlmaster", oControlMaster },
289856ea928SPeter Avalos 	{ "controlpersist", oControlPersist },
29018de8d7fSPeter Avalos 	{ "hashknownhosts", oHashKnownHosts },
291e9778795SPeter Avalos 	{ "include", oInclude },
29218de8d7fSPeter Avalos 	{ "tunnel", oTunnel },
29318de8d7fSPeter Avalos 	{ "tunneldevice", oTunnelDevice },
29418de8d7fSPeter Avalos 	{ "localcommand", oLocalCommand },
29518de8d7fSPeter Avalos 	{ "permitlocalcommand", oPermitLocalCommand },
296ce74bacaSMatthew Dillon 	{ "remotecommand", oRemoteCommand },
29718de8d7fSPeter Avalos 	{ "visualhostkey", oVisualHostKey },
2989f304aafSPeter Avalos 	{ "kexalgorithms", oKexAlgorithms },
2999f304aafSPeter Avalos 	{ "ipqos", oIPQoS },
3001c188a7fSPeter Avalos 	{ "requesttty", oRequestTTY },
30150a69bb5SSascha Wildner 	{ "sessiontype", oSessionType },
30250a69bb5SSascha Wildner 	{ "stdinnull", oStdinNull },
30350a69bb5SSascha Wildner 	{ "forkafterauthentication", oForkAfterAuthentication },
30436e94dc5SPeter Avalos 	{ "proxyusefdpass", oProxyUseFdpass },
30536e94dc5SPeter Avalos 	{ "canonicaldomains", oCanonicalDomains },
30636e94dc5SPeter Avalos 	{ "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
30736e94dc5SPeter Avalos 	{ "canonicalizehostname", oCanonicalizeHostname },
30836e94dc5SPeter Avalos 	{ "canonicalizemaxdots", oCanonicalizeMaxDots },
30936e94dc5SPeter Avalos 	{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
31036e94dc5SPeter Avalos 	{ "streamlocalbindmask", oStreamLocalBindMask },
31136e94dc5SPeter Avalos 	{ "streamlocalbindunlink", oStreamLocalBindUnlink },
312e9778795SPeter Avalos 	{ "revokedhostkeys", oRevokedHostKeys },
313e9778795SPeter Avalos 	{ "fingerprinthash", oFingerprintHash },
314e9778795SPeter Avalos 	{ "updatehostkeys", oUpdateHostkeys },
31550a69bb5SSascha Wildner 	{ "hostbasedacceptedalgorithms", oHostbasedAcceptedAlgorithms },
31650a69bb5SSascha Wildner 	{ "hostbasedkeytypes", oHostbasedAcceptedAlgorithms }, /* obsolete */
31750a69bb5SSascha Wildner 	{ "pubkeyacceptedalgorithms", oPubkeyAcceptedAlgorithms },
31850a69bb5SSascha Wildner 	{ "pubkeyacceptedkeytypes", oPubkeyAcceptedAlgorithms }, /* obsolete */
31936e94dc5SPeter Avalos 	{ "ignoreunknown", oIgnoreUnknown },
320e9778795SPeter Avalos 	{ "proxyjump", oProxyJump },
3210cbfa66cSDaniel Fojt 	{ "securitykeyprovider", oSecurityKeyProvider },
32250a69bb5SSascha Wildner 	{ "knownhostscommand", oKnownHostsCommand },
323*ee116499SAntonio Huete Jimenez 	{ "requiredrsasize", oRequiredRSASize },
324cb5eb4f1SPeter Avalos 
32518de8d7fSPeter Avalos 	{ NULL, oBadOption }
32618de8d7fSPeter Avalos };
32718de8d7fSPeter Avalos 
32850a69bb5SSascha Wildner static const char *lookup_opcode_name(OpCodes code);
3290cbfa66cSDaniel Fojt 
3300cbfa66cSDaniel Fojt const char *
kex_default_pk_alg(void)3310cbfa66cSDaniel Fojt kex_default_pk_alg(void)
3320cbfa66cSDaniel Fojt {
33350a69bb5SSascha Wildner 	static char *pkalgs;
33450a69bb5SSascha Wildner 
33550a69bb5SSascha Wildner 	if (pkalgs == NULL) {
33650a69bb5SSascha Wildner 		char *all_key;
33750a69bb5SSascha Wildner 
33850a69bb5SSascha Wildner 		all_key = sshkey_alg_list(0, 0, 1, ',');
33950a69bb5SSascha Wildner 		pkalgs = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
34050a69bb5SSascha Wildner 		free(all_key);
34150a69bb5SSascha Wildner 	}
34250a69bb5SSascha Wildner 	return pkalgs;
3430cbfa66cSDaniel Fojt }
3440cbfa66cSDaniel Fojt 
3450cbfa66cSDaniel Fojt char *
ssh_connection_hash(const char * thishost,const char * host,const char * portstr,const char * user)3460cbfa66cSDaniel Fojt ssh_connection_hash(const char *thishost, const char *host, const char *portstr,
3470cbfa66cSDaniel Fojt     const char *user)
3480cbfa66cSDaniel Fojt {
3490cbfa66cSDaniel Fojt 	struct ssh_digest_ctx *md;
3500cbfa66cSDaniel Fojt 	u_char conn_hash[SSH_DIGEST_MAX_LENGTH];
3510cbfa66cSDaniel Fojt 
3520cbfa66cSDaniel Fojt 	if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL ||
3530cbfa66cSDaniel Fojt 	    ssh_digest_update(md, thishost, strlen(thishost)) < 0 ||
3540cbfa66cSDaniel Fojt 	    ssh_digest_update(md, host, strlen(host)) < 0 ||
3550cbfa66cSDaniel Fojt 	    ssh_digest_update(md, portstr, strlen(portstr)) < 0 ||
3560cbfa66cSDaniel Fojt 	    ssh_digest_update(md, user, strlen(user)) < 0 ||
3570cbfa66cSDaniel Fojt 	    ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0)
35850a69bb5SSascha Wildner 		fatal_f("mux digest failed");
3590cbfa66cSDaniel Fojt 	ssh_digest_free(md);
3600cbfa66cSDaniel Fojt 	return tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1));
3610cbfa66cSDaniel Fojt }
3620cbfa66cSDaniel Fojt 
36318de8d7fSPeter Avalos /*
36418de8d7fSPeter Avalos  * Adds a local TCP/IP port forward to options.  Never returns if there is an
36518de8d7fSPeter Avalos  * error.
36618de8d7fSPeter Avalos  */
36718de8d7fSPeter Avalos 
36818de8d7fSPeter Avalos void
add_local_forward(Options * options,const struct Forward * newfwd)36936e94dc5SPeter Avalos add_local_forward(Options *options, const struct Forward *newfwd)
37018de8d7fSPeter Avalos {
37136e94dc5SPeter Avalos 	struct Forward *fwd;
372e9778795SPeter Avalos 	int i;
373e9778795SPeter Avalos 
374e9778795SPeter Avalos 	/* Don't add duplicates */
375e9778795SPeter Avalos 	for (i = 0; i < options->num_local_forwards; i++) {
376e9778795SPeter Avalos 		if (forward_equals(newfwd, options->local_forwards + i))
377e9778795SPeter Avalos 			return;
378e9778795SPeter Avalos 	}
379e9778795SPeter Avalos 	options->local_forwards = xreallocarray(options->local_forwards,
380856ea928SPeter Avalos 	    options->num_local_forwards + 1,
381856ea928SPeter Avalos 	    sizeof(*options->local_forwards));
38218de8d7fSPeter Avalos 	fwd = &options->local_forwards[options->num_local_forwards++];
38318de8d7fSPeter Avalos 
384cb5eb4f1SPeter Avalos 	fwd->listen_host = newfwd->listen_host;
38518de8d7fSPeter Avalos 	fwd->listen_port = newfwd->listen_port;
38636e94dc5SPeter Avalos 	fwd->listen_path = newfwd->listen_path;
387cb5eb4f1SPeter Avalos 	fwd->connect_host = newfwd->connect_host;
38818de8d7fSPeter Avalos 	fwd->connect_port = newfwd->connect_port;
38936e94dc5SPeter Avalos 	fwd->connect_path = newfwd->connect_path;
39018de8d7fSPeter Avalos }
39118de8d7fSPeter Avalos 
39218de8d7fSPeter Avalos /*
39318de8d7fSPeter Avalos  * Adds a remote TCP/IP port forward to options.  Never returns if there is
39418de8d7fSPeter Avalos  * an error.
39518de8d7fSPeter Avalos  */
39618de8d7fSPeter Avalos 
39718de8d7fSPeter Avalos void
add_remote_forward(Options * options,const struct Forward * newfwd)39836e94dc5SPeter Avalos add_remote_forward(Options *options, const struct Forward *newfwd)
39918de8d7fSPeter Avalos {
40036e94dc5SPeter Avalos 	struct Forward *fwd;
401e9778795SPeter Avalos 	int i;
402856ea928SPeter Avalos 
403e9778795SPeter Avalos 	/* Don't add duplicates */
404e9778795SPeter Avalos 	for (i = 0; i < options->num_remote_forwards; i++) {
405e9778795SPeter Avalos 		if (forward_equals(newfwd, options->remote_forwards + i))
406e9778795SPeter Avalos 			return;
407e9778795SPeter Avalos 	}
408e9778795SPeter Avalos 	options->remote_forwards = xreallocarray(options->remote_forwards,
409856ea928SPeter Avalos 	    options->num_remote_forwards + 1,
410856ea928SPeter Avalos 	    sizeof(*options->remote_forwards));
41118de8d7fSPeter Avalos 	fwd = &options->remote_forwards[options->num_remote_forwards++];
41218de8d7fSPeter Avalos 
413cb5eb4f1SPeter Avalos 	fwd->listen_host = newfwd->listen_host;
41418de8d7fSPeter Avalos 	fwd->listen_port = newfwd->listen_port;
41536e94dc5SPeter Avalos 	fwd->listen_path = newfwd->listen_path;
416cb5eb4f1SPeter Avalos 	fwd->connect_host = newfwd->connect_host;
41718de8d7fSPeter Avalos 	fwd->connect_port = newfwd->connect_port;
41836e94dc5SPeter Avalos 	fwd->connect_path = newfwd->connect_path;
41999e85e0dSPeter Avalos 	fwd->handle = newfwd->handle;
420856ea928SPeter Avalos 	fwd->allocated_port = 0;
42118de8d7fSPeter Avalos }
42218de8d7fSPeter Avalos 
42318de8d7fSPeter Avalos static void
clear_forwardings(Options * options)42418de8d7fSPeter Avalos clear_forwardings(Options *options)
42518de8d7fSPeter Avalos {
42618de8d7fSPeter Avalos 	int i;
42718de8d7fSPeter Avalos 
42818de8d7fSPeter Avalos 	for (i = 0; i < options->num_local_forwards; i++) {
42936e94dc5SPeter Avalos 		free(options->local_forwards[i].listen_host);
43036e94dc5SPeter Avalos 		free(options->local_forwards[i].listen_path);
43136e94dc5SPeter Avalos 		free(options->local_forwards[i].connect_host);
43236e94dc5SPeter Avalos 		free(options->local_forwards[i].connect_path);
43318de8d7fSPeter Avalos 	}
434856ea928SPeter Avalos 	if (options->num_local_forwards > 0) {
43536e94dc5SPeter Avalos 		free(options->local_forwards);
436856ea928SPeter Avalos 		options->local_forwards = NULL;
437856ea928SPeter Avalos 	}
43818de8d7fSPeter Avalos 	options->num_local_forwards = 0;
43918de8d7fSPeter Avalos 	for (i = 0; i < options->num_remote_forwards; i++) {
44036e94dc5SPeter Avalos 		free(options->remote_forwards[i].listen_host);
44136e94dc5SPeter Avalos 		free(options->remote_forwards[i].listen_path);
44236e94dc5SPeter Avalos 		free(options->remote_forwards[i].connect_host);
44336e94dc5SPeter Avalos 		free(options->remote_forwards[i].connect_path);
44418de8d7fSPeter Avalos 	}
445856ea928SPeter Avalos 	if (options->num_remote_forwards > 0) {
44636e94dc5SPeter Avalos 		free(options->remote_forwards);
447856ea928SPeter Avalos 		options->remote_forwards = NULL;
448856ea928SPeter Avalos 	}
44918de8d7fSPeter Avalos 	options->num_remote_forwards = 0;
45018de8d7fSPeter Avalos 	options->tun_open = SSH_TUNMODE_NO;
45118de8d7fSPeter Avalos }
45218de8d7fSPeter Avalos 
45336e94dc5SPeter Avalos void
add_certificate_file(Options * options,const char * path,int userprovided)454e9778795SPeter Avalos add_certificate_file(Options *options, const char *path, int userprovided)
455e9778795SPeter Avalos {
456e9778795SPeter Avalos 	int i;
457e9778795SPeter Avalos 
458e9778795SPeter Avalos 	if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
459e9778795SPeter Avalos 		fatal("Too many certificate files specified (max %d)",
460e9778795SPeter Avalos 		    SSH_MAX_CERTIFICATE_FILES);
461e9778795SPeter Avalos 
462e9778795SPeter Avalos 	/* Avoid registering duplicates */
463e9778795SPeter Avalos 	for (i = 0; i < options->num_certificate_files; i++) {
464e9778795SPeter Avalos 		if (options->certificate_file_userprovided[i] == userprovided &&
465e9778795SPeter Avalos 		    strcmp(options->certificate_files[i], path) == 0) {
46650a69bb5SSascha Wildner 			debug2_f("ignoring duplicate key %s", path);
467e9778795SPeter Avalos 			return;
468e9778795SPeter Avalos 		}
469e9778795SPeter Avalos 	}
470e9778795SPeter Avalos 
471e9778795SPeter Avalos 	options->certificate_file_userprovided[options->num_certificate_files] =
472e9778795SPeter Avalos 	    userprovided;
473e9778795SPeter Avalos 	options->certificate_files[options->num_certificate_files++] =
474e9778795SPeter Avalos 	    xstrdup(path);
475e9778795SPeter Avalos }
476e9778795SPeter Avalos 
477e9778795SPeter Avalos void
add_identity_file(Options * options,const char * dir,const char * filename,int userprovided)47836e94dc5SPeter Avalos add_identity_file(Options *options, const char *dir, const char *filename,
47936e94dc5SPeter Avalos     int userprovided)
48036e94dc5SPeter Avalos {
48136e94dc5SPeter Avalos 	char *path;
48236e94dc5SPeter Avalos 	int i;
48336e94dc5SPeter Avalos 
48436e94dc5SPeter Avalos 	if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
48536e94dc5SPeter Avalos 		fatal("Too many identity files specified (max %d)",
48636e94dc5SPeter Avalos 		    SSH_MAX_IDENTITY_FILES);
48736e94dc5SPeter Avalos 
48836e94dc5SPeter Avalos 	if (dir == NULL) /* no dir, filename is absolute */
48936e94dc5SPeter Avalos 		path = xstrdup(filename);
490ce74bacaSMatthew Dillon 	else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX)
491ce74bacaSMatthew Dillon 		fatal("Identity file path %s too long", path);
49236e94dc5SPeter Avalos 
49336e94dc5SPeter Avalos 	/* Avoid registering duplicates */
49436e94dc5SPeter Avalos 	for (i = 0; i < options->num_identity_files; i++) {
49536e94dc5SPeter Avalos 		if (options->identity_file_userprovided[i] == userprovided &&
49636e94dc5SPeter Avalos 		    strcmp(options->identity_files[i], path) == 0) {
49750a69bb5SSascha Wildner 			debug2_f("ignoring duplicate key %s", path);
49836e94dc5SPeter Avalos 			free(path);
49936e94dc5SPeter Avalos 			return;
50036e94dc5SPeter Avalos 		}
50136e94dc5SPeter Avalos 	}
50236e94dc5SPeter Avalos 
50336e94dc5SPeter Avalos 	options->identity_file_userprovided[options->num_identity_files] =
50436e94dc5SPeter Avalos 	    userprovided;
50536e94dc5SPeter Avalos 	options->identity_files[options->num_identity_files++] = path;
50636e94dc5SPeter Avalos }
50736e94dc5SPeter Avalos 
50836e94dc5SPeter Avalos int
default_ssh_port(void)50936e94dc5SPeter Avalos default_ssh_port(void)
51036e94dc5SPeter Avalos {
51136e94dc5SPeter Avalos 	static int port;
51236e94dc5SPeter Avalos 	struct servent *sp;
51336e94dc5SPeter Avalos 
51436e94dc5SPeter Avalos 	if (port == 0) {
51536e94dc5SPeter Avalos 		sp = getservbyname(SSH_SERVICE_NAME, "tcp");
51636e94dc5SPeter Avalos 		port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
51736e94dc5SPeter Avalos 	}
51836e94dc5SPeter Avalos 	return port;
51936e94dc5SPeter Avalos }
52036e94dc5SPeter Avalos 
52136e94dc5SPeter Avalos /*
52236e94dc5SPeter Avalos  * Execute a command in a shell.
52336e94dc5SPeter Avalos  * Return its exit status or -1 on abnormal exit.
52436e94dc5SPeter Avalos  */
52536e94dc5SPeter Avalos static int
execute_in_shell(const char * cmd)52636e94dc5SPeter Avalos execute_in_shell(const char *cmd)
52736e94dc5SPeter Avalos {
528e9778795SPeter Avalos 	char *shell;
52936e94dc5SPeter Avalos 	pid_t pid;
53050a69bb5SSascha Wildner 	int status;
53136e94dc5SPeter Avalos 
53236e94dc5SPeter Avalos 	if ((shell = getenv("SHELL")) == NULL)
53336e94dc5SPeter Avalos 		shell = _PATH_BSHELL;
53436e94dc5SPeter Avalos 
5350cbfa66cSDaniel Fojt 	if (access(shell, X_OK) == -1) {
5360cbfa66cSDaniel Fojt 		fatal("Shell \"%s\" is not executable: %s",
5370cbfa66cSDaniel Fojt 		    shell, strerror(errno));
5380cbfa66cSDaniel Fojt 	}
5390cbfa66cSDaniel Fojt 
54036e94dc5SPeter Avalos 	debug("Executing command: '%.500s'", cmd);
54136e94dc5SPeter Avalos 
54236e94dc5SPeter Avalos 	/* Fork and execute the command. */
54336e94dc5SPeter Avalos 	if ((pid = fork()) == 0) {
54436e94dc5SPeter Avalos 		char *argv[4];
54536e94dc5SPeter Avalos 
54650a69bb5SSascha Wildner 		if (stdfd_devnull(1, 1, 0) == -1)
54750a69bb5SSascha Wildner 			fatal_f("stdfd_devnull failed");
54836e94dc5SPeter Avalos 		closefrom(STDERR_FILENO + 1);
54936e94dc5SPeter Avalos 
55036e94dc5SPeter Avalos 		argv[0] = shell;
55136e94dc5SPeter Avalos 		argv[1] = "-c";
552e9778795SPeter Avalos 		argv[2] = xstrdup(cmd);
55336e94dc5SPeter Avalos 		argv[3] = NULL;
55436e94dc5SPeter Avalos 
55536e94dc5SPeter Avalos 		execv(argv[0], argv);
55636e94dc5SPeter Avalos 		error("Unable to execute '%.100s': %s", cmd, strerror(errno));
55736e94dc5SPeter Avalos 		/* Die with signal to make this error apparent to parent. */
5580cbfa66cSDaniel Fojt 		ssh_signal(SIGTERM, SIG_DFL);
55936e94dc5SPeter Avalos 		kill(getpid(), SIGTERM);
56036e94dc5SPeter Avalos 		_exit(1);
56136e94dc5SPeter Avalos 	}
56236e94dc5SPeter Avalos 	/* Parent. */
5630cbfa66cSDaniel Fojt 	if (pid == -1)
56450a69bb5SSascha Wildner 		fatal_f("fork: %.100s", strerror(errno));
56536e94dc5SPeter Avalos 
56636e94dc5SPeter Avalos 	while (waitpid(pid, &status, 0) == -1) {
56736e94dc5SPeter Avalos 		if (errno != EINTR && errno != EAGAIN)
56850a69bb5SSascha Wildner 			fatal_f("waitpid: %s", strerror(errno));
56936e94dc5SPeter Avalos 	}
57036e94dc5SPeter Avalos 	if (!WIFEXITED(status)) {
57136e94dc5SPeter Avalos 		error("command '%.100s' exited abnormally", cmd);
57236e94dc5SPeter Avalos 		return -1;
57336e94dc5SPeter Avalos 	}
57436e94dc5SPeter Avalos 	debug3("command returned status %d", WEXITSTATUS(status));
57536e94dc5SPeter Avalos 	return WEXITSTATUS(status);
57636e94dc5SPeter Avalos }
57736e94dc5SPeter Avalos 
57836e94dc5SPeter Avalos /*
57936e94dc5SPeter Avalos  * Parse and execute a Match directive.
58036e94dc5SPeter Avalos  */
58136e94dc5SPeter Avalos static int
match_cfg_line(Options * options,char ** condition,struct passwd * pw,const char * host_arg,const char * original_host,int final_pass,int * want_final_pass,const char * filename,int linenum)58236e94dc5SPeter Avalos match_cfg_line(Options *options, char **condition, struct passwd *pw,
583664f4763Szrj     const char *host_arg, const char *original_host, int final_pass,
584664f4763Szrj     int *want_final_pass, const char *filename, int linenum)
58536e94dc5SPeter Avalos {
586e9778795SPeter Avalos 	char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
58736e94dc5SPeter Avalos 	const char *ruser;
588e9778795SPeter Avalos 	int r, port, this_result, result = 1, attributes = 0, negate;
58936e94dc5SPeter Avalos 	char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
590664f4763Szrj 	char uidstr[32];
59136e94dc5SPeter Avalos 
59236e94dc5SPeter Avalos 	/*
59336e94dc5SPeter Avalos 	 * Configuration is likely to be incomplete at this point so we
59436e94dc5SPeter Avalos 	 * must be prepared to use default values.
59536e94dc5SPeter Avalos 	 */
59636e94dc5SPeter Avalos 	port = options->port <= 0 ? default_ssh_port() : options->port;
59736e94dc5SPeter Avalos 	ruser = options->user == NULL ? pw->pw_name : options->user;
598664f4763Szrj 	if (final_pass) {
599e9778795SPeter Avalos 		host = xstrdup(options->hostname);
600e9778795SPeter Avalos 	} else if (options->hostname != NULL) {
60136e94dc5SPeter Avalos 		/* NB. Please keep in sync with ssh.c:main() */
60236e94dc5SPeter Avalos 		host = percent_expand(options->hostname,
60336e94dc5SPeter Avalos 		    "h", host_arg, (char *)NULL);
604e9778795SPeter Avalos 	} else {
60536e94dc5SPeter Avalos 		host = xstrdup(host_arg);
606e9778795SPeter Avalos 	}
60736e94dc5SPeter Avalos 
608e9778795SPeter Avalos 	debug2("checking match for '%s' host %s originally %s",
609e9778795SPeter Avalos 	    cp, host, original_host);
610e9778795SPeter Avalos 	while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
61150a69bb5SSascha Wildner 		/* Terminate on comment */
61250a69bb5SSascha Wildner 		if (*attrib == '#') {
61350a69bb5SSascha Wildner 			cp = NULL; /* mark all arguments consumed */
61450a69bb5SSascha Wildner 			break;
61550a69bb5SSascha Wildner 		}
61650a69bb5SSascha Wildner 		arg = criteria = NULL;
617e9778795SPeter Avalos 		this_result = 1;
618e9778795SPeter Avalos 		if ((negate = attrib[0] == '!'))
619e9778795SPeter Avalos 			attrib++;
62050a69bb5SSascha Wildner 		/* Criterion "all" has no argument and must appear alone */
62136e94dc5SPeter Avalos 		if (strcasecmp(attrib, "all") == 0) {
62250a69bb5SSascha Wildner 			if (attributes > 1 || ((arg = strdelim(&cp)) != NULL &&
62350a69bb5SSascha Wildner 			    *arg != '\0' && *arg != '#')) {
624e9778795SPeter Avalos 				error("%.200s line %d: '%s' cannot be combined "
625e9778795SPeter Avalos 				    "with other Match attributes",
626e9778795SPeter Avalos 				    filename, linenum, oattrib);
62736e94dc5SPeter Avalos 				result = -1;
62836e94dc5SPeter Avalos 				goto out;
62936e94dc5SPeter Avalos 			}
63050a69bb5SSascha Wildner 			if (arg != NULL && *arg == '#')
63150a69bb5SSascha Wildner 				cp = NULL; /* mark all arguments consumed */
632e9778795SPeter Avalos 			if (result)
633e9778795SPeter Avalos 				result = negate ? 0 : 1;
63436e94dc5SPeter Avalos 			goto out;
63536e94dc5SPeter Avalos 		}
636e9778795SPeter Avalos 		attributes++;
63750a69bb5SSascha Wildner 		/* criteria "final" and "canonical" have no argument */
638664f4763Szrj 		if (strcasecmp(attrib, "canonical") == 0 ||
639664f4763Szrj 		    strcasecmp(attrib, "final") == 0) {
640664f4763Szrj 			/*
641664f4763Szrj 			 * If the config requests "Match final" then remember
642664f4763Szrj 			 * this so we can perform a second pass later.
643664f4763Szrj 			 */
644664f4763Szrj 			if (strcasecmp(attrib, "final") == 0 &&
645664f4763Szrj 			    want_final_pass != NULL)
646664f4763Szrj 				*want_final_pass = 1;
647664f4763Szrj 			r = !!final_pass;  /* force bitmask member to boolean */
648e9778795SPeter Avalos 			if (r == (negate ? 1 : 0))
649e9778795SPeter Avalos 				this_result = result = 0;
650e9778795SPeter Avalos 			debug3("%.200s line %d: %smatched '%s'",
651e9778795SPeter Avalos 			    filename, linenum,
652e9778795SPeter Avalos 			    this_result ? "" : "not ", oattrib);
653e9778795SPeter Avalos 			continue;
654e9778795SPeter Avalos 		}
655e9778795SPeter Avalos 		/* All other criteria require an argument */
65650a69bb5SSascha Wildner 		if ((arg = strdelim(&cp)) == NULL ||
65750a69bb5SSascha Wildner 		    *arg == '\0' || *arg == '#') {
65836e94dc5SPeter Avalos 			error("Missing Match criteria for %s", attrib);
65936e94dc5SPeter Avalos 			result = -1;
66036e94dc5SPeter Avalos 			goto out;
66136e94dc5SPeter Avalos 		}
66236e94dc5SPeter Avalos 		if (strcasecmp(attrib, "host") == 0) {
663e9778795SPeter Avalos 			criteria = xstrdup(host);
664e9778795SPeter Avalos 			r = match_hostname(host, arg) == 1;
665e9778795SPeter Avalos 			if (r == (negate ? 1 : 0))
666e9778795SPeter Avalos 				this_result = result = 0;
66736e94dc5SPeter Avalos 		} else if (strcasecmp(attrib, "originalhost") == 0) {
668e9778795SPeter Avalos 			criteria = xstrdup(original_host);
669e9778795SPeter Avalos 			r = match_hostname(original_host, arg) == 1;
670e9778795SPeter Avalos 			if (r == (negate ? 1 : 0))
671e9778795SPeter Avalos 				this_result = result = 0;
67236e94dc5SPeter Avalos 		} else if (strcasecmp(attrib, "user") == 0) {
673e9778795SPeter Avalos 			criteria = xstrdup(ruser);
674e9778795SPeter Avalos 			r = match_pattern_list(ruser, arg, 0) == 1;
675e9778795SPeter Avalos 			if (r == (negate ? 1 : 0))
676e9778795SPeter Avalos 				this_result = result = 0;
67736e94dc5SPeter Avalos 		} else if (strcasecmp(attrib, "localuser") == 0) {
678e9778795SPeter Avalos 			criteria = xstrdup(pw->pw_name);
679e9778795SPeter Avalos 			r = match_pattern_list(pw->pw_name, arg, 0) == 1;
680e9778795SPeter Avalos 			if (r == (negate ? 1 : 0))
681e9778795SPeter Avalos 				this_result = result = 0;
68236e94dc5SPeter Avalos 		} else if (strcasecmp(attrib, "exec") == 0) {
68350a69bb5SSascha Wildner 			char *conn_hash_hex, *keyalias;
6840cbfa66cSDaniel Fojt 
68536e94dc5SPeter Avalos 			if (gethostname(thishost, sizeof(thishost)) == -1)
68636e94dc5SPeter Avalos 				fatal("gethostname: %s", strerror(errno));
68736e94dc5SPeter Avalos 			strlcpy(shorthost, thishost, sizeof(shorthost));
68836e94dc5SPeter Avalos 			shorthost[strcspn(thishost, ".")] = '\0';
68936e94dc5SPeter Avalos 			snprintf(portstr, sizeof(portstr), "%d", port);
690664f4763Szrj 			snprintf(uidstr, sizeof(uidstr), "%llu",
691664f4763Szrj 			    (unsigned long long)pw->pw_uid);
6920cbfa66cSDaniel Fojt 			conn_hash_hex = ssh_connection_hash(thishost, host,
6930cbfa66cSDaniel Fojt 			    portstr, ruser);
69450a69bb5SSascha Wildner 			keyalias = options->host_key_alias ?
69550a69bb5SSascha Wildner 			    options->host_key_alias : host;
69636e94dc5SPeter Avalos 
69736e94dc5SPeter Avalos 			cmd = percent_expand(arg,
6980cbfa66cSDaniel Fojt 			    "C", conn_hash_hex,
69936e94dc5SPeter Avalos 			    "L", shorthost,
70036e94dc5SPeter Avalos 			    "d", pw->pw_dir,
70136e94dc5SPeter Avalos 			    "h", host,
70250a69bb5SSascha Wildner 			    "k", keyalias,
70336e94dc5SPeter Avalos 			    "l", thishost,
704e9778795SPeter Avalos 			    "n", original_host,
70536e94dc5SPeter Avalos 			    "p", portstr,
70636e94dc5SPeter Avalos 			    "r", ruser,
70736e94dc5SPeter Avalos 			    "u", pw->pw_name,
708664f4763Szrj 			    "i", uidstr,
70936e94dc5SPeter Avalos 			    (char *)NULL);
7100cbfa66cSDaniel Fojt 			free(conn_hash_hex);
71136e94dc5SPeter Avalos 			if (result != 1) {
71236e94dc5SPeter Avalos 				/* skip execution if prior predicate failed */
713e9778795SPeter Avalos 				debug3("%.200s line %d: skipped exec "
714e9778795SPeter Avalos 				    "\"%.100s\"", filename, linenum, cmd);
715e9778795SPeter Avalos 				free(cmd);
716e9778795SPeter Avalos 				continue;
717e9778795SPeter Avalos 			}
71836e94dc5SPeter Avalos 			r = execute_in_shell(cmd);
71936e94dc5SPeter Avalos 			if (r == -1) {
72036e94dc5SPeter Avalos 				fatal("%.200s line %d: match exec "
72136e94dc5SPeter Avalos 				    "'%.100s' error", filename,
72236e94dc5SPeter Avalos 				    linenum, cmd);
72336e94dc5SPeter Avalos 			}
724e9778795SPeter Avalos 			criteria = xstrdup(cmd);
72536e94dc5SPeter Avalos 			free(cmd);
726e9778795SPeter Avalos 			/* Force exit status to boolean */
727e9778795SPeter Avalos 			r = r == 0;
728e9778795SPeter Avalos 			if (r == (negate ? 1 : 0))
729e9778795SPeter Avalos 				this_result = result = 0;
73036e94dc5SPeter Avalos 		} else {
73136e94dc5SPeter Avalos 			error("Unsupported Match attribute %s", attrib);
73236e94dc5SPeter Avalos 			result = -1;
73336e94dc5SPeter Avalos 			goto out;
73436e94dc5SPeter Avalos 		}
735e9778795SPeter Avalos 		debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
736e9778795SPeter Avalos 		    filename, linenum, this_result ? "": "not ",
737e9778795SPeter Avalos 		    oattrib, criteria);
738e9778795SPeter Avalos 		free(criteria);
73936e94dc5SPeter Avalos 	}
74036e94dc5SPeter Avalos 	if (attributes == 0) {
74136e94dc5SPeter Avalos 		error("One or more attributes required for Match");
74236e94dc5SPeter Avalos 		result = -1;
74336e94dc5SPeter Avalos 		goto out;
74436e94dc5SPeter Avalos 	}
74536e94dc5SPeter Avalos  out:
746e9778795SPeter Avalos 	if (result != -1)
747e9778795SPeter Avalos 		debug2("match %sfound", result ? "" : "not ");
748e9778795SPeter Avalos 	*condition = cp;
74936e94dc5SPeter Avalos 	free(host);
75036e94dc5SPeter Avalos 	return result;
75136e94dc5SPeter Avalos }
75236e94dc5SPeter Avalos 
753664f4763Szrj /* Remove environment variable by pattern */
75436e94dc5SPeter Avalos static void
rm_env(Options * options,const char * arg,const char * filename,int linenum)755664f4763Szrj rm_env(Options *options, const char *arg, const char *filename, int linenum)
75636e94dc5SPeter Avalos {
757*ee116499SAntonio Huete Jimenez 	u_int i, j, onum_send_env = options->num_send_env;
75836e94dc5SPeter Avalos 
759664f4763Szrj 	/* Remove an environment variable */
760664f4763Szrj 	for (i = 0; i < options->num_send_env; ) {
761*ee116499SAntonio Huete Jimenez 		if (!match_pattern(options->send_env[i], arg + 1)) {
762664f4763Szrj 			i++;
763664f4763Szrj 			continue;
76436e94dc5SPeter Avalos 		}
765664f4763Szrj 		debug3("%s line %d: removing environment %s",
766*ee116499SAntonio Huete Jimenez 		    filename, linenum, options->send_env[i]);
767664f4763Szrj 		free(options->send_env[i]);
768664f4763Szrj 		options->send_env[i] = NULL;
769664f4763Szrj 		for (j = i; j < options->num_send_env - 1; j++) {
770664f4763Szrj 			options->send_env[j] = options->send_env[j + 1];
771664f4763Szrj 			options->send_env[j + 1] = NULL;
772664f4763Szrj 		}
773664f4763Szrj 		options->num_send_env--;
774664f4763Szrj 		/* NB. don't increment i */
775664f4763Szrj 	}
77650a69bb5SSascha Wildner 	if (onum_send_env != options->num_send_env) {
77750a69bb5SSascha Wildner 		options->send_env = xrecallocarray(options->send_env,
77850a69bb5SSascha Wildner 		    onum_send_env, options->num_send_env,
77950a69bb5SSascha Wildner 		    sizeof(*options->send_env));
78050a69bb5SSascha Wildner 	}
78136e94dc5SPeter Avalos }
78236e94dc5SPeter Avalos 
78318de8d7fSPeter Avalos /*
78418de8d7fSPeter Avalos  * Returns the number of the token pointed to by cp or oBadOption.
78518de8d7fSPeter Avalos  */
78618de8d7fSPeter Avalos static OpCodes
parse_token(const char * cp,const char * filename,int linenum,const char * ignored_unknown)78736e94dc5SPeter Avalos parse_token(const char *cp, const char *filename, int linenum,
78836e94dc5SPeter Avalos     const char *ignored_unknown)
78918de8d7fSPeter Avalos {
79036e94dc5SPeter Avalos 	int i;
79118de8d7fSPeter Avalos 
79218de8d7fSPeter Avalos 	for (i = 0; keywords[i].name; i++)
79336e94dc5SPeter Avalos 		if (strcmp(cp, keywords[i].name) == 0)
79418de8d7fSPeter Avalos 			return keywords[i].opcode;
795e9778795SPeter Avalos 	if (ignored_unknown != NULL &&
796e9778795SPeter Avalos 	    match_pattern_list(cp, ignored_unknown, 1) == 1)
79736e94dc5SPeter Avalos 		return oIgnoredUnknownOption;
79818de8d7fSPeter Avalos 	error("%s: line %d: Bad configuration option: %s",
79918de8d7fSPeter Avalos 	    filename, linenum, cp);
80018de8d7fSPeter Avalos 	return oBadOption;
80118de8d7fSPeter Avalos }
80218de8d7fSPeter Avalos 
80336e94dc5SPeter Avalos /* Multistate option parsing */
80436e94dc5SPeter Avalos struct multistate {
80536e94dc5SPeter Avalos 	char *key;
80636e94dc5SPeter Avalos 	int value;
80736e94dc5SPeter Avalos };
80836e94dc5SPeter Avalos static const struct multistate multistate_flag[] = {
80936e94dc5SPeter Avalos 	{ "true",			1 },
81036e94dc5SPeter Avalos 	{ "false",			0 },
81136e94dc5SPeter Avalos 	{ "yes",			1 },
81236e94dc5SPeter Avalos 	{ "no",				0 },
81336e94dc5SPeter Avalos 	{ NULL, -1 }
81436e94dc5SPeter Avalos };
81536e94dc5SPeter Avalos static const struct multistate multistate_yesnoask[] = {
81636e94dc5SPeter Avalos 	{ "true",			1 },
81736e94dc5SPeter Avalos 	{ "false",			0 },
81836e94dc5SPeter Avalos 	{ "yes",			1 },
81936e94dc5SPeter Avalos 	{ "no",				0 },
82036e94dc5SPeter Avalos 	{ "ask",			2 },
82136e94dc5SPeter Avalos 	{ NULL, -1 }
82236e94dc5SPeter Avalos };
823ce74bacaSMatthew Dillon static const struct multistate multistate_strict_hostkey[] = {
824ce74bacaSMatthew Dillon 	{ "true",			SSH_STRICT_HOSTKEY_YES },
825ce74bacaSMatthew Dillon 	{ "false",			SSH_STRICT_HOSTKEY_OFF },
826ce74bacaSMatthew Dillon 	{ "yes",			SSH_STRICT_HOSTKEY_YES },
827ce74bacaSMatthew Dillon 	{ "no",				SSH_STRICT_HOSTKEY_OFF },
828ce74bacaSMatthew Dillon 	{ "ask",			SSH_STRICT_HOSTKEY_ASK },
829ce74bacaSMatthew Dillon 	{ "off",			SSH_STRICT_HOSTKEY_OFF },
830ce74bacaSMatthew Dillon 	{ "accept-new",			SSH_STRICT_HOSTKEY_NEW },
831ce74bacaSMatthew Dillon 	{ NULL, -1 }
832ce74bacaSMatthew Dillon };
833e9778795SPeter Avalos static const struct multistate multistate_yesnoaskconfirm[] = {
834e9778795SPeter Avalos 	{ "true",			1 },
835e9778795SPeter Avalos 	{ "false",			0 },
836e9778795SPeter Avalos 	{ "yes",			1 },
837e9778795SPeter Avalos 	{ "no",				0 },
838e9778795SPeter Avalos 	{ "ask",			2 },
839e9778795SPeter Avalos 	{ "confirm",			3 },
840e9778795SPeter Avalos 	{ NULL, -1 }
841e9778795SPeter Avalos };
84236e94dc5SPeter Avalos static const struct multistate multistate_addressfamily[] = {
84336e94dc5SPeter Avalos 	{ "inet",			AF_INET },
84436e94dc5SPeter Avalos 	{ "inet6",			AF_INET6 },
84536e94dc5SPeter Avalos 	{ "any",			AF_UNSPEC },
84636e94dc5SPeter Avalos 	{ NULL, -1 }
84736e94dc5SPeter Avalos };
84836e94dc5SPeter Avalos static const struct multistate multistate_controlmaster[] = {
84936e94dc5SPeter Avalos 	{ "true",			SSHCTL_MASTER_YES },
85036e94dc5SPeter Avalos 	{ "yes",			SSHCTL_MASTER_YES },
85136e94dc5SPeter Avalos 	{ "false",			SSHCTL_MASTER_NO },
85236e94dc5SPeter Avalos 	{ "no",				SSHCTL_MASTER_NO },
85336e94dc5SPeter Avalos 	{ "auto",			SSHCTL_MASTER_AUTO },
85436e94dc5SPeter Avalos 	{ "ask",			SSHCTL_MASTER_ASK },
85536e94dc5SPeter Avalos 	{ "autoask",			SSHCTL_MASTER_AUTO_ASK },
85636e94dc5SPeter Avalos 	{ NULL, -1 }
85736e94dc5SPeter Avalos };
85836e94dc5SPeter Avalos static const struct multistate multistate_tunnel[] = {
85936e94dc5SPeter Avalos 	{ "ethernet",			SSH_TUNMODE_ETHERNET },
86036e94dc5SPeter Avalos 	{ "point-to-point",		SSH_TUNMODE_POINTOPOINT },
86136e94dc5SPeter Avalos 	{ "true",			SSH_TUNMODE_DEFAULT },
86236e94dc5SPeter Avalos 	{ "yes",			SSH_TUNMODE_DEFAULT },
86336e94dc5SPeter Avalos 	{ "false",			SSH_TUNMODE_NO },
86436e94dc5SPeter Avalos 	{ "no",				SSH_TUNMODE_NO },
86536e94dc5SPeter Avalos 	{ NULL, -1 }
86636e94dc5SPeter Avalos };
86736e94dc5SPeter Avalos static const struct multistate multistate_requesttty[] = {
86836e94dc5SPeter Avalos 	{ "true",			REQUEST_TTY_YES },
86936e94dc5SPeter Avalos 	{ "yes",			REQUEST_TTY_YES },
87036e94dc5SPeter Avalos 	{ "false",			REQUEST_TTY_NO },
87136e94dc5SPeter Avalos 	{ "no",				REQUEST_TTY_NO },
87236e94dc5SPeter Avalos 	{ "force",			REQUEST_TTY_FORCE },
87336e94dc5SPeter Avalos 	{ "auto",			REQUEST_TTY_AUTO },
87436e94dc5SPeter Avalos 	{ NULL, -1 }
87536e94dc5SPeter Avalos };
87650a69bb5SSascha Wildner static const struct multistate multistate_sessiontype[] = {
87750a69bb5SSascha Wildner 	{ "none",			SESSION_TYPE_NONE },
87850a69bb5SSascha Wildner 	{ "subsystem",			SESSION_TYPE_SUBSYSTEM },
87950a69bb5SSascha Wildner 	{ "default",			SESSION_TYPE_DEFAULT },
88050a69bb5SSascha Wildner 	{ NULL, -1 }
88150a69bb5SSascha Wildner };
88236e94dc5SPeter Avalos static const struct multistate multistate_canonicalizehostname[] = {
88336e94dc5SPeter Avalos 	{ "true",			SSH_CANONICALISE_YES },
88436e94dc5SPeter Avalos 	{ "false",			SSH_CANONICALISE_NO },
88536e94dc5SPeter Avalos 	{ "yes",			SSH_CANONICALISE_YES },
88636e94dc5SPeter Avalos 	{ "no",				SSH_CANONICALISE_NO },
88736e94dc5SPeter Avalos 	{ "always",			SSH_CANONICALISE_ALWAYS },
88836e94dc5SPeter Avalos 	{ NULL, -1 }
88936e94dc5SPeter Avalos };
890*ee116499SAntonio Huete Jimenez static const struct multistate multistate_pubkey_auth[] = {
891*ee116499SAntonio Huete Jimenez 	{ "true",			SSH_PUBKEY_AUTH_ALL },
892*ee116499SAntonio Huete Jimenez 	{ "false",			SSH_PUBKEY_AUTH_NO },
893*ee116499SAntonio Huete Jimenez 	{ "yes",			SSH_PUBKEY_AUTH_ALL },
894*ee116499SAntonio Huete Jimenez 	{ "no",				SSH_PUBKEY_AUTH_NO },
895*ee116499SAntonio Huete Jimenez 	{ "unbound",			SSH_PUBKEY_AUTH_UNBOUND },
896*ee116499SAntonio Huete Jimenez 	{ "host-bound",			SSH_PUBKEY_AUTH_HBOUND },
897*ee116499SAntonio Huete Jimenez 	{ NULL, -1 }
898*ee116499SAntonio Huete Jimenez };
8990cbfa66cSDaniel Fojt static const struct multistate multistate_compression[] = {
9000cbfa66cSDaniel Fojt #ifdef WITH_ZLIB
9010cbfa66cSDaniel Fojt 	{ "yes",			COMP_ZLIB },
9020cbfa66cSDaniel Fojt #endif
9030cbfa66cSDaniel Fojt 	{ "no",				COMP_NONE },
9040cbfa66cSDaniel Fojt 	{ NULL, -1 }
9050cbfa66cSDaniel Fojt };
90636e94dc5SPeter Avalos 
90750a69bb5SSascha Wildner static int
parse_multistate_value(const char * arg,const char * filename,int linenum,const struct multistate * multistate_ptr)90850a69bb5SSascha Wildner parse_multistate_value(const char *arg, const char *filename, int linenum,
90950a69bb5SSascha Wildner     const struct multistate *multistate_ptr)
91050a69bb5SSascha Wildner {
91150a69bb5SSascha Wildner 	int i;
91250a69bb5SSascha Wildner 
91350a69bb5SSascha Wildner 	if (!arg || *arg == '\0') {
91450a69bb5SSascha Wildner 		error("%s line %d: missing argument.", filename, linenum);
91550a69bb5SSascha Wildner 		return -1;
91650a69bb5SSascha Wildner 	}
91750a69bb5SSascha Wildner 	for (i = 0; multistate_ptr[i].key != NULL; i++) {
91850a69bb5SSascha Wildner 		if (strcasecmp(arg, multistate_ptr[i].key) == 0)
91950a69bb5SSascha Wildner 			return multistate_ptr[i].value;
92050a69bb5SSascha Wildner 	}
92150a69bb5SSascha Wildner 	return -1;
92250a69bb5SSascha Wildner }
92350a69bb5SSascha Wildner 
92418de8d7fSPeter Avalos /*
92518de8d7fSPeter Avalos  * Processes a single option line as used in the configuration files. This
92618de8d7fSPeter Avalos  * only sets those values that have not already been set.
92718de8d7fSPeter Avalos  */
92818de8d7fSPeter Avalos int
process_config_line(Options * options,struct passwd * pw,const char * host,const char * original_host,char * line,const char * filename,int linenum,int * activep,int flags)92936e94dc5SPeter Avalos process_config_line(Options *options, struct passwd *pw, const char *host,
930e9778795SPeter Avalos     const char *original_host, char *line, const char *filename,
931e9778795SPeter Avalos     int linenum, int *activep, int flags)
932e9778795SPeter Avalos {
933e9778795SPeter Avalos 	return process_config_line_depth(options, pw, host, original_host,
934664f4763Szrj 	    line, filename, linenum, activep, flags, NULL, 0);
935e9778795SPeter Avalos }
936e9778795SPeter Avalos 
937e9778795SPeter Avalos #define WHITESPACE " \t\r\n"
938e9778795SPeter Avalos static int
process_config_line_depth(Options * options,struct passwd * pw,const char * host,const char * original_host,char * line,const char * filename,int linenum,int * activep,int flags,int * want_final_pass,int depth)939e9778795SPeter Avalos process_config_line_depth(Options *options, struct passwd *pw, const char *host,
940e9778795SPeter Avalos     const char *original_host, char *line, const char *filename,
941664f4763Szrj     int linenum, int *activep, int flags, int *want_final_pass, int depth)
94218de8d7fSPeter Avalos {
943*ee116499SAntonio Huete Jimenez 	char *str, **charptr, *endofnumber, *keyword, *arg, *arg2, *p;
94450a69bb5SSascha Wildner 	char **cpptr, ***cppptr, fwdarg[256];
94550a69bb5SSascha Wildner 	u_int i, *uintptr, uvalue, max_entries = 0;
946e9778795SPeter Avalos 	int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
947ce74bacaSMatthew Dillon 	int remotefwd, dynamicfwd;
94818de8d7fSPeter Avalos 	LogLevel *log_level_ptr;
949ce74bacaSMatthew Dillon 	SyslogFacility *log_facility_ptr;
95036e94dc5SPeter Avalos 	long long val64;
95118de8d7fSPeter Avalos 	size_t len;
95236e94dc5SPeter Avalos 	struct Forward fwd;
95336e94dc5SPeter Avalos 	const struct multistate *multistate_ptr;
95436e94dc5SPeter Avalos 	struct allowed_cname *cname;
955e9778795SPeter Avalos 	glob_t gl;
956664f4763Szrj 	const char *errstr;
95750a69bb5SSascha Wildner 	char **oav = NULL, **av;
95850a69bb5SSascha Wildner 	int oac = 0, ac;
95950a69bb5SSascha Wildner 	int ret = -1;
96036e94dc5SPeter Avalos 
96136e94dc5SPeter Avalos 	if (activep == NULL) { /* We are processing a command line directive */
96236e94dc5SPeter Avalos 		cmdline = 1;
96336e94dc5SPeter Avalos 		activep = &cmdline;
96436e94dc5SPeter Avalos 	}
96518de8d7fSPeter Avalos 
966ce74bacaSMatthew Dillon 	/* Strip trailing whitespace. Allow \f (form feed) at EOL only */
967e9778795SPeter Avalos 	if ((len = strlen(line)) == 0)
968e9778795SPeter Avalos 		return 0;
969e9778795SPeter Avalos 	for (len--; len > 0; len--) {
970ce74bacaSMatthew Dillon 		if (strchr(WHITESPACE "\f", line[len]) == NULL)
97118de8d7fSPeter Avalos 			break;
97218de8d7fSPeter Avalos 		line[len] = '\0';
97318de8d7fSPeter Avalos 	}
97418de8d7fSPeter Avalos 
97550a69bb5SSascha Wildner 	str = line;
97618de8d7fSPeter Avalos 	/* Get the keyword. (Each line is supposed to begin with a keyword). */
97750a69bb5SSascha Wildner 	if ((keyword = strdelim(&str)) == NULL)
97818de8d7fSPeter Avalos 		return 0;
97918de8d7fSPeter Avalos 	/* Ignore leading whitespace. */
98018de8d7fSPeter Avalos 	if (*keyword == '\0')
98150a69bb5SSascha Wildner 		keyword = strdelim(&str);
98218de8d7fSPeter Avalos 	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
98318de8d7fSPeter Avalos 		return 0;
98436e94dc5SPeter Avalos 	/* Match lowercase keyword */
98536e94dc5SPeter Avalos 	lowercase(keyword);
98618de8d7fSPeter Avalos 
98750a69bb5SSascha Wildner 	/* Prepare to parse remainder of line */
98850a69bb5SSascha Wildner 	if (str != NULL)
98950a69bb5SSascha Wildner 		str += strspn(str, WHITESPACE);
99050a69bb5SSascha Wildner 	if (str == NULL || *str == '\0') {
99150a69bb5SSascha Wildner 		error("%s line %d: no argument after keyword \"%s\"",
99250a69bb5SSascha Wildner 		    filename, linenum, keyword);
99350a69bb5SSascha Wildner 		return -1;
99450a69bb5SSascha Wildner 	}
99536e94dc5SPeter Avalos 	opcode = parse_token(keyword, filename, linenum,
99636e94dc5SPeter Avalos 	    options->ignored_unknown);
99750a69bb5SSascha Wildner 	if (argv_split(str, &oac, &oav, 1) != 0) {
99850a69bb5SSascha Wildner 		error("%s line %d: invalid quotes", filename, linenum);
99950a69bb5SSascha Wildner 		return -1;
100050a69bb5SSascha Wildner 	}
100150a69bb5SSascha Wildner 	ac = oac;
100250a69bb5SSascha Wildner 	av = oav;
100318de8d7fSPeter Avalos 
100418de8d7fSPeter Avalos 	switch (opcode) {
100518de8d7fSPeter Avalos 	case oBadOption:
100618de8d7fSPeter Avalos 		/* don't panic, but count bad options */
100750a69bb5SSascha Wildner 		goto out;
1008ce74bacaSMatthew Dillon 	case oIgnore:
100950a69bb5SSascha Wildner 		argv_consume(&ac);
101050a69bb5SSascha Wildner 		break;
101136e94dc5SPeter Avalos 	case oIgnoredUnknownOption:
101236e94dc5SPeter Avalos 		debug("%s line %d: Ignored unknown option \"%s\"",
101336e94dc5SPeter Avalos 		    filename, linenum, keyword);
101450a69bb5SSascha Wildner 		argv_consume(&ac);
101550a69bb5SSascha Wildner 		break;
101618de8d7fSPeter Avalos 	case oConnectTimeout:
101718de8d7fSPeter Avalos 		intptr = &options->connection_timeout;
101818de8d7fSPeter Avalos parse_time:
101950a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
102050a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
102150a69bb5SSascha Wildner 			error("%s line %d: missing time value.",
102218de8d7fSPeter Avalos 			    filename, linenum);
102350a69bb5SSascha Wildner 			goto out;
102450a69bb5SSascha Wildner 		}
1025e9778795SPeter Avalos 		if (strcmp(arg, "none") == 0)
1026e9778795SPeter Avalos 			value = -1;
102750a69bb5SSascha Wildner 		else if ((value = convtime(arg)) == -1) {
102850a69bb5SSascha Wildner 			error("%s line %d: invalid time value.",
102918de8d7fSPeter Avalos 			    filename, linenum);
103050a69bb5SSascha Wildner 			goto out;
103150a69bb5SSascha Wildner 		}
103218de8d7fSPeter Avalos 		if (*activep && *intptr == -1)
103318de8d7fSPeter Avalos 			*intptr = value;
103418de8d7fSPeter Avalos 		break;
103518de8d7fSPeter Avalos 
103618de8d7fSPeter Avalos 	case oForwardAgent:
103718de8d7fSPeter Avalos 		intptr = &options->forward_agent;
10380cbfa66cSDaniel Fojt 
103950a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
104050a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
104150a69bb5SSascha Wildner 			error("%s line %d: missing argument.",
10420cbfa66cSDaniel Fojt 			    filename, linenum);
104350a69bb5SSascha Wildner 			goto out;
104450a69bb5SSascha Wildner 		}
10450cbfa66cSDaniel Fojt 
10460cbfa66cSDaniel Fojt 		value = -1;
10470cbfa66cSDaniel Fojt 		multistate_ptr = multistate_flag;
10480cbfa66cSDaniel Fojt 		for (i = 0; multistate_ptr[i].key != NULL; i++) {
10490cbfa66cSDaniel Fojt 			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
10500cbfa66cSDaniel Fojt 				value = multistate_ptr[i].value;
10510cbfa66cSDaniel Fojt 				break;
10520cbfa66cSDaniel Fojt 			}
10530cbfa66cSDaniel Fojt 		}
10540cbfa66cSDaniel Fojt 		if (value != -1) {
10550cbfa66cSDaniel Fojt 			if (*activep && *intptr == -1)
10560cbfa66cSDaniel Fojt 				*intptr = value;
10570cbfa66cSDaniel Fojt 			break;
10580cbfa66cSDaniel Fojt 		}
10590cbfa66cSDaniel Fojt 		/* ForwardAgent wasn't 'yes' or 'no', assume a path */
10600cbfa66cSDaniel Fojt 		if (*activep && *intptr == -1)
10610cbfa66cSDaniel Fojt 			*intptr = 1;
10620cbfa66cSDaniel Fojt 
10630cbfa66cSDaniel Fojt 		charptr = &options->forward_agent_sock_path;
10640cbfa66cSDaniel Fojt 		goto parse_agent_path;
10650cbfa66cSDaniel Fojt 
10660cbfa66cSDaniel Fojt 	case oForwardX11:
10670cbfa66cSDaniel Fojt 		intptr = &options->forward_x11;
106818de8d7fSPeter Avalos  parse_flag:
106936e94dc5SPeter Avalos 		multistate_ptr = multistate_flag;
107036e94dc5SPeter Avalos  parse_multistate:
107150a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
107250a69bb5SSascha Wildner 		if ((value = parse_multistate_value(arg, filename, linenum,
107350a69bb5SSascha Wildner 		    multistate_ptr)) == -1) {
107450a69bb5SSascha Wildner 			error("%s line %d: unsupported option \"%s\".",
107536e94dc5SPeter Avalos 			    filename, linenum, arg);
107650a69bb5SSascha Wildner 			goto out;
107750a69bb5SSascha Wildner 		}
107818de8d7fSPeter Avalos 		if (*activep && *intptr == -1)
107918de8d7fSPeter Avalos 			*intptr = value;
108018de8d7fSPeter Avalos 		break;
108118de8d7fSPeter Avalos 
108218de8d7fSPeter Avalos 	case oForwardX11Trusted:
108318de8d7fSPeter Avalos 		intptr = &options->forward_x11_trusted;
108418de8d7fSPeter Avalos 		goto parse_flag;
108518de8d7fSPeter Avalos 
1086856ea928SPeter Avalos 	case oForwardX11Timeout:
1087856ea928SPeter Avalos 		intptr = &options->forward_x11_timeout;
1088856ea928SPeter Avalos 		goto parse_time;
1089856ea928SPeter Avalos 
109018de8d7fSPeter Avalos 	case oGatewayPorts:
109136e94dc5SPeter Avalos 		intptr = &options->fwd_opts.gateway_ports;
109218de8d7fSPeter Avalos 		goto parse_flag;
109318de8d7fSPeter Avalos 
109418de8d7fSPeter Avalos 	case oExitOnForwardFailure:
109518de8d7fSPeter Avalos 		intptr = &options->exit_on_forward_failure;
109618de8d7fSPeter Avalos 		goto parse_flag;
109718de8d7fSPeter Avalos 
109818de8d7fSPeter Avalos 	case oPasswordAuthentication:
109918de8d7fSPeter Avalos 		intptr = &options->password_authentication;
110018de8d7fSPeter Avalos 		goto parse_flag;
110118de8d7fSPeter Avalos 
110218de8d7fSPeter Avalos 	case oKbdInteractiveAuthentication:
110318de8d7fSPeter Avalos 		intptr = &options->kbd_interactive_authentication;
110418de8d7fSPeter Avalos 		goto parse_flag;
110518de8d7fSPeter Avalos 
110618de8d7fSPeter Avalos 	case oKbdInteractiveDevices:
110718de8d7fSPeter Avalos 		charptr = &options->kbd_interactive_devices;
110818de8d7fSPeter Avalos 		goto parse_string;
110918de8d7fSPeter Avalos 
111018de8d7fSPeter Avalos 	case oPubkeyAuthentication:
1111*ee116499SAntonio Huete Jimenez 		multistate_ptr = multistate_pubkey_auth;
111218de8d7fSPeter Avalos 		intptr = &options->pubkey_authentication;
1113*ee116499SAntonio Huete Jimenez 		goto parse_multistate;
111418de8d7fSPeter Avalos 
111518de8d7fSPeter Avalos 	case oHostbasedAuthentication:
111618de8d7fSPeter Avalos 		intptr = &options->hostbased_authentication;
111718de8d7fSPeter Avalos 		goto parse_flag;
111818de8d7fSPeter Avalos 
111918de8d7fSPeter Avalos 	case oGssAuthentication:
112018de8d7fSPeter Avalos 		intptr = &options->gss_authentication;
112118de8d7fSPeter Avalos 		goto parse_flag;
112218de8d7fSPeter Avalos 
112318de8d7fSPeter Avalos 	case oGssDelegateCreds:
112418de8d7fSPeter Avalos 		intptr = &options->gss_deleg_creds;
112518de8d7fSPeter Avalos 		goto parse_flag;
112618de8d7fSPeter Avalos 
112718de8d7fSPeter Avalos 	case oBatchMode:
112818de8d7fSPeter Avalos 		intptr = &options->batch_mode;
112918de8d7fSPeter Avalos 		goto parse_flag;
113018de8d7fSPeter Avalos 
113118de8d7fSPeter Avalos 	case oCheckHostIP:
113218de8d7fSPeter Avalos 		intptr = &options->check_host_ip;
113318de8d7fSPeter Avalos 		goto parse_flag;
113418de8d7fSPeter Avalos 
113518de8d7fSPeter Avalos 	case oVerifyHostKeyDNS:
113618de8d7fSPeter Avalos 		intptr = &options->verify_host_key_dns;
113736e94dc5SPeter Avalos 		multistate_ptr = multistate_yesnoask;
113836e94dc5SPeter Avalos 		goto parse_multistate;
113918de8d7fSPeter Avalos 
114018de8d7fSPeter Avalos 	case oStrictHostKeyChecking:
114118de8d7fSPeter Avalos 		intptr = &options->strict_host_key_checking;
1142ce74bacaSMatthew Dillon 		multistate_ptr = multistate_strict_hostkey;
114336e94dc5SPeter Avalos 		goto parse_multistate;
114418de8d7fSPeter Avalos 
114518de8d7fSPeter Avalos 	case oCompression:
114618de8d7fSPeter Avalos 		intptr = &options->compression;
11470cbfa66cSDaniel Fojt 		multistate_ptr = multistate_compression;
11480cbfa66cSDaniel Fojt 		goto parse_multistate;
114918de8d7fSPeter Avalos 
115018de8d7fSPeter Avalos 	case oTCPKeepAlive:
115118de8d7fSPeter Avalos 		intptr = &options->tcp_keep_alive;
115218de8d7fSPeter Avalos 		goto parse_flag;
115318de8d7fSPeter Avalos 
115418de8d7fSPeter Avalos 	case oNoHostAuthenticationForLocalhost:
115518de8d7fSPeter Avalos 		intptr = &options->no_host_authentication_for_localhost;
115618de8d7fSPeter Avalos 		goto parse_flag;
115718de8d7fSPeter Avalos 
115818de8d7fSPeter Avalos 	case oNumberOfPasswordPrompts:
115918de8d7fSPeter Avalos 		intptr = &options->number_of_password_prompts;
116018de8d7fSPeter Avalos 		goto parse_int;
116118de8d7fSPeter Avalos 
116218de8d7fSPeter Avalos 	case oRekeyLimit:
116350a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
116450a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
116550a69bb5SSascha Wildner 			error("%.200s line %d: Missing argument.", filename,
116636e94dc5SPeter Avalos 			    linenum);
116750a69bb5SSascha Wildner 			goto out;
116850a69bb5SSascha Wildner 		}
116936e94dc5SPeter Avalos 		if (strcmp(arg, "default") == 0) {
117036e94dc5SPeter Avalos 			val64 = 0;
117136e94dc5SPeter Avalos 		} else {
117250a69bb5SSascha Wildner 			if (scan_scaled(arg, &val64) == -1) {
117350a69bb5SSascha Wildner 				error("%.200s line %d: Bad number '%s': %s",
117436e94dc5SPeter Avalos 				    filename, linenum, arg, strerror(errno));
117550a69bb5SSascha Wildner 				goto out;
117650a69bb5SSascha Wildner 			}
117750a69bb5SSascha Wildner 			if (val64 != 0 && val64 < 16) {
117850a69bb5SSascha Wildner 				error("%.200s line %d: RekeyLimit too small",
117918de8d7fSPeter Avalos 				    filename, linenum);
118050a69bb5SSascha Wildner 				goto out;
118150a69bb5SSascha Wildner 			}
118236e94dc5SPeter Avalos 		}
118318de8d7fSPeter Avalos 		if (*activep && options->rekey_limit == -1)
1184e9778795SPeter Avalos 			options->rekey_limit = val64;
118550a69bb5SSascha Wildner 		if (ac != 0) { /* optional rekey interval present */
118650a69bb5SSascha Wildner 			if (strcmp(av[0], "none") == 0) {
118750a69bb5SSascha Wildner 				(void)argv_next(&ac, &av);	/* discard */
118836e94dc5SPeter Avalos 				break;
118936e94dc5SPeter Avalos 			}
119036e94dc5SPeter Avalos 			intptr = &options->rekey_interval;
119136e94dc5SPeter Avalos 			goto parse_time;
119236e94dc5SPeter Avalos 		}
119318de8d7fSPeter Avalos 		break;
119418de8d7fSPeter Avalos 
119518de8d7fSPeter Avalos 	case oIdentityFile:
119650a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
119750a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
119850a69bb5SSascha Wildner 			error("%.200s line %d: Missing argument.",
119950a69bb5SSascha Wildner 			    filename, linenum);
120050a69bb5SSascha Wildner 			goto out;
120150a69bb5SSascha Wildner 		}
120218de8d7fSPeter Avalos 		if (*activep) {
120318de8d7fSPeter Avalos 			intptr = &options->num_identity_files;
120450a69bb5SSascha Wildner 			if (*intptr >= SSH_MAX_IDENTITY_FILES) {
120550a69bb5SSascha Wildner 				error("%.200s line %d: Too many identity files "
120650a69bb5SSascha Wildner 				    "specified (max %d).", filename, linenum,
120750a69bb5SSascha Wildner 				    SSH_MAX_IDENTITY_FILES);
120850a69bb5SSascha Wildner 				goto out;
120950a69bb5SSascha Wildner 			}
1210e9778795SPeter Avalos 			add_identity_file(options, NULL,
1211e9778795SPeter Avalos 			    arg, flags & SSHCONF_USERCONF);
1212e9778795SPeter Avalos 		}
1213e9778795SPeter Avalos 		break;
1214e9778795SPeter Avalos 
1215e9778795SPeter Avalos 	case oCertificateFile:
121650a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
121750a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
121850a69bb5SSascha Wildner 			error("%.200s line %d: Missing argument.",
1219e9778795SPeter Avalos 			    filename, linenum);
122050a69bb5SSascha Wildner 			goto out;
122150a69bb5SSascha Wildner 		}
1222e9778795SPeter Avalos 		if (*activep) {
1223e9778795SPeter Avalos 			intptr = &options->num_certificate_files;
1224e9778795SPeter Avalos 			if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
122550a69bb5SSascha Wildner 				error("%.200s line %d: Too many certificate "
1226e9778795SPeter Avalos 				    "files specified (max %d).",
1227e9778795SPeter Avalos 				    filename, linenum,
1228e9778795SPeter Avalos 				    SSH_MAX_CERTIFICATE_FILES);
122950a69bb5SSascha Wildner 				goto out;
1230e9778795SPeter Avalos 			}
1231e9778795SPeter Avalos 			add_certificate_file(options, arg,
1232e9778795SPeter Avalos 			    flags & SSHCONF_USERCONF);
123318de8d7fSPeter Avalos 		}
123418de8d7fSPeter Avalos 		break;
123518de8d7fSPeter Avalos 
123618de8d7fSPeter Avalos 	case oXAuthLocation:
123718de8d7fSPeter Avalos 		charptr=&options->xauth_location;
123818de8d7fSPeter Avalos 		goto parse_string;
123918de8d7fSPeter Avalos 
124018de8d7fSPeter Avalos 	case oUser:
124118de8d7fSPeter Avalos 		charptr = &options->user;
124218de8d7fSPeter Avalos parse_string:
124350a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
124450a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
124550a69bb5SSascha Wildner 			error("%.200s line %d: Missing argument.",
12461c188a7fSPeter Avalos 			    filename, linenum);
124750a69bb5SSascha Wildner 			goto out;
124850a69bb5SSascha Wildner 		}
124918de8d7fSPeter Avalos 		if (*activep && *charptr == NULL)
125018de8d7fSPeter Avalos 			*charptr = xstrdup(arg);
125118de8d7fSPeter Avalos 		break;
125218de8d7fSPeter Avalos 
125318de8d7fSPeter Avalos 	case oGlobalKnownHostsFile:
12541c188a7fSPeter Avalos 		cpptr = (char **)&options->system_hostfiles;
12551c188a7fSPeter Avalos 		uintptr = &options->num_system_hostfiles;
12561c188a7fSPeter Avalos 		max_entries = SSH_MAX_HOSTS_FILES;
12571c188a7fSPeter Avalos parse_char_array:
125850a69bb5SSascha Wildner 		i = 0;
125950a69bb5SSascha Wildner 		value = *uintptr == 0; /* was array empty when we started? */
126050a69bb5SSascha Wildner 		while ((arg = argv_next(&ac, &av)) != NULL) {
126150a69bb5SSascha Wildner 			if (*arg == '\0') {
126250a69bb5SSascha Wildner 				error("%s line %d: keyword %s empty argument",
126350a69bb5SSascha Wildner 				    filename, linenum, keyword);
126450a69bb5SSascha Wildner 				goto out;
126550a69bb5SSascha Wildner 			}
126650a69bb5SSascha Wildner 			/* Allow "none" only in first position */
126750a69bb5SSascha Wildner 			if (strcasecmp(arg, "none") == 0) {
126850a69bb5SSascha Wildner 				if (i > 0 || ac > 0) {
126950a69bb5SSascha Wildner 					error("%s line %d: keyword %s \"none\" "
127050a69bb5SSascha Wildner 					    "argument must appear alone.",
127150a69bb5SSascha Wildner 					    filename, linenum, keyword);
127250a69bb5SSascha Wildner 					goto out;
127350a69bb5SSascha Wildner 				}
127450a69bb5SSascha Wildner 			}
127550a69bb5SSascha Wildner 			i++;
127650a69bb5SSascha Wildner 			if (*activep && value) {
127750a69bb5SSascha Wildner 				if ((*uintptr) >= max_entries) {
127850a69bb5SSascha Wildner 					error("%s line %d: too many %s "
127950a69bb5SSascha Wildner 					    "entries.", filename, linenum,
128050a69bb5SSascha Wildner 					    keyword);
128150a69bb5SSascha Wildner 					goto out;
128250a69bb5SSascha Wildner 				}
12831c188a7fSPeter Avalos 				cpptr[(*uintptr)++] = xstrdup(arg);
12841c188a7fSPeter Avalos 			}
12851c188a7fSPeter Avalos 		}
128650a69bb5SSascha Wildner 		break;
128718de8d7fSPeter Avalos 
128818de8d7fSPeter Avalos 	case oUserKnownHostsFile:
12891c188a7fSPeter Avalos 		cpptr = (char **)&options->user_hostfiles;
12901c188a7fSPeter Avalos 		uintptr = &options->num_user_hostfiles;
12911c188a7fSPeter Avalos 		max_entries = SSH_MAX_HOSTS_FILES;
12921c188a7fSPeter Avalos 		goto parse_char_array;
129318de8d7fSPeter Avalos 
12940cbfa66cSDaniel Fojt 	case oHostname:
129518de8d7fSPeter Avalos 		charptr = &options->hostname;
129618de8d7fSPeter Avalos 		goto parse_string;
129718de8d7fSPeter Avalos 
129818de8d7fSPeter Avalos 	case oHostKeyAlias:
129918de8d7fSPeter Avalos 		charptr = &options->host_key_alias;
130018de8d7fSPeter Avalos 		goto parse_string;
130118de8d7fSPeter Avalos 
130218de8d7fSPeter Avalos 	case oPreferredAuthentications:
130318de8d7fSPeter Avalos 		charptr = &options->preferred_authentications;
130418de8d7fSPeter Avalos 		goto parse_string;
130518de8d7fSPeter Avalos 
130618de8d7fSPeter Avalos 	case oBindAddress:
130718de8d7fSPeter Avalos 		charptr = &options->bind_address;
130818de8d7fSPeter Avalos 		goto parse_string;
130918de8d7fSPeter Avalos 
1310664f4763Szrj 	case oBindInterface:
1311664f4763Szrj 		charptr = &options->bind_interface;
1312664f4763Szrj 		goto parse_string;
1313664f4763Szrj 
1314856ea928SPeter Avalos 	case oPKCS11Provider:
1315856ea928SPeter Avalos 		charptr = &options->pkcs11_provider;
131618de8d7fSPeter Avalos 		goto parse_string;
131718de8d7fSPeter Avalos 
13180cbfa66cSDaniel Fojt 	case oSecurityKeyProvider:
13190cbfa66cSDaniel Fojt 		charptr = &options->sk_provider;
13200cbfa66cSDaniel Fojt 		goto parse_string;
13210cbfa66cSDaniel Fojt 
132250a69bb5SSascha Wildner 	case oKnownHostsCommand:
132350a69bb5SSascha Wildner 		charptr = &options->known_hosts_command;
132450a69bb5SSascha Wildner 		goto parse_command;
132550a69bb5SSascha Wildner 
132618de8d7fSPeter Avalos 	case oProxyCommand:
132718de8d7fSPeter Avalos 		charptr = &options->proxy_command;
1328e9778795SPeter Avalos 		/* Ignore ProxyCommand if ProxyJump already specified */
1329e9778795SPeter Avalos 		if (options->jump_host != NULL)
1330e9778795SPeter Avalos 			charptr = &options->jump_host; /* Skip below */
133118de8d7fSPeter Avalos parse_command:
133250a69bb5SSascha Wildner 		if (str == NULL) {
133350a69bb5SSascha Wildner 			error("%.200s line %d: Missing argument.",
133450a69bb5SSascha Wildner 			    filename, linenum);
133550a69bb5SSascha Wildner 			goto out;
133650a69bb5SSascha Wildner 		}
133750a69bb5SSascha Wildner 		len = strspn(str, WHITESPACE "=");
133818de8d7fSPeter Avalos 		if (*activep && *charptr == NULL)
133950a69bb5SSascha Wildner 			*charptr = xstrdup(str + len);
134050a69bb5SSascha Wildner 		argv_consume(&ac);
134150a69bb5SSascha Wildner 		break;
134218de8d7fSPeter Avalos 
1343e9778795SPeter Avalos 	case oProxyJump:
134450a69bb5SSascha Wildner 		if (str == NULL) {
134550a69bb5SSascha Wildner 			error("%.200s line %d: Missing argument.",
1346e9778795SPeter Avalos 			    filename, linenum);
134750a69bb5SSascha Wildner 			goto out;
1348e9778795SPeter Avalos 		}
134950a69bb5SSascha Wildner 		len = strspn(str, WHITESPACE "=");
135050a69bb5SSascha Wildner 		/* XXX use argv? */
135150a69bb5SSascha Wildner 		if (parse_jump(str + len, options, *activep) == -1) {
135250a69bb5SSascha Wildner 			error("%.200s line %d: Invalid ProxyJump \"%s\"",
135350a69bb5SSascha Wildner 			    filename, linenum, str + len);
135450a69bb5SSascha Wildner 			goto out;
1355e9778795SPeter Avalos 		}
135650a69bb5SSascha Wildner 		argv_consume(&ac);
135750a69bb5SSascha Wildner 		break;
1358e9778795SPeter Avalos 
135918de8d7fSPeter Avalos 	case oPort:
136050a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
136150a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
136250a69bb5SSascha Wildner 			error("%.200s line %d: Missing argument.",
1363664f4763Szrj 			    filename, linenum);
136450a69bb5SSascha Wildner 			goto out;
136550a69bb5SSascha Wildner 		}
1366664f4763Szrj 		value = a2port(arg);
136750a69bb5SSascha Wildner 		if (value <= 0) {
136850a69bb5SSascha Wildner 			error("%.200s line %d: Bad port '%s'.",
1369664f4763Szrj 			    filename, linenum, arg);
137050a69bb5SSascha Wildner 			goto out;
137150a69bb5SSascha Wildner 		}
1372664f4763Szrj 		if (*activep && options->port == -1)
1373664f4763Szrj 			options->port = value;
137418de8d7fSPeter Avalos 		break;
137518de8d7fSPeter Avalos 
137618de8d7fSPeter Avalos 	case oConnectionAttempts:
137718de8d7fSPeter Avalos 		intptr = &options->connection_attempts;
1378664f4763Szrj parse_int:
137950a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
138050a69bb5SSascha Wildner 		if ((errstr = atoi_err(arg, &value)) != NULL) {
138150a69bb5SSascha Wildner 			error("%s line %d: integer value %s.",
1382664f4763Szrj 			    filename, linenum, errstr);
138350a69bb5SSascha Wildner 			goto out;
138450a69bb5SSascha Wildner 		}
1385664f4763Szrj 		if (*activep && *intptr == -1)
1386664f4763Szrj 			*intptr = value;
1387664f4763Szrj 		break;
138818de8d7fSPeter Avalos 
138918de8d7fSPeter Avalos 	case oCiphers:
139050a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
139150a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
139250a69bb5SSascha Wildner 			error("%.200s line %d: Missing argument.",
139350a69bb5SSascha Wildner 			    filename, linenum);
139450a69bb5SSascha Wildner 			goto out;
139550a69bb5SSascha Wildner 		}
13960cbfa66cSDaniel Fojt 		if (*arg != '-' &&
139750a69bb5SSascha Wildner 		    !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)){
139850a69bb5SSascha Wildner 			error("%.200s line %d: Bad SSH2 cipher spec '%s'.",
139918de8d7fSPeter Avalos 			    filename, linenum, arg ? arg : "<NONE>");
140050a69bb5SSascha Wildner 			goto out;
140150a69bb5SSascha Wildner 		}
140218de8d7fSPeter Avalos 		if (*activep && options->ciphers == NULL)
140318de8d7fSPeter Avalos 			options->ciphers = xstrdup(arg);
140418de8d7fSPeter Avalos 		break;
140518de8d7fSPeter Avalos 
140618de8d7fSPeter Avalos 	case oMacs:
140750a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
140850a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
140950a69bb5SSascha Wildner 			error("%.200s line %d: Missing argument.",
141050a69bb5SSascha Wildner 			    filename, linenum);
141150a69bb5SSascha Wildner 			goto out;
141250a69bb5SSascha Wildner 		}
14130cbfa66cSDaniel Fojt 		if (*arg != '-' &&
141450a69bb5SSascha Wildner 		    !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)) {
141550a69bb5SSascha Wildner 			error("%.200s line %d: Bad SSH2 MAC spec '%s'.",
141618de8d7fSPeter Avalos 			    filename, linenum, arg ? arg : "<NONE>");
141750a69bb5SSascha Wildner 			goto out;
141850a69bb5SSascha Wildner 		}
141918de8d7fSPeter Avalos 		if (*activep && options->macs == NULL)
142018de8d7fSPeter Avalos 			options->macs = xstrdup(arg);
142118de8d7fSPeter Avalos 		break;
142218de8d7fSPeter Avalos 
14239f304aafSPeter Avalos 	case oKexAlgorithms:
142450a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
142550a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
142650a69bb5SSascha Wildner 			error("%.200s line %d: Missing argument.",
14279f304aafSPeter Avalos 			    filename, linenum);
142850a69bb5SSascha Wildner 			goto out;
142950a69bb5SSascha Wildner 		}
1430ce74bacaSMatthew Dillon 		if (*arg != '-' &&
14310cbfa66cSDaniel Fojt 		    !kex_names_valid(*arg == '+' || *arg == '^' ?
143250a69bb5SSascha Wildner 		    arg + 1 : arg)) {
143350a69bb5SSascha Wildner 			error("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
14349f304aafSPeter Avalos 			    filename, linenum, arg ? arg : "<NONE>");
143550a69bb5SSascha Wildner 			goto out;
143650a69bb5SSascha Wildner 		}
14379f304aafSPeter Avalos 		if (*activep && options->kex_algorithms == NULL)
14389f304aafSPeter Avalos 			options->kex_algorithms = xstrdup(arg);
14399f304aafSPeter Avalos 		break;
14409f304aafSPeter Avalos 
144118de8d7fSPeter Avalos 	case oHostKeyAlgorithms:
1442e9778795SPeter Avalos 		charptr = &options->hostkeyalgorithms;
144350a69bb5SSascha Wildner parse_pubkey_algos:
144450a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
144550a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
144650a69bb5SSascha Wildner 			error("%.200s line %d: Missing argument.",
1447e9778795SPeter Avalos 			    filename, linenum);
144850a69bb5SSascha Wildner 			goto out;
144950a69bb5SSascha Wildner 		}
1450ce74bacaSMatthew Dillon 		if (*arg != '-' &&
14510cbfa66cSDaniel Fojt 		    !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
145250a69bb5SSascha Wildner 		    arg + 1 : arg, 1)) {
145350a69bb5SSascha Wildner 			error("%s line %d: Bad key types '%s'.",
145418de8d7fSPeter Avalos 			    filename, linenum, arg ? arg : "<NONE>");
145550a69bb5SSascha Wildner 			goto out;
145650a69bb5SSascha Wildner 		}
1457e9778795SPeter Avalos 		if (*activep && *charptr == NULL)
1458e9778795SPeter Avalos 			*charptr = xstrdup(arg);
145918de8d7fSPeter Avalos 		break;
146018de8d7fSPeter Avalos 
1461664f4763Szrj 	case oCASignatureAlgorithms:
1462664f4763Szrj 		charptr = &options->ca_sign_algorithms;
146350a69bb5SSascha Wildner 		goto parse_pubkey_algos;
1464664f4763Szrj 
146518de8d7fSPeter Avalos 	case oLogLevel:
146618de8d7fSPeter Avalos 		log_level_ptr = &options->log_level;
146750a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
146818de8d7fSPeter Avalos 		value = log_level_number(arg);
146950a69bb5SSascha Wildner 		if (value == SYSLOG_LEVEL_NOT_SET) {
147050a69bb5SSascha Wildner 			error("%.200s line %d: unsupported log level '%s'",
147118de8d7fSPeter Avalos 			    filename, linenum, arg ? arg : "<NONE>");
147250a69bb5SSascha Wildner 			goto out;
147350a69bb5SSascha Wildner 		}
147418de8d7fSPeter Avalos 		if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
147518de8d7fSPeter Avalos 			*log_level_ptr = (LogLevel) value;
147618de8d7fSPeter Avalos 		break;
147718de8d7fSPeter Avalos 
1478ce74bacaSMatthew Dillon 	case oLogFacility:
1479ce74bacaSMatthew Dillon 		log_facility_ptr = &options->log_facility;
148050a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
1481ce74bacaSMatthew Dillon 		value = log_facility_number(arg);
148250a69bb5SSascha Wildner 		if (value == SYSLOG_FACILITY_NOT_SET) {
148350a69bb5SSascha Wildner 			error("%.200s line %d: unsupported log facility '%s'",
1484ce74bacaSMatthew Dillon 			    filename, linenum, arg ? arg : "<NONE>");
148550a69bb5SSascha Wildner 			goto out;
148650a69bb5SSascha Wildner 		}
1487ce74bacaSMatthew Dillon 		if (*log_facility_ptr == -1)
1488ce74bacaSMatthew Dillon 			*log_facility_ptr = (SyslogFacility) value;
1489ce74bacaSMatthew Dillon 		break;
1490ce74bacaSMatthew Dillon 
149150a69bb5SSascha Wildner 	case oLogVerbose:
149250a69bb5SSascha Wildner 		cppptr = &options->log_verbose;
149350a69bb5SSascha Wildner 		uintptr = &options->num_log_verbose;
149450a69bb5SSascha Wildner 		i = 0;
149550a69bb5SSascha Wildner 		while ((arg = argv_next(&ac, &av)) != NULL) {
149650a69bb5SSascha Wildner 			if (*arg == '\0') {
149750a69bb5SSascha Wildner 				error("%s line %d: keyword %s empty argument",
149850a69bb5SSascha Wildner 				    filename, linenum, keyword);
149950a69bb5SSascha Wildner 				goto out;
150050a69bb5SSascha Wildner 			}
150150a69bb5SSascha Wildner 			/* Allow "none" only in first position */
150250a69bb5SSascha Wildner 			if (strcasecmp(arg, "none") == 0) {
150350a69bb5SSascha Wildner 				if (i > 0 || ac > 0) {
150450a69bb5SSascha Wildner 					error("%s line %d: keyword %s \"none\" "
150550a69bb5SSascha Wildner 					    "argument must appear alone.",
150650a69bb5SSascha Wildner 					    filename, linenum, keyword);
150750a69bb5SSascha Wildner 					goto out;
150850a69bb5SSascha Wildner 				}
150950a69bb5SSascha Wildner 			}
151050a69bb5SSascha Wildner 			i++;
151150a69bb5SSascha Wildner 			if (*activep && *uintptr == 0) {
151250a69bb5SSascha Wildner 				*cppptr = xrecallocarray(*cppptr, *uintptr,
151350a69bb5SSascha Wildner 				    *uintptr + 1, sizeof(**cppptr));
151450a69bb5SSascha Wildner 				(*cppptr)[(*uintptr)++] = xstrdup(arg);
151550a69bb5SSascha Wildner 			}
151650a69bb5SSascha Wildner 		}
151750a69bb5SSascha Wildner 		break;
151850a69bb5SSascha Wildner 
151918de8d7fSPeter Avalos 	case oLocalForward:
152018de8d7fSPeter Avalos 	case oRemoteForward:
1521cb5eb4f1SPeter Avalos 	case oDynamicForward:
152250a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
152350a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
152450a69bb5SSascha Wildner 			error("%.200s line %d: Missing argument.",
152518de8d7fSPeter Avalos 			    filename, linenum);
152650a69bb5SSascha Wildner 			goto out;
152750a69bb5SSascha Wildner 		}
1528cb5eb4f1SPeter Avalos 
1529ce74bacaSMatthew Dillon 		remotefwd = (opcode == oRemoteForward);
1530ce74bacaSMatthew Dillon 		dynamicfwd = (opcode == oDynamicForward);
1531ce74bacaSMatthew Dillon 
1532ce74bacaSMatthew Dillon 		if (!dynamicfwd) {
153350a69bb5SSascha Wildner 			arg2 = argv_next(&ac, &av);
1534ce74bacaSMatthew Dillon 			if (arg2 == NULL || *arg2 == '\0') {
1535ce74bacaSMatthew Dillon 				if (remotefwd)
1536ce74bacaSMatthew Dillon 					dynamicfwd = 1;
153750a69bb5SSascha Wildner 				else {
153850a69bb5SSascha Wildner 					error("%.200s line %d: Missing target "
1539ce74bacaSMatthew Dillon 					    "argument.", filename, linenum);
154050a69bb5SSascha Wildner 					goto out;
154150a69bb5SSascha Wildner 				}
1542ce74bacaSMatthew Dillon 			} else {
154318de8d7fSPeter Avalos 				/* construct a string for parse_forward */
1544ce74bacaSMatthew Dillon 				snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg,
1545ce74bacaSMatthew Dillon 				    arg2);
1546cb5eb4f1SPeter Avalos 			}
1547ce74bacaSMatthew Dillon 		}
1548ce74bacaSMatthew Dillon 		if (dynamicfwd)
1549ce74bacaSMatthew Dillon 			strlcpy(fwdarg, arg, sizeof(fwdarg));
155018de8d7fSPeter Avalos 
155150a69bb5SSascha Wildner 		if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0) {
155250a69bb5SSascha Wildner 			error("%.200s line %d: Bad forwarding specification.",
155318de8d7fSPeter Avalos 			    filename, linenum);
155450a69bb5SSascha Wildner 			goto out;
155550a69bb5SSascha Wildner 		}
155618de8d7fSPeter Avalos 
155718de8d7fSPeter Avalos 		if (*activep) {
1558ce74bacaSMatthew Dillon 			if (remotefwd) {
155918de8d7fSPeter Avalos 				add_remote_forward(options, &fwd);
1560ce74bacaSMatthew Dillon 			} else {
1561ce74bacaSMatthew Dillon 				add_local_forward(options, &fwd);
1562ce74bacaSMatthew Dillon 			}
156318de8d7fSPeter Avalos 		}
156418de8d7fSPeter Avalos 		break;
156518de8d7fSPeter Avalos 
156650a69bb5SSascha Wildner 	case oPermitRemoteOpen:
156750a69bb5SSascha Wildner 		uintptr = &options->num_permitted_remote_opens;
156850a69bb5SSascha Wildner 		cppptr = &options->permitted_remote_opens;
156950a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
157050a69bb5SSascha Wildner 		if (!arg || *arg == '\0')
157150a69bb5SSascha Wildner 			fatal("%s line %d: missing %s specification",
157250a69bb5SSascha Wildner 			    filename, linenum, lookup_opcode_name(opcode));
157350a69bb5SSascha Wildner 		uvalue = *uintptr;	/* modified later */
157450a69bb5SSascha Wildner 		if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) {
157550a69bb5SSascha Wildner 			if (*activep && uvalue == 0) {
157650a69bb5SSascha Wildner 				*uintptr = 1;
157750a69bb5SSascha Wildner 				*cppptr = xcalloc(1, sizeof(**cppptr));
157850a69bb5SSascha Wildner 				(*cppptr)[0] = xstrdup(arg);
157950a69bb5SSascha Wildner 			}
158050a69bb5SSascha Wildner 			break;
158150a69bb5SSascha Wildner 		}
158250a69bb5SSascha Wildner 		while ((arg = argv_next(&ac, &av)) != NULL) {
158350a69bb5SSascha Wildner 			arg2 = xstrdup(arg);
1584*ee116499SAntonio Huete Jimenez 			p = hpdelim(&arg);
1585*ee116499SAntonio Huete Jimenez 			if (p == NULL) {
158650a69bb5SSascha Wildner 				fatal("%s line %d: missing host in %s",
158750a69bb5SSascha Wildner 				    filename, linenum,
158850a69bb5SSascha Wildner 				    lookup_opcode_name(opcode));
158950a69bb5SSascha Wildner 			}
159050a69bb5SSascha Wildner 			p = cleanhostname(p);
159150a69bb5SSascha Wildner 			/*
159250a69bb5SSascha Wildner 			 * don't want to use permitopen_port to avoid
159350a69bb5SSascha Wildner 			 * dependency on channels.[ch] here.
159450a69bb5SSascha Wildner 			 */
159550a69bb5SSascha Wildner 			if (arg == NULL ||
159650a69bb5SSascha Wildner 			    (strcmp(arg, "*") != 0 && a2port(arg) <= 0)) {
159750a69bb5SSascha Wildner 				fatal("%s line %d: bad port number in %s",
159850a69bb5SSascha Wildner 				    filename, linenum,
159950a69bb5SSascha Wildner 				    lookup_opcode_name(opcode));
160050a69bb5SSascha Wildner 			}
160150a69bb5SSascha Wildner 			if (*activep && uvalue == 0) {
160250a69bb5SSascha Wildner 				opt_array_append(filename, linenum,
160350a69bb5SSascha Wildner 				    lookup_opcode_name(opcode),
160450a69bb5SSascha Wildner 				    cppptr, uintptr, arg2);
160550a69bb5SSascha Wildner 			}
160650a69bb5SSascha Wildner 			free(arg2);
160750a69bb5SSascha Wildner 		}
160850a69bb5SSascha Wildner 		break;
160950a69bb5SSascha Wildner 
161018de8d7fSPeter Avalos 	case oClearAllForwardings:
161118de8d7fSPeter Avalos 		intptr = &options->clear_forwardings;
161218de8d7fSPeter Avalos 		goto parse_flag;
161318de8d7fSPeter Avalos 
161418de8d7fSPeter Avalos 	case oHost:
161550a69bb5SSascha Wildner 		if (cmdline) {
161650a69bb5SSascha Wildner 			error("Host directive not supported as a command-line "
161736e94dc5SPeter Avalos 			    "option");
161850a69bb5SSascha Wildner 			goto out;
161950a69bb5SSascha Wildner 		}
162018de8d7fSPeter Avalos 		*activep = 0;
16211c188a7fSPeter Avalos 		arg2 = NULL;
162250a69bb5SSascha Wildner 		while ((arg = argv_next(&ac, &av)) != NULL) {
162350a69bb5SSascha Wildner 			if (*arg == '\0') {
162450a69bb5SSascha Wildner 				error("%s line %d: keyword %s empty argument",
162550a69bb5SSascha Wildner 				    filename, linenum, keyword);
162650a69bb5SSascha Wildner 				goto out;
162750a69bb5SSascha Wildner 			}
162850a69bb5SSascha Wildner 			if ((flags & SSHCONF_NEVERMATCH) != 0) {
162950a69bb5SSascha Wildner 				argv_consume(&ac);
1630e9778795SPeter Avalos 				break;
163150a69bb5SSascha Wildner 			}
16321c188a7fSPeter Avalos 			negated = *arg == '!';
16331c188a7fSPeter Avalos 			if (negated)
16341c188a7fSPeter Avalos 				arg++;
163518de8d7fSPeter Avalos 			if (match_pattern(host, arg)) {
16361c188a7fSPeter Avalos 				if (negated) {
16371c188a7fSPeter Avalos 					debug("%.200s line %d: Skipping Host "
16381c188a7fSPeter Avalos 					    "block because of negated match "
16391c188a7fSPeter Avalos 					    "for %.100s", filename, linenum,
16401c188a7fSPeter Avalos 					    arg);
16411c188a7fSPeter Avalos 					*activep = 0;
164250a69bb5SSascha Wildner 					argv_consume(&ac);
164318de8d7fSPeter Avalos 					break;
164418de8d7fSPeter Avalos 				}
16451c188a7fSPeter Avalos 				if (!*activep)
16461c188a7fSPeter Avalos 					arg2 = arg; /* logged below */
16471c188a7fSPeter Avalos 				*activep = 1;
16481c188a7fSPeter Avalos 			}
16491c188a7fSPeter Avalos 		}
16501c188a7fSPeter Avalos 		if (*activep)
16511c188a7fSPeter Avalos 			debug("%.200s line %d: Applying options for %.100s",
16521c188a7fSPeter Avalos 			    filename, linenum, arg2);
165350a69bb5SSascha Wildner 		break;
165418de8d7fSPeter Avalos 
165536e94dc5SPeter Avalos 	case oMatch:
165650a69bb5SSascha Wildner 		if (cmdline) {
165750a69bb5SSascha Wildner 			error("Host directive not supported as a command-line "
165836e94dc5SPeter Avalos 			    "option");
165950a69bb5SSascha Wildner 			goto out;
166050a69bb5SSascha Wildner 		}
166150a69bb5SSascha Wildner 		value = match_cfg_line(options, &str, pw, host, original_host,
1662664f4763Szrj 		    flags & SSHCONF_FINAL, want_final_pass,
1663664f4763Szrj 		    filename, linenum);
166450a69bb5SSascha Wildner 		if (value < 0) {
166550a69bb5SSascha Wildner 			error("%.200s line %d: Bad Match condition", filename,
166636e94dc5SPeter Avalos 			    linenum);
166750a69bb5SSascha Wildner 			goto out;
166850a69bb5SSascha Wildner 		}
1669e9778795SPeter Avalos 		*activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
167050a69bb5SSascha Wildner 		/*
167150a69bb5SSascha Wildner 		 * If match_cfg_line() didn't consume all its arguments then
167250a69bb5SSascha Wildner 		 * arrange for the extra arguments check below to fail.
167350a69bb5SSascha Wildner 		 */
167450a69bb5SSascha Wildner 
167550a69bb5SSascha Wildner 		if (str == NULL || *str == '\0')
167650a69bb5SSascha Wildner 			argv_consume(&ac);
167736e94dc5SPeter Avalos 		break;
167836e94dc5SPeter Avalos 
167918de8d7fSPeter Avalos 	case oEscapeChar:
168018de8d7fSPeter Avalos 		intptr = &options->escape_char;
168150a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
168250a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
168350a69bb5SSascha Wildner 			error("%.200s line %d: Missing argument.",
168450a69bb5SSascha Wildner 			    filename, linenum);
168550a69bb5SSascha Wildner 			goto out;
168650a69bb5SSascha Wildner 		}
1687e9778795SPeter Avalos 		if (strcmp(arg, "none") == 0)
1688e9778795SPeter Avalos 			value = SSH_ESCAPECHAR_NONE;
1689e9778795SPeter Avalos 		else if (arg[1] == '\0')
1690e9778795SPeter Avalos 			value = (u_char) arg[0];
1691e9778795SPeter Avalos 		else if (arg[0] == '^' && arg[2] == 0 &&
169218de8d7fSPeter Avalos 		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
169318de8d7fSPeter Avalos 			value = (u_char) arg[1] & 31;
169418de8d7fSPeter Avalos 		else {
169550a69bb5SSascha Wildner 			error("%.200s line %d: Bad escape character.",
169618de8d7fSPeter Avalos 			    filename, linenum);
169750a69bb5SSascha Wildner 			goto out;
169818de8d7fSPeter Avalos 		}
169918de8d7fSPeter Avalos 		if (*activep && *intptr == -1)
170018de8d7fSPeter Avalos 			*intptr = value;
170118de8d7fSPeter Avalos 		break;
170218de8d7fSPeter Avalos 
170318de8d7fSPeter Avalos 	case oAddressFamily:
170418de8d7fSPeter Avalos 		intptr = &options->address_family;
170536e94dc5SPeter Avalos 		multistate_ptr = multistate_addressfamily;
170636e94dc5SPeter Avalos 		goto parse_multistate;
170718de8d7fSPeter Avalos 
170818de8d7fSPeter Avalos 	case oEnableSSHKeysign:
170918de8d7fSPeter Avalos 		intptr = &options->enable_ssh_keysign;
171018de8d7fSPeter Avalos 		goto parse_flag;
171118de8d7fSPeter Avalos 
171218de8d7fSPeter Avalos 	case oIdentitiesOnly:
171318de8d7fSPeter Avalos 		intptr = &options->identities_only;
171418de8d7fSPeter Avalos 		goto parse_flag;
171518de8d7fSPeter Avalos 
171618de8d7fSPeter Avalos 	case oServerAliveInterval:
171718de8d7fSPeter Avalos 		intptr = &options->server_alive_interval;
171818de8d7fSPeter Avalos 		goto parse_time;
171918de8d7fSPeter Avalos 
172018de8d7fSPeter Avalos 	case oServerAliveCountMax:
172118de8d7fSPeter Avalos 		intptr = &options->server_alive_count_max;
172218de8d7fSPeter Avalos 		goto parse_int;
172318de8d7fSPeter Avalos 
172418de8d7fSPeter Avalos 	case oSendEnv:
172550a69bb5SSascha Wildner 		while ((arg = argv_next(&ac, &av)) != NULL) {
172650a69bb5SSascha Wildner 			if (*arg == '\0' || strchr(arg, '=') != NULL) {
172750a69bb5SSascha Wildner 				error("%s line %d: Invalid environment name.",
172818de8d7fSPeter Avalos 				    filename, linenum);
172950a69bb5SSascha Wildner 				goto out;
173050a69bb5SSascha Wildner 			}
173118de8d7fSPeter Avalos 			if (!*activep)
173218de8d7fSPeter Avalos 				continue;
1733664f4763Szrj 			if (*arg == '-') {
1734664f4763Szrj 				/* Removing an env var */
1735664f4763Szrj 				rm_env(options, arg, filename, linenum);
1736664f4763Szrj 				continue;
173750a69bb5SSascha Wildner 			}
1738*ee116499SAntonio Huete Jimenez 			opt_array_append(filename, linenum,
1739*ee116499SAntonio Huete Jimenez 			    lookup_opcode_name(opcode),
1740*ee116499SAntonio Huete Jimenez 			    &options->send_env, &options->num_send_env, arg);
1741664f4763Szrj 		}
1742664f4763Szrj 		break;
1743664f4763Szrj 
1744664f4763Szrj 	case oSetEnv:
1745664f4763Szrj 		value = options->num_setenv;
174650a69bb5SSascha Wildner 		while ((arg = argv_next(&ac, &av)) != NULL) {
174750a69bb5SSascha Wildner 			if (strchr(arg, '=') == NULL) {
174850a69bb5SSascha Wildner 				error("%s line %d: Invalid SetEnv.",
1749664f4763Szrj 				    filename, linenum);
175050a69bb5SSascha Wildner 				goto out;
175150a69bb5SSascha Wildner 			}
1752664f4763Szrj 			if (!*activep || value != 0)
1753664f4763Szrj 				continue;
1754*ee116499SAntonio Huete Jimenez 			if (lookup_setenv_in_list(arg, options->setenv,
1755*ee116499SAntonio Huete Jimenez 			    options->num_setenv) != NULL) {
1756*ee116499SAntonio Huete Jimenez 				debug2("%s line %d: ignoring duplicate env "
1757*ee116499SAntonio Huete Jimenez 				    "name \"%.64s\"", filename, linenum, arg);
1758*ee116499SAntonio Huete Jimenez 				continue;
175950a69bb5SSascha Wildner 			}
1760*ee116499SAntonio Huete Jimenez 			opt_array_append(filename, linenum,
1761*ee116499SAntonio Huete Jimenez 			    lookup_opcode_name(opcode),
1762*ee116499SAntonio Huete Jimenez 			    &options->setenv, &options->num_setenv, arg);
1763664f4763Szrj 		}
176418de8d7fSPeter Avalos 		break;
176518de8d7fSPeter Avalos 
176618de8d7fSPeter Avalos 	case oControlPath:
176718de8d7fSPeter Avalos 		charptr = &options->control_path;
176818de8d7fSPeter Avalos 		goto parse_string;
176918de8d7fSPeter Avalos 
177018de8d7fSPeter Avalos 	case oControlMaster:
177118de8d7fSPeter Avalos 		intptr = &options->control_master;
177236e94dc5SPeter Avalos 		multistate_ptr = multistate_controlmaster;
177336e94dc5SPeter Avalos 		goto parse_multistate;
177418de8d7fSPeter Avalos 
1775856ea928SPeter Avalos 	case oControlPersist:
1776856ea928SPeter Avalos 		/* no/false/yes/true, or a time spec */
1777856ea928SPeter Avalos 		intptr = &options->control_persist;
177850a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
177950a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
178050a69bb5SSascha Wildner 			error("%.200s line %d: Missing ControlPersist"
1781856ea928SPeter Avalos 			    " argument.", filename, linenum);
178250a69bb5SSascha Wildner 			goto out;
178350a69bb5SSascha Wildner 		}
1784856ea928SPeter Avalos 		value = 0;
1785856ea928SPeter Avalos 		value2 = 0;	/* timeout */
1786856ea928SPeter Avalos 		if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1787856ea928SPeter Avalos 			value = 0;
1788856ea928SPeter Avalos 		else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1789856ea928SPeter Avalos 			value = 1;
1790856ea928SPeter Avalos 		else if ((value2 = convtime(arg)) >= 0)
1791856ea928SPeter Avalos 			value = 1;
179250a69bb5SSascha Wildner 		else {
179350a69bb5SSascha Wildner 			error("%.200s line %d: Bad ControlPersist argument.",
1794856ea928SPeter Avalos 			    filename, linenum);
179550a69bb5SSascha Wildner 			goto out;
179650a69bb5SSascha Wildner 		}
1797856ea928SPeter Avalos 		if (*activep && *intptr == -1) {
1798856ea928SPeter Avalos 			*intptr = value;
1799856ea928SPeter Avalos 			options->control_persist_timeout = value2;
1800856ea928SPeter Avalos 		}
1801856ea928SPeter Avalos 		break;
1802856ea928SPeter Avalos 
180318de8d7fSPeter Avalos 	case oHashKnownHosts:
180418de8d7fSPeter Avalos 		intptr = &options->hash_known_hosts;
180518de8d7fSPeter Avalos 		goto parse_flag;
180618de8d7fSPeter Avalos 
180718de8d7fSPeter Avalos 	case oTunnel:
180818de8d7fSPeter Avalos 		intptr = &options->tun_open;
180936e94dc5SPeter Avalos 		multistate_ptr = multistate_tunnel;
181036e94dc5SPeter Avalos 		goto parse_multistate;
181118de8d7fSPeter Avalos 
181218de8d7fSPeter Avalos 	case oTunnelDevice:
181350a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
181450a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
181550a69bb5SSascha Wildner 			error("%.200s line %d: Missing argument.",
181650a69bb5SSascha Wildner 			    filename, linenum);
181750a69bb5SSascha Wildner 			goto out;
181850a69bb5SSascha Wildner 		}
181918de8d7fSPeter Avalos 		value = a2tun(arg, &value2);
182050a69bb5SSascha Wildner 		if (value == SSH_TUNID_ERR) {
182150a69bb5SSascha Wildner 			error("%.200s line %d: Bad tun device.",
182250a69bb5SSascha Wildner 			    filename, linenum);
182350a69bb5SSascha Wildner 			goto out;
182450a69bb5SSascha Wildner 		}
182550a69bb5SSascha Wildner 		if (*activep && options->tun_local == -1) {
182618de8d7fSPeter Avalos 			options->tun_local = value;
182718de8d7fSPeter Avalos 			options->tun_remote = value2;
182818de8d7fSPeter Avalos 		}
182918de8d7fSPeter Avalos 		break;
183018de8d7fSPeter Avalos 
183118de8d7fSPeter Avalos 	case oLocalCommand:
183218de8d7fSPeter Avalos 		charptr = &options->local_command;
183318de8d7fSPeter Avalos 		goto parse_command;
183418de8d7fSPeter Avalos 
183518de8d7fSPeter Avalos 	case oPermitLocalCommand:
183618de8d7fSPeter Avalos 		intptr = &options->permit_local_command;
183718de8d7fSPeter Avalos 		goto parse_flag;
183818de8d7fSPeter Avalos 
1839ce74bacaSMatthew Dillon 	case oRemoteCommand:
1840ce74bacaSMatthew Dillon 		charptr = &options->remote_command;
1841ce74bacaSMatthew Dillon 		goto parse_command;
1842ce74bacaSMatthew Dillon 
184318de8d7fSPeter Avalos 	case oVisualHostKey:
184418de8d7fSPeter Avalos 		intptr = &options->visual_host_key;
184518de8d7fSPeter Avalos 		goto parse_flag;
184618de8d7fSPeter Avalos 
1847e9778795SPeter Avalos 	case oInclude:
184850a69bb5SSascha Wildner 		if (cmdline) {
184950a69bb5SSascha Wildner 			error("Include directive not supported as a "
1850e9778795SPeter Avalos 			    "command-line option");
185150a69bb5SSascha Wildner 			goto out;
185250a69bb5SSascha Wildner 		}
1853e9778795SPeter Avalos 		value = 0;
185450a69bb5SSascha Wildner 		while ((arg = argv_next(&ac, &av)) != NULL) {
185550a69bb5SSascha Wildner 			if (*arg == '\0') {
185650a69bb5SSascha Wildner 				error("%s line %d: keyword %s empty argument",
185750a69bb5SSascha Wildner 				    filename, linenum, keyword);
185850a69bb5SSascha Wildner 				goto out;
185950a69bb5SSascha Wildner 			}
1860e9778795SPeter Avalos 			/*
1861e9778795SPeter Avalos 			 * Ensure all paths are anchored. User configuration
1862e9778795SPeter Avalos 			 * files may begin with '~/' but system configurations
1863e9778795SPeter Avalos 			 * must not. If the path is relative, then treat it
1864e9778795SPeter Avalos 			 * as living in ~/.ssh for user configurations or
1865e9778795SPeter Avalos 			 * /etc/ssh for system ones.
1866e9778795SPeter Avalos 			 */
186750a69bb5SSascha Wildner 			if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0) {
186850a69bb5SSascha Wildner 				error("%.200s line %d: bad include path %s.",
1869e9778795SPeter Avalos 				    filename, linenum, arg);
187050a69bb5SSascha Wildner 				goto out;
187150a69bb5SSascha Wildner 			}
1872664f4763Szrj 			if (!path_absolute(arg) && *arg != '~') {
1873e9778795SPeter Avalos 				xasprintf(&arg2, "%s/%s",
1874e9778795SPeter Avalos 				    (flags & SSHCONF_USERCONF) ?
1875e9778795SPeter Avalos 				    "~/" _PATH_SSH_USER_DIR : SSHDIR, arg);
1876e9778795SPeter Avalos 			} else
1877e9778795SPeter Avalos 				arg2 = xstrdup(arg);
1878e9778795SPeter Avalos 			memset(&gl, 0, sizeof(gl));
1879e9778795SPeter Avalos 			r = glob(arg2, GLOB_TILDE, NULL, &gl);
1880e9778795SPeter Avalos 			if (r == GLOB_NOMATCH) {
1881e9778795SPeter Avalos 				debug("%.200s line %d: include %s matched no "
1882e9778795SPeter Avalos 				    "files",filename, linenum, arg2);
1883ce74bacaSMatthew Dillon 				free(arg2);
1884e9778795SPeter Avalos 				continue;
188550a69bb5SSascha Wildner 			} else if (r != 0) {
188650a69bb5SSascha Wildner 				error("%.200s line %d: glob failed for %s.",
1887e9778795SPeter Avalos 				    filename, linenum, arg2);
188850a69bb5SSascha Wildner 				goto out;
188950a69bb5SSascha Wildner 			}
1890e9778795SPeter Avalos 			free(arg2);
1891e9778795SPeter Avalos 			oactive = *activep;
18920cbfa66cSDaniel Fojt 			for (i = 0; i < gl.gl_pathc; i++) {
1893e9778795SPeter Avalos 				debug3("%.200s line %d: Including file %s "
1894e9778795SPeter Avalos 				    "depth %d%s", filename, linenum,
1895e9778795SPeter Avalos 				    gl.gl_pathv[i], depth,
1896e9778795SPeter Avalos 				    oactive ? "" : " (parse only)");
1897e9778795SPeter Avalos 				r = read_config_file_depth(gl.gl_pathv[i],
1898e9778795SPeter Avalos 				    pw, host, original_host, options,
1899e9778795SPeter Avalos 				    flags | SSHCONF_CHECKPERM |
1900e9778795SPeter Avalos 				    (oactive ? 0 : SSHCONF_NEVERMATCH),
1901664f4763Szrj 				    activep, want_final_pass, depth + 1);
1902ce74bacaSMatthew Dillon 				if (r != 1 && errno != ENOENT) {
190350a69bb5SSascha Wildner 					error("Can't open user config file "
1904ce74bacaSMatthew Dillon 					    "%.100s: %.100s", gl.gl_pathv[i],
1905ce74bacaSMatthew Dillon 					    strerror(errno));
190650a69bb5SSascha Wildner 					globfree(&gl);
190750a69bb5SSascha Wildner 					goto out;
1908ce74bacaSMatthew Dillon 				}
1909e9778795SPeter Avalos 				/*
1910e9778795SPeter Avalos 				 * don't let Match in includes clobber the
1911e9778795SPeter Avalos 				 * containing file's Match state.
1912e9778795SPeter Avalos 				 */
1913e9778795SPeter Avalos 				*activep = oactive;
1914e9778795SPeter Avalos 				if (r != 1)
1915e9778795SPeter Avalos 					value = -1;
1916e9778795SPeter Avalos 			}
1917e9778795SPeter Avalos 			globfree(&gl);
1918e9778795SPeter Avalos 		}
1919e9778795SPeter Avalos 		if (value != 0)
192050a69bb5SSascha Wildner 			ret = value;
1921e9778795SPeter Avalos 		break;
1922e9778795SPeter Avalos 
19239f304aafSPeter Avalos 	case oIPQoS:
192450a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
192550a69bb5SSascha Wildner 		if ((value = parse_ipqos(arg)) == -1) {
192650a69bb5SSascha Wildner 			error("%s line %d: Bad IPQoS value: %s",
19279f304aafSPeter Avalos 			    filename, linenum, arg);
192850a69bb5SSascha Wildner 			goto out;
192950a69bb5SSascha Wildner 		}
193050a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
19319f304aafSPeter Avalos 		if (arg == NULL)
19329f304aafSPeter Avalos 			value2 = value;
193350a69bb5SSascha Wildner 		else if ((value2 = parse_ipqos(arg)) == -1) {
193450a69bb5SSascha Wildner 			error("%s line %d: Bad IPQoS value: %s",
19359f304aafSPeter Avalos 			    filename, linenum, arg);
193650a69bb5SSascha Wildner 			goto out;
193750a69bb5SSascha Wildner 		}
193850a69bb5SSascha Wildner 		if (*activep && options->ip_qos_interactive == -1) {
19399f304aafSPeter Avalos 			options->ip_qos_interactive = value;
19409f304aafSPeter Avalos 			options->ip_qos_bulk = value2;
19419f304aafSPeter Avalos 		}
19429f304aafSPeter Avalos 		break;
19439f304aafSPeter Avalos 
19441c188a7fSPeter Avalos 	case oRequestTTY:
194536e94dc5SPeter Avalos 		intptr = &options->request_tty;
194636e94dc5SPeter Avalos 		multistate_ptr = multistate_requesttty;
194736e94dc5SPeter Avalos 		goto parse_multistate;
194836e94dc5SPeter Avalos 
194950a69bb5SSascha Wildner 	case oSessionType:
195050a69bb5SSascha Wildner 		intptr = &options->session_type;
195150a69bb5SSascha Wildner 		multistate_ptr = multistate_sessiontype;
195250a69bb5SSascha Wildner 		goto parse_multistate;
195350a69bb5SSascha Wildner 
195450a69bb5SSascha Wildner 	case oStdinNull:
195550a69bb5SSascha Wildner 		intptr = &options->stdin_null;
195650a69bb5SSascha Wildner 		goto parse_flag;
195750a69bb5SSascha Wildner 
195850a69bb5SSascha Wildner 	case oForkAfterAuthentication:
195950a69bb5SSascha Wildner 		intptr = &options->fork_after_authentication;
196050a69bb5SSascha Wildner 		goto parse_flag;
196150a69bb5SSascha Wildner 
196236e94dc5SPeter Avalos 	case oIgnoreUnknown:
196336e94dc5SPeter Avalos 		charptr = &options->ignored_unknown;
196436e94dc5SPeter Avalos 		goto parse_string;
196536e94dc5SPeter Avalos 
196636e94dc5SPeter Avalos 	case oProxyUseFdpass:
196736e94dc5SPeter Avalos 		intptr = &options->proxy_use_fdpass;
196836e94dc5SPeter Avalos 		goto parse_flag;
196936e94dc5SPeter Avalos 
197036e94dc5SPeter Avalos 	case oCanonicalDomains:
197136e94dc5SPeter Avalos 		value = options->num_canonical_domains != 0;
197250a69bb5SSascha Wildner 		i = 0;
197350a69bb5SSascha Wildner 		while ((arg = argv_next(&ac, &av)) != NULL) {
197450a69bb5SSascha Wildner 			if (*arg == '\0') {
197550a69bb5SSascha Wildner 				error("%s line %d: keyword %s empty argument",
197650a69bb5SSascha Wildner 				    filename, linenum, keyword);
197750a69bb5SSascha Wildner 				goto out;
197850a69bb5SSascha Wildner 			}
197950a69bb5SSascha Wildner 			/* Allow "none" only in first position */
198050a69bb5SSascha Wildner 			if (strcasecmp(arg, "none") == 0) {
198150a69bb5SSascha Wildner 				if (i > 0 || ac > 0) {
198250a69bb5SSascha Wildner 					error("%s line %d: keyword %s \"none\" "
198350a69bb5SSascha Wildner 					    "argument must appear alone.",
198450a69bb5SSascha Wildner 					    filename, linenum, keyword);
198550a69bb5SSascha Wildner 					goto out;
198650a69bb5SSascha Wildner 				}
198750a69bb5SSascha Wildner 			}
198850a69bb5SSascha Wildner 			i++;
1989664f4763Szrj 			if (!valid_domain(arg, 1, &errstr)) {
199050a69bb5SSascha Wildner 				error("%s line %d: %s", filename, linenum,
1991664f4763Szrj 				    errstr);
199250a69bb5SSascha Wildner 				goto out;
1993664f4763Szrj 			}
199436e94dc5SPeter Avalos 			if (!*activep || value)
199536e94dc5SPeter Avalos 				continue;
199650a69bb5SSascha Wildner 			if (options->num_canonical_domains >=
199750a69bb5SSascha Wildner 			    MAX_CANON_DOMAINS) {
199850a69bb5SSascha Wildner 				error("%s line %d: too many hostname suffixes.",
199936e94dc5SPeter Avalos 				    filename, linenum);
200050a69bb5SSascha Wildner 				goto out;
200150a69bb5SSascha Wildner 			}
200236e94dc5SPeter Avalos 			options->canonical_domains[
200336e94dc5SPeter Avalos 			    options->num_canonical_domains++] = xstrdup(arg);
200436e94dc5SPeter Avalos 		}
200536e94dc5SPeter Avalos 		break;
200636e94dc5SPeter Avalos 
200736e94dc5SPeter Avalos 	case oCanonicalizePermittedCNAMEs:
200836e94dc5SPeter Avalos 		value = options->num_permitted_cnames != 0;
200950a69bb5SSascha Wildner 		i = 0;
201050a69bb5SSascha Wildner 		while ((arg = argv_next(&ac, &av)) != NULL) {
201150a69bb5SSascha Wildner 			/*
201250a69bb5SSascha Wildner 			 * Either 'none' (only in first position), '*' for
201350a69bb5SSascha Wildner 			 * everything or 'list:list'
201450a69bb5SSascha Wildner 			 */
201550a69bb5SSascha Wildner 			if (strcasecmp(arg, "none") == 0) {
201650a69bb5SSascha Wildner 				if (i > 0 || ac > 0) {
201750a69bb5SSascha Wildner 					error("%s line %d: keyword %s \"none\" "
201850a69bb5SSascha Wildner 					    "argument must appear alone.",
201950a69bb5SSascha Wildner 					    filename, linenum, keyword);
202050a69bb5SSascha Wildner 					goto out;
202150a69bb5SSascha Wildner 				}
202250a69bb5SSascha Wildner 				arg2 = "";
202350a69bb5SSascha Wildner 			} else if (strcmp(arg, "*") == 0) {
202436e94dc5SPeter Avalos 				arg2 = arg;
202550a69bb5SSascha Wildner 			} else {
202636e94dc5SPeter Avalos 				lowercase(arg);
202736e94dc5SPeter Avalos 				if ((arg2 = strchr(arg, ':')) == NULL ||
202836e94dc5SPeter Avalos 				    arg2[1] == '\0') {
202950a69bb5SSascha Wildner 					error("%s line %d: "
203036e94dc5SPeter Avalos 					    "Invalid permitted CNAME \"%s\"",
203136e94dc5SPeter Avalos 					    filename, linenum, arg);
203250a69bb5SSascha Wildner 					goto out;
203336e94dc5SPeter Avalos 				}
203436e94dc5SPeter Avalos 				*arg2 = '\0';
203536e94dc5SPeter Avalos 				arg2++;
203636e94dc5SPeter Avalos 			}
203750a69bb5SSascha Wildner 			i++;
203836e94dc5SPeter Avalos 			if (!*activep || value)
203936e94dc5SPeter Avalos 				continue;
204050a69bb5SSascha Wildner 			if (options->num_permitted_cnames >=
204150a69bb5SSascha Wildner 			    MAX_CANON_DOMAINS) {
204250a69bb5SSascha Wildner 				error("%s line %d: too many permitted CNAMEs.",
204336e94dc5SPeter Avalos 				    filename, linenum);
204450a69bb5SSascha Wildner 				goto out;
204550a69bb5SSascha Wildner 			}
204636e94dc5SPeter Avalos 			cname = options->permitted_cnames +
204736e94dc5SPeter Avalos 			    options->num_permitted_cnames++;
204836e94dc5SPeter Avalos 			cname->source_list = xstrdup(arg);
204936e94dc5SPeter Avalos 			cname->target_list = xstrdup(arg2);
205036e94dc5SPeter Avalos 		}
205136e94dc5SPeter Avalos 		break;
205236e94dc5SPeter Avalos 
205336e94dc5SPeter Avalos 	case oCanonicalizeHostname:
205436e94dc5SPeter Avalos 		intptr = &options->canonicalize_hostname;
205536e94dc5SPeter Avalos 		multistate_ptr = multistate_canonicalizehostname;
205636e94dc5SPeter Avalos 		goto parse_multistate;
205736e94dc5SPeter Avalos 
205836e94dc5SPeter Avalos 	case oCanonicalizeMaxDots:
205936e94dc5SPeter Avalos 		intptr = &options->canonicalize_max_dots;
206036e94dc5SPeter Avalos 		goto parse_int;
206136e94dc5SPeter Avalos 
206236e94dc5SPeter Avalos 	case oCanonicalizeFallbackLocal:
206336e94dc5SPeter Avalos 		intptr = &options->canonicalize_fallback_local;
206436e94dc5SPeter Avalos 		goto parse_flag;
206536e94dc5SPeter Avalos 
206636e94dc5SPeter Avalos 	case oStreamLocalBindMask:
206750a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
206850a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
206950a69bb5SSascha Wildner 			error("%.200s line %d: Missing StreamLocalBindMask "
207050a69bb5SSascha Wildner 			    "argument.", filename, linenum);
207150a69bb5SSascha Wildner 			goto out;
207250a69bb5SSascha Wildner 		}
207336e94dc5SPeter Avalos 		/* Parse mode in octal format */
207436e94dc5SPeter Avalos 		value = strtol(arg, &endofnumber, 8);
207550a69bb5SSascha Wildner 		if (arg == endofnumber || value < 0 || value > 0777) {
207650a69bb5SSascha Wildner 			error("%.200s line %d: Bad mask.", filename, linenum);
207750a69bb5SSascha Wildner 			goto out;
207850a69bb5SSascha Wildner 		}
207936e94dc5SPeter Avalos 		options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
20801c188a7fSPeter Avalos 		break;
20811c188a7fSPeter Avalos 
208236e94dc5SPeter Avalos 	case oStreamLocalBindUnlink:
208336e94dc5SPeter Avalos 		intptr = &options->fwd_opts.streamlocal_bind_unlink;
208436e94dc5SPeter Avalos 		goto parse_flag;
208536e94dc5SPeter Avalos 
2086e9778795SPeter Avalos 	case oRevokedHostKeys:
2087e9778795SPeter Avalos 		charptr = &options->revoked_host_keys;
2088e9778795SPeter Avalos 		goto parse_string;
2089e9778795SPeter Avalos 
2090e9778795SPeter Avalos 	case oFingerprintHash:
2091e9778795SPeter Avalos 		intptr = &options->fingerprint_hash;
209250a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
209350a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
209450a69bb5SSascha Wildner 			error("%.200s line %d: Missing argument.",
2095e9778795SPeter Avalos 			    filename, linenum);
209650a69bb5SSascha Wildner 			goto out;
209750a69bb5SSascha Wildner 		}
209850a69bb5SSascha Wildner 		if ((value = ssh_digest_alg_by_name(arg)) == -1) {
209950a69bb5SSascha Wildner 			error("%.200s line %d: Invalid hash algorithm \"%s\".",
2100e9778795SPeter Avalos 			    filename, linenum, arg);
210150a69bb5SSascha Wildner 			goto out;
210250a69bb5SSascha Wildner 		}
2103e9778795SPeter Avalos 		if (*activep && *intptr == -1)
2104e9778795SPeter Avalos 			*intptr = value;
2105e9778795SPeter Avalos 		break;
2106e9778795SPeter Avalos 
2107e9778795SPeter Avalos 	case oUpdateHostkeys:
2108e9778795SPeter Avalos 		intptr = &options->update_hostkeys;
2109e9778795SPeter Avalos 		multistate_ptr = multistate_yesnoask;
2110e9778795SPeter Avalos 		goto parse_multistate;
2111e9778795SPeter Avalos 
211250a69bb5SSascha Wildner 	case oHostbasedAcceptedAlgorithms:
211350a69bb5SSascha Wildner 		charptr = &options->hostbased_accepted_algos;
211450a69bb5SSascha Wildner 		goto parse_pubkey_algos;
2115e9778795SPeter Avalos 
211650a69bb5SSascha Wildner 	case oPubkeyAcceptedAlgorithms:
211750a69bb5SSascha Wildner 		charptr = &options->pubkey_accepted_algos;
211850a69bb5SSascha Wildner 		goto parse_pubkey_algos;
2119e9778795SPeter Avalos 
2120e9778795SPeter Avalos 	case oAddKeysToAgent:
212150a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
212250a69bb5SSascha Wildner 		arg2 = argv_next(&ac, &av);
212350a69bb5SSascha Wildner 		value = parse_multistate_value(arg, filename, linenum,
212450a69bb5SSascha Wildner 		    multistate_yesnoaskconfirm);
212550a69bb5SSascha Wildner 		value2 = 0; /* unlimited lifespan by default */
212650a69bb5SSascha Wildner 		if (value == 3 && arg2 != NULL) {
212750a69bb5SSascha Wildner 			/* allow "AddKeysToAgent confirm 5m" */
212850a69bb5SSascha Wildner 			if ((value2 = convtime(arg2)) == -1 ||
212950a69bb5SSascha Wildner 			    value2 > INT_MAX) {
213050a69bb5SSascha Wildner 				error("%s line %d: invalid time value.",
213150a69bb5SSascha Wildner 				    filename, linenum);
213250a69bb5SSascha Wildner 				goto out;
213350a69bb5SSascha Wildner 			}
213450a69bb5SSascha Wildner 		} else if (value == -1 && arg2 == NULL) {
213550a69bb5SSascha Wildner 			if ((value2 = convtime(arg)) == -1 ||
213650a69bb5SSascha Wildner 			    value2 > INT_MAX) {
213750a69bb5SSascha Wildner 				error("%s line %d: unsupported option",
213850a69bb5SSascha Wildner 				    filename, linenum);
213950a69bb5SSascha Wildner 				goto out;
214050a69bb5SSascha Wildner 			}
214150a69bb5SSascha Wildner 			value = 1; /* yes */
214250a69bb5SSascha Wildner 		} else if (value == -1 || arg2 != NULL) {
214350a69bb5SSascha Wildner 			error("%s line %d: unsupported option",
214450a69bb5SSascha Wildner 			    filename, linenum);
214550a69bb5SSascha Wildner 			goto out;
214650a69bb5SSascha Wildner 		}
214750a69bb5SSascha Wildner 		if (*activep && options->add_keys_to_agent == -1) {
214850a69bb5SSascha Wildner 			options->add_keys_to_agent = value;
214950a69bb5SSascha Wildner 			options->add_keys_to_agent_lifespan = value2;
215050a69bb5SSascha Wildner 		}
215150a69bb5SSascha Wildner 		break;
2152e9778795SPeter Avalos 
2153e9778795SPeter Avalos 	case oIdentityAgent:
2154e9778795SPeter Avalos 		charptr = &options->identity_agent;
215550a69bb5SSascha Wildner 		arg = argv_next(&ac, &av);
215650a69bb5SSascha Wildner 		if (!arg || *arg == '\0') {
215750a69bb5SSascha Wildner 			error("%.200s line %d: Missing argument.",
2158664f4763Szrj 			    filename, linenum);
215950a69bb5SSascha Wildner 			goto out;
216050a69bb5SSascha Wildner 		}
21610cbfa66cSDaniel Fojt   parse_agent_path:
2162664f4763Szrj 		/* Extra validation if the string represents an env var. */
216350a69bb5SSascha Wildner 		if ((arg2 = dollar_expand(&r, arg)) == NULL || r) {
216450a69bb5SSascha Wildner 			error("%.200s line %d: Invalid environment expansion "
216550a69bb5SSascha Wildner 			    "%s.", filename, linenum, arg);
216650a69bb5SSascha Wildner 			goto out;
216750a69bb5SSascha Wildner 		}
216850a69bb5SSascha Wildner 		free(arg2);
216950a69bb5SSascha Wildner 		/* check for legacy environment format */
217050a69bb5SSascha Wildner 		if (arg[0] == '$' && arg[1] != '{' &&
217150a69bb5SSascha Wildner 		    !valid_env_name(arg + 1)) {
217250a69bb5SSascha Wildner 			error("%.200s line %d: Invalid environment name %s.",
2173664f4763Szrj 			    filename, linenum, arg);
217450a69bb5SSascha Wildner 			goto out;
2175664f4763Szrj 		}
2176664f4763Szrj 		if (*activep && *charptr == NULL)
2177664f4763Szrj 			*charptr = xstrdup(arg);
2178664f4763Szrj 		break;
2179e9778795SPeter Avalos 
2180*ee116499SAntonio Huete Jimenez 	case oRequiredRSASize:
2181*ee116499SAntonio Huete Jimenez 		intptr = &options->required_rsa_size;
2182*ee116499SAntonio Huete Jimenez 		goto parse_int;
2183*ee116499SAntonio Huete Jimenez 
218418de8d7fSPeter Avalos 	case oDeprecated:
218518de8d7fSPeter Avalos 		debug("%s line %d: Deprecated option \"%s\"",
218618de8d7fSPeter Avalos 		    filename, linenum, keyword);
218750a69bb5SSascha Wildner 		argv_consume(&ac);
218850a69bb5SSascha Wildner 		break;
218918de8d7fSPeter Avalos 
219018de8d7fSPeter Avalos 	case oUnsupported:
219118de8d7fSPeter Avalos 		error("%s line %d: Unsupported option \"%s\"",
219218de8d7fSPeter Avalos 		    filename, linenum, keyword);
219350a69bb5SSascha Wildner 		argv_consume(&ac);
219450a69bb5SSascha Wildner 		break;
219518de8d7fSPeter Avalos 
219618de8d7fSPeter Avalos 	default:
219750a69bb5SSascha Wildner 		error("%s line %d: Unimplemented opcode %d",
219850a69bb5SSascha Wildner 		    filename, linenum, opcode);
219950a69bb5SSascha Wildner 		goto out;
220018de8d7fSPeter Avalos 	}
220118de8d7fSPeter Avalos 
220218de8d7fSPeter Avalos 	/* Check that there is no garbage at end of line. */
220350a69bb5SSascha Wildner 	if (ac > 0) {
220450a69bb5SSascha Wildner 		error("%.200s line %d: keyword %s extra arguments "
220550a69bb5SSascha Wildner 		    "at end of line", filename, linenum, keyword);
220650a69bb5SSascha Wildner 		goto out;
220718de8d7fSPeter Avalos 	}
220850a69bb5SSascha Wildner 
220950a69bb5SSascha Wildner 	/* success */
221050a69bb5SSascha Wildner 	ret = 0;
221150a69bb5SSascha Wildner  out:
221250a69bb5SSascha Wildner 	argv_free(oav, oac);
221350a69bb5SSascha Wildner 	return ret;
221418de8d7fSPeter Avalos }
221518de8d7fSPeter Avalos 
221618de8d7fSPeter Avalos /*
221718de8d7fSPeter Avalos  * Reads the config file and modifies the options accordingly.  Options
221818de8d7fSPeter Avalos  * should already be initialized before this call.  This never returns if
221918de8d7fSPeter Avalos  * there is an error.  If the file does not exist, this returns 0.
222018de8d7fSPeter Avalos  */
222118de8d7fSPeter Avalos int
read_config_file(const char * filename,struct passwd * pw,const char * host,const char * original_host,Options * options,int flags,int * want_final_pass)222236e94dc5SPeter Avalos read_config_file(const char *filename, struct passwd *pw, const char *host,
2223664f4763Szrj     const char *original_host, Options *options, int flags,
2224664f4763Szrj     int *want_final_pass)
2225e9778795SPeter Avalos {
2226e9778795SPeter Avalos 	int active = 1;
2227e9778795SPeter Avalos 
2228e9778795SPeter Avalos 	return read_config_file_depth(filename, pw, host, original_host,
2229664f4763Szrj 	    options, flags, &active, want_final_pass, 0);
2230e9778795SPeter Avalos }
2231e9778795SPeter Avalos 
2232e9778795SPeter Avalos #define READCONF_MAX_DEPTH	16
2233e9778795SPeter Avalos static int
read_config_file_depth(const char * filename,struct passwd * pw,const char * host,const char * original_host,Options * options,int flags,int * activep,int * want_final_pass,int depth)2234e9778795SPeter Avalos read_config_file_depth(const char *filename, struct passwd *pw,
2235e9778795SPeter Avalos     const char *host, const char *original_host, Options *options,
2236664f4763Szrj     int flags, int *activep, int *want_final_pass, int depth)
223718de8d7fSPeter Avalos {
223818de8d7fSPeter Avalos 	FILE *f;
2239664f4763Szrj 	char *line = NULL;
2240664f4763Szrj 	size_t linesize = 0;
2241e9778795SPeter Avalos 	int linenum;
224218de8d7fSPeter Avalos 	int bad_options = 0;
224318de8d7fSPeter Avalos 
2244e9778795SPeter Avalos 	if (depth < 0 || depth > READCONF_MAX_DEPTH)
2245e9778795SPeter Avalos 		fatal("Too many recursive configuration includes");
2246e9778795SPeter Avalos 
224718de8d7fSPeter Avalos 	if ((f = fopen(filename, "r")) == NULL)
224818de8d7fSPeter Avalos 		return 0;
224918de8d7fSPeter Avalos 
225036e94dc5SPeter Avalos 	if (flags & SSHCONF_CHECKPERM) {
225118de8d7fSPeter Avalos 		struct stat sb;
225218de8d7fSPeter Avalos 
225318de8d7fSPeter Avalos 		if (fstat(fileno(f), &sb) == -1)
225418de8d7fSPeter Avalos 			fatal("fstat %s: %s", filename, strerror(errno));
225518de8d7fSPeter Avalos 		if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
225618de8d7fSPeter Avalos 		    (sb.st_mode & 022) != 0))
225718de8d7fSPeter Avalos 			fatal("Bad owner or permissions on %s", filename);
225818de8d7fSPeter Avalos 	}
225918de8d7fSPeter Avalos 
226018de8d7fSPeter Avalos 	debug("Reading configuration data %.200s", filename);
226118de8d7fSPeter Avalos 
226218de8d7fSPeter Avalos 	/*
226318de8d7fSPeter Avalos 	 * Mark that we are now processing the options.  This flag is turned
226418de8d7fSPeter Avalos 	 * on/off by Host specifications.
226518de8d7fSPeter Avalos 	 */
226618de8d7fSPeter Avalos 	linenum = 0;
2267664f4763Szrj 	while (getline(&line, &linesize, f) != -1) {
226818de8d7fSPeter Avalos 		/* Update line number counter. */
226918de8d7fSPeter Avalos 		linenum++;
227050a69bb5SSascha Wildner 		/*
227150a69bb5SSascha Wildner 		 * Trim out comments and strip whitespace.
227250a69bb5SSascha Wildner 		 * NB - preserve newlines, they are needed to reproduce
227350a69bb5SSascha Wildner 		 * line numbers later for error messages.
227450a69bb5SSascha Wildner 		 */
2275e9778795SPeter Avalos 		if (process_config_line_depth(options, pw, host, original_host,
2276664f4763Szrj 		    line, filename, linenum, activep, flags, want_final_pass,
2277664f4763Szrj 		    depth) != 0)
227818de8d7fSPeter Avalos 			bad_options++;
227918de8d7fSPeter Avalos 	}
2280664f4763Szrj 	free(line);
228118de8d7fSPeter Avalos 	fclose(f);
228218de8d7fSPeter Avalos 	if (bad_options > 0)
228318de8d7fSPeter Avalos 		fatal("%s: terminating, %d bad configuration options",
228418de8d7fSPeter Avalos 		    filename, bad_options);
228518de8d7fSPeter Avalos 	return 1;
228618de8d7fSPeter Avalos }
228718de8d7fSPeter Avalos 
228836e94dc5SPeter Avalos /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
228936e94dc5SPeter Avalos int
option_clear_or_none(const char * o)229036e94dc5SPeter Avalos option_clear_or_none(const char *o)
229136e94dc5SPeter Avalos {
229236e94dc5SPeter Avalos 	return o == NULL || strcasecmp(o, "none") == 0;
229336e94dc5SPeter Avalos }
229436e94dc5SPeter Avalos 
229518de8d7fSPeter Avalos /*
229650a69bb5SSascha Wildner  * Returns 1 if CanonicalizePermittedCNAMEs have been specified, 0 otherwise.
229750a69bb5SSascha Wildner  * Allowed to be called on non-final configuration.
229850a69bb5SSascha Wildner  */
229950a69bb5SSascha Wildner int
config_has_permitted_cnames(Options * options)230050a69bb5SSascha Wildner config_has_permitted_cnames(Options *options)
230150a69bb5SSascha Wildner {
230250a69bb5SSascha Wildner 	if (options->num_permitted_cnames == 1 &&
230350a69bb5SSascha Wildner 	    strcasecmp(options->permitted_cnames[0].source_list, "none") == 0 &&
230450a69bb5SSascha Wildner 	    strcmp(options->permitted_cnames[0].target_list, "") == 0)
230550a69bb5SSascha Wildner 		return 0;
230650a69bb5SSascha Wildner 	return options->num_permitted_cnames > 0;
230750a69bb5SSascha Wildner }
230850a69bb5SSascha Wildner 
230950a69bb5SSascha Wildner /*
231018de8d7fSPeter Avalos  * Initializes options to special values that indicate that they have not yet
231118de8d7fSPeter Avalos  * been set.  Read_config_file will only set options with this value. Options
231218de8d7fSPeter Avalos  * are processed in the following order: command line, user config file,
231318de8d7fSPeter Avalos  * system config file.  Last, fill_default_options is called.
231418de8d7fSPeter Avalos  */
231518de8d7fSPeter Avalos 
231618de8d7fSPeter Avalos void
initialize_options(Options * options)231718de8d7fSPeter Avalos initialize_options(Options * options)
231818de8d7fSPeter Avalos {
231918de8d7fSPeter Avalos 	memset(options, 'X', sizeof(*options));
232018de8d7fSPeter Avalos 	options->forward_agent = -1;
23210cbfa66cSDaniel Fojt 	options->forward_agent_sock_path = NULL;
232218de8d7fSPeter Avalos 	options->forward_x11 = -1;
232318de8d7fSPeter Avalos 	options->forward_x11_trusted = -1;
2324856ea928SPeter Avalos 	options->forward_x11_timeout = -1;
2325e9778795SPeter Avalos 	options->stdio_forward_host = NULL;
2326e9778795SPeter Avalos 	options->stdio_forward_port = 0;
2327e9778795SPeter Avalos 	options->clear_forwardings = -1;
232818de8d7fSPeter Avalos 	options->exit_on_forward_failure = -1;
232918de8d7fSPeter Avalos 	options->xauth_location = NULL;
233036e94dc5SPeter Avalos 	options->fwd_opts.gateway_ports = -1;
233136e94dc5SPeter Avalos 	options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
233236e94dc5SPeter Avalos 	options->fwd_opts.streamlocal_bind_unlink = -1;
233318de8d7fSPeter Avalos 	options->pubkey_authentication = -1;
233418de8d7fSPeter Avalos 	options->gss_authentication = -1;
233518de8d7fSPeter Avalos 	options->gss_deleg_creds = -1;
233618de8d7fSPeter Avalos 	options->password_authentication = -1;
233718de8d7fSPeter Avalos 	options->kbd_interactive_authentication = -1;
233818de8d7fSPeter Avalos 	options->kbd_interactive_devices = NULL;
233918de8d7fSPeter Avalos 	options->hostbased_authentication = -1;
234018de8d7fSPeter Avalos 	options->batch_mode = -1;
234118de8d7fSPeter Avalos 	options->check_host_ip = -1;
234218de8d7fSPeter Avalos 	options->strict_host_key_checking = -1;
234318de8d7fSPeter Avalos 	options->compression = -1;
234418de8d7fSPeter Avalos 	options->tcp_keep_alive = -1;
234518de8d7fSPeter Avalos 	options->port = -1;
234618de8d7fSPeter Avalos 	options->address_family = -1;
234718de8d7fSPeter Avalos 	options->connection_attempts = -1;
234818de8d7fSPeter Avalos 	options->connection_timeout = -1;
234918de8d7fSPeter Avalos 	options->number_of_password_prompts = -1;
235018de8d7fSPeter Avalos 	options->ciphers = NULL;
235118de8d7fSPeter Avalos 	options->macs = NULL;
23529f304aafSPeter Avalos 	options->kex_algorithms = NULL;
235318de8d7fSPeter Avalos 	options->hostkeyalgorithms = NULL;
2354664f4763Szrj 	options->ca_sign_algorithms = NULL;
235518de8d7fSPeter Avalos 	options->num_identity_files = 0;
235650a69bb5SSascha Wildner 	memset(options->identity_keys, 0, sizeof(options->identity_keys));
2357e9778795SPeter Avalos 	options->num_certificate_files = 0;
235850a69bb5SSascha Wildner 	memset(options->certificates, 0, sizeof(options->certificates));
235918de8d7fSPeter Avalos 	options->hostname = NULL;
236018de8d7fSPeter Avalos 	options->host_key_alias = NULL;
236118de8d7fSPeter Avalos 	options->proxy_command = NULL;
2362e9778795SPeter Avalos 	options->jump_user = NULL;
2363e9778795SPeter Avalos 	options->jump_host = NULL;
2364e9778795SPeter Avalos 	options->jump_port = -1;
2365e9778795SPeter Avalos 	options->jump_extra = NULL;
236618de8d7fSPeter Avalos 	options->user = NULL;
236718de8d7fSPeter Avalos 	options->escape_char = -1;
23681c188a7fSPeter Avalos 	options->num_system_hostfiles = 0;
23691c188a7fSPeter Avalos 	options->num_user_hostfiles = 0;
2370856ea928SPeter Avalos 	options->local_forwards = NULL;
237118de8d7fSPeter Avalos 	options->num_local_forwards = 0;
2372856ea928SPeter Avalos 	options->remote_forwards = NULL;
237318de8d7fSPeter Avalos 	options->num_remote_forwards = 0;
237450a69bb5SSascha Wildner 	options->permitted_remote_opens = NULL;
237550a69bb5SSascha Wildner 	options->num_permitted_remote_opens = 0;
2376ce74bacaSMatthew Dillon 	options->log_facility = SYSLOG_FACILITY_NOT_SET;
237718de8d7fSPeter Avalos 	options->log_level = SYSLOG_LEVEL_NOT_SET;
237850a69bb5SSascha Wildner 	options->num_log_verbose = 0;
237950a69bb5SSascha Wildner 	options->log_verbose = NULL;
238018de8d7fSPeter Avalos 	options->preferred_authentications = NULL;
238118de8d7fSPeter Avalos 	options->bind_address = NULL;
2382664f4763Szrj 	options->bind_interface = NULL;
2383856ea928SPeter Avalos 	options->pkcs11_provider = NULL;
23840cbfa66cSDaniel Fojt 	options->sk_provider = NULL;
238518de8d7fSPeter Avalos 	options->enable_ssh_keysign = - 1;
238618de8d7fSPeter Avalos 	options->no_host_authentication_for_localhost = - 1;
238718de8d7fSPeter Avalos 	options->identities_only = - 1;
238818de8d7fSPeter Avalos 	options->rekey_limit = - 1;
238936e94dc5SPeter Avalos 	options->rekey_interval = -1;
239018de8d7fSPeter Avalos 	options->verify_host_key_dns = -1;
239118de8d7fSPeter Avalos 	options->server_alive_interval = -1;
239218de8d7fSPeter Avalos 	options->server_alive_count_max = -1;
2393664f4763Szrj 	options->send_env = NULL;
239418de8d7fSPeter Avalos 	options->num_send_env = 0;
2395664f4763Szrj 	options->setenv = NULL;
2396664f4763Szrj 	options->num_setenv = 0;
239718de8d7fSPeter Avalos 	options->control_path = NULL;
239818de8d7fSPeter Avalos 	options->control_master = -1;
2399856ea928SPeter Avalos 	options->control_persist = -1;
2400856ea928SPeter Avalos 	options->control_persist_timeout = 0;
240118de8d7fSPeter Avalos 	options->hash_known_hosts = -1;
240218de8d7fSPeter Avalos 	options->tun_open = -1;
240318de8d7fSPeter Avalos 	options->tun_local = -1;
240418de8d7fSPeter Avalos 	options->tun_remote = -1;
240518de8d7fSPeter Avalos 	options->local_command = NULL;
240618de8d7fSPeter Avalos 	options->permit_local_command = -1;
2407ce74bacaSMatthew Dillon 	options->remote_command = NULL;
2408e9778795SPeter Avalos 	options->add_keys_to_agent = -1;
240950a69bb5SSascha Wildner 	options->add_keys_to_agent_lifespan = -1;
2410e9778795SPeter Avalos 	options->identity_agent = NULL;
241118de8d7fSPeter Avalos 	options->visual_host_key = -1;
24129f304aafSPeter Avalos 	options->ip_qos_interactive = -1;
24139f304aafSPeter Avalos 	options->ip_qos_bulk = -1;
24141c188a7fSPeter Avalos 	options->request_tty = -1;
241550a69bb5SSascha Wildner 	options->session_type = -1;
241650a69bb5SSascha Wildner 	options->stdin_null = -1;
241750a69bb5SSascha Wildner 	options->fork_after_authentication = -1;
241836e94dc5SPeter Avalos 	options->proxy_use_fdpass = -1;
241936e94dc5SPeter Avalos 	options->ignored_unknown = NULL;
242036e94dc5SPeter Avalos 	options->num_canonical_domains = 0;
242136e94dc5SPeter Avalos 	options->num_permitted_cnames = 0;
242236e94dc5SPeter Avalos 	options->canonicalize_max_dots = -1;
242336e94dc5SPeter Avalos 	options->canonicalize_fallback_local = -1;
242436e94dc5SPeter Avalos 	options->canonicalize_hostname = -1;
2425e9778795SPeter Avalos 	options->revoked_host_keys = NULL;
2426e9778795SPeter Avalos 	options->fingerprint_hash = -1;
2427e9778795SPeter Avalos 	options->update_hostkeys = -1;
242850a69bb5SSascha Wildner 	options->hostbased_accepted_algos = NULL;
242950a69bb5SSascha Wildner 	options->pubkey_accepted_algos = NULL;
243050a69bb5SSascha Wildner 	options->known_hosts_command = NULL;
2431*ee116499SAntonio Huete Jimenez 	options->required_rsa_size = -1;
243236e94dc5SPeter Avalos }
243336e94dc5SPeter Avalos 
243436e94dc5SPeter Avalos /*
243536e94dc5SPeter Avalos  * A petite version of fill_default_options() that just fills the options
243636e94dc5SPeter Avalos  * needed for hostname canonicalization to proceed.
243736e94dc5SPeter Avalos  */
243836e94dc5SPeter Avalos void
fill_default_options_for_canonicalization(Options * options)243936e94dc5SPeter Avalos fill_default_options_for_canonicalization(Options *options)
244036e94dc5SPeter Avalos {
244136e94dc5SPeter Avalos 	if (options->canonicalize_max_dots == -1)
244236e94dc5SPeter Avalos 		options->canonicalize_max_dots = 1;
244336e94dc5SPeter Avalos 	if (options->canonicalize_fallback_local == -1)
244436e94dc5SPeter Avalos 		options->canonicalize_fallback_local = 1;
244536e94dc5SPeter Avalos 	if (options->canonicalize_hostname == -1)
244636e94dc5SPeter Avalos 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
244718de8d7fSPeter Avalos }
244818de8d7fSPeter Avalos 
244918de8d7fSPeter Avalos /*
245018de8d7fSPeter Avalos  * Called after processing other sources of option data, this fills those
245118de8d7fSPeter Avalos  * options for which no value has been specified with their default values.
245218de8d7fSPeter Avalos  */
245350a69bb5SSascha Wildner int
fill_default_options(Options * options)245418de8d7fSPeter Avalos fill_default_options(Options * options)
245518de8d7fSPeter Avalos {
2456664f4763Szrj 	char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
24570cbfa66cSDaniel Fojt 	char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
245850a69bb5SSascha Wildner 	int ret = 0, r;
2459664f4763Szrj 
246018de8d7fSPeter Avalos 	if (options->forward_agent == -1)
246118de8d7fSPeter Avalos 		options->forward_agent = 0;
246218de8d7fSPeter Avalos 	if (options->forward_x11 == -1)
246318de8d7fSPeter Avalos 		options->forward_x11 = 0;
246418de8d7fSPeter Avalos 	if (options->forward_x11_trusted == -1)
246518de8d7fSPeter Avalos 		options->forward_x11_trusted = 0;
2466856ea928SPeter Avalos 	if (options->forward_x11_timeout == -1)
2467856ea928SPeter Avalos 		options->forward_x11_timeout = 1200;
2468e9778795SPeter Avalos 	/*
2469e9778795SPeter Avalos 	 * stdio forwarding (-W) changes the default for these but we defer
2470e9778795SPeter Avalos 	 * setting the values so they can be overridden.
2471e9778795SPeter Avalos 	 */
247218de8d7fSPeter Avalos 	if (options->exit_on_forward_failure == -1)
2473e9778795SPeter Avalos 		options->exit_on_forward_failure =
2474e9778795SPeter Avalos 		    options->stdio_forward_host != NULL ? 1 : 0;
2475e9778795SPeter Avalos 	if (options->clear_forwardings == -1)
2476e9778795SPeter Avalos 		options->clear_forwardings =
2477e9778795SPeter Avalos 		    options->stdio_forward_host != NULL ? 1 : 0;
2478e9778795SPeter Avalos 	if (options->clear_forwardings == 1)
2479e9778795SPeter Avalos 		clear_forwardings(options);
2480e9778795SPeter Avalos 
248118de8d7fSPeter Avalos 	if (options->xauth_location == NULL)
248250a69bb5SSascha Wildner 		options->xauth_location = xstrdup(_PATH_XAUTH);
248336e94dc5SPeter Avalos 	if (options->fwd_opts.gateway_ports == -1)
248436e94dc5SPeter Avalos 		options->fwd_opts.gateway_ports = 0;
248536e94dc5SPeter Avalos 	if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
248636e94dc5SPeter Avalos 		options->fwd_opts.streamlocal_bind_mask = 0177;
248736e94dc5SPeter Avalos 	if (options->fwd_opts.streamlocal_bind_unlink == -1)
248836e94dc5SPeter Avalos 		options->fwd_opts.streamlocal_bind_unlink = 0;
248918de8d7fSPeter Avalos 	if (options->pubkey_authentication == -1)
2490*ee116499SAntonio Huete Jimenez 		options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL;
249118de8d7fSPeter Avalos 	if (options->gss_authentication == -1)
249218de8d7fSPeter Avalos 		options->gss_authentication = 0;
249318de8d7fSPeter Avalos 	if (options->gss_deleg_creds == -1)
249418de8d7fSPeter Avalos 		options->gss_deleg_creds = 0;
249518de8d7fSPeter Avalos 	if (options->password_authentication == -1)
249618de8d7fSPeter Avalos 		options->password_authentication = 1;
249718de8d7fSPeter Avalos 	if (options->kbd_interactive_authentication == -1)
249818de8d7fSPeter Avalos 		options->kbd_interactive_authentication = 1;
249918de8d7fSPeter Avalos 	if (options->hostbased_authentication == -1)
250018de8d7fSPeter Avalos 		options->hostbased_authentication = 0;
250118de8d7fSPeter Avalos 	if (options->batch_mode == -1)
250218de8d7fSPeter Avalos 		options->batch_mode = 0;
250318de8d7fSPeter Avalos 	if (options->check_host_ip == -1)
250450a69bb5SSascha Wildner 		options->check_host_ip = 0;
250518de8d7fSPeter Avalos 	if (options->strict_host_key_checking == -1)
2506ce74bacaSMatthew Dillon 		options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK;
250718de8d7fSPeter Avalos 	if (options->compression == -1)
250818de8d7fSPeter Avalos 		options->compression = 0;
250918de8d7fSPeter Avalos 	if (options->tcp_keep_alive == -1)
251018de8d7fSPeter Avalos 		options->tcp_keep_alive = 1;
251118de8d7fSPeter Avalos 	if (options->port == -1)
251218de8d7fSPeter Avalos 		options->port = 0;	/* Filled in ssh_connect. */
251318de8d7fSPeter Avalos 	if (options->address_family == -1)
251418de8d7fSPeter Avalos 		options->address_family = AF_UNSPEC;
251518de8d7fSPeter Avalos 	if (options->connection_attempts == -1)
251618de8d7fSPeter Avalos 		options->connection_attempts = 1;
251718de8d7fSPeter Avalos 	if (options->number_of_password_prompts == -1)
251818de8d7fSPeter Avalos 		options->number_of_password_prompts = 3;
251918de8d7fSPeter Avalos 	/* options->hostkeyalgorithms, default set in myproposals.h */
252050a69bb5SSascha Wildner 	if (options->add_keys_to_agent == -1) {
2521e9778795SPeter Avalos 		options->add_keys_to_agent = 0;
252250a69bb5SSascha Wildner 		options->add_keys_to_agent_lifespan = 0;
252350a69bb5SSascha Wildner 	}
252418de8d7fSPeter Avalos 	if (options->num_identity_files == 0) {
2525ce74bacaSMatthew Dillon 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0);
25269f304aafSPeter Avalos #ifdef OPENSSL_HAS_ECC
2527ce74bacaSMatthew Dillon 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
25280cbfa66cSDaniel Fojt 		add_identity_file(options, "~/",
25290cbfa66cSDaniel Fojt 		    _PATH_SSH_CLIENT_ID_ECDSA_SK, 0);
25309f304aafSPeter Avalos #endif
253136e94dc5SPeter Avalos 		add_identity_file(options, "~/",
253236e94dc5SPeter Avalos 		    _PATH_SSH_CLIENT_ID_ED25519, 0);
25330cbfa66cSDaniel Fojt 		add_identity_file(options, "~/",
25340cbfa66cSDaniel Fojt 		    _PATH_SSH_CLIENT_ID_ED25519_SK, 0);
2535664f4763Szrj 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0);
2536*ee116499SAntonio Huete Jimenez 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0);
253718de8d7fSPeter Avalos 	}
253818de8d7fSPeter Avalos 	if (options->escape_char == -1)
253918de8d7fSPeter Avalos 		options->escape_char = '~';
25401c188a7fSPeter Avalos 	if (options->num_system_hostfiles == 0) {
25411c188a7fSPeter Avalos 		options->system_hostfiles[options->num_system_hostfiles++] =
25421c188a7fSPeter Avalos 		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
25431c188a7fSPeter Avalos 		options->system_hostfiles[options->num_system_hostfiles++] =
25441c188a7fSPeter Avalos 		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
25451c188a7fSPeter Avalos 	}
254650a69bb5SSascha Wildner 	if (options->update_hostkeys == -1) {
254750a69bb5SSascha Wildner 		if (options->verify_host_key_dns <= 0 &&
254850a69bb5SSascha Wildner 		    (options->num_user_hostfiles == 0 ||
254950a69bb5SSascha Wildner 		    (options->num_user_hostfiles == 1 && strcmp(options->
255050a69bb5SSascha Wildner 		    user_hostfiles[0], _PATH_SSH_USER_HOSTFILE) == 0)))
255150a69bb5SSascha Wildner 			options->update_hostkeys = SSH_UPDATE_HOSTKEYS_YES;
255250a69bb5SSascha Wildner 		else
25530cbfa66cSDaniel Fojt 			options->update_hostkeys = SSH_UPDATE_HOSTKEYS_NO;
255450a69bb5SSascha Wildner 	}
25551c188a7fSPeter Avalos 	if (options->num_user_hostfiles == 0) {
25561c188a7fSPeter Avalos 		options->user_hostfiles[options->num_user_hostfiles++] =
25571c188a7fSPeter Avalos 		    xstrdup(_PATH_SSH_USER_HOSTFILE);
25581c188a7fSPeter Avalos 		options->user_hostfiles[options->num_user_hostfiles++] =
25591c188a7fSPeter Avalos 		    xstrdup(_PATH_SSH_USER_HOSTFILE2);
25601c188a7fSPeter Avalos 	}
256118de8d7fSPeter Avalos 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
256218de8d7fSPeter Avalos 		options->log_level = SYSLOG_LEVEL_INFO;
2563ce74bacaSMatthew Dillon 	if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
2564ce74bacaSMatthew Dillon 		options->log_facility = SYSLOG_FACILITY_USER;
256518de8d7fSPeter Avalos 	if (options->no_host_authentication_for_localhost == - 1)
256618de8d7fSPeter Avalos 		options->no_host_authentication_for_localhost = 0;
256718de8d7fSPeter Avalos 	if (options->identities_only == -1)
256818de8d7fSPeter Avalos 		options->identities_only = 0;
256918de8d7fSPeter Avalos 	if (options->enable_ssh_keysign == -1)
257018de8d7fSPeter Avalos 		options->enable_ssh_keysign = 0;
257118de8d7fSPeter Avalos 	if (options->rekey_limit == -1)
257218de8d7fSPeter Avalos 		options->rekey_limit = 0;
257336e94dc5SPeter Avalos 	if (options->rekey_interval == -1)
257436e94dc5SPeter Avalos 		options->rekey_interval = 0;
257518de8d7fSPeter Avalos 	if (options->verify_host_key_dns == -1)
257618de8d7fSPeter Avalos 		options->verify_host_key_dns = 0;
257718de8d7fSPeter Avalos 	if (options->server_alive_interval == -1)
257818de8d7fSPeter Avalos 		options->server_alive_interval = 0;
257918de8d7fSPeter Avalos 	if (options->server_alive_count_max == -1)
258018de8d7fSPeter Avalos 		options->server_alive_count_max = 3;
258118de8d7fSPeter Avalos 	if (options->control_master == -1)
258218de8d7fSPeter Avalos 		options->control_master = 0;
2583856ea928SPeter Avalos 	if (options->control_persist == -1) {
2584856ea928SPeter Avalos 		options->control_persist = 0;
2585856ea928SPeter Avalos 		options->control_persist_timeout = 0;
2586856ea928SPeter Avalos 	}
258718de8d7fSPeter Avalos 	if (options->hash_known_hosts == -1)
258818de8d7fSPeter Avalos 		options->hash_known_hosts = 0;
258918de8d7fSPeter Avalos 	if (options->tun_open == -1)
259018de8d7fSPeter Avalos 		options->tun_open = SSH_TUNMODE_NO;
259118de8d7fSPeter Avalos 	if (options->tun_local == -1)
259218de8d7fSPeter Avalos 		options->tun_local = SSH_TUNID_ANY;
259318de8d7fSPeter Avalos 	if (options->tun_remote == -1)
259418de8d7fSPeter Avalos 		options->tun_remote = SSH_TUNID_ANY;
259518de8d7fSPeter Avalos 	if (options->permit_local_command == -1)
259618de8d7fSPeter Avalos 		options->permit_local_command = 0;
259718de8d7fSPeter Avalos 	if (options->visual_host_key == -1)
259818de8d7fSPeter Avalos 		options->visual_host_key = 0;
25999f304aafSPeter Avalos 	if (options->ip_qos_interactive == -1)
2600664f4763Szrj 		options->ip_qos_interactive = IPTOS_DSCP_AF21;
26019f304aafSPeter Avalos 	if (options->ip_qos_bulk == -1)
2602664f4763Szrj 		options->ip_qos_bulk = IPTOS_DSCP_CS1;
26031c188a7fSPeter Avalos 	if (options->request_tty == -1)
26041c188a7fSPeter Avalos 		options->request_tty = REQUEST_TTY_AUTO;
260550a69bb5SSascha Wildner 	if (options->session_type == -1)
260650a69bb5SSascha Wildner 		options->session_type = SESSION_TYPE_DEFAULT;
260750a69bb5SSascha Wildner 	if (options->stdin_null == -1)
260850a69bb5SSascha Wildner 		options->stdin_null = 0;
260950a69bb5SSascha Wildner 	if (options->fork_after_authentication == -1)
261050a69bb5SSascha Wildner 		options->fork_after_authentication = 0;
261136e94dc5SPeter Avalos 	if (options->proxy_use_fdpass == -1)
261236e94dc5SPeter Avalos 		options->proxy_use_fdpass = 0;
261336e94dc5SPeter Avalos 	if (options->canonicalize_max_dots == -1)
261436e94dc5SPeter Avalos 		options->canonicalize_max_dots = 1;
261536e94dc5SPeter Avalos 	if (options->canonicalize_fallback_local == -1)
261636e94dc5SPeter Avalos 		options->canonicalize_fallback_local = 1;
261736e94dc5SPeter Avalos 	if (options->canonicalize_hostname == -1)
261836e94dc5SPeter Avalos 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
2619e9778795SPeter Avalos 	if (options->fingerprint_hash == -1)
2620e9778795SPeter Avalos 		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
26210cbfa66cSDaniel Fojt #ifdef ENABLE_SK_INTERNAL
26220cbfa66cSDaniel Fojt 	if (options->sk_provider == NULL)
26230cbfa66cSDaniel Fojt 		options->sk_provider = xstrdup("internal");
26240cbfa66cSDaniel Fojt #else
26250cbfa66cSDaniel Fojt 	if (options->sk_provider == NULL)
26260cbfa66cSDaniel Fojt 		options->sk_provider = xstrdup("$SSH_SK_PROVIDER");
26270cbfa66cSDaniel Fojt #endif
2628*ee116499SAntonio Huete Jimenez 	if (options->required_rsa_size == -1)
2629*ee116499SAntonio Huete Jimenez 		options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
2630664f4763Szrj 
2631664f4763Szrj 	/* Expand KEX name lists */
2632664f4763Szrj 	all_cipher = cipher_alg_list(',', 0);
2633664f4763Szrj 	all_mac = mac_alg_list(',');
2634664f4763Szrj 	all_kex = kex_alg_list(',');
2635664f4763Szrj 	all_key = sshkey_alg_list(0, 0, 1, ',');
2636664f4763Szrj 	all_sig = sshkey_alg_list(0, 1, 1, ',');
26370cbfa66cSDaniel Fojt 	/* remove unsupported algos from default lists */
263850a69bb5SSascha Wildner 	def_cipher = match_filter_allowlist(KEX_CLIENT_ENCRYPT, all_cipher);
263950a69bb5SSascha Wildner 	def_mac = match_filter_allowlist(KEX_CLIENT_MAC, all_mac);
264050a69bb5SSascha Wildner 	def_kex = match_filter_allowlist(KEX_CLIENT_KEX, all_kex);
264150a69bb5SSascha Wildner 	def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
264250a69bb5SSascha Wildner 	def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
2643664f4763Szrj #define ASSEMBLE(what, defaults, all) \
2644664f4763Szrj 	do { \
2645664f4763Szrj 		if ((r = kex_assemble_names(&options->what, \
264650a69bb5SSascha Wildner 		    defaults, all)) != 0) { \
264750a69bb5SSascha Wildner 			error_fr(r, "%s", #what); \
264850a69bb5SSascha Wildner 			goto fail; \
264950a69bb5SSascha Wildner 		} \
2650664f4763Szrj 	} while (0)
26510cbfa66cSDaniel Fojt 	ASSEMBLE(ciphers, def_cipher, all_cipher);
26520cbfa66cSDaniel Fojt 	ASSEMBLE(macs, def_mac, all_mac);
26530cbfa66cSDaniel Fojt 	ASSEMBLE(kex_algorithms, def_kex, all_kex);
265450a69bb5SSascha Wildner 	ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
265550a69bb5SSascha Wildner 	ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
26560cbfa66cSDaniel Fojt 	ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
2657664f4763Szrj #undef ASSEMBLE
2658e9778795SPeter Avalos 
265936e94dc5SPeter Avalos #define CLEAR_ON_NONE(v) \
266036e94dc5SPeter Avalos 	do { \
266136e94dc5SPeter Avalos 		if (option_clear_or_none(v)) { \
266236e94dc5SPeter Avalos 			free(v); \
266336e94dc5SPeter Avalos 			v = NULL; \
266436e94dc5SPeter Avalos 		} \
266536e94dc5SPeter Avalos 	} while(0)
266636e94dc5SPeter Avalos 	CLEAR_ON_NONE(options->local_command);
2667ce74bacaSMatthew Dillon 	CLEAR_ON_NONE(options->remote_command);
266836e94dc5SPeter Avalos 	CLEAR_ON_NONE(options->proxy_command);
266936e94dc5SPeter Avalos 	CLEAR_ON_NONE(options->control_path);
2670e9778795SPeter Avalos 	CLEAR_ON_NONE(options->revoked_host_keys);
2671664f4763Szrj 	CLEAR_ON_NONE(options->pkcs11_provider);
26720cbfa66cSDaniel Fojt 	CLEAR_ON_NONE(options->sk_provider);
267350a69bb5SSascha Wildner 	CLEAR_ON_NONE(options->known_hosts_command);
2674664f4763Szrj 	if (options->jump_host != NULL &&
2675664f4763Szrj 	    strcmp(options->jump_host, "none") == 0 &&
2676664f4763Szrj 	    options->jump_port == 0 && options->jump_user == NULL) {
2677664f4763Szrj 		free(options->jump_host);
2678664f4763Szrj 		options->jump_host = NULL;
2679664f4763Szrj 	}
268050a69bb5SSascha Wildner 	if (options->num_permitted_cnames == 1 &&
268150a69bb5SSascha Wildner 	    !config_has_permitted_cnames(options)) {
268250a69bb5SSascha Wildner 		/* clean up CanonicalizePermittedCNAMEs=none */
268350a69bb5SSascha Wildner 		free(options->permitted_cnames[0].source_list);
268450a69bb5SSascha Wildner 		free(options->permitted_cnames[0].target_list);
268550a69bb5SSascha Wildner 		memset(options->permitted_cnames, '\0',
268650a69bb5SSascha Wildner 		    sizeof(*options->permitted_cnames));
268750a69bb5SSascha Wildner 		options->num_permitted_cnames = 0;
268850a69bb5SSascha Wildner 	}
2689e9778795SPeter Avalos 	/* options->identity_agent distinguishes NULL from 'none' */
269018de8d7fSPeter Avalos 	/* options->user will be set in the main program if appropriate */
269118de8d7fSPeter Avalos 	/* options->hostname will be set in the main program if appropriate */
269218de8d7fSPeter Avalos 	/* options->host_key_alias should not be set by default */
269318de8d7fSPeter Avalos 	/* options->preferred_authentications will be set in ssh */
269450a69bb5SSascha Wildner 
269550a69bb5SSascha Wildner 	/* success */
269650a69bb5SSascha Wildner 	ret = 0;
269750a69bb5SSascha Wildner  fail:
269850a69bb5SSascha Wildner 	free(all_cipher);
269950a69bb5SSascha Wildner 	free(all_mac);
270050a69bb5SSascha Wildner 	free(all_kex);
270150a69bb5SSascha Wildner 	free(all_key);
270250a69bb5SSascha Wildner 	free(all_sig);
270350a69bb5SSascha Wildner 	free(def_cipher);
270450a69bb5SSascha Wildner 	free(def_mac);
270550a69bb5SSascha Wildner 	free(def_kex);
270650a69bb5SSascha Wildner 	free(def_key);
270750a69bb5SSascha Wildner 	free(def_sig);
270850a69bb5SSascha Wildner 	return ret;
270950a69bb5SSascha Wildner }
271050a69bb5SSascha Wildner 
271150a69bb5SSascha Wildner void
free_options(Options * o)271250a69bb5SSascha Wildner free_options(Options *o)
271350a69bb5SSascha Wildner {
271450a69bb5SSascha Wildner 	int i;
271550a69bb5SSascha Wildner 
271650a69bb5SSascha Wildner 	if (o == NULL)
271750a69bb5SSascha Wildner 		return;
271850a69bb5SSascha Wildner 
271950a69bb5SSascha Wildner #define FREE_ARRAY(type, n, a) \
272050a69bb5SSascha Wildner 	do { \
272150a69bb5SSascha Wildner 		type _i; \
272250a69bb5SSascha Wildner 		for (_i = 0; _i < (n); _i++) \
272350a69bb5SSascha Wildner 			free((a)[_i]); \
272450a69bb5SSascha Wildner 	} while (0)
272550a69bb5SSascha Wildner 
272650a69bb5SSascha Wildner 	free(o->forward_agent_sock_path);
272750a69bb5SSascha Wildner 	free(o->xauth_location);
272850a69bb5SSascha Wildner 	FREE_ARRAY(u_int, o->num_log_verbose, o->log_verbose);
272950a69bb5SSascha Wildner 	free(o->log_verbose);
273050a69bb5SSascha Wildner 	free(o->ciphers);
273150a69bb5SSascha Wildner 	free(o->macs);
273250a69bb5SSascha Wildner 	free(o->hostkeyalgorithms);
273350a69bb5SSascha Wildner 	free(o->kex_algorithms);
273450a69bb5SSascha Wildner 	free(o->ca_sign_algorithms);
273550a69bb5SSascha Wildner 	free(o->hostname);
273650a69bb5SSascha Wildner 	free(o->host_key_alias);
273750a69bb5SSascha Wildner 	free(o->proxy_command);
273850a69bb5SSascha Wildner 	free(o->user);
273950a69bb5SSascha Wildner 	FREE_ARRAY(u_int, o->num_system_hostfiles, o->system_hostfiles);
274050a69bb5SSascha Wildner 	FREE_ARRAY(u_int, o->num_user_hostfiles, o->user_hostfiles);
274150a69bb5SSascha Wildner 	free(o->preferred_authentications);
274250a69bb5SSascha Wildner 	free(o->bind_address);
274350a69bb5SSascha Wildner 	free(o->bind_interface);
274450a69bb5SSascha Wildner 	free(o->pkcs11_provider);
274550a69bb5SSascha Wildner 	free(o->sk_provider);
274650a69bb5SSascha Wildner 	for (i = 0; i < o->num_identity_files; i++) {
274750a69bb5SSascha Wildner 		free(o->identity_files[i]);
274850a69bb5SSascha Wildner 		sshkey_free(o->identity_keys[i]);
274950a69bb5SSascha Wildner 	}
275050a69bb5SSascha Wildner 	for (i = 0; i < o->num_certificate_files; i++) {
275150a69bb5SSascha Wildner 		free(o->certificate_files[i]);
275250a69bb5SSascha Wildner 		sshkey_free(o->certificates[i]);
275350a69bb5SSascha Wildner 	}
275450a69bb5SSascha Wildner 	free(o->identity_agent);
275550a69bb5SSascha Wildner 	for (i = 0; i < o->num_local_forwards; i++) {
275650a69bb5SSascha Wildner 		free(o->local_forwards[i].listen_host);
275750a69bb5SSascha Wildner 		free(o->local_forwards[i].listen_path);
275850a69bb5SSascha Wildner 		free(o->local_forwards[i].connect_host);
275950a69bb5SSascha Wildner 		free(o->local_forwards[i].connect_path);
276050a69bb5SSascha Wildner 	}
276150a69bb5SSascha Wildner 	free(o->local_forwards);
276250a69bb5SSascha Wildner 	for (i = 0; i < o->num_remote_forwards; i++) {
276350a69bb5SSascha Wildner 		free(o->remote_forwards[i].listen_host);
276450a69bb5SSascha Wildner 		free(o->remote_forwards[i].listen_path);
276550a69bb5SSascha Wildner 		free(o->remote_forwards[i].connect_host);
276650a69bb5SSascha Wildner 		free(o->remote_forwards[i].connect_path);
276750a69bb5SSascha Wildner 	}
276850a69bb5SSascha Wildner 	free(o->remote_forwards);
276950a69bb5SSascha Wildner 	free(o->stdio_forward_host);
2770*ee116499SAntonio Huete Jimenez 	FREE_ARRAY(u_int, o->num_send_env, o->send_env);
277150a69bb5SSascha Wildner 	free(o->send_env);
2772*ee116499SAntonio Huete Jimenez 	FREE_ARRAY(u_int, o->num_setenv, o->setenv);
277350a69bb5SSascha Wildner 	free(o->setenv);
277450a69bb5SSascha Wildner 	free(o->control_path);
277550a69bb5SSascha Wildner 	free(o->local_command);
277650a69bb5SSascha Wildner 	free(o->remote_command);
277750a69bb5SSascha Wildner 	FREE_ARRAY(int, o->num_canonical_domains, o->canonical_domains);
277850a69bb5SSascha Wildner 	for (i = 0; i < o->num_permitted_cnames; i++) {
277950a69bb5SSascha Wildner 		free(o->permitted_cnames[i].source_list);
278050a69bb5SSascha Wildner 		free(o->permitted_cnames[i].target_list);
278150a69bb5SSascha Wildner 	}
278250a69bb5SSascha Wildner 	free(o->revoked_host_keys);
278350a69bb5SSascha Wildner 	free(o->hostbased_accepted_algos);
278450a69bb5SSascha Wildner 	free(o->pubkey_accepted_algos);
278550a69bb5SSascha Wildner 	free(o->jump_user);
278650a69bb5SSascha Wildner 	free(o->jump_host);
278750a69bb5SSascha Wildner 	free(o->jump_extra);
278850a69bb5SSascha Wildner 	free(o->ignored_unknown);
278950a69bb5SSascha Wildner 	explicit_bzero(o, sizeof(*o));
279050a69bb5SSascha Wildner #undef FREE_ARRAY
279118de8d7fSPeter Avalos }
279218de8d7fSPeter Avalos 
279336e94dc5SPeter Avalos struct fwdarg {
279436e94dc5SPeter Avalos 	char *arg;
279536e94dc5SPeter Avalos 	int ispath;
279636e94dc5SPeter Avalos };
279736e94dc5SPeter Avalos 
279836e94dc5SPeter Avalos /*
279936e94dc5SPeter Avalos  * parse_fwd_field
280036e94dc5SPeter Avalos  * parses the next field in a port forwarding specification.
280136e94dc5SPeter Avalos  * sets fwd to the parsed field and advances p past the colon
280236e94dc5SPeter Avalos  * or sets it to NULL at end of string.
280336e94dc5SPeter Avalos  * returns 0 on success, else non-zero.
280436e94dc5SPeter Avalos  */
280536e94dc5SPeter Avalos static int
parse_fwd_field(char ** p,struct fwdarg * fwd)280636e94dc5SPeter Avalos parse_fwd_field(char **p, struct fwdarg *fwd)
280736e94dc5SPeter Avalos {
280836e94dc5SPeter Avalos 	char *ep, *cp = *p;
280936e94dc5SPeter Avalos 	int ispath = 0;
281036e94dc5SPeter Avalos 
281136e94dc5SPeter Avalos 	if (*cp == '\0') {
281236e94dc5SPeter Avalos 		*p = NULL;
281336e94dc5SPeter Avalos 		return -1;	/* end of string */
281436e94dc5SPeter Avalos 	}
281536e94dc5SPeter Avalos 
281636e94dc5SPeter Avalos 	/*
281736e94dc5SPeter Avalos 	 * A field escaped with square brackets is used literally.
281836e94dc5SPeter Avalos 	 * XXX - allow ']' to be escaped via backslash?
281936e94dc5SPeter Avalos 	 */
282036e94dc5SPeter Avalos 	if (*cp == '[') {
282136e94dc5SPeter Avalos 		/* find matching ']' */
282236e94dc5SPeter Avalos 		for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
282336e94dc5SPeter Avalos 			if (*ep == '/')
282436e94dc5SPeter Avalos 				ispath = 1;
282536e94dc5SPeter Avalos 		}
282636e94dc5SPeter Avalos 		/* no matching ']' or not at end of field. */
282736e94dc5SPeter Avalos 		if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
282836e94dc5SPeter Avalos 			return -1;
282936e94dc5SPeter Avalos 		/* NUL terminate the field and advance p past the colon */
283036e94dc5SPeter Avalos 		*ep++ = '\0';
283136e94dc5SPeter Avalos 		if (*ep != '\0')
283236e94dc5SPeter Avalos 			*ep++ = '\0';
283336e94dc5SPeter Avalos 		fwd->arg = cp + 1;
283436e94dc5SPeter Avalos 		fwd->ispath = ispath;
283536e94dc5SPeter Avalos 		*p = ep;
283636e94dc5SPeter Avalos 		return 0;
283736e94dc5SPeter Avalos 	}
283836e94dc5SPeter Avalos 
283936e94dc5SPeter Avalos 	for (cp = *p; *cp != '\0'; cp++) {
284036e94dc5SPeter Avalos 		switch (*cp) {
284136e94dc5SPeter Avalos 		case '\\':
284236e94dc5SPeter Avalos 			memmove(cp, cp + 1, strlen(cp + 1) + 1);
2843e9778795SPeter Avalos 			if (*cp == '\0')
2844e9778795SPeter Avalos 				return -1;
284536e94dc5SPeter Avalos 			break;
284636e94dc5SPeter Avalos 		case '/':
284736e94dc5SPeter Avalos 			ispath = 1;
284836e94dc5SPeter Avalos 			break;
284936e94dc5SPeter Avalos 		case ':':
285036e94dc5SPeter Avalos 			*cp++ = '\0';
285136e94dc5SPeter Avalos 			goto done;
285236e94dc5SPeter Avalos 		}
285336e94dc5SPeter Avalos 	}
285436e94dc5SPeter Avalos done:
285536e94dc5SPeter Avalos 	fwd->arg = *p;
285636e94dc5SPeter Avalos 	fwd->ispath = ispath;
285736e94dc5SPeter Avalos 	*p = cp;
285836e94dc5SPeter Avalos 	return 0;
285936e94dc5SPeter Avalos }
286036e94dc5SPeter Avalos 
286118de8d7fSPeter Avalos /*
286218de8d7fSPeter Avalos  * parse_forward
286318de8d7fSPeter Avalos  * parses a string containing a port forwarding specification of the form:
2864cb5eb4f1SPeter Avalos  *   dynamicfwd == 0
286536e94dc5SPeter Avalos  *	[listenhost:]listenport|listenpath:connecthost:connectport|connectpath
286636e94dc5SPeter Avalos  *	listenpath:connectpath
2867cb5eb4f1SPeter Avalos  *   dynamicfwd == 1
2868cb5eb4f1SPeter Avalos  *	[listenhost:]listenport
286918de8d7fSPeter Avalos  * returns number of arguments parsed or zero on error
287018de8d7fSPeter Avalos  */
287118de8d7fSPeter Avalos int
parse_forward(struct Forward * fwd,const char * fwdspec,int dynamicfwd,int remotefwd)287236e94dc5SPeter Avalos parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
287318de8d7fSPeter Avalos {
287436e94dc5SPeter Avalos 	struct fwdarg fwdargs[4];
287536e94dc5SPeter Avalos 	char *p, *cp;
287650a69bb5SSascha Wildner 	int i, err;
287718de8d7fSPeter Avalos 
287836e94dc5SPeter Avalos 	memset(fwd, 0, sizeof(*fwd));
287936e94dc5SPeter Avalos 	memset(fwdargs, 0, sizeof(fwdargs));
288018de8d7fSPeter Avalos 
288150a69bb5SSascha Wildner 	/*
288250a69bb5SSascha Wildner 	 * We expand environment variables before checking if we think they're
288350a69bb5SSascha Wildner 	 * paths so that if ${VAR} expands to a fully qualified path it is
288450a69bb5SSascha Wildner 	 * treated as a path.
288550a69bb5SSascha Wildner 	 */
288650a69bb5SSascha Wildner 	cp = p = dollar_expand(&err, fwdspec);
288750a69bb5SSascha Wildner 	if (p == NULL || err)
288850a69bb5SSascha Wildner 		return 0;
288918de8d7fSPeter Avalos 
289018de8d7fSPeter Avalos 	/* skip leading spaces */
289136e94dc5SPeter Avalos 	while (isspace((u_char)*cp))
289218de8d7fSPeter Avalos 		cp++;
289318de8d7fSPeter Avalos 
289436e94dc5SPeter Avalos 	for (i = 0; i < 4; ++i) {
289536e94dc5SPeter Avalos 		if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
289618de8d7fSPeter Avalos 			break;
289736e94dc5SPeter Avalos 	}
289818de8d7fSPeter Avalos 
2899cb5eb4f1SPeter Avalos 	/* Check for trailing garbage */
290036e94dc5SPeter Avalos 	if (cp != NULL && *cp != '\0') {
290118de8d7fSPeter Avalos 		i = 0;	/* failure */
290236e94dc5SPeter Avalos 	}
290318de8d7fSPeter Avalos 
290418de8d7fSPeter Avalos 	switch (i) {
2905cb5eb4f1SPeter Avalos 	case 1:
290636e94dc5SPeter Avalos 		if (fwdargs[0].ispath) {
290736e94dc5SPeter Avalos 			fwd->listen_path = xstrdup(fwdargs[0].arg);
290836e94dc5SPeter Avalos 			fwd->listen_port = PORT_STREAMLOCAL;
290936e94dc5SPeter Avalos 		} else {
2910cb5eb4f1SPeter Avalos 			fwd->listen_host = NULL;
291136e94dc5SPeter Avalos 			fwd->listen_port = a2port(fwdargs[0].arg);
291236e94dc5SPeter Avalos 		}
2913cb5eb4f1SPeter Avalos 		fwd->connect_host = xstrdup("socks");
2914cb5eb4f1SPeter Avalos 		break;
2915cb5eb4f1SPeter Avalos 
2916cb5eb4f1SPeter Avalos 	case 2:
291736e94dc5SPeter Avalos 		if (fwdargs[0].ispath && fwdargs[1].ispath) {
291836e94dc5SPeter Avalos 			fwd->listen_path = xstrdup(fwdargs[0].arg);
291936e94dc5SPeter Avalos 			fwd->listen_port = PORT_STREAMLOCAL;
292036e94dc5SPeter Avalos 			fwd->connect_path = xstrdup(fwdargs[1].arg);
292136e94dc5SPeter Avalos 			fwd->connect_port = PORT_STREAMLOCAL;
292236e94dc5SPeter Avalos 		} else if (fwdargs[1].ispath) {
292336e94dc5SPeter Avalos 			fwd->listen_host = NULL;
292436e94dc5SPeter Avalos 			fwd->listen_port = a2port(fwdargs[0].arg);
292536e94dc5SPeter Avalos 			fwd->connect_path = xstrdup(fwdargs[1].arg);
292636e94dc5SPeter Avalos 			fwd->connect_port = PORT_STREAMLOCAL;
292736e94dc5SPeter Avalos 		} else {
292836e94dc5SPeter Avalos 			fwd->listen_host = xstrdup(fwdargs[0].arg);
292936e94dc5SPeter Avalos 			fwd->listen_port = a2port(fwdargs[1].arg);
2930cb5eb4f1SPeter Avalos 			fwd->connect_host = xstrdup("socks");
293136e94dc5SPeter Avalos 		}
2932cb5eb4f1SPeter Avalos 		break;
2933cb5eb4f1SPeter Avalos 
293418de8d7fSPeter Avalos 	case 3:
293536e94dc5SPeter Avalos 		if (fwdargs[0].ispath) {
293636e94dc5SPeter Avalos 			fwd->listen_path = xstrdup(fwdargs[0].arg);
293736e94dc5SPeter Avalos 			fwd->listen_port = PORT_STREAMLOCAL;
293836e94dc5SPeter Avalos 			fwd->connect_host = xstrdup(fwdargs[1].arg);
293936e94dc5SPeter Avalos 			fwd->connect_port = a2port(fwdargs[2].arg);
294036e94dc5SPeter Avalos 		} else if (fwdargs[2].ispath) {
294136e94dc5SPeter Avalos 			fwd->listen_host = xstrdup(fwdargs[0].arg);
294236e94dc5SPeter Avalos 			fwd->listen_port = a2port(fwdargs[1].arg);
294336e94dc5SPeter Avalos 			fwd->connect_path = xstrdup(fwdargs[2].arg);
294436e94dc5SPeter Avalos 			fwd->connect_port = PORT_STREAMLOCAL;
294536e94dc5SPeter Avalos 		} else {
294618de8d7fSPeter Avalos 			fwd->listen_host = NULL;
294736e94dc5SPeter Avalos 			fwd->listen_port = a2port(fwdargs[0].arg);
294836e94dc5SPeter Avalos 			fwd->connect_host = xstrdup(fwdargs[1].arg);
294936e94dc5SPeter Avalos 			fwd->connect_port = a2port(fwdargs[2].arg);
295036e94dc5SPeter Avalos 		}
295118de8d7fSPeter Avalos 		break;
295218de8d7fSPeter Avalos 
295318de8d7fSPeter Avalos 	case 4:
295436e94dc5SPeter Avalos 		fwd->listen_host = xstrdup(fwdargs[0].arg);
295536e94dc5SPeter Avalos 		fwd->listen_port = a2port(fwdargs[1].arg);
295636e94dc5SPeter Avalos 		fwd->connect_host = xstrdup(fwdargs[2].arg);
295736e94dc5SPeter Avalos 		fwd->connect_port = a2port(fwdargs[3].arg);
295818de8d7fSPeter Avalos 		break;
295918de8d7fSPeter Avalos 	default:
296018de8d7fSPeter Avalos 		i = 0; /* failure */
296118de8d7fSPeter Avalos 	}
296218de8d7fSPeter Avalos 
296336e94dc5SPeter Avalos 	free(p);
296418de8d7fSPeter Avalos 
2965cb5eb4f1SPeter Avalos 	if (dynamicfwd) {
2966cb5eb4f1SPeter Avalos 		if (!(i == 1 || i == 2))
2967cb5eb4f1SPeter Avalos 			goto fail_free;
2968cb5eb4f1SPeter Avalos 	} else {
296936e94dc5SPeter Avalos 		if (!(i == 3 || i == 4)) {
297036e94dc5SPeter Avalos 			if (fwd->connect_path == NULL &&
297136e94dc5SPeter Avalos 			    fwd->listen_path == NULL)
2972cb5eb4f1SPeter Avalos 				goto fail_free;
297336e94dc5SPeter Avalos 		}
297436e94dc5SPeter Avalos 		if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
2975cb5eb4f1SPeter Avalos 			goto fail_free;
2976cb5eb4f1SPeter Avalos 	}
2977cb5eb4f1SPeter Avalos 
297836e94dc5SPeter Avalos 	if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
297936e94dc5SPeter Avalos 	    (!remotefwd && fwd->listen_port == 0))
298018de8d7fSPeter Avalos 		goto fail_free;
298118de8d7fSPeter Avalos 	if (fwd->connect_host != NULL &&
298218de8d7fSPeter Avalos 	    strlen(fwd->connect_host) >= NI_MAXHOST)
298318de8d7fSPeter Avalos 		goto fail_free;
298450a69bb5SSascha Wildner 	/*
298550a69bb5SSascha Wildner 	 * XXX - if connecting to a remote socket, max sun len may not
298650a69bb5SSascha Wildner 	 * match this host
298750a69bb5SSascha Wildner 	 */
298836e94dc5SPeter Avalos 	if (fwd->connect_path != NULL &&
298936e94dc5SPeter Avalos 	    strlen(fwd->connect_path) >= PATH_MAX_SUN)
299036e94dc5SPeter Avalos 		goto fail_free;
2991cb5eb4f1SPeter Avalos 	if (fwd->listen_host != NULL &&
2992cb5eb4f1SPeter Avalos 	    strlen(fwd->listen_host) >= NI_MAXHOST)
2993cb5eb4f1SPeter Avalos 		goto fail_free;
299436e94dc5SPeter Avalos 	if (fwd->listen_path != NULL &&
299536e94dc5SPeter Avalos 	    strlen(fwd->listen_path) >= PATH_MAX_SUN)
299636e94dc5SPeter Avalos 		goto fail_free;
299718de8d7fSPeter Avalos 
299818de8d7fSPeter Avalos 	return (i);
299918de8d7fSPeter Avalos 
300018de8d7fSPeter Avalos  fail_free:
300136e94dc5SPeter Avalos 	free(fwd->connect_host);
3002cb5eb4f1SPeter Avalos 	fwd->connect_host = NULL;
300336e94dc5SPeter Avalos 	free(fwd->connect_path);
300436e94dc5SPeter Avalos 	fwd->connect_path = NULL;
300536e94dc5SPeter Avalos 	free(fwd->listen_host);
3006cb5eb4f1SPeter Avalos 	fwd->listen_host = NULL;
300736e94dc5SPeter Avalos 	free(fwd->listen_path);
300836e94dc5SPeter Avalos 	fwd->listen_path = NULL;
300918de8d7fSPeter Avalos 	return (0);
301018de8d7fSPeter Avalos }
3011e9778795SPeter Avalos 
3012e9778795SPeter Avalos int
parse_jump(const char * s,Options * o,int active)3013e9778795SPeter Avalos parse_jump(const char *s, Options *o, int active)
3014e9778795SPeter Avalos {
3015e9778795SPeter Avalos 	char *orig, *sdup, *cp;
3016e9778795SPeter Avalos 	char *host = NULL, *user = NULL;
301750a69bb5SSascha Wildner 	int r, ret = -1, port = -1, first;
3018e9778795SPeter Avalos 
3019e9778795SPeter Avalos 	active &= o->proxy_command == NULL && o->jump_host == NULL;
3020e9778795SPeter Avalos 
3021e9778795SPeter Avalos 	orig = sdup = xstrdup(s);
302250a69bb5SSascha Wildner 
302350a69bb5SSascha Wildner 	/* Remove comment and trailing whitespace */
302450a69bb5SSascha Wildner 	if ((cp = strchr(orig, '#')) != NULL)
302550a69bb5SSascha Wildner 		*cp = '\0';
302650a69bb5SSascha Wildner 	rtrim(orig);
302750a69bb5SSascha Wildner 
3028e9778795SPeter Avalos 	first = active;
3029e9778795SPeter Avalos 	do {
3030664f4763Szrj 		if (strcasecmp(s, "none") == 0)
3031664f4763Szrj 			break;
3032e9778795SPeter Avalos 		if ((cp = strrchr(sdup, ',')) == NULL)
3033e9778795SPeter Avalos 			cp = sdup; /* last */
3034e9778795SPeter Avalos 		else
3035e9778795SPeter Avalos 			*cp++ = '\0';
3036e9778795SPeter Avalos 
3037e9778795SPeter Avalos 		if (first) {
3038e9778795SPeter Avalos 			/* First argument and configuration is active */
303950a69bb5SSascha Wildner 			r = parse_ssh_uri(cp, &user, &host, &port);
304050a69bb5SSascha Wildner 			if (r == -1 || (r == 1 &&
304150a69bb5SSascha Wildner 			    parse_user_host_port(cp, &user, &host, &port) != 0))
3042e9778795SPeter Avalos 				goto out;
3043e9778795SPeter Avalos 		} else {
3044e9778795SPeter Avalos 			/* Subsequent argument or inactive configuration */
304550a69bb5SSascha Wildner 			r = parse_ssh_uri(cp, NULL, NULL, NULL);
304650a69bb5SSascha Wildner 			if (r == -1 || (r == 1 &&
304750a69bb5SSascha Wildner 			    parse_user_host_port(cp, NULL, NULL, NULL) != 0))
3048e9778795SPeter Avalos 				goto out;
3049e9778795SPeter Avalos 		}
3050e9778795SPeter Avalos 		first = 0; /* only check syntax for subsequent hosts */
3051e9778795SPeter Avalos 	} while (cp != sdup);
3052e9778795SPeter Avalos 	/* success */
3053e9778795SPeter Avalos 	if (active) {
3054664f4763Szrj 		if (strcasecmp(s, "none") == 0) {
3055664f4763Szrj 			o->jump_host = xstrdup("none");
3056664f4763Szrj 			o->jump_port = 0;
3057664f4763Szrj 		} else {
3058e9778795SPeter Avalos 			o->jump_user = user;
3059e9778795SPeter Avalos 			o->jump_host = host;
3060e9778795SPeter Avalos 			o->jump_port = port;
3061e9778795SPeter Avalos 			o->proxy_command = xstrdup("none");
3062e9778795SPeter Avalos 			user = host = NULL;
3063e9778795SPeter Avalos 			if ((cp = strrchr(s, ',')) != NULL && cp != s) {
3064e9778795SPeter Avalos 				o->jump_extra = xstrdup(s);
3065e9778795SPeter Avalos 				o->jump_extra[cp - s] = '\0';
3066e9778795SPeter Avalos 			}
3067e9778795SPeter Avalos 		}
3068664f4763Szrj 	}
3069e9778795SPeter Avalos 	ret = 0;
3070e9778795SPeter Avalos  out:
3071e9778795SPeter Avalos 	free(orig);
3072e9778795SPeter Avalos 	free(user);
3073e9778795SPeter Avalos 	free(host);
3074e9778795SPeter Avalos 	return ret;
3075e9778795SPeter Avalos }
3076e9778795SPeter Avalos 
3077664f4763Szrj int
parse_ssh_uri(const char * uri,char ** userp,char ** hostp,int * portp)3078664f4763Szrj parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
3079664f4763Szrj {
308050a69bb5SSascha Wildner 	char *user = NULL, *host = NULL, *path = NULL;
308150a69bb5SSascha Wildner 	int r, port;
3082664f4763Szrj 
308350a69bb5SSascha Wildner 	r = parse_uri("ssh", uri, &user, &host, &port, &path);
3084664f4763Szrj 	if (r == 0 && path != NULL)
3085664f4763Szrj 		r = -1;		/* path not allowed */
308650a69bb5SSascha Wildner 	if (r == 0) {
308750a69bb5SSascha Wildner 		if (userp != NULL) {
308850a69bb5SSascha Wildner 			*userp = user;
308950a69bb5SSascha Wildner 			user = NULL;
309050a69bb5SSascha Wildner 		}
309150a69bb5SSascha Wildner 		if (hostp != NULL) {
309250a69bb5SSascha Wildner 			*hostp = host;
309350a69bb5SSascha Wildner 			host = NULL;
309450a69bb5SSascha Wildner 		}
309550a69bb5SSascha Wildner 		if (portp != NULL)
309650a69bb5SSascha Wildner 			*portp = port;
309750a69bb5SSascha Wildner 	}
309850a69bb5SSascha Wildner 	free(user);
309950a69bb5SSascha Wildner 	free(host);
310050a69bb5SSascha Wildner 	free(path);
3101664f4763Szrj 	return r;
3102664f4763Szrj }
3103664f4763Szrj 
3104e9778795SPeter Avalos /* XXX the following is a near-vebatim copy from servconf.c; refactor */
3105e9778795SPeter Avalos static const char *
fmt_multistate_int(int val,const struct multistate * m)3106e9778795SPeter Avalos fmt_multistate_int(int val, const struct multistate *m)
3107e9778795SPeter Avalos {
3108e9778795SPeter Avalos 	u_int i;
3109e9778795SPeter Avalos 
3110e9778795SPeter Avalos 	for (i = 0; m[i].key != NULL; i++) {
3111e9778795SPeter Avalos 		if (m[i].value == val)
3112e9778795SPeter Avalos 			return m[i].key;
3113e9778795SPeter Avalos 	}
3114e9778795SPeter Avalos 	return "UNKNOWN";
3115e9778795SPeter Avalos }
3116e9778795SPeter Avalos 
3117e9778795SPeter Avalos static const char *
fmt_intarg(OpCodes code,int val)3118e9778795SPeter Avalos fmt_intarg(OpCodes code, int val)
3119e9778795SPeter Avalos {
3120e9778795SPeter Avalos 	if (val == -1)
3121e9778795SPeter Avalos 		return "unset";
3122e9778795SPeter Avalos 	switch (code) {
3123e9778795SPeter Avalos 	case oAddressFamily:
3124e9778795SPeter Avalos 		return fmt_multistate_int(val, multistate_addressfamily);
3125e9778795SPeter Avalos 	case oVerifyHostKeyDNS:
3126e9778795SPeter Avalos 	case oUpdateHostkeys:
3127e9778795SPeter Avalos 		return fmt_multistate_int(val, multistate_yesnoask);
3128ce74bacaSMatthew Dillon 	case oStrictHostKeyChecking:
3129ce74bacaSMatthew Dillon 		return fmt_multistate_int(val, multistate_strict_hostkey);
3130e9778795SPeter Avalos 	case oControlMaster:
3131e9778795SPeter Avalos 		return fmt_multistate_int(val, multistate_controlmaster);
3132e9778795SPeter Avalos 	case oTunnel:
3133e9778795SPeter Avalos 		return fmt_multistate_int(val, multistate_tunnel);
3134e9778795SPeter Avalos 	case oRequestTTY:
3135e9778795SPeter Avalos 		return fmt_multistate_int(val, multistate_requesttty);
313650a69bb5SSascha Wildner 	case oSessionType:
313750a69bb5SSascha Wildner 		return fmt_multistate_int(val, multistate_sessiontype);
3138e9778795SPeter Avalos 	case oCanonicalizeHostname:
3139e9778795SPeter Avalos 		return fmt_multistate_int(val, multistate_canonicalizehostname);
3140664f4763Szrj 	case oAddKeysToAgent:
3141664f4763Szrj 		return fmt_multistate_int(val, multistate_yesnoaskconfirm);
3142*ee116499SAntonio Huete Jimenez 	case oPubkeyAuthentication:
3143*ee116499SAntonio Huete Jimenez 		return fmt_multistate_int(val, multistate_pubkey_auth);
3144e9778795SPeter Avalos 	case oFingerprintHash:
3145e9778795SPeter Avalos 		return ssh_digest_alg_name(val);
3146e9778795SPeter Avalos 	default:
3147e9778795SPeter Avalos 		switch (val) {
3148e9778795SPeter Avalos 		case 0:
3149e9778795SPeter Avalos 			return "no";
3150e9778795SPeter Avalos 		case 1:
3151e9778795SPeter Avalos 			return "yes";
3152e9778795SPeter Avalos 		default:
3153e9778795SPeter Avalos 			return "UNKNOWN";
3154e9778795SPeter Avalos 		}
3155e9778795SPeter Avalos 	}
3156e9778795SPeter Avalos }
3157e9778795SPeter Avalos 
3158e9778795SPeter Avalos static const char *
lookup_opcode_name(OpCodes code)3159e9778795SPeter Avalos lookup_opcode_name(OpCodes code)
3160e9778795SPeter Avalos {
3161e9778795SPeter Avalos 	u_int i;
3162e9778795SPeter Avalos 
3163e9778795SPeter Avalos 	for (i = 0; keywords[i].name != NULL; i++)
3164e9778795SPeter Avalos 		if (keywords[i].opcode == code)
3165e9778795SPeter Avalos 			return(keywords[i].name);
3166e9778795SPeter Avalos 	return "UNKNOWN";
3167e9778795SPeter Avalos }
3168e9778795SPeter Avalos 
3169e9778795SPeter Avalos static void
dump_cfg_int(OpCodes code,int val)3170e9778795SPeter Avalos dump_cfg_int(OpCodes code, int val)
3171e9778795SPeter Avalos {
3172e9778795SPeter Avalos 	printf("%s %d\n", lookup_opcode_name(code), val);
3173e9778795SPeter Avalos }
3174e9778795SPeter Avalos 
3175e9778795SPeter Avalos static void
dump_cfg_fmtint(OpCodes code,int val)3176e9778795SPeter Avalos dump_cfg_fmtint(OpCodes code, int val)
3177e9778795SPeter Avalos {
3178e9778795SPeter Avalos 	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
3179e9778795SPeter Avalos }
3180e9778795SPeter Avalos 
3181e9778795SPeter Avalos static void
dump_cfg_string(OpCodes code,const char * val)3182e9778795SPeter Avalos dump_cfg_string(OpCodes code, const char *val)
3183e9778795SPeter Avalos {
3184e9778795SPeter Avalos 	if (val == NULL)
3185e9778795SPeter Avalos 		return;
3186e9778795SPeter Avalos 	printf("%s %s\n", lookup_opcode_name(code), val);
3187e9778795SPeter Avalos }
3188e9778795SPeter Avalos 
3189e9778795SPeter Avalos static void
dump_cfg_strarray(OpCodes code,u_int count,char ** vals)3190e9778795SPeter Avalos dump_cfg_strarray(OpCodes code, u_int count, char **vals)
3191e9778795SPeter Avalos {
3192e9778795SPeter Avalos 	u_int i;
3193e9778795SPeter Avalos 
3194e9778795SPeter Avalos 	for (i = 0; i < count; i++)
3195e9778795SPeter Avalos 		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
3196e9778795SPeter Avalos }
3197e9778795SPeter Avalos 
3198e9778795SPeter Avalos static void
dump_cfg_strarray_oneline(OpCodes code,u_int count,char ** vals)3199e9778795SPeter Avalos dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
3200e9778795SPeter Avalos {
3201e9778795SPeter Avalos 	u_int i;
3202e9778795SPeter Avalos 
3203e9778795SPeter Avalos 	printf("%s", lookup_opcode_name(code));
320450a69bb5SSascha Wildner 	if (count == 0)
320550a69bb5SSascha Wildner 		printf(" none");
3206e9778795SPeter Avalos 	for (i = 0; i < count; i++)
3207e9778795SPeter Avalos 		printf(" %s",  vals[i]);
3208e9778795SPeter Avalos 	printf("\n");
3209e9778795SPeter Avalos }
3210e9778795SPeter Avalos 
3211e9778795SPeter Avalos static void
dump_cfg_forwards(OpCodes code,u_int count,const struct Forward * fwds)3212e9778795SPeter Avalos dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
3213e9778795SPeter Avalos {
3214e9778795SPeter Avalos 	const struct Forward *fwd;
3215e9778795SPeter Avalos 	u_int i;
3216e9778795SPeter Avalos 
3217e9778795SPeter Avalos 	/* oDynamicForward */
3218e9778795SPeter Avalos 	for (i = 0; i < count; i++) {
3219e9778795SPeter Avalos 		fwd = &fwds[i];
3220ce74bacaSMatthew Dillon 		if (code == oDynamicForward && fwd->connect_host != NULL &&
3221e9778795SPeter Avalos 		    strcmp(fwd->connect_host, "socks") != 0)
3222e9778795SPeter Avalos 			continue;
3223ce74bacaSMatthew Dillon 		if (code == oLocalForward && fwd->connect_host != NULL &&
3224e9778795SPeter Avalos 		    strcmp(fwd->connect_host, "socks") == 0)
3225e9778795SPeter Avalos 			continue;
3226e9778795SPeter Avalos 		printf("%s", lookup_opcode_name(code));
3227e9778795SPeter Avalos 		if (fwd->listen_port == PORT_STREAMLOCAL)
3228e9778795SPeter Avalos 			printf(" %s", fwd->listen_path);
3229e9778795SPeter Avalos 		else if (fwd->listen_host == NULL)
3230e9778795SPeter Avalos 			printf(" %d", fwd->listen_port);
3231e9778795SPeter Avalos 		else {
3232e9778795SPeter Avalos 			printf(" [%s]:%d",
3233e9778795SPeter Avalos 			    fwd->listen_host, fwd->listen_port);
3234e9778795SPeter Avalos 		}
3235e9778795SPeter Avalos 		if (code != oDynamicForward) {
3236e9778795SPeter Avalos 			if (fwd->connect_port == PORT_STREAMLOCAL)
3237e9778795SPeter Avalos 				printf(" %s", fwd->connect_path);
3238e9778795SPeter Avalos 			else if (fwd->connect_host == NULL)
3239e9778795SPeter Avalos 				printf(" %d", fwd->connect_port);
3240e9778795SPeter Avalos 			else {
3241e9778795SPeter Avalos 				printf(" [%s]:%d",
3242e9778795SPeter Avalos 				    fwd->connect_host, fwd->connect_port);
3243e9778795SPeter Avalos 			}
3244e9778795SPeter Avalos 		}
3245e9778795SPeter Avalos 		printf("\n");
3246e9778795SPeter Avalos 	}
3247e9778795SPeter Avalos }
3248e9778795SPeter Avalos 
3249e9778795SPeter Avalos void
dump_client_config(Options * o,const char * host)3250e9778795SPeter Avalos dump_client_config(Options *o, const char *host)
3251e9778795SPeter Avalos {
32520cbfa66cSDaniel Fojt 	int i, r;
3253664f4763Szrj 	char buf[8], *all_key;
3254e9778795SPeter Avalos 
32550cbfa66cSDaniel Fojt 	/*
32560cbfa66cSDaniel Fojt 	 * Expand HostKeyAlgorithms name lists. This isn't handled in
32570cbfa66cSDaniel Fojt 	 * fill_default_options() like the other algorithm lists because
32580cbfa66cSDaniel Fojt 	 * the host key algorithms are by default dynamically chosen based
32590cbfa66cSDaniel Fojt 	 * on the host's keys found in known_hosts.
32600cbfa66cSDaniel Fojt 	 */
3261664f4763Szrj 	all_key = sshkey_alg_list(0, 0, 1, ',');
32620cbfa66cSDaniel Fojt 	if ((r = kex_assemble_names(&o->hostkeyalgorithms, kex_default_pk_alg(),
32630cbfa66cSDaniel Fojt 	    all_key)) != 0)
326450a69bb5SSascha Wildner 		fatal_fr(r, "expand HostKeyAlgorithms");
3265664f4763Szrj 	free(all_key);
3266e9778795SPeter Avalos 
3267e9778795SPeter Avalos 	/* Most interesting options first: user, host, port */
3268e9778795SPeter Avalos 	dump_cfg_string(oUser, o->user);
32690cbfa66cSDaniel Fojt 	dump_cfg_string(oHostname, host);
3270e9778795SPeter Avalos 	dump_cfg_int(oPort, o->port);
3271e9778795SPeter Avalos 
3272e9778795SPeter Avalos 	/* Flag options */
3273e9778795SPeter Avalos 	dump_cfg_fmtint(oAddressFamily, o->address_family);
3274e9778795SPeter Avalos 	dump_cfg_fmtint(oBatchMode, o->batch_mode);
3275e9778795SPeter Avalos 	dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
3276e9778795SPeter Avalos 	dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
3277e9778795SPeter Avalos 	dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
3278e9778795SPeter Avalos 	dump_cfg_fmtint(oCompression, o->compression);
3279e9778795SPeter Avalos 	dump_cfg_fmtint(oControlMaster, o->control_master);
3280e9778795SPeter Avalos 	dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
3281e9778795SPeter Avalos 	dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
3282e9778795SPeter Avalos 	dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
3283e9778795SPeter Avalos 	dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
3284e9778795SPeter Avalos 	dump_cfg_fmtint(oForwardX11, o->forward_x11);
3285e9778795SPeter Avalos 	dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
3286e9778795SPeter Avalos 	dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
3287e9778795SPeter Avalos #ifdef GSSAPI
3288e9778795SPeter Avalos 	dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
3289e9778795SPeter Avalos 	dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
3290e9778795SPeter Avalos #endif /* GSSAPI */
3291e9778795SPeter Avalos 	dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
3292e9778795SPeter Avalos 	dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
3293e9778795SPeter Avalos 	dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
3294e9778795SPeter Avalos 	dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
3295e9778795SPeter Avalos 	dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
3296e9778795SPeter Avalos 	dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
3297e9778795SPeter Avalos 	dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
3298e9778795SPeter Avalos 	dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
3299e9778795SPeter Avalos 	dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
3300e9778795SPeter Avalos 	dump_cfg_fmtint(oRequestTTY, o->request_tty);
330150a69bb5SSascha Wildner 	dump_cfg_fmtint(oSessionType, o->session_type);
330250a69bb5SSascha Wildner 	dump_cfg_fmtint(oStdinNull, o->stdin_null);
330350a69bb5SSascha Wildner 	dump_cfg_fmtint(oForkAfterAuthentication, o->fork_after_authentication);
3304e9778795SPeter Avalos 	dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
3305e9778795SPeter Avalos 	dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
3306e9778795SPeter Avalos 	dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
3307e9778795SPeter Avalos 	dump_cfg_fmtint(oTunnel, o->tun_open);
3308e9778795SPeter Avalos 	dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
3309e9778795SPeter Avalos 	dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
3310e9778795SPeter Avalos 	dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
3311e9778795SPeter Avalos 
3312e9778795SPeter Avalos 	/* Integer options */
3313e9778795SPeter Avalos 	dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
3314e9778795SPeter Avalos 	dump_cfg_int(oConnectionAttempts, o->connection_attempts);
3315e9778795SPeter Avalos 	dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
3316e9778795SPeter Avalos 	dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
3317e9778795SPeter Avalos 	dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
3318e9778795SPeter Avalos 	dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
3319*ee116499SAntonio Huete Jimenez 	dump_cfg_int(oRequiredRSASize, o->required_rsa_size);
3320e9778795SPeter Avalos 
3321e9778795SPeter Avalos 	/* String options */
3322e9778795SPeter Avalos 	dump_cfg_string(oBindAddress, o->bind_address);
3323664f4763Szrj 	dump_cfg_string(oBindInterface, o->bind_interface);
33240cbfa66cSDaniel Fojt 	dump_cfg_string(oCiphers, o->ciphers);
3325e9778795SPeter Avalos 	dump_cfg_string(oControlPath, o->control_path);
3326e9778795SPeter Avalos 	dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
3327e9778795SPeter Avalos 	dump_cfg_string(oHostKeyAlias, o->host_key_alias);
332850a69bb5SSascha Wildner 	dump_cfg_string(oHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
3329e9778795SPeter Avalos 	dump_cfg_string(oIdentityAgent, o->identity_agent);
3330664f4763Szrj 	dump_cfg_string(oIgnoreUnknown, o->ignored_unknown);
3331e9778795SPeter Avalos 	dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
33320cbfa66cSDaniel Fojt 	dump_cfg_string(oKexAlgorithms, o->kex_algorithms);
33330cbfa66cSDaniel Fojt 	dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms);
3334e9778795SPeter Avalos 	dump_cfg_string(oLocalCommand, o->local_command);
3335ce74bacaSMatthew Dillon 	dump_cfg_string(oRemoteCommand, o->remote_command);
3336e9778795SPeter Avalos 	dump_cfg_string(oLogLevel, log_level_name(o->log_level));
33370cbfa66cSDaniel Fojt 	dump_cfg_string(oMacs, o->macs);
3338ce74bacaSMatthew Dillon #ifdef ENABLE_PKCS11
3339e9778795SPeter Avalos 	dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
3340ce74bacaSMatthew Dillon #endif
33410cbfa66cSDaniel Fojt 	dump_cfg_string(oSecurityKeyProvider, o->sk_provider);
3342e9778795SPeter Avalos 	dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
334350a69bb5SSascha Wildner 	dump_cfg_string(oPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
3344e9778795SPeter Avalos 	dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
3345e9778795SPeter Avalos 	dump_cfg_string(oXAuthLocation, o->xauth_location);
334650a69bb5SSascha Wildner 	dump_cfg_string(oKnownHostsCommand, o->known_hosts_command);
3347e9778795SPeter Avalos 
3348e9778795SPeter Avalos 	/* Forwards */
3349e9778795SPeter Avalos 	dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
3350e9778795SPeter Avalos 	dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
3351e9778795SPeter Avalos 	dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
3352e9778795SPeter Avalos 
3353e9778795SPeter Avalos 	/* String array options */
3354e9778795SPeter Avalos 	dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
3355e9778795SPeter Avalos 	dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
3356664f4763Szrj 	dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files);
3357e9778795SPeter Avalos 	dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
3358e9778795SPeter Avalos 	dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
3359e9778795SPeter Avalos 	dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
3360664f4763Szrj 	dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
336150a69bb5SSascha Wildner 	dump_cfg_strarray_oneline(oLogVerbose,
336250a69bb5SSascha Wildner 	    o->num_log_verbose, o->log_verbose);
3363e9778795SPeter Avalos 
3364e9778795SPeter Avalos 	/* Special cases */
3365e9778795SPeter Avalos 
336650a69bb5SSascha Wildner 	/* PermitRemoteOpen */
336750a69bb5SSascha Wildner 	if (o->num_permitted_remote_opens == 0)
336850a69bb5SSascha Wildner 		printf("%s any\n", lookup_opcode_name(oPermitRemoteOpen));
336950a69bb5SSascha Wildner 	else
337050a69bb5SSascha Wildner 		dump_cfg_strarray_oneline(oPermitRemoteOpen,
337150a69bb5SSascha Wildner 		    o->num_permitted_remote_opens, o->permitted_remote_opens);
337250a69bb5SSascha Wildner 
337350a69bb5SSascha Wildner 	/* AddKeysToAgent */
337450a69bb5SSascha Wildner 	if (o->add_keys_to_agent_lifespan <= 0)
337550a69bb5SSascha Wildner 		dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent);
337650a69bb5SSascha Wildner 	else {
337750a69bb5SSascha Wildner 		printf("addkeystoagent%s %d\n",
337850a69bb5SSascha Wildner 		    o->add_keys_to_agent == 3 ? " confirm" : "",
337950a69bb5SSascha Wildner 		    o->add_keys_to_agent_lifespan);
338050a69bb5SSascha Wildner 	}
338150a69bb5SSascha Wildner 
33820cbfa66cSDaniel Fojt 	/* oForwardAgent */
33830cbfa66cSDaniel Fojt 	if (o->forward_agent_sock_path == NULL)
33840cbfa66cSDaniel Fojt 		dump_cfg_fmtint(oForwardAgent, o->forward_agent);
33850cbfa66cSDaniel Fojt 	else
33860cbfa66cSDaniel Fojt 		dump_cfg_string(oForwardAgent, o->forward_agent_sock_path);
33870cbfa66cSDaniel Fojt 
3388e9778795SPeter Avalos 	/* oConnectTimeout */
3389e9778795SPeter Avalos 	if (o->connection_timeout == -1)
3390e9778795SPeter Avalos 		printf("connecttimeout none\n");
3391e9778795SPeter Avalos 	else
3392e9778795SPeter Avalos 		dump_cfg_int(oConnectTimeout, o->connection_timeout);
3393e9778795SPeter Avalos 
3394e9778795SPeter Avalos 	/* oTunnelDevice */
3395e9778795SPeter Avalos 	printf("tunneldevice");
3396e9778795SPeter Avalos 	if (o->tun_local == SSH_TUNID_ANY)
3397e9778795SPeter Avalos 		printf(" any");
3398e9778795SPeter Avalos 	else
3399e9778795SPeter Avalos 		printf(" %d", o->tun_local);
3400e9778795SPeter Avalos 	if (o->tun_remote == SSH_TUNID_ANY)
3401e9778795SPeter Avalos 		printf(":any");
3402e9778795SPeter Avalos 	else
3403e9778795SPeter Avalos 		printf(":%d", o->tun_remote);
3404e9778795SPeter Avalos 	printf("\n");
3405e9778795SPeter Avalos 
3406e9778795SPeter Avalos 	/* oCanonicalizePermittedCNAMEs */
3407e9778795SPeter Avalos 	printf("canonicalizePermittedcnames");
340850a69bb5SSascha Wildner 	if (o->num_permitted_cnames == 0)
340950a69bb5SSascha Wildner 		printf(" none");
3410e9778795SPeter Avalos 	for (i = 0; i < o->num_permitted_cnames; i++) {
3411e9778795SPeter Avalos 		printf(" %s:%s", o->permitted_cnames[i].source_list,
3412e9778795SPeter Avalos 		    o->permitted_cnames[i].target_list);
3413e9778795SPeter Avalos 	}
3414e9778795SPeter Avalos 	printf("\n");
3415e9778795SPeter Avalos 
3416e9778795SPeter Avalos 	/* oControlPersist */
3417e9778795SPeter Avalos 	if (o->control_persist == 0 || o->control_persist_timeout == 0)
3418e9778795SPeter Avalos 		dump_cfg_fmtint(oControlPersist, o->control_persist);
3419e9778795SPeter Avalos 	else
3420e9778795SPeter Avalos 		dump_cfg_int(oControlPersist, o->control_persist_timeout);
3421e9778795SPeter Avalos 
3422e9778795SPeter Avalos 	/* oEscapeChar */
3423e9778795SPeter Avalos 	if (o->escape_char == SSH_ESCAPECHAR_NONE)
3424e9778795SPeter Avalos 		printf("escapechar none\n");
3425e9778795SPeter Avalos 	else {
3426e9778795SPeter Avalos 		vis(buf, o->escape_char, VIS_WHITE, 0);
3427e9778795SPeter Avalos 		printf("escapechar %s\n", buf);
3428e9778795SPeter Avalos 	}
3429e9778795SPeter Avalos 
3430e9778795SPeter Avalos 	/* oIPQoS */
3431e9778795SPeter Avalos 	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
3432e9778795SPeter Avalos 	printf("%s\n", iptos2str(o->ip_qos_bulk));
3433e9778795SPeter Avalos 
3434e9778795SPeter Avalos 	/* oRekeyLimit */
3435e9778795SPeter Avalos 	printf("rekeylimit %llu %d\n",
3436e9778795SPeter Avalos 	    (unsigned long long)o->rekey_limit, o->rekey_interval);
3437e9778795SPeter Avalos 
3438e9778795SPeter Avalos 	/* oStreamLocalBindMask */
3439e9778795SPeter Avalos 	printf("streamlocalbindmask 0%o\n",
3440e9778795SPeter Avalos 	    o->fwd_opts.streamlocal_bind_mask);
3441e9778795SPeter Avalos 
3442664f4763Szrj 	/* oLogFacility */
3443664f4763Szrj 	printf("syslogfacility %s\n", log_facility_name(o->log_facility));
3444664f4763Szrj 
3445e9778795SPeter Avalos 	/* oProxyCommand / oProxyJump */
3446e9778795SPeter Avalos 	if (o->jump_host == NULL)
3447e9778795SPeter Avalos 		dump_cfg_string(oProxyCommand, o->proxy_command);
3448e9778795SPeter Avalos 	else {
3449e9778795SPeter Avalos 		/* Check for numeric addresses */
3450e9778795SPeter Avalos 		i = strchr(o->jump_host, ':') != NULL ||
3451e9778795SPeter Avalos 		    strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
3452e9778795SPeter Avalos 		snprintf(buf, sizeof(buf), "%d", o->jump_port);
3453e9778795SPeter Avalos 		printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
3454e9778795SPeter Avalos 		    /* optional additional jump spec */
3455e9778795SPeter Avalos 		    o->jump_extra == NULL ? "" : o->jump_extra,
3456e9778795SPeter Avalos 		    o->jump_extra == NULL ? "" : ",",
3457e9778795SPeter Avalos 		    /* optional user */
3458e9778795SPeter Avalos 		    o->jump_user == NULL ? "" : o->jump_user,
3459e9778795SPeter Avalos 		    o->jump_user == NULL ? "" : "@",
3460e9778795SPeter Avalos 		    /* opening [ if hostname is numeric */
3461e9778795SPeter Avalos 		    i ? "[" : "",
3462e9778795SPeter Avalos 		    /* mandatory hostname */
3463e9778795SPeter Avalos 		    o->jump_host,
3464e9778795SPeter Avalos 		    /* closing ] if hostname is numeric */
3465e9778795SPeter Avalos 		    i ? "]" : "",
3466e9778795SPeter Avalos 		    /* optional port number */
3467e9778795SPeter Avalos 		    o->jump_port <= 0 ? "" : ":",
3468e9778795SPeter Avalos 		    o->jump_port <= 0 ? "" : buf);
3469e9778795SPeter Avalos 	}
3470e9778795SPeter Avalos }
3471