session server ssh BUGFIX partial auth methods
Require the client to authenticate via all of his configured auth
methods, previously only the count of successes mattered.
Fixes CESNET/netopeer2#1629
diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c
index e244c3b..71a60f1 100644
--- a/src/session_server_ssh.c
+++ b/src/session_server_ssh.c
@@ -1438,15 +1438,15 @@
* @param[in] method Type of the authentication method.
* @param[in] str_method String representation of the authentication method.
* @param[in] local_users_supported Whether the server supports local users.
- * @param[in,out] state Authentication state.
+ * @param[in,out] auth_state Authentication state.
* @return 1 in case of a fatal error, 0 otherwise.
*/
static int
nc_server_ssh_auth(struct nc_session *session, struct nc_server_ssh_opts *opts, ssh_message msg,
- int method, const char *str_method, int local_users_supported, struct nc_auth_state *state)
+ int method, const char *str_method, int local_users_supported, struct nc_auth_state *auth_state)
{
const char *username;
- int libssh_auth_methods = 0, ret = 0;
+ int ret = 0;
uint16_t i;
struct nc_auth_client *auth_client = NULL;
struct nc_endpt *referenced_endpt;
@@ -1473,7 +1473,7 @@
}
return nc_server_ssh_auth(session, referenced_endpt->opts.ssh, msg, method,
- str_method, local_users_supported, state);
+ str_method, local_users_supported, auth_state);
}
/* user not known, set his authentication methods to public key only so that
@@ -1495,29 +1495,29 @@
(auth_client->store == NC_STORE_TRUSTSTORE) || (auth_client->store == NC_STORE_SYSTEM)) {
/* either locally configured pubkeys, or truststore or system (need to check for
* pubkey count, because NC_STORE_LOCAL is the default enum value) */
- state->auth_method_count++;
- libssh_auth_methods |= SSH_AUTH_METHOD_PUBLICKEY;
+ auth_state->methods |= SSH_AUTH_METHOD_PUBLICKEY;
+ auth_state->method_count++;
}
if (auth_client->password) {
- state->auth_method_count++;
- libssh_auth_methods |= SSH_AUTH_METHOD_PASSWORD;
+ auth_state->methods |= SSH_AUTH_METHOD_PASSWORD;
+ auth_state->method_count++;
}
if (auth_client->kb_int_enabled) {
- state->auth_method_count++;
- libssh_auth_methods |= SSH_AUTH_METHOD_INTERACTIVE;
+ auth_state->methods |= SSH_AUTH_METHOD_INTERACTIVE;
+ auth_state->method_count++;
}
if (auth_client->none_enabled) {
- state->auth_method_count++;
- libssh_auth_methods |= SSH_AUTH_METHOD_NONE;
+ auth_state->methods |= SSH_AUTH_METHOD_NONE;
+ auth_state->method_count++;
}
} else {
/* no local users meaning pw, pubkey and kbdint methods are supported, method count is set to 1,
- * because only one method is needed for successul auth */
- state->auth_method_count = 1;
- libssh_auth_methods = SSH_AUTH_METHOD_PUBLICKEY | SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_INTERACTIVE;
+ * because only one method is needed for successful auth */
+ auth_state->methods = SSH_AUTH_METHOD_PUBLICKEY | SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_INTERACTIVE;
+ auth_state->method_count = 1;
}
- ssh_set_auth_methods(session->ti.libssh.session, libssh_auth_methods);
+ ssh_set_auth_methods(session->ti.libssh.session, auth_state->methods);
} else {
if (strcmp(username, session->username)) {
/* changing username not allowed */
@@ -1547,11 +1547,13 @@
}
if (!ret) {
- state->auth_success_count++;
+ auth_state->success_methods |= method;
+ auth_state->success_count++;
- if (state->auth_success_count < state->auth_method_count) {
+ if (auth_state->success_count < auth_state->method_count) {
/* success, but he needs to do another method */
VRB(session, "User \"%s\" partially authenticated, but still needs to authenticate via the rest of his configured methods.", username);
+ ssh_set_auth_methods(session->ti.libssh.session, auth_state->methods & ~auth_state->success_methods);
ssh_message_auth_reply_success(msg, 1);
} else {
/* authenticated */
@@ -1571,7 +1573,7 @@
}
int
-nc_session_ssh_msg(struct nc_session *session, struct nc_server_ssh_opts *opts, ssh_message msg, struct nc_auth_state *state)
+nc_session_ssh_msg(struct nc_session *session, struct nc_server_ssh_opts *opts, ssh_message msg, struct nc_auth_state *auth_state)
{
const char *str_type, *str_subtype = NULL;
int subtype, type, rc, local_users_supported;
@@ -1707,7 +1709,7 @@
ERR(session, "User \"%s\" authenticated, but requested another authentication.", session->username);
ssh_message_reply_default(msg);
return 0;
- } else if (!state || !opts) {
+ } else if (!auth_state || !opts) {
/* these two parameters should always be set during an authentication,
* however do a check just in case something goes really wrong, since they
* are not needed for other types of messages
@@ -1738,7 +1740,7 @@
}
/* authenticate */
- return nc_server_ssh_auth(session, opts, msg, subtype, str_subtype, local_users_supported, state);
+ return nc_server_ssh_auth(session, opts, msg, subtype, str_subtype, local_users_supported, auth_state);
} else if (session->flags & NC_SESSION_SSH_AUTHENTICATED) {
if ((type == SSH_REQUEST_CHANNEL_OPEN) && ((enum ssh_channel_type_e)subtype == SSH_CHANNEL_SESSION)) {
if (nc_server_ssh_channel_open(session, msg)) {
@@ -1862,7 +1864,7 @@
{
struct timespec ts_timeout;
ssh_message msg;
- struct nc_auth_state state = {0};
+ struct nc_auth_state auth_state = {0};
/* authenticate */
if (opts->auth_timeout) {
@@ -1876,7 +1878,7 @@
msg = ssh_message_get(session->ti.libssh.session);
if (msg) {
- if (nc_session_ssh_msg(session, opts, msg, &state)) {
+ if (nc_session_ssh_msg(session, opts, msg, &auth_state)) {
ssh_message_reply_default(msg);
}
ssh_message_free(msg);