Compare commits

..

249 Commits

Author SHA1 Message Date
Matt Johnston
6da90b34fe 2013.58 2013-04-18 22:57:47 +08:00
Matt Johnston
43769b5bb3 Don't enable CLI_IMMEDIATE_AUTH by default, it breaks blank password logins 2013-04-18 21:47:38 +08:00
Matt Johnston
f98eb5808b Use % rather than # for port delimiter 2013-04-17 23:17:27 +08:00
Matt Johnston
3525cabf48 Use '#' for host#port separator, document it. This fixes scp
in multihop
2013-04-17 22:48:43 +08:00
Matt Johnston
54a76342f5 If running as non-root only allow that user to log in 2013-04-17 22:29:18 +08:00
Matt Johnston
154a65fc31 Fix build when zlib is disabled, from
http://freetz.org/browser/trunk/make/dropbear/patches/350-no_zlib_fix.patch
2013-04-16 22:16:32 +08:00
Matt Johnston
bd7a46f514 Added signature for changeset 095b46180bbc 2013-04-15 22:11:11 +08:00
Matt Johnston
79a307bca2 Added tag DROPBEAR_2013.57 for changeset 96b8bcb88017 2013-04-15 22:10:49 +08:00
Matt Johnston
38f42a0fa2 Fix error message for requirenext change 2013-04-15 22:01:41 +08:00
Matt Johnston
b4cdfcb506 bump version to 2013.57 2013-04-15 21:56:04 +08:00
Matt Johnston
d3cef72f26 changelog updates for 2013.57 2013-04-15 21:51:27 +08:00
Matt Johnston
ef151888fb requirenext fixup for firstkexfollows 2013-04-14 23:16:16 +08:00
Matt Johnston
ba15bbfe33 Document escape chars 2013-04-14 23:08:57 +08:00
Matt Johnston
3bdfae61a2 merge 2013-04-14 22:49:19 +08:00
Matt Johnston
4404126501 -y -y to disable hostkey checking
fix missing trailing space when passing arguments for multihop mode
From Hans Harder
2013-04-14 22:49:10 +08:00
Matt Johnston
adeb372a66 Fix zlib for split newkeys 2013-04-11 23:03:58 +08:00
Matt Johnston
c0d7c6693f run closehandlers on cleanup 2013-04-10 21:32:55 +08:00
Matt Johnston
3ec4670478 reset terminal modes before printing a message 2013-04-10 21:32:44 +08:00
Matt Johnston
2fdb5fd6ce setup tcp after requesting a channel - might hide some DNS latency 2013-04-04 07:51:13 +08:00
Matt Johnston
7f42096d0f Take transmit and receive keys into use separately 2013-04-04 00:18:50 +08:00
Matt Johnston
e2c813df4d Fix MAC bug which would prevent asymmetric hashes 2013-04-03 23:54:58 +08:00
Matt Johnston
a2f70a3751 Just put the version string on the queue, don't use atomicio 2013-04-03 19:23:53 +08:00
Matt Johnston
286fa93a8d fix leftover kexguess debugging 2013-04-03 07:34:18 +08:00
Matt Johnston
557d86aa79 Fix a few options and headers 2013-04-03 07:33:47 +08:00
Matt Johnston
8e68d5e2d5 merge 2013-04-03 00:50:46 +08:00
Matt Johnston
1a16da38d5 merge kexguess branch 2013-04-03 00:49:24 +08:00
Matt Johnston
cbd3d5e3a5 Put some #ifdef options around first-follows options in case they
need to be disabled

--HG--
branch : kexguess
2013-04-03 00:43:31 +08:00
Matt Johnston
78fbed8c3e Don't usually need to recalculate dh_e for the repeated kexdh_init packet
--HG--
branch : kexguess
2013-04-03 00:32:55 +08:00
Matt Johnston
f267ca1f3a Add sentinel attribute
--HG--
branch : kexguess
2013-04-03 00:32:05 +08:00
Matt Johnston
a6eb824950 add IUTF8 2013-04-02 19:11:13 +08:00
Matt Johnston
dcd1527a11 fix tabs 2013-04-02 18:59:00 +08:00
Matt Johnston
f8a92d1eed merge 2013-04-02 18:54:04 +08:00
Matt Johnston
e55e468754 Fix segfault when /dev/urandom isn't writable 2013-04-02 18:53:18 +08:00
Matt Johnston
ff2aa20565 Be a bit more careful about when we want to use CLI_AUTH_IMMEDIATE
Only use it if we have pubkeys to try, or we have $DROPBEAR_PASSWORD set
2013-04-02 00:11:53 +08:00
Matt Johnston
90b5691183 Run the cleanup handler also when we close due to TCP connection being closed 2013-04-01 22:26:55 +08:00
Matt Johnston
5af0d33164 Try password before interactive - bit of a hack 2013-04-01 22:26:24 +08:00
Matt Johnston
e5072c6b12 merge from head roundtrip changes
--HG--
branch : kexguess
2013-04-01 00:13:41 +08:00
Matt Johnston
90cf7f012c Move the more verbose TRACE() statements into TRACE2() 2013-04-01 00:07:26 +08:00
Matt Johnston
484516da51 Send an auth packet straight away, save another roundtrip
This needs a bit of testing to make sure it doesn't have side-effects.
2013-03-31 23:48:25 +08:00
Matt Johnston
5abe22d1a5 Fix incorrect logic for USE_VFORK and calling arg_setup() 2013-03-31 23:29:03 +08:00
Matt Johnston
f6b304250b Try using writev() for writing packets out to tcp 2013-03-31 23:15:35 +08:00
Matt Johnston
36526700a9 Don't bother waiting for a ssh-connection service reply - the server
will disconnect if it wasn't accepted
2013-03-31 21:38:17 +08:00
Matt Johnston
32294978a3 merge
--HG--
branch : kexguess
2013-03-31 00:41:15 +08:00
Matt Johnston
a0e931005b send out our kexinit packet before blocking to read the SSH version string 2013-03-31 00:40:00 +08:00
Matt Johnston
9c7485331a Get rid of client/server specific buf_match_algo, use single
function with a couple of if statements instead

--HG--
branch : kexguess
2013-03-30 23:55:05 +08:00
Matt Johnston
99d9cf500b Add kexguess2 behaviour
--HG--
branch : kexguess
2013-03-29 23:29:48 +08:00
Matt Johnston
4f62da0f0d first_kex_packet_follows working, needs tidying
--HG--
branch : kexguess
2013-03-29 20:44:13 +08:00
Matt Johnston
9be0d6b53d Define _GNU_SOURCE for vasprintf 2013-03-24 00:02:20 +08:00
Mike Frysinger
bbf6d5f2f5 rename configure.in -> configure.ac
Latest autotools warn now if the file is named configure.in

--HG--
rename : configure.in => configure.ac
2013-03-24 00:00:39 +08:00
Matt Johnston
c4861340e9 Fix a few compile warnings 2013-03-23 23:17:01 +08:00
Matt Johnston
5996c3824c Add ~. and ~^Z handling to exit/suspend dbclient 2013-03-23 23:16:06 +08:00
Matt Johnston
c172fb3b32 Added signature for changeset 9b80981212fe 2013-03-21 23:35:07 +08:00
Matt Johnston
03a0d11c4d Added tag DROPBEAR_2013.56 for changeset 1b8b2b9d6e94 2013-03-21 23:33:12 +08:00
Matt Johnston
156e0187bf Forgot date in CHANGES 2013-03-21 23:29:04 +08:00
Matt Johnston
fcaaa7b4c2 2013.56 changelog 2013-03-21 23:19:06 +08:00
Matt Johnston
2f098325f8 update text about authorized_keys options 2013-03-21 23:11:16 +08:00
Matt Johnston
9dc30fbd2a Add URL to usage text 2013-03-21 23:10:47 +08:00
Matt Johnston
024d268d8c Make hmac-sha2-256 and hmac-sha2-512 work 2013-03-21 22:55:12 +08:00
Matt Johnston
eaa737fecd Make sure "struct timeval" is initialised on OS X to avoid valgrind warnings 2013-03-21 21:23:34 +08:00
Matt Johnston
845ad0be39 Fix "-c none" so that it allows aes during authentication
Default for options.h shouldn't allow "none"
2013-03-20 23:52:49 +08:00
Matt Johnston
2259ce4cdf Fix "-m none" case and ugly typo 2013-03-20 23:13:45 +08:00
Matt Johnston
34f9b2a8f7 Fix "-m none" case where an entire packet fits in a block and can be
read by read_packet_init()
2013-03-20 23:13:19 +08:00
Matt Johnston
d37dcc636f Merge "none" cipher/MAC branch. Also adds sha256 and sha512 2013-03-20 22:41:07 +08:00
Matt Johnston
804a1e69f2 use an empty writebuf rather than a NULL one 2013-03-20 22:31:07 +08:00
Matt Johnston
f7b1222073 document a few more changes 2013-03-20 00:05:19 +08:00
Matt Johnston
4fd4fbc255 Fix memory leak when direct TCP connections time out on connection.
Long-standing bug probably stemming from the awkwardly named
delete_channel() versus remove_channel()
2013-03-19 23:54:32 +08:00
Matt Johnston
8393c5f016 Allow specifying server "-p" options with ipv6 bracket notation,
patch from Ben Jencks
2013-03-19 20:55:11 +08:00
Matt Johnston
5ff341206e Android returns NULL for pw_crypt, set it to something else 2013-03-19 20:15:44 +08:00
Matt Johnston
da59afe798 ignore I_PUSH if it isn't defined, for Android from Reimar Döffinger 2013-03-19 20:12:19 +08:00
Matt Johnston
6270ed2f8a Fix compat basename() to handle paths with no slashes. Thanks to Frank Teo 2013-03-19 20:04:55 +08:00
Matt Johnston
80e77b5e6d Include /proc/vmstat as another random source 2013-03-19 19:47:29 +08:00
Matt Johnston
58c7d4474c link to Dropbear webpage 2013-03-19 19:43:47 +08:00
Matt Johnston
3af964304f Removed tag t:ltc-0.95-db-merge1 2013-03-19 19:26:54 +08:00
Matt Johnston
4289324c4b Removed tag t:ltc-0.95-orig 2013-03-19 19:26:46 +08:00
Matt Johnston
9f3c817491 fix signedness error in prototype 2013-03-11 23:07:45 +08:00
Matt Johnston
a9cf0ca25f improve subsystem/sftp documentation, and multi-hop manual formatting 2013-03-03 11:47:41 +08:00
Matt Johnston
72a5612a29 fix typo 2013-02-24 00:16:02 +08:00
Matt Johnston
d7f2153631 DSS_PROTOK is not necessary now that private keys are included
in the random generation input
2013-02-23 17:55:46 +08:00
Matt Johnston
26b07ccafc add loadavg and entropy_avail as sources 2013-02-23 10:27:49 +08:00
Paul Eggleton
1205fa68df Allow configuring "allow blank password option" at runtime
Changes this from a compile-time switch to a command-line option.

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
2013-02-12 15:52:57 +00:00
Matt Johnston
f5be0fb218 Some changes since 2012.55 2013-02-22 23:54:47 +08:00
Matt Johnston
88fc38c8f0 Document "-m" and "-c"
Update URLs with https
2013-02-22 23:53:49 +08:00
Matt Johnston
545de7a3a1 /dev/random blocks on busy servers too. 2012-07-19 21:34:27 +08:00
Matt Johnston
6ba2b2b384 Add a few more files in /proc for Linux 2012-06-30 22:12:28 +08:00
Matt Johnston
d5ccc32b4d Improve RNG seeding.
Try to read from /dev/urandom multiple times, take input from extra sources,
and use /dev/random when generating private keys
2012-06-29 23:19:43 +08:00
Matt Johnston
e719a9ef6f - Only request "none" cipher after auth has succeeded
--HG--
branch : insecure-nocrypto
2012-05-17 20:52:57 +08:00
Matt Johnston
a02d38072a Add ALLOW_NONE_PASSWORD_AUTH option
--HG--
branch : insecure-nocrypto
2012-05-17 08:33:11 +08:00
Matt Johnston
f2cd610750 Merge in "-m"/"-c" code
--HG--
branch : insecure-nocrypto
2012-05-17 08:09:19 +08:00
Matt Johnston
db34044c7f ENABLE_USER_ALGO_LIST should work for the client 2012-05-17 00:26:12 +08:00
Matt Johnston
036edd6206 Add rough support for choosing ciphers/hashes with "-c" or "-m" 2012-05-17 00:12:42 +08:00
Matt Johnston
f40ed8bad7 Update insecure-nocrypto to current head
--HG--
branch : insecure-nocrypto
2012-05-16 22:54:51 +08:00
Matt Johnston
41f50057f1 Disable SHA256 and SHA512 by default in options.h
--HG--
branch : sha2
2012-05-16 21:56:50 +08:00
Matt Johnston
c62e53807f - Add hmac-sha2-256 and hmac-sha2-512. Needs debugging, seems to be
getting keyed incorrectly

--HG--
branch : sha2
2012-05-10 08:38:37 +08:00
Matt Johnston
10d7a35841 Don't TRACE() the pw_passwd 2012-05-09 22:52:58 +08:00
Matt Johnston
6b4105ffe6 Fix empty password immediate login 2012-05-09 22:51:59 +08:00
Matt Johnston
2713445e91 Return immediate success for blank passwords if allowed 2012-05-09 22:37:04 +08:00
Matt Johnston
1984aabc95 Server shouldn't return "localhost" in response to -R forward connections
if that wasn't what the client requested.
2012-05-09 21:09:34 +08:00
Matt Johnston
f4c4ca64a8 Initialise agent_fd to -1 so we don't end up closing stdin (fd 0)
if public key authentication is disabled
2012-05-09 20:34:55 +08:00
Matt Johnston
2a02c4084a - Don't sent SSH_MSG_UNIMPLEMENTED if we don't have ENABLE_SVR_REMOTETCPFWD
- Fix build if ENABLE_SVR_REMOTETCPFWD is disabled but ENABLE_SVR_LOCALTCPFWD
  is enabled
2012-05-09 20:33:16 +08:00
Matt Johnston
e242b2820c Ignore -q if SCP_PROGRESS isn't set 2012-04-24 22:05:55 +08:00
Matt Johnston
6467b8d903 Split listening port argument at the rightmost colon, allows binding to
specific IPv6 addresses.

From OpenWRT,
https://dev.openwrt.org/browser/trunk/package/dropbear/patches/300-ipv6_addr_port_split.patch
2012-04-12 22:04:16 +08:00
Matt Johnston
3e2b6a1821 Improve comment about sha1-96 2012-04-12 21:57:30 +08:00
Matt Johnston
4d009daaa0 Slight formatting change for ENABLE_CLI_AGENTFWD if statement 2012-04-09 21:29:41 +08:00
Andrey Mazo
d4a14fcb3d Fixed compilation with unset ENABLE_{SVR,CLI}_AGENTFWD.
Got rid of ENABLE_AGENTFWD macro.
2012-03-26 16:17:16 +04:00
Matt Johnston
49b79fa02d Rename HAVE_FORK to USE_VFORK
It makes it a bit more obvious why there's a test there since HAVE_FORK
is the normal case.
2012-04-09 20:35:13 +08:00
Mike Frysinger
c957edbe75 check for fork() and not __uClinux__ 2012-04-08 01:50:52 -04:00
Mike Frysinger
33ae2be52e fix out-of-tree cleaning
If we build out of tree and then run `make clean`, we hit an
infinite loop where libtommath tries to enter subdirs that don't
exist and run `make clean`.
2012-04-08 02:06:54 -04:00
Matt Johnston
496c1db974 Added signature for changeset 85f835f2fe0a 2012-02-23 21:46:02 +08:00
Matt Johnston
f381274278 Added tag DROPBEAR_2012.55 for changeset d354464b2aa6 2012-02-23 21:45:42 +08:00
Matt Johnston
398339218e - Improve CHANGES description 2012-02-23 21:45:36 +08:00
Matt Johnston
4dda424f74 2012.55 2012-02-22 22:12:15 +08:00
Matt Johnston
f403c1f18b - Fix minor leak 2012-02-22 22:05:24 +08:00
Matt Johnston
ff5d94a7a4 Fix accidentally committed change 2012-02-22 19:33:07 +08:00
Matt Johnston
a15fc009da - Initialise sa_mask properly 2011-12-04 05:41:46 +08:00
Matt Johnston
6c4390c848 - Merge 2012-02-21 23:00:30 +08:00
Matt Johnston
a3188b44f0 - Make sure sa_mask is set 2012-02-21 22:57:19 +08:00
Matt Johnston
aaa72ddbfc - Burn buffers to 0x00 instead 2012-02-21 22:56:45 +08:00
Matt Johnston
bcf3a3ab93 Merge 2012-02-10 19:09:52 +08:00
Matt Johnston
5feebd300e Clear a few buffers when possible 2012-02-10 18:32:18 +08:00
Matt Johnston
aec23e5f79 - Fix use-after-free if multiple command requests were sent. Move
the original_command into chansess struct since that makes more sense
2011-12-04 05:31:25 +08:00
Matt Johnston
52a466b8af - Remove unused variable/code 2011-12-04 05:27:57 +08:00
Matt Johnston
baa32218b0 - Make sure we don't use channel-specific data after it has been freed
with a ChanType->closehandler()
2011-12-04 05:27:29 +08:00
Matt Johnston
fd0b05943d - Fix some format strings in TRACE()s 2011-12-04 05:24:50 +08:00
Matt Johnston
2e0145fb95 - We don't need to test for NULL before free() 2011-12-04 05:23:43 +08:00
Matt Johnston
c894ea4ea2 Put better #if guards around IPv6 socket options for IPV6_TCLASS and
IPV6_V6ONLY. From Gustavo Zacarias.
2011-11-10 18:17:00 +08:00
Matt Johnston
88278dee74 Added signature for changeset 3f12086c2ef2 2011-11-08 21:06:29 +08:00
Matt Johnston
d0fadd992f Added tag DROPBEAR_2011.54 for changeset 3f12086c2ef2 2011-11-08 21:06:01 +08:00
Matt Johnston
eb45ce0e8a Changelog and version bump for 2011.54 2011-11-08 20:48:15 +08:00
Matt Johnston
194b700592 Fix symlink target created by installdropbearmulti 2011-11-08 20:33:19 +08:00
Matt Johnston
5454c2a7f1 Added signature for changeset aa2f51a6b81d 2011-11-08 00:01:47 +08:00
Matt Johnston
a6568626a5 Use "uint64_t" instead of "u_int64_t" since the Solaris doesn't have the
latter
2011-11-07 19:31:53 +08:00
Matt Johnston
59943acffe Fix crash with -R forwarding 2011-11-06 20:22:34 +08:00
Matt Johnston
d4e7654ed0 Print the server allocated port when using dbclient -R 0:....
Patch from Ali Onur Uyar
2011-11-05 23:12:15 +08:00
convert-repo
68b458ece9 update tags 2011-11-03 07:18:37 +00:00
Matt Johnston
1119ad3a2f Set IPTOS_LOWDELAY for IPv6 too
--HG--
extra : convert_revision : bebc84493fc5f4ca914ae8828e6db7204c086ac2
2011-10-26 16:02:06 +00:00
Matt Johnston
29e68e9d79 - Add ALLOW_BLANK_PASSWORD option
- Don't reject blank-password logins via public key

--HG--
extra : convert_revision : 2d4bb3ecb013a7be47a7b470fc6b23e653a43dfb
2011-10-26 15:49:47 +00:00
Matt Johnston
c1fe2ec5ae Try bind IPV6_V6ONLY
--HG--
extra : convert_revision : cfe965c1503984cafaa98b684269db99bec310eb
2011-10-20 13:45:43 +00:00
Matt Johnston
81cacd9f15 list.c also has no trailing newline
--HG--
extra : convert_revision : cfe8e94b86e98f79b18abebbcd49c6eb5908c74c
2011-07-05 12:52:06 +00:00
Matt Johnston
6def0ab5f1 Fix lost ending newline
--HG--
extra : convert_revision : eacbbecc4f4aad52a29b013beed83b7d54a98796
2011-07-05 12:50:15 +00:00
Matt Johnston
d20627585a Hopefully fix -lcrypt problem
--HG--
extra : convert_revision : 94d41df148dba424a62b442aebdb5cf0db11449a
2011-06-30 14:34:32 +00:00
Matt Johnston
2bcb60fe56 Fix case where "-K 1" would cause a SSH_MSG_IGNORE packet to be sent
with the wrong encryption key ("bad packet length" symptom) while
key exchange was happening.

--HG--
extra : convert_revision : f7d27ec094c4aba2a4289c523c722fcb3c3f58ca
2011-06-07 11:55:44 +00:00
Matt Johnston
0f83379dc0 Mention that the value is in seconds
--HG--
extra : convert_revision : fcdafc69f831ab356b34815958114cc3d75d23bb
2011-06-07 11:08:47 +00:00
Matt Johnston
ca6d5fd05c Clean up leaked FD if getnameinfo fails. From Klocwork
--HG--
extra : convert_revision : 712881a0b28aa45804bed6803fb72a4a35714e41
2011-04-07 13:52:43 +00:00
Matt Johnston
b9e21e2367 Fix crash when remote forwarding was requested
--HG--
extra : convert_revision : 5c0a794976692a54ec36111291179020e2ae6c1e
2011-04-07 13:39:10 +00:00
Matt Johnston
665b768cef Fix leak found by Klocwork
--HG--
extra : convert_revision : 51ce088e100e9ea150efc6bf3d021f019a46b2f5
2011-04-07 13:38:27 +00:00
Matt Johnston
b272b967e2 Properly fix the bug found years ago by Klocwork, refound again.
--HG--
extra : convert_revision : 65b95facde07c748c56e0bfa25c801397dc16a99
2011-04-07 13:33:26 +00:00
Matt Johnston
22c16a8b71 Clean up fd on failure. Found by Klocwork
--HG--
extra : convert_revision : 4b999175c8e91ee3ddf283b17525999499a12849
2011-04-07 13:25:00 +00:00
Matt Johnston
f924aa18f2 Define LTC_NO_FILE to avoid hmac_file() etc
--HG--
extra : convert_revision : b918fd450c1572ce055a6a1fe8c161a495ddec34
2011-04-07 13:24:41 +00:00
Matt Johnston
72c446f160 Fix FD leak if connect() fails, found by Klocwork
--HG--
extra : convert_revision : 4f7dec450bb69aee8d7789b8ab10311b1d1655bb
2011-04-07 13:05:10 +00:00
Matt Johnston
2028b1b517 Add noreturn and format attribute hints for some functions.
--HG--
extra : convert_revision : 6cc8735d01f0360b918edc26be05681725c0022a
2011-04-07 12:59:18 +00:00
Matt Johnston
72a82cc0ac Fix memory leak found by Klocwork
--HG--
extra : convert_revision : 6f1e5e6dd6462f1c35a6bfd601a0f5f8b99410d6
2011-04-07 12:34:44 +00:00
Matt Johnston
eef35883b7 Tidy error handling and get rid of some commented out code
--HG--
extra : convert_revision : beb6fc766123135d5ae455ff7ad6b48d85386f62
2011-04-07 12:30:20 +00:00
Matt Johnston
8028e07815 Change comparison to be more paranoid (and perhaps avoid Klocwork false
positive). Does not change behaviour.

--HG--
extra : convert_revision : 11d5ca4bf2f4197ed2d14b6772a351bcb59f775e
2011-04-07 11:18:35 +00:00
Matt Johnston
3fc6569d46 Fix check of wrong variable found by Klocwork
--HG--
extra : convert_revision : 6f3b074e83bb808019f49c5aca3451b70f9f1e8f
2011-04-07 11:14:22 +00:00
Matt Johnston
2303d0fd09 Avoid segfault when handling childpid race
--HG--
extra : convert_revision : 8845727a7e2b096015dbb76d8f3df13c9acee7da
2011-03-31 14:42:11 +00:00
Matt Johnston
9a007c30d4 Use mp_init_size() to avoid some mp_grow()s
--HG--
extra : convert_revision : 94b7dd79a8e970e9641d4e655b3db48190ac2531
2011-03-18 14:31:07 +00:00
Matt Johnston
8a545a0d04 Update changelog for 0.53.1
--HG--
extra : convert_revision : c7f6c45c46a2f8e2394756c68ae825d6e4dc7489
2011-03-02 13:23:27 +00:00
Matt Johnston
0993e44b4f merge of '8a608f0ed5e4b491dba4bf330e560636ec7376fd'
and 'b31879a384d3bf8cbcbe2ed731d7d79d49799b1d'

--HG--
extra : convert_revision : dfa0557e6070859d23ff096789f339e51a870177
2011-02-28 13:51:34 +00:00
Matt Johnston
d634b502cf - Don't allow setting memLevel since that doesn't work properly
- Better handling of the case where compressing makes the data
larger (possibly only happens when memLevel is adjusted, but better
to be safe)

--HG--
extra : convert_revision : b31879a384d3bf8cbcbe2ed731d7d79d49799b1d
2011-02-28 13:51:27 +00:00
Matt Johnston
53fc7eaf03 Compile fix for when both client and server agent forwarding is disabled
--HG--
extra : convert_revision : 8a608f0ed5e4b491dba4bf330e560636ec7376fd
2011-02-28 13:39:18 +00:00
Matt Johnston
3c42c5407c Refer to RFCs rather than drafts, update some section references
--HG--
extra : convert_revision : b5c5c88e702f427b9d5e8c592e2b7e1bda204ff3
2011-02-27 13:57:32 +00:00
Matt Johnston
9d9a8ff735 - Fix DROPBEAR_PRNGD_SOCKET since it doesn't need to call connect()
any more

--HG--
extra : convert_revision : 535f2029a34cba3d86eb8ce104d57c910c89c4a4
2011-02-27 13:12:17 +00:00
Matt Johnston
abed230cdb Updates changelog. Mention diffie-hellman-group14-sha1 in 0.53
release, -lcrypt order for 0.53.1

--HG--
extra : convert_revision : 2fa3bd3d29fe694a50f929a12ca249931c92311d
2011-02-25 12:16:14 +00:00
Matt Johnston
e9879cd07b -lcrypt needs to be before object files when static linking
--HG--
extra : convert_revision : 8ecc9a039f16d8492d2b7f64e8602d3f6302e212
2011-02-25 12:14:33 +00:00
Matt Johnston
84c51f933c - Set debian version to 0.53
--HG--
extra : convert_revision : bddea10d0d68b0beafbd98d694df462961e489e6
2011-02-24 14:21:36 +00:00
Matt Johnston
977c43fffb Changelog for 0.53, bump version
--HG--
extra : convert_revision : 5369d8c2cbcbc07a86fce6a1b66ebd4979866a2d
2011-02-24 14:19:36 +00:00
Matt Johnston
f99a19b6ca Mention -L/-R listenaddress argument in manpage
--HG--
extra : convert_revision : 2728be15a280f7b0d48741d033381c0ebf2281f5
2011-02-24 14:18:13 +00:00
Matt Johnston
5a7a88b843 It happened to sony
--HG--
extra : convert_revision : c2d5690ca9ed85c7d75dd9cc2c150de50503aa3b
2011-02-24 12:45:17 +00:00
Matt Johnston
0ffdf2bba9 Add diffie-hellman-group14-sha1 KEX method
--HG--
extra : convert_revision : 5b9c394ad43745e48c42d671cefac7a5c346082f
2011-02-24 12:42:42 +00:00
Matt Johnston
38ed870ffe Improve capitalisation for all logged strings
--HG--
extra : convert_revision : 997e53cec7a9efb7413ac6e17b6be60a5597bd2e
2011-02-23 15:50:30 +00:00
Matt Johnston
1e4ed404c5 merge of '8849ec659cb45b924158cc3322390a1d3d48daef'
and 'a46ca9204de0df58d8701df0d79b6b8ec601b9ce'

--HG--
extra : convert_revision : 00e4e5abea55474624e2ea0ea09f6fbc6c9e4c89
2011-02-23 15:10:31 +00:00
Matt Johnston
642920585f Don't reset last_packet_time when we're transmitting SSH_MSG_IGNORE packets
(from keepalives)

--HG--
extra : convert_revision : a46ca9204de0df58d8701df0d79b6b8ec601b9ce
2011-02-23 15:10:28 +00:00
Matt Johnston
af07eb115a remove unused variable
--HG--
extra : convert_revision : 8849ec659cb45b924158cc3322390a1d3d48daef
2010-07-21 14:07:13 +00:00
Matt Johnston
66371f9920 merge of '4b90e96a8a8afcc9feafc59cb47592a4a6d1cc30'
and '94427244d30e268c74ddade212e31ba01f6f0950'

--HG--
extra : convert_revision : 09d7a0d8401b94db3975c71f5bcafde428cb34d7
2010-07-21 13:53:29 +00:00
Matt Johnston
aabe0677c0 - Update fake-rfc2553.{c,h} from OpenSSH 5.5p1
--HG--
extra : convert_revision : 4b90e96a8a8afcc9feafc59cb47592a4a6d1cc30
2010-07-21 13:53:23 +00:00
Matt Johnston
0fa65ebd4d Fix bug in primality testing, see
http://bugs.gentoo.org/show_bug.cgi?id=328383
http://bugs.gentoo.org/show_bug.cgi?id=328409
https://bugzilla.redhat.com/show_bug.cgi?id=615088

Exact effects of the bug are uncertain.

--HG--
extra : convert_revision : 94427244d30e268c74ddade212e31ba01f6f0950
2010-07-21 13:33:07 +00:00
Matt Johnston
27fddd2c35 Work properly again with bundled libtom*. autoconf is a hassle.
--HG--
extra : convert_revision : 4077fc3332bd7c965aadbb05b02eba6d00fa9621
2010-07-21 13:27:44 +00:00
Matt Johnston
fced1113d3 Rename rsa_key to dropbear_rsa_key (and same for dss too) so
we don't conflict with libtomcrypt.

--HG--
extra : convert_revision : 77961344ec415d73d48fdc7b1ebead3099c13394
2010-07-21 12:55:25 +00:00
Matt Johnston
4d050c34cb Use system libtomcrypt/libtommath if available. Doesn't currently
build due to clash in rsa_key identifier.

--HG--
extra : convert_revision : c9a4726d1c89e17ee8e96801d1aaa8049216aae1
2010-07-21 12:38:46 +00:00
Matt Johnston
a8c28714cd Comment public/private parts
--HG--
extra : convert_revision : 914cbb822f488fa5d17affdad01fcc7dae6006b1
2010-07-20 13:54:20 +00:00
Matt Johnston
eabfd803c9 merge of '0adbc6745a5ada0b6780b0683209f5b26b1a335d'
and 'a014a978f213e6ff424e7d10794ae426375f3191'

--HG--
extra : convert_revision : eecc64377b2b55ba1d9e77855f4323cdc9f8e1c6
2010-03-21 06:07:22 +00:00
Matt Johnston
07b764ead6 - make structure static
--HG--
extra : convert_revision : 0adbc6745a5ada0b6780b0683209f5b26b1a335d
2010-03-21 06:06:42 +00:00
Matt Johnston
8bad5d61fd don't #include "utmp.h"
--HG--
extra : convert_revision : a014a978f213e6ff424e7d10794ae426375f3191
2010-03-04 14:50:19 +00:00
Matt Johnston
9f42a75ef6 - fixes for listenaddr
--HG--
extra : convert_revision : 9eebe96bb7c26c4c09c77a2e89a67a7332abcd49
2010-02-27 12:15:27 +00:00
Matt Johnston
ddbfdb0799 merge of '48fdaa8706d1acda35e9d564adc9a1fbc96c18c8'
and '658fd03abd21e0da7c4c89b9fff9dc693c72daae'

--HG--
extra : convert_revision : 8064882fcaa13d586651021462b9014b74332107
2010-02-27 11:53:18 +00:00
Matt Johnston
3b07844548 - tcpfwd bindaddr support against trunk. needs merging.
--HG--
extra : convert_revision : 658fd03abd21e0da7c4c89b9fff9dc693c72daae
2010-02-27 11:51:19 +00:00
Matt Johnston
85288d7b61 - Progress for allowing specifying a listenaddr for tcp forwards
--HG--
extra : convert_revision : 48fdaa8706d1acda35e9d564adc9a1fbc96c18c8
2010-02-24 16:13:15 +00:00
Matt Johnston
8174a2f27b Mention -p's address argument in manpage synopsis
--HG--
extra : convert_revision : abef8fc8584889de6fd92ceaec28d094419462e0
2009-09-13 15:31:29 +00:00
Matt Johnston
e3ca0513a0 - Disable compression for non-final multihops
--HG--
extra : convert_revision : c507a2aacb9e0db4c0266891b8915c614e32857e
2009-09-11 14:02:04 +00:00
Matt Johnston
95a01f9002 Remove extraneous semicolon
--HG--
extra : convert_revision : ea33f9576dd0ff344d6f1d150a01265470f56131
2009-09-10 11:12:31 +00:00
Matt Johnston
52551cb771 - Test for pam_fail_delay() function in configure
- Recognise "username:" as a PAM prompt
- Add some randomness to the auth-failure delay
- Fix wrongly committed options.h/debug.h

--HG--
extra : convert_revision : f242f0e66fb0ea5d3b374995d2f548d37dd8f3a3
2009-09-08 14:53:53 +00:00
Matt Johnston
4dfb834f7c Move remotehost into svr_ses structure since we can't look it up
once we've forked (the connection socket has been closed).
Fixes inetd mode.

--HG--
extra : convert_revision : 7d5d152ec84fb11a188966c1400d213c908cc511
2009-09-05 11:40:00 +00:00
Matt Johnston
c35e38c5e9 - Remove options that dbclient won't know about
--HG--
extra : convert_revision : 2d401308f73352e92d3c662d33920b24fc12bfa1
2009-09-02 15:17:14 +00:00
Matt Johnston
48734bb3b5 - scp progressbar needs strlcat(), so add compat.o
--HG--
extra : convert_revision : 0743230bac5ae28d1b773fb4d89c4d88b6a9a0c1
2009-09-02 15:05:14 +00:00
Matt Johnston
4e9f22c602 - Set $SSH_CONNECTION
- Document environment variables in the manpage

--HG--
extra : convert_revision : 1a93c6112f00730f5cd21a853d3bd5ca8079f725
2009-09-02 14:47:12 +00:00
Matt Johnston
f88bed7a30 Rearrange getaddrstring() etc
--HG--
extra : convert_revision : 8a18c4a60aeaec085923d13d98fa0f93c506ceba
2009-09-01 16:38:26 +00:00
Matt Johnston
ccd02552dd - set $SSH_TTY environment variable
- remove extraneous (crash causing) printf()

--HG--
extra : convert_revision : cf4b256bf6785be384eca32f7b229b89e58539eb
2009-08-31 15:25:39 +00:00
Matt Johnston
4b1f9e50f2 - set $SSH_ORIGINAL_COMMAND if a command is forced, and log it
if LOG_COMMANDS is set

--HG--
extra : convert_revision : d9e8aa0ecbe7607285fa4f96f0d6f9b1523719d8
2009-08-26 14:09:22 +00:00
Matt Johnston
0b50010436 merge of '0d7a9127af37d6e74efc5ec031a7001ce63d334d'
and 'e35cd321b6d4fab6ad854827249f610da3bb6878'

--HG--
extra : convert_revision : a0fef159e70c5d1b24d10764066290362965e879
2009-08-25 11:11:35 +00:00
Matt Johnston
d773103730 - Move netcat struct to where it stays in scope.
--HG--
extra : convert_revision : e35cd321b6d4fab6ad854827249f610da3bb6878
2009-08-25 05:24:18 +00:00
Matt Johnston
c7e3eb9b3f - Don't print warning if SSH_AUTH_SOCK is unset
--HG--
extra : convert_revision : 0d7a9127af37d6e74efc5ec031a7001ce63d334d
2009-08-13 14:57:27 +00:00
Matt Johnston
f15feb2ac6 - Handle failure to connect to forwarding socket
--HG--
extra : convert_revision : 0cc1ae25ba35931d6ddd9e989e875ef975616be6
2009-07-31 15:51:33 +00:00
Matt Johnston
2f1ed9a34b propagate from branch 'au.asn.ucc.matt.dropbear.cli-agent' (head eb0dae4b62e243ba37a897beb7ba81a4f637d8b3)
to branch 'au.asn.ucc.matt.dropbear' (head ff0abce7b29e61630e3b09e5fc5820ae6e192808)

--HG--
extra : convert_revision : 49e078caffa785d121cefaf05b64fecc71fecd63
2009-07-30 15:15:12 +00:00
Matt Johnston
bb8234c2f1 Agent forwarding works
--HG--
branch : agent-client
extra : convert_revision : eb0dae4b62e243ba37a897beb7ba81a4f637d8b3
2009-07-30 15:14:33 +00:00
Matt Johnston
bacd2a8c79 propagate from branch 'au.asn.ucc.matt.dropbear' (head bbe4e11695a7b22bd89a722600eb4a4020b6fdf3)
to branch 'au.asn.ucc.matt.dropbear.cli-agent' (head 276cf5e82276b6c879d246ba64739ec6868f5150)

--HG--
branch : agent-client
extra : convert_revision : d23b0c21649eb2f0b2d13dbf33c0a9faca25628a
2009-07-29 02:58:33 +00:00
Matt Johnston
103a829eac Use /usr/bin/X11/xauth default path instead
--HG--
extra : convert_revision : ff0abce7b29e61630e3b09e5fc5820ae6e192808
2009-07-28 16:16:14 +00:00
Matt Johnston
0dcecfa526 Turn off DEBUG_TRACE accidentally committed
--HG--
extra : convert_revision : bbe4e11695a7b22bd89a722600eb4a4020b6fdf3
2009-07-26 16:14:50 +00:00
Matt Johnston
bcd541d65f - Payload length doesn't include macsize.
--HG--
extra : convert_revision : 98ac17a573ab350cbd6e358b3943237d2ad5c9cf
2009-07-26 16:11:27 +00:00
Matt Johnston
3608775306 - Add option to change zlib windowBits/memLevel
--HG--
extra : convert_revision : 5fc51ba0b8f165426c78f8d32162e5ccb51e524f
2009-07-26 15:39:47 +00:00
Matt Johnston
8181d41bb5 Disable Blowfish by default, it has inefficient key memory use
--HG--
extra : convert_revision : a37b8ae5fb524be221dbdfd71b4f35eb6a48565c
2009-07-24 13:49:07 +00:00
Matt Johnston
a996e61a2e - For uclinux, only cleanup on exit for the main process. This avoids
trashing the state when a failing child exits.

--HG--
extra : convert_revision : 5d029ce4602908c3becf0035cf2b7e62816959bc
2009-07-09 16:01:30 +00:00
Matt Johnston
8a19a049b2 - Client auth using an agent's key works. Still need to implement client
agent forwarding.

--HG--
branch : agent-client
extra : convert_revision : 276cf5e82276b6c879d246ba64739ec6868f5150
2009-07-06 14:02:45 +00:00
Matt Johnston
c742137dc8 New standard linked list to use, rather than adhoc SignKeyList or TCPFwdList
--HG--
branch : agent-client
extra : convert_revision : 5465e639cc3f5ee0c6c55f0de6e7b6d5a8769da3
2009-07-06 12:59:13 +00:00
Matt Johnston
9dc9aff016 Talking to the agent works now. Can't interpret the pubkeys.
--HG--
branch : agent-client
extra : convert_revision : 357373f28e889108178b8627480fd24bc26dcbd7
2009-07-01 06:27:27 +00:00
Matt Johnston
c6582dbe37 Make it compile, update for changes in channel structure.
--HG--
branch : agent-client
extra : convert_revision : 84676a98a0848224078a716b1292744a34e9d80c
2009-07-01 04:53:17 +00:00
Matt Johnston
709a3e75cf propagate from branch 'au.asn.ucc.matt.dropbear' (head 899a8851a5edf840b2f7925bcc26ffe99dcac54d)
to branch 'au.asn.ucc.matt.dropbear.cli-agent' (head 6bbab8364de17bd9ecb1dee5ffb796e48c0380d2)

--HG--
branch : agent-client
extra : convert_revision : d39a49137cc36b624768d4e79e564141dde8d355
2009-07-01 04:16:32 +00:00
Matt Johnston
cb82c6e3e0 - Print banner to stderr. Probably the right way, and avoids
bad interactions with multihop or netcat-alike mode.

--HG--
extra : convert_revision : 899a8851a5edf840b2f7925bcc26ffe99dcac54d
2009-06-16 15:22:33 +00:00
Matt Johnston
d6441f4397 - Make -i and -W pass through multihop arguments
--HG--
extra : convert_revision : 70c64073c9ec07b4dfb54ee60e39cec2bd8c6910
2009-06-12 14:58:43 +00:00
Matt Johnston
08893f03a5 - Don't memcpy() in place with void_encrypt
--HG--
extra : convert_revision : d123343d78df1b5998d8dd2674fd83fd682ce0c0
2009-06-09 13:18:52 +00:00
Matt Johnston
4be3826dd5 Wrap proxycmd function in ENABLE_CLI_PROXYCMD #ifdef
(commit the right file this time)

--HG--
extra : convert_revision : d86e846566d01b739b51fa2ecdb8f62006e38dbd
2009-06-08 14:53:29 +00:00
Matt Johnston
a21cf67a6c disapproval of revision '6d6160b277bfc7c2db6888a2ac91ac618cef6de3'
--HG--
extra : convert_revision : 64088637337d7b6024a9b48b9a616eecf8621cf6
2009-06-08 14:51:22 +00:00
Matt Johnston
fe03c39241 Wrap proxycmd function in ENABLE_CLI_PROXYCMD #ifdef
--HG--
extra : convert_revision : 6d6160b277bfc7c2db6888a2ac91ac618cef6de3
2009-06-08 14:44:23 +00:00
Matt Johnston
6e78eca7c8 use memset() rather than bzero()
--HG--
extra : convert_revision : d44b31a46d0fdfcc92bf4f16e7c49fd49eb40aa1
2009-06-08 14:40:29 +00:00
Matt Johnston
5d3dae1492 merge of '0a8dfaa3e5365a2004db2b55895e11f65b5cefcc'
and 'ef3b41f37e9f4dd45358bc40f9559ee23f71c284'

--HG--
extra : convert_revision : 36f4aee4c1a6a38c7904e2482102d8555ff45fa0
2009-03-17 22:30:39 +00:00
Matt Johnston
061565865c - Add the signal pipe to maxfd
--HG--
extra : convert_revision : 0a8dfaa3e5365a2004db2b55895e11f65b5cefcc
2009-03-17 22:30:25 +00:00
Matt Johnston
b639e18d39 - Turn DROPBEAR_SMALL_CODE off by default
--HG--
extra : convert_revision : ef3b41f37e9f4dd45358bc40f9559ee23f71c284
2009-03-03 13:42:54 +00:00
Matt Johnston
2b54d3397c Remove extraneous debugging
--HG--
extra : convert_revision : 58d53a027555e98d6d274b4659d38211eea7ad11
2009-03-03 13:20:00 +00:00
Matt Johnston
ff763e4005 - Get rid of decryptreadbuf, just decrypt in-place with readbuf
- Share make_mac function for both packet creation and validation
- Split recv/trans parts of key_context into their own structures

--HG--
extra : convert_revision : 043bc598c76ed43625987e6937e32238f7ed6240
2009-03-01 16:15:57 +00:00
Matt Johnston
8e72bbaa9d Encrypt in-place, avoid an extra malloc
--HG--
extra : convert_revision : 981e3e4b44e6fdc8537775518e898a33e76a38db
2009-03-01 14:38:25 +00:00
Matt Johnston
4b37932ba1 merge of 'e1c100e6366c5d607af08f4abdbb0f4281df4fa9'
and 'fe8161b0698c9816b98f79e3cab2b9d59f2be71b'

--HG--
extra : convert_revision : 23e1a99e40fc3baad5216b2a7e7318f8243f86a3
2009-02-26 13:21:14 +00:00
Matt Johnston
d1bfb6bfb7 disapproval of revision 'a101cbd046507cf723e6362a49196dbd4b924042'
--HG--
extra : convert_revision : e1c100e6366c5d607af08f4abdbb0f4281df4fa9
2009-02-26 13:20:53 +00:00
Matt Johnston
35f3d2ff90 merge of 'a101cbd046507cf723e6362a49196dbd4b924042'
and 'c8e1b84cfe874887ad7df0dd95a00de46dbc0136'

--HG--
extra : convert_revision : fe8161b0698c9816b98f79e3cab2b9d59f2be71b
2009-02-26 12:18:34 +00:00
Matt Johnston
a60cb7dbaa - Try to write out as much as we can
--HG--
extra : convert_revision : a101cbd046507cf723e6362a49196dbd4b924042
2009-02-26 12:18:11 +00:00
Matt Johnston
cca4e1a080 - Don't be dumb and encrypt/decrypt in a while() loop - why did I do this??
--HG--
extra : convert_revision : c8e1b84cfe874887ad7df0dd95a00de46dbc0136
2009-02-25 14:04:02 +00:00
Matt Johnston
c04cc62ebf - Allow building with neither server nor client specified
--HG--
extra : convert_revision : d9a8b717bf65021efa4c61c34faf24d050d95da4
2008-11-18 12:53:39 +00:00
Matt Johnston
8158e952b9 - Use the right variable notation
--HG--
extra : convert_revision : 8d1eddd800cc6c405f2b3eaad148433c0d6bc0c8
2008-11-18 12:53:02 +00:00
Matt Johnston
b717efb577 Only use -lcrypt for Dropbear server binary
--HG--
extra : convert_revision : 7d3d93a5f58d60933277ab6f2595d662e5fb1815
2008-11-17 14:04:14 +00:00
Matt Johnston
1912439526 Update nocrypto branch to current head
--HG--
branch : insecure-nocrypto
extra : convert_revision : 9e5e6e33be005d27cd5b3270c574edc45b5c2893
2008-11-06 13:33:06 +00:00
Matt Johnston
800810a181 propagate from branch 'au.asn.ucc.matt.dropbear' (head cdcc3c729e29544e8b98a408e2dc60e4483dfd2a)
to branch 'au.asn.ucc.matt.dropbear.insecure-nocrypto' (head 0ca38a1cf349f7426ac9de34ebe4c3e3735effab)

--HG--
branch : insecure-nocrypto
extra : convert_revision : dbb093e087a68abf2e54ab0b711af70771ddb29d
2008-11-06 13:16:55 +00:00
Matt Johnston
e674c73ee6 propagate from branch 'au.asn.ucc.matt.dropbear' (head 4fb35083f0f46ea667e7043e7d4314aecd3df46c)
to branch 'au.asn.ucc.matt.dropbear.cli-agent' (head 833d0adef6cdbf43ea75283524c665e70b0ee1ee)

--HG--
branch : agent-client
extra : convert_revision : 6bbab8364de17bd9ecb1dee5ffb796e48c0380d2
2008-09-23 16:05:04 +00:00
Matt Johnston
bb84e33d99 propagate from branch 'au.asn.ucc.matt.dropbear' (head fb7080ca6e254faaf7cfaee93b0ab6ab6de4ed59)
to branch 'au.asn.ucc.matt.dropbear.cli-agent' (head 78d02301ae8310efa2639f15da0ea62dea110e4b)

--HG--
branch : agent-client
extra : convert_revision : 833d0adef6cdbf43ea75283524c665e70b0ee1ee
2007-11-29 11:38:06 +00:00
Matt Johnston
e41452afeb propagate from branch 'au.asn.ucc.matt.dropbear' (head 8a7db1e2fdc5636abb338adb636babc32f465739)
to branch 'au.asn.ucc.matt.dropbear.cli-agent' (head d82c25da2f7e4fb6da510d806c64344e80bb270d)

--HG--
branch : agent-client
extra : convert_revision : 78d02301ae8310efa2639f15da0ea62dea110e4b
2007-08-16 13:34:37 +00:00
Matt Johnston
3301bad391 Comment cleanups
--HG--
branch : insecure-nocrypto
extra : convert_revision : 0ca38a1cf349f7426ac9de34ebe4c3e3735effab
2006-10-02 06:40:51 +00:00
Matt Johnston
f5d75b099b explicit merge of '0501e6f661b5415eb76f3b312d183c3adfbfb712'
and '2b954d406290e6a2be8eb4a262d3675ac95ac544'

--HG--
branch : insecure-nocrypto
extra : convert_revision : 9bd1d83f67b428efb0f0e8f55c6efc4749f635d9
2006-10-02 06:39:32 +00:00
Matt Johnston
1e26b86f15 propagate from branch 'au.asn.ucc.matt.dropbear' (head 138a11bc1e2babcd8b1182e6cb2a85d4e9404b11)
to branch 'au.asn.ucc.matt.dropbear.cli-agent' (head 12b2f59db65e7339d340e95ac67d6d9ddb193c2b)

--HG--
branch : agent-client
extra : convert_revision : d82c25da2f7e4fb6da510d806c64344e80bb270d
2006-06-06 15:40:09 +00:00
Matt Johnston
f7caf6f5c6 propagate from branch 'au.asn.ucc.matt.dropbear' (head 0501e6f661b5415eb76f3b312d183c3adfbfb712)
to branch 'au.asn.ucc.matt.dropbear.cli-agent' (head 01038174ec27245b51bd43a66c01ad930880f67b)

--HG--
branch : agent-client
extra : convert_revision : 12b2f59db65e7339d340e95ac67d6d9ddb193c2b
2006-03-21 16:20:59 +00:00
Matt Johnston
ba869e5601 propagate from branch 'au.asn.ucc.matt.dropbear' (head 7ad1775ed65e75dbece27fe6b65bf1a234db386a)
to branch 'au.asn.ucc.matt.dropbear.insecure-nocrypto' (head 88ed2b94d9bfec9a4f661caf592ed01da5eb3b6a)

--HG--
branch : insecure-nocrypto
extra : convert_revision : 2b954d406290e6a2be8eb4a262d3675ac95ac544
2006-03-10 06:30:52 +00:00
Matt Johnston
1632bd4a18 - a hack for grahame to run dropbear with "none" cipher.
DO NOT USE IF YOU DON'T KNOW THE CONSEQUENCES
  Here is your noose. Use it wisely.

--HG--
branch : insecure-nocrypto
extra : convert_revision : 88ed2b94d9bfec9a4f661caf592ed01da5eb3b6a
2005-09-23 16:29:19 +00:00
Matt Johnston
e444f0cfe6 - progress towards client agent forwarding
(incomplete and does not compile)

--HG--
branch : agent-client
extra : convert_revision : 01038174ec27245b51bd43a66c01ad930880f67b
2005-07-18 14:32:52 +00:00
108 changed files with 3650 additions and 2245 deletions

5
.hgsigs Normal file
View File

@@ -0,0 +1,5 @@
aa2f51a6b81d33de5e9898a7f27c792a173d9b26 0 iD8DBQBOuADmjPn4sExkf7wRAv/fAJ9FJFvjDoF+wd1ipDx1wkzdeBQNqgCgykUrSbXv76FBbxKntVbk9oS3GjI=
3f12086c2ef2b9ffe36a822fdb3ff647fcec1831 0 iD8DBQBOuSlQjPn4sExkf7wRAvkbAKCgE1e8xEMQ16CGeoywhIQ0QR4eNgCfZdYYlzjb/+521Uvh5/7FRYEmrho=
85f835f2fe0ac2c503c50a414de127222fb0a57c 0 iD8DBQBPRkMUjPn4sExkf7wRAvM4AJ9mw2OAkyjhSbamM1MizlEJUX18HACgoFKQkYf6BnYxN34Nv2HhM0cmzUc=
9b80981212fe6c01b7c16b3ca7c4e66af56f12f1 0 iEYEABECAAYFAlFLKKcACgkQjPn4sExkf7xK7wCfcioCmJPsysSbQO6+4qZMVe0mmLwAn2/o+wRf4MrUXlohrr7aXEF9vdSB
095b46180bbc412b029420587736a6185afc17e1 0 iEYEABECAAYFAlFsCnkACgkQjPn4sExkf7xLrwCfeMWjUaSmfU/fvseT5TdrYRqBEVQAoLz5SFLEA40C5f8zE8Ma/vgVJVIC

39
.hgtags Normal file
View File

@@ -0,0 +1,39 @@
03f65e461915a940939e4cc689fc89721ffc40de DROPBEAR_0.48.1
0f967bfef5cd0056b7ec60e2305d917e51cbf30d DROPBEAR_0.44
170329dc8ce5dfcf6298e1ad6699f109bf78e73d DROPBEAR_0.51
1dbd2473482f320ea59f76ce961385cb3a0150a9 DROPBEAR_0.46
2098857ab826dd42ae05a9a22c3ce2cc835b9844 DROPBEAR_0.45
36160290a1b27451178be36752ed038840f59cdd LTC_DB_0.46
39d5d58461d6e93337636e69d4cdf184a09c8d24 LTC_1.05
55a99934db873be2e63b5968fb6532e5d9bd02e4 DROPBEAR_0.48
59400faa4b44708c5d0b595e81193bc621e752d3 libtomcrypt-1.05
66087d87c3555c78b47cf01f32bb5a32054c3ceb DROPBEAR_0.44test4
677843bfa734238a67636b461a02c110c462ffaf DROPBEAR_0.44test1
7faae8f46238e23975430876547b8950b4e75481 t:ltc-0.95-orig
8220862baae829ebc762587b99c662480d57bb23 DROPBEAR_0.53
86e0b50a9b588239c3fc9cc9cfe255ef586df17b ltm-0.30-orig
88e0a1ad951add46b795511dc2698e36b4aee922 DROPBEAR_0.44test3
8e94663164c6e106ccc5c9e997dedf6e04d77dd2 LTM_DB_0.44
91fbc376f01084037cd5f6a5bf2e2db4903e8e99 libtommath-0.35
97db060d0ef5f8cf8e67eb602ef037055a185ca9 libtommath-0.40
aa2f51a6b81d33de5e9898a7f27c792a173d9b26 DROPBEAR_0.53.1
ab370c629d363f8c9a3eca512bfa86e362034654 DROPBEAR_0.49
c2ac796b130eeb6fa840873d8c230544c8ec7e4b DROPBEAR_0.44test2
cd1143579f00b0248c79f63ca70efee4a35a57e8 LTC_DB_0.44
ce104c8b0be1ff3f2c2590b7cdc3fd6870c865cd DROPBEAR_0.52
d5faf4814ddbc5abd9e209409bb9e7a4686c8cd7 libtomcrypt-1.16
d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1
d8254fc979e99560c93ca2cece77a6df31927ea5 LTM_0.35
e109027b9edfb02f0bdf96ec45bb1cd9ad41e7da LTM_DB_0.46
e109027b9edfb02f0bdf96ec45bb1cd9ad41e7da LTM_DB_0.47
e37b160c414cab6466622f63b0c4dcbf6ebc47a9 DROPBEAR_0.47
e430a26064ee86ab79aef372118d6d03b2441996 DROPBEAR_0.50
e5d119ea4c63656bc54ecfd865d04591ac2ed225 LTC_DB_0.47
3f12086c2ef2b9ffe36a822fdb3ff647fcec1831 DROPBEAR_2011.54
d354464b2aa6f6ba0bf44d43bcae5aa798435393 DROPBEAR_2012.55
7faae8f46238e23975430876547b8950b4e75481 t:ltc-0.95-orig
0000000000000000000000000000000000000000 t:ltc-0.95-orig
d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1
0000000000000000000000000000000000000000 t:ltc-0.95-db-merge1
1b8b2b9d6e94bc3cc5e61b620476ea36cc466e1b DROPBEAR_2013.56
96b8bcb88017815040949a417caa55686271e8a9 DROPBEAR_2013.57

192
CHANGES
View File

@@ -1,3 +1,195 @@
2013.58 - Thursday 18 April 2013
- Fix building with Zlib disabled, thanks to Hans Harder and cuma@freetz
- Use % as a separator for ports, fixes scp in multihop mode, from Hans Harder
- Reject logins for other users when running as non-root, from Hans Harder
- Disable client immediate authentication request by default, it prevents
passwordless logins from working
2013.57 - Monday 15 April 2013
- Decreased connection setup time particularly with high latency connections,
the number of round trips has been reduced for both client and server.
CPU time hasn't been changed.
- Client will send an initial key exchange guess to save a round trip.
Dropbear implements an extension kexguess2@matt.ucc.asn.au to allow the first
packet guess to succeed in wider circumstances than the standard behaviour.
When communicating with other implementations the standard behaviour is used.
- Client side: when public key or password authentication with
$DROPBEAR_PASSWORD is used an initial authentication request will
be sent immediately rather than querying the list of available methods.
This behaviour is enabled by CLI_IMMEDIATE_AUTH option (on by default),
please let the Dropbear author know if it causes any interoperability
problems.
- Implement client escape characters ~. (terminate session) and
~^Z (background session)
- Server will more reliably clean up utmp when connection is closed, reported by
Mattias Walström
- Don't crash if /dev/urandom isn't writable (RHEL5), thanks to Scott Case
- Add "-y -y" client option to skip host key checking, thanks to Hans Harder
- scp didn't work properly on systems using vfork(), thanks to Frank Van Uffelen
- Added IUTF8 terminal mode support (Linux and Mac OS). Not standardised yet
though probably will be soon
- Some verbose DROPBEAR_TRACE output is now hidden unless $DROPBEAR_TRACE2
enviroment variable is set
- Fix using asymmetric MAC algorithms (broke in )
- Renamed configure.in to configure.ac to quieten autoconf, from Mike Frysinger
2013.56 - Thursday 21 March 2013
- Allow specifying cipher (-c) and MAC (-m) lists for dbclient
- Allow using 'none' cipher or MAC (off by default, use options.h). Encryption
is used during authentication then disabled, similar to OpenSSH HPN mode
- Allow a user in immediately if the account has a blank password and blank
passwords are enabled
- Include a few extra sources of entropy from /proc on Linux, hash private keys
as well. Dropbear will also write gathered entropy back into /dev/urandom
- Added hmac-sha2-256 and hmac-sha2-512 support (off by default, use options.h)
- Don't sent bad address "localhost" for -R forward connections,
reported by Denis Bider
- Add "-B" runtime option to allow blank passwords
- Allow using IPv6 bracket notation for addresses in server "-p" option, from Ben Jencks
- A few improvements for Android from Reimar Döffinger
- Fix memory leak for TCP forwarded connections to hosts that timed out,
reported by Norbert Benczúr. Appears to be a very long-standing bug.
- Fix "make clean" for out of tree builds
- Fix compilation when ENABLE_{SVR,CLI}_AGENTFWD are unset
2012.55 - Wednesday 22 February 2012
- Security: Fix use-after-free bug that could be triggered if command="..."
authorized_keys restrictions are used. Could allow arbitrary code execution
or bypass of the command="..." restriction to an authenticated user.
This bug affects releases 0.52 onwards. Ref CVE-2012-0920.
Thanks to Danny Fullerton of Mantor Organization for reporting
the bug.
- Compile fix, only apply IPV6 socket options if they are available in headers
Thanks to Gustavo Zacarias for the patch
- Overwrite session key memory on exit
- Fix minor memory leak in unusual PAM authentication configurations.
Thanks to Stathis Voukelatos
- Other small code cleanups
2011.54 - Tuesday 8 November 2011
- Building statically works again, broke in 0.53 and 0.53.1
- Fix crash when forwarding with -R
- Fixed various leaks found by Klocwork analysis software, thanks to them for
running it
- Set IPTOS_LOWDELAY for IPv6, thanks to Dave Taht
- Bind to sockets with IPV6_V6ONLY so that it works properly on systems
regardless of the system-wide setting
- Added ALLOW_BLANK_PASSWORD option. Dropbear also now allows public key logins
to accounts with a blank password. Thanks to Rob Landley
- Fixed case where "-K 1" keepalive for dbclient would cause a SSH_MSG_IGNORE
packet to be sent
- Avoid some memory allocations in big number maths routines, improves
performance slightly
- Fix symlink target for installdropbearmulti with DESTDIR set, thanks to
Scottie Shore
- When requesting server allocated remote ports (-R 0:host:port) print a
message informing what the port is, thanks to Ali Onur Uyar.
- New version numbering scheme.
Source repository has now migrated to Mercurial at
https://secure.ucc.asn.au/hg/dropbear/graph/default
0.53.1 - Wednesday 2 March 2011
- -lcrypt needs to be before object files for static linking
- Compile fix when both client and agent forwarding are disabled
- Fix DROPBEAR_PRNGD_SOCKET mode
- Don't allow setting zlib memLevel since it seems buggy
0.53 - Thurs 24 February 2011
- Various performance/memory use improvements
- Client agent forwarding now works, using OpenSSH's ssh-agent
- Improve robustness of client multihop mode
- Fix a prime generation bug in bundled libtommath. This is unlikely to have
generated any bad keys in the wild.
See
https://bugzilla.redhat.com/show_bug.cgi?id=615088
http://bugs.gentoo.org/show_bug.cgi?id=328383
http://bugs.gentoo.org/show_bug.cgi?id=328409
- Attempt to build against system libtomcrypt/libtommath if available. This
can be disabled with ./configure --enable-bundled-libtom
- Make -K (keepalive) and -I (idle timeout) work together sensibly in the client.
The idle timeout is no longer reset by SSH_MSG_IGNORE packets.
- Add diffie-hellman-group14-sha1 key exchange method
- Compile fix if ENABLE_CLI_PROXYCMD is disabled
- /usr/bin/X11/xauth is now the default path
- Client remote forward (-L/-R) arguments now accept a listen address
- In uClinux avoid trashing the parent process when a session exits
- Blowfish is now disabled by default since it has large memory usage
- Add option to change zlib windowbits/memlevel. Use less memory by default
- DROPBEAR_SMALL_CODE is now disabled by default
- SSH_ORIGINAL_COMMAND environment variable is set by the server when an
authorized_keys command is specified.
- Set SSH_TTY and SSH_CONNECTION environment variables in the server
- Client banner is now printed to standard error rather than standard output
- Capitalisation in many log messages has been made consistent. This may affect
scripts that parse logfiles.
0.52 - Wed 12 November 2008
- Add "netcat-alike" option (-B) to dbclient, allowing Dropbear to tunnel

View File

@@ -16,20 +16,27 @@ endif
LTC=libtomcrypt/libtomcrypt.a
LTM=libtommath/libtommath.a
ifeq (@BUNDLED_LIBTOM@, 1)
LIBTOM_DEPS=$(LTC) $(LTM)
CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
LIBS+=$(LTC) $(LTM)
endif
COMMONOBJS=dbutil.o buffer.o \
dss.o bignum.o \
signkey.o rsa.o random.o \
queue.o \
atomicio.o compat.o fake-rfc2553.o
atomicio.o compat.o fake-rfc2553.o
SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \
SVROBJS=svr-kex.o svr-auth.o sshpty.o \
svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.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-authpam.o @CRYPTLIB@
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-channel.o cli-authinteract.o
CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
cli-session.o cli-runopts.o cli-chansession.o \
cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.o \
cli-agentfwd.o list.o
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
common-channel.o common-chansession.o termcodes.o loginrec.o \
@@ -40,7 +47,7 @@ KEYOBJS=dropbearkey.o gendss.o genrsa.o
CONVERTOBJS=dropbearconvert.o keyimport.o
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \
dss.h bignum.h signkey.h rsa.h random.h service.h auth.h \
@@ -49,7 +56,7 @@ HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \
loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \
listener.h fake-rfc2553.h
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) @CRYPTLIB@
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
@@ -69,8 +76,8 @@ RANLIB=@RANLIB@
STRIP=@STRIP@
INSTALL=@INSTALL@
CPPFLAGS=@CPPFLAGS@
CFLAGS=-I. -I$(srcdir) -I$(srcdir)/libtomcrypt/src/headers/ $(CPPFLAGS) @CFLAGS@
LIBS=$(LTC) $(LTM) @LIBS@
CFLAGS+=-I. -I$(srcdir) $(CPPFLAGS) @CFLAGS@
LIBS+=@LIBS@
LDFLAGS=@LDFLAGS@
EXEEXT=@EXEEXT@
@@ -106,10 +113,6 @@ ifeq ($(SCPPROGRESS), 1)
CFLAGS+=-DPROGRESS_METER
endif
#%: $(HEADERS)
#%: $(HEADERS) Makefile
# TODO
all: $(TARGETS)
strip: $(TARGETS)
@@ -126,12 +129,14 @@ insdbmulti: dropbearmulti
-chgrp 0 $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT)
insmultidropbear: dropbearmulti
$(INSTALL) -d -m 755 $(DESTDIR)$(sbindir)
-rm -f $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
-ln -s $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
insmulti%: dropbearmulti
$(INSTALL) -d -m 755 $(DESTDIR)$(bindir)
-rm -f $(DESTDIR)$(bindir)/$*$(EXEEXT)
-ln -s $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT)
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT)
# dropbear should go in sbin, so it needs a seperate rule
inst_dropbear: dropbear
@@ -153,8 +158,7 @@ dbclient: $(dbclientobjs)
dropbearkey: $(dropbearkeyobjs)
dropbearconvert: $(dropbearconvertobjs)
dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LTC) $(LTM) \
Makefile
dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBS)
# scp doesn't use the libs so is special.
@@ -165,13 +169,13 @@ scp: $(SCPOBJS) $(HEADERS) Makefile
# multi-binary compilation.
MULTIOBJS=
ifeq ($(MULTI),1)
MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs)))
MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs))) @CRYPTLIB@
CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
endif
dropbearmulti: multilink
multibinary: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) Makefile
multibinary: $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS)
multilink: multibinary $(addprefix link, $(PROGRAMS))

4
README
View File

@@ -1,4 +1,5 @@
This is Dropbear, a smallish SSH 2 server and client.
https://matt.ucc.asn.au/dropbear/dropbear.html
INSTALL has compilation instructions.
@@ -27,8 +28,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAwVa6M6cGVmUcLl2cFzkxEoJd06Ub4bVDsYrWvXhvUV+Z
You must make sure that ~/.ssh, and the key file, are only writable by the
user. Beware of editors that split the key into multiple lines.
NOTE: Dropbear ignores authorized_keys options such as those described in the
OpenSSH sshd manpage, and will not allow a login for these keys.
Dropbear supports some options for authorized_keys entries, see the manpage.
============================================================================

View File

@@ -23,21 +23,41 @@
* SOFTWARE. */
#ifndef _AGENTFWD_H_
#define _AGENTFWD_H_
#ifndef DISABLE_AGENTFWD
#include "includes.h"
#include "chansession.h"
#include "channel.h"
#include "auth.h"
#include "list.h"
int agentreq(struct ChanSess * chansess);
void agentsetauth(struct ChanSess *chansess);
void agentcleanup(struct ChanSess * chansess);
void agentset(struct ChanSess *chansess);
#ifdef ENABLE_CLI_AGENTFWD
/* An agent reply can be reasonably large, as it can
* contain a list of all public keys held by the agent.
* 10000 is arbitrary */
#define MAX_AGENT_REPLY 10000
/* client functions */
void cli_load_agent_keys(m_list * ret_list);
void agent_buf_sign(buffer *sigblob, sign_key *key,
const unsigned char *data, unsigned int len);
void cli_setup_agent(struct Channel *channel);
#ifdef __hpux
#define seteuid(a) setresuid(-1, (a), -1)
#define setegid(a) setresgid(-1, (a), -1)
#endif
#endif /* DROPBEAR_AGENTFWD */
extern const struct ChanType cli_chan_agent;
#endif /* ENABLE_CLI_AGENTFWD */
#ifdef ENABLE_SVR_AGENTFWD
int svr_agentreq(struct ChanSess * chansess);
void svr_agentcleanup(struct ChanSess * chansess);
void svr_agentset(struct ChanSess *chansess);
#endif /* ENABLE_SVR_AGENTFWD */
#endif /* _AGENTFWD_H_ */

26
algo.h
View File

@@ -50,7 +50,8 @@ extern algo_type sshkex[];
extern algo_type sshhostkey[];
extern algo_type sshciphers[];
extern algo_type sshhashes[];
extern algo_type sshcompress[];
extern algo_type ssh_compress[];
extern algo_type ssh_nocompress[];
extern const struct dropbear_cipher dropbear_nocipher;
extern const struct dropbear_cipher_mode dropbear_mode_none;
@@ -82,9 +83,24 @@ void crypto_init();
int have_algo(char* algo, size_t algolen, algo_type algos[]);
void buf_put_algolist(buffer * buf, algo_type localalgos[]);
algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
int *goodguess);
algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
int *goodguess);
enum kexguess2_used {
KEXGUESS2_LOOK,
KEXGUESS2_NO,
KEXGUESS2_YES,
};
#define KEXGUESS2_ALGO_NAME "kexguess2@matt.ucc.asn.au"
#define KEXGUESS2_ALGO_ID 99
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
enum kexguess2_used *kexguess2, int *goodguess);
#ifdef ENABLE_USER_ALGO_LIST
int check_user_algos(const char* user_algo_list, algo_type * algos,
const char *algo_desc);
char * algolist_string(algo_type algos[]);
#endif
#endif /* _ALGO_H_ */

19
auth.h
View File

@@ -26,6 +26,7 @@
#define _AUTH_H_
#include "includes.h"
#include "signkey.h"
#include "chansession.h"
void svr_authinitialise();
@@ -66,13 +67,14 @@ void recv_msg_userauth_pk_ok();
void recv_msg_userauth_info_request();
void cli_get_user();
void cli_auth_getmethods();
void cli_auth_try();
int cli_auth_try();
void recv_msg_userauth_banner();
void cli_pubkeyfail();
void cli_auth_password();
int cli_auth_pubkey();
void cli_auth_interactive();
char* getpass_or_cancel(char* prompt);
void cli_auth_pubkey_cleanup();
#define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
@@ -97,7 +99,6 @@ char* getpass_or_cancel(char* prompt);
* relatively little extraneous bits when used for the client rather than the
* server */
struct AuthState {
char *username; /* This is the username the client presents to check. It
is updated each run through, used for auth checking */
unsigned char authtypes; /* Flags indicating which auth types are still
@@ -120,19 +121,6 @@ struct AuthState {
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
struct PubKeyOptions* pubkey_options;
#endif
};
struct SignKeyList;
/* A singly linked list of signing keys */
struct SignKeyList {
sign_key *key;
int type; /* The type of key */
struct SignKeyList *next;
/* filename? or the buffer? for encrypted keys, so we can later get
* the private key portion */
};
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
@@ -145,7 +133,6 @@ struct PubKeyOptions {
int no_pty_flag;
/* "command=" option. */
unsigned char * forced_command;
};
#endif

View File

@@ -31,7 +31,7 @@
void m_mp_init(mp_int *mp) {
if (mp_init(mp) != MP_OKAY) {
dropbear_exit("mem alloc error");
dropbear_exit("Mem alloc error");
}
}
@@ -45,7 +45,7 @@ void m_mp_init_multi(mp_int *mp, ...)
va_start(args, mp); /* init args to next argument from caller */
while (cur_arg != NULL) {
if (mp_init(cur_arg) != MP_OKAY) {
dropbear_exit("mem alloc error");
dropbear_exit("Mem alloc error");
}
cur_arg = va_arg(args, mp_int*);
}
@@ -55,7 +55,7 @@ void m_mp_init_multi(mp_int *mp, ...)
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {
if (mp_read_unsigned_bin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
dropbear_exit("mem alloc error");
dropbear_exit("Mem alloc error");
}
}

View File

@@ -26,9 +26,10 @@
#define _BIGNUM_H_
#include "includes.h"
#include "dbutil.h"
void m_mp_init(mp_int *mp);
void m_mp_init_multi(mp_int *mp, ...);
void m_mp_init_multi(mp_int *mp, ...) ATTRIB_SENTINEL;
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
void sha1_process_mp(hash_state *hs, mp_int *mp);

View File

@@ -106,7 +106,7 @@ buffer* buf_newcopy(buffer* buf) {
/* Set the length of the buffer */
void buf_setlen(buffer* buf, unsigned int len) {
if (len > buf->size) {
dropbear_exit("bad buf_setlen");
dropbear_exit("Bad buf_setlen");
}
buf->len = len;
}
@@ -114,7 +114,7 @@ void buf_setlen(buffer* buf, unsigned int len) {
/* Increment the length of the buffer */
void buf_incrlen(buffer* buf, unsigned int incr) {
if (incr > BUF_MAX_INCR || buf->len + incr > buf->size) {
dropbear_exit("bad buf_incrlen");
dropbear_exit("Bad buf_incrlen");
}
buf->len += incr;
}
@@ -122,7 +122,7 @@ void buf_incrlen(buffer* buf, unsigned int incr) {
void buf_setpos(buffer* buf, unsigned int pos) {
if (pos > buf->len) {
dropbear_exit("bad buf_setpos");
dropbear_exit("Bad buf_setpos");
}
buf->pos = pos;
}
@@ -130,7 +130,7 @@ void buf_setpos(buffer* buf, unsigned int pos) {
/* increment the postion by incr, increasing the buffer length if required */
void buf_incrwritepos(buffer* buf, unsigned int incr) {
if (incr > BUF_MAX_INCR || buf->pos + incr > buf->size) {
dropbear_exit("bad buf_incrwritepos");
dropbear_exit("Bad buf_incrwritepos");
}
buf->pos += incr;
if (buf->pos > buf->len) {
@@ -144,7 +144,7 @@ void buf_incrpos(buffer* buf, int incr) {
if (incr > BUF_MAX_INCR ||
(unsigned int)((int)buf->pos + incr) > buf->len
|| ((int)buf->pos + incr) < 0) {
dropbear_exit("bad buf_incrpos");
dropbear_exit("Bad buf_incrpos");
}
buf->pos += incr;
}
@@ -155,7 +155,7 @@ unsigned char buf_getbyte(buffer* buf) {
/* This check is really just ==, but the >= allows us to check for the
* bad case of pos > len, which should _never_ happen. */
if (buf->pos >= buf->len) {
dropbear_exit("bad buf_getbyte");
dropbear_exit("Bad buf_getbyte");
}
return buf->data[buf->pos++];
}
@@ -185,7 +185,7 @@ void buf_putbyte(buffer* buf, unsigned char val) {
unsigned char* buf_getptr(buffer* buf, unsigned int len) {
if (buf->pos + len > buf->len) {
dropbear_exit("bad buf_getptr");
dropbear_exit("Bad buf_getptr");
}
return &buf->data[buf->pos];
}
@@ -195,7 +195,7 @@ unsigned char* buf_getptr(buffer* buf, unsigned int len) {
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len) {
if (buf->pos + len > buf->size) {
dropbear_exit("bad buf_getwriteptr");
dropbear_exit("Bad buf_getwriteptr");
}
return &buf->data[buf->pos];
}
@@ -209,7 +209,7 @@ unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
unsigned char* ret;
len = buf_getint(buf);
if (len > MAX_STRING_LEN) {
dropbear_exit("string too long");
dropbear_exit("String too long");
}
if (retlen != NULL) {
@@ -223,6 +223,20 @@ unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
return ret;
}
/* Return a string as a newly allocated buffer */
buffer * buf_getstringbuf(buffer *buf) {
buffer *ret;
unsigned char* str;
unsigned int len;
str = buf_getstring(buf, &len);
ret = m_malloc(sizeof(*ret));
ret->data = str;
ret->len = len;
ret->size = len;
ret->pos = 0;
return ret;
}
/* Just increment the buffer position the same as if we'd used buf_getstring,
* but don't bother copying/malloc()ing for it */
void buf_eatstring(buffer *buf) {
@@ -268,7 +282,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"))
TRACE2(("enter buf_putmpint"))
dropbear_assert(mp != NULL);
@@ -304,7 +318,7 @@ void buf_putmpint(buffer* buf, mp_int * mp) {
buf_incrwritepos(buf, len-pad);
}
TRACE(("leave buf_putmpint"))
TRACE2(("leave buf_putmpint"))
}
/* Retrieve an mp_int from the buffer.

View File

@@ -55,6 +55,7 @@ void buf_putbyte(buffer* buf, unsigned char val);
unsigned char* buf_getptr(buffer* buf, unsigned int len);
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len);
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen);
buffer * buf_getstringbuf(buffer *buf);
void buf_eatstring(buffer *buf);
void buf_putint(buffer* buf, unsigned int val);
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len);

View File

@@ -58,10 +58,11 @@ struct Channel {
unsigned int recvmaxpacket, transmaxpacket;
void* typedata; /* a pointer to type specific data */
int writefd; /* read from wire, written to insecure side */
int readfd; /* read from insecure size, written to wire */
int readfd; /* read from insecure side, written to wire */
int errfd; /* used like writefd or readfd, 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 *writebuf; /* data from the wire, for local consumption. Can be
initially NULL */
circbuffer *extrabuf; /* extended-data for the program - used like writebuf
but for stderr */
@@ -69,6 +70,10 @@ struct Channel {
int sent_close, recv_close;
int recv_eof, sent_eof;
/* Set after running the ChanType-specific close hander
* to ensure we don't run it twice (nor type->checkclose()). */
int close_handler_done;
int initconn; /* used for TCP forwarding, whether the channel has been
fully initialised */
@@ -78,8 +83,10 @@ struct Channel {
int flushing;
const struct ChanType* type;
/* Used by client chansession to handle ~ escaping, NULL ignored otherwise */
void (*read_mangler)(struct Channel*, unsigned char* bytes, int *len);
const struct ChanType* type;
};
struct ChanType {
@@ -98,9 +105,6 @@ void chancleanup();
void setchannelfds(fd_set *readfd, fd_set *writefd);
void channelio(fd_set *readfd, fd_set *writefd);
struct Channel* getchannel();
struct Channel* newchannel(unsigned int remotechan,
const struct ChanType *type,
unsigned int transwindow, unsigned int transmaxpacket);
void recv_msg_channel_open();
void recv_msg_channel_request();

View File

@@ -50,6 +50,10 @@ struct ChanSess {
/* exit details */
struct exitinfo exit;
/* Used to set $SSH_CONNECTION in the child session.
Is only set temporarily before forking */
char *connection_string;
#ifndef DISABLE_X11FWD
struct Listener * x11listener;
@@ -60,11 +64,15 @@ struct ChanSess {
unsigned char x11singleconn;
#endif
#ifndef DISABLE_AGENTFWD
#ifdef ENABLE_SVR_AGENTFWD
struct Listener * agentlistener;
char * agentfile;
char * agentdir;
#endif
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
char *original_command;
#endif
};
struct ChildPid {
@@ -81,6 +89,7 @@ void cli_chansess_winchange();
#ifdef ENABLE_CLI_NETCAT
void cli_send_netcat_request();
#endif
void cli_start_send_channel_request(struct Channel *channel, unsigned char *type);
void svr_chansessinitialise();
extern const struct ChanType svrchansess;

View File

@@ -33,11 +33,13 @@ circbuffer * cbuf_new(unsigned int size) {
circbuffer *cbuf = NULL;
if (size > MAX_CBUF_SIZE) {
dropbear_exit("bad cbuf size");
dropbear_exit("Bad cbuf size");
}
cbuf = (circbuffer*)m_malloc(sizeof(circbuffer));
cbuf->data = (unsigned char*)m_malloc(size);
if (size > 0) {
cbuf->data = (unsigned char*)m_malloc(size);
}
cbuf->used = 0;
cbuf->readpos = 0;
cbuf->writepos = 0;
@@ -48,6 +50,7 @@ circbuffer * cbuf_new(unsigned int size) {
void cbuf_free(circbuffer * cbuf) {
m_burn(cbuf->data, cbuf->size);
m_free(cbuf->data);
m_free(cbuf);
}
@@ -101,7 +104,7 @@ unsigned int cbuf_writelen(circbuffer *cbuf) {
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_readlen(cbuf)) {
dropbear_exit("bad cbuf read");
dropbear_exit("Bad cbuf read");
}
return &cbuf->data[cbuf->readpos];
@@ -110,7 +113,7 @@ unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) {
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_writelen(cbuf)) {
dropbear_exit("bad cbuf write");
dropbear_exit("Bad cbuf write");
}
return &cbuf->data[cbuf->writepos];
@@ -118,7 +121,7 @@ unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_writelen(cbuf)) {
dropbear_exit("bad cbuf write");
dropbear_exit("Bad cbuf write");
}
cbuf->used += len;
@@ -129,7 +132,7 @@ void cbuf_incrwrite(circbuffer *cbuf, unsigned int len) {
void cbuf_incrread(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_readlen(cbuf)) {
dropbear_exit("bad cbuf read");
dropbear_exit("Bad cbuf read");
}
dropbear_assert(cbuf->used >= len);

309
cli-agentfwd.c Normal file
View File

@@ -0,0 +1,309 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2005 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#ifdef ENABLE_CLI_AGENTFWD
#include "agentfwd.h"
#include "session.h"
#include "ssh.h"
#include "dbutil.h"
#include "chansession.h"
#include "channel.h"
#include "packet.h"
#include "buffer.h"
#include "random.h"
#include "listener.h"
#include "runopts.h"
#include "atomicio.h"
#include "signkey.h"
#include "auth.h"
/* The protocol implemented to talk to OpenSSH's SSH2 agent is documented in
PROTOCOL.agent in recent OpenSSH source distributions (5.1p1 has it). */
static int new_agent_chan(struct Channel * channel);
const struct ChanType cli_chan_agent = {
0, /* sepfds */
"auth-agent@openssh.com",
new_agent_chan,
NULL,
NULL,
NULL
};
static int connect_agent() {
int fd = -1;
char* agent_sock = NULL;
agent_sock = getenv("SSH_AUTH_SOCK");
if (agent_sock == NULL)
return -1;
fd = connect_unix(agent_sock);
if (fd < 0) {
dropbear_log(LOG_INFO, "Failed to connect to agent");
}
return fd;
}
// handle a request for a connection to the locally running ssh-agent
// or forward.
static int new_agent_chan(struct Channel * channel) {
int fd = -1;
if (!cli_opts.agent_fwd)
return SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
fd = connect_agent();
if (fd < 0) {
return SSH_OPEN_CONNECT_FAILED;
}
setnonblocking(fd);
ses.maxfd = MAX(ses.maxfd, fd);
channel->readfd = fd;
channel->writefd = fd;
// success
return 0;
}
/* Sends a request to the agent, returning a newly allocated buffer
* with the response */
/* This function will block waiting for a response - it will
* only be used by client authentication (not for forwarded requests)
* won't cause problems for interactivity. */
/* Packet format (from draft-ylonen)
4 bytes Length, msb first. Does not include length itself.
1 byte Packet type. The value 255 is reserved for future extensions.
data Any data, depending on packet type. Encoding as in the ssh packet
protocol.
*/
static buffer * agent_request(unsigned char type, buffer *data) {
buffer * payload = NULL;
buffer * inbuf = NULL;
size_t readlen = 0;
ssize_t ret;
const int fd = cli_opts.agent_fd;
unsigned int data_len = 0;
if (data)
{
data_len = data->len;
}
payload = buf_new(4 + 1 + data_len);
buf_putint(payload, 1 + data_len);
buf_putbyte(payload, type);
if (data) {
buf_putbytes(payload, data->data, data->len);
}
buf_setpos(payload, 0);
ret = atomicio(write, fd, buf_getptr(payload, payload->len), payload->len);
if ((size_t)ret != payload->len) {
TRACE(("write failed fd %d for agent_request, %s", fd, strerror(errno)))
goto out;
}
buf_free(payload);
payload = NULL;
TRACE(("Wrote out bytes for agent_request"))
/* Now we read the response */
inbuf = buf_new(4);
ret = atomicio(read, fd, buf_getwriteptr(inbuf, 4), 4);
if (ret != 4) {
TRACE(("read of length failed for agent_request"))
goto out;
}
buf_setpos(inbuf, 0);
buf_setlen(inbuf, ret);
readlen = buf_getint(inbuf);
if (readlen > MAX_AGENT_REPLY) {
TRACE(("agent reply is too big"));
goto out;
}
buf_resize(inbuf, readlen);
buf_setpos(inbuf, 0);
ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen);
if ((size_t)ret != readlen) {
TRACE(("read of data failed for agent_request"))
goto out;
}
buf_incrwritepos(inbuf, readlen);
buf_setpos(inbuf, 0);
out:
if (payload)
buf_free(payload);
return inbuf;
}
static void agent_get_key_list(m_list * ret_list)
{
buffer * inbuf = NULL;
unsigned int num = 0;
unsigned char packet_type;
unsigned int i;
int ret;
inbuf = agent_request(SSH2_AGENTC_REQUEST_IDENTITIES, NULL);
if (!inbuf) {
TRACE(("agent_request failed returning identities"))
goto out;
}
/* The reply has a format of:
byte SSH2_AGENT_IDENTITIES_ANSWER
uint32 num_keys
Followed by zero or more consecutive keys, encoded as:
string key_blob
string key_comment
*/
packet_type = buf_getbyte(inbuf);
if (packet_type != SSH2_AGENT_IDENTITIES_ANSWER) {
goto out;
}
num = buf_getint(inbuf);
for (i = 0; i < num; i++) {
sign_key * pubkey = NULL;
int key_type = DROPBEAR_SIGNKEY_ANY;
buffer * key_buf;
/* each public key is encoded as a string */
key_buf = buf_getstringbuf(inbuf);
pubkey = new_sign_key();
ret = buf_get_pub_key(key_buf, pubkey, &key_type);
buf_free(key_buf);
if (ret != DROPBEAR_SUCCESS) {
/* This is slack, properly would cleanup vars etc */
dropbear_exit("Bad pubkey received from agent");
}
pubkey->type = key_type;
pubkey->source = SIGNKEY_SOURCE_AGENT;
list_append(ret_list, pubkey);
/* We'll ignore the comment for now. might want it later.*/
buf_eatstring(inbuf);
}
out:
if (inbuf) {
buf_free(inbuf);
inbuf = NULL;
}
}
void cli_setup_agent(struct Channel *channel) {
if (!getenv("SSH_AUTH_SOCK")) {
return;
}
cli_start_send_channel_request(channel, "auth-agent-req@openssh.com");
/* Don't want replies */
buf_putbyte(ses.writepayload, 0);
encrypt_packet();
}
/* Returned keys are prepended to ret_list, which will
be updated. */
void cli_load_agent_keys(m_list *ret_list) {
/* agent_fd will be closed after successful auth */
cli_opts.agent_fd = connect_agent();
if (cli_opts.agent_fd < 0) {
return;
}
agent_get_key_list(ret_list);
}
void agent_buf_sign(buffer *sigblob, sign_key *key,
const unsigned char *data, unsigned int len) {
buffer *request_data = NULL;
buffer *response = NULL;
unsigned int siglen;
int packet_type;
/* Request format
byte SSH2_AGENTC_SIGN_REQUEST
string key_blob
string data
uint32 flags
*/
request_data = buf_new(MAX_PUBKEY_SIZE + len + 12);
buf_put_pub_key(request_data, key, key->type);
buf_putstring(request_data, data, len);
buf_putint(request_data, 0);
response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);
if (!response) {
goto fail;
}
packet_type = buf_getbyte(response);
if (packet_type != SSH2_AGENT_SIGN_RESPONSE) {
goto fail;
}
/* Response format
byte SSH2_AGENT_SIGN_RESPONSE
string signature_blob
*/
siglen = buf_getint(response);
buf_putbytes(sigblob, buf_getptr(response, siglen), siglen);
goto cleanup;
fail:
/* XXX don't fail badly here. instead propagate a failure code back up to
the cli auth pubkey code, and just remove this key from the list of
ones to try. */
dropbear_exit("Agent failed signing key");
cleanup:
if (request_data) {
buf_free(request_data);
}
if (response) {
buf_free(response);
}
}
#endif

View File

@@ -1,99 +0,0 @@
/*
* Dropbear - a SSH2 server
* SSH client implementation
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "algo.h"
#include "dbutil.h"
/*
* The chosen [encryption | MAC | compression] algorithm to each
* direction MUST be the first algorithm on the client's list
* that is also on the server's list.
*/
algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
int *goodguess) {
unsigned char * algolist = NULL;
unsigned char * remotealgos[MAX_PROPOSED_ALGO];
unsigned int len;
unsigned int count, i, j;
algo_type * ret = NULL;
*goodguess = 0;
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
algolist = buf_getstring(buf, &len);
TRACE(("cli_buf_match_algo: %s", algolist))
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
goto out; /* just a sanity check, no other use */
}
/* remotealgos will contain a list of the strings parsed out */
/* We will have at least one string (even if it's just "") */
remotealgos[0] = algolist;
count = 1;
/* Iterate through, replacing ','s with NULs, to split it into
* words. */
for (i = 0; i < len; i++) {
if (algolist[i] == '\0') {
/* someone is trying something strange */
goto out;
}
if (algolist[i] == ',') {
algolist[i] = '\0';
remotealgos[count] = &algolist[i+1];
count++;
}
if (count == MAX_PROPOSED_ALGO) {
break;
}
}
/* iterate and find the first match */
for (j = 0; localalgos[j].name != NULL; j++) {
if (localalgos[j].usable) {
len = strlen(localalgos[j].name);
for (i = 0; i < count; i++) {
if (len == strlen(remotealgos[i])
&& strncmp(localalgos[j].name,
remotealgos[i], len) == 0) {
if (i == 0 && j == 0) {
/* was a good guess */
*goodguess = 1;
}
ret = &localalgos[j];
goto out;
}
}
}
}
out:
m_free(algolist);
return ret;
}

View File

@@ -40,11 +40,18 @@ void cli_authinitialise() {
/* Send a "none" auth request to get available methods */
void cli_auth_getmethods() {
TRACE(("enter cli_auth_getmethods"))
#ifdef CLI_IMMEDIATE_AUTH
ses.authstate.authtypes = AUTH_TYPE_PUBKEY;
if (getenv(DROPBEAR_PASSWORD_ENV)) {
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT;
}
if (cli_auth_try() == DROPBEAR_SUCCESS) {
TRACE(("skipped initial none auth query"))
return;
}
#endif
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
buf_putstring(ses.writepayload, cli_opts.username,
strlen(cli_opts.username));
@@ -54,7 +61,6 @@ void cli_auth_getmethods() {
encrypt_packet();
TRACE(("leave cli_auth_getmethods"))
}
void recv_msg_userauth_banner() {
@@ -91,7 +97,7 @@ void recv_msg_userauth_banner() {
}
}
printf("%s\n", banner);
fprintf(stderr, "%s\n", banner);
out:
m_free(banner);
@@ -234,9 +240,13 @@ void recv_msg_userauth_success() {
ses.authstate.authdone = 1;
cli_ses.state = USERAUTH_SUCCESS_RCVD;
cli_ses.lastauthtype = AUTH_TYPE_NONE;
#ifdef ENABLE_CLI_PUBKEY_AUTH
cli_auth_pubkey_cleanup();
#endif
}
void cli_auth_try() {
int cli_auth_try() {
int finished = 0;
TRACE(("enter cli_auth_try"))
@@ -252,33 +262,40 @@ void cli_auth_try() {
}
#endif
#ifdef ENABLE_CLI_INTERACT_AUTH
if (!finished && ses.authstate.authtypes & AUTH_TYPE_INTERACT) {
if (cli_ses.auth_interact_failed) {
finished = 0;
#ifdef ENABLE_CLI_PASSWORD_AUTH
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_PASSWORD)) {
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n");
} else {
cli_auth_interactive();
cli_ses.lastauthtype = AUTH_TYPE_INTERACT;
cli_auth_password();
finished = 1;
cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
}
}
#endif
#ifdef ENABLE_CLI_PASSWORD_AUTH
if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
cli_auth_password();
finished = 1;
cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
#ifdef ENABLE_CLI_INTERACT_AUTH
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_INTERACT)) {
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
fprintf(stderr, "Sorry, I won't let you use interactive auth unencrypted.\n");
} else {
if (!cli_ses.auth_interact_failed) {
cli_auth_interactive();
cli_ses.lastauthtype = AUTH_TYPE_INTERACT;
finished = 1;
}
}
}
#endif
TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype))
if (!finished) {
dropbear_exit("No auth methods could be used.");
if (finished) {
TRACE(("leave cli_auth_try success"))
return DROPBEAR_SUCCESS;
}
TRACE(("leave cli_auth_try"))
TRACE(("leave cli_auth_try failure"))
return DROPBEAR_FAILURE;
}
/* A helper for getpass() that exits if the user cancels. The returned

View File

@@ -131,6 +131,7 @@ void recv_msg_userauth_info_request() {
response_len = strlen(response);
buf_putstring(ses.writepayload, response, response_len);
m_burn(response, response_len);
m_free(prompt);
m_free(response);
}

View File

@@ -30,6 +30,7 @@
#include "ssh.h"
#include "runopts.h"
#include "auth.h"
#include "agentfwd.h"
#ifdef ENABLE_CLI_PUBKEY_AUTH
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
@@ -37,30 +38,23 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
/* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request.
* We use it to remove the key we tried from the list */
void cli_pubkeyfail() {
struct SignKeyList *keyitem;
struct SignKeyList **previtem;
TRACE(("enter cli_pubkeyfail"))
previtem = &cli_opts.privkeys;
/* Find the key we failed with, and remove it */
for (keyitem = cli_opts.privkeys; keyitem != NULL; keyitem = keyitem->next) {
if (keyitem == cli_ses.lastprivkey) {
*previtem = keyitem->next;
m_list_elem *iter;
for (iter = cli_opts.privkeys->first; iter; iter = iter->next) {
sign_key *iter_key = (sign_key*)iter->item;
if (iter_key == cli_ses.lastprivkey)
{
/* found the failing key */
list_remove(iter);
sign_key_free(iter_key);
cli_ses.lastprivkey = NULL;
return;
}
previtem = &keyitem;
}
sign_key_free(cli_ses.lastprivkey->key); /* It won't be used again */
m_free(cli_ses.lastprivkey);
TRACE(("leave cli_pubkeyfail"))
}
void recv_msg_userauth_pk_ok() {
struct SignKeyList *keyitem = NULL;
m_list_elem *iter;
buffer* keybuf = NULL;
char* algotype = NULL;
unsigned int algolen;
@@ -80,9 +74,9 @@ void recv_msg_userauth_pk_ok() {
/* Iterate through our keys, find which one it was that matched, and
* send a real request with that key */
for (keyitem = cli_opts.privkeys; keyitem != NULL; keyitem = keyitem->next) {
if (keyitem->type != keytype) {
for (iter = cli_opts.privkeys->first; iter; iter = iter->next) {
sign_key *key = (sign_key*)iter->item;
if (key->type != keytype) {
/* Types differed */
TRACE(("types differed"))
continue;
@@ -90,7 +84,7 @@ void recv_msg_userauth_pk_ok() {
/* Now we compare the contents of the key */
keybuf->pos = keybuf->len = 0;
buf_put_pub_key(keybuf, keyitem->key, keytype);
buf_put_pub_key(keybuf, key, keytype);
buf_setpos(keybuf, 0);
buf_incrpos(keybuf, 4); /* first int is the length of the remainder (ie
remotelen) which has already been taken from
@@ -114,11 +108,11 @@ void recv_msg_userauth_pk_ok() {
}
buf_free(keybuf);
if (keyitem != NULL) {
if (iter != NULL) {
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);
send_msg_userauth_pubkey((sign_key*)iter->item, 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"))
}
@@ -126,6 +120,27 @@ void recv_msg_userauth_pk_ok() {
TRACE(("leave recv_msg_userauth_pk_ok"))
}
void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
const unsigned char *data, unsigned int len)
{
#ifdef ENABLE_CLI_AGENTFWD
if (key->source == SIGNKEY_SOURCE_AGENT) {
/* Format the agent signature ourselves, as buf_put_sign would. */
buffer *sigblob;
sigblob = buf_new(MAX_PUBKEY_SIZE);
agent_buf_sign(sigblob, key, data, len);
buf_setpos(sigblob, 0);
buf_putstring(buf, buf_getptr(sigblob, sigblob->len),
sigblob->len);
buf_free(sigblob);
} else
#endif /* ENABLE_CLI_AGENTFWD */
{
buf_put_sign(buf, key, type, data, len);
}
}
/* TODO: make it take an agent reference to use as well */
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
@@ -161,7 +176,7 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
sigbuf = buf_new(4 + SHA1_HASH_SIZE + ses.writepayload->len);
buf_putstring(sigbuf, ses.session_id, SHA1_HASH_SIZE);
buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len);
buf_put_sign(ses.writepayload, key, type, sigbuf->data, sigbuf->len);
cli_buf_put_sign(ses.writepayload, key, type, sigbuf->data, sigbuf->len);
buf_free(sigbuf); /* Nothing confidential in the buffer */
}
@@ -169,20 +184,43 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
TRACE(("leave send_msg_userauth_pubkey"))
}
/* Returns 1 if a key was tried */
int cli_auth_pubkey() {
TRACE(("enter cli_auth_pubkey"))
if (cli_opts.privkeys != NULL) {
#ifdef ENABLE_CLI_AGENTFWD
if (!cli_opts.agent_keys_loaded) {
/* get the list of available keys from the agent */
cli_load_agent_keys(cli_opts.privkeys);
cli_opts.agent_keys_loaded = 1;
}
#endif
if (cli_opts.privkeys->first) {
sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
/* Send a trial request */
send_msg_userauth_pubkey(cli_opts.privkeys->key,
cli_opts.privkeys->type, 0);
cli_ses.lastprivkey = cli_opts.privkeys;
send_msg_userauth_pubkey(key, key->type, 0);
cli_ses.lastprivkey = key;
TRACE(("leave cli_auth_pubkey-success"))
return 1;
} else {
/* no more keys left */
TRACE(("leave cli_auth_pubkey-failure"))
return 0;
}
}
void cli_auth_pubkey_cleanup() {
#ifdef ENABLE_CLI_AGENTFWD
m_close(cli_opts.agent_fd);
cli_opts.agent_fd = -1;
#endif
while (cli_opts.privkeys->first) {
sign_key * key = list_remove(cli_opts.privkeys->first);
sign_key_free(key);
}
}
#endif /* Pubkey auth */

View File

@@ -33,15 +33,15 @@
#include "runopts.h"
#include "termcodes.h"
#include "chansession.h"
#include "agentfwd.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);
static void send_chansess_pty_req(struct Channel *channel);
static void send_chansess_shell_req(struct Channel *channel);
static void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len);
static void cli_tty_setup();
@@ -82,17 +82,15 @@ out:
/* If the main session goes, we close it up */
static void cli_closechansess(struct Channel *UNUSED(channel)) {
cli_tty_cleanup(); /* Restore tty modes etc */
/* This channel hasn't gone yet, so we have > 1 */
if (ses.chancount > 1) {
dropbear_log(LOG_INFO, "Waiting for other channels to close...");
}
cli_tty_cleanup(); /* Restore tty modes etc */
}
static void start_channel_request(struct Channel *channel,
void cli_start_send_channel_request(struct Channel *channel,
unsigned char *type) {
CHECKCLEARTOWRITE();
@@ -287,7 +285,7 @@ static void send_chansess_pty_req(struct Channel *channel) {
TRACE(("enter send_chansess_pty_req"))
start_channel_request(channel, "pty-req");
cli_start_send_channel_request(channel, "pty-req");
/* Don't want replies */
buf_putbyte(ses.writepayload, 0);
@@ -309,7 +307,7 @@ static void send_chansess_pty_req(struct Channel *channel) {
/* Set up a window-change handler */
if (signal(SIGWINCH, sigwinch_handler) == SIG_ERR) {
dropbear_exit("signal error");
dropbear_exit("Signal error");
}
TRACE(("leave send_chansess_pty_req"))
}
@@ -330,7 +328,7 @@ static void send_chansess_shell_req(struct Channel *channel) {
reqtype = "shell";
}
start_channel_request(channel, reqtype);
cli_start_send_channel_request(channel, reqtype);
/* XXX TODO */
buf_putbyte(ses.writepayload, 0); /* Don't want replies */
@@ -361,6 +359,12 @@ static int cli_initchansess(struct Channel *channel) {
cli_init_stdpipe_sess(channel);
#ifdef ENABLE_CLI_AGENTFWD
if (cli_opts.agent_fwd) {
cli_setup_agent(channel);
}
#endif
if (cli_opts.wantpty) {
send_chansess_pty_req(channel);
}
@@ -369,27 +373,29 @@ static int cli_initchansess(struct Channel *channel) {
if (cli_opts.wantpty) {
cli_tty_setup();
}
channel->read_mangler = cli_escape_handler;
cli_ses.last_char = '\r';
}
return 0; /* Success */
}
#ifdef ENABLE_CLI_NETCAT
static const struct ChanType cli_chan_netcat = {
0, /* sepfds */
"direct-tcpip",
cli_init_stdpipe_sess, /* inithandler */
NULL,
NULL,
cli_closechansess
};
void cli_send_netcat_request() {
const unsigned char* source_host = "127.0.0.1";
const int source_port = 22;
const struct ChanType cli_chan_netcat = {
0, /* sepfds */
"direct-tcpip",
cli_init_stdpipe_sess, /* inithandler */
NULL,
NULL,
cli_closechansess
};
cli_opts.wantpty = 0;
if (send_msg_channel_open_init(STDIN_FILENO, &cli_chan_netcat)
@@ -425,15 +431,58 @@ void cli_send_chansess_request() {
}
// returns 1 if the character should be consumed, 0 to pass through
static int
do_escape(unsigned char c) {
switch (c) {
case '.':
dropbear_exit("Terminated");
return 1;
break;
case 0x1a:
// ctrl-z
cli_tty_cleanup();
kill(getpid(), SIGTSTP);
// after continuation
cli_tty_setup();
cli_ses.winchange = 1;
return 1;
break;
}
return 0;
}
#if 0
while (cli_opts.localfwds != NULL) {
ret = cli_localtcp(cli_opts.localfwds->listenport,
cli_opts.localfwds->connectaddr,
cli_opts.localfwds->connectport);
if (ret == DROPBEAR_FAILURE) {
dropbear_log(LOG_WARNING, "Failed local port forward %d:%s:%d",
cli_opts.localfwds->listenport,
cli_opts.localfwds->connectaddr,
cli_opts.localfwds->connectport);
#endif
static
void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len) {
char c;
int skip_char = 0;
// only handle escape characters if they are read one at a time. simplifies
// the code and avoids nasty people putting ~. at the start of a line to paste
if (*len != 1) {
cli_ses.last_char = 0x0;
return;
}
c = buf[0];
if (cli_ses.last_char == DROPBEAR_ESCAPE_CHAR) {
skip_char = do_escape(c);
cli_ses.last_char = 0x0;
} else {
if (c == DROPBEAR_ESCAPE_CHAR) {
if (cli_ses.last_char == '\r') {
cli_ses.last_char = DROPBEAR_ESCAPE_CHAR;
skip_char = 1;
} else {
cli_ses.last_char = 0x0;
}
} else {
cli_ses.last_char = c;
}
}
if (skip_char) {
*len = 0;
}
}

View File

@@ -42,18 +42,27 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen);
#define MAX_KNOWNHOSTS_LINE 4500
void send_msg_kexdh_init() {
TRACE(("send_msg_kexdh_init()"))
if ((cli_ses.dh_e && cli_ses.dh_x
&& cli_ses.dh_val_algo == ses.newkeys->algo_kex)) {
TRACE(("reusing existing dh_e from first_kex_packet_follows"))
} else {
if (!cli_ses.dh_e || !cli_ses.dh_e) {
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);
}
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);
gen_kexdh_vals(cli_ses.dh_e, cli_ses.dh_x);
cli_ses.dh_val_algo = ses.newkeys->algo_kex;
}
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
buf_putmpint(ses.writepayload, cli_ses.dh_e);
encrypt_packet();
ses.requirenext = SSH_MSG_KEXDH_REPLY;
ses.requirenext[0] = SSH_MSG_KEXDH_REPLY;
ses.requirenext[1] = SSH_MSG_KEXINIT;
}
/* Handle a diffie-hellman key exchange reply. */
@@ -98,6 +107,7 @@ void recv_msg_kexdh_reply() {
mp_clear_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
m_free(cli_ses.dh_e);
m_free(cli_ses.dh_x);
cli_ses.dh_val_algo = DROPBEAR_KEX_NONE;
if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE)
!= DROPBEAR_SUCCESS) {
@@ -108,7 +118,8 @@ void recv_msg_kexdh_reply() {
hostkey = NULL;
send_msg_newkeys();
ses.requirenext = SSH_MSG_NEWKEYS;
ses.requirenext[0] = SSH_MSG_NEWKEYS;
ses.requirenext[1] = 0;
TRACE(("leave recv_msg_kexdh_init"))
}
@@ -217,6 +228,11 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
buffer * line = NULL;
int ret;
if (cli_opts.no_hostkey_check) {
fprintf(stderr, "Caution, skipping hostkey check for %s\n", cli_opts.remotehost);
return;
}
hostsfile = open_known_hosts_file(&readonly);
if (!hostsfile) {
ask_to_confirm(keyblob, keybloblen);
@@ -246,7 +262,6 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
/* Compare hostnames */
if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen),
hostlen) != 0) {
TRACE(("hosts don't match"))
continue;
}
@@ -304,12 +319,11 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */
buf_setpos(line, 0);
buf_setlen(line, 0);
buf_putbytes(line, ses.remotehost, hostlen);
buf_putbytes(line, cli_opts.remotehost, hostlen);
buf_putbyte(line, ' ');
buf_putbytes(line, algoname, algolen);
buf_putbyte(line, ' ');
len = line->size - line->pos;
TRACE(("keybloblen %d, len %d", keybloblen, len))
/* The only failure with base64 is buffer_overflow, but buf_getwriteptr
* will die horribly in the case anyway */
base64_encode(keyblob, keybloblen, buf_getwriteptr(line, len), &len);
@@ -327,4 +341,5 @@ out:
if (line != NULL) {
buf_free(line);
}
m_free(fingerprint);
}

View File

@@ -29,10 +29,12 @@
#include "runopts.h"
#include "session.h"
static void cli_dropbear_exit(int exitcode, const char* format, va_list param);
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
static void cli_dropbear_log(int priority, const char* format, va_list param);
#ifdef ENABLE_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out);
#endif
#if defined(DBMULTI_dbclient) || !defined(DROPBEAR_MULTI)
#if defined(DBMULTI_dbclient) && defined(DROPBEAR_MULTI)
@@ -43,8 +45,6 @@ int main(int argc, char ** argv) {
int sock_in, sock_out;
char* error = NULL;
char* hostandport;
int len;
_dropbear_exit = cli_dropbear_exit;
_dropbear_log = cli_dropbear_log;
@@ -63,6 +63,7 @@ int main(int argc, char ** argv) {
#ifdef ENABLE_CLI_PROXYCMD
if (cli_opts.proxycmd) {
cli_proxy_cmd(&sock_in, &sock_out);
m_free(cli_opts.proxycmd);
} else
#endif
{
@@ -75,14 +76,7 @@ int main(int argc, char ** argv) {
dropbear_exit("%s", error);
}
/* Set up the host:port log */
len = strlen(cli_opts.remotehost);
len += 10; /* 16 bit port and leeway*/
hostandport = (char*)m_malloc(len);
snprintf(hostandport, len, "%s:%s",
cli_opts.remotehost, cli_opts.remoteport);
cli_session(sock_in, sock_out, hostandport);
cli_session(sock_in, sock_out);
/* not reached */
return -1;
@@ -94,18 +88,17 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
char fmtbuf[300];
if (!sessinitdone) {
snprintf(fmtbuf, sizeof(fmtbuf), "exited: %s",
snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s",
format);
} else {
snprintf(fmtbuf, sizeof(fmtbuf),
"connection to %s@%s:%s exited: %s",
"Connection to %s@%s:%s exited: %s",
cli_opts.username, cli_opts.remotehost,
cli_opts.remoteport, format);
}
/* Do the cleanup first, since then the terminal will be reset */
cli_session_cleanup();
common_session_cleanup();
session_cleanup();
_dropbear_log(LOG_INFO, fmtbuf, param);
@@ -132,6 +125,7 @@ static void exec_proxy_cmd(void *user_data_cmd) {
dropbear_exit("Failed to run '%s'\n", cmd);
}
#ifdef ENABLE_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out) {
int ret;
@@ -144,3 +138,4 @@ static void cli_proxy_cmd(int *sock_in, int *sock_out) {
*sock_in = *sock_out = -1;
}
}
#endif // ENABLE_CLI_PROXYCMD

View File

@@ -29,6 +29,7 @@
#include "dbutil.h"
#include "algo.h"
#include "tcpfwd.h"
#include "list.h"
cli_runopts cli_opts; /* GLOBAL */
@@ -40,7 +41,7 @@ static void fill_own_user();
static void loadidentityfile(const char* filename);
#endif
#ifdef ENABLE_CLI_ANYTCPFWD
static void addforward(const char* str, struct TCPFwdList** fwdlist);
static void addforward(const char* str, m_list *fwdlist);
#endif
#ifdef ENABLE_CLI_NETCAT
static void add_netcat(const char *str);
@@ -48,13 +49,12 @@ static void add_netcat(const char *str);
static void printhelp() {
fprintf(stderr, "Dropbear client v%s\n"
fprintf(stderr, "Dropbear SSH client v%s https://matt.ucc.asn.au/dropbear/dropbear.html\n"
#ifdef ENABLE_CLI_MULTIHOP
"Usage: %s [options] [user@]host[/port][,[user@]host/port],...] [command]\n"
#else
"Usage: %s [options] [user@]host[/port] [command]\n"
#endif
"Options are:\n"
"-p <remoteport>\n"
"-l <username>\n"
"-t Allocate a pty\n"
@@ -62,16 +62,20 @@ static void printhelp() {
"-N Don't run a remote command\n"
"-f Run in background after auth\n"
"-y Always accept remote host key if unknown\n"
"-s Request a subsystem (use for sftp)\n"
"-y -y Don't perform any remote host key checking (caution)\n"
"-s Request a subsystem (use by external sftp)\n"
#ifdef ENABLE_CLI_PUBKEY_AUTH
"-i <identityfile> (multiple allowed)\n"
#endif
#ifdef ENABLE_CLI_AGENTFWD
"-A Enable agent auth forwarding\n"
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
"-L <listenport:remotehost:remoteport> Local port forwarding\n"
"-L <[listenaddress:]listenport:remotehost:remoteport> Local port forwarding\n"
"-g Allow remote hosts to connect to forwarded ports\n"
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
"-R <listenport:remotehost:remoteport> Remote port forwarding\n"
"-R <[listenaddress:]listenport:remotehost:remoteport> Remote port forwarding\n"
#endif
"-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
"-K <keepalive> (0 is never, default %d)\n"
@@ -82,6 +86,10 @@ static void printhelp() {
#ifdef ENABLE_CLI_PROXYCMD
"-J <proxy_program> Use program pipe rather than TCP connection\n"
#endif
#ifdef ENABLE_USER_ALGO_LIST
"-c <cipher list> Specify preferred ciphers ('-c help' to list options)\n"
"-m <MAC list> Specify preferred MACs for packet verification (or '-m help')\n"
#endif
#ifdef DEBUG_TRACE
"-v verbose (compiled with DEBUG_TRACE)\n"
#endif
@@ -91,7 +99,6 @@ static void printhelp() {
}
void cli_getopts(int argc, char ** argv) {
unsigned int i, j;
char ** next = 0;
unsigned int cmdlen;
@@ -112,6 +119,7 @@ void cli_getopts(int argc, char ** argv) {
char* recv_window_arg = NULL;
char* keepalive_arg = NULL;
char* idle_timeout_arg = NULL;
char *host_arg = NULL;
/* see printhelp() for options */
cli_opts.progname = argv[0];
@@ -123,19 +131,32 @@ void cli_getopts(int argc, char ** argv) {
cli_opts.backgrounded = 0;
cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */
cli_opts.always_accept_key = 0;
cli_opts.no_hostkey_check = 0;
cli_opts.is_subsystem = 0;
#ifdef ENABLE_CLI_PUBKEY_AUTH
cli_opts.privkeys = NULL;
cli_opts.privkeys = list_new();
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
cli_opts.localfwds = NULL;
cli_opts.localfwds = list_new();
opts.listen_fwd_all = 0;
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
cli_opts.remotefwds = NULL;
cli_opts.remotefwds = list_new();
#endif
#ifdef ENABLE_CLI_AGENTFWD
cli_opts.agent_fwd = 0;
cli_opts.agent_fd = -1;
cli_opts.agent_keys_loaded = 0;
#endif
#ifdef ENABLE_CLI_PROXYCMD
cli_opts.proxycmd = NULL;
#endif
#ifndef DISABLE_ZLIB
opts.enable_compress = 1;
#endif
#ifdef ENABLE_USER_ALGO_LIST
opts.cipher_list = NULL;
opts.mac_list = NULL;
#endif
/* not yet
opts.ipv4 = 1;
@@ -158,7 +179,7 @@ void cli_getopts(int argc, char ** argv) {
#ifdef ENABLE_CLI_REMOTETCPFWD
if (nextisremote) {
TRACE(("nextisremote true"))
addforward(argv[i], &cli_opts.remotefwds);
addforward(argv[i], cli_opts.remotefwds);
nextisremote = 0;
continue;
}
@@ -166,7 +187,7 @@ void cli_getopts(int argc, char ** argv) {
#ifdef ENABLE_CLI_LOCALTCPFWD
if (nextislocal) {
TRACE(("nextislocal true"))
addforward(argv[i], &cli_opts.localfwds);
addforward(argv[i], cli_opts.localfwds);
nextislocal = 0;
continue;
}
@@ -194,6 +215,10 @@ void cli_getopts(int argc, char ** argv) {
switch (argv[i][1]) {
case 'y': /* always accept the remote hostkey */
if (cli_opts.always_accept_key) {
// twice means no checking at all
cli_opts.no_hostkey_check = 1;
}
cli_opts.always_accept_key = 1;
break;
case 'p': /* remoteport */
@@ -266,6 +291,19 @@ void cli_getopts(int argc, char ** argv) {
case 'I':
next = &idle_timeout_arg;
break;
#ifdef ENABLE_CLI_AGENTFWD
case 'A':
cli_opts.agent_fwd = 1;
break;
#endif
#ifdef ENABLE_USER_ALGO_LIST
case 'c':
next = &opts.cipher_list;
break;
case 'm':
next = &opts.mac_list;
break;
#endif
#ifdef DEBUG_TRACE
case 'v':
debug_trace = 1;
@@ -273,8 +311,10 @@ void cli_getopts(int argc, char ** argv) {
#endif
case 'F':
case 'e':
#ifndef ENABLE_USER_ALGO_LIST
case 'c':
case 'm':
#endif
case 'D':
#ifndef ENABLE_CLI_REMOTETCPFWD
case 'R':
@@ -304,12 +344,8 @@ void cli_getopts(int argc, char ** argv) {
/* Either the hostname or commands */
if (cli_opts.remotehost == NULL) {
#ifdef ENABLE_CLI_MULTIHOP
parse_multihop_hostname(argv[i], argv[0]);
#else
parse_hostname(argv[i]);
#endif
if (host_arg == NULL) {
host_arg = argv[i];
} else {
/* this is part of the commands to send - after this we
@@ -338,7 +374,11 @@ void cli_getopts(int argc, char ** argv) {
/* And now a few sanity checks and setup */
if (cli_opts.remotehost == NULL) {
#ifdef ENABLE_USER_ALGO_LIST
parse_ciphers_macs();
#endif
if (host_arg == NULL) {
printhelp();
exit(EXIT_FAILURE);
}
@@ -359,7 +399,7 @@ void cli_getopts(int argc, char ** argv) {
if (cli_opts.backgrounded && cli_opts.cmd == NULL
&& cli_opts.no_cmd == 0) {
dropbear_exit("command required for -f");
dropbear_exit("Command required for -f");
}
if (recv_window_arg) {
@@ -369,15 +409,19 @@ void cli_getopts(int argc, char ** argv) {
}
}
if (keepalive_arg) {
if (m_str_to_uint(keepalive_arg, &opts.keepalive_secs) == DROPBEAR_FAILURE) {
unsigned int val;
if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
dropbear_exit("Bad keepalive '%s'", keepalive_arg);
}
opts.keepalive_secs = val;
}
if (idle_timeout_arg) {
if (m_str_to_uint(idle_timeout_arg, &opts.idle_timeout_secs) == DROPBEAR_FAILURE) {
unsigned int val;
if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
}
opts.idle_timeout_secs = val;
}
#ifdef ENABLE_CLI_NETCAT
@@ -385,36 +429,90 @@ void cli_getopts(int argc, char ** argv) {
dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd);
}
#endif
/* The hostname gets set up last, since
* in multi-hop mode it will require knowledge
* of other flags such as -i */
#ifdef ENABLE_CLI_MULTIHOP
parse_multihop_hostname(host_arg, argv[0]);
#else
parse_hostname(host_arg);
#endif
}
#ifdef ENABLE_CLI_PUBKEY_AUTH
static void loadidentityfile(const char* filename) {
struct SignKeyList * nextkey;
sign_key *key;
int keytype;
key = new_sign_key();
keytype = DROPBEAR_SIGNKEY_ANY;
if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
sign_key_free(key);
} else {
nextkey = (struct SignKeyList*)m_malloc(sizeof(struct SignKeyList));
nextkey->key = key;
nextkey->next = cli_opts.privkeys;
nextkey->type = keytype;
cli_opts.privkeys = nextkey;
key->type = keytype;
key->source = SIGNKEY_SOURCE_RAW_FILE;
key->filename = m_strdup(filename);
list_append(cli_opts.privkeys, key);
}
}
#endif
#ifdef ENABLE_CLI_MULTIHOP
static char*
multihop_passthrough_args() {
char *ret;
int total;
unsigned int len = 0;
m_list_elem *iter;
/* Fill out -i, -y, -W options that make sense for all
* the intermediate processes */
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
{
sign_key * key = (sign_key*)iter->item;
len += 3 + strlen(key->filename);
}
len += 30; // space for -W <size>, terminator.
ret = m_malloc(len);
total = 0;
if (cli_opts.no_hostkey_check)
{
int written = snprintf(ret+total, len-total, "-y -y ");
total += written;
}
else if (cli_opts.always_accept_key)
{
int written = snprintf(ret+total, len-total, "-y ");
total += written;
}
if (opts.recv_window != DEFAULT_RECV_WINDOW)
{
int written = snprintf(ret+total, len-total, "-W %d ", opts.recv_window);
total += written;
}
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
{
sign_key * key = (sign_key*)iter->item;
const size_t size = len - total;
int written = snprintf(ret+total, size, "-i %s ", key->filename);
dropbear_assert((unsigned int)written < size);
total += written;
}
/* if args were passed, total will be not zero, and it will have a space at the end, so remove that */
if (total > 0)
{
total--;
}
return ret;
}
/* Sets up 'onion-forwarding' connections. This will spawn
* a separate dbclient process for each hop.
* As an example, if the cmdline is
@@ -429,7 +527,8 @@ static void loadidentityfile(const char* filename) {
*/
static void parse_multihop_hostname(const char* orighostarg, const char* argv0) {
char *userhostarg = NULL;
char *last_hop = NULL;;
char *hostbuf = NULL;
char *last_hop = NULL;
char *remainder = NULL;
/* both scp and rsync parse a user@host argument
@@ -441,11 +540,12 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
&& strchr(cli_opts.username, ',')
&& strchr(cli_opts.username, '@')) {
unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2;
userhostarg = m_malloc(len);
snprintf(userhostarg, len, "%s@%s", cli_opts.username, orighostarg);
hostbuf = m_malloc(len);
snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg);
} else {
userhostarg = m_strdup(orighostarg);
hostbuf = m_strdup(orighostarg);
}
userhostarg = hostbuf;
last_hop = strrchr(userhostarg, ',');
if (last_hop) {
@@ -463,19 +563,28 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
if (last_hop) {
/* Set up the proxycmd */
unsigned int cmd_len = 0;
char *passthrough_args = multihop_passthrough_args();
if (cli_opts.proxycmd) {
dropbear_exit("-J can't be used with multihop mode");
}
if (cli_opts.remoteport == NULL) {
cli_opts.remoteport = "22";
}
cmd_len = strlen(remainder)
cmd_len = strlen(argv0) + strlen(remainder)
+ strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport)
+ strlen(argv0) + 30;
+ strlen(passthrough_args)
+ 30;
cli_opts.proxycmd = m_malloc(cmd_len);
snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s",
argv0, cli_opts.remotehost, cli_opts.remoteport, remainder);
snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s",
argv0, cli_opts.remotehost, cli_opts.remoteport,
passthrough_args, remainder);
#ifndef DISABLE_ZLIB
/* The stream will be incompressible since it's encrypted. */
opts.enable_compress = 0;
#endif
m_free(passthrough_args);
}
m_free(hostbuf);
}
#endif /* !ENABLE_CLI_MULTIHOP */
@@ -501,7 +610,11 @@ static void parse_hostname(const char* orighostarg) {
cli_opts.username = m_strdup(cli_opts.own_user);
}
port = strchr(cli_opts.remotehost, '/');
port = strchr(cli_opts.remotehost, '%');
if (!port) {
// legacy separator
port = strchr(cli_opts.remotehost, '/');
}
if (port) {
*port = '\0';
cli_opts.remoteport = port+1;
@@ -564,14 +677,16 @@ static void fill_own_user() {
}
#ifdef ENABLE_CLI_ANYTCPFWD
/* Turn a "listenport:remoteaddr:remoteport" string into into a forwarding
/* Turn a "[listenaddr:]listenport:remoteaddr:remoteport" string into into a forwarding
* set, and add it to the forwarding list */
static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
static void addforward(const char* origstr, m_list *fwdlist) {
char *part1 = NULL, *part2 = NULL, *part3 = NULL, *part4 = NULL;
char * listenaddr = NULL;
char * listenport = NULL;
char * connectport = NULL;
char * connectaddr = NULL;
struct TCPFwdList* newfwd = NULL;
char * connectport = NULL;
struct TCPFwdEntry* newfwd = NULL;
char * str = NULL;
TRACE(("enter addforward"))
@@ -580,25 +695,43 @@ static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
is never free()d. */
str = m_strdup(origstr);
listenport = str;
part1 = str;
connectaddr = strchr(str, ':');
if (connectaddr == NULL) {
TRACE(("connectaddr == NULL"))
part2 = strchr(str, ':');
if (part2 == NULL) {
TRACE(("part2 == NULL"))
goto fail;
}
*connectaddr = '\0';
connectaddr++;
*part2 = '\0';
part2++;
connectport = strchr(connectaddr, ':');
if (connectport == NULL) {
TRACE(("connectport == NULL"))
part3 = strchr(part2, ':');
if (part3 == NULL) {
TRACE(("part3 == NULL"))
goto fail;
}
*connectport = '\0';
connectport++;
*part3 = '\0';
part3++;
newfwd = (struct TCPFwdList*)m_malloc(sizeof(struct TCPFwdList));
part4 = strchr(part3, ':');
if (part4) {
*part4 = '\0';
part4++;
}
if (part4) {
listenaddr = part1;
listenport = part2;
connectaddr = part3;
connectport = part4;
} else {
listenaddr = NULL;
listenport = part1;
connectaddr = part2;
connectport = part3;
}
newfwd = m_malloc(sizeof(struct TCPFwdEntry));
/* Now we check the ports - note that the port ints are unsigned,
* the check later only checks for >= MAX_PORT */
@@ -612,6 +745,7 @@ static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
goto fail;
}
newfwd->listenaddr = listenaddr;
newfwd->connectaddr = connectaddr;
if (newfwd->listenport > 65535) {
@@ -625,8 +759,7 @@ static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
}
newfwd->have_reply = 0;
newfwd->next = *fwdlist;
*fwdlist = newfwd;
list_append(fwdlist, newfwd);
TRACE(("leave addforward: done"))
return;

View File

@@ -1,85 +0,0 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "service.h"
#include "dbutil.h"
#include "packet.h"
#include "buffer.h"
#include "session.h"
#include "ssh.h"
void send_msg_service_request(char* servicename) {
TRACE(("enter send_msg_service_request: servicename='%s'", servicename))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST);
buf_putstring(ses.writepayload, servicename, strlen(servicename));
encrypt_packet();
TRACE(("leave send_msg_service_request"))
}
/* This just sets up the state variables right for the main client session loop
* to deal with */
void recv_msg_service_accept() {
unsigned char* servicename;
unsigned int len;
TRACE(("enter recv_msg_service_accept"))
servicename = buf_getstring(ses.payload, &len);
/* ssh-userauth */
if (cli_ses.state == SERVICE_AUTH_REQ_SENT
&& len == SSH_SERVICE_USERAUTH_LEN
&& strncmp(SSH_SERVICE_USERAUTH, servicename, len) == 0) {
cli_ses.state = SERVICE_AUTH_ACCEPT_RCVD;
m_free(servicename);
TRACE(("leave recv_msg_service_accept: done ssh-userauth"))
return;
}
/* ssh-connection */
if (cli_ses.state == SERVICE_CONN_REQ_SENT
&& len == SSH_SERVICE_CONNECTION_LEN
&& strncmp(SSH_SERVICE_CONNECTION, servicename, len) == 0) {
if (ses.authstate.authdone != 1) {
dropbear_exit("request for connection before auth");
}
cli_ses.state = SERVICE_CONN_ACCEPT_RCVD;
m_free(servicename);
TRACE(("leave recv_msg_service_accept: done ssh-connection"))
return;
}
dropbear_exit("unrecognised service accept");
}

View File

@@ -35,11 +35,14 @@
#include "service.h"
#include "runopts.h"
#include "chansession.h"
#include "agentfwd.h"
static void cli_remoteclosed();
static void cli_sessionloop();
static void cli_session_init();
static void cli_finished();
static void recv_msg_service_accept(void);
static void cli_session_cleanup(void);
struct clientsession cli_ses; /* GLOBAL */
@@ -74,17 +77,20 @@ static const packettype cli_packettypes[] = {
static const struct ChanType *cli_chantypes[] = {
#ifdef ENABLE_CLI_REMOTETCPFWD
&cli_chan_tcpremote,
#endif
#ifdef ENABLE_CLI_AGENTFWD
&cli_chan_agent,
#endif
NULL /* Null termination */
};
void cli_session(int sock_in, int sock_out, char* remotehost) {
void cli_session(int sock_in, int sock_out) {
seedrandom();
crypto_init();
common_session_init(sock_in, sock_out, remotehost);
common_session_init(sock_in, sock_out);
chaninitialise(cli_chantypes);
@@ -95,7 +101,7 @@ void cli_session(int sock_in, int sock_out, char* remotehost) {
sessinitdone = 1;
/* Exchange identification */
session_identification();
send_session_identification();
send_msg_kexinit();
@@ -105,6 +111,12 @@ void cli_session(int sock_in, int sock_out, char* remotehost) {
}
#ifdef USE_KEX_FIRST_FOLLOWS
static void cli_send_kex_first_guess() {
send_msg_kexdh_init();
}
#endif
static void cli_session_init() {
cli_ses.state = STATE_NOTHING;
@@ -129,39 +141,70 @@ static void cli_session_init() {
cli_ses.lastprivkey = NULL;
cli_ses.lastauthtype = 0;
#ifdef DROPBEAR_NONE_CIPHER
cli_ses.cipher_none_after_auth = get_algo_usable(sshciphers, "none");
set_algo_usable(sshciphers, "none", 0);
#else
cli_ses.cipher_none_after_auth = 0;
#endif
/* For printing "remote host closed" for the user */
ses.remoteclosed = cli_remoteclosed;
ses.buf_match_algo = cli_buf_match_algo;
ses.extra_session_cleanup = cli_session_cleanup;
/* packet handlers */
ses.packettypes = cli_packettypes;
ses.isserver = 0;
#ifdef USE_KEX_FIRST_FOLLOWS
ses.send_kex_first_guess = cli_send_kex_first_guess;
#endif
}
static void send_msg_service_request(char* servicename) {
TRACE(("enter send_msg_service_request: servicename='%s'", servicename))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST);
buf_putstring(ses.writepayload, servicename, strlen(servicename));
encrypt_packet();
TRACE(("leave send_msg_service_request"))
}
static void recv_msg_service_accept(void) {
// do nothing, if it failed then the server MUST have disconnected
}
/* This function drives the progress of the session - it initiates KEX,
* service, userauth and channel requests */
static void cli_sessionloop() {
TRACE(("enter cli_sessionloop"))
TRACE2(("enter cli_sessionloop"))
if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) {
cli_ses.kex_state = KEXINIT_RCVD;
if (ses.lastpacket == 0) {
TRACE2(("exit cli_sessionloop: no real packets yet"))
return;
}
if (cli_ses.kex_state == KEXINIT_RCVD) {
if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) {
/* We initiate the KEXDH. If DH wasn't the correct type, the KEXINIT
* negotiation would have failed. */
send_msg_kexdh_init();
cli_ses.kex_state = KEXDH_INIT_SENT;
if (!ses.kexstate.our_first_follows_matches) {
send_msg_kexdh_init();
}
cli_ses.kex_state = KEXDH_INIT_SENT;
TRACE(("leave cli_sessionloop: done with KEXINIT_RCVD"))
return;
}
/* A KEX has finished, so we should go back to our KEX_NOTHING state */
if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.recvkexinit == 0
&& ses.kexstate.sentkexinit == 0) {
if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.sentnewkeys) {
cli_ses.kex_state = KEX_NOTHING;
}
@@ -171,10 +214,10 @@ static void cli_sessionloop() {
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"))
/* We might reach here if we have partial packet reads or have
* received SSG_MSG_IGNORE etc. Just skip it */
TRACE2(("donefirstkex false\n"))
return;
}
@@ -184,32 +227,36 @@ static void cli_sessionloop() {
/* We've got the transport layer sorted, we now need to request
* userauth */
send_msg_service_request(SSH_SERVICE_USERAUTH);
cli_ses.state = SERVICE_AUTH_REQ_SENT;
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"))
return;
case USERAUTH_FAIL_RCVD:
cli_auth_try();
if (cli_auth_try() == DROPBEAR_FAILURE) {
dropbear_exit("No auth methods could be used.");
}
cli_ses.state = USERAUTH_REQ_SENT;
TRACE(("leave cli_sessionloop: cli_auth_try"))
return;
case USERAUTH_SUCCESS_RCVD:
#ifdef DROPBEAR_NONE_CIPHER
if (cli_ses.cipher_none_after_auth)
{
set_algo_usable(sshciphers, "none", 1);
send_msg_kexinit();
}
#endif
if (cli_opts.backgrounded) {
int devnull;
/* keeping stdin open steals input from the terminal and
is confusing, though stdout/stderr could be useful. */
devnull = open(_PATH_DEVNULL, O_RDONLY);
if (devnull < 0) {
dropbear_exit("opening /dev/null: %d %s",
dropbear_exit("Opening /dev/null: %d %s",
errno, strerror(errno));
}
dup2(devnull, STDIN_FILENO);
@@ -219,6 +266,15 @@ static void cli_sessionloop() {
}
}
#ifdef ENABLE_CLI_NETCAT
if (cli_opts.netcat_host) {
cli_send_netcat_request();
} else
#endif
if (!cli_opts.no_cmd) {
cli_send_chansess_request();
}
#ifdef ENABLE_CLI_LOCALTCPFWD
setup_localtcp();
#endif
@@ -226,14 +282,6 @@ static void cli_sessionloop() {
setup_remotetcp();
#endif
#ifdef ENABLE_CLI_NETCAT
if (cli_opts.netcat_host) {
cli_send_netcat_request();
} else
#endif
if (!cli_opts.no_cmd) {
cli_send_chansess_request();
}
TRACE(("leave cli_sessionloop: running"))
cli_ses.state = SESSION_RUNNING;
return;
@@ -255,11 +303,11 @@ static void cli_sessionloop() {
break;
}
TRACE(("leave cli_sessionloop: fell out"))
TRACE2(("leave cli_sessionloop: fell out"))
}
void cli_session_cleanup() {
static void cli_session_cleanup(void) {
if (!sessinitdone) {
return;
@@ -277,8 +325,7 @@ void cli_session_cleanup() {
static void cli_finished() {
cli_session_cleanup();
common_session_cleanup();
session_cleanup();
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
cli_opts.remotehost, cli_opts.remoteport);
exit(cli_ses.retval);
@@ -294,7 +341,7 @@ static void cli_remoteclosed() {
m_close(ses.sock_out);
ses.sock_in = -1;
ses.sock_out = -1;
dropbear_exit("remote closed the connection");
dropbear_exit("Remote closed the connection");
}
/* Operates in-place turning dirty (untrusted potentially containing control

View File

@@ -45,7 +45,9 @@ const struct ChanType cli_chan_tcpremote = {
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
static int cli_localtcp(const char* listenaddr,
unsigned int listenport,
const char* remoteaddr,
unsigned int remoteport);
static const struct ChanType cli_chan_tcplocal = {
1, /* sepfds */
@@ -59,33 +61,33 @@ static const struct ChanType cli_chan_tcplocal = {
#ifdef ENABLE_CLI_LOCALTCPFWD
void setup_localtcp() {
m_list_elem *iter;
int ret;
TRACE(("enter setup_localtcp"))
if (cli_opts.localfwds == NULL) {
TRACE(("cli_opts.localfwds == NULL"))
}
while (cli_opts.localfwds != NULL) {
ret = cli_localtcp(cli_opts.localfwds->listenport,
cli_opts.localfwds->connectaddr,
cli_opts.localfwds->connectport);
for (iter = cli_opts.localfwds->first; iter; iter = iter->next) {
struct TCPFwdEntry * fwd = (struct TCPFwdEntry*)iter->item;
ret = cli_localtcp(
fwd->listenaddr,
fwd->listenport,
fwd->connectaddr,
fwd->connectport);
if (ret == DROPBEAR_FAILURE) {
dropbear_log(LOG_WARNING, "Failed local port forward %d:%s:%d",
cli_opts.localfwds->listenport,
cli_opts.localfwds->connectaddr,
cli_opts.localfwds->connectport);
}
cli_opts.localfwds = cli_opts.localfwds->next;
dropbear_log(LOG_WARNING, "Failed local port forward %s:%d:%s:%d",
fwd->listenaddr,
fwd->listenport,
fwd->connectaddr,
fwd->connectport);
}
}
TRACE(("leave setup_localtcp"))
}
static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
static int cli_localtcp(const char* listenaddr,
unsigned int listenport,
const char* remoteaddr,
unsigned int remoteport) {
struct TCPListener* tcpinfo = NULL;
@@ -99,10 +101,17 @@ static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
tcpinfo->sendaddr = m_strdup(remoteaddr);
tcpinfo->sendport = remoteport;
if (opts.listen_fwd_all) {
tcpinfo->listenaddr = m_strdup("");
} else {
tcpinfo->listenaddr = m_strdup("localhost");
if (listenaddr)
{
tcpinfo->listenaddr = m_strdup(listenaddr);
}
else
{
if (opts.listen_fwd_all) {
tcpinfo->listenaddr = m_strdup("");
} else {
tcpinfo->listenaddr = m_strdup("localhost");
}
}
tcpinfo->listenport = listenport;
@@ -120,22 +129,15 @@ static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
#endif /* ENABLE_CLI_LOCALTCPFWD */
#ifdef ENABLE_CLI_REMOTETCPFWD
static void send_msg_global_request_remotetcp(int port) {
static void send_msg_global_request_remotetcp(const char *addr, int port) {
char* listenspec = NULL;
TRACE(("enter send_msg_global_request_remotetcp"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
buf_putstring(ses.writepayload, "tcpip-forward", 13);
buf_putbyte(ses.writepayload, 1); /* want_reply */
if (opts.listen_fwd_all) {
listenspec = "";
} else {
listenspec = "localhost";
}
/* TODO: IPv6? */;
buf_putstring(ses.writepayload, listenspec, strlen(listenspec));
buf_putstring(ses.writepayload, addr, strlen(addr));
buf_putint(ses.writepayload, port);
encrypt_packet();
@@ -146,90 +148,97 @@ static void send_msg_global_request_remotetcp(int port) {
/* The only global success/failure messages are for remotetcp.
* Since there isn't any identifier in these messages, we have to rely on them
* being in the same order as we sent the requests. This is the ordering
* of the cli_opts.remotefwds list */
* of the cli_opts.remotefwds list.
* If the requested remote port is 0 the listen port will be
* dynamically allocated by the server and the port number will be returned
* to client and the port number reported to the user. */
void cli_recv_msg_request_success() {
/* Nothing in the packet. We just mark off that we have received the reply,
/* We just mark off that we have received the reply,
* so that we can report failure for later ones. */
struct TCPFwdList * iter = NULL;
iter = cli_opts.remotefwds;
while (iter != NULL) {
if (!iter->have_reply)
{
iter->have_reply = 1;
m_list_elem * iter = NULL;
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
if (!fwd->have_reply) {
fwd->have_reply = 1;
if (fwd->listenport == 0) {
/* The server should let us know which port was allocated if we requestd port 0 */
int allocport = buf_getint(ses.payload);
if (allocport > 0) {
dropbear_log(LOG_INFO, "Allocated port %d for remote forward to %s:%d",
allocport, fwd->connectaddr, fwd->connectport);
}
}
return;
}
iter = iter->next;
}
}
void cli_recv_msg_request_failure() {
struct TCPFwdList * iter = NULL;
iter = cli_opts.remotefwds;
while (iter != NULL) {
if (!iter->have_reply)
{
iter->have_reply = 1;
dropbear_log(LOG_WARNING, "Remote TCP forward request failed (port %d -> %s:%d)", iter->listenport, iter->connectaddr, iter->connectport);
m_list_elem *iter;
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
if (!fwd->have_reply) {
fwd->have_reply = 1;
dropbear_log(LOG_WARNING, "Remote TCP forward request failed (port %d -> %s:%d)", fwd->listenport, fwd->connectaddr, fwd->connectport);
return;
}
iter = iter->next;
}
}
void setup_remotetcp() {
struct TCPFwdList * iter = NULL;
m_list_elem *iter;
TRACE(("enter setup_remotetcp"))
if (cli_opts.remotefwds == NULL) {
TRACE(("cli_opts.remotefwds == NULL"))
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
if (!fwd->listenaddr)
{
// we store the addresses so that we can compare them
// when the server sends them back
if (opts.listen_fwd_all) {
fwd->listenaddr = m_strdup("");
} else {
fwd->listenaddr = m_strdup("localhost");
}
}
send_msg_global_request_remotetcp(fwd->listenaddr, fwd->listenport);
}
iter = cli_opts.remotefwds;
while (iter != NULL) {
send_msg_global_request_remotetcp(iter->listenport);
iter = iter->next;
}
TRACE(("leave setup_remotetcp"))
}
static int newtcpforwarded(struct Channel * channel) {
char *origaddr = NULL;
unsigned int origport;
struct TCPFwdList * iter = NULL;
m_list_elem * iter = NULL;
struct TCPFwdEntry *fwd;
char portstring[NI_MAXSERV];
int sock;
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
/* We don't care what address they connected to */
buf_eatstring(ses.payload);
origaddr = buf_getstring(ses.payload, NULL);
origport = buf_getint(ses.payload);
/* Find which port corresponds */
iter = cli_opts.remotefwds;
while (iter != NULL) {
if (origport == iter->listenport) {
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
fwd = (struct TCPFwdEntry*)iter->item;
if (origport == fwd->listenport
&& (strcmp(origaddr, fwd->listenaddr) == 0)) {
break;
}
iter = iter->next;
}
if (iter == NULL) {
/* We didn't request forwarding on that port */
dropbear_log(LOG_INFO, "Server send unrequested port, from port %d",
origport);
cleantext(origaddr);
dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"",
origaddr, origport);
goto out;
}
snprintf(portstring, sizeof(portstring), "%d", iter->connectport);
sock = connect_remote(iter->connectaddr, portstring, 1, NULL);
snprintf(portstring, sizeof(portstring), "%d", fwd->connectport);
sock = connect_remote(fwd->connectaddr, portstring, 1, NULL);
if (sock < 0) {
TRACE(("leave newtcpdirect: sock failed"))
err = SSH_OPEN_CONNECT_FAILED;
@@ -246,6 +255,7 @@ static int newtcpforwarded(struct Channel * channel) {
err = SSH_OPEN_IN_PROGRESS;
out:
m_free(origaddr);
TRACE(("leave newtcpdirect: err %d", err))
return err;
}

View File

@@ -24,6 +24,7 @@
* SOFTWARE. */
#include "algo.h"
#include "session.h"
#include "dbutil.h"
/* This file (algo.c) organises the ciphers which can be used, and is used to
@@ -31,7 +32,9 @@
static int void_cipher(const unsigned char* in, unsigned char* out,
unsigned long len, void *cipher_state) {
memcpy(out, in, len);
if (in != out) {
memmove(out, in, len);
}
return CRYPT_OK;
}
@@ -43,8 +46,8 @@ static int void_start(int cipher, const unsigned char *IV,
/* Mappings for ciphers, parameters are
{&cipher_desc, keysize, blocksize} */
/* NOTE: if keysize > 2*SHA1_HASH_SIZE, code such as hashkeys()
needs revisiting */
/* Remember to add new ciphers/hashes to regciphers/reghashes too */
#ifdef DROPBEAR_AES256
static const struct dropbear_cipher dropbear_aes256 =
@@ -104,6 +107,14 @@ static const struct dropbear_hash dropbear_sha1 =
static const struct dropbear_hash dropbear_sha1_96 =
{&sha1_desc, 20, 12};
#endif
#ifdef DROPBEAR_SHA2_256_HMAC
static const struct dropbear_hash dropbear_sha2_256 =
{&sha256_desc, 32, 32};
#endif
#ifdef DROPBEAR_SHA2_512_HMAC
static const struct dropbear_hash dropbear_sha2_512 =
{&sha512_desc, 64, 64};
#endif
#ifdef DROPBEAR_MD5_HMAC
static const struct dropbear_hash dropbear_md5 =
{&md5_desc, 16, 16};
@@ -149,11 +160,20 @@ algo_type sshciphers[] = {
#endif
#ifdef DROPBEAR_BLOWFISH
{"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_NONE_CIPHER
{"none", 0, (void*)&dropbear_nocipher, 1, &dropbear_mode_none},
#endif
{NULL, 0, NULL, 0, NULL}
};
algo_type sshhashes[] = {
#ifdef DROPBEAR_SHA2_256_HMAC
{"hmac-sha2-256", 0, &dropbear_sha2_256, 1, NULL},
#endif
#ifdef DROPBEAR_SHA2_512_HMAC
{"hmac-sha2-512", 0, &dropbear_sha2_512, 1, NULL},
#endif
#ifdef DROPBEAR_SHA1_96_HMAC
{"hmac-sha1-96", 0, &dropbear_sha1_96, 1, NULL},
#endif
@@ -161,16 +181,24 @@ algo_type sshhashes[] = {
{"hmac-sha1", 0, &dropbear_sha1, 1, NULL},
#endif
#ifdef DROPBEAR_MD5_HMAC
{"hmac-md5", 0, &dropbear_md5, 1, NULL},
{"hmac-md5", 0, (void*)&dropbear_md5, 1, NULL},
#endif
#ifdef DROPBEAR_NONE_INTEGRITY
{"none", 0, (void*)&dropbear_nohash, 1, NULL},
#endif
{NULL, 0, NULL, 0, NULL}
};
algo_type sshcompress[] = {
#ifndef DISABLE_ZLIB
algo_type ssh_compress[] = {
{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL},
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
{NULL, 0, NULL, 0, NULL}
};
#endif
algo_type ssh_nocompress[] = {
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
{NULL, 0, NULL, 0, NULL}
};
@@ -187,6 +215,10 @@ algo_type sshhostkey[] = {
algo_type sshkex[] = {
{"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL},
{"diffie-hellman-group14-sha1", DROPBEAR_KEX_DH_GROUP14, NULL, 1, NULL},
#ifdef USE_KEXGUESS2
{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
#endif
{NULL, 0, NULL, 0, NULL}
};
@@ -216,6 +248,12 @@ void crypto_init() {
&sha1_desc,
#ifdef DROPBEAR_MD5_HMAC
&md5_desc,
#endif
#ifdef DROPBEAR_SHA2_256_HMAC
&sha256_desc,
#endif
#ifdef DROPBEAR_SHA2_512_HMAC
&sha512_desc,
#endif
NULL
};
@@ -223,13 +261,13 @@ void crypto_init() {
for (i = 0; regciphers[i] != NULL; i++) {
if (register_cipher(regciphers[i]) == -1) {
dropbear_exit("error registering crypto");
dropbear_exit("Error registering crypto");
}
}
for (i = 0; reghashes[i] != NULL; i++) {
if (register_hash(reghashes[i]) == -1) {
dropbear_exit("error registering crypto");
dropbear_exit("Error registering crypto");
}
}
}
@@ -252,8 +290,6 @@ int have_algo(char* algo, size_t algolen, algo_type algos[]) {
return DROPBEAR_FAILURE;
}
/* Output a comma separated list of algorithms to a buffer */
void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
@@ -274,3 +310,232 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
buf_putstring(buf, algolist->data, algolist->len);
buf_free(algolist);
}
/* match the first algorithm in the comma-separated list in buf which is
* also in localalgos[], or return NULL on failure.
* (*goodguess) is set to 1 if the preferred client/server algos match,
* 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
* guessed correctly */
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
enum kexguess2_used *kexguess2, int *goodguess)
{
unsigned char * algolist = NULL;
const unsigned char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
unsigned int len;
unsigned int remotecount, localcount, clicount, servcount, i, j;
algo_type * ret = NULL;
const unsigned char **clinames, **servnames;
if (goodguess) {
*goodguess = 0;
}
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
algolist = buf_getstring(buf, &len);
TRACE(("buf_match_algo: %s", algolist))
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
goto out;
}
/* remotenames will contain a list of the strings parsed out */
/* We will have at least one string (even if it's just "") */
remotenames[0] = algolist;
remotecount = 1;
for (i = 0; i < len; i++) {
if (algolist[i] == '\0') {
/* someone is trying something strange */
goto out;
}
if (algolist[i] == ',') {
algolist[i] = '\0';
remotenames[remotecount] = &algolist[i+1];
remotecount++;
}
if (remotecount >= MAX_PROPOSED_ALGO) {
break;
}
}
if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) {
for (i = 0; i < remotecount; i++)
{
if (strcmp(remotenames[i], KEXGUESS2_ALGO_NAME) == 0) {
*kexguess2 = KEXGUESS2_YES;
break;
}
}
if (*kexguess2 == KEXGUESS2_LOOK) {
*kexguess2 = KEXGUESS2_NO;
}
}
for (i = 0; localalgos[i].name != NULL; i++) {
if (localalgos[i].usable) {
localnames[i] = localalgos[i].name;
} else {
localnames[i] = NULL;
}
}
localcount = i;
if (IS_DROPBEAR_SERVER) {
clinames = remotenames;
clicount = remotecount;
servnames = localnames;
servcount = localcount;
} else {
clinames = localnames;
clicount = localcount;
servnames = remotenames;
servcount = remotecount;
}
/* iterate and find the first match */
for (i = 0; i < clicount; i++) {
for (j = 0; j < servcount; j++) {
if (!(servnames[j] && clinames[i])) {
// unusable algos are NULL
continue;
}
if (strcmp(servnames[j], clinames[i]) == 0) {
/* set if it was a good guess */
if (goodguess && kexguess2) {
if (*kexguess2 == KEXGUESS2_YES) {
if (i == 0) {
*goodguess = 1;
}
} else {
if (i == 0 && j == 0) {
*goodguess = 1;
}
}
}
/* set the algo to return */
if (IS_DROPBEAR_SERVER) {
ret = &localalgos[j];
} else {
ret = &localalgos[i];
}
goto out;
}
}
}
out:
m_free(algolist);
return ret;
}
#ifdef DROPBEAR_NONE_CIPHER
void
set_algo_usable(algo_type algos[], const char * algo_name, int usable)
{
algo_type *a;
for (a = algos; a->name != NULL; a++)
{
if (strcmp(a->name, algo_name) == 0)
{
a->usable = usable;
return;
}
}
}
int
get_algo_usable(algo_type algos[], const char * algo_name)
{
algo_type *a;
for (a = algos; a->name != NULL; a++)
{
if (strcmp(a->name, algo_name) == 0)
{
return a->usable;
}
}
return 0;
}
#endif // DROPBEAR_NONE_CIPHER
#ifdef ENABLE_USER_ALGO_LIST
char *
algolist_string(algo_type algos[])
{
char *ret_list;
buffer *b = buf_new(200);
buf_put_algolist(b, algos);
buf_setpos(b, b->len);
buf_putbyte(b, '\0');
buf_setpos(b, 4);
ret_list = m_strdup(buf_getptr(b, b->len - b->pos));
buf_free(b);
return ret_list;
}
static algo_type*
check_algo(const char* algo_name, algo_type *algos)
{
algo_type *a;
for (a = algos; a->name != NULL; a++)
{
if (strcmp(a->name, algo_name) == 0)
{
return a;
}
}
return NULL;
}
static void
try_add_algo(const char *algo_name, algo_type *algos,
const char *algo_desc, algo_type * new_algos, int *num_ret)
{
algo_type *match_algo = check_algo(algo_name, algos);
if (!match_algo)
{
dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", algo_name, algo_desc);
return;
}
new_algos[*num_ret] = *match_algo;
(*num_ret)++;
}
/* Checks a user provided comma-separated algorithm list for available
* options. Any that are not acceptable are removed in-place. Returns the
* number of valid algorithms. */
int
check_user_algos(const char* user_algo_list, algo_type * algos,
const char *algo_desc)
{
algo_type new_algos[MAX_PROPOSED_ALGO];
/* this has two passes. first we sweep through the given list of
* algorithms and mark them as usable=2 in the algo_type[] array... */
int num_ret = 0;
char *work_list = m_strdup(user_algo_list);
char *last_name = work_list;
char *c;
for (c = work_list; *c; c++)
{
if (*c == ',')
{
*c = '\0';
try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret);
c++;
last_name = c;
}
}
try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret);
m_free(work_list);
new_algos[num_ret].name = NULL;
/* Copy one more as a blank delimiter */
memcpy(algos, new_algos, sizeof(*new_algos) * (num_ret+1));
return num_ret;
}
#endif // ENABLE_USER_ALGO_LIST

View File

@@ -48,7 +48,6 @@ static void send_msg_channel_data(struct Channel *channel, int isextended);
static void send_msg_channel_eof(struct Channel *channel);
static void send_msg_channel_close(struct Channel *channel);
static void remove_channel(struct Channel *channel);
static void delete_channel(struct Channel *channel);
static void check_in_progress(struct Channel *channel);
static unsigned int write_pending(struct Channel * channel);
static void check_close(struct Channel *channel);
@@ -93,11 +92,20 @@ void chancleanup() {
TRACE(("leave chancleanup"))
}
static void
chan_initwritebuf(struct Channel *channel)
{
dropbear_assert(channel->writebuf->size == 0 && channel->recvwindow == 0);
cbuf_free(channel->writebuf);
channel->writebuf = cbuf_new(opts.recv_window);
channel->recvwindow = opts.recv_window;
}
/* Create a new channel entry, send a reply confirm or failure */
/* If remotechan, transwindow and transmaxpacket are not know (for a new
* outgoing connection, with them to be filled on confirmation), they should
* all be set to 0 */
struct Channel* newchannel(unsigned int remotechan,
static struct Channel* newchannel(unsigned int remotechan,
const struct ChanType *type,
unsigned int transwindow, unsigned int transmaxpacket) {
@@ -138,6 +146,7 @@ struct Channel* newchannel(unsigned int remotechan,
newchan->index = i;
newchan->sent_close = newchan->recv_close = 0;
newchan->sent_eof = newchan->recv_eof = 0;
newchan->close_handler_done = 0;
newchan->remotechan = remotechan;
newchan->transwindow = transwindow;
@@ -151,9 +160,10 @@ struct Channel* newchannel(unsigned int remotechan,
newchan->await_open = 0;
newchan->flushing = 0;
newchan->writebuf = cbuf_new(opts.recv_window);
newchan->writebuf = cbuf_new(0); /* resized later by chan_initwritebuf */
newchan->recvwindow = 0;
newchan->extrabuf = NULL; /* The user code can set it up */
newchan->recvwindow = opts.recv_window;
newchan->recvdonelen = 0;
newchan->recvmaxpacket = RECV_MAX_PAYLOAD_LEN;
@@ -263,14 +273,16 @@ static unsigned int write_pending(struct Channel * channel) {
static void check_close(struct Channel *channel) {
int close_allowed = 0;
TRACE(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d",
TRACE2(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d",
channel->writefd, channel->readfd,
channel->errfd, channel->sent_close, channel->recv_close))
TRACE(("writebuf size %d extrabuf size %d",
cbuf_getused(channel->writebuf),
TRACE2(("writebuf size %d extrabuf size %d",
channel->writebuf ? cbuf_getused(channel->writebuf) : 0,
channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0))
if (!channel->flushing && channel->type->check_close
if (!channel->flushing
&& !channel->close_handler_done
&& channel->type->check_close
&& channel->type->check_close(channel))
{
channel->flushing = 1;
@@ -281,7 +293,8 @@ static void check_close(struct Channel *channel) {
channel, to ensure that the shell has exited (and the exit status
retrieved) before we close things up. */
if (!channel->type->check_close
|| channel->type->check_close(channel)) {
|| channel->close_handler_done
|| channel->type->check_close(channel)) {
close_allowed = 1;
}
@@ -348,9 +361,10 @@ static void check_in_progress(struct Channel *channel) {
send_msg_channel_open_failure(channel->remotechan,
SSH_OPEN_CONNECT_FAILED, "", "");
close(channel->writefd);
delete_channel(channel);
remove_channel(channel);
TRACE(("leave check_in_progress: fail"))
} else {
chan_initwritebuf(channel);
send_msg_channel_open_confirmation(channel, channel->recvwindow,
channel->recvmaxpacket);
channel->readfd = channel->writefd;
@@ -363,9 +377,11 @@ static void check_in_progress(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"))
if (channel->type->closehandler) {
TRACE(("enter send_msg_channel_close %p", channel))
if (channel->type->closehandler
&& !channel->close_handler_done) {
channel->type->closehandler(channel);
channel->close_handler_done = 1;
}
CHECKCLEARTOWRITE();
@@ -468,13 +484,13 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
}
/* Stuff from the wire */
if ((channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0 )
|| channel->initconn) {
if (channel->initconn
||(channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0)) {
FD_SET(channel->writefd, writefds);
}
if (ERRFD_IS_WRITE(channel) && channel->errfd >= 0
&& cbuf_getused(channel->extrabuf) > 0 ) {
&& cbuf_getused(channel->extrabuf) > 0) {
FD_SET(channel->errfd, writefds);
}
@@ -545,22 +561,18 @@ static void remove_channel(struct Channel * channel) {
TRACE(("CLOSE errfd %d", channel->errfd))
close(channel->errfd);
channel->typedata = NULL;
delete_channel(channel);
TRACE(("leave remove_channel"))
}
/* Remove a channel entry */
static void delete_channel(struct Channel *channel) {
if (!channel->close_handler_done
&& channel->type->closehandler) {
channel->type->closehandler(channel);
channel->close_handler_done = 1;
}
ses.channels[channel->index] = NULL;
m_free(channel);
ses.chancount--;
}
TRACE(("leave remove_channel"))
}
/* Handle channel specific requests, passing off to corresponding handlers
* such as chansession or x11fwd */
@@ -568,16 +580,17 @@ void recv_msg_channel_request() {
struct Channel *channel;
TRACE(("enter recv_msg_channel_request"))
channel = getchannel();
TRACE(("enter recv_msg_channel_request %p", channel))
if (channel->sent_close) {
TRACE(("leave recv_msg_channel_request: already closed channel"))
return;
}
if (channel->type->reqhandler) {
if (channel->type->reqhandler
&& !channel->close_handler_done) {
channel->type->reqhandler(channel);
} else {
send_msg_channel_failure(channel);
@@ -616,7 +629,7 @@ static void send_msg_channel_data(struct Channel *channel, int isextended) {
* exttype if is extended */
maxlen = MIN(maxlen,
ses.writepayload->size - 1 - 4 - 4 - (isextended ? 4 : 0));
TRACE(("maxlen %d", maxlen))
TRACE(("maxlen %zd", maxlen))
if (maxlen == 0) {
TRACE(("leave send_msg_channel_data: no window"))
return;
@@ -634,6 +647,7 @@ static void send_msg_channel_data(struct Channel *channel, int isextended) {
/* read the data */
len = read(fd, buf_getwriteptr(ses.writepayload, maxlen), maxlen);
if (len <= 0) {
if (len == 0 || errno != EINTR) {
/* This will also get hit in the case of EAGAIN. The only
@@ -641,11 +655,23 @@ static void send_msg_channel_data(struct Channel *channel, int isextended) {
in which case it can be treated the same as EOF */
close_chan_fd(channel, fd, SHUT_RD);
}
ses.writepayload->len = ses.writepayload->pos = 0;
buf_setpos(ses.writepayload, 0);
buf_setlen(ses.writepayload, 0);
TRACE(("leave send_msg_channel_data: len %d read err %d or EOF for fd %d",
len, errno, fd))
return;
}
if (channel->read_mangler) {
channel->read_mangler(channel, buf_getwriteptr(ses.writepayload, len), &len);
if (len == 0) {
buf_setpos(ses.writepayload, 0);
buf_setlen(ses.writepayload, 0);
return;
}
}
TRACE(("send_msg_channel_data: len %d fd %d", len, fd))
buf_incrwritepos(ses.writepayload, len);
/* ... real size here */
buf_setpos(ses.writepayload, size_pos);
@@ -688,10 +714,10 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
TRACE(("enter recv_msg_channel_data"))
if (channel->recv_eof) {
dropbear_exit("received data after eof");
dropbear_exit("Received data after eof");
}
if (fd < 0) {
if (fd < 0 || !cbuf) {
/* If we have encountered failed write, the far side might still
* be sending data without having yet received our close notification.
* We just drop the data. */
@@ -829,12 +855,14 @@ void recv_msg_channel_open() {
}
if (ret > 0) {
errtype = ret;
delete_channel(channel);
remove_channel(channel);
TRACE(("inithandler returned failure %d", ret))
goto failure;
}
}
chan_initwritebuf(channel);
/* success */
send_msg_channel_open_confirmation(channel, channel->recvwindow,
channel->recvmaxpacket);
@@ -973,6 +1001,10 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
return DROPBEAR_FAILURE;
}
/* Outbound opened channels don't make use of in-progress connections,
* we can set it up straight away */
chan_initwritebuf(chan);
/* set fd non-blocking */
setnonblocking(fd);
@@ -1006,7 +1038,7 @@ void recv_msg_channel_open_confirmation() {
channel = getchannel();
if (!channel->await_open) {
dropbear_exit("unexpected channel reply");
dropbear_exit("Unexpected channel reply");
}
channel->await_open = 0;
@@ -1038,7 +1070,7 @@ void recv_msg_channel_open_failure() {
channel = getchannel();
if (!channel->await_open) {
dropbear_exit("unexpected channel reply");
dropbear_exit("Unexpected channel reply");
}
channel->await_open = 0;

View File

@@ -33,9 +33,11 @@
#include "packet.h"
#include "bignum.h"
#include "random.h"
#include "runopts.h"
/* diffie-hellman-group1-sha1 value for p */
static const unsigned char dh_p_val[] = {
#define DH_P_1_LEN 128
static const unsigned char dh_p_1[DH_P_1_LEN] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
@@ -47,14 +49,41 @@ static const unsigned char dh_p_val[] = {
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
#define DH_P_LEN sizeof(dh_p_val)
/* diffie-hellman-group14-sha1 value for p */
#define DH_P_14_LEN 256
static const unsigned char dh_p_14[DH_P_14_LEN] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2,
0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C,
0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF};
/* Same for group1 and group14 */
static const int DH_G_VAL = 2;
static void kexinitialise();
void gen_new_keys();
static void gen_new_keys();
#ifndef DISABLE_ZLIB
static void gen_new_zstreams();
static void gen_new_zstream_recv();
static void gen_new_zstream_trans();
#endif
static void read_kex_algos();
/* helper function for gen_new_keys */
@@ -90,11 +119,12 @@ void send_msg_kexinit() {
/* mac_algorithms_server_to_client */
buf_put_algolist(ses.writepayload, sshhashes);
/* compression_algorithms_client_to_server */
buf_put_algolist(ses.writepayload, sshcompress);
buf_put_algolist(ses.writepayload, ses.compress_algos);
/* compression_algorithms_server_to_client */
buf_put_algolist(ses.writepayload, sshcompress);
buf_put_algolist(ses.writepayload, ses.compress_algos);
/* languages_client_to_server */
buf_putstring(ses.writepayload, "", 0);
@@ -102,8 +132,8 @@ void send_msg_kexinit() {
/* languages_server_to_client */
buf_putstring(ses.writepayload, "", 0);
/* first_kex_packet_follows - unimplemented for now */
buf_putbyte(ses.writepayload, 0x00);
/* first_kex_packet_follows */
buf_putbyte(ses.writepayload, (ses.send_kex_first_guess != NULL));
/* reserved unit32 */
buf_putint(ses.writepayload, 0);
@@ -115,16 +145,60 @@ void send_msg_kexinit() {
encrypt_packet();
ses.dataallowed = 0; /* don't send other packets during kex */
ses.kexstate.sentkexinit = 1;
ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
if (ses.send_kex_first_guess) {
ses.newkeys->algo_kex = sshkex[0].val;
ses.newkeys->algo_hostkey = sshhostkey[0].val;
ses.send_kex_first_guess();
}
TRACE(("DATAALLOWED=0"))
TRACE(("-> KEXINIT"))
ses.kexstate.sentkexinit = 1;
}
/* *** NOTE regarding (send|recv)_msg_newkeys ***
* Changed by mihnea from the original kex.c to set dataallowed after a
* completed key exchange, no matter the order in which it was performed.
* This enables client mode without affecting server functionality.
*/
static void switch_keys() {
TRACE2(("enter switch_keys"))
if (!(ses.kexstate.sentkexinit && ses.kexstate.recvkexinit)) {
dropbear_exit("Unexpected newkeys message");
}
if (!ses.keys) {
ses.keys = m_malloc(sizeof(*ses.newkeys));
}
if (ses.kexstate.recvnewkeys && ses.newkeys->recv.valid) {
TRACE(("switch_keys recv"))
#ifndef DISABLE_ZLIB
gen_new_zstream_recv();
#endif
ses.keys->recv = ses.newkeys->recv;
m_burn(&ses.newkeys->recv, sizeof(ses.newkeys->recv));
ses.newkeys->recv.valid = 0;
}
if (ses.kexstate.sentnewkeys && ses.newkeys->trans.valid) {
TRACE(("switch_keys trans"))
#ifndef DISABLE_ZLIB
gen_new_zstream_trans();
#endif
ses.keys->trans = ses.newkeys->trans;
m_burn(&ses.newkeys->trans, sizeof(ses.newkeys->trans));
ses.newkeys->trans.valid = 0;
}
if (ses.kexstate.sentnewkeys && ses.kexstate.recvnewkeys)
{
TRACE(("switch_keys done"))
ses.keys->algo_kex = ses.newkeys->algo_kex;
ses.keys->algo_hostkey = ses.newkeys->algo_hostkey;
ses.keys->allow_compress = 0;
m_free(ses.newkeys);
ses.newkeys = NULL;
kexinitialise();
}
TRACE2(("leave switch_keys"))
}
/* Bring new keys into use after a key exchange, and let the client know*/
void send_msg_newkeys() {
@@ -135,44 +209,25 @@ void send_msg_newkeys() {
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_NEWKEYS);
encrypt_packet();
/* set up our state */
if (ses.kexstate.recvnewkeys) {
TRACE(("while RECVNEWKEYS=1"))
gen_new_keys();
kexinitialise(); /* we've finished with this kex */
TRACE((" -> DATAALLOWED=1"))
ses.dataallowed = 1; /* we can send other packets again now */
ses.kexstate.donefirstkex = 1;
} else {
ses.kexstate.sentnewkeys = 1;
TRACE(("SENTNEWKEYS=1"))
}
ses.kexstate.sentnewkeys = 1;
ses.kexstate.donefirstkex = 1;
ses.dataallowed = 1; /* we can send other packets again now */
gen_new_keys();
switch_keys();
TRACE(("-> MSG_NEWKEYS"))
TRACE(("leave send_msg_newkeys"))
}
/* Bring the new keys into use after a key exchange */
void recv_msg_newkeys() {
TRACE(("<- MSG_NEWKEYS"))
TRACE(("enter recv_msg_newkeys"))
/* simply check if we've sent SSH_MSG_NEWKEYS, and if so,
* switch to the new keys */
if (ses.kexstate.sentnewkeys) {
TRACE(("while SENTNEWKEYS=1"))
gen_new_keys();
kexinitialise(); /* we've finished with this kex */
TRACE((" -> DATAALLOWED=1"))
ses.dataallowed = 1; /* we can send other packets again now */
ses.kexstate.donefirstkex = 1;
} else {
TRACE(("RECVNEWKEYS=1"))
ses.kexstate.recvnewkeys = 1;
}
ses.kexstate.recvnewkeys = 1;
switch_keys();
TRACE(("leave recv_msg_newkeys"))
}
@@ -180,8 +235,16 @@ void recv_msg_newkeys() {
/* Set up the kex for the first time */
void kexfirstinitialise() {
ses.kexstate.donefirstkex = 0;
#ifndef DISABLE_ZLIB
if (opts.enable_compress) {
ses.compress_algos = ssh_compress;
} else
#endif
{
ses.compress_algos = ssh_nocompress;
}
kexinitialise();
}
@@ -199,11 +262,13 @@ static void kexinitialise() {
ses.kexstate.sentnewkeys = 0;
/* first_packet_follows */
ses.kexstate.firstfollows = 0;
ses.kexstate.them_firstfollows = 0;
ses.kexstate.datatrans = 0;
ses.kexstate.datarecv = 0;
ses.kexstate.our_first_follows_matches = 0;
ses.kexstate.lastkextime = time(NULL);
}
@@ -212,38 +277,39 @@ static void kexinitialise() {
* already initialised hash_state hs, which should already have processed
* the dh_K and hash, since these are common. X is the letter 'A', 'B' etc.
* out must have at least min(SHA1_HASH_SIZE, outlen) bytes allocated.
* The output will only be expanded once, as we are assured that
* outlen <= 2*SHA1_HASH_SIZE for all known hashes.
*
* See Section 7.2 of rfc4253 (ssh transport) for details */
static void hashkeys(unsigned char *out, int outlen,
const hash_state * hs, const unsigned char X) {
hash_state hs2;
unsigned char k2[SHA1_HASH_SIZE]; /* used to extending */
int offset;
memcpy(&hs2, hs, sizeof(hash_state));
sha1_process(&hs2, &X, 1);
sha1_process(&hs2, ses.session_id, SHA1_HASH_SIZE);
sha1_done(&hs2, out);
if (SHA1_HASH_SIZE < outlen) {
for (offset = SHA1_HASH_SIZE;
offset < outlen;
offset += SHA1_HASH_SIZE)
{
/* need to extend */
unsigned char k2[SHA1_HASH_SIZE];
memcpy(&hs2, hs, sizeof(hash_state));
sha1_process(&hs2, out, SHA1_HASH_SIZE);
sha1_process(&hs2, out, offset);
sha1_done(&hs2, k2);
memcpy(&out[SHA1_HASH_SIZE], k2, outlen - SHA1_HASH_SIZE);
memcpy(&out[offset], k2, MIN(outlen - offset, SHA1_HASH_SIZE));
}
}
/* Generate the actual encryption/integrity keys, using the results of the
* key exchange, as specified in section 5.2 of the IETF secsh-transport
* draft. This occurs after the DH key-exchange.
* key exchange, as specified in section 7.2 of the transport rfc 4253.
* This occurs after the DH key-exchange.
*
* ses.newkeys is the new set of keys which are generated, these are only
* taken into use after both sides have sent a newkeys message */
/* Originally from kex.c, generalized for cli/svr mode --mihnea */
void gen_new_keys() {
static void gen_new_keys() {
unsigned char C2S_IV[MAX_IV_LEN];
unsigned char C2S_key[MAX_KEY_LEN];
@@ -255,7 +321,6 @@ void gen_new_keys() {
hash_state hs;
unsigned int C2S_keysize, S2C_keysize;
char mactransletter, macrecvletter; /* Client or server specific */
int recv_cipher = 0, trans_cipher = 0;
TRACE(("enter gen_new_keys"))
/* the dh_K and hash are the start of all hashes, we make use of that */
@@ -272,8 +337,8 @@ void gen_new_keys() {
recv_IV = S2C_IV;
trans_key = C2S_key;
recv_key = S2C_key;
C2S_keysize = ses.newkeys->trans_algo_crypt->keysize;
S2C_keysize = ses.newkeys->recv_algo_crypt->keysize;
C2S_keysize = ses.newkeys->trans.algo_crypt->keysize;
S2C_keysize = ses.newkeys->recv.algo_crypt->keysize;
mactransletter = 'E';
macrecvletter = 'F';
} else {
@@ -281,8 +346,8 @@ void gen_new_keys() {
recv_IV = C2S_IV;
trans_key = S2C_key;
recv_key = C2S_key;
C2S_keysize = ses.newkeys->recv_algo_crypt->keysize;
S2C_keysize = ses.newkeys->trans_algo_crypt->keysize;
C2S_keysize = ses.newkeys->recv.algo_crypt->keysize;
S2C_keysize = ses.newkeys->trans.algo_crypt->keysize;
mactransletter = 'F';
macrecvletter = 'E';
}
@@ -292,41 +357,50 @@ void gen_new_keys() {
hashkeys(C2S_key, C2S_keysize, &hs, 'C');
hashkeys(S2C_key, S2C_keysize, &hs, 'D');
recv_cipher = find_cipher(ses.newkeys->recv_algo_crypt->cipherdesc->name);
if (recv_cipher < 0)
dropbear_exit("crypto error");
if (ses.newkeys->recv_crypt_mode->start(recv_cipher,
recv_IV, recv_key,
ses.newkeys->recv_algo_crypt->keysize, 0,
&ses.newkeys->recv_cipher_state) != CRYPT_OK) {
dropbear_exit("crypto error");
if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) {
int recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
if (recv_cipher < 0)
dropbear_exit("Crypto error");
if (ses.newkeys->recv.crypt_mode->start(recv_cipher,
recv_IV, recv_key,
ses.newkeys->recv.algo_crypt->keysize, 0,
&ses.newkeys->recv.cipher_state) != CRYPT_OK) {
dropbear_exit("Crypto error");
}
}
trans_cipher = find_cipher(ses.newkeys->trans_algo_crypt->cipherdesc->name);
if (trans_cipher < 0)
dropbear_exit("crypto error");
if (ses.newkeys->trans_crypt_mode->start(trans_cipher,
trans_IV, trans_key,
ses.newkeys->trans_algo_crypt->keysize, 0,
&ses.newkeys->trans_cipher_state) != CRYPT_OK) {
dropbear_exit("crypto error");
if (ses.newkeys->trans.algo_crypt->cipherdesc != NULL) {
int trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
if (trans_cipher < 0)
dropbear_exit("Crypto error");
if (ses.newkeys->trans.crypt_mode->start(trans_cipher,
trans_IV, trans_key,
ses.newkeys->trans.algo_crypt->keysize, 0,
&ses.newkeys->trans.cipher_state) != CRYPT_OK) {
dropbear_exit("Crypto error");
}
}
/* MAC keys */
hashkeys(ses.newkeys->transmackey,
ses.newkeys->trans_algo_mac->keysize, &hs, mactransletter);
hashkeys(ses.newkeys->recvmackey,
ses.newkeys->recv_algo_mac->keysize, &hs, macrecvletter);
#ifndef DISABLE_ZLIB
gen_new_zstreams();
#endif
/* Switch over to the new keys */
m_burn(ses.keys, sizeof(struct key_context));
m_free(ses.keys);
ses.keys = ses.newkeys;
ses.newkeys = NULL;
if (ses.newkeys->trans.algo_mac->hashdesc != NULL) {
hashkeys(ses.newkeys->trans.mackey,
ses.newkeys->trans.algo_mac->keysize, &hs, mactransletter);
ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hashdesc->name);
}
if (ses.newkeys->recv.algo_mac->hashdesc != NULL) {
hashkeys(ses.newkeys->recv.mackey,
ses.newkeys->recv.algo_mac->keysize, &hs, macrecvletter);
ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hashdesc->name);
}
/* Ready to switch over */
ses.newkeys->trans.valid = 1;
ses.newkeys->recv.valid = 1;
m_burn(C2S_IV, sizeof(C2S_IV));
m_burn(C2S_key, sizeof(C2S_key));
m_burn(S2C_IV, sizeof(S2C_IV));
m_burn(S2C_key, sizeof(S2C_key));
TRACE(("leave gen_new_keys"))
}
@@ -334,63 +408,68 @@ void gen_new_keys() {
#ifndef DISABLE_ZLIB
int is_compress_trans() {
return ses.keys->trans_algo_comp == DROPBEAR_COMP_ZLIB
return ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|| (ses.authstate.authdone
&& ses.keys->trans_algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
&& ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
}
int is_compress_recv() {
return ses.keys->recv_algo_comp == DROPBEAR_COMP_ZLIB
return ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|| (ses.authstate.authdone
&& ses.keys->recv_algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
&& ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
}
/* Set up new zlib compression streams, close the old ones. Only
* called from gen_new_keys() */
static void gen_new_zstreams() {
static void gen_new_zstream_recv() {
/* create new zstreams */
if (ses.newkeys->recv_algo_comp == DROPBEAR_COMP_ZLIB
|| ses.newkeys->recv_algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
ses.newkeys->recv_zstream = (z_streamp)m_malloc(sizeof(z_stream));
ses.newkeys->recv_zstream->zalloc = Z_NULL;
ses.newkeys->recv_zstream->zfree = Z_NULL;
if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|| ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream));
ses.newkeys->recv.zstream->zalloc = Z_NULL;
ses.newkeys->recv.zstream->zfree = Z_NULL;
if (inflateInit(ses.newkeys->recv_zstream) != Z_OK) {
if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) {
dropbear_exit("zlib error");
}
} else {
ses.newkeys->recv_zstream = NULL;
ses.newkeys->recv.zstream = NULL;
}
/* clean up old keys */
if (ses.keys->recv.zstream != NULL) {
if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
dropbear_exit("Crypto error");
}
m_free(ses.keys->recv.zstream);
}
}
if (ses.newkeys->trans_algo_comp == DROPBEAR_COMP_ZLIB
|| ses.newkeys->trans_algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
ses.newkeys->trans_zstream = (z_streamp)m_malloc(sizeof(z_stream));
ses.newkeys->trans_zstream->zalloc = Z_NULL;
ses.newkeys->trans_zstream->zfree = Z_NULL;
static void gen_new_zstream_trans() {
if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|| ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream));
ses.newkeys->trans.zstream->zalloc = Z_NULL;
ses.newkeys->trans.zstream->zfree = Z_NULL;
if (deflateInit(ses.newkeys->trans_zstream, Z_DEFAULT_COMPRESSION)
if (deflateInit2(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION,
Z_DEFLATED, DROPBEAR_ZLIB_WINDOW_BITS,
DROPBEAR_ZLIB_MEM_LEVEL, Z_DEFAULT_STRATEGY)
!= Z_OK) {
dropbear_exit("zlib error");
}
} else {
ses.newkeys->trans_zstream = NULL;
ses.newkeys->trans.zstream = NULL;
}
/* clean up old keys */
if (ses.keys->recv_zstream != NULL) {
if (inflateEnd(ses.keys->recv_zstream) == Z_STREAM_ERROR) {
if (ses.keys->trans.zstream != NULL) {
if (deflateEnd(ses.keys->trans.zstream) == Z_STREAM_ERROR) {
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
dropbear_exit("crypto error");
dropbear_exit("Crypto error");
}
m_free(ses.keys->recv_zstream);
}
if (ses.keys->trans_zstream != NULL) {
if (deflateEnd(ses.keys->trans_zstream) == Z_STREAM_ERROR) {
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
dropbear_exit("crypto error");
}
m_free(ses.keys->trans_zstream);
m_free(ses.keys->trans.zstream);
}
}
#endif /* DISABLE_ZLIB */
@@ -467,7 +546,7 @@ void recv_msg_kexinit() {
buf_putstring(ses.kexhashbuf,
ses.transkexinit->data, ses.transkexinit->len);
ses.requirenext = SSH_MSG_KEXDH_INIT;
ses.requirenext[0] = SSH_MSG_KEXDH_INIT;
}
buf_free(ses.transkexinit);
@@ -479,8 +558,20 @@ void recv_msg_kexinit() {
TRACE(("leave recv_msg_kexinit"))
}
static void load_dh_p(mp_int * dh_p)
{
switch (ses.newkeys->algo_kex) {
case DROPBEAR_KEX_DH_GROUP1:
bytes_to_mp(dh_p, dh_p_1, DH_P_1_LEN);
break;
case DROPBEAR_KEX_DH_GROUP14:
bytes_to_mp(dh_p, dh_p_14, DH_P_14_LEN);
break;
}
}
/* Initialises and generate one side of the diffie-hellman key exchange values.
* See the ietf-secsh-transport draft, section 6, for details */
* See the transport rfc 4253 section 8 for details */
/* dh_pub and dh_priv MUST be already initialised */
void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
@@ -488,12 +579,12 @@ void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
DEF_MP_INT(dh_q);
DEF_MP_INT(dh_g);
TRACE(("enter send_msg_kexdh_reply"))
TRACE(("enter gen_kexdh_vals"))
m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL);
/* read the prime and generator*/
bytes_to_mp(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN);
load_dh_p(&dh_p);
if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) {
dropbear_exit("Diffie-Hellman error");
@@ -531,7 +622,7 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
/* read the prime and generator*/
m_mp_init(&dh_p);
bytes_to_mp(&dh_p, dh_p_val, DH_P_LEN);
load_dh_p(&dh_p);
/* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */
if (mp_cmp(dh_pub_them, &dh_p) != MP_LT
@@ -611,20 +702,27 @@ static void read_kex_algos() {
buf_incrpos(ses.payload, 16); /* start after the cookie */
ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
memset(ses.newkeys, 0x0, sizeof(*ses.newkeys));
#ifdef USE_KEXGUESS2
enum kexguess2_used kexguess2 = KEXGUESS2_LOOK;
#else
enum kexguess2_used kexguess2 = KEXGUESS2_NO;
#endif
/* kex_algorithms */
algo = ses.buf_match_algo(ses.payload, sshkex, &goodguess);
algo = buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess);
allgood &= goodguess;
if (algo == NULL) {
if (algo == NULL || algo->val == KEXGUESS2_ALGO_ID) {
erralgo = "kex";
goto error;
}
TRACE(("kexguess2 %d", kexguess2))
TRACE(("kex algo %s", algo->name))
ses.newkeys->algo_kex = algo->val;
/* server_host_key_algorithms */
algo = ses.buf_match_algo(ses.payload, sshhostkey, &goodguess);
algo = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess);
allgood &= goodguess;
if (algo == NULL) {
erralgo = "hostkey";
@@ -634,7 +732,7 @@ static void read_kex_algos() {
ses.newkeys->algo_hostkey = algo->val;
/* encryption_algorithms_client_to_server */
c2s_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
if (c2s_cipher_algo == NULL) {
erralgo = "enc c->s";
goto error;
@@ -642,7 +740,7 @@ static void read_kex_algos() {
TRACE(("enc c2s is %s", c2s_cipher_algo->name))
/* encryption_algorithms_server_to_client */
s2c_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
if (s2c_cipher_algo == NULL) {
erralgo = "enc s->c";
goto error;
@@ -650,7 +748,7 @@ static void read_kex_algos() {
TRACE(("enc s2c is %s", s2c_cipher_algo->name))
/* mac_algorithms_client_to_server */
c2s_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
if (c2s_hash_algo == NULL) {
erralgo = "mac c->s";
goto error;
@@ -658,7 +756,7 @@ static void read_kex_algos() {
TRACE(("hash c2s is %s", c2s_hash_algo->name))
/* mac_algorithms_server_to_client */
s2c_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
if (s2c_hash_algo == NULL) {
erralgo = "mac s->c";
goto error;
@@ -666,7 +764,7 @@ static void read_kex_algos() {
TRACE(("hash s2c is %s", s2c_hash_algo->name))
/* compression_algorithms_client_to_server */
c2s_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
if (c2s_comp_algo == NULL) {
erralgo = "comp c->s";
goto error;
@@ -674,7 +772,7 @@ static void read_kex_algos() {
TRACE(("hash c2s is %s", c2s_comp_algo->name))
/* compression_algorithms_server_to_client */
s2c_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
if (s2c_comp_algo == NULL) {
erralgo = "comp s->c";
goto error;
@@ -687,9 +785,10 @@ static void read_kex_algos() {
/* languages_server_to_client */
buf_eatstring(ses.payload);
/* first_kex_packet_follows */
/* their first_kex_packet_follows */
if (buf_getbool(ses.payload)) {
ses.kexstate.firstfollows = 1;
TRACE(("them kex firstfollows. allgood %d", allgood))
ses.kexstate.them_firstfollows = 1;
/* if the guess wasn't good, we ignore the packet sent */
if (!allgood) {
ses.ignorenext = 1;
@@ -698,42 +797,47 @@ static void read_kex_algos() {
/* Handle the asymmetry */
if (IS_DROPBEAR_CLIENT) {
ses.newkeys->recv_algo_crypt =
ses.newkeys->recv.algo_crypt =
(struct dropbear_cipher*)s2c_cipher_algo->data;
ses.newkeys->trans_algo_crypt =
ses.newkeys->trans.algo_crypt =
(struct dropbear_cipher*)c2s_cipher_algo->data;
ses.newkeys->recv_crypt_mode =
ses.newkeys->recv.crypt_mode =
(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
ses.newkeys->trans_crypt_mode =
ses.newkeys->trans.crypt_mode =
(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
ses.newkeys->recv_algo_mac =
ses.newkeys->recv.algo_mac =
(struct dropbear_hash*)s2c_hash_algo->data;
ses.newkeys->trans_algo_mac =
ses.newkeys->trans.algo_mac =
(struct dropbear_hash*)c2s_hash_algo->data;
ses.newkeys->recv_algo_comp = s2c_comp_algo->val;
ses.newkeys->trans_algo_comp = c2s_comp_algo->val;
ses.newkeys->recv.algo_comp = s2c_comp_algo->val;
ses.newkeys->trans.algo_comp = c2s_comp_algo->val;
} else {
/* SERVER */
ses.newkeys->recv_algo_crypt =
ses.newkeys->recv.algo_crypt =
(struct dropbear_cipher*)c2s_cipher_algo->data;
ses.newkeys->trans_algo_crypt =
ses.newkeys->trans.algo_crypt =
(struct dropbear_cipher*)s2c_cipher_algo->data;
ses.newkeys->recv_crypt_mode =
ses.newkeys->recv.crypt_mode =
(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
ses.newkeys->trans_crypt_mode =
ses.newkeys->trans.crypt_mode =
(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
ses.newkeys->recv_algo_mac =
ses.newkeys->recv.algo_mac =
(struct dropbear_hash*)c2s_hash_algo->data;
ses.newkeys->trans_algo_mac =
ses.newkeys->trans.algo_mac =
(struct dropbear_hash*)s2c_hash_algo->data;
ses.newkeys->recv_algo_comp = c2s_comp_algo->val;
ses.newkeys->trans_algo_comp = s2c_comp_algo->val;
ses.newkeys->recv.algo_comp = c2s_comp_algo->val;
ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
}
/* reserved for future extensions */
buf_getint(ses.payload);
if (ses.send_kex_first_guess && allgood) {
TRACE(("our_first_follows_matches 1"))
ses.kexstate.our_first_follows_matches = 1;
}
return;
error:
dropbear_exit("no matching algo %s", erralgo);
dropbear_exit("No matching algo %s", erralgo);
}

View File

@@ -28,6 +28,8 @@
#include "buffer.h"
#include "dbutil.h"
#include "auth.h"
#include "algo.h"
#include "random.h"
runopts opts; /* GLOBAL */
@@ -44,6 +46,9 @@ int readhostkey(const char * filename, sign_key * hostkey, int *type) {
goto out;
}
buf_setpos(buf, 0);
addrandom(buf_getptr(buf, buf->len), buf->len);
if (buf_get_priv_key(buf, hostkey, type) == DROPBEAR_FAILURE) {
goto out;
}
@@ -55,3 +60,48 @@ out:
buf_free(buf);
return ret;
}
#ifdef ENABLE_USER_ALGO_LIST
void
parse_ciphers_macs()
{
if (opts.cipher_list)
{
if (strcmp(opts.cipher_list, "help") == 0)
{
char *ciphers = algolist_string(sshciphers);
dropbear_log(LOG_INFO, "Available ciphers:\n%s\n", ciphers);
m_free(ciphers);
dropbear_exit(".");
}
if (strcmp(opts.cipher_list, "none") == 0)
{
/* Encryption is required during authentication */
opts.cipher_list = "none,aes128-ctr";
}
if (check_user_algos(opts.cipher_list, sshciphers, "cipher") == 0)
{
dropbear_exit("No valid ciphers specified for '-c'");
}
}
if (opts.mac_list)
{
if (strcmp(opts.mac_list, "help") == 0)
{
char *macs = algolist_string(sshhashes);
dropbear_log(LOG_INFO, "Available MACs:\n%s\n", macs);
m_free(macs);
dropbear_exit(".");
}
if (check_user_algos(opts.mac_list, sshhashes, "MAC") == 0)
{
dropbear_exit("No valid MACs specified for '-m'");
}
}
}
#endif

View File

@@ -33,12 +33,12 @@
#include "random.h"
#include "kex.h"
#include "channel.h"
#include "atomicio.h"
#include "runopts.h"
static void checktimeouts();
static long select_timeout();
static int ident_readln(int fd, char* buf, int count);
static void read_session_identification();
struct sshsession ses; /* GLOBAL */
@@ -49,15 +49,11 @@ int sessinitdone = 0; /* GLOBAL */
/* this is set when we get SIGINT or SIGTERM, the handler is in main.c */
int exitflag = 0; /* GLOBAL */
/* called only at the start of a session, set up initial state */
void common_session_init(int sock_in, int sock_out, char* remotehost) {
void common_session_init(int sock_in, int sock_out) {
TRACE(("enter session_init"))
ses.remotehost = remotehost;
ses.sock_in = sock_in;
ses.sock_out = sock_out;
ses.maxfd = MAX(sock_in, sock_out);
@@ -67,10 +63,13 @@ void common_session_init(int sock_in, int sock_out, char* remotehost) {
ses.last_packet_time = 0;
if (pipe(ses.signal_pipe) < 0) {
dropbear_exit("signal pipe failed");
dropbear_exit("Signal pipe failed");
}
setnonblocking(ses.signal_pipe[0]);
setnonblocking(ses.signal_pipe[1]);
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
kexfirstinitialise(); /* initialise the kex state */
@@ -78,13 +77,12 @@ void common_session_init(int sock_in, int sock_out, char* remotehost) {
ses.transseq = 0;
ses.readbuf = NULL;
ses.decryptreadbuf = NULL;
ses.payload = NULL;
ses.recvseq = 0;
initqueue(&ses.writequeue);
ses.requirenext = SSH_MSG_KEXINIT;
ses.requirenext[0] = SSH_MSG_KEXINIT;
ses.dataallowed = 1; /* we can send data until we actually
send the SSH_MSG_KEXINIT */
ses.ignorenext = 0;
@@ -95,22 +93,22 @@ void common_session_init(int sock_in, int sock_out, char* remotehost) {
/* set all the algos to none */
ses.keys = (struct key_context*)m_malloc(sizeof(struct key_context));
ses.newkeys = NULL;
ses.keys->recv_algo_crypt = &dropbear_nocipher;
ses.keys->trans_algo_crypt = &dropbear_nocipher;
ses.keys->recv_crypt_mode = &dropbear_mode_none;
ses.keys->trans_crypt_mode = &dropbear_mode_none;
ses.keys->recv.algo_crypt = &dropbear_nocipher;
ses.keys->trans.algo_crypt = &dropbear_nocipher;
ses.keys->recv.crypt_mode = &dropbear_mode_none;
ses.keys->trans.crypt_mode = &dropbear_mode_none;
ses.keys->recv_algo_mac = &dropbear_nohash;
ses.keys->trans_algo_mac = &dropbear_nohash;
ses.keys->recv.algo_mac = &dropbear_nohash;
ses.keys->trans.algo_mac = &dropbear_nohash;
ses.keys->algo_kex = -1;
ses.keys->algo_hostkey = -1;
ses.keys->recv_algo_comp = DROPBEAR_COMP_NONE;
ses.keys->trans_algo_comp = DROPBEAR_COMP_NONE;
ses.keys->recv.algo_comp = DROPBEAR_COMP_NONE;
ses.keys->trans.algo_comp = DROPBEAR_COMP_NONE;
#ifndef DISABLE_ZLIB
ses.keys->recv_zstream = NULL;
ses.keys->trans_zstream = NULL;
ses.keys->recv.zstream = NULL;
ses.keys->trans.zstream = NULL;
#endif
/* key exchange buffers */
@@ -141,7 +139,10 @@ void session_loop(void(*loophandler)()) {
FD_ZERO(&writefd);
FD_ZERO(&readfd);
dropbear_assert(ses.payload == NULL);
if (ses.sock_in != -1) {
/* during initial setup we flush out the KEXINIT packet before
* attempting to read the remote version string, which might block */
if (ses.sock_in != -1 && (ses.remoteident || isempty(&ses.writequeue))) {
FD_SET(ses.sock_in, &readfd);
}
if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
@@ -195,7 +196,12 @@ void session_loop(void(*loophandler)()) {
if (ses.sock_in != -1) {
if (FD_ISSET(ses.sock_in, &readfd)) {
read_packet();
if (!ses.remoteident) {
/* blocking read of the version string */
read_session_identification();
} else {
read_packet();
}
}
/* Process the decrypted packet. After this, the read buffer
@@ -225,7 +231,7 @@ void session_loop(void(*loophandler)()) {
}
/* clean up a session on exit */
void common_session_cleanup() {
void session_cleanup() {
TRACE(("enter session_cleanup"))
@@ -234,6 +240,10 @@ void common_session_cleanup() {
TRACE(("leave session_cleanup: !sessinitdone"))
return;
}
if (ses.extra_session_cleanup) {
ses.extra_session_cleanup();
}
m_free(ses.session_id);
m_burn(ses.keys, sizeof(struct key_context));
@@ -244,21 +254,20 @@ void common_session_cleanup() {
TRACE(("leave session_cleanup"))
}
void send_session_identification() {
buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
buf_putbytes(writebuf, LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
buf_putbyte(writebuf, 0x0); // packet type
buf_setpos(writebuf, 0);
enqueue(&ses.writequeue, writebuf);
}
void session_identification() {
static void read_session_identification() {
/* max length of 255 chars */
char linebuf[256];
int len = 0;
char done = 0;
int i;
/* write our version string, this blocks */
if (atomicio(write, ses.sock_out, LOCAL_IDENT "\r\n",
strlen(LOCAL_IDENT "\r\n")) == DROPBEAR_FAILURE) {
ses.remoteclosed();
}
/* If they send more than 50 lines, something is wrong */
for (i = 0; i < 50; i++) {
len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf));
@@ -453,6 +462,20 @@ void fill_passwd(const char* username) {
ses.authstate.pw_name = m_strdup(pw->pw_name);
ses.authstate.pw_dir = m_strdup(pw->pw_dir);
ses.authstate.pw_shell = m_strdup(pw->pw_shell);
ses.authstate.pw_passwd = m_strdup(pw->pw_passwd);
{
char *passwd_crypt = pw->pw_passwd;
#ifdef HAVE_SHADOW_H
/* get the shadow password if possible */
struct spwd *spasswd = getspnam(ses.authstate.pw_name);
if (spasswd && spasswd->sp_pwdp) {
passwd_crypt = spasswd->sp_pwdp;
}
#endif
if (!passwd_crypt) {
/* android supposedly returns NULL */
passwd_crypt = "!!";
}
ses.authstate.pw_passwd = m_strdup(passwd_crypt);
}
}

View File

@@ -193,6 +193,10 @@ int daemon(int nochdir, int noclose) {
char *basename(const char *path) {
char *foo = strrchr(path, '/');
if (!foo)
{
return path;
}
return ++foo;
}

View File

@@ -146,6 +146,7 @@ AC_ARG_ENABLE(pam,
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_NOTICE(Enabling PAM)
AC_CHECK_FUNCS(pam_fail_delay)
else
AC_DEFINE(DISABLE_PAM,, Use PAM)
AC_MSG_NOTICE(Disabling PAM)
@@ -210,7 +211,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 security/pam_appl.h pam/pam_appl.h netinet/in_systm.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 netinet/in_systm.h, sys/uio.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
@@ -362,6 +363,25 @@ AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
AC_CHECK_FUNCS(setutxent utmpxname)
AC_CHECK_FUNCS(logout updwtmp logwtmp)
AC_ARG_ENABLE(bundled-libtom,
[ --enable-bundled-libtom Use bundled libtomcrypt/libtommath even if a system version exists],
[
BUNDLED_LIBTOM=1
AC_MSG_NOTICE(Forcing bundled libtom*)
],
[
BUNDLED_LIBTOM=0
AC_CHECK_LIB(tomcrypt, register_cipher, , BUNDLED_LIBTOM=1)
AC_CHECK_LIB(tommath, mp_exptmod, , BUNDLED_LIBTOM=1)
]
)
if test $BUNDLED_LIBTOM = 1 ; then
AC_DEFINE(BUNDLED_LIBTOM,,Use bundled libtom)
fi
AC_SUBST(BUNDLED_LIBTOM)
dnl Added from OpenSSH 3.6.1p2's configure.ac
dnl allow user to disable some login recording features
@@ -596,7 +616,7 @@ AC_PROG_GCC_TRADITIONAL
AC_FUNC_MEMCMP
AC_FUNC_SELECT_ARGTYPES
AC_TYPE_SIGNAL
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo])
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev])
AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
@@ -670,5 +690,13 @@ AC_CONFIG_HEADER(config.h)
AC_OUTPUT(Makefile)
AC_OUTPUT(libtomcrypt/Makefile)
AC_OUTPUT(libtommath/Makefile)
AC_MSG_NOTICE()
if test $BUNDLED_LIBTOM = 1 ; then
AC_MSG_NOTICE(Using bundled libtomcrypt and libtommath)
else
AC_MSG_NOTICE(Using system libtomcrypt and libtommath)
fi
AC_MSG_NOTICE()
AC_MSG_NOTICE(Now edit options.h to choose features.)

View File

@@ -15,7 +15,7 @@ dbclient \- lightweight SSH2 client
.B dbclient
[
.I args ]
.I [user1]@host1[/port1],[user2]@host2[/port2],...
.I [user1]@host1[%port1],[user2]@host2[%port2],...
.SH DESCRIPTION
.B dbclient
@@ -24,10 +24,9 @@ environments, while still being functional and secure enough for general use.
.SH OPTIONS
.TP
.B \-p \fIport
Remote port.
Connect to port
Connect to
.I port
on the remote host.
on the remote host. Alternatively a port can be specified as hostname%port.
Default is 22.
.TP
.B \-i \fIidfile
@@ -36,7 +35,7 @@ Read the identity from file
.I idfile
(multiple allowed).
.TP
.B \-L \fIlistenport\fR:\fIhost\fR:\fIport\fR
.B \-L [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
Local port forwarding.
Forward the port
.I listenport
@@ -45,7 +44,7 @@ on the local host through the SSH connection to port
on the host
.IR host .
.TP
.B \-R \fIlistenport\fR:\fIhost\fR:\fIport\fR
.B \-R [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
Remote port forwarding.
Forward the port
.I listenport
@@ -61,10 +60,10 @@ Login as
on the remote host.
.TP
.B \-t
Allocate a pty.
Allocate a PTY.
.TP
.B \-T
Don't allocate a pty.
Don't allocate a PTY.
.TP
.B \-N
Don't request a remote shell or run any commands. Any command arguments are ignored.
@@ -80,7 +79,13 @@ by the ssh server.
.TP
.B \-y
Always accept hostkeys if they are unknown. If a hostkey mismatch occurs the
connection will abort as normal.
connection will abort as normal. If specified a second time no host key checking
is performed at all, this is usually undesirable.
.TP
.B \-A
Forward agent connections to the remote host. dbclient will use any
OpenSSH-style agent program if available ($SSH_AUTH_SOCK will be set) for
public key authentication. Forwarding is only enabled if -A is specified.
.TP
.B \-W \fIwindowsize
Specify the per-channel receive window buffer size. Increasing this
@@ -106,12 +111,22 @@ comparing saved hostkeys.
"Netcat-alike" mode, where Dropbear will connect to the given host, then create a
forwarded connection to \fIendhost\fR. This will then be presented as dbclient's
standard input/output.
.TP
.B \-c \fIcipherlist
Specify a comma separated list of ciphers to enable. Use \fI-c help\fR to list possibilities.
.TP
.B \-m \fIMAClist
Specify a comma separated list of authentication MACs to enable. Use \fI-m help\fR to list possibilities.
.TP
.B \-s
The specified command will be requested as a subsystem, used for sftp. Dropbear doesn't implement sftp itself but the OpenSSH sftp client can be used eg \fIsftp -S dbclient user@host\fR
.SH MULTI-HOP
Dropbear will also allow multiple "hops" to be specified, separated by commas. In
this case a connection will be made to the first host, then a TCP forwarded
connection will be made through that to the second host, and so on. Hosts other than
the final destination will not see anything other than the encrypted SSH stream.
A port for a host can be specified with a slash (eg matt@martello/44 ).
A port for a host can be specified with a hash (eg matt@martello%44 ).
This syntax can also be used with scp or rsync (specifying dbclient as the
ssh/rsh command). A file can be "bounced" through multiple SSH hops, eg
@@ -121,6 +136,11 @@ Note that hostnames are resolved by the prior hop (so "canyons" would be resolve
in the example above, the same way as other -L TCP forwarded hosts are. Host keys are
checked locally based on the given hostname.
.SH ESCAPE CHARACTERS
Typing a newline followed by the key sequence \fI~.\fR (tilde, dot) will terminate a connection.
The sequence \fI~^Z\fR (tilde, ctrl-z) will background the connection. This behaviour only
applies when a PTY is used.
.SH ENVIRONMENT
.TP
.B DROPBEAR_PASSWORD
@@ -143,4 +163,4 @@ Gerrit Pape (pape@smarden.org) wrote this manual page.
.SH SEE ALSO
dropbear(8), dropbearkey(8)
.P
http://matt.ucc.asn.au/dropbear/dropbear.html
https://matt.ucc.asn.au/dropbear/dropbear.html

View File

@@ -66,7 +66,7 @@ int main(int argc, char ** argv) {
#endif
}
fprintf(stderr, "Dropbear multi-purpose version %s\n"
fprintf(stderr, "Dropbear SSH multi-purpose v%s\n"
"Make a symlink pointing at this binary with one of the following names:\n"
#ifdef DBMULTI_dropbear
"'dropbear' - the Dropbear server\n"

211
dbutil.c
View File

@@ -57,11 +57,11 @@
#define MAX_FMT 100
static void generic_dropbear_exit(int exitcode, const char* format,
va_list param);
va_list param) ATTRIB_NORETURN;
static void generic_dropbear_log(int priority, const char* format,
va_list param);
void (*_dropbear_exit)(int exitcode, const char* format, va_list param)
void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN
= generic_dropbear_exit;
void (*_dropbear_log)(int priority, const char* format, va_list param)
= generic_dropbear_log;
@@ -111,7 +111,7 @@ static void generic_dropbear_exit(int exitcode, const char* format,
}
void fail_assert(const char* expr, const char* file, int line) {
dropbear_exit("failed assertion (%s:%d): `%s'", file, line, expr);
dropbear_exit("Failed assertion (%s:%d): `%s'", file, line, expr);
}
static void generic_dropbear_log(int UNUSED(priority), const char* format,
@@ -138,15 +138,39 @@ void dropbear_log(int priority, const char* format, ...) {
#ifdef DEBUG_TRACE
void dropbear_trace(const char* format, ...) {
va_list param;
struct timeval tv;
if (!debug_trace) {
return;
}
gettimeofday(&tv, NULL);
va_start(param, format);
fprintf(stderr, "TRACE (%d): ", getpid());
fprintf(stderr, "TRACE (%d) %d.%d: ", getpid(), tv.tv_sec, tv.tv_usec);
vfprintf(stderr, format, param);
fprintf(stderr, "\n");
va_end(param);
}
void dropbear_trace2(const char* format, ...) {
static int trace_env = -1;
va_list param;
struct timeval tv;
if (trace_env == -1) {
trace_env = getenv("DROPBEAR_TRACE2") ? 1 : 0;
}
if (!(debug_trace && trace_env)) {
return;
}
gettimeofday(&tv, NULL);
va_start(param, format);
fprintf(stderr, "TRACE2 (%d) %d.%d: ", getpid(), tv.tv_sec, tv.tv_usec);
vfprintf(stderr, format, param);
fprintf(stderr, "\n");
va_end(param);
@@ -161,10 +185,12 @@ static void set_sock_priority(int sock) {
val = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
/* set the TOS bit. note that this will fail for ipv6, I can't find any
* equivalent. */
/* set the TOS bit for either ipv4 or ipv6 */
#ifdef IPTOS_LOWDELAY
val = IPTOS_LOWDELAY;
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&val, sizeof(val));
#endif
setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&val, sizeof(val));
#endif
@@ -254,6 +280,16 @@ int dropbear_listen(const char* address, const char* port,
linger.l_linger = 5;
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if (res->ai_family == AF_INET6) {
int on = 1;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
&on, sizeof(on)) == -1) {
dropbear_log(LOG_WARNING, "Couldn't set IPV6_V6ONLY");
}
}
#endif
set_sock_priority(sock);
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
@@ -295,6 +331,29 @@ int dropbear_listen(const char* address, const char* port,
return nsock;
}
/* Connect to a given unix socket. The socket is blocking */
#ifdef ENABLE_CONNECT_UNIX
int connect_unix(const char* path) {
struct sockaddr_un addr;
int fd = -1;
memset((void*)&addr, 0x0, sizeof(addr));
addr.sun_family = AF_UNIX;
strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
TRACE(("Failed to open unix socket"))
return -1;
}
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
TRACE(("Failed to connect to '%s' socket", path))
m_close(fd);
return -1;
}
return fd;
}
#endif
/* Connect via TCP to a host. Connection will try ipv4 or ipv6, will
* return immediately if nonblocking is set. On failure, if errstring
* wasn't null, it will be a newly malloced error message */
@@ -341,15 +400,7 @@ int connect_remote(const char* remotehost, const char* remoteport,
}
if (nonblocking) {
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
close(sock);
sock = -1;
if (errstring != NULL && *errstring == NULL) {
*errstring = m_strdup("Failed non-blocking");
}
TRACE(("Failed non-blocking: %s", strerror(errno)))
continue;
}
setnonblocking(sock);
}
if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
@@ -416,7 +467,7 @@ int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
return DROPBEAR_FAILURE;
}
#ifdef __uClinux__
#ifdef USE_VFORK
pid = vfork();
#else
pid = fork();
@@ -441,7 +492,7 @@ int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
(dup2(outfds[FDOUT], STDOUT_FILENO) < 0) ||
(ret_errfd && dup2(errfds[FDOUT], STDERR_FILENO) < 0)) {
TRACE(("leave noptycommand: error redirecting FDs"))
dropbear_exit("child dup2() failure");
dropbear_exit("Child dup2() failure");
}
close(infds[FDOUT]);
@@ -525,14 +576,47 @@ void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) {
execv(usershell, argv);
}
void get_socket_address(int fd, char **local_host, char **local_port,
char **remote_host, char **remote_port, int host_lookup)
{
struct sockaddr_storage addr;
socklen_t addrlen;
if (local_host || local_port) {
addrlen = sizeof(addr);
if (getsockname(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
dropbear_exit("Failed socket address: %s", strerror(errno));
}
getaddrstring(&addr, local_host, local_port, host_lookup);
}
if (remote_host || remote_port) {
addrlen = sizeof(addr);
if (getpeername(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
dropbear_exit("Failed socket address: %s", strerror(errno));
}
getaddrstring(&addr, remote_host, remote_port, host_lookup);
}
}
/* Return a string representation of the socket address passed. The return
* value is allocated with malloc() */
unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {
void getaddrstring(struct sockaddr_storage* addr,
char **ret_host, char **ret_port,
int host_lookup) {
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
char *retstring = NULL;
int ret;
char host[NI_MAXHOST+1], serv[NI_MAXSERV+1];
unsigned int len;
int ret;
int flags = NI_NUMERICSERV | NI_NUMERICHOST;
#ifndef DO_HOST_LOOKUP
host_lookup = 0;
#endif
if (host_lookup) {
flags = NI_NUMERICSERV;
}
len = sizeof(struct sockaddr_storage);
/* Some platforms such as Solaris 8 require that len is the length
@@ -550,67 +634,28 @@ unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {
#endif
#endif
ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
sbuf, sizeof(sbuf), NI_NUMERICSERV | NI_NUMERICHOST);
ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1,
serv, sizeof(serv)-1, flags);
if (ret != 0) {
/* This is a fairly bad failure - it'll fallback to IP if it
* just can't resolve */
dropbear_exit("failed lookup (%d, %d)", ret, errno);
if (host_lookup) {
/* On some systems (Darwin does it) we get EINTR from getnameinfo
* somehow. Eew. So we'll just return the IP, since that doesn't seem
* to exhibit that behaviour. */
getaddrstring(addr, ret_host, ret_port, 0);
return;
} else {
/* if we can't do a numeric lookup, something's gone terribly wrong */
dropbear_exit("Failed lookup: %s", gai_strerror(ret));
}
}
if (withport) {
len = strlen(hbuf) + 2 + strlen(sbuf);
retstring = (char*)m_malloc(len);
snprintf(retstring, len, "%s:%s", hbuf, sbuf);
} else {
retstring = m_strdup(hbuf);
if (ret_host) {
*ret_host = m_strdup(host);
}
return retstring;
}
/* Get the hostname corresponding to the address addr. On failure, the IP
* address is returned. The return value is allocated with strdup() */
char* getaddrhostname(struct sockaddr_storage * addr) {
char hbuf[NI_MAXHOST];
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. */
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
if (addr->ss_family == AF_INET) {
len = sizeof(struct sockaddr_in);
if (ret_port) {
*ret_port = m_strdup(serv);
}
#ifdef AF_INET6
if (addr->ss_family == AF_INET6) {
len = sizeof(struct sockaddr_in6);
}
#endif
#endif
ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
sbuf, sizeof(sbuf), flags);
if (ret != 0) {
/* On some systems (Darwin does it) we get EINTR from getnameinfo
* somehow. Eew. So we'll just return the IP, since that doesn't seem
* to exhibit that behaviour. */
return getaddrstring(addr, 0);
}
return m_strdup(hbuf);
}
#ifdef DEBUG_TRACE
@@ -704,8 +749,6 @@ int buf_getline(buffer * line, FILE * authfile) {
int c = EOF;
TRACE(("enter buf_getline"))
buf_setpos(line, 0);
buf_setlen(line, 0);
@@ -729,10 +772,8 @@ out:
/* if we didn't read anything before EOF or error, exit */
if (c == EOF && line->pos == 0) {
TRACE(("leave buf_getline: failure"))
return DROPBEAR_FAILURE;
} else {
TRACE(("leave buf_getline: success"))
buf_setpos(line, 0);
return DROPBEAR_SUCCESS;
}
@@ -779,12 +820,6 @@ void * m_strdup(const char * str) {
return ret;
}
void __m_free(void* ptr) {
if (ptr != NULL) {
free(ptr);
}
}
void * m_realloc(void* ptr, size_t size) {
void *ret;
@@ -809,7 +844,7 @@ void m_burn(void *data, unsigned int len) {
if (data == NULL)
return;
while (len--) {
*p++ = 0x66;
*p++ = 0x0;
}
}

View File

@@ -33,28 +33,48 @@
void startsyslog();
#endif
extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param);
#ifdef __GNUC__
#define ATTRIB_PRINTF(fmt,args) __attribute__((format(printf, fmt, args)))
#define ATTRIB_NORETURN __attribute__((noreturn))
#define ATTRIB_SENTINEL __attribute__((sentinel))
#else
#define ATTRIB_PRINTF(fmt,args)
#define ATTRIB_NORETURN
#define ATTRIB_SENTINEL
#endif
extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
extern void (*_dropbear_log)(int priority, const char* format, va_list param);
void dropbear_exit(const char* format, ...);
void dropbear_close(const char* format, ...);
void dropbear_log(int priority, const char* format, ...);
void fail_assert(const char* expr, const char* file, int line);
void dropbear_exit(const char* format, ...) ATTRIB_PRINTF(1,2) ATTRIB_NORETURN;
void dropbear_close(const char* format, ...) ATTRIB_PRINTF(1,2) ;
void dropbear_log(int priority, const char* format, ...) ATTRIB_PRINTF(2,3) ;
void fail_assert(const char* expr, const char* file, int line) ATTRIB_NORETURN;
#ifdef DEBUG_TRACE
void dropbear_trace(const char* format, ...);
void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace2(const char* format, ...) ATTRIB_PRINTF(1,2);
void printhex(const char * label, const unsigned char * buf, int len);
extern int debug_trace;
#endif
char * stripcontrol(const char * text);
unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport);
void get_socket_address(int fd, char **local_host, char **local_port,
char **remote_host, char **remote_port, int host_lookup);
void getaddrstring(struct sockaddr_storage* addr,
char **ret_host, char **ret_port, int host_lookup);
int dropbear_listen(const char* address, const char* port,
int *socks, unsigned int sockcount, char **errstring, int *maxfd);
int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
int *writefd, int *readfd, int *errfd, pid_t *pid);
void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell);
#ifdef ENABLE_CONNECT_UNIX
int connect_unix(const char* addr);
#endif
int connect_remote(const char* remotehost, const char* remoteport,
int nonblocking, char ** errstring);
char* getaddrhostname(struct sockaddr_storage * addr);
int buf_readfile(buffer* buf, const char* filename);
int buf_getline(buffer * line, FILE * authfile);
@@ -62,8 +82,7 @@ void m_close(int fd);
void * m_malloc(size_t size);
void * m_strdup(const char * str);
void * m_realloc(void* ptr, size_t size);
#define m_free(X) __m_free(X); (X) = NULL;
void __m_free(void* ptr);
#define m_free(X) free(X); (X) = NULL;
void m_burn(void* data, unsigned int len);
void setnonblocking(int fd);
void disallow_core();

48
debian/changelog vendored
View File

@@ -1,20 +1,44 @@
dropbear (0.52-2) unstable; urgency=low
dropbear (2013.58-0.1) unstable; urgency=low
* Make key utils part of dropbear-server package (since it's
required anyway, single binary saves space), rename -common to
-keyutils
* Don't make clean between builds, just rm *.o since only
top-level files change
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 19 Nov 2008 21:54:00 +0900
-- Matt Johnston <matt@ucc.asn.au> Thu, 18 Apr 2013 22:54:00 +0800
dropbear (0.52-1) unstable; urgency=low
dropbear (2013.57-0.1) unstable; urgency=low
* Maemo port, split into 5 packages
(dropbear, dropbear-server, dropbear-client, dropbear-common, dropbear-scp).
This avoids conflicts with openssh package.
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 19 Nov 2008 20:54:00 +0900
-- Matt Johnston <matt@ucc.asn.au> Mon, 15 Apr 2013 22:54:00 +0800
dropbear (2013.56-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 21 Mar 2013 22:54:00 +0800
dropbear (2012.55-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 22 Feb 2012 22:54:00 +0800
dropbear (2011.54-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Tues, 8 Nov 2011 22:54:00 +0800
dropbear (0.53.1-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 2 Mar 2011 22:54:00 +0900
dropbear (0.53-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 24 Feb 2011 22:54:00 +0900
dropbear (0.52-0.1) unstable; urgency=low

79
debian/control vendored
View File

@@ -1,7 +1,7 @@
Source: dropbear
Section: user/network
Section: net
Priority: optional
Maintainer: Matt Johnston <matt@ucc.asn.au>
Maintainer: Gerrit Pape <pape@smarden.org>
Build-Depends: libz-dev
Standards-Version: 3.7.3.0
@@ -9,9 +9,6 @@ Package: dropbear
Architecture: any
Depends: ${shlibs:Depends}
Suggests: openssh-client, runit
Section: user/network
Conflicts: dropbear-server, dropbear-client, dropbear-keyutils, dropbear-scp
XB-Maemo-Display-Name: Dropbear SSH Client and Server
Description: lightweight SSH2 server and client
dropbear is a SSH 2 server and client designed to be small enough to
be used in small memory environments, while still being functional and
@@ -20,76 +17,4 @@ Description: lightweight SSH2 server and client
It implements most required features of the SSH 2 protocol, and other
features such as X11 and authentication agent forwarding.
.
This package provides Dropbear client and server as a single binary,
as well as key utilities and SCP.
.
See http://matt.ucc.asn.au/dropbear/dropbear.html
Package: dropbear-server
Architecture: any
Depends: ${shlibs:Depends}
Section: user/network
Conflicts: dropbear, dropbear-keyutils
Provides: dropbear-keyutils
Recommends: dropbear-scp
XB-Maemo-Display-Name: Dropbear SSH Server
Description: lightweight SSH2 server
dropbear is a SSH 2 server and client designed to be small enough to
be used in small memory environments, while still being functional and
secure enough for general use.
.
It implements most required features of the SSH 2 protocol, and other
features such as X11 and authentication agent forwarding.
.
This package provides only the Dropbear server.
.
See http://matt.ucc.asn.au/dropbear/dropbear.html
Package: dropbear-client
Architecture: any
Conflicts: dropbear
Section: user/network
Depends: ${shlibs:Depends}
Recommends: dropbear-scp
Suggests: dropbear-keyutils
XB-Maemo-Display-Name: Dropbear SSH Client
Description: lightweight SSH2 client
dropbear is a SSH 2 server and client designed to be small enough to
be used in small memory environments, while still being functional and
secure enough for general use.
.
It implements most required features of the SSH 2 protocol, and other
features such as X11 and authentication agent forwarding.
.
This package provides only the Dropbear client.
.
See http://matt.ucc.asn.au/dropbear/dropbear.html
Package: dropbear-keyutils
Architecture: any
Conflicts: dropbear, dropbear-server
Section: user/network
XB-Maemo-Display-Name: Dropbear SSH Key Utils
Depends: ${shlibs:Depends}
Description: lightweight SSH2, key management utilities
dropbear is a SSH 2 server and client designed to be small enough to
be used in small memory environments, while still being functional and
secure enough for general use.
.
This package provides dropbearkey and dropbearconvert programs,
for generating keys and converting to/from OpenSSH keys.
.
See http://matt.ucc.asn.au/dropbear/dropbear.html
Package: dropbear-scp
Architecture: any
Section: user/network
Conflicts: dropbear
XB-Maemo-Display-Name: Dropbear SCP
Depends: ${shlibs:Depends}
Description: lightweight SSH2 scp
dropbear is a SSH 2 server and client designed to be small enough to
be used in small memory environments, while still being functional and
secure enough for general use.
.
This dropbear-scp package provides /usr/bin/scp.

View File

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

View File

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

View File

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

View File

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

View File

@@ -38,7 +38,7 @@ test -n "$DROPBEAR_RECEIVE_WINDOW" || \
case "$1" in
start)
test "$NO_START" = "0" || cancel '/etc/default/dropbear NO_START is set, Dropbear will not run.'
test "$NO_START" = "0" || cancel 'NO_START is not set to zero.'
echo -n "Starting $DESC: "
start-stop-daemon --start --quiet --pidfile /var/run/"$NAME".pid \
--exec "$DAEMON" -- -d "$DROPBEAR_DSSKEY" -r "$DROPBEAR_RSAKEY" \
@@ -51,7 +51,7 @@ case "$1" in
echo "$NAME."
;;
restart|force-reload)
test "$NO_START" = "0" || cancel '/etc/default/dropbear NO_START is set, Dropbear will not run.'
test "$NO_START" = "0" || cancel 'NO_START is not set to zero.'
echo -n "Restarting $DESC: "
start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/"$NAME".pid
sleep 1

146
debian/rules vendored
View File

@@ -13,7 +13,7 @@ CFLAGS =-Wall -g
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
CFLAGS +=-O0
else
CFLAGS +=-Os
CFLAGS +=-O2
endif
CONFFLAGS =
@@ -23,6 +23,8 @@ ifneq (,$(findstring diet,$(DEB_BUILD_OPTIONS)))
CC =diet -v -Os gcc -nostdinc
endif
DIR =$(shell pwd)/debian/dropbear
patch: deb-checkdir patch-stamp
patch-stamp:
for i in `ls -1 debian/diff/*.diff || :`; do \
@@ -37,15 +39,13 @@ config.status: patch-stamp configure
--build='$(DEB_BUILD_GNU_TYPE)' --prefix=/usr \
--mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info \
$(CONFFLAGS)
$(MAKE) clean
build: deb-checkdir build-stamp
build-stamp: config.status
$(MAKE) CC='$(CC)' LD='$(CC)'
touch build-stamp
clean: DIR=$(shell pwd)/debian/dropbear
clean: deb-checkdir deb-checkuid
clean: deb-checkdir deb-checkuid
test ! -r Makefile || $(MAKE) distclean
rm -f libtomcrypt/Makefile libtommath/Makefile
test ! -e patch-stamp || \
@@ -54,117 +54,22 @@ clean: deb-checkdir deb-checkuid
done
rm -f patch-stamp build-stamp config.log config.status
rm -rf '$(DIR)'
rm -rf '$(DIR)'-client
rm -rf '$(DIR)'-server
rm -rf '$(DIR)'-keyutils
rm -rf '$(DIR)'-scp
rm -f debian/files debian/substvars debian/copyright changelog
install-server: DIR=$(shell pwd)/debian/dropbear-server
install-server: deb-checkdir deb-checkuid config.status
rm -f '$(DIR)'
rm *.o
$(MAKE) CC='$(CC)' LD='$(LD)' PROGRAMS="dropbear dropbearkey dropbearconvert" MULTI=1
install: deb-checkdir deb-checkuid build-stamp
rm -rf '$(DIR)'
install -d -m0755 '$(DIR)'/etc/dropbear
# programs
install -d -m0755 '$(DIR)'/usr/bin
install -d -m0755 '$(DIR)'/usr/sbin
install -d -m0755 '$(DIR)'/usr/lib/dropbear
install -m0755 dropbearmulti \
'$(DIR)'/usr/lib/dropbear/dropbearmulti
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/bin/dropbearkey
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/sbin/dropbear
ln -s dropbearmulti '$(DIR)'/usr/lib/dropbear/dropbearconvert
# init and run scripts
install -d -m0755 '$(DIR)'/etc/init.d
install -m0755 debian/dropbear.init '$(DIR)'/etc/init.d/dropbear
install -m0755 debian/service/run '$(DIR)'/etc/dropbear/run
install -d -m0755 '$(DIR)'/etc/dropbear/log
install -m0755 debian/service/log '$(DIR)'/etc/dropbear/log/run
ln -s /var/log/dropbear '$(DIR)'/etc/dropbear/log/main
install -d -m0755 '$(DIR)'/usr/share/man/man8
for i in dropbear.8 ; do \
install -m644 $$i '$(DIR)'/usr/share/man/man8/ || exit 1; \
done
gzip -9 '$(DIR)'/usr/share/man/man8/*.8
# copyright, changelog
cat debian/copyright.in LICENSE > debian/copyright
test -r changelog || ln -s CHANGES changelog
$(STRIP) -R .comment -R .note '$(DIR)'/usr/lib/dropbear/*
install -d -m0755 '$(DIR)'/DEBIAN
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/lib/dropbear/*
install-client: DIR=$(shell pwd)/debian/dropbear-client
install-client: deb-checkdir deb-checkuid config.status
rm -f '$(DIR)'
rm *.o
$(MAKE) CC='$(CC)' LD='$(LD)' PROGRAMS=dbclient dbclient
install -m0755 dropbear '$(DIR)'/usr/sbin/dropbear
install -d -m0755 '$(DIR)'/usr/bin
install -m0755 dbclient '$(DIR)'/usr/bin/dbclient
install -d -m0755 '$(DIR)'/usr/share/man/man1
install -m644 dbclient.1 '$(DIR)'/usr/share/man/man1/
gzip -9 '$(DIR)'/usr/share/man/man1/*.1
$(STRIP) -R .comment -R .note '$(DIR)'/usr/bin/*
install -d -m0755 '$(DIR)'/DEBIAN
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/bin/*
install-keyutils: DIR=$(shell pwd)/debian/dropbear-keyutils
install-keyutils: deb-checkdir deb-checkuid config.status
rm -f '$(DIR)'
rm *.o
$(MAKE) CC='$(CC)' LD='$(LD)' PROGRAMS="dropbearkey dropbearconvert" MULTI=1
install -d -m0755 '$(DIR)'/usr/bin
install -m0755 dropbearkey '$(DIR)'/usr/bin/dropbearkey
install -d -m0755 '$(DIR)'/usr/lib/dropbear
install -m0755 dropbearmulti \
'$(DIR)'/usr/lib/dropbear/dropbearmulti
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/bin/dropbearkey
ln -s dropbearmulti '$(DIR)'/usr/lib/dropbear/dropbearconvert
install -d -m0755 '$(DIR)'/usr/share/man/man8
for i in dropbearkey.8; do \
install -m644 $$i '$(DIR)'/usr/share/man/man8/ || exit 1; \
done
gzip -9 '$(DIR)'/usr/share/man/man8/*.8
$(STRIP) -R .comment -R .note \
'$(DIR)'/usr/lib/dropbear/*
install -d -m0755 '$(DIR)'/DEBIAN
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/lib/dropbear/*
install-scp: DIR=$(shell pwd)/debian/dropbear-scp
install-scp: deb-checkdir deb-checkuid config.status
rm -f '$(DIR)'
rm *.o
$(MAKE) CC='$(CC)' LD='$(LD)' PROGRAMS="scp" scp
install -d -m0755 '$(DIR)'/usr/bin
install -m0755 scp '$(DIR)'/usr/bin/scp
$(STRIP) -R .comment -R .note '$(DIR)'/usr/bin/*
install -d -m0755 '$(DIR)'/DEBIAN
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/bin/*
install-multi: DIR=$(shell pwd)/debian/dropbear
install-multi: deb-checkdir deb-checkuid config.status
rm -f '$(DIR)'
rm *.o
$(MAKE) CC='$(CC)' LD='$(LD)' PROGRAMS="dropbearkey dropbearconvert scp dropbear dbclient" MULTI=1
install -d -m0755 '$(DIR)'/etc/dropbear
# programs
install -d -m0755 '$(DIR)'/usr/bin
install -d -m0755 '$(DIR)'/usr/sbin
install -d -m0755 '$(DIR)'/usr/lib/dropbear
install -m0755 dropbearmulti \
'$(DIR)'/usr/lib/dropbear/dropbearmulti
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/bin/dropbearkey
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/bin/dbclient
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/bin/scp
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/sbin/dropbear
ln -s dropbearmulti '$(DIR)'/usr/lib/dropbear/dropbearconvert
install -m0755 dropbearconvert \
'$(DIR)'/usr/lib/dropbear/dropbearconvert
$(STRIP) -R .comment -R .note '$(DIR)'/usr/sbin/* \
'$(DIR)'/usr/bin/* '$(DIR)'/usr/lib/dropbear/*
# init and run scripts
install -d -m0755 '$(DIR)'/etc/init.d
install -m0755 debian/dropbear.init '$(DIR)'/etc/init.d/dropbear
@@ -172,6 +77,7 @@ install-multi: deb-checkdir deb-checkuid config.status
install -d -m0755 '$(DIR)'/etc/dropbear/log
install -m0755 debian/service/log '$(DIR)'/etc/dropbear/log/run
ln -s /var/log/dropbear '$(DIR)'/etc/dropbear/log/main
# man pages
install -d -m0755 '$(DIR)'/usr/share/man/man8
for i in dropbear.8 dropbearkey.8; do \
install -m644 $$i '$(DIR)'/usr/share/man/man8/ || exit 1; \
@@ -180,26 +86,18 @@ install-multi: deb-checkdir deb-checkuid config.status
install -d -m0755 '$(DIR)'/usr/share/man/man1
install -m644 dbclient.1 '$(DIR)'/usr/share/man/man1/
gzip -9 '$(DIR)'/usr/share/man/man1/*.1
$(STRIP) -R .comment -R .note '$(DIR)'/usr/lib/dropbear/*
# copyright, changelog
cat debian/copyright.in LICENSE >debian/copyright
test -r changelog || ln -s CHANGES changelog
install -d -m0755 '$(DIR)'/DEBIAN
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/lib/dropbear/*
install: install-client install-server install-keyutils install-multi install-scp
binary-indep:
binary-arch: install dropbear.deb dropbear-server.deb dropbear-keyutils.deb dropbear-scp.deb dropbear-client.deb
dpkg-gencontrol -isp -pdropbear -P'$(shell pwd)/debian'/dropbear
dpkg-gencontrol -isp -pdropbear-server -P'$(shell pwd)/debian'/dropbear-server
dpkg-gencontrol -isp -pdropbear-client -P'$(shell pwd)/debian'/dropbear-client
dpkg-gencontrol -isp -pdropbear-keyutils -P'$(shell pwd)/debian'/dropbear-keyutils
dpkg-gencontrol -isp -pdropbear-scp -P'$(shell pwd)/debian'/dropbear-scp
dpkg -b '$(shell pwd)/debian'/dropbear ..
dpkg -b '$(shell pwd)/debian'/dropbear-server ..
dpkg -b '$(shell pwd)/debian'/dropbear-keyutils ..
dpkg -b '$(shell pwd)/debian'/dropbear-scp ..
dpkg -b '$(shell pwd)/debian'/dropbear-client ..
binary-arch: install dropbear.deb
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/sbin/* '$(DIR)'/usr/bin/* \
'$(DIR)'/usr/lib/dropbear/*
dpkg-gencontrol -isp -pdropbear -P'$(DIR)'
dpkg -b '$(DIR)' ..
binary: binary-arch binary-indep

View File

@@ -39,7 +39,7 @@
* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
* since the printing may not sanitise strings etc. This will add a reasonable
* amount to your executable size. */
/*#define DEBUG_TRACE*/
/* #define DEBUG_TRACE */
/* All functions writing to the cleartext payload buffer call
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're
@@ -63,8 +63,10 @@
/* you don't need to touch this block */
#ifdef DEBUG_TRACE
#define TRACE(X) dropbear_trace X;
#define TRACE2(X) dropbear_trace2 X;
#else /*DEBUG_TRACE*/
#define TRACE(X)
#define TRACE2(X)
#endif /*DEBUG_TRACE*/
/* To debug with GDB it is easier to run with no forking of child processes.

View File

@@ -7,7 +7,7 @@ dropbear \- lightweight SSH2 server
.I banner\fR] [\-d
.I dsskey\fR] [\-r
.I rsakey\fR] [\-p
.IR port ]
.IR [address:]port ]
.SH DESCRIPTION
.B dropbear
is a SSH 2 server designed to be small enough to be used in small memory
@@ -154,6 +154,34 @@ By default the file /etc/motd will be printed for any login shell (unless
disabled at compile-time). This can also be disabled per-user
by creating a file ~/.hushlogin .
.SH ENVIRONMENT VARIABLES
Dropbear sets the standard variables USER, LOGNAME, HOME, SHELL, PATH, and TERM.
The variables below are set for sessions as appropriate.
.TP
.B SSH_TTY
This is set to the allocated TTY if a PTY was used.
.TP
.B SSH_CONNECTION
Contains "<remote_ip> <remote_port> <local_ip> <local_port>".
.TP
.B DISPLAY
Set X11 forwarding is used.
.TP
.B SSH_ORIGINAL_COMMAND
If a 'command=' authorized_keys option was used, the original command is specified
in this variable. If a shell was requested this is set to an empty value.
.TP
.B SSH_AUTH_SOCK
Set to a forwarded ssh-agent connection.
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.br
@@ -161,4 +189,4 @@ Gerrit Pape (pape@smarden.org) wrote this manual page.
.SH SEE ALSO
dropbearkey(8), dbclient(1)
.P
http://matt.ucc.asn.au/dropbear/dropbear.html
https://matt.ucc.asn.au/dropbear/dropbear.html

View File

@@ -47,4 +47,4 @@ Gerrit Pape (pape@smarden.org) wrote this manual page.
.SH SEE ALSO
dropbear(8), dbclient(1)
.P
http://matt.ucc.asn.au/dropbear/dropbear.html
https://matt.ucc.asn.au/dropbear/dropbear.html

View File

@@ -23,7 +23,7 @@
* SOFTWARE. */
/* The format of the keyfiles is basically a raw dump of the buffer. Data types
* are specified in the transport draft - string is a 32-bit len then the
* are specified in the transport rfc 4253 - string is a 32-bit len then the
* non-null-terminated string, mp_int is a 32-bit len then the bignum data.
* The actual functions are buf_put_rsa_priv_key() and buf_put_dss_priv_key()
@@ -65,7 +65,6 @@ static void justprintpub(const char* filename);
static void printhelp(char * progname) {
fprintf(stderr, "Usage: %s -t <type> -f <filename> [-s bits]\n"
"Options are:\n"
"-t type Type of key to generate. One of:\n"
#ifdef DROPBEAR_RSA
" rsa\n"

104
dss.c
View File

@@ -43,7 +43,7 @@
* The key will have the same format as buf_put_dss_key.
* These should be freed with dss_key_free.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_get_dss_pub_key(buffer* buf, dss_key *key) {
int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
TRACE(("enter buf_get_dss_pub_key"))
dropbear_assert(key != NULL);
@@ -76,7 +76,7 @@ int buf_get_dss_pub_key(buffer* buf, dss_key *key) {
/* Same as buf_get_dss_pub_key, but reads a private "x" key at the end.
* Loads a private dss key from a buffer
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_get_dss_priv_key(buffer* buf, dss_key *key) {
int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
int ret = DROPBEAR_FAILURE;
@@ -99,11 +99,11 @@ 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) {
void dss_key_free(dropbear_dss_key *key) {
TRACE(("enter dsa_key_free"))
TRACE2(("enter dsa_key_free"))
if (key == NULL) {
TRACE(("enter dsa_key_free: key == NULL"))
TRACE2(("enter dsa_key_free: key == NULL"))
return;
}
if (key->p) {
@@ -127,7 +127,7 @@ void dss_key_free(dss_key *key) {
m_free(key->x);
}
m_free(key);
TRACE(("leave dsa_key_free"))
TRACE2(("leave dsa_key_free"))
}
/* put the dss public key into the buffer in the required format:
@@ -138,7 +138,7 @@ void dss_key_free(dss_key *key) {
* mpint g
* mpint y
*/
void buf_put_dss_pub_key(buffer* buf, dss_key *key) {
void buf_put_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
dropbear_assert(key != NULL);
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
@@ -150,7 +150,7 @@ void buf_put_dss_pub_key(buffer* buf, dss_key *key) {
}
/* Same as buf_put_dss_pub_key, but with the private "x" key appended */
void buf_put_dss_priv_key(buffer* buf, dss_key *key) {
void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
dropbear_assert(key != NULL);
buf_put_dss_pub_key(buf, key);
@@ -161,7 +161,7 @@ void buf_put_dss_priv_key(buffer* buf, dss_key *key) {
#ifdef DROPBEAR_SIGNKEY_VERIFY
/* Verify a DSS signature (in buf) made on data by the key given.
* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
unsigned int len) {
unsigned char msghash[SHA1_HASH_SIZE];
@@ -258,52 +258,14 @@ out:
}
#endif /* DROPBEAR_SIGNKEY_VERIFY */
#ifdef DSS_PROTOK
/* 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;
}
#endif
/* Sign the data presented with key, writing the signature contents
* to the buffer
*
* When DSS_PROTOK is #defined:
* The alternate k generation method is based on the method used in PuTTY.
* In particular to avoid being vulnerable to attacks using flaws in random
* generation of k, we use the following:
*
* proto_k = SHA512 ( SHA512(x) || SHA160(message) )
* k = proto_k mod q
*
* Now we aren't relying on the random number generation to protect the private
* key x, which is a long term secret */
void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
* to the buffer */
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
unsigned int len) {
unsigned char msghash[SHA1_HASH_SIZE];
unsigned int writelen;
unsigned int i;
#ifdef DSS_PROTOK
unsigned char privkeyhash[SHA512_HASH_SIZE];
unsigned char *privkeytmp;
unsigned char proto_k[SHA512_HASH_SIZE];
DEF_MP_INT(dss_protok);
#endif
DEF_MP_INT(dss_k);
DEF_MP_INT(dss_m);
DEF_MP_INT(dss_temp1);
@@ -322,63 +284,39 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
m_mp_init_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
&dss_m, NULL);
#ifdef DSS_PROTOK
/* hash the privkey */
privkeytmp = mptobytes(key->x, &i);
sha512_init(&hs);
sha512_process(&hs, "the quick brown fox jumped over the lazy dog", 44);
sha512_process(&hs, privkeytmp, i);
sha512_done(&hs, privkeyhash);
m_burn(privkeytmp, i);
m_free(privkeytmp);
/* calculate proto_k */
sha512_init(&hs);
sha512_process(&hs, privkeyhash, SHA512_HASH_SIZE);
sha512_process(&hs, msghash, SHA1_HASH_SIZE);
sha512_done(&hs, proto_k);
/* generate k */
m_mp_init(&dss_protok);
bytes_to_mp(&dss_protok, proto_k, SHA512_HASH_SIZE);
if (mp_mod(&dss_protok, key->q, &dss_k) != MP_OKAY) {
dropbear_exit("dss error");
}
mp_clear(&dss_protok);
m_burn(proto_k, SHA512_HASH_SIZE);
#else /* DSS_PROTOK not defined*/
/* the random number generator's input has included the private key which
* avoids DSS's problem of private key exposure due to low entropy */
gen_random_mpint(key->q, &dss_k);
#endif
/* now generate the actual signature */
bytes_to_mp(&dss_m, msghash, SHA1_HASH_SIZE);
/* g^k mod p */
if (mp_exptmod(key->g, &dss_k, key->p, &dss_temp1) != MP_OKAY) {
dropbear_exit("dss error");
dropbear_exit("DSS error");
}
/* r = (g^k mod p) mod q */
if (mp_mod(&dss_temp1, key->q, &dss_r) != MP_OKAY) {
dropbear_exit("dss error");
dropbear_exit("DSS error");
}
/* x*r mod q */
if (mp_mulmod(&dss_r, key->x, key->q, &dss_temp1) != MP_OKAY) {
dropbear_exit("dss error");
dropbear_exit("DSS error");
}
/* (SHA1(M) + xr) mod q) */
if (mp_addmod(&dss_m, &dss_temp1, key->q, &dss_temp2) != MP_OKAY) {
dropbear_exit("dss error");
dropbear_exit("DSS error");
}
/* (k^-1) mod q */
if (mp_invmod(&dss_k, key->q, &dss_temp1) != MP_OKAY) {
dropbear_exit("dss error");
dropbear_exit("DSS error");
}
/* s = (k^-1(SHA1(M) + xr)) mod q */
if (mp_mulmod(&dss_temp1, &dss_temp2, key->q, &dss_s) != MP_OKAY) {
dropbear_exit("dss error");
dropbear_exit("DSS error");
}
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
@@ -392,7 +330,7 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
}
if (mp_to_unsigned_bin(&dss_r, buf_getwriteptr(buf, writelen))
!= MP_OKAY) {
dropbear_exit("dss error");
dropbear_exit("DSS error");
}
mp_clear(&dss_r);
buf_incrwritepos(buf, writelen);
@@ -405,7 +343,7 @@ void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
}
if (mp_to_unsigned_bin(&dss_s, buf_getwriteptr(buf, writelen))
!= MP_OKAY) {
dropbear_exit("dss error");
dropbear_exit("DSS error");
}
mp_clear(&dss_s);
buf_incrwritepos(buf, writelen);

21
dss.h
View File

@@ -32,29 +32,28 @@
#define DSS_SIGNATURE_SIZE 4+SSH_SIGNKEY_DSS_LEN+4+2*SHA1_HASH_SIZE
struct DSS_key {
typedef struct {
mp_int* p;
mp_int* q;
mp_int* g;
mp_int* y;
/* x is the private part */
mp_int* x;
};
} dropbear_dss_key;
typedef struct DSS_key dss_key;
void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
unsigned int len);
#ifdef DROPBEAR_SIGNKEY_VERIFY
int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
unsigned int len);
#endif
int buf_get_dss_pub_key(buffer* buf, dss_key *key);
int buf_get_dss_priv_key(buffer* buf, dss_key *key);
void buf_put_dss_pub_key(buffer* buf, dss_key *key);
void buf_put_dss_priv_key(buffer* buf, dss_key *key);
void dss_key_free(dss_key *key);
int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key);
int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key);
void buf_put_dss_pub_key(buffer* buf, dropbear_dss_key *key);
void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key);
void dss_key_free(dropbear_dss_key *key);
#endif /* DROPBEAR_DSS */

View File

@@ -1,7 +1,6 @@
/* Taken for Dropbear from OpenSSH 5.5p1 */
/*
*
* Taken from OpenSSH 3.8.1p1
*
* Copyright (C) 2000-2003 Damien Miller. All rights reserved.
* Copyright (C) 1999 WIDE Project. All rights reserved.
*
@@ -40,7 +39,11 @@
#include "includes.h"
/* RCSID("$.Id: fake-rfc2553.c,v 1.5 2003/09/22 02:08:23 dtucker Exp $");*/
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifndef HAVE_GETNAMEINFO
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
@@ -50,6 +53,8 @@ int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
struct hostent *hp;
char tmpserv[16];
if (sa->sa_family != AF_UNSPEC && sa->sa_family != AF_INET)
return (EAI_FAMILY);
if (serv != NULL) {
snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
if (strlcpy(serv, tmpserv, servlen) >= servlen)
@@ -94,6 +99,8 @@ gai_strerror(int err)
return ("memory allocation failure.");
case EAI_NONAME:
return ("nodename nor servname provided, or not known");
case EAI_FAMILY:
return ("ai_family not supported");
default:
return ("unknown/invalid error.");
}
@@ -158,6 +165,9 @@ getaddrinfo(const char *hostname, const char *servname,
u_long addr;
port = 0;
if (hints && hints->ai_family != AF_UNSPEC &&
hints->ai_family != AF_INET)
return (EAI_FAMILY);
if (servname != NULL) {
char *cp;

View File

@@ -1,6 +1,6 @@
/* Taken from OpenSSH 3.8.1p1 */
/* Taken for Dropbear from OpenSSH 5.5p1 */
/* $.Id: fake-rfc2553.h,v 1.9 2004/03/10 10:06:33 dtucker Exp $ */
/* $Id: fake-rfc2553.h,v 1.16 2008/07/14 11:37:37 djm Exp $ */
/*
* Copyright (C) 2000-2003 Damien Miller. All rights reserved.
@@ -43,6 +43,10 @@
#define _FAKE_RFC2553_H
#include "includes.h"
#include <sys/types.h>
#if defined(HAVE_NETDB_H)
# include <netdb.h>
#endif
/*
* First, socket and INET6 related definitions
@@ -75,6 +79,7 @@ struct sockaddr_in6 {
u_int16_t sin6_port;
u_int32_t sin6_flowinfo;
struct in6_addr sin6_addr;
u_int32_t sin6_scope_id;
};
#endif /* !HAVE_STRUCT_SOCKADDR_IN6 */
@@ -115,9 +120,19 @@ struct sockaddr_in6 {
#endif /* !NI_MAXHOST */
#ifndef EAI_NODATA
# define EAI_NODATA 1
# define EAI_MEMORY 2
# define EAI_NONAME 3
# define EAI_NODATA (INT_MAX - 1)
#endif
#ifndef EAI_MEMORY
# define EAI_MEMORY (INT_MAX - 2)
#endif
#ifndef EAI_NONAME
# define EAI_NONAME (INT_MAX - 3)
#endif
#ifndef EAI_SYSTEM
# define EAI_SYSTEM (INT_MAX - 4)
#endif
#ifndef EAI_FAMILY
# define EAI_FAMILY (INT_MAX - 5)
#endif
#ifndef HAVE_STRUCT_ADDRINFO
@@ -143,7 +158,7 @@ int getaddrinfo(const char *, const char *,
#endif /* !HAVE_GETADDRINFO */
#if !defined(HAVE_GAI_STRERROR) && !defined(HAVE_CONST_GAI_STRERROR_PROTO)
#define gai_strerror(a) (ssh_gai_strerror(a))
#define gai_strerror(a) (_ssh_compat_gai_strerror(a))
char *gai_strerror(int);
#endif /* !HAVE_GAI_STRERROR */

View File

@@ -37,17 +37,17 @@
#ifdef DROPBEAR_DSS
static void getq(dss_key *key);
static void getp(dss_key *key, unsigned int size);
static void getg(dss_key *key);
static void getx(dss_key *key);
static void gety(dss_key *key);
static void getq(dropbear_dss_key *key);
static void getp(dropbear_dss_key *key, unsigned int size);
static void getg(dropbear_dss_key *key);
static void getx(dropbear_dss_key *key);
static void gety(dropbear_dss_key *key);
dss_key * gen_dss_priv_key(unsigned int size) {
dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
dss_key *key;
dropbear_dss_key *key;
key = (dss_key*)m_malloc(sizeof(dss_key));
key = m_malloc(sizeof(*key));
key->p = (mp_int*)m_malloc(sizeof(mp_int));
key->q = (mp_int*)m_malloc(sizeof(mp_int));
@@ -68,7 +68,7 @@ dss_key * gen_dss_priv_key(unsigned int size) {
}
static void getq(dss_key *key) {
static void getq(dropbear_dss_key *key) {
char buf[QSIZE];
@@ -81,12 +81,12 @@ static void getq(dss_key *key) {
/* 18 rounds are required according to HAC */
if (mp_prime_next_prime(key->q, 18, 0) != MP_OKAY) {
fprintf(stderr, "dss key generation failed\n");
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
}
static void getp(dss_key *key, unsigned int size) {
static void getp(dropbear_dss_key *key, unsigned int size) {
DEF_MP_INT(tempX);
DEF_MP_INT(tempC);
@@ -100,7 +100,7 @@ static void getp(dss_key *key, unsigned int size) {
/* 2*q */
if (mp_mul_d(key->q, 2, &temp2q) != MP_OKAY) {
fprintf(stderr, "dss key generation failed\n");
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
@@ -117,25 +117,25 @@ static void getp(dss_key *key, unsigned int size) {
/* C = X mod 2q */
if (mp_mod(&tempX, &temp2q, &tempC) != MP_OKAY) {
fprintf(stderr, "dss key generation failed\n");
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
/* P = X - (C - 1) = X - C + 1*/
if (mp_sub(&tempX, &tempC, &tempP) != MP_OKAY) {
fprintf(stderr, "dss key generation failed\n");
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
if (mp_add_d(&tempP, 1, key->p) != MP_OKAY) {
fprintf(stderr, "dss key generation failed\n");
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
/* now check for prime, 5 rounds is enough according to HAC */
/* result == 1 => p is prime */
if (mp_prime_is_prime(key->p, 5, &result) != MP_OKAY) {
fprintf(stderr, "dss key generation failed\n");
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
} while (!result);
@@ -145,7 +145,7 @@ static void getp(dss_key *key, unsigned int size) {
m_free(buf);
}
static void getg(dss_key * key) {
static void getg(dropbear_dss_key * key) {
DEF_MP_INT(div);
DEF_MP_INT(h);
@@ -155,11 +155,11 @@ static void getg(dss_key * key) {
/* get div=(p-1)/q */
if (mp_sub_d(key->p, 1, &val) != MP_OKAY) {
fprintf(stderr, "dss key generation failed\n");
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
if (mp_div(&val, key->q, &div, NULL) != MP_OKAY) {
fprintf(stderr, "dss key generation failed\n");
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
@@ -168,12 +168,12 @@ static void getg(dss_key * key) {
do {
/* now keep going with g=h^div mod p, until g > 1 */
if (mp_exptmod(&h, &div, key->p, key->g) != MP_OKAY) {
fprintf(stderr, "dss key generation failed\n");
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
if (mp_add_d(&h, 1, &h) != MP_OKAY) {
fprintf(stderr, "dss key generation failed\n");
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
@@ -182,15 +182,15 @@ static void getg(dss_key * key) {
mp_clear_multi(&div, &h, &val, NULL);
}
static void getx(dss_key *key) {
static void getx(dropbear_dss_key *key) {
gen_random_mpint(key->q, key->x);
}
static void gety(dss_key *key) {
static void gety(dropbear_dss_key *key) {
if (mp_exptmod(key->g, key->x, key->p, key->y) != MP_OKAY) {
fprintf(stderr, "dss key generation failed\n");
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
}

View File

@@ -29,7 +29,7 @@
#ifdef DROPBEAR_DSS
dss_key * gen_dss_priv_key(unsigned int size);
dropbear_dss_key * gen_dss_priv_key(unsigned int size);
#endif /* DROPBEAR_DSS */

View File

@@ -37,14 +37,14 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
mp_int* rsa_e, unsigned int size);
/* mostly taken from libtomcrypt's rsa key generation routine */
rsa_key * gen_rsa_priv_key(unsigned int size) {
dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
rsa_key * key;
dropbear_rsa_key * key;
DEF_MP_INT(pminus);
DEF_MP_INT(qminus);
DEF_MP_INT(lcm);
key = (rsa_key*)m_malloc(sizeof(rsa_key));
key = m_malloc(sizeof(*key));
key->e = (mp_int*)m_malloc(sizeof(mp_int));
key->n = (mp_int*)m_malloc(sizeof(mp_int));
@@ -58,7 +58,7 @@ rsa_key * gen_rsa_priv_key(unsigned int size) {
seedrandom();
if (mp_set_int(key->e, RSA_E) != MP_OKAY) {
fprintf(stderr, "rsa generation failed\n");
fprintf(stderr, "RSA generation failed\n");
exit(1);
}
@@ -66,20 +66,20 @@ rsa_key * gen_rsa_priv_key(unsigned int size) {
getrsaprime(key->q, &qminus, key->e, size/2);
if (mp_mul(key->p, key->q, key->n) != MP_OKAY) {
fprintf(stderr, "rsa generation failed\n");
fprintf(stderr, "RSA generation failed\n");
exit(1);
}
/* lcm(p-1, q-1) */
if (mp_lcm(&pminus, &qminus, &lcm) != MP_OKAY) {
fprintf(stderr, "rsa generation failed\n");
fprintf(stderr, "RSA generation failed\n");
exit(1);
}
/* de = 1 mod lcm(p-1,q-1) */
/* therefore d = (e^-1) mod lcm(p-1,q-1) */
if (mp_invmod(key->e, &lcm, key->d) != MP_OKAY) {
fprintf(stderr, "rsa generation failed\n");
fprintf(stderr, "RSA generation failed\n");
exit(1);
}
@@ -108,18 +108,18 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
/* find the next integer which is prime, 8 round of miller-rabin */
if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) {
fprintf(stderr, "rsa generation failed\n");
fprintf(stderr, "RSA generation failed\n");
exit(1);
}
/* subtract one to get p-1 */
if (mp_sub_d(prime, 1, primeminus) != MP_OKAY) {
fprintf(stderr, "rsa generation failed\n");
fprintf(stderr, "RSA generation failed\n");
exit(1);
}
/* check relative primality to e */
if (mp_gcd(primeminus, rsa_e, &temp_gcd) != MP_OKAY) {
fprintf(stderr, "rsa generation failed\n");
fprintf(stderr, "RSA generation failed\n");
exit(1);
}
} while (mp_cmp_d(&temp_gcd, 1) != MP_EQ); /* while gcd(p-1, e) != 1 */

View File

@@ -29,7 +29,7 @@
#ifdef DROPBEAR_RSA
rsa_key * gen_rsa_priv_key(unsigned int size);
dropbear_rsa_key * gen_rsa_priv_key(unsigned int size);
#endif /* DROPBEAR_RSA */

View File

@@ -120,8 +120,18 @@
#include <libgen.h>
#endif
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
#ifdef BUNDLED_LIBTOM
#include "libtomcrypt/src/headers/tomcrypt.h"
#include "libtommath/tommath.h"
#else
#include <tomcrypt.h>
#include <tommath.h>
#endif
#include "compat.h"
#include "fake-rfc2553.h"

9
kex.h
View File

@@ -51,19 +51,22 @@ struct KEXState {
unsigned sentkexinit : 1; /*set when we've sent/recv kexinit packet */
unsigned recvkexinit : 1;
unsigned firstfollows : 1; /* true when first_kex_packet_follows is set */
unsigned sentnewkeys : 1; /* set once we've send/recv'ed MSG_NEWKEYS*/
unsigned recvnewkeys : 1;
unsigned them_firstfollows : 1; /* true when first_kex_packet_follows is set */
unsigned sentnewkeys : 1; /* set once we've send MSG_NEWKEYS (will be cleared once we have also received */
unsigned recvnewkeys : 1; /* set once we've received MSG_NEWKEYS (cleared once we have also sent */
unsigned donefirstkex : 1; /* Set to 1 after the first kex has completed,
ie the transport layer has been set up */
unsigned our_first_follows_matches : 1;
time_t lastkextime; /* time of the last kex */
unsigned int datatrans; /* data transmitted since last kex */
unsigned int datarecv; /* data received since last kex */
};
#define MAX_KEXHASHBUF 2000
#endif /* _KEX_H_ */

View File

@@ -78,7 +78,7 @@
/* #define LTC_CLEAN_STACK */
/* disable all file related functions */
/* #define LTC_NO_FILE */
#define LTC_NO_FILE
/* disable all forms of ASM */
/* #define LTC_NO_ASM */
@@ -118,16 +118,20 @@
#define LTC_CTR_MODE
#endif
#if defined(DROPBEAR_DSS) && defined(DSS_PROTOK)
#define SHA512
#endif
#define SHA1
#ifdef DROPBEAR_MD5_HMAC
#ifdef DROPBEAR_MD5
#define MD5
#endif
#ifdef DROPBEAR_SHA256
#define SHA256
#endif
#ifdef DROPBEAR_SHA512
#define SHA512
#endif
#define LTC_HMAC
/* Various tidbits of modern neatoness */

View File

@@ -170,8 +170,8 @@ clean:
rm -f *.bat *.pdf *.o *.a *.obj *.lib *.exe *.dll etclib/*.o demo/demo.o test ltmtest mpitest mtest/mtest mtest/mtest.exe \
*.idx *.toc *.log *.aux *.dvi *.lof *.ind *.ilg *.ps *.log *.s mpi.c *.da *.dyn *.dpi tommath.tex `find . -type f | grep [~] | xargs` *.lo *.la
rm -rf .libs
cd etc ; MAKE=${MAKE} ${MAKE} clean
cd pics ; MAKE=${MAKE} ${MAKE} clean
-cd etc && MAKE=${MAKE} ${MAKE} clean
-cd pics && MAKE=${MAKE} ${MAKE} clean
#zipup the project (take that!)
no_oops: clean

View File

@@ -67,13 +67,13 @@ int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode
/* init M array */
/* init first cell */
if ((err = mp_init(&M[1])) != MP_OKAY) {
if ((err = mp_init_size(&M[1], P->alloc)) != MP_OKAY) {
return err;
}
/* now init the second half of the array */
for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
if ((err = mp_init(&M[x])) != MP_OKAY) {
if ((err = mp_init_size(&M[x], P->alloc)) != MP_OKAY) {
for (y = 1<<(winsize-1); y < x; y++) {
mp_clear (&M[y]);
}
@@ -133,7 +133,7 @@ int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode
}
/* setup result */
if ((err = mp_init (&res)) != MP_OKAY) {
if ((err = mp_init_size (&res, P->alloc)) != MP_OKAY) {
goto LBL_M;
}

View File

@@ -20,7 +20,7 @@ int mp_init_copy (mp_int * a, mp_int * b)
{
int res;
if ((res = mp_init (a)) != MP_OKAY) {
if ((res = mp_init_size (a, b->used)) != MP_OKAY) {
return res;
}
return mp_copy (b, a);

View File

@@ -22,7 +22,7 @@ mp_mod (mp_int * a, mp_int * b, mp_int * c)
mp_int t;
int res;
if ((res = mp_init (&t)) != MP_OKAY) {
if ((res = mp_init_size (&t, b->used)) != MP_OKAY) {
return res;
}

View File

@@ -21,7 +21,7 @@ int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
int res;
mp_int t;
if ((res = mp_init (&t)) != MP_OKAY) {
if ((res = mp_init_size (&t, c->used)) != MP_OKAY) {
return res;
}

View File

@@ -143,7 +143,7 @@ int mp_prime_next_prime(mp_int *a, int t, int bbs_style)
/* is this prime? */
for (x = 0; x < t; x++) {
mp_set(&b, ltm_prime_tab[t]);
mp_set(&b, ltm_prime_tab[x]);
if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
goto LBL_ERR;
}

49
list.c Normal file
View File

@@ -0,0 +1,49 @@
#include "options.h"
#include "dbutil.h"
#include "list.h"
void list_append(m_list *list, void *item) {
m_list_elem *elem;
elem = m_malloc(sizeof(*elem));
elem->item = item;
elem->list = list;
elem->next = NULL;
if (!list->first) {
list->first = elem;
elem->prev = NULL;
} else {
elem->prev = list->last;
list->last->next = elem;
}
list->last = elem;
}
m_list * list_new() {
m_list *ret = m_malloc(sizeof(m_list));
ret->first = ret->last = NULL;
return ret;
}
void * list_remove(m_list_elem *elem) {
void *item = elem->item;
m_list *list = elem->list;
if (list->first == elem)
{
list->first = elem->next;
}
if (list->last == elem)
{
list->last = elem->prev;
}
if (elem->prev)
{
elem->prev->next = elem->next;
}
if (elem->next)
{
elem->next->prev = elem->prev;
}
m_free(elem);
return item;
}

28
list.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef _DROPBEAR_LIST_H
#define _DROPBEAR_LIST_H
struct _m_list;
struct _m_list_elem {
void *item;
struct _m_list_elem *next;
struct _m_list_elem *prev;
struct _m_list *list;
};
typedef struct _m_list_elem m_list_elem;
struct _m_list {
m_list_elem *first;
m_list_elem *last;
};
typedef struct _m_list m_list;
m_list * list_new();
void list_append(m_list *list, void *item);
/* returns the item for the element removed */
void * list_remove(m_list_elem *elem);
#endif /* _DROPBEAR_LIST_H */

View File

@@ -329,8 +329,6 @@ login_write (struct logininfo *li)
{
#ifndef HAVE_CYGWIN
if ((int)geteuid() != 0) {
dropbear_log(LOG_WARNING,
"Attempt to write login records by non-root user (aborting)");
return 1;
}
#endif

View File

@@ -46,9 +46,10 @@
/*#define NO_FAST_EXPTMOD*/
/* Set this if you want to use the DROPBEAR_SMALL_CODE option. This can save
several kB in binary size, however will make the symmetrical ciphers (AES, DES
etc) slower (perhaps by 50%). Recommended for most small systems. */
#define DROPBEAR_SMALL_CODE
several kB in binary size however will make the symmetrical ciphers and hashes
slower, perhaps by 50%. Recommended for small systems that aren't doing
much traffic. */
/*#define DROPBEAR_SMALL_CODE*/
/* Enable X11 Forwarding - server only */
#define ENABLE_X11FWD
@@ -63,8 +64,9 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
#define ENABLE_SVR_LOCALTCPFWD
#define ENABLE_SVR_REMOTETCPFWD
/* Enable Authentication Agent Forwarding - server only for now */
#define ENABLE_AGENTFWD
/* Enable Authentication Agent Forwarding */
#define ENABLE_SVR_AGENTFWD
#define ENABLE_CLI_AGENTFWD
/* Note: Both ENABLE_CLI_PROXYCMD and ENABLE_CLI_NETCAT must be set to
@@ -78,6 +80,9 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
* to a remote TCP-forwarded connection */
#define ENABLE_CLI_NETCAT
/* Whether to support "-c" and "-m" flags to choose ciphers/MACs at runtime */
#define ENABLE_USER_ALGO_LIST
/* Encryption - at least one required.
* Protocol RFC requires 3DES and recommends AES128 for interoperability.
* Including multiple keysize variants the same cipher
@@ -85,7 +90,8 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
#define DROPBEAR_AES128
#define DROPBEAR_3DES
#define DROPBEAR_AES256
#define DROPBEAR_BLOWFISH
/* Compiling in Blowfish will add ~6kB to runtime heap memory usage */
/*#define DROPBEAR_BLOWFISH*/
#define DROPBEAR_TWOFISH256
#define DROPBEAR_TWOFISH128
@@ -94,12 +100,18 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
* size and is recommended for most cases */
#define DROPBEAR_ENABLE_CTR_MODE
/* You can compile with no encryption if you want. In some circumstances
* this could be safe security-wise, though make sure you know what
* you're doing. Anyone can see everything that goes over the wire, so
* the only safe auth method is public key. */
/* #define DROPBEAR_NONE_CIPHER */
/* Message Integrity - at least one required.
* Protocol RFC requires sha1 and recommends sha1-96.
* sha1-96 may be of use for slow links, as it has a smaller overhead.
* sha1-96 is of use for slow links as it has a smaller overhead.
*
* Note: there's no point disabling sha1 to save space, since it's used
* for the random number generator and public-key cryptography anyway.
* There's no reason to disable sha1 or sha1-96 to save space since it's
* used for the random number generator and public-key cryptography anyway.
* Disabling it here will just stop it from being used as the integrity portion
* of the ssh protocol.
*
@@ -108,8 +120,15 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
* which are not the standard form. */
#define DROPBEAR_SHA1_HMAC
#define DROPBEAR_SHA1_96_HMAC
/*#define DROPBEAR_SHA2_256_HMAC*/
/*#define DROPBEAR_SHA2_512_HMAC*/
#define DROPBEAR_MD5_HMAC
/* You can also disable integrity. Don't bother disabling this if you're
* still using a cipher, it's relatively cheap. If you disable this it's dead
* simple to run arbitrary commands on the remote host. Beware. */
/* #define DROPBEAR_NONE_INTEGRITY */
/* Hostkey/public key algorithms - at least one required, these are used
* for hostkey as well as for verifying signatures with pubkey auth.
* Removing either of these won't save very much space.
@@ -122,14 +141,19 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
* signing operations slightly slower. */
#define RSA_BLINDING
/* Define DSS_PROTOK to use PuTTY's method of generating the value k for dss,
* rather than just from the random byte source. Undefining this will save you
* ~4k in binary size with static uclibc, but your DSS hostkey could be exposed
* if the random number source isn't good. In general this isn't required */
/* #define DSS_PROTOK */
/* Control the memory/performance/compression tradeoff for zlib.
* Set windowBits=8 for least memory usage, see your system's
* zlib.h for full details.
* Default settings (windowBits=15) will use 256kB for compression
* windowBits=8 will use 129kB for compression.
* Both modes will use ~35kB for decompression (using windowBits=15 for
* interoperability) */
#ifndef DROPBEAR_ZLIB_WINDOW_BITS
#define DROPBEAR_ZLIB_WINDOW_BITS 15
#endif
/* Whether to do reverse DNS lookups. */
#define DO_HOST_LOOKUP
//#define DO_HOST_LOOKUP
/* Whether to print the message of the day (MOTD). This doesn't add much code
* size */
@@ -143,18 +167,20 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
/* 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
/* 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.
* It's useful for systems like OS X where standard password crypts don't work
* but there's an interface via a PAM module. It won't work for more complex
* PAM challenge/response.
* You can't enable both PASSWORD and PAM. */
#define ENABLE_SVR_PASSWORD_AUTH
/* PAM requires ./configure --enable-pam */
/*#define ENABLE_SVR_PAM_AUTH*/
//#define ENABLE_SVR_PAM_AUTH
#define ENABLE_SVR_PUBKEY_AUTH
/* Wether to ake public key options in authorized_keys file into account */
/* Whether to take public key options in
* authorized_keys file into account */
#ifdef ENABLE_SVR_PUBKEY_AUTH
#define ENABLE_SVR_PUBKEY_OPTIONS
#endif
@@ -178,21 +204,22 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
* return the password on standard output */
/*#define ENABLE_CLI_ASKPASS_HELPER*/
/* 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). */
/* Send a real auth request first rather than requesting a list of available methods.
* It saves a network round trip at login but prevents immediate login to
* accounts with no password, and might be rejected by some strict servers (none
* encountered yet) - hence it isn't enabled by default. */
/* #define CLI_IMMEDIATE_AUTH */
/* We'll use /dev/urandom by default, since /dev/random is too much hassle.
* If system developers aren't keeping seeds between boots nor getting
* any entropy from somewhere it's their own fault. */
#define DROPBEAR_RANDOM_DEV "/dev/urandom"
/* prngd must be manually set up to produce output */
/* Source for randomness. This must be able to provide hundreds of bytes per SSH
* connection without blocking. In addition /dev/random is used for seeding
* rsa/dss key generation */
#define DROPBEAR_URANDOM_DEV "/dev/urandom"
/* Set this to use PRNGD or EGD instead of /dev/urandom or /dev/random */
/*#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 */
/* The first setting is per-IP, to avoid denial of service */
@@ -220,7 +247,7 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
/* The command to invoke for xauth when using X11 forwarding.
* "-q" for quiet */
#ifndef XAUTH_COMMAND
#define XAUTH_COMMAND "/usr/X11R6/bin/xauth -q"
#define XAUTH_COMMAND "/usr/bin/X11/xauth -q"
#endif
/* if you want to enable running an sftp server (such as the one included with
@@ -246,13 +273,19 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
significant difference to network performance. 24kB was empirically
chosen for a 100mbit ethernet network. The value can be altered at
runtime with the -W argument. */
#ifndef DEFAULT_RECV_WINDOW
#define DEFAULT_RECV_WINDOW 24576
#endif
/* Maximum size of a received SSH data packet - this _MUST_ be >= 32768
in order to interoperate with other implementations */
#ifndef RECV_MAX_PAYLOAD_LEN
#define RECV_MAX_PAYLOAD_LEN 32768
#endif
/* Maximum size of a transmitted data packet - this can be any value,
though increasing it may not make a significant difference. */
#ifndef TRANS_MAX_PAYLOAD_LEN
#define TRANS_MAX_PAYLOAD_LEN 16384
#endif
/* Ensure that data is transmitted every KEEPALIVE seconds. This can
be overridden at runtime with -K. 0 disables keepalives */

492
packet.c
View File

@@ -35,11 +35,13 @@
#include "auth.h"
#include "channel.h"
static void read_packet_init();
static void writemac(buffer * outputbuffer, buffer * clearwritebuf);
static int checkmac(buffer* hashbuf, buffer* readbuf);
static int read_packet_init();
static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
buffer * clear_buf, unsigned int clear_len,
unsigned char *output_mac);
static int checkmac();
#define ZLIB_COMPRESS_INCR 20 /* this is 12 bytes + 0.1% of 8000 bytes */
#define ZLIB_COMPRESS_INCR 100
#define ZLIB_DECOMPRESS_INCR 100
#ifndef DISABLE_ZLIB
static buffer* buf_decompress(buffer* buf, unsigned int len);
@@ -51,29 +53,84 @@ void write_packet() {
int len, written;
buffer * writebuf = NULL;
time_t now;
unsigned packet_type;
int all_ignore = 1;
#ifdef HAVE_WRITEV
struct iovec *iov = NULL;
int i;
struct Link *l;
#endif
TRACE(("enter write_packet"))
TRACE2(("enter write_packet"))
dropbear_assert(!isempty(&ses.writequeue));
#ifdef HAVE_WRITEV
iov = m_malloc(sizeof(*iov) * ses.writequeue.count);
for (l = ses.writequeue.head, i = 0; l; l = l->link, i++)
{
writebuf = (buffer*)l->item;
packet_type = writebuf->data[writebuf->len-1];
len = writebuf->len - 1 - writebuf->pos;
dropbear_assert(len > 0);
all_ignore &= (packet_type == SSH_MSG_IGNORE);
TRACE2(("write_packet writev #%d type %d len %d/%d", i, packet_type,
len, writebuf->len-1))
iov[i].iov_base = buf_getptr(writebuf, len);
iov[i].iov_len = len;
}
written = writev(ses.sock_out, iov, ses.writequeue.count);
if (written < 0) {
if (errno == EINTR) {
m_free(iov);
TRACE2(("leave writepacket: EINTR"))
return;
} else {
dropbear_exit("Error writing");
}
}
if (written == 0) {
ses.remoteclosed();
}
while (written > 0) {
writebuf = (buffer*)examine(&ses.writequeue);
len = writebuf->len - 1 - writebuf->pos;
if (len > written) {
// partial buffer write
buf_incrpos(writebuf, written);
written = 0;
} else {
written -= len;
dequeue(&ses.writequeue);
buf_free(writebuf);
}
}
m_free(iov);
#else
/* Get the next buffer in the queue of encrypted packets to write*/
writebuf = (buffer*)examine(&ses.writequeue);
len = writebuf->len - writebuf->pos;
/* The last byte of the buffer is not to be transmitted, but is
* a cleartext packet_type indicator */
packet_type = writebuf->data[writebuf->len-1];
len = writebuf->len - 1 - writebuf->pos;
dropbear_assert(len > 0);
/* Try to write as much as possible */
written = write(ses.sock_out, buf_getptr(writebuf, len), len);
if (written < 0) {
if (errno == EINTR) {
TRACE(("leave writepacket: EINTR"))
TRACE2(("leave writepacket: EINTR"))
return;
} else {
dropbear_exit("error writing");
dropbear_exit("Error writing");
}
}
ses.last_trx_packet_time = time(NULL);
ses.last_packet_time = time(NULL);
all_ignore = (packet_type == SSH_MSG_IGNORE);
if (written == 0) {
ses.remoteclosed();
@@ -89,7 +146,15 @@ void write_packet() {
buf_incrpos(writebuf, written);
}
TRACE(("leave write_packet"))
#endif
now = time(NULL);
ses.last_trx_packet_time = now;
if (!all_ignore) {
ses.last_packet_time = now;
}
TRACE2(("leave write_packet"))
}
/* Non-blocking function reading available portion of a packet into the
@@ -101,44 +166,50 @@ void read_packet() {
unsigned int maxlen;
unsigned char blocksize;
TRACE(("enter read_packet"))
blocksize = ses.keys->recv_algo_crypt->blocksize;
TRACE2(("enter read_packet"))
blocksize = ses.keys->recv.algo_crypt->blocksize;
if (ses.readbuf == NULL || ses.readbuf->len < blocksize) {
int ret;
/* In the first blocksize of a packet */
/* Read the first blocksize of the packet, so we can decrypt it and
* find the length of the whole packet */
read_packet_init();
ret = read_packet_init();
/* If we don't have the length of decryptreadbuf, we didn't read
* a whole blocksize and should exit */
if (ses.decryptreadbuf->len == 0) {
TRACE(("leave read_packet: packetinit done"))
if (ret == DROPBEAR_FAILURE) {
/* didn't read enough to determine the length */
TRACE2(("leave read_packet: packetinit done"))
return;
}
}
/* Attempt to read the remainder of the packet, note that there
* mightn't be any available (EAGAIN) */
dropbear_assert(ses.readbuf != NULL);
maxlen = ses.readbuf->len - ses.readbuf->pos;
len = read(ses.sock_in, buf_getptr(ses.readbuf, maxlen), maxlen);
if (maxlen == 0) {
/* Occurs when the packet is only a single block long and has all
* been read in read_packet_init(). Usually means that MAC is disabled
*/
len = 0;
} else {
len = read(ses.sock_in, buf_getptr(ses.readbuf, maxlen), maxlen);
if (len == 0) {
ses.remoteclosed();
}
if (len < 0) {
if (errno == EINTR || errno == EAGAIN) {
TRACE(("leave read_packet: EINTR or EAGAIN"))
return;
} else {
dropbear_exit("error reading: %s", strerror(errno));
if (len == 0) {
ses.remoteclosed();
}
}
buf_incrpos(ses.readbuf, len);
if (len < 0) {
if (errno == EINTR || errno == EAGAIN) {
TRACE2(("leave read_packet: EINTR or EAGAIN"))
return;
} else {
dropbear_exit("Error reading: %s", strerror(errno));
}
}
buf_incrpos(ses.readbuf, len);
}
if ((unsigned int)len == maxlen) {
/* The whole packet has been read */
@@ -146,76 +217,80 @@ void read_packet() {
/* The main select() loop process_packet() to
* handle the packet contents... */
}
TRACE(("leave read_packet"))
TRACE2(("leave read_packet"))
}
/* Function used to read the initial portion of a packet, and determine the
* length. Only called during the first BLOCKSIZE of a packet. */
static void read_packet_init() {
/* Returns DROPBEAR_SUCCESS if the length is determined,
* DROPBEAR_FAILURE otherwise */
static int read_packet_init() {
unsigned int maxlen;
int len;
unsigned char blocksize;
unsigned char macsize;
int slen;
unsigned int len;
unsigned int blocksize;
unsigned int macsize;
blocksize = ses.keys->recv_algo_crypt->blocksize;
macsize = ses.keys->recv_algo_mac->hashsize;
blocksize = ses.keys->recv.algo_crypt->blocksize;
macsize = ses.keys->recv.algo_mac->hashsize;
if (ses.readbuf == NULL) {
/* start of a new packet */
ses.readbuf = buf_new(INIT_READBUF);
dropbear_assert(ses.decryptreadbuf == NULL);
ses.decryptreadbuf = buf_new(blocksize);
}
maxlen = blocksize - ses.readbuf->pos;
/* read the rest of the packet if possible */
len = read(ses.sock_in, buf_getwriteptr(ses.readbuf, maxlen),
slen = read(ses.sock_in, buf_getwriteptr(ses.readbuf, maxlen),
maxlen);
if (len == 0) {
if (slen == 0) {
ses.remoteclosed();
}
if (len < 0) {
if (slen < 0) {
if (errno == EINTR) {
TRACE(("leave read_packet_init: EINTR"))
return;
TRACE2(("leave read_packet_init: EINTR"))
return DROPBEAR_FAILURE;
}
dropbear_exit("error reading: %s", strerror(errno));
dropbear_exit("Error reading: %s", strerror(errno));
}
buf_incrwritepos(ses.readbuf, len);
buf_incrwritepos(ses.readbuf, slen);
if ((unsigned int)len != maxlen) {
if ((unsigned int)slen != maxlen) {
/* don't have enough bytes to determine length, get next time */
return;
return DROPBEAR_FAILURE;
}
/* now we have the first block, need to get packet length, so we decrypt
* the first block (only need first 4 bytes) */
buf_setpos(ses.readbuf, 0);
if (ses.keys->recv_crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize),
buf_getwriteptr(ses.decryptreadbuf,blocksize),
if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize),
buf_getwriteptr(ses.readbuf, blocksize),
blocksize,
&ses.keys->recv_cipher_state) != CRYPT_OK) {
dropbear_exit("error decrypting");
&ses.keys->recv.cipher_state) != CRYPT_OK) {
dropbear_exit("Error decrypting");
}
buf_setlen(ses.decryptreadbuf, blocksize);
len = buf_getint(ses.decryptreadbuf) + 4 + macsize;
len = buf_getint(ses.readbuf) + 4 + macsize;
TRACE2(("packet size is %d, block %d mac %d", len, blocksize, macsize))
buf_setpos(ses.readbuf, blocksize);
/* check packet length */
if ((len > RECV_MAX_PACKET_LEN) ||
(len < MIN_PACKET_LEN + macsize) ||
((len - macsize) % blocksize != 0)) {
dropbear_exit("bad packet size %d", len);
dropbear_exit("Integrity error (bad packet size %d)", len);
}
buf_resize(ses.readbuf, len);
if (len > ses.readbuf->size) {
buf_resize(ses.readbuf, len);
}
buf_setlen(ses.readbuf, len);
buf_setpos(ses.readbuf, blocksize);
return DROPBEAR_SUCCESS;
}
/* handle the received packet */
@@ -226,120 +301,82 @@ void decrypt_packet() {
unsigned int padlen;
unsigned int len;
TRACE(("enter decrypt_packet"))
blocksize = ses.keys->recv_algo_crypt->blocksize;
macsize = ses.keys->recv_algo_mac->hashsize;
TRACE2(("enter decrypt_packet"))
blocksize = ses.keys->recv.algo_crypt->blocksize;
macsize = ses.keys->recv.algo_mac->hashsize;
ses.kexstate.datarecv += ses.readbuf->len;
/* we've already decrypted the first blocksize in read_packet_init */
buf_setpos(ses.readbuf, blocksize);
buf_resize(ses.decryptreadbuf, ses.readbuf->len - macsize);
buf_setlen(ses.decryptreadbuf, ses.decryptreadbuf->size);
buf_setpos(ses.decryptreadbuf, blocksize);
/* decrypt it */
while (ses.readbuf->pos < ses.readbuf->len - macsize) {
if (ses.keys->recv_crypt_mode->decrypt(
buf_getptr(ses.readbuf, blocksize),
buf_getwriteptr(ses.decryptreadbuf, blocksize),
blocksize,
&ses.keys->recv_cipher_state) != CRYPT_OK) {
dropbear_exit("error decrypting");
}
buf_incrpos(ses.readbuf, blocksize);
buf_incrwritepos(ses.decryptreadbuf, blocksize);
/* decrypt it in-place */
len = ses.readbuf->len - macsize - ses.readbuf->pos;
if (ses.keys->recv.crypt_mode->decrypt(
buf_getptr(ses.readbuf, len),
buf_getwriteptr(ses.readbuf, len),
len,
&ses.keys->recv.cipher_state) != CRYPT_OK) {
dropbear_exit("Error decrypting");
}
buf_incrpos(ses.readbuf, len);
/* check the hmac */
buf_setpos(ses.readbuf, ses.readbuf->len - macsize);
if (checkmac(ses.readbuf, ses.decryptreadbuf) != DROPBEAR_SUCCESS) {
if (checkmac() != DROPBEAR_SUCCESS) {
dropbear_exit("Integrity error");
}
/* readbuf no longer required */
buf_free(ses.readbuf);
ses.readbuf = NULL;
/* get padding length */
buf_setpos(ses.decryptreadbuf, PACKET_PADDING_OFF);
padlen = buf_getbyte(ses.decryptreadbuf);
buf_setpos(ses.readbuf, PACKET_PADDING_OFF);
padlen = buf_getbyte(ses.readbuf);
/* payload length */
/* - 4 - 1 is for LEN and PADLEN values */
len = ses.decryptreadbuf->len - padlen - 4 - 1;
len = ses.readbuf->len - padlen - 4 - 1 - macsize;
if ((len > RECV_MAX_PAYLOAD_LEN) || (len < 1)) {
dropbear_exit("bad packet size");
dropbear_exit("Bad packet size %d", len);
}
buf_setpos(ses.decryptreadbuf, PACKET_PAYLOAD_OFF);
buf_setpos(ses.readbuf, PACKET_PAYLOAD_OFF);
#ifndef DISABLE_ZLIB
if (is_compress_recv()) {
/* decompress */
ses.payload = buf_decompress(ses.decryptreadbuf, len);
ses.payload = buf_decompress(ses.readbuf, len);
} else
#endif
{
/* copy payload */
ses.payload = buf_new(len);
memcpy(ses.payload->data, buf_getptr(ses.decryptreadbuf, len), len);
memcpy(ses.payload->data, buf_getptr(ses.readbuf, len), len);
buf_incrlen(ses.payload, len);
}
buf_free(ses.decryptreadbuf);
ses.decryptreadbuf = NULL;
buf_free(ses.readbuf);
ses.readbuf = NULL;
buf_setpos(ses.payload, 0);
ses.recvseq++;
TRACE(("leave decrypt_packet"))
TRACE2(("leave decrypt_packet"))
}
/* Checks the mac in hashbuf, for the data in readbuf.
/* Checks the mac at the end of a decrypted readbuf.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
static int checkmac(buffer* macbuf, buffer* sourcebuf) {
static int checkmac() {
unsigned int macsize;
hmac_state hmac;
unsigned char tempbuf[MAX_MAC_LEN];
unsigned long bufsize;
unsigned int len;
macsize = ses.keys->recv_algo_mac->hashsize;
if (macsize == 0) {
return DROPBEAR_SUCCESS;
}
/* calculate the mac */
if (hmac_init(&hmac,
find_hash(ses.keys->recv_algo_mac->hashdesc->name),
ses.keys->recvmackey,
ses.keys->recv_algo_mac->keysize)
!= CRYPT_OK) {
dropbear_exit("HMAC error");
}
unsigned char mac_bytes[MAX_MAC_LEN];
unsigned int mac_size, contents_len;
/* sequence number */
STORE32H(ses.recvseq, tempbuf);
if (hmac_process(&hmac, tempbuf, 4) != CRYPT_OK) {
dropbear_exit("HMAC error");
}
mac_size = ses.keys->recv.algo_mac->hashsize;
contents_len = ses.readbuf->len - mac_size;
buf_setpos(sourcebuf, 0);
len = sourcebuf->len;
if (hmac_process(&hmac, buf_getptr(sourcebuf, len), len) != CRYPT_OK) {
dropbear_exit("HMAC error");
}
bufsize = sizeof(tempbuf);
if (hmac_done(&hmac, tempbuf, &bufsize) != CRYPT_OK) {
dropbear_exit("HMAC error");
}
buf_setpos(ses.readbuf, 0);
make_mac(ses.recvseq, &ses.keys->recv, ses.readbuf, contents_len, mac_bytes);
/* compare the hash */
if (memcmp(tempbuf, buf_getptr(macbuf, macsize), macsize) != 0) {
buf_setpos(ses.readbuf, contents_len);
if (memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {
return DROPBEAR_FAILURE;
} else {
return DROPBEAR_SUCCESS;
@@ -354,7 +391,7 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) {
buffer * ret;
z_streamp zstream;
zstream = ses.keys->recv_zstream;
zstream = ses.keys->recv.zstream;
ret = buf_new(len);
zstream->avail_in = len;
@@ -420,7 +457,6 @@ static void enqueue_reply_packet() {
ses.reply_queue_head = new_item;
}
ses.reply_queue_tail = new_item;
TRACE(("leave enqueue_reply_packet"))
}
void maybe_flush_reply_queue() {
@@ -450,52 +486,69 @@ void maybe_flush_reply_queue() {
void encrypt_packet() {
unsigned char padlen;
unsigned char blocksize, macsize;
buffer * writebuf; /* the packet which will go on the wire */
buffer * clearwritebuf; /* unencrypted, possibly compressed */
unsigned char type;
unsigned int clear_len;
unsigned char blocksize, mac_size;
buffer * writebuf; /* the packet which will go on the wire. This is
encrypted in-place. */
unsigned char packet_type;
unsigned int len, encrypt_buf_size;
unsigned char mac_bytes[MAX_MAC_LEN];
type = ses.writepayload->data[0];
TRACE(("enter encrypt_packet()"))
TRACE(("encrypt_packet type is %d", type))
TRACE2(("enter encrypt_packet()"))
buf_setpos(ses.writepayload, 0);
packet_type = buf_getbyte(ses.writepayload);
buf_setpos(ses.writepayload, 0);
TRACE2(("encrypt_packet type is %d", packet_type))
if (!ses.dataallowed && !packet_is_okay_kex(type)) {
if ((!ses.dataallowed && !packet_is_okay_kex(packet_type))) {
/* During key exchange only particular packets are allowed.
Since this type isn't OK we just enqueue it to send
Since this packet_type isn't OK we just enqueue it to send
after the KEX, see maybe_flush_reply_queue */
enqueue_reply_packet();
return;
}
blocksize = ses.keys->trans_algo_crypt->blocksize;
macsize = ses.keys->trans_algo_mac->hashsize;
/* Encrypted packet len is payload+5, then worst case is if we are 3 away
* from a blocksize multiple. In which case we need to pad to the
* multiple, then add another blocksize (or MIN_PACKET_LEN) */
clear_len = (ses.writepayload->len+4+1) + MIN_PACKET_LEN + 3;
blocksize = ses.keys->trans.algo_crypt->blocksize;
mac_size = ses.keys->trans.algo_mac->hashsize;
/* Encrypted packet len is payload+5. We need to then make sure
* there is enough space for padding or MIN_PACKET_LEN.
* Add extra 3 since we need at least 4 bytes of padding */
encrypt_buf_size = (ses.writepayload->len+4+1)
+ MAX(MIN_PACKET_LEN, blocksize) + 3
/* add space for the MAC at the end */
+ mac_size
#ifndef DISABLE_ZLIB
clear_len += ZLIB_COMPRESS_INCR; /* bit of a kludge, but we can't know len*/
/* some extra in case 'compression' makes it larger */
+ ZLIB_COMPRESS_INCR
#endif
clearwritebuf = buf_new(clear_len);
buf_setlen(clearwritebuf, PACKET_PAYLOAD_OFF);
buf_setpos(clearwritebuf, PACKET_PAYLOAD_OFF);
/* and an extra cleartext (stripped before transmission) byte for the
* packet type */
+ 1;
buf_setpos(ses.writepayload, 0);
writebuf = buf_new(encrypt_buf_size);
buf_setlen(writebuf, PACKET_PAYLOAD_OFF);
buf_setpos(writebuf, PACKET_PAYLOAD_OFF);
#ifndef DISABLE_ZLIB
/* compression */
if (is_compress_trans()) {
buf_compress(clearwritebuf, ses.writepayload, ses.writepayload->len);
int compress_delta;
buf_compress(writebuf, ses.writepayload, ses.writepayload->len);
compress_delta = (writebuf->len - PACKET_PAYLOAD_OFF) - ses.writepayload->len;
/* Handle the case where 'compress' increased the size. */
if (compress_delta > ZLIB_COMPRESS_INCR) {
buf_resize(writebuf, writebuf->size + compress_delta);
}
} else
#endif
{
memcpy(buf_getwriteptr(clearwritebuf, ses.writepayload->len),
memcpy(buf_getwriteptr(writebuf, ses.writepayload->len),
buf_getptr(ses.writepayload, ses.writepayload->len),
ses.writepayload->len);
buf_incrwritepos(clearwritebuf, ses.writepayload->len);
buf_incrwritepos(writebuf, ses.writepayload->len);
}
/* finished with payload */
@@ -504,53 +557,48 @@ void encrypt_packet() {
/* length of padding - packet length must be a multiple of blocksize,
* with a minimum of 4 bytes of padding */
padlen = blocksize - (clearwritebuf->len) % blocksize;
padlen = blocksize - (writebuf->len) % blocksize;
if (padlen < 4) {
padlen += blocksize;
}
/* check for min packet length */
if (clearwritebuf->len + padlen < MIN_PACKET_LEN) {
if (writebuf->len + padlen < MIN_PACKET_LEN) {
padlen += blocksize;
}
buf_setpos(clearwritebuf, 0);
buf_setpos(writebuf, 0);
/* packet length excluding the packetlength uint32 */
buf_putint(clearwritebuf, clearwritebuf->len + padlen - 4);
buf_putint(writebuf, writebuf->len + padlen - 4);
/* padding len */
buf_putbyte(clearwritebuf, padlen);
buf_putbyte(writebuf, padlen);
/* actual padding */
buf_setpos(clearwritebuf, clearwritebuf->len);
buf_incrlen(clearwritebuf, padlen);
genrandom(buf_getptr(clearwritebuf, padlen), padlen);
buf_setpos(writebuf, writebuf->len);
buf_incrlen(writebuf, padlen);
genrandom(buf_getptr(writebuf, padlen), padlen);
/* do the actual encryption */
buf_setpos(clearwritebuf, 0);
/* create a new writebuffer, this is freed when it has been put on the
* wire by writepacket() */
writebuf = buf_new(clearwritebuf->len + macsize);
make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes);
/* encrypt it */
while (clearwritebuf->pos < clearwritebuf->len) {
if (ses.keys->trans_crypt_mode->encrypt(
buf_getptr(clearwritebuf, blocksize),
buf_getwriteptr(writebuf, blocksize),
blocksize,
&ses.keys->trans_cipher_state) != CRYPT_OK) {
dropbear_exit("error encrypting");
}
buf_incrpos(clearwritebuf, blocksize);
buf_incrwritepos(writebuf, blocksize);
/* do the actual encryption, in-place */
buf_setpos(writebuf, 0);
/* encrypt it in-place*/
len = writebuf->len;
if (ses.keys->trans.crypt_mode->encrypt(
buf_getptr(writebuf, len),
buf_getwriteptr(writebuf, len),
len,
&ses.keys->trans.cipher_state) != CRYPT_OK) {
dropbear_exit("Error encrypting");
}
buf_incrpos(writebuf, len);
/* now add a hmac and we're done */
writemac(writebuf, clearwritebuf);
/* stick the MAC on it */
buf_putbytes(writebuf, mac_bytes, mac_size);
/* clearwritebuf is finished with */
buf_free(clearwritebuf);
clearwritebuf = NULL;
/* enqueue the packet for sending */
/* The last byte of the buffer stores the cleartext packet_type. It is not
* transmitted but is used for transmit timeout purposes */
buf_putbyte(writebuf, packet_type);
/* enqueue the packet for sending. It will get freed after transmission. */
buf_setpos(writebuf, 0);
enqueue(&ses.writequeue, (void*)writebuf);
@@ -558,54 +606,48 @@ void encrypt_packet() {
ses.kexstate.datatrans += writebuf->len;
ses.transseq++;
TRACE(("leave encrypt_packet()"))
TRACE2(("leave encrypt_packet()"))
}
/* Create the packet mac, and append H(seqno|clearbuf) to the output */
static void writemac(buffer * outputbuffer, buffer * clearwritebuf) {
unsigned int macsize;
/* output_mac must have ses.keys->trans.algo_mac->hashsize bytes. */
static void make_mac(unsigned int seqno, const struct key_context_directional * key_state,
buffer * clear_buf, unsigned int clear_len,
unsigned char *output_mac) {
unsigned char seqbuf[4];
unsigned char tempbuf[MAX_MAC_LEN];
unsigned long bufsize;
hmac_state hmac;
TRACE(("enter writemac"))
macsize = ses.keys->trans_algo_mac->hashsize;
if (macsize > 0) {
if (key_state->algo_mac->hashsize > 0) {
/* calculate the mac */
if (hmac_init(&hmac,
find_hash(ses.keys->trans_algo_mac->hashdesc->name),
ses.keys->transmackey,
ses.keys->trans_algo_mac->keysize) != CRYPT_OK) {
key_state->hash_index,
key_state->mackey,
key_state->algo_mac->keysize) != CRYPT_OK) {
dropbear_exit("HMAC error");
}
/* sequence number */
STORE32H(ses.transseq, seqbuf);
STORE32H(seqno, seqbuf);
if (hmac_process(&hmac, seqbuf, 4) != CRYPT_OK) {
dropbear_exit("HMAC error");
}
/* the actual contents */
buf_setpos(clearwritebuf, 0);
buf_setpos(clear_buf, 0);
if (hmac_process(&hmac,
buf_getptr(clearwritebuf,
clearwritebuf->len),
clearwritebuf->len) != CRYPT_OK) {
buf_getptr(clear_buf, clear_len),
clear_len) != CRYPT_OK) {
dropbear_exit("HMAC error");
}
bufsize = sizeof(tempbuf);
if (hmac_done(&hmac, tempbuf, &bufsize)
!= CRYPT_OK) {
bufsize = MAX_MAC_LEN;
if (hmac_done(&hmac, output_mac, &bufsize) != CRYPT_OK) {
dropbear_exit("HMAC error");
}
buf_putbytes(outputbuffer, tempbuf, macsize);
}
TRACE(("leave writemac"))
TRACE2(("leave writemac"))
}
#ifndef DISABLE_ZLIB
@@ -616,33 +658,33 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
unsigned int endpos = src->pos + len;
int result;
TRACE(("enter buf_compress"))
TRACE2(("enter buf_compress"))
while (1) {
ses.keys->trans_zstream->avail_in = endpos - src->pos;
ses.keys->trans_zstream->next_in =
buf_getptr(src, ses.keys->trans_zstream->avail_in);
ses.keys->trans.zstream->avail_in = endpos - src->pos;
ses.keys->trans.zstream->next_in =
buf_getptr(src, ses.keys->trans.zstream->avail_in);
ses.keys->trans_zstream->avail_out = dest->size - dest->pos;
ses.keys->trans_zstream->next_out =
buf_getwriteptr(dest, ses.keys->trans_zstream->avail_out);
ses.keys->trans.zstream->avail_out = dest->size - dest->pos;
ses.keys->trans.zstream->next_out =
buf_getwriteptr(dest, ses.keys->trans.zstream->avail_out);
result = deflate(ses.keys->trans_zstream, Z_SYNC_FLUSH);
result = deflate(ses.keys->trans.zstream, Z_SYNC_FLUSH);
buf_setpos(src, endpos - ses.keys->trans_zstream->avail_in);
buf_setlen(dest, dest->size - ses.keys->trans_zstream->avail_out);
buf_setpos(src, endpos - ses.keys->trans.zstream->avail_in);
buf_setlen(dest, dest->size - ses.keys->trans.zstream->avail_out);
buf_setpos(dest, dest->len);
if (result != Z_OK) {
dropbear_exit("zlib error");
}
if (ses.keys->trans_zstream->avail_in == 0) {
if (ses.keys->trans.zstream->avail_in == 0) {
break;
}
dropbear_assert(ses.keys->trans_zstream->avail_out == 0);
dropbear_assert(ses.keys->trans.zstream->avail_out == 0);
/* the buffer has been filled, we must extend. This only happens in
* unusual circumstances where the data grows in size after deflate(),
@@ -650,6 +692,6 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
buf_resize(dest, dest->size + ZLIB_COMPRESS_INCR);
}
TRACE(("leave buf_compress"))
TRACE2(("leave buf_compress"))
}
#endif

View File

@@ -44,6 +44,6 @@ typedef struct PacketType {
#define PACKET_PADDING_OFF 4
#define PACKET_PAYLOAD_OFF 5
#define INIT_READBUF 200
#define INIT_READBUF 128
#endif /* _PACKET_H_ */

View File

@@ -45,13 +45,15 @@ void process_packet() {
unsigned char type;
unsigned int i;
TRACE(("enter process_packet"))
TRACE2(("enter process_packet"))
type = buf_getbyte(ses.payload);
TRACE(("process_packet: packet type = %d", type))
TRACE(("process_packet: packet type = %d, len %d", type, ses.payload->len))
ses.lastpacket = type;
ses.last_packet_time = time(NULL);
/* These packets we can receive at any time */
switch(type) {
@@ -63,25 +65,24 @@ void process_packet() {
case SSH_MSG_UNIMPLEMENTED:
/* debugging XXX */
TRACE(("SSH_MSG_UNIMPLEMENTED"))
dropbear_exit("received SSH_MSG_UNIMPLEMENTED");
dropbear_exit("Received SSH_MSG_UNIMPLEMENTED");
case SSH_MSG_DISCONNECT:
/* TODO cleanup? */
dropbear_close("Disconnect received");
}
ses.last_packet_time = time(NULL);
/* This applies for KEX, where the spec says the next packet MUST be
* NEWKEYS */
if (ses.requirenext != 0) {
if (ses.requirenext != type) {
/* TODO send disconnect? */
dropbear_exit("unexpected packet type %d, expected %d", type,
ses.requirenext);
if (ses.requirenext[0] != 0) {
if (ses.requirenext[0] != type
&& (ses.requirenext[1] == 0 || ses.requirenext[1] != type)) {
dropbear_exit("Unexpected packet type %d, expected [%d,%d]", type,
ses.requirenext[0], ses.requirenext[1]);
} else {
/* Got what we expected */
ses.requirenext = 0;
ses.requirenext[0] = 0;
ses.requirenext[1] = 0;
}
}
@@ -99,7 +100,7 @@ void process_packet() {
* NOTE: if the protocol changes and new types are added, revisit this
* assumption */
if ( !ses.authstate.authdone && type > MAX_UNAUTH_PACKET_TYPE ) {
dropbear_exit("received message %d before userauth", type);
dropbear_exit("Received message %d before userauth", type);
}
for (i = 0; ; i++) {
@@ -123,7 +124,7 @@ out:
buf_free(ses.payload);
ses.payload = NULL;
TRACE(("leave process_packet"))
TRACE2(("leave process_packet"))
}

View File

@@ -70,7 +70,6 @@ void enqueue(struct Queue* queue, void* item) {
struct Link* newlink;
TRACE(("enter enqueue"))
newlink = (struct Link*)m_malloc(sizeof(struct Link));
newlink->item = item;
@@ -85,5 +84,4 @@ void enqueue(struct Queue* queue, void* item) {
queue->head = newlink;
}
queue->count++;
TRACE(("leave enqueue"))
}

View File

@@ -36,7 +36,7 @@ struct Queue {
struct Link* head;
struct Link* tail;
unsigned int count; /* safety value */
unsigned int count;
};

249
random.c
View File

@@ -26,20 +26,18 @@
#include "buffer.h"
#include "dbutil.h"
#include "bignum.h"
static int donerandinit = 0;
#include "random.h"
/* this is used to generate unique output from the same hashpool */
static uint32_t counter = 0;
/* the max value for the counter, so it won't integer overflow */
#define MAX_COUNTER 1<<30
static unsigned char hashpool[SHA1_HASH_SIZE];
static unsigned char hashpool[SHA1_HASH_SIZE] = {0};
static int donerandinit = 0;
#define INIT_SEED_SIZE 32 /* 256 bits */
static void readrand(unsigned char* buf, unsigned int buflen);
/* The basic setup is we read some data from /dev/(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
@@ -50,129 +48,198 @@ static void readrand(unsigned char* buf, unsigned int buflen);
*
*/
static void readrand(unsigned char* buf, unsigned int buflen) {
/* Pass len=0 to hash an entire file */
static int
process_file(hash_state *hs, const char *filename,
unsigned int len, int prngd)
{
static int already_blocked = 0;
int readfd;
unsigned int readpos;
int readlen;
#ifdef DROPBEAR_PRNGD_SOCKET
struct sockaddr_un egdsock;
char egdcmd[2];
#endif
#ifdef DROPBEAR_RANDOM_DEV
readfd = open(DROPBEAR_RANDOM_DEV, O_RDONLY);
if (readfd < 0) {
dropbear_exit("couldn't open random device");
}
#endif
unsigned int readcount;
int ret = DROPBEAR_FAILURE;
#ifdef DROPBEAR_PRNGD_SOCKET
memset((void*)&egdsock, 0x0, sizeof(egdsock));
egdsock.sun_family = AF_UNIX;
strlcpy(egdsock.sun_path, DROPBEAR_PRNGD_SOCKET,
sizeof(egdsock.sun_path));
readfd = socket(PF_UNIX, SOCK_STREAM, 0);
if (readfd < 0) {
dropbear_exit("couldn't open random device");
if (prngd)
{
readfd = connect_unix(filename);
}
/* todo - try various common locations */
if (connect(readfd, (struct sockaddr*)&egdsock,
sizeof(struct sockaddr_un)) < 0) {
dropbear_exit("couldn't open random device");
}
if (buflen > 255)
dropbear_exit("can't request more than 255 bytes from egd");
egdcmd[0] = 0x02; /* blocking read */
egdcmd[1] = (unsigned char)buflen;
if (write(readfd, egdcmd, 2) < 0)
dropbear_exit("can't send command to egd");
else
#endif
{
readfd = open(filename, O_RDONLY);
}
/* read the actual random data */
readpos = 0;
do {
if (readfd < 0) {
goto out;
}
readcount = 0;
while (len == 0 || readcount < len)
{
int readlen, wantread;
unsigned char readbuf[2048];
if (!already_blocked)
{
int ret;
struct timeval timeout;
struct timeval timeout = { .tv_sec = 2, .tv_usec = 0};
fd_set read_fds;
timeout.tv_sec = 2; /* two seconds should be enough */
timeout.tv_usec = 0;
FD_ZERO(&read_fds);
FD_SET(readfd, &read_fds);
ret = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
if (ret == 0)
{
dropbear_log(LOG_INFO, "Warning: Reading the random source seems to have blocked.\nIf you experience problems, you probably need to find a better entropy source.");
dropbear_log(LOG_WARNING, "Warning: Reading the randomness source '%s' seems to have blocked.\nYou may need to find a better entropy source.", filename);
already_blocked = 1;
}
}
readlen = read(readfd, &buf[readpos], buflen - readpos);
if (len == 0)
{
wantread = sizeof(readbuf);
}
else
{
wantread = MIN(sizeof(readbuf), len-readcount);
}
#ifdef DROPBEAR_PRNGD_SOCKET
if (prngd)
{
char egdcmd[2];
egdcmd[0] = 0x02; /* blocking read */
egdcmd[1] = (unsigned char)wantread;
if (write(readfd, egdcmd, 2) < 0)
{
dropbear_exit("Can't send command to egd");
}
}
#endif
readlen = read(readfd, readbuf, wantread);
if (readlen <= 0) {
if (readlen < 0 && errno == EINTR) {
continue;
}
dropbear_exit("error reading random source");
if (readlen == 0 && len == 0)
{
/* whole file was read as requested */
break;
}
goto out;
}
readpos += readlen;
} while (readpos < buflen);
close (readfd);
sha1_process(hs, readbuf, readlen);
readcount += readlen;
}
ret = DROPBEAR_SUCCESS;
out:
close(readfd);
return ret;
}
/* initialise the prng from /dev/(u)random or prngd */
void seedrandom() {
unsigned char readbuf[INIT_SEED_SIZE];
void addrandom(char * buf, unsigned int len)
{
hash_state hs;
/* initialise so that things won't warn about
* hashing an undefined buffer */
if (!donerandinit) {
m_burn(hashpool, sizeof(hashpool));
}
/* get the seed data */
readrand(readbuf, sizeof(readbuf));
/* hash in the new seed data */
sha1_init(&hs);
/* existing state (zeroes on startup) */
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
sha1_process(&hs, (void*)readbuf, sizeof(readbuf));
/* new */
sha1_process(&hs, buf, len);
sha1_done(&hs, hashpool);
}
static void write_urandom()
{
#ifndef DROPBEAR_PRNGD_SOCKET
/* This is opportunistic, don't worry about failure */
unsigned char buf[INIT_SEED_SIZE];
FILE *f = fopen(DROPBEAR_URANDOM_DEV, "w");
if (!f) {
return;
}
genrandom(buf, sizeof(buf));
fwrite(buf, sizeof(buf), 1, f);
fclose(f);
#endif
}
/* Initialise the prng from /dev/urandom or prngd. This function can
* be called multiple times */
void seedrandom() {
hash_state hs;
pid_t pid;
struct timeval tv;
clock_t clockval;
/* hash in the new seed data */
sha1_init(&hs);
/* existing state */
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
#ifdef DROPBEAR_PRNGD_SOCKET
if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1)
!= DROPBEAR_SUCCESS) {
dropbear_exit("Failure reading random device %s",
DROPBEAR_PRNGD_SOCKET);
}
#else
/* non-blocking random source (probably /dev/urandom) */
if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0)
!= DROPBEAR_SUCCESS) {
dropbear_exit("Failure reading random device %s",
DROPBEAR_URANDOM_DEV);
}
#endif
/* A few other sources to fall back on.
* Add more here for other platforms */
#ifdef __linux__
/* Seems to be a reasonable source of entropy from timers. Possibly hard
* for even local attackers to reproduce */
process_file(&hs, "/proc/timer_list", 0, 0);
/* Might help on systems with wireless */
process_file(&hs, "/proc/interrupts", 0, 0);
process_file(&hs, "/proc/loadavg", 0, 0);
process_file(&hs, "/proc/sys/kernel/random/entropy_avail", 0, 0);
/* Mostly network visible but useful in some situations */
process_file(&hs, "/proc/net/netstat", 0, 0);
process_file(&hs, "/proc/net/dev", 0, 0);
process_file(&hs, "/proc/net/tcp", 0, 0);
/* Also includes interface lo */
process_file(&hs, "/proc/net/rt_cache", 0, 0);
process_file(&hs, "/proc/vmstat", 0, 0);
#endif
pid = getpid();
sha1_process(&hs, (void*)&pid, sizeof(pid));
// gettimeofday() doesn't completely fill out struct timeval on
// OS X (10.8.3), avoid valgrind warnings by clearing it first
memset(&tv, 0x0, sizeof(tv));
gettimeofday(&tv, NULL);
sha1_process(&hs, (void*)&tv, sizeof(tv));
clockval = clock();
sha1_process(&hs, (void*)&clockval, sizeof(clockval));
/* When a private key is read by the client or server it will
* be added to the hashpool - see runopts.c */
sha1_done(&hs, hashpool);
counter = 0;
donerandinit = 1;
}
/* hash the current random pool with some unique identifiers
* for this process and point-in-time. this is used to separate
* the random pools for fork()ed processes. */
void reseedrandom() {
pid_t pid;
hash_state hs;
struct timeval tv;
if (!donerandinit) {
dropbear_exit("seedrandom not done");
}
pid = getpid();
gettimeofday(&tv, NULL);
sha1_init(&hs);
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
sha1_process(&hs, (void*)&pid, sizeof(pid));
sha1_process(&hs, (void*)&tv, sizeof(tv));
sha1_done(&hs, hashpool);
/* Feed it all back into /dev/urandom - this might help if Dropbear
* is running from inetd and gets new state each time */
write_urandom();
}
/* return len bytes of pseudo-random data */

View File

@@ -28,9 +28,8 @@
struct mp_int;
void seedrandom();
void reseedrandom();
void genrandom(unsigned char* buf, int len);
void addrandom(unsigned char* buf, int len);
void genrandom(unsigned char* buf, unsigned int len);
void addrandom(char * buf, unsigned int len);
void gen_random_mpint(mp_int *max, mp_int *rand);
#endif /* _RANDOM_H_ */

40
rsa.c
View File

@@ -38,7 +38,7 @@
#ifdef DROPBEAR_RSA
static void rsa_pad_em(rsa_key * key,
static void rsa_pad_em(dropbear_rsa_key * key,
const unsigned char * data, unsigned int len,
mp_int * rsa_em);
@@ -46,7 +46,7 @@ static void rsa_pad_em(rsa_key * key,
* The key will have the same format as buf_put_rsa_key.
* These should be freed with rsa_key_free.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_get_rsa_pub_key(buffer* buf, rsa_key *key) {
int buf_get_rsa_pub_key(buffer* buf, dropbear_rsa_key *key) {
int ret = DROPBEAR_FAILURE;
TRACE(("enter buf_get_rsa_pub_key"))
@@ -67,7 +67,7 @@ int buf_get_rsa_pub_key(buffer* buf, rsa_key *key) {
}
if (mp_count_bits(key->n) < MIN_RSA_KEYLEN) {
dropbear_log(LOG_WARNING, "rsa key too short");
dropbear_log(LOG_WARNING, "RSA key too short");
goto out;
}
@@ -84,7 +84,7 @@ out:
/* Same as buf_get_rsa_pub_key, but reads private bits at the end.
* Loads a private rsa key from a buffer
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_get_rsa_priv_key(buffer* buf, rsa_key *key) {
int buf_get_rsa_priv_key(buffer* buf, dropbear_rsa_key *key) {
int ret = DROPBEAR_FAILURE;
TRACE(("enter buf_get_rsa_priv_key"))
@@ -137,12 +137,12 @@ out:
/* Clear and free the memory used by a public or private key */
void rsa_key_free(rsa_key *key) {
void rsa_key_free(dropbear_rsa_key *key) {
TRACE(("enter rsa_key_free"))
TRACE2(("enter rsa_key_free"))
if (key == NULL) {
TRACE(("leave rsa_key_free: key == NULL"))
TRACE2(("leave rsa_key_free: key == NULL"))
return;
}
if (key->d) {
@@ -166,7 +166,7 @@ void rsa_key_free(rsa_key *key) {
m_free(key->q);
}
m_free(key);
TRACE(("leave rsa_key_free"))
TRACE2(("leave rsa_key_free"))
}
/* Put the public rsa key into the buffer in the required format:
@@ -175,7 +175,7 @@ void rsa_key_free(rsa_key *key) {
* mp_int e
* mp_int n
*/
void buf_put_rsa_pub_key(buffer* buf, rsa_key *key) {
void buf_put_rsa_pub_key(buffer* buf, dropbear_rsa_key *key) {
TRACE(("enter buf_put_rsa_pub_key"))
dropbear_assert(key != NULL);
@@ -189,7 +189,7 @@ void buf_put_rsa_pub_key(buffer* buf, rsa_key *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) {
void buf_put_rsa_priv_key(buffer* buf, dropbear_rsa_key *key) {
TRACE(("enter buf_put_rsa_priv_key"))
@@ -213,7 +213,7 @@ void buf_put_rsa_priv_key(buffer* buf, rsa_key *key) {
#ifdef DROPBEAR_SIGNKEY_VERIFY
/* Verify a signature in buf, made on data by the key given.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_rsa_verify(buffer * buf, rsa_key *key, const unsigned char* data,
int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, const unsigned char* data,
unsigned int len) {
unsigned int slen;
@@ -270,7 +270,7 @@ out:
/* Sign the data presented with key, writing the signature contents
* to the buffer */
void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* data,
unsigned int len) {
unsigned int nsize, ssize;
@@ -302,26 +302,26 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
/* rsa_s used as a temp var*/
if (mp_exptmod(&rsa_tmp2, key->e, key->n, &rsa_s) != MP_OKAY) {
dropbear_exit("rsa error");
dropbear_exit("RSA error");
}
if (mp_invmod(&rsa_tmp2, key->n, &rsa_tmp3) != MP_OKAY) {
dropbear_exit("rsa error");
dropbear_exit("RSA error");
}
if (mp_mulmod(&rsa_tmp1, &rsa_s, key->n, &rsa_tmp2) != MP_OKAY) {
dropbear_exit("rsa error");
dropbear_exit("RSA error");
}
/* rsa_tmp2 is em' */
/* s' = (em')^d mod n */
if (mp_exptmod(&rsa_tmp2, key->d, key->n, &rsa_tmp1) != MP_OKAY) {
dropbear_exit("rsa error");
dropbear_exit("RSA error");
}
/* rsa_tmp1 is s' */
/* rsa_tmp3 is r^(-1) mod n */
/* s = (s')r^(-1) mod n */
if (mp_mulmod(&rsa_tmp1, &rsa_tmp3, key->n, &rsa_s) != MP_OKAY) {
dropbear_exit("rsa error");
dropbear_exit("RSA error");
}
#else
@@ -329,7 +329,7 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
/* s = em^d mod n */
/* rsa_tmp1 is em */
if (mp_exptmod(&rsa_tmp1, key->d, key->n, &rsa_s) != MP_OKAY) {
dropbear_exit("rsa error");
dropbear_exit("RSA error");
}
#endif /* RSA_BLINDING */
@@ -351,7 +351,7 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
}
if (mp_to_unsigned_bin(&rsa_s, buf_getwriteptr(buf, ssize)) != MP_OKAY) {
dropbear_exit("rsa error");
dropbear_exit("RSA error");
}
buf_incrwritepos(buf, ssize);
mp_clear(&rsa_s);
@@ -376,7 +376,7 @@ void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
*
* rsa_em must be a pointer to an initialised mp_int.
*/
static void rsa_pad_em(rsa_key * key,
static void rsa_pad_em(dropbear_rsa_key * key,
const unsigned char * data, unsigned int len,
mp_int * rsa_em) {

21
rsa.h
View File

@@ -32,29 +32,28 @@
#define RSA_SIGNATURE_SIZE 4+7+4+40
struct RSA_key {
typedef struct {
mp_int* n;
mp_int* e;
/* d, p, and q are private parts */
mp_int* d;
mp_int* p;
mp_int* q;
};
} dropbear_rsa_key;
typedef struct RSA_key rsa_key;
void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* data,
unsigned int len);
#ifdef DROPBEAR_SIGNKEY_VERIFY
int buf_rsa_verify(buffer * buf, rsa_key *key, const unsigned char* data,
int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, const unsigned char* data,
unsigned int len);
#endif
int buf_get_rsa_pub_key(buffer* buf, rsa_key *key);
int buf_get_rsa_priv_key(buffer* buf, rsa_key *key);
void buf_put_rsa_pub_key(buffer* buf, rsa_key *key);
void buf_put_rsa_priv_key(buffer* buf, rsa_key *key);
void rsa_key_free(rsa_key *key);
int buf_get_rsa_pub_key(buffer* buf, dropbear_rsa_key *key);
int buf_get_rsa_priv_key(buffer* buf, dropbear_rsa_key *key);
void buf_put_rsa_pub_key(buffer* buf, dropbear_rsa_key *key);
void buf_put_rsa_priv_key(buffer* buf, dropbear_rsa_key *key);
void rsa_key_free(dropbear_rsa_key *key);
#endif /* DROPBEAR_RSA */

View File

@@ -37,8 +37,20 @@ typedef struct runopts {
int listen_fwd_all;
#endif
unsigned int recv_window;
unsigned int keepalive_secs;
unsigned int idle_timeout_secs;
time_t keepalive_secs;
time_t idle_timeout_secs;
#ifndef DISABLE_ZLIB
/* TODO: add a commandline flag. Currently this is on by default if compression
* is compiled in, but disabled for a client's non-final multihop stages. (The
* intermediate stages are compressed streams, so are uncompressible. */
int enable_compress;
#endif
#ifdef ENABLE_USER_ALGO_LIST
char *cipher_list;
char *mac_list;
#endif
} runopts;
@@ -77,6 +89,7 @@ typedef struct svr_runopts {
int noauthpass;
int norootpass;
int allowblankpass;
#ifdef ENABLE_SVR_REMOTETCPFWD
int noremotetcp;
@@ -108,17 +121,25 @@ typedef struct cli_runopts {
char *cmd;
int wantpty;
int always_accept_key;
int no_hostkey_check;
int no_cmd;
int backgrounded;
int is_subsystem;
#ifdef ENABLE_CLI_PUBKEY_AUTH
struct SignKeyList *privkeys; /* Keys to use for public-key auth */
m_list *privkeys; /* Keys to use for public-key auth */
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
struct TCPFwdList * remotefwds;
m_list * remotefwds;
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
struct TCPFwdList * localfwds;
m_list * localfwds;
#endif
#ifdef ENABLE_CLI_AGENTFWD
int agent_fwd;
int agent_keys_loaded; /* whether pubkeys has been populated with a
list of keys held by the agent */
int agent_fd; /* The agent fd is only set during authentication. Forwarded
agent sessions have their own file descriptors */
#endif
#ifdef ENABLE_CLI_NETCAT
@@ -128,10 +149,13 @@ typedef struct cli_runopts {
#ifdef ENABLE_CLI_PROXYCMD
char *proxycmd;
#endif
} cli_runopts;
extern cli_runopts cli_opts;
void cli_getopts(int argc, char ** argv);
#ifdef ENABLE_USER_ALGO_LIST
void parse_ciphers_macs();
#endif
#endif /* _RUNOPTS_H_ */

71
scp.c
View File

@@ -130,22 +130,22 @@ do_local_cmd(arglist *a)
fprintf(stderr, " %s", a->list[i]);
fprintf(stderr, "\n");
}
#ifdef __uClinux__
#ifdef USE_VFORK
pid = vfork();
#else
pid = fork();
#endif /* __uClinux__ */
#endif
if (pid == -1)
fatal("do_local_cmd: fork: %s", strerror(errno));
if (pid == 0) {
execvp(a->list[0], a->list);
perror(a->list[0]);
#ifdef __uClinux__
#ifdef USE_VFORK
_exit(1);
#else
exit(1);
#endif /* __uClinux__ */
#endif
}
do_cmd_pid = pid;
@@ -171,6 +171,16 @@ do_local_cmd(arglist *a)
* assigns the input and output file descriptors on success.
*/
static void
arg_setup(char *host, char *remuser, char *cmd)
{
replacearg(&args, 0, "%s", ssh_program);
if (remuser != NULL)
addargs(&args, "-l%s", remuser);
addargs(&args, "%s", host);
addargs(&args, "%s", cmd);
}
int
do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
{
@@ -198,22 +208,18 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
close(reserved[0]);
close(reserved[1]);
/* uClinux needs to build the args here before vforking,
otherwise we do it later on. */
#ifdef __uClinux__
replacearg(&args, 0, "%s", ssh_program);
if (remuser != NULL)
addargs(&args, "-l%s", remuser);
addargs(&args, "%s", host);
addargs(&args, "%s", cmd);
#endif /* __uClinux__ */
/* uClinux needs to build the args here before vforking,
otherwise we do it later on. */
#ifdef USE_VFORK
arg_setup(host, remuser, cmd);
#endif
/* Fork a child to execute the command on the remote host using ssh. */
#ifdef __uClinux__
#ifdef USE_VFORK
do_cmd_pid = vfork();
#else
do_cmd_pid = fork();
#endif /* __uClinux__ */
#endif
if (do_cmd_pid == 0) {
/* Child. */
@@ -224,27 +230,22 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
close(pin[0]);
close(pout[1]);
#ifndef __uClinux__
replacearg(&args, 0, "%s", ssh_program);
if (remuser != NULL)
addargs(&args, "-l%s", remuser);
addargs(&args, "%s", host);
addargs(&args, "%s", cmd);
#endif /* __uClinux__ */
#ifndef USE_VFORK
arg_setup(host, remuser, cmd);
#endif
execvp(ssh_program, args.list);
perror(ssh_program);
#ifndef __uClinux__
exit(1);
#else
#ifdef USE_VFORK
_exit(1);
#endif /* __uClinux__ */
#else
exit(1);
#endif
} else if (do_cmd_pid == -1) {
fatal("fork: %s", strerror(errno));
}
#ifdef __uClinux__
#ifdef USE_VFORK
/* clean up command */
/* pop cmd */
xfree(args.list[args.num-1]);
@@ -260,7 +261,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
args.list[args.num-1]=NULL;
args.num--;
}
#endif /* __uClinux__ */
#endif
/* Parent. Close the other side, and return the local side. */
close(pin[0]);
@@ -343,7 +344,7 @@ main(int argc, char **argv)
addargs(&args, "-p%s", optarg);
break;
case 'B':
addargs(&args, "-oBatchmode yes");
fprintf(stderr, "Note: -B option is disabled in this version of scp");
break;
case 'l':
speed = strtod(optarg, &endp);
@@ -364,12 +365,12 @@ main(int argc, char **argv)
addargs(&args, "-v");
verbose_mode = 1;
break;
#ifdef PROGRESS_METER
case 'q':
#ifdef PROGRESS_METER
addargs(&args, "-q");
showprogress = 0;
break;
#endif
break;
/* Server options. */
case 'd':
@@ -492,9 +493,13 @@ toremote(char *targ, int argc, char **argv)
addargs(&alist, "%s", ssh_program);
if (verbose_mode)
addargs(&alist, "-v");
#if 0
// Disabled since dbclient won't understand them
// and scp works fine without them.
addargs(&alist, "-x");
addargs(&alist, "-oClearAllForwardings yes");
addargs(&alist, "-n");
#endif
*src++ = 0;
if (*src == 0)
@@ -769,7 +774,7 @@ bwlimit(int amount)
{
static struct timeval bwstart, bwend;
static int lamt, thresh = 16384;
u_int64_t waitlen;
uint64_t waitlen;
struct timespec ts, rm;
if (!timerisset(&bwstart)) {

View File

@@ -40,6 +40,7 @@
/*RCSID("OpenBSD: xmalloc.c,v 1.16 2001/07/23 18:21:46 stevesk Exp ");*/
#define _GNU_SOURCE
#include "includes.h"
#include "scpmisc.h"

View File

@@ -26,7 +26,5 @@
#define _SERVICE_H_
void recv_msg_service_request(); /* Server */
void send_msg_service_request(); /* Client */
void recv_msg_service_accept(); /* Client */
#endif /* _SERVICE_H_ */

109
session.h
View File

@@ -37,65 +37,60 @@
#include "packet.h"
#include "tcpfwd.h"
#include "chansession.h"
#include "dbutil.h"
extern int sessinitdone; /* Is set to 0 somewhere */
extern int exitflag;
void common_session_init(int sock_in, int sock_out, char* remotehost);
void common_session_init(int sock_in, int sock_out);
void session_loop(void(*loophandler)());
void common_session_cleanup();
void session_identification();
void session_cleanup();
void send_session_identification();
void send_msg_ignore();
const char* get_user_shell();
void fill_passwd(const char* username);
/* Server */
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_session(int sock, int childpipe);
void svr_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
void svr_dropbear_log(int priority, const char* format, va_list param);
/* Client */
void cli_session(int sock_in, int sock_out, char *remotehost);
void cli_session_cleanup();
void cli_session(int sock_in, int sock_out);
void cleantext(unsigned char* dirtytext);
struct key_context {
const struct dropbear_cipher *recv_algo_crypt; /* NULL for none */
const struct dropbear_cipher *trans_algo_crypt; /* NULL for none */
const struct dropbear_cipher_mode *recv_crypt_mode;
const struct dropbear_cipher_mode *trans_crypt_mode;
const struct dropbear_hash *recv_algo_mac; /* NULL for none */
const struct dropbear_hash *trans_algo_mac; /* NULL for none */
char algo_kex;
char algo_hostkey;
char recv_algo_comp; /* compression */
char trans_algo_comp;
int allow_compress; /* whether compression has started (useful in
zlib@openssh.com delayed compression case) */
/* crypto parameters that are stored individually for transmit and receive */
struct key_context_directional {
const struct dropbear_cipher *algo_crypt;
const struct dropbear_cipher_mode *crypt_mode;
const struct dropbear_hash *algo_mac;
int hash_index; /* lookup for libtomcrypt */
char algo_comp; /* compression */
#ifndef DISABLE_ZLIB
z_streamp recv_zstream;
z_streamp trans_zstream;
z_streamp zstream;
#endif
/* actual keys */
union {
symmetric_CBC cbc;
#ifdef DROPBEAR_ENABLE_CTR_MODE
symmetric_CTR ctr;
#endif
} recv_cipher_state;
union {
symmetric_CBC cbc;
#ifdef DROPBEAR_ENABLE_CTR_MODE
symmetric_CTR ctr;
#endif
} trans_cipher_state;
unsigned char recvmackey[MAX_MAC_KEY];
unsigned char transmackey[MAX_MAC_KEY];
} cipher_state;
unsigned char mackey[MAX_MAC_LEN];
int valid;
};
struct key_context {
struct key_context_directional recv;
struct key_context_directional trans;
char algo_kex;
char algo_hostkey;
int allow_compress; /* whether compression has started (useful in
zlib@openssh.com delayed compression case) */
};
struct packetlist;
@@ -116,9 +111,10 @@ struct sshsession {
int sock_in;
int sock_out;
unsigned char *remotehost; /* the peer hostname */
unsigned char *remoteident;
/* remotehost will be initially NULL as we delay
* reading the remote version string. it will be set
* by the time any recv_() packet methods are called */
unsigned char *remoteident;
int maxfd; /* the maximum file descriptor to check with select() */
@@ -128,8 +124,7 @@ struct sshsession {
throughout the code, as handlers fill out this
buffer with the packet to send. */
struct Queue writequeue; /* A queue of encrypted packets to send */
buffer *readbuf; /* Encrypted */
buffer *decryptreadbuf; /* Post-decryption */
buffer *readbuf; /* From the wire, decrypted in-place */
buffer *payload; /* Post-decompression, the actual SSH packet */
unsigned int transseq, recvseq; /* Sequence IDs */
@@ -140,8 +135,9 @@ struct sshsession {
unsigned dataallowed : 1; /* whether we can send data packets or we are in
the middle of a KEX or something */
unsigned char requirenext; /* byte indicating what packet we require next,
or 0x00 for any */
unsigned char requirenext[2]; /* bytes indicating what packets we require next,
or 0x00 for any. Second option can only be
used if the first byte is also set */
unsigned char ignorenext; /* whether to ignore the next packet,
used for kex_follows stuff */
@@ -169,20 +165,19 @@ struct sshsession {
buffer* kexhashbuf; /* session hash buffer calculated from various packets*/
buffer* transkexinit; /* the kexinit packet we send should be kept so we
can add it to the hash when generating keys */
/* Enables/disables compression */
algo_type *compress_algos;
/* a list of queued replies that should be sent after a KEX has
concluded (ie, while dataallowed was unset)*/
struct packetlist *reply_queue_head, *reply_queue_tail;
algo_type*(*buf_match_algo)(buffer*buf, algo_type localalgos[],
int *goodguess); /* The function to use to choose which algorithm
to use from the ones presented by the remote
side. Is specific to the client/server mode,
hence the function-pointer callback.*/
void(*remoteclosed)(); /* A callback to handle closure of the
remote connection */
void(*extra_session_cleanup)(); /* client or server specific cleanup */
void(*send_kex_first_guess)();
struct AuthState authstate; /* Common amongst client and server, since most
struct elements are common */
@@ -220,6 +215,13 @@ struct serversession {
/* The numeric address they connected from, used for logging */
char * addrstring;
/* The resolved remote address, used for lastlog etc */
char *remotehost;
#ifdef USE_VFORK
pid_t server_pid;
#endif
};
typedef enum {
@@ -231,10 +233,6 @@ typedef enum {
typedef enum {
STATE_NOTHING,
SERVICE_AUTH_REQ_SENT,
SERVICE_AUTH_ACCEPT_RCVD,
SERVICE_CONN_REQ_SENT,
SERVICE_CONN_ACCEPT_RCVD,
USERAUTH_REQ_SENT,
USERAUTH_FAIL_RCVD,
USERAUTH_SUCCESS_RCVD,
@@ -244,6 +242,7 @@ typedef enum {
struct clientsession {
mp_int *dh_e, *dh_x; /* Used during KEX */
int dh_val_algo; /* KEX algorithm corresponding to current dh_e and dh_x */
cli_kex_state kex_state; /* Used for progressing KEX */
cli_state state; /* Used to progress auth/channelsession etc */
unsigned donefirstkex : 1; /* Set when we set sentnewkeys, never reset */
@@ -257,6 +256,9 @@ struct clientsession {
int stderrcopy;
int stderrflags;
/* for escape char handling */
int last_char;
int winchange; /* Set to 1 when a windowchange signal happens */
int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
@@ -267,8 +269,11 @@ struct clientsession {
int interact_request_received; /* flag whether we've received an
info request from the server for
interactive auth.*/
int cipher_none_after_auth; /* Set to 1 if the user requested "none"
auth */
#endif
struct SignKeyList *lastprivkey;
sign_key *lastprivkey;
int retval; /* What the command exit status was - we emulate it */
#if 0

View File

@@ -40,8 +40,10 @@ sign_key * new_sign_key() {
#ifdef DROPBEAR_RSA
ret->rsakey = NULL;
#endif
ret->filename = NULL;
ret->type = DROPBEAR_SIGNKEY_NONE;
ret->source = SIGNKEY_SOURCE_INVALID;
return ret;
}
/* Returns "ssh-dss" or "ssh-rsa" corresponding to the type. Exits fatally
@@ -60,7 +62,7 @@ const char* signkey_name_from_type(int type, int *namelen) {
return SSH_SIGNKEY_DSS;
}
#endif
dropbear_exit("bad key type %d", type);
dropbear_exit("Bad key type %d", type);
return NULL; /* notreached */
}
@@ -81,6 +83,8 @@ int signkey_type_from_name(const char* name, int namelen) {
}
#endif
TRACE(("signkey_type_from_name unexpected key type."))
return DROPBEAR_SIGNKEY_NONE;
}
@@ -94,15 +98,18 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
int keytype;
int ret = DROPBEAR_FAILURE;
TRACE(("enter buf_get_pub_key"))
TRACE2(("enter buf_get_pub_key"))
ident = buf_getstring(buf, &len);
keytype = signkey_type_from_name(ident, len);
m_free(ident);
if (*type != DROPBEAR_SIGNKEY_ANY && *type != keytype) {
TRACE(("buf_get_pub_key bad type - got %d, expected %d", keytype, *type))
return DROPBEAR_FAILURE;
}
TRACE2(("buf_get_pub_key keytype is %d", keytype))
*type = keytype;
@@ -112,7 +119,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
#ifdef DROPBEAR_DSS
if (keytype == DROPBEAR_SIGNKEY_DSS) {
dss_key_free(key->dsskey);
key->dsskey = (dss_key*)m_malloc(sizeof(dss_key));
key->dsskey = m_malloc(sizeof(*key->dsskey));
ret = buf_get_dss_pub_key(buf, key->dsskey);
if (ret == DROPBEAR_FAILURE) {
m_free(key->dsskey);
@@ -122,7 +129,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
#ifdef DROPBEAR_RSA
if (keytype == DROPBEAR_SIGNKEY_RSA) {
rsa_key_free(key->rsakey);
key->rsakey = (rsa_key*)m_malloc(sizeof(rsa_key));
key->rsakey = m_malloc(sizeof(*key->rsakey));
ret = buf_get_rsa_pub_key(buf, key->rsakey);
if (ret == DROPBEAR_FAILURE) {
m_free(key->rsakey);
@@ -130,7 +137,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
}
#endif
TRACE(("leave buf_get_pub_key"))
TRACE2(("leave buf_get_pub_key"))
return ret;
@@ -146,7 +153,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
int keytype;
int ret = DROPBEAR_FAILURE;
TRACE(("enter buf_get_priv_key"))
TRACE2(("enter buf_get_priv_key"))
ident = buf_getstring(buf, &len);
keytype = signkey_type_from_name(ident, len);
@@ -165,7 +172,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
#ifdef DROPBEAR_DSS
if (keytype == DROPBEAR_SIGNKEY_DSS) {
dss_key_free(key->dsskey);
key->dsskey = (dss_key*)m_malloc(sizeof(dss_key));
key->dsskey = m_malloc(sizeof(*key->dsskey));
ret = buf_get_dss_priv_key(buf, key->dsskey);
if (ret == DROPBEAR_FAILURE) {
m_free(key->dsskey);
@@ -175,7 +182,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
#ifdef DROPBEAR_RSA
if (keytype == DROPBEAR_SIGNKEY_RSA) {
rsa_key_free(key->rsakey);
key->rsakey = (rsa_key*)m_malloc(sizeof(rsa_key));
key->rsakey = m_malloc(sizeof(*key->rsakey));
ret = buf_get_rsa_priv_key(buf, key->rsakey);
if (ret == DROPBEAR_FAILURE) {
m_free(key->rsakey);
@@ -183,7 +190,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
}
#endif
TRACE(("leave buf_get_priv_key"))
TRACE2(("leave buf_get_priv_key"))
return ret;
@@ -194,7 +201,7 @@ void buf_put_pub_key(buffer* buf, sign_key *key, int type) {
buffer *pubkeys;
TRACE(("enter buf_put_pub_key"))
TRACE2(("enter buf_put_pub_key"))
pubkeys = buf_new(MAX_PUBKEY_SIZE);
#ifdef DROPBEAR_DSS
@@ -208,7 +215,7 @@ void buf_put_pub_key(buffer* buf, sign_key *key, int type) {
}
#endif
if (pubkeys->len == 0) {
dropbear_exit("bad key types in buf_put_pub_key");
dropbear_exit("Bad key types in buf_put_pub_key");
}
buf_setpos(pubkeys, 0);
@@ -216,7 +223,7 @@ void buf_put_pub_key(buffer* buf, sign_key *key, int type) {
pubkeys->len);
buf_free(pubkeys);
TRACE(("leave buf_put_pub_key"))
TRACE2(("leave buf_put_pub_key"))
}
/* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
@@ -239,12 +246,12 @@ void buf_put_priv_key(buffer* buf, sign_key *key, int type) {
return;
}
#endif
dropbear_exit("bad key types in put pub key");
dropbear_exit("Bad key types in put pub key");
}
void sign_key_free(sign_key *key) {
TRACE(("enter sign_key_free"))
TRACE2(("enter sign_key_free"))
#ifdef DROPBEAR_DSS
dss_key_free(key->dsskey);
@@ -255,8 +262,10 @@ void sign_key_free(sign_key *key) {
key->rsakey = NULL;
#endif
m_free(key->filename);
m_free(key);
TRACE(("leave sign_key_free"))
TRACE2(("leave sign_key_free"))
}
static char hexdig(unsigned char x) {
@@ -358,7 +367,6 @@ void buf_put_sign(buffer* buf, sign_key *key, int type,
const unsigned char *data, unsigned int len) {
buffer *sigblob;
sigblob = buf_new(MAX_PUBKEY_SIZE);
#ifdef DROPBEAR_DSS
@@ -372,9 +380,8 @@ void buf_put_sign(buffer* buf, sign_key *key, int type,
}
#endif
if (sigblob->len == 0) {
dropbear_exit("non-matching signing type");
dropbear_exit("Non-matching signing type");
}
buf_setpos(sigblob, 0);
buf_putstring(buf, buf_getptr(sigblob, sigblob->len),
sigblob->len);
@@ -405,7 +412,7 @@ int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
memcmp(ident, SSH_SIGNKEY_DSS, identlen) == 0) {
m_free(ident);
if (key->dsskey == NULL) {
dropbear_exit("no dss key to verify signature");
dropbear_exit("No DSS key to verify signature");
}
return buf_dss_verify(buf, key->dsskey, data, len);
}
@@ -415,14 +422,14 @@ int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
if (memcmp(ident, SSH_SIGNKEY_RSA, identlen) == 0) {
m_free(ident);
if (key->rsakey == NULL) {
dropbear_exit("no rsa key to verify signature");
dropbear_exit("No RSA key to verify signature");
}
return buf_rsa_verify(buf, key->rsakey, data, len);
}
#endif
m_free(ident);
dropbear_exit("non-matching signing type");
dropbear_exit("Non-matching signing type");
return DROPBEAR_FAILURE;
}
#endif /* DROPBEAR_SIGNKEY_VERIFY */

View File

@@ -29,13 +29,27 @@
#include "dss.h"
#include "rsa.h"
/* Sources for signing keys */
typedef enum {
SIGNKEY_SOURCE_RAW_FILE,
SIGNKEY_SOURCE_AGENT,
SIGNKEY_SOURCE_INVALID,
} signkey_source;
struct SIGN_key {
int type; /* The type of key (dss or rsa) */
signkey_source source;
char *filename;
/* the buffer? for encrypted keys, so we can later get
* the private key portion */
#ifdef DROPBEAR_DSS
dss_key * dsskey;
dropbear_dss_key * dsskey;
#endif
#ifdef DROPBEAR_RSA
rsa_key * rsakey;
dropbear_rsa_key * rsakey;
#endif
};

11
ssh.h
View File

@@ -105,3 +105,14 @@
#define SSH_SIGNKEY_DSS_LEN 7
#define SSH_SIGNKEY_RSA "ssh-rsa"
#define SSH_SIGNKEY_RSA_LEN 7
/* Agent commands. These aren't part of the spec, and are defined
* only on the openssh implementation. */
#define SSH_AGENT_FAILURE 5
#define SSH_AGENT_SUCCESS 6
#define SSH2_AGENTC_REQUEST_IDENTITIES 11
#define SSH2_AGENT_IDENTITIES_ANSWER 12
#define SSH2_AGENTC_SIGN_REQUEST 13
#define SSH2_AGENT_SIGN_RESPONSE 14
#define SSH2_AGENT_FAILURE 30

View File

@@ -133,7 +133,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
close(*ptyfd);
return 0;
}
#ifndef HAVE_CYGWIN
#if !defined(HAVE_CYGWIN) && defined(I_PUSH)
/*
* Push the appropriate streams modules, as described in Solaris pts(7).
* HP-UX pts(7) doesn't have ttcompat module.
@@ -234,7 +234,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
return 1;
}
dropbear_log(LOG_WARNING, "failed to open any /dev/pty?? devices");
dropbear_log(LOG_WARNING, "Failed to open any /dev/pty?? devices");
return 0;
#endif /* HAVE_DEV_PTS_AND_PTC */
#endif /* USE_DEV_PTMX */

View File

@@ -27,7 +27,7 @@
#include "includes.h"
#ifndef DISABLE_AGENTFWD
#ifdef ENABLE_SVR_AGENTFWD
#include "agentfwd.h"
#include "session.h"
@@ -49,9 +49,8 @@ static void agentaccept(struct Listener * listener, int sock);
/* Handles client requests to start agent forwarding, sets up listening socket.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int agentreq(struct ChanSess * chansess) {
int fd;
int svr_agentreq(struct ChanSess * chansess) {
int fd = -1;
if (!svr_pubkey_allows_agentfwd()) {
return DROPBEAR_FAILURE;
@@ -91,8 +90,9 @@ int agentreq(struct ChanSess * chansess) {
return DROPBEAR_SUCCESS;
fail:
m_close(fd);
/* cleanup */
agentcleanup(chansess);
svr_agentcleanup(chansess);
return DROPBEAR_FAILURE;
}
@@ -118,7 +118,7 @@ static void agentaccept(struct Listener *UNUSED(listener), int sock) {
/* set up the environment variable pointing to the socket. This is called
* just before command/shell execution, after dropping priveleges */
void agentset(struct ChanSess * chansess) {
void svr_agentset(struct ChanSess * chansess) {
char *path = NULL;
int len;
@@ -137,7 +137,7 @@ void agentset(struct ChanSess * chansess) {
}
/* close the socket, remove the socket-file */
void agentcleanup(struct ChanSess * chansess) {
void svr_agentcleanup(struct ChanSess * chansess) {
char *path = NULL;
uid_t uid;
@@ -157,7 +157,7 @@ void agentcleanup(struct ChanSess * chansess) {
gid = getgid();
if ((setegid(ses.authstate.pw_gid)) < 0 ||
(seteuid(ses.authstate.pw_uid)) < 0) {
dropbear_exit("failed to set euid");
dropbear_exit("Failed to set euid");
}
/* 2 for "/" and "\0" */
@@ -172,7 +172,7 @@ void agentcleanup(struct ChanSess * chansess) {
if ((seteuid(uid)) < 0 ||
(setegid(gid)) < 0) {
dropbear_exit("failed to revert euid");
dropbear_exit("Failed to revert euid");
}
m_free(chansess->agentfile);
@@ -181,7 +181,7 @@ void agentcleanup(struct ChanSess * chansess) {
}
static const struct ChanType chan_agent = {
static const struct ChanType chan_svr_agent = {
0, /* sepfds */
"auth-agent@openssh.com",
NULL,
@@ -194,7 +194,7 @@ static const struct ChanType chan_agent = {
/* helper for accepting an agent request */
static int send_msg_channel_open_agent(int fd) {
if (send_msg_channel_open_init(fd, &chan_agent) == DROPBEAR_SUCCESS) {
if (send_msg_channel_open_init(fd, &chan_svr_agent) == DROPBEAR_SUCCESS) {
encrypt_packet();
return DROPBEAR_SUCCESS;
} else {
@@ -220,7 +220,7 @@ static int bindagent(int fd, struct ChanSess * chansess) {
gid = getgid();
if ((setegid(ses.authstate.pw_gid)) < 0 ||
(seteuid(ses.authstate.pw_uid)) < 0) {
dropbear_exit("failed to set euid");
dropbear_exit("Failed to set euid");
}
memset((void*)&addr, 0x0, sizeof(addr));
@@ -263,7 +263,7 @@ bindsocket:
out:
if ((seteuid(uid)) < 0 ||
(setegid(gid)) < 0) {
dropbear_exit("failed to revert euid");
dropbear_exit("Failed to revert euid");
}
return ret;
}

View File

@@ -1,100 +0,0 @@
/*
* Dropbear - a SSH2 server
* SSH client implementation
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "algo.h"
#include "dbutil.h"
/* match the first algorithm in the comma-separated list in buf which is
* also in localalgos[], or return NULL on failure.
* (*goodguess) is set to 1 if the preferred client/server algos match,
* 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
* guessed correctly */
algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
int *goodguess)
{
unsigned char * algolist = NULL;
unsigned char * remotealgos[MAX_PROPOSED_ALGO];
unsigned int len;
unsigned int count, i, j;
algo_type * ret = NULL;
*goodguess = 0;
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
algolist = buf_getstring(buf, &len);
/* Debug this */
TRACE(("buf_match_algo: %s", algolist))
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
goto out; /* just a sanity check, no other use */
}
/* remotealgos will contain a list of the strings parsed out */
/* We will have at least one string (even if it's just "") */
remotealgos[0] = algolist;
count = 1;
/* Iterate through, replacing ','s with NULs, to split it into
* words. */
for (i = 0; i < len; i++) {
if (algolist[i] == '\0') {
/* someone is trying something strange */
goto out;
}
if (algolist[i] == ',') {
algolist[i] = '\0';
remotealgos[count] = &algolist[i+1];
count++;
}
if (count == MAX_PROPOSED_ALGO) {
break;
}
}
/* iterate and find the first match */
for (i = 0; i < count; i++) {
len = strlen(remotealgos[i]);
for (j = 0; localalgos[j].name != NULL; j++) {
if (localalgos[j].usable) {
if (len == strlen(localalgos[j].name) &&
strncmp(localalgos[j].name, remotealgos[i], len) == 0) {
/* set if it was a good guess */
if (i == 0 && j == 0) {
*goodguess = 1;
}
/* set the algo to return */
ret = &localalgos[j];
goto out;
}
}
}
}
out:
m_free(algolist);
return ret;
}

View File

@@ -33,6 +33,7 @@
#include "packet.h"
#include "auth.h"
#include "runopts.h"
#include "random.h"
static void authclear();
static int checkusername(unsigned char *username, unsigned int userlen);
@@ -140,15 +141,6 @@ void recv_msg_userauth_request() {
dropbear_exit("unknown service in auth");
}
/* user wants to know what methods are supported */
if (methodlen == AUTH_METHOD_NONE_LEN &&
strncmp(methodname, AUTH_METHOD_NONE,
AUTH_METHOD_NONE_LEN) == 0) {
TRACE(("recv_msg_userauth_request: 'none' request"))
send_msg_userauth_failure(0, 0);
goto out;
}
/* check username is good before continuing */
if (checkusername(username, userlen) == DROPBEAR_FAILURE) {
/* username is invalid/no shell/etc - send failure */
@@ -157,6 +149,30 @@ void recv_msg_userauth_request() {
goto out;
}
/* user wants to know what methods are supported */
if (methodlen == AUTH_METHOD_NONE_LEN &&
strncmp(methodname, AUTH_METHOD_NONE,
AUTH_METHOD_NONE_LEN) == 0) {
TRACE(("recv_msg_userauth_request: 'none' request"))
if (svr_opts.allowblankpass
&& !svr_opts.noauthpass
&& !(svr_opts.norootpass && ses.authstate.pw_uid == 0)
&& ses.authstate.pw_passwd[0] == '\0')
{
dropbear_log(LOG_NOTICE,
"Auth succeeded with blank password for '%s' from %s",
ses.authstate.pw_name,
svr_ses.addrstring);
send_msg_userauth_success();
goto out;
}
else
{
send_msg_userauth_failure(0, 0);
goto out;
}
}
#ifdef ENABLE_SVR_PASSWORD_AUTH
if (!svr_opts.noauthpass &&
!(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) {
@@ -204,13 +220,13 @@ out:
}
/* Check that the username exists, has a non-empty password, and has a valid
* shell.
/* Check that the username exists and isn't disallowed (root), and has a valid shell.
* returns DROPBEAR_SUCCESS on valid username, DROPBEAR_FAILURE on failure */
static int checkusername(unsigned char *username, unsigned int userlen) {
char* listshell = NULL;
char* usershell = NULL;
int uid;
TRACE(("enter checkusername"))
if (userlen > MAX_USERNAME_LEN) {
return DROPBEAR_FAILURE;
@@ -221,7 +237,7 @@ 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 from %s",
dropbear_log(LOG_WARNING, "Client trying multiple usernames from %s",
svr_ses.addrstring);
m_free(ses.authstate.username);
}
@@ -234,7 +250,19 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
if (!ses.authstate.pw_name) {
TRACE(("leave checkusername: user '%s' doesn't exist", username))
dropbear_log(LOG_WARNING,
"login attempt for nonexistent user from %s",
"Login attempt for nonexistent user from %s",
svr_ses.addrstring);
send_msg_userauth_failure(0, 1);
return DROPBEAR_FAILURE;
}
/* check if we are running as non-root, and login user is different from the server */
uid = geteuid();
if (uid != 0 && uid != ses.authstate.pw_uid) {
TRACE(("running as nonroot, only server uid is allowed"))
dropbear_log(LOG_WARNING,
"Login attempt with wrong user %s from %s",
ses.authstate.pw_name,
svr_ses.addrstring);
send_msg_userauth_failure(0, 1);
return DROPBEAR_FAILURE;
@@ -248,15 +276,6 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
return DROPBEAR_FAILURE;
}
/* check for an empty password */
if (ses.authstate.pw_passwd[0] == '\0') {
TRACE(("leave checkusername: empty pword"))
dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected",
ses.authstate.pw_name);
send_msg_userauth_failure(0, 1);
return DROPBEAR_FAILURE;
}
TRACE(("shell is %s", ses.authstate.pw_shell))
/* check that the shell is set */
@@ -280,7 +299,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
/* no matching shell */
endusershell();
TRACE(("no matching shell"))
dropbear_log(LOG_WARNING, "user '%s' has invalid shell, rejected",
dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected",
ses.authstate.pw_name);
send_msg_userauth_failure(0, 1);
return DROPBEAR_FAILURE;
@@ -337,7 +356,11 @@ void send_msg_userauth_failure(int partial, int incrfail) {
encrypt_packet();
if (incrfail) {
usleep(300000); /* XXX improve this */
unsigned int delay;
genrandom((unsigned char*)&delay, sizeof(delay));
/* We delay for 300ms +- 50ms, 0.1ms granularity */
delay = 250000 + (delay % 1000)*100;
usleep(delay);
ses.authstate.failcount++;
}

View File

@@ -56,11 +56,7 @@ pamConvFunc(int num_msg,
struct UserDataS* userDatap = (struct UserDataS*) appdata_ptr;
unsigned int msg_len = 0;
unsigned int i = 0;
const char* message = (*msg)->msg;
/* make a copy we can strip */
char * compare_message = m_strdup(message);
char * compare_message = NULL;
TRACE(("enter pamConvFunc"))
@@ -71,15 +67,10 @@ pamConvFunc(int num_msg,
dropbear_log(LOG_INFO, "pamConvFunc() called with >1 messages: not supported.");
return PAM_CONV_ERR;
}
/* make a copy we can strip */
compare_message = m_strdup((*msg)->msg);
TRACE(("msg_style is %d", (*msg)->msg_style))
if (compare_message) {
TRACE(("message is '%s'", compare_message))
} else {
TRACE(("null message"))
}
/* Make the string lowercase. */
msg_len = strlen(compare_message);
for (i = 0; i < msg_len; i++) {
@@ -101,8 +92,9 @@ pamConvFunc(int num_msg,
if (!(strcmp(compare_message, "password:") == 0)) {
/* We don't recognise the prompt as asking for a password,
so can't handle it. Add more above as required for
different pam modules/implementations */
dropbear_log(LOG_NOTICE, "PAM unknown prompt %s (no echo)",
different pam modules/implementations. If you need
to add an entry here please mail the Dropbear developer */
dropbear_log(LOG_NOTICE, "PAM unknown prompt '%s' (no echo)",
compare_message);
rc = PAM_CONV_ERR;
break;
@@ -123,12 +115,16 @@ pamConvFunc(int num_msg,
case PAM_PROMPT_ECHO_ON:
if (!((strcmp(compare_message, "login:" ) == 0)
|| (strcmp(compare_message, "please enter username:") == 0))) {
if (!(
(strcmp(compare_message, "login:" ) == 0)
|| (strcmp(compare_message, "please enter username:") == 0)
|| (strcmp(compare_message, "username:") == 0)
)) {
/* We don't recognise the prompt as asking for a username,
so can't handle it. Add more above as required for
different pam modules/implementations */
dropbear_log(LOG_NOTICE, "PAM unknown prompt %s (with echo)",
different pam modules/implementations. If you need
to add an entry here please mail the Dropbear developer */
dropbear_log(LOG_NOTICE, "PAM unknown prompt '%s' (with echo)",
compare_message);
rc = PAM_CONV_ERR;
break;
@@ -212,7 +208,10 @@ void svr_auth_pam() {
goto cleanup;
}
#ifdef HAVE_PAM_FAIL_DELAY
/* We have our own random delay code already, disable PAM's */
(void) pam_fail_delay(pamHandlep, 0 /* musec_delay */);
#endif
/* (void) pam_set_item(pamHandlep, PAM_FAIL_DELAY, (void*) pamDelayFunc); */
@@ -220,7 +219,7 @@ void svr_auth_pam() {
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",
"Bad PAM password attempt for '%s' from %s",
ses.authstate.pw_name,
svr_ses.addrstring);
send_msg_userauth_failure(0, 1);
@@ -231,7 +230,7 @@ void svr_auth_pam() {
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",
"Bad PAM password attempt for '%s' from %s",
ses.authstate.pw_name,
svr_ses.addrstring);
send_msg_userauth_failure(0, 1);

View File

@@ -29,6 +29,7 @@
#include "buffer.h"
#include "dbutil.h"
#include "auth.h"
#include "runopts.h"
#ifdef ENABLE_SVR_PASSWORD_AUTH
@@ -36,9 +37,6 @@
* appropriate */
void svr_auth_password() {
#ifdef HAVE_SHADOW_H
struct spwd *spasswd = NULL;
#endif
char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */
char * testcrypt = NULL; /* crypt generated from the user's password sent */
unsigned char * password;
@@ -47,29 +45,12 @@ void svr_auth_password() {
unsigned int changepw;
passwdcrypt = ses.authstate.pw_passwd;
#ifdef HAVE_SHADOW_H
/* get the shadow password if possible */
spasswd = getspnam(ses.authstate.pw_name);
if (spasswd != NULL && spasswd->sp_pwdp != NULL) {
passwdcrypt = spasswd->sp_pwdp;
}
#endif
#ifdef DEBUG_HACKCRYPT
/* debugging crypt for non-root testing with shadows */
passwdcrypt = DEBUG_HACKCRYPT;
#endif
/* check for empty password - need to do this again here
* since the shadow password may differ to that tested
* in auth.c */
if (passwdcrypt[0] == '\0') {
dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected",
ses.authstate.pw_name);
send_msg_userauth_failure(0, 1);
return;
}
/* check if client wants to change password */
changepw = buf_getbool(ses.payload);
if (changepw) {
@@ -85,21 +66,28 @@ void svr_auth_password() {
m_burn(password, passwordlen);
m_free(password);
/* check for empty password */
if (passwdcrypt[0] == '\0') {
dropbear_log(LOG_WARNING, "User '%s' has blank password, rejected",
ses.authstate.pw_name);
send_msg_userauth_failure(0, 1);
return;
}
if (strcmp(testcrypt, passwdcrypt) == 0) {
/* successful authentication */
dropbear_log(LOG_NOTICE,
"password auth succeeded for '%s' from %s",
"Password auth succeeded for '%s' from %s",
ses.authstate.pw_name,
svr_ses.addrstring);
send_msg_userauth_success();
} else {
dropbear_log(LOG_WARNING,
"bad password attempt for '%s' from %s",
"Bad password attempt for '%s' from %s",
ses.authstate.pw_name,
svr_ses.addrstring);
send_msg_userauth_failure(0, 1);
}
}
#endif

View File

@@ -135,12 +135,12 @@ 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 from %s",
"Pubkey auth succeeded for '%s' with key %s from %s",
ses.authstate.pw_name, fp, svr_ses.addrstring);
send_msg_userauth_success();
} else {
dropbear_log(LOG_WARNING,
"pubkey auth bad signature for '%s' with key %s from %s",
"Pubkey auth bad signature for '%s' with key %s from %s",
ses.authstate.pw_name, fp, svr_ses.addrstring);
send_msg_userauth_failure(0, 1);
}
@@ -198,7 +198,7 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
/* 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' from %s",
"Pubkey auth attempt with unknown algo for '%s' from %s",
ses.authstate.pw_name, svr_ses.addrstring);
goto out;
}

View File

@@ -88,10 +88,21 @@ int svr_pubkey_allows_pty() {
return 1;
}
/* Set chansession command to the one forced by 'command' public key option */
/* Set chansession command to the one forced
* by any 'command' public key option. */
void svr_pubkey_set_forced_command(struct ChanSess *chansess) {
if (ses.authstate.pubkey_options)
chansess->cmd = ses.authstate.pubkey_options->forced_command;
if (ses.authstate.pubkey_options) {
if (chansess->cmd) {
/* original_command takes ownership */
chansess->original_command = chansess->cmd;
} else {
chansess->original_command = m_strdup("");
}
chansess->cmd = m_strdup(ses.authstate.pubkey_options->forced_command);
#ifdef LOG_COMMANDS
dropbear_log(LOG_INFO, "Command forced to '%s'", chansess->original_command);
#endif
}
}
/* Free potential public key options */
@@ -124,7 +135,6 @@ int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filena
TRACE(("enter addpubkeyoptions"))
ses.authstate.pubkey_options = (struct PubKeyOptions*)m_malloc(sizeof( struct PubKeyOptions ));
memset(ses.authstate.pubkey_options, '\0', sizeof(*ses.authstate.pubkey_options));
buf_setpos(options_buf, 0);
while (options_buf->pos < options_buf->len) {
@@ -133,7 +143,7 @@ int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filena
ses.authstate.pubkey_options->no_port_forwarding_flag = 1;
goto next_option;
}
#ifdef ENABLE_AGENTFWD
#ifdef ENABLE_SVR_AGENTFWD
if (match_option(options_buf, "no-agent-forwarding") == DROPBEAR_SUCCESS) {
dropbear_log(LOG_WARNING, "Agent forwarding disabled.");
ses.authstate.pubkey_options->no_agent_forwarding_flag = 1;

View File

@@ -33,7 +33,6 @@
#include "termcodes.h"
#include "ssh.h"
#include "random.h"
#include "utmp.h"
#include "x11fwd.h"
#include "agentfwd.h"
#include "runopts.h"
@@ -138,6 +137,7 @@ static void sesssigchild_handler(int UNUSED(dummy)) {
sa_chld.sa_handler = sesssigchild_handler;
sa_chld.sa_flags = SA_NOCLDSTOP;
sigemptyset(&sa_chld.sa_mask);
sigaction(SIGCHLD, &sa_chld, NULL);
TRACE(("leave sigchld handler"))
}
@@ -218,10 +218,13 @@ static int newchansess(struct Channel *channel) {
struct ChanSess *chansess;
TRACE(("new chansess %p", channel))
dropbear_assert(channel->typedata == NULL);
chansess = (struct ChanSess*)m_malloc(sizeof(struct ChanSess));
chansess->cmd = NULL;
chansess->connection_string = NULL;
chansess->pid = 0;
/* pty details */
@@ -240,7 +243,7 @@ static int newchansess(struct Channel *channel) {
chansess->x11authcookie = NULL;
#endif
#ifndef DISABLE_AGENTFWD
#ifdef ENABLE_SVR_AGENTFWD
chansess->agentlistener = NULL;
chansess->agentfile = NULL;
chansess->agentdir = NULL;
@@ -250,6 +253,14 @@ static int newchansess(struct Channel *channel) {
}
static struct logininfo*
chansess_login_alloc(struct ChanSess *chansess) {
struct logininfo * li;
li = login_alloc_entry(chansess->pid, ses.authstate.username,
svr_ses.remotehost, chansess->tty);
return li;
}
/* clean a session channel */
static void closechansess(struct Channel *channel) {
@@ -271,10 +282,13 @@ static void closechansess(struct Channel *channel) {
m_free(chansess->cmd);
m_free(chansess->term);
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
m_free(chansess->original_command);
#endif
if (chansess->tty) {
/* write the utmp/wtmp login record */
li = login_alloc_entry(chansess->pid, ses.authstate.username,
ses.remotehost, chansess->tty);
li = chansess_login_alloc(chansess);
login_logout(li);
login_free_entry(li);
@@ -286,8 +300,8 @@ static void closechansess(struct Channel *channel) {
x11cleanup(chansess);
#endif
#ifndef DISABLE_AGENTFWD
agentcleanup(chansess);
#ifdef ENABLE_SVR_AGENTFWD
svr_agentcleanup(chansess);
#endif
/* clear child pid entries */
@@ -344,9 +358,9 @@ static void chansessionrequest(struct Channel *channel) {
} else if (strcmp(type, "x11-req") == 0) {
ret = x11req(chansess);
#endif
#ifndef DISABLE_AGENTFWD
#ifdef ENABLE_SVR_AGENTFWD
} else if (strcmp(type, "auth-agent-req@openssh.com") == 0) {
ret = agentreq(chansess);
ret = svr_agentreq(chansess);
#endif
} else if (strcmp(type, "signal") == 0) {
ret = sessionsignal(chansess);
@@ -448,7 +462,7 @@ static void get_termmodes(struct ChanSess *chansess) {
TRACE(("term mode str %d p->l %d p->p %d",
len, ses.payload->len , ses.payload->pos));
if (len != ses.payload->len - ses.payload->pos) {
dropbear_exit("bad term mode string");
dropbear_exit("Bad term mode string");
}
if (len == 0) {
@@ -513,7 +527,7 @@ static void get_termmodes(struct ChanSess *chansess) {
}
}
if (tcsetattr(chansess->master, TCSANOW, &termio) < 0) {
dropbear_log(LOG_INFO, "error setting terminal attributes");
dropbear_log(LOG_INFO, "Error setting terminal attributes");
}
TRACE(("leave get_termmodes"))
}
@@ -543,7 +557,7 @@ static int sessionpty(struct ChanSess * chansess) {
/* allocate the pty */
if (chansess->master != -1) {
dropbear_exit("multiple pty requests");
dropbear_exit("Multiple pty requests");
}
if (pty_allocate(&chansess->master, &chansess->slave, namebuf, 64) == 0) {
TRACE(("leave sessionpty: failed to allocate pty"))
@@ -552,7 +566,7 @@ static int sessionpty(struct ChanSess * chansess) {
chansess->tty = (char*)m_strdup(namebuf);
if (!chansess->tty) {
dropbear_exit("out of memory"); /* TODO disconnect */
dropbear_exit("Out of memory"); /* TODO disconnect */
}
pw = getpwnam(ses.authstate.pw_name);
@@ -570,6 +584,21 @@ static int sessionpty(struct ChanSess * chansess) {
return DROPBEAR_SUCCESS;
}
static char* make_connection_string() {
char *local_ip, *local_port, *remote_ip, *remote_port;
size_t len;
char *ret;
get_socket_address(ses.sock_in, &local_ip, &local_port, &remote_ip, &remote_port, 0);
len = strlen(local_ip) + strlen(local_port) + strlen(remote_ip) + strlen(remote_port) + 4;
ret = m_malloc(len);
snprintf(ret, len, "%s %s %s %s", remote_ip, remote_port, local_ip, local_port);
m_free(local_ip);
m_free(local_port);
m_free(remote_ip);
m_free(remote_port);
return ret;
}
/* Handle a command request from the client. This is used for both shell
* and command-execution requests, and passes the command to
* noptycommand or ptycommand as appropriate.
@@ -589,9 +618,6 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
return DROPBEAR_FAILURE;
}
/* take public key option 'command' into account */
svr_pubkey_set_forced_command(chansess);
if (iscmd) {
/* "exec" */
if (chansess->cmd == NULL) {
@@ -616,17 +642,26 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
}
}
}
/* take public key option 'command' into account */
svr_pubkey_set_forced_command(chansess);
#ifdef LOG_COMMANDS
if (chansess->cmd) {
dropbear_log(LOG_INFO, "user %s executing '%s'",
dropbear_log(LOG_INFO, "User %s executing '%s'",
ses.authstate.pw_name, chansess->cmd);
} else {
dropbear_log(LOG_INFO, "user %s executing login shell",
dropbear_log(LOG_INFO, "User %s executing login shell",
ses.authstate.pw_name);
}
#endif
/* uClinux will vfork(), so there'll be a race as
connection_string is freed below. */
#ifndef USE_VFORK
chansess->connection_string = make_connection_string();
#endif
if (chansess->term == NULL) {
/* no pty */
ret = noptycommand(channel, chansess);
@@ -635,6 +670,10 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
ret = ptycommand(channel, chansess);
}
#ifndef USE_VFORK
m_free(chansess->connection_string);
#endif
if (ret == DROPBEAR_FAILURE) {
m_free(chansess->cmd);
}
@@ -660,6 +699,8 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) {
ses.maxfd = MAX(ses.maxfd, channel->readfd);
ses.maxfd = MAX(ses.maxfd, channel->errfd);
sleep(1);
addchildpid(chansess, chansess->pid);
if (svr_ses.lastexit.exitpid != -1) {
@@ -673,6 +714,7 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) {
TRACE(("found match for lastexitpid"))
svr_ses.childpids[i].chansess->exit = svr_ses.lastexit;
svr_ses.lastexit.exitpid = -1;
break;
}
}
}
@@ -699,11 +741,11 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
/* we need to have a pty allocated */
if (chansess->master == -1 || chansess->tty == NULL) {
dropbear_log(LOG_WARNING, "no pty was allocated, couldn't execute");
dropbear_log(LOG_WARNING, "No pty was allocated, couldn't execute");
return DROPBEAR_FAILURE;
}
#ifdef __uClinux__
#ifdef USE_VFORK
pid = vfork();
#else
pid = fork();
@@ -736,13 +778,10 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
/* write the utmp/wtmp login record - must be after changing the
* terminal used for stdout with the dup2 above */
li= login_alloc_entry(getpid(), ses.authstate.username,
ses.remotehost, chansess->tty);
li = chansess_login_alloc(chansess);
login_login(li);
login_free_entry(li);
m_free(chansess->tty);
#ifdef DO_MOTD
if (svr_opts.domotd) {
/* don't show the motd if ~/.hushlogin exists */
@@ -824,15 +863,15 @@ static void execchild(void *user_data) {
struct ChanSess *chansess = user_data;
char *usershell = NULL;
/* with uClinux we'll have vfork()ed, so don't want to overwrite the
* hostkey. can't think of a workaround to clear it */
#ifndef __uClinux__
/* with uClinux we'll have vfork()ed, so don't want to overwrite the
* hostkey. can't think of a workaround to clear it */
#ifndef USE_VFORK
/* wipe the hostkey */
sign_key_free(svr_opts.hostkey);
svr_opts.hostkey = NULL;
/* overwrite the prng state */
reseedrandom();
seedrandom();
#endif
/* clear environment */
@@ -855,10 +894,10 @@ static void execchild(void *user_data) {
if ((setgid(ses.authstate.pw_gid) < 0) ||
(initgroups(ses.authstate.pw_name,
ses.authstate.pw_gid) < 0)) {
dropbear_exit("error changing user group");
dropbear_exit("Error changing user group");
}
if (setuid(ses.authstate.pw_uid) < 0) {
dropbear_exit("error changing user");
dropbear_exit("Error changing user");
}
} else {
/* ... but if the daemon is the same uid as the requested uid, we don't
@@ -869,7 +908,7 @@ static void execchild(void *user_data) {
* differing groups won't be set (as with initgroups()). The solution
* is for the sysadmin not to give out the UID twice */
if (getuid() != ses.authstate.pw_uid) {
dropbear_exit("couldn't change user as non-root");
dropbear_exit("Couldn't change user as non-root");
}
}
@@ -883,25 +922,39 @@ static void execchild(void *user_data) {
addnewvar("TERM", chansess->term);
}
if (chansess->tty) {
addnewvar("SSH_TTY", chansess->tty);
}
if (chansess->connection_string) {
addnewvar("SSH_CONNECTION", chansess->connection_string);
}
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
if (chansess->original_command) {
addnewvar("SSH_ORIGINAL_COMMAND", chansess->original_command);
}
#endif
/* change directory */
if (chdir(ses.authstate.pw_dir) < 0) {
dropbear_exit("error changing directory");
dropbear_exit("Error changing directory");
}
#ifndef DISABLE_X11FWD
/* set up X11 forwarding if enabled */
x11setauth(chansess);
#endif
#ifndef DISABLE_AGENTFWD
#ifdef ENABLE_SVR_AGENTFWD
/* set up agent env variable */
agentset(chansess);
svr_agentset(chansess);
#endif
usershell = m_strdup(get_user_shell());
run_shell_command(chansess->cmd, ses.maxfd, usershell);
/* only reached on error */
dropbear_exit("child failed");
dropbear_exit("Child failed");
}
const struct ChanType svrchansess = {
@@ -928,6 +981,7 @@ void svr_chansessinitialise() {
svr_ses.lastexit.exitpid = -1; /* Nothing has exited yet */
sa_chld.sa_handler = sesssigchild_handler;
sa_chld.sa_flags = SA_NOCLDSTOP;
sigemptyset(&sa_chld.sa_mask);
if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) {
dropbear_exit("signal() error");
}

View File

@@ -61,7 +61,8 @@ void recv_msg_kexdh_init() {
mp_clear(&dh_e);
send_msg_newkeys();
ses.requirenext = SSH_MSG_NEWKEYS;
ses.requirenext[0] = SSH_MSG_NEWKEYS;
ses.requirenext[1] = 0;
TRACE(("leave recv_msg_kexdh_init"))
}
@@ -70,7 +71,7 @@ void recv_msg_kexdh_init() {
* that, the session hash is calculated, and signed with RSA or DSS. The
* result is sent to the client.
*
* See the ietf-secsh-transport draft, section 6, for details */
* See the transport rfc 4253 section 8 for details */
static void send_msg_kexdh_reply(mp_int *dh_e) {
DEF_MP_INT(dh_y);

View File

@@ -77,22 +77,16 @@ int main(int argc, char ** argv)
#ifdef INETD_MODE
static void main_inetd() {
struct sockaddr_storage remoteaddr;
socklen_t remoteaddrlen;
char * addrstring = NULL;
char *host, *port = NULL;
/* Set up handlers, syslog, seed random */
commonsetup();
remoteaddrlen = sizeof(remoteaddr);
if (getpeername(0, (struct sockaddr*)&remoteaddr, &remoteaddrlen) < 0) {
dropbear_exit("Unable to getpeername: %s", strerror(errno));
}
/* In case our inetd was lax in logging source addresses */
addrstring = getaddrstring(&remoteaddr, 1);
dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
get_socket_address(0, NULL, NULL, &host, &port, 0);
dropbear_log(LOG_INFO, "Child connection from %s:%s", host, port);
m_free(host);
m_free(port);
/* Don't check the return value - it may just fail since inetd has
* already done setsid() after forking (xinetd on Darwin appears to do
@@ -102,7 +96,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), addrstring);
svr_session(0, -1);
/* notreached */
}
@@ -133,7 +127,7 @@ void main_noinetd() {
for (i = 0; i < MAX_UNAUTH_CLIENTS; i++) {
childpipes[i] = -1;
}
bzero(preauth_addrs, sizeof(preauth_addrs));
memset(preauth_addrs, 0x0, sizeof(preauth_addrs));
/* Set up the listening sockets */
listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock);
@@ -218,14 +212,13 @@ void main_noinetd() {
/* handle each socket which has something to say */
for (i = 0; i < listensockcount; i++) {
struct sockaddr_storage remoteaddr;
socklen_t remoteaddrlen = 0;
size_t num_unauthed_for_addr = 0;
size_t num_unauthed_total = 0;
char * remote_addr_str = NULL;
char *remote_host = NULL, *remote_port = NULL;
pid_t fork_ret = 0;
size_t conn_idx = 0;
struct sockaddr_storage remoteaddr;
socklen_t remoteaddrlen;
if (!FD_ISSET(listensocks[i], &fds))
continue;
@@ -240,14 +233,14 @@ void main_noinetd() {
}
/* Limit the number of unauthenticated connections per IP */
remote_addr_str = getaddrstring(&remoteaddr, 0);
getaddrstring(&remoteaddr, &remote_host, NULL, 0);
num_unauthed_for_addr = 0;
num_unauthed_total = 0;
for (j = 0; j < MAX_UNAUTH_CLIENTS; j++) {
if (childpipes[j] >= 0) {
num_unauthed_total++;
if (strcmp(remote_addr_str, preauth_addrs[j]) == 0) {
if (strcmp(remote_host, preauth_addrs[j]) == 0) {
num_unauthed_for_addr++;
}
} else {
@@ -261,6 +254,8 @@ void main_noinetd() {
goto out;
}
seedrandom();
if (pipe(childpipe) < 0) {
TRACE(("error creating child pipe"))
goto out;
@@ -272,29 +267,32 @@ void main_noinetd() {
fork_ret = fork();
#endif
if (fork_ret < 0) {
dropbear_log(LOG_WARNING, "error forking: %s", strerror(errno));
dropbear_log(LOG_WARNING, "Error forking: %s", strerror(errno));
goto out;
}
} else if (fork_ret > 0) {
addrandom((void*)&fork_ret, sizeof(fork_ret));
if (fork_ret > 0) {
/* parent */
childpipes[conn_idx] = childpipe[0];
m_close(childpipe[1]);
preauth_addrs[conn_idx] = remote_addr_str;
remote_addr_str = NULL;
preauth_addrs[conn_idx] = remote_host;
remote_host = NULL;
} else {
/* child */
char * addrstring = NULL;
#ifdef DEBUG_FORKGPROF
extern void _start(void), etext(void);
monstartup((u_long)&_start, (u_long)&etext);
#endif /* DEBUG_FORKGPROF */
m_free(remote_addr_str);
addrstring = getaddrstring(&remoteaddr, 1);
dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
getaddrstring(&remoteaddr, NULL, &remote_port, 0);
dropbear_log(LOG_INFO, "Child connection from %s:%s", remote_host, remote_port);
m_free(remote_host);
m_free(remote_port);
#ifndef DEBUG_NOFORK
if (setsid() < 0) {
@@ -310,9 +308,7 @@ void main_noinetd() {
m_close(childpipe[0]);
/* start the session */
svr_session(childsock, childpipe[1],
getaddrhostname(&remoteaddr),
addrstring);
svr_session(childsock, childpipe[1]);
/* don't return */
dropbear_assert(0);
}
@@ -320,8 +316,8 @@ void main_noinetd() {
out:
/* This section is important for the parent too */
m_close(childsock);
if (remote_addr_str) {
m_free(remote_addr_str);
if (remote_host) {
m_free(remote_host);
}
}
} /* for(;;) loop */
@@ -379,6 +375,7 @@ static void commonsetup() {
/* catch and reap zombie children */
sa_chld.sa_handler = sigchld_handler;
sa_chld.sa_flags = SA_NOCLDSTOP;
sigemptyset(&sa_chld.sa_mask);
if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) {
dropbear_exit("signal() error");
}

View File

@@ -36,18 +36,17 @@ static void addportandaddress(char* spec);
static void printhelp(const char * progname) {
fprintf(stderr, "Dropbear sshd v%s\n"
fprintf(stderr, "Dropbear server v%s https://matt.ucc.asn.au/dropbear/dropbear.html\n"
"Usage: %s [options]\n"
"Options are:\n"
"-b bannerfile Display the contents of bannerfile"
" before user login\n"
" (default: none)\n"
#ifdef DROPBEAR_DSS
"-d dsskeyfile Use dsskeyfile for the dss host key\n"
"-d dsskeyfile Use dsskeyfile for the DSS host key\n"
" (default: %s)\n"
#endif
#ifdef DROPBEAR_RSA
"-r rsakeyfile Use rsakeyfile for the rsa host key\n"
"-r rsakeyfile Use rsakeyfile for the RSA host key\n"
" (default: %s)\n"
#endif
"-F Don't fork into background\n"
@@ -63,6 +62,7 @@ static void printhelp(const char * progname) {
#if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
"-s Disable password logins\n"
"-g Disable password logins for root\n"
"-B Allow blank password logins\n"
#endif
#ifdef ENABLE_SVR_LOCALTCPFWD
"-j Disable local port forwarding\n"
@@ -81,8 +81,8 @@ static void printhelp(const char * progname) {
"-i Start for inetd\n"
#endif
"-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
"-K <keepalive> (0 is never, default %d)\n"
"-I <idle_timeout> (0 is never, default %d)\n"
"-K <keepalive> (0 is never, default %d, in seconds)\n"
"-I <idle_timeout> (0 is never, default %d, in seconds)\n"
#ifdef DEBUG_TRACE
"-v verbose (compiled with DEBUG_TRACE)\n"
#endif
@@ -115,6 +115,7 @@ void svr_getopts(int argc, char ** argv) {
svr_opts.norootlogin = 0;
svr_opts.noauthpass = 0;
svr_opts.norootpass = 0;
svr_opts.allowblankpass = 0;
svr_opts.inetdmode = 0;
svr_opts.portcount = 0;
svr_opts.hostkey = NULL;
@@ -124,6 +125,9 @@ void svr_getopts(int argc, char ** argv) {
#endif
#ifdef ENABLE_SVR_REMOTETCPFWD
svr_opts.noremotetcp = 0;
#endif
#ifndef DISABLE_ZLIB
opts.enable_compress = 1;
#endif
/* not yet
opts.ipv4 = 1;
@@ -231,6 +235,9 @@ void svr_getopts(int argc, char ** argv) {
case 'g':
svr_opts.norootpass = 1;
break;
case 'B':
svr_opts.allowblankpass = 1;
break;
#endif
case 'h':
printhelp(argv[0]);
@@ -296,15 +303,19 @@ void svr_getopts(int argc, char ** argv) {
}
if (keepalive_arg) {
if (m_str_to_uint(keepalive_arg, &opts.keepalive_secs) == DROPBEAR_FAILURE) {
unsigned int val;
if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
dropbear_exit("Bad keepalive '%s'", keepalive_arg);
}
opts.keepalive_secs = val;
}
if (idle_timeout_arg) {
if (m_str_to_uint(idle_timeout_arg, &opts.idle_timeout_secs) == DROPBEAR_FAILURE) {
unsigned int val;
if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
}
opts.idle_timeout_secs = val;
}
}
@@ -317,8 +328,23 @@ static void addportandaddress(char* spec) {
/* We don't free it, it becomes part of the runopt state */
myspec = m_strdup(spec);
/* search for ':', that separates address and port */
svr_opts.ports[svr_opts.portcount] = strchr(myspec, ':');
if (myspec[0] == '[') {
myspec++;
svr_opts.ports[svr_opts.portcount] = strchr(myspec, ']');
if (svr_opts.ports[svr_opts.portcount] == NULL) {
/* Unmatched [ -> exit */
dropbear_exit("Bad listen address");
}
svr_opts.ports[svr_opts.portcount][0] = '\0';
svr_opts.ports[svr_opts.portcount]++;
if (svr_opts.ports[svr_opts.portcount][0] != ':') {
/* Missing port -> exit */
dropbear_exit("Missing port");
}
} else {
/* search for ':', that separates address and port */
svr_opts.ports[svr_opts.portcount] = strrchr(myspec, ':');
}
if (svr_opts.ports[svr_opts.portcount] == NULL) {
/* no ':' -> the whole string specifies just a port */

Some files were not shown because too many files have changed in this diff Show More