1
0
mirror of https://git.libssh.org/projects/libssh.git synced 2025-11-26 01:03:15 +03:00

add control master and path option

Signed-off-by: Ahsen Kamal <itsahsenkamal@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
This commit is contained in:
Ahsen Kamal
2023-05-29 17:41:03 +05:30
committed by Jakub Jelen
parent 83ce7bfa59
commit 15dbf3ace7
6 changed files with 130 additions and 2 deletions

View File

@@ -63,6 +63,8 @@ enum ssh_config_opcode_e {
SOC_REKEYLIMIT, SOC_REKEYLIMIT,
SOC_IDENTITYAGENT, SOC_IDENTITYAGENT,
SOC_IDENTITIESONLY, SOC_IDENTITIESONLY,
SOC_CONTROLMASTER,
SOC_CONTROLPATH,
SOC_MAX /* Keep this one last in the list */ SOC_MAX /* Keep this one last in the list */
}; };

View File

@@ -360,6 +360,14 @@ enum {
/** @} */ /** @} */
enum ssh_control_master_options_e {
SSH_CONTROL_MASTER_NO,
SSH_CONTROL_MASTER_AUTO,
SSH_CONTROL_MASTER_YES,
SSH_CONTROL_MASTER_ASK,
SSH_CONTROL_MASTER_AUTOASK
};
enum ssh_options_e { enum ssh_options_e {
SSH_OPTIONS_HOST, SSH_OPTIONS_HOST,
SSH_OPTIONS_PORT, SSH_OPTIONS_PORT,
@@ -405,6 +413,8 @@ enum ssh_options_e {
SSH_OPTIONS_RSA_MIN_SIZE, SSH_OPTIONS_RSA_MIN_SIZE,
SSH_OPTIONS_IDENTITY_AGENT, SSH_OPTIONS_IDENTITY_AGENT,
SSH_OPTIONS_IDENTITIES_ONLY, SSH_OPTIONS_IDENTITIES_ONLY,
SSH_OPTIONS_CONTROL_MASTER,
SSH_OPTIONS_CONTROL_PATH,
}; };
enum { enum {

View File

@@ -106,6 +106,7 @@ enum ssh_pending_call_e {
#define SSH_OPT_EXP_FLAG_GLOBAL_KNOWNHOSTS 0x2 #define SSH_OPT_EXP_FLAG_GLOBAL_KNOWNHOSTS 0x2
#define SSH_OPT_EXP_FLAG_PROXYCOMMAND 0x4 #define SSH_OPT_EXP_FLAG_PROXYCOMMAND 0x4
#define SSH_OPT_EXP_FLAG_IDENTITY 0x8 #define SSH_OPT_EXP_FLAG_IDENTITY 0x8
#define SSH_OPT_EXP_FLAG_CONTROL_PATH 0x10
/* extensions flags */ /* extensions flags */
/* negotiation enabled */ /* negotiation enabled */
@@ -260,6 +261,8 @@ struct ssh_session_struct {
uint32_t rekey_time; uint32_t rekey_time;
int rsa_min_size; int rsa_min_size;
bool identities_only; bool identities_only;
int control_master;
char *control_path;
} opts; } opts;
/* counters */ /* counters */
ssh_counter socket_counter; ssh_counter socket_counter;

View File

@@ -127,9 +127,9 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
{ "verifyhostkeydns", SOC_UNSUPPORTED}, { "verifyhostkeydns", SOC_UNSUPPORTED},
{ "visualhostkey", SOC_UNSUPPORTED}, { "visualhostkey", SOC_UNSUPPORTED},
{ "clearallforwardings", SOC_NA}, { "clearallforwardings", SOC_NA},
{ "controlmaster", SOC_NA}, { "controlmaster", SOC_CONTROLMASTER},
{ "controlpersist", SOC_NA}, { "controlpersist", SOC_NA},
{ "controlpath", SOC_NA}, { "controlpath", SOC_CONTROLPATH},
{ "dynamicforward", SOC_NA}, { "dynamicforward", SOC_NA},
{ "escapechar", SOC_NA}, { "escapechar", SOC_NA},
{ "exitonforwardfailure", SOC_NA}, { "exitonforwardfailure", SOC_NA},
@@ -1186,6 +1186,38 @@ ssh_config_parse_line(ssh_session session,
ssh_options_set(session, SSH_OPTIONS_IDENTITIES_ONLY, &b); ssh_options_set(session, SSH_OPTIONS_IDENTITIES_ONLY, &b);
} }
break; break;
case SOC_CONTROLMASTER:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
int value = -1;
if (strcasecmp(p, "auto") == 0) {
value = SSH_CONTROL_MASTER_AUTO;
} else if (strcasecmp(p, "yes") == 0) {
value = SSH_CONTROL_MASTER_YES;
} else if (strcasecmp(p, "no") == 0) {
value = SSH_CONTROL_MASTER_NO;
} else if (strcasecmp(p, "autoask") == 0) {
value = SSH_CONTROL_MASTER_AUTOASK;
} else if (strcasecmp(p, "ask") == 0) {
value = SSH_CONTROL_MASTER_ASK;
}
if (value != -1) {
ssh_options_set(session, SSH_OPTIONS_CONTROL_MASTER, &value);
}
}
break;
case SOC_CONTROLPATH:
p = ssh_config_get_str_tok(&s, NULL);
if (p == NULL) {
SAFE_FREE(x);
return -1;
}
if (*parsing) {
ssh_options_set(session, SSH_OPTIONS_CONTROL_PATH, p);
}
break;
default: default:
ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d", ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d",
opcode); opcode);

View File

@@ -204,6 +204,14 @@ int ssh_options_copy(ssh_session src, ssh_session *dest)
} }
} }
if (src->opts.control_path != NULL) {
new->opts.control_path = strdup(src->opts.control_path);
if (new->opts.control_path == NULL) {
ssh_free(new);
return -1;
}
}
memcpy(new->opts.options_seen, src->opts.options_seen, memcpy(new->opts.options_seen, src->opts.options_seen,
sizeof(new->opts.options_seen)); sizeof(new->opts.options_seen));
@@ -217,6 +225,7 @@ int ssh_options_copy(ssh_session src, ssh_session *dest)
new->opts.flags = src->opts.flags; new->opts.flags = src->opts.flags;
new->opts.nodelay = src->opts.nodelay; new->opts.nodelay = src->opts.nodelay;
new->opts.config_processed = src->opts.config_processed; new->opts.config_processed = src->opts.config_processed;
new->opts.control_master = src->opts.control_master;
new->common.log_verbosity = src->common.log_verbosity; new->common.log_verbosity = src->common.log_verbosity;
new->common.callbacks = src->common.callbacks; new->common.callbacks = src->common.callbacks;
@@ -536,6 +545,26 @@ int ssh_options_set_algo(ssh_session session,
* offers more. * offers more.
* (bool) * (bool)
* *
* - SSH_OPTIONS_CONTROL_MASTER
* Set the option to enable the sharing of multiple sessions over a
* single network connection using connection multiplexing.
*
* The possible options are among the following:
* - SSH_CONTROL_MASTER_AUTO: enable connection sharing if possible
* - SSH_CONTROL_MASTER_YES: enable connection sharing unconditionally
* - SSH_CONTROL_MASTER_ASK: ask for confirmation if connection sharing is to be enabled
* - SSH_CONTROL_MASTER_AUTOASK: enable connection sharing if possible,
* but ask for confirmation
* - SSH_CONTROL_MASTER_NO: disable connection sharing unconditionally
*
* The default is SSH_CONTROL_MASTER_NO.
*
* - SSH_OPTIONS_CONTROL_PATH
* Set the path to the control socket used for connection sharing.
* Set to "none" to disable connection sharing.
* (const char *)
*
*
* @param value The value to set. This is a generic pointer and the * @param value The value to set. This is a generic pointer and the
* datatype which is used should be set according to the * datatype which is used should be set according to the
* type set. * type set.
@@ -1173,6 +1202,37 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
session->opts.identities_only = *x; session->opts.identities_only = *x;
} }
break; break;
case SSH_OPTIONS_CONTROL_MASTER:
if (value == NULL) {
ssh_set_error_invalid(session);
return -1;
} else {
int *x = (int *) value;
if (*x < SSH_CONTROL_MASTER_NO || *x > SSH_CONTROL_MASTER_AUTOASK) {
ssh_set_error_invalid(session);
return -1;
}
session->opts.control_master = *x;
}
break;
case SSH_OPTIONS_CONTROL_PATH:
v = value;
if (v == NULL || v[0] == '\0') {
ssh_set_error_invalid(session);
return -1;
} else {
SAFE_FREE(session->opts.control_path);
rc = strcasecmp(v, "none");
if (rc != 0) {
session->opts.control_path = ssh_path_expand_tilde(v);
if (session->opts.control_path == NULL) {
ssh_set_error_oom(session);
return -1;
}
session->opts.exp_flags &= ~SSH_OPT_EXP_FLAG_CONTROL_PATH;
}
}
break;
default: default:
ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type); ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
return -1; return -1;
@@ -1247,6 +1307,9 @@ int ssh_options_get_port(ssh_session session, unsigned int* port_target) {
* - SSH_OPTIONS_KNOWNHOSTS: * - SSH_OPTIONS_KNOWNHOSTS:
* Get the path to the known_hosts file being used. * Get the path to the known_hosts file being used.
* *
* - SSH_OPTIONS_CONTROL_PATH:
* Get the path to the control socket being used for connection multiplexing.
*
* @param value The value to get into. As a char**, space will be * @param value The value to get into. As a char**, space will be
* allocated by the function for the value, it is * allocated by the function for the value, it is
* your responsibility to free the memory using * your responsibility to free the memory using
@@ -1301,6 +1364,10 @@ int ssh_options_get(ssh_session session, enum ssh_options_e type, char** value)
src = session->opts.global_knownhosts; src = session->opts.global_knownhosts;
break; break;
} }
case SSH_OPTIONS_CONTROL_PATH: {
src = session->opts.control_path;
break;
}
default: default:
ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type); ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
return SSH_ERROR; return SSH_ERROR;
@@ -1646,6 +1713,18 @@ int ssh_options_apply(ssh_session session)
} }
} }
if ((session->opts.exp_flags & SSH_OPT_EXP_FLAG_CONTROL_PATH) == 0) {
if (session->opts.control_path != NULL) {
tmp = ssh_path_expand_escape(session, session->opts.control_path);
if (tmp == NULL) {
return -1;
}
free(session->opts.control_path);
session->opts.control_path = tmp;
session->opts.exp_flags |= SSH_OPT_EXP_FLAG_CONTROL_PATH;
}
}
for (tmp = ssh_list_pop_head(char *, session->opts.identity_non_exp); for (tmp = ssh_list_pop_head(char *, session->opts.identity_non_exp);
tmp != NULL; tmp != NULL;
tmp = ssh_list_pop_head(char *, session->opts.identity_non_exp)) { tmp = ssh_list_pop_head(char *, session->opts.identity_non_exp)) {

View File

@@ -109,6 +109,7 @@ ssh_session ssh_new(void)
session->opts.compressionlevel = 7; session->opts.compressionlevel = 7;
session->opts.nodelay = 0; session->opts.nodelay = 0;
session->opts.identities_only = false; session->opts.identities_only = false;
session->opts.control_master = SSH_CONTROL_MASTER_NO;
session->opts.flags = SSH_OPT_FLAG_PASSWORD_AUTH | session->opts.flags = SSH_OPT_FLAG_PASSWORD_AUTH |
SSH_OPT_FLAG_PUBKEY_AUTH | SSH_OPT_FLAG_PUBKEY_AUTH |
@@ -320,6 +321,7 @@ void ssh_free(ssh_session session)
SAFE_FREE(session->opts.gss_server_identity); SAFE_FREE(session->opts.gss_server_identity);
SAFE_FREE(session->opts.gss_client_identity); SAFE_FREE(session->opts.gss_client_identity);
SAFE_FREE(session->opts.pubkey_accepted_types); SAFE_FREE(session->opts.pubkey_accepted_types);
SAFE_FREE(session->opts.control_path);
for (i = 0; i < SSH_KEX_METHODS; i++) { for (i = 0; i < SSH_KEX_METHODS; i++) {
if (session->opts.wanted_methods[i]) { if (session->opts.wanted_methods[i]) {