# HG changeset patch # User Matt Johnston # Date 1086281153 0 # Node ID 7f77962de9987ef152b792d6b69d3f67f2334986 # Parent 425ed5c20157516e3debcc4e3ac390da2777cc41 - Reworked non-channel fd handling to listener.c - More channel cleaning up diff -r 425ed5c20157 -r 7f77962de998 Makefile.in --- a/Makefile.in Wed Jun 02 04:59:49 2004 +0000 +++ b/Makefile.in Thu Jun 03 16:45:53 2004 +0000 @@ -4,9 +4,9 @@ COMMONOBJS=dbutil.o common-session.o common-packet.o common-algo.o buffer.o \ common-kex.o dss.o bignum.o \ signkey.o rsa.o random.o common-channel.o \ - common-chansession.o queue.o termcodes.o runopts.o \ - loginrec.o atomicio.o x11fwd.o agentfwd.o localtcpfwd.o compat.o \ - remotetcpfwd.o tcpfwd.o + common-chansession.o queue.o termcodes.o \ + loginrec.o atomicio.o 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 \ svr-authpasswd.o svr-authpubkey.o svr-session.o svr-service.o \ @@ -28,8 +28,8 @@ dss.h bignum.h signkey.h rsa.h random.h service.h auth.h authpasswd.h \ debug.h channel.h chansession.h debug.h config.h queue.h sshpty.h \ termcodes.h gendss.h genrsa.h authpubkey.h runopts.h includes.h \ - loginrec.h atomicio.h x11fwd.h agentfwd.h localtcpfwd.h compat.h \ - remotetcpfwd.h tcpfwd.h + loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd-direct.h compat.h \ + tcpfwd-remote.h listener.h ALLOBJS=$(OBJS) $(DROPBEARKEYOBJS) $(DROPBEAROBJS) diff -r 425ed5c20157 -r 7f77962de998 channel.h --- a/channel.h Wed Jun 02 04:59:49 2004 +0000 +++ b/channel.h Thu Jun 03 16:45:53 2004 +0000 @@ -114,8 +114,7 @@ void recv_msg_channel_eof(); #ifdef USE_LISTENERS -int send_msg_channel_open_init(int fd, struct ChanType *type, - const char * typestring); +int send_msg_channel_open_init(int fd, const struct ChanType *type); void recv_msg_channel_open_confirmation(); void recv_msg_channel_open_failure(); #endif diff -r 425ed5c20157 -r 7f77962de998 chansession.h --- a/chansession.h Wed Jun 02 04:59:49 2004 +0000 +++ b/chansession.h Thu Jun 03 16:45:53 2004 +0000 @@ -27,6 +27,7 @@ #include "loginrec.h" #include "channel.h" +#include "listener.h" struct ChanSess { @@ -47,7 +48,7 @@ unsigned char exitcore; #ifndef DISABLE_X11FWD - int x11fd; /* set to -1 to indicate forwarding not established */ + struct Listener * x11listener; int x11port; char * x11authprot; char * x11authcookie; @@ -56,7 +57,7 @@ #endif #ifndef DISABLE_AGENTFWD - int agentfd; + struct Listener * agentlistener; char * agentfile; char * agentdir; #endif diff -r 425ed5c20157 -r 7f77962de998 common-channel.c --- a/common-channel.c Wed Jun 02 04:59:49 2004 +0000 +++ b/common-channel.c Thu Jun 03 16:45:53 2004 +0000 @@ -32,9 +32,9 @@ #include "dbutil.h" #include "channel.h" #include "ssh.h" -#include "localtcpfwd.h" -#include "remotetcpfwd.h" -#include "tcpfwd.h" +#include "tcpfwd-direct.h" +#include "tcpfwd-remote.h" +#include "listener.h" static void send_msg_channel_open_failure(unsigned int remotechan, int reason, const unsigned char *text, const unsigned char *lang); @@ -70,8 +70,8 @@ ses.chantypes = chantypes; -#ifdef USING_TCP_LISTENERS - tcp_fwd_initialise(); +#ifdef USING_LISTENERS + listeners_initialise(); #endif } @@ -219,9 +219,9 @@ } /* foreach channel */ - /* Not channel specific */ -#ifdef USING_TCP_LISTENERS - handle_tcp_fwd(readfd); + /* Listeners such as TCP, X11, agent-auth */ +#ifdef USING_LISTENERS + handle_listeners(readfd); #endif } @@ -429,8 +429,8 @@ } /* foreach channel */ -#ifdef USING_TCP_LISTENERS - set_tcp_fwd_fds(readfd); +#ifdef USING_LISTENERS + set_listener_fds(readfd); #endif } @@ -895,8 +895,7 @@ * options, with the calling function calling encrypt_packet() after * completion. It is mandatory for the caller to encrypt_packet() if * DROPBEAR_SUCCESS is returned */ -int send_msg_channel_open_init(int fd, struct ChanType *type, - const char * typestring) { +int send_msg_channel_open_init(int fd, const struct ChanType *type) { struct Channel* chan; @@ -920,7 +919,7 @@ CHECKCLEARTOWRITE(); buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN); - buf_putstring(ses.writepayload, typestring, strlen(typestring)); + buf_putstring(ses.writepayload, type->name, strlen(type->name)); buf_putint(ses.writepayload, chan->index); buf_putint(ses.writepayload, RECV_MAXWINDOW); buf_putint(ses.writepayload, RECV_MAXPACKET); diff -r 425ed5c20157 -r 7f77962de998 listener.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/listener.c Thu Jun 03 16:45:53 2004 +0000 @@ -0,0 +1,123 @@ +#include "includes.h" +#include "listener.h" +#include "session.h" +#include "dbutil.h" + +void listener_initialise() { + + /* just one slot to start with */ + ses.listeners = (struct Listener**)m_malloc(sizeof(struct Listener*)); + ses.listensize = 1; + ses.listeners[0] = NULL; + +} + +void set_listener_fds(fd_set * readfds) { + + unsigned int i; + struct Listener *listener; + + /* check each in turn */ + for (i = 0; i < ses.listensize; i++) { + listener = ses.listeners[i]; + if (listener != NULL) { + FD_SET(listener->sock, readfds); + } + } +} + + +void handle_listeners(fd_set * readfds) { + + unsigned int i; + struct Listener *listener; + + /* check each in turn */ + for (i = 0; i < ses.listensize; i++) { + listener = ses.listeners[i]; + if (listener != NULL) { + if (FD_ISSET(listener->sock, readfds)) { + listener->accepter(listener); + } + } + } +} + + +/* accepter(int fd, void* typedata) is a function to accept connections, + * cleanup(void* typedata) happens when cleaning up */ +struct Listener* new_listener(int sock, int type, void* typedata, + void (*accepter)(struct Listener*), + void (*cleanup)(struct Listener*)) { + + unsigned int i, j; + struct Listener *newlisten = NULL; + /* try get a new structure to hold it */ + for (i = 0; i < ses.listensize; i++) { + if (ses.listeners[i] == NULL) { + break; + } + } + + /* or create a new one */ + if (i == ses.listensize) { + if (ses.listensize > MAX_LISTENERS) { + TRACE(("leave newlistener: too many already")); + close(sock); + return NULL; + } + + ses.listeners = (struct Listener**)m_realloc(ses.listeners, + (ses.listensize+LISTENER_EXTEND_SIZE) + *sizeof(struct Listener*)); + + ses.listensize += LISTENER_EXTEND_SIZE; + + for (j = i; j < ses.listensize; j++) { + ses.listeners[j] = NULL; + } + } + + ses.maxfd = MAX(ses.maxfd, sock); + + newlisten = (struct Listener*)m_malloc(sizeof(struct Listener)); + newlisten->index = i; + newlisten->type = type; + newlisten->typedata = typedata; + newlisten->sock = sock; + newlisten->accepter = accepter; + newlisten->cleanup = cleanup; + + ses.listeners[i] = newlisten; + return newlisten; +} + +/* Return the first listener which matches the type-specific comparison + * function. Particularly needed for global requests, like tcp */ +struct Listener * get_listener(int type, void* typedata, + int (*match)(void*, void*)) { + + unsigned int i; + struct Listener* listener; + + for (i = 0, listener = ses.listeners[i]; i < ses.listensize; i++) { + if (listener->type == type + && match(typedata, listener->typedata)) { + return listener; + } + } + + return NULL; +} + +void remove_listener(struct Listener* listener) { + + if (listener->cleanup) { + listener->cleanup(listener); + } + + close(listener->sock); + ses.listeners[listener->index] = NULL; + m_free(listener); + +} diff -r 425ed5c20157 -r 7f77962de998 listener.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/listener.h Thu Jun 03 16:45:53 2004 +0000 @@ -0,0 +1,37 @@ +#ifndef _LISTENER_H +#define _LISTENER_H + +#define MAX_LISTENERS 20 +#define LISTENER_EXTEND_SIZE 1 + +struct Listener { + + int sock; + + int index; /* index in the array of listeners */ + + void (*accepter)(struct Listener*); + void (*cleanup)(struct Listener*); + + int type; /* CHANNEL_ID_X11, CHANNEL_ID_AGENT, + CHANNEL_ID_TCPDIRECT (for clients), + CHANNEL_ID_TCPFORWARDED (for servers) */ + + void *typedata; + +}; + +void listener_initialise(); +void handle_listeners(fd_set * readfds); +void set_listener_fds(fd_set * readfds); + +struct Listener* new_listener(int sock, int type, void* typedata, + void (*accepter)(struct Listener*), + void (*cleanup)(struct Listener*)); + +struct Listener * get_listener(int type, void* typedata, + int (*match)(void*, void*)); + +void remove_listener(struct Listener* listener); + +#endif /* _LISTENER_H */ diff -r 425ed5c20157 -r 7f77962de998 localtcpfwd.c --- a/localtcpfwd.c Wed Jun 02 04:59:49 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -#include "includes.h" -#include "session.h" -#include "dbutil.h" -#include "channel.h" -#include "localtcpfwd.h" - -#ifndef DISABLE_LOCALTCPFWD -static int newtcpdirect(struct Channel * channel); -static int newtcp(const char * host, int port); - -const struct ChanType chan_tcpdirect = { - 0, /* sepfds */ - "direct-tcpip", - newtcpdirect, /* init */ - NULL, /* checkclose */ - NULL, /* reqhandler */ - NULL /* closehandler */ -}; - - - -/* Called upon creating a new direct tcp channel (ie we connect out to an - * address */ -static int newtcpdirect(struct Channel * channel) { - - unsigned char* desthost = NULL; - unsigned int destport; - unsigned char* orighost = NULL; - unsigned int origport; - int sock; - int len; - int ret = DROPBEAR_FAILURE; - - if (ses.opts->nolocaltcp) { - TRACE(("leave newtcpdirect: local tcp forwarding disabled")); - goto out; - } - - desthost = buf_getstring(ses.payload, &len); - if (len > MAX_HOST_LEN) { - TRACE(("leave newtcpdirect: desthost too long")); - goto out; - } - - destport = buf_getint(ses.payload); - - orighost = buf_getstring(ses.payload, &len); - if (len > MAX_HOST_LEN) { - TRACE(("leave newtcpdirect: orighost too long")); - goto out; - } - - origport = buf_getint(ses.payload); - - /* best be sure */ - if (origport > 65535 || destport > 65535) { - TRACE(("leave newtcpdirect: port > 65535")); - goto out; - } - - sock = newtcp(desthost, destport); - if (sock < 0) { - TRACE(("leave newtcpdirect: sock failed")); - goto out; - } - - ses.maxfd = MAX(ses.maxfd, sock); - - /* Note that infd is actually the "outgoing" direction on the - * tcp connection, vice versa for outfd. - * We don't set outfd, that will get set after the connection's - * progress succeeds */ - channel->infd = sock; - channel->initconn = 1; - - ret = DROPBEAR_SUCCESS; - -out: - m_free(desthost); - m_free(orighost); - TRACE(("leave newtcpdirect: ret %d", ret)); - return ret; -} - -/* Initiate a new TCP connection - this is non-blocking, so the socket - * returned will need to be checked for success when it is first written. - * Similarities with OpenSSH's connect_to() are not coincidental. - * Returns -1 on failure */ -static int newtcp(const char * host, int port) { - - int sock = -1; - char portstring[6]; - struct addrinfo *res = NULL, *ai; - int val; - - struct addrinfo hints; - - TRACE(("enter newtcp")); - - memset(&hints, 0, sizeof(hints)); - /* TCP, either ip4 or ip6 */ - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = PF_UNSPEC; - - snprintf(portstring, sizeof(portstring), "%d", port); - if (getaddrinfo(host, portstring, &hints, &res) != 0) { - if (res) { - freeaddrinfo(res); - } - TRACE(("leave newtcp: failed getaddrinfo")); - return -1; - } - - /* Use the first socket that works */ - for (ai = res; ai != NULL; ai = ai->ai_next) { - - if (ai->ai_family != PF_INET && ai->ai_family != PF_INET6) { - continue; - } - - sock = socket(ai->ai_family, SOCK_STREAM, 0); - if (sock < 0) { - TRACE(("TCP socket() failed")); - continue; - } - - if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { - close(sock); - TRACE(("TCP non-blocking failed")); - continue; - } - - /* non-blocking, so it might return without success (EINPROGRESS) */ - if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { - if (errno == EINPROGRESS) { - TRACE(("connect in progress")); - } else { - close(sock); - TRACE(("TCP connect failed")); - continue; - } - } - break; - } - - freeaddrinfo(res); - - if (ai == NULL) { - return -1; - } - - setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val)); - return sock; -} -#endif /* DISABLE_LOCALTCPFWD */ diff -r 425ed5c20157 -r 7f77962de998 localtcpfwd.h --- a/localtcpfwd.h Wed Jun 02 04:59:49 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +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. */ -#ifndef _LOCALTCPFWD_H_ -#define _LOCALTCPFWD_H_ -#ifndef DISABLE_LOCALTCPFWD - -#include "includes.h" -#include "channel.h" - -extern const struct ChanType chan_tcpdirect; - -#endif -#endif diff -r 425ed5c20157 -r 7f77962de998 options.h --- a/options.h Wed Jun 02 04:59:49 2004 +0000 +++ b/options.h Thu Jun 03 16:45:53 2004 +0000 @@ -296,7 +296,7 @@ #endif #ifndef ENABLE_LOCALTCPFWD -#define DISABLE_LOCALTCPFWD +#define DISABLE_TCPDIRECT #endif #ifndef ENABLE_REMOTETCPFWD diff -r 425ed5c20157 -r 7f77962de998 remotetcpfwd.c --- a/remotetcpfwd.c Wed Jun 02 04:59:49 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,302 +0,0 @@ -#include "includes.h" -#include "ssh.h" -#include "remotetcpfwd.h" -#include "dbutil.h" -#include "session.h" -#include "buffer.h" -#include "packet.h" -#include "tcpfwd.h" - -#ifndef DISABLE_REMOTETCPFWD - -struct RemoteTCP { - - unsigned char* addr; - unsigned int port; - -}; - -static void send_msg_request_success(); -static void send_msg_request_failure(); -static int cancelremotetcp(); -static int remotetcpreq(); -static int newlistener(unsigned char* bindaddr, unsigned int port); -static void acceptremote(struct TCPListener *listener); - -/* At the moment this is completely used for tcp code (with the name reflecting - * that). If new request types are added, this should be replaced with code - * similar to the request-switching in chansession.c */ -void recv_msg_global_request_remotetcp() { - - unsigned char* reqname = NULL; - unsigned int namelen; - unsigned int wantreply = 0; - int ret = DROPBEAR_FAILURE; - - TRACE(("enter recv_msg_global_request_remotetcp")); - - if (ses.opts->noremotetcp) { - TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled")); - goto out; - } - - reqname = buf_getstring(ses.payload, &namelen); - wantreply = buf_getbyte(ses.payload); - - if (namelen > MAXNAMLEN) { - TRACE(("name len is wrong: %d", namelen)); - goto out; - } - - if (strcmp("tcpip-forward", reqname) == 0) { - ret = remotetcpreq(); - } else if (strcmp("cancel-tcpip-forward", reqname) == 0) { - ret = cancelremotetcp(); - } else { - TRACE(("reqname isn't tcpip-forward: '%s'", reqname)); - } - -out: - if (wantreply) { - if (ret == DROPBEAR_SUCCESS) { - send_msg_request_success(); - } else { - send_msg_request_failure(); - } - } - - m_free(reqname); - - TRACE(("leave recv_msg_global_request")); -} - -static void acceptremote(struct TCPListener *listener) { - - int fd; - struct sockaddr addr; - int len; - char ipstring[NI_MAXHOST], portstring[NI_MAXSERV]; - struct RemoteTCP *tcpinfo = (struct RemoteTCP*)(listener->typedata); - - len = sizeof(addr); - - fd = accept(listener->sock, &addr, &len); - if (fd < 0) { - return; - } - - if (getnameinfo(&addr, len, ipstring, sizeof(ipstring), portstring, - sizeof(portstring), NI_NUMERICHOST | NI_NUMERICSERV) != 0) { - return; - } - - /* XXX XXX XXX - type here needs fixing */ - if (send_msg_channel_open_init(fd, CHANNEL_ID_TCPFORWARDED, - "forwarded-tcpip") == DROPBEAR_SUCCESS) { - buf_putstring(ses.writepayload, tcpinfo->addr, - strlen(tcpinfo->addr)); - buf_putint(ses.writepayload, tcpinfo->port); - buf_putstring(ses.writepayload, ipstring, strlen(ipstring)); - buf_putint(ses.writepayload, atol(portstring)); - encrypt_packet(); - } -} - -static void cleanupremote(struct TCPListener *listener) { - - struct RemoteTCP *tcpinfo = (struct RemoteTCP*)(listener->typedata); - - m_free(tcpinfo->addr); - m_free(tcpinfo); -} - -static void send_msg_request_success() { - - CHECKCLEARTOWRITE(); - buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS); - encrypt_packet(); - -} - -static void send_msg_request_failure() { - - CHECKCLEARTOWRITE(); - buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE); - encrypt_packet(); - -} - -static int matchtcp(void* typedata1, void* typedata2) { - - const struct RemoteTCP *info1 = (struct RemoteTCP*)typedata1; - const struct RemoteTCP *info2 = (struct RemoteTCP*)typedata2; - - return info1->port == info2->port - && (strcmp(info1->addr, info2->addr) == 0); -} - -static int cancelremotetcp() { - - int ret = DROPBEAR_FAILURE; - unsigned char * bindaddr = NULL; - unsigned int addrlen; - unsigned int port; - struct TCPListener * listener = NULL; - struct RemoteTCP tcpinfo; - - TRACE(("enter cancelremotetcp")); - - bindaddr = buf_getstring(ses.payload, &addrlen); - if (addrlen > MAX_IP_LEN) { - TRACE(("addr len too long: %d", addrlen)); - goto out; - } - - port = buf_getint(ses.payload); - - tcpinfo.addr = bindaddr; - tcpinfo.port = port; - listener = get_listener(CHANNEL_ID_TCPFORWARDED, &tcpinfo, matchtcp); - if (listener) { - remove_listener( listener ); - ret = DROPBEAR_SUCCESS; - } - -out: - m_free(bindaddr); - TRACE(("leave cancelremotetcp")); - return ret; -} - -static int remotetcpreq() { - - int ret = DROPBEAR_FAILURE; - unsigned char * bindaddr = NULL; - unsigned int addrlen; - unsigned int port; - - TRACE(("enter remotetcpreq")); - - bindaddr = buf_getstring(ses.payload, &addrlen); - if (addrlen > MAX_IP_LEN) { - TRACE(("addr len too long: %d", addrlen)); - goto out; - } - - port = buf_getint(ses.payload); - - if (port == 0) { - dropbear_log(LOG_INFO, "Server chosen tcpfwd ports are unsupported"); - goto out; - } - - if (port < 1 || port > 65535) { - TRACE(("invalid port: %d", port)); - goto out; - } - - /* XXX matt - server change - if (ses.authstate.pw->pw_uid != 0 - && port < IPPORT_RESERVED) { - TRACE(("can't assign port < 1024 for non-root")); - goto out; - } - */ - - ret = newlistener(bindaddr, port); - -out: - if (ret == DROPBEAR_FAILURE) { - /* we only free it if a listener wasn't created, since the listener - * has to remember it if it's to be cancelled */ - m_free(bindaddr); - } - TRACE(("leave remotetcpreq")); - return ret; -} - -static int newlistener(unsigned char* bindaddr, unsigned int port) { - - struct RemoteTCP * tcpinfo = NULL; - char portstring[6]; /* "65535\0" */ - struct addrinfo *res = NULL, *ai = NULL; - struct addrinfo hints; - int sock = -1; - int ret = DROPBEAR_FAILURE; - - TRACE(("enter newlistener")); - - /* first we try to bind, so don't need to do so much cleanup on failure */ - snprintf(portstring, sizeof(portstring), "%d", port); - memset(&hints, 0x0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = PF_INET; - hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; - - if (getaddrinfo(bindaddr, portstring, &hints, &res) < 0) { - TRACE(("leave newlistener: getaddrinfo failed: %s", - strerror(errno))); - goto done; - } - - /* find the first one which works */ - for (ai = res; ai != NULL; ai = ai->ai_next) { - if (ai->ai_family != PF_INET && ai->ai_family != PF_INET6) { - continue; - } - - sock = socket(ai->ai_family, SOCK_STREAM, 0); - if (sock < 0) { - TRACE(("socket failed: %s", strerror(errno))); - goto fail; - } - - if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { - TRACE(("bind failed: %s", strerror(errno))); - goto fail; - } - - if (listen(sock, 20) < 0) { - TRACE(("listen failed: %s", strerror(errno))); - goto fail; - } - - if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { - TRACE(("fcntl nonblocking failed: %s", strerror(errno))); - goto fail; - } - - /* success */ - break; - -fail: - close(sock); - } - - - if (ai == NULL) { - TRACE(("no successful sockets")); - goto done; - } - - tcpinfo = (struct RemoteTCP*)m_malloc(sizeof(struct RemoteTCP)); - tcpinfo->addr = bindaddr; - tcpinfo->port = port; - - ret = new_fwd(sock, CHANNEL_ID_TCPFORWARDED, tcpinfo, - acceptremote, cleanupremote); - - if (ret == DROPBEAR_FAILURE) { - m_free(tcpinfo); - } - -done: - if (res) { - freeaddrinfo(res); - } - - TRACE(("leave newlistener")); - return ret; -} - -#endif /* DISABLE_REMOTETCPFWD */ diff -r 425ed5c20157 -r 7f77962de998 remotetcpfwd.h --- a/remotetcpfwd.h Wed Jun 02 04:59:49 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -#ifndef _REMOTETCPFWD_H -#define _REMOTETCPFWD_H - -void recv_msg_global_request_remotetcp(); - -#endif /* _REMOTETCPFWD_H */ diff -r 425ed5c20157 -r 7f77962de998 session.h --- a/session.h Wed Jun 02 04:59:49 2004 +0000 +++ b/session.h Thu Jun 03 16:45:53 2004 +0000 @@ -33,7 +33,7 @@ #include "channel.h" #include "queue.h" #include "runopts.h" -#include "remotetcpfwd.h" +#include "listener.h" extern int sessinitdone; /* Is set to 0 somewhere */ extern int exitflag; @@ -139,8 +139,8 @@ /* TCP forwarding - where manage listeners */ #ifndef DISABLE_REMOTETCPFWD - struct TCPListener ** tcplisteners; - unsigned int tcplistensize; + struct Listener ** listeners; + unsigned int listensize; #endif }; diff -r 425ed5c20157 -r 7f77962de998 svr-chansession.c --- a/svr-chansession.c Wed Jun 02 04:59:49 2004 +0000 +++ b/svr-chansession.c Thu Jun 03 16:45:53 2004 +0000 @@ -201,13 +201,13 @@ channel->typedata = chansess; #ifndef DISABLE_X11FWD - chansess->x11fd = -1; + chansess->x11listener = NULL; chansess->x11authprot = NULL; chansess->x11authcookie = NULL; #endif #ifndef DISABLE_AGENTFWD - chansess->agentfd = -1; + chansess->agentlistener = NULL; chansess->agentfile = NULL; chansess->agentdir = NULL; #endif @@ -881,7 +881,7 @@ /* only reached on error */ dropbear_exit("child failed"); } - + const struct ChanType svrchansess = { 0, /* sepfds */ "session", /* name */ diff -r 425ed5c20157 -r 7f77962de998 svr-session.c --- a/svr-session.c Wed Jun 02 04:59:49 2004 +0000 +++ b/svr-session.c Thu Jun 03 16:45:53 2004 +0000 @@ -35,7 +35,7 @@ #include "channel.h" #include "chansession.h" #include "atomicio.h" -#include "localtcpfwd.h" +#include "tcpfwd-direct.h" static void svr_remoteclosed(); diff -r 425ed5c20157 -r 7f77962de998 tcpfwd-direct.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tcpfwd-direct.c Thu Jun 03 16:45:53 2004 +0000 @@ -0,0 +1,154 @@ +#include "includes.h" +#include "session.h" +#include "dbutil.h" +#include "channel.h" +#include "tcpfwd-direct.h" + +#ifndef DISABLE_TCPFWD_DIRECT +static int newtcpdirect(struct Channel * channel); +static int newtcp(const char * host, int port); + +const struct ChanType chan_tcpdirect = { + 0, /* sepfds */ + "direct-tcpip", + newtcpdirect, /* init */ + NULL, /* checkclose */ + NULL, /* reqhandler */ + NULL /* closehandler */ +}; + + +/* Called upon creating a new direct tcp channel (ie we connect out to an + * address */ +static int newtcpdirect(struct Channel * channel) { + + unsigned char* desthost = NULL; + unsigned int destport; + unsigned char* orighost = NULL; + unsigned int origport; + int sock; + int len; + int ret = DROPBEAR_FAILURE; + + if (ses.opts->nolocaltcp) { + TRACE(("leave newtcpdirect: local tcp forwarding disabled")); + goto out; + } + + desthost = buf_getstring(ses.payload, &len); + if (len > MAX_HOST_LEN) { + TRACE(("leave newtcpdirect: desthost too long")); + goto out; + } + + destport = buf_getint(ses.payload); + + orighost = buf_getstring(ses.payload, &len); + if (len > MAX_HOST_LEN) { + TRACE(("leave newtcpdirect: orighost too long")); + goto out; + } + + origport = buf_getint(ses.payload); + + /* best be sure */ + if (origport > 65535 || destport > 65535) { + TRACE(("leave newtcpdirect: port > 65535")); + goto out; + } + + sock = newtcp(desthost, destport); + if (sock < 0) { + TRACE(("leave newtcpdirect: sock failed")); + goto out; + } + + ses.maxfd = MAX(ses.maxfd, sock); + + /* Note that infd is actually the "outgoing" direction on the + * tcp connection, vice versa for outfd. + * We don't set outfd, that will get set after the connection's + * progress succeeds */ + channel->infd = sock; + channel->initconn = 1; + + ret = DROPBEAR_SUCCESS; + +out: + m_free(desthost); + m_free(orighost); + TRACE(("leave newtcpdirect: ret %d", ret)); + return ret; +} + +/* Initiate a new TCP connection - this is non-blocking, so the socket + * returned will need to be checked for success when it is first written. + * Similarities with OpenSSH's connect_to() are not coincidental. + * Returns -1 on failure */ +static int newtcp(const char * host, int port) { + + int sock = -1; + char portstring[6]; + struct addrinfo *res = NULL, *ai; + int val; + + struct addrinfo hints; + + TRACE(("enter newtcp")); + + memset(&hints, 0, sizeof(hints)); + /* TCP, either ip4 or ip6 */ + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = PF_UNSPEC; + + snprintf(portstring, sizeof(portstring), "%d", port); + if (getaddrinfo(host, portstring, &hints, &res) != 0) { + if (res) { + freeaddrinfo(res); + } + TRACE(("leave newtcp: failed getaddrinfo")); + return -1; + } + + /* Use the first socket that works */ + for (ai = res; ai != NULL; ai = ai->ai_next) { + + if (ai->ai_family != PF_INET && ai->ai_family != PF_INET6) { + continue; + } + + sock = socket(ai->ai_family, SOCK_STREAM, 0); + if (sock < 0) { + TRACE(("TCP socket() failed")); + continue; + } + + if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { + close(sock); + TRACE(("TCP non-blocking failed")); + continue; + } + + /* non-blocking, so it might return without success (EINPROGRESS) */ + if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { + if (errno == EINPROGRESS) { + TRACE(("connect in progress")); + } else { + close(sock); + TRACE(("TCP connect failed")); + continue; + } + } + break; + } + + freeaddrinfo(res); + + if (ai == NULL) { + return -1; + } + + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val)); + return sock; +} +#endif /* DISABLE_TCPFWD_DIRECT */ diff -r 425ed5c20157 -r 7f77962de998 tcpfwd-direct.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tcpfwd-direct.h Thu Jun 03 16:45:53 2004 +0000 @@ -0,0 +1,34 @@ +/* + * 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. */ +#ifndef _TCPFWD_DIRECT_H_ +#define _TCPFWD_DIRECT_H_ +#ifndef DISABLE_TCFWD_DIRECT + +#include "includes.h" +#include "channel.h" + +extern const struct ChanType chan_tcpdirect; + +#endif +#endif diff -r 425ed5c20157 -r 7f77962de998 tcpfwd-remote.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tcpfwd-remote.c Thu Jun 03 16:45:53 2004 +0000 @@ -0,0 +1,319 @@ +#include "includes.h" +#include "ssh.h" +#include "tcpfwd-remote.h" +#include "dbutil.h" +#include "session.h" +#include "buffer.h" +#include "packet.h" +#include "listener.h" + +#ifndef DISABLE_REMOTETCPFWD + +struct RemoteTCP { + + unsigned char* addr; + unsigned int port; + +}; + +static void send_msg_request_success(); +static void send_msg_request_failure(); +static int cancelremotetcp(); +static int remotetcpreq(); +static int listen_tcpfwd(unsigned char* bindaddr, unsigned int port); +static void acceptremote(struct Listener *listener); + +/* At the moment this is completely used for tcp code (with the name reflecting + * that). If new request types are added, this should be replaced with code + * similar to the request-switching in chansession.c */ +void recv_msg_global_request_remotetcp() { + + unsigned char* reqname = NULL; + unsigned int namelen; + unsigned int wantreply = 0; + int ret = DROPBEAR_FAILURE; + + TRACE(("enter recv_msg_global_request_remotetcp")); + + if (ses.opts->noremotetcp) { + TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled")); + goto out; + } + + reqname = buf_getstring(ses.payload, &namelen); + wantreply = buf_getbyte(ses.payload); + + if (namelen > MAXNAMLEN) { + TRACE(("name len is wrong: %d", namelen)); + goto out; + } + + if (strcmp("tcpip-forward", reqname) == 0) { + ret = remotetcpreq(); + } else if (strcmp("cancel-tcpip-forward", reqname) == 0) { + ret = cancelremotetcp(); + } else { + TRACE(("reqname isn't tcpip-forward: '%s'", reqname)); + } + +out: + if (wantreply) { + if (ret == DROPBEAR_SUCCESS) { + send_msg_request_success(); + } else { + send_msg_request_failure(); + } + } + + m_free(reqname); + + TRACE(("leave recv_msg_global_request")); +} + +static const struct ChanType chan_tcpremote = { + 0, /* sepfds */ + "forwarded-tcpip", + NULL, + NULL, + NULL, + NULL +}; + + +static void acceptremote(struct Listener *listener) { + + int fd; + struct sockaddr addr; + int len; + char ipstring[NI_MAXHOST], portstring[NI_MAXSERV]; + struct RemoteTCP *tcpinfo = (struct RemoteTCP*)(listener->typedata); + + len = sizeof(addr); + + fd = accept(listener->sock, &addr, &len); + if (fd < 0) { + return; + } + + if (getnameinfo(&addr, len, ipstring, sizeof(ipstring), portstring, + sizeof(portstring), NI_NUMERICHOST | NI_NUMERICSERV) != 0) { + return; + } + + if (send_msg_channel_open_init(fd, &chan_tcpremote) == DROPBEAR_SUCCESS) { + + buf_putstring(ses.writepayload, tcpinfo->addr, + strlen(tcpinfo->addr)); + buf_putint(ses.writepayload, tcpinfo->port); + buf_putstring(ses.writepayload, ipstring, strlen(ipstring)); + buf_putint(ses.writepayload, atol(portstring)); + encrypt_packet(); + + } else { + /* XXX debug? */ + close(fd); + } +} + +static void cleanupremote(struct Listener *listener) { + + struct RemoteTCP *tcpinfo = (struct RemoteTCP*)(listener->typedata); + + m_free(tcpinfo->addr); + m_free(tcpinfo); +} + +static void send_msg_request_success() { + + CHECKCLEARTOWRITE(); + buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS); + encrypt_packet(); + +} + +static void send_msg_request_failure() { + + CHECKCLEARTOWRITE(); + buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE); + encrypt_packet(); + +} + +static int matchtcp(void* typedata1, void* typedata2) { + + const struct RemoteTCP *info1 = (struct RemoteTCP*)typedata1; + const struct RemoteTCP *info2 = (struct RemoteTCP*)typedata2; + + return info1->port == info2->port + && (strcmp(info1->addr, info2->addr) == 0); +} + +static int cancelremotetcp() { + + int ret = DROPBEAR_FAILURE; + unsigned char * bindaddr = NULL; + unsigned int addrlen; + unsigned int port; + struct Listener * listener = NULL; + struct RemoteTCP tcpinfo; + + TRACE(("enter cancelremotetcp")); + + bindaddr = buf_getstring(ses.payload, &addrlen); + if (addrlen > MAX_IP_LEN) { + TRACE(("addr len too long: %d", addrlen)); + goto out; + } + + port = buf_getint(ses.payload); + + tcpinfo.addr = bindaddr; + tcpinfo.port = port; + listener = get_listener(CHANNEL_ID_TCPFORWARDED, &tcpinfo, matchtcp); + if (listener) { + remove_listener( listener ); + ret = DROPBEAR_SUCCESS; + } + +out: + m_free(bindaddr); + TRACE(("leave cancelremotetcp")); + return ret; +} + +static int remotetcpreq() { + + int ret = DROPBEAR_FAILURE; + unsigned char * bindaddr = NULL; + unsigned int addrlen; + unsigned int port; + + TRACE(("enter remotetcpreq")); + + bindaddr = buf_getstring(ses.payload, &addrlen); + if (addrlen > MAX_IP_LEN) { + TRACE(("addr len too long: %d", addrlen)); + goto out; + } + + port = buf_getint(ses.payload); + + if (port == 0) { + dropbear_log(LOG_INFO, "Server chosen tcpfwd ports are unsupported"); + goto out; + } + + if (port < 1 || port > 65535) { + TRACE(("invalid port: %d", port)); + goto out; + } + + /* XXX matt - server change + if (ses.authstate.pw->pw_uid != 0 + && port < IPPORT_RESERVED) { + TRACE(("can't assign port < 1024 for non-root")); + goto out; + } + */ + + ret = listen_tcpfwd(bindaddr, port); + +out: + if (ret == DROPBEAR_FAILURE) { + /* we only free it if a listener wasn't created, since the listener + * has to remember it if it's to be cancelled */ + m_free(bindaddr); + } + TRACE(("leave remotetcpreq")); + return ret; +} + +static int listen_tcpfwd(unsigned char* bindaddr, unsigned int port) { + + struct RemoteTCP * tcpinfo = NULL; + char portstring[6]; /* "65535\0" */ + struct addrinfo *res = NULL, *ai = NULL; + struct addrinfo hints; + int sock = -1; + struct Listener *listener = NULL; + + TRACE(("enter listen_tcpfwd")); + + /* first we try to bind, so don't need to do so much cleanup on failure */ + snprintf(portstring, sizeof(portstring), "%d", port); + memset(&hints, 0x0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = PF_INET; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + + if (getaddrinfo(bindaddr, portstring, &hints, &res) < 0) { + TRACE(("leave listen_tcpfwd: getaddrinfo failed: %s", + strerror(errno))); + goto done; + } + + /* find the first one which works */ + for (ai = res; ai != NULL; ai = ai->ai_next) { + if (ai->ai_family != PF_INET && ai->ai_family != PF_INET6) { + continue; + } + + sock = socket(ai->ai_family, SOCK_STREAM, 0); + if (sock < 0) { + TRACE(("socket failed: %s", strerror(errno))); + goto fail; + } + + if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { + TRACE(("bind failed: %s", strerror(errno))); + goto fail; + } + + if (listen(sock, 20) < 0) { + TRACE(("listen failed: %s", strerror(errno))); + goto fail; + } + + if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { + TRACE(("fcntl nonblocking failed: %s", strerror(errno))); + goto fail; + } + + /* success */ + break; + +fail: + close(sock); + } + + + if (ai == NULL) { + TRACE(("no successful sockets")); + goto done; + } + + tcpinfo = (struct RemoteTCP*)m_malloc(sizeof(struct RemoteTCP)); + tcpinfo->addr = bindaddr; + tcpinfo->port = port; + + listener = new_listener(sock, CHANNEL_ID_TCPFORWARDED, tcpinfo, + acceptremote, cleanupremote); + + if (listener == NULL) { + m_free(tcpinfo); + } + +done: + if (res) { + freeaddrinfo(res); + } + + TRACE(("leave listen_tcpfwd")); + if (listener == NULL) { + return DROPBEAR_FAILURE; + } else { + return DROPBEAR_SUCCESS; + } +} + +#endif /* DISABLE_REMOTETCPFWD */ diff -r 425ed5c20157 -r 7f77962de998 tcpfwd-remote.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tcpfwd-remote.h Thu Jun 03 16:45:53 2004 +0000 @@ -0,0 +1,6 @@ +#ifndef _REMOTETCPFWD_H +#define _REMOTETCPFWD_H + +void recv_msg_global_request_remotetcp(); + +#endif /* _REMOTETCPFWD_H */ diff -r 425ed5c20157 -r 7f77962de998 tcpfwd.c --- a/tcpfwd.c Wed Jun 02 04:59:49 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -#include "includes.h" -#include "tcpfwd.h" -#include "session.h" -#include "dbutil.h" - -void tcp_fwd_initialise() { - - /* just one slot to start with */ - ses.tcplisteners = - (struct TCPListener**)m_malloc(sizeof(struct TCPListener*)); - ses.tcplistensize = 1; - ses.tcplisteners[0] = NULL; - -} - -void set_tcp_fwd_fds(fd_set * readfds) { - - unsigned int i; - struct TCPListener *listener; - - /* check each in turn */ - for (i = 0; i < ses.tcplistensize; i++) { - listener = ses.tcplisteners[i]; - if (listener != NULL) { - FD_SET(listener->sock, readfds); - } - } -} - - -void handle_tcp_fwd(fd_set * readfds) { - - unsigned int i; - struct TCPListener *listener; - - /* check each in turn */ - for (i = 0; i < ses.tcplistensize; i++) { - listener = ses.tcplisteners[i]; - if (listener != NULL) { - if (FD_ISSET(listener->sock, readfds)) { - listener->accepter(listener); - } - } - } -} - - -/* accepter(int fd, void* typedata) is a function to accept connections, - * cleanup(void* typedata) happens when cleaning up */ -int new_fwd(int sock, int type, void* typedata, - void (*accepter)(struct TCPListener*), - void (*cleanup)(struct TCPListener*)) { - - unsigned int i, j; - struct TCPListener *newtcp = NULL; - /* try get a new structure to hold it */ - for (i = 0; i < ses.tcplistensize; i++) { - if (ses.tcplisteners[i] == NULL) { - break; - } - } - - /* or create a new one */ - if (i == ses.tcplistensize) { - if (ses.tcplistensize > MAX_TCPLISTENERS) { - TRACE(("leave newlistener: too many already")); - close(sock); - return DROPBEAR_FAILURE; - } - - ses.tcplisteners = (struct TCPListener**)m_realloc(ses.tcplisteners, - (ses.tcplistensize+TCP_EXTEND_SIZE) - *sizeof(struct TCPListener*)); - - ses.tcplistensize += TCP_EXTEND_SIZE; - - for (j = i; j < ses.tcplistensize; j++) { - ses.tcplisteners[j] = NULL; - } - } - - ses.maxfd = MAX(ses.maxfd, sock); - - newtcp = (struct TCPListener*)m_malloc(sizeof(struct TCPListener)); - newtcp->index = i; - newtcp->type = type; - newtcp->typedata = typedata; - newtcp->sock = sock; - newtcp->accepter = accepter; - newtcp->cleanup = cleanup; - - ses.tcplisteners[i] = newtcp; - return DROPBEAR_SUCCESS; -} - -/* Return the first listener which matches the type-specific comparison - * function */ -struct TCPListener * get_listener(int type, void* typedata, - int (*match)(void*, void*)) { - - unsigned int i; - struct TCPListener* listener; - - for (i = 0, listener = ses.tcplisteners[i]; i < ses.tcplistensize; i++) { - if (listener->type == type - && match(typedata, listener->typedata)) { - return listener; - } - } - - return NULL; -} - -void remove_listener(struct TCPListener* listener) { - - if (listener->cleanup) { - listener->cleanup(listener); - } - - close(listener->sock); - ses.tcplisteners[listener->index] = NULL; - m_free(listener); - -} diff -r 425ed5c20157 -r 7f77962de998 tcpfwd.h --- a/tcpfwd.h Wed Jun 02 04:59:49 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -#ifndef _TCPFWD_H -#define _TCPFWD_H - -#define MAX_TCPLISTENERS 20 -#define TCP_EXTEND_SIZE 1 - -struct TCPListener { - - int sock; - - int index; /* index in the array of listeners */ - - void (*accepter)(struct TCPListener*); - void (*cleanup)(struct TCPListener*); - - int type; /* CHANNEL_ID_X11, CHANNEL_ID_AGENT, - CHANNEL_ID_TCPDIRECT (for clients), - CHANNEL_ID_TCPFORWARDED (for servers) */ - - void *typedata; - -}; - -void tcp_fwd_initialise(); -void handle_tcp_fwd(fd_set * readfds); -void set_tcp_fwd_fds(fd_set * readfds); - -int new_fwd(int sock, int type, void* typedata, - void (*accepter)(struct TCPListener*), - void (*cleanup)(struct TCPListener*)); - -struct TCPListener * get_listener(int type, void* typedata, - int (*match)(void*, void*)); - -void remove_listener(struct TCPListener* listener); - -#endif /* _TCPFWD_H */ diff -r 425ed5c20157 -r 7f77962de998 x11fwd.c --- a/x11fwd.c Wed Jun 02 04:59:49 2004 +0000 +++ b/x11fwd.c Thu Jun 03 16:45:53 2004 +0000 @@ -37,6 +37,8 @@ #define X11BASEPORT 6000 #define X11BINDBASE 6010 +static void x11accept(struct Listener* listener); +static void x11cleanup(struct Listener *listener); static int bindport(int fd); static int send_msg_channel_open_x11(int fd, struct sockaddr_in* addr); @@ -44,8 +46,10 @@ /* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ int x11req(struct ChanSess * chansess) { + int fd; + /* we already have an x11 connection */ - if (chansess->x11fd != -1) { + if (chansess->x11listener != NULL) { return DROPBEAR_FAILURE; } @@ -55,62 +59,71 @@ chansess->x11screennum = buf_getint(ses.payload); /* create listening socket */ - chansess->x11fd = socket(PF_INET, SOCK_STREAM, 0); - if (chansess->x11fd < 0) { + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { goto fail; } /* allocate port and bind */ - chansess->x11port = bindport(chansess->x11fd); + chansess->x11port = bindport(fd); if (chansess->x11port < 0) { goto fail; } /* listen */ - if (listen(chansess->x11fd, 20) < 0) { + if (listen(fd, 20) < 0) { goto fail; } /* set non-blocking */ - if (fcntl(chansess->x11fd, F_SETFL, O_NONBLOCK) < 0) { + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { goto fail; } - /* channel.c's channel fd code will handle the socket now */ - - /* set the maxfd so that select() loop will notice it */ - ses.maxfd = MAX(ses.maxfd, chansess->x11fd); + /* 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 */ - x11cleanup(chansess); + m_free(chansess->x11authprot); + m_free(chansess->x11authcookie); + close(fd); return DROPBEAR_FAILURE; } /* accepts a new X11 socket */ /* returns DROPBEAR_FAILURE or DROPBEAR_SUCCESS */ -int x11accept(struct ChanSess * chansess) { +static void x11accept(struct Listener* listener) { int fd; struct sockaddr_in addr; int len; + int ret; len = sizeof(addr); - fd = accept(chansess->x11fd, (struct sockaddr*)&addr, &len); + fd = accept(listener->sock, (struct sockaddr*)&addr, &len); if (fd < 0) { - return DROPBEAR_FAILURE; + return; } /* if single-connection we close it up */ - if (chansess->x11singleconn) { - x11cleanup(chansess); + if (((struct ChanSess *)(listener->typedata))->x11singleconn) { + x11cleanup(listener); } - return send_msg_channel_open_x11(fd, &addr); + 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 @@ -121,7 +134,7 @@ FILE * authprog; int val; - if (chansess->x11fd == -1) { + if (chansess->x11listener == NULL) { return; } @@ -154,24 +167,31 @@ } } -void x11cleanup(struct ChanSess * chansess) { +static void x11cleanup(struct Listener *listener) { - if (chansess->x11fd == -1) { - return; - } + struct ChanSess *chansess = (struct ChanSess*)listener->typedata; m_free(chansess->x11authprot); m_free(chansess->x11authcookie); - close(chansess->x11fd); - chansess->x11fd = -1; + 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, CHANNEL_ID_X11, "x11") - == DROPBEAR_SUCCESS) { + 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); diff -r 425ed5c20157 -r 7f77962de998 x11fwd.h --- a/x11fwd.h Wed Jun 02 04:59:49 2004 +0000 +++ b/x11fwd.h Thu Jun 03 16:45:53 2004 +0000 @@ -30,8 +30,6 @@ #include "channel.h" int x11req(struct ChanSess * chansess); -int x11accept(struct ChanSess * chansess); -void x11cleanup(struct ChanSess * chansess); void x11setauth(struct ChanSess *chansess); #endif /* DROPBEAR_X11FWD */