Blame src/bind_config.c

Packit Service 31306d
/*
Packit Service 31306d
 * bind_config.c - Parse the SSH server configuration file
Packit Service 31306d
 *
Packit Service 31306d
 * This file is part of the SSH Library
Packit Service 31306d
 *
Packit Service 31306d
 * Copyright (c) 2019 by Red Hat, Inc.
Packit Service 31306d
 *
Packit Service 31306d
 * Author: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
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
Packit Service 31306d
#include "libssh/bind.h"
Packit Service 31306d
#include "libssh/bind_config.h"
Packit Service 31306d
#include "libssh/config_parser.h"
Packit Service 31306d
#include "libssh/priv.h"
Packit Service 31306d
#include "libssh/server.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
/* Flags used for the parser state */
Packit Service 31306d
#define PARSING     1
Packit Service 31306d
#define IN_MATCH    (1<<1)
Packit Service 31306d
Packit Service 31306d
struct ssh_bind_config_keyword_table_s {
Packit Service 31306d
  const char *name;
Packit Service 31306d
  enum ssh_bind_config_opcode_e opcode;
Packit Service 31306d
  bool allowed_in_match;
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
static struct ssh_bind_config_keyword_table_s
Packit Service 31306d
ssh_bind_config_keyword_table[] = {
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "include",
Packit Service 31306d
        .opcode = BIND_CFG_INCLUDE
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "hostkey",
Packit Service 31306d
        .opcode = BIND_CFG_HOSTKEY
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "listenaddress",
Packit Service 31306d
        .opcode = BIND_CFG_LISTENADDRESS
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "port",
Packit Service 31306d
        .opcode = BIND_CFG_PORT
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "loglevel",
Packit Service 31306d
        .opcode = BIND_CFG_LOGLEVEL,
Packit Service 31306d
        .allowed_in_match = true,
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "ciphers",
Packit Service 31306d
        .opcode = BIND_CFG_CIPHERS
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "macs",
Packit Service 31306d
        .opcode = BIND_CFG_MACS
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "kexalgorithms",
Packit Service 31306d
        .opcode = BIND_CFG_KEXALGORITHMS
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "match",
Packit Service 31306d
        .opcode = BIND_CFG_MATCH,
Packit Service 31306d
        .allowed_in_match = true
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "pubkeyacceptedkeytypes",
Packit Service 31306d
        .opcode = BIND_CFG_PUBKEY_ACCEPTED_KEY_TYPES,
Packit Service 31306d
        .allowed_in_match = true
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "hostkeyalgorithms",
Packit Service 31306d
        .opcode = BIND_CFG_HOSTKEY_ALGORITHMS,
Packit Service 31306d
        .allowed_in_match = true
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .opcode = BIND_CFG_UNKNOWN,
Packit Service 31306d
    }
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
enum ssh_bind_config_match_e {
Packit Service 31306d
    BIND_MATCH_UNKNOWN = -1,
Packit Service 31306d
    BIND_MATCH_ALL,
Packit Service 31306d
    BIND_MATCH_USER,
Packit Service 31306d
    BIND_MATCH_GROUP,
Packit Service 31306d
    BIND_MATCH_HOST,
Packit Service 31306d
    BIND_MATCH_LOCALADDRESS,
Packit Service 31306d
    BIND_MATCH_LOCALPORT,
Packit Service 31306d
    BIND_MATCH_RDOMAIN,
Packit Service 31306d
    BIND_MATCH_ADDRESS,
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
struct ssh_bind_config_match_keyword_table_s {
Packit Service 31306d
    const char *name;
Packit Service 31306d
    enum ssh_bind_config_match_e opcode;
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
static struct ssh_bind_config_match_keyword_table_s
Packit Service 31306d
ssh_bind_config_match_keyword_table[] = {
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "all",
Packit Service 31306d
        .opcode = BIND_MATCH_ALL
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "user",
Packit Service 31306d
        .opcode = BIND_MATCH_USER
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "group",
Packit Service 31306d
        .opcode = BIND_MATCH_GROUP
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "host",
Packit Service 31306d
        .opcode = BIND_MATCH_HOST
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "localaddress",
Packit Service 31306d
        .opcode = BIND_MATCH_LOCALADDRESS
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "localport",
Packit Service 31306d
        .opcode = BIND_MATCH_LOCALPORT
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "rdomain",
Packit Service 31306d
        .opcode = BIND_MATCH_RDOMAIN
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .name   = "address",
Packit Service 31306d
        .opcode = BIND_MATCH_ADDRESS
Packit Service 31306d
    },
Packit Service 31306d
    {
Packit Service 31306d
        .opcode = BIND_MATCH_UNKNOWN
Packit Service 31306d
    },
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
static enum ssh_bind_config_opcode_e
Packit Service 31306d
ssh_bind_config_get_opcode(char *keyword, uint32_t *parser_flags)
Packit Service 31306d
{
Packit Service 31306d
    int i;
Packit Service 31306d
Packit Service 31306d
    for (i = 0; ssh_bind_config_keyword_table[i].name != NULL; i++) {
Packit Service 31306d
        if (strcasecmp(keyword, ssh_bind_config_keyword_table[i].name) == 0) {
Packit Service 31306d
            if ((*parser_flags & IN_MATCH) &&
Packit Service 31306d
                !(ssh_bind_config_keyword_table[i].allowed_in_match))
Packit Service 31306d
            {
Packit Service 31306d
                return BIND_CFG_NOT_ALLOWED_IN_MATCH;
Packit Service 31306d
            }
Packit Service 31306d
            return ssh_bind_config_keyword_table[i].opcode;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return BIND_CFG_UNKNOWN;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int
Packit Service 31306d
ssh_bind_config_parse_line(ssh_bind bind,
Packit Service 31306d
                           const char *line,
Packit Service 31306d
                           unsigned int count,
Packit Service 31306d
                           uint32_t *parser_flags,
Packit Service 31306d
                           uint8_t *seen);
Packit Service 31306d
Packit Service 31306d
static void local_parse_file(ssh_bind bind,
Packit Service 31306d
                             const char *filename,
Packit Service 31306d
                             uint32_t *parser_flags,
Packit Service 31306d
                             uint8_t *seen)
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",
Packit Service 31306d
            filename);
Packit Service 31306d
Packit Service 31306d
    while (fgets(line, sizeof(line), f)) {
Packit Service 31306d
        count++;
Packit Service 31306d
        rv = ssh_bind_config_parse_line(bind, line, count, parser_flags, seen);
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_bind bind,
Packit Service 31306d
                             const char *fileglob,
Packit Service 31306d
                             uint32_t *parser_flags,
Packit Service 31306d
                             uint8_t *seen)
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
    u_int 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(bind, globbuf.gl_pathv[i], parser_flags, seen);
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_bind_config_match_e
Packit Service 31306d
ssh_bind_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_bind_config_match_keyword_table[i].name != NULL; i++) {
Packit Service 31306d
        if (strcasecmp(keyword, ssh_bind_config_match_keyword_table[i].name) == 0) {
Packit Service 31306d
            return ssh_bind_config_match_keyword_table[i].opcode;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return BIND_MATCH_UNKNOWN;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int
Packit Service 31306d
ssh_bind_config_parse_line(ssh_bind bind,
Packit Service 31306d
                           const char *line,
Packit Service 31306d
                           unsigned int count,
Packit Service 31306d
                           uint32_t *parser_flags,
Packit Service 31306d
                           uint8_t *seen)
Packit Service 31306d
{
Packit Service 31306d
    enum ssh_bind_config_opcode_e opcode;
Packit Service 31306d
    const char *p = NULL;
Packit Service 31306d
    char *s = NULL, *x = NULL;
Packit Service 31306d
    char *keyword = NULL;
Packit Service 31306d
    size_t len;
Packit Service 31306d
Packit Service 31306d
    int rc = 0;
Packit Service 31306d
Packit Service 31306d
    if (bind == NULL) {
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if ((line == NULL) || (parser_flags == NULL)) {
Packit Service 31306d
        ssh_set_error_invalid(bind);
Packit Service 31306d
        return -1;
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(bind);
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_bind_config_get_opcode(keyword, parser_flags);
Packit Service 31306d
    if ((*parser_flags & PARSING) &&
Packit Service 31306d
            opcode != BIND_CFG_HOSTKEY &&
Packit Service 31306d
            opcode != BIND_CFG_INCLUDE &&
Packit Service 31306d
            opcode != BIND_CFG_MATCH &&
Packit Service 31306d
            opcode > BIND_CFG_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 BIND_CFG_INCLUDE:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && (*parser_flags & PARSING)) {
Packit Service 31306d
#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER)
Packit Service 31306d
            local_parse_glob(bind, p, parser_flags, seen);
Packit Service 31306d
#else
Packit Service 31306d
            local_parse_file(bind, p, parser_flags, seen);
Packit Service 31306d
#endif /* HAVE_GLOB */
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
Packit Service 31306d
    case BIND_CFG_HOSTKEY:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && (*parser_flags & PARSING)) {
Packit Service 31306d
            rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HOSTKEY, p);
Packit Service 31306d
            if (rc != 0) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                        "line %d: Failed to set Hostkey value '%s'",
Packit Service 31306d
                        count, p);
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case BIND_CFG_LISTENADDRESS:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && (*parser_flags & PARSING)) {
Packit Service 31306d
            rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDADDR, p);
Packit Service 31306d
            if (rc != 0) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                        "line %d: Failed to set ListenAddress value '%s'",
Packit Service 31306d
                        count, p);
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case BIND_CFG_PORT:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && (*parser_flags & PARSING)) {
Packit Service 31306d
            rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDPORT_STR, p);
Packit Service 31306d
            if (rc != 0) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                        "line %d: Failed to set Port value '%s'",
Packit Service 31306d
                        count, p);
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case BIND_CFG_CIPHERS:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && (*parser_flags & PARSING)) {
Packit Service 31306d
            rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_CIPHERS_C_S, p);
Packit Service 31306d
            if (rc != 0) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                        "line %d: Failed to set C->S Ciphers value '%s'",
Packit Service 31306d
                        count, p);
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_CIPHERS_S_C, p);
Packit Service 31306d
            if (rc != 0) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                        "line %d: Failed to set S->C Ciphers value '%s'",
Packit Service 31306d
                        count, p);
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case BIND_CFG_MACS:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && (*parser_flags & PARSING)) {
Packit Service 31306d
            rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HMAC_C_S, p);
Packit Service 31306d
            if (rc != 0) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                        "line %d: Failed to set C->S MAC value '%s'",
Packit Service 31306d
                        count, p);
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HMAC_S_C, p);
Packit Service 31306d
            if (rc != 0) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                        "line %d: Failed to set S->C MAC value '%s'",
Packit Service 31306d
                        count, p);
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case BIND_CFG_LOGLEVEL:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && (*parser_flags & 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
                rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_LOG_VERBOSITY,
Packit Service 31306d
                        &value);
Packit Service 31306d
                if (rc != 0) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                            "line %d: Failed to set LogLevel value '%s'",
Packit Service 31306d
                            count, p);
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case BIND_CFG_KEXALGORITHMS:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && (*parser_flags & PARSING)) {
Packit Service 31306d
            rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_KEY_EXCHANGE, p);
Packit Service 31306d
            if (rc != 0) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                        "line %d: Failed to set KexAlgorithms value '%s'",
Packit Service 31306d
                        count, p);
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case BIND_CFG_MATCH: {
Packit Service 31306d
        bool negate;
Packit Service 31306d
        int result = PARSING;
Packit Service 31306d
        size_t args = 0;
Packit Service 31306d
        enum ssh_bind_config_match_e opt;
Packit Service 31306d
        const char *p2 = NULL;
Packit Service 31306d
Packit Service 31306d
        /* The options set in Match blocks should be applied when a connection
Packit Service 31306d
         * is accepted, and not right away when parsing the file (as it is
Packit Service 31306d
         * currently done). This means the configuration files should be parsed
Packit Service 31306d
         * again or the options set in the Match blocks should be stored and
Packit Service 31306d
         * applied as necessary. */
Packit Service 31306d
Packit Service 31306d
        /* If this is the first Match block, erase the seen table to allow
Packit Service 31306d
         * options to be overridden. Erasing the seen table was the easiest way
Packit Service 31306d
         * to allow overriding an option, but only for the first occurrence of
Packit Service 31306d
         * an option in a Match block. This is sufficient for the current
Packit Service 31306d
         * implementation which supports only the 'All' criterion, meaning the
Packit Service 31306d
         * options can be applied right away. */
Packit Service 31306d
        if (!(*parser_flags & IN_MATCH)) {
Packit Service 31306d
            memset(seen, 0x00, BIND_CFG_MAX * sizeof(uint8_t));
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /* In this line the PARSING bit is cleared from the flags */
Packit Service 31306d
        *parser_flags = IN_MATCH;
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_bind_config_get_match_opcode(p);
Packit Service 31306d
            switch (opt) {
Packit Service 31306d
            case BIND_MATCH_ALL:
Packit Service 31306d
                p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
                if ((args == 1) && (p == NULL || p[0] == '\0')) {
Packit Service 31306d
                    /* The "all" keyword does not accept arguments or modifiers
Packit Service 31306d
                     */
Packit Service 31306d
                    if (negate == true) {
Packit Service 31306d
                        result = 0;
Packit Service 31306d
                    }
Packit Service 31306d
                    break;
Packit Service 31306d
                }
Packit Service 31306d
                ssh_set_error(bind, 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
            case BIND_MATCH_USER:
Packit Service 31306d
            case BIND_MATCH_GROUP:
Packit Service 31306d
            case BIND_MATCH_HOST:
Packit Service 31306d
            case BIND_MATCH_LOCALADDRESS:
Packit Service 31306d
            case BIND_MATCH_LOCALPORT:
Packit Service 31306d
            case BIND_MATCH_RDOMAIN:
Packit Service 31306d
            case BIND_MATCH_ADDRESS:
Packit Service 31306d
                /* Only "All" is supported for now */
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\n", 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\n",
Packit Service 31306d
                        count,
Packit Service 31306d
                        p2);
Packit Service 31306d
                result = 0;
Packit Service 31306d
                break;
Packit Service 31306d
            case BIND_MATCH_UNKNOWN:
Packit Service 31306d
            default:
Packit Service 31306d
                ssh_set_error(bind, 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(bind, 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
        /* This line only sets the PARSING flag if all checks passed */
Packit Service 31306d
        *parser_flags |= result;
Packit Service 31306d
        break;
Packit Service 31306d
    }
Packit Service 31306d
    case BIND_CFG_PUBKEY_ACCEPTED_KEY_TYPES:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && (*parser_flags & PARSING)) {
Packit Service 31306d
            rc = ssh_bind_options_set(bind,
Packit Service 31306d
                                 SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES, p);
Packit Service 31306d
            if (rc != 0) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                        "line %d: Failed to set PubKeyAcceptedKeyTypes value '%s'",
Packit Service 31306d
                        count, p);
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case BIND_CFG_HOSTKEY_ALGORITHMS:
Packit Service 31306d
        p = ssh_config_get_str_tok(&s, NULL);
Packit Service 31306d
        if (p && (*parser_flags & PARSING)) {
Packit Service 31306d
            rc = ssh_bind_options_set(bind,
Packit Service 31306d
                                 SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, p);
Packit Service 31306d
            if (rc != 0) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                        "line %d: Failed to set HostkeyAlgorithms value '%s'",
Packit Service 31306d
                        count, p);
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case BIND_CFG_NOT_ALLOWED_IN_MATCH:
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Option not allowed in Match block: %s, line: %d",
Packit Service 31306d
                keyword, count);
Packit Service 31306d
        break;
Packit Service 31306d
    case BIND_CFG_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
    case BIND_CFG_UNSUPPORTED:
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Unsupported option: %s, line: %d",
Packit Service 31306d
                keyword, count);
Packit Service 31306d
        break;
Packit Service 31306d
    case BIND_CFG_NA:
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Option not applicable: %s, line: %d",
Packit Service 31306d
                keyword, count);
Packit Service 31306d
        break;
Packit Service 31306d
    default:
Packit Service 31306d
        ssh_set_error(bind, 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 rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int ssh_bind_config_parse_file(ssh_bind bind, 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
    uint32_t parser_flags;
Packit Service 31306d
    int rv;
Packit Service 31306d
Packit Service 31306d
    /* This local table is used during the parsing of the current file (and
Packit Service 31306d
     * files included recursively in this file) to prevent an option to be
Packit Service 31306d
     * redefined, i.e. the first value set is kept. But this DO NOT prevent the
Packit Service 31306d
     * option to be redefined later by another file. */
Packit Service 31306d
    uint8_t seen[BIND_CFG_MAX] = {0};
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
    parser_flags = PARSING;
Packit Service 31306d
    while (fgets(line, sizeof(line), f)) {
Packit Service 31306d
        count++;
Packit Service 31306d
        rv = ssh_bind_config_parse_line(bind, line, count, &parser_flags, seen);
Packit Service 31306d
        if (rv) {
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
}