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_auth_state_e auth_state;
|
||||||
enum ssh_channel_request_state_e global_req_state;
|
enum ssh_channel_request_state_e global_req_state;
|
||||||
struct ssh_agent_state_struct *agent_state;
|
struct ssh_agent_state_struct *agent_state;
|
||||||
|
struct ssh_auth_auto_state_struct *auth_auto_state;
|
||||||
|
|
||||||
KEX server_kex;
|
KEX server_kex;
|
||||||
KEX client_kex;
|
KEX client_kex;
|
||||||
|
279
src/auth.c
279
src/auth.c
@ -1010,6 +1010,20 @@ int ssh_userauth_agent(ssh_session session,
|
|||||||
}
|
}
|
||||||
#endif
|
#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"
|
* @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 *username,
|
||||||
const char *passphrase)
|
const char *passphrase)
|
||||||
{
|
{
|
||||||
struct ssh_iterator *it;
|
|
||||||
ssh_auth_callback auth_fn = NULL;
|
ssh_auth_callback auth_fn = NULL;
|
||||||
void *auth_data = NULL;
|
void *auth_data = NULL;
|
||||||
|
struct ssh_auth_auto_state_struct *state;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (session == NULL) {
|
if (session == NULL) {
|
||||||
@ -1056,141 +1070,178 @@ int ssh_userauth_publickey_auto(ssh_session session,
|
|||||||
auth_fn = session->common.callbacks->auth_function;
|
auth_fn = session->common.callbacks->auth_function;
|
||||||
auth_data = session->common.callbacks->userdata;
|
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
|
#ifndef _WIN32
|
||||||
/* Try authentication with ssh-agent first */
|
/* Try authentication with ssh-agent first */
|
||||||
rc = ssh_userauth_agent(session, username);
|
rc = ssh_userauth_agent(session, username);
|
||||||
if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_SUCCESS) {
|
if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_SUCCESS) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
if (rc == SSH_AUTH_AGAIN)
|
||||||
|
return rc;
|
||||||
#endif
|
#endif
|
||||||
|
state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
|
||||||
for (it = ssh_list_get_iterator(session->identity);
|
}
|
||||||
it != NULL;
|
if (state->it == NULL)
|
||||||
it = it->next) {
|
state->it = ssh_list_get_iterator(session->identity);
|
||||||
const char *privkey_file = it->data;
|
while (state->it != NULL){
|
||||||
|
const char *privkey_file = state->it->data;
|
||||||
char pubkey_file[1024] = {0};
|
char pubkey_file[1024] = {0};
|
||||||
ssh_key privkey = NULL;
|
if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY){
|
||||||
ssh_key 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,
|
rc = ssh_pki_import_pubkey_file(pubkey_file, &state->pubkey);
|
||||||
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);
|
|
||||||
if (rc == SSH_ERROR) {
|
if (rc == SSH_ERROR) {
|
||||||
ssh_set_error(session,
|
ssh_set_error(session,
|
||||||
SSH_FATAL,
|
SSH_FATAL,
|
||||||
"Failed to read private key: %s",
|
"Failed to import public key: %s",
|
||||||
privkey_file);
|
pubkey_file);
|
||||||
continue;
|
SAFE_FREE(session->auth_auto_state);
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
} else if (rc == SSH_EOF) {
|
} 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(session,
|
||||||
SSH_LOG_PACKET,
|
SSH_LOG_RARE,
|
||||||
"Private key %s doesn't exist.",
|
"Public key authentication error for %s",
|
||||||
privkey_file);
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
state->state = SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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(session,
|
||||||
SSH_LOG_RARE,
|
SSH_LOG_RARE,
|
||||||
"Public key authentication error for %s",
|
"The server accepted the public key but refused the signature");
|
||||||
privkey_file);
|
state->it=state->it->next;
|
||||||
ssh_key_free(privkey);
|
state->state=SSH_AUTH_AUTO_STATE_PUBKEY;
|
||||||
ssh_key_free(pubkey);
|
/* continue */
|
||||||
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);
|
|
||||||
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(session,
|
||||||
SSH_LOG_PROTOCOL,
|
SSH_LOG_PROTOCOL,
|
||||||
"Tried every public key, none matched");
|
"Tried every public key, none matched");
|
||||||
|
SAFE_FREE(session->auth_auto_state);
|
||||||
return SSH_AUTH_DENIED;
|
return SSH_AUTH_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user