freebsd-src/crypto/openssh/readconf.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

3724 lines
104 KiB
C
Raw Normal View History

2024-03-17 17:47:10 +00:00
/* $OpenBSD: readconf.c,v 1.386 2024/03/04 04:13:18 djm Exp $ */
2000-02-24 14:29:47 +00:00
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Functions for reading the configuration files.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
2000-02-24 14:29:47 +00:00
*/
#include "includes.h"
2006-09-30 13:38:06 +00:00
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
2014-01-30 10:56:49 +00:00
#include <sys/wait.h>
2015-01-05 16:09:55 +00:00
#include <sys/un.h>
2006-09-30 13:38:06 +00:00
2023-08-10 16:16:53 +00:00
#include <net/if.h>
2006-09-30 13:38:06 +00:00
#include <netinet/in.h>
2011-02-17 11:47:40 +00:00
#include <netinet/in_systm.h>
#include <netinet/ip.h>
2014-03-22 15:23:38 +00:00
#include <arpa/inet.h>
2006-09-30 13:38:06 +00:00
#include <ctype.h>
#include <errno.h>
2014-01-30 10:56:49 +00:00
#include <fcntl.h>
2023-08-10 16:16:53 +00:00
#ifdef HAVE_IFADDRS_H
# include <ifaddrs.h>
#endif
2015-07-02 13:15:34 +00:00
#include <limits.h>
2006-09-30 13:38:06 +00:00
#include <netdb.h>
2014-01-30 10:56:49 +00:00
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
#include <pwd.h>
2006-09-30 13:38:06 +00:00
#include <signal.h>
#include <stdio.h>
#include <string.h>
2021-02-14 21:04:52 +00:00
#include <stdarg.h>
2006-09-30 13:38:06 +00:00
#include <unistd.h>
2017-01-31 12:29:48 +00:00
#ifdef USE_SYSTEM_GLOB
# include <glob.h>
#else
# include "openbsd-compat/glob.h"
#endif
2013-09-18 17:27:38 +00:00
#ifdef HAVE_UTIL_H
#include <util.h>
#endif
2015-07-02 13:15:34 +00:00
#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
# include <vis.h>
#endif
2000-02-24 14:29:47 +00:00
#include "xmalloc.h"
2006-09-30 13:38:06 +00:00
#include "ssh.h"
2018-08-28 10:47:58 +00:00
#include "ssherr.h"
2001-05-04 04:14:23 +00:00
#include "cipher.h"
#include "pathnames.h"
#include "log.h"
2015-07-02 13:15:34 +00:00
#include "sshkey.h"
2015-01-05 16:09:55 +00:00
#include "misc.h"
2001-05-04 04:14:23 +00:00
#include "readconf.h"
#include "match.h"
#include "kex.h"
#include "mac.h"
2014-01-30 10:56:49 +00:00
#include "uidswap.h"
2015-07-02 13:15:34 +00:00
#include "myproposal.h"
#include "digest.h"
2000-02-24 14:29:47 +00:00
/* Format of the configuration file:
# Configuration data is parsed as follows:
# 1. command line options
# 2. user-specific file
# 3. system-wide file
# Any configuration value is only changed the first time it is set.
# Thus, host-specific definitions should be at the beginning of the
# configuration file, and defaults at the end.
# Host-specific declarations. These may override anything above. A single
# host may match multiple declarations; these are processed in the order
# that they are given in.
Host *.ngs.fi ngs.fi
User foo
2000-02-24 14:29:47 +00:00
Host fake.com
2021-02-14 21:00:25 +00:00
Hostname another.host.name.real.org
2000-02-24 14:29:47 +00:00
User blaah
Port 34289
ForwardX11 no
ForwardAgent no
Host books.com
RemoteForward 9999 shadows.cs.hut.fi:9999
2017-08-03 10:10:20 +00:00
Ciphers 3des-cbc
2000-02-24 14:29:47 +00:00
Host fascist.blob.com
Port 23123
User tylonen
PasswordAuthentication no
Host puukko.hut.fi
User t35124p
ProxyCommand ssh-proxy %h %p
Host *.fr
PublicKeyAuthentication no
2000-02-24 14:29:47 +00:00
Host *.su
2017-08-03 10:10:20 +00:00
Ciphers aes128-ctr
2000-02-24 14:29:47 +00:00
PasswordAuthentication no
2006-03-22 20:41:37 +00:00
Host vpn.fake.com
Tunnel yes
TunnelDevice 3
2000-02-24 14:29:47 +00:00
# Defaults for various options
Host *
ForwardAgent no
2001-05-04 04:14:23 +00:00
ForwardX11 no
2000-02-24 14:29:47 +00:00
PasswordAuthentication yes
StrictHostKeyChecking yes
2004-02-26 10:52:33 +00:00
TcpKeepAlive no
2000-02-24 14:29:47 +00:00
IdentityFile ~/.ssh/identity
Port 22
EscapeChar ~
*/
2017-01-31 12:29:48 +00:00
static int read_config_file_depth(const char *filename, struct passwd *pw,
const char *host, const char *original_host, Options *options,
2020-02-14 19:47:15 +00:00
int flags, int *activep, int *want_final_pass, int depth);
2017-01-31 12:29:48 +00:00
static int process_config_line_depth(Options *options, struct passwd *pw,
const char *host, const char *original_host, char *line,
2020-02-14 19:47:15 +00:00
const char *filename, int linenum, int *activep, int flags,
int *want_final_pass, int depth);
2017-01-31 12:29:48 +00:00
2000-02-24 14:29:47 +00:00
/* Keyword tokens. */
typedef enum {
oBadOption,
2023-08-10 16:16:53 +00:00
oHost, oMatch, oInclude, oTag,
2010-11-08 10:45:44 +00:00
oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
oGatewayPorts, oExitOnForwardFailure,
2021-02-14 21:04:52 +00:00
oPasswordAuthentication,
2021-08-30 19:14:33 +00:00
oXAuthLocation,
2021-02-14 21:04:52 +00:00
oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward,
2021-04-23 19:10:38 +00:00
oPermitRemoteOpen,
2017-01-31 12:29:48 +00:00
oCertificateFile, oAddKeysToAgent, oIdentityAgent,
2021-02-14 21:04:52 +00:00
oUser, oEscapeChar, oProxyCommand,
2000-02-24 14:29:47 +00:00
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
2021-02-14 21:04:52 +00:00
oTCPKeepAlive, oNumberOfPasswordPrompts,
2021-04-23 19:10:38 +00:00
oLogFacility, oLogLevel, oLogVerbose, oCiphers, oMacs,
2015-07-02 13:15:34 +00:00
oPubkeyAuthentication,
2001-05-04 04:14:23 +00:00
oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
2018-05-06 12:27:04 +00:00
oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider,
oClearAllForwardings, oNoHostAuthenticationForLocalhost,
oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
oAddressFamily, oGssAuthentication, oGssDelegateCreds,
2004-04-20 09:46:41 +00:00
oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
2018-08-28 10:47:58 +00:00
oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
2010-11-08 10:45:44 +00:00
oHashKnownHosts,
2018-05-06 12:24:45 +00:00
oTunnel, oTunnelDevice,
oLocalCommand, oPermitLocalCommand, oRemoteCommand,
2016-03-10 20:10:25 +00:00
oVisualHostKey,
2021-08-30 19:14:33 +00:00
oKexAlgorithms, oIPQoS, oRequestTTY, oSessionType, oStdinNull,
oForkAfterAuthentication, oIgnoreUnknown, oProxyUseFdpass,
2014-01-30 10:56:49 +00:00
oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
2015-07-02 13:15:34 +00:00
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
2021-04-23 19:10:38 +00:00
oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
2022-10-04 15:10:40 +00:00
oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize,
2023-12-18 15:59:40 +00:00
oEnableEscapeCommandline, oObscureKeystrokeTiming, oChannelTimeout,
2018-05-06 12:24:45 +00:00
oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
2000-02-24 14:29:47 +00:00
} OpCodes;
/* Textual representations of the tokens. */
static struct {
const char *name;
OpCodes opcode;
} keywords[] = {
2017-08-03 10:10:20 +00:00
/* Deprecated options */
2018-05-06 12:24:45 +00:00
{ "protocol", oIgnore }, /* NB. silently ignored */
{ "cipher", oDeprecated },
2017-08-03 10:10:20 +00:00
{ "fallbacktorsh", oDeprecated },
{ "globalknownhostsfile2", oDeprecated },
{ "rhostsauthentication", oDeprecated },
{ "userknownhostsfile2", oDeprecated },
{ "useroaming", oDeprecated },
{ "usersh", oDeprecated },
2018-08-28 10:47:58 +00:00
{ "useprivilegedport", oDeprecated },
2017-08-03 10:10:20 +00:00
/* Unsupported options */
{ "afstokenpassing", oUnsupported },
{ "kerberosauthentication", oUnsupported },
{ "kerberostgtpassing", oUnsupported },
2021-02-14 21:04:52 +00:00
{ "rsaauthentication", oUnsupported },
{ "rhostsrsaauthentication", oUnsupported },
{ "compressionlevel", oUnsupported },
2017-08-03 10:10:20 +00:00
/* Sometimes-unsupported options */
#if defined(GSSAPI)
{ "gssapiauthentication", oGssAuthentication },
{ "gssapidelegatecredentials", oGssDelegateCreds },
# else
{ "gssapiauthentication", oUnsupported },
{ "gssapidelegatecredentials", oUnsupported },
#endif
#ifdef ENABLE_PKCS11
{ "pkcs11provider", oPKCS11Provider },
2020-02-14 19:47:15 +00:00
{ "smartcarddevice", oPKCS11Provider },
2017-08-03 10:10:20 +00:00
# else
{ "smartcarddevice", oUnsupported },
{ "pkcs11provider", oUnsupported },
#endif
2000-02-24 14:29:47 +00:00
{ "forwardagent", oForwardAgent },
{ "forwardx11", oForwardX11 },
2004-02-26 10:52:33 +00:00
{ "forwardx11trusted", oForwardX11Trusted },
2010-11-08 10:45:44 +00:00
{ "forwardx11timeout", oForwardX11Timeout },
2006-09-30 13:38:06 +00:00
{ "exitonforwardfailure", oExitOnForwardFailure },
{ "xauthlocation", oXAuthLocation },
2000-02-24 14:29:47 +00:00
{ "gatewayports", oGatewayPorts },
{ "passwordauthentication", oPasswordAuthentication },
{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
{ "kbdinteractivedevices", oKbdInteractiveDevices },
2021-08-30 19:14:33 +00:00
{ "challengeresponseauthentication", oKbdInteractiveAuthentication }, /* alias */
{ "skeyauthentication", oKbdInteractiveAuthentication }, /* alias */
{ "tisauthentication", oKbdInteractiveAuthentication }, /* alias */
2001-05-04 04:14:23 +00:00
{ "pubkeyauthentication", oPubkeyAuthentication },
{ "dsaauthentication", oPubkeyAuthentication }, /* alias */
{ "hostbasedauthentication", oHostbasedAuthentication },
2000-02-24 14:29:47 +00:00
{ "identityfile", oIdentityFile },
2009-02-24 18:49:27 +00:00
{ "identityfile2", oIdentityFile }, /* obsolete */
2004-04-20 09:46:41 +00:00
{ "identitiesonly", oIdentitiesOnly },
2016-03-10 20:10:25 +00:00
{ "certificatefile", oCertificateFile },
{ "addkeystoagent", oAddKeysToAgent },
2017-01-31 12:29:48 +00:00
{ "identityagent", oIdentityAgent },
2021-02-14 21:00:25 +00:00
{ "hostname", oHostname },
2001-05-04 04:14:23 +00:00
{ "hostkeyalias", oHostKeyAlias },
2000-02-24 14:29:47 +00:00
{ "proxycommand", oProxyCommand },
{ "port", oPort },
{ "ciphers", oCiphers },
2001-05-04 04:14:23 +00:00
{ "macs", oMacs },
2000-02-24 14:29:47 +00:00
{ "remoteforward", oRemoteForward },
{ "localforward", oLocalForward },
2021-04-23 19:10:38 +00:00
{ "permitremoteopen", oPermitRemoteOpen },
2000-02-24 14:29:47 +00:00
{ "user", oUser },
{ "host", oHost },
2014-01-30 10:56:49 +00:00
{ "match", oMatch },
2023-08-10 16:16:53 +00:00
{ "tag", oTag },
2000-02-24 14:29:47 +00:00
{ "escapechar", oEscapeChar },
{ "globalknownhostsfile", oGlobalKnownHostsFile },
2009-02-24 18:49:27 +00:00
{ "userknownhostsfile", oUserKnownHostsFile },
2000-02-24 14:29:47 +00:00
{ "connectionattempts", oConnectionAttempts },
{ "batchmode", oBatchMode },
{ "checkhostip", oCheckHostIP },
{ "stricthostkeychecking", oStrictHostKeyChecking },
{ "compression", oCompression },
2004-02-26 10:52:33 +00:00
{ "tcpkeepalive", oTCPKeepAlive },
{ "keepalive", oTCPKeepAlive }, /* obsolete */
2000-02-24 14:29:47 +00:00
{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
2018-05-06 12:24:45 +00:00
{ "syslogfacility", oLogFacility },
2000-02-24 14:29:47 +00:00
{ "loglevel", oLogLevel },
2021-04-23 19:10:38 +00:00
{ "logverbose", oLogVerbose },
2001-05-04 04:14:23 +00:00
{ "dynamicforward", oDynamicForward },
{ "preferredauthentications", oPreferredAuthentications },
{ "hostkeyalgorithms", oHostKeyAlgorithms },
2019-02-05 15:03:53 +00:00
{ "casignaturealgorithms", oCASignatureAlgorithms },
2002-03-18 10:09:43 +00:00
{ "bindaddress", oBindAddress },
2018-05-06 12:27:04 +00:00
{ "bindinterface", oBindInterface },
2002-03-18 10:09:43 +00:00
{ "clearallforwardings", oClearAllForwardings },
2003-04-23 17:13:13 +00:00
{ "enablesshkeysign", oEnableSSHKeysign },
{ "verifyhostkeydns", oVerifyHostKeyDNS },
2002-03-18 10:09:43 +00:00
{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
{ "rekeylimit", oRekeyLimit },
{ "connecttimeout", oConnectTimeout },
{ "addressfamily", oAddressFamily },
2004-02-26 10:52:33 +00:00
{ "serveraliveinterval", oServerAliveInterval },
{ "serveralivecountmax", oServerAliveCountMax },
2004-10-28 16:11:31 +00:00
{ "sendenv", oSendEnv },
2018-08-28 10:47:58 +00:00
{ "setenv", oSetEnv },
2004-10-28 16:11:31 +00:00
{ "controlpath", oControlPath },
{ "controlmaster", oControlMaster },
2010-11-08 10:45:44 +00:00
{ "controlpersist", oControlPersist },
2005-06-05 15:46:09 +00:00
{ "hashknownhosts", oHashKnownHosts },
2017-01-31 12:29:48 +00:00
{ "include", oInclude },
2006-03-22 20:41:37 +00:00
{ "tunnel", oTunnel },
{ "tunneldevice", oTunnelDevice },
{ "localcommand", oLocalCommand },
{ "permitlocalcommand", oPermitLocalCommand },
2018-05-06 12:24:45 +00:00
{ "remotecommand", oRemoteCommand },
2008-07-23 09:33:08 +00:00
{ "visualhostkey", oVisualHostKey },
2011-02-17 11:47:40 +00:00
{ "kexalgorithms", oKexAlgorithms },
{ "ipqos", oIPQoS },
2011-09-28 08:14:41 +00:00
{ "requesttty", oRequestTTY },
2021-08-30 19:14:33 +00:00
{ "sessiontype", oSessionType },
{ "stdinnull", oStdinNull },
{ "forkafterauthentication", oForkAfterAuthentication },
2014-01-30 10:56:49 +00:00
{ "proxyusefdpass", oProxyUseFdpass },
{ "canonicaldomains", oCanonicalDomains },
{ "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
{ "canonicalizehostname", oCanonicalizeHostname },
{ "canonicalizemaxdots", oCanonicalizeMaxDots },
{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
2015-01-05 16:09:55 +00:00
{ "streamlocalbindmask", oStreamLocalBindMask },
{ "streamlocalbindunlink", oStreamLocalBindUnlink },
2015-07-02 13:15:34 +00:00
{ "revokedhostkeys", oRevokedHostKeys },
{ "fingerprinthash", oFingerprintHash },
{ "updatehostkeys", oUpdateHostkeys },
2021-08-30 19:14:33 +00:00
{ "hostbasedacceptedalgorithms", oHostbasedAcceptedAlgorithms },
2021-04-23 19:10:38 +00:00
{ "hostbasedkeytypes", oHostbasedAcceptedAlgorithms }, /* obsolete */
{ "pubkeyacceptedalgorithms", oPubkeyAcceptedAlgorithms },
{ "pubkeyacceptedkeytypes", oPubkeyAcceptedAlgorithms }, /* obsolete */
2013-09-18 17:27:38 +00:00
{ "ignoreunknown", oIgnoreUnknown },
2017-01-31 12:29:48 +00:00
{ "proxyjump", oProxyJump },
2021-02-14 21:04:52 +00:00
{ "securitykeyprovider", oSecurityKeyProvider },
2021-04-23 19:10:38 +00:00
{ "knownhostscommand", oKnownHostsCommand },
2022-10-04 15:10:40 +00:00
{ "requiredrsasize", oRequiredRSASize },
2023-02-05 18:04:12 +00:00
{ "enableescapecommandline", oEnableEscapeCommandline },
2023-10-04 12:06:41 +00:00
{ "obscurekeystroketiming", oObscureKeystrokeTiming },
2023-12-18 15:59:40 +00:00
{ "channeltimeout", oChannelTimeout },
2009-02-24 18:49:27 +00:00
2002-03-18 10:09:43 +00:00
{ NULL, oBadOption }
2000-02-24 14:29:47 +00:00
};
2021-04-23 19:10:38 +00:00
static const char *lookup_opcode_name(OpCodes code);
2021-02-14 21:04:52 +00:00
const char *
kex_default_pk_alg(void)
{
2021-04-23 19:10:38 +00:00
static char *pkalgs;
if (pkalgs == NULL) {
char *all_key;
all_key = sshkey_alg_list(0, 0, 1, ',');
pkalgs = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
free(all_key);
}
return pkalgs;
2021-02-14 21:04:52 +00:00
}
2021-02-14 21:07:21 +00:00
char *
ssh_connection_hash(const char *thishost, const char *host, const char *portstr,
2023-12-18 15:59:40 +00:00
const char *user, const char *jumphost)
2021-02-14 21:07:21 +00:00
{
struct ssh_digest_ctx *md;
u_char conn_hash[SSH_DIGEST_MAX_LENGTH];
if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL ||
ssh_digest_update(md, thishost, strlen(thishost)) < 0 ||
ssh_digest_update(md, host, strlen(host)) < 0 ||
ssh_digest_update(md, portstr, strlen(portstr)) < 0 ||
ssh_digest_update(md, user, strlen(user)) < 0 ||
2023-12-18 15:59:40 +00:00
ssh_digest_update(md, jumphost, strlen(jumphost)) < 0 ||
2021-02-14 21:07:21 +00:00
ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0)
2021-04-23 19:10:38 +00:00
fatal_f("mux digest failed");
2021-02-14 21:07:21 +00:00
ssh_digest_free(md);
return tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1));
}
2000-02-24 14:29:47 +00:00
/*
* Adds a local TCP/IP port forward to options. Never returns if there is an
* error.
*/
void
2015-01-05 16:09:55 +00:00
add_local_forward(Options *options, const struct Forward *newfwd)
2000-02-24 14:29:47 +00:00
{
2015-01-05 16:09:55 +00:00
struct Forward *fwd;
int i;
2017-01-31 12:29:48 +00:00
/* Don't add duplicates */
for (i = 0; i < options->num_local_forwards; i++) {
if (forward_equals(newfwd, options->local_forwards + i))
return;
}
2015-07-02 13:18:50 +00:00
options->local_forwards = xreallocarray(options->local_forwards,
2010-11-08 10:45:44 +00:00
options->num_local_forwards + 1,
sizeof(*options->local_forwards));
2000-02-24 14:29:47 +00:00
fwd = &options->local_forwards[options->num_local_forwards++];
2005-06-05 15:46:09 +00:00
2009-02-24 18:49:27 +00:00
fwd->listen_host = newfwd->listen_host;
2005-06-05 15:46:09 +00:00
fwd->listen_port = newfwd->listen_port;
2015-01-05 16:09:55 +00:00
fwd->listen_path = newfwd->listen_path;
2009-02-24 18:49:27 +00:00
fwd->connect_host = newfwd->connect_host;
2005-06-05 15:46:09 +00:00
fwd->connect_port = newfwd->connect_port;
2015-01-05 16:09:55 +00:00
fwd->connect_path = newfwd->connect_path;
2000-02-24 14:29:47 +00:00
}
/*
* Adds a remote TCP/IP port forward to options. Never returns if there is
* an error.
*/
void
2015-01-05 16:09:55 +00:00
add_remote_forward(Options *options, const struct Forward *newfwd)
2000-02-24 14:29:47 +00:00
{
2015-01-05 16:09:55 +00:00
struct Forward *fwd;
2017-01-31 12:29:48 +00:00
int i;
2010-11-08 10:45:44 +00:00
2017-01-31 12:29:48 +00:00
/* Don't add duplicates */
for (i = 0; i < options->num_remote_forwards; i++) {
if (forward_equals(newfwd, options->remote_forwards + i))
return;
}
2015-07-02 13:18:50 +00:00
options->remote_forwards = xreallocarray(options->remote_forwards,
2010-11-08 10:45:44 +00:00
options->num_remote_forwards + 1,
sizeof(*options->remote_forwards));
2000-02-24 14:29:47 +00:00
fwd = &options->remote_forwards[options->num_remote_forwards++];
2005-06-05 15:46:09 +00:00
2009-02-24 18:49:27 +00:00
fwd->listen_host = newfwd->listen_host;
2005-06-05 15:46:09 +00:00
fwd->listen_port = newfwd->listen_port;
2015-01-05 16:09:55 +00:00
fwd->listen_path = newfwd->listen_path;
2009-02-24 18:49:27 +00:00
fwd->connect_host = newfwd->connect_host;
2005-06-05 15:46:09 +00:00
fwd->connect_port = newfwd->connect_port;
2015-01-05 16:09:55 +00:00
fwd->connect_path = newfwd->connect_path;
2012-08-29 15:46:01 +00:00
fwd->handle = newfwd->handle;
2010-11-08 10:45:44 +00:00
fwd->allocated_port = 0;
2000-02-24 14:29:47 +00:00
}
2002-03-18 10:09:43 +00:00
static void
clear_forwardings(Options *options)
{
int i;
2005-06-05 15:46:09 +00:00
for (i = 0; i < options->num_local_forwards; i++) {
2013-09-18 17:27:38 +00:00
free(options->local_forwards[i].listen_host);
2015-01-05 16:09:55 +00:00
free(options->local_forwards[i].listen_path);
2013-09-18 17:27:38 +00:00
free(options->local_forwards[i].connect_host);
2015-01-05 16:09:55 +00:00
free(options->local_forwards[i].connect_path);
2005-06-05 15:46:09 +00:00
}
2010-11-08 10:45:44 +00:00
if (options->num_local_forwards > 0) {
2013-09-18 17:27:38 +00:00
free(options->local_forwards);
2010-11-08 10:45:44 +00:00
options->local_forwards = NULL;
}
2002-03-18 10:09:43 +00:00
options->num_local_forwards = 0;
2005-06-05 15:46:09 +00:00
for (i = 0; i < options->num_remote_forwards; i++) {
2013-09-18 17:27:38 +00:00
free(options->remote_forwards[i].listen_host);
2015-01-05 16:09:55 +00:00
free(options->remote_forwards[i].listen_path);
2013-09-18 17:27:38 +00:00
free(options->remote_forwards[i].connect_host);
2015-01-05 16:09:55 +00:00
free(options->remote_forwards[i].connect_path);
2005-06-05 15:46:09 +00:00
}
2010-11-08 10:45:44 +00:00
if (options->num_remote_forwards > 0) {
2013-09-18 17:27:38 +00:00
free(options->remote_forwards);
2010-11-08 10:45:44 +00:00
options->remote_forwards = NULL;
}
2002-03-18 10:09:43 +00:00
options->num_remote_forwards = 0;
2006-03-22 20:41:37 +00:00
options->tun_open = SSH_TUNMODE_NO;
2002-03-18 10:09:43 +00:00
}
2016-03-10 20:10:25 +00:00
void
add_certificate_file(Options *options, const char *path, int userprovided)
{
int i;
if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
fatal("Too many certificate files specified (max %d)",
SSH_MAX_CERTIFICATE_FILES);
/* Avoid registering duplicates */
for (i = 0; i < options->num_certificate_files; i++) {
if (options->certificate_file_userprovided[i] == userprovided &&
strcmp(options->certificate_files[i], path) == 0) {
2021-04-23 19:10:38 +00:00
debug2_f("ignoring duplicate key %s", path);
2016-03-10 20:10:25 +00:00
return;
}
}
options->certificate_file_userprovided[options->num_certificate_files] =
userprovided;
options->certificate_files[options->num_certificate_files++] =
xstrdup(path);
}
void
add_identity_file(Options *options, const char *dir, const char *filename,
int userprovided)
{
char *path;
2015-01-05 16:09:55 +00:00
int i;
if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
fatal("Too many identity files specified (max %d)",
SSH_MAX_IDENTITY_FILES);
if (dir == NULL) /* no dir, filename is absolute */
path = xstrdup(filename);
2018-05-06 12:24:45 +00:00
else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX)
fatal("Identity file path %s too long", path);
2015-01-05 16:09:55 +00:00
/* Avoid registering duplicates */
for (i = 0; i < options->num_identity_files; i++) {
if (options->identity_file_userprovided[i] == userprovided &&
strcmp(options->identity_files[i], path) == 0) {
2021-04-23 19:10:38 +00:00
debug2_f("ignoring duplicate key %s", path);
2015-01-05 16:09:55 +00:00
free(path);
return;
}
}
options->identity_file_userprovided[options->num_identity_files] =
userprovided;
options->identity_files[options->num_identity_files++] = path;
}
2014-01-30 10:56:49 +00:00
int
default_ssh_port(void)
{
static int port;
struct servent *sp;
if (port == 0) {
sp = getservbyname(SSH_SERVICE_NAME, "tcp");
port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
}
return port;
}
2000-02-24 14:29:47 +00:00
/*
2014-01-30 10:56:49 +00:00
* Execute a command in a shell.
* Return its exit status or -1 on abnormal exit.
2000-02-24 14:29:47 +00:00
*/
2014-01-30 10:56:49 +00:00
static int
execute_in_shell(const char *cmd)
{
2016-03-10 20:10:25 +00:00
char *shell;
2014-01-30 10:56:49 +00:00
pid_t pid;
2021-04-23 19:10:38 +00:00
int status;
2014-01-30 10:56:49 +00:00
if ((shell = getenv("SHELL")) == NULL)
shell = _PATH_BSHELL;
2021-02-14 21:00:25 +00:00
if (access(shell, X_OK) == -1) {
fatal("Shell \"%s\" is not executable: %s",
shell, strerror(errno));
}
2014-01-30 10:56:49 +00:00
debug("Executing command: '%.500s'", cmd);
/* Fork and execute the command. */
if ((pid = fork()) == 0) {
char *argv[4];
2021-04-23 19:10:38 +00:00
if (stdfd_devnull(1, 1, 0) == -1)
fatal_f("stdfd_devnull failed");
2014-01-30 10:56:49 +00:00
closefrom(STDERR_FILENO + 1);
argv[0] = shell;
argv[1] = "-c";
2016-03-10 20:10:25 +00:00
argv[2] = xstrdup(cmd);
2014-01-30 10:56:49 +00:00
argv[3] = NULL;
execv(argv[0], argv);
error("Unable to execute '%.100s': %s", cmd, strerror(errno));
/* Die with signal to make this error apparent to parent. */
2021-02-14 21:04:52 +00:00
ssh_signal(SIGTERM, SIG_DFL);
2014-01-30 10:56:49 +00:00
kill(getpid(), SIGTERM);
_exit(1);
}
/* Parent. */
2021-02-14 21:00:25 +00:00
if (pid == -1)
2021-04-23 19:10:38 +00:00
fatal_f("fork: %.100s", strerror(errno));
2014-01-30 10:56:49 +00:00
while (waitpid(pid, &status, 0) == -1) {
if (errno != EINTR && errno != EAGAIN)
2021-04-23 19:10:38 +00:00
fatal_f("waitpid: %s", strerror(errno));
2014-01-30 10:56:49 +00:00
}
if (!WIFEXITED(status)) {
error("command '%.100s' exited abnormally", cmd);
return -1;
2015-07-02 13:15:34 +00:00
}
2014-01-30 10:56:49 +00:00
debug3("command returned status %d", WEXITSTATUS(status));
return WEXITSTATUS(status);
}
2023-08-10 16:16:53 +00:00
/*
* Check whether a local network interface address appears in CIDR pattern-
* list 'addrlist'. Returns 1 if matched or 0 otherwise.
*/
static int
check_match_ifaddrs(const char *addrlist)
{
#ifdef HAVE_IFADDRS_H
struct ifaddrs *ifa, *ifaddrs = NULL;
int r, found = 0;
char addr[NI_MAXHOST];
socklen_t salen;
if (getifaddrs(&ifaddrs) != 0) {
error("match localnetwork: getifaddrs failed: %s",
strerror(errno));
return 0;
}
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL ||
(ifa->ifa_flags & IFF_UP) == 0)
continue;
switch (ifa->ifa_addr->sa_family) {
case AF_INET:
salen = sizeof(struct sockaddr_in);
break;
case AF_INET6:
salen = sizeof(struct sockaddr_in6);
break;
#ifdef AF_LINK
case AF_LINK:
/* ignore */
continue;
#endif /* AF_LINK */
default:
debug2_f("interface %s: unsupported address family %d",
ifa->ifa_name, ifa->ifa_addr->sa_family);
continue;
}
if ((r = getnameinfo(ifa->ifa_addr, salen, addr, sizeof(addr),
NULL, 0, NI_NUMERICHOST)) != 0) {
debug2_f("interface %s getnameinfo failed: %s",
ifa->ifa_name, gai_strerror(r));
continue;
}
debug3_f("interface %s addr %s", ifa->ifa_name, addr);
if (addr_match_cidr_list(addr, addrlist) == 1) {
debug3_f("matched interface %s: address %s in %s",
ifa->ifa_name, addr, addrlist);
found = 1;
break;
}
}
freeifaddrs(ifaddrs);
return found;
#else /* HAVE_IFADDRS_H */
error("match localnetwork: not supported on this platform");
return 0;
#endif /* HAVE_IFADDRS_H */
}
2014-01-30 10:56:49 +00:00
/*
* Parse and execute a Match directive.
2000-02-24 14:29:47 +00:00
*/
2014-01-30 10:56:49 +00:00
static int
match_cfg_line(Options *options, char **condition, struct passwd *pw,
2020-02-14 19:47:15 +00:00
const char *host_arg, const char *original_host, int final_pass,
int *want_final_pass, const char *filename, int linenum)
2014-01-30 10:56:49 +00:00
{
2015-07-02 13:15:34 +00:00
char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
2014-01-30 10:56:49 +00:00
const char *ruser;
2015-07-02 13:15:34 +00:00
int r, port, this_result, result = 1, attributes = 0, negate;
2014-01-30 10:56:49 +00:00
char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
2018-08-28 10:47:58 +00:00
char uidstr[32];
2014-01-30 10:56:49 +00:00
/*
* Configuration is likely to be incomplete at this point so we
* must be prepared to use default values.
*/
port = options->port <= 0 ? default_ssh_port() : options->port;
ruser = options->user == NULL ? pw->pw_name : options->user;
2020-02-14 19:47:15 +00:00
if (final_pass) {
2016-03-10 20:10:25 +00:00
host = xstrdup(options->hostname);
} else if (options->hostname != NULL) {
2014-01-30 10:56:49 +00:00
/* NB. Please keep in sync with ssh.c:main() */
host = percent_expand(options->hostname,
"h", host_arg, (char *)NULL);
2016-03-10 20:10:25 +00:00
} else {
2014-01-30 10:56:49 +00:00
host = xstrdup(host_arg);
2016-03-10 20:10:25 +00:00
}
2014-01-30 10:56:49 +00:00
2015-07-02 13:15:34 +00:00
debug2("checking match for '%s' host %s originally %s",
cp, host, original_host);
while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
2021-08-30 19:14:33 +00:00
/* Terminate on comment */
if (*attrib == '#') {
cp = NULL; /* mark all arguments consumed */
break;
}
arg = criteria = NULL;
2015-07-02 13:15:34 +00:00
this_result = 1;
2023-03-16 12:41:22 +00:00
if ((negate = (attrib[0] == '!')))
2015-07-02 13:15:34 +00:00
attrib++;
2021-08-30 19:14:33 +00:00
/* Criterion "all" has no argument and must appear alone */
2014-01-30 10:56:49 +00:00
if (strcasecmp(attrib, "all") == 0) {
2021-08-30 19:14:33 +00:00
if (attributes > 1 || ((arg = strdelim(&cp)) != NULL &&
*arg != '\0' && *arg != '#')) {
2015-07-02 13:15:34 +00:00
error("%.200s line %d: '%s' cannot be combined "
"with other Match attributes",
filename, linenum, oattrib);
2014-01-30 10:56:49 +00:00
result = -1;
goto out;
}
2021-08-30 19:14:33 +00:00
if (arg != NULL && *arg == '#')
cp = NULL; /* mark all arguments consumed */
2015-07-02 13:15:34 +00:00
if (result)
result = negate ? 0 : 1;
2014-01-30 10:56:49 +00:00
goto out;
}
2015-07-02 13:15:34 +00:00
attributes++;
2021-08-30 19:14:33 +00:00
/* criteria "final" and "canonical" have no argument */
2020-02-14 19:47:15 +00:00
if (strcasecmp(attrib, "canonical") == 0 ||
strcasecmp(attrib, "final") == 0) {
/*
* If the config requests "Match final" then remember
* this so we can perform a second pass later.
*/
if (strcasecmp(attrib, "final") == 0 &&
want_final_pass != NULL)
*want_final_pass = 1;
r = !!final_pass; /* force bitmask member to boolean */
2015-07-02 13:15:34 +00:00
if (r == (negate ? 1 : 0))
this_result = result = 0;
debug3("%.200s line %d: %smatched '%s'",
filename, linenum,
this_result ? "" : "not ", oattrib);
continue;
}
/* All other criteria require an argument */
2021-08-30 19:14:33 +00:00
if ((arg = strdelim(&cp)) == NULL ||
*arg == '\0' || *arg == '#') {
2014-01-30 10:56:49 +00:00
error("Missing Match criteria for %s", attrib);
result = -1;
goto out;
}
if (strcasecmp(attrib, "host") == 0) {
2015-07-02 13:15:34 +00:00
criteria = xstrdup(host);
2015-07-02 13:18:50 +00:00
r = match_hostname(host, arg) == 1;
2015-07-02 13:15:34 +00:00
if (r == (negate ? 1 : 0))
this_result = result = 0;
2014-01-30 10:56:49 +00:00
} else if (strcasecmp(attrib, "originalhost") == 0) {
2015-07-02 13:15:34 +00:00
criteria = xstrdup(original_host);
2015-07-02 13:18:50 +00:00
r = match_hostname(original_host, arg) == 1;
2015-07-02 13:15:34 +00:00
if (r == (negate ? 1 : 0))
this_result = result = 0;
2014-01-30 10:56:49 +00:00
} else if (strcasecmp(attrib, "user") == 0) {
2015-07-02 13:15:34 +00:00
criteria = xstrdup(ruser);
2015-07-02 13:18:50 +00:00
r = match_pattern_list(ruser, arg, 0) == 1;
2015-07-02 13:15:34 +00:00
if (r == (negate ? 1 : 0))
this_result = result = 0;
2014-01-30 10:56:49 +00:00
} else if (strcasecmp(attrib, "localuser") == 0) {
2015-07-02 13:15:34 +00:00
criteria = xstrdup(pw->pw_name);
2015-07-02 13:18:50 +00:00
r = match_pattern_list(pw->pw_name, arg, 0) == 1;
2015-07-02 13:15:34 +00:00
if (r == (negate ? 1 : 0))
this_result = result = 0;
2023-08-10 16:16:53 +00:00
} else if (strcasecmp(attrib, "localnetwork") == 0) {
if (addr_match_cidr_list(NULL, arg) == -1) {
/* Error already printed */
result = -1;
goto out;
}
r = check_match_ifaddrs(arg) == 1;
if (r == (negate ? 1 : 0))
this_result = result = 0;
} else if (strcasecmp(attrib, "tagged") == 0) {
criteria = xstrdup(options->tag == NULL ? "" :
options->tag);
r = match_pattern_list(criteria, arg, 0) == 1;
if (r == (negate ? 1 : 0))
this_result = result = 0;
2014-01-30 10:56:49 +00:00
} else if (strcasecmp(attrib, "exec") == 0) {
2023-12-18 15:59:40 +00:00
char *conn_hash_hex, *keyalias, *jmphost;
2021-02-14 21:07:21 +00:00
2014-01-30 10:56:49 +00:00
if (gethostname(thishost, sizeof(thishost)) == -1)
fatal("gethostname: %s", strerror(errno));
2023-12-18 15:59:40 +00:00
jmphost = option_clear_or_none(options->jump_host) ?
"" : options->jump_host;
2014-01-30 10:56:49 +00:00
strlcpy(shorthost, thishost, sizeof(shorthost));
shorthost[strcspn(thishost, ".")] = '\0';
snprintf(portstr, sizeof(portstr), "%d", port);
2018-08-28 10:47:58 +00:00
snprintf(uidstr, sizeof(uidstr), "%llu",
(unsigned long long)pw->pw_uid);
2021-02-14 21:07:21 +00:00
conn_hash_hex = ssh_connection_hash(thishost, host,
2023-12-18 15:59:40 +00:00
portstr, ruser, jmphost);
2021-02-14 21:09:58 +00:00
keyalias = options->host_key_alias ?
options->host_key_alias : host;
2014-01-30 10:56:49 +00:00
cmd = percent_expand(arg,
2021-02-14 21:07:21 +00:00
"C", conn_hash_hex,
2014-01-30 10:56:49 +00:00
"L", shorthost,
"d", pw->pw_dir,
"h", host,
2021-02-14 21:09:58 +00:00
"k", keyalias,
2014-01-30 10:56:49 +00:00
"l", thishost,
2015-07-02 13:15:34 +00:00
"n", original_host,
2014-01-30 10:56:49 +00:00
"p", portstr,
"r", ruser,
"u", pw->pw_name,
2018-08-28 10:47:58 +00:00
"i", uidstr,
2023-12-18 15:59:40 +00:00
"j", jmphost,
2014-01-30 10:56:49 +00:00
(char *)NULL);
2021-02-14 21:07:21 +00:00
free(conn_hash_hex);
2014-03-22 15:23:38 +00:00
if (result != 1) {
/* skip execution if prior predicate failed */
2015-07-02 13:15:34 +00:00
debug3("%.200s line %d: skipped exec "
"\"%.100s\"", filename, linenum, cmd);
free(cmd);
continue;
2014-03-22 15:23:38 +00:00
}
2015-07-02 13:15:34 +00:00
r = execute_in_shell(cmd);
if (r == -1) {
fatal("%.200s line %d: match exec "
"'%.100s' error", filename,
linenum, cmd);
}
criteria = xstrdup(cmd);
2014-01-30 10:56:49 +00:00
free(cmd);
2015-07-02 13:15:34 +00:00
/* Force exit status to boolean */
r = r == 0;
if (r == (negate ? 1 : 0))
this_result = result = 0;
2014-01-30 10:56:49 +00:00
} else {
error("Unsupported Match attribute %s", attrib);
result = -1;
goto out;
}
2023-08-10 16:16:53 +00:00
debug3("%.200s line %d: %smatched '%s%s%.100s%s' ",
filename, linenum, this_result ? "": "not ", oattrib,
criteria == NULL ? "" : " \"",
criteria == NULL ? "" : criteria,
criteria == NULL ? "" : "\"");
2015-07-02 13:15:34 +00:00
free(criteria);
2014-01-30 10:56:49 +00:00
}
if (attributes == 0) {
error("One or more attributes required for Match");
result = -1;
goto out;
}
out:
2015-07-02 13:15:34 +00:00
if (result != -1)
debug2("match %sfound", result ? "" : "not ");
*condition = cp;
2014-01-30 10:56:49 +00:00
free(host);
return result;
}
2000-02-24 14:29:47 +00:00
2018-08-28 10:47:58 +00:00
/* Remove environment variable by pattern */
static void
rm_env(Options *options, const char *arg, const char *filename, int linenum)
{
2022-10-04 15:10:40 +00:00
u_int i, j, onum_send_env = options->num_send_env;
2018-08-28 10:47:58 +00:00
/* Remove an environment variable */
for (i = 0; i < options->num_send_env; ) {
2022-10-04 15:10:40 +00:00
if (!match_pattern(options->send_env[i], arg + 1)) {
2018-08-28 10:47:58 +00:00
i++;
continue;
}
debug3("%s line %d: removing environment %s",
2022-10-04 15:10:40 +00:00
filename, linenum, options->send_env[i]);
2018-08-28 10:47:58 +00:00
free(options->send_env[i]);
options->send_env[i] = NULL;
for (j = i; j < options->num_send_env - 1; j++) {
options->send_env[j] = options->send_env[j + 1];
options->send_env[j + 1] = NULL;
}
options->num_send_env--;
/* NB. don't increment i */
}
2021-02-14 21:09:58 +00:00
if (onum_send_env != options->num_send_env) {
options->send_env = xrecallocarray(options->send_env,
onum_send_env, options->num_send_env,
sizeof(*options->send_env));
}
2018-08-28 10:47:58 +00:00
}
2014-01-30 10:56:49 +00:00
/*
* Returns the number of the token pointed to by cp or oBadOption.
*/
static OpCodes
2013-09-18 17:27:38 +00:00
parse_token(const char *cp, const char *filename, int linenum,
const char *ignored_unknown)
2000-02-24 14:29:47 +00:00
{
2013-09-18 17:27:38 +00:00
int i;
2000-02-24 14:29:47 +00:00
for (i = 0; keywords[i].name; i++)
2013-09-18 17:27:38 +00:00
if (strcmp(cp, keywords[i].name) == 0)
2000-02-24 14:29:47 +00:00
return keywords[i].opcode;
2015-07-02 13:18:50 +00:00
if (ignored_unknown != NULL &&
match_pattern_list(cp, ignored_unknown, 1) == 1)
2013-09-18 17:27:38 +00:00
return oIgnoredUnknownOption;
2001-05-04 04:14:23 +00:00
error("%s: line %d: Bad configuration option: %s",
filename, linenum, cp);
2000-02-24 14:29:47 +00:00
return oBadOption;
}
2024-03-17 17:47:10 +00:00
static void
free_canon_cnames(struct allowed_cname *cnames, u_int n)
{
u_int i;
if (cnames == NULL || n == 0)
return;
for (i = 0; i < n; i++) {
free(cnames[i].source_list);
free(cnames[i].target_list);
}
free(cnames);
}
2014-01-30 10:56:49 +00:00
/* Multistate option parsing */
struct multistate {
char *key;
int value;
};
static const struct multistate multistate_flag[] = {
{ "true", 1 },
{ "false", 0 },
{ "yes", 1 },
{ "no", 0 },
{ NULL, -1 }
};
static const struct multistate multistate_yesnoask[] = {
{ "true", 1 },
{ "false", 0 },
{ "yes", 1 },
{ "no", 0 },
{ "ask", 2 },
{ NULL, -1 }
};
2018-05-06 12:24:45 +00:00
static const struct multistate multistate_strict_hostkey[] = {
{ "true", SSH_STRICT_HOSTKEY_YES },
{ "false", SSH_STRICT_HOSTKEY_OFF },
{ "yes", SSH_STRICT_HOSTKEY_YES },
{ "no", SSH_STRICT_HOSTKEY_OFF },
{ "ask", SSH_STRICT_HOSTKEY_ASK },
{ "off", SSH_STRICT_HOSTKEY_OFF },
{ "accept-new", SSH_STRICT_HOSTKEY_NEW },
{ NULL, -1 }
};
2016-03-10 20:10:25 +00:00
static const struct multistate multistate_yesnoaskconfirm[] = {
{ "true", 1 },
{ "false", 0 },
{ "yes", 1 },
{ "no", 0 },
{ "ask", 2 },
{ "confirm", 3 },
{ NULL, -1 }
};
2014-01-30 10:56:49 +00:00
static const struct multistate multistate_addressfamily[] = {
{ "inet", AF_INET },
{ "inet6", AF_INET6 },
{ "any", AF_UNSPEC },
{ NULL, -1 }
};
static const struct multistate multistate_controlmaster[] = {
{ "true", SSHCTL_MASTER_YES },
{ "yes", SSHCTL_MASTER_YES },
{ "false", SSHCTL_MASTER_NO },
{ "no", SSHCTL_MASTER_NO },
{ "auto", SSHCTL_MASTER_AUTO },
{ "ask", SSHCTL_MASTER_ASK },
{ "autoask", SSHCTL_MASTER_AUTO_ASK },
{ NULL, -1 }
};
static const struct multistate multistate_tunnel[] = {
{ "ethernet", SSH_TUNMODE_ETHERNET },
{ "point-to-point", SSH_TUNMODE_POINTOPOINT },
{ "true", SSH_TUNMODE_DEFAULT },
{ "yes", SSH_TUNMODE_DEFAULT },
{ "false", SSH_TUNMODE_NO },
{ "no", SSH_TUNMODE_NO },
{ NULL, -1 }
};
static const struct multistate multistate_requesttty[] = {
{ "true", REQUEST_TTY_YES },
{ "yes", REQUEST_TTY_YES },
{ "false", REQUEST_TTY_NO },
{ "no", REQUEST_TTY_NO },
{ "force", REQUEST_TTY_FORCE },
{ "auto", REQUEST_TTY_AUTO },
{ NULL, -1 }
};
2021-08-30 19:14:33 +00:00
static const struct multistate multistate_sessiontype[] = {
{ "none", SESSION_TYPE_NONE },
{ "subsystem", SESSION_TYPE_SUBSYSTEM },
{ "default", SESSION_TYPE_DEFAULT },
{ NULL, -1 }
};
2014-01-30 10:56:49 +00:00
static const struct multistate multistate_canonicalizehostname[] = {
{ "true", SSH_CANONICALISE_YES },
{ "false", SSH_CANONICALISE_NO },
{ "yes", SSH_CANONICALISE_YES },
{ "no", SSH_CANONICALISE_NO },
{ "always", SSH_CANONICALISE_ALWAYS },
{ NULL, -1 }
};
2022-02-23 18:16:45 +00:00
static const struct multistate multistate_pubkey_auth[] = {
{ "true", SSH_PUBKEY_AUTH_ALL },
{ "false", SSH_PUBKEY_AUTH_NO },
{ "yes", SSH_PUBKEY_AUTH_ALL },
{ "no", SSH_PUBKEY_AUTH_NO },
{ "unbound", SSH_PUBKEY_AUTH_UNBOUND },
{ "host-bound", SSH_PUBKEY_AUTH_HBOUND },
{ NULL, -1 }
};
2021-02-14 21:04:52 +00:00
static const struct multistate multistate_compression[] = {
#ifdef WITH_ZLIB
{ "yes", COMP_ZLIB },
#endif
{ "no", COMP_NONE },
{ NULL, -1 }
};
2014-01-30 10:56:49 +00:00
2021-02-14 21:09:58 +00:00
static int
parse_multistate_value(const char *arg, const char *filename, int linenum,
const struct multistate *multistate_ptr)
{
int i;
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%s line %d: missing argument.", filename, linenum);
return -1;
}
2021-02-14 21:09:58 +00:00
for (i = 0; multistate_ptr[i].key != NULL; i++) {
if (strcasecmp(arg, multistate_ptr[i].key) == 0)
return multistate_ptr[i].value;
}
return -1;
}
2014-01-30 10:56:49 +00:00
2000-02-24 14:29:47 +00:00
/*
* Processes a single option line as used in the configuration files. This
* only sets those values that have not already been set.
*/
int
2014-01-30 10:56:49 +00:00
process_config_line(Options *options, struct passwd *pw, const char *host,
2015-07-02 13:15:34 +00:00
const char *original_host, char *line, const char *filename,
int linenum, int *activep, int flags)
2017-01-31 12:29:48 +00:00
{
return process_config_line_depth(options, pw, host, original_host,
2020-02-14 19:47:15 +00:00
line, filename, linenum, activep, flags, NULL, 0);
2017-01-31 12:29:48 +00:00
}
#define WHITESPACE " \t\r\n"
static int
process_config_line_depth(Options *options, struct passwd *pw, const char *host,
const char *original_host, char *line, const char *filename,
2020-02-14 19:47:15 +00:00
int linenum, int *activep, int flags, int *want_final_pass, int depth)
2000-02-24 14:29:47 +00:00
{
2022-02-23 18:16:45 +00:00
char *str, **charptr, *endofnumber, *keyword, *arg, *arg2, *p;
2021-04-23 19:10:38 +00:00
char **cpptr, ***cppptr, fwdarg[256];
2024-03-17 17:47:10 +00:00
u_int i, *uintptr, max_entries = 0;
2017-01-31 12:29:48 +00:00
int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
2024-03-17 17:47:10 +00:00
int remotefwd, dynamicfwd, ca_only = 0, found = 0;
LogLevel *log_level_ptr;
2018-05-06 12:24:45 +00:00
SyslogFacility *log_facility_ptr;
2013-09-18 17:27:38 +00:00
long long val64;
2003-04-23 17:13:13 +00:00
size_t len;
2015-01-05 16:09:55 +00:00
struct Forward fwd;
2014-01-30 10:56:49 +00:00
const struct multistate *multistate_ptr;
2017-01-31 12:29:48 +00:00
glob_t gl;
2018-05-06 12:27:04 +00:00
const char *errstr;
2021-08-30 19:14:33 +00:00
char **oav = NULL, **av;
int oac = 0, ac;
int ret = -1;
2024-03-17 17:47:10 +00:00
struct allowed_cname *cnames = NULL;
u_int ncnames = 0;
char **strs = NULL; /* string array arguments; freed implicitly */
u_int nstrs = 0;
2014-01-30 10:56:49 +00:00
if (activep == NULL) { /* We are processing a command line directive */
cmdline = 1;
activep = &cmdline;
}
2000-02-24 14:29:47 +00:00
2017-08-03 10:10:20 +00:00
/* Strip trailing whitespace. Allow \f (form feed) at EOL only */
2015-07-02 13:18:50 +00:00
if ((len = strlen(line)) == 0)
return 0;
for (len--; len > 0; len--) {
2017-08-03 10:10:20 +00:00
if (strchr(WHITESPACE "\f", line[len]) == NULL)
break;
line[len] = '\0';
}
2021-08-30 19:14:33 +00:00
str = line;
/* Get the keyword. (Each line is supposed to begin with a keyword). */
2021-08-30 19:14:33 +00:00
if ((keyword = strdelim(&str)) == NULL)
2006-09-30 13:38:06 +00:00
return 0;
/* Ignore leading whitespace. */
if (*keyword == '\0')
2021-08-30 19:14:33 +00:00
keyword = strdelim(&str);
2001-05-04 04:14:23 +00:00
if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
2000-02-24 14:29:47 +00:00
return 0;
2013-09-18 17:27:38 +00:00
/* Match lowercase keyword */
2014-01-30 10:56:49 +00:00
lowercase(keyword);
2000-02-24 14:29:47 +00:00
2021-08-30 19:14:33 +00:00
/* Prepare to parse remainder of line */
if (str != NULL)
str += strspn(str, WHITESPACE);
if (str == NULL || *str == '\0') {
error("%s line %d: no argument after keyword \"%s\"",
filename, linenum, keyword);
return -1;
}
2013-09-18 17:27:38 +00:00
opcode = parse_token(keyword, filename, linenum,
options->ignored_unknown);
2021-08-30 19:14:33 +00:00
if (argv_split(str, &oac, &oav, 1) != 0) {
error("%s line %d: invalid quotes", filename, linenum);
return -1;
}
ac = oac;
av = oav;
2000-02-24 14:29:47 +00:00
switch (opcode) {
case oBadOption:
/* don't panic, but count bad options */
2021-08-30 19:14:33 +00:00
goto out;
2018-05-06 12:24:45 +00:00
case oIgnore:
2021-08-30 19:14:33 +00:00
argv_consume(&ac);
break;
2013-09-18 17:27:38 +00:00
case oIgnoredUnknownOption:
debug("%s line %d: Ignored unknown option \"%s\"",
filename, linenum, keyword);
2021-08-30 19:14:33 +00:00
argv_consume(&ac);
break;
case oConnectTimeout:
intptr = &options->connection_timeout;
2004-02-26 10:52:33 +00:00
parse_time:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%s line %d: missing time value.",
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2015-07-02 13:15:34 +00:00
if (strcmp(arg, "none") == 0)
value = -1;
2021-04-23 19:10:38 +00:00
else if ((value = convtime(arg)) == -1) {
error("%s line %d: invalid time value.",
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
if (*activep && *intptr == -1)
*intptr = value;
break;
2000-02-24 14:29:47 +00:00
case oForwardAgent:
intptr = &options->forward_agent;
2021-02-14 21:04:52 +00:00
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%s line %d: missing argument.",
2014-01-30 10:56:49 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2021-02-14 21:04:52 +00:00
2014-01-30 10:56:49 +00:00
value = -1;
2021-02-14 21:04:52 +00:00
multistate_ptr = multistate_flag;
2014-01-30 10:56:49 +00:00
for (i = 0; multistate_ptr[i].key != NULL; i++) {
if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
value = multistate_ptr[i].value;
break;
}
}
2021-02-14 21:04:52 +00:00
if (value != -1) {
if (*activep && *intptr == -1)
*intptr = value;
break;
}
/* ForwardAgent wasn't 'yes' or 'no', assume a path */
2000-02-24 14:29:47 +00:00
if (*activep && *intptr == -1)
2021-02-14 21:04:52 +00:00
*intptr = 1;
charptr = &options->forward_agent_sock_path;
goto parse_agent_path;
2000-02-24 14:29:47 +00:00
case oForwardX11:
intptr = &options->forward_x11;
2014-01-30 10:56:49 +00:00
parse_flag:
multistate_ptr = multistate_flag;
parse_multistate:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-02-14 21:09:58 +00:00
if ((value = parse_multistate_value(arg, filename, linenum,
2021-04-23 19:13:32 +00:00
multistate_ptr)) == -1) {
2021-04-23 19:10:38 +00:00
error("%s line %d: unsupported option \"%s\".",
2014-01-30 10:56:49 +00:00
filename, linenum, arg);
2021-08-30 19:14:33 +00:00
goto out;
2021-02-14 21:09:58 +00:00
}
2000-02-24 14:29:47 +00:00
if (*activep && *intptr == -1)
*intptr = value;
break;
2004-02-26 10:52:33 +00:00
case oForwardX11Trusted:
intptr = &options->forward_x11_trusted;
goto parse_flag;
2015-07-02 13:15:34 +00:00
2010-11-08 10:45:44 +00:00
case oForwardX11Timeout:
intptr = &options->forward_x11_timeout;
goto parse_time;
2004-02-26 10:52:33 +00:00
2000-02-24 14:29:47 +00:00
case oGatewayPorts:
2015-01-05 16:09:55 +00:00
intptr = &options->fwd_opts.gateway_ports;
2000-02-24 14:29:47 +00:00
goto parse_flag;
2006-09-30 13:38:06 +00:00
case oExitOnForwardFailure:
intptr = &options->exit_on_forward_failure;
goto parse_flag;
2000-02-24 14:29:47 +00:00
case oPasswordAuthentication:
intptr = &options->password_authentication;
goto parse_flag;
case oKbdInteractiveAuthentication:
intptr = &options->kbd_interactive_authentication;
goto parse_flag;
case oKbdInteractiveDevices:
charptr = &options->kbd_interactive_devices;
goto parse_string;
2001-05-04 04:14:23 +00:00
case oPubkeyAuthentication:
2022-02-23 18:16:45 +00:00
multistate_ptr = multistate_pubkey_auth;
2001-05-04 04:14:23 +00:00
intptr = &options->pubkey_authentication;
2022-02-23 18:16:45 +00:00
goto parse_multistate;
2001-05-04 04:14:23 +00:00
case oHostbasedAuthentication:
intptr = &options->hostbased_authentication;
2000-02-24 14:29:47 +00:00
goto parse_flag;
case oGssAuthentication:
intptr = &options->gss_authentication;
goto parse_flag;
case oGssDelegateCreds:
intptr = &options->gss_deleg_creds;
2000-02-24 14:29:47 +00:00
goto parse_flag;
2000-02-24 14:29:47 +00:00
case oBatchMode:
intptr = &options->batch_mode;
goto parse_flag;
case oCheckHostIP:
intptr = &options->check_host_ip;
goto parse_flag;
case oVerifyHostKeyDNS:
intptr = &options->verify_host_key_dns;
2014-01-30 10:56:49 +00:00
multistate_ptr = multistate_yesnoask;
goto parse_multistate;
2000-02-24 14:29:47 +00:00
case oStrictHostKeyChecking:
intptr = &options->strict_host_key_checking;
2018-05-06 12:24:45 +00:00
multistate_ptr = multistate_strict_hostkey;
2014-01-30 10:56:49 +00:00
goto parse_multistate;
2000-02-24 14:29:47 +00:00
case oCompression:
intptr = &options->compression;
2021-02-14 21:04:52 +00:00
multistate_ptr = multistate_compression;
goto parse_multistate;
2000-02-24 14:29:47 +00:00
2004-02-26 10:52:33 +00:00
case oTCPKeepAlive:
intptr = &options->tcp_keep_alive;
2000-02-24 14:29:47 +00:00
goto parse_flag;
2002-03-18 10:09:43 +00:00
case oNoHostAuthenticationForLocalhost:
intptr = &options->no_host_authentication_for_localhost;
goto parse_flag;
2000-02-24 14:29:47 +00:00
case oNumberOfPasswordPrompts:
intptr = &options->number_of_password_prompts;
goto parse_int;
case oRekeyLimit:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.", filename,
2013-09-18 17:27:38 +00:00
linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2013-09-18 17:27:38 +00:00
if (strcmp(arg, "default") == 0) {
val64 = 0;
} else {
2021-04-23 19:10:38 +00:00
if (scan_scaled(arg, &val64) == -1) {
error("%.200s line %d: Bad number '%s': %s",
2013-09-18 17:27:38 +00:00
filename, linenum, arg, strerror(errno));
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
if (val64 != 0 && val64 < 16) {
error("%.200s line %d: RekeyLimit too small",
2013-09-18 17:27:38 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
}
if (*activep && options->rekey_limit == -1)
2016-03-10 20:10:25 +00:00
options->rekey_limit = val64;
2021-08-30 19:14:33 +00:00
if (ac != 0) { /* optional rekey interval present */
if (strcmp(av[0], "none") == 0) {
(void)argv_next(&ac, &av); /* discard */
2013-09-18 17:27:38 +00:00
break;
}
intptr = &options->rekey_interval;
goto parse_time;
}
break;
2000-02-24 14:29:47 +00:00
case oIdentityFile:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2000-02-24 14:29:47 +00:00
if (*activep) {
2001-05-04 04:14:23 +00:00
intptr = &options->num_identity_files;
2021-04-23 19:10:38 +00:00
if (*intptr >= SSH_MAX_IDENTITY_FILES) {
error("%.200s line %d: Too many identity files "
"specified (max %d).", filename, linenum,
SSH_MAX_IDENTITY_FILES);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2015-07-02 13:15:34 +00:00
add_identity_file(options, NULL,
arg, flags & SSHCONF_USERCONF);
2000-02-24 14:29:47 +00:00
}
break;
2016-03-10 20:10:25 +00:00
case oCertificateFile:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
2016-03-10 20:10:25 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2016-03-10 20:10:25 +00:00
if (*activep) {
intptr = &options->num_certificate_files;
if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
2021-04-23 19:10:38 +00:00
error("%.200s line %d: Too many certificate "
2016-03-10 20:10:25 +00:00
"files specified (max %d).",
filename, linenum,
SSH_MAX_CERTIFICATE_FILES);
2021-08-30 19:14:33 +00:00
goto out;
2016-03-10 20:10:25 +00:00
}
add_certificate_file(options, arg,
flags & SSHCONF_USERCONF);
}
break;
case oXAuthLocation:
charptr=&options->xauth_location;
goto parse_string;
2000-02-24 14:29:47 +00:00
case oUser:
charptr = &options->user;
parse_string:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
2011-09-28 08:14:41 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2000-02-24 14:29:47 +00:00
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
2000-02-24 14:29:47 +00:00
break;
case oGlobalKnownHostsFile:
2011-09-28 08:14:41 +00:00
cpptr = (char **)&options->system_hostfiles;
uintptr = &options->num_system_hostfiles;
max_entries = SSH_MAX_HOSTS_FILES;
parse_char_array:
2021-08-30 19:14:33 +00:00
i = 0;
value = *uintptr == 0; /* was array empty when we started? */
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0') {
error("%s line %d: keyword %s empty argument",
filename, linenum, keyword);
goto out;
}
/* Allow "none" only in first position */
if (strcasecmp(arg, "none") == 0) {
if (i > 0 || ac > 0) {
error("%s line %d: keyword %s \"none\" "
"argument must appear alone.",
filename, linenum, keyword);
goto out;
}
}
i++;
if (*activep && value) {
2021-04-23 19:10:38 +00:00
if ((*uintptr) >= max_entries) {
2021-08-30 19:14:33 +00:00
error("%s line %d: too many %s "
"entries.", filename, linenum,
keyword);
goto out;
2021-04-23 19:10:38 +00:00
}
2011-09-28 08:14:41 +00:00
cpptr[(*uintptr)++] = xstrdup(arg);
}
}
2021-08-30 19:14:33 +00:00
break;
2000-02-24 14:29:47 +00:00
case oUserKnownHostsFile:
2011-09-28 08:14:41 +00:00
cpptr = (char **)&options->user_hostfiles;
uintptr = &options->num_user_hostfiles;
max_entries = SSH_MAX_HOSTS_FILES;
goto parse_char_array;
2021-02-14 21:00:25 +00:00
case oHostname:
2000-02-24 14:29:47 +00:00
charptr = &options->hostname;
goto parse_string;
2023-08-10 16:16:53 +00:00
case oTag:
charptr = &options->tag;
goto parse_string;
2001-05-04 04:14:23 +00:00
case oHostKeyAlias:
charptr = &options->host_key_alias;
goto parse_string;
case oPreferredAuthentications:
charptr = &options->preferred_authentications;
goto parse_string;
2002-03-18 10:09:43 +00:00
case oBindAddress:
charptr = &options->bind_address;
goto parse_string;
2018-05-06 12:27:04 +00:00
case oBindInterface:
charptr = &options->bind_interface;
goto parse_string;
2010-03-08 11:19:52 +00:00
case oPKCS11Provider:
charptr = &options->pkcs11_provider;
2002-03-18 10:09:43 +00:00
goto parse_string;
2021-02-14 21:04:52 +00:00
case oSecurityKeyProvider:
charptr = &options->sk_provider;
goto parse_string;
2021-04-23 19:10:38 +00:00
case oKnownHostsCommand:
charptr = &options->known_hosts_command;
goto parse_command;
2000-02-24 14:29:47 +00:00
case oProxyCommand:
2006-03-22 20:41:37 +00:00
charptr = &options->proxy_command;
2017-01-31 12:29:48 +00:00
/* Ignore ProxyCommand if ProxyJump already specified */
if (options->jump_host != NULL)
charptr = &options->jump_host; /* Skip below */
2006-03-22 20:41:37 +00:00
parse_command:
2021-08-30 19:14:33 +00:00
if (str == NULL) {
2021-04-23 19:10:38 +00:00
error("%.200s line %d: Missing argument.",
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2021-08-30 19:14:33 +00:00
len = strspn(str, WHITESPACE "=");
2000-02-24 14:29:47 +00:00
if (*activep && *charptr == NULL)
2021-08-30 19:14:33 +00:00
*charptr = xstrdup(str + len);
argv_consume(&ac);
break;
2000-02-24 14:29:47 +00:00
2017-01-31 12:29:48 +00:00
case oProxyJump:
2021-08-30 19:14:33 +00:00
if (str == NULL) {
2021-04-23 19:10:38 +00:00
error("%.200s line %d: Missing argument.",
2017-01-31 12:29:48 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2017-01-31 12:29:48 +00:00
}
2021-08-30 19:14:33 +00:00
len = strspn(str, WHITESPACE "=");
/* XXX use argv? */
if (parse_jump(str + len, options, *activep) == -1) {
2021-04-23 19:10:38 +00:00
error("%.200s line %d: Invalid ProxyJump \"%s\"",
2021-08-30 19:14:33 +00:00
filename, linenum, str + len);
goto out;
2017-01-31 12:29:48 +00:00
}
2021-08-30 19:14:33 +00:00
argv_consume(&ac);
break;
2017-01-31 12:29:48 +00:00
2000-02-24 14:29:47 +00:00
case oPort:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
2019-02-05 15:03:53 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2019-02-05 15:03:53 +00:00
value = a2port(arg);
2021-04-23 19:10:38 +00:00
if (value <= 0) {
error("%.200s line %d: Bad port '%s'.",
2019-02-05 15:03:53 +00:00
filename, linenum, arg);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2019-02-05 15:03:53 +00:00
if (*activep && options->port == -1)
options->port = value;
break;
case oConnectionAttempts:
intptr = &options->connection_attempts;
2000-02-24 14:29:47 +00:00
parse_int:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if ((errstr = atoi_err(arg, &value)) != NULL) {
error("%s line %d: integer value %s.",
2018-05-06 12:27:04 +00:00
filename, linenum, errstr);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2000-02-24 14:29:47 +00:00
if (*activep && *intptr == -1)
*intptr = value;
break;
case oCiphers:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2021-02-14 21:00:25 +00:00
if (*arg != '-' &&
2021-04-23 19:10:38 +00:00
!ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)){
error("%.200s line %d: Bad SSH2 cipher spec '%s'.",
2002-03-18 10:09:43 +00:00
filename, linenum, arg ? arg : "<NONE>");
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
if (*activep && options->ciphers == NULL)
options->ciphers = xstrdup(arg);
break;
2001-05-04 04:14:23 +00:00
case oMacs:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2021-02-14 21:00:25 +00:00
if (*arg != '-' &&
2021-04-23 19:10:38 +00:00
!mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)) {
error("%.200s line %d: Bad SSH2 MAC spec '%s'.",
2002-03-18 10:09:43 +00:00
filename, linenum, arg ? arg : "<NONE>");
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2001-05-04 04:14:23 +00:00
if (*activep && options->macs == NULL)
options->macs = xstrdup(arg);
break;
2011-02-17 11:47:40 +00:00
case oKexAlgorithms:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
2011-02-17 11:47:40 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2017-08-03 10:10:20 +00:00
if (*arg != '-' &&
2021-02-14 21:00:25 +00:00
!kex_names_valid(*arg == '+' || *arg == '^' ?
2021-04-23 19:10:38 +00:00
arg + 1 : arg)) {
error("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
2011-02-17 11:47:40 +00:00
filename, linenum, arg ? arg : "<NONE>");
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2011-02-17 11:47:40 +00:00
if (*activep && options->kex_algorithms == NULL)
options->kex_algorithms = xstrdup(arg);
break;
2001-05-04 04:14:23 +00:00
case oHostKeyAlgorithms:
2015-08-26 09:25:17 +00:00
charptr = &options->hostkeyalgorithms;
2023-08-10 16:16:53 +00:00
ca_only = 0;
2021-04-23 19:10:38 +00:00
parse_pubkey_algos:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
2015-08-26 09:25:17 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2017-08-03 10:10:20 +00:00
if (*arg != '-' &&
2021-02-14 21:00:25 +00:00
!sshkey_names_valid2(*arg == '+' || *arg == '^' ?
2023-08-10 16:16:53 +00:00
arg + 1 : arg, 1, ca_only)) {
2021-04-23 19:10:38 +00:00
error("%s line %d: Bad key types '%s'.",
filename, linenum, arg ? arg : "<NONE>");
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2015-08-26 09:25:17 +00:00
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
2001-05-04 04:14:23 +00:00
break;
2019-02-05 15:03:53 +00:00
case oCASignatureAlgorithms:
charptr = &options->ca_sign_algorithms;
2023-08-10 16:16:53 +00:00
ca_only = 1;
2021-04-23 19:10:38 +00:00
goto parse_pubkey_algos;
2019-02-05 15:03:53 +00:00
2000-02-24 14:29:47 +00:00
case oLogLevel:
log_level_ptr = &options->log_level;
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
value = log_level_number(arg);
2021-04-23 19:10:38 +00:00
if (value == SYSLOG_LEVEL_NOT_SET) {
error("%.200s line %d: unsupported log level '%s'",
2002-03-18 10:09:43 +00:00
filename, linenum, arg ? arg : "<NONE>");
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
*log_level_ptr = (LogLevel) value;
2000-02-24 14:29:47 +00:00
break;
2018-05-06 12:24:45 +00:00
case oLogFacility:
log_facility_ptr = &options->log_facility;
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2018-05-06 12:24:45 +00:00
value = log_facility_number(arg);
2021-04-23 19:10:38 +00:00
if (value == SYSLOG_FACILITY_NOT_SET) {
error("%.200s line %d: unsupported log facility '%s'",
2018-05-06 12:24:45 +00:00
filename, linenum, arg ? arg : "<NONE>");
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2018-05-06 12:24:45 +00:00
if (*log_facility_ptr == -1)
*log_facility_ptr = (SyslogFacility) value;
break;
2021-04-23 19:10:38 +00:00
case oLogVerbose:
cppptr = &options->log_verbose;
uintptr = &options->num_log_verbose;
2021-08-30 19:14:33 +00:00
i = 0;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0') {
error("%s line %d: keyword %s empty argument",
filename, linenum, keyword);
goto out;
}
/* Allow "none" only in first position */
if (strcasecmp(arg, "none") == 0) {
if (i > 0 || ac > 0) {
error("%s line %d: keyword %s \"none\" "
"argument must appear alone.",
filename, linenum, keyword);
goto out;
}
}
i++;
if (*activep && *uintptr == 0) {
2021-04-23 19:10:38 +00:00
*cppptr = xrecallocarray(*cppptr, *uintptr,
*uintptr + 1, sizeof(**cppptr));
(*cppptr)[(*uintptr)++] = xstrdup(arg);
}
}
2021-08-30 19:14:33 +00:00
break;
2021-04-23 19:10:38 +00:00
2000-02-24 14:29:47 +00:00
case oLocalForward:
2002-03-18 10:09:43 +00:00
case oRemoteForward:
2009-02-24 18:49:27 +00:00
case oDynamicForward:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
2002-03-18 10:09:43 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2005-06-05 15:46:09 +00:00
2018-05-06 12:24:45 +00:00
remotefwd = (opcode == oRemoteForward);
dynamicfwd = (opcode == oDynamicForward);
2009-02-24 18:49:27 +00:00
2018-05-06 12:24:45 +00:00
if (!dynamicfwd) {
2021-08-30 19:14:33 +00:00
arg2 = argv_next(&ac, &av);
2018-05-06 12:24:45 +00:00
if (arg2 == NULL || *arg2 == '\0') {
if (remotefwd)
dynamicfwd = 1;
2021-04-23 19:10:38 +00:00
else {
error("%.200s line %d: Missing target "
2018-05-06 12:24:45 +00:00
"argument.", filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2018-05-06 12:24:45 +00:00
} else {
/* construct a string for parse_forward */
snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg,
arg2);
}
2009-02-24 18:49:27 +00:00
}
2018-05-06 12:24:45 +00:00
if (dynamicfwd)
strlcpy(fwdarg, arg, sizeof(fwdarg));
2005-06-05 15:46:09 +00:00
2021-04-23 19:10:38 +00:00
if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0) {
error("%.200s line %d: Bad forwarding specification.",
2002-03-18 10:09:43 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2005-06-05 15:46:09 +00:00
2002-03-18 10:09:43 +00:00
if (*activep) {
2018-05-06 12:24:45 +00:00
if (remotefwd) {
2005-06-05 15:46:09 +00:00
add_remote_forward(options, &fwd);
2018-05-06 12:24:45 +00:00
} else {
add_local_forward(options, &fwd);
}
2002-03-18 10:09:43 +00:00
}
2000-02-24 14:29:47 +00:00
break;
2021-04-23 19:10:38 +00:00
case oPermitRemoteOpen:
uintptr = &options->num_permitted_remote_opens;
cppptr = &options->permitted_remote_opens;
2024-03-17 17:47:10 +00:00
found = *uintptr == 0;
2021-08-30 19:14:33 +00:00
while ((arg = argv_next(&ac, &av)) != NULL) {
2021-04-23 19:10:38 +00:00
arg2 = xstrdup(arg);
/* Allow any/none only in first position */
if (strcasecmp(arg, "none") == 0 ||
strcasecmp(arg, "any") == 0) {
2024-03-17 17:47:10 +00:00
if (nstrs > 0 || ac > 0) {
error("%s line %d: keyword %s \"%s\" "
"argument must appear alone.",
filename, linenum, keyword, arg);
2023-08-10 16:16:53 +00:00
free(arg2);
goto out;
}
} else {
p = hpdelim(&arg);
if (p == NULL) {
fatal("%s line %d: missing host in %s",
filename, linenum,
lookup_opcode_name(opcode));
}
p = cleanhostname(p);
/*
* don't want to use permitopen_port to avoid
* dependency on channels.[ch] here.
*/
if (arg == NULL || (strcmp(arg, "*") != 0 &&
a2port(arg) <= 0)) {
fatal("%s line %d: bad port number "
"in %s", filename, linenum,
lookup_opcode_name(opcode));
}
2021-04-23 19:10:38 +00:00
}
2024-03-17 17:47:10 +00:00
opt_array_append(filename, linenum,
lookup_opcode_name(opcode),
&strs, &nstrs, arg2);
2021-04-23 19:10:38 +00:00
free(arg2);
}
2024-03-17 17:47:10 +00:00
if (nstrs == 0)
fatal("%s line %d: missing %s specification",
filename, linenum, lookup_opcode_name(opcode));
2024-03-17 17:47:10 +00:00
if (found && *activep) {
*cppptr = strs;
*uintptr = nstrs;
strs = NULL; /* transferred */
nstrs = 0;
}
2021-04-23 19:10:38 +00:00
break;
2002-03-18 10:09:43 +00:00
case oClearAllForwardings:
intptr = &options->clear_forwardings;
goto parse_flag;
2000-02-24 14:29:47 +00:00
case oHost:
2021-04-23 19:10:38 +00:00
if (cmdline) {
error("Host directive not supported as a command-line "
2014-01-30 10:56:49 +00:00
"option");
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2000-02-24 14:29:47 +00:00
*activep = 0;
2011-09-28 08:14:41 +00:00
arg2 = NULL;
2021-08-30 19:14:33 +00:00
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0') {
error("%s line %d: keyword %s empty argument",
filename, linenum, keyword);
goto out;
}
if ((flags & SSHCONF_NEVERMATCH) != 0) {
argv_consume(&ac);
2017-01-31 12:29:48 +00:00
break;
2021-08-30 19:14:33 +00:00
}
2011-09-28 08:14:41 +00:00
negated = *arg == '!';
if (negated)
arg++;
if (match_pattern(host, arg)) {
2011-09-28 08:14:41 +00:00
if (negated) {
debug("%.200s line %d: Skipping Host "
"block because of negated match "
"for %.100s", filename, linenum,
arg);
*activep = 0;
2021-08-30 19:14:33 +00:00
argv_consume(&ac);
2011-09-28 08:14:41 +00:00
break;
}
if (!*activep)
arg2 = arg; /* logged below */
2000-02-24 14:29:47 +00:00
*activep = 1;
}
2011-09-28 08:14:41 +00:00
}
if (*activep)
debug("%.200s line %d: Applying options for %.100s",
filename, linenum, arg2);
2021-08-30 19:14:33 +00:00
break;
2000-02-24 14:29:47 +00:00
2014-01-30 10:56:49 +00:00
case oMatch:
2021-04-23 19:10:38 +00:00
if (cmdline) {
error("Host directive not supported as a command-line "
2014-01-30 10:56:49 +00:00
"option");
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2021-08-30 19:14:33 +00:00
value = match_cfg_line(options, &str, pw, host, original_host,
2020-02-14 19:47:15 +00:00
flags & SSHCONF_FINAL, want_final_pass,
filename, linenum);
2021-04-23 19:10:38 +00:00
if (value < 0) {
error("%.200s line %d: Bad Match condition", filename,
2014-01-30 10:56:49 +00:00
linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2017-01-31 12:29:48 +00:00
*activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
2021-08-30 19:14:33 +00:00
/*
* If match_cfg_line() didn't consume all its arguments then
* arrange for the extra arguments check below to fail.
*/
if (str == NULL || *str == '\0')
argv_consume(&ac);
2014-01-30 10:56:49 +00:00
break;
2000-02-24 14:29:47 +00:00
case oEscapeChar:
intptr = &options->escape_char;
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2015-07-02 13:18:50 +00:00
if (strcmp(arg, "none") == 0)
value = SSH_ESCAPECHAR_NONE;
else if (arg[1] == '\0')
value = (u_char) arg[0];
else if (arg[0] == '^' && arg[2] == 0 &&
2001-05-04 04:14:23 +00:00
(u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
value = (u_char) arg[1] & 31;
2000-02-24 14:29:47 +00:00
else {
2021-04-23 19:10:38 +00:00
error("%.200s line %d: Bad escape character.",
2002-03-18 10:09:43 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2000-02-24 14:29:47 +00:00
}
if (*activep && *intptr == -1)
*intptr = value;
break;
case oAddressFamily:
intptr = &options->address_family;
2014-01-30 10:56:49 +00:00
multistate_ptr = multistate_addressfamily;
goto parse_multistate;
2003-04-23 17:13:13 +00:00
case oEnableSSHKeysign:
intptr = &options->enable_ssh_keysign;
goto parse_flag;
2004-04-20 09:46:41 +00:00
case oIdentitiesOnly:
intptr = &options->identities_only;
goto parse_flag;
2004-02-26 10:52:33 +00:00
case oServerAliveInterval:
intptr = &options->server_alive_interval;
goto parse_time;
case oServerAliveCountMax:
intptr = &options->server_alive_count_max;
goto parse_int;
2004-10-28 16:11:31 +00:00
case oSendEnv:
2024-03-17 17:47:10 +00:00
/* XXX appends to list; doesn't respect first-match-wins */
2021-08-30 19:14:33 +00:00
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0' || strchr(arg, '=') != NULL) {
2021-04-23 19:10:38 +00:00
error("%s line %d: Invalid environment name.",
2004-10-28 16:11:31 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2024-03-17 17:47:10 +00:00
found = 1;
2005-06-05 15:46:09 +00:00
if (!*activep)
continue;
2018-08-28 10:47:58 +00:00
if (*arg == '-') {
/* Removing an env var */
rm_env(options, arg, filename, linenum);
continue;
}
2022-10-04 15:10:40 +00:00
opt_array_append(filename, linenum,
lookup_opcode_name(opcode),
&options->send_env, &options->num_send_env, arg);
2018-08-28 10:47:58 +00:00
}
2024-03-17 17:47:10 +00:00
if (!found) {
fatal("%s line %d: no %s specified",
filename, linenum, keyword);
}
2018-08-28 10:47:58 +00:00
break;
case oSetEnv:
2024-03-17 17:47:10 +00:00
found = options->num_setenv == 0;
2021-08-30 19:14:33 +00:00
while ((arg = argv_next(&ac, &av)) != NULL) {
2021-04-23 19:10:38 +00:00
if (strchr(arg, '=') == NULL) {
error("%s line %d: Invalid SetEnv.",
2018-08-28 10:47:58 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2024-03-17 17:47:10 +00:00
if (lookup_setenv_in_list(arg, strs, nstrs) != NULL) {
2022-10-04 15:10:40 +00:00
debug2("%s line %d: ignoring duplicate env "
"name \"%.64s\"", filename, linenum, arg);
continue;
2021-04-23 19:10:38 +00:00
}
2022-10-04 15:10:40 +00:00
opt_array_append(filename, linenum,
lookup_opcode_name(opcode),
2024-03-17 17:47:10 +00:00
&strs, &nstrs, arg);
}
if (nstrs == 0) {
fatal("%s line %d: no %s specified",
filename, linenum, keyword);
}
if (found && *activep) {
options->setenv = strs;
options->num_setenv = nstrs;
strs = NULL; /* transferred */
nstrs = 0;
2004-10-28 16:11:31 +00:00
}
break;
case oControlPath:
charptr = &options->control_path;
goto parse_string;
case oControlMaster:
intptr = &options->control_master;
2014-01-30 10:56:49 +00:00
multistate_ptr = multistate_controlmaster;
goto parse_multistate;
2004-10-28 16:11:31 +00:00
2010-11-08 10:45:44 +00:00
case oControlPersist:
/* no/false/yes/true, or a time spec */
intptr = &options->control_persist;
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing ControlPersist"
2010-11-08 10:45:44 +00:00
" argument.", filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2010-11-08 10:45:44 +00:00
value = 0;
value2 = 0; /* timeout */
if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
value = 0;
else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
value = 1;
else if ((value2 = convtime(arg)) >= 0)
value = 1;
2021-04-23 19:10:38 +00:00
else {
error("%.200s line %d: Bad ControlPersist argument.",
2010-11-08 10:45:44 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2010-11-08 10:45:44 +00:00
if (*activep && *intptr == -1) {
*intptr = value;
options->control_persist_timeout = value2;
}
break;
2005-06-05 15:46:09 +00:00
case oHashKnownHosts:
intptr = &options->hash_known_hosts;
goto parse_flag;
2006-03-22 20:41:37 +00:00
case oTunnel:
intptr = &options->tun_open;
2014-01-30 10:56:49 +00:00
multistate_ptr = multistate_tunnel;
goto parse_multistate;
2006-03-22 20:41:37 +00:00
case oTunnelDevice:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2006-03-22 20:41:37 +00:00
value = a2tun(arg, &value2);
2021-04-23 19:10:38 +00:00
if (value == SSH_TUNID_ERR) {
error("%.200s line %d: Bad tun device.",
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2021-08-30 19:14:33 +00:00
if (*activep && options->tun_local == -1) {
2006-03-22 20:41:37 +00:00
options->tun_local = value;
options->tun_remote = value2;
}
break;
case oLocalCommand:
charptr = &options->local_command;
goto parse_command;
case oPermitLocalCommand:
intptr = &options->permit_local_command;
goto parse_flag;
2018-05-06 12:24:45 +00:00
case oRemoteCommand:
charptr = &options->remote_command;
goto parse_command;
2008-07-23 09:33:08 +00:00
case oVisualHostKey:
intptr = &options->visual_host_key;
goto parse_flag;
2017-01-31 12:29:48 +00:00
case oInclude:
2021-04-23 19:10:38 +00:00
if (cmdline) {
error("Include directive not supported as a "
2017-01-31 12:29:48 +00:00
"command-line option");
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2017-01-31 12:29:48 +00:00
value = 0;
2021-08-30 19:14:33 +00:00
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0') {
error("%s line %d: keyword %s empty argument",
filename, linenum, keyword);
goto out;
}
2017-01-31 12:29:48 +00:00
/*
* Ensure all paths are anchored. User configuration
* files may begin with '~/' but system configurations
* must not. If the path is relative, then treat it
* as living in ~/.ssh for user configurations or
* /etc/ssh for system ones.
*/
2021-04-23 19:10:38 +00:00
if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0) {
error("%.200s line %d: bad include path %s.",
2017-01-31 12:29:48 +00:00
filename, linenum, arg);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2020-02-14 19:47:15 +00:00
if (!path_absolute(arg) && *arg != '~') {
2017-01-31 12:29:48 +00:00
xasprintf(&arg2, "%s/%s",
(flags & SSHCONF_USERCONF) ?
"~/" _PATH_SSH_USER_DIR : SSHDIR, arg);
} else
arg2 = xstrdup(arg);
memset(&gl, 0, sizeof(gl));
r = glob(arg2, GLOB_TILDE, NULL, &gl);
if (r == GLOB_NOMATCH) {
debug("%.200s line %d: include %s matched no "
"files",filename, linenum, arg2);
2017-08-03 10:10:20 +00:00
free(arg2);
2017-01-31 12:29:48 +00:00
continue;
2021-04-23 19:10:38 +00:00
} else if (r != 0) {
error("%.200s line %d: glob failed for %s.",
2017-01-31 12:29:48 +00:00
filename, linenum, arg2);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2017-01-31 12:29:48 +00:00
free(arg2);
oactive = *activep;
2021-02-14 21:04:52 +00:00
for (i = 0; i < gl.gl_pathc; i++) {
2017-01-31 12:29:48 +00:00
debug3("%.200s line %d: Including file %s "
"depth %d%s", filename, linenum,
gl.gl_pathv[i], depth,
oactive ? "" : " (parse only)");
r = read_config_file_depth(gl.gl_pathv[i],
pw, host, original_host, options,
flags | SSHCONF_CHECKPERM |
(oactive ? 0 : SSHCONF_NEVERMATCH),
2020-02-14 19:47:15 +00:00
activep, want_final_pass, depth + 1);
2017-08-03 10:10:20 +00:00
if (r != 1 && errno != ENOENT) {
2021-04-23 19:10:38 +00:00
error("Can't open user config file "
2017-08-03 10:10:20 +00:00
"%.100s: %.100s", gl.gl_pathv[i],
strerror(errno));
2021-04-23 19:10:38 +00:00
globfree(&gl);
2021-08-30 19:14:33 +00:00
goto out;
2017-08-03 10:10:20 +00:00
}
2017-01-31 12:29:48 +00:00
/*
* don't let Match in includes clobber the
* containing file's Match state.
*/
*activep = oactive;
if (r != 1)
value = -1;
}
globfree(&gl);
}
if (value != 0)
2021-08-30 19:14:33 +00:00
ret = value;
2017-01-31 12:29:48 +00:00
break;
2011-02-17 11:47:40 +00:00
case oIPQoS:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if ((value = parse_ipqos(arg)) == -1) {
error("%s line %d: Bad IPQoS value: %s",
2011-02-17 11:47:40 +00:00
filename, linenum, arg);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2011-02-17 11:47:40 +00:00
if (arg == NULL)
value2 = value;
2021-04-23 19:10:38 +00:00
else if ((value2 = parse_ipqos(arg)) == -1) {
error("%s line %d: Bad IPQoS value: %s",
2011-02-17 11:47:40 +00:00
filename, linenum, arg);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2021-08-30 19:14:33 +00:00
if (*activep && options->ip_qos_interactive == -1) {
2011-02-17 11:47:40 +00:00
options->ip_qos_interactive = value;
options->ip_qos_bulk = value2;
}
break;
2011-09-28 08:14:41 +00:00
case oRequestTTY:
intptr = &options->request_tty;
2014-01-30 10:56:49 +00:00
multistate_ptr = multistate_requesttty;
goto parse_multistate;
2021-08-30 19:14:33 +00:00
case oSessionType:
intptr = &options->session_type;
multistate_ptr = multistate_sessiontype;
goto parse_multistate;
case oStdinNull:
intptr = &options->stdin_null;
goto parse_flag;
case oForkAfterAuthentication:
intptr = &options->fork_after_authentication;
goto parse_flag;
2013-09-18 17:27:38 +00:00
case oIgnoreUnknown:
charptr = &options->ignored_unknown;
goto parse_string;
2014-01-30 10:56:49 +00:00
case oProxyUseFdpass:
intptr = &options->proxy_use_fdpass;
goto parse_flag;
case oCanonicalDomains:
2024-03-17 17:47:10 +00:00
found = options->num_canonical_domains == 0;
2021-08-30 19:14:33 +00:00
while ((arg = argv_next(&ac, &av)) != NULL) {
/* Allow "none" only in first position */
if (strcasecmp(arg, "none") == 0) {
2024-03-17 17:47:10 +00:00
if (nstrs > 0 || ac > 0) {
2021-08-30 19:14:33 +00:00
error("%s line %d: keyword %s \"none\" "
"argument must appear alone.",
filename, linenum, keyword);
goto out;
}
}
2018-05-06 12:27:04 +00:00
if (!valid_domain(arg, 1, &errstr)) {
2021-04-23 19:10:38 +00:00
error("%s line %d: %s", filename, linenum,
2018-05-06 12:27:04 +00:00
errstr);
2021-08-30 19:14:33 +00:00
goto out;
2018-05-06 12:27:04 +00:00
}
2024-03-17 17:47:10 +00:00
opt_array_append(filename, linenum, keyword,
&strs, &nstrs, arg);
}
if (nstrs == 0) {
fatal("%s line %d: no %s specified",
filename, linenum, keyword);
}
if (found && *activep) {
options->canonical_domains = strs;
options->num_canonical_domains = nstrs;
strs = NULL; /* transferred */
nstrs = 0;
2014-01-30 10:56:49 +00:00
}
break;
case oCanonicalizePermittedCNAMEs:
2024-03-17 17:47:10 +00:00
found = options->num_permitted_cnames == 0;
2021-08-30 19:14:33 +00:00
while ((arg = argv_next(&ac, &av)) != NULL) {
2021-11-04 17:16:52 +00:00
/*
* Either 'none' (only in first position), '*' for
* everything or 'list:list'
*/
if (strcasecmp(arg, "none") == 0) {
2024-03-17 17:47:10 +00:00
if (ncnames > 0 || ac > 0) {
2021-11-04 17:16:52 +00:00
error("%s line %d: keyword %s \"none\" "
"argument must appear alone.",
filename, linenum, keyword);
goto out;
}
arg2 = "";
} else if (strcmp(arg, "*") == 0) {
2014-01-30 10:56:49 +00:00
arg2 = arg;
2021-11-04 17:16:52 +00:00
} else {
2014-01-30 10:56:49 +00:00
lowercase(arg);
if ((arg2 = strchr(arg, ':')) == NULL ||
arg2[1] == '\0') {
2021-04-23 19:10:38 +00:00
error("%s line %d: "
2014-01-30 10:56:49 +00:00
"Invalid permitted CNAME \"%s\"",
filename, linenum, arg);
2021-08-30 19:14:33 +00:00
goto out;
2014-01-30 10:56:49 +00:00
}
*arg2 = '\0';
arg2++;
}
2024-03-17 17:47:10 +00:00
cnames = xrecallocarray(cnames, ncnames, ncnames + 1,
sizeof(*cnames));
cnames[ncnames].source_list = xstrdup(arg);
cnames[ncnames].target_list = xstrdup(arg2);
ncnames++;
}
if (ncnames == 0) {
fatal("%s line %d: no %s specified",
filename, linenum, keyword);
}
if (found && *activep) {
options->permitted_cnames = cnames;
options->num_permitted_cnames = ncnames;
cnames = NULL; /* transferred */
ncnames = 0;
}
/* un-transferred cnames is cleaned up before exit */
2014-01-30 10:56:49 +00:00
break;
case oCanonicalizeHostname:
intptr = &options->canonicalize_hostname;
multistate_ptr = multistate_canonicalizehostname;
goto parse_multistate;
case oCanonicalizeMaxDots:
intptr = &options->canonicalize_max_dots;
goto parse_int;
case oCanonicalizeFallbackLocal:
intptr = &options->canonicalize_fallback_local;
goto parse_flag;
2015-01-05 16:09:55 +00:00
case oStreamLocalBindMask:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing StreamLocalBindMask "
"argument.", filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2015-01-05 16:09:55 +00:00
/* Parse mode in octal format */
value = strtol(arg, &endofnumber, 8);
2021-04-23 19:10:38 +00:00
if (arg == endofnumber || value < 0 || value > 0777) {
error("%.200s line %d: Bad mask.", filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2015-01-05 16:09:55 +00:00
options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
break;
case oStreamLocalBindUnlink:
intptr = &options->fwd_opts.streamlocal_bind_unlink;
goto parse_flag;
2015-07-02 13:15:34 +00:00
case oRevokedHostKeys:
charptr = &options->revoked_host_keys;
goto parse_string;
case oFingerprintHash:
intptr = &options->fingerprint_hash;
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
2015-07-02 13:15:34 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
if ((value = ssh_digest_alg_by_name(arg)) == -1) {
error("%.200s line %d: Invalid hash algorithm \"%s\".",
2015-07-02 13:15:34 +00:00
filename, linenum, arg);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2015-07-02 13:15:34 +00:00
if (*activep && *intptr == -1)
*intptr = value;
break;
case oUpdateHostkeys:
intptr = &options->update_hostkeys;
multistate_ptr = multistate_yesnoask;
goto parse_multistate;
2021-04-23 19:10:38 +00:00
case oHostbasedAcceptedAlgorithms:
charptr = &options->hostbased_accepted_algos;
2023-08-10 16:16:53 +00:00
ca_only = 0;
2021-04-23 19:10:38 +00:00
goto parse_pubkey_algos;
2015-08-26 09:25:17 +00:00
2021-04-23 19:10:38 +00:00
case oPubkeyAcceptedAlgorithms:
charptr = &options->pubkey_accepted_algos;
2023-08-10 16:16:53 +00:00
ca_only = 0;
2021-04-23 19:10:38 +00:00
goto parse_pubkey_algos;
2015-07-02 13:15:34 +00:00
2016-03-10 20:10:25 +00:00
case oAddKeysToAgent:
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
arg2 = argv_next(&ac, &av);
2021-02-14 21:09:58 +00:00
value = parse_multistate_value(arg, filename, linenum,
2021-04-23 19:13:32 +00:00
multistate_yesnoaskconfirm);
2021-02-14 21:09:58 +00:00
value2 = 0; /* unlimited lifespan by default */
if (value == 3 && arg2 != NULL) {
/* allow "AddKeysToAgent confirm 5m" */
2023-03-16 12:41:22 +00:00
if ((value2 = convtime(arg2)) == -1) {
2021-04-23 19:10:38 +00:00
error("%s line %d: invalid time value.",
2021-02-14 21:09:58 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2021-02-14 21:09:58 +00:00
} else if (value == -1 && arg2 == NULL) {
2023-03-16 12:41:22 +00:00
if ((value2 = convtime(arg)) == -1) {
2021-04-23 19:10:38 +00:00
error("%s line %d: unsupported option",
2021-02-14 21:09:58 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2021-02-14 21:09:58 +00:00
value = 1; /* yes */
} else if (value == -1 || arg2 != NULL) {
2021-04-23 19:10:38 +00:00
error("%s line %d: unsupported option",
2021-02-14 21:09:58 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-02-14 21:09:58 +00:00
}
if (*activep && options->add_keys_to_agent == -1) {
options->add_keys_to_agent = value;
options->add_keys_to_agent_lifespan = value2;
}
break;
2016-03-10 20:10:25 +00:00
2017-01-31 12:29:48 +00:00
case oIdentityAgent:
charptr = &options->identity_agent;
2021-08-30 19:14:33 +00:00
arg = argv_next(&ac, &av);
2021-04-23 19:10:38 +00:00
if (!arg || *arg == '\0') {
error("%.200s line %d: Missing argument.",
2019-02-05 15:03:53 +00:00
filename, linenum);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2021-02-14 21:04:52 +00:00
parse_agent_path:
2019-02-05 15:03:53 +00:00
/* Extra validation if the string represents an env var. */
2021-04-23 19:10:38 +00:00
if ((arg2 = dollar_expand(&r, arg)) == NULL || r) {
error("%.200s line %d: Invalid environment expansion "
2021-02-14 21:09:58 +00:00
"%s.", filename, linenum, arg);
2021-08-30 19:14:33 +00:00
goto out;
2021-04-23 19:10:38 +00:00
}
2021-02-14 21:09:58 +00:00
free(arg2);
/* check for legacy environment format */
2021-04-23 19:10:38 +00:00
if (arg[0] == '$' && arg[1] != '{' &&
!valid_env_name(arg + 1)) {
error("%.200s line %d: Invalid environment name %s.",
2019-02-05 15:03:53 +00:00
filename, linenum, arg);
2021-08-30 19:14:33 +00:00
goto out;
2019-02-05 15:03:53 +00:00
}
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
break;
2017-01-31 12:29:48 +00:00
2023-02-05 18:04:12 +00:00
case oEnableEscapeCommandline:
intptr = &options->enable_escape_commandline;
goto parse_flag;
2022-10-04 15:10:40 +00:00
case oRequiredRSASize:
intptr = &options->required_rsa_size;
goto parse_int;
2023-10-04 12:06:41 +00:00
case oObscureKeystrokeTiming:
value = -1;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (value != -1) {
error("%s line %d: invalid arguments",
filename, linenum);
goto out;
}
if (strcmp(arg, "yes") == 0 ||
strcmp(arg, "true") == 0)
value = SSH_KEYSTROKE_DEFAULT_INTERVAL_MS;
else if (strcmp(arg, "no") == 0 ||
strcmp(arg, "false") == 0)
value = 0;
else if (strncmp(arg, "interval:", 9) == 0) {
if ((errstr = atoi_err(arg + 9,
&value)) != NULL) {
error("%s line %d: integer value %s.",
filename, linenum, errstr);
goto out;
}
if (value <= 0 || value > 1000) {
error("%s line %d: value out of range.",
filename, linenum);
goto out;
}
} else {
error("%s line %d: unsupported argument \"%s\"",
filename, linenum, arg);
goto out;
}
}
if (value == -1) {
error("%s line %d: missing argument",
filename, linenum);
goto out;
}
intptr = &options->obscure_keystroke_timing_interval;
if (*activep && *intptr == -1)
*intptr = value;
break;
2023-12-18 15:59:40 +00:00
case oChannelTimeout:
2024-03-17 17:47:10 +00:00
found = options->num_channel_timeouts == 0;
2023-12-18 15:59:40 +00:00
while ((arg = argv_next(&ac, &av)) != NULL) {
/* Allow "none" only in first position */
if (strcasecmp(arg, "none") == 0) {
2024-03-17 17:47:10 +00:00
if (nstrs > 0 || ac > 0) {
2023-12-18 15:59:40 +00:00
error("%s line %d: keyword %s \"none\" "
"argument must appear alone.",
filename, linenum, keyword);
goto out;
}
} else if (parse_pattern_interval(arg,
NULL, NULL) != 0) {
fatal("%s line %d: invalid channel timeout %s",
filename, linenum, arg);
}
opt_array_append(filename, linenum, keyword,
2024-03-17 17:47:10 +00:00
&strs, &nstrs, arg);
}
if (nstrs == 0) {
fatal("%s line %d: no %s specified",
filename, linenum, keyword);
}
if (found && *activep) {
options->channel_timeouts = strs;
options->num_channel_timeouts = nstrs;
strs = NULL; /* transferred */
nstrs = 0;
2023-12-18 15:59:40 +00:00
}
break;
case oDeprecated:
debug("%s line %d: Deprecated option \"%s\"",
filename, linenum, keyword);
2021-08-30 19:14:33 +00:00
argv_consume(&ac);
break;
case oUnsupported:
error("%s line %d: Unsupported option \"%s\"",
filename, linenum, keyword);
2021-08-30 19:14:33 +00:00
argv_consume(&ac);
break;
2000-02-24 14:29:47 +00:00
default:
2021-04-23 19:10:38 +00:00
error("%s line %d: Unimplemented opcode %d",
filename, linenum, opcode);
2021-08-30 19:14:33 +00:00
goto out;
2000-02-24 14:29:47 +00:00
}
/* Check that there is no garbage at end of line. */
2021-08-30 19:14:33 +00:00
if (ac > 0) {
error("%.200s line %d: keyword %s extra arguments "
"at end of line", filename, linenum, keyword);
goto out;
}
2021-08-30 19:14:33 +00:00
/* success */
ret = 0;
out:
2024-03-17 17:47:10 +00:00
free_canon_cnames(cnames, ncnames);
opt_array_free2(strs, NULL, nstrs);
2021-08-30 19:14:33 +00:00
argv_free(oav, oac);
return ret;
2000-02-24 14:29:47 +00:00
}
/*
* Reads the config file and modifies the options accordingly. Options
* should already be initialized before this call. This never returns if
2002-03-18 10:09:43 +00:00
* there is an error. If the file does not exist, this returns 0.
2000-02-24 14:29:47 +00:00
*/
2002-03-18 10:09:43 +00:00
int
2014-01-30 10:56:49 +00:00
read_config_file(const char *filename, struct passwd *pw, const char *host,
2020-02-14 19:47:15 +00:00
const char *original_host, Options *options, int flags,
int *want_final_pass)
2017-01-31 12:29:48 +00:00
{
int active = 1;
return read_config_file_depth(filename, pw, host, original_host,
2020-02-14 19:47:15 +00:00
options, flags, &active, want_final_pass, 0);
2017-01-31 12:29:48 +00:00
}
#define READCONF_MAX_DEPTH 16
static int
read_config_file_depth(const char *filename, struct passwd *pw,
const char *host, const char *original_host, Options *options,
2020-02-14 19:47:15 +00:00
int flags, int *activep, int *want_final_pass, int depth)
2000-02-24 14:29:47 +00:00
{
FILE *f;
2018-08-28 10:47:58 +00:00
char *line = NULL;
size_t linesize = 0;
2017-01-31 12:29:48 +00:00
int linenum;
2000-02-24 14:29:47 +00:00
int bad_options = 0;
2017-01-31 12:29:48 +00:00
if (depth < 0 || depth > READCONF_MAX_DEPTH)
fatal("Too many recursive configuration includes");
2004-10-28 16:11:31 +00:00
if ((f = fopen(filename, "r")) == NULL)
2002-03-18 10:09:43 +00:00
return 0;
2000-02-24 14:29:47 +00:00
if (flags & SSHCONF_CHECKPERM) {
2004-10-28 16:11:31 +00:00
struct stat sb;
if (fstat(fileno(f), &sb) == -1)
fatal("fstat %s: %s", filename, strerror(errno));
if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
(sb.st_mode & 022) != 0))
fatal("Bad owner or permissions on %s", filename);
}
2000-02-24 14:29:47 +00:00
debug("Reading configuration data %.200s", filename);
/*
* Mark that we are now processing the options. This flag is turned
* on/off by Host specifications.
*/
linenum = 0;
2018-08-28 10:47:58 +00:00
while (getline(&line, &linesize, f) != -1) {
2000-02-24 14:29:47 +00:00
/* Update line number counter. */
linenum++;
2021-04-23 19:10:38 +00:00
/*
* Trim out comments and strip whitespace.
* NB - preserve newlines, they are needed to reproduce
* line numbers later for error messages.
*/
2017-01-31 12:29:48 +00:00
if (process_config_line_depth(options, pw, host, original_host,
2020-02-14 19:47:15 +00:00
line, filename, linenum, activep, flags, want_final_pass,
depth) != 0)
2000-02-24 14:29:47 +00:00
bad_options++;
}
2018-08-28 10:47:58 +00:00
free(line);
2000-02-24 14:29:47 +00:00
fclose(f);
if (bad_options > 0)
2001-05-04 04:14:23 +00:00
fatal("%s: terminating, %d bad configuration options",
2002-03-18 10:09:43 +00:00
filename, bad_options);
return 1;
2000-02-24 14:29:47 +00:00
}
2014-03-22 15:23:38 +00:00
/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
int
option_clear_or_none(const char *o)
{
return o == NULL || strcasecmp(o, "none") == 0;
}
2021-11-04 17:16:52 +00:00
/*
* Returns 1 if CanonicalizePermittedCNAMEs have been specified, 0 otherwise.
* Allowed to be called on non-final configuration.
*/
int
config_has_permitted_cnames(Options *options)
{
if (options->num_permitted_cnames == 1 &&
strcasecmp(options->permitted_cnames[0].source_list, "none") == 0 &&
strcmp(options->permitted_cnames[0].target_list, "") == 0)
return 0;
return options->num_permitted_cnames > 0;
}
2000-02-24 14:29:47 +00:00
/*
* Initializes options to special values that indicate that they have not yet
* been set. Read_config_file will only set options with this value. Options
* are processed in the following order: command line, user config file,
* system config file. Last, fill_default_options is called.
*/
void
2000-02-24 14:29:47 +00:00
initialize_options(Options * options)
{
memset(options, 'X', sizeof(*options));
2023-02-05 18:04:12 +00:00
options->host_arg = NULL;
2000-02-24 14:29:47 +00:00
options->forward_agent = -1;
2021-02-14 21:04:52 +00:00
options->forward_agent_sock_path = NULL;
2000-02-24 14:29:47 +00:00
options->forward_x11 = -1;
2004-02-26 10:52:33 +00:00
options->forward_x11_trusted = -1;
2010-11-08 10:45:44 +00:00
options->forward_x11_timeout = -1;
2017-01-31 12:29:48 +00:00
options->stdio_forward_host = NULL;
options->stdio_forward_port = 0;
options->clear_forwardings = -1;
2006-09-30 13:38:06 +00:00
options->exit_on_forward_failure = -1;
options->xauth_location = NULL;
2015-01-05 16:09:55 +00:00
options->fwd_opts.gateway_ports = -1;
options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
options->fwd_opts.streamlocal_bind_unlink = -1;
2001-05-04 04:14:23 +00:00
options->pubkey_authentication = -1;
options->gss_authentication = -1;
options->gss_deleg_creds = -1;
2000-02-24 14:29:47 +00:00
options->password_authentication = -1;
options->kbd_interactive_authentication = -1;
options->kbd_interactive_devices = NULL;
2001-05-04 04:14:23 +00:00
options->hostbased_authentication = -1;
2000-02-24 14:29:47 +00:00
options->batch_mode = -1;
options->check_host_ip = -1;
options->strict_host_key_checking = -1;
options->compression = -1;
2004-02-26 10:52:33 +00:00
options->tcp_keep_alive = -1;
2000-02-24 14:29:47 +00:00
options->port = -1;
options->address_family = -1;
2000-02-24 14:29:47 +00:00
options->connection_attempts = -1;
options->connection_timeout = -1;
2000-02-24 14:29:47 +00:00
options->number_of_password_prompts = -1;
options->ciphers = NULL;
2001-05-04 04:14:23 +00:00
options->macs = NULL;
2011-02-17 11:47:40 +00:00
options->kex_algorithms = NULL;
2001-05-04 04:14:23 +00:00
options->hostkeyalgorithms = NULL;
2019-02-05 15:03:53 +00:00
options->ca_sign_algorithms = NULL;
2000-02-24 14:29:47 +00:00
options->num_identity_files = 0;
2021-04-23 19:10:38 +00:00
memset(options->identity_keys, 0, sizeof(options->identity_keys));
2016-03-10 20:10:25 +00:00
options->num_certificate_files = 0;
2021-04-23 19:10:38 +00:00
memset(options->certificates, 0, sizeof(options->certificates));
2000-02-24 14:29:47 +00:00
options->hostname = NULL;
2001-05-04 04:14:23 +00:00
options->host_key_alias = NULL;
2000-02-24 14:29:47 +00:00
options->proxy_command = NULL;
2017-01-31 12:29:48 +00:00
options->jump_user = NULL;
options->jump_host = NULL;
options->jump_port = -1;
options->jump_extra = NULL;
2000-02-24 14:29:47 +00:00
options->user = NULL;
options->escape_char = -1;
2011-09-28 08:14:41 +00:00
options->num_system_hostfiles = 0;
options->num_user_hostfiles = 0;
2010-11-08 10:45:44 +00:00
options->local_forwards = NULL;
2000-02-24 14:29:47 +00:00
options->num_local_forwards = 0;
2010-11-08 10:45:44 +00:00
options->remote_forwards = NULL;
2000-02-24 14:29:47 +00:00
options->num_remote_forwards = 0;
2021-04-23 19:10:38 +00:00
options->permitted_remote_opens = NULL;
options->num_permitted_remote_opens = 0;
2018-05-06 12:24:45 +00:00
options->log_facility = SYSLOG_FACILITY_NOT_SET;
2002-03-18 10:09:43 +00:00
options->log_level = SYSLOG_LEVEL_NOT_SET;
2021-04-23 19:10:38 +00:00
options->num_log_verbose = 0;
options->log_verbose = NULL;
2001-05-04 04:14:23 +00:00
options->preferred_authentications = NULL;
2002-03-18 10:09:43 +00:00
options->bind_address = NULL;
2018-05-06 12:27:04 +00:00
options->bind_interface = NULL;
2010-03-08 11:19:52 +00:00
options->pkcs11_provider = NULL;
2021-02-14 21:04:52 +00:00
options->sk_provider = NULL;
2003-04-23 17:13:13 +00:00
options->enable_ssh_keysign = - 1;
2002-03-18 10:09:43 +00:00
options->no_host_authentication_for_localhost = - 1;
2004-04-20 09:46:41 +00:00
options->identities_only = - 1;
options->rekey_limit = - 1;
2013-09-18 17:27:38 +00:00
options->rekey_interval = -1;
options->verify_host_key_dns = -1;
2004-02-26 10:52:33 +00:00
options->server_alive_interval = -1;
options->server_alive_count_max = -1;
2018-08-28 10:47:58 +00:00
options->send_env = NULL;
2004-10-28 16:11:31 +00:00
options->num_send_env = 0;
2018-08-28 10:47:58 +00:00
options->setenv = NULL;
options->num_setenv = 0;
2004-10-28 16:11:31 +00:00
options->control_path = NULL;
options->control_master = -1;
2010-11-08 10:45:44 +00:00
options->control_persist = -1;
options->control_persist_timeout = 0;
2005-06-05 15:46:09 +00:00
options->hash_known_hosts = -1;
2006-03-22 20:41:37 +00:00
options->tun_open = -1;
options->tun_local = -1;
options->tun_remote = -1;
options->local_command = NULL;
options->permit_local_command = -1;
2018-05-06 12:24:45 +00:00
options->remote_command = NULL;
2016-03-10 20:10:25 +00:00
options->add_keys_to_agent = -1;
2021-02-14 21:09:58 +00:00
options->add_keys_to_agent_lifespan = -1;
2017-01-31 12:29:48 +00:00
options->identity_agent = NULL;
2008-07-23 09:33:08 +00:00
options->visual_host_key = -1;
2011-02-17 11:47:40 +00:00
options->ip_qos_interactive = -1;
options->ip_qos_bulk = -1;
2011-09-28 08:14:41 +00:00
options->request_tty = -1;
2021-08-30 19:14:33 +00:00
options->session_type = -1;
options->stdin_null = -1;
options->fork_after_authentication = -1;
2014-01-30 10:56:49 +00:00
options->proxy_use_fdpass = -1;
2013-09-18 17:27:38 +00:00
options->ignored_unknown = NULL;
2014-01-30 10:56:49 +00:00
options->num_canonical_domains = 0;
options->num_permitted_cnames = 0;
options->canonicalize_max_dots = -1;
options->canonicalize_fallback_local = -1;
options->canonicalize_hostname = -1;
2015-07-02 13:15:34 +00:00
options->revoked_host_keys = NULL;
options->fingerprint_hash = -1;
options->update_hostkeys = -1;
2021-04-23 19:10:38 +00:00
options->hostbased_accepted_algos = NULL;
options->pubkey_accepted_algos = NULL;
options->known_hosts_command = NULL;
2022-10-04 15:10:40 +00:00
options->required_rsa_size = -1;
2023-02-05 18:04:12 +00:00
options->enable_escape_commandline = -1;
2023-10-04 12:06:41 +00:00
options->obscure_keystroke_timing_interval = -1;
2023-08-10 16:16:53 +00:00
options->tag = NULL;
2023-12-18 15:59:40 +00:00
options->channel_timeouts = NULL;
options->num_channel_timeouts = 0;
2000-02-24 14:29:47 +00:00
}
2014-03-22 15:23:38 +00:00
/*
* A petite version of fill_default_options() that just fills the options
* needed for hostname canonicalization to proceed.
*/
void
fill_default_options_for_canonicalization(Options *options)
{
if (options->canonicalize_max_dots == -1)
options->canonicalize_max_dots = 1;
if (options->canonicalize_fallback_local == -1)
options->canonicalize_fallback_local = 1;
if (options->canonicalize_hostname == -1)
options->canonicalize_hostname = SSH_CANONICALISE_NO;
}
2000-02-24 14:29:47 +00:00
/*
* Called after processing other sources of option data, this fills those
* options for which no value has been specified with their default values.
*/
2021-04-23 19:10:38 +00:00
int
2000-02-24 14:29:47 +00:00
fill_default_options(Options * options)
{
2019-02-05 15:03:53 +00:00
char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
2021-02-14 21:04:52 +00:00
char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
2021-04-23 19:10:38 +00:00
int ret = 0, r;
2018-08-28 10:47:58 +00:00
2000-02-24 14:29:47 +00:00
if (options->forward_agent == -1)
options->forward_agent = 0;
2000-02-24 14:29:47 +00:00
if (options->forward_x11 == -1)
options->forward_x11 = 0;
2004-02-26 10:52:33 +00:00
if (options->forward_x11_trusted == -1)
options->forward_x11_trusted = 0;
2010-11-08 10:45:44 +00:00
if (options->forward_x11_timeout == -1)
options->forward_x11_timeout = 1200;
2017-01-31 12:29:48 +00:00
/*
* stdio forwarding (-W) changes the default for these but we defer
* setting the values so they can be overridden.
*/
2006-09-30 13:38:06 +00:00
if (options->exit_on_forward_failure == -1)
2017-01-31 12:29:48 +00:00
options->exit_on_forward_failure =
options->stdio_forward_host != NULL ? 1 : 0;
if (options->clear_forwardings == -1)
options->clear_forwardings =
options->stdio_forward_host != NULL ? 1 : 0;
if (options->clear_forwardings == 1)
clear_forwardings(options);
if (options->xauth_location == NULL)
2021-04-23 19:10:38 +00:00
options->xauth_location = xstrdup(_PATH_XAUTH);
2015-01-05 16:09:55 +00:00
if (options->fwd_opts.gateway_ports == -1)
options->fwd_opts.gateway_ports = 0;
if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
options->fwd_opts.streamlocal_bind_mask = 0177;
if (options->fwd_opts.streamlocal_bind_unlink == -1)
options->fwd_opts.streamlocal_bind_unlink = 0;
2001-05-04 04:14:23 +00:00
if (options->pubkey_authentication == -1)
2022-02-23 18:16:45 +00:00
options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL;
if (options->gss_authentication == -1)
2004-02-26 10:52:33 +00:00
options->gss_authentication = 0;
if (options->gss_deleg_creds == -1)
options->gss_deleg_creds = 0;
2000-02-24 14:29:47 +00:00
if (options->password_authentication == -1)
options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1)
2001-05-04 04:14:23 +00:00
options->kbd_interactive_authentication = 1;
if (options->hostbased_authentication == -1)
options->hostbased_authentication = 0;
2000-02-24 14:29:47 +00:00
if (options->batch_mode == -1)
options->batch_mode = 0;
if (options->check_host_ip == -1)
options->check_host_ip = 0;
2000-02-24 14:29:47 +00:00
if (options->strict_host_key_checking == -1)
2018-05-06 12:24:45 +00:00
options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK;
2000-02-24 14:29:47 +00:00
if (options->compression == -1)
options->compression = 0;
2004-02-26 10:52:33 +00:00
if (options->tcp_keep_alive == -1)
options->tcp_keep_alive = 1;
2000-02-24 14:29:47 +00:00
if (options->port == -1)
options->port = 0; /* Filled in ssh_connect. */
if (options->address_family == -1)
options->address_family = AF_UNSPEC;
2000-02-24 14:29:47 +00:00
if (options->connection_attempts == -1)
2002-03-18 10:09:43 +00:00
options->connection_attempts = 1;
2000-02-24 14:29:47 +00:00
if (options->number_of_password_prompts == -1)
options->number_of_password_prompts = 3;
2001-05-04 04:14:23 +00:00
/* options->hostkeyalgorithms, default set in myproposals.h */
2021-02-14 21:09:58 +00:00
if (options->add_keys_to_agent == -1) {
2016-03-10 20:10:25 +00:00
options->add_keys_to_agent = 0;
2021-02-14 21:09:58 +00:00
options->add_keys_to_agent_lifespan = 0;
}
2000-02-24 14:29:47 +00:00
if (options->num_identity_files == 0) {
2018-05-06 12:24:45 +00:00
add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0);
2011-02-17 11:47:40 +00:00
#ifdef OPENSSL_HAS_ECC
2018-05-06 12:24:45 +00:00
add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
2021-02-14 21:04:52 +00:00
add_identity_file(options, "~/",
_PATH_SSH_CLIENT_ID_ECDSA_SK, 0);
2011-02-17 11:47:40 +00:00
#endif
2018-05-06 12:24:45 +00:00
add_identity_file(options, "~/",
_PATH_SSH_CLIENT_ID_ED25519, 0);
2021-02-14 21:04:52 +00:00
add_identity_file(options, "~/",
_PATH_SSH_CLIENT_ID_ED25519_SK, 0);
2018-05-06 12:27:04 +00:00
add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0);
2024-03-17 17:47:10 +00:00
#ifdef WITH_DSA
2022-02-23 18:16:45 +00:00
add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0);
2024-03-17 17:47:10 +00:00
#endif
}
2000-02-24 14:29:47 +00:00
if (options->escape_char == -1)
options->escape_char = '~';
2011-09-28 08:14:41 +00:00
if (options->num_system_hostfiles == 0) {
options->system_hostfiles[options->num_system_hostfiles++] =
xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
options->system_hostfiles[options->num_system_hostfiles++] =
xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
}
2021-04-23 19:10:38 +00:00
if (options->update_hostkeys == -1) {
if (options->verify_host_key_dns <= 0 &&
(options->num_user_hostfiles == 0 ||
(options->num_user_hostfiles == 1 && strcmp(options->
user_hostfiles[0], _PATH_SSH_USER_HOSTFILE) == 0)))
options->update_hostkeys = SSH_UPDATE_HOSTKEYS_YES;
else
2021-02-14 21:04:52 +00:00
options->update_hostkeys = SSH_UPDATE_HOSTKEYS_NO;
2021-04-23 19:10:38 +00:00
}
2011-09-28 08:14:41 +00:00
if (options->num_user_hostfiles == 0) {
options->user_hostfiles[options->num_user_hostfiles++] =
xstrdup(_PATH_SSH_USER_HOSTFILE);
options->user_hostfiles[options->num_user_hostfiles++] =
xstrdup(_PATH_SSH_USER_HOSTFILE2);
}
2002-03-18 10:09:43 +00:00
if (options->log_level == SYSLOG_LEVEL_NOT_SET)
2000-02-24 14:29:47 +00:00
options->log_level = SYSLOG_LEVEL_INFO;
2018-05-06 12:24:45 +00:00
if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
options->log_facility = SYSLOG_FACILITY_USER;
2002-03-18 10:09:43 +00:00
if (options->no_host_authentication_for_localhost == - 1)
options->no_host_authentication_for_localhost = 0;
2004-04-20 09:46:41 +00:00
if (options->identities_only == -1)
options->identities_only = 0;
2003-04-23 17:13:13 +00:00
if (options->enable_ssh_keysign == -1)
options->enable_ssh_keysign = 0;
if (options->rekey_limit == -1)
options->rekey_limit = 0;
2013-09-18 17:27:38 +00:00
if (options->rekey_interval == -1)
options->rekey_interval = 0;
if (options->verify_host_key_dns == -1)
options->verify_host_key_dns = 0;
2004-02-26 10:52:33 +00:00
if (options->server_alive_interval == -1)
options->server_alive_interval = 0;
if (options->server_alive_count_max == -1)
options->server_alive_count_max = 3;
2004-10-28 16:11:31 +00:00
if (options->control_master == -1)
options->control_master = 0;
2010-11-08 10:45:44 +00:00
if (options->control_persist == -1) {
options->control_persist = 0;
options->control_persist_timeout = 0;
}
2005-06-05 15:46:09 +00:00
if (options->hash_known_hosts == -1)
options->hash_known_hosts = 0;
2006-03-22 20:41:37 +00:00
if (options->tun_open == -1)
options->tun_open = SSH_TUNMODE_NO;
if (options->tun_local == -1)
options->tun_local = SSH_TUNID_ANY;
if (options->tun_remote == -1)
options->tun_remote = SSH_TUNID_ANY;
if (options->permit_local_command == -1)
options->permit_local_command = 0;
2008-07-23 09:33:08 +00:00
if (options->visual_host_key == -1)
options->visual_host_key = 0;
2011-02-17 11:47:40 +00:00
if (options->ip_qos_interactive == -1)
2018-08-28 10:47:58 +00:00
options->ip_qos_interactive = IPTOS_DSCP_AF21;
2011-02-17 11:47:40 +00:00
if (options->ip_qos_bulk == -1)
2018-08-28 10:47:58 +00:00
options->ip_qos_bulk = IPTOS_DSCP_CS1;
2011-09-28 08:14:41 +00:00
if (options->request_tty == -1)
options->request_tty = REQUEST_TTY_AUTO;
2021-08-30 19:14:33 +00:00
if (options->session_type == -1)
options->session_type = SESSION_TYPE_DEFAULT;
if (options->stdin_null == -1)
options->stdin_null = 0;
if (options->fork_after_authentication == -1)
options->fork_after_authentication = 0;
2014-01-30 10:56:49 +00:00
if (options->proxy_use_fdpass == -1)
options->proxy_use_fdpass = 0;
if (options->canonicalize_max_dots == -1)
options->canonicalize_max_dots = 1;
if (options->canonicalize_fallback_local == -1)
options->canonicalize_fallback_local = 1;
if (options->canonicalize_hostname == -1)
options->canonicalize_hostname = SSH_CANONICALISE_NO;
2015-07-02 13:15:34 +00:00
if (options->fingerprint_hash == -1)
options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
2021-02-14 21:04:52 +00:00
#ifdef ENABLE_SK_INTERNAL
if (options->sk_provider == NULL)
options->sk_provider = xstrdup("internal");
#else
if (options->sk_provider == NULL)
options->sk_provider = xstrdup("$SSH_SK_PROVIDER");
#endif
2022-10-04 15:10:40 +00:00
if (options->required_rsa_size == -1)
options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
2023-02-05 18:04:12 +00:00
if (options->enable_escape_commandline == -1)
options->enable_escape_commandline = 0;
2023-10-04 12:06:41 +00:00
if (options->obscure_keystroke_timing_interval == -1) {
options->obscure_keystroke_timing_interval =
SSH_KEYSTROKE_DEFAULT_INTERVAL_MS;
}
2018-08-28 10:47:58 +00:00
/* Expand KEX name lists */
all_cipher = cipher_alg_list(',', 0);
all_mac = mac_alg_list(',');
all_kex = kex_alg_list(',');
all_key = sshkey_alg_list(0, 0, 1, ',');
2019-02-05 15:03:53 +00:00
all_sig = sshkey_alg_list(0, 1, 1, ',');
2021-02-14 21:04:52 +00:00
/* remove unsupported algos from default lists */
2021-02-14 21:09:58 +00:00
def_cipher = match_filter_allowlist(KEX_CLIENT_ENCRYPT, all_cipher);
def_mac = match_filter_allowlist(KEX_CLIENT_MAC, all_mac);
def_kex = match_filter_allowlist(KEX_CLIENT_KEX, all_kex);
def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
2018-08-28 10:47:58 +00:00
#define ASSEMBLE(what, defaults, all) \
do { \
if ((r = kex_assemble_names(&options->what, \
2021-04-23 19:10:38 +00:00
defaults, all)) != 0) { \
error_fr(r, "%s", #what); \
goto fail; \
} \
2018-08-28 10:47:58 +00:00
} while (0)
2021-02-14 21:04:52 +00:00
ASSEMBLE(ciphers, def_cipher, all_cipher);
ASSEMBLE(macs, def_mac, all_mac);
ASSEMBLE(kex_algorithms, def_kex, all_kex);
2021-04-23 19:10:38 +00:00
ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
2021-02-14 21:04:52 +00:00
ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
2018-08-28 10:47:58 +00:00
#undef ASSEMBLE
2015-07-02 13:15:34 +00:00
2014-01-30 10:56:49 +00:00
#define CLEAR_ON_NONE(v) \
do { \
2014-03-22 15:23:38 +00:00
if (option_clear_or_none(v)) { \
2014-01-30 10:56:49 +00:00
free(v); \
v = NULL; \
} \
} while(0)
2023-12-18 15:59:40 +00:00
#define CLEAR_ON_NONE_ARRAY(v, nv, none) \
do { \
if (options->nv == 1 && \
strcasecmp(options->v[0], none) == 0) { \
free(options->v[0]); \
free(options->v); \
options->v = NULL; \
options->nv = 0; \
} \
} while (0)
2014-01-30 10:56:49 +00:00
CLEAR_ON_NONE(options->local_command);
2018-05-06 12:24:45 +00:00
CLEAR_ON_NONE(options->remote_command);
2014-01-30 10:56:49 +00:00
CLEAR_ON_NONE(options->proxy_command);
CLEAR_ON_NONE(options->control_path);
2015-07-02 13:15:34 +00:00
CLEAR_ON_NONE(options->revoked_host_keys);
2020-02-14 19:47:15 +00:00
CLEAR_ON_NONE(options->pkcs11_provider);
2021-02-14 21:04:52 +00:00
CLEAR_ON_NONE(options->sk_provider);
2021-04-23 19:10:38 +00:00
CLEAR_ON_NONE(options->known_hosts_command);
2023-12-18 15:59:40 +00:00
CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none");
#undef CLEAR_ON_NONE
#undef CLEAR_ON_NONE_ARRAY
2018-08-28 10:47:58 +00:00
if (options->jump_host != NULL &&
strcmp(options->jump_host, "none") == 0 &&
options->jump_port == 0 && options->jump_user == NULL) {
free(options->jump_host);
options->jump_host = NULL;
}
2021-11-04 17:16:52 +00:00
if (options->num_permitted_cnames == 1 &&
!config_has_permitted_cnames(options)) {
/* clean up CanonicalizePermittedCNAMEs=none */
free(options->permitted_cnames[0].source_list);
free(options->permitted_cnames[0].target_list);
memset(options->permitted_cnames, '\0',
sizeof(*options->permitted_cnames));
options->num_permitted_cnames = 0;
}
2017-01-31 12:29:48 +00:00
/* options->identity_agent distinguishes NULL from 'none' */
2000-02-24 14:29:47 +00:00
/* options->user will be set in the main program if appropriate */
/* options->hostname will be set in the main program if appropriate */
2001-05-04 04:14:23 +00:00
/* options->host_key_alias should not be set by default */
/* options->preferred_authentications will be set in ssh */
2021-04-23 19:10:38 +00:00
/* success */
ret = 0;
fail:
free(all_cipher);
free(all_mac);
free(all_kex);
free(all_key);
free(all_sig);
free(def_cipher);
free(def_mac);
free(def_kex);
free(def_key);
free(def_sig);
return ret;
}
void
free_options(Options *o)
{
int i;
if (o == NULL)
return;
#define FREE_ARRAY(type, n, a) \
do { \
type _i; \
for (_i = 0; _i < (n); _i++) \
free((a)[_i]); \
} while (0)
free(o->forward_agent_sock_path);
free(o->xauth_location);
FREE_ARRAY(u_int, o->num_log_verbose, o->log_verbose);
free(o->log_verbose);
free(o->ciphers);
free(o->macs);
free(o->hostkeyalgorithms);
free(o->kex_algorithms);
free(o->ca_sign_algorithms);
free(o->hostname);
free(o->host_key_alias);
free(o->proxy_command);
free(o->user);
FREE_ARRAY(u_int, o->num_system_hostfiles, o->system_hostfiles);
FREE_ARRAY(u_int, o->num_user_hostfiles, o->user_hostfiles);
free(o->preferred_authentications);
free(o->bind_address);
free(o->bind_interface);
free(o->pkcs11_provider);
free(o->sk_provider);
for (i = 0; i < o->num_identity_files; i++) {
free(o->identity_files[i]);
sshkey_free(o->identity_keys[i]);
}
for (i = 0; i < o->num_certificate_files; i++) {
free(o->certificate_files[i]);
sshkey_free(o->certificates[i]);
}
free(o->identity_agent);
for (i = 0; i < o->num_local_forwards; i++) {
free(o->local_forwards[i].listen_host);
free(o->local_forwards[i].listen_path);
free(o->local_forwards[i].connect_host);
free(o->local_forwards[i].connect_path);
}
free(o->local_forwards);
for (i = 0; i < o->num_remote_forwards; i++) {
free(o->remote_forwards[i].listen_host);
free(o->remote_forwards[i].listen_path);
free(o->remote_forwards[i].connect_host);
free(o->remote_forwards[i].connect_path);
}
free(o->remote_forwards);
free(o->stdio_forward_host);
2022-10-04 15:10:40 +00:00
FREE_ARRAY(u_int, o->num_send_env, o->send_env);
2021-04-23 19:10:38 +00:00
free(o->send_env);
2022-10-04 15:10:40 +00:00
FREE_ARRAY(u_int, o->num_setenv, o->setenv);
2021-04-23 19:10:38 +00:00
free(o->setenv);
free(o->control_path);
free(o->local_command);
free(o->remote_command);
FREE_ARRAY(int, o->num_canonical_domains, o->canonical_domains);
for (i = 0; i < o->num_permitted_cnames; i++) {
free(o->permitted_cnames[i].source_list);
free(o->permitted_cnames[i].target_list);
}
free(o->revoked_host_keys);
free(o->hostbased_accepted_algos);
free(o->pubkey_accepted_algos);
free(o->jump_user);
free(o->jump_host);
free(o->jump_extra);
free(o->ignored_unknown);
explicit_bzero(o, sizeof(*o));
#undef FREE_ARRAY
2000-02-24 14:29:47 +00:00
}
2005-06-05 15:46:09 +00:00
2015-01-05 16:09:55 +00:00
struct fwdarg {
char *arg;
int ispath;
};
/*
* parse_fwd_field
* parses the next field in a port forwarding specification.
* sets fwd to the parsed field and advances p past the colon
* or sets it to NULL at end of string.
* returns 0 on success, else non-zero.
*/
static int
parse_fwd_field(char **p, struct fwdarg *fwd)
{
char *ep, *cp = *p;
int ispath = 0;
if (*cp == '\0') {
*p = NULL;
return -1; /* end of string */
}
/*
* A field escaped with square brackets is used literally.
* XXX - allow ']' to be escaped via backslash?
*/
if (*cp == '[') {
/* find matching ']' */
for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
if (*ep == '/')
ispath = 1;
}
/* no matching ']' or not at end of field. */
if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
return -1;
/* NUL terminate the field and advance p past the colon */
*ep++ = '\0';
if (*ep != '\0')
*ep++ = '\0';
fwd->arg = cp + 1;
fwd->ispath = ispath;
*p = ep;
return 0;
}
for (cp = *p; *cp != '\0'; cp++) {
switch (*cp) {
case '\\':
memmove(cp, cp + 1, strlen(cp + 1) + 1);
2015-07-02 13:18:50 +00:00
if (*cp == '\0')
return -1;
2015-01-05 16:09:55 +00:00
break;
case '/':
ispath = 1;
break;
case ':':
*cp++ = '\0';
goto done;
}
}
done:
fwd->arg = *p;
fwd->ispath = ispath;
*p = cp;
return 0;
}
2005-06-05 15:46:09 +00:00
/*
* parse_forward
* parses a string containing a port forwarding specification of the form:
2009-02-24 18:49:27 +00:00
* dynamicfwd == 0
2015-01-05 16:09:55 +00:00
* [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
* listenpath:connectpath
2009-02-24 18:49:27 +00:00
* dynamicfwd == 1
* [listenhost:]listenport
2005-06-05 15:46:09 +00:00
* returns number of arguments parsed or zero on error
*/
int
2015-01-05 16:09:55 +00:00
parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
2005-06-05 15:46:09 +00:00
{
2015-01-05 16:09:55 +00:00
struct fwdarg fwdargs[4];
char *p, *cp;
2021-02-14 21:09:58 +00:00
int i, err;
2005-06-05 15:46:09 +00:00
2015-01-05 16:09:55 +00:00
memset(fwd, 0, sizeof(*fwd));
memset(fwdargs, 0, sizeof(fwdargs));
2005-06-05 15:46:09 +00:00
2021-02-14 21:09:58 +00:00
/*
* We expand environment variables before checking if we think they're
* paths so that if ${VAR} expands to a fully qualified path it is
* treated as a path.
*/
cp = p = dollar_expand(&err, fwdspec);
if (p == NULL || err)
return 0;
2005-06-05 15:46:09 +00:00
/* skip leading spaces */
2014-01-30 10:56:49 +00:00
while (isspace((u_char)*cp))
2005-06-05 15:46:09 +00:00
cp++;
2015-01-05 16:09:55 +00:00
for (i = 0; i < 4; ++i) {
if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
2005-06-05 15:46:09 +00:00
break;
2015-01-05 16:09:55 +00:00
}
2005-06-05 15:46:09 +00:00
2009-02-24 18:49:27 +00:00
/* Check for trailing garbage */
2015-01-05 16:09:55 +00:00
if (cp != NULL && *cp != '\0') {
2005-06-05 15:46:09 +00:00
i = 0; /* failure */
2015-01-05 16:09:55 +00:00
}
2005-06-05 15:46:09 +00:00
switch (i) {
2009-02-24 18:49:27 +00:00
case 1:
2015-01-05 16:09:55 +00:00
if (fwdargs[0].ispath) {
fwd->listen_path = xstrdup(fwdargs[0].arg);
fwd->listen_port = PORT_STREAMLOCAL;
} else {
fwd->listen_host = NULL;
fwd->listen_port = a2port(fwdargs[0].arg);
}
2009-02-24 18:49:27 +00:00
fwd->connect_host = xstrdup("socks");
break;
case 2:
2015-01-05 16:09:55 +00:00
if (fwdargs[0].ispath && fwdargs[1].ispath) {
fwd->listen_path = xstrdup(fwdargs[0].arg);
fwd->listen_port = PORT_STREAMLOCAL;
fwd->connect_path = xstrdup(fwdargs[1].arg);
fwd->connect_port = PORT_STREAMLOCAL;
} else if (fwdargs[1].ispath) {
fwd->listen_host = NULL;
fwd->listen_port = a2port(fwdargs[0].arg);
fwd->connect_path = xstrdup(fwdargs[1].arg);
fwd->connect_port = PORT_STREAMLOCAL;
} else {
fwd->listen_host = xstrdup(fwdargs[0].arg);
fwd->listen_port = a2port(fwdargs[1].arg);
fwd->connect_host = xstrdup("socks");
}
2009-02-24 18:49:27 +00:00
break;
2005-06-05 15:46:09 +00:00
case 3:
2015-01-05 16:09:55 +00:00
if (fwdargs[0].ispath) {
fwd->listen_path = xstrdup(fwdargs[0].arg);
fwd->listen_port = PORT_STREAMLOCAL;
fwd->connect_host = xstrdup(fwdargs[1].arg);
fwd->connect_port = a2port(fwdargs[2].arg);
} else if (fwdargs[2].ispath) {
fwd->listen_host = xstrdup(fwdargs[0].arg);
fwd->listen_port = a2port(fwdargs[1].arg);
fwd->connect_path = xstrdup(fwdargs[2].arg);
fwd->connect_port = PORT_STREAMLOCAL;
} else {
fwd->listen_host = NULL;
fwd->listen_port = a2port(fwdargs[0].arg);
fwd->connect_host = xstrdup(fwdargs[1].arg);
fwd->connect_port = a2port(fwdargs[2].arg);
}
2005-06-05 15:46:09 +00:00
break;
case 4:
2015-01-05 16:09:55 +00:00
fwd->listen_host = xstrdup(fwdargs[0].arg);
fwd->listen_port = a2port(fwdargs[1].arg);
fwd->connect_host = xstrdup(fwdargs[2].arg);
fwd->connect_port = a2port(fwdargs[3].arg);
2005-06-05 15:46:09 +00:00
break;
default:
i = 0; /* failure */
}
2013-09-18 17:27:38 +00:00
free(p);
2005-06-05 15:46:09 +00:00
2009-02-24 18:49:27 +00:00
if (dynamicfwd) {
if (!(i == 1 || i == 2))
goto fail_free;
} else {
2015-01-05 16:09:55 +00:00
if (!(i == 3 || i == 4)) {
if (fwd->connect_path == NULL &&
fwd->listen_path == NULL)
goto fail_free;
}
if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
2009-02-24 18:49:27 +00:00
goto fail_free;
}
2015-01-05 16:09:55 +00:00
if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
(!remotefwd && fwd->listen_port == 0))
2005-06-05 15:46:09 +00:00
goto fail_free;
if (fwd->connect_host != NULL &&
strlen(fwd->connect_host) >= NI_MAXHOST)
goto fail_free;
2021-08-30 19:14:33 +00:00
/*
* XXX - if connecting to a remote socket, max sun len may not
* match this host
*/
2015-01-05 16:09:55 +00:00
if (fwd->connect_path != NULL &&
strlen(fwd->connect_path) >= PATH_MAX_SUN)
goto fail_free;
2009-02-24 18:49:27 +00:00
if (fwd->listen_host != NULL &&
strlen(fwd->listen_host) >= NI_MAXHOST)
goto fail_free;
2015-01-05 16:09:55 +00:00
if (fwd->listen_path != NULL &&
strlen(fwd->listen_path) >= PATH_MAX_SUN)
goto fail_free;
2005-06-05 15:46:09 +00:00
return (i);
fail_free:
2013-09-18 17:27:38 +00:00
free(fwd->connect_host);
fwd->connect_host = NULL;
2015-01-05 16:09:55 +00:00
free(fwd->connect_path);
fwd->connect_path = NULL;
2013-09-18 17:27:38 +00:00
free(fwd->listen_host);
fwd->listen_host = NULL;
2015-01-05 16:09:55 +00:00
free(fwd->listen_path);
fwd->listen_path = NULL;
2005-06-05 15:46:09 +00:00
return (0);
}
2015-07-02 13:15:34 +00:00
2017-01-31 12:29:48 +00:00
int
parse_jump(const char *s, Options *o, int active)
{
char *orig, *sdup, *cp;
char *host = NULL, *user = NULL;
2021-04-23 19:10:38 +00:00
int r, ret = -1, port = -1, first;
2017-01-31 12:29:48 +00:00
active &= o->proxy_command == NULL && o->jump_host == NULL;
orig = sdup = xstrdup(s);
2021-08-30 19:14:33 +00:00
/* Remove comment and trailing whitespace */
if ((cp = strchr(orig, '#')) != NULL)
*cp = '\0';
rtrim(orig);
2017-01-31 12:29:48 +00:00
first = active;
do {
2018-08-28 10:47:58 +00:00
if (strcasecmp(s, "none") == 0)
break;
2017-01-31 12:29:48 +00:00
if ((cp = strrchr(sdup, ',')) == NULL)
cp = sdup; /* last */
else
*cp++ = '\0';
if (first) {
/* First argument and configuration is active */
2021-04-23 19:10:38 +00:00
r = parse_ssh_uri(cp, &user, &host, &port);
if (r == -1 || (r == 1 &&
parse_user_host_port(cp, &user, &host, &port) != 0))
2017-01-31 12:29:48 +00:00
goto out;
} else {
/* Subsequent argument or inactive configuration */
2021-04-23 19:10:38 +00:00
r = parse_ssh_uri(cp, NULL, NULL, NULL);
if (r == -1 || (r == 1 &&
parse_user_host_port(cp, NULL, NULL, NULL) != 0))
2017-01-31 12:29:48 +00:00
goto out;
}
first = 0; /* only check syntax for subsequent hosts */
} while (cp != sdup);
/* success */
if (active) {
2018-08-28 10:47:58 +00:00
if (strcasecmp(s, "none") == 0) {
o->jump_host = xstrdup("none");
o->jump_port = 0;
} else {
o->jump_user = user;
o->jump_host = host;
o->jump_port = port;
o->proxy_command = xstrdup("none");
user = host = NULL;
if ((cp = strrchr(s, ',')) != NULL && cp != s) {
o->jump_extra = xstrdup(s);
o->jump_extra[cp - s] = '\0';
}
2017-01-31 12:29:48 +00:00
}
}
ret = 0;
out:
free(orig);
free(user);
free(host);
return ret;
}
2018-05-06 12:27:04 +00:00
int
parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
{
2021-04-23 19:10:38 +00:00
char *user = NULL, *host = NULL, *path = NULL;
int r, port;
2018-05-06 12:27:04 +00:00
2021-04-23 19:10:38 +00:00
r = parse_uri("ssh", uri, &user, &host, &port, &path);
2018-05-06 12:27:04 +00:00
if (r == 0 && path != NULL)
r = -1; /* path not allowed */
2021-04-23 19:10:38 +00:00
if (r == 0) {
if (userp != NULL) {
*userp = user;
user = NULL;
}
if (hostp != NULL) {
*hostp = host;
host = NULL;
}
if (portp != NULL)
*portp = port;
}
free(user);
free(host);
free(path);
2018-05-06 12:27:04 +00:00
return r;
}
2015-07-02 13:15:34 +00:00
/* XXX the following is a near-vebatim copy from servconf.c; refactor */
static const char *
fmt_multistate_int(int val, const struct multistate *m)
{
u_int i;
for (i = 0; m[i].key != NULL; i++) {
if (m[i].value == val)
return m[i].key;
}
return "UNKNOWN";
}
static const char *
fmt_intarg(OpCodes code, int val)
{
if (val == -1)
return "unset";
switch (code) {
case oAddressFamily:
return fmt_multistate_int(val, multistate_addressfamily);
case oVerifyHostKeyDNS:
case oUpdateHostkeys:
return fmt_multistate_int(val, multistate_yesnoask);
2018-05-06 12:24:45 +00:00
case oStrictHostKeyChecking:
return fmt_multistate_int(val, multistate_strict_hostkey);
2015-07-02 13:15:34 +00:00
case oControlMaster:
return fmt_multistate_int(val, multistate_controlmaster);
case oTunnel:
return fmt_multistate_int(val, multistate_tunnel);
case oRequestTTY:
return fmt_multistate_int(val, multistate_requesttty);
2021-08-30 19:14:33 +00:00
case oSessionType:
return fmt_multistate_int(val, multistate_sessiontype);
2015-07-02 13:15:34 +00:00
case oCanonicalizeHostname:
return fmt_multistate_int(val, multistate_canonicalizehostname);
2018-08-28 10:47:58 +00:00
case oAddKeysToAgent:
return fmt_multistate_int(val, multistate_yesnoaskconfirm);
2022-02-23 18:16:45 +00:00
case oPubkeyAuthentication:
return fmt_multistate_int(val, multistate_pubkey_auth);
2015-07-02 13:15:34 +00:00
case oFingerprintHash:
return ssh_digest_alg_name(val);
default:
switch (val) {
case 0:
return "no";
case 1:
return "yes";
default:
return "UNKNOWN";
}
}
}
static const char *
lookup_opcode_name(OpCodes code)
{
u_int i;
for (i = 0; keywords[i].name != NULL; i++)
if (keywords[i].opcode == code)
return(keywords[i].name);
return "UNKNOWN";
}
static void
dump_cfg_int(OpCodes code, int val)
{
2023-10-04 12:06:41 +00:00
if (code == oObscureKeystrokeTiming) {
if (val == 0) {
printf("%s no\n", lookup_opcode_name(code));
return;
} else if (val == SSH_KEYSTROKE_DEFAULT_INTERVAL_MS) {
printf("%s yes\n", lookup_opcode_name(code));
return;
}
/* FALLTHROUGH */
}
2015-07-02 13:15:34 +00:00
printf("%s %d\n", lookup_opcode_name(code), val);
}
static void
dump_cfg_fmtint(OpCodes code, int val)
{
printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
}
static void
dump_cfg_string(OpCodes code, const char *val)
{
if (val == NULL)
return;
printf("%s %s\n", lookup_opcode_name(code), val);
}
static void
dump_cfg_strarray(OpCodes code, u_int count, char **vals)
{
u_int i;
for (i = 0; i < count; i++)
printf("%s %s\n", lookup_opcode_name(code), vals[i]);
}
static void
dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
{
u_int i;
printf("%s", lookup_opcode_name(code));
2021-08-30 19:14:33 +00:00
if (count == 0)
printf(" none");
2015-07-02 13:15:34 +00:00
for (i = 0; i < count; i++)
printf(" %s", vals[i]);
printf("\n");
}
static void
dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
{
const struct Forward *fwd;
u_int i;
/* oDynamicForward */
for (i = 0; i < count; i++) {
fwd = &fwds[i];
2017-08-03 10:10:20 +00:00
if (code == oDynamicForward && fwd->connect_host != NULL &&
2015-07-02 13:15:34 +00:00
strcmp(fwd->connect_host, "socks") != 0)
continue;
2017-08-03 10:10:20 +00:00
if (code == oLocalForward && fwd->connect_host != NULL &&
2015-07-02 13:15:34 +00:00
strcmp(fwd->connect_host, "socks") == 0)
continue;
printf("%s", lookup_opcode_name(code));
if (fwd->listen_port == PORT_STREAMLOCAL)
printf(" %s", fwd->listen_path);
else if (fwd->listen_host == NULL)
printf(" %d", fwd->listen_port);
else {
printf(" [%s]:%d",
fwd->listen_host, fwd->listen_port);
}
if (code != oDynamicForward) {
if (fwd->connect_port == PORT_STREAMLOCAL)
printf(" %s", fwd->connect_path);
else if (fwd->connect_host == NULL)
printf(" %d", fwd->connect_port);
else {
printf(" [%s]:%d",
fwd->connect_host, fwd->connect_port);
}
}
printf("\n");
}
}
void
dump_client_config(Options *o, const char *host)
{
2021-02-14 21:04:52 +00:00
int i, r;
2018-08-28 10:47:58 +00:00
char buf[8], *all_key;
2015-07-02 13:15:34 +00:00
2021-02-14 21:04:52 +00:00
/*
* Expand HostKeyAlgorithms name lists. This isn't handled in
* fill_default_options() like the other algorithm lists because
* the host key algorithms are by default dynamically chosen based
* on the host's keys found in known_hosts.
*/
2018-08-28 10:47:58 +00:00
all_key = sshkey_alg_list(0, 0, 1, ',');
2021-02-14 21:04:52 +00:00
if ((r = kex_assemble_names(&o->hostkeyalgorithms, kex_default_pk_alg(),
all_key)) != 0)
2021-04-23 19:10:38 +00:00
fatal_fr(r, "expand HostKeyAlgorithms");
2018-08-28 10:47:58 +00:00
free(all_key);
2016-03-10 20:10:25 +00:00
2015-07-02 13:15:34 +00:00
/* Most interesting options first: user, host, port */
2023-02-05 18:04:12 +00:00
dump_cfg_string(oHost, o->host_arg);
2015-07-02 13:15:34 +00:00
dump_cfg_string(oUser, o->user);
2021-02-14 21:00:25 +00:00
dump_cfg_string(oHostname, host);
2015-07-02 13:15:34 +00:00
dump_cfg_int(oPort, o->port);
/* Flag options */
dump_cfg_fmtint(oAddressFamily, o->address_family);
dump_cfg_fmtint(oBatchMode, o->batch_mode);
dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
dump_cfg_fmtint(oCompression, o->compression);
dump_cfg_fmtint(oControlMaster, o->control_master);
dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
2017-01-31 12:29:48 +00:00
dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
2015-07-02 13:15:34 +00:00
dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
dump_cfg_fmtint(oForwardX11, o->forward_x11);
dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
#ifdef GSSAPI
dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
#endif /* GSSAPI */
dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
dump_cfg_fmtint(oRequestTTY, o->request_tty);
2021-08-30 19:14:33 +00:00
dump_cfg_fmtint(oSessionType, o->session_type);
dump_cfg_fmtint(oStdinNull, o->stdin_null);
dump_cfg_fmtint(oForkAfterAuthentication, o->fork_after_authentication);
2015-07-02 13:15:34 +00:00
dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
dump_cfg_fmtint(oTunnel, o->tun_open);
dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
2023-02-05 18:04:12 +00:00
dump_cfg_fmtint(oEnableEscapeCommandline, o->enable_escape_commandline);
2015-07-02 13:15:34 +00:00
/* Integer options */
dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
dump_cfg_int(oConnectionAttempts, o->connection_attempts);
dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
2022-10-04 15:10:40 +00:00
dump_cfg_int(oRequiredRSASize, o->required_rsa_size);
2023-10-04 12:06:41 +00:00
dump_cfg_int(oObscureKeystrokeTiming,
o->obscure_keystroke_timing_interval);
2015-07-02 13:15:34 +00:00
/* String options */
dump_cfg_string(oBindAddress, o->bind_address);
2018-05-06 12:27:04 +00:00
dump_cfg_string(oBindInterface, o->bind_interface);
2021-02-14 21:04:52 +00:00
dump_cfg_string(oCiphers, o->ciphers);
2015-07-02 13:15:34 +00:00
dump_cfg_string(oControlPath, o->control_path);
2016-03-10 20:10:25 +00:00
dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
2015-07-02 13:15:34 +00:00
dump_cfg_string(oHostKeyAlias, o->host_key_alias);
2021-04-23 19:10:38 +00:00
dump_cfg_string(oHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
2017-01-31 12:29:48 +00:00
dump_cfg_string(oIdentityAgent, o->identity_agent);
2018-08-28 10:47:58 +00:00
dump_cfg_string(oIgnoreUnknown, o->ignored_unknown);
2015-07-02 13:15:34 +00:00
dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
2021-02-14 21:04:52 +00:00
dump_cfg_string(oKexAlgorithms, o->kex_algorithms);
dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms);
2015-07-02 13:15:34 +00:00
dump_cfg_string(oLocalCommand, o->local_command);
2018-05-06 12:24:45 +00:00
dump_cfg_string(oRemoteCommand, o->remote_command);
2015-07-02 13:15:34 +00:00
dump_cfg_string(oLogLevel, log_level_name(o->log_level));
2021-02-14 21:04:52 +00:00
dump_cfg_string(oMacs, o->macs);
2017-08-03 10:10:20 +00:00
#ifdef ENABLE_PKCS11
2015-07-02 13:15:34 +00:00
dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
2017-08-03 10:10:20 +00:00
#endif
2021-02-14 21:04:52 +00:00
dump_cfg_string(oSecurityKeyProvider, o->sk_provider);
2015-07-02 13:15:34 +00:00
dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
2021-04-23 19:10:38 +00:00
dump_cfg_string(oPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
2015-07-02 13:15:34 +00:00
dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
dump_cfg_string(oXAuthLocation, o->xauth_location);
2021-04-23 19:10:38 +00:00
dump_cfg_string(oKnownHostsCommand, o->known_hosts_command);
2023-08-10 16:16:53 +00:00
dump_cfg_string(oTag, o->tag);
2015-07-02 13:15:34 +00:00
/* Forwards */
dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
/* String array options */
dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
2018-08-28 10:47:58 +00:00
dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files);
2015-07-02 13:15:34 +00:00
dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
2018-08-28 10:47:58 +00:00
dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
2021-04-23 19:10:38 +00:00
dump_cfg_strarray_oneline(oLogVerbose,
o->num_log_verbose, o->log_verbose);
2023-12-18 15:59:40 +00:00
dump_cfg_strarray_oneline(oChannelTimeout,
o->num_channel_timeouts, o->channel_timeouts);
2015-07-02 13:15:34 +00:00
/* Special cases */
2021-04-23 19:10:38 +00:00
/* PermitRemoteOpen */
if (o->num_permitted_remote_opens == 0)
printf("%s any\n", lookup_opcode_name(oPermitRemoteOpen));
else
dump_cfg_strarray_oneline(oPermitRemoteOpen,
o->num_permitted_remote_opens, o->permitted_remote_opens);
2021-02-14 21:09:58 +00:00
/* AddKeysToAgent */
if (o->add_keys_to_agent_lifespan <= 0)
dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent);
else {
printf("addkeystoagent%s %d\n",
o->add_keys_to_agent == 3 ? " confirm" : "",
o->add_keys_to_agent_lifespan);
}
2021-02-14 21:04:52 +00:00
/* oForwardAgent */
if (o->forward_agent_sock_path == NULL)
dump_cfg_fmtint(oForwardAgent, o->forward_agent);
else
dump_cfg_string(oForwardAgent, o->forward_agent_sock_path);
2015-07-02 13:15:34 +00:00
/* oConnectTimeout */
if (o->connection_timeout == -1)
printf("connecttimeout none\n");
else
dump_cfg_int(oConnectTimeout, o->connection_timeout);
/* oTunnelDevice */
printf("tunneldevice");
if (o->tun_local == SSH_TUNID_ANY)
printf(" any");
else
printf(" %d", o->tun_local);
if (o->tun_remote == SSH_TUNID_ANY)
printf(":any");
else
printf(":%d", o->tun_remote);
printf("\n");
/* oCanonicalizePermittedCNAMEs */
2021-11-04 17:16:52 +00:00
printf("canonicalizePermittedcnames");
if (o->num_permitted_cnames == 0)
printf(" none");
for (i = 0; i < o->num_permitted_cnames; i++) {
printf(" %s:%s", o->permitted_cnames[i].source_list,
o->permitted_cnames[i].target_list);
2015-07-02 13:15:34 +00:00
}
2021-11-04 17:16:52 +00:00
printf("\n");
2015-07-02 13:15:34 +00:00
/* oControlPersist */
if (o->control_persist == 0 || o->control_persist_timeout == 0)
dump_cfg_fmtint(oControlPersist, o->control_persist);
else
dump_cfg_int(oControlPersist, o->control_persist_timeout);
/* oEscapeChar */
if (o->escape_char == SSH_ESCAPECHAR_NONE)
printf("escapechar none\n");
else {
2017-01-31 12:29:48 +00:00
vis(buf, o->escape_char, VIS_WHITE, 0);
printf("escapechar %s\n", buf);
2015-07-02 13:15:34 +00:00
}
/* oIPQoS */
printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
printf("%s\n", iptos2str(o->ip_qos_bulk));
/* oRekeyLimit */
2016-03-10 20:10:25 +00:00
printf("rekeylimit %llu %d\n",
(unsigned long long)o->rekey_limit, o->rekey_interval);
2015-07-02 13:15:34 +00:00
/* oStreamLocalBindMask */
printf("streamlocalbindmask 0%o\n",
o->fwd_opts.streamlocal_bind_mask);
2017-01-31 12:29:48 +00:00
2018-08-28 10:47:58 +00:00
/* oLogFacility */
printf("syslogfacility %s\n", log_facility_name(o->log_facility));
2017-01-31 12:29:48 +00:00
/* oProxyCommand / oProxyJump */
if (o->jump_host == NULL)
dump_cfg_string(oProxyCommand, o->proxy_command);
else {
/* Check for numeric addresses */
i = strchr(o->jump_host, ':') != NULL ||
strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
snprintf(buf, sizeof(buf), "%d", o->jump_port);
printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
/* optional additional jump spec */
o->jump_extra == NULL ? "" : o->jump_extra,
o->jump_extra == NULL ? "" : ",",
/* optional user */
o->jump_user == NULL ? "" : o->jump_user,
o->jump_user == NULL ? "" : "@",
/* opening [ if hostname is numeric */
i ? "[" : "",
/* mandatory hostname */
o->jump_host,
/* closing ] if hostname is numeric */
i ? "]" : "",
/* optional port number */
o->jump_port <= 0 ? "" : ":",
o->jump_port <= 0 ? "" : buf);
}
2015-07-02 13:15:34 +00:00
}