Report generated at: Mon Oct 13 11:12:57 CEST 2008
| Total number of functions | 196 |
| Number of low risk functions | 136 |
| Number of moderate risk functions | 38 |
| Number of high risk functions | 18 |
| Number of untestable functions | 4 |
Used ranges:
| Cyclomatic Complexity | Risk Evaluation | |
| 0 - 10 | Simple module, without much risk | |
| 11 - 20 | More complex module, moderate risk | |
| 21 - 50 | Complex module, high risk | |
| greater than 50 | Untestable module, very high risk |
| Function Name |
Cyclomatic
Complexity |
Number of
Statements |
Number of
Lines |
Source File | |
| ↓ | libssh2_scp_recv | 83 | 217 | 496 | src/scp.c |
LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
{
int path_len = strlen(path);
int rc;
if (session->scpRecv_state == libssh2_NB_state_idle) {
session->scpRecv_mode = 0;
session->scpRecv_size = 0;
session->scpRecv_mtime = 0;
session->scpRecv_atime = 0;
session->scpRecv_command_len = path_len + sizeof("scp -f ");
if (sb) {
session->scpRecv_command_len++;
}
session->scpRecv_command =
LIBSSH2_ALLOC(session, session->scpRecv_command_len);
if (!session->scpRecv_command) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate a command buffer for SCP session",
0);
return NULL;
}
if (sb) {
memcpy(session->scpRecv_command, "scp -pf ",
sizeof("scp -pf ") - 1);
memcpy(session->scpRecv_command + sizeof("scp -pf ") - 1, path,
path_len);
} else {
memcpy(session->scpRecv_command, "scp -f ", sizeof("scp -f ") - 1);
memcpy(session->scpRecv_command + sizeof("scp -f ") - 1, path,
path_len);
}
session->scpRecv_command[session->scpRecv_command_len - 1] = '\0';
_libssh2_debug(session, LIBSSH2_DBG_SCP,
"Opening channel for SCP receive");
session->scpRecv_state = libssh2_NB_state_created;
}
if (session->scpRecv_state == libssh2_NB_state_created) {
/* Allocate a channel */
do {
session->scpRecv_channel =
libssh2_channel_open_ex(session, "session",
sizeof("session") - 1,
LIBSSH2_CHANNEL_WINDOW_DEFAULT,
LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL,
0);
if (!session->scpRecv_channel) {
if (libssh2_session_last_errno(session) !=
LIBSSH2_ERROR_EAGAIN) {
LIBSSH2_FREE(session, session->scpRecv_command);
session->scpRecv_command = NULL;
session->scpRecv_state = libssh2_NB_state_idle;
return NULL;
} else if (libssh2_session_last_errno(session) ==
LIBSSH2_ERROR_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block starting up channel", 0);
return NULL;
}
}
} while (!session->scpRecv_channel);
session->scpRecv_state = libssh2_NB_state_sent;
}
if (session->scpRecv_state == libssh2_NB_state_sent) {
/* Request SCP for the desired file */
rc = libssh2_channel_process_startup(session->scpRecv_channel, "exec",
sizeof("exec") - 1,
(char *) session->scpRecv_command,
session->scpRecv_command_len);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block requesting SCP startup", 0);
return NULL;
} else if (rc) {
LIBSSH2_FREE(session, session->scpRecv_command);
session->scpRecv_command = NULL;
goto scp_recv_error;
}
LIBSSH2_FREE(session, session->scpRecv_command);
session->scpRecv_command = NULL;
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sending initial wakeup");
/* SCP ACK */
session->scpRecv_response[0] = '\0';
session->scpRecv_state = libssh2_NB_state_sent1;
}
if (session->scpRecv_state == libssh2_NB_state_sent1) {
rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
(char *) session->scpRecv_response, 1);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block sending initial wakeup", 0);
return NULL;
} else if (rc != 1) {
goto scp_recv_error;
}
/* Parse SCP response */
session->scpRecv_response_len = 0;
session->scpRecv_state = libssh2_NB_state_sent2;
}
if ((session->scpRecv_state == libssh2_NB_state_sent2)
|| (session->scpRecv_state == libssh2_NB_state_sent3)) {
while (sb
&& (session->scpRecv_response_len <
LIBSSH2_SCP_RESPONSE_BUFLEN)) {
unsigned char *s, *p;
if (session->scpRecv_state == libssh2_NB_state_sent2) {
rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
(char *) session->
scpRecv_response +
session->scpRecv_response_len, 1);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block waiting for SCP response", 0);
return NULL;
} else if (rc <= 0) {
/* Timeout, give up */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Timed out waiting for SCP response", 0);
goto scp_recv_error;
}
session->scpRecv_response_len++;
if (session->scpRecv_response[0] != 'T') {
/*
* Set this as the default error for here, if
* we are successful it will be replaced
*/
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid data in SCP response, missing Time data",
0);
session->scpRecv_err_len =
libssh2_channel_packet_data_len(session->
scpRecv_channel, 0);
session->scpRecv_err_msg =
LIBSSH2_ALLOC(session, session->scpRecv_err_len + 1);
if (!session->scpRecv_err_msg) {
goto scp_recv_error;
}
memset(session->scpRecv_err_msg, 0,
session->scpRecv_err_len + 1);
/* Read the remote error message */
rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
session->scpRecv_err_msg,
session->scpRecv_err_len);
if (rc <= 0) {
/*
* Since we have alread started reading this packet, it is
* already in the systems so it can't return PACKET_EAGAIN
*/
LIBSSH2_FREE(session, session->scpRecv_err_msg);
session->scpRecv_err_msg = NULL;
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Unknown error while getting error string",
0);
goto scp_recv_error;
}
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
session->scpRecv_err_msg, 1);
session->scpRecv_err_msg = NULL;
goto scp_recv_error;
}
if ((session->scpRecv_response_len > 1) &&
((session->
scpRecv_response[session->scpRecv_response_len - 1] <
'0')
|| (session->
scpRecv_response[session->scpRecv_response_len - 1] >
'9'))
&& (session->
scpRecv_response[session->scpRecv_response_len - 1] !=
' ')
&& (session->
scpRecv_response[session->scpRecv_response_len - 1] !=
'\r')
&& (session->
scpRecv_response[session->scpRecv_response_len - 1] !=
'\n')) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid data in SCP response", 0);
goto scp_recv_error;
}
if ((session->scpRecv_response_len < 9)
|| (session->
scpRecv_response[session->scpRecv_response_len - 1] !=
'\n')) {
if (session->scpRecv_response_len ==
LIBSSH2_SCP_RESPONSE_BUFLEN) {
/* You had your chance */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Unterminated response from SCP server",
0);
goto scp_recv_error;
}
/* Way too short to be an SCP response, or not done yet, short circuit */
continue;
}
/* We're guaranteed not to go under response_len == 0 by the logic above */
while ((session->
scpRecv_response[session->scpRecv_response_len - 1] ==
'\r')
|| (session->
scpRecv_response[session->scpRecv_response_len -
1] == '\n'))
session->scpRecv_response_len--;
session->scpRecv_response[session->scpRecv_response_len] =
'\0';
if (session->scpRecv_response_len < 8) {
/* EOL came too soon */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid response from SCP server, too short",
0);
goto scp_recv_error;
}
s = session->scpRecv_response + 1;
p = (unsigned char *) strchr((char *) s, ' ');
if (!p || ((p - s) <= 0)) {
/* No spaces or space in the wrong spot */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid response from SCP server, malformed mtime",
0);
goto scp_recv_error;
}
*(p++) = '\0';
/* Make sure we don't get fooled by leftover values */
errno = 0;
session->scpRecv_mtime = strtol((char *) s, NULL, 10);
if (errno) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid response from SCP server, invalid mtime",
0);
goto scp_recv_error;
}
s = (unsigned char *) strchr((char *) p, ' ');
if (!s || ((s - p) <= 0)) {
/* No spaces or space in the wrong spot */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid response from SCP server, malformed mtime.usec",
0);
goto scp_recv_error;
}
/* Ignore mtime.usec */
s++;
p = (unsigned char *) strchr((char *) s, ' ');
if (!p || ((p - s) <= 0)) {
/* No spaces or space in the wrong spot */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid response from SCP server, too short or malformed",
0);
goto scp_recv_error;
}
*(p++) = '\0';
/* Make sure we don't get fooled by leftover values */
errno = 0;
session->scpRecv_atime = strtol((char *) s, NULL, 10);
if (errno) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid response from SCP server, invalid atime",
0);
goto scp_recv_error;
}
/* SCP ACK */
session->scpRecv_response[0] = '\0';
session->scpRecv_state = libssh2_NB_state_sent3;
}
if (session->scpRecv_state == libssh2_NB_state_sent3) {
rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
(char *) session->
scpRecv_response, 1);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block waiting to send SCP ACK", 0);
return NULL;
} else if (rc != 1) {
goto scp_recv_error;
}
_libssh2_debug(session, LIBSSH2_DBG_SCP,
"mtime = %ld, atime = %ld",
session->scpRecv_mtime, session->scpRecv_atime);
/* We *should* check that atime.usec is valid, but why let that stop use? */
break;
}
}
session->scpRecv_state = libssh2_NB_state_sent4;
}
if (session->scpRecv_state == libssh2_NB_state_sent4) {
session->scpRecv_response_len = 0;
session->scpRecv_state = libssh2_NB_state_sent5;
}
if ((session->scpRecv_state == libssh2_NB_state_sent5)
|| (session->scpRecv_state == libssh2_NB_state_sent6)) {
while (session->scpRecv_response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) {
char *s, *p, *e = NULL;
if (session->scpRecv_state == libssh2_NB_state_sent5) {
rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
(char *) session->
scpRecv_response +
session->scpRecv_response_len, 1);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block waiting for SCP response", 0);
return NULL;
} else if (rc <= 0) {
/* Timeout, give up */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Timed out waiting for SCP response", 0);
goto scp_recv_error;
}
session->scpRecv_response_len++;
if (session->scpRecv_response[0] != 'C') {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid response from SCP server", 0);
goto scp_recv_error;
}
if ((session->scpRecv_response_len > 1) &&
(session->
scpRecv_response[session->scpRecv_response_len - 1] !=
'\r')
&& (session->
scpRecv_response[session->scpRecv_response_len - 1] !=
'\n')
&&
((session->
scpRecv_response[session->scpRecv_response_len - 1] < 32)
|| (session->
scpRecv_response[session->scpRecv_response_len - 1] >
126))) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid data in SCP response", 0);
goto scp_recv_error;
}
if ((session->scpRecv_response_len < 7)
|| (session->
scpRecv_response[session->scpRecv_response_len - 1] !=
'\n')) {
if (session->scpRecv_response_len ==
LIBSSH2_SCP_RESPONSE_BUFLEN) {
/* You had your chance */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Unterminated response from SCP server",
0);
goto scp_recv_error;
}
/* Way too short to be an SCP response, or not done yet, short circuit */
continue;
}
/* We're guaranteed not to go under response_len == 0 by the logic above */
while ((session->
scpRecv_response[session->scpRecv_response_len - 1] ==
'\r')
|| (session->
scpRecv_response[session->scpRecv_response_len -
1] == '\n')) {
session->scpRecv_response_len--;
}
session->scpRecv_response[session->scpRecv_response_len] =
'\0';
if (session->scpRecv_response_len < 6) {
/* EOL came too soon */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid response from SCP server, too short",
0);
goto scp_recv_error;
}
s = (char *) session->scpRecv_response + 1;
p = strchr(s, ' ');
if (!p || ((p - s) <= 0)) {
/* No spaces or space in the wrong spot */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid response from SCP server, malformed mode",
0);
goto scp_recv_error;
}
*(p++) = '\0';
/* Make sure we don't get fooled by leftover values */
errno = 0;
session->scpRecv_mode = strtol(s, &e, 8);
if ((e && *e) || errno) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid response from SCP server, invalid mode",
0);
goto scp_recv_error;
}
s = strchr(p, ' ');
if (!s || ((s - p) <= 0)) {
/* No spaces or space in the wrong spot */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid response from SCP server, too short or malformed",
0);
goto scp_recv_error;
}
*(s++) = '\0';
/* Make sure we don't get fooled by leftover values */
errno = 0;
session->scpRecv_size = scpsize_strtol(p, &e, 10);
if ((e && *e) || errno) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid response from SCP server, invalid size",
0);
goto scp_recv_error;
}
/* SCP ACK */
session->scpRecv_response[0] = '\0';
session->scpRecv_state = libssh2_NB_state_sent6;
}
if (session->scpRecv_state == libssh2_NB_state_sent6) {
rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
(char *) session->
scpRecv_response, 1);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block sending SCP ACK", 0);
return NULL;
} else if (rc != 1) {
goto scp_recv_error;
}
_libssh2_debug(session, LIBSSH2_DBG_SCP,
"mode = 0%lo size = %ld", session->scpRecv_mode,
session->scpRecv_size);
/* We *should* check that basename is valid, but why let that stop us? */
break;
}
}
session->scpRecv_state = libssh2_NB_state_sent7;
}
if (sb) {
memset(sb, 0, sizeof(struct stat));
sb->st_mtime = session->scpRecv_mtime;
sb->st_atime = session->scpRecv_atime;
sb->st_size = session->scpRecv_size;
sb->st_mode = session->scpRecv_mode;
}
session->scpRecv_state = libssh2_NB_state_idle;
return session->scpRecv_channel;
scp_recv_error:
while (libssh2_channel_free(session->scpRecv_channel) == PACKET_EAGAIN);
session->scpRecv_channel = NULL;
session->scpRecv_state = libssh2_NB_state_idle;
return NULL;
}
|
|||||
| ↓ | libssh2_session_free | 63 | 117 | 228 | src/session.c |
LIBSSH2_API int
libssh2_session_free(LIBSSH2_SESSION * session)
{
int rc;
if (session->free_state == libssh2_NB_state_idle) {
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Freeing session resource",
session->remote.banner);
session->state = libssh2_NB_state_created;
}
if (session->free_state == libssh2_NB_state_created) {
while (session->channels.head) {
LIBSSH2_CHANNEL *tmp = session->channels.head;
rc = libssh2_channel_free(session->channels.head);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
}
if (tmp == session->channels.head) {
/* channel_free couldn't do it's job, perform a messy cleanup */
tmp = session->channels.head;
/* unlink */
session->channels.head = tmp->next;
/* free */
LIBSSH2_FREE(session, tmp);
/* reverse linking isn't important here, we're killing the structure */
}
}
session->state = libssh2_NB_state_sent;
}
if (session->state == libssh2_NB_state_sent) {
while (session->listeners) {
rc = libssh2_channel_forward_cancel(session->listeners);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
}
}
session->state = libssh2_NB_state_sent1;
}
if (session->state & LIBSSH2_STATE_NEWKEYS) {
/* hostkey */
if (session->hostkey && session->hostkey->dtor) {
session->hostkey->dtor(session, &session->server_hostkey_abstract);
}
/* Client to Server */
/* crypt */
if (session->local.crypt && session->local.crypt->dtor) {
session->local.crypt->dtor(session,
&session->local.crypt_abstract);
}
/* comp */
if (session->local.comp && session->local.comp->dtor) {
session->local.comp->dtor(session, 1,
&session->local.comp_abstract);
}
/* mac */
if (session->local.mac && session->local.mac->dtor) {
session->local.mac->dtor(session, &session->local.mac_abstract);
}
/* Server to Client */
/* crypt */
if (session->remote.crypt && session->remote.crypt->dtor) {
session->remote.crypt->dtor(session,
&session->remote.crypt_abstract);
}
/* comp */
if (session->remote.comp && session->remote.comp->dtor) {
session->remote.comp->dtor(session, 0,
&session->remote.comp_abstract);
}
/* mac */
if (session->remote.mac && session->remote.mac->dtor) {
session->remote.mac->dtor(session, &session->remote.mac_abstract);
}
/* session_id */
if (session->session_id) {
LIBSSH2_FREE(session, session->session_id);
}
}
/* Free banner(s) */
if (session->remote.banner) {
LIBSSH2_FREE(session, session->remote.banner);
}
if (session->local.banner) {
LIBSSH2_FREE(session, session->local.banner);
}
/* Free preference(s) */
if (session->kex_prefs) {
LIBSSH2_FREE(session, session->kex_prefs);
}
if (session->hostkey_prefs) {
LIBSSH2_FREE(session, session->hostkey_prefs);
}
if (session->local.crypt_prefs) {
LIBSSH2_FREE(session, session->local.crypt_prefs);
}
if (session->local.mac_prefs) {
LIBSSH2_FREE(session, session->local.mac_prefs);
}
if (session->local.comp_prefs) {
LIBSSH2_FREE(session, session->local.comp_prefs);
}
if (session->local.lang_prefs) {
LIBSSH2_FREE(session, session->local.lang_prefs);
}
if (session->remote.crypt_prefs) {
LIBSSH2_FREE(session, session->remote.crypt_prefs);
}
if (session->remote.mac_prefs) {
LIBSSH2_FREE(session, session->remote.mac_prefs);
}
if (session->remote.comp_prefs) {
LIBSSH2_FREE(session, session->remote.comp_prefs);
}
if (session->remote.lang_prefs) {
LIBSSH2_FREE(session, session->remote.lang_prefs);
}
/*
* Make sure all memory used in the state variables are free
*/
if (session->startup_data) {
LIBSSH2_FREE(session, session->startup_data);
}
if (session->disconnect_data) {
LIBSSH2_FREE(session, session->disconnect_data);
}
if (session->userauth_list_data) {
LIBSSH2_FREE(session, session->userauth_list_data);
}
if (session->userauth_pswd_data) {
LIBSSH2_FREE(session, session->userauth_pswd_data);
}
if (session->userauth_pswd_newpw) {
LIBSSH2_FREE(session, session->userauth_pswd_newpw);
}
if (session->userauth_host_packet) {
LIBSSH2_FREE(session, session->userauth_host_packet);
}
if (session->userauth_host_method) {
LIBSSH2_FREE(session, session->userauth_host_method);
}
if (session->userauth_host_data) {
LIBSSH2_FREE(session, session->userauth_host_data);
}
if (session->userauth_pblc_data) {
LIBSSH2_FREE(session, session->userauth_pblc_data);
}
if (session->userauth_pblc_packet) {
LIBSSH2_FREE(session, session->userauth_pblc_packet);
}
if (session->userauth_pblc_method) {
LIBSSH2_FREE(session, session->userauth_pblc_method);
}
if (session->userauth_kybd_data) {
LIBSSH2_FREE(session, session->userauth_kybd_data);
}
if (session->userauth_kybd_packet) {
LIBSSH2_FREE(session, session->userauth_kybd_packet);
}
if (session->userauth_kybd_auth_instruction) {
LIBSSH2_FREE(session, session->userauth_kybd_auth_instruction);
}
if (session->open_packet) {
LIBSSH2_FREE(session, session->open_packet);
}
if (session->open_data) {
LIBSSH2_FREE(session, session->open_data);
}
if (session->direct_message) {
LIBSSH2_FREE(session, session->direct_message);
}
if (session->fwdLstn_packet) {
LIBSSH2_FREE(session, session->fwdLstn_packet);
}
if (session->pkeyInit_data) {
LIBSSH2_FREE(session, session->pkeyInit_data);
}
if (session->scpRecv_command) {
LIBSSH2_FREE(session, session->scpRecv_command);
}
if (session->scpSend_command) {
LIBSSH2_FREE(session, session->scpSend_command);
}
if (session->scpRecv_err_msg) {
LIBSSH2_FREE(session, session->scpRecv_err_msg);
}
if (session->scpSend_err_msg) {
LIBSSH2_FREE(session, session->scpSend_err_msg);
}
/* Free the error message, if we ar supposed to */
if (session->err_msg && session->err_should_free) {
LIBSSH2_FREE(session, session->err_msg);
}
/* Cleanup any remaining packets */
while (session->packets.head) {
LIBSSH2_PACKET *tmp = session->packets.head;
/* unlink */
session->packets.head = tmp->next;
/* free */
LIBSSH2_FREE(session, tmp->data);
LIBSSH2_FREE(session, tmp);
}
LIBSSH2_FREE(session, session);
return 0;
}
|
|||||
| ↓ | libssh2_poll | 70 | 159 | 298 | src/session.c |
LIBSSH2_API int
libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout)
{
long timeout_remaining;
unsigned int i, active_fds;
#ifdef HAVE_POLL
LIBSSH2_SESSION *session = NULL;
#ifdef HAVE_ALLOCA
struct pollfd *sockets = alloca(sizeof(struct pollfd) * nfds);
#else
struct pollfd sockets[256];
if (nfds > 256)
/* systems without alloca use a fixed-size array, this can be fixed
if we really want to, at least if the compiler is a C99 capable one */
return -1;
#endif
/* Setup sockets for polling */
for(i = 0; i < nfds; i++) {
fds[i].revents = 0;
switch (fds[i].type) {
case LIBSSH2_POLLFD_SOCKET:
sockets[i].fd = fds[i].fd.socket;
sockets[i].events = fds[i].events;
sockets[i].revents = 0;
break;
case LIBSSH2_POLLFD_CHANNEL:
sockets[i].fd = fds[i].fd.channel->session->socket_fd;
sockets[i].events = POLLIN;
sockets[i].revents = 0;
if (!session)
session = fds[i].fd.channel->session;
break;
case LIBSSH2_POLLFD_LISTENER:
sockets[i].fd = fds[i].fd.listener->session->socket_fd;
sockets[i].events = POLLIN;
sockets[i].revents = 0;
if (!session)
session = fds[i].fd.listener->session;
break;
default:
if (session)
libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE,
"Invalid descriptor passed to libssh2_poll()",
0);
return -1;
}
}
#elif defined(HAVE_SELECT)
LIBSSH2_SESSION *session = NULL;
int maxfd = 0;
fd_set rfds, wfds;
struct timeval tv;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
for(i = 0; i < nfds; i++) {
fds[i].revents = 0;
switch (fds[i].type) {
case LIBSSH2_POLLFD_SOCKET:
if (fds[i].events & LIBSSH2_POLLFD_POLLIN) {
FD_SET(fds[i].fd.socket, &rfds);
if (fds[i].fd.socket > maxfd)
maxfd = fds[i].fd.socket;
}
if (fds[i].events & LIBSSH2_POLLFD_POLLOUT) {
FD_SET(fds[i].fd.socket, &wfds);
if (fds[i].fd.socket > maxfd)
maxfd = fds[i].fd.socket;
}
break;
case LIBSSH2_POLLFD_CHANNEL:
FD_SET(fds[i].fd.channel->session->socket_fd, &rfds);
if (fds[i].fd.channel->session->socket_fd > maxfd)
maxfd = fds[i].fd.channel->session->socket_fd;
if (!session)
session = fds[i].fd.channel->session;
break;
case LIBSSH2_POLLFD_LISTENER:
FD_SET(fds[i].fd.listener->session->socket_fd, &rfds);
if (fds[i].fd.listener->session->socket_fd > maxfd)
maxfd = fds[i].fd.listener->session->socket_fd;
if (!session)
session = fds[i].fd.listener->session;
break;
default:
if (session)
libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE,
"Invalid descriptor passed to libssh2_poll()",
0);
return -1;
}
}
#else
/* No select() or poll()
* no sockets sturcture to setup
*/
timeout = 0;
#endif /* HAVE_POLL or HAVE_SELECT */
timeout_remaining = timeout;
do {
#if defined(HAVE_POLL) || defined(HAVE_SELECT)
int sysret;
#endif
active_fds = 0;
for(i = 0; i < nfds; i++) {
if (fds[i].events != fds[i].revents) {
switch (fds[i].type) {
case LIBSSH2_POLLFD_CHANNEL:
if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want to be ready for read */
((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* Not yet known to be ready for read */
fds[i].revents |=
libssh2_poll_channel_read(fds[i].fd.channel,
0) ?
LIBSSH2_POLLFD_POLLIN : 0;
}
if ((fds[i].events & LIBSSH2_POLLFD_POLLEXT) && /* Want to be ready for extended read */
((fds[i].revents & LIBSSH2_POLLFD_POLLEXT) == 0)) { /* Not yet known to be ready for extended read */
fds[i].revents |=
libssh2_poll_channel_read(fds[i].fd.channel,
1) ?
LIBSSH2_POLLFD_POLLEXT : 0;
}
if ((fds[i].events & LIBSSH2_POLLFD_POLLOUT) && /* Want to be ready for write */
((fds[i].revents & LIBSSH2_POLLFD_POLLOUT) == 0)) { /* Not yet known to be ready for write */
fds[i].revents |=
libssh2_poll_channel_write(fds[i].fd.
channel) ?
LIBSSH2_POLLFD_POLLOUT : 0;
}
if (fds[i].fd.channel->remote.close
|| fds[i].fd.channel->local.close) {
fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED;
}
if (fds[i].fd.channel->session->socket_state ==
LIBSSH2_SOCKET_DISCONNECTED) {
fds[i].revents |=
LIBSSH2_POLLFD_CHANNEL_CLOSED |
LIBSSH2_POLLFD_SESSION_CLOSED;
}
break;
case LIBSSH2_POLLFD_LISTENER:
if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want a connection */
((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* No connections known of yet */
fds[i].revents |=
libssh2_poll_listener_queued(fds[i].fd.
listener) ?
LIBSSH2_POLLFD_POLLIN : 0;
}
if (fds[i].fd.listener->session->socket_state ==
LIBSSH2_SOCKET_DISCONNECTED) {
fds[i].revents |=
LIBSSH2_POLLFD_LISTENER_CLOSED |
LIBSSH2_POLLFD_SESSION_CLOSED;
}
break;
}
}
if (fds[i].revents) {
active_fds++;
}
}
if (active_fds) {
/* Don't block on the sockets if we have channels/listeners which are ready */
timeout_remaining = 0;
}
#ifdef HAVE_POLL
#ifdef HAVE_GETTIMEOFDAY
{
struct timeval tv_begin, tv_end;
gettimeofday((struct timeval *) &tv_begin, NULL);
sysret = poll(sockets, nfds, timeout_remaining);
gettimeofday((struct timeval *) &tv_end, NULL);
timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
}
#else
/* If the platform doesn't support gettimeofday,
* then just make the call non-blocking and walk away
*/
sysret = poll(sockets, nfds, timeout_remaining);
timeout_remaining = 0;
#endif /* HAVE_GETTIMEOFDAY */
if (sysret > 0) {
for(i = 0; i < nfds; i++) {
switch (fds[i].type) {
case LIBSSH2_POLLFD_SOCKET:
fds[i].revents = sockets[i].revents;
sockets[i].revents = 0; /* In case we loop again, be nice */
if (fds[i].revents) {
active_fds++;
}
break;
case LIBSSH2_POLLFD_CHANNEL:
if (sockets[i].events & POLLIN) {
/* Spin session until no data available */
while (libssh2_packet_read(fds[i].fd.channel->session)
> 0);
}
if (sockets[i].revents & POLLHUP) {
fds[i].revents |=
LIBSSH2_POLLFD_CHANNEL_CLOSED |
LIBSSH2_POLLFD_SESSION_CLOSED;
}
sockets[i].revents = 0;
break;
case LIBSSH2_POLLFD_LISTENER:
if (sockets[i].events & POLLIN) {
/* Spin session until no data available */
while (libssh2_packet_read(fds[i].fd.listener->session)
> 0);
}
if (sockets[i].revents & POLLHUP) {
fds[i].revents |=
LIBSSH2_POLLFD_LISTENER_CLOSED |
LIBSSH2_POLLFD_SESSION_CLOSED;
}
sockets[i].revents = 0;
break;
}
}
}
#elif defined(HAVE_SELECT)
tv.tv_sec = timeout_remaining / 1000;
tv.tv_usec = (timeout_remaining % 1000) * 1000;
#ifdef HAVE_GETTIMEOFDAY
{
struct timeval tv_begin, tv_end;
gettimeofday((struct timeval *) &tv_begin, NULL);
sysret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
gettimeofday((struct timeval *) &tv_end, NULL);
timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
}
#else
/* If the platform doesn't support gettimeofday,
* then just make the call non-blocking and walk away
*/
sysret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
timeout_remaining = 0;
#endif
if (sysret > 0) {
for(i = 0; i < nfds; i++) {
switch (fds[i].type) {
case LIBSSH2_POLLFD_SOCKET:
if (FD_ISSET(fds[i].fd.socket, &rfds)) {
fds[i].revents |= LIBSSH2_POLLFD_POLLIN;
}
if (FD_ISSET(fds[i].fd.socket, &wfds)) {
fds[i].revents |= LIBSSH2_POLLFD_POLLOUT;
}
if (fds[i].revents) {
active_fds++;
}
break;
case LIBSSH2_POLLFD_CHANNEL:
if (FD_ISSET(fds[i].fd.channel->session->socket_fd, &rfds)) {
/* Spin session until no data available */
while (libssh2_packet_read(fds[i].fd.channel->session)
> 0);
}
break;
case LIBSSH2_POLLFD_LISTENER:
if (FD_ISSET
(fds[i].fd.listener->session->socket_fd, &rfds)) {
/* Spin session until no data available */
while (libssh2_packet_read(fds[i].fd.listener->session)
> 0);
}
break;
}
}
}
#endif /* else no select() or poll() -- timeout (and by extension timeout_remaining) will be equal to 0 */
} while ((timeout_remaining > 0) && !active_fds);
return active_fds;
}
|
|||||
| ↓ | libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange | 60 | 294 | 581 | src/kex.c |
static int
libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *
session,
_libssh2_bn * g,
_libssh2_bn * p,
int group_order,
unsigned char
packet_type_init,
unsigned char
packet_type_reply,
unsigned char
*midhash,
unsigned long
midhash_len,
kmdhgGPsha1kex_state_t
* exchange_state)
{
int ret = 0;
int rc;
if (exchange_state->state == libssh2_NB_state_idle) {
/* Setup initial values */
exchange_state->e_packet = NULL;
exchange_state->s_packet = NULL;
exchange_state->k_value = NULL;
exchange_state->ctx = _libssh2_bn_ctx_new();
exchange_state->x = _libssh2_bn_init(); /* Random from client */
exchange_state->e = _libssh2_bn_init(); /* g^x mod p */
exchange_state->f = _libssh2_bn_init(); /* g^(Random from server) mod p */
exchange_state->k = _libssh2_bn_init(); /* The shared secret: f^x mod p */
/* Zero the whole thing out */
memset(&exchange_state->req_state, 0, sizeof(packet_require_state_t));
/* Generate x and e */
_libssh2_bn_rand(exchange_state->x, group_order, 0, -1);
_libssh2_bn_mod_exp(exchange_state->e, g, exchange_state->x, p,
exchange_state->ctx);
/* Send KEX init */
/* packet_type(1) + String Length(4) + leading 0(1) */
exchange_state->e_packet_len =
_libssh2_bn_bytes(exchange_state->e) + 6;
if (_libssh2_bn_bits(exchange_state->e) % 8) {
/* Leading 00 not needed */
exchange_state->e_packet_len--;
}
exchange_state->e_packet =
LIBSSH2_ALLOC(session, exchange_state->e_packet_len);
if (!exchange_state->e_packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Out of memory error",
0);
ret = -1;
goto clean_exit;
}
exchange_state->e_packet[0] = packet_type_init;
libssh2_htonu32(exchange_state->e_packet + 1,
exchange_state->e_packet_len - 5);
if (_libssh2_bn_bits(exchange_state->e) % 8) {
_libssh2_bn_to_bin(exchange_state->e,
exchange_state->e_packet + 5);
} else {
exchange_state->e_packet[5] = 0;
_libssh2_bn_to_bin(exchange_state->e,
exchange_state->e_packet + 6);
}
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending KEX packet %d",
(int) packet_type_init);
exchange_state->state = libssh2_NB_state_created;
}
if (exchange_state->state == libssh2_NB_state_created) {
rc = libssh2_packet_write(session, exchange_state->e_packet,
exchange_state->e_packet_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send KEX init message", 0);
ret = -1;
goto clean_exit;
}
exchange_state->state = libssh2_NB_state_sent;
}
if (exchange_state->state == libssh2_NB_state_sent) {
if (session->burn_optimistic_kexinit) {
/* The first KEX packet to come along will be the guess initially
* sent by the server. That guess turned out to be wrong so we
* need to silently ignore it */
int burn_type;
_libssh2_debug(session, LIBSSH2_DBG_KEX,
"Waiting for badly guessed KEX packet (to be ignored)");
burn_type =
libssh2_packet_burn(session, &exchange_state->burn_state);
if (burn_type == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (burn_type <= 0) {
/* Failed to receive a packet */
ret = -1;
goto clean_exit;
}
session->burn_optimistic_kexinit = 0;
_libssh2_debug(session, LIBSSH2_DBG_KEX,
"Burnt packet of type: %02x",
(unsigned int) burn_type);
}
exchange_state->state = libssh2_NB_state_sent1;
}
if (exchange_state->state == libssh2_NB_state_sent1) {
/* Wait for KEX reply */
rc = libssh2_packet_require_ex(session, packet_type_reply,
&exchange_state->s_packet,
&exchange_state->s_packet_len, 0, NULL,
0, &exchange_state->req_state);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
}
if (rc) {
libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
"Timed out waiting for KEX reply", 0);
ret = -1;
goto clean_exit;
}
/* Parse KEXDH_REPLY */
exchange_state->s = exchange_state->s_packet + 1;
session->server_hostkey_len = libssh2_ntohu32(exchange_state->s);
exchange_state->s += 4;
session->server_hostkey =
LIBSSH2_ALLOC(session, session->server_hostkey_len);
if (!session->server_hostkey) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for a copy of the host key",
0);
ret = -1;
goto clean_exit;
}
memcpy(session->server_hostkey, exchange_state->s,
session->server_hostkey_len);
exchange_state->s += session->server_hostkey_len;
#if LIBSSH2_MD5
{
libssh2_md5_ctx fingerprint_ctx;
libssh2_md5_init(&fingerprint_ctx);
libssh2_md5_update(fingerprint_ctx, session->server_hostkey,
session->server_hostkey_len);
libssh2_md5_final(fingerprint_ctx, session->server_hostkey_md5);
}
#ifdef LIBSSH2DEBUG
{
char fingerprint[50], *fprint = fingerprint;
int i;
for(i = 0; i < 16; i++, fprint += 3) {
snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]);
}
*(--fprint) = '\0';
_libssh2_debug(session, LIBSSH2_DBG_KEX,
"Server's MD5 Fingerprint: %s", fingerprint);
}
#endif /* LIBSSH2DEBUG */
#endif /* ! LIBSSH2_MD5 */
{
libssh2_sha1_ctx fingerprint_ctx;
libssh2_sha1_init(&fingerprint_ctx);
libssh2_sha1_update(fingerprint_ctx, session->server_hostkey,
session->server_hostkey_len);
libssh2_sha1_final(fingerprint_ctx, session->server_hostkey_sha1);
}
#ifdef LIBSSH2DEBUG
{
char fingerprint[64], *fprint = fingerprint;
int i;
for(i = 0; i < 20; i++, fprint += 3) {
snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]);
}
*(--fprint) = '\0';
_libssh2_debug(session, LIBSSH2_DBG_KEX,
"Server's SHA1 Fingerprint: %s", fingerprint);
}
#endif /* LIBSSH2DEBUG */
if (session->hostkey->
init(session, session->server_hostkey, session->server_hostkey_len,
&session->server_hostkey_abstract)) {
libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT,
"Unable to initialize hostkey importer", 0);
ret = -1;
goto clean_exit;
}
exchange_state->f_value_len = libssh2_ntohu32(exchange_state->s);
exchange_state->s += 4;
exchange_state->f_value = exchange_state->s;
exchange_state->s += exchange_state->f_value_len;
_libssh2_bn_from_bin(exchange_state->f, exchange_state->f_value_len,
exchange_state->f_value);
exchange_state->h_sig_len = libssh2_ntohu32(exchange_state->s);
exchange_state->s += 4;
exchange_state->h_sig = exchange_state->s;
/* Compute the shared secret */
_libssh2_bn_mod_exp(exchange_state->k, exchange_state->f,
exchange_state->x, p, exchange_state->ctx);
exchange_state->k_value_len = _libssh2_bn_bytes(exchange_state->k) + 5;
if (_libssh2_bn_bits(exchange_state->k) % 8) {
/* don't need leading 00 */
exchange_state->k_value_len--;
}
exchange_state->k_value =
LIBSSH2_ALLOC(session, exchange_state->k_value_len);
if (!exchange_state->k_value) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate buffer for K", 0);
ret = -1;
goto clean_exit;
}
libssh2_htonu32(exchange_state->k_value,
exchange_state->k_value_len - 4);
if (_libssh2_bn_bits(exchange_state->k) % 8) {
_libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4);
} else {
exchange_state->k_value[4] = 0;
_libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5);
}
libssh2_sha1_init(&exchange_state->exchange_hash);
if (session->local.banner) {
libssh2_htonu32(exchange_state->h_sig_comp,
strlen((char *) session->local.banner) - 2);
libssh2_sha1_update(exchange_state->exchange_hash,
exchange_state->h_sig_comp, 4);
libssh2_sha1_update(exchange_state->exchange_hash,
(char *) session->local.banner,
strlen((char *) session->local.banner) - 2);
} else {
libssh2_htonu32(exchange_state->h_sig_comp,
sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
libssh2_sha1_update(exchange_state->exchange_hash,
exchange_state->h_sig_comp, 4);
libssh2_sha1_update(exchange_state->exchange_hash,
LIBSSH2_SSH_DEFAULT_BANNER,
sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
}
libssh2_htonu32(exchange_state->h_sig_comp,
strlen((char *) session->remote.banner));
libssh2_sha1_update(exchange_state->exchange_hash,
exchange_state->h_sig_comp, 4);
libssh2_sha1_update(exchange_state->exchange_hash,
session->remote.banner,
strlen((char *) session->remote.banner));
libssh2_htonu32(exchange_state->h_sig_comp,
session->local.kexinit_len);
libssh2_sha1_update(exchange_state->exchange_hash,
exchange_state->h_sig_comp, 4);
libssh2_sha1_update(exchange_state->exchange_hash,
session->local.kexinit,
session->local.kexinit_len);
libssh2_htonu32(exchange_state->h_sig_comp,
session->remote.kexinit_len);
libssh2_sha1_update(exchange_state->exchange_hash,
exchange_state->h_sig_comp, 4);
libssh2_sha1_update(exchange_state->exchange_hash,
session->remote.kexinit,
session->remote.kexinit_len);
libssh2_htonu32(exchange_state->h_sig_comp,
session->server_hostkey_len);
libssh2_sha1_update(exchange_state->exchange_hash,
exchange_state->h_sig_comp, 4);
libssh2_sha1_update(exchange_state->exchange_hash,
session->server_hostkey,
session->server_hostkey_len);
if (packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) {
/* diffie-hellman-group-exchange hashes additional fields */
#ifdef LIBSSH2_DH_GEX_NEW
libssh2_htonu32(exchange_state->h_sig_comp,
LIBSSH2_DH_GEX_MINGROUP);
libssh2_htonu32(exchange_state->h_sig_comp + 4,
LIBSSH2_DH_GEX_OPTGROUP);
libssh2_htonu32(exchange_state->h_sig_comp + 8,
LIBSSH2_DH_GEX_MAXGROUP);
libssh2_sha1_update(exchange_state->exchange_hash,
exchange_state->h_sig_comp, 12);
#else
libssh2_htonu32(exchange_state->h_sig_comp,
LIBSSH2_DH_GEX_OPTGROUP);
libssh2_sha1_update(exchange_state->exchange_hash,
exchange_state->h_sig_comp, 4);
#endif
}
if (midhash) {
libssh2_sha1_update(exchange_state->exchange_hash, midhash,
midhash_len);
}
libssh2_sha1_update(exchange_state->exchange_hash,
exchange_state->e_packet + 1,
exchange_state->e_packet_len - 1);
libssh2_htonu32(exchange_state->h_sig_comp,
exchange_state->f_value_len);
libssh2_sha1_update(exchange_state->exchange_hash,
exchange_state->h_sig_comp, 4);
libssh2_sha1_update(exchange_state->exchange_hash,
exchange_state->f_value,
exchange_state->f_value_len);
libssh2_sha1_update(exchange_state->exchange_hash,
exchange_state->k_value,
exchange_state->k_value_len);
libssh2_sha1_final(exchange_state->exchange_hash,
exchange_state->h_sig_comp);
if (session->hostkey->
sig_verify(session, exchange_state->h_sig,
exchange_state->h_sig_len, exchange_state->h_sig_comp,
20, &session->server_hostkey_abstract)) {
libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN,
"Unable to verify hostkey signature", 0);
ret = -1;
goto clean_exit;
}
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending NEWKEYS message");
exchange_state->c = SSH_MSG_NEWKEYS;
exchange_state->state = libssh2_NB_state_sent2;
}
if (exchange_state->state == libssh2_NB_state_sent2) {
rc = libssh2_packet_write(session, &exchange_state->c, 1);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send NEWKEYS message", 0);
ret = -1;
goto clean_exit;
}
exchange_state->state = libssh2_NB_state_sent3;
}
if (exchange_state->state == libssh2_NB_state_sent3) {
rc = libssh2_packet_require_ex(session, SSH_MSG_NEWKEYS,
&exchange_state->tmp,
&exchange_state->tmp_len, 0, NULL, 0,
&exchange_state->req_state);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
"Timed out waiting for NEWKEYS", 0);
ret = -1;
goto clean_exit;
}
/* The first key exchange has been performed,
switch to active crypt/comp/mac mode */
session->state |= LIBSSH2_STATE_NEWKEYS;
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Received NEWKEYS message");
/* This will actually end up being just packet_type(1)
for this packet type anyway */
LIBSSH2_FREE(session, exchange_state->tmp);
if (!session->session_id) {
session->session_id = LIBSSH2_ALLOC(session, SHA_DIGEST_LENGTH);
if (!session->session_id) {
ret = -1;
goto clean_exit;
}
memcpy(session->session_id, exchange_state->h_sig_comp,
SHA_DIGEST_LENGTH);
session->session_id_len = SHA_DIGEST_LENGTH;
_libssh2_debug(session, LIBSSH2_DBG_KEX, "session_id calculated");
}
/* Cleanup any existing cipher */
if (session->local.crypt->dtor) {
session->local.crypt->dtor(session,
&session->local.crypt_abstract);
}
/* Calculate IV/Secret/Key for each direction */
if (session->local.crypt->init) {
unsigned char *iv = NULL, *secret = NULL;
int free_iv = 0, free_secret = 0;
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv,
session->local.crypt->
iv_len, "A");
if (!iv) {
ret = -1;
goto clean_exit;
}
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret,
session->local.crypt->
secret_len, "C");
if (!secret) {
LIBSSH2_FREE(session, iv);
ret = -1;
goto clean_exit;
}
if (session->local.crypt->
init(session, session->local.crypt, iv, &free_iv, secret,
&free_secret, 1, &session->local.crypt_abstract)) {
LIBSSH2_FREE(session, iv);
LIBSSH2_FREE(session, secret);
ret = -1;
goto clean_exit;
}
if (free_iv) {
memset(iv, 0, session->local.crypt->iv_len);
LIBSSH2_FREE(session, iv);
}
if (free_secret) {
memset(secret, 0, session->local.crypt->secret_len);
LIBSSH2_FREE(session, secret);
}
}
_libssh2_debug(session, LIBSSH2_DBG_KEX,
"Client to Server IV and Key calculated");
if (session->remote.crypt->dtor) {
/* Cleanup any existing cipher */
session->remote.crypt->dtor(session,
&session->remote.crypt_abstract);
}
if (session->remote.crypt->init) {
unsigned char *iv = NULL, *secret = NULL;
int free_iv = 0, free_secret = 0;
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv,
session->remote.crypt->
iv_len, "B");
if (!iv) {
ret = -1;
goto clean_exit;
}
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret,
session->remote.crypt->
secret_len, "D");
if (!secret) {
LIBSSH2_FREE(session, iv);
ret = -1;
goto clean_exit;
}
if (session->remote.crypt->
init(session, session->remote.crypt, iv, &free_iv, secret,
&free_secret, 0, &session->remote.crypt_abstract)) {
LIBSSH2_FREE(session, iv);
LIBSSH2_FREE(session, secret);
ret = -1;
goto clean_exit;
}
if (free_iv) {
memset(iv, 0, session->remote.crypt->iv_len);
LIBSSH2_FREE(session, iv);
}
if (free_secret) {
memset(secret, 0, session->remote.crypt->secret_len);
LIBSSH2_FREE(session, secret);
}
}
_libssh2_debug(session, LIBSSH2_DBG_KEX,
"Server to Client IV and Key calculated");
if (session->local.mac->dtor) {
session->local.mac->dtor(session, &session->local.mac_abstract);
}
if (session->local.mac->init) {
unsigned char *key = NULL;
int free_key = 0;
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key,
session->local.mac->
key_len, "E");
if (!key) {
ret = -1;
goto clean_exit;
}
session->local.mac->init(session, key, &free_key,
&session->local.mac_abstract);
if (free_key) {
memset(key, 0, session->local.mac->key_len);
LIBSSH2_FREE(session, key);
}
}
_libssh2_debug(session, LIBSSH2_DBG_KEX,
"Client to Server HMAC Key calculated");
if (session->remote.mac->dtor) {
session->remote.mac->dtor(session, &session->remote.mac_abstract);
}
if (session->remote.mac->init) {
unsigned char *key = NULL;
int free_key = 0;
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key,
session->remote.mac->
key_len, "F");
if (!key) {
ret = -1;
goto clean_exit;
}
session->remote.mac->init(session, key, &free_key,
&session->remote.mac_abstract);
if (free_key) {
memset(key, 0, session->remote.mac->key_len);
LIBSSH2_FREE(session, key);
}
}
_libssh2_debug(session, LIBSSH2_DBG_KEX,
"Server to Client HMAC Key calculated");
}
clean_exit:
_libssh2_bn_free(exchange_state->x);
exchange_state->x = NULL;
_libssh2_bn_free(exchange_state->e);
exchange_state->e = NULL;
_libssh2_bn_free(exchange_state->f);
exchange_state->f = NULL;
_libssh2_bn_free(exchange_state->k);
exchange_state->k = NULL;
_libssh2_bn_ctx_free(exchange_state->ctx);
exchange_state->ctx = NULL;
if (exchange_state->e_packet) {
LIBSSH2_FREE(session, exchange_state->e_packet);
exchange_state->e_packet = NULL;
}
if (exchange_state->s_packet) {
LIBSSH2_FREE(session, exchange_state->s_packet);
exchange_state->s_packet = NULL;
}
if (exchange_state->k_value) {
LIBSSH2_FREE(session, exchange_state->k_value);
exchange_state->k_value = NULL;
}
if (session->server_hostkey) {
LIBSSH2_FREE(session, session->server_hostkey);
session->server_hostkey = NULL;
}
exchange_state->state = libssh2_NB_state_idle;
return ret;
}
|
|||||
| ↓ | libssh2_packet_add | 57 | 204 | 510 | src/packet.c |
int
libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
size_t datalen, int macstate)
{
int rc;
if (session->packAdd_state == libssh2_NB_state_idle) {
session->packAdd_data_head = 0;
/* Zero the whole thing out */
memset(&session->packAdd_key_state, 0,
sizeof(session->packAdd_key_state));
/* Zero the whole thing out */
memset(&session->packAdd_Qlstn_state, 0,
sizeof(session->packAdd_Qlstn_state));
/* Zero the whole thing out */
memset(&session->packAdd_x11open_state, 0,
sizeof(session->packAdd_x11open_state));
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
"Packet type %d received, length=%d",
(int) data[0], (int) datalen);
if (macstate == LIBSSH2_MAC_INVALID) {
if (session->macerror) {
if (LIBSSH2_MACERROR(session, (char *) data, datalen) == 0) {
/* Calling app has given the OK, Process it anyway */
macstate = LIBSSH2_MAC_CONFIRMED;
} else {
libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
"Invalid Message Authentication Code received",
0);
if (session->ssh_msg_disconnect) {
LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR,
"Invalid MAC received",
sizeof("Invalid MAC received") - 1,
"", 0);
}
LIBSSH2_FREE(session, data);
return -1;
}
} else {
libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
"Invalid Message Authentication Code received",
0);
if (session->ssh_msg_disconnect) {
LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR,
"Invalid MAC received",
sizeof("Invalid MAC received") - 1,
"", 0);
}
LIBSSH2_FREE(session, data);
return -1;
}
}
session->packAdd_state = libssh2_NB_state_allocated;
}
/*
* =============================== NOTE ===============================
* I know this is very ugly and not a really good use of "goto", but
* this case statement would be even uglier to do it any other way
*/
if (session->packAdd_state == libssh2_NB_state_jump1) {
goto libssh2_packet_add_jump_point1;
} else if (session->packAdd_state == libssh2_NB_state_jump2) {
goto libssh2_packet_add_jump_point2;
} else if (session->packAdd_state == libssh2_NB_state_jump3) {
goto libssh2_packet_add_jump_point3;
}
if (session->packAdd_state == libssh2_NB_state_allocated) {
/* A couple exceptions to the packet adding rule: */
switch (data[0]) {
case SSH_MSG_DISCONNECT:
{
char *message, *language;
int reason, message_len, language_len;
reason = libssh2_ntohu32(data + 1);
message_len = libssh2_ntohu32(data + 5);
/* 9 = packet_type(1) + reason(4) + message_len(4) */
message = (char *) data + 9;
language_len = libssh2_ntohu32(data + 9 + message_len);
/*
* This is where we hack on the data a little,
* Use the MSB of language_len to to a terminating NULL
* (In all liklihood it is already)
* Shift the language tag back a byte (In all likelihood
* it's zero length anyway)
* Store a NULL in the last byte of the packet to terminate
* the language string
* With the lengths passed this isn't *REALLY* necessary,
* but it's "kind"
*/
message[message_len] = '\0';
language = (char *) data + 9 + message_len + 3;
if (language_len) {
memcpy(language, language + 1, language_len);
}
language[language_len] = '\0';
if (session->ssh_msg_disconnect) {
LIBSSH2_DISCONNECT(session, reason, message,
message_len, language, language_len);
}
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
"Disconnect(%d): %s(%s)", reason,
message, language);
LIBSSH2_FREE(session, data);
session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
session->packAdd_state = libssh2_NB_state_idle;
return -1;
}
break;
case SSH_MSG_IGNORE:
/* As with disconnect, back it up one and add a trailing NULL */
memcpy(data + 4, data + 5, datalen - 5);
data[datalen] = '\0';
if (session->ssh_msg_ignore) {
LIBSSH2_IGNORE(session, (char *) data + 4, datalen - 5);
}
LIBSSH2_FREE(session, data);
session->packAdd_state = libssh2_NB_state_idle;
return 0;
break;
case SSH_MSG_DEBUG:
{
int always_display = data[0];
char *message, *language;
int message_len, language_len;
message_len = libssh2_ntohu32(data + 2);
/* 6 = packet_type(1) + display(1) + message_len(4) */
message = (char *) data + 6;
language_len = libssh2_ntohu32(data + 6 + message_len);
/*
* This is where we hack on the data a little,
* Use the MSB of language_len to to a terminating NULL
* (In all liklihood it is already)
* Shift the language tag back a byte (In all likelihood
* it's zero length anyway)
* Store a NULL in the last byte of the packet to terminate
* the language string
* With the lengths passed this isn't *REALLY* necessary,
* but it's "kind"
*/
message[message_len] = '\0';
language = (char *) data + 6 + message_len + 3;
if (language_len) {
memcpy(language, language + 1, language_len);
}
language[language_len] = '\0';
if (session->ssh_msg_debug) {
LIBSSH2_DEBUG(session, always_display, message,
message_len, language, language_len);
}
/*
* _libssh2_debug will actually truncate this for us so
* that it's not an inordinate about of data
*/
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
"Debug Packet: %s", message);
LIBSSH2_FREE(session, data);
session->packAdd_state = libssh2_NB_state_idle;
return 0;
}
break;
case SSH_MSG_CHANNEL_EXTENDED_DATA:
/* streamid(4) */
session->packAdd_data_head += 4;
case SSH_MSG_CHANNEL_DATA:
/* packet_type(1) + channelno(4) + datalen(4) */
session->packAdd_data_head += 9;
{
session->packAdd_channel = libssh2_channel_locate(session,
libssh2_ntohu32
(data + 1));
if (!session->packAdd_channel) {
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN,
"Packet received for unknown channel, ignoring",
0);
LIBSSH2_FREE(session, data);
session->packAdd_state = libssh2_NB_state_idle;
return 0;
}
#ifdef LIBSSH2DEBUG
{
unsigned long stream_id = 0;
if (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) {
stream_id = libssh2_ntohu32(data + 5);
}
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"%d bytes received for channel %lu/%lu stream #%lu",
(int) (datalen -
session->packAdd_data_head),
session->packAdd_channel->local.id,
session->packAdd_channel->remote.id,
stream_id);
}
#endif
if ((session->packAdd_channel->remote.
extended_data_ignore_mode ==
LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE)
&& (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)) {
/* Pretend we didn't receive this */
LIBSSH2_FREE(session, data);
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Ignoring extended data and refunding %d bytes",
(int) (datalen - 13));
/* Adjust the window based on the block we just freed */
libssh2_packet_add_jump_point1:
session->packAdd_state = libssh2_NB_state_jump1;
rc = libssh2_channel_receive_window_adjust(session->
packAdd_channel,
datalen - 13,
0);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
}
session->packAdd_state = libssh2_NB_state_idle;
return 0;
}
/*
* REMEMBER! remote means remote as source of data,
* NOT remote window!
*/
if (session->packAdd_channel->remote.packet_size <
(datalen - session->packAdd_data_head)) {
/*
* Spec says we MAY ignore bytes sent beyond
* packet_size
*/
libssh2_error(session,
LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED,
"Packet contains more data than we offered to receive, truncating",
0);
datalen =
session->packAdd_channel->remote.packet_size +
session->packAdd_data_head;
}
if (session->packAdd_channel->remote.window_size <= 0) {
/*
* Spec says we MAY ignore bytes sent beyond
* window_size
*/
libssh2_error(session,
LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
"The current receive window is full, data ignored",
0);
LIBSSH2_FREE(session, data);
session->packAdd_state = libssh2_NB_state_idle;
return 0;
}
/* Reset EOF status */
session->packAdd_channel->remote.eof = 0;
if ((datalen - session->packAdd_data_head) >
session->packAdd_channel->remote.window_size) {
libssh2_error(session,
LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
"Remote sent more data than current window allows, truncating",
0);
datalen =
session->packAdd_channel->remote.window_size +
session->packAdd_data_head;
} else {
/* Now that we've received it, shrink our window */
session->packAdd_channel->remote.window_size -=
datalen - session->packAdd_data_head;
}
}
break;
case SSH_MSG_CHANNEL_EOF:
{
session->packAdd_channel = libssh2_channel_locate(session,
libssh2_ntohu32
(data + 1));
if (!session->packAdd_channel) {
/* We may have freed already, just quietly ignore this... */
LIBSSH2_FREE(session, data);
session->packAdd_state = libssh2_NB_state_idle;
return 0;
}
_libssh2_debug(session,
LIBSSH2_DBG_CONN,
"EOF received for channel %lu/%lu",
session->packAdd_channel->local.id,
session->packAdd_channel->remote.id);
session->packAdd_channel->remote.eof = 1;
LIBSSH2_FREE(session, data);
session->packAdd_state = libssh2_NB_state_idle;
return 0;
}
break;
case SSH_MSG_CHANNEL_REQUEST:
{
if (libssh2_ntohu32(data + 5) == sizeof("exit-status") - 1
&& !memcmp("exit-status", data + 9,
sizeof("exit-status") - 1)) {
/* we've got "exit-status" packet. Set the session value */
session->packAdd_channel =
libssh2_channel_locate(session,
libssh2_ntohu32(data + 1));
if (session->packAdd_channel) {
session->packAdd_channel->exit_status =
libssh2_ntohu32(data + 9 + sizeof("exit-status"));
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Exit status %lu received for channel %lu/%lu",
session->packAdd_channel->exit_status,
session->packAdd_channel->local.id,
session->packAdd_channel->remote.id);
}
LIBSSH2_FREE(session, data);
session->packAdd_state = libssh2_NB_state_idle;
return 0;
}
}
break;
case SSH_MSG_CHANNEL_CLOSE:
{
session->packAdd_channel = libssh2_channel_locate(session,
libssh2_ntohu32
(data + 1));
if (!session->packAdd_channel) {
/* We may have freed already, just quietly ignore this... */
LIBSSH2_FREE(session, data);
session->packAdd_state = libssh2_NB_state_idle;
return 0;
}
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Close received for channel %lu/%lu",
session->packAdd_channel->local.id,
session->packAdd_channel->remote.id);
session->packAdd_channel->remote.close = 1;
session->packAdd_channel->remote.eof = 1;
/* TODO: Add a callback for this */
LIBSSH2_FREE(session, data);
session->packAdd_state = libssh2_NB_state_idle;
return 0;
}
break;
case SSH_MSG_CHANNEL_OPEN:
if ((datalen >= (sizeof("forwarded-tcpip") + 4)) &&
((sizeof("forwarded-tcpip") - 1) == libssh2_ntohu32(data + 1))
&&
(memcmp
(data + 5, "forwarded-tcpip",
sizeof("forwarded-tcpip") - 1) == 0)) {
libssh2_packet_add_jump_point2:
session->packAdd_state = libssh2_NB_state_jump2;
rc = libssh2_packet_queue_listener(session, data, datalen,
&session->
packAdd_Qlstn_state);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
}
LIBSSH2_FREE(session, data);
session->packAdd_state = libssh2_NB_state_idle;
return rc;
}
if ((datalen >= (sizeof("x11") + 4)) &&
((sizeof("x11") - 1) == libssh2_ntohu32(data + 1)) &&
(memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {
libssh2_packet_add_jump_point3:
session->packAdd_state = libssh2_NB_state_jump3;
rc = libssh2_packet_x11_open(session, data, datalen,
&session->packAdd_x11open_state);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
}
LIBSSH2_FREE(session, data);
session->packAdd_state = libssh2_NB_state_idle;
return rc;
}
break;
case SSH_MSG_CHANNEL_WINDOW_ADJUST:
{
unsigned long bytestoadd = libssh2_ntohu32(data + 5);
session->packAdd_channel = libssh2_channel_locate(session,
libssh2_ntohu32
(data + 1));
if (session->packAdd_channel && bytestoadd) {
session->packAdd_channel->local.window_size += bytestoadd;
}
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Window adjust received for channel %lu/%lu, adding %lu bytes, new window_size=%lu",
session->packAdd_channel->local.id,
session->packAdd_channel->remote.id,
bytestoadd,
session->packAdd_channel->local.window_size);
LIBSSH2_FREE(session, data);
session->packAdd_state = libssh2_NB_state_idle;
return 0;
}
break;
}
session->packAdd_state = libssh2_NB_state_sent;
}
if (session->packAdd_state == libssh2_NB_state_sent) {
session->packAdd_packet =
LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
if (!session->packAdd_packet) {
_libssh2_debug(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for LIBSSH2_PACKET");
LIBSSH2_FREE(session, data);
session->packAdd_state = libssh2_NB_state_idle;
return -1;
}
memset(session->packAdd_packet, 0, sizeof(LIBSSH2_PACKET));
session->packAdd_packet->data = data;
session->packAdd_packet->data_len = datalen;
session->packAdd_packet->data_head = session->packAdd_data_head;
session->packAdd_packet->mac = macstate;
session->packAdd_packet->brigade = &session->packets;
session->packAdd_packet->next = NULL;
if (session->packets.tail) {
session->packAdd_packet->prev = session->packets.tail;
session->packAdd_packet->prev->next = session->packAdd_packet;
session->packets.tail = session->packAdd_packet;
} else {
session->packets.head = session->packAdd_packet;
session->packets.tail = session->packAdd_packet;
session->packAdd_packet->prev = NULL;
}
session->packAdd_state = libssh2_NB_state_sent1;
}
if ((data[0] == SSH_MSG_KEXINIT &&
!(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) ||
(session->packAdd_state == libssh2_NB_state_sent2)) {
if (session->packAdd_state == libssh2_NB_state_sent1) {
/*
* Remote wants new keys
* Well, it's already in the brigade,
* let's just call back into ourselves
*/
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Renegotiating Keys");
session->packAdd_state = libssh2_NB_state_sent2;
}
/*
* The KEXINIT message has been added to the queue.
* The packAdd and readPack states need to be reset
* because libssh2_kex_exchange (eventually) calls upon
* libssh2_packet_read to read the rest of the key exchange
* conversation.
*/
session->readPack_state = libssh2_NB_state_idle;
session->packet.total_num = 0;
session->packAdd_state = libssh2_NB_state_idle;
session->fullpacket_state = libssh2_NB_state_idle;
/*
* Also, don't use packAdd_key_state for key re-exchange,
* as it will be wiped out in the middle of the exchange.
* How about re-using the startup_key_state?
*/
memset(&session->startup_key_state, 0, sizeof(key_exchange_state_t));
/*
* If there was a key reexchange failure, let's just hope we didn't
* send NEWKEYS yet, otherwise remote will drop us like a rock
*/
rc = libssh2_kex_exchange(session, 1, &session->startup_key_state);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
}
}
session->packAdd_state = libssh2_NB_state_idle;
return 0;
}
|
|||||
| ↓ | libssh2_scp_send_ex | 42 | 124 | 255 | src/scp.c |
LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode,
size_t size, long mtime, long atime)
{
int path_len = strlen(path);
unsigned const char *base;
int rc;
if (session->scpSend_state == libssh2_NB_state_idle) {
session->scpSend_command_len = path_len + sizeof("scp -t ");
if (mtime || atime) {
session->scpSend_command_len++;
}
session->scpSend_command =
LIBSSH2_ALLOC(session, session->scpSend_command_len);
if (!session->scpSend_command) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate a command buffer for scp session",
0);
return NULL;
}
if (mtime || atime) {
memcpy(session->scpSend_command, "scp -pt ",
sizeof("scp -pt ") - 1);
memcpy(session->scpSend_command + sizeof("scp -pt ") - 1, path,
path_len);
} else {
memcpy(session->scpSend_command, "scp -t ", sizeof("scp -t ") - 1);
memcpy(session->scpSend_command + sizeof("scp -t ") - 1, path,
path_len);
}
session->scpSend_command[session->scpSend_command_len - 1] = '\0';
_libssh2_debug(session, LIBSSH2_DBG_SCP,
"Opening channel for SCP send");
/* Allocate a channel */
session->scpSend_state = libssh2_NB_state_created;
}
if (session->scpSend_state == libssh2_NB_state_created) {
session->scpSend_channel =
libssh2_channel_open_ex(session, "session", sizeof("session") - 1,
LIBSSH2_CHANNEL_WINDOW_DEFAULT,
LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0);
if (!session->scpSend_channel) {
if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
/* previous call set libssh2_session_last_error(), pass it through */
LIBSSH2_FREE(session, session->scpSend_command);
session->scpSend_command = NULL;
session->scpSend_state = libssh2_NB_state_idle;
return NULL;
} else if (libssh2_session_last_errno(session) ==
LIBSSH2_ERROR_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block starting up channel", 0);
return NULL;
}
}
session->scpSend_state = libssh2_NB_state_sent;
}
if (session->scpSend_state == libssh2_NB_state_sent) {
/* Request SCP for the desired file */
rc = libssh2_channel_process_startup(session->scpSend_channel, "exec",
sizeof("exec") - 1,
(char *) session->scpSend_command,
session->scpSend_command_len);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block requesting SCP startup", 0);
return NULL;
} else if (rc) {
/* previous call set libssh2_session_last_error(), pass it through */
LIBSSH2_FREE(session, session->scpSend_command);
session->scpSend_command = NULL;
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Unknown error while getting error string", 0);
goto scp_send_error;
}
LIBSSH2_FREE(session, session->scpSend_command);
session->scpSend_command = NULL;
session->scpSend_state = libssh2_NB_state_sent1;
}
if (session->scpSend_state == libssh2_NB_state_sent1) {
/* Wait for ACK */
rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
(char *) session->scpSend_response, 1);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block waiting for response from remote", 0);
return NULL;
} else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid ACK response from remote", 0);
goto scp_send_error;
}
if (mtime || atime) {
/* Send mtime and atime to be used for file */
session->scpSend_response_len =
snprintf((char *) session->scpSend_response,
LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", mtime,
atime);
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s",
session->scpSend_response);
}
session->scpSend_state = libssh2_NB_state_sent2;
}
/* Send mtime and atime to be used for file */
if (mtime || atime) {
if (session->scpSend_state == libssh2_NB_state_sent2) {
rc = libssh2_channel_write_ex(session->scpSend_channel, 0,
(char *) session->scpSend_response,
session->scpSend_response_len);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block sending time data for SCP file", 0);
return NULL;
} else if (rc != session->scpSend_response_len) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send time data for SCP file", 0);
goto scp_send_error;
}
session->scpSend_state = libssh2_NB_state_sent3;
}
if (session->scpSend_state == libssh2_NB_state_sent3) {
/* Wait for ACK */
rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
(char *) session->scpSend_response,
1);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block waiting for response", 0);
return NULL;
} else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid ACK response from remote", 0);
goto scp_send_error;
}
session->scpSend_state = libssh2_NB_state_sent4;
}
} else {
if (session->scpSend_state == libssh2_NB_state_sent2) {
session->scpSend_state = libssh2_NB_state_sent4;
}
}
if (session->scpSend_state == libssh2_NB_state_sent4) {
/* Send mode, size, and basename */
base = (unsigned char *) strrchr(path, '/');
if (base) {
base++;
} else {
base = (unsigned char *) path;
}
session->scpSend_response_len =
snprintf((char *) session->scpSend_response,
LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %lu %s\n", mode,
(unsigned long) size, base);
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s",
session->scpSend_response);
session->scpSend_state = libssh2_NB_state_sent5;
}
if (session->scpSend_state == libssh2_NB_state_sent5) {
rc = libssh2_channel_write_ex(session->scpSend_channel, 0,
(char *) session->scpSend_response,
session->scpSend_response_len);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block send core file data for SCP file", 0);
return NULL;
} else if (rc != session->scpSend_response_len) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send core file data for SCP file", 0);
goto scp_send_error;
}
session->scpSend_state = libssh2_NB_state_sent6;
}
if (session->scpSend_state == libssh2_NB_state_sent6) {
/* Wait for ACK */
rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
(char *) session->scpSend_response, 1);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block waiting for response", 0);
return NULL;
} else if (rc <= 0) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid ACK response from remote", 0);
goto scp_send_error;
} else if (session->scpSend_response[0] != 0) {
/*
* Set this as the default error for here, if
* we are successful it will be replaced
*/
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
"Invalid ACK response from remote", 0);
session->scpSend_err_len =
libssh2_channel_packet_data_len(session->scpSend_channel, 0);
session->scpSend_err_msg =
LIBSSH2_ALLOC(session, session->scpSend_err_len + 1);
if (!session->scpSend_err_msg) {
goto scp_send_error;
}
memset(session->scpSend_err_msg, 0, session->scpSend_err_len + 1);
/* Read the remote error message */
rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
session->scpSend_err_msg,
session->scpSend_err_len);
if (rc <= 0) {
/*
* Since we have alread started reading this packet, it is
* already in the systems so it can't return PACKET_EAGAIN
*/
LIBSSH2_FREE(session, session->scpSend_err_msg);
session->scpSend_err_msg = NULL;
goto scp_send_error;
}
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
session->scpSend_err_msg, 1);
session->scpSend_err_msg = NULL;
goto scp_send_error;
}
}
session->scpSend_state = libssh2_NB_state_idle;
return session->scpSend_channel;
scp_send_error:
while (libssh2_channel_free(session->scpSend_channel) == PACKET_EAGAIN);
session->scpSend_channel = NULL;
session->scpSend_state = libssh2_NB_state_idle;
return NULL;
}
|
|||||
| ↓ | libssh2_channel_read_ex | 35 | 67 | 174 | src/channel.c |
LIBSSH2_API ssize_t
libssh2_channel_read_ex(LIBSSH2_CHANNEL * channel, int stream_id, char *buf,
size_t buflen)
{
LIBSSH2_SESSION *session = channel->session;
libssh2pack_t rc = 0;
if (channel->read_state == libssh2_NB_state_idle) {
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Attempting to read %d bytes from channel %lu/%lu stream #%d",
(int) buflen, channel->local.id, channel->remote.id,
stream_id);
/* process all incoming packets */
do {
if (libssh2_waitsocket(session, 0) > 0) {
rc = libssh2_packet_read(session);
} else {
/* Set for PACKET_EAGAIN so we continue */
rc = PACKET_EAGAIN;
}
} while (rc > 0);
if ((rc < 0) && (rc != PACKET_EAGAIN)) {
return rc;
}
channel->read_bytes_read = 0;
channel->read_block = 0;
channel->read_packet = session->packets.head;
channel->read_state = libssh2_NB_state_created;
}
/*
* =============================== NOTE ===============================
* I know this is very ugly and not a really good use of "goto", but
* this case statement would be even uglier to do it any other way
*/
if (channel->read_state == libssh2_NB_state_jump1) {
goto channel_read_ex_point1;
}
rc = 0;
do {
if (channel->read_block) {
/* in the second lap and onwards, do this */
rc = libssh2_packet_read(session);
channel->read_packet = session->packets.head;
}
/* We didn't read any data from the socket and
* no packets are waiting to be read */
if ((rc < 0) && (! channel->read_packet)) {
if (rc != PACKET_EAGAIN) {
channel->read_state = libssh2_NB_state_idle;
}
/* no packets available */
return rc;
}
while (channel->read_packet
&& (channel->read_bytes_read < (int) buflen)) {
/* In case packet gets destroyed during this iteration */
channel->read_next = channel->read_packet->next;
channel->read_local_id =
libssh2_ntohu32(channel->read_packet->data + 1);
/*
* Either we asked for a specific extended data stream
* (and data was available),
* or the standard stream (and data was available),
* or the standard stream with extended_data_merge
* enabled and data was available
*/
if ((stream_id
&& (channel->read_packet->data[0] ==
SSH_MSG_CHANNEL_EXTENDED_DATA)
&& (channel->local.id == channel->read_local_id)
&& (stream_id ==
(int) libssh2_ntohu32(channel->read_packet->data + 5)))
|| (!stream_id
&& (channel->read_packet->data[0] == SSH_MSG_CHANNEL_DATA)
&& (channel->local.id == channel->read_local_id))
|| (!stream_id
&& (channel->read_packet->data[0] ==
SSH_MSG_CHANNEL_EXTENDED_DATA)
&& (channel->local.id == channel->read_local_id)
&& (channel->remote.extended_data_ignore_mode ==
LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) {
channel->read_want = buflen - channel->read_bytes_read;
channel->read_unlink_packet = 0;
if (channel->read_want >=
(int) (channel->read_packet->data_len -
channel->read_packet->data_head)) {
channel->read_want =
channel->read_packet->data_len -
channel->read_packet->data_head;
channel->read_unlink_packet = 1;
}
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Reading %d of buffered data from %lu/%lu/%d",
channel->read_want, channel->local.id,
channel->remote.id, stream_id);
memcpy(buf + channel->read_bytes_read,
channel->read_packet->data +
channel->read_packet->data_head, channel->read_want);
channel->read_packet->data_head += channel->read_want;
channel->read_bytes_read += channel->read_want;
if (channel->read_unlink_packet) {
if (channel->read_packet->prev) {
channel->read_packet->prev->next =
channel->read_packet->next;
} else {
session->packets.head = channel->read_packet->next;
}
if (channel->read_packet->next) {
channel->read_packet->next->prev =
channel->read_packet->prev;
} else {
session->packets.tail = channel->read_packet->prev;
}
LIBSSH2_FREE(session, channel->read_packet->data);
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Unlinking empty packet buffer from channel %lu/%lu",
channel->local.id, channel->remote.id);
channel_read_ex_point1:
channel->read_state = libssh2_NB_state_jump1;
rc = libssh2_channel_receive_window_adjust(channel,
channel->
read_packet->
data_len -
(stream_id ? 13
: 9), 0);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
}
channel->read_state = libssh2_NB_state_created;
LIBSSH2_FREE(session, channel->read_packet);
channel->read_packet = NULL;
}
}
channel->read_packet = channel->read_next;
}
channel->read_block = 1;
} while ((channel->read_bytes_read == 0) && !channel->remote.close);
channel->read_state = libssh2_NB_state_idle;
if (channel->read_bytes_read == 0) {
if (channel->session->socket_block) {
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_CLOSED,
"Remote end has closed this channel", 0);
} else {
/*
* when non-blocking, we must return PACKET_EAGAIN if we haven't
* completed reading the channel
*/
if (!libssh2_channel_eof(channel)) {
return PACKET_EAGAIN;
}
}
}
channel->read_state = libssh2_NB_state_idle;
return channel->read_bytes_read;
}
|
|||||
| ↓ | ssh_host_parse_key | 34 | 78 | 154 | src/sshentry.c |
static int
ssh_host_parse_key(LIBSSH2_SESSION * session,
LIBSSH2_KNOWNHOSTS * s,
char *line,
int is_base64_encoded)
{
int i, j;
char *tmp, *tmp2;
/* workaround for the MD5 stuff */
libssh2_md5_ctx ctx;
/* the bits, exponent, modulus format */
if (is_base64_encoded == 0) {
s->ssh_version = 1;
s->key_type = 0;
if (!isdigit (*line))
return -1;
if (sscanf (line, "%hu %hu ", &(s->bits), &(s->exponent)) != 2)
return -2;
/* TODO:
* There's probably an acceptable range...
*/
if (s->bits <= 0 || s->exponent <= 0)
return 1;
line = strchr (line, ' ');
if (line == NULL)
return -3;
line++;
line = strchr (line, ' ');
if (line == NULL)
return -4;
line++;
/* TODO:
* figure out what format modulus is in since its not clear
* from the man page
*/
return -5;
}
else {
s->ssh_version = 2;
/* we only handle the rsa type */
if (strstr (line, "ssh-rsa") != line)
return -6;
s->key_type = 0;
line += 7;
if (*line != ' ')
return 2;
line++;
i = 0;
while (*line) {
if ((line[i] >= 0x30 && line[i] <= 0x39) ||
(line[i] >= 0x41 && line[i] <= 0x5a) ||
(line[i] >= 0x61 && line[i] <= 0x7a) ||
(line[i] == '+') || (line[i] == '/') || (line[i] == '='))
i++;
else
break;
}
if (i == 0)
return 3;
tmp = LIBSSH2_ALLOC (session, sizeof (char) * (i + 5));
strncpy (tmp, line, i);
/* this should hopefully avoid any issues with reading
* past the array if its malformed */
tmp[i] = tmp[i + 1] = tmp[i + 2] = tmp[i + 3] = tmp[i + 4] = 0;
/*
i = j = Curl_base64_decode (tmp, (unsigned char **) &tmp2);
*/
/* FIXME:
* Must use a base64 decoder implementation in order to decode stuff.
*/
{
/* TODO: rework the api interface instead of making a local instance */
i = libssh2_base64_decode(session, &tmp2, (unsigned int *)&j,
tmp, strlen(tmp));
LIBSSH2_FREE(session, tmp);
if (i != 0)
return 4;
}
/* printf("Decode Size: %d\n", i); */
/* free (tmp); */
#if LIBSSH2_MD5
s->md5 = LIBSSH2_ALLOC (session, 16);
libssh2_md5_init (&ctx);
libssh2_md5_update (ctx, tmp2, j);
libssh2_md5_final (ctx, s->md5);
/*
MD5_Init (ctx);
MD5_Update (ctx, tmp2, j);
MD5_Final (s->md5, ctx);
*/
#endif
line = tmp2;
i = ssh_proto_str_read (session, line, &tmp, tmp2 + j);
if (i < 0) {
LIBSSH2_FREE (session, tmp2);
return 5;
}
/* TODO: verify that its ssh-rsa -- its the only one
* supported
*/
if (!(i == 11 && tmp[0] == 's' && tmp[1] == 's' &&
tmp[2] == 'h' && tmp[3] == '-' && tmp[4] == 'r' &&
tmp[5] == 's' && tmp[6] == 'a')) {
free (tmp);
free (tmp2);
return 8;
}
LIBSSH2_FREE (session, tmp);
line += i;
i = ssh_proto_str_read (session, line, &tmp, tmp2 + j);
if (i < 0) {
LIBSSH2_FREE (session, tmp2);
return 6;
}
/* TODO: verify that the exponent is valid */
if (i == 5)
s->exponent = (unsigned short) ((unsigned char) *tmp);
else {
LIBSSH2_FREE (session, tmp);
LIBSSH2_FREE (session, tmp2);
return 9;
}
LIBSSH2_FREE (session, tmp);
line += i;
i = ssh_proto_str_read (session, line, &tmp, tmp2 + j);
if (i < 0) {
LIBSSH2_FREE (session, tmp2);
return 7;
}
/* TODO: the modulus may need to be converted to
* big integer format
*/
s->modulus_length = i - 4;
s->modulus = tmp;
s->bits = (s->modulus_length - 1) * 8;
LIBSSH2_FREE (session, tmp2);
return 0;
}
}
|
|||||
| ↓ | libssh2_packet_read | 37 | 120 | 331 | src/transport.c |
libssh2pack_t
libssh2_packet_read(LIBSSH2_SESSION * session)
{
libssh2pack_t rc;
struct transportpacket *p = &session->packet;
int remainbuf;
int remainpack;
int numbytes;
int numdecrypt;
unsigned char block[MAX_BLOCKSIZE];
int blocksize;
int encrypted = 1;
int status;
/*
* All channels, systems, subsystems, etc eventually make it down here
* when looking for more incoming data. If a key exchange is going on
* (LIBSSH2_STATE_EXCHANGING_KEYS bit is set) then the remote end
* will ONLY send key exchange related traffic. In non-blocking mode,
* there is a chance to break out of the kex_exchange function with an
* EAGAIN status, and never come back to it. If LIBSSH2_STATE_EXCHANGING_KEYS
* is active, then we must redirect to the key exchange. However,
* if kex_exchange is active (as in it is the one that calls this execution
* of packet_read, then don't redirect, as that would be an infinite loop!
*/
if (session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
!(session->state & LIBSSH2_STATE_KEX_ACTIVE)) {
/* Whoever wants a packet won't get anything until the key re-exchange
* is done!
*/
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Redirecting into the"
" key re-exchange");
status = libssh2_kex_exchange(session, 1, &session->startup_key_state);
if (status == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block exchanging encryption keys", 0);
return PACKET_EAGAIN;
} else if (status) {
libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE,
"Unable to exchange encryption keys",0);
return LIBSSH2_ERROR_KEX_FAILURE;
}
}
/*
* =============================== NOTE ===============================
* I know this is very ugly and not a really good use of "goto", but
* this case statement would be even uglier to do it any other way
*/
if (session->readPack_state == libssh2_NB_state_jump1) {
session->readPack_state = libssh2_NB_state_idle;
encrypted = session->readPack_encrypted;
goto libssh2_packet_read_point1;
}
do {
if (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
return PACKET_NONE;
}
if (session->state & LIBSSH2_STATE_NEWKEYS) {
blocksize = session->remote.crypt->blocksize;
} else {
encrypted = 0; /* not encrypted */
blocksize = 5; /* not strictly true, but we can use 5 here to
make the checks below work fine still */
}
/* read/use a whole big chunk into a temporary area stored in
the LIBSSH2_SESSION struct. We will decrypt data from that
buffer into the packet buffer so this temp one doesn't have
to be able to keep a whole SSH packet, just be large enough
so that we can read big chunks from the network layer. */
/* how much data there is remaining in the buffer to deal with
before we should read more from the network */
remainbuf = p->writeidx - p->readidx;
/* if remainbuf turns negative we have a bad internal error */
assert(remainbuf >= 0);
if (remainbuf < blocksize) {
/* If we have less than a blocksize left, it is too
little data to deal with, read more */
ssize_t nread;
/* move any remainder to the start of the buffer so
that we can do a full refill */
if (remainbuf) {
memmove(p->buf, &p->buf[p->readidx], remainbuf);
p->readidx = 0;
p->writeidx = remainbuf;
} else {
/* nothing to move, just zero the indexes */
p->readidx = p->writeidx = 0;
}
/* now read a big chunk from the network into the temp buffer */
nread =
recv(session->socket_fd, &p->buf[remainbuf],
PACKETBUFSIZE - remainbuf,
LIBSSH2_SOCKET_RECV_FLAGS(session));
if (nread <= 0) {
/* check if this is due to EAGAIN and return the special
return code if so, error out normally otherwise */
#ifdef WIN32
switch (WSAGetLastError()) {
case WSAEWOULDBLOCK:
errno = EAGAIN;
break;
case WSAENOTSOCK:
errno = EBADF;
break;
case WSAENOTCONN:
case WSAECONNABORTED:
errno = WSAENOTCONN;
break;
case WSAEINTR:
errno = EINTR;
break;
}
#endif /* WIN32 */
if ((nread < 0) && (errno == EAGAIN)) {
return PACKET_EAGAIN;
}
return PACKET_FAIL;
}
debugdump(session, "libssh2_packet_read() raw",
&p->buf[remainbuf], nread);
/* advance write pointer */
p->writeidx += nread;
/* update remainbuf counter */
remainbuf = p->writeidx - p->readidx;
}
/* how much data to deal with from the buffer */
numbytes = remainbuf;
if (!p->total_num) {
/* No payload package area allocated yet. To know the
size of this payload, we need to decrypt the first
blocksize data. */
if (numbytes < blocksize) {
/* we can't act on anything less than blocksize, but this
check is only done for the initial block since once we have
got the start of a block we can in fact deal with fractions
*/
return PACKET_EAGAIN;
}
if (encrypted) {
rc = decrypt(session, &p->buf[p->readidx], block, blocksize);
if (rc != PACKET_NONE) {
return rc;
}
/* save the first 5 bytes of the decrypted package, to be
used in the hash calculation later down. */
memcpy(p->init, &p->buf[p->readidx], 5);
} else {
/* the data is plain, just copy it verbatim to
the working block buffer */
memcpy(block, &p->buf[p->readidx], blocksize);
}
/* advance the read pointer */
p->readidx += blocksize;
/* we now have the initial blocksize bytes decrypted,
* and we can extract packet and padding length from it
*/
p->packet_length = libssh2_ntohu32(block);
p->padding_length = block[4];
/* total_num is the number of bytes following the initial
(5 bytes) packet length and padding length fields */
p->total_num =
p->packet_length - 1 +
(encrypted ? session->remote.mac->mac_len : 0);
/* RFC4253 section 6.1 Maximum Packet Length says:
*
* "All implementations MUST be able to process
* packets with uncompressed payload length of 32768
* bytes or less and total packet size of 35000 bytes
* or less (including length, padding length, payload,
* padding, and MAC.)."
*/
if (p->total_num > LIBSSH2_PACKET_MAXPAYLOAD) {
return PACKET_TOOBIG;
}
/* Get a packet handle put data into. We get one to
hold all data, including padding and MAC. */
p->payload = LIBSSH2_ALLOC(session, p->total_num);
if (!p->payload) {
return PACKET_ENOMEM;
}
/* init write pointer to start of payload buffer */
p->wptr = p->payload;
if (blocksize > 5) {
/* copy the data from index 5 to the end of
the blocksize from the temporary buffer to
the start of the decrypted buffer */
memcpy(p->wptr, &block[5], blocksize - 5);
p->wptr += blocksize - 5; /* advance write pointer */
}
/* init the data_num field to the number of bytes of
the package read so far */
p->data_num = p->wptr - p->payload;
/* we already dealt with a blocksize worth of data */
numbytes -= blocksize;
}
/* how much there is left to add to the current payload
package */
remainpack = p->total_num - p->data_num;
if (numbytes > remainpack) {
/* if we have more data in the buffer than what is going into this
particular packet, we limit this round to this packet only */
numbytes = remainpack;
}
if (encrypted) {
/* At the end of the incoming stream, there is a MAC,
and we don't want to decrypt that since we need it
"raw". We MUST however decrypt the padding data
since it is used for the hash later on. */
int skip = session->remote.mac->mac_len;
/* if what we have plus numbytes is bigger than the
total minus the skip margin, we should lower the
amount to decrypt even more */
if ((p->data_num + numbytes) > (p->total_num - skip)) {
numdecrypt = (p->total_num - skip) - p->data_num;
} else {
int frac;
numdecrypt = numbytes;
frac = numdecrypt % blocksize;
if (frac) {
/* not an aligned amount of blocks,
align it */
numdecrypt -= frac;
/* and make it no unencrypted data
after it */
numbytes = 0;
}
}
} else {
/* unencrypted data should not be decrypted at all */
numdecrypt = 0;
}
/* if there are bytes to decrypt, do that */
if (numdecrypt > 0) {
/* now decrypt the lot */
rc = decrypt(session, &p->buf[p->readidx], p->wptr, numdecrypt);
if (rc != PACKET_NONE) {
return rc;
}
/* advance the read pointer */
p->readidx += numdecrypt;
/* advance write pointer */
p->wptr += numdecrypt;
/* increse data_num */
p->data_num += numdecrypt;
/* bytes left to take care of without decryption */
numbytes -= numdecrypt;
}
/* if there are bytes to copy that aren't decrypted, simply
copy them as-is to the target buffer */
if (numbytes > 0) {
memcpy(p->wptr, &p->buf[p->readidx], numbytes);
/* advance the read pointer */
p->readidx += numbytes;
/* advance write pointer */
p->wptr += numbytes;
/* increse data_num */
p->data_num += numbytes;
}
/* now check how much data there's left to read to finish the
current packet */
remainpack = p->total_num - p->data_num;
if (!remainpack) {
/* we have a full packet */
libssh2_packet_read_point1:
rc = fullpacket(session, encrypted);
if (rc == PACKET_EAGAIN) {
if (session->packAdd_state != libssh2_NB_state_idle)
{
/* fullpacket only returns PACKET_EAGAIN if
* libssh2_packet_add returns PACKET_EAGAIN. If that
* returns PACKET_EAGAIN but the packAdd_state is idle,
* then the packet has been added to the brigade, but some
* immediate action that was taken based on the packet
* type (such as key re-exchange) is not yet complete.
* Clear the way for a new packet to be read in.
*/
session->readPack_encrypted = encrypted;
session->readPack_state = libssh2_NB_state_jump1;
}
return PACKET_EAGAIN;
}
p->total_num = 0; /* no packet buffer available */
return rc;
}
} while (1); /* loop */
return PACKET_FAIL; /* we never reach this point */
}
|
|||||
| ↓ | libssh2_publickey_init | 30 | 118 | 229 | src/publickey.c |
LIBSSH2_API LIBSSH2_PUBLICKEY *
libssh2_publickey_init(LIBSSH2_SESSION * session)
{
/* 19 = packet_len(4) + version_len(4) + "version"(7) + version_num(4) */
unsigned char buffer[19];
unsigned char *s;
int response;
int rc;
if (session->pkeyInit_state == libssh2_NB_state_idle) {
session->pkeyInit_data = NULL;
session->pkeyInit_pkey = NULL;
session->pkeyInit_channel = NULL;
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
"Initializing publickey subsystem");
session->pkeyInit_state = libssh2_NB_state_allocated;
}
if (session->pkeyInit_state == libssh2_NB_state_allocated) {
do {
session->pkeyInit_channel =
libssh2_channel_open_ex(session, "session",
sizeof("session") - 1,
LIBSSH2_CHANNEL_WINDOW_DEFAULT,
LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL,
0);
if (!session->pkeyInit_channel
&& (libssh2_session_last_errno(session) ==
LIBSSH2_ERROR_EAGAIN)) {
/* The error state is already set, so leave it */
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block to startup channel", 0);
return NULL;
} else if (!session->pkeyInit_channel
&& (libssh2_session_last_errno(session) !=
LIBSSH2_ERROR_EAGAIN)) {
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
"Unable to startup channel", 0);
goto err_exit;
}
} while (!session->pkeyInit_channel);
session->pkeyInit_state = libssh2_NB_state_sent;
}
if (session->pkeyInit_state == libssh2_NB_state_sent) {
rc = libssh2_channel_process_startup(session->pkeyInit_channel,
"subsystem",
sizeof("subsystem") - 1,
"publickey", strlen("publickey"));
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block starting publickkey subsystem", 0);
return NULL;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
"Unable to request publickey subsystem", 0);
goto err_exit;
}
session->pkeyInit_state = libssh2_NB_state_sent1;
}
if (session->pkeyInit_state == libssh2_NB_state_sent1) {
rc = libssh2_channel_handle_extended_data2(session->pkeyInit_channel,
LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block starting publickkey subsystem", 0);
return NULL;
}
session->pkeyInit_pkey =
LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PUBLICKEY));
if (!session->pkeyInit_pkey) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate a new publickey structure", 0);
goto err_exit;
}
memset(session->pkeyInit_pkey, 0, sizeof(LIBSSH2_PUBLICKEY));
session->pkeyInit_pkey->channel = session->pkeyInit_channel;
session->pkeyInit_pkey->version = 0;
s = buffer;
libssh2_htonu32(s, 4 + (sizeof("version") - 1) + 4);
s += 4;
libssh2_htonu32(s, sizeof("version") - 1);
s += 4;
memcpy(s, "version", sizeof("version") - 1);
s += sizeof("version") - 1;
libssh2_htonu32(s, LIBSSH2_PUBLICKEY_VERSION);
s += 4;
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
"Sending publickey version packet advertising version %d support",
(int) LIBSSH2_PUBLICKEY_VERSION);
session->pkeyInit_state = libssh2_NB_state_sent2;
}
if (session->pkeyInit_state == libssh2_NB_state_sent2) {
rc = libssh2_channel_write_ex(session->pkeyInit_channel, 0,
(char *) buffer, (s - buffer));
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block sending publickkey version packet", 0);
return NULL;
} else if ((s - buffer) != rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send publickey version packet", 0);
goto err_exit;
}
session->pkeyInit_state = libssh2_NB_state_sent3;
}
if (session->pkeyInit_state == libssh2_NB_state_sent3) {
while (1) {
rc = libssh2_publickey_packet_receive(session->pkeyInit_pkey,
&session->pkeyInit_data,
&session->pkeyInit_data_len);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block waiting for response from publickey subsystem",
0);
return NULL;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for response from publickey subsystem",
0);
goto err_exit;
}
s = session->pkeyInit_data;
if ((response =
libssh2_publickey_response_id(&s,
session->pkeyInit_data_len)) <
0) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
"Invalid publickey subsystem response code", 0);
goto err_exit;
}
switch (response) {
case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
/* Error */
{
unsigned long status, descr_len, lang_len;
unsigned char *descr, *lang;
status = libssh2_ntohu32(s);
s += 4;
descr_len = libssh2_ntohu32(s);
s += 4;
descr = s;
s += descr_len;
lang_len = libssh2_ntohu32(s);
s += 4;
lang = s;
s += lang_len;
if (s >
session->pkeyInit_data + session->pkeyInit_data_len) {
libssh2_error(session,
LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
"Malformed publickey subsystem packet",
0);
goto err_exit;
}
libssh2_publickey_status_error(NULL, session, status,
descr, descr_len);
goto err_exit;
}
case LIBSSH2_PUBLICKEY_RESPONSE_VERSION:
/* What we want */
session->pkeyInit_pkey->version = libssh2_ntohu32(s);
if (session->pkeyInit_pkey->version >
LIBSSH2_PUBLICKEY_VERSION) {
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
"Truncating remote publickey version from %lu",
session->pkeyInit_pkey->version);
session->pkeyInit_pkey->version =
LIBSSH2_PUBLICKEY_VERSION;
}
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
"Enabling publickey subsystem version %lu",
session->pkeyInit_pkey->version);
LIBSSH2_FREE(session, session->pkeyInit_data);
session->pkeyInit_data = NULL;
session->pkeyInit_state = libssh2_NB_state_idle;
return session->pkeyInit_pkey;
default:
/* Unknown/Unexpected */
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
"Unexpected publickey subsystem response, ignoring",
0);
LIBSSH2_FREE(session, session->pkeyInit_data);
session->pkeyInit_data = NULL;
}
}
}
/* Never reached except by direct goto */
err_exit:
session->pkeyInit_state = libssh2_NB_state_sent4;
if (session->pkeyInit_channel) {
rc = libssh2_channel_close(session->pkeyInit_channel);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block closing channel", 0);
return NULL;
}
}
if (session->pkeyInit_pkey) {
LIBSSH2_FREE(session, session->pkeyInit_pkey);
session->pkeyInit_pkey = NULL;
}
if (session->pkeyInit_data) {
LIBSSH2_FREE(session, session->pkeyInit_data);
session->pkeyInit_data = NULL;
}
session->pkeyInit_state = libssh2_NB_state_idle;
return NULL;
}
|
|||||
| ↓ | libssh2_userauth_keyboard_interactive_ex | 29 | 169 | 323 | src/userauth.c |
LIBSSH2_API int
libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,
const char *username,
unsigned int username_len,
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
{
unsigned char *s;
int rc;
static const unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS,
SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0
};
unsigned int language_tag_len;
unsigned int i;
if (session->userauth_kybd_state == libssh2_NB_state_idle) {
session->userauth_kybd_auth_name = NULL;
session->userauth_kybd_auth_instruction = NULL;
session->userauth_kybd_num_prompts = 0;
session->userauth_kybd_auth_failure = 1;
session->userauth_kybd_prompts = NULL;
session->userauth_kybd_responses = NULL;
/* Zero the whole thing out */
memset(&session->userauth_kybd_packet_requirev_state, 0,
sizeof(session->userauth_kybd_packet_requirev_state));
session->userauth_kybd_packet_len = 1 /* byte SSH_MSG_USERAUTH_REQUEST */
+ 4 + username_len /* string user name (ISO-10646 UTF-8, as defined in [RFC-3629]) */
+ 4 + 14 /* string service name (US-ASCII) */
+ 4 + 20 /* string "keyboard-interactive" (US-ASCII) */
+ 4 + 0 /* string language tag (as defined in [RFC-3066]) */
+ 4 + 0 /* string submethods (ISO-10646 UTF-8) */
;
session->userauth_kybd_data = s =
LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
if (!s) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for keyboard-interactive authentication",
0);
return -1;
}
*s++ = SSH_MSG_USERAUTH_REQUEST;
/* user name */
libssh2_htonu32(s, username_len);
s += 4;
memcpy(s, username, username_len);
s += username_len;
/* service name */
libssh2_htonu32(s, sizeof("ssh-connection") - 1);
s += 4;
memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1);
s += sizeof("ssh-connection") - 1;
/* "keyboard-interactive" */
libssh2_htonu32(s, sizeof("keyboard-interactive") - 1);
s += 4;
memcpy(s, "keyboard-interactive", sizeof("keyboard-interactive") - 1);
s += sizeof("keyboard-interactive") - 1;
/* language tag */
libssh2_htonu32(s, 0);
s += 4;
/* submethods */
libssh2_htonu32(s, 0);
s += 4;
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
"Attempting keyboard-interactive authentication");
session->userauth_kybd_state = libssh2_NB_state_created;
}
if (session->userauth_kybd_state == libssh2_NB_state_created) {
rc = libssh2_packet_write(session, session->userauth_kybd_data,
session->userauth_kybd_packet_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send keyboard-interactive request", 0);
LIBSSH2_FREE(session, session->userauth_kybd_data);
session->userauth_kybd_data = NULL;
session->userauth_kybd_state = libssh2_NB_state_idle;
return -1;
}
LIBSSH2_FREE(session, session->userauth_kybd_data);
session->userauth_kybd_data = NULL;
session->userauth_kybd_state = libssh2_NB_state_sent;
}
for(;;) {
if (session->userauth_kybd_state == libssh2_NB_state_sent) {
rc = libssh2_packet_requirev_ex(session, reply_codes,
&session->userauth_kybd_data,
&session->userauth_kybd_data_len,
0, NULL, 0,
&session->
userauth_kybd_packet_requirev_state);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
session->userauth_kybd_state = libssh2_NB_state_idle;
return -1;
}
if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
"Keyboard-interactive authentication successful");
LIBSSH2_FREE(session, session->userauth_kybd_data);
session->userauth_kybd_data = NULL;
session->state |= LIBSSH2_STATE_AUTHENTICATED;
session->userauth_kybd_state = libssh2_NB_state_idle;
return 0;
}
if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_FAILURE) {
LIBSSH2_FREE(session, session->userauth_kybd_data);
session->userauth_kybd_data = NULL;
session->userauth_kybd_state = libssh2_NB_state_idle;
return -1;
}
/* server requested PAM-like conversation */
s = session->userauth_kybd_data + 1;
/* string name (ISO-10646 UTF-8) */
session->userauth_kybd_auth_name_len = libssh2_ntohu32(s);
s += 4;
session->userauth_kybd_auth_name =
LIBSSH2_ALLOC(session, session->userauth_kybd_auth_name_len);
if (!session->userauth_kybd_auth_name) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for keyboard-interactive 'name' request field",
0);
goto cleanup;
}
memcpy(session->userauth_kybd_auth_name, s,
session->userauth_kybd_auth_name_len);
s += session->userauth_kybd_auth_name_len;
/* string instruction (ISO-10646 UTF-8) */
session->userauth_kybd_auth_instruction_len = libssh2_ntohu32(s);
s += 4;
session->userauth_kybd_auth_instruction =
LIBSSH2_ALLOC(session,
session->userauth_kybd_auth_instruction_len);
if (!session->userauth_kybd_auth_instruction) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for keyboard-interactive 'instruction' request field",
0);
goto cleanup;
}
memcpy(session->userauth_kybd_auth_instruction, s,
session->userauth_kybd_auth_instruction_len);
s += session->userauth_kybd_auth_instruction_len;
/* string language tag (as defined in [RFC-3066]) */
language_tag_len = libssh2_ntohu32(s);
s += 4;
/* ignoring this field as deprecated */
s += language_tag_len;
/* int num-prompts */
session->userauth_kybd_num_prompts = libssh2_ntohu32(s);
s += 4;
session->userauth_kybd_prompts =
LIBSSH2_ALLOC(session,
sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
session->userauth_kybd_num_prompts);
if (!session->userauth_kybd_prompts) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for keyboard-interactive prompts array",
0);
goto cleanup;
}
memset(session->userauth_kybd_prompts, 0,
sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
session->userauth_kybd_num_prompts);
session->userauth_kybd_responses =
LIBSSH2_ALLOC(session,
sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
session->userauth_kybd_num_prompts);
if (!session->userauth_kybd_responses) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for keyboard-interactive responses array",
0);
goto cleanup;
}
memset(session->userauth_kybd_responses, 0,
sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
session->userauth_kybd_num_prompts);
for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
/* string prompt[1] (ISO-10646 UTF-8) */
session->userauth_kybd_prompts[i].length = libssh2_ntohu32(s);
s += 4;
session->userauth_kybd_prompts[i].text =
LIBSSH2_ALLOC(session,
session->userauth_kybd_prompts[i].length);
if (!session->userauth_kybd_prompts[i].text) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for keyboard-interactive prompt message",
0);
goto cleanup;
}
memcpy(session->userauth_kybd_prompts[i].text, s,
session->userauth_kybd_prompts[i].length);
s += session->userauth_kybd_prompts[i].length;
/* boolean echo[1] */
session->userauth_kybd_prompts[i].echo = *s++;
}
response_callback(session->userauth_kybd_auth_name,
session->userauth_kybd_auth_name_len,
session->userauth_kybd_auth_instruction,
session->userauth_kybd_auth_instruction_len,
session->userauth_kybd_num_prompts,
session->userauth_kybd_prompts,
session->userauth_kybd_responses,
&session->abstract);
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
"Keyboard-interactive response callback function invoked");
session->userauth_kybd_packet_len = 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */
+ 4 /* int num-responses */
;
for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
/* string response[1] (ISO-10646 UTF-8) */
session->userauth_kybd_packet_len +=
4 + session->userauth_kybd_responses[i].length;
}
session->userauth_kybd_data = s =
LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
if (!s) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for keyboard-interactive response packet",
0);
goto cleanup;
}
*s = SSH_MSG_USERAUTH_INFO_RESPONSE;
s++;
libssh2_htonu32(s, session->userauth_kybd_num_prompts);
s += 4;
for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
libssh2_htonu32(s, session->userauth_kybd_responses[i].length);
s += 4;
memcpy(s, session->userauth_kybd_responses[i].text,
session->userauth_kybd_responses[i].length);
s += session->userauth_kybd_responses[i].length;
}
session->userauth_kybd_state = libssh2_NB_state_sent1;
}
if (session->userauth_kybd_state == libssh2_NB_state_sent1) {
rc = libssh2_packet_write(session, session->userauth_kybd_data,
session->userauth_kybd_packet_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
}
if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send userauth-keyboard-interactive request",
0);
goto cleanup;
}
session->userauth_kybd_auth_failure = 0;
}
cleanup:
/*
* It's safe to clean all the data here, because unallocated pointers
* are filled by zeroes
*/
LIBSSH2_FREE(session, session->userauth_kybd_data);
session->userauth_kybd_data = NULL;
if (session->userauth_kybd_prompts) {
for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
LIBSSH2_FREE(session, session->userauth_kybd_prompts[i].text);
session->userauth_kybd_prompts[i].text = NULL;
}
}
if (session->userauth_kybd_responses) {
for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
LIBSSH2_FREE(session,
session->userauth_kybd_responses[i].text);
session->userauth_kybd_responses[i].text = NULL;
}
}
LIBSSH2_FREE(session, session->userauth_kybd_prompts);
session->userauth_kybd_prompts = NULL;
LIBSSH2_FREE(session, session->userauth_kybd_responses);
session->userauth_kybd_responses = NULL;
if (session->userauth_kybd_auth_failure) {
session->userauth_kybd_state = libssh2_NB_state_idle;
return -1;
}
session->userauth_kybd_state = libssh2_NB_state_sent;
}
}
|
|||||
| ↓ | libssh2_sftp_readdir_ex | 26 | 112 | 196 | src/sftp.c |
LIBSSH2_API int
libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
size_t buffer_maxlen, char *longentry,
size_t longentry_maxlen,
LIBSSH2_SFTP_ATTRIBUTES * attrs)
{
LIBSSH2_SFTP *sftp = handle->sftp;
LIBSSH2_CHANNEL *channel = sftp->channel;
LIBSSH2_SESSION *session = channel->session;
LIBSSH2_SFTP_ATTRIBUTES attrs_dummy;
unsigned long data_len, filename_len, longentry_len, num_names;
/* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
ssize_t packet_len = handle->handle_len + 13;
unsigned char *s, *data;
unsigned char read_responses[2] = { SSH_FXP_NAME, SSH_FXP_STATUS };
int retcode;
if (sftp->readdir_state == libssh2_NB_state_idle) {
if (handle->u.dir.names_left) {
/*
* A prior request returned more than one directory entry,
* feed it back from the buffer
*/
unsigned char *s = (unsigned char *) handle->u.dir.next_name;
unsigned long real_filename_len = libssh2_ntohu32(s);
filename_len = real_filename_len;
s += 4;
if (filename_len > buffer_maxlen) {
filename_len = buffer_maxlen;
}
memcpy(buffer, s, filename_len);
s += real_filename_len;
/* The filename is not null terminated, make it so if possible */
if (filename_len < buffer_maxlen) {
buffer[filename_len] = '\0';
}
if ((longentry == NULL) || (longentry_maxlen == 0)) {
/* Skip longname */
s += 4 + libssh2_ntohu32(s);
} else {
unsigned long real_longentry_len = libssh2_ntohu32(s);
longentry_len = real_longentry_len;
s += 4;
if (longentry_len > longentry_maxlen) {
longentry_len = longentry_maxlen;
}
memcpy(longentry, s, longentry_len);
s += real_longentry_len;
/* The longentry is not null terminated, make it so if possible */
if (longentry_len < longentry_maxlen) {
longentry[longentry_len] = '\0';
}
}
if (attrs) {
memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
}
s += libssh2_sftp_bin2attr(attrs ? attrs : &attrs_dummy, s);
handle->u.dir.next_name = (char *) s;
if ((--handle->u.dir.names_left) == 0) {
LIBSSH2_FREE(session, handle->u.dir.names_packet);
}
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
"libssh2_sftp_readdir_ex() return %d",
filename_len);
return filename_len;
}
/* Request another entry(entries?) */
s = sftp->readdir_packet = LIBSSH2_ALLOC(session, packet_len);
if (!sftp->readdir_packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for FXP_READDIR packet",
0);
return -1;
}
libssh2_htonu32(s, packet_len - 4);
s += 4;
*(s++) = SSH_FXP_READDIR;
sftp->readdir_request_id = sftp->request_id++;
libssh2_htonu32(s, sftp->readdir_request_id);
s += 4;
libssh2_htonu32(s, handle->handle_len);
s += 4;
memcpy(s, handle->handle, handle->handle_len);
s += handle->handle_len;
sftp->readdir_state = libssh2_NB_state_created;
}
if (sftp->readdir_state == libssh2_NB_state_created) {
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
"Reading entries from directory handle");
if ((retcode =
libssh2_channel_write_ex(channel, 0,
(char *) sftp->readdir_packet,
packet_len)) == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (packet_len != retcode) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send FXP_READ command", 0);
LIBSSH2_FREE(session, sftp->readdir_packet);
sftp->readdir_packet = NULL;
sftp->readdir_state = libssh2_NB_state_idle;
return -1;
}
LIBSSH2_FREE(session, sftp->readdir_packet);
sftp->readdir_packet = NULL;
sftp->readdir_state = libssh2_NB_state_sent;
}
retcode =
libssh2_sftp_packet_requirev(sftp, 2, read_responses,
sftp->readdir_request_id, &data,
&data_len);
if (retcode == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (retcode) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for status message", 0);
sftp->readdir_state = libssh2_NB_state_idle;
return -1;
}
if (data[0] == SSH_FXP_STATUS) {
retcode = libssh2_ntohu32(data + 5);
LIBSSH2_FREE(session, data);
if (retcode == LIBSSH2_FX_EOF) {
sftp->readdir_state = libssh2_NB_state_idle;
return 0;
} else {
sftp->last_errno = retcode;
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"SFTP Protocol Error", 0);
sftp->readdir_state = libssh2_NB_state_idle;
return -1;
}
}
num_names = libssh2_ntohu32(data + 5);
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu entries returned",
num_names);
if (num_names <= 0) {
LIBSSH2_FREE(session, data);
sftp->readdir_state = libssh2_NB_state_idle;
return (num_names == 0) ? 0 : -1;
}
if (num_names == 1) {
unsigned long real_filename_len = libssh2_ntohu32(data + 9);
filename_len = real_filename_len;
if (filename_len > buffer_maxlen) {
filename_len = buffer_maxlen;
}
memcpy(buffer, data + 13, filename_len);
/* The filename is not null terminated, make it so if possible */
if (filename_len < buffer_maxlen) {
buffer[filename_len] = '\0';
}
if (attrs) {
memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
libssh2_sftp_bin2attr(attrs, data + 13 + real_filename_len +
(4 +
libssh2_ntohu32(data + 13 +
real_filename_len)));
}
LIBSSH2_FREE(session, data);
sftp->readdir_state = libssh2_NB_state_idle;
return filename_len;
}
handle->u.dir.names_left = num_names;
handle->u.dir.names_packet = data;
handle->u.dir.next_name = (char *) data + 9;
sftp->readdir_state = libssh2_NB_state_idle;
/* Be lazy, just use the name popping mechanism from the start of the function */
return libssh2_sftp_readdir_ex(handle, buffer, buffer_maxlen, longentry,
longentry_maxlen, attrs);
}
|
|||||
| ↓ | libssh2_userauth_password_ex | 25 | 131 | 246 | src/userauth.c |
LIBSSH2_API int
libssh2_userauth_password_ex(LIBSSH2_SESSION * session, const char *username,
unsigned int username_len, const char *password,
unsigned int password_len,
LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
{
unsigned char *s;
static const unsigned char reply_codes[4] =
{ SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0
};
int rc;
if (session->userauth_pswd_state == libssh2_NB_state_idle) {
/* Zero the whole thing out */
memset(&session->userauth_pswd_packet_requirev_state, 0,
sizeof(session->userauth_pswd_packet_requirev_state));
/*
* 40 = acket_type(1) + username_len(4) + service_len(4) +
* service(14)"ssh-connection" + method_len(4) + method(8)"password" +
* chgpwdbool(1) + password_len(4) */
session->userauth_pswd_data_len = username_len + password_len + 40;
session->userauth_pswd_data0 = ~SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;
s = session->userauth_pswd_data =
LIBSSH2_ALLOC(session, session->userauth_pswd_data_len);
if (!session->userauth_pswd_data) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for userauth-password request",
0);
return -1;
}
*(s++) = SSH_MSG_USERAUTH_REQUEST;
libssh2_htonu32(s, username_len);
s += 4;
memcpy(s, username, username_len);
s += username_len;
libssh2_htonu32(s, sizeof("ssh-connection") - 1);
s += 4;
memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1);
s += sizeof("ssh-connection") - 1;
libssh2_htonu32(s, sizeof("password") - 1);
s += 4;
memcpy(s, "password", sizeof("password") - 1);
s += sizeof("password") - 1;
*s = '\0';
s++;
libssh2_htonu32(s, password_len);
s += 4;
memcpy(s, password, password_len);
s += password_len;
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
"Attempting to login using password authentication");
session->userauth_pswd_state = libssh2_NB_state_created;
}
if (session->userauth_pswd_state == libssh2_NB_state_created) {
rc = libssh2_packet_write(session, session->userauth_pswd_data,
session->userauth_pswd_data_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send userauth-password request", 0);
LIBSSH2_FREE(session, session->userauth_pswd_data);
session->userauth_pswd_data = NULL;
session->userauth_pswd_state = libssh2_NB_state_idle;
return -1;
}
LIBSSH2_FREE(session, session->userauth_pswd_data);
session->userauth_pswd_data = NULL;
session->userauth_pswd_state = libssh2_NB_state_sent;
}
password_response:
if ((session->userauth_pswd_state == libssh2_NB_state_sent)
|| (session->userauth_pswd_state == libssh2_NB_state_sent1)
|| (session->userauth_pswd_state == libssh2_NB_state_sent2)) {
if (session->userauth_pswd_state == libssh2_NB_state_sent) {
rc = libssh2_packet_requirev_ex(session, reply_codes,
&session->userauth_pswd_data,
&session->userauth_pswd_data_len,
0, NULL, 0,
&session->
userauth_pswd_packet_requirev_state);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
session->userauth_pswd_state = libssh2_NB_state_idle;
return -1;
}
if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
"Password authentication successful");
LIBSSH2_FREE(session, session->userauth_pswd_data);
session->userauth_pswd_data = NULL;
session->state |= LIBSSH2_STATE_AUTHENTICATED;
session->userauth_pswd_state = libssh2_NB_state_idle;
return 0;
}
session->userauth_pswd_newpw = NULL;
session->userauth_pswd_newpw_len = 0;
session->userauth_pswd_state = libssh2_NB_state_sent1;
}
if ((session->userauth_pswd_data[0] ==
SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)
|| (session->userauth_pswd_data0 ==
SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)) {
session->userauth_pswd_data0 = SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;
if ((session->userauth_pswd_state == libssh2_NB_state_sent1) ||
(session->userauth_pswd_state == libssh2_NB_state_sent2)) {
if (session->userauth_pswd_state == libssh2_NB_state_sent1) {
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
"Password change required");
LIBSSH2_FREE(session, session->userauth_pswd_data);
session->userauth_pswd_data = NULL;
}
if (passwd_change_cb) {
if (session->userauth_pswd_state == libssh2_NB_state_sent1) {
passwd_change_cb(session,
&session->userauth_pswd_newpw,
&session->userauth_pswd_newpw_len,
&session->abstract);
if (!session->userauth_pswd_newpw) {
libssh2_error(session,
LIBSSH2_ERROR_PASSWORD_EXPIRED,
"Password expired, and callback failed",
0);
return -1;
}
/* basic data_len + newpw_len(4) */
session->userauth_pswd_data_len =
username_len + password_len + 44 +
session->userauth_pswd_newpw_len;
s = session->userauth_pswd_data =
LIBSSH2_ALLOC(session,
session->userauth_pswd_data_len);
if (!session->userauth_pswd_data) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for userauth-password-change request",
0);
LIBSSH2_FREE(session,
session->userauth_pswd_newpw);
session->userauth_pswd_newpw = NULL;
return -1;
}
*(s++) = SSH_MSG_USERAUTH_REQUEST;
libssh2_htonu32(s, username_len);
s += 4;
memcpy(s, username, username_len);
s += username_len;
libssh2_htonu32(s, sizeof("ssh-connection") - 1);
s += 4;
memcpy(s, "ssh-connection",
sizeof("ssh-connection") - 1);
s += sizeof("ssh-connection") - 1;
libssh2_htonu32(s, sizeof("password") - 1);
s += 4;
memcpy(s, "password", sizeof("password") - 1);
s += sizeof("password") - 1;
*s = 0x01;
s++;
libssh2_htonu32(s, password_len);
s += 4;
memcpy(s, password, password_len);
s += password_len;
libssh2_htonu32(s, session->userauth_pswd_newpw_len);
s += 4;
memcpy(s, session->userauth_pswd_newpw,
session->userauth_pswd_newpw_len);
s += session->userauth_pswd_newpw_len;
session->userauth_pswd_state = libssh2_NB_state_sent2;
}
if (session->userauth_pswd_state == libssh2_NB_state_sent2) {
rc = libssh2_packet_write(session,
session->userauth_pswd_data,
session->
userauth_pswd_data_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send userauth-password-change request",
0);
LIBSSH2_FREE(session, session->userauth_pswd_data);
session->userauth_pswd_data = NULL;
LIBSSH2_FREE(session,
session->userauth_pswd_newpw);
session->userauth_pswd_newpw = NULL;
return -1;
}
LIBSSH2_FREE(session, session->userauth_pswd_data);
session->userauth_pswd_data = NULL;
LIBSSH2_FREE(session, session->userauth_pswd_newpw);
session->userauth_pswd_newpw = NULL;
/*
* Ugliest use of goto ever. Blame it on the
* askN => requirev migration.
*/
session->userauth_pswd_state = libssh2_NB_state_sent;
goto password_response;
}
}
} else {
libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED,
"Password Expired, and no callback specified",
0);
session->userauth_pswd_state = libssh2_NB_state_idle;
return -1;
}
}
}
/* FAILURE */
LIBSSH2_FREE(session, session->userauth_pswd_data);
session->userauth_pswd_data = NULL;
session->userauth_pswd_state = libssh2_NB_state_idle;
return -1;
}
|
|||||
| ↓ | libssh2_channel_open_ex | 25 | 106 | 205 | src/channel.c |
LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_channel_open_ex(LIBSSH2_SESSION * session, const char *channel_type,
unsigned int channel_type_len,
unsigned int window_size, unsigned int packet_size,
const char *message, unsigned int message_len)
{
static const unsigned char reply_codes[3] = {
SSH_MSG_CHANNEL_OPEN_CONFIRMATION,
SSH_MSG_CHANNEL_OPEN_FAILURE,
0
};
unsigned char *s;
int rc;
if (session->open_state == libssh2_NB_state_idle) {
session->open_channel = NULL;
session->open_packet = NULL;
session->open_data = NULL;
/* 17 = packet_type(1) + channel_type_len(4) + sender_channel(4) + window_size(4) + packet_size(4) */
session->open_packet_len = channel_type_len + message_len + 17;
session->open_local_channel = libssh2_channel_nextid(session);
/* Zero the whole thing out */
memset(&session->open_packet_requirev_state, 0,
sizeof(session->open_packet_requirev_state));
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Opening Channel - win %d pack %d", window_size,
packet_size);
session->open_channel =
LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
if (!session->open_channel) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate space for channel data", 0);
return NULL;
}
memset(session->open_channel, 0, sizeof(LIBSSH2_CHANNEL));
session->open_channel->channel_type_len = channel_type_len;
session->open_channel->channel_type =
LIBSSH2_ALLOC(session, channel_type_len);
if (!session->open_channel->channel_type) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Failed allocating memory for channel type name", 0);
LIBSSH2_FREE(session, session->open_channel);
session->open_channel = NULL;
return NULL;
}
memcpy(session->open_channel->channel_type, channel_type,
channel_type_len);
/* REMEMBER: local as in locally sourced */
session->open_channel->local.id = session->open_local_channel;
session->open_channel->remote.window_size = window_size;
session->open_channel->remote.window_size_initial = window_size;
session->open_channel->remote.packet_size = packet_size;
libssh2_channel_add(session, session->open_channel);
s = session->open_packet =
LIBSSH2_ALLOC(session, session->open_packet_len);
if (!session->open_packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate temporary space for packet", 0);
goto channel_error;
}
*(s++) = SSH_MSG_CHANNEL_OPEN;
libssh2_htonu32(s, channel_type_len);
s += 4;
memcpy(s, channel_type, channel_type_len);
s += channel_type_len;
libssh2_htonu32(s, session->open_local_channel);
s += 4;
libssh2_htonu32(s, window_size);
s += 4;
libssh2_htonu32(s, packet_size);
s += 4;
if (message && message_len) {
memcpy(s, message, message_len);
s += message_len;
}
session->open_state = libssh2_NB_state_created;
}
if (session->open_state == libssh2_NB_state_created) {
rc = libssh2_packet_write(session, session->open_packet,
session->open_packet_len);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block sending channel-open request", 0);
return NULL;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send channel-open request", 0);
goto channel_error;
}
session->open_state = libssh2_NB_state_sent;
}
if (session->open_state == libssh2_NB_state_sent) {
rc = libssh2_packet_requirev_ex(session, reply_codes,
&session->open_data,
&session->open_data_len, 1,
session->open_packet + 5 +
channel_type_len, 4,
&session->open_packet_requirev_state);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block", 0);
return NULL;
} else if (rc) {
goto channel_error;
}
if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
session->open_channel->remote.id =
libssh2_ntohu32(session->open_data + 5);
session->open_channel->local.window_size =
libssh2_ntohu32(session->open_data + 9);
session->open_channel->local.window_size_initial =
libssh2_ntohu32(session->open_data + 9);
session->open_channel->local.packet_size =
libssh2_ntohu32(session->open_data + 13);
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Connection Established - ID: %lu/%lu win: %lu/%lu pack: %lu/%lu",
session->open_channel->local.id,
session->open_channel->remote.id,
session->open_channel->local.window_size,
session->open_channel->remote.window_size,
session->open_channel->local.packet_size,
session->open_channel->remote.packet_size);
LIBSSH2_FREE(session, session->open_packet);
session->open_packet = NULL;
LIBSSH2_FREE(session, session->open_data);
session->open_data = NULL;
session->open_state = libssh2_NB_state_idle;
return session->open_channel;
}
if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_FAILURE) {
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
"Channel open failure", 0);
}
}
channel_error:
if (session->open_data) {
LIBSSH2_FREE(session, session->open_data);
session->open_data = NULL;
}
if (session->open_packet) {
LIBSSH2_FREE(session, session->open_packet);
session->open_packet = NULL;
}
if (session->open_channel) {
unsigned char channel_id[4];
LIBSSH2_FREE(session, session->open_channel->channel_type);
if (session->open_channel->next) {
session->open_channel->next->prev = session->open_channel->prev;
}
if (session->open_channel->prev) {
session->open_channel->prev->next = session->open_channel->next;
}
if (session->channels.head == session->open_channel) {
session->channels.head = session->open_channel->next;
}
if (session->channels.tail == session->open_channel) {
session->channels.tail = session->open_channel->prev;
}
/* Clear out packets meant for this channel */
libssh2_htonu32(channel_id, session->open_channel->local.id);
while ((libssh2_packet_ask_ex
(session, SSH_MSG_CHANNEL_DATA, &session->open_data,
&session->open_data_len, 1, channel_id, 4, 0) >= 0)
||
(libssh2_packet_ask_ex
(session, SSH_MSG_CHANNEL_EXTENDED_DATA, &session->open_data,
&session->open_data_len, 1, channel_id, 4, 0) >= 0)) {
LIBSSH2_FREE(session, session->open_data);
session->open_data = NULL;
}
/* Free any state variables still holding data */
if (session->open_channel->write_packet) {
LIBSSH2_FREE(session, session->open_channel->write_packet);
session->open_channel->write_packet = NULL;
}
LIBSSH2_FREE(session, session->open_channel);
session->open_channel = NULL;
}
session->open_state = libssh2_NB_state_idle;
return NULL;
}
|
|||||
| ↓ | libssh2_userauth_publickey_fromfile_ex | 24 | 179 | 312 | src/userauth.c |
LIBSSH2_API int
libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION * session,
const char *username,
unsigned int username_len,
const char *publickey,
const char *privatekey,
const char *passphrase)
{
const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
void *abstract;
unsigned char buf[5];
struct iovec datavec[4];
unsigned char *pubkeydata, *sig;
unsigned char reply_codes[4] =
{ SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
SSH_MSG_USERAUTH_PK_OK, 0
};
unsigned long pubkeydata_len, sig_len;
int rc;
if (session->userauth_pblc_state == libssh2_NB_state_idle) {
/* Zero the whole thing out */
memset(&session->userauth_pblc_packet_requirev_state, 0,
sizeof(session->userauth_pblc_packet_requirev_state));
if (libssh2_file_read_publickey
(session, &session->userauth_pblc_method,
&session->userauth_pblc_method_len, &pubkeydata, &pubkeydata_len,
publickey)) {
return -1;
}
/*
* 45 = packet_type(1) + username_len(4) + servicename_len(4) +
* service_name(14)"ssh-connection" + authmethod_len(4) +
* authmethod(9)"publickey" + sig_included(1)'\0' + algmethod_len(4) +
* publickey_len(4)
*/
session->userauth_pblc_packet_len =
username_len + session->userauth_pblc_method_len + pubkeydata_len +
45;
/*
* Preallocate space for an overall length, method name again, and
* the signature, which won't be any larger than the size of the
* publickeydata itself
*/
session->userauth_pblc_s = session->userauth_pblc_packet =
LIBSSH2_ALLOC(session,
session->userauth_pblc_packet_len + 4 + (4 +
session->
userauth_pblc_method_len)
+ (4 + pubkeydata_len));
if (!session->userauth_pblc_packet) {
LIBSSH2_FREE(session, session->userauth_pblc_method);
session->userauth_pblc_method = NULL;
LIBSSH2_FREE(session, pubkeydata);
return -1;
}
*(session->userauth_pblc_s++) = SSH_MSG_USERAUTH_REQUEST;
libssh2_htonu32(session->userauth_pblc_s, username_len);
session->userauth_pblc_s += 4;
memcpy(session->userauth_pblc_s, username, username_len);
session->userauth_pblc_s += username_len;
libssh2_htonu32(session->userauth_pblc_s, 14);
session->userauth_pblc_s += 4;
memcpy(session->userauth_pblc_s, "ssh-connection", 14);
session->userauth_pblc_s += 14;
libssh2_htonu32(session->userauth_pblc_s, 9);
session->userauth_pblc_s += 4;
memcpy(session->userauth_pblc_s, "publickey", 9);
session->userauth_pblc_s += 9;
session->userauth_pblc_b = session->userauth_pblc_s;
/* Not sending signature with *this* packet */
*(session->userauth_pblc_s++) = 0;
libssh2_htonu32(session->userauth_pblc_s,
session->userauth_pblc_method_len);
session->userauth_pblc_s += 4;
memcpy(session->userauth_pblc_s, session->userauth_pblc_method,
session->userauth_pblc_method_len);
session->userauth_pblc_s += session->userauth_pblc_method_len;
libssh2_htonu32(session->userauth_pblc_s, pubkeydata_len);
session->userauth_pblc_s += 4;
memcpy(session->userauth_pblc_s, pubkeydata, pubkeydata_len);
session->userauth_pblc_s += pubkeydata_len;
LIBSSH2_FREE(session, pubkeydata);
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
"Attempting publickey authentication");
session->userauth_pblc_state = libssh2_NB_state_created;
}
if (session->userauth_pblc_state == libssh2_NB_state_created) {
rc = libssh2_packet_write(session, session->userauth_pblc_packet,
session->userauth_pblc_packet_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send userauth-publickey request", 0);
LIBSSH2_FREE(session, session->userauth_pblc_packet);
session->userauth_pblc_packet = NULL;
LIBSSH2_FREE(session, session->userauth_pblc_method);
session->userauth_pblc_method = NULL;
session->userauth_pblc_state = libssh2_NB_state_idle;
return -1;
}
session->userauth_pblc_state = libssh2_NB_state_sent;
}
if (session->userauth_pblc_state == libssh2_NB_state_sent) {
rc = libssh2_packet_requirev_ex(session, reply_codes,
&session->userauth_pblc_data,
&session->userauth_pblc_data_len, 0,
NULL, 0,
&session->
userauth_pblc_packet_requirev_state);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
LIBSSH2_FREE(session, session->userauth_pblc_packet);
session->userauth_pblc_packet = NULL;
LIBSSH2_FREE(session, session->userauth_pblc_method);
session->userauth_pblc_method = NULL;
session->userauth_pblc_state = libssh2_NB_state_idle;
return -1;
}
if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
"Pubkey authentication prematurely successful");
/*
* God help any SSH server that allows an UNVERIFIED
* public key to validate the user
*/
LIBSSH2_FREE(session, session->userauth_pblc_data);
session->userauth_pblc_data = NULL;
LIBSSH2_FREE(session, session->userauth_pblc_packet);
session->userauth_pblc_packet = NULL;
LIBSSH2_FREE(session, session->userauth_pblc_method);
session->userauth_pblc_method = NULL;
session->state |= LIBSSH2_STATE_AUTHENTICATED;
session->userauth_pblc_state = libssh2_NB_state_idle;
return 0;
}
if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_FAILURE) {
/* This public key is not allowed for this user on this server */
LIBSSH2_FREE(session, session->userauth_pblc_data);
session->userauth_pblc_data = NULL;
LIBSSH2_FREE(session, session->userauth_pblc_packet);
session->userauth_pblc_packet = NULL;
LIBSSH2_FREE(session, session->userauth_pblc_method);
session->userauth_pblc_method = NULL;
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED,
"Username/PublicKey combination invalid", 0);
session->userauth_pblc_state = libssh2_NB_state_idle;
return -1;
}
/* Semi-Success! */
LIBSSH2_FREE(session, session->userauth_pblc_data);
session->userauth_pblc_data = NULL;
if (libssh2_file_read_privatekey
(session, &privkeyobj, &abstract, session->userauth_pblc_method,
session->userauth_pblc_method_len, privatekey, passphrase)) {
LIBSSH2_FREE(session, session->userauth_pblc_method);
session->userauth_pblc_method = NULL;
LIBSSH2_FREE(session, session->userauth_pblc_packet);
session->userauth_pblc_packet = NULL;
session->userauth_pblc_state = libssh2_NB_state_idle;
return -1;
}
*session->userauth_pblc_b = 0x01;
libssh2_htonu32(buf, session->session_id_len);
datavec[0].iov_base = buf;
datavec[0].iov_len = 4;
datavec[1].iov_base = session->session_id;
datavec[1].iov_len = session->session_id_len;
datavec[2].iov_base = session->userauth_pblc_packet;
datavec[2].iov_len = session->userauth_pblc_packet_len;
if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
LIBSSH2_FREE(session, session->userauth_pblc_method);
session->userauth_pblc_method = NULL;
LIBSSH2_FREE(session, session->userauth_pblc_packet);
session->userauth_pblc_packet = NULL;
if (privkeyobj->dtor) {
privkeyobj->dtor(session, &abstract);
}
session->userauth_pblc_state = libssh2_NB_state_idle;
return -1;
}
if (privkeyobj->dtor) {
privkeyobj->dtor(session, &abstract);
}
if (sig_len > pubkeydata_len) {
unsigned char *newpacket;
/* Should *NEVER* happen, but...well.. better safe than sorry */
newpacket = LIBSSH2_REALLOC(session, session->userauth_pblc_packet, session->userauth_pblc_packet_len + 4 + (4 + session->userauth_pblc_method_len) + (4 + sig_len)); /* PK sigblob */
if (!newpacket) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Failed allocating additional space for userauth-publickey packet",
0);
LIBSSH2_FREE(session, sig);
LIBSSH2_FREE(session, session->userauth_pblc_packet);
session->userauth_pblc_packet = NULL;
LIBSSH2_FREE(session, session->userauth_pblc_method);
session->userauth_pblc_method = NULL;
session->userauth_pblc_state = libssh2_NB_state_idle;
return -1;
}
session->userauth_pblc_packet = newpacket;
}
session->userauth_pblc_s =
session->userauth_pblc_packet + session->userauth_pblc_packet_len;
libssh2_htonu32(session->userauth_pblc_s,
4 + session->userauth_pblc_method_len + 4 + sig_len);
session->userauth_pblc_s += 4;
libssh2_htonu32(session->userauth_pblc_s,
session->userauth_pblc_method_len);
session->userauth_pblc_s += 4;
memcpy(session->userauth_pblc_s, session->userauth_pblc_method,
session->userauth_pblc_method_len);
session->userauth_pblc_s += session->userauth_pblc_method_len;
LIBSSH2_FREE(session, session->userauth_pblc_method);
session->userauth_pblc_method = NULL;
libssh2_htonu32(session->userauth_pblc_s, sig_len);
session->userauth_pblc_s += 4;
memcpy(session->userauth_pblc_s, sig, sig_len);
session->userauth_pblc_s += sig_len;
LIBSSH2_FREE(session, sig);
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
"Attempting publickey authentication -- phase 2");
session->userauth_pblc_state = libssh2_NB_state_sent1;
}
if (session->userauth_pblc_state == libssh2_NB_state_sent1) {
rc = libssh2_packet_write(session, session->userauth_pblc_packet,
session->userauth_pblc_s -
session->userauth_pblc_packet);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send userauth-publickey request", 0);
LIBSSH2_FREE(session, session->userauth_pblc_packet);
session->userauth_pblc_packet = NULL;
session->userauth_pblc_state = libssh2_NB_state_idle;
return -1;
}
LIBSSH2_FREE(session, session->userauth_pblc_packet);
session->userauth_pblc_packet = NULL;
session->userauth_pblc_state = libssh2_NB_state_sent2;
}
/* PK_OK is no longer valid */
reply_codes[2] = 0;
rc = libssh2_packet_requirev_ex(session, reply_codes,
&session->userauth_pblc_data,
&session->userauth_pblc_data_len, 0, NULL,
0,
&session->
userauth_pblc_packet_requirev_state);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
session->userauth_pblc_state = libssh2_NB_state_idle;
return -1;
}
if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
"Publickey authentication successful");
/* We are us and we've proved it. */
LIBSSH2_FREE(session, session->userauth_pblc_data);
session->userauth_pblc_data = NULL;
session->state |= LIBSSH2_STATE_AUTHENTICATED;
session->userauth_pblc_state = libssh2_NB_state_idle;
return 0;
}
/* This public key is not allowed for this user on this server */
LIBSSH2_FREE(session, session->userauth_pblc_data);
session->userauth_pblc_data = NULL;
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
"Invalid signature for supplied public key, or bad username/public key combination",
0);
session->userauth_pblc_state = libssh2_NB_state_idle;
return -1;
}
|
|||||
| ↓ | libssh2_kex_exchange | 23 | 71 | 125 | src/kex.c |
int
libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, /* session->flags |= SERVER */
key_exchange_state_t * key_state)
{
int rc = 0;
int retcode;
session->state |= LIBSSH2_STATE_KEX_ACTIVE;
if (key_state->state == libssh2_NB_state_idle) {
/* Prevent loop in packet_add() */
session->state |= LIBSSH2_STATE_EXCHANGING_KEYS;
if (reexchange) {
session->kex = NULL;
if (session->hostkey && session->hostkey->dtor) {
session->hostkey->dtor(session,
&session->server_hostkey_abstract);
}
session->hostkey = NULL;
}
key_state->state = libssh2_NB_state_created;
}
if (!session->kex || !session->hostkey) {
if (key_state->state == libssh2_NB_state_created) {
/* Preserve in case of failure */
key_state->oldlocal = session->local.kexinit;
key_state->oldlocal_len = session->local.kexinit_len;
session->local.kexinit = NULL;
key_state->state = libssh2_NB_state_sent;
}
if (key_state->state == libssh2_NB_state_sent) {
retcode = libssh2_kexinit(session);
if (retcode == PACKET_EAGAIN) {
session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
return PACKET_EAGAIN;
} else if (retcode) {
session->local.kexinit = key_state->oldlocal;
session->local.kexinit_len = key_state->oldlocal_len;
key_state->state = libssh2_NB_state_idle;
session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
return -1;
}
key_state->state = libssh2_NB_state_sent1;
}
if (key_state->state == libssh2_NB_state_sent1) {
retcode =
libssh2_packet_require_ex(session, SSH_MSG_KEXINIT,
&key_state->data,
&key_state->data_len, 0, NULL, 0,
&key_state->req_state);
if (retcode == PACKET_EAGAIN) {
session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
return PACKET_EAGAIN;
} else if (retcode) {
if (session->local.kexinit) {
LIBSSH2_FREE(session, session->local.kexinit);
}
session->local.kexinit = key_state->oldlocal;
session->local.kexinit_len = key_state->oldlocal_len;
key_state->state = libssh2_NB_state_idle;
session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
return -1;
}
if (session->remote.kexinit) {
LIBSSH2_FREE(session, session->remote.kexinit);
}
session->remote.kexinit = key_state->data;
session->remote.kexinit_len = key_state->data_len;
if (libssh2_kex_agree_methods
(session, key_state->data, key_state->data_len)) {
rc = -1;
}
key_state->state = libssh2_NB_state_sent2;
}
} else {
key_state->state = libssh2_NB_state_sent2;
}
if (rc == 0) {
if (key_state->state == libssh2_NB_state_sent2) {
retcode =
session->kex->exchange_keys(session,
&key_state->key_state_low);
if (retcode == PACKET_EAGAIN) {
session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
return PACKET_EAGAIN;
} else if (retcode) {
libssh2_error(session, LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE,
"Unrecoverable error exchanging keys", 0);
rc = -1;
}
}
}
/* Done with kexinit buffers */
if (session->local.kexinit) {
LIBSSH2_FREE(session, session->local.kexinit);
session->local.kexinit = NULL;
}
if (session->remote.kexinit) {
LIBSSH2_FREE(session, session->remote.kexinit);
session->remote.kexinit = NULL;
}
session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
key_state->state = libssh2_NB_state_idle;
return rc;
}
|
|||||
| ↓ | libssh2_publickey_list_fetch | 23 | 138 | 226 | src/publickey.c |
LIBSSH2_API int
libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys,
libssh2_publickey_list ** pkey_list)
{
LIBSSH2_CHANNEL *channel = pkey->channel;
LIBSSH2_SESSION *session = channel->session;
libssh2_publickey_list *list = NULL;
unsigned long buffer_len = 12, keys = 0, max_keys = 0, i;
/* 12 = packet_len(4) + list_len(4) + "list"(4) */
int response;
int rc;
if (pkey->listFetch_state == libssh2_NB_state_idle) {
pkey->listFetch_data = NULL;
pkey->listFetch_s = pkey->listFetch_buffer;
libssh2_htonu32(pkey->listFetch_s, buffer_len - 4);
pkey->listFetch_s += 4;
libssh2_htonu32(pkey->listFetch_s, sizeof("list") - 1);
pkey->listFetch_s += 4;
memcpy(pkey->listFetch_s, "list", sizeof("list") - 1);
pkey->listFetch_s += sizeof("list") - 1;
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
"Sending publickey \"list\" packet");
pkey->listFetch_state = libssh2_NB_state_created;
}
if (pkey->listFetch_state == libssh2_NB_state_created) {
rc = libssh2_channel_write_ex(channel, 0,
(char *) pkey->listFetch_buffer,
(pkey->listFetch_s -
pkey->listFetch_buffer));
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if ((pkey->listFetch_s - pkey->listFetch_buffer) != rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send publickey list packet", 0);
pkey->listFetch_state = libssh2_NB_state_idle;
return -1;
}
pkey->listFetch_state = libssh2_NB_state_sent;
}
while (1) {
rc = libssh2_publickey_packet_receive(pkey, &pkey->listFetch_data,
&pkey->listFetch_data_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for response from publickey subsystem",
0);
goto err_exit;
}
pkey->listFetch_s = pkey->listFetch_data;
if ((response =
libssh2_publickey_response_id(&pkey->listFetch_s,
pkey->listFetch_data_len)) < 0) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
"Invalid publickey subsystem response code", 0);
goto err_exit;
}
switch (response) {
case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
/* Error, or processing complete */
{
unsigned long status, descr_len, lang_len;
unsigned char *descr, *lang;
status = libssh2_ntohu32(pkey->listFetch_s);
pkey->listFetch_s += 4;
descr_len = libssh2_ntohu32(pkey->listFetch_s);
pkey->listFetch_s += 4;
descr = pkey->listFetch_s;
pkey->listFetch_s += descr_len;
lang_len = libssh2_ntohu32(pkey->listFetch_s);
pkey->listFetch_s += 4;
lang = pkey->listFetch_s;
pkey->listFetch_s += lang_len;
if (pkey->listFetch_s >
pkey->listFetch_data + pkey->listFetch_data_len) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
"Malformed publickey subsystem packet", 0);
goto err_exit;
}
if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
LIBSSH2_FREE(session, pkey->listFetch_data);
pkey->listFetch_data = NULL;
*pkey_list = list;
*num_keys = keys;
pkey->listFetch_state = libssh2_NB_state_idle;
return 0;
}
libssh2_publickey_status_error(pkey, session, status, descr,
descr_len);
goto err_exit;
}
case LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY:
/* What we want */
if (keys >= max_keys) {
libssh2_publickey_list *newlist;
/* Grow the key list if necessary */
max_keys += 8;
newlist =
LIBSSH2_REALLOC(session, list,
(max_keys +
1) * sizeof(libssh2_publickey_list));
if (!newlist) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for publickey list",
0);
goto err_exit;
}
list = newlist;
}
if (pkey->version == 1) {
unsigned long comment_len;
comment_len = libssh2_ntohu32(pkey->listFetch_s);
pkey->listFetch_s += 4;
if (comment_len) {
list[keys].num_attrs = 1;
list[keys].attrs =
LIBSSH2_ALLOC(session,
sizeof(libssh2_publickey_attribute));
if (!list[keys].attrs) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for publickey attributes",
0);
goto err_exit;
}
list[keys].attrs[0].name = "comment";
list[keys].attrs[0].name_len = sizeof("comment") - 1;
list[keys].attrs[0].value = (char *) pkey->listFetch_s;
list[keys].attrs[0].value_len = comment_len;
list[keys].attrs[0].mandatory = 0;
pkey->listFetch_s += comment_len;
} else {
list[keys].num_attrs = 0;
list[keys].attrs = NULL;
}
list[keys].name_len = libssh2_ntohu32(pkey->listFetch_s);
pkey->listFetch_s += 4;
list[keys].name = pkey->listFetch_s;
pkey->listFetch_s += list[keys].name_len;
list[keys].blob_len = libssh2_ntohu32(pkey->listFetch_s);
pkey->listFetch_s += 4;
list[keys].blob = pkey->listFetch_s;
pkey->listFetch_s += list[keys].blob_len;
} else {
/* Version == 2 */
list[keys].name_len = libssh2_ntohu32(pkey->listFetch_s);
pkey->listFetch_s += 4;
list[keys].name = pkey->listFetch_s;
pkey->listFetch_s += list[keys].name_len;
list[keys].blob_len = libssh2_ntohu32(pkey->listFetch_s);
pkey->listFetch_s += 4;
list[keys].blob = pkey->listFetch_s;
pkey->listFetch_s += list[keys].blob_len;
list[keys].num_attrs = libssh2_ntohu32(pkey->listFetch_s);
pkey->listFetch_s += 4;
if (list[keys].num_attrs) {
list[keys].attrs =
LIBSSH2_ALLOC(session,
list[keys].num_attrs *
sizeof(libssh2_publickey_attribute));
if (!list[keys].attrs) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for publickey attributes",
0);
goto err_exit;
}
for(i = 0; i < list[keys].num_attrs; i++) {
list[keys].attrs[i].name_len =
libssh2_ntohu32(pkey->listFetch_s);
pkey->listFetch_s += 4;
list[keys].attrs[i].name = (char *) pkey->listFetch_s;
pkey->listFetch_s += list[keys].attrs[i].name_len;
list[keys].attrs[i].value_len =
libssh2_ntohu32(pkey->listFetch_s);
pkey->listFetch_s += 4;
list[keys].attrs[i].value = (char *) pkey->listFetch_s;
pkey->listFetch_s += list[keys].attrs[i].value_len;
list[keys].attrs[i].mandatory = 0; /* actually an ignored value */
}
} else {
list[keys].attrs = NULL;
}
}
list[keys].packet = pkey->listFetch_data; /* To be FREEd in libssh2_publickey_list_free() */
keys++;
list[keys].packet = NULL; /* Terminate the list */
pkey->listFetch_data = NULL;
break;
default:
/* Unknown/Unexpected */
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
"Unexpected publickey subsystem response, ignoring",
0);
LIBSSH2_FREE(session, pkey->listFetch_data);
pkey->listFetch_data = NULL;
}
}
/* Only reached via explicit goto */
err_exit:
if (pkey->listFetch_data) {
LIBSSH2_FREE(session, pkey->listFetch_data);
pkey->listFetch_data = NULL;
}
if (list) {
libssh2_publickey_list_free(pkey, list);
}
pkey->listFetch_state = libssh2_NB_state_idle;
return -1;
}
|
|||||
| ↓ | libssh2_sftp_init | 22 | 94 | 168 | src/sftp.c |
LIBSSH2_API LIBSSH2_SFTP *
libssh2_sftp_init(LIBSSH2_SESSION * session)
{
unsigned char *data, *s;
unsigned long data_len;
int rc;
if (session->sftpInit_state == libssh2_NB_state_idle) {
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
"Initializing SFTP subsystem");
session->sftpInit_sftp = NULL;
session->sftpInit_state = libssh2_NB_state_created;
}
if (session->sftpInit_state == libssh2_NB_state_created) {
session->sftpInit_channel =
libssh2_channel_open_ex(session, "session", sizeof("session") - 1,
LIBSSH2_CHANNEL_WINDOW_DEFAULT,
LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0);
if (!session->sftpInit_channel) {
if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block starting up channel", 0);
return NULL;
} else if (libssh2_session_last_errno(session) !=
LIBSSH2_ERROR_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
"Unable to startup channel", 0);
session->sftpInit_state = libssh2_NB_state_idle;
return NULL;
}
}
session->sftpInit_state = libssh2_NB_state_sent;
}
if (session->sftpInit_state == libssh2_NB_state_sent) {
rc = libssh2_channel_process_startup(session->sftpInit_channel,
"subsystem",
sizeof("subsystem") - 1, "sftp",
strlen("sftp"));
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block to request SFTP subsystem", 0);
return NULL;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
"Unable to request SFTP subsystem", 0);
goto sftp_init_error;
}
session->sftpInit_state = libssh2_NB_state_sent1;
}
if (session->sftpInit_state == libssh2_NB_state_sent1) {
rc = libssh2_channel_handle_extended_data2(session->sftpInit_channel,
LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block requesting handle extended data", 0);
return NULL;
}
session->sftpInit_sftp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP));
if (!session->sftpInit_sftp) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate a new SFTP structure", 0);
goto sftp_init_error;
}
memset(session->sftpInit_sftp, 0, sizeof(LIBSSH2_SFTP));
session->sftpInit_sftp->channel = session->sftpInit_channel;
session->sftpInit_sftp->request_id = 0;
libssh2_htonu32(session->sftpInit_buffer, 5);
session->sftpInit_buffer[4] = SSH_FXP_INIT;
libssh2_htonu32(session->sftpInit_buffer + 5, LIBSSH2_SFTP_VERSION);
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
"Sending FXP_INIT packet advertising version %d support",
(int) LIBSSH2_SFTP_VERSION);
session->sftpInit_state = libssh2_NB_state_sent2;
}
if (session->sftpInit_state == libssh2_NB_state_sent2) {
rc = libssh2_channel_write_ex(session->sftpInit_channel, 0,
(char *) session->sftpInit_buffer, 9);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block sending SSH_FXP_INIT", 0);
return NULL;
} else if (9 != rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send SSH_FXP_INIT", 0);
goto sftp_init_error;
}
session->sftpInit_state = libssh2_NB_state_sent3;
}
/* For initiallization we are requiring blocking, probably reasonable */
rc = libssh2_sftp_packet_require(session->sftpInit_sftp, SSH_FXP_VERSION,
0, &data, &data_len);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block waiting for response from SFTP subsystem",
0);
return NULL;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for response from SFTP subsystem", 0);
goto sftp_init_error;
}
if (data_len < 5) {
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"Invalid SSH_FXP_VERSION response", 0);
goto sftp_init_error;
}
s = data + 1;
session->sftpInit_sftp->version = libssh2_ntohu32(s);
s += 4;
if (session->sftpInit_sftp->version > LIBSSH2_SFTP_VERSION) {
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
"Truncating remote SFTP version from %lu",
session->sftpInit_sftp->version);
session->sftpInit_sftp->version = LIBSSH2_SFTP_VERSION;
}
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
"Enabling SFTP version %lu compatability",
session->sftpInit_sftp->version);
while (s < (data + data_len)) {
unsigned char *extension_name, *extension_data;
unsigned long extname_len, extdata_len;
extname_len = libssh2_ntohu32(s);
s += 4;
extension_name = s;
s += extname_len;
extdata_len = libssh2_ntohu32(s);
s += 4;
extension_data = s;
s += extdata_len;
/* TODO: Actually process extensions */
}
LIBSSH2_FREE(session, data);
/* Make sure that when the channel gets closed, the SFTP service is shut down too */
session->sftpInit_sftp->channel->abstract = session->sftpInit_sftp;
session->sftpInit_sftp->channel->close_cb = libssh2_sftp_dtor;
session->sftpInit_state = libssh2_NB_state_idle;
return session->sftpInit_sftp;
sftp_init_error:
while (libssh2_channel_free(session->sftpInit_channel) == PACKET_EAGAIN);
session->sftpInit_channel = NULL;
if (session->sftpInit_sftp) {
LIBSSH2_FREE(session, session->sftpInit_sftp);
session->sftpInit_sftp = NULL;
}
session->sftpInit_state = libssh2_NB_state_idle;
return NULL;
}
|
|||||
| ↓ | libssh2_comp_method_zlib_comp | 22 | 74 | 132 | src/comp.c |
static int
libssh2_comp_method_zlib_comp(LIBSSH2_SESSION * session,
int compress,
unsigned char **dest,
unsigned long *dest_len,
unsigned long payload_limit,
int *free_dest,
const unsigned char *src,
unsigned long src_len, void **abstract)
{
z_stream *strm = *abstract;
/* A short-term alloc of a full data chunk is better than a series of
reallocs */
char *out;
int out_maxlen = compress ? (src_len + 4) : (2 * src_len);
int limiter = 0;
/* In practice they never come smaller than this */
if (out_maxlen < 25) {
out_maxlen = 25;
}
if (out_maxlen > (int) payload_limit) {
out_maxlen = payload_limit;
}
strm->next_in = (unsigned char *) src;
strm->avail_in = src_len;
strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, out_maxlen);
out = (char *) strm->next_out;
strm->avail_out = out_maxlen;
if (!strm->next_out) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate compression/decompression buffer",
0);
return -1;
}
while (strm->avail_in) {
int status;
if (compress) {
status = deflate(strm, Z_PARTIAL_FLUSH);
} else {
status = inflate(strm, Z_PARTIAL_FLUSH);
}
if (status != Z_OK) {
libssh2_error(session, LIBSSH2_ERROR_ZLIB,
"compress/decompression failure", 0);
LIBSSH2_FREE(session, out);
return -1;
}
if (strm->avail_in) {
unsigned long out_ofs = out_maxlen - strm->avail_out;
char *newout;
out_maxlen +=
compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
if ((out_maxlen > (int) payload_limit) && !compress && limiter++) {
libssh2_error(session, LIBSSH2_ERROR_ZLIB,
"Excessive growth in decompression phase", 0);
LIBSSH2_FREE(session, out);
return -1;
}
newout = LIBSSH2_REALLOC(session, out, out_maxlen);
if (!newout) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to expand compress/decompression buffer",
0);
LIBSSH2_FREE(session, out);
return -1;
}
out = newout;
strm->next_out = (unsigned char *) out + out_ofs;
strm->avail_out +=
compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
} else
while (!strm->avail_out) {
/* Done with input, might be a byte or two in internal buffer during compress
* Or potentially many bytes if it's a decompress
*/
int grow_size = compress ? 8 : 1024;
char *newout;
if (out_maxlen >= (int) payload_limit) {
libssh2_error(session, LIBSSH2_ERROR_ZLIB,
"Excessive growth in decompression phase",
0);
LIBSSH2_FREE(session, out);
return -1;
}
if (grow_size > (int) (payload_limit - out_maxlen)) {
grow_size = payload_limit - out_maxlen;
}
out_maxlen += grow_size;
strm->avail_out = grow_size;
newout = LIBSSH2_REALLOC(session, out, out_maxlen);
if (!newout) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to expand final compress/decompress buffer",
0);
LIBSSH2_FREE(session, out);
return -1;
}
out = newout;
strm->next_out = (unsigned char *) out + out_maxlen -
grow_size;
if (compress) {
status = deflate(strm, Z_PARTIAL_FLUSH);
} else {
status = inflate(strm, Z_PARTIAL_FLUSH);
}
if (status != Z_OK) {
libssh2_error(session, LIBSSH2_ERROR_ZLIB,
"compress/decompression failure", 0);
LIBSSH2_FREE(session, out);
return -1;
}
}
}
*dest = (unsigned char *) out;
*dest_len = out_maxlen - strm->avail_out;
*free_dest = 1;
return 0;
}
|
|||||
| ↓ | libssh2_session_startup | 22 | 70 | 143 | src/session.c |
LIBSSH2_API int
libssh2_session_startup(LIBSSH2_SESSION * session, int sock)
{
int rc;
if (session->startup_state == libssh2_NB_state_idle) {
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
"session_startup for socket %d", sock);
/* FIXME: on some platforms (like win32) sockets are unsigned */
if (sock < 0) {
/* Did we forget something? */
libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE,
"Bad socket provided", 0);
return LIBSSH2_ERROR_SOCKET_NONE;
}
session->socket_fd = sock;
session->socket_block =
!_libssh2_get_socket_nonblocking(session->socket_fd);
if (session->socket_block) {
/*
* Since we can't be sure that we are in blocking or there
* was an error detecting the state, so set to blocking to
* be sure
*/
_libssh2_nonblock(session->socket_fd, 0);
}
session->startup_state = libssh2_NB_state_created;
}
/* TODO: Liveness check */
if (session->startup_state == libssh2_NB_state_created) {
rc = libssh2_banner_send(session);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block sending banner to remote host", 0);
return LIBSSH2_ERROR_EAGAIN;
} else if (rc) {
/* Unable to send banner? */
libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND,
"Error sending banner to remote host", 0);
return LIBSSH2_ERROR_BANNER_SEND;
}
session->startup_state = libssh2_NB_state_sent;
}
if (session->startup_state == libssh2_NB_state_sent) {
rc = libssh2_banner_receive(session);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block waiting for banner", 0);
return LIBSSH2_ERROR_EAGAIN;
} else if (rc) {
/* Unable to receive banner from remote */
libssh2_error(session, LIBSSH2_ERROR_BANNER_NONE,
"Timeout waiting for banner", 0);
return LIBSSH2_ERROR_BANNER_NONE;
}
session->startup_state = libssh2_NB_state_sent1;
}
if (session->startup_state == libssh2_NB_state_sent1) {
rc = libssh2_kex_exchange(session, 0, &session->startup_key_state);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block exchanging encryption keys", 0);
return LIBSSH2_ERROR_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE,
"Unable to exchange encryption keys", 0);
return LIBSSH2_ERROR_KEX_FAILURE;
}
session->startup_state = libssh2_NB_state_sent2;
}
if (session->startup_state == libssh2_NB_state_sent2) {
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
"Requesting userauth service");
/* Request the userauth service */
session->startup_service[0] = SSH_MSG_SERVICE_REQUEST;
libssh2_htonu32(session->startup_service + 1,
sizeof("ssh-userauth") - 1);
memcpy(session->startup_service + 5, "ssh-userauth",
sizeof("ssh-userauth") - 1);
session->startup_state = libssh2_NB_state_sent3;
}
if (session->startup_state == libssh2_NB_state_sent3) {
rc = libssh2_packet_write(session, session->startup_service,
sizeof("ssh-userauth") + 5 - 1);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block asking for ssh-userauth service", 0);
return LIBSSH2_ERROR_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to ask for ssh-userauth service", 0);
return LIBSSH2_ERROR_SOCKET_SEND;
}
session->startup_state = libssh2_NB_state_sent4;
}
if (session->startup_state == libssh2_NB_state_sent4) {
rc = libssh2_packet_require_ex(session, SSH_MSG_SERVICE_ACCEPT,
&session->startup_data,
&session->startup_data_len, 0, NULL, 0,
&session->startup_req_state);
if (rc == PACKET_EAGAIN) {
return LIBSSH2_ERROR_EAGAIN;
} else if (rc) {
return LIBSSH2_ERROR_SOCKET_DISCONNECT;
}
session->startup_service_length =
libssh2_ntohu32(session->startup_data + 1);
if ((session->startup_service_length != (sizeof("ssh-userauth") - 1))
|| strncmp("ssh-userauth", (char *) session->startup_data + 5,
session->startup_service_length)) {
LIBSSH2_FREE(session, session->startup_data);
session->startup_data = NULL;
libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Invalid response received from server", 0);
return LIBSSH2_ERROR_PROTO;
}
LIBSSH2_FREE(session, session->startup_data);
session->startup_data = NULL;
session->startup_state = libssh2_NB_state_idle;
return 0;
}
/* just for safety return some error */
return LIBSSH2_ERROR_INVAL;
}
|
|||||
| ↓ | libssh2_channel_write_ex | 22 | 69 | 174 | src/channel.c |
LIBSSH2_API ssize_t
libssh2_channel_write_ex(LIBSSH2_CHANNEL * channel, int stream_id,
const char *buf, size_t buflen)
{
LIBSSH2_SESSION *session = channel->session;
libssh2pack_t rc;
if (channel->write_state == libssh2_NB_state_idle) {
channel->write_bufwrote = 0;
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Writing %d bytes on channel %lu/%lu, stream #%d",
(int) buflen, channel->local.id, channel->remote.id,
stream_id);
if (channel->local.close) {
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_CLOSED,
"We've already closed this channel", 0);
return -1;
}
if (channel->local.eof) {
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_EOF_SENT,
"EOF has already been sight, data might be ignored",
0);
}
#if 0
/*
The following chunk of code is #ifdef'ed out, since I wanted it to
remain here with the given explanation why having the code in here
is not a good idea. The text is taken from the email Gavrie
Philipson wrote to libssh2-devel on Nov 8 2007.
The logic behind this is that in nonblocking mode, if the local
window size has shrunk to zero, there's no point in trying to send
anything more. However, exiting the function at that point does not
allow any adjusts from the remote side to be received, since
libssh2_packet_read (that is called further on in this function) is
never called in this case.
Removing this bit of code fixes the problem. This should not cause
busy waiting, since after the libssh2_packet_read, the function
correctly returns PACKET_EAGAIN if the window size was not adjusted.
*/
if (!channel->session->socket_block &&
(channel->local.window_size <= 0)) {
/* Can't write anything */
return 0;
}
#endif
/* [13] 9 = packet_type(1) + channelno(4) [ + streamid(4) ] + buflen(4) */
channel->write_packet_len = buflen + (stream_id ? 13 : 9);
channel->write_packet =
LIBSSH2_ALLOC(session, channel->write_packet_len);
if (!channel->write_packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocte space for data transmission packet",
0);
return -1;
}
channel->write_state = libssh2_NB_state_allocated;
}
while (buflen > 0) {
if (channel->write_state == libssh2_NB_state_allocated) {
channel->write_bufwrite = buflen;
channel->write_s = channel->write_packet;
*(channel->write_s++) =
stream_id ? SSH_MSG_CHANNEL_EXTENDED_DATA :
SSH_MSG_CHANNEL_DATA;
libssh2_htonu32(channel->write_s, channel->remote.id);
channel->write_s += 4;
if (stream_id) {
libssh2_htonu32(channel->write_s, stream_id);
channel->write_s += 4;
}
/* twiddle our thumbs until there's window space available */
while (channel->local.window_size <= 0) {
/* Don't worry -- This is never hit unless it's a
blocking channel anyway */
rc = libssh2_packet_read(session);
if (rc < 0) {
/* Error or EAGAIN occurred, disconnect? */
if (rc != PACKET_EAGAIN) {
channel->write_state = libssh2_NB_state_idle;
}
return rc;
}
if ((rc == 0) && (session->socket_block == 0)) {
/*
* if rc == 0 and in non-blocking, then fake EAGAIN
* to prevent busyloops until data arriaves on the network
* which seemed like a very bad idea
*/
return PACKET_EAGAIN;
}
}
/* Don't exceed the remote end's limits */
/* REMEMBER local means local as the SOURCE of the data */
if (channel->write_bufwrite > channel->local.window_size) {
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Splitting write block due to %lu byte window_size on %lu/%lu/%d",
channel->local.window_size, channel->local.id,
channel->remote.id, stream_id);
channel->write_bufwrite = channel->local.window_size;
}
if (channel->write_bufwrite > channel->local.packet_size) {
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Splitting write block due to %lu byte packet_size on %lu/%lu/%d",
channel->local.packet_size, channel->local.id,
channel->remote.id, stream_id);
channel->write_bufwrite = channel->local.packet_size;
}
libssh2_htonu32(channel->write_s, channel->write_bufwrite);
channel->write_s += 4;
memcpy(channel->write_s, buf, channel->write_bufwrite);
channel->write_s += channel->write_bufwrite;
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Sending %d bytes on channel %lu/%lu, stream_id=%d",
(int) channel->write_bufwrite, channel->local.id,
channel->remote.id, stream_id);
channel->write_state = libssh2_NB_state_created;
}
if (channel->write_state == libssh2_NB_state_created) {
rc = libssh2_packet_write(session, channel->write_packet,
channel->write_s -
channel->write_packet);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send channel data", 0);
LIBSSH2_FREE(session, channel->write_packet);
channel->write_packet = NULL;
channel->write_state = libssh2_NB_state_idle;
return -1;
}
/* Shrink local window size */
channel->local.window_size -= channel->write_bufwrite;
/* Adjust buf for next iteration */
buflen -= channel->write_bufwrite;
buf += channel->write_bufwrite;
channel->write_bufwrote += channel->write_bufwrite;
channel->write_state = libssh2_NB_state_allocated;
/*
* Not sure this is still wanted
if (!channel->session->socket_block) {
break;
}
*/
}
}
LIBSSH2_FREE(session, channel->write_packet);
channel->write_packet = NULL;
channel->write_state = libssh2_NB_state_idle;
return channel->write_bufwrote;
}
|
|||||
| ↓ | libssh2_packet_write | 21 | 68 | 150 | src/transport.c |
int
libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
unsigned long data_len)
{
int blocksize =
(session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->
blocksize : 8;
int padding_length;
int packet_length;
int total_length;
int free_data = 0;
#ifdef RANDOM_PADDING
int rand_max;
int seed = data[0]; /* FIXME: make this random */
#endif
struct transportpacket *p = &session->packet;
int encrypted;
int i;
ssize_t ret;
libssh2pack_t rc;
unsigned char *orgdata = data;
unsigned long orgdata_len = data_len;
debugdump(session, "libssh2_packet_write plain", data, data_len);
/* FIRST, check if we have a pending write to complete */
rc = send_existing(session, data, data_len, &ret);
if (rc || ret) {
return rc;
}
encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0;
/* check if we should compress */
if (encrypted && strcmp(session->local.comp->name, "none")) {
if (session->local.comp->
comp(session, 1, &data, &data_len, LIBSSH2_PACKET_MAXCOMP,
&free_data, data, data_len, &session->local.comp_abstract)) {
return PACKET_COMPRESS; /* compression failure */
}
}
/* RFC4253 says: Note that the length of the concatenation of
'packet_length', 'padding_length', 'payload', and 'random padding'
MUST be a multiple of the cipher block size or 8, whichever is
larger. */
/* Plain math: (4 + 1 + packet_length + padding_length) % blocksize == 0 */
packet_length = data_len + 1 + 4; /* 1 is for padding_length field
4 for the packet_length field */
/* at this point we have it all except the padding */
/* first figure out our minimum padding amount to make it an even
block size */
padding_length = blocksize - (packet_length % blocksize);
/* if the padding becomes too small we add another blocksize worth
of it (taken from the original libssh2 where it didn't have any
real explanation) */
if (padding_length < 4) {
padding_length += blocksize;
}
#ifdef RANDOM_PADDING
/* FIXME: we can add padding here, but that also makes the packets
bigger etc */
/* now we can add 'blocksize' to the padding_length N number of times
(to "help thwart traffic analysis") but it must be less than 255 in
total */
rand_max = (255 - padding_length) / blocksize + 1;
padding_length += blocksize * (seed % rand_max);
#endif
packet_length += padding_length;
/* append the MAC length to the total_length size */
total_length =
packet_length + (encrypted ? session->local.mac->mac_len : 0);
/* allocate memory to store the outgoing packet in, in case we can't
send the whole one and thus need to keep it after this function
returns. */
p->outbuf = LIBSSH2_ALLOC(session, total_length);
if (!p->outbuf) {
return PACKET_ENOMEM;
}
/* store packet_length, which is the size of the whole packet except
the MAC and the packet_length field itself */
libssh2_htonu32(p->outbuf, packet_length - 4);
/* store padding_length */
p->outbuf[4] = padding_length;
/* copy the payload data */
memcpy(p->outbuf + 5, data, data_len);
/* fill the padding area with random junk */
libssh2_random(p->outbuf + 5 + data_len, padding_length);
if (free_data) {
LIBSSH2_FREE(session, data);
}
if (encrypted) {
/* Calculate MAC hash. Put the output at index packet_length,
since that size includes the whole packet. The MAC is
calculated on the entire unencrypted packet, including all
fields except the MAC field itself. */
session->local.mac->hash(session, p->outbuf + packet_length,
session->local.seqno, p->outbuf,
packet_length, NULL, 0,
&session->local.mac_abstract);
/* Encrypt the whole packet data, one block size at a time.
The MAC field is not encrypted. */
for(i = 0; i < packet_length; i += session->local.crypt->blocksize) {
unsigned char *ptr = &p->outbuf[i];
if (session->local.crypt->
crypt(session, ptr, &session->local.crypt_abstract))
return PACKET_FAIL; /* encryption failure */
}
}
session->local.seqno++;
ret = send(session->socket_fd, p->outbuf, total_length,
LIBSSH2_SOCKET_SEND_FLAGS(session));
if (ret != -1) {
debugdump(session, "libssh2_packet_write send()", p->outbuf, ret);
}
if (ret != total_length) {
if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
/* the whole packet could not be sent, save the rest */
p->odata = orgdata;
p->olen = orgdata_len;
p->osent = (ret == -1) ? 0 : ret;
p->ototal_num = total_length;
return PACKET_EAGAIN;
}
return PACKET_FAIL;
}
/* the whole thing got sent away */
p->odata = NULL;
p->olen = 0;
LIBSSH2_FREE(session, p->outbuf);
p->outbuf = NULL;
return PACKET_NONE; /* all is good */
}
|
|||||
| ↓ | libssh2_channel_forward_listen_ex | 20 | 94 | 156 | src/channel.c |
LIBSSH2_API LIBSSH2_LISTENER *
libssh2_channel_forward_listen_ex(LIBSSH2_SESSION * session, const char *host,
int port, int *bound_port, int queue_maxsize)
{
unsigned char *s, *data;
static const unsigned char reply_codes[3] =
{ SSH_MSG_REQUEST_SUCCESS, SSH_MSG_REQUEST_FAILURE, 0 };
unsigned long data_len;
int rc;
if (session->fwdLstn_state == libssh2_NB_state_idle) {
session->fwdLstn_host_len =
(host ? strlen(host) : (sizeof("0.0.0.0") - 1));
/* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4) + port(4) */
session->fwdLstn_packet_len =
session->fwdLstn_host_len + (sizeof("tcpip-forward") - 1) + 14;
/* Zero the whole thing out */
memset(&session->fwdLstn_packet_requirev_state, 0,
sizeof(session->fwdLstn_packet_requirev_state));
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Requesting tcpip-forward session for %s:%d", host,
port);
s = session->fwdLstn_packet =
LIBSSH2_ALLOC(session, session->fwdLstn_packet_len);
if (!session->fwdLstn_packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memeory for setenv packet", 0);
return NULL;
}
*(s++) = SSH_MSG_GLOBAL_REQUEST;
libssh2_htonu32(s, sizeof("tcpip-forward") - 1);
s += 4;
memcpy(s, "tcpip-forward", sizeof("tcpip-forward") - 1);
s += sizeof("tcpip-forward") - 1;
*(s++) = 0x01; /* want_reply */
libssh2_htonu32(s, session->fwdLstn_host_len);
s += 4;
memcpy(s, host ? host : "0.0.0.0", session->fwdLstn_host_len);
s += session->fwdLstn_host_len;
libssh2_htonu32(s, port);
s += 4;
session->fwdLstn_state = libssh2_NB_state_created;
}
if (session->fwdLstn_state == libssh2_NB_state_created) {
rc = libssh2_packet_write(session, session->fwdLstn_packet,
session->fwdLstn_packet_len);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block sending global-request packet for forward listen request",
0);
return NULL;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send global-request packet for forward listen request",
0);
LIBSSH2_FREE(session, session->fwdLstn_packet);
session->fwdLstn_packet = NULL;
session->fwdLstn_state = libssh2_NB_state_idle;
return NULL;
}
LIBSSH2_FREE(session, session->fwdLstn_packet);
session->fwdLstn_packet = NULL;
session->fwdLstn_state = libssh2_NB_state_sent;
}
if (session->fwdLstn_state == libssh2_NB_state_sent) {
rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
0, NULL, 0,
&session->
fwdLstn_packet_requirev_state);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block", 0);
return NULL;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_PROTO, "Unknown", 0);
session->fwdLstn_state = libssh2_NB_state_idle;
return NULL;
}
if (data[0] == SSH_MSG_REQUEST_SUCCESS) {
LIBSSH2_LISTENER *listener;
listener = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_LISTENER));
if (!listener) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for listener queue",
0);
LIBSSH2_FREE(session, data);
session->fwdLstn_state = libssh2_NB_state_idle;
return NULL;
}
memset(listener, 0, sizeof(LIBSSH2_LISTENER));
listener->session = session;
listener->host =
LIBSSH2_ALLOC(session, session->fwdLstn_host_len + 1);
if (!listener->host) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for listener queue",
0);
LIBSSH2_FREE(session, listener);
LIBSSH2_FREE(session, data);
session->fwdLstn_state = libssh2_NB_state_idle;
return NULL;
}
memcpy(listener->host, host ? host : "0.0.0.0",
session->fwdLstn_host_len);
listener->host[session->fwdLstn_host_len] = 0;
if (data_len >= 5 && !port) {
listener->port = libssh2_ntohu32(data + 1);
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Dynamic tcpip-forward port allocated: %d",
listener->port);
} else {
listener->port = port;
}
listener->queue_size = 0;
listener->queue_maxsize = queue_maxsize;
listener->next = session->listeners;
listener->prev = NULL;
if (session->listeners) {
session->listeners->prev = listener;
}
session->listeners = listener;
if (bound_port) {
*bound_port = listener->port;
}
LIBSSH2_FREE(session, data);
session->fwdLstn_state = libssh2_NB_state_idle;
return listener;
}
if (data[0] == SSH_MSG_REQUEST_FAILURE) {
LIBSSH2_FREE(session, data);
libssh2_error(session, LIBSSH2_ERROR_REQUEST_DENIED,
"Unable to complete request for forward-listen", 0);
session->fwdLstn_state = libssh2_NB_state_idle;
return NULL;
}
}
session->fwdLstn_state = libssh2_NB_state_idle;
return NULL;
}
|
|||||
| ↓ | libssh2_sftp_open_ex | 20 | 90 | 151 | src/sftp.c |
LIBSSH2_API LIBSSH2_SFTP_HANDLE *
libssh2_sftp_open_ex(LIBSSH2_SFTP * sftp, const char *filename,
unsigned int filename_len, unsigned long flags, long mode,
int open_type)
{
LIBSSH2_CHANNEL *channel = sftp->channel;
LIBSSH2_SESSION *session = channel->session;
LIBSSH2_SFTP_HANDLE *fp;
LIBSSH2_SFTP_ATTRIBUTES attrs = {
LIBSSH2_SFTP_ATTR_PERMISSIONS, 0, 0, 0, 0, 0, 0
};
unsigned long data_len;
unsigned char *data, *s;
static const unsigned char fopen_responses[2] =
{ SSH_FXP_HANDLE, SSH_FXP_STATUS };
int rc;
if (sftp->open_state == libssh2_NB_state_idle) {
/* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) + flags(4) */
sftp->open_packet_len = filename_len + 13 +
((open_type ==
LIBSSH2_SFTP_OPENFILE) ? (4 +
libssh2_sftp_attrsize(&attrs)) : 0);
s = sftp->open_packet = LIBSSH2_ALLOC(session, sftp->open_packet_len);
if (!sftp->open_packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for FXP_OPEN or FXP_OPENDIR packet",
0);
return NULL;
}
/* Filetype in SFTP 3 and earlier */
attrs.permissions = mode |
((open_type ==
LIBSSH2_SFTP_OPENFILE) ? LIBSSH2_SFTP_ATTR_PFILETYPE_FILE :
LIBSSH2_SFTP_ATTR_PFILETYPE_DIR);
libssh2_htonu32(s, sftp->open_packet_len - 4);
s += 4;
*(s++) =
(open_type ==
LIBSSH2_SFTP_OPENFILE) ? SSH_FXP_OPEN : SSH_FXP_OPENDIR;
sftp->open_request_id = sftp->request_id++;
libssh2_htonu32(s, sftp->open_request_id);
s += 4;
libssh2_htonu32(s, filename_len);
s += 4;
memcpy(s, filename, filename_len);
s += filename_len;
if (open_type == LIBSSH2_SFTP_OPENFILE) {
libssh2_htonu32(s, flags);
s += 4;
s += libssh2_sftp_attr2bin(s, &attrs);
}
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending %s open request",
(open_type ==
LIBSSH2_SFTP_OPENFILE) ? "file" : "directory");
sftp->open_state = libssh2_NB_state_created;
}
if (sftp->open_state == libssh2_NB_state_created) {
rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->open_packet,
sftp->open_packet_len);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block sending FXP_OPEN or FXP_OPENDIR command",
0);
return NULL;
} else if (sftp->open_packet_len != rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send FXP_OPEN or FXP_OPENDIR command", 0);
LIBSSH2_FREE(session, sftp->open_packet);
sftp->open_packet = NULL;
sftp->open_state = libssh2_NB_state_idle;
return NULL;
}
LIBSSH2_FREE(session, sftp->open_packet);
sftp->open_packet = NULL;
sftp->open_state = libssh2_NB_state_sent;
}
if (sftp->open_state == libssh2_NB_state_sent) {
rc = libssh2_sftp_packet_requirev(sftp, 2, fopen_responses,
sftp->open_request_id, &data,
&data_len);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block waiting for status message", 0);
return NULL;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for status message", 0);
sftp->open_state = libssh2_NB_state_idle;
return NULL;
}
}
sftp->open_state = libssh2_NB_state_idle;
if (data[0] == SSH_FXP_STATUS) {
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"Failed opening remote file", 0);
sftp->last_errno = libssh2_ntohu32(data + 5);
LIBSSH2_FREE(session, data);
return NULL;
}
fp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP_HANDLE));
if (!fp) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate new SFTP handle structure", 0);
LIBSSH2_FREE(session, data);
return NULL;
}
memset(fp, 0, sizeof(LIBSSH2_SFTP_HANDLE));
fp->handle_type =
(open_type ==
LIBSSH2_SFTP_OPENFILE) ? LIBSSH2_SFTP_HANDLE_FILE :
LIBSSH2_SFTP_HANDLE_DIR;
fp->handle_len = libssh2_ntohu32(data + 5);
if (fp->handle_len > 256) {
/* SFTP doesn't allow handles longer than 256 characters */
fp->handle_len = 256;
}
fp->handle = LIBSSH2_ALLOC(session, fp->handle_len);
if (!fp->handle) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate space for SFTP file/dir handle", 0);
LIBSSH2_FREE(session, data);
LIBSSH2_FREE(session, fp);
return NULL;
}
memcpy(fp->handle, data + 9, fp->handle_len);
LIBSSH2_FREE(session, data);
/* Link the file and the sftp session together */
fp->next = sftp->handles;
if (fp->next) {
fp->next->prev = fp;
}
fp->sftp = sftp;
fp->u.file.offset = 0;
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Open command successful");
return fp;
}
|
|||||
| ↓ | libssh2_sftp_packet_read | 20 | 57 | 102 | src/sftp.c |
static int
libssh2_sftp_packet_read(LIBSSH2_SFTP * sftp, int flush)
{
LIBSSH2_CHANNEL *channel = sftp->channel;
LIBSSH2_SESSION *session = channel->session;
unsigned char buffer[4]; /* To store the packet length */
unsigned char *packet;
unsigned long packet_len, packet_received;
ssize_t bytes_received;
int rc;
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Waiting for packet");
if (flush && sftp->partial_packet) {
/* When flushing, remove previous partial */
LIBSSH2_FREE(session, sftp->partial_packet);
sftp->partial_packet = NULL;
}
/* If there was a previous partial, start using it */
if (sftp->partial_packet) {
packet = sftp->partial_packet;
packet_len = sftp->partial_len;
packet_received = sftp->partial_received;
sftp->partial_packet = NULL;
} else {
if (flush && session->socket_block && !libssh2_waitsocket(session, 0)) {
/* While flushing in blocking mode, check before reading */
return -1;
}
rc = libssh2_channel_read_ex(channel, 0, (char *) buffer, 4);
if (flush && (rc < 0)) {
/* When flushing, exit quickly */
return -1;
} else if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (4 != rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for FXP packet", 0);
return -1;
}
packet_len = libssh2_ntohu32(buffer);
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
"Data begin - Packet Length: %lu", packet_len);
if (packet_len > LIBSSH2_SFTP_PACKET_MAXLEN) {
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED,
"SFTP packet too large", 0);
return -1;
}
packet = LIBSSH2_ALLOC(session, packet_len);
if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate SFTP packet", 0);
return -1;
}
packet_received = 0;
}
/* Read as much of the packet as we can */
while (packet_len > packet_received) {
bytes_received =
libssh2_channel_read_ex(channel, 0,
(char *) packet + packet_received,
packet_len - packet_received);
if (flush && (bytes_received < 0)) {
if (packet) {
/* When flushing, remove packet if existing */
LIBSSH2_FREE(session, packet);
}
/* When flushing, exit quickly */
return -1;
} else if (bytes_received == PACKET_EAGAIN) {
/*
* We received EAGAIN, save what we have and
* return to EAGAIN to the caller
*/
sftp->partial_packet = packet;
sftp->partial_len = packet_len;
sftp->partial_received = packet_received;
packet = NULL;
return PACKET_EAGAIN;
} else if (bytes_received < 0) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Receive error waiting for SFTP packet", 0);
LIBSSH2_FREE(session, packet);
return -1;
}
packet_received += bytes_received;
}
if (libssh2_sftp_packet_add(sftp, packet, packet_len)) {
LIBSSH2_FREE(session, packet);
return -1;
}
return packet[0];
}
|
|||||
| ↓ | libssh2_sftp_symlink_ex | 21 | 80 | 137 | src/sftp.c |
LIBSSH2_API int
libssh2_sftp_symlink_ex(LIBSSH2_SFTP * sftp, const char *path,
unsigned int path_len, char *target,
unsigned int target_len, int link_type)
{
LIBSSH2_CHANNEL *channel = sftp->channel;
LIBSSH2_SESSION *session = channel->session;
unsigned long data_len, link_len;
/* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
ssize_t packet_len =
path_len + 13 +
((link_type == LIBSSH2_SFTP_SYMLINK) ? (4 + target_len) : 0);
unsigned char *s, *data;
static const unsigned char link_responses[2] =
{ SSH_FXP_NAME, SSH_FXP_STATUS };
int rc;
if ((sftp->version < 3) && (link_type != LIBSSH2_SFTP_REALPATH)) {
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"Server does not support SYMLINK or READLINK", 0);
return -1;
}
if (sftp->symlink_state == libssh2_NB_state_idle) {
s = sftp->symlink_packet = LIBSSH2_ALLOC(session, packet_len);
if (!sftp->symlink_packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for SYMLINK/READLINK/REALPATH packet",
0);
return -1;
}
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s on %s",
(link_type ==
LIBSSH2_SFTP_SYMLINK) ? "Creating" : "Reading",
(link_type ==
LIBSSH2_SFTP_REALPATH) ? "realpath" : "symlink", path);
libssh2_htonu32(s, packet_len - 4);
s += 4;
switch (link_type) {
case LIBSSH2_SFTP_REALPATH:
*(s++) = SSH_FXP_REALPATH;
break;
case LIBSSH2_SFTP_SYMLINK:
*(s++) = SSH_FXP_SYMLINK;
break;
case LIBSSH2_SFTP_READLINK:
default:
*(s++) = SSH_FXP_READLINK;
}
sftp->symlink_request_id = sftp->request_id++;
libssh2_htonu32(s, sftp->symlink_request_id);
s += 4;
libssh2_htonu32(s, path_len);
s += 4;
memcpy(s, path, path_len);
s += path_len;
if (link_type == LIBSSH2_SFTP_SYMLINK) {
libssh2_htonu32(s, target_len);
s += 4;
memcpy(s, target, target_len);
s += target_len;
}
sftp->symlink_state = libssh2_NB_state_created;
}
if (sftp->symlink_state == libssh2_NB_state_created) {
rc = libssh2_channel_write_ex(channel, 0,
(char *) sftp->symlink_packet,
packet_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (packet_len != rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send SYMLINK/READLINK command", 0);
LIBSSH2_FREE(session, sftp->symlink_packet);
sftp->symlink_packet = NULL;
sftp->symlink_state = libssh2_NB_state_idle;
return -1;
}
LIBSSH2_FREE(session, sftp->symlink_packet);
sftp->symlink_packet = NULL;
sftp->symlink_state = libssh2_NB_state_sent;
}
rc = libssh2_sftp_packet_requirev(sftp, 2, link_responses,
sftp->symlink_request_id, &data,
&data_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for status message", 0);
sftp->symlink_state = libssh2_NB_state_idle;
return -1;
}
sftp->symlink_state = libssh2_NB_state_idle;
if (data[0] == SSH_FXP_STATUS) {
int retcode;
retcode = libssh2_ntohu32(data + 5);
LIBSSH2_FREE(session, data);
if (retcode == LIBSSH2_FX_OK) {
return 0;
} else {
sftp->last_errno = retcode;
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"SFTP Protocol Error", 0);
return -1;
}
}
if (libssh2_ntohu32(data + 5) < 1) {
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"Invalid READLINK/REALPATH response, no name entries",
0);
LIBSSH2_FREE(session, data);
return -1;
}
link_len = libssh2_ntohu32(data + 9);
if (link_len >= target_len) {
link_len = target_len - 1;
}
memcpy(target, data + 13, link_len);
target[link_len] = 0;
LIBSSH2_FREE(session, data);
return link_len;
}
|
|||||
| ↓ | libssh2_kex_agree_hostkey | 19 | 28 | 65 | src/kex.c |
static int
libssh2_kex_agree_hostkey(LIBSSH2_SESSION * session, unsigned long kex_flags,
unsigned char *hostkey, unsigned long hostkey_len)
{
const LIBSSH2_HOSTKEY_METHOD **hostkeyp = libssh2_hostkey_methods();
unsigned char *s;
if (session->hostkey_prefs) {
s = (unsigned char *) session->hostkey_prefs;
while (s && *s) {
unsigned char *p = (unsigned char *) strchr((char *) s, ',');
int method_len = (p ? (p - s) : strlen((char *) s));
if (libssh2_kex_agree_instr(hostkey, hostkey_len, s, method_len)) {
const LIBSSH2_HOSTKEY_METHOD *method =
(const LIBSSH2_HOSTKEY_METHOD *)
libssh2_get_method_by_name((char *) s, method_len,
(const LIBSSH2_COMMON_METHOD **)
hostkeyp);
if (!method) {
/* Invalid method -- Should never be reached */
return -1;
}
/* So far so good, but does it suit our purposes? (Encrypting vs Signing) */
if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) ==
0) || (method->encrypt)) {
/* Either this hostkey can do encryption or this kex just doesn't require it */
if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY)
== 0) || (method->sig_verify)) {
/* Either this hostkey can do signing or this kex just doesn't require it */
session->hostkey = method;
return 0;
}
}
}
s = p ? p + 1 : NULL;
}
return -1;
}
while (hostkeyp && (*hostkeyp)->name) {
s = libssh2_kex_agree_instr(hostkey, hostkey_len,
(unsigned char *) (*hostkeyp)->name,
strlen((*hostkeyp)->name));
if (s) {
/* So far so good, but does it suit our purposes? (Encrypting vs Signing) */
if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) == 0) ||
((*hostkeyp)->encrypt)) {
/* Either this hostkey can do encryption or this kex just doesn't require it */
if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY) ==
0) || ((*hostkeyp)->sig_verify)) {
/* Either this hostkey can do signing or this kex just doesn't require it */
session->hostkey = *hostkeyp;
return 0;
}
}
}
hostkeyp++;
}
return -1;
}
|
|||||
| ↓ | libssh2_packet_queue_listener | 19 | 117 | 205 | src/packet.c |
static inline int
libssh2_packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
unsigned long datalen,
packet_queue_listener_state_t * listen_state)
{
/*
* Look for a matching listener
*/
unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5;
/* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
unsigned long packet_len = 17 + (sizeof(FwdNotReq) - 1);
unsigned char *p;
LIBSSH2_LISTENER *listen = session->listeners;
char failure_code = 1; /* SSH_OPEN_ADMINISTRATIVELY_PROHIBITED */
int rc;
(void) datalen;
if (listen_state->state == libssh2_NB_state_idle) {
listen_state->sender_channel = libssh2_ntohu32(s);
s += 4;
listen_state->initial_window_size = libssh2_ntohu32(s);
s += 4;
listen_state->packet_size = libssh2_ntohu32(s);
s += 4;
listen_state->host_len = libssh2_ntohu32(s);
s += 4;
listen_state->host = s;
s += listen_state->host_len;
listen_state->port = libssh2_ntohu32(s);
s += 4;
listen_state->shost_len = libssh2_ntohu32(s);
s += 4;
listen_state->shost = s;
s += listen_state->shost_len;
listen_state->sport = libssh2_ntohu32(s);
s += 4;
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Remote received connection from %s:%ld to %s:%ld",
listen_state->shost, listen_state->sport,
listen_state->host, listen_state->port);
listen_state->state = libssh2_NB_state_allocated;
}
if (listen_state->state != libssh2_NB_state_sent) {
while (listen) {
if ((listen->port == (int) listen_state->port) &&
(strlen(listen->host) == listen_state->host_len) &&
(memcmp
(listen->host, listen_state->host,
listen_state->host_len) == 0)) {
/* This is our listener */
LIBSSH2_CHANNEL *channel, *last_queued = listen->queue;
last_queued = listen->queue;
if (listen_state->state == libssh2_NB_state_allocated) {
if (listen->queue_maxsize &&
(listen->queue_maxsize <= listen->queue_size)) {
/* Queue is full */
failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Listener queue full, ignoring");
listen_state->state = libssh2_NB_state_sent;
break;
}
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
if (!channel) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate a channel for new connection",
0);
failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
listen_state->state = libssh2_NB_state_sent;
break;
}
memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
channel->session = session;
channel->channel_type_len = sizeof("forwarded-tcpip") - 1;
channel->channel_type = LIBSSH2_ALLOC(session,
channel->
channel_type_len +
1);
if (!channel->channel_type) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate a channel for new connection",
0);
LIBSSH2_FREE(session, channel);
failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
listen_state->state = libssh2_NB_state_sent;
break;
}
memcpy(channel->channel_type, "forwarded-tcpip",
channel->channel_type_len + 1);
channel->remote.id = listen_state->sender_channel;
channel->remote.window_size_initial =
LIBSSH2_CHANNEL_WINDOW_DEFAULT;
channel->remote.window_size =
LIBSSH2_CHANNEL_WINDOW_DEFAULT;
channel->remote.packet_size =
LIBSSH2_CHANNEL_PACKET_DEFAULT;
channel->local.id = libssh2_channel_nextid(session);
channel->local.window_size_initial =
listen_state->initial_window_size;
channel->local.window_size =
listen_state->initial_window_size;
channel->local.packet_size = listen_state->packet_size;
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Connection queued: channel %lu/%lu win %lu/%lu packet %lu/%lu",
channel->local.id, channel->remote.id,
channel->local.window_size,
channel->remote.window_size,
channel->local.packet_size,
channel->remote.packet_size);
p = listen_state->packet;
*(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
libssh2_htonu32(p, channel->remote.id);
p += 4;
libssh2_htonu32(p, channel->local.id);
p += 4;
libssh2_htonu32(p, channel->remote.window_size_initial);
p += 4;
libssh2_htonu32(p, channel->remote.packet_size);
p += 4;
listen_state->state = libssh2_NB_state_created;
}
if (listen_state->state == libssh2_NB_state_created) {
rc = libssh2_packet_write(session, listen_state->packet,
17);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send channel open confirmation",
0);
listen_state->state = libssh2_NB_state_idle;
return -1;
}
/* Link the channel into the end of the queue list */
if (!last_queued) {
listen->queue = channel;
listen_state->state = libssh2_NB_state_idle;
return 0;
}
while (last_queued->next) {
last_queued = last_queued->next;
}
last_queued->next = channel;
channel->prev = last_queued;
listen->queue_size++;
listen_state->state = libssh2_NB_state_idle;
return 0;
}
}
listen = listen->next;
}
listen_state->state = libssh2_NB_state_sent;
}
/* We're not listening to you */
{
p = listen_state->packet;
*(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
libssh2_htonu32(p, listen_state->sender_channel);
p += 4;
libssh2_htonu32(p, failure_code);
p += 4;
libssh2_htonu32(p, sizeof(FwdNotReq) - 1);
p += 4;
memcpy(s, FwdNotReq, sizeof(FwdNotReq) - 1);
p += sizeof(FwdNotReq) - 1;
libssh2_htonu32(p, 0);
rc = libssh2_packet_write(session, listen_state->packet, packet_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send open failure", 0);
listen_state->state = libssh2_NB_state_idle;
return -1;
}
listen_state->state = libssh2_NB_state_idle;
return 0;
}
}
|
|||||
| ↓ | libssh2_channel_x11_req_ex | 18 | 77 | 124 | src/channel.c |
LIBSSH2_API int
libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL * channel, int single_connection,
const char *auth_proto, const char *auth_cookie,
int screen_number)
{
LIBSSH2_SESSION *session = channel->session;
unsigned char *s, *data;
static const unsigned char reply_codes[3] =
{ SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
unsigned long data_len;
unsigned long proto_len =
auth_proto ? strlen(auth_proto) : (sizeof("MIT-MAGIC-COOKIE-1") - 1);
unsigned long cookie_len =
auth_cookie ? strlen(auth_cookie) : LIBSSH2_X11_RANDOM_COOKIE_LEN;
int rc;
if (channel->reqX11_state == libssh2_NB_state_idle) {
/* 30 = packet_type(1) + channel(4) + x11_req_len(4) + "x11-req"(7) +
* want_reply(1) + single_cnx(1) + proto_len(4) + cookie_len(4) +
* screen_num(4) */
channel->reqX11_packet_len = proto_len + cookie_len + 30;
/* Zero the whole thing out */
memset(&channel->reqX11_packet_requirev_state, 0,
sizeof(channel->reqX11_packet_requirev_state));
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Requesting x11-req for channel %lu/%lu: single=%d proto=%s cookie=%s screen=%d",
channel->local.id, channel->remote.id,
single_connection,
auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1",
auth_cookie ? auth_cookie : "
|
|||||
| ↓ | libssh2_publickey_add_ex | 17 | 92 | 133 | src/publickey.c |
LIBSSH2_API int
libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY * pkey, const unsigned char *name,
unsigned long name_len, const unsigned char *blob,
unsigned long blob_len, char overwrite,
unsigned long num_attrs,
const libssh2_publickey_attribute attrs[])
{
LIBSSH2_CHANNEL *channel = pkey->channel;
LIBSSH2_SESSION *session = channel->session;
/* 19 = packet_len(4) + add_len(4) + "add"(3) + name_len(4) + {name} blob_len(4) + {blob} */
unsigned long i, packet_len = 19 + name_len + blob_len;
unsigned char *comment = NULL;
unsigned long comment_len = 0;
int rc;
if (pkey->add_state == libssh2_NB_state_idle) {
pkey->add_packet = NULL;
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Adding %s publickey",
name);
if (pkey->version == 1) {
for(i = 0; i < num_attrs; i++) {
/* Search for a comment attribute */
if (attrs[i].name_len == (sizeof("comment") - 1) &&
strncmp(attrs[i].name, "comment",
sizeof("comment") - 1) == 0) {
comment = (unsigned char *) attrs[i].value;
comment_len = attrs[i].value_len;
break;
}
}
packet_len += 4 + comment_len;
} else {
packet_len += 5; /* overwrite(1) + attribute_count(4) */
for(i = 0; i < num_attrs; i++) {
packet_len += 9 + attrs[i].name_len + attrs[i].value_len;
/* name_len(4) + value_len(4) + mandatory(1) */
}
}
pkey->add_packet = LIBSSH2_ALLOC(session, packet_len);
if (!pkey->add_packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for publickey \"add\" packet",
0);
return -1;
}
pkey->add_s = pkey->add_packet;
libssh2_htonu32(pkey->add_s, packet_len - 4);
pkey->add_s += 4;
libssh2_htonu32(pkey->add_s, sizeof("add") - 1);
pkey->add_s += 4;
memcpy(pkey->add_s, "add", sizeof("add") - 1);
pkey->add_s += sizeof("add") - 1;
if (pkey->version == 1) {
libssh2_htonu32(pkey->add_s, comment_len);
pkey->add_s += 4;
if (comment) {
memcpy(pkey->add_s, comment, comment_len);
pkey->add_s += comment_len;
}
libssh2_htonu32(pkey->add_s, name_len);
pkey->add_s += 4;
memcpy(pkey->add_s, name, name_len);
pkey->add_s += name_len;
libssh2_htonu32(pkey->add_s, blob_len);
pkey->add_s += 4;
memcpy(pkey->add_s, blob, blob_len);
pkey->add_s += blob_len;
} else {
/* Version == 2 */
libssh2_htonu32(pkey->add_s, name_len);
pkey->add_s += 4;
memcpy(pkey->add_s, name, name_len);
pkey->add_s += name_len;
libssh2_htonu32(pkey->add_s, blob_len);
pkey->add_s += 4;
memcpy(pkey->add_s, blob, blob_len);
pkey->add_s += blob_len;
*(pkey->add_s++) = overwrite ? 0x01 : 0;
libssh2_htonu32(pkey->add_s, num_attrs);
pkey->add_s += 4;
for(i = 0; i < num_attrs; i++) {
libssh2_htonu32(pkey->add_s, attrs[i].name_len);
pkey->add_s += 4;
memcpy(pkey->add_s, attrs[i].name, attrs[i].name_len);
pkey->add_s += attrs[i].name_len;
libssh2_htonu32(pkey->add_s, attrs[i].value_len);
pkey->add_s += 4;
memcpy(pkey->add_s, attrs[i].value, attrs[i].value_len);
pkey->add_s += attrs[i].value_len;
*(pkey->add_s++) = attrs[i].mandatory ? 0x01 : 0;
}
}
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
"Sending publickey \"add\" packet: type=%s blob_len=%ld num_attrs=%ld",
name, blob_len, num_attrs);
pkey->add_state = libssh2_NB_state_created;
}
if (pkey->add_state == libssh2_NB_state_created) {
rc = libssh2_channel_write_ex(channel, 0, (char *) pkey->add_packet,
(pkey->add_s - pkey->add_packet));
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if ((pkey->add_s - pkey->add_packet) != rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send publickey add packet", 0);
LIBSSH2_FREE(session, pkey->add_packet);
pkey->add_packet = NULL;
return -1;
}
LIBSSH2_FREE(session, pkey->add_packet);
pkey->add_packet = NULL;
pkey->add_state = libssh2_NB_state_sent;
}
rc = libssh2_publickey_response_success(pkey);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
}
pkey->add_state = libssh2_NB_state_idle;
return rc;
}
|
|||||
| ↓ | libssh2_kex_agree_methods | 17 | 64 | 119 | src/kex.c |
static int
libssh2_kex_agree_methods(LIBSSH2_SESSION * session, unsigned char *data,
unsigned data_len)
{
unsigned char *kex, *hostkey, *crypt_cs, *crypt_sc, *comp_cs, *comp_sc,
*mac_cs, *mac_sc, *lang_cs, *lang_sc;
size_t kex_len, hostkey_len, crypt_cs_len, crypt_sc_len, comp_cs_len;
size_t comp_sc_len, mac_cs_len, mac_sc_len, lang_cs_len, lang_sc_len;
unsigned char *s = data;
/* Skip packet_type, we know it already */
s++;
/* Skip cookie, don't worry, it's preserved in the kexinit field */
s += 16;
/* Locate each string */
kex_len = libssh2_ntohu32(s);
kex = s + 4;
s += 4 + kex_len;
hostkey_len = libssh2_ntohu32(s);
hostkey = s + 4;
s += 4 + hostkey_len;
crypt_cs_len = libssh2_ntohu32(s);
crypt_cs = s + 4;
s += 4 + crypt_cs_len;
crypt_sc_len = libssh2_ntohu32(s);
crypt_sc = s + 4;
s += 4 + crypt_sc_len;
mac_cs_len = libssh2_ntohu32(s);
mac_cs = s + 4;
s += 4 + mac_cs_len;
mac_sc_len = libssh2_ntohu32(s);
mac_sc = s + 4;
s += 4 + mac_sc_len;
comp_cs_len = libssh2_ntohu32(s);
comp_cs = s + 4;
s += 4 + comp_cs_len;
comp_sc_len = libssh2_ntohu32(s);
comp_sc = s + 4;
s += 4 + comp_sc_len;
lang_cs_len = libssh2_ntohu32(s);
lang_cs = s + 4;
s += 4 + lang_cs_len;
lang_sc_len = libssh2_ntohu32(s);
lang_sc = s + 4;
s += 4 + lang_sc_len;
/* If the server sent an optimistic packet, assume that it guessed wrong.
* If the guess is determined to be right (by libssh2_kex_agree_kex_hostkey)
* This flag will be reset to zero so that it's not ignored */
session->burn_optimistic_kexinit = *(s++);
/* Next uint32 in packet is all zeros (reserved) */
if (data_len < (unsigned) (s - data))
return -1; /* short packet */
if (libssh2_kex_agree_kex_hostkey
(session, kex, kex_len, hostkey, hostkey_len)) {
return -1;
}
if (libssh2_kex_agree_crypt
(session, &session->local, crypt_cs, crypt_cs_len)
|| libssh2_kex_agree_crypt(session, &session->remote, crypt_sc,
crypt_sc_len)) {
return -1;
}
if (libssh2_kex_agree_mac(session, &session->local, mac_cs, mac_cs_len) ||
libssh2_kex_agree_mac(session, &session->remote, mac_sc, mac_sc_len)) {
return -1;
}
if (libssh2_kex_agree_comp(session, &session->local, comp_cs, comp_cs_len)
|| libssh2_kex_agree_comp(session, &session->remote, comp_sc,
comp_sc_len)) {
return -1;
}
if (libssh2_kex_agree_lang(session, &session->local, lang_cs, lang_cs_len)
|| libssh2_kex_agree_lang(session, &session->remote, lang_sc,
lang_sc_len)) {
return -1;
}
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on KEX method: %s",
session->kex->name);
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on HOSTKEY method: %s",
session->hostkey->name);
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_CS method: %s",
session->local.crypt->name);
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_SC method: %s",
session->remote.crypt->name);
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_CS method: %s",
session->local.mac->name);
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_SC method: %s",
session->remote.mac->name);
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_CS method: %s",
session->local.comp->name);
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_SC method: %s",
session->remote.comp->name);
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_CS method:"); /* None yet */
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_SC method:"); /* None yet */
/* Initialize compression layer */
if (session->local.comp && session->local.comp->init &&
session->local.comp->init(session, 1, &session->local.comp_abstract)) {
return -1;
}
if (session->remote.comp && session->remote.comp->init &&
session->remote.comp->init(session, 0,
&session->remote.comp_abstract)) {
return -1;
}
return 0;
}
|
|||||
| ↓ | libssh2_channel_flush_ex | 17 | 32 | 73 | src/channel.c |
LIBSSH2_API int
libssh2_channel_flush_ex(LIBSSH2_CHANNEL * channel, int streamid)
{
LIBSSH2_PACKET *packet = channel->session->packets.head;
if (channel->flush_state == libssh2_NB_state_idle) {
channel->flush_refund_bytes = 0;
channel->flush_flush_bytes = 0;
while (packet) {
LIBSSH2_PACKET *next = packet->next;
unsigned char packet_type = packet->data[0];
if (((packet_type == SSH_MSG_CHANNEL_DATA)
|| (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA))
&& (libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
/* It's our channel at least */
long packet_stream_id =
(packet_type ==
SSH_MSG_CHANNEL_DATA) ? 0 : libssh2_ntohu32(packet->data +
5);
if ((streamid == LIBSSH2_CHANNEL_FLUSH_ALL)
|| ((packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)
&& ((streamid == LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA)
|| (streamid == packet_stream_id)))
|| ((packet_type == SSH_MSG_CHANNEL_DATA)
&& (streamid == 0))) {
int bytes_to_flush = packet->data_len - packet->data_head;
_libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
"Flushing %d bytes of data from stream %lu on channel %lu/%lu",
bytes_to_flush, packet_stream_id,
channel->local.id, channel->remote.id);
/* It's one of the streams we wanted to flush */
channel->flush_refund_bytes += packet->data_len - 13;
channel->flush_flush_bytes += bytes_to_flush;
LIBSSH2_FREE(channel->session, packet->data);
if (packet->prev) {
packet->prev->next = packet->next;
} else {
channel->session->packets.head = packet->next;
}
if (packet->next) {
packet->next->prev = packet->prev;
} else {
channel->session->packets.tail = packet->prev;
}
LIBSSH2_FREE(channel->session, packet);
}
}
packet = next;
}
channel->flush_state = libssh2_NB_state_created;
}
if (channel->flush_refund_bytes) {
int rc;
rc = libssh2_channel_receive_window_adjust(channel,
channel->flush_refund_bytes,
0);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
}
}
channel->flush_state = libssh2_NB_state_idle;
return channel->flush_flush_bytes;
}
|
|||||
| ↓ | libssh2_kex_agree_kex_hostkey | 17 | 30 | 70 | src/kex.c |
static int
libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex,
unsigned long kex_len, unsigned char *hostkey,
unsigned long hostkey_len)
{
const LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods;
unsigned char *s;
if (session->kex_prefs) {
s = (unsigned char *) session->kex_prefs;
while (s && *s) {
unsigned char *q, *p = (unsigned char *) strchr((char *) s, ',');
int method_len = (p ? (p - s) : strlen((char *) s));
if ((q = libssh2_kex_agree_instr(kex, kex_len, s, method_len))) {
const LIBSSH2_KEX_METHOD *method = (const LIBSSH2_KEX_METHOD *)
libssh2_get_method_by_name((char *) s, method_len,
(const LIBSSH2_COMMON_METHOD **)
kexp);
if (!method) {
/* Invalid method -- Should never be reached */
return -1;
}
/* We've agreed on a key exchange method,
* Can we agree on a hostkey that works with this kex?
*/
if (libssh2_kex_agree_hostkey
(session, method->flags, hostkey, hostkey_len) == 0) {
session->kex = method;
if (session->burn_optimistic_kexinit && (kex == q)) {
/* Server sent an optimistic packet,
* and client agrees with preference
* cancel burning the first KEX_INIT packet that comes in */
session->burn_optimistic_kexinit = 0;
}
return 0;
}
}
s = p ? p + 1 : NULL;
}
return -1;
}
while (*kexp && (*kexp)->name) {
s = libssh2_kex_agree_instr(kex, kex_len,
(unsigned char *) (*kexp)->name,
strlen((*kexp)->name));
if (s) {
/* We've agreed on a key exchange method,
* Can we agree on a hostkey that works with this kex?
*/
if (libssh2_kex_agree_hostkey
(session, (*kexp)->flags, hostkey, hostkey_len) == 0) {
session->kex = *kexp;
if (session->burn_optimistic_kexinit && (kex == s)) {
/* Server sent an optimistic packet,
* and client agrees with preference
* cancel burning the first KEX_INIT packet that comes in */
session->burn_optimistic_kexinit = 0;
}
return 0;
}
}
kexp++;
}
return -1;
}
|
|||||
| ↓ | libssh2_userauth_hostbased_fromfile_ex | 17 | 130 | 232 | src/userauth.c |
LIBSSH2_API int
libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION * session,
const char *username,
unsigned int username_len,
const char *publickey,
const char *privatekey,
const char *passphrase,
const char *hostname,
unsigned int hostname_len,
const char *local_username,
unsigned int local_username_len)
{
const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
void *abstract;
unsigned char buf[5];
struct iovec datavec[4];
unsigned char *pubkeydata, *sig;
static const unsigned char reply_codes[3] =
{ SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
unsigned long pubkeydata_len, sig_len, data_len;
int rc;
if (session->userauth_host_state == libssh2_NB_state_idle) {
/* Zero the whole thing out */
memset(&session->userauth_host_packet_requirev_state, 0,
sizeof(session->userauth_host_packet_requirev_state));
if (libssh2_file_read_publickey
(session, &session->userauth_host_method,
&session->userauth_host_method_len, &pubkeydata, &pubkeydata_len,
publickey)) {
return -1;
}
/*
* 48 = packet_type(1) + username_len(4) + servicename_len(4) +
* service_name(14)"ssh-connection" + authmethod_len(4) +
* authmethod(9)"hostbased" + method_len(4) + pubkeydata_len(4) +
* local_username_len(4)
*/
session->userauth_host_packet_len =
username_len + session->userauth_host_method_len + hostname_len +
local_username_len + pubkeydata_len + 48;
/*
* Preallocate space for an overall length, method name again,
* and the signature, which won't be any larger than the size of
* the publickeydata itself
*/
session->userauth_host_s = session->userauth_host_packet =
LIBSSH2_ALLOC(session,
session->userauth_host_packet_len + 4 + (4 +
session->
userauth_host_method_len)
+ (4 + pubkeydata_len));
if (!session->userauth_host_packet) {
LIBSSH2_FREE(session, session->userauth_host_method);
session->userauth_host_method = NULL;
return -1;
}
*(session->userauth_host_s++) = SSH_MSG_USERAUTH_REQUEST;
libssh2_htonu32(session->userauth_host_s, username_len);
session->userauth_host_s += 4;
memcpy(session->userauth_host_s, username, username_len);
session->userauth_host_s += username_len;
libssh2_htonu32(session->userauth_host_s, 14);
session->userauth_host_s += 4;
memcpy(session->userauth_host_s, "ssh-connection", 14);
session->userauth_host_s += 14;
libssh2_htonu32(session->userauth_host_s, 9);
session->userauth_host_s += 4;
memcpy(session->userauth_host_s, "hostbased", 9);
session->userauth_host_s += 9;
libssh2_htonu32(session->userauth_host_s,
session->userauth_host_method_len);
session->userauth_host_s += 4;
memcpy(session->userauth_host_s, session->userauth_host_method,
session->userauth_host_method_len);
session->userauth_host_s += session->userauth_host_method_len;
libssh2_htonu32(session->userauth_host_s, pubkeydata_len);
session->userauth_host_s += 4;
memcpy(session->userauth_host_s, pubkeydata, pubkeydata_len);
session->userauth_host_s += pubkeydata_len;
libssh2_htonu32(session->userauth_host_s, hostname_len);
session->userauth_host_s += 4;
memcpy(session->userauth_host_s, hostname, hostname_len);
session->userauth_host_s += hostname_len;
libssh2_htonu32(session->userauth_host_s, local_username_len);
session->userauth_host_s += 4;
memcpy(session->userauth_host_s, local_username, local_username_len);
session->userauth_host_s += local_username_len;
if (libssh2_file_read_privatekey
(session, &privkeyobj, &abstract, session->userauth_host_method,
session->userauth_host_method_len, privatekey, passphrase)) {
LIBSSH2_FREE(session, session->userauth_host_method);
session->userauth_host_method = NULL;
LIBSSH2_FREE(session, session->userauth_host_packet);
session->userauth_host_packet = NULL;
return -1;
}
libssh2_htonu32(buf, session->session_id_len);
datavec[0].iov_base = buf;
datavec[0].iov_len = 4;
datavec[1].iov_base = session->session_id;
datavec[1].iov_len = session->session_id_len;
datavec[2].iov_base = session->userauth_host_packet;
datavec[2].iov_len = session->userauth_host_packet_len;
if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
LIBSSH2_FREE(session, session->userauth_host_method);
session->userauth_host_method = NULL;
LIBSSH2_FREE(session, session->userauth_host_packet);
session->userauth_host_packet = NULL;
if (privkeyobj->dtor) {
privkeyobj->dtor(session, &abstract);
}
return -1;
}
if (privkeyobj->dtor) {
privkeyobj->dtor(session, &abstract);
}
if (sig_len > pubkeydata_len) {
unsigned char *newpacket;
/* Should *NEVER* happen, but...well.. better safe than sorry */
newpacket = LIBSSH2_REALLOC(session, session->userauth_host_packet, session->userauth_host_packet_len + 4 + (4 + session->userauth_host_method_len) + (4 + sig_len)); /* PK sigblob */
if (!newpacket) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Failed allocating additional space for userauth-hostbased packet",
0);
LIBSSH2_FREE(session, sig);
LIBSSH2_FREE(session, session->userauth_host_packet);
session->userauth_host_packet = NULL;
LIBSSH2_FREE(session, session->userauth_host_method);
session->userauth_host_method = NULL;
return -1;
}
session->userauth_host_packet = newpacket;
}
session->userauth_host_s =
session->userauth_host_packet + session->userauth_host_packet_len;
libssh2_htonu32(session->userauth_host_s,
4 + session->userauth_host_method_len + 4 + sig_len);
session->userauth_host_s += 4;
libssh2_htonu32(session->userauth_host_s,
session->userauth_host_method_len);
session->userauth_host_s += 4;
memcpy(session->userauth_host_s, session->userauth_host_method,
session->userauth_host_method_len);
session->userauth_host_s += session->userauth_host_method_len;
LIBSSH2_FREE(session, session->userauth_host_method);
session->userauth_host_method = NULL;
libssh2_htonu32(session->userauth_host_s, sig_len);
session->userauth_host_s += 4;
memcpy(session->userauth_host_s, sig, sig_len);
session->userauth_host_s += sig_len;
LIBSSH2_FREE(session, sig);
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
"Attempting hostbased authentication");
session->userauth_host_state = libssh2_NB_state_created;
}
if (session->userauth_host_state == libssh2_NB_state_created) {
rc = libssh2_packet_write(session, session->userauth_host_packet,
session->userauth_host_s -
session->userauth_host_packet);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send userauth-hostbased request", 0);
LIBSSH2_FREE(session, session->userauth_host_packet);
session->userauth_host_packet = NULL;
session->userauth_host_state = libssh2_NB_state_idle;
return -1;
}
LIBSSH2_FREE(session, session->userauth_host_packet);
session->userauth_host_packet = NULL;
session->userauth_host_state = libssh2_NB_state_sent;
}
if (session->userauth_host_state == libssh2_NB_state_sent) {
rc = libssh2_packet_requirev_ex(session, reply_codes,
&session->userauth_host_data,
&data_len, 0, NULL, 0,
&session->
userauth_host_packet_requirev_state);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
session->userauth_host_state = libssh2_NB_state_idle;
return -1;
}
if (session->userauth_host_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
_libssh2_debug(session, LIBSSH2_DBG_AUTH,
"Hostbased authentication successful");
/* We are us and we've proved it. */
LIBSSH2_FREE(session, session->userauth_host_data);
session->userauth_host_data = NULL;
session->state |= LIBSSH2_STATE_AUTHENTICATED;
session->userauth_host_state = libssh2_NB_state_idle;
return 0;
}
}
/* This public key is not allowed for this user on this server */
LIBSSH2_FREE(session, session->userauth_host_data);
session->userauth_host_data = NULL;
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
"Invalid signature for supplied public key, or bad username/public key combination",
0);
session->userauth_host_state = libssh2_NB_state_idle;
return -1;
}
|
|||||
| ↓ | libssh2_channel_free | 16 | 38 | 87 | src/channel.c |
LIBSSH2_API int
libssh2_channel_free(LIBSSH2_CHANNEL * channel)
{
LIBSSH2_SESSION *session = channel->session;
unsigned char channel_id[4];
unsigned char *data;
unsigned long data_len;
int rc;
if (channel->free_state == libssh2_NB_state_idle) {
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Freeing channel %lu/%lu resources", channel->local.id,
channel->remote.id);
channel->free_state = libssh2_NB_state_created;
}
/* Allow channel freeing even when the socket has lost its connection */
if (!channel->local.close
&& (session->socket_state == LIBSSH2_SOCKET_CONNECTED)) {
while ((rc = libssh2_channel_close(channel)) == PACKET_EAGAIN);
if (rc) {
channel->free_state = libssh2_NB_state_idle;
return -1;
}
}
channel->free_state = libssh2_NB_state_idle;
/*
* channel->remote.close *might* not be set yet, Well...
* We've sent the close packet, what more do you want?
* Just let packet_add ignore it when it finally arrives
*/
/* Clear out packets meant for this channel */
libssh2_htonu32(channel_id, channel->local.id);
while ((libssh2_packet_ask_ex
(session, SSH_MSG_CHANNEL_DATA, &data, &data_len, 1, channel_id, 4,
0) >= 0)
||
(libssh2_packet_ask_ex
(session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, &data_len, 1,
channel_id, 4, 0) >= 0)) {
LIBSSH2_FREE(session, data);
}
/* free "channel_type" */
if (channel->channel_type) {
LIBSSH2_FREE(session, channel->channel_type);
}
/* Unlink from channel brigade */
if (channel->prev) {
channel->prev->next = channel->next;
} else {
session->channels.head = channel->next;
}
if (channel->next) {
channel->next->prev = channel->prev;
} else {
session->channels.tail = channel->prev;
}
/*
* Make sure all memory used in the state variables are free
*/
if (channel->setenv_packet) {
LIBSSH2_FREE(session, channel->setenv_packet);
}
if (channel->reqPTY_packet) {
LIBSSH2_FREE(session, channel->reqPTY_packet);
}
if (channel->reqX11_packet) {
LIBSSH2_FREE(session, channel->reqX11_packet);
}
if (channel->process_packet) {
LIBSSH2_FREE(session, channel->process_packet);
}
if (channel->write_packet) {
LIBSSH2_FREE(session, channel->write_packet);
}
LIBSSH2_FREE(session, channel);
return 0;
}
|
|||||
| ↓ | libssh2_banner_receive | 19 | 46 | 95 | src/session.c |
static int
libssh2_banner_receive(LIBSSH2_SESSION * session)
{
int ret;
int banner_len;
if (session->banner_TxRx_state == libssh2_NB_state_idle) {
banner_len = 0;
session->banner_TxRx_state = libssh2_NB_state_created;
} else {
banner_len = session->banner_TxRx_total_send;
}
while ((banner_len < (int) sizeof(session->banner_TxRx_banner)) &&
((banner_len == 0)
|| (session->banner_TxRx_banner[banner_len - 1] != '\n'))) {
char c = '\0';
ret =
recv(session->socket_fd, &c, 1,
LIBSSH2_SOCKET_RECV_FLAGS(session));
if (ret < 0) {
#ifdef WIN32
switch (WSAGetLastError()) {
case WSAEWOULDBLOCK:
errno = EAGAIN;
break;
case WSAENOTSOCK:
errno = EBADF;
break;
case WSAENOTCONN:
case WSAECONNABORTED:
errno = WSAENOTCONN;
break;
case WSAEINTR:
errno = EINTR;
break;
}
#endif /* WIN32 */
if (errno == EAGAIN) {
session->banner_TxRx_total_send = banner_len;
return PACKET_EAGAIN;
}
/* Some kinda error */
session->banner_TxRx_state = libssh2_NB_state_idle;
session->banner_TxRx_total_send = 0;
return 1;
}
if (ret == 0) {
session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
return PACKET_FAIL;
}
if (c == '\0') {
/* NULLs are not allowed in SSH banners */
session->banner_TxRx_state = libssh2_NB_state_idle;
session->banner_TxRx_total_send = 0;
return 1;
}
session->banner_TxRx_banner[banner_len++] = c;
}
while (banner_len &&
((session->banner_TxRx_banner[banner_len - 1] == '\n') ||
(session->banner_TxRx_banner[banner_len - 1] == '\r'))) {
banner_len--;
}
/* From this point on, we are done here */
session->banner_TxRx_state = libssh2_NB_state_idle;
session->banner_TxRx_total_send = 0;
if (!banner_len)
return 1;
session->remote.banner = LIBSSH2_ALLOC(session, banner_len + 1);
if (!session->remote.banner) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Error allocating space for remote banner", 0);
return 1;
}
memcpy(session->remote.banner, session->banner_TxRx_banner, banner_len);
session->remote.banner[banner_len] = '\0';
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Received Banner: %s",
session->remote.banner);
return 0;
}
|
|||||
| ↓ | libssh2_sftp_stat_ex | 17 | 67 | 112 | src/sftp.c |
LIBSSH2_API int
libssh2_sftp_stat_ex(LIBSSH2_SFTP * sftp, const char *path,
unsigned int path_len, int stat_type,
LIBSSH2_SFTP_ATTRIBUTES * attrs)
{
LIBSSH2_CHANNEL *channel = sftp->channel;
LIBSSH2_SESSION *session = channel->session;
unsigned long data_len;
/* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
ssize_t packet_len =
path_len + 13 +
((stat_type ==
LIBSSH2_SFTP_SETSTAT) ? libssh2_sftp_attrsize(attrs) : 0);
unsigned char *s, *data;
static const unsigned char stat_responses[2] =
{ SSH_FXP_ATTRS, SSH_FXP_STATUS };
int rc;
if (sftp->stat_state == libssh2_NB_state_idle) {
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s",
(stat_type == LIBSSH2_SFTP_SETSTAT) ? "Set-statting" :
(stat_type ==
LIBSSH2_SFTP_LSTAT ? "LStatting" : "Statting"), path);
s = sftp->stat_packet = LIBSSH2_ALLOC(session, packet_len);
if (!sftp->stat_packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for FXP_MKDIR packet", 0);
return -1;
}
libssh2_htonu32(s, packet_len - 4);
s += 4;
switch (stat_type) {
case LIBSSH2_SFTP_SETSTAT:
*(s++) = SSH_FXP_SETSTAT;
break;
case LIBSSH2_SFTP_LSTAT:
*(s++) = SSH_FXP_LSTAT;
break;
case LIBSSH2_SFTP_STAT:
default:
*(s++) = SSH_FXP_STAT;
}
sftp->stat_request_id = sftp->request_id++;
libssh2_htonu32(s, sftp->stat_request_id);
s += 4;
libssh2_htonu32(s, path_len);
s += 4;
memcpy(s, path, path_len);
s += path_len;
if (stat_type == LIBSSH2_SFTP_SETSTAT) {
s += libssh2_sftp_attr2bin(s, attrs);
}
sftp->stat_state = libssh2_NB_state_created;
}
if (sftp->stat_state == libssh2_NB_state_created) {
rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->stat_packet,
packet_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (packet_len != rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send STAT/LSTAT/SETSTAT command", 0);
LIBSSH2_FREE(session, sftp->stat_packet);
sftp->stat_packet = NULL;
sftp->stat_state = libssh2_NB_state_idle;
return -1;
}
LIBSSH2_FREE(session, sftp->stat_packet);
sftp->stat_packet = NULL;
sftp->stat_state = libssh2_NB_state_sent;
}
rc = libssh2_sftp_packet_requirev(sftp, 2, stat_responses,
sftp->stat_request_id, &data, &data_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for status message", 0);
sftp->stat_state = libssh2_NB_state_idle;
return -1;
}
sftp->stat_state = libssh2_NB_state_idle;
if (data[0] == SSH_FXP_STATUS) {
int retcode;
retcode = libssh2_ntohu32(data + 5);
LIBSSH2_FREE(session, data);
if (retcode == LIBSSH2_FX_OK) {
return 0;
} else {
sftp->last_errno = retcode;
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"SFTP Protocol Error", 0);
return -1;
}
}
memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
libssh2_sftp_bin2attr(attrs, data + 5);
LIBSSH2_FREE(session, data);
return 0;
}
|
|||||
| ↓ | libssh2_sftp_read | 16 | 97 | 162 | src/sftp.c |
LIBSSH2_API ssize_t
libssh2_sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
size_t buffer_maxlen)
{
LIBSSH2_SFTP *sftp = handle->sftp;
LIBSSH2_CHANNEL *channel = sftp->channel;
LIBSSH2_SESSION *session = channel->session;
unsigned long data_len, request_id = 0;
/* 25 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) + offset(8) + length(4) */
ssize_t packet_len = handle->handle_len + 25;
unsigned char *packet, *s, *data;
static const unsigned char read_responses[2] =
{ SSH_FXP_DATA, SSH_FXP_STATUS };
size_t bytes_read = 0;
size_t bytes_requested = 0;
size_t total_read = 0;
int retcode;
if (sftp->read_state == libssh2_NB_state_idle) {
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
"Reading %lu bytes from SFTP handle",
(unsigned long) buffer_maxlen);
packet = LIBSSH2_ALLOC(session, packet_len);
if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for FXP_CLOSE packet", 0);
return -1;
}
sftp->read_state = libssh2_NB_state_allocated;
} else {
packet = sftp->read_packet;
request_id = sftp->read_request_id;
total_read = sftp->read_total_read;
}
while (total_read < buffer_maxlen) {
s = packet;
/*
* If buffer_maxlen bytes will be requested, server may return all
* with one packet. But libssh2 have packet length limit.
* So we request data by pieces.
*/
bytes_requested = buffer_maxlen - total_read;
/* 10 = packet_type(1)+request_id(4)+data_length(4)+end_of_line_flag(1) */
if (bytes_requested > LIBSSH2_SFTP_PACKET_MAXLEN - 10) {
bytes_requested = LIBSSH2_SFTP_PACKET_MAXLEN - 10;
}
#ifdef LIBSSH2_DEBUG_SFTP
_libssh2_debug(session, LIBSSH2_DBG_SFTP,
"Requesting %lu bytes from SFTP handle",
(unsigned long) bytes_requested);
#endif
if (sftp->read_state == libssh2_NB_state_allocated) {
libssh2_htonu32(s, packet_len - 4);
s += 4;
*(s++) = SSH_FXP_READ;
request_id = sftp->request_id++;
libssh2_htonu32(s, request_id);
s += 4;
libssh2_htonu32(s, handle->handle_len);
s += 4;
memcpy(s, handle->handle, handle->handle_len);
s += handle->handle_len;
libssh2_htonu64(s, handle->u.file.offset);
s += 8;
libssh2_htonu32(s, buffer_maxlen);
s += 4;
sftp->read_state = libssh2_NB_state_created;
}
if (sftp->read_state == libssh2_NB_state_created) {
retcode =
libssh2_channel_write_ex(channel, 0, (char *) packet,
packet_len);
if (retcode == PACKET_EAGAIN) {
sftp->read_packet = packet;
sftp->read_request_id = request_id;
sftp->read_total_read = total_read;
return PACKET_EAGAIN;
} else if (packet_len != retcode) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send FXP_READ command", 0);
LIBSSH2_FREE(session, packet);
sftp->read_packet = NULL;
sftp->read_state = libssh2_NB_state_idle;
return -1;
}
sftp->read_packet = packet;
sftp->read_request_id = request_id;
sftp->read_total_read = total_read;
sftp->read_state = libssh2_NB_state_sent;
}
if (sftp->read_state == libssh2_NB_state_sent) {
retcode =
libssh2_sftp_packet_requirev(sftp, 2, read_responses,
request_id, &data, &data_len);
if (retcode == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (retcode) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for status message", 0);
LIBSSH2_FREE(session, packet);
sftp->read_packet = NULL;
sftp->read_state = libssh2_NB_state_idle;
return -1;
}
sftp->read_state = libssh2_NB_state_sent1;
}
switch (data[0]) {
case SSH_FXP_STATUS:
retcode = libssh2_ntohu32(data + 5);
LIBSSH2_FREE(session, packet);
LIBSSH2_FREE(session, data);
sftp->read_packet = NULL;
sftp->read_state = libssh2_NB_state_idle;
if (retcode == LIBSSH2_FX_EOF) {
return total_read;
} else {
sftp->last_errno = retcode;
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"SFTP Protocol Error", 0);
return -1;
}
case SSH_FXP_DATA:
bytes_read = libssh2_ntohu32(data + 5);
if (bytes_read > (data_len - 9)) {
LIBSSH2_FREE(session, packet);
sftp->read_packet = NULL;
sftp->read_state = libssh2_NB_state_idle;
return -1;
}
#ifdef LIBSSH2_DEBUG_SFTP
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu bytes returned",
(unsigned long) bytes_read);
#endif
memcpy(buffer + total_read, data + 9, bytes_read);
handle->u.file.offset += bytes_read;
total_read += bytes_read;
LIBSSH2_FREE(session, data);
/*
* Set the state back to allocated, so a new one will be
* created to either request more data or get EOF
*/
sftp->read_state = libssh2_NB_state_allocated;
}
}
LIBSSH2_FREE(session, packet);
sftp->read_packet = NULL;
sftp->read_state = libssh2_NB_state_idle;
return total_read;
}
|
|||||
| ↓ | libssh2_sftp_fstat_ex | 15 | 63 | 97 | src/sftp.c |
LIBSSH2_API int
libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE * handle,
LIBSSH2_SFTP_ATTRIBUTES * attrs, int setstat)
{
LIBSSH2_SFTP *sftp = handle->sftp;
LIBSSH2_CHANNEL *channel = sftp->channel;
LIBSSH2_SESSION *session = channel->session;
unsigned long data_len;
/* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
ssize_t packet_len =
handle->handle_len + 13 + (setstat ? libssh2_sftp_attrsize(attrs) : 0);
unsigned char *s, *data;
static const unsigned char fstat_responses[2] =
{ SSH_FXP_ATTRS, SSH_FXP_STATUS };
int rc;
if (sftp->fstat_state == libssh2_NB_state_idle) {
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Issuing %s command",
setstat ? "set-stat" : "stat");
s = sftp->fstat_packet = LIBSSH2_ALLOC(session, packet_len);
if (!sftp->fstat_packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for FSTAT/FSETSTAT packet",
0);
return -1;
}
libssh2_htonu32(s, packet_len - 4);
s += 4;
*(s++) = setstat ? SSH_FXP_FSETSTAT : SSH_FXP_FSTAT;
sftp->fstat_request_id = sftp->request_id++;
libssh2_htonu32(s, sftp->fstat_request_id);
s += 4;
libssh2_htonu32(s, handle->handle_len);
s += 4;
memcpy(s, handle->handle, handle->handle_len);
s += handle->handle_len;
if (setstat) {
s += libssh2_sftp_attr2bin(s, attrs);
}
sftp->fstat_state = libssh2_NB_state_created;
}
if (sftp->fstat_state == libssh2_NB_state_created) {
rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->fstat_packet,
packet_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (packet_len != rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
(setstat ? "Unable to send FXP_FSETSTAT"
: "Unable to send FXP_FSTAT command"), 0);
LIBSSH2_FREE(session, sftp->fstat_packet);
sftp->fstat_packet = NULL;
sftp->fstat_state = libssh2_NB_state_idle;
return -1;
}
LIBSSH2_FREE(session, sftp->fstat_packet);
sftp->fstat_packet = NULL;
sftp->fstat_state = libssh2_NB_state_sent;
}
rc = libssh2_sftp_packet_requirev(sftp, 2, fstat_responses,
sftp->fstat_request_id, &data,
&data_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for status message", 0);
sftp->fstat_state = libssh2_NB_state_idle;
return -1;
}
sftp->fstat_state = libssh2_NB_state_idle;
if (data[0] == SSH_FXP_STATUS) {
int retcode;
retcode = libssh2_ntohu32(data + 5);
LIBSSH2_FREE(session, data);
if (retcode == LIBSSH2_FX_OK) {
return 0;
} else {
sftp->last_errno = retcode;
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"SFTP Protocol Error", 0);
return -1;
}
}
libssh2_sftp_bin2attr(attrs, data + 5);
return 0;
}
|
|||||
| _libssh2_rsa_new_private | 3 | 7 | 20 | src/openssl.c | |
| ↓ | libssh2_file_read_publickey | 15 | 52 | 96 | src/userauth.c |
static int
libssh2_file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method,
unsigned long *method_len,
unsigned char **pubkeydata,
unsigned long *pubkeydata_len,
const char *pubkeyfile)
{
FILE *fd;
char c;
unsigned char *pubkey = NULL, *sp1, *sp2, *tmp;
size_t pubkey_len = 0;
unsigned int tmp_len;
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading public key file: %s",
pubkeyfile);
/* Read Public Key */
fd = fopen(pubkeyfile, "r");
if (!fd) {
libssh2_error(session, LIBSSH2_ERROR_FILE,
"Unable to open public key file", 0);
return -1;
}
while (!feof(fd) && (c = fgetc(fd)) != '\r' && c != '\n')
pubkey_len++;
if (feof(fd)) {
/* the last character was EOF */
pubkey_len--;
}
rewind(fd);
if (pubkey_len <= 1) {
libssh2_error(session, LIBSSH2_ERROR_FILE,
"Invalid data in public key file", 0);
fclose(fd);
return -1;
}
pubkey = LIBSSH2_ALLOC(session, pubkey_len);
if (!pubkey) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for public key data", 0);
fclose(fd);
return -1;
}
if (fread(pubkey, 1, pubkey_len, fd) != pubkey_len) {
libssh2_error(session, LIBSSH2_ERROR_FILE,
"Unable to read public key from file", 0);
LIBSSH2_FREE(session, pubkey);
fclose(fd);
return -1;
}
fclose(fd);
/*
* Remove trailing whitespace
*/
while (pubkey_len && isspace(pubkey[pubkey_len - 1]))
pubkey_len--;
if (!pubkey_len) {
libssh2_error(session, LIBSSH2_ERROR_FILE, "Missing public key data",
0);
LIBSSH2_FREE(session, pubkey);
return -1;
}
if ((sp1 = memchr(pubkey, ' ', pubkey_len)) == NULL) {
libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid public key data",
0);
LIBSSH2_FREE(session, pubkey);
return -1;
}
/* Wasting some bytes here (okay, more than some),
* but since it's likely to be freed soon anyway,
* we'll just avoid the extra free/alloc and call it a wash */
*method = pubkey;
*method_len = sp1 - pubkey;
sp1++;
if ((sp2 = memchr(sp1, ' ', pubkey_len - *method_len)) == NULL) {
/* Assume that the id string is missing, but that it's okay */
sp2 = pubkey + pubkey_len;
}
if (libssh2_base64_decode
(session, (char **) &tmp, &tmp_len, (char *) sp1, sp2 - sp1)) {
libssh2_error(session, LIBSSH2_ERROR_FILE,
"Invalid key data, not base64 encoded", 0);
LIBSSH2_FREE(session, pubkey);
return -1;
}
*pubkeydata = tmp;
*pubkeydata_len = tmp_len;
return 0;
}
|
|||||
| ↓ | libssh2_sftp_close_handle | 14 | 63 | 101 | src/sftp.c |
LIBSSH2_API int
libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE * handle)
{
LIBSSH2_SFTP *sftp = handle->sftp;
LIBSSH2_CHANNEL *channel = sftp->channel;
LIBSSH2_SESSION *session = channel->session;
unsigned long data_len, retcode;
/* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
ssize_t packet_len = handle->handle_len + 13;
unsigned char *s, *data;
int rc;
if (handle->close_state == libssh2_NB_state_idle) {
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Closing handle");
s = handle->close_packet = LIBSSH2_ALLOC(session, packet_len);
if (!handle->close_packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for FXP_CLOSE packet", 0);
return -1;
}
libssh2_htonu32(s, packet_len - 4);
s += 4;
*(s++) = SSH_FXP_CLOSE;
handle->close_request_id = sftp->request_id++;
libssh2_htonu32(s, handle->close_request_id);
s += 4;
libssh2_htonu32(s, handle->handle_len);
s += 4;
memcpy(s, handle->handle, handle->handle_len);
s += handle->handle_len;
handle->close_state = libssh2_NB_state_created;
}
if (handle->close_state == libssh2_NB_state_created) {
rc = libssh2_channel_write_ex(channel, 0,
(char *) handle->close_packet,
packet_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (packet_len != rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send FXP_CLOSE command", 0);
LIBSSH2_FREE(session, handle->close_packet);
handle->close_packet = NULL;
handle->close_state = libssh2_NB_state_idle;
return -1;
}
LIBSSH2_FREE(session, handle->close_packet);
handle->close_packet = NULL;
handle->close_state = libssh2_NB_state_sent;
}
if (handle->close_state == libssh2_NB_state_sent) {
rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
handle->close_request_id, &data,
&data_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for status message", 0);
handle->close_state = libssh2_NB_state_idle;
return -1;
}
handle->close_state = libssh2_NB_state_sent1;
}
retcode = libssh2_ntohu32(data + 5);
LIBSSH2_FREE(session, data);
if (retcode != LIBSSH2_FX_OK) {
sftp->last_errno = retcode;
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"SFTP Protocol Error", 0);
handle->close_state = libssh2_NB_state_idle;
return -1;
}
if (handle == sftp->handles) {
sftp->handles = handle->next;
}
if (handle->next) {
handle->next->prev = NULL;
}
if ((handle->handle_type == LIBSSH2_SFTP_HANDLE_DIR)
&& handle->u.dir.names_left) {
LIBSSH2_FREE(session, handle->u.dir.names_packet);
}
handle->close_state = libssh2_NB_state_idle;
LIBSSH2_FREE(session, handle->handle);
LIBSSH2_FREE(session, handle);
return 0;
}
|
|||||
| _libssh2_dsa_sha1_sign | 3 | 16 | 29 | src/openssl.c | |
| ↓ | libssh2_channel_packet_data_len | 14 | 11 | 47 | src/channel.c |
unsigned long
libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
{
LIBSSH2_SESSION *session = channel->session;
LIBSSH2_PACKET *read_packet;
uint32_t read_local_id;
if ((read_packet = session->packets.head) == NULL) {
return 0;
}
while (read_packet) {
read_local_id = libssh2_ntohu32(read_packet->data + 1);
/*
* Either we asked for a specific extended data stream
* (and data was available),
* or the standard stream (and data was available),
* or the standard stream with extended_data_merge
* enabled and data was available
*/
if ((stream_id
&& (read_packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)
&& (channel->local.id == read_local_id)
&& (stream_id == (int) libssh2_ntohu32(read_packet->data + 5)))
|| (!stream_id && (read_packet->data[0] == SSH_MSG_CHANNEL_DATA)
&& (channel->local.id == read_local_id)) || (!stream_id
&& (read_packet->
data[0] ==
SSH_MSG_CHANNEL_EXTENDED_DATA)
&& (channel->
local.id ==
read_local_id)
&& (channel->
remote.
extended_data_ignore_mode
==
LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE)))
{
return (read_packet->data_len - read_packet->data_head);
}
read_packet = read_packet->next;
}
return 0;
}
|
|||||
| _libssh2_dsa_new_private | 3 | 7 | 20 | src/openssl.c | |
| ↓ | fullpacket | 13 | 43 | 109 | src/transport.c |
static libssh2pack_t
fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
{
unsigned char macbuf[MAX_MACSIZE];
struct transportpacket *p = &session->packet;
int rc;
if (session->fullpacket_state == libssh2_NB_state_idle) {
session->fullpacket_macstate = LIBSSH2_MAC_CONFIRMED;
session->fullpacket_payload_len = p->packet_length - 1;
if (encrypted) {
/* Calculate MAC hash */
session->remote.mac->hash(session, macbuf, /* store hash here */
session->remote.seqno,
p->init, 5,
p->payload,
session->fullpacket_payload_len,
&session->remote.mac_abstract);
/* Compare the calculated hash with the MAC we just read from
* the network. The read one is at the very end of the payload
* buffer. Note that 'payload_len' here is the packet_length
* field which includes the padding but not the MAC.
*/
if (memcmp(macbuf, p->payload + session->fullpacket_payload_len,
session->remote.mac->mac_len)) {
session->fullpacket_macstate = LIBSSH2_MAC_INVALID;
}
}
session->remote.seqno++;
/* ignore the padding */
session->fullpacket_payload_len -= p->padding_length;
/* Check for and deal with decompression */
if (session->remote.comp && strcmp(session->remote.comp->name, "none")) {
unsigned char *data;
unsigned long data_len;
int free_payload = 1;
if (session->remote.comp->comp(session, 0,
&data, &data_len,
LIBSSH2_PACKET_MAXDECOMP,
&free_payload,
p->payload,
session->fullpacket_payload_len,
&session->remote.comp_abstract)) {
LIBSSH2_FREE(session, p->payload);
return PACKET_FAIL;
}
if (free_payload) {
LIBSSH2_FREE(session, p->payload);
p->payload = data;
session->fullpacket_payload_len = data_len;
} else {
if (data == p->payload) {
/* It's not to be freed, because the
* compression layer reused payload, So let's
* do the same!
*/
session->fullpacket_payload_len = data_len;
} else {
/* No comp_method actually lets this happen,
* but let's prepare for the future */
LIBSSH2_FREE(session, p->payload);
/* We need a freeable struct otherwise the
* brigade won't know what to do with it */
p->payload = LIBSSH2_ALLOC(session, data_len);
if (!p->payload) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, (char *)
"Unable to allocate memory for copy of uncompressed data",
0);
return PACKET_ENOMEM;
}
memcpy(p->payload, data, data_len);
session->fullpacket_payload_len = data_len;
}
}
}
session->fullpacket_packet_type = p->payload[0];
debugdump(session, "libssh2_packet_read() plain",
p->payload, session->fullpacket_payload_len);
session->fullpacket_state = libssh2_NB_state_created;
}
if (session->fullpacket_state == libssh2_NB_state_created) {
rc = libssh2_packet_add(session, p->payload,
session->fullpacket_payload_len,
session->fullpacket_macstate);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc < 0) {
return PACKET_FAIL;
}
}
session->fullpacket_state = libssh2_NB_state_idle;
return session->fullpacket_packet_type;
}
|
|||||
| ↓ | libssh2_sftp_shutdown | 13 | 37 | 57 | src/sftp.c |
LIBSSH2_API int
libssh2_sftp_shutdown(LIBSSH2_SFTP * sftp)
{
/*
* Make sure all memory used in the state variables are free
*/
if (sftp->partial_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->partial_packet);
sftp->partial_packet = NULL;
}
if (sftp->open_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->open_packet);
sftp->open_packet = NULL;
}
if (sftp->read_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->read_packet);
sftp->read_packet = NULL;
}
if (sftp->readdir_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->readdir_packet);
sftp->readdir_packet = NULL;
}
if (sftp->write_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->write_packet);
sftp->write_packet = NULL;
}
if (sftp->fstat_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->fstat_packet);
sftp->fstat_packet = NULL;
}
if (sftp->unlink_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->unlink_packet);
sftp->unlink_packet = NULL;
}
if (sftp->rename_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->rename_packet);
sftp->rename_packet = NULL;
}
if (sftp->mkdir_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->mkdir_packet);
sftp->mkdir_packet = NULL;
}
if (sftp->rmdir_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->rmdir_packet);
sftp->rmdir_packet = NULL;
}
if (sftp->stat_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->stat_packet);
sftp->stat_packet = NULL;
}
if (sftp->symlink_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->symlink_packet);
sftp->symlink_packet = NULL;
}
return libssh2_channel_free(sftp->channel);
}
|
|||||
| ↓ | libssh2_channel_close | 13 | 35 | 63 | src/channel.c |
LIBSSH2_API int
libssh2_channel_close(LIBSSH2_CHANNEL * channel)
{
LIBSSH2_SESSION *session = channel->session;
int rc = 0;
int retcode;
if (channel->local.close) {
/* Already closed, act like we sent another close,
* even though we didn't... shhhhhh */
channel->close_state = libssh2_NB_state_idle;
return 0;
}
if (channel->close_state == libssh2_NB_state_idle) {
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Closing channel %lu/%lu",
channel->local.id, channel->remote.id);
if (channel->close_cb) {
LIBSSH2_CHANNEL_CLOSE(session, channel);
}
channel->local.close = 1;
channel->close_packet[0] = SSH_MSG_CHANNEL_CLOSE;
libssh2_htonu32(channel->close_packet + 1, channel->remote.id);
channel->close_state = libssh2_NB_state_created;
}
if (channel->close_state == libssh2_NB_state_created) {
retcode = libssh2_packet_write(session, channel->close_packet, 5);
if (retcode == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (retcode) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send close-channel request", 0);
channel->close_state = libssh2_NB_state_idle;
return -1;
}
channel->close_state = libssh2_NB_state_sent;
}
if (channel->close_state == libssh2_NB_state_sent) {
/* We must wait for the remote SSH_MSG_CHANNEL_CLOSE message */
if (!channel->remote.close) {
libssh2pack_t ret;
do {
ret = libssh2_packet_read(session);
if (ret == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (ret < 0) {
rc = -1;
}
} while ((ret != SSH_MSG_CHANNEL_CLOSE) && (rc == 0));
}
}
channel->close_state = libssh2_NB_state_idle;
return rc;
}
|
|||||
| ↓ | libssh2_sftp_packet_requirev | 13 | 30 | 62 | src/sftp.c |
static int
libssh2_sftp_packet_requirev(LIBSSH2_SFTP * sftp, int num_valid_responses,
const unsigned char *valid_responses,
unsigned long request_id, unsigned char **data,
unsigned long *data_len)
{
int i;
int ret;
/*
* If no timeout is active, start a new one and flush
* any pending packets
*/
if (sftp->requirev_start == 0) {
_libssh2_debug(sftp->channel->session, LIBSSH2_DBG_SFTP,
"_requirev(): Initialize timeout");
sftp->requirev_start = time(NULL);
/* Flush */
while (libssh2_sftp_packet_read(sftp, 1) > 0);
}
while (sftp->channel->session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
for(i = 0; i < num_valid_responses; i++) {
if (libssh2_sftp_packet_ask
(sftp, valid_responses[i], request_id, data, data_len,
0) == 0) {
/*
* Set to zero before all returns to say
* the timeout is not active
*/
sftp->requirev_start = 0;
return 0;
}
}
ret = libssh2_sftp_packet_read(sftp, 0);
if ((ret < 0) && (ret != PACKET_EAGAIN)) {
sftp->requirev_start = 0;
return -1;
} else if (ret <= 0) {
/* prevent busy-looping */
long left =
LIBSSH2_READ_TIMEOUT - (time(NULL) - sftp->requirev_start);
if (left <= 0) {
sftp->requirev_start = 0;
return PACKET_TIMEOUT;
} else if (sftp->channel->session->socket_block
&& (libssh2_waitsocket(sftp->channel->session, left) <=
0)) {
sftp->requirev_start = 0;
return PACKET_TIMEOUT;
} else if (ret == PACKET_EAGAIN) {
return PACKET_EAGAIN;
}
}
}
sftp->requirev_start = 0;
return -1;
}
|
|||||
| ↓ | libssh2_session_last_error | 13 | 27 | 50 | src/session.c |
LIBSSH2_API int
libssh2_session_last_error(LIBSSH2_SESSION * session, char **errmsg,
int *errmsg_len, int want_buf)
{
/* No error to report */
if (!session->err_code) {
if (errmsg) {
if (want_buf) {
*errmsg = LIBSSH2_ALLOC(session, 1);
if (*errmsg) {
**errmsg = 0;
}
} else {
*errmsg = (char *) "";
}
}
if (errmsg_len) {
*errmsg_len = 0;
}
return 0;
}
if (errmsg) {
char *serrmsg = session->err_msg ? session->err_msg : (char *) "";
int ownbuf = session->err_msg ? session->err_should_free : 0;
if (want_buf) {
if (ownbuf) {
/* Just give the calling program the buffer */
*errmsg = serrmsg;
session->err_should_free = 0;
} else {
/* Make a copy so the calling program can own it */
*errmsg = LIBSSH2_ALLOC(session, session->err_msglen + 1);
if (*errmsg) {
memcpy(*errmsg, session->err_msg, session->err_msglen);
(*errmsg)[session->err_msglen] = 0;
}
}
} else {
*errmsg = serrmsg;
}
}
if (errmsg_len) {
*errmsg_len = session->err_msglen;
}
return session->err_code;
}
|
|||||
| ↓ | libssh2_session_method_pref | 21 | 60 | 108 | src/kex.c |
LIBSSH2_API int
libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type,
const char *prefs)
{
char **prefvar, *s, *newprefs;
int prefs_len = strlen(prefs);
const LIBSSH2_COMMON_METHOD **mlist;
switch (method_type) {
case LIBSSH2_METHOD_KEX:
prefvar = &session->kex_prefs;
mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods;
break;
case LIBSSH2_METHOD_HOSTKEY:
prefvar = &session->hostkey_prefs;
mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods();
break;
case LIBSSH2_METHOD_CRYPT_CS:
prefvar = &session->local.crypt_prefs;
mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods();
break;
case LIBSSH2_METHOD_CRYPT_SC:
prefvar = &session->remote.crypt_prefs;
mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods();
break;
case LIBSSH2_METHOD_MAC_CS:
prefvar = &session->local.mac_prefs;
mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_mac_methods();
break;
case LIBSSH2_METHOD_MAC_SC:
prefvar = &session->remote.mac_prefs;
mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_mac_methods();
break;
case LIBSSH2_METHOD_COMP_CS:
prefvar = &session->local.comp_prefs;
mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_comp_methods();
break;
case LIBSSH2_METHOD_COMP_SC:
prefvar = &session->remote.comp_prefs;
mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_comp_methods();
break;
case LIBSSH2_METHOD_LANG_CS:
prefvar = &session->local.lang_prefs;
mlist = NULL;
break;
case LIBSSH2_METHOD_LANG_SC:
prefvar = &session->remote.lang_prefs;
mlist = NULL;
break;
default:
libssh2_error(session, LIBSSH2_ERROR_INVAL,
"Invalid parameter specified for method_type", 0);
return -1;
}
s = newprefs = LIBSSH2_ALLOC(session, prefs_len + 1);
if (!newprefs) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Error allocated space for method preferences", 0);
return -1;
}
memcpy(s, prefs, prefs_len + 1);
while (s && *s) {
char *p = strchr(s, ',');
int method_len = p ? (p - s) : (int) strlen(s);
if (!libssh2_get_method_by_name(s, method_len, mlist)) {
/* Strip out unsupported method */
if (p) {
memcpy(s, p + 1, strlen(s) - method_len);
} else {
if (s > newprefs) {
*(--s) = '\0';
} else {
*s = '\0';
}
}
}
s = p ? (p + 1) : NULL;
}
if (strlen(newprefs) == 0) {
libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
"The requested method(s) are not currently supported",
0);
LIBSSH2_FREE(session, newprefs);
return -1;
}
if (*prefvar) {
LIBSSH2_FREE(session, *prefvar);
}
*prefvar = newprefs;
return 0;
}
|
|||||
| ↓ | libssh2_sftp_rename_ex | 14 | 71 | 123 | src/sftp.c |
LIBSSH2_API int
libssh2_sftp_rename_ex(LIBSSH2_SFTP * sftp, const char *source_filename,
unsigned int source_filename_len,
const char *dest_filename,
unsigned int dest_filename_len, long flags)
{
LIBSSH2_CHANNEL *channel = sftp->channel;
LIBSSH2_SESSION *session = channel->session;
unsigned long data_len, retcode;
ssize_t packet_len =
source_filename_len + dest_filename_len + 17 + (sftp->version >=
5 ? 4 : 0);
/* packet_len(4) + packet_type(1) + request_id(4) +
source_filename_len(4) + dest_filename_len(4) + flags(4){SFTP5+) */
unsigned char *data;
int rc;
if (sftp->version < 2) {
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"Server does not support RENAME", 0);
return -1;
}
if (sftp->rename_state == libssh2_NB_state_idle) {
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Renaming %s to %s",
source_filename, dest_filename);
sftp->rename_s = sftp->rename_packet =
LIBSSH2_ALLOC(session, packet_len);
if (!sftp->rename_packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for FXP_RENAME packet",
0);
return -1;
}
libssh2_htonu32(sftp->rename_s, packet_len - 4);
sftp->rename_s += 4;
*(sftp->rename_s++) = SSH_FXP_RENAME;
sftp->rename_request_id = sftp->request_id++;
libssh2_htonu32(sftp->rename_s, sftp->rename_request_id);
sftp->rename_s += 4;
libssh2_htonu32(sftp->rename_s, source_filename_len);
sftp->rename_s += 4;
memcpy(sftp->rename_s, source_filename, source_filename_len);
sftp->rename_s += source_filename_len;
libssh2_htonu32(sftp->rename_s, dest_filename_len);
sftp->rename_s += 4;
memcpy(sftp->rename_s, dest_filename, dest_filename_len);
sftp->rename_s += dest_filename_len;
if (sftp->version >= 5) {
libssh2_htonu32(sftp->rename_s, flags);
sftp->rename_s += 4;
}
sftp->rename_state = libssh2_NB_state_created;
}
if (sftp->rename_state == libssh2_NB_state_created) {
rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->rename_packet,
sftp->rename_s - sftp->rename_packet);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (packet_len != rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send FXP_RENAME command", 0);
LIBSSH2_FREE(session, sftp->rename_packet);
sftp->rename_packet = NULL;
sftp->rename_state = libssh2_NB_state_idle;
return -1;
}
LIBSSH2_FREE(session, sftp->rename_packet);
sftp->rename_packet = NULL;
sftp->rename_state = libssh2_NB_state_sent;
}
rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
sftp->rename_request_id, &data,
&data_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for status message", 0);
sftp->rename_state = libssh2_NB_state_idle;
return -1;
}
sftp->rename_state = libssh2_NB_state_idle;
retcode = libssh2_ntohu32(data + 5);
LIBSSH2_FREE(session, data);
switch (retcode) {
case LIBSSH2_FX_OK:
retcode = 0;
break;
case LIBSSH2_FX_FILE_ALREADY_EXISTS:
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"File already exists and SSH_FXP_RENAME_OVERWRITE not specified",
0);
sftp->last_errno = retcode;
retcode = -1;
break;
case LIBSSH2_FX_OP_UNSUPPORTED:
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"Operation Not Supported", 0);
sftp->last_errno = retcode;
retcode = -1;
break;
default:
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"SFTP Protocol Error", 0);
sftp->last_errno = retcode;
retcode = -1;
}
return retcode;
}
|
|||||
| ↓ | libssh2_packet_x11_open | 12 | 98 | 159 | src/packet.c |
static inline int
libssh2_packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
unsigned long datalen,
packet_x11_open_state_t * x11open_state)
{
int failure_code = 2; /* SSH_OPEN_CONNECT_FAILED */
unsigned char *s = data + (sizeof("x11") - 1) + 5;
/* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
unsigned long packet_len = 17 + (sizeof(X11FwdUnAvil) - 1);
unsigned char *p;
LIBSSH2_CHANNEL *channel;
int rc;
(void) datalen;
if (x11open_state->state == libssh2_NB_state_idle) {
x11open_state->sender_channel = libssh2_ntohu32(s);
s += 4;
x11open_state->initial_window_size = libssh2_ntohu32(s);
s += 4;
x11open_state->packet_size = libssh2_ntohu32(s);
s += 4;
x11open_state->shost_len = libssh2_ntohu32(s);
s += 4;
x11open_state->shost = s;
s += x11open_state->shost_len;
x11open_state->sport = libssh2_ntohu32(s);
s += 4;
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"X11 Connection Received from %s:%ld on channel %lu",
x11open_state->shost, x11open_state->sport,
x11open_state->sender_channel);
x11open_state->state = libssh2_NB_state_allocated;
}
if (session->x11) {
if (x11open_state->state == libssh2_NB_state_allocated) {
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
if (!channel) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate a channel for new connection",
0);
failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
goto x11_exit;
}
memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
channel->session = session;
channel->channel_type_len = sizeof("x11") - 1;
channel->channel_type = LIBSSH2_ALLOC(session,
channel->channel_type_len +
1);
if (!channel->channel_type) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate a channel for new connection",
0);
LIBSSH2_FREE(session, channel);
failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
goto x11_exit;
}
memcpy(channel->channel_type, "x11",
channel->channel_type_len + 1);
channel->remote.id = x11open_state->sender_channel;
channel->remote.window_size_initial =
LIBSSH2_CHANNEL_WINDOW_DEFAULT;
channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT;
channel->local.id = libssh2_channel_nextid(session);
channel->local.window_size_initial =
x11open_state->initial_window_size;
channel->local.window_size = x11open_state->initial_window_size;
channel->local.packet_size = x11open_state->packet_size;
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"X11 Connection established: channel %lu/%lu win %lu/%lu packet %lu/%lu",
channel->local.id, channel->remote.id,
channel->local.window_size,
channel->remote.window_size,
channel->local.packet_size,
channel->remote.packet_size);
p = x11open_state->packet;
*(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
libssh2_htonu32(p, channel->remote.id);
p += 4;
libssh2_htonu32(p, channel->local.id);
p += 4;
libssh2_htonu32(p, channel->remote.window_size_initial);
p += 4;
libssh2_htonu32(p, channel->remote.packet_size);
p += 4;
x11open_state->state = libssh2_NB_state_created;
}
if (x11open_state->state == libssh2_NB_state_created) {
rc = libssh2_packet_write(session, x11open_state->packet, 17);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send channel open confirmation", 0);
x11open_state->state = libssh2_NB_state_idle;
return -1;
}
/* Link the channel into the session */
if (session->channels.tail) {
session->channels.tail->next = channel;
channel->prev = session->channels.tail;
} else {
session->channels.head = channel;
channel->prev = NULL;
}
channel->next = NULL;
session->channels.tail = channel;
/*
* Pass control to the callback, they may turn right around and
* free the channel, or actually use it
*/
LIBSSH2_X11_OPEN(channel, (char *) x11open_state->shost,
x11open_state->sport);
x11open_state->state = libssh2_NB_state_idle;
return 0;
}
} else {
failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
}
x11_exit:
p = x11open_state->packet;
*(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
libssh2_htonu32(p, x11open_state->sender_channel);
p += 4;
libssh2_htonu32(p, failure_code);
p += 4;
libssh2_htonu32(p, sizeof(X11FwdUnAvil) - 1);
p += 4;
memcpy(s, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1);
p += sizeof(X11FwdUnAvil) - 1;
libssh2_htonu32(p, 0);
rc = libssh2_packet_write(session, x11open_state->packet, packet_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send open failure", 0);
x11open_state->state = libssh2_NB_state_idle;
return -1;
}
x11open_state->state = libssh2_NB_state_idle;
return 0;
}
|
|||||
| ↓ | libssh2_channel_request_pty_ex | 12 | 69 | 117 | src/channel.c |
LIBSSH2_API int
libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL * channel, const char *term,
unsigned int term_len, const char *modes,
unsigned int modes_len, int width, int height,
int width_px, int height_px)
{
LIBSSH2_SESSION *session = channel->session;
unsigned char *s, *data;
static const unsigned char reply_codes[3] =
{ SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
unsigned long data_len;
int rc;
if (channel->reqPTY_state == libssh2_NB_state_idle) {
/* 41 = packet_type(1) + channel(4) + pty_req_len(4) + "pty_req"(7) +
* want_reply(1) + term_len(4) + width(4) + height(4) + width_px(4) +
* height_px(4) + modes_len(4) */
channel->reqPTY_packet_len = term_len + modes_len + 41;
/* Zero the whole thing out */
memset(&channel->reqPTY_packet_requirev_state, 0,
sizeof(channel->reqPTY_packet_requirev_state));
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"Allocating tty on channel %lu/%lu", channel->local.id,
channel->remote.id);
s = channel->reqPTY_packet =
LIBSSH2_ALLOC(session, channel->reqPTY_packet_len);
if (!channel->reqPTY_packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for pty-request", 0);
return -1;
}
*(s++) = SSH_MSG_CHANNEL_REQUEST;
libssh2_htonu32(s, channel->remote.id);
s += 4;
libssh2_htonu32(s, sizeof("pty-req") - 1);
s += 4;
memcpy(s, "pty-req", sizeof("pty-req") - 1);
s += sizeof("pty-req") - 1;
*(s++) = 0x01;
libssh2_htonu32(s, term_len);
s += 4;
if (term) {
memcpy(s, term, term_len);
s += term_len;
}
libssh2_htonu32(s, width);
s += 4;
libssh2_htonu32(s, height);
s += 4;
libssh2_htonu32(s, width_px);
s += 4;
libssh2_htonu32(s, height_px);
s += 4;
libssh2_htonu32(s, modes_len);
s += 4;
if (modes) {
memcpy(s, modes, modes_len);
s += modes_len;
}
channel->reqPTY_state = libssh2_NB_state_created;
}
if (channel->reqPTY_state == libssh2_NB_state_created) {
rc = libssh2_packet_write(session, channel->reqPTY_packet,
channel->reqPTY_packet_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send pty-request packet", 0);
LIBSSH2_FREE(session, channel->reqPTY_packet);
channel->reqPTY_packet = NULL;
channel->reqPTY_state = libssh2_NB_state_idle;
return -1;
}
LIBSSH2_FREE(session, channel->reqPTY_packet);
channel->reqPTY_packet = NULL;
libssh2_htonu32(channel->reqPTY_local_channel, channel->local.id);
channel->reqPTY_state = libssh2_NB_state_sent;
}
if (channel->reqPTY_state == libssh2_NB_state_sent) {
rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
1, channel->reqPTY_local_channel, 4,
&channel->
reqPTY_packet_requirev_state);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
channel->reqPTY_state = libssh2_NB_state_idle;
return -1;
}
if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
LIBSSH2_FREE(session, data);
channel->reqPTY_state = libssh2_NB_state_idle;
return 0;
}
}
LIBSSH2_FREE(session, data);
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
"Unable to complete request for channel request-pty", 0);
channel->reqPTY_state = libssh2_NB_state_idle;
return -1;
}
|
|||||
| ↓ | libssh2_channel_process_startup | 12 | 58 | 103 | src/channel.c |
LIBSSH2_API int
libssh2_channel_process_startup(LIBSSH2_CHANNEL * channel, const char *request,
unsigned int request_len, const char *message,
unsigned int message_len)
{
LIBSSH2_SESSION *session = channel->session;
unsigned char *s, *data;
static const unsigned char reply_codes[3] =
{ SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
unsigned long data_len;
libssh2pack_t rc;
if (channel->process_state == libssh2_NB_state_idle) {
/* 10 = packet_type(1) + channel(4) + request_len(4) + want_reply(1) */
channel->process_packet_len = request_len + 10;
/* Zero the whole thing out */
memset(&channel->process_packet_requirev_state, 0,
sizeof(channel->process_packet_requirev_state));
if (message) {
channel->process_packet_len += message_len + 4;
}
_libssh2_debug(session, LIBSSH2_DBG_CONN,
"starting request(%s) on channel %lu/%lu, message=%s",
request, channel->local.id, channel->remote.id,
message);
s = channel->process_packet =
LIBSSH2_ALLOC(session, channel->process_packet_len);
if (!channel->process_packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for channel-process request",
0);
return -1;
}
*(s++) = SSH_MSG_CHANNEL_REQUEST;
libssh2_htonu32(s, channel->remote.id);
s += 4;
libssh2_htonu32(s, request_len);
s += 4;
memcpy(s, request, request_len);
s += request_len;
*(s++) = 0x01;
if (message) {
libssh2_htonu32(s, message_len);
s += 4;
memcpy(s, message, message_len);
s += message_len;
}
channel->process_state = libssh2_NB_state_created;
}
if (channel->process_state == libssh2_NB_state_created) {
rc = libssh2_packet_write(session, channel->process_packet,
channel->process_packet_len);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send channel request", 0);
LIBSSH2_FREE(session, channel->process_packet);
channel->process_packet = NULL;
channel->process_state = libssh2_NB_state_idle;
return -1;
}
LIBSSH2_FREE(session, channel->process_packet);
channel->process_packet = NULL;
libssh2_htonu32(channel->process_local_channel, channel->local.id);
channel->process_state = libssh2_NB_state_sent;
}
if (channel->process_state == libssh2_NB_state_sent) {
rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
1, channel->process_local_channel, 4,
&channel->
process_packet_requirev_state);
if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if (rc) {
channel->process_state = libssh2_NB_state_idle;
return -1;
}
if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
LIBSSH2_FREE(session, data);
channel->process_state = libssh2_NB_state_idle;
return 0;
}
}
LIBSSH2_FREE(session, data);
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
"Unable to complete request for channel-process-startup", 0);
channel->process_state = libssh2_NB_state_idle;
return -1;
}
|
|||||
| ↓ | libssh2_packet_require_ex | 12 | 24 | 55 | src/packet.c |
int
libssh2_packet_require_ex(LIBSSH2_SESSION * session, unsigned char packet_type,
unsigned char **data, unsigned long *data_len,
unsigned long match_ofs,
const unsigned char *match_buf,
unsigned long match_len,
packet_require_state_t * state)
{
if (state->start == 0) {
if (libssh2_packet_ask_ex
(session, packet_type, data, data_len, match_ofs, match_buf,
match_len, 0) == 0) {
/* A packet was available in the packet brigade */
return 0;
}
state->start = time(NULL);
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
"May block until packet of type %d becomes available",
(int) packet_type);
}
while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
libssh2pack_t ret = libssh2_packet_read(session);
if (ret == PACKET_EAGAIN) {
return PACKET_EAGAIN;
} else if ((ret == 0) && (!session->socket_block)) {
/* If we are in non-blocking and there is no data, return that */
return PACKET_EAGAIN;
} else if (ret < 0) {
state->start = 0;
/* an error which is not just because of blocking */
return ret;
} else if (ret == packet_type) {
/* Be lazy, let packet_ask pull it out of the brigade */
ret =
libssh2_packet_ask_ex(session, packet_type, data, data_len,
match_ofs, match_buf, match_len, 0);
state->start = 0;
return ret;
} else if (ret == 0) {
/* nothing available, wait until data arrives or we time out */
long left = LIBSSH2_READ_TIMEOUT - (time(NULL) - state->start);
if ((left <= 0) || (libssh2_waitsocket(session, left) <= 0)) {
state->start = 0;
return PACKET_TIMEOUT;
}
}
}
/* Only reached if the socket died */
return -1;
}
|
|||||
| ↓ | libssh2_userauth_list | 11 | 62 | 109 | src/userauth.c |
LIBSSH2_API char *
libssh2_userauth_list(LIBSSH2_SESSION * session, const char *username,
unsigned int username_len)
{
static const unsigned char reply_codes[3] =
{ SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
/* packet_type(1) + username_len(4) + service_len(4) +
service(14)"ssh-connection" + method_len(4) + method(4)"none" */
unsigned long methods_len;
unsigned char *s;
int rc;
if (session->userauth_list_state == libssh2_NB_state_idle) {
/* Zero the whole thing out */
memset(&session->userauth_list_packet_requirev_state, 0,
sizeof(session->userauth_list_packet_requirev_state));
session->userauth_list_data_len = username_len + 31;
s = session->userauth_list_data =
LIBSSH2_ALLOC(session, session->userauth_list_data_len);
if (!session->userauth_list_data) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"Unable to allocate memory for userauth_list", 0);
return NULL;
}
*(s++) = SSH_MSG_USERAUTH_REQUEST;
libssh2_htonu32(s, username_len);
s += 4;
if (username) {
memcpy(s, username, username_len);
s += username_len;
}
libssh2_htonu32(s, 14);
s += 4;
memcpy(s, "ssh-connection", 14);
s += 14;
libssh2_htonu32(s, 4);
s += 4;
memcpy(s, "none", 4);
s += 4;
session->userauth_list_state = libssh2_NB_state_created;
}
if (session->userauth_list_state == libssh2_NB_state_created) {
rc = libssh2_packet_write(session, session->userauth_list_data,
session->userauth_list_data_len);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block requesting userauth list", 0);
return NULL;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send userauth-none request", 0);
LIBSSH2_FREE(session, session->userauth_list_data);
session->userauth_list_data = NULL;
session->userauth_list_state = libssh2_NB_state_idle;
return NULL;
}
LIBSSH2_FREE(session, session->userauth_list_data);
session->userauth_list_data = NULL;
session->userauth_list_state = libssh2_NB_state_sent;
}
if (session->userauth_list_state == libssh2_NB_state_sent) {
rc = libssh2_packet_requirev_ex(session, reply_codes,
&session->userauth_list_data,
&session->userauth_list_data_len, 0,
NULL, 0,
&session->
userauth_list_packet_requirev_state);
if (rc == PACKET_EAGAIN) {
libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block requesting userauth list", 0);
return NULL;
} else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_NONE, "No error", 0);
session->userauth_list_state = libssh2_NB_state_idle;
return NULL;
}
if (session->userauth_list_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
/* Wow, who'dve thought... */
libssh2_error(session, LIBSSH2_ERROR_NONE, "No error", 0);
LIBSSH2_FREE(session, session->userauth_list_data);
session->userauth_list_data = NULL;
session->state |= LIBSSH2_STATE_AUTHENTICATED;
session->userauth_list_state = libssh2_NB_state_idle;
return NULL;
}
methods_len = libssh2_ntohu32(session->userauth_list_data + 1);
/* Do note that the memory areas overlap! */
memmove(session->userauth_list_data, session->userauth_list_data + 5,
methods_len);
session->userauth_list_data[methods_len] = '\0';
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Permitted auth methods: %s",
session->userauth_list_data);
}
session->userauth_list_state = libssh2_NB_state_idle;
return (char *) session->userauth_list_data;
}
|
|||||
| ↓ | libssh2_new_host_entry | 11 | 35 | 50 | src/sshentry.c |
LIBSSH2_API int
libssh2_new_host_entry(LIBSSH2_SESSION * session,
LIBSSH2_KNOWNHOSTS ** s,
char *line)
{
char *tmp = NULL;
LIBSSH2_KNOWNHOSTS *t = NULL;
int i;
if (line == NULL || *line == 0)
return 1;
if (s == NULL)
return 2;
tmp = strchr (line, ' ');
if (tmp == NULL)
return 3;
t = (LIBSSH2_KNOWNHOSTS *)
LIBSSH2_ALLOC(session, sizeof(LIBSSH2_KNOWNHOSTS));
t->hostname_line = NULL;
t->hostnames = NULL;
t->hostnames_size = t->bits = t->exponent = -1;
t->modulus = NULL;
t->modulus_length = -1;
t->ssh_version = -1;
t->md5 = NULL;
i = ssh_host_parse_hostnames (session, t, line, tmp);
if (i != 0) {
libssh2_free_host_entry (session, t);
return ((i > 0) ? 4 : -1);
}
line = tmp + 1;
tmp = strchr (line, ' ');
if (tmp != NULL)
tmp = strchr (tmp + 1, ' ');
i = ssh_host_parse_key (session, t, line, tmp == NULL ? 1 : 0);
if (i != 0) {
libssh2_free_host_entry (session, t);
return ((i > 0) ? 5 : -2);
}
*s = t;
return 0;
}
|
|||||
| ↓ | libssh2_kex_agree_comp | 11 | 25 | 50 | src/kex.c |
static int
libssh2_kex_agree_comp(LIBSSH2_SESSION * session,
libssh2_endpoint_data * endpoint, unsigned char *comp,
unsigned long comp_len)
{
const LIBSSH2_COMP_METHOD **compp = libssh2_comp_methods();
unsigned char *s;
(void) session;
if (endpoint->comp_prefs) {
s = (unsigned char *) endpoint->comp_prefs;
while (s && *s) {
unsigned char *p = (unsigned char *) strchr((char *) s, ',');
int method_len = (p ? (p - s) : strlen((char *) s));
if (libssh2_kex_agree_instr(comp, comp_len, s, method_len)) {
const LIBSSH2_COMP_METHOD *method =
(const LIBSSH2_COMP_METHOD *)
libssh2_get_method_by_name((char *) s, method_len,
(const LIBSSH2_COMMON_METHOD **)
compp);
if (!method) {
/* Invalid method -- Should never be reached */
return -1;
}
endpoint->comp = method;
return 0;
}
s = p ? p + 1 : NULL;
}
return -1;
}
while (*compp && (*compp)->name) {
s = libssh2_kex_agree_instr(comp, comp_len,
(unsigned char *) (*compp)->name,
strlen((*compp)->name));
if (s) {
endpoint->comp = *compp;
return 0;
}
compp++;
}
return -1;
}
|
|||||
| ↓ | libssh2_kex_agree_mac | 11 | 25 | 49 | src/kex.c |
static int
libssh2_kex_agree_mac(LIBSSH2_SESSION * session,
libssh2_endpoint_data * endpoint, unsigned char *mac,
unsigned long mac_len)
{
const LIBSSH2_MAC_METHOD **macp = libssh2_mac_methods();
unsigned char *s;
(void) session;
if (endpoint->mac_prefs) {
s = (unsigned char *) endpoint->mac_prefs;
while (s && *s) {
unsigned char *p = (unsigned char *) strchr((char *) s, ',');
int method_len = (p ? (p - s) : strlen((char *) s));
if (libssh2_kex_agree_instr(mac, mac_len, s, method_len)) {
const LIBSSH2_MAC_METHOD *method = (const LIBSSH2_MAC_METHOD *)
libssh2_get_method_by_name((char *) s, method_len,
(const LIBSSH2_COMMON_METHOD **)
macp);
if (!method) {
/* Invalid method -- Should never be reached */
return -1;
}
endpoint->mac = method;
return 0;
}
s = p ? p + 1 : NULL;
}
return -1;
}
while (*macp && (*macp)->name) {
s = libssh2_kex_agree_instr(mac, mac_len,
(unsigned char *) (*macp)->name,
strlen((*macp)->name));
if (s) {
endpoint->mac = *macp;
return 0;
}
macp++;
}
return -1;
}
|
|||||
| ↓ | libssh2_kex_agree_crypt | 11 | 25 | 51 | src/kex.c |
static int
libssh2_kex_agree_crypt(LIBSSH2_SESSION * session,
libssh2_endpoint_data * endpoint, unsigned char *crypt,
unsigned long crypt_len)
{
const LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods();
unsigned char *s;
(void) session;
if (endpoint->crypt_prefs) {
s = (unsigned char *) endpoint->crypt_prefs;
while (s && *s) {
unsigned char *p = (unsigned char *) strchr((char *) s, ',');
int method_len = (p ? (p - s) : strlen((char *) s));
if (libssh2_kex_agree_instr(crypt, crypt_len, s, method_len)) {
const LIBSSH2_CRYPT_METHOD *method =
(const LIBSSH2_CRYPT_METHOD *)
libssh2_get_method_by_name((char *) s, method_len,
(const LIBSSH2_COMMON_METHOD **)
cryptp);
if (!method) {
/* Invalid method -- Should never be reached */
return -1;
}
endpoint->crypt = method;
return 0;
}
s = p ? p + 1 : NULL;
}
return -1;
}
while (*cryptp && (*cryptp)->name) {
s = libssh2_kex_agree_instr(crypt, crypt_len,
(unsigned char *) (*cryptp)->name,
strlen((*cryptp)->name));
if (s) {
endpoint->crypt = *cryptp;
return 0;
}
cryptp++;
}
return -1;
}
|
|||||
| ↓ | libssh2_packet_requirev_ex | 11 | 21 | 51 | src/packet.c |
int
libssh2_packet_requirev_ex(LIBSSH2_SESSION * session,
const unsigned char *packet_types,
unsigned char **data, unsigned long *data_len,
unsigned long match_ofs,
const unsigned char *match_buf,
unsigned long match_len,
packet_requirev_state_t * state)
{
if (libssh2_packet_askv_ex
(session, packet_types, data, data_len, match_ofs, match_buf,
match_len, 0) == 0) {
/* One of the packets listed was available in the packet
brigade */
state->start = 0;
return 0;
}
if (state->start == 0) {
state->start = time(NULL);
}
while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
int ret = libssh2_packet_read(session);
if ((ret < 0) && (ret != PACKET_EAGAIN)) {
state->start = 0;
return ret;
}
if (ret <= 0) {
long left = LIBSSH2_READ_TIMEOUT - (time(NULL) - state->start);
if ((left <= 0) || (libssh2_waitsocket(session, left) <= 0)) {
state->start = 0;
return PACKET_TIMEOUT;
} else if (ret == PACKET_EAGAIN) {
return PACKET_EAGAIN;
}
}
if (strchr((char *) packet_types, ret)) {
/* Be lazy, let packet_ask pull it out of the brigade */
return libssh2_packet_askv_ex(session, packet_types, data,
data_len, match_ofs, match_buf,
match_len, 0);
}
}
/* Only reached if the socket died */
state->start = 0;
return -1;
}
|
|||||
| ↓ | libssh2_packet_ask_ex | 11 | 20 | 57 | src/packet.c |
int
libssh2_packet_ask_ex(LIBSSH2_SESSION * session, unsigned char packet_type,
unsigned char **data, unsigned long *data_len,
unsigned long match_ofs, const unsigned char *match_buf,
unsigned long match_len, int poll_socket)
{
LIBSSH2_PACKET *packet = session->packets.head;
if (poll_socket) {
/*
* XXX CHECK ***
* When "poll_socket" is "1" libhss2_packet_read() can return
* PACKET_EAGAIN. I am not sure what should happen, but internally
* there is only one location that might do so, libssh2_packet_askv_ex()
*/
libssh2pack_t rc = libssh2_packet_read(session);
if ((rc < 0) && !packet) {
return rc;
}
}
_libssh2_debug(session, LIBSSH2_DBG_TRANS,
"Looking for packet of type: %d", (int) packet_type);
while (packet) {
if (packet->data[0] == packet_type
&& (packet->data_len >= (match_ofs + match_len)) && (!match_buf
||
(memcmp
(packet->
data +
match_ofs,
match_buf,
match_len)
== 0))) {
*data = packet->data;
*data_len = packet->data_len;
if (packet->prev) {
packet->prev->next = packet->next;
} else {
session->packets.head = packet->next;
}
if (packet->next) {
packet->next->prev = packet->prev;
} else {
session->packets.tail = packet->prev;
}
LIBSSH2_FREE(session, packet);
return 0;
}
packet = packet->next;
}
return -1;
}
|
|||||
| libssh2_channel_setenv_ex | 10 | 59 | 105 | src/channel.c | |
| libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange | 10 | 56 | 97 | src/kex.c | |
| libssh2_channel_forward_cancel | 10 | 52 | 86 | src/channel.c | |
| libssh2_kex_agree_instr | 10 | 11 | 33 | src/kex.c | |
| libssh2_sftp_write | 9 | 58 | 88 | src/sftp.c | |
| libssh2_sftp_mkdir_ex | 9 | 57 | 89 | src/sftp.c | |
| libssh2_sftp_rmdir_ex | 9 | 51 | 80 | src/sftp.c | |
| libssh2_sftp_unlink_ex | 9 | 51 | 81 | src/sftp.c | |
| _libssh2_pem_parse | 9 | 32 | 54 | src/pem.c | |
| libssh2_sftp_packet_ask | 9 | 29 | 54 | src/sftp.c | |
| libssh2_packet_burn | 9 | 29 | 53 | src/packet.c | |
| debugdump | 9 | 24 | 37 | src/transport.c | |
| libssh2_publickey_response_success | 8 | 43 | 75 | src/publickey.c | |
| libssh2_session_disconnect_ex | 8 | 36 | 64 | src/session.c | |
| ssh_host_parse_hostnames | 8 | 31 | 51 | src/sshentry.c | |
| libssh2_publickey_packet_receive | 8 | 31 | 54 | src/publickey.c | |
| libssh2_banner_send | 8 | 26 | 55 | src/session.c | |
| libssh2_channel_receive_window_adjust | 8 | 25 | 53 | src/channel.c | |
| libssh2_poll_channel_read | 8 | 10 | 24 | src/session.c | |
| libssh2_publickey_remove_ex | 7 | 45 | 73 | src/publickey.c | |
| libssh2_publickey_status_error | 7 | 28 | 49 | src/publickey.c | |
| _libssh2_rsa_sha1_sign | 3 | 14 | 30 | src/openssl.c | |
| send_existing | 7 | 22 | 51 | src/transport.c | |
| libssh2_channel_wait_closed | 7 | 19 | 41 | src/channel.c | |
| libssh2_free_host_entry | 7 | 18 | 39 | src/sshentry.c | |
| read_asn1_length | 7 | 18 | 33 | src/pem.c | |
| libssh2_file_read_privatekey | 7 | 16 | 39 | src/userauth.c | |
| libssh2_channel_window_read_ex | 7 | 12 | 30 | src/channel.c | |
| libssh2_base64_decode | 9 | 28 | 45 | src/misc.c | |
| libssh2_kexinit | 6 | 81 | 153 | src/kex.c | |
| readline | 6 | 7 | 14 | src/pem.c | |
| libssh2_channel_request_pty_size_ex | 6 | 45 | 74 | src/channel.c | |
| libssh2_sftp_attr2bin | 6 | 24 | 44 | src/sftp.c | |
| libssh2_channel_forward_accept | 6 | 23 | 41 | src/channel.c | |
| _libssh2_cipher_init | 1 | 3 | 9 | src/openssl.c | |
| libssh2_channel_wait_eof | 6 | 17 | 35 | src/channel.c | |
| libssh2_publickey_shutdown | 6 | 17 | 32 | src/publickey.c | |
| libssh2_publickey_response_id | 6 | 16 | 31 | src/publickey.c | |
| libssh2_sftp_packet_require | 6 | 14 | 35 | src/sftp.c | |
| libssh2_sftp_attrsize | 6 | 12 | 20 | src/sftp.c | |
| libssh2_host_entry_match | 5 | 9 | 19 | src/sshentry.c | |
| libssh2_kex_method_strlen | 5 | 7 | 16 | src/kex.c | |
| libssh2_channel_eof | 5 | 7 | 18 | src/channel.c | |
| libssh2_channel_direct_tcpip_ex | 5 | 34 | 66 | src/channel.c | |
| libssh2_hostkey_method_ssh_rsa_init | 5 | 25 | 44 | src/hostkey.c | |
| libssh2_sftp_bin2attr | 5 | 21 | 35 | src/sftp.c | |
| libssh2_session_init_ex | 5 | 20 | 33 | src/session.c | |
| libssh2_banner_set | 5 | 18 | 31 | src/session.c | |
| _libssh2_pem_decode_integer | 5 | 18 | 34 | src/pem.c | |
| _libssh2_pem_decode_sequence | 5 | 14 | 27 | src/pem.c | |
| libssh2_kex_method_list | 5 | 11 | 21 | src/kex.c | |
| libssh2_channel_handle_extended_data2 | 5 | 10 | 26 | src/channel.c | |
| libssh2_packet_askv_ex | 4 | 8 | 26 | src/packet.c | |
| libssh2_get_method_by_name | 4 | 5 | 13 | src/kex.c | |
| libssh2_hostkey_method_ssh_dss_init | 4 | 32 | 47 | src/hostkey.c | |
| libssh2_hostkey_method_ssh_dss_signv | 4 | 19 | 34 | src/hostkey.c | |
| libssh2_comp_method_zlib_init | 4 | 18 | 35 | src/comp.c | |
| _libssh2_rsa_sha1_verify | 2 | 6 | 14 | src/openssl.c | |
| _libssh2_dsa_sha1_verify | 2 | 13 | 21 | src/openssl.c | |
| libssh2_hostkey_method_ssh_dss_initPEM | 4 | 15 | 30 | src/hostkey.c | |
| libssh2_hostkey_method_ssh_rsa_initPEM | 4 | 15 | 30 | src/hostkey.c | |
| _libssh2_get_socket_nonblocking | 4 | 14 | 55 | src/session.c | |
| _libssh2_debug | 4 | 14 | 35 | src/misc.c | |
| _libssh2_cipher_crypt | 3 | 8 | 19 | src/libgcrypt.c | |
| LIBSSH2_CHANNEL_CLOSE_FUNC | 4 | 10 | 24 | src/sftp.c | |
| ssh_unit_tests | 4 | 10 | 27 | src/sshentry.c | |
| ssh_proto_str_read | 3 | 9 | 19 | src/sshentry.c | |
| _libssh2_cipher_crypt | 3 | 8 | 19 | src/libgcrypt.c | |
| libssh2_comp_method_zlib_dtor | 3 | 8 | 22 | src/comp.c | |
| _libssh2_dsa_new | 2 | 13 | 33 | src/openssl.c | |
| libssh2_publickey_list_free | 3 | 8 | 17 | src/publickey.c | |
| _libssh2_dsa_new_private | 3 | 7 | 20 | src/openssl.c | |
| _libssh2_rsa_new_private | 3 | 7 | 20 | src/openssl.c | |
| libssh2_channel_locate | 3 | 6 | 13 | src/channel.c | |
| _libssh2_dtor | 3 | 6 | 11 | src/crypt.c | |
| libssh2_sftp_packet_add | 3 | 19 | 32 | src/sftp.c | |
| libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange | 3 | 18 | 79 | src/kex.c | |
| libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange | 3 | 18 | 65 | src/kex.c | |
| _libssh2_dsa_sha1_sign | 3 | 16 | 29 | src/openssl.c | |
| _libssh2_nonblock | 3 | 16 | 64 | src/session.c | |
| libssh2_hostkey_method_ssh_rsa_signv | 3 | 15 | 28 | src/hostkey.c | |
| _libssh2_rsa_sha1_sign | 3 | 14 | 30 | src/openssl.c | |
| libssh2_channel_send_eof | 3 | 14 | 23 | src/channel.c | |
| decrypt | 3 | 13 | 31 | src/transport.c | |
| _libssh2_init | 3 | 12 | 23 | src/crypt.c | |
| _libssh2_rsa_new | 2 | 19 | 47 | src/openssl.c | |
| libssh2_mac_method_hmac_ripemd160_hash | 3 | 12 | 26 | src/mac.c | |
| libssh2_mac_method_hmac_md5_hash | 3 | 12 | 25 | src/mac.c | |
| libssh2_mac_method_hmac_sha1_hash | 3 | 12 | 25 | src/mac.c | |
| libssh2_channel_nextid | 3 | 10 | 25 | src/channel.c | |
| libssh2_session_methods | 12 | 28 | 62 | src/session.c | |
| libssh2_session_callback_set | 6 | 18 | 37 | src/session.c | |
| libssh2_hostkey_hash | 3 | 5 | 16 | src/hostkey.c | |
| libssh2_hostkey_method_ssh_dss_sig_verify | 2 | 7 | 19 | src/hostkey.c | |
| passphrase_cb | 2 | 7 | 14 | src/openssl.c | |
| _libssh2_session_set_blocking | 2 | 7 | 16 | src/session.c | |
| _libssh2_rsa_sha1_verify | 2 | 6 | 14 | src/openssl.c | |
| libssh2_mac_method_common_dtor | 2 | 4 | 10 | src/mac.c | |
| libssh2_session_flag | 2 | 4 | 11 | src/session.c | |
| libssh2_channel_window_write_ex | 2 | 3 | 11 | src/channel.c | |
| libssh2_channel_handle_extended_data | 2 | 2 | 7 | src/channel.c | |
| libssh2_poll_listener_queued | 2 | 2 | 5 | src/session.c | |
| libssh2_poll_channel_write | 2 | 2 | 5 | src/session.c | |
| _libssh2_rsa_new | 2 | 19 | 47 | src/openssl.c | |
| _libssh2_dsa_sha1_verify | 2 | 13 | 21 | src/openssl.c | |
| _libssh2_dsa_new | 2 | 13 | 33 | src/openssl.c | |
| libssh2_htonu64 | 1 | 9 | 15 | src/misc.c | |
| libssh2_waitsocket | 1 | 9 | 18 | src/packet.c | |
| libssh2_comp_method_none_comp | 1 | 8 | 21 | src/comp.c | |
| libssh2_hostkey_method_ssh_dss_dtor | 1 | 5 | 12 | src/hostkey.c | |
| libssh2_hostkey_method_ssh_rsa_dtor | 1 | 5 | 12 | src/hostkey.c | |
| libssh2_hostkey_method_ssh_rsa_sig_verify | 1 | 5 | 15 | src/hostkey.c | |
| libssh2_htonu32 | 1 | 4 | 8 | src/misc.c | |
| libssh2_mac_method_common_init | 1 | 4 | 10 | src/mac.c | |
| libssh2_ntohu64 | 1 | 4 | 10 | src/misc.c | |
| libssh2_mac_method_hmac_md5_96_hash | 1 | 4 | 16 | src/mac.c | |
| libssh2_mac_method_hmac_sha1_96_hash | 1 | 4 | 16 | src/mac.c | |
| _libssh2_encrypt | 1 | 3 | 8 | src/crypt.c | |
| libssh2_trace | 1 | 2 | 6 | src/misc.c | |
| _libssh2_cipher_init | 1 | 3 | 9 | src/openssl.c | |
| libssh2_comp_method_zlib_free | 1 | 2 | 7 | src/comp.c | |
| libssh2_comp_method_zlib_alloc | 1 | 2 | 7 | src/comp.c | |
| LIBSSH2_REALLOC_FUNC | 1 | 2 | 6 | src/session.c | |
| LIBSSH2_FREE_FUNC | 1 | 2 | 6 | src/session.c | |
| LIBSSH2_ALLOC_FUNC | 1 | 2 | 6 | src/session.c | |
| libssh2_trace | 1 | 2 | 6 | src/misc.c | |
| libssh2_ntohu32 | 1 | 1 | 5 | src/misc.c | |
| libssh2_mac_none_MAC | 1 | 1 | 8 | src/mac.c | |
| libssh2_crypt_none_crypt | 1 | 1 | 7 | src/crypt.c | |
| libssh2_hostkey_methods | 1 | 1 | 5 | src/hostkey.c | |
| libssh2_comp_methods | 1 | 1 | 5 | src/comp.c | |
| libssh2_mac_methods | 1 | 1 | 5 | src/mac.c | |
| libssh2_crypt_methods | 1 | 1 | 5 | src/crypt.c | |
| libssh2_sftp_last_error | 1 | 1 | 5 | src/sftp.c | |
| libssh2_userauth_authenticated | 1 | 1 | 5 | src/userauth.c | |
| libssh2_sftp_tell | 1 | 1 | 5 | src/sftp.c | |
| libssh2_sftp_seek2 | 1 | 1 | 5 | src/sftp.c | |
| libssh2_sftp_seek | 1 | 1 | 5 | src/sftp.c | |
| libssh2_channel_get_exit_status | 1 | 1 | 5 | src/channel.c | |
| libssh2_channel_set_blocking | 1 | 1 | 5 | src/channel.c | |
| libssh2_session_get_blocking | 1 | 1 | 5 | src/session.c | |
| libssh2_session_set_blocking | 1 | 1 | 5 | src/session.c | |
| libssh2_session_last_errno | 1 | 1 | 5 | src/session.c | |