aboutsummaryrefslogtreecommitdiff
path: root/src/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/config.c')
-rw-r--r--src/config.c304
1 files changed, 205 insertions, 99 deletions
diff --git a/src/config.c b/src/config.c
index 599d6f80..7135c3b1 100644
--- a/src/config.c
+++ b/src/config.c
@@ -48,7 +48,9 @@
#include "libssh/misc.h"
#include "libssh/options.h"
+#ifndef MAX_LINE_SIZE
#define MAX_LINE_SIZE 1024
+#endif
struct ssh_config_keyword_table_s {
const char *name;
@@ -66,7 +68,6 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
{ "macs", SOC_MACS },
{ "compression", SOC_COMPRESSION },
{ "connecttimeout", SOC_TIMEOUT },
- { "protocol", SOC_PROTOCOL },
{ "stricthostkeychecking", SOC_STRICTHOSTKEYCHECK },
{ "userknownhostsfile", SOC_KNOWNHOSTS },
{ "proxycommand", SOC_PROXYCOMMAND },
@@ -79,7 +80,6 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
{ "loglevel", SOC_LOGLEVEL},
{ "hostkeyalgorithms", SOC_HOSTKEYALGORITHMS},
{ "kexalgorithms", SOC_KEXALGORITHMS},
- { "mac", SOC_UNSUPPORTED}, /* SSHv1 */
{ "gssapiauthentication", SOC_GSSAPIAUTHENTICATION},
{ "kbdinteractiveauthentication", SOC_KBDINTERACTIVEAUTHENTICATION},
{ "passwordauthentication", SOC_PASSWORDAUTHENTICATION},
@@ -92,24 +92,19 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
{ "canonicalizehostname", SOC_UNSUPPORTED},
{ "canonicalizemaxdots", SOC_UNSUPPORTED},
{ "canonicalizepermittedcnames", SOC_UNSUPPORTED},
- { "certificatefile", SOC_UNSUPPORTED},
- { "challengeresponseauthentication", SOC_UNSUPPORTED},
+ { "certificatefile", SOC_CERTIFICATE},
+ { "kbdinteractiveauthentication", SOC_UNSUPPORTED},
{ "checkhostip", SOC_UNSUPPORTED},
- { "cipher", SOC_UNSUPPORTED}, /* SSHv1 */
- { "compressionlevel", SOC_UNSUPPORTED}, /* SSHv1 */
{ "connectionattempts", SOC_UNSUPPORTED},
{ "enablesshkeysign", SOC_UNSUPPORTED},
{ "fingerprinthash", SOC_UNSUPPORTED},
{ "forwardagent", SOC_UNSUPPORTED},
- { "gssapikeyexchange", SOC_UNSUPPORTED},
- { "gssapirenewalforcesrekey", SOC_UNSUPPORTED},
- { "gssapitrustdns", SOC_UNSUPPORTED},
{ "hashknownhosts", SOC_UNSUPPORTED},
{ "hostbasedauthentication", SOC_UNSUPPORTED},
- { "hostbasedkeytypes", SOC_UNSUPPORTED},
+ { "hostbasedacceptedalgorithms", SOC_UNSUPPORTED},
{ "hostkeyalias", SOC_UNSUPPORTED},
- { "identitiesonly", SOC_UNSUPPORTED},
- { "identityagent", SOC_UNSUPPORTED},
+ { "identitiesonly", SOC_IDENTITIESONLY},
+ { "identityagent", SOC_IDENTITYAGENT},
{ "ipqos", SOC_UNSUPPORTED},
{ "kbdinteractivedevices", SOC_UNSUPPORTED},
{ "nohostauthenticationforlocalhost", SOC_UNSUPPORTED},
@@ -118,12 +113,10 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
{ "preferredauthentications", SOC_UNSUPPORTED},
{ "proxyjump", SOC_PROXYJUMP},
{ "proxyusefdpass", SOC_UNSUPPORTED},
- { "pubkeyacceptedtypes", SOC_PUBKEYACCEPTEDTYPES},
+ { "pubkeyacceptedalgorithms", SOC_PUBKEYACCEPTEDKEYTYPES},
{ "rekeylimit", SOC_REKEYLIMIT},
{ "remotecommand", SOC_UNSUPPORTED},
{ "revokedhostkeys", SOC_UNSUPPORTED},
- { "rhostsrsaauthentication", SOC_UNSUPPORTED},
- { "rsaauthentication", SOC_UNSUPPORTED}, /* SSHv1 */
{ "serveralivecountmax", SOC_UNSUPPORTED},
{ "serveraliveinterval", SOC_UNSUPPORTED},
{ "streamlocalbindmask", SOC_UNSUPPORTED},
@@ -131,13 +124,12 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
{ "syslogfacility", SOC_UNSUPPORTED},
{ "tcpkeepalive", SOC_UNSUPPORTED},
{ "updatehostkeys", SOC_UNSUPPORTED},
- { "useprivilegedport", SOC_UNSUPPORTED},
{ "verifyhostkeydns", SOC_UNSUPPORTED},
{ "visualhostkey", SOC_UNSUPPORTED},
{ "clearallforwardings", SOC_NA},
- { "controlmaster", SOC_NA},
+ { "controlmaster", SOC_CONTROLMASTER},
{ "controlpersist", SOC_NA},
- { "controlpath", SOC_NA},
+ { "controlpath", SOC_CONTROLPATH},
{ "dynamicforward", SOC_NA},
{ "escapechar", SOC_NA},
{ "exitonforwardfailure", SOC_NA},
@@ -155,7 +147,7 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
{ "tunnel", SOC_NA},
{ "tunneldevice", SOC_NA},
{ "xauthlocation", SOC_NA},
- { "pubkeyacceptedkeytypes", SOC_PUBKEYACCEPTEDTYPES},
+ { "pubkeyacceptedkeytypes", SOC_PUBKEYACCEPTEDKEYTYPES},
{ NULL, SOC_UNKNOWN }
};
@@ -189,7 +181,7 @@ static struct ssh_config_match_keyword_table_s ssh_config_match_keyword_table[]
};
static int ssh_config_parse_line(ssh_session session, const char *line,
- unsigned int count, int *parsing);
+ unsigned int count, int *parsing, unsigned int depth, bool global);
static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
int i;
@@ -203,16 +195,26 @@ static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
return SOC_UNKNOWN;
}
+#define LIBSSH_CONF_MAX_DEPTH 16
static void
local_parse_file(ssh_session session,
const char *filename,
- int *parsing)
+ int *parsing,
+ unsigned int depth,
+ bool global)
{
FILE *f;
char line[MAX_LINE_SIZE] = {0};
unsigned int count = 0;
int rv;
+ if (depth > LIBSSH_CONF_MAX_DEPTH) {
+ ssh_set_error(session, SSH_FATAL,
+ "ERROR - Too many levels of configuration includes "
+ "when processing file '%s'", filename);
+ return;
+ }
+
f = fopen(filename, "r");
if (f == NULL) {
SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
@@ -223,7 +225,7 @@ local_parse_file(ssh_session session,
SSH_LOG(SSH_LOG_PACKET, "Reading additional configuration data from %s", filename);
while (fgets(line, sizeof(line), f)) {
count++;
- rv = ssh_config_parse_line(session, line, count, parsing);
+ rv = ssh_config_parse_line(session, line, count, parsing, depth, global);
if (rv < 0) {
fclose(f);
return;
@@ -237,7 +239,9 @@ local_parse_file(ssh_session session,
#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER)
static void local_parse_glob(ssh_session session,
const char *fileglob,
- int *parsing)
+ int *parsing,
+ unsigned int depth,
+ bool global)
{
glob_t globbuf = {
.gl_flags = 0,
@@ -257,7 +261,7 @@ static void local_parse_glob(ssh_session session,
}
for (i = 0; i < globbuf.gl_pathc; i++) {
- local_parse_file(session, globbuf.gl_pathv[i], parsing);
+ local_parse_file(session, globbuf.gl_pathv[i], parsing, depth, global);
}
globfree(&globbuf);
@@ -315,6 +319,7 @@ ssh_exec_shell(char *cmd)
char *shell = NULL;
pid_t pid;
int status, devnull, rc;
+ char err_msg[SSH_ERRNO_MSG_MAX] = {0};
shell = getenv("SHELL");
if (shell == NULL || shell[0] == '\0') {
@@ -330,7 +335,8 @@ ssh_exec_shell(char *cmd)
/* Need this to redirect subprocess stdin/out */
devnull = open("/dev/null", O_RDWR);
if (devnull == -1) {
- SSH_LOG(SSH_LOG_WARN, "Failed to open(/dev/null): %s", strerror(errno));
+ SSH_LOG(SSH_LOG_WARN, "Failed to open(/dev/null): %s",
+ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
return -1;
}
@@ -342,13 +348,15 @@ ssh_exec_shell(char *cmd)
/* Redirect child stdin and stdout. Leave stderr */
rc = dup2(devnull, STDIN_FILENO);
if (rc == -1) {
- SSH_LOG(SSH_LOG_WARN, "dup2: %s", strerror(errno));
+ SSH_LOG(SSH_LOG_WARN, "dup2: %s",
+ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
exit(1);
}
rc = dup2(devnull, STDOUT_FILENO);
if (rc == -1) {
- SSH_LOG(SSH_LOG_WARN, "dup2: %s", strerror(errno));
- exit(1);
+ SSH_LOG(SSH_LOG_WARN, "dup2: %s",
+ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
+ exit(1);
}
if (devnull > STDERR_FILENO) {
close(devnull);
@@ -362,7 +370,7 @@ ssh_exec_shell(char *cmd)
rc = execv(argv[0], argv);
if (rc == -1) {
SSH_LOG(SSH_LOG_WARN, "Failed to execute command '%s': %s", cmd,
- strerror(errno));
+ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
/* Die with signal to make this error apparent to parent. */
signal(SIGTERM, SIG_DFL);
kill(getpid(), SIGTERM);
@@ -373,19 +381,21 @@ ssh_exec_shell(char *cmd)
/* Parent */
close(devnull);
if (pid == -1) { /* Error */
- SSH_LOG(SSH_LOG_WARN, "Failed to fork child: %s", strerror(errno));
+ SSH_LOG(SSH_LOG_WARN, "Failed to fork child: %s",
+ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
return -1;
}
while (waitpid(pid, &status, 0) == -1) {
if (errno != EINTR) {
- SSH_LOG(SSH_LOG_WARN, "waitpid failed: %s", strerror(errno));
+ SSH_LOG(SSH_LOG_WARN, "waitpid failed: %s",
+ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
return -1;
}
}
if (!WIFEXITED(status)) {
- SSH_LOG(SSH_LOG_WARN, "Command %s exitted abnormally", cmd);
+ SSH_LOG(SSH_LOG_WARN, "Command %s exited abnormally", cmd);
return -1;
}
SSH_LOG(SSH_LOG_TRACE, "Command '%s' returned %d", cmd, WEXITSTATUS(status));
@@ -454,7 +464,7 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
}
if (parse_entry) {
/* We actually care only about the first item */
- rv = ssh_config_parse_uri(cp, &username, &hostname, &port);
+ rv = ssh_config_parse_uri(cp, &username, &hostname, &port, false);
/* The rest of the list needs to be passed on */
if (endp != NULL) {
next = strdup(endp + 1);
@@ -465,7 +475,7 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
}
} else {
/* The rest is just sanity-checked to avoid failures later */
- rv = ssh_config_parse_uri(cp, NULL, NULL, NULL);
+ rv = ssh_config_parse_uri(cp, NULL, NULL, NULL, false);
}
if (rv != SSH_OK) {
goto out;
@@ -481,7 +491,7 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
if (hostname != NULL && do_parsing) {
char com[512] = {0};
- rv = snprintf(com, sizeof(com), "ssh%s%s%s%s%s%s -W [%%h]:%%p %s",
+ rv = snprintf(com, sizeof(com), "ssh%s%s%s%s%s%s -W '[%%h]:%%p' %s",
username ? " -l " : "",
username ? username : "",
port ? " -p " : "",
@@ -490,7 +500,7 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
next ? next : "",
hostname);
if (rv < 0 || rv >= (int)sizeof(com)) {
- SSH_LOG(SSH_LOG_WARN, "Too long ProxyJump configuration line");
+ SSH_LOG(SSH_LOG_TRACE, "Too long ProxyJump configuration line");
rv = SSH_ERROR;
goto out;
}
@@ -507,11 +517,68 @@ out:
return rv;
}
+static char *
+ssh_config_make_absolute(ssh_session session,
+ const char *path,
+ bool global)
+{
+ size_t outlen = 0;
+ char *out = NULL;
+ int rv;
+
+ /* Looks like absolute path */
+ if (path[0] == '/') {
+ return strdup(path);
+ }
+
+ /* relative path */
+ if (global) {
+ /* Parsing global config */
+ outlen = strlen(path) + strlen("/etc/ssh/") + 1;
+ out = malloc(outlen);
+ if (out == NULL) {
+ ssh_set_error_oom(session);
+ return NULL;
+ }
+ rv = snprintf(out, outlen, "/etc/ssh/%s", path);
+ if (rv < 1) {
+ free(out);
+ return NULL;
+ }
+ return out;
+ }
+
+ /* paths starting with tilde are already absolute */
+ if (path[0] == '~') {
+ return ssh_path_expand_tilde(path);
+ }
+
+ /* Parsing user config relative to home directory (generally ~/.ssh) */
+ if (session->opts.sshdir == NULL) {
+ ssh_set_error_invalid(session);
+ return NULL;
+ }
+ outlen = strlen(path) + strlen(session->opts.sshdir) + 1 + 1;
+ out = malloc(outlen);
+ if (out == NULL) {
+ ssh_set_error_oom(session);
+ return NULL;
+ }
+ rv = snprintf(out, outlen, "%s/%s", session->opts.sshdir, path);
+ if (rv < 1) {
+ free(out);
+ return NULL;
+ }
+ return out;
+}
+
static int
ssh_config_parse_line(ssh_session session,
const char *line,
unsigned int count,
- int *parsing)
+ int *parsing,
+ unsigned int depth,
+ bool global)
{
enum ssh_config_opcode_e opcode;
const char *p = NULL, *p2 = NULL;
@@ -556,7 +623,9 @@ ssh_config_parse_line(ssh_session session,
opcode != SOC_MATCH &&
opcode != SOC_INCLUDE &&
opcode != SOC_IDENTITY &&
- opcode > SOC_UNSUPPORTED) { /* Ignore all unknown types here */
+ opcode != SOC_CERTIFICATE &&
+ opcode > SOC_UNSUPPORTED &&
+ opcode < SOC_MAX) { /* Ignore all unknown types here */
/* Skip all the options that were already applied */
if (seen[opcode] != 0) {
SAFE_FREE(x);
@@ -570,11 +639,19 @@ ssh_config_parse_line(ssh_session session,
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
+ char *path = ssh_config_make_absolute(session, p, global);
+ if (path == NULL) {
+ SSH_LOG(SSH_LOG_WARN, "line %d: Failed to allocate memory "
+ "for the include path expansion", count);
+ SAFE_FREE(x);
+ return -1;
+ }
#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER)
- local_parse_glob(session, p, parsing);
+ local_parse_glob(session, path, parsing, depth + 1, global);
#else
- local_parse_file(session, p, parsing);
+ local_parse_file(session, path, parsing, depth + 1, global);
#endif /* HAVE_GLOB */
+ free(path);
}
break;
@@ -592,7 +669,7 @@ ssh_config_parse_line(ssh_session session,
break;
}
args++;
- SSH_LOG(SSH_LOG_TRACE, "line %d: Processing Match keyword '%s'",
+ SSH_LOG(SSH_LOG_DEBUG, "line %d: Processing Match keyword '%s'",
count, p);
/* If the option is prefixed with ! the result should be negated */
@@ -624,7 +701,7 @@ ssh_config_parse_line(ssh_session session,
case MATCH_FINAL:
case MATCH_CANONICAL:
- SSH_LOG(SSH_LOG_INFO,
+ SSH_LOG(SSH_LOG_DEBUG,
"line %d: Unsupported Match keyword '%s', skipping",
count,
p);
@@ -636,13 +713,13 @@ ssh_config_parse_line(ssh_session session,
/* Skip one argument (including in quotes) */
p = ssh_config_get_token(&s);
if (p == NULL || p[0] == '\0') {
- SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword "
+ SSH_LOG(SSH_LOG_TRACE, "line %d: Match keyword "
"'%s' requires argument", count, p2);
SAFE_FREE(x);
return -1;
}
if (result != 1) {
- SSH_LOG(SSH_LOG_INFO, "line %d: Skipped match exec "
+ SSH_LOG(SSH_LOG_DEBUG, "line %d: Skipped match exec "
"'%s' as previous conditions already failed.",
count, p2);
continue;
@@ -663,7 +740,7 @@ ssh_config_parse_line(ssh_session session,
}
localuser = ssh_get_local_username();
if (localuser == NULL) {
- SSH_LOG(SSH_LOG_WARN, "line %d: Can not get local username "
+ SSH_LOG(SSH_LOG_TRACE, "line %d: Can not get local username "
"for conditional matching.", count);
SAFE_FREE(x);
return -1;
@@ -677,13 +754,13 @@ ssh_config_parse_line(ssh_session session,
/* Skip one argument */
p = ssh_config_get_str_tok(&s, NULL);
if (p == NULL || p[0] == '\0') {
- SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword "
+ SSH_LOG(SSH_LOG_TRACE, "line %d: Match keyword "
"'%s' requires argument", count, p2);
SAFE_FREE(x);
return -1;
}
args++;
- SSH_LOG(SSH_LOG_INFO,
+ SSH_LOG(SSH_LOG_TRACE,
"line %d: Unsupported Match keyword '%s', ignoring",
count,
p2);
@@ -813,34 +890,6 @@ ssh_config_parse_line(ssh_session session,
}
}
break;
- case SOC_PROTOCOL:
- p = ssh_config_get_str_tok(&s, NULL);
- if (p && *parsing) {
- char *a, *b;
- b = strdup(p);
- if (b == NULL) {
- SAFE_FREE(x);
- ssh_set_error_oom(session);
- return -1;
- }
- i = 0;
- ssh_options_set(session, SSH_OPTIONS_SSH2, &i);
-
- for (a = strtok(b, ","); a; a = strtok(NULL, ",")) {
- switch (atoi(a)) {
- case 1:
- break;
- case 2:
- i = 1;
- ssh_options_set(session, SSH_OPTIONS_SSH2, &i);
- break;
- default:
- break;
- }
- }
- SAFE_FREE(b);
- }
- break;
case SOC_TIMEOUT:
l = ssh_config_get_long(&s, -1);
if (l >= 0 && *parsing) {
@@ -918,10 +967,10 @@ ssh_config_parse_line(ssh_session session,
if (strcasecmp(p, "quiet") == 0) {
value = SSH_LOG_NONE;
} else if (strcasecmp(p, "fatal") == 0 ||
- strcasecmp(p, "error")== 0 ||
- strcasecmp(p, "info") == 0) {
+ strcasecmp(p, "error")== 0) {
value = SSH_LOG_WARN;
- } else if (strcasecmp(p, "verbose") == 0) {
+ } else if (strcasecmp(p, "verbose") == 0 ||
+ strcasecmp(p, "info") == 0) {
value = SSH_LOG_INFO;
} else if (strcasecmp(p, "DEBUG") == 0 ||
strcasecmp(p, "DEBUG1") == 0) {
@@ -941,7 +990,7 @@ ssh_config_parse_line(ssh_session session,
ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, p);
}
break;
- case SOC_PUBKEYACCEPTEDTYPES:
+ case SOC_PUBKEYACCEPTEDKEYTYPES:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES, p);
@@ -959,20 +1008,20 @@ ssh_config_parse_line(ssh_session session,
if (p == NULL) {
break;
} else if (strcmp(p, "default") == 0) {
- /* Default rekey limits enforced automaticaly */
+ /* Default rekey limits enforced automatically */
ll = 0;
} else {
char *endp = NULL;
ll = strtoll(p, &endp, 10);
if (p == endp || ll < 0) {
/* No number or negative */
- SSH_LOG(SSH_LOG_WARN, "Invalid argument to rekey limit");
+ SSH_LOG(SSH_LOG_TRACE, "Invalid argument to rekey limit");
break;
}
switch (*endp) {
case 'G':
if (ll > LLONG_MAX / 1024) {
- SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
+ SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit");
ll = -1;
break;
}
@@ -980,7 +1029,7 @@ ssh_config_parse_line(ssh_session session,
FALL_THROUGH;
case 'M':
if (ll > LLONG_MAX / 1024) {
- SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
+ SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit");
ll = -1;
break;
}
@@ -988,7 +1037,7 @@ ssh_config_parse_line(ssh_session session,
FALL_THROUGH;
case 'K':
if (ll > LLONG_MAX / 1024) {
- SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
+ SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit");
ll = -1;
break;
}
@@ -1004,7 +1053,7 @@ ssh_config_parse_line(ssh_session session,
break;
}
if (*endp != ' ' && *endp != '\0') {
- SSH_LOG(SSH_LOG_WARN,
+ SSH_LOG(SSH_LOG_TRACE,
"Invalid trailing characters after the rekey limit: %s",
endp);
break;
@@ -1025,14 +1074,14 @@ ssh_config_parse_line(ssh_session session,
ll = strtoll(p, &endp, 10);
if (p == endp || ll < 0) {
/* No number or negative */
- SSH_LOG(SSH_LOG_WARN, "Invalid argument to rekey limit");
+ SSH_LOG(SSH_LOG_TRACE, "Invalid argument to rekey limit");
break;
}
switch (*endp) {
case 'w':
case 'W':
if (ll > LLONG_MAX / 7) {
- SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
+ SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit");
ll = -1;
break;
}
@@ -1041,7 +1090,7 @@ ssh_config_parse_line(ssh_session session,
case 'd':
case 'D':
if (ll > LLONG_MAX / 24) {
- SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
+ SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit");
ll = -1;
break;
}
@@ -1050,7 +1099,7 @@ ssh_config_parse_line(ssh_session session,
case 'h':
case 'H':
if (ll > LLONG_MAX / 60) {
- SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
+ SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit");
ll = -1;
break;
}
@@ -1059,7 +1108,7 @@ ssh_config_parse_line(ssh_session session,
case 'm':
case 'M':
if (ll > LLONG_MAX / 60) {
- SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
+ SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit");
ll = -1;
break;
}
@@ -1078,7 +1127,7 @@ ssh_config_parse_line(ssh_session session,
break;
}
if (*endp != '\0') {
- SSH_LOG(SSH_LOG_WARN, "Invalid trailing characters after the"
+ SSH_LOG(SSH_LOG_TRACE, "Invalid trailing characters after the"
" rekey limit: %s", endp);
break;
}
@@ -1114,17 +1163,68 @@ ssh_config_parse_line(ssh_session session,
}
break;
case SOC_NA:
- SSH_LOG(SSH_LOG_INFO, "Unapplicable option: %s, line: %d",
+ SSH_LOG(SSH_LOG_TRACE, "Unapplicable option: %s, line: %d",
keyword, count);
break;
case SOC_UNSUPPORTED:
- SSH_LOG(SSH_LOG_INFO, "Unsupported option: %s, line: %d",
+ SSH_LOG(SSH_LOG_RARE, "Unsupported option: %s, line: %d",
keyword, count);
break;
case SOC_UNKNOWN:
- SSH_LOG(SSH_LOG_INFO, "Unknown option: %s, line: %d",
+ SSH_LOG(SSH_LOG_TRACE, "Unknown option: %s, line: %d",
keyword, count);
break;
+ case SOC_IDENTITYAGENT:
+ p = ssh_config_get_str_tok(&s, NULL);
+ if (p && *parsing) {
+ ssh_options_set(session, SSH_OPTIONS_IDENTITY_AGENT, p);
+ }
+ break;
+ case SOC_IDENTITIESONLY:
+ i = ssh_config_get_yesno(&s, -1);
+ if (i >= 0 && *parsing) {
+ bool b = i;
+ ssh_options_set(session, SSH_OPTIONS_IDENTITIES_ONLY, &b);
+ }
+ break;
+ case SOC_CONTROLMASTER:
+ p = ssh_config_get_str_tok(&s, NULL);
+ if (p && *parsing) {
+ int value = -1;
+
+ if (strcasecmp(p, "auto") == 0) {
+ value = SSH_CONTROL_MASTER_AUTO;
+ } else if (strcasecmp(p, "yes") == 0) {
+ value = SSH_CONTROL_MASTER_YES;
+ } else if (strcasecmp(p, "no") == 0) {
+ value = SSH_CONTROL_MASTER_NO;
+ } else if (strcasecmp(p, "autoask") == 0) {
+ value = SSH_CONTROL_MASTER_AUTOASK;
+ } else if (strcasecmp(p, "ask") == 0) {
+ value = SSH_CONTROL_MASTER_ASK;
+ }
+
+ if (value != -1) {
+ ssh_options_set(session, SSH_OPTIONS_CONTROL_MASTER, &value);
+ }
+ }
+ break;
+ case SOC_CONTROLPATH:
+ p = ssh_config_get_str_tok(&s, NULL);
+ if (p == NULL) {
+ SAFE_FREE(x);
+ return -1;
+ }
+ if (*parsing) {
+ ssh_options_set(session, SSH_OPTIONS_CONTROL_PATH, p);
+ }
+ break;
+ case SOC_CERTIFICATE:
+ p = ssh_config_get_str_tok(&s, NULL);
+ if (p && *parsing) {
+ ssh_options_set(session, SSH_OPTIONS_CERTIFICATE, p);
+ }
+ break;
default:
ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d",
opcode);
@@ -1150,18 +1250,24 @@ int ssh_config_parse_file(ssh_session session, const char *filename)
unsigned int count = 0;
FILE *f;
int parsing, rv;
+ bool global = 0;
f = fopen(filename, "r");
if (f == NULL) {
return 0;
}
+ rv = strcmp(filename, GLOBAL_CLIENT_CONFIG);
+ if (rv == 0) {
+ global = true;
+ }
+
SSH_LOG(SSH_LOG_PACKET, "Reading configuration data from %s", filename);
parsing = 1;
while (fgets(line, sizeof(line), f)) {
count++;
- rv = ssh_config_parse_line(session, line, count, &parsing);
+ rv = ssh_config_parse_line(session, line, count, &parsing, 0, global);
if (rv < 0) {
fclose(f);
return -1;
@@ -1196,24 +1302,24 @@ int ssh_config_parse_string(ssh_session session, const char *input)
line_start = c;
c = strchr(line_start, '\n');
if (c == NULL) {
- /* if there is no newline in the end of the string */
+ /* if there is no newline at the end of the string */
c = strchr(line_start, '\0');
}
if (c == NULL) {
/* should not happen, would mean a string without trailing '\0' */
- SSH_LOG(SSH_LOG_WARN, "No trailing '\\0' in config string");
+ SSH_LOG(SSH_LOG_TRACE, "No trailing '\\0' in config string");
return SSH_ERROR;
}
line_len = c - line_start;
if (line_len > MAX_LINE_SIZE - 1) {
- SSH_LOG(SSH_LOG_WARN, "Line %u too long: %u characters",
+ SSH_LOG(SSH_LOG_TRACE, "Line %u too long: %u characters",
line_num, line_len);
return SSH_ERROR;
}
memcpy(line, line_start, line_len);
line[line_len] = '\0';
SSH_LOG(SSH_LOG_DEBUG, "Line %u: %s", line_num, line);
- rv = ssh_config_parse_line(session, line, line_num, &parsing);
+ rv = ssh_config_parse_line(session, line, line_num, &parsing, 0, false);
if (rv < 0) {
return SSH_ERROR;
}