aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libssh/session.h1
-rw-r--r--src/auth.c271
2 files changed, 162 insertions, 110 deletions
diff --git a/include/libssh/session.h b/include/libssh/session.h
index b2d610de..894b8453 100644
--- a/include/libssh/session.h
+++ b/include/libssh/session.h
@@ -118,6 +118,7 @@ struct ssh_session_struct {
enum ssh_auth_state_e auth_state;
enum ssh_channel_request_state_e global_req_state;
struct ssh_agent_state_struct *agent_state;
+ struct ssh_auth_auto_state_struct *auth_auto_state;
KEX server_kex;
KEX client_kex;
diff --git a/src/auth.c b/src/auth.c
index 84cb92e4..a683e455 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -1010,6 +1010,20 @@ int ssh_userauth_agent(ssh_session session,
}
#endif
+enum ssh_auth_auto_state_e {
+ SSH_AUTH_AUTO_STATE_NONE=0,
+ SSH_AUTH_AUTO_STATE_PUBKEY,
+ SSH_AUTH_AUTO_STATE_KEY_IMPORTED,
+ SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED
+};
+
+struct ssh_auth_auto_state_struct {
+ enum ssh_auth_auto_state_e state;
+ struct ssh_iterator *it;
+ ssh_key privkey;
+ ssh_key pubkey;
+};
+
/**
* @brief Tries to automatically authenticate with public key and "none"
*
@@ -1043,9 +1057,9 @@ int ssh_userauth_publickey_auto(ssh_session session,
const char *username,
const char *passphrase)
{
- struct ssh_iterator *it;
ssh_auth_callback auth_fn = NULL;
void *auth_data = NULL;
+ struct ssh_auth_auto_state_struct *state;
int rc;
if (session == NULL) {
@@ -1056,141 +1070,178 @@ int ssh_userauth_publickey_auto(ssh_session session,
auth_fn = session->common.callbacks->auth_function;
auth_data = session->common.callbacks->userdata;
}
-
+ if (!session->auth_auto_state){
+ session->auth_auto_state =
+ malloc(sizeof(struct ssh_auth_auto_state_struct));
+ if (!session->auth_auto_state){
+ ssh_set_error_oom(session);
+ return SSH_AUTH_ERROR;
+ }
+ ZERO_STRUCTP(session->auth_auto_state);
+ }
+ state = session->auth_auto_state;
+ if (state->state == SSH_AUTH_AUTO_STATE_NONE){
#ifndef _WIN32
/* Try authentication with ssh-agent first */
- rc = ssh_userauth_agent(session, username);
- if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_SUCCESS) {
- return rc;
- }
+ rc = ssh_userauth_agent(session, username);
+ if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_SUCCESS) {
+ return rc;
+ }
+ if (rc == SSH_AUTH_AGAIN)
+ return rc;
#endif
-
- for (it = ssh_list_get_iterator(session->identity);
- it != NULL;
- it = it->next) {
- const char *privkey_file = it->data;
+ state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
+ }
+ if (state->it == NULL)
+ state->it = ssh_list_get_iterator(session->identity);
+ while (state->it != NULL){
+ const char *privkey_file = state->it->data;
char pubkey_file[1024] = {0};
- ssh_key privkey = NULL;
- ssh_key pubkey;
-
- ssh_log(session,
- SSH_LOG_PROTOCOL,
- "Trying to authenticate with %s",
- privkey_file);
-
- snprintf(pubkey_file, sizeof(pubkey_file), "%s.pub", privkey_file);
+ if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY){
+ ssh_log(session,
+ SSH_LOG_PROTOCOL,
+ "Trying to authenticate with %s",
+ privkey_file);
+ state->privkey = NULL;
+ state->pubkey = NULL;
+ snprintf(pubkey_file, sizeof(pubkey_file), "%s.pub", privkey_file);
- rc = ssh_pki_import_pubkey_file(pubkey_file, &pubkey);
- if (rc == SSH_ERROR) {
- ssh_set_error(session,
- SSH_FATAL,
- "Failed to import public key: %s",
- pubkey_file);
- return SSH_AUTH_ERROR;
- } else if (rc == SSH_EOF) {
- /* Read the private key and save the public key to file */
- rc = ssh_pki_import_privkey_file(privkey_file,
- passphrase,
- auth_fn,
- auth_data,
- &privkey);
+ rc = ssh_pki_import_pubkey_file(pubkey_file, &state->pubkey);
if (rc == SSH_ERROR) {
ssh_set_error(session,
- SSH_FATAL,
- "Failed to read private key: %s",
- privkey_file);
- continue;
+ SSH_FATAL,
+ "Failed to import public key: %s",
+ pubkey_file);
+ SAFE_FREE(session->auth_auto_state);
return SSH_AUTH_ERROR;
} else if (rc == SSH_EOF) {
- /* If the file doesn't exist, continue */
+ /* Read the private key and save the public key to file */
+ rc = ssh_pki_import_privkey_file(privkey_file,
+ passphrase,
+ auth_fn,
+ auth_data,
+ &state->privkey);
+ if (rc == SSH_ERROR) {
+ ssh_set_error(session,
+ SSH_FATAL,
+ "Failed to read private key: %s",
+ privkey_file);
+ state->it=state->it->next;
+ continue;
+ } else if (rc == SSH_EOF) {
+ /* If the file doesn't exist, continue */
+ ssh_log(session,
+ SSH_LOG_PACKET,
+ "Private key %s doesn't exist.",
+ privkey_file);
+ state->it=state->it->next;
+ continue;
+ }
+
+ rc = ssh_pki_export_privkey_to_pubkey(state->privkey, &state->pubkey);
+ if (rc == SSH_ERROR) {
+ ssh_key_free(state->privkey);
+ SAFE_FREE(session->auth_auto_state);
+ return SSH_AUTH_ERROR;
+ }
+
+ rc = ssh_pki_export_pubkey_file(state->pubkey, pubkey_file);
+ if (rc == SSH_ERROR) {
+ ssh_log(session,
+ SSH_LOG_PACKET,
+ "Could not write public key to file: %s",
+ pubkey_file);
+ }
+ }
+ state->state = SSH_AUTH_AUTO_STATE_KEY_IMPORTED;
+ }
+ if (state->state == SSH_AUTH_AUTO_STATE_KEY_IMPORTED){
+ rc = ssh_userauth_try_publickey(session, username, state->pubkey);
+ if (rc == SSH_AUTH_ERROR) {
+ ssh_log(session,
+ SSH_LOG_RARE,
+ "Public key authentication error for %s",
+ privkey_file);
+ ssh_key_free(state->privkey);
+ ssh_key_free(state->pubkey);
+ SAFE_FREE(session->auth_auto_state);
+ return rc;
+ } else if (rc == SSH_AUTH_AGAIN){
+ return rc;
+ } else if (rc != SSH_AUTH_SUCCESS) {
ssh_log(session,
- SSH_LOG_PACKET,
- "Private key %s doesn't exist.",
+ SSH_LOG_PROTOCOL,
+ "Public key for %s refused by server",
privkey_file);
+ ssh_key_free(state->privkey);
+ ssh_key_free(state->pubkey);
+ state->it=state->it->next;
continue;
}
-
- rc = ssh_pki_export_privkey_to_pubkey(privkey, &pubkey);
- if (rc == SSH_ERROR) {
- ssh_key_free(privkey);
- return SSH_AUTH_ERROR;
+ state->state = SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED;
+ }
+ if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED){
+ /* Public key has been accepted by the server */
+ if (state->privkey == NULL) {
+ rc = ssh_pki_import_privkey_file(privkey_file,
+ passphrase,
+ auth_fn,
+ auth_data,
+ &state->privkey);
+ if (rc == SSH_ERROR) {
+ ssh_key_free(state->pubkey);
+ state->pubkey=NULL;
+ ssh_set_error(session,
+ SSH_FATAL,
+ "Failed to read private key: %s",
+ privkey_file);
+ state->it=state->it->next;
+ state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
+ continue;
+ } else if (rc == SSH_EOF) {
+ /* If the file doesn't exist, continue */
+ ssh_key_free(state->pubkey);
+ state->pubkey=NULL;
+ ssh_log(session,
+ SSH_LOG_PACKET,
+ "Private key %s doesn't exist.",
+ privkey_file);
+ state->it=state->it->next;
+ state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
+ continue;
+ }
}
- rc = ssh_pki_export_pubkey_file(pubkey, pubkey_file);
- if (rc == SSH_ERROR) {
- ssh_log(session,
- SSH_LOG_PACKET,
- "Could not write public key to file: %s",
- pubkey_file);
+ rc = ssh_userauth_publickey(session, username, state->privkey);
+ if (rc != SSH_AUTH_AGAIN && rc != SSH_AUTH_DENIED) {
+ ssh_key_free(state->privkey);
+ ssh_key_free(state->pubkey);
+ SAFE_FREE(session->auth_auto_state);
}
- }
-
- rc = ssh_userauth_try_publickey(session, username, pubkey);
- if (rc == SSH_AUTH_ERROR) {
- ssh_log(session,
- SSH_LOG_RARE,
- "Public key authentication error for %s",
- privkey_file);
- ssh_key_free(privkey);
- ssh_key_free(pubkey);
- return rc;
- } else if (rc != SSH_AUTH_SUCCESS) {
- ssh_log(session,
- SSH_LOG_PROTOCOL,
- "Public key for %s refused by server",
- privkey_file);
- ssh_key_free(privkey);
- ssh_key_free(pubkey);
- continue;
- }
-
- /* Public key has been accepted by the server */
- if (privkey == NULL) {
- rc = ssh_pki_import_privkey_file(privkey_file,
- passphrase,
- auth_fn,
- auth_data,
- &privkey);
- if (rc == SSH_ERROR) {
- ssh_key_free(pubkey);
- ssh_set_error(session,
- SSH_FATAL,
- "Failed to read private key: %s",
- privkey_file);
- continue;
- } else if (rc == SSH_EOF) {
- /* If the file doesn't exist, continue */
- ssh_key_free(pubkey);
+ if (rc == SSH_AUTH_ERROR) {
+ return rc;
+ } else if (rc == SSH_AUTH_SUCCESS) {
ssh_log(session,
- SSH_LOG_PACKET,
- "Private key %s doesn't exist.",
+ SSH_LOG_PROTOCOL,
+ "Successfully authenticated using %s",
privkey_file);
- continue;
+ return rc;
+ } else if (rc == SSH_AUTH_AGAIN){
+ return rc;
}
- }
- rc = ssh_userauth_publickey(session, username, privkey);
- ssh_key_free(privkey);
- ssh_key_free(pubkey);
- if (rc == SSH_AUTH_ERROR) {
- return rc;
- } else if (rc == SSH_AUTH_SUCCESS) {
ssh_log(session,
- SSH_LOG_PROTOCOL,
- "Successfully authenticated using %s",
- privkey_file);
- return rc;
+ SSH_LOG_RARE,
+ "The server accepted the public key but refused the signature");
+ state->it=state->it->next;
+ state->state=SSH_AUTH_AUTO_STATE_PUBKEY;
+ /* continue */
}
-
- ssh_log(session,
- SSH_LOG_RARE,
- "The server accepted the public key but refused the signature");
- /* continue */
}
ssh_log(session,
SSH_LOG_PROTOCOL,
"Tried every public key, none matched");
-
+ SAFE_FREE(session->auth_auto_state);
return SSH_AUTH_DENIED;
}