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;
|
int control_master;
|
||||||
char *control_path;
|
char *control_path;
|
||||||
int address_family;
|
int address_family;
|
||||||
|
char *originalhost; /* user-supplied host for config matching */
|
||||||
|
bool config_hostname_only; /* config hostname path: update host only,
|
||||||
|
not originalhost */
|
||||||
} opts;
|
} opts;
|
||||||
|
|
||||||
/* server options */
|
/* server options */
|
||||||
|
|||||||
@@ -582,9 +582,8 @@ int ssh_connect(ssh_session session)
|
|||||||
session->client = 1;
|
session->client = 1;
|
||||||
|
|
||||||
if (session->opts.fd == SSH_INVALID_SOCKET &&
|
if (session->opts.fd == SSH_INVALID_SOCKET &&
|
||||||
session->opts.host == NULL &&
|
session->opts.originalhost == NULL &&
|
||||||
session->opts.ProxyCommand == NULL)
|
session->opts.ProxyCommand == NULL) {
|
||||||
{
|
|
||||||
ssh_set_error(session, SSH_FATAL, "Hostname required");
|
ssh_set_error(session, SSH_FATAL, "Hostname required");
|
||||||
return SSH_ERROR;
|
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) {
|
} else if (parse_entry) {
|
||||||
/* We actually care only about the first item */
|
/* 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) {
|
if (rv != SSH_OK) {
|
||||||
ssh_set_error_invalid(session);
|
ssh_set_error_invalid(session);
|
||||||
goto out;
|
goto out;
|
||||||
@@ -1041,20 +1046,20 @@ static int ssh_config_parse_line_internal(ssh_session session,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MATCH_ORIGINALHOST:
|
case MATCH_ORIGINALHOST:
|
||||||
/* Skip one argument */
|
/* Here we match only one argument */
|
||||||
p = ssh_config_get_str_tok(&s, NULL);
|
p = ssh_config_get_str_tok(&s, NULL);
|
||||||
if (p == NULL || p[0] == '\0') {
|
if (p == NULL || p[0] == '\0') {
|
||||||
SSH_LOG(SSH_LOG_TRACE, "line %d: Match keyword "
|
ssh_set_error(session,
|
||||||
"'%s' requires argument", count, p2);
|
SSH_FATAL,
|
||||||
|
"line %d: ERROR - Match originalhost keyword "
|
||||||
|
"requires argument",
|
||||||
|
count);
|
||||||
SAFE_FREE(x);
|
SAFE_FREE(x);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
result &=
|
||||||
|
ssh_config_match(session->opts.originalhost, p, negate);
|
||||||
args++;
|
args++;
|
||||||
SSH_LOG(SSH_LOG_TRACE,
|
|
||||||
"line %d: Unsupported Match keyword '%s', ignoring",
|
|
||||||
count,
|
|
||||||
p2);
|
|
||||||
result = 0;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MATCH_HOST:
|
case MATCH_HOST:
|
||||||
@@ -1067,7 +1072,11 @@ static int ssh_config_parse_line_internal(ssh_session session,
|
|||||||
SAFE_FREE(x);
|
SAFE_FREE(x);
|
||||||
return -1;
|
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++;
|
args++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1155,7 +1164,9 @@ static int ssh_config_parse_line_internal(ssh_session session,
|
|||||||
int ok = 0, result = -1;
|
int ok = 0, result = -1;
|
||||||
|
|
||||||
*parsing = 0;
|
*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);
|
for (p = ssh_config_get_str_tok(&s, NULL);
|
||||||
p != NULL && p[0] != '\0';
|
p != NULL && p[0] != '\0';
|
||||||
p = ssh_config_get_str_tok(&s, NULL)) {
|
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) {
|
if (z == NULL) {
|
||||||
z = strdup(p);
|
z = strdup(p);
|
||||||
}
|
}
|
||||||
|
session->opts.config_hostname_only = true;
|
||||||
ssh_options_set(session, SSH_OPTIONS_HOST, z);
|
ssh_options_set(session, SSH_OPTIONS_HOST, z);
|
||||||
|
session->opts.config_hostname_only = false;
|
||||||
free(z);
|
free(z);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1432,6 +1432,8 @@ char *ssh_path_expand_escape(ssh_session session, const char *s)
|
|||||||
case 'h':
|
case 'h':
|
||||||
if (session->opts.host) {
|
if (session->opts.host) {
|
||||||
x = strdup(session->opts.host);
|
x = strdup(session->opts.host);
|
||||||
|
} else if (session->opts.originalhost) {
|
||||||
|
x = strdup(session->opts.originalhost);
|
||||||
} else {
|
} else {
|
||||||
ssh_set_error(session, SSH_FATAL, "Cannot expand host");
|
ssh_set_error(session, SSH_FATAL, "Cannot expand host");
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.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) {
|
if (src->opts.bindaddr != NULL) {
|
||||||
new->opts.bindaddr = strdup(src->opts.bindaddr);
|
new->opts.bindaddr = strdup(src->opts.bindaddr);
|
||||||
if (new->opts.bindaddr == NULL) {
|
if (new->opts.bindaddr == NULL) {
|
||||||
@@ -718,18 +727,52 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
|||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
char *username = NULL, *hostname = NULL;
|
char *username = NULL, *hostname = NULL;
|
||||||
rc = ssh_config_parse_uri(value, &username, &hostname, NULL, true, true);
|
char *strict_hostname = NULL;
|
||||||
if (rc != SSH_OK) {
|
|
||||||
|
/* 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);
|
ssh_set_error_invalid(session);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Non-strict passed: set username and originalhost */
|
||||||
if (username != NULL) {
|
if (username != NULL) {
|
||||||
SAFE_FREE(session->opts.username);
|
SAFE_FREE(session->opts.username);
|
||||||
session->opts.username = 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);
|
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;
|
break;
|
||||||
@@ -1646,7 +1689,8 @@ int ssh_options_get(ssh_session session, enum ssh_options_e type, char** value)
|
|||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case SSH_OPTIONS_HOST:
|
case SSH_OPTIONS_HOST:
|
||||||
src = session->opts.host;
|
src = session->opts.host ? session->opts.host
|
||||||
|
: session->opts.originalhost;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SSH_OPTIONS_USER:
|
case SSH_OPTIONS_USER:
|
||||||
@@ -1980,7 +2024,7 @@ int ssh_options_parse_config(ssh_session session, const char *filename)
|
|||||||
if (session == NULL) {
|
if (session == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (session->opts.host == NULL) {
|
if (session->opts.originalhost == NULL) {
|
||||||
ssh_set_error_invalid(session);
|
ssh_set_error_invalid(session);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -406,6 +406,7 @@ void ssh_free(ssh_session session)
|
|||||||
SAFE_FREE(session->opts.bindaddr);
|
SAFE_FREE(session->opts.bindaddr);
|
||||||
SAFE_FREE(session->opts.username);
|
SAFE_FREE(session->opts.username);
|
||||||
SAFE_FREE(session->opts.host);
|
SAFE_FREE(session->opts.host);
|
||||||
|
SAFE_FREE(session->opts.originalhost);
|
||||||
SAFE_FREE(session->opts.homedir);
|
SAFE_FREE(session->opts.homedir);
|
||||||
SAFE_FREE(session->opts.sshdir);
|
SAFE_FREE(session->opts.sshdir);
|
||||||
SAFE_FREE(session->opts.knownhosts);
|
SAFE_FREE(session->opts.knownhosts);
|
||||||
|
|||||||
Reference in New Issue
Block a user