1*0ae642c7SEd Maste /* $OpenBSD: readconf.c,v 1.392 2024/09/26 23:55:08 djm Exp $ */
2511b41d2SMark Murray /*
3511b41d2SMark Murray * Author: Tatu Ylonen <ylo@cs.hut.fi>
4511b41d2SMark Murray * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5511b41d2SMark Murray * All rights reserved
6511b41d2SMark Murray * Functions for reading the configuration files.
7511b41d2SMark Murray *
8c2d3a559SKris Kennaway * As far as I am concerned, the code I have written for this software
9c2d3a559SKris Kennaway * can be used freely for any purpose. Any derived versions of this
10c2d3a559SKris Kennaway * software must be clearly marked as such, and if the derived work is
11c2d3a559SKris Kennaway * incompatible with the protocol description in the RFC file, it must be
12c2d3a559SKris Kennaway * called by a name other than "ssh" or "Secure Shell".
13511b41d2SMark Murray */
14511b41d2SMark Murray
15511b41d2SMark Murray #include "includes.h"
16511b41d2SMark Murray
17333ee039SDag-Erling Smørgrav #include <sys/types.h>
18333ee039SDag-Erling Smørgrav #include <sys/stat.h>
19333ee039SDag-Erling Smørgrav #include <sys/socket.h>
20f7167e0eSDag-Erling Smørgrav #include <sys/wait.h>
21a0ee8cc6SDag-Erling Smørgrav #include <sys/un.h>
22333ee039SDag-Erling Smørgrav
23535af610SEd Maste #include <net/if.h>
24333ee039SDag-Erling Smørgrav #include <netinet/in.h>
254a421b63SDag-Erling Smørgrav #include <netinet/in_systm.h>
264a421b63SDag-Erling Smørgrav #include <netinet/ip.h>
27b83788ffSDag-Erling Smørgrav #include <arpa/inet.h>
28333ee039SDag-Erling Smørgrav
29333ee039SDag-Erling Smørgrav #include <ctype.h>
30333ee039SDag-Erling Smørgrav #include <errno.h>
31f7167e0eSDag-Erling Smørgrav #include <fcntl.h>
32535af610SEd Maste #ifdef HAVE_IFADDRS_H
33535af610SEd Maste # include <ifaddrs.h>
34535af610SEd Maste #endif
35bc5531deSDag-Erling Smørgrav #include <limits.h>
36333ee039SDag-Erling Smørgrav #include <netdb.h>
37f7167e0eSDag-Erling Smørgrav #ifdef HAVE_PATHS_H
38f7167e0eSDag-Erling Smørgrav # include <paths.h>
39f7167e0eSDag-Erling Smørgrav #endif
40f7167e0eSDag-Erling Smørgrav #include <pwd.h>
41333ee039SDag-Erling Smørgrav #include <signal.h>
42333ee039SDag-Erling Smørgrav #include <stdio.h>
43333ee039SDag-Erling Smørgrav #include <string.h>
4419261079SEd Maste #include <stdarg.h>
45333ee039SDag-Erling Smørgrav #include <unistd.h>
46076ad2f8SDag-Erling Smørgrav #ifdef USE_SYSTEM_GLOB
47076ad2f8SDag-Erling Smørgrav # include <glob.h>
48076ad2f8SDag-Erling Smørgrav #else
49076ad2f8SDag-Erling Smørgrav # include "openbsd-compat/glob.h"
50076ad2f8SDag-Erling Smørgrav #endif
51e4a9863fSDag-Erling Smørgrav #ifdef HAVE_UTIL_H
52e4a9863fSDag-Erling Smørgrav #include <util.h>
53e4a9863fSDag-Erling Smørgrav #endif
54bc5531deSDag-Erling Smørgrav #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
55bc5531deSDag-Erling Smørgrav # include <vis.h>
56bc5531deSDag-Erling Smørgrav #endif
57333ee039SDag-Erling Smørgrav
58511b41d2SMark Murray #include "xmalloc.h"
59333ee039SDag-Erling Smørgrav #include "ssh.h"
60190cef3dSDag-Erling Smørgrav #include "ssherr.h"
61ca3176e7SBrian Feldman #include "cipher.h"
62ca3176e7SBrian Feldman #include "pathnames.h"
63ca3176e7SBrian Feldman #include "log.h"
64bc5531deSDag-Erling Smørgrav #include "sshkey.h"
65a0ee8cc6SDag-Erling Smørgrav #include "misc.h"
66ca3176e7SBrian Feldman #include "readconf.h"
67ca3176e7SBrian Feldman #include "match.h"
68ca3176e7SBrian Feldman #include "kex.h"
69ca3176e7SBrian Feldman #include "mac.h"
70f7167e0eSDag-Erling Smørgrav #include "uidswap.h"
71bc5531deSDag-Erling Smørgrav #include "myproposal.h"
72bc5531deSDag-Erling Smørgrav #include "digest.h"
73511b41d2SMark Murray
74511b41d2SMark Murray /* Format of the configuration file:
75511b41d2SMark Murray
76511b41d2SMark Murray # Configuration data is parsed as follows:
77511b41d2SMark Murray # 1. command line options
78511b41d2SMark Murray # 2. user-specific file
79511b41d2SMark Murray # 3. system-wide file
80511b41d2SMark Murray # Any configuration value is only changed the first time it is set.
81511b41d2SMark Murray # Thus, host-specific definitions should be at the beginning of the
82511b41d2SMark Murray # configuration file, and defaults at the end.
83511b41d2SMark Murray
84511b41d2SMark Murray # Host-specific declarations. These may override anything above. A single
85511b41d2SMark Murray # host may match multiple declarations; these are processed in the order
86511b41d2SMark Murray # that they are given in.
87511b41d2SMark Murray
88511b41d2SMark Murray Host *.ngs.fi ngs.fi
8980628bacSDag-Erling Smørgrav User foo
90511b41d2SMark Murray
91511b41d2SMark Murray Host fake.com
9219261079SEd Maste Hostname another.host.name.real.org
93511b41d2SMark Murray User blaah
94511b41d2SMark Murray Port 34289
95511b41d2SMark Murray ForwardX11 no
96511b41d2SMark Murray ForwardAgent no
97511b41d2SMark Murray
98511b41d2SMark Murray Host books.com
99511b41d2SMark Murray RemoteForward 9999 shadows.cs.hut.fi:9999
100d93a896eSDag-Erling Smørgrav Ciphers 3des-cbc
101511b41d2SMark Murray
102511b41d2SMark Murray Host fascist.blob.com
103511b41d2SMark Murray Port 23123
104511b41d2SMark Murray User tylonen
105511b41d2SMark Murray PasswordAuthentication no
106511b41d2SMark Murray
107511b41d2SMark Murray Host puukko.hut.fi
108511b41d2SMark Murray User t35124p
109511b41d2SMark Murray ProxyCommand ssh-proxy %h %p
110511b41d2SMark Murray
111511b41d2SMark Murray Host *.fr
11280628bacSDag-Erling Smørgrav PublicKeyAuthentication no
113511b41d2SMark Murray
114511b41d2SMark Murray Host *.su
115d93a896eSDag-Erling Smørgrav Ciphers aes128-ctr
116511b41d2SMark Murray PasswordAuthentication no
117511b41d2SMark Murray
118b74df5b2SDag-Erling Smørgrav Host vpn.fake.com
119b74df5b2SDag-Erling Smørgrav Tunnel yes
120b74df5b2SDag-Erling Smørgrav TunnelDevice 3
121b74df5b2SDag-Erling Smørgrav
122511b41d2SMark Murray # Defaults for various options
123511b41d2SMark Murray Host *
124511b41d2SMark Murray ForwardAgent no
125ca3176e7SBrian Feldman ForwardX11 no
126511b41d2SMark Murray PasswordAuthentication yes
127511b41d2SMark Murray StrictHostKeyChecking yes
1281ec0d754SDag-Erling Smørgrav TcpKeepAlive no
129511b41d2SMark Murray IdentityFile ~/.ssh/identity
130511b41d2SMark Murray Port 22
131511b41d2SMark Murray EscapeChar ~
132511b41d2SMark Murray
133511b41d2SMark Murray */
134511b41d2SMark Murray
135076ad2f8SDag-Erling Smørgrav static int read_config_file_depth(const char *filename, struct passwd *pw,
136076ad2f8SDag-Erling Smørgrav const char *host, const char *original_host, Options *options,
13719261079SEd Maste int flags, int *activep, int *want_final_pass, int depth);
138076ad2f8SDag-Erling Smørgrav static int process_config_line_depth(Options *options, struct passwd *pw,
139076ad2f8SDag-Erling Smørgrav const char *host, const char *original_host, char *line,
14019261079SEd Maste const char *filename, int linenum, int *activep, int flags,
14119261079SEd Maste int *want_final_pass, int depth);
142076ad2f8SDag-Erling Smørgrav
143511b41d2SMark Murray /* Keyword tokens. */
144511b41d2SMark Murray
145511b41d2SMark Murray typedef enum {
146511b41d2SMark Murray oBadOption,
147535af610SEd Maste oHost, oMatch, oInclude, oTag,
148e2f6069cSDag-Erling Smørgrav oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
149e2f6069cSDag-Erling Smørgrav oGatewayPorts, oExitOnForwardFailure,
15019261079SEd Maste oPasswordAuthentication,
15119261079SEd Maste oXAuthLocation,
15219261079SEd Maste oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward,
15319261079SEd Maste oPermitRemoteOpen,
154076ad2f8SDag-Erling Smørgrav oCertificateFile, oAddKeysToAgent, oIdentityAgent,
15519261079SEd Maste oUser, oEscapeChar, oProxyCommand,
156511b41d2SMark Murray oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
157511b41d2SMark Murray oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
15819261079SEd Maste oTCPKeepAlive, oNumberOfPasswordPrompts,
15919261079SEd Maste oLogFacility, oLogLevel, oLogVerbose, oCiphers, oMacs,
160bc5531deSDag-Erling Smørgrav oPubkeyAuthentication,
161ca3176e7SBrian Feldman oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
162ca3176e7SBrian Feldman oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
16347dd1d1bSDag-Erling Smørgrav oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider,
1649e2cbe04SDag-Erling Smørgrav oClearAllForwardings, oNoHostAuthenticationForLocalhost,
165cf2b5f3bSDag-Erling Smørgrav oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
166cf2b5f3bSDag-Erling Smørgrav oAddressFamily, oGssAuthentication, oGssDelegateCreds,
1675962c0e9SDag-Erling Smørgrav oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
168190cef3dSDag-Erling Smørgrav oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
169e2f6069cSDag-Erling Smørgrav oHashKnownHosts,
1704f52dfbbSDag-Erling Smørgrav oTunnel, oTunnelDevice,
1714f52dfbbSDag-Erling Smørgrav oLocalCommand, oPermitLocalCommand, oRemoteCommand,
172acc1a9efSDag-Erling Smørgrav oVisualHostKey,
17319261079SEd Maste oKexAlgorithms, oIPQoS, oRequestTTY, oSessionType, oStdinNull,
17419261079SEd Maste oForkAfterAuthentication, oIgnoreUnknown, oProxyUseFdpass,
175f7167e0eSDag-Erling Smørgrav oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
176f7167e0eSDag-Erling Smørgrav oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
177bc5531deSDag-Erling Smørgrav oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
17819261079SEd Maste oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
17919261079SEd Maste oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
18038a52bd3SEd Maste oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize,
181069ac184SEd Maste oEnableEscapeCommandline, oObscureKeystrokeTiming, oChannelTimeout,
1824f52dfbbSDag-Erling Smørgrav oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
183511b41d2SMark Murray } OpCodes;
184511b41d2SMark Murray
185511b41d2SMark Murray /* Textual representations of the tokens. */
186511b41d2SMark Murray
187511b41d2SMark Murray static struct {
188511b41d2SMark Murray const char *name;
189511b41d2SMark Murray OpCodes opcode;
190511b41d2SMark Murray } keywords[] = {
191d93a896eSDag-Erling Smørgrav /* Deprecated options */
1924f52dfbbSDag-Erling Smørgrav { "protocol", oIgnore }, /* NB. silently ignored */
1934f52dfbbSDag-Erling Smørgrav { "cipher", oDeprecated },
194d93a896eSDag-Erling Smørgrav { "fallbacktorsh", oDeprecated },
195d93a896eSDag-Erling Smørgrav { "globalknownhostsfile2", oDeprecated },
196d93a896eSDag-Erling Smørgrav { "rhostsauthentication", oDeprecated },
197d93a896eSDag-Erling Smørgrav { "userknownhostsfile2", oDeprecated },
198d93a896eSDag-Erling Smørgrav { "useroaming", oDeprecated },
199d93a896eSDag-Erling Smørgrav { "usersh", oDeprecated },
200190cef3dSDag-Erling Smørgrav { "useprivilegedport", oDeprecated },
201d93a896eSDag-Erling Smørgrav
202d93a896eSDag-Erling Smørgrav /* Unsupported options */
203d93a896eSDag-Erling Smørgrav { "afstokenpassing", oUnsupported },
204d93a896eSDag-Erling Smørgrav { "kerberosauthentication", oUnsupported },
205d93a896eSDag-Erling Smørgrav { "kerberostgtpassing", oUnsupported },
20619261079SEd Maste { "rsaauthentication", oUnsupported },
20719261079SEd Maste { "rhostsrsaauthentication", oUnsupported },
20819261079SEd Maste { "compressionlevel", oUnsupported },
209d93a896eSDag-Erling Smørgrav
210d93a896eSDag-Erling Smørgrav /* Sometimes-unsupported options */
211d93a896eSDag-Erling Smørgrav #if defined(GSSAPI)
212d93a896eSDag-Erling Smørgrav { "gssapiauthentication", oGssAuthentication },
213d93a896eSDag-Erling Smørgrav { "gssapidelegatecredentials", oGssDelegateCreds },
214d93a896eSDag-Erling Smørgrav # else
215d93a896eSDag-Erling Smørgrav { "gssapiauthentication", oUnsupported },
216d93a896eSDag-Erling Smørgrav { "gssapidelegatecredentials", oUnsupported },
217d93a896eSDag-Erling Smørgrav #endif
218d93a896eSDag-Erling Smørgrav #ifdef ENABLE_PKCS11
219d93a896eSDag-Erling Smørgrav { "pkcs11provider", oPKCS11Provider },
22019261079SEd Maste { "smartcarddevice", oPKCS11Provider },
221d93a896eSDag-Erling Smørgrav # else
222d93a896eSDag-Erling Smørgrav { "smartcarddevice", oUnsupported },
223d93a896eSDag-Erling Smørgrav { "pkcs11provider", oUnsupported },
224d93a896eSDag-Erling Smørgrav #endif
225d93a896eSDag-Erling Smørgrav
226511b41d2SMark Murray { "forwardagent", oForwardAgent },
227511b41d2SMark Murray { "forwardx11", oForwardX11 },
2281ec0d754SDag-Erling Smørgrav { "forwardx11trusted", oForwardX11Trusted },
229e2f6069cSDag-Erling Smørgrav { "forwardx11timeout", oForwardX11Timeout },
230333ee039SDag-Erling Smørgrav { "exitonforwardfailure", oExitOnForwardFailure },
231c2d3a559SKris Kennaway { "xauthlocation", oXAuthLocation },
232511b41d2SMark Murray { "gatewayports", oGatewayPorts },
233511b41d2SMark Murray { "passwordauthentication", oPasswordAuthentication },
23409958426SBrian Feldman { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
23509958426SBrian Feldman { "kbdinteractivedevices", oKbdInteractiveDevices },
23619261079SEd Maste { "challengeresponseauthentication", oKbdInteractiveAuthentication }, /* alias */
23719261079SEd Maste { "skeyauthentication", oKbdInteractiveAuthentication }, /* alias */
23819261079SEd Maste { "tisauthentication", oKbdInteractiveAuthentication }, /* alias */
239ca3176e7SBrian Feldman { "pubkeyauthentication", oPubkeyAuthentication },
240ca3176e7SBrian Feldman { "dsaauthentication", oPubkeyAuthentication }, /* alias */
241ca3176e7SBrian Feldman { "hostbasedauthentication", oHostbasedAuthentication },
242511b41d2SMark Murray { "identityfile", oIdentityFile },
243cce7d346SDag-Erling Smørgrav { "identityfile2", oIdentityFile }, /* obsolete */
2445962c0e9SDag-Erling Smørgrav { "identitiesonly", oIdentitiesOnly },
245acc1a9efSDag-Erling Smørgrav { "certificatefile", oCertificateFile },
246acc1a9efSDag-Erling Smørgrav { "addkeystoagent", oAddKeysToAgent },
247076ad2f8SDag-Erling Smørgrav { "identityagent", oIdentityAgent },
24819261079SEd Maste { "hostname", oHostname },
249ca3176e7SBrian Feldman { "hostkeyalias", oHostKeyAlias },
250511b41d2SMark Murray { "proxycommand", oProxyCommand },
251511b41d2SMark Murray { "port", oPort },
252e8aafc91SKris Kennaway { "ciphers", oCiphers },
253ca3176e7SBrian Feldman { "macs", oMacs },
254511b41d2SMark Murray { "remoteforward", oRemoteForward },
255511b41d2SMark Murray { "localforward", oLocalForward },
25619261079SEd Maste { "permitremoteopen", oPermitRemoteOpen },
257511b41d2SMark Murray { "user", oUser },
258511b41d2SMark Murray { "host", oHost },
259f7167e0eSDag-Erling Smørgrav { "match", oMatch },
260535af610SEd Maste { "tag", oTag },
261511b41d2SMark Murray { "escapechar", oEscapeChar },
262511b41d2SMark Murray { "globalknownhostsfile", oGlobalKnownHostsFile },
263cce7d346SDag-Erling Smørgrav { "userknownhostsfile", oUserKnownHostsFile },
264511b41d2SMark Murray { "connectionattempts", oConnectionAttempts },
265511b41d2SMark Murray { "batchmode", oBatchMode },
266511b41d2SMark Murray { "checkhostip", oCheckHostIP },
267511b41d2SMark Murray { "stricthostkeychecking", oStrictHostKeyChecking },
268511b41d2SMark Murray { "compression", oCompression },
2691ec0d754SDag-Erling Smørgrav { "tcpkeepalive", oTCPKeepAlive },
2701ec0d754SDag-Erling Smørgrav { "keepalive", oTCPKeepAlive }, /* obsolete */
271511b41d2SMark Murray { "numberofpasswordprompts", oNumberOfPasswordPrompts },
2724f52dfbbSDag-Erling Smørgrav { "syslogfacility", oLogFacility },
273511b41d2SMark Murray { "loglevel", oLogLevel },
27419261079SEd Maste { "logverbose", oLogVerbose },
275ca3176e7SBrian Feldman { "dynamicforward", oDynamicForward },
276ca3176e7SBrian Feldman { "preferredauthentications", oPreferredAuthentications },
277ca3176e7SBrian Feldman { "hostkeyalgorithms", oHostKeyAlgorithms },
2782f513db7SEd Maste { "casignaturealgorithms", oCASignatureAlgorithms },
279af12a3e7SDag-Erling Smørgrav { "bindaddress", oBindAddress },
28047dd1d1bSDag-Erling Smørgrav { "bindinterface", oBindInterface },
281af12a3e7SDag-Erling Smørgrav { "clearallforwardings", oClearAllForwardings },
282e73e9afaSDag-Erling Smørgrav { "enablesshkeysign", oEnableSSHKeysign },
283cf2b5f3bSDag-Erling Smørgrav { "verifyhostkeydns", oVerifyHostKeyDNS },
284af12a3e7SDag-Erling Smørgrav { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
285cf2b5f3bSDag-Erling Smørgrav { "rekeylimit", oRekeyLimit },
286cf2b5f3bSDag-Erling Smørgrav { "connecttimeout", oConnectTimeout },
287cf2b5f3bSDag-Erling Smørgrav { "addressfamily", oAddressFamily },
2881ec0d754SDag-Erling Smørgrav { "serveraliveinterval", oServerAliveInterval },
2891ec0d754SDag-Erling Smørgrav { "serveralivecountmax", oServerAliveCountMax },
29021e764dfSDag-Erling Smørgrav { "sendenv", oSendEnv },
291190cef3dSDag-Erling Smørgrav { "setenv", oSetEnv },
29221e764dfSDag-Erling Smørgrav { "controlpath", oControlPath },
29321e764dfSDag-Erling Smørgrav { "controlmaster", oControlMaster },
294e2f6069cSDag-Erling Smørgrav { "controlpersist", oControlPersist },
295aa49c926SDag-Erling Smørgrav { "hashknownhosts", oHashKnownHosts },
296076ad2f8SDag-Erling Smørgrav { "include", oInclude },
297b74df5b2SDag-Erling Smørgrav { "tunnel", oTunnel },
298b74df5b2SDag-Erling Smørgrav { "tunneldevice", oTunnelDevice },
299b74df5b2SDag-Erling Smørgrav { "localcommand", oLocalCommand },
300b74df5b2SDag-Erling Smørgrav { "permitlocalcommand", oPermitLocalCommand },
3014f52dfbbSDag-Erling Smørgrav { "remotecommand", oRemoteCommand },
302d4af9e69SDag-Erling Smørgrav { "visualhostkey", oVisualHostKey },
3034a421b63SDag-Erling Smørgrav { "kexalgorithms", oKexAlgorithms },
3044a421b63SDag-Erling Smørgrav { "ipqos", oIPQoS },
305e146993eSDag-Erling Smørgrav { "requesttty", oRequestTTY },
30619261079SEd Maste { "sessiontype", oSessionType },
30719261079SEd Maste { "stdinnull", oStdinNull },
30819261079SEd Maste { "forkafterauthentication", oForkAfterAuthentication },
309f7167e0eSDag-Erling Smørgrav { "proxyusefdpass", oProxyUseFdpass },
310f7167e0eSDag-Erling Smørgrav { "canonicaldomains", oCanonicalDomains },
311f7167e0eSDag-Erling Smørgrav { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
312f7167e0eSDag-Erling Smørgrav { "canonicalizehostname", oCanonicalizeHostname },
313f7167e0eSDag-Erling Smørgrav { "canonicalizemaxdots", oCanonicalizeMaxDots },
314f7167e0eSDag-Erling Smørgrav { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
315a0ee8cc6SDag-Erling Smørgrav { "streamlocalbindmask", oStreamLocalBindMask },
316a0ee8cc6SDag-Erling Smørgrav { "streamlocalbindunlink", oStreamLocalBindUnlink },
317bc5531deSDag-Erling Smørgrav { "revokedhostkeys", oRevokedHostKeys },
318bc5531deSDag-Erling Smørgrav { "fingerprinthash", oFingerprintHash },
319bc5531deSDag-Erling Smørgrav { "updatehostkeys", oUpdateHostkeys },
32019261079SEd Maste { "hostbasedacceptedalgorithms", oHostbasedAcceptedAlgorithms },
32119261079SEd Maste { "hostbasedkeytypes", oHostbasedAcceptedAlgorithms }, /* obsolete */
32219261079SEd Maste { "pubkeyacceptedalgorithms", oPubkeyAcceptedAlgorithms },
32319261079SEd Maste { "pubkeyacceptedkeytypes", oPubkeyAcceptedAlgorithms }, /* obsolete */
324e4a9863fSDag-Erling Smørgrav { "ignoreunknown", oIgnoreUnknown },
325076ad2f8SDag-Erling Smørgrav { "proxyjump", oProxyJump },
32619261079SEd Maste { "securitykeyprovider", oSecurityKeyProvider },
32719261079SEd Maste { "knownhostscommand", oKnownHostsCommand },
32838a52bd3SEd Maste { "requiredrsasize", oRequiredRSASize },
329f374ba41SEd Maste { "enableescapecommandline", oEnableEscapeCommandline },
330edf85781SEd Maste { "obscurekeystroketiming", oObscureKeystrokeTiming },
331069ac184SEd Maste { "channeltimeout", oChannelTimeout },
332076ad2f8SDag-Erling Smørgrav
333af12a3e7SDag-Erling Smørgrav { NULL, oBadOption }
334511b41d2SMark Murray };
335511b41d2SMark Murray
33619261079SEd Maste static const char *lookup_opcode_name(OpCodes code);
33719261079SEd Maste
33819261079SEd Maste const char *
kex_default_pk_alg(void)33919261079SEd Maste kex_default_pk_alg(void)
34019261079SEd Maste {
34119261079SEd Maste static char *pkalgs;
34219261079SEd Maste
34319261079SEd Maste if (pkalgs == NULL) {
34419261079SEd Maste char *all_key;
34519261079SEd Maste
34619261079SEd Maste all_key = sshkey_alg_list(0, 0, 1, ',');
34719261079SEd Maste pkalgs = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
34819261079SEd Maste free(all_key);
34919261079SEd Maste }
35019261079SEd Maste return pkalgs;
35119261079SEd Maste }
35219261079SEd Maste
35319261079SEd Maste char *
ssh_connection_hash(const char * thishost,const char * host,const char * portstr,const char * user,const char * jumphost)35419261079SEd Maste ssh_connection_hash(const char *thishost, const char *host, const char *portstr,
355069ac184SEd Maste const char *user, const char *jumphost)
35619261079SEd Maste {
35719261079SEd Maste struct ssh_digest_ctx *md;
35819261079SEd Maste u_char conn_hash[SSH_DIGEST_MAX_LENGTH];
35919261079SEd Maste
36019261079SEd Maste if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL ||
36119261079SEd Maste ssh_digest_update(md, thishost, strlen(thishost)) < 0 ||
36219261079SEd Maste ssh_digest_update(md, host, strlen(host)) < 0 ||
36319261079SEd Maste ssh_digest_update(md, portstr, strlen(portstr)) < 0 ||
36419261079SEd Maste ssh_digest_update(md, user, strlen(user)) < 0 ||
365069ac184SEd Maste ssh_digest_update(md, jumphost, strlen(jumphost)) < 0 ||
36619261079SEd Maste ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0)
36719261079SEd Maste fatal_f("mux digest failed");
36819261079SEd Maste ssh_digest_free(md);
36919261079SEd Maste return tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1));
37019261079SEd Maste }
37119261079SEd Maste
372511b41d2SMark Murray /*
373511b41d2SMark Murray * Adds a local TCP/IP port forward to options. Never returns if there is an
374511b41d2SMark Murray * error.
375511b41d2SMark Murray */
376511b41d2SMark Murray
377511b41d2SMark Murray void
add_local_forward(Options * options,const struct Forward * newfwd)378a0ee8cc6SDag-Erling Smørgrav add_local_forward(Options *options, const struct Forward *newfwd)
379511b41d2SMark Murray {
380a0ee8cc6SDag-Erling Smørgrav struct Forward *fwd;
3819e14b918SEd Maste int i;
38203f6c5cdSDag-Erling Smørgrav
383076ad2f8SDag-Erling Smørgrav /* Don't add duplicates */
384076ad2f8SDag-Erling Smørgrav for (i = 0; i < options->num_local_forwards; i++) {
385076ad2f8SDag-Erling Smørgrav if (forward_equals(newfwd, options->local_forwards + i))
386076ad2f8SDag-Erling Smørgrav return;
387076ad2f8SDag-Erling Smørgrav }
388557f75e5SDag-Erling Smørgrav options->local_forwards = xreallocarray(options->local_forwards,
389e2f6069cSDag-Erling Smørgrav options->num_local_forwards + 1,
390e2f6069cSDag-Erling Smørgrav sizeof(*options->local_forwards));
391511b41d2SMark Murray fwd = &options->local_forwards[options->num_local_forwards++];
392aa49c926SDag-Erling Smørgrav
393cce7d346SDag-Erling Smørgrav fwd->listen_host = newfwd->listen_host;
394aa49c926SDag-Erling Smørgrav fwd->listen_port = newfwd->listen_port;
395a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = newfwd->listen_path;
396cce7d346SDag-Erling Smørgrav fwd->connect_host = newfwd->connect_host;
397aa49c926SDag-Erling Smørgrav fwd->connect_port = newfwd->connect_port;
398a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = newfwd->connect_path;
399511b41d2SMark Murray }
400511b41d2SMark Murray
401511b41d2SMark Murray /*
402511b41d2SMark Murray * Adds a remote TCP/IP port forward to options. Never returns if there is
403511b41d2SMark Murray * an error.
404511b41d2SMark Murray */
405511b41d2SMark Murray
406511b41d2SMark Murray void
add_remote_forward(Options * options,const struct Forward * newfwd)407a0ee8cc6SDag-Erling Smørgrav add_remote_forward(Options *options, const struct Forward *newfwd)
408511b41d2SMark Murray {
409a0ee8cc6SDag-Erling Smørgrav struct Forward *fwd;
410076ad2f8SDag-Erling Smørgrav int i;
411e2f6069cSDag-Erling Smørgrav
412076ad2f8SDag-Erling Smørgrav /* Don't add duplicates */
413076ad2f8SDag-Erling Smørgrav for (i = 0; i < options->num_remote_forwards; i++) {
414076ad2f8SDag-Erling Smørgrav if (forward_equals(newfwd, options->remote_forwards + i))
415076ad2f8SDag-Erling Smørgrav return;
416076ad2f8SDag-Erling Smørgrav }
417557f75e5SDag-Erling Smørgrav options->remote_forwards = xreallocarray(options->remote_forwards,
418e2f6069cSDag-Erling Smørgrav options->num_remote_forwards + 1,
419e2f6069cSDag-Erling Smørgrav sizeof(*options->remote_forwards));
420511b41d2SMark Murray fwd = &options->remote_forwards[options->num_remote_forwards++];
421aa49c926SDag-Erling Smørgrav
422cce7d346SDag-Erling Smørgrav fwd->listen_host = newfwd->listen_host;
423aa49c926SDag-Erling Smørgrav fwd->listen_port = newfwd->listen_port;
424a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = newfwd->listen_path;
425cce7d346SDag-Erling Smørgrav fwd->connect_host = newfwd->connect_host;
426aa49c926SDag-Erling Smørgrav fwd->connect_port = newfwd->connect_port;
427a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = newfwd->connect_path;
428462c32cbSDag-Erling Smørgrav fwd->handle = newfwd->handle;
429e2f6069cSDag-Erling Smørgrav fwd->allocated_port = 0;
430511b41d2SMark Murray }
431511b41d2SMark Murray
432af12a3e7SDag-Erling Smørgrav static void
clear_forwardings(Options * options)433af12a3e7SDag-Erling Smørgrav clear_forwardings(Options *options)
434af12a3e7SDag-Erling Smørgrav {
435af12a3e7SDag-Erling Smørgrav int i;
436af12a3e7SDag-Erling Smørgrav
437aa49c926SDag-Erling Smørgrav for (i = 0; i < options->num_local_forwards; i++) {
438e4a9863fSDag-Erling Smørgrav free(options->local_forwards[i].listen_host);
439a0ee8cc6SDag-Erling Smørgrav free(options->local_forwards[i].listen_path);
440e4a9863fSDag-Erling Smørgrav free(options->local_forwards[i].connect_host);
441a0ee8cc6SDag-Erling Smørgrav free(options->local_forwards[i].connect_path);
442aa49c926SDag-Erling Smørgrav }
443e2f6069cSDag-Erling Smørgrav if (options->num_local_forwards > 0) {
444e4a9863fSDag-Erling Smørgrav free(options->local_forwards);
445e2f6069cSDag-Erling Smørgrav options->local_forwards = NULL;
446e2f6069cSDag-Erling Smørgrav }
447af12a3e7SDag-Erling Smørgrav options->num_local_forwards = 0;
448aa49c926SDag-Erling Smørgrav for (i = 0; i < options->num_remote_forwards; i++) {
449e4a9863fSDag-Erling Smørgrav free(options->remote_forwards[i].listen_host);
450a0ee8cc6SDag-Erling Smørgrav free(options->remote_forwards[i].listen_path);
451e4a9863fSDag-Erling Smørgrav free(options->remote_forwards[i].connect_host);
452a0ee8cc6SDag-Erling Smørgrav free(options->remote_forwards[i].connect_path);
453aa49c926SDag-Erling Smørgrav }
454e2f6069cSDag-Erling Smørgrav if (options->num_remote_forwards > 0) {
455e4a9863fSDag-Erling Smørgrav free(options->remote_forwards);
456e2f6069cSDag-Erling Smørgrav options->remote_forwards = NULL;
457e2f6069cSDag-Erling Smørgrav }
458af12a3e7SDag-Erling Smørgrav options->num_remote_forwards = 0;
459b74df5b2SDag-Erling Smørgrav options->tun_open = SSH_TUNMODE_NO;
460af12a3e7SDag-Erling Smørgrav }
461af12a3e7SDag-Erling Smørgrav
462fa67e83cSDag-Erling Smørgrav void
add_certificate_file(Options * options,const char * path,int userprovided)463acc1a9efSDag-Erling Smørgrav add_certificate_file(Options *options, const char *path, int userprovided)
464acc1a9efSDag-Erling Smørgrav {
465acc1a9efSDag-Erling Smørgrav int i;
466acc1a9efSDag-Erling Smørgrav
467acc1a9efSDag-Erling Smørgrav if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
468acc1a9efSDag-Erling Smørgrav fatal("Too many certificate files specified (max %d)",
469acc1a9efSDag-Erling Smørgrav SSH_MAX_CERTIFICATE_FILES);
470acc1a9efSDag-Erling Smørgrav
471acc1a9efSDag-Erling Smørgrav /* Avoid registering duplicates */
472acc1a9efSDag-Erling Smørgrav for (i = 0; i < options->num_certificate_files; i++) {
473acc1a9efSDag-Erling Smørgrav if (options->certificate_file_userprovided[i] == userprovided &&
474acc1a9efSDag-Erling Smørgrav strcmp(options->certificate_files[i], path) == 0) {
47519261079SEd Maste debug2_f("ignoring duplicate key %s", path);
476acc1a9efSDag-Erling Smørgrav return;
477acc1a9efSDag-Erling Smørgrav }
478acc1a9efSDag-Erling Smørgrav }
479acc1a9efSDag-Erling Smørgrav
480acc1a9efSDag-Erling Smørgrav options->certificate_file_userprovided[options->num_certificate_files] =
481acc1a9efSDag-Erling Smørgrav userprovided;
482acc1a9efSDag-Erling Smørgrav options->certificate_files[options->num_certificate_files++] =
483acc1a9efSDag-Erling Smørgrav xstrdup(path);
484acc1a9efSDag-Erling Smørgrav }
485acc1a9efSDag-Erling Smørgrav
486acc1a9efSDag-Erling Smørgrav void
add_identity_file(Options * options,const char * dir,const char * filename,int userprovided)487fa67e83cSDag-Erling Smørgrav add_identity_file(Options *options, const char *dir, const char *filename,
488fa67e83cSDag-Erling Smørgrav int userprovided)
489fa67e83cSDag-Erling Smørgrav {
490fa67e83cSDag-Erling Smørgrav char *path;
491a0ee8cc6SDag-Erling Smørgrav int i;
492fa67e83cSDag-Erling Smørgrav
493fa67e83cSDag-Erling Smørgrav if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
494fa67e83cSDag-Erling Smørgrav fatal("Too many identity files specified (max %d)",
495fa67e83cSDag-Erling Smørgrav SSH_MAX_IDENTITY_FILES);
496fa67e83cSDag-Erling Smørgrav
497fa67e83cSDag-Erling Smørgrav if (dir == NULL) /* no dir, filename is absolute */
498fa67e83cSDag-Erling Smørgrav path = xstrdup(filename);
4994f52dfbbSDag-Erling Smørgrav else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX)
5004f52dfbbSDag-Erling Smørgrav fatal("Identity file path %s too long", path);
501fa67e83cSDag-Erling Smørgrav
502a0ee8cc6SDag-Erling Smørgrav /* Avoid registering duplicates */
503a0ee8cc6SDag-Erling Smørgrav for (i = 0; i < options->num_identity_files; i++) {
504a0ee8cc6SDag-Erling Smørgrav if (options->identity_file_userprovided[i] == userprovided &&
505a0ee8cc6SDag-Erling Smørgrav strcmp(options->identity_files[i], path) == 0) {
50619261079SEd Maste debug2_f("ignoring duplicate key %s", path);
507a0ee8cc6SDag-Erling Smørgrav free(path);
508a0ee8cc6SDag-Erling Smørgrav return;
509a0ee8cc6SDag-Erling Smørgrav }
510a0ee8cc6SDag-Erling Smørgrav }
511a0ee8cc6SDag-Erling Smørgrav
512fa67e83cSDag-Erling Smørgrav options->identity_file_userprovided[options->num_identity_files] =
513fa67e83cSDag-Erling Smørgrav userprovided;
514fa67e83cSDag-Erling Smørgrav options->identity_files[options->num_identity_files++] = path;
515fa67e83cSDag-Erling Smørgrav }
516fa67e83cSDag-Erling Smørgrav
517f7167e0eSDag-Erling Smørgrav int
default_ssh_port(void)518f7167e0eSDag-Erling Smørgrav default_ssh_port(void)
519f7167e0eSDag-Erling Smørgrav {
520f7167e0eSDag-Erling Smørgrav static int port;
521f7167e0eSDag-Erling Smørgrav struct servent *sp;
522f7167e0eSDag-Erling Smørgrav
523f7167e0eSDag-Erling Smørgrav if (port == 0) {
524f7167e0eSDag-Erling Smørgrav sp = getservbyname(SSH_SERVICE_NAME, "tcp");
525f7167e0eSDag-Erling Smørgrav port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
526f7167e0eSDag-Erling Smørgrav }
527f7167e0eSDag-Erling Smørgrav return port;
528f7167e0eSDag-Erling Smørgrav }
529f7167e0eSDag-Erling Smørgrav
530f7167e0eSDag-Erling Smørgrav /*
531f7167e0eSDag-Erling Smørgrav * Execute a command in a shell.
532f7167e0eSDag-Erling Smørgrav * Return its exit status or -1 on abnormal exit.
533f7167e0eSDag-Erling Smørgrav */
534f7167e0eSDag-Erling Smørgrav static int
execute_in_shell(const char * cmd)535f7167e0eSDag-Erling Smørgrav execute_in_shell(const char *cmd)
536f7167e0eSDag-Erling Smørgrav {
537acc1a9efSDag-Erling Smørgrav char *shell;
538f7167e0eSDag-Erling Smørgrav pid_t pid;
53919261079SEd Maste int status;
540f7167e0eSDag-Erling Smørgrav
541f7167e0eSDag-Erling Smørgrav if ((shell = getenv("SHELL")) == NULL)
542f7167e0eSDag-Erling Smørgrav shell = _PATH_BSHELL;
543f7167e0eSDag-Erling Smørgrav
54419261079SEd Maste if (access(shell, X_OK) == -1) {
54519261079SEd Maste fatal("Shell \"%s\" is not executable: %s",
54619261079SEd Maste shell, strerror(errno));
54719261079SEd Maste }
548f7167e0eSDag-Erling Smørgrav
549f7167e0eSDag-Erling Smørgrav debug("Executing command: '%.500s'", cmd);
550f7167e0eSDag-Erling Smørgrav
551f7167e0eSDag-Erling Smørgrav /* Fork and execute the command. */
552f7167e0eSDag-Erling Smørgrav if ((pid = fork()) == 0) {
553f7167e0eSDag-Erling Smørgrav char *argv[4];
554f7167e0eSDag-Erling Smørgrav
55519261079SEd Maste if (stdfd_devnull(1, 1, 0) == -1)
55619261079SEd Maste fatal_f("stdfd_devnull failed");
557f7167e0eSDag-Erling Smørgrav closefrom(STDERR_FILENO + 1);
558f7167e0eSDag-Erling Smørgrav
559f7167e0eSDag-Erling Smørgrav argv[0] = shell;
560f7167e0eSDag-Erling Smørgrav argv[1] = "-c";
561acc1a9efSDag-Erling Smørgrav argv[2] = xstrdup(cmd);
562f7167e0eSDag-Erling Smørgrav argv[3] = NULL;
563f7167e0eSDag-Erling Smørgrav
564f7167e0eSDag-Erling Smørgrav execv(argv[0], argv);
565f7167e0eSDag-Erling Smørgrav error("Unable to execute '%.100s': %s", cmd, strerror(errno));
566f7167e0eSDag-Erling Smørgrav /* Die with signal to make this error apparent to parent. */
56719261079SEd Maste ssh_signal(SIGTERM, SIG_DFL);
568f7167e0eSDag-Erling Smørgrav kill(getpid(), SIGTERM);
569f7167e0eSDag-Erling Smørgrav _exit(1);
570f7167e0eSDag-Erling Smørgrav }
571f7167e0eSDag-Erling Smørgrav /* Parent. */
57219261079SEd Maste if (pid == -1)
57319261079SEd Maste fatal_f("fork: %.100s", strerror(errno));
574f7167e0eSDag-Erling Smørgrav
575f7167e0eSDag-Erling Smørgrav while (waitpid(pid, &status, 0) == -1) {
576f7167e0eSDag-Erling Smørgrav if (errno != EINTR && errno != EAGAIN)
57719261079SEd Maste fatal_f("waitpid: %s", strerror(errno));
578f7167e0eSDag-Erling Smørgrav }
579f7167e0eSDag-Erling Smørgrav if (!WIFEXITED(status)) {
580f7167e0eSDag-Erling Smørgrav error("command '%.100s' exited abnormally", cmd);
581f7167e0eSDag-Erling Smørgrav return -1;
582f7167e0eSDag-Erling Smørgrav }
583f7167e0eSDag-Erling Smørgrav debug3("command returned status %d", WEXITSTATUS(status));
584f7167e0eSDag-Erling Smørgrav return WEXITSTATUS(status);
585f7167e0eSDag-Erling Smørgrav }
586f7167e0eSDag-Erling Smørgrav
587f7167e0eSDag-Erling Smørgrav /*
588535af610SEd Maste * Check whether a local network interface address appears in CIDR pattern-
589535af610SEd Maste * list 'addrlist'. Returns 1 if matched or 0 otherwise.
590535af610SEd Maste */
591535af610SEd Maste static int
check_match_ifaddrs(const char * addrlist)592535af610SEd Maste check_match_ifaddrs(const char *addrlist)
593535af610SEd Maste {
594535af610SEd Maste #ifdef HAVE_IFADDRS_H
595535af610SEd Maste struct ifaddrs *ifa, *ifaddrs = NULL;
596535af610SEd Maste int r, found = 0;
597535af610SEd Maste char addr[NI_MAXHOST];
598535af610SEd Maste socklen_t salen;
599535af610SEd Maste
600535af610SEd Maste if (getifaddrs(&ifaddrs) != 0) {
601535af610SEd Maste error("match localnetwork: getifaddrs failed: %s",
602535af610SEd Maste strerror(errno));
603535af610SEd Maste return 0;
604535af610SEd Maste }
605535af610SEd Maste for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
606535af610SEd Maste if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL ||
607535af610SEd Maste (ifa->ifa_flags & IFF_UP) == 0)
608535af610SEd Maste continue;
609535af610SEd Maste switch (ifa->ifa_addr->sa_family) {
610535af610SEd Maste case AF_INET:
611535af610SEd Maste salen = sizeof(struct sockaddr_in);
612535af610SEd Maste break;
613535af610SEd Maste case AF_INET6:
614535af610SEd Maste salen = sizeof(struct sockaddr_in6);
615535af610SEd Maste break;
616535af610SEd Maste #ifdef AF_LINK
617535af610SEd Maste case AF_LINK:
618535af610SEd Maste /* ignore */
619535af610SEd Maste continue;
620535af610SEd Maste #endif /* AF_LINK */
621535af610SEd Maste default:
622535af610SEd Maste debug2_f("interface %s: unsupported address family %d",
623535af610SEd Maste ifa->ifa_name, ifa->ifa_addr->sa_family);
624535af610SEd Maste continue;
625535af610SEd Maste }
626535af610SEd Maste if ((r = getnameinfo(ifa->ifa_addr, salen, addr, sizeof(addr),
627535af610SEd Maste NULL, 0, NI_NUMERICHOST)) != 0) {
628535af610SEd Maste debug2_f("interface %s getnameinfo failed: %s",
629535af610SEd Maste ifa->ifa_name, gai_strerror(r));
630535af610SEd Maste continue;
631535af610SEd Maste }
632535af610SEd Maste debug3_f("interface %s addr %s", ifa->ifa_name, addr);
633535af610SEd Maste if (addr_match_cidr_list(addr, addrlist) == 1) {
634535af610SEd Maste debug3_f("matched interface %s: address %s in %s",
635535af610SEd Maste ifa->ifa_name, addr, addrlist);
636535af610SEd Maste found = 1;
637535af610SEd Maste break;
638535af610SEd Maste }
639535af610SEd Maste }
640535af610SEd Maste freeifaddrs(ifaddrs);
641535af610SEd Maste return found;
642535af610SEd Maste #else /* HAVE_IFADDRS_H */
643535af610SEd Maste error("match localnetwork: not supported on this platform");
644535af610SEd Maste return 0;
645535af610SEd Maste #endif /* HAVE_IFADDRS_H */
646535af610SEd Maste }
647535af610SEd Maste
648535af610SEd Maste /*
6493d9fd9fcSEd Maste * Expand a "match exec" command or an Include path, caller must free returned
6503d9fd9fcSEd Maste * value.
6513d9fd9fcSEd Maste */
6523d9fd9fcSEd Maste static char *
expand_match_exec_or_include_path(const char * path,Options * options,struct passwd * pw,const char * host_arg,const char * original_host,int final_pass,int is_include_path)6533d9fd9fcSEd Maste expand_match_exec_or_include_path(const char *path, Options *options,
6543d9fd9fcSEd Maste struct passwd *pw, const char *host_arg, const char *original_host,
6553d9fd9fcSEd Maste int final_pass, int is_include_path)
6563d9fd9fcSEd Maste {
6573d9fd9fcSEd Maste char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
6583d9fd9fcSEd Maste char uidstr[32], *conn_hash_hex, *keyalias, *jmphost, *ruser;
6593d9fd9fcSEd Maste char *host, *ret;
6603d9fd9fcSEd Maste int port;
6613d9fd9fcSEd Maste
6623d9fd9fcSEd Maste port = options->port <= 0 ? default_ssh_port() : options->port;
6633d9fd9fcSEd Maste ruser = options->user == NULL ? pw->pw_name : options->user;
6643d9fd9fcSEd Maste if (final_pass) {
6653d9fd9fcSEd Maste host = xstrdup(options->hostname);
6663d9fd9fcSEd Maste } else if (options->hostname != NULL) {
6673d9fd9fcSEd Maste /* NB. Please keep in sync with ssh.c:main() */
6683d9fd9fcSEd Maste host = percent_expand(options->hostname,
6693d9fd9fcSEd Maste "h", host_arg, (char *)NULL);
6703d9fd9fcSEd Maste } else {
6713d9fd9fcSEd Maste host = xstrdup(host_arg);
6723d9fd9fcSEd Maste }
6733d9fd9fcSEd Maste if (gethostname(thishost, sizeof(thishost)) == -1)
6743d9fd9fcSEd Maste fatal("gethostname: %s", strerror(errno));
6753d9fd9fcSEd Maste jmphost = option_clear_or_none(options->jump_host) ?
6763d9fd9fcSEd Maste "" : options->jump_host;
6773d9fd9fcSEd Maste strlcpy(shorthost, thishost, sizeof(shorthost));
6783d9fd9fcSEd Maste shorthost[strcspn(thishost, ".")] = '\0';
6793d9fd9fcSEd Maste snprintf(portstr, sizeof(portstr), "%d", port);
6803d9fd9fcSEd Maste snprintf(uidstr, sizeof(uidstr), "%llu",
6813d9fd9fcSEd Maste (unsigned long long)pw->pw_uid);
6823d9fd9fcSEd Maste conn_hash_hex = ssh_connection_hash(thishost, host,
6833d9fd9fcSEd Maste portstr, ruser, jmphost);
6843d9fd9fcSEd Maste keyalias = options->host_key_alias ? options->host_key_alias : host;
6853d9fd9fcSEd Maste
6863d9fd9fcSEd Maste ret = (is_include_path ? percent_dollar_expand : percent_expand)(path,
6873d9fd9fcSEd Maste "C", conn_hash_hex,
6883d9fd9fcSEd Maste "L", shorthost,
6893d9fd9fcSEd Maste "d", pw->pw_dir,
6903d9fd9fcSEd Maste "h", host,
6913d9fd9fcSEd Maste "k", keyalias,
6923d9fd9fcSEd Maste "l", thishost,
6933d9fd9fcSEd Maste "n", original_host,
6943d9fd9fcSEd Maste "p", portstr,
6953d9fd9fcSEd Maste "r", ruser,
6963d9fd9fcSEd Maste "u", pw->pw_name,
6973d9fd9fcSEd Maste "i", uidstr,
6983d9fd9fcSEd Maste "j", jmphost,
6993d9fd9fcSEd Maste (char *)NULL);
7003d9fd9fcSEd Maste free(host);
7013d9fd9fcSEd Maste free(conn_hash_hex);
7023d9fd9fcSEd Maste return ret;
7033d9fd9fcSEd Maste }
7043d9fd9fcSEd Maste
7053d9fd9fcSEd Maste /*
706f7167e0eSDag-Erling Smørgrav * Parse and execute a Match directive.
707f7167e0eSDag-Erling Smørgrav */
708f7167e0eSDag-Erling Smørgrav static int
match_cfg_line(Options * options,const char * full_line,int * acp,char *** avp,struct passwd * pw,const char * host_arg,const char * original_host,int final_pass,int * want_final_pass,const char * filename,int linenum)7093d9fd9fcSEd Maste match_cfg_line(Options *options, const char *full_line, int *acp, char ***avp,
7103d9fd9fcSEd Maste struct passwd *pw, const char *host_arg, const char *original_host,
7113d9fd9fcSEd Maste int final_pass, int *want_final_pass, const char *filename, int linenum)
712f7167e0eSDag-Erling Smørgrav {
713*0ae642c7SEd Maste char *arg, *oattrib = NULL, *attrib = NULL, *cmd, *host, *criteria;
714f7167e0eSDag-Erling Smørgrav const char *ruser;
7153d9fd9fcSEd Maste int r, this_result, result = 1, attributes = 0, negate;
716f7167e0eSDag-Erling Smørgrav
717f7167e0eSDag-Erling Smørgrav /*
718f7167e0eSDag-Erling Smørgrav * Configuration is likely to be incomplete at this point so we
719f7167e0eSDag-Erling Smørgrav * must be prepared to use default values.
720f7167e0eSDag-Erling Smørgrav */
721f7167e0eSDag-Erling Smørgrav ruser = options->user == NULL ? pw->pw_name : options->user;
72219261079SEd Maste if (final_pass) {
723acc1a9efSDag-Erling Smørgrav host = xstrdup(options->hostname);
724acc1a9efSDag-Erling Smørgrav } else if (options->hostname != NULL) {
725f7167e0eSDag-Erling Smørgrav /* NB. Please keep in sync with ssh.c:main() */
726f7167e0eSDag-Erling Smørgrav host = percent_expand(options->hostname,
727f7167e0eSDag-Erling Smørgrav "h", host_arg, (char *)NULL);
728acc1a9efSDag-Erling Smørgrav } else {
729f7167e0eSDag-Erling Smørgrav host = xstrdup(host_arg);
730acc1a9efSDag-Erling Smørgrav }
731f7167e0eSDag-Erling Smørgrav
732bc5531deSDag-Erling Smørgrav debug2("checking match for '%s' host %s originally %s",
7333d9fd9fcSEd Maste full_line, host, original_host);
734*0ae642c7SEd Maste while ((attrib = argv_next(acp, avp)) != NULL) {
735*0ae642c7SEd Maste attrib = oattrib = xstrdup(attrib);
73619261079SEd Maste /* Terminate on comment */
73719261079SEd Maste if (*attrib == '#') {
7383d9fd9fcSEd Maste argv_consume(acp);
73919261079SEd Maste break;
74019261079SEd Maste }
74119261079SEd Maste arg = criteria = NULL;
742bc5531deSDag-Erling Smørgrav this_result = 1;
7434d3fc8b0SEd Maste if ((negate = (attrib[0] == '!')))
744bc5531deSDag-Erling Smørgrav attrib++;
74519261079SEd Maste /* Criterion "all" has no argument and must appear alone */
746f7167e0eSDag-Erling Smørgrav if (strcasecmp(attrib, "all") == 0) {
7473d9fd9fcSEd Maste if (attributes > 1 ||
7483d9fd9fcSEd Maste ((arg = argv_next(acp, avp)) != NULL &&
74919261079SEd Maste *arg != '\0' && *arg != '#')) {
750bc5531deSDag-Erling Smørgrav error("%.200s line %d: '%s' cannot be combined "
751bc5531deSDag-Erling Smørgrav "with other Match attributes",
752bc5531deSDag-Erling Smørgrav filename, linenum, oattrib);
753f7167e0eSDag-Erling Smørgrav result = -1;
754f7167e0eSDag-Erling Smørgrav goto out;
755f7167e0eSDag-Erling Smørgrav }
75619261079SEd Maste if (arg != NULL && *arg == '#')
7573d9fd9fcSEd Maste argv_consume(acp); /* consume remaining args */
758bc5531deSDag-Erling Smørgrav if (result)
759bc5531deSDag-Erling Smørgrav result = negate ? 0 : 1;
760f7167e0eSDag-Erling Smørgrav goto out;
761f7167e0eSDag-Erling Smørgrav }
762bc5531deSDag-Erling Smørgrav attributes++;
76319261079SEd Maste /* criteria "final" and "canonical" have no argument */
76419261079SEd Maste if (strcasecmp(attrib, "canonical") == 0 ||
76519261079SEd Maste strcasecmp(attrib, "final") == 0) {
76619261079SEd Maste /*
76719261079SEd Maste * If the config requests "Match final" then remember
76819261079SEd Maste * this so we can perform a second pass later.
76919261079SEd Maste */
77019261079SEd Maste if (strcasecmp(attrib, "final") == 0 &&
77119261079SEd Maste want_final_pass != NULL)
77219261079SEd Maste *want_final_pass = 1;
77319261079SEd Maste r = !!final_pass; /* force bitmask member to boolean */
774bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0))
775bc5531deSDag-Erling Smørgrav this_result = result = 0;
776bc5531deSDag-Erling Smørgrav debug3("%.200s line %d: %smatched '%s'",
777bc5531deSDag-Erling Smørgrav filename, linenum,
778bc5531deSDag-Erling Smørgrav this_result ? "" : "not ", oattrib);
779bc5531deSDag-Erling Smørgrav continue;
780bc5531deSDag-Erling Smørgrav }
781*0ae642c7SEd Maste
782*0ae642c7SEd Maste /* Keep this list in sync with below */
783*0ae642c7SEd Maste if (strprefix(attrib, "host=", 1) != NULL ||
784*0ae642c7SEd Maste strprefix(attrib, "originalhost=", 1) != NULL ||
785*0ae642c7SEd Maste strprefix(attrib, "user=", 1) != NULL ||
786*0ae642c7SEd Maste strprefix(attrib, "localuser=", 1) != NULL ||
787*0ae642c7SEd Maste strprefix(attrib, "localnetwork=", 1) != NULL ||
788*0ae642c7SEd Maste strprefix(attrib, "tagged=", 1) != NULL ||
789*0ae642c7SEd Maste strprefix(attrib, "exec=", 1) != NULL) {
790*0ae642c7SEd Maste arg = strchr(attrib, '=');
791*0ae642c7SEd Maste *(arg++) = '\0';
792*0ae642c7SEd Maste } else {
793*0ae642c7SEd Maste arg = argv_next(acp, avp);
794*0ae642c7SEd Maste }
795*0ae642c7SEd Maste
796bc5531deSDag-Erling Smørgrav /* All other criteria require an argument */
797*0ae642c7SEd Maste if (arg == NULL || *arg == '\0' || *arg == '#') {
798f7167e0eSDag-Erling Smørgrav error("Missing Match criteria for %s", attrib);
799f7167e0eSDag-Erling Smørgrav result = -1;
800f7167e0eSDag-Erling Smørgrav goto out;
801f7167e0eSDag-Erling Smørgrav }
802f7167e0eSDag-Erling Smørgrav if (strcasecmp(attrib, "host") == 0) {
803bc5531deSDag-Erling Smørgrav criteria = xstrdup(host);
804557f75e5SDag-Erling Smørgrav r = match_hostname(host, arg) == 1;
805bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0))
806bc5531deSDag-Erling Smørgrav this_result = result = 0;
807f7167e0eSDag-Erling Smørgrav } else if (strcasecmp(attrib, "originalhost") == 0) {
808bc5531deSDag-Erling Smørgrav criteria = xstrdup(original_host);
809557f75e5SDag-Erling Smørgrav r = match_hostname(original_host, arg) == 1;
810bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0))
811bc5531deSDag-Erling Smørgrav this_result = result = 0;
812f7167e0eSDag-Erling Smørgrav } else if (strcasecmp(attrib, "user") == 0) {
813bc5531deSDag-Erling Smørgrav criteria = xstrdup(ruser);
814557f75e5SDag-Erling Smørgrav r = match_pattern_list(ruser, arg, 0) == 1;
815bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0))
816bc5531deSDag-Erling Smørgrav this_result = result = 0;
817f7167e0eSDag-Erling Smørgrav } else if (strcasecmp(attrib, "localuser") == 0) {
818bc5531deSDag-Erling Smørgrav criteria = xstrdup(pw->pw_name);
819557f75e5SDag-Erling Smørgrav r = match_pattern_list(pw->pw_name, arg, 0) == 1;
820bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0))
821bc5531deSDag-Erling Smørgrav this_result = result = 0;
822535af610SEd Maste } else if (strcasecmp(attrib, "localnetwork") == 0) {
823535af610SEd Maste if (addr_match_cidr_list(NULL, arg) == -1) {
824535af610SEd Maste /* Error already printed */
825535af610SEd Maste result = -1;
826535af610SEd Maste goto out;
827535af610SEd Maste }
828535af610SEd Maste r = check_match_ifaddrs(arg) == 1;
829535af610SEd Maste if (r == (negate ? 1 : 0))
830535af610SEd Maste this_result = result = 0;
831535af610SEd Maste } else if (strcasecmp(attrib, "tagged") == 0) {
832535af610SEd Maste criteria = xstrdup(options->tag == NULL ? "" :
833535af610SEd Maste options->tag);
834535af610SEd Maste r = match_pattern_list(criteria, arg, 0) == 1;
835535af610SEd Maste if (r == (negate ? 1 : 0))
836535af610SEd Maste this_result = result = 0;
837f7167e0eSDag-Erling Smørgrav } else if (strcasecmp(attrib, "exec") == 0) {
8383d9fd9fcSEd Maste if ((cmd = expand_match_exec_or_include_path(arg,
8393d9fd9fcSEd Maste options, pw, host_arg, original_host,
8403d9fd9fcSEd Maste final_pass, 0)) == NULL) {
8413d9fd9fcSEd Maste fatal("%.200s line %d: failed to expand match "
8423d9fd9fcSEd Maste "exec '%.100s'", filename, linenum, arg);
8433d9fd9fcSEd Maste }
844b83788ffSDag-Erling Smørgrav if (result != 1) {
845b83788ffSDag-Erling Smørgrav /* skip execution if prior predicate failed */
846bc5531deSDag-Erling Smørgrav debug3("%.200s line %d: skipped exec "
847bc5531deSDag-Erling Smørgrav "\"%.100s\"", filename, linenum, cmd);
848bc5531deSDag-Erling Smørgrav free(cmd);
849bc5531deSDag-Erling Smørgrav continue;
850bc5531deSDag-Erling Smørgrav }
851f7167e0eSDag-Erling Smørgrav r = execute_in_shell(cmd);
852f7167e0eSDag-Erling Smørgrav if (r == -1) {
853b83788ffSDag-Erling Smørgrav fatal("%.200s line %d: match exec "
854b83788ffSDag-Erling Smørgrav "'%.100s' error", filename,
855b83788ffSDag-Erling Smørgrav linenum, cmd);
856b83788ffSDag-Erling Smørgrav }
857bc5531deSDag-Erling Smørgrav criteria = xstrdup(cmd);
858f7167e0eSDag-Erling Smørgrav free(cmd);
859bc5531deSDag-Erling Smørgrav /* Force exit status to boolean */
860bc5531deSDag-Erling Smørgrav r = r == 0;
861bc5531deSDag-Erling Smørgrav if (r == (negate ? 1 : 0))
862bc5531deSDag-Erling Smørgrav this_result = result = 0;
863f7167e0eSDag-Erling Smørgrav } else {
864f7167e0eSDag-Erling Smørgrav error("Unsupported Match attribute %s", attrib);
865f7167e0eSDag-Erling Smørgrav result = -1;
866f7167e0eSDag-Erling Smørgrav goto out;
867f7167e0eSDag-Erling Smørgrav }
868535af610SEd Maste debug3("%.200s line %d: %smatched '%s%s%.100s%s' ",
869535af610SEd Maste filename, linenum, this_result ? "": "not ", oattrib,
870535af610SEd Maste criteria == NULL ? "" : " \"",
871535af610SEd Maste criteria == NULL ? "" : criteria,
872535af610SEd Maste criteria == NULL ? "" : "\"");
873bc5531deSDag-Erling Smørgrav free(criteria);
874*0ae642c7SEd Maste free(oattrib);
875*0ae642c7SEd Maste oattrib = attrib = NULL;
876f7167e0eSDag-Erling Smørgrav }
877f7167e0eSDag-Erling Smørgrav if (attributes == 0) {
878f7167e0eSDag-Erling Smørgrav error("One or more attributes required for Match");
879f7167e0eSDag-Erling Smørgrav result = -1;
880f7167e0eSDag-Erling Smørgrav goto out;
881f7167e0eSDag-Erling Smørgrav }
882f7167e0eSDag-Erling Smørgrav out:
883bc5531deSDag-Erling Smørgrav if (result != -1)
884bc5531deSDag-Erling Smørgrav debug2("match %sfound", result ? "" : "not ");
885*0ae642c7SEd Maste free(oattrib);
886f7167e0eSDag-Erling Smørgrav free(host);
887f7167e0eSDag-Erling Smørgrav return result;
888f7167e0eSDag-Erling Smørgrav }
889f7167e0eSDag-Erling Smørgrav
890190cef3dSDag-Erling Smørgrav /* Remove environment variable by pattern */
891190cef3dSDag-Erling Smørgrav static void
rm_env(Options * options,const char * arg,const char * filename,int linenum)892190cef3dSDag-Erling Smørgrav rm_env(Options *options, const char *arg, const char *filename, int linenum)
893190cef3dSDag-Erling Smørgrav {
89438a52bd3SEd Maste u_int i, j, onum_send_env = options->num_send_env;
895190cef3dSDag-Erling Smørgrav
896190cef3dSDag-Erling Smørgrav /* Remove an environment variable */
897190cef3dSDag-Erling Smørgrav for (i = 0; i < options->num_send_env; ) {
89838a52bd3SEd Maste if (!match_pattern(options->send_env[i], arg + 1)) {
899190cef3dSDag-Erling Smørgrav i++;
900190cef3dSDag-Erling Smørgrav continue;
901190cef3dSDag-Erling Smørgrav }
902190cef3dSDag-Erling Smørgrav debug3("%s line %d: removing environment %s",
90338a52bd3SEd Maste filename, linenum, options->send_env[i]);
904190cef3dSDag-Erling Smørgrav free(options->send_env[i]);
905190cef3dSDag-Erling Smørgrav options->send_env[i] = NULL;
906190cef3dSDag-Erling Smørgrav for (j = i; j < options->num_send_env - 1; j++) {
907190cef3dSDag-Erling Smørgrav options->send_env[j] = options->send_env[j + 1];
908190cef3dSDag-Erling Smørgrav options->send_env[j + 1] = NULL;
909190cef3dSDag-Erling Smørgrav }
910190cef3dSDag-Erling Smørgrav options->num_send_env--;
911190cef3dSDag-Erling Smørgrav /* NB. don't increment i */
912190cef3dSDag-Erling Smørgrav }
91319261079SEd Maste if (onum_send_env != options->num_send_env) {
91419261079SEd Maste options->send_env = xrecallocarray(options->send_env,
91519261079SEd Maste onum_send_env, options->num_send_env,
91619261079SEd Maste sizeof(*options->send_env));
91719261079SEd Maste }
918190cef3dSDag-Erling Smørgrav }
919190cef3dSDag-Erling Smørgrav
920511b41d2SMark Murray /*
921ca3176e7SBrian Feldman * Returns the number of the token pointed to by cp or oBadOption.
922511b41d2SMark Murray */
923511b41d2SMark Murray static OpCodes
parse_token(const char * cp,const char * filename,int linenum,const char * ignored_unknown)924e4a9863fSDag-Erling Smørgrav parse_token(const char *cp, const char *filename, int linenum,
925e4a9863fSDag-Erling Smørgrav const char *ignored_unknown)
926511b41d2SMark Murray {
927e4a9863fSDag-Erling Smørgrav int i;
928511b41d2SMark Murray
929511b41d2SMark Murray for (i = 0; keywords[i].name; i++)
930e4a9863fSDag-Erling Smørgrav if (strcmp(cp, keywords[i].name) == 0)
931511b41d2SMark Murray return keywords[i].opcode;
932557f75e5SDag-Erling Smørgrav if (ignored_unknown != NULL &&
933557f75e5SDag-Erling Smørgrav match_pattern_list(cp, ignored_unknown, 1) == 1)
934e4a9863fSDag-Erling Smørgrav return oIgnoredUnknownOption;
935ca3176e7SBrian Feldman error("%s: line %d: Bad configuration option: %s",
936511b41d2SMark Murray filename, linenum, cp);
937511b41d2SMark Murray return oBadOption;
938511b41d2SMark Murray }
939511b41d2SMark Murray
940a91a2465SEd Maste static void
free_canon_cnames(struct allowed_cname * cnames,u_int n)941a91a2465SEd Maste free_canon_cnames(struct allowed_cname *cnames, u_int n)
942a91a2465SEd Maste {
943a91a2465SEd Maste u_int i;
944a91a2465SEd Maste
945a91a2465SEd Maste if (cnames == NULL || n == 0)
946a91a2465SEd Maste return;
947a91a2465SEd Maste for (i = 0; i < n; i++) {
948a91a2465SEd Maste free(cnames[i].source_list);
949a91a2465SEd Maste free(cnames[i].target_list);
950a91a2465SEd Maste }
951a91a2465SEd Maste free(cnames);
952a91a2465SEd Maste }
953a91a2465SEd Maste
954f7167e0eSDag-Erling Smørgrav /* Multistate option parsing */
955f7167e0eSDag-Erling Smørgrav struct multistate {
956f7167e0eSDag-Erling Smørgrav char *key;
957f7167e0eSDag-Erling Smørgrav int value;
958f7167e0eSDag-Erling Smørgrav };
959f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_flag[] = {
960f7167e0eSDag-Erling Smørgrav { "true", 1 },
961f7167e0eSDag-Erling Smørgrav { "false", 0 },
962f7167e0eSDag-Erling Smørgrav { "yes", 1 },
963f7167e0eSDag-Erling Smørgrav { "no", 0 },
964f7167e0eSDag-Erling Smørgrav { NULL, -1 }
965f7167e0eSDag-Erling Smørgrav };
966f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_yesnoask[] = {
967f7167e0eSDag-Erling Smørgrav { "true", 1 },
968f7167e0eSDag-Erling Smørgrav { "false", 0 },
969f7167e0eSDag-Erling Smørgrav { "yes", 1 },
970f7167e0eSDag-Erling Smørgrav { "no", 0 },
971f7167e0eSDag-Erling Smørgrav { "ask", 2 },
972f7167e0eSDag-Erling Smørgrav { NULL, -1 }
973f7167e0eSDag-Erling Smørgrav };
9744f52dfbbSDag-Erling Smørgrav static const struct multistate multistate_strict_hostkey[] = {
9754f52dfbbSDag-Erling Smørgrav { "true", SSH_STRICT_HOSTKEY_YES },
9764f52dfbbSDag-Erling Smørgrav { "false", SSH_STRICT_HOSTKEY_OFF },
9774f52dfbbSDag-Erling Smørgrav { "yes", SSH_STRICT_HOSTKEY_YES },
9784f52dfbbSDag-Erling Smørgrav { "no", SSH_STRICT_HOSTKEY_OFF },
9794f52dfbbSDag-Erling Smørgrav { "ask", SSH_STRICT_HOSTKEY_ASK },
9804f52dfbbSDag-Erling Smørgrav { "off", SSH_STRICT_HOSTKEY_OFF },
9814f52dfbbSDag-Erling Smørgrav { "accept-new", SSH_STRICT_HOSTKEY_NEW },
9824f52dfbbSDag-Erling Smørgrav { NULL, -1 }
9834f52dfbbSDag-Erling Smørgrav };
984acc1a9efSDag-Erling Smørgrav static const struct multistate multistate_yesnoaskconfirm[] = {
985acc1a9efSDag-Erling Smørgrav { "true", 1 },
986acc1a9efSDag-Erling Smørgrav { "false", 0 },
987acc1a9efSDag-Erling Smørgrav { "yes", 1 },
988acc1a9efSDag-Erling Smørgrav { "no", 0 },
989acc1a9efSDag-Erling Smørgrav { "ask", 2 },
990acc1a9efSDag-Erling Smørgrav { "confirm", 3 },
991acc1a9efSDag-Erling Smørgrav { NULL, -1 }
992acc1a9efSDag-Erling Smørgrav };
993f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_addressfamily[] = {
994f7167e0eSDag-Erling Smørgrav { "inet", AF_INET },
995f7167e0eSDag-Erling Smørgrav { "inet6", AF_INET6 },
996f7167e0eSDag-Erling Smørgrav { "any", AF_UNSPEC },
997f7167e0eSDag-Erling Smørgrav { NULL, -1 }
998f7167e0eSDag-Erling Smørgrav };
999f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_controlmaster[] = {
1000f7167e0eSDag-Erling Smørgrav { "true", SSHCTL_MASTER_YES },
1001f7167e0eSDag-Erling Smørgrav { "yes", SSHCTL_MASTER_YES },
1002f7167e0eSDag-Erling Smørgrav { "false", SSHCTL_MASTER_NO },
1003f7167e0eSDag-Erling Smørgrav { "no", SSHCTL_MASTER_NO },
1004f7167e0eSDag-Erling Smørgrav { "auto", SSHCTL_MASTER_AUTO },
1005f7167e0eSDag-Erling Smørgrav { "ask", SSHCTL_MASTER_ASK },
1006f7167e0eSDag-Erling Smørgrav { "autoask", SSHCTL_MASTER_AUTO_ASK },
1007f7167e0eSDag-Erling Smørgrav { NULL, -1 }
1008f7167e0eSDag-Erling Smørgrav };
1009f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_tunnel[] = {
1010f7167e0eSDag-Erling Smørgrav { "ethernet", SSH_TUNMODE_ETHERNET },
1011f7167e0eSDag-Erling Smørgrav { "point-to-point", SSH_TUNMODE_POINTOPOINT },
1012f7167e0eSDag-Erling Smørgrav { "true", SSH_TUNMODE_DEFAULT },
1013f7167e0eSDag-Erling Smørgrav { "yes", SSH_TUNMODE_DEFAULT },
1014f7167e0eSDag-Erling Smørgrav { "false", SSH_TUNMODE_NO },
1015f7167e0eSDag-Erling Smørgrav { "no", SSH_TUNMODE_NO },
1016f7167e0eSDag-Erling Smørgrav { NULL, -1 }
1017f7167e0eSDag-Erling Smørgrav };
1018f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_requesttty[] = {
1019f7167e0eSDag-Erling Smørgrav { "true", REQUEST_TTY_YES },
1020f7167e0eSDag-Erling Smørgrav { "yes", REQUEST_TTY_YES },
1021f7167e0eSDag-Erling Smørgrav { "false", REQUEST_TTY_NO },
1022f7167e0eSDag-Erling Smørgrav { "no", REQUEST_TTY_NO },
1023f7167e0eSDag-Erling Smørgrav { "force", REQUEST_TTY_FORCE },
1024f7167e0eSDag-Erling Smørgrav { "auto", REQUEST_TTY_AUTO },
1025f7167e0eSDag-Erling Smørgrav { NULL, -1 }
1026f7167e0eSDag-Erling Smørgrav };
102719261079SEd Maste static const struct multistate multistate_sessiontype[] = {
102819261079SEd Maste { "none", SESSION_TYPE_NONE },
102919261079SEd Maste { "subsystem", SESSION_TYPE_SUBSYSTEM },
103019261079SEd Maste { "default", SESSION_TYPE_DEFAULT },
103119261079SEd Maste { NULL, -1 }
103219261079SEd Maste };
1033f7167e0eSDag-Erling Smørgrav static const struct multistate multistate_canonicalizehostname[] = {
1034f7167e0eSDag-Erling Smørgrav { "true", SSH_CANONICALISE_YES },
1035f7167e0eSDag-Erling Smørgrav { "false", SSH_CANONICALISE_NO },
1036f7167e0eSDag-Erling Smørgrav { "yes", SSH_CANONICALISE_YES },
1037f7167e0eSDag-Erling Smørgrav { "no", SSH_CANONICALISE_NO },
1038f7167e0eSDag-Erling Smørgrav { "always", SSH_CANONICALISE_ALWAYS },
1039f7167e0eSDag-Erling Smørgrav { NULL, -1 }
1040f7167e0eSDag-Erling Smørgrav };
10411323ec57SEd Maste static const struct multistate multistate_pubkey_auth[] = {
10421323ec57SEd Maste { "true", SSH_PUBKEY_AUTH_ALL },
10431323ec57SEd Maste { "false", SSH_PUBKEY_AUTH_NO },
10441323ec57SEd Maste { "yes", SSH_PUBKEY_AUTH_ALL },
10451323ec57SEd Maste { "no", SSH_PUBKEY_AUTH_NO },
10461323ec57SEd Maste { "unbound", SSH_PUBKEY_AUTH_UNBOUND },
10471323ec57SEd Maste { "host-bound", SSH_PUBKEY_AUTH_HBOUND },
10481323ec57SEd Maste { NULL, -1 }
10491323ec57SEd Maste };
105019261079SEd Maste static const struct multistate multistate_compression[] = {
105119261079SEd Maste #ifdef WITH_ZLIB
10523d9fd9fcSEd Maste { "yes", COMP_DELAYED },
105319261079SEd Maste #endif
105419261079SEd Maste { "no", COMP_NONE },
105519261079SEd Maste { NULL, -1 }
105619261079SEd Maste };
105719261079SEd Maste
105819261079SEd Maste static int
parse_multistate_value(const char * arg,const char * filename,int linenum,const struct multistate * multistate_ptr)105919261079SEd Maste parse_multistate_value(const char *arg, const char *filename, int linenum,
106019261079SEd Maste const struct multistate *multistate_ptr)
106119261079SEd Maste {
106219261079SEd Maste int i;
106319261079SEd Maste
106419261079SEd Maste if (!arg || *arg == '\0') {
106519261079SEd Maste error("%s line %d: missing argument.", filename, linenum);
106619261079SEd Maste return -1;
106719261079SEd Maste }
106819261079SEd Maste for (i = 0; multistate_ptr[i].key != NULL; i++) {
106919261079SEd Maste if (strcasecmp(arg, multistate_ptr[i].key) == 0)
107019261079SEd Maste return multistate_ptr[i].value;
107119261079SEd Maste }
107219261079SEd Maste return -1;
107319261079SEd Maste }
1074f7167e0eSDag-Erling Smørgrav
1075511b41d2SMark Murray /*
1076511b41d2SMark Murray * Processes a single option line as used in the configuration files. This
1077511b41d2SMark Murray * only sets those values that have not already been set.
1078511b41d2SMark Murray */
1079511b41d2SMark Murray 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)1080f7167e0eSDag-Erling Smørgrav process_config_line(Options *options, struct passwd *pw, const char *host,
1081bc5531deSDag-Erling Smørgrav const char *original_host, char *line, const char *filename,
1082bc5531deSDag-Erling Smørgrav int linenum, int *activep, int flags)
1083511b41d2SMark Murray {
1084076ad2f8SDag-Erling Smørgrav return process_config_line_depth(options, pw, host, original_host,
108519261079SEd Maste line, filename, linenum, activep, flags, NULL, 0);
1086076ad2f8SDag-Erling Smørgrav }
1087076ad2f8SDag-Erling Smørgrav
1088076ad2f8SDag-Erling Smørgrav #define WHITESPACE " \t\r\n"
1089076ad2f8SDag-Erling Smørgrav 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)1090076ad2f8SDag-Erling Smørgrav process_config_line_depth(Options *options, struct passwd *pw, const char *host,
1091076ad2f8SDag-Erling Smørgrav const char *original_host, char *line, const char *filename,
109219261079SEd Maste int linenum, int *activep, int flags, int *want_final_pass, int depth)
1093076ad2f8SDag-Erling Smørgrav {
10941323ec57SEd Maste char *str, **charptr, *endofnumber, *keyword, *arg, *arg2, *p;
109519261079SEd Maste char **cpptr, ***cppptr, fwdarg[256];
1096a91a2465SEd Maste u_int i, *uintptr, max_entries = 0;
1097076ad2f8SDag-Erling Smørgrav int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
1098a91a2465SEd Maste int remotefwd, dynamicfwd, ca_only = 0, found = 0;
1099d4af9e69SDag-Erling Smørgrav LogLevel *log_level_ptr;
11004f52dfbbSDag-Erling Smørgrav SyslogFacility *log_facility_ptr;
1101e4a9863fSDag-Erling Smørgrav long long val64;
1102e73e9afaSDag-Erling Smørgrav size_t len;
1103a0ee8cc6SDag-Erling Smørgrav struct Forward fwd;
1104f7167e0eSDag-Erling Smørgrav const struct multistate *multistate_ptr;
1105076ad2f8SDag-Erling Smørgrav glob_t gl;
110647dd1d1bSDag-Erling Smørgrav const char *errstr;
110719261079SEd Maste char **oav = NULL, **av;
110819261079SEd Maste int oac = 0, ac;
110919261079SEd Maste int ret = -1;
1110a91a2465SEd Maste struct allowed_cname *cnames = NULL;
1111a91a2465SEd Maste u_int ncnames = 0;
1112a91a2465SEd Maste char **strs = NULL; /* string array arguments; freed implicitly */
1113a91a2465SEd Maste u_int nstrs = 0;
1114f7167e0eSDag-Erling Smørgrav
1115f7167e0eSDag-Erling Smørgrav if (activep == NULL) { /* We are processing a command line directive */
1116f7167e0eSDag-Erling Smørgrav cmdline = 1;
1117f7167e0eSDag-Erling Smørgrav activep = &cmdline;
1118f7167e0eSDag-Erling Smørgrav }
1119511b41d2SMark Murray
1120d93a896eSDag-Erling Smørgrav /* Strip trailing whitespace. Allow \f (form feed) at EOL only */
1121557f75e5SDag-Erling Smørgrav if ((len = strlen(line)) == 0)
1122557f75e5SDag-Erling Smørgrav return 0;
1123557f75e5SDag-Erling Smørgrav for (len--; len > 0; len--) {
1124d93a896eSDag-Erling Smørgrav if (strchr(WHITESPACE "\f", line[len]) == NULL)
1125cf2b5f3bSDag-Erling Smørgrav break;
1126cf2b5f3bSDag-Erling Smørgrav line[len] = '\0';
1127cf2b5f3bSDag-Erling Smørgrav }
1128cf2b5f3bSDag-Erling Smørgrav
112919261079SEd Maste str = line;
1130c2d3a559SKris Kennaway /* Get the keyword. (Each line is supposed to begin with a keyword). */
113119261079SEd Maste if ((keyword = strdelim(&str)) == NULL)
1132333ee039SDag-Erling Smørgrav return 0;
1133c2d3a559SKris Kennaway /* Ignore leading whitespace. */
1134c2d3a559SKris Kennaway if (*keyword == '\0')
113519261079SEd Maste keyword = strdelim(&str);
1136ca3176e7SBrian Feldman if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
1137511b41d2SMark Murray return 0;
1138e4a9863fSDag-Erling Smørgrav /* Match lowercase keyword */
1139f7167e0eSDag-Erling Smørgrav lowercase(keyword);
1140511b41d2SMark Murray
114119261079SEd Maste /* Prepare to parse remainder of line */
114219261079SEd Maste if (str != NULL)
114319261079SEd Maste str += strspn(str, WHITESPACE);
114419261079SEd Maste if (str == NULL || *str == '\0') {
114519261079SEd Maste error("%s line %d: no argument after keyword \"%s\"",
114619261079SEd Maste filename, linenum, keyword);
114719261079SEd Maste return -1;
114819261079SEd Maste }
1149e4a9863fSDag-Erling Smørgrav opcode = parse_token(keyword, filename, linenum,
1150e4a9863fSDag-Erling Smørgrav options->ignored_unknown);
115119261079SEd Maste if (argv_split(str, &oac, &oav, 1) != 0) {
115219261079SEd Maste error("%s line %d: invalid quotes", filename, linenum);
115319261079SEd Maste return -1;
115419261079SEd Maste }
115519261079SEd Maste ac = oac;
115619261079SEd Maste av = oav;
1157511b41d2SMark Murray
1158511b41d2SMark Murray switch (opcode) {
1159511b41d2SMark Murray case oBadOption:
1160511b41d2SMark Murray /* don't panic, but count bad options */
116119261079SEd Maste goto out;
11624f52dfbbSDag-Erling Smørgrav case oIgnore:
116319261079SEd Maste argv_consume(&ac);
116419261079SEd Maste break;
1165e4a9863fSDag-Erling Smørgrav case oIgnoredUnknownOption:
1166e4a9863fSDag-Erling Smørgrav debug("%s line %d: Ignored unknown option \"%s\"",
1167e4a9863fSDag-Erling Smørgrav filename, linenum, keyword);
116819261079SEd Maste argv_consume(&ac);
116919261079SEd Maste break;
1170cf2b5f3bSDag-Erling Smørgrav case oConnectTimeout:
1171cf2b5f3bSDag-Erling Smørgrav intptr = &options->connection_timeout;
11721ec0d754SDag-Erling Smørgrav parse_time:
117319261079SEd Maste arg = argv_next(&ac, &av);
117419261079SEd Maste if (!arg || *arg == '\0') {
117519261079SEd Maste error("%s line %d: missing time value.",
1176cf2b5f3bSDag-Erling Smørgrav filename, linenum);
117719261079SEd Maste goto out;
117819261079SEd Maste }
1179bc5531deSDag-Erling Smørgrav if (strcmp(arg, "none") == 0)
1180bc5531deSDag-Erling Smørgrav value = -1;
118119261079SEd Maste else if ((value = convtime(arg)) == -1) {
118219261079SEd Maste error("%s line %d: invalid time value.",
1183cf2b5f3bSDag-Erling Smørgrav filename, linenum);
118419261079SEd Maste goto out;
118519261079SEd Maste }
1186d4af9e69SDag-Erling Smørgrav if (*activep && *intptr == -1)
1187cf2b5f3bSDag-Erling Smørgrav *intptr = value;
1188cf2b5f3bSDag-Erling Smørgrav break;
1189cf2b5f3bSDag-Erling Smørgrav
1190511b41d2SMark Murray case oForwardAgent:
1191511b41d2SMark Murray intptr = &options->forward_agent;
119219261079SEd Maste
119319261079SEd Maste arg = argv_next(&ac, &av);
119419261079SEd Maste if (!arg || *arg == '\0') {
119519261079SEd Maste error("%s line %d: missing argument.",
1196f7167e0eSDag-Erling Smørgrav filename, linenum);
119719261079SEd Maste goto out;
119819261079SEd Maste }
119919261079SEd Maste
1200f7167e0eSDag-Erling Smørgrav value = -1;
120119261079SEd Maste multistate_ptr = multistate_flag;
1202f7167e0eSDag-Erling Smørgrav for (i = 0; multistate_ptr[i].key != NULL; i++) {
1203f7167e0eSDag-Erling Smørgrav if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1204f7167e0eSDag-Erling Smørgrav value = multistate_ptr[i].value;
1205f7167e0eSDag-Erling Smørgrav break;
1206f7167e0eSDag-Erling Smørgrav }
1207f7167e0eSDag-Erling Smørgrav }
120819261079SEd Maste if (value != -1) {
1209511b41d2SMark Murray if (*activep && *intptr == -1)
1210511b41d2SMark Murray *intptr = value;
1211511b41d2SMark Murray break;
121219261079SEd Maste }
121319261079SEd Maste /* ForwardAgent wasn't 'yes' or 'no', assume a path */
121419261079SEd Maste if (*activep && *intptr == -1)
121519261079SEd Maste *intptr = 1;
121619261079SEd Maste
121719261079SEd Maste charptr = &options->forward_agent_sock_path;
121819261079SEd Maste goto parse_agent_path;
1219511b41d2SMark Murray
1220511b41d2SMark Murray case oForwardX11:
1221511b41d2SMark Murray intptr = &options->forward_x11;
122219261079SEd Maste parse_flag:
122319261079SEd Maste multistate_ptr = multistate_flag;
122419261079SEd Maste parse_multistate:
122519261079SEd Maste arg = argv_next(&ac, &av);
122619261079SEd Maste if ((value = parse_multistate_value(arg, filename, linenum,
122719261079SEd Maste multistate_ptr)) == -1) {
122819261079SEd Maste error("%s line %d: unsupported option \"%s\".",
122919261079SEd Maste filename, linenum, arg);
123019261079SEd Maste goto out;
123119261079SEd Maste }
123219261079SEd Maste if (*activep && *intptr == -1)
123319261079SEd Maste *intptr = value;
123419261079SEd Maste break;
1235511b41d2SMark Murray
12361ec0d754SDag-Erling Smørgrav case oForwardX11Trusted:
12371ec0d754SDag-Erling Smørgrav intptr = &options->forward_x11_trusted;
12381ec0d754SDag-Erling Smørgrav goto parse_flag;
12391ec0d754SDag-Erling Smørgrav
1240e2f6069cSDag-Erling Smørgrav case oForwardX11Timeout:
1241e2f6069cSDag-Erling Smørgrav intptr = &options->forward_x11_timeout;
1242e2f6069cSDag-Erling Smørgrav goto parse_time;
1243e2f6069cSDag-Erling Smørgrav
1244511b41d2SMark Murray case oGatewayPorts:
1245a0ee8cc6SDag-Erling Smørgrav intptr = &options->fwd_opts.gateway_ports;
1246511b41d2SMark Murray goto parse_flag;
1247511b41d2SMark Murray
1248333ee039SDag-Erling Smørgrav case oExitOnForwardFailure:
1249333ee039SDag-Erling Smørgrav intptr = &options->exit_on_forward_failure;
1250333ee039SDag-Erling Smørgrav goto parse_flag;
1251333ee039SDag-Erling Smørgrav
1252511b41d2SMark Murray case oPasswordAuthentication:
1253511b41d2SMark Murray intptr = &options->password_authentication;
1254511b41d2SMark Murray goto parse_flag;
1255511b41d2SMark Murray
125609958426SBrian Feldman case oKbdInteractiveAuthentication:
125709958426SBrian Feldman intptr = &options->kbd_interactive_authentication;
125809958426SBrian Feldman goto parse_flag;
125909958426SBrian Feldman
126009958426SBrian Feldman case oKbdInteractiveDevices:
126109958426SBrian Feldman charptr = &options->kbd_interactive_devices;
126209958426SBrian Feldman goto parse_string;
126309958426SBrian Feldman
1264ca3176e7SBrian Feldman case oPubkeyAuthentication:
12651323ec57SEd Maste multistate_ptr = multistate_pubkey_auth;
1266ca3176e7SBrian Feldman intptr = &options->pubkey_authentication;
12671323ec57SEd Maste goto parse_multistate;
1268e8aafc91SKris Kennaway
1269ca3176e7SBrian Feldman case oHostbasedAuthentication:
1270ca3176e7SBrian Feldman intptr = &options->hostbased_authentication;
1271511b41d2SMark Murray goto parse_flag;
1272511b41d2SMark Murray
1273cf2b5f3bSDag-Erling Smørgrav case oGssAuthentication:
1274cf2b5f3bSDag-Erling Smørgrav intptr = &options->gss_authentication;
1275511b41d2SMark Murray goto parse_flag;
1276cf2b5f3bSDag-Erling Smørgrav
1277cf2b5f3bSDag-Erling Smørgrav case oGssDelegateCreds:
1278cf2b5f3bSDag-Erling Smørgrav intptr = &options->gss_deleg_creds;
1279ca3176e7SBrian Feldman goto parse_flag;
1280cf2b5f3bSDag-Erling Smørgrav
1281511b41d2SMark Murray case oBatchMode:
1282511b41d2SMark Murray intptr = &options->batch_mode;
1283511b41d2SMark Murray goto parse_flag;
1284511b41d2SMark Murray
1285511b41d2SMark Murray case oCheckHostIP:
1286511b41d2SMark Murray intptr = &options->check_host_ip;
1287511b41d2SMark Murray goto parse_flag;
1288511b41d2SMark Murray
1289cf2b5f3bSDag-Erling Smørgrav case oVerifyHostKeyDNS:
1290cf2b5f3bSDag-Erling Smørgrav intptr = &options->verify_host_key_dns;
1291f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_yesnoask;
1292f7167e0eSDag-Erling Smørgrav goto parse_multistate;
1293cf2b5f3bSDag-Erling Smørgrav
1294511b41d2SMark Murray case oStrictHostKeyChecking:
1295511b41d2SMark Murray intptr = &options->strict_host_key_checking;
12964f52dfbbSDag-Erling Smørgrav multistate_ptr = multistate_strict_hostkey;
1297f7167e0eSDag-Erling Smørgrav goto parse_multistate;
1298511b41d2SMark Murray
1299511b41d2SMark Murray case oCompression:
1300511b41d2SMark Murray intptr = &options->compression;
130119261079SEd Maste multistate_ptr = multistate_compression;
130219261079SEd Maste goto parse_multistate;
1303511b41d2SMark Murray
13041ec0d754SDag-Erling Smørgrav case oTCPKeepAlive:
13051ec0d754SDag-Erling Smørgrav intptr = &options->tcp_keep_alive;
1306511b41d2SMark Murray goto parse_flag;
1307511b41d2SMark Murray
1308af12a3e7SDag-Erling Smørgrav case oNoHostAuthenticationForLocalhost:
1309af12a3e7SDag-Erling Smørgrav intptr = &options->no_host_authentication_for_localhost;
1310af12a3e7SDag-Erling Smørgrav goto parse_flag;
1311af12a3e7SDag-Erling Smørgrav
1312511b41d2SMark Murray case oNumberOfPasswordPrompts:
1313511b41d2SMark Murray intptr = &options->number_of_password_prompts;
1314511b41d2SMark Murray goto parse_int;
1315511b41d2SMark Murray
1316cf2b5f3bSDag-Erling Smørgrav case oRekeyLimit:
131719261079SEd Maste arg = argv_next(&ac, &av);
131819261079SEd Maste if (!arg || *arg == '\0') {
131919261079SEd Maste error("%.200s line %d: Missing argument.", filename,
1320e4a9863fSDag-Erling Smørgrav linenum);
132119261079SEd Maste goto out;
132219261079SEd Maste }
1323e4a9863fSDag-Erling Smørgrav if (strcmp(arg, "default") == 0) {
1324e4a9863fSDag-Erling Smørgrav val64 = 0;
1325e4a9863fSDag-Erling Smørgrav } else {
132619261079SEd Maste if (scan_scaled(arg, &val64) == -1) {
132719261079SEd Maste error("%.200s line %d: Bad number '%s': %s",
1328e4a9863fSDag-Erling Smørgrav filename, linenum, arg, strerror(errno));
132919261079SEd Maste goto out;
133019261079SEd Maste }
133119261079SEd Maste if (val64 != 0 && val64 < 16) {
133219261079SEd Maste error("%.200s line %d: RekeyLimit too small",
1333333ee039SDag-Erling Smørgrav filename, linenum);
133419261079SEd Maste goto out;
133519261079SEd Maste }
1336e4a9863fSDag-Erling Smørgrav }
1337d4af9e69SDag-Erling Smørgrav if (*activep && options->rekey_limit == -1)
1338acc1a9efSDag-Erling Smørgrav options->rekey_limit = val64;
133919261079SEd Maste if (ac != 0) { /* optional rekey interval present */
134019261079SEd Maste if (strcmp(av[0], "none") == 0) {
134119261079SEd Maste (void)argv_next(&ac, &av); /* discard */
1342e4a9863fSDag-Erling Smørgrav break;
1343e4a9863fSDag-Erling Smørgrav }
1344e4a9863fSDag-Erling Smørgrav intptr = &options->rekey_interval;
1345e4a9863fSDag-Erling Smørgrav goto parse_time;
1346e4a9863fSDag-Erling Smørgrav }
1347cf2b5f3bSDag-Erling Smørgrav break;
1348cf2b5f3bSDag-Erling Smørgrav
1349511b41d2SMark Murray case oIdentityFile:
135019261079SEd Maste arg = argv_next(&ac, &av);
135119261079SEd Maste if (!arg || *arg == '\0') {
135219261079SEd Maste error("%.200s line %d: Missing argument.",
135319261079SEd Maste filename, linenum);
135419261079SEd Maste goto out;
135519261079SEd Maste }
1356511b41d2SMark Murray if (*activep) {
1357ca3176e7SBrian Feldman intptr = &options->num_identity_files;
135819261079SEd Maste if (*intptr >= SSH_MAX_IDENTITY_FILES) {
135919261079SEd Maste error("%.200s line %d: Too many identity files "
136019261079SEd Maste "specified (max %d).", filename, linenum,
136119261079SEd Maste SSH_MAX_IDENTITY_FILES);
136219261079SEd Maste goto out;
136319261079SEd Maste }
1364bc5531deSDag-Erling Smørgrav add_identity_file(options, NULL,
1365bc5531deSDag-Erling Smørgrav arg, flags & SSHCONF_USERCONF);
1366511b41d2SMark Murray }
1367511b41d2SMark Murray break;
1368511b41d2SMark Murray
1369acc1a9efSDag-Erling Smørgrav case oCertificateFile:
137019261079SEd Maste arg = argv_next(&ac, &av);
137119261079SEd Maste if (!arg || *arg == '\0') {
137219261079SEd Maste error("%.200s line %d: Missing argument.",
1373acc1a9efSDag-Erling Smørgrav filename, linenum);
137419261079SEd Maste goto out;
137519261079SEd Maste }
1376acc1a9efSDag-Erling Smørgrav if (*activep) {
1377acc1a9efSDag-Erling Smørgrav intptr = &options->num_certificate_files;
1378acc1a9efSDag-Erling Smørgrav if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
137919261079SEd Maste error("%.200s line %d: Too many certificate "
1380acc1a9efSDag-Erling Smørgrav "files specified (max %d).",
1381acc1a9efSDag-Erling Smørgrav filename, linenum,
1382acc1a9efSDag-Erling Smørgrav SSH_MAX_CERTIFICATE_FILES);
138319261079SEd Maste goto out;
1384acc1a9efSDag-Erling Smørgrav }
1385acc1a9efSDag-Erling Smørgrav add_certificate_file(options, arg,
1386acc1a9efSDag-Erling Smørgrav flags & SSHCONF_USERCONF);
1387acc1a9efSDag-Erling Smørgrav }
1388acc1a9efSDag-Erling Smørgrav break;
1389acc1a9efSDag-Erling Smørgrav
1390c2d3a559SKris Kennaway case oXAuthLocation:
1391c2d3a559SKris Kennaway charptr=&options->xauth_location;
1392c2d3a559SKris Kennaway goto parse_string;
1393c2d3a559SKris Kennaway
1394511b41d2SMark Murray case oUser:
1395511b41d2SMark Murray charptr = &options->user;
1396511b41d2SMark Murray parse_string:
139719261079SEd Maste arg = argv_next(&ac, &av);
139819261079SEd Maste if (!arg || *arg == '\0') {
139919261079SEd Maste error("%.200s line %d: Missing argument.",
1400e146993eSDag-Erling Smørgrav filename, linenum);
140119261079SEd Maste goto out;
140219261079SEd Maste }
1403511b41d2SMark Murray if (*activep && *charptr == NULL)
1404c2d3a559SKris Kennaway *charptr = xstrdup(arg);
1405511b41d2SMark Murray break;
1406511b41d2SMark Murray
1407511b41d2SMark Murray case oGlobalKnownHostsFile:
1408e146993eSDag-Erling Smørgrav cpptr = (char **)&options->system_hostfiles;
1409e146993eSDag-Erling Smørgrav uintptr = &options->num_system_hostfiles;
1410e146993eSDag-Erling Smørgrav max_entries = SSH_MAX_HOSTS_FILES;
1411e146993eSDag-Erling Smørgrav parse_char_array:
141219261079SEd Maste i = 0;
141319261079SEd Maste value = *uintptr == 0; /* was array empty when we started? */
141419261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
141519261079SEd Maste if (*arg == '\0') {
141619261079SEd Maste error("%s line %d: keyword %s empty argument",
141719261079SEd Maste filename, linenum, keyword);
141819261079SEd Maste goto out;
141919261079SEd Maste }
142019261079SEd Maste /* Allow "none" only in first position */
142119261079SEd Maste if (strcasecmp(arg, "none") == 0) {
142219261079SEd Maste if (i > 0 || ac > 0) {
142319261079SEd Maste error("%s line %d: keyword %s \"none\" "
142419261079SEd Maste "argument must appear alone.",
142519261079SEd Maste filename, linenum, keyword);
142619261079SEd Maste goto out;
142719261079SEd Maste }
142819261079SEd Maste }
142919261079SEd Maste i++;
143019261079SEd Maste if (*activep && value) {
143119261079SEd Maste if ((*uintptr) >= max_entries) {
143219261079SEd Maste error("%s line %d: too many %s "
143319261079SEd Maste "entries.", filename, linenum,
143419261079SEd Maste keyword);
143519261079SEd Maste goto out;
143619261079SEd Maste }
1437e146993eSDag-Erling Smørgrav cpptr[(*uintptr)++] = xstrdup(arg);
1438e146993eSDag-Erling Smørgrav }
1439e146993eSDag-Erling Smørgrav }
144019261079SEd Maste break;
1441511b41d2SMark Murray
1442511b41d2SMark Murray case oUserKnownHostsFile:
1443e146993eSDag-Erling Smørgrav cpptr = (char **)&options->user_hostfiles;
1444e146993eSDag-Erling Smørgrav uintptr = &options->num_user_hostfiles;
1445e146993eSDag-Erling Smørgrav max_entries = SSH_MAX_HOSTS_FILES;
1446e146993eSDag-Erling Smørgrav goto parse_char_array;
1447e8aafc91SKris Kennaway
144819261079SEd Maste case oHostname:
1449511b41d2SMark Murray charptr = &options->hostname;
1450511b41d2SMark Murray goto parse_string;
1451511b41d2SMark Murray
1452535af610SEd Maste case oTag:
1453535af610SEd Maste charptr = &options->tag;
1454535af610SEd Maste goto parse_string;
1455535af610SEd Maste
1456ca3176e7SBrian Feldman case oHostKeyAlias:
1457ca3176e7SBrian Feldman charptr = &options->host_key_alias;
1458ca3176e7SBrian Feldman goto parse_string;
1459ca3176e7SBrian Feldman
1460ca3176e7SBrian Feldman case oPreferredAuthentications:
1461ca3176e7SBrian Feldman charptr = &options->preferred_authentications;
1462ca3176e7SBrian Feldman goto parse_string;
1463ca3176e7SBrian Feldman
1464af12a3e7SDag-Erling Smørgrav case oBindAddress:
1465af12a3e7SDag-Erling Smørgrav charptr = &options->bind_address;
1466af12a3e7SDag-Erling Smørgrav goto parse_string;
1467af12a3e7SDag-Erling Smørgrav
146847dd1d1bSDag-Erling Smørgrav case oBindInterface:
146947dd1d1bSDag-Erling Smørgrav charptr = &options->bind_interface;
147047dd1d1bSDag-Erling Smørgrav goto parse_string;
147147dd1d1bSDag-Erling Smørgrav
1472b15c8340SDag-Erling Smørgrav case oPKCS11Provider:
1473b15c8340SDag-Erling Smørgrav charptr = &options->pkcs11_provider;
1474af12a3e7SDag-Erling Smørgrav goto parse_string;
1475af12a3e7SDag-Erling Smørgrav
147619261079SEd Maste case oSecurityKeyProvider:
147719261079SEd Maste charptr = &options->sk_provider;
147819261079SEd Maste goto parse_string;
147919261079SEd Maste
148019261079SEd Maste case oKnownHostsCommand:
148119261079SEd Maste charptr = &options->known_hosts_command;
148219261079SEd Maste goto parse_command;
148319261079SEd Maste
1484511b41d2SMark Murray case oProxyCommand:
1485b74df5b2SDag-Erling Smørgrav charptr = &options->proxy_command;
1486076ad2f8SDag-Erling Smørgrav /* Ignore ProxyCommand if ProxyJump already specified */
1487076ad2f8SDag-Erling Smørgrav if (options->jump_host != NULL)
1488076ad2f8SDag-Erling Smørgrav charptr = &options->jump_host; /* Skip below */
1489b74df5b2SDag-Erling Smørgrav parse_command:
149019261079SEd Maste if (str == NULL) {
149119261079SEd Maste error("%.200s line %d: Missing argument.",
149219261079SEd Maste filename, linenum);
149319261079SEd Maste goto out;
149419261079SEd Maste }
149519261079SEd Maste len = strspn(str, WHITESPACE "=");
1496511b41d2SMark Murray if (*activep && *charptr == NULL)
149719261079SEd Maste *charptr = xstrdup(str + len);
149819261079SEd Maste argv_consume(&ac);
149919261079SEd Maste break;
1500511b41d2SMark Murray
1501076ad2f8SDag-Erling Smørgrav case oProxyJump:
150219261079SEd Maste if (str == NULL) {
150319261079SEd Maste error("%.200s line %d: Missing argument.",
1504076ad2f8SDag-Erling Smørgrav filename, linenum);
150519261079SEd Maste goto out;
1506076ad2f8SDag-Erling Smørgrav }
150719261079SEd Maste len = strspn(str, WHITESPACE "=");
150819261079SEd Maste /* XXX use argv? */
150919261079SEd Maste if (parse_jump(str + len, options, *activep) == -1) {
151019261079SEd Maste error("%.200s line %d: Invalid ProxyJump \"%s\"",
151119261079SEd Maste filename, linenum, str + len);
151219261079SEd Maste goto out;
1513076ad2f8SDag-Erling Smørgrav }
151419261079SEd Maste argv_consume(&ac);
151519261079SEd Maste break;
1516076ad2f8SDag-Erling Smørgrav
1517511b41d2SMark Murray case oPort:
151819261079SEd Maste arg = argv_next(&ac, &av);
151919261079SEd Maste if (!arg || *arg == '\0') {
152019261079SEd Maste error("%.200s line %d: Missing argument.",
15212f513db7SEd Maste filename, linenum);
152219261079SEd Maste goto out;
152319261079SEd Maste }
15242f513db7SEd Maste value = a2port(arg);
152519261079SEd Maste if (value <= 0) {
152619261079SEd Maste error("%.200s line %d: Bad port '%s'.",
15272f513db7SEd Maste filename, linenum, arg);
152819261079SEd Maste goto out;
152919261079SEd Maste }
15302f513db7SEd Maste if (*activep && options->port == -1)
15312f513db7SEd Maste options->port = value;
15322f513db7SEd Maste break;
15332f513db7SEd Maste
15342f513db7SEd Maste case oConnectionAttempts:
15352f513db7SEd Maste intptr = &options->connection_attempts;
1536511b41d2SMark Murray parse_int:
153719261079SEd Maste arg = argv_next(&ac, &av);
153819261079SEd Maste if ((errstr = atoi_err(arg, &value)) != NULL) {
153919261079SEd Maste error("%s line %d: integer value %s.",
154047dd1d1bSDag-Erling Smørgrav filename, linenum, errstr);
154119261079SEd Maste goto out;
154219261079SEd Maste }
1543511b41d2SMark Murray if (*activep && *intptr == -1)
1544511b41d2SMark Murray *intptr = value;
1545511b41d2SMark Murray break;
1546511b41d2SMark Murray
1547e8aafc91SKris Kennaway case oCiphers:
154819261079SEd Maste arg = argv_next(&ac, &av);
154919261079SEd Maste if (!arg || *arg == '\0') {
155019261079SEd Maste error("%.200s line %d: Missing argument.",
155119261079SEd Maste filename, linenum);
155219261079SEd Maste goto out;
155319261079SEd Maste }
155419261079SEd Maste if (*arg != '-' &&
155519261079SEd Maste !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)){
155619261079SEd Maste error("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1557c2d3a559SKris Kennaway filename, linenum, arg ? arg : "<NONE>");
155819261079SEd Maste goto out;
155919261079SEd Maste }
1560e8aafc91SKris Kennaway if (*activep && options->ciphers == NULL)
1561c2d3a559SKris Kennaway options->ciphers = xstrdup(arg);
1562e8aafc91SKris Kennaway break;
1563e8aafc91SKris Kennaway
1564ca3176e7SBrian Feldman case oMacs:
156519261079SEd Maste arg = argv_next(&ac, &av);
156619261079SEd Maste if (!arg || *arg == '\0') {
156719261079SEd Maste error("%.200s line %d: Missing argument.",
156819261079SEd Maste filename, linenum);
156919261079SEd Maste goto out;
157019261079SEd Maste }
157119261079SEd Maste if (*arg != '-' &&
157219261079SEd Maste !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)) {
157319261079SEd Maste error("%.200s line %d: Bad SSH2 MAC spec '%s'.",
1574ca3176e7SBrian Feldman filename, linenum, arg ? arg : "<NONE>");
157519261079SEd Maste goto out;
157619261079SEd Maste }
1577ca3176e7SBrian Feldman if (*activep && options->macs == NULL)
1578ca3176e7SBrian Feldman options->macs = xstrdup(arg);
1579ca3176e7SBrian Feldman break;
1580ca3176e7SBrian Feldman
15814a421b63SDag-Erling Smørgrav case oKexAlgorithms:
158219261079SEd Maste arg = argv_next(&ac, &av);
158319261079SEd Maste if (!arg || *arg == '\0') {
158419261079SEd Maste error("%.200s line %d: Missing argument.",
15854a421b63SDag-Erling Smørgrav filename, linenum);
158619261079SEd Maste goto out;
158719261079SEd Maste }
1588d93a896eSDag-Erling Smørgrav if (*arg != '-' &&
158919261079SEd Maste !kex_names_valid(*arg == '+' || *arg == '^' ?
159019261079SEd Maste arg + 1 : arg)) {
159119261079SEd Maste error("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
15924a421b63SDag-Erling Smørgrav filename, linenum, arg ? arg : "<NONE>");
159319261079SEd Maste goto out;
159419261079SEd Maste }
15954a421b63SDag-Erling Smørgrav if (*activep && options->kex_algorithms == NULL)
15964a421b63SDag-Erling Smørgrav options->kex_algorithms = xstrdup(arg);
15974a421b63SDag-Erling Smørgrav break;
15984a421b63SDag-Erling Smørgrav
1599ca3176e7SBrian Feldman case oHostKeyAlgorithms:
1600eccfee6eSDag-Erling Smørgrav charptr = &options->hostkeyalgorithms;
1601535af610SEd Maste ca_only = 0;
160219261079SEd Maste parse_pubkey_algos:
160319261079SEd Maste arg = argv_next(&ac, &av);
160419261079SEd Maste if (!arg || *arg == '\0') {
160519261079SEd Maste error("%.200s line %d: Missing argument.",
1606eccfee6eSDag-Erling Smørgrav filename, linenum);
160719261079SEd Maste goto out;
160819261079SEd Maste }
1609d93a896eSDag-Erling Smørgrav if (*arg != '-' &&
161019261079SEd Maste !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
1611535af610SEd Maste arg + 1 : arg, 1, ca_only)) {
161219261079SEd Maste error("%s line %d: Bad key types '%s'.",
1613ca3176e7SBrian Feldman filename, linenum, arg ? arg : "<NONE>");
161419261079SEd Maste goto out;
161519261079SEd Maste }
1616eccfee6eSDag-Erling Smørgrav if (*activep && *charptr == NULL)
1617eccfee6eSDag-Erling Smørgrav *charptr = xstrdup(arg);
1618ca3176e7SBrian Feldman break;
1619ca3176e7SBrian Feldman
16202f513db7SEd Maste case oCASignatureAlgorithms:
16212f513db7SEd Maste charptr = &options->ca_sign_algorithms;
1622535af610SEd Maste ca_only = 1;
162319261079SEd Maste goto parse_pubkey_algos;
16242f513db7SEd Maste
1625511b41d2SMark Murray case oLogLevel:
1626d4af9e69SDag-Erling Smørgrav log_level_ptr = &options->log_level;
162719261079SEd Maste arg = argv_next(&ac, &av);
1628c2d3a559SKris Kennaway value = log_level_number(arg);
162919261079SEd Maste if (value == SYSLOG_LEVEL_NOT_SET) {
163019261079SEd Maste error("%.200s line %d: unsupported log level '%s'",
1631c2d3a559SKris Kennaway filename, linenum, arg ? arg : "<NONE>");
163219261079SEd Maste goto out;
163319261079SEd Maste }
1634d4af9e69SDag-Erling Smørgrav if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1635d4af9e69SDag-Erling Smørgrav *log_level_ptr = (LogLevel) value;
1636511b41d2SMark Murray break;
1637511b41d2SMark Murray
16384f52dfbbSDag-Erling Smørgrav case oLogFacility:
16394f52dfbbSDag-Erling Smørgrav log_facility_ptr = &options->log_facility;
164019261079SEd Maste arg = argv_next(&ac, &av);
16414f52dfbbSDag-Erling Smørgrav value = log_facility_number(arg);
164219261079SEd Maste if (value == SYSLOG_FACILITY_NOT_SET) {
164319261079SEd Maste error("%.200s line %d: unsupported log facility '%s'",
16444f52dfbbSDag-Erling Smørgrav filename, linenum, arg ? arg : "<NONE>");
164519261079SEd Maste goto out;
164619261079SEd Maste }
16474f52dfbbSDag-Erling Smørgrav if (*log_facility_ptr == -1)
16484f52dfbbSDag-Erling Smørgrav *log_facility_ptr = (SyslogFacility) value;
16494f52dfbbSDag-Erling Smørgrav break;
16504f52dfbbSDag-Erling Smørgrav
165119261079SEd Maste case oLogVerbose:
165219261079SEd Maste cppptr = &options->log_verbose;
165319261079SEd Maste uintptr = &options->num_log_verbose;
165419261079SEd Maste i = 0;
165519261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
165619261079SEd Maste if (*arg == '\0') {
165719261079SEd Maste error("%s line %d: keyword %s empty argument",
165819261079SEd Maste filename, linenum, keyword);
165919261079SEd Maste goto out;
166019261079SEd Maste }
166119261079SEd Maste /* Allow "none" only in first position */
166219261079SEd Maste if (strcasecmp(arg, "none") == 0) {
166319261079SEd Maste if (i > 0 || ac > 0) {
166419261079SEd Maste error("%s line %d: keyword %s \"none\" "
166519261079SEd Maste "argument must appear alone.",
166619261079SEd Maste filename, linenum, keyword);
166719261079SEd Maste goto out;
166819261079SEd Maste }
166919261079SEd Maste }
167019261079SEd Maste i++;
167119261079SEd Maste if (*activep && *uintptr == 0) {
167219261079SEd Maste *cppptr = xrecallocarray(*cppptr, *uintptr,
167319261079SEd Maste *uintptr + 1, sizeof(**cppptr));
167419261079SEd Maste (*cppptr)[(*uintptr)++] = xstrdup(arg);
167519261079SEd Maste }
167619261079SEd Maste }
167719261079SEd Maste break;
167819261079SEd Maste
1679af12a3e7SDag-Erling Smørgrav case oLocalForward:
1680511b41d2SMark Murray case oRemoteForward:
1681cce7d346SDag-Erling Smørgrav case oDynamicForward:
168219261079SEd Maste arg = argv_next(&ac, &av);
168319261079SEd Maste if (!arg || *arg == '\0') {
168419261079SEd Maste error("%.200s line %d: Missing argument.",
1685af12a3e7SDag-Erling Smørgrav filename, linenum);
168619261079SEd Maste goto out;
168719261079SEd Maste }
1688cce7d346SDag-Erling Smørgrav
16894f52dfbbSDag-Erling Smørgrav remotefwd = (opcode == oRemoteForward);
16904f52dfbbSDag-Erling Smørgrav dynamicfwd = (opcode == oDynamicForward);
16914f52dfbbSDag-Erling Smørgrav
16924f52dfbbSDag-Erling Smørgrav if (!dynamicfwd) {
169319261079SEd Maste arg2 = argv_next(&ac, &av);
16944f52dfbbSDag-Erling Smørgrav if (arg2 == NULL || *arg2 == '\0') {
16954f52dfbbSDag-Erling Smørgrav if (remotefwd)
16964f52dfbbSDag-Erling Smørgrav dynamicfwd = 1;
169719261079SEd Maste else {
169819261079SEd Maste error("%.200s line %d: Missing target "
16994f52dfbbSDag-Erling Smørgrav "argument.", filename, linenum);
170019261079SEd Maste goto out;
170119261079SEd Maste }
17024f52dfbbSDag-Erling Smørgrav } else {
1703aa49c926SDag-Erling Smørgrav /* construct a string for parse_forward */
17044f52dfbbSDag-Erling Smørgrav snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg,
17054f52dfbbSDag-Erling Smørgrav arg2);
1706cce7d346SDag-Erling Smørgrav }
17074f52dfbbSDag-Erling Smørgrav }
17084f52dfbbSDag-Erling Smørgrav if (dynamicfwd)
17094f52dfbbSDag-Erling Smørgrav strlcpy(fwdarg, arg, sizeof(fwdarg));
1710aa49c926SDag-Erling Smørgrav
171119261079SEd Maste if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0) {
171219261079SEd Maste error("%.200s line %d: Bad forwarding specification.",
1713511b41d2SMark Murray filename, linenum);
171419261079SEd Maste goto out;
171519261079SEd Maste }
1716aa49c926SDag-Erling Smørgrav
1717af12a3e7SDag-Erling Smørgrav if (*activep) {
17184f52dfbbSDag-Erling Smørgrav if (remotefwd) {
1719aa49c926SDag-Erling Smørgrav add_remote_forward(options, &fwd);
17204f52dfbbSDag-Erling Smørgrav } else {
17214f52dfbbSDag-Erling Smørgrav add_local_forward(options, &fwd);
17224f52dfbbSDag-Erling Smørgrav }
1723af12a3e7SDag-Erling Smørgrav }
1724511b41d2SMark Murray break;
1725511b41d2SMark Murray
172619261079SEd Maste case oPermitRemoteOpen:
172719261079SEd Maste uintptr = &options->num_permitted_remote_opens;
172819261079SEd Maste cppptr = &options->permitted_remote_opens;
1729a91a2465SEd Maste found = *uintptr == 0;
173019261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
173119261079SEd Maste arg2 = xstrdup(arg);
173294e21addSEd Maste /* Allow any/none only in first position */
173394e21addSEd Maste if (strcasecmp(arg, "none") == 0 ||
173494e21addSEd Maste strcasecmp(arg, "any") == 0) {
1735a91a2465SEd Maste if (nstrs > 0 || ac > 0) {
173694e21addSEd Maste error("%s line %d: keyword %s \"%s\" "
173794e21addSEd Maste "argument must appear alone.",
173894e21addSEd Maste filename, linenum, keyword, arg);
1739535af610SEd Maste free(arg2);
174094e21addSEd Maste goto out;
174194e21addSEd Maste }
174294e21addSEd Maste } else {
17431323ec57SEd Maste p = hpdelim(&arg);
17441323ec57SEd Maste if (p == NULL) {
174519261079SEd Maste fatal("%s line %d: missing host in %s",
174619261079SEd Maste filename, linenum,
174719261079SEd Maste lookup_opcode_name(opcode));
174819261079SEd Maste }
174919261079SEd Maste p = cleanhostname(p);
175019261079SEd Maste /*
175119261079SEd Maste * don't want to use permitopen_port to avoid
175219261079SEd Maste * dependency on channels.[ch] here.
175319261079SEd Maste */
175494e21addSEd Maste if (arg == NULL || (strcmp(arg, "*") != 0 &&
175594e21addSEd Maste a2port(arg) <= 0)) {
175694e21addSEd Maste fatal("%s line %d: bad port number "
175794e21addSEd Maste "in %s", filename, linenum,
175819261079SEd Maste lookup_opcode_name(opcode));
175919261079SEd Maste }
176094e21addSEd Maste }
176119261079SEd Maste opt_array_append(filename, linenum,
176219261079SEd Maste lookup_opcode_name(opcode),
1763a91a2465SEd Maste &strs, &nstrs, arg2);
176419261079SEd Maste free(arg2);
176519261079SEd Maste }
1766a91a2465SEd Maste if (nstrs == 0)
176794e21addSEd Maste fatal("%s line %d: missing %s specification",
176894e21addSEd Maste filename, linenum, lookup_opcode_name(opcode));
1769a91a2465SEd Maste if (found && *activep) {
1770a91a2465SEd Maste *cppptr = strs;
1771a91a2465SEd Maste *uintptr = nstrs;
1772a91a2465SEd Maste strs = NULL; /* transferred */
1773a91a2465SEd Maste nstrs = 0;
1774a91a2465SEd Maste }
177519261079SEd Maste break;
177619261079SEd Maste
1777af12a3e7SDag-Erling Smørgrav case oClearAllForwardings:
1778af12a3e7SDag-Erling Smørgrav intptr = &options->clear_forwardings;
1779af12a3e7SDag-Erling Smørgrav goto parse_flag;
1780af12a3e7SDag-Erling Smørgrav
1781511b41d2SMark Murray case oHost:
178219261079SEd Maste if (cmdline) {
178319261079SEd Maste error("Host directive not supported as a command-line "
1784f7167e0eSDag-Erling Smørgrav "option");
178519261079SEd Maste goto out;
178619261079SEd Maste }
1787511b41d2SMark Murray *activep = 0;
1788e146993eSDag-Erling Smørgrav arg2 = NULL;
178919261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
179019261079SEd Maste if (*arg == '\0') {
179119261079SEd Maste error("%s line %d: keyword %s empty argument",
179219261079SEd Maste filename, linenum, keyword);
179319261079SEd Maste goto out;
179419261079SEd Maste }
179519261079SEd Maste if ((flags & SSHCONF_NEVERMATCH) != 0) {
179619261079SEd Maste argv_consume(&ac);
1797076ad2f8SDag-Erling Smørgrav break;
179819261079SEd Maste }
1799e146993eSDag-Erling Smørgrav negated = *arg == '!';
1800e146993eSDag-Erling Smørgrav if (negated)
1801e146993eSDag-Erling Smørgrav arg++;
1802c2d3a559SKris Kennaway if (match_pattern(host, arg)) {
1803e146993eSDag-Erling Smørgrav if (negated) {
1804e146993eSDag-Erling Smørgrav debug("%.200s line %d: Skipping Host "
1805e146993eSDag-Erling Smørgrav "block because of negated match "
1806e146993eSDag-Erling Smørgrav "for %.100s", filename, linenum,
1807e146993eSDag-Erling Smørgrav arg);
1808e146993eSDag-Erling Smørgrav *activep = 0;
180919261079SEd Maste argv_consume(&ac);
1810511b41d2SMark Murray break;
1811511b41d2SMark Murray }
1812e146993eSDag-Erling Smørgrav if (!*activep)
1813e146993eSDag-Erling Smørgrav arg2 = arg; /* logged below */
1814e146993eSDag-Erling Smørgrav *activep = 1;
1815e146993eSDag-Erling Smørgrav }
1816e146993eSDag-Erling Smørgrav }
1817e146993eSDag-Erling Smørgrav if (*activep)
1818e146993eSDag-Erling Smørgrav debug("%.200s line %d: Applying options for %.100s",
1819e146993eSDag-Erling Smørgrav filename, linenum, arg2);
182019261079SEd Maste break;
1821511b41d2SMark Murray
1822f7167e0eSDag-Erling Smørgrav case oMatch:
182319261079SEd Maste if (cmdline) {
182419261079SEd Maste error("Host directive not supported as a command-line "
1825f7167e0eSDag-Erling Smørgrav "option");
182619261079SEd Maste goto out;
182719261079SEd Maste }
18283d9fd9fcSEd Maste value = match_cfg_line(options, str, &ac, &av, pw, host,
18293d9fd9fcSEd Maste original_host, flags & SSHCONF_FINAL, want_final_pass,
183019261079SEd Maste filename, linenum);
183119261079SEd Maste if (value < 0) {
183219261079SEd Maste error("%.200s line %d: Bad Match condition", filename,
1833f7167e0eSDag-Erling Smørgrav linenum);
183419261079SEd Maste goto out;
183519261079SEd Maste }
1836076ad2f8SDag-Erling Smørgrav *activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
1837f7167e0eSDag-Erling Smørgrav break;
1838f7167e0eSDag-Erling Smørgrav
1839511b41d2SMark Murray case oEscapeChar:
1840511b41d2SMark Murray intptr = &options->escape_char;
184119261079SEd Maste arg = argv_next(&ac, &av);
184219261079SEd Maste if (!arg || *arg == '\0') {
184319261079SEd Maste error("%.200s line %d: Missing argument.",
184419261079SEd Maste filename, linenum);
184519261079SEd Maste goto out;
184619261079SEd Maste }
1847557f75e5SDag-Erling Smørgrav if (strcmp(arg, "none") == 0)
1848557f75e5SDag-Erling Smørgrav value = SSH_ESCAPECHAR_NONE;
1849557f75e5SDag-Erling Smørgrav else if (arg[1] == '\0')
1850557f75e5SDag-Erling Smørgrav value = (u_char) arg[0];
1851557f75e5SDag-Erling Smørgrav else if (arg[0] == '^' && arg[2] == 0 &&
1852ca3176e7SBrian Feldman (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1853ca3176e7SBrian Feldman value = (u_char) arg[1] & 31;
1854511b41d2SMark Murray else {
185519261079SEd Maste error("%.200s line %d: Bad escape character.",
1856511b41d2SMark Murray filename, linenum);
185719261079SEd Maste goto out;
1858511b41d2SMark Murray }
1859511b41d2SMark Murray if (*activep && *intptr == -1)
1860511b41d2SMark Murray *intptr = value;
1861511b41d2SMark Murray break;
1862511b41d2SMark Murray
1863cf2b5f3bSDag-Erling Smørgrav case oAddressFamily:
1864cf2b5f3bSDag-Erling Smørgrav intptr = &options->address_family;
1865f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_addressfamily;
1866f7167e0eSDag-Erling Smørgrav goto parse_multistate;
1867cf2b5f3bSDag-Erling Smørgrav
1868e73e9afaSDag-Erling Smørgrav case oEnableSSHKeysign:
1869e73e9afaSDag-Erling Smørgrav intptr = &options->enable_ssh_keysign;
1870e73e9afaSDag-Erling Smørgrav goto parse_flag;
1871e73e9afaSDag-Erling Smørgrav
18725962c0e9SDag-Erling Smørgrav case oIdentitiesOnly:
18735962c0e9SDag-Erling Smørgrav intptr = &options->identities_only;
18745962c0e9SDag-Erling Smørgrav goto parse_flag;
18755962c0e9SDag-Erling Smørgrav
18761ec0d754SDag-Erling Smørgrav case oServerAliveInterval:
18771ec0d754SDag-Erling Smørgrav intptr = &options->server_alive_interval;
18781ec0d754SDag-Erling Smørgrav goto parse_time;
18791ec0d754SDag-Erling Smørgrav
18801ec0d754SDag-Erling Smørgrav case oServerAliveCountMax:
18811ec0d754SDag-Erling Smørgrav intptr = &options->server_alive_count_max;
18821ec0d754SDag-Erling Smørgrav goto parse_int;
18831ec0d754SDag-Erling Smørgrav
188421e764dfSDag-Erling Smørgrav case oSendEnv:
1885a91a2465SEd Maste /* XXX appends to list; doesn't respect first-match-wins */
188619261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
188719261079SEd Maste if (*arg == '\0' || strchr(arg, '=') != NULL) {
188819261079SEd Maste error("%s line %d: Invalid environment name.",
188921e764dfSDag-Erling Smørgrav filename, linenum);
189019261079SEd Maste goto out;
189119261079SEd Maste }
1892a91a2465SEd Maste found = 1;
1893aa49c926SDag-Erling Smørgrav if (!*activep)
1894aa49c926SDag-Erling Smørgrav continue;
1895190cef3dSDag-Erling Smørgrav if (*arg == '-') {
1896190cef3dSDag-Erling Smørgrav /* Removing an env var */
1897190cef3dSDag-Erling Smørgrav rm_env(options, arg, filename, linenum);
1898190cef3dSDag-Erling Smørgrav continue;
189919261079SEd Maste }
190038a52bd3SEd Maste opt_array_append(filename, linenum,
190138a52bd3SEd Maste lookup_opcode_name(opcode),
190238a52bd3SEd Maste &options->send_env, &options->num_send_env, arg);
1903190cef3dSDag-Erling Smørgrav }
1904a91a2465SEd Maste if (!found) {
1905a91a2465SEd Maste fatal("%s line %d: no %s specified",
1906a91a2465SEd Maste filename, linenum, keyword);
1907a91a2465SEd Maste }
1908190cef3dSDag-Erling Smørgrav break;
1909190cef3dSDag-Erling Smørgrav
1910190cef3dSDag-Erling Smørgrav case oSetEnv:
1911a91a2465SEd Maste found = options->num_setenv == 0;
191219261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
191319261079SEd Maste if (strchr(arg, '=') == NULL) {
191419261079SEd Maste error("%s line %d: Invalid SetEnv.",
1915190cef3dSDag-Erling Smørgrav filename, linenum);
191619261079SEd Maste goto out;
191719261079SEd Maste }
1918a91a2465SEd Maste if (lookup_setenv_in_list(arg, strs, nstrs) != NULL) {
191938a52bd3SEd Maste debug2("%s line %d: ignoring duplicate env "
192038a52bd3SEd Maste "name \"%.64s\"", filename, linenum, arg);
192138a52bd3SEd Maste continue;
192219261079SEd Maste }
192338a52bd3SEd Maste opt_array_append(filename, linenum,
192438a52bd3SEd Maste lookup_opcode_name(opcode),
1925a91a2465SEd Maste &strs, &nstrs, arg);
1926a91a2465SEd Maste }
1927a91a2465SEd Maste if (nstrs == 0) {
1928a91a2465SEd Maste fatal("%s line %d: no %s specified",
1929a91a2465SEd Maste filename, linenum, keyword);
1930a91a2465SEd Maste }
1931a91a2465SEd Maste if (found && *activep) {
1932a91a2465SEd Maste options->setenv = strs;
1933a91a2465SEd Maste options->num_setenv = nstrs;
1934a91a2465SEd Maste strs = NULL; /* transferred */
1935a91a2465SEd Maste nstrs = 0;
1936190cef3dSDag-Erling Smørgrav }
193721e764dfSDag-Erling Smørgrav break;
193821e764dfSDag-Erling Smørgrav
193921e764dfSDag-Erling Smørgrav case oControlPath:
194021e764dfSDag-Erling Smørgrav charptr = &options->control_path;
194121e764dfSDag-Erling Smørgrav goto parse_string;
194221e764dfSDag-Erling Smørgrav
194321e764dfSDag-Erling Smørgrav case oControlMaster:
194421e764dfSDag-Erling Smørgrav intptr = &options->control_master;
1945f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_controlmaster;
1946f7167e0eSDag-Erling Smørgrav goto parse_multistate;
194721e764dfSDag-Erling Smørgrav
1948e2f6069cSDag-Erling Smørgrav case oControlPersist:
1949e2f6069cSDag-Erling Smørgrav /* no/false/yes/true, or a time spec */
1950e2f6069cSDag-Erling Smørgrav intptr = &options->control_persist;
195119261079SEd Maste arg = argv_next(&ac, &av);
195219261079SEd Maste if (!arg || *arg == '\0') {
195319261079SEd Maste error("%.200s line %d: Missing ControlPersist"
1954e2f6069cSDag-Erling Smørgrav " argument.", filename, linenum);
195519261079SEd Maste goto out;
195619261079SEd Maste }
1957e2f6069cSDag-Erling Smørgrav value = 0;
1958e2f6069cSDag-Erling Smørgrav value2 = 0; /* timeout */
1959e2f6069cSDag-Erling Smørgrav if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1960e2f6069cSDag-Erling Smørgrav value = 0;
1961e2f6069cSDag-Erling Smørgrav else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1962e2f6069cSDag-Erling Smørgrav value = 1;
1963e2f6069cSDag-Erling Smørgrav else if ((value2 = convtime(arg)) >= 0)
1964e2f6069cSDag-Erling Smørgrav value = 1;
196519261079SEd Maste else {
196619261079SEd Maste error("%.200s line %d: Bad ControlPersist argument.",
1967e2f6069cSDag-Erling Smørgrav filename, linenum);
196819261079SEd Maste goto out;
196919261079SEd Maste }
1970e2f6069cSDag-Erling Smørgrav if (*activep && *intptr == -1) {
1971e2f6069cSDag-Erling Smørgrav *intptr = value;
1972e2f6069cSDag-Erling Smørgrav options->control_persist_timeout = value2;
1973e2f6069cSDag-Erling Smørgrav }
1974e2f6069cSDag-Erling Smørgrav break;
1975e2f6069cSDag-Erling Smørgrav
1976aa49c926SDag-Erling Smørgrav case oHashKnownHosts:
1977aa49c926SDag-Erling Smørgrav intptr = &options->hash_known_hosts;
1978aa49c926SDag-Erling Smørgrav goto parse_flag;
1979aa49c926SDag-Erling Smørgrav
1980b74df5b2SDag-Erling Smørgrav case oTunnel:
1981b74df5b2SDag-Erling Smørgrav intptr = &options->tun_open;
1982f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_tunnel;
1983f7167e0eSDag-Erling Smørgrav goto parse_multistate;
1984b74df5b2SDag-Erling Smørgrav
1985b74df5b2SDag-Erling Smørgrav case oTunnelDevice:
198619261079SEd Maste arg = argv_next(&ac, &av);
198719261079SEd Maste if (!arg || *arg == '\0') {
198819261079SEd Maste error("%.200s line %d: Missing argument.",
198919261079SEd Maste filename, linenum);
199019261079SEd Maste goto out;
199119261079SEd Maste }
1992b74df5b2SDag-Erling Smørgrav value = a2tun(arg, &value2);
199319261079SEd Maste if (value == SSH_TUNID_ERR) {
199419261079SEd Maste error("%.200s line %d: Bad tun device.",
199519261079SEd Maste filename, linenum);
199619261079SEd Maste goto out;
199719261079SEd Maste }
199819261079SEd Maste if (*activep && options->tun_local == -1) {
1999b74df5b2SDag-Erling Smørgrav options->tun_local = value;
2000b74df5b2SDag-Erling Smørgrav options->tun_remote = value2;
2001b74df5b2SDag-Erling Smørgrav }
2002b74df5b2SDag-Erling Smørgrav break;
2003b74df5b2SDag-Erling Smørgrav
2004b74df5b2SDag-Erling Smørgrav case oLocalCommand:
2005b74df5b2SDag-Erling Smørgrav charptr = &options->local_command;
2006b74df5b2SDag-Erling Smørgrav goto parse_command;
2007b74df5b2SDag-Erling Smørgrav
2008b74df5b2SDag-Erling Smørgrav case oPermitLocalCommand:
2009b74df5b2SDag-Erling Smørgrav intptr = &options->permit_local_command;
2010b74df5b2SDag-Erling Smørgrav goto parse_flag;
2011b74df5b2SDag-Erling Smørgrav
20124f52dfbbSDag-Erling Smørgrav case oRemoteCommand:
20134f52dfbbSDag-Erling Smørgrav charptr = &options->remote_command;
20144f52dfbbSDag-Erling Smørgrav goto parse_command;
20154f52dfbbSDag-Erling Smørgrav
2016d4af9e69SDag-Erling Smørgrav case oVisualHostKey:
2017d4af9e69SDag-Erling Smørgrav intptr = &options->visual_host_key;
2018d4af9e69SDag-Erling Smørgrav goto parse_flag;
2019d4af9e69SDag-Erling Smørgrav
2020076ad2f8SDag-Erling Smørgrav case oInclude:
202119261079SEd Maste if (cmdline) {
202219261079SEd Maste error("Include directive not supported as a "
2023076ad2f8SDag-Erling Smørgrav "command-line option");
202419261079SEd Maste goto out;
202519261079SEd Maste }
2026076ad2f8SDag-Erling Smørgrav value = 0;
202719261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
202819261079SEd Maste if (*arg == '\0') {
202919261079SEd Maste error("%s line %d: keyword %s empty argument",
203019261079SEd Maste filename, linenum, keyword);
203119261079SEd Maste goto out;
203219261079SEd Maste }
20333d9fd9fcSEd Maste /* Expand %tokens and environment variables */
20343d9fd9fcSEd Maste if ((p = expand_match_exec_or_include_path(arg,
20353d9fd9fcSEd Maste options, pw, host, original_host,
20363d9fd9fcSEd Maste flags & SSHCONF_FINAL, 1)) == NULL) {
20373d9fd9fcSEd Maste error("%.200s line %d: Unable to expand user "
20383d9fd9fcSEd Maste "config file '%.100s'",
20393d9fd9fcSEd Maste filename, linenum, arg);
20403d9fd9fcSEd Maste continue;
20413d9fd9fcSEd Maste }
2042076ad2f8SDag-Erling Smørgrav /*
2043076ad2f8SDag-Erling Smørgrav * Ensure all paths are anchored. User configuration
2044076ad2f8SDag-Erling Smørgrav * files may begin with '~/' but system configurations
2045076ad2f8SDag-Erling Smørgrav * must not. If the path is relative, then treat it
2046076ad2f8SDag-Erling Smørgrav * as living in ~/.ssh for user configurations or
2047076ad2f8SDag-Erling Smørgrav * /etc/ssh for system ones.
2048076ad2f8SDag-Erling Smørgrav */
20493d9fd9fcSEd Maste if (*p == '~' && (flags & SSHCONF_USERCONF) == 0) {
205019261079SEd Maste error("%.200s line %d: bad include path %s.",
20513d9fd9fcSEd Maste filename, linenum, p);
205219261079SEd Maste goto out;
205319261079SEd Maste }
20543d9fd9fcSEd Maste if (!path_absolute(p) && *p != '~') {
2055076ad2f8SDag-Erling Smørgrav xasprintf(&arg2, "%s/%s",
2056076ad2f8SDag-Erling Smørgrav (flags & SSHCONF_USERCONF) ?
20573d9fd9fcSEd Maste "~/" _PATH_SSH_USER_DIR : SSHDIR, p);
20583d9fd9fcSEd Maste } else {
20593d9fd9fcSEd Maste arg2 = xstrdup(p);
20603d9fd9fcSEd Maste }
20613d9fd9fcSEd Maste free(p);
2062076ad2f8SDag-Erling Smørgrav memset(&gl, 0, sizeof(gl));
2063076ad2f8SDag-Erling Smørgrav r = glob(arg2, GLOB_TILDE, NULL, &gl);
2064076ad2f8SDag-Erling Smørgrav if (r == GLOB_NOMATCH) {
2065076ad2f8SDag-Erling Smørgrav debug("%.200s line %d: include %s matched no "
2066076ad2f8SDag-Erling Smørgrav "files",filename, linenum, arg2);
2067d93a896eSDag-Erling Smørgrav free(arg2);
2068076ad2f8SDag-Erling Smørgrav continue;
206919261079SEd Maste } else if (r != 0) {
207019261079SEd Maste error("%.200s line %d: glob failed for %s.",
2071076ad2f8SDag-Erling Smørgrav filename, linenum, arg2);
207219261079SEd Maste goto out;
207319261079SEd Maste }
2074076ad2f8SDag-Erling Smørgrav free(arg2);
2075076ad2f8SDag-Erling Smørgrav oactive = *activep;
207619261079SEd Maste for (i = 0; i < gl.gl_pathc; i++) {
2077076ad2f8SDag-Erling Smørgrav debug3("%.200s line %d: Including file %s "
2078076ad2f8SDag-Erling Smørgrav "depth %d%s", filename, linenum,
2079076ad2f8SDag-Erling Smørgrav gl.gl_pathv[i], depth,
2080076ad2f8SDag-Erling Smørgrav oactive ? "" : " (parse only)");
2081076ad2f8SDag-Erling Smørgrav r = read_config_file_depth(gl.gl_pathv[i],
2082076ad2f8SDag-Erling Smørgrav pw, host, original_host, options,
2083076ad2f8SDag-Erling Smørgrav flags | SSHCONF_CHECKPERM |
2084076ad2f8SDag-Erling Smørgrav (oactive ? 0 : SSHCONF_NEVERMATCH),
208519261079SEd Maste activep, want_final_pass, depth + 1);
2086d93a896eSDag-Erling Smørgrav if (r != 1 && errno != ENOENT) {
20873d9fd9fcSEd Maste error("%.200s line %d: Can't open user "
20883d9fd9fcSEd Maste "config file %.100s: %.100s",
20893d9fd9fcSEd Maste filename, linenum, gl.gl_pathv[i],
2090d93a896eSDag-Erling Smørgrav strerror(errno));
209119261079SEd Maste globfree(&gl);
209219261079SEd Maste goto out;
2093d93a896eSDag-Erling Smørgrav }
2094076ad2f8SDag-Erling Smørgrav /*
2095076ad2f8SDag-Erling Smørgrav * don't let Match in includes clobber the
2096076ad2f8SDag-Erling Smørgrav * containing file's Match state.
2097076ad2f8SDag-Erling Smørgrav */
2098076ad2f8SDag-Erling Smørgrav *activep = oactive;
2099076ad2f8SDag-Erling Smørgrav if (r != 1)
2100076ad2f8SDag-Erling Smørgrav value = -1;
2101076ad2f8SDag-Erling Smørgrav }
2102076ad2f8SDag-Erling Smørgrav globfree(&gl);
2103076ad2f8SDag-Erling Smørgrav }
2104076ad2f8SDag-Erling Smørgrav if (value != 0)
210519261079SEd Maste ret = value;
2106076ad2f8SDag-Erling Smørgrav break;
2107076ad2f8SDag-Erling Smørgrav
21084a421b63SDag-Erling Smørgrav case oIPQoS:
210919261079SEd Maste arg = argv_next(&ac, &av);
211019261079SEd Maste if ((value = parse_ipqos(arg)) == -1) {
211119261079SEd Maste error("%s line %d: Bad IPQoS value: %s",
21124a421b63SDag-Erling Smørgrav filename, linenum, arg);
211319261079SEd Maste goto out;
211419261079SEd Maste }
211519261079SEd Maste arg = argv_next(&ac, &av);
21164a421b63SDag-Erling Smørgrav if (arg == NULL)
21174a421b63SDag-Erling Smørgrav value2 = value;
211819261079SEd Maste else if ((value2 = parse_ipqos(arg)) == -1) {
211919261079SEd Maste error("%s line %d: Bad IPQoS value: %s",
21204a421b63SDag-Erling Smørgrav filename, linenum, arg);
212119261079SEd Maste goto out;
212219261079SEd Maste }
212319261079SEd Maste if (*activep && options->ip_qos_interactive == -1) {
21244a421b63SDag-Erling Smørgrav options->ip_qos_interactive = value;
21254a421b63SDag-Erling Smørgrav options->ip_qos_bulk = value2;
21264a421b63SDag-Erling Smørgrav }
21274a421b63SDag-Erling Smørgrav break;
21284a421b63SDag-Erling Smørgrav
2129e146993eSDag-Erling Smørgrav case oRequestTTY:
2130e146993eSDag-Erling Smørgrav intptr = &options->request_tty;
2131f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_requesttty;
2132f7167e0eSDag-Erling Smørgrav goto parse_multistate;
2133975616f0SDag-Erling Smørgrav
213419261079SEd Maste case oSessionType:
213519261079SEd Maste intptr = &options->session_type;
213619261079SEd Maste multistate_ptr = multistate_sessiontype;
213719261079SEd Maste goto parse_multistate;
213819261079SEd Maste
213919261079SEd Maste case oStdinNull:
214019261079SEd Maste intptr = &options->stdin_null;
214119261079SEd Maste goto parse_flag;
214219261079SEd Maste
214319261079SEd Maste case oForkAfterAuthentication:
214419261079SEd Maste intptr = &options->fork_after_authentication;
214519261079SEd Maste goto parse_flag;
214619261079SEd Maste
2147e4a9863fSDag-Erling Smørgrav case oIgnoreUnknown:
2148e4a9863fSDag-Erling Smørgrav charptr = &options->ignored_unknown;
2149e4a9863fSDag-Erling Smørgrav goto parse_string;
2150e4a9863fSDag-Erling Smørgrav
2151f7167e0eSDag-Erling Smørgrav case oProxyUseFdpass:
2152f7167e0eSDag-Erling Smørgrav intptr = &options->proxy_use_fdpass;
2153f7167e0eSDag-Erling Smørgrav goto parse_flag;
2154f7167e0eSDag-Erling Smørgrav
2155f7167e0eSDag-Erling Smørgrav case oCanonicalDomains:
2156a91a2465SEd Maste found = options->num_canonical_domains == 0;
215719261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
215819261079SEd Maste /* Allow "none" only in first position */
215919261079SEd Maste if (strcasecmp(arg, "none") == 0) {
2160a91a2465SEd Maste if (nstrs > 0 || ac > 0) {
216119261079SEd Maste error("%s line %d: keyword %s \"none\" "
216219261079SEd Maste "argument must appear alone.",
216319261079SEd Maste filename, linenum, keyword);
216419261079SEd Maste goto out;
216519261079SEd Maste }
216619261079SEd Maste }
216747dd1d1bSDag-Erling Smørgrav if (!valid_domain(arg, 1, &errstr)) {
216819261079SEd Maste error("%s line %d: %s", filename, linenum,
216947dd1d1bSDag-Erling Smørgrav errstr);
217019261079SEd Maste goto out;
217147dd1d1bSDag-Erling Smørgrav }
2172a91a2465SEd Maste opt_array_append(filename, linenum, keyword,
2173a91a2465SEd Maste &strs, &nstrs, arg);
217419261079SEd Maste }
2175a91a2465SEd Maste if (nstrs == 0) {
2176a91a2465SEd Maste fatal("%s line %d: no %s specified",
2177a91a2465SEd Maste filename, linenum, keyword);
2178a91a2465SEd Maste }
2179a91a2465SEd Maste if (found && *activep) {
2180a91a2465SEd Maste options->canonical_domains = strs;
2181a91a2465SEd Maste options->num_canonical_domains = nstrs;
2182a91a2465SEd Maste strs = NULL; /* transferred */
2183a91a2465SEd Maste nstrs = 0;
2184f7167e0eSDag-Erling Smørgrav }
2185f7167e0eSDag-Erling Smørgrav break;
2186f7167e0eSDag-Erling Smørgrav
2187f7167e0eSDag-Erling Smørgrav case oCanonicalizePermittedCNAMEs:
2188a91a2465SEd Maste found = options->num_permitted_cnames == 0;
218919261079SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
2190e9e8876aSEd Maste /*
2191e9e8876aSEd Maste * Either 'none' (only in first position), '*' for
2192e9e8876aSEd Maste * everything or 'list:list'
2193e9e8876aSEd Maste */
2194e9e8876aSEd Maste if (strcasecmp(arg, "none") == 0) {
2195a91a2465SEd Maste if (ncnames > 0 || ac > 0) {
2196e9e8876aSEd Maste error("%s line %d: keyword %s \"none\" "
2197e9e8876aSEd Maste "argument must appear alone.",
2198e9e8876aSEd Maste filename, linenum, keyword);
2199e9e8876aSEd Maste goto out;
2200e9e8876aSEd Maste }
2201e9e8876aSEd Maste arg2 = "";
2202e9e8876aSEd Maste } else if (strcmp(arg, "*") == 0) {
2203f7167e0eSDag-Erling Smørgrav arg2 = arg;
2204e9e8876aSEd Maste } else {
2205f7167e0eSDag-Erling Smørgrav lowercase(arg);
2206f7167e0eSDag-Erling Smørgrav if ((arg2 = strchr(arg, ':')) == NULL ||
2207f7167e0eSDag-Erling Smørgrav arg2[1] == '\0') {
220819261079SEd Maste error("%s line %d: "
2209f7167e0eSDag-Erling Smørgrav "Invalid permitted CNAME \"%s\"",
2210f7167e0eSDag-Erling Smørgrav filename, linenum, arg);
221119261079SEd Maste goto out;
2212f7167e0eSDag-Erling Smørgrav }
2213f7167e0eSDag-Erling Smørgrav *arg2 = '\0';
2214f7167e0eSDag-Erling Smørgrav arg2++;
2215f7167e0eSDag-Erling Smørgrav }
2216a91a2465SEd Maste cnames = xrecallocarray(cnames, ncnames, ncnames + 1,
2217a91a2465SEd Maste sizeof(*cnames));
2218a91a2465SEd Maste cnames[ncnames].source_list = xstrdup(arg);
2219a91a2465SEd Maste cnames[ncnames].target_list = xstrdup(arg2);
2220a91a2465SEd Maste ncnames++;
222119261079SEd Maste }
2222a91a2465SEd Maste if (ncnames == 0) {
2223a91a2465SEd Maste fatal("%s line %d: no %s specified",
2224a91a2465SEd Maste filename, linenum, keyword);
2225f7167e0eSDag-Erling Smørgrav }
2226a91a2465SEd Maste if (found && *activep) {
2227a91a2465SEd Maste options->permitted_cnames = cnames;
2228a91a2465SEd Maste options->num_permitted_cnames = ncnames;
2229a91a2465SEd Maste cnames = NULL; /* transferred */
2230a91a2465SEd Maste ncnames = 0;
2231a91a2465SEd Maste }
2232a91a2465SEd Maste /* un-transferred cnames is cleaned up before exit */
2233f7167e0eSDag-Erling Smørgrav break;
2234f7167e0eSDag-Erling Smørgrav
2235f7167e0eSDag-Erling Smørgrav case oCanonicalizeHostname:
2236f7167e0eSDag-Erling Smørgrav intptr = &options->canonicalize_hostname;
2237f7167e0eSDag-Erling Smørgrav multistate_ptr = multistate_canonicalizehostname;
2238f7167e0eSDag-Erling Smørgrav goto parse_multistate;
2239f7167e0eSDag-Erling Smørgrav
2240f7167e0eSDag-Erling Smørgrav case oCanonicalizeMaxDots:
2241f7167e0eSDag-Erling Smørgrav intptr = &options->canonicalize_max_dots;
2242f7167e0eSDag-Erling Smørgrav goto parse_int;
2243f7167e0eSDag-Erling Smørgrav
2244f7167e0eSDag-Erling Smørgrav case oCanonicalizeFallbackLocal:
2245f7167e0eSDag-Erling Smørgrav intptr = &options->canonicalize_fallback_local;
2246f7167e0eSDag-Erling Smørgrav goto parse_flag;
2247f7167e0eSDag-Erling Smørgrav
2248a0ee8cc6SDag-Erling Smørgrav case oStreamLocalBindMask:
224919261079SEd Maste arg = argv_next(&ac, &av);
225019261079SEd Maste if (!arg || *arg == '\0') {
225119261079SEd Maste error("%.200s line %d: Missing StreamLocalBindMask "
225219261079SEd Maste "argument.", filename, linenum);
225319261079SEd Maste goto out;
225419261079SEd Maste }
2255a0ee8cc6SDag-Erling Smørgrav /* Parse mode in octal format */
2256a0ee8cc6SDag-Erling Smørgrav value = strtol(arg, &endofnumber, 8);
225719261079SEd Maste if (arg == endofnumber || value < 0 || value > 0777) {
225819261079SEd Maste error("%.200s line %d: Bad mask.", filename, linenum);
225919261079SEd Maste goto out;
226019261079SEd Maste }
2261a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
2262a0ee8cc6SDag-Erling Smørgrav break;
2263a0ee8cc6SDag-Erling Smørgrav
2264a0ee8cc6SDag-Erling Smørgrav case oStreamLocalBindUnlink:
2265a0ee8cc6SDag-Erling Smørgrav intptr = &options->fwd_opts.streamlocal_bind_unlink;
2266a0ee8cc6SDag-Erling Smørgrav goto parse_flag;
2267a0ee8cc6SDag-Erling Smørgrav
2268bc5531deSDag-Erling Smørgrav case oRevokedHostKeys:
2269bc5531deSDag-Erling Smørgrav charptr = &options->revoked_host_keys;
2270bc5531deSDag-Erling Smørgrav goto parse_string;
2271bc5531deSDag-Erling Smørgrav
2272bc5531deSDag-Erling Smørgrav case oFingerprintHash:
2273bc5531deSDag-Erling Smørgrav intptr = &options->fingerprint_hash;
227419261079SEd Maste arg = argv_next(&ac, &av);
227519261079SEd Maste if (!arg || *arg == '\0') {
227619261079SEd Maste error("%.200s line %d: Missing argument.",
2277bc5531deSDag-Erling Smørgrav filename, linenum);
227819261079SEd Maste goto out;
227919261079SEd Maste }
228019261079SEd Maste if ((value = ssh_digest_alg_by_name(arg)) == -1) {
228119261079SEd Maste error("%.200s line %d: Invalid hash algorithm \"%s\".",
2282bc5531deSDag-Erling Smørgrav filename, linenum, arg);
228319261079SEd Maste goto out;
228419261079SEd Maste }
2285bc5531deSDag-Erling Smørgrav if (*activep && *intptr == -1)
2286bc5531deSDag-Erling Smørgrav *intptr = value;
2287bc5531deSDag-Erling Smørgrav break;
2288bc5531deSDag-Erling Smørgrav
2289bc5531deSDag-Erling Smørgrav case oUpdateHostkeys:
2290bc5531deSDag-Erling Smørgrav intptr = &options->update_hostkeys;
2291bc5531deSDag-Erling Smørgrav multistate_ptr = multistate_yesnoask;
2292bc5531deSDag-Erling Smørgrav goto parse_multistate;
2293bc5531deSDag-Erling Smørgrav
229419261079SEd Maste case oHostbasedAcceptedAlgorithms:
229519261079SEd Maste charptr = &options->hostbased_accepted_algos;
2296535af610SEd Maste ca_only = 0;
229719261079SEd Maste goto parse_pubkey_algos;
2298eccfee6eSDag-Erling Smørgrav
229919261079SEd Maste case oPubkeyAcceptedAlgorithms:
230019261079SEd Maste charptr = &options->pubkey_accepted_algos;
2301535af610SEd Maste ca_only = 0;
230219261079SEd Maste goto parse_pubkey_algos;
2303bc5531deSDag-Erling Smørgrav
2304acc1a9efSDag-Erling Smørgrav case oAddKeysToAgent:
230519261079SEd Maste arg = argv_next(&ac, &av);
230619261079SEd Maste arg2 = argv_next(&ac, &av);
230719261079SEd Maste value = parse_multistate_value(arg, filename, linenum,
230819261079SEd Maste multistate_yesnoaskconfirm);
230919261079SEd Maste value2 = 0; /* unlimited lifespan by default */
231019261079SEd Maste if (value == 3 && arg2 != NULL) {
231119261079SEd Maste /* allow "AddKeysToAgent confirm 5m" */
23124d3fc8b0SEd Maste if ((value2 = convtime(arg2)) == -1) {
231319261079SEd Maste error("%s line %d: invalid time value.",
231419261079SEd Maste filename, linenum);
231519261079SEd Maste goto out;
231619261079SEd Maste }
231719261079SEd Maste } else if (value == -1 && arg2 == NULL) {
23184d3fc8b0SEd Maste if ((value2 = convtime(arg)) == -1) {
231919261079SEd Maste error("%s line %d: unsupported option",
232019261079SEd Maste filename, linenum);
232119261079SEd Maste goto out;
232219261079SEd Maste }
232319261079SEd Maste value = 1; /* yes */
232419261079SEd Maste } else if (value == -1 || arg2 != NULL) {
232519261079SEd Maste error("%s line %d: unsupported option",
232619261079SEd Maste filename, linenum);
232719261079SEd Maste goto out;
232819261079SEd Maste }
232919261079SEd Maste if (*activep && options->add_keys_to_agent == -1) {
233019261079SEd Maste options->add_keys_to_agent = value;
233119261079SEd Maste options->add_keys_to_agent_lifespan = value2;
233219261079SEd Maste }
233319261079SEd Maste break;
2334acc1a9efSDag-Erling Smørgrav
2335076ad2f8SDag-Erling Smørgrav case oIdentityAgent:
2336076ad2f8SDag-Erling Smørgrav charptr = &options->identity_agent;
233719261079SEd Maste arg = argv_next(&ac, &av);
233819261079SEd Maste if (!arg || *arg == '\0') {
233919261079SEd Maste error("%.200s line %d: Missing argument.",
23402f513db7SEd Maste filename, linenum);
234119261079SEd Maste goto out;
234219261079SEd Maste }
234319261079SEd Maste parse_agent_path:
23442f513db7SEd Maste /* Extra validation if the string represents an env var. */
234519261079SEd Maste if ((arg2 = dollar_expand(&r, arg)) == NULL || r) {
234619261079SEd Maste error("%.200s line %d: Invalid environment expansion "
234719261079SEd Maste "%s.", filename, linenum, arg);
234819261079SEd Maste goto out;
234919261079SEd Maste }
235019261079SEd Maste free(arg2);
235119261079SEd Maste /* check for legacy environment format */
235219261079SEd Maste if (arg[0] == '$' && arg[1] != '{' &&
235319261079SEd Maste !valid_env_name(arg + 1)) {
235419261079SEd Maste error("%.200s line %d: Invalid environment name %s.",
23552f513db7SEd Maste filename, linenum, arg);
235619261079SEd Maste goto out;
23572f513db7SEd Maste }
23582f513db7SEd Maste if (*activep && *charptr == NULL)
23592f513db7SEd Maste *charptr = xstrdup(arg);
23602f513db7SEd Maste break;
2361076ad2f8SDag-Erling Smørgrav
2362f374ba41SEd Maste case oEnableEscapeCommandline:
2363f374ba41SEd Maste intptr = &options->enable_escape_commandline;
2364f374ba41SEd Maste goto parse_flag;
2365f374ba41SEd Maste
236638a52bd3SEd Maste case oRequiredRSASize:
236738a52bd3SEd Maste intptr = &options->required_rsa_size;
236838a52bd3SEd Maste goto parse_int;
236938a52bd3SEd Maste
2370edf85781SEd Maste case oObscureKeystrokeTiming:
2371edf85781SEd Maste value = -1;
2372edf85781SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
2373edf85781SEd Maste if (value != -1) {
2374edf85781SEd Maste error("%s line %d: invalid arguments",
2375edf85781SEd Maste filename, linenum);
2376edf85781SEd Maste goto out;
2377edf85781SEd Maste }
2378edf85781SEd Maste if (strcmp(arg, "yes") == 0 ||
2379edf85781SEd Maste strcmp(arg, "true") == 0)
2380edf85781SEd Maste value = SSH_KEYSTROKE_DEFAULT_INTERVAL_MS;
2381edf85781SEd Maste else if (strcmp(arg, "no") == 0 ||
2382edf85781SEd Maste strcmp(arg, "false") == 0)
2383edf85781SEd Maste value = 0;
2384edf85781SEd Maste else if (strncmp(arg, "interval:", 9) == 0) {
2385edf85781SEd Maste if ((errstr = atoi_err(arg + 9,
2386edf85781SEd Maste &value)) != NULL) {
2387edf85781SEd Maste error("%s line %d: integer value %s.",
2388edf85781SEd Maste filename, linenum, errstr);
2389edf85781SEd Maste goto out;
2390edf85781SEd Maste }
2391edf85781SEd Maste if (value <= 0 || value > 1000) {
2392edf85781SEd Maste error("%s line %d: value out of range.",
2393edf85781SEd Maste filename, linenum);
2394edf85781SEd Maste goto out;
2395edf85781SEd Maste }
2396edf85781SEd Maste } else {
2397edf85781SEd Maste error("%s line %d: unsupported argument \"%s\"",
2398edf85781SEd Maste filename, linenum, arg);
2399edf85781SEd Maste goto out;
2400edf85781SEd Maste }
2401edf85781SEd Maste }
2402edf85781SEd Maste if (value == -1) {
2403edf85781SEd Maste error("%s line %d: missing argument",
2404edf85781SEd Maste filename, linenum);
2405edf85781SEd Maste goto out;
2406edf85781SEd Maste }
2407edf85781SEd Maste intptr = &options->obscure_keystroke_timing_interval;
2408edf85781SEd Maste if (*activep && *intptr == -1)
2409edf85781SEd Maste *intptr = value;
2410edf85781SEd Maste break;
2411edf85781SEd Maste
2412069ac184SEd Maste case oChannelTimeout:
2413a91a2465SEd Maste found = options->num_channel_timeouts == 0;
2414069ac184SEd Maste while ((arg = argv_next(&ac, &av)) != NULL) {
2415069ac184SEd Maste /* Allow "none" only in first position */
2416069ac184SEd Maste if (strcasecmp(arg, "none") == 0) {
2417a91a2465SEd Maste if (nstrs > 0 || ac > 0) {
2418069ac184SEd Maste error("%s line %d: keyword %s \"none\" "
2419069ac184SEd Maste "argument must appear alone.",
2420069ac184SEd Maste filename, linenum, keyword);
2421069ac184SEd Maste goto out;
2422069ac184SEd Maste }
2423069ac184SEd Maste } else if (parse_pattern_interval(arg,
2424069ac184SEd Maste NULL, NULL) != 0) {
2425069ac184SEd Maste fatal("%s line %d: invalid channel timeout %s",
2426069ac184SEd Maste filename, linenum, arg);
2427069ac184SEd Maste }
2428069ac184SEd Maste opt_array_append(filename, linenum, keyword,
2429a91a2465SEd Maste &strs, &nstrs, arg);
2430a91a2465SEd Maste }
2431a91a2465SEd Maste if (nstrs == 0) {
2432a91a2465SEd Maste fatal("%s line %d: no %s specified",
2433a91a2465SEd Maste filename, linenum, keyword);
2434a91a2465SEd Maste }
2435a91a2465SEd Maste if (found && *activep) {
2436a91a2465SEd Maste options->channel_timeouts = strs;
2437a91a2465SEd Maste options->num_channel_timeouts = nstrs;
2438a91a2465SEd Maste strs = NULL; /* transferred */
2439a91a2465SEd Maste nstrs = 0;
2440069ac184SEd Maste }
2441069ac184SEd Maste break;
2442069ac184SEd Maste
244380628bacSDag-Erling Smørgrav case oDeprecated:
244480628bacSDag-Erling Smørgrav debug("%s line %d: Deprecated option \"%s\"",
244580628bacSDag-Erling Smørgrav filename, linenum, keyword);
244619261079SEd Maste argv_consume(&ac);
244719261079SEd Maste break;
244880628bacSDag-Erling Smørgrav
2449cf2b5f3bSDag-Erling Smørgrav case oUnsupported:
2450cf2b5f3bSDag-Erling Smørgrav error("%s line %d: Unsupported option \"%s\"",
2451cf2b5f3bSDag-Erling Smørgrav filename, linenum, keyword);
245219261079SEd Maste argv_consume(&ac);
245319261079SEd Maste break;
2454cf2b5f3bSDag-Erling Smørgrav
2455511b41d2SMark Murray default:
245619261079SEd Maste error("%s line %d: Unimplemented opcode %d",
245719261079SEd Maste filename, linenum, opcode);
245819261079SEd Maste goto out;
2459511b41d2SMark Murray }
2460511b41d2SMark Murray
2461511b41d2SMark Murray /* Check that there is no garbage at end of line. */
246219261079SEd Maste if (ac > 0) {
246319261079SEd Maste error("%.200s line %d: keyword %s extra arguments "
246419261079SEd Maste "at end of line", filename, linenum, keyword);
246519261079SEd Maste goto out;
2466c2d3a559SKris Kennaway }
246719261079SEd Maste
246819261079SEd Maste /* success */
246919261079SEd Maste ret = 0;
247019261079SEd Maste out:
2471a91a2465SEd Maste free_canon_cnames(cnames, ncnames);
2472a91a2465SEd Maste opt_array_free2(strs, NULL, nstrs);
247319261079SEd Maste argv_free(oav, oac);
247419261079SEd Maste return ret;
2475511b41d2SMark Murray }
2476511b41d2SMark Murray
2477511b41d2SMark Murray /*
2478511b41d2SMark Murray * Reads the config file and modifies the options accordingly. Options
2479511b41d2SMark Murray * should already be initialized before this call. This never returns if
2480af12a3e7SDag-Erling Smørgrav * there is an error. If the file does not exist, this returns 0.
2481511b41d2SMark Murray */
2482af12a3e7SDag-Erling Smørgrav 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)2483f7167e0eSDag-Erling Smørgrav read_config_file(const char *filename, struct passwd *pw, const char *host,
248419261079SEd Maste const char *original_host, Options *options, int flags,
248519261079SEd Maste int *want_final_pass)
2486511b41d2SMark Murray {
2487076ad2f8SDag-Erling Smørgrav int active = 1;
2488076ad2f8SDag-Erling Smørgrav
2489076ad2f8SDag-Erling Smørgrav return read_config_file_depth(filename, pw, host, original_host,
249019261079SEd Maste options, flags, &active, want_final_pass, 0);
2491076ad2f8SDag-Erling Smørgrav }
2492076ad2f8SDag-Erling Smørgrav
2493076ad2f8SDag-Erling Smørgrav #define READCONF_MAX_DEPTH 16
2494076ad2f8SDag-Erling Smørgrav 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)2495076ad2f8SDag-Erling Smørgrav read_config_file_depth(const char *filename, struct passwd *pw,
2496076ad2f8SDag-Erling Smørgrav const char *host, const char *original_host, Options *options,
249719261079SEd Maste int flags, int *activep, int *want_final_pass, int depth)
2498076ad2f8SDag-Erling Smørgrav {
2499511b41d2SMark Murray FILE *f;
2500190cef3dSDag-Erling Smørgrav char *line = NULL;
2501190cef3dSDag-Erling Smørgrav size_t linesize = 0;
2502076ad2f8SDag-Erling Smørgrav int linenum;
2503511b41d2SMark Murray int bad_options = 0;
2504511b41d2SMark Murray
2505076ad2f8SDag-Erling Smørgrav if (depth < 0 || depth > READCONF_MAX_DEPTH)
2506076ad2f8SDag-Erling Smørgrav fatal("Too many recursive configuration includes");
2507076ad2f8SDag-Erling Smørgrav
250821e764dfSDag-Erling Smørgrav if ((f = fopen(filename, "r")) == NULL)
2509af12a3e7SDag-Erling Smørgrav return 0;
2510511b41d2SMark Murray
251173370613SDag-Erling Smørgrav if (flags & SSHCONF_CHECKPERM) {
251221e764dfSDag-Erling Smørgrav struct stat sb;
251321e764dfSDag-Erling Smørgrav
251421e764dfSDag-Erling Smørgrav if (fstat(fileno(f), &sb) == -1)
251521e764dfSDag-Erling Smørgrav fatal("fstat %s: %s", filename, strerror(errno));
251621e764dfSDag-Erling Smørgrav if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
251721e764dfSDag-Erling Smørgrav (sb.st_mode & 022) != 0))
251821e764dfSDag-Erling Smørgrav fatal("Bad owner or permissions on %s", filename);
251921e764dfSDag-Erling Smørgrav }
252021e764dfSDag-Erling Smørgrav
2521511b41d2SMark Murray debug("Reading configuration data %.200s", filename);
2522511b41d2SMark Murray
2523511b41d2SMark Murray /*
2524511b41d2SMark Murray * Mark that we are now processing the options. This flag is turned
2525511b41d2SMark Murray * on/off by Host specifications.
2526511b41d2SMark Murray */
2527511b41d2SMark Murray linenum = 0;
2528190cef3dSDag-Erling Smørgrav while (getline(&line, &linesize, f) != -1) {
2529511b41d2SMark Murray /* Update line number counter. */
2530511b41d2SMark Murray linenum++;
253119261079SEd Maste /*
253219261079SEd Maste * Trim out comments and strip whitespace.
253319261079SEd Maste * NB - preserve newlines, they are needed to reproduce
253419261079SEd Maste * line numbers later for error messages.
253519261079SEd Maste */
2536076ad2f8SDag-Erling Smørgrav if (process_config_line_depth(options, pw, host, original_host,
253719261079SEd Maste line, filename, linenum, activep, flags, want_final_pass,
253819261079SEd Maste depth) != 0)
2539511b41d2SMark Murray bad_options++;
2540511b41d2SMark Murray }
2541190cef3dSDag-Erling Smørgrav free(line);
2542511b41d2SMark Murray fclose(f);
2543511b41d2SMark Murray if (bad_options > 0)
2544ca3176e7SBrian Feldman fatal("%s: terminating, %d bad configuration options",
2545511b41d2SMark Murray filename, bad_options);
2546af12a3e7SDag-Erling Smørgrav return 1;
2547511b41d2SMark Murray }
2548511b41d2SMark Murray
2549b83788ffSDag-Erling Smørgrav /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
2550b83788ffSDag-Erling Smørgrav int
option_clear_or_none(const char * o)2551b83788ffSDag-Erling Smørgrav option_clear_or_none(const char *o)
2552b83788ffSDag-Erling Smørgrav {
2553b83788ffSDag-Erling Smørgrav return o == NULL || strcasecmp(o, "none") == 0;
2554b83788ffSDag-Erling Smørgrav }
2555b83788ffSDag-Erling Smørgrav
2556511b41d2SMark Murray /*
2557e9e8876aSEd Maste * Returns 1 if CanonicalizePermittedCNAMEs have been specified, 0 otherwise.
2558e9e8876aSEd Maste * Allowed to be called on non-final configuration.
2559e9e8876aSEd Maste */
2560e9e8876aSEd Maste int
config_has_permitted_cnames(Options * options)2561e9e8876aSEd Maste config_has_permitted_cnames(Options *options)
2562e9e8876aSEd Maste {
2563e9e8876aSEd Maste if (options->num_permitted_cnames == 1 &&
2564e9e8876aSEd Maste strcasecmp(options->permitted_cnames[0].source_list, "none") == 0 &&
2565e9e8876aSEd Maste strcmp(options->permitted_cnames[0].target_list, "") == 0)
2566e9e8876aSEd Maste return 0;
2567e9e8876aSEd Maste return options->num_permitted_cnames > 0;
2568e9e8876aSEd Maste }
2569e9e8876aSEd Maste
2570e9e8876aSEd Maste /*
2571511b41d2SMark Murray * Initializes options to special values that indicate that they have not yet
2572511b41d2SMark Murray * been set. Read_config_file will only set options with this value. Options
2573511b41d2SMark Murray * are processed in the following order: command line, user config file,
2574511b41d2SMark Murray * system config file. Last, fill_default_options is called.
2575511b41d2SMark Murray */
2576511b41d2SMark Murray
2577511b41d2SMark Murray void
initialize_options(Options * options)2578511b41d2SMark Murray initialize_options(Options * options)
2579511b41d2SMark Murray {
2580511b41d2SMark Murray memset(options, 'X', sizeof(*options));
2581f374ba41SEd Maste options->host_arg = NULL;
2582511b41d2SMark Murray options->forward_agent = -1;
258319261079SEd Maste options->forward_agent_sock_path = NULL;
2584511b41d2SMark Murray options->forward_x11 = -1;
25851ec0d754SDag-Erling Smørgrav options->forward_x11_trusted = -1;
2586e2f6069cSDag-Erling Smørgrav options->forward_x11_timeout = -1;
2587076ad2f8SDag-Erling Smørgrav options->stdio_forward_host = NULL;
2588076ad2f8SDag-Erling Smørgrav options->stdio_forward_port = 0;
2589076ad2f8SDag-Erling Smørgrav options->clear_forwardings = -1;
2590333ee039SDag-Erling Smørgrav options->exit_on_forward_failure = -1;
2591c2d3a559SKris Kennaway options->xauth_location = NULL;
2592a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.gateway_ports = -1;
2593a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
2594a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_unlink = -1;
2595ca3176e7SBrian Feldman options->pubkey_authentication = -1;
2596cf2b5f3bSDag-Erling Smørgrav options->gss_authentication = -1;
2597cf2b5f3bSDag-Erling Smørgrav options->gss_deleg_creds = -1;
2598511b41d2SMark Murray options->password_authentication = -1;
259909958426SBrian Feldman options->kbd_interactive_authentication = -1;
260009958426SBrian Feldman options->kbd_interactive_devices = NULL;
2601ca3176e7SBrian Feldman options->hostbased_authentication = -1;
2602511b41d2SMark Murray options->batch_mode = -1;
2603511b41d2SMark Murray options->check_host_ip = -1;
2604511b41d2SMark Murray options->strict_host_key_checking = -1;
2605511b41d2SMark Murray options->compression = -1;
26061ec0d754SDag-Erling Smørgrav options->tcp_keep_alive = -1;
2607511b41d2SMark Murray options->port = -1;
2608cf2b5f3bSDag-Erling Smørgrav options->address_family = -1;
2609511b41d2SMark Murray options->connection_attempts = -1;
2610cf2b5f3bSDag-Erling Smørgrav options->connection_timeout = -1;
2611511b41d2SMark Murray options->number_of_password_prompts = -1;
2612e8aafc91SKris Kennaway options->ciphers = NULL;
2613ca3176e7SBrian Feldman options->macs = NULL;
26144a421b63SDag-Erling Smørgrav options->kex_algorithms = NULL;
2615ca3176e7SBrian Feldman options->hostkeyalgorithms = NULL;
26162f513db7SEd Maste options->ca_sign_algorithms = NULL;
2617511b41d2SMark Murray options->num_identity_files = 0;
261819261079SEd Maste memset(options->identity_keys, 0, sizeof(options->identity_keys));
2619acc1a9efSDag-Erling Smørgrav options->num_certificate_files = 0;
262019261079SEd Maste memset(options->certificates, 0, sizeof(options->certificates));
2621511b41d2SMark Murray options->hostname = NULL;
2622ca3176e7SBrian Feldman options->host_key_alias = NULL;
2623511b41d2SMark Murray options->proxy_command = NULL;
2624076ad2f8SDag-Erling Smørgrav options->jump_user = NULL;
2625076ad2f8SDag-Erling Smørgrav options->jump_host = NULL;
2626076ad2f8SDag-Erling Smørgrav options->jump_port = -1;
2627076ad2f8SDag-Erling Smørgrav options->jump_extra = NULL;
2628511b41d2SMark Murray options->user = NULL;
2629511b41d2SMark Murray options->escape_char = -1;
2630e146993eSDag-Erling Smørgrav options->num_system_hostfiles = 0;
2631e146993eSDag-Erling Smørgrav options->num_user_hostfiles = 0;
2632e2f6069cSDag-Erling Smørgrav options->local_forwards = NULL;
2633511b41d2SMark Murray options->num_local_forwards = 0;
2634e2f6069cSDag-Erling Smørgrav options->remote_forwards = NULL;
2635511b41d2SMark Murray options->num_remote_forwards = 0;
263619261079SEd Maste options->permitted_remote_opens = NULL;
263719261079SEd Maste options->num_permitted_remote_opens = 0;
26384f52dfbbSDag-Erling Smørgrav options->log_facility = SYSLOG_FACILITY_NOT_SET;
2639af12a3e7SDag-Erling Smørgrav options->log_level = SYSLOG_LEVEL_NOT_SET;
264019261079SEd Maste options->num_log_verbose = 0;
264119261079SEd Maste options->log_verbose = NULL;
2642ca3176e7SBrian Feldman options->preferred_authentications = NULL;
2643af12a3e7SDag-Erling Smørgrav options->bind_address = NULL;
264447dd1d1bSDag-Erling Smørgrav options->bind_interface = NULL;
2645b15c8340SDag-Erling Smørgrav options->pkcs11_provider = NULL;
264619261079SEd Maste options->sk_provider = NULL;
2647e73e9afaSDag-Erling Smørgrav options->enable_ssh_keysign = - 1;
2648af12a3e7SDag-Erling Smørgrav options->no_host_authentication_for_localhost = - 1;
26495962c0e9SDag-Erling Smørgrav options->identities_only = - 1;
2650cf2b5f3bSDag-Erling Smørgrav options->rekey_limit = - 1;
2651e4a9863fSDag-Erling Smørgrav options->rekey_interval = -1;
2652cf2b5f3bSDag-Erling Smørgrav options->verify_host_key_dns = -1;
26531ec0d754SDag-Erling Smørgrav options->server_alive_interval = -1;
26541ec0d754SDag-Erling Smørgrav options->server_alive_count_max = -1;
2655190cef3dSDag-Erling Smørgrav options->send_env = NULL;
265621e764dfSDag-Erling Smørgrav options->num_send_env = 0;
2657190cef3dSDag-Erling Smørgrav options->setenv = NULL;
2658190cef3dSDag-Erling Smørgrav options->num_setenv = 0;
265921e764dfSDag-Erling Smørgrav options->control_path = NULL;
266021e764dfSDag-Erling Smørgrav options->control_master = -1;
2661e2f6069cSDag-Erling Smørgrav options->control_persist = -1;
2662e2f6069cSDag-Erling Smørgrav options->control_persist_timeout = 0;
2663aa49c926SDag-Erling Smørgrav options->hash_known_hosts = -1;
2664b74df5b2SDag-Erling Smørgrav options->tun_open = -1;
2665b74df5b2SDag-Erling Smørgrav options->tun_local = -1;
2666b74df5b2SDag-Erling Smørgrav options->tun_remote = -1;
2667b74df5b2SDag-Erling Smørgrav options->local_command = NULL;
2668b74df5b2SDag-Erling Smørgrav options->permit_local_command = -1;
26694f52dfbbSDag-Erling Smørgrav options->remote_command = NULL;
2670acc1a9efSDag-Erling Smørgrav options->add_keys_to_agent = -1;
267119261079SEd Maste options->add_keys_to_agent_lifespan = -1;
2672076ad2f8SDag-Erling Smørgrav options->identity_agent = NULL;
2673d4af9e69SDag-Erling Smørgrav options->visual_host_key = -1;
26744a421b63SDag-Erling Smørgrav options->ip_qos_interactive = -1;
26754a421b63SDag-Erling Smørgrav options->ip_qos_bulk = -1;
2676e146993eSDag-Erling Smørgrav options->request_tty = -1;
267719261079SEd Maste options->session_type = -1;
267819261079SEd Maste options->stdin_null = -1;
267919261079SEd Maste options->fork_after_authentication = -1;
2680f7167e0eSDag-Erling Smørgrav options->proxy_use_fdpass = -1;
2681e4a9863fSDag-Erling Smørgrav options->ignored_unknown = NULL;
2682f7167e0eSDag-Erling Smørgrav options->num_canonical_domains = 0;
2683f7167e0eSDag-Erling Smørgrav options->num_permitted_cnames = 0;
2684f7167e0eSDag-Erling Smørgrav options->canonicalize_max_dots = -1;
2685f7167e0eSDag-Erling Smørgrav options->canonicalize_fallback_local = -1;
2686f7167e0eSDag-Erling Smørgrav options->canonicalize_hostname = -1;
2687bc5531deSDag-Erling Smørgrav options->revoked_host_keys = NULL;
2688bc5531deSDag-Erling Smørgrav options->fingerprint_hash = -1;
2689bc5531deSDag-Erling Smørgrav options->update_hostkeys = -1;
269019261079SEd Maste options->hostbased_accepted_algos = NULL;
269119261079SEd Maste options->pubkey_accepted_algos = NULL;
269219261079SEd Maste options->known_hosts_command = NULL;
269338a52bd3SEd Maste options->required_rsa_size = -1;
2694f374ba41SEd Maste options->enable_escape_commandline = -1;
2695edf85781SEd Maste options->obscure_keystroke_timing_interval = -1;
2696535af610SEd Maste options->tag = NULL;
2697069ac184SEd Maste options->channel_timeouts = NULL;
2698069ac184SEd Maste options->num_channel_timeouts = 0;
2699511b41d2SMark Murray }
2700511b41d2SMark Murray
2701511b41d2SMark Murray /*
2702b83788ffSDag-Erling Smørgrav * A petite version of fill_default_options() that just fills the options
2703b83788ffSDag-Erling Smørgrav * needed for hostname canonicalization to proceed.
2704b83788ffSDag-Erling Smørgrav */
2705b83788ffSDag-Erling Smørgrav void
fill_default_options_for_canonicalization(Options * options)2706b83788ffSDag-Erling Smørgrav fill_default_options_for_canonicalization(Options *options)
2707b83788ffSDag-Erling Smørgrav {
2708b83788ffSDag-Erling Smørgrav if (options->canonicalize_max_dots == -1)
2709b83788ffSDag-Erling Smørgrav options->canonicalize_max_dots = 1;
2710b83788ffSDag-Erling Smørgrav if (options->canonicalize_fallback_local == -1)
2711b83788ffSDag-Erling Smørgrav options->canonicalize_fallback_local = 1;
2712b83788ffSDag-Erling Smørgrav if (options->canonicalize_hostname == -1)
2713b83788ffSDag-Erling Smørgrav options->canonicalize_hostname = SSH_CANONICALISE_NO;
2714b83788ffSDag-Erling Smørgrav }
2715b83788ffSDag-Erling Smørgrav
2716b83788ffSDag-Erling Smørgrav /*
2717511b41d2SMark Murray * Called after processing other sources of option data, this fills those
2718511b41d2SMark Murray * options for which no value has been specified with their default values.
2719511b41d2SMark Murray */
272019261079SEd Maste int
fill_default_options(Options * options)2721511b41d2SMark Murray fill_default_options(Options * options)
2722511b41d2SMark Murray {
27232f513db7SEd Maste char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
272419261079SEd Maste char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
272519261079SEd Maste int ret = 0, r;
2726190cef3dSDag-Erling Smørgrav
2727511b41d2SMark Murray if (options->forward_agent == -1)
2728db1cb46cSKris Kennaway options->forward_agent = 0;
2729511b41d2SMark Murray if (options->forward_x11 == -1)
27305dc73ebeSBrian Feldman options->forward_x11 = 0;
27311ec0d754SDag-Erling Smørgrav if (options->forward_x11_trusted == -1)
27321ec0d754SDag-Erling Smørgrav options->forward_x11_trusted = 0;
2733e2f6069cSDag-Erling Smørgrav if (options->forward_x11_timeout == -1)
2734e2f6069cSDag-Erling Smørgrav options->forward_x11_timeout = 1200;
2735076ad2f8SDag-Erling Smørgrav /*
2736076ad2f8SDag-Erling Smørgrav * stdio forwarding (-W) changes the default for these but we defer
2737076ad2f8SDag-Erling Smørgrav * setting the values so they can be overridden.
2738076ad2f8SDag-Erling Smørgrav */
2739333ee039SDag-Erling Smørgrav if (options->exit_on_forward_failure == -1)
2740076ad2f8SDag-Erling Smørgrav options->exit_on_forward_failure =
2741076ad2f8SDag-Erling Smørgrav options->stdio_forward_host != NULL ? 1 : 0;
2742076ad2f8SDag-Erling Smørgrav if (options->clear_forwardings == -1)
2743076ad2f8SDag-Erling Smørgrav options->clear_forwardings =
2744076ad2f8SDag-Erling Smørgrav options->stdio_forward_host != NULL ? 1 : 0;
2745076ad2f8SDag-Erling Smørgrav if (options->clear_forwardings == 1)
2746076ad2f8SDag-Erling Smørgrav clear_forwardings(options);
2747076ad2f8SDag-Erling Smørgrav
2748c2d3a559SKris Kennaway if (options->xauth_location == NULL)
274919261079SEd Maste options->xauth_location = xstrdup(_PATH_XAUTH);
2750a0ee8cc6SDag-Erling Smørgrav if (options->fwd_opts.gateway_ports == -1)
2751a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.gateway_ports = 0;
2752a0ee8cc6SDag-Erling Smørgrav if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
2753a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_mask = 0177;
2754a0ee8cc6SDag-Erling Smørgrav if (options->fwd_opts.streamlocal_bind_unlink == -1)
2755a0ee8cc6SDag-Erling Smørgrav options->fwd_opts.streamlocal_bind_unlink = 0;
2756ca3176e7SBrian Feldman if (options->pubkey_authentication == -1)
27571323ec57SEd Maste options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL;
2758cf2b5f3bSDag-Erling Smørgrav if (options->gss_authentication == -1)
27591ec0d754SDag-Erling Smørgrav options->gss_authentication = 0;
2760cf2b5f3bSDag-Erling Smørgrav if (options->gss_deleg_creds == -1)
2761cf2b5f3bSDag-Erling Smørgrav options->gss_deleg_creds = 0;
2762511b41d2SMark Murray if (options->password_authentication == -1)
2763511b41d2SMark Murray options->password_authentication = 1;
276409958426SBrian Feldman if (options->kbd_interactive_authentication == -1)
2765ca3176e7SBrian Feldman options->kbd_interactive_authentication = 1;
2766ca3176e7SBrian Feldman if (options->hostbased_authentication == -1)
2767ca3176e7SBrian Feldman options->hostbased_authentication = 0;
2768511b41d2SMark Murray if (options->batch_mode == -1)
2769511b41d2SMark Murray options->batch_mode = 0;
2770511b41d2SMark Murray if (options->check_host_ip == -1)
2771975616f0SDag-Erling Smørgrav options->check_host_ip = 0;
2772511b41d2SMark Murray if (options->strict_host_key_checking == -1)
27734f52dfbbSDag-Erling Smørgrav options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK;
2774511b41d2SMark Murray if (options->compression == -1)
2775511b41d2SMark Murray options->compression = 0;
27761ec0d754SDag-Erling Smørgrav if (options->tcp_keep_alive == -1)
27771ec0d754SDag-Erling Smørgrav options->tcp_keep_alive = 1;
2778511b41d2SMark Murray if (options->port == -1)
2779511b41d2SMark Murray options->port = 0; /* Filled in ssh_connect. */
2780cf2b5f3bSDag-Erling Smørgrav if (options->address_family == -1)
2781cf2b5f3bSDag-Erling Smørgrav options->address_family = AF_UNSPEC;
2782511b41d2SMark Murray if (options->connection_attempts == -1)
2783af12a3e7SDag-Erling Smørgrav options->connection_attempts = 1;
2784511b41d2SMark Murray if (options->number_of_password_prompts == -1)
2785511b41d2SMark Murray options->number_of_password_prompts = 3;
2786ca3176e7SBrian Feldman /* options->hostkeyalgorithms, default set in myproposals.h */
278719261079SEd Maste if (options->add_keys_to_agent == -1) {
2788acc1a9efSDag-Erling Smørgrav options->add_keys_to_agent = 0;
278919261079SEd Maste options->add_keys_to_agent_lifespan = 0;
279019261079SEd Maste }
2791511b41d2SMark Murray if (options->num_identity_files == 0) {
27924f52dfbbSDag-Erling Smørgrav add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0);
27934a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
27944f52dfbbSDag-Erling Smørgrav add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
279519261079SEd Maste add_identity_file(options, "~/",
279619261079SEd Maste _PATH_SSH_CLIENT_ID_ECDSA_SK, 0);
27974a421b63SDag-Erling Smørgrav #endif
2798f7167e0eSDag-Erling Smørgrav add_identity_file(options, "~/",
2799f7167e0eSDag-Erling Smørgrav _PATH_SSH_CLIENT_ID_ED25519, 0);
280019261079SEd Maste add_identity_file(options, "~/",
280119261079SEd Maste _PATH_SSH_CLIENT_ID_ED25519_SK, 0);
280247dd1d1bSDag-Erling Smørgrav add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0);
2803a91a2465SEd Maste #ifdef WITH_DSA
28041323ec57SEd Maste add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0);
2805a91a2465SEd Maste #endif
2806ca3176e7SBrian Feldman }
2807511b41d2SMark Murray if (options->escape_char == -1)
2808511b41d2SMark Murray options->escape_char = '~';
2809e146993eSDag-Erling Smørgrav if (options->num_system_hostfiles == 0) {
2810e146993eSDag-Erling Smørgrav options->system_hostfiles[options->num_system_hostfiles++] =
2811e146993eSDag-Erling Smørgrav xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
2812e146993eSDag-Erling Smørgrav options->system_hostfiles[options->num_system_hostfiles++] =
2813e146993eSDag-Erling Smørgrav xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
2814e146993eSDag-Erling Smørgrav }
281519261079SEd Maste if (options->update_hostkeys == -1) {
281619261079SEd Maste if (options->verify_host_key_dns <= 0 &&
281719261079SEd Maste (options->num_user_hostfiles == 0 ||
281819261079SEd Maste (options->num_user_hostfiles == 1 && strcmp(options->
281919261079SEd Maste user_hostfiles[0], _PATH_SSH_USER_HOSTFILE) == 0)))
282019261079SEd Maste options->update_hostkeys = SSH_UPDATE_HOSTKEYS_YES;
282119261079SEd Maste else
282219261079SEd Maste options->update_hostkeys = SSH_UPDATE_HOSTKEYS_NO;
282319261079SEd Maste }
2824e146993eSDag-Erling Smørgrav if (options->num_user_hostfiles == 0) {
2825e146993eSDag-Erling Smørgrav options->user_hostfiles[options->num_user_hostfiles++] =
2826e146993eSDag-Erling Smørgrav xstrdup(_PATH_SSH_USER_HOSTFILE);
2827e146993eSDag-Erling Smørgrav options->user_hostfiles[options->num_user_hostfiles++] =
2828e146993eSDag-Erling Smørgrav xstrdup(_PATH_SSH_USER_HOSTFILE2);
2829e146993eSDag-Erling Smørgrav }
2830af12a3e7SDag-Erling Smørgrav if (options->log_level == SYSLOG_LEVEL_NOT_SET)
2831511b41d2SMark Murray options->log_level = SYSLOG_LEVEL_INFO;
28324f52dfbbSDag-Erling Smørgrav if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
28334f52dfbbSDag-Erling Smørgrav options->log_facility = SYSLOG_FACILITY_USER;
2834af12a3e7SDag-Erling Smørgrav if (options->no_host_authentication_for_localhost == - 1)
2835af12a3e7SDag-Erling Smørgrav options->no_host_authentication_for_localhost = 0;
28365962c0e9SDag-Erling Smørgrav if (options->identities_only == -1)
28375962c0e9SDag-Erling Smørgrav options->identities_only = 0;
2838e73e9afaSDag-Erling Smørgrav if (options->enable_ssh_keysign == -1)
2839e73e9afaSDag-Erling Smørgrav options->enable_ssh_keysign = 0;
2840cf2b5f3bSDag-Erling Smørgrav if (options->rekey_limit == -1)
2841cf2b5f3bSDag-Erling Smørgrav options->rekey_limit = 0;
2842e4a9863fSDag-Erling Smørgrav if (options->rekey_interval == -1)
2843e4a9863fSDag-Erling Smørgrav options->rekey_interval = 0;
2844cf2b5f3bSDag-Erling Smørgrav if (options->verify_host_key_dns == -1)
2845cf2b5f3bSDag-Erling Smørgrav options->verify_host_key_dns = 0;
28461ec0d754SDag-Erling Smørgrav if (options->server_alive_interval == -1)
28471ec0d754SDag-Erling Smørgrav options->server_alive_interval = 0;
28481ec0d754SDag-Erling Smørgrav if (options->server_alive_count_max == -1)
28491ec0d754SDag-Erling Smørgrav options->server_alive_count_max = 3;
285021e764dfSDag-Erling Smørgrav if (options->control_master == -1)
285121e764dfSDag-Erling Smørgrav options->control_master = 0;
2852e2f6069cSDag-Erling Smørgrav if (options->control_persist == -1) {
2853e2f6069cSDag-Erling Smørgrav options->control_persist = 0;
2854e2f6069cSDag-Erling Smørgrav options->control_persist_timeout = 0;
2855e2f6069cSDag-Erling Smørgrav }
2856aa49c926SDag-Erling Smørgrav if (options->hash_known_hosts == -1)
2857aa49c926SDag-Erling Smørgrav options->hash_known_hosts = 0;
2858b74df5b2SDag-Erling Smørgrav if (options->tun_open == -1)
2859b74df5b2SDag-Erling Smørgrav options->tun_open = SSH_TUNMODE_NO;
2860b74df5b2SDag-Erling Smørgrav if (options->tun_local == -1)
2861b74df5b2SDag-Erling Smørgrav options->tun_local = SSH_TUNID_ANY;
2862b74df5b2SDag-Erling Smørgrav if (options->tun_remote == -1)
2863b74df5b2SDag-Erling Smørgrav options->tun_remote = SSH_TUNID_ANY;
2864b74df5b2SDag-Erling Smørgrav if (options->permit_local_command == -1)
2865b74df5b2SDag-Erling Smørgrav options->permit_local_command = 0;
2866d4af9e69SDag-Erling Smørgrav if (options->visual_host_key == -1)
2867d4af9e69SDag-Erling Smørgrav options->visual_host_key = 0;
28684a421b63SDag-Erling Smørgrav if (options->ip_qos_interactive == -1)
2869190cef3dSDag-Erling Smørgrav options->ip_qos_interactive = IPTOS_DSCP_AF21;
28704a421b63SDag-Erling Smørgrav if (options->ip_qos_bulk == -1)
2871190cef3dSDag-Erling Smørgrav options->ip_qos_bulk = IPTOS_DSCP_CS1;
2872e146993eSDag-Erling Smørgrav if (options->request_tty == -1)
2873e146993eSDag-Erling Smørgrav options->request_tty = REQUEST_TTY_AUTO;
287419261079SEd Maste if (options->session_type == -1)
287519261079SEd Maste options->session_type = SESSION_TYPE_DEFAULT;
287619261079SEd Maste if (options->stdin_null == -1)
287719261079SEd Maste options->stdin_null = 0;
287819261079SEd Maste if (options->fork_after_authentication == -1)
287919261079SEd Maste options->fork_after_authentication = 0;
2880f7167e0eSDag-Erling Smørgrav if (options->proxy_use_fdpass == -1)
2881f7167e0eSDag-Erling Smørgrav options->proxy_use_fdpass = 0;
2882f7167e0eSDag-Erling Smørgrav if (options->canonicalize_max_dots == -1)
2883f7167e0eSDag-Erling Smørgrav options->canonicalize_max_dots = 1;
2884f7167e0eSDag-Erling Smørgrav if (options->canonicalize_fallback_local == -1)
2885f7167e0eSDag-Erling Smørgrav options->canonicalize_fallback_local = 1;
2886f7167e0eSDag-Erling Smørgrav if (options->canonicalize_hostname == -1)
2887f7167e0eSDag-Erling Smørgrav options->canonicalize_hostname = SSH_CANONICALISE_NO;
2888bc5531deSDag-Erling Smørgrav if (options->fingerprint_hash == -1)
2889bc5531deSDag-Erling Smørgrav options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
289019261079SEd Maste #ifdef ENABLE_SK_INTERNAL
289119261079SEd Maste if (options->sk_provider == NULL)
289219261079SEd Maste options->sk_provider = xstrdup("internal");
289319261079SEd Maste #else
289419261079SEd Maste if (options->sk_provider == NULL)
289519261079SEd Maste options->sk_provider = xstrdup("$SSH_SK_PROVIDER");
289619261079SEd Maste #endif
289738a52bd3SEd Maste if (options->required_rsa_size == -1)
289838a52bd3SEd Maste options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
2899f374ba41SEd Maste if (options->enable_escape_commandline == -1)
2900f374ba41SEd Maste options->enable_escape_commandline = 0;
2901edf85781SEd Maste if (options->obscure_keystroke_timing_interval == -1) {
2902edf85781SEd Maste options->obscure_keystroke_timing_interval =
2903edf85781SEd Maste SSH_KEYSTROKE_DEFAULT_INTERVAL_MS;
2904edf85781SEd Maste }
2905190cef3dSDag-Erling Smørgrav
2906190cef3dSDag-Erling Smørgrav /* Expand KEX name lists */
2907190cef3dSDag-Erling Smørgrav all_cipher = cipher_alg_list(',', 0);
2908190cef3dSDag-Erling Smørgrav all_mac = mac_alg_list(',');
2909190cef3dSDag-Erling Smørgrav all_kex = kex_alg_list(',');
2910190cef3dSDag-Erling Smørgrav all_key = sshkey_alg_list(0, 0, 1, ',');
29112f513db7SEd Maste all_sig = sshkey_alg_list(0, 1, 1, ',');
291219261079SEd Maste /* remove unsupported algos from default lists */
291319261079SEd Maste def_cipher = match_filter_allowlist(KEX_CLIENT_ENCRYPT, all_cipher);
291419261079SEd Maste def_mac = match_filter_allowlist(KEX_CLIENT_MAC, all_mac);
291519261079SEd Maste def_kex = match_filter_allowlist(KEX_CLIENT_KEX, all_kex);
291619261079SEd Maste def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
291719261079SEd Maste def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
2918190cef3dSDag-Erling Smørgrav #define ASSEMBLE(what, defaults, all) \
2919190cef3dSDag-Erling Smørgrav do { \
2920190cef3dSDag-Erling Smørgrav if ((r = kex_assemble_names(&options->what, \
292119261079SEd Maste defaults, all)) != 0) { \
292219261079SEd Maste error_fr(r, "%s", #what); \
292319261079SEd Maste goto fail; \
292419261079SEd Maste } \
2925190cef3dSDag-Erling Smørgrav } while (0)
292619261079SEd Maste ASSEMBLE(ciphers, def_cipher, all_cipher);
292719261079SEd Maste ASSEMBLE(macs, def_mac, all_mac);
292819261079SEd Maste ASSEMBLE(kex_algorithms, def_kex, all_kex);
292919261079SEd Maste ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
293019261079SEd Maste ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
293119261079SEd Maste ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
2932190cef3dSDag-Erling Smørgrav #undef ASSEMBLE
2933bc5531deSDag-Erling Smørgrav
2934f7167e0eSDag-Erling Smørgrav #define CLEAR_ON_NONE(v) \
2935f7167e0eSDag-Erling Smørgrav do { \
2936b83788ffSDag-Erling Smørgrav if (option_clear_or_none(v)) { \
2937f7167e0eSDag-Erling Smørgrav free(v); \
2938f7167e0eSDag-Erling Smørgrav v = NULL; \
2939f7167e0eSDag-Erling Smørgrav } \
2940f7167e0eSDag-Erling Smørgrav } while(0)
2941069ac184SEd Maste #define CLEAR_ON_NONE_ARRAY(v, nv, none) \
2942069ac184SEd Maste do { \
2943069ac184SEd Maste if (options->nv == 1 && \
2944069ac184SEd Maste strcasecmp(options->v[0], none) == 0) { \
2945069ac184SEd Maste free(options->v[0]); \
2946069ac184SEd Maste free(options->v); \
2947069ac184SEd Maste options->v = NULL; \
2948069ac184SEd Maste options->nv = 0; \
2949069ac184SEd Maste } \
2950069ac184SEd Maste } while (0)
2951f7167e0eSDag-Erling Smørgrav CLEAR_ON_NONE(options->local_command);
29524f52dfbbSDag-Erling Smørgrav CLEAR_ON_NONE(options->remote_command);
2953f7167e0eSDag-Erling Smørgrav CLEAR_ON_NONE(options->proxy_command);
2954f7167e0eSDag-Erling Smørgrav CLEAR_ON_NONE(options->control_path);
2955bc5531deSDag-Erling Smørgrav CLEAR_ON_NONE(options->revoked_host_keys);
295619261079SEd Maste CLEAR_ON_NONE(options->pkcs11_provider);
295719261079SEd Maste CLEAR_ON_NONE(options->sk_provider);
295819261079SEd Maste CLEAR_ON_NONE(options->known_hosts_command);
2959069ac184SEd Maste CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none");
2960069ac184SEd Maste #undef CLEAR_ON_NONE
2961069ac184SEd Maste #undef CLEAR_ON_NONE_ARRAY
2962190cef3dSDag-Erling Smørgrav if (options->jump_host != NULL &&
2963190cef3dSDag-Erling Smørgrav strcmp(options->jump_host, "none") == 0 &&
2964190cef3dSDag-Erling Smørgrav options->jump_port == 0 && options->jump_user == NULL) {
2965190cef3dSDag-Erling Smørgrav free(options->jump_host);
2966190cef3dSDag-Erling Smørgrav options->jump_host = NULL;
2967190cef3dSDag-Erling Smørgrav }
2968e9e8876aSEd Maste if (options->num_permitted_cnames == 1 &&
2969e9e8876aSEd Maste !config_has_permitted_cnames(options)) {
2970e9e8876aSEd Maste /* clean up CanonicalizePermittedCNAMEs=none */
2971e9e8876aSEd Maste free(options->permitted_cnames[0].source_list);
2972e9e8876aSEd Maste free(options->permitted_cnames[0].target_list);
2973e9e8876aSEd Maste memset(options->permitted_cnames, '\0',
2974e9e8876aSEd Maste sizeof(*options->permitted_cnames));
2975e9e8876aSEd Maste options->num_permitted_cnames = 0;
2976e9e8876aSEd Maste }
2977076ad2f8SDag-Erling Smørgrav /* options->identity_agent distinguishes NULL from 'none' */
2978511b41d2SMark Murray /* options->user will be set in the main program if appropriate */
2979511b41d2SMark Murray /* options->hostname will be set in the main program if appropriate */
2980ca3176e7SBrian Feldman /* options->host_key_alias should not be set by default */
2981ca3176e7SBrian Feldman /* options->preferred_authentications will be set in ssh */
298219261079SEd Maste
298319261079SEd Maste /* success */
298419261079SEd Maste ret = 0;
298519261079SEd Maste fail:
298619261079SEd Maste free(all_cipher);
298719261079SEd Maste free(all_mac);
298819261079SEd Maste free(all_kex);
298919261079SEd Maste free(all_key);
299019261079SEd Maste free(all_sig);
299119261079SEd Maste free(def_cipher);
299219261079SEd Maste free(def_mac);
299319261079SEd Maste free(def_kex);
299419261079SEd Maste free(def_key);
299519261079SEd Maste free(def_sig);
299619261079SEd Maste return ret;
299719261079SEd Maste }
299819261079SEd Maste
299919261079SEd Maste void
free_options(Options * o)300019261079SEd Maste free_options(Options *o)
300119261079SEd Maste {
300219261079SEd Maste int i;
300319261079SEd Maste
300419261079SEd Maste if (o == NULL)
300519261079SEd Maste return;
300619261079SEd Maste
300719261079SEd Maste #define FREE_ARRAY(type, n, a) \
300819261079SEd Maste do { \
300919261079SEd Maste type _i; \
301019261079SEd Maste for (_i = 0; _i < (n); _i++) \
301119261079SEd Maste free((a)[_i]); \
301219261079SEd Maste } while (0)
301319261079SEd Maste
301419261079SEd Maste free(o->forward_agent_sock_path);
301519261079SEd Maste free(o->xauth_location);
301619261079SEd Maste FREE_ARRAY(u_int, o->num_log_verbose, o->log_verbose);
301719261079SEd Maste free(o->log_verbose);
301819261079SEd Maste free(o->ciphers);
301919261079SEd Maste free(o->macs);
302019261079SEd Maste free(o->hostkeyalgorithms);
302119261079SEd Maste free(o->kex_algorithms);
302219261079SEd Maste free(o->ca_sign_algorithms);
302319261079SEd Maste free(o->hostname);
302419261079SEd Maste free(o->host_key_alias);
302519261079SEd Maste free(o->proxy_command);
302619261079SEd Maste free(o->user);
302719261079SEd Maste FREE_ARRAY(u_int, o->num_system_hostfiles, o->system_hostfiles);
302819261079SEd Maste FREE_ARRAY(u_int, o->num_user_hostfiles, o->user_hostfiles);
302919261079SEd Maste free(o->preferred_authentications);
303019261079SEd Maste free(o->bind_address);
303119261079SEd Maste free(o->bind_interface);
303219261079SEd Maste free(o->pkcs11_provider);
303319261079SEd Maste free(o->sk_provider);
303419261079SEd Maste for (i = 0; i < o->num_identity_files; i++) {
303519261079SEd Maste free(o->identity_files[i]);
303619261079SEd Maste sshkey_free(o->identity_keys[i]);
303719261079SEd Maste }
303819261079SEd Maste for (i = 0; i < o->num_certificate_files; i++) {
303919261079SEd Maste free(o->certificate_files[i]);
304019261079SEd Maste sshkey_free(o->certificates[i]);
304119261079SEd Maste }
304219261079SEd Maste free(o->identity_agent);
304319261079SEd Maste for (i = 0; i < o->num_local_forwards; i++) {
304419261079SEd Maste free(o->local_forwards[i].listen_host);
304519261079SEd Maste free(o->local_forwards[i].listen_path);
304619261079SEd Maste free(o->local_forwards[i].connect_host);
304719261079SEd Maste free(o->local_forwards[i].connect_path);
304819261079SEd Maste }
304919261079SEd Maste free(o->local_forwards);
305019261079SEd Maste for (i = 0; i < o->num_remote_forwards; i++) {
305119261079SEd Maste free(o->remote_forwards[i].listen_host);
305219261079SEd Maste free(o->remote_forwards[i].listen_path);
305319261079SEd Maste free(o->remote_forwards[i].connect_host);
305419261079SEd Maste free(o->remote_forwards[i].connect_path);
305519261079SEd Maste }
305619261079SEd Maste free(o->remote_forwards);
305719261079SEd Maste free(o->stdio_forward_host);
305838a52bd3SEd Maste FREE_ARRAY(u_int, o->num_send_env, o->send_env);
305919261079SEd Maste free(o->send_env);
306038a52bd3SEd Maste FREE_ARRAY(u_int, o->num_setenv, o->setenv);
306119261079SEd Maste free(o->setenv);
306219261079SEd Maste free(o->control_path);
306319261079SEd Maste free(o->local_command);
306419261079SEd Maste free(o->remote_command);
306519261079SEd Maste FREE_ARRAY(int, o->num_canonical_domains, o->canonical_domains);
306619261079SEd Maste for (i = 0; i < o->num_permitted_cnames; i++) {
306719261079SEd Maste free(o->permitted_cnames[i].source_list);
306819261079SEd Maste free(o->permitted_cnames[i].target_list);
306919261079SEd Maste }
307019261079SEd Maste free(o->revoked_host_keys);
307119261079SEd Maste free(o->hostbased_accepted_algos);
307219261079SEd Maste free(o->pubkey_accepted_algos);
307319261079SEd Maste free(o->jump_user);
307419261079SEd Maste free(o->jump_host);
307519261079SEd Maste free(o->jump_extra);
307619261079SEd Maste free(o->ignored_unknown);
307719261079SEd Maste explicit_bzero(o, sizeof(*o));
307819261079SEd Maste #undef FREE_ARRAY
3079511b41d2SMark Murray }
3080aa49c926SDag-Erling Smørgrav
3081a0ee8cc6SDag-Erling Smørgrav struct fwdarg {
3082a0ee8cc6SDag-Erling Smørgrav char *arg;
3083a0ee8cc6SDag-Erling Smørgrav int ispath;
3084a0ee8cc6SDag-Erling Smørgrav };
3085a0ee8cc6SDag-Erling Smørgrav
3086a0ee8cc6SDag-Erling Smørgrav /*
3087a0ee8cc6SDag-Erling Smørgrav * parse_fwd_field
3088a0ee8cc6SDag-Erling Smørgrav * parses the next field in a port forwarding specification.
3089a0ee8cc6SDag-Erling Smørgrav * sets fwd to the parsed field and advances p past the colon
3090a0ee8cc6SDag-Erling Smørgrav * or sets it to NULL at end of string.
3091a0ee8cc6SDag-Erling Smørgrav * returns 0 on success, else non-zero.
3092a0ee8cc6SDag-Erling Smørgrav */
3093a0ee8cc6SDag-Erling Smørgrav static int
parse_fwd_field(char ** p,struct fwdarg * fwd)3094a0ee8cc6SDag-Erling Smørgrav parse_fwd_field(char **p, struct fwdarg *fwd)
3095a0ee8cc6SDag-Erling Smørgrav {
3096a0ee8cc6SDag-Erling Smørgrav char *ep, *cp = *p;
3097a0ee8cc6SDag-Erling Smørgrav int ispath = 0;
3098a0ee8cc6SDag-Erling Smørgrav
3099a0ee8cc6SDag-Erling Smørgrav if (*cp == '\0') {
3100a0ee8cc6SDag-Erling Smørgrav *p = NULL;
3101a0ee8cc6SDag-Erling Smørgrav return -1; /* end of string */
3102a0ee8cc6SDag-Erling Smørgrav }
3103a0ee8cc6SDag-Erling Smørgrav
3104a0ee8cc6SDag-Erling Smørgrav /*
3105a0ee8cc6SDag-Erling Smørgrav * A field escaped with square brackets is used literally.
3106a0ee8cc6SDag-Erling Smørgrav * XXX - allow ']' to be escaped via backslash?
3107a0ee8cc6SDag-Erling Smørgrav */
3108a0ee8cc6SDag-Erling Smørgrav if (*cp == '[') {
3109a0ee8cc6SDag-Erling Smørgrav /* find matching ']' */
3110a0ee8cc6SDag-Erling Smørgrav for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
3111a0ee8cc6SDag-Erling Smørgrav if (*ep == '/')
3112a0ee8cc6SDag-Erling Smørgrav ispath = 1;
3113a0ee8cc6SDag-Erling Smørgrav }
3114a0ee8cc6SDag-Erling Smørgrav /* no matching ']' or not at end of field. */
3115a0ee8cc6SDag-Erling Smørgrav if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
3116a0ee8cc6SDag-Erling Smørgrav return -1;
3117a0ee8cc6SDag-Erling Smørgrav /* NUL terminate the field and advance p past the colon */
3118a0ee8cc6SDag-Erling Smørgrav *ep++ = '\0';
3119a0ee8cc6SDag-Erling Smørgrav if (*ep != '\0')
3120a0ee8cc6SDag-Erling Smørgrav *ep++ = '\0';
3121a0ee8cc6SDag-Erling Smørgrav fwd->arg = cp + 1;
3122a0ee8cc6SDag-Erling Smørgrav fwd->ispath = ispath;
3123a0ee8cc6SDag-Erling Smørgrav *p = ep;
3124a0ee8cc6SDag-Erling Smørgrav return 0;
3125a0ee8cc6SDag-Erling Smørgrav }
3126a0ee8cc6SDag-Erling Smørgrav
3127a0ee8cc6SDag-Erling Smørgrav for (cp = *p; *cp != '\0'; cp++) {
3128a0ee8cc6SDag-Erling Smørgrav switch (*cp) {
3129a0ee8cc6SDag-Erling Smørgrav case '\\':
3130a0ee8cc6SDag-Erling Smørgrav memmove(cp, cp + 1, strlen(cp + 1) + 1);
3131557f75e5SDag-Erling Smørgrav if (*cp == '\0')
3132557f75e5SDag-Erling Smørgrav return -1;
3133a0ee8cc6SDag-Erling Smørgrav break;
3134a0ee8cc6SDag-Erling Smørgrav case '/':
3135a0ee8cc6SDag-Erling Smørgrav ispath = 1;
3136a0ee8cc6SDag-Erling Smørgrav break;
3137a0ee8cc6SDag-Erling Smørgrav case ':':
3138a0ee8cc6SDag-Erling Smørgrav *cp++ = '\0';
3139a0ee8cc6SDag-Erling Smørgrav goto done;
3140a0ee8cc6SDag-Erling Smørgrav }
3141a0ee8cc6SDag-Erling Smørgrav }
3142a0ee8cc6SDag-Erling Smørgrav done:
3143a0ee8cc6SDag-Erling Smørgrav fwd->arg = *p;
3144a0ee8cc6SDag-Erling Smørgrav fwd->ispath = ispath;
3145a0ee8cc6SDag-Erling Smørgrav *p = cp;
3146a0ee8cc6SDag-Erling Smørgrav return 0;
3147a0ee8cc6SDag-Erling Smørgrav }
3148a0ee8cc6SDag-Erling Smørgrav
3149aa49c926SDag-Erling Smørgrav /*
3150aa49c926SDag-Erling Smørgrav * parse_forward
3151aa49c926SDag-Erling Smørgrav * parses a string containing a port forwarding specification of the form:
3152cce7d346SDag-Erling Smørgrav * dynamicfwd == 0
3153a0ee8cc6SDag-Erling Smørgrav * [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
3154a0ee8cc6SDag-Erling Smørgrav * listenpath:connectpath
3155cce7d346SDag-Erling Smørgrav * dynamicfwd == 1
3156cce7d346SDag-Erling Smørgrav * [listenhost:]listenport
3157aa49c926SDag-Erling Smørgrav * returns number of arguments parsed or zero on error
3158aa49c926SDag-Erling Smørgrav */
3159aa49c926SDag-Erling Smørgrav int
parse_forward(struct Forward * fwd,const char * fwdspec,int dynamicfwd,int remotefwd)3160a0ee8cc6SDag-Erling Smørgrav parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
3161aa49c926SDag-Erling Smørgrav {
3162a0ee8cc6SDag-Erling Smørgrav struct fwdarg fwdargs[4];
3163a0ee8cc6SDag-Erling Smørgrav char *p, *cp;
316419261079SEd Maste int i, err;
3165aa49c926SDag-Erling Smørgrav
3166a0ee8cc6SDag-Erling Smørgrav memset(fwd, 0, sizeof(*fwd));
3167a0ee8cc6SDag-Erling Smørgrav memset(fwdargs, 0, sizeof(fwdargs));
3168aa49c926SDag-Erling Smørgrav
316919261079SEd Maste /*
317019261079SEd Maste * We expand environment variables before checking if we think they're
317119261079SEd Maste * paths so that if ${VAR} expands to a fully qualified path it is
317219261079SEd Maste * treated as a path.
317319261079SEd Maste */
317419261079SEd Maste cp = p = dollar_expand(&err, fwdspec);
317519261079SEd Maste if (p == NULL || err)
317619261079SEd Maste return 0;
3177aa49c926SDag-Erling Smørgrav
3178aa49c926SDag-Erling Smørgrav /* skip leading spaces */
3179f7167e0eSDag-Erling Smørgrav while (isspace((u_char)*cp))
3180aa49c926SDag-Erling Smørgrav cp++;
3181aa49c926SDag-Erling Smørgrav
3182a0ee8cc6SDag-Erling Smørgrav for (i = 0; i < 4; ++i) {
3183a0ee8cc6SDag-Erling Smørgrav if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
3184aa49c926SDag-Erling Smørgrav break;
3185a0ee8cc6SDag-Erling Smørgrav }
3186aa49c926SDag-Erling Smørgrav
3187cce7d346SDag-Erling Smørgrav /* Check for trailing garbage */
3188a0ee8cc6SDag-Erling Smørgrav if (cp != NULL && *cp != '\0') {
3189aa49c926SDag-Erling Smørgrav i = 0; /* failure */
3190a0ee8cc6SDag-Erling Smørgrav }
3191aa49c926SDag-Erling Smørgrav
3192aa49c926SDag-Erling Smørgrav switch (i) {
3193cce7d346SDag-Erling Smørgrav case 1:
3194a0ee8cc6SDag-Erling Smørgrav if (fwdargs[0].ispath) {
3195a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = xstrdup(fwdargs[0].arg);
3196a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = PORT_STREAMLOCAL;
3197a0ee8cc6SDag-Erling Smørgrav } else {
3198cce7d346SDag-Erling Smørgrav fwd->listen_host = NULL;
3199a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[0].arg);
3200a0ee8cc6SDag-Erling Smørgrav }
3201cce7d346SDag-Erling Smørgrav fwd->connect_host = xstrdup("socks");
3202cce7d346SDag-Erling Smørgrav break;
3203cce7d346SDag-Erling Smørgrav
3204cce7d346SDag-Erling Smørgrav case 2:
3205a0ee8cc6SDag-Erling Smørgrav if (fwdargs[0].ispath && fwdargs[1].ispath) {
3206a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = xstrdup(fwdargs[0].arg);
3207a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = PORT_STREAMLOCAL;
3208a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = xstrdup(fwdargs[1].arg);
3209a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = PORT_STREAMLOCAL;
3210a0ee8cc6SDag-Erling Smørgrav } else if (fwdargs[1].ispath) {
3211a0ee8cc6SDag-Erling Smørgrav fwd->listen_host = NULL;
3212a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[0].arg);
3213a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = xstrdup(fwdargs[1].arg);
3214a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = PORT_STREAMLOCAL;
3215a0ee8cc6SDag-Erling Smørgrav } else {
3216a0ee8cc6SDag-Erling Smørgrav fwd->listen_host = xstrdup(fwdargs[0].arg);
3217a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[1].arg);
3218cce7d346SDag-Erling Smørgrav fwd->connect_host = xstrdup("socks");
3219a0ee8cc6SDag-Erling Smørgrav }
3220cce7d346SDag-Erling Smørgrav break;
3221cce7d346SDag-Erling Smørgrav
3222aa49c926SDag-Erling Smørgrav case 3:
3223a0ee8cc6SDag-Erling Smørgrav if (fwdargs[0].ispath) {
3224a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = xstrdup(fwdargs[0].arg);
3225a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = PORT_STREAMLOCAL;
3226a0ee8cc6SDag-Erling Smørgrav fwd->connect_host = xstrdup(fwdargs[1].arg);
3227a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = a2port(fwdargs[2].arg);
3228a0ee8cc6SDag-Erling Smørgrav } else if (fwdargs[2].ispath) {
3229a0ee8cc6SDag-Erling Smørgrav fwd->listen_host = xstrdup(fwdargs[0].arg);
3230a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[1].arg);
3231a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = xstrdup(fwdargs[2].arg);
3232a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = PORT_STREAMLOCAL;
3233a0ee8cc6SDag-Erling Smørgrav } else {
3234aa49c926SDag-Erling Smørgrav fwd->listen_host = NULL;
3235a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[0].arg);
3236a0ee8cc6SDag-Erling Smørgrav fwd->connect_host = xstrdup(fwdargs[1].arg);
3237a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = a2port(fwdargs[2].arg);
3238a0ee8cc6SDag-Erling Smørgrav }
3239aa49c926SDag-Erling Smørgrav break;
3240aa49c926SDag-Erling Smørgrav
3241aa49c926SDag-Erling Smørgrav case 4:
3242a0ee8cc6SDag-Erling Smørgrav fwd->listen_host = xstrdup(fwdargs[0].arg);
3243a0ee8cc6SDag-Erling Smørgrav fwd->listen_port = a2port(fwdargs[1].arg);
3244a0ee8cc6SDag-Erling Smørgrav fwd->connect_host = xstrdup(fwdargs[2].arg);
3245a0ee8cc6SDag-Erling Smørgrav fwd->connect_port = a2port(fwdargs[3].arg);
3246aa49c926SDag-Erling Smørgrav break;
3247aa49c926SDag-Erling Smørgrav default:
3248aa49c926SDag-Erling Smørgrav i = 0; /* failure */
3249aa49c926SDag-Erling Smørgrav }
3250aa49c926SDag-Erling Smørgrav
3251e4a9863fSDag-Erling Smørgrav free(p);
3252aa49c926SDag-Erling Smørgrav
3253cce7d346SDag-Erling Smørgrav if (dynamicfwd) {
3254cce7d346SDag-Erling Smørgrav if (!(i == 1 || i == 2))
3255cce7d346SDag-Erling Smørgrav goto fail_free;
3256cce7d346SDag-Erling Smørgrav } else {
3257a0ee8cc6SDag-Erling Smørgrav if (!(i == 3 || i == 4)) {
3258a0ee8cc6SDag-Erling Smørgrav if (fwd->connect_path == NULL &&
3259a0ee8cc6SDag-Erling Smørgrav fwd->listen_path == NULL)
3260cce7d346SDag-Erling Smørgrav goto fail_free;
3261a0ee8cc6SDag-Erling Smørgrav }
3262a0ee8cc6SDag-Erling Smørgrav if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
3263cce7d346SDag-Erling Smørgrav goto fail_free;
3264cce7d346SDag-Erling Smørgrav }
3265cce7d346SDag-Erling Smørgrav
3266a0ee8cc6SDag-Erling Smørgrav if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
3267a0ee8cc6SDag-Erling Smørgrav (!remotefwd && fwd->listen_port == 0))
3268aa49c926SDag-Erling Smørgrav goto fail_free;
3269aa49c926SDag-Erling Smørgrav if (fwd->connect_host != NULL &&
3270aa49c926SDag-Erling Smørgrav strlen(fwd->connect_host) >= NI_MAXHOST)
3271aa49c926SDag-Erling Smørgrav goto fail_free;
327219261079SEd Maste /*
327319261079SEd Maste * XXX - if connecting to a remote socket, max sun len may not
327419261079SEd Maste * match this host
327519261079SEd Maste */
3276a0ee8cc6SDag-Erling Smørgrav if (fwd->connect_path != NULL &&
3277a0ee8cc6SDag-Erling Smørgrav strlen(fwd->connect_path) >= PATH_MAX_SUN)
3278a0ee8cc6SDag-Erling Smørgrav goto fail_free;
3279cce7d346SDag-Erling Smørgrav if (fwd->listen_host != NULL &&
3280cce7d346SDag-Erling Smørgrav strlen(fwd->listen_host) >= NI_MAXHOST)
3281cce7d346SDag-Erling Smørgrav goto fail_free;
3282a0ee8cc6SDag-Erling Smørgrav if (fwd->listen_path != NULL &&
3283a0ee8cc6SDag-Erling Smørgrav strlen(fwd->listen_path) >= PATH_MAX_SUN)
3284a0ee8cc6SDag-Erling Smørgrav goto fail_free;
3285aa49c926SDag-Erling Smørgrav
3286aa49c926SDag-Erling Smørgrav return (i);
3287aa49c926SDag-Erling Smørgrav
3288aa49c926SDag-Erling Smørgrav fail_free:
3289e4a9863fSDag-Erling Smørgrav free(fwd->connect_host);
3290cce7d346SDag-Erling Smørgrav fwd->connect_host = NULL;
3291a0ee8cc6SDag-Erling Smørgrav free(fwd->connect_path);
3292a0ee8cc6SDag-Erling Smørgrav fwd->connect_path = NULL;
3293e4a9863fSDag-Erling Smørgrav free(fwd->listen_host);
3294cce7d346SDag-Erling Smørgrav fwd->listen_host = NULL;
3295a0ee8cc6SDag-Erling Smørgrav free(fwd->listen_path);
3296a0ee8cc6SDag-Erling Smørgrav fwd->listen_path = NULL;
3297aa49c926SDag-Erling Smørgrav return (0);
3298aa49c926SDag-Erling Smørgrav }
3299bc5531deSDag-Erling Smørgrav
3300076ad2f8SDag-Erling Smørgrav int
parse_jump(const char * s,Options * o,int active)3301076ad2f8SDag-Erling Smørgrav parse_jump(const char *s, Options *o, int active)
3302076ad2f8SDag-Erling Smørgrav {
3303076ad2f8SDag-Erling Smørgrav char *orig, *sdup, *cp;
3304076ad2f8SDag-Erling Smørgrav char *host = NULL, *user = NULL;
330519261079SEd Maste int r, ret = -1, port = -1, first;
3306076ad2f8SDag-Erling Smørgrav
3307076ad2f8SDag-Erling Smørgrav active &= o->proxy_command == NULL && o->jump_host == NULL;
3308076ad2f8SDag-Erling Smørgrav
3309076ad2f8SDag-Erling Smørgrav orig = sdup = xstrdup(s);
331019261079SEd Maste
331119261079SEd Maste /* Remove comment and trailing whitespace */
331219261079SEd Maste if ((cp = strchr(orig, '#')) != NULL)
331319261079SEd Maste *cp = '\0';
331419261079SEd Maste rtrim(orig);
331519261079SEd Maste
3316076ad2f8SDag-Erling Smørgrav first = active;
3317076ad2f8SDag-Erling Smørgrav do {
3318190cef3dSDag-Erling Smørgrav if (strcasecmp(s, "none") == 0)
3319190cef3dSDag-Erling Smørgrav break;
3320076ad2f8SDag-Erling Smørgrav if ((cp = strrchr(sdup, ',')) == NULL)
3321076ad2f8SDag-Erling Smørgrav cp = sdup; /* last */
3322076ad2f8SDag-Erling Smørgrav else
3323076ad2f8SDag-Erling Smørgrav *cp++ = '\0';
3324076ad2f8SDag-Erling Smørgrav
3325076ad2f8SDag-Erling Smørgrav if (first) {
3326076ad2f8SDag-Erling Smørgrav /* First argument and configuration is active */
332719261079SEd Maste r = parse_ssh_uri(cp, &user, &host, &port);
332819261079SEd Maste if (r == -1 || (r == 1 &&
332919261079SEd Maste parse_user_host_port(cp, &user, &host, &port) != 0))
3330076ad2f8SDag-Erling Smørgrav goto out;
3331076ad2f8SDag-Erling Smørgrav } else {
3332076ad2f8SDag-Erling Smørgrav /* Subsequent argument or inactive configuration */
333319261079SEd Maste r = parse_ssh_uri(cp, NULL, NULL, NULL);
333419261079SEd Maste if (r == -1 || (r == 1 &&
333519261079SEd Maste parse_user_host_port(cp, NULL, NULL, NULL) != 0))
3336076ad2f8SDag-Erling Smørgrav goto out;
3337076ad2f8SDag-Erling Smørgrav }
3338076ad2f8SDag-Erling Smørgrav first = 0; /* only check syntax for subsequent hosts */
3339076ad2f8SDag-Erling Smørgrav } while (cp != sdup);
3340076ad2f8SDag-Erling Smørgrav /* success */
3341076ad2f8SDag-Erling Smørgrav if (active) {
3342190cef3dSDag-Erling Smørgrav if (strcasecmp(s, "none") == 0) {
3343190cef3dSDag-Erling Smørgrav o->jump_host = xstrdup("none");
3344190cef3dSDag-Erling Smørgrav o->jump_port = 0;
3345190cef3dSDag-Erling Smørgrav } else {
3346076ad2f8SDag-Erling Smørgrav o->jump_user = user;
3347076ad2f8SDag-Erling Smørgrav o->jump_host = host;
3348076ad2f8SDag-Erling Smørgrav o->jump_port = port;
3349076ad2f8SDag-Erling Smørgrav o->proxy_command = xstrdup("none");
3350076ad2f8SDag-Erling Smørgrav user = host = NULL;
3351076ad2f8SDag-Erling Smørgrav if ((cp = strrchr(s, ',')) != NULL && cp != s) {
3352076ad2f8SDag-Erling Smørgrav o->jump_extra = xstrdup(s);
3353076ad2f8SDag-Erling Smørgrav o->jump_extra[cp - s] = '\0';
3354076ad2f8SDag-Erling Smørgrav }
3355076ad2f8SDag-Erling Smørgrav }
3356190cef3dSDag-Erling Smørgrav }
3357076ad2f8SDag-Erling Smørgrav ret = 0;
3358076ad2f8SDag-Erling Smørgrav out:
3359076ad2f8SDag-Erling Smørgrav free(orig);
3360076ad2f8SDag-Erling Smørgrav free(user);
3361076ad2f8SDag-Erling Smørgrav free(host);
3362076ad2f8SDag-Erling Smørgrav return ret;
3363076ad2f8SDag-Erling Smørgrav }
3364076ad2f8SDag-Erling Smørgrav
336547dd1d1bSDag-Erling Smørgrav int
parse_ssh_uri(const char * uri,char ** userp,char ** hostp,int * portp)336647dd1d1bSDag-Erling Smørgrav parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
336747dd1d1bSDag-Erling Smørgrav {
336819261079SEd Maste char *user = NULL, *host = NULL, *path = NULL;
336919261079SEd Maste int r, port;
337047dd1d1bSDag-Erling Smørgrav
337119261079SEd Maste r = parse_uri("ssh", uri, &user, &host, &port, &path);
337247dd1d1bSDag-Erling Smørgrav if (r == 0 && path != NULL)
337347dd1d1bSDag-Erling Smørgrav r = -1; /* path not allowed */
337419261079SEd Maste if (r == 0) {
337519261079SEd Maste if (userp != NULL) {
337619261079SEd Maste *userp = user;
337719261079SEd Maste user = NULL;
337819261079SEd Maste }
337919261079SEd Maste if (hostp != NULL) {
338019261079SEd Maste *hostp = host;
338119261079SEd Maste host = NULL;
338219261079SEd Maste }
338319261079SEd Maste if (portp != NULL)
338419261079SEd Maste *portp = port;
338519261079SEd Maste }
338619261079SEd Maste free(user);
338719261079SEd Maste free(host);
338819261079SEd Maste free(path);
338947dd1d1bSDag-Erling Smørgrav return r;
339047dd1d1bSDag-Erling Smørgrav }
339147dd1d1bSDag-Erling Smørgrav
33920fdf8faeSEd Maste /* XXX the following is a near-verbatim copy from servconf.c; refactor */
3393bc5531deSDag-Erling Smørgrav static const char *
fmt_multistate_int(int val,const struct multistate * m)3394bc5531deSDag-Erling Smørgrav fmt_multistate_int(int val, const struct multistate *m)
3395bc5531deSDag-Erling Smørgrav {
3396bc5531deSDag-Erling Smørgrav u_int i;
3397bc5531deSDag-Erling Smørgrav
3398bc5531deSDag-Erling Smørgrav for (i = 0; m[i].key != NULL; i++) {
3399bc5531deSDag-Erling Smørgrav if (m[i].value == val)
3400bc5531deSDag-Erling Smørgrav return m[i].key;
3401bc5531deSDag-Erling Smørgrav }
3402bc5531deSDag-Erling Smørgrav return "UNKNOWN";
3403bc5531deSDag-Erling Smørgrav }
3404bc5531deSDag-Erling Smørgrav
3405bc5531deSDag-Erling Smørgrav static const char *
fmt_intarg(OpCodes code,int val)3406bc5531deSDag-Erling Smørgrav fmt_intarg(OpCodes code, int val)
3407bc5531deSDag-Erling Smørgrav {
3408bc5531deSDag-Erling Smørgrav if (val == -1)
3409bc5531deSDag-Erling Smørgrav return "unset";
3410bc5531deSDag-Erling Smørgrav switch (code) {
3411bc5531deSDag-Erling Smørgrav case oAddressFamily:
3412bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_addressfamily);
3413bc5531deSDag-Erling Smørgrav case oVerifyHostKeyDNS:
3414bc5531deSDag-Erling Smørgrav case oUpdateHostkeys:
3415bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_yesnoask);
34164f52dfbbSDag-Erling Smørgrav case oStrictHostKeyChecking:
34174f52dfbbSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_strict_hostkey);
3418bc5531deSDag-Erling Smørgrav case oControlMaster:
3419bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_controlmaster);
3420bc5531deSDag-Erling Smørgrav case oTunnel:
3421bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_tunnel);
3422bc5531deSDag-Erling Smørgrav case oRequestTTY:
3423bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_requesttty);
342419261079SEd Maste case oSessionType:
342519261079SEd Maste return fmt_multistate_int(val, multistate_sessiontype);
3426bc5531deSDag-Erling Smørgrav case oCanonicalizeHostname:
3427bc5531deSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_canonicalizehostname);
3428190cef3dSDag-Erling Smørgrav case oAddKeysToAgent:
3429190cef3dSDag-Erling Smørgrav return fmt_multistate_int(val, multistate_yesnoaskconfirm);
34301323ec57SEd Maste case oPubkeyAuthentication:
34311323ec57SEd Maste return fmt_multistate_int(val, multistate_pubkey_auth);
3432bc5531deSDag-Erling Smørgrav case oFingerprintHash:
3433bc5531deSDag-Erling Smørgrav return ssh_digest_alg_name(val);
3434bc5531deSDag-Erling Smørgrav default:
3435bc5531deSDag-Erling Smørgrav switch (val) {
3436bc5531deSDag-Erling Smørgrav case 0:
3437bc5531deSDag-Erling Smørgrav return "no";
3438bc5531deSDag-Erling Smørgrav case 1:
3439bc5531deSDag-Erling Smørgrav return "yes";
3440bc5531deSDag-Erling Smørgrav default:
3441bc5531deSDag-Erling Smørgrav return "UNKNOWN";
3442bc5531deSDag-Erling Smørgrav }
3443bc5531deSDag-Erling Smørgrav }
3444bc5531deSDag-Erling Smørgrav }
3445bc5531deSDag-Erling Smørgrav
3446bc5531deSDag-Erling Smørgrav static const char *
lookup_opcode_name(OpCodes code)3447bc5531deSDag-Erling Smørgrav lookup_opcode_name(OpCodes code)
3448bc5531deSDag-Erling Smørgrav {
3449bc5531deSDag-Erling Smørgrav u_int i;
3450bc5531deSDag-Erling Smørgrav
3451bc5531deSDag-Erling Smørgrav for (i = 0; keywords[i].name != NULL; i++)
3452bc5531deSDag-Erling Smørgrav if (keywords[i].opcode == code)
3453bc5531deSDag-Erling Smørgrav return(keywords[i].name);
3454bc5531deSDag-Erling Smørgrav return "UNKNOWN";
3455bc5531deSDag-Erling Smørgrav }
3456bc5531deSDag-Erling Smørgrav
3457bc5531deSDag-Erling Smørgrav static void
dump_cfg_int(OpCodes code,int val)3458bc5531deSDag-Erling Smørgrav dump_cfg_int(OpCodes code, int val)
3459bc5531deSDag-Erling Smørgrav {
3460edf85781SEd Maste if (code == oObscureKeystrokeTiming) {
3461edf85781SEd Maste if (val == 0) {
3462edf85781SEd Maste printf("%s no\n", lookup_opcode_name(code));
3463edf85781SEd Maste return;
3464edf85781SEd Maste } else if (val == SSH_KEYSTROKE_DEFAULT_INTERVAL_MS) {
3465edf85781SEd Maste printf("%s yes\n", lookup_opcode_name(code));
3466edf85781SEd Maste return;
3467edf85781SEd Maste }
3468edf85781SEd Maste /* FALLTHROUGH */
3469edf85781SEd Maste }
3470bc5531deSDag-Erling Smørgrav printf("%s %d\n", lookup_opcode_name(code), val);
3471bc5531deSDag-Erling Smørgrav }
3472bc5531deSDag-Erling Smørgrav
3473bc5531deSDag-Erling Smørgrav static void
dump_cfg_fmtint(OpCodes code,int val)3474bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(OpCodes code, int val)
3475bc5531deSDag-Erling Smørgrav {
3476bc5531deSDag-Erling Smørgrav printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
3477bc5531deSDag-Erling Smørgrav }
3478bc5531deSDag-Erling Smørgrav
3479bc5531deSDag-Erling Smørgrav static void
dump_cfg_string(OpCodes code,const char * val)3480bc5531deSDag-Erling Smørgrav dump_cfg_string(OpCodes code, const char *val)
3481bc5531deSDag-Erling Smørgrav {
3482bc5531deSDag-Erling Smørgrav if (val == NULL)
3483bc5531deSDag-Erling Smørgrav return;
3484bc5531deSDag-Erling Smørgrav printf("%s %s\n", lookup_opcode_name(code), val);
3485bc5531deSDag-Erling Smørgrav }
3486bc5531deSDag-Erling Smørgrav
3487bc5531deSDag-Erling Smørgrav static void
dump_cfg_strarray(OpCodes code,u_int count,char ** vals)3488bc5531deSDag-Erling Smørgrav dump_cfg_strarray(OpCodes code, u_int count, char **vals)
3489bc5531deSDag-Erling Smørgrav {
3490bc5531deSDag-Erling Smørgrav u_int i;
3491bc5531deSDag-Erling Smørgrav
3492bc5531deSDag-Erling Smørgrav for (i = 0; i < count; i++)
3493bc5531deSDag-Erling Smørgrav printf("%s %s\n", lookup_opcode_name(code), vals[i]);
3494bc5531deSDag-Erling Smørgrav }
3495bc5531deSDag-Erling Smørgrav
3496bc5531deSDag-Erling Smørgrav static void
dump_cfg_strarray_oneline(OpCodes code,u_int count,char ** vals)3497bc5531deSDag-Erling Smørgrav dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
3498bc5531deSDag-Erling Smørgrav {
3499bc5531deSDag-Erling Smørgrav u_int i;
3500bc5531deSDag-Erling Smørgrav
3501bc5531deSDag-Erling Smørgrav printf("%s", lookup_opcode_name(code));
350219261079SEd Maste if (count == 0)
350319261079SEd Maste printf(" none");
3504bc5531deSDag-Erling Smørgrav for (i = 0; i < count; i++)
3505bc5531deSDag-Erling Smørgrav printf(" %s", vals[i]);
3506bc5531deSDag-Erling Smørgrav printf("\n");
3507bc5531deSDag-Erling Smørgrav }
3508bc5531deSDag-Erling Smørgrav
3509bc5531deSDag-Erling Smørgrav static void
dump_cfg_forwards(OpCodes code,u_int count,const struct Forward * fwds)3510bc5531deSDag-Erling Smørgrav dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
3511bc5531deSDag-Erling Smørgrav {
3512bc5531deSDag-Erling Smørgrav const struct Forward *fwd;
3513bc5531deSDag-Erling Smørgrav u_int i;
3514bc5531deSDag-Erling Smørgrav
3515bc5531deSDag-Erling Smørgrav /* oDynamicForward */
3516bc5531deSDag-Erling Smørgrav for (i = 0; i < count; i++) {
3517bc5531deSDag-Erling Smørgrav fwd = &fwds[i];
3518d93a896eSDag-Erling Smørgrav if (code == oDynamicForward && fwd->connect_host != NULL &&
3519bc5531deSDag-Erling Smørgrav strcmp(fwd->connect_host, "socks") != 0)
3520bc5531deSDag-Erling Smørgrav continue;
3521d93a896eSDag-Erling Smørgrav if (code == oLocalForward && fwd->connect_host != NULL &&
3522bc5531deSDag-Erling Smørgrav strcmp(fwd->connect_host, "socks") == 0)
3523bc5531deSDag-Erling Smørgrav continue;
3524bc5531deSDag-Erling Smørgrav printf("%s", lookup_opcode_name(code));
3525bc5531deSDag-Erling Smørgrav if (fwd->listen_port == PORT_STREAMLOCAL)
3526bc5531deSDag-Erling Smørgrav printf(" %s", fwd->listen_path);
3527bc5531deSDag-Erling Smørgrav else if (fwd->listen_host == NULL)
3528bc5531deSDag-Erling Smørgrav printf(" %d", fwd->listen_port);
3529bc5531deSDag-Erling Smørgrav else {
3530bc5531deSDag-Erling Smørgrav printf(" [%s]:%d",
3531bc5531deSDag-Erling Smørgrav fwd->listen_host, fwd->listen_port);
3532bc5531deSDag-Erling Smørgrav }
3533bc5531deSDag-Erling Smørgrav if (code != oDynamicForward) {
3534bc5531deSDag-Erling Smørgrav if (fwd->connect_port == PORT_STREAMLOCAL)
3535bc5531deSDag-Erling Smørgrav printf(" %s", fwd->connect_path);
3536bc5531deSDag-Erling Smørgrav else if (fwd->connect_host == NULL)
3537bc5531deSDag-Erling Smørgrav printf(" %d", fwd->connect_port);
3538bc5531deSDag-Erling Smørgrav else {
3539bc5531deSDag-Erling Smørgrav printf(" [%s]:%d",
3540bc5531deSDag-Erling Smørgrav fwd->connect_host, fwd->connect_port);
3541bc5531deSDag-Erling Smørgrav }
3542bc5531deSDag-Erling Smørgrav }
3543bc5531deSDag-Erling Smørgrav printf("\n");
3544bc5531deSDag-Erling Smørgrav }
3545bc5531deSDag-Erling Smørgrav }
3546bc5531deSDag-Erling Smørgrav
3547bc5531deSDag-Erling Smørgrav void
dump_client_config(Options * o,const char * host)3548bc5531deSDag-Erling Smørgrav dump_client_config(Options *o, const char *host)
3549bc5531deSDag-Erling Smørgrav {
355019261079SEd Maste int i, r;
3551190cef3dSDag-Erling Smørgrav char buf[8], *all_key;
3552bc5531deSDag-Erling Smørgrav
355319261079SEd Maste /*
355419261079SEd Maste * Expand HostKeyAlgorithms name lists. This isn't handled in
355519261079SEd Maste * fill_default_options() like the other algorithm lists because
355619261079SEd Maste * the host key algorithms are by default dynamically chosen based
355719261079SEd Maste * on the host's keys found in known_hosts.
355819261079SEd Maste */
3559190cef3dSDag-Erling Smørgrav all_key = sshkey_alg_list(0, 0, 1, ',');
356019261079SEd Maste if ((r = kex_assemble_names(&o->hostkeyalgorithms, kex_default_pk_alg(),
356119261079SEd Maste all_key)) != 0)
356219261079SEd Maste fatal_fr(r, "expand HostKeyAlgorithms");
3563190cef3dSDag-Erling Smørgrav free(all_key);
3564acc1a9efSDag-Erling Smørgrav
3565bc5531deSDag-Erling Smørgrav /* Most interesting options first: user, host, port */
3566f374ba41SEd Maste dump_cfg_string(oHost, o->host_arg);
3567bc5531deSDag-Erling Smørgrav dump_cfg_string(oUser, o->user);
356819261079SEd Maste dump_cfg_string(oHostname, host);
3569bc5531deSDag-Erling Smørgrav dump_cfg_int(oPort, o->port);
3570bc5531deSDag-Erling Smørgrav
3571bc5531deSDag-Erling Smørgrav /* Flag options */
3572bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oAddressFamily, o->address_family);
3573bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oBatchMode, o->batch_mode);
3574bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
3575bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
3576bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
3577bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oCompression, o->compression);
3578bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oControlMaster, o->control_master);
3579bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
3580076ad2f8SDag-Erling Smørgrav dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
3581bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
3582bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
3583bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oForwardX11, o->forward_x11);
3584bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
3585bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
3586bc5531deSDag-Erling Smørgrav #ifdef GSSAPI
3587bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
3588bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
3589bc5531deSDag-Erling Smørgrav #endif /* GSSAPI */
3590bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
3591bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
3592bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
3593bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
3594bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
3595bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
3596bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
3597bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
3598bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
3599bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oRequestTTY, o->request_tty);
360019261079SEd Maste dump_cfg_fmtint(oSessionType, o->session_type);
360119261079SEd Maste dump_cfg_fmtint(oStdinNull, o->stdin_null);
360219261079SEd Maste dump_cfg_fmtint(oForkAfterAuthentication, o->fork_after_authentication);
3603bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
3604bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
3605bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
3606bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oTunnel, o->tun_open);
3607bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
3608bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
3609bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
3610f374ba41SEd Maste dump_cfg_fmtint(oEnableEscapeCommandline, o->enable_escape_commandline);
3611bc5531deSDag-Erling Smørgrav
3612bc5531deSDag-Erling Smørgrav /* Integer options */
3613bc5531deSDag-Erling Smørgrav dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
3614bc5531deSDag-Erling Smørgrav dump_cfg_int(oConnectionAttempts, o->connection_attempts);
3615bc5531deSDag-Erling Smørgrav dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
3616bc5531deSDag-Erling Smørgrav dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
3617bc5531deSDag-Erling Smørgrav dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
3618bc5531deSDag-Erling Smørgrav dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
361938a52bd3SEd Maste dump_cfg_int(oRequiredRSASize, o->required_rsa_size);
3620edf85781SEd Maste dump_cfg_int(oObscureKeystrokeTiming,
3621edf85781SEd Maste o->obscure_keystroke_timing_interval);
3622bc5531deSDag-Erling Smørgrav
3623bc5531deSDag-Erling Smørgrav /* String options */
3624bc5531deSDag-Erling Smørgrav dump_cfg_string(oBindAddress, o->bind_address);
362547dd1d1bSDag-Erling Smørgrav dump_cfg_string(oBindInterface, o->bind_interface);
362619261079SEd Maste dump_cfg_string(oCiphers, o->ciphers);
3627bc5531deSDag-Erling Smørgrav dump_cfg_string(oControlPath, o->control_path);
3628acc1a9efSDag-Erling Smørgrav dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
3629bc5531deSDag-Erling Smørgrav dump_cfg_string(oHostKeyAlias, o->host_key_alias);
363019261079SEd Maste dump_cfg_string(oHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
3631076ad2f8SDag-Erling Smørgrav dump_cfg_string(oIdentityAgent, o->identity_agent);
3632190cef3dSDag-Erling Smørgrav dump_cfg_string(oIgnoreUnknown, o->ignored_unknown);
3633bc5531deSDag-Erling Smørgrav dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
363419261079SEd Maste dump_cfg_string(oKexAlgorithms, o->kex_algorithms);
363519261079SEd Maste dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms);
3636bc5531deSDag-Erling Smørgrav dump_cfg_string(oLocalCommand, o->local_command);
36374f52dfbbSDag-Erling Smørgrav dump_cfg_string(oRemoteCommand, o->remote_command);
3638bc5531deSDag-Erling Smørgrav dump_cfg_string(oLogLevel, log_level_name(o->log_level));
363919261079SEd Maste dump_cfg_string(oMacs, o->macs);
3640d93a896eSDag-Erling Smørgrav #ifdef ENABLE_PKCS11
3641bc5531deSDag-Erling Smørgrav dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
3642d93a896eSDag-Erling Smørgrav #endif
364319261079SEd Maste dump_cfg_string(oSecurityKeyProvider, o->sk_provider);
3644bc5531deSDag-Erling Smørgrav dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
364519261079SEd Maste dump_cfg_string(oPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
3646bc5531deSDag-Erling Smørgrav dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
3647bc5531deSDag-Erling Smørgrav dump_cfg_string(oXAuthLocation, o->xauth_location);
364819261079SEd Maste dump_cfg_string(oKnownHostsCommand, o->known_hosts_command);
3649535af610SEd Maste dump_cfg_string(oTag, o->tag);
3650bc5531deSDag-Erling Smørgrav
3651bc5531deSDag-Erling Smørgrav /* Forwards */
3652bc5531deSDag-Erling Smørgrav dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
3653bc5531deSDag-Erling Smørgrav dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
3654bc5531deSDag-Erling Smørgrav dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
3655bc5531deSDag-Erling Smørgrav
3656bc5531deSDag-Erling Smørgrav /* String array options */
3657bc5531deSDag-Erling Smørgrav dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
3658bc5531deSDag-Erling Smørgrav dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
3659190cef3dSDag-Erling Smørgrav dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files);
3660bc5531deSDag-Erling Smørgrav dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
3661bc5531deSDag-Erling Smørgrav dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
3662bc5531deSDag-Erling Smørgrav dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
3663190cef3dSDag-Erling Smørgrav dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
366419261079SEd Maste dump_cfg_strarray_oneline(oLogVerbose,
366519261079SEd Maste o->num_log_verbose, o->log_verbose);
3666069ac184SEd Maste dump_cfg_strarray_oneline(oChannelTimeout,
3667069ac184SEd Maste o->num_channel_timeouts, o->channel_timeouts);
3668bc5531deSDag-Erling Smørgrav
3669bc5531deSDag-Erling Smørgrav /* Special cases */
3670bc5531deSDag-Erling Smørgrav
367119261079SEd Maste /* PermitRemoteOpen */
367219261079SEd Maste if (o->num_permitted_remote_opens == 0)
367319261079SEd Maste printf("%s any\n", lookup_opcode_name(oPermitRemoteOpen));
367419261079SEd Maste else
367519261079SEd Maste dump_cfg_strarray_oneline(oPermitRemoteOpen,
367619261079SEd Maste o->num_permitted_remote_opens, o->permitted_remote_opens);
367719261079SEd Maste
367819261079SEd Maste /* AddKeysToAgent */
367919261079SEd Maste if (o->add_keys_to_agent_lifespan <= 0)
368019261079SEd Maste dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent);
368119261079SEd Maste else {
368219261079SEd Maste printf("addkeystoagent%s %d\n",
368319261079SEd Maste o->add_keys_to_agent == 3 ? " confirm" : "",
368419261079SEd Maste o->add_keys_to_agent_lifespan);
368519261079SEd Maste }
368619261079SEd Maste
368719261079SEd Maste /* oForwardAgent */
368819261079SEd Maste if (o->forward_agent_sock_path == NULL)
368919261079SEd Maste dump_cfg_fmtint(oForwardAgent, o->forward_agent);
369019261079SEd Maste else
369119261079SEd Maste dump_cfg_string(oForwardAgent, o->forward_agent_sock_path);
369219261079SEd Maste
3693bc5531deSDag-Erling Smørgrav /* oConnectTimeout */
3694bc5531deSDag-Erling Smørgrav if (o->connection_timeout == -1)
3695bc5531deSDag-Erling Smørgrav printf("connecttimeout none\n");
3696bc5531deSDag-Erling Smørgrav else
3697bc5531deSDag-Erling Smørgrav dump_cfg_int(oConnectTimeout, o->connection_timeout);
3698bc5531deSDag-Erling Smørgrav
3699bc5531deSDag-Erling Smørgrav /* oTunnelDevice */
3700bc5531deSDag-Erling Smørgrav printf("tunneldevice");
3701bc5531deSDag-Erling Smørgrav if (o->tun_local == SSH_TUNID_ANY)
3702bc5531deSDag-Erling Smørgrav printf(" any");
3703bc5531deSDag-Erling Smørgrav else
3704bc5531deSDag-Erling Smørgrav printf(" %d", o->tun_local);
3705bc5531deSDag-Erling Smørgrav if (o->tun_remote == SSH_TUNID_ANY)
3706bc5531deSDag-Erling Smørgrav printf(":any");
3707bc5531deSDag-Erling Smørgrav else
3708bc5531deSDag-Erling Smørgrav printf(":%d", o->tun_remote);
3709bc5531deSDag-Erling Smørgrav printf("\n");
3710bc5531deSDag-Erling Smørgrav
3711bc5531deSDag-Erling Smørgrav /* oCanonicalizePermittedCNAMEs */
3712bc5531deSDag-Erling Smørgrav printf("canonicalizePermittedcnames");
3713e9e8876aSEd Maste if (o->num_permitted_cnames == 0)
3714e9e8876aSEd Maste printf(" none");
3715bc5531deSDag-Erling Smørgrav for (i = 0; i < o->num_permitted_cnames; i++) {
3716bc5531deSDag-Erling Smørgrav printf(" %s:%s", o->permitted_cnames[i].source_list,
3717bc5531deSDag-Erling Smørgrav o->permitted_cnames[i].target_list);
3718bc5531deSDag-Erling Smørgrav }
3719bc5531deSDag-Erling Smørgrav printf("\n");
3720bc5531deSDag-Erling Smørgrav
3721bc5531deSDag-Erling Smørgrav /* oControlPersist */
3722bc5531deSDag-Erling Smørgrav if (o->control_persist == 0 || o->control_persist_timeout == 0)
3723bc5531deSDag-Erling Smørgrav dump_cfg_fmtint(oControlPersist, o->control_persist);
3724bc5531deSDag-Erling Smørgrav else
3725bc5531deSDag-Erling Smørgrav dump_cfg_int(oControlPersist, o->control_persist_timeout);
3726bc5531deSDag-Erling Smørgrav
3727bc5531deSDag-Erling Smørgrav /* oEscapeChar */
3728bc5531deSDag-Erling Smørgrav if (o->escape_char == SSH_ESCAPECHAR_NONE)
3729bc5531deSDag-Erling Smørgrav printf("escapechar none\n");
3730bc5531deSDag-Erling Smørgrav else {
3731076ad2f8SDag-Erling Smørgrav vis(buf, o->escape_char, VIS_WHITE, 0);
3732076ad2f8SDag-Erling Smørgrav printf("escapechar %s\n", buf);
3733bc5531deSDag-Erling Smørgrav }
3734bc5531deSDag-Erling Smørgrav
3735bc5531deSDag-Erling Smørgrav /* oIPQoS */
3736bc5531deSDag-Erling Smørgrav printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
3737bc5531deSDag-Erling Smørgrav printf("%s\n", iptos2str(o->ip_qos_bulk));
3738bc5531deSDag-Erling Smørgrav
3739bc5531deSDag-Erling Smørgrav /* oRekeyLimit */
3740acc1a9efSDag-Erling Smørgrav printf("rekeylimit %llu %d\n",
3741acc1a9efSDag-Erling Smørgrav (unsigned long long)o->rekey_limit, o->rekey_interval);
3742bc5531deSDag-Erling Smørgrav
3743bc5531deSDag-Erling Smørgrav /* oStreamLocalBindMask */
3744bc5531deSDag-Erling Smørgrav printf("streamlocalbindmask 0%o\n",
3745bc5531deSDag-Erling Smørgrav o->fwd_opts.streamlocal_bind_mask);
3746076ad2f8SDag-Erling Smørgrav
3747190cef3dSDag-Erling Smørgrav /* oLogFacility */
3748190cef3dSDag-Erling Smørgrav printf("syslogfacility %s\n", log_facility_name(o->log_facility));
3749190cef3dSDag-Erling Smørgrav
3750076ad2f8SDag-Erling Smørgrav /* oProxyCommand / oProxyJump */
3751076ad2f8SDag-Erling Smørgrav if (o->jump_host == NULL)
3752076ad2f8SDag-Erling Smørgrav dump_cfg_string(oProxyCommand, o->proxy_command);
3753076ad2f8SDag-Erling Smørgrav else {
3754076ad2f8SDag-Erling Smørgrav /* Check for numeric addresses */
3755076ad2f8SDag-Erling Smørgrav i = strchr(o->jump_host, ':') != NULL ||
3756076ad2f8SDag-Erling Smørgrav strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
3757076ad2f8SDag-Erling Smørgrav snprintf(buf, sizeof(buf), "%d", o->jump_port);
3758076ad2f8SDag-Erling Smørgrav printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
3759076ad2f8SDag-Erling Smørgrav /* optional additional jump spec */
3760076ad2f8SDag-Erling Smørgrav o->jump_extra == NULL ? "" : o->jump_extra,
3761076ad2f8SDag-Erling Smørgrav o->jump_extra == NULL ? "" : ",",
3762076ad2f8SDag-Erling Smørgrav /* optional user */
3763076ad2f8SDag-Erling Smørgrav o->jump_user == NULL ? "" : o->jump_user,
3764076ad2f8SDag-Erling Smørgrav o->jump_user == NULL ? "" : "@",
3765076ad2f8SDag-Erling Smørgrav /* opening [ if hostname is numeric */
3766076ad2f8SDag-Erling Smørgrav i ? "[" : "",
3767076ad2f8SDag-Erling Smørgrav /* mandatory hostname */
3768076ad2f8SDag-Erling Smørgrav o->jump_host,
3769076ad2f8SDag-Erling Smørgrav /* closing ] if hostname is numeric */
3770076ad2f8SDag-Erling Smørgrav i ? "]" : "",
3771076ad2f8SDag-Erling Smørgrav /* optional port number */
3772076ad2f8SDag-Erling Smørgrav o->jump_port <= 0 ? "" : ":",
3773076ad2f8SDag-Erling Smørgrav o->jump_port <= 0 ? "" : buf);
3774076ad2f8SDag-Erling Smørgrav }
3775bc5531deSDag-Erling Smørgrav }
3776