summaryrefslogtreecommitdiff
path: root/readconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'readconf.c')
-rw-r--r--readconf.c1142
1 files changed, 822 insertions, 320 deletions
diff --git a/readconf.c b/readconf.c
index ebbf2195..2afcbaec 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.c,v 1.232 2015/02/16 22:13:32 djm Exp $ */
+/* $OpenBSD: readconf.c,v 1.329 2020/04/24 03:33:21 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -35,10 +35,15 @@
#endif
#include <pwd.h>
#include <signal.h>
-#include <stdarg.h>
#include <stdio.h>
#include <string.h>
+#include <stdarg.h>
#include <unistd.h>
+#ifdef USE_SYSTEM_GLOB
+# include <glob.h>
+#else
+# include "openbsd-compat/glob.h"
+#endif
#ifdef HAVE_UTIL_H
#include <util.h>
#endif
@@ -48,6 +53,7 @@
#include "xmalloc.h"
#include "ssh.h"
+#include "ssherr.h"
#include "compat.h"
#include "cipher.h"
#include "pathnames.h"
@@ -80,7 +86,7 @@
User foo
Host fake.com
- HostName another.host.name.real.org
+ Hostname another.host.name.real.org
User blaah
Port 34289
ForwardX11 no
@@ -88,7 +94,7 @@
Host books.com
RemoteForward 9999 shadows.cs.hut.fi:9999
- Cipher 3des
+ Ciphers 3des-cbc
Host fascist.blob.com
Port 23123
@@ -103,7 +109,7 @@
PublicKeyAuthentication no
Host *.su
- Cipher none
+ Ciphers aes128-ctr
PasswordAuthentication no
Host vpn.fake.com
@@ -115,8 +121,6 @@
ForwardAgent no
ForwardX11 no
PasswordAuthentication yes
- RSAAuthentication yes
- RhostsRSAAuthentication yes
StrictHostKeyChecking yes
TcpKeepAlive no
IdentityFile ~/.ssh/identity
@@ -125,39 +129,51 @@
*/
+static int read_config_file_depth(const char *filename, struct passwd *pw,
+ const char *host, const char *original_host, Options *options,
+ int flags, int *activep, int *want_final_pass, int depth);
+static int process_config_line_depth(Options *options, struct passwd *pw,
+ const char *host, const char *original_host, char *line,
+ const char *filename, int linenum, int *activep, int flags,
+ int *want_final_pass, int depth);
+
/* Keyword tokens. */
typedef enum {
oBadOption,
- oHost, oMatch,
+ oHost, oMatch, oInclude,
oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
oGatewayPorts, oExitOnForwardFailure,
- oPasswordAuthentication, oRSAAuthentication,
+ oPasswordAuthentication,
oChallengeResponseAuthentication, oXAuthLocation,
- oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
- oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
+ oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward,
+ oCertificateFile, oAddKeysToAgent, oIdentityAgent,
+ oUser, oEscapeChar, oProxyCommand,
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
- oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
- oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
+ oTCPKeepAlive, oNumberOfPasswordPrompts,
+ oLogFacility, oLogLevel, oCiphers, oMacs,
oPubkeyAuthentication,
oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
- oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
+ oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider,
oClearAllForwardings, oNoHostAuthenticationForLocalhost,
oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
oAddressFamily, oGssAuthentication, oGssDelegateCreds,
oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
- oSendEnv, oControlPath, oControlMaster, oControlPersist,
+ oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
oHashKnownHosts,
- oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
- oVisualHostKey, oUseRoaming,
+ oTunnel, oTunnelDevice,
+ oLocalCommand, oPermitLocalCommand, oRemoteCommand,
+ oVisualHostKey,
oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
- oIgnoredUnknownOption, oDeprecated, oUnsupported
+ oPubkeyAcceptedKeyTypes, oCASignatureAlgorithms, oProxyJump,
+ oSecurityKeyProvider,
+ oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
} OpCodes;
/* Textual representations of the tokens. */
@@ -166,6 +182,41 @@ static struct {
const char *name;
OpCodes opcode;
} keywords[] = {
+ /* Deprecated options */
+ { "protocol", oIgnore }, /* NB. silently ignored */
+ { "cipher", oDeprecated },
+ { "fallbacktorsh", oDeprecated },
+ { "globalknownhostsfile2", oDeprecated },
+ { "rhostsauthentication", oDeprecated },
+ { "userknownhostsfile2", oDeprecated },
+ { "useroaming", oDeprecated },
+ { "usersh", oDeprecated },
+ { "useprivilegedport", oDeprecated },
+
+ /* Unsupported options */
+ { "afstokenpassing", oUnsupported },
+ { "kerberosauthentication", oUnsupported },
+ { "kerberostgtpassing", oUnsupported },
+ { "rsaauthentication", oUnsupported },
+ { "rhostsrsaauthentication", oUnsupported },
+ { "compressionlevel", oUnsupported },
+
+ /* Sometimes-unsupported options */
+#if defined(GSSAPI)
+ { "gssapiauthentication", oGssAuthentication },
+ { "gssapidelegatecredentials", oGssDelegateCreds },
+# else
+ { "gssapiauthentication", oUnsupported },
+ { "gssapidelegatecredentials", oUnsupported },
+#endif
+#ifdef ENABLE_PKCS11
+ { "pkcs11provider", oPKCS11Provider },
+ { "smartcarddevice", oPKCS11Provider },
+# else
+ { "smartcarddevice", oUnsupported },
+ { "pkcs11provider", oUnsupported },
+#endif
+
{ "forwardagent", oForwardAgent },
{ "forwardx11", oForwardX11 },
{ "forwardx11trusted", oForwardX11Trusted },
@@ -173,42 +224,27 @@ static struct {
{ "exitonforwardfailure", oExitOnForwardFailure },
{ "xauthlocation", oXAuthLocation },
{ "gatewayports", oGatewayPorts },
- { "useprivilegedport", oUsePrivilegedPort },
- { "rhostsauthentication", oDeprecated },
{ "passwordauthentication", oPasswordAuthentication },
{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
{ "kbdinteractivedevices", oKbdInteractiveDevices },
- { "rsaauthentication", oRSAAuthentication },
{ "pubkeyauthentication", oPubkeyAuthentication },
{ "dsaauthentication", oPubkeyAuthentication }, /* alias */
- { "rhostsrsaauthentication", oRhostsRSAAuthentication },
{ "hostbasedauthentication", oHostbasedAuthentication },
{ "challengeresponseauthentication", oChallengeResponseAuthentication },
- { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
+ { "skeyauthentication", oUnsupported },
{ "tisauthentication", oChallengeResponseAuthentication }, /* alias */
- { "kerberosauthentication", oUnsupported },
- { "kerberostgtpassing", oUnsupported },
- { "afstokenpassing", oUnsupported },
-#if defined(GSSAPI)
- { "gssapiauthentication", oGssAuthentication },
- { "gssapidelegatecredentials", oGssDelegateCreds },
-#else
- { "gssapiauthentication", oUnsupported },
- { "gssapidelegatecredentials", oUnsupported },
-#endif
- { "fallbacktorsh", oDeprecated },
- { "usersh", oDeprecated },
{ "identityfile", oIdentityFile },
{ "identityfile2", oIdentityFile }, /* obsolete */
{ "identitiesonly", oIdentitiesOnly },
- { "hostname", oHostName },
+ { "certificatefile", oCertificateFile },
+ { "addkeystoagent", oAddKeysToAgent },
+ { "identityagent", oIdentityAgent },
+ { "hostname", oHostname },
{ "hostkeyalias", oHostKeyAlias },
{ "proxycommand", oProxyCommand },
{ "port", oPort },
- { "cipher", oCipher },
{ "ciphers", oCiphers },
{ "macs", oMacs },
- { "protocol", oProtocol },
{ "remoteforward", oRemoteForward },
{ "localforward", oLocalForward },
{ "user", oUser },
@@ -216,30 +252,23 @@ static struct {
{ "match", oMatch },
{ "escapechar", oEscapeChar },
{ "globalknownhostsfile", oGlobalKnownHostsFile },
- { "globalknownhostsfile2", oDeprecated },
{ "userknownhostsfile", oUserKnownHostsFile },
- { "userknownhostsfile2", oDeprecated },
{ "connectionattempts", oConnectionAttempts },
{ "batchmode", oBatchMode },
{ "checkhostip", oCheckHostIP },
{ "stricthostkeychecking", oStrictHostKeyChecking },
{ "compression", oCompression },
- { "compressionlevel", oCompressionLevel },
{ "tcpkeepalive", oTCPKeepAlive },
{ "keepalive", oTCPKeepAlive }, /* obsolete */
{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
+ { "syslogfacility", oLogFacility },
{ "loglevel", oLogLevel },
{ "dynamicforward", oDynamicForward },
{ "preferredauthentications", oPreferredAuthentications },
{ "hostkeyalgorithms", oHostKeyAlgorithms },
+ { "casignaturealgorithms", oCASignatureAlgorithms },
{ "bindaddress", oBindAddress },
-#ifdef ENABLE_PKCS11
- { "smartcarddevice", oPKCS11Provider },
- { "pkcs11provider", oPKCS11Provider },
-#else
- { "smartcarddevice", oUnsupported },
- { "pkcs11provider", oUnsupported },
-#endif
+ { "bindinterface", oBindInterface },
{ "clearallforwardings", oClearAllForwardings },
{ "enablesshkeysign", oEnableSSHKeysign },
{ "verifyhostkeydns", oVerifyHostKeyDNS },
@@ -250,16 +279,18 @@ static struct {
{ "serveraliveinterval", oServerAliveInterval },
{ "serveralivecountmax", oServerAliveCountMax },
{ "sendenv", oSendEnv },
+ { "setenv", oSetEnv },
{ "controlpath", oControlPath },
{ "controlmaster", oControlMaster },
{ "controlpersist", oControlPersist },
{ "hashknownhosts", oHashKnownHosts },
+ { "include", oInclude },
{ "tunnel", oTunnel },
{ "tunneldevice", oTunnelDevice },
{ "localcommand", oLocalCommand },
{ "permitlocalcommand", oPermitLocalCommand },
+ { "remotecommand", oRemoteCommand },
{ "visualhostkey", oVisualHostKey },
- { "useroaming", oUseRoaming },
{ "kexalgorithms", oKexAlgorithms },
{ "ipqos", oIPQoS },
{ "requesttty", oRequestTTY },
@@ -275,11 +306,42 @@ static struct {
{ "fingerprinthash", oFingerprintHash },
{ "updatehostkeys", oUpdateHostkeys },
{ "hostbasedkeytypes", oHostbasedKeyTypes },
+ { "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
{ "ignoreunknown", oIgnoreUnknown },
+ { "proxyjump", oProxyJump },
+ { "securitykeyprovider", oSecurityKeyProvider },
{ NULL, oBadOption }
};
+static char *kex_default_pk_alg_filtered;
+
+const char *
+kex_default_pk_alg(void)
+{
+ if (kex_default_pk_alg_filtered == NULL)
+ fatal("kex_default_pk_alg not initialized.");
+ return kex_default_pk_alg_filtered;
+}
+
+char *
+ssh_connection_hash(const char *thishost, const char *host, const char *portstr,
+ const char *user)
+{
+ 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 ||
+ ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0)
+ fatal("%s: mux digest failed", __func__);
+ ssh_digest_free(md);
+ return tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1));
+}
+
/*
* Adds a local TCP/IP port forward to options. Never returns if there is an
* error.
@@ -289,13 +351,14 @@ void
add_local_forward(Options *options, const struct Forward *newfwd)
{
struct Forward *fwd;
-#ifndef NO_IPPORT_RESERVED_CONCEPT
- extern uid_t original_real_uid;
- if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0 &&
- newfwd->listen_path == NULL)
- fatal("Privileged ports can only be forwarded by root.");
-#endif
- options->local_forwards = xrealloc(options->local_forwards,
+ int i;
+
+ /* Don't add duplicates */
+ for (i = 0; i < options->num_local_forwards; i++) {
+ if (forward_equals(newfwd, options->local_forwards + i))
+ return;
+ }
+ options->local_forwards = xreallocarray(options->local_forwards,
options->num_local_forwards + 1,
sizeof(*options->local_forwards));
fwd = &options->local_forwards[options->num_local_forwards++];
@@ -317,8 +380,14 @@ void
add_remote_forward(Options *options, const struct Forward *newfwd)
{
struct Forward *fwd;
+ int i;
- options->remote_forwards = xrealloc(options->remote_forwards,
+ /* Don't add duplicates */
+ for (i = 0; i < options->num_remote_forwards; i++) {
+ if (forward_equals(newfwd, options->remote_forwards + i))
+ return;
+ }
+ options->remote_forwards = xreallocarray(options->remote_forwards,
options->num_remote_forwards + 1,
sizeof(*options->remote_forwards));
fwd = &options->remote_forwards[options->num_remote_forwards++];
@@ -364,6 +433,30 @@ clear_forwardings(Options *options)
}
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) {
+ debug2("%s: ignoring duplicate key %s", __func__, path);
+ 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)
{
@@ -376,8 +469,8 @@ add_identity_file(Options *options, const char *dir, const char *filename,
if (dir == NULL) /* no dir, filename is absolute */
path = xstrdup(filename);
- else
- (void)xasprintf(&path, "%.100s%.100s", dir, filename);
+ else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX)
+ fatal("Identity file path %s too long", path);
/* Avoid registering duplicates */
for (i = 0; i < options->num_identity_files; i++) {
@@ -414,19 +507,17 @@ default_ssh_port(void)
static int
execute_in_shell(const char *cmd)
{
- char *shell, *command_string;
+ char *shell;
pid_t pid;
int devnull, status;
- extern uid_t original_real_uid;
if ((shell = getenv("SHELL")) == NULL)
shell = _PATH_BSHELL;
- /*
- * Use "exec" to avoid "sh -c" processes on some platforms
- * (e.g. Solaris)
- */
- xasprintf(&command_string, "exec %s", cmd);
+ if (access(shell, X_OK) == -1) {
+ fatal("Shell \"%s\" is not executable: %s",
+ shell, strerror(errno));
+ }
/* Need this to redirect subprocess stdin/out */
if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
@@ -438,9 +529,6 @@ execute_in_shell(const char *cmd)
if ((pid = fork()) == 0) {
char *argv[4];
- /* Child. Permanently give up superuser privileges. */
- permanently_drop_suid(original_real_uid);
-
/* Redirect child stdin and stdout. Leave stderr */
if (dup2(devnull, STDIN_FILENO) == -1)
fatal("dup2: %s", strerror(errno));
@@ -452,22 +540,21 @@ execute_in_shell(const char *cmd)
argv[0] = shell;
argv[1] = "-c";
- argv[2] = command_string;
+ argv[2] = xstrdup(cmd);
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. */
- signal(SIGTERM, SIG_DFL);
+ ssh_signal(SIGTERM, SIG_DFL);
kill(getpid(), SIGTERM);
_exit(1);
}
/* Parent. */
- if (pid < 0)
+ if (pid == -1)
fatal("%s: fork: %.100s", __func__, strerror(errno));
close(devnull);
- free(command_string);
while (waitpid(pid, &status, 0) == -1) {
if (errno != EINTR && errno != EAGAIN)
@@ -486,14 +573,14 @@ execute_in_shell(const char *cmd)
*/
static int
match_cfg_line(Options *options, char **condition, struct passwd *pw,
- const char *host_arg, const char *original_host, int post_canon,
- const char *filename, int linenum)
+ const char *host_arg, const char *original_host, int final_pass,
+ int *want_final_pass, const char *filename, int linenum)
{
char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
const char *ruser;
int r, port, this_result, result = 1, attributes = 0, negate;
- size_t len;
char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
+ char uidstr[32];
/*
* Configuration is likely to be incomplete at this point so we
@@ -501,12 +588,15 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
*/
port = options->port <= 0 ? default_ssh_port() : options->port;
ruser = options->user == NULL ? pw->pw_name : options->user;
- if (options->hostname != NULL) {
+ if (final_pass) {
+ host = xstrdup(options->hostname);
+ } else if (options->hostname != NULL) {
/* NB. Please keep in sync with ssh.c:main() */
host = percent_expand(options->hostname,
"h", host_arg, (char *)NULL);
- } else
+ } else {
host = xstrdup(host_arg);
+ }
debug2("checking match for '%s' host %s originally %s",
cp, host, original_host);
@@ -530,8 +620,16 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
goto out;
}
attributes++;
- if (strcasecmp(attrib, "canonical") == 0) {
- r = !!post_canon; /* force bitmask member to boolean */
+ 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 */
if (r == (negate ? 1 : 0))
this_result = result = 0;
debug3("%.200s line %d: %smatched '%s'",
@@ -545,35 +643,41 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
result = -1;
goto out;
}
- len = strlen(arg);
if (strcasecmp(attrib, "host") == 0) {
criteria = xstrdup(host);
- r = match_hostname(host, arg, len) == 1;
+ r = match_hostname(host, arg) == 1;
if (r == (negate ? 1 : 0))
this_result = result = 0;
} else if (strcasecmp(attrib, "originalhost") == 0) {
criteria = xstrdup(original_host);
- r = match_hostname(original_host, arg, len) == 1;
+ r = match_hostname(original_host, arg) == 1;
if (r == (negate ? 1 : 0))
this_result = result = 0;
} else if (strcasecmp(attrib, "user") == 0) {
criteria = xstrdup(ruser);
- r = match_pattern_list(ruser, arg, len, 0) == 1;
+ r = match_pattern_list(ruser, arg, 0) == 1;
if (r == (negate ? 1 : 0))
this_result = result = 0;
} else if (strcasecmp(attrib, "localuser") == 0) {
criteria = xstrdup(pw->pw_name);
- r = match_pattern_list(pw->pw_name, arg, len, 0) == 1;
+ r = match_pattern_list(pw->pw_name, arg, 0) == 1;
if (r == (negate ? 1 : 0))
this_result = result = 0;
} else if (strcasecmp(attrib, "exec") == 0) {
+ char *conn_hash_hex;
+
if (gethostname(thishost, sizeof(thishost)) == -1)
fatal("gethostname: %s", strerror(errno));
strlcpy(shorthost, thishost, sizeof(shorthost));
shorthost[strcspn(thishost, ".")] = '\0';
snprintf(portstr, sizeof(portstr), "%d", port);
+ snprintf(uidstr, sizeof(uidstr), "%llu",
+ (unsigned long long)pw->pw_uid);
+ conn_hash_hex = ssh_connection_hash(thishost, host,
+ portstr, ruser);
cmd = percent_expand(arg,
+ "C", conn_hash_hex,
"L", shorthost,
"d", pw->pw_dir,
"h", host,
@@ -582,7 +686,9 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
"p", portstr,
"r", ruser,
"u", pw->pw_name,
+ "i", uidstr,
(char *)NULL);
+ free(conn_hash_hex);
if (result != 1) {
/* skip execution if prior predicate failed */
debug3("%.200s line %d: skipped exec "
@@ -625,32 +731,33 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
return result;
}
-/* Check and prepare a domain name: removes trailing '.' and lowercases */
+/* Remove environment variable by pattern */
static void
-valid_domain(char *name, const char *filename, int linenum)
+rm_env(Options *options, const char *arg, const char *filename, int linenum)
{
- size_t i, l = strlen(name);
- u_char c, last = '\0';
-
- if (l == 0)
- fatal("%s line %d: empty hostname suffix", filename, linenum);
- if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0]))
- fatal("%s line %d: hostname suffix \"%.100s\" "
- "starts with invalid character", filename, linenum, name);
- for (i = 0; i < l; i++) {
- c = tolower((u_char)name[i]);
- name[i] = (char)c;
- if (last == '.' && c == '.')
- fatal("%s line %d: hostname suffix \"%.100s\" contains "
- "consecutive separators", filename, linenum, name);
- if (c != '.' && c != '-' && !isalnum(c) &&
- c != '_') /* technically invalid, but common */
- fatal("%s line %d: hostname suffix \"%.100s\" contains "
- "invalid characters", filename, linenum, name);
- last = c;
+ int i, j;
+ char *cp;
+
+ /* Remove an environment variable */
+ for (i = 0; i < options->num_send_env; ) {
+ cp = xstrdup(options->send_env[i]);
+ if (!match_pattern(cp, arg + 1)) {
+ free(cp);
+ i++;
+ continue;
+ }
+ debug3("%s line %d: removing environment %s",
+ filename, linenum, cp);
+ free(cp);
+ 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 */
}
- if (name[l - 1] == '.')
- name[l - 1] = '\0';
}
/*
@@ -665,8 +772,8 @@ parse_token(const char *cp, const char *filename, int linenum,
for (i = 0; keywords[i].name; i++)
if (strcmp(cp, keywords[i].name) == 0)
return keywords[i].opcode;
- if (ignored_unknown != NULL && match_pattern_list(cp, ignored_unknown,
- strlen(ignored_unknown), 1) == 1)
+ if (ignored_unknown != NULL &&
+ match_pattern_list(cp, ignored_unknown, 1) == 1)
return oIgnoredUnknownOption;
error("%s: line %d: Bad configuration option: %s",
filename, linenum, cp);
@@ -693,6 +800,25 @@ static const struct multistate multistate_yesnoask[] = {
{ "ask", 2 },
{ NULL, -1 }
};
+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 }
+};
+static const struct multistate multistate_yesnoaskconfirm[] = {
+ { "true", 1 },
+ { "false", 0 },
+ { "yes", 1 },
+ { "no", 0 },
+ { "ask", 2 },
+ { "confirm", 3 },
+ { NULL, -1 }
+};
static const struct multistate multistate_addressfamily[] = {
{ "inet", AF_INET },
{ "inet6", AF_INET6 },
@@ -735,36 +861,58 @@ static const struct multistate multistate_canonicalizehostname[] = {
{ "always", SSH_CANONICALISE_ALWAYS },
{ NULL, -1 }
};
+static const struct multistate multistate_compression[] = {
+#ifdef WITH_ZLIB
+ { "yes", COMP_ZLIB },
+#endif
+ { "no", COMP_NONE },
+ { NULL, -1 }
+};
/*
* Processes a single option line as used in the configuration files. This
* only sets those values that have not already been set.
*/
-#define WHITESPACE " \t\r\n"
int
process_config_line(Options *options, struct passwd *pw, const char *host,
const char *original_host, char *line, const char *filename,
int linenum, int *activep, int flags)
{
+ return process_config_line_depth(options, pw, host, original_host,
+ line, filename, linenum, activep, flags, NULL, 0);
+}
+
+#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,
+ int linenum, int *activep, int flags, int *want_final_pass, int depth)
+{
char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
char **cpptr, fwdarg[256];
u_int i, *uintptr, max_entries = 0;
- int negated, opcode, *intptr, value, value2, cmdline = 0;
+ int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
+ int remotefwd, dynamicfwd;
LogLevel *log_level_ptr;
+ SyslogFacility *log_facility_ptr;
long long val64;
size_t len;
struct Forward fwd;
const struct multistate *multistate_ptr;
struct allowed_cname *cname;
+ glob_t gl;
+ const char *errstr;
if (activep == NULL) { /* We are processing a command line directive */
cmdline = 1;
activep = &cmdline;
}
- /* Strip trailing whitespace */
- for (len = strlen(line) - 1; len > 0; len--) {
- if (strchr(WHITESPACE, line[len]) == NULL)
+ /* Strip trailing whitespace. Allow \f (form feed) at EOL only */
+ if ((len = strlen(line)) == 0)
+ return 0;
+ for (len--; len > 0; len--) {
+ if (strchr(WHITESPACE "\f", line[len]) == NULL)
break;
line[len] = '\0';
}
@@ -788,7 +936,8 @@ process_config_line(Options *options, struct passwd *pw, const char *host,
case oBadOption:
/* don't panic, but count bad options */
return -1;
- /* NOTREACHED */
+ case oIgnore:
+ return 0;
case oIgnoredUnknownOption:
debug("%s line %d: Ignored unknown option \"%s\"",
filename, linenum, keyword);
@@ -811,6 +960,34 @@ parse_time:
case oForwardAgent:
intptr = &options->forward_agent;
+
+ arg = strdelim(&s);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: missing argument.",
+ filename, linenum);
+
+ value = -1;
+ multistate_ptr = multistate_flag;
+ for (i = 0; multistate_ptr[i].key != NULL; i++) {
+ if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
+ value = multistate_ptr[i].value;
+ break;
+ }
+ }
+ if (value != -1) {
+ if (*activep && *intptr == -1)
+ *intptr = value;
+ break;
+ }
+ /* ForwardAgent wasn't 'yes' or 'no', assume a path */
+ if (*activep && *intptr == -1)
+ *intptr = 1;
+
+ charptr = &options->forward_agent_sock_path;
+ goto parse_agent_path;
+
+ case oForwardX11:
+ intptr = &options->forward_x11;
parse_flag:
multistate_ptr = multistate_flag;
parse_multistate:
@@ -832,10 +1009,6 @@ parse_time:
*intptr = value;
break;
- case oForwardX11:
- intptr = &options->forward_x11;
- goto parse_flag;
-
case oForwardX11Trusted:
intptr = &options->forward_x11_trusted;
goto parse_flag;
@@ -852,10 +1025,6 @@ parse_time:
intptr = &options->exit_on_forward_failure;
goto parse_flag;
- case oUsePrivilegedPort:
- intptr = &options->use_privileged_port;
- goto parse_flag;
-
case oPasswordAuthentication:
intptr = &options->password_authentication;
goto parse_flag;
@@ -872,14 +1041,6 @@ parse_time:
intptr = &options->pubkey_authentication;
goto parse_flag;
- case oRSAAuthentication:
- intptr = &options->rsa_authentication;
- goto parse_flag;
-
- case oRhostsRSAAuthentication:
- intptr = &options->rhosts_rsa_authentication;
- goto parse_flag;
-
case oHostbasedAuthentication:
intptr = &options->hostbased_authentication;
goto parse_flag;
@@ -911,12 +1072,13 @@ parse_time:
case oStrictHostKeyChecking:
intptr = &options->strict_host_key_checking;
- multistate_ptr = multistate_yesnoask;
+ multistate_ptr = multistate_strict_hostkey;
goto parse_multistate;
case oCompression:
intptr = &options->compression;
- goto parse_flag;
+ multistate_ptr = multistate_compression;
+ goto parse_multistate;
case oTCPKeepAlive:
intptr = &options->tcp_keep_alive;
@@ -930,10 +1092,6 @@ parse_time:
intptr = &options->number_of_password_prompts;
goto parse_int;
- case oCompressionLevel:
- intptr = &options->compression_level;
- goto parse_int;
-
case oRekeyLimit:
arg = strdelim(&s);
if (!arg || *arg == '\0')
@@ -945,16 +1103,12 @@ parse_time:
if (scan_scaled(arg, &val64) == -1)
fatal("%.200s line %d: Bad number '%s': %s",
filename, linenum, arg, strerror(errno));
- /* check for too-large or too-small limits */
- if (val64 > UINT_MAX)
- fatal("%.200s line %d: RekeyLimit too large",
- filename, linenum);
if (val64 != 0 && val64 < 16)
fatal("%.200s line %d: RekeyLimit too small",
filename, linenum);
}
if (*activep && options->rekey_limit == -1)
- options->rekey_limit = (u_int32_t)val64;
+ options->rekey_limit = val64;
if (s != NULL) { /* optional rekey interval present */
if (strcmp(s, "none") == 0) {
(void)strdelim(&s); /* discard */
@@ -979,6 +1133,24 @@ parse_time:
}
break;
+ case oCertificateFile:
+ arg = strdelim(&s);
+ if (!arg || *arg == '\0')
+ fatal("%.200s line %d: Missing argument.",
+ filename, linenum);
+ if (*activep) {
+ intptr = &options->num_certificate_files;
+ if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
+ fatal("%.200s line %d: Too many certificate "
+ "files specified (max %d).",
+ filename, linenum,
+ SSH_MAX_CERTIFICATE_FILES);
+ }
+ add_certificate_file(options, arg,
+ flags & SSHCONF_USERCONF);
+ }
+ break;
+
case oXAuthLocation:
charptr=&options->xauth_location;
goto parse_string;
@@ -1003,7 +1175,7 @@ parse_char_array:
while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
if ((*uintptr) >= max_entries)
fatal("%s line %d: "
- "too many authorized keys files.",
+ "too many known hosts files.",
filename, linenum);
cpptr[(*uintptr)++] = xstrdup(arg);
}
@@ -1016,7 +1188,7 @@ parse_char_array:
max_entries = SSH_MAX_HOSTS_FILES;
goto parse_char_array;
- case oHostName:
+ case oHostname:
charptr = &options->hostname;
goto parse_string;
@@ -1032,12 +1204,23 @@ parse_char_array:
charptr = &options->bind_address;
goto parse_string;
+ case oBindInterface:
+ charptr = &options->bind_interface;
+ goto parse_string;
+
case oPKCS11Provider:
charptr = &options->pkcs11_provider;
goto parse_string;
+ case oSecurityKeyProvider:
+ charptr = &options->sk_provider;
+ goto parse_string;
+
case oProxyCommand:
charptr = &options->proxy_command;
+ /* Ignore ProxyCommand if ProxyJump already specified */
+ if (options->jump_host != NULL)
+ charptr = &options->jump_host; /* Skip below */
parse_command:
if (s == NULL)
fatal("%.200s line %d: Missing argument.", filename, linenum);
@@ -1046,36 +1229,38 @@ parse_command:
*charptr = xstrdup(s + len);
return 0;
+ case oProxyJump:
+ if (s == NULL) {
+ fatal("%.200s line %d: Missing argument.",
+ filename, linenum);
+ }
+ len = strspn(s, WHITESPACE "=");
+ if (parse_jump(s + len, options, *activep) == -1) {
+ fatal("%.200s line %d: Invalid ProxyJump \"%s\"",
+ filename, linenum, s + len);
+ }
+ return 0;
+
case oPort:
- intptr = &options->port;
-parse_int:
arg = strdelim(&s);
if (!arg || *arg == '\0')
- fatal("%.200s line %d: Missing argument.", filename, linenum);
- if (arg[0] < '0' || arg[0] > '9')
- fatal("%.200s line %d: Bad number.", filename, linenum);
-
- /* Octal, decimal, or hex format? */
- value = strtol(arg, &endofnumber, 0);
- if (arg == endofnumber)
- fatal("%.200s line %d: Bad number.", filename, linenum);
- if (*activep && *intptr == -1)
- *intptr = value;
+ fatal("%.200s line %d: Missing argument.",
+ filename, linenum);
+ value = a2port(arg);
+ if (value <= 0)
+ fatal("%.200s line %d: Bad port '%s'.",
+ filename, linenum, arg);
+ if (*activep && options->port == -1)
+ options->port = value;
break;
case oConnectionAttempts:
intptr = &options->connection_attempts;
- goto parse_int;
-
- case oCipher:
- intptr = &options->cipher;
+parse_int:
arg = strdelim(&s);
- if (!arg || *arg == '\0')
- fatal("%.200s line %d: Missing argument.", filename, linenum);
- value = cipher_number(arg);
- if (value == -1)
- fatal("%.200s line %d: Bad cipher '%s'.",
- filename, linenum, arg ? arg : "<NONE>");
+ if ((errstr = atoi_err(arg, &value)) != NULL)
+ fatal("%s line %d: integer value %s.",
+ filename, linenum, errstr);
if (*activep && *intptr == -1)
*intptr = value;
break;
@@ -1084,7 +1269,8 @@ parse_int:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum);
- if (!ciphers_valid(arg))
+ if (*arg != '-' &&
+ !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
if (*activep && options->ciphers == NULL)
@@ -1095,8 +1281,9 @@ parse_int:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum);
- if (!mac_valid(arg))
- fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
+ if (*arg != '-' &&
+ !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg))
+ fatal("%.200s line %d: Bad SSH2 MAC spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
if (*activep && options->macs == NULL)
options->macs = xstrdup(arg);
@@ -1107,7 +1294,9 @@ parse_int:
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.",
filename, linenum);
- if (!kex_names_valid(arg))
+ if (*arg != '-' &&
+ !kex_names_valid(*arg == '+' || *arg == '^' ?
+ arg + 1 : arg))
fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
filename, linenum, arg ? arg : "<NONE>");
if (*activep && options->kex_algorithms == NULL)
@@ -1115,28 +1304,24 @@ parse_int:
break;
case oHostKeyAlgorithms:
+ charptr = &options->hostkeyalgorithms;
+parse_keytypes:
arg = strdelim(&s);
if (!arg || *arg == '\0')
- fatal("%.200s line %d: Missing argument.", filename, linenum);
- if (!sshkey_names_valid2(arg, 1))
- fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
- filename, linenum, arg ? arg : "<NONE>");
- if (*activep && options->hostkeyalgorithms == NULL)
- options->hostkeyalgorithms = xstrdup(arg);
+ fatal("%.200s line %d: Missing argument.",
+ filename, linenum);
+ if (*arg != '-' &&
+ !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
+ arg + 1 : arg, 1))
+ fatal("%s line %d: Bad key types '%s'.",
+ filename, linenum, arg ? arg : "<NONE>");
+ if (*activep && *charptr == NULL)
+ *charptr = xstrdup(arg);
break;
- case oProtocol:
- intptr = &options->protocol;
- arg = strdelim(&s);
- if (!arg || *arg == '\0')
- fatal("%.200s line %d: Missing argument.", filename, linenum);
- value = proto_spec(arg);
- if (value == SSH_PROTO_UNKNOWN)
- fatal("%.200s line %d: Bad protocol spec '%s'.",
- filename, linenum, arg ? arg : "<NONE>");
- if (*activep && *intptr == SSH_PROTO_UNKNOWN)
- *intptr = value;
- break;
+ case oCASignatureAlgorithms:
+ charptr = &options->ca_sign_algorithms;
+ goto parse_keytypes;
case oLogLevel:
log_level_ptr = &options->log_level;
@@ -1149,6 +1334,17 @@ parse_int:
*log_level_ptr = (LogLevel) value;
break;
+ case oLogFacility:
+ log_facility_ptr = &options->log_facility;
+ arg = strdelim(&s);
+ value = log_facility_number(arg);
+ if (value == SYSLOG_FACILITY_NOT_SET)
+ fatal("%.200s line %d: unsupported log facility '%s'",
+ filename, linenum, arg ? arg : "<NONE>");
+ if (*log_facility_ptr == -1)
+ *log_facility_ptr = (SyslogFacility) value;
+ break;
+
case oLocalForward:
case oRemoteForward:
case oDynamicForward:
@@ -1157,31 +1353,36 @@ parse_int:
fatal("%.200s line %d: Missing port argument.",
filename, linenum);
- if (opcode == oLocalForward ||
- opcode == oRemoteForward) {
- arg2 = strdelim(&s);
- if (arg2 == NULL || *arg2 == '\0')
- fatal("%.200s line %d: Missing target argument.",
- filename, linenum);
+ remotefwd = (opcode == oRemoteForward);
+ dynamicfwd = (opcode == oDynamicForward);
- /* construct a string for parse_forward */
- snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
- } else if (opcode == oDynamicForward) {
- strlcpy(fwdarg, arg, sizeof(fwdarg));
+ if (!dynamicfwd) {
+ arg2 = strdelim(&s);
+ if (arg2 == NULL || *arg2 == '\0') {
+ if (remotefwd)
+ dynamicfwd = 1;
+ else
+ fatal("%.200s line %d: Missing target "
+ "argument.", filename, linenum);
+ } else {
+ /* construct a string for parse_forward */
+ snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg,
+ arg2);
+ }
}
+ if (dynamicfwd)
+ strlcpy(fwdarg, arg, sizeof(fwdarg));
- if (parse_forward(&fwd, fwdarg,
- opcode == oDynamicForward ? 1 : 0,
- opcode == oRemoteForward ? 1 : 0) == 0)
+ if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0)
fatal("%.200s line %d: Bad forwarding specification.",
filename, linenum);
if (*activep) {
- if (opcode == oLocalForward ||
- opcode == oDynamicForward)
- add_local_forward(options, &fwd);
- else if (opcode == oRemoteForward)
+ if (remotefwd) {
add_remote_forward(options, &fwd);
+ } else {
+ add_local_forward(options, &fwd);
+ }
}
break;
@@ -1196,6 +1397,8 @@ parse_int:
*activep = 0;
arg2 = NULL;
while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
+ if ((flags & SSHCONF_NEVERMATCH) != 0)
+ break;
negated = *arg == '!';
if (negated)
arg++;
@@ -1224,11 +1427,12 @@ parse_int:
fatal("Host directive not supported as a command-line "
"option");
value = match_cfg_line(options, &s, pw, host, original_host,
- flags & SSHCONF_POSTCANON, filename, linenum);
+ flags & SSHCONF_FINAL, want_final_pass,
+ filename, linenum);
if (value < 0)
fatal("%.200s line %d: Bad Match condition", filename,
linenum);
- *activep = value;
+ *activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
break;
case oEscapeChar:
@@ -1236,13 +1440,13 @@ parse_int:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum);
- if (arg[0] == '^' && arg[2] == 0 &&
+ 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 &&
(u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
value = (u_char) arg[1] & 31;
- else if (strlen(arg) == 1)
- value = (u_char) arg[0];
- else if (strcmp(arg, "none") == 0)
- value = SSH_ESCAPECHAR_NONE;
else {
fatal("%.200s line %d: Bad escape character.",
filename, linenum);
@@ -1281,11 +1485,41 @@ parse_int:
filename, linenum);
if (!*activep)
continue;
- if (options->num_send_env >= MAX_SEND_ENV)
- fatal("%s line %d: too many send env.",
+ if (*arg == '-') {
+ /* Removing an env var */
+ rm_env(options, arg, filename, linenum);
+ continue;
+ } else {
+ /* Adding an env var */
+ if (options->num_send_env >= INT_MAX)
+ fatal("%s line %d: too many send env.",
+ filename, linenum);
+ options->send_env = xrecallocarray(
+ options->send_env, options->num_send_env,
+ options->num_send_env + 1,
+ sizeof(*options->send_env));
+ options->send_env[options->num_send_env++] =
+ xstrdup(arg);
+ }
+ }
+ break;
+
+ case oSetEnv:
+ value = options->num_setenv;
+ while ((arg = strdelimw(&s)) != NULL && *arg != '\0') {
+ if (strchr(arg, '=') == NULL)
+ fatal("%s line %d: Invalid SetEnv.",
+ filename, linenum);
+ if (!*activep || value != 0)
+ continue;
+ /* Adding a setenv var */
+ if (options->num_setenv >= INT_MAX)
+ fatal("%s line %d: too many SetEnv.",
filename, linenum);
- options->send_env[options->num_send_env++] =
- xstrdup(arg);
+ options->setenv = xrecallocarray(
+ options->setenv, options->num_setenv,
+ options->num_setenv + 1, sizeof(*options->setenv));
+ options->setenv[options->num_setenv++] = xstrdup(arg);
}
break;
@@ -1352,10 +1586,77 @@ parse_int:
intptr = &options->permit_local_command;
goto parse_flag;
+ case oRemoteCommand:
+ charptr = &options->remote_command;
+ goto parse_command;
+
case oVisualHostKey:
intptr = &options->visual_host_key;
goto parse_flag;
+ case oInclude:
+ if (cmdline)
+ fatal("Include directive not supported as a "
+ "command-line option");
+ value = 0;
+ while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
+ /*
+ * 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.
+ */
+ if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0)
+ fatal("%.200s line %d: bad include path %s.",
+ filename, linenum, arg);
+ if (!path_absolute(arg) && *arg != '~') {
+ 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);
+ free(arg2);
+ continue;
+ } else if (r != 0)
+ fatal("%.200s line %d: glob failed for %s.",
+ filename, linenum, arg2);
+ free(arg2);
+ oactive = *activep;
+ for (i = 0; i < gl.gl_pathc; i++) {
+ 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),
+ activep, want_final_pass, depth + 1);
+ if (r != 1 && errno != ENOENT) {
+ fatal("Can't open user config file "
+ "%.100s: %.100s", gl.gl_pathv[i],
+ strerror(errno));
+ }
+ /*
+ * 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)
+ return value;
+ break;
+
case oIPQoS:
arg = strdelim(&s);
if ((value = parse_ipqos(arg)) == -1)
@@ -1373,10 +1674,6 @@ parse_int:
}
break;
- case oUseRoaming:
- intptr = &options->use_roaming;
- goto parse_flag;
-
case oRequestTTY:
intptr = &options->request_tty;
multistate_ptr = multistate_requesttty;
@@ -1393,7 +1690,10 @@ parse_int:
case oCanonicalDomains:
value = options->num_canonical_domains != 0;
while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
- valid_domain(arg, filename, linenum);
+ if (!valid_domain(arg, 1, &errstr)) {
+ fatal("%s line %d: %s", filename, linenum,
+ errstr);
+ }
if (!*activep || value)
continue;
if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
@@ -1485,13 +1785,29 @@ parse_int:
case oHostbasedKeyTypes:
charptr = &options->hostbased_key_types;
+ goto parse_keytypes;
+
+ case oPubkeyAcceptedKeyTypes:
+ charptr = &options->pubkey_key_types;
+ goto parse_keytypes;
+
+ case oAddKeysToAgent:
+ intptr = &options->add_keys_to_agent;
+ multistate_ptr = multistate_yesnoaskconfirm;
+ goto parse_multistate;
+
+ case oIdentityAgent:
+ charptr = &options->identity_agent;
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.",
filename, linenum);
- if (!sshkey_names_valid2(arg, 1))
- fatal("%s line %d: Bad key types '%s'.",
- filename, linenum, arg ? arg : "<NONE>");
+ parse_agent_path:
+ /* Extra validation if the string represents an env var. */
+ if (arg[0] == '$' && !valid_env_name(arg + 1)) {
+ fatal("%.200s line %d: Invalid environment name %s.",
+ filename, linenum, arg);
+ }
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
break;
@@ -1518,22 +1834,37 @@ parse_int:
return 0;
}
-
/*
* Reads the config file and modifies the options accordingly. Options
* should already be initialized before this call. This never returns if
* there is an error. If the file does not exist, this returns 0.
*/
-
int
read_config_file(const char *filename, struct passwd *pw, const char *host,
- const char *original_host, Options *options, int flags)
+ const char *original_host, Options *options, int flags,
+ int *want_final_pass)
+{
+ int active = 1;
+
+ return read_config_file_depth(filename, pw, host, original_host,
+ options, flags, &active, want_final_pass, 0);
+}
+
+#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,
+ int flags, int *activep, int *want_final_pass, int depth)
{
FILE *f;
- char line[1024];
- int active, linenum;
+ char *line = NULL;
+ size_t linesize = 0;
+ int linenum;
int bad_options = 0;
+ if (depth < 0 || depth > READCONF_MAX_DEPTH)
+ fatal("Too many recursive configuration includes");
+
if ((f = fopen(filename, "r")) == NULL)
return 0;
@@ -1553,15 +1884,16 @@ read_config_file(const char *filename, struct passwd *pw, const char *host,
* Mark that we are now processing the options. This flag is turned
* on/off by Host specifications.
*/
- active = 1;
linenum = 0;
- while (fgets(line, sizeof(line), f)) {
+ while (getline(&line, &linesize, f) != -1) {
/* Update line number counter. */
linenum++;
- if (process_config_line(options, pw, host, original_host,
- line, filename, linenum, &active, flags) != 0)
+ if (process_config_line_depth(options, pw, host, original_host,
+ line, filename, linenum, activep, flags, want_final_pass,
+ depth) != 0)
bad_options++;
}
+ free(line);
fclose(f);
if (bad_options > 0)
fatal("%s: terminating, %d bad configuration options",
@@ -1588,16 +1920,18 @@ initialize_options(Options * options)
{
memset(options, 'X', sizeof(*options));
options->forward_agent = -1;
+ options->forward_agent_sock_path = NULL;
options->forward_x11 = -1;
options->forward_x11_trusted = -1;
options->forward_x11_timeout = -1;
+ options->stdio_forward_host = NULL;
+ options->stdio_forward_port = 0;
+ options->clear_forwardings = -1;
options->exit_on_forward_failure = -1;
options->xauth_location = NULL;
options->fwd_opts.gateway_ports = -1;
options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
options->fwd_opts.streamlocal_bind_unlink = -1;
- options->use_privileged_port = -1;
- options->rsa_authentication = -1;
options->pubkey_authentication = -1;
options->challenge_response_authentication = -1;
options->gss_authentication = -1;
@@ -1605,29 +1939,31 @@ initialize_options(Options * options)
options->password_authentication = -1;
options->kbd_interactive_authentication = -1;
options->kbd_interactive_devices = NULL;
- options->rhosts_rsa_authentication = -1;
options->hostbased_authentication = -1;
options->batch_mode = -1;
options->check_host_ip = -1;
options->strict_host_key_checking = -1;
options->compression = -1;
options->tcp_keep_alive = -1;
- options->compression_level = -1;
options->port = -1;
options->address_family = -1;
options->connection_attempts = -1;
options->connection_timeout = -1;
options->number_of_password_prompts = -1;
- options->cipher = -1;
options->ciphers = NULL;
options->macs = NULL;
options->kex_algorithms = NULL;
options->hostkeyalgorithms = NULL;
- options->protocol = SSH_PROTO_UNKNOWN;
+ options->ca_sign_algorithms = NULL;
options->num_identity_files = 0;
+ options->num_certificate_files = 0;
options->hostname = NULL;
options->host_key_alias = NULL;
options->proxy_command = NULL;
+ options->jump_user = NULL;
+ options->jump_host = NULL;
+ options->jump_port = -1;
+ options->jump_extra = NULL;
options->user = NULL;
options->escape_char = -1;
options->num_system_hostfiles = 0;
@@ -1636,11 +1972,13 @@ initialize_options(Options * options)
options->num_local_forwards = 0;
options->remote_forwards = NULL;
options->num_remote_forwards = 0;
- options->clear_forwardings = -1;
+ options->log_facility = SYSLOG_FACILITY_NOT_SET;
options->log_level = SYSLOG_LEVEL_NOT_SET;
options->preferred_authentications = NULL;
options->bind_address = NULL;
+ options->bind_interface = NULL;
options->pkcs11_provider = NULL;
+ options->sk_provider = NULL;
options->enable_ssh_keysign = - 1;
options->no_host_authentication_for_localhost = - 1;
options->identities_only = - 1;
@@ -1649,7 +1987,10 @@ initialize_options(Options * options)
options->verify_host_key_dns = -1;
options->server_alive_interval = -1;
options->server_alive_count_max = -1;
+ options->send_env = NULL;
options->num_send_env = 0;
+ options->setenv = NULL;
+ options->num_setenv = 0;
options->control_path = NULL;
options->control_master = -1;
options->control_persist = -1;
@@ -1660,7 +2001,9 @@ initialize_options(Options * options)
options->tun_remote = -1;
options->local_command = NULL;
options->permit_local_command = -1;
- options->use_roaming = 0;
+ options->remote_command = NULL;
+ options->add_keys_to_agent = -1;
+ options->identity_agent = NULL;
options->visual_host_key = -1;
options->ip_qos_interactive = -1;
options->ip_qos_bulk = -1;
@@ -1676,6 +2019,7 @@ initialize_options(Options * options)
options->fingerprint_hash = -1;
options->update_hostkeys = -1;
options->hostbased_key_types = NULL;
+ options->pubkey_key_types = NULL;
}
/*
@@ -1700,6 +2044,10 @@ fill_default_options_for_canonicalization(Options *options)
void
fill_default_options(Options * options)
{
+ char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
+ char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
+ int r;
+
if (options->forward_agent == -1)
options->forward_agent = 0;
if (options->forward_x11 == -1)
@@ -1708,8 +2056,19 @@ fill_default_options(Options * options)
options->forward_x11_trusted = 0;
if (options->forward_x11_timeout == -1)
options->forward_x11_timeout = 1200;
+ /*
+ * stdio forwarding (-W) changes the default for these but we defer
+ * setting the values so they can be overridden.
+ */
if (options->exit_on_forward_failure == -1)
- options->exit_on_forward_failure = 0;
+ 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)
options->xauth_location = _PATH_XAUTH;
if (options->fwd_opts.gateway_ports == -1)
@@ -1718,10 +2077,6 @@ fill_default_options(Options * options)
options->fwd_opts.streamlocal_bind_mask = 0177;
if (options->fwd_opts.streamlocal_bind_unlink == -1)
options->fwd_opts.streamlocal_bind_unlink = 0;
- if (options->use_privileged_port == -1)
- options->use_privileged_port = 0;
- if (options->rsa_authentication == -1)
- options->rsa_authentication = 1;
if (options->pubkey_authentication == -1)
options->pubkey_authentication = 1;
if (options->challenge_response_authentication == -1)
@@ -1734,8 +2089,6 @@ fill_default_options(Options * options)
options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1)
options->kbd_interactive_authentication = 1;
- if (options->rhosts_rsa_authentication == -1)
- options->rhosts_rsa_authentication = 0;
if (options->hostbased_authentication == -1)
options->hostbased_authentication = 0;
if (options->batch_mode == -1)
@@ -1743,13 +2096,11 @@ fill_default_options(Options * options)
if (options->check_host_ip == -1)
options->check_host_ip = 1;
if (options->strict_host_key_checking == -1)
- options->strict_host_key_checking = 2; /* 2 is default */
+ options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK;
if (options->compression == -1)
options->compression = 0;
if (options->tcp_keep_alive == -1)
options->tcp_keep_alive = 1;
- if (options->compression_level == -1)
- options->compression_level = 6;
if (options->port == -1)
options->port = 0; /* Filled in ssh_connect. */
if (options->address_family == -1)
@@ -1758,32 +2109,22 @@ fill_default_options(Options * options)
options->connection_attempts = 1;
if (options->number_of_password_prompts == -1)
options->number_of_password_prompts = 3;
- /* Selected in ssh_login(). */
- if (options->cipher == -1)
- options->cipher = SSH_CIPHER_NOT_SET;
- /* options->ciphers, default set in myproposals.h */
- /* options->macs, default set in myproposals.h */
- /* options->kex_algorithms, default set in myproposals.h */
/* options->hostkeyalgorithms, default set in myproposals.h */
- if (options->protocol == SSH_PROTO_UNKNOWN)
- options->protocol = SSH_PROTO_2;
+ if (options->add_keys_to_agent == -1)
+ options->add_keys_to_agent = 0;
if (options->num_identity_files == 0) {
- if (options->protocol & SSH_PROTO_1) {
- add_identity_file(options, "~/",
- _PATH_SSH_CLIENT_IDENTITY, 0);
- }
- if (options->protocol & SSH_PROTO_2) {
- add_identity_file(options, "~/",
- _PATH_SSH_CLIENT_ID_RSA, 0);
- add_identity_file(options, "~/",
- _PATH_SSH_CLIENT_ID_DSA, 0);
+ add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0);
+ add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0);
#ifdef OPENSSL_HAS_ECC
- add_identity_file(options, "~/",
- _PATH_SSH_CLIENT_ID_ECDSA, 0);
+ add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
+ add_identity_file(options, "~/",
+ _PATH_SSH_CLIENT_ID_ECDSA_SK, 0);
#endif
- add_identity_file(options, "~/",
- _PATH_SSH_CLIENT_ID_ED25519, 0);
- }
+ add_identity_file(options, "~/",
+ _PATH_SSH_CLIENT_ID_ED25519, 0);
+ add_identity_file(options, "~/",
+ _PATH_SSH_CLIENT_ID_ED25519_SK, 0);
+ add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0);
}
if (options->escape_char == -1)
options->escape_char = '~';
@@ -1793,6 +2134,8 @@ fill_default_options(Options * options)
options->system_hostfiles[options->num_system_hostfiles++] =
xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
}
+ if (options->update_hostkeys == -1)
+ options->update_hostkeys = SSH_UPDATE_HOSTKEYS_NO;
if (options->num_user_hostfiles == 0) {
options->user_hostfiles[options->num_user_hostfiles++] =
xstrdup(_PATH_SSH_USER_HOSTFILE);
@@ -1801,8 +2144,8 @@ fill_default_options(Options * options)
}
if (options->log_level == SYSLOG_LEVEL_NOT_SET)
options->log_level = SYSLOG_LEVEL_INFO;
- if (options->clear_forwardings == 1)
- clear_forwardings(options);
+ if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
+ options->log_facility = SYSLOG_FACILITY_USER;
if (options->no_host_authentication_for_localhost == - 1)
options->no_host_authentication_for_localhost = 0;
if (options->identities_only == -1)
@@ -1835,13 +2178,12 @@ fill_default_options(Options * options)
options->tun_remote = SSH_TUNID_ANY;
if (options->permit_local_command == -1)
options->permit_local_command = 0;
- options->use_roaming = 0;
if (options->visual_host_key == -1)
options->visual_host_key = 0;
if (options->ip_qos_interactive == -1)
- options->ip_qos_interactive = IPTOS_LOWDELAY;
+ options->ip_qos_interactive = IPTOS_DSCP_AF21;
if (options->ip_qos_bulk == -1)
- options->ip_qos_bulk = IPTOS_THROUGHPUT;
+ options->ip_qos_bulk = IPTOS_DSCP_CS1;
if (options->request_tty == -1)
options->request_tty = REQUEST_TTY_AUTO;
if (options->proxy_use_fdpass == -1)
@@ -1854,10 +2196,49 @@ fill_default_options(Options * options)
options->canonicalize_hostname = SSH_CANONICALISE_NO;
if (options->fingerprint_hash == -1)
options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
- if (options->update_hostkeys == -1)
- options->update_hostkeys = 0;
- if (options->hostbased_key_types == NULL)
- options->hostbased_key_types = xstrdup("*");
+#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
+
+ /* 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, ',');
+ all_sig = sshkey_alg_list(0, 1, 1, ',');
+ /* remove unsupported algos from default lists */
+ def_cipher = match_filter_whitelist(KEX_CLIENT_ENCRYPT, all_cipher);
+ def_mac = match_filter_whitelist(KEX_CLIENT_MAC, all_mac);
+ def_kex = match_filter_whitelist(KEX_CLIENT_KEX, all_kex);
+ def_key = match_filter_whitelist(KEX_DEFAULT_PK_ALG, all_key);
+ def_sig = match_filter_whitelist(SSH_ALLOWED_CA_SIGALGS, all_sig);
+#define ASSEMBLE(what, defaults, all) \
+ do { \
+ if ((r = kex_assemble_names(&options->what, \
+ defaults, all)) != 0) \
+ fatal("%s: %s: %s", __func__, #what, ssh_err(r)); \
+ } while (0)
+ ASSEMBLE(ciphers, def_cipher, all_cipher);
+ ASSEMBLE(macs, def_mac, all_mac);
+ ASSEMBLE(kex_algorithms, def_kex, all_kex);
+ ASSEMBLE(hostbased_key_types, def_key, all_key);
+ ASSEMBLE(pubkey_key_types, def_key, all_key);
+ ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
+#undef ASSEMBLE
+ free(all_cipher);
+ free(all_mac);
+ free(all_kex);
+ free(all_key);
+ free(all_sig);
+ free(def_cipher);
+ free(def_mac);
+ free(def_kex);
+ kex_default_pk_alg_filtered = def_key; /* save for later use */
+ free(def_sig);
#define CLEAR_ON_NONE(v) \
do { \
@@ -1867,9 +2248,19 @@ fill_default_options(Options * options)
} \
} while(0)
CLEAR_ON_NONE(options->local_command);
+ CLEAR_ON_NONE(options->remote_command);
CLEAR_ON_NONE(options->proxy_command);
CLEAR_ON_NONE(options->control_path);
CLEAR_ON_NONE(options->revoked_host_keys);
+ CLEAR_ON_NONE(options->pkcs11_provider);
+ CLEAR_ON_NONE(options->sk_provider);
+ 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;
+ }
+ /* options->identity_agent distinguishes NULL from 'none' */
/* options->user will be set in the main program if appropriate */
/* options->hostname will be set in the main program if appropriate */
/* options->host_key_alias should not be set by default */
@@ -1926,7 +2317,8 @@ parse_fwd_field(char **p, struct fwdarg *fwd)
switch (*cp) {
case '\\':
memmove(cp, cp + 1, strlen(cp + 1) + 1);
- cp++;
+ if (*cp == '\0')
+ return -1;
break;
case '/':
ispath = 1;
@@ -2084,6 +2476,75 @@ parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remo
return (0);
}
+int
+parse_jump(const char *s, Options *o, int active)
+{
+ char *orig, *sdup, *cp;
+ char *host = NULL, *user = NULL;
+ int ret = -1, port = -1, first;
+
+ active &= o->proxy_command == NULL && o->jump_host == NULL;
+
+ orig = sdup = xstrdup(s);
+ first = active;
+ do {
+ if (strcasecmp(s, "none") == 0)
+ break;
+ if ((cp = strrchr(sdup, ',')) == NULL)
+ cp = sdup; /* last */
+ else
+ *cp++ = '\0';
+
+ if (first) {
+ /* First argument and configuration is active */
+ if (parse_ssh_uri(cp, &user, &host, &port) == -1 ||
+ parse_user_host_port(cp, &user, &host, &port) != 0)
+ goto out;
+ } else {
+ /* Subsequent argument or inactive configuration */
+ if (parse_ssh_uri(cp, NULL, NULL, NULL) == -1 ||
+ parse_user_host_port(cp, NULL, NULL, NULL) != 0)
+ goto out;
+ }
+ first = 0; /* only check syntax for subsequent hosts */
+ } while (cp != sdup);
+ /* success */
+ if (active) {
+ 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';
+ }
+ }
+ }
+ ret = 0;
+ out:
+ free(orig);
+ free(user);
+ free(host);
+ return ret;
+}
+
+int
+parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
+{
+ char *path;
+ int r;
+
+ r = parse_uri("ssh", uri, userp, hostp, portp, &path);
+ if (r == 0 && path != NULL)
+ r = -1; /* path not allowed */
+ return r;
+}
+
/* XXX the following is a near-vebatim copy from servconf.c; refactor */
static const char *
fmt_multistate_int(int val, const struct multistate *m)
@@ -2106,9 +2567,10 @@ fmt_intarg(OpCodes code, int val)
case oAddressFamily:
return fmt_multistate_int(val, multistate_addressfamily);
case oVerifyHostKeyDNS:
- case oStrictHostKeyChecking:
case oUpdateHostkeys:
return fmt_multistate_int(val, multistate_yesnoask);
+ case oStrictHostKeyChecking:
+ return fmt_multistate_int(val, multistate_strict_hostkey);
case oControlMaster:
return fmt_multistate_int(val, multistate_controlmaster);
case oTunnel:
@@ -2117,19 +2579,10 @@ fmt_intarg(OpCodes code, int val)
return fmt_multistate_int(val, multistate_requesttty);
case oCanonicalizeHostname:
return fmt_multistate_int(val, multistate_canonicalizehostname);
+ case oAddKeysToAgent:
+ return fmt_multistate_int(val, multistate_yesnoaskconfirm);
case oFingerprintHash:
return ssh_digest_alg_name(val);
- case oProtocol:
- switch (val) {
- case SSH_PROTO_1:
- return "1";
- case SSH_PROTO_2:
- return "2";
- case (SSH_PROTO_1|SSH_PROTO_2):
- return "2,1";
- default:
- return "UNKNOWN";
- }
default:
switch (val) {
case 0:
@@ -2202,10 +2655,10 @@ dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
/* oDynamicForward */
for (i = 0; i < count; i++) {
fwd = &fwds[i];
- if (code == oDynamicForward &&
+ if (code == oDynamicForward && fwd->connect_host != NULL &&
strcmp(fwd->connect_host, "socks") != 0)
continue;
- if (code == oLocalForward &&
+ if (code == oLocalForward && fwd->connect_host != NULL &&
strcmp(fwd->connect_host, "socks") == 0)
continue;
printf("%s", lookup_opcode_name(code));
@@ -2234,15 +2687,28 @@ dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
void
dump_client_config(Options *o, const char *host)
{
- int i;
- char vbuf[5];
+ int i, r;
+ char buf[8], *all_key;
+
+ /*
+ * 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.
+ */
+ all_key = sshkey_alg_list(0, 0, 1, ',');
+ if ((r = kex_assemble_names(&o->hostkeyalgorithms, kex_default_pk_alg(),
+ all_key)) != 0)
+ fatal("%s: expand HostKeyAlgorithms: %s", __func__, ssh_err(r));
+ free(all_key);
/* Most interesting options first: user, host, port */
dump_cfg_string(oUser, o->user);
- dump_cfg_string(oHostName, host);
+ dump_cfg_string(oHostname, host);
dump_cfg_int(oPort, o->port);
/* Flag options */
+ dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent);
dump_cfg_fmtint(oAddressFamily, o->address_family);
dump_cfg_fmtint(oBatchMode, o->batch_mode);
dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
@@ -2252,9 +2718,9 @@ dump_client_config(Options *o, const char *host)
dump_cfg_fmtint(oCompression, o->compression);
dump_cfg_fmtint(oControlMaster, o->control_master);
dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
+ dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
- dump_cfg_fmtint(oForwardAgent, o->forward_agent);
dump_cfg_fmtint(oForwardX11, o->forward_x11);
dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
@@ -2269,24 +2735,19 @@ dump_client_config(Options *o, const char *host)
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(oProtocol, o->protocol);
dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
dump_cfg_fmtint(oRequestTTY, o->request_tty);
- dump_cfg_fmtint(oRhostsRSAAuthentication, o->rhosts_rsa_authentication);
- dump_cfg_fmtint(oRSAAuthentication, o->rsa_authentication);
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(oUsePrivilegedPort, o->use_privileged_port);
dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
/* Integer options */
dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
- dump_cfg_int(oCompressionLevel, o->compression_level);
dump_cfg_int(oConnectionAttempts, o->connection_attempts);
dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
@@ -2295,19 +2756,27 @@ dump_client_config(Options *o, const char *host)
/* String options */
dump_cfg_string(oBindAddress, o->bind_address);
- dump_cfg_string(oCiphers, o->ciphers ? o->ciphers : KEX_CLIENT_ENCRYPT);
+ dump_cfg_string(oBindInterface, o->bind_interface);
+ dump_cfg_string(oCiphers, o->ciphers);
dump_cfg_string(oControlPath, o->control_path);
- dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms ? o->hostkeyalgorithms : KEX_DEFAULT_PK_ALG);
+ dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
dump_cfg_string(oHostKeyAlias, o->host_key_alias);
dump_cfg_string(oHostbasedKeyTypes, o->hostbased_key_types);
+ dump_cfg_string(oIdentityAgent, o->identity_agent);
+ dump_cfg_string(oIgnoreUnknown, o->ignored_unknown);
dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
- dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX);
+ dump_cfg_string(oKexAlgorithms, o->kex_algorithms);
+ dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms);
dump_cfg_string(oLocalCommand, o->local_command);
+ dump_cfg_string(oRemoteCommand, o->remote_command);
dump_cfg_string(oLogLevel, log_level_name(o->log_level));
- dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
+ dump_cfg_string(oMacs, o->macs);
+#ifdef ENABLE_PKCS11
dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
+#endif
+ dump_cfg_string(oSecurityKeyProvider, o->sk_provider);
dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
- dump_cfg_string(oProxyCommand, o->proxy_command);
+ dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types);
dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
dump_cfg_string(oXAuthLocation, o->xauth_location);
@@ -2319,12 +2788,20 @@ dump_client_config(Options *o, const char *host)
/* 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);
+ dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files);
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);
+ dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
/* Special cases */
+ /* 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);
+
/* oConnectTimeout */
if (o->connection_timeout == -1)
printf("connecttimeout none\n");
@@ -2353,10 +2830,6 @@ dump_client_config(Options *o, const char *host)
printf("\n");
}
- /* oCipher */
- if (o->cipher != SSH_CIPHER_NOT_SET)
- printf("Cipher %s\n", cipher_name(o->cipher));
-
/* oControlPersist */
if (o->control_persist == 0 || o->control_persist_timeout == 0)
dump_cfg_fmtint(oControlPersist, o->control_persist);
@@ -2367,8 +2840,8 @@ dump_client_config(Options *o, const char *host)
if (o->escape_char == SSH_ESCAPECHAR_NONE)
printf("escapechar none\n");
else {
- vis(vbuf, o->escape_char, VIS_WHITE, 0);
- printf("escapechar %s\n", vbuf);
+ vis(buf, o->escape_char, VIS_WHITE, 0);
+ printf("escapechar %s\n", buf);
}
/* oIPQoS */
@@ -2376,10 +2849,39 @@ dump_client_config(Options *o, const char *host)
printf("%s\n", iptos2str(o->ip_qos_bulk));
/* oRekeyLimit */
- printf("rekeylimit %lld %d\n",
- (long long)o->rekey_limit, o->rekey_interval);
+ printf("rekeylimit %llu %d\n",
+ (unsigned long long)o->rekey_limit, o->rekey_interval);
/* oStreamLocalBindMask */
printf("streamlocalbindmask 0%o\n",
o->fwd_opts.streamlocal_bind_mask);
+
+ /* oLogFacility */
+ printf("syslogfacility %s\n", log_facility_name(o->log_facility));
+
+ /* 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);
+ }
}