From 79049981a513f9a10fac0f153e9b0b588326021f Mon Sep 17 00:00:00 2001 From: Anderson Toshiyuki Sasaki Date: Fri, 22 Feb 2019 13:06:49 +0100 Subject: [PATCH] config: Move common parser functions to config_parser.c This will allow the moved functions to be used in the server side configuration parser implementation. Signed-off-by: Anderson Toshiyuki Sasaki Reviewed-by: Andreas Schneider CVE:CVE-2023-6004 Upstream-Status: Backport [https://git.libssh.org/projects/libssh.git/commit/?id=79049981a513f9a10fac0f153e9b0b588326021f] Signed-off-by: nikhil r Comment: Removed 1 hunk from config.c as the function was intoduced in later version --- include/libssh/config_parser.h | 57 ++++++++ src/CMakeLists.txt | 1 + src/config.c | 216 +----------------------------- src/config_parser.c | 238 +++++++++++++++++++++++++++++++++ 4 files changed, 297 insertions(+), 215 deletions(-) create mode 100644 include/libssh/config_parser.h create mode 100644 src/config_parser.c diff --git a/include/libssh/config_parser.h b/include/libssh/config_parser.h new file mode 100644 index 00000000..e974917c --- /dev/null +++ b/include/libssh/config_parser.h @@ -0,0 +1,57 @@ +/* + * config_parser.h - Common configuration file parser functions + * + * This file is part of the SSH Library + * + * Copyright (c) 2019 by Red Hat, Inc. + * + * Author: Anderson Toshiyuki Sasaki + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#ifndef CONFIG_PARSER_H_ +#define CONFIG_PARSER_H_ + +char *ssh_config_get_cmd(char **str); + +char *ssh_config_get_token(char **str); + +long ssh_config_get_long(char **str, long notfound); + +const char *ssh_config_get_str_tok(char **str, const char *def); + +int ssh_config_get_yesno(char **str, int notfound); + +/* @brief Parse SSH URI in format [user@]host[:port] from the given string + * + * @param[in] tok String to parse + * @param[out] username Pointer to the location, where the new username will + * be stored or NULL if we do not care about the result. + * @param[out] hostname Pointer to the location, where the new hostname will + * be stored or NULL if we do not care about the result. + * @param[out] port Pointer to the location, where the new port will + * be stored or NULL if we do not care about the result. + * + * @returns SSH_OK if the provided string is in format of SSH URI, + * SSH_ERROR on failure + */ +int ssh_config_parse_uri(const char *tok, + char **username, + char **hostname, + char **port); + +#endif /* LIBSSH_CONFIG_H_ */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fdb53baf..de66f056 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -163,6 +163,7 @@ set(libssh_SRCS external/poly1305.c external/sc25519.c chachapoly.c + config_parser.c ) if (CMAKE_USE_PTHREADS_INIT) diff --git a/src/config.c b/src/config.c index 85ecd96a..4268545d 100644 --- a/src/config.c +++ b/src/config.c @@ -22,7 +22,7 @@ */ #include "config.h" - +#include "libssh/config_parser.h" #include #include #include @@ -228,102 +228,6 @@ static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) { return SOC_UNKNOWN; } -static char *ssh_config_get_cmd(char **str) { - register char *c; - char *r; - - /* Ignore leading spaces */ - for (c = *str; *c; c++) { - if (! isblank(*c)) { - break; - } - } - - if (*c == '\"') { - for (r = ++c; *c; c++) { - if (*c == '\"') { - *c = '\0'; - goto out; - } - } - } - - for (r = c; *c; c++) { - if (*c == '\n') { - *c = '\0'; - goto out; - } - } - -out: - *str = c + 1; - - return r; -} - -static char *ssh_config_get_token(char **str) { - register char *c; - char *r; - - c = ssh_config_get_cmd(str); - - for (r = c; *c; c++) { - if (isblank(*c) || *c == '=') { - *c = '\0'; - goto out; - } - } - -out: - *str = c + 1; - - return r; -} - -static long ssh_config_get_long(char **str, long notfound) { - char *p, *endp; - long i; - - p = ssh_config_get_token(str); - if (p && *p) { - i = strtol(p, &endp, 10); - if (p == endp) { - return notfound; - } - return i; - } - - return notfound; -} - -static const char *ssh_config_get_str_tok(char **str, const char *def) { - char *p; - - p = ssh_config_get_token(str); - if (p && *p) { - return p; - } - - return def; -} - -static int ssh_config_get_yesno(char **str, int notfound) { - const char *p; - - p = ssh_config_get_str_tok(str, NULL); - if (p == NULL) { - return notfound; - } - - if (strncasecmp(p, "yes", 3) == 0) { - return 1; - } else if (strncasecmp(p, "no", 2) == 0) { - return 0; - } - - return notfound; -} - static void local_parse_file(ssh_session session, const char *filename, int *parsing, int seen[]) { FILE *f; char line[MAX_LINE_SIZE] = {0}; diff --git a/src/config_parser.c b/src/config_parser.c new file mode 100644 index 00000000..ae2aa2c8 --- /dev/null +++ b/src/config_parser.c @@ -0,0 +1,238 @@ +/* + * config_parser.c - Common configuration file parser functions + * + * This file is part of the SSH Library + * + * Copyright (c) 2009-2013 by Andreas Schneider + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "libssh/config_parser.h" +#include "libssh/priv.h" + +char *ssh_config_get_cmd(char **str) +{ + register char *c; + char *r; + + /* Ignore leading spaces */ + for (c = *str; *c; c++) { + if (! isblank(*c)) { + break; + } + } + + if (*c == '\"') { + for (r = ++c; *c; c++) { + if (*c == '\"') { + *c = '\0'; + goto out; + } + } + } + + for (r = c; *c; c++) { + if (*c == '\n') { + *c = '\0'; + goto out; + } + } + +out: + *str = c + 1; + + return r; +} + +char *ssh_config_get_token(char **str) +{ + register char *c; + char *r; + + c = ssh_config_get_cmd(str); + + for (r = c; *c; c++) { + if (isblank(*c) || *c == '=') { + *c = '\0'; + goto out; + } + } + +out: + *str = c + 1; + + return r; +} + +long ssh_config_get_long(char **str, long notfound) +{ + char *p, *endp; + long i; + + p = ssh_config_get_token(str); + if (p && *p) { + i = strtol(p, &endp, 10); + if (p == endp) { + return notfound; + } + return i; + } + + return notfound; +} + +const char *ssh_config_get_str_tok(char **str, const char *def) +{ + char *p; + + p = ssh_config_get_token(str); + if (p && *p) { + return p; + } + + return def; +} + +int ssh_config_get_yesno(char **str, int notfound) +{ + const char *p; + + p = ssh_config_get_str_tok(str, NULL); + if (p == NULL) { + return notfound; + } + + if (strncasecmp(p, "yes", 3) == 0) { + return 1; + } else if (strncasecmp(p, "no", 2) == 0) { + return 0; + } + + return notfound; +} + +int ssh_config_parse_uri(const char *tok, + char **username, + char **hostname, + char **port) +{ + char *endp = NULL; + long port_n; + + /* Sanitize inputs */ + if (username != NULL) { + *username = NULL; + } + if (hostname != NULL) { + *hostname = NULL; + } + if (port != NULL) { + *port = NULL; + } + + /* Username part (optional) */ + endp = strchr(tok, '@'); + if (endp != NULL) { + /* Zero-length username is not valid */ + if (tok == endp) { + goto error; + } + if (username != NULL) { + *username = strndup(tok, endp - tok); + if (*username == NULL) { + goto error; + } + } + tok = endp + 1; + /* If there is second @ character, this does not look like our URI */ + endp = strchr(tok, '@'); + if (endp != NULL) { + goto error; + } + } + + /* Hostname */ + if (*tok == '[') { + /* IPv6 address is enclosed with square brackets */ + tok++; + endp = strchr(tok, ']'); + if (endp == NULL) { + goto error; + } + } else { + /* Hostnames or aliases expand to the last colon or to the end */ + endp = strrchr(tok, ':'); + if (endp == NULL) { + endp = strchr(tok, '\0'); + } + } + if (tok == endp) { + /* Zero-length hostnames are not valid */ + goto error; + } + if (hostname != NULL) { + *hostname = strndup(tok, endp - tok); + if (*hostname == NULL) { + goto error; + } + } + /* Skip also the closing bracket */ + if (*endp == ']') { + endp++; + } + + /* Port (optional) */ + if (*endp != '\0') { + char *port_end = NULL; + + /* Verify the port is valid positive number */ + port_n = strtol(endp + 1, &port_end, 10); + if (port_n < 1 || *port_end != '\0') { + SSH_LOG(SSH_LOG_WARN, "Failed to parse port number." + " The value '%ld' is invalid or there are some" + " trailing characters: '%s'", port_n, port_end); + goto error; + } + if (port != NULL) { + *port = strdup(endp + 1); + if (*port == NULL) { + goto error; + } + } + } + + return SSH_OK; + +error: + if (username != NULL) { + SAFE_FREE(*username); + } + if (hostname != NULL) { + SAFE_FREE(*hostname); + } + if (port != NULL) { + SAFE_FREE(*port); + } + return SSH_ERROR; +} -- 2.25.1