propagate of 717950f4061f1123659ee87c7c168805af920ab7 and 839f98f136788cc1466e4641bf796f96040a085d from branch 'matt.dbclient.authpam' to 'matt.dbclient.rez'

--HG--
branch : private-rez
extra : convert_revision : d58a4ff37f9784978a07df6a944f7dbae8196f6d
This commit is contained in:
Matt Johnston
2004-09-12 04:56:50 +00:00
94 changed files with 3793 additions and 1603 deletions

130
CHANGES
View File

@@ -1,3 +1,133 @@
0.44test3 - Fri Aug 27 22:20:54 +0800
- Fixed a bunch of warnings.
- scp works correctly when passed a username (fix for the dbclient program
itself as well, "-lmatt" works as well as "-l matt").
- Remove unrequired debian files
- Exit with the remote process's return code for dbclient
- Display stderr messages from the server in the client
- Add circular buffering to the channel code. This should dramatically reduce
the amount of backtraffic sent in response to traffic incoming to the
Dropbear end - improves high-latency performance (ie dialup).
- Various other related channel-handling fixups.
- Allow leading lines in the banner when connecting to servers
- Fixed printing out errors onto the network socket with stderr (for inetd
mode when using xinetd)
- Remove obselete documentation
- Fix a null-pointer exception when trying to free non-existant listeners
at cleanup.
- DEBUG_TRACE now only works if you add "-v" to the program commandline
- Don't leave stdin non-blocking on exit - this caused the parent shell
of dbclient to close when dbclient exited, for some shells in BusyBox
- Server connections no longer timeout after 5 minutes
- Fixed stupid DSS hostkey typo (server couldn't load host keys)
0.44test2 - Tues Aug 17 2004 17:43:54 +0800
- Fix up dropbearmulti targets in the Makefile - symlinks are now created
- Compile fake-rfc2553 even with dropbearconvert/dropbearkey - this
allows them to work on platforms without a native getaddrinfo()
- Create ~/.ssh/known_hosts properly if it doesn't exist
- Fix basename() function prototype
- Backport some local changes (more #ifdefs for termcodes.c, a fix for missing
defines on AIX).
- Let dbclient be run as "ssh"
- Initialise mp_ints by default
0.44test1 - Sun Aug 16 2005 17:43:54 +0800
- TESTING RELEASE - this is the first public release of the client codebase,
so there are sure to be bugs to be found. In addition, if you're just using
the server portion, the final binary size probably will increase - I'll
be trying to get it back down in future releases.
- Dropbear client added - lots of changes to the server code as well to
generalise things
- IPv6 support added for client, server, and forwarding
- New makefile with more generic support for multiple-program binaries
0.43 - Fri Jul 16 2004 17:44:54 +0800
- SECURITY: Don't try to free() uninitialised variables in DSS verification
code. Thanks to Arne Bernin for pointing out this bug. This is possibly
exploitable, all users with DSS and pubkey-auth compiled in are advised to
upgrade.
- Clean up agent forwarding socket files correctly, patch from Gerrit Pape.
- Don't go into an infinite loop when portforwarding to servers which don't
send any initial data/banner. Patch from Nikola Vladov
- Fix for network vs. host byte order in logging remote TCP ports, also
from Gerrit Pape.
- Initialise many pointers to NULL, for general safety. Also checked cleanup
code for mp_ints (related to security issues above).
0.42 - Wed Jun 16 2004 12:44:54 +0800
- Updated to Gerrit Pape's official Debian subdirectory
- Fixed bad check when opening /dev/urandom - thanks to Danny Sung.
- Added -i inetd mode flag, and associated options in options.h . Dropbear
can be compiled with either normal mode, inetd, or both modes. Thanks
to Gerrit Pape for basic patch and motivation.
- Use <dirent.h> rather than <sys/dir.h> for POSIX compliance. Thanks to Bill
Sommerfield.
- Fixed a TCP forwarding (client-local, -L style) bug which caused the whole
session to close if the TCP connection failed. Thanks to Andrew Braund for
reporting it and helping track it down.
- Re-enable sigpipe for child processes. Thanks to Gerrit Pape for some
suggestions, and BSD manpages for a clearer explanation of the behaviour.
- Added manpages, thanks to Gerrit Pape.
- Changed license text for LibTomCrypt and LibTomMath.
- Added strip-static target
- Fixed a bug in agent-forwarding cleanup handler - would segfault
(dereferencing a null pointer) if agent forwarding had failed.
- Fix behaviour of authorized_keys parsing, so larger (>1024 bit) DSA keys will
work. Thanks to Dr. Markus Waldeck for the report.
- Fixed local port forwarding code so that the "-j" option will make forwarding
attempts fail more gracefully.
- Allow repeated requests in a single session if previous ones fail - this fixes PuTTY and some other SCP clients, which try SFTP, then fall-back to SCP if it
isn't available. Thanks to Stirling Westrup for the report.
- Updated to LibTomCrypt 0.96 and LibTomMath 0.30. The AES code now uses
smaller non-precomputed tables if DROPBEAR_SMALL_CODE is defined in
options.h, leading to a significant reduction in the binary size.
0.41 - Mon Jan 19 2004 22:40:19 +0800
- Fix in configure so that cross-compiling works, thanks to numerous people for

80
INSTALL
View File

@@ -1,45 +1,30 @@
Basic Dropbear build instructions:
- First, edit options.h to choose user-defined features to choose, such as
which ciphers/hashes you want, which forwarding you want, etc.
- Edit options.h to set which features you want.
- Edit debug.h if you want any debug options (not usually required).
- Edit debug.h if you want any debug options
- Now configure Dropbear's host-specific options
(if you are using a cvs copy, "autoconf; autoheader" first)
(If using a non-tarball copy, "autoconf; autoheader")
./configure (optionally with --disable-zlib or --disable-syslog,
or --help for other options)
- Then compile and optionally install Dropbear:
Now compile:
(the Makefile requires GNU make, if you want to make it portable, send me
some patches)
make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp"
make
make install (installs to /usr/local/sbin, /usr/local/bin by default)
And install (/usr/local/bin is usual default):
You need to generate server keys, this is one-off:
./dropbearkey -t rsa -f dropbear_rsa_host_key
./dropbearkey -t dss -f dropbear_dss_host_key
make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" install
or alternatively convert OpenSSH keys to Dropbear:
./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key
(you can leave items out of the PROGRAMS list to avoid compiling them. If you
recompile after changing the PROGRAMS list, you *MUST* "make clean" before
recompiling - bad things will happen otherwise)
And you can now run the server.
./dropbear
See MULTI for instructions on making all-in-one binaries.
or './dropbear -h' to get options.
If you want to compile statically, add "STATIC=1" to the make command-line.
If the server is run as non-root, you most likely won't be able to allocate a
pty, and you cannot login as any user other than that running the daemon
(obviously). Shadow passwords will also be unusable as non-root.
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
the progress meter isn't compiled in to save space, you can enable it with
"make scp-progress".
Binaries can be strippd with "make strip"
============================================================================
@@ -50,18 +35,11 @@ versions is broken. Also note that you may get strange issues if your uClibc
headers don't match the library you are running with, ie the headers might
say that shadow password support exists, but the libraries don't have it.
To compile for uClibc the following should work:
rm config.cache
CC=i386-uclib-gcc ./configure --disable-zlib
make clean
make
make strip
... and that should be it. You can use "make static" to make statically linked
binaries, and it is advisable to strip the binaries too. If you're looking
to make a small binary, you should remove unneeded ciphers and MD5, by
editing options.h
Compiling for uClibc should be the same as normal, just set CC to the magic
uClibc toolchain compiler (ie export CC=i386-uclibc-gcc or whatever).
You can use "make STATIC=1" to make statically linked binaries, and it is
advisable to strip the binaries too. If you're looking to make a small binary,
you should remove unneeded ciphers and MD5, by editing options.h
It is possible to compile zlib in, by copying zlib.h and zconf.h into a
subdirectory (ie zlibincludes), and
@@ -78,7 +56,11 @@ globally in ~/.ssh/config, not just in the host entry in that file.
You may want to manually disable lastlog recording when using uClibc, configure
with --disable-lastlog.
One common problem is pty allocation. There are a number of types of pty allocation which can be used -- if they work properly, the end result is the same for each type. Running configure should detect the best type to use automatically, however for some embedded systems, this may be incorrect. Some things to note:
One common problem is pty allocation. There are a number of types of pty
allocation which can be used -- if they work properly, the end result is the
same for each type. Running configure should detect the best type to use
automatically, however for some systems, this may be incorrect. Some
things to note:
If your system expects /dev/pts to be mounted (this is a uClibc option),
make sure that it is.
@@ -90,19 +72,3 @@ One common problem is pty allocation. There are a number of types of pty allocat
to create all the /dev/pty?? and /dev/tty?? devices, which can be
problematic for devfs. In general, openpty() is the best way to allocate
PTYs, so it's best to try and get it working.
============================================================================
Public key auth:
You can use ~/.ssh/authorized_keys in the same way as with OpenSSH, just put
the key entries in that file. They should be of the form:
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAwVa6M6cGVmUcLl2cFzkxEoJd06Ub4bVDsYrWvXhvUV+ZAM9uGuewZBDoAqNKJxoIn0Hyd0Nk/yU99UVv6NWV/5YSHtnf35LKds56j7cuzoQpFIdjNwdxAN0PCET/MG8qyskG/2IE2DPNIaJ3Wy+Ws4IZEgdJgPlTYUBWWtCWOGc= someone@hostname
You must make sure that ~/.ssh, and the key file, are only writable by the
user.
NOTE: Dropbear ignores authorized_keys options such as those described in the
OpenSSH sshd manpage, and will not allow a login for these keys.

17
LICENSE
View File

@@ -1,6 +1,15 @@
The majority of code is written by Matt Johnston, under the following license:
Dropbear contains a number of components from different sources, hence there
are a few licenses and authors involved. All licenses are fairly
non-restrictive.
Copyright (c) 2002,2003 Matt Johnston
The majority of code is written by Matt Johnston, under the license below.
Portions of the client-mode work are (c) 2004 Mihnea Stoenescu, under the
same license:
Copyright (c) 2002-2004 Matt Johnston
Portions copyright (c) 2004 Mihnea Stoenescu
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -23,9 +32,7 @@ SOFTWARE.
=====
LibTomCrypt and LibTomMath are (c) Tom St Denis, under TDCAL (Tom Doesn't Care
About Licenses) some files are from public domain sources, see
libtomcrypt/legal.txt
LibTomCrypt and LibTomMath are written by Tom St Denis, and are Public Domain.
=====

19
MULTI
View File

@@ -3,29 +3,24 @@ Multi-binary compilation
To compile for systems without much space (floppy distributions etc), you
can create a single binary. This will save disk space by avoiding repeated
code between the three components (dropbear, dropbearkey, dropbearconvert).
code between the various parts.
If you are familiar with "busybox", it's the same principle.
To use the multi-purpose binary, firstly enable the "#define DROPBEAR_MULTI"
line in options.h
To compile the multi-binary, first "make clean" (if you've compiled
previously), then
Then enable which of the binaries you want to compile, also in options.h
(by default these are all enabled).
You should then "make clean" (if you compiled previously), then
"make dropbearmulti"
("make dropbearmultistatic" will make a static binary).
make PROGRAMS="programs you want here" MULTI=1
To use the binary, symlink it from the desired executable:
ln -s dropbearmulti dropbear
ln -s dropbearmulti dbclient
etc
then execute as normal:
./dropbear <options here>
"make install" doesn't currently work for multi-binary configuration, however
"make install" doesn't currently work for multi-binary configuration, though
in most situations where it is being used, the target and build systems will
differ.

View File

@@ -3,14 +3,13 @@
# 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 dropbearkey
PROGRAMS=dropbear dbclient dropbearkey dropbearconvert
endif
LTC=libtomcrypt/libtomcrypt.a
@@ -20,21 +19,22 @@ 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 \
svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\
svr-authpam.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 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 \
tcpfwd-direct.o tcpfwd-remote.o listener.o process-packet.o \
common-runopts.o
tcp-accept.o listener.o process-packet.o \
common-runopts.o circbuffer.o
KEYOBJS=dropbearkey.o gendss.o genrsa.o
@@ -43,11 +43,11 @@ 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 \
loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd-direct.h compat.h \
tcpfwd-remote.h listener.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
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
@@ -115,25 +115,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)$(sbindir)/$(SPREFIX)$*$(EXEEXT)
-chgrp 0 $(DESTDIR)$(sbindir)/$(SPREFIX)$*$(EXEEXT)
ifeq ($(MULTI), 1)
@echo
@echo "You must manually create links for $*"
endif
-chown root $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT)
-chgrp 0 $(DESTDIR)$(bindir)/$(SPREFIX)$*$(EXEEXT)
# for some reason the rule further down doesn't like $($@objs) as a prereq.
@@ -158,11 +169,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)
@@ -179,7 +195,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

62
README
View File

@@ -1,4 +1,4 @@
This is Dropbear, a smallish SSH 2 server.
This is Dropbear, a smallish SSH 2 server and client.
INSTALL has compilation instructions.
@@ -12,3 +12,63 @@ me if you have any questions/bugs found/features/ideas/comments etc :)
Matt Johnston
matt@ucc.asn.au
In the absence of detailed documentation, some notes follow:
============================================================================
Server public key auth:
You can use ~/.ssh/authorized_keys in the same way as with OpenSSH, just put
the key entries in that file. They should be of the form:
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAwVa6M6cGVmUcLl2cFzkxEoJd06Ub4bVDsYrWvXhvUV+ZAM9uGuewZBDoAqNKJxoIn0Hyd0Nk/yU99UVv6NWV/5YSHtnf35LKds56j7cuzoQpFIdjNwdxAN0PCET/MG8qyskG/2IE2DPNIaJ3Wy+Ws4IZEgdJgPlTYUBWWtCWOGc= someone@hostname
You must make sure that ~/.ssh, and the key file, are only writable by the
user.
NOTE: Dropbear ignores authorized_keys options such as those described in the
OpenSSH sshd manpage, and will not allow a login for these keys.
============================================================================
Client public key auth:
Dropbear can do public key auth as a client, but you will have to convert
OpenSSH style keys to Dropbear format, or use dropbearkey to create them.
If you have an OpenSSH-style private key ~/.ssh/id_rsa, you need to do:
dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_rsa.db
dbclient -i ~/.ssh/id_rsa.db <hostname>
Currently encrypted keys aren't supported, neither is agent forwarding. At some
stage both hopefully will be.
============================================================================
If you want to get the public-key portion of a Dropbear private key, look at
dropbearkey's '-y' option.
============================================================================
To run the server, you need to generate server keys, this is one-off:
./dropbearkey -t rsa -f dropbear_rsa_host_key
./dropbearkey -t dss -f dropbear_dss_host_key
or alternatively convert OpenSSH keys to Dropbear:
./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key
============================================================================
If the server is run as non-root, you most likely won't be able to allocate a
pty, and you cannot login as any user other than that running the daemon
(obviously). Shadow passwords will also be unusable as non-root.
============================================================================
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
the progress meter isn't compiled in to save space, you can enable it by
adding 'SCPPROGRESS=1' to the make commandline.

22
TODO
View File

@@ -1,29 +1,29 @@
Current:
Things which need doing:
Things which might need doing:
- Make options.h generated from configure perhaps?
- investigate self-pipe?
- Improved queueing of unauthed connections
- fix agent fwd problems
- improve channel window adjustment algorithm (circular buffering)
- Don't use pregenerated AES tables
- handle /etc/environment in AIX
- check PRNG
- check that there aren't timing issues with valid/invalid user authentication
feedback.
- IP6 (binding to :: takes over ipv4 as well, sigh. If anyone wants to suggest
a clean way (ie no V4MAPPED or setsockopt things) please let me know :)
- Binding to different interfaces (see ipv6 probably)
- Binding to different interfaces
- PAM ??
- inetd
- possible RSA blinding? need to check whether this is vuln to timing attacks
- check PRNG
- CTR mode, SSH_MSG_IGNORE sending to improve CBC security
- DH Group Exchange possibly
- 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

View File

@@ -1,5 +1,5 @@
/*
* Dropbear - a SSH2 server
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
@@ -34,8 +34,8 @@
#define BUF_MAX_INCR 1000000000
#define BUF_MAX_SIZE 1000000000
/* avoid excessively large numbers, > 5000 bit */
#define BUF_MAX_MPINT (5000 / 8)
/* avoid excessively large numbers, > ~8192 bits */
#define BUF_MAX_MPINT (8240 / 8)
/* Create (malloc) a new buffer of size */
buffer* buf_new(unsigned int size) {
@@ -76,7 +76,8 @@ void buf_burn(buffer* buf) {
}
/* resize a buffer, pos and len will be repositioned if required */
/* resize a buffer, pos and len will be repositioned if required when
* downsizing */
void buf_resize(buffer *buf, unsigned int newsize) {
if (newsize > BUF_MAX_SIZE) {
@@ -151,6 +152,8 @@ void buf_incrpos(buffer* buf, int incr) {
/* Get a byte from the buffer and increment the pos */
unsigned char buf_getbyte(buffer* buf) {
/* This check is really just ==, but the >= allows us to check for the
* assert()able case of pos > len, which should _never_ happen. */
if (buf->pos >= buf->len) {
dropbear_exit("bad buf_getbyte");
}

View File

@@ -27,6 +27,7 @@
#include "includes.h"
#include "buffer.h"
#include "circbuffer.h"
/* channel->type values */
#define CHANNEL_ID_NONE 0
@@ -41,14 +42,18 @@
#define SSH_OPEN_UNKNOWN_CHANNEL_TYPE 3
#define SSH_OPEN_RESOURCE_SHORTAGE 4
#define MAX_CHANNELS 60 /* simple mem restriction, includes each tcp/x11
/* Not a real type */
#define SSH_OPEN_IN_PROGRESS 99
#define MAX_CHANNELS 100 /* simple mem restriction, includes each tcp/x11
connection, so can't be _too_ small */
#define CHAN_EXTEND_SIZE 3 /* how many extra slots to add when we need more */
#define RECV_MAXWINDOW 6000 /* tweak */
#define RECV_MAXPACKET 1400 /* tweak */
#define RECV_MINWINDOW 19000 /* when we get below this, we send a windowadjust */
#define RECV_MAXWINDOW 4000 /* tweak */
#define RECV_WINDOWEXTEND 500 /* We send a "window extend" every
RECV_WINDOWEXTEND bytes */
#define RECV_MAXPACKET RECV_MAXWINDOW /* tweak */
struct ChanType;
@@ -57,15 +62,16 @@ struct Channel {
unsigned int index; /* the local channel index */
unsigned int remotechan;
unsigned int recvwindow, transwindow;
unsigned int recvdonelen;
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;
@@ -94,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);
@@ -103,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();

View File

@@ -68,11 +68,6 @@ struct ChildPid {
};
void chansessionrequest(struct Channel * channel);
void send_msg_chansess_exitstatus(struct Channel * channel,
struct ChanSess * chansess);
void send_msg_chansess_exitsignal(struct Channel * channel,
struct ChanSess * chansess);
void addnewvar(const char* param, const char* var);
void cli_send_chansess_request();

138
circbuffer.c Normal file
View File

@@ -0,0 +1,138 @@
/*
* 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 "dbutil.h"
#include "circbuffer.h"
#define MAX_CBUF_SIZE 100000000
circbuffer * cbuf_new(unsigned int size) {
circbuffer *cbuf = NULL;
if (size > MAX_CBUF_SIZE) {
dropbear_exit("bad cbuf size");
}
cbuf = (circbuffer*)m_malloc(sizeof(circbuffer));
cbuf->data = (unsigned char*)m_malloc(size);
cbuf->used = 0;
cbuf->readpos = 0;
cbuf->writepos = 0;
cbuf->size = size;
return cbuf;
}
void cbuf_free(circbuffer * cbuf) {
m_free(cbuf->data);
m_free(cbuf);
}
unsigned int cbuf_getused(circbuffer * cbuf) {
return cbuf->used;
}
unsigned int cbuf_getavail(circbuffer * cbuf) {
return cbuf->size - cbuf->used;
}
unsigned int cbuf_readlen(circbuffer *cbuf) {
assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
if (cbuf->used == 0) {
TRACE(("cbuf_readlen: unused buffer"));
return 0;
}
if (cbuf->readpos < cbuf->writepos) {
return cbuf->writepos - cbuf->readpos;
}
return cbuf->size - cbuf->readpos;
}
unsigned int cbuf_writelen(circbuffer *cbuf) {
assert(cbuf->used <= cbuf->size);
assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
if (cbuf->used == cbuf->size) {
TRACE(("cbuf_writelen: full buffer"));
return 0; /* full */
}
if (cbuf->writepos < cbuf->readpos) {
return cbuf->readpos - cbuf->writepos;
}
return cbuf->size - cbuf->writepos;
}
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_readlen(cbuf)) {
dropbear_exit("bad cbuf read");
}
return &cbuf->data[cbuf->readpos];
}
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_writelen(cbuf)) {
dropbear_exit("bad cbuf write");
}
return &cbuf->data[cbuf->writepos];
}
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_writelen(cbuf)) {
dropbear_exit("bad cbuf write");
}
cbuf->used += len;
assert(cbuf->used <= cbuf->size);
cbuf->writepos = (cbuf->writepos + len) % cbuf->size;
}
void cbuf_incrread(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_readlen(cbuf)) {
dropbear_exit("bad cbuf read");
}
assert(cbuf->used >= len);
cbuf->used -= len;
cbuf->readpos = (cbuf->readpos + len) % cbuf->size;
}

View File

@@ -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
@@ -21,14 +21,30 @@
* 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"
#ifndef _CIRCBUFFER_H_
#define _CIRCBUFFER_H_
struct circbuf {
extern const struct ChanType chan_tcpdirect;
unsigned int size;
unsigned int readpos;
unsigned int writepos;
unsigned int used;
unsigned char* data;
};
#endif
typedef struct circbuf circbuffer;
circbuffer * cbuf_new(unsigned int size);
void cbuf_free(circbuffer * cbuf);
unsigned int cbuf_getused(circbuffer * cbuf); /* how much data stored */
unsigned int cbuf_getavail(circbuffer * cbuf); /* how much we can write */
unsigned int cbuf_readlen(circbuffer *cbuf); /* max linear read len */
unsigned int cbuf_writelen(circbuffer *cbuf); /* max linear write len */
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len);
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len);
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len);
void cbuf_incrread(circbuffer *cbuf, unsigned int len);
#endif

View File

@@ -1,3 +1,28 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* 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 "session.h"
#include "auth.h"
@@ -92,7 +117,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 +151,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;
@@ -144,6 +169,8 @@ void recv_msg_userauth_failure() {
}
}
m_free(methods);
cli_ses.state = USERAUTH_FAIL_RCVD;
TRACE(("leave recv_msg_userauth_failure"));
@@ -163,14 +190,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;

View File

@@ -1,3 +1,27 @@
/*
* Dropbear SSH
*
* 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 "buffer.h"
#include "dbutil.h"
@@ -5,6 +29,7 @@
#include "ssh.h"
#include "runopts.h"
#ifdef ENABLE_CLI_PASSWORD_AUTH
int cli_auth_password() {
char* password = NULL;
@@ -35,3 +60,4 @@ int cli_auth_password() {
return 1; /* Password auth can always be tried */
}
#endif

View File

@@ -1,3 +1,28 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* 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"
@@ -6,6 +31,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.
@@ -13,17 +39,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 +176,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 {
@@ -152,3 +184,4 @@ int cli_auth_pubkey() {
return 0;
}
}
#endif /* Pubkey auth */

View File

@@ -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
@@ -22,12 +22,44 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _PUBKEY_AUTH_
#define _PUBKEY_AUTH_
#include "includes.h"
#include "channel.h"
#include "buffer.h"
#include "circbuffer.h"
#include "dbutil.h"
#include "session.h"
#include "ssh.h"
#ifdef DROPBEAR_PUBKEY_AUTH
/* We receive channel data - only used by the client chansession code*/
void recv_msg_channel_extended_data() {
void pubkeyauth();
unsigned int chan;
struct Channel *channel;
unsigned int datatype;
#endif /* DROPBEAR_PUBKEY_AUTH */
#endif /* _PUBKEY_AUTH_ */
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"));
}

View File

@@ -1,3 +1,28 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* 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 "packet.h"
#include "buffer.h"
@@ -7,9 +32,11 @@
#include "ssh.h"
#include "runopts.h"
#include "termcodes.h"
#include "chansession.h"
static void cli_closechansess(struct Channel *channel);
static int cli_initchansess(struct Channel *channel);
static void cli_chansessreq(struct Channel *channel);
static void start_channel_request(struct Channel *channel, unsigned char *type);
@@ -17,19 +44,43 @@ static void send_chansess_pty_req(struct Channel *channel);
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 */
NULL, /* checkclosehandler */
NULL, /* reqhandler */
cli_chansessreq, /* reqhandler */
cli_closechansess, /* closehandler */
};
static void cli_chansessreq(struct Channel *channel) {
unsigned char* type = NULL;
int wantreply;
TRACE(("enter cli_chansessreq"));
type = buf_getstring(ses.payload, NULL);
wantreply = buf_getbyte(ses.payload);
if (strcmp(type, "exit-status") != 0) {
TRACE(("unknown request '%s'", type));
send_msg_channel_failure(channel);
goto out;
}
/* We'll just trust what they tell us */
cli_ses.retval = buf_getint(ses.payload);
TRACE(("got exit-status of '%d'", cli_ses.retval));
out:
m_free(type);
}
/* If the main session goes, we close it up */
static void cli_closechansess(struct Channel *channel) {
static void cli_closechansess(struct Channel *UNUSED(channel)) {
/* This channel hasn't gone yet, so we have > 1 */
if (ses.chancount > 1) {
@@ -178,7 +229,7 @@ static void put_termcodes() {
bufpos2 = ses.writepayload->pos;
buf_setpos(ses.writepayload, bufpos1); /* Jump back */
buf_putint(ses.writepayload, bufpos2 - bufpos1); /* len(termcodes) */
buf_putint(ses.writepayload, bufpos2 - bufpos1 - 4); /* len(termcodes) */
buf_setpos(ses.writepayload, bufpos2); /* Back where we were */
TRACE(("leave put_termcodes"));
@@ -203,7 +254,7 @@ static void put_winsize() {
}
static void sigwinch_handler(int dummy) {
static void sigwinch_handler(int UNUSED(unused)) {
cli_ses.winchange = 1;
@@ -288,9 +339,17 @@ static void send_chansess_shell_req(struct Channel *channel) {
static int cli_initchansess(struct Channel *channel) {
channel->infd = STDOUT_FILENO;
//channel->outfd = STDIN_FILENO;
//channel->errfd = STDERR_FILENO;
setnonblocking(STDOUT_FILENO);
channel->outfd = STDIN_FILENO;
setnonblocking(STDIN_FILENO);
channel->errfd = STDERR_FILENO;
setnonblocking(STDERR_FILENO);
channel->extrabuf = cbuf_new(RECV_MAXWINDOW);
if (cli_opts.wantpty) {
send_chansess_pty_req(channel);

View File

@@ -1,7 +1,8 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2002-2004 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -44,8 +45,8 @@ void send_msg_kexdh_init() {
cli_ses.dh_e = (mp_int*)m_malloc(sizeof(mp_int));
cli_ses.dh_x = (mp_int*)m_malloc(sizeof(mp_int));
m_mp_init_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
gen_kexdh_vals(cli_ses.dh_e, cli_ses.dh_x);
CHECKCLEARTOWRITE();
@@ -58,13 +59,18 @@ void send_msg_kexdh_init() {
/* Handle a diffie-hellman key exchange reply. */
void recv_msg_kexdh_reply() {
mp_int dh_f;
DEF_MP_INT(dh_f);
sign_key *hostkey = NULL;
unsigned int type, keybloblen;
unsigned char* keyblob = NULL;
TRACE(("enter recv_msg_kexdh_reply"));
if (cli_ses.kex_state != KEXDH_INIT_SENT) {
dropbear_exit("Received out-of-order kexdhreply");
}
m_mp_init(&dh_f);
type = ses.newkeys->algo_hostkey;
TRACE(("type is %d", type));
@@ -82,7 +88,6 @@ void recv_msg_kexdh_reply() {
dropbear_exit("Bad KEX packet");
}
m_mp_init(&dh_f);
if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
TRACE(("failed getting mpint"));
dropbear_exit("Bad KEX packet");
@@ -90,6 +95,9 @@ void recv_msg_kexdh_reply() {
kexdh_comb_key(cli_ses.dh_e, cli_ses.dh_x, &dh_f, hostkey);
mp_clear(&dh_f);
mp_clear_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
m_free(cli_ses.dh_e);
m_free(cli_ses.dh_x);
if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE)
!= DROPBEAR_SUCCESS) {
@@ -125,8 +133,10 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
char * filename = NULL;
FILE *hostsfile = NULL;
int readonly = 0;
struct passwd *pw = NULL;
unsigned int len, hostlen;
unsigned int hostlen, algolen;
unsigned long len;
const char *algoname = NULL;
buffer * line = NULL;
int ret;
@@ -144,20 +154,37 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
/* Check that ~/.ssh exists - easiest way is just to mkdir */
if (mkdir(filename, S_IRWXU) != 0) {
if (errno != EEXIST) {
dropbear_log(LOG_INFO, "Warning: failed creating ~/.ssh: %s",
strerror(errno));
TRACE(("mkdir didn't work: %s", strerror(errno)));
ask_to_confirm(keyblob, keybloblen);
goto out; /* only get here on success */
}
}
snprintf(filename, len+18, "%s/.ssh/known_hosts", pw->pw_dir);
hostsfile = fopen(filename, "r+");
hostsfile = fopen(filename, "a+");
if (hostsfile != NULL) {
fseek(hostsfile, 0, SEEK_SET);
} else {
/* We mightn't have been able to open it if it was read-only */
if (errno == EACCES || errno == EROFS) {
TRACE(("trying readonly: %s", strerror(errno)));
readonly = 1;
hostsfile = fopen(filename, "r");
}
}
if (hostsfile == NULL) {
TRACE(("hostsfile didn't open: %s", strerror(errno)));
ask_to_confirm(keyblob, keybloblen);
goto out; /* We only get here on success */
}
line = buf_new(MAX_KNOWNHOSTS_LINE);
hostlen = strlen(cli_opts.remotehost);
algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen);
do {
if (buf_getline(line, hostsfile) == DROPBEAR_FAILURE) {
@@ -188,20 +215,19 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
continue;
}
algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &len);
if ( strncmp(buf_getptr(line, len), algoname, len) != 0) {
if ( strncmp(buf_getptr(line, algolen), algoname, algolen) != 0) {
TRACE(("algo doesn't match"));
continue;
}
buf_incrpos(line, len);
buf_incrpos(line, algolen);
if (buf_getbyte(line) != ' ') {
TRACE(("missing space after algo"));
continue;
}
/* Now we're at the interesting hostkey */
ret = cmp_base64_key(keyblob, keybloblen, algoname, len, line);
ret = cmp_base64_key(keyblob, keybloblen, algoname, algolen, line);
if (ret == DROPBEAR_SUCCESS) {
/* Good matching key */
@@ -214,12 +240,39 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
/* Key doesn't exist yet */
ask_to_confirm(keyblob, keybloblen);
/* If we get here, they said yes */
if (readonly) {
TRACE(("readonly"));
goto out;
}
/* put the new entry in the file */
fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */
buf_setpos(line, 0);
buf_setlen(line, 0);
buf_putbytes(line, ses.remotehost, hostlen);
buf_putbyte(line, ' ');
buf_putbytes(line, algoname, algolen);
buf_putbyte(line, ' ');
len = line->size - line->pos;
TRACE(("keybloblen %d, len %d", keybloblen, len));
/* The only failure with base64 is buffer_overflow, but buf_getwriteptr
* will die horribly in the case anyway */
base64_encode(keyblob, keybloblen, buf_getwriteptr(line, len), &len);
buf_incrwritepos(line, len);
buf_putbyte(line, '\n');
buf_setpos(line, 0);
fwrite(buf_getptr(line, line->len), line->len, 1, hostsfile);
/* We ignore errors, since there's not much we can do about them */
out:
if (hostsfile != NULL) {
fclose(hostsfile);
}
m_free(filename);
buf_free(line);
if (line != NULL) {
buf_free(line);
}
}

View File

@@ -1,3 +1,29 @@
/*
* Dropbear - a SSH2 server
* SSH client implementation
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* 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 "runopts.h"
@@ -26,6 +52,10 @@ int main(int argc, char ** argv) {
TRACE(("user='%s' host='%s' port='%s'", cli_opts.username,
cli_opts.remotehost, cli_opts.remoteport));
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
dropbear_exit("signal() error");
}
sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
0, &error);
@@ -70,7 +100,8 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
exit(exitcode);
}
static void cli_dropbear_log(int priority, const char* format, va_list param) {
static void cli_dropbear_log(int UNUSED(priority),
const char* format, va_list param) {
char printbuf[1024];

View File

@@ -28,25 +28,39 @@
#include "buffer.h"
#include "dbutil.h"
#include "algo.h"
#include "tcpfwd.h"
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
static void addforward(char* str, struct TCPFwdList** fwdlist);
#endif
static void printhelp() {
fprintf(stderr, "Dropbear client v%s\n"
"Usage: %s [options] user@host\n"
"Usage: %s [options] [user@]host\n"
"Options are:\n"
"-p <remoteport>\n"
"-t Allocate a pty\n"
"-T Don't allocate a pty\n"
#ifdef DROPBEAR_PUBKEY_AUTH
#ifdef ENABLE_CLI_PUBKEY_AUTH
"-i <identityfile> (multiple allowed)\n"
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
"-L <listenport:remotehsot:reportport> Local port forwarding\n"
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
"-R <listenport:remotehost:remoteport> Remote port forwarding\n"
#endif
"-l <username>\n"
#ifdef DEBUG_TRACE
"-v verbose\n"
#endif
,DROPBEAR_VERSION, cli_opts.progname);
}
@@ -56,11 +70,16 @@ 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
int nextislocal = 0;
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
int nextisremote = 0;
#endif
char* dummy = NULL; /* Not used for anything real */
/* see printhelp() for options */
cli_opts.progname = argv[0];
@@ -69,8 +88,14 @@ 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
cli_opts.localfwds = NULL;
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
cli_opts.remotefwds = NULL;
#endif
opts.nolocaltcp = 0;
opts.noremotetcp = 0;
@@ -81,13 +106,29 @@ 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]);
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 */
@@ -106,7 +147,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;
@@ -117,17 +158,58 @@ void cli_getopts(int argc, char ** argv) {
case 'T': /* don't want a pty */
cli_opts.wantpty = 0;
break;
default:
fprintf(stderr, "Unknown argument '%s'\n", argv[i]);
#ifdef ENABLE_CLI_LOCALTCPFWD
case 'L':
nextislocal = 1;
break;
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
case 'R':
nextisremote = 1;
break;
#endif
case 'l':
next = &cli_opts.username;
break;
case 'h':
printhelp();
exit(EXIT_FAILURE);
exit(EXIT_SUCCESS);
break;
#ifdef DEBUG_TRACE
case 'v':
debug_trace = 1;
break;
#endif
case 'F':
case 'e':
case 'c':
case 'm':
case 'D':
#ifndef ENABLE_CLI_REMOTETCPFWD
case 'R':
#endif
#ifndef ENABLE_CLI_LOCALTCPFWD
case 'L':
#endif
case 'o':
case 'b':
next = &dummy;
default:
fprintf(stderr,
"WARNING: Ignoring unknown argument '%s'\n", argv[i]);
break;
} /* Switch */
/* Now we handle args where they might be "-luser" (no spaces)*/
if (next && strlen(argv[i]) > 2) {
*next = &argv[i][2];
next = NULL;
}
continue; /* next argument */
} else {
TRACE(("non-flag arg"));
TRACE(("non-flag arg: '%s'", argv[i]));
/* Either the hostname or commands */
@@ -162,7 +244,8 @@ void cli_getopts(int argc, char ** argv) {
}
if (cli_opts.remotehost == NULL) {
dropbear_exit("Bad syntax");
printhelp();
exit(EXIT_FAILURE);
}
if (cli_opts.remoteport == NULL) {
@@ -180,7 +263,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;
@@ -208,10 +291,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) {
@@ -239,3 +326,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

View File

@@ -1,3 +1,28 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* 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 "service.h"
#include "dbutil.h"

View File

@@ -1,11 +1,35 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* 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 "session.h"
#include "dbutil.h"
#include "kex.h"
#include "ssh.h"
#include "packet.h"
#include "tcpfwd-direct.h"
#include "tcpfwd-remote.h"
#include "tcpfwd.h"
#include "channel.h"
#include "random.h"
#include "service.h"
@@ -22,8 +46,9 @@ struct clientsession cli_ses; /* GLOBAL */
/* Sorted in decreasing frequency will be more efficient - data and window
* should be first */
static const packettype cli_packettypes[] = {
/* TYPE, AUTHREQUIRED, FUNCTION */
/* 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 */
@@ -31,7 +56,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},
@@ -39,15 +63,16 @@ 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 */
};
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 */
};
@@ -88,6 +113,14 @@ static void cli_session_init() {
cli_ses.tty_raw_mode = 0;
cli_ses.winchange = 0;
/* We store stdin's flags, so we can set them back on exit (otherwise
* busybox's ash isn't happy */
cli_ses.stdincopy = dup(STDIN_FILENO);
cli_ses.stdinflags = fcntl(STDIN_FILENO, F_GETFL, 0);
cli_ses.retval = EXIT_SUCCESS; /* Assume it's clean if we don't get a
specific exit status */
/* Auth */
cli_ses.lastpubkey = NULL;
cli_ses.lastauthtype = NULL;
@@ -179,6 +212,12 @@ static void cli_sessionloop() {
*/
case USERAUTH_SUCCESS_RCVD:
#ifdef ENABLE_CLI_LOCALTCPFWD
setup_localtcp();
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
setup_remotetcp();
#endif
cli_send_chansess_request();
TRACE(("leave cli_sessionloop: cli_send_chansess_request"));
cli_ses.state = SESSION_RUNNING;
@@ -210,6 +249,11 @@ void cli_session_cleanup() {
if (!sessinitdone) {
return;
}
/* Set stdin back to non-blocking - busybox ash dies nastily
* if we don't revert the flags */
fcntl(cli_ses.stdincopy, F_SETFL, cli_ses.stdinflags);
cli_tty_cleanup();
}
@@ -220,11 +264,10 @@ static void cli_finished() {
common_session_cleanup();
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
cli_opts.remotehost, cli_opts.remoteport);
exit(EXIT_SUCCESS);
exit(cli_ses.retval);
}
/* called when the remote side closes the connection */
static void cli_remoteclosed() {

193
cli-tcpfwd.c Normal file
View File

@@ -0,0 +1,193 @@
/*
* Dropbear SSH
*
* 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 "options.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() {
int ret;
TRACE(("enter setup_localtcp"));
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;
}
TRACE(("leave setup_localtcp"));
}
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 = m_strdup(remoteaddr);
tcpinfo->sendport = remoteport;
tcpinfo->listenport = listenport;
tcpinfo->chantype = &cli_chan_tcplocal;
ret = listen_tcpfwd(tcpinfo);
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;
TRACE(("enter setup_remotetcp"));
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;
}
TRACE(("leave setup_remotetcp"));
}
static int newtcpforwarded(struct Channel * channel) {
unsigned int origport;
struct TCPFwdList * iter = NULL;
char portstring[NI_MAXSERV];
int sock;
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
/* 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"));
err = SSH_OPEN_CONNECT_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;
err = SSH_OPEN_IN_PROGRESS;
out:
TRACE(("leave newtcpdirect: err %d", err));
return err;
}

View File

@@ -1,7 +1,8 @@
/*
* Dropbear - a SSH2 server
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@@ -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,11 +29,10 @@
#include "packet.h"
#include "ssh.h"
#include "buffer.h"
#include "circbuffer.h"
#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,
@@ -41,7 +40,7 @@ static void send_msg_channel_open_failure(unsigned int remotechan, int reason,
static void send_msg_channel_open_confirmation(struct Channel* channel,
unsigned int recvwindow,
unsigned int recvmaxpacket);
static void writechannel(struct Channel *channel);
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf);
static void send_msg_channel_window_adjust(struct Channel *channel,
unsigned int incr);
static void send_msg_channel_data(struct Channel *channel, int isextended,
@@ -149,8 +148,10 @@ 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->recvdonelen = 0;
newchan->recvmaxpacket = RECV_MAXPACKET;
ses.channels[i] = newchan;
@@ -162,7 +163,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;
}
@@ -174,6 +175,7 @@ void channelio(fd_set *readfd, fd_set *writefd) {
struct Channel *channel;
unsigned int i;
int ret;
/* iterate through all the possible channels */
for (i = 0; i < ses.chansize; i++) {
@@ -190,7 +192,8 @@ void channelio(fd_set *readfd, fd_set *writefd) {
}
/* read from program/pipe stderr */
if (channel->errfd >= 0 && FD_ISSET(channel->errfd, readfd)) {
if (channel->extrabuf == NULL &&
channel->errfd >= 0 && FD_ISSET(channel->errfd, readfd)) {
send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR);
}
@@ -198,8 +201,15 @@ void channelio(fd_set *readfd, fd_set *writefd) {
* see if it has errors */
if (channel->infd >= 0 && channel->infd != channel->outfd
&& FD_ISSET(channel->infd, readfd)) {
int ret;
ret = write(channel->infd, NULL, 0);
if (channel->initconn) {
/* Handling for "in progress" connection - this is needed
* to avoid spinning 100% CPU when we connect to a server
* which doesn't send anything (tcpfwding) */
checkinitdone(channel);
continue; /* Important not to use the channel after
checkinitdone(), as it may be NULL */
}
ret = write(channel->infd, NULL, 0); /* Fake write */
if (ret < 0 && errno != EINTR && errno != EAGAIN) {
closeinfd(channel);
}
@@ -211,9 +221,14 @@ void channelio(fd_set *readfd, fd_set *writefd) {
checkinitdone(channel);
continue; /* Important not to use the channel after
checkinitdone(), as it may be NULL */
} else {
writechannel(channel);
}
writechannel(channel, channel->infd, channel->writebuf);
}
/* stderr for client mode */
if (channel->extrabuf != NULL
&& channel->errfd >= 0 && FD_ISSET(channel->errfd, writefd)) {
writechannel(channel, channel->errfd, channel->extrabuf);
}
/* now handle any of the channel-closing type stuff */
@@ -231,6 +246,14 @@ void channelio(fd_set *readfd, fd_set *writefd) {
/* do all the EOF/close type stuff checking for a channel */
static void checkclose(struct Channel *channel) {
TRACE(("checkclose: infd %d, outfd %d, errfd %d, sentclosed %d, recvclosed %d",
channel->infd, channel->outfd,
channel->errfd, channel->sentclosed, channel->recvclosed));
TRACE(("writebuf %d extrabuf %s extrabuf %d",
cbuf_getused(channel->writebuf),
channel->writebuf,
channel->writebuf ? 0 : cbuf_getused(channel->extrabuf)));
if (!channel->sentclosed) {
/* check for exited - currently only used for server sessions,
@@ -243,13 +266,13 @@ static void checkclose(struct Channel *channel) {
if (!channel->senteof
&& channel->outfd == FD_CLOSED
&& channel->errfd == FD_CLOSED) {
&& (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
send_msg_channel_eof(channel);
}
if (channel->infd == FD_CLOSED
&& channel->outfd == FD_CLOSED
&& channel->errfd == FD_CLOSED) {
&& channel->outfd == FD_CLOSED
&& (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
send_msg_channel_close(channel);
}
}
@@ -287,10 +310,14 @@ static void checkinitdone(struct Channel *channel) {
if (getsockopt(channel->infd, SOL_SOCKET, SO_ERROR, &val, &vallen)
|| val != 0) {
send_msg_channel_open_failure(channel->remotechan,
SSH_OPEN_CONNECT_FAILED, "", "");
close(channel->infd);
deletechannel(channel);
TRACE(("leave checkinitdone: fail"));
} else {
send_msg_channel_open_confirmation(channel, channel->recvwindow,
channel->recvmaxpacket);
channel->outfd = channel->infd;
channel->initconn = 0;
TRACE(("leave checkinitdone: success"));
@@ -307,13 +334,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();
@@ -343,49 +363,53 @@ 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) {
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
int len, maxlen;
buffer *buf;
TRACE(("enter writechannel"));
buf = channel->writebuf;
maxlen = buf->len - buf->pos;
maxlen = cbuf_readlen(cbuf);
len = write(channel->infd, buf_getptr(buf, maxlen), maxlen);
/* Write the data out */
len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen);
if (len <= 0) {
if (len < 0 && errno != EINTR) {
/* no more to write */
/* no more to write - we close it even if the fd was stderr, since
* that's a nasty failure too */
closeinfd(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"));
}
cbuf_incrread(cbuf, len);
channel->recvdonelen += len;
/* 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);
if (fd == channel->infd && len == maxlen && channel->recveof) {
/* Check if we're closing up */
closeinfd(channel);
TRACE(("leave writechannel: recveof set"));
return;
}
/* Window adjust handling */
if (channel->recvdonelen >= RECV_WINDOWEXTEND) {
/* Set it back to max window */
send_msg_channel_window_adjust(channel, channel->recvdonelen);
channel->recvwindow += channel->recvdonelen;
channel->recvdonelen = 0;
}
assert(channel->recvwindow <= RECV_MAXWINDOW);
assert(channel->recvwindow <= cbuf_getavail(channel->writebuf));
assert(channel->extrabuf == NULL ||
channel->recvwindow <= cbuf_getavail(channel->extrabuf));
TRACE(("leave writechannel"));
}
@@ -403,30 +427,38 @@ 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 */
TRACE(("infd = %d, outfd %d, errfd %d, bufused %d",
channel->infd, channel->outfd,
channel->errfd,
cbuf_getused(channel->writebuf) ));
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_getused(channel->extrabuf) > 0 ) {
FD_SET(channel->errfd, writefd);
}
} /* foreach channel */
@@ -455,7 +487,9 @@ void recv_msg_channel_eof() {
}
channel->recveof = 1;
if (channel->writebuf->len == 0) {
if (cbuf_getused(channel->writebuf) == 0
&& (channel->extrabuf == NULL
|| cbuf_getused(channel->extrabuf) == 0)) {
closeinfd(channel);
}
@@ -497,15 +531,22 @@ 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);
close(channel->outfd);
if (channel->errfd >= 0) {
close(channel->errfd);
}
close(channel->errfd);
channel->typedata = NULL;
deletechannel(channel);
@@ -545,23 +586,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"));
}
@@ -604,15 +628,19 @@ static void send_msg_channel_data(struct Channel *channel, int isextended,
}
/* read the data */
TRACE(("maxlen %d", maxlen));
buf = buf_new(maxlen);
TRACE(("buf pos %d data %x", buf->pos, buf->data));
len = read(fd, buf_getwriteptr(buf, maxlen), maxlen);
if (len <= 0) {
/* on error/eof, send eof */
if (len == 0 || errno != EINTR) {
closeoutfd(channel, fd);
TRACE(("leave send_msg_channel_data: read err %d", channel->index));
}
buf_free(buf);
buf = NULL;
TRACE(("leave send_msg_channel_data: read err or EOF for fd %d",
channel->index));
return;
}
buf_incrlen(buf, len);
@@ -627,6 +655,7 @@ static void send_msg_channel_data(struct Channel *channel, int isextended,
buf_putstring(ses.writepayload, buf_getptr(buf, len), len);
buf_free(buf);
buf = NULL;
channel->transwindow -= len;
@@ -634,59 +663,72 @@ 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);
/* 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);
/* Whilst the spec says we "MAY ignore data past the end" this could
* lead to corrupted file transfers etc (chunks missed etc). It's better to
* just die horribly */
if (datalen > maxdata) {
TRACE(("Warning: recv_msg_channel_data: extra data past window"));
datalen = maxdata;
dropbear_exit("Oversized packet");
}
/* 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 */
/* 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);
buflen = MIN(buflen, len);
memcpy(cbuf_writeptr(cbuf, buflen),
buf_getptr(ses.payload, buflen), buflen);
cbuf_incrwrite(cbuf, buflen);
buf_incrpos(ses.payload, buflen);
len -= buflen;
}
assert(channel->recvwindow >= datalen);
channel->recvwindow -= datalen;
/* 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;
}*/
assert(channel->recvwindow <= RECV_MAXWINDOW);
TRACE(("leave recv_msg_channel_data"));
}
@@ -790,6 +832,10 @@ void recv_msg_channel_open() {
if (channel->type->inithandler) {
ret = channel->type->inithandler(channel);
if (ret > 0) {
if (ret == SSH_OPEN_IN_PROGRESS) {
/* We'll send the confirmation later */
goto cleanup;
}
errtype = ret;
deletechannel(channel);
TRACE(("inithandler returned failure %d", ret));
@@ -797,23 +843,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);
@@ -910,10 +939,7 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
}
/* set fd non-blocking */
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
TRACE(("leave send_msg_channel_open_init() - FAILED in fcntl()"));
return DROPBEAR_FAILURE;
}
setnonblocking(fd);
chan->infd = chan->outfd = fd;
ses.maxfd = MAX(ses.maxfd, fd);
@@ -1017,15 +1043,19 @@ static void closechanfd(struct Channel *channel, int fd, int how) {
closein = closeout = 1;
}
if (closeout && fd == channel->errfd) {
channel->errfd = FD_CLOSED;
}
if (closeout && fd == channel->outfd) {
channel->outfd = FD_CLOSED;
}
if (closeout && (channel->extrabuf == NULL) && (fd == channel->errfd)) {
channel->errfd = FD_CLOSED;
}
if (closein && fd == channel->infd) {
channel->infd = FD_CLOSED;
}
if (closein && (channel->extrabuf != NULL) && (fd == channel->errfd)) {
channel->errfd = FD_CLOSED;
}
}
#endif /* USING_LISTENERS */

View File

@@ -1,9 +1,5 @@
/*
* Dropbear - a SSH2 server
* SSH client implementation
*
* This code is copied from the larger file "kex.c"
* some functions are verbatim, others are generalized --mihnea
* Dropbear SSH
*
* Copyright (c) 2002-2004 Matt Johnston
* Portions Copyright (c) 2004 by Mihnea Stoenescu
@@ -468,15 +464,18 @@ void recv_msg_kexinit() {
/* Initialises and generate one side of the diffie-hellman key exchange values.
* See the ietf-secsh-transport draft, section 6, for details */
/* dh_pub and dh_priv MUST be already initialised */
void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
mp_int dh_p, dh_q, dh_g;
DEF_MP_INT(dh_p);
DEF_MP_INT(dh_q);
DEF_MP_INT(dh_g);
unsigned char randbuf[DH_P_LEN];
int dh_q_len;
TRACE(("enter send_msg_kexdh_reply"));
m_mp_init_multi(&dh_g, &dh_p, &dh_q, dh_priv, dh_pub, NULL);
m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL);
/* read the prime and generator*/
if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN)
@@ -635,42 +634,44 @@ static void read_kex_algos() {
/* encryption_algorithms_client_to_server */
c2s_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
if (algo == NULL) {
if (c2s_cipher_algo == NULL) {
erralgo = "enc c->s";
goto error;
}
TRACE(("c2s is %s", c2s_cipher_algo->name));
/* encryption_algorithms_server_to_client */
s2c_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
if (algo == NULL) {
if (s2c_cipher_algo == NULL) {
erralgo = "enc s->c";
goto error;
}
TRACE(("s2c is %s", s2c_cipher_algo->name));
/* mac_algorithms_client_to_server */
c2s_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
if (algo == NULL) {
if (c2s_hash_algo == NULL) {
erralgo = "mac c->s";
goto error;
}
/* mac_algorithms_server_to_client */
s2c_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
if (algo == NULL) {
if (s2c_hash_algo == NULL) {
erralgo = "mac s->c";
goto error;
}
/* compression_algorithms_client_to_server */
c2s_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
if (algo == NULL) {
if (c2s_comp_algo == NULL) {
erralgo = "comp c->s";
goto error;
}
/* compression_algorithms_server_to_client */
s2c_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
if (algo == NULL) {
if (s2c_comp_algo == NULL) {
erralgo = "comp s->c";
goto error;
}

View File

@@ -35,6 +35,8 @@
#include "channel.h"
#include "atomicio.h"
static void checktimeouts();
static int ident_readln(int fd, char* buf, int count);
struct sshsession ses; /* GLOBAL */
@@ -46,8 +48,6 @@ int sessinitdone = 0; /* GLOBAL */
int exitflag = 0; /* GLOBAL */
static void checktimeouts();
static int ident_readln(int fd, char* buf, int count);
/* called only at the start of a session, set up initial state */
void common_session_init(int sock, char* remotehost) {
@@ -223,6 +223,7 @@ void session_identification() {
char linebuf[256];
int len = 0;
char done = 0;
int i;
/* write our version string, this blocks */
if (atomicio(write, ses.sock, LOCAL_IDENT "\r\n",
@@ -230,14 +231,27 @@ void session_identification() {
dropbear_exit("Error writing ident string");
}
len = ident_readln(ses.sock, linebuf, 256);
if (len >= 4 && memcmp(linebuf, "SSH-", 4) == 0) {
/* start of line matches */
done = 1;
/* We allow up to 9 lines before the actual version string, to
* 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, sizeof(linebuf));
if (len < 0 && errno != EINTR) {
/* It failed */
break;
}
if (len >= 4 && memcmp(linebuf, "SSH-", 4) == 0) {
/* start of line matches */
done = 1;
break;
}
}
if (!done) {
dropbear_exit("Failed to get client version");
TRACE(("err: %s for '%s'\n", strerror(errno), linebuf));
dropbear_exit("Failed to get remote version");
} else {
/* linebuf is already null terminated */
ses.remoteident = m_malloc(len);

View File

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

View File

@@ -1,3 +1,27 @@
/*
* Dropbear SSH
*
* 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 _COMPAT_H_
#define _COMPAT_H_

View File

@@ -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
@@ -241,6 +250,84 @@ AC_CHECK_TYPE([socklen_t], ,[
[#include <sys/types.h>
#include <sys/socket.h>])
# 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 <sys/types.h>
#include <sys/socket.h>
],
[ 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 <sys/types.h>
#include <netinet/in.h>
],
[ 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 <sys/types.h>
#include <netinet/in.h>
],
[ 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 <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
],
[ 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 <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
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
@@ -498,7 +585,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))
@@ -519,6 +606,7 @@ if test -z "$no_ptc_check" ; then
fi
fi
AC_EXEEXT
AC_CONFIG_HEADER(config.h)
AC_OUTPUT(Makefile)
AC_MSG_RESULT()

View File

@@ -1,3 +1,27 @@
/*
* Dropbear SSH
*
* 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"
/* definitions are cleanest if we just put them here */
@@ -20,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
@@ -47,7 +72,7 @@ int main(int argc, char ** argv) {
"'dropbear' - the Dropbear server\n"
#endif
#ifdef DBMULTI_dbclient
"'dbclient' - the Dropbear client\n"
"'dbclient' or 'ssh' - the Dropbear client\n"
#endif
#ifdef DBMULTI_dropbearkey
"'dropbearkey' - the key generator\n"

244
dbutil.c
View File

@@ -56,8 +56,19 @@
#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;
#ifdef DEBUG_TRACE
int debug_trace = 0;
#endif
int usingsyslog = 0; /* set by runopts, but required externally to sessions */
#ifndef DISABLE_SYSLOG
@@ -88,6 +99,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 UNUSED(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, ...) {
@@ -105,6 +138,10 @@ void dropbear_trace(const char* format, ...) {
va_list param;
if (!debug_trace) {
return;
}
va_start(param, format);
fprintf(stderr, "TRACE: ");
vfprintf(stderr, format, param);
@@ -113,8 +150,114 @@ void dropbear_trace(const char* format, ...) {
}
#endif /* DEBUG_TRACE */
/* Listen on address:port. Unless address is NULL, in which case listen on
* everything. If called with address == "", we'll listen on localhost/loopback.
* 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 = NULL, *res0 = NULL;
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;
if (address && address[0] == '\0') {
TRACE(("dropbear_listen: local loopback"));
address = NULL;
} else {
TRACE(("dropbear_listen: not local loopback"));
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(%s) failed", port));
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 listening: %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) {
@@ -167,7 +310,7 @@ int connect_remote(const char* remotehost, const char* remoteport,
}
if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
if (errno == EINPROGRESS) {
if (errno == EINPROGRESS && nonblocking) {
TRACE(("Connect in progress"));
break;
} else {
@@ -181,7 +324,7 @@ int connect_remote(const char* remotehost, const char* remoteport,
break; /* Success */
}
if (sock < 0) {
if (sock < 0 && !(errno == EINPROGRESS && nonblocking)) {
/* Failed */
if (errstring != NULL && *errstring == NULL) {
int len;
@@ -197,58 +340,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;
default:
/* XXX ipv6 */
strcpy(retstring, "Bad protocol");
ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
sbuf, sizeof(sbuf), NI_NUMERICSERV | NI_NUMERICHOST);
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) {
@@ -324,7 +479,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;
@@ -351,18 +506,17 @@ int buf_getline(buffer * line, FILE * authfile) {
out:
buf_setpos(line, 0);
/* if we didn't read anything before EOF or error, exit */
if (c == EOF && line->pos == 0) {
TRACE(("leave getauthline: failure"));
TRACE(("leave buf_getline: failure"));
return DROPBEAR_FAILURE;
} else {
TRACE(("leave getauthline: success"));
TRACE(("leave buf_getline: success"));
buf_setpos(line, 0);
return DROPBEAR_SUCCESS;
}
TRACE(("leave buf_getline"));
}
#endif
@@ -440,3 +594,13 @@ void m_burn(void *data, unsigned int len) {
}
}
void setnonblocking(int fd) {
TRACE(("setnonblocking: %d", fd));
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
dropbear_exit("Couldn't set nonblocking");
}
TRACE(("leave setnonblocking"));
}

View File

@@ -42,12 +42,15 @@ void dropbear_log(int priority, const char* format, ...);
#ifdef DEBUG_TRACE
void dropbear_trace(const char* format, ...);
void printhex(unsigned char* buf, int len);
extern int debug_trace;
#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);
@@ -58,6 +61,7 @@ void * m_realloc(void* ptr, size_t size);
#define m_free(X) __m_free(X); (X) = NULL;
void __m_free(void* ptr);
void m_burn(void* data, unsigned int len);
void setnonblocking(int fd);
/* Used to force mp_ints to be initialised */
#define DEF_MP_INT(X) mp_int X = {0, 0, 0, NULL}

46
debian/README.runit vendored Normal file
View File

@@ -0,0 +1,46 @@
Using the dropbear SSH server with runit's services supervision
---------------------------------------------------------------
The dropbear SSH server is perfectly suited to be run under runit's
service supervision, and this package already has prepared an adequate
service directory. Follow these steps to enable the dropbear service
using the runit package.
If not yet installed on your system, install the runit package, and make
sure its service supervision is enabled (it's by default)
# apt-get install runit
Make sure the dropbear service normally handled through the sysv init
script is stopped
# /etc/init.d/dropbear stop
Create the system user ``dropbearlog'' which will run the logger service,
and own the logs
# adduser --system --home /var/log/dropbear --no-create-home dropbearlog
Create the log directory and make the newly created system user the owner
of this directory
# mkdir -p /var/log/dropbear && chown dropbearlog /var/log/dropbear
Optionally adjust the configuration of the dropbear service by editing the
run script
# vi /etc/dropbear/run
Finally enable the service by linking dropbear's service directory to
/var/service/. The service will be started within five seconds, and
automatically at boot time. The sysv init script is disabled; see the
runsvctrl(8) program for information on how to control services handled by
runit. See the svlogd(8) program on how to configure the log service.
# ln -s /etc/dropbear /var/service/
Optionally check the status of the service a few seconds later
# runsvstat -l /var/service/dropbear
-- Gerrit Pape <pape@smarden.org>, Sun, 16 May 2004 15:52:34 +0000

71
debian/changelog vendored
View File

@@ -1,3 +1,74 @@
dropbear (0.44test3-1) unstable; urgency=medium
* New upstream beta, various useful fixes.
-- Matt Johnston <matt@ucc.asn.au> Fri, 27 August 2004 22:20:00 +0800
dropbear (0.44test2-1) unstable; urgency=low
* New upstream beta, various minor fixes.
-- Matt Johnston <matt@ucc.asn.au> Tues, 17 August 2004 19:00:00 +0800
dropbear (0.44test1-1) unstable; urgency=low
* Upstream beta 0.44test1
* Huge changes to allow client functionality
-- Matt Johnston <matt@ucc.asn.au> Sat, 14 August 2004 23:00:00 +0800
dropbear (0.43-1) unstable; urgency=high
* New upstream release 0.43
* SECURITY: Don't attempt to free uninitialised buffers in DSS verification
code
* Handle portforwarding to servers which don't send any initial data
(Closes: #258426)
-- Matt Johnston <matt@ucc.asn.au> Fri, 16 July 2004 17:44:54 +0800
dropbear (0.42-1) unstable; urgency=low
* New upstream release 0.42
-- Matt Johnston <matt@ucc.asn.au> Wed, 16 June 2004 12:44:54 +0800
dropbear (0.41-3) unstable; urgency=low
* 1st upload to the Debian archive (closes: #216553).
* debian/diff/cvs-20040520.diff: new; stable cvs snapshot.
* debian/rules: new target patch: apply diffs in debian/diff/, reverse
apply in target clean; install man pages.
* debian/control: Priority: optional.
-- Gerrit Pape <pape@smarden.org> Sun, 23 May 2004 08:32:37 +0000
dropbear (0.41-2) unstable; urgency=low
* new maintainer.
* debian/control: no longer Build-Depends: debhelper; Build-Depends:
libz-dev; Standards-Version: 3.6.1.0; Suggests: runit; update
descriptions.
* debian/rules: stop using debhelper, use implicit rules; cleanup;
install dropbearconvert into /usr/lib/dropbear/.
* debian/impicit: new; implicit rules.
* debian/copyright.in: adapt.
* debian/dropbear.init: minor adaptions; test for dropbear service
directory.
* debian/README.runit: new; how to use dropbear with runit.
* debian/README.Debian, debian/docs: rename to debian/dropbear.*.
* debian/dropbear.docs: add debian/README.runit
* debian/conffiles: rename to debian/dropbear.conffiles; add init
script, and run scripts.
* debian/postinst: rename to debian/dropbear.postinst; adapt; use
invloke-rc.d dropbear start.
* debian/dropbear.prerm: new; invoke-rc.d dropbear stop.
* debian/postrm: rename to debian/dropbear.postrm; adapt; clean up
service directories.
* debian/compat, debian/dirs, dropbear.default: remove; obsolete.
-- Gerrit Pape <pape@smarden.org> Sun, 16 May 2004 16:50:55 +0000
dropbear (0.41-1) unstable; urgency=low
* Updated to 0.41 release.

1
debian/compat vendored
View File

@@ -1 +0,0 @@
4

0
debian/conffiles vendored
View File

24
debian/control vendored
View File

@@ -1,14 +1,20 @@
Source: dropbear
Section: net
Priority: standard
Maintainer: Grahame Bowland <grahame@angrygoats.net>
Build-Depends: debhelper (>> 4.0.0), zlib1g-dev
Standards-Version: 3.5.8
Priority: optional
Maintainer: Gerrit Pape <pape@smarden.org>
Build-Depends: libz-dev
Standards-Version: 3.6.1.0
Package: dropbear
Architecture: any
Depends: ${shlibs:Depends} ${misc:Depends}
Suggests: ssh
Description: a minimal SSH2 server
A small secure shell version 2 server.
Depends: ${shlibs:Depends}
Suggests: ssh, runit
Description: lightweight SSH2 server
dropbear is a SSH 2 server designed to be small enough to be used in small
memory environments, while still being functional and secure enough for
general use.
.
It implements most required features of the SSH 2 protocol, and other
features such as X11 and authentication agent forwarding.
.
See http://matt.ucc.asn.au/dropbear/dropbear.html

6
debian/copyright.in vendored
View File

@@ -1,9 +1,11 @@
This package was debianized by Grahame Bowland <grahame.angrygoats.net> on
Tue, 17 Jun 2003 15:04:47 +0800.
Tue, 17 Jun 2003 15:04:47 +0800, maintained temporarily by Matt Johnston
<matt@ucc.asn.au>, and was adopted by Gerrit Pape <pape@smarden.org> on
Sun, 16 May 2004 14:38:33 +0000.
It was downloaded from http://matt.ucc.asn.au/dropbear/
Upstream Author(s): Matt Johnston <matt@ucc.asn.au>
Upstream Author: Matt Johnston <matt@ucc.asn.au>
Copyright:

2
debian/dirs vendored
View File

@@ -1,2 +0,0 @@
usr/bin
usr/sbin

2
debian/docs vendored
View File

@@ -1,2 +0,0 @@
README
TODO

41
debian/dropbear.README.Debian vendored Normal file
View File

@@ -0,0 +1,41 @@
Dropbear for Debian
-------------------
This package will attempt to listen on port 22. If the OpenSSH
package ("ssh") is installed, the file /etc/default/dropbear
will be set up so that the server does not start by default.
You can run Dropbear concurrently with OpenSSH 'sshd' by
modifying /etc/default/dropbear so that "NO_START" is set to
"0" and changing the port number that Dropbear runs on. Follow
the instructions in the file.
This package suggests you install the "ssh" package. This package
provides the "ssh" client program, as well as the "/usr/bin/scp"
binary you will need to be able to retrieve files from a server
running Dropbear via SCP.
Replacing OpenSSH "sshd" with Dropbear
--------------------------------------
You will still want to have the "ssh" package installed, as it
provides the "ssh" and "scp" binaries. When you install this
package, it checks for existing OpenSSH host keys and if found,
converts them to the Dropbear format.
If this appears to have worked, you should be able to change over
by following these steps:
1. Stop the OpenSSH server
% /etc/init.d/ssh stop
2. Prevent the OpenSSH server from starting in the future
% touch /etc/ssh/sshd_not_to_be_run
3. Modify the Dropbear defaults file, set NO_START to 0 and
ensure DROPBEAR_PORT is set to 22.
% editor /etc/default/dropbear
4. Restart the Dropbear server.
% /etc/init.d/dropbear restart
See the Dropbear homepage for more information:
http://matt.ucc.asn.au/dropbear/dropbear.html

3
debian/dropbear.conffiles vendored Normal file
View File

@@ -0,0 +1,3 @@
/etc/init.d/dropbear
/etc/dropbear/run
/etc/dropbear/log/run

3
debian/dropbear.docs vendored Normal file
View File

@@ -0,0 +1,3 @@
README
TODO
debian/README.runit

60
debian/dropbear.init vendored
View File

@@ -1,15 +1,4 @@
#! /bin/sh
#
# skeleton example file to build /etc/init.d/ scripts.
# This file should be used to construct scripts for /etc/init.d.
#
# Written by Miquel van Smoorenburg <miquels@cistron.nl>.
# Modified for Debian
# by Ian Murdock <imurdock@gnu.ai.mit.edu>.
#
# Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl
#
#!/bin/sh
#
# Do not configure this file. Edit /etc/default/dropbear instead!
#
@@ -22,54 +11,45 @@ DESC="Dropbear SSH server"
DROPBEAR_PORT=22
DROPBEAR_EXTRA_ARGS=
NO_START=0
set -e
test -f /etc/default/dropbear && . /etc/default/dropbear
if [ -n "$DROPBEAR_BANNER" ]; then
DROPBEAR_EXTRA_ARGS="$DROPBEAR_EXTRA_ARGS -b $DROPBEAR_BANNER"
fi
test ! -r /etc/default/dropbear || . /etc/default/dropbear
test "$NO_START" = "0" || exit 0
test -x "$DAEMON" || exit 0
test ! -h /var/service/dropbear || exit 0
if [ -z "$DROPBEAR_RSAKEY" ]; then
DROPBEAR_RSAKEY="/etc/dropbear/dropbear_rsa_host_key"
fi
if [ -z "$DROPBEAR_DSSKEY" ]; then
DROPBEAR_DSSKEY="/etc/dropbear/dropbear_dss_host_key"
fi
test "$NO_START" != "0" && exit 0
test -x $DAEMON || exit 0
test -z "$DROPBEAR_BANNER" || \
DROPBEAR_EXTRA_ARGS="$DROPBEAR_EXTRA_ARGS -b $DROPBEAR_BANNER"
test -n "$DROPBEAR_RSAKEY" || \
DROPBEAR_RSAKEY="/etc/dropbear/dropbear_rsa_host_key"
test -n "$DROPBEAR_DSSKEY" || \
DROPBEAR_DSSKEY="/etc/dropbear/dropbear_dss_host_key"
case "$1" in
start)
echo -n "Starting $DESC: "
start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \
--exec $DAEMON -- -d $DROPBEAR_DSSKEY -r $DROPBEAR_RSAKEY -p $DROPBEAR_PORT $DROPBEAR_EXTRA_ARGS
start-stop-daemon --start --quiet --pidfile /var/run/"$NAME".pid \
--exec "$DAEMON" -- -d "$DROPBEAR_DSSKEY" -r "$DROPBEAR_RSAKEY" \
-p "$DROPBEAR_PORT" $DROPBEAR_EXTRA_ARGS
echo "$NAME."
;;
stop)
echo -n "Stopping $DESC: "
start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/$NAME.pid
start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/"$NAME".pid
echo "$NAME."
;;
restart|force-reload)
#
# If the "reload" option is implemented, move the "force-reload"
# option to the "reload" entry above. If not, "force-reload" is
# just the same as "restart".
#
echo -n "Restarting $DESC: "
start-stop-daemon --stop --quiet --oknodo --pidfile \
/var/run/$NAME.pid
start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/"$NAME".pid
sleep 1
start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \
--exec $DAEMON -- -d $DROPBEAR_DSSKEY -r $DROPBEAR_RSAKEY -p $DROPBEAR_PORT $DROPBEAR_EXTRA_ARGS
start-stop-daemon --start --quiet --pidfile /var/run/"$NAME".pid \
--exec "$DAEMON" -- -d "$DROPBEAR_DSSKEY" -r "$DROPBEAR_RSAKEY" \
-p "$DROPBEAR_PORT" $DROPBEAR_EXTRA_ARGS
echo "$NAME."
;;
*)
N=/etc/init.d/$NAME
# echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $N {start|stop|restart|force-reload}" >&2
exit 1
;;

68
debian/dropbear.postinst vendored Normal file
View File

@@ -0,0 +1,68 @@
#!/bin/sh
set -e
test "$1" = 'configure' || exit 0
test -n "$2" || chown log /etc/dropbear/log/main || true
if test ! -e /etc/dropbear/dropbear_rsa_host_key; then
if test -f /etc/ssh/ssh_host_rsa_key; then
echo "Converting existing OpenSSH RSA host key to Dropbear format."
/usr/lib/dropbear/dropbearconvert openssh dropbear \
/etc/ssh/ssh_host_rsa_key /etc/dropbear/dropbear_rsa_host_key
else
echo "Generating Dropbear RSA key. Please wait."
dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
fi
fi
if test ! -e /etc/dropbear/dropbear_dss_host_key; then
if test -f /etc/ssh/ssh_host_dsa_key; then
echo "Converting existing OpenSSH RSA host key to Dropbear format."
/usr/lib/dropbear/dropbearconvert openssh dropbear \
/etc/ssh/ssh_host_dsa_key /etc/dropbear/dropbear_dss_host_key
else
echo "Generating Dropbear DSS key. Please wait."
dropbearkey -t dss -f /etc/dropbear/dropbear_dss_host_key
fi
fi
if test ! -s /etc/default/dropbear; then
# check whether OpenSSH seems to be installed.
if test -x /usr/sbin/sshd; then
cat <<EOT
OpenSSH appears to be installed. Setting /etc/default/dropbear so that
Dropbear will not start by default. Edit this file to change this behaviour.
EOT
cat >>/etc/default/dropbear <<EOT
# disabled because OpenSSH is installed
# change to NO_START=0 to enable Dropbear
NO_START=1
EOT
fi
cat >>/etc/default/dropbear <<EOT
# the TCP port that Dropbear listens on
DROPBEAR_PORT=22
# any additional arguments for Dropbear
DROPBEAR_EXTRA_ARGS=
# specify an optional banner file containing a message to be
# sent to clients before they connect, such as "/etc/issue.net"
DROPBEAR_BANNER=""
# RSA hostkey file (default: /etc/dropbear/dropbear_rsa_host_key)
#DROPBEAR_RSAKEY="/etc/dropbear/dropbear_rsa_host_key"
# DSS hostkey file (default: /etc/dropbear/dropbear_dss_host_key)
#DROPBEAR_DSSKEY="/etc/dropbear/dropbear_dss_host_key"
EOT
fi
if test -x /etc/init.d/dropbear; then
update-rc.d dropbear defaults >/dev/null
if test -x /usr/sbin/invoke-rc.d; then
invoke-rc.d dropbear start
else
/etc/init.d/dropbear start
fi
fi

12
debian/dropbear.postrm vendored Normal file
View File

@@ -0,0 +1,12 @@
#! /bin/sh
set -e
test "$1" = 'purge' || exit 0
if test -e /etc/dropbear; then
rm -f /etc/dropbear/dropbear_rsa_host_key
rm -f /etc/dropbear/dropbear_dss_host_key
rmdir --ignore-fail-on-non-empty /etc/dropbear
fi
update-rc.d dropbear remove >/dev/null
rm -f /etc/default/dropbear
rm -rf /etc/dropbear/supervise /etc/dropbear/log/supervise

11
debian/dropbear.prerm vendored Normal file
View File

@@ -0,0 +1,11 @@
#!/bin/sh
set -u
test "$1" = 'remove' || test "$1" = 'deconfigure' || exit 0
if test -x /etc/init.d/dropbear; then
if test -x /usr/sbin/invoke-rc.d; then
invoke-rc.d dropbear stop
else
/etc/init.d/dropbear stop
fi
fi

79
debian/implicit vendored Normal file
View File

@@ -0,0 +1,79 @@
# $Id: implicit,v 1.1 2004/06/16 05:08:32 matt Exp $
.PHONY: deb-checkdir deb-checkuid
deb-checkdir:
@test -e debian/control || sh -cx '! : wrong directory'
deb-checkuid:
@test "`id -u`" -eq 0 || sh -cx '! : need root privileges'
%.deb: %.deb-docs %.deb-DEBIAN
@rm -f $*.deb $*.deb-checkdir $*.deb-docs $*.deb-docs-base \
$*.deb-docs-docs $*.deb-docs-examples $*.deb-DEBIAN \
$*.deb-DEBIAN-dir $*.deb-DEBIAN-scripts $*.deb-DEBIAN-md5sums
%.deb-checkdir:
@test -d debian/$* || sh -cx '! : directory debian/$* missing'
@test "`id -u`" -eq 0 || sh -cx '! : need root privileges'
%.deb-docs-base:
: implicit
@rm -f debian/$*/usr/share/doc/$*/* || :
@install -d -m0755 debian/$*/usr/share/doc/$*
: debian/$*/usr/share/doc/$*/
@sh -cx 'install -m0644 debian/copyright debian/$*/usr/share/doc/$*/'
@sh -cx 'install -m0644 debian/changelog \
debian/$*/usr/share/doc/$*/changelog.Debian'
@test ! -r changelog || \
sh -cx 'install -m0644 changelog debian/$*/usr/share/doc/$*/'
@test -r debian/$*/usr/share/doc/$*/changelog || \
sh -cx 'mv debian/$*/usr/share/doc/$*/changelog.Debian \
debian/$*/usr/share/doc/$*/changelog'
@gzip -9 debian/$*/usr/share/doc/$*/changelog*
%.deb-docs-docs:
@for i in `cat debian/$*.docs 2>/dev/null || :`; do \
sh -cx "install -m0644 $$i debian/$*/usr/share/doc/$*/" || exit 1; \
done
@test ! -r debian/$*.README.Debian || \
sh -cx 'install -m0644 debian/$*.README.Debian \
debian/$*/usr/share/doc/$*/README.Debian'
@if test -r debian/$*.NEWS.Debian; then \
sh -cx 'install -m0644 debian/$*.NEWS.Debian \
debian/$*/usr/share/doc/$*/NEWS.Debian && \
gzip -9 debian/$*/usr/share/doc/$*/NEWS.Debian'; \
fi
%.deb-docs-examples:
@rm -rf debian/$*/usr/share/doc/$*/examples
: debian/$*/usr/share/doc/$*/examples/
@test ! -r debian/$*.examples || \
install -d -m0755 debian/$*/usr/share/doc/$*/examples
@for i in `cat debian/$*.examples 2>/dev/null || :`; do \
sh -cx "install -m0644 $$i debian/$*/usr/share/doc/$*/examples/" \
|| exit 1; \
done
%.deb-docs: %.deb-checkdir %.deb-docs-base %.deb-docs-docs %.deb-docs-examples
: debian/$*/usr/share/doc/$*/ ok
%.deb-DEBIAN-base:
@rm -rf debian/$*/DEBIAN
: debian/$*/DEBIAN/
@install -d -m0755 debian/$*/DEBIAN
@for i in conffiles shlibs; do \
test ! -r debian/$*.$$i || \
sh -cx "install -m0644 debian/$*.$$i debian/$*/DEBIAN/$$i" \
|| exit 1; \
done
%.deb-DEBIAN-scripts:
@for i in preinst prerm postinst postrm; do \
test ! -r debian/$*.$$i || \
sh -cx "install -m0755 debian/$*.$$i debian/$*/DEBIAN/$$i" \
|| exit 1; \
done
%.deb-DEBIAN-md5sums:
: debian/$*/DEBIAN/md5sums
@rm -f debian/$*/DEBIAN/md5sums
@cd debian/$* && find * -path 'DEBIAN' -prune -o \
-type f -exec md5sum {} >>DEBIAN/md5sums \;
%.deb-DEBIAN: %.deb-checkdir %.deb-DEBIAN-base %.deb-DEBIAN-scripts \
%.deb-DEBIAN-md5sums
: debian/$*/DEBIAN/ ok

90
debian/postinst vendored
View File

@@ -1,90 +0,0 @@
#! /bin/sh
# postinst script for #PACKAGE#
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
# <failed-install-package> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
#
# quoting from the policy:
# Any necessary prompting should almost always be confined to the
# post-installation script, and should be protected with a conditional
# so that unnecessary prompting doesn't happen if a package's
# installation fails and the `postinst' is called with `abort-upgrade',
# `abort-remove' or `abort-deconfigure'.
case "$1" in
configure)
if [ ! -e /etc/dropbear/dropbear_rsa_host_key ]; then
if [ -f /etc/ssh/ssh_host_rsa_key ]; then
echo "Converting existing OpenSSH RSA host key to Dropbear format."
/usr/bin/dropbearconvert openssh dropbear /etc/ssh/ssh_host_rsa_key /etc/dropbear/dropbear_rsa_host_key
else
echo "Generating Dropbear RSA key. Please wait."
/usr/bin/dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
fi
fi
if [ ! -e /etc/dropbear/dropbear_dss_host_key ]; then
if [ -f /etc/ssh/ssh_host_dsa_key ]; then
echo "Converting existing OpenSSH RSA host key to Dropbear format."
/usr/bin/dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key /etc/dropbear/dropbear_dss_host_key
else
echo "Generating Dropbear DSS key. Please wait."
/usr/bin/dropbearkey -t dss -f /etc/dropbear/dropbear_dss_host_key
fi
fi
if [ ! -s /etc/default/dropbear ]; then
# check whether OpenSSH seems to be installed.
if dpkg -l ssh >/dev/null 2>&1; then
echo "OpenSSH appears to be installed. Setting /etc/default/dropbear"
echo "so that Dropbear will not start by default. Edit this file to change"
echo "this behaviour."
echo "# disabled because OpenSSH is installed, change to NO_START=0 to enable Dropbear" > /etc/default/dropbear
echo "NO_START=1" >> /etc/default/dropbear
fi
echo "# the TCP port that Dropbear listens on" >> /etc/default/dropbear
echo "DROPBEAR_PORT=22" >> /etc/default/dropbear
echo "# any additional arguments for Dropbear" >> /etc/default/dropbear
echo "DROPBEAR_EXTRA_ARGS=" >> /etc/default/dropbear
echo "# specify an optional banner file containing a message to be" >> /etc/default/dropbear
echo "# sent to clients before they connect, such as \"/etc/issue.net\"" >> /etc/default/dropbear
echo "DROPBEAR_BANNER=\"\"" >> /etc/default/dropbear
echo "# RSA hostkey file (default: /etc/dropbear/dropbear_rsa_host_key" >> /etc/default/dropbear
echo "#DROPBEAR_RSAKEY=\"/etc/dropbear/dropbear_rsa_host_key\"" >> /etc/default/dropbear
echo "# DSS hostkey file (default: /etc/dropbear/dropbear_dss_host_key" >> /etc/default/dropbear
echo "#DROPBEAR_DSSKEY=\"/etc/dropbear/dropbear_dss_host_key\"" >> /etc/default/dropbear
fi
if [ -e /etc/init.d/dropbear ]; then
update-rc.d dropbear defaults >/dev/null
/etc/init.d/dropbear restart
fi
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
exit 0

45
debian/postrm vendored
View File

@@ -1,45 +0,0 @@
#! /bin/sh
# postrm script for #PACKAGE#
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postrm> `remove'
# * <postrm> `purge'
# * <old-postrm> `upgrade' <new-version>
# * <new-postrm> `failed-upgrade' <old-version>
# * <new-postrm> `abort-install'
# * <new-postrm> `abort-install' <old-version>
# * <new-postrm> `abort-upgrade' <old-version>
# * <disappearer's-postrm> `disappear' <r>overwrit>r> <new-version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
if [ "$1" = "purge" ]
then
if [ -e /etc/dropbear ]; then
rm -f /etc/dropbear/dropbear_rsa_host_key
rm -f /etc/dropbear/dropbear_dss_host_key
rmdir --ignore-fail-on-non-empty /etc/dropbear
fi
update-rc.d dropbear remove >/dev/null
fi
;;
*)
echo "postrm called with unknown argument \`$1'" >&2
exit 1
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

199
debian/rules vendored
View File

@@ -1,134 +1,97 @@
#!/usr/bin/make -f
# Sample debian/rules that uses debhelper.
# GNU copyright 1997 to 1999 by Joey Hess.
#
# Modified to make a template file for a multi-binary package with separated
# build-arch and build-indep targets by Bill Allombert 2001
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
#export DH_OPTIONS
DEB_HOST_GNU_TYPE ?=$(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
DEB_BUILD_GNU_TYPE ?=$(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
# This has to be exported to make some magic below work.
export DH_OPTIONS
# These are used for cross-compiling and for saving the configure script
# from having to guess our platform (since we know it already)
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
CFLAGS = -Wall -g
STRIP =strip
ifneq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
STRIP =: nostrip
endif
CFLAGS =-Wall -g
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
CFLAGS += -O0
CFLAGS +=-O0
else
CFLAGS += -O2
endif
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
INSTALL_PROGRAM += -s
CFLAGS +=-O2
endif
config.status: configure
dh_testdir
# Add here commands to configure the package.
CFLAGS='-DSFTPSERVER_PATH="\"/usr/lib/sftp-server\""' ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info
#Architecture
build: build-arch #build-indep
build-arch: build-arch-stamp
build-arch-stamp: config.status
# Add here commands to compile the arch part of the package.
$(MAKE) CC=gcc LD=gcc
build-indep: build-indep-stamp
build-indep-stamp: config.status
# Add here commands to compile the indep part of the package.
#$(MAKE) doc
clean:
dh_testdir
dh_testroot
rm -f build-arch-stamp build-indep-stamp config-stamp
# Add here commands to clean up after the build process.
-$(MAKE) clean
ifneq "$(wildcard /usr/share/misc/config.sub)" ""
cp -f /usr/share/misc/config.sub config.sub
endif
ifneq "$(wildcard /usr/share/misc/config.guess)" ""
cp -f /usr/share/misc/config.guess config.guess
CC =gcc
ifneq (,$(findstring diet,$(DEB_BUILD_OPTIONS)))
CC =diet -v -Os gcc
endif
dh_clean
DIR=`pwd`/debian/dropbear
install: install-indep install-arch
install-indep:
dh_testdir
dh_testroot
dh_clean -k -i
dh_installdirs -i
# Add here commands to install the indep part of the package into
# debian/<package>-doc.
#INSTALLDOC#
dh_install -i
patch: deb-checkdir patch-stamp
patch-stamp:
# no patches for now
# for i in debian/diff/*.diff; do patch -p0 <$$i || exit 1; done
touch patch-stamp
install-arch:
dh_testdir
dh_testroot
dh_clean -k -a
dh_installdirs -a
dh_installdirs /etc/dropbear
config.status: patch-stamp configure
CFLAGS="$(CFLAGS)"' -DSFTPSERVER_PATH="\"/usr/lib/sftp-server\""' \
./configure --host="$(DEB_HOST_GNU_TYPE)" \
--build="$(DEB_BUILD_GNU_TYPE)" --prefix=/usr \
--mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info
# Add here commands to install the arch part of the package into
# debian/tmp.
$(MAKE) install prefix=$(CURDIR)/debian/dropbear/usr
build: deb-checkdir build-stamp
build-stamp: config.status
$(MAKE) CC="$(CC)" LD="$(CC)"
touch build-stamp
dh_install -a
# Must not depend on anything. This is to be called by
# binary-arch/binary-multi
# in another 'make' thread.
binary-common:
cat $(CURDIR)/debian/copyright.in $(CURDIR)/LICENSE > $(CURDIR)/debian/copyright
dh_testdir
dh_testroot
dh_installchangelogs CHANGES
dh_installdocs
dh_installexamples
# dh_installmenu
# dh_installdebconf
# dh_installlogrotate
# dh_installemacsen
# dh_installpam
# dh_installmime
dh_installinit
# dh_installcron
# dh_installinfo
dh_installman
dh_link
dh_strip
dh_compress
dh_fixperms
# dh_perl
# dh_python
dh_makeshlibs
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
# Build architecture independant packages using the common target.
binary-indep: build-indep install-indep
$(MAKE) -f debian/rules DH_OPTIONS=-i binary-common
clean: deb-checkdir deb-checkuid
-$(MAKE) distclean
# test ! -e patch-stamp || \
# for i in debian/diff/*.diff; do patch -p0 -R <$$i; done
rm -f patch-stamp build-stamp config.log config.status
rm -rf "$(DIR)"
rm -f debian/files debian/substvars debian/copyright changelog
# Build architecture dependant packages using the common target.
binary-arch: build-arch install-arch
$(MAKE) -f debian/rules DH_OPTIONS=-a binary-common
install: deb-checkdir deb-checkuid build-stamp
rm -rf "$(DIR)"
install -d -m0755 "$(DIR)"/etc/dropbear
# programs
install -d -m0755 "$(DIR)"/usr/sbin
install -m0755 dropbear "$(DIR)"/usr/sbin/dropbear
install -d -m0755 "$(DIR)"/usr/bin
install -m0755 dbclient "$(DIR)"/usr/bin/dbclient
install -m0755 dropbearkey "$(DIR)"/usr/bin/dropbearkey
install -d -m0755 "$(DIR)"/usr/lib/dropbear
install -m0755 dropbearconvert \
"$(DIR)"/usr/lib/dropbear/dropbearconvert
$(STRIP) -R .comment -R .note "$(DIR)"/usr/sbin/* \
"$(DIR)"/usr/bin/* "$(DIR)"/usr/lib/dropbear/*
# init and run scripts
install -d -m0755 "$(DIR)"/etc/init.d
install -m0755 debian/dropbear.init "$(DIR)"/etc/init.d/dropbear
install -m0755 debian/service/run "$(DIR)"/etc/dropbear/run
install -d -m0755 "$(DIR)"/etc/dropbear/log
install -m0755 debian/service/log "$(DIR)"/etc/dropbear/log/run
ln -s /var/log/dropbear "$(DIR)"/etc/dropbear/log/main
ln -s /var/run/dropbear "$(DIR)"/etc/dropbear/supervise
ln -s /var/run/dropbear.log "$(DIR)"/etc/dropbear/log/supervise
# man pages
install -d -m0755 "$(DIR)"/usr/share/man/man8
for i in dropbear.8 dropbearkey.8; do \
install -m644 $$i "$(DIR)"/usr/share/man/man8/ || exit 1; \
done
gzip -9 "$(DIR)"/usr/share/man/man8/*.8
# copyright, changelog
cat debian/copyright.in LICENSE >debian/copyright
ln -s CHANGES changelog
binary: binary-arch #binary-indep
.PHONY: build clean binary-indep binary-arch binary install install-indep install-arch
binary-indep:
binary-arch: install dropbear.deb
test "$(CC)" != 'gcc' || \
dpkg-shlibdeps "$(DIR)"/usr/sbin/* "$(DIR)"/usr/bin/* \
"$(DIR)"/usr/lib/dropbear/*
dpkg-gencontrol -isp -pdropbear -P"$(DIR)"
dpkg -b "$(DIR)" ..
binary: binary-arch binary-indep
.PHONY: patch build clean install binary-indep binary-arch binary
include debian/implicit

2
debian/service/log vendored Normal file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
exec chpst -udropbearlog svlogd -tt ./main

3
debian/service/run vendored Normal file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
exec 2>&1
exec dropbear -d ./dropbear_dss_host_key -r ./dropbear_rsa_host_key -F -E -p 22

12
debug.h
View File

@@ -33,10 +33,13 @@
* etc. Don't use this normally, it might cause problems */
/* #define DEBUG_VALGRIND */
/* 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 this to compile in trace debugging printf()s.
* You'll need to run programs with "-v" to turn this on.
*
* 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 */
/* All functions writing to the cleartext payload buffer call
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're
@@ -47,6 +50,7 @@
/* Define this, compile with -pg and set GMON_OUT_PREFIX=gmon to get gmon
* output when Dropbear forks. This will allow it gprof to be used.
* It's useful to run dropbear -F, so you don't fork as much */
/* (This is Linux specific) */
/*#define DEBUG_FORKGPROF*/
/* A couple of flags, not usually useful, and mightn't do anything */

View File

@@ -47,10 +47,8 @@ static void printhelp(char * progname) {
"dropbear\n"
"\n"
"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"
"standard input or standard output.\n", progname);
"dropbearconvert openssh dropbear /etc/ssh/ssh_host_rsa_key /etc/dropbear_rsa_host_key\n",
progname);
}
#if defined(DBMULTI_dropbearconvert) || !defined(DROPBEAR_MULTI)
@@ -64,6 +62,11 @@ int main(int argc, char ** argv) {
const char* infile;
const char* outfile;
#ifdef DEBUG_TRACE
/* It's hard for it to get in the way _too_ much */
debug_trace = 1;
#endif
/* get the commandline options */
if (argc != 5) {
fprintf(stderr, "All arguments must be specified\n");

View File

@@ -45,7 +45,6 @@
*
*/
#include "includes.h"
#include "runopts.h"
#include "signkey.h"
#include "buffer.h"
#include "dbutil.h"
@@ -55,29 +54,32 @@
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 <type> -f <filename> [-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",
progname);
"-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 <filename>.\n"
#ifdef DEBUG_TRACE
"-v verbose\n"
#endif
,progname);
}
#if defined(DBMULTI_dropbearkey) || !defined(DROPBEAR_MULTI)
@@ -89,23 +91,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;
}
@@ -120,10 +123,18 @@ int main(int argc, char ** argv) {
case 's':
next = &sizetext;
break;
case 'y':
printpub = 1;
break;
case 'h':
printhelp(argv[0]);
exit(EXIT_SUCCESS);
break;
#ifdef DEBUG_TRACE
case 'v':
debug_trace = 1;
break;
#endif
default:
fprintf(stderr, "Unknown argument %s\n", argv[i]);
printhelp(argv[0]);
@@ -133,17 +144,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);
}
@@ -191,11 +205,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);
@@ -223,7 +232,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);
@@ -231,14 +240,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) {

20
dss.c
View File

@@ -164,13 +164,18 @@ int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
unsigned char msghash[SHA1_HASH_SIZE];
hash_state hs;
int ret = DROPBEAR_FAILURE;
mp_int val1, val2, val3, val4;
DEF_MP_INT(val1);
DEF_MP_INT(val2);
DEF_MP_INT(val3);
DEF_MP_INT(val4);
char * string = NULL;
int stringlen;
TRACE(("enter buf_dss_verify"));
assert(key != NULL);
m_mp_init_multi(&val1, &val2, &val3, &val4, NULL);
/* get blob, check length */
string = buf_getstring(buf, &stringlen);
if (stringlen != 2*SHA1_HASH_SIZE) {
@@ -182,8 +187,6 @@ int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
sha1_process(&hs, data, len);
sha1_done(&hs, msghash);
m_mp_init_multi(&val1, &val2, &val3, &val4, NULL);
/* create the signature - s' and r' are the received signatures in buf */
/* w = (s')-1 mod q */
/* let val1 = s' */
@@ -281,13 +284,16 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
unsigned char privkeyhash[SHA512_HASH_SIZE];
unsigned char *privkeytmp;
unsigned char proto_k[SHA512_HASH_SIZE];
mp_int dss_protok;
DEF_MP_INT(dss_protok);
#else
unsigned char kbuf[SHA1_HASH_SIZE];
#endif
mp_int dss_k, dss_m;
mp_int dss_temp1, dss_temp2;
mp_int dss_r, dss_s;
DEF_MP_INT(dss_k);
DEF_MP_INT(dss_m);
DEF_MP_INT(dss_temp1);
DEF_MP_INT(dss_temp2);
DEF_MP_INT(dss_r);
DEF_MP_INT(dss_s);
hash_state hs;
TRACE(("enter buf_put_dss_sign"));

227
fake-rfc2553.c Normal file
View File

@@ -0,0 +1,227 @@
/*
*
* Taken from OpenSSH 3.8.1p1
*
* 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 */

162
fake-rfc2553.h Normal file
View File

@@ -0,0 +1,162 @@
/* 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.
* 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"
/*
* 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 */

View File

@@ -1,3 +1,7 @@
This file is out of date - it remains here in case it is still of use.
The basic naming convention is svr- and cli- for seperate parts,
then common- for common parts. Some files have no prefix.
A brief rundown on which files do what, and their corresponding sections
in the IETF drafts. The .c files usually have corresponding .h files.

View File

@@ -31,9 +31,10 @@
#include "gendss.h"
#include "dss.h"
#define PSIZE 128 /* 1024 bit*/
#define QSIZE 20 /* 160 bit */
/* This is just a test */
#ifdef DROPBEAR_DSS
static void getq(dss_key *key);
@@ -90,7 +91,10 @@ static void getq(dss_key *key) {
static void getp(dss_key *key, unsigned int size) {
mp_int tempX, tempC, tempP, temp2q;
DEF_MP_INT(tempX);
DEF_MP_INT(tempC);
DEF_MP_INT(tempP);
DEF_MP_INT(temp2q);
int result;
unsigned char *buf;
@@ -148,8 +152,9 @@ static void getp(dss_key *key, unsigned int size) {
static void getg(dss_key * key) {
char printbuf[1000];
mp_int div, h, val;
DEF_MP_INT(div);
DEF_MP_INT(h);
DEF_MP_INT(val);
m_mp_init_multi(&div, &h, &val, NULL);
@@ -179,14 +184,12 @@ static void getg(dss_key * key) {
} while (mp_cmp_d(key->g, 1) != MP_GT);
mp_toradix(key->g, printbuf, 10);
mp_clear_multi(&div, &h, &val, NULL);
}
static void getx(dss_key *key) {
mp_int val;
DEF_MP_INT(val);
char buf[QSIZE];
m_mp_init(&val);

View File

@@ -40,7 +40,9 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
rsa_key * gen_rsa_priv_key(unsigned int size) {
rsa_key * key;
mp_int pminus, qminus, lcm;
DEF_MP_INT(pminus);
DEF_MP_INT(qminus);
DEF_MP_INT(lcm);
key = (rsa_key*)m_malloc(sizeof(rsa_key));
@@ -95,7 +97,7 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
mp_int* rsa_e, unsigned int size) {
unsigned char *buf;
mp_int temp_gcd;
DEF_MP_INT(temp_gcd);
buf = (unsigned char*)m_malloc(size+1);

View File

@@ -38,7 +38,6 @@
#include <sys/time.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <sys/dir.h>
#include <stdio.h>
#include <errno.h>
@@ -56,6 +55,7 @@
#include <netdb.h>
#include <ctype.h>
#include <stdarg.h>
#include <dirent.h>
#include <arpa/inet.h>
@@ -111,14 +111,11 @@
#include <libgen.h>
#endif
#ifdef HAVE_SYS_DIRENT_H
#include <sys/dirent.h>
#endif
#include "libtomcrypt/mycrypt_custom.h"
#include "libtommath/tommath.h"
#include "compat.h"
#include "fake-rfc2553.h"
#ifndef HAVE_UINT16_T
#ifndef HAVE_U_INT16_T
@@ -131,4 +128,14 @@ typedef u_int16_t uint16_t;
#define LOG_AUTHPRIV LOG_AUTH
#endif
/* so we can avoid warnings about unused params (ie in signal handlers etc) */
#ifdef UNUSED
#elif defined(__GNUC__)
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
#elif defined(__LCLINT__)
# define UNUSED(x) /*@unused@*/ x
#else
# define UNUSED(x) x
#endif
#endif /* _INCLUDES_H_ */

View File

@@ -108,30 +108,14 @@ int import_write(const char *filename, sign_key *key, char *passphrase,
static sign_key *dropbear_read(const char* filename) {
buffer * buf = NULL;
int len, maxlen;
FILE *fp;
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);
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,14 +157,10 @@ 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] == '-') {
fp = stdout;
} else {
fp = fopen(filename, "w");
}
fp = fopen(filename, "w");
if (!fp) {
ret = 0;
goto out;

View File

@@ -1,3 +1,27 @@
/*
* Dropbear SSH
*
* 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 _KEYIMPORT_H_
#define _KEYIMPORT_H_

View File

@@ -1,3 +1,27 @@
/*
* Dropbear SSH
*
* 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 "listener.h"
#include "session.h"
@@ -14,15 +38,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,26 +55,30 @@ 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->acceptor(listener, sock);
}
}
}
}
}
} /* Woo brace matching */
/* accepter(int fd, void* typedata) is a function to accept connections,
/* acceptor(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 (*acceptor)(struct Listener* listener, int sock),
void (*cleanup)(struct Listener*)) {
unsigned int i, j;
@@ -65,7 +94,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,16 +111,19 @@ 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->accepter = accepter;
newlisten->nsocks = nsocks;
memcpy(newlisten->socks, socks, nsocks * sizeof(int));
newlisten->acceptor = acceptor;
newlisten->cleanup = cleanup;
ses.listeners[i] = newlisten;
@@ -116,11 +150,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);

View File

@@ -1,3 +1,27 @@
/*
* Dropbear SSH
*
* 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 _LISTENER_H
#define _LISTENER_H
@@ -6,11 +30,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 (*acceptor)(struct Listener*, int sock);
void (*cleanup)(struct Listener*);
int type; /* CHANNEL_ID_X11, CHANNEL_ID_AGENT,
@@ -25,8 +50,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 (*acceptor)(struct Listener* listener, int sock),
void (*cleanup)(struct Listener*));
struct Listener * get_listener(int type, void* typedata,

View File

@@ -1,26 +1,6 @@
/*
* Dropbear - a SSH2 server
*
/* Dropbear SSH
* 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. */
* All rights reserved. See LICENSE for the license. */
#ifndef _OPTIONS_H_
#define _OPTIONS_H_
@@ -30,8 +10,8 @@
* parts are to allow for commandline -DDROPBEAR_XXX options etc.
******************************************************************/
#ifndef DROPBEAR_PORT
#define DROPBEAR_PORT 22
#ifndef DROPBEAR_DEFPORT
#define DROPBEAR_DEFPORT "22"
#endif
/* Default hostkey paths - these can be specified on the command line */
@@ -42,21 +22,43 @@
#define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key"
#endif
/* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens
* on chosen ports and keeps accepting connections. This is the default.
*
* Set INETD_MODE if you want to be able to run Dropbear with inetd (or
* similar), where it will use stdin/stdout for connections, and each process
* lasts for a single connection. Dropbear should be invoked with the -i flag
* for inetd, and can only accept IPv4 connections.
*
* Both of these flags can be defined at once, don't compile without at least
* one of them. */
#define NON_INETD_MODE
#define INETD_MODE
/* Setting this disables the fast exptmod bignum code. It saves ~5kB, but is
* perhaps 20% slower for pubkey operations (it is probably worth experimenting
* if you want to use this) */
/*#define NO_FAST_EXPTMOD*/
/* Enable X11 Forwarding */
/* Set this if you want to use the DROPBEAR_SMALL_CODE option. This can save
several kB in binary size, however will make the symmetrical ciphers (AES, DES
etc) slower (perhaps by 50%). Recommended for most small systems. */
#define DROPBEAR_SMALL_CODE
/* Enable X11 Forwarding - server only */
#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
/* 'Local' is "-L" style (client listening port forwarded via server)
* 'Remote' is "-R" style (server listening port forwarded via client) */
/* Enable Authentication Agent Forwarding */
#define ENABLE_CLI_LOCALTCPFWD
#define ENABLE_CLI_REMOTETCPFWD
#define ENABLE_SVR_LOCALTCPFWD
#define ENABLE_SVR_REMOTETCPFWD
/* Enable Authentication Agent Forwarding - server only for now */
#define ENABLE_AGENTFWD
/* Encryption - at least one required.
@@ -115,9 +117,14 @@
* to make sure PAM libraries etc are installed */
#define DROPBEAR_PAM_AUTH
#define DROPBEAR_PUBKEY_AUTH
#define ENABLE_SVR_PASSWORD_AUTH
#define ENABLE_SVR_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
* DEV_URANDOM is recommended on hosts with a good /dev/urandom, otherwise use
* PRNGD and run prngd, specifying the socket. This device must be able to
* produce a large amount of random data, so using /dev/random or Entropy
* Gathering Daemon (egd) may result in halting, as it waits for more random
@@ -136,7 +143,7 @@
#define MAX_UNAUTH_CLIENTS 30
#endif
/* Maximum number of failed authentication tries */
/* Maximum number of failed authentication tries (server option) */
#ifndef MAX_AUTH_TRIES
#define MAX_AUTH_TRIES 10
#endif
@@ -159,8 +166,9 @@
#define SFTPSERVER_PATH "/usr/libexec/sftp-server"
#endif
/* This is used by the scp binary when used as a client binary */
#define _PATH_SSH_PROGRAM "/usr/bin/ssh"
/* This is used by the scp binary when used as a client binary. If you're
* not using the Dropbear client, you'll need to change it */
#define _PATH_SSH_PROGRAM "/usr/bin/dbclient"
/* Multi-purpose binary configuration has now moved. Look at the top
* of the Makefile for instructions, or INSTALL */
@@ -170,7 +178,7 @@
*******************************************************************/
#ifndef DROPBEAR_VERSION
#define DROPBEAR_VERSION "0.41-and-client"
#define DROPBEAR_VERSION "0.44test3"
#endif
#define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
@@ -236,7 +244,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
@@ -283,6 +291,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
@@ -299,12 +310,20 @@
#define DISABLE_REMOTETCPFWD
#endif
#if defined(ENABLE_CLI_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD)
#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
#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

View File

@@ -50,7 +50,7 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len);
void write_packet() {
int len, written;
buffer * writebuf;
buffer * writebuf = NULL;
TRACE(("enter write_packet"));
assert(!isempty(&ses.writequeue));
@@ -80,6 +80,7 @@ void write_packet() {
/* We've finished with the packet, free it */
dequeue(&ses.writequeue);
buf_free(writebuf);
writebuf = NULL;
} else {
/* More packet left to write, leave it in the queue for later */
buf_incrpos(writebuf, written);
@@ -503,6 +504,7 @@ void encrypt_packet() {
/* clearwritebuf is finished with */
buf_free(clearwritebuf);
clearwritebuf = NULL;
/* enqueue the packet for sending */
buf_setpos(writebuf, 0);

View File

@@ -60,7 +60,7 @@ static void readrand(unsigned char* buf, unsigned int buflen) {
#ifdef DROPBEAR_DEV_URANDOM
readfd = open(DEV_URANDOM, O_RDONLY);
if (!readfd) {
if (readfd < 0) {
dropbear_exit("couldn't open random device");
}
#endif
@@ -71,7 +71,8 @@ static void readrand(unsigned char* buf, unsigned int buflen) {
strlcpy(egdsock.sun_path, DROPBEAR_EGD_SOCKET,
sizeof(egdsock.sun_path));
if ((readfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
readfd = socket(PF_UNIX, SOCK_STREAM, 0);
if (readfd < 0) {
dropbear_exit("couldn't open random device");
}
/* todo - try various common locations */

21
rsa.c
View File

@@ -201,7 +201,8 @@ int buf_rsa_verify(buffer * buf, rsa_key *key, const unsigned char* data,
unsigned int len) {
unsigned int slen;
mp_int rsa_s, rsa_mdash;
DEF_MP_INT(rsa_s);
DEF_MP_INT(rsa_mdash);
mp_int *rsa_em = NULL;
int ret = DROPBEAR_FAILURE;
@@ -244,8 +245,11 @@ int buf_rsa_verify(buffer * buf, rsa_key *key, const unsigned char* data,
}
out:
mp_clear_multi(rsa_em, &rsa_mdash, &rsa_s, NULL);
m_free(rsa_em);
if (rsa_em) {
mp_clear(rsa_em);
m_free(rsa_em);
}
mp_clear_multi(&rsa_mdash, &rsa_s, NULL);
TRACE(("leave buf_rsa_verify: ret %d", ret));
return ret;
@@ -259,16 +263,17 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
unsigned int nsize, ssize;
unsigned int i;
mp_int rsa_s;
mp_int *rsa_em;
DEF_MP_INT(rsa_s);
mp_int *rsa_em = NULL;
TRACE(("enter buf_put_rsa_sign"));
assert(key != NULL);
rsa_em = rsa_pad_em(key, data, len);
/* the actual signing of the padded data */
m_mp_init(&rsa_s);
/* the actual signing of the padded data */
/* s = em^d mod n */
if (mp_exptmod(rsa_em, key->d, key->n, &rsa_s) != MP_OKAY) {
dropbear_exit("rsa error");
@@ -322,10 +327,10 @@ static mp_int * rsa_pad_em(rsa_key * key,
{0x00, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b,
0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14};
#define RSA_ASN1_MAGIC_LEN 16
buffer * rsa_EM;
buffer * rsa_EM = NULL;
hash_state hs;
unsigned int nsize;
mp_int * rsa_em;
mp_int * rsa_em = NULL;
assert(key != NULL);
assert(data != NULL);

View File

@@ -29,6 +29,7 @@
#include "signkey.h"
#include "buffer.h"
#include "auth.h"
#include "tcpfwd.h"
typedef struct runopts {
@@ -51,9 +52,11 @@ typedef struct svr_runopts {
int usingsyslog;
/* ports is an array of the portcount listening ports */
uint16_t *ports;
char *ports[DROPBEAR_MAX_PORTS];
unsigned int portcount;
int inetdmode;
/* Flags indicating whether to use ipv4 and ipv6 */
/* not used yet
int ipv4;
@@ -78,6 +81,7 @@ typedef struct svr_runopts {
extern svr_runopts svr_opts;
void svr_getopts(int argc, char ** argv);
void loadhostkeys();
/* Uncompleted XXX matt */
typedef struct cli_runopts {
@@ -90,8 +94,14 @@ typedef struct cli_runopts {
char *cmd;
int wantpty;
#ifdef ENABLE_CLI_PUBKEY_AUTH
struct PubkeyList *pubkeys; /* Keys to use for public-key auth */
#ifdef DROPBEAR_PUBKEY_AUTH
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
struct TCPFwdList * remotefwds;
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
struct TCPFwdList * localfwds;
#endif
/* XXX TODO */

6
scp.c
View File

@@ -178,8 +178,10 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
close(pout[1]);
args.list[0] = ssh_program;
if (remuser != NULL)
addargs(&args, "-l%s", remuser);
if (remuser != NULL) {
addargs(&args, "-l");
addargs(&args, "%s", remuser);
}
addargs(&args, "%s", host);
addargs(&args, "%s", cmd);

View File

@@ -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;
@@ -42,7 +43,6 @@ extern int exitflag;
void common_session_init(int sock, char* remotehost);
void session_loop(void(*loophandler)());
void common_session_cleanup();
void checktimeouts();
void session_identification();
@@ -53,8 +53,6 @@ void svr_dropbear_log(int priority, const char* format, va_list param);
/* Client */
void cli_session(int sock, char *remotehost);
void cli_dropbear_exit(int exitcode, const char* format, va_list param);
void cli_dropbear_log(int priority, const char* format, va_list param);
void cli_session_cleanup();
void cleantext(unsigned char* dirtytext);
@@ -211,12 +209,16 @@ struct clientsession {
int tty_raw_mode; /* Whether we're in raw mode (and have to clean up) */
struct termios saved_tio;
int stdincopy;
int stdinflags;
int winchange; /* Set to 1 when a windowchange signal happens */
int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
for the last type of auth we tried */
struct PubkeyList *lastpubkey;
int retval; /* What the command exit status was - we emulate it */
#if 0
TODO
struct AgentkeyList *agentkeys; /* Keys to use for public-key auth */

View File

@@ -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;
}
@@ -194,7 +195,7 @@ void buf_put_pub_key(buffer* buf, sign_key *key, int type) {
buffer *pubkeys;
TRACE(("enter buf_put_pub_key"));
pubkeys = buf_new(1000);
pubkeys = buf_new(MAX_PUBKEY_SIZE);
#ifdef DROPBEAR_DSS
if (type == DROPBEAR_SIGNKEY_DSS) {
@@ -356,7 +357,7 @@ void buf_put_sign(buffer* buf, sign_key *key, int type,
buffer *sigblob;
sigblob = buf_new(1000);
sigblob = buf_new(MAX_PUBKEY_SIZE);
#ifdef DROPBEAR_DSS
if (type == DROPBEAR_SIGNKEY_DSS) {

View File

@@ -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 */
@@ -64,7 +64,7 @@ int agentreq(struct ChanSess * chansess) {
/* create the unix socket dir and file */
if (bindagent(fd, chansess) == DROPBEAR_FAILURE) {
return DROPBEAR_FAILURE;
goto fail;
}
/* listen */
@@ -73,12 +73,10 @@ int agentreq(struct ChanSess * chansess) {
}
/* set non-blocking */
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
goto fail;
}
setnonblocking(fd);
/* 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 +95,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 *UNUSED(listener), int sock) {
int fd;
fd = accept(listener->sock, NULL, NULL);
fd = accept(sock, NULL, NULL);
if (fd < 0) {
TRACE(("accept failed"));
return;
@@ -146,7 +144,7 @@ void agentcleanup(struct ChanSess * chansess) {
chansess->agentlistener = NULL;
}
if (chansess->agentfile && chansess->agentdir) {
if (chansess->agentfile != NULL && chansess->agentdir != NULL) {
/* Remove the dir as the user. That way they can't cause problems except
* for themselves */

View File

@@ -1,3 +1,29 @@
/*
* Dropbear - a SSH2 server
* SSH client implementation
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* 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 "algo.h"
#include "dbutil.h"

View File

@@ -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,11 @@ 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
#if defined(DROPBEAR_PASSWORD_AUTH) || defined(DROPBEAR_PAM_AUTH)
#ifdef ENABLE_SVR_PASSWORD_AUTH
if (!svr_opts.noauthpass) {
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD;
}
@@ -93,7 +92,7 @@ static void send_msg_userauth_banner() {
* checking, and handle success or failure */
void recv_msg_userauth_request() {
unsigned char *username, *servicename, *methodname;
unsigned char *username = NULL, *servicename = NULL, *methodname = NULL;
unsigned int userlen, servicelen, methodlen;
TRACE(("enter recv_msg_userauth_request"));
@@ -143,7 +142,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 */
@@ -169,7 +168,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,
@@ -290,7 +289,7 @@ goodshell:
* failures */
void send_msg_userauth_failure(int partial, int incrfail) {
buffer *typebuf;
buffer *typebuf = NULL;
TRACE(("enter send_msg_userauth_failure"));
@@ -355,6 +354,8 @@ void send_msg_userauth_success() {
encrypt_packet();
ses.authstate.authdone = 1;
ses.connecttimeout = 0;
if (ses.authstate.pw->pw_uid == 0) {
ses.allowprivport = 1;

View File

@@ -29,23 +29,22 @@
#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 */
void svr_auth_password() {
#ifdef HAVE_SHADOW_H
struct spwd *spasswd;
struct spwd *spasswd = NULL;
#endif
char * passwdcrypt; /* the crypt from /etc/passwd or /etc/shadow */
char * testcrypt; /* crypt generated from the user's password sent */
char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */
char * testcrypt = NULL; /* crypt generated from the user's password sent */
unsigned char * password;
unsigned int passwordlen;
unsigned char changepw;
unsigned int changepw;
passwdcrypt = ses.authstate.pw->pw_passwd;
#ifdef HAVE_SHADOW_H
@@ -105,4 +104,4 @@ void svr_auth_password() {
}
#endif /* DROPBEAR_PASSWORD_AUTH */
#endif

View File

@@ -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 */
@@ -54,7 +53,7 @@ void svr_auth_pubkey() {
unsigned char testkey; /* whether we're just checking if a key is usable */
unsigned char* algo = NULL; /* pubkey algo */
unsigned int algolen;
unsigned char* keyblob;
unsigned char* keyblob = NULL;
unsigned int keybloblen;
buffer * signbuf = NULL;
sign_key * key = NULL;
@@ -336,4 +335,4 @@ static int checkfileperm(char * filename) {
}
#endif /* DROPBEAR_PUBKEY_AUTH */
#endif

View File

@@ -55,6 +55,10 @@ static int newchansess(struct Channel *channel);
static void chansessionrequest(struct Channel *channel);
static void send_exitsignalstatus(struct Channel *channel);
static void send_msg_chansess_exitstatus(struct Channel * channel,
struct ChanSess * chansess);
static void send_msg_chansess_exitsignal(struct Channel * channel,
struct ChanSess * chansess);
static int sesscheckclose(struct Channel *channel);
static void get_termmodes(struct ChanSess *chansess);
@@ -68,7 +72,7 @@ static int sesscheckclose(struct Channel *channel) {
}
/* handler for childs exiting, store the state for return to the client */
static void sesssigchild_handler(int dummy) {
static void sesssigchild_handler(int UNUSED(dummy)) {
int status;
pid_t pid;
@@ -78,7 +82,6 @@ static void sesssigchild_handler(int dummy) {
TRACE(("enter sigchld handler"));
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
/* find the corresponding chansess */
for (i = 0; i < svr_ses.childpidsize; i++) {
if (svr_ses.childpids[i].pid == pid) {
@@ -90,8 +93,10 @@ static void sesssigchild_handler(int dummy) {
}
if (WIFSIGNALED(status)) {
chansess->exitsignal = WTERMSIG(status);
#ifndef AIX
#if !defined(AIX) && defined(WCOREDUMP)
chansess->exitcore = WCOREDUMP(status);
#else
chansess->exitcore = 0;
#endif
} else {
/* we use this to determine how pid exited */
@@ -273,7 +278,7 @@ static void closechansess(struct Channel *channel) {
* or x11/authagent forwarding. These are passed to appropriate handlers */
static void chansessionrequest(struct Channel *channel) {
unsigned char * type;
unsigned char * type = NULL;
unsigned int typelen;
unsigned char wantreply;
int ret = 1;
@@ -320,7 +325,7 @@ static void chansessionrequest(struct Channel *channel) {
out:
if (wantreply) {
if (ret == 0) {
if (ret == DROPBEAR_SUCCESS) {
send_msg_channel_success(channel);
} else {
send_msg_channel_failure(channel);
@@ -336,7 +341,7 @@ out:
static int sessionsignal(struct ChanSess *chansess) {
int sig = 0;
unsigned char* signame;
unsigned char* signame = NULL;
int i;
if (chansess->pid == 0) {
@@ -408,6 +413,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");
}
@@ -495,7 +502,9 @@ static int sessionpty(struct ChanSess * chansess) {
}
/* allocate the pty */
assert(chansess->master == -1); /* haven't already got one */
if (chansess->master != -1) {
dropbear_exit("multiple pty requests");
}
if (pty_allocate(&chansess->master, &chansess->slave, namebuf, 64) == 0) {
TRACE(("leave sessionpty: failed to allocate pty"));
return DROPBEAR_FAILURE;
@@ -526,11 +535,14 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
int iscmd, int issubsys) {
unsigned int cmdlen;
int ret;
TRACE(("enter sessioncommand"));
if (chansess->cmd != NULL) {
/* TODO - send error - multiple commands? */
/* Note that only one command can _succeed_. The client might try
* one command (which fails), then try another. Ie fallback
* from sftp to scp */
return DROPBEAR_FAILURE;
}
@@ -539,6 +551,7 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
chansess->cmd = buf_getstring(ses.payload, &cmdlen);
if (cmdlen > MAX_CMD_LEN) {
m_free(chansess->cmd);
/* TODO - send error - too long ? */
return DROPBEAR_FAILURE;
}
@@ -550,6 +563,7 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
} else
#endif
{
m_free(chansess->cmd);
return DROPBEAR_FAILURE;
}
}
@@ -557,11 +571,16 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
if (chansess->term == NULL) {
/* no pty */
return noptycommand(channel, chansess);
ret = noptycommand(channel, chansess);
} else {
/* want pty */
return ptycommand(channel, chansess);
ret = ptycommand(channel, chansess);
}
if (ret == DROPBEAR_FAILURE) {
m_free(chansess->cmd);
}
return ret;
}
/* Execute a command and set up redirection of stdin/stdout/stderr without a
@@ -616,7 +635,10 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) {
TRACE(("continue noptycommand: parent"));
chansess->pid = pid;
/* add a child pid */
/* add a child pid - Beware: there's a race between this, and the
* exec() called from the child. If the child finishes before we've
* done this (ie if it was a shell builtin and fast), we won't return a
* proper return code. For now, we ignore this case. */
addchildpid(chansess, pid);
close(infds[FDIN]);
@@ -629,11 +651,10 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) {
ses.maxfd = MAX(ses.maxfd, channel->outfd);
ses.maxfd = MAX(ses.maxfd, channel->errfd);
if ((fcntl(channel->outfd, F_SETFL, O_NONBLOCK) < 0) ||
(fcntl(channel->infd, F_SETFL, O_NONBLOCK) < 0) ||
(fcntl(channel->errfd, F_SETFL, O_NONBLOCK) < 0)) {
dropbear_exit("Couldn't set nonblocking");
}
setnonblocking(channel->outfd);
setnonblocking(channel->infd);
setnonblocking(channel->errfd);
}
#undef FDIN
#undef FDOUT
@@ -648,7 +669,7 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) {
static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
pid_t pid;
struct logininfo *li;
struct logininfo *li = NULL;
#ifdef DO_MOTD
buffer * motdbuf = NULL;
int len;
@@ -739,9 +760,7 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
/* don't need to set stderr here */
ses.maxfd = MAX(ses.maxfd, chansess->master);
if (fcntl(chansess->master, F_SETFL, O_NONBLOCK) < 0) {
dropbear_exit("Couldn't set nonblocking");
}
setnonblocking(chansess->master);
}
@@ -776,8 +795,8 @@ static void addchildpid(struct ChanSess *chansess, pid_t pid) {
static void execchild(struct ChanSess *chansess) {
char *argv[4];
char * usershell;
char * baseshell;
char * usershell = NULL;
char * baseshell = NULL;
unsigned int i;
/* wipe the hostkey */
@@ -861,6 +880,11 @@ static void execchild(struct ChanSess *chansess) {
agentset(chansess);
#endif
/* Re-enable SIGPIPE for the executed process */
if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) {
dropbear_exit("signal() error");
}
baseshell = basename(usershell);
if (chansess->cmd != NULL) {
@@ -919,7 +943,7 @@ void svr_chansessinitialise() {
/* add a new environment variable, allocating space for the entry */
void addnewvar(const char* param, const char* var) {
char* newvar;
char* newvar = NULL;
int plen, vlen;
plen = strlen(param);

View File

@@ -2,6 +2,7 @@
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -43,7 +44,7 @@ static void send_msg_kexdh_reply(mp_int *dh_e);
* that function, then brings the new keys into use */
void recv_msg_kexdh_init() {
mp_int dh_e;
DEF_MP_INT(dh_e);
TRACE(("enter recv_msg_kexdh_init"));
if (!ses.kexstate.recvkexinit) {
@@ -70,9 +71,11 @@ void recv_msg_kexdh_init() {
* See the ietf-secsh-transport draft, section 6, for details */
static void send_msg_kexdh_reply(mp_int *dh_e) {
mp_int dh_y, dh_f;
DEF_MP_INT(dh_y);
DEF_MP_INT(dh_f);
TRACE(("enter send_msg_kexdh_reply"));
m_mp_init_multi(&dh_y, &dh_f, NULL);
gen_kexdh_vals(&dh_f, &dh_y);

View File

@@ -29,10 +29,13 @@
#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);
static void main_inetd();
static void main_noinetd();
static void commonsetup();
static int childpipes[MAX_UNAUTH_CLIENTS];
@@ -44,22 +47,6 @@ 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;
@@ -67,6 +54,75 @@ int main(int argc, char ** argv)
/* get commandline options */
svr_getopts(argc, argv);
#ifdef INETD_MODE
/* service program mode */
if (svr_opts.inetdmode) {
main_inetd();
/* notreached */
}
#endif
#ifdef NON_INETD_MODE
main_noinetd();
/* notreached */
#endif
dropbear_exit("Compiled without normal mode, can't run without -i\n");
return -1;
}
#endif
#ifdef INETD_MODE
static void main_inetd() {
struct sockaddr_storage remoteaddr;
int remoteaddrlen;
char * addrstring = NULL;
/* Set up handlers, syslog */
commonsetup();
remoteaddrlen = sizeof(remoteaddr);
if (getpeername(0, (struct sockaddr*)&remoteaddr, &remoteaddrlen) < 0) {
dropbear_exit("Unable to getpeername: %s", strerror(errno));
}
/* In case our inetd was lax in logging source addresses */
addrstring = getaddrstring(&remoteaddr, 1);
dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
m_free(addrstring);
/* Don't check the return value - it may just fail since inetd has
* already done setsid() after forking (xinetd on Darwin appears to do
* this */
setsid();
/* Start service program
* -1 is a dummy childpipe, just something we can close() without
* mattering. */
svr_session(0, -1, getaddrhostname(&remoteaddr));
/* notreached */
}
#endif /* INETD_MODE */
#ifdef NON_INETD_MODE
void main_noinetd() {
fd_set fds;
struct timeval seltimeout;
unsigned int i, j;
int val;
int maxsock = -1;
struct sockaddr_storage remoteaddr;
int remoteaddrlen;
int listensocks[MAX_LISTEN_ADDR];
int listensockcount = 0;
FILE *pidfile = NULL;
int childsock;
pid_t childpid;
int childpipe[2];
/* fork */
if (svr_opts.forkbg) {
int closefds = 0;
@@ -76,16 +132,12 @@ int main(int argc, char ** argv)
}
#endif
if (daemon(0, closefds) < 0) {
dropbear_exit("Failed to create background process: %s",
strerror(errno));
dropbear_exit("Failed to daemonize: %s", strerror(errno));
}
}
#ifndef DISABLE_SYSLOG
if (svr_opts.usingsyslog) {
startsyslog();
}
#endif
commonsetup();
/* should be done after syslog is working */
if (svr_opts.forkbg) {
@@ -101,25 +153,6 @@ int main(int argc, char ** argv)
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;
@@ -127,7 +160,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 +174,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,13 +215,13 @@ 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);
childsock = accept(listensocks[i], &remoteaddr, &remoteaddrlen);
remoteaddrlen = sizeof(remoteaddr);
childsock = accept(listensocks[i],
(struct sockaddr*)&remoteaddr, &remoteaddrlen);
if (childsock < 0) {
/* accept failed */
@@ -222,7 +258,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 +267,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");
}
@@ -258,12 +294,12 @@ int main(int argc, char ** argv)
} /* for(;;) loop */
/* don't reach here */
return -1;
}
#endif
#endif /* NON_INETD_MODE */
/* catch + reap zombie children */
static void sigchld_handler(int fish) {
static void sigchld_handler(int UNUSED(unused)) {
struct sigaction sa_chld;
while(waitpid(-1, NULL, WNOHANG) > 0);
@@ -276,72 +312,79 @@ static void sigchld_handler(int fish) {
}
/* catch any segvs */
static void sigsegv_handler(int fish) {
static void sigsegv_handler(int UNUSED(unused)) {
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) {
static void sigintterm_handler(int UNUSED(unused)) {
exitflag = 1;
}
/* Things used by inetd and non-inetd modes */
static void commonsetup() {
struct sigaction sa_chld;
#ifndef DISABLE_SYSLOG
if (svr_opts.usingsyslog) {
startsyslog();
}
#endif
/* 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");
}
/* Now we can setup the hostkeys - needs to be after logging is on,
* otherwise we might end up blatting error messages to the socket */
loadhostkeys();
}
/* 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* errstring = NULL;
unsigned int sockpos = 0;
int nsock;
TRACE(("listensockets: %d to try\n", svr_opts.portcount));
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");
TRACE(("listening on '%s'", svr_opts.ports[i]));
nsock = dropbear_listen(NULL, svr_opts.ports[i], &sock[sockpos],
sockcount - sockpos,
&errstring, maxfd);
if (nsock < 0) {
dropbear_log(LOG_WARNING, "Failed listening on '%s': %s",
svr_opts.ports[i], errstring);
m_free(errstring);
continue;
}
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));
sockpos += nsock;
/* 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;
return sockpos;
}

View File

@@ -31,8 +31,6 @@
svr_runopts svr_opts; /* GLOBAL */
static sign_key * loadhostkeys(const char * dsskeyfile,
const char * rsakeyfile);
static void printhelp(const char * progname);
static void printhelp(const char * progname) {
@@ -61,7 +59,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
@@ -72,9 +70,13 @@ static void printhelp(const char * progname) {
"-k Disable remote port forwarding\n"
#endif
"-p port Listen on specified tcp port, up to %d can be specified\n"
" (default %d if none specified)\n"
/* "-4/-6 Disable listening on ipv4/ipv6 respectively\n"*/
" (default %s if none specified)\n"
#ifdef INETD_MODE
"-i Start for inetd\n"
#endif
#ifdef DEBUG_TRACE
"-v verbose\n"
#endif
,DROPBEAR_VERSION, progname,
#ifdef DROPBEAR_DSS
DSS_PRIV_FILENAME,
@@ -82,16 +84,13 @@ static void printhelp(const char * progname) {
#ifdef DROPBEAR_RSA
RSA_PRIV_FILENAME,
#endif
DROPBEAR_MAX_PORTS, DROPBEAR_PORT);
DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT);
}
void svr_getopts(int argc, char ** argv) {
unsigned int i;
char ** next = 0;
unsigned int portnum = 0;
char *portstring[DROPBEAR_MAX_PORTS];
unsigned int longport;
/* see printhelp() for options */
svr_opts.rsakeyfile = NULL;
@@ -102,6 +101,9 @@ void svr_getopts(int argc, char ** argv) {
svr_opts.norootlogin = 0;
svr_opts.noauthpass = 0;
svr_opts.norootpass = 0;
svr_opts.inetdmode = 0;
svr_opts.portcount = 0;
svr_opts.hostkey = NULL;
opts.nolocaltcp = 0;
opts.noremotetcp = 0;
/* not yet
@@ -157,12 +159,19 @@ void svr_getopts(int argc, char ** argv) {
case 'k':
opts.noremotetcp = 1;
break;
#endif
#ifdef INETD_MODE
case 'i':
svr_opts.inetdmode = 1;
break;
#endif
case 'p':
if (portnum < DROPBEAR_MAX_PORTS) {
portstring[portnum] = NULL;
next = &portstring[portnum];
portnum++;
if (svr_opts.portcount < DROPBEAR_MAX_PORTS) {
svr_opts.ports[svr_opts.portcount] = NULL;
next = &svr_opts.ports[svr_opts.portcount];
/* Note: if it doesn't actually get set, we'll
* decrement it after the loop */
svr_opts.portcount++;
}
break;
#ifdef DO_MOTD
@@ -174,7 +183,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;
@@ -186,14 +195,11 @@ void svr_getopts(int argc, char ** argv) {
printhelp(argv[0]);
exit(EXIT_FAILURE);
break;
/*
case '4':
svr_opts.ipv4 = 0;
#ifdef DEBUG_TRACE
case 'v':
debug_trace = 1;
break;
case '6':
svr_opts.ipv6 = 0;
break;
*/
#endif
default:
fprintf(stderr, "Unknown argument %s\n", argv[i]);
printhelp(argv[0]);
@@ -203,13 +209,24 @@ void svr_getopts(int argc, char ** argv) {
}
}
/* Set up listening ports */
if (svr_opts.portcount == 0) {
svr_opts.ports[0] = m_strdup(DROPBEAR_DEFPORT);
svr_opts.portcount = 1;
} else {
/* we may have been given a -p option but no argument to go with
* it */
if (svr_opts.ports[svr_opts.portcount-1] == NULL) {
svr_opts.portcount--;
}
}
if (svr_opts.dsskeyfile == NULL) {
svr_opts.dsskeyfile = DSS_PRIV_FILENAME;
}
if (svr_opts.rsakeyfile == NULL) {
svr_opts.rsakeyfile = RSA_PRIV_FILENAME;
}
svr_opts.hostkey = loadhostkeys(svr_opts.dsskeyfile, svr_opts.rsakeyfile);
if (svr_opts.bannerfile) {
struct stat buf;
@@ -231,35 +248,6 @@ void svr_getopts(int argc, char ** argv) {
buf_setpos(svr_opts.banner, 0);
}
/* not yet
if (!(svr_opts.ipv4 || svr_opts.ipv6)) {
fprintf(stderr, "You can't disable ipv4 and ipv6.\n");
exit(1);
}
*/
/* create the array of listening ports */
if (portnum == 0) {
/* non specified */
svr_opts.portcount = 1;
svr_opts.ports = m_malloc(sizeof(uint16_t));
svr_opts.ports[0] = DROPBEAR_PORT;
} else {
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) {
svr_opts.ports[i] = (uint16_t)longport;
continue;
}
}
fprintf(stderr, "Bad port '%s'\n",
portstring[i] ? portstring[i] : "null");
}
}
}
static void disablekey(int type, const char* filename) {
@@ -272,47 +260,45 @@ static void disablekey(int type, const char* filename) {
break;
}
}
fprintf(stderr, "Failed reading '%s', disabling %s\n", filename,
dropbear_log(LOG_WARNING, "Failed reading '%s', disabling %s", filename,
type == DROPBEAR_SIGNKEY_DSS ? "DSS" : "RSA");
}
static sign_key * loadhostkeys(const char * dsskeyfile,
const char * rsakeyfile) {
/* Must be called after syslog/etc is working */
void loadhostkeys() {
sign_key * hostkey;
int ret;
int type;
TRACE(("enter loadhostkeys"));
hostkey = new_sign_key();
svr_opts.hostkey = new_sign_key();
#ifdef DROPBEAR_RSA
type = DROPBEAR_SIGNKEY_RSA;
ret = readhostkey(rsakeyfile, hostkey, &type);
ret = readhostkey(svr_opts.rsakeyfile, svr_opts.hostkey, &type);
if (ret == DROPBEAR_FAILURE) {
disablekey(DROPBEAR_SIGNKEY_RSA, rsakeyfile);
disablekey(DROPBEAR_SIGNKEY_RSA, svr_opts.rsakeyfile);
}
#endif
#ifdef DROPBEAR_DSS
type = DROPBEAR_SIGNKEY_RSA;
ret = readhostkey(dsskeyfile, hostkey, &type);
type = DROPBEAR_SIGNKEY_DSS;
ret = readhostkey(svr_opts.dsskeyfile, svr_opts.hostkey, &type);
if (ret == DROPBEAR_FAILURE) {
disablekey(DROPBEAR_SIGNKEY_DSS, dsskeyfile);
disablekey(DROPBEAR_SIGNKEY_DSS, svr_opts.dsskeyfile);
}
#endif
if ( 1
#ifdef DROPBEAR_DSS
&& hostkey->dsskey == NULL
&& svr_opts.hostkey->dsskey == NULL
#endif
#ifdef DROPBEAR_RSA
&& hostkey->rsakey == NULL
&& svr_opts.hostkey->rsakey == NULL
#endif
) {
dropbear_exit("No hostkeys available");
}
TRACE(("leave loadhostkeys"));
return hostkey;
}

View File

@@ -35,10 +35,9 @@
#include "channel.h"
#include "chansession.h"
#include "atomicio.h"
#include "tcpfwd-direct.h"
#include "tcpfwd.h"
#include "service.h"
#include "auth.h"
#include "tcpfwd-remote.h"
#include "runopts.h"
static void svr_remoteclosed();
@@ -65,7 +64,7 @@ static const packettype svr_packettypes[] = {
static const struct ChanType *svr_chantypes[] = {
&svrchansess,
&chan_tcpdirect,
&svr_chan_tcpdirect,
NULL /* Null termination is mandatory. */
};
@@ -169,7 +168,7 @@ void svr_dropbear_log(int priority, const char* format, va_list param) {
/* if we are using DEBUG_TRACE, we want to print to stderr even if
* syslog is used, so it is included in error reports */
#ifdef DEBUG_TRACE
havetrace = 1;
havetrace = debug_trace;
#endif
if (!svr_opts.usingsyslog || havetrace)

291
svr-tcpfwd.c Normal file
View File

@@ -0,0 +1,291 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* 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 "ssh.h"
#include "tcpfwd.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();
static int newtcpdirect(struct Channel * channel);
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->sendport == info2->sendport)
&& (info1->chantype == info2->chantype)
&& (strcmp(info1->sendaddr, info2->sendaddr) == 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.sendaddr = bindaddr;
tcpinfo.sendport = 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"));
/* NOTE: at this stage, we ignore bindaddr. see below and listen_tcpfwd */
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->sendaddr = bindaddr;
tcpinfo->sendport = port;
tcpinfo->listenport = port;
tcpinfo->chantype = &svr_chan_tcpremote;
/* Note: bindaddr is actually ignored by listen_tcpfwd, since
* we only want to bind to localhost */
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->sendaddr);
m_free(tcpinfo);
}
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 err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
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) {
err = SSH_OPEN_CONNECT_FAILED;
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;
err = SSH_OPEN_IN_PROGRESS;
out:
m_free(desthost);
m_free(orighost);
TRACE(("leave newtcpdirect: err %d", err));
return err;
}
#endif

View File

@@ -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);
@@ -75,14 +75,12 @@ int x11req(struct ChanSess * chansess) {
}
/* set non-blocking */
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
goto fail;
}
setnonblocking(fd);
/* 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 +98,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 +108,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;
}
@@ -131,7 +129,7 @@ static void x11accept(struct Listener* listener) {
void x11setauth(struct ChanSess *chansess) {
char display[20]; /* space for "localhost:12345.123" */
FILE * authprog;
FILE * authprog = NULL;
int val;
if (chansess->x11listener == NULL) {
@@ -171,8 +169,12 @@ void x11cleanup(struct ChanSess *chansess) {
m_free(chansess->x11authprot);
m_free(chansess->x11authcookie);
remove_listener(chansess->x11listener);
chansess->x11listener = NULL;
TRACE(("chansess %s", chansess));
if (chansess->x11listener != NULL) {
remove_listener(chansess->x11listener);
chansess->x11listener = NULL;
}
}
static const struct ChanType chan_x11 = {
@@ -187,7 +189,7 @@ static const struct ChanType chan_x11 = {
static int send_msg_channel_open_x11(int fd, struct sockaddr_in* addr) {
char* ipstring;
char* ipstring = NULL;
if (send_msg_channel_open_init(fd, &chan_x11) == DROPBEAR_SUCCESS) {
ipstring = inet_ntoa(addr->sin_addr);

120
tcp-accept.c Normal file
View File

@@ -0,0 +1,120 @@
/*
* Dropbear SSH
*
* 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 "ssh.h"
#include "tcpfwd.h"
#include "dbutil.h"
#include "session.h"
#include "buffer.h"
#include "packet.h"
#include "listener.h"
#include "runopts.h"
#ifdef DROPBEAR_TCP_ACCEPT
static void cleanup_tcp(struct Listener *listener) {
struct TCPListener *tcpinfo = (struct TCPListener*)(listener->typedata);
m_free(tcpinfo->sendaddr);
m_free(tcpinfo);
}
static void tcp_acceptor(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->sendaddr,
strlen(tcpinfo->sendaddr));
buf_putint(ses.writepayload, tcpinfo->sendport);
buf_putstring(ses.writepayload, ipstring, strlen(ipstring));
buf_putint(ses.writepayload, atol(portstring));
encrypt_packet();
} else {
/* XXX debug? */
close(fd);
}
}
int listen_tcpfwd(struct TCPListener* tcpinfo) {
char portstring[NI_MAXSERV];
int socks[DROPBEAR_MAX_SOCKS];
struct Listener *listener = NULL;
int nsocks;
char* errstring = 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", 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
* the "" argument. but that requires UI changes too */
nsocks = dropbear_listen("", portstring, socks,
DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd);
if (nsocks < 0) {
dropbear_log(LOG_INFO, "TCP forward failed: %s", errstring);
m_free(errstring);
TRACE(("leave listen_tcpfwd: dropbear_listen failed"));
return DROPBEAR_FAILURE;
}
listener = new_listener(socks, nsocks, CHANNEL_ID_TCPFORWARDED, tcpinfo,
tcp_acceptor, 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 /* DROPBEAR_TCP_ACCEPT */

View File

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

View File

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

View File

@@ -1,6 +0,0 @@
#ifndef _REMOTETCPFWD_H
#define _REMOTETCPFWD_H
void recv_msg_global_request_remotetcp();
#endif /* _REMOTETCPFWD_H */

View File

@@ -21,13 +21,50 @@
* 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
#ifndef _AUTH_PASSWD_
#define _AUTH_PASSWD_
#include "channel.h"
#ifdef DROPBEAR_PASSWORD_AUTH
struct TCPListener {
void passwordauth();
/* 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;
#endif /* DROPBEAR_PASSWORD_AUTH */
#endif /* _AUTH_PASSWD_ */
/* 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 {
const unsigned 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();
void setup_remotetcp();
extern const struct ChanType cli_chan_tcpremote;
/* Common */
int listen_tcpfwd(struct TCPListener* tcpinfo);
#endif

View File

@@ -131,7 +131,11 @@ const struct TermCode termcodes[MAX_TERMCODE+1] = {
{IEXTEN, TERMCODE_LOCAL},
{ECHOCTL, TERMCODE_LOCAL},
{ECHOKE, TERMCODE_LOCAL},
#ifdef PENDIN
{PENDIN, TERMCODE_LOCAL},
#else
{0, 0},
#endif
{0, 0}, /* 63 */
{0, 0},
{0, 0},