mirror of
https://github.com/clearml/dropbear
synced 2025-06-26 18:17:32 +00:00
Makefile.in contains updated files required
--HG-- extra : convert_revision : cc8a8c49dc70e632c352853a39801089b08149be
This commit is contained in:
252
CHANGES
Normal file
252
CHANGES
Normal file
@@ -0,0 +1,252 @@
|
||||
0.41 - Mon Jan 19 2004 22:40:19 +0800
|
||||
|
||||
- Fix in configure so that cross-compiling works, thanks to numerous people for
|
||||
reporting and testing
|
||||
|
||||
- Terminal mode parsing now handles empty terminal mode strings (sent by
|
||||
Windows ssh.com clients), thanks to Ricardo Derbes for the report
|
||||
|
||||
- Handling is improved for users with no shell specified in /etc/passwd,
|
||||
thanks again to Ricardo Derbes
|
||||
|
||||
- Fix for compiling with --disable-syslog, thanks to gordonfh
|
||||
|
||||
- Various minor fixes allow scp to work with irix, thanks to Paul Marinceu for
|
||||
fixing it up
|
||||
|
||||
- Use <stropts.h> not <sys/stropts.h>, since the former seems more common
|
||||
|
||||
0.40 - Tue Jan 13 2004 21:05:19 +0800
|
||||
|
||||
- Remote TCP forwarding (-R) style implemented
|
||||
|
||||
- Local and remote TCP forwarding can each be disabled at runtime (-k and -j
|
||||
switches)
|
||||
|
||||
- Fix for problems detecting openpty() with uClibc - many thanks to various
|
||||
people for reporting and testing fixes, including (in random order) Cristian
|
||||
Ionescu-Idbohrn, James Ewing, Steve Dover, Thomas Lundquist and Frederic
|
||||
Lavernhe
|
||||
|
||||
- Improved portability for IRIX, thanks to Paul Marinceu
|
||||
|
||||
- AIX and HPUX portability fixes, thanks to Darren Tucker for patches
|
||||
|
||||
- prngd should now work correctly, thanks to Darren Tucker for the patch
|
||||
|
||||
- scp compilation on systems without strlcpy() is fixed, thanks to Peter
|
||||
Jannesen and David Muse for reporting it (independently and simultaneously :)
|
||||
|
||||
- Merged in new LibTomCrypt 0.92 and LibTomMath 0.28
|
||||
|
||||
0.39 - Tue Dec 16 2003 15:19:19 +0800
|
||||
|
||||
- Better checking of key lengths and parameters for DSS and RSA auth
|
||||
|
||||
- Print fingerprint of keys used for pubkey auth
|
||||
|
||||
- More consistent logging of usernames and IPs
|
||||
|
||||
- Added option to disable password auth (or just for root) at runtime
|
||||
|
||||
- Avoid including bignum functions which don't give much speed benefit but
|
||||
take up binary size
|
||||
|
||||
- Added a stripped down version of OpenSSH's scp binary
|
||||
|
||||
- Added additional supporting functions for Irix, thanks to Paul Marinceu
|
||||
|
||||
- Don't check for unused libraries in configure script
|
||||
|
||||
- Removed trailing comma in algorithm lists (thanks to Mihnea Stoenescu)
|
||||
|
||||
- Fixed up channel close handling, always send close packet in response
|
||||
(also thanks to Mihnea Stoenescu)
|
||||
|
||||
- Various makefile improvements for cross-compiling, thanks to Friedrich
|
||||
Lobenstock and Mihnea Stoenescu
|
||||
|
||||
- Use daemon() function if available (or our own copy) rather than separate
|
||||
code (thanks to Frédéric Lavernhe for the report and debugging, and Bernard
|
||||
Blackham for his suggestion on what to look at)
|
||||
|
||||
- Fixed up support for first_kex_packet_follows, required to talk to ssh.com
|
||||
clients. Thanks to Marian Stagarescu for the bug report.
|
||||
|
||||
- Avoid using MAXPATHLEN, pointer from Ian Morris
|
||||
|
||||
- Improved input sanity checking
|
||||
|
||||
0.38 - Sat Oct 11 2003 16:28:13 +0800
|
||||
|
||||
- Default hostkey path changed to /etc/dropbear/dropbear_{rsa,dss}_host_key
|
||||
rather than /etc/dropbear_{rsa,dss}_host_key
|
||||
|
||||
- Added SMALL and MULTI text files which have info on compiling for multiple
|
||||
binaries or small binaries
|
||||
|
||||
- Allow for commandline definition of some options.h settings
|
||||
(without warnings)
|
||||
|
||||
- Be more careful handling EINTR
|
||||
|
||||
- More fixes for channel closing
|
||||
|
||||
- Added multi-binary support
|
||||
|
||||
- Improved logging of IPs, now get logged in all cases
|
||||
|
||||
- Don't chew cpu when waiting for version identification string, also
|
||||
make sure that we kick off people if they don't auth within 5 minutes.
|
||||
|
||||
- Various small fixes, warnings etc
|
||||
|
||||
- Display MOTD if requested - suggested by
|
||||
Trent Lloyd <lathiat at sixlabs.org> and
|
||||
Zach White <zwhite at darkstar.frop.org>
|
||||
|
||||
- sftp support works (relies on OpenSSH sftp binary or similar)
|
||||
|
||||
- Added --disable-shadow option (requested by the floppyfw guys)
|
||||
|
||||
0.37 - Wed Sept 24 2003 19:42:12 +0800
|
||||
|
||||
- Various portability fixes, fixes for Solaris 9, Tru64 5.1, Mac OS X 10.2,
|
||||
AIX, BSDs
|
||||
|
||||
- Updated LibTomMath to 0.27 and LibTomCrypt to 0.90
|
||||
|
||||
- Renamed util.{c,h} to dbutil.{c,h} to avoid conflicts with system util.h
|
||||
|
||||
- Added some small changes so it'll work with AIX (plus Linux Affinity).
|
||||
Thanks to Shig for them.
|
||||
|
||||
- Improved the closing messages, so a clean exit is "Exited normally"
|
||||
|
||||
- Added some more robust integer/size checking in buffer.c as a backstop for
|
||||
integer overflows
|
||||
|
||||
- X11 forwarding fixed for OSX, path for xauth changed to /usr/X11R6/bin/xauth
|
||||
|
||||
- Channel code handles closing more nicely, doesn't sit waiting for an extra
|
||||
keystroke on BSD/OSX platforms, and data is flushed fully before closing
|
||||
child processes (thanks to
|
||||
Cristian Ionescu-Idbohrn <cristian.ionescu-idbohrn at axis.com> for
|
||||
pointing that out).
|
||||
|
||||
- Changed "DISABLE_TCPFWD" to "ENABLE_TCPFWD" (and for x11/auth) so
|
||||
"disable DISABLE_TCPWD" isn't so confusing.
|
||||
|
||||
- Fix authorized_keys handling (don't crash on too-long keys, and
|
||||
use fgetc not getc to avoid strange macro-related issues), thanks to
|
||||
Cristian Ionescu-Idbohrn <cristian.ionescu-idbohrn at axis.com>
|
||||
and Steve Rodgers <hwstar at cox.net> for reporting and testing.
|
||||
|
||||
- Fixes to the README with regard to uClibc systems, thanks to
|
||||
Cristian Ionescu-Idbohrn <cristian.ionescu-idbohrn at axis.com>,
|
||||
as well as general improvements to documentation (split README/INSTALL)
|
||||
|
||||
- Fixed up some compilation problems with dropbearconvert/dropbearkey if
|
||||
DSS or RSA were disabled, reported by Patrik Karlsson <patrik at cqure.net>
|
||||
|
||||
- Fix double-free bug for hostkeys, reported by
|
||||
Vincent Sanders <vince at kyllikki.org>
|
||||
|
||||
- Fix up missing \ns from dropbearconvert help message,
|
||||
thanks to Mordy Ovits <movits at bloomberg.com> for the patch
|
||||
|
||||
0.36 - Tue August 19 2003 12:16:23 +0800
|
||||
|
||||
- Fix uninitialised temporary variable in DSS signing code
|
||||
(thanks to Matthew Franz <mdfranz at io.com> for reporting, and the authors
|
||||
of Valgrind for making it easy to track down)
|
||||
- Fix remote version-string parsing error
|
||||
(thanks to Bernard Blackham <bernard at blackham.com.au> for noticing)
|
||||
- Improved host-algorithm-matching algorithm in algo.c
|
||||
- Decreased MAX_STRING_LEN to a more realistic value
|
||||
- Fix incorrect version (0.34) in this CHANGES file for the previous release.
|
||||
|
||||
0.35 - Sun August 17 2003 05:37:47 +0800
|
||||
|
||||
- Fix for remotely exploitable format string buffer overflow.
|
||||
(thanks to Joel Eriksson <je at bitnux.com>)
|
||||
|
||||
0.34 - Fri August 15 2003 15:10:00 +0800
|
||||
|
||||
- Made syslog optional, both at compile time and as a compile option
|
||||
(suggested by Laurent Bercot <ska at skarnet.org>)
|
||||
- Fixup for bad base64 parsing in authorized_keys
|
||||
(noticed by Davyd Madeley <davyd at zdlcomputing.com>)
|
||||
- Added initial tcp forwarding code, only -L (local) at this stage
|
||||
- Improved "make install" with DESTDIR and changing ownership seperately,
|
||||
don't check for setpgrp on Linux for crosscompiling.
|
||||
(from Erik Andersen <andersen at codepoet.org>)
|
||||
- More commenting, fix minor compile warnings, make return values more
|
||||
consistent etc
|
||||
- Various signedness fixes
|
||||
- Can listen on multiple ports
|
||||
- added option to disable openpty with configure script,
|
||||
(from K.-P. Kirchdörfer <kapeka at epost.de>)
|
||||
- Various cleanups to bignum code
|
||||
(thanks to Tom St Denis <tomstdenis at iahu.ca>)
|
||||
- Fix compile error when disabling RSA
|
||||
(from Marc Kleine-Budde <kleine-budde at gmx.de>)
|
||||
- Other cleanups, splitting large functions for packet and kex handling etc
|
||||
|
||||
0.33 - Sun June 22 2003 22:24:12 +0800
|
||||
|
||||
- Fixed some invalid assertions in the channel code, fixing the server dying
|
||||
when forwarding X11 connections.
|
||||
- Add dropbearconvert to convert to/from OpenSSH host keys and Dropbear keys
|
||||
- RSA keys now keep p and q parameters for compatibility -- old Dropbear keys
|
||||
still work, but can't be converted to OpenSSH etc.
|
||||
- Debian packaging directory added, thanks to
|
||||
Grahame (grahame at angrygoats.net)
|
||||
- 'install' target added to the makefile
|
||||
- general tidying, improve consistency of functions etc
|
||||
- If RSA or DSS hostkeys don't exist, that algorithm won't be used.
|
||||
- Improved RSA and DSS key generation, more efficient and fixed some minor bugs
|
||||
(thanks to Tom St Denis for the advice)
|
||||
- Merged new versions of LibTomCrypt (0.86) and LibTomMath (0.21)
|
||||
|
||||
0.32 - Sat May 24 2003 12:44:11 +0800
|
||||
|
||||
- Don't compile unused code from libtomcrypt (test vectors etc)
|
||||
- Updated to libtommath 0.17 and libtomcrypt 0.83. New libtommath results
|
||||
in smaller binary size, due to not linking unrequired code
|
||||
- X11 forwarding added
|
||||
- Agent forwarding added (for OpenSSH.com ssh client/agent)
|
||||
- Fix incorrect buffer freeing when banners are used
|
||||
- Hostname resolution works
|
||||
- Various minor bugfixes/code size improvements etc
|
||||
|
||||
0.31 - Fri May 9 2003 17:57:16 +0800
|
||||
|
||||
- Improved syslog messages - IP logging etc
|
||||
- Strip control characters from log messages (specified username currently)
|
||||
- Login recording (utmp/wtmp) support, so last/w/who work - taken from OpenSSH
|
||||
- Shell is started as a proper login shell, so /etc/profile etc is sourced
|
||||
- Ptys work on Solaris (2.8 x86 tested) now
|
||||
- Fixed bug in specifying the rsa hostkey
|
||||
- Fixed bug in compression code, could trigger if compression resulted in
|
||||
larger output than input (uncommon but possible).
|
||||
|
||||
0.30 - Thu Apr 17 2003 18:46:15 +0800
|
||||
|
||||
- SECURITY: buffer.c had bad checking for buffer increment length - fixed
|
||||
- channel code now closes properly on EOF - scp processes don't hang around
|
||||
- syslog support added - improved auth/login/failure messages
|
||||
- general code tidying, made return codes more consistent
|
||||
- Makefile fixed for dependencies and makes libtomcrypt as well
|
||||
- Implemented sending SSH_MSG_UNIMPLEMENTED :)
|
||||
|
||||
0.29 - Wed Apr 9 2003
|
||||
|
||||
- Fixed a stupid bug in 0.28 release, 'newstr = strdup(oldstr)',
|
||||
not 'newstr=oldstr'
|
||||
|
||||
0.28 - Sun Apr 6 2003
|
||||
|
||||
- Initial public release
|
||||
|
||||
Development was started in October 2002
|
||||
108
INSTALL
Normal file
108
INSTALL
Normal file
@@ -0,0 +1,108 @@
|
||||
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 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)
|
||||
|
||||
./configure (optionally with --disable-zlib or --disable-syslog,
|
||||
or --help for other options)
|
||||
|
||||
- Then compile and optionally install Dropbear:
|
||||
|
||||
(the Makefile requires GNU make, if you want to make it portable, send me
|
||||
some patches)
|
||||
|
||||
make
|
||||
make install (installs to /usr/local/sbin, /usr/local/bin by 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
|
||||
|
||||
or alternatively convert OpenSSH keys to Dropbear:
|
||||
./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key
|
||||
|
||||
And you can now run the server.
|
||||
./dropbear
|
||||
|
||||
or './dropbear -h' to get options.
|
||||
|
||||
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".
|
||||
|
||||
============================================================================
|
||||
|
||||
Compiling with uClibc:
|
||||
|
||||
Firstly, make sure you have at least uclibc 0.9.17, as getusershell() in prior
|
||||
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
|
||||
|
||||
It is possible to compile zlib in, by copying zlib.h and zconf.h into a
|
||||
subdirectory (ie zlibincludes), and
|
||||
|
||||
export CFLAGS="-Izlibincludes -I../zlibincludes"
|
||||
export LDFLAGS=/usr/lib/libz.a
|
||||
|
||||
before ./configure and make.
|
||||
|
||||
If you disable zlib, you must explicitly disable compression for the client -
|
||||
OpenSSH is possibly buggy in this regard, it seems you need to disable it
|
||||
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:
|
||||
|
||||
If your system expects /dev/pts to be mounted (this is a uClibc option),
|
||||
make sure that it is.
|
||||
|
||||
Make sure that your libc headers match the library version you are using.
|
||||
|
||||
If openpty() is being used (HAVE_OPENPTY defined in config.h) and it fails,
|
||||
you can try compiling with --disable-openpty. You will probably then need
|
||||
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.
|
||||
82
LICENSE
Normal file
82
LICENSE
Normal file
@@ -0,0 +1,82 @@
|
||||
The majority of code is written by Matt Johnston, under the following license:
|
||||
|
||||
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.
|
||||
|
||||
=====
|
||||
|
||||
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
|
||||
|
||||
=====
|
||||
|
||||
sshpty.c is taken from OpenSSH 3.5p1,
|
||||
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
All rights reserved
|
||||
"As far as I am concerned, the code I have written for this software
|
||||
can be used freely for any purpose. Any derived versions of this
|
||||
software must be clearly marked as such, and if the derived work is
|
||||
incompatible with the protocol description in the RFC file, it must be
|
||||
called by a name other than "ssh" or "Secure Shell". "
|
||||
|
||||
=====
|
||||
|
||||
loginrec.c
|
||||
loginrec.h
|
||||
atomicio.h
|
||||
atomicio.c
|
||||
and strlcat() (included in util.c) are from OpenSSH 3.6.1p2, and are licensed
|
||||
under the 2 point BSD license.
|
||||
|
||||
loginrec is written primarily by Andre Lucas, atomicio.c by Theo de Raadt.
|
||||
|
||||
strlcat() is (c) Todd C. Miller
|
||||
|
||||
=====
|
||||
|
||||
Import code in keyimport.c is modified from PuTTY's import.c, licensed as
|
||||
follows:
|
||||
|
||||
PuTTY is copyright 1997-2003 Simon Tatham.
|
||||
|
||||
Portions copyright Robert de Bath, Joris van Rantwijk, Delian
|
||||
Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
|
||||
Justin Bradford, and CORE SDI S.A.
|
||||
|
||||
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 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.
|
||||
31
MULTI
Normal file
31
MULTI
Normal file
@@ -0,0 +1,31 @@
|
||||
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).
|
||||
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
|
||||
|
||||
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).
|
||||
|
||||
To use the binary, symlink it from the desired executable:
|
||||
|
||||
ln -s dropbearmulti dropbear
|
||||
|
||||
then execute as normal:
|
||||
|
||||
./dropbear <options here>
|
||||
|
||||
"make install" doesn't currently work for multi-binary configuration, however
|
||||
in most situations where it is being used, the target and build systems will
|
||||
differ.
|
||||
164
Makefile.in
Normal file
164
Makefile.in
Normal file
@@ -0,0 +1,164 @@
|
||||
LTC=libtomcrypt/libtomcrypt.a
|
||||
LTM=libtommath/libtommath.a
|
||||
|
||||
COMMONOBJS=dbutil.o common-session.o common-packet.o common-algo.o buffer.o \
|
||||
common-kex.o dss.o bignum.o \
|
||||
signkey.o rsa.o random.o common-channel.o \
|
||||
common-chansession.o queue.o termcodes.o runopts.o \
|
||||
loginrec.o atomicio.o x11fwd.o agentfwd.o localtcpfwd.o compat.o \
|
||||
remotetcpfwd.o tcpfwd.o
|
||||
|
||||
SVROBJS=svr-kex.o svr-packet.o svr-algo.o svr-auth.o sshpty.o \
|
||||
svr-authpasswd.o svr-authpubkey.o svr-session.o svr-service.o \
|
||||
svr-chansession.o svr-runopts.o svr-agentfwd.o
|
||||
|
||||
CLIOBJS=
|
||||
|
||||
OBJS=$(COMMONOBJS) $(SVROBJS)
|
||||
|
||||
DROPBEAROBJS=main.o
|
||||
|
||||
DROPBEARKEYOBJS=dropbearkey.o gendss.o genrsa.o
|
||||
|
||||
CONVERTOBJS=dropbearconvert.o keyimport.o
|
||||
|
||||
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o
|
||||
|
||||
HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \
|
||||
dss.h bignum.h signkey.h rsa.h random.h service.h auth.h authpasswd.h \
|
||||
debug.h channel.h chansession.h debug.h config.h queue.h sshpty.h \
|
||||
termcodes.h gendss.h genrsa.h authpubkey.h runopts.h includes.h \
|
||||
loginrec.h atomicio.h x11fwd.h agentfwd.h localtcpfwd.h compat.h \
|
||||
remotetcpfwd.h tcpfwd.h
|
||||
|
||||
ALLOBJS=$(OBJS) $(DROPBEARKEYOBJS) $(DROPBEAROBJS)
|
||||
|
||||
prefix=@prefix@
|
||||
exec_prefix=${prefix}
|
||||
bindir=${exec_prefix}/bin
|
||||
sbindir=${exec_prefix}/sbin
|
||||
|
||||
CC=@CC@
|
||||
LD=@CC@
|
||||
AR=@AR@
|
||||
RANLIB=@RANLIB@
|
||||
STRIP=@STRIP@
|
||||
INSTALL=@INSTALL@
|
||||
CFLAGS=-Ilibtomcrypt @CFLAGS@
|
||||
LIBS=$(LTC) $(LTM) @LIBS@
|
||||
LDFLAGS=@LDFLAGS@
|
||||
|
||||
# these are exported so that libtomcrypt's makefile will use them
|
||||
export CC
|
||||
export CFLAGS
|
||||
export RANLIB AR STRIP
|
||||
|
||||
all: dropbear dropbearkey dropbearconvert
|
||||
@echo
|
||||
@echo Run \"make strip\" if you want stripped binaries,
|
||||
@echo or \"make install\" to install to ${prefix}
|
||||
|
||||
strip:
|
||||
-$(STRIP) dropbear
|
||||
-$(STRIP) dropbearkey
|
||||
-$(STRIP) dropbearconvert
|
||||
|
||||
install: all
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -m 755 dropbear $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) -m 755 dropbearkey $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -m 755 dropbearconvert $(DESTDIR)$(bindir)
|
||||
# chown might fail, so do it separately to the install
|
||||
-chown root $(DESTDIR)$(sbindir)/dropbear
|
||||
-chgrp 0 $(DESTDIR)$(sbindir)/dropbear
|
||||
-chown root $(DESTDIR)$(bindir)/dropbearkey
|
||||
-chgrp 0 $(DESTDIR)$(bindir)/dropbearkey
|
||||
-chown root $(DESTDIR)$(bindir)/dropbearconvert
|
||||
-chgrp 0 $(DESTDIR)$(bindir)/dropbearconvert
|
||||
|
||||
|
||||
static: dropbear-static dropbearkey-static dropbearconvert-static
|
||||
|
||||
$(ALLOBJS): $(HEADERS) Makefile
|
||||
|
||||
dropbear: $(DROPBEAROBJS) $(OBJS) $(HEADERS) Makefile $(LTC) $(LTM)
|
||||
$(LD) $(LDFLAGS) -o dropbear $(DROPBEAROBJS) $(OBJS) $(LIBS)
|
||||
|
||||
dropbear-static: $(DROPBEAROBJS) $(OBJS) $(HEADERS) Makefile $(LTC) $(LTM)
|
||||
$(LD) $(LDFLAGS) -o staticdropbear $(DROPBEAROBJS) $(OBJS) $(LIBS) -static
|
||||
|
||||
dropbearkey: $(OBJS) $(HEADERS) Makefile $(DROPBEARKEYOBJS) $(LTC) $(LTM)
|
||||
$(LD) $(LDFLAGS) -o dropbearkey $(DROPBEARKEYOBJS) \
|
||||
$(OBJS) $(LIBS)
|
||||
|
||||
dropbearkey-static: $(OBJS) $(HEADERS) Makefile $(DROPBEARKEYOBJS) $(LTC) $(LTM)
|
||||
$(LD) $(LDFLAGS) -o staticdropbearkey $(DROPBEARKEYOBJS) \
|
||||
$(OBJS) $(LIBS) -static
|
||||
|
||||
dropbearconvert: $(OBJS) $(HEADERS) Makefile $(CONVERTOBJS) $(LTC) $(LTM)
|
||||
$(LD) $(LDFLAGS) -o dropbearconvert $(CONVERTOBJS) $(OBJS) $(LIBS)
|
||||
|
||||
dropbearconvert-static: $(OBJS) $(HEADERS) Makefile $(CONVERTOBJS) $(LTC) $(LTM)
|
||||
$(LD) $(LDFLAGS) -o staticdropbearconvert $(CONVERTOBJS) $(OBJS) $(LIBS) \
|
||||
-static
|
||||
|
||||
multi: dropbearmulti
|
||||
|
||||
dropbearmulti: $(HEADERS) $(OBJS) $(LTC) $(LTM) $(CONVERTOBJS) \
|
||||
$(DROPBEARKEYOBJS) $(DROPBEAROBJS) dbmulti.o
|
||||
$(LD) $(LDFLAGS) -o dropbearmulti $(OBJS) $(LTM) $(LTM) $(CONVERTOBJS) \
|
||||
$(DROPBEARKEYOBJS) $(DROPBEAROBJS) dbmulti.o $(LIBS)
|
||||
@echo "You should now create symlinks to the programs you have included"
|
||||
@echo "ie 'ln -s dropbearmulti dropbear'"
|
||||
|
||||
dropbearmultistatic: $(HEADERS) $(OBJS) $(LTC) $(LTM) $(CONVERTOBJS) \
|
||||
$(DROPBEARKEYOBJS) $(DROPBEAROBJS) dbmulti.o
|
||||
$(LD) $(LDFLAGS) -o staticdropbearmulti $(OBJS) $(LTM) $(LTM) \
|
||||
$(CONVERTOBJS) $(DROPBEARKEYOBJS) $(DROPBEAROBJS) \
|
||||
dbmulti.o $(LIBS) -static
|
||||
@echo "You should now create symlinks to the programs you have included"
|
||||
@echo "ie 'ln -s dropbearmultistatic dropbear'"
|
||||
|
||||
stripmulti: dropbearmulti
|
||||
-$(STRIP) dropbearmulti
|
||||
|
||||
|
||||
scp: $(SCPOBJS) Makefile
|
||||
$(LD) $(LDFLAGS) -o $@ $(SCPOBJS)
|
||||
|
||||
# gnumake before 3.80 is broken. So this is uglyish
|
||||
scp-progress: atomicio.o scpmisc.o $(HEADERS) Makefile
|
||||
-rm scp.o progressmeter.o
|
||||
$(MAKE) CFLAGS="$(CFLAGS) -DPROGRESS_METER" scp.o progressmeter.o
|
||||
$(LD) $(LDFLAGS) -o $@ $(SCPOBJS)
|
||||
|
||||
scpstatic: $(SCPOBJS) $(HEADERS) Makefile
|
||||
$(LD) $(LDFLAGS) -o $@ $(SCPOBJS) -static
|
||||
|
||||
$(LTC): $(HEADERS)
|
||||
cd libtomcrypt && $(MAKE) clean && $(MAKE)
|
||||
|
||||
$(LTM): $(HEADERS)
|
||||
cd libtommath && $(MAKE)
|
||||
|
||||
ltc-clean:
|
||||
cd libtomcrypt && $(MAKE) clean
|
||||
|
||||
ltm-clean:
|
||||
cd libtommath && $(MAKE) clean
|
||||
|
||||
sizes: dropbear
|
||||
objdump -t dropbear|grep ".text"|cut -d "." -f 2|sort -rn
|
||||
|
||||
clean: ltc-clean ltm-clean
|
||||
-rm -f dropbear dropbear dropbearkey staticdropbear staticdropbearkey
|
||||
-rm -f dropbearconvert staticdropbearconvert scp scp-progress scpstatic
|
||||
-rm -f dropbearmulti dropbearmultistatic
|
||||
-rm -f *.o *.da *.bb *.bbg *.prof
|
||||
|
||||
distclean: clean tidy
|
||||
-rm -f Makefile config.h
|
||||
|
||||
tidy:
|
||||
-rm -f *~ *.gcov */*~
|
||||
14
README
Normal file
14
README
Normal file
@@ -0,0 +1,14 @@
|
||||
This is Dropbear, a smallish SSH 2 server.
|
||||
|
||||
INSTALL has compilation instructions.
|
||||
|
||||
MULTI has instructions on making a multi-purpose binary (ie a single binary
|
||||
which performs multiple tasks, to save disk space)
|
||||
|
||||
SMALL has some tips on creating small binaries.
|
||||
|
||||
See TODO for a few of the things I know need looking at, and please contact
|
||||
me if you have any questions/bugs found/features/ideas/comments etc :)
|
||||
|
||||
Matt Johnston
|
||||
matt@ucc.asn.au
|
||||
42
SMALL
Normal file
42
SMALL
Normal file
@@ -0,0 +1,42 @@
|
||||
Tips for a small system:
|
||||
|
||||
The following are set in options.h
|
||||
|
||||
- You can safely disable blowfish and twofish ciphers, and MD5 hmac, without
|
||||
affecting interoperability
|
||||
|
||||
- If you're compiling statically, you can turn off host lookups
|
||||
|
||||
- You can disable either password or public-key authentication, though note
|
||||
that the IETF draft states that pubkey authentication is required.
|
||||
|
||||
- Similarly with DSS and RSA, you can disable one of these if you know that
|
||||
all clients will be able to support a particular one. The IETF draft
|
||||
states that DSS is required, however you may prefer to use RSA.
|
||||
DON'T disable either of these on systems where you aren't 100% sure about
|
||||
who will be connecting and what clients they will be using.
|
||||
|
||||
- Disabling the MOTD code and SFTP-SERVER may save a small amount of codesize
|
||||
|
||||
- You can disable x11, tcp and agent forwarding as desired. None of these are
|
||||
essential, although agent-forwarding is often useful even on firewall boxes.
|
||||
|
||||
If you are compiling statically, you may want to disable zlib, as it will use
|
||||
a few tens of kB of binary-size (./configure --disable-zlib).
|
||||
|
||||
You can create a combined binary, see the file MULTI, which will put all
|
||||
the functions into one binary, avoiding repeated code.
|
||||
|
||||
If you're compiling with gcc, you might want to look at gcc's options for
|
||||
stripping unused code. The relevant vars to set before configure are:
|
||||
|
||||
LDFLAGS=-Wl,--gc-sections
|
||||
CFLAGS="-ffunction-sections -fdata-sections"
|
||||
|
||||
You can also experiment with optimisation flags such as -Os, note that in some
|
||||
cases these flags actually seem to increase size, so experiment before
|
||||
deciding.
|
||||
|
||||
Of course using small C libraries such as uClibc and dietlibc can also help.
|
||||
|
||||
If you have any queries, mail me and I'll see if I can help.
|
||||
27
TODO
Normal file
27
TODO
Normal file
@@ -0,0 +1,27 @@
|
||||
Current:
|
||||
|
||||
Things which need doing:
|
||||
|
||||
- Make options.h generated from configure perhaps?
|
||||
|
||||
- investigate self-pipe?
|
||||
- fix agent fwd problems
|
||||
- improve channel window adjustment algorithm (circular buffering)
|
||||
|
||||
- Don't use pregenerated AES tables
|
||||
|
||||
- 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)
|
||||
|
||||
- PAM ??
|
||||
- inetd
|
||||
- possible RSA blinding? need to check whether this is vuln to timing attacks
|
||||
- CTR mode, SSH_MSG_IGNORE sending to improve CBC security
|
||||
- DH Group Exchange possibly
|
||||
|
||||
- fix scp.c for IRIX
|
||||
44
agentfwd.h
Normal file
44
agentfwd.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
#ifndef _AGENTFWD_H_
|
||||
#define _AGENTFWD_H_
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
|
||||
#include "includes.h"
|
||||
#include "chansession.h"
|
||||
#include "channel.h"
|
||||
|
||||
int agentreq(struct ChanSess * chansess);
|
||||
int agentaccept(struct ChanSess * chansess);
|
||||
void agentcleanup(struct ChanSess * chansess);
|
||||
void agentsetauth(struct ChanSess *chansess);
|
||||
void agentset(struct ChanSess *chansess);
|
||||
|
||||
#ifdef __hpux
|
||||
#define seteuid(a) setresuid(-1, (a), -1)
|
||||
#define setegid(a) setresgid(-1, (a), -1)
|
||||
#endif
|
||||
|
||||
#endif /* DROPBEAR_AGENTFWD */
|
||||
#endif /* _AGENTFWD_H_ */
|
||||
75
algo.h
Normal file
75
algo.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _ALGO_H_
|
||||
|
||||
#define _ALGO_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
|
||||
struct Algo_Type {
|
||||
|
||||
unsigned char *name; /* identifying name */
|
||||
char val; /* a value for this cipher, or -1 for invalid */
|
||||
void *data; /* algorithm specific data */
|
||||
unsigned usable : 1; /* whether we can use this algorithm */
|
||||
|
||||
};
|
||||
|
||||
typedef struct Algo_Type algo_type;
|
||||
|
||||
/* lists mapping ssh types of algorithms to internal values */
|
||||
extern algo_type sshkex[];
|
||||
extern algo_type sshhostkey[];
|
||||
extern algo_type sshciphers[];
|
||||
extern algo_type sshhashes[];
|
||||
extern algo_type sshcompress[];
|
||||
|
||||
extern const struct dropbear_cipher dropbear_nocipher;
|
||||
extern const struct dropbear_hash dropbear_nohash;
|
||||
|
||||
struct dropbear_cipher {
|
||||
const struct _cipher_descriptor *cipherdesc;
|
||||
unsigned long keysize;
|
||||
unsigned char blocksize;
|
||||
};
|
||||
|
||||
struct dropbear_hash {
|
||||
const struct _hash_descriptor *hashdesc;
|
||||
unsigned long keysize;
|
||||
unsigned char hashsize;
|
||||
};
|
||||
|
||||
void crypto_init();
|
||||
int have_algo(char* algo, size_t algolen, algo_type algos[]);
|
||||
void buf_put_algolist(buffer * buf, algo_type localalgos[]);
|
||||
|
||||
algo_type * common_buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
int *goodguess);
|
||||
algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
int *goodguess);
|
||||
algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[]);
|
||||
|
||||
#endif /* _ALGO_H_ */
|
||||
64
atomicio.c
Normal file
64
atomicio.c
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copied from OpenSSH 3.6.1p2, required for loginrec.c
|
||||
*
|
||||
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
*/
|
||||
|
||||
/* Taken from OpenSSH for use with the loginrec code */
|
||||
|
||||
/* RCSID("$OpenBSD: atomicio.c,v 1.10 2001/05/08 22:48:07 markus Exp $"); */
|
||||
|
||||
#include "atomicio.h"
|
||||
|
||||
/*
|
||||
* ensure all of data on socket comes through. f==read || f==write
|
||||
*/
|
||||
ssize_t
|
||||
atomicio(f, fd, _s, n)
|
||||
ssize_t (*f) ();
|
||||
int fd;
|
||||
void *_s;
|
||||
size_t n;
|
||||
{
|
||||
char *s = _s;
|
||||
ssize_t res, pos = 0;
|
||||
|
||||
while (n > pos) {
|
||||
res = (f) (fd, s + pos, n - pos);
|
||||
switch (res) {
|
||||
case -1:
|
||||
#ifdef EWOULDBLOCK
|
||||
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
#else
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
#endif
|
||||
continue;
|
||||
case 0:
|
||||
return (res);
|
||||
default:
|
||||
pos += res;
|
||||
}
|
||||
}
|
||||
return (pos);
|
||||
}
|
||||
36
atomicio.h
Normal file
36
atomicio.h
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
/*
|
||||
* Copied from OpenSSH 3.6.1p2, required for loginrec.c
|
||||
*
|
||||
* $OpenBSD: atomicio.h,v 1.4 2001/06/26 06:32:46 itojun Exp $
|
||||
*
|
||||
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
/*
|
||||
* Ensure all of data on socket comes through. f==read || f==write
|
||||
*/
|
||||
ssize_t atomicio(ssize_t (*)(), int, void *, size_t);
|
||||
63
auth.h
Normal file
63
auth.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _AUTH_H_
|
||||
#define _AUTH_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
void authinitialise();
|
||||
|
||||
void recv_msg_userauth_request();
|
||||
void send_msg_userauth_failure(int partial, int incrfail);
|
||||
void send_msg_userauth_success();
|
||||
|
||||
#define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
|
||||
|
||||
#define AUTH_TYPE_PUBKEY 1 << 0
|
||||
#define AUTH_TYPE_PASSWORD 1 << 1
|
||||
|
||||
/* auth types, "none" means we should return list of acceptable types */
|
||||
#define AUTH_METHOD_NONE "none"
|
||||
#define AUTH_METHOD_NONE_LEN 4
|
||||
#define AUTH_METHOD_PUBKEY "publickey"
|
||||
#define AUTH_METHOD_PUBKEY_LEN 9
|
||||
#define AUTH_METHOD_PASSWORD "password"
|
||||
#define AUTH_METHOD_PASSWORD_LEN 8
|
||||
|
||||
struct AuthState {
|
||||
|
||||
char *username; /* This is the username the client presents to check. It
|
||||
is updated each run through, used for auth checking */
|
||||
char *printableuser; /* stripped of control chars, used for logs etc */
|
||||
struct passwd * pw;
|
||||
unsigned char authtypes; /* Flags indicating which auth types are still
|
||||
valid */
|
||||
unsigned int failcount; /* Number of (failed) authentication attempts.*/
|
||||
unsigned authdone : 1; /* 0 if we haven't authed, 1 if we have */
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif /* _AUTH_H_ */
|
||||
33
authpasswd.h
Normal file
33
authpasswd.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _AUTH_PASSWD_
|
||||
#define _AUTH_PASSWD_
|
||||
|
||||
#ifdef DROPBEAR_PASSWORD_AUTH
|
||||
|
||||
void passwordauth();
|
||||
|
||||
#endif /* DROPBEAR_PASSWORD_AUTH */
|
||||
#endif /* _AUTH_PASSWD_ */
|
||||
33
authpubkey.h
Normal file
33
authpubkey.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _PUBKEY_AUTH_
|
||||
#define _PUBKEY_AUTH_
|
||||
|
||||
#ifdef DROPBEAR_PUBKEY_AUTH
|
||||
|
||||
void pubkeyauth();
|
||||
|
||||
#endif /* DROPBEAR_PUBKEY_AUTH */
|
||||
#endif /* _PUBKEY_AUTH_ */
|
||||
94
bignum.c
Normal file
94
bignum.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
/* Contains helper functions for mp_int handling */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
/* wrapper for mp_init, failing fatally on errors (memory allocation) */
|
||||
void m_mp_init(mp_int *mp) {
|
||||
|
||||
if (mp_init(mp) != MP_OKAY) {
|
||||
dropbear_exit("mem alloc error");
|
||||
}
|
||||
}
|
||||
|
||||
/* simplified duplication of bn_mp_multi's mp_init_multi, but die fatally
|
||||
* on error */
|
||||
void m_mp_init_multi(mp_int *mp, ...)
|
||||
{
|
||||
mp_int* cur_arg = mp;
|
||||
va_list args;
|
||||
|
||||
va_start(args, mp); /* init args to next argument from caller */
|
||||
while (cur_arg != NULL) {
|
||||
if (mp_init(cur_arg) != MP_OKAY) {
|
||||
dropbear_exit("mem alloc error");
|
||||
}
|
||||
cur_arg = va_arg(args, mp_int*);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* convert an unsigned mp into an array of bytes, malloced.
|
||||
* This array must be freed after use, len contains the length of the array,
|
||||
* if len != NULL */
|
||||
unsigned char* mptobytes(mp_int *mp, int *len) {
|
||||
|
||||
unsigned char* ret;
|
||||
int size;
|
||||
|
||||
size = mp_unsigned_bin_size(mp);
|
||||
ret = m_malloc(size);
|
||||
if (mp_to_unsigned_bin(mp, ret) != MP_OKAY) {
|
||||
dropbear_exit("mem alloc error");
|
||||
}
|
||||
if (len != NULL) {
|
||||
*len = size;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void bytestomp(mp_int *mp, unsigned char* bytes, unsigned int len) {
|
||||
|
||||
if (mp_read_unsigned_bin(mp, bytes, len) != MP_OKAY) {
|
||||
dropbear_exit("mem alloc error");
|
||||
}
|
||||
}
|
||||
|
||||
/* hash the ssh representation of the mp_int mp */
|
||||
void sha1_process_mp(hash_state *hs, mp_int *mp) {
|
||||
|
||||
int i;
|
||||
buffer * buf;
|
||||
|
||||
buf = buf_new(512 + 20); /* max buffer is a 4096 bit key,
|
||||
plus header + some leeway*/
|
||||
buf_putmpint(buf, mp);
|
||||
i = buf->pos;
|
||||
buf_setpos(buf, 0);
|
||||
sha1_process(hs, buf_getptr(buf, i), i);
|
||||
buf_free(buf);
|
||||
}
|
||||
36
bignum.h
Normal file
36
bignum.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _BIGNUM_H_
|
||||
#define _BIGNUM_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
void m_mp_init(mp_int *mp);
|
||||
void m_mp_init_multi(mp_int *mp, ...);
|
||||
unsigned char* mptobytes(mp_int *mp, int *len);
|
||||
void bytestomp(mp_int *mp, unsigned char* bytes, unsigned int len);
|
||||
void sha1_process_mp(hash_state *hs, mp_int *mp);
|
||||
|
||||
#endif /* _BIGNUM_H_ */
|
||||
325
buffer.c
Normal file
325
buffer.c
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
/* Buffer handling routines, designed to avoid overflows/using invalid data */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/* Prevent integer overflows when incrementing buffer position/length.
|
||||
* Calling functions should check arguments first, but this provides a
|
||||
* backstop */
|
||||
#define BUF_MAX_INCR 1000000000
|
||||
#define BUF_MAX_SIZE 1000000000
|
||||
|
||||
/* avoid excessively large numbers, > 5000 bit */
|
||||
#define BUF_MAX_MPINT (5000 / 8)
|
||||
|
||||
/* Create (malloc) a new buffer of size */
|
||||
buffer* buf_new(unsigned int size) {
|
||||
|
||||
buffer* buf;
|
||||
|
||||
if (size > BUF_MAX_SIZE) {
|
||||
dropbear_exit("buf->size too big");
|
||||
}
|
||||
|
||||
buf = (buffer*)m_malloc(sizeof(buffer));
|
||||
|
||||
if (size > 0) {
|
||||
buf->data = (unsigned char*)m_malloc(size);
|
||||
} else {
|
||||
buf->data = NULL;
|
||||
}
|
||||
|
||||
buf->size = size;
|
||||
buf->pos = 0;
|
||||
buf->len = 0;
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
/* free the buffer's data and the buffer itself */
|
||||
void buf_free(buffer* buf) {
|
||||
|
||||
m_free(buf->data)
|
||||
m_free(buf);
|
||||
}
|
||||
|
||||
/* overwrite the contents of the buffer to clear it */
|
||||
void buf_burn(buffer* buf) {
|
||||
|
||||
m_burn(buf->data, buf->size);
|
||||
|
||||
}
|
||||
|
||||
/* resize a buffer, pos and len will be repositioned if required */
|
||||
void buf_resize(buffer *buf, unsigned int newsize) {
|
||||
|
||||
if (newsize > BUF_MAX_SIZE) {
|
||||
dropbear_exit("buf->size too big");
|
||||
}
|
||||
|
||||
buf->data = m_realloc(buf->data, newsize);
|
||||
buf->size = newsize;
|
||||
buf->len = MIN(newsize, buf->len);
|
||||
buf->pos = MIN(newsize, buf->pos);
|
||||
|
||||
}
|
||||
|
||||
/* Create a copy of buf, allocating required memory etc. */
|
||||
/* The new buffer is sized the same as the length of the source buffer. */
|
||||
buffer* buf_newcopy(buffer* buf) {
|
||||
|
||||
buffer* ret;
|
||||
|
||||
ret = buf_new(buf->len);
|
||||
ret->len = buf->len;
|
||||
memcpy(ret->data, buf->data, buf->len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set the length of the buffer */
|
||||
void buf_setlen(buffer* buf, unsigned int len) {
|
||||
if (len > buf->size) {
|
||||
dropbear_exit("bad buf_setlen");
|
||||
}
|
||||
buf->len = len;
|
||||
}
|
||||
|
||||
/* Increment the length of the buffer */
|
||||
void buf_incrlen(buffer* buf, unsigned int incr) {
|
||||
if (incr > BUF_MAX_INCR || buf->len + incr > buf->size) {
|
||||
dropbear_exit("bad buf_incrlen");
|
||||
}
|
||||
buf->len += incr;
|
||||
}
|
||||
/* Set the position of the buffer */
|
||||
void buf_setpos(buffer* buf, unsigned int pos) {
|
||||
|
||||
if (pos > buf->len) {
|
||||
dropbear_exit("bad buf_setpos");
|
||||
}
|
||||
buf->pos = pos;
|
||||
}
|
||||
|
||||
/* increment the postion by incr, increasing the buffer length if required */
|
||||
void buf_incrwritepos(buffer* buf, unsigned int incr) {
|
||||
if (incr > BUF_MAX_INCR || buf->pos + incr > buf->size) {
|
||||
dropbear_exit("bad buf_incrwritepos");
|
||||
}
|
||||
buf->pos += incr;
|
||||
if (buf->pos > buf->len) {
|
||||
buf->len = buf->pos;
|
||||
}
|
||||
}
|
||||
|
||||
/* increment the position by incr, negative values are allowed, to
|
||||
* decrement the pos*/
|
||||
void buf_incrpos(buffer* buf, int incr) {
|
||||
if (incr > BUF_MAX_INCR ||
|
||||
(unsigned int)((int)buf->pos + incr) > buf->len
|
||||
|| ((int)buf->pos + incr) < 0) {
|
||||
dropbear_exit("bad buf_incrpos");
|
||||
}
|
||||
buf->pos += incr;
|
||||
}
|
||||
|
||||
/* Get a byte from the buffer and increment the pos */
|
||||
unsigned char buf_getbyte(buffer* buf) {
|
||||
|
||||
if (buf->pos >= buf->len) {
|
||||
dropbear_exit("bad buf_getbyte");
|
||||
}
|
||||
return buf->data[buf->pos++];
|
||||
}
|
||||
|
||||
/* put a byte, incrementing the length if required */
|
||||
void buf_putbyte(buffer* buf, unsigned char val) {
|
||||
|
||||
if (buf->pos >= buf->len) {
|
||||
buf_incrlen(buf, 1);
|
||||
}
|
||||
buf->data[buf->pos] = val;
|
||||
buf->pos++;
|
||||
}
|
||||
|
||||
/* returns an in-place pointer to the buffer, checking that
|
||||
* the next len bytes from that position can be used */
|
||||
unsigned char* buf_getptr(buffer* buf, unsigned int len) {
|
||||
|
||||
if (buf->pos + len > buf->len) {
|
||||
dropbear_exit("bad buf_getptr");
|
||||
}
|
||||
return &buf->data[buf->pos];
|
||||
}
|
||||
|
||||
/* like buf_getptr, but checks against total size, not used length.
|
||||
* This allows writing past the used length, but not past the size */
|
||||
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len) {
|
||||
|
||||
if (buf->pos + len > buf->size) {
|
||||
dropbear_exit("bad buf_getwriteptr");
|
||||
}
|
||||
return &buf->data[buf->pos];
|
||||
}
|
||||
|
||||
/* Return a null-terminated string, it is malloced, so must be free()ed
|
||||
* Note that the string isn't checked for null bytes, hence the retlen
|
||||
* may be longer than what is returned by strlen */
|
||||
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
|
||||
unsigned int len;
|
||||
unsigned char* ret;
|
||||
len = buf_getint(buf);
|
||||
if (len > MAX_STRING_LEN) {
|
||||
dropbear_exit("string too long");
|
||||
}
|
||||
|
||||
if (retlen != NULL) {
|
||||
*retlen = len;
|
||||
}
|
||||
ret = m_malloc(len+1);
|
||||
memcpy(ret, buf_getptr(buf, len), len);
|
||||
buf_incrpos(buf, len);
|
||||
ret[len] = '\0';
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Just increment the buffer position the same as if we'd used buf_getstring,
|
||||
* but don't bother copying/malloc()ing for it */
|
||||
void buf_eatstring(buffer *buf) {
|
||||
|
||||
buf_incrpos( buf, buf_getint(buf) );
|
||||
}
|
||||
|
||||
/* Get an uint32 from the buffer and increment the pos */
|
||||
unsigned int buf_getint(buffer* buf) {
|
||||
unsigned int ret;
|
||||
|
||||
LOAD32H(ret, buf_getptr(buf, 4));
|
||||
buf_incrpos(buf, 4);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* put a 32bit uint into the buffer, incr bufferlen & pos if required */
|
||||
void buf_putint(buffer* buf, int unsigned val) {
|
||||
|
||||
STORE32H(val, buf_getwriteptr(buf, 4));
|
||||
buf_incrwritepos(buf, 4);
|
||||
|
||||
}
|
||||
|
||||
/* put a SSH style string into the buffer, increasing buffer len if required */
|
||||
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len) {
|
||||
|
||||
buf_putint(buf, len);
|
||||
buf_putbytes(buf, str, len);
|
||||
|
||||
}
|
||||
|
||||
/* put the set of len bytes into the buffer, incrementing the pos, increasing
|
||||
* len if required */
|
||||
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
|
||||
memcpy(buf_getwriteptr(buf, len), bytes, len);
|
||||
buf_incrwritepos(buf, len);
|
||||
}
|
||||
|
||||
|
||||
/* for our purposes we only need positive (or 0) numbers, so will
|
||||
* fail if we get negative numbers */
|
||||
void buf_putmpint(buffer* buf, mp_int * mp) {
|
||||
|
||||
unsigned int len, pad = 0;
|
||||
TRACE(("enter buf_putmpint"));
|
||||
|
||||
assert(mp != NULL);
|
||||
|
||||
if (SIGN(mp) == MP_NEG) {
|
||||
dropbear_exit("negative bignum");
|
||||
}
|
||||
|
||||
/* zero check */
|
||||
if (USED(mp) == 1 && DIGIT(mp, 0) == 0) {
|
||||
len = 0;
|
||||
} else {
|
||||
/* SSH spec requires padding for mpints with the MSB set, this code
|
||||
* implements it */
|
||||
len = mp_count_bits(mp);
|
||||
/* if the top bit of MSB is set, we need to pad */
|
||||
pad = (len%8 == 0) ? 1 : 0;
|
||||
len = len / 8 + 1; /* don't worry about rounding, we need it for
|
||||
padding anyway when len%8 == 0 */
|
||||
|
||||
}
|
||||
|
||||
/* store the length */
|
||||
buf_putint(buf, len);
|
||||
|
||||
/* store the actual value */
|
||||
if (len > 0) {
|
||||
if (pad) {
|
||||
buf_putbyte(buf, 0x00);
|
||||
}
|
||||
if (mp_to_unsigned_bin(mp, buf_getwriteptr(buf, len-pad)) != MP_OKAY) {
|
||||
dropbear_exit("mpint error");
|
||||
}
|
||||
buf_incrwritepos(buf, len-pad);
|
||||
}
|
||||
|
||||
TRACE(("leave buf_putmpint"));
|
||||
}
|
||||
|
||||
/* Retrieve an mp_int from the buffer.
|
||||
* Will fail for -ve since they shouldn't be required here.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_getmpint(buffer* buf, mp_int* mp) {
|
||||
|
||||
unsigned int len;
|
||||
len = buf_getint(buf);
|
||||
|
||||
if (len == 0) {
|
||||
mp_zero(mp);
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
if (len > BUF_MAX_MPINT) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* check for negative */
|
||||
if (*buf_getptr(buf, 1) & (1 << (CHAR_BIT-1))) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
if (mp_read_unsigned_bin(mp, buf_getptr(buf, len), len) != MP_OKAY) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
buf_incrpos(buf, len);
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
65
buffer.h
Normal file
65
buffer.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _BUFFER_H_
|
||||
|
||||
#define _BUFFER_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
struct buf {
|
||||
|
||||
unsigned char * data;
|
||||
unsigned int len; /* the used size */
|
||||
unsigned int pos;
|
||||
unsigned int size; /* the memory size */
|
||||
|
||||
};
|
||||
|
||||
typedef struct buf buffer;
|
||||
|
||||
buffer * buf_new(unsigned int size);
|
||||
void buf_resize(buffer *buf, unsigned int newsize);
|
||||
void buf_free(buffer* buf);
|
||||
void buf_burn(buffer* buf);
|
||||
buffer* buf_newcopy(buffer* buf);
|
||||
void buf_setlen(buffer* buf, unsigned int len);
|
||||
void buf_incrlen(buffer* buf, unsigned int incr);
|
||||
void buf_setpos(buffer* buf, unsigned int pos);
|
||||
void buf_incrpos(buffer* buf, int incr); /* -ve is ok, to go backwards */
|
||||
void buf_incrwritepos(buffer* buf, unsigned int incr);
|
||||
unsigned char buf_getbyte(buffer* buf);
|
||||
void buf_putbyte(buffer* buf, unsigned char val);
|
||||
unsigned char* buf_getptr(buffer* buf, unsigned int len);
|
||||
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len);
|
||||
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen);
|
||||
void buf_eatstring(buffer *buf);
|
||||
void buf_putint(buffer* buf, unsigned int val);
|
||||
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len);
|
||||
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
|
||||
void buf_putmpint(buffer* buf, mp_int * mp);
|
||||
int buf_getmpint(buffer* buf, mp_int* mp);
|
||||
unsigned int buf_getint(buffer* buf);
|
||||
|
||||
#endif /* _BUFFER_H_ */
|
||||
122
channel.h
Normal file
122
channel.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _CHANNEL_H_
|
||||
#define _CHANNEL_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/* channel->type values */
|
||||
#define CHANNEL_ID_NONE 0
|
||||
#define CHANNEL_ID_SESSION 1
|
||||
#define CHANNEL_ID_X11 2
|
||||
#define CHANNEL_ID_AGENT 3
|
||||
#define CHANNEL_ID_TCPDIRECT 4
|
||||
#define CHANNEL_ID_TCPFORWARDED 5
|
||||
|
||||
#define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1
|
||||
#define SSH_OPEN_CONNECT_FAILED 2
|
||||
#define SSH_OPEN_UNKNOWN_CHANNEL_TYPE 3
|
||||
#define SSH_OPEN_RESOURCE_SHORTAGE 4
|
||||
|
||||
#define MAX_CHANNELS 60 /* 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 */
|
||||
|
||||
/* a simpler way to define that we need code for listeners */
|
||||
#if !defined(DISABLE_X11FWD) || !defined(DISABLE_AUTHFWD) || \
|
||||
!defined(DISABLE_REMOTETCPFWD)
|
||||
#define USE_LISTENERS
|
||||
#endif
|
||||
|
||||
struct ChanType;
|
||||
|
||||
struct Channel {
|
||||
|
||||
unsigned int index; /* the local channel index */
|
||||
unsigned int remotechan;
|
||||
unsigned int recvwindow, transwindow;
|
||||
unsigned int recvmaxpacket, transmaxpacket;
|
||||
void* typedata; /* a pointer to type specific data */
|
||||
int infd; /* stdin for the program, we write to this */
|
||||
int outfd; /* stdout for the program, we read from this */
|
||||
int errfd; /* stdout for a program. This doesn't really fit here,
|
||||
but makes the code a lot tidyer without being too bad. This
|
||||
is -1 for channels which don't requre it. Currently only
|
||||
a 'session' without a pty will use it */
|
||||
buffer *writebuf; /* data for the program */
|
||||
|
||||
int sentclosed, recvclosed;
|
||||
|
||||
/* this is set when we receive/send a channel eof packet */
|
||||
int recveof, senteof;
|
||||
|
||||
int initconn; /* used for TCP forwarding, whether the channel has been
|
||||
fully initialised */
|
||||
|
||||
struct ChanType* type;
|
||||
|
||||
};
|
||||
|
||||
struct ChanType {
|
||||
|
||||
int sepfds; /* Whether this channel has seperate pipes for in/out or not */
|
||||
char *name;
|
||||
int (*inithandler)(struct Channel*);
|
||||
int (*checkclose)(struct Channel*);
|
||||
void (*reqhandler)(struct Channel*);
|
||||
void (*closehandler)(struct Channel*);
|
||||
|
||||
};
|
||||
|
||||
void chaninitialise();
|
||||
void chancleanup();
|
||||
void setchannelfds(fd_set *readfd, fd_set *writefd);
|
||||
void channelio(fd_set *readfd, fd_set *writefd);
|
||||
struct Channel* newchannel(unsigned int remotechan, struct ChanType *type,
|
||||
unsigned int transwindow, unsigned int transmaxpacket);
|
||||
|
||||
void recv_msg_channel_open();
|
||||
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_window_adjust();
|
||||
void recv_msg_channel_close();
|
||||
void recv_msg_channel_eof();
|
||||
|
||||
#ifdef USE_LISTENERS
|
||||
int send_msg_channel_open_init(int fd, struct ChanType *type,
|
||||
const char * typestring);
|
||||
void recv_msg_channel_open_confirmation();
|
||||
void recv_msg_channel_open_failure();
|
||||
#endif
|
||||
|
||||
#endif /* _CHANNEL_H_ */
|
||||
89
chansession.h
Normal file
89
chansession.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _CHANSESSION_H_
|
||||
#define _CHANSESSION_H_
|
||||
|
||||
#include "loginrec.h"
|
||||
#include "channel.h"
|
||||
|
||||
struct ChanSess {
|
||||
|
||||
unsigned char * cmd; /* command to exec */
|
||||
pid_t pid; /* child process pid */
|
||||
|
||||
/* pty details */
|
||||
int master; /* the master terminal fd*/
|
||||
int slave;
|
||||
unsigned char * tty;
|
||||
unsigned char * term;
|
||||
unsigned int termw, termh, termc, termr; /* width, height, col, rows */
|
||||
|
||||
/* exit details */
|
||||
int exited;
|
||||
int exitstatus;
|
||||
int exitsignal;
|
||||
unsigned char exitcore;
|
||||
|
||||
#ifndef DISABLE_X11FWD
|
||||
int x11fd; /* set to -1 to indicate forwarding not established */
|
||||
int x11port;
|
||||
char * x11authprot;
|
||||
char * x11authcookie;
|
||||
unsigned int x11screennum;
|
||||
unsigned char x11singleconn;
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
int agentfd;
|
||||
char * agentfile;
|
||||
char * agentdir;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ChildPid {
|
||||
pid_t pid;
|
||||
struct ChanSess * chansess;
|
||||
};
|
||||
|
||||
|
||||
void newchansess(struct Channel * channel);
|
||||
void chansessionrequest(struct Channel * channel);
|
||||
void closechansess(struct Channel * channel);
|
||||
void svr_chansessinitialise();
|
||||
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);
|
||||
|
||||
|
||||
struct SigMap {
|
||||
int signal;
|
||||
char* name;
|
||||
};
|
||||
|
||||
extern const struct SigMap signames[];
|
||||
|
||||
#endif /* _CHANSESSION_H_ */
|
||||
92
cli_algo.c
Normal file
92
cli_algo.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
|
||||
/*
|
||||
* The chosen [encryption | MAC | compression] algorithm to each
|
||||
* direction MUST be the first algorithm on the client's list
|
||||
* that is also on the server's list.
|
||||
*/
|
||||
algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[]) {
|
||||
|
||||
unsigned char * algolist = NULL;
|
||||
unsigned char * remotealgos[MAX_PROPOSED_ALGO];
|
||||
unsigned int len;
|
||||
unsigned int count, i, j;
|
||||
algo_type * ret = NULL;
|
||||
|
||||
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
|
||||
algolist = buf_getstring(buf, &len);
|
||||
TRACE(("cli_buf_match_algo: %s", algolist));
|
||||
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
goto out; /* just a sanity check, no other use */
|
||||
}
|
||||
|
||||
/* remotealgos will contain a list of the strings parsed out */
|
||||
/* We will have at least one string (even if it's just "") */
|
||||
remotealgos[0] = algolist;
|
||||
count = 1;
|
||||
/* Iterate through, replacing ','s with NULs, to split it into
|
||||
* words. */
|
||||
for (i = 0; i < len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
goto out;
|
||||
}
|
||||
if (algolist[i] == ',') {
|
||||
algolist[i] = '\0';
|
||||
remotealgos[count] = &algolist[i+1];
|
||||
count++;
|
||||
}
|
||||
if (count == MAX_PROPOSED_ALGO) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* iterate and find the first match */
|
||||
|
||||
for (j = 0; localalgos[j].name != NULL; j++) {
|
||||
if (localalgos[j].usable) {
|
||||
len = strlen(localalgos[j].name);
|
||||
for (i = 0; i < count; i++) {
|
||||
if (len == strlen(remotealgos[i])
|
||||
&& strncmp(localalgos[j].name,
|
||||
remotealgos[i], len) == 0) {
|
||||
ret = &localalgos[j];
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
m_free(algolist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
206
common-algo.c
Normal file
206
common-algo.c
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "algo.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
/* This file (algo.c) organises the ciphers which can be used, and is used to
|
||||
* decide which ciphers/hashes/compression/signing to use during key exchange*/
|
||||
|
||||
/* Mappings for ciphers, parameters are
|
||||
{&cipher_desc, keysize, blocksize} */
|
||||
|
||||
#ifdef DROPBEAR_AES128_CBC
|
||||
const struct dropbear_cipher dropbear_aes128 =
|
||||
{&rijndael_desc, 16, 16};
|
||||
#endif
|
||||
#ifdef DROPBEAR_BLOWFISH_CBC
|
||||
const struct dropbear_cipher dropbear_blowfish =
|
||||
{&blowfish_desc, 16, 8};
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH128_CBC
|
||||
const struct dropbear_cipher dropbear_twofish128 =
|
||||
{&twofish_desc, 16, 16};
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES_CBC
|
||||
const struct dropbear_cipher dropbear_3des =
|
||||
{&des3_desc, 24, 8};
|
||||
#endif
|
||||
|
||||
/* used to indicate no encryption, as defined in rfc2410 */
|
||||
const struct dropbear_cipher dropbear_nocipher =
|
||||
{NULL, 16, 8};
|
||||
|
||||
/* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
|
||||
{&hash_desc, keysize, hashsize} */
|
||||
|
||||
#ifdef DROPBEAR_SHA1_HMAC
|
||||
const struct dropbear_hash dropbear_sha1 =
|
||||
{&sha1_desc, 20, 20};
|
||||
#endif
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
const struct dropbear_hash dropbear_md5 =
|
||||
{&md5_desc, 16, 16};
|
||||
#endif
|
||||
|
||||
const struct dropbear_hash dropbear_nohash =
|
||||
{NULL, 16, 0}; /* used initially */
|
||||
|
||||
|
||||
/* The following map ssh names to internal values */
|
||||
|
||||
algo_type sshciphers[] = {
|
||||
#ifdef DROPBEAR_AES128_CBC
|
||||
{"aes128-cbc", 0, (void*)&dropbear_aes128, 1},
|
||||
#endif
|
||||
#ifdef DROPBEAR_BLOWFISH_CBC
|
||||
{"blowfish-cbc", 0, (void*)&dropbear_blowfish, 1},
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH128_CBC
|
||||
{"twofish-cbc", 0, (void*)&dropbear_twofish128, 1},
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES_CBC
|
||||
{"3des-cbc", 0, (void*)&dropbear_3des, 1},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
algo_type sshhashes[] = {
|
||||
#ifdef DROPBEAR_SHA1_HMAC
|
||||
{"hmac-sha1", 0, (void*)&dropbear_sha1, 1},
|
||||
#endif
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
{"hmac-md5", 0, (void*)&dropbear_md5, 1},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
algo_type sshcompress[] = {
|
||||
{"none", DROPBEAR_COMP_NONE, NULL, 1},
|
||||
#ifndef DISABLE_ZLIB
|
||||
{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
algo_type sshhostkey[] = {
|
||||
#ifdef DROPBEAR_RSA
|
||||
{"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1},
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
{"ssh-dss", DROPBEAR_SIGNKEY_DSS, NULL, 1},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
algo_type sshkex[] = {
|
||||
{"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
|
||||
/* Register the compiled in ciphers.
|
||||
* This should be run before using any of the ciphers/hashes */
|
||||
void crypto_init() {
|
||||
|
||||
const struct _cipher_descriptor *regciphers[] = {
|
||||
#ifdef DROPBEAR_AES128_CBC
|
||||
&rijndael_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_BLOWFISH_CBC
|
||||
&blowfish_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH128_CBC
|
||||
&twofish_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES_CBC
|
||||
&des3_desc,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct _hash_descriptor *reghashes[] = {
|
||||
/* we need sha1 for hostkey stuff regardless */
|
||||
&sha1_desc,
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
&md5_desc,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; regciphers[i] != NULL; i++) {
|
||||
if (register_cipher(regciphers[i]) == -1) {
|
||||
dropbear_exit("error registering crypto");
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; reghashes[i] != NULL; i++) {
|
||||
if (register_hash(reghashes[i]) == -1) {
|
||||
dropbear_exit("error registering crypto");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* algolen specifies the length of algo, algos is our local list to match
|
||||
* against.
|
||||
* Returns DROPBEAR_SUCCESS if we have a match for algo, DROPBEAR_FAILURE
|
||||
* otherwise */
|
||||
int have_algo(char* algo, size_t algolen, algo_type algos[]) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; algos[i].name != NULL; i++) {
|
||||
if (strlen(algos[i].name) == algolen
|
||||
&& (strncmp(algos[i].name, algo, algolen) == 0)) {
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Output a comma separated list of algorithms to a buffer */
|
||||
void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
|
||||
|
||||
unsigned int pos = 0, i, len;
|
||||
char str[50]; /* enough for local algo storage */
|
||||
|
||||
for (i = 0; localalgos[i].name != NULL; i++) {
|
||||
if (localalgos[i].usable) {
|
||||
/* Avoid generating a trailing comma */
|
||||
if (pos)
|
||||
str[pos++] = ',';
|
||||
len = strlen(localalgos[i].name);
|
||||
memcpy(&str[pos], localalgos[i].name, len);
|
||||
pos += len;
|
||||
}
|
||||
}
|
||||
str[pos]=0;
|
||||
/* Debug this */
|
||||
TRACE(("buf_put_algolist: %s", str));
|
||||
buf_putstring(buf, str, pos);
|
||||
}
|
||||
1008
common-channel.c
Normal file
1008
common-channel.c
Normal file
File diff suppressed because it is too large
Load Diff
43
common-chansession.c
Normal file
43
common-chansession.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "chansession.h"
|
||||
|
||||
/* Mapping of signal values to ssh signal strings */
|
||||
const extern struct SigMap signames[] = {
|
||||
{SIGABRT, "ABRT"},
|
||||
{SIGALRM, "ALRM"},
|
||||
{SIGFPE, "FPE"},
|
||||
{SIGHUP, "HUP"},
|
||||
{SIGILL, "ILL"},
|
||||
{SIGINT, "INT"},
|
||||
{SIGKILL, "KILL"},
|
||||
{SIGPIPE, "PIPE"},
|
||||
{SIGQUIT, "QUIT"},
|
||||
{SIGSEGV, "SEGV"},
|
||||
{SIGTERM, "TERM"},
|
||||
{SIGUSR1, "USR1"},
|
||||
{SIGUSR2, "USR2"},
|
||||
{0, NULL}
|
||||
};
|
||||
458
common-kex.c
Normal file
458
common-kex.c
Normal file
@@ -0,0 +1,458 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Portions 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 "algo.h"
|
||||
#include "buffer.h"
|
||||
#include "session.h"
|
||||
#include "kex.h"
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "bignum.h"
|
||||
#include "random.h"
|
||||
|
||||
/* diffie-hellman-group1-sha1 value for p */
|
||||
const unsigned char dh_p_val[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
|
||||
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
|
||||
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
||||
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
|
||||
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
|
||||
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
|
||||
0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
|
||||
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
|
||||
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
const int DH_G_VAL = 2;
|
||||
|
||||
static void gen_new_keys();
|
||||
#ifndef DISABLE_ZLIB
|
||||
static void gen_new_zstreams();
|
||||
#endif
|
||||
/* helper function for gen_new_keys */
|
||||
static void hashkeys(unsigned char *out, int outlen,
|
||||
const hash_state * hs, unsigned const char X);
|
||||
|
||||
|
||||
/* Send our list of algorithms we can use */
|
||||
void send_msg_kexinit() {
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_KEXINIT);
|
||||
|
||||
/* cookie */
|
||||
genrandom(buf_getwriteptr(ses.writepayload, 16), 16);
|
||||
buf_incrwritepos(ses.writepayload, 16);
|
||||
|
||||
/* kex algos */
|
||||
buf_put_algolist(ses.writepayload, sshkex);
|
||||
|
||||
/* server_host_key_algorithms */
|
||||
buf_put_algolist(ses.writepayload, sshhostkey);
|
||||
|
||||
/* encryption_algorithms_client_to_server */
|
||||
buf_put_algolist(ses.writepayload, sshciphers);
|
||||
|
||||
/* encryption_algorithms_server_to_client */
|
||||
buf_put_algolist(ses.writepayload, sshciphers);
|
||||
|
||||
/* mac_algorithms_client_to_server */
|
||||
buf_put_algolist(ses.writepayload, sshhashes);
|
||||
|
||||
/* mac_algorithms_server_to_client */
|
||||
buf_put_algolist(ses.writepayload, sshhashes);
|
||||
|
||||
/* compression_algorithms_client_to_server */
|
||||
buf_put_algolist(ses.writepayload, sshcompress);
|
||||
|
||||
/* compression_algorithms_server_to_client */
|
||||
buf_put_algolist(ses.writepayload, sshcompress);
|
||||
|
||||
/* languages_client_to_server */
|
||||
buf_putstring(ses.writepayload, "", 0);
|
||||
|
||||
/* languages_server_to_client */
|
||||
buf_putstring(ses.writepayload, "", 0);
|
||||
|
||||
/* first_kex_packet_follows - unimplemented for now */
|
||||
buf_putbyte(ses.writepayload, 0x00);
|
||||
|
||||
/* reserved unit32 */
|
||||
buf_putint(ses.writepayload, 0);
|
||||
|
||||
/* set up transmitted kex packet buffer for hashing.
|
||||
* This is freed after the end of the kex */
|
||||
ses.transkexinit = buf_newcopy(ses.writepayload);
|
||||
|
||||
encrypt_packet();
|
||||
ses.dataallowed = 0; /* don't send other packets during kex */
|
||||
|
||||
TRACE(("DATAALLOWED=0"));
|
||||
TRACE(("-> KEXINIT"));
|
||||
ses.kexstate.sentkexinit = 1;
|
||||
}
|
||||
|
||||
/* *** NOTE regarding (send|recv)_msg_newkeys ***
|
||||
* Changed by mihnea from the original kex.c to set dataallowed after a
|
||||
* completed key exchange, no matter the order in which it was performed.
|
||||
* This enables client mode without affecting server functionality.
|
||||
*/
|
||||
|
||||
/* Bring new keys into use after a key exchange, and let the client know*/
|
||||
void send_msg_newkeys() {
|
||||
|
||||
TRACE(("enter send_msg_newkeys"));
|
||||
|
||||
/* generate the kexinit request */
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_NEWKEYS);
|
||||
encrypt_packet();
|
||||
|
||||
|
||||
/* set up our state */
|
||||
if (ses.kexstate.recvnewkeys) {
|
||||
TRACE(("while RECVNEWKEYS=1"));
|
||||
gen_new_keys();
|
||||
kexinitialise(); /* we've finished with this kex */
|
||||
TRACE((" -> DATAALLOWED=1"));
|
||||
ses.dataallowed = 1; /* we can send other packets again now */
|
||||
} else {
|
||||
ses.kexstate.sentnewkeys = 1;
|
||||
TRACE(("SENTNEWKEYS=1"));
|
||||
}
|
||||
|
||||
TRACE(("-> MSG_NEWKEYS"));
|
||||
TRACE(("leave send_msg_newkeys"));
|
||||
}
|
||||
|
||||
/* Bring the new keys into use after a key exchange */
|
||||
void recv_msg_newkeys() {
|
||||
|
||||
TRACE(("<- MSG_NEWKEYS"));
|
||||
TRACE(("enter recv_msg_newkeys"));
|
||||
|
||||
/* simply check if we've sent SSH_MSG_NEWKEYS, and if so,
|
||||
* switch to the new keys */
|
||||
if (ses.kexstate.sentnewkeys) {
|
||||
TRACE(("while SENTNEWKEYS=1"));
|
||||
gen_new_keys();
|
||||
kexinitialise(); /* we've finished with this kex */
|
||||
TRACE((" -> DATAALLOWED=1"));
|
||||
ses.dataallowed = 1; /* we can send other packets again now */
|
||||
} else {
|
||||
TRACE(("RECVNEWKEYS=1"));
|
||||
ses.kexstate.recvnewkeys = 1;
|
||||
}
|
||||
|
||||
TRACE(("leave recv_msg_newkeys"));
|
||||
}
|
||||
|
||||
|
||||
/* Duplicated verbatim from kex.c --mihnea */
|
||||
void kexinitialise() {
|
||||
|
||||
struct timeval tv;
|
||||
|
||||
TRACE(("kexinitialise()"));
|
||||
|
||||
/* sent/recv'd MSG_KEXINIT */
|
||||
ses.kexstate.sentkexinit = 0;
|
||||
ses.kexstate.recvkexinit = 0;
|
||||
|
||||
/* sent/recv'd MSG_NEWKEYS */
|
||||
ses.kexstate.recvnewkeys = 0;
|
||||
ses.kexstate.sentnewkeys = 0;
|
||||
|
||||
/* first_packet_follows */
|
||||
/* TODO - currently not handled */
|
||||
ses.kexstate.firstfollows = 0;
|
||||
|
||||
ses.kexstate.datatrans = 0;
|
||||
ses.kexstate.datarecv = 0;
|
||||
|
||||
if (gettimeofday(&tv, 0) < 0) {
|
||||
dropbear_exit("Error getting time");
|
||||
}
|
||||
ses.kexstate.lastkextime = tv.tv_sec;
|
||||
|
||||
}
|
||||
|
||||
/* Helper function for gen_new_keys, creates a hash. It makes a copy of the
|
||||
* already initialised hash_state hs, which should already have processed
|
||||
* the dh_K and hash, since these are common. X is the letter 'A', 'B' etc.
|
||||
* out must have at least min(SHA1_HASH_SIZE, outlen) bytes allocated.
|
||||
* The output will only be expanded once, since that is all that is required
|
||||
* (for 3DES and SHA, with 24 and 20 bytes respectively).
|
||||
*
|
||||
* See Section 5.2 of the IETF secsh Transport Draft for details */
|
||||
|
||||
/* Duplicated verbatim from kex.c --mihnea */
|
||||
static void hashkeys(unsigned char *out, int outlen,
|
||||
const hash_state * hs, const unsigned char X) {
|
||||
|
||||
hash_state hs2;
|
||||
unsigned char k2[SHA1_HASH_SIZE]; /* used to extending */
|
||||
|
||||
memcpy(&hs2, hs, sizeof(hash_state));
|
||||
sha1_process(&hs2, &X, 1);
|
||||
sha1_process(&hs2, ses.session_id, SHA1_HASH_SIZE);
|
||||
sha1_done(&hs2, out);
|
||||
if (SHA1_HASH_SIZE < outlen) {
|
||||
/* need to extend */
|
||||
memcpy(&hs2, hs, sizeof(hash_state));
|
||||
sha1_process(&hs2, out, SHA1_HASH_SIZE);
|
||||
sha1_done(&hs2, k2);
|
||||
memcpy(&out[SHA1_HASH_SIZE], k2, outlen - SHA1_HASH_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate the actual encryption/integrity keys, using the results of the
|
||||
* key exchange, as specified in section 5.2 of the IETF secsh-transport
|
||||
* draft. This occurs after the DH key-exchange.
|
||||
*
|
||||
* ses.newkeys is the new set of keys which are generated, these are only
|
||||
* taken into use after both sides have sent a newkeys message */
|
||||
|
||||
/* Originally from kex.c, generalized for cli/svr mode --mihnea */
|
||||
static void gen_new_keys() {
|
||||
|
||||
unsigned char C2S_IV[MAX_IV_LEN];
|
||||
unsigned char C2S_key[MAX_KEY_LEN];
|
||||
unsigned char S2C_IV[MAX_IV_LEN];
|
||||
unsigned char S2C_key[MAX_KEY_LEN];
|
||||
/* unsigned char key[MAX_KEY_LEN]; */
|
||||
unsigned char *trans_IV, *trans_key, *recv_IV, *recv_key;
|
||||
|
||||
hash_state hs;
|
||||
unsigned int C2S_keysize, S2C_keysize;
|
||||
char mactransletter, macrecvletter; /* Client or server specific */
|
||||
|
||||
TRACE(("enter gen_new_keys"));
|
||||
/* the dh_K and hash are the start of all hashes, we make use of that */
|
||||
|
||||
sha1_init(&hs);
|
||||
sha1_process_mp(&hs, ses.dh_K);
|
||||
mp_clear(ses.dh_K);
|
||||
m_free(ses.dh_K);
|
||||
sha1_process(&hs, ses.hash, SHA1_HASH_SIZE);
|
||||
m_burn(ses.hash, SHA1_HASH_SIZE);
|
||||
|
||||
hashkeys(C2S_IV, SHA1_HASH_SIZE, &hs, 'A');
|
||||
hashkeys(S2C_IV, SHA1_HASH_SIZE, &hs, 'B');
|
||||
|
||||
if (IS_DROPBEAR_CLIENT) {
|
||||
trans_IV = C2S_IV;
|
||||
recv_IV = S2C_IV;
|
||||
trans_key = C2S_key;
|
||||
recv_key = S2C_key;
|
||||
C2S_keysize = ses.newkeys->trans_algo_crypt->keysize;
|
||||
S2C_keysize = ses.newkeys->recv_algo_crypt->keysize;
|
||||
mactransletter = 'E';
|
||||
macrecvletter = 'F';
|
||||
} else {
|
||||
trans_IV = S2C_IV;
|
||||
recv_IV = C2S_IV;
|
||||
trans_key = S2C_key;
|
||||
recv_key = C2S_key;
|
||||
C2S_keysize = ses.newkeys->recv_algo_crypt->keysize;
|
||||
S2C_keysize = ses.newkeys->trans_algo_crypt->keysize;
|
||||
mactransletter = 'F';
|
||||
macrecvletter = 'E';
|
||||
}
|
||||
|
||||
hashkeys(C2S_key, C2S_keysize, &hs, 'C');
|
||||
hashkeys(S2C_key, S2C_keysize, &hs, 'D');
|
||||
|
||||
if (cbc_start(
|
||||
find_cipher(ses.newkeys->recv_algo_crypt->cipherdesc->name),
|
||||
recv_IV, recv_key,
|
||||
ses.newkeys->recv_algo_crypt->keysize, 0,
|
||||
&ses.newkeys->recv_symmetric_struct) != CRYPT_OK) {
|
||||
dropbear_exit("crypto error");
|
||||
}
|
||||
|
||||
if (cbc_start(
|
||||
find_cipher(ses.newkeys->trans_algo_crypt->cipherdesc->name),
|
||||
trans_IV, trans_key,
|
||||
ses.newkeys->trans_algo_crypt->keysize, 0,
|
||||
&ses.newkeys->trans_symmetric_struct) != CRYPT_OK) {
|
||||
dropbear_exit("crypto error");
|
||||
}
|
||||
|
||||
/* MAC keys */
|
||||
hashkeys(ses.newkeys->transmackey,
|
||||
ses.newkeys->trans_algo_mac->keysize, &hs, mactransletter);
|
||||
hashkeys(ses.newkeys->recvmackey,
|
||||
ses.newkeys->recv_algo_mac->keysize, &hs, macrecvletter);
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
gen_new_zstreams();
|
||||
#endif
|
||||
|
||||
/* Switch over to the new keys */
|
||||
m_burn(ses.keys, sizeof(struct key_context));
|
||||
m_free(ses.keys);
|
||||
ses.keys = ses.newkeys;
|
||||
ses.newkeys = NULL;
|
||||
|
||||
TRACE(("leave gen_new_keys"));
|
||||
}
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* Set up new zlib compression streams, close the old ones. Only
|
||||
* called from gen_new_keys() */
|
||||
static void gen_new_zstreams() {
|
||||
|
||||
/* create new zstreams */
|
||||
if (ses.newkeys->recv_algo_comp == DROPBEAR_COMP_ZLIB) {
|
||||
ses.newkeys->recv_zstream = (z_streamp)m_malloc(sizeof(z_stream));
|
||||
ses.newkeys->recv_zstream->zalloc = Z_NULL;
|
||||
ses.newkeys->recv_zstream->zfree = Z_NULL;
|
||||
|
||||
if (inflateInit(ses.newkeys->recv_zstream) != Z_OK) {
|
||||
dropbear_exit("zlib error");
|
||||
}
|
||||
} else {
|
||||
ses.newkeys->recv_zstream = NULL;
|
||||
}
|
||||
|
||||
if (ses.newkeys->trans_algo_comp == DROPBEAR_COMP_ZLIB) {
|
||||
ses.newkeys->trans_zstream = (z_streamp)m_malloc(sizeof(z_stream));
|
||||
ses.newkeys->trans_zstream->zalloc = Z_NULL;
|
||||
ses.newkeys->trans_zstream->zfree = Z_NULL;
|
||||
|
||||
if (deflateInit(ses.newkeys->trans_zstream, Z_DEFAULT_COMPRESSION)
|
||||
!= Z_OK) {
|
||||
dropbear_exit("zlib error");
|
||||
}
|
||||
} else {
|
||||
ses.newkeys->trans_zstream = NULL;
|
||||
}
|
||||
|
||||
/* clean up old keys */
|
||||
if (ses.keys->recv_zstream != NULL) {
|
||||
if (inflateEnd(ses.keys->recv_zstream) == Z_STREAM_ERROR) {
|
||||
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
|
||||
dropbear_exit("crypto error");
|
||||
}
|
||||
m_free(ses.keys->recv_zstream);
|
||||
}
|
||||
if (ses.keys->trans_zstream != NULL) {
|
||||
if (deflateEnd(ses.keys->trans_zstream) == Z_STREAM_ERROR) {
|
||||
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
|
||||
dropbear_exit("crypto error");
|
||||
}
|
||||
m_free(ses.keys->trans_zstream);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Executed upon receiving a kexinit message from the client to initiate
|
||||
* key exchange. If we haven't already done so, we send the list of our
|
||||
* preferred algorithms. The client's requested algorithms are processed,
|
||||
* and we calculate the first portion of the key-exchange-hash for used
|
||||
* later in the key exchange. No response is sent, as the client should
|
||||
* initiate the diffie-hellman key exchange */
|
||||
|
||||
/* Originally from kex.c, generalized for cli/svr mode --mihnea */
|
||||
/* Belongs in common_kex.c where it should be moved after review */
|
||||
void recv_msg_kexinit() {
|
||||
|
||||
TRACE(("<- KEXINIT"));
|
||||
TRACE(("enter recv_msg_kexinit"));
|
||||
|
||||
/* start the kex hash */
|
||||
ses.kexhashbuf = buf_new(MAX_KEXHASHBUF);
|
||||
|
||||
if (!ses.kexstate.sentkexinit) {
|
||||
/* we need to send a kex packet */
|
||||
send_msg_kexinit();
|
||||
TRACE(("continue recv_msg_kexinit: sent kexinit"));
|
||||
}
|
||||
|
||||
|
||||
if (IS_DROPBEAR_CLIENT) {
|
||||
|
||||
/* read the peer's choice of algos */
|
||||
cli_read_kex();
|
||||
|
||||
/* V_C, the client's version string (CR and NL excluded) */
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
(unsigned char*)LOCAL_IDENT, strlen(LOCAL_IDENT));
|
||||
/* V_S, the server's version string (CR and NL excluded) */
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
ses.remoteident, strlen((char*)ses.remoteident));
|
||||
|
||||
/* I_C, the payload of the client's SSH_MSG_KEXINIT */
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
buf_getptr(ses.transkexinit, ses.transkexinit->len),
|
||||
ses.transkexinit->len);
|
||||
/* I_S, the payload of the server's SSH_MSG_KEXINIT */
|
||||
buf_setpos(ses.payload, 0);
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
buf_getptr(ses.payload, ses.payload->len),
|
||||
ses.payload->len);
|
||||
|
||||
} else {
|
||||
|
||||
/* read the peer's choice of algos */
|
||||
svr_read_kex();
|
||||
/* V_C, the client's version string (CR and NL excluded) */
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
ses.remoteident, strlen((char*)ses.remoteident));
|
||||
/* V_S, the server's version string (CR and NL excluded) */
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
(unsigned char*)LOCAL_IDENT, strlen(LOCAL_IDENT));
|
||||
|
||||
/* I_C, the payload of the client's SSH_MSG_KEXINIT */
|
||||
buf_setpos(ses.payload, 0);
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
buf_getptr(ses.payload, ses.payload->len),
|
||||
ses.payload->len);
|
||||
/* I_S, the payload of the server's SSH_MSG_KEXINIT */
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
buf_getptr(ses.transkexinit, ses.transkexinit->len),
|
||||
ses.transkexinit->len);
|
||||
}
|
||||
|
||||
buf_free(ses.transkexinit);
|
||||
ses.transkexinit = NULL;
|
||||
/* the rest of ses.kexhashbuf will be done after DH exchange */
|
||||
|
||||
ses.kexstate.recvkexinit = 1;
|
||||
// ses.expecting = SSH_MSG_KEXDH_INIT;
|
||||
ses.expecting = 0;
|
||||
|
||||
TRACE(("leave recv_msg_kexinit"));
|
||||
}
|
||||
|
||||
620
common-packet.c
Normal file
620
common-packet.c
Normal file
@@ -0,0 +1,620 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "packet.h"
|
||||
#include "session.h"
|
||||
#include "dbutil.h"
|
||||
#include "ssh.h"
|
||||
#include "algo.h"
|
||||
#include "buffer.h"
|
||||
#include "kex.h"
|
||||
#include "random.h"
|
||||
#include "service.h"
|
||||
#include "auth.h"
|
||||
#include "channel.h"
|
||||
|
||||
static void read_packet_init();
|
||||
static void writemac(buffer * outputbuffer, buffer * clearwritebuf);
|
||||
static int checkmac(buffer* hashbuf, buffer* readbuf);
|
||||
|
||||
#define ZLIB_COMPRESS_INCR 20 /* this is 12 bytes + 0.1% of 8000 bytes */
|
||||
#define ZLIB_DECOMPRESS_INCR 100
|
||||
#ifndef DISABLE_ZLIB
|
||||
static buffer* buf_decompress(buffer* buf, unsigned int len);
|
||||
static void buf_compress(buffer * dest, buffer * src, unsigned int len);
|
||||
#endif
|
||||
|
||||
/* non-blocking function writing out a current encrypted packet */
|
||||
void write_packet() {
|
||||
|
||||
int len, written;
|
||||
buffer * writebuf;
|
||||
|
||||
TRACE(("enter write_packet"));
|
||||
assert(!isempty(&ses.writequeue));
|
||||
|
||||
/* Get the next buffer in the queue of encrypted packets to write*/
|
||||
writebuf = (buffer*)examine(&ses.writequeue);
|
||||
|
||||
len = writebuf->len - writebuf->pos;
|
||||
assert(len > 0);
|
||||
/* Try to write as much as possible */
|
||||
written = write(ses.sock, buf_getptr(writebuf, len), len);
|
||||
|
||||
if (written < 0) {
|
||||
if (errno == EINTR) {
|
||||
TRACE(("leave writepacket: EINTR"));
|
||||
return;
|
||||
} else {
|
||||
dropbear_exit("error writing");
|
||||
}
|
||||
}
|
||||
|
||||
if (written == 0) {
|
||||
session_remoteclosed();
|
||||
}
|
||||
|
||||
if (written == len) {
|
||||
/* We've finished with the packet, free it */
|
||||
dequeue(&ses.writequeue);
|
||||
buf_free(writebuf);
|
||||
} else {
|
||||
/* More packet left to write, leave it in the queue for later */
|
||||
buf_incrpos(writebuf, written);
|
||||
}
|
||||
|
||||
TRACE(("leave write_packet"));
|
||||
}
|
||||
|
||||
/* Non-blocking function reading available portion of a packet into the
|
||||
* ses's buffer, decrypting the length if encrypted, decrypting the
|
||||
* full portion if possible */
|
||||
void read_packet() {
|
||||
|
||||
int len;
|
||||
unsigned int maxlen;
|
||||
unsigned char blocksize;
|
||||
|
||||
TRACE(("enter read_packet"));
|
||||
blocksize = ses.keys->recv_algo_crypt->blocksize;
|
||||
|
||||
if (ses.readbuf == NULL || ses.readbuf->len < blocksize) {
|
||||
/* In the first blocksize of a packet */
|
||||
|
||||
/* Read the first blocksize of the packet, so we can decrypt it and
|
||||
* find the length of the whole packet */
|
||||
read_packet_init();
|
||||
|
||||
/* If we don't have the length of decryptreadbuf, we didn't read
|
||||
* a whole blocksize and should exit */
|
||||
if (ses.decryptreadbuf->len == 0) {
|
||||
TRACE(("leave read_packet: packetinit done"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt to read the remainder of the packet, note that there
|
||||
* mightn't be any available (EAGAIN) */
|
||||
assert(ses.readbuf != NULL);
|
||||
maxlen = ses.readbuf->len - ses.readbuf->pos;
|
||||
len = read(ses.sock, buf_getptr(ses.readbuf, maxlen), maxlen);
|
||||
|
||||
if (len == 0) {
|
||||
session_remoteclosed();
|
||||
}
|
||||
|
||||
if (len < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
TRACE(("leave read_packet: EINTR or EAGAIN"));
|
||||
return;
|
||||
} else {
|
||||
dropbear_exit("error reading: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
buf_incrpos(ses.readbuf, len);
|
||||
|
||||
if ((unsigned int)len == maxlen) {
|
||||
/* The whole packet has been read */
|
||||
decrypt_packet();
|
||||
/* The main select() loop process_packet() to
|
||||
* handle the packet contents... */
|
||||
}
|
||||
TRACE(("leave read_packet"));
|
||||
}
|
||||
|
||||
/* Function used to read the initial portion of a packet, and determine the
|
||||
* length. Only called during the first BLOCKSIZE of a packet. */
|
||||
static void read_packet_init() {
|
||||
|
||||
unsigned int maxlen;
|
||||
int len;
|
||||
unsigned char blocksize;
|
||||
unsigned char macsize;
|
||||
|
||||
|
||||
blocksize = ses.keys->recv_algo_crypt->blocksize;
|
||||
macsize = ses.keys->recv_algo_mac->hashsize;
|
||||
|
||||
if (ses.readbuf == NULL) {
|
||||
/* start of a new packet */
|
||||
ses.readbuf = buf_new(INIT_READBUF);
|
||||
assert(ses.decryptreadbuf == NULL);
|
||||
ses.decryptreadbuf = buf_new(blocksize);
|
||||
}
|
||||
|
||||
maxlen = blocksize - ses.readbuf->pos;
|
||||
|
||||
/* read the rest of the packet if possible */
|
||||
len = read(ses.sock, buf_getwriteptr(ses.readbuf, maxlen),
|
||||
maxlen);
|
||||
if (len == 0) {
|
||||
session_remoteclosed();
|
||||
}
|
||||
if (len < 0) {
|
||||
if (errno == EINTR) {
|
||||
TRACE(("leave read_packet_init: EINTR"));
|
||||
return;
|
||||
}
|
||||
dropbear_exit("error reading: %s", strerror(errno));
|
||||
}
|
||||
|
||||
buf_incrwritepos(ses.readbuf, len);
|
||||
|
||||
if ((unsigned int)len != maxlen) {
|
||||
/* don't have enough bytes to determine length, get next time */
|
||||
return;
|
||||
}
|
||||
|
||||
/* now we have the first block, need to get packet length, so we decrypt
|
||||
* the first block (only need first 4 bytes) */
|
||||
buf_setpos(ses.readbuf, 0);
|
||||
if (ses.keys->recv_algo_crypt->cipherdesc == NULL) {
|
||||
/* copy it */
|
||||
memcpy(buf_getwriteptr(ses.decryptreadbuf, blocksize),
|
||||
buf_getptr(ses.readbuf, blocksize),
|
||||
blocksize);
|
||||
} else {
|
||||
/* decrypt it */
|
||||
if (cbc_decrypt(buf_getptr(ses.readbuf, blocksize),
|
||||
buf_getwriteptr(ses.decryptreadbuf,blocksize),
|
||||
&ses.keys->recv_symmetric_struct) != CRYPT_OK) {
|
||||
dropbear_exit("error decrypting");
|
||||
}
|
||||
}
|
||||
buf_setlen(ses.decryptreadbuf, blocksize);
|
||||
len = buf_getint(ses.decryptreadbuf) + 4 + macsize;
|
||||
|
||||
buf_setpos(ses.readbuf, blocksize);
|
||||
|
||||
/* check packet length */
|
||||
if ((len > MAX_PACKET_LEN) ||
|
||||
(len < MIN_PACKET_LEN + macsize) ||
|
||||
((len - macsize) % blocksize != 0)) {
|
||||
dropbear_exit("bad packet size");
|
||||
}
|
||||
|
||||
buf_resize(ses.readbuf, len);
|
||||
buf_setlen(ses.readbuf, len);
|
||||
|
||||
}
|
||||
|
||||
/* handle the received packet */
|
||||
void decrypt_packet() {
|
||||
|
||||
unsigned char blocksize;
|
||||
unsigned char macsize;
|
||||
unsigned int padlen;
|
||||
unsigned int len;
|
||||
|
||||
TRACE(("enter decrypt_packet"));
|
||||
blocksize = ses.keys->recv_algo_crypt->blocksize;
|
||||
macsize = ses.keys->recv_algo_mac->hashsize;
|
||||
|
||||
ses.kexstate.datarecv += ses.readbuf->len;
|
||||
|
||||
/* we've already decrypted the first blocksize in read_packet_init */
|
||||
buf_setpos(ses.readbuf, blocksize);
|
||||
|
||||
buf_resize(ses.decryptreadbuf, ses.readbuf->len - macsize);
|
||||
buf_setlen(ses.decryptreadbuf, ses.decryptreadbuf->size);
|
||||
buf_setpos(ses.decryptreadbuf, blocksize);
|
||||
|
||||
/* decrypt if encryption is set, memcpy otherwise */
|
||||
if (ses.keys->recv_algo_crypt->cipherdesc == NULL) {
|
||||
/* copy it */
|
||||
len = ses.readbuf->len - macsize - blocksize;
|
||||
memcpy(buf_getwriteptr(ses.decryptreadbuf, len),
|
||||
buf_getptr(ses.readbuf, len), len);
|
||||
} else {
|
||||
/* decrypt */
|
||||
while (ses.readbuf->pos < ses.readbuf->len - macsize) {
|
||||
if (cbc_decrypt(buf_getptr(ses.readbuf, blocksize),
|
||||
buf_getwriteptr(ses.decryptreadbuf, blocksize),
|
||||
&ses.keys->recv_symmetric_struct) != CRYPT_OK) {
|
||||
dropbear_exit("error decrypting");
|
||||
}
|
||||
buf_incrpos(ses.readbuf, blocksize);
|
||||
buf_incrwritepos(ses.decryptreadbuf, blocksize);
|
||||
}
|
||||
}
|
||||
|
||||
/* check the hmac */
|
||||
buf_setpos(ses.readbuf, ses.readbuf->len - macsize);
|
||||
if (checkmac(ses.readbuf, ses.decryptreadbuf) != DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Integrity error");
|
||||
}
|
||||
|
||||
/* readbuf no longer required */
|
||||
buf_free(ses.readbuf);
|
||||
ses.readbuf = NULL;
|
||||
|
||||
/* get padding length */
|
||||
buf_setpos(ses.decryptreadbuf, PACKET_PADDING_OFF);
|
||||
padlen = buf_getbyte(ses.decryptreadbuf);
|
||||
|
||||
/* payload length */
|
||||
/* - 4 - 1 is for LEN and PADLEN values */
|
||||
len = ses.decryptreadbuf->len - padlen - 4 - 1;
|
||||
if ((len > MAX_PAYLOAD_LEN) || (len < 1)) {
|
||||
dropbear_exit("bad packet size");
|
||||
}
|
||||
|
||||
buf_setpos(ses.decryptreadbuf, PACKET_PAYLOAD_OFF);
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
if (ses.keys->recv_algo_comp == DROPBEAR_COMP_ZLIB) {
|
||||
/* decompress */
|
||||
ses.payload = buf_decompress(ses.decryptreadbuf, len);
|
||||
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* copy payload */
|
||||
ses.payload = buf_new(len);
|
||||
memcpy(ses.payload->data, buf_getptr(ses.decryptreadbuf, len), len);
|
||||
buf_incrlen(ses.payload, len);
|
||||
}
|
||||
|
||||
buf_free(ses.decryptreadbuf);
|
||||
ses.decryptreadbuf = NULL;
|
||||
buf_setpos(ses.payload, 0);
|
||||
|
||||
ses.recvseq++;
|
||||
|
||||
TRACE(("leave decrypt_packet"));
|
||||
}
|
||||
|
||||
/* Checks the mac in hashbuf, for the data in readbuf.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int checkmac(buffer* macbuf, buffer* sourcebuf) {
|
||||
|
||||
unsigned char macsize;
|
||||
hmac_state hmac;
|
||||
unsigned char tempbuf[MAX_MAC_LEN];
|
||||
unsigned long hashsize;
|
||||
int len;
|
||||
|
||||
macsize = ses.keys->recv_algo_mac->hashsize;
|
||||
|
||||
if (macsize == 0) {
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* calculate the mac */
|
||||
if (hmac_init(&hmac,
|
||||
find_hash(ses.keys->recv_algo_mac->hashdesc->name),
|
||||
ses.keys->recvmackey,
|
||||
ses.keys->recv_algo_mac->keysize)
|
||||
!= CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
|
||||
/* sequence number */
|
||||
STORE32H(ses.recvseq, tempbuf);
|
||||
if (hmac_process(&hmac, tempbuf, 4) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
|
||||
buf_setpos(sourcebuf, 0);
|
||||
len = sourcebuf->len;
|
||||
if (hmac_process(&hmac, buf_getptr(sourcebuf, len), len) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
|
||||
hashsize = sizeof(tempbuf);
|
||||
if (hmac_done(&hmac, tempbuf, &hashsize) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
|
||||
/* compare the hash */
|
||||
if (memcmp(tempbuf, buf_getptr(macbuf, macsize), macsize) != 0) {
|
||||
return DROPBEAR_FAILURE;
|
||||
} else {
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* returns a pointer to a newly created buffer */
|
||||
static buffer* buf_decompress(buffer* buf, unsigned int len) {
|
||||
|
||||
int result;
|
||||
buffer * ret;
|
||||
z_streamp zstream;
|
||||
|
||||
zstream = ses.keys->recv_zstream;
|
||||
ret = buf_new(len);
|
||||
|
||||
zstream->avail_in = len;
|
||||
zstream->next_in = buf_getptr(buf, len);
|
||||
|
||||
/* decompress the payload, incrementally resizing the output buffer */
|
||||
while (1) {
|
||||
|
||||
zstream->avail_out = ret->size - ret->pos;
|
||||
zstream->next_out = buf_getwriteptr(ret, zstream->avail_out);
|
||||
|
||||
result = inflate(zstream, Z_SYNC_FLUSH);
|
||||
|
||||
buf_setlen(ret, ret->size - zstream->avail_out);
|
||||
buf_setpos(ret, ret->len);
|
||||
|
||||
if (result != Z_BUF_ERROR && result != Z_OK) {
|
||||
dropbear_exit("zlib error");
|
||||
}
|
||||
|
||||
if (zstream->avail_in == 0 &&
|
||||
(zstream->avail_out != 0 || result == Z_BUF_ERROR)) {
|
||||
/* we can only exit if avail_out hasn't all been used,
|
||||
* and there's no remaining input */
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (zstream->avail_out == 0) {
|
||||
buf_resize(ret, ret->size + ZLIB_DECOMPRESS_INCR);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* This must be called directly after receiving the unimplemented packet.
|
||||
* Isn't the most clean implementation, it relies on packet processing
|
||||
* occurring directly after decryption. This is reasonably valid, since
|
||||
* there is only a single decryption buffer */
|
||||
void recv_unimplemented() {
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_UNIMPLEMENTED);
|
||||
/* the decryption routine increments the sequence number, we must
|
||||
* decrement */
|
||||
buf_putint(ses.writepayload, ses.recvseq - 1);
|
||||
|
||||
encrypt_packet();
|
||||
}
|
||||
|
||||
/* encrypt the writepayload, putting into writebuf, ready for write_packet()
|
||||
* to put on the wire */
|
||||
void encrypt_packet() {
|
||||
|
||||
unsigned char padlen;
|
||||
unsigned char blocksize, macsize;
|
||||
buffer * writebuf; /* the packet which will go on the wire */
|
||||
buffer * clearwritebuf; /* unencrypted, possibly compressed */
|
||||
|
||||
TRACE(("enter encrypt_packet()"));
|
||||
TRACE(("encrypt_packet type is %d", ses.writepayload->data[0]));
|
||||
blocksize = ses.keys->trans_algo_crypt->blocksize;
|
||||
macsize = ses.keys->trans_algo_mac->hashsize;
|
||||
|
||||
/* Encrypted packet len is payload+5, then worst case is if we are 3 away
|
||||
* from a blocksize multiple. In which case we need to pad to the
|
||||
* multiple, then add another blocksize (or MIN_PACKET_LEN) */
|
||||
clearwritebuf = buf_new((ses.writepayload->len+4+1) + MIN_PACKET_LEN + 3
|
||||
#ifndef DISABLE_ZLIB
|
||||
+ ZLIB_COMPRESS_INCR /* bit of a kludge, but we can't know len*/
|
||||
#endif
|
||||
);
|
||||
buf_setlen(clearwritebuf, PACKET_PAYLOAD_OFF);
|
||||
buf_setpos(clearwritebuf, PACKET_PAYLOAD_OFF);
|
||||
|
||||
buf_setpos(ses.writepayload, 0);
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* compression */
|
||||
if (ses.keys->trans_algo_comp == DROPBEAR_COMP_ZLIB) {
|
||||
buf_compress(clearwritebuf, ses.writepayload, ses.writepayload->len);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
memcpy(buf_getwriteptr(clearwritebuf, ses.writepayload->len),
|
||||
buf_getptr(ses.writepayload, ses.writepayload->len),
|
||||
ses.writepayload->len);
|
||||
buf_incrwritepos(clearwritebuf, ses.writepayload->len);
|
||||
}
|
||||
|
||||
/* finished with payload */
|
||||
buf_setpos(ses.writepayload, 0);
|
||||
buf_setlen(ses.writepayload, 0);
|
||||
|
||||
/* length of padding - packet length must be a multiple of blocksize,
|
||||
* with a minimum of 4 bytes of padding */
|
||||
padlen = blocksize - (clearwritebuf->len) % blocksize;
|
||||
if (padlen < 4) {
|
||||
padlen += blocksize;
|
||||
}
|
||||
/* check for min packet length */
|
||||
if (clearwritebuf->len + padlen < MIN_PACKET_LEN) {
|
||||
padlen += blocksize;
|
||||
}
|
||||
|
||||
buf_setpos(clearwritebuf, 0);
|
||||
/* packet length excluding the packetlength uint32 */
|
||||
buf_putint(clearwritebuf, clearwritebuf->len + padlen - 4);
|
||||
|
||||
/* padding len */
|
||||
buf_putbyte(clearwritebuf, padlen);
|
||||
/* actual padding */
|
||||
buf_setpos(clearwritebuf, clearwritebuf->len);
|
||||
buf_incrlen(clearwritebuf, padlen);
|
||||
genrandom(buf_getptr(clearwritebuf, padlen), padlen);
|
||||
|
||||
/* do the actual encryption */
|
||||
buf_setpos(clearwritebuf, 0);
|
||||
/* create a new writebuffer, this is freed when it has been put on the
|
||||
* wire by writepacket() */
|
||||
writebuf = buf_new(clearwritebuf->len + macsize);
|
||||
|
||||
if (ses.keys->trans_algo_crypt->cipherdesc == NULL) {
|
||||
/* copy it */
|
||||
memcpy(buf_getwriteptr(writebuf, clearwritebuf->len),
|
||||
buf_getptr(clearwritebuf, clearwritebuf->len),
|
||||
clearwritebuf->len);
|
||||
buf_incrwritepos(writebuf, clearwritebuf->len);
|
||||
} else {
|
||||
/* encrypt it */
|
||||
while (clearwritebuf->pos < clearwritebuf->len) {
|
||||
if (cbc_encrypt(buf_getptr(clearwritebuf, blocksize),
|
||||
buf_getwriteptr(writebuf, blocksize),
|
||||
&ses.keys->trans_symmetric_struct) != CRYPT_OK) {
|
||||
dropbear_exit("error encrypting");
|
||||
}
|
||||
buf_incrpos(clearwritebuf, blocksize);
|
||||
buf_incrwritepos(writebuf, blocksize);
|
||||
}
|
||||
}
|
||||
|
||||
/* now add a hmac and we're done */
|
||||
writemac(writebuf, clearwritebuf);
|
||||
|
||||
/* clearwritebuf is finished with */
|
||||
buf_free(clearwritebuf);
|
||||
|
||||
/* enqueue the packet for sending */
|
||||
buf_setpos(writebuf, 0);
|
||||
enqueue(&ses.writequeue, (void*)writebuf);
|
||||
|
||||
/* Update counts */
|
||||
ses.kexstate.datatrans += writebuf->len;
|
||||
ses.transseq++;
|
||||
|
||||
TRACE(("leave encrypt_packet()"));
|
||||
}
|
||||
|
||||
|
||||
/* Create the packet mac, and append H(seqno|clearbuf) to the output */
|
||||
static void writemac(buffer * outputbuffer, buffer * clearwritebuf) {
|
||||
|
||||
int macsize;
|
||||
unsigned char seqbuf[4];
|
||||
unsigned long hashsize;
|
||||
hmac_state hmac;
|
||||
|
||||
TRACE(("enter writemac"));
|
||||
|
||||
macsize = ses.keys->trans_algo_mac->hashsize;
|
||||
|
||||
if (macsize > 0) {
|
||||
/* calculate the mac */
|
||||
if (hmac_init(&hmac,
|
||||
find_hash(ses.keys->trans_algo_mac->hashdesc->name),
|
||||
ses.keys->transmackey,
|
||||
ses.keys->trans_algo_mac->keysize) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
|
||||
/* sequence number */
|
||||
STORE32H(ses.transseq, seqbuf);
|
||||
if (hmac_process(&hmac, seqbuf, 4) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
|
||||
/* the actual contents */
|
||||
buf_setpos(clearwritebuf, 0);
|
||||
if (hmac_process(&hmac,
|
||||
buf_getptr(clearwritebuf,
|
||||
clearwritebuf->len),
|
||||
clearwritebuf->len) != CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
|
||||
hashsize = macsize;
|
||||
if (hmac_done(&hmac, buf_getwriteptr(outputbuffer, macsize), &hashsize)
|
||||
!= CRYPT_OK) {
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
buf_incrwritepos(outputbuffer, macsize);
|
||||
}
|
||||
TRACE(("leave writemac"));
|
||||
}
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
/* compresses len bytes from src, outputting to dest (starting from the
|
||||
* respective current positions. */
|
||||
static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
|
||||
|
||||
unsigned int endpos = src->pos + len;
|
||||
int result;
|
||||
|
||||
TRACE(("enter buf_compress"));
|
||||
|
||||
while (1) {
|
||||
|
||||
ses.keys->trans_zstream->avail_in = endpos - src->pos;
|
||||
ses.keys->trans_zstream->next_in =
|
||||
buf_getptr(src, ses.keys->trans_zstream->avail_in);
|
||||
|
||||
ses.keys->trans_zstream->avail_out = dest->size - dest->pos;
|
||||
ses.keys->trans_zstream->next_out =
|
||||
buf_getwriteptr(dest, ses.keys->trans_zstream->avail_out);
|
||||
|
||||
result = deflate(ses.keys->trans_zstream, Z_SYNC_FLUSH);
|
||||
|
||||
buf_setpos(src, endpos - ses.keys->trans_zstream->avail_in);
|
||||
buf_setlen(dest, dest->size - ses.keys->trans_zstream->avail_out);
|
||||
buf_setpos(dest, dest->len);
|
||||
|
||||
if (result != Z_OK) {
|
||||
dropbear_exit("zlib error");
|
||||
}
|
||||
|
||||
if (ses.keys->trans_zstream->avail_in == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
assert(ses.keys->trans_zstream->avail_out == 0);
|
||||
|
||||
/* the buffer has been filled, we must extend. This only happens in
|
||||
* unusual circumstances where the data grows in size after deflate(),
|
||||
* but it is possible */
|
||||
buf_resize(dest, dest->size + ZLIB_COMPRESS_INCR);
|
||||
|
||||
}
|
||||
TRACE(("leave buf_compress"));
|
||||
}
|
||||
#endif
|
||||
267
common-session.c
Normal file
267
common-session.c
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "session.h"
|
||||
#include "dbutil.h"
|
||||
#include "packet.h"
|
||||
#include "algo.h"
|
||||
#include "buffer.h"
|
||||
#include "dss.h"
|
||||
#include "ssh.h"
|
||||
#include "random.h"
|
||||
#include "kex.h"
|
||||
#include "channel.h"
|
||||
#include "atomicio.h"
|
||||
|
||||
struct sshsession ses;
|
||||
|
||||
/* need to know if the session struct has been initialised, this way isn't the
|
||||
* cleanest, but works OK */
|
||||
int sessinitdone = 0;
|
||||
|
||||
/* this is set when we get SIGINT or SIGTERM, the handler is in main.c */
|
||||
int exitflag = 0;
|
||||
|
||||
static int ident_readln(int fd, char* buf, int count);
|
||||
|
||||
|
||||
void(*session_remoteclosed)() = NULL;
|
||||
|
||||
|
||||
/* called only at the start of a session, set up initial state */
|
||||
void common_session_init(int sock, runopts *opts) {
|
||||
|
||||
TRACE(("enter session_init"));
|
||||
|
||||
ses.remoteaddr = NULL;
|
||||
ses.remotehost = NULL;
|
||||
|
||||
ses.sock = sock;
|
||||
ses.maxfd = sock;
|
||||
|
||||
ses.opts = opts;
|
||||
|
||||
ses.connecttimeout = 0;
|
||||
|
||||
kexinitialise(); /* initialise the kex state */
|
||||
chaninitialise(); /* initialise the channel state */
|
||||
|
||||
ses.writepayload = buf_new(MAX_TRANS_PAYLOAD_LEN);
|
||||
ses.transseq = 0;
|
||||
|
||||
ses.readbuf = NULL;
|
||||
ses.decryptreadbuf = NULL;
|
||||
ses.payload = NULL;
|
||||
ses.recvseq = 0;
|
||||
|
||||
ses.expecting = SSH_MSG_KEXINIT;
|
||||
ses.dataallowed = 0; /* don't send data yet, we'll wait until after kex */
|
||||
ses.ignorenext = 0;
|
||||
|
||||
/* set all the algos to none */
|
||||
ses.keys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
ses.newkeys = NULL;
|
||||
ses.keys->recv_algo_crypt = &dropbear_nocipher;
|
||||
ses.keys->trans_algo_crypt = &dropbear_nocipher;
|
||||
|
||||
ses.keys->recv_algo_mac = &dropbear_nohash;
|
||||
ses.keys->trans_algo_mac = &dropbear_nohash;
|
||||
|
||||
ses.keys->algo_kex = -1;
|
||||
ses.keys->algo_hostkey = -1;
|
||||
ses.keys->recv_algo_comp = DROPBEAR_COMP_NONE;
|
||||
ses.keys->trans_algo_comp = DROPBEAR_COMP_NONE;
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
ses.keys->recv_zstream = NULL;
|
||||
ses.keys->trans_zstream = NULL;
|
||||
#endif
|
||||
|
||||
/* key exchange buffers */
|
||||
ses.session_id = NULL;
|
||||
ses.kexhashbuf = NULL;
|
||||
ses.transkexinit = NULL;
|
||||
ses.dh_K = NULL;
|
||||
ses.remoteident = NULL;
|
||||
|
||||
|
||||
TRACE(("leave session_init"));
|
||||
}
|
||||
|
||||
/* clean up a session on exit */
|
||||
void common_session_cleanup() {
|
||||
|
||||
TRACE(("enter session_cleanup"));
|
||||
|
||||
/* we can't cleanup if we don't know the session state */
|
||||
if (!sessinitdone) {
|
||||
TRACE(("leave session_cleanup: !sessinitdone"));
|
||||
return;
|
||||
}
|
||||
|
||||
m_free(ses.session_id);
|
||||
freerunopts(ses.opts);
|
||||
m_burn(ses.keys, sizeof(struct key_context));
|
||||
m_free(ses.keys);
|
||||
|
||||
chancleanup();
|
||||
|
||||
TRACE(("leave session_cleanup"));
|
||||
}
|
||||
|
||||
/* Check all timeouts which are required. Currently these are the time for
|
||||
* user authentication, and the automatic rekeying. */
|
||||
void checktimeouts() {
|
||||
|
||||
struct timeval tv;
|
||||
long secs;
|
||||
|
||||
if (gettimeofday(&tv, 0) < 0) {
|
||||
dropbear_exit("Error getting time");
|
||||
}
|
||||
|
||||
secs = tv.tv_sec;
|
||||
|
||||
if (ses.connecttimeout != 0 && secs > ses.connecttimeout) {
|
||||
dropbear_close("Timeout before auth");
|
||||
}
|
||||
|
||||
/* we can't rekey if we haven't done remote ident exchange yet */
|
||||
if (ses.remoteident == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ses.kexstate.sentkexinit
|
||||
&& (secs - ses.kexstate.lastkextime >= KEX_REKEY_TIMEOUT
|
||||
|| ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)){
|
||||
TRACE(("rekeying after timeout or max data reached"));
|
||||
send_msg_kexinit();
|
||||
}
|
||||
}
|
||||
void session_identification() {
|
||||
|
||||
/* max length of 255 chars */
|
||||
char linebuf[256];
|
||||
int len = 0;
|
||||
char done = 0;
|
||||
|
||||
/* write our version string, this blocks */
|
||||
if (atomicio(write, ses.sock, LOCAL_IDENT "\r\n",
|
||||
strlen(LOCAL_IDENT "\r\n")) == DROPBEAR_FAILURE) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (!done) {
|
||||
dropbear_exit("Failed to get client version");
|
||||
} else {
|
||||
/* linebuf is already null terminated */
|
||||
ses.remoteident = m_malloc(len);
|
||||
memcpy(ses.remoteident, linebuf, len);
|
||||
}
|
||||
|
||||
TRACE(("remoteident: %s", ses.remoteident));
|
||||
|
||||
}
|
||||
|
||||
/* returns the length including null-terminating zero on success,
|
||||
* or -1 on failure */
|
||||
static int ident_readln(int fd, char* buf, int count) {
|
||||
|
||||
char in;
|
||||
int pos = 0;
|
||||
int num = 0;
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
|
||||
TRACE(("enter ident_readln"));
|
||||
|
||||
if (count < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
FD_ZERO(&fds);
|
||||
|
||||
/* select since it's a non-blocking fd */
|
||||
|
||||
/* leave space to null-terminate */
|
||||
while (pos < count-1) {
|
||||
|
||||
FD_SET(fd, &fds);
|
||||
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
if (select(fd+1, &fds, NULL, NULL, &timeout) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
TRACE(("leave ident_readln: select error"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
checktimeouts();
|
||||
|
||||
/* Have to go one byte at a time, since we don't want to read past
|
||||
* the end, and have to somehow shove bytes back into the normal
|
||||
* packet reader */
|
||||
if (FD_ISSET(fd, &fds)) {
|
||||
num = read(fd, &in, 1);
|
||||
/* a "\n" is a newline, "\r" we want to read in and keep going
|
||||
* so that it won't be read as part of the next line */
|
||||
if (num < 0) {
|
||||
/* error */
|
||||
if (errno == EINTR) {
|
||||
continue; /* not a real error */
|
||||
}
|
||||
TRACE(("leave ident_readln: read error"));
|
||||
return -1;
|
||||
}
|
||||
if (num == 0) {
|
||||
/* EOF */
|
||||
TRACE(("leave ident_readln: EOF"));
|
||||
return -1;
|
||||
}
|
||||
if (in == '\n') {
|
||||
/* end of ident string */
|
||||
break;
|
||||
}
|
||||
/* we don't want to include '\r's */
|
||||
if (in != '\r') {
|
||||
buf[pos] = in;
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buf[pos] = '\0';
|
||||
TRACE(("leave ident_readln: return %d", pos+1));
|
||||
return pos+1;
|
||||
}
|
||||
|
||||
281
compat.c
Normal file
281
compat.c
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* strlcat() is copyright as follows:
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
* 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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.
|
||||
*
|
||||
* daemon() and getusershell() is copyright as follows:
|
||||
*
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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.
|
||||
*
|
||||
* Modifications for Dropbear to getusershell() are by Paul Marinceu
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifndef HAVE_GETUSERSHELL
|
||||
static char **curshell, **shells, *strings;
|
||||
static char **initshells();
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRLCPY
|
||||
/* Implemented by matt as specified in freebsd 4.7 manpage.
|
||||
* We don't require great speed, is simply for use with sshpty code */
|
||||
size_t strlcpy(char *dst, const char *src, size_t size) {
|
||||
|
||||
size_t i;
|
||||
|
||||
/* this is undefined, though size==0 -> return 0 */
|
||||
if (size < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < size-1; i++) {
|
||||
if (src[i] == '\0') {
|
||||
break;
|
||||
} else {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
dst[i] = '\0';
|
||||
return strlen(src);
|
||||
|
||||
}
|
||||
#endif /* HAVE_STRLCPY */
|
||||
|
||||
#ifndef HAVE_STRLCAT
|
||||
/* taken from openbsd-compat for OpenSSH 3.6.1p1 */
|
||||
/* "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $"
|
||||
*
|
||||
* Appends src to string dst of size siz (unlike strncat, siz is the
|
||||
* full size of dst, not space left). At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
|
||||
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
|
||||
* If retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcat(dst, src, siz)
|
||||
char *dst;
|
||||
const char *src;
|
||||
size_t siz;
|
||||
{
|
||||
register char *d = dst;
|
||||
register const char *s = src;
|
||||
register size_t n = siz;
|
||||
size_t dlen;
|
||||
|
||||
/* Find the end of dst and adjust bytes left but don't go past end */
|
||||
while (n-- != 0 && *d != '\0')
|
||||
d++;
|
||||
dlen = d - dst;
|
||||
n = siz - dlen;
|
||||
|
||||
if (n == 0)
|
||||
return(dlen + strlen(s));
|
||||
while (*s != '\0') {
|
||||
if (n != 1) {
|
||||
*d++ = *s;
|
||||
n--;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
*d = '\0';
|
||||
|
||||
return(dlen + (s - src)); /* count does not include NUL */
|
||||
}
|
||||
#endif /* HAVE_STRLCAT */
|
||||
|
||||
#ifndef HAVE_DAEMON
|
||||
/* From NetBSD - daemonise a process */
|
||||
|
||||
int daemon(int nochdir, int noclose) {
|
||||
|
||||
int fd;
|
||||
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
return (-1);
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
if (setsid() == -1)
|
||||
return -1;
|
||||
|
||||
if (!nochdir)
|
||||
(void)chdir("/");
|
||||
|
||||
if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
|
||||
(void)dup2(fd, STDIN_FILENO);
|
||||
(void)dup2(fd, STDOUT_FILENO);
|
||||
(void)dup2(fd, STDERR_FILENO);
|
||||
if (fd > STDERR_FILENO)
|
||||
(void)close(fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_DAEMON */
|
||||
|
||||
#ifndef HAVE_BASENAME
|
||||
|
||||
char *basename(char *path) {
|
||||
|
||||
char *foo = strrchr(path, '/');
|
||||
return ++foo;
|
||||
}
|
||||
|
||||
#endif /* HAVE_BASENAME */
|
||||
|
||||
#ifndef HAVE_GETUSERSHELL
|
||||
|
||||
/*
|
||||
* Get a list of shells from /etc/shells, if it exists.
|
||||
*/
|
||||
char * getusershell() {
|
||||
char *ret;
|
||||
|
||||
if (curshell == NULL)
|
||||
curshell = initshells();
|
||||
ret = *curshell;
|
||||
if (ret != NULL)
|
||||
curshell++;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
void endusershell() {
|
||||
|
||||
if (shells != NULL)
|
||||
free(shells);
|
||||
shells = NULL;
|
||||
if (strings != NULL)
|
||||
free(strings);
|
||||
strings = NULL;
|
||||
curshell = NULL;
|
||||
}
|
||||
|
||||
void setusershell() {
|
||||
curshell = initshells();
|
||||
}
|
||||
|
||||
static char **initshells() {
|
||||
/* don't touch this list. */
|
||||
const char *okshells[] = { "/bin/sh", "/bin/csh", NULL };
|
||||
register char **sp, *cp;
|
||||
register FILE *fp;
|
||||
struct stat statb;
|
||||
int flen;
|
||||
|
||||
if (shells != NULL)
|
||||
free(shells);
|
||||
shells = NULL;
|
||||
if (strings != NULL)
|
||||
free(strings);
|
||||
strings = NULL;
|
||||
if ((fp = fopen("/etc/shells", "rc")) == NULL)
|
||||
return (char **) okshells;
|
||||
if (fstat(fileno(fp), &statb) == -1) {
|
||||
(void)fclose(fp);
|
||||
return (char **) okshells;
|
||||
}
|
||||
if ((strings = malloc((u_int)statb.st_size + 1)) == NULL) {
|
||||
(void)fclose(fp);
|
||||
return (char **) okshells;
|
||||
}
|
||||
shells = calloc((unsigned)statb.st_size / 3, sizeof (char *));
|
||||
if (shells == NULL) {
|
||||
(void)fclose(fp);
|
||||
free(strings);
|
||||
strings = NULL;
|
||||
return (char **) okshells;
|
||||
}
|
||||
sp = shells;
|
||||
cp = strings;
|
||||
flen = statb.st_size;
|
||||
while (fgets(cp, flen - (cp - strings), fp) != NULL) {
|
||||
while (*cp != '#' && *cp != '/' && *cp != '\0')
|
||||
cp++;
|
||||
if (*cp == '#' || *cp == '\0')
|
||||
continue;
|
||||
*sp++ = cp;
|
||||
while (!isspace(*cp) && *cp != '#' && *cp != '\0')
|
||||
cp++;
|
||||
*cp++ = '\0';
|
||||
}
|
||||
*sp = NULL;
|
||||
(void)fclose(fp);
|
||||
return (shells);
|
||||
}
|
||||
|
||||
#endif /* HAVE_GETUSERSHELL */
|
||||
32
compat.h
Normal file
32
compat.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef _COMPAT_H_
|
||||
#define _COMPAT_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifndef HAVE_STRLCPY
|
||||
size_t strlcpy(char *dst, const char *src, size_t size);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRLCAT
|
||||
size_t strlcat(char *dst, const char *src, size_t siz);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_DAEMON
|
||||
int daemon(int nochdir, int noclose);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_BASENAME
|
||||
char *basename(const char* path);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETUSERSHELL
|
||||
char *getusershell();
|
||||
void setusershell();
|
||||
void endusershell();
|
||||
#endif
|
||||
|
||||
#ifndef _PATH_DEVNULL
|
||||
#define _PATH_DEVNULL "/dev/null"
|
||||
#endif
|
||||
|
||||
#endif /* _COMPAT_H_ */
|
||||
1391
config.guess
vendored
Normal file
1391
config.guess
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1492
config.sub
vendored
Normal file
1492
config.sub
vendored
Normal file
File diff suppressed because it is too large
Load Diff
489
configure.in
Normal file
489
configure.in
Normal file
@@ -0,0 +1,489 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
# This Autoconf file was cobbled from various locations.
|
||||
|
||||
AC_PREREQ(2.50)
|
||||
AC_INIT(buffer.c)
|
||||
|
||||
OLDCFLAGS=$CFLAGS
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_MAKE_SET
|
||||
|
||||
if test -z "$LD" ; then
|
||||
LD=$CC
|
||||
fi
|
||||
AC_SUBST(LD)
|
||||
|
||||
if test -z "$OLDCFLAGS" && test "$GCC" = "yes"; then
|
||||
AC_MSG_RESULT(No \$CFLAGS set... using "-Os -W -Wall for GCC")
|
||||
CFLAGS="-Os -W -Wall"
|
||||
fi
|
||||
|
||||
# Host specific options
|
||||
# this isn't a definitive list of hosts, they are just added as required
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
case "$host" in
|
||||
|
||||
*-*-linux*)
|
||||
no_ptmx_check=1
|
||||
;;
|
||||
|
||||
*-*-solaris*)
|
||||
CFLAGS="$CFLAGS -I/usr/local/include"
|
||||
LDFLAGS="$LDFLAGS -L/usr/local/lib -R/usr/local/lib"
|
||||
conf_lastlog_location="/var/adm/lastlog"
|
||||
AC_MSG_CHECKING(for obsolete utmp and wtmp in solaris2.x)
|
||||
sol2ver=`echo "$host"| sed -e 's/.*[[0-9]]\.//'`
|
||||
if test "$sol2ver" -ge 8; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(DISABLE_UTMP,,Disable utmp)
|
||||
AC_DEFINE(DISABLE_WTMP,,Disable wtmp)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket")
|
||||
AC_CHECK_LIB(nsl, yp_match, LIBS="$LIBS -lnsl")
|
||||
;;
|
||||
|
||||
*-*-aix*)
|
||||
AC_DEFINE(AIX,,Using AIX)
|
||||
;;
|
||||
|
||||
*-*-hpux*)
|
||||
LIBS="$LIBS -lsec"
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_CHECK_TOOL(AR, ar, :)
|
||||
AC_CHECK_TOOL(RANLIB, ranlib, :)
|
||||
AC_CHECK_TOOL(STRIP, strip, :)
|
||||
AC_CHECK_TOOL(INSTALL, install, :)
|
||||
|
||||
dnl Can't use login() or logout() with uclibc
|
||||
AC_CHECK_DECL(__UCLIBC__,
|
||||
[
|
||||
no_loginfunc_check=1
|
||||
AC_MSG_RESULT(Using uClibc - login() and logout() probably don't work, so we won't use them.)
|
||||
],,,)
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB(crypt, crypt, LIBS="$LIBS -lcrypt")
|
||||
|
||||
# Check if zlib is needed
|
||||
AC_ARG_WITH(zlib,
|
||||
[ --with-zlib=PATH Use zlib in PATH],
|
||||
[
|
||||
# option is given
|
||||
if test -d "$withval/lib"; then
|
||||
LDFLAGS="-L${withval}/lib ${LDFLAGS}"
|
||||
else
|
||||
LDFLAGS="-L${withval} ${LDFLAGS}"
|
||||
fi
|
||||
if test -d "$withval/include"; then
|
||||
CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
|
||||
else
|
||||
CPPFLAGS="-I${withval} ${CPPFLAGS}"
|
||||
fi
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(zlib,
|
||||
[ --disable-zlib Don't include zlib support],
|
||||
[
|
||||
if test "x$enableval" = "xno"; then
|
||||
AC_DEFINE(DISABLE_ZLIB,, Use zlib)
|
||||
AC_MSG_RESULT(Disabling zlib)
|
||||
else
|
||||
AC_CHECK_LIB(z, deflate, , AC_MSG_ERROR([*** zlib missing - install first or check config.log ***]))
|
||||
AC_MSG_RESULT(Enabling zlib)
|
||||
fi
|
||||
],
|
||||
[
|
||||
# if not disabled, check for zlib
|
||||
AC_CHECK_LIB(z, deflate, , AC_MSG_ERROR([*** zlib missing - install first or check config.log ***]))
|
||||
AC_MSG_RESULT(Enabling zlib)
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(openpty,
|
||||
[ --disable-openpty Don't use openpty, use alternative method],
|
||||
[
|
||||
if test "x$enableval" = "xno"; then
|
||||
AC_MSG_RESULT(Not using openpty)
|
||||
else
|
||||
AC_MSG_RESULT(Using openpty if available)
|
||||
AC_SEARCH_LIBS(openpty, util, [AC_DEFINE(HAVE_OPENPTY,,Have openpty() function)])
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(Using openpty if available)
|
||||
AC_SEARCH_LIBS(openpty, util, [AC_DEFINE(HAVE_OPENPTY)])
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
AC_ARG_ENABLE(syslog,
|
||||
[ --disable-syslog Don't include syslog support],
|
||||
[
|
||||
if test "x$enableval" = "xno"; then
|
||||
AC_DEFINE(DISABLE_SYSLOG,, Using syslog)
|
||||
AC_MSG_RESULT(Disabling syslog)
|
||||
else
|
||||
AC_MSG_RESULT(Enabling syslog)
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(Enabling syslog)
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(shadow,
|
||||
[ --disable-shadow Don't use shadow passwords (if available)],
|
||||
[
|
||||
if test "x$enableval" = "xno"; then
|
||||
AC_MSG_RESULT(Not using shadow passwords)
|
||||
else
|
||||
AC_CHECK_HEADERS([shadow.h])
|
||||
AC_MSG_RESULT(Using shadow passwords if available)
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_CHECK_HEADERS([shadow.h])
|
||||
AC_MSG_RESULT(Using shadow passwords if available)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h sys/dirent.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_TYPE_UID_T
|
||||
AC_TYPE_MODE_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_HEADER_TIME
|
||||
|
||||
AC_CHECK_TYPES([uint16_t, u_int16_t, struct sockaddr_storage])
|
||||
AC_CHECK_TYPE([socklen_t], ,[
|
||||
AC_MSG_CHECKING([for socklen_t equivalent])
|
||||
AC_CACHE_VAL([curl_cv_socklen_t_equiv],
|
||||
[
|
||||
# Systems have either "struct sockaddr *" or
|
||||
# "void *" as the second argument to getpeername
|
||||
curl_cv_socklen_t_equiv=
|
||||
for arg2 in "struct sockaddr" void; do
|
||||
for t in int size_t unsigned long "unsigned long"; do
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
int getpeername (int, $arg2 *, $t *);
|
||||
],[
|
||||
$t len;
|
||||
getpeername(0,0,&len);
|
||||
],[
|
||||
curl_cv_socklen_t_equiv="$t"
|
||||
break
|
||||
])
|
||||
done
|
||||
done
|
||||
|
||||
if test "x$curl_cv_socklen_t_equiv" = x; then
|
||||
AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
|
||||
fi
|
||||
])
|
||||
AC_MSG_RESULT($curl_cv_socklen_t_equiv)
|
||||
AC_DEFINE_UNQUOTED(socklen_t, $curl_cv_socklen_t_equiv,
|
||||
[type to use in place of socklen_t if not defined])],
|
||||
[#include <sys/types.h>
|
||||
#include <sys/socket.h>])
|
||||
|
||||
|
||||
# for loginrec.c
|
||||
|
||||
AC_CHECK_MEMBERS([struct utmp.ut_host, struct utmp.ut_pid, struct utmp.ut_type, struct utmp.ut_tv, struct utmp.ut_id, struct utmp.ut_addr, struct utmp.ut_addr_v6, struct utmp.ut_exit, struct utmp.ut_time],,,[
|
||||
#include <sys/types.h>
|
||||
#if HAVE_UTMP_H
|
||||
#include <utmp.h>
|
||||
#endif
|
||||
])
|
||||
|
||||
AC_CHECK_MEMBERS([struct utmpx.ut_host, struct utmpx.ut_syslen, struct utmpx.ut_type, struct utmpx.ut_id, struct utmpx.ut_addr, struct utmpx.ut_addr_v6, struct utmpx.ut_time, struct utmpx.ut_tv],,,[
|
||||
#include <sys/types.h>
|
||||
#if HAVE_UTMPX_H
|
||||
#include <utmpx.h>
|
||||
#endif
|
||||
])
|
||||
|
||||
AC_CHECK_FUNCS(endutent getutent getutid getutline pututline setutent)
|
||||
AC_CHECK_FUNCS(utmpname)
|
||||
AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
|
||||
AC_CHECK_FUNCS(setutxent utmpxname)
|
||||
AC_CHECK_FUNCS(logout updwtmp logwtmp)
|
||||
|
||||
dnl Added from OpenSSH 3.6.1p2's configure.ac
|
||||
|
||||
dnl allow user to disable some login recording features
|
||||
AC_ARG_ENABLE(lastlog,
|
||||
[ --disable-lastlog Disable use of lastlog even if detected [no]],
|
||||
[ AC_DEFINE(DISABLE_LASTLOG,,Disable use of lastlog()) ]
|
||||
)
|
||||
AC_ARG_ENABLE(utmp,
|
||||
[ --disable-utmp Disable use of utmp even if detected [no]],
|
||||
[ AC_DEFINE(DISABLE_UTMP,,Disable use of utmp) ]
|
||||
)
|
||||
AC_ARG_ENABLE(utmpx,
|
||||
[ --disable-utmpx Disable use of utmpx even if detected [no]],
|
||||
[ AC_DEFINE(DISABLE_UTMPX,,Disable use of utmpx) ]
|
||||
)
|
||||
AC_ARG_ENABLE(wtmp,
|
||||
[ --disable-wtmp Disable use of wtmp even if detected [no]],
|
||||
[ AC_DEFINE(DISABLE_WTMP,,Disable use of wtmp) ]
|
||||
)
|
||||
AC_ARG_ENABLE(wtmpx,
|
||||
[ --disable-wtmpx Disable use of wtmpx even if detected [no]],
|
||||
[ AC_DEFINE(DISABLE_WTMPX,,Disable use of wtmpx) ]
|
||||
)
|
||||
AC_ARG_ENABLE(loginfunc,
|
||||
[ --disable-loginfunc Disable use of login() etc. [no]],
|
||||
[ no_loginfunc_check=1
|
||||
AC_MSG_RESULT(Not using login() etc) ]
|
||||
)
|
||||
AC_ARG_ENABLE(pututline,
|
||||
[ --disable-pututline Disable use of pututline() etc. ([uw]tmp) [no]],
|
||||
[ AC_DEFINE(DISABLE_PUTUTLINE,,Disable use of pututline()) ]
|
||||
)
|
||||
AC_ARG_ENABLE(pututxline,
|
||||
[ --disable-pututxline Disable use of pututxline() etc. ([uw]tmpx) [no]],
|
||||
[ AC_DEFINE(DISABLE_PUTUTXLINE,,Disable use of pututxline()) ]
|
||||
)
|
||||
AC_ARG_WITH(lastlog,
|
||||
[ --with-lastlog=FILE|DIR specify lastlog location [common locations]],
|
||||
[
|
||||
if test "x$withval" = "xno" ; then
|
||||
AC_DEFINE(DISABLE_LASTLOG)
|
||||
else
|
||||
conf_lastlog_location=$withval
|
||||
fi
|
||||
]
|
||||
)
|
||||
|
||||
if test -z "$no_loginfunc_check"; then
|
||||
dnl Checks for libutil functions (login(), logout() etc, not openpty() )
|
||||
AC_SEARCH_LIBS(login, util bsd, [AC_DEFINE(HAVE_LOGIN,,Have login() function)])
|
||||
AC_CHECK_FUNCS(logout updwtmp logwtmp)
|
||||
fi
|
||||
|
||||
dnl lastlog, [uw]tmpx? detection
|
||||
dnl NOTE: set the paths in the platform section to avoid the
|
||||
dnl need for command-line parameters
|
||||
dnl lastlog and [uw]tmp are subject to a file search if all else fails
|
||||
|
||||
dnl lastlog detection
|
||||
dnl NOTE: the code itself will detect if lastlog is a directory
|
||||
AC_MSG_CHECKING([if your system defines LASTLOG_FILE])
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_LASTLOG_H
|
||||
# include <lastlog.h>
|
||||
#endif
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
#ifdef HAVE_LOGIN_H
|
||||
# include <login.h>
|
||||
#endif
|
||||
],
|
||||
[ char *lastlog = LASTLOG_FILE; ],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
AC_MSG_CHECKING([if your system defines _PATH_LASTLOG])
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_LASTLOG_H
|
||||
# include <lastlog.h>
|
||||
#endif
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
],
|
||||
[ char *lastlog = _PATH_LASTLOG; ],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
system_lastlog_path=no
|
||||
])
|
||||
]
|
||||
)
|
||||
|
||||
if test -z "$conf_lastlog_location"; then
|
||||
if test x"$system_lastlog_path" = x"no" ; then
|
||||
for f in /var/log/lastlog /usr/adm/lastlog /var/adm/lastlog /etc/security/lastlog ; do
|
||||
if (test -d "$f" || test -f "$f") ; then
|
||||
conf_lastlog_location=$f
|
||||
fi
|
||||
done
|
||||
if test -z "$conf_lastlog_location"; then
|
||||
AC_MSG_WARN([** Cannot find lastlog **])
|
||||
dnl Don't define DISABLE_LASTLOG - that means we don't try wtmp/wtmpx
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$conf_lastlog_location"; then
|
||||
AC_DEFINE_UNQUOTED(CONF_LASTLOG_FILE, "$conf_lastlog_location", lastlog file location)
|
||||
fi
|
||||
|
||||
dnl utmp detection
|
||||
AC_MSG_CHECKING([if your system defines UTMP_FILE])
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
],
|
||||
[ char *utmp = UTMP_FILE; ],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[ AC_MSG_RESULT(no)
|
||||
system_utmp_path=no ]
|
||||
)
|
||||
if test -z "$conf_utmp_location"; then
|
||||
if test x"$system_utmp_path" = x"no" ; then
|
||||
for f in /etc/utmp /usr/adm/utmp /var/run/utmp; do
|
||||
if test -f $f ; then
|
||||
conf_utmp_location=$f
|
||||
fi
|
||||
done
|
||||
if test -z "$conf_utmp_location"; then
|
||||
AC_DEFINE(DISABLE_UTMP)
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test -n "$conf_utmp_location"; then
|
||||
AC_DEFINE_UNQUOTED(CONF_UTMP_FILE, "$conf_utmp_location", utmp file location)
|
||||
fi
|
||||
|
||||
dnl wtmp detection
|
||||
AC_MSG_CHECKING([if your system defines WTMP_FILE])
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
],
|
||||
[ char *wtmp = WTMP_FILE; ],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[ AC_MSG_RESULT(no)
|
||||
system_wtmp_path=no ]
|
||||
)
|
||||
if test -z "$conf_wtmp_location"; then
|
||||
if test x"$system_wtmp_path" = x"no" ; then
|
||||
for f in /usr/adm/wtmp /var/log/wtmp; do
|
||||
if test -f $f ; then
|
||||
conf_wtmp_location=$f
|
||||
fi
|
||||
done
|
||||
if test -z "$conf_wtmp_location"; then
|
||||
AC_DEFINE(DISABLE_WTMP)
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test -n "$conf_wtmp_location"; then
|
||||
AC_DEFINE_UNQUOTED(CONF_WTMP_FILE, "$conf_wtmp_location", wtmp file location)
|
||||
fi
|
||||
|
||||
|
||||
dnl utmpx detection - I don't know any system so perverse as to require
|
||||
dnl utmpx, but not define UTMPX_FILE (ditto wtmpx.) No doubt it's out
|
||||
dnl there, though.
|
||||
AC_MSG_CHECKING([if your system defines UTMPX_FILE])
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_UTMPX_H
|
||||
#include <utmpx.h>
|
||||
#endif
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
],
|
||||
[ char *utmpx = UTMPX_FILE; ],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[ AC_MSG_RESULT(no)
|
||||
system_utmpx_path=no ]
|
||||
)
|
||||
if test -z "$conf_utmpx_location"; then
|
||||
if test x"$system_utmpx_path" = x"no" ; then
|
||||
AC_DEFINE(DISABLE_UTMPX)
|
||||
fi
|
||||
else
|
||||
AC_DEFINE_UNQUOTED(CONF_UTMPX_FILE, "$conf_utmpx_location", utmpx file location)
|
||||
fi
|
||||
|
||||
dnl wtmpx detection
|
||||
AC_MSG_CHECKING([if your system defines WTMPX_FILE])
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#ifdef HAVE_UTMPX_H
|
||||
#include <utmpx.h>
|
||||
#endif
|
||||
#ifdef HAVE_PATHS_H
|
||||
# include <paths.h>
|
||||
#endif
|
||||
],
|
||||
[ char *wtmpx = WTMPX_FILE; ],
|
||||
[ AC_MSG_RESULT(yes) ],
|
||||
[ AC_MSG_RESULT(no)
|
||||
system_wtmpx_path=no ]
|
||||
)
|
||||
if test -z "$conf_wtmpx_location"; then
|
||||
if test x"$system_wtmpx_path" = x"no" ; then
|
||||
AC_DEFINE(DISABLE_WTMPX)
|
||||
fi
|
||||
else
|
||||
AC_DEFINE_UNQUOTED(CONF_WTMPX_FILE, "$conf_wtmpx_location", wtmpx file location)
|
||||
fi
|
||||
|
||||
# Checks for library functions.
|
||||
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_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
|
||||
|
||||
# Solaris needs ptmx
|
||||
if test -z "$no_ptmx_check" ; then
|
||||
if test x"$cross_compiling" = x"no" ; then
|
||||
AC_CHECK_FILE("/dev/ptmx", AC_DEFINE(USE_DEV_PTMX,,Use /dev/ptmx))
|
||||
else
|
||||
AC_MSG_RESULT(Not checking for /dev/ptmx, we're cross-compiling)
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$no_ptc_check" ; then
|
||||
if test x"$cross_compiling" = x"no" ; then
|
||||
AC_CHECK_FILE("/dev/ptc", AC_DEFINE(HAVE_DEV_PTS_AND_PTC,,Use /dev/ptc & /dev/pts))
|
||||
else
|
||||
AC_MSG_RESULT(Not checking for /dev/ptc & /dev/pts\, we're cross-compiling)
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_OUTPUT(Makefile)
|
||||
AC_MSG_RESULT()
|
||||
AC_MSG_RESULT(Now edit options.h to choose features.)
|
||||
48
dbmulti.c
Normal file
48
dbmulti.c
Normal file
@@ -0,0 +1,48 @@
|
||||
#include "includes.h"
|
||||
|
||||
/* definitions are cleanest if we just put them here */
|
||||
int dropbear_main(int argc, char ** argv);
|
||||
int dropbearkey_main(int argc, char ** argv);
|
||||
int dropbearconvert_main(int argc, char ** argv);
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
|
||||
char * progname;
|
||||
|
||||
if (argc > 0) {
|
||||
/* figure which form we're being called as */
|
||||
progname = basename(argv[0]);
|
||||
|
||||
#ifdef DBMULTI_DROPBEAR
|
||||
if (strcmp(progname, "dropbear") == 0) {
|
||||
return dropbear_main(argc, argv);
|
||||
}
|
||||
#endif
|
||||
#ifdef DBMULTI_KEY
|
||||
if (strcmp(progname, "dropbearkey") == 0) {
|
||||
return dropbearkey_main(argc, argv);
|
||||
}
|
||||
#endif
|
||||
#ifdef DBMULTI_CONVERT
|
||||
if (strcmp(progname, "dropbearconvert") == 0) {
|
||||
return dropbearconvert_main(argc, argv);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
fprintf(stderr, "Dropbear multi-purpose version %s\n"
|
||||
"Make a symlink pointing at this binary with one of the following names:\n"
|
||||
#ifdef DBMULTI_DROPBEAR
|
||||
"'dropbear' - the Dropbear server\n"
|
||||
#endif
|
||||
#ifdef DBMULTI_KEY
|
||||
"'dropbearkey' - the key generator\n"
|
||||
#endif
|
||||
#ifdef DBMULTI_CONVERT
|
||||
"'dropbearconvert' - the key converter\n"
|
||||
#endif
|
||||
,
|
||||
DROPBEAR_VERSION);
|
||||
exit(1);
|
||||
|
||||
}
|
||||
296
dbutil.c
Normal file
296
dbutil.c
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* strlcat() is copyright as follows:
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
* 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "buffer.h"
|
||||
#include "session.h"
|
||||
#include "atomicio.h"
|
||||
|
||||
#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;
|
||||
|
||||
int usingsyslog = 0; /* set by runopts, but required externally to sessions */
|
||||
#ifndef DISABLE_SYSLOG
|
||||
void startsyslog() {
|
||||
|
||||
openlog(PROGNAME, LOG_PID, LOG_AUTHPRIV);
|
||||
|
||||
}
|
||||
#endif /* DISABLE_SYSLOG */
|
||||
|
||||
/* the "format" string must be <= 100 characters */
|
||||
void dropbear_close(const char* format, ...) {
|
||||
|
||||
va_list param;
|
||||
|
||||
va_start(param, format);
|
||||
_dropbear_exit(EXIT_SUCCESS, format, param);
|
||||
va_end(param);
|
||||
|
||||
}
|
||||
|
||||
void dropbear_exit(const char* format, ...) {
|
||||
|
||||
va_list param;
|
||||
|
||||
va_start(param, format);
|
||||
_dropbear_exit(EXIT_FAILURE, format, param);
|
||||
va_end(param);
|
||||
}
|
||||
|
||||
|
||||
/* this is what can be called to write arbitrary log messages */
|
||||
void dropbear_log(int priority, const char* format, ...) {
|
||||
|
||||
va_list param;
|
||||
|
||||
va_start(param, format);
|
||||
_dropbear_log(priority, format, param);
|
||||
va_end(param);
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
void dropbear_trace(const char* format, ...) {
|
||||
|
||||
va_list param;
|
||||
|
||||
va_start(param, format);
|
||||
fprintf(stderr, "TRACE: ");
|
||||
vfprintf(stderr, format, param);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(param);
|
||||
}
|
||||
#endif /* DEBUG_TRACE */
|
||||
|
||||
/* Return a string representation of the socket address passed. The return
|
||||
* value is allocated with malloc() */
|
||||
unsigned char * getaddrstring(struct sockaddr * addr) {
|
||||
|
||||
char *retstring;
|
||||
|
||||
/* space for "255.255.255.255:65535\0" = 22 */
|
||||
retstring = m_malloc(22);
|
||||
|
||||
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");
|
||||
|
||||
}
|
||||
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) {
|
||||
|
||||
struct hostent *host = NULL;
|
||||
char * retstring;
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
return strdup(retstring);
|
||||
}
|
||||
#ifdef DEBUG_TRACE
|
||||
void printhex(unsigned char* buf, int len) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
fprintf(stderr, "%02x", buf[i]);
|
||||
if (i % 16 == 15) {
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
else if (i % 2 == 1) {
|
||||
fprintf(stderr, " ");
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Strip all control characters from text (a null-terminated string), except
|
||||
* for '\n', '\r' and '\t'.
|
||||
* The result returned is a newly allocated string, this must be free()d after
|
||||
* use */
|
||||
char * stripcontrol(const char * text) {
|
||||
|
||||
char * ret;
|
||||
int len, pos;
|
||||
int i;
|
||||
|
||||
len = strlen(text);
|
||||
ret = m_malloc(len+1);
|
||||
|
||||
pos = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
if ((text[i] <= '~' && text[i] >= ' ') /* normal printable range */
|
||||
|| text[i] == '\n' || text[i] == '\r' || text[i] == '\t') {
|
||||
ret[pos] = text[i];
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
ret[pos] = 0x0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* reads the contents of filename into the buffer buf, from the current
|
||||
* position, either to the end of the file, or the buffer being full.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_readfile(buffer* buf, const char* filename) {
|
||||
|
||||
int fd;
|
||||
int len;
|
||||
int maxlen;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
|
||||
if (fd < 0) {
|
||||
close(fd);
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
do {
|
||||
maxlen = buf->size - buf->pos;
|
||||
len = read(fd, buf_getwriteptr(buf, maxlen),
|
||||
maxlen);
|
||||
buf_incrwritepos(buf, len);
|
||||
} while (len < maxlen && len > 0);
|
||||
|
||||
close(fd);
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* loop until the socket is closed (in case of EINTR) or
|
||||
* we get and error.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int m_close(int fd) {
|
||||
|
||||
int val;
|
||||
do {
|
||||
val = close(fd);
|
||||
} while (val < 0 && errno == EINTR);
|
||||
|
||||
if (val == 0 || errno == EBADF) {
|
||||
return DROPBEAR_SUCCESS;
|
||||
} else {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
void * m_malloc(size_t size) {
|
||||
|
||||
void* ret;
|
||||
|
||||
if (size == 0) {
|
||||
dropbear_exit("m_malloc failed");
|
||||
}
|
||||
ret = malloc(size);
|
||||
if (ret == NULL) {
|
||||
dropbear_exit("m_malloc failed");
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void __m_free(void* ptr) {
|
||||
if (ptr != NULL) {
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void * m_realloc(void* ptr, size_t size) {
|
||||
|
||||
void *ret;
|
||||
|
||||
if (size == 0) {
|
||||
dropbear_exit("m_realloc failed");
|
||||
}
|
||||
ret = realloc(ptr, size);
|
||||
if (ret == NULL) {
|
||||
dropbear_exit("m_realloc failed");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Clear the data, based on the method in David Wheeler's
|
||||
* "Secure Programming for Linux and Unix HOWTO" */
|
||||
void m_burn(void *data, unsigned int len) {
|
||||
volatile char *p = data;
|
||||
|
||||
if (data == NULL)
|
||||
return;
|
||||
while (len--) {
|
||||
*p++ = 0x66;
|
||||
}
|
||||
}
|
||||
59
dbutil.h
Normal file
59
dbutil.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _DBUTIL_H_
|
||||
|
||||
#define _DBUTIL_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#ifndef DISABLE_SYSLOG
|
||||
void startsyslog();
|
||||
#endif
|
||||
extern int usingsyslog;
|
||||
|
||||
extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param);
|
||||
extern void (*_dropbear_log)(int priority, const char* format, va_list param);
|
||||
|
||||
void dropbear_exit(const char* format, ...);
|
||||
void dropbear_close(const char* format, ...);
|
||||
void dropbear_log(int priority, const char* format, ...);
|
||||
#ifdef DEBUG_TRACE
|
||||
void dropbear_trace(const char* format, ...);
|
||||
void printhex(unsigned char* buf, int len);
|
||||
#endif
|
||||
char * stripcontrol(const char * text);
|
||||
unsigned char * getaddrstring(struct sockaddr * addr);
|
||||
char* getaddrhostname(struct sockaddr * addr);
|
||||
int buf_readfile(buffer* buf, const char* filename);
|
||||
|
||||
int m_close(int fd);
|
||||
void * m_malloc(size_t size);
|
||||
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);
|
||||
|
||||
#endif /* _DBUTIL_H_ */
|
||||
41
debian/README.Debian
vendored
Normal file
41
debian/README.Debian
vendored
Normal 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
|
||||
|
||||
79
debian/changelog
vendored
Normal file
79
debian/changelog
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
dropbear (0.41-1) unstable; urgency=low
|
||||
|
||||
* Updated to 0.41 release.
|
||||
* Various minor fixes
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Mon, 19 Jan 2004 23:20:54 +0800
|
||||
|
||||
dropbear (0.39-1) unstable; urgency=low
|
||||
|
||||
* updated to 0.39 release. Some new features, some bugfixes.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Tue, 16 Dec 2003 16:20:54 +0800
|
||||
|
||||
dropbear (0.38-1) unstable; urgency=medium
|
||||
|
||||
* updated to 0.38 release - various important bugfixes
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Sat, 11 Oct 2003 16:28:54 +0800
|
||||
|
||||
dropbear (0.37-1) unstable; urgency=medium
|
||||
|
||||
* updated to 0.37 release - various important bugfixes
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 24 Sept 2003 19:43:54 +0800
|
||||
|
||||
dropbear (0.36-1) unstable; urgency=high
|
||||
|
||||
* updated to 0.36 release - various important bugfixes
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Tues, 19 Aug 2003 12:20:54 +0800
|
||||
|
||||
dropbear (0.35-1) unstable; urgency=high
|
||||
|
||||
* updated to 0.35 release - contains fix for remotely exploitable
|
||||
vulnerability.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Sun, 17 Aug 2003 05:37:47 +0800
|
||||
|
||||
dropbear (0.34-1) unstable; urgency=medium
|
||||
|
||||
* updated to 0.34 release
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Fri, 15 Aug 2003 15:10:00 +0800
|
||||
|
||||
dropbear (0.33-1) unstable; urgency=medium
|
||||
|
||||
* updated to 0.33 release
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Sun, 22 Jun 2003 22:22:00 +0800
|
||||
|
||||
dropbear (0.32cvs-1) unstable; urgency=medium
|
||||
|
||||
* now maintained in UCC CVS
|
||||
* debian/copyright.in file added, generated from LICENSE
|
||||
|
||||
-- Grahame Bowland <grahame@angrygoats.net> Tue, 21 Jun 2003 17:57:02 +0800
|
||||
|
||||
dropbear (0.32cvs-1) unstable; urgency=medium
|
||||
|
||||
* sync with CVS
|
||||
* fixes X crash bug
|
||||
|
||||
-- Grahame Bowland <grahame@angrygoats.net> Tue, 20 Jun 2003 15:04:47 +0800
|
||||
|
||||
dropbear (0.32-2) unstable; urgency=low
|
||||
|
||||
* fix creation of host keys to use correct names in /etc/dropbear
|
||||
* init script "restart" function fixed
|
||||
* purging this package now deletes the host keys and /etc/dropbear
|
||||
* change priority in debian/control to 'standard'
|
||||
|
||||
-- Grahame Bowland <grahame@angrygoats.net> Tue, 17 Jun 2003 15:04:47 +0800
|
||||
|
||||
dropbear (0.32-1) unstable; urgency=low
|
||||
|
||||
* Initial Release.
|
||||
|
||||
-- Grahame Bowland <grahame@angrygoats.net> Tue, 17 Jun 2003 15:04:47 +0800
|
||||
|
||||
1
debian/compat
vendored
Normal file
1
debian/compat
vendored
Normal file
@@ -0,0 +1 @@
|
||||
4
|
||||
0
debian/conffiles
vendored
Normal file
0
debian/conffiles
vendored
Normal file
14
debian/control
vendored
Normal file
14
debian/control
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
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
|
||||
|
||||
Package: dropbear
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends} ${misc:Depends}
|
||||
Suggests: ssh
|
||||
Description: a minimal SSH2 server
|
||||
A small secure shell version 2 server.
|
||||
|
||||
9
debian/copyright.in
vendored
Normal file
9
debian/copyright.in
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
This package was debianized by Grahame Bowland <grahame.angrygoats.net> on
|
||||
Tue, 17 Jun 2003 15:04:47 +0800.
|
||||
|
||||
It was downloaded from http://matt.ucc.asn.au/dropbear/
|
||||
|
||||
Upstream Author(s): Matt Johnston <matt@ucc.asn.au>
|
||||
|
||||
Copyright:
|
||||
|
||||
2
debian/dirs
vendored
Normal file
2
debian/dirs
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
usr/bin
|
||||
usr/sbin
|
||||
2
debian/docs
vendored
Normal file
2
debian/docs
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
README
|
||||
TODO
|
||||
0
debian/dropbear.default
vendored
Normal file
0
debian/dropbear.default
vendored
Normal file
78
debian/dropbear.init
vendored
Normal file
78
debian/dropbear.init
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
#! /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
|
||||
#
|
||||
|
||||
#
|
||||
# Do not configure this file. Edit /etc/default/dropbear instead!
|
||||
#
|
||||
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
DAEMON=/usr/sbin/dropbear
|
||||
NAME=dropbear
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
echo "$NAME."
|
||||
;;
|
||||
stop)
|
||||
echo -n "Stopping $DESC: "
|
||||
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
|
||||
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
|
||||
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
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
90
debian/postinst
vendored
Normal file
90
debian/postinst
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
#! /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
Normal file
45
debian/postrm
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
#! /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
|
||||
134
debian/rules
vendored
Normal file
134
debian/rules
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
#!/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
|
||||
|
||||
# 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
|
||||
|
||||
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
|
||||
CFLAGS += -O0
|
||||
else
|
||||
CFLAGS += -O2
|
||||
endif
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
INSTALL_PROGRAM += -s
|
||||
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
|
||||
endif
|
||||
|
||||
|
||||
dh_clean
|
||||
|
||||
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
|
||||
|
||||
install-arch:
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_clean -k -a
|
||||
dh_installdirs -a
|
||||
dh_installdirs /etc/dropbear
|
||||
|
||||
# Add here commands to install the arch part of the package into
|
||||
# debian/tmp.
|
||||
$(MAKE) install prefix=$(CURDIR)/debian/dropbear/usr
|
||||
|
||||
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
|
||||
|
||||
# Build architecture dependant packages using the common target.
|
||||
binary-arch: build-arch install-arch
|
||||
$(MAKE) -f debian/rules DH_OPTIONS=-a binary-common
|
||||
|
||||
binary: binary-arch #binary-indep
|
||||
.PHONY: build clean binary-indep binary-arch binary install install-indep install-arch
|
||||
68
debug.h
Normal file
68
debug.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _DEBUG_H_
|
||||
#define _DEBUG_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
/* Debugging */
|
||||
|
||||
/* Work well for valgrind - don't clear environment, be nicer with signals
|
||||
* etc. Don't use this normally, it might cause problems */
|
||||
/* #define DEBUG_VALGRIND */
|
||||
|
||||
/* Define this to print trace statements - very verbose */
|
||||
/* #define DEBUG_TRACE */
|
||||
|
||||
/* All functions writing to the cleartext payload buffer call
|
||||
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're
|
||||
* attempting to track down a problem */
|
||||
#define CHECKCLEARTOWRITE() assert(ses.writepayload->len == 0 && \
|
||||
ses.writepayload->pos == 0)
|
||||
|
||||
/* 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 */
|
||||
/*#define DEBUG_FORKGPROF*/
|
||||
|
||||
/* A couple of flags, not usually useful, and mightn't do anything */
|
||||
|
||||
/*#define DEBUG_KEXHASH*/
|
||||
/*#define DEBUG_RSA*/
|
||||
|
||||
/* you don't need to touch this block */
|
||||
#ifdef DEBUG_TRACE
|
||||
#define TRACE(X) (dropbear_trace X)
|
||||
#else /*DEBUG_TRACE*/
|
||||
#define TRACE(X)
|
||||
#endif /*DEBUG_TRACE*/
|
||||
|
||||
/* For testing as non-root on shadowed systems, include the crypt of a password
|
||||
* here. You can then log in as any user with this password. Ensure that you
|
||||
* make your own password, and are careful about using this. This will also
|
||||
* disable some of the chown pty code etc*/
|
||||
/* #define DEBUG_HACKCRYPT "hL8nrFDt0aJ3E" */ /* this is crypt("password") */
|
||||
|
||||
#endif
|
||||
146
dropbearconvert.c
Normal file
146
dropbearconvert.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
/* This program converts to/from Dropbear and OpenSSH private-key formats */
|
||||
#include "includes.h"
|
||||
#include "signkey.h"
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "keyimport.h"
|
||||
|
||||
|
||||
static int do_convert(int intype, const char* infile, int outtype,
|
||||
const char* outfile);
|
||||
|
||||
static void printhelp(char * progname);
|
||||
|
||||
static void printhelp(char * progname) {
|
||||
|
||||
fprintf(stderr, "Usage: %s <inputtype> <outputtype> <inputfile> <outputfile>\n\n"
|
||||
"CAUTION: This program is for convenience only, and is not secure if used on\n"
|
||||
"untrusted input files, ie it could allow arbitrary code execution.\n"
|
||||
"All parameters must be specified in order.\n"
|
||||
"\n"
|
||||
"The input and output types are one of:\n"
|
||||
"openssh\n"
|
||||
"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);
|
||||
}
|
||||
|
||||
#if defined(DBMULTI_CONVERT) || !defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_CONVERT) && defined(DROPBEAR_MULTI)
|
||||
int dropbearconvert_main(int argc, char ** argv) {
|
||||
#else
|
||||
int main(int argc, char ** argv) {
|
||||
#endif
|
||||
|
||||
int intype, outtype;
|
||||
const char* infile;
|
||||
const char* outfile;
|
||||
|
||||
/* get the commandline options */
|
||||
if (argc != 5) {
|
||||
fprintf(stderr, "All arguments must be specified\n");
|
||||
goto usage;
|
||||
}
|
||||
|
||||
/* input type */
|
||||
if (argv[1][0] == 'd') {
|
||||
intype = KEYFILE_DROPBEAR;
|
||||
} else if (argv[1][0] == 'o') {
|
||||
intype = KEYFILE_OPENSSH;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid input key type\n");
|
||||
goto usage;
|
||||
}
|
||||
|
||||
/* output type */
|
||||
if (argv[2][0] == 'd') {
|
||||
outtype = KEYFILE_DROPBEAR;
|
||||
} else if (argv[2][0] == 'o') {
|
||||
outtype = KEYFILE_OPENSSH;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid output key type\n");
|
||||
goto usage;
|
||||
}
|
||||
|
||||
/* we don't want output readable by others */
|
||||
umask(077);
|
||||
|
||||
infile = argv[3];
|
||||
outfile = argv[4];
|
||||
|
||||
return do_convert(intype, infile, outtype, outfile);
|
||||
|
||||
usage:
|
||||
printhelp(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int do_convert(int intype, const char* infile, int outtype,
|
||||
const char* outfile) {
|
||||
|
||||
sign_key * key = NULL;
|
||||
char * keytype = NULL;
|
||||
int ret = 1;
|
||||
|
||||
key = import_read(infile, NULL, intype);
|
||||
if (!key) {
|
||||
fprintf(stderr, "Error reading key from '%s'\n",
|
||||
infile);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (key->rsakey != NULL) {
|
||||
keytype = "RSA";
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (key->dsskey != NULL) {
|
||||
keytype = "DSS";
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "Key is a %s key\n", keytype);
|
||||
|
||||
if (import_write(outfile, key, NULL, outtype) != 1) {
|
||||
fprintf(stderr, "Error writing key to '%s'\n", outfile);
|
||||
} else {
|
||||
fprintf(stderr, "Wrote key to '%s'\n", outfile);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
if (key) {
|
||||
sign_key_free(key);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
272
dropbearkey.c
Normal file
272
dropbearkey.c
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
/* The format of the keyfiles is basically a raw dump of the buffer. Data types
|
||||
* are specified in the transport draft - string is a 32-bit len then the
|
||||
* non-null-terminated string, mp_int is a 32-bit len then the bignum data.
|
||||
* The actual functions are buf_put_rsa_priv_key() and buf_put_dss_priv_key()
|
||||
|
||||
* RSA:
|
||||
* string "ssh-rsa"
|
||||
* mp_int e
|
||||
* mp_int n
|
||||
* mp_int d
|
||||
* mp_int p (newer versions only)
|
||||
* mp_int q (newer versions only)
|
||||
*
|
||||
* DSS:
|
||||
* string "ssh-dss"
|
||||
* mp_int p
|
||||
* mp_int q
|
||||
* mp_int g
|
||||
* mp_int y
|
||||
* mp_int x
|
||||
*
|
||||
*/
|
||||
#include "includes.h"
|
||||
#include "runopts.h"
|
||||
#include "signkey.h"
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
#include "genrsa.h"
|
||||
#include "gendss.h"
|
||||
|
||||
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);
|
||||
|
||||
/* 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"
|
||||
#ifdef DROPBEAR_RSA
|
||||
" rsa\n"
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
" 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);
|
||||
}
|
||||
|
||||
#if defined(DBMULTI_KEY) || !defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_KEY) && defined(DROPBEAR_MULTI)
|
||||
int dropbearkey_main(int argc, char ** argv) {
|
||||
#else
|
||||
int main(int argc, char ** argv) {
|
||||
#endif
|
||||
|
||||
int i;
|
||||
char ** next = 0;
|
||||
sign_key *key;
|
||||
buffer *buf;
|
||||
char * filename = NULL;
|
||||
int keytype = -1;
|
||||
char * typetext = NULL;
|
||||
char * sizetext = NULL;
|
||||
unsigned int bits;
|
||||
unsigned int keysize;
|
||||
|
||||
/* get the commandline options */
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (next) {
|
||||
*next = argv[i];
|
||||
if (*next == NULL) {
|
||||
fprintf(stderr, "Invalid null argument");
|
||||
}
|
||||
next = 0x00;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argv[i][0] == '-') {
|
||||
switch (argv[i][1]) {
|
||||
case 'f':
|
||||
next = &filename;
|
||||
break;
|
||||
case 't':
|
||||
next = &typetext;
|
||||
break;
|
||||
case 's':
|
||||
next = &sizetext;
|
||||
break;
|
||||
case 'h':
|
||||
printhelp(argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown argument %s\n", argv[i]);
|
||||
printhelp(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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"
|
||||
);
|
||||
printhelp(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (strlen(typetext) == 3) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (strncmp(typetext, "rsa", 3) == 0) {
|
||||
keytype = DROPBEAR_SIGNKEY_RSA;
|
||||
TRACE(("type is rsa"));
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (strncmp(typetext, "dss", 3) == 0) {
|
||||
keytype = DROPBEAR_SIGNKEY_DSS;
|
||||
TRACE(("type is dss"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (keytype == -1) {
|
||||
fprintf(stderr, "Unknown key type '%s'\n", typetext);
|
||||
printhelp(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (sizetext) {
|
||||
if (sscanf(sizetext, "%u", &bits) != 1) {
|
||||
fprintf(stderr, "Bits must be an integer\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
|
||||
fprintf(stderr, "Bits must satisfy 512 <= bits <= 4096, and be a"
|
||||
" multiple of 8\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
keysize = bits / 8;
|
||||
} else {
|
||||
if (keytype == DROPBEAR_SIGNKEY_DSS) {
|
||||
keysize = DSS_SIZE;
|
||||
} else if (keytype == DROPBEAR_SIGNKEY_RSA) {
|
||||
keysize = RSA_SIZE;
|
||||
} else {
|
||||
exit(EXIT_FAILURE); /* not reached */
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* don't want the file readable by others */
|
||||
umask(077);
|
||||
|
||||
/* now we can generate the key */
|
||||
key = new_sign_key();
|
||||
|
||||
fprintf(stderr, "Generating key, this may take a while...\n");
|
||||
switch(keytype) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
key->rsakey = gen_rsa_priv_key(keysize); /* 128 bytes = 1024 bit */
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
key->dsskey = gen_dss_priv_key(keysize); /* 128 bytes = 1024 bit */
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
fprintf(stderr, "Internal error, bad key type\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
buf = buf_new(BUF_SIZE);
|
||||
|
||||
buf_put_priv_key(buf, key, keytype);
|
||||
buf_setpos(buf, 0);
|
||||
buf_writefile(buf, filename);
|
||||
|
||||
buf_burn(buf);
|
||||
buf_free(buf);
|
||||
sign_key_free(key);
|
||||
|
||||
fprintf(stderr, "Done.\n");
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Write a buffer to a file specified, failing if the file exists */
|
||||
static void buf_writefile(buffer * buf, const char * filename) {
|
||||
|
||||
int fd;
|
||||
int len;
|
||||
|
||||
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Couldn't create new file %s\n", filename);
|
||||
perror("Reason");
|
||||
buf_burn(buf);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* write the file now */
|
||||
while (buf->pos != buf->len) {
|
||||
len = write(fd, buf_getptr(buf, buf->len - buf->pos),
|
||||
buf->len - buf->pos);
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (len <= 0) {
|
||||
fprintf(stderr, "Failed writing file '%s'\n",filename);
|
||||
perror("Reason");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
buf_incrpos(buf, len);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
399
dss.c
Normal file
399
dss.c
Normal file
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "bignum.h"
|
||||
#include "dss.h"
|
||||
#include "buffer.h"
|
||||
#include "ssh.h"
|
||||
#include "random.h"
|
||||
|
||||
/* Handle DSS (Digital Signature Standard), aka DSA (D.S. Algorithm),
|
||||
* operations, such as key reading, signing, verification. Key generation
|
||||
* is in gendss.c, since it isn't required in the server itself.
|
||||
*
|
||||
* See FIPS186 or the Handbook of Applied Cryptography for details of the
|
||||
* algorithm */
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
|
||||
/* Load a dss key from a buffer, initialising the values.
|
||||
* The key will have the same format as buf_put_dss_key.
|
||||
* These should be freed with dss_key_free.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_dss_pub_key(buffer* buf, dss_key *key) {
|
||||
|
||||
assert(key != NULL);
|
||||
key->p = m_malloc(sizeof(mp_int));
|
||||
key->q = m_malloc(sizeof(mp_int));
|
||||
key->g = m_malloc(sizeof(mp_int));
|
||||
key->y = m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(key->p, key->q, key->g, key->y, NULL);
|
||||
key->x = NULL;
|
||||
|
||||
buf_incrpos(buf, 4+SSH_SIGNKEY_DSS_LEN); /* int + "ssh-dss" */
|
||||
if (buf_getmpint(buf, key->p) == DROPBEAR_FAILURE
|
||||
|| buf_getmpint(buf, key->q) == DROPBEAR_FAILURE
|
||||
|| buf_getmpint(buf, key->g) == DROPBEAR_FAILURE
|
||||
|| buf_getmpint(buf, key->y) == DROPBEAR_FAILURE) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
if (mp_count_bits(key->p) < MIN_DSS_KEYLEN) {
|
||||
dropbear_log(LOG_WARNING, "DSS key too short");
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* Same as buf_get_dss_pub_key, but reads a private "x" key at the end.
|
||||
* Loads a private dss key from a buffer
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_dss_priv_key(buffer* buf, dss_key *key) {
|
||||
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
assert(key != NULL);
|
||||
|
||||
ret = buf_get_dss_pub_key(buf, key);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
key->x = m_malloc(sizeof(mp_int));
|
||||
m_mp_init(key->x);
|
||||
ret = buf_getmpint(buf, key->x);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Clear and free the memory used by a public or private key */
|
||||
void dss_key_free(dss_key *key) {
|
||||
|
||||
TRACE(("enter dsa_key_free"));
|
||||
if (key == NULL) {
|
||||
TRACE(("enter dsa_key_free: key == NULL"));
|
||||
return;
|
||||
}
|
||||
if (key->p) {
|
||||
mp_clear(key->p);
|
||||
m_free(key->p);
|
||||
}
|
||||
if (key->q) {
|
||||
mp_clear(key->q);
|
||||
m_free(key->q);
|
||||
}
|
||||
if (key->g) {
|
||||
mp_clear(key->g);
|
||||
m_free(key->g);
|
||||
}
|
||||
if (key->y) {
|
||||
mp_clear(key->y);
|
||||
m_free(key->y);
|
||||
}
|
||||
if (key->x) {
|
||||
mp_clear(key->x);
|
||||
m_free(key->x);
|
||||
}
|
||||
m_free(key);
|
||||
TRACE(("leave dsa_key_free"));
|
||||
}
|
||||
|
||||
/* put the dss public key into the buffer in the required format:
|
||||
*
|
||||
* string "ssh-dss"
|
||||
* mpint p
|
||||
* mpint q
|
||||
* mpint g
|
||||
* mpint y
|
||||
*/
|
||||
void buf_put_dss_pub_key(buffer* buf, dss_key *key) {
|
||||
|
||||
assert(key != NULL);
|
||||
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
|
||||
buf_putmpint(buf, key->p);
|
||||
buf_putmpint(buf, key->q);
|
||||
buf_putmpint(buf, key->g);
|
||||
buf_putmpint(buf, key->y);
|
||||
|
||||
}
|
||||
|
||||
/* Same as buf_put_dss_pub_key, but with the private "x" key appended */
|
||||
void buf_put_dss_priv_key(buffer* buf, dss_key *key) {
|
||||
|
||||
assert(key != NULL);
|
||||
buf_put_dss_pub_key(buf, key);
|
||||
buf_putmpint(buf, key->x);
|
||||
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
/* Verify a DSS signature (in buf) made on data by the key given.
|
||||
* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
unsigned char msghash[SHA1_HASH_SIZE];
|
||||
hash_state hs;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
mp_int val1, val2, val3, val4;
|
||||
char * string = NULL;
|
||||
int stringlen;
|
||||
|
||||
TRACE(("enter buf_dss_verify"));
|
||||
assert(key != NULL);
|
||||
|
||||
/* get blob, check length */
|
||||
string = buf_getstring(buf, &stringlen);
|
||||
if (stringlen != 2*SHA1_HASH_SIZE) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* hash the data */
|
||||
sha1_init(&hs);
|
||||
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' */
|
||||
if (mp_read_unsigned_bin(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE)
|
||||
!= MP_OKAY) {
|
||||
goto out;
|
||||
}
|
||||
if (mp_cmp(&val1, key->q) != MP_LT) {
|
||||
TRACE(("verify failed, s' >= q"));
|
||||
goto out;
|
||||
}
|
||||
/* let val2 = w = (s')^-1 mod q*/
|
||||
if (mp_invmod(&val1, key->q, &val2) != MP_OKAY) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* u1 = ((SHA(M')w) mod q */
|
||||
/* let val1 = SHA(M') = msghash */
|
||||
if (mp_read_unsigned_bin(&val1, msghash, SHA1_HASH_SIZE) != MP_OKAY) {
|
||||
goto out;
|
||||
}
|
||||
/* let val3 = u1 = ((SHA(M')w) mod q */
|
||||
if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* u2 = ((r')w) mod q */
|
||||
/* let val1 = r' */
|
||||
if (mp_read_unsigned_bin(&val1, &string[0], SHA1_HASH_SIZE)
|
||||
!= MP_OKAY) {
|
||||
goto out;
|
||||
}
|
||||
if (mp_cmp(&val1, key->q) != MP_LT) {
|
||||
TRACE(("verify failed, r' >= q"));
|
||||
goto out;
|
||||
}
|
||||
/* let val4 = u2 = ((r')w) mod q */
|
||||
if (mp_mulmod(&val1, &val2, key->q, &val4) != MP_OKAY) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* v = (((g)^u1 (y)^u2) mod p) mod q */
|
||||
/* val2 = g^u1 mod p */
|
||||
if (mp_exptmod(key->g, &val3, key->p, &val2) != MP_OKAY) {
|
||||
goto out;
|
||||
}
|
||||
/* val3 = y^u2 mod p */
|
||||
if (mp_exptmod(key->y, &val4, key->p, &val3) != MP_OKAY) {
|
||||
goto out;
|
||||
}
|
||||
/* val4 = ((g)^u1 (y)^u2) mod p */
|
||||
if (mp_mulmod(&val2, &val3, key->p, &val4) != MP_OKAY) {
|
||||
goto out;
|
||||
}
|
||||
/* val2 = v = (((g)^u1 (y)^u2) mod p) mod q */
|
||||
if (mp_mod(&val4, key->q, &val2) != MP_OKAY) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* check whether signatures verify */
|
||||
if (mp_cmp(&val2, &val1) == MP_EQ) {
|
||||
/* good sig */
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
out:
|
||||
mp_clear_multi(&val1, &val2, &val3, &val4, NULL);
|
||||
m_free(string);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
/* Sign the data presented with key, writing the signature contents
|
||||
* to the buffer
|
||||
*
|
||||
* When DSS_PROTOK is #defined:
|
||||
* The alternate k generation method is based on the method used in PuTTY.
|
||||
* In particular to avoid being vulnerable to attacks using flaws in random
|
||||
* generation of k, we use the following:
|
||||
*
|
||||
* proto_k = SHA512 ( SHA512(x) || SHA160(message) )
|
||||
* k = proto_k mod q
|
||||
*
|
||||
* Now we aren't relying on the random number generation to protect the private
|
||||
* key x, which is a long term secret */
|
||||
void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
unsigned char msghash[SHA1_HASH_SIZE];
|
||||
unsigned int writelen;
|
||||
unsigned int i;
|
||||
#ifdef DSS_PROTOK
|
||||
unsigned char privkeyhash[SHA512_HASH_SIZE];
|
||||
unsigned char *privkeytmp;
|
||||
unsigned char proto_k[SHA512_HASH_SIZE];
|
||||
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;
|
||||
hash_state hs;
|
||||
|
||||
TRACE(("enter buf_put_dss_sign"));
|
||||
assert(key != NULL);
|
||||
|
||||
/* hash the data */
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, data, len);
|
||||
sha1_done(&hs, msghash);
|
||||
|
||||
m_mp_init_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
|
||||
&dss_m, NULL);
|
||||
#ifdef DSS_PROTOK
|
||||
/* hash the privkey */
|
||||
privkeytmp = mptobytes(key->x, &i);
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs, "the quick brown fox jumped over the lazy dog", 44);
|
||||
sha512_process(&hs, privkeytmp, i);
|
||||
sha512_done(&hs, privkeyhash);
|
||||
m_burn(privkeytmp, i);
|
||||
m_free(privkeytmp);
|
||||
|
||||
/* calculate proto_k */
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs, privkeyhash, SHA512_HASH_SIZE);
|
||||
sha512_process(&hs, msghash, SHA1_HASH_SIZE);
|
||||
sha512_done(&hs, proto_k);
|
||||
|
||||
/* generate k */
|
||||
m_mp_init(&dss_protok);
|
||||
bytestomp(&dss_protok, proto_k, SHA512_HASH_SIZE);
|
||||
mp_mod(&dss_protok, key->q, &dss_k);
|
||||
mp_clear(&dss_protok);
|
||||
m_burn(proto_k, SHA512_HASH_SIZE);
|
||||
#else /* DSS_PROTOK not defined*/
|
||||
do {
|
||||
genrandom(kbuf, SHA1_HASH_SIZE);
|
||||
if (mp_read_unsigned_bin(&dss_k, kbuf, SHA1_HASH_SIZE) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
}
|
||||
} while (mp_cmp(&dss_k, key->q) == MP_GT || mp_cmp_d(&dss_k, 0) != MP_GT);
|
||||
m_burn(kbuf, SHA1_HASH_SIZE);
|
||||
#endif
|
||||
|
||||
/* now generate the actual signature */
|
||||
bytestomp(&dss_m, msghash, SHA1_HASH_SIZE);
|
||||
|
||||
/* g^k mod p */
|
||||
if (mp_exptmod(key->g, &dss_k, key->p, &dss_temp1) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
}
|
||||
/* r = (g^k mod p) mod q */
|
||||
if (mp_mod(&dss_temp1, key->q, &dss_r) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
}
|
||||
|
||||
/* x*r mod q */
|
||||
if (mp_mulmod(&dss_r, key->x, key->q, &dss_temp1) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
}
|
||||
/* (SHA1(M) + xr) mod q) */
|
||||
if (mp_addmod(&dss_m, &dss_temp1, key->q, &dss_temp2) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
}
|
||||
|
||||
/* (k^-1) mod q */
|
||||
if (mp_invmod(&dss_k, key->q, &dss_temp1) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
}
|
||||
|
||||
/* s = (k^-1(SHA1(M) + xr)) mod q */
|
||||
if (mp_mulmod(&dss_temp1, &dss_temp2, key->q, &dss_s) != MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
}
|
||||
|
||||
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
|
||||
buf_putint(buf, 2*SHA1_HASH_SIZE);
|
||||
|
||||
writelen = mp_unsigned_bin_size(&dss_r);
|
||||
assert(writelen <= SHA1_HASH_SIZE);
|
||||
/* need to pad to 160 bits with leading zeros */
|
||||
for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
|
||||
buf_putbyte(buf, 0);
|
||||
}
|
||||
if (mp_to_unsigned_bin(&dss_r, buf_getwriteptr(buf, writelen))
|
||||
!= MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
}
|
||||
mp_clear(&dss_r);
|
||||
buf_incrwritepos(buf, writelen);
|
||||
|
||||
writelen = mp_unsigned_bin_size(&dss_s);
|
||||
assert(writelen <= SHA1_HASH_SIZE);
|
||||
/* need to pad to 160 bits with leading zeros */
|
||||
for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
|
||||
buf_putbyte(buf, 0);
|
||||
}
|
||||
if (mp_to_unsigned_bin(&dss_s, buf_getwriteptr(buf, writelen))
|
||||
!= MP_OKAY) {
|
||||
dropbear_exit("dss error");
|
||||
}
|
||||
mp_clear(&dss_s);
|
||||
buf_incrwritepos(buf, writelen);
|
||||
|
||||
mp_clear_multi(&dss_k, &dss_temp1, &dss_temp1, &dss_r, &dss_s,
|
||||
&dss_m, NULL);
|
||||
|
||||
/* create the signature to return */
|
||||
|
||||
TRACE(("leave buf_put_dss_sign"));
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_DSS */
|
||||
61
dss.h
Normal file
61
dss.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _DSS_H_
|
||||
#define _DSS_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
|
||||
#define DSS_SIGNATURE_SIZE 4+SSH_SIGNKEY_DSS_LEN+4+2*SHA1_HASH_SIZE
|
||||
|
||||
struct DSS_key {
|
||||
|
||||
mp_int* p;
|
||||
mp_int* q;
|
||||
mp_int* g;
|
||||
mp_int* y;
|
||||
mp_int* x;
|
||||
|
||||
};
|
||||
|
||||
typedef struct DSS_key dss_key;
|
||||
|
||||
void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
#endif
|
||||
int buf_get_dss_pub_key(buffer* buf, dss_key *key);
|
||||
int buf_get_dss_priv_key(buffer* buf, dss_key *key);
|
||||
void buf_put_dss_pub_key(buffer* buf, dss_key *key);
|
||||
void buf_put_dss_priv_key(buffer* buf, dss_key *key);
|
||||
void dss_key_free(dss_key *key);
|
||||
|
||||
#endif /* DROPBEAR_DSS */
|
||||
|
||||
#endif /* _DSS_H_ */
|
||||
113
filelist.txt
Normal file
113
filelist.txt
Normal file
@@ -0,0 +1,113 @@
|
||||
A brief rundown on which files do what, and their corresponding sections
|
||||
in the IETF drafts. The .c files usually have corresponding .h files.
|
||||
|
||||
Transport layer draft-ietf-secsh-transport-16.txt
|
||||
===============
|
||||
|
||||
session.c Contains the main select() loop, and handles setting
|
||||
up/closing down ssh connections
|
||||
|
||||
algo.c Framework for handling various ciphers/hashes/algos,
|
||||
and choosing between the lists of client/server
|
||||
preferred ones
|
||||
|
||||
kex.c Key exchange routines, used at startup to negotiate
|
||||
which algorithms to use, and also to obtain session
|
||||
keys. This also runs when rekeying during the
|
||||
connection.
|
||||
|
||||
packet.c Handles the basic packet encryption/decryption,
|
||||
and switching to the appropriate packet handlers.
|
||||
Called from session.c's main select loop.
|
||||
|
||||
service.c Handles service requests (userauth or connection)
|
||||
|
||||
|
||||
Authentication draft-ietf-secsh-userauth-17.txt
|
||||
==============
|
||||
|
||||
auth.c General auth handling, including user checking etc,
|
||||
passes different auth types to auth{passwd,pubkey}
|
||||
|
||||
authpasswd.c Handles /etc/passwd or /etc/shadow auth
|
||||
|
||||
authpubkey.c Handles ~/.ssh/authorized_keys auth
|
||||
|
||||
|
||||
Connection draft-ietf-secsh-connect-17.txt
|
||||
==========
|
||||
|
||||
channel.c Channel handling routines - each shell/tcp conn/agent
|
||||
etc is a channel.
|
||||
|
||||
chansession.c Handles shell/exec requests
|
||||
|
||||
sshpty.c From OpenSSH, allocates PTYs etc
|
||||
|
||||
termcodes.c Mapping of POSIX terminal codes to SSH terminal codes
|
||||
|
||||
loginrec.c From OpenSSH, handles utmp/wtmp logging
|
||||
|
||||
x11fwd.c Handles X11 forwarding
|
||||
|
||||
agentfwd.c Handles auth-agent forwarding requests
|
||||
|
||||
localtcpfwd.c Handles -L style tcp forwarding requests, setting
|
||||
up the listening port and also handling connections
|
||||
to that port (and subsequent channels)
|
||||
|
||||
|
||||
Program-related
|
||||
===============
|
||||
|
||||
dbmulti.c Combination binary chooser main() function
|
||||
|
||||
dbutil.c Various utility functions, incl logging, memory etc
|
||||
|
||||
dropbearconvert.c Conversion from dropbear<->openssh keys, uses
|
||||
keyimport.c to do most of the work
|
||||
|
||||
dropbearkey.c Generates keys, calling gen{dss,rsa}
|
||||
|
||||
keyimport.c Modified from PuTTY, converts between key types
|
||||
|
||||
main.c dropbear's main(), handles listening, forking for
|
||||
new connections, child-process limits
|
||||
|
||||
runopts.c Parses commandline options
|
||||
|
||||
options.h Compile-time feature selection
|
||||
|
||||
config.h Features selected from configure
|
||||
|
||||
debug.h Compile-time selection of debug features
|
||||
|
||||
includes.h Included system headers etc
|
||||
|
||||
|
||||
Generic Routines
|
||||
================
|
||||
|
||||
signkey.c A generic handler for pubkeys, switches to dss or rsa
|
||||
depending on the key type
|
||||
|
||||
rsa.c RSA asymmetric crypto routines
|
||||
|
||||
dss.c DSS asymmetric crypto routines
|
||||
|
||||
gendss.c DSS key generation
|
||||
|
||||
genrsa.c RSA key generation
|
||||
|
||||
bignum.c Some bignum helper functions
|
||||
|
||||
queue.c A queue, used to enqueue encrypted packets to send
|
||||
|
||||
random.c PRNG, based on /dev/urandom or prngd
|
||||
|
||||
atomicio.c From OpenSSH, does `blocking' IO on non-blocking fds
|
||||
|
||||
buffer.c Buffer-usage routines, with size checking etc
|
||||
|
||||
|
||||
vim:set ts=8:
|
||||
215
gendss.c
Normal file
215
gendss.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "signkey.h"
|
||||
#include "bignum.h"
|
||||
#include "random.h"
|
||||
#include "buffer.h"
|
||||
#include "gendss.h"
|
||||
#include "dss.h"
|
||||
|
||||
#define PSIZE 128 /* 1024 bit*/
|
||||
#define QSIZE 20 /* 160 bit */
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
|
||||
static void getq(dss_key *key);
|
||||
static void getp(dss_key *key, unsigned int size);
|
||||
static void getg(dss_key *key);
|
||||
static void getx(dss_key *key);
|
||||
static void gety(dss_key *key);
|
||||
|
||||
dss_key * gen_dss_priv_key(unsigned int size) {
|
||||
|
||||
dss_key *key;
|
||||
|
||||
key = (dss_key*)m_malloc(sizeof(dss_key));
|
||||
|
||||
key->p = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->q = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->g = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->y = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->x = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(key->p, key->q, key->g, key->y, key->x, NULL);
|
||||
|
||||
seedrandom();
|
||||
|
||||
getq(key);
|
||||
getp(key, size);
|
||||
getg(key);
|
||||
getx(key);
|
||||
gety(key);
|
||||
|
||||
return key;
|
||||
|
||||
}
|
||||
|
||||
static void getq(dss_key *key) {
|
||||
|
||||
char buf[QSIZE];
|
||||
|
||||
/* 160 bit prime */
|
||||
genrandom(buf, QSIZE);
|
||||
buf[0] |= 0x80; /* top bit high */
|
||||
buf[QSIZE-1] |= 0x01; /* bottom bit high */
|
||||
|
||||
if (mp_read_unsigned_bin(key->q, buf, QSIZE) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* 18 rounds are required according to HAC */
|
||||
if (mp_prime_next_prime(key->q, 18, 0) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void getp(dss_key *key, unsigned int size) {
|
||||
|
||||
mp_int tempX, tempC, tempP, temp2q;
|
||||
int result;
|
||||
unsigned char *buf;
|
||||
|
||||
m_mp_init_multi(&tempX, &tempC, &tempP, &temp2q, NULL);
|
||||
|
||||
|
||||
/* 2*q */
|
||||
if (mp_mul_d(key->q, 2, &temp2q) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
buf = (unsigned char*)m_malloc(size);
|
||||
|
||||
result = 0;
|
||||
do {
|
||||
|
||||
genrandom(buf, size);
|
||||
buf[0] |= 0x80; /* set the top bit high */
|
||||
|
||||
/* X is a random mp_int */
|
||||
if (mp_read_unsigned_bin(&tempX, buf, size) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* C = X mod 2q */
|
||||
if (mp_mod(&tempX, &temp2q, &tempC) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* P = X - (C - 1) = X - C + 1*/
|
||||
if (mp_sub(&tempX, &tempC, &tempP) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (mp_add_d(&tempP, 1, key->p) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* now check for prime, 5 rounds is enough according to HAC */
|
||||
/* result == 1 => p is prime */
|
||||
if (mp_prime_is_prime(key->p, 5, &result) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
} while (!result);
|
||||
|
||||
mp_clear_multi(&tempX, &tempC, &tempP, &temp2q, NULL);
|
||||
m_free(buf);
|
||||
}
|
||||
|
||||
static void getg(dss_key * key) {
|
||||
|
||||
char printbuf[1000];
|
||||
mp_int div, h, val;
|
||||
|
||||
m_mp_init_multi(&div, &h, &val, NULL);
|
||||
|
||||
/* get div=(p-1)/q */
|
||||
if (mp_sub_d(key->p, 1, &val) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if (mp_div(&val, key->q, &div, NULL) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* initialise h=1 */
|
||||
mp_set(&h, 1);
|
||||
do {
|
||||
/* now keep going with g=h^div mod p, until g > 1 */
|
||||
if (mp_exptmod(&h, &div, key->p, key->g) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (mp_add_d(&h, 1, &h) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
} 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;
|
||||
char buf[QSIZE];
|
||||
|
||||
m_mp_init(&val);
|
||||
|
||||
do {
|
||||
genrandom(buf, QSIZE);
|
||||
|
||||
if (mp_read_unsigned_bin(&val, buf, QSIZE) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
}
|
||||
} while ((mp_cmp_d(&val, 1) == MP_GT) && (mp_cmp(&val, key->q) == MP_LT));
|
||||
|
||||
mp_copy(&val, key->x);
|
||||
mp_clear(&val);
|
||||
|
||||
}
|
||||
|
||||
static void gety(dss_key *key) {
|
||||
|
||||
if (mp_exptmod(key->g, key->x, key->p, key->y) != MP_OKAY) {
|
||||
fprintf(stderr, "dss key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_DSS */
|
||||
36
gendss.h
Normal file
36
gendss.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _GENDSS_H_
|
||||
#define _GENDSS_H_
|
||||
|
||||
#include "dss.h"
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
|
||||
dss_key * gen_dss_priv_key(unsigned int size);
|
||||
|
||||
#endif /* DROPBEAR_DSS */
|
||||
|
||||
#endif /* _GENDSS_H_ */
|
||||
138
genrsa.c
Normal file
138
genrsa.c
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "bignum.h"
|
||||
#include "random.h"
|
||||
#include "rsa.h"
|
||||
#include "genrsa.h"
|
||||
|
||||
#define RSA_E 65537
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
|
||||
static void getrsaprime(mp_int* prime, mp_int *primeminus,
|
||||
mp_int* rsa_e, unsigned int size);
|
||||
|
||||
/* mostly taken from libtomcrypt's rsa key generation routine */
|
||||
rsa_key * gen_rsa_priv_key(unsigned int size) {
|
||||
|
||||
rsa_key * key;
|
||||
mp_int pminus, qminus, lcm;
|
||||
|
||||
key = (rsa_key*)m_malloc(sizeof(rsa_key));
|
||||
|
||||
key->e = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->n = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->d = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->p = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->q = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
|
||||
m_mp_init_multi(key->e, key->n, key->d, key->p, key->q,
|
||||
&pminus, &lcm, &qminus, NULL);
|
||||
|
||||
seedrandom();
|
||||
|
||||
if (mp_set_int(key->e, RSA_E) != MP_OKAY) {
|
||||
fprintf(stderr, "rsa generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* PuTTY doesn't like it if the modulus isn't a multiple of 8 bits,
|
||||
* so we just generate them until we get one which is OK */
|
||||
getrsaprime(key->p, &pminus, key->e, size/2);
|
||||
do {
|
||||
getrsaprime(key->q, &qminus, key->e, size/2);
|
||||
|
||||
if (mp_mul(key->p, key->q, key->n) != MP_OKAY) {
|
||||
fprintf(stderr, "rsa generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
} while (mp_count_bits(key->n) % 8 != 0);
|
||||
|
||||
/* lcm(p-1, q-1) */
|
||||
if (mp_lcm(&pminus, &qminus, &lcm) != MP_OKAY) {
|
||||
fprintf(stderr, "rsa generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* de = 1 mod lcm(p-1,q-1) */
|
||||
/* therefore d = (e^-1) mod lcm(p-1,q-1) */
|
||||
if (mp_invmod(key->e, &lcm, key->d) != MP_OKAY) {
|
||||
fprintf(stderr, "rsa generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mp_clear_multi(&pminus, &qminus, &lcm, NULL);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/* return a prime suitable for p or q */
|
||||
static void getrsaprime(mp_int* prime, mp_int *primeminus,
|
||||
mp_int* rsa_e, unsigned int size) {
|
||||
|
||||
unsigned char *buf;
|
||||
mp_int temp_gcd;
|
||||
|
||||
buf = (unsigned char*)m_malloc(size+1);
|
||||
|
||||
m_mp_init(&temp_gcd);
|
||||
do {
|
||||
/* generate a random odd number with MSB set, then find the
|
||||
the next prime above it */
|
||||
genrandom(buf, size+1);
|
||||
buf[0] |= 0x80; /* MSB set */
|
||||
|
||||
if (mp_read_unsigned_bin(prime, buf, size+1) != MP_OKAY) {
|
||||
fprintf(stderr, "rsa generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* find the next integer which is prime, 8 round of miller-rabin */
|
||||
if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) {
|
||||
fprintf(stderr, "rsa generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* subtract one to get p-1 */
|
||||
if (mp_sub_d(prime, 1, primeminus) != MP_OKAY) {
|
||||
fprintf(stderr, "rsa generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
/* check relative primality to e */
|
||||
if (mp_gcd(primeminus, rsa_e, &temp_gcd) != MP_OKAY) {
|
||||
fprintf(stderr, "rsa generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
} while (mp_cmp_d(&temp_gcd, 1) != MP_EQ); /* while gcd(p-1, e) != 1 */
|
||||
|
||||
/* now we have a good value for result */
|
||||
mp_clear(&temp_gcd);
|
||||
m_burn(buf, size+1);
|
||||
m_free(buf);
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_RSA */
|
||||
36
genrsa.h
Normal file
36
genrsa.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _GENRSA_H_
|
||||
#define _GENRSA_H_
|
||||
|
||||
#include "rsa.h"
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
|
||||
rsa_key * gen_rsa_priv_key(unsigned int size);
|
||||
|
||||
#endif /* DROPBEAR_RSA */
|
||||
|
||||
#endif /* _GENRSA_H_ */
|
||||
134
includes.h
Normal file
134
includes.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _INCLUDES_H_
|
||||
#define _INCLUDES_H_
|
||||
|
||||
|
||||
#include "config.h"
|
||||
#include "options.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/param.h> /* required for BSD4_4 define */
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/dir.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <limits.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <netdb.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#ifdef HAVE_UTMP_H
|
||||
#include <utmp.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UTMPX_H
|
||||
#include <utmpx.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PATHS_H
|
||||
#include <paths.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LASTLOG_H
|
||||
#include <lastlog.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_TCP_H
|
||||
#include <netinet/tcp.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBUTIL_H
|
||||
#include <libutil.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CRYPT_H
|
||||
#include <crypt.h>
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UTIL_H
|
||||
#include <util.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SHADOW_H
|
||||
#include <shadow.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBGEN_H
|
||||
#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"
|
||||
|
||||
#ifndef HAVE_UINT16_T
|
||||
#ifndef HAVE_U_INT16_T
|
||||
typedef unsigned short u_int16_t;
|
||||
#endif /* HAVE_U_INT16_T */
|
||||
typedef u_int16_t uint16_t;
|
||||
#endif /* HAVE_UINT16_T */
|
||||
|
||||
#ifndef LOG_AUTHPRIV
|
||||
#define LOG_AUTHPRIV LOG_AUTH
|
||||
#endif
|
||||
|
||||
#endif /* _INCLUDES_H_ */
|
||||
251
install-sh
Normal file
251
install-sh
Normal file
@@ -0,0 +1,251 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# install - install a program, script, or datafile
|
||||
# This comes from X11R5 (mit/util/scripts/install.sh).
|
||||
#
|
||||
# Copyright 1991 by the Massachusetts Institute of Technology
|
||||
#
|
||||
# Permission to use, copy, modify, distribute, and sell this software and its
|
||||
# documentation for any purpose is hereby granted without fee, provided that
|
||||
# the above copyright notice appear in all copies and that both that
|
||||
# copyright notice and this permission notice appear in supporting
|
||||
# documentation, and that the name of M.I.T. not be used in advertising or
|
||||
# publicity pertaining to distribution of the software without specific,
|
||||
# written prior permission. M.I.T. makes no representations about the
|
||||
# suitability of this software for any purpose. It is provided "as is"
|
||||
# without express or implied warranty.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch. It can only install one file at a time, a restriction
|
||||
# shared with many OS's install programs.
|
||||
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
|
||||
|
||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||
|
||||
mvprog="${MVPROG-mv}"
|
||||
cpprog="${CPPROG-cp}"
|
||||
chmodprog="${CHMODPROG-chmod}"
|
||||
chownprog="${CHOWNPROG-chown}"
|
||||
chgrpprog="${CHGRPPROG-chgrp}"
|
||||
stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
mkdirprog="${MKDIRPROG-mkdir}"
|
||||
|
||||
transformbasename=""
|
||||
transform_arg=""
|
||||
instcmd="$mvprog"
|
||||
chmodcmd="$chmodprog 0755"
|
||||
chowncmd=""
|
||||
chgrpcmd=""
|
||||
stripcmd=""
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=""
|
||||
dst=""
|
||||
dir_arg=""
|
||||
|
||||
while [ x"$1" != x ]; do
|
||||
case $1 in
|
||||
-c) instcmd="$cpprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-s) stripcmd="$stripprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
*) if [ x"$src" = x ]
|
||||
then
|
||||
src=$1
|
||||
else
|
||||
# this colon is to work around a 386BSD /bin/sh bug
|
||||
:
|
||||
dst=$1
|
||||
fi
|
||||
shift
|
||||
continue;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "install: no input file specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]; then
|
||||
dst=$src
|
||||
src=""
|
||||
|
||||
if [ -d $dst ]; then
|
||||
instcmd=:
|
||||
chmodcmd=""
|
||||
else
|
||||
instcmd=mkdir
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
|
||||
if [ -f $src -o -d $src ]
|
||||
then
|
||||
true
|
||||
else
|
||||
echo "install: $src does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "install: no destination specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# If destination is a directory, append the input filename; if your system
|
||||
# does not like double slashes in filenames, you may need to add some logic
|
||||
|
||||
if [ -d $dst ]
|
||||
then
|
||||
dst="$dst"/`basename $src`
|
||||
else
|
||||
true
|
||||
fi
|
||||
fi
|
||||
|
||||
## this sed command emulates the dirname command
|
||||
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
|
||||
# Make sure that the destination directory exists.
|
||||
# this part is taken from Noah Friedman's mkinstalldirs script
|
||||
|
||||
# Skip lots of stat calls in the usual case.
|
||||
if [ ! -d "$dstdir" ]; then
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-${defaultIFS}}"
|
||||
|
||||
oIFS="${IFS}"
|
||||
# Some sh's can't handle IFS=/ for some reason.
|
||||
IFS='%'
|
||||
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||
IFS="${oIFS}"
|
||||
|
||||
pathcomp=''
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
pathcomp="${pathcomp}${1}"
|
||||
shift
|
||||
|
||||
if [ ! -d "${pathcomp}" ] ;
|
||||
then
|
||||
$mkdirprog "${pathcomp}"
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
pathcomp="${pathcomp}/"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]
|
||||
then
|
||||
$doit $instcmd $dst &&
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
|
||||
else
|
||||
|
||||
# If we're going to rename the final executable, determine the name now.
|
||||
|
||||
if [ x"$transformarg" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
dstfile=`basename $dst $transformbasename |
|
||||
sed $transformarg`$transformbasename
|
||||
fi
|
||||
|
||||
# don't allow the sed command to completely eliminate the filename
|
||||
|
||||
if [ x"$dstfile" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# Make a temp file name in the proper directory.
|
||||
|
||||
dsttmp=$dstdir/#inst.$$#
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
|
||||
$doit $instcmd $src $dsttmp &&
|
||||
|
||||
trap "rm -f ${dsttmp}" 0 &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits
|
||||
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
|
||||
$doit $rmcmd -f $dstdir/$dstfile &&
|
||||
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||
|
||||
fi &&
|
||||
|
||||
|
||||
exit 0
|
||||
62
kex.h
Normal file
62
kex.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _KEX_H_
|
||||
#define _KEX_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
void send_msg_kexinit();
|
||||
void recv_msg_kexinit();
|
||||
void send_dh_kex();
|
||||
void recv_msg_kexdh_init();
|
||||
void send_msg_newkeys();
|
||||
void recv_msg_newkeys();
|
||||
void kexinitialise();
|
||||
|
||||
void svr_read_kex();
|
||||
void cli_read_kex();
|
||||
|
||||
extern const unsigned char dh_p_val[];
|
||||
#define DH_P_LEN 128 /* The length of the dh_p_val array */
|
||||
|
||||
extern const int DH_G_VAL; /* == 2 */
|
||||
|
||||
struct KEXState {
|
||||
|
||||
unsigned sentkexinit : 1; /*set when we've sent/recv kexinit packet */
|
||||
unsigned recvkexinit : 1;
|
||||
unsigned firstfollows : 1; /* true when first_kex_packet_follows is set */
|
||||
unsigned sentnewkeys : 1; /* set once we've send/recv'ed MSG_NEWKEYS*/
|
||||
unsigned recvnewkeys : 1;
|
||||
|
||||
long lastkextime; /* time of the last kex */
|
||||
unsigned int datatrans; /* data transmitted since last kex */
|
||||
unsigned int datarecv; /* data received since last kex */
|
||||
|
||||
};
|
||||
|
||||
#define MAX_KEXHASHBUF 2000
|
||||
|
||||
#endif /* _KEX_H_ */
|
||||
1748
keyimport.c
Normal file
1748
keyimport.c
Normal file
File diff suppressed because it is too large
Load Diff
18
keyimport.h
Normal file
18
keyimport.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef _KEYIMPORT_H_
|
||||
#define _KEYIMPORT_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "signkey.h"
|
||||
|
||||
enum {
|
||||
KEYFILE_DROPBEAR,
|
||||
KEYFILE_OPENSSH,
|
||||
KEYFILE_SSHCOM
|
||||
};
|
||||
|
||||
int import_write(const char *filename, sign_key *key, char *passphrase,
|
||||
int filetype);
|
||||
sign_key *import_read(const char *filename, char *passphrase, int filetype);
|
||||
int import_encrypted(const char* filename, int filetype);
|
||||
|
||||
#endif /* _KEYIMPORT_H_ */
|
||||
142
localtcpfwd.c
Normal file
142
localtcpfwd.c
Normal file
@@ -0,0 +1,142 @@
|
||||
#include "includes.h"
|
||||
#include "session.h"
|
||||
#include "dbutil.h"
|
||||
#include "localtcpfwd.h"
|
||||
|
||||
#ifndef DISABLE_LOCALTCPFWD
|
||||
static int newtcp(const char * host, int port);
|
||||
|
||||
/* Called upon creating a new direct tcp channel (ie we connect out to an
|
||||
* address */
|
||||
int newtcpdirect(struct Channel * channel) {
|
||||
|
||||
unsigned char* desthost = NULL;
|
||||
unsigned int destport;
|
||||
unsigned char* orighost = NULL;
|
||||
unsigned int origport;
|
||||
int sock;
|
||||
int len;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
if (ses.opts->nolocaltcp) {
|
||||
TRACE(("leave newtcpdirect: local tcp forwarding disabled"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
desthost = buf_getstring(ses.payload, &len);
|
||||
if (len > MAX_HOST_LEN) {
|
||||
TRACE(("leave newtcpdirect: desthost too long"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
destport = buf_getint(ses.payload);
|
||||
|
||||
orighost = buf_getstring(ses.payload, &len);
|
||||
if (len > MAX_HOST_LEN) {
|
||||
TRACE(("leave newtcpdirect: orighost too long"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
origport = buf_getint(ses.payload);
|
||||
|
||||
/* best be sure */
|
||||
if (origport > 65535 || destport > 65535) {
|
||||
TRACE(("leave newtcpdirect: port > 65535"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
sock = newtcp(desthost, destport);
|
||||
if (sock < 0) {
|
||||
TRACE(("leave newtcpdirect: sock failed"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
ses.maxfd = MAX(ses.maxfd, sock);
|
||||
|
||||
/* Note that infd is actually the "outgoing" direction on the
|
||||
* tcp connection, vice versa for outfd.
|
||||
* We don't set outfd, that will get set after the connection's
|
||||
* progress succeeds */
|
||||
channel->infd = sock;
|
||||
channel->initconn = 1;
|
||||
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
|
||||
out:
|
||||
m_free(desthost);
|
||||
m_free(orighost);
|
||||
TRACE(("leave newtcpdirect: ret %d", ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initiate a new TCP connection - this is non-blocking, so the socket
|
||||
* returned will need to be checked for success when it is first written.
|
||||
* Similarities with OpenSSH's connect_to() are not coincidental.
|
||||
* Returns -1 on failure */
|
||||
static int newtcp(const char * host, int port) {
|
||||
|
||||
int sock = -1;
|
||||
char portstring[6];
|
||||
struct addrinfo *res = NULL, *ai;
|
||||
int val;
|
||||
|
||||
struct addrinfo hints;
|
||||
|
||||
TRACE(("enter newtcp"));
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
/* TCP, either ip4 or ip6 */
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
|
||||
snprintf(portstring, sizeof(portstring), "%d", port);
|
||||
if (getaddrinfo(host, portstring, &hints, &res) != 0) {
|
||||
if (res) {
|
||||
freeaddrinfo(res);
|
||||
}
|
||||
TRACE(("leave newtcp: failed getaddrinfo"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Use the first socket that works */
|
||||
for (ai = res; ai != NULL; ai = ai->ai_next) {
|
||||
|
||||
if (ai->ai_family != PF_INET && ai->ai_family != PF_INET6) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sock = socket(ai->ai_family, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
TRACE(("TCP socket() failed"));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
|
||||
close(sock);
|
||||
TRACE(("TCP non-blocking failed"));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* non-blocking, so it might return without success (EINPROGRESS) */
|
||||
if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
|
||||
if (errno == EINPROGRESS) {
|
||||
TRACE(("connect in progress"));
|
||||
} else {
|
||||
close(sock);
|
||||
TRACE(("TCP connect failed"));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
|
||||
if (ai == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
|
||||
return sock;
|
||||
}
|
||||
#endif /* DISABLE_LOCALTCPFWD */
|
||||
34
localtcpfwd.h
Normal file
34
localtcpfwd.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
#ifndef _LOCALTCPFWD_H_
|
||||
#define _LOCALTCPFWD_H_
|
||||
#ifndef DISABLE_LOCALTCPFWD
|
||||
|
||||
#include "includes.h"
|
||||
#include "channel.h"
|
||||
|
||||
int newtcpdirect(struct Channel * channel);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
1540
loginrec.c
Normal file
1540
loginrec.c
Normal file
File diff suppressed because it is too large
Load Diff
194
loginrec.h
Normal file
194
loginrec.h
Normal file
@@ -0,0 +1,194 @@
|
||||
#ifndef _HAVE_LOGINREC_H_
|
||||
#define _HAVE_LOGINREC_H_
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Andre Lucas. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
** loginrec.h: platform-independent login recording and lastlog retrieval
|
||||
**/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
/* RCSID("$Id: loginrec.h,v 1.2 2004/05/04 10:17:43 matt Exp $"); */
|
||||
|
||||
/* The following #defines are from OpenSSH's defines.h, required for loginrec */
|
||||
|
||||
/* FIXME: put default paths back in */
|
||||
#ifndef UTMP_FILE
|
||||
# ifdef _PATH_UTMP
|
||||
# define UTMP_FILE _PATH_UTMP
|
||||
# else
|
||||
# ifdef CONF_UTMP_FILE
|
||||
# define UTMP_FILE CONF_UTMP_FILE
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#ifndef WTMP_FILE
|
||||
# ifdef _PATH_WTMP
|
||||
# define WTMP_FILE _PATH_WTMP
|
||||
# else
|
||||
# ifdef CONF_WTMP_FILE
|
||||
# define WTMP_FILE CONF_WTMP_FILE
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
/* pick up the user's location for lastlog if given */
|
||||
#ifndef LASTLOG_FILE
|
||||
# ifdef _PATH_LASTLOG
|
||||
# define LASTLOG_FILE _PATH_LASTLOG
|
||||
# else
|
||||
# ifdef CONF_LASTLOG_FILE
|
||||
# define LASTLOG_FILE CONF_LASTLOG_FILE
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/* The login() library function in libutil is first choice */
|
||||
#if defined(HAVE_LOGIN) && !defined(DISABLE_LOGIN)
|
||||
# define USE_LOGIN
|
||||
|
||||
#else
|
||||
/* Simply select your favourite login types. */
|
||||
/* Can't do if-else because some systems use several... <sigh> */
|
||||
# if defined(UTMPX_FILE) && !defined(DISABLE_UTMPX)
|
||||
# define USE_UTMPX
|
||||
# endif
|
||||
# if defined(UTMP_FILE) && !defined(DISABLE_UTMP)
|
||||
# define USE_UTMP
|
||||
# endif
|
||||
# if defined(WTMPX_FILE) && !defined(DISABLE_WTMPX)
|
||||
# define USE_WTMPX
|
||||
# endif
|
||||
# if defined(WTMP_FILE) && !defined(DISABLE_WTMP)
|
||||
# define USE_WTMP
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/* I hope that the presence of LASTLOG_FILE is enough to detect this */
|
||||
#if defined(LASTLOG_FILE) && !defined(DISABLE_LASTLOG)
|
||||
# define USE_LASTLOG
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
** you should use the login_* calls to work around platform dependencies
|
||||
**/
|
||||
|
||||
/*
|
||||
* login_netinfo structure
|
||||
*/
|
||||
|
||||
union login_netinfo {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sa_in;
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
|
||||
struct sockaddr_storage sa_storage;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* * logininfo structure *
|
||||
*/
|
||||
/* types - different to utmp.h 'type' macros */
|
||||
/* (though set to the same value as linux, openbsd and others...) */
|
||||
#define LTYPE_LOGIN 7
|
||||
#define LTYPE_LOGOUT 8
|
||||
|
||||
/* string lengths - set very long */
|
||||
#define LINFO_PROGSIZE 64
|
||||
#define LINFO_LINESIZE 64
|
||||
#define LINFO_NAMESIZE 64
|
||||
#define LINFO_HOSTSIZE 256
|
||||
|
||||
struct logininfo {
|
||||
char progname[LINFO_PROGSIZE]; /* name of program (for PAM) */
|
||||
int progname_null;
|
||||
short int type; /* type of login (LTYPE_*) */
|
||||
int pid; /* PID of login process */
|
||||
int uid; /* UID of this user */
|
||||
char line[LINFO_LINESIZE]; /* tty/pty name */
|
||||
char username[LINFO_NAMESIZE]; /* login username */
|
||||
char hostname[LINFO_HOSTSIZE]; /* remote hostname */
|
||||
/* 'exit_status' structure components */
|
||||
int exit; /* process exit status */
|
||||
int termination; /* process termination status */
|
||||
/* struct timeval (sys/time.h) isn't always available, if it isn't we'll
|
||||
* use time_t's value as tv_sec and set tv_usec to 0
|
||||
*/
|
||||
unsigned int tv_sec;
|
||||
unsigned int tv_usec;
|
||||
union login_netinfo hostaddr; /* caller's host address(es) */
|
||||
}; /* struct logininfo */
|
||||
|
||||
/*
|
||||
* login recording functions
|
||||
*/
|
||||
|
||||
/** 'public' functions */
|
||||
|
||||
/* construct a new login entry */
|
||||
struct logininfo *login_alloc_entry(int pid, const char *username,
|
||||
const char *hostname, const char *line);
|
||||
/* free a structure */
|
||||
void login_free_entry(struct logininfo *li);
|
||||
/* fill out a pre-allocated structure with useful information */
|
||||
int login_init_entry(struct logininfo *li, int pid, const char *username,
|
||||
const char *hostname, const char *line);
|
||||
/* place the current time in a logininfo struct */
|
||||
void login_set_current_time(struct logininfo *li);
|
||||
|
||||
/* record the entry */
|
||||
int login_login (struct logininfo *li);
|
||||
int login_logout(struct logininfo *li);
|
||||
#ifdef LOGIN_NEEDS_UTMPX
|
||||
int login_utmp_only(struct logininfo *li);
|
||||
#endif
|
||||
|
||||
/** End of public functions */
|
||||
|
||||
/* record the entry */
|
||||
int login_write (struct logininfo *li);
|
||||
int login_log_entry(struct logininfo *li);
|
||||
|
||||
/* set the network address based on network address type */
|
||||
void login_set_addr(struct logininfo *li, const struct sockaddr *sa,
|
||||
const unsigned int sa_size);
|
||||
|
||||
/*
|
||||
* lastlog retrieval functions
|
||||
*/
|
||||
/* lastlog *entry* functions fill out a logininfo */
|
||||
struct logininfo *login_get_lastlog(struct logininfo *li, const int uid);
|
||||
/* lastlog *time* functions return time_t equivalent (uint) */
|
||||
unsigned int login_get_lastlog_time(const int uid);
|
||||
|
||||
/* produce various forms of the line filename */
|
||||
char *line_fullname(char *dst, const char *src, size_t dstsize);
|
||||
char *line_stripname(char *dst, const char *src, size_t dstsize);
|
||||
char *line_abbrevname(char *dst, const char *src, size_t dstsize);
|
||||
|
||||
#endif /* _HAVE_LOGINREC_H_ */
|
||||
343
main.c
Normal file
343
main.c
Normal file
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "session.h"
|
||||
#include "buffer.h"
|
||||
#include "signkey.h"
|
||||
#include "runopts.h"
|
||||
|
||||
static int listensockets(int *sock, runopts * opts, int *maxfd);
|
||||
static void sigchld_handler(int dummy);
|
||||
static void sigsegv_handler(int);
|
||||
static void sigintterm_handler(int fish);
|
||||
|
||||
static int childpipes[MAX_UNAUTH_CLIENTS];
|
||||
|
||||
#if defined(DBMULTI_DROPBEAR) || !defined(DROPBEAR_MULTI)
|
||||
#if defined(DBMULTI_DROPBEAR) && defined(DROPBEAR_MULTI)
|
||||
int dropbear_main(int argc, char ** argv)
|
||||
#else
|
||||
int main(int argc, char ** argv)
|
||||
#endif
|
||||
{
|
||||
|
||||
fd_set fds;
|
||||
struct timeval seltimeout;
|
||||
unsigned int i, j;
|
||||
int val;
|
||||
int maxsock = -1;
|
||||
struct sockaddr remoteaddr;
|
||||
int remoteaddrlen;
|
||||
int listensocks[MAX_LISTEN_ADDR];
|
||||
unsigned int listensockcount = 0;
|
||||
runopts * opts;
|
||||
FILE * pidfile;
|
||||
|
||||
int childsock;
|
||||
pid_t childpid;
|
||||
int childpipe[2];
|
||||
|
||||
struct sigaction sa_chld;
|
||||
|
||||
/* get commandline options */
|
||||
opts = getrunopts(argc, argv);
|
||||
|
||||
/* fork */
|
||||
if (opts->forkbg) {
|
||||
int closefds = 0;
|
||||
#ifndef DEBUG_TRACE
|
||||
if (!usingsyslog) {
|
||||
closefds = 1;
|
||||
}
|
||||
#endif
|
||||
if (daemon(0, closefds) < 0) {
|
||||
dropbear_exit("Failed to create background process: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DISABLE_SYSLOG
|
||||
if (usingsyslog) {
|
||||
startsyslog();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* should be done after syslog is working */
|
||||
if (opts->forkbg) {
|
||||
dropbear_log(LOG_INFO, "Running in background");
|
||||
} else {
|
||||
dropbear_log(LOG_INFO, "Not forking");
|
||||
}
|
||||
|
||||
/* create a PID file so that we can be killed easily */
|
||||
pidfile = fopen(DROPBEAR_PIDFILE, "w");
|
||||
if (pidfile) {
|
||||
fprintf(pidfile, "%d\n", getpid());
|
||||
fclose(pidfile);
|
||||
}
|
||||
|
||||
/* set up cleanup handler */
|
||||
if (signal(SIGINT, sigintterm_handler) == SIG_ERR ||
|
||||
#ifndef DEBUG_VALGRIND
|
||||
signal(SIGTERM, sigintterm_handler) == SIG_ERR ||
|
||||
#endif
|
||||
signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
|
||||
dropbear_exit("signal() error");
|
||||
}
|
||||
|
||||
/* catch and reap zombie children */
|
||||
sa_chld.sa_handler = sigchld_handler;
|
||||
sa_chld.sa_flags = SA_NOCLDSTOP;
|
||||
if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) {
|
||||
dropbear_exit("signal() error");
|
||||
}
|
||||
if (signal(SIGSEGV, sigsegv_handler) == SIG_ERR) {
|
||||
dropbear_exit("signal() error");
|
||||
}
|
||||
|
||||
/* sockets to identify pre-authenticated clients */
|
||||
for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
|
||||
childpipes[i] = -1;
|
||||
}
|
||||
|
||||
/* Set up the listening sockets */
|
||||
/* XXX XXX ports */
|
||||
listensockcount = listensockets(listensocks, opts, &maxsock);
|
||||
|
||||
/* incoming connection select loop */
|
||||
for(;;) {
|
||||
|
||||
FD_ZERO(&fds);
|
||||
|
||||
seltimeout.tv_sec = 60;
|
||||
seltimeout.tv_usec = 0;
|
||||
|
||||
/* listening sockets */
|
||||
for (i = 0; i < listensockcount; i++) {
|
||||
FD_SET(listensocks[i], &fds);
|
||||
}
|
||||
|
||||
/* pre-authentication clients */
|
||||
for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
|
||||
if (childpipes[i] >= 0) {
|
||||
FD_SET(childpipes[i], &fds);
|
||||
maxsock = MAX(maxsock, childpipes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
val = select(maxsock+1, &fds, NULL, NULL, &seltimeout);
|
||||
|
||||
if (exitflag) {
|
||||
unlink(DROPBEAR_PIDFILE);
|
||||
dropbear_exit("Terminated by signal");
|
||||
}
|
||||
|
||||
if (val == 0) {
|
||||
/* timeout reached */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (val < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
dropbear_exit("Listening socket error");
|
||||
}
|
||||
|
||||
/* close fds which have been authed or closed - auth.c handles
|
||||
* closing the auth sockets on success */
|
||||
for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
|
||||
if (childpipes[i] >= 0 && FD_ISSET(childpipes[i], &fds)) {
|
||||
close(childpipes[i]);
|
||||
childpipes[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* handle each socket which has something to say */
|
||||
for (i = 0; i < listensockcount; i++) {
|
||||
if (!FD_ISSET(listensocks[i], &fds))
|
||||
continue;
|
||||
|
||||
/* child connection XXX - ip6 stuff here */
|
||||
remoteaddrlen = sizeof(struct sockaddr_in);
|
||||
childsock = accept(listensocks[i], &remoteaddr, &remoteaddrlen);
|
||||
|
||||
if (childsock < 0) {
|
||||
/* accept failed */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check for max number of connections not authorised */
|
||||
for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) {
|
||||
if (childpipes[j] < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j == MAX_UNAUTH_CLIENTS) {
|
||||
/* no free connections */
|
||||
/* TODO - possibly log, though this would be an easy way
|
||||
* to fill logs/disk */
|
||||
close(childsock);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pipe(childpipe) < 0) {
|
||||
TRACE(("error creating child pipe"));
|
||||
close(childsock);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((childpid = fork()) == 0) {
|
||||
|
||||
/* child */
|
||||
char * addrstring = NULL;
|
||||
#ifdef DEBUG_FORKGPROF
|
||||
extern void _start(void), etext(void);
|
||||
monstartup((u_long)&_start, (u_long)&etext);
|
||||
#endif /* DEBUG_FORKGPROF */
|
||||
|
||||
addrstring = getaddrstring(&remoteaddr);
|
||||
dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
|
||||
m_free(addrstring);
|
||||
|
||||
if (setsid() < 0) {
|
||||
dropbear_exit("setsid: %s", strerror(errno));
|
||||
}
|
||||
|
||||
/* make sure we close sockets */
|
||||
for (i = 0; i < listensockcount; i++) {
|
||||
if (m_close(listensocks[i]) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Couldn't close socket");
|
||||
}
|
||||
}
|
||||
|
||||
if (m_close(childpipe[0]) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Couldn't close socket");
|
||||
}
|
||||
/* start the session */
|
||||
child_session(childsock, opts, childpipe[1], &remoteaddr);
|
||||
/* don't return */
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/* parent */
|
||||
childpipes[j] = childpipe[0];
|
||||
if (m_close(childpipe[1]) == DROPBEAR_FAILURE
|
||||
|| m_close(childsock) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Couldn't close socket");
|
||||
}
|
||||
}
|
||||
} /* for(;;) loop */
|
||||
|
||||
/* don't reach here */
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* catch + reap zombie children */
|
||||
static void sigchld_handler(int fish) {
|
||||
struct sigaction sa_chld;
|
||||
|
||||
while(waitpid(-1, NULL, WNOHANG) > 0);
|
||||
|
||||
sa_chld.sa_handler = sigchld_handler;
|
||||
sa_chld.sa_flags = SA_NOCLDSTOP;
|
||||
if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) {
|
||||
dropbear_exit("signal() error");
|
||||
}
|
||||
}
|
||||
|
||||
/* catch any segvs */
|
||||
static void sigsegv_handler(int fish) {
|
||||
fprintf(stderr, "Aiee, segfault! You should probably report "
|
||||
"this as a bug to the developer\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* catch ctrl-c or sigterm */
|
||||
static void sigintterm_handler(int fish) {
|
||||
|
||||
exitflag = 1;
|
||||
}
|
||||
|
||||
/* Set up listening sockets for all the requested ports */
|
||||
static int listensockets(int *sock, runopts * opts, int *maxfd) {
|
||||
|
||||
int listensock; /* listening fd */
|
||||
struct sockaddr_in listen_addr;
|
||||
struct linger linger;
|
||||
unsigned int i;
|
||||
int val;
|
||||
|
||||
for (i = 0; i < opts->portcount; i++) {
|
||||
|
||||
/* iterate through all the sockets to listen on */
|
||||
listensock = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (listensock < 0) {
|
||||
dropbear_exit("Failed to create socket");
|
||||
}
|
||||
|
||||
val = 1;
|
||||
/* set to reuse, quick timeout */
|
||||
setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR,
|
||||
(void*) &val, sizeof(val));
|
||||
linger.l_onoff = 1;
|
||||
linger.l_linger = 5;
|
||||
setsockopt(listensock, SOL_SOCKET, SO_LINGER,
|
||||
(void*)&linger, sizeof(linger));
|
||||
|
||||
/* disable nagle */
|
||||
setsockopt(listensock, IPPROTO_TCP, TCP_NODELAY,
|
||||
(void*)&val, sizeof(val));
|
||||
|
||||
memset((void*)&listen_addr, 0x0, sizeof(listen_addr));
|
||||
listen_addr.sin_family = AF_INET;
|
||||
listen_addr.sin_port = htons(opts->ports[i]);
|
||||
listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
memset(&(listen_addr.sin_zero), '\0', 8);
|
||||
|
||||
if (bind(listensock, (struct sockaddr *)&listen_addr,
|
||||
sizeof(listen_addr)) < 0) {
|
||||
dropbear_exit("Bind failed port %d", opts->ports[i]);
|
||||
}
|
||||
|
||||
/* 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 opts->portcount;
|
||||
}
|
||||
327
options.h
Normal file
327
options.h
Normal file
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _OPTIONS_H_
|
||||
#define _OPTIONS_H_
|
||||
|
||||
/******************************************************************
|
||||
* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
|
||||
* parts are to allow for commandline -DDROPBEAR_XXX options etc.
|
||||
******************************************************************/
|
||||
#define DROPBEAR_SERVER
|
||||
/* #define DROPBEAR_CLIENT */
|
||||
|
||||
#ifndef DROPBEAR_PORT
|
||||
#define DROPBEAR_PORT 22
|
||||
#endif
|
||||
|
||||
/* Default hostkey paths - these can be specified on the command line */
|
||||
#ifndef DSS_PRIV_FILENAME
|
||||
#define DSS_PRIV_FILENAME "/etc/dropbear/dropbear_dss_host_key"
|
||||
#endif
|
||||
#ifndef RSA_PRIV_FILENAME
|
||||
#define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key"
|
||||
#endif
|
||||
|
||||
/* 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 */
|
||||
#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
|
||||
|
||||
/* Enable Authentication Agent Forwarding */
|
||||
#define ENABLE_AGENTFWD
|
||||
|
||||
/* Encryption - at least one required.
|
||||
* RFC Draft requires 3DES, and recommends Blowfish, AES128 & Twofish128 */
|
||||
#define DROPBEAR_AES128_CBC
|
||||
#define DROPBEAR_BLOWFISH_CBC
|
||||
#define DROPBEAR_TWOFISH128_CBC
|
||||
#define DROPBEAR_3DES_CBC
|
||||
|
||||
/* Integrity - at least one required.
|
||||
* RFC Draft requires sha1-hmac, and recommends md5-hmac.
|
||||
*
|
||||
* Note: there's no point disabling sha1 to save space, since it's used in the
|
||||
* for the random number generator and public-key cryptography anyway.
|
||||
* Disabling it here will just stop it from being used as the integrity portion
|
||||
* of the ssh protocol.
|
||||
*
|
||||
* These are also used for key fingerprints in logs (when pubkey auth is used),
|
||||
* MD5 fingerprints are printed if available, however SHA1 fingerprints will be
|
||||
* generated otherwise. This isn't exactly optimal, although SHA1 fingerprints
|
||||
* are not too hard to create from pubkeys if required. */
|
||||
#define DROPBEAR_SHA1_HMAC
|
||||
#define DROPBEAR_MD5_HMAC
|
||||
|
||||
/* Hostkey/public key algorithms - at least one required, these are used
|
||||
* for hostkey as well as for verifying signatures with pubkey auth.
|
||||
* Removing either of these won't save very much space.
|
||||
* SSH2 RFC Draft requires dss, recommends rsa */
|
||||
#define DROPBEAR_RSA
|
||||
#define DROPBEAR_DSS
|
||||
|
||||
/* Define DSS_PROTOK to use PuTTY's method of generating the value k for dss,
|
||||
* rather than just from the random byte source. Undefining this will save you
|
||||
* ~4k in binary size with static uclibc, but your DSS hostkey could be exposed
|
||||
* if the random number source isn't good. In general this isn't required */
|
||||
/* #define DSS_PROTOK */
|
||||
|
||||
/* Whether to do reverse DNS lookups. This is advisable, though will add
|
||||
* code size with gethostbyname() etc, so for very small environments where
|
||||
* you are statically linking, you might want to undefine this */
|
||||
#define DO_HOST_LOOKUP
|
||||
|
||||
/* Whether to print the message of the day (MOTD). This doesn't add much code
|
||||
* size */
|
||||
#define DO_MOTD
|
||||
|
||||
/* The MOTD file path */
|
||||
#ifndef MOTD_FILENAME
|
||||
#define MOTD_FILENAME "/etc/motd"
|
||||
#endif
|
||||
|
||||
/* Authentication types to enable, at least one required.
|
||||
RFC Draft requires pubkey auth, and recommends password */
|
||||
#define DROPBEAR_PASSWORD_AUTH
|
||||
#define DROPBEAR_PUBKEY_AUTH
|
||||
|
||||
/* Random device to use - you must specify _one only_.
|
||||
* DEV_RANDOM is recommended on hosts with a good /dev/urandom, otherwise use
|
||||
* 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
|
||||
* data */
|
||||
#define DROPBEAR_DEV_URANDOM /* use /dev/urandom */
|
||||
|
||||
/*#undef DROPBEAR_PRNGD */ /* use prngd socket - you must manually set up prngd
|
||||
to produce output */
|
||||
#ifndef DROPBEAR_PRNGD_SOCKET
|
||||
#define DROPBEAR_PRNGD_SOCKET "/var/run/dropbear-rng"
|
||||
#endif
|
||||
|
||||
/* Specify the number of clients we will allow to be connected but
|
||||
* not yet authenticated. After this limit, connections are rejected */
|
||||
#ifndef MAX_UNAUTH_CLIENTS
|
||||
#define MAX_UNAUTH_CLIENTS 30
|
||||
#endif
|
||||
|
||||
/* Maximum number of failed authentication tries */
|
||||
#ifndef MAX_AUTH_TRIES
|
||||
#define MAX_AUTH_TRIES 10
|
||||
#endif
|
||||
|
||||
/* The file to store the daemon's process ID, for shutdown scripts etc */
|
||||
#ifndef DROPBEAR_PIDFILE
|
||||
#define DROPBEAR_PIDFILE "/var/run/dropbear.pid"
|
||||
#endif
|
||||
|
||||
/* The command to invoke for xauth when using X11 forwarding.
|
||||
* "-q" for quiet */
|
||||
#ifndef XAUTH_COMMAND
|
||||
#define XAUTH_COMMAND "/usr/X11R6/bin/xauth -q"
|
||||
#endif
|
||||
|
||||
/* if you want to enable running an sftp server (such as the one included with
|
||||
* OpenSSH), set the path below. If the path isn't defined, sftp will not
|
||||
* be enabled */
|
||||
#ifndef SFTPSERVER_PATH
|
||||
#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"
|
||||
|
||||
/* Multi-purpose binary configuration - if you want to make the combined
|
||||
* binary, first define DROPBEAR_MULTI, and then define which of the three
|
||||
* components you want. You should then compile Dropbear with
|
||||
* "make clean; make dropbearmulti". You'll need to install the binary
|
||||
* manually, see MULTI for details */
|
||||
|
||||
/* #define DROPBEAR_MULTI */
|
||||
|
||||
/* The three multi binaries: dropbear, dropbearkey, dropbearconvert
|
||||
* Comment out these if you don't want some of them */
|
||||
#define DBMULTI_DROPBEAR
|
||||
#define DBMULTI_KEY
|
||||
#define DBMULTI_CONVERT
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* You shouldn't edit below here unless you know you need to.
|
||||
*******************************************************************/
|
||||
|
||||
#ifndef DROPBEAR_VERSION
|
||||
#define DROPBEAR_VERSION "0.41"
|
||||
#endif
|
||||
|
||||
#define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
|
||||
#define PROGNAME "dropbear"
|
||||
|
||||
/* Spec recommends after one hour or 1 gigabyte of data. One hour
|
||||
* is a bit too verbose, so we try 8 hours */
|
||||
#ifndef KEX_REKEY_TIMEOUT
|
||||
#define KEX_REKEY_TIMEOUT (3600 * 8)
|
||||
#endif
|
||||
#ifndef KEX_REKEY_DATA
|
||||
#define KEX_REKEY_DATA (1<<30) /* 2^30 == 1GB, this value must be < INT_MAX */
|
||||
#endif
|
||||
/* Close connections to clients which haven't authorised after AUTH_TIMEOUT */
|
||||
#ifndef AUTH_TIMEOUT
|
||||
#define AUTH_TIMEOUT 300 /* we choose 5 minutes */
|
||||
#endif
|
||||
|
||||
/* Minimum key sizes for DSS and RSA */
|
||||
#ifndef MIN_DSS_KEYLEN
|
||||
#define MIN_DSS_KEYLEN 512
|
||||
#endif
|
||||
#ifndef MIN_RSA_KEYLEN
|
||||
#define MIN_RSA_KEYLEN 512
|
||||
#endif
|
||||
|
||||
#define MAX_BANNER_SIZE 2000 /* this is 25*80 chars, any more is foolish */
|
||||
|
||||
#define DEV_URANDOM "/dev/urandom"
|
||||
|
||||
/* the number of NAME=VALUE pairs to malloc for environ, if we don't have
|
||||
* the clearenv() function */
|
||||
#define ENV_SIZE 100
|
||||
|
||||
#define MAX_CMD_LEN 1024 /* max length of a command */
|
||||
#define MAX_TERM_LEN 200 /* max length of TERM name */
|
||||
|
||||
#define MAX_HOST_LEN 254 /* max hostname len for tcp fwding */
|
||||
#define MAX_IP_LEN 15 /* strlen("255.255.255.255") == 15 */
|
||||
|
||||
#define DROPBEAR_MAX_PORTS 10 /* max number of ports which can be specified,
|
||||
ipv4 and ipv6 don't count twice */
|
||||
|
||||
#define _PATH_TTY "/dev/tty"
|
||||
|
||||
/* Timeouts in seconds */
|
||||
#define SELECT_TIMEOUT 20
|
||||
|
||||
/* success/failure defines */
|
||||
#define DROPBEAR_SUCCESS 0
|
||||
#define DROPBEAR_FAILURE -1
|
||||
|
||||
/* various algorithm identifiers */
|
||||
#define DROPBEAR_KEX_DH_GROUP1 0
|
||||
|
||||
#define DROPBEAR_SIGNKEY_ANY 0
|
||||
#define DROPBEAR_SIGNKEY_RSA 1
|
||||
#define DROPBEAR_SIGNKEY_DSS 2
|
||||
|
||||
#define DROPBEAR_COMP_NONE 0
|
||||
#define DROPBEAR_COMP_ZLIB 1
|
||||
|
||||
/* Required for pubkey auth */
|
||||
#ifdef DROPBEAR_PUBKEY_AUTH
|
||||
#define DROPBEAR_SIGNKEY_VERIFY
|
||||
#endif
|
||||
|
||||
/* SHA1 is 20 bytes == 160 bits */
|
||||
#define SHA1_HASH_SIZE 20
|
||||
/* SHA512 is 64 bytes == 512 bits */
|
||||
#define SHA512_HASH_SIZE 64
|
||||
/* MD5 is 16 bytes = 128 bits */
|
||||
#define MD5_HASH_SIZE 16
|
||||
|
||||
/* largest of MD5 and SHA1 */
|
||||
#define MAX_MAC_LEN SHA1_HASH_SIZE
|
||||
|
||||
|
||||
#define MAX_KEY_LEN 24 /* 3DES requires a 24 byte key */
|
||||
#define MAX_IV_LEN 20 /* must be same as max blocksize,
|
||||
and >= SHA1_HASH_SIZE */
|
||||
#define MAX_MAC_KEY 20
|
||||
|
||||
#define MAX_NAME_LEN 64 /* maximum length of a protocol name, isn't
|
||||
explicitly specified for all protocols (just
|
||||
for algos) but seems valid */
|
||||
|
||||
#define MAX_PROPOSED_ALGO 20
|
||||
|
||||
/* size/count limits */
|
||||
#define MAX_LISTEN_ADDR 10
|
||||
|
||||
#define MAX_PACKET_LEN 35000
|
||||
#define MIN_PACKET_LEN 16
|
||||
#define MAX_PAYLOAD_LEN 32768
|
||||
|
||||
#define MAX_TRANS_PAYLOAD_LEN 32768
|
||||
#define MAX_TRANS_PACKET_LEN (MAX_TRANS_PAYLOAD_LEN+50)
|
||||
|
||||
#define MAX_TRANS_WINDOW 500000000 /* 500MB is sufficient, stopping overflow */
|
||||
#define MAX_TRANS_WIN_INCR 500000000 /* overflow prevention */
|
||||
|
||||
#define MAX_STRING_LEN 1400 /* ~= MAX_PROPOSED_ALGO * MAX_NAME_LEN, also
|
||||
is the max length for a password etc */
|
||||
|
||||
#ifndef ENABLE_X11FWD
|
||||
#define DISABLE_X11FWD
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_AGENTFWD
|
||||
#define DISABLE_AGENTFWD
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_LOCALTCPFWD
|
||||
#define DISABLE_LOCALTCPFWD
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_REMOTETCPFWD
|
||||
#define DISABLE_REMOTETCPFWD
|
||||
#endif
|
||||
|
||||
/* We use dropbear_client and dropbear_server as shortcuts to avoid redundant
|
||||
* code, if we're just compiling as client or server */
|
||||
#if defined(DROPBEAR_SERVER) && defined(DROPBEAR_CLIENT)
|
||||
|
||||
#define IS_DROPBEAR_SERVER (ses.isserver == 1)
|
||||
#define IS_DROPBEAR_CLIENT (ses.isserver == 0)
|
||||
|
||||
#elif defined(DROPBEAR_SERVER)
|
||||
|
||||
#define IS_DROPBEAR_SERVER 1
|
||||
#define IS_DROPBEAR_CLIENT 0
|
||||
|
||||
#elif defined(DROPBEAR_CLIENT)
|
||||
|
||||
#define IS_DROPBEAR_SERVER 0
|
||||
#define IS_DROPBEAR_CLIENT 1
|
||||
|
||||
#else
|
||||
#error You must compiled with either DROPBEAR_CLIENT or DROPBEAR_SERVER selected
|
||||
#endif
|
||||
|
||||
#endif /* _OPTIONS_H_ */
|
||||
44
packet.h
Normal file
44
packet.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _PACKET_H_
|
||||
|
||||
#define _PACKET_H_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
void write_packet();
|
||||
void read_packet();
|
||||
void decrypt_packet();
|
||||
void encrypt_packet();
|
||||
void recv_unimplemented();
|
||||
|
||||
void svr_process_packet();
|
||||
|
||||
#define PACKET_PADDING_OFF 4
|
||||
#define PACKET_PAYLOAD_OFF 5
|
||||
|
||||
#define INIT_READBUF 200
|
||||
|
||||
#endif /* _PACKET_H_ */
|
||||
267
progressmeter.c
Normal file
267
progressmeter.c
Normal file
@@ -0,0 +1,267 @@
|
||||
#ifdef PROGRESS_METER
|
||||
/*
|
||||
* Copyright (c) 2003 Nils Nordman. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
/*RCSID("$OpenBSD: progressmeter.c,v 1.15 2003/08/31 12:14:22 markus Exp $");*/
|
||||
|
||||
#include "progressmeter.h"
|
||||
#include "atomicio.h"
|
||||
#include "scpmisc.h"
|
||||
|
||||
#define DEFAULT_WINSIZE 80
|
||||
#define MAX_WINSIZE 512
|
||||
#define PADDING 1 /* padding between the progress indicators */
|
||||
#define UPDATE_INTERVAL 1 /* update the progress meter every second */
|
||||
#define STALL_TIME 5 /* we're stalled after this many seconds */
|
||||
|
||||
/* determines whether we can output to the terminal */
|
||||
static int can_output(void);
|
||||
|
||||
/* formats and inserts the specified size into the given buffer */
|
||||
static void format_size(char *, int, off_t);
|
||||
static void format_rate(char *, int, off_t);
|
||||
|
||||
/* updates the progressmeter to reflect the current state of the transfer */
|
||||
void refresh_progress_meter(void);
|
||||
|
||||
/* signal handler for updating the progress meter */
|
||||
static void update_progress_meter(int);
|
||||
|
||||
static time_t start; /* start progress */
|
||||
static time_t last_update; /* last progress update */
|
||||
static char *file; /* name of the file being transferred */
|
||||
static off_t end_pos; /* ending position of transfer */
|
||||
static off_t cur_pos; /* transfer position as of last refresh */
|
||||
static volatile off_t *counter; /* progress counter */
|
||||
static long stalled; /* how long we have been stalled */
|
||||
static int bytes_per_second; /* current speed in bytes per second */
|
||||
static int win_size; /* terminal window size */
|
||||
|
||||
/* units for format_size */
|
||||
static const char unit[] = " KMGT";
|
||||
|
||||
static int
|
||||
can_output(void)
|
||||
{
|
||||
return (getpgrp() == tcgetpgrp(STDOUT_FILENO));
|
||||
}
|
||||
|
||||
static void
|
||||
format_rate(char *buf, int size, off_t bytes)
|
||||
{
|
||||
int i;
|
||||
|
||||
bytes *= 100;
|
||||
for (i = 0; bytes >= 100*1000 && unit[i] != 'T'; i++)
|
||||
bytes = (bytes + 512) / 1024;
|
||||
if (i == 0) {
|
||||
i++;
|
||||
bytes = (bytes + 512) / 1024;
|
||||
}
|
||||
snprintf(buf, size, "%3lld.%1lld%c%s",
|
||||
(int64_t) bytes / 100,
|
||||
(int64_t) (bytes + 5) / 10 % 10,
|
||||
unit[i],
|
||||
i ? "B" : " ");
|
||||
}
|
||||
|
||||
static void
|
||||
format_size(char *buf, int size, off_t bytes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; bytes >= 10000 && unit[i] != 'T'; i++)
|
||||
bytes = (bytes + 512) / 1024;
|
||||
snprintf(buf, size, "%4lld%c%s",
|
||||
(int64_t) bytes,
|
||||
unit[i],
|
||||
i ? "B" : " ");
|
||||
}
|
||||
|
||||
void
|
||||
refresh_progress_meter(void)
|
||||
{
|
||||
char buf[MAX_WINSIZE + 1];
|
||||
time_t now;
|
||||
off_t transferred;
|
||||
double elapsed;
|
||||
int percent;
|
||||
int bytes_left;
|
||||
int cur_speed;
|
||||
int hours, minutes, seconds;
|
||||
int i, len;
|
||||
int file_len;
|
||||
|
||||
transferred = *counter - cur_pos;
|
||||
cur_pos = *counter;
|
||||
now = time(NULL);
|
||||
bytes_left = end_pos - cur_pos;
|
||||
|
||||
if (bytes_left > 0)
|
||||
elapsed = now - last_update;
|
||||
else
|
||||
elapsed = now - start;
|
||||
|
||||
/* calculate speed */
|
||||
if (elapsed != 0)
|
||||
cur_speed = (transferred / elapsed);
|
||||
else
|
||||
cur_speed = 0;
|
||||
|
||||
#define AGE_FACTOR 0.9
|
||||
if (bytes_per_second != 0) {
|
||||
bytes_per_second = (bytes_per_second * AGE_FACTOR) +
|
||||
(cur_speed * (1.0 - AGE_FACTOR));
|
||||
} else
|
||||
bytes_per_second = cur_speed;
|
||||
|
||||
/* filename */
|
||||
buf[0] = '\0';
|
||||
file_len = win_size - 35;
|
||||
if (file_len > 0) {
|
||||
len = snprintf(buf, file_len + 1, "\r%s", file);
|
||||
if (len < 0)
|
||||
len = 0;
|
||||
for (i = len; i < file_len; i++ )
|
||||
buf[i] = ' ';
|
||||
buf[file_len] = '\0';
|
||||
}
|
||||
|
||||
/* percent of transfer done */
|
||||
if (end_pos != 0)
|
||||
percent = ((float)cur_pos / end_pos) * 100;
|
||||
else
|
||||
percent = 100;
|
||||
snprintf(buf + strlen(buf), win_size - strlen(buf),
|
||||
" %3d%% ", percent);
|
||||
|
||||
/* amount transferred */
|
||||
format_size(buf + strlen(buf), win_size - strlen(buf),
|
||||
cur_pos);
|
||||
strlcat(buf, " ", win_size);
|
||||
|
||||
/* bandwidth usage */
|
||||
format_rate(buf + strlen(buf), win_size - strlen(buf),
|
||||
bytes_per_second);
|
||||
strlcat(buf, "/s ", win_size);
|
||||
|
||||
/* ETA */
|
||||
if (!transferred)
|
||||
stalled += elapsed;
|
||||
else
|
||||
stalled = 0;
|
||||
|
||||
if (stalled >= STALL_TIME)
|
||||
strlcat(buf, "- stalled -", win_size);
|
||||
else if (bytes_per_second == 0 && bytes_left)
|
||||
strlcat(buf, " --:-- ETA", win_size);
|
||||
else {
|
||||
if (bytes_left > 0)
|
||||
seconds = bytes_left / bytes_per_second;
|
||||
else
|
||||
seconds = elapsed;
|
||||
|
||||
hours = seconds / 3600;
|
||||
seconds -= hours * 3600;
|
||||
minutes = seconds / 60;
|
||||
seconds -= minutes * 60;
|
||||
|
||||
if (hours != 0)
|
||||
snprintf(buf + strlen(buf), win_size - strlen(buf),
|
||||
"%d:%02d:%02d", hours, minutes, seconds);
|
||||
else
|
||||
snprintf(buf + strlen(buf), win_size - strlen(buf),
|
||||
" %02d:%02d", minutes, seconds);
|
||||
|
||||
if (bytes_left > 0)
|
||||
strlcat(buf, " ETA", win_size);
|
||||
else
|
||||
strlcat(buf, " ", win_size);
|
||||
}
|
||||
|
||||
atomicio(vwrite, STDOUT_FILENO, buf, win_size);
|
||||
last_update = now;
|
||||
}
|
||||
|
||||
static void
|
||||
update_progress_meter(int ignore)
|
||||
{
|
||||
int save_errno;
|
||||
|
||||
save_errno = errno;
|
||||
|
||||
if (can_output())
|
||||
refresh_progress_meter();
|
||||
|
||||
signal(SIGALRM, update_progress_meter);
|
||||
alarm(UPDATE_INTERVAL);
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
void
|
||||
start_progress_meter(char *f, off_t filesize, off_t *stat)
|
||||
{
|
||||
struct winsize winsize;
|
||||
|
||||
start = last_update = time(NULL);
|
||||
file = f;
|
||||
end_pos = filesize;
|
||||
cur_pos = 0;
|
||||
counter = stat;
|
||||
stalled = 0;
|
||||
bytes_per_second = 0;
|
||||
|
||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) != -1 &&
|
||||
winsize.ws_col != 0) {
|
||||
if (winsize.ws_col > MAX_WINSIZE)
|
||||
win_size = MAX_WINSIZE;
|
||||
else
|
||||
win_size = winsize.ws_col;
|
||||
} else
|
||||
win_size = DEFAULT_WINSIZE;
|
||||
win_size += 1; /* trailing \0 */
|
||||
|
||||
if (can_output())
|
||||
refresh_progress_meter();
|
||||
|
||||
signal(SIGALRM, update_progress_meter);
|
||||
alarm(UPDATE_INTERVAL);
|
||||
}
|
||||
|
||||
void
|
||||
stop_progress_meter(void)
|
||||
{
|
||||
alarm(0);
|
||||
|
||||
if (!can_output())
|
||||
return;
|
||||
|
||||
/* Ensure we complete the progress */
|
||||
if (cur_pos != end_pos)
|
||||
refresh_progress_meter();
|
||||
|
||||
atomicio(vwrite, STDOUT_FILENO, "\n", 1);
|
||||
}
|
||||
#endif /* PROGRESS_METER */
|
||||
27
progressmeter.h
Normal file
27
progressmeter.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/* $OpenBSD: progressmeter.h,v 1.1 2003/01/10 08:19:07 fgsch Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2002 Nils Nordman. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
*/
|
||||
|
||||
void start_progress_meter(char *, off_t, off_t *);
|
||||
void stop_progress_meter(void);
|
||||
89
queue.c
Normal file
89
queue.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "queue.h"
|
||||
|
||||
void initqueue(struct Queue* queue) {
|
||||
|
||||
queue->head = NULL;
|
||||
queue->tail = NULL;
|
||||
queue->count = 0;
|
||||
}
|
||||
|
||||
int isempty(struct Queue* queue) {
|
||||
|
||||
return (queue->head == NULL);
|
||||
}
|
||||
|
||||
void* dequeue(struct Queue* queue) {
|
||||
|
||||
void* ret;
|
||||
struct Link* oldhead;
|
||||
assert(!isempty(queue));
|
||||
|
||||
ret = queue->head->item;
|
||||
oldhead = queue->head;
|
||||
|
||||
if (oldhead->link != NULL) {
|
||||
queue->head = oldhead->link;
|
||||
} else {
|
||||
queue->head = NULL;
|
||||
queue->tail = NULL;
|
||||
TRACE(("empty queue dequeing"));
|
||||
}
|
||||
|
||||
m_free(oldhead);
|
||||
queue->count--;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *examine(struct Queue* queue) {
|
||||
|
||||
assert(!isempty(queue));
|
||||
return queue->head->item;
|
||||
}
|
||||
|
||||
void enqueue(struct Queue* queue, void* item) {
|
||||
|
||||
struct Link* newlink;
|
||||
|
||||
TRACE(("enter enqueue"));
|
||||
newlink = (struct Link*)m_malloc(sizeof(struct Link));
|
||||
|
||||
newlink->item = item;
|
||||
newlink->link = NULL;
|
||||
|
||||
if (queue->tail != NULL) {
|
||||
queue->tail->link = newlink;
|
||||
}
|
||||
queue->tail = newlink;
|
||||
|
||||
if (queue->head == NULL) {
|
||||
queue->head = newlink;
|
||||
}
|
||||
queue->count++;
|
||||
TRACE(("leave enqueue"));
|
||||
}
|
||||
49
queue.h
Normal file
49
queue.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _QUEUE_H_
|
||||
#define _QUEUE_H_
|
||||
|
||||
struct Link {
|
||||
|
||||
void* item;
|
||||
struct Link* link;
|
||||
|
||||
};
|
||||
|
||||
struct Queue {
|
||||
|
||||
struct Link* head;
|
||||
struct Link* tail;
|
||||
unsigned int count; /* safety value */
|
||||
|
||||
};
|
||||
|
||||
void initqueue(struct Queue* queue);
|
||||
int isempty(struct Queue* queue);
|
||||
void* dequeue(struct Queue* queue);
|
||||
void *examine(struct Queue* queue);
|
||||
void enqueue(struct Queue* queue, void* item);
|
||||
|
||||
#endif
|
||||
178
random.c
Normal file
178
random.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
int donerandinit = 0;
|
||||
|
||||
/* this is used to generate unique output from the same hashpool */
|
||||
unsigned int counter = 0;
|
||||
#define MAX_COUNTER 1000000/* the max value for the counter, so it won't loop */
|
||||
|
||||
unsigned char hashpool[SHA1_HASH_SIZE];
|
||||
|
||||
#define INIT_SEED_SIZE 32 /* 256 bits */
|
||||
|
||||
static void readrand(unsigned char* buf, unsigned int buflen);
|
||||
|
||||
/* The basic setup is we read some data from DEV_URANDOM or PRNGD and hash it
|
||||
* into hashpool. To read data, we hash together current hashpool contents,
|
||||
* and a counter. We feed more data in by hashing the current pool and new
|
||||
* data into the pool.
|
||||
*
|
||||
* It is important to ensure that counter doesn't wrap around before we
|
||||
* feed in new entropy.
|
||||
*
|
||||
*/
|
||||
|
||||
static void readrand(unsigned char* buf, unsigned int buflen) {
|
||||
|
||||
int readfd;
|
||||
unsigned int readpos;
|
||||
int readlen;
|
||||
#ifdef DROPBEAR_EGD
|
||||
struct sockaddr_un egdsock;
|
||||
char egdcmd[2];
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_DEV_URANDOM
|
||||
readfd = open(DEV_URANDOM, O_RDONLY);
|
||||
if (!readfd) {
|
||||
dropbear_exit("couldn't open random device");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_EGD
|
||||
memset((void*)&egdsock, 0x0, sizeof(egdsock));
|
||||
egdsock.sun_family = AF_UNIX;
|
||||
strlcpy(egdsock.sun_path, DROPBEAR_EGD_SOCKET,
|
||||
sizeof(egdsock.sun_path));
|
||||
|
||||
if ((readfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
dropbear_exit("couldn't open random device");
|
||||
}
|
||||
/* todo - try various common locations */
|
||||
if (connect(readfd, (struct sockaddr*)&egdsock,
|
||||
sizeof(struct sockaddr_un)) < 0) {
|
||||
dropbear_exit("couldn't open random device");
|
||||
}
|
||||
|
||||
if (buflen > 255)
|
||||
dropbear_exit("can't request more than 255 bytes from egd");
|
||||
egdcmd[0] = 0x02; /* blocking read */
|
||||
egdcmd[1] = (unsigned char)buflen;
|
||||
if (write(readfd, egdcmd, 2) < 0)
|
||||
dropbear_exit("can't send command to egd");
|
||||
#endif
|
||||
|
||||
/* read the actual random data */
|
||||
readpos = 0;
|
||||
do {
|
||||
readlen = read(readfd, &buf[readpos], buflen - readpos);
|
||||
if (readlen <= 0) {
|
||||
if (readlen < 0 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
dropbear_exit("error reading random source");
|
||||
}
|
||||
readpos += readlen;
|
||||
} while (readpos < buflen);
|
||||
|
||||
close (readfd);
|
||||
}
|
||||
|
||||
/* initialise the prng from /dev/urandom or prngd */
|
||||
void seedrandom() {
|
||||
|
||||
unsigned char readbuf[INIT_SEED_SIZE];
|
||||
|
||||
hash_state hs;
|
||||
|
||||
/* initialise so compilers will be happy about hashing it */
|
||||
if (!donerandinit) {
|
||||
m_burn(hashpool, sizeof(hashpool));
|
||||
}
|
||||
|
||||
/* get the seed data */
|
||||
readrand(readbuf, sizeof(readbuf));
|
||||
|
||||
/* hash in the new seed data */
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
|
||||
sha1_process(&hs, (void*)readbuf, sizeof(readbuf));
|
||||
sha1_done(&hs, hashpool);
|
||||
|
||||
counter = 0;
|
||||
donerandinit = 1;
|
||||
}
|
||||
|
||||
/* return len bytes of pseudo-random data */
|
||||
void genrandom(unsigned char* buf, unsigned int len) {
|
||||
|
||||
hash_state hs;
|
||||
unsigned char hash[SHA1_HASH_SIZE];
|
||||
unsigned int copylen;
|
||||
|
||||
if (!donerandinit) {
|
||||
dropbear_exit("seedrandom not done");
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
|
||||
sha1_process(&hs, (void*)&counter, sizeof(counter));
|
||||
sha1_done(&hs, hash);
|
||||
|
||||
counter++;
|
||||
if (counter > MAX_COUNTER) {
|
||||
seedrandom();
|
||||
}
|
||||
|
||||
copylen = MIN(len, SHA1_HASH_SIZE);
|
||||
memcpy(buf, hash, copylen);
|
||||
len -= copylen;
|
||||
buf += copylen;
|
||||
}
|
||||
m_burn(hash, sizeof(hash));
|
||||
}
|
||||
|
||||
/* Adds entropy to the PRNG state. As long as the hash is strong, then we
|
||||
* don't need to worry about entropy being added "diluting" the current
|
||||
* state - it should only make it stronger. */
|
||||
void addrandom(unsigned char* buf, unsigned int len) {
|
||||
|
||||
hash_state hs;
|
||||
if (!donerandinit) {
|
||||
dropbear_exit("seedrandom not done");
|
||||
}
|
||||
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, (void*)buf, len);
|
||||
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
|
||||
sha1_done(&hs, hashpool);
|
||||
counter = 0;
|
||||
|
||||
}
|
||||
32
random.h
Normal file
32
random.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _RANDOM_H_
|
||||
#define _RANDOM_H_
|
||||
|
||||
void seedrandom();
|
||||
void genrandom(unsigned char* buf, int len);
|
||||
void addrandom(unsigned char* buf, int len);
|
||||
|
||||
#endif /* _RANDOM_H_ */
|
||||
301
remotetcpfwd.c
Normal file
301
remotetcpfwd.c
Normal file
@@ -0,0 +1,301 @@
|
||||
#include "includes.h"
|
||||
#include "ssh.h"
|
||||
#include "remotetcpfwd.h"
|
||||
#include "dbutil.h"
|
||||
#include "session.h"
|
||||
#include "buffer.h"
|
||||
#include "packet.h"
|
||||
#include "tcpfwd.h"
|
||||
|
||||
#ifndef DISABLE_REMOTETCPFWD
|
||||
|
||||
struct RemoteTCP {
|
||||
|
||||
unsigned char* addr;
|
||||
unsigned int port;
|
||||
|
||||
};
|
||||
|
||||
static void send_msg_request_success();
|
||||
static void send_msg_request_failure();
|
||||
static int cancelremotetcp();
|
||||
static int remotetcpreq();
|
||||
static int newlistener(unsigned char* bindaddr, unsigned int port);
|
||||
static void acceptremote(struct TCPListener *listener);
|
||||
|
||||
/* At the moment this is completely used for tcp code (with the name reflecting
|
||||
* that). If new request types are added, this should be replaced with code
|
||||
* similar to the request-switching in chansession.c */
|
||||
void recv_msg_global_request_remotetcp() {
|
||||
|
||||
unsigned char* reqname = NULL;
|
||||
unsigned int namelen;
|
||||
unsigned int wantreply = 0;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
TRACE(("enter recv_msg_global_request_remotetcp"));
|
||||
|
||||
if (ses.opts->noremotetcp) {
|
||||
TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
reqname = buf_getstring(ses.payload, &namelen);
|
||||
wantreply = buf_getbyte(ses.payload);
|
||||
|
||||
if (namelen > MAXNAMLEN) {
|
||||
TRACE(("name len is wrong: %d", namelen));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strcmp("tcpip-forward", reqname) == 0) {
|
||||
ret = remotetcpreq();
|
||||
} else if (strcmp("cancel-tcpip-forward", reqname) == 0) {
|
||||
ret = cancelremotetcp();
|
||||
} else {
|
||||
TRACE(("reqname isn't tcpip-forward: '%s'", reqname));
|
||||
}
|
||||
|
||||
out:
|
||||
if (wantreply) {
|
||||
if (ret == DROPBEAR_SUCCESS) {
|
||||
send_msg_request_success();
|
||||
} else {
|
||||
send_msg_request_failure();
|
||||
}
|
||||
}
|
||||
|
||||
m_free(reqname);
|
||||
|
||||
TRACE(("leave recv_msg_global_request"));
|
||||
}
|
||||
|
||||
static void acceptremote(struct TCPListener *listener) {
|
||||
|
||||
int fd;
|
||||
struct sockaddr addr;
|
||||
int len;
|
||||
char ipstring[NI_MAXHOST], portstring[NI_MAXSERV];
|
||||
struct RemoteTCP *tcpinfo = (struct RemoteTCP*)(listener->typedata);
|
||||
|
||||
len = sizeof(addr);
|
||||
|
||||
fd = accept(listener->sock, &addr, &len);
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getnameinfo(&addr, len, ipstring, sizeof(ipstring), portstring,
|
||||
sizeof(portstring), NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (send_msg_channel_open_init(fd, CHANNEL_ID_TCPFORWARDED,
|
||||
"forwarded-tcpip") == DROPBEAR_SUCCESS) {
|
||||
buf_putstring(ses.writepayload, tcpinfo->addr,
|
||||
strlen(tcpinfo->addr));
|
||||
buf_putint(ses.writepayload, tcpinfo->port);
|
||||
buf_putstring(ses.writepayload, ipstring, strlen(ipstring));
|
||||
buf_putint(ses.writepayload, atol(portstring));
|
||||
encrypt_packet();
|
||||
}
|
||||
}
|
||||
|
||||
static void cleanupremote(struct TCPListener *listener) {
|
||||
|
||||
struct RemoteTCP *tcpinfo = (struct RemoteTCP*)(listener->typedata);
|
||||
|
||||
m_free(tcpinfo->addr);
|
||||
m_free(tcpinfo);
|
||||
}
|
||||
|
||||
static void send_msg_request_success() {
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS);
|
||||
encrypt_packet();
|
||||
|
||||
}
|
||||
|
||||
static void send_msg_request_failure() {
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE);
|
||||
encrypt_packet();
|
||||
|
||||
}
|
||||
|
||||
static int matchtcp(void* typedata1, void* typedata2) {
|
||||
|
||||
const struct RemoteTCP *info1 = (struct RemoteTCP*)typedata1;
|
||||
const struct RemoteTCP *info2 = (struct RemoteTCP*)typedata2;
|
||||
|
||||
return info1->port == info2->port
|
||||
&& (strcmp(info1->addr, info2->addr) == 0);
|
||||
}
|
||||
|
||||
static int cancelremotetcp() {
|
||||
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
unsigned char * bindaddr = NULL;
|
||||
unsigned int addrlen;
|
||||
unsigned int port;
|
||||
struct TCPListener * listener = NULL;
|
||||
struct RemoteTCP tcpinfo;
|
||||
|
||||
TRACE(("enter cancelremotetcp"));
|
||||
|
||||
bindaddr = buf_getstring(ses.payload, &addrlen);
|
||||
if (addrlen > MAX_IP_LEN) {
|
||||
TRACE(("addr len too long: %d", addrlen));
|
||||
goto out;
|
||||
}
|
||||
|
||||
port = buf_getint(ses.payload);
|
||||
|
||||
tcpinfo.addr = bindaddr;
|
||||
tcpinfo.port = port;
|
||||
listener = get_listener(CHANNEL_ID_TCPFORWARDED, &tcpinfo, matchtcp);
|
||||
if (listener) {
|
||||
remove_listener( listener );
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
out:
|
||||
m_free(bindaddr);
|
||||
TRACE(("leave cancelremotetcp"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int remotetcpreq() {
|
||||
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
unsigned char * bindaddr = NULL;
|
||||
unsigned int addrlen;
|
||||
unsigned int port;
|
||||
|
||||
TRACE(("enter remotetcpreq"));
|
||||
|
||||
bindaddr = buf_getstring(ses.payload, &addrlen);
|
||||
if (addrlen > MAX_IP_LEN) {
|
||||
TRACE(("addr len too long: %d", addrlen));
|
||||
goto out;
|
||||
}
|
||||
|
||||
port = buf_getint(ses.payload);
|
||||
|
||||
if (port == 0) {
|
||||
dropbear_log(LOG_INFO, "Server chosen tcpfwd ports are unsupported");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (port < 1 || port > 65535) {
|
||||
TRACE(("invalid port: %d", port));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* XXX matt - server change
|
||||
if (ses.authstate.pw->pw_uid != 0
|
||||
&& port < IPPORT_RESERVED) {
|
||||
TRACE(("can't assign port < 1024 for non-root"));
|
||||
goto out;
|
||||
}
|
||||
*/
|
||||
|
||||
ret = newlistener(bindaddr, port);
|
||||
|
||||
out:
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
/* we only free it if a listener wasn't created, since the listener
|
||||
* has to remember it if it's to be cancelled */
|
||||
m_free(bindaddr);
|
||||
}
|
||||
TRACE(("leave remotetcpreq"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int newlistener(unsigned char* bindaddr, unsigned int port) {
|
||||
|
||||
struct RemoteTCP * tcpinfo = NULL;
|
||||
char portstring[6]; /* "65535\0" */
|
||||
struct addrinfo *res = NULL, *ai = NULL;
|
||||
struct addrinfo hints;
|
||||
int sock = -1;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
TRACE(("enter newlistener"));
|
||||
|
||||
/* first we try to bind, so don't need to do so much cleanup on failure */
|
||||
snprintf(portstring, sizeof(portstring), "%d", port);
|
||||
memset(&hints, 0x0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_family = PF_INET;
|
||||
hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
|
||||
|
||||
if (getaddrinfo(bindaddr, portstring, &hints, &res) < 0) {
|
||||
TRACE(("leave newlistener: getaddrinfo failed: %s",
|
||||
strerror(errno)));
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* find the first one which works */
|
||||
for (ai = res; ai != NULL; ai = ai->ai_next) {
|
||||
if (ai->ai_family != PF_INET && ai->ai_family != PF_INET6) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sock = socket(ai->ai_family, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
TRACE(("socket failed: %s", strerror(errno)));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
|
||||
TRACE(("bind failed: %s", strerror(errno)));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (listen(sock, 20) < 0) {
|
||||
TRACE(("listen failed: %s", strerror(errno)));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
|
||||
TRACE(("fcntl nonblocking failed: %s", strerror(errno)));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* success */
|
||||
break;
|
||||
|
||||
fail:
|
||||
close(sock);
|
||||
}
|
||||
|
||||
|
||||
if (ai == NULL) {
|
||||
TRACE(("no successful sockets"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
tcpinfo = (struct RemoteTCP*)m_malloc(sizeof(struct RemoteTCP));
|
||||
tcpinfo->addr = bindaddr;
|
||||
tcpinfo->port = port;
|
||||
|
||||
ret = new_fwd(sock, CHANNEL_ID_TCPFORWARDED, tcpinfo,
|
||||
acceptremote, cleanupremote);
|
||||
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_free(tcpinfo);
|
||||
}
|
||||
|
||||
done:
|
||||
if (res) {
|
||||
freeaddrinfo(res);
|
||||
}
|
||||
|
||||
TRACE(("leave newlistener"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* DISABLE_REMOTETCPFWD */
|
||||
6
remotetcpfwd.h
Normal file
6
remotetcpfwd.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef _REMOTETCPFWD_H
|
||||
#define _REMOTETCPFWD_H
|
||||
|
||||
void recv_msg_global_request_remotetcp();
|
||||
|
||||
#endif /* _REMOTETCPFWD_H */
|
||||
362
rsa.c
Normal file
362
rsa.c
Normal file
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
/* Perform RSA operations on data, including reading keys, signing and
|
||||
* verification.
|
||||
*
|
||||
* The format is specified in rfc2437, Applied Cryptography or The Handbook of
|
||||
* Applied Cryptography detail the general algorithm. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "bignum.h"
|
||||
#include "rsa.h"
|
||||
#include "buffer.h"
|
||||
#include "ssh.h"
|
||||
#include "random.h"
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
|
||||
static mp_int * rsa_pad_em(rsa_key * key,
|
||||
const unsigned char * data, unsigned int len);
|
||||
|
||||
/* Load a public rsa key from a buffer, initialising the values.
|
||||
* The key will have the same format as buf_put_rsa_key.
|
||||
* These should be freed with rsa_key_free.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_rsa_pub_key(buffer* buf, rsa_key *key) {
|
||||
|
||||
TRACE(("enter buf_get_rsa_pub_key"));
|
||||
assert(key != NULL);
|
||||
key->e = m_malloc(sizeof(mp_int));
|
||||
key->n = m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(key->e, key->n, NULL);
|
||||
key->d = NULL;
|
||||
key->p = NULL;
|
||||
key->q = NULL;
|
||||
|
||||
buf_incrpos(buf, 4+SSH_SIGNKEY_RSA_LEN); /* int + "ssh-rsa" */
|
||||
|
||||
if (buf_getmpint(buf, key->e) == DROPBEAR_FAILURE
|
||||
|| buf_getmpint(buf, key->n) == DROPBEAR_FAILURE) {
|
||||
TRACE(("leave buf_get_rsa_pub_key: failure"));
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
if (mp_count_bits(key->n) < MIN_RSA_KEYLEN) {
|
||||
dropbear_log(LOG_WARNING, "rsa key too short");
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
TRACE(("leave buf_get_rsa_pub_key: success"));
|
||||
return DROPBEAR_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
/* Same as buf_get_rsa_pub_key, but reads a private "x" key at the end.
|
||||
* Loads a private rsa key from a buffer
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_rsa_priv_key(buffer* buf, rsa_key *key) {
|
||||
|
||||
assert(key != NULL);
|
||||
|
||||
TRACE(("enter buf_get_rsa_priv_key"));
|
||||
|
||||
if (buf_get_rsa_pub_key(buf, key) == DROPBEAR_FAILURE) {
|
||||
TRACE(("leave buf_get_rsa_priv_key: pub: ret == DROPBEAR_FAILURE"));
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
key->d = m_malloc(sizeof(mp_int));
|
||||
m_mp_init(key->d);
|
||||
if (buf_getmpint(buf, key->d) == DROPBEAR_FAILURE) {
|
||||
TRACE(("leave buf_get_rsa_priv_key: d: ret == DROPBEAR_FAILURE"));
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* old Dropbear private keys didn't keep p and q, so we will ignore them*/
|
||||
if (buf->pos == buf->len) {
|
||||
key->p = NULL;
|
||||
key->q = NULL;
|
||||
} else {
|
||||
key->p = m_malloc(sizeof(mp_int));
|
||||
key->q = m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(key->p, key->q, NULL);
|
||||
|
||||
if (buf_getmpint(buf, key->p) == DROPBEAR_FAILURE) {
|
||||
TRACE(("leave buf_get_rsa_priv_key: p: ret == DROPBEAR_FAILURE"));
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
if (buf_getmpint(buf, key->q) == DROPBEAR_FAILURE) {
|
||||
TRACE(("leave buf_get_rsa_priv_key: q: ret == DROPBEAR_FAILURE"));
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE(("leave buf_get_rsa_priv_key"));
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Clear and free the memory used by a public or private key */
|
||||
void rsa_key_free(rsa_key *key) {
|
||||
|
||||
TRACE(("enter rsa_key_free"));
|
||||
|
||||
if (key == NULL) {
|
||||
TRACE(("leave rsa_key_free: key == NULL"));
|
||||
return;
|
||||
}
|
||||
if (key->d) {
|
||||
mp_clear(key->d);
|
||||
m_free(key->d);
|
||||
}
|
||||
if (key->e) {
|
||||
mp_clear(key->e);
|
||||
m_free(key->e);
|
||||
}
|
||||
if (key->n) {
|
||||
mp_clear(key->n);
|
||||
m_free(key->n);
|
||||
}
|
||||
if (key->p) {
|
||||
mp_clear(key->p);
|
||||
m_free(key->p);
|
||||
}
|
||||
if (key->q) {
|
||||
mp_clear(key->q);
|
||||
m_free(key->q);
|
||||
}
|
||||
m_free(key);
|
||||
TRACE(("leave rsa_key_free"));
|
||||
}
|
||||
|
||||
/* Put the public rsa key into the buffer in the required format:
|
||||
*
|
||||
* string "ssh-rsa"
|
||||
* mp_int e
|
||||
* mp_int n
|
||||
*/
|
||||
void buf_put_rsa_pub_key(buffer* buf, rsa_key *key) {
|
||||
|
||||
TRACE(("enter buf_put_rsa_pub_key"));
|
||||
assert(key != NULL);
|
||||
|
||||
buf_putstring(buf, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN);
|
||||
buf_putmpint(buf, key->e);
|
||||
buf_putmpint(buf, key->n);
|
||||
|
||||
TRACE(("leave buf_put_rsa_pub_key"));
|
||||
|
||||
}
|
||||
|
||||
/* Same as buf_put_rsa_pub_key, but with the private "x" key appended */
|
||||
void buf_put_rsa_priv_key(buffer* buf, rsa_key *key) {
|
||||
|
||||
TRACE(("enter buf_put_rsa_priv_key"));
|
||||
|
||||
assert(key != NULL);
|
||||
buf_put_rsa_pub_key(buf, key);
|
||||
buf_putmpint(buf, key->d);
|
||||
|
||||
/* new versions have p and q, old versions don't */
|
||||
if (key->p) {
|
||||
buf_putmpint(buf, key->p);
|
||||
}
|
||||
if (key->q) {
|
||||
buf_putmpint(buf, key->q);
|
||||
}
|
||||
|
||||
|
||||
TRACE(("leave buf_put_rsa_priv_key"));
|
||||
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
/* Verify a signature in buf, made on data by the key given.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
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;
|
||||
mp_int *rsa_em = NULL;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
assert(key != NULL);
|
||||
|
||||
m_mp_init_multi(&rsa_mdash, &rsa_s, NULL);
|
||||
|
||||
slen = buf_getint(buf);
|
||||
if (slen != (unsigned int)mp_unsigned_bin_size(key->n)) {
|
||||
TRACE(("bad size"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mp_read_unsigned_bin(&rsa_s, buf_getptr(buf, buf->len - buf->pos),
|
||||
buf->len - buf->pos) != MP_OKAY) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* check that s <= n-1 */
|
||||
if (mp_cmp(&rsa_s, key->n) != MP_LT) {
|
||||
TRACE(("s > n-1"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* create the magic PKCS padded value */
|
||||
rsa_em = rsa_pad_em(key, data, len);
|
||||
|
||||
if (mp_exptmod(&rsa_s, key->e, key->n, &rsa_mdash) != MP_OKAY) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mp_cmp(rsa_em, &rsa_mdash) == MP_EQ) {
|
||||
/* signature is valid */
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
out:
|
||||
mp_clear_multi(rsa_em, &rsa_mdash, &rsa_s, NULL);
|
||||
m_free(rsa_em);
|
||||
return ret;
|
||||
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
/* Sign the data presented with key, writing the signature contents
|
||||
* to the buffer */
|
||||
void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
unsigned int nsize, ssize;
|
||||
unsigned int i;
|
||||
mp_int rsa_s;
|
||||
mp_int *rsa_em;
|
||||
|
||||
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);
|
||||
/* s = em^d mod n */
|
||||
if (mp_exptmod(rsa_em, key->d, key->n, &rsa_s) != MP_OKAY) {
|
||||
dropbear_exit("rsa error");
|
||||
}
|
||||
mp_clear(rsa_em);
|
||||
m_free(rsa_em);
|
||||
|
||||
/* create the signature to return */
|
||||
buf_putstring(buf, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN);
|
||||
|
||||
nsize = mp_unsigned_bin_size(key->n);
|
||||
|
||||
/* string rsa_signature_blob length */
|
||||
buf_putint(buf, nsize);
|
||||
/* pad out s to same length as n */
|
||||
ssize = mp_unsigned_bin_size(&rsa_s);
|
||||
assert(ssize <= nsize);
|
||||
for (i = 0; i < nsize-ssize; i++) {
|
||||
buf_putbyte(buf, 0x00);
|
||||
}
|
||||
|
||||
if (mp_to_unsigned_bin(&rsa_s, buf_getwriteptr(buf, ssize)) != MP_OKAY) {
|
||||
dropbear_exit("rsa error");
|
||||
}
|
||||
buf_incrwritepos(buf, ssize);
|
||||
mp_clear(&rsa_s);
|
||||
|
||||
#if defined(DEBUG_RSA) && defined(DEBUG_TRACE)
|
||||
printhex(buf->data, buf->len);
|
||||
#endif
|
||||
|
||||
|
||||
TRACE(("leave buf_put_rsa_sign"));
|
||||
}
|
||||
|
||||
/* Creates the message value as expected by PKCS, see rfc2437 etc */
|
||||
/* format to be padded to is:
|
||||
* EM = 01 | FF* | 00 | prefix | hash
|
||||
*
|
||||
* where FF is repeated enough times to make EM one byte
|
||||
* shorter than the size of key->n
|
||||
*
|
||||
* prefix is the ASN1 designator prefix,
|
||||
* hex 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14
|
||||
*/
|
||||
static mp_int * rsa_pad_em(rsa_key * key,
|
||||
const unsigned char * data, unsigned int len) {
|
||||
|
||||
/* ASN1 designator (including the 0x00 preceding) */
|
||||
const char rsa_asn1_magic[] =
|
||||
{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;
|
||||
hash_state hs;
|
||||
unsigned int nsize;
|
||||
mp_int * rsa_em;
|
||||
|
||||
assert(key != NULL);
|
||||
assert(data != NULL);
|
||||
nsize = mp_unsigned_bin_size(key->n);
|
||||
|
||||
rsa_EM = buf_new(nsize-1);
|
||||
/* type byte */
|
||||
buf_putbyte(rsa_EM, 0x01);
|
||||
/* Padding with 0xFF bytes */
|
||||
while(rsa_EM->pos != rsa_EM->size - RSA_ASN1_MAGIC_LEN - SHA1_HASH_SIZE) {
|
||||
buf_putbyte(rsa_EM, 0xff);
|
||||
}
|
||||
/* Magic ASN1 stuff */
|
||||
memcpy(buf_getwriteptr(rsa_EM, RSA_ASN1_MAGIC_LEN),
|
||||
rsa_asn1_magic, RSA_ASN1_MAGIC_LEN);
|
||||
buf_incrwritepos(rsa_EM, RSA_ASN1_MAGIC_LEN);
|
||||
|
||||
/* The hash of the data */
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, data, len);
|
||||
sha1_done(&hs, buf_getwriteptr(rsa_EM, SHA1_HASH_SIZE));
|
||||
buf_incrwritepos(rsa_EM, SHA1_HASH_SIZE);
|
||||
|
||||
assert(rsa_EM->pos == rsa_EM->size);
|
||||
|
||||
/* Create the mp_int from the encoded bytes */
|
||||
buf_setpos(rsa_EM, 0);
|
||||
rsa_em = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
m_mp_init(rsa_em);
|
||||
if (mp_read_unsigned_bin(rsa_em, buf_getptr(rsa_EM, rsa_EM->size),
|
||||
rsa_EM->size) != MP_OKAY) {
|
||||
dropbear_exit("rsa error");
|
||||
}
|
||||
buf_free(rsa_EM);
|
||||
|
||||
return rsa_em;
|
||||
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_RSA */
|
||||
61
rsa.h
Normal file
61
rsa.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _RSA_H_
|
||||
#define _RSA_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
|
||||
#define RSA_SIGNATURE_SIZE 4+7+4+40
|
||||
|
||||
struct RSA_key {
|
||||
|
||||
mp_int* n;
|
||||
mp_int* e;
|
||||
mp_int* d;
|
||||
mp_int* p;
|
||||
mp_int* q;
|
||||
|
||||
};
|
||||
|
||||
typedef struct RSA_key rsa_key;
|
||||
|
||||
void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_rsa_verify(buffer * buf, rsa_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
#endif
|
||||
int buf_get_rsa_pub_key(buffer* buf, rsa_key *key);
|
||||
int buf_get_rsa_priv_key(buffer* buf, rsa_key *key);
|
||||
void buf_put_rsa_pub_key(buffer* buf, rsa_key *key);
|
||||
void buf_put_rsa_priv_key(buffer* buf, rsa_key *key);
|
||||
void rsa_key_free(rsa_key *key);
|
||||
|
||||
#endif /* DROPBEAR_RSA */
|
||||
|
||||
#endif /* _RSA_H_ */
|
||||
72
runopts.h
Normal file
72
runopts.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _RUNOPTS_H_
|
||||
#define _RUNOPTS_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "signkey.h"
|
||||
#include "buffer.h"
|
||||
|
||||
struct SvrRunOpts {
|
||||
|
||||
char * rsakeyfile;
|
||||
char * dsskeyfile;
|
||||
char * bannerfile;
|
||||
int forkbg;
|
||||
|
||||
/* ports is an array of the portcount listening ports */
|
||||
uint16_t *ports;
|
||||
unsigned int portcount;
|
||||
|
||||
/* Flags indicating whether to use ipv4 and ipv6 */
|
||||
/* not used yet
|
||||
int ipv4;
|
||||
int ipv6;
|
||||
*/
|
||||
|
||||
#ifdef DO_MOTD
|
||||
/* whether to print the MOTD */
|
||||
int domotd;
|
||||
#endif
|
||||
|
||||
int norootlogin;
|
||||
|
||||
int noauthpass;
|
||||
int norootpass;
|
||||
|
||||
int nolocaltcp;
|
||||
int noremotetcp;
|
||||
|
||||
sign_key *hostkey;
|
||||
buffer * banner;
|
||||
|
||||
};
|
||||
|
||||
typedef struct SvrRunOpts runopts;
|
||||
|
||||
runopts * getrunopts(int argc, char ** argv);
|
||||
void freerunopts(runopts* opts);
|
||||
|
||||
#endif /* _RUNOPTS_H_ */
|
||||
161
scpmisc.c
Normal file
161
scpmisc.c
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
*/
|
||||
|
||||
/*RCSID("$OpenBSD: misc.c,v 1.22 2003/09/18 08:49:45 markus Exp $");*/
|
||||
|
||||
/* For xmalloc, xfree etc:
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Versions of malloc and friends that check their results, and never return
|
||||
* failure (they call fatal if they encounter an error).
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
/*RCSID("$OpenBSD: xmalloc.c,v 1.16 2001/07/23 18:21:46 stevesk Exp $");*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "scpmisc.h"
|
||||
|
||||
void *
|
||||
xmalloc(size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
if (size == 0) {
|
||||
fprintf(stderr, "xmalloc: zero size\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
ptr = malloc(size);
|
||||
if (ptr == NULL) {
|
||||
fprintf(stderr, "xmalloc: out of memory (allocating %lu bytes)\n", (u_long) size);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *
|
||||
xrealloc(void *ptr, size_t new_size)
|
||||
{
|
||||
void *new_ptr;
|
||||
|
||||
if (new_size == 0) {
|
||||
fprintf(stderr, "xrealloc: zero size\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (ptr == NULL)
|
||||
new_ptr = malloc(new_size);
|
||||
else
|
||||
new_ptr = realloc(ptr, new_size);
|
||||
if (new_ptr == NULL) {
|
||||
fprintf(stderr, "xrealloc: out of memory (new_size %lu bytes)\n", (u_long) new_size);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void
|
||||
xfree(void *ptr)
|
||||
{
|
||||
if (ptr == NULL) {
|
||||
fprintf(stderr, "xfree: NULL pointer given as argument\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
char *
|
||||
xstrdup(const char *str)
|
||||
{
|
||||
size_t len;
|
||||
char *cp;
|
||||
|
||||
len = strlen(str) + 1;
|
||||
cp = xmalloc(len);
|
||||
strncpy(cp, str, len);
|
||||
return cp;
|
||||
}
|
||||
|
||||
char *
|
||||
cleanhostname(char *host)
|
||||
{
|
||||
if (*host == '[' && host[strlen(host) - 1] == ']') {
|
||||
host[strlen(host) - 1] = '\0';
|
||||
return (host + 1);
|
||||
} else
|
||||
return host;
|
||||
}
|
||||
|
||||
char *
|
||||
colon(char *cp)
|
||||
{
|
||||
int flag = 0;
|
||||
|
||||
if (*cp == ':') /* Leading colon is part of file name. */
|
||||
return (0);
|
||||
if (*cp == '[')
|
||||
flag = 1;
|
||||
|
||||
for (; *cp; ++cp) {
|
||||
if (*cp == '@' && *(cp+1) == '[')
|
||||
flag = 1;
|
||||
if (*cp == ']' && *(cp+1) == ':' && flag)
|
||||
return (cp+1);
|
||||
if (*cp == ':' && !flag)
|
||||
return (cp);
|
||||
if (*cp == '/')
|
||||
return (0);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* function to assist building execv() arguments */
|
||||
void
|
||||
addargs(arglist *args, char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[1024];
|
||||
int nalloc;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
nalloc = args->nalloc;
|
||||
if (args->list == NULL) {
|
||||
nalloc = 32;
|
||||
args->num = 0;
|
||||
} else if (args->num+2 >= nalloc)
|
||||
nalloc *= 2;
|
||||
|
||||
args->list = xrealloc(args->list, nalloc * sizeof(char *));
|
||||
args->nalloc = nalloc;
|
||||
args->list[args->num++] = xstrdup(buf);
|
||||
args->list[args->num] = NULL;
|
||||
}
|
||||
44
scpmisc.h
Normal file
44
scpmisc.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* $OpenBSD: misc.h,v 1.12 2002/03/19 10:49:35 markus Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
/* actually from atomicio, but is only used in scp code */
|
||||
#define vwrite (ssize_t (*)(int, void *, size_t))write
|
||||
|
||||
char *chop(char *);
|
||||
char *strdelim(char **);
|
||||
void set_nonblock(int);
|
||||
void unset_nonblock(int);
|
||||
void set_nodelay(int);
|
||||
int a2port(const char *);
|
||||
char *cleanhostname(char *);
|
||||
char *colon(char *);
|
||||
long convtime(const char *);
|
||||
|
||||
struct passwd *pwcopy(struct passwd *);
|
||||
|
||||
typedef struct arglist arglist;
|
||||
struct arglist {
|
||||
char **list;
|
||||
int num;
|
||||
int nalloc;
|
||||
};
|
||||
void addargs(arglist *, char *, ...);
|
||||
|
||||
/* from xmalloc.h */
|
||||
void *xmalloc(size_t);
|
||||
void *xrealloc(void *, size_t);
|
||||
void xfree(void *);
|
||||
char *xstrdup(const char *);
|
||||
|
||||
|
||||
30
service.h
Normal file
30
service.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _SERVICE_H_
|
||||
#define _SERVICE_H_
|
||||
|
||||
void recv_msg_service_request();
|
||||
|
||||
#endif /* _SERVICE_H_ */
|
||||
176
session.h
Normal file
176
session.h
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _SESSION_H_
|
||||
#define _SESSION_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
#include "signkey.h"
|
||||
#include "kex.h"
|
||||
#include "auth.h"
|
||||
#include "channel.h"
|
||||
#include "queue.h"
|
||||
#include "runopts.h"
|
||||
#include "remotetcpfwd.h"
|
||||
|
||||
extern int sessinitdone; /* Is set to 0 somewhere */
|
||||
extern int exitflag;
|
||||
|
||||
void common_session_init(int sock, runopts *opts);
|
||||
void common_session_cleanup();
|
||||
void checktimeouts();
|
||||
void session_identification();
|
||||
|
||||
extern void(*session_remoteclosed)();
|
||||
|
||||
/* Server */
|
||||
void svr_session(int sock, runopts *opts, int childpipe,
|
||||
struct sockaddr *remoteaddr);
|
||||
|
||||
struct key_context {
|
||||
|
||||
const struct dropbear_cipher *recv_algo_crypt; /* NULL for none */
|
||||
const struct dropbear_cipher *trans_algo_crypt; /* NULL for none */
|
||||
const struct dropbear_hash *recv_algo_mac; /* NULL for none */
|
||||
const struct dropbear_hash *trans_algo_mac; /* NULL for none */
|
||||
char algo_kex;
|
||||
char algo_hostkey;
|
||||
|
||||
char recv_algo_comp; /* compression */
|
||||
char trans_algo_comp;
|
||||
#ifndef DISABLE_ZLIB
|
||||
z_streamp recv_zstream;
|
||||
z_streamp trans_zstream;
|
||||
#endif
|
||||
|
||||
/* actual keys */
|
||||
symmetric_CBC recv_symmetric_struct;
|
||||
symmetric_CBC trans_symmetric_struct;
|
||||
unsigned char recvmackey[MAX_MAC_KEY];
|
||||
unsigned char transmackey[MAX_MAC_KEY];
|
||||
|
||||
};
|
||||
|
||||
struct sshsession {
|
||||
|
||||
/* Is it a client or server? */
|
||||
unsigned char isserver;
|
||||
|
||||
runopts * opts; /* runtime options, incl hostkey, banner etc */
|
||||
|
||||
long connecttimeout; /* time to disconnect if we have a timeout (for
|
||||
userauth etc), or 0 for no timeout */
|
||||
|
||||
int sock;
|
||||
|
||||
struct sockaddr *remoteaddr;
|
||||
unsigned char *remotehost; /* the peer hostname */
|
||||
unsigned char *remoteident;
|
||||
|
||||
int maxfd; /* the maximum file descriptor to check with select() */
|
||||
|
||||
|
||||
/* Packet buffers/values etc */
|
||||
buffer *writepayload; /* Unencrypted payload to write - this is used
|
||||
throughout the code, as handlers fill out this
|
||||
buffer with the packet to send. */
|
||||
struct Queue writequeue; /* A queue of encrypted packets to send */
|
||||
buffer *readbuf; /* Encrypted */
|
||||
buffer *decryptreadbuf; /* Post-decryption */
|
||||
buffer *payload; /* Post-decompression, the actual SSH packet */
|
||||
unsigned int transseq, recvseq; /* Sequence IDs */
|
||||
|
||||
/* Packet-handling flags */
|
||||
unsigned dataallowed : 1; /* whether we can send data packets or we are in
|
||||
the middle of a KEX or something */
|
||||
|
||||
unsigned char expecting; /* byte indicating what packet we expect next,
|
||||
or 0x00 for any */
|
||||
|
||||
unsigned char ignorenext; /* whether to ignore the next packet,
|
||||
used for kex_follows stuff */
|
||||
|
||||
|
||||
|
||||
/* KEX/encryption related */
|
||||
struct KEXState kexstate;
|
||||
struct key_context *keys;
|
||||
struct key_context *newkeys;
|
||||
unsigned char *session_id; /* this is the hash from the first kex */
|
||||
/* The below are used temorarily during kex, are freed after use */
|
||||
mp_int * dh_K; /* SSH_MSG_KEXDH_REPLY and sending SSH_MSH_NEWKEYS */
|
||||
unsigned char hash[SHA1_HASH_SIZE]; /* the hash*/
|
||||
buffer* kexhashbuf; /* session hash buffer calculated from various packets*/
|
||||
buffer* transkexinit; /* the kexinit packet we send should be kept so we
|
||||
can add it to the hash when generating keys */
|
||||
|
||||
|
||||
|
||||
/* Channel related */
|
||||
struct Channel ** channels; /* these pointers may be null */
|
||||
unsigned int chansize; /* the number of Channel*s allocated for channels */
|
||||
struct ChanType **chantypes; /* The valid channel types */
|
||||
|
||||
|
||||
/* TCP forwarding - where manage listeners */
|
||||
#ifndef DISABLE_REMOTETCPFWD
|
||||
struct TCPListener ** tcplisteners;
|
||||
unsigned int tcplistensize;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
struct serversession {
|
||||
|
||||
/* Server specific options */
|
||||
int childpipe; /* kept open until we successfully authenticate */
|
||||
/* userauth */
|
||||
struct AuthState authstate;
|
||||
|
||||
struct ChildPid * childpids; /* array of mappings childpid<->channel */
|
||||
unsigned int childpidsize;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct clientsession {
|
||||
|
||||
int something; /* XXX */
|
||||
|
||||
};
|
||||
|
||||
/* Global structs storing the state */
|
||||
extern struct sshsession ses;
|
||||
|
||||
#ifdef DROPBEAR_SERVER
|
||||
extern struct serversession svr_ses;
|
||||
#endif /* DROPBEAR_SERVER */
|
||||
|
||||
#ifdef DROPBEAR_CLIENT
|
||||
extern struct serversession cli_ses;
|
||||
#endif /* DROPBEAR_CLIENT */
|
||||
|
||||
#endif /* _SESSION_H_ */
|
||||
376
signkey.c
Normal file
376
signkey.c
Normal file
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "signkey.h"
|
||||
#include "buffer.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/* malloc a new sign_key and set the dss and rsa keys to NULL */
|
||||
sign_key * new_sign_key() {
|
||||
|
||||
sign_key * ret;
|
||||
|
||||
ret = (sign_key*)m_malloc(sizeof(sign_key));
|
||||
#ifdef DROPBEAR_DSS
|
||||
ret->dsskey = NULL;
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
ret->rsakey = NULL;
|
||||
#endif
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
|
||||
* type is set to hold the type returned */
|
||||
int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
|
||||
|
||||
unsigned char* ident;
|
||||
unsigned int len;
|
||||
|
||||
ident = buf_getstring(buf, &len);
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (memcmp(ident, SSH_SIGNKEY_DSS, len) == 0
|
||||
&& (*type == DROPBEAR_SIGNKEY_ANY
|
||||
|| *type == DROPBEAR_SIGNKEY_DSS)) {
|
||||
m_free(ident);
|
||||
buf_setpos(buf, buf->pos - len - 4);
|
||||
dss_key_free(key->dsskey);
|
||||
key->dsskey = (dss_key*)m_malloc(sizeof(dss_key));
|
||||
*type = DROPBEAR_SIGNKEY_DSS;
|
||||
return buf_get_dss_pub_key(buf, key->dsskey);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (memcmp(ident, SSH_SIGNKEY_RSA, len) == 0
|
||||
&& (*type == DROPBEAR_SIGNKEY_ANY
|
||||
|| *type == DROPBEAR_SIGNKEY_RSA)) {
|
||||
m_free(ident);
|
||||
buf_setpos(buf, buf->pos - len - 4);
|
||||
rsa_key_free(key->rsakey);
|
||||
key->rsakey = (rsa_key*)m_malloc(sizeof(rsa_key));
|
||||
*type = DROPBEAR_SIGNKEY_RSA;
|
||||
return buf_get_rsa_pub_key(buf, key->rsakey);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_free(ident);
|
||||
|
||||
return DROPBEAR_FAILURE;
|
||||
|
||||
}
|
||||
|
||||
/* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
/* type is set to hold the type returned */
|
||||
int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
|
||||
|
||||
unsigned char* ident;
|
||||
unsigned int len;
|
||||
int ret;
|
||||
|
||||
TRACE(("enter buf_get_priv_key"));
|
||||
ident = buf_getstring(buf, &len);
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (memcmp(ident, SSH_SIGNKEY_DSS, len) == 0
|
||||
&& (*type == DROPBEAR_SIGNKEY_ANY
|
||||
|| *type == DROPBEAR_SIGNKEY_DSS)) {
|
||||
m_free(ident);
|
||||
buf_setpos(buf, buf->pos - len - 4);
|
||||
dss_key_free(key->dsskey);
|
||||
key->dsskey = (dss_key*)m_malloc(sizeof(dss_key));
|
||||
ret = buf_get_dss_priv_key(buf, key->dsskey);
|
||||
*type = DROPBEAR_SIGNKEY_DSS;
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_free(key->dsskey);
|
||||
}
|
||||
TRACE(("leave buf_get_priv_key: done get dss"));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (memcmp(ident, SSH_SIGNKEY_RSA, len) == 0
|
||||
&& (*type == DROPBEAR_SIGNKEY_ANY
|
||||
|| *type == DROPBEAR_SIGNKEY_RSA)) {
|
||||
m_free(ident);
|
||||
buf_setpos(buf, buf->pos - len - 4);
|
||||
rsa_key_free(key->rsakey);
|
||||
key->rsakey = (rsa_key*)m_malloc(sizeof(rsa_key));
|
||||
ret = buf_get_rsa_priv_key(buf, key->rsakey);
|
||||
*type = DROPBEAR_SIGNKEY_RSA;
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_free(key->rsakey);
|
||||
}
|
||||
TRACE(("leave buf_get_priv_key: done get rsa"));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_free(ident);
|
||||
|
||||
TRACE(("leave buf_get_priv_key"));
|
||||
return DROPBEAR_FAILURE;
|
||||
|
||||
}
|
||||
|
||||
/* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
|
||||
void buf_put_pub_key(buffer* buf, sign_key *key, int type) {
|
||||
|
||||
buffer *pubkeys;
|
||||
|
||||
TRACE(("enter buf_put_pub_key"));
|
||||
pubkeys = buf_new(1000);
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (type == DROPBEAR_SIGNKEY_DSS) {
|
||||
buf_put_dss_pub_key(pubkeys, key->dsskey);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (type == DROPBEAR_SIGNKEY_RSA) {
|
||||
buf_put_rsa_pub_key(pubkeys, key->rsakey);
|
||||
}
|
||||
#endif
|
||||
if (pubkeys->len == 0) {
|
||||
dropbear_exit("bad key types in buf_put_pub_key");
|
||||
}
|
||||
|
||||
buf_setpos(pubkeys, 0);
|
||||
buf_putstring(buf, buf_getptr(pubkeys, pubkeys->len),
|
||||
pubkeys->len);
|
||||
|
||||
buf_free(pubkeys);
|
||||
TRACE(("leave buf_put_pub_key"));
|
||||
}
|
||||
|
||||
/* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
|
||||
void buf_put_priv_key(buffer* buf, sign_key *key, int type) {
|
||||
|
||||
TRACE(("enter buf_put_priv_key"));
|
||||
TRACE(("type is %d", type));
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (type == DROPBEAR_SIGNKEY_DSS) {
|
||||
buf_put_dss_priv_key(buf, key->dsskey);
|
||||
TRACE(("leave buf_put_priv_key: dss done"));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (type == DROPBEAR_SIGNKEY_RSA) {
|
||||
buf_put_rsa_priv_key(buf, key->rsakey);
|
||||
TRACE(("leave buf_put_priv_key: rsa done"));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
dropbear_exit("bad key types in put pub key");
|
||||
}
|
||||
|
||||
void sign_key_free(sign_key *key) {
|
||||
|
||||
TRACE(("enter sign_key_free"));
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
dss_key_free(key->dsskey);
|
||||
key->dsskey = NULL;
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
rsa_key_free(key->rsakey);
|
||||
key->rsakey = NULL;
|
||||
#endif
|
||||
|
||||
m_free(key);
|
||||
TRACE(("leave sign_key_free"));
|
||||
}
|
||||
|
||||
static char hexdig(unsigned char x) {
|
||||
|
||||
if (x > 0xf)
|
||||
return 'X';
|
||||
|
||||
if (x < 10)
|
||||
return '0' + x;
|
||||
else
|
||||
return 'a' + x - 10;
|
||||
}
|
||||
|
||||
/* Since we're not sure if we'll have md5 or sha1, we present both.
|
||||
* MD5 is used in preference, but sha1 could still be useful */
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
static char * sign_key_md5_fingerprint(sign_key *key, int type) {
|
||||
|
||||
char * ret;
|
||||
hash_state hs;
|
||||
buffer *pubkeys;
|
||||
unsigned char hash[MD5_HASH_SIZE];
|
||||
unsigned int h, i;
|
||||
unsigned int buflen;
|
||||
|
||||
md5_init(&hs);
|
||||
|
||||
pubkeys = buf_new(1000);
|
||||
buf_put_pub_key(pubkeys, key, type);
|
||||
/* skip the size int of the string - this is a bit messy */
|
||||
buf_setpos(pubkeys, 4);
|
||||
md5_process(&hs, buf_getptr(pubkeys, pubkeys->len-pubkeys->pos),
|
||||
pubkeys->len-pubkeys->pos);
|
||||
|
||||
buf_free(pubkeys);
|
||||
md5_done(&hs, hash);
|
||||
|
||||
/* "md5 hexfingerprinthere\0", each hex digit is "AB:" etc */
|
||||
buflen = 4 + 3*MD5_HASH_SIZE;
|
||||
ret = (char*)m_malloc(buflen);
|
||||
|
||||
memset(ret, 'Z', buflen);
|
||||
strcpy(ret, "md5 ");
|
||||
|
||||
for (i = 4, h = 0; i < buflen; i+=3, h++) {
|
||||
ret[i] = hexdig(hash[h] >> 4);
|
||||
ret[i+1] = hexdig(hash[h] & 0x0f);
|
||||
ret[i+2] = ':';
|
||||
}
|
||||
ret[buflen-1] = 0x0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* use SHA1 rather than MD5 for fingerprint */
|
||||
static char * sign_key_sha1_fingerprint(sign_key *key, int type) {
|
||||
|
||||
char * ret;
|
||||
hash_state hs;
|
||||
buffer *pubkeys;
|
||||
unsigned char hash[SHA1_HASH_SIZE];
|
||||
unsigned int h, i;
|
||||
unsigned int buflen;
|
||||
|
||||
sha1_init(&hs);
|
||||
|
||||
pubkeys = buf_new(1000);
|
||||
buf_put_pub_key(pubkeys, key, type);
|
||||
buf_setpos(pubkeys, 4);
|
||||
/* skip the size int of the string - this is a bit messy */
|
||||
sha1_process(&hs, buf_getptr(pubkeys, pubkeys->len-pubkeys->pos),
|
||||
pubkeys->len-pubkeys->pos);
|
||||
|
||||
buf_free(pubkeys);
|
||||
sha1_done(&hs, hash);
|
||||
|
||||
/* "sha1 hexfingerprinthere\0", each hex digit is "AB:" etc */
|
||||
buflen = 5 + 3*SHA1_HASH_SIZE;
|
||||
ret = (char*)m_malloc(buflen);
|
||||
|
||||
strcpy(ret, "sha1 ");
|
||||
|
||||
for (i = 5, h = 0; i < buflen; i+=3, h++) {
|
||||
ret[i] = hexdig(hash[h] >> 4);
|
||||
ret[i+1] = hexdig(hash[h] & 0x0f);
|
||||
ret[i+2] = ':';
|
||||
}
|
||||
ret[buflen-1] = 0x0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* MD5/SHA1 switch */
|
||||
|
||||
/* This will return a freshly malloced string, containing a fingerprint
|
||||
* in either sha1 or md5 */
|
||||
char * sign_key_fingerprint(sign_key *key, int type) {
|
||||
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
return sign_key_md5_fingerprint(key, type);
|
||||
#else
|
||||
return sign_key_sha1_fingerprint(key, type);
|
||||
#endif
|
||||
}
|
||||
|
||||
void buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
const unsigned char *data, unsigned int len) {
|
||||
|
||||
buffer *sigblob;
|
||||
|
||||
sigblob = buf_new(1000);
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (type == DROPBEAR_SIGNKEY_DSS) {
|
||||
buf_put_dss_sign(sigblob, key->dsskey, data, len);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (type == DROPBEAR_SIGNKEY_RSA) {
|
||||
buf_put_rsa_sign(sigblob, key->rsakey, data, len);
|
||||
}
|
||||
#endif
|
||||
if (sigblob->len == 0) {
|
||||
dropbear_exit("non-matching signing type");
|
||||
}
|
||||
|
||||
buf_setpos(sigblob, 0);
|
||||
buf_putstring(buf, buf_getptr(sigblob, sigblob->len),
|
||||
sigblob->len);
|
||||
|
||||
buf_free(sigblob);
|
||||
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
/* Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE.
|
||||
* If FAILURE is returned, the position of
|
||||
* buf is undefined. If SUCCESS is returned, buf will be positioned after the
|
||||
* signature blob */
|
||||
int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
|
||||
unsigned int len) {
|
||||
|
||||
unsigned int bloblen;
|
||||
unsigned char * ident = NULL;
|
||||
unsigned int identlen = 0;
|
||||
|
||||
bloblen = buf_getint(buf);
|
||||
ident = buf_getstring(buf, &identlen);
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (bloblen == DSS_SIGNATURE_SIZE &&
|
||||
memcmp(ident, SSH_SIGNKEY_DSS, identlen) == 0) {
|
||||
m_free(ident);
|
||||
return buf_dss_verify(buf, key->dsskey, data, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (memcmp(ident, SSH_SIGNKEY_RSA, identlen) == 0) {
|
||||
m_free(ident);
|
||||
return buf_rsa_verify(buf, key->rsakey, data, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_free(ident);
|
||||
dropbear_exit("non-matching signing type");
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
58
signkey.h
Normal file
58
signkey.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef _SIGNKEY_H_
|
||||
#define _SIGNKEY_H_
|
||||
|
||||
#include "buffer.h"
|
||||
#include "dss.h"
|
||||
#include "rsa.h"
|
||||
|
||||
struct SIGN_key {
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
dss_key * dsskey;
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
rsa_key * rsakey;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct SIGN_key sign_key;
|
||||
|
||||
sign_key * new_sign_key();
|
||||
int buf_get_pub_key(buffer *buf, sign_key *key, int *type);
|
||||
int buf_get_priv_key(buffer* buf, sign_key *key, int *type);
|
||||
void buf_put_pub_key(buffer* buf, sign_key *key, int type);
|
||||
void buf_put_priv_key(buffer* buf, sign_key *key, int type);
|
||||
void sign_key_free(sign_key *key);
|
||||
void buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
const unsigned char *data, unsigned int len);
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
|
||||
unsigned int len);
|
||||
char * sign_key_fingerprint(sign_key *key, int type);
|
||||
#endif
|
||||
|
||||
#endif /* _SIGNKEY_H_ */
|
||||
93
ssh.h
Normal file
93
ssh.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
/* This file contains the various numbers in the protocol */
|
||||
|
||||
|
||||
/* message numbers */
|
||||
#define SSH_MSG_DISCONNECT 1
|
||||
#define SSH_MSG_IGNORE 2
|
||||
#define SSH_MSG_UNIMPLEMENTED 3
|
||||
#define SSH_MSG_DEBUG 4
|
||||
#define SSH_MSG_SERVICE_REQUEST 5
|
||||
#define SSH_MSG_SERVICE_ACCEPT 6
|
||||
#define SSH_MSG_KEXINIT 20
|
||||
#define SSH_MSG_NEWKEYS 21
|
||||
#define SSH_MSG_KEXDH_INIT 30
|
||||
#define SSH_MSG_KEXDH_REPLY 31
|
||||
|
||||
/* userauth message numbers */
|
||||
#define SSH_MSG_USERAUTH_REQUEST 50
|
||||
#define SSH_MSG_USERAUTH_FAILURE 51
|
||||
#define SSH_MSG_USERAUTH_SUCCESS 52
|
||||
#define SSH_MSG_USERAUTH_BANNER 53
|
||||
#define SSH_MSG_USERAUTH_PK_OK 60
|
||||
|
||||
/* connect message numbers */
|
||||
#define SSH_MSG_GLOBAL_REQUEST 80
|
||||
#define SSH_MSG_REQUEST_SUCCESS 81
|
||||
#define SSH_MSG_REQUEST_FAILURE 82
|
||||
#define SSH_MSG_CHANNEL_OPEN 90
|
||||
#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 91
|
||||
#define SSH_MSG_CHANNEL_OPEN_FAILURE 92
|
||||
#define SSH_MSG_CHANNEL_WINDOW_ADJUST 93
|
||||
#define SSH_MSG_CHANNEL_DATA 94
|
||||
#define SSH_MSG_CHANNEL_EXTENDED_DATA 95
|
||||
#define SSH_MSG_CHANNEL_EOF 96
|
||||
#define SSH_MSG_CHANNEL_CLOSE 97
|
||||
#define SSH_MSG_CHANNEL_REQUEST 98
|
||||
#define SSH_MSG_CHANNEL_SUCCESS 99
|
||||
#define SSH_MSG_CHANNEL_FAILURE 100
|
||||
|
||||
/* extended data types */
|
||||
#define SSH_EXTENDED_DATA_STDERR 1
|
||||
|
||||
/* disconnect codes */
|
||||
#define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1
|
||||
#define SSH_DISCONNECT_PROTOCOL_ERROR 2
|
||||
#define SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3
|
||||
#define SSH_DISCONNECT_RESERVED 4
|
||||
#define SSH_DISCONNECT_MAC_ERROR 5
|
||||
#define SSH_DISCONNECT_COMPRESSION_ERROR 6
|
||||
#define SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7
|
||||
#define SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8
|
||||
#define SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9
|
||||
#define SSH_DISCONNECT_CONNECTION_LOST 10
|
||||
#define SSH_DISCONNECT_BY_APPLICATION 11
|
||||
#define SSH_DISCONNECT_TOO_MANY_CONNECTIONS 12
|
||||
#define SSH_DISCONNECT_AUTH_CANCELLED_BY_USER 13
|
||||
#define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14
|
||||
#define SSH_DISCONNECT_ILLEGAL_USER_NAME 15
|
||||
|
||||
/* service types */
|
||||
#define SSH_SERVICE_USERAUTH "ssh-userauth"
|
||||
#define SSH_SERVICE_USERAUTH_LEN 12
|
||||
#define SSH_SERVICE_CONNECTION "ssh-connection"
|
||||
#define SSH_SERVICE_CONNECTION_LEN 14
|
||||
|
||||
/* public key types */
|
||||
#define SSH_SIGNKEY_DSS "ssh-dss"
|
||||
#define SSH_SIGNKEY_DSS_LEN 7
|
||||
#define SSH_SIGNKEY_RSA "ssh-rsa"
|
||||
#define SSH_SIGNKEY_RSA_LEN 7
|
||||
412
sshpty.c
Normal file
412
sshpty.c
Normal file
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copied from OpenSSH-3.5p1 source, modified by Matt Johnston 2003
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Allocating a pseudo-terminal, and making it the controlling tty.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
/*RCSID("$OpenBSD: sshpty.c,v 1.7 2002/06/24 17:57:20 deraadt Exp $");*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "errno.h"
|
||||
#include "sshpty.h"
|
||||
|
||||
/* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
|
||||
#if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
|
||||
#undef HAVE_DEV_PTMX
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PTY_H
|
||||
# include <pty.h>
|
||||
#endif
|
||||
#if defined(USE_DEV_PTMX) && defined(HAVE_STROPTS_H)
|
||||
# include <stropts.h>
|
||||
#endif
|
||||
|
||||
#ifndef O_NOCTTY
|
||||
#define O_NOCTTY 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocates and opens a pty. Returns 0 if no pty could be allocated, or
|
||||
* nonzero if a pty was successfully allocated. On success, open file
|
||||
* descriptors for the pty and tty sides and the name of the tty side are
|
||||
* returned (the buffer must be able to hold at least 64 characters).
|
||||
*/
|
||||
|
||||
int
|
||||
pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
|
||||
{
|
||||
#if defined(HAVE_OPENPTY)
|
||||
/* exists in recent (4.4) BSDs and OSF/1 */
|
||||
char *name;
|
||||
int i;
|
||||
|
||||
i = openpty(ptyfd, ttyfd, NULL, NULL, NULL);
|
||||
if (i < 0) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"pty_allocate: openpty: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
name = ttyname(*ttyfd);
|
||||
if (!name) {
|
||||
dropbear_exit("ttyname fails for openpty device");
|
||||
}
|
||||
|
||||
strlcpy(namebuf, name, namebuflen); /* possible truncation */
|
||||
return 1;
|
||||
#else /* HAVE_OPENPTY */
|
||||
#ifdef HAVE__GETPTY
|
||||
/*
|
||||
* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
|
||||
* pty's automagically when needed
|
||||
*/
|
||||
char *slave;
|
||||
|
||||
slave = _getpty(ptyfd, O_RDWR, 0622, 0);
|
||||
if (slave == NULL) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"pty_allocate: _getpty: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
strlcpy(namebuf, slave, namebuflen);
|
||||
/* Open the slave side. */
|
||||
*ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
|
||||
if (*ttyfd < 0) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"pty_allocate error: ttyftd open error");
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
#else /* HAVE__GETPTY */
|
||||
#if defined(USE_DEV_PTMX)
|
||||
/*
|
||||
* This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
|
||||
* also has bsd-style ptys, but they simply do not work.)
|
||||
*
|
||||
* Linux systems may have the /dev/ptmx device, but this code won't work.
|
||||
*/
|
||||
int ptm;
|
||||
char *pts;
|
||||
|
||||
ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
|
||||
if (ptm < 0) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"pty_allocate: /dev/ptmx: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if (grantpt(ptm) < 0) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"grantpt: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if (unlockpt(ptm) < 0) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"unlockpt: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
pts = ptsname(ptm);
|
||||
if (pts == NULL) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"Slave pty side name could not be obtained.");
|
||||
}
|
||||
strlcpy(namebuf, pts, namebuflen);
|
||||
*ptyfd = ptm;
|
||||
|
||||
/* Open the slave side. */
|
||||
*ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
|
||||
if (*ttyfd < 0) {
|
||||
dropbear_log(LOG_ERR,
|
||||
"error opening pts %.100s: %.100s", namebuf, strerror(errno));
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
#ifndef HAVE_CYGWIN
|
||||
/*
|
||||
* Push the appropriate streams modules, as described in Solaris pts(7).
|
||||
* HP-UX pts(7) doesn't have ttcompat module.
|
||||
*/
|
||||
if (ioctl(*ttyfd, I_PUSH, "ptem") < 0) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"ioctl I_PUSH ptem: %.100s", strerror(errno));
|
||||
}
|
||||
if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"ioctl I_PUSH ldterm: %.100s", strerror(errno));
|
||||
}
|
||||
#ifndef __hpux
|
||||
if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"ioctl I_PUSH ttcompat: %.100s", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return 1;
|
||||
#else /* USE_DEV_PTMX */
|
||||
#ifdef HAVE_DEV_PTS_AND_PTC
|
||||
/* AIX-style pty code. */
|
||||
const char *name;
|
||||
|
||||
*ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
|
||||
if (*ptyfd < 0) {
|
||||
dropbear_log(LOG_ERR,
|
||||
"Could not open /dev/ptc: %.100s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
name = ttyname(*ptyfd);
|
||||
if (!name) {
|
||||
dropbear_exit("ttyname fails for /dev/ptc device");
|
||||
}
|
||||
strlcpy(namebuf, name, namebuflen);
|
||||
*ttyfd = open(name, O_RDWR | O_NOCTTY);
|
||||
if (*ttyfd < 0) {
|
||||
dropbear_log(LOG_ERR,
|
||||
"Could not open pty slave side %.100s: %.100s",
|
||||
name, strerror(errno));
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
#else /* HAVE_DEV_PTS_AND_PTC */
|
||||
|
||||
/* BSD-style pty code. */
|
||||
char buf[64];
|
||||
int i;
|
||||
const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
const char *ptyminors = "0123456789abcdef";
|
||||
int num_minors = strlen(ptyminors);
|
||||
int num_ptys = strlen(ptymajors) * num_minors;
|
||||
struct termios tio;
|
||||
|
||||
for (i = 0; i < num_ptys; i++) {
|
||||
snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors],
|
||||
ptyminors[i % num_minors]);
|
||||
snprintf(namebuf, namebuflen, "/dev/tty%c%c",
|
||||
ptymajors[i / num_minors], ptyminors[i % num_minors]);
|
||||
|
||||
*ptyfd = open(buf, O_RDWR | O_NOCTTY);
|
||||
if (*ptyfd < 0) {
|
||||
/* Try SCO style naming */
|
||||
snprintf(buf, sizeof buf, "/dev/ptyp%d", i);
|
||||
snprintf(namebuf, namebuflen, "/dev/ttyp%d", i);
|
||||
*ptyfd = open(buf, O_RDWR | O_NOCTTY);
|
||||
if (*ptyfd < 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Open the slave side. */
|
||||
*ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
|
||||
if (*ttyfd < 0) {
|
||||
dropbear_log(LOG_ERR,
|
||||
"pty_allocate: %.100s: %.100s", namebuf, strerror(errno));
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
/* set tty modes to a sane state for broken clients */
|
||||
if (tcgetattr(*ptyfd, &tio) < 0) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"ptyallocate: tty modes failed: %.100s", strerror(errno));
|
||||
} else {
|
||||
tio.c_lflag |= (ECHO | ISIG | ICANON);
|
||||
tio.c_oflag |= (OPOST | ONLCR);
|
||||
tio.c_iflag |= ICRNL;
|
||||
|
||||
/* Set the new modes for the terminal. */
|
||||
if (tcsetattr(*ptyfd, TCSANOW, &tio) < 0) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"Setting tty modes for pty failed: %.100s",
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
dropbear_log(LOG_WARNING, "failed to open any /dev/pty?? devices");
|
||||
return 0;
|
||||
#endif /* HAVE_DEV_PTS_AND_PTC */
|
||||
#endif /* USE_DEV_PTMX */
|
||||
#endif /* HAVE__GETPTY */
|
||||
#endif /* HAVE_OPENPTY */
|
||||
}
|
||||
|
||||
/* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
|
||||
|
||||
void
|
||||
pty_release(const char *tty_name)
|
||||
{
|
||||
if (chown(tty_name, (uid_t) 0, (gid_t) 0) < 0
|
||||
&& (errno != ENOENT)) {
|
||||
dropbear_log(LOG_ERR,
|
||||
"chown %.100s 0 0 failed: %.100s", tty_name, strerror(errno));
|
||||
}
|
||||
if (chmod(tty_name, (mode_t) 0666) < 0
|
||||
&& (errno != ENOENT)) {
|
||||
dropbear_log(LOG_ERR,
|
||||
"chmod %.100s 0666 failed: %.100s", tty_name, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
/* Makes the tty the processes controlling tty and sets it to sane modes. */
|
||||
|
||||
void
|
||||
pty_make_controlling_tty(int *ttyfd, const char *tty_name)
|
||||
{
|
||||
int fd;
|
||||
#ifdef USE_VHANGUP
|
||||
void *old;
|
||||
#endif /* USE_VHANGUP */
|
||||
|
||||
/* Solaris has a problem with TIOCNOTTY for a bg process, so
|
||||
* we disable the signal which would STOP the process - matt */
|
||||
signal(SIGTTOU, SIG_IGN);
|
||||
|
||||
/* First disconnect from the old controlling tty. */
|
||||
#ifdef TIOCNOTTY
|
||||
fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
|
||||
if (fd >= 0) {
|
||||
(void) ioctl(fd, TIOCNOTTY, NULL);
|
||||
close(fd);
|
||||
}
|
||||
#endif /* TIOCNOTTY */
|
||||
if (setsid() < 0) {
|
||||
dropbear_log(LOG_ERR,
|
||||
"setsid: %.100s", strerror(errno));
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that we are successfully disconnected from the controlling
|
||||
* tty.
|
||||
*/
|
||||
fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
|
||||
if (fd >= 0) {
|
||||
dropbear_log(LOG_ERR,
|
||||
"Failed to disconnect from controlling tty.\n");
|
||||
close(fd);
|
||||
}
|
||||
/* Make it our controlling tty. */
|
||||
#ifdef TIOCSCTTY
|
||||
if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0) {
|
||||
dropbear_log(LOG_ERR,
|
||||
"ioctl(TIOCSCTTY): %.100s", strerror(errno));
|
||||
}
|
||||
#endif /* TIOCSCTTY */
|
||||
#ifdef HAVE_NEWS4
|
||||
if (setpgrp(0,0) < 0) {
|
||||
dropbear_log(LOG_ERR,
|
||||
error("SETPGRP %s",strerror(errno)));
|
||||
}
|
||||
#endif /* HAVE_NEWS4 */
|
||||
#ifdef USE_VHANGUP
|
||||
old = mysignal(SIGHUP, SIG_IGN);
|
||||
vhangup();
|
||||
mysignal(SIGHUP, old);
|
||||
#endif /* USE_VHANGUP */
|
||||
fd = open(tty_name, O_RDWR);
|
||||
if (fd < 0) {
|
||||
dropbear_log(LOG_ERR,
|
||||
"%.100s: %.100s", tty_name, strerror(errno));
|
||||
} else {
|
||||
#ifdef USE_VHANGUP
|
||||
close(*ttyfd);
|
||||
*ttyfd = fd;
|
||||
#else /* USE_VHANGUP */
|
||||
close(fd);
|
||||
#endif /* USE_VHANGUP */
|
||||
}
|
||||
/* Verify that we now have a controlling tty. */
|
||||
fd = open(_PATH_TTY, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
dropbear_log(LOG_ERR,
|
||||
"open /dev/tty failed - could not set controlling tty: %.100s",
|
||||
strerror(errno));
|
||||
} else {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
/* Changes the window size associated with the pty. */
|
||||
|
||||
void
|
||||
pty_change_window_size(int ptyfd, int row, int col,
|
||||
int xpixel, int ypixel)
|
||||
{
|
||||
struct winsize w;
|
||||
|
||||
w.ws_row = row;
|
||||
w.ws_col = col;
|
||||
w.ws_xpixel = xpixel;
|
||||
w.ws_ypixel = ypixel;
|
||||
(void) ioctl(ptyfd, TIOCSWINSZ, &w);
|
||||
}
|
||||
|
||||
void
|
||||
pty_setowner(struct passwd *pw, const char *tty_name)
|
||||
{
|
||||
struct group *grp;
|
||||
gid_t gid;
|
||||
mode_t mode;
|
||||
struct stat st;
|
||||
|
||||
/* Determine the group to make the owner of the tty. */
|
||||
grp = getgrnam("tty");
|
||||
if (grp) {
|
||||
gid = grp->gr_gid;
|
||||
mode = S_IRUSR | S_IWUSR | S_IWGRP;
|
||||
} else {
|
||||
gid = pw->pw_gid;
|
||||
mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change owner and mode of the tty as required.
|
||||
* Warn but continue if filesystem is read-only and the uids match/
|
||||
* tty is owned by root.
|
||||
*/
|
||||
if (stat(tty_name, &st)) {
|
||||
dropbear_exit("pty_setowner: stat(%.101s) failed: %.100s",
|
||||
tty_name, strerror(errno));
|
||||
}
|
||||
|
||||
if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
|
||||
if (chown(tty_name, pw->pw_uid, gid) < 0) {
|
||||
if (errno == EROFS &&
|
||||
(st.st_uid == pw->pw_uid || st.st_uid == 0)) {
|
||||
dropbear_log(LOG_ERR,
|
||||
"chown(%.100s, %u, %u) failed: %.100s",
|
||||
tty_name, (unsigned int)pw->pw_uid, (unsigned int)gid,
|
||||
strerror(errno));
|
||||
} else {
|
||||
dropbear_exit("chown(%.100s, %u, %u) failed: %.100s",
|
||||
tty_name, (unsigned int)pw->pw_uid, (unsigned int)gid,
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) {
|
||||
if (chmod(tty_name, mode) < 0) {
|
||||
if (errno == EROFS &&
|
||||
(st.st_mode & (S_IRGRP | S_IROTH)) == 0) {
|
||||
dropbear_log(LOG_ERR,
|
||||
"chmod(%.100s, 0%o) failed: %.100s",
|
||||
tty_name, mode, strerror(errno));
|
||||
} else {
|
||||
dropbear_exit("chmod(%.100s, 0%o) failed: %.100s",
|
||||
tty_name, mode, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
28
sshpty.h
Normal file
28
sshpty.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/* $OpenBSD: sshpty.h,v 1.4 2002/03/04 17:27:39 stevesk Exp $ */
|
||||
|
||||
/*
|
||||
* Copied from openssh-3.5p1 source by Matt Johnston 2003
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Functions for allocating a pseudo-terminal and making it the controlling
|
||||
* tty.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
#ifndef SSHPTY_H
|
||||
#define SSHPTY_H
|
||||
|
||||
int pty_allocate(int *, int *, char *, int);
|
||||
void pty_release(const char *);
|
||||
void pty_make_controlling_tty(int *, const char *);
|
||||
void pty_change_window_size(int, int, int, int, int);
|
||||
void pty_setowner(struct passwd *, const char *);
|
||||
|
||||
#endif /* SSHPTY_H */
|
||||
247
svr-agentfwd.c
Normal file
247
svr-agentfwd.c
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
/* This file (agentfwd.c) handles authentication agent forwarding, for OpenSSH
|
||||
* style agents. */
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
|
||||
#include "agentfwd.h"
|
||||
#include "session.h"
|
||||
#include "ssh.h"
|
||||
#include "dbutil.h"
|
||||
#include "chansession.h"
|
||||
#include "channel.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "random.h"
|
||||
|
||||
#define AGENTDIRPREFIX "/tmp/dropbear-"
|
||||
|
||||
static int send_msg_channel_open_agent(int fd);
|
||||
static int bindagent(struct ChanSess * chansess);
|
||||
|
||||
/* Handles client requests to start agent forwarding, sets up listening socket.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int agentreq(struct ChanSess * chansess) {
|
||||
|
||||
if (chansess->agentfd != -1) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* create listening socket */
|
||||
chansess->agentfd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (chansess->agentfd < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* create the unix socket dir and file */
|
||||
if (bindagent(chansess) == DROPBEAR_FAILURE) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* listen */
|
||||
if (listen(chansess->agentfd, 20) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* set non-blocking */
|
||||
if (fcntl(chansess->agentfd, F_SETFL, O_NONBLOCK) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* channel.c's channel fd code will handle the socket now */
|
||||
|
||||
/* set the maxfd so that select() loop will notice it */
|
||||
ses.maxfd = MAX(ses.maxfd, chansess->agentfd);
|
||||
|
||||
return DROPBEAR_SUCCESS;
|
||||
|
||||
fail:
|
||||
/* cleanup */
|
||||
agentcleanup(chansess);
|
||||
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* accepts a connection on the forwarded socket and opens a new channel for it
|
||||
* back to the client */
|
||||
/* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int agentaccept(struct ChanSess * chansess) {
|
||||
|
||||
int fd;
|
||||
|
||||
fd = accept(chansess->agentfd, NULL, NULL);
|
||||
if (fd < 0) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
return send_msg_channel_open_agent(fd);
|
||||
|
||||
}
|
||||
|
||||
/* set up the environment variable pointing to the socket. This is called
|
||||
* just before command/shell execution, after dropping priveleges */
|
||||
void agentset(struct ChanSess * chansess) {
|
||||
|
||||
char *path = NULL;
|
||||
int len;
|
||||
|
||||
if (chansess->agentfd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* 2 for "/" and "\0" */
|
||||
len = strlen(chansess->agentdir) + strlen(chansess->agentfile) + 2;
|
||||
|
||||
path = m_malloc(len);
|
||||
snprintf(path, len, "%s/%s", chansess->agentdir, chansess->agentfile);
|
||||
addnewvar("SSH_AUTH_SOCK", path);
|
||||
m_free(path);
|
||||
}
|
||||
|
||||
/* close the socket, remove the socket-file */
|
||||
void agentcleanup(struct ChanSess * chansess) {
|
||||
|
||||
char *path = NULL;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
int len;
|
||||
|
||||
if (chansess->agentfd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
close(chansess->agentfd);
|
||||
|
||||
/* Remove the dir as the user. That way they can't cause problems except
|
||||
* for themselves */
|
||||
uid = getuid();
|
||||
gid = getgid();
|
||||
if ((setegid(ses.authstate.pw->pw_gid)) < 0 ||
|
||||
(seteuid(ses.authstate.pw->pw_uid)) < 0) {
|
||||
dropbear_exit("failed to set euid");
|
||||
}
|
||||
|
||||
/* 2 for "/" and "\0" */
|
||||
len = strlen(chansess->agentdir) + strlen(chansess->agentfile) + 2;
|
||||
|
||||
path = m_malloc(len);
|
||||
snprintf(path, len, "%s/%s", chansess->agentdir, chansess->agentfile);
|
||||
unlink(path);
|
||||
m_free(path);
|
||||
|
||||
rmdir(chansess->agentdir);
|
||||
|
||||
if ((seteuid(uid)) < 0 ||
|
||||
(setegid(gid)) < 0) {
|
||||
dropbear_exit("failed to revert euid");
|
||||
}
|
||||
|
||||
m_free(chansess->agentfile);
|
||||
m_free(chansess->agentdir);
|
||||
|
||||
}
|
||||
|
||||
/* helper for accepting an agent request */
|
||||
static int send_msg_channel_open_agent(int fd) {
|
||||
|
||||
if (send_msg_channel_open_init(fd, CHANNEL_ID_AGENT,
|
||||
"auth-agent@openssh.com") == DROPBEAR_SUCCESS) {
|
||||
encrypt_packet();
|
||||
return DROPBEAR_SUCCESS;
|
||||
} else {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/* helper for creating the agent socket-file
|
||||
returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int bindagent(struct ChanSess * chansess) {
|
||||
|
||||
struct sockaddr_un addr;
|
||||
unsigned int prefix;
|
||||
char path[sizeof(addr.sun_path)], sockfile[sizeof(addr.sun_path)];
|
||||
mode_t mode;
|
||||
int i;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
/* drop to user privs to make the dir/file */
|
||||
uid = getuid();
|
||||
gid = getgid();
|
||||
if ((setegid(ses.authstate.pw->pw_gid)) < 0 ||
|
||||
(seteuid(ses.authstate.pw->pw_uid)) < 0) {
|
||||
dropbear_exit("failed to set euid");
|
||||
}
|
||||
|
||||
memset((void*)&addr, 0x0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
|
||||
mode = S_IRWXU;
|
||||
|
||||
for (i = 0; i < 20; i++) {
|
||||
genrandom((unsigned char*)&prefix, sizeof(prefix));
|
||||
/* we want 32 bits (8 hex digits) - "/tmp/dropbear-f19c62c0" */
|
||||
snprintf(path, sizeof(path), AGENTDIRPREFIX "%.8x", prefix);
|
||||
|
||||
if (mkdir(path, mode) == 0) {
|
||||
goto bindsocket;
|
||||
}
|
||||
if (errno != EEXIST) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* couldn't make a dir */
|
||||
goto out;
|
||||
|
||||
bindsocket:
|
||||
/* Format is "/tmp/dropbear-0246dead/auth-d00f7654-23".
|
||||
* The "23" is the file desc, the random data is to avoid collisions
|
||||
* between subsequent user processes reusing socket fds (odds are now
|
||||
* 1/(2^64) */
|
||||
genrandom((unsigned char*)&prefix, sizeof(prefix));
|
||||
snprintf(sockfile, sizeof(sockfile), "auth-%.8x-%d", prefix,
|
||||
chansess->agentfd);
|
||||
snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", path, sockfile);
|
||||
|
||||
if (bind(chansess->agentfd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
|
||||
chansess->agentdir = strdup(path);
|
||||
chansess->agentfile = strdup(sockfile);
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
out:
|
||||
if ((seteuid(uid)) < 0 ||
|
||||
(setegid(gid)) < 0) {
|
||||
dropbear_exit("failed to revert euid");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
74
svr-algo.c
Normal file
74
svr-algo.c
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "algo.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
/* match the first algorithm in the comma-separated list in buf which is
|
||||
* also in localalgos[], or return NULL on failure.
|
||||
* (*goodguess) is set to 1 if the preferred client/server algos match,
|
||||
* 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
|
||||
* guessed correctly */
|
||||
algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
int *goodguess)
|
||||
{
|
||||
|
||||
unsigned char * algolist = NULL;
|
||||
unsigned char * remotealgos[MAX_PROPOSED_ALGO];
|
||||
unsigned int len;
|
||||
unsigned int count, i, j;
|
||||
algo_type * ret = NULL;
|
||||
|
||||
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
|
||||
algolist = buf_getstring(buf, &len);
|
||||
/* Debug this */
|
||||
TRACE(("buf_match_algo: %s", algolist));
|
||||
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
goto out; /* just a sanity check, no other use */
|
||||
}
|
||||
|
||||
/* remotealgos will contain a list of the strings parsed out */
|
||||
/* We will have at least one string (even if it's just "") */
|
||||
remotealgos[0] = algolist;
|
||||
count = 1;
|
||||
/* Iterate through, replacing ','s with NULs, to split it into
|
||||
* words. */
|
||||
for (i = 0; i < len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
goto out;
|
||||
}
|
||||
if (algolist[i] == ',') {
|
||||
algolist[i] = '\0';
|
||||
remotealgos[count] = &algolist[i+1];
|
||||
count++;
|
||||
}
|
||||
if (count == MAX_PROPOSED_ALGO) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* iterate and find the first match */
|
||||
for (i = 0; i < count; i++) {
|
||||
|
||||
len = strlen(remotealgos[i]);
|
||||
|
||||
for (j = 0; localalgos[j].name != NULL; j++) {
|
||||
if (localalgos[j].usable) {
|
||||
if (len == strlen(localalgos[j].name) &&
|
||||
strncmp(localalgos[j].name, remotealgos[i], len) == 0) {
|
||||
/* set if it was a good guess */
|
||||
if (i == 0 && j == 0) {
|
||||
*goodguess = 1;
|
||||
} else {
|
||||
*goodguess = 0;
|
||||
}
|
||||
/* set the algo to return */
|
||||
ret = &localalgos[j];
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
m_free(algolist);
|
||||
return ret;
|
||||
}
|
||||
351
svr-auth.c
Normal file
351
svr-auth.c
Normal file
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
/* This file (auth.c) handles authentication requests, passing it to the
|
||||
* particular type (auth-passwd, auth-pubkey). */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "session.h"
|
||||
#include "buffer.h"
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "auth.h"
|
||||
#include "authpasswd.h"
|
||||
#include "authpubkey.h"
|
||||
|
||||
static void authclear();
|
||||
static int checkusername(unsigned char *username, unsigned int userlen);
|
||||
static void send_msg_userauth_banner();
|
||||
|
||||
/* initialise the first time for a session, resetting all parameters */
|
||||
void authinitialise() {
|
||||
|
||||
svr_ses.authstate.failcount = 0;
|
||||
authclear();
|
||||
|
||||
}
|
||||
|
||||
/* Reset the auth state, but don't reset the failcount. This is for if the
|
||||
* user decides to try with a different username etc, and is also invoked
|
||||
* on initialisation */
|
||||
static void authclear() {
|
||||
|
||||
svr_ses.authstate.authdone = 0;
|
||||
svr_ses.authstate.pw = NULL;
|
||||
svr_ses.authstate.username = NULL;
|
||||
svr_ses.authstate.printableuser = NULL;
|
||||
svr_ses.authstate.authtypes = 0;
|
||||
#ifdef DROPBEAR_PUBKEY_AUTH
|
||||
svr_ses.authstate.authtypes |= AUTH_TYPE_PUBKEY;
|
||||
#endif
|
||||
#ifdef DROPBEAR_PASSWORD_AUTH
|
||||
if (!ses.opts->noauthpass) {
|
||||
svr_ses.authstate.authtypes |= AUTH_TYPE_PASSWORD;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* Send a banner message if specified to the client. The client might
|
||||
* ignore this, but possibly serves as a legal "no trespassing" sign */
|
||||
static void send_msg_userauth_banner() {
|
||||
|
||||
TRACE(("enter send_msg_userauth_banner"));
|
||||
if (ses.opts->banner == NULL) {
|
||||
TRACE(("leave send_msg_userauth_banner: banner is NULL"));
|
||||
return;
|
||||
}
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_BANNER);
|
||||
buf_putstring(ses.writepayload, buf_getptr(ses.opts->banner,
|
||||
ses.opts->banner->len), ses.opts->banner->len);
|
||||
buf_putstring(ses.writepayload, "en", 2);
|
||||
|
||||
encrypt_packet();
|
||||
buf_free(ses.opts->banner);
|
||||
ses.opts->banner = NULL;
|
||||
|
||||
TRACE(("leave send_msg_userauth_banner"));
|
||||
}
|
||||
|
||||
/* handle a userauth request, check validity, pass to password or pubkey
|
||||
* checking, and handle success or failure */
|
||||
void recv_msg_userauth_request() {
|
||||
|
||||
unsigned char *username, *servicename, *methodname;
|
||||
unsigned int userlen, servicelen, methodlen;
|
||||
|
||||
TRACE(("enter recv_msg_userauth_request"));
|
||||
|
||||
/* ignore packets if auth is already done */
|
||||
if (svr_ses.authstate.authdone == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* send the banner if it exists, it will only exist once */
|
||||
if (ses.opts->banner) {
|
||||
send_msg_userauth_banner();
|
||||
}
|
||||
|
||||
|
||||
username = buf_getstring(ses.payload, &userlen);
|
||||
servicename = buf_getstring(ses.payload, &servicelen);
|
||||
methodname = buf_getstring(ses.payload, &methodlen);
|
||||
|
||||
/* only handle 'ssh-connection' currently */
|
||||
if (servicelen != SSH_SERVICE_CONNECTION_LEN
|
||||
&& (strncmp(servicename, SSH_SERVICE_CONNECTION,
|
||||
SSH_SERVICE_CONNECTION_LEN) != 0)) {
|
||||
|
||||
/* TODO - disconnect here */
|
||||
m_free(username);
|
||||
m_free(servicename);
|
||||
m_free(methodname);
|
||||
dropbear_exit("unknown service in auth");
|
||||
}
|
||||
|
||||
/* user wants to know what methods are supported */
|
||||
if (methodlen == AUTH_METHOD_NONE_LEN &&
|
||||
strncmp(methodname, AUTH_METHOD_NONE,
|
||||
AUTH_METHOD_NONE_LEN) == 0) {
|
||||
send_msg_userauth_failure(0, 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* check username is good before continuing */
|
||||
if (checkusername(username, userlen) == DROPBEAR_FAILURE) {
|
||||
/* username is invalid/no shell/etc - send failure */
|
||||
TRACE(("sending checkusername failure"));
|
||||
send_msg_userauth_failure(0, 1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_PASSWORD_AUTH
|
||||
if (!ses.opts->noauthpass &&
|
||||
!(ses.opts->norootpass && svr_ses.authstate.pw->pw_uid == 0) ) {
|
||||
/* user wants to try password auth */
|
||||
if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
|
||||
strncmp(methodname, AUTH_METHOD_PASSWORD,
|
||||
AUTH_METHOD_PASSWORD_LEN) == 0) {
|
||||
passwordauth(username, userlen);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_PUBKEY_AUTH
|
||||
/* user wants to try pubkey auth */
|
||||
if (methodlen == AUTH_METHOD_PUBKEY_LEN &&
|
||||
strncmp(methodname, AUTH_METHOD_PUBKEY,
|
||||
AUTH_METHOD_PUBKEY_LEN) == 0) {
|
||||
pubkeyauth(username, userlen);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* nothing matched, we just fail */
|
||||
send_msg_userauth_failure(0, 1);
|
||||
|
||||
out:
|
||||
|
||||
m_free(username);
|
||||
m_free(servicename);
|
||||
m_free(methodname);
|
||||
}
|
||||
|
||||
/* Check that the username exists, has a non-empty password, and has a valid
|
||||
* shell.
|
||||
* returns DROPBEAR_SUCCESS on valid username, DROPBEAR_FAILURE on failure */
|
||||
static int checkusername(unsigned char *username, unsigned int userlen) {
|
||||
|
||||
char* listshell = NULL;
|
||||
char* usershell = NULL;
|
||||
|
||||
TRACE(("enter checkusername"));
|
||||
if (userlen > MAX_USERNAME_LEN) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* new user or username has changed */
|
||||
if (svr_ses.authstate.username == NULL ||
|
||||
strcmp(username, svr_ses.authstate.username) != 0) {
|
||||
/* the username needs resetting */
|
||||
if (svr_ses.authstate.username != NULL) {
|
||||
dropbear_log(LOG_WARNING, "client trying multiple usernames");
|
||||
m_free(svr_ses.authstate.username);
|
||||
}
|
||||
authclear();
|
||||
svr_ses.authstate.pw = getpwnam((char*)username);
|
||||
svr_ses.authstate.username = strdup(username);
|
||||
m_free(svr_ses.authstate.printableuser);
|
||||
}
|
||||
|
||||
/* check that user exists */
|
||||
if (svr_ses.authstate.pw == NULL) {
|
||||
TRACE(("leave checkusername: user '%s' doesn't exist", username));
|
||||
dropbear_log(LOG_WARNING,
|
||||
"login attempt for nonexistent user");
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* We can set it once we know its a real user */
|
||||
svr_ses.authstate.printableuser = strdup(svr_ses.authstate.pw->pw_name);
|
||||
|
||||
/* check for non-root if desired */
|
||||
if (ses.opts->norootlogin && svr_ses.authstate.pw->pw_uid == 0) {
|
||||
TRACE(("leave checkusername: root login disabled"));
|
||||
dropbear_log(LOG_WARNING, "root login rejected");
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* check for an empty password */
|
||||
if (svr_ses.authstate.pw->pw_passwd[0] == '\0') {
|
||||
TRACE(("leave checkusername: empty pword"));
|
||||
dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected",
|
||||
svr_ses.authstate.printableuser);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
TRACE(("shell is %s", svr_ses.authstate.pw->pw_shell));
|
||||
|
||||
/* check that the shell is set */
|
||||
usershell = svr_ses.authstate.pw->pw_shell;
|
||||
if (usershell[0] == '\0') {
|
||||
/* empty shell in /etc/passwd means /bin/sh according to passwd(5) */
|
||||
usershell = "/bin/sh";
|
||||
}
|
||||
|
||||
/* check the shell is valid. If /etc/shells doesn't exist, getusershell()
|
||||
* should return some standard shells like "/bin/sh" and "/bin/csh" (this
|
||||
* is platform-specific) */
|
||||
setusershell();
|
||||
while ((listshell = getusershell()) != NULL) {
|
||||
TRACE(("test shell is '%s'", listshell));
|
||||
if (strcmp(listshell, usershell) == 0) {
|
||||
/* have a match */
|
||||
goto goodshell;
|
||||
}
|
||||
}
|
||||
/* no matching shell */
|
||||
endusershell();
|
||||
TRACE(("no matching shell"));
|
||||
dropbear_log(LOG_WARNING, "user '%s' has invalid shell, rejected",
|
||||
svr_ses.authstate.printableuser);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return DROPBEAR_FAILURE;
|
||||
|
||||
goodshell:
|
||||
endusershell();
|
||||
TRACE(("matching shell"));
|
||||
|
||||
TRACE(("uid = %d", svr_ses.authstate.pw->pw_uid));
|
||||
TRACE(("leave checkusername"));
|
||||
return DROPBEAR_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
/* Send a failure message to the client, in responds to a userauth_request.
|
||||
* Partial indicates whether to set the "partial success" flag,
|
||||
* incrfail is whether to count this failure in the failure count (which
|
||||
* is limited. This function also handles disconnection after too many
|
||||
* failures */
|
||||
void send_msg_userauth_failure(int partial, int incrfail) {
|
||||
|
||||
buffer *typebuf;
|
||||
|
||||
TRACE(("enter send_msg_userauth_failure"));
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_FAILURE);
|
||||
|
||||
/* put a list of allowed types */
|
||||
typebuf = buf_new(30); /* long enough for PUBKEY and PASSWORD */
|
||||
|
||||
if (svr_ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
|
||||
buf_putbytes(typebuf, AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN);
|
||||
if (svr_ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
|
||||
buf_putbyte(typebuf, ',');
|
||||
}
|
||||
}
|
||||
|
||||
if (svr_ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
|
||||
buf_putbytes(typebuf, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN);
|
||||
}
|
||||
|
||||
buf_setpos(typebuf, 0);
|
||||
buf_putstring(ses.writepayload, buf_getptr(typebuf, typebuf->len),
|
||||
typebuf->len);
|
||||
buf_free(typebuf);
|
||||
|
||||
buf_putbyte(ses.writepayload, partial ? 1 : 0);
|
||||
encrypt_packet();
|
||||
|
||||
if (incrfail) {
|
||||
usleep(300000); /* XXX improve this */
|
||||
svr_ses.authstate.failcount++;
|
||||
}
|
||||
|
||||
if (svr_ses.authstate.failcount >= MAX_AUTH_TRIES) {
|
||||
char * userstr;
|
||||
/* XXX - send disconnect ? */
|
||||
TRACE(("Max auth tries reached, exiting"));
|
||||
|
||||
if (svr_ses.authstate.printableuser == NULL) {
|
||||
userstr = "is invalid";
|
||||
} else {
|
||||
userstr = svr_ses.authstate.printableuser;
|
||||
}
|
||||
dropbear_exit("Max auth tries reached - user %s", userstr);
|
||||
}
|
||||
|
||||
TRACE(("leave send_msg_userauth_failure"));
|
||||
}
|
||||
|
||||
/* Send a success message to the user, and set the "authdone" flag */
|
||||
void send_msg_userauth_success() {
|
||||
|
||||
TRACE(("enter send_msg_userauth_success"));
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_SUCCESS);
|
||||
encrypt_packet();
|
||||
|
||||
svr_ses.authstate.authdone = 1;
|
||||
|
||||
/* Remove from the list of pre-auth sockets. Should be m_close(), since if
|
||||
* we fail, we might end up leaking connection slots, and disallow new
|
||||
* logins - a nasty situation. */
|
||||
m_close(svr_ses.childpipe);
|
||||
|
||||
TRACE(("leave send_msg_userauth_success"));
|
||||
|
||||
}
|
||||
108
svr-authpasswd.c
Normal file
108
svr-authpasswd.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
/* Validates a user password */
|
||||
|
||||
#include "includes.h"
|
||||
#include "session.h"
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "auth.h"
|
||||
#include "authpasswd.h"
|
||||
|
||||
#ifdef DROPBEAR_PASSWORD_AUTH
|
||||
|
||||
/* Process a password auth request, sending success or failure messages as
|
||||
* appropriate */
|
||||
void passwordauth() {
|
||||
|
||||
#ifdef HAVE_SHADOW_H
|
||||
struct spwd *spasswd;
|
||||
#endif
|
||||
char * passwdcrypt; /* the crypt from /etc/passwd or /etc/shadow */
|
||||
char * testcrypt; /* crypt generated from the user's password sent */
|
||||
unsigned char * password;
|
||||
unsigned int passwordlen;
|
||||
|
||||
unsigned char changepw;
|
||||
|
||||
passwdcrypt = svr_ses.authstate.pw->pw_passwd;
|
||||
#ifdef HAVE_SHADOW_H
|
||||
/* get the shadow password if possible */
|
||||
spasswd = getspnam(svr_ses.authstate.pw->pw_name);
|
||||
if (spasswd != NULL && spasswd->sp_pwdp != NULL) {
|
||||
passwdcrypt = spasswd->sp_pwdp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_HACKCRYPT
|
||||
/* debugging crypt for non-root testing with shadows */
|
||||
passwdcrypt = DEBUG_HACKCRYPT;
|
||||
#endif
|
||||
|
||||
/* check for empty password - need to do this again here
|
||||
* since the shadow password may differ to that tested
|
||||
* in auth.c */
|
||||
if (passwdcrypt[0] == '\0') {
|
||||
dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected",
|
||||
svr_ses.authstate.printableuser);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if client wants to change password */
|
||||
changepw = buf_getbyte(ses.payload);
|
||||
if (changepw) {
|
||||
/* not implemented by this server */
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
password = buf_getstring(ses.payload, &passwordlen);
|
||||
|
||||
/* clear the buffer containing the password */
|
||||
buf_incrpos(ses.payload, -passwordlen - 4);
|
||||
m_burn(buf_getptr(ses.payload, passwordlen + 4), passwordlen + 4);
|
||||
|
||||
/* the first bytes of passwdcrypt are the salt */
|
||||
testcrypt = crypt((char*)password, passwdcrypt);
|
||||
|
||||
if (strcmp(testcrypt, passwdcrypt) == 0) {
|
||||
/* successful authentication */
|
||||
dropbear_log(LOG_NOTICE,
|
||||
"password auth succeeded for '%s'",
|
||||
svr_ses.authstate.printableuser);
|
||||
send_msg_userauth_success();
|
||||
} else {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"bad password attempt for '%s'",
|
||||
svr_ses.authstate.printableuser);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
}
|
||||
|
||||
m_burn(password, passwordlen);
|
||||
m_free(password);
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_PASSWORD_AUTH */
|
||||
424
svr-authpubkey.c
Normal file
424
svr-authpubkey.c
Normal file
@@ -0,0 +1,424 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
/* Process a pubkey auth request */
|
||||
|
||||
#include "includes.h"
|
||||
#include "session.h"
|
||||
#include "dbutil.h"
|
||||
#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
|
||||
|
||||
#define MIN_AUTHKEYS_LINE 10 /* "ssh-rsa AB" - short but doesn't matter */
|
||||
#define MAX_AUTHKEYS_LINE 1000 /* max length of a line in authkeys */
|
||||
|
||||
static int checkpubkey(unsigned char* algo, unsigned int algolen,
|
||||
unsigned char* keyblob, unsigned int keybloblen);
|
||||
static int checkpubkeyperms();
|
||||
static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen,
|
||||
unsigned char* keyblob, unsigned int keybloblen);
|
||||
static int checkfileperm(char * filename);
|
||||
static int getauthline(buffer * line, FILE * authfile);
|
||||
|
||||
/* process a pubkey auth request, sending success or failure message as
|
||||
* appropriate */
|
||||
void pubkeyauth() {
|
||||
|
||||
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 int keybloblen;
|
||||
buffer * signbuf = NULL;
|
||||
unsigned int sigoffset;
|
||||
sign_key * key = NULL;
|
||||
char* fp = NULL;
|
||||
int type = -1;
|
||||
|
||||
TRACE(("enter pubkeyauth"));
|
||||
|
||||
/* 0 indicates user just wants to check if key can be used, 1 is an
|
||||
* actual attempt*/
|
||||
testkey = (buf_getbyte(ses.payload) == 0);
|
||||
|
||||
algo = buf_getstring(ses.payload, &algolen);
|
||||
keybloblen = buf_getint(ses.payload);
|
||||
keyblob = buf_getptr(ses.payload, keybloblen);
|
||||
|
||||
/* check if the key is valid */
|
||||
if (checkpubkey(algo, algolen, keyblob, keybloblen) == DROPBEAR_FAILURE) {
|
||||
send_msg_userauth_failure(0, 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* let them know that the key is ok to use */
|
||||
if (testkey) {
|
||||
send_msg_userauth_pk_ok(algo, algolen, keyblob, keybloblen);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* now we can actually verify the signature */
|
||||
|
||||
/* get the key */
|
||||
key = new_sign_key();
|
||||
type = DROPBEAR_SIGNKEY_ANY;
|
||||
if (buf_get_pub_key(ses.payload, key, &type) == DROPBEAR_FAILURE) {
|
||||
send_msg_userauth_failure(0, 1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* create the data which has been signed - this a string containing
|
||||
* session_id, concatenated with the payload packet up to the signature */
|
||||
signbuf = buf_new(ses.payload->pos + 4 + SHA1_HASH_SIZE);
|
||||
buf_putstring(signbuf, ses.session_id, SHA1_HASH_SIZE);
|
||||
sigoffset = ses.payload->pos;
|
||||
buf_setpos(ses.payload, 0);
|
||||
memcpy(buf_getwriteptr(signbuf, sigoffset),
|
||||
buf_getptr(ses.payload, sigoffset), sigoffset);
|
||||
buf_incrwritepos(signbuf, sigoffset);
|
||||
buf_setpos(ses.payload, sigoffset);
|
||||
|
||||
buf_setpos(signbuf, 0);
|
||||
/* ... and finally verify the signature */
|
||||
fp = sign_key_fingerprint(key, type);
|
||||
if (buf_verify(ses.payload, key, buf_getptr(signbuf, signbuf->len),
|
||||
signbuf->len) == DROPBEAR_SUCCESS) {
|
||||
dropbear_log(LOG_NOTICE,
|
||||
"pubkey auth succeeded for '%s' with key %s",
|
||||
svr_ses.authstate.printableuser, fp);
|
||||
send_msg_userauth_success();
|
||||
} else {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"pubkey auth bad signature for '%s' with key %s",
|
||||
svr_ses.authstate.printableuser, fp);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
}
|
||||
m_free(fp);
|
||||
|
||||
out:
|
||||
/* cleanup stuff */
|
||||
if (signbuf) {
|
||||
buf_free(signbuf);
|
||||
}
|
||||
if (algo) {
|
||||
m_free(algo);
|
||||
}
|
||||
if (key) {
|
||||
sign_key_free(key);
|
||||
key = NULL;
|
||||
}
|
||||
TRACE(("leave pubkeyauth"));
|
||||
}
|
||||
|
||||
/* Reply that the key is valid for auth, this is sent when the user sends
|
||||
* a straight copy of their pubkey to test, to avoid having to perform
|
||||
* expensive signing operations with a worthless key */
|
||||
static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen,
|
||||
unsigned char* keyblob, unsigned int keybloblen) {
|
||||
|
||||
TRACE(("enter send_msg_userauth_pk_ok"));
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_PK_OK);
|
||||
buf_putstring(ses.writepayload, algo, algolen);
|
||||
buf_putstring(ses.writepayload, keyblob, keybloblen);
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave send_msg_userauth_pk_ok"));
|
||||
|
||||
}
|
||||
|
||||
/* Checks whether a specified publickey (and associated algorithm) is an
|
||||
* acceptable key for authentication */
|
||||
/* Returns DROPBEAR_SUCCESS if key is ok for auth, DROPBEAR_FAILURE otherwise */
|
||||
static int checkpubkey(unsigned char* algo, unsigned int algolen,
|
||||
unsigned char* keyblob, unsigned int keybloblen) {
|
||||
|
||||
FILE * authfile = NULL;
|
||||
char * filename = NULL;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
buffer * line = NULL;
|
||||
buffer * decodekey = NULL;
|
||||
unsigned long decodekeylen;
|
||||
unsigned char* filealgo = NULL;
|
||||
unsigned int filealgolen;
|
||||
unsigned int len, pos;
|
||||
|
||||
TRACE(("enter checkpubkey"));
|
||||
|
||||
/* check that we can use the algo */
|
||||
if (have_algo(algo, algolen, sshhostkey) == DROPBEAR_FAILURE) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"pubkey auth attempt with unknown algo for '%s'",
|
||||
svr_ses.authstate.printableuser);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* check file permissions, also whether file exists */
|
||||
if (checkpubkeyperms() == DROPBEAR_FAILURE) {
|
||||
TRACE(("bad authorized_keys permissions, or file doesn't exist"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* we don't need to check pw and pw_dir for validity, since
|
||||
* its been done in checkpubkeyperms. */
|
||||
len = strlen(svr_ses.authstate.pw->pw_dir);
|
||||
/* allocate max required pathname storage,
|
||||
* = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
|
||||
filename = m_malloc(len + 22);
|
||||
snprintf(filename, len + 22, "%s/.ssh/authorized_keys",
|
||||
svr_ses.authstate.pw->pw_dir);
|
||||
|
||||
/* open the file */
|
||||
authfile = fopen(filename, "r");
|
||||
if (authfile == NULL) {
|
||||
goto out;
|
||||
}
|
||||
TRACE(("checkpubkey: opened authorized_keys OK"));
|
||||
|
||||
line = buf_new(MAX_AUTHKEYS_LINE);
|
||||
|
||||
/* iterate through the lines */
|
||||
do {
|
||||
/* free reused vars */
|
||||
if (decodekey) {
|
||||
buf_free(decodekey);
|
||||
decodekey = NULL;
|
||||
}
|
||||
m_free(filealgo);
|
||||
|
||||
if (getauthline(line, authfile) == DROPBEAR_FAILURE) {
|
||||
/* EOF reached */
|
||||
TRACE(("checkpubkey: authorized_keys EOF reached"));
|
||||
break;
|
||||
}
|
||||
|
||||
if (line->len < MIN_AUTHKEYS_LINE) {
|
||||
TRACE(("checkpubkey: line too short"));
|
||||
continue; /* line is too short for it to be a valid key */
|
||||
}
|
||||
|
||||
/* check the key type - this also stops us from using keys
|
||||
* which have options with them */
|
||||
if (strncmp(buf_getptr(line, algolen), algo, algolen) != 0) {
|
||||
continue;
|
||||
}
|
||||
buf_incrpos(line, algolen);
|
||||
|
||||
/* check for space (' ') character */
|
||||
if (buf_getbyte(line) != ' ') {
|
||||
TRACE(("checkpubkey: space character expected, isn't there"));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* truncate the line at the space after the base64 data */
|
||||
pos = line->pos;
|
||||
for (len = 0; line->pos < line->len; len++) {
|
||||
if (buf_getbyte(line) == ' ') break;
|
||||
}
|
||||
buf_setpos(line, pos);
|
||||
buf_setlen(line, line->pos + len);
|
||||
|
||||
TRACE(("checkpubkey: line pos = %d len = %d", line->pos, line->len));
|
||||
|
||||
/* now we have the actual data */
|
||||
decodekeylen = (line->len - line->pos) * 2;
|
||||
decodekey = buf_new(decodekeylen);
|
||||
if (base64_decode(buf_getptr(line, line->len - line->pos),
|
||||
line->len - line->pos,
|
||||
buf_getwriteptr(decodekey, decodekey->size),
|
||||
&decodekeylen) != CRYPT_OK) {
|
||||
TRACE(("checkpubkey: base64 decode failed"));
|
||||
continue;
|
||||
}
|
||||
TRACE(("checkpubkey: base64_decode success"));
|
||||
buf_incrlen(decodekey, decodekeylen);
|
||||
|
||||
/* compare the keys */
|
||||
if (decodekeylen != keybloblen || memcmp(
|
||||
buf_getptr(decodekey, decodekey->len),
|
||||
keyblob, decodekey->len) != 0) {
|
||||
TRACE(("checkpubkey: compare failed"));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* and also check that the algo specified and the algo in the key
|
||||
* itself match */
|
||||
filealgo = buf_getstring(decodekey, &filealgolen);
|
||||
if (filealgolen != algolen || memcmp(filealgo, algo, algolen) != 0) {
|
||||
TRACE(("checkpubkey: algo match failed"));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* now we know this key is good */
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
break;
|
||||
|
||||
} while (1);
|
||||
|
||||
out:
|
||||
if (authfile) {
|
||||
fclose(authfile);
|
||||
}
|
||||
if (line) {
|
||||
buf_free(line);
|
||||
}
|
||||
if (decodekey) {
|
||||
buf_free(decodekey);
|
||||
}
|
||||
m_free(filename);
|
||||
m_free(filealgo);
|
||||
TRACE(("leave checkpubkey: ret=%d", ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* get a line from the file into buffer in the style expected for an
|
||||
* authkeys file.
|
||||
* Will return DROPBEAR_SUCCESS if data is read, or DROPBEAR_FAILURE on EOF.*/
|
||||
static int getauthline(buffer * line, FILE * authfile) {
|
||||
|
||||
int c = EOF;
|
||||
|
||||
TRACE(("enter getauthline"));
|
||||
|
||||
buf_setpos(line, 0);
|
||||
buf_setlen(line, 0);
|
||||
|
||||
while (line->pos < line->size) {
|
||||
c = fgetc(authfile); /*getc() is weird with some uClibc systems*/
|
||||
if (c == EOF || c == '\n' || c == '\r') {
|
||||
goto out;
|
||||
}
|
||||
buf_putbyte(line, (unsigned char)c);
|
||||
}
|
||||
|
||||
TRACE(("leave getauthline: line too long"));
|
||||
return DROPBEAR_FAILURE;
|
||||
|
||||
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"));
|
||||
return DROPBEAR_FAILURE;
|
||||
} else {
|
||||
TRACE(("leave getauthline: success"));
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
TRACE(("leave getauthline"));
|
||||
}
|
||||
|
||||
/* Returns DROPBEAR_SUCCESS if file permissions for pubkeys are ok,
|
||||
* DROPBEAR_FAILURE otherwise.
|
||||
* Checks that the user's homedir, ~/.ssh, and
|
||||
* ~/.ssh/authorized_keys are all owned by either root or the user, and are
|
||||
* g-w, o-w */
|
||||
static int checkpubkeyperms() {
|
||||
|
||||
char* filename = NULL;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
unsigned int len;
|
||||
|
||||
TRACE(("enter checkpubkeyperms"));
|
||||
|
||||
assert(svr_ses.authstate.pw);
|
||||
if (svr_ses.authstate.pw->pw_dir == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((len = strlen(svr_ses.authstate.pw->pw_dir)) == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* allocate max required pathname storage,
|
||||
* = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
|
||||
filename = m_malloc(len + 22);
|
||||
strncpy(filename, svr_ses.authstate.pw->pw_dir, len+1);
|
||||
|
||||
/* check ~ */
|
||||
if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* check ~/.ssh */
|
||||
strncat(filename, "/.ssh", 5); /* strlen("/.ssh") == 5 */
|
||||
if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* now check ~/.ssh/authorized_keys */
|
||||
strncat(filename, "/authorized_keys", 16);
|
||||
if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* file looks ok, return success */
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
|
||||
out:
|
||||
m_free(filename);
|
||||
|
||||
TRACE(("leave checkpubkeyperms"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Checks that a file is owned by the user or root, and isn't writable by
|
||||
* group or other */
|
||||
/* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int checkfileperm(char * filename) {
|
||||
struct stat filestat;
|
||||
|
||||
TRACE(("enter checkfileperm(%s)", filename));
|
||||
|
||||
if (stat(filename, &filestat) != 0) {
|
||||
TRACE(("leave checkfileperm: stat() != 0"));
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
/* check ownership - user or root only*/
|
||||
if (filestat.st_uid != svr_ses.authstate.pw->pw_uid
|
||||
&& filestat.st_uid != 0) {
|
||||
TRACE(("leave checkfileperm: wrong ownership"));
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
/* check permissions - don't want group or others +w */
|
||||
if (filestat.st_mode & (S_IWGRP | S_IWOTH)) {
|
||||
TRACE(("leave checkfileperm: wrong perms"));
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
TRACE(("leave checkfileperm: success"));
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#endif /* DROPBEAR_PUBKEY_AUTH */
|
||||
931
svr-chansession.c
Normal file
931
svr-chansession.c
Normal file
@@ -0,0 +1,931 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "session.h"
|
||||
#include "dbutil.h"
|
||||
#include "channel.h"
|
||||
#include "chansession.h"
|
||||
#include "sshpty.h"
|
||||
#include "termcodes.h"
|
||||
#include "ssh.h"
|
||||
#include "random.h"
|
||||
#include "utmp.h"
|
||||
#include "x11fwd.h"
|
||||
#include "agentfwd.h"
|
||||
|
||||
/* Handles sessions (either shells or programs) requested by the client */
|
||||
|
||||
static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
|
||||
int iscmd, int issubsys);
|
||||
static int sessionpty(struct ChanSess * chansess);
|
||||
static int sessionsignal(struct ChanSess *chansess);
|
||||
static int noptycommand(struct Channel *channel, struct ChanSess *chansess);
|
||||
static int ptycommand(struct Channel *channel, struct ChanSess *chansess);
|
||||
static int sessionwinchange(struct ChanSess *chansess);
|
||||
static void execchild(struct ChanSess *chansess);
|
||||
static void addchildpid(struct ChanSess *chansess, pid_t pid);
|
||||
static void sesssigchild_handler(int val);
|
||||
static void closechansess(struct Channel *channel);
|
||||
static void newchansess(struct Channel *channel);
|
||||
static void chansessionrequest(struct Channel *channel);
|
||||
|
||||
static void send_exitsignalstatus(struct Channel *channel);
|
||||
static int sesscheckclose(struct Channel *channel);
|
||||
|
||||
const struct ChanType svrchansess = {
|
||||
0, /* sepfds */
|
||||
"session", /* name */
|
||||
newchansess, /* inithandler */
|
||||
sesscheckclose, /* checkclosehandler */
|
||||
chansessionrequest, /* reqhandler */
|
||||
closechansess, /* closehandler */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* required to clear environment */
|
||||
extern char** environ;
|
||||
|
||||
static int sesscheckclose(struct Channel *channel) {
|
||||
struct ChanSess *chansess = (struct ChanSess*)channel->typedata;
|
||||
return chansess->exited;
|
||||
}
|
||||
|
||||
/* Set up the general chansession environment, in particular child-exit
|
||||
* handling */
|
||||
void svr_chansessinitialise() {
|
||||
|
||||
struct sigaction sa_chld;
|
||||
|
||||
/* single child process intially */
|
||||
svr_ses.childpids = (struct ChildPid*)m_malloc(sizeof(struct ChildPid));
|
||||
svr_ses.childpids[0].pid = -1; /* unused */
|
||||
svr_ses.childpids[0].chansess = NULL;
|
||||
svr_ses.childpidsize = 1;
|
||||
sa_chld.sa_handler = sesssigchild_handler;
|
||||
sa_chld.sa_flags = SA_NOCLDSTOP;
|
||||
if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) {
|
||||
dropbear_exit("signal() error");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* handler for childs exiting, store the state for return to the client */
|
||||
static void sesssigchild_handler(int dummy) {
|
||||
|
||||
int status;
|
||||
pid_t pid;
|
||||
unsigned int i;
|
||||
struct ChanSess * chansess;
|
||||
struct sigaction sa_chld;
|
||||
|
||||
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) {
|
||||
|
||||
chansess = svr_ses.childpids[i].chansess;
|
||||
chansess->exited = 1;
|
||||
if (WIFEXITED(status)) {
|
||||
chansess->exitstatus = WEXITSTATUS(status);
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
chansess->exitsignal = WTERMSIG(status);
|
||||
#ifndef AIX
|
||||
chansess->exitcore = WCOREDUMP(status);
|
||||
#endif
|
||||
} else {
|
||||
/* we use this to determine how pid exited */
|
||||
chansess->exitsignal = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sa_chld.sa_handler = sesssigchild_handler;
|
||||
sa_chld.sa_flags = SA_NOCLDSTOP;
|
||||
sigaction(SIGCHLD, &sa_chld, NULL);
|
||||
TRACE(("leave sigchld handler"));
|
||||
}
|
||||
|
||||
/* send the exit status or the signal causing termination for a session */
|
||||
/* XXX server */
|
||||
static void send_exitsignalstatus(struct Channel *channel) {
|
||||
|
||||
struct ChanSess *chansess = (struct ChanSess*)channel->typedata;
|
||||
|
||||
if (chansess->exited) {
|
||||
if (chansess->exitsignal > 0) {
|
||||
send_msg_chansess_exitsignal(channel, chansess);
|
||||
} else {
|
||||
send_msg_chansess_exitstatus(channel, chansess);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* send the exitstatus to the client */
|
||||
static void send_msg_chansess_exitstatus(struct Channel * channel,
|
||||
struct ChanSess * chansess) {
|
||||
|
||||
assert(chansess->exited);
|
||||
assert(chansess->exitsignal == -1);
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
|
||||
buf_putint(ses.writepayload, channel->remotechan);
|
||||
buf_putstring(ses.writepayload, "exit-status", 11);
|
||||
buf_putbyte(ses.writepayload, 0); /* boolean FALSE */
|
||||
buf_putint(ses.writepayload, chansess->exitstatus);
|
||||
|
||||
encrypt_packet();
|
||||
|
||||
}
|
||||
|
||||
/* send the signal causing the exit to the client */
|
||||
static void send_msg_chansess_exitsignal(struct Channel * channel,
|
||||
struct ChanSess * chansess) {
|
||||
|
||||
int i;
|
||||
char* signame = NULL;
|
||||
|
||||
assert(chansess->exited);
|
||||
assert(chansess->exitsignal > 0);
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
/* we check that we can match a signal name, otherwise
|
||||
* don't send anything */
|
||||
for (i = 0; signames[i].name != NULL; i++) {
|
||||
if (signames[i].signal == chansess->exitsignal) {
|
||||
signame = signames[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (signame == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
|
||||
buf_putint(ses.writepayload, channel->remotechan);
|
||||
buf_putstring(ses.writepayload, "exit-signal", 11);
|
||||
buf_putbyte(ses.writepayload, 0); /* boolean FALSE */
|
||||
buf_putstring(ses.writepayload, signame, strlen(signame));
|
||||
buf_putbyte(ses.writepayload, chansess->exitcore);
|
||||
buf_putstring(ses.writepayload, "", 0); /* error msg */
|
||||
buf_putstring(ses.writepayload, "", 0); /* lang */
|
||||
|
||||
encrypt_packet();
|
||||
}
|
||||
|
||||
/* set up a session channel */
|
||||
static void newchansess(struct Channel *channel) {
|
||||
|
||||
struct ChanSess *chansess;
|
||||
|
||||
assert(channel->typedata == NULL);
|
||||
|
||||
chansess = (struct ChanSess*)m_malloc(sizeof(struct ChanSess));
|
||||
chansess->cmd = NULL;
|
||||
chansess->pid = 0;
|
||||
|
||||
/* pty details */
|
||||
chansess->master = -1;
|
||||
chansess->slave = -1;
|
||||
chansess->tty = NULL;
|
||||
chansess->term = NULL;
|
||||
chansess->termw = 0;
|
||||
chansess->termh = 0;
|
||||
chansess->termc = 0;
|
||||
chansess->termr = 0;
|
||||
|
||||
chansess->exited = 0;
|
||||
|
||||
channel->typedata = chansess;
|
||||
|
||||
#ifndef DISABLE_X11FWD
|
||||
chansess->x11fd = -1;
|
||||
chansess->x11authprot = NULL;
|
||||
chansess->x11authcookie = NULL;
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
chansess->agentfd = -1;
|
||||
chansess->agentfile = NULL;
|
||||
chansess->agentdir = NULL;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* clean a session channel */
|
||||
static void closechansess(struct Channel *channel) {
|
||||
|
||||
struct ChanSess *chansess;
|
||||
unsigned int i;
|
||||
struct logininfo *li;
|
||||
|
||||
chansess = (struct ChanSess*)channel->typedata;
|
||||
|
||||
send_exitsignalstatus(chansess);
|
||||
|
||||
TRACE(("enter closechansess"));
|
||||
if (chansess == NULL) {
|
||||
TRACE(("leave closechansess: chansess == NULL"));
|
||||
return;
|
||||
}
|
||||
|
||||
m_free(chansess->cmd);
|
||||
m_free(chansess->term);
|
||||
|
||||
if (chansess->tty) {
|
||||
/* write the utmp/wtmp login record */
|
||||
li = login_alloc_entry(chansess->pid, svr_ses.authstate.username,
|
||||
ses.remotehost, chansess->tty);
|
||||
login_logout(li);
|
||||
login_free_entry(li);
|
||||
|
||||
pty_release(chansess->tty);
|
||||
m_free(chansess->tty);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_X11FWD
|
||||
x11cleanup(chansess);
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
agentcleanup(chansess);
|
||||
#endif
|
||||
|
||||
/* clear child pid entries */
|
||||
for (i = 0; i < svr_ses.childpidsize; i++) {
|
||||
if (svr_ses.childpids[i].chansess == chansess) {
|
||||
assert(svr_ses.childpids[i].pid > 0);
|
||||
TRACE(("closing pid %d", svr_ses.childpids[i].pid));
|
||||
TRACE(("exited = %d", chansess->exited));
|
||||
svr_ses.childpids[i].pid = -1;
|
||||
svr_ses.childpids[i].chansess = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
m_free(chansess);
|
||||
|
||||
TRACE(("leave closechansess"));
|
||||
}
|
||||
|
||||
/* Handle requests for a channel. These can be execution requests,
|
||||
* or x11/authagent forwarding. These are passed to appropriate handlers */
|
||||
static void chansessionrequest(struct Channel *channel) {
|
||||
|
||||
unsigned char * type;
|
||||
unsigned int typelen;
|
||||
unsigned char wantreply;
|
||||
int ret = 1;
|
||||
struct ChanSess *chansess;
|
||||
|
||||
TRACE(("enter chansessionrequest"));
|
||||
|
||||
assert(channel->type == CHANNEL_ID_SESSION);
|
||||
|
||||
type = buf_getstring(ses.payload, &typelen);
|
||||
wantreply = buf_getbyte(ses.payload);
|
||||
|
||||
if (typelen > MAX_NAME_LEN) {
|
||||
TRACE(("leave chansessionrequest: type too long")); /* XXX send error?*/
|
||||
goto out;
|
||||
}
|
||||
|
||||
chansess = (struct ChanSess*)channel->typedata;
|
||||
assert(chansess != NULL);
|
||||
TRACE(("type is %s", type));
|
||||
|
||||
if (strcmp(type, "window-change") == 0) {
|
||||
ret = sessionwinchange(chansess);
|
||||
} else if (strcmp(type, "shell") == 0) {
|
||||
ret = sessioncommand(channel, chansess, 0, 0);
|
||||
} else if (strcmp(type, "pty-req") == 0) {
|
||||
ret = sessionpty(chansess);
|
||||
} else if (strcmp(type, "exec") == 0) {
|
||||
ret = sessioncommand(channel, chansess, 1, 0);
|
||||
} else if (strcmp(type, "subsystem") == 0) {
|
||||
ret = sessioncommand(channel, chansess, 1, 1);
|
||||
#ifndef DISABLE_X11FWD
|
||||
} else if (strcmp(type, "x11-req") == 0) {
|
||||
ret = x11req(chansess);
|
||||
#endif
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
} else if (strcmp(type, "auth-agent-req@openssh.com") == 0) {
|
||||
ret = agentreq(chansess);
|
||||
#endif
|
||||
} else if (strcmp(type, "signal") == 0) {
|
||||
ret = sessionsignal(chansess);
|
||||
} else {
|
||||
/* etc, todo "env", "subsystem" */
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
if (wantreply) {
|
||||
if (ret == 0) {
|
||||
send_msg_channel_success(channel);
|
||||
} else {
|
||||
send_msg_channel_failure(channel);
|
||||
}
|
||||
}
|
||||
|
||||
m_free(type);
|
||||
TRACE(("leave chansessionrequest"));
|
||||
}
|
||||
|
||||
|
||||
/* Send a signal to a session's process as requested by the client*/
|
||||
static int sessionsignal(struct ChanSess *chansess) {
|
||||
|
||||
int sig = 0;
|
||||
unsigned char* signame;
|
||||
int i;
|
||||
|
||||
if (chansess->pid == 0) {
|
||||
/* haven't got a process pid yet */
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
signame = buf_getstring(ses.payload, NULL);
|
||||
|
||||
i = 0;
|
||||
while (signames[i].name != 0) {
|
||||
if (strcmp(signames[i].name, signame) == 0) {
|
||||
sig = signames[i].signal;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
m_free(signame);
|
||||
|
||||
if (sig == 0) {
|
||||
/* failed */
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
if (kill(chansess->pid, sig) < 0) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* Let the process know that the window size has changed, as notified from the
|
||||
* client. Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int sessionwinchange(struct ChanSess *chansess) {
|
||||
|
||||
if (chansess->master < 0) {
|
||||
/* haven't got a pty yet */
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
chansess->termc = buf_getint(ses.payload);
|
||||
chansess->termr = buf_getint(ses.payload);
|
||||
chansess->termw = buf_getint(ses.payload);
|
||||
chansess->termh = buf_getint(ses.payload);
|
||||
|
||||
pty_change_window_size(chansess->master, chansess->termr, chansess->termc,
|
||||
chansess->termw, chansess->termh);
|
||||
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* Set up a session pty which will be used to execute the shell or program.
|
||||
* The pty is allocated now, and kept for when the shell/program executes.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int sessionpty(struct ChanSess * chansess) {
|
||||
|
||||
unsigned int termlen;
|
||||
unsigned char namebuf[65];
|
||||
struct termios termio;
|
||||
|
||||
TRACE(("enter sessionpty"));
|
||||
chansess->term = buf_getstring(ses.payload, &termlen);
|
||||
if (termlen > MAX_TERM_LEN) {
|
||||
/* TODO send disconnect ? */
|
||||
TRACE(("leave sessionpty: term len too long"));
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
chansess->termc = buf_getint(ses.payload);
|
||||
chansess->termr = buf_getint(ses.payload);
|
||||
chansess->termw = buf_getint(ses.payload);
|
||||
chansess->termh = buf_getint(ses.payload);
|
||||
|
||||
/* allocate the pty */
|
||||
assert(chansess->master == -1); /* haven't already got one */
|
||||
if (pty_allocate(&chansess->master, &chansess->slave, namebuf, 64) == 0) {
|
||||
TRACE(("leave sessionpty: failed to allocate pty"));
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
chansess->tty = (char*)strdup(namebuf);
|
||||
if (!chansess->tty) {
|
||||
dropbear_exit("out of memory"); /* TODO disconnect */
|
||||
}
|
||||
|
||||
pty_setowner(svr_ses.authstate.pw, chansess->tty);
|
||||
pty_change_window_size(chansess->master, chansess->termr, chansess->termc,
|
||||
chansess->termw, chansess->termh);
|
||||
|
||||
/* Term modes */
|
||||
/* We'll ignore errors and continue if we can't set modes.
|
||||
* We're ignoring baud rates since they seem evil */
|
||||
if (tcgetattr(chansess->master, &termio) == 0) {
|
||||
unsigned char opcode;
|
||||
unsigned int value;
|
||||
const struct TermCode * termcode;
|
||||
unsigned int len;
|
||||
|
||||
len = buf_getint(ses.payload);
|
||||
if (len != ses.payload->len - ses.payload->pos) {
|
||||
dropbear_exit("bad term mode string");
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
TRACE(("empty terminal modes string"));
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
while (((opcode = buf_getbyte(ses.payload)) != 0x00) &&
|
||||
opcode <= 159) {
|
||||
|
||||
/* must be before checking type, so that value is consumed even if
|
||||
* we don't use it */
|
||||
value = buf_getint(ses.payload);
|
||||
|
||||
/* handle types of code */
|
||||
if (opcode > MAX_TERMCODE) {
|
||||
continue;
|
||||
}
|
||||
termcode = &termcodes[(unsigned int)opcode];
|
||||
|
||||
|
||||
switch (termcode->type) {
|
||||
|
||||
case TERMCODE_NONE:
|
||||
break;
|
||||
|
||||
case TERMCODE_CONTROLCHAR:
|
||||
termio.c_cc[termcode->mapcode] = value;
|
||||
break;
|
||||
|
||||
case TERMCODE_INPUT:
|
||||
if (value) {
|
||||
termio.c_iflag |= termcode->mapcode;
|
||||
} else {
|
||||
termio.c_iflag &= ~(termcode->mapcode);
|
||||
}
|
||||
break;
|
||||
|
||||
case TERMCODE_OUTPUT:
|
||||
if (value) {
|
||||
termio.c_oflag |= termcode->mapcode;
|
||||
} else {
|
||||
termio.c_oflag &= ~(termcode->mapcode);
|
||||
}
|
||||
break;
|
||||
|
||||
case TERMCODE_LOCAL:
|
||||
if (value) {
|
||||
termio.c_lflag |= termcode->mapcode;
|
||||
} else {
|
||||
termio.c_lflag &= ~(termcode->mapcode);
|
||||
}
|
||||
break;
|
||||
|
||||
case TERMCODE_CONTROL:
|
||||
if (value) {
|
||||
termio.c_cflag |= termcode->mapcode;
|
||||
} else {
|
||||
termio.c_cflag &= ~(termcode->mapcode);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
if (tcsetattr(chansess->master, TCSANOW, &termio) < 0) {
|
||||
dropbear_log(LOG_INFO, "error setting terminal attributes");
|
||||
}
|
||||
}
|
||||
|
||||
TRACE(("leave sessionpty"));
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* Handle a command request from the client. This is used for both shell
|
||||
* and command-execution requests, and passes the command to
|
||||
* noptycommand or ptycommand as appropriate.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
|
||||
int iscmd, int issubsys) {
|
||||
|
||||
unsigned int cmdlen;
|
||||
|
||||
TRACE(("enter sessioncommand"));
|
||||
|
||||
if (chansess->cmd != NULL) {
|
||||
/* TODO - send error - multiple commands? */
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
if (iscmd) {
|
||||
/* "exec" */
|
||||
chansess->cmd = buf_getstring(ses.payload, &cmdlen);
|
||||
|
||||
if (cmdlen > MAX_CMD_LEN) {
|
||||
/* TODO - send error - too long ? */
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
if (issubsys) {
|
||||
#ifdef SFTPSERVER_PATH
|
||||
if ((cmdlen == 4) && strncmp(chansess->cmd, "sftp", 4) == 0) {
|
||||
m_free(chansess->cmd);
|
||||
chansess->cmd = strdup(SFTPSERVER_PATH);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chansess->term == NULL) {
|
||||
/* no pty */
|
||||
return noptycommand(channel, chansess);
|
||||
} else {
|
||||
/* want pty */
|
||||
return ptycommand(channel, chansess);
|
||||
}
|
||||
}
|
||||
|
||||
/* Execute a command and set up redirection of stdin/stdout/stderr without a
|
||||
* pty.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int noptycommand(struct Channel *channel, struct ChanSess *chansess) {
|
||||
|
||||
int infds[2];
|
||||
int outfds[2];
|
||||
int errfds[2];
|
||||
pid_t pid;
|
||||
|
||||
TRACE(("enter noptycommand"));
|
||||
|
||||
/* redirect stdin/stdout/stderr */
|
||||
if (pipe(infds) != 0)
|
||||
return DROPBEAR_FAILURE;
|
||||
if (pipe(outfds) != 0)
|
||||
return DROPBEAR_FAILURE;
|
||||
if (pipe(errfds) != 0)
|
||||
return DROPBEAR_FAILURE;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return DROPBEAR_FAILURE;
|
||||
|
||||
if (!pid) {
|
||||
/* child */
|
||||
|
||||
/* redirect stdin/stdout */
|
||||
#define FDIN 0
|
||||
#define FDOUT 1
|
||||
if ((dup2(infds[FDIN], STDIN_FILENO) < 0) ||
|
||||
(dup2(outfds[FDOUT], STDOUT_FILENO) < 0) ||
|
||||
(dup2(errfds[FDOUT], STDERR_FILENO) < 0)) {
|
||||
TRACE(("leave noptycommand: error redirecting FDs"));
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
close(infds[FDOUT]);
|
||||
close(infds[FDIN]);
|
||||
close(outfds[FDIN]);
|
||||
close(outfds[FDOUT]);
|
||||
close(errfds[FDIN]);
|
||||
close(errfds[FDOUT]);
|
||||
|
||||
execchild(chansess);
|
||||
/* not reached */
|
||||
|
||||
} else {
|
||||
/* parent */
|
||||
TRACE(("continue noptycommand: parent"));
|
||||
chansess->pid = pid;
|
||||
|
||||
/* add a child pid */
|
||||
addchildpid(chansess, pid);
|
||||
|
||||
close(infds[FDIN]);
|
||||
close(outfds[FDOUT]);
|
||||
close(errfds[FDOUT]);
|
||||
channel->infd = infds[FDOUT];
|
||||
channel->outfd = outfds[FDIN];
|
||||
channel->errfd = errfds[FDIN];
|
||||
ses.maxfd = MAX(ses.maxfd, channel->infd);
|
||||
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");
|
||||
}
|
||||
}
|
||||
#undef FDIN
|
||||
#undef FDOUT
|
||||
|
||||
TRACE(("leave noptycommand"));
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* Execute a command or shell within a pty environment, and set up
|
||||
* redirection as appropriate.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
|
||||
|
||||
pid_t pid;
|
||||
struct logininfo *li;
|
||||
#ifdef DO_MOTD
|
||||
buffer * motdbuf = NULL;
|
||||
int len;
|
||||
struct stat sb;
|
||||
char *hushpath = NULL;
|
||||
#endif
|
||||
|
||||
TRACE(("enter ptycommand"));
|
||||
|
||||
/* we need to have a pty allocated */
|
||||
if (chansess->master == -1 || chansess->tty == NULL) {
|
||||
dropbear_log(LOG_WARNING, "no pty was allocated, couldn't execute");
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return DROPBEAR_FAILURE;
|
||||
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
|
||||
/* redirect stdin/stdout/stderr */
|
||||
close(chansess->master);
|
||||
|
||||
pty_make_controlling_tty(&chansess->slave, chansess->tty);
|
||||
|
||||
if ((dup2(chansess->slave, STDIN_FILENO) < 0) ||
|
||||
(dup2(chansess->slave, STDERR_FILENO) < 0) ||
|
||||
(dup2(chansess->slave, STDOUT_FILENO) < 0)) {
|
||||
TRACE(("leave ptycommand: error redirecting filedesc"));
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
close(chansess->slave);
|
||||
|
||||
/* write the utmp/wtmp login record - must be after changing the
|
||||
* terminal used for stdout with the dup2 above */
|
||||
li= login_alloc_entry(getpid(), svr_ses.authstate.username,
|
||||
ses.remotehost, chansess->tty);
|
||||
login_login(li);
|
||||
login_free_entry(li);
|
||||
|
||||
m_free(chansess->tty);
|
||||
|
||||
#ifdef DO_MOTD
|
||||
if (ses.opts->domotd) {
|
||||
/* don't show the motd if ~/.hushlogin exists */
|
||||
|
||||
/* 11 == strlen("/hushlogin\0") */
|
||||
len = strlen(svr_ses.authstate.pw->pw_dir) + 11;
|
||||
|
||||
hushpath = m_malloc(len);
|
||||
snprintf(hushpath, len, "%s/hushlogin", svr_ses.authstate.pw->pw_dir);
|
||||
|
||||
if (stat(hushpath, &sb) < 0) {
|
||||
/* more than a screenful is stupid IMHO */
|
||||
motdbuf = buf_new(80 * 25);
|
||||
if (buf_readfile(motdbuf, MOTD_FILENAME) == DROPBEAR_SUCCESS) {
|
||||
buf_setpos(motdbuf, 0);
|
||||
while (motdbuf->pos != motdbuf->len) {
|
||||
len = motdbuf->len - motdbuf->pos;
|
||||
len = write(STDOUT_FILENO,
|
||||
buf_getptr(motdbuf, len), len);
|
||||
buf_incrpos(motdbuf, len);
|
||||
}
|
||||
}
|
||||
buf_free(motdbuf);
|
||||
}
|
||||
m_free(hushpath);
|
||||
}
|
||||
#endif /* DO_MOTD */
|
||||
|
||||
execchild(chansess);
|
||||
/* not reached */
|
||||
|
||||
} else {
|
||||
/* parent */
|
||||
TRACE(("continue ptycommand: parent"));
|
||||
chansess->pid = pid;
|
||||
|
||||
/* add a child pid */
|
||||
addchildpid(chansess, pid);
|
||||
|
||||
close(chansess->slave);
|
||||
channel->infd = chansess->master;
|
||||
channel->outfd = chansess->master;
|
||||
/* 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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TRACE(("leave ptycommand"));
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* Add the pid of a child to the list for exit-handling */
|
||||
static void addchildpid(struct ChanSess *chansess, pid_t pid) {
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < svr_ses.childpidsize; i++) {
|
||||
if (svr_ses.childpids[i].pid == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* need to increase size */
|
||||
if (i == svr_ses.childpidsize) {
|
||||
svr_ses.childpids = (struct ChildPid*)m_realloc(svr_ses.childpids,
|
||||
sizeof(struct ChildPid) * svr_ses.childpidsize+1);
|
||||
svr_ses.childpidsize++;
|
||||
}
|
||||
|
||||
svr_ses.childpids[i].pid = pid;
|
||||
svr_ses.childpids[i].chansess = chansess;
|
||||
|
||||
}
|
||||
|
||||
/* Clean up, drop to user privileges, set up the environment and execute
|
||||
* the command/shell. This function does not return. */
|
||||
static void execchild(struct ChanSess *chansess) {
|
||||
|
||||
char *argv[4];
|
||||
char * usershell;
|
||||
char * baseshell;
|
||||
unsigned int i;
|
||||
|
||||
/* wipe the hostkey */
|
||||
sign_key_free(ses.opts->hostkey);
|
||||
ses.opts->hostkey = NULL;
|
||||
|
||||
/* overwrite the prng state */
|
||||
seedrandom();
|
||||
|
||||
/* close file descriptors except stdin/stdout/stderr
|
||||
* Need to be sure FDs are closed here to avoid reading files as root */
|
||||
for (i = 3; i < (unsigned int)ses.maxfd; i++) {
|
||||
if (m_close(i) == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("Error closing file desc");
|
||||
}
|
||||
}
|
||||
|
||||
/* clear environment */
|
||||
/* if we're debugging using valgrind etc, we need to keep the LD_PRELOAD
|
||||
* etc. This is hazardous, so should only be used for debugging. */
|
||||
#ifndef DEBUG_VALGRIND
|
||||
#ifdef HAVE_CLEARENV
|
||||
clearenv();
|
||||
#else /* don't HAVE_CLEARENV */
|
||||
/* Yay for posix. */
|
||||
if (environ) {
|
||||
environ[0] = NULL;
|
||||
}
|
||||
#endif /* HAVE_CLEARENV */
|
||||
#endif /* DEBUG_VALGRIND */
|
||||
|
||||
/* We can only change uid/gid as root ... */
|
||||
if (getuid() == 0) {
|
||||
|
||||
if ((setgid(svr_ses.authstate.pw->pw_gid) < 0) ||
|
||||
(initgroups(svr_ses.authstate.pw->pw_name,
|
||||
svr_ses.authstate.pw->pw_gid) < 0) ||
|
||||
(setuid(svr_ses.authstate.pw->pw_uid) < 0)) {
|
||||
dropbear_exit("error changing user");
|
||||
}
|
||||
} else {
|
||||
/* ... but if the daemon is the same uid as the requested uid, we don't
|
||||
* need to */
|
||||
|
||||
/* XXX - there is a minor issue here, in that if there are multiple
|
||||
* usernames with the same uid, but differing groups, then the
|
||||
* differing groups won't be set (as with initgroups()). The solution
|
||||
* is for the sysadmin not to give out the UID twice */
|
||||
if (getuid() != svr_ses.authstate.pw->pw_uid) {
|
||||
dropbear_exit("couldn't change user as non-root");
|
||||
}
|
||||
}
|
||||
|
||||
/* an empty shell should be interpreted as "/bin/sh" */
|
||||
if (svr_ses.authstate.pw->pw_shell[0] == '\0') {
|
||||
usershell = "/bin/sh";
|
||||
} else {
|
||||
usershell = svr_ses.authstate.pw->pw_shell;
|
||||
}
|
||||
|
||||
/* set env vars */
|
||||
addnewvar("USER", svr_ses.authstate.pw->pw_name);
|
||||
addnewvar("LOGNAME", svr_ses.authstate.pw->pw_name);
|
||||
addnewvar("HOME", svr_ses.authstate.pw->pw_dir);
|
||||
addnewvar("SHELL", usershell);
|
||||
if (chansess->term != NULL) {
|
||||
addnewvar("TERM", chansess->term);
|
||||
}
|
||||
|
||||
/* change directory */
|
||||
if (chdir(svr_ses.authstate.pw->pw_dir) < 0) {
|
||||
dropbear_exit("error changing directory");
|
||||
}
|
||||
|
||||
#ifndef DISABLE_X11FWD
|
||||
/* set up X11 forwarding if enabled */
|
||||
x11setauth(chansess);
|
||||
#endif
|
||||
#ifndef DISABLE_AGENTFWD
|
||||
/* set up agent env variable */
|
||||
agentset(chansess);
|
||||
#endif
|
||||
|
||||
baseshell = basename(usershell);
|
||||
|
||||
if (chansess->cmd != NULL) {
|
||||
argv[0] = baseshell;
|
||||
} else {
|
||||
/* a login shell should be "-bash" for "/bin/bash" etc */
|
||||
int len = strlen(baseshell) + 2; /* 2 for "-" */
|
||||
argv[0] = (char*)m_malloc(len);
|
||||
snprintf(argv[0], len, "-%s", baseshell);
|
||||
}
|
||||
|
||||
if (chansess->cmd != NULL) {
|
||||
argv[1] = "-c";
|
||||
argv[2] = chansess->cmd;
|
||||
argv[3] = NULL;
|
||||
} else {
|
||||
/* construct a shell of the form "-bash" etc */
|
||||
argv[1] = NULL;
|
||||
}
|
||||
|
||||
execv(usershell, argv);
|
||||
|
||||
/* only reached on error */
|
||||
dropbear_exit("child failed");
|
||||
}
|
||||
|
||||
/* add a new environment variable, allocating space for the entry */
|
||||
void addnewvar(const char* param, const char* var) {
|
||||
|
||||
char* newvar;
|
||||
int plen, vlen;
|
||||
|
||||
plen = strlen(param);
|
||||
vlen = strlen(var);
|
||||
|
||||
newvar = m_malloc(plen + vlen + 2); /* 2 is for '=' and '\0' */
|
||||
memcpy(newvar, param, plen);
|
||||
newvar[plen] = '=';
|
||||
memcpy(&newvar[plen+1], var, vlen);
|
||||
newvar[plen+vlen+1] = '\0';
|
||||
if (putenv(newvar) < 0) {
|
||||
dropbear_exit("environ error");
|
||||
}
|
||||
}
|
||||
274
svr-kex.c
Normal file
274
svr-kex.c
Normal file
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "algo.h"
|
||||
#include "buffer.h"
|
||||
#include "session.h"
|
||||
#include "kex.h"
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "bignum.h"
|
||||
#include "random.h"
|
||||
|
||||
|
||||
static void send_msg_kexdh_reply(mp_int *dh_e);
|
||||
|
||||
/* Handle a diffie-hellman key exchange initialisation. This involves
|
||||
* calculating a session key reply value, and corresponding hash. These
|
||||
* are carried out by send_msg_kexdh_reply(). recv_msg_kexdh_init() calls
|
||||
* that function, then brings the new keys into use */
|
||||
void recv_msg_kexdh_init() {
|
||||
|
||||
mp_int dh_e;
|
||||
|
||||
TRACE(("enter recv_msg_kexdh_init"));
|
||||
if (!ses.kexstate.recvkexinit) {
|
||||
dropbear_exit("Premature kexdh_init message received");
|
||||
}
|
||||
|
||||
m_mp_init(&dh_e);
|
||||
buf_getmpint(ses.payload, &dh_e);
|
||||
|
||||
send_msg_kexdh_reply(&dh_e);
|
||||
|
||||
mp_clear(&dh_e);
|
||||
|
||||
send_msg_newkeys();
|
||||
ses.expecting = SSH_MSG_NEWKEYS;
|
||||
TRACE(("leave recv_msg_kexdh_init"));
|
||||
}
|
||||
|
||||
/* Generate our side of the diffie-hellman key exchange value (dh_f), and
|
||||
* calculate the session key using the diffie-hellman algorithm. Following
|
||||
* that, the session hash is calculated, and signed with RSA or DSS. The
|
||||
* result is sent to the client.
|
||||
*
|
||||
* See the ietf-secsh-transport draft, section 6, for details */
|
||||
static void send_msg_kexdh_reply(mp_int *dh_e) {
|
||||
|
||||
mp_int dh_p, dh_q, dh_g, dh_y, dh_f;
|
||||
unsigned char randbuf[DH_P_LEN];
|
||||
int dh_q_len;
|
||||
hash_state hs;
|
||||
|
||||
TRACE(("enter send_msg_kexdh_reply"));
|
||||
|
||||
m_mp_init_multi(&dh_g, &dh_p, &dh_q, &dh_y, &dh_f, NULL);
|
||||
|
||||
/* read the prime and generator*/
|
||||
if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN)
|
||||
!= MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
|
||||
if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
|
||||
/* calculate q = (p-1)/2 */
|
||||
if (mp_sub_d(&dh_p, 1, &dh_y) != MP_OKAY) { /*dh_y is just a temp var here*/
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
if (mp_div_2(&dh_y, &dh_q) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
|
||||
dh_q_len = mp_unsigned_bin_size(&dh_q);
|
||||
|
||||
/* calculate our random value dh_y */
|
||||
do {
|
||||
assert((unsigned int)dh_q_len <= sizeof(randbuf));
|
||||
genrandom(randbuf, dh_q_len);
|
||||
if (mp_read_unsigned_bin(&dh_y, randbuf, dh_q_len) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
} while (mp_cmp(&dh_y, &dh_q) == MP_GT || mp_cmp_d(&dh_y, 0) != MP_GT);
|
||||
|
||||
/* f = g^y mod p */
|
||||
if (mp_exptmod(&dh_g, &dh_y, &dh_p, &dh_f) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
mp_clear(&dh_g);
|
||||
|
||||
/* K = e^y mod p */
|
||||
ses.dh_K = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
m_mp_init(ses.dh_K);
|
||||
if (mp_exptmod(dh_e, &dh_y, &dh_p, ses.dh_K) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
|
||||
/* clear no longer needed vars */
|
||||
mp_clear_multi(&dh_y, &dh_p, &dh_q, NULL);
|
||||
|
||||
/* Create the remainder of the hash buffer, to generate the exchange hash */
|
||||
/* K_S, the host key */
|
||||
buf_put_pub_key(ses.kexhashbuf, ses.opts->hostkey,
|
||||
ses.newkeys->algo_hostkey);
|
||||
/* e, exchange value sent by the client */
|
||||
buf_putmpint(ses.kexhashbuf, dh_e);
|
||||
/* f, exchange value sent by the server */
|
||||
buf_putmpint(ses.kexhashbuf, &dh_f);
|
||||
/* K, the shared secret */
|
||||
buf_putmpint(ses.kexhashbuf, ses.dh_K);
|
||||
|
||||
/* calculate the hash H to sign */
|
||||
sha1_init(&hs);
|
||||
buf_setpos(ses.kexhashbuf, 0);
|
||||
sha1_process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len),
|
||||
ses.kexhashbuf->len);
|
||||
sha1_done(&hs, ses.hash);
|
||||
buf_free(ses.kexhashbuf);
|
||||
ses.kexhashbuf = NULL;
|
||||
|
||||
/* first time around, we set the session_id to H */
|
||||
if (ses.session_id == NULL) {
|
||||
/* create the session_id, this never needs freeing */
|
||||
ses.session_id = (unsigned char*)m_malloc(SHA1_HASH_SIZE);
|
||||
memcpy(ses.session_id, ses.hash, SHA1_HASH_SIZE);
|
||||
}
|
||||
|
||||
/* we can start creating the kexdh_reply packet */
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_REPLY);
|
||||
buf_put_pub_key(ses.writepayload, ses.opts->hostkey,
|
||||
ses.newkeys->algo_hostkey);
|
||||
|
||||
/* put f */
|
||||
buf_putmpint(ses.writepayload, &dh_f);
|
||||
mp_clear(&dh_f);
|
||||
|
||||
/* calc the signature */
|
||||
buf_put_sign(ses.writepayload, ses.opts->hostkey,
|
||||
ses.newkeys->algo_hostkey, ses.hash, SHA1_HASH_SIZE);
|
||||
|
||||
/* the SSH_MSG_KEXDH_REPLY is done */
|
||||
encrypt_packet();
|
||||
|
||||
TRACE(("leave send_msg_kexdh_reply"));
|
||||
}
|
||||
|
||||
/* read the client's choice of algorithms */
|
||||
void svr_read_kex() {
|
||||
|
||||
algo_type * algo;
|
||||
char * erralgo = NULL;
|
||||
|
||||
int goodguess = 0;
|
||||
int allgood = 1; /* we AND this with each goodguess and see if its still
|
||||
true after */
|
||||
|
||||
buf_incrpos(ses.payload, 16); /* start after the cookie */
|
||||
|
||||
ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
|
||||
/* kex_algorithms */
|
||||
algo = svr_buf_match_algo(ses.payload, sshkex, &goodguess);
|
||||
allgood &= goodguess;
|
||||
if (algo == NULL) {
|
||||
erralgo = "kex";
|
||||
goto error;
|
||||
}
|
||||
ses.newkeys->algo_kex = algo->val;
|
||||
|
||||
/* server_host_key_algorithms */
|
||||
algo = svr_buf_match_algo(ses.payload, sshhostkey, &goodguess);
|
||||
allgood &= goodguess;
|
||||
if (algo == NULL) {
|
||||
erralgo = "hostkey";
|
||||
goto error;
|
||||
}
|
||||
ses.newkeys->algo_hostkey = algo->val;
|
||||
|
||||
/* encryption_algorithms_client_to_server */
|
||||
algo = svr_buf_match_algo(ses.payload, sshciphers, &goodguess);
|
||||
if (algo == NULL) {
|
||||
erralgo = "enc c->s";
|
||||
goto error;
|
||||
}
|
||||
ses.newkeys->recv_algo_crypt = (struct dropbear_cipher*)algo->data;
|
||||
|
||||
/* encryption_algorithms_server_to_client */
|
||||
algo = svr_buf_match_algo(ses.payload, sshciphers, &goodguess);
|
||||
if (algo == NULL) {
|
||||
erralgo = "enc s->c";
|
||||
goto error;
|
||||
}
|
||||
ses.newkeys->trans_algo_crypt = (struct dropbear_cipher*)algo->data;
|
||||
|
||||
/* mac_algorithms_client_to_server */
|
||||
algo = svr_buf_match_algo(ses.payload, sshhashes, &goodguess);
|
||||
if (algo == NULL) {
|
||||
erralgo = "mac c->s";
|
||||
goto error;
|
||||
}
|
||||
ses.newkeys->recv_algo_mac = (struct dropbear_hash*)algo->data;
|
||||
|
||||
/* mac_algorithms_server_to_client */
|
||||
algo = svr_buf_match_algo(ses.payload, sshhashes, &goodguess);
|
||||
if (algo == NULL) {
|
||||
erralgo = "mac s->c";
|
||||
goto error;
|
||||
}
|
||||
ses.newkeys->trans_algo_mac = (struct dropbear_hash*)algo->data;
|
||||
|
||||
/* compression_algorithms_client_to_server */
|
||||
algo = svr_buf_match_algo(ses.payload, sshcompress, &goodguess);
|
||||
if (algo == NULL) {
|
||||
erralgo = "comp c->s";
|
||||
goto error;
|
||||
}
|
||||
ses.newkeys->recv_algo_comp = algo->val;
|
||||
|
||||
/* compression_algorithms_server_to_client */
|
||||
algo = svr_buf_match_algo(ses.payload, sshcompress, &goodguess);
|
||||
if (algo == NULL) {
|
||||
erralgo = "comp s->c";
|
||||
goto error;
|
||||
}
|
||||
ses.newkeys->trans_algo_comp = algo->val;
|
||||
|
||||
/* languages_client_to_server */
|
||||
buf_eatstring(ses.payload);
|
||||
|
||||
/* languages_server_to_client */
|
||||
buf_eatstring(ses.payload);
|
||||
|
||||
/* first_kex_packet_follows */
|
||||
if (buf_getbyte(ses.payload)) {
|
||||
ses.kexstate.firstfollows = 1;
|
||||
/* if the guess wasn't good, we ignore the packet sent */
|
||||
if (!allgood) {
|
||||
ses.ignorenext = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* reserved for future extensions */
|
||||
buf_getint(ses.payload);
|
||||
return;
|
||||
|
||||
error:
|
||||
dropbear_exit("no matching algo %s", erralgo);
|
||||
}
|
||||
196
svr-packet.c
Normal file
196
svr-packet.c
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "packet.h"
|
||||
#include "session.h"
|
||||
#include "dbutil.h"
|
||||
#include "ssh.h"
|
||||
#include "algo.h"
|
||||
#include "buffer.h"
|
||||
#include "kex.h"
|
||||
#include "random.h"
|
||||
#include "service.h"
|
||||
#include "auth.h"
|
||||
#include "channel.h"
|
||||
|
||||
static void svr_process_postauth_packet(unsigned int type);
|
||||
|
||||
/* process a decrypted packet, call the appropriate handler */
|
||||
void svr_process_packet() {
|
||||
|
||||
unsigned char type;
|
||||
|
||||
TRACE(("enter process_packet"));
|
||||
|
||||
type = buf_getbyte(ses.payload);
|
||||
TRACE(("process_packet: packet type = %d", type));
|
||||
|
||||
/* these packets we can receive at any time, regardless of expecting
|
||||
* other packets: */
|
||||
switch(type) {
|
||||
|
||||
case SSH_MSG_IGNORE:
|
||||
case SSH_MSG_DEBUG:
|
||||
TRACE(("received SSH_MSG_IGNORE or SSH_MSG_DEBUG"));
|
||||
goto out;
|
||||
|
||||
case SSH_MSG_UNIMPLEMENTED:
|
||||
/* debugging XXX */
|
||||
TRACE(("SSH_MSG_UNIMPLEMENTED"));
|
||||
dropbear_exit("received SSH_MSG_UNIMPLEMENTED");
|
||||
|
||||
case SSH_MSG_DISCONNECT:
|
||||
/* TODO cleanup? */
|
||||
dropbear_close("Disconnect received");
|
||||
}
|
||||
|
||||
/* Check if we should ignore this packet. Used currently only for
|
||||
* KEX code, with first_kex_packet_follows */
|
||||
if (ses.ignorenext) {
|
||||
TRACE(("Ignoring packet, type = %d", type));
|
||||
ses.ignorenext = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* check that we aren't expecting a particular packet */
|
||||
if (ses.expecting && ses.expecting != type) {
|
||||
/* TODO send disconnect? */
|
||||
dropbear_exit("unexpected packet type %d, expected %d", type,
|
||||
ses.expecting);
|
||||
}
|
||||
|
||||
/* handle the packet depending on type */
|
||||
ses.expecting = 0;
|
||||
|
||||
switch (type) {
|
||||
|
||||
case SSH_MSG_SERVICE_REQUEST:
|
||||
recv_msg_service_request();
|
||||
break;
|
||||
|
||||
case SSH_MSG_USERAUTH_REQUEST:
|
||||
recv_msg_userauth_request();
|
||||
break;
|
||||
|
||||
case SSH_MSG_KEXINIT:
|
||||
recv_msg_kexinit();
|
||||
break;
|
||||
|
||||
case SSH_MSG_KEXDH_INIT:
|
||||
recv_msg_kexdh_init();
|
||||
break;
|
||||
|
||||
case SSH_MSG_NEWKEYS:
|
||||
recv_msg_newkeys();
|
||||
break;
|
||||
|
||||
/* this is ugly, need to make a cleaner way to do it */
|
||||
case SSH_MSG_CHANNEL_DATA:
|
||||
case SSH_MSG_CHANNEL_WINDOW_ADJUST:
|
||||
case SSH_MSG_CHANNEL_REQUEST:
|
||||
case SSH_MSG_CHANNEL_OPEN:
|
||||
case SSH_MSG_CHANNEL_EOF:
|
||||
case SSH_MSG_CHANNEL_CLOSE:
|
||||
case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
|
||||
case SSH_MSG_CHANNEL_OPEN_FAILURE:
|
||||
case SSH_MSG_GLOBAL_REQUEST:
|
||||
/* these should be checked for authdone below */
|
||||
svr_process_postauth_packet(type);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* TODO this possibly should be handled */
|
||||
TRACE(("preauth unknown packet"));
|
||||
recv_unimplemented();
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
buf_free(ses.payload);
|
||||
ses.payload = NULL;
|
||||
|
||||
TRACE(("leave process_packet"));
|
||||
}
|
||||
|
||||
/* process a packet, and also check that auth has been done */
|
||||
static void svr_process_postauth_packet(unsigned int type) {
|
||||
|
||||
/* messages following here require userauth before use */
|
||||
|
||||
/* IF YOU ADD MORE PACKET TYPES, MAKE SURE THEY'RE ALSO ADDED TO THE LIST
|
||||
* IN process_packet() XXX XXX XXX */
|
||||
if (!svr_ses.authstate.authdone) {
|
||||
dropbear_exit("received message %d before userauth", type);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
|
||||
case SSH_MSG_CHANNEL_DATA:
|
||||
recv_msg_channel_data();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_WINDOW_ADJUST:
|
||||
recv_msg_channel_window_adjust();
|
||||
break;
|
||||
|
||||
#ifndef DISABLE_REMOTETCPFWD
|
||||
case SSH_MSG_GLOBAL_REQUEST:
|
||||
/* currently only used for remote tcp, so we cheat a little */
|
||||
recv_msg_global_request_remotetcp();
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SSH_MSG_CHANNEL_REQUEST:
|
||||
recv_msg_channel_request();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_OPEN:
|
||||
recv_msg_channel_open();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_EOF:
|
||||
recv_msg_channel_eof();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_CLOSE:
|
||||
recv_msg_channel_close();
|
||||
break;
|
||||
|
||||
#ifdef USE_LISTENERS /* for x11, tcp fwd etc */
|
||||
case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
|
||||
recv_msg_channel_open_confirmation();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_OPEN_FAILURE:
|
||||
recv_msg_channel_open_failure();
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
TRACE(("unknown packet()"));
|
||||
recv_unimplemented();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user