Asynchronous authentication works !
Этот коммит содержится в:
родитель
682ed18123
Коммит
a229cb4676
@ -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;
|
||||||
|
172
libssh/auth.c
172
libssh/auth.c
@ -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
|
||||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user