Add X11 forwarding support

This commit is contained in:
Sara Golemon 2005-01-06 00:51:30 +00:00
parent dc4bb1af96
commit a119685410
5 changed files with 192 additions and 1 deletions

View File

@ -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))

View File

@ -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;

View File

@ -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)
*/

View File

@ -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;
}

View File

@ -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;