# HG changeset patch # User Matt Johnston # Date 1086283757 0 # Node ID 7a37cff272584a1368a18487c1711b865412a8e7 # Parent f76c9389e9e044fa037452e874bb9bb5c259928c# Parent 0f7d69d31b9d19e7206914cb1bf37d42ff03685d merge of a585c2284e9ad17bfe6c6fd8f18b1c5042b2df47 and e3f735bb16fbd5cfb6bcad70885550c1b79b874c diff -r f76c9389e9e0 -r 7a37cff27258 Makefile.in --- a/Makefile.in Thu Jun 03 17:22:48 2004 +0000 +++ b/Makefile.in Thu Jun 03 17:29:17 2004 +0000 @@ -5,7 +5,7 @@ common-kex.o dss.o bignum.o \ signkey.o rsa.o random.o common-channel.o \ common-chansession.o queue.o termcodes.o \ - loginrec.o atomicio.o x11fwd.o tcpfwd-direct.o compat.o \ + loginrec.o atomicio.o svr-x11fwd.o tcpfwd-direct.o compat.o \ tcpfwd-remote.o listener.o SVROBJS=svr-kex.o svr-packet.o svr-algo.o svr-auth.o sshpty.o \ diff -r f76c9389e9e0 -r 7a37cff27258 svr-x11fwd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/svr-x11fwd.c Thu Jun 03 17:29:17 2004 +0000 @@ -0,0 +1,235 @@ +/* + * Dropbear - a SSH2 server + * + * Copyright (c) 2002,2003 Matt Johnston + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ + +#include "includes.h" + +#ifndef DISABLE_X11FWD +#include "x11fwd.h" +#include "session.h" +#include "ssh.h" +#include "dbutil.h" +#include "chansession.h" +#include "channel.h" +#include "packet.h" +#include "buffer.h" + +#define X11BASEPORT 6000 +#define X11BINDBASE 6010 + +static void x11accept(struct Listener* listener); +static int bindport(int fd); +static int send_msg_channel_open_x11(int fd, struct sockaddr_in* addr); + +/* called as a request for a session channel, sets up listening X11 */ +/* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ +int x11req(struct ChanSess * chansess) { + + int fd; + + /* we already have an x11 connection */ + if (chansess->x11listener != NULL) { + return DROPBEAR_FAILURE; + } + + chansess->x11singleconn = buf_getbyte(ses.payload); + chansess->x11authprot = buf_getstring(ses.payload, NULL); + chansess->x11authcookie = buf_getstring(ses.payload, NULL); + chansess->x11screennum = buf_getint(ses.payload); + + /* create listening socket */ + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + goto fail; + } + + /* allocate port and bind */ + chansess->x11port = bindport(fd); + if (chansess->x11port < 0) { + goto fail; + } + + /* listen */ + if (listen(fd, 20) < 0) { + goto fail; + } + + /* set non-blocking */ + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { + goto fail; + } + + /* listener code will handle the socket now. + * No cleanup handler needed, since listener_remove only happens + * from our cleanup anyway */ + chansess->x11listener = new_listener( fd, 0, chansess, x11accept, NULL); + if (chansess->x11listener == NULL) { + goto fail; + } + + return DROPBEAR_SUCCESS; + +fail: + /* cleanup */ + m_free(chansess->x11authprot); + m_free(chansess->x11authcookie); + close(fd); + + return DROPBEAR_FAILURE; +} + +/* accepts a new X11 socket */ +/* returns DROPBEAR_FAILURE or DROPBEAR_SUCCESS */ +static void x11accept(struct Listener* listener) { + + int fd; + struct sockaddr_in addr; + int len; + int ret; + + len = sizeof(addr); + + fd = accept(listener->sock, (struct sockaddr*)&addr, &len); + if (fd < 0) { + return; + } + + /* if single-connection we close it up */ + if (((struct ChanSess *)(listener->typedata))->x11singleconn) { + x11cleanup(listener); + } + + ret = send_msg_channel_open_x11(fd, &addr); + if (ret == DROPBEAR_FAILURE) { + close(fd); + } +} + +/* This is called after switching to the user, and sets up the xauth + * and environment variables. */ +void x11setauth(struct ChanSess *chansess) { + + char display[20]; /* space for "localhost:12345.123" */ + FILE * authprog; + int val; + + if (chansess->x11listener == NULL) { + return; + } + + /* create the DISPLAY string */ + val = snprintf(display, sizeof(display), "localhost:%d.%d", + chansess->x11port - X11BASEPORT, chansess->x11screennum); + if (val < 0 || val >= (int)sizeof(display)) { + /* string was truncated */ + return; + } + + addnewvar("DISPLAY", display); + + /* create the xauth string */ + val = snprintf(display, sizeof(display), "unix:%d.%d", + chansess->x11port - X11BASEPORT, chansess->x11screennum); + if (val < 0 || val >= (int)sizeof(display)) { + /* string was truncated */ + return; + } + + /* popen is a nice function - code is strongly based on OpenSSH's */ + authprog = popen(XAUTH_COMMAND, "w"); + if (authprog) { + fprintf(authprog, "add %s %s %s\n", + display, chansess->x11authprot, chansess->x11authcookie); + pclose(authprog); + } else { + fprintf(stderr, "Failed to run %s\n", XAUTH_COMMAND); + } +} + +void x11cleanup(struct Listener *listener) { + + struct ChanSess *chansess = (struct ChanSess*)listener->typedata; + + m_free(chansess->x11authprot); + m_free(chansess->x11authcookie); + remove_listener(listener); + chansess->x11listener = NULL; +} + +static const struct ChanType chan_x11 = { + 0, /* sepfds */ + "x11", + NULL, /* inithandler */ + NULL, /* checkclose */ + NULL, /* reqhandler */ + NULL /* closehandler */ +}; + + +static int send_msg_channel_open_x11(int fd, struct sockaddr_in* addr) { + + char* ipstring; + + if (send_msg_channel_open_init(fd, &chan_x11) == DROPBEAR_SUCCESS) { + ipstring = inet_ntoa(addr->sin_addr); + buf_putstring(ses.writepayload, ipstring, strlen(ipstring)); + buf_putint(ses.writepayload, addr->sin_port); + + encrypt_packet(); + return DROPBEAR_SUCCESS; + } else { + return DROPBEAR_FAILURE; + } + +} + +/* returns the port bound to, or -1 on failure. + * Will attempt to bind to a port X11BINDBASE (6010 usually) or upwards */ +static int bindport(int fd) { + + struct sockaddr_in addr; + uint16_t port; + + memset((void*)&addr, 0x0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + /* if we can't find one in 2000 ports free, something's wrong */ + for (port = X11BINDBASE; port < X11BINDBASE + 2000; port++) { + addr.sin_port = htons(port); + if (bind(fd, (struct sockaddr*)&addr, + sizeof(struct sockaddr_in)) == 0) { + /* success */ + return port; + } + if (errno == EADDRINUSE) { + /* try the next port */ + continue; + } + /* otherwise it was an error we don't know about */ + dropbear_log(LOG_DEBUG, "failed to bind x11 socket"); + break; + } + return -1; +} +#endif /* DROPBEAR_X11FWD */ diff -r f76c9389e9e0 -r 7a37cff27258 x11fwd.c --- a/x11fwd.c Thu Jun 03 17:22:48 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,235 +0,0 @@ -/* - * Dropbear - a SSH2 server - * - * Copyright (c) 2002,2003 Matt Johnston - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ - -#include "includes.h" - -#ifndef DISABLE_X11FWD -#include "x11fwd.h" -#include "session.h" -#include "ssh.h" -#include "dbutil.h" -#include "chansession.h" -#include "channel.h" -#include "packet.h" -#include "buffer.h" - -#define X11BASEPORT 6000 -#define X11BINDBASE 6010 - -static void x11accept(struct Listener* listener); -static int bindport(int fd); -static int send_msg_channel_open_x11(int fd, struct sockaddr_in* addr); - -/* called as a request for a session channel, sets up listening X11 */ -/* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ -int x11req(struct ChanSess * chansess) { - - int fd; - - /* we already have an x11 connection */ - if (chansess->x11listener != NULL) { - return DROPBEAR_FAILURE; - } - - chansess->x11singleconn = buf_getbyte(ses.payload); - chansess->x11authprot = buf_getstring(ses.payload, NULL); - chansess->x11authcookie = buf_getstring(ses.payload, NULL); - chansess->x11screennum = buf_getint(ses.payload); - - /* create listening socket */ - fd = socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - goto fail; - } - - /* allocate port and bind */ - chansess->x11port = bindport(fd); - if (chansess->x11port < 0) { - goto fail; - } - - /* listen */ - if (listen(fd, 20) < 0) { - goto fail; - } - - /* set non-blocking */ - if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { - goto fail; - } - - /* listener code will handle the socket now. - * No cleanup handler needed, since listener_remove only happens - * from our cleanup anyway */ - chansess->x11listener = new_listener( fd, 0, chansess, x11accept, NULL); - if (chansess->x11listener == NULL) { - goto fail; - } - - return DROPBEAR_SUCCESS; - -fail: - /* cleanup */ - m_free(chansess->x11authprot); - m_free(chansess->x11authcookie); - close(fd); - - return DROPBEAR_FAILURE; -} - -/* accepts a new X11 socket */ -/* returns DROPBEAR_FAILURE or DROPBEAR_SUCCESS */ -static void x11accept(struct Listener* listener) { - - int fd; - struct sockaddr_in addr; - int len; - int ret; - - len = sizeof(addr); - - fd = accept(listener->sock, (struct sockaddr*)&addr, &len); - if (fd < 0) { - return; - } - - /* if single-connection we close it up */ - if (((struct ChanSess *)(listener->typedata))->x11singleconn) { - x11cleanup(listener); - } - - ret = send_msg_channel_open_x11(fd, &addr); - if (ret == DROPBEAR_FAILURE) { - close(fd); - } -} - -/* This is called after switching to the user, and sets up the xauth - * and environment variables. */ -void x11setauth(struct ChanSess *chansess) { - - char display[20]; /* space for "localhost:12345.123" */ - FILE * authprog; - int val; - - if (chansess->x11listener == NULL) { - return; - } - - /* create the DISPLAY string */ - val = snprintf(display, sizeof(display), "localhost:%d.%d", - chansess->x11port - X11BASEPORT, chansess->x11screennum); - if (val < 0 || val >= (int)sizeof(display)) { - /* string was truncated */ - return; - } - - addnewvar("DISPLAY", display); - - /* create the xauth string */ - val = snprintf(display, sizeof(display), "unix:%d.%d", - chansess->x11port - X11BASEPORT, chansess->x11screennum); - if (val < 0 || val >= (int)sizeof(display)) { - /* string was truncated */ - return; - } - - /* popen is a nice function - code is strongly based on OpenSSH's */ - authprog = popen(XAUTH_COMMAND, "w"); - if (authprog) { - fprintf(authprog, "add %s %s %s\n", - display, chansess->x11authprot, chansess->x11authcookie); - pclose(authprog); - } else { - fprintf(stderr, "Failed to run %s\n", XAUTH_COMMAND); - } -} - -void x11cleanup(struct Listener *listener) { - - struct ChanSess *chansess = (struct ChanSess*)listener->typedata; - - m_free(chansess->x11authprot); - m_free(chansess->x11authcookie); - remove_listener(listener); - chansess->x11listener = NULL; -} - -static const struct ChanType chan_x11 = { - 0, /* sepfds */ - "x11", - NULL, /* inithandler */ - NULL, /* checkclose */ - NULL, /* reqhandler */ - NULL /* closehandler */ -}; - - -static int send_msg_channel_open_x11(int fd, struct sockaddr_in* addr) { - - char* ipstring; - - if (send_msg_channel_open_init(fd, &chan_x11) == DROPBEAR_SUCCESS) { - ipstring = inet_ntoa(addr->sin_addr); - buf_putstring(ses.writepayload, ipstring, strlen(ipstring)); - buf_putint(ses.writepayload, addr->sin_port); - - encrypt_packet(); - return DROPBEAR_SUCCESS; - } else { - return DROPBEAR_FAILURE; - } - -} - -/* returns the port bound to, or -1 on failure. - * Will attempt to bind to a port X11BINDBASE (6010 usually) or upwards */ -static int bindport(int fd) { - - struct sockaddr_in addr; - uint16_t port; - - memset((void*)&addr, 0x0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - /* if we can't find one in 2000 ports free, something's wrong */ - for (port = X11BINDBASE; port < X11BINDBASE + 2000; port++) { - addr.sin_port = htons(port); - if (bind(fd, (struct sockaddr*)&addr, - sizeof(struct sockaddr_in)) == 0) { - /* success */ - return port; - } - if (errno == EADDRINUSE) { - /* try the next port */ - continue; - } - /* otherwise it was an error we don't know about */ - dropbear_log(LOG_DEBUG, "failed to bind x11 socket"); - break; - } - return -1; -} -#endif /* DROPBEAR_X11FWD */