1
0
mirror of https://git.libssh.org/projects/libssh.git synced 2025-07-19 07:03:12 +03:00

Add new options

Pair-Programmed-With: Jakub Jelen <jjelen@redhat.com>
Signed-off-by: Aris Adamantiadis <aris@0xbadc0de.be>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
Aris Adamantiadis
2014-08-03 22:29:49 +02:00
committed by Andreas Schneider
parent 094aa5eb02
commit f818e63f8f
9 changed files with 343 additions and 19 deletions

View File

@ -351,6 +351,11 @@ enum ssh_options_e {
SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS,
SSH_OPTIONS_HMAC_C_S,
SSH_OPTIONS_HMAC_S_C,
SSH_OPTIONS_PASSWORD_AUTH,
SSH_OPTIONS_PUBKEY_AUTH,
SSH_OPTIONS_KBDINT_AUTH,
SSH_OPTIONS_GSSAPI_AUTH,
SSH_OPTIONS_GLOBAL_KNOWNHOSTS
};
enum {

View File

@ -79,6 +79,13 @@ enum ssh_pending_call_e {
/* Don't block at all */
#define SSH_TIMEOUT_NONBLOCKING 0
/* options flags */
/* Authentication with *** allowed */
#define SSH_OPT_FLAG_PASSWORD_AUTH 0x1
#define SSH_OPT_FLAG_PUBKEY_AUTH 0x2
#define SSH_OPT_FLAG_KBDINT_AUTH 0x4
#define SSH_OPT_FLAG_GSSAPI_AUTH 0x8
/* members that are common to ssh_session and ssh_bind */
struct ssh_common_struct {
struct error_struct error;
@ -182,6 +189,7 @@ struct ssh_session_struct {
char *bindaddr; /* bind the client to an ip addr */
char *sshdir;
char *knownhosts;
char *global_knownhosts;
char *wanted_methods[10];
char *ProxyCommand;
char *custombanner;
@ -196,6 +204,7 @@ struct ssh_session_struct {
char *gss_server_identity;
char *gss_client_identity;
int gss_delegate_creds;
int flags;
} opts;
/* counters */
ssh_counter socket_counter;

View File

@ -921,7 +921,10 @@ int ssh_userauth_publickey_auto(ssh_session session,
if (session == NULL) {
return SSH_AUTH_ERROR;
}
if (! (session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH)) {
session->auth_methods &= ~SSH_AUTH_METHOD_PUBLICKEY;
return SSH_AUTH_DENIED;
}
if (session->common.callbacks) {
auth_fn = session->common.callbacks->auth_function;
auth_data = session->common.callbacks->userdata;

View File

@ -36,8 +36,14 @@
#define MAX_LINE_SIZE 1024
enum ssh_config_opcode_e {
/* Unknown opcode */
SOC_UNKNOWN = -3,
/* Known and not applicable to libssh */
SOC_NA = -2,
/* Known but not supported by current libssh version */
SOC_UNSUPPORTED = -1,
SOC_HOST,
SOC_MATCH,
SOC_HOSTNAME,
SOC_PORT,
SOC_USERNAME,
@ -53,6 +59,17 @@ enum ssh_config_opcode_e {
SOC_GSSAPICLIENTIDENTITY,
SOC_GSSAPIDELEGATECREDENTIALS,
SOC_INCLUDE,
SOC_BINDADDRESS,
SOC_CONNECTTIMEOUT,
SOC_GLOBALKNOWNHOSTSFILE,
SOC_LOGLEVEL,
SOC_HOSTKEYALGORITHMS,
SOC_KEXALGORITHMS,
SOC_MAC,
SOC_GSSAPIAUTHENTICATION,
SOC_KBDINTERACTIVEAUTHENTICATION,
SOC_PASSWORDAUTHENTICATION,
SOC_PUBKEYAUTHENTICATION,
SOC_END /* Keep this one last in the list */
};
@ -64,6 +81,7 @@ struct ssh_config_keyword_table_s {
static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
{ "host", SOC_HOST },
{ "match", SOC_MATCH },
{ "hostname", SOC_HOSTNAME },
{ "port", SOC_PORT },
{ "user", SOC_USERNAME },
@ -79,7 +97,76 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
{ "gssapiserveridentity", SOC_GSSAPICLIENTIDENTITY },
{ "gssapidelegatecredentials", SOC_GSSAPIDELEGATECREDENTIALS },
{ "include", SOC_INCLUDE },
{ NULL, SOC_UNSUPPORTED }
{ "bindaddress", SOC_BINDADDRESS},
{ "connecttimeout", SOC_CONNECTTIMEOUT},
{ "globalknownhostsfile", SOC_GLOBALKNOWNHOSTSFILE},
{ "loglevel", SOC_LOGLEVEL},
{ "hostkeyalgorithms", SOC_HOSTKEYALGORITHMS},
{ "kexalgorithms", SOC_KEXALGORITHMS},
{ "mac", SOC_MAC},
{ "gssapiauthentication", SOC_GSSAPIAUTHENTICATION},
{ "kbdinteractiveauthentication", SOC_KBDINTERACTIVEAUTHENTICATION},
{ "passwordauthentication", SOC_PASSWORDAUTHENTICATION},
{ "pubkeyauthentication", SOC_PUBKEYAUTHENTICATION},
{ "addressfamily", SOC_UNSUPPORTED},
{ "batchmode", SOC_UNSUPPORTED},
{ "canonicaldomains", SOC_UNSUPPORTED},
{ "canonicalizefallbacklocal", SOC_UNSUPPORTED},
{ "canonicalizehostname", SOC_UNSUPPORTED},
{ "canonicalizemaxdots", SOC_UNSUPPORTED},
{ "canonicalizepermittedcnames", SOC_UNSUPPORTED},
{ "challengeresponseauthentication", SOC_UNSUPPORTED},
{ "checkhostip", SOC_UNSUPPORTED},
{ "cipher", SOC_UNSUPPORTED},
{ "compressionlevel", SOC_UNSUPPORTED},
{ "connectionattempts", SOC_UNSUPPORTED},
{ "enablesshkeysign", SOC_UNSUPPORTED},
{ "forwardagent", SOC_UNSUPPORTED},
{ "gssapikeyexchange", SOC_UNSUPPORTED},
{ "gssapirenewalforcesrekey", SOC_UNSUPPORTED},
{ "gssapitrustdns", SOC_UNSUPPORTED},
{ "hashknownhosts", SOC_UNSUPPORTED},
{ "hostbasedauthentication", SOC_UNSUPPORTED},
{ "hostkeyalias", SOC_UNSUPPORTED},
{ "identitiesonly", SOC_UNSUPPORTED},
{ "ipqos", SOC_UNSUPPORTED},
{ "kbdinteractivedevices", SOC_UNSUPPORTED},
{ "nohostauthenticationforlocalhost", SOC_UNSUPPORTED},
{ "numberofpasswordprompts", SOC_UNSUPPORTED},
{ "pkcs11provider", SOC_UNSUPPORTED},
{ "preferredauthentications", SOC_UNSUPPORTED},
{ "proxyusefdpass", SOC_UNSUPPORTED},
{ "rekeylimit", SOC_UNSUPPORTED},
{ "rhostsrsaauthentication", SOC_UNSUPPORTED},
{ "rsaauthentication", SOC_UNSUPPORTED},
{ "serveralivecountmax", SOC_UNSUPPORTED},
{ "serveraliveinterval", SOC_UNSUPPORTED},
{ "tcpkeepalive", SOC_UNSUPPORTED},
{ "useprivilegedport", SOC_UNSUPPORTED},
{ "verifyhostkeydns", SOC_UNSUPPORTED},
{ "visualhostkey", SOC_UNSUPPORTED},
{ "clearallforwardings", SOC_NA},
{ "controlmaster", SOC_NA},
{ "controlpersist", SOC_NA},
{ "controlpath", SOC_NA},
{ "dynamicforward", SOC_NA},
{ "escapechar", SOC_NA},
{ "exitonforwardfailure", SOC_NA},
{ "forwardx11", SOC_NA},
{ "forwardx11timeout", SOC_NA},
{ "forwardx11trusted", SOC_NA},
{ "gatewayports", SOC_NA},
{ "ignoreunknown", SOC_NA},
{ "localcommand", SOC_NA},
{ "localforward", SOC_NA},
{ "permitlocalcommand", SOC_NA},
{ "remoteforward", SOC_NA},
{ "requesttty", SOC_NA},
{ "sendenv", SOC_NA},
{ "tunnel", SOC_NA},
{ "tunneldevice", SOC_NA},
{ "xauthlocation", SOC_NA},
{ NULL, SOC_UNKNOWN }
};
static int ssh_config_parse_line(ssh_session session, const char *line,
@ -94,7 +181,7 @@ static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
}
}
return SOC_UNSUPPORTED;
return SOC_UNKNOWN;
}
static char *ssh_config_get_cmd(char **str) {
@ -297,13 +384,11 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
}
break;
case SOC_PORT:
if (session->opts.port == 0) {
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
}
}
break;
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
}
break;
case SOC_USERNAME:
if (session->opts.username == NULL) {
p = ssh_config_get_str_tok(&s, NULL);
@ -408,10 +493,101 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
ssh_options_set(session, SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS, &i);
}
break;
case SOC_BINDADDRESS:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_BINDADDR, p);
}
break;
case SOC_CONNECTTIMEOUT:
i = ssh_config_get_int(&s, 0);
if (i >= 0 && *parsing) {
long t = i;
ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &t);
}
break;
case SOC_GLOBALKNOWNHOSTSFILE:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, p);
}
break;
case SOC_LOGLEVEL:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
if (strcasecmp(p, "quiet") == 0) {
ssh_set_log_level(SSH_LOG_NONE);
} else if (strcasecmp(p, "fatal") == 0 ||
strcasecmp(p, "error")== 0 ||
strcasecmp(p, "info") == 0) {
ssh_set_log_level(SSH_LOG_WARN);
} else if (strcasecmp(p, "verbose") == 0) {
ssh_set_log_level(SSH_LOG_INFO);
} else if (strcasecmp(p, "DEBUG") == 0 ||
strcasecmp(p, "DEBUG1") == 0) {
ssh_set_log_level(SSH_LOG_DEBUG);
} else if (strcasecmp(p, "DEBUG2") == 0 ||
strcasecmp(p, "DEBUG3") == 0) {
ssh_set_log_level(SSH_LOG_TRACE);
}
}
break;
case SOC_HOSTKEYALGORITHMS:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, p);
}
break;
case SOC_KEXALGORITHMS:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, p);
}
break;
case SOC_MAC:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_HMAC_C_S, p);
ssh_options_set(session, SSH_OPTIONS_HMAC_S_C, p);
}
break;
case SOC_GSSAPIAUTHENTICATION:
case SOC_KBDINTERACTIVEAUTHENTICATION:
case SOC_PASSWORDAUTHENTICATION:
case SOC_PUBKEYAUTHENTICATION:
i = ssh_config_get_yesno(&s, 0);
if (i>=0 && *parsing) {
switch(opcode){
case SOC_GSSAPIAUTHENTICATION:
ssh_options_set(session, SSH_OPTIONS_GSSAPI_AUTH, &i);
break;
case SOC_KBDINTERACTIVEAUTHENTICATION:
ssh_options_set(session, SSH_OPTIONS_KBDINT_AUTH, &i);
break;
case SOC_PASSWORDAUTHENTICATION:
ssh_options_set(session, SSH_OPTIONS_PASSWORD_AUTH, &i);
break;
case SOC_PUBKEYAUTHENTICATION:
ssh_options_set(session, SSH_OPTIONS_PUBKEY_AUTH, &i);
break;
/* make gcc happy */
default:
break;
}
}
break;
case SOC_NA:
SSH_LOG(SSH_LOG_INFO, "Unapplicable option: %s, line: %d\n",
keyword, count);
break;
case SOC_UNSUPPORTED:
SSH_LOG(SSH_LOG_RARE, "Unsupported option: %s, line: %d",
keyword, count);
break;
case SOC_UNKNOWN:
SSH_LOG(SSH_LOG_WARN, "Unknown option: %s, line: %d\n",
keyword, count);
break;
default:
ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d",
opcode);

View File

@ -410,6 +410,8 @@ int ssh_is_server_known(ssh_session session) {
char *hostport;
const char *type;
int match;
int i=0;
char * files[3];
int ret = SSH_SERVER_NOT_KNOWN;
if (session->opts.knownhosts == NULL) {
@ -444,14 +446,27 @@ int ssh_is_server_known(ssh_session session) {
return SSH_SERVER_ERROR;
}
/* set the list of known hosts */
i = 0;
if (session->opts.global_knownhosts != NULL){
files[i++]=session->opts.global_knownhosts;
}
files[i++] = session->opts.knownhosts;
files[i] = NULL;
i = 0;
do {
tokens = ssh_get_knownhost_line(&file,
session->opts.knownhosts,
files[i],
&type);
/* End of file, return the current state */
/* End of file, return the current state or use next file */
if (tokens == NULL) {
break;
++i;
if(files[i] == NULL)
break;
else
continue;
}
match = match_hashed_host(host, tokens[0]);
if (match == 0){
@ -694,7 +709,8 @@ char **ssh_knownhosts_algorithms(ssh_session session) {
const char *type;
int match;
char **array;
int i=0, j;
char *files[3] = { NULL };
int i=0, j, k;
if (session->opts.knownhosts == NULL) {
if (ssh_options_apply(session) < 0) {
@ -720,13 +736,26 @@ char **ssh_knownhosts_algorithms(ssh_session session) {
return NULL;
}
/* set the list of known hosts */
if (session->opts.global_knownhosts != NULL){
files[i++]=session->opts.global_knownhosts;
}
files[i++] = session->opts.knownhosts;
files[i] = NULL;
k = 0;
i = 0;
do {
tokens = ssh_get_knownhost_line(&file,
session->opts.knownhosts, &type);
tokens = ssh_get_knownhost_line(&file, files[k], &type);
/* End of file, return the current state */
if (tokens == NULL) {
break;
++k;
if (files[k] == NULL) {
break;
} else {
continue;
}
}
match = match_hashed_host(host, tokens[0]);
if (match == 0){

View File

@ -681,6 +681,17 @@ char *ssh_path_expand_tilde(const char *d) {
return r;
}
/** @internal
* @brief expands a string in function of session options
* @param[in] s Format string to expand. Known parameters:
* %d SSH configuration directory (~/.ssh)
* %h target host name
* %u local username
* %l local hostname
* %r remote username
* %p remote port
* @returns Expanded string.
*/
char *ssh_path_expand_escape(ssh_session session, const char *s) {
char host[NI_MAXHOST];
char buf[MAX_BUF_SIZE];
@ -971,7 +982,7 @@ int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout) {
* -2 means user-defined timeout as available in
* session->timeout, session->timeout_usec.
*/
fprintf(stderr, "ssh_timeout_elapsed called with -2. this needs to "
SSH_LOG(SSH_LOG_WARN, "ssh_timeout_elapsed called with -2. this needs to "
"be fixed. please set a breakpoint on %s:%d and "
"fix the caller\n", __FILE__, __LINE__);
return 0;

View File

@ -374,6 +374,28 @@ int ssh_options_set_algo(ssh_session session,
* Set it to specify that GSSAPI should delegate credentials
* to the server (int, 0 = false).
*
* - SSH_OPTIONS_PASSWORD_AUTH
* Set it if password authentication should be used
* in ssh_userauth_auto_pubkey(). (int, 0=false).
* Currently without effect (ssh_userauth_auto_pubkey doesn't use
* password authentication).
*
* - SSH_OPTIONS_PUBKEY_AUTH
* Set it if pubkey authentication should be used
* in ssh_userauth_auto_pubkey(). (int, 0=false).
*
* - SSH_OPTIONS_KBDINT_AUTH
* Set it if keyboard-interactive authentication should be used
* in ssh_userauth_auto_pubkey(). (int, 0=false).
* Currently without effect (ssh_userauth_auto_pubkey doesn't use
* keyboard-interactive authentication).
*
* - SSH_OPTIONS_GSSAPI_AUTH
* Set it if gssapi authentication should be used
* in ssh_userauth_auto_pubkey(). (int, 0=false).
* Currently without effect (ssh_userauth_auto_pubkey doesn't use
* gssapi authentication).
*
* @param value The value to set. This is a generic pointer and the
* datatype which is used should be set according to the
* type set.
@ -385,6 +407,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
const char *v;
char *p, *q;
long int i;
unsigned int u;
int rc;
if (session == NULL) {
@ -574,6 +597,20 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
}
}
break;
case SSH_OPTIONS_GLOBAL_KNOWNHOSTS:
v = value;
SAFE_FREE(session->opts.global_knownhosts);
if (v == NULL || v[0] == '\0') {
ssh_set_error_invalid(session);
return -1;
} else {
session->opts.global_knownhosts = strdup(v);
if (session->opts.global_knownhosts == NULL) {
ssh_set_error_oom(session);
return -1;
}
}
break;
case SSH_OPTIONS_TIMEOUT:
if (value == NULL) {
ssh_set_error_invalid(session);
@ -858,6 +895,30 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
session->opts.gss_delegate_creds = (x & 0xff);
}
break;
case SSH_OPTIONS_PASSWORD_AUTH:
case SSH_OPTIONS_PUBKEY_AUTH:
case SSH_OPTIONS_KBDINT_AUTH:
case SSH_OPTIONS_GSSAPI_AUTH:
u = 0;
if (value == NULL) {
ssh_set_error_invalid(session);
return -1;
} else {
int x = *(int *)value;
u = type == SSH_OPTIONS_PASSWORD_AUTH ?
SSH_OPT_FLAG_PASSWORD_AUTH:
type == SSH_OPTIONS_PUBKEY_AUTH ?
SSH_OPT_FLAG_PUBKEY_AUTH:
type == SSH_OPTIONS_KBDINT_AUTH ?
SSH_OPT_FLAG_KBDINT_AUTH:
SSH_OPT_FLAG_GSSAPI_AUTH;
if (x != 0){
session->opts.flags |= u;
} else {
session->opts.flags &= ~u;
}
}
break;
default:
ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);

View File

@ -112,7 +112,8 @@ ssh_session ssh_new(void) {
#else
session->opts.ssh1 = 0;
#endif
session->opts.flags = SSH_OPT_FLAG_PASSWORD_AUTH | SSH_OPT_FLAG_PUBKEY_AUTH |
SSH_OPT_FLAG_KBDINT_AUTH | SSH_OPT_FLAG_GSSAPI_AUTH;
session->opts.identity = ssh_list_new();
if (session->opts.identity == NULL) {
goto err;

View File

@ -239,6 +239,34 @@ static void torture_options_proxycommand(void **state) {
assert_null(session->opts.ProxyCommand);
}
static void torture_options_config_host(void **state) {
ssh_session session = *state;
FILE *config = NULL;
/* create a new config file */
config = fopen("test_config", "w");
assert_non_null(config);
fputs("Host testhost1\nPort 42\nHost testhost2,testhost3\nPort 43\n", config);
fclose(config);
ssh_options_set(session, SSH_OPTIONS_HOST, "testhost1");
ssh_options_parse_config(session, "test_config");
assert_int_equal(session->opts.port, 42);
ssh_options_set(session, SSH_OPTIONS_HOST, "testhost2");
ssh_options_parse_config(session, "test_config");
assert_int_equal(session->opts.port, 43);
session->opts.port = 0;
ssh_options_set(session, SSH_OPTIONS_HOST, "testhost3");
ssh_options_parse_config(session, "test_config");
assert_int_equal(session->opts.port, 43);
unlink("test_config");
}
#ifdef WITH_SERVER
/* sshbind options */
@ -304,6 +332,7 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_options_proxycommand, setup, teardown),
cmocka_unit_test_setup_teardown(torture_options_set_ciphers, setup, teardown),
cmocka_unit_test_setup_teardown(torture_options_set_macs, setup, teardown),
cmocka_unit_test_setup_teardown(torture_options_config_host, setup, teardown)
};
#ifdef WITH_SERVER