Auth: nonblocking ssh_userauth_pubkey_auto
Этот коммит содержится в:
родитель
7b663df185
Коммит
ff5bf51af1
@ -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;
|
||||
|
279
src/auth.c
279
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;
|
||||
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);
|
||||
|
||||
ssh_log(session,
|
||||
SSH_LOG_PROTOCOL,
|
||||
"Trying to authenticate with %s",
|
||||
privkey_file);
|
||||
|
||||
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_PACKET,
|
||||
"Private key %s doesn't exist.",
|
||||
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_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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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_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);
|
||||
}
|
||||
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;
|
||||
} else if (rc == SSH_AUTH_AGAIN){
|
||||
return rc;
|
||||
}
|
||||
|
||||
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;
|
||||
"The server accepted the public key but refused the signature");
|
||||
state->it=state->it->next;
|
||||
state->state=SSH_AUTH_AUTO_STATE_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);
|
||||
ssh_log(session,
|
||||
SSH_LOG_PACKET,
|
||||
"Private key %s doesn't exist.",
|
||||
privkey_file);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
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(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;
|
||||
}
|
||||
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user