mirror of
https://github.com/clearml/dropbear
synced 2025-03-12 06:41:20 +00:00
- Reworked non-channel fd handling to listener.c
- More channel cleaning up --HG-- extra : convert_revision : 385ec76d0304b93e277d1cc193383db5fd773703
This commit is contained in:
parent
513f947d62
commit
444dbb5364
10
Makefile.in
10
Makefile.in
@ -4,9 +4,9 @@ LTM=libtommath/libtommath.a
|
||||
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 @@ HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \
|
||||
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)
|
||||
|
||||
|
@ -114,8 +114,7 @@ void recv_msg_channel_close();
|
||||
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
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include "loginrec.h"
|
||||
#include "channel.h"
|
||||
#include "listener.h"
|
||||
|
||||
struct ChanSess {
|
||||
|
||||
@ -47,7 +48,7 @@ struct ChanSess {
|
||||
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 @@ struct ChanSess {
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
int agentfd;
|
||||
struct Listener * agentlistener;
|
||||
char * agentfile;
|
||||
char * agentdir;
|
||||
#endif
|
||||
|
@ -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 @@ void chaninitialise(const struct ChanType *chantypes[]) {
|
||||
|
||||
ses.chantypes = chantypes;
|
||||
|
||||
#ifdef USING_TCP_LISTENERS
|
||||
tcp_fwd_initialise();
|
||||
#ifdef USING_LISTENERS
|
||||
listeners_initialise();
|
||||
#endif
|
||||
|
||||
}
|
||||
@ -219,9 +219,9 @@ void channelio(fd_set *readfd, fd_set *writefd) {
|
||||
|
||||
} /* 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 @@ void setchannelfds(fd_set *readfd, fd_set *writefd) {
|
||||
|
||||
} /* foreach channel */
|
||||
|
||||
#ifdef USING_TCP_LISTENERS
|
||||
set_tcp_fwd_fds(readfd);
|
||||
#ifdef USING_LISTENERS
|
||||
set_listener_fds(readfd);
|
||||
#endif
|
||||
|
||||
}
|
||||
@ -895,8 +895,7 @@ static void send_msg_channel_open_confirmation(struct Channel* channel,
|
||||
* 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 @@ int send_msg_channel_open_init(int fd, struct ChanType *type,
|
||||
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);
|
||||
|
123
listener.c
Normal file
123
listener.c
Normal file
@ -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);
|
||||
|
||||
}
|
37
listener.h
Normal file
37
listener.h
Normal file
@ -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 */
|
@ -296,7 +296,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_LOCALTCPFWD
|
||||
#define DISABLE_LOCALTCPFWD
|
||||
#define DISABLE_TCPDIRECT
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_REMOTETCPFWD
|
||||
|
@ -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 @@ struct sshsession {
|
||||
|
||||
/* TCP forwarding - where manage listeners */
|
||||
#ifndef DISABLE_REMOTETCPFWD
|
||||
struct TCPListener ** tcplisteners;
|
||||
unsigned int tcplistensize;
|
||||
struct Listener ** listeners;
|
||||
unsigned int listensize;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
@ -201,13 +201,13 @@ static int newchansess(struct Channel *channel) {
|
||||
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
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include "channel.h"
|
||||
#include "chansession.h"
|
||||
#include "atomicio.h"
|
||||
#include "localtcpfwd.h"
|
||||
#include "tcpfwd-direct.h"
|
||||
|
||||
static void svr_remoteclosed();
|
||||
|
||||
|
@ -2,9 +2,9 @@
|
||||
#include "session.h"
|
||||
#include "dbutil.h"
|
||||
#include "channel.h"
|
||||
#include "localtcpfwd.h"
|
||||
#include "tcpfwd-direct.h"
|
||||
|
||||
#ifndef DISABLE_LOCALTCPFWD
|
||||
#ifndef DISABLE_TCPFWD_DIRECT
|
||||
static int newtcpdirect(struct Channel * channel);
|
||||
static int newtcp(const char * host, int port);
|
||||
|
||||
@ -18,7 +18,6 @@ const struct ChanType chan_tcpdirect = {
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Called upon creating a new direct tcp channel (ie we connect out to an
|
||||
* address */
|
||||
static int newtcpdirect(struct Channel * channel) {
|
||||
@ -152,4 +151,4 @@ static int newtcp(const char * host, int port) {
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
|
||||
return sock;
|
||||
}
|
||||
#endif /* DISABLE_LOCALTCPFWD */
|
||||
#endif /* DISABLE_TCPFWD_DIRECT */
|
@ -21,9 +21,9 @@
|
||||
* 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
|
||||
#ifndef _TCPFWD_DIRECT_H_
|
||||
#define _TCPFWD_DIRECT_H_
|
||||
#ifndef DISABLE_TCFWD_DIRECT
|
||||
|
||||
#include "includes.h"
|
||||
#include "channel.h"
|
@ -1,11 +1,11 @@
|
||||
#include "includes.h"
|
||||
#include "ssh.h"
|
||||
#include "remotetcpfwd.h"
|
||||
#include "tcpfwd-remote.h"
|
||||
#include "dbutil.h"
|
||||
#include "session.h"
|
||||
#include "buffer.h"
|
||||
#include "packet.h"
|
||||
#include "tcpfwd.h"
|
||||
#include "listener.h"
|
||||
|
||||
#ifndef DISABLE_REMOTETCPFWD
|
||||
|
||||
@ -20,8 +20,8 @@ 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);
|
||||
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
|
||||
@ -70,7 +70,17 @@ out:
|
||||
TRACE(("leave recv_msg_global_request"));
|
||||
}
|
||||
|
||||
static void acceptremote(struct TCPListener *listener) {
|
||||
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;
|
||||
@ -90,19 +100,22 @@ static void acceptremote(struct TCPListener *listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* XXX XXX XXX - type here needs fixing */
|
||||
if (send_msg_channel_open_init(fd, CHANNEL_ID_TCPFORWARDED,
|
||||
"forwarded-tcpip") == DROPBEAR_SUCCESS) {
|
||||
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 TCPListener *listener) {
|
||||
static void cleanupremote(struct Listener *listener) {
|
||||
|
||||
struct RemoteTCP *tcpinfo = (struct RemoteTCP*)(listener->typedata);
|
||||
|
||||
@ -141,7 +154,7 @@ static int cancelremotetcp() {
|
||||
unsigned char * bindaddr = NULL;
|
||||
unsigned int addrlen;
|
||||
unsigned int port;
|
||||
struct TCPListener * listener = NULL;
|
||||
struct Listener * listener = NULL;
|
||||
struct RemoteTCP tcpinfo;
|
||||
|
||||
TRACE(("enter cancelremotetcp"));
|
||||
@ -203,7 +216,7 @@ static int remotetcpreq() {
|
||||
}
|
||||
*/
|
||||
|
||||
ret = newlistener(bindaddr, port);
|
||||
ret = listen_tcpfwd(bindaddr, port);
|
||||
|
||||
out:
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
@ -215,16 +228,16 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int newlistener(unsigned char* bindaddr, unsigned int port) {
|
||||
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;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
struct Listener *listener = NULL;
|
||||
|
||||
TRACE(("enter newlistener"));
|
||||
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);
|
||||
@ -234,7 +247,7 @@ static int newlistener(unsigned char* bindaddr, unsigned int port) {
|
||||
hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
|
||||
|
||||
if (getaddrinfo(bindaddr, portstring, &hints, &res) < 0) {
|
||||
TRACE(("leave newlistener: getaddrinfo failed: %s",
|
||||
TRACE(("leave listen_tcpfwd: getaddrinfo failed: %s",
|
||||
strerror(errno)));
|
||||
goto done;
|
||||
}
|
||||
@ -283,10 +296,10 @@ fail:
|
||||
tcpinfo->addr = bindaddr;
|
||||
tcpinfo->port = port;
|
||||
|
||||
ret = new_fwd(sock, CHANNEL_ID_TCPFORWARDED, tcpinfo,
|
||||
listener = new_listener(sock, CHANNEL_ID_TCPFORWARDED, tcpinfo,
|
||||
acceptremote, cleanupremote);
|
||||
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
if (listener == NULL) {
|
||||
m_free(tcpinfo);
|
||||
}
|
||||
|
||||
@ -295,8 +308,12 @@ done:
|
||||
freeaddrinfo(res);
|
||||
}
|
||||
|
||||
TRACE(("leave newlistener"));
|
||||
return ret;
|
||||
TRACE(("leave listen_tcpfwd"));
|
||||
if (listener == NULL) {
|
||||
return DROPBEAR_FAILURE;
|
||||
} else {
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DISABLE_REMOTETCPFWD */
|
124
tcpfwd.c
124
tcpfwd.c
@ -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);
|
||||
|
||||
}
|
37
tcpfwd.h
37
tcpfwd.h
@ -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 */
|
72
x11fwd.c
72
x11fwd.c
@ -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 @@ static int send_msg_channel_open_x11(int fd, struct sockaddr_in* addr);
|
||||
/* 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 @@ int x11req(struct ChanSess * chansess) {
|
||||
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 @@ void x11setauth(struct ChanSess *chansess) {
|
||||
FILE * authprog;
|
||||
int val;
|
||||
|
||||
if (chansess->x11fd == -1) {
|
||||
if (chansess->x11listener == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -154,24 +167,31 @@ void x11setauth(struct ChanSess *chansess) {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user