mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-03-24 20:40:09 +09:00
Implement originalhost/host separation and Match support
Signed-off-by: Rui Li <ruili3422@gmail.com> Reviewed-by: Jakub Jelen <jjelen@redhat.com>
This commit is contained in:
@@ -286,6 +286,9 @@ struct ssh_session_struct {
|
||||
int control_master;
|
||||
char *control_path;
|
||||
int address_family;
|
||||
char *originalhost; /* user-supplied host for config matching */
|
||||
bool config_hostname_only; /* config hostname path: update host only,
|
||||
not originalhost */
|
||||
} opts;
|
||||
|
||||
/* server options */
|
||||
|
||||
@@ -582,9 +582,8 @@ int ssh_connect(ssh_session session)
|
||||
session->client = 1;
|
||||
|
||||
if (session->opts.fd == SSH_INVALID_SOCKET &&
|
||||
session->opts.host == NULL &&
|
||||
session->opts.ProxyCommand == NULL)
|
||||
{
|
||||
session->opts.originalhost == NULL &&
|
||||
session->opts.ProxyCommand == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Hostname required");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
35
src/config.c
35
src/config.c
@@ -567,7 +567,12 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
|
||||
}
|
||||
} else if (parse_entry) {
|
||||
/* We actually care only about the first item */
|
||||
rv = ssh_config_parse_uri(cp, &username, &hostname, &port, false, false);
|
||||
rv = ssh_config_parse_uri(cp,
|
||||
&username,
|
||||
&hostname,
|
||||
&port,
|
||||
false,
|
||||
false);
|
||||
if (rv != SSH_OK) {
|
||||
ssh_set_error_invalid(session);
|
||||
goto out;
|
||||
@@ -1041,20 +1046,20 @@ static int ssh_config_parse_line_internal(ssh_session session,
|
||||
break;
|
||||
|
||||
case MATCH_ORIGINALHOST:
|
||||
/* Skip one argument */
|
||||
/* Here we match only one argument */
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
SSH_LOG(SSH_LOG_TRACE, "line %d: Match keyword "
|
||||
"'%s' requires argument", count, p2);
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"line %d: ERROR - Match originalhost keyword "
|
||||
"requires argument",
|
||||
count);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
result &=
|
||||
ssh_config_match(session->opts.originalhost, p, negate);
|
||||
args++;
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"line %d: Unsupported Match keyword '%s', ignoring",
|
||||
count,
|
||||
p2);
|
||||
result = 0;
|
||||
break;
|
||||
|
||||
case MATCH_HOST:
|
||||
@@ -1067,7 +1072,11 @@ static int ssh_config_parse_line_internal(ssh_session session,
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
result &= ssh_config_match(session->opts.host, p, negate);
|
||||
result &= ssh_config_match(session->opts.host
|
||||
? session->opts.host
|
||||
: session->opts.originalhost,
|
||||
p,
|
||||
negate);
|
||||
args++;
|
||||
break;
|
||||
|
||||
@@ -1155,7 +1164,9 @@ static int ssh_config_parse_line_internal(ssh_session session,
|
||||
int ok = 0, result = -1;
|
||||
|
||||
*parsing = 0;
|
||||
lowerhost = (session->opts.host) ? ssh_lowercase(session->opts.host) : NULL;
|
||||
lowerhost = (session->opts.originalhost)
|
||||
? ssh_lowercase(session->opts.originalhost)
|
||||
: NULL;
|
||||
for (p = ssh_config_get_str_tok(&s, NULL);
|
||||
p != NULL && p[0] != '\0';
|
||||
p = ssh_config_get_str_tok(&s, NULL)) {
|
||||
@@ -1182,7 +1193,9 @@ static int ssh_config_parse_line_internal(ssh_session session,
|
||||
if (z == NULL) {
|
||||
z = strdup(p);
|
||||
}
|
||||
session->opts.config_hostname_only = true;
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, z);
|
||||
session->opts.config_hostname_only = false;
|
||||
free(z);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1432,6 +1432,8 @@ char *ssh_path_expand_escape(ssh_session session, const char *s)
|
||||
case 'h':
|
||||
if (session->opts.host) {
|
||||
x = strdup(session->opts.host);
|
||||
} else if (session->opts.originalhost) {
|
||||
x = strdup(session->opts.originalhost);
|
||||
} else {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot expand host");
|
||||
free(buf);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -106,6 +107,14 @@ int ssh_options_copy(ssh_session src, ssh_session *dest)
|
||||
}
|
||||
}
|
||||
|
||||
if (src->opts.originalhost != NULL) {
|
||||
new->opts.originalhost = strdup(src->opts.originalhost);
|
||||
if (new->opts.originalhost == NULL) {
|
||||
ssh_free(new);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (src->opts.bindaddr != NULL) {
|
||||
new->opts.bindaddr = strdup(src->opts.bindaddr);
|
||||
if (new->opts.bindaddr == NULL) {
|
||||
@@ -718,18 +727,52 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
||||
return -1;
|
||||
} else {
|
||||
char *username = NULL, *hostname = NULL;
|
||||
rc = ssh_config_parse_uri(value, &username, &hostname, NULL, true, true);
|
||||
if (rc != SSH_OK) {
|
||||
char *strict_hostname = NULL;
|
||||
|
||||
/* Non-strict parse: reject shell metacharacters */
|
||||
rc = ssh_config_parse_uri(value,
|
||||
&username,
|
||||
&hostname,
|
||||
NULL,
|
||||
true,
|
||||
false);
|
||||
if (rc != SSH_OK || hostname == NULL) {
|
||||
SAFE_FREE(username);
|
||||
SAFE_FREE(hostname);
|
||||
ssh_set_error_invalid(session);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Non-strict passed: set username and originalhost */
|
||||
if (username != NULL) {
|
||||
SAFE_FREE(session->opts.username);
|
||||
session->opts.username = username;
|
||||
}
|
||||
if (hostname != NULL) {
|
||||
if (!session->opts.config_hostname_only) {
|
||||
SAFE_FREE(session->opts.originalhost);
|
||||
session->opts.originalhost = hostname;
|
||||
} else {
|
||||
SAFE_FREE(hostname);
|
||||
}
|
||||
|
||||
/* Strict parse: set host only if valid hostname or IP */
|
||||
rc = ssh_config_parse_uri(value,
|
||||
NULL,
|
||||
&strict_hostname,
|
||||
NULL,
|
||||
true,
|
||||
true);
|
||||
if (rc != SSH_OK || strict_hostname == NULL) {
|
||||
SAFE_FREE(session->opts.host);
|
||||
session->opts.host = hostname;
|
||||
SAFE_FREE(strict_hostname);
|
||||
if (session->opts.config_hostname_only) {
|
||||
/* Config path: Hostname must be valid */
|
||||
ssh_set_error_invalid(session);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
SAFE_FREE(session->opts.host);
|
||||
session->opts.host = strict_hostname;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1646,7 +1689,8 @@ int ssh_options_get(ssh_session session, enum ssh_options_e type, char** value)
|
||||
switch(type)
|
||||
{
|
||||
case SSH_OPTIONS_HOST:
|
||||
src = session->opts.host;
|
||||
src = session->opts.host ? session->opts.host
|
||||
: session->opts.originalhost;
|
||||
break;
|
||||
|
||||
case SSH_OPTIONS_USER:
|
||||
@@ -1980,7 +2024,7 @@ int ssh_options_parse_config(ssh_session session, const char *filename)
|
||||
if (session == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (session->opts.host == NULL) {
|
||||
if (session->opts.originalhost == NULL) {
|
||||
ssh_set_error_invalid(session);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -406,6 +406,7 @@ void ssh_free(ssh_session session)
|
||||
SAFE_FREE(session->opts.bindaddr);
|
||||
SAFE_FREE(session->opts.username);
|
||||
SAFE_FREE(session->opts.host);
|
||||
SAFE_FREE(session->opts.originalhost);
|
||||
SAFE_FREE(session->opts.homedir);
|
||||
SAFE_FREE(session->opts.sshdir);
|
||||
SAFE_FREE(session->opts.knownhosts);
|
||||
|
||||
Reference in New Issue
Block a user