From 674a60748884dc55ee7091b7c23a41240e75f73c Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 1 Jun 2004 02:46:09 +0000 Subject: Makefile.in contains updated files required --HG-- extra : convert_revision : cc8a8c49dc70e632c352853a39801089b08149be --- Makefile.in | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 Makefile.in (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..10d3cc1 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,164 @@ +LTC=libtomcrypt/libtomcrypt.a +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 + +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 \ + svr-chansession.o svr-runopts.o svr-agentfwd.o + +CLIOBJS= + +OBJS=$(COMMONOBJS) $(SVROBJS) + +DROPBEAROBJS=main.o + +DROPBEARKEYOBJS=dropbearkey.o gendss.o genrsa.o + +CONVERTOBJS=dropbearconvert.o keyimport.o + +SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o + +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 + +ALLOBJS=$(OBJS) $(DROPBEARKEYOBJS) $(DROPBEAROBJS) + +prefix=@prefix@ +exec_prefix=${prefix} +bindir=${exec_prefix}/bin +sbindir=${exec_prefix}/sbin + +CC=@CC@ +LD=@CC@ +AR=@AR@ +RANLIB=@RANLIB@ +STRIP=@STRIP@ +INSTALL=@INSTALL@ +CFLAGS=-Ilibtomcrypt @CFLAGS@ +LIBS=$(LTC) $(LTM) @LIBS@ +LDFLAGS=@LDFLAGS@ + +# these are exported so that libtomcrypt's makefile will use them +export CC +export CFLAGS +export RANLIB AR STRIP + +all: dropbear dropbearkey dropbearconvert + @echo + @echo Run \"make strip\" if you want stripped binaries, + @echo or \"make install\" to install to ${prefix} + +strip: + -$(STRIP) dropbear + -$(STRIP) dropbearkey + -$(STRIP) dropbearconvert + +install: all + $(INSTALL) -d -m 755 $(DESTDIR)$(sbindir) + $(INSTALL) -d -m 755 $(DESTDIR)$(bindir) + $(INSTALL) -m 755 dropbear $(DESTDIR)$(sbindir) + $(INSTALL) -m 755 dropbearkey $(DESTDIR)$(bindir) + $(INSTALL) -m 755 dropbearconvert $(DESTDIR)$(bindir) + # chown might fail, so do it separately to the install + -chown root $(DESTDIR)$(sbindir)/dropbear + -chgrp 0 $(DESTDIR)$(sbindir)/dropbear + -chown root $(DESTDIR)$(bindir)/dropbearkey + -chgrp 0 $(DESTDIR)$(bindir)/dropbearkey + -chown root $(DESTDIR)$(bindir)/dropbearconvert + -chgrp 0 $(DESTDIR)$(bindir)/dropbearconvert + + +static: dropbear-static dropbearkey-static dropbearconvert-static + +$(ALLOBJS): $(HEADERS) Makefile + +dropbear: $(DROPBEAROBJS) $(OBJS) $(HEADERS) Makefile $(LTC) $(LTM) + $(LD) $(LDFLAGS) -o dropbear $(DROPBEAROBJS) $(OBJS) $(LIBS) + +dropbear-static: $(DROPBEAROBJS) $(OBJS) $(HEADERS) Makefile $(LTC) $(LTM) + $(LD) $(LDFLAGS) -o staticdropbear $(DROPBEAROBJS) $(OBJS) $(LIBS) -static + +dropbearkey: $(OBJS) $(HEADERS) Makefile $(DROPBEARKEYOBJS) $(LTC) $(LTM) + $(LD) $(LDFLAGS) -o dropbearkey $(DROPBEARKEYOBJS) \ + $(OBJS) $(LIBS) + +dropbearkey-static: $(OBJS) $(HEADERS) Makefile $(DROPBEARKEYOBJS) $(LTC) $(LTM) + $(LD) $(LDFLAGS) -o staticdropbearkey $(DROPBEARKEYOBJS) \ + $(OBJS) $(LIBS) -static + +dropbearconvert: $(OBJS) $(HEADERS) Makefile $(CONVERTOBJS) $(LTC) $(LTM) + $(LD) $(LDFLAGS) -o dropbearconvert $(CONVERTOBJS) $(OBJS) $(LIBS) + +dropbearconvert-static: $(OBJS) $(HEADERS) Makefile $(CONVERTOBJS) $(LTC) $(LTM) + $(LD) $(LDFLAGS) -o staticdropbearconvert $(CONVERTOBJS) $(OBJS) $(LIBS) \ + -static + +multi: dropbearmulti + +dropbearmulti: $(HEADERS) $(OBJS) $(LTC) $(LTM) $(CONVERTOBJS) \ + $(DROPBEARKEYOBJS) $(DROPBEAROBJS) dbmulti.o + $(LD) $(LDFLAGS) -o dropbearmulti $(OBJS) $(LTM) $(LTM) $(CONVERTOBJS) \ + $(DROPBEARKEYOBJS) $(DROPBEAROBJS) dbmulti.o $(LIBS) + @echo "You should now create symlinks to the programs you have included" + @echo "ie 'ln -s dropbearmulti dropbear'" + +dropbearmultistatic: $(HEADERS) $(OBJS) $(LTC) $(LTM) $(CONVERTOBJS) \ + $(DROPBEARKEYOBJS) $(DROPBEAROBJS) dbmulti.o + $(LD) $(LDFLAGS) -o staticdropbearmulti $(OBJS) $(LTM) $(LTM) \ + $(CONVERTOBJS) $(DROPBEARKEYOBJS) $(DROPBEAROBJS) \ + dbmulti.o $(LIBS) -static + @echo "You should now create symlinks to the programs you have included" + @echo "ie 'ln -s dropbearmultistatic dropbear'" + +stripmulti: dropbearmulti + -$(STRIP) dropbearmulti + + +scp: $(SCPOBJS) Makefile + $(LD) $(LDFLAGS) -o $@ $(SCPOBJS) + +# gnumake before 3.80 is broken. So this is uglyish +scp-progress: atomicio.o scpmisc.o $(HEADERS) Makefile + -rm scp.o progressmeter.o + $(MAKE) CFLAGS="$(CFLAGS) -DPROGRESS_METER" scp.o progressmeter.o + $(LD) $(LDFLAGS) -o $@ $(SCPOBJS) + +scpstatic: $(SCPOBJS) $(HEADERS) Makefile + $(LD) $(LDFLAGS) -o $@ $(SCPOBJS) -static + +$(LTC): $(HEADERS) + cd libtomcrypt && $(MAKE) clean && $(MAKE) + +$(LTM): $(HEADERS) + cd libtommath && $(MAKE) + +ltc-clean: + cd libtomcrypt && $(MAKE) clean + +ltm-clean: + cd libtommath && $(MAKE) clean + +sizes: dropbear + objdump -t dropbear|grep ".text"|cut -d "." -f 2|sort -rn + +clean: ltc-clean ltm-clean + -rm -f dropbear dropbear dropbearkey staticdropbear staticdropbearkey + -rm -f dropbearconvert staticdropbearconvert scp scp-progress scpstatic + -rm -f dropbearmulti dropbearmultistatic + -rm -f *.o *.da *.bb *.bbg *.prof + +distclean: clean tidy + -rm -f Makefile config.h + +tidy: + -rm -f *~ *.gcov */*~ -- cgit v1.2.3 From 444dbb5364798925a3cacddba7b1bb3041e41a23 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 3 Jun 2004 16:45:53 +0000 Subject: - Reworked non-channel fd handling to listener.c - More channel cleaning up --HG-- extra : convert_revision : 385ec76d0304b93e277d1cc193383db5fd773703 --- Makefile.in | 10 +- channel.h | 3 +- chansession.h | 5 +- common-channel.c | 25 ++--- listener.c | 123 +++++++++++++++++++++ listener.h | 37 +++++++ localtcpfwd.c | 155 -------------------------- localtcpfwd.h | 34 ------ options.h | 2 +- remotetcpfwd.c | 302 --------------------------------------------------- remotetcpfwd.h | 6 - session.h | 6 +- svr-chansession.c | 6 +- svr-session.c | 2 +- tcpfwd-direct.c | 154 ++++++++++++++++++++++++++ tcpfwd-direct.h | 34 ++++++ tcpfwd-remote.c | 319 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ tcpfwd-remote.h | 6 + tcpfwd.c | 124 --------------------- tcpfwd.h | 37 ------- x11fwd.c | 72 +++++++----- x11fwd.h | 2 - 22 files changed, 748 insertions(+), 716 deletions(-) create mode 100644 listener.c create mode 100644 listener.h delete mode 100644 localtcpfwd.c delete mode 100644 localtcpfwd.h delete mode 100644 remotetcpfwd.c delete mode 100644 remotetcpfwd.h create mode 100644 tcpfwd-direct.c create mode 100644 tcpfwd-direct.h create mode 100644 tcpfwd-remote.c create mode 100644 tcpfwd-remote.h delete mode 100644 tcpfwd.c delete mode 100644 tcpfwd.h (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 10d3cc1..cc3127a 100644 --- a/Makefile.in +++ b/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) diff --git a/channel.h b/channel.h index e033164..b77a660 100644 --- a/channel.h +++ b/channel.h @@ -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 diff --git a/chansession.h b/chansession.h index 85dc9c1..7879791 100644 --- a/chansession.h +++ b/chansession.h @@ -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 diff --git a/common-channel.c b/common-channel.c index 4643fc2..63ed275 100644 --- a/common-channel.c +++ b/common-channel.c @@ -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); diff --git a/listener.c b/listener.c new file mode 100644 index 0000000..df66629 --- /dev/null +++ b/listener.c @@ -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 --git a/listener.h b/listener.h new file mode 100644 index 0000000..ab77351 --- /dev/null +++ b/listener.h @@ -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 --git a/localtcpfwd.c b/localtcpfwd.c deleted file mode 100644 index bf89fa0..0000000 --- a/localtcpfwd.c +++ /dev/null @@ -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 --git a/localtcpfwd.h b/localtcpfwd.h deleted file mode 100644 index 65efa6e..0000000 --- a/localtcpfwd.h +++ /dev/null @@ -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 --git a/options.h b/options.h index d1f1794..703fec0 100644 --- a/options.h +++ b/options.h @@ -296,7 +296,7 @@ #endif #ifndef ENABLE_LOCALTCPFWD -#define DISABLE_LOCALTCPFWD +#define DISABLE_TCPDIRECT #endif #ifndef ENABLE_REMOTETCPFWD diff --git a/remotetcpfwd.c b/remotetcpfwd.c deleted file mode 100644 index 40a3a82..0000000 --- a/remotetcpfwd.c +++ /dev/null @@ -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 --git a/remotetcpfwd.h b/remotetcpfwd.h deleted file mode 100644 index 64dbed3..0000000 --- a/remotetcpfwd.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _REMOTETCPFWD_H -#define _REMOTETCPFWD_H - -void recv_msg_global_request_remotetcp(); - -#endif /* _REMOTETCPFWD_H */ diff --git a/session.h b/session.h index e372232..0cb2eaa 100644 --- a/session.h +++ b/session.h @@ -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 }; diff --git a/svr-chansession.c b/svr-chansession.c index f5b4308..4dd4228 100644 --- a/svr-chansession.c +++ b/svr-chansession.c @@ -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 @@ -881,7 +881,7 @@ static void execchild(struct ChanSess *chansess) { /* only reached on error */ dropbear_exit("child failed"); } - + const struct ChanType svrchansess = { 0, /* sepfds */ "session", /* name */ diff --git a/svr-session.c b/svr-session.c index 8e8eaea..2a97f94 100644 --- a/svr-session.c +++ b/svr-session.c @@ -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 --git a/tcpfwd-direct.c b/tcpfwd-direct.c new file mode 100644 index 0000000..81cd415 --- /dev/null +++ b/tcpfwd-direct.c @@ -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 --git a/tcpfwd-direct.h b/tcpfwd-direct.h new file mode 100644 index 0000000..20cd278 --- /dev/null +++ b/tcpfwd-direct.h @@ -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 --git a/tcpfwd-remote.c b/tcpfwd-remote.c new file mode 100644 index 0000000..9996dbd --- /dev/null +++ b/tcpfwd-remote.c @@ -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 --git a/tcpfwd-remote.h b/tcpfwd-remote.h new file mode 100644 index 0000000..64dbed3 --- /dev/null +++ b/tcpfwd-remote.h @@ -0,0 +1,6 @@ +#ifndef _REMOTETCPFWD_H +#define _REMOTETCPFWD_H + +void recv_msg_global_request_remotetcp(); + +#endif /* _REMOTETCPFWD_H */ diff --git a/tcpfwd.c b/tcpfwd.c deleted file mode 100644 index d95970a..0000000 --- a/tcpfwd.c +++ /dev/null @@ -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 --git a/tcpfwd.h b/tcpfwd.h deleted file mode 100644 index 85d7373..0000000 --- a/tcpfwd.h +++ /dev/null @@ -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 --git a/x11fwd.c b/x11fwd.c index 229b0df..e1b6961 100644 --- a/x11fwd.c +++ b/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); diff --git a/x11fwd.h b/x11fwd.h index 889033f..6cf4b96 100644 --- a/x11fwd.h +++ b/x11fwd.h @@ -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 */ -- cgit v1.2.3 From 790726519e69f5d93b579a21951d78f8f777a5cb Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 3 Jun 2004 17:15:02 +0000 Subject: - renaming x11fwd.c to svr-x11fwd.c, to testing monotone --HG-- extra : convert_revision : b5f7a97c08fd454f31a546a9ac9d3a4a5768a2ac --- Makefile.in | 2 +- svr-x11fwd.c | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ x11fwd.c | 236 ----------------------------------------------------------- 3 files changed, 237 insertions(+), 237 deletions(-) create mode 100644 svr-x11fwd.c delete mode 100644 x11fwd.c (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index cc3127a..8ad1677 100644 --- a/Makefile.in +++ b/Makefile.in @@ -5,7 +5,7 @@ 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 \ - 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 --git a/svr-x11fwd.c b/svr-x11fwd.c new file mode 100644 index 0000000..e1b6961 --- /dev/null +++ b/svr-x11fwd.c @@ -0,0 +1,236 @@ +/* + * 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 void x11cleanup(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); + } +} + +static 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 --git a/x11fwd.c b/x11fwd.c deleted file mode 100644 index e1b6961..0000000 --- a/x11fwd.c +++ /dev/null @@ -1,236 +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 void x11cleanup(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); - } -} - -static 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 */ -- cgit v1.2.3 From 9c676d0ddd4f5cc5ff271653fc1d8acf92c0d69f Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 23 Jun 2004 07:24:22 +0000 Subject: Makefile.in --HG-- extra : convert_revision : 95173a527ef15143d4cbb8c574dff59076120f68 --- Makefile.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 8ad1677..67e5e5f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -6,9 +6,9 @@ COMMONOBJS=dbutil.o common-session.o common-packet.o common-algo.o buffer.o \ signkey.o rsa.o random.o common-channel.o \ common-chansession.o queue.o termcodes.o \ loginrec.o atomicio.o svr-x11fwd.o tcpfwd-direct.o compat.o \ - tcpfwd-remote.o listener.o + tcpfwd-remote.o listener.o process-packet.o -SVROBJS=svr-kex.o svr-packet.o svr-algo.o svr-auth.o sshpty.o \ +SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ svr-authpasswd.o svr-authpubkey.o svr-session.o svr-service.o \ svr-chansession.o svr-runopts.o svr-agentfwd.o @@ -26,7 +26,7 @@ SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o 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 \ + debug.h channel.h chansession.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 tcpfwd-direct.h compat.h \ tcpfwd-remote.h listener.h -- cgit v1.2.3 From 62aab2227c2e1aca8e9b807bc203a1d6ecb14daf Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 20 Jul 2004 12:05:00 +0000 Subject: switching to global vars --HG-- extra : convert_revision : 800073097767c2ac153ab834cbcf0121cb765118 --- Makefile.in | 2 +- TODO | 2 + common-session.c | 11 ++---- dbutil.h | 1 - main.c | 27 ++++++------- runopts.h | 33 ++++++++++++---- session.h | 8 +--- svr-auth.c | 21 +++++----- svr-chansession.c | 7 ++-- svr-kex.c | 7 ++-- svr-runopts.c | 115 +++++++++++++++++++++++------------------------------- svr-session.c | 12 +++--- tcpfwd-direct.c | 3 +- tcpfwd-remote.c | 3 +- 14 files changed, 125 insertions(+), 127 deletions(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 67e5e5f..4d6d342 100644 --- a/Makefile.in +++ b/Makefile.in @@ -6,7 +6,7 @@ COMMONOBJS=dbutil.o common-session.o common-packet.o common-algo.o buffer.o \ signkey.o rsa.o random.o common-channel.o \ common-chansession.o queue.o termcodes.o \ loginrec.o atomicio.o svr-x11fwd.o tcpfwd-direct.o compat.o \ - tcpfwd-remote.o listener.o process-packet.o + tcpfwd-remote.o listener.o process-packet.o common-runopts.o SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ svr-authpasswd.o svr-authpubkey.o svr-session.o svr-service.o \ diff --git a/TODO b/TODO index 64cbd5e..8a567c2 100644 --- a/TODO +++ b/TODO @@ -24,4 +24,6 @@ Things which need doing: - CTR mode, SSH_MSG_IGNORE sending to improve CBC security - DH Group Exchange possibly +- Use m_burn for clearing sensitive items in LTM/LTC + - fix scp.c for IRIX diff --git a/common-session.c b/common-session.c index b7793f9..6e37e29 100644 --- a/common-session.c +++ b/common-session.c @@ -35,14 +35,14 @@ #include "channel.h" #include "atomicio.h" -struct sshsession ses; +struct sshsession ses; /* GLOBAL */ /* need to know if the session struct has been initialised, this way isn't the * cleanest, but works OK */ -int sessinitdone = 0; +int sessinitdone = 0; /* GLOBAL */ /* this is set when we get SIGINT or SIGTERM, the handler is in main.c */ -int exitflag = 0; +int exitflag = 0; /* GLOBAL */ static int ident_readln(int fd, char* buf, int count); @@ -51,7 +51,7 @@ void(*session_remoteclosed)() = NULL; /* called only at the start of a session, set up initial state */ -void common_session_init(int sock, runopts *opts) { +void common_session_init(int sock) { TRACE(("enter session_init")); @@ -61,8 +61,6 @@ void common_session_init(int sock, runopts *opts) { ses.sock = sock; ses.maxfd = sock; - ses.opts = opts; - ses.connecttimeout = 0; kexinitialise(); /* initialise the kex state */ @@ -128,7 +126,6 @@ void common_session_cleanup() { } m_free(ses.session_id); - freerunopts(ses.opts); m_burn(ses.keys, sizeof(struct key_context)); m_free(ses.keys); diff --git a/dbutil.h b/dbutil.h index 3888452..3da6b2f 100644 --- a/dbutil.h +++ b/dbutil.h @@ -32,7 +32,6 @@ #ifndef DISABLE_SYSLOG void startsyslog(); #endif -extern int usingsyslog; extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param); extern void (*_dropbear_log)(int priority, const char* format, va_list param); diff --git a/main.c b/main.c index 0087895..b9ff7aa 100644 --- a/main.c +++ b/main.c @@ -29,7 +29,7 @@ #include "signkey.h" #include "runopts.h" -static int listensockets(int *sock, runopts * opts, int *maxfd); +static int listensockets(int *sock, int *maxfd); static void sigchld_handler(int dummy); static void sigsegv_handler(int); static void sigintterm_handler(int fish); @@ -53,7 +53,6 @@ int main(int argc, char ** argv) int remoteaddrlen; int listensocks[MAX_LISTEN_ADDR]; unsigned int listensockcount = 0; - runopts * opts; FILE * pidfile; int childsock; @@ -66,13 +65,13 @@ int main(int argc, char ** argv) _dropbear_log = svr_dropbear_log; /* get commandline options */ - opts = svr_getopts(argc, argv); + svr_getopts(argc, argv); /* fork */ - if (opts->forkbg) { + if (svr_opts.forkbg) { int closefds = 0; #ifndef DEBUG_TRACE - if (!usingsyslog) { + if (!svr_opts.usingsyslog) { closefds = 1; } #endif @@ -83,13 +82,13 @@ int main(int argc, char ** argv) } #ifndef DISABLE_SYSLOG - if (usingsyslog) { + if (svr_opts.usingsyslog) { startsyslog(); } #endif /* should be done after syslog is working */ - if (opts->forkbg) { + if (svr_opts.forkbg) { dropbear_log(LOG_INFO, "Running in background"); } else { dropbear_log(LOG_INFO, "Not forking"); @@ -128,7 +127,7 @@ int main(int argc, char ** argv) /* Set up the listening sockets */ /* XXX XXX ports */ - listensockcount = listensockets(listensocks, opts, &maxsock); + listensockcount = listensockets(listensocks, &maxsock); /* incoming connection select loop */ for(;;) { @@ -242,7 +241,7 @@ int main(int argc, char ** argv) dropbear_exit("Couldn't close socket"); } /* start the session */ - svr_session(childsock, opts, childpipe[1], &remoteaddr); + svr_session(childsock, childpipe[1], &remoteaddr); /* don't return */ assert(0); } @@ -288,7 +287,7 @@ static void sigintterm_handler(int fish) { } /* Set up listening sockets for all the requested ports */ -static int listensockets(int *sock, runopts * opts, int *maxfd) { +static int listensockets(int *sock, int *maxfd) { int listensock; /* listening fd */ struct sockaddr_in listen_addr; @@ -296,7 +295,7 @@ static int listensockets(int *sock, runopts * opts, int *maxfd) { unsigned int i; int val; - for (i = 0; i < opts->portcount; i++) { + for (i = 0; i < svr_opts.portcount; i++) { /* iterate through all the sockets to listen on */ listensock = socket(PF_INET, SOCK_STREAM, 0); @@ -319,13 +318,13 @@ static int listensockets(int *sock, runopts * opts, int *maxfd) { memset((void*)&listen_addr, 0x0, sizeof(listen_addr)); listen_addr.sin_family = AF_INET; - listen_addr.sin_port = htons(opts->ports[i]); + listen_addr.sin_port = htons(svr_opts.ports[i]); listen_addr.sin_addr.s_addr = htonl(INADDR_ANY); memset(&(listen_addr.sin_zero), '\0', 8); if (bind(listensock, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) < 0) { - dropbear_exit("Bind failed port %d", opts->ports[i]); + dropbear_exit("Bind failed port %d", svr_opts.ports[i]); } /* listen */ @@ -342,5 +341,5 @@ static int listensockets(int *sock, runopts * opts, int *maxfd) { *maxfd = MAX(listensock, *maxfd); } - return opts->portcount; + return svr_opts.portcount; } diff --git a/runopts.h b/runopts.h index cdf3af9..1bf1539 100644 --- a/runopts.h +++ b/runopts.h @@ -29,12 +29,23 @@ #include "signkey.h" #include "buffer.h" -struct SvrRunOpts { +typedef struct runopts { + + int nolocaltcp; + int noremotetcp; + +} runopts; + +extern runopts opts; + +typedef struct svr_runopts { char * rsakeyfile; char * dsskeyfile; char * bannerfile; + int forkbg; + int usingsyslog; /* ports is an array of the portcount listening ports */ uint16_t *ports; @@ -56,17 +67,23 @@ struct SvrRunOpts { int noauthpass; int norootpass; - int nolocaltcp; - int noremotetcp; - sign_key *hostkey; buffer * banner; -}; +} svr_runopts; + +extern svr_runopts svr_opts; + +void svr_getopts(int argc, char ** argv); + +/* Uncompleted XXX matt */ +typedef struct cli_runopts { + + int todo; -typedef struct SvrRunOpts runopts; +} cli_runopts; -runopts * getrunopts(int argc, char ** argv); -void freerunopts(runopts* opts); +extern cli_runopts cli_opts; +void cli_getopts(int argc, char ** argv); #endif /* _RUNOPTS_H_ */ diff --git a/session.h b/session.h index 1106144..cc8340d 100644 --- a/session.h +++ b/session.h @@ -32,14 +32,13 @@ #include "auth.h" #include "channel.h" #include "queue.h" -#include "runopts.h" #include "listener.h" #include "packet.h" extern int sessinitdone; /* Is set to 0 somewhere */ extern int exitflag; -void common_session_init(int sock, runopts *opts); +void common_session_init(int sock); void common_session_cleanup(); void checktimeouts(); void session_identification(); @@ -47,8 +46,7 @@ void session_identification(); extern void(*session_remoteclosed)(); /* Server */ -void svr_session(int sock, runopts *opts, int childpipe, - struct sockaddr *remoteaddr); +void svr_session(int sock, int childpipe, struct sockaddr *remoteaddr); void svr_dropbear_exit(int exitcode, const char* format, va_list param); void svr_dropbear_log(int priority, const char* format, va_list param); @@ -82,8 +80,6 @@ struct sshsession { /* Is it a client or server? */ unsigned char isserver; - runopts * opts; /* runtime options, incl hostkey, banner etc */ - long connecttimeout; /* time to disconnect if we have a timeout (for userauth etc), or 0 for no timeout */ diff --git a/svr-auth.c b/svr-auth.c index 386c3e1..7b588c0 100644 --- a/svr-auth.c +++ b/svr-auth.c @@ -34,6 +34,7 @@ #include "auth.h" #include "authpasswd.h" #include "authpubkey.h" +#include "runopts.h" static void authclear(); static int checkusername(unsigned char *username, unsigned int userlen); @@ -61,7 +62,7 @@ static void authclear() { svr_ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; #endif #ifdef DROPBEAR_PASSWORD_AUTH - if (!ses.opts->noauthpass) { + if (svr_opts.noauthpass) { svr_ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; } #endif @@ -73,7 +74,7 @@ static void authclear() { static void send_msg_userauth_banner() { TRACE(("enter send_msg_userauth_banner")); - if (ses.opts->banner == NULL) { + if (svr_opts.banner == NULL) { TRACE(("leave send_msg_userauth_banner: banner is NULL")); return; } @@ -81,13 +82,13 @@ static void send_msg_userauth_banner() { CHECKCLEARTOWRITE(); buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_BANNER); - buf_putstring(ses.writepayload, buf_getptr(ses.opts->banner, - ses.opts->banner->len), ses.opts->banner->len); + buf_putstring(ses.writepayload, buf_getptr(svr_opts.banner, + svr_opts.banner->len), svr_opts.banner->len); buf_putstring(ses.writepayload, "en", 2); encrypt_packet(); - buf_free(ses.opts->banner); - ses.opts->banner = NULL; + buf_free(svr_opts.banner); + svr_opts.banner = NULL; TRACE(("leave send_msg_userauth_banner")); } @@ -107,7 +108,7 @@ void recv_msg_userauth_request() { } /* send the banner if it exists, it will only exist once */ - if (ses.opts->banner) { + if (svr_opts.banner) { send_msg_userauth_banner(); } @@ -145,8 +146,8 @@ void recv_msg_userauth_request() { } #ifdef DROPBEAR_PASSWORD_AUTH - if (!ses.opts->noauthpass && - !(ses.opts->norootpass && svr_ses.authstate.pw->pw_uid == 0) ) { + if (!svr_opts.noauthpass && + !(svr_opts.norootpass && svr_ses.authstate.pw->pw_uid == 0) ) { /* user wants to try password auth */ if (methodlen == AUTH_METHOD_PASSWORD_LEN && strncmp(methodname, AUTH_METHOD_PASSWORD, @@ -217,7 +218,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) { svr_ses.authstate.printableuser = m_strdup(svr_ses.authstate.pw->pw_name); /* check for non-root if desired */ - if (ses.opts->norootlogin && svr_ses.authstate.pw->pw_uid == 0) { + if (svr_opts.norootlogin && svr_ses.authstate.pw->pw_uid == 0) { TRACE(("leave checkusername: root login disabled")); dropbear_log(LOG_WARNING, "root login rejected"); send_msg_userauth_failure(0, 1); diff --git a/svr-chansession.c b/svr-chansession.c index c6526dc..cbc7ebe 100644 --- a/svr-chansession.c +++ b/svr-chansession.c @@ -36,6 +36,7 @@ #include "utmp.h" #include "x11fwd.h" #include "agentfwd.h" +#include "runopts.h" /* Handles sessions (either shells or programs) requested by the client */ @@ -690,7 +691,7 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) { m_free(chansess->tty); #ifdef DO_MOTD - if (ses.opts->domotd) { + if (svr_opts.domotd) { /* don't show the motd if ~/.hushlogin exists */ /* 11 == strlen("/hushlogin\0") */ @@ -776,8 +777,8 @@ static void execchild(struct ChanSess *chansess) { unsigned int i; /* wipe the hostkey */ - sign_key_free(ses.opts->hostkey); - ses.opts->hostkey = NULL; + sign_key_free(svr_opts.hostkey); + svr_opts.hostkey = NULL; /* overwrite the prng state */ seedrandom(); diff --git a/svr-kex.c b/svr-kex.c index 80f7c0a..4dfa6a7 100644 --- a/svr-kex.c +++ b/svr-kex.c @@ -32,6 +32,7 @@ #include "packet.h" #include "bignum.h" #include "random.h" +#include "runopts.h" static void send_msg_kexdh_reply(mp_int *dh_e); @@ -125,7 +126,7 @@ static void send_msg_kexdh_reply(mp_int *dh_e) { /* Create the remainder of the hash buffer, to generate the exchange hash */ /* K_S, the host key */ - buf_put_pub_key(ses.kexhashbuf, ses.opts->hostkey, + buf_put_pub_key(ses.kexhashbuf, svr_opts.hostkey, ses.newkeys->algo_hostkey); /* e, exchange value sent by the client */ buf_putmpint(ses.kexhashbuf, dh_e); @@ -153,7 +154,7 @@ static void send_msg_kexdh_reply(mp_int *dh_e) { /* we can start creating the kexdh_reply packet */ CHECKCLEARTOWRITE(); buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_REPLY); - buf_put_pub_key(ses.writepayload, ses.opts->hostkey, + buf_put_pub_key(ses.writepayload, svr_opts.hostkey, ses.newkeys->algo_hostkey); /* put f */ @@ -161,7 +162,7 @@ static void send_msg_kexdh_reply(mp_int *dh_e) { mp_clear(&dh_f); /* calc the signature */ - buf_put_sign(ses.writepayload, ses.opts->hostkey, + buf_put_sign(ses.writepayload, svr_opts.hostkey, ses.newkeys->algo_hostkey, ses.hash, SHA1_HASH_SIZE); /* the SSH_MSG_KEXDH_REPLY is done */ diff --git a/svr-runopts.c b/svr-runopts.c index f7a427f..1f5b0c6 100644 --- a/svr-runopts.c +++ b/svr-runopts.c @@ -29,6 +29,8 @@ #include "dbutil.h" #include "algo.h" +svr_runopts svr_opts; /* GLOBAL */ + static sign_key * loadhostkeys(const char * dsskeyfile, const char * rsakeyfile); static int readhostkey(const char * filename, sign_key * hostkey, int type); @@ -84,38 +86,34 @@ static void printhelp(const char * progname) { DROPBEAR_MAX_PORTS, DROPBEAR_PORT); } -/* returns NULL on failure, or a pointer to a freshly allocated - * runopts structure */ -runopts * svr_getopts(int argc, char ** argv) { +void svr_getopts(int argc, char ** argv) { unsigned int i; char ** next = 0; - runopts * opts; unsigned int portnum = 0; char *portstring[DROPBEAR_MAX_PORTS]; unsigned int longport; /* see printhelp() for options */ - opts = (runopts*)m_malloc(sizeof(runopts)); - opts->rsakeyfile = NULL; - opts->dsskeyfile = NULL; - opts->bannerfile = NULL; - opts->banner = NULL; - opts->forkbg = 1; - opts->norootlogin = 0; - opts->noauthpass = 0; - opts->norootpass = 0; - opts->nolocaltcp = 0; - opts->noremotetcp = 0; + svr_opts.rsakeyfile = NULL; + svr_opts.dsskeyfile = NULL; + svr_opts.bannerfile = NULL; + svr_opts.banner = NULL; + svr_opts.forkbg = 1; + svr_opts.norootlogin = 0; + svr_opts.noauthpass = 0; + svr_opts.norootpass = 0; + opts.nolocaltcp = 0; + opts.noremotetcp = 0; /* not yet - opts->ipv4 = 1; - opts->ipv6 = 1; + svr_opts.ipv4 = 1; + svr_opts.ipv6 = 1; */ #ifdef DO_MOTD - opts->domotd = 1; + svr_opts.domotd = 1; #endif #ifndef DISABLE_SYSLOG - usingsyslog = 1; + svr_opts.usingsyslog = 1; #endif for (i = 1; i < (unsigned int)argc; i++) { @@ -131,34 +129,34 @@ runopts * svr_getopts(int argc, char ** argv) { if (argv[i][0] == '-') { switch (argv[i][1]) { case 'b': - next = &opts->bannerfile; + next = &svr_opts.bannerfile; break; #ifdef DROPBEAR_DSS case 'd': - next = &opts->dsskeyfile; + next = &svr_opts.dsskeyfile; break; #endif #ifdef DROPBEAR_RSA case 'r': - next = &opts->rsakeyfile; + next = &svr_opts.rsakeyfile; break; #endif case 'F': - opts->forkbg = 0; + svr_opts.forkbg = 0; break; #ifndef DISABLE_SYSLOG case 'E': - usingsyslog = 0; + svr_opts.usingsyslog = 0; break; #endif #ifndef DISABLE_LOCALTCPFWD case 'j': - opts->nolocaltcp = 1; + opts.nolocaltcp = 1; break; #endif #ifndef DISABLE_REMOTETCPFWD case 'k': - opts->noremotetcp = 1; + opts.noremotetcp = 1; break; #endif case 'p': @@ -171,18 +169,18 @@ runopts * svr_getopts(int argc, char ** argv) { #ifdef DO_MOTD /* motd is displayed by default, -m turns it off */ case 'm': - opts->domotd = 0; + svr_opts.domotd = 0; break; #endif case 'w': - opts->norootlogin = 1; + svr_opts.norootlogin = 1; break; #ifdef DROPBEAR_PASSWORD_AUTH case 's': - opts->noauthpass = 1; + svr_opts.noauthpass = 1; break; case 'g': - opts->norootpass = 1; + svr_opts.norootpass = 1; break; #endif case 'h': @@ -191,10 +189,10 @@ runopts * svr_getopts(int argc, char ** argv) { break; /* case '4': - opts->ipv4 = 0; + svr_opts.ipv4 = 0; break; case '6': - opts->ipv6 = 0; + svr_opts.ipv6 = 0; break; */ default: @@ -206,19 +204,19 @@ runopts * svr_getopts(int argc, char ** argv) { } } - if (opts->dsskeyfile == NULL) { - opts->dsskeyfile = DSS_PRIV_FILENAME; + if (svr_opts.dsskeyfile == NULL) { + svr_opts.dsskeyfile = DSS_PRIV_FILENAME; } - if (opts->rsakeyfile == NULL) { - opts->rsakeyfile = RSA_PRIV_FILENAME; + if (svr_opts.rsakeyfile == NULL) { + svr_opts.rsakeyfile = RSA_PRIV_FILENAME; } - opts->hostkey = loadhostkeys(opts->dsskeyfile, opts->rsakeyfile); + svr_opts.hostkey = loadhostkeys(svr_opts.dsskeyfile, svr_opts.rsakeyfile); - if (opts->bannerfile) { + if (svr_opts.bannerfile) { struct stat buf; - if (stat(opts->bannerfile, &buf) != 0) { + if (stat(svr_opts.bannerfile, &buf) != 0) { dropbear_exit("Error opening banner file '%s'", - opts->bannerfile); + svr_opts.bannerfile); } if (buf.st_size > MAX_BANNER_SIZE) { @@ -226,16 +224,16 @@ runopts * svr_getopts(int argc, char ** argv) { MAX_BANNER_SIZE); } - opts->banner = buf_new(buf.st_size); - if (buf_readfile(opts->banner, opts->bannerfile)!=DROPBEAR_SUCCESS) { + svr_opts.banner = buf_new(buf.st_size); + if (buf_readfile(svr_opts.banner, svr_opts.bannerfile)!=DROPBEAR_SUCCESS) { dropbear_exit("Error reading banner file '%s'", - opts->bannerfile); + svr_opts.bannerfile); } - buf_setpos(opts->banner, 0); + buf_setpos(svr_opts.banner, 0); } /* not yet - if (!(opts->ipv4 || opts->ipv6)) { + if (!(svr_opts.ipv4 || svr_opts.ipv6)) { fprintf(stderr, "You can't disable ipv4 and ipv6.\n"); exit(1); } @@ -244,17 +242,17 @@ runopts * svr_getopts(int argc, char ** argv) { /* create the array of listening ports */ if (portnum == 0) { /* non specified */ - opts->portcount = 1; - opts->ports = m_malloc(sizeof(uint16_t)); - opts->ports[0] = DROPBEAR_PORT; + svr_opts.portcount = 1; + svr_opts.ports = m_malloc(sizeof(uint16_t)); + svr_opts.ports[0] = DROPBEAR_PORT; } else { - opts->portcount = portnum; - opts->ports = (uint16_t*)m_malloc(sizeof(uint16_t)*portnum); + svr_opts.portcount = portnum; + svr_opts.ports = (uint16_t*)m_malloc(sizeof(uint16_t)*portnum); for (i = 0; i < portnum; i++) { if (portstring[i]) { longport = atoi(portstring[i]); if (longport <= 65535 && longport > 0) { - opts->ports[i] = (uint16_t)longport; + svr_opts.ports[i] = (uint16_t)longport; continue; } } @@ -263,23 +261,8 @@ runopts * svr_getopts(int argc, char ** argv) { } } - return opts; } -void freerunopts(runopts* opts) { - - if (!opts) { - return; - } - - if (opts->hostkey) { - sign_key_free(opts->hostkey); - opts->hostkey = NULL; - } - - m_free(opts->ports); - m_free(opts); -} /* returns success or failure */ static int readhostkey(const char * filename, sign_key * hostkey, int type) { diff --git a/svr-session.c b/svr-session.c index d3094ea..927a1c1 100644 --- a/svr-session.c +++ b/svr-session.c @@ -39,10 +39,11 @@ #include "service.h" #include "auth.h" #include "tcpfwd-remote.h" +#include "runopts.h" static void svr_remoteclosed(); -struct serversession svr_ses; +struct serversession svr_ses; /* GLOBAL */ static const packettype svr_packettypes[] = { /* TYPE, AUTHREQUIRED, FUNCTION */ @@ -69,15 +70,14 @@ static const struct ChanType *svr_chantypes[] = { NULL /* Null termination is mandatory. */ }; -void svr_session(int sock, runopts *opts, int childpipe, - struct sockaddr* remoteaddr) { +void svr_session(int sock, int childpipe, struct sockaddr* remoteaddr) { fd_set readfd, writefd; struct timeval timeout; int val; crypto_init(); - common_session_init(sock, opts); + common_session_init(sock); ses.remoteaddr = remoteaddr; ses.remotehost = getaddrhostname(remoteaddr); @@ -227,7 +227,7 @@ void svr_dropbear_log(int priority, const char* format, va_list param) { vsnprintf(printbuf, sizeof(printbuf), format, param); #ifndef DISABLE_SYSLOG - if (usingsyslog) { + if (svr_opts.usingsyslog) { syslog(priority, "%s", printbuf); } #endif @@ -238,7 +238,7 @@ void svr_dropbear_log(int priority, const char* format, va_list param) { havetrace = 1; #endif - if (!usingsyslog || havetrace) + if (!svr_opts.usingsyslog || havetrace) { timesec = time(NULL); if (strftime(datestr, sizeof(datestr), "%b %d %H:%M:%S", diff --git a/tcpfwd-direct.c b/tcpfwd-direct.c index 1131602..b6a2178 100644 --- a/tcpfwd-direct.c +++ b/tcpfwd-direct.c @@ -3,6 +3,7 @@ #include "dbutil.h" #include "channel.h" #include "tcpfwd-direct.h" +#include "runopts.h" #ifndef DISABLE_TCPFWD_DIRECT static int newtcpdirect(struct Channel * channel); @@ -30,7 +31,7 @@ static int newtcpdirect(struct Channel * channel) { int len; int ret = DROPBEAR_FAILURE; - if (ses.opts->nolocaltcp) { + if (opts.nolocaltcp) { TRACE(("leave newtcpdirect: local tcp forwarding disabled")); goto out; } diff --git a/tcpfwd-remote.c b/tcpfwd-remote.c index 16b1105..d0a67a1 100644 --- a/tcpfwd-remote.c +++ b/tcpfwd-remote.c @@ -6,6 +6,7 @@ #include "buffer.h" #include "packet.h" #include "listener.h" +#include "runopts.h" #ifndef DISABLE_REMOTETCPFWD @@ -35,7 +36,7 @@ void recv_msg_global_request_remotetcp() { TRACE(("enter recv_msg_global_request_remotetcp")); - if (ses.opts->noremotetcp) { + if (opts.noremotetcp) { TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled")); goto out; } -- cgit v1.2.3 From 58baa046d26f1f7ded8682ae73ca945bebc0f71b Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 27 Jul 2004 13:32:54 +0000 Subject: Totally reworked Makefile.in Doesn't totally work, but getting there --HG-- extra : convert_revision : 517f94c41885417c1040a6a6cf14aa2248334f26 --- Makefile.in | 177 ++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 100 insertions(+), 77 deletions(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 4d6d342..de01aff 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,22 +1,36 @@ +# This Makefile is for Dropbear SSH Server and Client + +# invocation: +# make PROGRAMS="dropbear dbclient scp" MULTI=1 STATIC=1 SCPPROGRESS=1 +# +# to make a single multiple statically linked binary "staticdropbearmulti", +# which includes dropbear, scp and dbclient functionality, and includes the +# progress-bar functionality in scp. Hopefully that seems intuitive. + +# This makefile is quite evil. + +ifndef PROGRAMS + PROGRAMS="dropbear dbclient dropbearkey dropbearmulti" +endif + LTC=libtomcrypt/libtomcrypt.a LTM=libtommath/libtommath.a -COMMONOBJS=dbutil.o common-session.o common-packet.o common-algo.o buffer.o \ +COMMONOBJS=dbutil.o common-session.o 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 \ - loginrec.o atomicio.o svr-x11fwd.o tcpfwd-direct.o compat.o \ + loginrec.o atomicio.o tcpfwd-direct.o compat.o \ tcpfwd-remote.o listener.o process-packet.o common-runopts.o SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ svr-authpasswd.o svr-authpubkey.o svr-session.o svr-service.o \ - svr-chansession.o svr-runopts.o svr-agentfwd.o - -CLIOBJS= + svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o -OBJS=$(COMMONOBJS) $(SVROBJS) +CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ + cli-session.o cli-service.o -DROPBEAROBJS=main.o +DROPBEAROBJS= DROPBEARKEYOBJS=dropbearkey.o gendss.o genrsa.o @@ -31,7 +45,11 @@ HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \ loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd-direct.h compat.h \ tcpfwd-remote.h listener.h -ALLOBJS=$(OBJS) $(DROPBEARKEYOBJS) $(DROPBEAROBJS) +dropbearobjs=$(COMMONOBJS) $(SVROBJS) +dbclientobjs=$(COMMONOBJS) $(CLIOBJS) +dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS) +dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS) +scpobjs=$(SCPOBJS) prefix=@prefix@ exec_prefix=${prefix} @@ -44,97 +62,101 @@ AR=@AR@ RANLIB=@RANLIB@ STRIP=@STRIP@ INSTALL=@INSTALL@ -CFLAGS=-Ilibtomcrypt @CFLAGS@ +CFLAGS=@CFLAGS@ LIBS=$(LTC) $(LTM) @LIBS@ LDFLAGS=@LDFLAGS@ +EXEEXT=@EXEEXT@ + +# whether we're building client, server, or both for the common objects. +space:= $(empty) $(empty) +CLISVRFLAGS= +# evilness so we detect 'dropbear' by itself as a word +ifneq (,$(findstring $(space)dropbear$(space), $(space)$(PROGRAMS)$(space))) + CLISVRFLAGS+= -DDROPBEAR_SERVER +endif +ifneq (,$(findstring $(space)dbclient$(space), $(space)$(PROGRAMS)$(space))) + CLISVRFLAGS+= -DDROPBEAR_CLIENT +endif + +CFLAGS+=$(CLISVRFLAGS) + # these are exported so that libtomcrypt's makefile will use them export CC export CFLAGS export RANLIB AR STRIP -all: dropbear dropbearkey dropbearconvert - @echo - @echo Run \"make strip\" if you want stripped binaries, - @echo or \"make install\" to install to ${prefix} - -strip: - -$(STRIP) dropbear - -$(STRIP) dropbearkey - -$(STRIP) dropbearconvert +ifeq ($(STATIC), 1) + LDFLAGS+=-static + SPREFIX=static +else + SPREFIX= +endif -install: all - $(INSTALL) -d -m 755 $(DESTDIR)$(sbindir) - $(INSTALL) -d -m 755 $(DESTDIR)$(bindir) - $(INSTALL) -m 755 dropbear $(DESTDIR)$(sbindir) - $(INSTALL) -m 755 dropbearkey $(DESTDIR)$(bindir) - $(INSTALL) -m 755 dropbearconvert $(DESTDIR)$(bindir) - # chown might fail, so do it separately to the install - -chown root $(DESTDIR)$(sbindir)/dropbear - -chgrp 0 $(DESTDIR)$(sbindir)/dropbear - -chown root $(DESTDIR)$(bindir)/dropbearkey - -chgrp 0 $(DESTDIR)$(bindir)/dropbearkey - -chown root $(DESTDIR)$(bindir)/dropbearconvert - -chgrp 0 $(DESTDIR)$(bindir)/dropbearconvert +ifeq ($(MULTI), 1) + TARGETS=dropbearmulti +else + TARGETS=$(PROGRAMS) +endif +# for the scp progress meter. The -D doesn't affect anything else. +ifeq ($(SCPPROGRESS), 1) + CFLAGS+=-DPROGRESS_METER +endif -static: dropbear-static dropbearkey-static dropbearconvert-static +#%: $(HEADERS) +#%: $(HEADERS) Makefile +# TODO -$(ALLOBJS): $(HEADERS) Makefile -dropbear: $(DROPBEAROBJS) $(OBJS) $(HEADERS) Makefile $(LTC) $(LTM) - $(LD) $(LDFLAGS) -o dropbear $(DROPBEAROBJS) $(OBJS) $(LIBS) +strip: $(TARGETS) + $(STRIP) $(foreach prog, $(TARGETS), $(SPREFIX)$(prog)$(EXEEXT)) -dropbear-static: $(DROPBEAROBJS) $(OBJS) $(HEADERS) Makefile $(LTC) $(LTM) - $(LD) $(LDFLAGS) -o staticdropbear $(DROPBEAROBJS) $(OBJS) $(LIBS) -static -dropbearkey: $(OBJS) $(HEADERS) Makefile $(DROPBEARKEYOBJS) $(LTC) $(LTM) - $(LD) $(LDFLAGS) -o dropbearkey $(DROPBEARKEYOBJS) \ - $(OBJS) $(LIBS) +install: $(foreach prog, $(TARGETS), install$prog) -dropbearkey-static: $(OBJS) $(HEADERS) Makefile $(DROPBEARKEYOBJS) $(LTC) $(LTM) - $(LD) $(LDFLAGS) -o staticdropbearkey $(DROPBEARKEYOBJS) \ - $(OBJS) $(LIBS) -static +# dropbear should go in sbin, so it needs a seperate rule +installdropbear: dropbear + $(INSTALL) -d -m 755 $(DESTDIR)$(sbindir) + $(INSTALL) -m 755 $(SPREFIX)dropbear$(EXEEXT) $(DESTDIR)$(sbindir) + -chown root $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT) + -chgrp 0 $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT) -dropbearconvert: $(OBJS) $(HEADERS) Makefile $(CONVERTOBJS) $(LTC) $(LTM) - $(LD) $(LDFLAGS) -o dropbearconvert $(CONVERTOBJS) $(OBJS) $(LIBS) +install%: $* + $(INSTALL) -d -m 755 $(DESTDIR)$(bindir) + $(INSTALL) -m 755 $(SPREFIX)$*$(EXEEXT) $(DESTDIR)$(bindir) + -chown root $(DESTDIR)$(sbindir)/$(SPREFIX)$*$(EXEEXT) + -chgrp 0 $(DESTDIR)$(sbindir)/$(SPREFIX)$*$(EXEEXT) + ifeq ($(MULTI), 1) + @echo "You must manually create links for $*" + endif -dropbearconvert-static: $(OBJS) $(HEADERS) Makefile $(CONVERTOBJS) $(LTC) $(LTM) - $(LD) $(LDFLAGS) -o staticdropbearconvert $(CONVERTOBJS) $(OBJS) $(LIBS) \ - -static -multi: dropbearmulti -dropbearmulti: $(HEADERS) $(OBJS) $(LTC) $(LTM) $(CONVERTOBJS) \ - $(DROPBEARKEYOBJS) $(DROPBEAROBJS) dbmulti.o - $(LD) $(LDFLAGS) -o dropbearmulti $(OBJS) $(LTM) $(LTM) $(CONVERTOBJS) \ - $(DROPBEARKEYOBJS) $(DROPBEAROBJS) dbmulti.o $(LIBS) - @echo "You should now create symlinks to the programs you have included" - @echo "ie 'ln -s dropbearmulti dropbear'" +# The actual binaries +dropbear: $(dropbearobjs) -dropbearmultistatic: $(HEADERS) $(OBJS) $(LTC) $(LTM) $(CONVERTOBJS) \ - $(DROPBEARKEYOBJS) $(DROPBEAROBJS) dbmulti.o - $(LD) $(LDFLAGS) -o staticdropbearmulti $(OBJS) $(LTM) $(LTM) \ - $(CONVERTOBJS) $(DROPBEARKEYOBJS) $(DROPBEAROBJS) \ - dbmulti.o $(LIBS) -static - @echo "You should now create symlinks to the programs you have included" - @echo "ie 'ln -s dropbearmultistatic dropbear'" +dropbear dbclient dropbearkey dropbearconvert: $($($@objs)) $(HEADERS) \ + $(LTC) $(LTM) + @echo $(CLISVRFLAGS) + $(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $($@objs) $(LIBS) -stripmulti: dropbearmulti - -$(STRIP) dropbearmulti +# scp doesn't use the libs so is special. +scp: $(SCPOBJS) $(HEADERS) + $(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $(SCPOBJS) -scp: $(SCPOBJS) Makefile - $(LD) $(LDFLAGS) -o $@ $(SCPOBJS) -# gnumake before 3.80 is broken. So this is uglyish -scp-progress: atomicio.o scpmisc.o $(HEADERS) Makefile - -rm scp.o progressmeter.o - $(MAKE) CFLAGS="$(CFLAGS) -DPROGRESS_METER" scp.o progressmeter.o - $(LD) $(LDFLAGS) -o $@ $(SCPOBJS) +MULTIOBJS=dbmulti.o +ifeq ($(MULTI),1) + deftarget=multi + MULTIOBJS=$(foreach prog, $(PROGRAMS), $($(prog)objs)) +endif -scpstatic: $(SCPOBJS) $(HEADERS) Makefile - $(LD) $(LDFLAGS) -o $@ $(SCPOBJS) -static +dropbearmulti: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) + $(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $(MULTIOBJS) $(LIBS) + @echo "You should now create symlinks to the programs you have included" + @echo "ie 'ln -s dropbearmulti dropbear'" $(LTC): $(HEADERS) cd libtomcrypt && $(MAKE) clean && $(MAKE) @@ -152,13 +174,14 @@ sizes: dropbear objdump -t dropbear|grep ".text"|cut -d "." -f 2|sort -rn clean: ltc-clean ltm-clean - -rm -f dropbear dropbear dropbearkey staticdropbear staticdropbearkey - -rm -f dropbearconvert staticdropbearconvert scp scp-progress scpstatic - -rm -f dropbearmulti dropbearmultistatic + -rm -f dropbear dbclient dropbearkey dropbearconvert scp scp-progress + -rm -f staticdropbear staticdropbearkey staticdropbearconvert staticscp + -rm -f dropbearmulti staticdropbearmulti -rm -f *.o *.da *.bb *.bbg *.prof distclean: clean tidy - -rm -f Makefile config.h + -rm -f config.h + -rm -f Makefile tidy: -rm -f *~ *.gcov */*~ -- cgit v1.2.3 From 8b6ddcb06620031611f7482561c88346a1245f57 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 27 Jul 2004 14:44:43 +0000 Subject: Switching to the magical new Makefile, and new dbmulti style --HG-- extra : convert_revision : 3f8efcdd56aab197d30a1ea81527c37dfee2f928 --- Makefile.in | 69 ++++++----- dbmulti.c | 21 +++- dropbearconvert.c | 4 +- dropbearkey.c | 4 +- main.c | 347 ------------------------------------------------------ svr-main.c | 347 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 405 insertions(+), 387 deletions(-) delete mode 100644 main.c create mode 100644 svr-main.c (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index de01aff..fcaa6f2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -10,18 +10,17 @@ # This makefile is quite evil. ifndef PROGRAMS - PROGRAMS="dropbear dbclient dropbearkey dropbearmulti" + PROGRAMS=dropbear dbclient dropbearkey dropbearmulti endif LTC=libtomcrypt/libtomcrypt.a LTM=libtommath/libtommath.a -COMMONOBJS=dbutil.o common-session.o 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 \ - loginrec.o atomicio.o tcpfwd-direct.o compat.o \ - tcpfwd-remote.o listener.o process-packet.o common-runopts.o +COMMONOBJS=dbutil.o buffer.o \ + dss.o bignum.o \ + signkey.o rsa.o random.o \ + queue.o \ + atomicio.o compat.o SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ svr-authpasswd.o svr-authpubkey.o svr-session.o svr-service.o \ @@ -30,9 +29,12 @@ SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ cli-session.o cli-service.o -DROPBEAROBJS= +CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \ + common-channel.o common-chansession.o termcodes.o loginrec.o \ + tcpfwd-direct.o tcpfwd-remote.o listener.o process-packet.o \ + common-runopts.o -DROPBEARKEYOBJS=dropbearkey.o gendss.o genrsa.o +KEYOBJS=dropbearkey.o gendss.o genrsa.o CONVERTOBJS=dropbearconvert.o keyimport.o @@ -45,8 +47,8 @@ HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \ loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd-direct.h compat.h \ tcpfwd-remote.h listener.h -dropbearobjs=$(COMMONOBJS) $(SVROBJS) -dbclientobjs=$(COMMONOBJS) $(CLIOBJS) +dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) +dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS) dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS) dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS) scpobjs=$(SCPOBJS) @@ -57,7 +59,7 @@ bindir=${exec_prefix}/bin sbindir=${exec_prefix}/sbin CC=@CC@ -LD=@CC@ +LD=@LD@ AR=@AR@ RANLIB=@RANLIB@ STRIP=@STRIP@ @@ -69,17 +71,15 @@ LDFLAGS=@LDFLAGS@ EXEEXT=@EXEEXT@ # whether we're building client, server, or both for the common objects. -space:= $(empty) $(empty) -CLISVRFLAGS= # evilness so we detect 'dropbear' by itself as a word -ifneq (,$(findstring $(space)dropbear$(space), $(space)$(PROGRAMS)$(space))) - CLISVRFLAGS+= -DDROPBEAR_SERVER +space:= $(empty) $(empty) +ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdropbearZ, Z$(prog)Z)))) + CFLAGS+= -DDROPBEAR_SERVER endif -ifneq (,$(findstring $(space)dbclient$(space), $(space)$(PROGRAMS)$(space))) - CLISVRFLAGS+= -DDROPBEAR_CLIENT +ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdbclientZ, Z$(prog)Z)))) + CFLAGS+= -DDROPBEAR_CLIENT endif -CFLAGS+=$(CLISVRFLAGS) # these are exported so that libtomcrypt's makefile will use them export CC @@ -108,12 +108,15 @@ endif #%: $(HEADERS) Makefile # TODO +all: $(TARGETS) -strip: $(TARGETS) - $(STRIP) $(foreach prog, $(TARGETS), $(SPREFIX)$(prog)$(EXEEXT)) +test: + @echo Z$(sort $(foreach prog, $(PROGRAMS), $($(prog)objs)))Z +strip: $(TARGETS) + $(STRIP) $(addsuffix $(EXEEXT), $(addprefix $(SPREFIX), $(TARGETS))) -install: $(foreach prog, $(TARGETS), install$prog) +install: $(addprefix install, $(TARGETS)) # dropbear should go in sbin, so it needs a seperate rule installdropbear: dropbear @@ -128,33 +131,39 @@ install%: $* -chown root $(DESTDIR)$(sbindir)/$(SPREFIX)$*$(EXEEXT) -chgrp 0 $(DESTDIR)$(sbindir)/$(SPREFIX)$*$(EXEEXT) ifeq ($(MULTI), 1) + @echo @echo "You must manually create links for $*" endif -# The actual binaries +# for some reason the rule further down doesn't like $($@objs) as a prereq. dropbear: $(dropbearobjs) +dbclient: $(dbclientobjs) +dropbearkey: $(dropbearkeyobjs) +dropbearconvert: $(dropbearconvertobjs) -dropbear dbclient dropbearkey dropbearconvert: $($($@objs)) $(HEADERS) \ - $(LTC) $(LTM) - @echo $(CLISVRFLAGS) +dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LTC) $(LTM) $(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $($@objs) $(LIBS) - # scp doesn't use the libs so is special. scp: $(SCPOBJS) $(HEADERS) $(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $(SCPOBJS) -MULTIOBJS=dbmulti.o +# multi-binary compilation. +MULTIOBJS= ifeq ($(MULTI),1) - deftarget=multi - MULTIOBJS=$(foreach prog, $(PROGRAMS), $($(prog)objs)) + MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs))) + CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI endif +testfoo: + echo $(MULTIOBJS) + dropbearmulti: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) $(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $(MULTIOBJS) $(LIBS) + @echo @echo "You should now create symlinks to the programs you have included" @echo "ie 'ln -s dropbearmulti dropbear'" diff --git a/dbmulti.c b/dbmulti.c index d82eff0..8f39227 100644 --- a/dbmulti.c +++ b/dbmulti.c @@ -4,6 +4,7 @@ int dropbear_main(int argc, char ** argv); int dropbearkey_main(int argc, char ** argv); int dropbearconvert_main(int argc, char ** argv); +int scp_main(int argc, char ** argv); int main(int argc, char ** argv) { @@ -13,33 +14,41 @@ int main(int argc, char ** argv) { /* figure which form we're being called as */ progname = basename(argv[0]); -#ifdef DBMULTI_DROPBEAR +#ifdef DBMULTI_dropbear if (strcmp(progname, "dropbear") == 0) { return dropbear_main(argc, argv); } #endif -#ifdef DBMULTI_KEY +#ifdef DBMULTI_dropbearkey if (strcmp(progname, "dropbearkey") == 0) { return dropbearkey_main(argc, argv); } #endif -#ifdef DBMULTI_CONVERT +#ifdef DBMULTI_dropbearconvert if (strcmp(progname, "dropbearconvert") == 0) { return dropbearconvert_main(argc, argv); } +#endif +#ifdef DBMULTI_scp + if (strcmp(progname, "scp") == 0) { + return scp_main(argc, argv); + } #endif } fprintf(stderr, "Dropbear multi-purpose version %s\n" "Make a symlink pointing at this binary with one of the following names:\n" -#ifdef DBMULTI_DROPBEAR +#ifdef DBMULTI_dropbear "'dropbear' - the Dropbear server\n" #endif -#ifdef DBMULTI_KEY +#ifdef DBMULTI_dropbearkey "'dropbearkey' - the key generator\n" #endif -#ifdef DBMULTI_CONVERT +#ifdef DBMULTI_dropbearconvert "'dropbearconvert' - the key converter\n" +#endif +#ifdef DBMULTI_scp + "'scp' - secure copy\n" #endif , DROPBEAR_VERSION); diff --git a/dropbearconvert.c b/dropbearconvert.c index 0929ba8..3ceccff 100644 --- a/dropbearconvert.c +++ b/dropbearconvert.c @@ -53,8 +53,8 @@ static void printhelp(char * progname) { "standard input or standard output.\n", progname); } -#if defined(DBMULTI_CONVERT) || !defined(DROPBEAR_MULTI) -#if defined(DBMULTI_CONVERT) && defined(DROPBEAR_MULTI) +#if defined(DBMULTI_dropbearconvert) || !defined(DROPBEAR_MULTI) +#if defined(DBMULTI_dropbearconvert) && defined(DROPBEAR_MULTI) int dropbearconvert_main(int argc, char ** argv) { #else int main(int argc, char ** argv) { diff --git a/dropbearkey.c b/dropbearkey.c index bc2b1ae..eac0823 100644 --- a/dropbearkey.c +++ b/dropbearkey.c @@ -80,8 +80,8 @@ static void printhelp(char * progname) { progname); } -#if defined(DBMULTI_KEY) || !defined(DROPBEAR_MULTI) -#if defined(DBMULTI_KEY) && defined(DROPBEAR_MULTI) +#if defined(DBMULTI_dropbearkey) || !defined(DROPBEAR_MULTI) +#if defined(DBMULTI_dropbearkey) && defined(DROPBEAR_MULTI) int dropbearkey_main(int argc, char ** argv) { #else int main(int argc, char ** argv) { diff --git a/main.c b/main.c deleted file mode 100644 index 0ef1e62..0000000 --- a/main.c +++ /dev/null @@ -1,347 +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" -#include "dbutil.h" -#include "session.h" -#include "buffer.h" -#include "signkey.h" -#include "runopts.h" - -static int listensockets(int *sock, int *maxfd); -static void sigchld_handler(int dummy); -static void sigsegv_handler(int); -static void sigintterm_handler(int fish); - -static int childpipes[MAX_UNAUTH_CLIENTS]; - -#if defined(DBMULTI_DROPBEAR) || !defined(DROPBEAR_MULTI) -#if defined(DBMULTI_DROPBEAR) && defined(DROPBEAR_MULTI) -int dropbear_main(int argc, char ** argv) -#else -int main(int argc, char ** argv) -#endif -{ - - fd_set fds; - struct timeval seltimeout; - unsigned int i, j; - int val; - int maxsock = -1; - struct sockaddr remoteaddr; - int remoteaddrlen; - int listensocks[MAX_LISTEN_ADDR]; - unsigned int listensockcount = 0; - FILE * pidfile; - - int childsock; - pid_t childpid; - int childpipe[2]; - - struct sigaction sa_chld; - - _dropbear_exit = svr_dropbear_exit; - _dropbear_log = svr_dropbear_log; - - /* get commandline options */ - svr_getopts(argc, argv); - - /* fork */ - if (svr_opts.forkbg) { - int closefds = 0; -#ifndef DEBUG_TRACE - if (!svr_opts.usingsyslog) { - closefds = 1; - } -#endif - if (daemon(0, closefds) < 0) { - dropbear_exit("Failed to create background process: %s", - strerror(errno)); - } - } - -#ifndef DISABLE_SYSLOG - if (svr_opts.usingsyslog) { - startsyslog(); - } -#endif - - /* should be done after syslog is working */ - if (svr_opts.forkbg) { - dropbear_log(LOG_INFO, "Running in background"); - } else { - dropbear_log(LOG_INFO, "Not forking"); - } - - /* create a PID file so that we can be killed easily */ - pidfile = fopen(DROPBEAR_PIDFILE, "w"); - if (pidfile) { - fprintf(pidfile, "%d\n", getpid()); - fclose(pidfile); - } - - /* set up cleanup handler */ - if (signal(SIGINT, sigintterm_handler) == SIG_ERR || -#ifndef DEBUG_VALGRIND - signal(SIGTERM, sigintterm_handler) == SIG_ERR || -#endif - signal(SIGPIPE, SIG_IGN) == SIG_ERR) { - dropbear_exit("signal() error"); - } - - /* catch and reap zombie children */ - sa_chld.sa_handler = sigchld_handler; - sa_chld.sa_flags = SA_NOCLDSTOP; - if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) { - dropbear_exit("signal() error"); - } - if (signal(SIGSEGV, sigsegv_handler) == SIG_ERR) { - dropbear_exit("signal() error"); - } - - /* sockets to identify pre-authenticated clients */ - for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { - childpipes[i] = -1; - } - - /* Set up the listening sockets */ - /* XXX XXX ports */ - listensockcount = listensockets(listensocks, &maxsock); - - /* incoming connection select loop */ - for(;;) { - - FD_ZERO(&fds); - - seltimeout.tv_sec = 60; - seltimeout.tv_usec = 0; - - /* listening sockets */ - for (i = 0; i < listensockcount; i++) { - FD_SET(listensocks[i], &fds); - } - - /* pre-authentication clients */ - for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { - if (childpipes[i] >= 0) { - FD_SET(childpipes[i], &fds); - maxsock = MAX(maxsock, childpipes[i]); - } - } - - val = select(maxsock+1, &fds, NULL, NULL, &seltimeout); - - if (exitflag) { - unlink(DROPBEAR_PIDFILE); - dropbear_exit("Terminated by signal"); - } - - if (val == 0) { - /* timeout reached */ - continue; - } - - if (val < 0) { - if (errno == EINTR) { - continue; - } - dropbear_exit("Listening socket error"); - } - - /* close fds which have been authed or closed - auth.c handles - * closing the auth sockets on success */ - for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { - if (childpipes[i] >= 0 && FD_ISSET(childpipes[i], &fds)) { - close(childpipes[i]); - childpipes[i] = -1; - } - } - - /* handle each socket which has something to say */ - for (i = 0; i < listensockcount; i++) { - if (!FD_ISSET(listensocks[i], &fds)) - continue; - - /* child connection XXX - ip6 stuff here */ - remoteaddrlen = sizeof(struct sockaddr_in); - childsock = accept(listensocks[i], &remoteaddr, &remoteaddrlen); - - if (childsock < 0) { - /* accept failed */ - continue; - } - - /* check for max number of connections not authorised */ - for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) { - if (childpipes[j] < 0) { - break; - } - } - - if (j == MAX_UNAUTH_CLIENTS) { - /* no free connections */ - /* TODO - possibly log, though this would be an easy way - * to fill logs/disk */ - close(childsock); - continue; - } - - if (pipe(childpipe) < 0) { - TRACE(("error creating child pipe")); - close(childsock); - continue; - } - - if ((childpid = fork()) == 0) { - - /* child */ - char * addrstring = NULL; -#ifdef DEBUG_FORKGPROF - extern void _start(void), etext(void); - monstartup((u_long)&_start, (u_long)&etext); -#endif /* DEBUG_FORKGPROF */ - - addrstring = getaddrstring(&remoteaddr); - dropbear_log(LOG_INFO, "Child connection from %s", addrstring); - m_free(addrstring); - - if (setsid() < 0) { - dropbear_exit("setsid: %s", strerror(errno)); - } - - /* make sure we close sockets */ - for (i = 0; i < listensockcount; i++) { - if (m_close(listensocks[i]) == DROPBEAR_FAILURE) { - dropbear_exit("Couldn't close socket"); - } - } - - if (m_close(childpipe[0]) == DROPBEAR_FAILURE) { - dropbear_exit("Couldn't close socket"); - } - - /* start the session */ - svr_session(childsock, childpipe[1], - getaddrhostname(&remoteaddr)); - /* don't return */ - assert(0); - } - - /* parent */ - childpipes[j] = childpipe[0]; - if (m_close(childpipe[1]) == DROPBEAR_FAILURE - || m_close(childsock) == DROPBEAR_FAILURE) { - dropbear_exit("Couldn't close socket"); - } - } - } /* for(;;) loop */ - - /* don't reach here */ - return -1; -} -#endif - -/* catch + reap zombie children */ -static void sigchld_handler(int fish) { - struct sigaction sa_chld; - - while(waitpid(-1, NULL, WNOHANG) > 0); - - sa_chld.sa_handler = sigchld_handler; - sa_chld.sa_flags = SA_NOCLDSTOP; - if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) { - dropbear_exit("signal() error"); - } -} - -/* catch any segvs */ -static void sigsegv_handler(int fish) { - fprintf(stderr, "Aiee, segfault! You should probably report " - "this as a bug to the developer\n"); - exit(EXIT_FAILURE); -} - -/* catch ctrl-c or sigterm */ -static void sigintterm_handler(int fish) { - - exitflag = 1; -} - -/* Set up listening sockets for all the requested ports */ -static int listensockets(int *sock, int *maxfd) { - - int listensock; /* listening fd */ - struct sockaddr_in listen_addr; - struct linger linger; - unsigned int i; - int val; - - for (i = 0; i < svr_opts.portcount; i++) { - - /* iterate through all the sockets to listen on */ - listensock = socket(PF_INET, SOCK_STREAM, 0); - if (listensock < 0) { - dropbear_exit("Failed to create socket"); - } - - val = 1; - /* set to reuse, quick timeout */ - setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, - (void*) &val, sizeof(val)); - linger.l_onoff = 1; - linger.l_linger = 5; - setsockopt(listensock, SOL_SOCKET, SO_LINGER, - (void*)&linger, sizeof(linger)); - - /* disable nagle */ - setsockopt(listensock, IPPROTO_TCP, TCP_NODELAY, - (void*)&val, sizeof(val)); - - memset((void*)&listen_addr, 0x0, sizeof(listen_addr)); - listen_addr.sin_family = AF_INET; - listen_addr.sin_port = htons(svr_opts.ports[i]); - listen_addr.sin_addr.s_addr = htonl(INADDR_ANY); - memset(&(listen_addr.sin_zero), '\0', 8); - - if (bind(listensock, (struct sockaddr *)&listen_addr, - sizeof(listen_addr)) < 0) { - dropbear_exit("Bind failed port %d", svr_opts.ports[i]); - } - - /* listen */ - if (listen(listensock, 20) < 0) { /* TODO set listen count */ - dropbear_exit("Listen failed"); - } - - /* nonblock */ - if (fcntl(listensock, F_SETFL, O_NONBLOCK) < 0) { - dropbear_exit("Failed to set non-blocking"); - } - - sock[i] = listensock; - *maxfd = MAX(listensock, *maxfd); - } - - return svr_opts.portcount; -} diff --git a/svr-main.c b/svr-main.c new file mode 100644 index 0000000..312e47c --- /dev/null +++ b/svr-main.c @@ -0,0 +1,347 @@ +/* + * 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" +#include "dbutil.h" +#include "session.h" +#include "buffer.h" +#include "signkey.h" +#include "runopts.h" + +static int listensockets(int *sock, int *maxfd); +static void sigchld_handler(int dummy); +static void sigsegv_handler(int); +static void sigintterm_handler(int fish); + +static int childpipes[MAX_UNAUTH_CLIENTS]; + +#if defined(DBMULTI_dropbear) || !defined(DROPBEAR_MULTI) +#if defined(DBMULTI_dropbear) && defined(DROPBEAR_MULTI) +int dropbear_main(int argc, char ** argv) +#else +int main(int argc, char ** argv) +#endif +{ + + fd_set fds; + struct timeval seltimeout; + unsigned int i, j; + int val; + int maxsock = -1; + struct sockaddr remoteaddr; + int remoteaddrlen; + int listensocks[MAX_LISTEN_ADDR]; + unsigned int listensockcount = 0; + FILE * pidfile; + + int childsock; + pid_t childpid; + int childpipe[2]; + + struct sigaction sa_chld; + + _dropbear_exit = svr_dropbear_exit; + _dropbear_log = svr_dropbear_log; + + /* get commandline options */ + svr_getopts(argc, argv); + + /* fork */ + if (svr_opts.forkbg) { + int closefds = 0; +#ifndef DEBUG_TRACE + if (!svr_opts.usingsyslog) { + closefds = 1; + } +#endif + if (daemon(0, closefds) < 0) { + dropbear_exit("Failed to create background process: %s", + strerror(errno)); + } + } + +#ifndef DISABLE_SYSLOG + if (svr_opts.usingsyslog) { + startsyslog(); + } +#endif + + /* should be done after syslog is working */ + if (svr_opts.forkbg) { + dropbear_log(LOG_INFO, "Running in background"); + } else { + dropbear_log(LOG_INFO, "Not forking"); + } + + /* create a PID file so that we can be killed easily */ + pidfile = fopen(DROPBEAR_PIDFILE, "w"); + if (pidfile) { + fprintf(pidfile, "%d\n", getpid()); + fclose(pidfile); + } + + /* set up cleanup handler */ + if (signal(SIGINT, sigintterm_handler) == SIG_ERR || +#ifndef DEBUG_VALGRIND + signal(SIGTERM, sigintterm_handler) == SIG_ERR || +#endif + signal(SIGPIPE, SIG_IGN) == SIG_ERR) { + dropbear_exit("signal() error"); + } + + /* catch and reap zombie children */ + sa_chld.sa_handler = sigchld_handler; + sa_chld.sa_flags = SA_NOCLDSTOP; + if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) { + dropbear_exit("signal() error"); + } + if (signal(SIGSEGV, sigsegv_handler) == SIG_ERR) { + dropbear_exit("signal() error"); + } + + /* sockets to identify pre-authenticated clients */ + for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { + childpipes[i] = -1; + } + + /* Set up the listening sockets */ + /* XXX XXX ports */ + listensockcount = listensockets(listensocks, &maxsock); + + /* incoming connection select loop */ + for(;;) { + + FD_ZERO(&fds); + + seltimeout.tv_sec = 60; + seltimeout.tv_usec = 0; + + /* listening sockets */ + for (i = 0; i < listensockcount; i++) { + FD_SET(listensocks[i], &fds); + } + + /* pre-authentication clients */ + for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { + if (childpipes[i] >= 0) { + FD_SET(childpipes[i], &fds); + maxsock = MAX(maxsock, childpipes[i]); + } + } + + val = select(maxsock+1, &fds, NULL, NULL, &seltimeout); + + if (exitflag) { + unlink(DROPBEAR_PIDFILE); + dropbear_exit("Terminated by signal"); + } + + if (val == 0) { + /* timeout reached */ + continue; + } + + if (val < 0) { + if (errno == EINTR) { + continue; + } + dropbear_exit("Listening socket error"); + } + + /* close fds which have been authed or closed - auth.c handles + * closing the auth sockets on success */ + for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) { + if (childpipes[i] >= 0 && FD_ISSET(childpipes[i], &fds)) { + close(childpipes[i]); + childpipes[i] = -1; + } + } + + /* handle each socket which has something to say */ + for (i = 0; i < listensockcount; i++) { + if (!FD_ISSET(listensocks[i], &fds)) + continue; + + /* child connection XXX - ip6 stuff here */ + remoteaddrlen = sizeof(struct sockaddr_in); + childsock = accept(listensocks[i], &remoteaddr, &remoteaddrlen); + + if (childsock < 0) { + /* accept failed */ + continue; + } + + /* check for max number of connections not authorised */ + for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) { + if (childpipes[j] < 0) { + break; + } + } + + if (j == MAX_UNAUTH_CLIENTS) { + /* no free connections */ + /* TODO - possibly log, though this would be an easy way + * to fill logs/disk */ + close(childsock); + continue; + } + + if (pipe(childpipe) < 0) { + TRACE(("error creating child pipe")); + close(childsock); + continue; + } + + if ((childpid = fork()) == 0) { + + /* child */ + char * addrstring = NULL; +#ifdef DEBUG_FORKGPROF + extern void _start(void), etext(void); + monstartup((u_long)&_start, (u_long)&etext); +#endif /* DEBUG_FORKGPROF */ + + addrstring = getaddrstring(&remoteaddr); + dropbear_log(LOG_INFO, "Child connection from %s", addrstring); + m_free(addrstring); + + if (setsid() < 0) { + dropbear_exit("setsid: %s", strerror(errno)); + } + + /* make sure we close sockets */ + for (i = 0; i < listensockcount; i++) { + if (m_close(listensocks[i]) == DROPBEAR_FAILURE) { + dropbear_exit("Couldn't close socket"); + } + } + + if (m_close(childpipe[0]) == DROPBEAR_FAILURE) { + dropbear_exit("Couldn't close socket"); + } + + /* start the session */ + svr_session(childsock, childpipe[1], + getaddrhostname(&remoteaddr)); + /* don't return */ + assert(0); + } + + /* parent */ + childpipes[j] = childpipe[0]; + if (m_close(childpipe[1]) == DROPBEAR_FAILURE + || m_close(childsock) == DROPBEAR_FAILURE) { + dropbear_exit("Couldn't close socket"); + } + } + } /* for(;;) loop */ + + /* don't reach here */ + return -1; +} +#endif + +/* catch + reap zombie children */ +static void sigchld_handler(int fish) { + struct sigaction sa_chld; + + while(waitpid(-1, NULL, WNOHANG) > 0); + + sa_chld.sa_handler = sigchld_handler; + sa_chld.sa_flags = SA_NOCLDSTOP; + if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) { + dropbear_exit("signal() error"); + } +} + +/* catch any segvs */ +static void sigsegv_handler(int fish) { + fprintf(stderr, "Aiee, segfault! You should probably report " + "this as a bug to the developer\n"); + exit(EXIT_FAILURE); +} + +/* catch ctrl-c or sigterm */ +static void sigintterm_handler(int fish) { + + exitflag = 1; +} + +/* Set up listening sockets for all the requested ports */ +static int listensockets(int *sock, int *maxfd) { + + int listensock; /* listening fd */ + struct sockaddr_in listen_addr; + struct linger linger; + unsigned int i; + int val; + + for (i = 0; i < svr_opts.portcount; i++) { + + /* iterate through all the sockets to listen on */ + listensock = socket(PF_INET, SOCK_STREAM, 0); + if (listensock < 0) { + dropbear_exit("Failed to create socket"); + } + + val = 1; + /* set to reuse, quick timeout */ + setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, + (void*) &val, sizeof(val)); + linger.l_onoff = 1; + linger.l_linger = 5; + setsockopt(listensock, SOL_SOCKET, SO_LINGER, + (void*)&linger, sizeof(linger)); + + /* disable nagle */ + setsockopt(listensock, IPPROTO_TCP, TCP_NODELAY, + (void*)&val, sizeof(val)); + + memset((void*)&listen_addr, 0x0, sizeof(listen_addr)); + listen_addr.sin_family = AF_INET; + listen_addr.sin_port = htons(svr_opts.ports[i]); + listen_addr.sin_addr.s_addr = htonl(INADDR_ANY); + memset(&(listen_addr.sin_zero), '\0', 8); + + if (bind(listensock, (struct sockaddr *)&listen_addr, + sizeof(listen_addr)) < 0) { + dropbear_exit("Bind failed port %d", svr_opts.ports[i]); + } + + /* listen */ + if (listen(listensock, 20) < 0) { /* TODO set listen count */ + dropbear_exit("Listen failed"); + } + + /* nonblock */ + if (fcntl(listensock, F_SETFL, O_NONBLOCK) < 0) { + dropbear_exit("Failed to set non-blocking"); + } + + sock[i] = listensock; + *maxfd = MAX(listensock, *maxfd); + } + + return svr_opts.portcount; +} -- cgit v1.2.3 From d244f750fc12fabec886a6bbf9a56c428579f3dc Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 27 Jul 2004 14:54:25 +0000 Subject: removed some test targets --HG-- extra : convert_revision : 955ad253022493b8edc121802529f014b9aac505 --- Makefile.in | 6 ------ 1 file changed, 6 deletions(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index fcaa6f2..0d2fc31 100644 --- a/Makefile.in +++ b/Makefile.in @@ -110,9 +110,6 @@ endif all: $(TARGETS) -test: - @echo Z$(sort $(foreach prog, $(PROGRAMS), $($(prog)objs)))Z - strip: $(TARGETS) $(STRIP) $(addsuffix $(EXEEXT), $(addprefix $(SPREFIX), $(TARGETS))) @@ -158,9 +155,6 @@ ifeq ($(MULTI),1) CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI endif -testfoo: - echo $(MULTIOBJS) - dropbearmulti: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) $(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $(MULTIOBJS) $(LIBS) @echo -- cgit v1.2.3 From 052bf7df933634688ccfd89efeec7f29aa628510 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 27 Jul 2004 15:12:29 +0000 Subject: forgot to include libtomcrypt dir --HG-- extra : convert_revision : c936c6ac2910e212338966955bc0fb337b31f915 --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 0d2fc31..645da6d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -64,7 +64,7 @@ AR=@AR@ RANLIB=@RANLIB@ STRIP=@STRIP@ INSTALL=@INSTALL@ -CFLAGS=@CFLAGS@ +CFLAGS=-Ilibtomcrypt @CFLAGS@ LIBS=$(LTC) $(LTM) @LIBS@ LDFLAGS=@LDFLAGS@ -- cgit v1.2.3 From a76b1ba06868c1743837a5267efcbf2e07c9d81d Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 27 Jul 2004 16:30:46 +0000 Subject: Progressing client support --HG-- extra : convert_revision : 48946be1cef774d1c33b0f78689962b18720c627 --- Makefile.in | 13 ++--- auth.h | 30 +++++++++-- cli-auth.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ cli-authpasswd.c | 36 +++++++++++++ cli-kex.c | 1 + cli-main.c | 49 +++++++++++++++++- cli-service.c | 62 +++++++++++++++++++++++ cli-session.c | 92 +++++++++++++++++++++++++++------ common-kex.c | 42 +++++++++------- common-runopts.c | 28 +++++++++++ common-session.c | 6 +-- dbmulti.c | 8 +++ debug.h | 2 +- kex.h | 9 ++-- options.h | 23 ++------- packet.c | 6 +-- runopts.h | 6 ++- scp.c | 7 ++- service.h | 3 +- session.h | 38 ++++++++++---- svr-agentfwd.c | 8 +-- svr-auth.c | 72 +++++++++++++------------- svr-authpasswd.c | 12 ++--- svr-authpubkey.c | 22 ++++---- svr-chansession.c | 32 ++++++------ svr-runopts.c | 4 +- svr-service.c | 3 +- svr-session.c | 13 ++--- 28 files changed, 599 insertions(+), 176 deletions(-) create mode 100644 cli-auth.c create mode 100644 cli-authpasswd.c create mode 100644 cli-service.c create mode 100644 common-runopts.c (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 645da6d..b8de23e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -27,7 +27,7 @@ SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ - cli-session.o cli-service.o + cli-session.o cli-service.o cli-runopts.o CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \ common-channel.o common-chansession.o termcodes.o loginrec.o \ @@ -140,11 +140,12 @@ dbclient: $(dbclientobjs) dropbearkey: $(dropbearkeyobjs) dropbearconvert: $(dropbearconvertobjs) -dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LTC) $(LTM) +dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LTC) $(LTM) \ + Makefile $(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $($@objs) $(LIBS) # scp doesn't use the libs so is special. -scp: $(SCPOBJS) $(HEADERS) +scp: $(SCPOBJS) $(HEADERS) Makefile $(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $(SCPOBJS) @@ -155,16 +156,16 @@ ifeq ($(MULTI),1) CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI endif -dropbearmulti: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) +dropbearmulti: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) Makefile $(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $(MULTIOBJS) $(LIBS) @echo @echo "You should now create symlinks to the programs you have included" @echo "ie 'ln -s dropbearmulti dropbear'" -$(LTC): $(HEADERS) +$(LTC): options.h cd libtomcrypt && $(MAKE) clean && $(MAKE) -$(LTM): $(HEADERS) +$(LTM): options.h cd libtommath && $(MAKE) ltc-clean: diff --git a/auth.h b/auth.h index 8d2db3e..df8ae0c 100644 --- a/auth.h +++ b/auth.h @@ -27,12 +27,28 @@ #include "includes.h" -void authinitialise(); +void svr_authinitialise(); +void cli_authinitialise(); +void svr_auth_password(); +void svr_auth_pubkey(); + +int cli_auth_password(); +int cli_auth_pubkey(); + +/* Server functions */ void recv_msg_userauth_request(); void send_msg_userauth_failure(int partial, int incrfail); void send_msg_userauth_success(); +/* Client functions */ +void recv_msg_userauth_failure(); +void recv_msg_userauth_success(); +void cli_get_user(); +void cli_auth_getmethods(); +void cli_auth_try(); + + #define MAX_USERNAME_LEN 25 /* arbitrary for the moment */ #define AUTH_TYPE_PUBKEY 1 << 0 @@ -46,17 +62,23 @@ void send_msg_userauth_success(); #define AUTH_METHOD_PASSWORD "password" #define AUTH_METHOD_PASSWORD_LEN 8 +/* This structure is shared between server and client - it contains + * relatively little extraneous bits when used for the client rather than the + * server */ struct AuthState { char *username; /* This is the username the client presents to check. It is updated each run through, used for auth checking */ - char *printableuser; /* stripped of control chars, used for logs etc */ - struct passwd * pw; unsigned char authtypes; /* Flags indicating which auth types are still valid */ unsigned int failcount; /* Number of (failed) authentication attempts.*/ - unsigned authdone : 1; /* 0 if we haven't authed, 1 if we have */ + unsigned authdone : 1; /* 0 if we haven't authed, 1 if we have. Applies for + client and server (though has differing [obvious] + meanings). */ + /* These are only used for the server */ + char *printableuser; /* stripped of control chars, used for logs etc */ + struct passwd * pw; }; diff --git a/cli-auth.c b/cli-auth.c new file mode 100644 index 0000000..952546e --- /dev/null +++ b/cli-auth.c @@ -0,0 +1,148 @@ +#include "includes.h" +#include "session.h" +#include "auth.h" +#include "dbutil.h" +#include "buffer.h" +#include "ssh.h" +#include "packet.h" +#include "runopts.h" + +void cli_authinitialise() { + + memset(&ses.authstate, 0, sizeof(ses.authstate)); +} + + +void cli_get_user() { + + uid_t uid; + struct passwd *pw; + + TRACE(("enter cli_get_user")); + if (cli_opts.username != NULL) { + ses.authstate.username = cli_opts.username; + } else { + uid = getuid(); + + pw = getpwuid(uid); + if (pw == NULL || pw->pw_name == NULL) { + dropbear_exit("Couldn't find username for current user"); + } + + ses.authstate.username = m_strdup(pw->pw_name); + } + TRACE(("leave cli_get_user: %s", cli_ses.username)); +} + +/* Send a "none" auth request to get available methods */ +void cli_auth_getmethods() { + + TRACE(("enter cli_auth_getmethods")); + + CHECKCLEARTOWRITE(); + + buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST); + buf_putstring(ses.writepayload, ses.authstate.username, + strlen(ses.authstate.username)); + buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION, + SSH_SERVICE_CONNECTION_LEN); + buf_putstring(ses.writepayload, "none", 4); /* 'none' method */ + + encrypt_packet(); + cli_ses.state = USERAUTH_METHODS_SENT; + TRACE(("leave cli_auth_getmethods")); + +} + +void recv_msg_userauth_failure() { + + unsigned char * methods = NULL; + unsigned char * tok = NULL; + unsigned int methlen = 0; + unsigned int partial = 0; + unsigned int i = 0; + + TRACE(("<- MSG_USERAUTH_FAILURE")); + TRACE(("enter recv_msg_userauth_failure")); + + methods = buf_getstring(ses.payload, &methlen); + + partial = buf_getbyte(ses.payload); + + if (partial) { + dropbear_log(LOG_INFO, "Authentication partially succeeded, more attempts required"); + } else { + ses.authstate.failcount++; + } + + TRACE(("Methods (len %d): '%s'", methlen, methods)); + + ses.authstate.authdone=0; + ses.authstate.authtypes=0; + + /* Split with nulls rather than commas */ + for (i = 0; i < methlen; i++) { + if (methods[i] == ',') { + methods[i] = '\0'; + } + } + + tok = methods; /* tok stores the next method we'll compare */ + for (i = 0; i <= methlen; i++) { + if (methods[i] == '\0') { + TRACE(("auth method '%s'\n", tok)); +#ifdef DROPBEAR_PUBKEY_AUTH + if (strncmp(AUTH_METHOD_PUBKEY, tok, + AUTH_METHOD_PUBKEY_LEN) == 0) { + ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; + } +#endif +#ifdef DROPBEAR_PASSWORD_AUTH + if (strncmp(AUTH_METHOD_PASSWORD, tok, + AUTH_METHOD_PASSWORD_LEN) == 0) { + ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; + } +#endif + tok = &methods[i]; /* Must make sure we don't use it after + the last loop, since it'll point + to something undefined */ + } + } + + cli_ses.state = USERAUTH_FAIL_RCVD; + + TRACE(("leave recv_msg_userauth_failure")); +} + +void recv_msg_userauth_success() { + TRACE(("received msg_userauth_success")); + ses.authstate.authdone = 1; +} + +void cli_auth_try() { + + TRACE(("enter cli_auth_try")); + int finished = 0; + + CHECKCLEARTOWRITE(); + + /* XXX We hardcode that we try a pubkey first */ +#ifdef DROPBEAR_PUBKEY_AUTH + if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) { + finished = cli_auth_pubkey(); + } +#endif + +#ifdef DROPBEAR_PASSWORD_AUTH + if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) { + finished = cli_auth_password(); + } +#endif + + if (!finished) { + dropbear_exit("No auth methods could be used."); + } + + cli_ses.state = USERAUTH_REQ_SENT; + TRACE(("leave cli_auth_try")); +} diff --git a/cli-authpasswd.c b/cli-authpasswd.c new file mode 100644 index 0000000..6185334 --- /dev/null +++ b/cli-authpasswd.c @@ -0,0 +1,36 @@ +#include "includes.h" +#include "buffer.h" +#include "dbutil.h" +#include "session.h" +#include "ssh.h" + +int cli_auth_password() { + + char* password = NULL; + TRACE(("enter cli_auth_password")); + + CHECKCLEARTOWRITE(); + password = getpass("Password: "); + + buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST); + + buf_putstring(ses.writepayload, ses.authstate.username, + strlen(ses.authstate.username)); + + buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION, + SSH_SERVICE_CONNECTION_LEN); + + buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD, + AUTH_METHOD_PASSWORD_LEN); + + buf_putbyte(ses.writepayload, 0); /* FALSE - so says the spec */ + + buf_putstring(ses.writepayload, password, strlen(password)); + + encrypt_packet(); + m_burn(password, strlen(password)); + + TRACE(("leave cli_auth_password")); + return 1; /* Password auth can always be tried */ + +} diff --git a/cli-kex.c b/cli-kex.c index 4d26332..2577caf 100644 --- a/cli-kex.c +++ b/cli-kex.c @@ -34,6 +34,7 @@ #include "bignum.h" #include "random.h" #include "runopts.h" +#include "signkey.h" diff --git a/cli-main.c b/cli-main.c index 2460060..c5d5b3e 100644 --- a/cli-main.c +++ b/cli-main.c @@ -1,6 +1,17 @@ -#include +#include "includes.h" +#include "dbutil.h" +#include "runopts.h" +#include "session.h" +static void cli_dropbear_exit(int exitcode, const char* format, va_list param); +static void cli_dropbear_log(int priority, const char* format, va_list param); + +#if defined(DBMULTI_dbclient) || !defined(DROPBEAR_MULTI) +#if defined(DBMULTI_dbclient) && defined(DROPBEAR_MULTI) +int cli_main(int argc, char ** argv) { +#else int main(int argc, char ** argv) { +#endif int sock; char* error = NULL; @@ -12,6 +23,9 @@ int main(int argc, char ** argv) { cli_getopts(argc, argv); + TRACE(("user='%s' host='%s' port='%s'", cli_opts.username, + cli_opts.remotehost, cli_opts.remoteport)); + sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport, 0, &error); @@ -23,7 +37,7 @@ int main(int argc, char ** argv) { len = strlen(cli_opts.remotehost); len += 10; /* 16 bit port and leeway*/ hostandport = (char*)m_malloc(len); - snprintf(hostandport, len, "%s%d", + snprintf(hostandport, len, "%s:%s", cli_opts.remotehost, cli_opts.remoteport); cli_session(sock, hostandport); @@ -31,3 +45,34 @@ int main(int argc, char ** argv) { /* not reached */ return -1; } +#endif /* DBMULTI stuff */ + +static void cli_dropbear_exit(int exitcode, const char* format, va_list param) { + + char fmtbuf[300]; + + if (!sessinitdone) { + snprintf(fmtbuf, sizeof(fmtbuf), "exited: %s", + format); + } else { + snprintf(fmtbuf, sizeof(fmtbuf), + "connection to %s@%s:%s exited: %s", + cli_opts.username, cli_opts.remotehost, + cli_opts.remoteport, format); + } + + _dropbear_log(LOG_INFO, fmtbuf, param); + + common_session_cleanup(); + exit(exitcode); +} + +static void cli_dropbear_log(int priority, const char* format, va_list param) { + + char printbuf[1024]; + + vsnprintf(printbuf, sizeof(printbuf), format, param); + + fprintf(stderr, "Dropbear: %s\n", printbuf); + +} diff --git a/cli-service.c b/cli-service.c new file mode 100644 index 0000000..c873919 --- /dev/null +++ b/cli-service.c @@ -0,0 +1,62 @@ +#include "includes.h" +#include "service.h" +#include "dbutil.h" +#include "packet.h" +#include "buffer.h" +#include "session.h" +#include "ssh.h" + +void send_msg_service_request(char* servicename) { + + TRACE(("enter send_msg_service_request: servicename='%s'", servicename)); + + CHECKCLEARTOWRITE(); + + buf_putbyte(ses.payload, SSH_MSG_SERVICE_REQUEST); + buf_putstring(ses.payload, servicename, strlen(servicename)); + + encrypt_packet(); + TRACE(("leave send_msg_service_request")); +} + +/* This just sets up the state variables right for the main client session loop + * to deal with */ +void recv_msg_service_accept() { + + unsigned char* servicename; + unsigned int len; + + TRACE(("enter recv_msg_service_accept")); + + servicename = buf_getstring(ses.payload, &len); + + /* ssh-userauth */ + if (cli_ses.state = SERVICE_AUTH_REQ_SENT + && len == SSH_SERVICE_USERAUTH_LEN + && strncmp(SSH_SERVICE_USERAUTH, servicename, len) == 0) { + + cli_ses.state = SERVICE_AUTH_ACCEPT_RCVD; + m_free(servicename); + TRACE(("leave recv_msg_service_accept: done ssh-userauth")); + return; + } + + /* ssh-connection */ + if (cli_ses.state = SERVICE_CONN_REQ_SENT + && len == SSH_SERVICE_CONNECTION_LEN + && strncmp(SSH_SERVICE_CONNECTION, servicename, len) == 0) { + + if (ses.authstate.authdone != 1) { + dropbear_exit("request for connection before auth"); + } + + cli_ses.state = SERVICE_CONN_ACCEPT_RCVD; + m_free(servicename); + TRACE(("leave recv_msg_service_accept: done ssh-connection")); + return; + } + + dropbear_exit("unrecognised service accept"); + /* m_free(servicename); not reached */ + +} diff --git a/cli-session.c b/cli-session.c index d5afaf9..9f80bd1 100644 --- a/cli-session.c +++ b/cli-session.c @@ -8,9 +8,11 @@ #include "tcpfwd-remote.h" #include "channel.h" #include "random.h" +#include "service.h" static void cli_remoteclosed(); static void cli_sessionloop(); +static void cli_session_init(); struct clientsession cli_ses; /* GLOBAL */ @@ -28,6 +30,8 @@ static const packettype cli_packettypes[] = { {SSH_MSG_CHANNEL_CLOSE, recv_msg_channel_close}, {SSH_MSG_CHANNEL_OPEN_CONFIRMATION, recv_msg_channel_open_confirmation}, {SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure}, + {SSH_MSG_USERAUTH_FAILURE, recv_msg_userauth_failure}, + {SSH_MSG_USERAUTH_SUCCESS, recv_msg_userauth_success}, {0, 0} /* End */ }; @@ -37,6 +41,7 @@ static const struct ChanType *cli_chantypes[] = { * that forwarding */ NULL /* Null termination */ }; + void cli_session(int sock, char* remotehost) { crypto_init(); @@ -44,11 +49,9 @@ void cli_session(int sock, char* remotehost) { chaninitialise(cli_chantypes); - /* For printing "remote host closed" for the user */ - session_remoteclosed = cli_remoteclosed; - /* packet handlers */ - ses.packettypes = cli_packettypes; + /* Set up cli_ses vars */ + cli_session_init(); /* Ready to go */ sessinitdone = 1; @@ -66,26 +69,85 @@ void cli_session(int sock, char* remotehost) { /* Not reached */ +} + +static void cli_session_init() { + cli_ses.state = STATE_NOTHING; + cli_ses.kex_state = KEX_NOTHING; + + /* For printing "remote host closed" for the user */ + ses.remoteclosed = cli_remoteclosed; + ses.buf_match_algo = cli_buf_match_algo; + + /* packet handlers */ + ses.packettypes = cli_packettypes; } +/* This function drives the progress of the session - it initiates KEX, + * service, userauth and channel requests */ static void cli_sessionloop() { - switch (cli_ses.state) { + TRACE(("enter cli_sessionloop")); + + if (cli_ses.kex_state == KEX_NOTHING && ses.kexstate.recvkexinit) { + cli_ses.state = KEXINIT_RCVD; + } - KEXINIT_RCVD: - /* We initiate the KEX. If DH wasn't the correct type, the KEXINIT - * negotiation would have failed. */ - send_msg_kexdh_init(); - cli_ses.state = KEXDH_INIT_SENT; - break; + if (cli_ses.state == KEXINIT_RCVD) { - default: - break; + /* We initiate the KEXDH. If DH wasn't the correct type, the KEXINIT + * negotiation would have failed. */ + send_msg_kexdh_init(); + cli_ses.kex_state = KEXDH_INIT_SENT; + TRACE(("leave cli_sessionloop: done with KEXINIT_RCVD")); + return; } - if (cli_ses.donefirstkex && !cli_ses.authdone) { + /* A KEX has finished, so we should go back to our KEX_NOTHING state */ + if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.recvkexinit == 0 + && ses.kexstate.sentkexinit == 0) { + cli_ses.kex_state = KEX_NOTHING; + } + + /* We shouldn't do anything else if a KEX is in progress */ + if (cli_ses.kex_state != KEX_NOTHING) { + TRACE(("leave cli_sessionloop: kex_state != KEX_NOTHING")); + return; + } + /* We should exit if we haven't donefirstkex: we shouldn't reach here + * in normal operation */ + if (ses.kexstate.donefirstkex == 0) { + TRACE(("XXX XXX might be bad! leave cli_sessionloop: haven't donefirstkex")); + } + + switch (cli_ses.state) { + + case STATE_NOTHING: + /* We've got the transport layer sorted, we now need to request + * userauth */ + send_msg_service_request(SSH_SERVICE_USERAUTH); + cli_ses.state = SERVICE_AUTH_REQ_SENT; + return; + + /* userauth code */ + case SERVICE_AUTH_ACCEPT_RCVD: + cli_get_user(); + cli_auth_getmethods(); + cli_ses.state = USERAUTH_METHODS_SENT; + return; + + case USERAUTH_FAIL_RCVD: + cli_auth_try(); + return; + + /* XXX more here needed */ + + + default: + break; + } } @@ -97,5 +159,5 @@ static void cli_remoteclosed() { * already sent/received disconnect message(s) ??? */ close(ses.sock); ses.sock = -1; - dropbear_exit("%s closed the connection", ses.remotehost); + dropbear_exit("remote closed the connection"); } diff --git a/common-kex.c b/common-kex.c index 21accb6..9847a48 100644 --- a/common-kex.c +++ b/common-kex.c @@ -5,7 +5,7 @@ * This code is copied from the larger file "kex.c" * some functions are verbatim, others are generalized --mihnea * - * Copyright (c) 2002,2003 Matt Johnston + * Copyright (c) 2002-2004 Matt Johnston * Portions Copyright (c) 2004 by Mihnea Stoenescu * All rights reserved. * @@ -54,10 +54,12 @@ const unsigned char dh_p_val[] = { const int DH_G_VAL = 2; +static void kexinitialise(); static void gen_new_keys(); #ifndef DISABLE_ZLIB static void gen_new_zstreams(); #endif +static void read_kex_algos(); /* helper function for gen_new_keys */ static void hashkeys(unsigned char *out, int outlen, const hash_state * hs, unsigned const char X); @@ -145,6 +147,7 @@ void send_msg_newkeys() { kexinitialise(); /* we've finished with this kex */ TRACE((" -> DATAALLOWED=1")); ses.dataallowed = 1; /* we can send other packets again now */ + ses.kexstate.donefirstkex = 1; } else { ses.kexstate.sentnewkeys = 1; TRACE(("SENTNEWKEYS=1")); @@ -168,6 +171,7 @@ void recv_msg_newkeys() { kexinitialise(); /* we've finished with this kex */ TRACE((" -> DATAALLOWED=1")); ses.dataallowed = 1; /* we can send other packets again now */ + ses.kexstate.donefirstkex = 1; } else { TRACE(("RECVNEWKEYS=1")); ses.kexstate.recvnewkeys = 1; @@ -177,8 +181,15 @@ void recv_msg_newkeys() { } -/* Duplicated verbatim from kex.c --mihnea */ -void kexinitialise() { +/* Set up the kex for the first time */ +void kexfirstinitialise() { + + ses.kexstate.donefirstkex = 0; + kexinitialise(); +} + +/* Reset the kex state, ready for a new negotiation */ +static void kexinitialise() { struct timeval tv; @@ -404,7 +415,7 @@ void recv_msg_kexinit() { #ifdef DROPBEAR_CLIENT /* read the peer's choice of algos */ - read_kex_algos(cli_buf_match_algo); + read_kex_algos(); /* V_C, the client's version string (CR and NL excluded) */ buf_putstring(ses.kexhashbuf, @@ -423,14 +434,13 @@ void recv_msg_kexinit() { buf_getptr(ses.payload, ses.payload->len), ses.payload->len); - cli_ses.state = KEXINIT_RCVD; #endif } else { /* SERVER */ #ifdef DROPBEAR_SERVER /* read the peer's choice of algos */ - read_kex_algos(svr_buf_match_algo); + read_kex_algos(); /* V_C, the client's version string (CR and NL excluded) */ buf_putstring(ses.kexhashbuf, ses.remoteident, strlen((char*)ses.remoteident)); @@ -583,9 +593,7 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them, /* read the other side's algo list. buf_match_algo is a callback to match * algos for the client or server. */ -void read_kex_algos( - algo_type*(buf_match_algo)(buffer*buf, algo_type localalgos[], - int *goodguess)) { +static void read_kex_algos() { algo_type * algo; char * erralgo = NULL; @@ -599,7 +607,7 @@ void read_kex_algos( ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context)); /* kex_algorithms */ - algo = buf_match_algo(ses.payload, sshkex, &goodguess); + algo = ses.buf_match_algo(ses.payload, sshkex, &goodguess); allgood &= goodguess; if (algo == NULL) { erralgo = "kex"; @@ -608,7 +616,7 @@ void read_kex_algos( ses.newkeys->algo_kex = algo->val; /* server_host_key_algorithms */ - algo = buf_match_algo(ses.payload, sshhostkey, &goodguess); + algo = ses.buf_match_algo(ses.payload, sshhostkey, &goodguess); allgood &= goodguess; if (algo == NULL) { erralgo = "hostkey"; @@ -617,7 +625,7 @@ void read_kex_algos( ses.newkeys->algo_hostkey = algo->val; /* encryption_algorithms_client_to_server */ - algo = buf_match_algo(ses.payload, sshciphers, &goodguess); + algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess); if (algo == NULL) { erralgo = "enc c->s"; goto error; @@ -625,7 +633,7 @@ void read_kex_algos( ses.newkeys->recv_algo_crypt = (struct dropbear_cipher*)algo->data; /* encryption_algorithms_server_to_client */ - algo = buf_match_algo(ses.payload, sshciphers, &goodguess); + algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess); if (algo == NULL) { erralgo = "enc s->c"; goto error; @@ -633,7 +641,7 @@ void read_kex_algos( ses.newkeys->trans_algo_crypt = (struct dropbear_cipher*)algo->data; /* mac_algorithms_client_to_server */ - algo = buf_match_algo(ses.payload, sshhashes, &goodguess); + algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess); if (algo == NULL) { erralgo = "mac c->s"; goto error; @@ -641,7 +649,7 @@ void read_kex_algos( ses.newkeys->recv_algo_mac = (struct dropbear_hash*)algo->data; /* mac_algorithms_server_to_client */ - algo = buf_match_algo(ses.payload, sshhashes, &goodguess); + algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess); if (algo == NULL) { erralgo = "mac s->c"; goto error; @@ -649,7 +657,7 @@ void read_kex_algos( ses.newkeys->trans_algo_mac = (struct dropbear_hash*)algo->data; /* compression_algorithms_client_to_server */ - algo = buf_match_algo(ses.payload, sshcompress, &goodguess); + algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess); if (algo == NULL) { erralgo = "comp c->s"; goto error; @@ -657,7 +665,7 @@ void read_kex_algos( ses.newkeys->recv_algo_comp = algo->val; /* compression_algorithms_server_to_client */ - algo = buf_match_algo(ses.payload, sshcompress, &goodguess); + algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess); if (algo == NULL) { erralgo = "comp s->c"; goto error; diff --git a/common-runopts.c b/common-runopts.c new file mode 100644 index 0000000..097ab12 --- /dev/null +++ b/common-runopts.c @@ -0,0 +1,28 @@ +/* + * 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" +#include "runopts.h" + +runopts opts; /* GLOBAL */ diff --git a/common-session.c b/common-session.c index 70ddbfe..93e7c74 100644 --- a/common-session.c +++ b/common-session.c @@ -45,8 +45,6 @@ int sessinitdone = 0; /* GLOBAL */ /* this is set when we get SIGINT or SIGTERM, the handler is in main.c */ int exitflag = 0; /* GLOBAL */ -void(*session_remoteclosed)() = NULL; - static void checktimeouts(); static int ident_readln(int fd, char* buf, int count); @@ -63,7 +61,7 @@ void common_session_init(int sock, char* remotehost) { ses.connecttimeout = 0; - kexinitialise(); /* initialise the kex state */ + kexfirstinitialise(); /* initialise the kex state */ chaninitialise(); /* initialise the channel state */ ses.writepayload = buf_new(MAX_TRANS_PAYLOAD_LEN); @@ -104,8 +102,6 @@ void common_session_init(int sock, char* remotehost) { ses.dh_K = NULL; ses.remoteident = NULL; - ses.authdone = 0; - ses.chantypes = NULL; ses.allowprivport = 0; diff --git a/dbmulti.c b/dbmulti.c index 8f39227..24adce1 100644 --- a/dbmulti.c +++ b/dbmulti.c @@ -19,6 +19,11 @@ int main(int argc, char ** argv) { return dropbear_main(argc, argv); } #endif +#ifdef DBMULTI_dbclient + if (strcmp(progname, "dbclient") == 0) { + return cli_main(argc, argv); + } +#endif #ifdef DBMULTI_dropbearkey if (strcmp(progname, "dropbearkey") == 0) { return dropbearkey_main(argc, argv); @@ -41,6 +46,9 @@ int main(int argc, char ** argv) { #ifdef DBMULTI_dropbear "'dropbear' - the Dropbear server\n" #endif +#ifdef DBMULTI_dbclient + "'dbclient' - the Dropbear client\n" +#endif #ifdef DBMULTI_dropbearkey "'dropbearkey' - the key generator\n" #endif diff --git a/debug.h b/debug.h index 736690a..d619a58 100644 --- a/debug.h +++ b/debug.h @@ -36,7 +36,7 @@ /* Define this to print trace statements - very verbose */ /* Caution: Don't use this in an unfriendly environment (ie unfirewalled), * since the printing does not sanitise strings etc */ -//#define DEBUG_TRACE +#define DEBUG_TRACE /* All functions writing to the cleartext payload buffer call * CHECKCLEARTOWRITE() before writing. This is only really useful if you're diff --git a/kex.h b/kex.h index e6c8ac1..01626ed 100644 --- a/kex.h +++ b/kex.h @@ -32,15 +32,11 @@ void send_msg_kexinit(); void recv_msg_kexinit(); void send_msg_newkeys(); void recv_msg_newkeys(); -void kexinitialise(); +void kexfirstinitialise(); void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv); void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them, sign_key *hostkey); -void read_kex_algos( - algo_type*(buf_match_algo)(buffer*buf, algo_type localalgos[], - int *goodguess)); - void recv_msg_kexdh_init(); // server void send_msg_kexdh_init(); // client @@ -59,6 +55,9 @@ struct KEXState { unsigned sentnewkeys : 1; /* set once we've send/recv'ed MSG_NEWKEYS*/ unsigned recvnewkeys : 1; + unsigned donefirstkex : 1; /* Set to 1 after the first kex has completed, + ie the transport layer has been set up */ + long lastkextime; /* time of the last kex */ unsigned int datatrans; /* data transmitted since last kex */ unsigned int datarecv; /* data received since last kex */ diff --git a/options.h b/options.h index 3aeac0f..ee0ee60 100644 --- a/options.h +++ b/options.h @@ -29,8 +29,6 @@ * Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif" * parts are to allow for commandline -DDROPBEAR_XXX options etc. ******************************************************************/ -#define DROPBEAR_SERVER -//#define DROPBEAR_CLIENT #ifndef DROPBEAR_PORT #define DROPBEAR_PORT 22 @@ -48,7 +46,6 @@ * perhaps 20% slower for pubkey operations (it is probably worth experimenting * if you want to use this) */ /*#define NO_FAST_EXPTMOD*/ -#define DROPBEAR_SMALL_CODE /* Enable X11 Forwarding */ #define ENABLE_X11FWD @@ -114,7 +111,7 @@ /* Authentication types to enable, at least one required. RFC Draft requires pubkey auth, and recommends password */ #define DROPBEAR_PASSWORD_AUTH -#define DROPBEAR_PUBKEY_AUTH +//#define DROPBEAR_PUBKEY_AUTH /* Random device to use - you must specify _one only_. * DEV_RANDOM is recommended on hosts with a good /dev/urandom, otherwise use @@ -162,20 +159,8 @@ /* This is used by the scp binary when used as a client binary */ #define _PATH_SSH_PROGRAM "/usr/bin/ssh" -/* Multi-purpose binary configuration - if you want to make the combined - * binary, first define DROPBEAR_MULTI, and then define which of the three - * components you want. You should then compile Dropbear with - * "make clean; make dropbearmulti". You'll need to install the binary - * manually, see MULTI for details */ - -/* #define DROPBEAR_MULTI */ - -/* The three multi binaries: dropbear, dropbearkey, dropbearconvert - * Comment out these if you don't want some of them */ -#define DBMULTI_DROPBEAR -#define DBMULTI_KEY -#define DBMULTI_CONVERT - +/* Multi-purpose binary configuration has now moved. Look at the top + * of the Makefile for instructions, or INSTALL */ /******************************************************************* * You shouldn't edit below here unless you know you need to. @@ -246,7 +231,7 @@ #define DROPBEAR_COMP_ZLIB 1 /* Required for pubkey auth */ -#ifdef DROPBEAR_PUBKEY_AUTH +#if defined(DROPBEAR_PUBKEY_AUTH) || defined(DROPBEAR_CLIENT) #define DROPBEAR_SIGNKEY_VERIFY #endif diff --git a/packet.c b/packet.c index 886fe67..997bc6f 100644 --- a/packet.c +++ b/packet.c @@ -73,7 +73,7 @@ void write_packet() { } if (written == 0) { - session_remoteclosed(); + ses.remoteclosed(); } if (written == len) { @@ -122,7 +122,7 @@ void read_packet() { len = read(ses.sock, buf_getptr(ses.readbuf, maxlen), maxlen); if (len == 0) { - session_remoteclosed(); + ses.remoteclosed(); } if (len < 0) { @@ -171,7 +171,7 @@ static void read_packet_init() { len = read(ses.sock, buf_getwriteptr(ses.readbuf, maxlen), maxlen); if (len == 0) { - session_remoteclosed(); + ses.remoteclosed(); } if (len < 0) { if (errno == EINTR) { diff --git a/runopts.h b/runopts.h index 1bf1539..125d737 100644 --- a/runopts.h +++ b/runopts.h @@ -79,7 +79,11 @@ void svr_getopts(int argc, char ** argv); /* Uncompleted XXX matt */ typedef struct cli_runopts { - int todo; + char *remotehost; + char *remoteport; + + char *username; + /* XXX TODO */ } cli_runopts; diff --git a/scp.c b/scp.c index b23dec6..b6eec88 100644 --- a/scp.c +++ b/scp.c @@ -229,8 +229,12 @@ void tolocal(int, char *[]); void toremote(char *, int, char *[]); void usage(void); -int +#if defined(DBMULTI_scp) || !defined(DROPBEAR_MULTI) +#if defined(DBMULTI_scp) && defined(DROPBEAR_MULTI) +int scp_main(int argc, char **argv) +#else main(int argc, char **argv) +#endif { int ch, fflag, tflag, status; double speed; @@ -379,6 +383,7 @@ main(int argc, char **argv) } exit(errs != 0); } +#endif /* DBMULTI stuff */ void toremote(char *targ, int argc, char **argv) diff --git a/service.h b/service.h index 0dfcd6e..5f50347 100644 --- a/service.h +++ b/service.h @@ -25,6 +25,7 @@ #ifndef _SERVICE_H_ #define _SERVICE_H_ -void recv_msg_service_request(); +void recv_msg_service_request(); /* Server */ +void send_msg_service_request(); /* Client */ #endif /* _SERVICE_H_ */ diff --git a/session.h b/session.h index d929c1c..4a7e0ac 100644 --- a/session.h +++ b/session.h @@ -45,7 +45,6 @@ void common_session_cleanup(); void checktimeouts(); void session_identification(); -extern void(*session_remoteclosed)(); /* Server */ void svr_session(int sock, int childpipe, char *remotehost); @@ -135,13 +134,18 @@ struct sshsession { buffer* transkexinit; /* the kexinit packet we send should be kept so we can add it to the hash when generating keys */ + algo_type*(*buf_match_algo)(buffer*buf, algo_type localalgos[], + int *goodguess); /* The function to use to choose which algorithm + to use from the ones presented by the remote + side. Is specific to the client/server mode, + hence the function-pointer callback.*/ - unsigned char authdone; /* Indicates when authentication has been - completed. This applies to both client and - server - in the server it gets set to 1 when - authentication is successful, in the client it - is set when the server has told us that auth - succeeded */ + void(*remoteclosed)(); /* A callback to handle closure of the + remote connection */ + + + struct AuthState authstate; /* Common amongst client and server, since most + struct elements are common */ /* Channel related */ struct Channel ** channels; /* these pointers may be null */ @@ -165,7 +169,6 @@ struct serversession { /* Server specific options */ int childpipe; /* kept open until we successfully authenticate */ /* userauth */ - struct AuthState authstate; struct ChildPid * childpids; /* array of mappings childpid<->channel */ unsigned int childpidsize; @@ -173,17 +176,30 @@ struct serversession { }; typedef enum { - NOTHING, + KEX_NOTHING, KEXINIT_RCVD, KEXDH_INIT_SENT, - KEXDH_REPLY_RCVD, + KEXDONE, + +} cli_kex_state; + +typedef enum { + STATE_NOTHING, + SERVICE_AUTH_REQ_SENT, + SERVICE_AUTH_ACCEPT_RCVD, + SERVICE_CONN_REQ_SENT, + SERVICE_CONN_ACCEPT_RCVD, + USERAUTH_METHODS_SENT, + USERAUTH_REQ_SENT, + USERAUTH_FAIL_RCVD, } cli_state; struct clientsession { mp_int *dh_e, *dh_x; /* Used during KEX */ - cli_state state; /* Used to progress the KEX/auth/channelsession etc */ + cli_kex_state kex_state; /* Used for progressing KEX */ + cli_state state; /* Used to progress auth/channelsession etc */ int something; /* XXX */ unsigned donefirstkex : 1; /* Set when we set sentnewkeys, never reset */ diff --git a/svr-agentfwd.c b/svr-agentfwd.c index fd068fe..0dad2a4 100644 --- a/svr-agentfwd.c +++ b/svr-agentfwd.c @@ -152,8 +152,8 @@ void agentcleanup(struct ChanSess * chansess) { * for themselves */ uid = getuid(); gid = getgid(); - if ((setegid(svr_ses.authstate.pw->pw_gid)) < 0 || - (seteuid(svr_ses.authstate.pw->pw_uid)) < 0) { + if ((setegid(ses.authstate.pw->pw_gid)) < 0 || + (seteuid(ses.authstate.pw->pw_uid)) < 0) { dropbear_exit("failed to set euid"); } @@ -215,8 +215,8 @@ static int bindagent(int fd, struct ChanSess * chansess) { /* drop to user privs to make the dir/file */ uid = getuid(); gid = getgid(); - if ((setegid(svr_ses.authstate.pw->pw_gid)) < 0 || - (seteuid(svr_ses.authstate.pw->pw_uid)) < 0) { + if ((setegid(ses.authstate.pw->pw_gid)) < 0 || + (seteuid(ses.authstate.pw->pw_uid)) < 0) { dropbear_exit("failed to set euid"); } diff --git a/svr-auth.c b/svr-auth.c index 7b588c0..0f0ef67 100644 --- a/svr-auth.c +++ b/svr-auth.c @@ -41,9 +41,9 @@ static int checkusername(unsigned char *username, unsigned int userlen); static void send_msg_userauth_banner(); /* initialise the first time for a session, resetting all parameters */ -void authinitialise() { +void svr_authinitialise() { - svr_ses.authstate.failcount = 0; + ses.authstate.failcount = 0; authclear(); } @@ -53,17 +53,13 @@ void authinitialise() { * on initialisation */ static void authclear() { - ses.authdone = 0; - svr_ses.authstate.pw = NULL; - svr_ses.authstate.username = NULL; - svr_ses.authstate.printableuser = NULL; - svr_ses.authstate.authtypes = 0; + memset(&ses.authstate, 0, sizeof(ses.authstate)); #ifdef DROPBEAR_PUBKEY_AUTH - svr_ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; + ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; #endif #ifdef DROPBEAR_PASSWORD_AUTH if (svr_opts.noauthpass) { - svr_ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; + ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; } #endif @@ -103,7 +99,7 @@ void recv_msg_userauth_request() { TRACE(("enter recv_msg_userauth_request")); /* ignore packets if auth is already done */ - if (ses.authdone == 1) { + if (ses.authstate.authdone == 1) { return; } @@ -147,12 +143,12 @@ void recv_msg_userauth_request() { #ifdef DROPBEAR_PASSWORD_AUTH if (!svr_opts.noauthpass && - !(svr_opts.norootpass && svr_ses.authstate.pw->pw_uid == 0) ) { + !(svr_opts.norootpass && ses.authstate.pw->pw_uid == 0) ) { /* user wants to try password auth */ if (methodlen == AUTH_METHOD_PASSWORD_LEN && strncmp(methodname, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN) == 0) { - passwordauth(); + svr_auth_password(); goto out; } } @@ -163,7 +159,7 @@ void recv_msg_userauth_request() { if (methodlen == AUTH_METHOD_PUBKEY_LEN && strncmp(methodname, AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN) == 0) { - pubkeyauth(); + svr_auth_pubkey(); goto out; } #endif @@ -192,21 +188,21 @@ static int checkusername(unsigned char *username, unsigned int userlen) { } /* new user or username has changed */ - if (svr_ses.authstate.username == NULL || - strcmp(username, svr_ses.authstate.username) != 0) { + if (ses.authstate.username == NULL || + strcmp(username, ses.authstate.username) != 0) { /* the username needs resetting */ - if (svr_ses.authstate.username != NULL) { + if (ses.authstate.username != NULL) { dropbear_log(LOG_WARNING, "client trying multiple usernames"); - m_free(svr_ses.authstate.username); + m_free(ses.authstate.username); } authclear(); - svr_ses.authstate.pw = getpwnam((char*)username); - svr_ses.authstate.username = m_strdup(username); - m_free(svr_ses.authstate.printableuser); + ses.authstate.pw = getpwnam((char*)username); + ses.authstate.username = m_strdup(username); + m_free(ses.authstate.printableuser); } /* check that user exists */ - if (svr_ses.authstate.pw == NULL) { + if (ses.authstate.pw == NULL) { TRACE(("leave checkusername: user '%s' doesn't exist", username)); dropbear_log(LOG_WARNING, "login attempt for nonexistent user"); @@ -215,10 +211,10 @@ static int checkusername(unsigned char *username, unsigned int userlen) { } /* We can set it once we know its a real user */ - svr_ses.authstate.printableuser = m_strdup(svr_ses.authstate.pw->pw_name); + ses.authstate.printableuser = m_strdup(ses.authstate.pw->pw_name); /* check for non-root if desired */ - if (svr_opts.norootlogin && svr_ses.authstate.pw->pw_uid == 0) { + if (svr_opts.norootlogin && ses.authstate.pw->pw_uid == 0) { TRACE(("leave checkusername: root login disabled")); dropbear_log(LOG_WARNING, "root login rejected"); send_msg_userauth_failure(0, 1); @@ -226,18 +222,18 @@ static int checkusername(unsigned char *username, unsigned int userlen) { } /* check for an empty password */ - if (svr_ses.authstate.pw->pw_passwd[0] == '\0') { + if (ses.authstate.pw->pw_passwd[0] == '\0') { TRACE(("leave checkusername: empty pword")); dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected", - svr_ses.authstate.printableuser); + ses.authstate.printableuser); send_msg_userauth_failure(0, 1); return DROPBEAR_FAILURE; } - TRACE(("shell is %s", svr_ses.authstate.pw->pw_shell)); + TRACE(("shell is %s", ses.authstate.pw->pw_shell)); /* check that the shell is set */ - usershell = svr_ses.authstate.pw->pw_shell; + usershell = ses.authstate.pw->pw_shell; if (usershell[0] == '\0') { /* empty shell in /etc/passwd means /bin/sh according to passwd(5) */ usershell = "/bin/sh"; @@ -258,7 +254,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) { endusershell(); TRACE(("no matching shell")); dropbear_log(LOG_WARNING, "user '%s' has invalid shell, rejected", - svr_ses.authstate.printableuser); + ses.authstate.printableuser); send_msg_userauth_failure(0, 1); return DROPBEAR_FAILURE; @@ -266,7 +262,7 @@ goodshell: endusershell(); TRACE(("matching shell")); - TRACE(("uid = %d", svr_ses.authstate.pw->pw_uid)); + TRACE(("uid = %d", ses.authstate.pw->pw_uid)); TRACE(("leave checkusername")); return DROPBEAR_SUCCESS; @@ -290,14 +286,14 @@ void send_msg_userauth_failure(int partial, int incrfail) { /* put a list of allowed types */ typebuf = buf_new(30); /* long enough for PUBKEY and PASSWORD */ - if (svr_ses.authstate.authtypes & AUTH_TYPE_PUBKEY) { + if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) { buf_putbytes(typebuf, AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN); - if (svr_ses.authstate.authtypes & AUTH_TYPE_PASSWORD) { + if (ses.authstate.authtypes & AUTH_TYPE_PASSWORD) { buf_putbyte(typebuf, ','); } } - if (svr_ses.authstate.authtypes & AUTH_TYPE_PASSWORD) { + if (ses.authstate.authtypes & AUTH_TYPE_PASSWORD) { buf_putbytes(typebuf, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN); } @@ -311,18 +307,18 @@ void send_msg_userauth_failure(int partial, int incrfail) { if (incrfail) { usleep(300000); /* XXX improve this */ - svr_ses.authstate.failcount++; + ses.authstate.failcount++; } - if (svr_ses.authstate.failcount >= MAX_AUTH_TRIES) { + if (ses.authstate.failcount >= MAX_AUTH_TRIES) { char * userstr; /* XXX - send disconnect ? */ TRACE(("Max auth tries reached, exiting")); - if (svr_ses.authstate.printableuser == NULL) { + if (ses.authstate.printableuser == NULL) { userstr = "is invalid"; } else { - userstr = svr_ses.authstate.printableuser; + userstr = ses.authstate.printableuser; } dropbear_exit("Max auth tries reached - user %s", userstr); } @@ -340,9 +336,9 @@ void send_msg_userauth_success() { buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_SUCCESS); encrypt_packet(); - ses.authdone = 1; + ses.authstate.authdone = 1; - if (svr_ses.authstate.pw->pw_uid == 0) { + if (ses.authstate.pw->pw_uid == 0) { ses.allowprivport = 1; } diff --git a/svr-authpasswd.c b/svr-authpasswd.c index 859cfd5..f161b69 100644 --- a/svr-authpasswd.c +++ b/svr-authpasswd.c @@ -35,7 +35,7 @@ /* Process a password auth request, sending success or failure messages as * appropriate */ -void passwordauth() { +void svr_auth_password() { #ifdef HAVE_SHADOW_H struct spwd *spasswd; @@ -47,10 +47,10 @@ void passwordauth() { unsigned char changepw; - passwdcrypt = svr_ses.authstate.pw->pw_passwd; + passwdcrypt = ses.authstate.pw->pw_passwd; #ifdef HAVE_SHADOW_H /* get the shadow password if possible */ - spasswd = getspnam(svr_ses.authstate.pw->pw_name); + spasswd = getspnam(ses.authstate.pw->pw_name); if (spasswd != NULL && spasswd->sp_pwdp != NULL) { passwdcrypt = spasswd->sp_pwdp; } @@ -66,7 +66,7 @@ void passwordauth() { * in auth.c */ if (passwdcrypt[0] == '\0') { dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected", - svr_ses.authstate.printableuser); + ses.authstate.printableuser); send_msg_userauth_failure(0, 1); return; } @@ -92,12 +92,12 @@ void passwordauth() { /* successful authentication */ dropbear_log(LOG_NOTICE, "password auth succeeded for '%s'", - svr_ses.authstate.printableuser); + ses.authstate.printableuser); send_msg_userauth_success(); } else { dropbear_log(LOG_WARNING, "bad password attempt for '%s'", - svr_ses.authstate.printableuser); + ses.authstate.printableuser); send_msg_userauth_failure(0, 1); } diff --git a/svr-authpubkey.c b/svr-authpubkey.c index e3e6947..9c58a8d 100644 --- a/svr-authpubkey.c +++ b/svr-authpubkey.c @@ -50,7 +50,7 @@ static int getauthline(buffer * line, FILE * authfile); /* process a pubkey auth request, sending success or failure message as * appropriate */ -void pubkeyauth() { +void svr_auth_pubkey() { unsigned char testkey; /* whether we're just checking if a key is usable */ unsigned char* algo = NULL; /* pubkey algo */ @@ -113,12 +113,12 @@ void pubkeyauth() { signbuf->len) == DROPBEAR_SUCCESS) { dropbear_log(LOG_NOTICE, "pubkey auth succeeded for '%s' with key %s", - svr_ses.authstate.printableuser, fp); + ses.authstate.printableuser, fp); send_msg_userauth_success(); } else { dropbear_log(LOG_WARNING, "pubkey auth bad signature for '%s' with key %s", - svr_ses.authstate.printableuser, fp); + ses.authstate.printableuser, fp); send_msg_userauth_failure(0, 1); } m_free(fp); @@ -178,7 +178,7 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen, if (have_algo(algo, algolen, sshhostkey) == DROPBEAR_FAILURE) { dropbear_log(LOG_WARNING, "pubkey auth attempt with unknown algo for '%s'", - svr_ses.authstate.printableuser); + ses.authstate.printableuser); goto out; } @@ -190,12 +190,12 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen, /* we don't need to check pw and pw_dir for validity, since * its been done in checkpubkeyperms. */ - len = strlen(svr_ses.authstate.pw->pw_dir); + len = strlen(ses.authstate.pw->pw_dir); /* allocate max required pathname storage, * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */ filename = m_malloc(len + 22); snprintf(filename, len + 22, "%s/.ssh/authorized_keys", - svr_ses.authstate.pw->pw_dir); + ses.authstate.pw->pw_dir); /* open the file */ authfile = fopen(filename, "r"); @@ -352,19 +352,19 @@ static int checkpubkeyperms() { TRACE(("enter checkpubkeyperms")); - assert(svr_ses.authstate.pw); - if (svr_ses.authstate.pw->pw_dir == NULL) { + assert(ses.authstate.pw); + if (ses.authstate.pw->pw_dir == NULL) { goto out; } - if ((len = strlen(svr_ses.authstate.pw->pw_dir)) == 0) { + if ((len = strlen(ses.authstate.pw->pw_dir)) == 0) { goto out; } /* allocate max required pathname storage, * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */ filename = m_malloc(len + 22); - strncpy(filename, svr_ses.authstate.pw->pw_dir, len+1); + strncpy(filename, ses.authstate.pw->pw_dir, len+1); /* check ~ */ if (checkfileperm(filename) != DROPBEAR_SUCCESS) { @@ -406,7 +406,7 @@ static int checkfileperm(char * filename) { return DROPBEAR_FAILURE; } /* check ownership - user or root only*/ - if (filestat.st_uid != svr_ses.authstate.pw->pw_uid + if (filestat.st_uid != ses.authstate.pw->pw_uid && filestat.st_uid != 0) { TRACE(("leave checkfileperm: wrong ownership")); return DROPBEAR_FAILURE; diff --git a/svr-chansession.c b/svr-chansession.c index cbc7ebe..50e0a5e 100644 --- a/svr-chansession.c +++ b/svr-chansession.c @@ -239,7 +239,7 @@ static void closechansess(struct Channel *channel) { if (chansess->tty) { /* write the utmp/wtmp login record */ - li = login_alloc_entry(chansess->pid, svr_ses.authstate.username, + li = login_alloc_entry(chansess->pid, ses.authstate.username, ses.remotehost, chansess->tty); login_logout(li); login_free_entry(li); @@ -425,7 +425,7 @@ static int sessionpty(struct ChanSess * chansess) { dropbear_exit("out of memory"); /* TODO disconnect */ } - pty_setowner(svr_ses.authstate.pw, chansess->tty); + pty_setowner(ses.authstate.pw, chansess->tty); pty_change_window_size(chansess->master, chansess->termr, chansess->termc, chansess->termw, chansess->termh); @@ -683,7 +683,7 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) { /* write the utmp/wtmp login record - must be after changing the * terminal used for stdout with the dup2 above */ - li= login_alloc_entry(getpid(), svr_ses.authstate.username, + li= login_alloc_entry(getpid(), ses.authstate.username, ses.remotehost, chansess->tty); login_login(li); login_free_entry(li); @@ -695,10 +695,10 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) { /* don't show the motd if ~/.hushlogin exists */ /* 11 == strlen("/hushlogin\0") */ - len = strlen(svr_ses.authstate.pw->pw_dir) + 11; + len = strlen(ses.authstate.pw->pw_dir) + 11; hushpath = m_malloc(len); - snprintf(hushpath, len, "%s/hushlogin", svr_ses.authstate.pw->pw_dir); + snprintf(hushpath, len, "%s/hushlogin", ses.authstate.pw->pw_dir); if (stat(hushpath, &sb) < 0) { /* more than a screenful is stupid IMHO */ @@ -808,10 +808,10 @@ static void execchild(struct ChanSess *chansess) { /* We can only change uid/gid as root ... */ if (getuid() == 0) { - if ((setgid(svr_ses.authstate.pw->pw_gid) < 0) || - (initgroups(svr_ses.authstate.pw->pw_name, - svr_ses.authstate.pw->pw_gid) < 0) || - (setuid(svr_ses.authstate.pw->pw_uid) < 0)) { + if ((setgid(ses.authstate.pw->pw_gid) < 0) || + (initgroups(ses.authstate.pw->pw_name, + ses.authstate.pw->pw_gid) < 0) || + (setuid(ses.authstate.pw->pw_uid) < 0)) { dropbear_exit("error changing user"); } } else { @@ -822,29 +822,29 @@ static void execchild(struct ChanSess *chansess) { * usernames with the same uid, but differing groups, then the * differing groups won't be set (as with initgroups()). The solution * is for the sysadmin not to give out the UID twice */ - if (getuid() != svr_ses.authstate.pw->pw_uid) { + if (getuid() != ses.authstate.pw->pw_uid) { dropbear_exit("couldn't change user as non-root"); } } /* an empty shell should be interpreted as "/bin/sh" */ - if (svr_ses.authstate.pw->pw_shell[0] == '\0') { + if (ses.authstate.pw->pw_shell[0] == '\0') { usershell = "/bin/sh"; } else { - usershell = svr_ses.authstate.pw->pw_shell; + usershell = ses.authstate.pw->pw_shell; } /* set env vars */ - addnewvar("USER", svr_ses.authstate.pw->pw_name); - addnewvar("LOGNAME", svr_ses.authstate.pw->pw_name); - addnewvar("HOME", svr_ses.authstate.pw->pw_dir); + addnewvar("USER", ses.authstate.pw->pw_name); + addnewvar("LOGNAME", ses.authstate.pw->pw_name); + addnewvar("HOME", ses.authstate.pw->pw_dir); addnewvar("SHELL", usershell); if (chansess->term != NULL) { addnewvar("TERM", chansess->term); } /* change directory */ - if (chdir(svr_ses.authstate.pw->pw_dir) < 0) { + if (chdir(ses.authstate.pw->pw_dir) < 0) { dropbear_exit("error changing directory"); } diff --git a/svr-runopts.c b/svr-runopts.c index 1f5b0c6..c79208c 100644 --- a/svr-runopts.c +++ b/svr-runopts.c @@ -106,8 +106,8 @@ void svr_getopts(int argc, char ** argv) { opts.nolocaltcp = 0; opts.noremotetcp = 0; /* not yet - svr_opts.ipv4 = 1; - svr_opts.ipv6 = 1; + opts.ipv4 = 1; + opts.ipv6 = 1; */ #ifdef DO_MOTD svr_opts.domotd = 1; diff --git a/svr-service.c b/svr-service.c index 7b717bf..e823490 100644 --- a/svr-service.c +++ b/svr-service.c @@ -56,7 +56,7 @@ void recv_msg_service_request() { /* ssh-connection */ if (len == SSH_SERVICE_CONNECTION_LEN && (strncmp(SSH_SERVICE_CONNECTION, name, len) == 0)) { - if (ses.authdone != 1) { + if (ses.authstate.authdone != 1) { dropbear_exit("request for connection before auth"); } @@ -70,7 +70,6 @@ void recv_msg_service_request() { /* TODO this should be a MSG_DISCONNECT */ dropbear_exit("unrecognised SSH_MSG_SERVICE_REQUEST"); - TRACE(("leave recv_msg_service_request")); } diff --git a/svr-session.c b/svr-session.c index cb309fe..80c622a 100644 --- a/svr-session.c +++ b/svr-session.c @@ -79,7 +79,7 @@ void svr_session(int sock, int childpipe, char* remotehost) { /* Initialise server specific parts of the session */ svr_ses.childpipe = childpipe; - authinitialise(); + svr_authinitialise(); chaninitialise(svr_chantypes); svr_chansessinitialise(); @@ -90,10 +90,11 @@ void svr_session(int sock, int childpipe, char* remotehost) { ses.connecttimeout = timeout.tv_sec + AUTH_TIMEOUT; /* set up messages etc */ - session_remoteclosed = svr_remoteclosed; + ses.remoteclosed = svr_remoteclosed; /* packet handlers */ ses.packettypes = svr_packettypes; + ses.buf_match_algo = svr_buf_match_algo; /* We're ready to go now */ sessinitdone = 1; @@ -123,16 +124,16 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) { /* before session init */ snprintf(fmtbuf, sizeof(fmtbuf), "premature exit: %s", format); - } else if (svr_ses.authstate.authdone) { + } else if (ses.authstate.authdone) { /* user has authenticated */ snprintf(fmtbuf, sizeof(fmtbuf), "exit after auth (%s): %s", - svr_ses.authstate.printableuser, format); - } else if (svr_ses.authstate.printableuser) { + ses.authstate.printableuser, format); + } else if (ses.authstate.printableuser) { /* we have a potential user */ snprintf(fmtbuf, sizeof(fmtbuf), "exit before auth (user '%s', %d fails): %s", - svr_ses.authstate.printableuser, svr_ses.authstate.failcount, format); + ses.authstate.printableuser, ses.authstate.failcount, format); } else { /* before userauth */ snprintf(fmtbuf, sizeof(fmtbuf), -- cgit v1.2.3 From b601f68cda9187ed77d21eb46126fc83ba0bd14b Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 30 Jul 2004 03:02:19 +0000 Subject: we're nearly there yet --HG-- extra : convert_revision : ab7e63234f2c134c2321406598ae67038e0ca576 --- Makefile.in | 2 +- cli-auth.c | 1 + cli-session.c | 15 ++++++++++++++- common-channel.c | 13 +++++++++++++ runopts.h | 3 +++ session.h | 3 +++ 6 files changed, 35 insertions(+), 2 deletions(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index b8de23e..efb64d6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -27,7 +27,7 @@ SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ - cli-session.o cli-service.o cli-runopts.o + cli-session.o cli-service.o cli-runopts.o cli-chansession.o CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \ common-channel.o common-chansession.o termcodes.o loginrec.o \ diff --git a/cli-auth.c b/cli-auth.c index 3759ff5..37e7814 100644 --- a/cli-auth.c +++ b/cli-auth.c @@ -96,6 +96,7 @@ void recv_msg_userauth_failure() { void recv_msg_userauth_success() { TRACE(("received msg_userauth_success")); ses.authstate.authdone = 1; + cli_ses.state = USERAUTH_SUCCESS_RCVD; } void cli_auth_try() { diff --git a/cli-session.c b/cli-session.c index c999aed..b126b27 100644 --- a/cli-session.c +++ b/cli-session.c @@ -37,7 +37,6 @@ static const packettype cli_packettypes[] = { }; static const struct ChanType *cli_chantypes[] = { -// &clichansess, /* &chan_tcpdirect etc, though need to only allow if we've requested * that forwarding */ NULL /* Null termination */ @@ -148,6 +147,20 @@ static void cli_sessionloop() { TRACE(("leave cli_sessionloop: cli_auth_try")); return; + /* + case USERAUTH_SUCCESS_RCVD: + send_msg_service_request(SSH_SERVICE_CONNECTION); + cli_ses.state = SERVICE_CONN_REQ_SENT; + TRACE(("leave cli_sessionloop: sent ssh-connection service req")); + return; + */ + + case USERAUTH_SUCCESS_RCVD: + cli_send_chansess_request(); + TRACE(("leave cli_sessionloop: cli_send_chansess_request")); + cli_ses.state = SESSION_RUNNING; + return; + /* XXX more here needed */ diff --git a/common-channel.c b/common-channel.c index 3eea044..fbfb00b 100644 --- a/common-channel.c +++ b/common-channel.c @@ -67,6 +67,7 @@ void chaninitialise(const struct ChanType *chantypes[]) { ses.channels = (struct Channel**)m_malloc(sizeof(struct Channel*)); ses.chansize = 1; ses.channels[0] = NULL; + ses.chancount = 0; ses.chantypes = chantypes; @@ -153,6 +154,7 @@ struct Channel* newchannel(unsigned int remotechan, newchan->recvmaxpacket = RECV_MAXPACKET; ses.channels[i] = newchan; + ses.chancount++; TRACE(("leave newchannel")); @@ -515,6 +517,7 @@ static void deletechannel(struct Channel *channel) { ses.channels[channel->index] = NULL; m_free(channel); + ses.chancount--; } @@ -934,6 +937,7 @@ void recv_msg_channel_open_confirmation() { unsigned int chan; struct Channel * channel; + int ret; TRACE(("enter recv_msg_channel_open_confirmation")); chan = buf_getint(ses.payload); @@ -949,6 +953,15 @@ void recv_msg_channel_open_confirmation() { TRACE(("new chan remote %d localho %d", channel->remotechan, chan)); + /* Run the inithandler callback */ + if (channel->type->inithandler) { + ret = channel->type->inithandler(channel); + if (ret > 0) { + removechannel(channel); + TRACE(("inithandler returned failure %d", ret)); + } + } + TRACE(("leave recv_msg_channel_open_confirmation")); } diff --git a/runopts.h b/runopts.h index 125d737..b2fc149 100644 --- a/runopts.h +++ b/runopts.h @@ -83,6 +83,9 @@ typedef struct cli_runopts { char *remoteport; char *username; + + char *cmd; + int wantpty; /* XXX TODO */ } cli_runopts; diff --git a/session.h b/session.h index bf6adb3..349c00f 100644 --- a/session.h +++ b/session.h @@ -152,6 +152,7 @@ struct sshsession { /* Channel related */ struct Channel ** channels; /* these pointers may be null */ unsigned int chansize; /* the number of Channel*s allocated for channels */ + unsigned int chancount; /* the number of Channel*s in use */ const struct ChanType **chantypes; /* The valid channel types */ @@ -194,6 +195,8 @@ typedef enum { USERAUTH_METHODS_SENT, USERAUTH_REQ_SENT, USERAUTH_FAIL_RCVD, + USERAUTH_SUCCESS_RCVD, + SESSION_RUNNING, } cli_state; -- cgit v1.2.3 From 333eac7f9a976d646e319a044923872a9b876789 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sat, 7 Aug 2004 15:50:58 +0000 Subject: Should be dropbearkey, rather than dropbearmulti, for the default targets --HG-- extra : convert_revision : bed848ac745ab66a9f4df57c3bc27e5e39c41d9a --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index efb64d6..c705e45 100644 --- a/Makefile.in +++ b/Makefile.in @@ -10,7 +10,7 @@ # This makefile is quite evil. ifndef PROGRAMS - PROGRAMS=dropbear dbclient dropbearkey dropbearmulti + PROGRAMS=dropbear dbclient dropbearkey dropbearkey endif LTC=libtomcrypt/libtomcrypt.a -- cgit v1.2.3 From b8ae152c4b09a4c9dcdeede1110a724a6f7a5f65 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 8 Aug 2004 16:55:03 +0000 Subject: add cli-authpubkey --HG-- extra : convert_revision : fb7a0272b88cd9cbc53004d0ba6184bc3098c9f2 --- Makefile.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index c705e45..2bffe90 100644 --- a/Makefile.in +++ b/Makefile.in @@ -27,7 +27,8 @@ SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ - cli-session.o cli-service.o cli-runopts.o cli-chansession.o + cli-session.o cli-service.o cli-runopts.o cli-chansession.o \ + cli-authpubkey.o CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \ common-channel.o common-chansession.o termcodes.o loginrec.o \ -- cgit v1.2.3 From 3238bed9c9467a4c77bb6b430cd8f9fc394315c2 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 8 Aug 2004 16:57:37 +0000 Subject: svr-authpam code merged and works. needs tidying a log --HG-- branch : authpam extra : convert_revision : abeb2807b88fbd8b95d92b760a209a0816cbaea9 --- Makefile.in | 3 +- auth.h | 1 + configure.in | 38 ++++++++++- options.h | 5 +- svr-auth.c | 15 +++- svr-authpam.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 273 insertions(+), 4 deletions(-) create mode 100644 svr-authpam.c (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 2bffe90..6cb94e4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -24,7 +24,8 @@ COMMONOBJS=dbutil.o buffer.o \ SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ svr-authpasswd.o svr-authpubkey.o svr-session.o svr-service.o \ - svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o + svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\ + svr-authpam.o CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ cli-session.o cli-service.o cli-runopts.o cli-chansession.o \ diff --git a/auth.h b/auth.h index edac5a9..399db2d 100644 --- a/auth.h +++ b/auth.h @@ -36,6 +36,7 @@ void send_msg_userauth_failure(int partial, int incrfail); void send_msg_userauth_success(); void svr_auth_password(); void svr_auth_pubkey(); +void svr_auth_pam(); /* Client functions */ void recv_msg_userauth_failure(); diff --git a/configure.in b/configure.in index 47a9a29..d3c5229 100644 --- a/configure.in +++ b/configure.in @@ -108,6 +108,42 @@ AC_ARG_ENABLE(zlib, ] ) +# Check if pam is needed +AC_ARG_WITH(pam, + [ --with-pam=PATH Use pam in PATH], + [ + # option is given + if test -d "$withval/lib"; then + LDFLAGS="-L${withval}/lib ${LDFLAGS}" + else + LDFLAGS="-L${withval} ${LDFLAGS}" + fi + if test -d "$withval/include"; then + CPPFLAGS="-I${withval}/include ${CPPFLAGS}" + else + CPPFLAGS="-I${withval} ${CPPFLAGS}" + fi + ] +) + +AC_ARG_ENABLE(pam, + [ --disable-pam Don't include PAM support], + [ + if test "x$enableval" = "xno"; then + AC_DEFINE(DISABLE_PAM,, Use PAM) + AC_MSG_RESULT(Disabling PAM) + else + AC_CHECK_LIB(pam, pam_authenticate, , AC_MSG_ERROR([*** PAM missing - install first or check config.log ***])) + AC_MSG_RESULT(Enabling PAM) + fi + ], + [ + # if not disabled, check for pam + AC_CHECK_LIB(pam, pam_authenticate, , AC_MSG_ERROR([*** PAM missing - install first or check config.log ***])) + AC_MSG_RESULT(Enabling PAM) + ] +) + AC_ARG_ENABLE(openpty, [ --disable-openpty Don't use openpty, use alternative method], [ @@ -160,7 +196,7 @@ AC_ARG_ENABLE(shadow, # Checks for header files. AC_HEADER_STDC AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h sys/dirent.h]) +AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h sys/dirent.h security/pam_appl.h pam/pam_appl.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST diff --git a/options.h b/options.h index d4abf09..6ea5277 100644 --- a/options.h +++ b/options.h @@ -110,7 +110,10 @@ /* Authentication types to enable, at least one required. RFC Draft requires pubkey auth, and recommends password */ -#define DROPBEAR_PASSWORD_AUTH +//#define DROPBEAR_PASSWORD_AUTH +/* Only set PAM auth if you aren't using PASSWORD auth. Also, you'll need + * to make sure PAM libraries etc are installed */ +#define DROPBEAR_PAM_AUTH #define DROPBEAR_PUBKEY_AUTH /* Random device to use - you must specify _one only_. diff --git a/svr-auth.c b/svr-auth.c index db1d6a4..9e82b25 100644 --- a/svr-auth.c +++ b/svr-auth.c @@ -57,7 +57,7 @@ static void authclear() { #ifdef DROPBEAR_PUBKEY_AUTH ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; #endif -#ifdef DROPBEAR_PASSWORD_AUTH +#if defined(DROPBEAR_PASSWORD_AUTH) || defined(DROPBEAR_PAM_AUTH) if (!svr_opts.noauthpass) { ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; } @@ -156,6 +156,19 @@ void recv_msg_userauth_request() { } #endif +#ifdef DROPBEAR_PAM_AUTH + if (!svr_opts.noauthpass && + !(svr_opts.norootpass && ses.authstate.pw->pw_uid == 0) ) { + /* user wants to try password auth */ + if (methodlen == AUTH_METHOD_PASSWORD_LEN && + strncmp(methodname, AUTH_METHOD_PASSWORD, + AUTH_METHOD_PASSWORD_LEN) == 0) { + svr_auth_pam(); + goto out; + } + } +#endif + #ifdef DROPBEAR_PUBKEY_AUTH /* user wants to try pubkey auth */ if (methodlen == AUTH_METHOD_PUBKEY_LEN && diff --git a/svr-authpam.c b/svr-authpam.c new file mode 100644 index 0000000..cfd4327 --- /dev/null +++ b/svr-authpam.c @@ -0,0 +1,215 @@ +/* + * 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. */ + +/* Validates a user password */ + +#include "includes.h" +#include "session.h" +#include "buffer.h" +#include "dbutil.h" +#include "auth.h" + +#if defined(HAVE_SECURITY_PAM_APPL_H) +#include +#elif defined (HAVE_PAM_PAM_APPL_H) +#include +#endif + +#ifdef DROPBEAR_PAM_AUTH + +struct UserDataS { + char* user; + char* passwd; +}; + +/* PAM conversation function */ +int +pamConvFunc(int num_msg, + const struct pam_message **msg, + struct pam_response **respp, + void *appdata_ptr) { + int rc = PAM_SUCCESS; + struct pam_response* resp = NULL; + struct UserDataS* userDatap = (struct UserDataS*) appdata_ptr; + + /* tbd only handles one msg */ + + switch((*msg)->msg_style) { + case PAM_PROMPT_ECHO_OFF: + dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_PROMPT_ECHO_OFF: (*msg)->msg=\"%s\"", (*msg)->msg); + + if (strcmp((*msg)->msg, "Password:") == 0) { + resp = (struct pam_response*) malloc(sizeof(struct pam_response)); + resp->resp = (char*) strdup(userDatap->passwd); + /* dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_PROMPT_ECHO_ON: userDatap->passwd=\"%s\"", userDatap->passwd); */ + resp->resp_retcode = 0; + (*respp) = resp; + } + else { + dropbear_log(LOG_WARNING, "pamConvFunc(): PAM_PROMPT_ECHO_OFF: unrecognized prompt, (*msg)->msg=\"%s\"", (*msg)->msg); + rc = PAM_CONV_ERR; + } + break; + case PAM_PROMPT_ECHO_ON: + dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_PROMPT_ECHO_ON: (*msg)->msg=\"%s\"", (*msg)->msg); + + if ((strcmp((*msg)->msg, "login: " ) == 0) || (strcmp((*msg)->msg, "Please enter username: " ) == 0)) { + resp = (struct pam_response*) malloc(sizeof(struct pam_response)); + resp->resp = (char*) strdup(userDatap->user); + dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_PROMPT_ECHO_ON: userDatap->user=\"%s\"", userDatap->user); + resp->resp_retcode = 0; + (*respp) = resp; + } + else { + dropbear_log(LOG_WARNING, "pamConvFunc(): PAM_PROMPT_ECHO_ON: unrecognized prompt, (*msg)->msg=\"%s\"", + (*msg)->msg); + rc = PAM_CONV_ERR; + } + break; + case PAM_ERROR_MSG: + dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_ERROR_MSG: (*msg)->msg=\"%s\"", (*msg)->msg); + /* printf("error msg: '%s'\n", (*msg)->msg); */ + rc = PAM_CONV_ERR; + break; + case PAM_TEXT_INFO: + dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_TEXT_INFO: (*msg)->msg=\"%s\"", (*msg)->msg); + /* printf("text info: '%s'\n", (*msg)->msg); */ + rc = PAM_CONV_ERR; + break; + case PAM_RADIO_TYPE: + dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_RADIO_TYPE: (*msg)->msg=\"%s\"", (*msg)->msg); + /* printf("radio type: '%s'\n", (*msg)->msg); */ + rc = PAM_CONV_ERR; + break; + case PAM_BINARY_PROMPT: + dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_BINARY_PROMPT: (*msg)->msg=\"%s\"", (*msg)->msg); + /* printf("binary prompt: '%s'\n", (*msg)->msg); */ + rc = PAM_CONV_ERR; + break; + default: + dropbear_log(LOG_DEBUG, "pamConvFunc(): Unknown PAM message"); + /* printf("unknown message\n"); */ + rc = PAM_CONV_ERR; + break; + } + + return rc; +} + +/* Process a password auth request, sending success or failure messages as + * appropriate */ +void svr_auth_pam() { + // PAM stuff + int rc = PAM_SUCCESS; + struct UserDataS userData; + struct pam_conv pamConv = { + pamConvFunc, + &userData /* submitted to pamvConvFunc as appdata_ptr */ + }; + pam_handle_t* pamHandlep = NULL; + unsigned char * password = NULL; + unsigned int passwordlen; + + unsigned char changepw; + + /* check if client wants to change password */ + changepw = buf_getbyte(ses.payload); + if (changepw) { + /* not implemented by this server */ + send_msg_userauth_failure(0, 1); + return; + } + + password = buf_getstring(ses.payload, &passwordlen); + + /* clear the buffer containing the password */ + buf_incrpos(ses.payload, -passwordlen - 4); + m_burn(buf_getptr(ses.payload, passwordlen + 4), passwordlen + 4); + + /* used to pass data to the PAM conversation function */ + userData.user = ses.authstate.printableuser; + TRACE(("user is %s\n", userData.user)); + userData.passwd = password; + + /* Init pam */ + if ((rc = pam_start("sshd", NULL, &pamConv, &pamHandlep)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); + /* fprintf(stderr, "pam_start() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); */ + goto clean; + } + + /* + if ((rc = pam_set_item(pamHandlep, PAM_RHOST, webReqp->ipaddr) != PAM_SUCCESS)) { + dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); + return; + } + */ + + /* just to set it to something */ + if ((rc = pam_set_item(pamHandlep, PAM_TTY, "ssh") != PAM_SUCCESS)) { + dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); + goto clean; + } + + (void) pam_fail_delay(pamHandlep, 0 /* musec_delay */); + + /* (void) pam_set_item(pamHandlep, PAM_FAIL_DELAY, (void*) pamDelayFunc); */ + + if ((rc = pam_authenticate(pamHandlep, 0)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_authenticate() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); + /* fprintf(stderr, "pam_authenticate() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); */ + dropbear_log(LOG_WARNING, + "bad pam password attempt for '%s'", + ses.authstate.printableuser); + send_msg_userauth_failure(0, 1); + goto clean; + } + + if ((rc = pam_acct_mgmt(pamHandlep, 0)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_acct_mgmt() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); + /* fprintf(stderr, "pam_acct_mgmt() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); */ + dropbear_log(LOG_WARNING, + "bad pam password attempt for '%s'", + ses.authstate.printableuser); + send_msg_userauth_failure(0, 1); + goto clean; + } + + /* successful authentication */ + dropbear_log(LOG_NOTICE, + "password auth succeeded for '%s'", + ses.authstate.printableuser); + send_msg_userauth_success(); + + clean: + if (password != NULL) { + m_burn(password, passwordlen); + m_free(password); + } + if (pamHandlep != NULL) { + (void) pam_end(pamHandlep, 0 /* pam_status */); + } +} + +#endif /* DROPBEAR_PAM_AUTH */ -- cgit v1.2.3 From a712baa8e566bfd8403a3e2bfdf350a0dc50ea9f Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 10 Aug 2004 17:09:52 +0000 Subject: just checkpointing --HG-- extra : convert_revision : fbbf404290f3fea3dfa9f6f53eba9389057e9044 --- Makefile.in | 11 +- cli-authpubkey.c | 10 +- cli-runopts.c | 18 ++++ cli-session.c | 5 +- cli-tcpfwd.c | 34 ++++++ common-channel.c | 43 -------- dbutil.c | 173 +++++++++++++++++++++++------ dbutil.h | 6 +- listener.c | 42 +++++--- listener.h | 10 +- options.h | 3 + svr-agentfwd.c | 8 +- svr-chansession.c | 2 + svr-main.c | 82 +++++--------- svr-session.c | 6 +- svr-tcpfwd.c | 196 +++++++++++++++++++++++++++++++++ svr-x11fwd.c | 8 +- tcp-accept.c | 88 +++++++++++++++ tcp-accept.h | 19 ++++ tcp-connect.c | 75 +++++++++++++ tcp-connect.h | 35 ++++++ tcpfwd-direct.c | 159 --------------------------- tcpfwd-direct.h | 34 ------ tcpfwd-remote.c | 317 ------------------------------------------------------ tcpfwd-remote.h | 6 -- 25 files changed, 706 insertions(+), 684 deletions(-) create mode 100644 cli-tcpfwd.c create mode 100644 svr-tcpfwd.c create mode 100644 tcp-accept.c create mode 100644 tcp-accept.h create mode 100644 tcp-connect.c create mode 100644 tcp-connect.h delete mode 100644 tcpfwd-direct.c delete mode 100644 tcpfwd-direct.h delete mode 100644 tcpfwd-remote.c delete mode 100644 tcpfwd-remote.h (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 2bffe90..af24bb0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -24,15 +24,16 @@ COMMONOBJS=dbutil.o buffer.o \ SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ svr-authpasswd.o svr-authpubkey.o svr-session.o svr-service.o \ - svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o + svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\ + svr-tcpfwd.o CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ cli-session.o cli-service.o cli-runopts.o cli-chansession.o \ - cli-authpubkey.o + cli-authpubkey.o cli-tcpfwd.o CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \ common-channel.o common-chansession.o termcodes.o loginrec.o \ - tcpfwd-direct.o tcpfwd-remote.o listener.o process-packet.o \ + tcp-accept.o tcp-connect.o listener.o process-packet.o \ common-runopts.o KEYOBJS=dropbearkey.o gendss.o genrsa.o @@ -45,8 +46,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 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 tcpfwd-direct.h compat.h \ - tcpfwd-remote.h listener.h + loginrec.h atomicio.h x11fwd.h agentfwd.h tcp-accept.h compat.h \ + tcp-connect.h listener.h dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS) diff --git a/cli-authpubkey.c b/cli-authpubkey.c index 6b6ab51..33514ce 100644 --- a/cli-authpubkey.c +++ b/cli-authpubkey.c @@ -13,17 +13,22 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign); void cli_pubkeyfail() { struct PubkeyList *keyitem; + struct PubkeyList **previtem; TRACE(("enter cli_pubkeyfail")); + previtem = &cli_opts.pubkeys; + /* Find the key we failed with, and remove it */ for (keyitem = cli_opts.pubkeys; keyitem != NULL; keyitem = keyitem->next) { - if (keyitem->next == cli_ses.lastpubkey) { - keyitem->next = cli_ses.lastpubkey->next; + if (keyitem == cli_ses.lastpubkey) { + *previtem = keyitem->next; } + previtem = &keyitem; } sign_key_free(cli_ses.lastpubkey->key); /* It won't be used again */ m_free(cli_ses.lastpubkey); + TRACE(("leave cli_pubkeyfail")); } @@ -145,6 +150,7 @@ int cli_auth_pubkey() { /* Send a trial request */ send_msg_userauth_pubkey(cli_opts.pubkeys->key, cli_opts.pubkeys->type, 0); + cli_ses.lastpubkey = cli_opts.pubkeys; TRACE(("leave cli_auth_pubkey-success")); return 1; } else { diff --git a/cli-runopts.c b/cli-runopts.c index eb718a4..4c84cc8 100644 --- a/cli-runopts.c +++ b/cli-runopts.c @@ -47,6 +47,12 @@ static void printhelp() { "-T Don't allocate a pty\n" #ifdef DROPBEAR_PUBKEY_AUTH "-i (multiple allowed)\n" +#endif +#ifndef DISABLE_REMOTETCPFWD + "-L Local port forwarding\n" +#endif +#ifndef DISABLE_TCPFWD_DIRECT + "-R Remote port forwarding\n" #endif ,DROPBEAR_VERSION, cli_opts.progname); } @@ -59,6 +65,12 @@ void cli_getopts(int argc, char ** argv) { #ifdef DROPBEAR_PUBKEY_AUTH int nextiskey = 0; /* A flag if the next argument is a keyfile */ #endif +#ifdef DROPBEAR_CLI_LOCALTCP + int nextislocal = 0; +#endif +#ifdef DROPBEAR_CLI_REMOTETCP + int nextisremote = 0; +#endif @@ -71,6 +83,12 @@ void cli_getopts(int argc, char ** argv) { cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */ #ifdef DROPBEAR_PUBKEY_AUTH cli_opts.pubkeys = NULL; +#endif +#ifdef DROPBEAR_CLI_LOCALTCP + cli_opts.localports = NULL; +#endif +#ifdef DROPBEAR_CLI_REMOTETCP + cli_opts.remoteports = NULL; #endif opts.nolocaltcp = 0; opts.noremotetcp = 0; diff --git a/cli-session.c b/cli-session.c index 973e9c7..22f7001 100644 --- a/cli-session.c +++ b/cli-session.c @@ -4,8 +4,8 @@ #include "kex.h" #include "ssh.h" #include "packet.h" -#include "tcpfwd-direct.h" -#include "tcpfwd-remote.h" +#include "tcp-accept.h" +#include "tcp-connect.h" #include "channel.h" #include "random.h" #include "service.h" @@ -31,7 +31,6 @@ static const packettype cli_packettypes[] = { {SSH_MSG_KEXDH_REPLY, recv_msg_kexdh_reply}, /* client */ {SSH_MSG_NEWKEYS, recv_msg_newkeys}, {SSH_MSG_SERVICE_ACCEPT, recv_msg_service_accept}, /* client */ - {SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_remotetcp}, {SSH_MSG_CHANNEL_REQUEST, recv_msg_channel_request}, {SSH_MSG_CHANNEL_OPEN, recv_msg_channel_open}, {SSH_MSG_CHANNEL_EOF, recv_msg_channel_eof}, diff --git a/cli-tcpfwd.c b/cli-tcpfwd.c new file mode 100644 index 0000000..3dc6e20 --- /dev/null +++ b/cli-tcpfwd.c @@ -0,0 +1,34 @@ +#include "includes.h" +#include "options.h" +#include "tcp-accept.h" +#include "tcp-connect.h" +#include "channel.h" + +static const struct ChanType cli_chan_tcplocal = { + 1, /* sepfds */ + "direct-tcpip", + NULL, + NULL, + NULL +}; + + + + +static int cli_localtcp(char* port) { + + struct TCPListener* tcpinfo = NULL; + + tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener*)); + tcpinfo->addr = NULL; + tcpinfo->port = port; + tcpinfo->chantype = &cli_chan_tcplocal; + + ret = listen_tcpfwd(tcpinfo); + + if (ret == DROPBEAR_FAILURE) { + DROPBEAR_LOG(LOG_WARNING, "Failed to listen on port %s", port); + m_free(tcpinfo); + } + return ret; +} diff --git a/common-channel.c b/common-channel.c index fbfb00b..5079031 100644 --- a/common-channel.c +++ b/common-channel.c @@ -32,8 +32,6 @@ #include "dbutil.h" #include "channel.h" #include "ssh.h" -#include "tcpfwd-direct.h" -#include "tcpfwd-remote.h" #include "listener.h" static void send_msg_channel_open_failure(unsigned int remotechan, int reason, @@ -307,13 +305,6 @@ static void send_msg_channel_close(struct Channel *channel) { if (channel->type->closehandler) { channel->type->closehandler(channel); } -#if 0 - if (channel->type == CHANNEL_ID_SESSION) { - send_exitsignalstatus(channel); - - closechansess(channel); - } -#endif CHECKCLEARTOWRITE(); @@ -545,23 +536,6 @@ void recv_msg_channel_request() { send_msg_channel_failure(channel); } -#if 0 - /* handle according to channel type */ - switch (channel->type) { - - case CHANNEL_ID_SESSION: - TRACE(("continue recv_msg_channel_request: session request")); - /* XXX server */ - /* Here we need to do things channel-specific style. Function - * pointer callbacks perhaps */ - chansessionrequest(channel); - break; - - default: - send_msg_channel_failure(channel); - } -#endif - TRACE(("leave recv_msg_channel_request")); } @@ -797,23 +771,6 @@ void recv_msg_channel_open() { } } -#if 0 - /* type specific initialisation */ - if (typeval == CHANNEL_ID_SESSION) { - newchansess(channel); -#ifndef DISABLE_LOCALTCPFWD - } else if (typeval == CHANNEL_ID_TCPDIRECT) { - if (ses.opts->nolocaltcp) { - errtype = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; - } else if (newtcpdirect(channel) == DROPBEAR_FAILURE) { - errtype = SSH_OPEN_CONNECT_FAILED; - deletechannel(channel); - goto failure; - } -#endif - } -#endif - /* success */ send_msg_channel_open_confirmation(channel, channel->recvwindow, channel->recvmaxpacket); diff --git a/dbutil.c b/dbutil.c index dd68416..a377da2 100644 --- a/dbutil.c +++ b/dbutil.c @@ -113,8 +113,109 @@ void dropbear_trace(const char* format, ...) { } #endif /* DEBUG_TRACE */ +/* Listen on address:port. Unless address is NULL, in which case listen on + * everything (ie 0.0.0.0, or ::1 - note that this is IPv? agnostic. Linux is + * broken with respect to listening to v6 or v4, so the addresses you get when + * people connect will be wrong. It doesn't break things, just looks quite + * ugly. Returns the number of sockets bound on success, or -1 on failure. On + * failure, if errstring wasn't NULL, it'll be a newly malloced error + * string.*/ +int dropbear_listen(const char* address, const char* port, + int *socks, unsigned int sockcount, char **errstring, int *maxfd) { + + struct addrinfo hints, *res, *res0; + int err; + unsigned int nsock; + struct linger linger; + int val; + int sock; + + TRACE(("enter dropbear_listen")); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */ + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + err = getaddrinfo(address, port, &hints, &res0); + + if (err) { + if (errstring != NULL && *errstring == NULL) { + int len; + len = 20 + strlen(gai_strerror(err)); + *errstring = (char*)m_malloc(len); + snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err)); + } + TRACE(("leave dropbear_listen: failed resolving")); + return -1; + } + + + nsock = 0; + for (res = res0; res != NULL && nsock < sockcount; + res = res->ai_next) { + + /* Get a socket */ + socks[nsock] = socket(res->ai_family, res->ai_socktype, + res->ai_protocol); + + sock = socks[nsock]; /* For clarity */ + + if (sock < 0) { + err = errno; + TRACE(("socket() failed")); + continue; + } + + /* Various useful socket options */ + val = 1; + /* set to reuse, quick timeout */ + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val)); + linger.l_onoff = 1; + linger.l_linger = 5; + setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger)); + + /* disable nagle */ + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val)); + + if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { + err = errno; + close(sock); + TRACE(("bind() failed")); + continue; + } + + if (listen(sock, 20) < 0) { + err = errno; + close(sock); + TRACE(("listen() failed")); + continue; + } + + *maxfd = MAX(*maxfd, sock); + + nsock++; + } + + if (nsock == 0) { + if (errstring != NULL && *errstring == NULL) { + int len; + len = 20 + strlen(strerror(err)); + *errstring = (char*)m_malloc(len); + snprintf(*errstring, len, "Error connecting: %s", strerror(err)); + TRACE(("leave dropbear_listen: failure, %s", strerror(err))); + return -1; + } + } + + TRACE(("leave dropbear_listen: success, %d socks bound", nsock)); + return nsock; +} + /* Connect via TCP to a host. Connection will try ipv4 or ipv6, will - * return immediately if nonblocking is set */ + * return immediately if nonblocking is set. On failure, if errstring + * wasn't null, it will be a newly malloced error message */ + +/* TODO: maxfd */ int connect_remote(const char* remotehost, const char* remoteport, int nonblocking, char ** errstring) { @@ -197,58 +298,70 @@ int connect_remote(const char* remotehost, const char* remoteport, } freeaddrinfo(res0); + if (sock > 0 && errstring != NULL && *errstring != NULL) { + m_free(*errstring); + } - TRACE(("leave connect_remote: sock %d", sock)); + TRACE(("leave connect_remote: sock %d\n", sock)); return sock; } /* Return a string representation of the socket address passed. The return * value is allocated with malloc() */ -unsigned char * getaddrstring(struct sockaddr * addr) { +unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) { - char *retstring; + char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; + char *retstring = NULL; + int ret; + unsigned int len; - /* space for "255.255.255.255:65535\0" = 22 */ - retstring = m_malloc(22); + len = sizeof(struct sockaddr_storage); - switch (addr->sa_family) { - case PF_INET: - snprintf(retstring, 22, "%s:%hu", - inet_ntoa(((struct sockaddr_in *)addr)->sin_addr), - ((struct sockaddr_in *)addr)->sin_port); - break; + ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf), + sbuf, sizeof(sbuf), NI_NUMERICSERV | NI_NUMERICHOST); - default: - /* XXX ipv6 */ - strcpy(retstring, "Bad protocol"); + if (ret != 0) { + /* This is a fairly bad failure - it'll fallback to IP if it + * just can't resolve */ + dropbear_exit("failed lookup (%d, %d)", ret, errno); + } + if (withport) { + len = strlen(hbuf) + 2 + strlen(sbuf); + retstring = (char*)m_malloc(len); + snprintf(retstring, len, "%s:%s", hbuf, sbuf); + } else { + retstring = m_strdup(hbuf); } + return retstring; } /* Get the hostname corresponding to the address addr. On failure, the IP * address is returned. The return value is allocated with strdup() */ -char* getaddrhostname(struct sockaddr * addr) { +char* getaddrhostname(struct sockaddr_storage * addr) { - struct hostent *host = NULL; - char * retstring; + char hbuf[NI_MAXHOST]; + char sbuf[NI_MAXSERV]; + int ret; + unsigned int len; -#ifdef DO_HOST_LOOKUP - host = gethostbyaddr((char*)&((struct sockaddr_in*)addr)->sin_addr, - sizeof(struct in_addr), AF_INET); -#endif - - if (host == NULL) { - /* return the address */ - retstring = inet_ntoa(((struct sockaddr_in *)addr)->sin_addr); - } else { - /* return the hostname */ - retstring = host->h_name; + len = sizeof(struct sockaddr_storage); + + ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf), + sbuf, sizeof(sbuf), NI_NUMERICSERV); + + if (ret != 0) { + /* On some systems (Darwin does it) we get EINTR from getnameinfo + * somehow. Eew. So we'll just return the IP, since that doesn't seem + * to exhibit that behaviour. */ + return getaddrstring(addr, 0); } - return m_strdup(retstring); + return m_strdup(hbuf); } + #ifdef DEBUG_TRACE void printhex(unsigned char* buf, int len) { diff --git a/dbutil.h b/dbutil.h index 21a9955..ce0f311 100644 --- a/dbutil.h +++ b/dbutil.h @@ -44,10 +44,12 @@ void dropbear_trace(const char* format, ...); void printhex(unsigned char* buf, int len); #endif char * stripcontrol(const char * text); -unsigned char * getaddrstring(struct sockaddr * addr); +unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport); +int dropbear_listen(const char* address, const char* port, + int *socks, unsigned int sockcount, char **errstring, int *maxfd); int connect_remote(const char* remotehost, const char* remoteport, int nonblocking, char ** errstring); -char* getaddrhostname(struct sockaddr * addr); +char* getaddrhostname(struct sockaddr_storage * addr); int buf_readfile(buffer* buf, const char* filename); int buf_getline(buffer * line, FILE * authfile); diff --git a/listener.c b/listener.c index 7296a61..3022bd5 100644 --- a/listener.c +++ b/listener.c @@ -14,15 +14,16 @@ void listeners_initialise() { void set_listener_fds(fd_set * readfds) { - unsigned int i; + unsigned int i, j; struct Listener *listener; /* check each in turn */ for (i = 0; i < ses.listensize; i++) { listener = ses.listeners[i]; if (listener != NULL) { - TRACE(("set listener fd %d", listener->sock)); - FD_SET(listener->sock, readfds); + for (j = 0; j < listener->nsocks; j++) { + FD_SET(listener->socks[j], readfds); + } } } } @@ -30,16 +31,19 @@ void set_listener_fds(fd_set * readfds) { void handle_listeners(fd_set * readfds) { - unsigned int i; + unsigned int i, j; struct Listener *listener; + int sock; /* check each in turn */ for (i = 0; i < ses.listensize; i++) { listener = ses.listeners[i]; if (listener != NULL) { - TRACE(("handle listener num %d fd %d", i, listener->sock)); - if (FD_ISSET(listener->sock, readfds)) { - listener->accepter(listener); + for (j = 0; j < listener->nsocks; j++) { + sock = listener->socks[j]; + if (FD_ISSET(sock, readfds)) { + listener->accepter(listener, sock); + } } } } @@ -48,8 +52,9 @@ void handle_listeners(fd_set * readfds) { /* 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*), +struct Listener* new_listener(int socks[], unsigned int nsocks, + int type, void* typedata, + void (*accepter)(struct Listener*, int sock), void (*cleanup)(struct Listener*)) { unsigned int i, j; @@ -65,7 +70,9 @@ struct Listener* new_listener(int sock, int type, void* typedata, if (i == ses.listensize) { if (ses.listensize > MAX_LISTENERS) { TRACE(("leave newlistener: too many already")); - close(sock); + for (j = 0; j < nsocks; j++) { + close(socks[i]); + } return NULL; } @@ -80,15 +87,18 @@ struct Listener* new_listener(int sock, int type, void* typedata, } } - ses.maxfd = MAX(ses.maxfd, sock); + for (j = 0; j < nsocks; j++) { + ses.maxfd = MAX(ses.maxfd, socks[j]); + } - TRACE(("new listener num %d fd %d", i, sock)); + TRACE(("new listener num %d ", i)); newlisten = (struct Listener*)m_malloc(sizeof(struct Listener)); newlisten->index = i; newlisten->type = type; newlisten->typedata = typedata; - newlisten->sock = sock; + newlisten->nsocks = nsocks; + memcpy(newlisten->socks, socks, nsocks * sizeof(int)); newlisten->accepter = accepter; newlisten->cleanup = cleanup; @@ -116,11 +126,15 @@ struct Listener * get_listener(int type, void* typedata, void remove_listener(struct Listener* listener) { + unsigned int j; + if (listener->cleanup) { listener->cleanup(listener); } - close(listener->sock); + for (j = 0; j < listener->nsocks; j++) { + close(listener->socks[j]); + } ses.listeners[listener->index] = NULL; m_free(listener); diff --git a/listener.h b/listener.h index bda24ff..c634ead 100644 --- a/listener.h +++ b/listener.h @@ -6,11 +6,12 @@ struct Listener { - int sock; + int socks[DROPBEAR_MAX_SOCKS]; + unsigned int nsocks; int index; /* index in the array of listeners */ - void (*accepter)(struct Listener*); + void (*accepter)(struct Listener*, int sock); void (*cleanup)(struct Listener*); int type; /* CHANNEL_ID_X11, CHANNEL_ID_AGENT, @@ -25,8 +26,9 @@ void listeners_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*), +struct Listener* new_listener(int socks[], unsigned int nsocks, + int type, void* typedata, + void (*accepter)(struct Listener*, int sock), void (*cleanup)(struct Listener*)); struct Listener * get_listener(int type, void* typedata, diff --git a/options.h b/options.h index d4abf09..99115db 100644 --- a/options.h +++ b/options.h @@ -280,6 +280,9 @@ /* For a 4096 bit DSS key, empirically determined to be 1590 bytes */ #define MAX_PRIVKEY_SIZE 1600 +#define DROPBEAR_MAX_SOCKS 2 /* IPv4, IPv6 are all we'll get for now. Revisit + in a few years time.... */ + #ifndef ENABLE_X11FWD #define DISABLE_X11FWD #endif diff --git a/svr-agentfwd.c b/svr-agentfwd.c index 0dad2a4..b588586 100644 --- a/svr-agentfwd.c +++ b/svr-agentfwd.c @@ -44,7 +44,7 @@ static int send_msg_channel_open_agent(int fd); static int bindagent(int fd, struct ChanSess * chansess); -static void agentaccept(struct Listener * listener); +static void agentaccept(struct Listener * listener, int sock); /* Handles client requests to start agent forwarding, sets up listening socket. * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ @@ -78,7 +78,7 @@ int agentreq(struct ChanSess * chansess) { } /* pass if off to listener */ - chansess->agentlistener = new_listener( fd, 0, chansess, + chansess->agentlistener = new_listener( &fd, 1, 0, chansess, agentaccept, NULL); if (chansess->agentlistener == NULL) { @@ -97,11 +97,11 @@ fail: /* accepts a connection on the forwarded socket and opens a new channel for it * back to the client */ /* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ -static void agentaccept(struct Listener * listener) { +static void agentaccept(struct Listener * listener, int sock) { int fd; - fd = accept(listener->sock, NULL, NULL); + fd = accept(sock, NULL, NULL); if (fd < 0) { TRACE(("accept failed")); return; diff --git a/svr-chansession.c b/svr-chansession.c index 9639961..a0e877c 100644 --- a/svr-chansession.c +++ b/svr-chansession.c @@ -408,6 +408,8 @@ static void get_termmodes(struct ChanSess *chansess) { } len = buf_getint(ses.payload); + TRACE(("term mode str %d p->l %d p->p %d", + len, ses.payload->len , ses.payload->pos)); if (len != ses.payload->len - ses.payload->pos) { dropbear_exit("bad term mode string"); } diff --git a/svr-main.c b/svr-main.c index 312e47c..6a49626 100644 --- a/svr-main.c +++ b/svr-main.c @@ -29,7 +29,7 @@ #include "signkey.h" #include "runopts.h" -static int listensockets(int *sock, int *maxfd); +static int listensockets(int *sock, int sockcount, int *maxfd); static void sigchld_handler(int dummy); static void sigsegv_handler(int); static void sigintterm_handler(int fish); @@ -49,10 +49,10 @@ int main(int argc, char ** argv) unsigned int i, j; int val; int maxsock = -1; - struct sockaddr remoteaddr; + struct sockaddr_storage remoteaddr; int remoteaddrlen; int listensocks[MAX_LISTEN_ADDR]; - unsigned int listensockcount = 0; + int listensockcount = 0; FILE * pidfile; int childsock; @@ -127,7 +127,10 @@ int main(int argc, char ** argv) /* Set up the listening sockets */ /* XXX XXX ports */ - listensockcount = listensockets(listensocks, &maxsock); + listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock); + if (listensockcount < 0) { + dropbear_exit("No listening ports available."); + } /* incoming connection select loop */ for(;;) { @@ -138,7 +141,7 @@ int main(int argc, char ** argv) seltimeout.tv_usec = 0; /* listening sockets */ - for (i = 0; i < listensockcount; i++) { + for (i = 0; i < (unsigned int)listensockcount; i++) { FD_SET(listensocks[i], &fds); } @@ -179,12 +182,12 @@ int main(int argc, char ** argv) } /* handle each socket which has something to say */ - for (i = 0; i < listensockcount; i++) { + for (i = 0; i < (unsigned int)listensockcount; i++) { if (!FD_ISSET(listensocks[i], &fds)) continue; /* child connection XXX - ip6 stuff here */ - remoteaddrlen = sizeof(struct sockaddr_in); + remoteaddrlen = sizeof(remoteaddr); childsock = accept(listensocks[i], &remoteaddr, &remoteaddrlen); if (childsock < 0) { @@ -222,7 +225,7 @@ int main(int argc, char ** argv) monstartup((u_long)&_start, (u_long)&etext); #endif /* DEBUG_FORKGPROF */ - addrstring = getaddrstring(&remoteaddr); + addrstring = getaddrstring(&remoteaddr, 1); dropbear_log(LOG_INFO, "Child connection from %s", addrstring); m_free(addrstring); @@ -231,7 +234,7 @@ int main(int argc, char ** argv) } /* make sure we close sockets */ - for (i = 0; i < listensockcount; i++) { + for (i = 0; i < (unsigned int)listensockcount; i++) { if (m_close(listensocks[i]) == DROPBEAR_FAILURE) { dropbear_exit("Couldn't close socket"); } @@ -289,59 +292,30 @@ static void sigintterm_handler(int fish) { } /* Set up listening sockets for all the requested ports */ -static int listensockets(int *sock, int *maxfd) { +static int listensockets(int *sock, int sockcount, int *maxfd) { - int listensock; /* listening fd */ - struct sockaddr_in listen_addr; - struct linger linger; unsigned int i; - int val; + char portstring[6]; + char* errstring = NULL; + unsigned int sockpos = 0; + int nsock; for (i = 0; i < svr_opts.portcount; i++) { - /* iterate through all the sockets to listen on */ - listensock = socket(PF_INET, SOCK_STREAM, 0); - if (listensock < 0) { - dropbear_exit("Failed to create socket"); - } - - val = 1; - /* set to reuse, quick timeout */ - setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, - (void*) &val, sizeof(val)); - linger.l_onoff = 1; - linger.l_linger = 5; - setsockopt(listensock, SOL_SOCKET, SO_LINGER, - (void*)&linger, sizeof(linger)); - - /* disable nagle */ - setsockopt(listensock, IPPROTO_TCP, TCP_NODELAY, - (void*)&val, sizeof(val)); - - memset((void*)&listen_addr, 0x0, sizeof(listen_addr)); - listen_addr.sin_family = AF_INET; - listen_addr.sin_port = htons(svr_opts.ports[i]); - listen_addr.sin_addr.s_addr = htonl(INADDR_ANY); - memset(&(listen_addr.sin_zero), '\0', 8); - - if (bind(listensock, (struct sockaddr *)&listen_addr, - sizeof(listen_addr)) < 0) { - dropbear_exit("Bind failed port %d", svr_opts.ports[i]); - } + snprintf(portstring, sizeof(portstring), "%d", svr_opts.ports[i]); + nsock = dropbear_listen(NULL, portstring, &sock[sockpos], + sockcount - sockpos, + &errstring, maxfd); - /* listen */ - if (listen(listensock, 20) < 0) { /* TODO set listen count */ - dropbear_exit("Listen failed"); + if (nsock < 0) { + dropbear_log(LOG_WARNING, "Failed listening on port %s: %s", + portstring, errstring); + m_free(errstring); + continue; } - /* nonblock */ - if (fcntl(listensock, F_SETFL, O_NONBLOCK) < 0) { - dropbear_exit("Failed to set non-blocking"); - } + sockpos += nsock; - sock[i] = listensock; - *maxfd = MAX(listensock, *maxfd); } - - return svr_opts.portcount; + return sockpos; } diff --git a/svr-session.c b/svr-session.c index e63ba32..d46adf4 100644 --- a/svr-session.c +++ b/svr-session.c @@ -35,10 +35,10 @@ #include "channel.h" #include "chansession.h" #include "atomicio.h" -#include "tcpfwd-direct.h" +#include "tcp-accept.h" +#include "tcp-connect.h" #include "service.h" #include "auth.h" -#include "tcpfwd-remote.h" #include "runopts.h" static void svr_remoteclosed(); @@ -65,7 +65,7 @@ static const packettype svr_packettypes[] = { static const struct ChanType *svr_chantypes[] = { &svrchansess, - &chan_tcpdirect, + &svr_chan_tcpdirect, NULL /* Null termination is mandatory. */ }; diff --git a/svr-tcpfwd.c b/svr-tcpfwd.c new file mode 100644 index 0000000..499ee46 --- /dev/null +++ b/svr-tcpfwd.c @@ -0,0 +1,196 @@ +#include "includes.h" +#include "ssh.h" +#include "tcp-accept.h" +#include "tcp-connect.h" +#include "dbutil.h" +#include "session.h" +#include "buffer.h" +#include "packet.h" +#include "listener.h" +#include "runopts.h" + +#ifndef DISABLE_SVR_REMOTETCPFWD + +static void send_msg_request_success(); +static void send_msg_request_failure(); +static int svr_cancelremotetcp(); +static int svr_remotetcpreq(); + + +const struct ChanType svr_chan_tcpdirect = { + 1, /* sepfds */ + "direct-tcpip", + newtcpdirect, /* init */ + NULL, /* checkclose */ + NULL, /* reqhandler */ + NULL /* closehandler */ +}; + +static const struct ChanType svr_chan_tcpremote = { + 1, /* sepfds */ + "forwarded-tcpip", + NULL, + NULL, + NULL, + NULL +}; + +/* 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 (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 = svr_remotetcpreq(); + } else if (strcmp("cancel-tcpip-forward", reqname) == 0) { + ret = svr_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 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 TCPListener *info1 = (struct TCPListener*)typedata1; + const struct TCPListener *info2 = (struct TCPListener*)typedata2; + + return (info1->port == info2->port) + && (info1->chantype == info2->chantype) + && (strcmp(info1->addr, info2->addr) == 0); +} + +static int svr_cancelremotetcp() { + + int ret = DROPBEAR_FAILURE; + unsigned char * bindaddr = NULL; + unsigned int addrlen; + unsigned int port; + struct Listener * listener = NULL; + struct TCPListener 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 svr_remotetcpreq() { + + int ret = DROPBEAR_FAILURE; + unsigned char * bindaddr = NULL; + unsigned int addrlen; + struct TCPListener *tcpinfo = NULL; + 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; + } + + if (!ses.allowprivport && port < IPPORT_RESERVED) { + TRACE(("can't assign port < 1024 for non-root")); + goto out; + } + + tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener)); + tcpinfo->addr = bindaddr; + tcpinfo->port = port; + tcpinfo->localport = -1; + tcpinfo->chantype = &svr_chan_tcpremote; + + ret = listen_tcpfwd(tcpinfo); + +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(tcpinfo->addr); + m_free(tcpinfo); + } + TRACE(("leave remotetcpreq")); + return ret; +} +#endif diff --git a/svr-x11fwd.c b/svr-x11fwd.c index aa0ba2d..0f4f71e 100644 --- a/svr-x11fwd.c +++ b/svr-x11fwd.c @@ -37,7 +37,7 @@ #define X11BASEPORT 6000 #define X11BINDBASE 6010 -static void x11accept(struct Listener* listener); +static void x11accept(struct Listener* listener, int sock); static int bindport(int fd); static int send_msg_channel_open_x11(int fd, struct sockaddr_in* addr); @@ -82,7 +82,7 @@ int x11req(struct ChanSess * chansess) { /* 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); + chansess->x11listener = new_listener( &fd, 1, 0, chansess, x11accept, NULL); if (chansess->x11listener == NULL) { goto fail; } @@ -100,7 +100,7 @@ fail: /* accepts a new X11 socket */ /* returns DROPBEAR_FAILURE or DROPBEAR_SUCCESS */ -static void x11accept(struct Listener* listener) { +static void x11accept(struct Listener* listener, int sock) { int fd; struct sockaddr_in addr; @@ -110,7 +110,7 @@ static void x11accept(struct Listener* listener) { len = sizeof(addr); - fd = accept(listener->sock, (struct sockaddr*)&addr, &len); + fd = accept(sock, (struct sockaddr*)&addr, &len); if (fd < 0) { return; } diff --git a/tcp-accept.c b/tcp-accept.c new file mode 100644 index 0000000..1fb80dd --- /dev/null +++ b/tcp-accept.c @@ -0,0 +1,88 @@ +#include "includes.h" +#include "ssh.h" +#include "tcp-accept.h" +#include "dbutil.h" +#include "session.h" +#include "buffer.h" +#include "packet.h" +#include "listener.h" +#include "runopts.h" + +#ifndef DISABLE_TCP_ACCEPT + +static void accept_tcp(struct Listener *listener, int sock) { + + int fd; + struct sockaddr_storage addr; + int len; + char ipstring[NI_MAXHOST], portstring[NI_MAXSERV]; + struct TCPListener *tcpinfo = (struct TCPListener*)(listener->typedata); + + len = sizeof(addr); + + fd = accept(sock, (struct sockaddr*)&addr, &len); + if (fd < 0) { + return; + } + + if (getnameinfo((struct sockaddr*)&addr, len, ipstring, sizeof(ipstring), + portstring, sizeof(portstring), + NI_NUMERICHOST | NI_NUMERICSERV) != 0) { + return; + } + + if (send_msg_channel_open_init(fd, tcpinfo->chantype) == 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 cleanup_tcp(struct Listener *listener) { + + struct TCPListener *tcpinfo = (struct TCPListener*)(listener->typedata); + + m_free(tcpinfo->addr); + m_free(tcpinfo); +} + + +int listen_tcpfwd(struct TCPListener* tcpinfo) { + + char portstring[6]; /* "65535\0" */ + int socks[DROPBEAR_MAX_SOCKS]; + struct Listener *listener = NULL; + int nsocks; + + 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", tcpinfo->port); + nsocks = dropbear_listen(tcpinfo->addr, portstring, socks, + DROPBEAR_MAX_SOCKS, NULL, &ses.maxfd); + if (nsocks < 0) { + TRACE(("leave listen_tcpfwd: dropbear_listen failed")); + return DROPBEAR_FAILURE; + } + + listener = new_listener(socks, nsocks, CHANNEL_ID_TCPFORWARDED, tcpinfo, + accept_tcp, cleanup_tcp); + + if (listener == NULL) { + m_free(tcpinfo); + TRACE(("leave listen_tcpfwd: listener failed")); + return DROPBEAR_FAILURE; + } + + TRACE(("leave listen_tcpfwd: success")); + return DROPBEAR_SUCCESS; +} + +#endif /* DISABLE_REMOTETCPFWD */ diff --git a/tcp-accept.h b/tcp-accept.h new file mode 100644 index 0000000..96ddb76 --- /dev/null +++ b/tcp-accept.h @@ -0,0 +1,19 @@ +#ifndef _REMOTETCPFWD_H +#define _REMOTETCPFWD_H + +struct TCPListener { + + /* Local ones */ + unsigned char *localaddr; /* Can be NULL */ + unsigned int localport; + /* Remote ones: */ + unsigned char *remoteaddr; + unsigned int remoteport; + const struct ChanType *chantype; + +}; + +void recv_msg_global_request_remotetcp(); +int listen_tcpfwd(struct TCPListener* tcpinfo); + +#endif /* _REMOTETCPFWD_H */ diff --git a/tcp-connect.c b/tcp-connect.c new file mode 100644 index 0000000..00dbd8a --- /dev/null +++ b/tcp-connect.c @@ -0,0 +1,75 @@ +#include "includes.h" +#include "session.h" +#include "dbutil.h" +#include "channel.h" +#include "tcp-connect.h" +#include "runopts.h" + +#ifndef DISABLE_TCP_CONNECT + +/* Called upon creating a new direct tcp channel (ie we connect out to an + * address */ +int newtcpdirect(struct Channel * channel) { + + unsigned char* desthost = NULL; + unsigned int destport; + unsigned char* orighost = NULL; + unsigned int origport; + char portstring[6]; + int sock; + int len; + int ret = DROPBEAR_FAILURE; + + if (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; + } + + snprintf(portstring, sizeof(portstring), "%d", destport); + sock = connect_remote(desthost, portstring, 1, NULL); + 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; +} + +#endif /* DISABLE_TCPFWD_DIRECT */ diff --git a/tcp-connect.h b/tcp-connect.h new file mode 100644 index 0000000..40ce22b --- /dev/null +++ b/tcp-connect.h @@ -0,0 +1,35 @@ +/* + * 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 svr_chan_tcpdirect; +int newtcpdirect(struct Channel * channel); + +#endif +#endif diff --git a/tcpfwd-direct.c b/tcpfwd-direct.c deleted file mode 100644 index b611283..0000000 --- a/tcpfwd-direct.c +++ /dev/null @@ -1,159 +0,0 @@ -#include "includes.h" -#include "session.h" -#include "dbutil.h" -#include "channel.h" -#include "tcpfwd-direct.h" -#include "runopts.h" - -#ifndef DISABLE_TCPFWD_DIRECT -static int newtcpdirect(struct Channel * channel); -static int newtcp(const char * host, int port); - -const struct ChanType chan_tcpdirect = { - 1, /* 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; - char portstring[6]; - int sock; - int len; - int ret = DROPBEAR_FAILURE; - - if (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; - } - - snprintf(portstring, sizeof(portstring), "%d", destport); - sock = connect_remote(desthost, portstring, 1, NULL); - 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 */ -#if 0 -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 -#endif /* DISABLE_TCPFWD_DIRECT */ diff --git a/tcpfwd-direct.h b/tcpfwd-direct.h deleted file mode 100644 index 20cd278..0000000 --- a/tcpfwd-direct.h +++ /dev/null @@ -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 _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 --git a/tcpfwd-remote.c b/tcpfwd-remote.c deleted file mode 100644 index d0a67a1..0000000 --- a/tcpfwd-remote.c +++ /dev/null @@ -1,317 +0,0 @@ -#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" -#include "runopts.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 (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 = { - 1, /* 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; - } - - if (!ses.allowprivport && 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 --git a/tcpfwd-remote.h b/tcpfwd-remote.h deleted file mode 100644 index 64dbed3..0000000 --- a/tcpfwd-remote.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _REMOTETCPFWD_H -#define _REMOTETCPFWD_H - -void recv_msg_global_request_remotetcp(); - -#endif /* _REMOTETCPFWD_H */ -- cgit v1.2.3 From e1057cd47720a03512e3ed0d5bbc2d5296b94fc2 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 12 Aug 2004 13:48:42 +0000 Subject: TCP forwarding works. --HG-- extra : convert_revision : 57dfb36d0d482ad84f31506904eb67863bd303ab --- Makefile.in | 4 +- cli-runopts.c | 134 ++++++++++++++++++++++++++++++---- cli-session.c | 13 ++-- cli-tcpfwd.c | 130 ++++++++++++++++++++++++++++++++- dbutil.c | 4 +- fake-rfc2553.c | 224 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fake-rfc2553.h | 161 +++++++++++++++++++++++++++++++++++++++++ options.h | 15 ++-- runopts.h | 9 ++- session.h | 1 + svr-tcpfwd.c | 72 ++++++++++++++++++- tcp-accept.c | 4 +- tcp-accept.h | 25 ------- tcp-connect.c | 75 ------------------- tcp-connect.h | 35 --------- tcpfwd.h | 69 ++++++++++++++++++ 16 files changed, 806 insertions(+), 169 deletions(-) create mode 100644 fake-rfc2553.c create mode 100644 fake-rfc2553.h delete mode 100644 tcp-accept.h delete mode 100644 tcp-connect.c delete mode 100644 tcp-connect.h create mode 100644 tcpfwd.h (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index af24bb0..68ef5d8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -46,8 +46,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 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 tcp-accept.h compat.h \ - tcp-connect.h listener.h + loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \ + listener.h dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS) diff --git a/cli-runopts.c b/cli-runopts.c index 4c84cc8..26eb634 100644 --- a/cli-runopts.c +++ b/cli-runopts.c @@ -28,6 +28,7 @@ #include "buffer.h" #include "dbutil.h" #include "algo.h" +#include "tcpfwd.h" cli_runopts cli_opts; /* GLOBAL */ @@ -36,6 +37,9 @@ static void parsehostname(char* userhostarg); #ifdef DROPBEAR_PUBKEY_AUTH static void loadidentityfile(const char* filename); #endif +#ifdef ENABLE_CLI_ANYTCPFWD +static void addforward(char* str, struct TCPFwdList** fwdlist); +#endif static void printhelp() { @@ -48,10 +52,10 @@ static void printhelp() { #ifdef DROPBEAR_PUBKEY_AUTH "-i (multiple allowed)\n" #endif -#ifndef DISABLE_REMOTETCPFWD +#ifdef ENABLE_CLI_LOCALTCPFWD "-L Local port forwarding\n" #endif -#ifndef DISABLE_TCPFWD_DIRECT +#ifdef ENABLE_CLI_REMOTETCPFWD "-R Remote port forwarding\n" #endif ,DROPBEAR_VERSION, cli_opts.progname); @@ -65,15 +69,13 @@ void cli_getopts(int argc, char ** argv) { #ifdef DROPBEAR_PUBKEY_AUTH int nextiskey = 0; /* A flag if the next argument is a keyfile */ #endif -#ifdef DROPBEAR_CLI_LOCALTCP +#ifdef ENABLE_CLI_LOCALTCPFWD int nextislocal = 0; #endif -#ifdef DROPBEAR_CLI_REMOTETCP +#ifdef ENABLE_CLI_REMOTETCPFWD int nextisremote = 0; #endif - - /* see printhelp() for options */ cli_opts.progname = argv[0]; cli_opts.remotehost = NULL; @@ -84,11 +86,11 @@ void cli_getopts(int argc, char ** argv) { #ifdef DROPBEAR_PUBKEY_AUTH cli_opts.pubkeys = NULL; #endif -#ifdef DROPBEAR_CLI_LOCALTCP - cli_opts.localports = NULL; +#ifdef ENABLE_CLI_LOCALTCPFWD + cli_opts.localfwds = NULL; #endif -#ifdef DROPBEAR_CLI_REMOTETCP - cli_opts.remoteports = NULL; +#ifdef ENABLE_CLI_REMOTETCPFWD + cli_opts.remotefwds = NULL; #endif opts.nolocaltcp = 0; opts.noremotetcp = 0; @@ -106,6 +108,22 @@ void cli_getopts(int argc, char ** argv) { nextiskey = 0; continue; } +#endif +#ifdef ENABLE_CLI_REMOTETCPFWD + if (nextisremote) { + TRACE(("nextisremote true")); + addforward(argv[i], &cli_opts.remotefwds); + nextisremote = 0; + continue; + } +#endif +#ifdef ENABLE_CLI_LOCALTCPFWD + if (nextislocal) { + TRACE(("nextislocal true")); + addforward(argv[i], &cli_opts.localfwds); + nextislocal = 0; + continue; + } #endif if (next) { /* The previous flag set a value to assign */ @@ -135,6 +153,16 @@ void cli_getopts(int argc, char ** argv) { case 'T': /* don't want a pty */ cli_opts.wantpty = 0; break; +#ifdef ENABLE_CLI_LOCALTCPFWD + case 'L': + nextislocal = 1; + break; +#endif +#ifdef ENABLE_CLI_REMOTETCPFWD + case 'R': + nextisremote = 1; + break; +#endif default: fprintf(stderr, "Unknown argument '%s'\n", argv[i]); printhelp(); @@ -145,7 +173,7 @@ void cli_getopts(int argc, char ** argv) { continue; /* next argument */ } else { - TRACE(("non-flag arg")); + TRACE(("non-flag arg: '%s'", argv[i])); /* Either the hostname or commands */ @@ -226,10 +254,14 @@ static void loadidentityfile(const char* filename) { /* Parses a [user@]hostname argument. userhostarg is the argv[i] corresponding * - note that it will be modified */ -static void parsehostname(char* userhostarg) { +static void parsehostname(char* orighostarg) { uid_t uid; struct passwd *pw = NULL; + char *userhostarg = NULL; + + /* We probably don't want to be editing argvs */ + userhostarg = m_strdup(orighostarg); cli_opts.remotehost = strchr(userhostarg, '@'); if (cli_opts.remotehost == NULL) { @@ -257,3 +289,81 @@ static void parsehostname(char* userhostarg) { dropbear_exit("Bad hostname"); } } + +#ifdef ENABLE_CLI_ANYTCPFWD +/* Turn a "listenport:remoteaddr:remoteport" string into into a forwarding + * set, and add it to the forwarding list */ +static void addforward(char* origstr, struct TCPFwdList** fwdlist) { + + char * listenport = NULL; + char * connectport = NULL; + char * connectaddr = NULL; + struct TCPFwdList* newfwd = NULL; + char * str = NULL; + + TRACE(("enter addforward")); + + /* We probably don't want to be editing argvs */ + str = m_strdup(origstr); + + listenport = str; + + connectaddr = strchr(str, ':'); + if (connectaddr == NULL) { + TRACE(("connectaddr == NULL")); + goto fail; + } + + connectaddr[0] = '\0'; + connectaddr++; + + connectport = strchr(connectaddr, ':'); + if (connectport == NULL) { + TRACE(("connectport == NULL")); + goto fail; + } + + connectport[0] = '\0'; + connectport++; + + newfwd = (struct TCPFwdList*)m_malloc(sizeof(struct TCPFwdList)); + + /* Now we check the ports - note that the port ints are unsigned, + * the check later only checks for >= MAX_PORT */ + newfwd->listenport = strtol(listenport, NULL, 10); + if (errno != 0) { + TRACE(("bad listenport strtol")); + goto fail; + } + + newfwd->connectport = strtol(connectport, NULL, 10); + if (errno != 0) { + TRACE(("bad connectport strtol")); + goto fail; + } + + newfwd->connectaddr = connectaddr; + + if (newfwd->listenport > 65535) { + TRACE(("listenport > 65535")); + goto badport; + } + + if (newfwd->connectport > 65535) { + TRACE(("connectport > 65535")); + goto badport; + } + + newfwd->next = *fwdlist; + *fwdlist = newfwd; + + TRACE(("leave addforward: done")); + return; + +fail: + dropbear_exit("Bad TCP forward '%s'", origstr); + +badport: + dropbear_exit("Bad TCP port in '%s'", origstr); +} +#endif diff --git a/cli-session.c b/cli-session.c index 22f7001..318bc64 100644 --- a/cli-session.c +++ b/cli-session.c @@ -4,8 +4,7 @@ #include "kex.h" #include "ssh.h" #include "packet.h" -#include "tcp-accept.h" -#include "tcp-connect.h" +#include "tcpfwd.h" #include "channel.h" #include "random.h" #include "service.h" @@ -45,8 +44,9 @@ static const packettype cli_packettypes[] = { }; static const struct ChanType *cli_chantypes[] = { - /* &chan_tcpdirect etc, though need to only allow if we've requested - * that forwarding */ +#ifdef ENABLE_CLI_REMOTETCPFWD + &cli_chan_tcpremote, +#endif NULL /* Null termination */ }; @@ -178,6 +178,10 @@ static void cli_sessionloop() { */ case USERAUTH_SUCCESS_RCVD: +#ifdef ENABLE_CLI_LOCALTCPFWD + TRACE(("recvd USERAUTH_SUCCESS_RCVD")); + setup_localtcp(); +#endif cli_send_chansess_request(); TRACE(("leave cli_sessionloop: cli_send_chansess_request")); cli_ses.state = SESSION_RUNNING; @@ -223,7 +227,6 @@ static void cli_finished() { } - /* called when the remote side closes the connection */ static void cli_remoteclosed() { diff --git a/cli-tcpfwd.c b/cli-tcpfwd.c index 955ffab..f32a53f 100644 --- a/cli-tcpfwd.c +++ b/cli-tcpfwd.c @@ -1,20 +1,54 @@ #include "includes.h" #include "options.h" -#include "tcp-accept.h" -#include "tcp-connect.h" +#include "dbutil.h" +#include "tcpfwd.h" #include "channel.h" +#include "runopts.h" +#include "session.h" +#include "ssh.h" +static int cli_localtcp(unsigned int listenport, const char* remoteaddr, + unsigned int remoteport); +static int newtcpforwarded(struct Channel * channel); + +const struct ChanType cli_chan_tcpremote = { + 1, /* sepfds */ + "forwarded-tcpip", + newtcpforwarded, + NULL, + NULL, + NULL +}; static const struct ChanType cli_chan_tcplocal = { 1, /* sepfds */ "direct-tcpip", NULL, NULL, + NULL, NULL }; void setup_localtcp() { - qv + int ret; + + if (cli_opts.localfwds == NULL) { + TRACE(("cli_opts.localfwds == NULL")); + } + + while (cli_opts.localfwds != NULL) { + ret = cli_localtcp(cli_opts.localfwds->listenport, + cli_opts.localfwds->connectaddr, + cli_opts.localfwds->connectport); + if (ret == DROPBEAR_FAILURE) { + dropbear_log(LOG_WARNING, "Failed local port forward %d:%s:%d", + cli_opts.localfwds->listenport, + cli_opts.localfwds->connectaddr, + cli_opts.localfwds->connectport); + } + + cli_opts.localfwds = cli_opts.localfwds->next; + } } @@ -22,6 +56,10 @@ static int cli_localtcp(unsigned int listenport, const char* remoteaddr, unsigned int remoteport) { struct TCPListener* tcpinfo = NULL; + int ret; + + TRACE(("enter cli_localtcp: %d %s %d", listenport, remoteaddr, + remoteport)); tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener*)); tcpinfo->sendaddr = remoteaddr; @@ -34,5 +72,91 @@ static int cli_localtcp(unsigned int listenport, const char* remoteaddr, if (ret == DROPBEAR_FAILURE) { m_free(tcpinfo); } + TRACE(("leave cli_localtcp: %d", ret)); + return ret; +} + +static void send_msg_global_request_remotetcp(int port) { + + TRACE(("enter send_msg_global_request_remotetcp")); + + CHECKCLEARTOWRITE(); + buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST); + buf_putstring(ses.writepayload, "tcpip-forward", 13); + buf_putbyte(ses.writepayload, 0); + buf_putstring(ses.writepayload, "0.0.0.0", 7); /* TODO: IPv6? */ + buf_putint(ses.writepayload, port); + + encrypt_packet(); + + TRACE(("leave send_msg_global_request_remotetcp")); +} + +void setup_remotetcp() { + + struct TCPFwdList * iter = NULL; + + if (cli_opts.remotefwds == NULL) { + TRACE(("cli_opts.remotefwds == NULL")); + } + + iter = cli_opts.remotefwds; + + while (iter != NULL) { + send_msg_global_request_remotetcp(iter->listenport); + iter = iter->next; + } +} + +static int newtcpforwarded(struct Channel * channel) { + + unsigned int origport; + struct TCPFwdList * iter = NULL; + char portstring[NI_MAXSERV]; + int sock; + int ret = DROPBEAR_FAILURE; + + /* We don't care what address they connected to */ + buf_eatstring(ses.payload); + + origport = buf_getint(ses.payload); + + /* Find which port corresponds */ + iter = cli_opts.remotefwds; + + while (iter != NULL) { + if (origport == iter->listenport) { + break; + } + iter = iter->next; + } + + if (iter == NULL) { + /* We didn't request forwarding on that port */ + dropbear_log(LOG_INFO, "Server send unrequested port, from port %d", + origport); + goto out; + } + + snprintf(portstring, sizeof(portstring), "%d", iter->connectport); + sock = connect_remote(iter->connectaddr, portstring, 1, NULL); + 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: + TRACE(("leave newtcpdirect: ret %d", ret)); return ret; } diff --git a/dbutil.c b/dbutil.c index 72d25e7..b5cd2b0 100644 --- a/dbutil.c +++ b/dbutil.c @@ -185,7 +185,7 @@ int dropbear_listen(const char* address, const char* port, if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { err = errno; close(sock); - TRACE(("bind() failed")); + TRACE(("bind(%s) failed", port)); continue; } @@ -206,7 +206,7 @@ int dropbear_listen(const char* address, const char* port, int len; len = 20 + strlen(strerror(err)); *errstring = (char*)m_malloc(len); - snprintf(*errstring, len, "Error connecting: %s", strerror(err)); + snprintf(*errstring, len, "Error listening: %s", strerror(err)); TRACE(("leave dropbear_listen: failure, %s", strerror(err))); return -1; } diff --git a/fake-rfc2553.c b/fake-rfc2553.c new file mode 100644 index 0000000..0186b53 --- /dev/null +++ b/fake-rfc2553.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2000-2003 Damien Miller. All rights reserved. + * Copyright (C) 1999 WIDE Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Pseudo-implementation of RFC2553 name / address resolution functions + * + * But these functions are not implemented correctly. The minimum subset + * is implemented for ssh use only. For example, this routine assumes + * that ai_family is AF_INET. Don't use it for another purpose. + */ + +#include "includes.h" + +RCSID("$Id: fake-rfc2553.c,v 1.5 2003/09/22 02:08:23 dtucker Exp $"); + +#ifndef HAVE_GETNAMEINFO +int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, + size_t hostlen, char *serv, size_t servlen, int flags) +{ + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + struct hostent *hp; + char tmpserv[16]; + + if (serv != NULL) { + snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port)); + if (strlcpy(serv, tmpserv, servlen) >= servlen) + return (EAI_MEMORY); + } + + if (host != NULL) { + if (flags & NI_NUMERICHOST) { + if (strlcpy(host, inet_ntoa(sin->sin_addr), + hostlen) >= hostlen) + return (EAI_MEMORY); + else + return (0); + } else { + hp = gethostbyaddr((char *)&sin->sin_addr, + sizeof(struct in_addr), AF_INET); + if (hp == NULL) + return (EAI_NODATA); + + if (strlcpy(host, hp->h_name, hostlen) >= hostlen) + return (EAI_MEMORY); + else + return (0); + } + } + return (0); +} +#endif /* !HAVE_GETNAMEINFO */ + +#ifndef HAVE_GAI_STRERROR +#ifdef HAVE_CONST_GAI_STRERROR_PROTO +const char * +#else +char * +#endif +gai_strerror(int err) +{ + switch (err) { + case EAI_NODATA: + return ("no address associated with name"); + case EAI_MEMORY: + return ("memory allocation failure."); + case EAI_NONAME: + return ("nodename nor servname provided, or not known"); + default: + return ("unknown/invalid error."); + } +} +#endif /* !HAVE_GAI_STRERROR */ + +#ifndef HAVE_FREEADDRINFO +void +freeaddrinfo(struct addrinfo *ai) +{ + struct addrinfo *next; + + for(; ai != NULL;) { + next = ai->ai_next; + free(ai); + ai = next; + } +} +#endif /* !HAVE_FREEADDRINFO */ + +#ifndef HAVE_GETADDRINFO +static struct +addrinfo *malloc_ai(int port, u_long addr, const struct addrinfo *hints) +{ + struct addrinfo *ai; + + ai = malloc(sizeof(*ai) + sizeof(struct sockaddr_in)); + if (ai == NULL) + return (NULL); + + memset(ai, '\0', sizeof(*ai) + sizeof(struct sockaddr_in)); + + ai->ai_addr = (struct sockaddr *)(ai + 1); + /* XXX -- ssh doesn't use sa_len */ + ai->ai_addrlen = sizeof(struct sockaddr_in); + ai->ai_addr->sa_family = ai->ai_family = AF_INET; + + ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port; + ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr; + + /* XXX: the following is not generally correct, but does what we want */ + if (hints->ai_socktype) + ai->ai_socktype = hints->ai_socktype; + else + ai->ai_socktype = SOCK_STREAM; + + if (hints->ai_protocol) + ai->ai_protocol = hints->ai_protocol; + + return (ai); +} + +int +getaddrinfo(const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) +{ + struct hostent *hp; + struct servent *sp; + struct in_addr in; + int i; + long int port; + u_long addr; + + port = 0; + if (servname != NULL) { + char *cp; + + port = strtol(servname, &cp, 10); + if (port > 0 && port <= 65535 && *cp == '\0') + port = htons(port); + else if ((sp = getservbyname(servname, NULL)) != NULL) + port = sp->s_port; + else + port = 0; + } + + if (hints && hints->ai_flags & AI_PASSIVE) { + addr = htonl(0x00000000); + if (hostname && inet_aton(hostname, &in) != 0) + addr = in.s_addr; + *res = malloc_ai(port, addr, hints); + if (*res == NULL) + return (EAI_MEMORY); + return (0); + } + + if (!hostname) { + *res = malloc_ai(port, htonl(0x7f000001), hints); + if (*res == NULL) + return (EAI_MEMORY); + return (0); + } + + if (inet_aton(hostname, &in)) { + *res = malloc_ai(port, in.s_addr, hints); + if (*res == NULL) + return (EAI_MEMORY); + return (0); + } + + /* Don't try DNS if AI_NUMERICHOST is set */ + if (hints && hints->ai_flags & AI_NUMERICHOST) + return (EAI_NONAME); + + hp = gethostbyname(hostname); + if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { + struct addrinfo *cur, *prev; + + cur = prev = *res = NULL; + for (i = 0; hp->h_addr_list[i]; i++) { + struct in_addr *in = (struct in_addr *)hp->h_addr_list[i]; + + cur = malloc_ai(port, in->s_addr, hints); + if (cur == NULL) { + if (*res != NULL) + freeaddrinfo(*res); + return (EAI_MEMORY); + } + if (prev) + prev->ai_next = cur; + else + *res = cur; + + prev = cur; + } + return (0); + } + + return (EAI_NODATA); +} +#endif /* !HAVE_GETADDRINFO */ diff --git a/fake-rfc2553.h b/fake-rfc2553.h new file mode 100644 index 0000000..baea070 --- /dev/null +++ b/fake-rfc2553.h @@ -0,0 +1,161 @@ +/* $Id: fake-rfc2553.h,v 1.9 2004/03/10 10:06:33 dtucker Exp $ */ + +/* + * Copyright (C) 2000-2003 Damien Miller. All rights reserved. + * Copyright (C) 1999 WIDE Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Pseudo-implementation of RFC2553 name / address resolution functions + * + * But these functions are not implemented correctly. The minimum subset + * is implemented for ssh use only. For example, this routine assumes + * that ai_family is AF_INET. Don't use it for another purpose. + */ + +#ifndef _FAKE_RFC2553_H +#define _FAKE_RFC2553_H + +#include "includes.h" +#include "sys/types.h" + +/* + * First, socket and INET6 related definitions + */ +#ifndef HAVE_STRUCT_SOCKADDR_STORAGE +# define _SS_MAXSIZE 128 /* Implementation specific max size */ +# define _SS_PADSIZE (_SS_MAXSIZE - sizeof (struct sockaddr)) +struct sockaddr_storage { + struct sockaddr ss_sa; + char __ss_pad2[_SS_PADSIZE]; +}; +# define ss_family ss_sa.sa_family +#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */ + +#ifndef IN6_IS_ADDR_LOOPBACK +# define IN6_IS_ADDR_LOOPBACK(a) \ + (((u_int32_t *)(a))[0] == 0 && ((u_int32_t *)(a))[1] == 0 && \ + ((u_int32_t *)(a))[2] == 0 && ((u_int32_t *)(a))[3] == htonl(1)) +#endif /* !IN6_IS_ADDR_LOOPBACK */ + +#ifndef HAVE_STRUCT_IN6_ADDR +struct in6_addr { + u_int8_t s6_addr[16]; +}; +#endif /* !HAVE_STRUCT_IN6_ADDR */ + +#ifndef HAVE_STRUCT_SOCKADDR_IN6 +struct sockaddr_in6 { + unsigned short sin6_family; + u_int16_t sin6_port; + u_int32_t sin6_flowinfo; + struct in6_addr sin6_addr; +}; +#endif /* !HAVE_STRUCT_SOCKADDR_IN6 */ + +#ifndef AF_INET6 +/* Define it to something that should never appear */ +#define AF_INET6 AF_MAX +#endif + +/* + * Next, RFC2553 name / address resolution API + */ + +#ifndef NI_NUMERICHOST +# define NI_NUMERICHOST (1) +#endif +#ifndef NI_NAMEREQD +# define NI_NAMEREQD (1<<1) +#endif +#ifndef NI_NUMERICSERV +# define NI_NUMERICSERV (1<<2) +#endif + +#ifndef AI_PASSIVE +# define AI_PASSIVE (1) +#endif +#ifndef AI_CANONNAME +# define AI_CANONNAME (1<<1) +#endif +#ifndef AI_NUMERICHOST +# define AI_NUMERICHOST (1<<2) +#endif + +#ifndef NI_MAXSERV +# define NI_MAXSERV 32 +#endif /* !NI_MAXSERV */ +#ifndef NI_MAXHOST +# define NI_MAXHOST 1025 +#endif /* !NI_MAXHOST */ + +#ifndef EAI_NODATA +# define EAI_NODATA 1 +# define EAI_MEMORY 2 +# define EAI_NONAME 3 +#endif + +#ifndef HAVE_STRUCT_ADDRINFO +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for hostname */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ +}; +#endif /* !HAVE_STRUCT_ADDRINFO */ + +#ifndef HAVE_GETADDRINFO +#ifdef getaddrinfo +# undef getaddrinfo +#endif +#define getaddrinfo(a,b,c,d) (ssh_getaddrinfo(a,b,c,d)) +int getaddrinfo(const char *, const char *, + const struct addrinfo *, struct addrinfo **); +#endif /* !HAVE_GETADDRINFO */ + +#if !defined(HAVE_GAI_STRERROR) && !defined(HAVE_CONST_GAI_STRERROR_PROTO) +#define gai_strerror(a) (ssh_gai_strerror(a)) +char *gai_strerror(int); +#endif /* !HAVE_GAI_STRERROR */ + +#ifndef HAVE_FREEADDRINFO +#define freeaddrinfo(a) (ssh_freeaddrinfo(a)) +void freeaddrinfo(struct addrinfo *); +#endif /* !HAVE_FREEADDRINFO */ + +#ifndef HAVE_GETNAMEINFO +#define getnameinfo(a,b,c,d,e,f,g) (ssh_getnameinfo(a,b,c,d,e,f,g)) +int getnameinfo(const struct sockaddr *, size_t, char *, size_t, + char *, size_t, int); +#endif /* !HAVE_GETNAMEINFO */ + +#endif /* !_FAKE_RFC2553_H */ + diff --git a/options.h b/options.h index 99115db..c841332 100644 --- a/options.h +++ b/options.h @@ -51,10 +51,13 @@ #define ENABLE_X11FWD /* Enable TCP Fowarding */ -/* OpenSSH's "-L" style forwarding (client port forwarded via server) */ -#define ENABLE_LOCALTCPFWD -/* OpenSSH's "-R" style forwarding (server port forwarded via client) */ -#define ENABLE_REMOTETCPFWD +/* "-L" style forwarding (client listening port forwarded via server) */ +#define ENABLE_CLI_LOCALTCPFWD +/* "-R" style forwarding (server listening port forwarded via client) */ +#define ENABLE_CLI_REMOTETCPFWD + +#define ENABLE_SVR_LOCALTCPFWD +#define ENABLE_SVR_REMOTETCPFWD /* Enable Authentication Agent Forwarding */ #define ENABLE_AGENTFWD @@ -299,6 +302,10 @@ #define DISABLE_REMOTETCPFWD #endif +#if defined(ENABLE_CLI_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD) +#define ENABLE_CLI_ANYTCPFWD +#endif + #if defined(ENABLE_REMOTETCPFWD) || defined(ENABLE_LOCALTCPFWD) || \ defined(ENABLE_AGENTFWD) || defined(ENABLE_X11FWD) #define USING_LISTENERS diff --git a/runopts.h b/runopts.h index c74dab5..a160a29 100644 --- a/runopts.h +++ b/runopts.h @@ -29,6 +29,7 @@ #include "signkey.h" #include "buffer.h" #include "auth.h" +#include "tcpfwd.h" typedef struct runopts { @@ -90,8 +91,14 @@ typedef struct cli_runopts { char *cmd; int wantpty; - struct PubkeyList *pubkeys; /* Keys to use for public-key auth */ #ifdef DROPBEAR_PUBKEY_AUTH + struct PubkeyList *pubkeys; /* Keys to use for public-key auth */ +#endif +#ifdef ENABLE_CLI_REMOTETCPFWD + struct TCPFwdList * remotefwds; +#endif +#ifdef ENABLE_CLI_LOCALTCPFWD + struct TCPFwdList * localfwds; #endif /* XXX TODO */ diff --git a/session.h b/session.h index 4a9d4ed..6a6ed07 100644 --- a/session.h +++ b/session.h @@ -35,6 +35,7 @@ #include "queue.h" #include "listener.h" #include "packet.h" +#include "tcpfwd.h" extern int sessinitdone; /* Is set to 0 somewhere */ extern int exitflag; diff --git a/svr-tcpfwd.c b/svr-tcpfwd.c index 46c7129..0eccae4 100644 --- a/svr-tcpfwd.c +++ b/svr-tcpfwd.c @@ -1,7 +1,6 @@ #include "includes.h" #include "ssh.h" -#include "tcp-accept.h" -#include "tcp-connect.h" +#include "tcpfwd.h" #include "dbutil.h" #include "session.h" #include "buffer.h" @@ -15,6 +14,7 @@ static void send_msg_request_success(); static void send_msg_request_failure(); static int svr_cancelremotetcp(); static int svr_remotetcpreq(); +static int newtcpdirect(struct Channel * channel); const struct ChanType svr_chan_tcpdirect = { @@ -178,8 +178,8 @@ static int svr_remotetcpreq() { tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener)); tcpinfo->sendaddr = bindaddr; - TRACE(("sendport = %d", port)); tcpinfo->sendport = port; + tcpinfo->listenport = port; tcpinfo->chantype = &svr_chan_tcpremote; /* Note: bindaddr is actually ignored by listen_tcpfwd, since @@ -196,4 +196,70 @@ out: TRACE(("leave remotetcpreq")); return ret; } + +/* 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; + char portstring[NI_MAXSERV]; + int sock; + int len; + int ret = DROPBEAR_FAILURE; + + if (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; + } + + snprintf(portstring, sizeof(portstring), "%d", destport); + sock = connect_remote(desthost, portstring, 1, NULL); + 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; +} + #endif diff --git a/tcp-accept.c b/tcp-accept.c index 8f8b5c0..6b82914 100644 --- a/tcp-accept.c +++ b/tcp-accept.c @@ -1,6 +1,6 @@ #include "includes.h" #include "ssh.h" -#include "tcp-accept.h" +#include "tcpfwd.h" #include "dbutil.h" #include "session.h" #include "buffer.h" @@ -67,7 +67,7 @@ int listen_tcpfwd(struct TCPListener* tcpinfo) { 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", tcpinfo->sendport); + snprintf(portstring, sizeof(portstring), "%d", tcpinfo->listenport); /* XXX Note: we're just listening on localhost, no matter what they tell * us. If someone wants to make it listen otherways, then change diff --git a/tcp-accept.h b/tcp-accept.h deleted file mode 100644 index 8c795dc..0000000 --- a/tcp-accept.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _REMOTETCPFWD_H -#define _REMOTETCPFWD_H - -struct TCPListener { - - /* sendaddr/sendport are what we send in the channel init request. For a - * forwarded-tcpip request, it's the addr/port we were binding to. - * For a direct-tcpip request, it's the addr/port we want the other - * end to connect to */ - - unsigned char *sendaddr; - unsigned int sendport; - - /* This is for direct-tcpip (ie the client listening), and specifies the - * port to listen on. Is unspecified for the server */ - unsigned int listenport; - - const struct ChanType *chantype; - -}; - -void recv_msg_global_request_remotetcp(); -int listen_tcpfwd(struct TCPListener* tcpinfo); - -#endif /* _REMOTETCPFWD_H */ diff --git a/tcp-connect.c b/tcp-connect.c deleted file mode 100644 index d24f32d..0000000 --- a/tcp-connect.c +++ /dev/null @@ -1,75 +0,0 @@ -#include "includes.h" -#include "session.h" -#include "dbutil.h" -#include "channel.h" -#include "tcp-connect.h" -#include "runopts.h" - -#ifndef DISABLE_TCP_CONNECT - -/* Called upon creating a new direct tcp channel (ie we connect out to an - * address */ -int newtcpdirect(struct Channel * channel) { - - unsigned char* desthost = NULL; - unsigned int destport; - unsigned char* orighost = NULL; - unsigned int origport; - char portstring[NI_MAXSERV]; - int sock; - int len; - int ret = DROPBEAR_FAILURE; - - if (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; - } - - snprintf(portstring, sizeof(portstring), "%d", destport); - sock = connect_remote(desthost, portstring, 1, NULL); - 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; -} - -#endif /* DISABLE_TCPFWD_DIRECT */ diff --git a/tcp-connect.h b/tcp-connect.h deleted file mode 100644 index 40ce22b..0000000 --- a/tcp-connect.h +++ /dev/null @@ -1,35 +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 _TCPFWD_DIRECT_H_ -#define _TCPFWD_DIRECT_H_ -#ifndef DISABLE_TCFWD_DIRECT - -#include "includes.h" -#include "channel.h" - -extern const struct ChanType svr_chan_tcpdirect; -int newtcpdirect(struct Channel * channel); - -#endif -#endif diff --git a/tcpfwd.h b/tcpfwd.h new file mode 100644 index 0000000..569d59d --- /dev/null +++ b/tcpfwd.h @@ -0,0 +1,69 @@ +/* + * 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_H +#define _TCPFWD_H + +#include "channel.h" + +struct TCPListener { + + /* sendaddr/sendport are what we send in the channel init request. For a + * forwarded-tcpip request, it's the addr/port we were binding to. + * For a direct-tcpip request, it's the addr/port we want the other + * end to connect to */ + + unsigned char *sendaddr; + unsigned int sendport; + + /* This is for direct-tcpip (ie the client listening), and specifies the + * port to listen on. Is unspecified for the server */ + unsigned int listenport; + + const struct ChanType *chantype; + +}; + +/* A link in a list of forwards */ +struct TCPFwdList { + + char* connectaddr; + unsigned int connectport; + unsigned int listenport; + struct TCPFwdList * next; + +}; + +/* Server */ +void recv_msg_global_request_remotetcp(); +extern const struct ChanType svr_chan_tcpdirect; + +/* Client */ +void setup_localtcp(); +extern const struct ChanType cli_chan_tcpremote; + +/* Common */ +int listen_tcpfwd(struct TCPListener* tcpinfo); + + +#endif -- cgit v1.2.3 From 9ea7c3bfcf5fdf3728471b7325278fa59d80fc54 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 12 Aug 2004 13:54:31 +0000 Subject: Oops, forgot to call the actual code. --HG-- extra : convert_revision : 1394bf640a0721eb3851fdb9e534c5a65c8bc0f6 --- Makefile.in | 2 +- cli-session.c | 4 +++- options.h | 4 ++++ tcp-accept.c | 5 ++--- 4 files changed, 10 insertions(+), 5 deletions(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 68ef5d8..4ea2f28 100644 --- a/Makefile.in +++ b/Makefile.in @@ -33,7 +33,7 @@ CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \ common-channel.o common-chansession.o termcodes.o loginrec.o \ - tcp-accept.o tcp-connect.o listener.o process-packet.o \ + tcp-accept.o listener.o process-packet.o \ common-runopts.o KEYOBJS=dropbearkey.o gendss.o genrsa.o diff --git a/cli-session.c b/cli-session.c index 318bc64..20ce89a 100644 --- a/cli-session.c +++ b/cli-session.c @@ -179,8 +179,10 @@ static void cli_sessionloop() { case USERAUTH_SUCCESS_RCVD: #ifdef ENABLE_CLI_LOCALTCPFWD - TRACE(("recvd USERAUTH_SUCCESS_RCVD")); setup_localtcp(); +#endif +#ifdef ENABLE_CLI_REMOTETCPFWD + setup_remotetcp(); #endif cli_send_chansess_request(); TRACE(("leave cli_sessionloop: cli_send_chansess_request")); diff --git a/options.h b/options.h index c841332..cb9dc9a 100644 --- a/options.h +++ b/options.h @@ -306,6 +306,10 @@ #define ENABLE_CLI_ANYTCPFWD #endif +#if defined(ENABLE_CLI_LOCALTCPFWD) || defined(ENABLE_SVR_REMOTETCPFWD) +#define DROPBEAR_TCP_ACCEPT +#endif + #if defined(ENABLE_REMOTETCPFWD) || defined(ENABLE_LOCALTCPFWD) || \ defined(ENABLE_AGENTFWD) || defined(ENABLE_X11FWD) #define USING_LISTENERS diff --git a/tcp-accept.c b/tcp-accept.c index 6b82914..63d9775 100644 --- a/tcp-accept.c +++ b/tcp-accept.c @@ -8,8 +8,7 @@ #include "listener.h" #include "runopts.h" -#ifndef DISABLE_TCP_ACCEPT - +#ifdef DROPBEAR_TCP_ACCEPT static void cleanup_tcp(struct Listener *listener) { @@ -94,4 +93,4 @@ int listen_tcpfwd(struct TCPListener* tcpinfo) { return DROPBEAR_SUCCESS; } -#endif /* DISABLE_REMOTETCPFWD */ +#endif /* DROPBEAR_TCP_ACCEPT */ -- cgit v1.2.3 From 96a0f77bb4d861d58e1bf36f480d14e8b20afb27 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 12 Aug 2004 14:39:17 +0000 Subject: fake-rfc stuff --HG-- extra : convert_revision : 796008def04e47dc990703134c9fe013f1919190 --- Makefile.in | 4 +-- configure.in | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- fake-rfc2553.c | 5 +++- fake-rfc2553.h | 5 ++-- includes.h | 1 + 5 files changed, 100 insertions(+), 7 deletions(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 4ea2f28..f70bca2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -34,7 +34,7 @@ CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \ common-channel.o common-chansession.o termcodes.o loginrec.o \ tcp-accept.o listener.o process-packet.o \ - common-runopts.o + common-runopts.o fake-rfc2553.o KEYOBJS=dropbearkey.o gendss.o genrsa.o @@ -47,7 +47,7 @@ HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \ debug.h channel.h chansession.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 tcpfwd.h compat.h \ - listener.h + listener.h fake-rfc2553.h dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS) diff --git a/configure.in b/configure.in index 47a9a29..bffd0da 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,9 @@ # -*- Autoconf -*- # Process this file with autoconf and autoheader to produce a configure script. -# This Autoconf file was cobbled from various locations. +# This Autoconf file was cobbled from various locations. In particular, a bunch +# of the platform checks have been taken straight from OpenSSH's configure.ac +# Huge thanks to them for dealing with the horrible platform-specifics :) AC_PREREQ(2.50) AC_INIT(buffer.c) @@ -50,10 +52,17 @@ case "$host" in *-*-aix*) AC_DEFINE(AIX,,Using AIX) + # OpenSSH thinks it's broken. If it isn't, let me know. + AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo) ;; *-*-hpux*) LIBS="$LIBS -lsec" + # It's probably broken. + AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo) + ;; +*-dec-osf*) + AC_DEFINE(BROKEN_GETADDRINFO,,Broken getaddrinfo) ;; esac @@ -205,6 +214,84 @@ AC_CHECK_TYPE([socklen_t], ,[ [#include #include ]) +# for the fake-rfc2553 stuff - straight from OpenSSH + +AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage, [ + AC_TRY_COMPILE( + [ +#include +#include + ], + [ struct sockaddr_storage s; ], + [ ac_cv_have_struct_sockaddr_storage="yes" ], + [ ac_cv_have_struct_sockaddr_storage="no" ] + ) +]) +if test "x$ac_cv_have_struct_sockaddr_storage" = "xyes" ; then + AC_DEFINE(HAVE_STRUCT_SOCKADDR_STORAGE) +fi + +AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [ + AC_TRY_COMPILE( + [ +#include +#include + ], + [ struct sockaddr_in6 s; s.sin6_family = 0; ], + [ ac_cv_have_struct_sockaddr_in6="yes" ], + [ ac_cv_have_struct_sockaddr_in6="no" ] + ) +]) +if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then + AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6,,Have struct sockaddr_in6) +fi + +AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [ + AC_TRY_COMPILE( + [ +#include +#include + ], + [ struct in6_addr s; s.s6_addr[0] = 0; ], + [ ac_cv_have_struct_in6_addr="yes" ], + [ ac_cv_have_struct_in6_addr="no" ] + ) +]) +if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then + AC_DEFINE(HAVE_STRUCT_IN6_ADDR,,Have struct in6_addr) +fi + +AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [ + AC_TRY_COMPILE( + [ +#include +#include +#include + ], + [ struct addrinfo s; s.ai_flags = AI_PASSIVE; ], + [ ac_cv_have_struct_addrinfo="yes" ], + [ ac_cv_have_struct_addrinfo="no" ] + ) +]) +if test "x$ac_cv_have_struct_addrinfo" = "xyes" ; then + AC_DEFINE(HAVE_STRUCT_ADDRINFO,,Have struct addrinfo) +fi + + +# IRIX has a const char return value for gai_strerror() +AC_CHECK_FUNCS(gai_strerror,[ + AC_DEFINE(HAVE_GAI_STRERROR) + AC_TRY_COMPILE([ +#include +#include +#include + +const char *gai_strerror(int);],[ +char *str; + +str = gai_strerror(0);],[ + AC_DEFINE(HAVE_CONST_GAI_STRERROR_PROTO, 1, + [Define if gai_strerror() returns const char *])])]) # for loginrec.c @@ -462,7 +549,7 @@ AC_PROG_GCC_TRADITIONAL AC_FUNC_MEMCMP AC_FUNC_SELECT_ARGTYPES AC_TYPE_SIGNAL -AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty ]) +AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo]) AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME)) @@ -483,6 +570,7 @@ if test -z "$no_ptc_check" ; then fi fi +AC_EXEEXT AC_CONFIG_HEADER(config.h) AC_OUTPUT(Makefile) AC_MSG_RESULT() diff --git a/fake-rfc2553.c b/fake-rfc2553.c index 0186b53..afbea88 100644 --- a/fake-rfc2553.c +++ b/fake-rfc2553.c @@ -1,4 +1,7 @@ /* + * + * Taken from OpenSSH 3.8.1p1 + * * Copyright (C) 2000-2003 Damien Miller. All rights reserved. * Copyright (C) 1999 WIDE Project. All rights reserved. * @@ -37,7 +40,7 @@ #include "includes.h" -RCSID("$Id: fake-rfc2553.c,v 1.5 2003/09/22 02:08:23 dtucker Exp $"); +/* RCSID("$.Id: fake-rfc2553.c,v 1.5 2003/09/22 02:08:23 dtucker Exp $");*/ #ifndef HAVE_GETNAMEINFO int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, diff --git a/fake-rfc2553.h b/fake-rfc2553.h index baea070..053e6a6 100644 --- a/fake-rfc2553.h +++ b/fake-rfc2553.h @@ -1,4 +1,6 @@ -/* $Id: fake-rfc2553.h,v 1.9 2004/03/10 10:06:33 dtucker Exp $ */ +/* Taken from OpenSSH 3.8.1p1 */ + +/* $.Id: fake-rfc2553.h,v 1.9 2004/03/10 10:06:33 dtucker Exp $ */ /* * Copyright (C) 2000-2003 Damien Miller. All rights reserved. @@ -41,7 +43,6 @@ #define _FAKE_RFC2553_H #include "includes.h" -#include "sys/types.h" /* * First, socket and INET6 related definitions diff --git a/includes.h b/includes.h index 3fdd729..52c48ed 100644 --- a/includes.h +++ b/includes.h @@ -119,6 +119,7 @@ #include "libtommath/tommath.h" #include "compat.h" +#include "fake-rfc2553.h" #ifndef HAVE_UINT16_T #ifndef HAVE_U_INT16_T -- cgit v1.2.3 From d7575f95f093f774145a3725a7c5a3e253962e7c Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 12 Aug 2004 14:56:22 +0000 Subject: cleaning up the pubkey defines --HG-- extra : convert_revision : 149ce7a9a9cc5fe670994d6789b40be49895c595 --- Makefile.in | 4 ++-- authpasswd.h | 33 --------------------------------- authpubkey.h | 33 --------------------------------- cli-auth.c | 10 +++++----- cli-authpasswd.c | 2 ++ cli-authpubkey.c | 2 ++ cli-runopts.c | 14 +++++++------- cli-session.c | 2 +- dbutil.c | 2 +- options.h | 12 ++++++------ runopts.h | 2 +- svr-auth.c | 10 ++++------ svr-authpasswd.c | 5 ++--- svr-authpubkey.c | 5 ++--- svr-runopts.c | 4 ++-- svr-session.c | 3 +-- 16 files changed, 38 insertions(+), 105 deletions(-) delete mode 100644 authpasswd.h delete mode 100644 authpubkey.h (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index f70bca2..761a3c9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -43,9 +43,9 @@ CONVERTOBJS=dropbearconvert.o keyimport.o SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o 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 \ + dss.h bignum.h signkey.h rsa.h random.h service.h auth.h \ debug.h channel.h chansession.h config.h queue.h sshpty.h \ - termcodes.h gendss.h genrsa.h authpubkey.h runopts.h includes.h \ + termcodes.h gendss.h genrsa.h runopts.h includes.h \ loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \ listener.h fake-rfc2553.h diff --git a/authpasswd.h b/authpasswd.h deleted file mode 100644 index 9738532..0000000 --- a/authpasswd.h +++ /dev/null @@ -1,33 +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 _AUTH_PASSWD_ -#define _AUTH_PASSWD_ - -#ifdef DROPBEAR_PASSWORD_AUTH - -void passwordauth(); - -#endif /* DROPBEAR_PASSWORD_AUTH */ -#endif /* _AUTH_PASSWD_ */ diff --git a/authpubkey.h b/authpubkey.h deleted file mode 100644 index bf9549e..0000000 --- a/authpubkey.h +++ /dev/null @@ -1,33 +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 _PUBKEY_AUTH_ -#define _PUBKEY_AUTH_ - -#ifdef DROPBEAR_PUBKEY_AUTH - -void pubkeyauth(); - -#endif /* DROPBEAR_PUBKEY_AUTH */ -#endif /* _PUBKEY_AUTH_ */ diff --git a/cli-auth.c b/cli-auth.c index 98e2e99..39a336e 100644 --- a/cli-auth.c +++ b/cli-auth.c @@ -92,7 +92,7 @@ void recv_msg_userauth_failure() { return; } -#ifdef DROPBEAR_PUBKEY_AUTH +#ifdef ENABLE_CLI_PUBKEY_AUTH /* If it was a pubkey auth request, we should cross that key * off the list. */ if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) { @@ -126,13 +126,13 @@ void recv_msg_userauth_failure() { for (i = 0; i <= methlen; i++) { if (methods[i] == '\0') { TRACE(("auth method '%s'", tok)); -#ifdef DROPBEAR_PUBKEY_AUTH +#ifdef ENABLE_CLI_PUBKEY_AUTH if (strncmp(AUTH_METHOD_PUBKEY, tok, AUTH_METHOD_PUBKEY_LEN) == 0) { ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; } #endif -#ifdef DROPBEAR_PASSWORD_AUTH +#ifdef ENABLE_CLI_PASSWORD_AUTH if (strncmp(AUTH_METHOD_PASSWORD, tok, AUTH_METHOD_PASSWORD_LEN) == 0) { ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; @@ -163,14 +163,14 @@ void cli_auth_try() { CHECKCLEARTOWRITE(); /* XXX We hardcode that we try a pubkey first */ -#ifdef DROPBEAR_PUBKEY_AUTH +#ifdef ENABLE_CLI_PUBKEY_AUTH if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) { finished = cli_auth_pubkey(); cli_ses.lastauthtype = AUTH_TYPE_PUBKEY; } #endif -#ifdef DROPBEAR_PASSWORD_AUTH +#ifdef ENABLE_CLI_PASSWORD_AUTH if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) { finished = cli_auth_password(); cli_ses.lastauthtype = AUTH_TYPE_PASSWORD; diff --git a/cli-authpasswd.c b/cli-authpasswd.c index c04d240..2a66a06 100644 --- a/cli-authpasswd.c +++ b/cli-authpasswd.c @@ -5,6 +5,7 @@ #include "ssh.h" #include "runopts.h" +#ifdef ENABLE_CLI_PASSWORD_AUTH int cli_auth_password() { char* password = NULL; @@ -35,3 +36,4 @@ int cli_auth_password() { return 1; /* Password auth can always be tried */ } +#endif diff --git a/cli-authpubkey.c b/cli-authpubkey.c index 33514ce..7e380e1 100644 --- a/cli-authpubkey.c +++ b/cli-authpubkey.c @@ -6,6 +6,7 @@ #include "runopts.h" #include "auth.h" +#ifdef ENABLE_CLI_PUBKEY_AUTH static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign); /* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request. @@ -158,3 +159,4 @@ int cli_auth_pubkey() { return 0; } } +#endif /* Pubkey auth */ diff --git a/cli-runopts.c b/cli-runopts.c index cef8312..e66f860 100644 --- a/cli-runopts.c +++ b/cli-runopts.c @@ -34,7 +34,7 @@ cli_runopts cli_opts; /* GLOBAL */ static void printhelp(); static void parsehostname(char* userhostarg); -#ifdef DROPBEAR_PUBKEY_AUTH +#ifdef ENABLE_CLI_PUBKEY_AUTH static void loadidentityfile(const char* filename); #endif #ifdef ENABLE_CLI_ANYTCPFWD @@ -49,7 +49,7 @@ static void printhelp() { "-p \n" "-t Allocate a pty\n" "-T Don't allocate a pty\n" -#ifdef DROPBEAR_PUBKEY_AUTH +#ifdef ENABLE_CLI_PUBKEY_AUTH "-i (multiple allowed)\n" #endif #ifdef ENABLE_CLI_LOCALTCPFWD @@ -67,7 +67,7 @@ void cli_getopts(int argc, char ** argv) { unsigned int i, j; char ** next = 0; unsigned int cmdlen; -#ifdef DROPBEAR_PUBKEY_AUTH +#ifdef ENABLE_CLI_PUBKEY_AUTH int nextiskey = 0; /* A flag if the next argument is a keyfile */ #endif #ifdef ENABLE_CLI_LOCALTCPFWD @@ -85,7 +85,7 @@ void cli_getopts(int argc, char ** argv) { cli_opts.username = NULL; cli_opts.cmd = NULL; cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */ -#ifdef DROPBEAR_PUBKEY_AUTH +#ifdef ENABLE_CLI_PUBKEY_AUTH cli_opts.pubkeys = NULL; #endif #ifdef ENABLE_CLI_LOCALTCPFWD @@ -103,7 +103,7 @@ void cli_getopts(int argc, char ** argv) { /* Iterate all the arguments */ for (i = 1; i < (unsigned int)argc; i++) { -#ifdef DROPBEAR_PUBKEY_AUTH +#ifdef ENABLE_CLI_PUBKEY_AUTH if (nextiskey) { /* Load a hostkey since the previous argument was "-i" */ loadidentityfile(argv[i]); @@ -150,7 +150,7 @@ void cli_getopts(int argc, char ** argv) { case 'p': /* remoteport */ next = &cli_opts.remoteport; break; -#ifdef DROPBEAR_PUBKEY_AUTH +#ifdef ENABLE_CLI_PUBKEY_AUTH case 'i': /* an identityfile */ nextiskey = 1; break; @@ -255,7 +255,7 @@ void cli_getopts(int argc, char ** argv) { } } -#ifdef DROPBEAR_PUBKEY_AUTH +#ifdef ENABLE_CLI_PUBKEY_AUTH static void loadidentityfile(const char* filename) { struct PubkeyList * nextkey; diff --git a/cli-session.c b/cli-session.c index 20ce89a..07a5ba8 100644 --- a/cli-session.c +++ b/cli-session.c @@ -37,7 +37,7 @@ static const packettype cli_packettypes[] = { {SSH_MSG_CHANNEL_OPEN_CONFIRMATION, recv_msg_channel_open_confirmation}, {SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure}, {SSH_MSG_USERAUTH_BANNER, recv_msg_userauth_banner}, /* client */ -#ifdef DROPBEAR_PUBKEY_AUTH +#ifdef ENABLE_CLI_PUBKEY_AUTH {SSH_MSG_USERAUTH_PK_OK, recv_msg_userauth_pk_ok}, /* client */ #endif {0, 0} /* End */ diff --git a/dbutil.c b/dbutil.c index b5cd2b0..5436cbb 100644 --- a/dbutil.c +++ b/dbutil.c @@ -442,7 +442,7 @@ int buf_readfile(buffer* buf, const char* filename) { * authkeys file. * Will return DROPBEAR_SUCCESS if data is read, or DROPBEAR_FAILURE on EOF.*/ /* Only used for ~/.ssh/known_hosts and ~/.ssh/authorized_keys */ -#if defined(DROPBEAR_CLIENT) || defined(DROPBEAR_PUBKEY_AUTH) +#if defined(DROPBEAR_CLIENT) || defined(ENABLE_SVR_PUBKEY_AUTH) int buf_getline(buffer * line, FILE * authfile) { int c = EOF; diff --git a/options.h b/options.h index 9708f23..f0831b9 100644 --- a/options.h +++ b/options.h @@ -114,11 +114,11 @@ /* Authentication types to enable, at least one required. RFC Draft requires pubkey auth, and recommends password */ -#define DROPBEAR_SVR_PASSWORD_AUTH -#define DROPBEAR_SVR_PUBKEY_AUTH +#define ENABLE_SVR_PASSWORD_AUTH +#define ENABLE_SVR_PUBKEY_AUTH -#define DROPBEAR_CLI_PASSWORD_AUTH -#define DROPBEAR_CLI_PUBKEY_AUTH +#define ENABLE_CLI_PASSWORD_AUTH +#define ENABLE_CLI_PUBKEY_AUTH /* Random device to use - you must specify _one only_. * DEV_RANDOM is recommended on hosts with a good /dev/urandom, otherwise use @@ -241,7 +241,7 @@ #define DROPBEAR_COMP_ZLIB 1 /* Required for pubkey auth */ -#if defined(DROPBEAR_PUBKEY_AUTH) || defined(DROPBEAR_CLIENT) +#if defined(ENABLE_SVR_PUBKEY_AUTH) || defined(DROPBEAR_CLIENT) #define DROPBEAR_SIGNKEY_VERIFY #endif @@ -320,7 +320,7 @@ #define USING_LISTENERS #endif -#if defined(DROPBEAR_CLIENT) || defined(DROPBEAR_PUBKEY_AUTH) +#if defined(DROPBEAR_CLIENT) || defined(ENABLE_SVR_PUBKEY_AUTH) #define DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */ #endif diff --git a/runopts.h b/runopts.h index a160a29..4bd3287 100644 --- a/runopts.h +++ b/runopts.h @@ -91,7 +91,7 @@ typedef struct cli_runopts { char *cmd; int wantpty; -#ifdef DROPBEAR_PUBKEY_AUTH +#ifdef ENABLE_CLI_PUBKEY_AUTH struct PubkeyList *pubkeys; /* Keys to use for public-key auth */ #endif #ifdef ENABLE_CLI_REMOTETCPFWD diff --git a/svr-auth.c b/svr-auth.c index db1d6a4..314171f 100644 --- a/svr-auth.c +++ b/svr-auth.c @@ -32,8 +32,6 @@ #include "ssh.h" #include "packet.h" #include "auth.h" -#include "authpasswd.h" -#include "authpubkey.h" #include "runopts.h" static void authclear(); @@ -54,10 +52,10 @@ void svr_authinitialise() { static void authclear() { memset(&ses.authstate, 0, sizeof(ses.authstate)); -#ifdef DROPBEAR_PUBKEY_AUTH +#ifdef ENABLE_SVR_PUBKEY_AUTH ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; #endif -#ifdef DROPBEAR_PASSWORD_AUTH +#ifdef ENABLE_SVR_PASSWORD_AUTH if (!svr_opts.noauthpass) { ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; } @@ -143,7 +141,7 @@ void recv_msg_userauth_request() { goto out; } -#ifdef DROPBEAR_PASSWORD_AUTH +#ifdef ENABLE_SVR_PASSWORD_AUTH if (!svr_opts.noauthpass && !(svr_opts.norootpass && ses.authstate.pw->pw_uid == 0) ) { /* user wants to try password auth */ @@ -156,7 +154,7 @@ void recv_msg_userauth_request() { } #endif -#ifdef DROPBEAR_PUBKEY_AUTH +#ifdef ENABLE_SVR_PUBKEY_AUTH /* user wants to try pubkey auth */ if (methodlen == AUTH_METHOD_PUBKEY_LEN && strncmp(methodname, AUTH_METHOD_PUBKEY, diff --git a/svr-authpasswd.c b/svr-authpasswd.c index 7249553..7c6c7b7 100644 --- a/svr-authpasswd.c +++ b/svr-authpasswd.c @@ -29,9 +29,8 @@ #include "buffer.h" #include "dbutil.h" #include "auth.h" -#include "authpasswd.h" -#ifdef DROPBEAR_PASSWORD_AUTH +#ifdef ENABLE_SVR_PASSWORD_AUTH /* Process a password auth request, sending success or failure messages as * appropriate */ @@ -105,4 +104,4 @@ void svr_auth_password() { } -#endif /* DROPBEAR_PASSWORD_AUTH */ +#endif diff --git a/svr-authpubkey.c b/svr-authpubkey.c index 53d5c06..9205078 100644 --- a/svr-authpubkey.c +++ b/svr-authpubkey.c @@ -30,12 +30,11 @@ #include "buffer.h" #include "signkey.h" #include "auth.h" -#include "authpubkey.h" #include "ssh.h" #include "packet.h" #include "algo.h" -#ifdef DROPBEAR_PUBKEY_AUTH +#ifdef ENABLE_SVR_PUBKEY_AUTH #define MIN_AUTHKEYS_LINE 10 /* "ssh-rsa AB" - short but doesn't matter */ #define MAX_AUTHKEYS_LINE 4200 /* max length of a line in authkeys */ @@ -336,4 +335,4 @@ static int checkfileperm(char * filename) { } -#endif /* DROPBEAR_PUBKEY_AUTH */ +#endif diff --git a/svr-runopts.c b/svr-runopts.c index 996c15c..9ecaf32 100644 --- a/svr-runopts.c +++ b/svr-runopts.c @@ -61,7 +61,7 @@ static void printhelp(const char * progname) { "-m Don't display the motd on login\n" #endif "-w Disallow root logins\n" -#ifdef DROPBEAR_PASSWORD_AUTH +#ifdef ENABLE_SVR_PASSWORD_AUTH "-s Disable password logins\n" "-g Disable password logins for root\n" #endif @@ -174,7 +174,7 @@ void svr_getopts(int argc, char ** argv) { case 'w': svr_opts.norootlogin = 1; break; -#ifdef DROPBEAR_PASSWORD_AUTH +#ifdef ENABLE_SVR_PASSWORD_AUTH case 's': svr_opts.noauthpass = 1; break; diff --git a/svr-session.c b/svr-session.c index d46adf4..a24765d 100644 --- a/svr-session.c +++ b/svr-session.c @@ -35,8 +35,7 @@ #include "channel.h" #include "chansession.h" #include "atomicio.h" -#include "tcp-accept.h" -#include "tcp-connect.h" +#include "tcpfwd.h" #include "service.h" #include "auth.h" #include "runopts.h" -- cgit v1.2.3 From 403c18a30092921f008d55a6d22995c854bce0f3 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sat, 14 Aug 2004 17:35:28 +0000 Subject: Dropbearkey can now print out pubkey portions --HG-- extra : convert_revision : 2d897b12ba8710efe0b042b36b1fd31b2469eb15 --- Makefile.in | 2 +- dbutil.c | 33 ++++++++++++- dropbearconvert.c | 2 +- dropbearkey.c | 138 ++++++++++++++++++++++++++++++++++++++++++------------ keyimport.c | 23 ++------- 5 files changed, 145 insertions(+), 53 deletions(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 761a3c9..b3e5658 100644 --- a/Makefile.in +++ b/Makefile.in @@ -10,7 +10,7 @@ # This makefile is quite evil. ifndef PROGRAMS - PROGRAMS=dropbear dbclient dropbearkey dropbearkey + PROGRAMS=dropbear dbclient dropbearkey dropbearconvert endif LTC=libtomcrypt/libtomcrypt.a diff --git a/dbutil.c b/dbutil.c index 30b5708..d8ecad5 100644 --- a/dbutil.c +++ b/dbutil.c @@ -56,8 +56,15 @@ #define MAX_FMT 100 -void (*_dropbear_exit)(int exitcode, const char* format, va_list param) = NULL; -void (*_dropbear_log)(int priority, const char* format, va_list param) = NULL; +static void generic_dropbear_exit(int exitcode, const char* format, + va_list param); +static void generic_dropbear_log(int priority, const char* format, + va_list param); + +void (*_dropbear_exit)(int exitcode, const char* format, va_list param) + = generic_dropbear_exit; +void (*_dropbear_log)(int priority, const char* format, va_list param) + = generic_dropbear_log; int usingsyslog = 0; /* set by runopts, but required externally to sessions */ #ifndef DISABLE_SYSLOG @@ -88,6 +95,28 @@ void dropbear_exit(const char* format, ...) { va_end(param); } +static void generic_dropbear_exit(int exitcode, const char* format, + va_list param) { + + char fmtbuf[300]; + + snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s", format); + + _dropbear_log(LOG_INFO, fmtbuf, param); + + exit(exitcode); +} + +static void generic_dropbear_log(int priority, const char* format, + va_list param) { + + char printbuf[1024]; + + vsnprintf(printbuf, sizeof(printbuf), format, param); + + fprintf(stderr, "%s\n", printbuf); + +} /* this is what can be called to write arbitrary log messages */ void dropbear_log(int priority, const char* format, ...) { diff --git a/dropbearconvert.c b/dropbearconvert.c index 3ceccff..e0d4baf 100644 --- a/dropbearconvert.c +++ b/dropbearconvert.c @@ -49,7 +49,7 @@ static void printhelp(char * progname) { "Example:\n" "dropbearconvert openssh dropbear /etc/ssh/ssh_host_rsa_key /etc/dropbear_rsa_host_key\n" "\n" - "The inputfile and output file can be '-' to specify\n" + "The inputfile and outputfile can be '-' to specify\n" "standard input or standard output.\n", progname); } diff --git a/dropbearkey.c b/dropbearkey.c index 5d4475b..6a10eab 100644 --- a/dropbearkey.c +++ b/dropbearkey.c @@ -54,28 +54,28 @@ static void printhelp(char * progname); -#define BUF_SIZE 2000 - #define RSA_SIZE (1024/8) /* 1024 bit */ #define DSS_SIZE (1024/8) /* 1024 bit */ static void buf_writefile(buffer * buf, const char * filename); +static void printpubkey(sign_key * key, int keytype); +static void justprintpub(const char* filename); /* Print a help message */ static void printhelp(char * progname) { fprintf(stderr, "Usage: %s -t -f [-s bits]\n" "Options are:\n" - "-t type Type of key to generate. One of:\n" + "-t type Type of key to generate. One of:\n" #ifdef DROPBEAR_RSA - " rsa\n" + " rsa\n" #endif #ifdef DROPBEAR_DSS - " dss\n" + " dss\n" #endif - "-f filename Use filename for the secret key\n" - "-s bits Key size in bits, should be " - "multiple of 8 (optional)\n", + "-f filename Use filename for the secret key\n" + "-s bits Key size in bits, should be a multiple of 8 (optional)\n" + "-y Just print the publickey and fingerprint for the\n private key in .\n", progname); } @@ -88,23 +88,24 @@ int main(int argc, char ** argv) { int i; char ** next = 0; - sign_key *key; - buffer *buf; + sign_key *key = NULL; + buffer *buf = NULL; char * filename = NULL; int keytype = -1; char * typetext = NULL; char * sizetext = NULL; unsigned int bits; unsigned int keysize; + int printpub = 0; /* get the commandline options */ for (i = 1; i < argc; i++) { + if (argv[i] == NULL) { + continue; /* Whack */ + } if (next) { *next = argv[i]; - if (*next == NULL) { - fprintf(stderr, "Invalid null argument"); - } - next = 0x00; + next = NULL; continue; } @@ -119,6 +120,9 @@ int main(int argc, char ** argv) { case 's': next = &sizetext; break; + case 'y': + printpub = 1; + break; case 'h': printhelp(argv[0]); exit(EXIT_SUCCESS); @@ -132,17 +136,20 @@ int main(int argc, char ** argv) { } } + if (!filename) { + fprintf(stderr, "Must specify a key filename\n"); + printhelp(argv[0]); + exit(EXIT_FAILURE); + } + + if (printpub) { + justprintpub(filename); + /* Not reached */ + } + /* check/parse args */ if (!typetext) { - fprintf(stderr, "Must specify file type, one of:\n" -#ifdef DROPBEAR_RSA - "rsa\n" -#endif -#ifdef DROPBEAR_DSS - "dss\n" -#endif - "\n" - ); + fprintf(stderr, "Must specify key type\n"); printhelp(argv[0]); exit(EXIT_FAILURE); } @@ -190,11 +197,6 @@ int main(int argc, char ** argv) { } } - if (!filename) { - fprintf(stderr, "Must specify a key filename\n"); - printhelp(argv[0]); - exit(EXIT_FAILURE); - } fprintf(stderr, "Will output %d bit %s secret key to '%s'\n", keysize*8, typetext, filename); @@ -222,7 +224,7 @@ int main(int argc, char ** argv) { exit(EXIT_FAILURE); } - buf = buf_new(BUF_SIZE); + buf = buf_new(MAX_PRIVKEY_SIZE); buf_put_priv_key(buf, key, keytype); buf_setpos(buf, 0); @@ -230,14 +232,88 @@ int main(int argc, char ** argv) { buf_burn(buf); buf_free(buf); - sign_key_free(key); - fprintf(stderr, "Done.\n"); + printpubkey(key, keytype); + + sign_key_free(key); return EXIT_SUCCESS; } #endif +static void justprintpub(const char* filename) { + + buffer *buf = NULL; + sign_key *key = NULL; + int keytype; + int ret; + int err = DROPBEAR_FAILURE; + + buf = buf_new(MAX_PRIVKEY_SIZE); + ret = buf_readfile(buf, filename); + + if (ret != DROPBEAR_SUCCESS) { + fprintf(stderr, "Failed reading '%s'\n", filename); + goto out; + } + + key = new_sign_key(); + keytype = DROPBEAR_SIGNKEY_ANY; + + buf_setpos(buf, 0); + ret = buf_get_priv_key(buf, key, &keytype); + if (ret == DROPBEAR_FAILURE) { + fprintf(stderr, "Bad key in '%s'\n", filename); + goto out; + } + + printpubkey(key, keytype); + + err = DROPBEAR_SUCCESS; + +out: + buf_burn(buf); + buf_free(buf); + buf = NULL; + sign_key_free(key); + key = NULL; + exit(err); +} + +static void printpubkey(sign_key * key, int keytype) { + + buffer * buf = NULL; + unsigned char base64key[MAX_PUBKEY_SIZE*2]; + unsigned long base64len; + int err; + const char * typestring = NULL; + char *fp = NULL; + int len; + + buf = buf_new(MAX_PUBKEY_SIZE); + buf_put_pub_key(buf, key, keytype); + buf_setpos(buf, 4); + + len = buf->len - buf->pos; + + base64len = sizeof(base64key); + err = base64_encode(buf_getptr(buf, len), len, base64key, &base64len); + + if (err != CRYPT_OK) { + fprintf(stderr, "base64 failed"); + } + + typestring = signkey_name_from_type(keytype, &err); + + fp = sign_key_fingerprint(buf_getptr(buf, len), len); + + printf("Public key portion is:\n%s %s\nFingerprint: %s\n", + typestring, base64key, fp); + + m_free(fp); + buf_free(buf); +} + /* Write a buffer to a file specified, failing if the file exists */ static void buf_writefile(buffer * buf, const char * filename) { diff --git a/keyimport.c b/keyimport.c index 34fac2f..32018b1 100644 --- a/keyimport.c +++ b/keyimport.c @@ -109,29 +109,16 @@ static sign_key *dropbear_read(const char* filename) { buffer * buf = NULL; int len, maxlen; - FILE *fp; + FILE *fp = NULL; sign_key *ret = NULL; int type; - buf = buf_new(2000); - /* can't use buf_readfile since we might have "-" as filename */ - if (strlen(filename) == 1 && filename[0] == '-') { - fp = stdin; - } else { - fp = fopen(filename, "r"); - } - if (!fp) { + buf = buf_new(MAX_PRIVKEY_SIZE); + /* buf_readfile knows about "-" */ + if (buf_readfile(buf, filename) == DROPBEAR_FAILURE) { goto error; } - do { - maxlen = buf->size - buf->pos; - len = fread(buf_getwriteptr(buf, maxlen), 1, maxlen, fp); - buf_incrwritepos(buf, len); - } while (len != maxlen && len > 0); - - fclose(fp); - buf_setpos(buf, 0); ret = new_sign_key(); @@ -173,7 +160,7 @@ static int dropbear_write(const char*filename, sign_key * key) { } #endif - buf = buf_new(2000); + buf = buf_new(MAX_PRIVKEY_SIZE); buf_put_priv_key(buf, key, keytype); if (strlen(filename) == 1 && filename[0] == '-') { -- cgit v1.2.3 From eb1f647c9cff9d6107db4dacaf3b3b45e588da61 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Mon, 16 Aug 2004 14:53:49 +0000 Subject: dbclient works as "ssh" too --HG-- extra : convert_revision : 4bf3c662e114ad16c54afdf923f2852e511f77eb --- Makefile.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index b3e5658..c6c716b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -127,8 +127,8 @@ installdropbear: dropbear install%: $* $(INSTALL) -d -m 755 $(DESTDIR)$(bindir) $(INSTALL) -m 755 $(SPREFIX)$*$(EXEEXT) $(DESTDIR)$(bindir) - -chown root $(DESTDIR)$(sbindir)/$(SPREFIX)$*$(EXEEXT) - -chgrp 0 $(DESTDIR)$(sbindir)/$(SPREFIX)$*$(EXEEXT) + -chown root $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT) + -chgrp 0 $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT) ifeq ($(MULTI), 1) @echo @echo "You must manually create links for $*" -- cgit v1.2.3 From 6ec818375005cfd1a6c0bb014cd3543364b16ae3 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 17 Aug 2004 04:35:01 +0000 Subject: do the symlinks for multi-binary compiles --HG-- extra : convert_revision : 1a0ab43c58435f03b261ef322d24fbb5c91e8abd --- Makefile.in | 55 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 20 deletions(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index c6c716b..3bbfe2a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -3,11 +3,10 @@ # invocation: # make PROGRAMS="dropbear dbclient scp" MULTI=1 STATIC=1 SCPPROGRESS=1 # -# to make a single multiple statically linked binary "staticdropbearmulti", -# which includes dropbear, scp and dbclient functionality, and includes the -# progress-bar functionality in scp. Hopefully that seems intuitive. - -# This makefile is quite evil. +# to make a multiple-program statically linked binary "staticdropbearmulti". +# This example will include dropbear, scp, dropbearkey, dropbearconvert, and +# dbclient functionality, and includes the progress-bar functionality in scp. +# Hopefully that seems intuitive. ifndef PROGRAMS PROGRAMS=dropbear dbclient dropbearkey dropbearconvert @@ -20,7 +19,7 @@ COMMONOBJS=dbutil.o buffer.o \ dss.o bignum.o \ signkey.o rsa.o random.o \ queue.o \ - atomicio.o compat.o + atomicio.o compat.o fake-rfc2553.o SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ svr-authpasswd.o svr-authpubkey.o svr-session.o svr-service.o \ @@ -34,7 +33,7 @@ CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \ common-channel.o common-chansession.o termcodes.o loginrec.o \ tcp-accept.o listener.o process-packet.o \ - common-runopts.o fake-rfc2553.o + common-runopts.o KEYOBJS=dropbearkey.o gendss.o genrsa.o @@ -115,25 +114,36 @@ all: $(TARGETS) strip: $(TARGETS) $(STRIP) $(addsuffix $(EXEEXT), $(addprefix $(SPREFIX), $(TARGETS))) -install: $(addprefix install, $(TARGETS)) +install: $(addprefix inst, $(TARGETS)) + +installdropbearmulti: insdbmulti $(addprefix insmulti, $(PROGRAMS)) + +insdbmulti: dropbearmulti + $(INSTALL) -d -m 755 $(DESTDIR)$(bindir) + $(INSTALL) -m 755 $(SPREFIX)dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir) + -chown root $(DESTDIR)$(bindir)/$(SPREFIX)dropbearmulti$(EXEEXT) + -chgrp 0 $(DESTDIR)$(bindir)/$(SPREFIX)dropbearmulti$(EXEEXT) + +insmultidropbear: dropbearmulti + -rm -f $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT) + -ln -s $(DESTDIR)$(bindir)/$(SPREFIX)dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT) + +insmulti%: dropbearmulti + -rm -f $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT) + -ln -s $(DESTDIR)$(bindir)/$(SPREFIX)dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT) # dropbear should go in sbin, so it needs a seperate rule -installdropbear: dropbear +instdropbear: dropbear $(INSTALL) -d -m 755 $(DESTDIR)$(sbindir) $(INSTALL) -m 755 $(SPREFIX)dropbear$(EXEEXT) $(DESTDIR)$(sbindir) -chown root $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT) -chgrp 0 $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT) -install%: $* +inst%: $* $(INSTALL) -d -m 755 $(DESTDIR)$(bindir) $(INSTALL) -m 755 $(SPREFIX)$*$(EXEEXT) $(DESTDIR)$(bindir) -chown root $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT) -chgrp 0 $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT) - ifeq ($(MULTI), 1) - @echo - @echo "You must manually create links for $*" - endif - # for some reason the rule further down doesn't like $($@objs) as a prereq. @@ -158,11 +168,16 @@ ifeq ($(MULTI),1) CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI endif -dropbearmulti: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) Makefile - $(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $(MULTIOBJS) $(LIBS) - @echo - @echo "You should now create symlinks to the programs you have included" - @echo "ie 'ln -s dropbearmulti dropbear'" +dropbearmulti: multilink + +multibinary: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) Makefile + $(LD) $(LDFLAGS) -o $(SPREFIX)dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS) + +multilink: multibinary $(addprefix link, $(PROGRAMS)) + +link%: + -rm -f $(SPREFIX)$*$(EXEEXT) + -ln -s $(SPREFIX)dropbearmulti$(EXEEXT) $(SPREFIX)$*$(EXEEXT) $(LTC): options.h cd libtomcrypt && $(MAKE) clean && $(MAKE) -- cgit v1.2.3 From 3cacc54b787e8ff933181af4ca4b41866ef2b1ce Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 17 Aug 2004 10:40:31 +0000 Subject: Small fixes --HG-- extra : convert_revision : 7f568ec9a453957b16efab56c215a4914f0cebf3 --- Makefile.in | 4 +++- compat.c | 2 +- dbmulti.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 3bbfe2a..2290745 100644 --- a/Makefile.in +++ b/Makefile.in @@ -194,7 +194,9 @@ ltm-clean: sizes: dropbear objdump -t dropbear|grep ".text"|cut -d "." -f 2|sort -rn -clean: ltc-clean ltm-clean +clean: ltc-clean ltm-clean thisclean + +thisclean: -rm -f dropbear dbclient dropbearkey dropbearconvert scp scp-progress -rm -f staticdropbear staticdropbearkey staticdropbearconvert staticscp -rm -f dropbearmulti staticdropbearmulti diff --git a/compat.c b/compat.c index fb6e70a..7e0c1ac 100644 --- a/compat.c +++ b/compat.c @@ -190,7 +190,7 @@ int daemon(int nochdir, int noclose) { #ifndef HAVE_BASENAME -char *basename(char *path) { +char *basename(const char *path) { char *foo = strrchr(path, '/'); return ++foo; diff --git a/dbmulti.c b/dbmulti.c index 8d61c5c..9d76055 100644 --- a/dbmulti.c +++ b/dbmulti.c @@ -44,7 +44,8 @@ int main(int argc, char ** argv) { } #endif #ifdef DBMULTI_dbclient - if (strcmp(progname, "dbclient") == 0) { + if (strcmp(progname, "dbclient") == 0 + || strcmp(progname, "ssh") == 0) { return cli_main(argc, argv); } #endif -- cgit v1.2.3 From 2dcd6b22d94755a4f328885f469908c441ac8534 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 24 Aug 2004 18:12:18 +0000 Subject: Nasty. --HG-- extra : convert_revision : e1229cd01c3007206d2937ea390ad4966c289a5a --- Makefile.in | 4 +- TODO | 2 + channel.h | 24 +++++--- cli-channel.c | 65 ++++++++++++++++++++++ cli-chansession.c | 5 +- cli-session.c | 1 + common-channel.c | 162 ++++++++++++++++++++++++++++++++---------------------- common-session.c | 2 +- dbutil.c | 1 + debug.h | 2 +- signkey.c | 1 + 11 files changed, 191 insertions(+), 78 deletions(-) create mode 100644 cli-channel.c (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 2290745..b945101 100644 --- a/Makefile.in +++ b/Makefile.in @@ -28,12 +28,12 @@ SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ cli-session.o cli-service.o cli-runopts.o cli-chansession.o \ - cli-authpubkey.o cli-tcpfwd.o + cli-authpubkey.o cli-tcpfwd.o cli-channel.o CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \ common-channel.o common-chansession.o termcodes.o loginrec.o \ tcp-accept.o listener.o process-packet.o \ - common-runopts.o + common-runopts.o circbuffer.o KEYOBJS=dropbearkey.o gendss.o genrsa.o diff --git a/TODO b/TODO index 8af3063..0af56c9 100644 --- a/TODO +++ b/TODO @@ -2,6 +2,8 @@ Current: Things which might need doing: +- errfd needs fixing + - Make options.h generated from configure perhaps? - Improved queueing of unauthed connections diff --git a/channel.h b/channel.h index 2289de1..3afd9f1 100644 --- a/channel.h +++ b/channel.h @@ -27,6 +27,7 @@ #include "includes.h" #include "buffer.h" +#include "circbuffer.h" /* channel->type values */ #define CHANNEL_ID_NONE 0 @@ -50,6 +51,8 @@ #define CHAN_EXTEND_SIZE 3 /* how many extra slots to add when we need more */ #define RECV_MAXWINDOW 6000 /* tweak */ +#define RECV_WINDOWEXTEND (RECV_MAXWINDOW/2) /* We send a "window extend" every + RECV_WINDOWEXTEND bytes */ #define RECV_MAXPACKET 1400 /* tweak */ #define RECV_MINWINDOW 19000 /* when we get below this, we send a windowadjust */ @@ -62,13 +65,13 @@ struct Channel { unsigned int recvwindow, transwindow; unsigned int recvmaxpacket, transmaxpacket; void* typedata; /* a pointer to type specific data */ - int infd; /* stdin for the program, we write to this */ - int outfd; /* stdout for the program, we read from this */ - int errfd; /* stdout for a program. This doesn't really fit here, - but makes the code a lot tidyer without being too bad. This - is -1 for channels which don't requre it. Currently only - a 'session' without a pty will use it */ - buffer *writebuf; /* data for the program */ + int infd; /* data to send over the wire */ + int outfd; /* data for consumption, what was in writebuf */ + int errfd; /* used like infd or errfd, depending if it's client or server. + Doesn't exactly belong here, but is cleaner here */ + circbuffer *writebuf; /* data from the wire, for local consumption */ + circbuffer *extrabuf; /* extended-data for the program - used like writebuf + but for stderr */ int sentclosed, recvclosed; @@ -97,6 +100,7 @@ void chaninitialise(); void chancleanup(); void setchannelfds(fd_set *readfd, fd_set *writefd); void channelio(fd_set *readfd, fd_set *writefd); +struct Channel* getchannel(unsigned int chan); struct Channel* newchannel(unsigned int remotechan, const struct ChanType *type, unsigned int transwindow, unsigned int transmaxpacket); @@ -106,10 +110,16 @@ void recv_msg_channel_request(); void send_msg_channel_failure(struct Channel *channel); void send_msg_channel_success(struct Channel *channel); void recv_msg_channel_data(); +void recv_msg_channel_extended_data(); void recv_msg_channel_window_adjust(); void recv_msg_channel_close(); void recv_msg_channel_eof(); +void common_recv_msg_channel_data(struct Channel *channel, int fd, + circbuffer * buf); + +const struct ChanType clichansess; + #ifdef USING_LISTENERS int send_msg_channel_open_init(int fd, const struct ChanType *type); void recv_msg_channel_open_confirmation(); diff --git a/cli-channel.c b/cli-channel.c new file mode 100644 index 0000000..ea4af69 --- /dev/null +++ b/cli-channel.c @@ -0,0 +1,65 @@ +/* + * Dropbear SSH + * + * Copyright (c) 2002-2004 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" +#include "channel.h" +#include "buffer.h" +#include "circbuffer.h" +#include "dbutil.h" +#include "session.h" +#include "ssh.h" + +/* We receive channel data - only used by the client chansession code*/ +void recv_msg_channel_extended_data() { + + unsigned int chan; + struct Channel *channel; + unsigned int datatype; + + TRACE(("enter recv_msg_channel_extended_data")); + + chan = buf_getint(ses.payload); + channel = getchannel(chan); + + if (channel == NULL) { + dropbear_exit("Unknown channel"); + } + + if (channel->type != &clichansess) { + TRACE(("leave recv_msg_channel_extended_data: chantype is wrong")); + return; /* we just ignore it */ + } + + datatype = buf_getint(ses.payload); + + if (datatype != SSH_EXTENDED_DATA_STDERR) { + TRACE(("leave recv_msg_channel_extended_data: wrong datatype: %d", + datatype)); + return; + } + + common_recv_msg_channel_data(channel, channel->errfd, channel->extrabuf); + + TRACE(("leave recv_msg_channel_extended_data")); +} diff --git a/cli-chansession.c b/cli-chansession.c index 1267ae0..df6eb45 100644 --- a/cli-chansession.c +++ b/cli-chansession.c @@ -44,7 +44,7 @@ static void send_chansess_shell_req(struct Channel *channel); static void cli_tty_setup(); void cli_tty_cleanup(); -static const struct ChanType clichansess = { +const struct ChanType clichansess = { 0, /* sepfds */ "session", /* name */ cli_initchansess, /* inithandler */ @@ -316,7 +316,8 @@ static int cli_initchansess(struct Channel *channel) { channel->infd = STDOUT_FILENO; channel->outfd = STDIN_FILENO; - //channel->errfd = STDERR_FILENO; + channel->errfd = STDERR_FILENO; + channel->extrabuf = buf_new(RECV_MAXWINDOW); if (cli_opts.wantpty) { send_chansess_pty_req(channel); diff --git a/cli-session.c b/cli-session.c index 6fef78d..b51e20f 100644 --- a/cli-session.c +++ b/cli-session.c @@ -48,6 +48,7 @@ struct clientsession cli_ses; /* GLOBAL */ static const packettype cli_packettypes[] = { /* TYPE, FUNCTION */ {SSH_MSG_CHANNEL_DATA, recv_msg_channel_data}, + {SSH_MSG_CHANNEL_EXTENDED_DATA, recv_msg_channel_extended_data}, {SSH_MSG_CHANNEL_WINDOW_ADJUST, recv_msg_channel_window_adjust}, {SSH_MSG_USERAUTH_FAILURE, recv_msg_userauth_failure}, /* client */ {SSH_MSG_USERAUTH_SUCCESS, recv_msg_userauth_success}, /* client */ diff --git a/common-channel.c b/common-channel.c index 64ea466..41a7208 100644 --- a/common-channel.c +++ b/common-channel.c @@ -1,7 +1,7 @@ /* - * Dropbear - a SSH2 server + * Dropbear SSH * - * Copyright (c) 2002,2003 Matt Johnston + * Copyright (c) 2002-2004 Matt Johnston * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -29,6 +29,7 @@ #include "packet.h" #include "ssh.h" #include "buffer.h" +#include "circbuffer.h" #include "dbutil.h" #include "channel.h" #include "ssh.h" @@ -147,7 +148,8 @@ struct Channel* newchannel(unsigned int remotechan, newchan->errfd = FD_CLOSED; /* this isn't always set to start with */ newchan->initconn = 0; - newchan->writebuf = buf_new(RECV_MAXWINDOW); + newchan->writebuf = cbuf_new(RECV_MAXWINDOW); + newchan->extrabuf = NULL; /* The user code can set it up */ newchan->recvwindow = RECV_MAXWINDOW; newchan->recvmaxpacket = RECV_MAXPACKET; @@ -160,7 +162,7 @@ struct Channel* newchannel(unsigned int remotechan, } /* Get the channel structure corresponding to a channel number */ -static struct Channel* getchannel(unsigned int chan) { +struct Channel* getchannel(unsigned int chan) { if (chan >= ses.chansize || ses.channels[chan] == NULL) { return NULL; } @@ -345,21 +347,23 @@ static void send_msg_channel_eof(struct Channel *channel) { TRACE(("leave send_msg_channel_eof")); } -/* Called to write data out to the server side of a channel (eg a shell or a - * program. +/* Called to write data out to the local side of the channel. * Only called when we know we can write to a channel, writes as much as * possible */ static void writechannel(struct Channel* channel) { int len, maxlen; - buffer *buf; + circbuffer *cbuf; TRACE(("enter writechannel")); - buf = channel->writebuf; - maxlen = buf->len - buf->pos; + cbuf = channel->writebuf; + maxlen = cbuf_readlen(cbuf); + + TRACE(("maxlen = %d", maxlen)); - len = write(channel->infd, buf_getptr(buf, maxlen), maxlen); + /* Write the data out */ + len = write(channel->infd, cbuf_readptr(cbuf, maxlen), maxlen); if (len <= 0) { if (len < 0 && errno != EINTR) { /* no more to write */ @@ -368,26 +372,27 @@ static void writechannel(struct Channel* channel) { TRACE(("leave writechannel: len <= 0")); return; } - - if (len == maxlen) { - buf_setpos(buf, 0); - buf_setlen(buf, 0); - if (channel->recveof) { - /* we're closing up */ - closeinfd(channel); - return; - TRACE(("leave writechannel: recveof set")); - } + TRACE(("len = %d", len)); + cbuf_incrread(cbuf, len); + + if (len == maxlen && channel->recveof) { + /* Check if we're closing up */ + closeinfd(channel); + return; + TRACE(("leave writechannel: recveof set")); - /* extend the window if we're at the end*/ - /* TODO - this is inefficient */ - send_msg_channel_window_adjust(channel, buf->size - - channel->recvwindow); - channel->recvwindow = buf->size; - } else { - buf_incrpos(buf, len); } + + /* Window adjust handling */ + if (channel->recvwindow < (RECV_MAXWINDOW - RECV_WINDOWEXTEND)) { + /* Set it back to max window */ + send_msg_channel_window_adjust(channel, RECV_MAXWINDOW - + channel->recvwindow); + channel->recvwindow = RECV_MAXWINDOW; + } + + TRACE(("leave writechannel")); } @@ -405,31 +410,37 @@ void setchannelfds(fd_set *readfd, fd_set *writefd) { continue; } - /* stdout and stderr */ + /* Stuff to put over the wire */ if (channel->transwindow > 0) { - /* stdout */ if (channel->outfd >= 0) { - /* there's space to read more from the program */ FD_SET(channel->outfd, readfd); } - /* stderr */ - if (channel->errfd >= 0) { + + if (channel->extrabuf == NULL && channel->errfd >= 0) { FD_SET(channel->errfd, readfd); } } + /* For checking FD status (ie closure etc) - we don't actually + * read data from infd */ if (channel->infd >= 0 && channel->infd != channel->outfd) { FD_SET(channel->infd, readfd); } - /* stdin */ - if (channel->infd >= 0 && - (channel->writebuf->pos < channel->writebuf->len || - channel->initconn)) { - /* there's space to write more to the program */ - FD_SET(channel->infd, writefd); + /* Stuff from the wire, to local program/shell/user etc */ + if ((channel->infd >= 0 && cbuf_getused(channel->writebuf) > 0 ) + || channel->initconn) { + + FD_SET(channel->infd, writefd); + } + + /* + if (channel->extrabuf != NULL && channel->errfd >= 0 + && cbuf_getavail(channel->extrabuf) > 0 ) { + FD_SET(channel->errfd, writefd); } + */ } /* foreach channel */ @@ -457,7 +468,7 @@ void recv_msg_channel_eof() { } channel->recveof = 1; - if (channel->writebuf->len == 0) { + if (cbuf_getused(channel->writebuf) == 0) { closeinfd(channel); } @@ -499,9 +510,15 @@ static void removechannel(struct Channel * channel) { TRACE(("enter removechannel")); TRACE(("channel index is %d", channel->index)); - buf_free(channel->writebuf); + cbuf_free(channel->writebuf); channel->writebuf = NULL; + if (channel->extrabuf) { + cbuf_free(channel->extrabuf); + channel->extrabuf = NULL; + } + + /* close the FDs in case they haven't been done * yet (ie they were shutdown etc */ close(channel->infd); @@ -623,59 +640,74 @@ static void send_msg_channel_data(struct Channel *channel, int isextended, TRACE(("leave send_msg_channel_data")); } - -/* when we receive channel data, put it in a buffer for writing to the program/ - * shell etc */ +/* We receive channel data */ void recv_msg_channel_data() { unsigned int chan; - struct Channel * channel; - unsigned int datalen; - unsigned int pos; - unsigned int maxdata; + struct Channel *channel; - TRACE(("enter recv_msg_channel_data")); - chan = buf_getint(ses.payload); channel = getchannel(chan); + if (channel == NULL) { dropbear_exit("Unknown channel"); } + common_recv_msg_channel_data(channel, channel->infd, channel->writebuf); +} + +/* Shared for data and stderr data - when we receive data, put it in a buffer + * for writing to the local file descriptor */ +void common_recv_msg_channel_data(struct Channel *channel, int fd, + circbuffer * cbuf) { + + unsigned int datalen; + unsigned int maxdata; + unsigned int buflen; + unsigned int len; + + TRACE(("enter recv_msg_channel_data")); + if (channel->recveof) { dropbear_exit("received data after eof"); } - if (channel->infd < 0) { + if (fd < 0) { dropbear_exit("received data with bad infd"); } datalen = buf_getint(ses.payload); + TRACE(("datalen = %d", datalen)); + /* if the client is going to send us more data than we've allocated, then * it has ignored the windowsize, so we "MAY ignore all extra data" */ - maxdata = channel->writebuf->size - channel->writebuf->pos; + maxdata = cbuf_getavail(cbuf); + TRACE(("maxdata = %d", maxdata)); if (datalen > maxdata) { TRACE(("Warning: recv_msg_channel_data: extra data past window")); datalen = maxdata; } - /* write to the buffer - we always append to the end of the buffer */ - pos = channel->writebuf->pos; - buf_setpos(channel->writebuf, channel->writebuf->len); - memcpy(buf_getwriteptr(channel->writebuf, datalen), - buf_getptr(ses.payload, datalen), datalen); - buf_incrwritepos(channel->writebuf, datalen); - buf_setpos(channel->writebuf, pos); /* revert pos */ - channel->recvwindow -= datalen; + /* We may have to run throught twice, if the buffer wraps around. Can't + * just "leave it for next time" like with writechannel, since this + * is payload data */ + len = datalen; + while (len > 0) { + buflen = cbuf_writelen(cbuf); + TRACE(("buflen = %d", buflen)); + buflen = MIN(buflen, len); + TRACE(("buflenmin = %d", buflen)); + + memcpy(cbuf_writeptr(cbuf, buflen), + buf_getptr(ses.payload, buflen), buflen); + cbuf_incrwrite(cbuf, buflen); + len -= buflen; + TRACE(("len = %d", buflen)); + } - /* matt - this might be for later */ -/* if (channel->recvwindow < RECV_MINWINDOW) { - send_msg_channel_window_adjust(channel, - RECV_MAXWINDOW - channel->recvwindow); - channel->recvwindow = RECV_MAXWINDOW; - }*/ + channel->recvwindow -= datalen; TRACE(("leave recv_msg_channel_data")); } diff --git a/common-session.c b/common-session.c index 420e03b..1888eb7 100644 --- a/common-session.c +++ b/common-session.c @@ -235,7 +235,7 @@ void session_identification() { * account for wrappers/cruft etc. According to the spec only the client * needs to handle this, but no harm in letting the server handle it too */ for (i = 0; i < 10; i++) { - len = ident_readln(ses.sock, linebuf, sizzeof(linebuf)); + len = ident_readln(ses.sock, linebuf, sizeof(linebuf)); if (len < 0 && errno != EINTR) { /* It failed */ diff --git a/dbutil.c b/dbutil.c index f49c78f..0896bc9 100644 --- a/dbutil.c +++ b/dbutil.c @@ -146,6 +146,7 @@ void dropbear_trace(const char* format, ...) { fprintf(stderr, "TRACE: "); vfprintf(stderr, format, param); fprintf(stderr, "\n"); + fflush(stderr); va_end(param); } #endif /* DEBUG_TRACE */ diff --git a/debug.h b/debug.h index 9bb840b..cc161dc 100644 --- a/debug.h +++ b/debug.h @@ -38,7 +38,7 @@ * Caution: Don't use this in an unfriendly environment (ie unfirewalled), * since the printing may not sanitise strings etc. This will add a reasonable * amount to your executable size. */ -/* #define DEBUG_TRACE */ + #define DEBUG_TRACE /* All functions writing to the cleartext payload buffer call * CHECKCLEARTOWRITE() before writing. This is only really useful if you're diff --git a/signkey.c b/signkey.c index 7ae08b8..2c8da55 100644 --- a/signkey.c +++ b/signkey.c @@ -153,6 +153,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) { m_free(ident); if (*type != DROPBEAR_SIGNKEY_ANY && *type != keytype) { + TRACE(("wrong key type: %d %d", *type, keytype)); return DROPBEAR_FAILURE; } -- cgit v1.2.3 From fa26b59b0c45aa34586a00718f14cc44bd94e513 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 12 Sep 2004 05:52:36 +0000 Subject: propagate of 08347df3bca787bd3621602fe2b466c85c9dc3e2 and 717950f4061f1123659ee87c7c168805af920ab7 from branch 'matt.dbclient.rez' to 'matt.dbclient.authpam' --HG-- branch : private-rez extra : convert_revision : 555c429bf4e557ea5fd0af9db3987166d8217d8b --- Makefile.in | 3 +- configure.in | 2 +- options.h | 17 +-- svr-auth.c | 5 +- svr-authpam.c | 328 +++++++++++++++++++++++++++---------------------------- svr-authpasswd.c | 4 - 6 files changed, 175 insertions(+), 184 deletions(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index cc221d5..0d77571 100644 --- a/Makefile.in +++ b/Makefile.in @@ -23,9 +23,8 @@ COMMONOBJS=dbutil.o buffer.o \ SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ svr-authpasswd.o svr-authpubkey.o svr-session.o svr-service.o \ - svr-authpam.o svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\ - svr-tcpfwd.o + svr-tcpfwd.o svr-authpam.o CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ cli-session.o cli-service.o cli-runopts.o cli-chansession.o \ diff --git a/configure.in b/configure.in index d29ae89..b86fc1d 100644 --- a/configure.in +++ b/configure.in @@ -205,7 +205,7 @@ AC_ARG_ENABLE(shadow, # Checks for header files. AC_HEADER_STDC AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h sys/dirent.h security/pam_appl.h pam/pam_appl.h]) +AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h pam/pam_appl.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST diff --git a/options.h b/options.h index 057ed16..213a7a9 100644 --- a/options.h +++ b/options.h @@ -112,12 +112,11 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ /* Authentication types to enable, at least one required. RFC Draft requires pubkey auth, and recommends password */ -//#define DROPBEAR_PASSWORD_AUTH -/* Only set PAM auth if you aren't using PASSWORD auth. Also, you'll need - * to make sure PAM libraries etc are installed */ -#define DROPBEAR_PAM_AUTH -#define DROPBEAR_PUBKEY_AUTH -#define ENABLE_SVR_PASSWORD_AUTH +/*#define ENABLE_SVR_PASSWORD_AUTH*/ +/* Only set PAM auth if you aren't using SVR_PASSWORD_AUTH. Also, you'll need + * to make sure PAM libraries etc are installed. To the client, PAM auth looks + * just like password auth. */ +#define ENABLE_SVR_PAM_AUTH #define ENABLE_SVR_PUBKEY_AUTH #define ENABLE_CLI_PASSWORD_AUTH @@ -178,7 +177,7 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ *******************************************************************/ #ifndef DROPBEAR_VERSION -#define DROPBEAR_VERSION "0.44test3" +#define DROPBEAR_VERSION "0.44rez1" #endif #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION @@ -327,6 +326,10 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ #define DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */ #endif +#if defined(ENABLE_SVR_PASSWORD_AUTH) && defined(ENABLE_SVR_PAM_AUTH) +#error "You can't turn on PASSWORD and PAM auth both at once. Fix it in options.h" +#endif + /* We use dropbear_client and dropbear_server as shortcuts to avoid redundant * code, if we're just compiling as client or server */ #if defined(DROPBEAR_SERVER) && defined(DROPBEAR_CLIENT) diff --git a/svr-auth.c b/svr-auth.c index 1f80b31..7c4a08c 100644 --- a/svr-auth.c +++ b/svr-auth.c @@ -55,8 +55,7 @@ static void authclear() { #ifdef ENABLE_SVR_PUBKEY_AUTH ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; #endif -#if defined(DROPBEAR_PASSWORD_AUTH) || defined(DROPBEAR_PAM_AUTH) -#ifdef ENABLE_SVR_PASSWORD_AUTH +#if defined(ENABLE_SVR_PUBKEY_AUTH) || defined(ENABLE_SVR_PAM_AUTH) if (!svr_opts.noauthpass) { ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; } @@ -155,7 +154,7 @@ void recv_msg_userauth_request() { } #endif -#ifdef DROPBEAR_PAM_AUTH +#ifdef ENABLE_SVR_PAM_AUTH if (!svr_opts.noauthpass && !(svr_opts.norootpass && ses.authstate.pw->pw_uid == 0) ) { /* user wants to try password auth */ diff --git a/svr-authpam.c b/svr-authpam.c index cfd4327..e271020 100644 --- a/svr-authpam.c +++ b/svr-authpam.c @@ -36,180 +36,174 @@ #include #endif -#ifdef DROPBEAR_PAM_AUTH - struct UserDataS { - char* user; - char* passwd; + char* user; + char* passwd; }; -/* PAM conversation function */ +/* PAM conversation function - for now we only handle one message */ int pamConvFunc(int num_msg, - const struct pam_message **msg, - struct pam_response **respp, - void *appdata_ptr) { - int rc = PAM_SUCCESS; - struct pam_response* resp = NULL; - struct UserDataS* userDatap = (struct UserDataS*) appdata_ptr; - - /* tbd only handles one msg */ - - switch((*msg)->msg_style) { - case PAM_PROMPT_ECHO_OFF: - dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_PROMPT_ECHO_OFF: (*msg)->msg=\"%s\"", (*msg)->msg); - - if (strcmp((*msg)->msg, "Password:") == 0) { - resp = (struct pam_response*) malloc(sizeof(struct pam_response)); - resp->resp = (char*) strdup(userDatap->passwd); - /* dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_PROMPT_ECHO_ON: userDatap->passwd=\"%s\"", userDatap->passwd); */ - resp->resp_retcode = 0; - (*respp) = resp; - } - else { - dropbear_log(LOG_WARNING, "pamConvFunc(): PAM_PROMPT_ECHO_OFF: unrecognized prompt, (*msg)->msg=\"%s\"", (*msg)->msg); - rc = PAM_CONV_ERR; - } - break; - case PAM_PROMPT_ECHO_ON: - dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_PROMPT_ECHO_ON: (*msg)->msg=\"%s\"", (*msg)->msg); - - if ((strcmp((*msg)->msg, "login: " ) == 0) || (strcmp((*msg)->msg, "Please enter username: " ) == 0)) { - resp = (struct pam_response*) malloc(sizeof(struct pam_response)); - resp->resp = (char*) strdup(userDatap->user); - dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_PROMPT_ECHO_ON: userDatap->user=\"%s\"", userDatap->user); - resp->resp_retcode = 0; - (*respp) = resp; - } - else { - dropbear_log(LOG_WARNING, "pamConvFunc(): PAM_PROMPT_ECHO_ON: unrecognized prompt, (*msg)->msg=\"%s\"", - (*msg)->msg); - rc = PAM_CONV_ERR; - } - break; - case PAM_ERROR_MSG: - dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_ERROR_MSG: (*msg)->msg=\"%s\"", (*msg)->msg); - /* printf("error msg: '%s'\n", (*msg)->msg); */ - rc = PAM_CONV_ERR; - break; - case PAM_TEXT_INFO: - dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_TEXT_INFO: (*msg)->msg=\"%s\"", (*msg)->msg); - /* printf("text info: '%s'\n", (*msg)->msg); */ - rc = PAM_CONV_ERR; - break; - case PAM_RADIO_TYPE: - dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_RADIO_TYPE: (*msg)->msg=\"%s\"", (*msg)->msg); - /* printf("radio type: '%s'\n", (*msg)->msg); */ - rc = PAM_CONV_ERR; - break; - case PAM_BINARY_PROMPT: - dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_BINARY_PROMPT: (*msg)->msg=\"%s\"", (*msg)->msg); - /* printf("binary prompt: '%s'\n", (*msg)->msg); */ - rc = PAM_CONV_ERR; - break; - default: - dropbear_log(LOG_DEBUG, "pamConvFunc(): Unknown PAM message"); - /* printf("unknown message\n"); */ - rc = PAM_CONV_ERR; - break; - } - - return rc; + const struct pam_message **msg, + struct pam_response **respp, + void *appdata_ptr) { + + int rc = PAM_SUCCESS; + struct pam_response* resp = NULL; + struct UserDataS* userDatap = (struct UserDataS*) appdata_ptr; + const char* message = (*msg)->msg; + + TRACE(("enter pamConvFunc")); + TRACE(("msg_style is %d", (*msg)->msg_style)); + if (message) { + TRACE(("message is '%s'", message)); + } else { + TRACE(("null message")); + } + + switch((*msg)->msg_style) { + + case PAM_PROMPT_ECHO_OFF: + + if (strcmp(message, "Password:") != 0) { + TRACE(("PAM_PROMPT_ECHO_OFF: unrecognized prompt")); + rc = PAM_CONV_ERR; + break; + } + + /* XXX leak */ + resp = (struct pam_response*) m_malloc(sizeof(struct pam_response)); + /* XXX leak */ + resp->resp = (char*) m_strdup(userDatap->passwd); + resp->resp_retcode = 0; + (*respp) = resp; + break; + + + case PAM_PROMPT_ECHO_ON: + + if ((strcmp(message, "login: " ) != 0) + && (strcmp(message, "login:" ) != 0) + && (strcmp(message, "Please enter username: " ) != 0)) { + TRACE(("PAM_PROMPT_ECHO_ON: unrecognized prompt")); + rc = PAM_CONV_ERR; + break; + } + + /* XXX leak */ + resp = (struct pam_response*) m_malloc(sizeof(struct pam_response)); + /* XXX leak */ + resp->resp = (char*) m_strdup(userDatap->user); + TRACE(("userDatap->user='%s'", userDatap->user)); + + resp->resp_retcode = 0; + (*respp) = resp; + break; + + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + case PAM_RADIO_TYPE: + case PAM_BINARY_PROMPT: + TRACE(("Unhandled message type")); + rc = PAM_CONV_ERR; + break; + + default: + TRACE(("Unknown message type")); + rc = PAM_CONV_ERR; + break; + } + + TRACE(("leave pamConvFunc, rc %d", rc)); + + return rc; } /* Process a password auth request, sending success or failure messages as - * appropriate */ + * appropriate. To the client it looks like it's doing normal password auth (as opposed to keyboard-interactive or something), so the pam module has to be fairly standard (ie just "what's your username, what's your password, OK"). + * + * Keyboard interactive would be a lot nicer, but since PAM is synchronous, it + * gets very messy trying to send the interactive challenges, and read the + * interactive responses, over the network. */ void svr_auth_pam() { - // PAM stuff - int rc = PAM_SUCCESS; - struct UserDataS userData; - struct pam_conv pamConv = { - pamConvFunc, - &userData /* submitted to pamvConvFunc as appdata_ptr */ - }; - pam_handle_t* pamHandlep = NULL; - unsigned char * password = NULL; - unsigned int passwordlen; - - unsigned char changepw; - - /* check if client wants to change password */ - changepw = buf_getbyte(ses.payload); - if (changepw) { - /* not implemented by this server */ - send_msg_userauth_failure(0, 1); - return; - } - - password = buf_getstring(ses.payload, &passwordlen); - - /* clear the buffer containing the password */ - buf_incrpos(ses.payload, -passwordlen - 4); - m_burn(buf_getptr(ses.payload, passwordlen + 4), passwordlen + 4); - - /* used to pass data to the PAM conversation function */ - userData.user = ses.authstate.printableuser; - TRACE(("user is %s\n", userData.user)); - userData.passwd = password; - - /* Init pam */ - if ((rc = pam_start("sshd", NULL, &pamConv, &pamHandlep)) != PAM_SUCCESS) { - dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); - /* fprintf(stderr, "pam_start() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); */ - goto clean; - } - - /* - if ((rc = pam_set_item(pamHandlep, PAM_RHOST, webReqp->ipaddr) != PAM_SUCCESS)) { - dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); - return; - } - */ - - /* just to set it to something */ - if ((rc = pam_set_item(pamHandlep, PAM_TTY, "ssh") != PAM_SUCCESS)) { - dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); - goto clean; - } - - (void) pam_fail_delay(pamHandlep, 0 /* musec_delay */); - - /* (void) pam_set_item(pamHandlep, PAM_FAIL_DELAY, (void*) pamDelayFunc); */ - - if ((rc = pam_authenticate(pamHandlep, 0)) != PAM_SUCCESS) { - dropbear_log(LOG_WARNING, "pam_authenticate() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); - /* fprintf(stderr, "pam_authenticate() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); */ - dropbear_log(LOG_WARNING, - "bad pam password attempt for '%s'", - ses.authstate.printableuser); - send_msg_userauth_failure(0, 1); - goto clean; - } - - if ((rc = pam_acct_mgmt(pamHandlep, 0)) != PAM_SUCCESS) { - dropbear_log(LOG_WARNING, "pam_acct_mgmt() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); - /* fprintf(stderr, "pam_acct_mgmt() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); */ - dropbear_log(LOG_WARNING, - "bad pam password attempt for '%s'", - ses.authstate.printableuser); - send_msg_userauth_failure(0, 1); - goto clean; - } - - /* successful authentication */ - dropbear_log(LOG_NOTICE, - "password auth succeeded for '%s'", - ses.authstate.printableuser); - send_msg_userauth_success(); - - clean: - if (password != NULL) { - m_burn(password, passwordlen); - m_free(password); - } - if (pamHandlep != NULL) { - (void) pam_end(pamHandlep, 0 /* pam_status */); - } -} -#endif /* DROPBEAR_PAM_AUTH */ + struct UserDataS userData; + struct pam_conv pamConv = { + pamConvFunc, + &userData /* submitted to pamvConvFunc as appdata_ptr */ + }; + + pam_handle_t* pamHandlep = NULL; + + unsigned char * password = NULL; + unsigned int passwordlen; + + int rc = PAM_SUCCESS; + unsigned char changepw; + + /* check if client wants to change password */ + changepw = buf_getbyte(ses.payload); + if (changepw) { + /* not implemented by this server */ + send_msg_userauth_failure(0, 1); + goto cleanup; + } + + password = buf_getstring(ses.payload, &passwordlen); + + /* used to pass data to the PAM conversation function */ + userData.user = ses.authstate.printableuser; + userData.passwd = password; + + /* Init pam */ + if ((rc = pam_start("sshd", NULL, &pamConv, &pamHandlep)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s\n", + rc, pam_strerror(pamHandlep, rc)); + goto cleanup; + } + + /* just to set it to something */ + if ((rc = pam_set_item(pamHandlep, PAM_TTY, "ssh") != PAM_SUCCESS)) { + dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s\n", + rc, pam_strerror(pamHandlep, rc)); + goto cleanup; + } + + (void) pam_fail_delay(pamHandlep, 0 /* musec_delay */); + + /* (void) pam_set_item(pamHandlep, PAM_FAIL_DELAY, (void*) pamDelayFunc); */ + + if ((rc = pam_authenticate(pamHandlep, 0)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_authenticate() failed, rc=%d, %s\n", + rc, pam_strerror(pamHandlep, rc)); + dropbear_log(LOG_WARNING, + "bad pam password attempt for '%s'", + ses.authstate.printableuser); + send_msg_userauth_failure(0, 1); + goto cleanup; + } + + if ((rc = pam_acct_mgmt(pamHandlep, 0)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_acct_mgmt() failed, rc=%d, %s\n", + rc, pam_strerror(pamHandlep, rc)); + dropbear_log(LOG_WARNING, + "bad pam password attempt for '%s'", + ses.authstate.printableuser); + send_msg_userauth_failure(0, 1); + goto cleanup; + } + + /* successful authentication */ + dropbear_log(LOG_NOTICE, "pam password auth succeeded for '%s'", + ses.authstate.printableuser); + send_msg_userauth_success(); + +cleanup: + if (password != NULL) { + m_burn(password, passwordlen); + m_free(password); + } + if (pamHandlep != NULL) { + (void) pam_end(pamHandlep, 0 /* pam_status */); + } +} diff --git a/svr-authpasswd.c b/svr-authpasswd.c index 6f7c909..458deef 100644 --- a/svr-authpasswd.c +++ b/svr-authpasswd.c @@ -80,10 +80,6 @@ void svr_auth_password() { password = buf_getstring(ses.payload, &passwordlen); - /* clear the buffer containing the password */ - buf_incrpos(ses.payload, -passwordlen - 4); - m_burn(buf_getptr(ses.payload, passwordlen + 4), passwordlen + 4); - /* the first bytes of passwdcrypt are the salt */ testcrypt = crypt((char*)password, passwdcrypt); m_burn(password, passwordlen); -- cgit v1.2.3 From 028e79ddda14d34ea2b8c528407af86c86c82e86 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 21 Sep 2004 12:14:20 +0000 Subject: use inst_ rather than inst, so it doesn't try to install "all". --HG-- extra : convert_revision : 17b3eab398414e4bd5e77289bcc73f6185c4c43f --- Makefile.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 0d77571..9feee84 100644 --- a/Makefile.in +++ b/Makefile.in @@ -114,7 +114,7 @@ all: $(TARGETS) strip: $(TARGETS) $(STRIP) $(addsuffix $(EXEEXT), $(addprefix $(SPREFIX), $(TARGETS))) -install: $(addprefix inst, $(TARGETS)) +install: $(addprefix inst_, $(TARGETS)) installdropbearmulti: insdbmulti $(addprefix insmulti, $(PROGRAMS)) @@ -133,13 +133,13 @@ insmulti%: dropbearmulti -ln -s $(DESTDIR)$(bindir)/$(SPREFIX)dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT) # dropbear should go in sbin, so it needs a seperate rule -instdropbear: dropbear +inst_dropbear: dropbear $(INSTALL) -d -m 755 $(DESTDIR)$(sbindir) $(INSTALL) -m 755 $(SPREFIX)dropbear$(EXEEXT) $(DESTDIR)$(sbindir) -chown root $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT) -chgrp 0 $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT) -inst%: $* +inst_%: $* $(INSTALL) -d -m 755 $(DESTDIR)$(bindir) $(INSTALL) -m 755 $(SPREFIX)$*$(EXEEXT) $(DESTDIR)$(bindir) -chown root $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT) -- cgit v1.2.3 From 8f14a1cc3823b09897dccb0aeece8db09bfa8b73 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 17 Dec 2004 06:26:55 +0000 Subject: Pristine compilation works. --HG-- extra : convert_revision : 64faed12a3a33720986786db602714dfaa4bc599 --- Makefile.in | 5 ++++- configure.in | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 9feee84..4cad5bf 100644 --- a/Makefile.in +++ b/Makefile.in @@ -54,6 +54,9 @@ dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS) dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS) scpobjs=$(SCPOBJS) +VPATH=@srcdir@ +srcdir=@srcdir@ + prefix=@prefix@ exec_prefix=${prefix} bindir=${exec_prefix}/bin @@ -65,7 +68,7 @@ AR=@AR@ RANLIB=@RANLIB@ STRIP=@STRIP@ INSTALL=@INSTALL@ -CFLAGS=-Ilibtomcrypt @CFLAGS@ +CFLAGS=-I. -I$(srcdir)/libtomcrypt @CFLAGS@ LIBS=$(LTC) $(LTM) @LIBS@ LDFLAGS=@LDFLAGS@ diff --git a/configure.in b/configure.in index 05b1ba0..17b267a 100644 --- a/configure.in +++ b/configure.in @@ -610,5 +610,7 @@ fi AC_EXEEXT AC_CONFIG_HEADER(config.h) AC_OUTPUT(Makefile) +AC_OUTPUT(libtomcrypt/Makefile) +AC_OUTPUT(libtommath/Makefile) AC_MSG_RESULT() AC_MSG_RESULT(Now edit options.h to choose features.) -- cgit v1.2.3 From b5bd8591e7bc35980370ffa5dbe74d9b137e75c7 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 2 Jan 2005 17:08:27 +0000 Subject: 0.44 release changes --HG-- extra : convert_revision : 47d6b5589a4eaf707ed1c3685d9ef49306af18d8 --- CHANGES | 32 ++++++++++++++++++++++++++------ Makefile.in | 1 + README | 2 +- SMALL | 39 +++++++++++++++++++++++++-------------- TODO | 5 +++-- dbutil.c | 2 ++ debian/changelog | 6 ++++++ options.h | 4 ++-- 8 files changed, 66 insertions(+), 25 deletions(-) (limited to 'Makefile.in') diff --git a/CHANGES b/CHANGES index 18c71f9..f2689c1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,18 +1,38 @@ -0.44test5 - +0.44 - Mon Jan 3 2005 + +- SECURITY: Fix for PAM auth so that usernames are logged and conversation + function responses are allocated correctly - all 0.44test4 users with PAM + compiled in (not default) are advised to upgrade. + +- Fix calls to getnameinfo() for compatibility with Solaris + +- Pristine compilation works (run 'configure' from a fresh dir and make it + there) + +- Fixes for compiling with most options disabled. + +- Upgraded to LibTomCrypt 0.99 and LibTomMath 0.32 + +- Make sure that zeroing out of values in LTM and LTC won't get optimised away + +- Removed unused functions from loginrec.c + +- /dev/random is now the default entropy source rather than /dev/urandom + +- Logging of IPs in auth success/failure messages for improved greppability - Fix dbclient so that "scp -i keyfile" works. (It can handle "-ikeyfile properly) -- Fix for PAM auth so that usernames are logged and conversation function - responses are allocated correctly. - - Avoid a race in server shell-handling code which prevents the exit-code - from being returned to the client. + from being returned to the client in some circumstances. - Makefile modified so that install target works correctly (doesn't try to install "all" binary) - patch from Juergen Daubert -0.44test4 - Tue Sept 14 21:15:54 +0800 +- Various minor fixes and compile warnings. + +0.44test4 - Tue Sept 14 2004 21:15:54 +0800 - Fix inetd mode so it actually loads the hostkeys (oops) diff --git a/Makefile.in b/Makefile.in index 4cad5bf..dfb2004 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,4 +1,5 @@ # This Makefile is for Dropbear SSH Server and Client +# @configure_input@ # invocation: # make PROGRAMS="dropbear dbclient scp" MULTI=1 STATIC=1 SCPPROGRESS=1 diff --git a/README b/README index 52e3cf0..43dd1f2 100644 --- a/README +++ b/README @@ -69,6 +69,6 @@ pty, and you cannot login as any user other than that running the daemon The Dropbear distribution includes a standalone version of OpenSSH's scp program. You can compile it with "make scp", you may want to change the path -of the ssh binary, specified near the top of the scp.c file. By default +of the ssh binary, specified by _PATH_SSH_PROGRAM in options.h . By default the progress meter isn't compiled in to save space, you can enable it by adding 'SCPPROGRESS=1' to the make commandline. diff --git a/SMALL b/SMALL index a7442aa..babd671 100644 --- a/SMALL +++ b/SMALL @@ -1,25 +1,36 @@ Tips for a small system: -The following are set in options.h +If you only want server functionality (for example), compile with + make PROGRAMS=dropbear +rather than just + make dropbear +so that client functionality in shared portions of Dropbear won't be included. +The same applies if you are compiling just a client. -- You can safely disable blowfish and twofish ciphers, and MD5 hmac, without - affecting interoperability +--- -- If you're compiling statically, you can turn off host lookups +The following are set in options.h: -- You can disable either password or public-key authentication, though note - that the IETF draft states that pubkey authentication is required. + - You can safely disable blowfish and twofish ciphers, and MD5 hmac, without + affecting interoperability -- Similarly with DSS and RSA, you can disable one of these if you know that - all clients will be able to support a particular one. The IETF draft - states that DSS is required, however you may prefer to use RSA. - DON'T disable either of these on systems where you aren't 100% sure about - who will be connecting and what clients they will be using. + - If you're compiling statically, you can turn off host lookups -- Disabling the MOTD code and SFTP-SERVER may save a small amount of codesize + - You can disable either password or public-key authentication, though note + that the IETF draft states that pubkey authentication is required. -- You can disable x11, tcp and agent forwarding as desired. None of these are - essential, although agent-forwarding is often useful even on firewall boxes. + - Similarly with DSS and RSA, you can disable one of these if you know that + all clients will be able to support a particular one. The IETF draft + states that DSS is required, however you may prefer to use RSA. + DON'T disable either of these on systems where you aren't 100% sure about + who will be connecting and what clients they will be using. + + - Disabling the MOTD code and SFTP-SERVER may save a small amount of codesize + + - You can disable x11, tcp and agent forwarding as desired. None of these are + essential, although agent-forwarding is often useful even on firewall boxes. + +--- If you are compiling statically, you may want to disable zlib, as it will use a few tens of kB of binary-size (./configure --disable-zlib). diff --git a/TODO b/TODO index dac9a04..4b82efc 100644 --- a/TODO +++ b/TODO @@ -20,10 +20,11 @@ Things which might need doing: - CTR mode, SSH_MSG_IGNORE sending to improve CBC security - DH Group Exchange possibly, or just add group14 (whatever it's called today) -- Use m_burn for clearing sensitive items in LTM/LTC - - fix scp.c for IRIX - Be able to use OpenSSH keys for the client? or at least have some form of encrypted keys. + - Client agent forwarding + +- Handle restrictions in ~/.ssh/authorized_keys ? diff --git a/dbutil.c b/dbutil.c index ce43933..c77386f 100644 --- a/dbutil.c +++ b/dbutil.c @@ -603,6 +603,8 @@ void * m_realloc(void* ptr, size_t size) { /* Clear the data, based on the method in David Wheeler's * "Secure Programming for Linux and Unix HOWTO" */ +/* Beware of calling this from within dbutil.c - things might get + * optimised away */ void m_burn(void *data, unsigned int len) { volatile char *p = data; diff --git a/debian/changelog b/debian/changelog index 279290c..bfc0730 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +dropbear (0.44test4-1) unstable; urgency=high + + * New upstream release, various fixes. + + -- Matt Johnston Mon, 3 January 2005 00:44:54 +0800 + dropbear (0.44test4-1) unstable; urgency=medium * New upstream beta, various useful fixes. diff --git a/options.h b/options.h index 7a8f1fd..11e7db1 100644 --- a/options.h +++ b/options.h @@ -117,7 +117,7 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ * simple "Login: " "Password: " (or something like that - if your module is * similar but not quite like that, edit the strings in svr-authpam.c). * Basically, it's useful for systems like OS X where standard password crypts - * don't work, but there's and interface via a PAM module. You'll need to + * don't work, but there's an interface via a PAM module. You'll need to * configure with --enable-pam as well, since it's off by default. And you * should only enable either PASSWORD _or_ PAM auth, not both. */ @@ -185,7 +185,7 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ *******************************************************************/ #ifndef DROPBEAR_VERSION -#define DROPBEAR_VERSION "0.44test4" +#define DROPBEAR_VERSION "0.44" #endif #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION -- cgit v1.2.3 From 2d28663f53235d39a42e6a6b65d9e426d1d675b0 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 2 Mar 2005 04:13:01 +0000 Subject: * don't add a 'static' prefix to binary names --HG-- extra : convert_revision : 7d2393b48b6b8ed87d3bed5685cf598356eada8d --- Makefile.in | 47 +++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 26 deletions(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index dfb2004..1fa0f99 100644 --- a/Makefile.in +++ b/Makefile.in @@ -93,9 +93,6 @@ export RANLIB AR STRIP ifeq ($(STATIC), 1) LDFLAGS+=-static - SPREFIX=static -else - SPREFIX= endif ifeq ($(MULTI), 1) @@ -116,7 +113,7 @@ endif all: $(TARGETS) strip: $(TARGETS) - $(STRIP) $(addsuffix $(EXEEXT), $(addprefix $(SPREFIX), $(TARGETS))) + $(STRIP) $(addsuffix $(EXEEXT), $(TARGETS)) install: $(addprefix inst_, $(TARGETS)) @@ -124,30 +121,30 @@ installdropbearmulti: insdbmulti $(addprefix insmulti, $(PROGRAMS)) insdbmulti: dropbearmulti $(INSTALL) -d -m 755 $(DESTDIR)$(bindir) - $(INSTALL) -m 755 $(SPREFIX)dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir) - -chown root $(DESTDIR)$(bindir)/$(SPREFIX)dropbearmulti$(EXEEXT) - -chgrp 0 $(DESTDIR)$(bindir)/$(SPREFIX)dropbearmulti$(EXEEXT) + $(INSTALL) -m 755 dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir) + -chown root $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT) + -chgrp 0 $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT) insmultidropbear: dropbearmulti - -rm -f $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT) - -ln -s $(DESTDIR)$(bindir)/$(SPREFIX)dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT) + -rm -f $(DESTDIR)$(sbindir)/dropbear$(EXEEXT) + -ln -s $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT) insmulti%: dropbearmulti - -rm -f $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT) - -ln -s $(DESTDIR)$(bindir)/$(SPREFIX)dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT) + -rm -f $(DESTDIR)$(bindir)/$*$(EXEEXT) + -ln -s $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT) # dropbear should go in sbin, so it needs a seperate rule inst_dropbear: dropbear $(INSTALL) -d -m 755 $(DESTDIR)$(sbindir) - $(INSTALL) -m 755 $(SPREFIX)dropbear$(EXEEXT) $(DESTDIR)$(sbindir) - -chown root $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT) - -chgrp 0 $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT) + $(INSTALL) -m 755 dropbear$(EXEEXT) $(DESTDIR)$(sbindir) + -chown root $(DESTDIR)$(sbindir)/dropbear$(EXEEXT) + -chgrp 0 $(DESTDIR)$(sbindir)/dropbear$(EXEEXT) inst_%: $* $(INSTALL) -d -m 755 $(DESTDIR)$(bindir) - $(INSTALL) -m 755 $(SPREFIX)$*$(EXEEXT) $(DESTDIR)$(bindir) - -chown root $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT) - -chgrp 0 $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT) + $(INSTALL) -m 755 $*$(EXEEXT) $(DESTDIR)$(bindir) + -chown root $(DESTDIR)$(bindir)/$*$(EXEEXT) + -chgrp 0 $(DESTDIR)$(bindir)/$*$(EXEEXT) # for some reason the rule further down doesn't like $($@objs) as a prereq. @@ -158,11 +155,11 @@ dropbearconvert: $(dropbearconvertobjs) dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LTC) $(LTM) \ Makefile - $(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $($@objs) $(LIBS) + $(LD) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBS) # scp doesn't use the libs so is special. scp: $(SCPOBJS) $(HEADERS) Makefile - $(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $(SCPOBJS) + $(LD) $(LDFLAGS) -o $@$(EXEEXT) $(SCPOBJS) # multi-binary compilation. @@ -175,13 +172,13 @@ endif dropbearmulti: multilink multibinary: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) Makefile - $(LD) $(LDFLAGS) -o $(SPREFIX)dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS) + $(LD) $(LDFLAGS) -o dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS) multilink: multibinary $(addprefix link, $(PROGRAMS)) link%: - -rm -f $(SPREFIX)$*$(EXEEXT) - -ln -s $(SPREFIX)dropbearmulti$(EXEEXT) $(SPREFIX)$*$(EXEEXT) + -rm -f $*$(EXEEXT) + -ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT) $(LTC): options.h cd libtomcrypt && $(MAKE) clean && $(MAKE) @@ -201,10 +198,8 @@ sizes: dropbear clean: ltc-clean ltm-clean thisclean thisclean: - -rm -f dropbear dbclient dropbearkey dropbearconvert scp scp-progress - -rm -f staticdropbear staticdropbearkey staticdropbearconvert staticscp - -rm -f dropbearmulti staticdropbearmulti - -rm -f *.o *.da *.bb *.bbg *.prof + -rm -f dropbear dbclient dropbearkey dropbearconvert scp scp-progress \ + dropbearmulti *.o *.da *.bb *.bbg *.prof distclean: clean tidy -rm -f config.h -- cgit v1.2.3 From e48e25a548696fa89c984e788f61b1cdf91112f7 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 10 May 2005 17:01:16 +0000 Subject: * change include path for libtomcrypt 1.02 --HG-- extra : convert_revision : 77a587ebc40afe3a2ac02db1676dfc01044c618a --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 1fa0f99..fc820dd 100644 --- a/Makefile.in +++ b/Makefile.in @@ -69,7 +69,7 @@ AR=@AR@ RANLIB=@RANLIB@ STRIP=@STRIP@ INSTALL=@INSTALL@ -CFLAGS=-I. -I$(srcdir)/libtomcrypt @CFLAGS@ +CFLAGS=-I. -I$(srcdir)/libtomcrypt/src/headers/ @CFLAGS@ LIBS=$(LTC) $(LTM) @LIBS@ LDFLAGS=@LDFLAGS@ -- cgit v1.2.3 From 876b7081d8f073edd4717ccdb7091fe3a6975ef6 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 20 Sep 2005 17:35:21 +0000 Subject: added keyboard-interactive client support --HG-- extra : convert_revision : 3df738e42f4fc8b7f0f3ff9ca767386f54edb1ea --- Makefile.in | 2 +- auth.h | 18 ++++-- cli-auth.c | 78 +++++++++++++++++++++++-- cli-authinteract.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++++ cli-authpasswd.c | 4 +- cli-session.c | 7 +-- options.h | 5 ++ session.h | 7 +++ ssh.h | 11 ++++ 9 files changed, 282 insertions(+), 18 deletions(-) create mode 100644 cli-authinteract.c (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index fc820dd..fc17c1f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -29,7 +29,7 @@ SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ cli-session.o cli-service.o cli-runopts.o cli-chansession.o \ - cli-authpubkey.o cli-tcpfwd.o cli-channel.o + cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.o CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \ common-channel.o common-chansession.o termcodes.o loginrec.o \ diff --git a/auth.h b/auth.h index 6d6ebc7..7e83247 100644 --- a/auth.h +++ b/auth.h @@ -41,28 +41,36 @@ void svr_auth_pam(); /* Client functions */ void recv_msg_userauth_failure(); void recv_msg_userauth_success(); +void recv_msg_userauth_specific_60(); void recv_msg_userauth_pk_ok(); +void recv_msg_userauth_info_request(); void cli_get_user(); void cli_auth_getmethods(); void cli_auth_try(); void recv_msg_userauth_banner(); void cli_pubkeyfail(); -int cli_auth_password(); +void cli_auth_password(); int cli_auth_pubkey(); +void cli_auth_interactive(); #define MAX_USERNAME_LEN 25 /* arbitrary for the moment */ -#define AUTH_TYPE_PUBKEY 1 << 0 -#define AUTH_TYPE_PASSWORD 1 << 1 +#define AUTH_TYPE_NONE 1 +#define AUTH_TYPE_PUBKEY 1 << 1 +#define AUTH_TYPE_PASSWORD 1 << 2 +#define AUTH_TYPE_INTERACT 1 << 3 -/* auth types, "none" means we should return list of acceptable types */ -#define AUTH_METHOD_NONE "none" +#define AUTH_METHOD_NONE "none" #define AUTH_METHOD_NONE_LEN 4 #define AUTH_METHOD_PUBKEY "publickey" #define AUTH_METHOD_PUBKEY_LEN 9 #define AUTH_METHOD_PASSWORD "password" #define AUTH_METHOD_PASSWORD_LEN 8 +#define AUTH_METHOD_INTERACT "keyboard-interactive" +#define AUTH_METHOD_INTERACT_LEN 20 + + /* This structure is shared between server and client - it contains * relatively little extraneous bits when used for the client rather than the diff --git a/cli-auth.c b/cli-auth.c index fc51061..6a6d53a 100644 --- a/cli-auth.c +++ b/cli-auth.c @@ -32,7 +32,6 @@ #include "packet.h" #include "runopts.h" - void cli_authinitialise() { memset(&ses.authstate, 0, sizeof(ses.authstate)); @@ -99,6 +98,40 @@ out: TRACE(("leave recv_msg_userauth_banner")) } +/* This handles the message-specific types which + * all have a value of 60. These are + * SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, + * SSH_MSG_USERAUTH_PK_OK, & + * SSH_MSG_USERAUTH_INFO_REQUEST. */ +void recv_msg_userauth_specific_60() { + +#ifdef ENABLE_CLI_PUBKEY_AUTH + if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) { + recv_msg_userauth_pk_ok(); + return; + } +#endif + +#ifdef ENABLE_CLI_INTERACT_AUTH + if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT) { + recv_msg_userauth_info_request(); + return; + } +#endif + +#ifdef ENABLE_CLI_PASSWORD_AUTH + if (cli_ses.lastauthtype == AUTH_TYPE_PASSWORD) { + /* Eventually there could be proper password-changing + * support. However currently few servers seem to + * implement it, and password auth is last-resort + * regardless - keyboard-interactive is more likely + * to be used anyway. */ + dropbear_close("Your password has expired."); + } +#endif + + dropbear_exit("Unexpected userauth packet"); +} void recv_msg_userauth_failure() { @@ -113,8 +146,7 @@ void recv_msg_userauth_failure() { if (cli_ses.state != USERAUTH_REQ_SENT) { /* Perhaps we should be more fatal? */ - TRACE(("But we didn't send a userauth request!!!!!!")) - return; + dropbear_exit("Unexpected userauth failure"); } #ifdef ENABLE_CLI_PUBKEY_AUTH @@ -125,6 +157,19 @@ void recv_msg_userauth_failure() { } #endif +#ifdef ENABLE_CLI_INTERACT_AUTH + /* If we get a failure message for keyboard interactive without + * receiving any request info packet, then we don't bother trying + * keyboard interactive again */ + if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT + && !cli_ses.interact_request_received) { + TRACE(("setting auth_interact_failed = 1")) + cli_ses.auth_interact_failed = 1; + } +#endif + + cli_ses.lastauthtype = AUTH_TYPE_NONE; + methods = buf_getstring(ses.payload, &methlen); partial = buf_getbool(ses.payload); @@ -157,6 +202,12 @@ void recv_msg_userauth_failure() { ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; } #endif +#ifdef ENABLE_CLI_INTERACT_AUTH + if (strncmp(AUTH_METHOD_INTERACT, tok, + AUTH_METHOD_INTERACT_LEN) == 0) { + ses.authstate.authtypes |= AUTH_TYPE_INTERACT; + } +#endif #ifdef ENABLE_CLI_PASSWORD_AUTH if (strncmp(AUTH_METHOD_PASSWORD, tok, AUTH_METHOD_PASSWORD_LEN) == 0) { @@ -180,6 +231,7 @@ void recv_msg_userauth_success() { TRACE(("received msg_userauth_success")) ses.authstate.authdone = 1; cli_ses.state = USERAUTH_SUCCESS_RCVD; + cli_ses.lastauthtype = AUTH_TYPE_NONE; } void cli_auth_try() { @@ -189,7 +241,8 @@ void cli_auth_try() { CHECKCLEARTOWRITE(); - /* XXX We hardcode that we try a pubkey first */ + /* Order to try is pubkey, interactive, password. + * As soon as "finished" is set for one, we don't do any more. */ #ifdef ENABLE_CLI_PUBKEY_AUTH if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) { finished = cli_auth_pubkey(); @@ -197,13 +250,28 @@ void cli_auth_try() { } #endif +#ifdef ENABLE_CLI_INTERACT_AUTH + if (!finished && ses.authstate.authtypes & AUTH_TYPE_INTERACT) { + if (cli_ses.auth_interact_failed) { + finished = 0; + } else { + cli_auth_interactive(); + cli_ses.lastauthtype = AUTH_TYPE_INTERACT; + finished = 1; + } + } +#endif + #ifdef ENABLE_CLI_PASSWORD_AUTH if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) { - finished = cli_auth_password(); + cli_auth_password(); + finished = 1; cli_ses.lastauthtype = AUTH_TYPE_PASSWORD; } #endif + TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype)) + if (!finished) { dropbear_exit("No auth methods could be used."); } diff --git a/cli-authinteract.c b/cli-authinteract.c new file mode 100644 index 0000000..90105e9 --- /dev/null +++ b/cli-authinteract.c @@ -0,0 +1,168 @@ +/* + * Dropbear SSH + * + * Copyright (c) 2005 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" +#include "buffer.h" +#include "dbutil.h" +#include "session.h" +#include "ssh.h" +#include "runopts.h" + +#ifdef ENABLE_CLI_INTERACT_AUTH + +static unsigned char* get_response(unsigned char* prompt) +{ + FILE* tty = NULL; + unsigned char* response = NULL; + /* not a password, but a reasonable limit */ + char buf[DROPBEAR_MAX_CLI_PASS]; + char* ret = NULL; + + fprintf(stderr, "%s", prompt); + + tty = fopen(_PATH_TTY, "r"); + if (tty) { + ret = fgets(buf, sizeof(buf), tty); + fclose(tty); + } else { + ret = fgets(buf, sizeof(buf), stdin); + } + + if (ret == NULL) { + response = (unsigned char*)m_strdup(""); + } else { + unsigned int buflen = strlen(buf); + /* fgets includes newlines */ + if (buflen > 0 && buf[buflen-1] == '\n') + buf[buflen-1] = '\0'; + response = (unsigned char*)m_strdup(buf); + } + + m_burn(buf, sizeof(buf)); + + return response; +} + +void recv_msg_userauth_info_request() { + + unsigned char *name = NULL; + unsigned char *instruction = NULL; + unsigned int num_prompts = 0; + unsigned int i; + + unsigned char *prompt = NULL; + unsigned int echo = 0; + unsigned char *response = NULL; + + TRACE(("enter recv_msg_recv_userauth_info_request")) + + cli_ses.interact_request_received = 1; + + name = buf_getstring(ses.payload, NULL); + instruction = buf_getstring(ses.payload, NULL); + + /* language tag */ + buf_eatstring(ses.payload); + + num_prompts = buf_getint(ses.payload); + + if (num_prompts >= DROPBEAR_MAX_CLI_INTERACT_PROMPTS) { + dropbear_exit("Too many prompts received for keyboard-interactive"); + } + + /* we'll build the response as we go */ + CHECKCLEARTOWRITE(); + buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_INFO_RESPONSE); + buf_putint(ses.writepayload, num_prompts); + + if (strlen(name) > 0) { + cleantext(name); + fprintf(stderr, "%s", name); + m_free(name); + } + if (strlen(instruction) > 0) { + cleantext(instruction); + fprintf(stderr, "%s", instruction); + m_free(instruction); + } + + for (i = 0; i < num_prompts; i++) { + unsigned int response_len = 0; + prompt = buf_getstring(ses.payload, NULL); + cleantext(prompt); + + echo = buf_getbool(ses.payload); + + if (echo) { + unsigned char* p = getpass(prompt); + response = m_strdup(p); + m_burn(p, strlen(p)); + } else { + response = get_response(prompt); + } + + response_len = strlen(response); + buf_putstring(ses.writepayload, response, response_len); + m_burn(response, response_len); + m_free(response); + } + + encrypt_packet(); + + + TRACE(("leave recv_msg_recv_userauth_info_request")) +} + +void cli_auth_interactive() { + + TRACE(("enter cli_auth_interactive")) + CHECKCLEARTOWRITE(); + + buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST); + + /* username */ + buf_putstring(ses.writepayload, cli_opts.username, + strlen(cli_opts.username)); + + /* service name */ + buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION, + SSH_SERVICE_CONNECTION_LEN); + + /* method */ + buf_putstring(ses.writepayload, AUTH_METHOD_INTERACT, + AUTH_METHOD_INTERACT_LEN); + + /* empty language tag */ + buf_putstring(ses.writepayload, "", 0); + + /* empty submethods */ + buf_putstring(ses.writepayload, "", 0); + + encrypt_packet(); + cli_ses.interact_request_received = 0; + + TRACE(("leave cli_auth_interactive")) + +} +#endif /* ENABLE_CLI_INTERACT_AUTH */ diff --git a/cli-authpasswd.c b/cli-authpasswd.c index a9f34bd..ec290e0 100644 --- a/cli-authpasswd.c +++ b/cli-authpasswd.c @@ -113,7 +113,7 @@ static char *gui_getpass(const char *prompt) { } #endif /* ENABLE_CLI_ASKPASS_HELPER */ -int cli_auth_password() { +void cli_auth_password() { char* password = NULL; @@ -149,7 +149,5 @@ int cli_auth_password() { m_burn(password, strlen(password)); TRACE(("leave cli_auth_password")) - return 1; /* Password auth can always be tried */ - } #endif /* ENABLE_CLI_PASSWORD_AUTH */ diff --git a/cli-session.c b/cli-session.c index 8b58526..0e906e6 100644 --- a/cli-session.c +++ b/cli-session.c @@ -63,9 +63,7 @@ static const packettype cli_packettypes[] = { {SSH_MSG_CHANNEL_OPEN_CONFIRMATION, recv_msg_channel_open_confirmation}, {SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure}, {SSH_MSG_USERAUTH_BANNER, recv_msg_userauth_banner}, /* client */ -#ifdef ENABLE_CLI_PUBKEY_AUTH - {SSH_MSG_USERAUTH_PK_OK, recv_msg_userauth_pk_ok}, /* client */ -#endif + {SSH_MSG_USERAUTH_SPECIFIC_60, recv_msg_userauth_specific_60}, /* client */ {0, 0} /* End */ }; @@ -285,7 +283,8 @@ static void cli_remoteclosed() { } /* Operates in-place turning dirty (untrusted potentially containing control - * characters) text into clean text. */ + * characters) text into clean text. + * Note: this is safe only with ascii - other charsets could have problems. */ void cleantext(unsigned char* dirtytext) { unsigned int i, j; diff --git a/options.h b/options.h index 5ec19fc..6285756 100644 --- a/options.h +++ b/options.h @@ -133,6 +133,7 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ #define ENABLE_CLI_PASSWORD_AUTH #define ENABLE_CLI_PUBKEY_AUTH +#define ENABLE_CLI_INTERACT_AUTH /* Define this (as well as ENABLE_CLI_PASSWORD_AUTH) to allow the use of * a helper program for the ssh client. The helper program should be @@ -315,6 +316,10 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ #define DROPBEAR_MAX_CLI_PASS 1024 +#define DROPBEAR_MAX_CLI_INTERACT_PROMPTS 80 /* The number of prompts we'll + accept for keyb-interactive + auth */ + #if defined(DROPBEAR_AES256_CBC) || defined(DROPBEAR_AES128_CBC) #define DROPBEAR_AES_CBC #endif diff --git a/session.h b/session.h index 2dbc7f8..a4ad45f 100644 --- a/session.h +++ b/session.h @@ -226,6 +226,13 @@ struct clientsession { int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD, for the last type of auth we tried */ +#ifdef ENABLE_CLI_INTERACT_AUTH + int auth_interact_failed; /* flag whether interactive auth can still + be used */ + int interact_request_received; /* flag whether we've received an + info request from the server for + interactive auth.*/ +#endif struct SignKeyList *lastprivkey; int retval; /* What the command exit status was - we emulate it */ diff --git a/ssh.h b/ssh.h index e976c57..26b51bf 100644 --- a/ssh.h +++ b/ssh.h @@ -42,8 +42,19 @@ #define SSH_MSG_USERAUTH_FAILURE 51 #define SSH_MSG_USERAUTH_SUCCESS 52 #define SSH_MSG_USERAUTH_BANNER 53 + +/* packets 60-79 are method-specific, aren't one-one mapping */ +#define SSH_MSG_USERAUTH_SPECIFIC_60 60 + +#define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60 + #define SSH_MSG_USERAUTH_PK_OK 60 +/* keyboard interactive auth */ +#define SSH_MSG_USERAUTH_INFO_REQUEST 60 +#define SSH_MSG_USERAUTH_INFO_RESPONSE 61 + + /* If adding numbers here, check MAX_UNAUTH_PACKET_TYPE in process-packet.c * is still valid */ -- cgit v1.2.3 From b6b96f884110f96a31e35139196749ed7f91462c Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 18 Apr 2006 01:33:30 +0000 Subject: Include CPPFLAGS in CFLAGS --HG-- extra : convert_revision : 138a11bc1e2babcd8b1182e6cb2a85d4e9404b11 --- Makefile.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index fc17c1f..1ce13d2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -69,7 +69,8 @@ AR=@AR@ RANLIB=@RANLIB@ STRIP=@STRIP@ INSTALL=@INSTALL@ -CFLAGS=-I. -I$(srcdir)/libtomcrypt/src/headers/ @CFLAGS@ +CPPFLAGS=@CPPFLAGS@ +CFLAGS=-I. -I$(srcdir)/libtomcrypt/src/headers/ $(CPPFLAGS) @CFLAGS@ LIBS=$(LTC) $(LTM) @LIBS@ LDFLAGS=@LDFLAGS@ -- cgit v1.2.3 From 35bcc463e5ffe2f630c71962ca12d69a84952568 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 11 Oct 2006 16:00:50 +0000 Subject: Fix up separate-directory building for libtomcrypt Use $CC rather than $LD for linking --HG-- extra : convert_revision : 31dcd7a22983ef19d6c63248e415e71d292dd0ec --- Makefile.in | 11 ++++++----- configure.in | 43 +++++++++++++++++++++++++++++++++++++++++++ libtomcrypt/Makefile.in | 2 +- options.h | 4 ++-- 4 files changed, 52 insertions(+), 8 deletions(-) (limited to 'Makefile.in') diff --git a/Makefile.in b/Makefile.in index 1ce13d2..f5b111f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -64,13 +64,12 @@ bindir=${exec_prefix}/bin sbindir=${exec_prefix}/sbin CC=@CC@ -LD=@LD@ AR=@AR@ RANLIB=@RANLIB@ STRIP=@STRIP@ INSTALL=@INSTALL@ CPPFLAGS=@CPPFLAGS@ -CFLAGS=-I. -I$(srcdir)/libtomcrypt/src/headers/ $(CPPFLAGS) @CFLAGS@ +CFLAGS=-I. -I$(srcdir) -I$(srcdir)/libtomcrypt/src/headers/ $(CPPFLAGS) @CFLAGS@ LIBS=$(LTC) $(LTM) @LIBS@ LDFLAGS=@LDFLAGS@ @@ -156,11 +155,11 @@ dropbearconvert: $(dropbearconvertobjs) dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LTC) $(LTM) \ Makefile - $(LD) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBS) + $(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBS) # scp doesn't use the libs so is special. scp: $(SCPOBJS) $(HEADERS) Makefile - $(LD) $(LDFLAGS) -o $@$(EXEEXT) $(SCPOBJS) + $(CC) $(LDFLAGS) -o $@$(EXEEXT) $(SCPOBJS) # multi-binary compilation. @@ -173,7 +172,7 @@ endif dropbearmulti: multilink multibinary: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) Makefile - $(LD) $(LDFLAGS) -o dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS) + $(CC) $(LDFLAGS) -o dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS) multilink: multibinary $(addprefix link, $(PROGRAMS)) @@ -187,6 +186,8 @@ $(LTC): options.h $(LTM): options.h cd libtommath && $(MAKE) +.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean + ltc-clean: cd libtomcrypt && $(MAKE) clean diff --git a/configure.in b/configure.in index df7adf2..798becc 100644 --- a/configure.in +++ b/configure.in @@ -617,6 +617,49 @@ if test -z "$no_ptc_check" ; then fi AC_EXEEXT + +# XXX there must be a nicer way to do this +AS_MKDIR_P(libtomcrypt/src/ciphers/aes) +AS_MKDIR_P(libtomcrypt/src/ciphers/safer) +AS_MKDIR_P(libtomcrypt/src/ciphers/twofish) +AS_MKDIR_P(libtomcrypt/src/encauth/ccm) +AS_MKDIR_P(libtomcrypt/src/encauth/eax) +AS_MKDIR_P(libtomcrypt/src/encauth/gcm) +AS_MKDIR_P(libtomcrypt/src/encauth/ocb) +AS_MKDIR_P(libtomcrypt/src/hashes) +AS_MKDIR_P(libtomcrypt/src/hashes/chc) +AS_MKDIR_P(libtomcrypt/src/hashes/helper) +AS_MKDIR_P(libtomcrypt/src/hashes/sha2) +AS_MKDIR_P(libtomcrypt/src/hashes/whirl) +AS_MKDIR_P(libtomcrypt/src/mac/hmac) +AS_MKDIR_P(libtomcrypt/src/mac/omac) +AS_MKDIR_P(libtomcrypt/src/mac/pelican) +AS_MKDIR_P(libtomcrypt/src/mac/pmac) +AS_MKDIR_P(libtomcrypt/src/misc/base64) +AS_MKDIR_P(libtomcrypt/src/misc/crypt) +AS_MKDIR_P(libtomcrypt/src/misc/mpi) +AS_MKDIR_P(libtomcrypt/src/misc/pkcs5) +AS_MKDIR_P(libtomcrypt/src/modes/cbc) +AS_MKDIR_P(libtomcrypt/src/modes/cfb) +AS_MKDIR_P(libtomcrypt/src/modes/ctr) +AS_MKDIR_P(libtomcrypt/src/modes/ecb) +AS_MKDIR_P(libtomcrypt/src/modes/ofb) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/bit) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/choice) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/ia5) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/integer) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/object_identifier) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/octet) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/printable_string) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/sequence) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/short_integer) +AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/utctime) +AS_MKDIR_P(libtomcrypt/src/pk/dh) +AS_MKDIR_P(libtomcrypt/src/pk/dsa) +AS_MKDIR_P(libtomcrypt/src/pk/ecc) +AS_MKDIR_P(libtomcrypt/src/pk/pkcs1) +AS_MKDIR_P(libtomcrypt/src/pk/rsa) +AS_MKDIR_P(libtomcrypt/src/prng) AC_CONFIG_HEADER(config.h) AC_OUTPUT(Makefile) AC_OUTPUT(libtomcrypt/Makefile) diff --git a/libtomcrypt/Makefile.in b/libtomcrypt/Makefile.in index e1bee57..f1cfdad 100644 --- a/libtomcrypt/Makefile.in +++ b/libtomcrypt/Makefile.in @@ -158,7 +158,7 @@ default:library #ciphers come in two flavours... enc+dec and enc src/ciphers/aes/aes_enc.o: src/ciphers/aes/aes.c src/ciphers/aes/aes_tab.c - $(CC) $(CFLAGS) -DENCRYPT_ONLY -c src/ciphers/aes/aes.c -o src/ciphers/aes/aes_enc.o + $(CC) $(CFLAGS) -DENCRYPT_ONLY -c $< -o src/ciphers/aes/aes_enc.o #These are the rules to make certain object files. src/ciphers/aes/aes.o: src/ciphers/aes/aes.c src/ciphers/aes/aes_tab.c diff --git a/options.h b/options.h index 886876f..ad82f8b 100644 --- a/options.h +++ b/options.h @@ -127,8 +127,8 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ * but there's an interface via a PAM module - don't bother using it otherwise. * You can't enable both PASSWORD and PAM. */ -/*#define ENABLE_SVR_PASSWORD_AUTH*/ -#define ENABLE_SVR_PAM_AUTH +#define ENABLE_SVR_PASSWORD_AUTH +/*#define ENABLE_SVR_PAM_AUTH */ #define ENABLE_SVR_PUBKEY_AUTH #define ENABLE_CLI_PASSWORD_AUTH -- cgit v1.2.3