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