1
1

Auth: nonblocking ssh_userauth_pubkey_auto

Этот коммит содержится в:
Aris Adamantiadis 2011-09-11 01:56:30 +02:00
родитель 7b663df185
Коммит ff5bf51af1
2 изменённых файлов: 166 добавлений и 114 удалений

Просмотреть файл

@ -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;

Просмотреть файл

@ -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;
}