Add X11 forwarding support
This commit is contained in:
parent
dc4bb1af96
commit
a119685410
@ -146,6 +146,7 @@
|
||||
#define LIBSSH2_DISCONNECT_FUNC(name) void name(LIBSSH2_SESSION *session, int reason, const char *message, int message_len, const char *language, int language_len, void **abstract)
|
||||
#define LIBSSH2_PASSWD_CHANGEREQ_FUNC(name) void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, void **abstract)
|
||||
#define LIBSSH2_MACERROR_FUNC(name) int name(LIBSSH2_SESSION *session, const char *packet, int packet_len, void **abstract)
|
||||
#define LIBSSH2_X11_OPEN_FUNC(name) void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, char *shost, int sport, void **abstract)
|
||||
|
||||
#define LIBSSH2_CHANNEL_CLOSE_FUNC(name) void name(LIBSSH2_SESSION *session, void **session_abstract, LIBSSH2_CHANNEL *channel, void **channel_abstract)
|
||||
|
||||
@ -154,6 +155,7 @@
|
||||
#define LIBSSH2_CALLBACK_DEBUG 1
|
||||
#define LIBSSH2_CALLBACK_DISCONNECT 2
|
||||
#define LIBSSH2_CALLBACK_MACERROR 3
|
||||
#define LIBSSH2_CALLBACK_X11 4
|
||||
|
||||
/* libssh2_session_method_pref() constants */
|
||||
#define LIBSSH2_METHOD_KEX 0
|
||||
@ -288,6 +290,9 @@ LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, char *varnam
|
||||
LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, char *term, int term_len, char *modes, int modes_len, int width, int height, int width_px, int height_px);
|
||||
#define libssh2_channel_request_pty(channel, term) libssh2_channel_request_pty_ex((channel), (term), strlen(term), NULL, 0, LIBSSH2_TERM_WIDTH, LIBSSH2_TERM_HEIGHT, LIBSSH2_TERM_WIDTH_PX, LIBSSH2_TERM_HEIGHT_PX)
|
||||
|
||||
LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, char *auth_proto, char *auth_cookie, int screen_number);
|
||||
#define libssh2_channel_x11_req(channel, screen_number) libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number))
|
||||
|
||||
LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, char *request, int request_len, char *message, int message_len);
|
||||
#define libssh2_channel_shell(channel) libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, NULL, 0)
|
||||
#define libssh2_channel_exec(channel, command) libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, (command), strlen(command))
|
||||
|
@ -58,6 +58,7 @@
|
||||
session->ssh_msg_disconnect((session), (reason), (message), (message_len), (language), (language_len), &(session)->abstract)
|
||||
|
||||
#define LIBSSH2_MACERROR(session, data, datalen) session->macerror((session), (data), (datalen), &(session)->abstract)
|
||||
#define LIBSSH2_X11_OPEN(channel, shost, sport) channel->session->x11(((channel)->session), (channel), (shost), (sport), (&(channel)->session->abstract))
|
||||
|
||||
#define LIBSSH2_CHANNEL_CLOSE(session, channel) channel->close_cb((session), &(session)->abstract, (channel), &(channel)->abstract)
|
||||
|
||||
@ -173,6 +174,7 @@ struct _LIBSSH2_SESSION {
|
||||
LIBSSH2_DEBUG_FUNC((*ssh_msg_debug));
|
||||
LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect));
|
||||
LIBSSH2_MACERROR_FUNC((*macerror));
|
||||
LIBSSH2_X11_OPEN_FUNC((*x11));
|
||||
|
||||
/* Method preferences -- NULL yields "load order" */
|
||||
char *kex_prefs;
|
||||
|
@ -36,6 +36,7 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <openssl/rand.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@ -576,6 +577,77 @@ LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, char *t
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_channel_x11_req_ex
|
||||
* Request X11 forwarding
|
||||
*/
|
||||
LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, char *auth_proto, char *auth_cookie, int screen_number)
|
||||
{
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char *s, *packet;
|
||||
unsigned long proto_len = auth_proto ? strlen(auth_proto) : (sizeof("MIT-MAGIC-COOKIE-1") - 1);
|
||||
unsigned long cookie_len = auth_cookie ? strlen(auth_cookie) : 32;
|
||||
unsigned long packet_len = proto_len + cookie_len + 41; /* packet_type(1) + channel(4) + x11_req_len(4) + "x11-req"(7) + want_reply(1) +
|
||||
single_cnx(4) + proto_len(4) + cookie_len(4) + screen_num(4) */
|
||||
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||
if (!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("x11-req") - 1); s += 4;
|
||||
memcpy(s, "x11-req", sizeof("x11-req") - 1); s += sizeof("x11-req") - 1;
|
||||
|
||||
*(s++) = 0xFF; /* want_reply */
|
||||
*(s++) = single_connection ? 0xFF : 0x00;
|
||||
|
||||
libssh2_htonu32(s, proto_len); s += 4;
|
||||
memcpy(s, auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", proto_len);
|
||||
s += proto_len;
|
||||
|
||||
libssh2_htonu32(s, cookie_len);
|
||||
if (auth_cookie) {
|
||||
memcpy(s, auth_cookie, cookie_len);
|
||||
} else {
|
||||
RAND_bytes(s, cookie_len);
|
||||
}
|
||||
s += cookie_len;
|
||||
|
||||
libssh2_htonu32(s, screen_number); s += 4;
|
||||
|
||||
if (libssh2_packet_write(session, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send pty-request packet", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
while (1) {
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
unsigned char local_channel[4];
|
||||
|
||||
libssh2_htonu32(local_channel, channel->local.id);
|
||||
|
||||
if (libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_SUCCESS, &data, &data_len, 1, local_channel, 4, 1) == 0) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_FAILURE, &data, &data_len, 1, local_channel, 4, 1) == 0) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, "Unable to complete request for channel x11-req", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Never reached, just giving the compiler something to not complain about */
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_channel_process_startup
|
||||
* Primitive for libssh2_channel_(shell|exec|subsystem)
|
||||
*/
|
||||
|
109
src/packet.c
109
src/packet.c
@ -99,7 +99,7 @@ inline int libssh2_packet_queue_listener(LIBSSH2_SESSION *session, unsigned char
|
||||
channel->session = session;
|
||||
channel->channel_type_len = sizeof("forwarded-tcpip") - 1;
|
||||
channel->channel_type = LIBSSH2_ALLOC(session, channel->channel_type_len + 1);
|
||||
if (!channel) {
|
||||
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 */
|
||||
@ -169,6 +169,105 @@ inline int libssh2_packet_queue_listener(LIBSSH2_SESSION *session, unsigned char
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_packet_x11_open
|
||||
* Accept a forwarded X11 connection
|
||||
*/
|
||||
inline int libssh2_packet_x11_open(LIBSSH2_SESSION *session, unsigned char *data, unsigned long datalen)
|
||||
{
|
||||
int failure_code = 2; /* SSH_OPEN_CONNECT_FAILED */
|
||||
unsigned char *s = data + (sizeof("x11") - 1) + 5;
|
||||
unsigned long packet_len = 17 + (sizeof("X11 Forward Unavailable") - 1);
|
||||
unsigned char *p, packet[17 + (sizeof("X11 Forward Unavailable") - 1)];
|
||||
/* packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
unsigned long sender_channel, initial_window_size, packet_size;
|
||||
unsigned char *shost;
|
||||
unsigned long sport, shost_len;
|
||||
|
||||
sender_channel = libssh2_ntohu32(s); s += 4;
|
||||
initial_window_size = libssh2_ntohu32(s); s += 4;
|
||||
packet_size = libssh2_ntohu32(s); s += 4;
|
||||
shost_len = libssh2_ntohu32(s); s += 4;
|
||||
shost = s; s += shost_len;
|
||||
sport = libssh2_ntohu32(s); s += 4;
|
||||
|
||||
if (session->x11) {
|
||||
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 = 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 = initial_window_size;
|
||||
channel->local.window_size = initial_window_size;
|
||||
channel->local.packet_size = packet_size;
|
||||
|
||||
p = 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;
|
||||
|
||||
if (libssh2_packet_write(session, packet, 17)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open confirmation", 0);
|
||||
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, shost, sport);
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
|
||||
}
|
||||
|
||||
x11_exit:
|
||||
p = packet;
|
||||
*(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
|
||||
libssh2_htonu32(p, sender_channel); p += 4;
|
||||
libssh2_htonu32(p, failure_code); p += 4;
|
||||
libssh2_htonu32(p, sizeof("X11 Forward Unavailable") - 1); p += 4;
|
||||
memcpy(s, "X11 Forward Unavailable", sizeof("X11 Forward Unavailable") - 1); p += sizeof("X11 Forward Unavailable") - 1;
|
||||
libssh2_htonu32(p, 0);
|
||||
|
||||
if (libssh2_packet_write(session, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send open failure", 0);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_packet_new
|
||||
* Create a new packet and attach it to the brigade
|
||||
@ -367,6 +466,14 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
LIBSSH2_FREE(session, data);
|
||||
return retval;
|
||||
}
|
||||
if ((datalen >= (sizeof("x11") + 4)) &&
|
||||
((sizeof("x11")-1) == libssh2_ntohu32(data + 1)) &&
|
||||
(memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {
|
||||
int retval = libssh2_packet_x11_open(session, data, datalen);
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
return retval;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -222,6 +222,11 @@ LIBSSH2_API void* libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbt
|
||||
session->macerror = callback;
|
||||
return oldcb;
|
||||
break;
|
||||
case LIBSSH2_CALLBACK_X11:
|
||||
oldcb = session->x11;
|
||||
session->x11 = callback;
|
||||
return oldcb;
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user