Blame src/config.c

Packit Service 31306d
/*
Packit Service 31306d
 * config.c - parse the ssh config file
Packit Service 31306d
 *
Packit Service 31306d
 * This file is part of the SSH Library
Packit Service 31306d
 *
Packit Service 31306d
 * Copyright (c) 2009-2013    by Andreas Schneider <asn@cryptomilk.org>
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is free software; you can redistribute it and/or modify
Packit Service 31306d
 * it under the terms of the GNU Lesser General Public License as published by
Packit Service 31306d
 * the Free Software Foundation; either version 2.1 of the License, or (at your
Packit Service 31306d
 * option) any later version.
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is distributed in the hope that it will be useful, but
Packit Service 31306d
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit Service 31306d
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
Packit Service 31306d
 * License for more details.
Packit Service 31306d
 *
Packit Service 31306d
 * You should have received a copy of the GNU Lesser General Public License
Packit Service 31306d
 * along with the SSH Library; see the file COPYING.  If not, write to
Packit Service 31306d
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
Packit Service 31306d
 * MA 02111-1307, USA.
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
#include "config.h"
Packit Service 31306d
Packit Service 31306d
#include <ctype.h>
Packit Service 31306d
#include <stdio.h>
Packit Service 31306d
#include <string.h>
Packit Service 31306d
#include <stdlib.h>
Packit Service 31306d
#ifdef HAVE_GLOB_H
Packit Service 31306d
# include <glob.h>
Packit Service 31306d
#endif
Packit Service 31306d
#include <stdbool.h>
Packit Service 31306d
#include <limits.h>
Packit Service 31306d
Packit Service 31306d
#include "libssh/config_parser.h"
Packit Service 31306d
#include "libssh/config.h"
Packit Service 31306d
#include "libssh/priv.h"
Packit Service 31306d
#include "libssh/session.h"
Packit Service 31306d
#include "libssh/misc.h"
Packit Service 31306d
#include "libssh/options.h"
Packit Service 31306d
Packit Service 31306d
#define MAX_LINE_SIZE 1024
Packit Service 31306d
Packit Service 31306d
struct ssh_config_keyword_table_s {
Packit Service 31306d
  const char *name;
Packit Service 31306d
  enum ssh_config_opcode_e opcode;
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
Packit Service 31306d
  { "host", SOC_HOST },
Packit Service 31306d
  { "match", SOC_MATCH },
Packit Service 31306d
  { "hostname", SOC_HOSTNAME },
Packit Service 31306d
  { "port", SOC_PORT },
Packit Service 31306d
  { "user", SOC_USERNAME },
Packit Service 31306d
  { "identityfile", SOC_IDENTITY },
Packit Service 31306d
  { "ciphers", SOC_CIPHERS },
Packit Service 31306d
  { "macs", SOC_MACS },
Packit Service 31306d
  { "compression", SOC_COMPRESSION },
Packit Service 31306d
  { "connecttimeout", SOC_TIMEOUT },
Packit Service 31306d
  { "protocol", SOC_PROTOCOL },
Packit Service 31306d
  { "stricthostkeychecking", SOC_STRICTHOSTKEYCHECK },
Packit Service 31306d
  { "userknownhostsfile", SOC_KNOWNHOSTS },
Packit Service 31306d
  { "proxycommand", SOC_PROXYCOMMAND },
Packit Service 31306d
  { "gssapiserveridentity", SOC_GSSAPISERVERIDENTITY },
Packit Service 31306d
  { "gssapiclientidentity", SOC_GSSAPICLIENTIDENTITY },
Packit Service 31306d
  { "gssapidelegatecredentials", SOC_GSSAPIDELEGATECREDENTIALS },
Packit Service 31306d
  { "include", SOC_INCLUDE },
Packit Service 31306d
  { "bindaddress", SOC_BINDADDRESS},
Packit Service 31306d
  { "globalknownhostsfile", SOC_GLOBALKNOWNHOSTSFILE},
Packit Service 31306d
  { "loglevel", SOC_LOGLEVEL},
Packit Service 31306d
  { "hostkeyalgorithms", SOC_HOSTKEYALGORITHMS},
Packit Service 31306d
  { "kexalgorithms", SOC_KEXALGORITHMS},
Packit Service 31306d
  { "mac", SOC_UNSUPPORTED}, /* SSHv1 */
Packit Service 31306d
  { "gssapiauthentication", SOC_GSSAPIAUTHENTICATION},
Packit Service 31306d
  { "kbdinteractiveauthentication", SOC_KBDINTERACTIVEAUTHENTICATION},
Packit Service 31306d
  { "passwordauthentication", SOC_PASSWORDAUTHENTICATION},
Packit Service 31306d
  { "pubkeyauthentication", SOC_PUBKEYAUTHENTICATION},
Packit Service 31306d
  { "addkeystoagent", SOC_UNSUPPORTED},
Packit Service 31306d
  { "addressfamily", SOC_UNSUPPORTED},
Packit Service 31306d
  { "batchmode", SOC_UNSUPPORTED},
Packit Service 31306d
  { "canonicaldomains", SOC_UNSUPPORTED},
Packit Service 31306d
  { "canonicalizefallbacklocal", SOC_UNSUPPORTED},
Packit Service 31306d
  { "canonicalizehostname", SOC_UNSUPPORTED},
Packit Service 31306d
  { "canonicalizemaxdots", SOC_UNSUPPORTED},
Packit Service 31306d
  { "canonicalizepermittedcnames", SOC_UNSUPPORTED},
Packit Service 31306d
  { "certificatefile", SOC_UNSUPPORTED},
Packit Service 31306d
  { "challengeresponseauthentication", SOC_UNSUPPORTED},
Packit Service 31306d
  { "checkhostip", SOC_UNSUPPORTED},
Packit Service 31306d
  { "cipher", SOC_UNSUPPORTED}, /* SSHv1 */
Packit Service 31306d
  { "compressionlevel", SOC_UNSUPPORTED}, /* SSHv1 */
Packit Service 31306d
  { "connectionattempts", SOC_UNSUPPORTED},
Packit Service 31306d
  { "enablesshkeysign", SOC_UNSUPPORTED},
Packit Service 31306d
  { "fingerprinthash", SOC_UNSUPPORTED},
Packit Service 31306d
  { "forwardagent", SOC_UNSUPPORTED},
Packit Service 31306d
  { "gssapikeyexchange", SOC_UNSUPPORTED},
Packit Service 31306d
  { "gssapirenewalforcesrekey", SOC_UNSUPPORTED},
Packit Service 31306d
  { "gssapitrustdns", SOC_UNSUPPORTED},
Packit Service 31306d
  { "hashknownhosts", SOC_UNSUPPORTED},
Packit Service 31306d
  { "hostbasedauthentication", SOC_UNSUPPORTED},
Packit Service 31306d
  { "hostbasedkeytypes", SOC_UNSUPPORTED},
Packit Service 31306d
  { "hostkeyalias", SOC_UNSUPPORTED},
Packit Service 31306d
  { "identitiesonly", SOC_UNSUPPORTED},
Packit Service 31306d
  { "identityagent", SOC_UNSUPPORTED},
Packit Service 31306d
  { "ipqos", SOC_UNSUPPORTED},
Packit Service 31306d
  { "kbdinteractivedevices", SOC_UNSUPPORTED},
Packit Service 31306d
  { "nohostauthenticationforlocalhost", SOC_UNSUPPORTED},
Packit Service 31306d
  { "numberofpasswordprompts", SOC_UNSUPPORTED},
Packit Service 31306d
  { "pkcs11provider", SOC_UNSUPPORTED},
Packit Service 31306d
  { "preferredauthentications", SOC_UNSUPPORTED},
Packit Service 31306d
  { "proxyjump", SOC_PROXYJUMP},
Packit Service 31306d
  { "proxyusefdpass", SOC_UNSUPPORTED},
Packit Service 31306d
  { "pubkeyacceptedtypes", SOC_PUBKEYACCEPTEDTYPES},
Packit Service 31306d
  { "rekeylimit", SOC_REKEYLIMIT},
Packit Service 31306d
  { "remotecommand", SOC_UNSUPPORTED},
Packit Service 31306d
  { "revokedhostkeys", SOC_UNSUPPORTED},
Packit Service 31306d
  { "rhostsrsaauthentication", SOC_UNSUPPORTED},
Packit Service 31306d
  { "rsaauthentication", SOC_UNSUPPORTED}, /* SSHv1 */
Packit Service 31306d
  { "serveralivecountmax", SOC_UNSUPPORTED},
Packit Service 31306d
  { "serveraliveinterval", SOC_UNSUPPORTED},
Packit Service 31306d
  { "streamlocalbindmask", SOC_UNSUPPORTED},
Packit Service 31306d
  { "streamlocalbindunlink", SOC_UNSUPPORTED},
Packit Service 31306d
  { "syslogfacility", SOC_UNSUPPORTED},
Packit Service 31306d
  { "tcpkeepalive", SOC_UNSUPPORTED},
Packit Service 31306d
  { "updatehostkeys", SOC_UNSUPPORTED},
Packit Service 31306d
  { "useprivilegedport", SOC_UNSUPPORTED},
Packit Service 31306d
  { "verifyhostkeydns", SOC_UNSUPPORTED},
Packit Service 31306d
  { "visualhostkey", SOC_UNSUPPORTED},
Packit Service 31306d
  { "clearallforwardings", SOC_NA},
Packit Service 31306d
  { "controlmaster", SOC_NA},
Packit Service 31306d
  { "controlpersist", SOC_NA},
Packit Service 31306d
  { "controlpath", SOC_NA},
Packit Service 31306d
  { "dynamicforward", SOC_NA},
Packit Service 31306d
  { "escapechar", SOC_NA},
Packit Service 31306d
  { "exitonforwardfailure", SOC_NA},
Packit Service 31306d
  { "forwardx11", SOC_NA},
Packit Service 31306d
  { "forwardx11timeout", SOC_NA},
Packit Service 31306d
  { "forwardx11trusted", SOC_NA},
Packit Service 31306d
  { "gatewayports", SOC_NA},
Packit Service 31306d
  { "ignoreunknown", SOC_NA},
Packit Service 31306d
  { "localcommand", SOC_NA},
Packit Service 31306d
  { "localforward", SOC_NA},
Packit Service 31306d
  { "permitlocalcommand", SOC_NA},
Packit Service 31306d
  { "remoteforward", SOC_NA},
Packit Service 31306d
  { "requesttty", SOC_NA},
Packit Service 31306d
  { "sendenv", SOC_NA},
Packit Service 31306d
  { "tunnel", SOC_NA},
Packit Service 31306d
  { "tunneldevice", SOC_NA},
Packit Service 31306d
  { "xauthlocation", SOC_NA},
Packit Service 31306d
  { "pubkeyacceptedkeytypes", SOC_PUBKEYACCEPTEDTYPES},
Packit Service 31306d
  { NULL, SOC_UNKNOWN }
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
enum ssh_config_match_e {
Packit Service 31306d
    MATCH_UNKNOWN = -1,
Packit Service 31306d
    MATCH_ALL,
Packit Service 31306d
    MATCH_FINAL,
Packit Service 31306d
    MATCH_CANONICAL,
Packit Service 31306d
    MATCH_EXEC,
Packit Service 31306d
    MATCH_HOST,
Packit Service 31306d
    MATCH_ORIGINALHOST,
Packit Service 31306d
    MATCH_USER,
Packit Service 31306d
    MATCH_LOCALUSER
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
struct ssh_config_match_keyword_table_s {
Packit Service 31306d
    const char *name;
Packit Service 31306d
    enum ssh_config_match_e opcode;
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
static struct ssh_config_match_keyword_table_s ssh_config_match_keyword_table[] = {
Packit Service 31306d
    { "all", MATCH_ALL },
Packit Service 31306d
    { "canonical", MATCH_CANONICAL },
Packit Service 31306d
    { "final", MATCH_FINAL },
Packit Service 31306d
    { "exec", MATCH_EXEC },
Packit Service 31306d
    { "host", MATCH_HOST },
Packit Service 31306d
    { "originalhost", MATCH_ORIGINALHOST },
Packit Service 31306d
    { "user", MATCH_USER },
Packit Service 31306d
    { "localuser", MATCH_LOCALUSER },
Packit Service 31306d
    { NULL, MATCH_UNKNOWN },
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
static int ssh_config_parse_line(ssh_session session, const char *line,
Packit Service 31306d
    unsigned int count, int *parsing);
Packit Service 31306d
Packit Service 31306d
static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
Packit Service 31306d
  int i;
Packit Service 31306d
Packit Service 31306d
  for (i = 0; ssh_config_keyword_table[i].name != NULL; i++) {
Packit Service 31306d
    if (strcasecmp(keyword, ssh_config_keyword_table[i].name) == 0) {
Packit Service 31306d
      return ssh_config_keyword_table[i].opcode;
Packit Service 31306d
    }
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return SOC_UNKNOWN;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void
Packit Service 31306d
local_parse_file(ssh_session session,
Packit Service 31306d
                 const char *filename,
Packit Service 31306d
                 int *parsing)
Packit Service 31306d
{
Packit Service 31306d
    FILE *f;
Packit Service 31306d
    char line[MAX_LINE_SIZE] = {0};
Packit Service 31306d
    unsigned int count = 0;
Packit Service 31306d
    int rv;
Packit Service 31306d
Packit Service 31306d
    f = fopen(filename, "r");
Packit Service 31306d
    if (f == NULL) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
Packit Service 31306d
                filename);
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_PACKET, "Reading additional configuration data from %s", filename);
Packit Service 31306d
    while (fgets(line, sizeof(line), f)) {
Packit Service 31306d
        count++;
Packit Service 31306d
        rv = ssh_config_parse_line(session, line, count, parsing);
Packit Service 31306d
        if (rv < 0) {
Packit Service 31306d
            fclose(f);
Packit Service 31306d
            return;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    fclose(f);
Packit Service 31306d
    return;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER)
Packit Service 31306d
static void local_parse_glob(ssh_session session,
Packit Service 31306d
                             const char *fileglob,
Packit Service 31306d
                             int *parsing)
Packit Service 31306d
{
Packit Service 31306d
    glob_t globbuf = {
Packit Service 31306d
        .gl_flags = 0,
Packit Service 31306d
    };
Packit Service 31306d
    int rt;
Packit Service 31306d
    size_t i;
Packit Service 31306d
Packit Service 31306d
    rt = glob(fileglob, GLOB_TILDE, NULL, &globbuf);
Packit Service 31306d
    if (rt == GLOB_NOMATCH) {
Packit Service 31306d
        globfree(&globbuf);
Packit Service 31306d
        return;
Packit Service 31306d
    } else if (rt != 0) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_RARE, "Glob error: %s",
Packit Service 31306d
                fileglob);
Packit Service 31306d
        globfree(&globbuf);
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    for (i = 0; i < globbuf.gl_pathc; i++) {
Packit Service 31306d
        local_parse_file(session, globbuf.gl_pathv[i], parsing);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    globfree(&globbuf);
Packit Service 31306d
}
Packit Service 31306d
#endif /* HAVE_GLOB HAVE_GLOB_GL_FLAGS_MEMBER */
Packit Service 31306d
Packit Service 31306d
static enum ssh_config_match_e
Packit Service 31306d
ssh_config_get_match_opcode(const char *keyword)
Packit Service 31306d
{
Packit Service 31306d
    size_t i;
Packit Service 31306d
Packit Service 31306d
    for (i = 0; ssh_config_match_keyword_table[i].name != NULL; i++) {
Packit Service 31306d
        if (strcasecmp(keyword, ssh_config_match_keyword_table[i].name) == 0) {
Packit Service 31306d
            return ssh_config_match_keyword_table[i].opcode;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return MATCH_UNKNOWN;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int
Packit Service 31306d
ssh_config_match(char *value, const char *pattern, bool negate)
Packit Service 31306d
{
Packit Service 31306d
    int ok, result = 0;
Packit Service 31306d
Packit Service 31306d
    ok = match_pattern_list(value, pattern, strlen(pattern), 0);
Packit Service 31306d
    if (ok <= 0 && negate == true) {
Packit Service 31306d
        result = 1;
Packit Service 31306d
    } else if (ok > 0 && negate == false) {
Packit Service 31306d
        result = 1;
Packit Service 31306d
    }
Packit Service 31306d
    SSH_LOG(SSH_LOG_TRACE, "%s '%s' against pattern '%s'%s (ok=%d)",
Packit Service 31306d
            result == 1 ? "Matched" : "Not matched", value, pattern,
Packit Service 31306d
            negate == true ? " (negated)" : "", ok);
Packit Service 31306d
    return result;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/* @brief: Parse the ProxyJump configuration line and if parsing,
Packit Service 31306d
 * stores the result in the configuration option
Packit Service 31306d
 */
Packit Service 31306d
static int
Packit Service 31306d
ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
Packit Service 31306d
{
Packit Service 31306d
    char *c = NULL, *cp = NULL, *endp = NULL;
Packit Service 31306d
    char *username = NULL;
Packit Service 31306d
    char *hostname = NULL;
Packit Service 31306d
    char *port = NULL;
Packit Service 31306d
    char *next = NULL;
Packit Service 31306d
    int cmp, rv = SSH_ERROR;
Packit Service 31306d
    bool parse_entry = do_parsing;
Packit Service 31306d
Packit Service 31306d
    /* Special value none disables the proxy */
Packit Service 31306d
    cmp = strcasecmp(s, "none");
Packit Service 31306d
    if (cmp == 0 && do_parsing) {
Packit Service 31306d
        ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, s);
Packit Service 31306d
        return SSH_OK;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* This is comma-separated list of [user@]host[:port] entries */
Packit Service 31306d
    c = strdup(s);
Packit Service 31306d
    if (c == NULL) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    cp = c;
Packit Service 31306d
    do {
Packit Service 31306d
        endp = strchr(cp, ',');
Packit Service 31306d
        if (endp != NULL) {
Packit Service 31306d
            /* Split out the token */
Packit Service 31306d
            *endp = '\0';
Packit Service 31306d
        }
Packit Service 31306d
        if (parse_entry) {
Packit Service 31306d
            /* We actually care only about the first item */
Packit Service 31306d
            rv = ssh_config_parse_uri(cp, &username, &hostname, &port);
Packit Service 31306d
            /* The rest of the list needs to be passed on */
Packit Service 31306d
            if (endp != NULL) {
Packit Service 31306d
                next = strdup(endp + 1);
Packit Service 31306d
                if (next == NULL) {
Packit Service 31306d
                    ssh_set_error_oom(session);
Packit Service 31306d
                    rv = SSH_ERROR;
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
        } else {
Packit Service 31306d
            /* The rest is just sanity-checked to avoid failures later */
Packit Service 31306d
            rv = ssh_config_parse_uri(cp, NULL, NULL, NULL);
Packit Service 31306d
        }
Packit Service 31306d
        if (rv != SSH_OK) {
Packit Service 31306d
            goto out;
Packit Service 31306d
        }
Packit Service 31306d
        parse_entry = 0;
Packit Service 31306d
        if (endp != NULL) {
Packit Service 31306d
            cp = endp + 1;
Packit Service 31306d
        } else {
Packit Service 31306d
            cp = NULL; /* end */
Packit Service 31306d
        }
Packit Service 31306d
    } while (cp != NULL);
Packit Service 31306d
Packit Service 31306d
    if (hostname != NULL && do_parsing) {
Packit Service 31306d
        char com[512] = {0};
Packit Service 31306d
Packit Service 31306d
        rv = snprintf(com, sizeof(com), "ssh%s%s%s%s%s%s -W [%%h]:%%p %s",
Packit Service 31306d
                      username ? " -l " : "",
Packit Service 31306d
                      username ? username : "",
Packit Service 31306d
                      port ? " -p " : "",
Packit Service 31306d
                      port ? port : "",
Packit Service 31306d
                      next ? " -J " : "",
Packit Service 31306d
                      next ? next : "",
Packit Service 31306d
                      hostname);
Packit Service 31306d
        if (rv < 0 || rv >= (int)sizeof(com)) {
Packit Service 31306d
            SSH_LOG(SSH_LOG_WARN, "Too long ProxyJump configuration line");
Packit Service 31306d
            rv = SSH_ERROR;
Packit Service 31306d
            goto out;
Packit Service 31306d
        }
Packit Service 31306d
        ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, com);
Packit Service 31306d
    }
Packit Service 31306d
    rv = SSH_OK;
Packit Service 31306d
Packit Service 31306d
out:
Packit Service 31306d
    SAFE_FREE(username);
Packit Service 31306d
    SAFE_FREE(hostname);
Packit Service 31306d
    SAFE_FREE(port);
Packit Service 31306d
    SAFE_FREE(next);
Packit Service 31306d
    SAFE_FREE(c);
Packit Service 31306d
    return rv;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int
Packit Service 31306d
ssh_config_parse_line(ssh_session session,
Packit Service 31306d
                      const char *line,
Packit Service 31306d
                      unsigned int count,
Packit Service 31306d
                      int *parsing)
Packit Service 31306d
{
Packit Service 31306d
  enum ssh_config_opcode_e opcode;
Packit Service 31306d
  const char *p = NULL, *p2 = NULL;
Packit Service 31306d
  char *s = NULL, *x = NULL;
Packit Service 31306d
  char *keyword = NULL;
Packit Service 31306d
  char *lowerhost = NULL;
Packit Service 31306d
  size_t len;
Packit Service 31306d
  int i, rv;
Packit Service 31306d
  uint8_t *seen = session->opts.options_seen;
Packit Service 31306d
  long l;
Packit Service 31306d
  int64_t ll;
Packit Service 31306d
Packit Service 31306d
  /* Ignore empty lines */
Packit Service 31306d
  if (line == NULL || *line == '\0') {
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  x = s = strdup(line);
Packit Service 31306d
  if (s == NULL) {
Packit Service 31306d
    ssh_set_error_oom(session);
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  /* Remove trailing spaces */
Packit Service 31306d
  for (len = strlen(s) - 1; len > 0; len--) {
Packit Service 31306d
    if (! isspace(s[len])) {
Packit Service 31306d
      break;
Packit Service 31306d
    }
Packit Service 31306d
    s[len] = '\0';
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  keyword = ssh_config_get_token(&s);
Packit Service 31306d
  if (keyword == NULL || *keyword == '#' ||
Packit Service 31306d
      *keyword == '\0' || *keyword == '\n') {
Packit Service 31306d
    SAFE_FREE(x);
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  opcode = ssh_config_get_opcode(keyword);
Packit Service 31306d
  if (*parsing == 1 &&
Packit Service 31306d
      opcode != SOC_HOST &&
Packit Service 31306d
      opcode != SOC_MATCH &&
Packit Service 31306d
      opcode != SOC_INCLUDE &&
Packit Service 31306d
      opcode > SOC_UNSUPPORTED) { /* Ignore all unknown types here */
Packit Service 31306d
      /* Skip all the options that were already applied */
Packit Service 31306d
      if (seen[opcode] != 0) {
Packit Service 31306d
          SAFE_FREE(x);
Packit Service 31306d
          return 0;
Packit Service 31306d
      }
Packit Service 31306d
      seen[opcode] = 1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  switch (opcode) {
Packit Service 31306d
    case SOC_INCLUDE: /* recursive include of other files */
Packit Service 31306d
Packit Service 31306d
      p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
      if (p && *parsing) {
Packit Service 31306d
#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER)
Packit Service 31306d
        local_parse_glob(session, p, parsing);
Packit Service 31306d
#else
Packit Service 31306d
        local_parse_file(session, p, parsing);
Packit Service 31306d
#endif /* HAVE_GLOB */
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
Packit Service 31306d
    case SOC_MATCH: {
Packit Service 31306d
        bool negate;
Packit Service 31306d
        int result = 1;
Packit Service 31306d
        size_t args = 0;
Packit Service 31306d
        enum ssh_config_match_e opt;
Packit Service 31306d
        char *localuser = NULL;
Packit Service 31306d
Packit Service 31306d
        *parsing = 0;
Packit Service 31306d
        do {
Packit Service 31306d
            p = p2 = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
            if (p == NULL || p[0] == '\0') {
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
            args++;
Packit Service 31306d
            SSH_LOG(SSH_LOG_TRACE, "line %d: Processing Match keyword '%s'",
Packit Service 31306d
                    count, p);
Packit Service 31306d
Packit Service 31306d
            /* If the option is prefixed with ! the result should be negated */
Packit Service 31306d
            negate = false;
Packit Service 31306d
            if (p[0] == '!') {
Packit Service 31306d
                negate = true;
Packit Service 31306d
                p++;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            opt = ssh_config_get_match_opcode(p);
Packit Service 31306d
            switch (opt) {
Packit Service 31306d
            case MATCH_ALL:
Packit Service 31306d
                p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
                if (args <= 2 && (p == NULL || p[0] == '\0')) {
Packit Service 31306d
                    /* The first or second, but last argument. The "all" keyword
Packit Service 31306d
                     * can be prefixed with either "final" or "canonical"
Packit Service 31306d
                     * keywords which do not have any effect here. */
Packit Service 31306d
                    if (negate == true) {
Packit Service 31306d
                        result = 0;
Packit Service 31306d
                    }
Packit Service 31306d
                    break;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
                              "line %d: ERROR - Match all cannot be combined with "
Packit Service 31306d
                              "other Match attributes", count);
Packit Service 31306d
                SAFE_FREE(x);
Packit Service 31306d
                return -1;
Packit Service 31306d
Packit Service 31306d
            case MATCH_FINAL:
Packit Service 31306d
            case MATCH_CANONICAL:
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                        "line %d: Unsupported Match keyword '%s', skipping",
Packit Service 31306d
                        count,
Packit Service 31306d
                        p);
Packit Service 31306d
                /* Not set any result here -- the result is dependent on the
Packit Service 31306d
                 * following matches after this keyword */
Packit Service 31306d
                break;
Packit Service 31306d
Packit Service 31306d
            case MATCH_EXEC:
Packit Service 31306d
                /* Skip to the end of line as unsupported */
Packit Service 31306d
                p = ssh_config_get_cmd(&s);
Packit Service 31306d
                if (p == NULL || p[0] == '\0') {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword "
Packit Service 31306d
                            "'%s' requires argument", count, p2);
Packit Service 31306d
                    SAFE_FREE(x);
Packit Service 31306d
                    return -1;
Packit Service 31306d
                }
Packit Service 31306d
                args++;
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                        "line %d: Unsupported Match keyword '%s', ignoring",
Packit Service 31306d
                        count,
Packit Service 31306d
                        p2);
Packit Service 31306d
                result = 0;
Packit Service 31306d
                break;
Packit Service 31306d
Packit Service 31306d
            case MATCH_LOCALUSER:
Packit Service 31306d
                /* Here we match only one argument */
Packit Service 31306d
                p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
                if (p == NULL || p[0] == '\0') {
Packit Service 31306d
                    ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
                                  "line %d: ERROR - Match user keyword "
Packit Service 31306d
                                  "requires argument", count);
Packit Service 31306d
                    SAFE_FREE(x);
Packit Service 31306d
                    return -1;
Packit Service 31306d
                }
Packit Service 31306d
                localuser = ssh_get_local_username();
Packit Service 31306d
                if (localuser == NULL) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "line %d: Can not get local username "
Packit Service 31306d
                            "for conditional matching.", count);
Packit Service 31306d
                    SAFE_FREE(x);
Packit Service 31306d
                    return -1;
Packit Service 31306d
                }
Packit Service 31306d
                result &= ssh_config_match(localuser, p, negate);
Packit Service 31306d
                SAFE_FREE(localuser);
Packit Service 31306d
                args++;
Packit Service 31306d
                break;
Packit Service 31306d
Packit Service 31306d
            case MATCH_ORIGINALHOST:
Packit Service 31306d
                /* Skip one argument */
Packit Service 31306d
                p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
                if (p == NULL || p[0] == '\0') {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword "
Packit Service 31306d
                            "'%s' requires argument", count, p2);
Packit Service 31306d
                    SAFE_FREE(x);
Packit Service 31306d
                    return -1;
Packit Service 31306d
                }
Packit Service 31306d
                args++;
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                        "line %d: Unsupported Match keyword '%s', ignoring",
Packit Service 31306d
                        count,
Packit Service 31306d
                        p2);
Packit Service 31306d
                result = 0;
Packit Service 31306d
                break;
Packit Service 31306d
Packit Service 31306d
            case MATCH_HOST:
Packit Service 31306d
                /* Here we match only one argument */
Packit Service 31306d
                p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
                if (p == NULL || p[0] == '\0') {
Packit Service 31306d
                    ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
                                  "line %d: ERROR - Match host keyword "
Packit Service 31306d
                                  "requires argument", count);
Packit Service 31306d
                    SAFE_FREE(x);
Packit Service 31306d
                    return -1;
Packit Service 31306d
                }
Packit Service 31306d
                result &= ssh_config_match(session->opts.host, p, negate);
Packit Service 31306d
                args++;
Packit Service 31306d
                break;
Packit Service 31306d
Packit Service 31306d
            case MATCH_USER:
Packit Service 31306d
                /* Here we match only one argument */
Packit Service 31306d
                p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
                if (p == NULL || p[0] == '\0') {
Packit Service 31306d
                    ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
                                  "line %d: ERROR - Match user keyword "
Packit Service 31306d
                                  "requires argument", count);
Packit Service 31306d
                    SAFE_FREE(x);
Packit Service 31306d
                    return -1;
Packit Service 31306d
                }
Packit Service 31306d
                result &= ssh_config_match(session->opts.username, p, negate);
Packit Service 31306d
                args++;
Packit Service 31306d
                break;
Packit Service 31306d
Packit Service 31306d
            case MATCH_UNKNOWN:
Packit Service 31306d
            default:
Packit Service 31306d
                ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
                              "ERROR - Unknown argument '%s' for Match keyword", p);
Packit Service 31306d
                SAFE_FREE(x);
Packit Service 31306d
                return -1;
Packit Service 31306d
            }
Packit Service 31306d
        } while (p != NULL && p[0] != '\0');
Packit Service 31306d
        if (args == 0) {
Packit Service 31306d
            ssh_set_error(session, SSH_FATAL,
Packit Service 31306d
                          "ERROR - Match keyword requires an argument");
Packit Service 31306d
            SAFE_FREE(x);
Packit Service 31306d
            return -1;
Packit Service 31306d
        }
Packit Service 31306d
        *parsing = result;
Packit Service 31306d
        break;
Packit Service 31306d
    }
Packit Service 31306d
    case SOC_HOST: {
Packit Service 31306d
        int ok = 0, result = -1;
Packit Service 31306d
Packit Service 31306d
        *parsing = 0;
Packit Service 31306d
        lowerhost = (session->opts.host) ? ssh_lowercase(session->opts.host) : NULL;
Packit Service 31306d
        for (p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
             p != NULL && p[0] != '\0';
Packit Service 31306d
             p = ssh_config_get_str_tok(&s, NULL)) {
Packit Service 31306d
             if (ok >= 0) {
Packit Service 31306d
               ok = match_hostname(lowerhost, p, strlen(p));
Packit Service 31306d
               if (result == -1 && ok < 0) {
Packit Service 31306d
                   result = 0;
Packit Service 31306d
               } else if (result == -1 && ok > 0) {
Packit Service 31306d
                   result = 1;
Packit Service 31306d
               }
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        SAFE_FREE(lowerhost);
Packit Service 31306d
        if (result != -1) {
Packit Service 31306d
            *parsing = result;
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    }
Packit Service 31306d
    case SOC_HOSTNAME:
Packit Service 31306d
      p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
      if (p && *parsing) {
Packit Service 31306d
        char *z = ssh_path_expand_escape(session, p);
Packit Service 31306d
        if (z == NULL) {
Packit Service 31306d
            z = strdup(p);
Packit Service 31306d
        }
Packit Service 31306d
        ssh_options_set(session, SSH_OPTIONS_HOST, z);
Packit Service 31306d
        free(z);
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SOC_PORT:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && *parsing) {
Packit Service 31306d
            ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SOC_USERNAME:
Packit Service 31306d
      if (session->opts.username == NULL) {
Packit Service 31306d
          p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
          if (p && *parsing) {
Packit Service 31306d
            ssh_options_set(session, SSH_OPTIONS_USER, p);
Packit Service 31306d
         }
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SOC_IDENTITY:
Packit Service 31306d
      p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
      if (p && *parsing) {
Packit Service 31306d
        ssh_options_set(session, SSH_OPTIONS_ADD_IDENTITY, p);
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SOC_CIPHERS:
Packit Service 31306d
      p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
      if (p && *parsing) {
Packit Service 31306d
        ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, p);
Packit Service 31306d
        ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, p);
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SOC_MACS:
Packit Service 31306d
      p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
      if (p && *parsing) {
Packit Service 31306d
        ssh_options_set(session, SSH_OPTIONS_HMAC_C_S, p);
Packit Service 31306d
        ssh_options_set(session, SSH_OPTIONS_HMAC_S_C, p);
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SOC_COMPRESSION:
Packit Service 31306d
      i = ssh_config_get_yesno(&s, -1);
Packit Service 31306d
      if (i >= 0 && *parsing) {
Packit Service 31306d
        if (i) {
Packit Service 31306d
          ssh_options_set(session, SSH_OPTIONS_COMPRESSION, "yes");
Packit Service 31306d
        } else {
Packit Service 31306d
          ssh_options_set(session, SSH_OPTIONS_COMPRESSION, "no");
Packit Service 31306d
        }
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SOC_PROTOCOL:
Packit Service 31306d
      p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
      if (p && *parsing) {
Packit Service 31306d
        char *a, *b;
Packit Service 31306d
        b = strdup(p);
Packit Service 31306d
        if (b == NULL) {
Packit Service 31306d
          SAFE_FREE(x);
Packit Service 31306d
          ssh_set_error_oom(session);
Packit Service 31306d
          return -1;
Packit Service 31306d
        }
Packit Service 31306d
        i = 0;
Packit Service 31306d
        ssh_options_set(session, SSH_OPTIONS_SSH2, &i);
Packit Service 31306d
Packit Service 31306d
        for (a = strtok(b, ","); a; a = strtok(NULL, ",")) {
Packit Service 31306d
          switch (atoi(a)) {
Packit Service 31306d
            case 1:
Packit Service 31306d
              break;
Packit Service 31306d
            case 2:
Packit Service 31306d
              i = 1;
Packit Service 31306d
              ssh_options_set(session, SSH_OPTIONS_SSH2, &i);
Packit Service 31306d
              break;
Packit Service 31306d
            default:
Packit Service 31306d
              break;
Packit Service 31306d
          }
Packit Service 31306d
        }
Packit Service 31306d
        SAFE_FREE(b);
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SOC_TIMEOUT:
Packit Service 31306d
      l = ssh_config_get_long(&s, -1);
Packit Service 31306d
      if (l >= 0 && *parsing) {
Packit Service 31306d
        ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &l);
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SOC_STRICTHOSTKEYCHECK:
Packit Service 31306d
      i = ssh_config_get_yesno(&s, -1);
Packit Service 31306d
      if (i >= 0 && *parsing) {
Packit Service 31306d
        ssh_options_set(session, SSH_OPTIONS_STRICTHOSTKEYCHECK, &i);
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SOC_KNOWNHOSTS:
Packit Service 31306d
      p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
      if (p && *parsing) {
Packit Service 31306d
        ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, p);
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SOC_PROXYCOMMAND:
Packit Service 31306d
      p = ssh_config_get_cmd(&s);
Packit Service 31306d
      /* We share the seen value with the ProxyJump */
Packit Service 31306d
      if (p && *parsing && !seen[SOC_PROXYJUMP]) {
Packit Service 31306d
        ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, p);
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SOC_PROXYJUMP:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p == NULL) {
Packit Service 31306d
            SAFE_FREE(x);
Packit Service 31306d
            return -1;
Packit Service 31306d
        }
Packit Service 31306d
        /* We share the seen value with the ProxyCommand */
Packit Service 31306d
        rv = ssh_config_parse_proxy_jump(session, p,
Packit Service 31306d
                                         (*parsing && !seen[SOC_PROXYCOMMAND]));
Packit Service 31306d
        if (rv != SSH_OK) {
Packit Service 31306d
            SAFE_FREE(x);
Packit Service 31306d
            return -1;
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SOC_GSSAPISERVERIDENTITY:
Packit Service 31306d
      p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
      if (p && *parsing) {
Packit Service 31306d
        ssh_options_set(session, SSH_OPTIONS_GSSAPI_SERVER_IDENTITY, p);
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SOC_GSSAPICLIENTIDENTITY:
Packit Service 31306d
      p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
      if (p && *parsing) {
Packit Service 31306d
        ssh_options_set(session, SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY, p);
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SOC_GSSAPIDELEGATECREDENTIALS:
Packit Service 31306d
      i = ssh_config_get_yesno(&s, -1);
Packit Service 31306d
      if (i >=0 && *parsing) {
Packit Service 31306d
        ssh_options_set(session, SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS, &i);
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SOC_BINDADDRESS:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && *parsing) {
Packit Service 31306d
            ssh_options_set(session, SSH_OPTIONS_BINDADDR, p);
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SOC_GLOBALKNOWNHOSTSFILE:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && *parsing) {
Packit Service 31306d
            ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, p);
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SOC_LOGLEVEL:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && *parsing) {
Packit Service 31306d
            int value = -1;
Packit Service 31306d
Packit Service 31306d
            if (strcasecmp(p, "quiet") == 0) {
Packit Service 31306d
                value = SSH_LOG_NONE;
Packit Service 31306d
            } else if (strcasecmp(p, "fatal") == 0 ||
Packit Service 31306d
                    strcasecmp(p, "error")== 0 ||
Packit Service 31306d
                    strcasecmp(p, "info") == 0) {
Packit Service 31306d
                value = SSH_LOG_WARN;
Packit Service 31306d
            } else if (strcasecmp(p, "verbose") == 0) {
Packit Service 31306d
                value = SSH_LOG_INFO;
Packit Service 31306d
            } else if (strcasecmp(p, "DEBUG") == 0 ||
Packit Service 31306d
                    strcasecmp(p, "DEBUG1") == 0) {
Packit Service 31306d
                value = SSH_LOG_DEBUG;
Packit Service 31306d
            } else if (strcasecmp(p, "DEBUG2") == 0 ||
Packit Service 31306d
                    strcasecmp(p, "DEBUG3") == 0) {
Packit Service 31306d
                value = SSH_LOG_TRACE;
Packit Service 31306d
            }
Packit Service 31306d
            if (value != -1) {
Packit Service 31306d
                ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &value);
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SOC_HOSTKEYALGORITHMS:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && *parsing) {
Packit Service 31306d
            ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, p);
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SOC_PUBKEYACCEPTEDTYPES:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && *parsing) {
Packit Service 31306d
            ssh_options_set(session, SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES, p);
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SOC_KEXALGORITHMS:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && *parsing) {
Packit Service 31306d
            ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, p);
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SOC_REKEYLIMIT:
Packit Service 31306d
        /* Parse the data limit */
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p == NULL) {
Packit Service 31306d
            break;
Packit Service 31306d
        } else if (strcmp(p, "default") == 0) {
Packit Service 31306d
            /* Default rekey limits enforced automaticaly */
Packit Service 31306d
            ll = 0;
Packit Service 31306d
        } else {
Packit Service 31306d
            char *endp = NULL;
Packit Service 31306d
            ll = strtoll(p, &endp, 10);
Packit Service 31306d
            if (p == endp || ll < 0) {
Packit Service 31306d
                /* No number or negative */
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN, "Invalid argument to rekey limit");
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
            switch (*endp) {
Packit Service 31306d
            case 'G':
Packit Service 31306d
                if (ll > LLONG_MAX / 1024) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
Packit Service 31306d
                    ll = -1;
Packit Service 31306d
                    break;
Packit Service 31306d
                }
Packit Service 31306d
                ll = ll * 1024;
Packit Service 31306d
                FALL_THROUGH;
Packit Service 31306d
            case 'M':
Packit Service 31306d
                if (ll > LLONG_MAX / 1024) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
Packit Service 31306d
                    ll = -1;
Packit Service 31306d
                    break;
Packit Service 31306d
                }
Packit Service 31306d
                ll = ll * 1024;
Packit Service 31306d
                FALL_THROUGH;
Packit Service 31306d
            case 'K':
Packit Service 31306d
                if (ll > LLONG_MAX / 1024) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
Packit Service 31306d
                    ll = -1;
Packit Service 31306d
                    break;
Packit Service 31306d
                }
Packit Service 31306d
                ll = ll * 1024;
Packit Service 31306d
                endp++;
Packit Service 31306d
                FALL_THROUGH;
Packit Service 31306d
            case '\0':
Packit Service 31306d
                /* just the number */
Packit Service 31306d
                break;
Packit Service 31306d
            default:
Packit Service 31306d
                /* Invalid suffix */
Packit Service 31306d
                ll = -1;
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
            if (*endp != ' ' && *endp != '\0') {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                        "Invalid trailing characters after the rekey limit: %s",
Packit Service 31306d
                        endp);
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        if (ll > -1 && *parsing) {
Packit Service 31306d
            uint64_t v = (uint64_t)ll;
Packit Service 31306d
            ssh_options_set(session, SSH_OPTIONS_REKEY_DATA, &v);
Packit Service 31306d
        }
Packit Service 31306d
        /* Parse the time limit */
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p == NULL) {
Packit Service 31306d
            break;
Packit Service 31306d
        } else if (strcmp(p, "none") == 0) {
Packit Service 31306d
            ll = 0;
Packit Service 31306d
        } else {
Packit Service 31306d
            char *endp = NULL;
Packit Service 31306d
            ll = strtoll(p, &endp, 10);
Packit Service 31306d
            if (p == endp || ll < 0) {
Packit Service 31306d
                /* No number or negative */
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN, "Invalid argument to rekey limit");
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
            switch (*endp) {
Packit Service 31306d
            case 'w':
Packit Service 31306d
            case 'W':
Packit Service 31306d
                if (ll > LLONG_MAX / 7) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
Packit Service 31306d
                    ll = -1;
Packit Service 31306d
                    break;
Packit Service 31306d
                }
Packit Service 31306d
                ll = ll * 7;
Packit Service 31306d
                FALL_THROUGH;
Packit Service 31306d
            case 'd':
Packit Service 31306d
            case 'D':
Packit Service 31306d
                if (ll > LLONG_MAX / 24) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
Packit Service 31306d
                    ll = -1;
Packit Service 31306d
                    break;
Packit Service 31306d
                }
Packit Service 31306d
                ll = ll * 24;
Packit Service 31306d
                FALL_THROUGH;
Packit Service 31306d
            case 'h':
Packit Service 31306d
            case 'H':
Packit Service 31306d
                if (ll > LLONG_MAX / 60) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
Packit Service 31306d
                    ll = -1;
Packit Service 31306d
                    break;
Packit Service 31306d
                }
Packit Service 31306d
                ll = ll * 60;
Packit Service 31306d
                FALL_THROUGH;
Packit Service 31306d
            case 'm':
Packit Service 31306d
            case 'M':
Packit Service 31306d
                if (ll > LLONG_MAX / 60) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
Packit Service 31306d
                    ll = -1;
Packit Service 31306d
                    break;
Packit Service 31306d
                }
Packit Service 31306d
                ll = ll * 60;
Packit Service 31306d
                FALL_THROUGH;
Packit Service 31306d
            case 's':
Packit Service 31306d
            case 'S':
Packit Service 31306d
                endp++;
Packit Service 31306d
                FALL_THROUGH;
Packit Service 31306d
            case '\0':
Packit Service 31306d
                /* just the number */
Packit Service 31306d
                break;
Packit Service 31306d
            default:
Packit Service 31306d
                /* Invalid suffix */
Packit Service 31306d
                ll = -1;
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
            if (*endp != '\0') {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN, "Invalid trailing characters after the"
Packit Service 31306d
                        " rekey limit: %s", endp);
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        if (ll > -1 && *parsing) {
Packit Service 31306d
            uint32_t v = (uint32_t)ll;
Packit Service 31306d
            ssh_options_set(session, SSH_OPTIONS_REKEY_TIME, &v);
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SOC_GSSAPIAUTHENTICATION:
Packit Service 31306d
    case SOC_KBDINTERACTIVEAUTHENTICATION:
Packit Service 31306d
    case SOC_PASSWORDAUTHENTICATION:
Packit Service 31306d
    case SOC_PUBKEYAUTHENTICATION:
Packit Service 31306d
        i = ssh_config_get_yesno(&s, 0);
Packit Service 31306d
        if (i>=0 && *parsing) {
Packit Service 31306d
            switch(opcode){
Packit Service 31306d
            case SOC_GSSAPIAUTHENTICATION:
Packit Service 31306d
                ssh_options_set(session, SSH_OPTIONS_GSSAPI_AUTH, &i);
Packit Service 31306d
                break;
Packit Service 31306d
            case SOC_KBDINTERACTIVEAUTHENTICATION:
Packit Service 31306d
                ssh_options_set(session, SSH_OPTIONS_KBDINT_AUTH, &i);
Packit Service 31306d
                break;
Packit Service 31306d
            case SOC_PASSWORDAUTHENTICATION:
Packit Service 31306d
                ssh_options_set(session, SSH_OPTIONS_PASSWORD_AUTH, &i);
Packit Service 31306d
                break;
Packit Service 31306d
            case SOC_PUBKEYAUTHENTICATION:
Packit Service 31306d
                ssh_options_set(session, SSH_OPTIONS_PUBKEY_AUTH, &i);
Packit Service 31306d
                break;
Packit Service 31306d
            /* make gcc happy */
Packit Service 31306d
            default:
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SOC_NA:
Packit Service 31306d
      SSH_LOG(SSH_LOG_INFO, "Unapplicable option: %s, line: %d",
Packit Service 31306d
              keyword, count);
Packit Service 31306d
      break;
Packit Service 31306d
    case SOC_UNSUPPORTED:
Packit Service 31306d
      SSH_LOG(SSH_LOG_RARE, "Unsupported option: %s, line: %d",
Packit Service 31306d
              keyword, count);
Packit Service 31306d
      break;
Packit Service 31306d
    case SOC_UNKNOWN:
Packit Service 31306d
      SSH_LOG(SSH_LOG_WARN, "Unknown option: %s, line: %d",
Packit Service 31306d
              keyword, count);
Packit Service 31306d
      break;
Packit Service 31306d
    default:
Packit Service 31306d
      ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d",
Packit Service 31306d
              opcode);
Packit Service 31306d
      SAFE_FREE(x);
Packit Service 31306d
      return -1;
Packit Service 31306d
      break;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  SAFE_FREE(x);
Packit Service 31306d
  return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/* @brief Parse configuration file and set the options to the given session
Packit Service 31306d
 *
Packit Service 31306d
 * @params[in] session   The ssh session
Packit Service 31306d
 * @params[in] filename  The path to the ssh configuration file
Packit Service 31306d
 *
Packit Service 31306d
 * @returns    0 on successful parsing the configuration file, -1 on error
Packit Service 31306d
 */
Packit Service 31306d
int ssh_config_parse_file(ssh_session session, const char *filename)
Packit Service 31306d
{
Packit Service 31306d
    char line[MAX_LINE_SIZE] = {0};
Packit Service 31306d
    unsigned int count = 0;
Packit Service 31306d
    FILE *f;
Packit Service 31306d
    int parsing, rv;
Packit Service 31306d
Packit Service 31306d
    f = fopen(filename, "r");
Packit Service 31306d
    if (f == NULL) {
Packit Service 31306d
        return 0;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_PACKET, "Reading configuration data from %s", filename);
Packit Service 31306d
Packit Service 31306d
    parsing = 1;
Packit Service 31306d
    while (fgets(line, sizeof(line), f)) {
Packit Service 31306d
        count++;
Packit Service 31306d
        rv = ssh_config_parse_line(session, line, count, &parsing);
Packit Service 31306d
        if (rv < 0) {
Packit Service 31306d
            fclose(f);
Packit Service 31306d
            return -1;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    fclose(f);
Packit Service 31306d
    return 0;
Packit Service 31306d
}