diff options
Diffstat (limited to 'src/config.c')
-rw-r--r-- | src/config.c | 304 |
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; } |