Compare commits

...

83 Commits

Author SHA1 Message Date
Matt Johnston
e903109d9f * fix comment style in options.h
* bump debian version

--HG--
extra : convert_revision : d815305b19d789fe97890c3fdedb55df2e9cf324
2005-03-07 04:25:43 +00:00
Matt Johnston
a3bb3137ac changes for 0.45
--HG--
extra : convert_revision : ced3f1d1fe81c6cc53ca2c15ac71a84d894971d8
2005-03-07 03:57:26 +00:00
Matt Johnston
2d28663f53 * don't add a 'static' prefix to binary names
--HG--
extra : convert_revision : 7d2393b48b6b8ed87d3bed5685cf598356eada8d
2005-03-02 04:13:01 +00:00
Matt Johnston
4127be0a95 * add SSH_ASKPASS support (based on patch from Paul Whittaker
* don't exit if setnonblocking() fails with "not supported by device"
  (allows redirection from /dev/null)

--HG--
extra : convert_revision : 02fb18acdb680a868b2bfbd6452b2ccdb4cdde99
2005-02-28 13:01:00 +00:00
Matt Johnston
03d78bbb31 * respect DO_HOST_LOOKUP config option
--HG--
extra : convert_revision : ab193dd162b03bdd935759fa667ff394a5e29734
2005-02-28 10:15:16 +00:00
Matt Johnston
6013d993b9 put back 'return;' on empty terminal mode strings which was erroneously
removed in 3a6c6eeefe450a64e244ee39030938ddaacb8987

--HG--
extra : convert_revision : 75ed8083a683ebdb2fceca4a856d803fdeeb60af
2005-01-19 11:41:04 +00:00
Matt Johnston
b7dbb29e68 Read "y/n" response for fingerprints from /dev/tty directly so that dbclient
will work with scp.

--HG--
extra : convert_revision : 1ec067604618a314ad36464920f08c7113d09aa3
2005-01-11 16:17:03 +00:00
Matt Johnston
37da919b7d Removed obselete (and incorrect) comment.
--HG--
extra : convert_revision : 79bdca55540f5a7e2ffbad4481668066185bf10a
2005-01-07 16:39:48 +00:00
Matt Johnston
9d4ef36e09 Version number needs munging so that comparison works correctly
--HG--
extra : convert_revision : 332396ccd4bc43741eb0bed94e5b55a04dd2af0e
2005-01-03 10:01:23 +00:00
Matt Johnston
c0ddf3df0c Forgot to increment the version number
--HG--
extra : convert_revision : fc84f73954840b0ed9b52225b4874c1aacb47c19
2005-01-03 09:33:05 +00:00
Matt Johnston
74055a3884 Make debian/rules executable
--HG--
extra : convert_revision : 99b61ecb1e074f6e384c6548aedc8186770c2318
2005-01-03 09:23:22 +00:00
Matt Johnston
8c1a429c44 Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
--HG--
extra : convert_revision : d928bc851e32be7bd429bf7504b148c0e4bf7e2f
2005-01-02 20:25:56 +00:00
Matt Johnston
b5bd8591e7 0.44 release changes
--HG--
extra : convert_revision : 47d6b5589a4eaf707ed1c3685d9ef49306af18d8
2005-01-02 17:08:27 +00:00
Matt Johnston
e6c957caaa Fix so that getnameinfo() is passed the address-specific structure size. This
lets it work on Solaris (and probably other platforms)

--HG--
extra : convert_revision : b486b773f163af8462b0ef6565ac4285a54708eb
2005-01-02 12:04:45 +00:00
Matt Johnston
6d75298284 random.c: fix missed instance of DROPBEAR_EGD_SOCKET
--HG--
extra : convert_revision : 0be7aaee2230fa65f252b2e74deee7102558ceb6
2004-12-27 16:38:44 +00:00
Matt Johnston
9d43183704 Log the IP along with auth success/fail attempts
--HG--
extra : convert_revision : 25eab43bd46e931fd4afecec49c22b9311062099
2004-12-23 17:00:15 +00:00
Matt Johnston
e7677a5e8d Rearrange preprocessor parts so that compilation with various options
disabled works OK.

--HG--
extra : convert_revision : cc92f744e34125062d052b757967e167f19d6db5
2004-12-22 15:37:50 +00:00
Matt Johnston
7dfb2bfcda loginrec.c: replaced erroneously removed function definition
--HG--
extra : convert_revision : b433b5f38ae275c058addac9897f221edd4e32f8
2004-12-20 14:46:12 +00:00
Matt Johnston
34445aa819 Cleaning out various dead wood found with -dead_strip
bignum.c: mptobytes now resides in dss.c
loginrec.c: remove lastlog code since it isn't used.
dbutil.c: removed obselete usingsyslog variable
channel.h: client channel type only defined for client compile
common-algo.c: s/rijndael/aes/

--HG--
extra : convert_revision : 411ea4e70506ecb0202376f94bcf2d330603d042
2004-12-20 14:24:57 +00:00
Matt Johnston
42c691a051 Cleaned up the random code, use /dev/random by default,
and remove the addrandom() function which wasn't used.

--HG--
extra : convert_revision : d560d214ad20001f8ef5d5494ff3c97e6184d9cc
2004-12-20 13:11:15 +00:00
Matt Johnston
8b32e8a08c includes.h: include mycrypt.h rather than mycrypt_custom.h
--HG--
extra : convert_revision : 63ea0f9a911a31bd88913afdfc31582240b0acfb
2004-12-19 16:28:08 +00:00
Matt Johnston
37ff2eaf2a configure.in: fix a status message
--HG--
extra : convert_revision : 14dde9c1d5a1f0d631336b82a9ff830b4e25a54a
2004-12-19 07:46:16 +00:00
Matt Johnston
27aa148e02 atomicio.c: one less compile warning
--HG--
extra : convert_revision : 25808b4e64822230283602dee93b85d9d4fa6507
2004-12-19 07:43:37 +00:00
Matt Johnston
8f14a1cc38 Pristine compilation works.
--HG--
extra : convert_revision : 64faed12a3a33720986786db602714dfaa4bc599
2004-12-17 06:26:55 +00:00
Matt Johnston
3e53f28f6e - Fixed a couple of compile warnings
- First public monotone import

--HG--
extra : convert_revision : 79e029a8b3adf823f0b6f7d6b1b5c4b9ab868eaa
2004-11-27 19:58:34 +00:00
Matt Johnston
96823c424d Initialise the outgoing packet queue
--HG--
extra : convert_revision : d9981dbae7bf47d3bd6d1bcf4e602e7bf682082f
2004-11-03 13:47:44 +00:00
Matt Johnston
08cb903731 -i works with scp now.
--HG--
extra : convert_revision : 0d1ed055bb2e8b8eca60cbf1cb8cab81688dbead
2004-10-17 10:35:19 +00:00
Matt Johnston
5c6e8b833e Initialise the "lastexit" variable so that we don't get session channels
terminating prematurely.

--HG--
extra : convert_revision : 5cb8d5a7c8fe405fa4d49906f66a61590ae4a087
2004-10-17 08:19:47 +00:00
Matt Johnston
028e79ddda use inst_ rather than inst, so it doesn't try to install "all".
--HG--
extra : convert_revision : 17b3eab398414e4bd5e77289bcc73f6185c4c43f
2004-09-21 12:14:20 +00:00
Matt Johnston
5ebfa4aaed strdup() variables correctly for the PAM conversation function
--HG--
branch : private-rez
extra : convert_revision : 706adc0b1c61920dc70b6b203b2033e27bc46c64
2004-09-21 11:42:03 +00:00
Matt Johnston
c2af67efd3 propagate of 82bb923d0154750ef716b66b498561f882891946 and f51a272341ee12268fe7028bc2f2bad66c603069 from branch 'matt.dbclient.work' to 'matt.dbclient.rez'
--HG--
branch : private-rez
extra : convert_revision : 440ee4177122c8a873ebf8984a90f96a9bd8a56a
2004-09-21 10:08:21 +00:00
Matt Johnston
6766dfae26 merge of cc7d47b52fc39dc6940ea8fff5b782fbd44a2f6c
and f697d6be3bdf1a59bfd78dc1239ea417d52904a7

--HG--
extra : convert_revision : b1cb6d6bba496c942d1850d0f6ca5d71c0deaf1f
2004-09-16 06:19:39 +00:00
Matt Johnston
199b67a68c Added dropbear.8 and dropbearkey.8 back in
--HG--
extra : convert_revision : dda3a93a5b9fb3338ea7fc45c45da6b76e3850f0
2004-09-14 15:26:50 +00:00
Matt Johnston
644488a5f3 put the #ifdefs back in for authpam
--HG--
extra : convert_revision : 93ad501313c213d77753d57def15f2c8cf5db8d7
2004-09-14 14:36:42 +00:00
Matt Johnston
1ace08645a Oops, PAM was on by default in options.h
--HG--
extra : convert_revision : 8f9d07675e82e64ef083bbdb833d0b2dbfe4d187
2004-09-14 13:47:10 +00:00
Matt Johnston
636b041b9b 0.44test4 probably
also bumped the channel recv window sizing

--HG--
extra : convert_revision : 2ab172def950d852426cf2c2e066c29aa50e2de9
2004-09-14 13:22:32 +00:00
Matt Johnston
a41f9dc036 calloc memory rather than mallocing it - can't hurt too much, and is
probably a bit safer

--HG--
extra : convert_revision : bbd2edbb1410ea8fd7bee089f60154f76d2a0ab7
2004-09-14 13:18:16 +00:00
Matt Johnston
448a05ae2c propagate of f51a272341ee12268fe7028bc2f2bad66c603069 and ab35ee4292ea910d4871c3609d6100fe34300720 from branch 'matt.dbclient.rez' to 'matt.dbclient.work'
--HG--
branch : private-rez
extra : convert_revision : 23e9cf6a5b5e33f172b7b8505c0731ce9c0b93df
2004-09-14 13:09:29 +00:00
Matt Johnston
099c9a3232 PAM improvements
--HG--
branch : private-rez
extra : convert_revision : c8f9300c5d598fe6003fcf19c831f5982620ec98
2004-09-14 12:51:16 +00:00
Matt Johnston
2575e227a5 Don't need to burn the payload buffer since process-packet.c does it
--HG--
extra : convert_revision : 12619953d6d88a1b8b0afc4dd5f6e0e2f8b324a0
2004-09-12 05:53:48 +00:00
Matt Johnston
fa26b59b0c propagate of 08347df3bca787bd3621602fe2b466c85c9dc3e2 and 717950f4061f1123659ee87c7c168805af920ab7 from branch 'matt.dbclient.rez' to 'matt.dbclient.authpam'
--HG--
branch : private-rez
extra : convert_revision : 555c429bf4e557ea5fd0af9db3987166d8217d8b
2004-09-12 05:52:36 +00:00
Matt Johnston
c23ffe4bc1 propagate of 717950f4061f1123659ee87c7c168805af920ab7 and 839f98f136788cc1466e4641bf796f96040a085d from branch 'matt.dbclient.authpam' to 'matt.dbclient.rez'
--HG--
branch : private-rez
extra : convert_revision : d58a4ff37f9784978a07df6a944f7dbae8196f6d
2004-09-12 04:56:50 +00:00
Matt Johnston
7ed5870ed9 Read the last line of a file without a finishing '\n' correctly
--HG--
branch : private-rez
extra : convert_revision : f64591461a40d54a2bd2e12493253ec76eab1ff2
2004-09-02 18:36:11 +00:00
Matt Johnston
8559be015a Check for non-matching algos properly
--HG--
extra : convert_revision : 20ab9edd3f3f714ecc4630bb97912185d88aa376
2004-09-02 15:24:17 +00:00
Matt Johnston
cb0657bdf3 WCOREDUMP finally
--HG--
extra : convert_revision : 12aa4fdb328febedfd3fd50d1dae783d8a0dab14
2004-08-31 08:52:41 +00:00
Matt Johnston
15fb479e94 Leak found with MallocDebug - it's kinda useful
--HG--
extra : convert_revision : 43fdd8b10616b9d5e11f677d16763c7a876a5ec3
2004-08-30 15:02:45 +00:00
Matt Johnston
0378cffafc Load the hostkeys for inetd too - oops
--HG--
extra : convert_revision : 815f75b9a450396fd5a9cca286803a91f0edc1a9
2004-08-30 13:26:42 +00:00
Matt Johnston
51fb224ef8 options.h
--HG--
extra : convert_revision : 10b3693ebf2d3f713a16aedf214e26bc8a04b9e6
2004-08-27 17:01:18 +00:00
Matt Johnston
a4516b4261 merge of 00b67a11e33c3ed390556805ed6d1078528bee70
and a3e68842a71eaba22c23468ff95fded952acb973

--HG--
extra : convert_revision : 51e1bd8be97b4591773adef1b4955f60100f09dd
2004-09-04 14:19:19 +00:00
Matt Johnston
a952d23781 Add help text that a symlink to "ssh" works
--HG--
extra : convert_revision : afa6de30e7e296599bde7f5f8082da551c7a997a
2004-08-27 15:20:47 +00:00
Matt Johnston
69282617fd merge of 50be59810e462f9f44f55e421227d6aa0b31982b
and 69b007796063cb5f042be7cca2d479e90db869c3

--HG--
extra : convert_revision : 5d0dfaa8c0ee6c728a3b4f0f0855199ba729db83
2004-08-27 14:39:01 +00:00
Matt Johnston
51a74b4799 - added circular buffering for channels
- added stderr support for the client
- cleaned up a bunch of "unused" warnings, duplicated header definitions
- added exit-status support for the client

--HG--
extra : convert_revision : 5bdf806d8b440c87f7235414662f4189195618f4
2004-08-26 13:16:40 +00:00
Matt Johnston
2dcd6b22d9 Nasty.
--HG--
extra : convert_revision : e1229cd01c3007206d2937ea390ad4966c289a5a
2004-08-24 18:12:18 +00:00
Matt Johnston
857dfdeb9e Fix if the first write fails
--HG--
extra : convert_revision : 5a12aa1aa66c9cfd5d0097acea235cd3cd7658ab
2004-08-24 07:22:36 +00:00
Matt Johnston
70b7c24cb0 Fix for "-l" scp option
--HG--
extra : convert_revision : 700ba4c9a06b892fa9742bc8f3b6fe73a32f94f7
2004-08-24 05:05:48 +00:00
Matt Johnston
e089ee4d85 Default port is now set as a string
--HG--
extra : convert_revision : c57157250f3c9339a1401b802b6c6e58748f4097
2004-08-24 04:12:08 +00:00
Matt Johnston
d254e0191d Allow leading lines before the ident banner when connecting
--HG--
extra : convert_revision : ae4b1bdb29e60927c032674800f0258fc5966807
2004-08-24 04:10:37 +00:00
Matt Johnston
0ab18bd14c merge of 5c31199418631253a3d311fe3b1ff87351e1c9ca
and c84edf4a78416c5c3172871d3c74d7fd64afab2d

--HG--
extra : convert_revision : 37d06b8560f822a1636a17e8f4739f6ab68f20ce
2004-08-24 04:07:41 +00:00
Matt Johnston
aaac206345 Change the way we load keys/ports so we don't print error messages into our
socket.

--HG--
extra : convert_revision : b830e790bd08933685502f36d8e7838f143f2f2f
2004-08-23 05:27:34 +00:00
Matt Johnston
f3761a3eda oops, the fcntl() was commented out
--HG--
extra : convert_revision : 83838fc3cc5ef5a89614c05222cab621ede5cd4e
2004-08-23 02:46:24 +00:00
Matt Johnston
aba8a3e2d4 Move the revert-to-non-blocking-stdin code to cli-session so it
always gets hit.

--HG--
extra : convert_revision : 3eb50d87fa6439d336b2238926fbed5066302d30
2004-08-22 09:23:59 +00:00
Matt Johnston
545ce7d8bf Fix for printing out things with inetd mode when we have DEBUG_TRACE
compiled in but no -v: we don't want to print messages out since it
goes to the socket (and over the wire - bad).

--HG--
extra : convert_revision : f18a0cff74b01ad04543718db6aac12857851b3c
2004-08-22 09:23:11 +00:00
Matt Johnston
3840a482c7 Remove obselete documentation
--HG--
extra : convert_revision : c4ca3b12cdef1ae3b4ce36e36b4a2f4a77b167f6
2004-08-19 15:27:47 +00:00
Matt Johnston
4dd70c433e Mention the race condition between setting the childpid entry, and
the child exiting.

--HG--
extra : convert_revision : 0acd2d97675d6a45fa1664790b4b9c891461de10
2004-08-18 16:42:08 +00:00
Matt Johnston
abf66aa7a1 Don't try to remove non-eixtant listeners
--HG--
extra : convert_revision : 87058f74626cd6795ecd495cc22779618c70eaa8
2004-08-18 16:31:05 +00:00
Matt Johnston
1e94425015 DEBUG_TRACE now only triggers with -v on the cmdline
--HG--
extra : convert_revision : 91ef4ca657cd116dba148a50a90c8bcc5d206d4b
2004-08-18 15:48:25 +00:00
Matt Johnston
a69e355a06 Don't leave the stdin FD non-blocking on exit - busybox doesn't like it.
--HG--
extra : convert_revision : 9c2b10bf10f9d38f62490346b53268a07afa0c3a
2004-08-18 12:42:21 +00:00
Matt Johnston
e17d27d91d Auth doesn't timeout after 5 minutes.
--HG--
extra : convert_revision : d7df458117bc7af1d7c748c52e06cf8ca03113c1
2004-08-18 09:14:43 +00:00
Matt Johnston
cc1860bc86 Stupid DSS hostkey bug fixed.
--HG--
extra : convert_revision : f8c94ac62bf0766d4b468c3ef88db8a11c5f75f4
2004-08-18 09:14:30 +00:00
Matt Johnston
f3c8bb2bce merge of 00b67a11e33c3ed390556805ed6d1078528bee70
and 42c7bdf484b16e279a0f68604a4346d8fa5ed70c

--HG--
extra : convert_revision : edf8bd9174de26de093d842aa4bd9cb43c2e257b
2004-09-04 14:19:17 +00:00
Matt Johnston
ee23b01f0b Some small fixes for unused vars, and old messages
--HG--
extra : convert_revision : 83d9a25ee973ab65fa64dcf8595838b160c21663
2004-08-17 11:14:13 +00:00
Matt Johnston
3cacc54b78 Small fixes
--HG--
extra : convert_revision : 7f568ec9a453957b16efab56c215a4914f0cebf3
2004-08-17 10:40:31 +00:00
Matt Johnston
4657ed1446 #ifdef for PENDIN
--HG--
extra : convert_revision : a9c59907d9b02918f78f5d0f9e7bc67be0b7ca6f
2004-08-17 10:29:04 +00:00
Matt Johnston
4a52217ed4 default initialisers for mp_ints
--HG--
extra : convert_revision : af69bacb50a31523e383e8f73844d04681f9e394
2004-08-17 10:20:20 +00:00
Matt Johnston
954a8dce0f fix for AIX not having WCOREDUMP
--HG--
extra : convert_revision : 9a728aa6db6d1105267c377fa3d5448ee5f5a4ca
2004-08-17 09:56:23 +00:00
Matt Johnston
6ec8183750 do the symlinks for multi-binary compiles
--HG--
extra : convert_revision : 1a0ab43c58435f03b261ef322d24fbb5c91e8abd
2004-08-17 04:35:01 +00:00
Matt Johnston
eb1f647c9c dbclient works as "ssh" too
--HG--
extra : convert_revision : 4bf3c662e114ad16c54afdf923f2852e511f77eb
2004-08-16 14:53:49 +00:00
Matt Johnston
029ae35058 create known_hosts properly
--HG--
extra : convert_revision : 3f808121bb4c3b4e0ce32db12525c63d692f1dbd
2004-08-16 14:46:13 +00:00
Matt Johnston
fdfc95df8b - don't crash when trying to add to known_hosts if it doesn't exist
- comments

--HG--
extra : convert_revision : ffafd48c7494fee17a98d901e30c3372e1a092e9
2004-08-16 08:59:11 +00:00
Matt Johnston
5a053fb6fc Just a test for merging heads
--HG--
extra : convert_revision : ede585c846c166007394decf3d57c24c42682160
2004-08-09 08:08:42 +00:00
Matt Johnston
41f5e21044 merge of 3b1edf7489e1de452e30aaaec37d647db44e4328
and 6cdb6b2c0e0e0a600eeb5975e499c9303fe2d4d4

--HG--
extra : convert_revision : 6bf41e419b773e153b574b15005ab1e498643400
2004-08-09 03:21:20 +00:00
Matt Johnston
3238bed9c9 svr-authpam code merged and works. needs tidying a log
--HG--
branch : authpam
extra : convert_revision : abeb2807b88fbd8b95d92b760a209a0816cbaea9
2004-08-08 16:57:37 +00:00
Matt Johnston
4936c9a3f3 Remove unused printbuf which prevented large DSS keys from being generated.
--HG--
extra : convert_revision : 6971cb6630c289a03a9f28c36c6797c7744ff9a1
2004-08-06 16:37:59 +00:00
83 changed files with 2209 additions and 1230 deletions

127
CHANGES
View File

@@ -1,4 +1,129 @@
0.44test1 - Sun Aug 16 2004 17:43:54 +0800
0.45 - Mon March 7 2005
- Makefile no longer appends 'static' to statically linked binaries
- Add optional SSH_ASKPASS support to the client
- Respect HOST_LOOKUP option
- Fix accidentally removed "return;" statement which was removed in 0.44
(causing clients which sent an empty terminal-modes string to fail to
connect - including pssh, ssh.com, danger hiptop). (patches
independently from Paul Fox, David Horwitt and Sven-Ola Tuecke)
- Read "y/n" response for fingerprints from /dev/tty directly so that dbclient
will work with scp.
0.44 - Mon Jan 3 2005
- SECURITY: Fix for PAM auth so that usernames are logged and conversation
function responses are allocated correctly - all 0.44test4 users with PAM
compiled in (not default) are advised to upgrade.
- Fix calls to getnameinfo() for compatibility with Solaris
- Pristine compilation works (run 'configure' from a fresh dir and make it
there)
- Fixes for compiling with most options disabled.
- Upgraded to LibTomCrypt 0.99 and LibTomMath 0.32
- Make sure that zeroing out of values in LTM and LTC won't get optimised away
- Removed unused functions from loginrec.c
- /dev/random is now the default entropy source rather than /dev/urandom
- Logging of IPs in auth success/failure messages for improved greppability
- Fix dbclient so that "scp -i keyfile" works. (It can handle "-ikeyfile
properly)
- Avoid a race in server shell-handling code which prevents the exit-code
from being returned to the client in some circumstances.
- Makefile modified so that install target works correctly (doesn't try
to install "all" binary) - patch from Juergen Daubert
- Various minor fixes and compile warnings.
0.44test4 - Tue Sept 14 2004 21:15:54 +0800
- Fix inetd mode so it actually loads the hostkeys (oops)
- Changed DROPBEAR_DEFPORT properly everywhere
- Fix a small memory leak in the auth code
- WCOREDUMP is only used on systems which support it (ie not cygwin or AIX)
- Check (and fail for) cases when we can't negotiate algorithms with the
remote side successfully (rather than bombing out ungracefully)
- Handle authorized_keys files without a terminating newline
- Fiddle the channel receive window size for possibly better performance
- Added in the PAM authentication code (finally! thanks to Martin Carlsson)
0.44test3 - Fri Aug 27 22:20:54 +0800
- Fixed a bunch of warnings.
- scp works correctly when passed a username (fix for the dbclient program
itself as well, "-lmatt" works as well as "-l matt").
- Remove unrequired debian files
- Exit with the remote process's return code for dbclient
- Display stderr messages from the server in the client
- Add circular buffering to the channel code. This should dramatically reduce
the amount of backtraffic sent in response to traffic incoming to the
Dropbear end - improves high-latency performance (ie dialup).
- Various other related channel-handling fixups.
- Allow leading lines in the banner when connecting to servers
- Fixed printing out errors onto the network socket with stderr (for inetd
mode when using xinetd)
- Remove obselete documentation
- Fix a null-pointer exception when trying to free non-existant listeners
at cleanup.
- DEBUG_TRACE now only works if you add "-v" to the program commandline
- Don't leave stdin non-blocking on exit - this caused the parent shell
of dbclient to close when dbclient exited, for some shells in BusyBox
- Server connections no longer timeout after 5 minutes
- Fixed stupid DSS hostkey typo (server couldn't load host keys)
0.44test2 - Tues Aug 17 2004 17:43:54 +0800
- Fix up dropbearmulti targets in the Makefile - symlinks are now created
- Compile fake-rfc2553 even with dropbearconvert/dropbearkey - this
allows them to work on platforms without a native getaddrinfo()
- Create ~/.ssh/known_hosts properly if it doesn't exist
- Fix basename() function prototype
- Backport some local changes (more #ifdefs for termcodes.c, a fix for missing
defines on AIX).
- Let dbclient be run as "ssh"
- Initialise mp_ints by default
0.44test1 - Sun Aug 16 2005 17:43:54 +0800
- TESTING RELEASE - this is the first public release of the client codebase,
so there are sure to be bugs to be found. In addition, if you're just using

View File

@@ -1,13 +1,13 @@
# This Makefile is for Dropbear SSH Server and Client
# @configure_input@
# invocation:
# make PROGRAMS="dropbear dbclient scp" MULTI=1 STATIC=1 SCPPROGRESS=1
#
# to make a single multiple statically linked binary "staticdropbearmulti",
# which includes dropbear, scp and dbclient functionality, and includes the
# progress-bar functionality in scp. Hopefully that seems intuitive.
# This makefile is quite evil.
# to make a multiple-program statically linked binary "staticdropbearmulti".
# This example will include dropbear, scp, dropbearkey, dropbearconvert, and
# dbclient functionality, and includes the progress-bar functionality in scp.
# Hopefully that seems intuitive.
ifndef PROGRAMS
PROGRAMS=dropbear dbclient dropbearkey dropbearconvert
@@ -20,21 +20,21 @@ COMMONOBJS=dbutil.o buffer.o \
dss.o bignum.o \
signkey.o rsa.o random.o \
queue.o \
atomicio.o compat.o
atomicio.o compat.o fake-rfc2553.o
SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \
svr-authpasswd.o svr-authpubkey.o svr-session.o svr-service.o \
svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\
svr-tcpfwd.o
svr-tcpfwd.o svr-authpam.o
CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
cli-session.o cli-service.o cli-runopts.o cli-chansession.o \
cli-authpubkey.o cli-tcpfwd.o
cli-authpubkey.o cli-tcpfwd.o cli-channel.o
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
common-channel.o common-chansession.o termcodes.o loginrec.o \
tcp-accept.o listener.o process-packet.o \
common-runopts.o fake-rfc2553.o
common-runopts.o circbuffer.o
KEYOBJS=dropbearkey.o gendss.o genrsa.o
@@ -55,6 +55,9 @@ dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
scpobjs=$(SCPOBJS)
VPATH=@srcdir@
srcdir=@srcdir@
prefix=@prefix@
exec_prefix=${prefix}
bindir=${exec_prefix}/bin
@@ -66,7 +69,7 @@ AR=@AR@
RANLIB=@RANLIB@
STRIP=@STRIP@
INSTALL=@INSTALL@
CFLAGS=-Ilibtomcrypt @CFLAGS@
CFLAGS=-I. -I$(srcdir)/libtomcrypt @CFLAGS@
LIBS=$(LTC) $(LTM) @LIBS@
LDFLAGS=@LDFLAGS@
@@ -90,9 +93,6 @@ export RANLIB AR STRIP
ifeq ($(STATIC), 1)
LDFLAGS+=-static
SPREFIX=static
else
SPREFIX=
endif
ifeq ($(MULTI), 1)
@@ -113,27 +113,38 @@ endif
all: $(TARGETS)
strip: $(TARGETS)
$(STRIP) $(addsuffix $(EXEEXT), $(addprefix $(SPREFIX), $(TARGETS)))
$(STRIP) $(addsuffix $(EXEEXT), $(TARGETS))
install: $(addprefix install, $(TARGETS))
install: $(addprefix inst_, $(TARGETS))
installdropbearmulti: insdbmulti $(addprefix insmulti, $(PROGRAMS))
insdbmulti: dropbearmulti
$(INSTALL) -d -m 755 $(DESTDIR)$(bindir)
$(INSTALL) -m 755 dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)
-chown root $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT)
-chgrp 0 $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT)
insmultidropbear: dropbearmulti
-rm -f $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
-ln -s $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
insmulti%: dropbearmulti
-rm -f $(DESTDIR)$(bindir)/$*$(EXEEXT)
-ln -s $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT)
# dropbear should go in sbin, so it needs a seperate rule
installdropbear: dropbear
inst_dropbear: dropbear
$(INSTALL) -d -m 755 $(DESTDIR)$(sbindir)
$(INSTALL) -m 755 $(SPREFIX)dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
-chown root $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT)
-chgrp 0 $(DESTDIR)$(sbindir)/$(SPREFIX)dropbear$(EXEEXT)
$(INSTALL) -m 755 dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
-chown root $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
-chgrp 0 $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
install%: $*
inst_%: $*
$(INSTALL) -d -m 755 $(DESTDIR)$(bindir)
$(INSTALL) -m 755 $(SPREFIX)$*$(EXEEXT) $(DESTDIR)$(bindir)
-chown root $(DESTDIR)$(sbindir)/$(SPREFIX)$*$(EXEEXT)
-chgrp 0 $(DESTDIR)$(sbindir)/$(SPREFIX)$*$(EXEEXT)
ifeq ($(MULTI), 1)
@echo
@echo "You must manually create links for $*"
endif
$(INSTALL) -m 755 $*$(EXEEXT) $(DESTDIR)$(bindir)
-chown root $(DESTDIR)$(bindir)/$*$(EXEEXT)
-chgrp 0 $(DESTDIR)$(bindir)/$*$(EXEEXT)
# for some reason the rule further down doesn't like $($@objs) as a prereq.
@@ -144,11 +155,11 @@ dropbearconvert: $(dropbearconvertobjs)
dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LTC) $(LTM) \
Makefile
$(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $($@objs) $(LIBS)
$(LD) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBS)
# scp doesn't use the libs so is special.
scp: $(SCPOBJS) $(HEADERS) Makefile
$(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $(SCPOBJS)
$(LD) $(LDFLAGS) -o $@$(EXEEXT) $(SCPOBJS)
# multi-binary compilation.
@@ -158,11 +169,16 @@ ifeq ($(MULTI),1)
CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
endif
dropbearmulti: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) Makefile
$(LD) $(LDFLAGS) -o $(SPREFIX)$@$(EXEEXT) $(MULTIOBJS) $(LIBS)
@echo
@echo "You should now create symlinks to the programs you have included"
@echo "ie 'ln -s dropbearmulti dropbear'"
dropbearmulti: multilink
multibinary: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) Makefile
$(LD) $(LDFLAGS) -o dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS)
multilink: multibinary $(addprefix link, $(PROGRAMS))
link%:
-rm -f $*$(EXEEXT)
-ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT)
$(LTC): options.h
cd libtomcrypt && $(MAKE) clean && $(MAKE)
@@ -179,11 +195,11 @@ ltm-clean:
sizes: dropbear
objdump -t dropbear|grep ".text"|cut -d "." -f 2|sort -rn
clean: ltc-clean ltm-clean
-rm -f dropbear dbclient dropbearkey dropbearconvert scp scp-progress
-rm -f staticdropbear staticdropbearkey staticdropbearconvert staticscp
-rm -f dropbearmulti staticdropbearmulti
-rm -f *.o *.da *.bb *.bbg *.prof
clean: ltc-clean ltm-clean thisclean
thisclean:
-rm -f dropbear dbclient dropbearkey dropbearconvert scp scp-progress \
dropbearmulti *.o *.da *.bb *.bbg *.prof
distclean: clean tidy
-rm -f config.h

19
README
View File

@@ -17,7 +17,7 @@ matt@ucc.asn.au
In the absence of detailed documentation, some notes follow:
============================================================================
Public key auth:
Server public key auth:
You can use ~/.ssh/authorized_keys in the same way as with OpenSSH, just put
the key entries in that file. They should be of the form:
@@ -32,6 +32,21 @@ OpenSSH sshd manpage, and will not allow a login for these keys.
============================================================================
Client public key auth:
Dropbear can do public key auth as a client, but you will have to convert
OpenSSH style keys to Dropbear format, or use dropbearkey to create them.
If you have an OpenSSH-style private key ~/.ssh/id_rsa, you need to do:
dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_rsa.db
dbclient -i ~/.ssh/id_rsa.db <hostname>
Currently encrypted keys aren't supported, neither is agent forwarding. At some
stage both hopefully will be.
============================================================================
If you want to get the public-key portion of a Dropbear private key, look at
dropbearkey's '-y' option.
@@ -54,6 +69,6 @@ pty, and you cannot login as any user other than that running the daemon
The Dropbear distribution includes a standalone version of OpenSSH's scp
program. You can compile it with "make scp", you may want to change the path
of the ssh binary, specified near the top of the scp.c file. By default
of the ssh binary, specified by _PATH_SSH_PROGRAM in options.h . By default
the progress meter isn't compiled in to save space, you can enable it by
adding 'SCPPROGRESS=1' to the make commandline.

39
SMALL
View File

@@ -1,25 +1,36 @@
Tips for a small system:
The following are set in options.h
If you only want server functionality (for example), compile with
make PROGRAMS=dropbear
rather than just
make dropbear
so that client functionality in shared portions of Dropbear won't be included.
The same applies if you are compiling just a client.
- You can safely disable blowfish and twofish ciphers, and MD5 hmac, without
affecting interoperability
---
- If you're compiling statically, you can turn off host lookups
The following are set in options.h:
- You can disable either password or public-key authentication, though note
that the IETF draft states that pubkey authentication is required.
- You can safely disable blowfish and twofish ciphers, and MD5 hmac, without
affecting interoperability
- Similarly with DSS and RSA, you can disable one of these if you know that
all clients will be able to support a particular one. The IETF draft
states that DSS is required, however you may prefer to use RSA.
DON'T disable either of these on systems where you aren't 100% sure about
who will be connecting and what clients they will be using.
- If you're compiling statically, you can turn off host lookups
- Disabling the MOTD code and SFTP-SERVER may save a small amount of codesize
- You can disable either password or public-key authentication, though note
that the IETF draft states that pubkey authentication is required.
- You can disable x11, tcp and agent forwarding as desired. None of these are
essential, although agent-forwarding is often useful even on firewall boxes.
- Similarly with DSS and RSA, you can disable one of these if you know that
all clients will be able to support a particular one. The IETF draft
states that DSS is required, however you may prefer to use RSA.
DON'T disable either of these on systems where you aren't 100% sure about
who will be connecting and what clients they will be using.
- Disabling the MOTD code and SFTP-SERVER may save a small amount of codesize
- You can disable x11, tcp and agent forwarding as desired. None of these are
essential, although agent-forwarding is often useful even on firewall boxes.
---
If you are compiling statically, you may want to disable zlib, as it will use
a few tens of kB of binary-size (./configure --disable-zlib).

7
TODO
View File

@@ -8,7 +8,7 @@ Things which might need doing:
- fix agent fwd problems
- improve channel window adjustment algorithm (circular buffering)
- handle /etc/environment in AIX
- check that there aren't timing issues with valid/invalid user authentication
feedback.
@@ -20,10 +20,11 @@ Things which might need doing:
- CTR mode, SSH_MSG_IGNORE sending to improve CBC security
- DH Group Exchange possibly, or just add group14 (whatever it's called today)
- Use m_burn for clearing sensitive items in LTM/LTC
- fix scp.c for IRIX
- Be able to use OpenSSH keys for the client? or at least have some form of
encrypted keys.
- Client agent forwarding
- Handle restrictions in ~/.ssh/authorized_keys ?

View File

@@ -1,5 +1,5 @@
/*
* Copied from OpenSSH 3.6.1p2, required for loginrec.c
* Copied from OpenSSH 3.6.1p2.
*
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved.
@@ -25,8 +25,6 @@
* 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"
@@ -42,7 +40,8 @@ atomicio(f, fd, _s, n)
size_t n;
{
char *s = _s;
ssize_t res, pos = 0;
ssize_t res;
size_t pos = 0;
while (n > pos) {
res = (f) (fd, s + pos, n - pos);

1
auth.h
View File

@@ -36,6 +36,7 @@ void send_msg_userauth_failure(int partial, int incrfail);
void send_msg_userauth_success();
void svr_auth_password();
void svr_auth_pubkey();
void svr_auth_pam();
/* Client functions */
void recv_msg_userauth_failure();

View File

@@ -52,25 +52,6 @@ void m_mp_init_multi(mp_int *mp, ...)
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) {

View File

@@ -29,7 +29,6 @@
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);

View File

@@ -1,5 +1,5 @@
/*
* Dropbear - a SSH2 server
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
@@ -258,7 +258,7 @@ void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
void buf_putmpint(buffer* buf, mp_int * mp) {
unsigned int len, pad = 0;
TRACE(("enter buf_putmpint"));
TRACE(("enter buf_putmpint"))
assert(mp != NULL);
@@ -294,7 +294,7 @@ void buf_putmpint(buffer* buf, mp_int * mp) {
buf_incrwritepos(buf, len-pad);
}
TRACE(("leave buf_putmpint"));
TRACE(("leave buf_putmpint"))
}
/* Retrieve an mp_int from the buffer.

View File

@@ -27,6 +27,7 @@
#include "includes.h"
#include "buffer.h"
#include "circbuffer.h"
/* channel->type values */
#define CHANNEL_ID_NONE 0
@@ -44,14 +45,15 @@
/* Not a real type */
#define SSH_OPEN_IN_PROGRESS 99
#define MAX_CHANNELS 60 /* simple mem restriction, includes each tcp/x11
#define MAX_CHANNELS 100 /* simple mem restriction, includes each tcp/x11
connection, so can't be _too_ small */
#define CHAN_EXTEND_SIZE 3 /* how many extra slots to add when we need more */
#define RECV_MAXWINDOW 6000 /* tweak */
#define RECV_MAXPACKET 1400 /* tweak */
#define RECV_MINWINDOW 19000 /* when we get below this, we send a windowadjust */
#define RECV_MAXWINDOW 8000 /* tweak */
#define RECV_WINDOWEXTEND 1000 /* We send a "window extend" every
RECV_WINDOWEXTEND bytes */
#define RECV_MAXPACKET RECV_MAXWINDOW /* tweak */
struct ChanType;
@@ -60,15 +62,16 @@ struct Channel {
unsigned int index; /* the local channel index */
unsigned int remotechan;
unsigned int recvwindow, transwindow;
unsigned int recvdonelen;
unsigned int recvmaxpacket, transmaxpacket;
void* typedata; /* a pointer to type specific data */
int infd; /* stdin for the program, we write to this */
int outfd; /* stdout for the program, we read from this */
int errfd; /* stdout for a program. This doesn't really fit here,
but makes the code a lot tidyer without being too bad. This
is -1 for channels which don't requre it. Currently only
a 'session' without a pty will use it */
buffer *writebuf; /* data for the program */
int infd; /* data to send over the wire */
int outfd; /* data for consumption, what was in writebuf */
int errfd; /* used like infd or errfd, depending if it's client or server.
Doesn't exactly belong here, but is cleaner here */
circbuffer *writebuf; /* data from the wire, for local consumption */
circbuffer *extrabuf; /* extended-data for the program - used like writebuf
but for stderr */
int sentclosed, recvclosed;
@@ -97,6 +100,7 @@ void chaninitialise();
void chancleanup();
void setchannelfds(fd_set *readfd, fd_set *writefd);
void channelio(fd_set *readfd, fd_set *writefd);
struct Channel* getchannel(unsigned int chan);
struct Channel* newchannel(unsigned int remotechan,
const struct ChanType *type,
unsigned int transwindow, unsigned int transmaxpacket);
@@ -106,11 +110,19 @@ void recv_msg_channel_request();
void send_msg_channel_failure(struct Channel *channel);
void send_msg_channel_success(struct Channel *channel);
void recv_msg_channel_data();
void recv_msg_channel_extended_data();
void recv_msg_channel_window_adjust();
void recv_msg_channel_close();
void recv_msg_channel_eof();
#ifdef USING_LISTENERS
void common_recv_msg_channel_data(struct Channel *channel, int fd,
circbuffer * buf);
#ifdef DROPBEAR_CLIENT
const struct ChanType clichansess;
#endif
#if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT)
int send_msg_channel_open_init(int fd, const struct ChanType *type);
void recv_msg_channel_open_confirmation();
void recv_msg_channel_open_failure();

View File

@@ -29,6 +29,14 @@
#include "channel.h"
#include "listener.h"
struct exitinfo {
int exitpid; /* -1 if not exited */
int exitstatus;
int exitsignal;
int exitcore;
};
struct ChanSess {
unsigned char * cmd; /* command to exec */
@@ -41,10 +49,7 @@ struct ChanSess {
unsigned char * term;
/* exit details */
int exited;
int exitstatus;
int exitsignal;
unsigned char exitcore;
struct exitinfo exit;
#ifndef DISABLE_X11FWD
struct Listener * x11listener;
@@ -68,11 +73,6 @@ struct ChildPid {
};
void chansessionrequest(struct Channel * channel);
void send_msg_chansess_exitstatus(struct Channel * channel,
struct ChanSess * chansess);
void send_msg_chansess_exitsignal(struct Channel * channel,
struct ChanSess * chansess);
void addnewvar(const char* param, const char* var);
void cli_send_chansess_request();

138
circbuffer.c Normal file
View File

@@ -0,0 +1,138 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002-2004 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "dbutil.h"
#include "circbuffer.h"
#define MAX_CBUF_SIZE 100000000
circbuffer * cbuf_new(unsigned int size) {
circbuffer *cbuf = NULL;
if (size > MAX_CBUF_SIZE) {
dropbear_exit("bad cbuf size");
}
cbuf = (circbuffer*)m_malloc(sizeof(circbuffer));
cbuf->data = (unsigned char*)m_malloc(size);
cbuf->used = 0;
cbuf->readpos = 0;
cbuf->writepos = 0;
cbuf->size = size;
return cbuf;
}
void cbuf_free(circbuffer * cbuf) {
m_free(cbuf->data);
m_free(cbuf);
}
unsigned int cbuf_getused(circbuffer * cbuf) {
return cbuf->used;
}
unsigned int cbuf_getavail(circbuffer * cbuf) {
return cbuf->size - cbuf->used;
}
unsigned int cbuf_readlen(circbuffer *cbuf) {
assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
if (cbuf->used == 0) {
TRACE(("cbuf_readlen: unused buffer"))
return 0;
}
if (cbuf->readpos < cbuf->writepos) {
return cbuf->writepos - cbuf->readpos;
}
return cbuf->size - cbuf->readpos;
}
unsigned int cbuf_writelen(circbuffer *cbuf) {
assert(cbuf->used <= cbuf->size);
assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
if (cbuf->used == cbuf->size) {
TRACE(("cbuf_writelen: full buffer"))
return 0; /* full */
}
if (cbuf->writepos < cbuf->readpos) {
return cbuf->readpos - cbuf->writepos;
}
return cbuf->size - cbuf->writepos;
}
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_readlen(cbuf)) {
dropbear_exit("bad cbuf read");
}
return &cbuf->data[cbuf->readpos];
}
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_writelen(cbuf)) {
dropbear_exit("bad cbuf write");
}
return &cbuf->data[cbuf->writepos];
}
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_writelen(cbuf)) {
dropbear_exit("bad cbuf write");
}
cbuf->used += len;
assert(cbuf->used <= cbuf->size);
cbuf->writepos = (cbuf->writepos + len) % cbuf->size;
}
void cbuf_incrread(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_readlen(cbuf)) {
dropbear_exit("bad cbuf read");
}
assert(cbuf->used >= len);
cbuf->used -= len;
cbuf->readpos = (cbuf->readpos + len) % cbuf->size;
}

50
circbuffer.h Normal file
View File

@@ -0,0 +1,50 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002-2004 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _CIRCBUFFER_H_
#define _CIRCBUFFER_H_
struct circbuf {
unsigned int size;
unsigned int readpos;
unsigned int writepos;
unsigned int used;
unsigned char* data;
};
typedef struct circbuf circbuffer;
circbuffer * cbuf_new(unsigned int size);
void cbuf_free(circbuffer * cbuf);
unsigned int cbuf_getused(circbuffer * cbuf); /* how much data stored */
unsigned int cbuf_getavail(circbuffer * cbuf); /* how much we can write */
unsigned int cbuf_readlen(circbuffer *cbuf); /* max linear read len */
unsigned int cbuf_writelen(circbuffer *cbuf); /* max linear write len */
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len);
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len);
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len);
void cbuf_incrread(circbuffer *cbuf, unsigned int len);
#endif

View File

@@ -46,7 +46,7 @@ algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
algolist = buf_getstring(buf, &len);
TRACE(("cli_buf_match_algo: %s", algolist));
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 */
}

View File

@@ -42,7 +42,7 @@ void cli_authinitialise() {
/* Send a "none" auth request to get available methods */
void cli_auth_getmethods() {
TRACE(("enter cli_auth_getmethods"));
TRACE(("enter cli_auth_getmethods"))
CHECKCLEARTOWRITE();
@@ -54,7 +54,7 @@ void cli_auth_getmethods() {
buf_putstring(ses.writepayload, "none", 4); /* 'none' method */
encrypt_packet();
TRACE(("leave cli_auth_getmethods"));
TRACE(("leave cli_auth_getmethods"))
}
@@ -64,9 +64,9 @@ void recv_msg_userauth_banner() {
unsigned int bannerlen;
unsigned int i, linecount;
TRACE(("enter recv_msg_userauth_banner"));
TRACE(("enter recv_msg_userauth_banner"))
if (ses.authstate.authdone) {
TRACE(("leave recv_msg_userauth_banner: banner after auth done"));
TRACE(("leave recv_msg_userauth_banner: banner after auth done"))
return;
}
@@ -74,7 +74,7 @@ void recv_msg_userauth_banner() {
buf_eatstring(ses.payload); /* The language string */
if (bannerlen > MAX_BANNER_SIZE) {
TRACE(("recv_msg_userauth_banner: bannerlen too long: %d", bannerlen));
TRACE(("recv_msg_userauth_banner: bannerlen too long: %d", bannerlen))
goto out;
}
@@ -96,7 +96,7 @@ void recv_msg_userauth_banner() {
out:
m_free(banner);
TRACE(("leave recv_msg_userauth_banner"));
TRACE(("leave recv_msg_userauth_banner"))
}
@@ -108,12 +108,12 @@ void recv_msg_userauth_failure() {
unsigned int partial = 0;
unsigned int i = 0;
TRACE(("<- MSG_USERAUTH_FAILURE"));
TRACE(("enter recv_msg_userauth_failure"));
TRACE(("<- MSG_USERAUTH_FAILURE"))
TRACE(("enter recv_msg_userauth_failure"))
if (cli_ses.state != USERAUTH_REQ_SENT) {
/* Perhaps we should be more fatal? */
TRACE(("But we didn't send a userauth request!!!!!!"));
TRACE(("But we didn't send a userauth request!!!!!!"))
return;
}
@@ -135,7 +135,7 @@ void recv_msg_userauth_failure() {
ses.authstate.failcount++;
}
TRACE(("Methods (len %d): '%s'", methlen, methods));
TRACE(("Methods (len %d): '%s'", methlen, methods))
ses.authstate.authdone=0;
ses.authstate.authtypes=0;
@@ -150,7 +150,7 @@ void recv_msg_userauth_failure() {
tok = methods; /* tok stores the next method we'll compare */
for (i = 0; i <= methlen; i++) {
if (methods[i] == '\0') {
TRACE(("auth method '%s'", tok));
TRACE(("auth method '%s'", tok))
#ifdef ENABLE_CLI_PUBKEY_AUTH
if (strncmp(AUTH_METHOD_PUBKEY, tok,
AUTH_METHOD_PUBKEY_LEN) == 0) {
@@ -169,20 +169,22 @@ void recv_msg_userauth_failure() {
}
}
m_free(methods);
cli_ses.state = USERAUTH_FAIL_RCVD;
TRACE(("leave recv_msg_userauth_failure"));
TRACE(("leave recv_msg_userauth_failure"))
}
void recv_msg_userauth_success() {
TRACE(("received msg_userauth_success"));
TRACE(("received msg_userauth_success"))
ses.authstate.authdone = 1;
cli_ses.state = USERAUTH_SUCCESS_RCVD;
}
void cli_auth_try() {
TRACE(("enter cli_auth_try"));
TRACE(("enter cli_auth_try"))
int finished = 0;
CHECKCLEARTOWRITE();
@@ -206,5 +208,5 @@ void cli_auth_try() {
dropbear_exit("No auth methods could be used.");
}
TRACE(("leave cli_auth_try"));
TRACE(("leave cli_auth_try"))
}

View File

@@ -30,13 +30,105 @@
#include "runopts.h"
#ifdef ENABLE_CLI_PASSWORD_AUTH
#ifdef ENABLE_CLI_ASKPASS_HELPER
/* Returns 1 if we want to use the askpass program, 0 otherwise */
static int want_askpass()
{
char* askpass_prog = NULL;
askpass_prog = getenv("SSH_ASKPASS");
return askpass_prog && !isatty(STDIN_FILENO) && getenv("DISPLAY");
}
/* returns a statically allocated password from a helper app, or NULL
* on failure */
static char *gui_getpass(const char *prompt) {
pid_t pid;
int p[2], maxlen, len, status;
static char buf[DROPBEAR_MAX_CLI_PASS + 1];
char* helper = NULL;
TRACE(("enter gui_getpass"))
helper = getenv("SSH_ASKPASS");
if (!helper)
{
TRACE(("leave gui_getpass: no askpass program"))
return NULL;
}
if (pipe(p) < 0) {
TRACE(("error creating child pipe"))
return NULL;
}
pid = fork();
if (pid < 0) {
TRACE(("fork error"))
return NULL;
}
if (!pid) {
/* child */
close(p[0]);
if (dup2(p[1], STDOUT_FILENO) < 0) {
TRACE(("error redirecting stdout"))
exit(1);
}
close(p[1]);
execlp(helper, helper, prompt, (char *)0);
TRACE(("execlp error"))
exit(1);
}
close(p[1]);
maxlen = sizeof(buf);
while (maxlen > 0) {
len = read(p[0], buf + sizeof(buf) - maxlen, maxlen);
if (len > 0) {
maxlen -= len;
} else {
if (errno != EINTR)
break;
}
}
close(p[0]);
while (waitpid(pid, &status, 0) < 0 && errno == EINTR)
;
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
return(NULL);
len = sizeof(buf) - maxlen;
buf[len] = '\0';
if (len > 0 && buf[len - 1] == '\n')
buf[len - 1] = '\0';
TRACE(("leave gui_getpass"))
return(buf);
}
#endif /* ENABLE_CLI_ASKPASS_HELPER */
int cli_auth_password() {
char* password = NULL;
TRACE(("enter cli_auth_password"));
TRACE(("enter cli_auth_password"))
CHECKCLEARTOWRITE();
password = getpass("Password: ");
#ifdef ENABLE_CLI_ASKPASS_HELPER
if (want_askpass())
password = gui_getpass("Password: ");
else
#endif
password = getpass("Password: ");
if (password == NULL)
return 0;
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
@@ -56,8 +148,8 @@ int cli_auth_password() {
encrypt_packet();
m_burn(password, strlen(password));
TRACE(("leave cli_auth_password"));
TRACE(("leave cli_auth_password"))
return 1; /* Password auth can always be tried */
}
#endif
#endif /* ENABLE_CLI_PASSWORD_AUTH */

View File

@@ -41,7 +41,7 @@ void cli_pubkeyfail() {
struct PubkeyList *keyitem;
struct PubkeyList **previtem;
TRACE(("enter cli_pubkeyfail"));
TRACE(("enter cli_pubkeyfail"))
previtem = &cli_opts.pubkeys;
/* Find the key we failed with, and remove it */
@@ -55,7 +55,7 @@ void cli_pubkeyfail() {
sign_key_free(cli_ses.lastpubkey->key); /* It won't be used again */
m_free(cli_ses.lastpubkey);
TRACE(("leave cli_pubkeyfail"));
TRACE(("leave cli_pubkeyfail"))
}
void recv_msg_userauth_pk_ok() {
@@ -67,11 +67,11 @@ void recv_msg_userauth_pk_ok() {
int keytype;
unsigned int remotelen;
TRACE(("enter recv_msg_userauth_pk_ok"));
TRACE(("enter recv_msg_userauth_pk_ok"))
algotype = buf_getstring(ses.payload, &algolen);
keytype = signkey_type_from_name(algotype, algolen);
TRACE(("recv_msg_userauth_pk_ok: type %d", keytype));
TRACE(("recv_msg_userauth_pk_ok: type %d", keytype))
m_free(algotype);
keybuf = buf_new(MAX_PUBKEY_SIZE);
@@ -84,7 +84,7 @@ void recv_msg_userauth_pk_ok() {
if (keyitem->type != keytype) {
/* Types differed */
TRACE(("types differed"));
TRACE(("types differed"))
continue;
}
@@ -98,14 +98,14 @@ void recv_msg_userauth_pk_ok() {
if (keybuf->len-4 != remotelen) {
TRACE(("lengths differed: localh %d remote %d", keybuf->len, remotelen));
TRACE(("lengths differed: localh %d remote %d", keybuf->len, remotelen))
/* Lengths differed */
continue;
}
if (memcmp(buf_getptr(keybuf, remotelen),
buf_getptr(ses.payload, remotelen), remotelen) != 0) {
/* Data didn't match this key */
TRACE(("data differed"));
TRACE(("data differed"))
continue;
}
@@ -114,15 +114,15 @@ void recv_msg_userauth_pk_ok() {
}
if (keyitem != NULL) {
TRACE(("matching key"));
TRACE(("matching key"))
/* XXX TODO: if it's an encrypted key, here we ask for their
* password */
send_msg_userauth_pubkey(keyitem->key, keytype, 1);
} else {
TRACE(("That was whacky. We got told that a key was valid, but it didn't match our list. Sounds like dodgy code on Dropbear's part"));
TRACE(("That was whacky. We got told that a key was valid, but it didn't match our list. Sounds like dodgy code on Dropbear's part"))
}
TRACE(("leave recv_msg_userauth_pk_ok"));
TRACE(("leave recv_msg_userauth_pk_ok"))
}
/* TODO: make it take an agent reference to use as well */
@@ -132,7 +132,7 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
int algolen;
buffer* sigbuf = NULL;
TRACE(("enter send_msg_userauth_pubkey"));
TRACE(("enter send_msg_userauth_pubkey"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
@@ -154,7 +154,7 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
buf_put_pub_key(ses.writepayload, key, type);
if (realsign) {
TRACE(("realsign"));
TRACE(("realsign"))
/* We put the signature as well - this contains string(session id), then
* the contents of the write payload to this point */
sigbuf = buf_new(4 + SHA1_HASH_SIZE + ses.writepayload->len);
@@ -165,22 +165,22 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
}
encrypt_packet();
TRACE(("leave send_msg_userauth_pubkey"));
TRACE(("leave send_msg_userauth_pubkey"))
}
int cli_auth_pubkey() {
TRACE(("enter cli_auth_pubkey"));
TRACE(("enter cli_auth_pubkey"))
if (cli_opts.pubkeys != NULL) {
/* Send a trial request */
send_msg_userauth_pubkey(cli_opts.pubkeys->key,
cli_opts.pubkeys->type, 0);
cli_ses.lastpubkey = cli_opts.pubkeys;
TRACE(("leave cli_auth_pubkey-success"));
TRACE(("leave cli_auth_pubkey-success"))
return 1;
} else {
TRACE(("leave cli_auth_pubkey-failure"));
TRACE(("leave cli_auth_pubkey-failure"))
return 0;
}
}

65
cli-channel.c Normal file
View File

@@ -0,0 +1,65 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002-2004 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "channel.h"
#include "buffer.h"
#include "circbuffer.h"
#include "dbutil.h"
#include "session.h"
#include "ssh.h"
/* We receive channel data - only used by the client chansession code*/
void recv_msg_channel_extended_data() {
unsigned int chan;
struct Channel *channel;
unsigned int datatype;
TRACE(("enter recv_msg_channel_extended_data"))
chan = buf_getint(ses.payload);
channel = getchannel(chan);
if (channel == NULL) {
dropbear_exit("Unknown channel");
}
if (channel->type != &clichansess) {
TRACE(("leave recv_msg_channel_extended_data: chantype is wrong"))
return; /* we just ignore it */
}
datatype = buf_getint(ses.payload);
if (datatype != SSH_EXTENDED_DATA_STDERR) {
TRACE(("leave recv_msg_channel_extended_data: wrong datatype: %d",
datatype))
return;
}
common_recv_msg_channel_data(channel, channel->errfd, channel->extrabuf);
TRACE(("leave recv_msg_channel_extended_data"))
}

View File

@@ -32,9 +32,11 @@
#include "ssh.h"
#include "runopts.h"
#include "termcodes.h"
#include "chansession.h"
static void cli_closechansess(struct Channel *channel);
static int cli_initchansess(struct Channel *channel);
static void cli_chansessreq(struct Channel *channel);
static void start_channel_request(struct Channel *channel, unsigned char *type);
@@ -42,19 +44,43 @@ static void send_chansess_pty_req(struct Channel *channel);
static void send_chansess_shell_req(struct Channel *channel);
static void cli_tty_setup();
void cli_tty_cleanup();
static const struct ChanType clichansess = {
const struct ChanType clichansess = {
0, /* sepfds */
"session", /* name */
cli_initchansess, /* inithandler */
NULL, /* checkclosehandler */
NULL, /* reqhandler */
cli_chansessreq, /* reqhandler */
cli_closechansess, /* closehandler */
};
static void cli_chansessreq(struct Channel *channel) {
unsigned char* type = NULL;
int wantreply;
TRACE(("enter cli_chansessreq"))
type = buf_getstring(ses.payload, NULL);
wantreply = buf_getbyte(ses.payload);
if (strcmp(type, "exit-status") != 0) {
TRACE(("unknown request '%s'", type))
send_msg_channel_failure(channel);
goto out;
}
/* We'll just trust what they tell us */
cli_ses.retval = buf_getint(ses.payload);
TRACE(("got exit-status of '%d'", cli_ses.retval))
out:
m_free(type);
}
/* If the main session goes, we close it up */
static void cli_closechansess(struct Channel *channel) {
static void cli_closechansess(struct Channel *UNUSED(channel)) {
/* This channel hasn't gone yet, so we have > 1 */
if (ses.chancount > 1) {
@@ -82,10 +108,10 @@ static void cli_tty_setup() {
struct termios tio;
TRACE(("enter cli_pty_setup"));
TRACE(("enter cli_pty_setup"))
if (cli_ses.tty_raw_mode == 1) {
TRACE(("leave cli_tty_setup: already in raw mode!"));
TRACE(("leave cli_tty_setup: already in raw mode!"))
return;
}
@@ -113,15 +139,15 @@ static void cli_tty_setup() {
}
cli_ses.tty_raw_mode = 1;
TRACE(("leave cli_tty_setup"));
TRACE(("leave cli_tty_setup"))
}
void cli_tty_cleanup() {
TRACE(("enter cli_tty_cleanup"));
TRACE(("enter cli_tty_cleanup"))
if (cli_ses.tty_raw_mode == 0) {
TRACE(("leave cli_tty_cleanup: not in raw mode"));
TRACE(("leave cli_tty_cleanup: not in raw mode"))
return;
}
@@ -131,12 +157,12 @@ void cli_tty_cleanup() {
cli_ses.tty_raw_mode = 0;
}
TRACE(("leave cli_tty_cleanup"));
TRACE(("leave cli_tty_cleanup"))
}
static void put_termcodes() {
TRACE(("enter put_termcodes"));
TRACE(("enter put_termcodes"))
struct termios tio;
unsigned int sshcode;
@@ -206,7 +232,7 @@ static void put_termcodes() {
buf_putint(ses.writepayload, bufpos2 - bufpos1 - 4); /* len(termcodes) */
buf_setpos(ses.writepayload, bufpos2); /* Back where we were */
TRACE(("leave put_termcodes"));
TRACE(("leave put_termcodes"))
}
static void put_winsize() {
@@ -228,7 +254,7 @@ static void put_winsize() {
}
static void sigwinch_handler(int dummy) {
static void sigwinch_handler(int UNUSED(unused)) {
cli_ses.winchange = 1;
@@ -258,7 +284,7 @@ static void send_chansess_pty_req(struct Channel *channel) {
unsigned char* term = NULL;
TRACE(("enter send_chansess_pty_req"));
TRACE(("enter send_chansess_pty_req"))
start_channel_request(channel, "pty-req");
@@ -284,14 +310,14 @@ static void send_chansess_pty_req(struct Channel *channel) {
if (signal(SIGWINCH, sigwinch_handler) == SIG_ERR) {
dropbear_exit("signal error");
}
TRACE(("leave send_chansess_pty_req"));
TRACE(("leave send_chansess_pty_req"))
}
static void send_chansess_shell_req(struct Channel *channel) {
unsigned char* reqtype = NULL;
TRACE(("enter send_chansess_shell_req"));
TRACE(("enter send_chansess_shell_req"))
if (cli_opts.cmd) {
reqtype = "exec";
@@ -308,14 +334,22 @@ static void send_chansess_shell_req(struct Channel *channel) {
}
encrypt_packet();
TRACE(("leave send_chansess_shell_req"));
TRACE(("leave send_chansess_shell_req"))
}
static int cli_initchansess(struct Channel *channel) {
channel->infd = STDOUT_FILENO;
//channel->outfd = STDIN_FILENO;
//channel->errfd = STDERR_FILENO;
setnonblocking(STDOUT_FILENO);
channel->outfd = STDIN_FILENO;
setnonblocking(STDIN_FILENO);
channel->errfd = STDERR_FILENO;
setnonblocking(STDERR_FILENO);
channel->extrabuf = cbuf_new(RECV_MAXWINDOW);
if (cli_opts.wantpty) {
send_chansess_pty_req(channel);
@@ -333,7 +367,7 @@ static int cli_initchansess(struct Channel *channel) {
void cli_send_chansess_request() {
TRACE(("enter cli_send_chansess_request"));
TRACE(("enter cli_send_chansess_request"))
if (send_msg_channel_open_init(STDIN_FILENO, &clichansess)
== DROPBEAR_FAILURE) {
dropbear_exit("Couldn't open initial channel");
@@ -341,6 +375,6 @@ void cli_send_chansess_request() {
/* No special channel request data */
encrypt_packet();
TRACE(("leave cli_send_chansess_request"));
TRACE(("leave cli_send_chansess_request"))
}

View File

@@ -45,8 +45,8 @@ void send_msg_kexdh_init() {
cli_ses.dh_e = (mp_int*)m_malloc(sizeof(mp_int));
cli_ses.dh_x = (mp_int*)m_malloc(sizeof(mp_int));
m_mp_init_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
gen_kexdh_vals(cli_ses.dh_e, cli_ses.dh_x);
CHECKCLEARTOWRITE();
@@ -59,15 +59,20 @@ void send_msg_kexdh_init() {
/* Handle a diffie-hellman key exchange reply. */
void recv_msg_kexdh_reply() {
mp_int dh_f;
DEF_MP_INT(dh_f);
sign_key *hostkey = NULL;
unsigned int type, keybloblen;
unsigned char* keyblob = NULL;
TRACE(("enter recv_msg_kexdh_reply"));
TRACE(("enter recv_msg_kexdh_reply"))
if (cli_ses.kex_state != KEXDH_INIT_SENT) {
dropbear_exit("Received out-of-order kexdhreply");
}
m_mp_init(&dh_f);
type = ses.newkeys->algo_hostkey;
TRACE(("type is %d", type));
TRACE(("type is %d", type))
hostkey = new_sign_key();
keybloblen = buf_getint(ses.payload);
@@ -79,18 +84,20 @@ void recv_msg_kexdh_reply() {
}
if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) {
TRACE(("failed getting pubkey"));
TRACE(("failed getting pubkey"))
dropbear_exit("Bad KEX packet");
}
m_mp_init(&dh_f);
if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
TRACE(("failed getting mpint"));
TRACE(("failed getting mpint"))
dropbear_exit("Bad KEX packet");
}
kexdh_comb_key(cli_ses.dh_e, cli_ses.dh_x, &dh_f, hostkey);
mp_clear(&dh_f);
mp_clear_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
m_free(cli_ses.dh_e);
m_free(cli_ses.dh_x);
if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE)
!= DROPBEAR_SUCCESS) {
@@ -102,19 +109,29 @@ void recv_msg_kexdh_reply() {
send_msg_newkeys();
ses.requirenext = SSH_MSG_NEWKEYS;
TRACE(("leave recv_msg_kexdh_init"));
TRACE(("leave recv_msg_kexdh_init"))
}
static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen) {
char* fp = NULL;
FILE *tty = NULL;
char response = 'z';
fp = sign_key_fingerprint(keyblob, keybloblen);
fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(fingerprint %s)\nDo you want to continue connecting? (y/n)\n",
cli_opts.remotehost,
fp);
if (getc(stdin) == 'y') {
tty = fopen(_PATH_TTY, "r");
if (tty) {
response = getc(tty);
fclose(tty);
} else {
response = getc(stdin);
}
if (response == 'y') {
m_free(fp);
return;
}
@@ -147,21 +164,30 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
/* Check that ~/.ssh exists - easiest way is just to mkdir */
if (mkdir(filename, S_IRWXU) != 0) {
if (errno != EEXIST) {
dropbear_log(LOG_INFO, "Warning: failed creating ~/.ssh: %s",
strerror(errno));
TRACE(("mkdir didn't work: %s", strerror(errno)))
ask_to_confirm(keyblob, keybloblen);
goto out; /* only get here on success */
}
}
snprintf(filename, len+18, "%s/.ssh/known_hosts", pw->pw_dir);
hostsfile = fopen(filename, "r+");
hostsfile = fopen(filename, "a+");
/* We mightn't have been able to open it if it was read-only */
if (hostsfile == NULL && (errno == EACCES || errno == EROFS)) {
readonly = 1;
hostsfile = fopen(filename, "r");
if (hostsfile != NULL) {
fseek(hostsfile, 0, SEEK_SET);
} else {
/* We mightn't have been able to open it if it was read-only */
if (errno == EACCES || errno == EROFS) {
TRACE(("trying readonly: %s", strerror(errno)))
readonly = 1;
hostsfile = fopen(filename, "r");
}
}
if (hostsfile == NULL) {
TRACE(("hostsfile didn't open: %s", strerror(errno)))
ask_to_confirm(keyblob, keybloblen);
goto out; /* We only get here on success */
}
@@ -172,7 +198,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
do {
if (buf_getline(line, hostsfile) == DROPBEAR_FAILURE) {
TRACE(("failed reading line: prob EOF"));
TRACE(("failed reading line: prob EOF"))
break;
}
@@ -181,32 +207,32 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
* buf_getfoo() past the end and die horribly - the base64 parsing
* code is what tiptoes up to the end nicely */
if (line->len < (hostlen+30) ) {
TRACE(("line is too short to be sensible"));
TRACE(("line is too short to be sensible"))
continue;
}
/* Compare hostnames */
if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen),
hostlen) != 0) {
TRACE(("hosts don't match"));
TRACE(("hosts don't match"))
continue;
}
buf_incrpos(line, hostlen);
if (buf_getbyte(line) != ' ') {
/* there wasn't a space after the hostname, something dodgy */
TRACE(("missing space afte matching hostname"));
TRACE(("missing space afte matching hostname"))
continue;
}
if ( strncmp(buf_getptr(line, algolen), algoname, algolen) != 0) {
TRACE(("algo doesn't match"));
TRACE(("algo doesn't match"))
continue;
}
buf_incrpos(line, algolen);
if (buf_getbyte(line) != ' ') {
TRACE(("missing space after algo"));
TRACE(("missing space after algo"))
continue;
}
@@ -215,7 +241,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
if (ret == DROPBEAR_SUCCESS) {
/* Good matching key */
TRACE(("good matching key"));
TRACE(("good matching key"))
goto out;
}
@@ -228,11 +254,12 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
/* If we get here, they said yes */
if (readonly) {
TRACE(("readonly"))
goto out;
}
/* put the new entry in the file */
fseek(hostsfile, 0, SEEK_END);
fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */
buf_setpos(line, 0);
buf_setlen(line, 0);
buf_putbytes(line, ses.remotehost, hostlen);
@@ -240,7 +267,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
buf_putbytes(line, algoname, algolen);
buf_putbyte(line, ' ');
len = line->size - line->pos;
TRACE(("keybloblen %d, len %d", keybloblen, len));
TRACE(("keybloblen %d, len %d", keybloblen, len))
/* The only failure with base64 is buffer_overflow, but buf_getwriteptr
* will die horribly in the case anyway */
base64_encode(keyblob, keybloblen, buf_getwriteptr(line, len), &len);
@@ -255,5 +282,7 @@ out:
fclose(hostsfile);
}
m_free(filename);
buf_free(line);
if (line != NULL) {
buf_free(line);
}
}

View File

@@ -50,7 +50,11 @@ int main(int argc, char ** argv) {
cli_getopts(argc, argv);
TRACE(("user='%s' host='%s' port='%s'", cli_opts.username,
cli_opts.remotehost, cli_opts.remoteport));
cli_opts.remotehost, cli_opts.remoteport))
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
dropbear_exit("signal() error");
}
sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
0, &error);
@@ -96,7 +100,8 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
exit(exitcode);
}
static void cli_dropbear_log(int priority, const char* format, va_list param) {
static void cli_dropbear_log(int UNUSED(priority),
const char* format, va_list param) {
char printbuf[1024];

View File

@@ -59,6 +59,9 @@ static void printhelp() {
"-R <listenport:remotehost:remoteport> Remote port forwarding\n"
#endif
"-l <username>\n"
#ifdef DEBUG_TRACE
"-v verbose\n"
#endif
,DROPBEAR_VERSION, cli_opts.progname);
}
@@ -113,7 +116,7 @@ void cli_getopts(int argc, char ** argv) {
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
if (nextisremote) {
TRACE(("nextisremote true"));
TRACE(("nextisremote true"))
addforward(argv[i], &cli_opts.remotefwds);
nextisremote = 0;
continue;
@@ -121,7 +124,7 @@ void cli_getopts(int argc, char ** argv) {
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
if (nextislocal) {
TRACE(("nextislocal true"));
TRACE(("nextislocal true"))
addforward(argv[i], &cli_opts.localfwds);
nextislocal = 0;
continue;
@@ -140,19 +143,18 @@ void cli_getopts(int argc, char ** argv) {
if (argv[i][0] == '-') {
/* A flag *waves* */
if (strlen(argv[i]) > 2) {
fprintf(stderr,
"WARNING: Ignoring unknown argument '%s'\n", argv[i]);
continue;
}
switch (argv[i][1]) {
case 'p': /* remoteport */
next = &cli_opts.remoteport;
break;
#ifdef ENABLE_CLI_PUBKEY_AUTH
case 'i': /* an identityfile */
nextiskey = 1;
/* Keep scp happy when it changes "-i file" to "-ifile" */
if (strlen(argv[i]) > 2) {
loadidentityfile(&argv[i][2]);
} else {
nextiskey = 1;
}
break;
#endif
case 't': /* we want a pty */
@@ -178,6 +180,11 @@ void cli_getopts(int argc, char ** argv) {
printhelp();
exit(EXIT_SUCCESS);
break;
#ifdef DEBUG_TRACE
case 'v':
debug_trace = 1;
break;
#endif
case 'F':
case 'e':
case 'c':
@@ -197,11 +204,17 @@ void cli_getopts(int argc, char ** argv) {
"WARNING: Ignoring unknown argument '%s'\n", argv[i]);
break;
} /* Switch */
/* Now we handle args where they might be "-luser" (no spaces)*/
if (next && strlen(argv[i]) > 2) {
*next = &argv[i][2];
next = NULL;
}
continue; /* next argument */
} else {
TRACE(("non-flag arg: '%s'", argv[i]));
TRACE(("non-flag arg: '%s'", argv[i]))
/* Either the hostname or commands */
@@ -330,7 +343,7 @@ static void addforward(char* origstr, struct TCPFwdList** fwdlist) {
struct TCPFwdList* newfwd = NULL;
char * str = NULL;
TRACE(("enter addforward"));
TRACE(("enter addforward"))
/* We probably don't want to be editing argvs */
str = m_strdup(origstr);
@@ -339,7 +352,7 @@ static void addforward(char* origstr, struct TCPFwdList** fwdlist) {
connectaddr = strchr(str, ':');
if (connectaddr == NULL) {
TRACE(("connectaddr == NULL"));
TRACE(("connectaddr == NULL"))
goto fail;
}
@@ -348,7 +361,7 @@ static void addforward(char* origstr, struct TCPFwdList** fwdlist) {
connectport = strchr(connectaddr, ':');
if (connectport == NULL) {
TRACE(("connectport == NULL"));
TRACE(("connectport == NULL"))
goto fail;
}
@@ -361,32 +374,32 @@ static void addforward(char* origstr, struct TCPFwdList** fwdlist) {
* the check later only checks for >= MAX_PORT */
newfwd->listenport = strtol(listenport, NULL, 10);
if (errno != 0) {
TRACE(("bad listenport strtol"));
TRACE(("bad listenport strtol"))
goto fail;
}
newfwd->connectport = strtol(connectport, NULL, 10);
if (errno != 0) {
TRACE(("bad connectport strtol"));
TRACE(("bad connectport strtol"))
goto fail;
}
newfwd->connectaddr = connectaddr;
if (newfwd->listenport > 65535) {
TRACE(("listenport > 65535"));
TRACE(("listenport > 65535"))
goto badport;
}
if (newfwd->connectport > 65535) {
TRACE(("connectport > 65535"));
TRACE(("connectport > 65535"))
goto badport;
}
newfwd->next = *fwdlist;
*fwdlist = newfwd;
TRACE(("leave addforward: done"));
TRACE(("leave addforward: done"))
return;
fail:

View File

@@ -33,7 +33,7 @@
void send_msg_service_request(char* servicename) {
TRACE(("enter send_msg_service_request: servicename='%s'", servicename));
TRACE(("enter send_msg_service_request: servicename='%s'", servicename))
CHECKCLEARTOWRITE();
@@ -41,7 +41,7 @@ void send_msg_service_request(char* servicename) {
buf_putstring(ses.writepayload, servicename, strlen(servicename));
encrypt_packet();
TRACE(("leave send_msg_service_request"));
TRACE(("leave send_msg_service_request"))
}
/* This just sets up the state variables right for the main client session loop
@@ -51,7 +51,7 @@ void recv_msg_service_accept() {
unsigned char* servicename;
unsigned int len;
TRACE(("enter recv_msg_service_accept"));
TRACE(("enter recv_msg_service_accept"))
servicename = buf_getstring(ses.payload, &len);
@@ -62,7 +62,7 @@ void recv_msg_service_accept() {
cli_ses.state = SERVICE_AUTH_ACCEPT_RCVD;
m_free(servicename);
TRACE(("leave recv_msg_service_accept: done ssh-userauth"));
TRACE(("leave recv_msg_service_accept: done ssh-userauth"))
return;
}
@@ -77,7 +77,7 @@ void recv_msg_service_accept() {
cli_ses.state = SERVICE_CONN_ACCEPT_RCVD;
m_free(servicename);
TRACE(("leave recv_msg_service_accept: done ssh-connection"));
TRACE(("leave recv_msg_service_accept: done ssh-connection"))
return;
}

View File

@@ -48,6 +48,7 @@ struct clientsession cli_ses; /* GLOBAL */
static const packettype cli_packettypes[] = {
/* TYPE, FUNCTION */
{SSH_MSG_CHANNEL_DATA, recv_msg_channel_data},
{SSH_MSG_CHANNEL_EXTENDED_DATA, recv_msg_channel_extended_data},
{SSH_MSG_CHANNEL_WINDOW_ADJUST, recv_msg_channel_window_adjust},
{SSH_MSG_USERAUTH_FAILURE, recv_msg_userauth_failure}, /* client */
{SSH_MSG_USERAUTH_SUCCESS, recv_msg_userauth_success}, /* client */
@@ -112,9 +113,17 @@ static void cli_session_init() {
cli_ses.tty_raw_mode = 0;
cli_ses.winchange = 0;
/* We store stdin's flags, so we can set them back on exit (otherwise
* busybox's ash isn't happy */
cli_ses.stdincopy = dup(STDIN_FILENO);
cli_ses.stdinflags = fcntl(STDIN_FILENO, F_GETFL, 0);
cli_ses.retval = EXIT_SUCCESS; /* Assume it's clean if we don't get a
specific exit status */
/* Auth */
cli_ses.lastpubkey = NULL;
cli_ses.lastauthtype = NULL;
cli_ses.lastauthtype = 0;
/* For printing "remote host closed" for the user */
ses.remoteclosed = cli_remoteclosed;
@@ -130,7 +139,7 @@ static void cli_session_init() {
* service, userauth and channel requests */
static void cli_sessionloop() {
TRACE(("enter cli_sessionloop"));
TRACE(("enter cli_sessionloop"))
if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) {
cli_ses.kex_state = KEXINIT_RCVD;
@@ -142,7 +151,7 @@ static void cli_sessionloop() {
* negotiation would have failed. */
send_msg_kexdh_init();
cli_ses.kex_state = KEXDH_INIT_SENT;
TRACE(("leave cli_sessionloop: done with KEXINIT_RCVD"));
TRACE(("leave cli_sessionloop: done with KEXINIT_RCVD"))
return;
}
@@ -154,14 +163,14 @@ static void cli_sessionloop() {
/* We shouldn't do anything else if a KEX is in progress */
if (cli_ses.kex_state != KEX_NOTHING) {
TRACE(("leave cli_sessionloop: kex_state != KEX_NOTHING"));
TRACE(("leave cli_sessionloop: kex_state != KEX_NOTHING"))
return;
}
/* We should exit if we haven't donefirstkex: we shouldn't reach here
* in normal operation */
if (ses.kexstate.donefirstkex == 0) {
TRACE(("XXX XXX might be bad! leave cli_sessionloop: haven't donefirstkex"));
TRACE(("XXX XXX might be bad! leave cli_sessionloop: haven't donefirstkex"))
return;
}
@@ -172,32 +181,32 @@ static void cli_sessionloop() {
* userauth */
send_msg_service_request(SSH_SERVICE_USERAUTH);
cli_ses.state = SERVICE_AUTH_REQ_SENT;
TRACE(("leave cli_sessionloop: sent userauth service req"));
TRACE(("leave cli_sessionloop: sent userauth service req"))
return;
/* userauth code */
case SERVICE_AUTH_ACCEPT_RCVD:
cli_auth_getmethods();
cli_ses.state = USERAUTH_REQ_SENT;
TRACE(("leave cli_sessionloop: sent userauth methods req"));
TRACE(("leave cli_sessionloop: sent userauth methods req"))
return;
case USERAUTH_FAIL_RCVD:
cli_auth_try();
cli_ses.state = USERAUTH_REQ_SENT;
TRACE(("leave cli_sessionloop: cli_auth_try"));
TRACE(("leave cli_sessionloop: cli_auth_try"))
return;
/*
case USERAUTH_SUCCESS_RCVD:
send_msg_service_request(SSH_SERVICE_CONNECTION);
cli_ses.state = SERVICE_CONN_REQ_SENT;
TRACE(("leave cli_sessionloop: sent ssh-connection service req"));
TRACE(("leave cli_sessionloop: sent ssh-connection service req"))
return;
case SERVICE_CONN_ACCEPT_RCVD:
cli_send_chansess_request();
TRACE(("leave cli_sessionloop: cli_send_chansess_request"));
TRACE(("leave cli_sessionloop: cli_send_chansess_request"))
cli_ses.state = SESSION_RUNNING;
return;
*/
@@ -210,7 +219,7 @@ static void cli_sessionloop() {
setup_remotetcp();
#endif
cli_send_chansess_request();
TRACE(("leave cli_sessionloop: cli_send_chansess_request"));
TRACE(("leave cli_sessionloop: cli_send_chansess_request"))
cli_ses.state = SESSION_RUNNING;
return;
@@ -231,7 +240,7 @@ static void cli_sessionloop() {
break;
}
TRACE(("leave cli_sessionloop: fell out"));
TRACE(("leave cli_sessionloop: fell out"))
}
@@ -240,6 +249,11 @@ void cli_session_cleanup() {
if (!sessinitdone) {
return;
}
/* Set stdin back to non-blocking - busybox ash dies nastily
* if we don't revert the flags */
fcntl(cli_ses.stdincopy, F_SETFL, cli_ses.stdinflags);
cli_tty_cleanup();
}
@@ -250,7 +264,7 @@ static void cli_finished() {
common_session_cleanup();
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
cli_opts.remotehost, cli_opts.remoteport);
exit(EXIT_SUCCESS);
exit(cli_ses.retval);
}

View File

@@ -31,8 +31,7 @@
#include "session.h"
#include "ssh.h"
static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
unsigned int remoteport);
#ifdef ENABLE_CLI_REMOTETCPFWD
static int newtcpforwarded(struct Channel * channel);
const struct ChanType cli_chan_tcpremote = {
@@ -43,6 +42,11 @@ const struct ChanType cli_chan_tcpremote = {
NULL,
NULL
};
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
unsigned int remoteport);
static const struct ChanType cli_chan_tcplocal = {
1, /* sepfds */
"direct-tcpip",
@@ -51,15 +55,17 @@ static const struct ChanType cli_chan_tcplocal = {
NULL,
NULL
};
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
void setup_localtcp() {
int ret;
TRACE(("enter setup_localtcp"));
TRACE(("enter setup_localtcp"))
if (cli_opts.localfwds == NULL) {
TRACE(("cli_opts.localfwds == NULL"));
TRACE(("cli_opts.localfwds == NULL"))
}
while (cli_opts.localfwds != NULL) {
@@ -75,7 +81,7 @@ void setup_localtcp() {
cli_opts.localfwds = cli_opts.localfwds->next;
}
TRACE(("leave setup_localtcp"));
TRACE(("leave setup_localtcp"))
}
@@ -89,7 +95,7 @@ static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
remoteport));
tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener*));
tcpinfo->sendaddr = remoteaddr;
tcpinfo->sendaddr = m_strdup(remoteaddr);
tcpinfo->sendport = remoteport;
tcpinfo->listenport = listenport;
tcpinfo->chantype = &cli_chan_tcplocal;
@@ -99,13 +105,15 @@ static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
if (ret == DROPBEAR_FAILURE) {
m_free(tcpinfo);
}
TRACE(("leave cli_localtcp: %d", ret));
TRACE(("leave cli_localtcp: %d", ret))
return ret;
}
#endif /* ENABLE_CLI_LOCALTCPFWD */
#ifdef ENABLE_CLI_REMOTETCPFWD
static void send_msg_global_request_remotetcp(int port) {
TRACE(("enter send_msg_global_request_remotetcp"));
TRACE(("enter send_msg_global_request_remotetcp"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
@@ -116,17 +124,17 @@ static void send_msg_global_request_remotetcp(int port) {
encrypt_packet();
TRACE(("leave send_msg_global_request_remotetcp"));
TRACE(("leave send_msg_global_request_remotetcp"))
}
void setup_remotetcp() {
struct TCPFwdList * iter = NULL;
TRACE(("enter setup_remotetcp"));
TRACE(("enter setup_remotetcp"))
if (cli_opts.remotefwds == NULL) {
TRACE(("cli_opts.remotefwds == NULL"));
TRACE(("cli_opts.remotefwds == NULL"))
}
iter = cli_opts.remotefwds;
@@ -135,7 +143,7 @@ void setup_remotetcp() {
send_msg_global_request_remotetcp(iter->listenport);
iter = iter->next;
}
TRACE(("leave setup_remotetcp"));
TRACE(("leave setup_remotetcp"))
}
static int newtcpforwarded(struct Channel * channel) {
@@ -171,7 +179,7 @@ static int newtcpforwarded(struct Channel * channel) {
snprintf(portstring, sizeof(portstring), "%d", iter->connectport);
sock = connect_remote(iter->connectaddr, portstring, 1, NULL);
if (sock < 0) {
TRACE(("leave newtcpdirect: sock failed"));
TRACE(("leave newtcpdirect: sock failed"))
err = SSH_OPEN_CONNECT_FAILED;
goto out;
}
@@ -188,6 +196,7 @@ static int newtcpforwarded(struct Channel * channel) {
err = SSH_OPEN_IN_PROGRESS;
out:
TRACE(("leave newtcpdirect: err %d", err));
TRACE(("leave newtcpdirect: err %d", err))
return err;
}
#endif /* ENABLE_CLI_REMOTETCPFWD */

View File

@@ -34,7 +34,7 @@
#ifdef DROPBEAR_AES128_CBC
const struct dropbear_cipher dropbear_aes128 =
{&rijndael_desc, 16, 16};
{&aes_desc, 16, 16};
#endif
#ifdef DROPBEAR_BLOWFISH_CBC
const struct dropbear_cipher dropbear_blowfish =
@@ -127,7 +127,7 @@ void crypto_init() {
const struct _cipher_descriptor *regciphers[] = {
#ifdef DROPBEAR_AES128_CBC
&rijndael_desc,
&aes_desc,
#endif
#ifdef DROPBEAR_BLOWFISH_CBC
&blowfish_desc,
@@ -202,6 +202,6 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
}
str[pos]=0;
/* Debug this */
TRACE(("buf_put_algolist: %s", str));
TRACE(("buf_put_algolist: %s", str))
buf_putstring(buf, str, pos);
}

View File

@@ -1,7 +1,7 @@
/*
* Dropbear - a SSH2 server
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2002-2004 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -29,6 +29,7 @@
#include "packet.h"
#include "ssh.h"
#include "buffer.h"
#include "circbuffer.h"
#include "dbutil.h"
#include "channel.h"
#include "ssh.h"
@@ -39,7 +40,7 @@ static void send_msg_channel_open_failure(unsigned int remotechan, int reason,
static void send_msg_channel_open_confirmation(struct Channel* channel,
unsigned int recvwindow,
unsigned int recvmaxpacket);
static void writechannel(struct Channel *channel);
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf);
static void send_msg_channel_window_adjust(struct Channel *channel,
unsigned int incr);
static void send_msg_channel_data(struct Channel *channel, int isextended,
@@ -80,15 +81,15 @@ void chancleanup() {
unsigned int i;
TRACE(("enter chancleanup"));
TRACE(("enter chancleanup"))
for (i = 0; i < ses.chansize; i++) {
if (ses.channels[i] != NULL) {
TRACE(("channel %d closing", i));
TRACE(("channel %d closing", i))
removechannel(ses.channels[i]);
}
}
m_free(ses.channels);
TRACE(("leave chancleanup"));
TRACE(("leave chancleanup"))
}
/* Create a new channel entry, send a reply confirm or failure */
@@ -102,7 +103,7 @@ struct Channel* newchannel(unsigned int remotechan,
struct Channel * newchan;
unsigned int i, j;
TRACE(("enter newchannel"));
TRACE(("enter newchannel"))
/* first see if we can use existing channels */
for (i = 0; i < ses.chansize; i++) {
@@ -114,7 +115,7 @@ struct Channel* newchannel(unsigned int remotechan,
/* otherwise extend the list */
if (i == ses.chansize) {
if (ses.chansize >= MAX_CHANNELS) {
TRACE(("leave newchannel: max chans reached"));
TRACE(("leave newchannel: max chans reached"))
return NULL;
}
@@ -147,20 +148,22 @@ struct Channel* newchannel(unsigned int remotechan,
newchan->errfd = FD_CLOSED; /* this isn't always set to start with */
newchan->initconn = 0;
newchan->writebuf = buf_new(RECV_MAXWINDOW);
newchan->writebuf = cbuf_new(RECV_MAXWINDOW);
newchan->extrabuf = NULL; /* The user code can set it up */
newchan->recvwindow = RECV_MAXWINDOW;
newchan->recvdonelen = 0;
newchan->recvmaxpacket = RECV_MAXPACKET;
ses.channels[i] = newchan;
ses.chancount++;
TRACE(("leave newchannel"));
TRACE(("leave newchannel"))
return newchan;
}
/* Get the channel structure corresponding to a channel number */
static struct Channel* getchannel(unsigned int chan) {
struct Channel* getchannel(unsigned int chan) {
if (chan >= ses.chansize || ses.channels[chan] == NULL) {
return NULL;
}
@@ -189,7 +192,8 @@ void channelio(fd_set *readfd, fd_set *writefd) {
}
/* read from program/pipe stderr */
if (channel->errfd >= 0 && FD_ISSET(channel->errfd, readfd)) {
if (channel->extrabuf == NULL &&
channel->errfd >= 0 && FD_ISSET(channel->errfd, readfd)) {
send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR);
}
@@ -218,7 +222,13 @@ void channelio(fd_set *readfd, fd_set *writefd) {
continue; /* Important not to use the channel after
checkinitdone(), as it may be NULL */
}
writechannel(channel);
writechannel(channel, channel->infd, channel->writebuf);
}
/* stderr for client mode */
if (channel->extrabuf != NULL
&& channel->errfd >= 0 && FD_ISSET(channel->errfd, writefd)) {
writechannel(channel, channel->errfd, channel->extrabuf);
}
/* now handle any of the channel-closing type stuff */
@@ -236,6 +246,14 @@ void channelio(fd_set *readfd, fd_set *writefd) {
/* do all the EOF/close type stuff checking for a channel */
static void checkclose(struct Channel *channel) {
TRACE(("checkclose: infd %d, outfd %d, errfd %d, sentclosed %d, recvclosed %d",
channel->infd, channel->outfd,
channel->errfd, channel->sentclosed, channel->recvclosed))
TRACE(("writebuf %d extrabuf %s extrabuf %d",
cbuf_getused(channel->writebuf),
channel->writebuf,
channel->writebuf ? 0 : cbuf_getused(channel->extrabuf)))
if (!channel->sentclosed) {
/* check for exited - currently only used for server sessions,
@@ -248,13 +266,13 @@ static void checkclose(struct Channel *channel) {
if (!channel->senteof
&& channel->outfd == FD_CLOSED
&& channel->errfd == FD_CLOSED) {
&& (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
send_msg_channel_eof(channel);
}
if (channel->infd == FD_CLOSED
&& channel->outfd == FD_CLOSED
&& channel->errfd == FD_CLOSED) {
&& channel->outfd == FD_CLOSED
&& (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
send_msg_channel_close(channel);
}
}
@@ -271,7 +289,7 @@ static void checkclose(struct Channel *channel) {
*/
if (channel->recvclosed) {
if (! channel->sentclosed) {
TRACE(("Sending MSG_CHANNEL_CLOSE in response to same."));
TRACE(("Sending MSG_CHANNEL_CLOSE in response to same."))
send_msg_channel_close(channel);
}
removechannel(channel);
@@ -288,7 +306,7 @@ static void checkinitdone(struct Channel *channel) {
int val;
socklen_t vallen = sizeof(val);
TRACE(("enter checkinitdone"));
TRACE(("enter checkinitdone"))
if (getsockopt(channel->infd, SOL_SOCKET, SO_ERROR, &val, &vallen)
|| val != 0) {
@@ -296,13 +314,13 @@ static void checkinitdone(struct Channel *channel) {
SSH_OPEN_CONNECT_FAILED, "", "");
close(channel->infd);
deletechannel(channel);
TRACE(("leave checkinitdone: fail"));
TRACE(("leave checkinitdone: fail"))
} else {
send_msg_channel_open_confirmation(channel, channel->recvwindow,
channel->recvmaxpacket);
channel->outfd = channel->infd;
channel->initconn = 0;
TRACE(("leave checkinitdone: success"));
TRACE(("leave checkinitdone: success"))
}
}
@@ -311,7 +329,7 @@ static void checkinitdone(struct Channel *channel) {
/* Send the close message and set the channel as closed */
static void send_msg_channel_close(struct Channel *channel) {
TRACE(("enter send_msg_channel_close"));
TRACE(("enter send_msg_channel_close"))
/* XXX server */
if (channel->type->closehandler) {
channel->type->closehandler(channel);
@@ -326,13 +344,13 @@ static void send_msg_channel_close(struct Channel *channel) {
channel->senteof = 1;
channel->sentclosed = 1;
TRACE(("leave send_msg_channel_close"));
TRACE(("leave send_msg_channel_close"))
}
/* call this when trans/eof channels are closed */
static void send_msg_channel_eof(struct Channel *channel) {
TRACE(("enter send_msg_channel_eof"));
TRACE(("enter send_msg_channel_eof"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_EOF);
@@ -342,53 +360,57 @@ static void send_msg_channel_eof(struct Channel *channel) {
channel->senteof = 1;
TRACE(("leave send_msg_channel_eof"));
TRACE(("leave send_msg_channel_eof"))
}
/* Called to write data out to the server side of a channel (eg a shell or a
* program.
/* Called to write data out to the local side of the channel.
* Only called when we know we can write to a channel, writes as much as
* possible */
static void writechannel(struct Channel* channel) {
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
int len, maxlen;
buffer *buf;
TRACE(("enter writechannel"));
TRACE(("enter writechannel"))
buf = channel->writebuf;
maxlen = buf->len - buf->pos;
maxlen = cbuf_readlen(cbuf);
len = write(channel->infd, buf_getptr(buf, maxlen), maxlen);
/* Write the data out */
len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen);
if (len <= 0) {
if (len < 0 && errno != EINTR) {
/* no more to write */
/* no more to write - we close it even if the fd was stderr, since
* that's a nasty failure too */
closeinfd(channel);
}
TRACE(("leave writechannel: len <= 0"));
TRACE(("leave writechannel: len <= 0"))
return;
}
if (len == maxlen) {
buf_setpos(buf, 0);
buf_setlen(buf, 0);
if (channel->recveof) {
/* we're closing up */
closeinfd(channel);
return;
TRACE(("leave writechannel: recveof set"));
}
cbuf_incrread(cbuf, len);
channel->recvdonelen += len;
/* extend the window if we're at the end*/
/* TODO - this is inefficient */
send_msg_channel_window_adjust(channel, buf->size
- channel->recvwindow);
channel->recvwindow = buf->size;
} else {
buf_incrpos(buf, len);
if (fd == channel->infd && len == maxlen && channel->recveof) {
/* Check if we're closing up */
closeinfd(channel);
TRACE(("leave writechannel: recveof set"))
return;
}
TRACE(("leave writechannel"));
/* Window adjust handling */
if (channel->recvdonelen >= RECV_WINDOWEXTEND) {
/* Set it back to max window */
send_msg_channel_window_adjust(channel, channel->recvdonelen);
channel->recvwindow += channel->recvdonelen;
channel->recvdonelen = 0;
}
assert(channel->recvwindow <= RECV_MAXWINDOW);
assert(channel->recvwindow <= cbuf_getavail(channel->writebuf));
assert(channel->extrabuf == NULL ||
channel->recvwindow <= cbuf_getavail(channel->extrabuf));
TRACE(("leave writechannel"))
}
/* Set the file descriptors for the main select in session.c
@@ -405,30 +427,38 @@ void setchannelfds(fd_set *readfd, fd_set *writefd) {
continue;
}
/* stdout and stderr */
/* Stuff to put over the wire */
if (channel->transwindow > 0) {
/* stdout */
if (channel->outfd >= 0) {
/* there's space to read more from the program */
FD_SET(channel->outfd, readfd);
}
/* stderr */
if (channel->errfd >= 0) {
if (channel->extrabuf == NULL && channel->errfd >= 0) {
FD_SET(channel->errfd, readfd);
}
}
/* For checking FD status (ie closure etc) - we don't actually
* read data from infd */
TRACE(("infd = %d, outfd %d, errfd %d, bufused %d",
channel->infd, channel->outfd,
channel->errfd,
cbuf_getused(channel->writebuf) ))
if (channel->infd >= 0 && channel->infd != channel->outfd) {
FD_SET(channel->infd, readfd);
}
/* stdin */
if (channel->infd >= 0 &&
(channel->writebuf->pos < channel->writebuf->len ||
channel->initconn)) {
/* there's space to write more to the program */
FD_SET(channel->infd, writefd);
/* Stuff from the wire, to local program/shell/user etc */
if ((channel->infd >= 0 && cbuf_getused(channel->writebuf) > 0 )
|| channel->initconn) {
FD_SET(channel->infd, writefd);
}
if (channel->extrabuf != NULL && channel->errfd >= 0
&& cbuf_getused(channel->extrabuf) > 0 ) {
FD_SET(channel->errfd, writefd);
}
} /* foreach channel */
@@ -447,7 +477,7 @@ void recv_msg_channel_eof() {
unsigned int chan;
struct Channel * channel;
TRACE(("enter recv_msg_channel_eof"));
TRACE(("enter recv_msg_channel_eof"))
chan = buf_getint(ses.payload);
channel = getchannel(chan);
@@ -457,11 +487,13 @@ void recv_msg_channel_eof() {
}
channel->recveof = 1;
if (channel->writebuf->len == 0) {
if (cbuf_getused(channel->writebuf) == 0
&& (channel->extrabuf == NULL
|| cbuf_getused(channel->extrabuf) == 0)) {
closeinfd(channel);
}
TRACE(("leave recv_msg_channel_eof"));
TRACE(("leave recv_msg_channel_eof"))
}
@@ -471,10 +503,10 @@ void recv_msg_channel_close() {
unsigned int chan;
struct Channel * channel;
TRACE(("enter recv_msg_channel_close"));
TRACE(("enter recv_msg_channel_close"))
chan = buf_getint(ses.payload);
TRACE(("close channel = %d", chan));
TRACE(("close channel = %d", chan))
channel = getchannel(chan);
if (channel == NULL) {
@@ -489,31 +521,36 @@ void recv_msg_channel_close() {
removechannel(channel);
}
TRACE(("leave recv_msg_channel_close"));
TRACE(("leave recv_msg_channel_close"))
}
/* Remove a channel entry, this is only executed after both sides have sent
* channel close */
static void removechannel(struct Channel * channel) {
TRACE(("enter removechannel"));
TRACE(("channel index is %d", channel->index));
TRACE(("enter removechannel"))
TRACE(("channel index is %d", channel->index))
buf_free(channel->writebuf);
cbuf_free(channel->writebuf);
channel->writebuf = NULL;
if (channel->extrabuf) {
cbuf_free(channel->extrabuf);
channel->extrabuf = NULL;
}
/* close the FDs in case they haven't been done
* yet (ie they were shutdown etc */
close(channel->infd);
close(channel->outfd);
if (channel->errfd >= 0) {
close(channel->errfd);
}
close(channel->errfd);
channel->typedata = NULL;
deletechannel(channel);
TRACE(("leave removechannel"));
TRACE(("leave removechannel"))
}
/* Remove a channel entry */
@@ -533,7 +570,7 @@ void recv_msg_channel_request() {
unsigned int chan;
struct Channel *channel;
TRACE(("enter recv_msg_channel_request"));
TRACE(("enter recv_msg_channel_request"))
chan = buf_getint(ses.payload);
channel = getchannel(chan);
@@ -549,7 +586,7 @@ void recv_msg_channel_request() {
send_msg_channel_failure(channel);
}
TRACE(("leave recv_msg_channel_request"));
TRACE(("leave recv_msg_channel_request"))
}
@@ -566,8 +603,8 @@ static void send_msg_channel_data(struct Channel *channel, int isextended,
unsigned int maxlen;
int fd;
/* TRACE(("enter send_msg_channel_data"));
TRACE(("extended = %d type = %d", isextended, exttype));*/
/* TRACE(("enter send_msg_channel_data"))
TRACE(("extended = %d type = %d", isextended, exttype))*/
CHECKCLEARTOWRITE();
@@ -586,21 +623,24 @@ static void send_msg_channel_data(struct Channel *channel, int isextended,
maxlen = MIN(maxlen,
ses.writepayload->size - 1 - 4 - 4 - (isextended ? 4 : 0));
if (maxlen == 0) {
TRACE(("leave send_msg_channel_data: no window"));
TRACE(("leave send_msg_channel_data: no window"))
return; /* the data will get written later */
}
/* read the data */
TRACE(("maxlen %d", maxlen))
buf = buf_new(maxlen);
TRACE(("buf pos %d data %x", buf->pos, buf->data))
len = read(fd, buf_getwriteptr(buf, maxlen), maxlen);
if (len <= 0) {
/* on error/eof, send eof */
if (len == 0 || errno != EINTR) {
closeoutfd(channel, fd);
TRACE(("leave send_msg_channel_data: read err %d", channel->index));
}
buf_free(buf);
buf = NULL;
TRACE(("leave send_msg_channel_data: read err or EOF for fd %d",
channel->index));
return;
}
buf_incrlen(buf, len);
@@ -620,64 +660,77 @@ static void send_msg_channel_data(struct Channel *channel, int isextended,
channel->transwindow -= len;
encrypt_packet();
TRACE(("leave send_msg_channel_data"));
TRACE(("leave send_msg_channel_data"))
}
/* when we receive channel data, put it in a buffer for writing to the program/
* shell etc */
/* We receive channel data */
void recv_msg_channel_data() {
unsigned int chan;
struct Channel * channel;
unsigned int datalen;
unsigned int pos;
unsigned int maxdata;
struct Channel *channel;
TRACE(("enter recv_msg_channel_data"));
chan = buf_getint(ses.payload);
channel = getchannel(chan);
if (channel == NULL) {
dropbear_exit("Unknown channel");
}
common_recv_msg_channel_data(channel, channel->infd, channel->writebuf);
}
/* Shared for data and stderr data - when we receive data, put it in a buffer
* for writing to the local file descriptor */
void common_recv_msg_channel_data(struct Channel *channel, int fd,
circbuffer * cbuf) {
unsigned int datalen;
unsigned int maxdata;
unsigned int buflen;
unsigned int len;
TRACE(("enter recv_msg_channel_data"))
if (channel->recveof) {
dropbear_exit("received data after eof");
}
if (channel->infd < 0) {
if (fd < 0) {
dropbear_exit("received data with bad infd");
}
datalen = buf_getint(ses.payload);
/* if the client is going to send us more data than we've allocated, then
* it has ignored the windowsize, so we "MAY ignore all extra data" */
maxdata = channel->writebuf->size - channel->writebuf->pos;
maxdata = cbuf_getavail(cbuf);
/* Whilst the spec says we "MAY ignore data past the end" this could
* lead to corrupted file transfers etc (chunks missed etc). It's better to
* just die horribly */
if (datalen > maxdata) {
TRACE(("Warning: recv_msg_channel_data: extra data past window"));
datalen = maxdata;
dropbear_exit("Oversized packet");
}
/* write to the buffer - we always append to the end of the buffer */
pos = channel->writebuf->pos;
buf_setpos(channel->writebuf, channel->writebuf->len);
memcpy(buf_getwriteptr(channel->writebuf, datalen),
buf_getptr(ses.payload, datalen), datalen);
buf_incrwritepos(channel->writebuf, datalen);
buf_setpos(channel->writebuf, pos); /* revert pos */
/* We may have to run throught twice, if the buffer wraps around. Can't
* just "leave it for next time" like with writechannel, since this
* is payload data */
len = datalen;
while (len > 0) {
buflen = cbuf_writelen(cbuf);
buflen = MIN(buflen, len);
memcpy(cbuf_writeptr(cbuf, buflen),
buf_getptr(ses.payload, buflen), buflen);
cbuf_incrwrite(cbuf, buflen);
buf_incrpos(ses.payload, buflen);
len -= buflen;
}
assert(channel->recvwindow >= datalen);
channel->recvwindow -= datalen;
assert(channel->recvwindow <= RECV_MAXWINDOW);
/* matt - this might be for later */
/* if (channel->recvwindow < RECV_MINWINDOW) {
send_msg_channel_window_adjust(channel,
RECV_MAXWINDOW - channel->recvwindow);
channel->recvwindow = RECV_MAXWINDOW;
}*/
TRACE(("leave recv_msg_channel_data"));
TRACE(("leave recv_msg_channel_data"))
}
/* Increment the outgoing data window for a channel - the remote end limits
@@ -697,7 +750,7 @@ void recv_msg_channel_window_adjust() {
}
incr = buf_getint(ses.payload);
TRACE(("received window increment %d", incr));
TRACE(("received window increment %d", incr))
incr = MIN(incr, MAX_TRANS_WIN_INCR);
channel->transwindow += incr;
@@ -710,7 +763,7 @@ void recv_msg_channel_window_adjust() {
static void send_msg_channel_window_adjust(struct Channel* channel,
unsigned int incr) {
TRACE(("sending window adjust %d", incr));
TRACE(("sending window adjust %d", incr))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_WINDOW_ADJUST);
@@ -734,7 +787,7 @@ void recv_msg_channel_open() {
int ret;
TRACE(("enter recv_msg_channel_open"));
TRACE(("enter recv_msg_channel_open"))
/* get the packet contents */
type = buf_getstring(ses.payload, &typelen);
@@ -762,17 +815,17 @@ void recv_msg_channel_open() {
}
if (chantype == NULL) {
TRACE(("No matching type for '%s'", type));
TRACE(("No matching type for '%s'", type))
goto failure;
}
TRACE(("matched type '%s'", type));
TRACE(("matched type '%s'", type))
/* create the channel */
channel = newchannel(remotechan, chantype, transwindow, transmaxpacket);
if (channel == NULL) {
TRACE(("newchannel returned NULL"));
TRACE(("newchannel returned NULL"))
goto failure;
}
@@ -785,7 +838,7 @@ void recv_msg_channel_open() {
}
errtype = ret;
deletechannel(channel);
TRACE(("inithandler returned failure %d", ret));
TRACE(("inithandler returned failure %d", ret))
goto failure;
}
}
@@ -796,39 +849,39 @@ void recv_msg_channel_open() {
goto cleanup;
failure:
TRACE(("recv_msg_channel_open failure"));
TRACE(("recv_msg_channel_open failure"))
send_msg_channel_open_failure(remotechan, errtype, "", "");
cleanup:
m_free(type);
TRACE(("leave recv_msg_channel_open"));
TRACE(("leave recv_msg_channel_open"))
}
/* Send a failure message */
void send_msg_channel_failure(struct Channel *channel) {
TRACE(("enter send_msg_channel_failure"));
TRACE(("enter send_msg_channel_failure"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_FAILURE);
buf_putint(ses.writepayload, channel->remotechan);
encrypt_packet();
TRACE(("leave send_msg_channel_failure"));
TRACE(("leave send_msg_channel_failure"))
}
/* Send a success message */
void send_msg_channel_success(struct Channel *channel) {
TRACE(("enter send_msg_channel_success"));
TRACE(("enter send_msg_channel_success"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_SUCCESS);
buf_putint(ses.writepayload, channel->remotechan);
encrypt_packet();
TRACE(("leave send_msg_channel_success"));
TRACE(("leave send_msg_channel_success"))
}
/* Send a channel open failure message, with a corresponding reason
@@ -836,7 +889,7 @@ void send_msg_channel_success(struct Channel *channel) {
static void send_msg_channel_open_failure(unsigned int remotechan,
int reason, const unsigned char *text, const unsigned char *lang) {
TRACE(("enter send_msg_channel_open_failure"));
TRACE(("enter send_msg_channel_open_failure"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN_FAILURE);
@@ -846,7 +899,7 @@ static void send_msg_channel_open_failure(unsigned int remotechan,
buf_putstring(ses.writepayload, lang, strlen((char*)lang));
encrypt_packet();
TRACE(("leave send_msg_channel_open_failure"));
TRACE(("leave send_msg_channel_open_failure"))
}
/* Confirm a channel open, and let the remote end know what number we've
@@ -855,7 +908,7 @@ static void send_msg_channel_open_confirmation(struct Channel* channel,
unsigned int recvwindow,
unsigned int recvmaxpacket) {
TRACE(("enter send_msg_channel_open_confirmation"));
TRACE(("enter send_msg_channel_open_confirmation"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
@@ -865,10 +918,10 @@ static void send_msg_channel_open_confirmation(struct Channel* channel,
buf_putint(ses.writepayload, recvmaxpacket);
encrypt_packet();
TRACE(("leave send_msg_channel_open_confirmation"));
TRACE(("leave send_msg_channel_open_confirmation"))
}
#ifdef USING_LISTENERS
#if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT)
/* Create a new channel, and start the open request. This is intended
* for X11, agent, tcp forwarding, and should be filled with channel-specific
* options, with the calling function calling encrypt_packet() after
@@ -878,18 +931,15 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
struct Channel* chan;
TRACE(("enter send_msg_channel_open_init()"));
TRACE(("enter send_msg_channel_open_init()"))
chan = newchannel(0, type, 0, 0);
if (!chan) {
TRACE(("leave send_msg_channel_open_init() - FAILED in newchannel()"));
TRACE(("leave send_msg_channel_open_init() - FAILED in newchannel()"))
return DROPBEAR_FAILURE;
}
/* set fd non-blocking */
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
TRACE(("leave send_msg_channel_open_init() - FAILED in fcntl()"));
return DROPBEAR_FAILURE;
}
setnonblocking(fd);
chan->infd = chan->outfd = fd;
ses.maxfd = MAX(ses.maxfd, fd);
@@ -903,7 +953,7 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
buf_putint(ses.writepayload, RECV_MAXWINDOW);
buf_putint(ses.writepayload, RECV_MAXPACKET);
TRACE(("leave send_msg_channel_open_init()"));
TRACE(("leave send_msg_channel_open_init()"))
return DROPBEAR_SUCCESS;
}
@@ -915,7 +965,7 @@ void recv_msg_channel_open_confirmation() {
struct Channel * channel;
int ret;
TRACE(("enter recv_msg_channel_open_confirmation"));
TRACE(("enter recv_msg_channel_open_confirmation"))
chan = buf_getint(ses.payload);
channel = getchannel(chan);
@@ -927,19 +977,19 @@ void recv_msg_channel_open_confirmation() {
channel->transwindow = buf_getint(ses.payload);
channel->transmaxpacket = buf_getint(ses.payload);
TRACE(("new chan remote %d localho %d", channel->remotechan, chan));
TRACE(("new chan remote %d localho %d", channel->remotechan, chan))
/* Run the inithandler callback */
if (channel->type->inithandler) {
ret = channel->type->inithandler(channel);
if (ret > 0) {
removechannel(channel);
TRACE(("inithandler returned failure %d", ret));
TRACE(("inithandler returned failure %d", ret))
}
}
TRACE(("leave recv_msg_channel_open_confirmation"));
TRACE(("leave recv_msg_channel_open_confirmation"))
}
/* Notification that our channel open request failed */
@@ -956,23 +1006,24 @@ void recv_msg_channel_open_failure() {
removechannel(channel);
}
#endif /* USING_LISTENERS */
/* close a stdout/stderr fd */
static void closeoutfd(struct Channel * channel, int fd) {
/* don't close it if it is the same as infd,
* unless infd is already set -1 */
TRACE(("enter closeoutfd"));
TRACE(("enter closeoutfd"))
closechanfd(channel, fd, 0);
TRACE(("leave closeoutfd"));
TRACE(("leave closeoutfd"))
}
/* close a stdin fd */
static void closeinfd(struct Channel * channel) {
TRACE(("enter closeinfd"));
TRACE(("enter closeinfd"))
closechanfd(channel, channel->infd, 1);
TRACE(("leave closeinfd"));
TRACE(("leave closeinfd"))
}
/* close a fd, how is 0 for stdout/stderr, 1 for stdin */
@@ -993,15 +1044,17 @@ static void closechanfd(struct Channel *channel, int fd, int how) {
closein = closeout = 1;
}
if (closeout && fd == channel->errfd) {
channel->errfd = FD_CLOSED;
}
if (closeout && fd == channel->outfd) {
channel->outfd = FD_CLOSED;
}
if (closeout && (channel->extrabuf == NULL) && (fd == channel->errfd)) {
channel->errfd = FD_CLOSED;
}
if (closein && fd == channel->infd) {
channel->infd = FD_CLOSED;
}
if (closein && (channel->extrabuf != NULL) && (fd == channel->errfd)) {
channel->errfd = FD_CLOSED;
}
}
#endif /* USING_LISTENERS */

View File

@@ -114,8 +114,8 @@ void send_msg_kexinit() {
encrypt_packet();
ses.dataallowed = 0; /* don't send other packets during kex */
TRACE(("DATAALLOWED=0"));
TRACE(("-> KEXINIT"));
TRACE(("DATAALLOWED=0"))
TRACE(("-> KEXINIT"))
ses.kexstate.sentkexinit = 1;
}
@@ -128,7 +128,7 @@ void send_msg_kexinit() {
/* Bring new keys into use after a key exchange, and let the client know*/
void send_msg_newkeys() {
TRACE(("enter send_msg_newkeys"));
TRACE(("enter send_msg_newkeys"))
/* generate the kexinit request */
CHECKCLEARTOWRITE();
@@ -138,42 +138,42 @@ void send_msg_newkeys() {
/* set up our state */
if (ses.kexstate.recvnewkeys) {
TRACE(("while RECVNEWKEYS=1"));
TRACE(("while RECVNEWKEYS=1"))
gen_new_keys();
kexinitialise(); /* we've finished with this kex */
TRACE((" -> DATAALLOWED=1"));
TRACE((" -> DATAALLOWED=1"))
ses.dataallowed = 1; /* we can send other packets again now */
ses.kexstate.donefirstkex = 1;
} else {
ses.kexstate.sentnewkeys = 1;
TRACE(("SENTNEWKEYS=1"));
TRACE(("SENTNEWKEYS=1"))
}
TRACE(("-> MSG_NEWKEYS"));
TRACE(("leave send_msg_newkeys"));
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"));
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"));
TRACE(("while SENTNEWKEYS=1"))
gen_new_keys();
kexinitialise(); /* we've finished with this kex */
TRACE((" -> DATAALLOWED=1"));
TRACE((" -> DATAALLOWED=1"))
ses.dataallowed = 1; /* we can send other packets again now */
ses.kexstate.donefirstkex = 1;
} else {
TRACE(("RECVNEWKEYS=1"));
TRACE(("RECVNEWKEYS=1"))
ses.kexstate.recvnewkeys = 1;
}
TRACE(("leave recv_msg_newkeys"));
TRACE(("leave recv_msg_newkeys"))
}
@@ -189,7 +189,7 @@ static void kexinitialise() {
struct timeval tv;
TRACE(("kexinitialise()"));
TRACE(("kexinitialise()"))
/* sent/recv'd MSG_KEXINIT */
ses.kexstate.sentkexinit = 0;
@@ -262,7 +262,7 @@ void gen_new_keys() {
unsigned int C2S_keysize, S2C_keysize;
char mactransletter, macrecvletter; /* Client or server specific */
TRACE(("enter gen_new_keys"));
TRACE(("enter gen_new_keys"))
/* the dh_K and hash are the start of all hashes, we make use of that */
sha1_init(&hs);
@@ -329,7 +329,7 @@ void gen_new_keys() {
ses.keys = ses.newkeys;
ses.newkeys = NULL;
TRACE(("leave gen_new_keys"));
TRACE(("leave gen_new_keys"))
}
#ifndef DISABLE_ZLIB
@@ -393,8 +393,8 @@ static void gen_new_zstreams() {
/* Belongs in common_kex.c where it should be moved after review */
void recv_msg_kexinit() {
TRACE(("<- KEXINIT"));
TRACE(("enter recv_msg_kexinit"));
TRACE(("<- KEXINIT"))
TRACE(("enter recv_msg_kexinit"))
/* start the kex hash */
ses.kexhashbuf = buf_new(MAX_KEXHASHBUF);
@@ -402,7 +402,7 @@ void recv_msg_kexinit() {
if (!ses.kexstate.sentkexinit) {
/* we need to send a kex packet */
send_msg_kexinit();
TRACE(("continue recv_msg_kexinit: sent kexinit"));
TRACE(("continue recv_msg_kexinit: sent kexinit"))
}
@@ -459,20 +459,23 @@ void recv_msg_kexinit() {
ses.kexstate.recvkexinit = 1;
// ses.expecting = 0; // client matt
TRACE(("leave recv_msg_kexinit"));
TRACE(("leave recv_msg_kexinit"))
}
/* Initialises and generate one side of the diffie-hellman key exchange values.
* See the ietf-secsh-transport draft, section 6, for details */
/* dh_pub and dh_priv MUST be already initialised */
void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
mp_int dh_p, dh_q, dh_g;
DEF_MP_INT(dh_p);
DEF_MP_INT(dh_q);
DEF_MP_INT(dh_g);
unsigned char randbuf[DH_P_LEN];
int dh_q_len;
TRACE(("enter send_msg_kexdh_reply"));
TRACE(("enter send_msg_kexdh_reply"))
m_mp_init_multi(&dh_g, &dh_p, &dh_q, dh_priv, dh_pub, NULL);
m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL);
/* read the prime and generator*/
if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN)
@@ -616,7 +619,7 @@ static void read_kex_algos() {
erralgo = "kex";
goto error;
}
TRACE(("kex algo %s", algo->name));
TRACE(("kex algo %s", algo->name))
ses.newkeys->algo_kex = algo->val;
/* server_host_key_algorithms */
@@ -626,47 +629,49 @@ static void read_kex_algos() {
erralgo = "hostkey";
goto error;
}
TRACE(("hostkey algo %s", algo->name));
TRACE(("hostkey algo %s", algo->name))
ses.newkeys->algo_hostkey = algo->val;
/* encryption_algorithms_client_to_server */
c2s_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
if (algo == NULL) {
if (c2s_cipher_algo == NULL) {
erralgo = "enc c->s";
goto error;
}
TRACE(("c2s is %s", c2s_cipher_algo->name))
/* encryption_algorithms_server_to_client */
s2c_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
if (algo == NULL) {
if (s2c_cipher_algo == NULL) {
erralgo = "enc s->c";
goto error;
}
TRACE(("s2c is %s", s2c_cipher_algo->name))
/* mac_algorithms_client_to_server */
c2s_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
if (algo == NULL) {
if (c2s_hash_algo == NULL) {
erralgo = "mac c->s";
goto error;
}
/* mac_algorithms_server_to_client */
s2c_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
if (algo == NULL) {
if (s2c_hash_algo == NULL) {
erralgo = "mac s->c";
goto error;
}
/* compression_algorithms_client_to_server */
c2s_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
if (algo == NULL) {
if (c2s_comp_algo == NULL) {
erralgo = "comp c->s";
goto error;
}
/* compression_algorithms_server_to_client */
s2c_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
if (algo == NULL) {
if (s2c_comp_algo == NULL) {
erralgo = "comp s->c";
goto error;
}
@@ -712,12 +717,12 @@ static void read_kex_algos() {
ses.newkeys->trans_algo_comp = s2c_comp_algo->val;
}
TRACE(("enc algo recv %s", algo->name));
TRACE(("enc algo trans %s", algo->name));
TRACE(("mac algo recv %s", algo->name));
TRACE(("mac algo trans %s", algo->name));
TRACE(("comp algo recv %s", algo->name));
TRACE(("comp algo trans %s", algo->name));
TRACE(("enc algo recv %s", algo->name))
TRACE(("enc algo trans %s", algo->name))
TRACE(("mac algo recv %s", algo->name))
TRACE(("mac algo trans %s", algo->name))
TRACE(("comp algo recv %s", algo->name))
TRACE(("comp algo trans %s", algo->name))
/* reserved for future extensions */
buf_getint(ses.payload);

View File

@@ -35,6 +35,8 @@
#include "channel.h"
#include "atomicio.h"
static void checktimeouts();
static int ident_readln(int fd, char* buf, int count);
struct sshsession ses; /* GLOBAL */
@@ -46,13 +48,11 @@ int sessinitdone = 0; /* GLOBAL */
int exitflag = 0; /* GLOBAL */
static void checktimeouts();
static int ident_readln(int fd, char* buf, int count);
/* called only at the start of a session, set up initial state */
void common_session_init(int sock, char* remotehost) {
TRACE(("enter session_init"));
TRACE(("enter session_init"))
ses.remotehost = remotehost;
@@ -72,6 +72,8 @@ void common_session_init(int sock, char* remotehost) {
ses.payload = NULL;
ses.recvseq = 0;
initqueue(&ses.writequeue);
ses.requirenext = SSH_MSG_KEXINIT;
ses.dataallowed = 0; /* don't send data yet, we'll wait until after kex */
ses.ignorenext = 0;
@@ -108,7 +110,7 @@ void common_session_init(int sock, char* remotehost) {
ses.allowprivport = 0;
TRACE(("leave session_init"));
TRACE(("leave session_init"))
}
void session_loop(void(*loophandler)()) {
@@ -160,7 +162,7 @@ void session_loop(void(*loophandler)()) {
if (val == 0) {
/* timeout */
TRACE(("select timeout"));
TRACE(("select timeout"))
continue;
}
@@ -199,11 +201,11 @@ void session_loop(void(*loophandler)()) {
/* clean up a session on exit */
void common_session_cleanup() {
TRACE(("enter 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"));
TRACE(("leave session_cleanup: !sessinitdone"))
return;
}
@@ -213,7 +215,7 @@ void common_session_cleanup() {
chancleanup();
TRACE(("leave session_cleanup"));
TRACE(("leave session_cleanup"))
}
@@ -223,6 +225,7 @@ void session_identification() {
char linebuf[256];
int len = 0;
char done = 0;
int i;
/* write our version string, this blocks */
if (atomicio(write, ses.sock, LOCAL_IDENT "\r\n",
@@ -230,21 +233,34 @@ void session_identification() {
dropbear_exit("Error writing ident string");
}
len = ident_readln(ses.sock, linebuf, 256);
if (len >= 4 && memcmp(linebuf, "SSH-", 4) == 0) {
/* start of line matches */
done = 1;
/* We allow up to 9 lines before the actual version string, to
* account for wrappers/cruft etc. According to the spec only the client
* needs to handle this, but no harm in letting the server handle it too */
for (i = 0; i < 10; i++) {
len = ident_readln(ses.sock, linebuf, sizeof(linebuf));
if (len < 0 && errno != EINTR) {
/* It failed */
break;
}
if (len >= 4 && memcmp(linebuf, "SSH-", 4) == 0) {
/* start of line matches */
done = 1;
break;
}
}
if (!done) {
dropbear_exit("Failed to get client version");
TRACE(("err: %s for '%s'\n", strerror(errno), linebuf))
dropbear_exit("Failed to get remote version");
} else {
/* linebuf is already null terminated */
ses.remoteident = m_malloc(len);
memcpy(ses.remoteident, linebuf, len);
}
TRACE(("remoteident: %s", ses.remoteident));
TRACE(("remoteident: %s", ses.remoteident))
}
@@ -258,7 +274,7 @@ static int ident_readln(int fd, char* buf, int count) {
fd_set fds;
struct timeval timeout;
TRACE(("enter ident_readln"));
TRACE(("enter ident_readln"))
if (count < 1) {
return -1;
@@ -279,7 +295,7 @@ static int ident_readln(int fd, char* buf, int count) {
if (errno == EINTR) {
continue;
}
TRACE(("leave ident_readln: select error"));
TRACE(("leave ident_readln: select error"))
return -1;
}
@@ -297,12 +313,12 @@ static int ident_readln(int fd, char* buf, int count) {
if (errno == EINTR) {
continue; /* not a real error */
}
TRACE(("leave ident_readln: read error"));
TRACE(("leave ident_readln: read error"))
return -1;
}
if (num == 0) {
/* EOF */
TRACE(("leave ident_readln: EOF"));
TRACE(("leave ident_readln: EOF"))
return -1;
}
if (in == '\n') {
@@ -318,7 +334,7 @@ static int ident_readln(int fd, char* buf, int count) {
}
buf[pos] = '\0';
TRACE(("leave ident_readln: return %d", pos+1));
TRACE(("leave ident_readln: return %d", pos+1))
return pos+1;
}
@@ -347,7 +363,7 @@ static void checktimeouts() {
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"));
TRACE(("rekeying after timeout or max data reached"))
send_msg_kexinit();
}
}

View File

@@ -190,7 +190,7 @@ int daemon(int nochdir, int noclose) {
#ifndef HAVE_BASENAME
char *basename(char *path) {
char *basename(const char *path) {
char *foo = strrchr(path, '/');
return ++foo;

View File

@@ -19,7 +19,7 @@ fi
AC_SUBST(LD)
if test -z "$OLDCFLAGS" && test "$GCC" = "yes"; then
AC_MSG_RESULT(No \$CFLAGS set... using "-Os -W -Wall for GCC")
AC_MSG_RESULT(No \$CFLAGS set... using "-Os -W -Wall" for GCC)
CFLAGS="-Os -W -Wall"
fi
@@ -117,6 +117,43 @@ AC_ARG_ENABLE(zlib,
]
)
# Check if pam is needed
AC_ARG_WITH(pam,
[ --with-pam=PATH Use pam in PATH],
[
# option is given
if test -d "$withval/lib"; then
LDFLAGS="-L${withval}/lib ${LDFLAGS}"
else
LDFLAGS="-L${withval} ${LDFLAGS}"
fi
if test -d "$withval/include"; then
CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
else
CPPFLAGS="-I${withval} ${CPPFLAGS}"
fi
]
)
AC_ARG_ENABLE(pam,
[ --enable-pam Try to include PAM support],
[
if test "x$enableval" = "xyes"; then
AC_CHECK_LIB(pam, pam_authenticate, , AC_MSG_ERROR([*** PAM missing - install first or check config.log ***]))
AC_MSG_RESULT(Enabling PAM)
else
AC_DEFINE(DISABLE_PAM,, Use PAM)
AC_MSG_RESULT(Disabling PAM)
fi
],
[
# disable it by default
AC_DEFINE(DISABLE_PAM,, Use PAM)
AC_MSG_RESULT(Disabling PAM)
]
)
AC_ARG_ENABLE(openpty,
[ --disable-openpty Don't use openpty, use alternative method],
[
@@ -169,7 +206,7 @@ AC_ARG_ENABLE(shadow,
# Checks for header files.
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h])
AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h pam/pam_appl.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
@@ -573,5 +610,7 @@ fi
AC_EXEEXT
AC_CONFIG_HEADER(config.h)
AC_OUTPUT(Makefile)
AC_OUTPUT(libtomcrypt/Makefile)
AC_OUTPUT(libtommath/Makefile)
AC_MSG_RESULT()
AC_MSG_RESULT(Now edit options.h to choose features.)

View File

@@ -44,7 +44,8 @@ int main(int argc, char ** argv) {
}
#endif
#ifdef DBMULTI_dbclient
if (strcmp(progname, "dbclient") == 0) {
if (strcmp(progname, "dbclient") == 0
|| strcmp(progname, "ssh") == 0) {
return cli_main(argc, argv);
}
#endif
@@ -71,7 +72,7 @@ int main(int argc, char ** argv) {
"'dropbear' - the Dropbear server\n"
#endif
#ifdef DBMULTI_dbclient
"'dbclient' - the Dropbear client\n"
"'dbclient' or 'ssh' - the Dropbear client\n"
#endif
#ifdef DBMULTI_dropbearkey
"'dropbearkey' - the key generator\n"

100
dbutil.c
View File

@@ -66,7 +66,10 @@ void (*_dropbear_exit)(int exitcode, const char* format, va_list param)
void (*_dropbear_log)(int priority, const char* format, va_list param)
= generic_dropbear_log;
int usingsyslog = 0; /* set by runopts, but required externally to sessions */
#ifdef DEBUG_TRACE
int debug_trace = 0;
#endif
#ifndef DISABLE_SYSLOG
void startsyslog() {
@@ -107,7 +110,7 @@ static void generic_dropbear_exit(int exitcode, const char* format,
exit(exitcode);
}
static void generic_dropbear_log(int priority, const char* format,
static void generic_dropbear_log(int UNUSED(priority), const char* format,
va_list param) {
char printbuf[1024];
@@ -134,6 +137,10 @@ void dropbear_trace(const char* format, ...) {
va_list param;
if (!debug_trace) {
return;
}
va_start(param, format);
fprintf(stderr, "TRACE: ");
vfprintf(stderr, format, param);
@@ -157,17 +164,17 @@ int dropbear_listen(const char* address, const char* port,
int val;
int sock;
TRACE(("enter dropbear_listen"));
TRACE(("enter dropbear_listen"))
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
hints.ai_socktype = SOCK_STREAM;
if (address && address[0] == '\0') {
TRACE(("dropbear_listen: local loopback"));
TRACE(("dropbear_listen: local loopback"))
address = NULL;
} else {
TRACE(("dropbear_listen: not local loopback"));
TRACE(("dropbear_listen: not local loopback"))
hints.ai_flags = AI_PASSIVE;
}
err = getaddrinfo(address, port, &hints, &res0);
@@ -179,7 +186,7 @@ int dropbear_listen(const char* address, const char* port,
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
}
TRACE(("leave dropbear_listen: failed resolving"));
TRACE(("leave dropbear_listen: failed resolving"))
return -1;
}
@@ -196,7 +203,7 @@ int dropbear_listen(const char* address, const char* port,
if (sock < 0) {
err = errno;
TRACE(("socket() failed"));
TRACE(("socket() failed"))
continue;
}
@@ -214,14 +221,14 @@ int dropbear_listen(const char* address, const char* port,
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
err = errno;
close(sock);
TRACE(("bind(%s) failed", port));
TRACE(("bind(%s) failed", port))
continue;
}
if (listen(sock, 20) < 0) {
err = errno;
close(sock);
TRACE(("listen() failed"));
TRACE(("listen() failed"))
continue;
}
@@ -236,12 +243,12 @@ int dropbear_listen(const char* address, const char* port,
len = 20 + strlen(strerror(err));
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error listening: %s", strerror(err));
TRACE(("leave dropbear_listen: failure, %s", strerror(err)));
TRACE(("leave dropbear_listen: failure, %s", strerror(err)))
return -1;
}
}
TRACE(("leave dropbear_listen: success, %d socks bound", nsock));
TRACE(("leave dropbear_listen: success, %d socks bound", nsock))
return nsock;
}
@@ -257,7 +264,7 @@ int connect_remote(const char* remotehost, const char* remoteport,
int sock;
int err;
TRACE(("enter connect_remote"));
TRACE(("enter connect_remote"))
if (errstring != NULL) {
*errstring = NULL;
@@ -275,7 +282,7 @@ int connect_remote(const char* remotehost, const char* remoteport,
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
}
TRACE(("Error resolving: %s", gai_strerror(err)));
TRACE(("Error resolving: %s", gai_strerror(err)))
return -1;
}
@@ -296,14 +303,14 @@ int connect_remote(const char* remotehost, const char* remoteport,
if (errstring != NULL && *errstring == NULL) {
*errstring = m_strdup("Failed non-blocking");
}
TRACE(("Failed non-blocking: %s", strerror(errno)));
TRACE(("Failed non-blocking: %s", strerror(errno)))
continue;
}
}
if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
if (errno == EINPROGRESS && nonblocking) {
TRACE(("Connect in progress"));
TRACE(("Connect in progress"))
break;
} else {
err = errno;
@@ -324,7 +331,7 @@ int connect_remote(const char* remotehost, const char* remoteport,
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error connecting: %s", strerror(err));
}
TRACE(("Error connecting: %s", strerror(err)));
TRACE(("Error connecting: %s", strerror(err)))
} else {
/* Success */
/* (err is used as a dummy var here) */
@@ -336,7 +343,7 @@ int connect_remote(const char* remotehost, const char* remoteport,
m_free(*errstring);
}
TRACE(("leave connect_remote: sock %d\n", sock));
TRACE(("leave connect_remote: sock %d\n", sock))
return sock;
}
@@ -350,6 +357,16 @@ unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {
unsigned int len;
len = sizeof(struct sockaddr_storage);
/* Some platforms such as Solaris 8 require that len is the length
* of the specific structure. */
if (addr->ss_family == AF_INET) {
len = sizeof(struct sockaddr_in);
}
#ifdef AF_INET6
if (addr->ss_family == AF_INET6) {
len = sizeof(struct sockaddr_in6);
}
#endif
ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
sbuf, sizeof(sbuf), NI_NUMERICSERV | NI_NUMERICHOST);
@@ -380,11 +397,27 @@ char* getaddrhostname(struct sockaddr_storage * addr) {
char sbuf[NI_MAXSERV];
int ret;
unsigned int len;
#ifdef DO_HOST_LOOKUP
const int flags = NI_NUMERICSERV;
#else
const int flags = NI_NUMERICHOST | NI_NUMERICSERV;
#endif
len = sizeof(struct sockaddr_storage);
/* Some platforms such as Solaris 8 require that len is the length
* of the specific structure. */
if (addr->ss_family == AF_INET) {
len = sizeof(struct sockaddr_in);
}
#ifdef AF_INET6
if (addr->ss_family == AF_INET6) {
len = sizeof(struct sockaddr_in6);
}
#endif
ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
sbuf, sizeof(sbuf), NI_NUMERICSERV);
sbuf, sizeof(sbuf), flags);
if (ret != 0) {
/* On some systems (Darwin does it) we get EINTR from getnameinfo
@@ -476,7 +509,7 @@ int buf_getline(buffer * line, FILE * authfile) {
int c = EOF;
TRACE(("enter buf_getline"));
TRACE(("enter buf_getline"))
buf_setpos(line, 0);
buf_setlen(line, 0);
@@ -491,25 +524,24 @@ int buf_getline(buffer * line, FILE * authfile) {
buf_putbyte(line, (unsigned char)c);
}
TRACE(("leave getauthline: line too long"));
TRACE(("leave getauthline: line too long"))
/* We return success, but the line length will be zeroed - ie we just
* ignore that line */
buf_setlen(line, 0);
out:
buf_setpos(line, 0);
/* if we didn't read anything before EOF or error, exit */
if (c == EOF && line->pos == 0) {
TRACE(("leave getauthline: failure"));
TRACE(("leave buf_getline: failure"))
return DROPBEAR_FAILURE;
} else {
TRACE(("leave getauthline: success"));
TRACE(("leave buf_getline: success"))
buf_setpos(line, 0);
return DROPBEAR_SUCCESS;
}
TRACE(("leave buf_getline"));
}
#endif
@@ -537,7 +569,7 @@ void * m_malloc(size_t size) {
if (size == 0) {
dropbear_exit("m_malloc failed");
}
ret = malloc(size);
ret = calloc(1, size);
if (ret == NULL) {
dropbear_exit("m_malloc failed");
}
@@ -577,6 +609,8 @@ void * m_realloc(void* ptr, size_t size) {
/* Clear the data, based on the method in David Wheeler's
* "Secure Programming for Linux and Unix HOWTO" */
/* Beware of calling this from within dbutil.c - things might get
* optimised away */
void m_burn(void *data, unsigned int len) {
volatile char *p = data;
@@ -587,3 +621,19 @@ void m_burn(void *data, unsigned int len) {
}
}
void setnonblocking(int fd) {
TRACE(("setnonblocking: %d", fd))
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
if (errno == ENODEV) {
/* Some devices (like /dev/null redirected in)
* can't be set to non-blocking */
TRACE(("ignoring ENODEV for setnonblocking"))
} else {
dropbear_exit("Couldn't set nonblocking");
}
}
TRACE(("leave setnonblocking"))
}

View File

@@ -42,6 +42,7 @@ void dropbear_log(int priority, const char* format, ...);
#ifdef DEBUG_TRACE
void dropbear_trace(const char* format, ...);
void printhex(unsigned char* buf, int len);
extern int debug_trace;
#endif
char * stripcontrol(const char * text);
unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport);
@@ -60,6 +61,7 @@ void * m_realloc(void* ptr, size_t size);
#define m_free(X) __m_free(X); (X) = NULL;
void __m_free(void* ptr);
void m_burn(void* data, unsigned int len);
void setnonblocking(int fd);
/* Used to force mp_ints to be initialised */
#define DEF_MP_INT(X) mp_int X = {0, 0, 0, NULL}

30
debian/changelog vendored
View File

@@ -1,3 +1,33 @@
dropbear (0.45-1) unstable; urgency=high
* New upstream release, various fixes.
-- Matt Johnston <matt@ucc.asn.au> Mon, 7 March 2005 00:44:54 +0800
dropbear (0.44+final-1) unstable; urgency=high
* New upstream release, various fixes.
-- Matt Johnston <matt@ucc.asn.au> Mon, 3 January 2005 00:44:54 +0800
dropbear (0.44test4-1) unstable; urgency=medium
* New upstream beta, various useful fixes.
-- Matt Johnston <matt@ucc.asn.au> Tues, 14 September 2004 21:20:00 +0800
dropbear (0.44test3-1) unstable; urgency=medium
* New upstream beta, various useful fixes.
-- Matt Johnston <matt@ucc.asn.au> Fri, 27 August 2004 22:20:00 +0800
dropbear (0.44test2-1) unstable; urgency=low
* New upstream beta, various minor fixes.
-- Matt Johnston <matt@ucc.asn.au> Tues, 17 August 2004 19:00:00 +0800
dropbear (0.44test1-1) unstable; urgency=low
* Upstream beta 0.44test1

1
debian/compat vendored
View File

@@ -1 +0,0 @@
4

0
debian/conffiles vendored
View File

2
debian/dirs vendored
View File

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

2
debian/docs vendored
View File

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

90
debian/postinst vendored
View File

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

45
debian/postrm vendored
View File

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

0
debian/rules vendored Normal file → Executable file
View File

14
debug.h
View File

@@ -33,10 +33,13 @@
* etc. Don't use this normally, it might cause problems */
/* #define DEBUG_VALGRIND */
/* Define this to print trace statements - very verbose */
/* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
* since the printing does not sanitise strings etc */
/* #define DEBUG_TRACE */
/* Define this to compile in trace debugging printf()s.
* You'll need to run programs with "-v" to turn this on.
*
* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
* since the printing may not sanitise strings etc. This will add a reasonable
* amount to your executable size. */
//#define DEBUG_TRACE
/* All functions writing to the cleartext payload buffer call
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're
@@ -47,6 +50,7 @@
/* Define this, compile with -pg and set GMON_OUT_PREFIX=gmon to get gmon
* output when Dropbear forks. This will allow it gprof to be used.
* It's useful to run dropbear -F, so you don't fork as much */
/* (This is Linux specific) */
/*#define DEBUG_FORKGPROF*/
/* A couple of flags, not usually useful, and mightn't do anything */
@@ -56,7 +60,7 @@
/* you don't need to touch this block */
#ifdef DEBUG_TRACE
#define TRACE(X) (dropbear_trace X)
#define TRACE(X) dropbear_trace X;
#else /*DEBUG_TRACE*/
#define TRACE(X)
#endif /*DEBUG_TRACE*/

81
dropbear.8 Normal file
View File

@@ -0,0 +1,81 @@
.TH dropbear 8
.SH NAME
dropbear \- lightweight SSH2 server
.SH SYNOPSIS
.B dropbear
[\-FEmwsgjki] [\-b
.I banner\fR] [\-d
.I dsskey\fR] [\-r
.I rsakey\fR] [\-p
.IR port ]
.SH DESCRIPTION
.B dropbear
is a SSH 2 server designed to be small enough to be used in small memory
environments, while still being functional and secure enough for general use.
.SH OPTIONS
.TP
.B \-b \fIbanner
bannerfile.
Display the contents of the file
.I banner
before user login (default: none).
.TP
.B \-d \fIdsskey
dsskeyfile.
Use the contents of the file
.I dsskey
for the dss host key (default: /etc/dropbear/dropbear_dss_host_key).
This file is generated with
.BR dropbearkey (8).
.TP
.B \-r \fIrsakey
rsakeyfile.
Use the contents of the file
.I rsakey
for the rsa host key (default: /etc/dropbear/dropbear_rsa_host_key).
This file is generated with
.BR dropbearkey (8).
.TP
.B \-F
Don't fork into background.
.TP
.B \-E
Log to standard error rather than syslog.
.TP
.B \-m
Don't display the message of the day on login.
.TP
.B \-w
Disallow root logins.
.TP
.B \-s
Disable password logins.
.TP
.B \-g
Disable password logins for root.
.TP
.B \-j
Disable local port forwarding.
.TP
.B \-k
Disable remote port forwarding.
.TP
.B \-p \fIport
Listen on specified tcp port
.IR port ;
up to 10 can be specified (default 22 if none specified).
.TP
.B \-i
Service program mode.
Use this option to run
.B dropbear
under TCP/IP servers like inetd, tcpsvd, or tcpserver.
In program mode the \-F option is implied, and \-p options are ignored.
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.br
Gerrit Pape (pape@smarden.org) wrote this manual page.
.SH SEE ALSO
dropbearkey(8)
.P
http://matt.ucc.asn.au/dropbear/dropbear.html

View File

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

47
dropbearkey.8 Normal file
View File

@@ -0,0 +1,47 @@
.TH dropbearkey 8
.SH NAME
dropbearkey \- create private keys for the use with dropbear(8)
.SH SYNOPSIS
.B dropbearkey
\-t
.I type
\-f
.I file
[\-s
.IR bits ]
.SH DESCRIPTION
.B dropbearkey
generates a type
.I rsa
or
.I dss
SSH private key, and saves it to a file for the use with the
.BR dropbear (8)
SSH 2 server.
.SH OPTIONS
.TP
.B \-t \fItype
Type of key to generate.
Must be one of
.I rsa
or
.IR dss .
.TP
.B \-f \fIfile
Write the secret key to the file
.IR file .
.TP
.B \-s \fIbits
Set the key size to
.I bits
bits, should be multiple of 8 (optional).
.SH EXAMPLE
# dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.br
Gerrit Pape (pape@smarden.org) wrote this manual page.
.SH SEE ALSO
dropbear(8)
.P
http://matt.ucc.asn.au/dropbear/dropbear.html

View File

@@ -75,8 +75,11 @@ static void printhelp(char * progname) {
#endif
"-f filename Use filename for the secret key\n"
"-s bits Key size in bits, should be a multiple of 8 (optional)\n"
"-y Just print the publickey and fingerprint for the\n private key in <filename>.\n",
progname);
"-y Just print the publickey and fingerprint for the\n private key in <filename>.\n"
#ifdef DEBUG_TRACE
"-v verbose\n"
#endif
,progname);
}
#if defined(DBMULTI_dropbearkey) || !defined(DROPBEAR_MULTI)
@@ -127,6 +130,11 @@ int main(int argc, char ** argv) {
printhelp(argv[0]);
exit(EXIT_SUCCESS);
break;
#ifdef DEBUG_TRACE
case 'v':
debug_trace = 1;
break;
#endif
default:
fprintf(stderr, "Unknown argument %s\n", argv[i]);
printhelp(argv[0]);
@@ -158,13 +166,13 @@ int main(int argc, char ** argv) {
#ifdef DROPBEAR_RSA
if (strncmp(typetext, "rsa", 3) == 0) {
keytype = DROPBEAR_SIGNKEY_RSA;
TRACE(("type is rsa"));
TRACE(("type is rsa"))
}
#endif
#ifdef DROPBEAR_DSS
if (strncmp(typetext, "dss", 3) == 0) {
keytype = DROPBEAR_SIGNKEY_DSS;
TRACE(("type is dss"));
TRACE(("type is dss"))
}
#endif
}

59
dss.c
View File

@@ -45,7 +45,7 @@
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_get_dss_pub_key(buffer* buf, dss_key *key) {
TRACE(("enter buf_get_dss_pub_key"));
TRACE(("enter buf_get_dss_pub_key"))
assert(key != NULL);
key->p = m_malloc(sizeof(mp_int));
key->q = m_malloc(sizeof(mp_int));
@@ -59,17 +59,17 @@ int buf_get_dss_pub_key(buffer* buf, dss_key *key) {
|| buf_getmpint(buf, key->q) == DROPBEAR_FAILURE
|| buf_getmpint(buf, key->g) == DROPBEAR_FAILURE
|| buf_getmpint(buf, key->y) == DROPBEAR_FAILURE) {
TRACE(("leave buf_get_dss_pub_key: failed reading mpints"));
TRACE(("leave buf_get_dss_pub_key: failed reading mpints"))
return DROPBEAR_FAILURE;
}
if (mp_count_bits(key->p) < MIN_DSS_KEYLEN) {
dropbear_log(LOG_WARNING, "DSS key too short");
TRACE(("leave buf_get_dss_pub_key: short key"));
TRACE(("leave buf_get_dss_pub_key: short key"))
return DROPBEAR_FAILURE;
}
TRACE(("leave buf_get_dss_pub_key: success"));
TRACE(("leave buf_get_dss_pub_key: success"))
return DROPBEAR_SUCCESS;
}
@@ -98,9 +98,9 @@ int buf_get_dss_priv_key(buffer* buf, dss_key *key) {
/* Clear and free the memory used by a public or private key */
void dss_key_free(dss_key *key) {
TRACE(("enter dsa_key_free"));
TRACE(("enter dsa_key_free"))
if (key == NULL) {
TRACE(("enter dsa_key_free: key == NULL"));
TRACE(("enter dsa_key_free: key == NULL"))
return;
}
if (key->p) {
@@ -124,7 +124,7 @@ void dss_key_free(dss_key *key) {
m_free(key->x);
}
m_free(key);
TRACE(("leave dsa_key_free"));
TRACE(("leave dsa_key_free"))
}
/* put the dss public key into the buffer in the required format:
@@ -164,11 +164,14 @@ int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
unsigned char msghash[SHA1_HASH_SIZE];
hash_state hs;
int ret = DROPBEAR_FAILURE;
mp_int val1, val2, val3, val4;
DEF_MP_INT(val1);
DEF_MP_INT(val2);
DEF_MP_INT(val3);
DEF_MP_INT(val4);
char * string = NULL;
int stringlen;
TRACE(("enter buf_dss_verify"));
TRACE(("enter buf_dss_verify"))
assert(key != NULL);
m_mp_init_multi(&val1, &val2, &val3, &val4, NULL);
@@ -192,7 +195,7 @@ int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
goto out;
}
if (mp_cmp(&val1, key->q) != MP_LT) {
TRACE(("verify failed, s' >= q"));
TRACE(("verify failed, s' >= q"))
goto out;
}
/* let val2 = w = (s')^-1 mod q*/
@@ -217,7 +220,7 @@ int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
goto out;
}
if (mp_cmp(&val1, key->q) != MP_LT) {
TRACE(("verify failed, r' >= q"));
TRACE(("verify failed, r' >= q"))
goto out;
}
/* let val4 = u2 = ((r')w) mod q */
@@ -258,6 +261,25 @@ out:
}
#endif /* DROPBEAR_SIGNKEY_VERIFY */
/* 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 */
static 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;
}
/* Sign the data presented with key, writing the signature contents
* to the buffer
*
@@ -281,16 +303,19 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
unsigned char privkeyhash[SHA512_HASH_SIZE];
unsigned char *privkeytmp;
unsigned char proto_k[SHA512_HASH_SIZE];
mp_int dss_protok;
DEF_MP_INT(dss_protok);
#else
unsigned char kbuf[SHA1_HASH_SIZE];
#endif
mp_int dss_k, dss_m;
mp_int dss_temp1, dss_temp2;
mp_int dss_r, dss_s;
DEF_MP_INT(dss_k);
DEF_MP_INT(dss_m);
DEF_MP_INT(dss_temp1);
DEF_MP_INT(dss_temp2);
DEF_MP_INT(dss_r);
DEF_MP_INT(dss_s);
hash_state hs;
TRACE(("enter buf_put_dss_sign"));
TRACE(("enter buf_put_dss_sign"))
assert(key != NULL);
/* hash the data */
@@ -397,7 +422,7 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
/* create the signature to return */
TRACE(("leave buf_put_dss_sign"));
TRACE(("leave buf_put_dss_sign"))
}
#endif /* DROPBEAR_DSS */

View File

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

View File

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

View File

@@ -111,7 +111,7 @@
#include <libgen.h>
#endif
#include "libtomcrypt/mycrypt_custom.h"
#include "libtomcrypt/mycrypt.h"
#include "libtommath/tommath.h"
#include "compat.h"
@@ -128,4 +128,14 @@ typedef u_int16_t uint16_t;
#define LOG_AUTHPRIV LOG_AUTH
#endif
/* so we can avoid warnings about unused params (ie in signal handlers etc) */
#ifdef UNUSED
#elif defined(__GNUC__)
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
#elif defined(__LCLINT__)
# define UNUSED(x) /*@unused@*/ x
#else
# define UNUSED(x) x
#endif
#endif /* _INCLUDES_H_ */

View File

@@ -108,13 +108,10 @@ int import_write(const char *filename, sign_key *key, char *passphrase,
static sign_key *dropbear_read(const char* filename) {
buffer * buf = NULL;
int len, maxlen;
FILE *fp = NULL;
sign_key *ret = NULL;
int type;
buf = buf_new(MAX_PRIVKEY_SIZE);
/* buf_readfile knows about "-" */
if (buf_readfile(buf, filename) == DROPBEAR_FAILURE) {
goto error;
}
@@ -163,11 +160,7 @@ static int dropbear_write(const char*filename, sign_key * key) {
buf = buf_new(MAX_PRIVKEY_SIZE);
buf_put_priv_key(buf, key, keytype);
if (strlen(filename) == 1 && filename[0] == '-') {
fp = stdout;
} else {
fp = fopen(filename, "w");
}
fp = fopen(filename, "w");
if (!fp) {
ret = 0;
goto out;

View File

@@ -93,7 +93,7 @@ struct Listener* new_listener(int socks[], unsigned int nsocks,
/* or create a new one */
if (i == ses.listensize) {
if (ses.listensize > MAX_LISTENERS) {
TRACE(("leave newlistener: too many already"));
TRACE(("leave newlistener: too many already"))
for (j = 0; j < nsocks; j++) {
close(socks[i]);
}
@@ -115,7 +115,7 @@ struct Listener* new_listener(int socks[], unsigned int nsocks,
ses.maxfd = MAX(ses.maxfd, socks[j]);
}
TRACE(("new listener num %d ", i));
TRACE(("new listener num %d ", i))
newlisten = (struct Listener*)m_malloc(sizeof(struct Listener));
newlisten->index = i;

View File

@@ -29,6 +29,8 @@
** loginrec.c: platform-independent login recording and lastlog retrieval
**/
/* For now lastlog code has been removed as it wasn't being used by Dropbear. */
/*
The new login code explained
============================
@@ -177,8 +179,6 @@ int wtmpx_write_entry(struct logininfo *li);
int lastlog_write_entry(struct logininfo *li);
int syslogin_write_entry(struct logininfo *li);
int getlast_entry(struct logininfo *li);
int lastlog_get_entry(struct logininfo *li);
int wtmp_get_entry(struct logininfo *li);
int wtmpx_get_entry(struct logininfo *li);
@@ -221,74 +221,6 @@ login_logout(struct logininfo *li)
return login_write(li);
}
/* login_get_lastlog_time(int) - Retrieve the last login time
*
* Retrieve the last login time for the given uid. Will try to use the
* system lastlog facilities if they are available, but will fall back
* to looking in wtmp/wtmpx if necessary
*
* Returns:
* 0 on failure, or if user has never logged in
* Time in seconds from the epoch if successful
*
* Useful preprocessor symbols:
* DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog
* info
* USE_LASTLOG: If set, indicates the presence of system lastlog
* facilities. If this and DISABLE_LASTLOG are not set,
* try to retrieve lastlog information from wtmp/wtmpx.
*/
unsigned int
login_get_lastlog_time(const int uid)
{
struct logininfo li;
if (login_get_lastlog(&li, uid))
return li.tv_sec;
else
return 0;
}
/* login_get_lastlog(struct logininfo *, int) - Retrieve a lastlog entry
*
* Retrieve a logininfo structure populated (only partially) with
* information from the system lastlog data, or from wtmp/wtmpx if no
* system lastlog information exists.
*
* Note this routine must be given a pre-allocated logininfo.
*
* Returns:
* >0: A pointer to your struct logininfo if successful
* 0 on failure (will use OpenSSH's logging facilities for diagnostics)
*
*/
struct logininfo *
login_get_lastlog(struct logininfo *li, const int uid)
{
struct passwd *pw;
memset(li, '\0', sizeof(*li));
li->uid = uid;
/*
* If we don't have a 'real' lastlog, we need the username to
* reliably search wtmp(x) for the last login (see
* wtmp_get_entry().)
*/
pw = getpwuid(uid);
if (pw == NULL)
dropbear_exit("login_get_lastlog: Cannot find account for uid %i", uid);
/* No MIN_SIZEOF here - we absolutely *must not* truncate the
* username */
strlcpy(li->username, pw->pw_name, sizeof(li->username));
if (getlast_entry(li))
return li;
else
return NULL;
}
/* login_alloc_entry(int, char*, char*, char*) - Allocate and initialise
* a logininfo structure
@@ -450,42 +382,6 @@ login_utmp_only(struct logininfo *li)
}
#endif
/**
** getlast_entry: Call low-level functions to retrieve the last login
** time.
**/
/* take the uid in li and return the last login time */
int
getlast_entry(struct logininfo *li)
{
#ifdef USE_LASTLOG
return(lastlog_get_entry(li));
#else /* !USE_LASTLOG */
#ifdef DISABLE_LASTLOG
/* On some systems we shouldn't even try to obtain last login
* time, e.g. AIX */
return 0;
# else /* DISABLE_LASTLOG */
/* Try to retrieve the last login time from wtmp */
# if defined(USE_WTMP) && (defined(HAVE_STRUCT_UTMP_UT_TIME) || defined(HAVE_STRUCT_UTMP_UT_TV))
/* retrieve last login time from utmp */
return (wtmp_get_entry(li));
# else /* defined(USE_WTMP) && (defined(HAVE_STRUCT_UTMP_UT_TIME) || defined(HAVE_STRUCT_UTMP_UT_TV)) */
/* If wtmp isn't available, try wtmpx */
# if defined(USE_WTMPX) && (defined(HAVE_STRUCT_UTMPX_UT_TIME) || defined(HAVE_STRUCT_UTMPX_UT_TV))
/* retrieve last login time from utmpx */
return (wtmpx_get_entry(li));
# else
/* Give up: No means of retrieving last login time */
return 0;
# endif /* USE_WTMPX && (HAVE_STRUCT_UTMPX_UT_TIME || HAVE_STRUCT_UTMPX_UT_TV) */
# endif /* USE_WTMP && (HAVE_STRUCT_UTMP_UT_TIME || HAVE_STRUCT_UTMP_UT_TV) */
# endif /* DISABLE_LASTLOG */
#endif /* USE_LASTLOG */
}
/*
@@ -1401,8 +1297,8 @@ lastlog_filetype(char *filename)
{
struct stat st;
if (stat(LASTLOG_FILE, &st) != 0) {
dropbear_log(LOG_WARNING, "lastlog_perform_login: Couldn't stat %s: %s", LASTLOG_FILE,
if (stat(filename, &st) != 0) {
dropbear_log(LOG_WARNING, "lastlog_perform_login: Couldn't stat %s: %s", filename,
strerror(errno));
return 0;
}
@@ -1495,45 +1391,4 @@ lastlog_write_entry(struct logininfo *li)
}
}
static void
lastlog_populate_entry(struct logininfo *li, struct lastlog *last)
{
line_fullname(li->line, last->ll_line, sizeof(li->line));
strlcpy(li->hostname, last->ll_host,
MIN_SIZEOF(li->hostname, last->ll_host));
li->tv_sec = last->ll_time;
}
int
lastlog_get_entry(struct logininfo *li)
{
struct lastlog last;
int fd, ret;
if (!lastlog_openseek(li, &fd, O_RDONLY))
return (0);
ret = atomicio(read, fd, &last, sizeof(last));
close(fd);
switch (ret) {
case 0:
memset(&last, '\0', sizeof(last));
/* FALLTHRU */
case sizeof(last):
lastlog_populate_entry(li, &last);
return (1);
case -1:
dropbear_log(LOG_ERR, "Error reading from %s: %s",
LASTLOG_FILE, strerror(errno));
return (0);
default:
dropbear_log(LOG_ERR, "Error reading from %s: Expecting %d, got %d",
LASTLOG_FILE, sizeof(last), ret);
return (0);
}
/* NOTREACHED */
return (0);
}
#endif /* USE_LASTLOG */

View File

@@ -150,7 +150,6 @@ struct logininfo {
/** '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 */
@@ -178,14 +177,6 @@ int login_log_entry(struct logininfo *li);
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);

View File

@@ -1,26 +1,6 @@
/*
* Dropbear - a SSH2 server
*
/* Dropbear SSH
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
* All rights reserved. See LICENSE for the license. */
#ifndef _OPTIONS_H_
#define _OPTIONS_H_
@@ -30,8 +10,8 @@
* parts are to allow for commandline -DDROPBEAR_XXX options etc.
******************************************************************/
#ifndef DROPBEAR_PORT
#define DROPBEAR_PORT 22
#ifndef DROPBEAR_DEFPORT
#define DROPBEAR_DEFPORT "22"
#endif
/* Default hostkey paths - these can be specified on the command line */
@@ -116,9 +96,7 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
* 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 */
/* Whether to do reverse DNS lookups. */
#define DO_HOST_LOOKUP
/* Whether to print the message of the day (MOTD). This doesn't add much code
@@ -130,27 +108,45 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
#define MOTD_FILENAME "/etc/motd"
#endif
/* Authentication types to enable, at least one required.
/* Authentication Types - at least one required.
RFC Draft requires pubkey auth, and recommends password */
/* Note: PAM auth is quite simple, and only works for PAM modules which just do
* a simple "Login: " "Password: " (you can edit the strings in svr-authpam.c).
* It's useful for systems like OS X where standard password crypts don't work,
* but there's an interface via a PAM module - don't bother using it otherwise.
* You can't enable both PASSWORD and PAM. */
#define ENABLE_SVR_PASSWORD_AUTH
/*#define ENABLE_SVR_PAM_AUTH*/
#define ENABLE_SVR_PUBKEY_AUTH
#define ENABLE_CLI_PASSWORD_AUTH
#define ENABLE_CLI_PUBKEY_AUTH
/* Random device to use - you must specify _one only_.
* DEV_RANDOM is recommended on hosts with a good /dev/urandom, otherwise use
* 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 */
/* Define this (as well as ENABLE_CLI_PASSWORD_AUTH) to allow the use of
* a helper program for the ssh client. The helper program should be
* specified in the SSH_ASKPASS environment variable, and dbclient
* should be run with DISPLAY set and no tty. The program should
* return the password on standard output */
/*#define ENABLE_CLI_ASKPASS_HELPER*/
/*#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
/* Random device to use - define either DROPBEAR_RANDOM_DEV or
* DROPBEAR_PRNGD_SOCKET.
* DROPBEAR_RANDOM_DEV is recommended on hosts with a good /dev/(u)random,
* otherwise use run prngd (or egd if you want), specifying the socket.
* The device will be queried for a few dozen bytes of seed a couple of times
* per session (or more for very long-lived sessions). */
/* If you are lacking entropy on the system then using /dev/urandom
* will prevent Dropbear from blocking on the device. This could
* however significantly reduce the security of your ssh connections
* if the PRNG state becomes guessable - make sure you know what you are
* doing if you change this. */
#define DROPBEAR_RANDOM_DEV "/dev/random"
/* prngd must be manually set up to produce output */
/*#define DROPBEAR_PRNGD_SOCKET "/var/run/dropbear-rng"*/
/* Specify the number of clients we will allow to be connected but
* not yet authenticated. After this limit, connections are rejected */
@@ -193,7 +189,7 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
*******************************************************************/
#ifndef DROPBEAR_VERSION
#define DROPBEAR_VERSION "0.44test1"
#define DROPBEAR_VERSION "0.45"
#endif
#define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
@@ -223,8 +219,6 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
#define MAX_BANNER_SIZE 2000 /* this is 25*80 chars, any more is foolish */
#define MAX_BANNER_LINES 20 /* How many lines the client will display */
#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
@@ -309,6 +303,8 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
#define DROPBEAR_MAX_SOCKS 2 /* IPv4, IPv6 are all we'll get for now. Revisit
in a few years time.... */
#define DROPBEAR_MAX_CLI_PASS 1024
#ifndef ENABLE_X11FWD
#define DISABLE_X11FWD
#endif
@@ -342,6 +338,18 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
#define DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */
#endif
#if defined(ENABLE_SVR_PASSWORD_AUTH) && defined(ENABLE_SVR_PAM_AUTH)
#error "You can't turn on PASSWORD and PAM auth both at once. Fix it in options.h"
#endif
#if defined(DROPBEAR_RANDOM_DEV) && defined(DROPBEAR_PRNGD_SOCKET)
#error "You can't turn on DROPBEAR_PRNGD_SOCKET and DROPBEAR_RANDOM_DEV at once"
#endif
#if !defined(DROPBEAR_RANDOM_DEV) && !defined(DROPBEAR_PRNGD_SOCKET)
#error "You must choose one of DROPBEAR_PRNGD_SOCKET or DROPBEAR_RANDOM_DEV in options.h"
#endif
/* We use dropbear_client and dropbear_server as shortcuts to avoid redundant
* code, if we're just compiling as client or server */
#if defined(DROPBEAR_SERVER) && defined(DROPBEAR_CLIENT)

View File

@@ -52,7 +52,7 @@ void write_packet() {
int len, written;
buffer * writebuf = NULL;
TRACE(("enter write_packet"));
TRACE(("enter write_packet"))
assert(!isempty(&ses.writequeue));
/* Get the next buffer in the queue of encrypted packets to write*/
@@ -65,7 +65,7 @@ void write_packet() {
if (written < 0) {
if (errno == EINTR) {
TRACE(("leave writepacket: EINTR"));
TRACE(("leave writepacket: EINTR"))
return;
} else {
dropbear_exit("error writing");
@@ -86,7 +86,7 @@ void write_packet() {
buf_incrpos(writebuf, written);
}
TRACE(("leave write_packet"));
TRACE(("leave write_packet"))
}
/* Non-blocking function reading available portion of a packet into the
@@ -98,7 +98,7 @@ void read_packet() {
unsigned int maxlen;
unsigned char blocksize;
TRACE(("enter read_packet"));
TRACE(("enter read_packet"))
blocksize = ses.keys->recv_algo_crypt->blocksize;
if (ses.readbuf == NULL || ses.readbuf->len < blocksize) {
@@ -111,7 +111,7 @@ void read_packet() {
/* 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"));
TRACE(("leave read_packet: packetinit done"))
return;
}
}
@@ -128,7 +128,7 @@ void read_packet() {
if (len < 0) {
if (errno == EINTR || errno == EAGAIN) {
TRACE(("leave read_packet: EINTR or EAGAIN"));
TRACE(("leave read_packet: EINTR or EAGAIN"))
return;
} else {
dropbear_exit("error reading: %s", strerror(errno));
@@ -143,7 +143,7 @@ void read_packet() {
/* The main select() loop process_packet() to
* handle the packet contents... */
}
TRACE(("leave read_packet"));
TRACE(("leave read_packet"))
}
/* Function used to read the initial portion of a packet, and determine the
@@ -176,7 +176,7 @@ static void read_packet_init() {
}
if (len < 0) {
if (errno == EINTR) {
TRACE(("leave read_packet_init: EINTR"));
TRACE(("leave read_packet_init: EINTR"))
return;
}
dropbear_exit("error reading: %s", strerror(errno));
@@ -230,7 +230,7 @@ void decrypt_packet() {
unsigned int padlen;
unsigned int len;
TRACE(("enter decrypt_packet"));
TRACE(("enter decrypt_packet"))
blocksize = ses.keys->recv_algo_crypt->blocksize;
macsize = ses.keys->recv_algo_mac->hashsize;
@@ -305,7 +305,7 @@ void decrypt_packet() {
ses.recvseq++;
TRACE(("leave decrypt_packet"));
TRACE(("leave decrypt_packet"))
}
/* Checks the mac in hashbuf, for the data in readbuf.
@@ -413,8 +413,8 @@ void encrypt_packet() {
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]));
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;
@@ -514,7 +514,7 @@ void encrypt_packet() {
ses.kexstate.datatrans += writebuf->len;
ses.transseq++;
TRACE(("leave encrypt_packet()"));
TRACE(("leave encrypt_packet()"))
}
@@ -526,7 +526,7 @@ static void writemac(buffer * outputbuffer, buffer * clearwritebuf) {
unsigned long hashsize;
hmac_state hmac;
TRACE(("enter writemac"));
TRACE(("enter writemac"))
macsize = ses.keys->trans_algo_mac->hashsize;
@@ -561,7 +561,7 @@ static void writemac(buffer * outputbuffer, buffer * clearwritebuf) {
}
buf_incrwritepos(outputbuffer, macsize);
}
TRACE(("leave writemac"));
TRACE(("leave writemac"))
}
#ifndef DISABLE_ZLIB
@@ -572,7 +572,7 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
unsigned int endpos = src->pos + len;
int result;
TRACE(("enter buf_compress"));
TRACE(("enter buf_compress"))
while (1) {
@@ -606,6 +606,6 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
buf_resize(dest, dest->size + ZLIB_COMPRESS_INCR);
}
TRACE(("leave buf_compress"));
TRACE(("leave buf_compress"))
}
#endif

View File

@@ -45,10 +45,10 @@ void process_packet() {
unsigned char type;
unsigned int i;
TRACE(("enter process_packet"));
TRACE(("enter process_packet"))
type = buf_getbyte(ses.payload);
TRACE(("process_packet: packet type = %d", type));
TRACE(("process_packet: packet type = %d", type))
ses.lastpacket = type;
@@ -57,12 +57,12 @@ void process_packet() {
case SSH_MSG_IGNORE:
case SSH_MSG_DEBUG:
TRACE(("received SSH_MSG_IGNORE or SSH_MSG_DEBUG"));
TRACE(("received SSH_MSG_IGNORE or SSH_MSG_DEBUG"))
goto out;
case SSH_MSG_UNIMPLEMENTED:
/* debugging XXX */
TRACE(("SSH_MSG_UNIMPLEMENTED"));
TRACE(("SSH_MSG_UNIMPLEMENTED"))
dropbear_exit("received SSH_MSG_UNIMPLEMENTED");
case SSH_MSG_DISCONNECT:
@@ -87,7 +87,7 @@ void process_packet() {
/* 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));
TRACE(("Ignoring packet, type = %d", type))
ses.ignorenext = 0;
goto out;
}
@@ -115,7 +115,7 @@ void process_packet() {
/* TODO do something more here? */
TRACE(("preauth unknown packet"));
TRACE(("preauth unknown packet"))
recv_unimplemented();
out:
@@ -123,7 +123,7 @@ out:
buf_free(ses.payload);
ses.payload = NULL;
TRACE(("leave process_packet"));
TRACE(("leave process_packet"))
}

View File

@@ -52,7 +52,7 @@ void* dequeue(struct Queue* queue) {
} else {
queue->head = NULL;
queue->tail = NULL;
TRACE(("empty queue dequeing"));
TRACE(("empty queue dequeing"))
}
m_free(oldhead);
@@ -70,7 +70,7 @@ void enqueue(struct Queue* queue, void* item) {
struct Link* newlink;
TRACE(("enter enqueue"));
TRACE(("enter enqueue"))
newlink = (struct Link*)m_malloc(sizeof(struct Link));
newlink->item = item;
@@ -85,5 +85,5 @@ void enqueue(struct Queue* queue, void* item) {
queue->head = newlink;
}
queue->count++;
TRACE(("leave enqueue"));
TRACE(("leave enqueue"))
}

View File

@@ -38,7 +38,7 @@ unsigned char hashpool[SHA1_HASH_SIZE];
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
/* The basic setup is we read some data from /dev/(u)random 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.
@@ -53,22 +53,22 @@ static void readrand(unsigned char* buf, unsigned int buflen) {
int readfd;
unsigned int readpos;
int readlen;
#ifdef DROPBEAR_EGD
#ifdef DROPBEAR_PRNGD_SOCKET
struct sockaddr_un egdsock;
char egdcmd[2];
#endif
#ifdef DROPBEAR_DEV_URANDOM
readfd = open(DEV_URANDOM, O_RDONLY);
#ifdef DROPBEAR_RANDOM_DEV
readfd = open(DROPBEAR_RANDOM_DEV, O_RDONLY);
if (readfd < 0) {
dropbear_exit("couldn't open random device");
}
#endif
#ifdef DROPBEAR_EGD
#ifdef DROPBEAR_PRNGD_SOCKET
memset((void*)&egdsock, 0x0, sizeof(egdsock));
egdsock.sun_family = AF_UNIX;
strlcpy(egdsock.sun_path, DROPBEAR_EGD_SOCKET,
strlcpy(egdsock.sun_path, DROPBEAR_PRNGD_SOCKET,
sizeof(egdsock.sun_path));
readfd = socket(PF_UNIX, SOCK_STREAM, 0);
@@ -105,7 +105,7 @@ static void readrand(unsigned char* buf, unsigned int buflen) {
close (readfd);
}
/* initialise the prng from /dev/urandom or prngd */
/* initialise the prng from /dev/(u)random or prngd */
void seedrandom() {
unsigned char readbuf[INIT_SEED_SIZE];
@@ -159,21 +159,3 @@ void genrandom(unsigned char* buf, unsigned int len) {
}
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;
}

55
rsa.c
View File

@@ -47,7 +47,7 @@ static mp_int * rsa_pad_em(rsa_key * key,
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_get_rsa_pub_key(buffer* buf, rsa_key *key) {
TRACE(("enter buf_get_rsa_pub_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));
@@ -60,7 +60,7 @@ int buf_get_rsa_pub_key(buffer* buf, rsa_key *key) {
if (buf_getmpint(buf, key->e) == DROPBEAR_FAILURE
|| buf_getmpint(buf, key->n) == DROPBEAR_FAILURE) {
TRACE(("leave buf_get_rsa_pub_key: failure"));
TRACE(("leave buf_get_rsa_pub_key: failure"))
return DROPBEAR_FAILURE;
}
@@ -69,7 +69,7 @@ int buf_get_rsa_pub_key(buffer* buf, rsa_key *key) {
return DROPBEAR_FAILURE;
}
TRACE(("leave buf_get_rsa_pub_key: success"));
TRACE(("leave buf_get_rsa_pub_key: success"))
return DROPBEAR_SUCCESS;
}
@@ -81,17 +81,17 @@ int buf_get_rsa_priv_key(buffer* buf, rsa_key *key) {
assert(key != NULL);
TRACE(("enter buf_get_rsa_priv_key"));
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"));
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"));
TRACE(("leave buf_get_rsa_priv_key: d: ret == DROPBEAR_FAILURE"))
return DROPBEAR_FAILURE;
}
@@ -105,17 +105,17 @@ int buf_get_rsa_priv_key(buffer* buf, rsa_key *key) {
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"));
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"));
TRACE(("leave buf_get_rsa_priv_key: q: ret == DROPBEAR_FAILURE"))
return DROPBEAR_FAILURE;
}
}
TRACE(("leave buf_get_rsa_priv_key"));
TRACE(("leave buf_get_rsa_priv_key"))
return DROPBEAR_SUCCESS;
}
@@ -123,10 +123,10 @@ int buf_get_rsa_priv_key(buffer* buf, rsa_key *key) {
/* Clear and free the memory used by a public or private key */
void rsa_key_free(rsa_key *key) {
TRACE(("enter rsa_key_free"));
TRACE(("enter rsa_key_free"))
if (key == NULL) {
TRACE(("leave rsa_key_free: key == NULL"));
TRACE(("leave rsa_key_free: key == NULL"))
return;
}
if (key->d) {
@@ -150,7 +150,7 @@ void rsa_key_free(rsa_key *key) {
m_free(key->q);
}
m_free(key);
TRACE(("leave rsa_key_free"));
TRACE(("leave rsa_key_free"))
}
/* Put the public rsa key into the buffer in the required format:
@@ -161,21 +161,21 @@ void rsa_key_free(rsa_key *key) {
*/
void buf_put_rsa_pub_key(buffer* buf, rsa_key *key) {
TRACE(("enter buf_put_rsa_pub_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"));
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"));
TRACE(("enter buf_put_rsa_priv_key"))
assert(key != NULL);
buf_put_rsa_pub_key(buf, key);
@@ -190,7 +190,7 @@ void buf_put_rsa_priv_key(buffer* buf, rsa_key *key) {
}
TRACE(("leave buf_put_rsa_priv_key"));
TRACE(("leave buf_put_rsa_priv_key"))
}
@@ -201,11 +201,12 @@ int buf_rsa_verify(buffer * buf, rsa_key *key, const unsigned char* data,
unsigned int len) {
unsigned int slen;
mp_int rsa_s, rsa_mdash;
DEF_MP_INT(rsa_s);
DEF_MP_INT(rsa_mdash);
mp_int *rsa_em = NULL;
int ret = DROPBEAR_FAILURE;
TRACE(("enter buf_rsa_verify"));
TRACE(("enter buf_rsa_verify"))
assert(key != NULL);
@@ -213,19 +214,19 @@ int buf_rsa_verify(buffer * buf, rsa_key *key, const unsigned char* data,
slen = buf_getint(buf);
if (slen != (unsigned int)mp_unsigned_bin_size(key->n)) {
TRACE(("bad size"));
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) {
TRACE(("failed reading rsa_s"));
TRACE(("failed reading rsa_s"))
goto out;
}
/* check that s <= n-1 */
if (mp_cmp(&rsa_s, key->n) != MP_LT) {
TRACE(("s > n-1"));
TRACE(("s > n-1"))
goto out;
}
@@ -233,13 +234,13 @@ int buf_rsa_verify(buffer * buf, rsa_key *key, const unsigned char* data,
rsa_em = rsa_pad_em(key, data, len);
if (mp_exptmod(&rsa_s, key->e, key->n, &rsa_mdash) != MP_OKAY) {
TRACE(("failed exptmod rsa_s"));
TRACE(("failed exptmod rsa_s"))
goto out;
}
if (mp_cmp(rsa_em, &rsa_mdash) == MP_EQ) {
/* signature is valid */
TRACE(("success!"));
TRACE(("success!"))
ret = DROPBEAR_SUCCESS;
}
@@ -249,7 +250,7 @@ out:
m_free(rsa_em);
}
mp_clear_multi(&rsa_mdash, &rsa_s, NULL);
TRACE(("leave buf_rsa_verify: ret %d", ret));
TRACE(("leave buf_rsa_verify: ret %d", ret))
return ret;
}
@@ -262,10 +263,10 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
unsigned int nsize, ssize;
unsigned int i;
mp_int rsa_s;
DEF_MP_INT(rsa_s);
mp_int *rsa_em = NULL;
TRACE(("enter buf_put_rsa_sign"));
TRACE(("enter buf_put_rsa_sign"))
assert(key != NULL);
rsa_em = rsa_pad_em(key, data, len);
@@ -305,7 +306,7 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
#endif
TRACE(("leave buf_put_rsa_sign"));
TRACE(("leave buf_put_rsa_sign"))
}
/* Creates the message value as expected by PKCS, see rfc2437 etc */

View File

@@ -52,7 +52,7 @@ typedef struct svr_runopts {
int usingsyslog;
/* ports is an array of the portcount listening ports */
uint16_t *ports;
char *ports[DROPBEAR_MAX_PORTS];
unsigned int portcount;
int inetdmode;
@@ -81,6 +81,7 @@ typedef struct svr_runopts {
extern svr_runopts svr_opts;
void svr_getopts(int argc, char ** argv);
void loadhostkeys();
/* Uncompleted XXX matt */
typedef struct cli_runopts {

6
scp.c
View File

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

View File

@@ -36,6 +36,7 @@
#include "listener.h"
#include "packet.h"
#include "tcpfwd.h"
#include "chansession.h"
extern int sessinitdone; /* Is set to 0 somewhere */
extern int exitflag;
@@ -43,19 +44,16 @@ extern int exitflag;
void common_session_init(int sock, char* remotehost);
void session_loop(void(*loophandler)());
void common_session_cleanup();
void checktimeouts();
void session_identification();
/* Server */
void svr_session(int sock, int childpipe, char *remotehost);
void svr_session(int sock, int childpipe, char *remotehost, char *addrstring);
void svr_dropbear_exit(int exitcode, const char* format, va_list param);
void svr_dropbear_log(int priority, const char* format, va_list param);
/* Client */
void cli_session(int sock, char *remotehost);
void cli_dropbear_exit(int exitcode, const char* format, va_list param);
void cli_dropbear_log(int priority, const char* format, va_list param);
void cli_session_cleanup();
void cleantext(unsigned char* dirtytext);
@@ -160,12 +158,11 @@ struct sshsession {
/* TCP forwarding - where manage listeners */
#ifdef USING_LISTENERS
struct Listener ** listeners;
unsigned int listensize;
/* Whether to allow binding to privileged ports (<1024). This doesn't
* really belong here, but nowhere else fits nicely */
#endif
int allowprivport;
};
@@ -179,6 +176,13 @@ struct serversession {
struct ChildPid * childpids; /* array of mappings childpid<->channel */
unsigned int childpidsize;
/* Used to avoid a race in the exit returncode handling - see
* svr-chansession.c for details */
struct exitinfo lastexit;
/* The numeric address they connected from, used for logging */
char * addrstring;
};
typedef enum {
@@ -212,12 +216,16 @@ struct clientsession {
int tty_raw_mode; /* Whether we're in raw mode (and have to clean up) */
struct termios saved_tio;
int stdincopy;
int stdinflags;
int winchange; /* Set to 1 when a windowchange signal happens */
int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
for the last type of auth we tried */
struct PubkeyList *lastpubkey;
int retval; /* What the command exit status was - we emulate it */
#if 0
TODO
struct AgentkeyList *agentkeys; /* Keys to use for public-key auth */

View File

@@ -94,7 +94,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
int keytype;
int ret = DROPBEAR_FAILURE;
TRACE(("enter buf_get_pub_key"));
TRACE(("enter buf_get_pub_key"))
ident = buf_getstring(buf, &len);
keytype = signkey_type_from_name(ident, len);
@@ -130,7 +130,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
}
#endif
TRACE(("leave buf_get_pub_key"));
TRACE(("leave buf_get_pub_key"))
return ret;
@@ -146,13 +146,14 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
int keytype;
int ret = DROPBEAR_FAILURE;
TRACE(("enter buf_get_priv_key"));
TRACE(("enter buf_get_priv_key"))
ident = buf_getstring(buf, &len);
keytype = signkey_type_from_name(ident, len);
m_free(ident);
if (*type != DROPBEAR_SIGNKEY_ANY && *type != keytype) {
TRACE(("wrong key type: %d %d", *type, keytype))
return DROPBEAR_FAILURE;
}
@@ -182,7 +183,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
}
#endif
TRACE(("leave buf_get_priv_key"));
TRACE(("leave buf_get_priv_key"))
return ret;
@@ -193,7 +194,7 @@ void buf_put_pub_key(buffer* buf, sign_key *key, int type) {
buffer *pubkeys;
TRACE(("enter buf_put_pub_key"));
TRACE(("enter buf_put_pub_key"))
pubkeys = buf_new(MAX_PUBKEY_SIZE);
#ifdef DROPBEAR_DSS
@@ -215,26 +216,26 @@ void buf_put_pub_key(buffer* buf, sign_key *key, int type) {
pubkeys->len);
buf_free(pubkeys);
TRACE(("leave buf_put_pub_key"));
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));
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"));
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"));
TRACE(("leave buf_put_priv_key: rsa done"))
return;
}
#endif
@@ -243,7 +244,7 @@ void buf_put_priv_key(buffer* buf, sign_key *key, int type) {
void sign_key_free(sign_key *key) {
TRACE(("enter sign_key_free"));
TRACE(("enter sign_key_free"))
#ifdef DROPBEAR_DSS
dss_key_free(key->dsskey);
@@ -255,7 +256,7 @@ void sign_key_free(sign_key *key) {
#endif
m_free(key);
TRACE(("leave sign_key_free"));
TRACE(("leave sign_key_free"))
}
static char hexdig(unsigned char x) {
@@ -392,7 +393,7 @@ int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
unsigned char * ident = NULL;
unsigned int identlen = 0;
TRACE(("enter buf_verify"));
TRACE(("enter buf_verify"))
bloblen = buf_getint(buf);
ident = buf_getstring(buf, &identlen);
@@ -441,17 +442,17 @@ int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen,
if (base64_decode(buf_getptr(line, len), len,
buf_getwriteptr(decodekey, decodekey->size),
&decodekeylen) != CRYPT_OK) {
TRACE(("checkpubkey: base64 decode failed"));
TRACE(("checkpubkey: base64 decode failed"))
goto out;
}
TRACE(("checkpubkey: base64_decode success"));
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"));
TRACE(("checkpubkey: compare failed"))
goto out;
}
@@ -460,7 +461,7 @@ int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen,
filealgolen = buf_getint(decodekey);
filealgo = buf_getptr(decodekey, filealgolen);
if (filealgolen != algolen || memcmp(filealgo, algoname, algolen) != 0) {
TRACE(("checkpubkey: algo match failed"));
TRACE(("checkpubkey: algo match failed"))
goto out;
}

View File

@@ -73,9 +73,7 @@ int agentreq(struct ChanSess * chansess) {
}
/* set non-blocking */
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
goto fail;
}
setnonblocking(fd);
/* pass if off to listener */
chansess->agentlistener = new_listener( &fd, 1, 0, chansess,
@@ -97,13 +95,13 @@ fail:
/* accepts a connection on the forwarded socket and opens a new channel for it
* back to the client */
/* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
static void agentaccept(struct Listener * listener, int sock) {
static void agentaccept(struct Listener *UNUSED(listener), int sock) {
int fd;
fd = accept(sock, NULL, NULL);
if (fd < 0) {
TRACE(("accept failed"));
TRACE(("accept failed"))
return;
}

View File

@@ -47,7 +47,7 @@ algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
/* 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));
TRACE(("buf_match_algo: %s", algolist))
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
goto out; /* just a sanity check, no other use */
}

View File

@@ -55,7 +55,7 @@ static void authclear() {
#ifdef ENABLE_SVR_PUBKEY_AUTH
ses.authstate.authtypes |= AUTH_TYPE_PUBKEY;
#endif
#ifdef ENABLE_SVR_PASSWORD_AUTH
#if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
if (!svr_opts.noauthpass) {
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD;
}
@@ -67,9 +67,9 @@ static void authclear() {
* ignore this, but possibly serves as a legal "no trespassing" sign */
static void send_msg_userauth_banner() {
TRACE(("enter send_msg_userauth_banner"));
TRACE(("enter send_msg_userauth_banner"))
if (svr_opts.banner == NULL) {
TRACE(("leave send_msg_userauth_banner: banner is NULL"));
TRACE(("leave send_msg_userauth_banner: banner is NULL"))
return;
}
@@ -84,7 +84,7 @@ static void send_msg_userauth_banner() {
buf_free(svr_opts.banner);
svr_opts.banner = NULL;
TRACE(("leave send_msg_userauth_banner"));
TRACE(("leave send_msg_userauth_banner"))
}
/* handle a userauth request, check validity, pass to password or pubkey
@@ -94,11 +94,11 @@ void recv_msg_userauth_request() {
unsigned char *username = NULL, *servicename = NULL, *methodname = NULL;
unsigned int userlen, servicelen, methodlen;
TRACE(("enter recv_msg_userauth_request"));
TRACE(("enter recv_msg_userauth_request"))
/* ignore packets if auth is already done */
if (ses.authstate.authdone == 1) {
TRACE(("leave recv_msg_userauth_request: authdone already"));
TRACE(("leave recv_msg_userauth_request: authdone already"))
return;
}
@@ -128,7 +128,7 @@ void recv_msg_userauth_request() {
if (methodlen == AUTH_METHOD_NONE_LEN &&
strncmp(methodname, AUTH_METHOD_NONE,
AUTH_METHOD_NONE_LEN) == 0) {
TRACE(("recv_msg_userauth_request: 'none' request"));
TRACE(("recv_msg_userauth_request: 'none' request"))
send_msg_userauth_failure(0, 0);
goto out;
}
@@ -136,7 +136,7 @@ void recv_msg_userauth_request() {
/* check username is good before continuing */
if (checkusername(username, userlen) == DROPBEAR_FAILURE) {
/* username is invalid/no shell/etc - send failure */
TRACE(("sending checkusername failure"));
TRACE(("sending checkusername failure"))
send_msg_userauth_failure(0, 1);
goto out;
}
@@ -154,6 +154,19 @@ void recv_msg_userauth_request() {
}
#endif
#ifdef ENABLE_SVR_PAM_AUTH
if (!svr_opts.noauthpass &&
!(svr_opts.norootpass && ses.authstate.pw->pw_uid == 0) ) {
/* user wants to try password auth */
if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
strncmp(methodname, AUTH_METHOD_PASSWORD,
AUTH_METHOD_PASSWORD_LEN) == 0) {
svr_auth_pam();
goto out;
}
}
#endif
#ifdef ENABLE_SVR_PUBKEY_AUTH
/* user wants to try pubkey auth */
if (methodlen == AUTH_METHOD_PUBKEY_LEN &&
@@ -182,7 +195,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
char* listshell = NULL;
char* usershell = NULL;
TRACE(("enter checkusername"));
TRACE(("enter checkusername"))
if (userlen > MAX_USERNAME_LEN) {
return DROPBEAR_FAILURE;
}
@@ -192,7 +205,8 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
strcmp(username, ses.authstate.username) != 0) {
/* the username needs resetting */
if (ses.authstate.username != NULL) {
dropbear_log(LOG_WARNING, "client trying multiple usernames");
dropbear_log(LOG_WARNING, "client trying multiple usernames from %s",
svr_ses.addrstring);
m_free(ses.authstate.username);
}
authclear();
@@ -203,9 +217,10 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
/* check that user exists */
if (ses.authstate.pw == NULL) {
TRACE(("leave checkusername: user '%s' doesn't exist", username));
TRACE(("leave checkusername: user '%s' doesn't exist", username))
dropbear_log(LOG_WARNING,
"login attempt for nonexistent user");
"login attempt for nonexistent user from %s",
svr_ses.addrstring);
send_msg_userauth_failure(0, 1);
return DROPBEAR_FAILURE;
}
@@ -215,7 +230,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
/* check for non-root if desired */
if (svr_opts.norootlogin && ses.authstate.pw->pw_uid == 0) {
TRACE(("leave checkusername: root login disabled"));
TRACE(("leave checkusername: root login disabled"))
dropbear_log(LOG_WARNING, "root login rejected");
send_msg_userauth_failure(0, 1);
return DROPBEAR_FAILURE;
@@ -223,14 +238,14 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
/* check for an empty password */
if (ses.authstate.pw->pw_passwd[0] == '\0') {
TRACE(("leave checkusername: empty pword"));
TRACE(("leave checkusername: empty pword"))
dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected",
ses.authstate.printableuser);
send_msg_userauth_failure(0, 1);
return DROPBEAR_FAILURE;
}
TRACE(("shell is %s", ses.authstate.pw->pw_shell));
TRACE(("shell is %s", ses.authstate.pw->pw_shell))
/* check that the shell is set */
usershell = ses.authstate.pw->pw_shell;
@@ -244,7 +259,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
* is platform-specific) */
setusershell();
while ((listshell = getusershell()) != NULL) {
TRACE(("test shell is '%s'", listshell));
TRACE(("test shell is '%s'", listshell))
if (strcmp(listshell, usershell) == 0) {
/* have a match */
goto goodshell;
@@ -252,7 +267,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
}
/* no matching shell */
endusershell();
TRACE(("no matching shell"));
TRACE(("no matching shell"))
dropbear_log(LOG_WARNING, "user '%s' has invalid shell, rejected",
ses.authstate.printableuser);
send_msg_userauth_failure(0, 1);
@@ -260,10 +275,10 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
goodshell:
endusershell();
TRACE(("matching shell"));
TRACE(("matching shell"))
TRACE(("uid = %d", ses.authstate.pw->pw_uid));
TRACE(("leave checkusername"));
TRACE(("uid = %d", ses.authstate.pw->pw_uid))
TRACE(("leave checkusername"))
return DROPBEAR_SUCCESS;
}
@@ -277,7 +292,7 @@ void send_msg_userauth_failure(int partial, int incrfail) {
buffer *typebuf = NULL;
TRACE(("enter send_msg_userauth_failure"));
TRACE(("enter send_msg_userauth_failure"))
CHECKCLEARTOWRITE();
@@ -316,23 +331,24 @@ void send_msg_userauth_failure(int partial, int incrfail) {
if (ses.authstate.failcount >= MAX_AUTH_TRIES) {
char * userstr;
/* XXX - send disconnect ? */
TRACE(("Max auth tries reached, exiting"));
TRACE(("Max auth tries reached, exiting"))
if (ses.authstate.printableuser == NULL) {
userstr = "is invalid";
} else {
userstr = ses.authstate.printableuser;
}
dropbear_exit("Max auth tries reached - user %s", userstr);
dropbear_exit("Max auth tries reached - user '%s' from %s",
userstr, svr_ses.addrstring);
}
TRACE(("leave send_msg_userauth_failure"));
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"));
TRACE(("enter send_msg_userauth_success"))
CHECKCLEARTOWRITE();
@@ -340,6 +356,8 @@ void send_msg_userauth_success() {
encrypt_packet();
ses.authstate.authdone = 1;
ses.connecttimeout = 0;
if (ses.authstate.pw->pw_uid == 0) {
ses.allowprivport = 1;
@@ -350,6 +368,6 @@ void send_msg_userauth_success() {
* logins - a nasty situation. */
m_close(svr_ses.childpipe);
TRACE(("leave send_msg_userauth_success"));
TRACE(("leave send_msg_userauth_success"))
}

230
svr-authpam.c Normal file
View File

@@ -0,0 +1,230 @@
/*
* Dropbear SSH
*
* Copyright (c) 2004 Martin Carlsson
* Portions (c) 2004 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
/* Validates a user password using PAM */
#include "includes.h"
#include "session.h"
#include "buffer.h"
#include "dbutil.h"
#include "auth.h"
#if defined(HAVE_SECURITY_PAM_APPL_H)
#include <security/pam_appl.h>
#elif defined (HAVE_PAM_PAM_APPL_H)
#include <pam/pam_appl.h>
#endif
#ifdef ENABLE_SVR_PAM_AUTH
struct UserDataS {
char* user;
char* passwd;
};
/* PAM conversation function - for now we only handle one message */
int
pamConvFunc(int num_msg,
const struct pam_message **msg,
struct pam_response **respp,
void *appdata_ptr) {
int rc = PAM_SUCCESS;
struct pam_response* resp = NULL;
struct UserDataS* userDatap = (struct UserDataS*) appdata_ptr;
const char* message = (*msg)->msg;
TRACE(("enter pamConvFunc"))
if (num_msg != 1) {
/* If you're getting here - Dropbear probably can't support your pam
* modules. This whole file is a bit of a hack around lack of
* asynchronocity in PAM anyway */
dropbear_log(LOG_INFO, "pamConvFunc() called with >1 messages: not supported.");
return PAM_CONV_ERR;
}
TRACE(("msg_style is %d", (*msg)->msg_style))
if (message) {
TRACE(("message is '%s'", message))
} else {
TRACE(("null message"))
}
switch((*msg)->msg_style) {
case PAM_PROMPT_ECHO_OFF:
if (strcmp(message, "Password:") != 0) {
TRACE(("PAM_PROMPT_ECHO_OFF: unrecognized prompt"))
rc = PAM_CONV_ERR;
break;
}
/* You have to read the PAM module-writers' docs (do we look like
* module writers? no.) to find out that the module will
* free the pam_response and its resp element - ie we _must_ malloc
* it here */
resp = (struct pam_response*) m_malloc(sizeof(struct pam_response));
memset(resp, 0, sizeof(struct pam_response));
resp->resp = m_strdup(userDatap->passwd);
m_burn(userDatap->passwd, strlen(userDatap->passwd));
(*respp) = resp;
break;
case PAM_PROMPT_ECHO_ON:
if ((strcmp(message, "login: " ) != 0)
&& (strcmp(message, "login:" ) != 0)
&& (strcmp(message, "Please enter username: " ) != 0)) {
TRACE(("PAM_PROMPT_ECHO_ON: unrecognized prompt"))
rc = PAM_CONV_ERR;
break;
}
/* You have to read the PAM module-writers' docs (do we look like
* module writers? no.) to find out that the module will
* free the pam_response and its resp element - ie we _must_ malloc
* it here */
resp = (struct pam_response*) m_malloc(sizeof(struct pam_response));
memset(resp, 0, sizeof(struct pam_response));
resp->resp = m_strdup(userDatap->user);
TRACE(("userDatap->user='%s'", userDatap->user))
(*respp) = resp;
break;
default:
TRACE(("Unknown message type"))
rc = PAM_CONV_ERR;
break;
}
TRACE(("leave pamConvFunc, rc %d", rc))
return rc;
}
/* Process a password auth request, sending success or failure messages as
* appropriate. To the client it looks like it's doing normal password auth (as
* opposed to keyboard-interactive or something), so the pam module has to be
* fairly standard (ie just "what's your username, what's your password, OK").
*
* Keyboard interactive would be a lot nicer, but since PAM is synchronous, it
* gets very messy trying to send the interactive challenges, and read the
* interactive responses, over the network. */
void svr_auth_pam() {
struct UserDataS userData = {NULL, NULL};
struct pam_conv pamConv = {
pamConvFunc,
&userData /* submitted to pamvConvFunc as appdata_ptr */
};
pam_handle_t* pamHandlep = NULL;
unsigned char * password = NULL;
unsigned int passwordlen;
int rc = PAM_SUCCESS;
unsigned char changepw;
/* check if client wants to change password */
changepw = buf_getbyte(ses.payload);
if (changepw) {
/* not implemented by this server */
send_msg_userauth_failure(0, 1);
goto cleanup;
}
password = buf_getstring(ses.payload, &passwordlen);
/* used to pass data to the PAM conversation function - don't bother with
* strdup() etc since these are touched only by our own conversation
* function (above) which takes care of it */
userData.user = ses.authstate.printableuser;
userData.passwd = password;
/* Init pam */
if ((rc = pam_start("sshd", NULL, &pamConv, &pamHandlep)) != PAM_SUCCESS) {
dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s\n",
rc, pam_strerror(pamHandlep, rc));
goto cleanup;
}
/* just to set it to something */
if ((rc = pam_set_item(pamHandlep, PAM_TTY, "ssh") != PAM_SUCCESS)) {
dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s\n",
rc, pam_strerror(pamHandlep, rc));
goto cleanup;
}
(void) pam_fail_delay(pamHandlep, 0 /* musec_delay */);
/* (void) pam_set_item(pamHandlep, PAM_FAIL_DELAY, (void*) pamDelayFunc); */
if ((rc = pam_authenticate(pamHandlep, 0)) != PAM_SUCCESS) {
dropbear_log(LOG_WARNING, "pam_authenticate() failed, rc=%d, %s\n",
rc, pam_strerror(pamHandlep, rc));
dropbear_log(LOG_WARNING,
"bad PAM password attempt for '%s' from %s",
ses.authstate.printableuser,
svr_ses.addrstring);
send_msg_userauth_failure(0, 1);
goto cleanup;
}
if ((rc = pam_acct_mgmt(pamHandlep, 0)) != PAM_SUCCESS) {
dropbear_log(LOG_WARNING, "pam_acct_mgmt() failed, rc=%d, %s\n",
rc, pam_strerror(pamHandlep, rc));
dropbear_log(LOG_WARNING,
"bad PAM password attempt for '%s' from %s",
ses.authstate.printableuser,
svr_ses.addrstring);
send_msg_userauth_failure(0, 1);
goto cleanup;
}
/* successful authentication */
dropbear_log(LOG_NOTICE, "PAM password auth succeeded for '%s' from %s",
ses.authstate.printableuser,
svr_ses.addrstring);
send_msg_userauth_success();
cleanup:
if (password != NULL) {
m_burn(password, passwordlen);
m_free(password);
}
if (pamHandlep != NULL) {
TRACE(("pam_end"))
(void) pam_end(pamHandlep, 0 /* pam_status */);
}
}
#endif /* ENABLE_SVR_PAM_AUTH */

View File

@@ -80,10 +80,6 @@ void svr_auth_password() {
password = buf_getstring(ses.payload, &passwordlen);
/* clear the buffer containing the password */
buf_incrpos(ses.payload, -passwordlen - 4);
m_burn(buf_getptr(ses.payload, passwordlen + 4), passwordlen + 4);
/* the first bytes of passwdcrypt are the salt */
testcrypt = crypt((char*)password, passwdcrypt);
m_burn(password, passwordlen);
@@ -92,13 +88,15 @@ void svr_auth_password() {
if (strcmp(testcrypt, passwdcrypt) == 0) {
/* successful authentication */
dropbear_log(LOG_NOTICE,
"password auth succeeded for '%s'",
ses.authstate.printableuser);
"password auth succeeded for '%s' from %s",
ses.authstate.printableuser,
svr_ses.addrstring);
send_msg_userauth_success();
} else {
dropbear_log(LOG_WARNING,
"bad password attempt for '%s'",
ses.authstate.printableuser);
"bad password attempt for '%s' from %s",
ses.authstate.printableuser,
svr_ses.addrstring);
send_msg_userauth_failure(0, 1);
}

View File

@@ -60,7 +60,7 @@ void svr_auth_pubkey() {
char* fp = NULL;
int type = -1;
TRACE(("enter pubkeyauth"));
TRACE(("enter pubkeyauth"))
/* 0 indicates user just wants to check if key can be used, 1 is an
* actual attempt*/
@@ -104,13 +104,13 @@ void svr_auth_pubkey() {
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",
ses.authstate.printableuser, fp);
"pubkey auth succeeded for '%s' with key %s from %s",
ses.authstate.printableuser, fp, svr_ses.addrstring);
send_msg_userauth_success();
} else {
dropbear_log(LOG_WARNING,
"pubkey auth bad signature for '%s' with key %s",
ses.authstate.printableuser, fp);
"pubkey auth bad signature for '%s' with key %s from %s",
ses.authstate.printableuser, fp, svr_ses.addrstring);
send_msg_userauth_failure(0, 1);
}
m_free(fp);
@@ -127,7 +127,7 @@ out:
sign_key_free(key);
key = NULL;
}
TRACE(("leave pubkeyauth"));
TRACE(("leave pubkeyauth"))
}
/* Reply that the key is valid for auth, this is sent when the user sends
@@ -136,7 +136,7 @@ out:
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"));
TRACE(("enter send_msg_userauth_pk_ok"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_PK_OK);
@@ -144,7 +144,7 @@ static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen,
buf_putstring(ses.writepayload, keyblob, keybloblen);
encrypt_packet();
TRACE(("leave send_msg_userauth_pk_ok"));
TRACE(("leave send_msg_userauth_pk_ok"))
}
@@ -160,19 +160,19 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
buffer * line = NULL;
unsigned int len, pos;
TRACE(("enter checkpubkey"));
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'",
ses.authstate.printableuser);
"pubkey auth attempt with unknown algo for '%s' from %s",
ses.authstate.printableuser, svr_ses.addrstring);
goto out;
}
/* check file permissions, also whether file exists */
if (checkpubkeyperms() == DROPBEAR_FAILURE) {
TRACE(("bad authorized_keys permissions, or file doesn't exist"));
TRACE(("bad authorized_keys permissions, or file doesn't exist"))
goto out;
}
@@ -190,7 +190,7 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
if (authfile == NULL) {
goto out;
}
TRACE(("checkpubkey: opened authorized_keys OK"));
TRACE(("checkpubkey: opened authorized_keys OK"))
line = buf_new(MAX_AUTHKEYS_LINE);
@@ -199,12 +199,12 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
if (buf_getline(line, authfile) == DROPBEAR_FAILURE) {
/* EOF reached */
TRACE(("checkpubkey: authorized_keys EOF reached"));
TRACE(("checkpubkey: authorized_keys EOF reached"))
break;
}
if (line->len < MIN_AUTHKEYS_LINE) {
TRACE(("checkpubkey: line too short"));
TRACE(("checkpubkey: line too short"))
continue; /* line is too short for it to be a valid key */
}
@@ -217,7 +217,7 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
/* check for space (' ') character */
if (buf_getbyte(line) != ' ') {
TRACE(("checkpubkey: space character expected, isn't there"));
TRACE(("checkpubkey: space character expected, isn't there"))
continue;
}
@@ -229,7 +229,7 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
buf_setpos(line, pos);
buf_setlen(line, line->pos + len);
TRACE(("checkpubkey: line pos = %d len = %d", line->pos, line->len));
TRACE(("checkpubkey: line pos = %d len = %d", line->pos, line->len))
ret = cmp_base64_key(keyblob, keybloblen, algo, algolen, line);
if (ret == DROPBEAR_SUCCESS) {
@@ -248,7 +248,7 @@ out:
buf_free(line);
}
m_free(filename);
TRACE(("leave checkpubkey: ret=%d", ret));
TRACE(("leave checkpubkey: ret=%d", ret))
return ret;
}
@@ -264,7 +264,7 @@ static int checkpubkeyperms() {
int ret = DROPBEAR_FAILURE;
unsigned int len;
TRACE(("enter checkpubkeyperms"));
TRACE(("enter checkpubkeyperms"))
assert(ses.authstate.pw);
if (ses.authstate.pw->pw_dir == NULL) {
@@ -303,7 +303,7 @@ static int checkpubkeyperms() {
out:
m_free(filename);
TRACE(("leave checkpubkeyperms"));
TRACE(("leave checkpubkeyperms"))
return ret;
}
@@ -313,24 +313,24 @@ out:
static int checkfileperm(char * filename) {
struct stat filestat;
TRACE(("enter checkfileperm(%s)", filename));
TRACE(("enter checkfileperm(%s)", filename))
if (stat(filename, &filestat) != 0) {
TRACE(("leave checkfileperm: stat() != 0"));
TRACE(("leave checkfileperm: stat() != 0"))
return DROPBEAR_FAILURE;
}
/* check ownership - user or root only*/
if (filestat.st_uid != ses.authstate.pw->pw_uid
&& filestat.st_uid != 0) {
TRACE(("leave checkfileperm: wrong ownership"));
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"));
TRACE(("leave checkfileperm: wrong perms"))
return DROPBEAR_FAILURE;
}
TRACE(("leave checkfileperm: success"));
TRACE(("leave checkfileperm: success"))
return DROPBEAR_SUCCESS;
}

View File

@@ -55,6 +55,10 @@ static int newchansess(struct Channel *channel);
static void chansessionrequest(struct Channel *channel);
static void send_exitsignalstatus(struct Channel *channel);
static void send_msg_chansess_exitstatus(struct Channel * channel,
struct ChanSess * chansess);
static void send_msg_chansess_exitsignal(struct Channel * channel,
struct ChanSess * chansess);
static int sesscheckclose(struct Channel *channel);
static void get_termmodes(struct ChanSess *chansess);
@@ -64,46 +68,65 @@ extern char** environ;
static int sesscheckclose(struct Channel *channel) {
struct ChanSess *chansess = (struct ChanSess*)channel->typedata;
return chansess->exited;
return chansess->exit.exitpid >= 0;
}
/* handler for childs exiting, store the state for return to the client */
static void sesssigchild_handler(int dummy) {
/* Handler for childs exiting, store the state for return to the client */
/* There's a particular race we have to watch out for: if the forked child
* executes, exits, and this signal-handler is called, all before the parent
* gets to run, then the childpids[] array won't have the pid in it. Hence we
* use the svr_ses.lastexit struct to hold the exit, which is then compared by
* the parent when it runs. This work correctly at least in the case of a
* single shell spawned (ie the usual case) */
static void sesssigchild_handler(int UNUSED(dummy)) {
int status;
pid_t pid;
unsigned int i;
struct ChanSess * chansess;
struct sigaction sa_chld;
struct exitinfo *exit = NULL;
TRACE(("enter sigchld handler"));
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;
}
exit = &svr_ses.childpids[i].chansess->exit;
break;
}
}
/* If the pid wasn't matched, then we might have hit the race mentioned
* above. So we just store the info for the parent to deal with */
if (i == svr_ses.childpidsize) {
exit = &svr_ses.lastexit;
}
exit->exitpid = pid;
if (WIFEXITED(status)) {
exit->exitstatus = WEXITSTATUS(status);
}
if (WIFSIGNALED(status)) {
exit->exitsignal = WTERMSIG(status);
#if !defined(AIX) && defined(WCOREDUMP)
exit->exitcore = WCOREDUMP(status);
#else
exit->exitcore = 0;
#endif
} else {
/* we use this to determine how pid exited */
exit->exitsignal = -1;
}
exit = NULL;
}
sa_chld.sa_handler = sesssigchild_handler;
sa_chld.sa_flags = SA_NOCLDSTOP;
sigaction(SIGCHLD, &sa_chld, NULL);
TRACE(("leave sigchld handler"));
TRACE(("leave sigchld handler"))
}
/* send the exit status or the signal causing termination for a session */
@@ -112,8 +135,8 @@ static void send_exitsignalstatus(struct Channel *channel) {
struct ChanSess *chansess = (struct ChanSess*)channel->typedata;
if (chansess->exited) {
if (chansess->exitsignal > 0) {
if (chansess->exit.exitpid >= 0) {
if (chansess->exit.exitsignal > 0) {
send_msg_chansess_exitsignal(channel, chansess);
} else {
send_msg_chansess_exitstatus(channel, chansess);
@@ -125,8 +148,8 @@ static void send_exitsignalstatus(struct Channel *channel) {
static void send_msg_chansess_exitstatus(struct Channel * channel,
struct ChanSess * chansess) {
assert(chansess->exited);
assert(chansess->exitsignal == -1);
assert(chansess->exit.exitpid != -1);
assert(chansess->exit.exitsignal == -1);
CHECKCLEARTOWRITE();
@@ -134,7 +157,7 @@ static void send_msg_chansess_exitstatus(struct Channel * channel,
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);
buf_putint(ses.writepayload, chansess->exit.exitstatus);
encrypt_packet();
@@ -147,15 +170,15 @@ static void send_msg_chansess_exitsignal(struct Channel * channel,
int i;
char* signame = NULL;
assert(chansess->exited);
assert(chansess->exitsignal > 0);
assert(chansess->exit.exitpid != -1);
assert(chansess->exit.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) {
if (signames[i].signal == chansess->exit.exitsignal) {
signame = signames[i].name;
break;
}
@@ -170,7 +193,7 @@ static void send_msg_chansess_exitsignal(struct Channel * channel,
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_putbyte(ses.writepayload, chansess->exit.exitcore);
buf_putstring(ses.writepayload, "", 0); /* error msg */
buf_putstring(ses.writepayload, "", 0); /* lang */
@@ -194,7 +217,7 @@ static int newchansess(struct Channel *channel) {
chansess->tty = NULL;
chansess->term = NULL;
chansess->exited = 0;
chansess->exit.exitpid = -1;
channel->typedata = chansess;
@@ -225,9 +248,9 @@ static void closechansess(struct Channel *channel) {
send_exitsignalstatus(channel);
TRACE(("enter closechansess"));
TRACE(("enter closechansess"))
if (chansess == NULL) {
TRACE(("leave closechansess: chansess == NULL"));
TRACE(("leave closechansess: chansess == NULL"))
return;
}
@@ -257,8 +280,8 @@ static void closechansess(struct Channel *channel) {
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));
TRACE(("closing pid %d", svr_ses.childpids[i].pid))
TRACE(("exitpid = %d", chansess->exit.exitpid))
svr_ses.childpids[i].pid = -1;
svr_ses.childpids[i].chansess = NULL;
}
@@ -266,7 +289,7 @@ static void closechansess(struct Channel *channel) {
m_free(chansess);
TRACE(("leave closechansess"));
TRACE(("leave closechansess"))
}
/* Handle requests for a channel. These can be execution requests,
@@ -279,19 +302,19 @@ static void chansessionrequest(struct Channel *channel) {
int ret = 1;
struct ChanSess *chansess;
TRACE(("enter chansessionrequest"));
TRACE(("enter chansessionrequest"))
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?*/
TRACE(("leave chansessionrequest: type too long")) /* XXX send error?*/
goto out;
}
chansess = (struct ChanSess*)channel->typedata;
assert(chansess != NULL);
TRACE(("type is %s", type));
TRACE(("type is %s", type))
if (strcmp(type, "window-change") == 0) {
ret = sessionwinchange(chansess);
@@ -328,7 +351,7 @@ out:
}
m_free(type);
TRACE(("leave chansessionrequest"));
TRACE(("leave chansessionrequest"))
}
@@ -398,7 +421,7 @@ static void get_termmodes(struct ChanSess *chansess) {
const struct TermCode * termcode;
unsigned int len;
TRACE(("enter get_termmodes"));
TRACE(("enter get_termmodes"))
/* Term modes */
/* We'll ignore errors and continue if we can't set modes.
@@ -415,7 +438,8 @@ static void get_termmodes(struct ChanSess *chansess) {
}
if (len == 0) {
TRACE(("leave get_termmodes: empty terminal modes string"));
TRACE(("leave get_termmodes: empty terminal modes string"))
return;
}
while (((opcode = buf_getbyte(ses.payload)) != 0x00) && opcode <= 159) {
@@ -477,7 +501,7 @@ static void get_termmodes(struct ChanSess *chansess) {
if (tcsetattr(chansess->master, TCSANOW, &termio) < 0) {
dropbear_log(LOG_INFO, "error setting terminal attributes");
}
TRACE(("leave get_termmodes"));
TRACE(("leave get_termmodes"))
}
/* Set up a session pty which will be used to execute the shell or program.
@@ -488,18 +512,20 @@ static int sessionpty(struct ChanSess * chansess) {
unsigned int termlen;
unsigned char namebuf[65];
TRACE(("enter sessionpty"));
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"));
TRACE(("leave sessionpty: term len too long"))
return DROPBEAR_FAILURE;
}
/* allocate the pty */
assert(chansess->master == -1); /* haven't already got one */
if (chansess->master != -1) {
dropbear_exit("multiple pty requests");
}
if (pty_allocate(&chansess->master, &chansess->slave, namebuf, 64) == 0) {
TRACE(("leave sessionpty: failed to allocate pty"));
TRACE(("leave sessionpty: failed to allocate pty"))
return DROPBEAR_FAILURE;
}
@@ -516,7 +542,7 @@ static int sessionpty(struct ChanSess * chansess) {
/* Read the terminal modes */
get_termmodes(chansess);
TRACE(("leave sessionpty"));
TRACE(("leave sessionpty"))
return DROPBEAR_SUCCESS;
}
@@ -530,7 +556,7 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
unsigned int cmdlen;
int ret;
TRACE(("enter sessioncommand"));
TRACE(("enter sessioncommand"))
if (chansess->cmd != NULL) {
/* Note that only one command can _succeed_. The client might try
@@ -585,8 +611,9 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) {
int outfds[2];
int errfds[2];
pid_t pid;
unsigned int i;
TRACE(("enter noptycommand"));
TRACE(("enter noptycommand"))
/* redirect stdin/stdout/stderr */
if (pipe(infds) != 0)
@@ -609,7 +636,7 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) {
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"));
TRACE(("leave noptycommand: error redirecting FDs"))
return DROPBEAR_FAILURE;
}
@@ -625,12 +652,24 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) {
} else {
/* parent */
TRACE(("continue noptycommand: parent"));
TRACE(("continue noptycommand: parent"))
chansess->pid = pid;
/* add a child pid */
addchildpid(chansess, pid);
if (svr_ses.lastexit.exitpid != -1) {
/* The child probably exited and the signal handler triggered
* possibly before we got around to adding the childpid. So we fill
* out it's data manually */
for (i = 0; i < svr_ses.childpidsize; i++) {
if (svr_ses.childpids[i].pid == pid) {
svr_ses.childpids[i].chansess->exit = svr_ses.lastexit;
svr_ses.lastexit.exitpid = -1;
}
}
}
close(infds[FDIN]);
close(outfds[FDOUT]);
close(errfds[FDOUT]);
@@ -641,16 +680,15 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) {
ses.maxfd = MAX(ses.maxfd, channel->outfd);
ses.maxfd = MAX(ses.maxfd, channel->errfd);
if ((fcntl(channel->outfd, F_SETFL, O_NONBLOCK) < 0) ||
(fcntl(channel->infd, F_SETFL, O_NONBLOCK) < 0) ||
(fcntl(channel->errfd, F_SETFL, O_NONBLOCK) < 0)) {
dropbear_exit("Couldn't set nonblocking");
}
setnonblocking(channel->outfd);
setnonblocking(channel->infd);
setnonblocking(channel->errfd);
}
#undef FDIN
#undef FDOUT
TRACE(("leave noptycommand"));
TRACE(("leave noptycommand"))
return DROPBEAR_SUCCESS;
}
@@ -668,7 +706,7 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
char *hushpath = NULL;
#endif
TRACE(("enter ptycommand"));
TRACE(("enter ptycommand"))
/* we need to have a pty allocated */
if (chansess->master == -1 || chansess->tty == NULL) {
@@ -691,7 +729,7 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
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"));
TRACE(("leave ptycommand: error redirecting filedesc"))
return DROPBEAR_FAILURE;
}
@@ -739,7 +777,7 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
} else {
/* parent */
TRACE(("continue ptycommand: parent"));
TRACE(("continue ptycommand: parent"))
chansess->pid = pid;
/* add a child pid */
@@ -751,13 +789,11 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
/* don't need to set stderr here */
ses.maxfd = MAX(ses.maxfd, chansess->master);
if (fcntl(chansess->master, F_SETFL, O_NONBLOCK) < 0) {
dropbear_exit("Couldn't set nonblocking");
}
setnonblocking(chansess->master);
}
TRACE(("leave ptycommand"));
TRACE(("leave ptycommand"))
return DROPBEAR_SUCCESS;
}
@@ -925,6 +961,7 @@ void svr_chansessinitialise() {
svr_ses.childpids[0].pid = -1; /* unused */
svr_ses.childpids[0].chansess = NULL;
svr_ses.childpidsize = 1;
svr_ses.lastexit.exitpid = -1; /* Nothing has exited yet */
sa_chld.sa_handler = sesssigchild_handler;
sa_chld.sa_flags = SA_NOCLDSTOP;
if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) {

View File

@@ -44,9 +44,9 @@ static void send_msg_kexdh_reply(mp_int *dh_e);
* that function, then brings the new keys into use */
void recv_msg_kexdh_init() {
mp_int dh_e;
DEF_MP_INT(dh_e);
TRACE(("enter recv_msg_kexdh_init"));
TRACE(("enter recv_msg_kexdh_init"))
if (!ses.kexstate.recvkexinit) {
dropbear_exit("Premature kexdh_init message received");
}
@@ -60,7 +60,7 @@ void recv_msg_kexdh_init() {
send_msg_newkeys();
ses.requirenext = SSH_MSG_NEWKEYS;
TRACE(("leave recv_msg_kexdh_init"));
TRACE(("leave recv_msg_kexdh_init"))
}
/* Generate our side of the diffie-hellman key exchange value (dh_f), and
@@ -71,9 +71,11 @@ void recv_msg_kexdh_init() {
* See the ietf-secsh-transport draft, section 6, for details */
static void send_msg_kexdh_reply(mp_int *dh_e) {
mp_int dh_y, dh_f;
DEF_MP_INT(dh_y);
DEF_MP_INT(dh_f);
TRACE(("enter send_msg_kexdh_reply"));
TRACE(("enter send_msg_kexdh_reply"))
m_mp_init_multi(&dh_y, &dh_f, NULL);
gen_kexdh_vals(&dh_f, &dh_y);
@@ -97,6 +99,6 @@ static void send_msg_kexdh_reply(mp_int *dh_e) {
/* the SSH_MSG_KEXDH_REPLY is done */
encrypt_packet();
TRACE(("leave send_msg_kexdh_reply"));
TRACE(("leave send_msg_kexdh_reply"))
}

View File

@@ -33,8 +33,12 @@ static int listensockets(int *sock, int sockcount, int *maxfd);
static void sigchld_handler(int dummy);
static void sigsegv_handler(int);
static void sigintterm_handler(int fish);
#ifdef INETD_MODE
static void main_inetd();
#endif
#ifdef NON_INETD_MODE
static void main_noinetd();
#endif
static void commonsetup();
static int childpipes[MAX_UNAUTH_CLIENTS];
@@ -90,7 +94,6 @@ static void main_inetd() {
/* In case our inetd was lax in logging source addresses */
addrstring = getaddrstring(&remoteaddr, 1);
dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
m_free(addrstring);
/* Don't check the return value - it may just fail since inetd has
* already done setsid() after forking (xinetd on Darwin appears to do
@@ -100,7 +103,7 @@ static void main_inetd() {
/* Start service program
* -1 is a dummy childpipe, just something we can close() without
* mattering. */
svr_session(0, -1, getaddrhostname(&remoteaddr));
svr_session(0, -1, getaddrhostname(&remoteaddr), addrstring);
/* notreached */
}
@@ -123,7 +126,6 @@ void main_noinetd() {
pid_t childpid;
int childpipe[2];
struct sigaction sa_chld;
/* fork */
if (svr_opts.forkbg) {
int closefds = 0;
@@ -139,6 +141,7 @@ void main_noinetd() {
commonsetup();
/* should be done after syslog is working */
if (svr_opts.forkbg) {
dropbear_log(LOG_INFO, "Running in background");
@@ -244,7 +247,7 @@ void main_noinetd() {
}
if (pipe(childpipe) < 0) {
TRACE(("error creating child pipe"));
TRACE(("error creating child pipe"))
close(childsock);
continue;
}
@@ -260,7 +263,6 @@ void main_noinetd() {
addrstring = getaddrstring(&remoteaddr, 1);
dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
m_free(addrstring);
if (setsid() < 0) {
dropbear_exit("setsid: %s", strerror(errno));
@@ -279,7 +281,8 @@ void main_noinetd() {
/* start the session */
svr_session(childsock, childpipe[1],
getaddrhostname(&remoteaddr));
getaddrhostname(&remoteaddr),
addrstring);
/* don't return */
assert(0);
}
@@ -299,7 +302,7 @@ void main_noinetd() {
/* catch + reap zombie children */
static void sigchld_handler(int fish) {
static void sigchld_handler(int UNUSED(unused)) {
struct sigaction sa_chld;
while(waitpid(-1, NULL, WNOHANG) > 0);
@@ -312,14 +315,14 @@ static void sigchld_handler(int fish) {
}
/* catch any segvs */
static void sigsegv_handler(int fish) {
static void sigsegv_handler(int UNUSED(unused)) {
fprintf(stderr, "Aiee, segfault! You should probably report "
"this as a bug to the developer\n");
exit(EXIT_FAILURE);
}
/* catch ctrl-c or sigterm */
static void sigintterm_handler(int fish) {
static void sigintterm_handler(int UNUSED(unused)) {
exitflag = 1;
}
@@ -352,27 +355,33 @@ static void commonsetup() {
if (signal(SIGSEGV, sigsegv_handler) == SIG_ERR) {
dropbear_exit("signal() error");
}
/* Now we can setup the hostkeys - needs to be after logging is on,
* otherwise we might end up blatting error messages to the socket */
loadhostkeys();
}
/* Set up listening sockets for all the requested ports */
static int listensockets(int *sock, int sockcount, int *maxfd) {
unsigned int i;
char portstring[NI_MAXSERV];
char* errstring = NULL;
unsigned int sockpos = 0;
int nsock;
TRACE(("listensockets: %d to try\n", svr_opts.portcount))
for (i = 0; i < svr_opts.portcount; i++) {
snprintf(portstring, sizeof(portstring), "%d", svr_opts.ports[i]);
nsock = dropbear_listen(NULL, portstring, &sock[sockpos],
TRACE(("listening on '%s'", svr_opts.ports[i]))
nsock = dropbear_listen(NULL, svr_opts.ports[i], &sock[sockpos],
sockcount - sockpos,
&errstring, maxfd);
if (nsock < 0) {
dropbear_log(LOG_WARNING, "Failed listening on port %s: %s",
portstring, errstring);
dropbear_log(LOG_WARNING, "Failed listening on '%s': %s",
svr_opts.ports[i], errstring);
m_free(errstring);
continue;
}

View File

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

View File

@@ -39,7 +39,7 @@ void recv_msg_service_request() {
unsigned char * name;
unsigned int len;
TRACE(("enter recv_msg_service_request"));
TRACE(("enter recv_msg_service_request"))
name = buf_getstring(ses.payload, &len);
@@ -49,7 +49,7 @@ void recv_msg_service_request() {
send_msg_service_accept(name, len);
m_free(name);
TRACE(("leave recv_msg_service_request: done ssh-userauth"));
TRACE(("leave recv_msg_service_request: done ssh-userauth"))
return;
}
@@ -62,7 +62,7 @@ void recv_msg_service_request() {
send_msg_service_accept(name, len);
m_free(name);
TRACE(("leave recv_msg_service_request: done ssh-connection"));
TRACE(("leave recv_msg_service_request: done ssh-connection"))
return;
}
@@ -75,7 +75,7 @@ void recv_msg_service_request() {
static void send_msg_service_accept(unsigned char *name, int len) {
TRACE(("accepting service %s", name));
TRACE(("accepting service %s", name))
CHECKCLEARTOWRITE();

View File

@@ -52,23 +52,30 @@ static const packettype svr_packettypes[] = {
{SSH_MSG_KEXINIT, recv_msg_kexinit},
{SSH_MSG_KEXDH_INIT, recv_msg_kexdh_init}, /* server */
{SSH_MSG_NEWKEYS, recv_msg_newkeys},
#ifdef ENABLE_SVR_REMOTETCPFWD
{SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_remotetcp},
#endif
{SSH_MSG_CHANNEL_REQUEST, recv_msg_channel_request},
{SSH_MSG_CHANNEL_OPEN, recv_msg_channel_open},
{SSH_MSG_CHANNEL_EOF, recv_msg_channel_eof},
{SSH_MSG_CHANNEL_CLOSE, recv_msg_channel_close},
#ifdef USING_LISTENERS
{SSH_MSG_CHANNEL_OPEN_CONFIRMATION, recv_msg_channel_open_confirmation},
{SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure},
#endif
{0, 0} /* End */
};
static const struct ChanType *svr_chantypes[] = {
&svrchansess,
#ifdef ENABLE_SVR_LOCALTCPFWD
&svr_chan_tcpdirect,
#endif
NULL /* Null termination is mandatory. */
};
void svr_session(int sock, int childpipe, char* remotehost) {
void svr_session(int sock, int childpipe,
char* remotehost, char *addrstring) {
struct timeval timeout;
@@ -77,6 +84,7 @@ void svr_session(int sock, int childpipe, char* remotehost) {
/* Initialise server specific parts of the session */
svr_ses.childpipe = childpipe;
svr_ses.addrstring = addrstring;
svr_authinitialise();
chaninitialise(svr_chantypes);
svr_chansessinitialise();
@@ -168,7 +176,7 @@ void svr_dropbear_log(int priority, const char* format, va_list param) {
/* if we are using DEBUG_TRACE, we want to print to stderr even if
* syslog is used, so it is included in error reports */
#ifdef DEBUG_TRACE
havetrace = 1;
havetrace = debug_trace;
#endif
if (!svr_opts.usingsyslog || havetrace)

View File

@@ -33,7 +33,7 @@
#include "listener.h"
#include "runopts.h"
#ifndef DISABLE_SVR_REMOTETCPFWD
#ifdef ENABLE_SVR_REMOTETCPFWD
static void send_msg_request_success();
static void send_msg_request_failure();
@@ -70,10 +70,10 @@ void recv_msg_global_request_remotetcp() {
unsigned int wantreply = 0;
int ret = DROPBEAR_FAILURE;
TRACE(("enter recv_msg_global_request_remotetcp"));
TRACE(("enter recv_msg_global_request_remotetcp"))
if (opts.noremotetcp) {
TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled"));
TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled"))
goto out;
}
@@ -81,7 +81,7 @@ void recv_msg_global_request_remotetcp() {
wantreply = buf_getbyte(ses.payload);
if (namelen > MAXNAMLEN) {
TRACE(("name len is wrong: %d", namelen));
TRACE(("name len is wrong: %d", namelen))
goto out;
}
@@ -90,7 +90,7 @@ void recv_msg_global_request_remotetcp() {
} else if (strcmp("cancel-tcpip-forward", reqname) == 0) {
ret = svr_cancelremotetcp();
} else {
TRACE(("reqname isn't tcpip-forward: '%s'", reqname));
TRACE(("reqname isn't tcpip-forward: '%s'", reqname))
}
out:
@@ -104,7 +104,7 @@ out:
m_free(reqname);
TRACE(("leave recv_msg_global_request"));
TRACE(("leave recv_msg_global_request"))
}
@@ -143,11 +143,11 @@ static int svr_cancelremotetcp() {
struct Listener * listener = NULL;
struct TCPListener tcpinfo;
TRACE(("enter cancelremotetcp"));
TRACE(("enter cancelremotetcp"))
bindaddr = buf_getstring(ses.payload, &addrlen);
if (addrlen > MAX_IP_LEN) {
TRACE(("addr len too long: %d", addrlen));
TRACE(("addr len too long: %d", addrlen))
goto out;
}
@@ -163,7 +163,7 @@ static int svr_cancelremotetcp() {
out:
m_free(bindaddr);
TRACE(("leave cancelremotetcp"));
TRACE(("leave cancelremotetcp"))
return ret;
}
@@ -175,12 +175,12 @@ static int svr_remotetcpreq() {
struct TCPListener *tcpinfo = NULL;
unsigned int port;
TRACE(("enter remotetcpreq"));
TRACE(("enter remotetcpreq"))
/* NOTE: at this stage, we ignore bindaddr. see below and listen_tcpfwd */
bindaddr = buf_getstring(ses.payload, &addrlen);
if (addrlen > MAX_IP_LEN) {
TRACE(("addr len too long: %d", addrlen));
TRACE(("addr len too long: %d", addrlen))
goto out;
}
@@ -192,12 +192,12 @@ static int svr_remotetcpreq() {
}
if (port < 1 || port > 65535) {
TRACE(("invalid port: %d", port));
TRACE(("invalid port: %d", port))
goto out;
}
if (!ses.allowprivport && port < IPPORT_RESERVED) {
TRACE(("can't assign port < 1024 for non-root"));
TRACE(("can't assign port < 1024 for non-root"))
goto out;
}
@@ -218,7 +218,7 @@ out:
m_free(tcpinfo->sendaddr);
m_free(tcpinfo);
}
TRACE(("leave remotetcpreq"));
TRACE(("leave remotetcpreq"))
return ret;
}
@@ -236,13 +236,13 @@ static int newtcpdirect(struct Channel * channel) {
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
if (opts.nolocaltcp) {
TRACE(("leave newtcpdirect: local tcp forwarding disabled"));
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"));
TRACE(("leave newtcpdirect: desthost too long"))
goto out;
}
@@ -250,7 +250,7 @@ static int newtcpdirect(struct Channel * channel) {
orighost = buf_getstring(ses.payload, &len);
if (len > MAX_HOST_LEN) {
TRACE(("leave newtcpdirect: orighost too long"));
TRACE(("leave newtcpdirect: orighost too long"))
goto out;
}
@@ -258,7 +258,7 @@ static int newtcpdirect(struct Channel * channel) {
/* best be sure */
if (origport > 65535 || destport > 65535) {
TRACE(("leave newtcpdirect: port > 65535"));
TRACE(("leave newtcpdirect: port > 65535"))
goto out;
}
@@ -266,7 +266,7 @@ static int newtcpdirect(struct Channel * channel) {
sock = connect_remote(desthost, portstring, 1, NULL);
if (sock < 0) {
err = SSH_OPEN_CONNECT_FAILED;
TRACE(("leave newtcpdirect: sock failed"));
TRACE(("leave newtcpdirect: sock failed"))
goto out;
}
@@ -284,7 +284,7 @@ static int newtcpdirect(struct Channel * channel) {
out:
m_free(desthost);
m_free(orighost);
TRACE(("leave newtcpdirect: err %d", err));
TRACE(("leave newtcpdirect: err %d", err))
return err;
}

View File

@@ -75,9 +75,7 @@ int x11req(struct ChanSess * chansess) {
}
/* set non-blocking */
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
goto fail;
}
setnonblocking(fd);
/* listener code will handle the socket now.
* No cleanup handler needed, since listener_remove only happens
@@ -171,8 +169,12 @@ void x11cleanup(struct ChanSess *chansess) {
m_free(chansess->x11authprot);
m_free(chansess->x11authcookie);
remove_listener(chansess->x11listener);
chansess->x11listener = NULL;
TRACE(("chansess %s", chansess))
if (chansess->x11listener != NULL) {
remove_listener(chansess->x11listener);
chansess->x11listener = NULL;
}
}
static const struct ChanType chan_x11 = {

View File

@@ -87,7 +87,7 @@ int listen_tcpfwd(struct TCPListener* tcpinfo) {
int nsocks;
char* errstring = NULL;
TRACE(("enter listen_tcpfwd"));
TRACE(("enter listen_tcpfwd"))
/* first we try to bind, so don't need to do so much cleanup on failure */
snprintf(portstring, sizeof(portstring), "%d", tcpinfo->listenport);
@@ -100,7 +100,7 @@ int listen_tcpfwd(struct TCPListener* tcpinfo) {
if (nsocks < 0) {
dropbear_log(LOG_INFO, "TCP forward failed: %s", errstring);
m_free(errstring);
TRACE(("leave listen_tcpfwd: dropbear_listen failed"));
TRACE(("leave listen_tcpfwd: dropbear_listen failed"))
return DROPBEAR_FAILURE;
}
@@ -109,11 +109,11 @@ int listen_tcpfwd(struct TCPListener* tcpinfo) {
if (listener == NULL) {
m_free(tcpinfo);
TRACE(("leave listen_tcpfwd: listener failed"));
TRACE(("leave listen_tcpfwd: listener failed"))
return DROPBEAR_FAILURE;
}
TRACE(("leave listen_tcpfwd: success"));
TRACE(("leave listen_tcpfwd: success"))
return DROPBEAR_SUCCESS;
}

View File

@@ -47,7 +47,7 @@ struct TCPListener {
/* A link in a list of forwards */
struct TCPFwdList {
char* connectaddr;
const unsigned char* connectaddr;
unsigned int connectport;
unsigned int listenport;
struct TCPFwdList * next;
@@ -60,6 +60,7 @@ extern const struct ChanType svr_chan_tcpdirect;
/* Client */
void setup_localtcp();
void setup_remotetcp();
extern const struct ChanType cli_chan_tcpremote;
/* Common */

View File

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