1
1

Asynchronous authentication works !

Этот коммит содержится в:
Aris Adamantiadis 2009-12-26 21:59:37 +01:00
родитель 682ed18123
Коммит a229cb4676
4 изменённых файлов: 193 добавлений и 119 удалений

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

@ -22,7 +22,47 @@
#ifndef AUTH_H_ #ifndef AUTH_H_
#define AUTH_H_ #define AUTH_H_
#include "libssh/callbacks.h" #include "libssh/callbacks.h"
SSH_PACKET_CALLBACK(ssh_packet_userauth_banner);
SSH_PACKET_CALLBACK(ssh_packet_userauth_banner);
SSH_PACKET_CALLBACK(ssh_packet_userauth_failure);
SSH_PACKET_CALLBACK(ssh_packet_userauth_success);
SSH_PACKET_CALLBACK(ssh_packet_userauth_pk_ok);
/** @internal
* States of authentication in the client-side. They describe
* what was the last response from the server
*/
enum ssh_auth_state_e {
/** No authentication asked */
SSH_AUTH_STATE_NONE=0,
/** Last authentication response was a partial success */
SSH_AUTH_STATE_PARTIAL,
/** Last authentication response was a success */
SSH_AUTH_STATE_SUCCESS,
/** Last authentication response was failed */
SSH_AUTH_STATE_FAILED,
/** Last authentication was erroneous */
SSH_AUTH_STATE_ERROR,
/** Last state was a keyboard-interactive ask for info */
SSH_AUTH_STATE_INFO,
/** Last state was a public key accepted for authentication */
SSH_AUTH_STATE_PK_OK
};
/** @internal
* @brief states of the authentication service request
*/
enum ssh_auth_service_state_e {
/** initial state */
SSH_AUTH_SERVICE_NONE=0,
/** Authentication service request packet sent */
SSH_AUTH_SERVICE_SENT,
/** Service accepted */
SSH_AUTH_SERVICE_ACCEPTED,
/** Access to service denied (fatal) */
SSH_AUTH_SERVICE_DENIED
};
#endif /* AUTH_H_ */ #endif /* AUTH_H_ */

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

@ -24,6 +24,7 @@
#include "libssh/priv.h" #include "libssh/priv.h"
#include "libssh/packet.h" #include "libssh/packet.h"
#include "libssh/pcap.h" #include "libssh/pcap.h"
#include "libssh/auth.h"
typedef struct ssh_kbdint_struct* ssh_kbdint; typedef struct ssh_kbdint_struct* ssh_kbdint;
@ -41,19 +42,6 @@ enum ssh_session_state_e {
SSH_SESSION_STATE_ERROR SSH_SESSION_STATE_ERROR
}; };
/** @internal
* @brief states of the authentication service request
*/
enum ssh_auth_service_state_e {
/** initial state */
SSH_AUTH_SERVICE_NONE=0,
/** Authentication service request packet sent */
SSH_AUTH_SERVICE_SENT,
/** Service accepted */
SSH_AUTH_SERVICE_ACCEPTED,
/** Access to service denied (fatal) */
SSH_AUTH_SERVICE_DENIED
};
struct ssh_session_struct { struct ssh_session_struct {
struct error_struct error; struct error_struct error;
@ -93,8 +81,9 @@ struct ssh_session_struct {
int packet_state; int packet_state;
int dh_handshake_state; int dh_handshake_state;
enum ssh_auth_service_state_e auth_service_state; enum ssh_auth_service_state_e auth_service_state;
ssh_string dh_server_signature; //information used by dh_handshake. enum ssh_auth_state_e auth_state;
ssh_string dh_server_signature; //information used by dh_handshake.
KEX server_kex; KEX server_kex;
KEX client_kex; KEX client_kex;
ssh_buffer in_hashbuf; ssh_buffer in_hashbuf;

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

@ -68,7 +68,7 @@ static int ask_userauth(ssh_session session) {
} }
/** @internal /** @internal
* @handles a SSH_USERAUTH_BANNER packet * @brief handles a SSH_USERAUTH_BANNER packet
* This banner should be shown to user prior to authentication * This banner should be shown to user prior to authentication
*/ */
SSH_PACKET_CALLBACK(ssh_packet_userauth_banner){ SSH_PACKET_CALLBACK(ssh_packet_userauth_banner){
@ -91,55 +91,49 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_banner){
return SSH_PACKET_USED; return SSH_PACKET_USED;
} }
/** @internal
static int wait_auth_status(ssh_session session, int kbdint) { * @brief handles a SSH_USERAUTH_FAILURE packet
* This handles the complete or partial authentication
* failure.
*/
SSH_PACKET_CALLBACK(ssh_packet_userauth_failure){
char *auth_methods = NULL; char *auth_methods = NULL;
ssh_string auth; ssh_string auth;
int rc = SSH_AUTH_ERROR;
int cont = 1;
uint8_t partial = 0; uint8_t partial = 0;
(void) type;
(void) user;
enter_function(); enter_function();
while (cont) { auth = buffer_get_ssh_string(packet);
if (packet_read(session) != SSH_OK) { if (auth == NULL || buffer_get_u8(packet, &partial) != 1) {
break;
}
if (packet_translate(session) != SSH_OK) {
break;
}
switch (session->in_packet.type) {
case SSH2_MSG_USERAUTH_FAILURE:
auth = buffer_get_ssh_string(session->in_buffer);
if (auth == NULL || buffer_get_u8(session->in_buffer, &partial) != 1) {
ssh_set_error(session, SSH_FATAL, ssh_set_error(session, SSH_FATAL,
"Invalid SSH_MSG_USERAUTH_FAILURE message"); "Invalid SSH_MSG_USERAUTH_FAILURE message");
leave_function(); session->auth_state=SSH_AUTH_STATE_ERROR;
return SSH_AUTH_ERROR; goto end;
} }
auth_methods = string_to_char(auth); auth_methods = string_to_char(auth);
if (auth_methods == NULL) { if (auth_methods == NULL) {
ssh_set_error(session, SSH_FATAL, ssh_set_error_oom(session);
"Not enough space"); goto end;
string_free(auth);
leave_function();
return SSH_AUTH_ERROR;
} }
if (partial) { if (partial) {
rc = SSH_AUTH_PARTIAL; session->auth_state=SSH_AUTH_STATE_PARTIAL;
ssh_set_error(session, SSH_NO_ERROR, ssh_log(session,SSH_LOG_PROTOCOL,
"Partial success. Authentication that can continue: %s", "Partial success. Authentication that can continue: %s",
auth_methods); auth_methods);
} else { } else {
rc = SSH_AUTH_DENIED; session->auth_state=SSH_AUTH_STATE_FAILED;
ssh_log(session, SSH_LOG_PROTOCOL,
"Access denied. Authentication that can continue: %s",
auth_methods);
ssh_set_error(session, SSH_REQUEST_DENIED, ssh_set_error(session, SSH_REQUEST_DENIED,
"Access denied. Authentication that can continue: %s", "Access denied. Authentication that can continue: %s",
auth_methods); auth_methods);
session->auth_methods = 0; session->auth_methods = 0;
}
if (strstr(auth_methods, "password") != NULL) { if (strstr(auth_methods, "password") != NULL) {
session->auth_methods |= SSH_AUTH_METHOD_PASSWORD; session->auth_methods |= SSH_AUTH_METHOD_PASSWORD;
} }
@ -152,35 +146,86 @@ static int wait_auth_status(ssh_session session, int kbdint) {
if (strstr(auth_methods, "hostbased") != NULL) { if (strstr(auth_methods, "hostbased") != NULL) {
session->auth_methods |= SSH_AUTH_METHOD_HOSTBASED; session->auth_methods |= SSH_AUTH_METHOD_HOSTBASED;
} }
}
end:
string_free(auth); string_free(auth);
SAFE_FREE(auth_methods); SAFE_FREE(auth_methods);
cont = 0; leave_function();
return SSH_PACKET_USED;
}
/** @internal
* @brief handles a SSH_USERAUTH_SUCCESS packet
* It is also used to communicate the new to the
* upper levels.
*/
SSH_PACKET_CALLBACK(ssh_packet_userauth_success){
enter_function();
(void)packet;
(void)type;
(void)user;
ssh_log(session,SSH_LOG_PACKET,"Received SSH_USERAUTH_SUCCESS");
ssh_log(session,SSH_LOG_PROTOCOL,"Authentication successful");
session->auth_state=SSH_AUTH_STATE_SUCCESS;
session->session_state=SSH_SESSION_STATE_AUTHENTICATED;
leave_function();
return SSH_PACKET_USED;
}
/** @internal
* @brief handles a SSH_USERAUTH_PK_OK or SSH_USERAUTH_INFO_REQUEST packet
* Since the two types of packets share the same code, additional
* work is done to understand if we are in a public key or
* keyboard-interactive context.
*/
SSH_PACKET_CALLBACK(ssh_packet_userauth_pk_ok){
enter_function();
(void)packet;
(void)type;
(void)user;
ssh_log(session,SSH_LOG_PACKET,"Received SSH_USERAUTH_PK_OK/INFO_REQUEST");
if(session->kbdint){
/* Assuming we are in keyboard-interactive context */
ssh_log(session,SSH_LOG_PACKET,"keyboard-interactive context exists, assuming SSH_USERAUTH_INFO_REQUEST");
session->auth_state=SSH_AUTH_STATE_INFO;
} else {
session->auth_state=SSH_AUTH_STATE_PK_OK;
ssh_log(session,SSH_LOG_PACKET,"assuming SSH_USERAUTH_PK_OK");
}
leave_function();
return SSH_PACKET_USED;
}
static int wait_auth_status(ssh_session session) {
int rc = SSH_AUTH_ERROR;
enter_function();
while (session->auth_state == SSH_AUTH_STATE_NONE) {
ssh_handle_packets(session);
}
switch(session->auth_state){
case SSH_AUTH_STATE_ERROR:
rc=SSH_AUTH_ERROR;
break; break;
case SSH2_MSG_USERAUTH_PK_OK: case SSH_AUTH_STATE_FAILED:
/* SSH monkeys have defined the same number for both */ rc=SSH_AUTH_DENIED;
/* SSH_MSG_USERAUTH_PK_OK and SSH_MSG_USERAUTH_INFO_REQUEST */ break;
/* which is not really smart; */ case SSH_AUTH_STATE_INFO:
/*case SSH2_MSG_USERAUTH_INFO_REQUEST: */
if (kbdint) {
rc=SSH_AUTH_INFO; rc=SSH_AUTH_INFO;
cont = 0;
break; break;
} case SSH_AUTH_STATE_PARTIAL:
/* continue through success */ rc=SSH_AUTH_PARTIAL;
case SSH2_MSG_USERAUTH_SUCCESS: break;
case SSH_AUTH_STATE_PK_OK:
case SSH_AUTH_STATE_SUCCESS:
rc=SSH_AUTH_SUCCESS; rc=SSH_AUTH_SUCCESS;
cont = 0;
break; break;
case SSH_AUTH_STATE_NONE:
default: /* not reached */
//packet_parse(session); rc=SSH_AUTH_ERROR;
//FIXME: broken
break; break;
} }
}
leave_function(); leave_function();
return rc; return rc;
} }
@ -212,9 +257,7 @@ int ssh_userauth_list(ssh_session session, const char *username) {
* *
* @param session The ssh session to use. * @param session The ssh session to use.
* *
* @param username The username to authenticate. You can specify NULL if * @param username Deprecated, set to NULL.
* ssh_option_set_username() has been used. You cannot try
* two different logins in a row.
* *
* @returns SSH_AUTH_ERROR: A serious error happened.\n * @returns SSH_AUTH_ERROR: A serious error happened.\n
* SSH_AUTH_DENIED: Authentication failed: use another method\n * SSH_AUTH_DENIED: Authentication failed: use another method\n
@ -280,12 +323,12 @@ int ssh_userauth_none(ssh_session session, const char *username) {
string_free(service); string_free(service);
string_free(method); string_free(method);
string_free(user); string_free(user);
session->auth_state=SSH_AUTH_STATE_NONE;
if (packet_send(session) == SSH_ERROR) { if (packet_send(session) == SSH_ERROR) {
leave_function(); leave_function();
return rc; return rc;
} }
rc = wait_auth_status(session, 0); rc = wait_auth_status(session);
leave_function(); leave_function();
return rc; return rc;
@ -394,12 +437,12 @@ int ssh_userauth_offer_pubkey(ssh_session session, const char *username,
string_free(method); string_free(method);
string_free(service); string_free(service);
string_free(algo); string_free(algo);
session->auth_state=SSH_AUTH_STATE_NONE;
if (packet_send(session) != SSH_OK) { if (packet_send(session) != SSH_OK) {
leave_function(); leave_function();
return rc; return rc;
} }
rc = wait_auth_status(session,0); rc = wait_auth_status(session);
leave_function(); leave_function();
return rc; return rc;
@ -514,12 +557,12 @@ int ssh_userauth_pubkey(ssh_session session, const char *username,
goto error; goto error;
} }
string_free(sign); string_free(sign);
session->auth_state=SSH_AUTH_STATE_NONE;
if (packet_send(session) != SSH_OK) { if (packet_send(session) != SSH_OK) {
leave_function(); leave_function();
return rc; return rc;
} }
rc = wait_auth_status(session,0); rc = wait_auth_status(session);
} }
leave_function(); leave_function();
@ -632,11 +675,12 @@ int ssh_userauth_agent_pubkey(ssh_session session, const char *username,
goto error; goto error;
} }
string_free(sign); string_free(sign);
session->auth_state=SSH_AUTH_STATE_NONE;
if (packet_send(session) != SSH_OK) { if (packet_send(session) != SSH_OK) {
leave_function(); leave_function();
return rc; return rc;
} }
rc = wait_auth_status(session,0); rc = wait_auth_status(session);
} }
string_free(user); string_free(user);
@ -751,12 +795,12 @@ int ssh_userauth_password(ssh_session session, const char *username,
string_free(method); string_free(method);
string_burn(pwd); string_burn(pwd);
string_free(pwd); string_free(pwd);
session->auth_state=SSH_AUTH_STATE_NONE;
if (packet_send(session) != SSH_OK) { if (packet_send(session) != SSH_OK) {
leave_function(); leave_function();
return rc; return rc;
} }
rc = wait_auth_status(session, 0); rc = wait_auth_status(session);
leave_function(); leave_function();
return rc; return rc;
@ -1161,12 +1205,12 @@ static int kbdauth_init(ssh_session session, const char *user,
string_free(service); string_free(service);
string_free(method); string_free(method);
string_free(sub); string_free(sub);
session->auth_state=SSH_AUTH_STATE_NONE;
if (packet_send(session) != SSH_OK) { if (packet_send(session) != SSH_OK) {
leave_function(); leave_function();
return rc; return rc;
} }
rc = wait_auth_status(session,1); rc = wait_auth_status(session);
leave_function(); leave_function();
return rc; return rc;
@ -1328,12 +1372,12 @@ static int kbdauth_send(ssh_session session) {
string_burn(answer); string_burn(answer);
string_free(answer); string_free(answer);
} }
session->auth_state=SSH_AUTH_STATE_NONE;
if (packet_send(session) != SSH_OK) { if (packet_send(session) != SSH_OK) {
leave_function(); leave_function();
return rc; return rc;
} }
rc = wait_auth_status(session,1); rc = wait_auth_status(session);
leave_function(); leave_function();
return rc; return rc;
@ -1405,7 +1449,7 @@ int ssh_userauth_kbdint(ssh_session session, const char *user,
leave_function(); leave_function();
return rc; /* error or first try success */ return rc; /* error or first try success */
} }
/* TODO: put this in packet handler */
rc = kbdauth_info_get(session); rc = kbdauth_info_get(session);
if (rc == SSH_AUTH_ERROR) { if (rc == SSH_AUTH_ERROR) {
kbdint_free(session->kbdint); kbdint_free(session->kbdint);

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

@ -68,10 +68,11 @@ ssh_packet_callback default_packet_handlers[]= {
NULL, NULL, NULL, NULL, NULL, // 35-49 NULL, NULL, NULL, NULL, NULL, // 35-49
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, //#define SSH2_MSG_USERAUTH_REQUEST 50 NULL, //#define SSH2_MSG_USERAUTH_REQUEST 50
NULL, //#define SSH2_MSG_USERAUTH_FAILURE 51 ssh_packet_userauth_failure, //#define SSH2_MSG_USERAUTH_FAILURE 51
NULL, //#define SSH2_MSG_USERAUTH_SUCCESS 52 ssh_packet_userauth_success, //#define SSH2_MSG_USERAUTH_SUCCESS 52
ssh_packet_userauth_banner, //#define SSH2_MSG_USERAUTH_BANNER 53 ssh_packet_userauth_banner, //#define SSH2_MSG_USERAUTH_BANNER 53
NULL, //#define SSH2_MSG_USERAUTH_PK_OK 60 SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60 NULL,NULL,NULL,NULL,NULL,NULL, // 54-59
ssh_packet_userauth_pk_ok, //#define SSH2_MSG_USERAUTH_PK_OK 60 SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60
//SSH2_MSG_USERAUTH_INFO_REQUEST 60 //SSH2_MSG_USERAUTH_INFO_REQUEST 60
NULL, //#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61 NULL, //#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, //62-79 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, //62-79