Compare commits

...

294 Commits

Author SHA1 Message Date
Matt Johnston
8c53621c24 update for 2016.73 2016-03-18 22:44:36 +08:00
Matt Johnston
514baf3bf7 Fix whitespace missed in merge 2016-03-18 20:43:22 +08:00
Matt Johnston
420151dbd9 move m_burn and function attributes to dbhelpers
use m_burn for libtomcrypt zeromem() too
2016-03-17 23:21:33 +08:00
Matt Johnston
156b28c771 Fix missing paths from m_burn commit 2016-03-17 06:40:31 +08:00
Matt Johnston
ad801851a2 use m_burn for mp_clear 2016-03-17 00:06:26 +08:00
Matt Johnston
b647b753e0 Use memset_s or explicit_bzero 2016-03-16 23:39:39 +08:00
Matt Johnston
48b855c581 add CVE 2016-03-16 23:04:55 +08:00
Matt Johnston
c830d30553 merge 2016-03-16 22:53:27 +08:00
Francois Perrad
0650182289 add the idiomatic do/while(0) in the macro SCREWUP 2016-03-16 22:41:20 +08:00
Francois Perrad
3e20c442de fix empty C prototypes 2016-03-16 22:41:20 +08:00
Francois Perrad
af87369cb3 add static in function definition
like in function declaration
2016-03-16 22:41:19 +08:00
Francois Perrad
edea73b1f8 add parentheses to macro 2016-03-16 22:41:19 +08:00
Francois Perrad
893d7be5bf const variables 2016-03-16 22:41:19 +08:00
Francois Perrad
c5b77e1b49 explicitly initialization of static variables 2016-03-16 22:41:19 +08:00
Francois Perrad
a5e5bab74b Suspicious use of ; 2016-03-16 22:41:19 +08:00
Francois Perrad
8f96b8908e rename loop variable
2 nested loops with the same variable 'i',
line 219 and line 309
2016-03-16 22:41:19 +08:00
Francois Perrad
f3a6dd139c Suspicious use of & 2016-03-16 22:41:19 +08:00
Francois Perrad
1dba0d4830 add comment FALLTHROUGH which recognize by many lint tools 2016-03-16 22:41:19 +08:00
Francois Perrad
da85400e57 put default in switch/case 2016-03-16 22:41:19 +08:00
Francois Perrad
7f38caefd0 remove unreachable code 2016-03-16 22:41:19 +08:00
Francois Perrad
937594c130 use #ifdef like everywhere 2016-03-16 22:41:05 +08:00
Matt Johnston
3e7672edca merge 2016-03-15 23:23:31 +08:00
Matt Johnston
098aba47c3 assertion for case that shouldn't happen 2016-03-15 23:20:01 +08:00
Matt Johnston
c67fc5693a m_close() rather than close() 2016-03-15 23:03:59 +08:00
Matt Johnston
6b5c6af613 ignore return value from fcntl() 2016-03-15 23:03:43 +08:00
Matt Johnston
3ccc36b3b7 Fix truncated type for getc() at confirmation prompt 2016-03-15 23:03:31 +08:00
Matt Johnston
e7828bb911 cast return type to enum 2016-03-15 22:40:15 +08:00
Matt Johnston
e255f0590b remove unused loginrec_set_addr() 2016-03-15 22:04:13 +08:00
Matt Johnston
4615631d83 update CHANGES 2016-03-15 22:03:23 +08:00
Matt Johnston
e708f9542f Merge pull request #23 from Chocobo1/travis_fix
TravisCI: re-enable MULTI=1 & NOWRITEV=1 builds on OSX
2016-03-15 21:55:11 +08:00
Matt Johnston
6bfbcdbfdb Merge branch 'fperrad-20151231_indent' 2016-03-15 21:41:22 +08:00
Matt Johnston
645b254173 Merge branch '20151231_indent' of https://github.com/fperrad/dropbear into fperrad-20151231_indent 2016-03-15 21:41:06 +08:00
Matt Johnston
fdc61f3ab2 Get rid of group15, move group16 to sha512.
New groups are disabled by default pending
draft-ietf-curdle-ssh-kex-sha2-02 being finalised
2016-03-12 16:21:13 +08:00
Matt Johnston
a991d3b56b merge github master 2016-03-10 21:37:35 +08:00
Matt Johnston
26a1a0a3bc allow specifying dropbearmulti command as an argument 2016-03-10 21:35:23 +08:00
Matt Johnston
73bc3a9853 merge 2016.72 2016-03-10 20:57:47 +08:00
Matt Johnston
9cb325ee6f Added signature for changeset fd1981f41c62 2016-03-10 20:50:31 +08:00
Matt Johnston
9e1d038a65 Added tag DROPBEAR_2016.72 for changeset 78b12b6549be 2016-03-10 20:50:24 +08:00
Matt Johnston
7e5fe1d813 debian changelog 2016-03-09 22:54:51 +08:00
Matt Johnston
97dff151ae 2016.72 2016-03-09 22:54:15 +08:00
Matt Johnston
18681875e3 Validate xauth input 2016-03-09 22:45:40 +08:00
Chocobo1
9b0a2714f0 TravisCI: re-enable MULTI=1 & NOWRITEV=1 builds on OSX, fixes d416a9b 2016-01-21 00:21:39 +08:00
Matt Johnston
a84ce21aec Merge pull request #22 from Chocobo1/travis
TravisCI: Improvements
2016-01-20 21:36:58 +08:00
Matt Johnston
1fc1559d15 Merge pull request #21 from Chocobo1/fix
Fix warnings
2016-01-20 21:24:36 +08:00
Matt Johnston
de70b02c2f Don't fail if can't get the username 2016-01-19 00:34:37 +08:00
Michael Witten
6453b5b70e scp: Have `fatal()' append a newline to the message
Date: Wed, 4 Nov 2015 20:33:19 -0000
It would seem that it's standard practice not to include a newline in the message
text, but that results in poor formatting, as a shell's command line then begins
on the line of the error message itself.

This commit simply instructs `fatal()' to append a newline after the message,
which should be suitable behavior for all of the invocations I've come across.
2016-01-19 00:23:19 +08:00
Matt Johnston
61b49ea2e3 Add note about OpenSSH origin 2016-01-19 00:22:23 +08:00
Matt Johnston
21ed9480d7 add dh group15 and group16, disabled by default 2016-01-15 00:19:11 +08:00
Matt Johnston
09e83ad742 Move dh group constants to a separate file 2016-01-14 21:54:58 +08:00
Chocobo1
3360072f84 TravisCI: fix linux + clang compile 2016-01-11 13:33:00 +08:00
Chocobo1
0ba59d80b6 TravisCI: use if block 2016-01-11 13:33:00 +08:00
Chocobo1
d416a9b818 TravisCI: enable osx builds 2016-01-11 13:32:59 +08:00
Chocobo1
de1993a1fd Fix parentheses weird placement 2016-01-05 22:44:09 +08:00
Chocobo1
307c71b66a TravisCI: enable build with clang 2016-01-05 14:14:29 +08:00
Chocobo1
b41ae80399 TravisCI: enable parallel build 2016-01-05 14:12:38 +08:00
Chocobo1
bbf9ba6d8d TravisCI: modify to run builds in container 2016-01-05 14:09:38 +08:00
Chocobo1
9bcd5f3c0a Fix print format specifier 2016-01-05 12:37:48 +08:00
Chocobo1
533aebe336 Fix "Pointer to local array variable returned" 2016-01-05 12:25:10 +08:00
Matt Johnston
5f8fcef688 Merge pull request #20 from kingosticks/debian-init-short-description
Added missing Short-Description init info field to debian init script.
2016-01-04 21:18:17 +08:00
Nick Steel
f37d67ff5e Added missing init info field to debian init script.
The Short-Description init info field is used by systemd and
displayed along with the service name. When it's missing the string
'null' is displayed instead.
2016-01-03 14:42:57 +00:00
Francois Perrad
9bda22e702 more hard tab 2016-01-01 15:02:09 +01:00
Francois Perrad
23ac7f56fa refactor indentation with hard tab 2015-12-31 16:00:23 +01:00
Matt Johnston
4c4aa502d4 use exec for proxycommand 2015-12-18 21:20:46 +08:00
Matt Johnston
20bdf3a5b1 revert removal of space handling, different fix for avoiding option prefix
matches
2015-12-15 22:57:22 +08:00
Matt Johnston
da108a9327 Don't allow spaces and don't get confused by -o usesyslogd=yes
(option name has another option name as a prefix)
2015-12-15 22:23:42 +08:00
Matt Johnston
e6432b1262 unknown options should be non-fatal 2015-12-15 22:19:41 +08:00
Matt Johnston
99bc4f451a rename killchild to kill_proxy_sighandler 2015-12-15 22:15:44 +08:00
Matt Johnston
79b43270a7 A few minor style fixes 2015-12-15 22:09:55 +08:00
Matt Johnston
3d33e65a35 Merge pull request #18 from annulen/dbclient_syslog
Support syslog logging in dbclient.
2015-12-15 21:55:51 +08:00
Konstantin Tokarev
5ab562f695 Use dropbear_log instead of some fprintf's in client code. 2015-12-15 16:52:53 +03:00
Konstantin Tokarev
3cb278c35c Support syslog logging in dbclient. 2015-12-15 16:52:53 +03:00
Konstantin Tokarev
c59827334c Allow setting syslog identifier via startsyslog(). 2015-12-15 16:43:29 +03:00
Konstantin Tokarev
2d6bbf341d Moved usingsyslog from svr_runopts to runopts. 2015-12-15 16:43:29 +03:00
Matt Johnston
2f62128297 Merge pull request #17 from annulen/kill_proxy_cmd
Client: kill proxy command when exiting application.
2015-12-15 21:40:32 +08:00
Matt Johnston
ed21e75235 Merge pull request #16 from annulen/openssh_options
Implemented ExitOnForwardFailure option for local and remote forwarding.
2015-12-15 21:30:59 +08:00
Matt Johnston
87d2c9c05c diffie-hellman-group14-sha256 2015-12-11 22:12:12 +08:00
Matt Johnston
df999ed1e1 Thanks 2015-12-03 21:40:31 +08:00
Matt Johnston
154de2aee3 Added signature for changeset 926e7275cef4 2015-12-03 21:33:48 +08:00
Matt Johnston
f808b8e930 Added tag DROPBEAR_2015.71 for changeset 9a944a243f08 2015-12-03 21:33:43 +08:00
Matt Johnston
5b2e57aa2f 2015.71 2015-12-03 21:23:54 +08:00
Konstantin Tokarev
960364d953 Client: kill proxy command when exiting application. 2015-12-03 16:22:29 +03:00
Matt Johnston
0b9793ccd0 wrong breakage version 2015-12-02 23:37:04 +08:00
Matt Johnston
fff298523d preliminary 2015.71 CHANGES 2015-12-02 23:35:14 +08:00
Matt Johnston
e81b6fbc6e ports and addresses must be malloced to avoid segfault on exit 2015-12-02 22:37:20 +08:00
Konstantin Tokarev
4dc1388ac7 Implemented ExitOnForwardFailure option for local and remote forwarding. 2015-11-30 21:05:36 +03:00
Konstantin Tokarev
1b69d6d658 Added OpenSSH-like -o command line option to dbclient.
Like in OpenSSH, whitespaces are ignored, key and value may be separated
by one '=' character.

For now only yes/no flag parsing is implemented.
2015-11-30 20:36:15 +03:00
Matt Johnston
f64a50f319 Merge pull request #15 from annulen/fix_cli_remotetcpfwd
Fixed build when ENABLE_CLI_REMOTETCPFWD is the only allowed TCP forw…
2015-11-30 21:13:03 +08:00
Juergen Daubert
f299caf612 The '==' comparision operator is not defined by POSIX, use '=' instead 2015-11-30 20:55:07 +08:00
Konstantin Tokarev
f76141a704 Fixed build when ENABLE_CLI_REMOTETCPFWD is the only allowed TCP forwarding. 2015-11-27 21:40:00 +03:00
Matt Johnston
a3049d6433 Fix "Avoid queueing into circbuffer when the channel is about to close"
which broken handling EAGAIN/EINTR
2015-11-27 22:19:08 +08:00
Matt Johnston
ee353847be Fix ses.channel_signal_pending race 2015-11-27 21:26:43 +08:00
Matt Johnston
33b2fbb5ef Added signature for changeset 5bb5976e6902 2015-11-26 23:15:27 +08:00
Matt Johnston
7d84615545 Added tag DROPBEAR_2015.70 for changeset 79a6ef02307d 2015-11-26 23:15:12 +08:00
Matt Johnston
b42113119a Wrong date 2015-11-26 23:05:38 +08:00
Matt Johnston
722944f307 2015.70 2015-11-26 23:04:13 +08:00
Matt Johnston
e038c26963 Another attempt at test for crypt() 2015-11-26 23:01:13 +08:00
Matt Johnston
56b9388702 Backed out changeset fbcd0a20e667 2015-11-26 22:21:14 +08:00
Matt Johnston
0e438f6d5c AC_SEARCH_LIBS not AC_CHECK_LIB to find crypt() 2015-11-26 21:58:25 +08:00
Matt Johnston
9f1eb695b4 release.sh reminds how to sign 2015-11-25 23:30:56 +08:00
Matt Johnston
9fef5d1050 Added signature for changeset af074dbcb68f 2015-11-25 23:30:44 +08:00
Matt Johnston
0bb7f77a8f Added tag DROPBEAR_2015.69 for changeset 1637dbd26212 2015-11-25 23:30:36 +08:00
Matt Johnston
9e4e562cfb 2015.69 2015-11-25 23:07:47 +08:00
Matt Johnston
92ec446cb9 debian changelog 2015-11-25 23:07:18 +08:00
Matt Johnston
9097da0284 changelog 2015-11-25 23:06:55 +08:00
Matt Johnston
eedeb009ec mention dropbearkey too 2015-11-25 23:05:41 +08:00
Matt Johnston
d8bc6abcf0 Mention "dropbear -R" if no hostkeys 2015-11-25 23:05:14 +08:00
Matt Johnston
2293e3d105 check for zero K value from curve25519 2015-11-25 22:15:59 +08:00
Guilhem Moulin
550b3056fd Fix minor manpage formatting issues 2015-11-25 20:46:06 +08:00
Matt Johnston
1ba5e8052e Improve dbclient manpage 2015-11-23 23:02:03 +08:00
Matt Johnston
6f5abeff2e Fix flags after the hostname 2015-11-23 22:47:43 +08:00
Guilhem Moulin
7cbf6b131b Bundling for dbclient 2015-11-23 22:28:56 +08:00
Matt Johnston
a461298109 Increase channel limit to 1000 2015-11-19 23:53:06 +08:00
Matt Johnston
90c3a74b2a Avoid queueing into circbuffer when the channel is about to close 2015-11-19 23:52:52 +08:00
Matt Johnston
87373be960 lazy allocation of circbuffer 2015-11-19 23:52:11 +08:00
Matt Johnston
85d9672e47 Send SSH_OPEN_RESOURCE_SHORTAGE response when too many channels open
rather than SSH_OPEN_UNKNOWN_CHANNEL_TYPE
2015-11-19 22:39:32 +08:00
Matt Johnston
e0ae527190 Only clear channel_signal_pending after handling all channels,
from Andrzej Szombierski
2015-11-17 20:53:30 +08:00
Guilhem Moulin
7fb1bec84a Enable bundling 2015-11-06 23:54:24 +08:00
Matt Johnston
1f308fb2b4 S_IWUSR rather than S_IWRITE for scp 2015-11-04 23:22:58 +08:00
Guilhem Moulin
e2d36d493f Mention -y flag 2015-10-28 21:44:16 +08:00
Matt Johnston
7c43594075 Add comment about compression 2015-10-28 21:42:09 +08:00
Matt Johnston
e4827025be Warn rather than fail if flags have trailing parts 2015-10-28 21:37:35 +08:00
Matt Johnston
00798ca8cc Test for crypt() rather than crypt.h
Print a message from configure if getpass() or crypt() were missing
2015-10-21 23:08:22 +08:00
Mike Frysinger
e84cb3c3c2 fix default build when getpass() is unavailable
if the system doesn't support getpass, we still default on the options
that require it which causes a build failure.  instead, only default
enable these when getpass is available.
2015-10-21 22:48:15 +08:00
Mike Frysinger
78b9cecb52 fix default build when crypt() is unavailable
if the system doesn't support crypt.h/crypt, then ENABLE_SVR_PASSWORD_AUTH
cannot work.  rather than default this to on all the time, do so only when
support for the header is found.
2015-10-21 22:40:11 +08:00
Mike Frysinger
93c54fe6f6 avoid getpass when not used
some systems (like android's bionic) do not provide getpass.  you can
disable ENABLE_CLI_PASSWORD_AUTH & ENABLE_CLI_INTERACT_AUTH to avoid
its use (and rely on pubkey auth), but the link still fails because
the support file calls getpass.  do not define this func if both of
those auth methods are not used.
2015-10-21 22:39:55 +08:00
Mike Frysinger
5f97d0fbbc fix build when ENABLE_CLI_INTERACT_AUTH is disabled
The session.h defines clientsession.cipher_none_after_auth only when
ENABLE_CLI_INTERACT_AUTH is defined, but cli-session.c will always
try to set that member.  export cipher_none_after_auth all the time.
2015-10-21 22:39:31 +08:00
Guilhem Moulin
dc01a8edd4 Don't display the MOTD when an explicit command is run.
(possibly via authorized_keys(5) restrictions), even when a
pseudo-terminal has been allocated for the session.  In other words,
only display the MOTD when the server starts the user's default shell.
2015-10-21 22:08:47 +08:00
Matt Johnston
23cc2bfb8c don't silently ignore extra flag arguments 2015-10-21 22:05:50 +08:00
Matt Johnston
9e379835c4 avoid invalidated iterator when connection fails 2015-09-29 22:19:11 +08:00
Matt Johnston
8ccbd216c6 make sure that the test for queued packets to write occurs after
those packets might have been enqueued by set_connect_fds()
2015-09-29 21:53:27 +08:00
Matt Johnston
90f4da29d7 Added signature for changeset ef4b26364b0c 2015-08-08 22:14:30 +08:00
Matt Johnston
54dbd5bbc8 Added signature for changeset a687f835236c 2015-08-08 22:14:19 +08:00
Matt Johnston
849b8ec469 Added tag DROPBEAR_2015.68 for changeset 809feaa9408f 2015-08-08 22:14:10 +08:00
Matt Johnston
84e18f72ae changelog and version 2015.68 2015-08-08 20:35:28 +08:00
Guilhem Moulin
633b98ef28 Fix typo in dropbear(8)'s manpage 2015-08-07 23:07:16 +08:00
Guilhem Moulin
2a34a72bff Fix segfault with restricted authorized_key files without forced command 2015-08-07 23:00:08 +08:00
Matt Johnston
24bae46e42 only update keepalive timeout post-auth (when keepalives are sent) 2015-08-07 21:02:49 +08:00
Matt Johnston
7585d4606e Build with -Werror for the simplest case 2015-08-04 08:20:50 +08:00
Matt Johnston
94bff1df66 couple more changelog items 2015-08-03 23:17:50 +08:00
Matt Johnston
2e60d20a76 set timeouts to time remaining rather than timeout duration 2015-08-03 23:05:43 +08:00
Matt Johnston
ce59260ee9 Fix problem where auth timeout wasn't checked when waiting for ident 2015-08-03 21:59:40 +08:00
Matt Johnston
387ebccf36 increase MAX_CMD_LEN to 9000 2015-08-03 21:17:23 +08:00
Matt Johnston
2f618af086 remove .hgtags from release 2015-08-03 21:05:42 +08:00
Matt Johnston
0ac33d22f7 Don't try to send data on first ack packet of 3way handshake.
Cisco SSH on 15.4(3)M2 or similar can't handle it.
2015-08-03 20:53:37 +08:00
Matt Johnston
c7bd5ac77d remove extraneous semicolon from m_free #define 2015-08-03 20:46:29 +08:00
Matt Johnston
941c067765 change DROPBEAR_DEFAULT_CLI_AUTHKEY to just prepend homedir
rather than doing ~ expansion
2015-08-03 20:45:04 +08:00
Matt Johnston
839e023ed8 check ecc key return, fix null pointer crash 2015-06-23 21:48:13 +08:00
Matt Johnston
2e05a2b8c4 Merge pull request #11 from nshopik/patch-2
Prepend DROPBEAR for scp.c
2015-06-12 22:57:48 +08:00
Matt Johnston
fc2c67e61c a bit more changelog 2015-06-12 22:55:10 +08:00
Matt Johnston
9c3e9fcdad merge 2015-06-04 23:24:08 +08:00
Matt Johnston
1a4db21fe4 buf_getstring and buf_putstring now use non-unsigned char* 2015-06-04 23:08:50 +08:00
Matt Johnston
d96a52541f Merge pull request #13 from gazoo74/fix-warnings
Fix warnings
2015-06-04 23:08:50 +08:00
Matt Johnston
e7ac4c1ab3 Merge pull request #13 from gazoo74/fix-warnings
Fix warnings
2015-06-04 22:25:28 +08:00
Matt Johnston
ecd8505218 Disable twofish-ctr by default, add config option 2015-06-03 22:59:59 +08:00
Matt Johnston
1fa1c3f9db note about constant_time_strcmp and lengths 2015-06-03 22:15:12 +08:00
Matt Johnston
91df741926 Fix building when ENABLE_CLI_PUBKEY_AUTH is unset 2015-06-03 21:45:32 +08:00
Matt Johnston
2a431cab03 separate client/server fastopen options 2015-05-29 23:19:11 +08:00
Gaël PORTAY
9fdab3ced8 Merge branch 'fix-pointer-sign-warnings' into fix-warnings 2015-05-05 20:42:38 +02:00
Gaël PORTAY
6e15e75391 Turn modptr local variable into unsigned char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
1c2a1838fc Turn name and instruction local variables into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
bfd730aa4c Turn type and term local variables into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
e3c6a86b1e Turn TCPFwdEntry's connectaddr and listenaddr attributes into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
bbaeb917ff Turn banner, methods and tok local variable into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
20f1e49b73 Turn many local variables into char *
reqname, bindaddr, request_addr, desthost and orighost to be exhaustive.
2015-05-05 20:39:14 +02:00
Gaël PORTAY
292656d899 Turn signame local variable into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
05b36b484e Turn ChanSess's cmd attribute into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
be3016b8d5 Turn send_msg_service_accept()'s name argument into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
5cf43d76bf Turn checkpubkey() and send_msg_userauth_pk_ok()'s algo argument into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
6f05e810d9 Turn addr local variable into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
947d2697cf Turn sshsession's remoteident attribute into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
449ddae628 Turn dropbear_ecc_curve's name into const char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
6b90885d4f Turn Algo_Type's name attribute into const char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
bd6c37adb6 Turn local key_indent variable into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
59235276ac Turn get_response()'s return type and prompt argument into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
e5ce3fc51b Turn type local variable into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
9f97511356 Turn ChanSess's tty and term attributes into char * 2015-05-05 20:39:14 +02:00
Gaël PORTAY
ef0aac432c Fix unused make_connection_string() warning [-Werror=unused-function]
This function is used when USE_VFORK is unset.
2015-05-05 20:39:13 +02:00
Gaël PORTAY
7928d83b02 Turn cleantext()'s dirtytext argument into char * 2015-05-05 20:39:13 +02:00
Gaël PORTAY
3e91ec07e4 Fix unused but set variable warnings [-Werror=unused-but-set-variable] 2015-05-05 20:39:13 +02:00
Gaël PORTAY
d680a9e3fb Turn username, servicename and methodname local variables into char *
Changing checkusername()'s username argument into char * as well.
2015-05-05 20:39:13 +02:00
Gaël PORTAY
6086851fc1 Fix unused parameters warnings [-Werror=unused-parameter] 2015-05-05 20:39:13 +02:00
Gaël PORTAY
61726df20c Turn sendaddr, listenaddr and request_listenaddr local variables into char * 2015-05-05 20:39:13 +02:00
Gaël PORTAY
1601a657d4 Turn send_msg_channel_open_failure()'s text and lang into const char * 2015-05-05 20:39:13 +02:00
Gaël PORTAY
50b14f696c Turn start_send_channel_request()'s type argument into char * 2015-05-05 20:39:13 +02:00
Gaël PORTAY
c239baf801 Turn addrandom()'s buf argument into unsigned char *
Data is usually represented as "unsigned char *" like genrandom().
2015-05-05 20:39:13 +02:00
Gaël PORTAY
18638859e6 Expect len to be a type of socklen_t [-Werror=pointer-sign] 2015-05-05 20:39:13 +02:00
Gaël PORTAY
224b16b247 Fix pointer differ in signess warnings [-Werror=pointer-sign] 2015-05-05 20:39:13 +02:00
Gaël PORTAY
d9d97969a3 Uses abort() instead of raising a SIGABRT signal [-Werror]
error: ‘noreturn’ function does return [-Werror]

abort() is a noreturn function while raise() is not.

And because crypt_argchk() is flagged as __attribute__(noreturn), abort()
appears to be a better condidate.

This compilation warning has probably been introduced by commit
1809f741cb.
2015-05-05 20:30:49 +02:00
Gaël PORTAY
897da4ee36 Uses k_size as an signed integer
buf_incrwritepos() and mp_to_unsigned_bin() functions use k_size as signed
integer argument.

k_size is also used in an assertion that compared it to curve_size which is
a signed long.

Only buf_getwriteptr() is using k_size as unsigned.

So it safe to use it as signed.
2015-05-05 20:30:49 +02:00
Gaël PORTAY
90f9f43335 Test struct existance against sizeof() operator
Instead of declaring an "unused-variable" or "unused-but-set-variable"
structure.

This avoid unexpected broken configurations when using something like:
$ ./configure CFLAGS="-Wall -Wextra -Werror"
It causes AC_COMPILE_IFELSE to fail and thus leading to a mismatch
configuration (because the CFLAGS are passed to the macro).
2015-05-05 20:23:54 +02:00
Matt Johnston
0e1dee828a Make sure kexfirstinitialise is called early enough 2015-05-03 00:00:35 +08:00
Matt Johnston
cbdc1f0753 fix travis more 2015-05-02 22:59:55 +08:00
Matt Johnston
7e306336d0 bad travis syntax 2015-05-02 22:55:53 +08:00
Matt Johnston
e7def4c211 add no-writev build 2015-05-02 22:51:46 +08:00
Matt Johnston
19e1afbd1c Fix no-writev fallback 2015-05-02 22:47:25 +08:00
Matt Johnston
fee32054e6 Should be AF_UNSPEC not PF_UNSPEC 2015-04-17 20:59:32 +08:00
Matt Johnston
9754fdd995 fastopen code was totally broken 2015-04-14 20:43:54 +08:00
Matt Johnston
ef20b9ff7a Avoid channel writev() when there is nothing to write 2015-03-21 22:43:08 +08:00
Matt Johnston
275611fbaa Make main socket nonblocking. Limit writequeue size. 2015-03-20 23:36:42 +08:00
Matt Johnston
a070159cc5 Fix when iov queue is large 2015-03-20 23:33:45 +08:00
Matt Johnston
20f9683ae0 avoid malloc for iovec 2015-03-20 22:53:32 +08:00
Matt Johnston
dce384668b dropbear_assert() rather than assert() 2015-03-16 21:33:01 +08:00
Nikolay Shopik
fdcd21e74b Prepend DROPBEAR for scp.c 2015-03-12 15:14:47 +03:00
Matt Johnston
67b4fa313e strdup strerror 2015-03-11 23:10:27 +08:00
Matt Johnston
5dff74109e Fix error handling for dbclient async connect 2015-03-03 20:53:00 +08:00
Matt Johnston
20d970a0e2 more changes 2015-03-02 21:40:06 +08:00
Matt Johnston
94734ad377 changes (also testing hg bookmarks) 2015-03-02 21:29:49 +08:00
Matt Johnston
14ad6a5972 merge 2015-03-01 23:27:08 +08:00
Matt Johnston
9e66b5a9b1 reword comment for clarity
--HG--
branch : nocircbuffer
2015-03-01 23:26:42 +08:00
Matt Johnston
f782cf375a Fix pubkey auth after change to reuse ses.readbuf as ses.payload
(4d7b4c5526c5)

--HG--
branch : nocircbuffer
2015-03-01 23:02:06 +08:00
Matt Johnston
3317916111 Fix some memory leaks in ecc code 2015-03-01 22:44:36 +08:00
Matt Johnston
f367273549 allocate buffer and data in a single allocation
--HG--
branch : nocircbuffer
2015-03-01 21:16:09 +08:00
Matt Johnston
91ef9b2fa9 Avoid malloc in hmac
--HG--
branch : nocircbuffer
2015-03-01 14:46:04 +08:00
Matt Johnston
579463933b A bit of a bodge to avoid memcpy if zlib is disabled
--HG--
branch : nocircbuffer
2015-03-01 00:57:21 +08:00
Matt Johnston
989c5c1436 Avoid copying data into circular buffer
--HG--
branch : nocircbuffer
2015-03-01 00:44:45 +08:00
Matt Johnston
3113932151 Better failure handling 2015-02-28 23:49:39 +08:00
Matt Johnston
125a970d71 merge tcp fastopen 2015-02-28 23:24:30 +08:00
Matt Johnston
89c0b2a6d8 Add cleanup
--HG--
branch : fastopen
2015-02-28 23:15:23 +08:00
Matt Johnston
31e379c300 merge from default
--HG--
branch : fastopen
2015-02-28 09:06:40 +08:00
Matt Johnston
843953379c EINPROGRESS for sendmsg() means it's working OK
--HG--
branch : fastopen
2015-02-27 00:02:48 +08:00
Matt Johnston
2a90c1ca7e ignore any sendmsg() errors
--HG--
branch : fastopen
2015-02-26 23:43:12 +08:00
Thorsten Horstmann
59bb1777be Use m_burn rather than memset 2015-02-24 22:48:14 +08:00
Thorsten Horstmann
c5f3c550a6 Avoid cppcheck warning 2015-02-24 22:41:26 +08:00
Matt Johnston
1809f741cb Add more ATTRIB_NORETURN annotations, from Thorsten Horstmann 2015-02-24 22:36:20 +08:00
Matt Johnston
9adfff5c1a Revert accidental commented out signal handlers 2015-02-24 22:23:32 +08:00
Matt Johnston
8008b595d3 Some additional cleanup functions 2015-02-24 22:17:04 +08:00
Matt Johnston
21bed0d21a Free memory before exiting. Based on patch from Thorsten Horstmann.
Client side is not complete.
2015-02-24 22:01:33 +08:00
Matt Johnston
4b1f5ec7c2 Use m_close() which will avoid close(-1) 2015-02-24 20:53:32 +08:00
Thorsten Horstmann
ab9439519a Fix for old compilers, variable declarations at beginning of functions
and /**/ comments
2015-02-24 20:51:18 +08:00
Thorsten Horstmann
abeb9d64a3 Some minor typo fixes, found by codespell. 2015-02-24 20:45:07 +08:00
Thorsten Horstmann
fdb7ffa864 DROPBEAR_ prefix for include guards to avoid collisions 2015-02-24 20:43:01 +08:00
Matt Johnston
46845fd3e8 get rid of some unnecessary code
--HG--
branch : fastopen
2015-02-21 00:43:32 +08:00
Matt Johnston
c53ca6ebc0 avoid some warnings
--HG--
branch : fastopen
2015-02-20 23:43:59 +08:00
Matt Johnston
f04a3a2cfa Fixes for backwards compatibility
--HG--
branch : fastopen
2015-02-20 23:38:05 +08:00
Matt Johnston
364a53577e Move generic network routines to netio.c
--HG--
branch : fastopen
2015-02-20 23:16:38 +08:00
Matt Johnston
1b1997bf2d Update priority once the socket is open
--HG--
branch : fastopen
2015-02-20 22:13:53 +08:00
Matt Johnston
34f9adb1c9 merge
--HG--
branch : fastopen
2015-02-19 22:42:30 +08:00
Matt Johnston
2e7d468b90 Add the missing second half of iov code
--HG--
branch : fastopen
2015-02-19 22:41:51 +08:00
Matt Johnston
86a717c80c fallback for old glibc and fastopen
memset rather than = {0} initialiser

--HG--
branch : fastopen
2015-02-19 22:33:51 +08:00
Matt Johnston
76a3eb393c In theory TFO should work. Needs platform cleanup and testing
--HG--
branch : fastopen
2015-02-19 00:32:00 +08:00
Matt Johnston
5f0cc969a0 generalise write iovec handling
--HG--
branch : fastopen
2015-02-18 23:02:49 +08:00
Matt Johnston
755c1458f0 async connections working
--HG--
branch : fastopen
2015-02-18 22:46:15 +08:00
Matt Johnston
8795d733ec work in progress for async connect
--HG--
branch : fastopen
2015-02-18 00:05:27 +08:00
Matt Johnston
28f61c8b3a tcp fastopen for the server
--HG--
branch : fastopen
2015-02-15 22:34:05 +08:00
Matt Johnston
9abcc7b909 connect_remote() is now always non-blocking 2015-02-14 09:56:11 +08:00
Matt Johnston
2c35f1c8fd Add envirnonment variable for debug timestamps to roughly match
network timestamps (in tshark)
2015-02-13 23:47:53 +08:00
Matt Johnston
136188259e Fix print that no longer works since we're not using fourCCs 2015-02-13 23:17:23 +08:00
Matt Johnston
02179b1218 merge 2015-02-13 23:15:12 +08:00
Matt Johnston
1e350de136 Make it compile 2015-02-13 23:13:58 +08:00
Matt Johnston
9aeda4c5bd piggyback data on acks when making connections on linux 2015-02-13 22:49:15 +08:00
Matt Johnston
8eb30c353a debug should be off by default 2015-02-13 21:45:15 +08:00
Matt Johnston
c44a78a2e6 Tighten validation of DH values. Odds of x==0 being generated are
improbable, roughly 2**-1023
Regression in 0.49
2015-02-10 21:46:19 +08:00
Matt Johnston
b6685bf806 twofish ctr modes 2015-02-04 22:12:06 +08:00
Matt Johnston
269d690e71 Added signature for changeset 1d2d81b1b7c1 2015-01-29 21:42:01 +08:00
Matt Johnston
4df268f10e sha256 2015-01-28 22:58:52 +08:00
Matt Johnston
19b3f01477 bump version 2015-01-28 22:57:33 +08:00
Matt Johnston
86811f4765 Added tag DROPBEAR_2015.67 for changeset cbd674d63cd4 2015-01-28 22:55:27 +08:00
Matt Johnston
dd0352d93b changelog for 2015.67 2015-01-28 22:54:23 +08:00
Matt Johnston
30ec18d938 merge 2015-01-28 22:49:40 +08:00
Matt Johnston
9d495ab2b5 changes for 2015.67 2015-01-28 22:49:28 +08:00
Matt Johnston
9174de47a9 Fix bad multi-statement define for m_free(), detected by Coverity 2015-01-28 22:43:01 +08:00
Christian Engelmayer
d857faf18e When clearing the memory of 'key' in function openssh_read(), only the size
of the pointer to the data instead of the whole size of struct openssh_key
is cleared. Correct the size calculation as detected by Coverity CID 1191543.
2015-01-28 22:42:29 +08:00
Matt Johnston
d5c8ba1690 Initialise sa_mask 2015-01-28 22:33:34 +08:00
Matt Johnston
9bb9b4829d Fix memory leak of ecdsa structure, found by Coverity 2015-01-28 22:29:18 +08:00
Matt Johnston
e25c297c3c Document ~/.ssh/id_dropbear 2015-01-28 22:22:32 +08:00
Matt Johnston
4de876f259 Keep sha1 default 2015-01-28 22:14:07 +08:00
Elan Ruusamäe
b9073961f7 Allow configure with libtomcrypt/libtommath directories missing
if using bundled libraries
2015-01-28 22:05:24 +08:00
Matt Johnston
a7a79d569a Disable non-delayed zlib for server 2015-01-28 21:38:27 +08:00
Matt Johnston
6165f53fcd Default client key path ~/.ssh/id_dropbear 2015-01-24 00:05:26 +08:00
Fedor Brunner
4122cac66b Prefer stronger algorithms in algorithm negotiation.
Prefer diffie-hellman-group14-sha1 (2048 bit) over
diffie-hellman-group1-sha1 (1024 bit).

Due to meet-in-the-middle attacks the effective key length of
three key 3DES is 112 bits. AES is stronger and faster then 3DES.

Prefer to delay the start of compression until after authentication
has completed. This avoids exposing compression code to attacks
from unauthenticated users.

(github pull request #9)
2015-01-23 23:00:25 +08:00
Like Ma
a1dcebe4f4 Fix installing dropbear.8 error when building in a separate directory.
(fix pull request #6)
2015-01-23 22:59:30 +08:00
Matt Johnston
6cbb23a819 Add config option to disable cbc. Disable twofish by default 2015-01-23 22:37:14 +08:00
Like Ma
5c57a31184 Fix variables may be uninitialized.
(fixup of pull request #7)
2015-01-23 22:23:23 +08:00
Fedor Brunner
7b2c42aa75 Integrity error (bad packet size %u) negative length
When corrupted packet is received negative length of packet is
    displayed.
    (re-apply of pull request #8)
2015-01-23 22:21:06 +08:00
Matt Johnston
1ed8d3938e Enable sha2 HMACs by default, they're required for ecdsa already 2015-01-13 20:55:04 +08:00
Matt Johnston
b24984deb3 clear hash state memory after use 2015-01-04 23:10:59 +08:00
Matt Johnston
eabd9f5e60 clarify bad/unknown 2015-01-04 22:32:38 +08:00
Catalin Patulea
d4609682af Handle invalid agent keys by skipping rather than exiting.
My agent exposes both conventional keys and certs (ecdsa-sha2-nistp256-cert-v01@openssh.com) and I want dropbear to be able to use the former.
2015-01-01 17:47:46 -05:00
Matt Johnston
634415f79e Open directories O_RDONLY for fsync, add debugging if it fails 2015-01-04 22:22:43 +08:00
Matt Johnston
4ba830fc31 Make sure hostkeys are flushed to disk to avoid empty files if the power
fails. Based on patch from Peter Korsgaard
2014-11-08 22:15:16 +08:00
Matt Johnston
3022a46039 Added signature for changeset 2d421bc0545d 2014-10-23 22:09:46 +08:00
Matt Johnston
d9a868ff60 Added tag DROPBEAR_2014.66 for changeset 735511a4c761 2014-10-23 22:09:22 +08:00
Matt Johnston
c890a0c133 changelog, version number bump 2014-10-23 21:43:00 +08:00
Matt Johnston
9ec934a94a Remove -o from scp help 2014-10-23 20:52:10 +08:00
Matt Johnston
5e606a964b increae MAX_STRING_LEN for sun ssh 2014-10-23 20:50:06 +08:00
Steven Honeyman
d88034434c Don't print "Failed loading hostkey" when -R delayed hostkey option is enabled 2014-10-22 07:12:52 +08:00
Matt Johnston
776d908703 Combine code for SSH_CONNECTION and SSH_CLIENT 2014-10-21 22:33:49 +08:00
Matt Johnston
444b15889f Merge pull request #5 from rcleere/ssh_client
Add SSH_CLIENT environment variable
2014-10-21 21:43:20 +08:00
Ryan Cleere
957450582f Add SSH_CLIENT environment variable 2014-10-20 12:59:47 -05:00
Matt Johnston
6d2d3669f3 Make keepalive handling more robust, this should now match what OpenSSH does 2014-08-19 23:08:56 +08:00
Whoopie
1387654cc8 Fix wtmp, testing for wtmp.h and wtmpx.h doesn't make sense 2014-08-13 22:07:43 +08:00
Matt Johnston
10eb218fb0 Don't send SSH_MSG_UNIMPLEMENTED for keepalive responses 2014-08-13 21:48:47 +08:00
Matt Johnston
bfb2b30de6 Added signature for changeset caac692b366c 2014-08-08 21:53:47 +08:00
Matt Johnston
426d4d72c6 Added tag DROPBEAR_2014.65 for changeset e9579816f20e 2014-08-08 21:53:42 +08:00
129 changed files with 3140 additions and 1795 deletions

View File

@@ -11,3 +11,12 @@ a50a1dc743317fad9b3737bc68fbca640659bb6d 0 iEYEABECAAYFAlJeqL0ACgkQjPn4sExkf7yVq
3d1d7d151c0ce3a79da62e86463f5632fa2b144a 0 iEYEABECAAYFAlKd5AEACgkQjPn4sExkf7wzWgCfdvPEEIdlMPqcbOQMJ7b+eAyy164An2ip1lPh1eS5g26/gSfruvWBVym4
277429102f1337bd10c89107d3e01de509cc1a7e 0 iEYEABECAAYFAlMEvF4ACgkQjPn4sExkf7xeVQCgtbxJ4G3hsFwUOM0K1WGr1J2vsbEAoMM8dEyr1mdrbgO1tzNLfD1nxbyn
96584b934d04ebab443f603e78d38fe692d36313 0 iEYEABECAAYFAlPVFrQACgkQjPn4sExkf7xr6ACglRiLE21vRrS1rJ809o2yMADIKtwAn1f5SyZUngSde8eE55JxCMwtMC5m
caac692b366c153cea0e9cd59aa2d79a7d843d4e 0 iEYEABECAAYFAlPk1mcACgkQjPn4sExkf7wLpgCeOqMYqpkf4lYUuyrn9VYThNpc7PkAn3JOSNgIqkKUcmSy6FstrI8jwJzq
2d421bc0545d1be6d59a4ebfe61606d94b124b0c 0 iEYEABECAAYFAlRJDCQACgkQjPn4sExkf7xUYACcCwVJkYWXJn5x/D5A+qMupy778lEAn0rg1oNiq96YU/4jOPsS5IMItihu
1d2d81b1b7c1b100e9c369e40b9fa5b2d491eea9 0 iEYEABECAAYFAlTKOKUACgkQjPn4sExkf7xWMACfYFozyHiRk5GaocTa5z6Ws1uyB4kAoLubxoxcnM3E7AA9mHAzc3OB5M0Y
a687f835236c7025b5cb2968fe9c4ebc4a49f0ea 0 iQIcBAABCgAGBQJVxg62AAoJEPSYMBLCC7qsC+EQAKw8YWogrVHhIFct2fx/nqybSPVrhFyKFKHhq7K/lZeVm0MGIWdSyVcQgP+Hs2jWNBWzG4AJ1BtifHWQH6IDh7W5RuwOXu5KobgPW9BsN3EVE9KIR+xe9jCAmFl9rIw0tNpy1q6R0TpYXx/sWlMilxecyEGyr2Ias2Sm19aY2mOEv8PLfh9BLfrJEKtt2NxL7TX8ScPwJXJMmVIQjN9WK4Ptx3tjcGNRivEVR/dftP5sJx2DBJx9avyDqrfloMW7Q7sPgJ88MPruCDxedOkbzH7JdHe3Humr2G4LsI0KPU7pNN6EBDjhJ+SVXuOyAgu5j/C0R+0ggGfjSrjDu8WjHyclFlwwu2MSGuHf111I1qkLtaRY3H1FZO5Y2gbLwBLQ82svA4klcBIxtP5jKAZDTh1jQMYsfKotvZdawOWrPDkNmKoUg2JXLHAtj9Dd0uGIhqfspZY3qlpzxw9uCkljWclUBD097ygotwAb2XdLoAWZ3KdvoPM+k448vIAQ7Q/aqcnm/dLQJr3Le029gpkOKoWKaQTlk0itrRGpgETHAhE2LnmWxYSKp6NYSKMgEONbfDiVNLyDTOlvpPiEb20RsOP64xA4wVDGmPenCURmMYoepQK6oJdtkNtCdth2S49KxPQAC+Dem4YZ7b+5b+cXrK5Nz7elBxZzRQWdjmZ4JDQK
ef4b26364b0cdda1084751d7de3d76c589e2d9cb 0 iQIcBAABCgAGBQJVxg7BAAoJEESTFJTynGdz9Q4P/A0Kq4H52rQqxq42PoEMFbVQIUfkFzyWjAz8eEGLmP5x5/sdpyxZDEyBSUG55uyNvOPTHE+Sd3t2h2Iieq749qwYgqggXC0P+C0zGzW3hB5Rv6dTUrKN1yCyaWE2tY488RsyVlcAs4vrp1Cum5Gv8/BUVKjzZmkZ1iq/3RyrvbLEiLoMrcLnQ+sUdaYHvfEwxDbzpOEvepg8iDJBitTrfG9xHp9otX6ucahwn1EumFvC5mvUxbiQ9jv76t4FJztjMoB24hPCH9T1FjB8uNsoM+j2Z67r81eJrGgNpJzjX0S3lY/AADZGhfGnfybTM9gFuQayIJuCJqduQibVwYkAAnPi17NmbdwPu0Rdz55oU+ft09XLVm/qkQcD1EP5bxYWnLIEMkkZQnFx7WdMpjKK9oGxZHeFYAKEgPgePCkk4TQ4PxNa+3854H19AUssQlaueGcbDLyPIRiSyqhleXawGfaJi+1jBt0DM7CNbAHAUWUE07VhQzNGWjabdEk4eXKTmDL+mZJFdHGBhyCve8sPmZBYJvM2PRgcXe8fwFh+R7gVj6kFbZJvgM9kG7EeF+4ZMEXG4yKpV/SKfMMeEPBCZjFxZhlJJ0fsZbB1Y/iLw8LXnJ0fa/5xFYv6k+iytfom/rqS4iUD7NWTjcEYHjd4EO4QlPD2Ef/AWOO8YBUBv8kA
af074dbcb68ff8670b3818e0d66d5dc6f1bd5877 0 iQIcBAABCgAGBQJWVdQfAAoJEPSYMBLCC7qs+n4P/RgZU3GsLFJN7v7Cn6NOdKdfjJBmlbCtK9KwlZZaj8fW4noqnLDcDd6a2xT4mDV3rCE6+QYialGXjNkkNCBwD9Z+gFc8spOtThrpQ54dgWzbgDlYB1y7Hp7DoWoJQIlU6Od9nWBemcSrAviOFNAX8+S6poRdEhrHgMcv2xJoqHjvT7X8gob0RnJcYxW5nLWzDaJV58QnX6QlXg4ClSB6IoCeEawdW6WzXlZ9MGsRycTtx1ool7Uo6Vo2xg48n9TaJqM/lbSsMAjHxO/fdTJMWzTId1fuZxJGFVeJbkhjSwlf7fkVXxrgDxjvIAmFDR8TSTfJo50CD82j5rPcd7KSEpQ12ImBUsntPDgOtt/mJZ3HcFds86OZ7NkPpqoJGVFFQ8yUpe//DNSB2Ovg1FrwhSKOq/9N61BBwk1INVFDp1hMq45PIa9gI9zW/99inGDeSSQlxa4iafEUEjXZTRYuX7mFjnWm5q7r134J7kyWQtN/jNUZ71F0mvhnemufgpNY/I/D7K6qkONpbDZ2nuzkhfoqugzhHYp467UePM0qmLTLdXGPPMukoGorpWeiSb2T25AEKm7N4A9NwPmdAnoFjAibjF9FAuU03sl+pu9MqFb+1ldsqjNfxhcJmoAUR5vy3pED9ailCb/OCBVTHkDPfTEhGU3waO9tPM+5x2rGB5fe
5bb5976e6902a0c9fba974a880c68c9487ee1e77 0 iQIcBAABCgAGBQJWVyIKAAoJEESTFJTynGdzQosP/0k5bVTerpUKZLjyNuMU8o0eyc7njkX8EyMOyGbtcArKpzO2opSBTRsuCT9Zsk1iiQ1GMTY1quKD7aNr86Hipqo4th/+ZXmLe9mmaCDukKjD0ZYC4dBVUy6RSUAMvdkDP9sZs7CMTO/22a9SqOsKTv3s2NN6XnsBGnmNbvVx5hkAk5hMVNFrjKIaexzI/7bWQIDRo2HQCaWaL06JvWEDSEQd2mynGSXxT/+m4hBnuGg6qxn2pd4XfG0g10tDAFx64HQkWgZqSB+F8z71Cvfjondy1zjJYgtABqNlwCKQJZhRUW2+PblqQnz08TUy83XN2vtisOju4avGcHSaBgBbMvg8Wx4ZtM7sPP9pLrhhOTd5ceERHeTceTJy+iI1SQFvccjrRfs5aJ0zAQX5q6f4bV0zp5SmxkvnZUEkZIoetkM8VrPOYugqx31LtHAWfVT9NM+VkV/rrxLhk6J0giIQvC9MPWxRDileFVDszPiOgTLcxWjOziOLT+xijcj7dtx1b/f2bNCduN5G7i+icjjTlCNtyRPRqhBqn705W7F+xESP2gsscM/1BjQ7TGidU5m1njdkUjbrqm3+Qic6iqkG7SfETHmQB9mHqpJ0hACRPvZlhwB7oimNHllkrlw8UJw9f0SiuLjfERIgVS2EOp+mAia0RU7MlTt19o017M1ffEYL
926e7275cef4f4f2a4251597ee4814748394824c 0 iQIcBAABCgAGBQJWYES4AAoJEESTFJTynGdzdT0P/0O/1frevtr698DwMe6kmJx35P6Bqq8szntMxYucv0HROTfr85JRcCCSvl/2SflDS215QmOxdvYLGLUWPJNz/gURCLpzsT88KLF68Y1tC72nl4Fj+LGIOlsWsvwEqQqw0v4iQkHIfcxI6q7g1r9Hfldf/ju4bzQ4HnKLxm6KNcLLoAsuehVpQ+njHpLmlLAGHU5a84B7xeXHFR+U/EBPxSdm637rNhmpLpkuK2Mym/Mzv7BThKDstpB8lhFHIwAVNqi3Cy4nGYxFZOJpooUN9pDornqAwuzHmOAMs9+49L8GZ1de5PBRGyFKibzjBIUWPEU9EIkfJVaVwTlqYK8Q/IRi9HjITPx6GpE8cZhdSvAibrQdb6BbIDrZ8eCvD9vnod6Uk0Jb9/ui6nCF9x+CN/3Qez4epV5+JCMYsqCiXFkVPm9Lab6L2eGZis7Q2TXImA/sSV+E4BGfH2urpkKlnuXTTtDp4XRG+lOISkIBXgjVY+uy8soVKNdx1gv+LeY8hu/oQ2NyOlaOeL47aSQ3who4Pk6pVRUOl6zfcKo9Vs6xDWm35A3Z6x/mrAENaXasB0JrfY5nIbefJUpbeSmi76fYldU98HdQNHPHCSeiKVYl7v/B6gi2JXp5xngLZz/5VVAurago7sRmpIp7G/AqU6LNE85IUzG8aQz8AfR0d1dW
fd1981f41c626a969f07b4823848deaefef3c8aa 0 iQIcBAABCgAGBQJW4W2TAAoJEESTFJTynGdzuOcP/j6tvB2WRwSj39KoJuRcRebFWWv4ZHiQXYMXWa3X0Ppzz52r9W0cXDjjlp5FyGdovCQsK+IXmjPo5cCvWBrZJYA6usFr9ssnUtTC+45lvPxPYwj47ZGPngCXDt7LD+v08XhqCu4LsctXIP/zejd30KVS1eR2RHI+tnEyaIKC0Xaa0igcv74MZX7Q8/U+B730QMX5adfYAHoeyRhoctRWaxVV3To7Vadd9jNXP45MRY5auhRcK7XyQcS85vJeCRoysfDUas4ERRQWYkX+68GyzO9GrkYFle931Akw2K6ZZfUuiC2TrF5xv1eRP1Zm2GX481U4ZGFTI8IzZL8sVQ6tvzq2Mxsecu589JNui9aB2d8Gp2Su/E2zn0h0ShIRmviGzf2HiBt+Bnji5X2h/fJKWbLaWge0MdOU5Jidfyh9k0YT7xo4piJLJYSaZ3nv+j4jTYnTfL7uYvuWbYkJ1T32aQVCan7Eup3BFAgQjzbWYi1XQVg6fvu8uHPpS3tNNA9EAMeeyTyg1l6zI2EIU5gPfd/dKmdyotY2lZBkFZNJqFkKRZuzjWekcw7hAxS+Bd68GKklt/DGrQiVycAgimqwXrfkzzQagawq2fXL2uXB8ghlsyxKLSQPnAtBF2Jcn5FH2z7HOQ+e18ZrFfNy0cYa/4OdH6K5aK1igTzhZZP2Urn0

View File

@@ -44,3 +44,11 @@ e894dbc015ba7ff4c3bf897ee20e28ca90c55a16 DROPBEAR_2013.61test
3d1d7d151c0ce3a79da62e86463f5632fa2b144a DROPBEAR_2013.62
2351b2da8e0d08dcc6e64fcc328b53b9630bda68 DROPBEAR_2014.63
0d2d39957c029adb7f4327d37fe6b4900f0736d9 DROPBEAR_2014.64
e9579816f20ea85affc6135e87f8477992808948 DROPBEAR_2014.65
735511a4c761141416ad0e6728989d2dafa55bc2 DROPBEAR_2014.66
cbd674d63cd4f3781464a8d4056a5506c8ae926f DROPBEAR_2015.67
809feaa9408f036734129c77f2b3c7e779d4f099 DROPBEAR_2015.68
1637dbd262124d113e52967df46afd6c715e4fad DROPBEAR_2015.69
79a6ef02307d05cb9dda10465cb5b807baa8f62e DROPBEAR_2015.70
9a944a243f08be6b22d32f166a0690eb4872462b DROPBEAR_2015.71
78b12b6549be08b0bea3da329b2578060a76ca31 DROPBEAR_2016.72

View File

@@ -1,20 +1,51 @@
language: c
os:
- linux
- osx
env:
matrix:
- BUNDLEDLIBTOM=--disable-bundled-libtom WEXTRAFLAGS=-Werror
- BUNDLEDLIBTOM=--enable-bundled-libtom
- MULTI=1
- NOWRITEV=1
# TODO: remove this section when libtomcrypt compiles on OSX: https://github.com/libtom/libtomcrypt/issues/82
matrix:
exclude:
- os: osx
env: BUNDLEDLIBTOM=--disable-bundled-libtom WEXTRAFLAGS=-Werror
compiler:
- gcc
- clang
script:
- autoconf && autoheader && ./configure $BUNDLEDLIBTOM CFLAGS="-O2 -Wall -Wno-pointer-sign" --prefix=$HOME/inst && make install
# container-based builds
sudo: false
addons:
apt:
packages:
# packages list: https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise
- zlib1g-dev
- libtomcrypt-dev
- libtommath-dev
before_install:
- if [ "$CC" = "clang" ]; then WEXTRAFLAGS="$WEXTRAFLAGS -Wno-error=incompatible-library-redeclaration" ; fi # workaround
install:
- if [ "$TRAVIS_OS_NAME" = "osx" -a "$BUNDLEDLIBTOM" = "--disable-bundled-libtom" ]; then brew update > /dev/null && brew install libtomcrypt libtommath ; fi
script:
- autoconf && autoheader && ./configure "$BUNDLEDLIBTOM" CFLAGS="-O2 -Wall -Wno-pointer-sign $WEXTRAFLAGS" --prefix="$HOME/inst"
- if [ "$NOWRITEV" = "1" ]; then sed -i -e s/HAVE_WRITEV/DONT_HAVE_WRITEV/ config.h ; fi
- make -j3 install
after_success:
- ~/inst/bin/dropbearkey -t rsa -f testrsa
- ~/inst/bin/dropbearkey -t dss -f testdss
- ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256
- ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384
- ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq libz-dev libtomcrypt-dev libtommath-dev
env:
- BUNDLEDLIBTOM=--disable-bundled-libtom
- BUNDLEDLIBTOM=--enable-bundled-libtom
- MULTI=1

164
CHANGES
View File

@@ -1,3 +1,167 @@
2016.73 - 18 March 2016
- Support syslog in dbclient, option -o usesyslog=yes. Patch from Konstantin Tokarev
- Kill a proxycommand when dbclient exits, patch from Konstantin Tokarev
- Option to exit when a TCP forward fails, patch from Konstantin Tokarev
- New "-o" option parsing from Konstantin Tokarev. This allows handling some extra options
in the style of OpenSSH, though implementing all OpenSSH options is not planned.
- Fix crash when fallback initshells() is used, reported by Michael Nowak and Mike Tzou
- Allow specifying commands eg "dropbearmulti dbclient ..." instead of symlinks
- Various cleanups for issues found by a lint tool, patch from Francois Perrad
- Fix tab indent consistency, patch from Francois Perrad
- Fix issues found by cppcheck, reported by Mike Tzou
- Use system memset_s() or explicit_bzero() if available to clear memory. Also make
libtomcrypt/libtommath routines use that (or Dropbear's own m_burn()).
- Prevent scp failing when the local user doesn't exist. Based on patch from Michael Witten.
- Improved Travis CI test running, thanks to Mike Tzou
- Improve some code that was flagged by Coverity and Fortify Static Code Analyzer
2016.72 - 9 March 2016
- Validate X11 forwarding input. Could allow bypass of authorized_keys command= restrictions,
found by github.com/tintinweb. Thanks for Damien Miller for a patch. CVE-2016-3116
2015.71 - 3 December 2015
- Fix "bad buf_incrpos" when data is transferred, broke in 2015.69
- Fix crash on exit when -p address:port is used, broke in 2015.68, thanks to
Frank Stollenwerk for reporting and investigation
- Fix building with only ENABLE_CLI_REMOTETCPFWD given, patch from Konstantin Tokarev
- Fix bad configure script test which didn't work with dash shell, patch from Juergen Daubert,
broke in 2015.70
- Fix server race condition that could cause sessions to hang on exit,
https://github.com/robotframework/SSHLibrary/issues/128
2015.70 - 26 November 2015
- Fix server password authentication on Linux, broke in 2015.69
2015.69 - 25 November 2015
- Fix crash when forwarded TCP connections fail to connect (bug introduced in 2015.68)
- Avoid hang on session close when multiple sessions are started, affects Qt Creator
Patch from Andrzej Szombierski
- Reduce per-channel memory consumption in common case, increase default
channel limit from 100 to 1000 which should improve SOCKS forwarding for modern
webpages
- Handle multiple command line arguments in a single flag, thanks to Guilhem Moulin
- Manpage improvements from Guilhem Moulin
- Build fixes for Android from Mike Frysinger
- Don't display the MOTD when an explicit command is run from Guilhem Moulin
- Check curve25519 shared secret isn't zero
2015.68 - Saturday 8 August 2015
- Reduce local data copying for improved efficiency. Measured 30%
increase in throughput for connections to localhost
- Forwarded TCP ports connect asynchronously and try all available addresses
(IPv4, IPv6, round robin DNS)
- Fix all compile warnings, many patches from Gaël Portay
Note that configure with -Werror may not be successful on some platforms (OS X)
and some configuration options may still result in unused variable
warnings.
- Use TCP Fast Open on Linux if available. Saves a round trip at connection
to hosts that have previously been connected.
Needs a recent Linux kernel and possibly "sysctl -w net.ipv4.tcp_fastopen=3"
Client side is disabled by default pending further compatibility testing
with networks and systems.
- Increase maximum command length to 9000 bytes
- Free memory before exiting, patch from Thorsten Horstmann. Useful for
Dropbear ports to embedded systems and for checking memory leaks
with valgrind. Only partially implemented for dbclient.
This is disabled by default, enable with DROPBEAR_CLEANUP in sysoptions.h
- DROPBEAR_DEFAULT_CLI_AUTHKEY setting now always prepends home directory unless
there is a leading slash (~ isn't treated specially)
- Fix small ECC memory leaks
- Tighten validation of Diffie-Hellman parameters, from Florent Daigniere of
Matta Consulting. Odds of bad values are around 2**-512 -- improbable.
- Twofish-ctr cipher is supported though disabled by default
- Fix pre-authentication timeout when waiting for client SSH-2.0 banner, thanks
to CL Ouyang
- Fix null pointer crash with restrictions in authorized_keys without a command, patch from
Guilhem Moulin
- Ensure authentication timeout is handled while reading the initial banner,
thanks to CL Ouyang for finding it.
- Fix null pointer crash when handling bad ECC keys. Found by afl-fuzz
2015.67 - Wednesday 28 January 2015
- Call fsync() after generating private keys to ensure they aren't lost if a
reboot occurs. Thanks to Peter Korsgaard
- Disable non-delayed zlib compression by default on the server. Can be
enabled if required for old clients with DROPBEAR_SERVER_DELAY_ZLIB
- Default client key path ~/.ssh/id_dropbear
- Prefer stronger algorithms by default, from Fedor Brunner.
AES256 over 3DES
Diffie-hellman group14 over group1
- Add option to disable CBC ciphers.
- Disable twofish in default options.h
- Enable sha2 HMAC algorithms by default, the code was already required
for ECC key exchange. sha1 is the first preference still for performance.
- Fix installing dropbear.8 in a separate build directory, from Like Ma
- Allow configure to succeed if libtomcrypt/libtommath are missing, from Elan Ruusamäe
- Don't crash if ssh-agent provides an unknown type of key. From Catalin Patulea
- Minor bug fixes, a few issues found by Coverity scan
2014.66 - Thursday 23 October 2014
- Use the same keepalive handling behaviour as OpenSSH. This will work better
with some SSH implementations that have different behaviour with unknown
message types.
- Don't reply with SSH_MSG_UNIMPLEMENTED when we receive a reply to our own
keepalive message
- Set $SSH_CLIENT to keep bash happy, patch from Ryan Cleere
- Fix wtmp which broke since 2013.62, patch from Whoopie
2014.65 - Friday 8 August 2014
- Fix 2014.64 regression, server session hang on exit with scp (and probably

View File

@@ -8,7 +8,7 @@ The majority of code is written by Matt Johnston, under the license below.
Portions of the client-mode work are (c) 2004 Mihnea Stoenescu, under the
same license:
Copyright (c) 2002-2013 Matt Johnston
Copyright (c) 2002-2015 Matt Johnston
Portions copyright (c) 2004 Mihnea Stoenescu
All rights reserved.

View File

@@ -24,7 +24,7 @@ CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM)
endif
COMMONOBJS=dbutil.o buffer.o \
COMMONOBJS=dbutil.o buffer.o dbhelpers.o \
dss.o bignum.o \
signkey.o rsa.o dbrandom.o \
queue.o \
@@ -40,12 +40,12 @@ SVROBJS=svr-kex.o svr-auth.o sshpty.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
cli-agentfwd.o
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
common-channel.o common-chansession.o termcodes.o loginrec.o \
tcp-accept.o listener.o process-packet.o \
common-runopts.o circbuffer.o curve25519-donna.o
tcp-accept.o listener.o process-packet.o dh_groups.o \
common-runopts.o circbuffer.o curve25519-donna.o list.o netio.o
KEYOBJS=dropbearkey.o
@@ -131,7 +131,7 @@ insmultidropbear: dropbearmulti
-rm -f $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
$(INSTALL) -m 644 dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
$(INSTALL) -m 644 $(srcdir)/dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
insmulti%: dropbearmulti
$(INSTALL) -d $(DESTDIR)$(bindir)
@@ -140,12 +140,12 @@ insmulti%: dropbearmulti
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
# dropbear should go in sbin, so it needs a seperate rule
# dropbear should go in sbin, so it needs a separate rule
inst_dropbear: dropbear
$(INSTALL) -d $(DESTDIR)$(sbindir)
$(INSTALL) dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
$(INSTALL) -m 644 dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
$(INSTALL) -m 644 $(srcdir)/dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
inst_%: %
$(INSTALL) -d $(DESTDIR)$(bindir)

View File

@@ -21,8 +21,8 @@
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _AGENTFWD_H_
#define _AGENTFWD_H_
#ifndef DROPBEAR_AGENTFWD_H_
#define DROPBEAR_AGENTFWD_H_
#include "includes.h"
#include "chansession.h"
@@ -60,4 +60,4 @@ void svr_agentset(struct ChanSess *chansess);
#endif /* ENABLE_SVR_AGENTFWD */
#endif /* _AGENTFWD_H_ */
#endif /* DROPBEAR_AGENTFWD_H_ */

9
algo.h
View File

@@ -22,9 +22,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _ALGO_H_
#ifndef DROPBEAR_ALGO_H_
#define _ALGO_H_
#define DROPBEAR_ALGO_H_
#include "includes.h"
#include "buffer.h"
@@ -35,7 +35,7 @@
struct Algo_Type {
const unsigned char *name; /* identifying name */
const char *name; /* identifying name */
char val; /* a value for this cipher, or -1 for invalid */
const void *data; /* algorithm specific data */
char usable; /* whether we can use this algorithm */
@@ -51,6 +51,7 @@ extern algo_type sshhostkey[];
extern algo_type sshciphers[];
extern algo_type sshhashes[];
extern algo_type ssh_compress[];
extern algo_type ssh_delaycompress[];
extern algo_type ssh_nocompress[];
extern const struct dropbear_cipher dropbear_nocipher;
@@ -133,4 +134,4 @@ enum {
DROPBEAR_COMP_ZLIB_DELAY,
};
#endif /* _ALGO_H_ */
#endif /* DROPBEAR_ALGO_H_ */

View File

@@ -53,6 +53,7 @@ atomicio(f, fd, _s, n)
if (errno == EINTR || errno == EAGAIN)
#endif
continue;
/* FALLTHROUGH */
case 0:
return (res);
default:

70
auth.h
View File

@@ -22,32 +22,32 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _AUTH_H_
#define _AUTH_H_
#ifndef DROPBEAR_AUTH_H_
#define DROPBEAR_AUTH_H_
#include "includes.h"
#include "signkey.h"
#include "chansession.h"
void svr_authinitialise();
void cli_authinitialise();
void svr_authinitialise(void);
void cli_authinitialise(void);
/* Server functions */
void recv_msg_userauth_request();
void recv_msg_userauth_request(void);
void send_msg_userauth_failure(int partial, int incrfail);
void send_msg_userauth_success();
void send_msg_userauth_success(void);
void send_msg_userauth_banner(buffer *msg);
void svr_auth_password();
void svr_auth_pubkey();
void svr_auth_pam();
void svr_auth_password(void);
void svr_auth_pubkey(void);
void svr_auth_pam(void);
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
int svr_pubkey_allows_agentfwd();
int svr_pubkey_allows_tcpfwd();
int svr_pubkey_allows_x11fwd();
int svr_pubkey_allows_pty();
int svr_pubkey_allows_agentfwd(void);
int svr_pubkey_allows_tcpfwd(void);
int svr_pubkey_allows_x11fwd(void);
int svr_pubkey_allows_pty(void);
void svr_pubkey_set_forced_command(struct ChanSess *chansess);
void svr_pubkey_options_cleanup();
void svr_pubkey_options_cleanup(void);
int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filename);
#else
/* no option : success */
@@ -56,34 +56,34 @@ int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filena
#define svr_pubkey_allows_x11fwd() 1
#define svr_pubkey_allows_pty() 1
static inline void svr_pubkey_set_forced_command(struct ChanSess *chansess) { }
static inline void svr_pubkey_options_cleanup() { }
static inline void svr_pubkey_options_cleanup(void) { }
#define svr_add_pubkey_options(x,y,z) DROPBEAR_SUCCESS
#endif
/* Client functions */
void recv_msg_userauth_failure();
void recv_msg_userauth_success();
void recv_msg_userauth_specific_60();
void recv_msg_userauth_pk_ok();
void recv_msg_userauth_info_request();
void cli_get_user();
void cli_auth_getmethods();
int cli_auth_try();
void recv_msg_userauth_banner();
void cli_pubkeyfail();
void cli_auth_password();
int cli_auth_pubkey();
void cli_auth_interactive();
void recv_msg_userauth_failure(void);
void recv_msg_userauth_success(void);
void recv_msg_userauth_specific_60(void);
void recv_msg_userauth_pk_ok(void);
void recv_msg_userauth_info_request(void);
void cli_get_user(void);
void cli_auth_getmethods(void);
int cli_auth_try(void);
void recv_msg_userauth_banner(void);
void cli_pubkeyfail(void);
void cli_auth_password(void);
int cli_auth_pubkey(void);
void cli_auth_interactive(void);
char* getpass_or_cancel(char* prompt);
void cli_auth_pubkey_cleanup();
void cli_auth_pubkey_cleanup(void);
#define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
#define AUTH_TYPE_NONE 1
#define AUTH_TYPE_PUBKEY 1 << 1
#define AUTH_TYPE_PASSWORD 1 << 2
#define AUTH_TYPE_INTERACT 1 << 3
#define AUTH_TYPE_PUBKEY (1 << 1)
#define AUTH_TYPE_PASSWORD (1 << 2)
#define AUTH_TYPE_INTERACT (1 << 3)
#define AUTH_METHOD_NONE "none"
#define AUTH_METHOD_NONE_LEN 4
@@ -106,7 +106,7 @@ struct AuthState {
valid */
unsigned int failcount; /* Number of (failed) authentication attempts.*/
unsigned authdone : 1; /* 0 if we haven't authed, 1 if we have. Applies for
client and server (though has differing [obvious]
client and server (though has differing
meanings). */
unsigned perm_warn : 1; /* Server only, set if bad permissions on
~/.ssh/authorized_keys have already been
@@ -133,8 +133,8 @@ struct PubKeyOptions {
int no_x11_forwarding_flag;
int no_pty_flag;
/* "command=" option. */
unsigned char * forced_command;
char * forced_command;
};
#endif
#endif /* _AUTH_H_ */
#endif /* DROPBEAR_AUTH_H_ */

View File

@@ -39,33 +39,33 @@ void m_mp_init(mp_int *mp) {
* on error */
void m_mp_init_multi(mp_int *mp, ...)
{
mp_int* cur_arg = mp;
va_list args;
mp_int* cur_arg = mp;
va_list args;
va_start(args, mp); /* init args to next argument from caller */
while (cur_arg != NULL) {
if (mp_init(cur_arg) != MP_OKAY) {
va_start(args, mp); /* init args to next argument from caller */
while (cur_arg != NULL) {
if (mp_init(cur_arg) != MP_OKAY) {
dropbear_exit("Mem alloc error");
}
cur_arg = va_arg(args, mp_int*);
}
va_end(args);
}
cur_arg = va_arg(args, mp_int*);
}
va_end(args);
}
void m_mp_alloc_init_multi(mp_int **mp, ...)
{
mp_int** cur_arg = mp;
va_list args;
mp_int** cur_arg = mp;
va_list args;
va_start(args, mp); /* init args to next argument from caller */
while (cur_arg != NULL) {
*cur_arg = m_malloc(sizeof(mp_int));
if (mp_init(*cur_arg) != MP_OKAY) {
va_start(args, mp); /* init args to next argument from caller */
while (cur_arg != NULL) {
*cur_arg = m_malloc(sizeof(mp_int));
if (mp_init(*cur_arg) != MP_OKAY) {
dropbear_exit("Mem alloc error");
}
cur_arg = va_arg(args, mp_int**);
}
va_end(args);
}
cur_arg = va_arg(args, mp_int**);
}
va_end(args);
}
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {

View File

@@ -22,11 +22,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _BIGNUM_H_
#define _BIGNUM_H_
#ifndef DROPBEAR_BIGNUM_H_
#define DROPBEAR_BIGNUM_H_
#include "includes.h"
#include "dbutil.h"
#include "dbhelpers.h"
void m_mp_init(mp_int *mp);
void m_mp_init_multi(mp_int *mp, ...) ATTRIB_SENTINEL;
@@ -35,4 +34,4 @@ void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
hash_state *hs, mp_int *mp);
#endif /* _BIGNUM_H_ */
#endif /* DROPBEAR_BIGNUM_H_ */

View File

@@ -46,17 +46,15 @@ buffer* buf_new(unsigned int size) {
dropbear_exit("buf->size too big");
}
buf = (buffer*)m_malloc(sizeof(buffer));
buf = (buffer*)m_malloc(sizeof(buffer)+size);
if (size > 0) {
buf->data = (unsigned char*)m_malloc(size);
buf->data = (unsigned char*)buf + sizeof(buffer);
} else {
buf->data = NULL;
}
buf->size = size;
buf->pos = 0;
buf->len = 0;
return buf;
@@ -65,7 +63,6 @@ buffer* buf_new(unsigned int size) {
/* free the buffer's data and the buffer itself */
void buf_free(buffer* buf) {
m_free(buf->data)
m_free(buf);
}
@@ -78,17 +75,18 @@ void buf_burn(buffer* buf) {
/* resize a buffer, pos and len will be repositioned if required when
* downsizing */
void buf_resize(buffer *buf, unsigned int newsize) {
buffer* buf_resize(buffer *buf, unsigned int newsize) {
if (newsize > BUF_MAX_SIZE) {
dropbear_exit("buf->size too big");
}
buf->data = m_realloc(buf->data, newsize);
buf = m_realloc(buf, sizeof(buffer)+newsize);
buf->data = (unsigned char*)buf + sizeof(buffer);
buf->size = newsize;
buf->len = MIN(newsize, buf->len);
buf->pos = MIN(newsize, buf->pos);
return buf;
}
/* Create a copy of buf, allocating required memory etc. */
@@ -99,7 +97,9 @@ buffer* buf_newcopy(buffer* buf) {
ret = buf_new(buf->len);
ret->len = buf->len;
memcpy(ret->data, buf->data, buf->len);
if (buf->len > 0) {
memcpy(ret->data, buf->data, buf->len);
}
return ret;
}
@@ -127,7 +127,7 @@ void buf_setpos(buffer* buf, unsigned int pos) {
buf->pos = pos;
}
/* increment the postion by incr, increasing the buffer length if required */
/* increment the position 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");
@@ -203,10 +203,10 @@ unsigned char* buf_getwriteptr(buffer* buf, unsigned int len) {
/* Return a null-terminated string, it is malloced, so must be free()ed
* Note that the string isn't checked for null bytes, hence the retlen
* may be longer than what is returned by strlen */
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
char* buf_getstring(buffer* buf, unsigned int *retlen) {
unsigned int len;
unsigned char* ret;
char* ret;
len = buf_getint(buf);
if (len > MAX_STRING_LEN) {
dropbear_exit("String too long");
@@ -225,15 +225,15 @@ unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
/* 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;
buffer *ret = NULL;
unsigned int len = buf_getint(buf);
if (len > MAX_STRING_LEN) {
dropbear_exit("String too long");
}
ret = buf_new(len);
memcpy(buf_getwriteptr(ret, len), buf_getptr(buf, len), len);
buf_incrpos(buf, len);
buf_incrlen(ret, len);
return ret;
}
@@ -262,16 +262,16 @@ void buf_putint(buffer* buf, int unsigned val) {
}
/* put a SSH style string into the buffer, increasing buffer len if required */
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len) {
void buf_putstring(buffer* buf, const char* str, unsigned int len) {
buf_putint(buf, len);
buf_putbytes(buf, str, len);
buf_putbytes(buf, (const unsigned char*)str, len);
}
/* puts an entire buffer as a SSH string. ignore pos of buf_str. */
void buf_putbufstring(buffer *buf, const buffer* buf_str) {
buf_putstring(buf, buf_str->data, buf_str->len);
buf_putstring(buf, (const char*)buf_str->data, buf_str->len);
}
/* put the set of len bytes into the buffer, incrementing the pos, increasing

View File

@@ -22,14 +22,15 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _BUFFER_H_
#ifndef DROPBEAR_BUFFER_H_
#define _BUFFER_H_
#define DROPBEAR_BUFFER_H_
#include "includes.h"
struct buf {
/* don't manipulate data member outside of buffer.c - it
is a pointer into the malloc holding buffer itself */
unsigned char * data;
unsigned int len; /* the used size */
unsigned int pos;
@@ -40,7 +41,8 @@ struct buf {
typedef struct buf buffer;
buffer * buf_new(unsigned int size);
void buf_resize(buffer *buf, unsigned int newsize);
/* Possibly returns a new buffer*, like realloc() */
buffer * buf_resize(buffer *buf, unsigned int newsize);
void buf_free(buffer* buf);
void buf_burn(buffer* buf);
buffer* buf_newcopy(buffer* buf);
@@ -54,15 +56,15 @@ unsigned char buf_getbool(buffer* buf);
void buf_putbyte(buffer* buf, unsigned char val);
unsigned char* buf_getptr(buffer* buf, unsigned int len);
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len);
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen);
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);
void buf_putstring(buffer* buf, const char* str, unsigned int len);
void buf_putbufstring(buffer *buf, const buffer* buf_str);
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
void buf_putmpint(buffer* buf, mp_int * mp);
int buf_getmpint(buffer* buf, mp_int* mp);
unsigned int buf_getint(buffer* buf);
#endif /* _BUFFER_H_ */
#endif /* DROPBEAR_BUFFER_H_ */

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _CHANNEL_H_
#define _CHANNEL_H_
#ifndef DROPBEAR_CHANNEL_H_
#define DROPBEAR_CHANNEL_H_
#include "includes.h"
#include "buffer.h"
@@ -73,6 +73,7 @@ struct Channel {
* to ensure we don't run it twice (nor type->checkclose()). */
int close_handler_done;
struct dropbear_progress_connection *conn_pending;
int initconn; /* used for TCP forwarding, whether the channel has been
fully initialised */
@@ -92,7 +93,7 @@ struct Channel {
struct ChanType {
int sepfds; /* Whether this channel has seperate pipes for in/out or not */
int sepfds; /* Whether this channel has separate pipes for in/out or not */
char *name;
int (*inithandler)(struct Channel*);
int (*check_close)(struct Channel*);
@@ -100,21 +101,27 @@ struct ChanType {
void (*closehandler)(struct Channel*);
};
void chaninitialise(const struct ChanType *chantypes[]);
void chancleanup();
void setchannelfds(fd_set *readfd, fd_set *writefd);
void channelio(fd_set *readfd, fd_set *writefd);
struct Channel* getchannel();
/* Callback for connect_remote */
void channel_connect_done(int result, int sock, void* user_data, const char* errstring);
void recv_msg_channel_open();
void recv_msg_channel_request();
void chaninitialise(const struct ChanType *chantypes[]);
void chancleanup(void);
void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads);
void channelio(fd_set *readfd, fd_set *writefd);
struct Channel* getchannel(void);
/* Returns an arbitrary channel that is in a ready state - not
being initialised and no EOF in either direction. NULL if none. */
struct Channel* get_any_ready_channel(void);
void recv_msg_channel_open(void);
void recv_msg_channel_request(void);
void send_msg_channel_failure(struct Channel *channel);
void send_msg_channel_success(struct Channel *channel);
void recv_msg_channel_data();
void recv_msg_channel_extended_data();
void recv_msg_channel_window_adjust();
void recv_msg_channel_close();
void recv_msg_channel_eof();
void recv_msg_channel_data(void);
void recv_msg_channel_extended_data(void);
void recv_msg_channel_window_adjust(void);
void recv_msg_channel_close(void);
void recv_msg_channel_eof(void);
void common_recv_msg_channel_data(struct Channel *channel, int fd,
circbuffer * buf);
@@ -125,11 +132,13 @@ extern const struct ChanType clichansess;
#if defined(USING_LISTENERS) || defined(DROPBEAR_CLIENT)
int send_msg_channel_open_init(int fd, const struct ChanType *type);
void recv_msg_channel_open_confirmation();
void recv_msg_channel_open_failure();
void recv_msg_channel_open_confirmation(void);
void recv_msg_channel_open_failure(void);
#endif
void start_send_channel_request(struct Channel *channel, char *type);
void send_msg_request_success();
void send_msg_request_failure();
void send_msg_request_success(void);
void send_msg_request_failure(void);
#endif /* _CHANNEL_H_ */
#endif /* DROPBEAR_CHANNEL_H_ */

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _CHANSESSION_H_
#define _CHANSESSION_H_
#ifndef DROPBEAR_CHANSESSION_H_
#define DROPBEAR_CHANSESSION_H_
#include "loginrec.h"
#include "channel.h"
@@ -39,21 +39,24 @@ struct exitinfo {
struct ChanSess {
unsigned char * cmd; /* command to exec */
char * cmd; /* command to exec */
pid_t pid; /* child process pid */
/* pty details */
int master; /* the master terminal fd*/
int slave;
unsigned char * tty;
unsigned char * term;
char * tty;
char * term;
/* exit details */
struct exitinfo exit;
/* Used to set $SSH_CONNECTION in the child session.
Is only set temporarily before forking */
/* These are only set temporarily before forking */
/* Used to set $SSH_CONNECTION in the child session. */
char *connection_string;
/* Used to set $SSH_CLIENT in the child session. */
char *client_string;
#ifndef DISABLE_X11FWD
struct Listener * x11listener;
@@ -83,15 +86,14 @@ struct ChildPid {
void addnewvar(const char* param, const char* var);
void cli_send_chansess_request();
void cli_tty_cleanup();
void cli_chansess_winchange();
void cli_send_chansess_request(void);
void cli_tty_cleanup(void);
void cli_chansess_winchange(void);
#ifdef ENABLE_CLI_NETCAT
void cli_send_netcat_request();
void cli_send_netcat_request(void);
#endif
void cli_start_send_channel_request(struct Channel *channel, unsigned char *type);
void svr_chansessinitialise();
void svr_chansessinitialise(void);
extern const struct ChanType svrchansess;
struct SigMap {
@@ -101,4 +103,4 @@ struct SigMap {
extern const struct SigMap signames[];
#endif /* _CHANSESSION_H_ */
#endif /* DROPBEAR_CHANSESSION_H_ */

View File

@@ -37,9 +37,8 @@ circbuffer * cbuf_new(unsigned int size) {
}
cbuf = (circbuffer*)m_malloc(sizeof(circbuffer));
if (size > 0) {
cbuf->data = (unsigned char*)m_malloc(size);
}
/* data is malloced on first write */
cbuf->data = NULL;
cbuf->used = 0;
cbuf->readpos = 0;
cbuf->writepos = 0;
@@ -50,8 +49,10 @@ circbuffer * cbuf_new(unsigned int size) {
void cbuf_free(circbuffer * cbuf) {
m_burn(cbuf->data, cbuf->size);
m_free(cbuf->data);
if (cbuf->data) {
m_burn(cbuf->data, cbuf->size);
m_free(cbuf->data);
}
m_free(cbuf);
}
@@ -67,23 +68,6 @@ unsigned int cbuf_getavail(circbuffer * cbuf) {
}
unsigned int cbuf_readlen(circbuffer *cbuf) {
dropbear_assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
dropbear_assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
if (cbuf->used == 0) {
TRACE(("cbuf_readlen: unused buffer"))
return 0;
}
if (cbuf->readpos < cbuf->writepos) {
return cbuf->writepos - cbuf->readpos;
}
return cbuf->size - cbuf->readpos;
}
unsigned int cbuf_writelen(circbuffer *cbuf) {
dropbear_assert(cbuf->used <= cbuf->size);
@@ -102,12 +86,19 @@ unsigned int cbuf_writelen(circbuffer *cbuf) {
return cbuf->size - cbuf->writepos;
}
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_readlen(cbuf)) {
dropbear_exit("Bad cbuf read");
}
void cbuf_readptrs(circbuffer *cbuf,
unsigned char **p1, unsigned int *len1,
unsigned char **p2, unsigned int *len2) {
*p1 = &cbuf->data[cbuf->readpos];
*len1 = MIN(cbuf->used, cbuf->size - cbuf->readpos);
return &cbuf->data[cbuf->readpos];
if (*len1 < cbuf->used) {
*p2 = cbuf->data;
*len2 = cbuf->used - *len1;
} else {
*p2 = NULL;
*len2 = 0;
}
}
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
@@ -116,6 +107,11 @@ unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
dropbear_exit("Bad cbuf write");
}
if (!cbuf->data) {
/* lazy allocation */
cbuf->data = (unsigned char*)m_malloc(cbuf->size);
}
return &cbuf->data[cbuf->writepos];
}
@@ -131,10 +127,6 @@ 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_assert(cbuf->used >= len);
cbuf->used -= len;
cbuf->readpos = (cbuf->readpos + len) % cbuf->size;

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _CIRCBUFFER_H_
#define _CIRCBUFFER_H_
#ifndef DROPBEAR_CIRCBUFFER_H_
#define DROPBEAR_CIRCBUFFER_H_
struct circbuf {
unsigned int size;
@@ -40,10 +40,12 @@ void cbuf_free(circbuffer * cbuf);
unsigned int cbuf_getused(circbuffer * cbuf); /* how much data stored */
unsigned int cbuf_getavail(circbuffer * cbuf); /* how much we can write */
unsigned int cbuf_readlen(circbuffer *cbuf); /* max linear read len */
unsigned int cbuf_writelen(circbuffer *cbuf); /* max linear write len */
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len);
/* returns pointers to the two portions of the circular buffer that can be read */
void cbuf_readptrs(circbuffer *cbuf,
unsigned char **p1, unsigned int *len1,
unsigned char **p2, unsigned int *len2);
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len);
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len);
void cbuf_incrread(circbuffer *cbuf, unsigned int len);

View File

@@ -155,7 +155,7 @@ static buffer * agent_request(unsigned char type, buffer *data) {
goto out;
}
buf_resize(inbuf, readlen);
inbuf = buf_resize(inbuf, readlen);
buf_setpos(inbuf, 0);
ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen);
if ((size_t)ret != readlen) {
@@ -210,13 +210,14 @@ static void agent_get_key_list(m_list * ret_list)
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;
TRACE(("Skipping bad/unknown type pubkey from agent"));
sign_key_free(pubkey);
} else {
pubkey->type = key_type;
pubkey->source = SIGNKEY_SOURCE_AGENT;
list_append(ret_list, pubkey);
list_append(ret_list, pubkey);
}
/* We'll ignore the comment for now. might want it later.*/
buf_eatstring(inbuf);
@@ -234,7 +235,7 @@ void cli_setup_agent(struct Channel *channel) {
return;
}
cli_start_send_channel_request(channel, "auth-agent-req@openssh.com");
start_send_channel_request(channel, "auth-agent-req@openssh.com");
/* Don't want replies */
buf_putbyte(ses.writepayload, 0);
encrypt_packet();

View File

@@ -43,9 +43,9 @@ void cli_auth_getmethods() {
TRACE(("enter cli_auth_getmethods"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
buf_putstring(ses.writepayload, cli_opts.username,
buf_putstring(ses.writepayload, cli_opts.username,
strlen(cli_opts.username));
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
SSH_SERVICE_CONNECTION_LEN);
buf_putstring(ses.writepayload, "none", 4); /* 'none' method */
@@ -75,7 +75,7 @@ void cli_auth_getmethods() {
void recv_msg_userauth_banner() {
unsigned char* banner = NULL;
char* banner = NULL;
unsigned int bannerlen;
unsigned int i, linecount;
@@ -151,8 +151,8 @@ void recv_msg_userauth_specific_60() {
void recv_msg_userauth_failure() {
unsigned char * methods = NULL;
unsigned char * tok = NULL;
char * methods = NULL;
char * tok = NULL;
unsigned int methlen = 0;
unsigned int partial = 0;
unsigned int i = 0;
@@ -324,6 +324,7 @@ int cli_auth_try() {
return DROPBEAR_FAILURE;
}
#if defined(ENABLE_CLI_PASSWORD_AUTH) || defined(ENABLE_CLI_INTERACT_AUTH)
/* A helper for getpass() that exits if the user cancels. The returned
* password is statically allocated by getpass() */
char* getpass_or_cancel(char* prompt)
@@ -331,12 +332,12 @@ char* getpass_or_cancel(char* prompt)
char* password = NULL;
#ifdef DROPBEAR_PASSWORD_ENV
/* Password provided in an environment var */
password = getenv(DROPBEAR_PASSWORD_ENV);
if (password)
{
return password;
}
/* Password provided in an environment var */
password = getenv(DROPBEAR_PASSWORD_ENV);
if (password)
{
return password;
}
#endif
password = getpass(prompt);
@@ -347,3 +348,4 @@ char* getpass_or_cancel(char* prompt)
}
return password;
}
#endif

View File

@@ -31,10 +31,10 @@
#ifdef ENABLE_CLI_INTERACT_AUTH
static unsigned char* get_response(unsigned char* prompt)
static char* get_response(char* prompt)
{
FILE* tty = NULL;
unsigned char* response = NULL;
char* response = NULL;
/* not a password, but a reasonable limit */
char buf[DROPBEAR_MAX_CLI_PASS];
char* ret = NULL;
@@ -50,13 +50,13 @@ static unsigned char* get_response(unsigned char* prompt)
}
if (ret == NULL) {
response = (unsigned char*)m_strdup("");
response = m_strdup("");
} else {
unsigned int buflen = strlen(buf);
/* fgets includes newlines */
if (buflen > 0 && buf[buflen-1] == '\n')
buf[buflen-1] = '\0';
response = (unsigned char*)m_strdup(buf);
response = m_strdup(buf);
}
m_burn(buf, sizeof(buf));
@@ -66,14 +66,14 @@ static unsigned char* get_response(unsigned char* prompt)
void recv_msg_userauth_info_request() {
unsigned char *name = NULL;
unsigned char *instruction = NULL;
char *name = NULL;
char *instruction = NULL;
unsigned int num_prompts = 0;
unsigned int i;
unsigned char *prompt = NULL;
char *prompt = NULL;
unsigned int echo = 0;
unsigned char *response = NULL;
char *response = NULL;
TRACE(("enter recv_msg_recv_userauth_info_request"))
@@ -121,7 +121,7 @@ void recv_msg_userauth_info_request() {
echo = buf_getbool(ses.payload);
if (!echo) {
unsigned char* p = getpass_or_cancel(prompt);
char* p = getpass_or_cancel(prompt);
response = m_strdup(p);
m_burn(p, strlen(p));
} else {
@@ -153,7 +153,7 @@ void cli_auth_interactive() {
strlen(cli_opts.username));
/* service name */
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
SSH_SERVICE_CONNECTION_LEN);
/* method */

View File

@@ -143,10 +143,10 @@ void cli_auth_password() {
buf_putstring(ses.writepayload, cli_opts.username,
strlen(cli_opts.username));
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
SSH_SERVICE_CONNECTION_LEN);
buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD,
buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD,
AUTH_METHOD_PASSWORD_LEN);
buf_putbyte(ses.writepayload, 0); /* FALSE - so says the spec */

View File

@@ -58,7 +58,7 @@ void recv_msg_userauth_pk_ok() {
buffer* keybuf = NULL;
char* algotype = NULL;
unsigned int algolen;
int keytype;
enum signkey_type keytype;
unsigned int remotelen;
TRACE(("enter recv_msg_userauth_pk_ok"))
@@ -141,7 +141,7 @@ void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
const char *algoname = NULL;
int algolen;
unsigned int algolen;
buffer* sigbuf = NULL;
TRACE(("enter send_msg_userauth_pubkey"))
@@ -152,10 +152,10 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
buf_putstring(ses.writepayload, cli_opts.username,
strlen(cli_opts.username));
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
SSH_SERVICE_CONNECTION_LEN);
buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY,
buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY,
AUTH_METHOD_PUBKEY_LEN);
buf_putbyte(ses.writepayload, realsign);

View File

@@ -43,7 +43,7 @@ static void send_chansess_shell_req(struct Channel *channel);
static void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len);
static int cli_init_netcat(struct Channel *channel);
static void cli_tty_setup();
static void cli_tty_setup(void);
const struct ChanType clichansess = {
0, /* sepfds */
@@ -56,7 +56,7 @@ const struct ChanType clichansess = {
static void cli_chansessreq(struct Channel *channel) {
unsigned char* type = NULL;
char* type = NULL;
int wantreply;
TRACE(("enter cli_chansessreq"))
@@ -92,17 +92,6 @@ static void cli_closechansess(struct Channel *UNUSED(channel)) {
}
}
void cli_start_send_channel_request(struct Channel *channel,
unsigned char *type) {
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
buf_putint(ses.writepayload, channel->remotechan);
buf_putstring(ses.writepayload, type, strlen(type));
}
/* Taken from OpenSSH's sshtty.c:
* RCSID("OpenBSD: sshtty.c,v 1.5 2003/09/19 17:43:35 markus Exp "); */
static void cli_tty_setup() {
@@ -283,11 +272,11 @@ void cli_chansess_winchange() {
static void send_chansess_pty_req(struct Channel *channel) {
unsigned char* term = NULL;
char* term = NULL;
TRACE(("enter send_chansess_pty_req"))
cli_start_send_channel_request(channel, "pty-req");
start_send_channel_request(channel, "pty-req");
/* Don't want replies */
buf_putbyte(ses.writepayload, 0);
@@ -316,7 +305,7 @@ static void send_chansess_pty_req(struct Channel *channel) {
static void send_chansess_shell_req(struct Channel *channel) {
unsigned char* reqtype = NULL;
char* reqtype = NULL;
TRACE(("enter send_chansess_shell_req"))
@@ -330,7 +319,7 @@ static void send_chansess_shell_req(struct Channel *channel) {
reqtype = "shell";
}
cli_start_send_channel_request(channel, reqtype);
start_send_channel_request(channel, reqtype);
/* XXX TODO */
buf_putbyte(ses.writepayload, 0); /* Don't want replies */
@@ -403,7 +392,7 @@ static const struct ChanType cli_chan_netcat = {
void cli_send_netcat_request() {
const unsigned char* source_host = "127.0.0.1";
const char* source_host = "127.0.0.1";
const int source_port = 22;
TRACE(("enter cli_send_netcat_request"))
@@ -414,7 +403,7 @@ void cli_send_netcat_request() {
dropbear_exit("Couldn't open initial channel");
}
buf_putstring(ses.writepayload, cli_opts.netcat_host,
buf_putstring(ses.writepayload, cli_opts.netcat_host,
strlen(cli_opts.netcat_host));
buf_putint(ses.writepayload, cli_opts.netcat_port);
@@ -449,7 +438,6 @@ do_escape(unsigned char c) {
case '.':
dropbear_exit("Terminated");
return 1;
break;
case 0x1a:
/* ctrl-z */
cli_tty_cleanup();
@@ -458,9 +446,9 @@ do_escape(unsigned char c) {
cli_tty_setup();
cli_ses.winchange = 1;
return 1;
break;
default:
return 0;
}
return 0;
}
static

View File

@@ -79,7 +79,7 @@ void send_msg_kexdh_init() {
}
cli_ses.curve25519_param = gen_kexcurve25519_param();
}
buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
buf_putstring(ses.writepayload, (const char*)cli_ses.curve25519_param->pub, CURVE25519_LEN);
#endif
break;
}
@@ -186,11 +186,11 @@ static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen,
char* fp = NULL;
FILE *tty = NULL;
char response = 'z';
int response = 'z';
fp = sign_key_fingerprint(keyblob, keybloblen);
if (cli_opts.always_accept_key) {
fprintf(stderr, "\nHost '%s' key accepted unconditionally.\n(%s fingerprint %s)\n",
dropbear_log(LOG_INFO, "\nHost '%s' key accepted unconditionally.\n(%s fingerprint %s)\n",
cli_opts.remotehost,
algoname,
fp);
@@ -290,7 +290,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
int ret;
if (cli_opts.no_hostkey_check) {
fprintf(stderr, "Caution, skipping hostkey check for %s\n", cli_opts.remotehost);
dropbear_log(LOG_INFO, "Caution, skipping hostkey check for %s\n", cli_opts.remotehost);
return;
}
@@ -322,7 +322,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
}
/* Compare hostnames */
if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen),
if (strncmp(cli_opts.remotehost, (const char *) buf_getptr(line, hostlen),
hostlen) != 0) {
continue;
}
@@ -334,7 +334,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
continue;
}
if (strncmp(buf_getptr(line, algolen), algoname, algolen) != 0) {
if (strncmp((const char *) buf_getptr(line, algolen), algoname, algolen) != 0) {
TRACE(("algo doesn't match"))
continue;
}
@@ -346,7 +346,7 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
}
/* Now we're at the interesting hostkey */
ret = cmp_base64_key(keyblob, keybloblen, algoname, algolen,
ret = cmp_base64_key(keyblob, keybloblen, (const unsigned char *) algoname, algolen,
line, &fingerprint);
if (ret == DROPBEAR_SUCCESS) {
@@ -382,9 +382,9 @@ 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, cli_opts.remotehost, hostlen);
buf_putbytes(line, (const unsigned char *) cli_opts.remotehost, hostlen);
buf_putbyte(line, ' ');
buf_putbytes(line, algoname, algolen);
buf_putbytes(line, (const unsigned char *) algoname, algolen);
buf_putbyte(line, ' ');
len = line->size - line->pos;
/* The only failure with base64 is buffer_overflow, but buf_getwriteptr

View File

@@ -30,12 +30,14 @@
#include "session.h"
#include "dbrandom.h"
#include "crypto_desc.h"
#include "netio.h"
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);
static void cli_proxy_cmd(int *sock_in, int *sock_out, pid_t *pid_out);
static void kill_proxy_sighandler(int signo);
#endif
#if defined(DBMULTI_dbclient) || !defined(DROPBEAR_MULTI)
@@ -46,7 +48,7 @@ int main(int argc, char ** argv) {
#endif
int sock_in, sock_out;
char* error = NULL;
struct dropbear_progress_connection *progress = NULL;
_dropbear_exit = cli_dropbear_exit;
_dropbear_log = cli_dropbear_log;
@@ -58,6 +60,12 @@ int main(int argc, char ** argv) {
cli_getopts(argc, argv);
#ifndef DISABLE_SYSLOG
if (opts.usingsyslog) {
startsyslog("dbclient");
}
#endif
TRACE(("user='%s' host='%s' port='%s'", cli_opts.username,
cli_opts.remotehost, cli_opts.remoteport))
@@ -65,23 +73,24 @@ int main(int argc, char ** argv) {
dropbear_exit("signal() error");
}
pid_t proxy_cmd_pid = 0;
#ifdef ENABLE_CLI_PROXYCMD
if (cli_opts.proxycmd) {
cli_proxy_cmd(&sock_in, &sock_out);
cli_proxy_cmd(&sock_in, &sock_out, &proxy_cmd_pid);
m_free(cli_opts.proxycmd);
if (signal(SIGINT, kill_proxy_sighandler) == SIG_ERR ||
signal(SIGTERM, kill_proxy_sighandler) == SIG_ERR ||
signal(SIGHUP, kill_proxy_sighandler) == SIG_ERR) {
dropbear_exit("signal() error");
}
} else
#endif
{
int sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
0, &error);
sock_in = sock_out = sock;
progress = connect_remote(cli_opts.remotehost, cli_opts.remoteport, cli_connected, &ses);
sock_in = sock_out = -1;
}
if (sock_in < 0) {
dropbear_exit("%s", error);
}
cli_session(sock_in, sock_out);
cli_session(sock_in, sock_out, progress, proxy_cmd_pid);
/* not reached */
return -1;
@@ -91,6 +100,7 @@ int main(int argc, char ** argv) {
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
char fmtbuf[300];
char exitmsg[500];
if (!sessinitdone) {
snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s",
@@ -102,22 +112,31 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
cli_opts.remoteport, format);
}
/* Arguments to the exit printout may be unsafe to use after session_cleanup() */
vsnprintf(exitmsg, sizeof(exitmsg), fmtbuf, param);
/* Do the cleanup first, since then the terminal will be reset */
session_cleanup();
/* Avoid printing onwards from terminal cruft */
fprintf(stderr, "\n");
_dropbear_log(LOG_INFO, fmtbuf, param);
dropbear_log(LOG_INFO, "%s", exitmsg);;
exit(exitcode);
}
static void cli_dropbear_log(int UNUSED(priority),
static void cli_dropbear_log(int priority,
const char* format, va_list param) {
char printbuf[1024];
vsnprintf(printbuf, sizeof(printbuf), format, param);
#ifndef DISABLE_SYSLOG
if (opts.usingsyslog) {
syslog(priority, "%s", printbuf);
}
#endif
fprintf(stderr, "%s: %s\n", cli_opts.progname, printbuf);
fflush(stderr);
}
@@ -132,16 +151,28 @@ static void exec_proxy_cmd(void *user_data_cmd) {
}
#ifdef ENABLE_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out) {
static void cli_proxy_cmd(int *sock_in, int *sock_out, pid_t *pid_out) {
char * ex_cmd = NULL;
size_t ex_cmdlen;
int ret;
fill_passwd(cli_opts.own_user);
ret = spawn_command(exec_proxy_cmd, cli_opts.proxycmd,
sock_out, sock_in, NULL, NULL);
ex_cmdlen = strlen(cli_opts.proxycmd) + 6; /* "exec " + command + '\0' */
ex_cmd = m_malloc(ex_cmdlen);
snprintf(ex_cmd, ex_cmdlen, "exec %s", cli_opts.proxycmd);
ret = spawn_command(exec_proxy_cmd, ex_cmd,
sock_out, sock_in, NULL, pid_out);
m_free(ex_cmd);
if (ret == DROPBEAR_FAILURE) {
dropbear_exit("Failed running proxy command");
*sock_in = *sock_out = -1;
}
}
static void kill_proxy_sighandler(int UNUSED(signo)) {
kill_proxy_command();
_exit(1);
}
#endif /* ENABLE_CLI_PROXYCMD */

View File

@@ -33,12 +33,12 @@
cli_runopts cli_opts; /* GLOBAL */
static void printhelp();
static void printhelp(void);
static void parse_hostname(const char* orighostarg);
static void parse_multihop_hostname(const char* orighostarg, const char* argv0);
static void fill_own_user();
static void fill_own_user(void);
#ifdef ENABLE_CLI_PUBKEY_AUTH
static void loadidentityfile(const char* filename);
static void loadidentityfile(const char* filename, int warnfail);
#endif
#ifdef ENABLE_CLI_ANYTCPFWD
static void addforward(const char* str, m_list *fwdlist);
@@ -46,6 +46,7 @@ static void addforward(const char* str, m_list *fwdlist);
#ifdef ENABLE_CLI_NETCAT
static void add_netcat(const char *str);
#endif
static void add_extendedopt(const char *str);
static void printhelp() {
@@ -64,8 +65,9 @@ static void printhelp() {
"-y Always accept remote host key if unknown\n"
"-y -y Don't perform any remote host key checking (caution)\n"
"-s Request a subsystem (use by external sftp)\n"
"-o option Set option in OpenSSH-like format ('-o help' to list options)\n"
#ifdef ENABLE_CLI_PUBKEY_AUTH
"-i <identityfile> (multiple allowed)\n"
"-i <identityfile> (multiple allowed, default %s)\n"
#endif
#ifdef ENABLE_CLI_AGENTFWD
"-A Enable agent auth forwarding\n"
@@ -95,6 +97,9 @@ static void printhelp() {
"-v verbose (compiled with DEBUG_TRACE)\n"
#endif
,DROPBEAR_VERSION, cli_opts.progname,
#ifdef ENABLE_CLI_PUBKEY_AUTH
DROPBEAR_DEFAULT_CLI_AUTHKEY,
#endif
DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
}
@@ -102,25 +107,31 @@ static void printhelp() {
void cli_getopts(int argc, char ** argv) {
unsigned int i, j;
char ** next = 0;
unsigned int cmdlen;
enum {
OPT_EXTENDED_OPTIONS,
#ifdef ENABLE_CLI_PUBKEY_AUTH
int nextiskey = 0; /* A flag if the next argument is a keyfile */
OPT_AUTHKEY,
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
int nextislocal = 0;
OPT_LOCALTCPFWD,
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
int nextisremote = 0;
OPT_REMOTETCPFWD,
#endif
#ifdef ENABLE_CLI_NETCAT
int nextisnetcat = 0;
OPT_NETCAT,
#endif
/* a flag (no arg) if 'next' is NULL, a string-valued option otherwise */
OPT_OTHER
} opt;
unsigned int cmdlen;
char* dummy = NULL; /* Not used for anything real */
char* recv_window_arg = NULL;
char* keepalive_arg = NULL;
char* idle_timeout_arg = NULL;
char *host_arg = NULL;
char c;
/* see printhelp() for options */
cli_opts.progname = argv[0];
@@ -137,6 +148,9 @@ void cli_getopts(int argc, char ** argv) {
#ifdef ENABLE_CLI_PUBKEY_AUTH
cli_opts.privkeys = list_new();
#endif
#ifdef ENABLE_CLI_ANYTCPFWD
cli_opts.exit_on_fwd_failure = 0;
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
cli_opts.localfwds = list_new();
opts.listen_fwd_all = 0;
@@ -153,11 +167,14 @@ void cli_getopts(int argc, char ** argv) {
cli_opts.proxycmd = NULL;
#endif
#ifndef DISABLE_ZLIB
opts.enable_compress = 1;
opts.compress_mode = DROPBEAR_COMPRESS_ON;
#endif
#ifdef ENABLE_USER_ALGO_LIST
opts.cipher_list = NULL;
opts.mac_list = NULL;
#endif
#ifndef DISABLE_SYSLOG
opts.usingsyslog = 0;
#endif
/* not yet
opts.ipv4 = 1;
@@ -169,54 +186,23 @@ void cli_getopts(int argc, char ** argv) {
fill_own_user();
/* Iterate all the arguments */
for (i = 1; i < (unsigned int)argc; i++) {
#ifdef ENABLE_CLI_PUBKEY_AUTH
if (nextiskey) {
/* Load a hostkey since the previous argument was "-i" */
loadidentityfile(argv[i]);
nextiskey = 0;
continue;
}
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
if (nextisremote) {
TRACE(("nextisremote true"))
addforward(argv[i], cli_opts.remotefwds);
nextisremote = 0;
continue;
}
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
if (nextislocal) {
TRACE(("nextislocal true"))
addforward(argv[i], cli_opts.localfwds);
nextislocal = 0;
continue;
}
#endif
#ifdef ENABLE_CLI_NETCAT
if (nextisnetcat) {
TRACE(("nextisnetcat true"))
add_netcat(argv[i]);
nextisnetcat = 0;
continue;
}
#endif
if (next) {
/* The previous flag set a value to assign */
*next = argv[i];
if (*next == NULL) {
dropbear_exit("Invalid null argument");
/* Handle non-flag arguments such as hostname or commands for the remote host */
if (argv[i][0] != '-')
{
if (host_arg == NULL) {
host_arg = argv[i];
continue;
}
next = NULL;
continue;
/* Commands to pass to the remote host. No more flag handling,
commands are consumed below */
break;
}
if (argv[i][0] == '-') {
/* A flag *waves* */
switch (argv[i][1]) {
/* Begins with '-' */
opt = OPT_OTHER;
for (j = 1; (c = argv[i][j]) != '\0' && !next && opt == OPT_OTHER; j++) {
switch (c) {
case 'y': /* always accept the remote hostkey */
if (cli_opts.always_accept_key) {
/* twice means no checking at all */
@@ -229,12 +215,7 @@ void cli_getopts(int argc, char ** argv) {
break;
#ifdef ENABLE_CLI_PUBKEY_AUTH
case 'i': /* an identityfile */
/* Keep scp happy when it changes "-i file" to "-ifile" */
if (strlen(argv[i]) > 2) {
loadidentityfile(&argv[i][2]);
} else {
nextiskey = 1;
}
opt = OPT_AUTHKEY;
break;
#endif
case 't': /* we want a pty */
@@ -252,9 +233,12 @@ void cli_getopts(int argc, char ** argv) {
case 's':
cli_opts.is_subsystem = 1;
break;
case 'o':
opt = OPT_EXTENDED_OPTIONS;
break;
#ifdef ENABLE_CLI_LOCALTCPFWD
case 'L':
nextislocal = 1;
opt = OPT_LOCALTCPFWD;
break;
case 'g':
opts.listen_fwd_all = 1;
@@ -262,12 +246,12 @@ void cli_getopts(int argc, char ** argv) {
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
case 'R':
nextisremote = 1;
opt = OPT_REMOTETCPFWD;
break;
#endif
#ifdef ENABLE_CLI_NETCAT
case 'B':
nextisnetcat = 1;
opt = OPT_NETCAT;
break;
#endif
#ifdef ENABLE_CLI_PROXYCMD
@@ -329,54 +313,94 @@ void cli_getopts(int argc, char ** argv) {
print_version();
exit(EXIT_SUCCESS);
break;
case 'o':
case 'b':
next = &dummy;
/* FALLTHROUGH */
default:
fprintf(stderr,
"WARNING: Ignoring unknown argument '%s'\n", argv[i]);
fprintf(stderr,
"WARNING: Ignoring unknown option -%c\n", c);
break;
} /* Switch */
/* Now we handle args where they might be "-luser" (no spaces)*/
if (next && strlen(argv[i]) > 2) {
*next = &argv[i][2];
next = NULL;
}
continue; /* next argument */
} else {
TRACE(("non-flag arg: '%s'", argv[i]))
/* Either the hostname or commands */
if (host_arg == NULL) {
host_arg = argv[i];
} else {
/* this is part of the commands to send - after this we
* don't parse any more options, and flags are sent as the
* command */
cmdlen = 0;
for (j = i; j < (unsigned int)argc; j++) {
cmdlen += strlen(argv[j]) + 1; /* +1 for spaces */
}
/* Allocate the space */
cli_opts.cmd = (char*)m_malloc(cmdlen);
cli_opts.cmd[0] = '\0';
/* Append all the bits */
for (j = i; j < (unsigned int)argc; j++) {
strlcat(cli_opts.cmd, argv[j], cmdlen);
strlcat(cli_opts.cmd, " ", cmdlen);
}
/* It'll be null-terminated here */
/* We've eaten all the options and flags */
break;
}
}
if (!next && opt == OPT_OTHER) /* got a flag */
continue;
if (c == '\0') {
i++;
j = 0;
if (!argv[i])
dropbear_exit("Missing argument");
}
if (opt == OPT_EXTENDED_OPTIONS) {
TRACE(("opt extended"))
add_extendedopt(&argv[i][j]);
}
else
#ifdef ENABLE_CLI_PUBKEY_AUTH
if (opt == OPT_AUTHKEY) {
TRACE(("opt authkey"))
loadidentityfile(&argv[i][j], 1);
}
else
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
if (opt == OPT_REMOTETCPFWD) {
TRACE(("opt remotetcpfwd"))
addforward(&argv[i][j], cli_opts.remotefwds);
}
else
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
if (opt == OPT_LOCALTCPFWD) {
TRACE(("opt localtcpfwd"))
addforward(&argv[i][j], cli_opts.localfwds);
}
else
#endif
#ifdef ENABLE_CLI_NETCAT
if (opt == OPT_NETCAT) {
TRACE(("opt netcat"))
add_netcat(&argv[i][j]);
}
else
#endif
if (next) {
/* The previous flag set a value to assign */
*next = &argv[i][j];
if (*next == NULL)
dropbear_exit("Invalid null argument");
next = NULL;
}
}
/* Done with options/flags; now handle the hostname (which may not
* start with a hyphen) and optional command */
if (host_arg == NULL) { /* missing hostname */
printhelp();
exit(EXIT_FAILURE);
}
TRACE(("host is: %s", host_arg))
if (i < (unsigned int)argc) {
/* Build the command to send */
cmdlen = 0;
for (j = i; j < (unsigned int)argc; j++)
cmdlen += strlen(argv[j]) + 1; /* +1 for spaces */
/* Allocate the space */
cli_opts.cmd = (char*)m_malloc(cmdlen);
cli_opts.cmd[0] = '\0';
/* Append all the bits */
for (j = i; j < (unsigned int)argc; j++) {
strlcat(cli_opts.cmd, argv[j], cmdlen);
strlcat(cli_opts.cmd, " ", cmdlen);
}
/* It'll be null-terminated here */
TRACE(("cmd is: %s", cli_opts.cmd))
}
/* And now a few sanity checks and setup */
@@ -385,11 +409,6 @@ void cli_getopts(int argc, char ** argv) {
parse_ciphers_macs();
#endif
if (host_arg == NULL) {
printhelp();
exit(EXIT_FAILURE);
}
#ifdef ENABLE_CLI_PROXYCMD
if (cli_opts.proxycmd) {
/* To match the common path of m_freeing it */
@@ -444,6 +463,14 @@ void cli_getopts(int argc, char ** argv) {
}
#endif
#if defined(DROPBEAR_DEFAULT_CLI_AUTHKEY) && defined(ENABLE_CLI_PUBKEY_AUTH)
{
char *expand_path = expand_homedir_path(DROPBEAR_DEFAULT_CLI_AUTHKEY);
loadidentityfile(expand_path, 0);
m_free(expand_path);
}
#endif
/* The hostname gets set up last, since
* in multi-hop mode it will require knowledge
* of other flags such as -i */
@@ -455,14 +482,18 @@ void cli_getopts(int argc, char ** argv) {
}
#ifdef ENABLE_CLI_PUBKEY_AUTH
static void loadidentityfile(const char* filename) {
static void loadidentityfile(const char* filename, int warnfail) {
sign_key *key;
enum signkey_type keytype;
TRACE(("loadidentityfile %s", filename))
key = new_sign_key();
keytype = DROPBEAR_SIGNKEY_ANY;
if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
if (warnfail) {
dropbear_log(LOG_WARNING, "Failed loading keyfile '%s'\n", filename);
}
sign_key_free(key);
} else {
key->type = keytype;
@@ -483,11 +514,14 @@ multihop_passthrough_args() {
m_list_elem *iter;
/* Fill out -i, -y, -W options that make sense for all
* the intermediate processes */
#ifdef ENABLE_CLI_PUBKEY_AUTH
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
{
sign_key * key = (sign_key*)iter->item;
len += 3 + strlen(key->filename);
}
#endif /* ENABLE_CLI_PUBKEY_AUTH */
len += 30; /* space for -W <size>, terminator. */
ret = m_malloc(len);
total = 0;
@@ -505,10 +539,11 @@ multihop_passthrough_args() {
if (opts.recv_window != DEFAULT_RECV_WINDOW)
{
int written = snprintf(ret+total, len-total, "-W %d ", opts.recv_window);
int written = snprintf(ret+total, len-total, "-W %u ", opts.recv_window);
total += written;
}
#ifdef ENABLE_CLI_PUBKEY_AUTH
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
{
sign_key * key = (sign_key*)iter->item;
@@ -517,6 +552,7 @@ multihop_passthrough_args() {
dropbear_assert((unsigned int)written < size);
total += written;
}
#endif /* ENABLE_CLI_PUBKEY_AUTH */
/* if args were passed, total will be not zero, and it will have a space at the end, so remove that */
if (total > 0)
@@ -594,7 +630,7 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
passthrough_args, remainder);
#ifndef DISABLE_ZLIB
/* The stream will be incompressible since it's encrypted. */
opts.enable_compress = 0;
opts.compress_mode = DROPBEAR_COMPRESS_OFF;
#endif
m_free(passthrough_args);
}
@@ -787,3 +823,76 @@ badport:
dropbear_exit("Bad TCP port in '%s'", origstr);
}
#endif
static int match_extendedopt(const char** strptr, const char *optname) {
int seen_eq = 0;
int optlen = strlen(optname);
const char *str = *strptr;
while (isspace(*str)) {
++str;
}
if (strncasecmp(str, optname, optlen) != 0) {
return DROPBEAR_FAILURE;
}
str += optlen;
while (isspace(*str) || (!seen_eq && *str == '=')) {
if (*str == '=') {
seen_eq = 1;
}
++str;
}
if (str-*strptr == optlen) {
/* matched just a prefix of optname */
return DROPBEAR_FAILURE;
}
*strptr = str;
return DROPBEAR_SUCCESS;
}
static int parse_flag_value(const char *value) {
if (strcmp(value, "yes") == 0 || strcmp(value, "true") == 0) {
return 1;
} else if (strcmp(value, "no") == 0 || strcmp(value, "false") == 0) {
return 0;
}
dropbear_exit("Bad yes/no argument '%s'", value);
}
static void add_extendedopt(const char* origstr) {
const char *optstr = origstr;
if (strcmp(origstr, "help") == 0) {
dropbear_log(LOG_INFO, "Available options:\n"
#ifdef ENABLE_CLI_ANYTCPFWD
"\tExitOnForwardFailure\n"
#endif
#ifndef DISABLE_SYSLOG
"\tUseSyslog\n"
#endif
);
exit(EXIT_SUCCESS);
}
#ifdef ENABLE_CLI_ANYTCPFWD
if (match_extendedopt(&optstr, "ExitOnForwardFailure") == DROPBEAR_SUCCESS) {
cli_opts.exit_on_fwd_failure = parse_flag_value(optstr);
return;
}
#endif
#ifndef DISABLE_SYSLOG
if (match_extendedopt(&optstr, "UseSyslog") == DROPBEAR_SUCCESS) {
opts.usingsyslog = parse_flag_value(optstr);
return;
}
#endif
dropbear_log(LOG_WARNING, "Ignoring unknown configuration option '%s'", origstr);
}

View File

@@ -37,11 +37,12 @@
#include "chansession.h"
#include "agentfwd.h"
#include "crypto_desc.h"
#include "netio.h"
static void cli_remoteclosed();
static void cli_sessionloop();
static void cli_session_init();
static void cli_finished();
static void cli_remoteclosed(void) ATTRIB_NORETURN;
static void cli_sessionloop(void);
static void cli_session_init(pid_t proxy_cmd_pid);
static void cli_finished(void) ATTRIB_NORETURN;
static void recv_msg_service_accept(void);
static void cli_session_cleanup(void);
static void recv_msg_global_request_cli(void);
@@ -70,9 +71,15 @@ static const packettype cli_packettypes[] = {
{SSH_MSG_USERAUTH_BANNER, recv_msg_userauth_banner}, /* client */
{SSH_MSG_USERAUTH_SPECIFIC_60, recv_msg_userauth_specific_60}, /* client */
{SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_cli},
{SSH_MSG_CHANNEL_SUCCESS, ignore_recv_response},
{SSH_MSG_CHANNEL_FAILURE, ignore_recv_response},
#ifdef ENABLE_CLI_REMOTETCPFWD
{SSH_MSG_REQUEST_SUCCESS, cli_recv_msg_request_success}, /* client */
{SSH_MSG_REQUEST_FAILURE, cli_recv_msg_request_failure}, /* client */
#else
/* For keepalive */
{SSH_MSG_REQUEST_SUCCESS, ignore_recv_response},
{SSH_MSG_REQUEST_FAILURE, ignore_recv_response},
#endif
{0, 0} /* End */
};
@@ -87,14 +94,28 @@ static const struct ChanType *cli_chantypes[] = {
NULL /* Null termination */
};
void cli_session(int sock_in, int sock_out) {
void cli_connected(int result, int sock, void* userdata, const char *errstring)
{
struct sshsession *myses = userdata;
if (result == DROPBEAR_FAILURE) {
dropbear_exit("Connect failed: %s", errstring);
}
myses->sock_in = myses->sock_out = sock;
update_channel_prio();
}
void cli_session(int sock_in, int sock_out, struct dropbear_progress_connection *progress, pid_t proxy_cmd_pid) {
common_session_init(sock_in, sock_out);
if (progress) {
connect_set_writequeue(progress, &ses.writequeue);
}
chaninitialise(cli_chantypes);
/* Set up cli_ses vars */
cli_session_init();
cli_session_init(proxy_cmd_pid);
/* Ready to go */
sessinitdone = 1;
@@ -102,6 +123,8 @@ void cli_session(int sock_in, int sock_out) {
/* Exchange identification */
send_session_identification();
kexfirstinitialise(); /* initialise the kex state */
send_msg_kexinit();
session_loop(cli_sessionloop);
@@ -116,7 +139,7 @@ static void cli_send_kex_first_guess() {
}
#endif
static void cli_session_init() {
static void cli_session_init(pid_t proxy_cmd_pid) {
cli_ses.state = STATE_NOTHING;
cli_ses.kex_state = KEX_NOTHING;
@@ -135,6 +158,8 @@ static void cli_session_init() {
cli_ses.retval = EXIT_SUCCESS; /* Assume it's clean if we don't get a
specific exit status */
cli_ses.proxy_cmd_pid = proxy_cmd_pid;
TRACE(("proxy command PID='%d'", proxy_cmd_pid));
/* Auth */
cli_ses.lastprivkey = NULL;
@@ -244,6 +269,11 @@ static void cli_sessionloop() {
return;
case USERAUTH_SUCCESS_RCVD:
#ifndef DISABLE_SYSLOG
if (opts.usingsyslog) {
dropbear_log(LOG_INFO, "Authentication succeeded.");
}
#endif
#ifdef DROPBEAR_NONE_CIPHER
if (cli_ses.cipher_none_after_auth)
@@ -310,17 +340,31 @@ static void cli_sessionloop() {
}
void kill_proxy_command(void) {
/*
* Send SIGHUP to proxy command if used. We don't wait() in
* case it hangs and instead rely on init to reap the child
*/
if (cli_ses.proxy_cmd_pid > 1) {
TRACE(("killing proxy command with PID='%d'", cli_ses.proxy_cmd_pid));
kill(cli_ses.proxy_cmd_pid, SIGHUP);
}
}
static void cli_session_cleanup(void) {
if (!sessinitdone) {
return;
}
kill_proxy_command();
/* Set std{in,out,err} back to non-blocking - busybox ash dies nastily if
* we don't revert the flags */
fcntl(cli_ses.stdincopy, F_SETFL, cli_ses.stdinflags);
fcntl(cli_ses.stdoutcopy, F_SETFL, cli_ses.stdoutflags);
fcntl(cli_ses.stderrcopy, F_SETFL, cli_ses.stderrflags);
/* Ignore return value since there's nothing we can do */
(void)fcntl(cli_ses.stdincopy, F_SETFL, cli_ses.stdinflags);
(void)fcntl(cli_ses.stdoutcopy, F_SETFL, cli_ses.stdoutflags);
(void)fcntl(cli_ses.stderrcopy, F_SETFL, cli_ses.stderrflags);
cli_tty_cleanup();
@@ -350,10 +394,10 @@ static void cli_remoteclosed() {
/* Operates in-place turning dirty (untrusted potentially containing control
* characters) text into clean text.
* Note: this is safe only with ascii - other charsets could have problems. */
void cleantext(unsigned char* dirtytext) {
void cleantext(char* dirtytext) {
unsigned int i, j;
unsigned char c;
char c;
j = 0;
for (i = 0; dirtytext[i] != '\0'; i++) {

View File

@@ -30,6 +30,7 @@
#include "runopts.h"
#include "session.h"
#include "ssh.h"
#include "netio.h"
#ifdef ENABLE_CLI_REMOTETCPFWD
static int newtcpforwarded(struct Channel * channel);
@@ -59,6 +60,23 @@ static const struct ChanType cli_chan_tcplocal = {
};
#endif
#ifdef ENABLE_CLI_ANYTCPFWD
static void fwd_failed(const char* format, ...) ATTRIB_PRINTF(1,2);
static void fwd_failed(const char* format, ...)
{
va_list param;
va_start(param, format);
if (cli_opts.exit_on_fwd_failure) {
_dropbear_exit(EXIT_FAILURE, format, param);
} else {
_dropbear_log(LOG_WARNING, format, param);
}
va_end(param);
}
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
void setup_localtcp() {
m_list_elem *iter;
@@ -74,7 +92,7 @@ void setup_localtcp() {
fwd->connectaddr,
fwd->connectport);
if (ret == DROPBEAR_FAILURE) {
dropbear_log(LOG_WARNING, "Failed local port forward %s:%d:%s:%d",
fwd_failed("Failed local port forward %s:%d:%s:%d",
fwd->listenaddr,
fwd->listenport,
fwd->connectaddr,
@@ -180,7 +198,10 @@ void cli_recv_msg_request_failure() {
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);
fwd_failed("Remote TCP forward request failed (port %d -> %s:%d)",
fwd->listenport,
fwd->connectaddr,
fwd->connectport);
return;
}
}
@@ -210,12 +231,11 @@ void setup_remotetcp() {
static int newtcpforwarded(struct Channel * channel) {
char *origaddr = NULL;
char *origaddr = NULL;
unsigned int origport;
m_list_elem * iter = NULL;
struct TCPFwdEntry *fwd;
char portstring[NI_MAXSERV];
int sock;
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
origaddr = buf_getstring(ses.payload, NULL);
@@ -247,26 +267,14 @@ static int newtcpforwarded(struct Channel * channel) {
if (iter == NULL) {
/* We didn't request forwarding on that port */
cleantext(origaddr);
cleantext(origaddr);
dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"",
origaddr, origport);
goto out;
}
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;
goto out;
}
ses.maxfd = MAX(ses.maxfd, sock);
/* We don't set readfd, that will get set after the connection's
* progress succeeds */
channel->writefd = sock;
channel->initconn = 1;
snprintf(portstring, sizeof(portstring), "%u", fwd->connectport);
channel->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done, channel);
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;

View File

@@ -27,7 +27,7 @@
#include "algo.h"
#include "session.h"
#include "dbutil.h"
#include "kex.h"
#include "dh_groups.h"
#include "ltc_prng.h"
#include "ecc.h"
@@ -84,10 +84,14 @@ const struct dropbear_cipher dropbear_nocipher =
/* A few void* s are required to silence warnings
* about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
#ifdef DROPBEAR_ENABLE_CBC_MODE
const struct dropbear_cipher_mode dropbear_mode_cbc =
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
#endif /* DROPBEAR_ENABLE_CBC_MODE */
const struct dropbear_cipher_mode dropbear_mode_none =
{void_start, void_cipher, void_cipher};
#ifdef DROPBEAR_ENABLE_CTR_MODE
/* a wrapper to make ctr_start and cbc_start look the same */
static int dropbear_big_endian_ctr_start(int cipher,
@@ -98,7 +102,7 @@ static int dropbear_big_endian_ctr_start(int cipher,
}
const struct dropbear_cipher_mode dropbear_mode_ctr =
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
#endif
#endif /* DROPBEAR_ENABLE_CTR_MODE */
/* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
{&hash_desc, keysize, hashsize} */
@@ -137,21 +141,24 @@ algo_type sshciphers[] = {
#ifdef DROPBEAR_AES128
{"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
#endif
#ifdef DROPBEAR_3DES
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
#endif
#ifdef DROPBEAR_AES256
{"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
#endif
#ifdef DROPBEAR_TWOFISH_CTR
/* twofish ctr is conditional as it hasn't been tested for interoperability, see options.h */
#ifdef DROPBEAR_TWOFISH256
{"twofish256-ctr", 0, &dropbear_twofish256, 1, &dropbear_mode_ctr},
#endif
#ifdef DROPBEAR_TWOFISH128
{"twofish128-ctr", 0, &dropbear_twofish128, 1, &dropbear_mode_ctr},
#endif
#endif /* DROPBEAR_TWOFISH_CTR */
#endif /* DROPBEAR_ENABLE_CTR_MODE */
/* CBC modes are always enabled */
#ifdef DROPBEAR_ENABLE_CBC_MODE
#ifdef DROPBEAR_AES128
{"aes128-cbc", 0, &dropbear_aes128, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_3DES
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_AES256
{"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc},
#endif
@@ -162,9 +169,16 @@ algo_type sshciphers[] = {
#ifdef DROPBEAR_TWOFISH128
{"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_3DES
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
#endif
#ifdef DROPBEAR_3DES
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_BLOWFISH
{"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc},
#endif
#endif /* DROPBEAR_ENABLE_CBC_MODE */
#ifdef DROPBEAR_NONE_CIPHER
{"none", 0, (void*)&dropbear_nocipher, 1, &dropbear_mode_none},
#endif
@@ -172,18 +186,18 @@ algo_type sshciphers[] = {
};
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
#ifdef DROPBEAR_SHA1_HMAC
{"hmac-sha1", 0, &dropbear_sha1, 1, NULL},
#endif
#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_MD5_HMAC
{"hmac-md5", 0, (void*)&dropbear_md5, 1, NULL},
#endif
@@ -195,7 +209,13 @@ algo_type sshhashes[] = {
#ifndef DISABLE_ZLIB
algo_type ssh_compress[] = {
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL},
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
{NULL, 0, NULL, 0, NULL}
};
algo_type ssh_delaycompress[] = {
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
{NULL, 0, NULL, 0, NULL}
@@ -228,20 +248,30 @@ algo_type sshhostkey[] = {
{NULL, 0, NULL, 0, NULL}
};
#if DROPBEAR_DH_GROUP1
static const struct dropbear_kex kex_dh_group1 = {DROPBEAR_KEX_NORMAL_DH, dh_p_1, DH_P_1_LEN, NULL, &sha1_desc };
static const struct dropbear_kex kex_dh_group14 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha1_desc };
#endif
#if DROPBEAR_DH_GROUP14
static const struct dropbear_kex kex_dh_group14_sha1 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha1_desc };
#if DROPBEAR_DH_GROUP14_256
static const struct dropbear_kex kex_dh_group14_sha256 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha256_desc };
#endif
#endif
#if DROPBEAR_DH_GROUP16
static const struct dropbear_kex kex_dh_group16_sha512 = {DROPBEAR_KEX_NORMAL_DH, dh_p_16, DH_P_16_LEN, NULL, &sha512_desc };
#endif
/* These can't be const since dropbear_ecc_fill_dp() fills out
ecc_curve at runtime */
#ifdef DROPBEAR_ECDH
#ifdef DROPBEAR_ECC_256
static struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc };
static const struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc };
#endif
#ifdef DROPBEAR_ECC_384
static struct dropbear_kex kex_ecdh_nistp384 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp384, &sha384_desc };
static const struct dropbear_kex kex_ecdh_nistp384 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp384, &sha384_desc };
#endif
#ifdef DROPBEAR_ECC_521
static struct dropbear_kex kex_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp521, &sha512_desc };
static const struct dropbear_kex kex_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp521, &sha512_desc };
#endif
#endif /* DROPBEAR_ECDH */
@@ -265,8 +295,18 @@ algo_type sshkex[] = {
{"ecdh-sha2-nistp256", 0, &kex_ecdh_nistp256, 1, NULL},
#endif
#endif
#if DROPBEAR_DH_GROUP14
#if DROPBEAR_DH_GROUP14_256
{"diffie-hellman-group14-sha256", 0, &kex_dh_group14_sha256, 1, NULL},
#endif
{"diffie-hellman-group14-sha1", 0, &kex_dh_group14_sha1, 1, NULL},
#endif
#if DROPBEAR_DH_GROUP1
{"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL},
{"diffie-hellman-group14-sha1", 0, &kex_dh_group14, 1, NULL},
#endif
#if DROPBEAR_DH_GROUP16
{"diffie-hellman-group16-sha512", 0, &kex_dh_group16_sha512, 1, NULL},
#endif
#ifdef USE_KEXGUESS2
{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
#endif
@@ -298,17 +338,17 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
unsigned int donefirst = 0;
buffer *algolist = NULL;
algolist = buf_new(200);
algolist = buf_new(300);
for (i = 0; localalgos[i].name != NULL; i++) {
if (localalgos[i].usable) {
if (donefirst)
buf_putbyte(algolist, ',');
donefirst = 1;
len = strlen(localalgos[i].name);
buf_putbytes(algolist, localalgos[i].name, len);
buf_putbytes(algolist, (const unsigned char *) localalgos[i].name, len);
}
}
buf_putstring(buf, algolist->data, algolist->len);
buf_putstring(buf, (const char*)algolist->data, algolist->len);
buf_free(algolist);
}
@@ -321,12 +361,12 @@ 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];
char * algolist = NULL;
const 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;
const char **clinames, **servnames;
if (goodguess) {
*goodguess = 0;
@@ -471,7 +511,7 @@ algolist_string(algo_type 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));
ret_list = m_strdup((const char *) buf_getptr(b, b->len - b->pos));
buf_free(b);
return ret_list;
}

View File

@@ -35,20 +35,21 @@
#include "ssh.h"
#include "listener.h"
#include "runopts.h"
#include "netio.h"
static void send_msg_channel_open_failure(unsigned int remotechan, int reason,
const unsigned char *text, const unsigned char *lang);
const char *text, const char *lang);
static void send_msg_channel_open_confirmation(struct Channel* channel,
unsigned int recvwindow,
unsigned int recvmaxpacket);
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf);
static int writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
const unsigned char *moredata, unsigned int *morelen);
static void send_msg_channel_window_adjust(struct Channel *channel,
unsigned int incr);
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 check_in_progress(struct Channel *channel);
static unsigned int write_pending(struct Channel * channel);
static void check_close(struct Channel *channel);
static void close_chan_fd(struct Channel *channel, int fd, int how);
@@ -99,15 +100,6 @@ 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
@@ -163,12 +155,11 @@ static struct Channel* newchannel(unsigned int remotechan,
newchan->writefd = FD_UNINIT;
newchan->readfd = FD_UNINIT;
newchan->errfd = FD_CLOSED; /* this isn't always set to start with */
newchan->initconn = 0;
newchan->await_open = 0;
newchan->flushing = 0;
newchan->writebuf = cbuf_new(0); /* resized later by chan_initwritebuf */
newchan->recvwindow = 0;
newchan->writebuf = cbuf_new(opts.recv_window);
newchan->recvwindow = opts.recv_window;
newchan->extrabuf = NULL; /* The user code can set it up */
newchan->recvdonelen = 0;
@@ -242,27 +233,20 @@ void channelio(fd_set *readfds, fd_set *writefds) {
/* write to program/pipe stdin */
if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) {
if (channel->initconn) {
/* XXX should this go somewhere cleaner? */
check_in_progress(channel);
continue; /* Important not to use the channel after
check_in_progress(), as it may be NULL */
}
writechannel(channel, channel->writefd, channel->writebuf);
writechannel(channel, channel->writefd, channel->writebuf, NULL, NULL);
do_check_close = 1;
}
/* stderr for client mode */
if (ERRFD_IS_WRITE(channel)
&& channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) {
writechannel(channel, channel->errfd, channel->extrabuf);
writechannel(channel, channel->errfd, channel->extrabuf, NULL, NULL);
do_check_close = 1;
}
if (ses.channel_signal_pending) {
/* SIGCHLD can change channel state for server sessions */
do_check_close = 1;
ses.channel_signal_pending = 0;
}
/* handle any channel closing etc */
@@ -374,27 +358,26 @@ static void check_close(struct Channel *channel) {
* if so, set up the channel properly. Otherwise, the channel is cleaned up, so
* it is important that the channel reference isn't used after a call to this
* function */
static void check_in_progress(struct Channel *channel) {
void channel_connect_done(int result, int sock, void* user_data, const char* UNUSED(errstring)) {
int val;
socklen_t vallen = sizeof(val);
struct Channel *channel = user_data;
TRACE(("enter check_in_progress"))
TRACE(("enter channel_connect_done"))
if (getsockopt(channel->writefd, SOL_SOCKET, SO_ERROR, &val, &vallen)
|| val != 0) {
send_msg_channel_open_failure(channel->remotechan,
SSH_OPEN_CONNECT_FAILED, "", "");
close(channel->writefd);
remove_channel(channel);
TRACE(("leave check_in_progress: fail"))
} else {
chan_initwritebuf(channel);
if (result == DROPBEAR_SUCCESS)
{
channel->readfd = channel->writefd = sock;
channel->conn_pending = NULL;
send_msg_channel_open_confirmation(channel, channel->recvwindow,
channel->recvmaxpacket);
channel->readfd = channel->writefd;
channel->initconn = 0;
TRACE(("leave check_in_progress: success"))
TRACE(("leave channel_connect_done: success"))
}
else
{
send_msg_channel_open_failure(channel->remotechan,
SSH_OPEN_CONNECT_FAILED, "", "");
remove_channel(channel);
TRACE(("leave check_in_progress: fail"))
}
}
@@ -402,7 +385,7 @@ 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 %p", channel))
TRACE(("enter send_msg_channel_close %p", (void*)channel))
if (channel->type->closehandler
&& !channel->close_handler_done) {
channel->type->closehandler(channel);
@@ -440,35 +423,120 @@ static void send_msg_channel_eof(struct Channel *channel) {
TRACE(("leave send_msg_channel_eof"))
}
/* Called to write data out to the local side of the channel.
* Only called when we know we can write to a channel, writes as much as
* possible */
static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
#ifndef HAVE_WRITEV
static int writechannel_fallback(struct Channel* channel, int fd, circbuffer *cbuf,
const unsigned char *UNUSED(moredata), unsigned int *morelen) {
int len, maxlen;
unsigned char *circ_p1, *circ_p2;
unsigned int circ_len1, circ_len2;
ssize_t written;
TRACE(("enter writechannel fd %d", fd))
maxlen = cbuf_readlen(cbuf);
/* Write the data out */
len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen);
if (len <= 0) {
TRACE(("errno %d len %d", errno, len))
if (len < 0 && errno != EINTR) {
close_chan_fd(channel, fd, SHUT_WR);
}
TRACE(("leave writechannel: len <= 0"))
return;
if (morelen) {
/* fallback doesn't consume moredata */
*morelen = 0;
}
TRACE(("writechannel wrote %d", len))
cbuf_incrread(cbuf, len);
channel->recvdonelen += len;
/* Write the first portion of the circular buffer */
cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2);
written = write(fd, circ_p1, circ_len1);
if (written < 0) {
if (errno != EINTR && errno != EAGAIN) {
TRACE(("channel IO write error fd %d %s", fd, strerror(errno)))
close_chan_fd(channel, fd, SHUT_WR);
return DROPBEAR_FAILURE;
}
} else {
cbuf_incrread(cbuf, written);
channel->recvdonelen += written;
}
return DROPBEAR_SUCCESS;
}
#endif /* !HAVE_WRITEV */
#ifdef HAVE_WRITEV
static int writechannel_writev(struct Channel* channel, int fd, circbuffer *cbuf,
const unsigned char *moredata, unsigned int *morelen) {
struct iovec iov[3];
unsigned char *circ_p1, *circ_p2;
unsigned int circ_len1, circ_len2;
int io_count = 0;
ssize_t written;
cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2);
if (circ_len1 > 0) {
TRACE(("circ1 %d", circ_len1))
iov[io_count].iov_base = circ_p1;
iov[io_count].iov_len = circ_len1;
io_count++;
}
if (circ_len2 > 0) {
TRACE(("circ2 %d", circ_len2))
iov[io_count].iov_base = circ_p2;
iov[io_count].iov_len = circ_len2;
io_count++;
}
if (morelen) {
assert(moredata);
TRACE(("more %d", *morelen))
iov[io_count].iov_base = (void*)moredata;
iov[io_count].iov_len = *morelen;
io_count++;
}
if (io_count == 0) {
/* writechannel may sometimes be called twice in a main loop iteration.
From common_recv_msg_channel_data() then channelio().
The second call may not have any data to write, so we just return. */
TRACE(("leave writechannel, no data"))
return DROPBEAR_SUCCESS;
}
if (morelen) {
/* Default return value, none consumed */
*morelen = 0;
}
written = writev(fd, iov, io_count);
if (written < 0) {
if (errno != EINTR && errno != EAGAIN) {
TRACE(("channel IO write error fd %d %s", fd, strerror(errno)))
close_chan_fd(channel, fd, SHUT_WR);
return DROPBEAR_FAILURE;
}
} else {
int cbuf_written = MIN(circ_len1+circ_len2, (unsigned int)written);
cbuf_incrread(cbuf, cbuf_written);
if (morelen) {
*morelen = written - cbuf_written;
}
channel->recvdonelen += written;
}
return DROPBEAR_SUCCESS;
}
#endif /* HAVE_WRITEV */
/* Called to write data out to the local side of the channel.
Writes the circular buffer contents and also the "moredata" buffer
if not null. Will ignore EAGAIN.
Returns DROPBEAR_FAILURE if writing to fd had an error and the channel is being closed, DROPBEAR_SUCCESS otherwise */
static int writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
const unsigned char *moredata, unsigned int *morelen) {
int ret = DROPBEAR_SUCCESS;
TRACE(("enter writechannel fd %d", fd))
#ifdef HAVE_WRITEV
ret = writechannel_writev(channel, fd, cbuf, moredata, morelen);
#else
ret = writechannel_fallback(channel, fd, cbuf, moredata, morelen);
#endif
/* Window adjust handling */
if (channel->recvdonelen >= RECV_WINDOWEXTEND) {
/* Set it back to max window */
send_msg_channel_window_adjust(channel, channel->recvdonelen);
channel->recvwindow += channel->recvdonelen;
channel->recvdonelen = 0;
@@ -480,11 +548,13 @@ static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) {
channel->recvwindow <= cbuf_getavail(channel->extrabuf));
TRACE(("leave writechannel"))
return ret;
}
/* Set the file descriptors for the main select in session.c
* This avoid channels which don't have any window available, are closed, etc*/
void setchannelfds(fd_set *readfds, fd_set *writefds) {
void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads) {
unsigned int i;
struct Channel * channel;
@@ -502,7 +572,7 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
FD if there's the possibility of "~."" to kill an
interactive session (the read_mangler) */
if (channel->transwindow > 0
&& (ses.dataallowed || channel->read_mangler)) {
&& ((ses.dataallowed && allow_reads) || channel->read_mangler)) {
if (channel->readfd >= 0) {
FD_SET(channel->readfd, readfds);
@@ -514,8 +584,7 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
}
/* Stuff from the wire */
if (channel->initconn
||(channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0)) {
if (channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0) {
FD_SET(channel->writefd, writefds);
}
@@ -586,11 +655,11 @@ static void remove_channel(struct Channel * channel) {
/* close the FDs in case they haven't been done
* yet (they might have been shutdown etc) */
TRACE(("CLOSE writefd %d", channel->writefd))
close(channel->writefd);
m_close(channel->writefd);
TRACE(("CLOSE readfd %d", channel->readfd))
close(channel->readfd);
m_close(channel->readfd);
TRACE(("CLOSE errfd %d", channel->errfd))
close(channel->errfd);
m_close(channel->errfd);
}
if (!channel->close_handler_done
@@ -599,6 +668,10 @@ static void remove_channel(struct Channel * channel) {
channel->close_handler_done = 1;
}
if (channel->conn_pending) {
cancel_connect(channel->conn_pending);
}
ses.channels[channel->index] = NULL;
m_free(channel);
ses.chancount--;
@@ -616,7 +689,7 @@ void recv_msg_channel_request() {
channel = getchannel();
TRACE(("enter recv_msg_channel_request %p", channel))
TRACE(("enter recv_msg_channel_request %p", (void*)channel))
if (channel->sent_close) {
TRACE(("leave recv_msg_channel_request: already closed channel"))
@@ -627,7 +700,12 @@ void recv_msg_channel_request() {
&& !channel->close_handler_done) {
channel->type->reqhandler(channel);
} else {
send_msg_channel_failure(channel);
int wantreply;
buf_eatstring(ses.payload);
wantreply = buf_getbool(ses.payload);
if (wantreply) {
send_msg_channel_failure(channel);
}
}
TRACE(("leave recv_msg_channel_request"))
@@ -744,6 +822,8 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
unsigned int maxdata;
unsigned int buflen;
unsigned int len;
unsigned int consumed;
int res;
TRACE(("enter recv_msg_channel_data"))
@@ -770,25 +850,36 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
dropbear_exit("Oversized packet");
}
/* We may have to run throught twice, if the buffer wraps around. Can't
* just "leave it for next time" like with writechannel, since this
* is payload data */
len = datalen;
while (len > 0) {
buflen = cbuf_writelen(cbuf);
buflen = MIN(buflen, len);
memcpy(cbuf_writeptr(cbuf, buflen),
buf_getptr(ses.payload, buflen), buflen);
cbuf_incrwrite(cbuf, buflen);
buf_incrpos(ses.payload, buflen);
len -= buflen;
}
dropbear_assert(channel->recvwindow >= datalen);
channel->recvwindow -= datalen;
dropbear_assert(channel->recvwindow <= opts.recv_window);
/* Attempt to write the data immediately without having to put it in the circular buffer */
consumed = datalen;
res = writechannel(channel, fd, cbuf, buf_getptr(ses.payload, datalen), &consumed);
datalen -= consumed;
buf_incrpos(ses.payload, consumed);
/* We may have to run throught twice, if the buffer wraps around. Can't
* just "leave it for next time" like with writechannel, since this
* is payload data.
* If the writechannel() failed then remaining data is discarded */
if (res == DROPBEAR_SUCCESS) {
len = datalen;
while (len > 0) {
buflen = cbuf_writelen(cbuf);
buflen = MIN(buflen, len);
memcpy(cbuf_writeptr(cbuf, buflen),
buf_getptr(ses.payload, buflen), buflen);
cbuf_incrwrite(cbuf, buflen);
buf_incrpos(ses.payload, buflen);
len -= buflen;
}
}
TRACE(("leave recv_msg_channel_data"))
}
@@ -829,7 +920,7 @@ static void send_msg_channel_window_adjust(struct Channel* channel,
/* Handle a new channel request, performing any channel-type-specific setup */
void recv_msg_channel_open() {
unsigned char *type;
char *type;
unsigned int typelen;
unsigned int remotechan, transwindow, transmaxpacket;
struct Channel *channel;
@@ -878,6 +969,7 @@ void recv_msg_channel_open() {
if (channel == NULL) {
TRACE(("newchannel returned NULL"))
errtype = SSH_OPEN_RESOURCE_SHORTAGE;
goto failure;
}
@@ -899,8 +991,6 @@ void recv_msg_channel_open() {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
}
chan_initwritebuf(channel);
/* success */
send_msg_channel_open_confirmation(channel, channel->recvwindow,
channel->recvmaxpacket);
@@ -947,7 +1037,7 @@ void send_msg_channel_success(struct Channel *channel) {
/* Send a channel open failure message, with a corresponding reason
* code (usually resource shortage or unknown chan type) */
static void send_msg_channel_open_failure(unsigned int remotechan,
int reason, const unsigned char *text, const unsigned char *lang) {
int reason, const char *text, const char *lang) {
TRACE(("enter send_msg_channel_open_failure"))
CHECKCLEARTOWRITE();
@@ -955,8 +1045,8 @@ static void send_msg_channel_open_failure(unsigned int remotechan,
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN_FAILURE);
buf_putint(ses.writepayload, remotechan);
buf_putint(ses.writepayload, reason);
buf_putstring(ses.writepayload, text, strlen((char*)text));
buf_putstring(ses.writepayload, lang, strlen((char*)lang));
buf_putstring(ses.writepayload, text, strlen(text));
buf_putstring(ses.writepayload, lang, strlen(lang));
encrypt_packet();
TRACE(("leave send_msg_channel_open_failure"))
@@ -996,7 +1086,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
}
} else {
TRACE(("CLOSE some fd %d", fd))
close(fd);
m_close(fd);
closein = closeout = 1;
}
@@ -1019,7 +1109,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
if (channel->type->sepfds && channel->readfd == FD_CLOSED
&& channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) {
TRACE(("CLOSE (finally) of %d", fd))
close(fd);
m_close(fd);
}
}
@@ -1043,7 +1133,6 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
/* 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);
@@ -1134,3 +1223,30 @@ void send_msg_request_failure() {
buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE);
encrypt_packet();
}
struct Channel* get_any_ready_channel() {
size_t i;
if (ses.chancount == 0) {
return NULL;
}
for (i = 0; i < ses.chansize; i++) {
struct Channel *chan = ses.channels[i];
if (chan
&& !(chan->sent_eof || chan->recv_eof)
&& !(chan->await_open)) {
return chan;
}
}
return NULL;
}
void start_send_channel_request(struct Channel *channel,
char *type) {
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
buf_putint(ses.writepayload, channel->remotechan);
buf_putstring(ses.writepayload, type, strlen(type));
}

View File

@@ -29,6 +29,7 @@
#include "buffer.h"
#include "session.h"
#include "kex.h"
#include "dh_groups.h"
#include "ssh.h"
#include "packet.h"
#include "bignum.h"
@@ -37,55 +38,13 @@
#include "ecc.h"
#include "crypto_desc.h"
/* diffie-hellman-group1-sha1 value for p */
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,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
/* diffie-hellman-group14-sha1 value for p */
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();
static void gen_new_keys();
static void kexinitialise(void);
static void gen_new_keys(void);
#ifndef DISABLE_ZLIB
static void gen_new_zstream_recv();
static void gen_new_zstream_trans();
static void gen_new_zstream_recv(void);
static void gen_new_zstream_trans(void);
#endif
static void read_kex_algos();
static void read_kex_algos(void);
/* helper function for gen_new_keys */
static void hashkeys(unsigned char *out, unsigned int outlen,
const hash_state * hs, const unsigned char X);
@@ -238,14 +197,24 @@ void recv_msg_newkeys() {
void kexfirstinitialise() {
ses.kexstate.donefirstkex = 0;
#ifndef DISABLE_ZLIB
if (opts.enable_compress) {
ses.compress_algos = ssh_compress;
} else
#endif
#ifdef DISABLE_ZLIB
ses.compress_algos = ssh_nocompress;
#else
switch (opts.compress_mode)
{
ses.compress_algos = ssh_nocompress;
case DROPBEAR_COMPRESS_DELAYED:
ses.compress_algos = ssh_delaycompress;
break;
case DROPBEAR_COMPRESS_ON:
ses.compress_algos = ssh_compress;
break;
case DROPBEAR_COMPRESS_OFF:
ses.compress_algos = ssh_nocompress;
break;
}
#endif
kexinitialise();
}
@@ -303,7 +272,7 @@ static void hashkeys(unsigned char *out, unsigned int outlen,
hash_desc->done(&hs2, tmpout);
memcpy(&out[offset], tmpout, MIN(outlen - offset, hash_desc->hashsize));
}
m_burn(&hs2, sizeof(hash_state));
}
/* Generate the actual encryption/integrity keys, using the results of the
@@ -339,17 +308,17 @@ static void gen_new_keys() {
ses.hash = NULL;
if (IS_DROPBEAR_CLIENT) {
trans_IV = C2S_IV;
recv_IV = S2C_IV;
trans_key = C2S_key;
recv_key = S2C_key;
trans_IV = C2S_IV;
recv_IV = S2C_IV;
trans_key = C2S_key;
recv_key = S2C_key;
mactransletter = 'E';
macrecvletter = 'F';
} else {
trans_IV = S2C_IV;
recv_IV = C2S_IV;
trans_key = S2C_key;
recv_key = C2S_key;
trans_IV = S2C_IV;
recv_IV = C2S_IV;
trans_key = S2C_key;
recv_key = C2S_key;
mactransletter = 'F';
macrecvletter = 'E';
}
@@ -403,6 +372,7 @@ static void gen_new_keys() {
m_burn(C2S_key, sizeof(C2S_key));
m_burn(S2C_IV, sizeof(S2C_IV));
m_burn(S2C_key, sizeof(S2C_key));
m_burn(&hs, sizeof(hash_state));
TRACE(("leave gen_new_keys"))
}
@@ -500,7 +470,7 @@ void recv_msg_kexinit() {
/* start the kex hash */
local_ident_len = strlen(LOCAL_IDENT);
remote_ident_len = strlen((char*)ses.remoteident);
remote_ident_len = strlen(ses.remoteident);
kexhashbuf_len = local_ident_len + remote_ident_len
+ ses.transkexinit->len + ses.payload->len
@@ -514,17 +484,18 @@ void recv_msg_kexinit() {
read_kex_algos();
/* V_C, the client's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf,
(unsigned char*)LOCAL_IDENT, local_ident_len);
buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len);
/* V_S, the server's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
/* I_C, the payload of the client's SSH_MSG_KEXINIT */
buf_putstring(ses.kexhashbuf,
ses.transkexinit->data, ses.transkexinit->len);
buf_putstring(ses.kexhashbuf,
(const char*)ses.transkexinit->data, ses.transkexinit->len);
/* I_S, the payload of the server's SSH_MSG_KEXINIT */
buf_setpos(ses.payload, 0);
buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len);
buf_setpos(ses.payload, ses.payload_beginning);
buf_putstring(ses.kexhashbuf,
(const char*)buf_getptr(ses.payload, ses.payload->len-ses.payload->pos),
ses.payload->len-ses.payload->pos);
ses.requirenext = SSH_MSG_KEXDH_REPLY;
} else {
/* SERVER */
@@ -532,18 +503,19 @@ void recv_msg_kexinit() {
/* read the peer's choice of algos */
read_kex_algos();
/* V_C, the client's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
/* V_S, the server's version string (CR and NL excluded) */
buf_putstring(ses.kexhashbuf,
(unsigned char*)LOCAL_IDENT, local_ident_len);
buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len);
/* I_C, the payload of the client's SSH_MSG_KEXINIT */
buf_setpos(ses.payload, 0);
buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len);
buf_setpos(ses.payload, ses.payload_beginning);
buf_putstring(ses.kexhashbuf,
(const char*)buf_getptr(ses.payload, ses.payload->len-ses.payload->pos),
ses.payload->len-ses.payload->pos);
/* I_S, the payload of the server's SSH_MSG_KEXINIT */
buf_putstring(ses.kexhashbuf,
ses.transkexinit->data, ses.transkexinit->len);
buf_putstring(ses.kexhashbuf,
(const char*)ses.transkexinit->data, ses.transkexinit->len);
ses.requirenext = SSH_MSG_KEXDH_INIT;
}
@@ -618,16 +590,20 @@ void free_kexdh_param(struct kex_dh_param *param)
void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
sign_key *hostkey) {
mp_int dh_p;
DEF_MP_INT(dh_p);
DEF_MP_INT(dh_p_min1);
mp_int *dh_e = NULL, *dh_f = NULL;
/* read the prime and generator*/
m_mp_init(&dh_p);
m_mp_init_multi(&dh_p, &dh_p_min1, NULL);
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
|| mp_cmp_d(dh_pub_them, 0) != MP_GT) {
if (mp_sub_d(&dh_p, 1, &dh_p_min1) != MP_OKAY) {
dropbear_exit("Diffie-Hellman error");
}
/* Check that dh_pub_them (dh_e or dh_f) is in the range [2, p-2] */
if (mp_cmp(dh_pub_them, &dh_p_min1) != MP_LT
|| mp_cmp_d(dh_pub_them, 1) != MP_GT) {
dropbear_exit("Diffie-Hellman error");
}
@@ -638,7 +614,7 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
}
/* clear no longer needed vars */
mp_clear_multi(&dh_p, NULL);
mp_clear_multi(&dh_p, &dh_p_min1, NULL);
/* From here on, the code needs to work with the _same_ vars on each side,
* not vice-versaing for client/server */
@@ -686,6 +662,9 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
ecc_key *Q_C, *Q_S, *Q_them;
Q_them = buf_get_ecc_raw_pubkey(pub_them, algo_kex->ecc_curve);
if (Q_them == NULL) {
dropbear_exit("ECC error");
}
ses.dh_K = dropbear_ecc_shared_secret(Q_them, &param->key);
@@ -740,6 +719,7 @@ void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_
unsigned char out[CURVE25519_LEN];
const unsigned char* Q_C = NULL;
const unsigned char* Q_S = NULL;
char zeroes[CURVE25519_LEN] = {0};
if (buf_pub_them->len != CURVE25519_LEN)
{
@@ -747,6 +727,11 @@ void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_
}
curve25519_donna(out, param->priv, buf_pub_them->data);
if (constant_time_memcmp(zeroes, out, CURVE25519_LEN) == 0) {
dropbear_exit("Bad curve25519");
}
m_mp_alloc_init_multi(&ses.dh_K, NULL);
bytes_to_mp(ses.dh_K, out, CURVE25519_LEN);
m_burn(out, sizeof(out));
@@ -764,9 +749,9 @@ void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_
/* K_S, the host key */
buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
/* Q_C, client's ephemeral public key octet string */
buf_putstring(ses.kexhashbuf, Q_C, CURVE25519_LEN);
buf_putstring(ses.kexhashbuf, (const char*)Q_C, CURVE25519_LEN);
/* Q_S, server's ephemeral public key octet string */
buf_putstring(ses.kexhashbuf, Q_S, CURVE25519_LEN);
buf_putstring(ses.kexhashbuf, (const char*)Q_S, CURVE25519_LEN);
/* K, the shared secret */
buf_putmpint(ses.kexhashbuf, ses.dh_K);
@@ -798,6 +783,7 @@ static void finish_kexhashbuf(void) {
buf_burn(ses.kexhashbuf);
buf_free(ses.kexhashbuf);
m_burn(&hs, sizeof(hash_state));
ses.kexhashbuf = NULL;
/* first time around, we set the session_id to H */
@@ -805,7 +791,6 @@ static void finish_kexhashbuf(void) {
/* create the session_id, this never needs freeing */
ses.session_id = buf_newcopy(ses.hash);
}
}
/* read the other side's algo list. buf_match_algo is a callback to match

View File

@@ -1,7 +1,7 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -34,11 +34,12 @@
#include "kex.h"
#include "channel.h"
#include "runopts.h"
#include "netio.h"
static void checktimeouts();
static long select_timeout();
static void checktimeouts(void);
static long select_timeout(void);
static int ident_readln(int fd, char* buf, int count);
static void read_session_identification();
static void read_session_identification(void);
struct sshsession ses; /* GLOBAL */
@@ -53,17 +54,29 @@ int exitflag = 0; /* GLOBAL */
void common_session_init(int sock_in, int sock_out) {
time_t now;
#ifdef DEBUG_TRACE
debug_start_net();
#endif
TRACE(("enter session_init"))
ses.sock_in = sock_in;
ses.sock_out = sock_out;
ses.maxfd = MAX(sock_in, sock_out);
if (sock_in >= 0) {
setnonblocking(sock_in);
}
if (sock_out >= 0) {
setnonblocking(sock_out);
}
ses.socket_prio = DROPBEAR_PRIO_DEFAULT;
/* Sets it to lowdelay */
update_channel_prio();
now = monotonic_now();
ses.connect_time = now;
ses.last_packet_time_keepalive_recv = now;
ses.last_packet_time_idle = now;
ses.last_packet_time_any_sent = 0;
@@ -78,8 +91,6 @@ void common_session_init(int sock_in, int sock_out) {
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
kexfirstinitialise(); /* initialise the kex state */
ses.writepayload = buf_new(TRANS_MAX_PAYLOAD_LEN);
ses.transseq = 0;
@@ -140,6 +151,7 @@ void session_loop(void(*loophandler)()) {
/* main loop, select()s for all sockets in use */
for(;;) {
const int writequeue_has_space = (ses.writequeue_len <= 2*TRANS_MAX_PAYLOAD_LEN);
timeout.tv_sec = select_timeout();
timeout.tv_usec = 0;
@@ -147,21 +159,34 @@ void session_loop(void(*loophandler)()) {
FD_ZERO(&readfd);
dropbear_assert(ses.payload == NULL);
/* 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)) {
FD_SET(ses.sock_out, &writefd);
}
/* We get woken up when signal handlers write to this pipe.
SIGCHLD in svr-chansession is the only one currently. */
FD_SET(ses.signal_pipe[0], &readfd);
ses.channel_signal_pending = 0;
/* set up for channels which can be read/written */
setchannelfds(&readfd, &writefd);
setchannelfds(&readfd, &writefd, writequeue_has_space);
/* Pending connections to test */
set_connect_fds(&writefd);
/* We delay reading from the input socket during initial setup until
after we have written out our initial KEXINIT packet (empty writequeue).
This means our initial packet can be in-flight while we're doing a blocking
read for the remote ident.
We also avoid reading from the socket if the writequeue is full, that avoids
replies backing up */
if (ses.sock_in != -1
&& (ses.remoteident || isempty(&ses.writequeue))
&& writequeue_has_space) {
FD_SET(ses.sock_in, &readfd);
}
/* Ordering is important, this test must occur after any other function
might have queued packets (such as connection handlers) */
if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
FD_SET(ses.sock_out, &writefd);
}
val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);
@@ -187,7 +212,9 @@ void session_loop(void(*loophandler)()) {
wake up the select() above. */
if (FD_ISSET(ses.signal_pipe[0], &readfd)) {
char x;
TRACE(("signal pipe set"))
while (read(ses.signal_pipe[0], &x, 1) > 0) {}
ses.channel_signal_pending = 1;
}
/* check for auth timeout, rekeying required etc */
@@ -210,11 +237,13 @@ void session_loop(void(*loophandler)()) {
process_packet();
}
}
/* if required, flush out any queued reply packets that
were being held up during a KEX */
maybe_flush_reply_queue();
handle_connect_fds(&writefd);
/* process pipes etc for the channels, ses.dataallowed == 0
* during rekeying ) */
channelio(&readfd, &writefd);
@@ -236,6 +265,15 @@ void session_loop(void(*loophandler)()) {
/* Not reached */
}
static void cleanup_buf(buffer **buf) {
if (!*buf) {
return;
}
buf_burn(*buf);
buf_free(*buf);
*buf = NULL;
}
/* clean up a session on exit */
void session_cleanup() {
@@ -247,24 +285,47 @@ void session_cleanup() {
return;
}
/* BEWARE of changing order of functions here. */
/* Must be before extra_session_cleanup() */
chancleanup();
if (ses.extra_session_cleanup) {
ses.extra_session_cleanup();
}
chancleanup();
/* Cleaning up keys must happen after other cleanup
functions which might queue packets */
if (ses.session_id) {
buf_burn(ses.session_id);
buf_free(ses.session_id);
ses.session_id = NULL;
/* After these are freed most functions will fail */
#ifdef DROPBEAR_CLEANUP
/* listeners call cleanup functions, this should occur before
other session state is freed. */
remove_all_listeners();
remove_connect_pending();
while (!isempty(&ses.writequeue)) {
buf_free(dequeue(&ses.writequeue));
}
if (ses.hash) {
buf_burn(ses.hash);
buf_free(ses.hash);
ses.hash = NULL;
m_free(ses.remoteident);
m_free(ses.authstate.pw_dir);
m_free(ses.authstate.pw_name);
m_free(ses.authstate.pw_shell);
m_free(ses.authstate.pw_passwd);
m_free(ses.authstate.username);
#endif
cleanup_buf(&ses.session_id);
cleanup_buf(&ses.hash);
cleanup_buf(&ses.payload);
cleanup_buf(&ses.readbuf);
cleanup_buf(&ses.writepayload);
cleanup_buf(&ses.kexhashbuf);
cleanup_buf(&ses.transkexinit);
if (ses.dh_K) {
mp_clear(ses.dh_K);
}
m_free(ses.dh_K);
m_burn(ses.keys, sizeof(struct key_context));
m_free(ses.keys);
@@ -273,10 +334,8 @@ void 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);
buf_putbytes(writebuf, (const unsigned char *) LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
writebuf_enqueue(writebuf, 0);
}
static void read_session_identification() {
@@ -394,14 +453,30 @@ static int ident_readln(int fd, char* buf, int count) {
return pos+1;
}
void ignore_recv_response() {
/* Do nothing */
TRACE(("Ignored msg_request_response"))
}
static void send_msg_keepalive() {
CHECKCLEARTOWRITE();
time_t old_time_idle = ses.last_packet_time_idle;
/* Try to force a response from the other end. Some peers will
reply with SSH_MSG_REQUEST_FAILURE, some will reply with SSH_MSG_UNIMPLEMENTED */
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
/* A short string */
buf_putstring(ses.writepayload, "k@dropbear.nl", 0);
struct Channel *chan = get_any_ready_channel();
CHECKCLEARTOWRITE();
if (chan) {
/* Channel requests are preferable, more implementations
handle them than SSH_MSG_GLOBAL_REQUEST */
TRACE(("keepalive channel request %d", chan->index))
start_send_channel_request(chan, DROPBEAR_KEEPALIVE_STRING);
} else {
TRACE(("keepalive global request"))
/* Some peers will reply with SSH_MSG_REQUEST_FAILURE,
some will reply with SSH_MSG_UNIMPLEMENTED, some will exit. */
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
buf_putstring(ses.writepayload, DROPBEAR_KEEPALIVE_STRING,
strlen(DROPBEAR_KEEPALIVE_STRING));
}
buf_putbyte(ses.writepayload, 1); /* want_reply */
encrypt_packet();
@@ -418,6 +493,11 @@ static void checktimeouts() {
time_t now;
now = monotonic_now();
if (IS_DROPBEAR_SERVER && ses.connect_time != 0
&& now - ses.connect_time >= AUTH_TIMEOUT) {
dropbear_close("Timeout before auth");
}
/* we can't rekey if we haven't done remote ident exchange yet */
if (ses.remoteident == NULL) {
return;
@@ -430,7 +510,10 @@ static void checktimeouts() {
send_msg_kexinit();
}
if (opts.keepalive_secs > 0) {
if (opts.keepalive_secs > 0 && ses.authstate.authdone) {
/* Avoid sending keepalives prior to auth - those are
not valid pre-auth packet types */
/* Send keepalives if we've been idle */
if (now - ses.last_packet_time_any_sent >= opts.keepalive_secs) {
send_msg_keepalive();
@@ -455,20 +538,39 @@ static void checktimeouts() {
}
}
static void update_timeout(long limit, long now, long last_event, long * timeout) {
TRACE2(("update_timeout limit %ld, now %ld, last %ld, timeout %ld",
limit, now, last_event, *timeout))
if (last_event > 0 && limit > 0) {
*timeout = MIN(*timeout, last_event+limit-now);
TRACE2(("new timeout %ld", *timeout))
}
}
static long select_timeout() {
/* determine the minimum timeout that might be required, so
as to avoid waking when unneccessary */
long ret = LONG_MAX;
if (KEX_REKEY_TIMEOUT > 0)
ret = MIN(KEX_REKEY_TIMEOUT, ret);
/* AUTH_TIMEOUT is only relevant before authdone */
if (ses.authstate.authdone != 1 && AUTH_TIMEOUT > 0)
ret = MIN(AUTH_TIMEOUT, ret);
if (opts.keepalive_secs > 0)
ret = MIN(opts.keepalive_secs, ret);
if (opts.idle_timeout_secs > 0)
ret = MIN(opts.idle_timeout_secs, ret);
return ret;
long timeout = LONG_MAX;
long now = monotonic_now();
update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout);
if (ses.authstate.authdone != 1 && IS_DROPBEAR_SERVER) {
/* AUTH_TIMEOUT is only relevant before authdone */
update_timeout(AUTH_TIMEOUT, now, ses.connect_time, &timeout);
}
if (ses.authstate.authdone) {
update_timeout(opts.keepalive_secs, now,
MAX(ses.last_packet_time_keepalive_recv, ses.last_packet_time_keepalive_sent),
&timeout);
}
update_timeout(opts.idle_timeout_secs, now, ses.last_packet_time_idle,
&timeout);
/* clamp negative timeouts to zero - event has already triggered */
return MAX(timeout, 0);
}
const char* get_user_shell() {
@@ -524,6 +626,11 @@ void update_channel_prio() {
TRACE(("update_channel_prio"))
if (ses.sock_out < 0) {
TRACE(("leave update_channel_prio: no socket"))
return;
}
new_prio = DROPBEAR_PRIO_BULK;
for (i = 0; i < ses.chansize; i++) {
struct Channel *channel = ses.channels[i];
@@ -554,7 +661,7 @@ void update_channel_prio() {
}
if (new_prio != ses.socket_prio) {
TRACE(("Dropbear priority transitioning %4.4s -> %4.4s", (char*)&ses.socket_prio, (char*)&new_prio))
TRACE(("Dropbear priority transitioning %d -> %d", ses.socket_prio, new_prio))
set_sock_priority(ses.sock_out, new_prio);
ses.socket_prio = new_prio;
}

View File

@@ -235,7 +235,7 @@ void setusershell() {
static char **initshells() {
/* don't touch this list. */
const char *okshells[] = { "/bin/sh", "/bin/csh", NULL };
static const char *okshells[] = { "/bin/sh", "/bin/csh", NULL };
register char **sp, *cp;
register FILE *fp;
struct stat statb;

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _COMPAT_H_
#define _COMPAT_H_
#ifndef DROPBEAR_COMPAT_H_
#define DROPBEAR_COMPAT_H_
#include "includes.h"
@@ -44,13 +44,13 @@ char *basename(const char* path);
#endif
#ifndef HAVE_GETUSERSHELL
char *getusershell();
void setusershell();
void endusershell();
char *getusershell(void);
void setusershell(void);
void endusershell(void);
#endif
#ifndef _PATH_DEVNULL
#define _PATH_DEVNULL "/dev/null"
#ifndef DROPBEAR_PATH_DEVNULL
#define DROPBEAR_PATH_DEVNULL "/dev/null"
#endif
#endif /* _COMPAT_H_ */
#endif /* DROPBEAR_COMPAT_H_ */

View File

@@ -82,9 +82,19 @@ AC_CHECK_DECL(__UCLIBC__,
AC_MSG_NOTICE([Using uClibc - login() and logout() probably don't work, so we won't use them.])
],,,)
# Checks for libraries.
AC_CHECK_LIB(crypt, crypt, CRYPTLIB="-lcrypt")
dnl We test for crypt() specially. On Linux (and others?) it resides in libcrypt
dnl but we don't want link all binaries to -lcrypt, just dropbear server.
dnl OS X doesn't need -lcrypt
AC_CHECK_FUNC(crypt, found_crypt_func=here)
AC_CHECK_LIB(crypt, crypt,
[
CRYPTLIB="-lcrypt"
found_crypt_func=here
])
AC_SUBST(CRYPTLIB)
if test "t$found_crypt_func" = there; then
AC_DEFINE(HAVE_CRYPT, 1, [crypt() function])
fi
# Check if zlib is needed
AC_ARG_WITH(zlib,
@@ -265,7 +275,7 @@ AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage
#include <sys/types.h>
#include <sys/socket.h>
]],
[[ struct sockaddr_storage s; ]])],
[[ if (sizeof(struct sockaddr_storage)) return 0 ]])],
[ ac_cv_have_struct_sockaddr_storage="yes" ],
[ ac_cv_have_struct_sockaddr_storage="no" ]
)
@@ -279,7 +289,7 @@ AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [
#include <sys/types.h>
#include <netinet/in.h>
]],
[[ struct sockaddr_in6 s; s.sin6_family = 0; ]])],
[[ if (sizeof(struct sockaddr_in6)) return 0 ]])],
[ ac_cv_have_struct_sockaddr_in6="yes" ],
[ ac_cv_have_struct_sockaddr_in6="no" ]
)
@@ -293,7 +303,7 @@ AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
#include <sys/types.h>
#include <netinet/in.h>
]],
[[ struct in6_addr s; s.s6_addr[0] = 0; ]])],
[[ if (sizeof(struct in6_addr)) return 0 ]])],
[ ac_cv_have_struct_in6_addr="yes" ],
[ ac_cv_have_struct_in6_addr="no" ]
)
@@ -308,7 +318,7 @@ AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
#include <sys/socket.h>
#include <netdb.h>
]],
[[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ]])],
[[ if (sizeof(struct addrinfo)) return 0 ]])],
[ ac_cv_have_struct_addrinfo="yes" ],
[ ac_cv_have_struct_addrinfo="no" ]
)
@@ -365,6 +375,9 @@ AC_CHECK_FUNCS(logout updwtmp logwtmp)
AC_CHECK_HEADERS([mach/mach_time.h])
AC_CHECK_FUNCS(mach_absolute_time)
AC_CHECK_FUNCS(explicit_bzero memset_s)
AC_ARG_ENABLE(bundled-libtom,
[ --enable-bundled-libtom Force using bundled libtomcrypt/libtommath even if a system version exists.
--disable-bundled-libtom Force using system libtomcrypt/libtommath, fail if it does not exist.
@@ -632,7 +645,7 @@ fi
AC_PROG_GCC_TRADITIONAL
AC_FUNC_MEMCMP
AC_FUNC_SELECT_ARGTYPES
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev])
AC_CHECK_FUNCS([dup2 getpass 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))
@@ -660,6 +673,7 @@ fi
AC_EXEEXT
# XXX there must be a nicer way to do this
if test $BUNDLED_LIBTOM = 1 ; then
AS_MKDIR_P(libtomcrypt/src/ciphers/aes)
AS_MKDIR_P(libtomcrypt/src/ciphers/safer)
AS_MKDIR_P(libtomcrypt/src/ciphers/twofish)
@@ -710,16 +724,29 @@ AS_MKDIR_P(libtomcrypt/src/pk/katja)
AS_MKDIR_P(libtomcrypt/src/pk/pkcs1)
AS_MKDIR_P(libtomcrypt/src/pk/rsa)
AS_MKDIR_P(libtomcrypt/src/prngs)
LIBTOM_FILES="libtomcrypt/Makefile libtommath/Makefile"
fi
AC_CONFIG_HEADER(config.h)
AC_CONFIG_FILES(Makefile libtomcrypt/Makefile libtommath/Makefile)
AC_CONFIG_FILES(Makefile $LIBTOM_FILES)
AC_OUTPUT
AC_MSG_NOTICE()
if test $BUNDLED_LIBTOM = 1 ; then
AC_MSG_NOTICE(Using bundled libtomcrypt and libtommath)
AC_MSG_NOTICE([Using bundled libtomcrypt and libtommath])
else
AC_MSG_NOTICE(Using system libtomcrypt and libtommath)
AC_MSG_NOTICE([Using system libtomcrypt and libtommath])
fi
if test "x$ac_cv_func_getpass" != xyes; then
AC_MSG_NOTICE()
AC_MSG_NOTICE([getpass() not available, dbclient will only have public-key authentication])
fi
if test "t$found_crypt_func" != there; then
AC_MSG_NOTICE()
AC_MSG_NOTICE([crypt() not available, dropbear server will not have password authentication])
fi
AC_MSG_NOTICE()
AC_MSG_NOTICE(Now edit options.h to choose features.)
AC_MSG_NOTICE([Now edit options.h to choose features.])

View File

@@ -1,9 +1,9 @@
#ifndef _CRYPTO_DESC_H
#define _CRYPTO_DESC_H
#ifndef DROPBEAR_CRYPTO_DESC_H
#define DROPBEAR_CRYPTO_DESC_H
void crypto_init();
void crypto_init(void);
extern int dropbear_ltc_prng;
#endif /* _CRYPTO_DESC_H */
#endif /* DROPBEAR_CRYPTO_DESC_H */

View File

@@ -527,7 +527,7 @@ static void fmonty(limb *x2, limb *z2, /* output 2Q */
memcpy(origx, x, 10 * sizeof(limb));
fsum(x, z);
fdifference(z, origx); // does x - z
fdifference(z, origx); /* does x - z */
memcpy(origxprime, xprime, sizeof(limb) * 10);
fsum(xprime, zprime);
@@ -554,7 +554,7 @@ static void fmonty(limb *x2, limb *z2, /* output 2Q */
fproduct(x2, xx, zz);
freduce_degree(x2);
freduce_coefficients(x2);
fdifference(zz, xx); // does zz = xx - zz
fdifference(zz, xx); /* does zz = xx - zz */
memset(zzz + 10, 0, sizeof(limb) * 9);
fscalar_product(zzz, zz, 121665);
/* No need to call freduce_degree here:
@@ -641,9 +641,9 @@ cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
memcpy(resultz, nqz, sizeof(limb) * 10);
}
// -----------------------------------------------------------------------------
// Shamelessly copied from djb's code
// -----------------------------------------------------------------------------
/* -----------------------------------------------------------------------------
* Shamelessly copied from djb's code
* ----------------------------------------------------------------------------- */
static void
crecip(limb *out, const limb *z) {
limb z2[10];

View File

@@ -3,25 +3,32 @@
dbclient \- lightweight SSH client
.SH SYNOPSIS
.B dbclient
[\-Tt] [\-p
[\fIflag arguments\fR] [\-p
.I port\fR] [\-i
.I id\fR] [\-L
.I l\fR:\fIh\fR:\fIr\fR] [\-R
.I l\fR:\fIh\fR:\fIr\fR] [\-l
.I l\fR:\fIh\fR:\fIp\fR] [\-R
.I l\fR:\fIh\fR:\fIp\fR] [\-l
.IR user ]
.I host
.RI [ \fImore\ flags\fR ]
.RI [ command ]
.B dbclient
[
.I args ]
.I [user1]@host1[^port1],[user2]@host2[^port2],...
[\fIargs\fR]
[\fIuser1\fR]@\fIhost1\fR[^\fIport1\fR],[\fIuser2\fR]@\fIhost2\fR[^\fIport2\fR],...
.SH DESCRIPTION
.B dbclient
is a small SSH client
.SH OPTIONS
.TP
.TP
.B command
A command to run on the remote host. This will normally be run by the remote host
using the user's shell. The command begins at the first hyphen argument after the
host argument. If no command is specified an interactive terminal will be opened
(see -t and -T).
.TP
.B \-p \fIport
Connect to
.I port
@@ -33,9 +40,9 @@ Identity file.
Read the identity key from file
.I idfile
(multiple allowed). This file is created with dropbearkey(1) or converted
from OpenSSH with dropbearconvert(1).
from OpenSSH with dropbearconvert(1). The default path ~/.ssh/id_dropbear is used
.TP
.B \-L [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
.B \-L\fR [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
Local port forwarding.
Forward the port
.I listenport
@@ -44,7 +51,7 @@ on the local host through the SSH connection to port
on the host
.IR host .
.TP
.B \-R [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
.B \-R\fR [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
Remote port forwarding.
Forward the port
.I listenport
@@ -60,10 +67,12 @@ Login as
on the remote host.
.TP
.B \-t
Allocate a PTY.
Allocate a PTY. This is the default when no command is given, it gives a full
interactive remote session. The main effect is that keystrokes are sent remotely
immediately as opposed to local line-based editing.
.TP
.B \-T
Don't allocate a PTY.
Don't allocate a PTY. This is the default a command is given. See -t.
.TP
.B \-N
Don't request a remote shell or run any commands. Any command arguments are ignored.
@@ -105,7 +114,8 @@ Disconnect the session if no traffic is transmitted or received for \fIidle_time
.B \-J \fIproxy_command
Use the standard input/output of the program \fIproxy_command\fR rather than using
a normal TCP connection. A hostname should be still be provided, as this is used for
comparing saved hostkeys.
comparing saved hostkeys. This command will be executed as "exec proxy_command ..." with the
default shell.
.TP
.B \-B \fIendhost:endport
"Netcat-alike" mode, where Dropbear will connect to the given host, then create a
@@ -118,6 +128,22 @@ Specify a comma separated list of ciphers to enable. Use \fI-c help\fR to list p
.B \-m \fIMAClist
Specify a comma separated list of authentication MACs to enable. Use \fI-m help\fR to list possibilities.
.TP
.B \-o \fIoption
Can be used to give options in the format used by OpenSSH config file. This is
useful for specifying options for which there is no separate command-line flag.
For full details of the options listed below, and their possible values, see
ssh_config(5).
For now following options have been implemented:
.RS
.TP
.B ExitOnForwardFailure
Specifies whether dbclient should terminate the connection if it cannot set up all requested local and remote port forwardings. The argument must be “yes” or “no”. The default is “no”.
.TP
.B UseSyslog
Send dbclient log messages to syslog in addition to stderr.
.RE
.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
.TP
@@ -129,7 +155,7 @@ Dropbear will also allow multiple "hops" to be specified, separated by commas. I
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 hash (eg matt@martello^44 ).
A port for a host can be specified with a caret (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
@@ -157,6 +183,10 @@ SSH_ASKPASS should be set to the path of a program that will return a password
on standard output. This program will only be used if either DISPLAY is set and
standard input is not a TTY, or the environment variable SSH_ASKPASS_ALWAYS is
set.
.SH NOTES
If compiled with zlib support and if the server supports it, dbclient will
always use compression.
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.br

25
dbhelpers.c Normal file
View File

@@ -0,0 +1,25 @@
#include "dbhelpers.h"
#include "includes.h"
/* Erase data */
void m_burn(void *data, unsigned int len) {
#if defined(HAVE_MEMSET_S)
memset_s(data, len, 0x0, len);
#elif defined(HAVE_EXPLICIT_BZERO)
explicit_bzero(data, len);
#else
/* Based on the method in David Wheeler's
* "Secure Programming for Linux and Unix HOWTO". May not be safe
* against link-time optimisation. */
volatile char *p = data;
if (data == NULL)
return;
while (len--) {
*p++ = 0x0;
}
#endif
}

21
dbhelpers.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef DROPBEAR_DBHELPERS_H_
#define DROPBEAR_DBHELPERS_H_
/* This header defines some things that are also used by libtomcrypt/math.
We avoid including normal include.h since that can result in conflicting
definitinos - only include config.h */
#include "config.h"
#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
void m_burn(void* data, unsigned int len);
#endif /* DROPBEAR_DBHELPERS_H_ */

View File

@@ -26,17 +26,13 @@
/* definitions are cleanest if we just put them here */
int dropbear_main(int argc, char ** argv);
int cli_main(int argc, char ** argv);
int dropbearkey_main(int argc, char ** argv);
int dropbearconvert_main(int argc, char ** argv);
int scp_main(int argc, char ** argv);
int main(int argc, char ** argv) {
char * progname;
if (argc > 0) {
/* figure which form we're being called as */
progname = basename(argv[0]);
static int runprog(const char *progname, int argc, char ** argv, int *match) {
*match = DROPBEAR_SUCCESS;
#ifdef DBMULTI_dropbear
if (strcmp(progname, "dropbear") == 0) {
@@ -64,10 +60,28 @@ int main(int argc, char ** argv) {
return scp_main(argc, argv);
}
#endif
*match = DROPBEAR_FAILURE;
return 1;
}
int main(int argc, char ** argv) {
int i;
for (i = 0; i < 2; i++) {
/* Try symlink first, then try as an argument eg "dropbearmulti dbclient host ..." */
if (argc > i) {
int match, res;
/* figure which form we're being called as */
const char* progname = basename(argv[i]);
res = runprog(progname, argc-i, &argv[i], &match);
if (match == DROPBEAR_SUCCESS) {
return res;
}
}
}
fprintf(stderr, "Dropbear SSH multi-purpose v%s\n"
"Make a symlink pointing at this binary with one of the following names:\n"
"Make a symlink pointing at this binary with one of the\n"
"following names or run 'dropbearmulti <command>'.\n"
#ifdef DBMULTI_dropbear
"'dropbear' - the Dropbear server\n"
#endif

View File

@@ -32,7 +32,7 @@
/* 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
#define MAX_COUNTER (1<<30)
static unsigned char hashpool[SHA1_HASH_SIZE] = {0};
static int donerandinit = 0;
@@ -141,7 +141,7 @@ out:
return ret;
}
void addrandom(char * buf, unsigned int len)
void addrandom(unsigned char * buf, unsigned int len)
{
hash_state hs;
@@ -306,7 +306,7 @@ void gen_random_mpint(mp_int *max, mp_int *rand) {
/* keep regenerating until we get one satisfying
* 0 < rand < max */
} while (mp_cmp(rand, max) != MP_LT);
} while (!(mp_cmp(rand, max) == MP_LT && mp_cmp_d(rand, 0) == MP_GT));
m_burn(randbuf, len);
m_free(randbuf);
}

View File

@@ -22,14 +22,14 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _RANDOM_H_
#define _RANDOM_H_
#ifndef DROPBEAR_RANDOM_H_
#define DROPBEAR_RANDOM_H_
#include "includes.h"
void seedrandom();
void seedrandom(void);
void genrandom(unsigned char* buf, unsigned int len);
void addrandom(char * buf, unsigned int len);
void addrandom(unsigned char * buf, unsigned int len);
void gen_random_mpint(mp_int *max, mp_int *rand);
#endif /* _RANDOM_H_ */
#endif /* DROPBEAR_RANDOM_H_ */

425
dbutil.c
View File

@@ -84,9 +84,9 @@ int debug_trace = 0;
#endif
#ifndef DISABLE_SYSLOG
void startsyslog() {
void startsyslog(const char *ident) {
openlog(PROGNAME, LOG_PID, LOG_AUTHPRIV);
openlog(ident, LOG_PID, LOG_AUTHPRIV);
}
#endif /* DISABLE_SYSLOG */
@@ -150,18 +150,44 @@ void dropbear_log(int priority, const char* format, ...) {
#ifdef DEBUG_TRACE
static double debug_start_time = -1;
void debug_start_net()
{
if (getenv("DROPBEAR_DEBUG_NET_TIMESTAMP"))
{
/* Timestamps start from first network activity */
struct timeval tv;
gettimeofday(&tv, NULL);
debug_start_time = tv.tv_sec + (tv.tv_usec / 1000000.0);
TRACE(("Resetting Dropbear TRACE timestamps"))
}
}
static double time_since_start()
{
double nowf;
struct timeval tv;
gettimeofday(&tv, NULL);
nowf = tv.tv_sec + (tv.tv_usec / 1000000.0);
if (debug_start_time < 0)
{
debug_start_time = nowf;
return 0;
}
return nowf - debug_start_time;
}
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) %d.%d: ", getpid(), (int)tv.tv_sec, (int)tv.tv_usec);
fprintf(stderr, "TRACE (%d) %f: ", getpid(), time_since_start());
vfprintf(stderr, format, param);
fprintf(stderr, "\n");
va_end(param);
@@ -170,7 +196,6 @@ void dropbear_trace(const char* format, ...) {
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;
@@ -180,193 +205,14 @@ void dropbear_trace2(const char* format, ...) {
return;
}
gettimeofday(&tv, NULL);
va_start(param, format);
fprintf(stderr, "TRACE2 (%d) %d.%d: ", getpid(), (int)tv.tv_sec, (int)tv.tv_usec);
fprintf(stderr, "TRACE2 (%d) %f: ", getpid(), time_since_start());
vfprintf(stderr, format, param);
fprintf(stderr, "\n");
va_end(param);
}
#endif /* DEBUG_TRACE */
void set_sock_nodelay(int sock) {
int val;
/* disable nagle */
val = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
}
void set_sock_priority(int sock, enum dropbear_prio prio) {
int iptos_val = 0, so_prio_val = 0, rc;
/* Don't log ENOTSOCK errors so that this can harmlessly be called
* on a client '-J' proxy pipe */
/* set the TOS bit for either ipv4 or ipv6 */
#ifdef IPTOS_LOWDELAY
if (prio == DROPBEAR_PRIO_LOWDELAY) {
iptos_val = IPTOS_LOWDELAY;
} else if (prio == DROPBEAR_PRIO_BULK) {
iptos_val = IPTOS_THROUGHPUT;
}
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
}
#endif
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
}
#endif
#ifdef SO_PRIORITY
if (prio == DROPBEAR_PRIO_LOWDELAY) {
so_prio_val = TC_PRIO_INTERACTIVE;
} else if (prio == DROPBEAR_PRIO_BULK) {
so_prio_val = TC_PRIO_BULK;
}
/* linux specific, sets QoS class. see tc-prio(8) */
rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &so_prio_val, sizeof(so_prio_val));
if (rc < 0 && errno != ENOTSOCK)
dropbear_log(LOG_WARNING, "Couldn't set SO_PRIORITY (%s)",
strerror(errno));
#endif
}
/* Listen on address:port.
* Special cases are address of "" listening on everything,
* and address of NULL listening on localhost only.
* Returns the number of sockets bound on success, or -1 on failure. On
* failure, if errstring wasn't NULL, it'll be a newly malloced error
* string.*/
int dropbear_listen(const char* address, const char* port,
int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
struct addrinfo hints, *res = NULL, *res0 = NULL;
int err;
unsigned int nsock;
struct linger linger;
int val;
int sock;
TRACE(("enter dropbear_listen"))
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
hints.ai_socktype = SOCK_STREAM;
/* for calling getaddrinfo:
address == NULL and !AI_PASSIVE: local loopback
address == NULL and AI_PASSIVE: all interfaces
address != NULL: whatever the address says */
if (!address) {
TRACE(("dropbear_listen: local loopback"))
} else {
if (address[0] == '\0') {
TRACE(("dropbear_listen: all interfaces"))
address = NULL;
}
hints.ai_flags = AI_PASSIVE;
}
err = getaddrinfo(address, port, &hints, &res0);
if (err) {
if (errstring != NULL && *errstring == NULL) {
int len;
len = 20 + strlen(gai_strerror(err));
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
}
if (res0) {
freeaddrinfo(res0);
res0 = NULL;
}
TRACE(("leave dropbear_listen: failed resolving"))
return -1;
}
nsock = 0;
for (res = res0; res != NULL && nsock < sockcount;
res = res->ai_next) {
/* Get a socket */
socks[nsock] = socket(res->ai_family, res->ai_socktype,
res->ai_protocol);
sock = socks[nsock]; /* For clarity */
if (sock < 0) {
err = errno;
TRACE(("socket() failed"))
continue;
}
/* Various useful socket options */
val = 1;
/* set to reuse, quick timeout */
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
linger.l_onoff = 1;
linger.l_linger = 5;
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
#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_nodelay(sock);
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
err = errno;
close(sock);
TRACE(("bind(%s) failed", port))
continue;
}
if (listen(sock, DROPBEAR_LISTEN_BACKLOG) < 0) {
err = errno;
close(sock);
TRACE(("listen() failed"))
continue;
}
*maxfd = MAX(*maxfd, sock);
nsock++;
}
if (res0) {
freeaddrinfo(res0);
res0 = NULL;
}
if (nsock == 0) {
if (errstring != NULL && *errstring == NULL) {
int len;
len = 20 + strlen(strerror(err));
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error listening: %s", strerror(err));
}
TRACE(("leave dropbear_listen: failure, %s", strerror(err)))
return -1;
}
TRACE(("leave dropbear_listen: success, %d socks bound", nsock))
return nsock;
}
/* Connect to a given unix socket. The socket is blocking */
#ifdef ENABLE_CONNECT_UNIX
int connect_unix(const char* path) {
@@ -390,93 +236,6 @@ int connect_unix(const char* path) {
}
#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 */
/* TODO: maxfd */
int connect_remote(const char* remotehost, const char* remoteport,
int nonblocking, char ** errstring) {
struct addrinfo *res0 = NULL, *res = NULL, hints;
int sock;
int err;
TRACE(("enter connect_remote"))
if (errstring != NULL) {
*errstring = NULL;
}
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = PF_UNSPEC;
err = getaddrinfo(remotehost, remoteport, &hints, &res0);
if (err) {
if (errstring != NULL && *errstring == NULL) {
int len;
len = 100 + strlen(gai_strerror(err));
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error resolving '%s' port '%s'. %s",
remotehost, remoteport, gai_strerror(err));
}
TRACE(("Error resolving: %s", gai_strerror(err)))
return -1;
}
sock = -1;
err = EADDRNOTAVAIL;
for (res = res0; res; res = res->ai_next) {
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock < 0) {
err = errno;
continue;
}
if (nonblocking) {
setnonblocking(sock);
}
if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
if (errno == EINPROGRESS && nonblocking) {
TRACE(("Connect in progress"))
break;
} else {
err = errno;
close(sock);
sock = -1;
continue;
}
}
break; /* Success */
}
if (sock < 0 && !(errno == EINPROGRESS && nonblocking)) {
/* Failed */
if (errstring != NULL && *errstring == NULL) {
int len;
len = 20 + strlen(strerror(err));
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error connecting: %s", strerror(err));
}
TRACE(("Error connecting: %s", strerror(err)))
} else {
/* Success */
set_sock_nodelay(sock);
}
freeaddrinfo(res0);
if (sock > 0 && errstring != NULL && *errstring != NULL) {
m_free(*errstring);
}
TRACE(("leave connect_remote: sock %d\n", sock))
return sock;
}
/* Sets up a pipe for a, returning three non-blocking file descriptors
* and the pid. exec_fn is the function that will actually execute the child process,
* it will be run after the child has fork()ed, and is passed exec_data.
@@ -612,88 +371,6 @@ 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() */
void getaddrstring(struct sockaddr_storage* addr,
char **ret_host, char **ret_port,
int host_lookup) {
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
* of the specific structure. Some older linux systems (glibc 2.1.3
* such as debian potato) have sockaddr_storage.__ss_family instead
* but we'll ignore them */
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
if (addr->ss_family == AF_INET) {
len = sizeof(struct sockaddr_in);
}
#ifdef AF_INET6
if (addr->ss_family == AF_INET6) {
len = sizeof(struct sockaddr_in6);
}
#endif
#endif
ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1,
serv, sizeof(serv)-1, flags);
if (ret != 0) {
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 (ret_host) {
*ret_host = m_strdup(host);
}
if (ret_port) {
*ret_port = m_strdup(serv);
}
}
#ifdef DEBUG_TRACE
void printhex(const char * label, const unsigned char * buf, int len) {
@@ -827,12 +504,12 @@ out:
/* make sure that the socket closes */
void m_close(int fd) {
int val;
if (fd == -1) {
return;
}
int val;
do {
val = close(fd);
} while (val < 0 && errno == EINTR);
@@ -882,21 +559,6 @@ void * m_realloc(void* ptr, size_t size) {
return ret;
}
/* Clear the data, based on the method in David Wheeler's
* "Secure Programming for Linux and Unix HOWTO" */
/* Beware of calling this from within dbutil.c - things might get
* optimised away */
void m_burn(void *data, unsigned int len) {
volatile char *p = data;
if (data == NULL)
return;
while (len--) {
*p++ = 0x0;
}
}
void setnonblocking(int fd) {
TRACE(("setnonblocking: %d", fd))
@@ -936,6 +598,24 @@ int m_str_to_uint(const char* str, unsigned int *val) {
}
}
/* Returns malloced path. inpath beginning with '/' is returned as-is,
otherwise home directory is prepended */
char * expand_homedir_path(const char *inpath) {
struct passwd *pw = NULL;
if (inpath[0] != '/') {
pw = getpwuid(getuid());
if (pw && pw->pw_dir) {
int len = strlen(inpath) + strlen(pw->pw_dir) + 2;
char *buf = m_malloc(len);
snprintf(buf, len, "%s/%s", pw->pw_dir, inpath);
return buf;
}
}
/* Fallback */
return m_strdup(inpath);
}
int constant_time_memcmp(const void* a, const void *b, size_t n)
{
const char *xa = a, *xb = b;
@@ -1001,3 +681,4 @@ time_t monotonic_now() {
return time(NULL);
}

View File

@@ -22,25 +22,17 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _DBUTIL_H_
#ifndef DROPBEAR_DBUTIL_H_
#define _DBUTIL_H_
#define DROPBEAR_DBUTIL_H_
#include "includes.h"
#include "buffer.h"
#include "queue.h"
#include "dbhelpers.h"
#ifndef DISABLE_SYSLOG
void startsyslog();
#endif
#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
void startsyslog(const char *ident);
#endif
extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
@@ -58,32 +50,18 @@ 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);
void printmpint(const char *label, mp_int *mp);
void debug_start_net(void);
extern int debug_trace;
#endif
enum dropbear_prio {
DROPBEAR_PRIO_DEFAULT = 10,
DROPBEAR_PRIO_LOWDELAY = 11,
DROPBEAR_PRIO_BULK = 12,
};
char * stripcontrol(const char * text);
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);
void set_sock_nodelay(int sock);
void set_sock_priority(int sock, enum dropbear_prio prio);
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);
int buf_readfile(buffer* buf, const char* filename);
int buf_getline(buffer * line, FILE * authfile);
@@ -91,10 +69,9 @@ 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) free(X); (X) = NULL;
void m_burn(void* data, unsigned int len);
#define m_free(X) do {free(X); (X) = NULL;} while (0)
void setnonblocking(int fd);
void disallow_core();
void disallow_core(void);
int m_str_to_uint(const char* str, unsigned int *val);
/* Used to force mp_ints to be initialised */
@@ -108,7 +85,8 @@ int constant_time_memcmp(const void* a, const void *b, size_t n);
/* Returns a time in seconds that doesn't go backwards - does not correspond to
a real-world clock */
time_t monotonic_now();
time_t monotonic_now(void);
char * expand_homedir_path(const char *inpath);
#endif /* _DBUTIL_H_ */
#endif /* DROPBEAR_DBUTIL_H_ */

42
debian/changelog vendored
View File

@@ -1,3 +1,45 @@
dropbear (2016.73-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Fri, 18 Mar 2016 22:52:58 +0800
dropbear (2016.72-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 10 Mar 2016 22:52:58 +0800
dropbear (2015.70-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 26 Nov 2015 22:52:58 +0800
dropbear (2015.69-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 25 Nov 2015 22:52:58 +0800
dropbear (2015.68-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Sat, 8 Aug 2015 22:52:58 +0800
dropbear (2015.67-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 28 Jan 2015 22:53:59 +0800
dropbear (2014.66-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 23 Oct 2014 22:54:00 +0800
dropbear (2014.65-0.1) unstable; urgency=low
* New upstream release.

View File

@@ -5,6 +5,7 @@
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Dropbear SSH server
### END INIT INFO
#
# Do not configure this file. Edit /etc/default/dropbear instead!

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _DEBUG_H_
#define _DEBUG_H_
#ifndef DROPBEAR_DEBUG_H_
#define DROPBEAR_DEBUG_H_
#include "includes.h"
@@ -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

94
dh_groups.c Normal file
View File

@@ -0,0 +1,94 @@
#include "options.h"
#include "dh_groups.h"
#if DROPBEAR_DH_GROUP1
/* diffie-hellman-group1-sha1 value for p */
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,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
#endif /* DROPBEAR_DH_GROUP1 */
#if DROPBEAR_DH_GROUP14
/* diffie-hellman-group14-sha1 value for p */
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};
#endif /* DROPBEAR_DH_GROUP14 */
#if DROPBEAR_DH_GROUP16
/* diffie-hellman-group16-256 value for p */
const unsigned char dh_p_16[DH_P_16_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, 0xAA, 0xC4,
0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB,
0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A,
0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1,
0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94,
0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E,
0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1,
0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46,
0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC,
0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A,
0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA,
0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, 0x1A, 0x94, 0x68,
0x34, 0xB6, 0x15, 0x0B, 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F,
0xBE, 0xCA, 0xA6, 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2,
0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7,
0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76,
0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, 0x93,
0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6,
0xC0, 0x8F, 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
#endif /* DROPBEAR_DH_GROUP16 */
/* Same for all groups */
const int DH_G_VAL = 2;

24
dh_groups.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef DROPBEAR_DH_GROUPS_H
#define DROPBEAR_DH_GROUPS_H
#include "options.h"
#if DROPBEAR_DH_GROUP1
#define DH_P_1_LEN 128
extern const unsigned char dh_p_1[DH_P_1_LEN];
#endif
#if DROPBEAR_DH_GROUP14
#define DH_P_14_LEN 256
extern const unsigned char dh_p_14[DH_P_14_LEN];
#endif
#if DROPBEAR_DH_GROUP16
#define DH_P_16_LEN 512
extern const unsigned char dh_p_16[DH_P_16_LEN];
#endif
extern const int DH_G_VAL;
#endif

View File

@@ -3,11 +3,10 @@
dropbear \- lightweight SSH server
.SH SYNOPSIS
.B dropbear
[\-RFEmwsgjki] [\-b
[\fIflag arguments\fR] [\-b
.I banner\fR]
[\-r
.I hostkeyfile\fR] [\-p
.IR [address:]port ]
.I hostkeyfile\fR] [\-p [\fIaddress\fR:]\fIport\fR]
.SH DESCRIPTION
.B dropbear
is a small SSH server
@@ -54,7 +53,7 @@ Disable local port forwarding.
.B \-k
Disable remote port forwarding.
.TP
.B \-p \fI[address:]port
.B \-p\fR [\fIaddress\fR:]\fIport
Listen on specified
.I address
and TCP
@@ -100,7 +99,8 @@ Print the version
.TP
Authorized Keys
~/.ssh/authorized_keys can be set up to allow remote login with a RSA or DSS
~/.ssh/authorized_keys can be set up to allow remote login with a RSA,
ECDSA, or DSS
key. Each line is of the form
.TP
[restrictions] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIgAsp... [comment]
@@ -127,7 +127,7 @@ Disable PTY allocation. Note that a user can still obtain most of the
same functionality with other means even if no-pty is set.
.TP
.B command="\fIforced_command\fR"
.B command=\fR"\fIforced_command\fR"
Disregard the command provided by the user and always run \fIforced_command\fR.
The authorized_keys file and its containing ~/.ssh directory must only be
@@ -139,7 +139,7 @@ Host Key Files
Host key files are read at startup from a standard location, by default
/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key, and
/etc/dropbear/dropbear-ecdsa_host_key
/etc/dropbear/dropbear_ecdsa_host_key
or specified on the commandline with -r. These are of the form generated
by dropbearkey. The -R option can be used to automatically generate keys
in the default location - keys will be generated after startup when the first

View File

@@ -21,27 +21,27 @@ from a private key by using
.P
Encrypted private keys are not supported, use ssh-keygen(1) to decrypt them
first.
.SH OPTIONS
.SH ARGUMENTS
.TP
.B input type
.I input_type
Either
.I dropbear
or
.I openssh
.TP
.B output type
.I output_type
Either
.I dropbear
or
.I openssh
.TP
.B input file
.I input_file
An existing Dropbear or OpenSSH private key file
.TP
.B output file
The path to write the converted private key file
.I output_file
The path to write the converted private key file. For client authentication ~/.ssh/id_dropbear is loaded by default
.SH EXAMPLE
# dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/dropbear_priv
# dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_dropbear
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.SH SEE ALSO

View File

@@ -9,13 +9,11 @@ dropbearkey \- create private keys for the use with dropbear(8) or dbclient(1)
.I file
[\-s
.IR bits ]
[\-y]
.SH DESCRIPTION
.B dropbearkey
generates a
.I RSA
.I DSS,
or
.I ECDSA
\fIRSA\fR, \fIDSS\fR, or \fIECDSA\fR
format SSH private key, and saves it to a file for the use with the
Dropbear client or server.
Note that
@@ -33,18 +31,25 @@ or
.TP
.B \-f \fIfile
Write the secret key to the file
.IR file .
\fIfile\fR. For client authentication ~/.ssh/id_dropbear is loaded by default
.TP
.B \-s \fIbits
Set the key size to
.I bits
bits, should be multiple of 8 (optional).
.TP
.B \-y
Just print the publickey and fingerprint for the private key in \fIfile\fR.
.SH NOTES
The program dropbearconvert(1) can be used to convert between Dropbear and OpenSSH key formats.
.P
Dropbear does not support encrypted keys.
.SH EXAMPLE
generate a host-key:
# dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
extract a public key suitable for authorized_keys from private key:
# dropbearkey -y -f id_rsa | grep "^ssh-rsa " >> authorized_keys
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.br

View File

@@ -76,7 +76,8 @@ static void printhelp(char * progname) {
#ifdef DROPBEAR_ECDSA
" ecdsa\n"
#endif
"-f filename Use filename for the secret key\n"
"-f filename Use filename for the secret key.\n"
" ~/.ssh/id_dropbear is recommended for client keys.\n"
"-s bits Key size in bits, should be a multiple of 8 (optional)\n"
#ifdef DROPBEAR_DSS
" DSS has a fixed size of 1024 bits\n"
@@ -104,25 +105,25 @@ static void printhelp(char * progname) {
/* fails fatally */
static void check_signkey_bits(enum signkey_type type, int bits)
{
switch (type) {
switch (type) {
#ifdef DROPBEAR_RSA
case DROPBEAR_SIGNKEY_RSA:
if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
dropbear_exit("Bits must satisfy 512 <= bits <= 4096, and be a"
" multiple of 8\n");
}
break;
case DROPBEAR_SIGNKEY_RSA:
if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
dropbear_exit("Bits must satisfy 512 <= bits <= 4096, and be a"
" multiple of 8\n");
}
break;
#endif
#ifdef DROPEAR_DSS
case DROPBEAR_SIGNKEY_DSS:
if (bits != 1024) {
dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
exit(EXIT_FAILURE);
}
case DROPBEAR_SIGNKEY_DSS:
if (bits != 1024) {
dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
exit(EXIT_FAILURE);
}
#endif
default:
(void)0; /* quiet, compiler. ecdsa handles checks itself */
}
default:
(void)0; /* quiet, compiler. ecdsa handles checks itself */
}
}
#if defined(DBMULTI_dropbearkey) || !defined(DROPBEAR_MULTI)
@@ -237,13 +238,13 @@ int main(int argc, char ** argv) {
}
check_signkey_bits(keytype, bits);;
}
}
fprintf(stderr, "Generating key, this may take a while...\n");
if (signkey_generate(keytype, bits, filename) == DROPBEAR_FAILURE)
{
dropbear_exit("Failed to generate key.\n");
}
if (signkey_generate(keytype, bits, filename) == DROPBEAR_FAILURE)
{
dropbear_exit("Failed to generate key.\n");
}
printpubfile(filename);

6
dss.c
View File

@@ -165,7 +165,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
DEF_MP_INT(val3);
DEF_MP_INT(val4);
char * string = NULL;
int stringlen;
unsigned int stringlen;
TRACE(("enter buf_dss_verify"))
dropbear_assert(key != NULL);
@@ -186,7 +186,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
/* create the signature - s' and r' are the received signatures in buf */
/* w = (s')-1 mod q */
/* let val1 = s' */
bytes_to_mp(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
bytes_to_mp(&val1, (const unsigned char*) &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
if (mp_cmp(&val1, key->q) != MP_LT) {
TRACE(("verify failed, s' >= q"))
@@ -208,7 +208,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
/* u2 = ((r')w) mod q */
/* let val1 = r' */
bytes_to_mp(&val1, &string[0], SHA1_HASH_SIZE);
bytes_to_mp(&val1, (const unsigned char*) &string[0], SHA1_HASH_SIZE);
if (mp_cmp(&val1, key->q) != MP_LT) {
TRACE(("verify failed, r' >= q"))
goto out;

6
dss.h
View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _DSS_H_
#define _DSS_H_
#ifndef DROPBEAR_DSS_H_
#define DROPBEAR_DSS_H_
#include "includes.h"
#include "buffer.h"
@@ -53,4 +53,4 @@ void dss_key_free(dropbear_dss_key *key);
#endif /* DROPBEAR_DSS */
#endif /* _DSS_H_ */
#endif /* DROPBEAR_DSS_H_ */

5
ecc.c
View File

@@ -86,11 +86,6 @@ static int ecc_is_point(ecc_key *key)
{
mp_int *prime, *b, *t1, *t2;
int err;
prime = m_malloc(sizeof(mp_int));
b = m_malloc(sizeof(mp_int));
t1 = m_malloc(sizeof(mp_int));
t2 = m_malloc(sizeof(mp_int));
m_mp_alloc_init_multi(&prime, &b, &t1, &t2, NULL);

10
ecc.h
View File

@@ -1,5 +1,5 @@
#ifndef _DROPBEAR_ECC_H
#define _DROPBEAR_ECC_H
#ifndef DROPBEAR_DROPBEAR_ECC_H
#define DROPBEAR_DROPBEAR_ECC_H
#include "includes.h"
#include "options.h"
@@ -12,7 +12,7 @@ struct dropbear_ecc_curve {
int ltc_size; /* to match the byte sizes in ltc_ecc_sets[] */
const ltc_ecc_set_type *dp; /* curve domain parameters */
const struct ltc_hash_descriptor *hash_desc;
const unsigned char *name;
const char *name;
};
extern struct dropbear_ecc_curve ecc_curve_nistp256;
@@ -20,7 +20,7 @@ extern struct dropbear_ecc_curve ecc_curve_nistp384;
extern struct dropbear_ecc_curve ecc_curve_nistp521;
extern struct dropbear_ecc_curve *dropbear_ecc_curves[];
void dropbear_ecc_fill_dp();
void dropbear_ecc_fill_dp(void);
struct dropbear_ecc_curve* curve_for_dp(const ltc_ecc_set_type *dp);
/* "pubkey" refers to a point, but LTC uses ecc_key structure for both public
@@ -33,4 +33,4 @@ mp_int * dropbear_ecc_shared_secret(ecc_key *pub_key, ecc_key *priv_key);
#endif
#endif /* _DROPBEAR_ECC_H */
#endif /* DROPBEAR_DROPBEAR_ECC_H */

19
ecdsa.c
View File

@@ -83,9 +83,9 @@ ecc_key *buf_get_ecdsa_pub_key(buffer* buf) {
ecc_key *new_key = NULL;
/* string "ecdsa-sha2-[identifier]" */
key_ident = buf_getstring(buf, &key_ident_len);
key_ident = (unsigned char*)buf_getstring(buf, &key_ident_len);
/* string "[identifier]" */
identifier = buf_getstring(buf, &identifier_len);
identifier = (unsigned char*)buf_getstring(buf, &identifier_len);
if (key_ident_len != identifier_len + strlen("ecdsa-sha2-")) {
TRACE(("Bad identifier lengths"))
@@ -131,6 +131,7 @@ ecc_key *buf_get_ecdsa_priv_key(buffer *buf) {
if (buf_getmpint(buf, new_key->k) != DROPBEAR_SUCCESS) {
ecc_free(new_key);
m_free(new_key);
return NULL;
}
@@ -139,10 +140,10 @@ ecc_key *buf_get_ecdsa_priv_key(buffer *buf) {
void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key) {
struct dropbear_ecc_curve *curve = NULL;
unsigned char key_ident[30];
char key_ident[30];
curve = curve_for_dp(key->dp);
snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
snprintf(key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
buf_putstring(buf, key_ident, strlen(key_ident));
buf_putstring(buf, curve->name, strlen(curve->name));
buf_put_ecc_raw_pubkey_string(buf, key);
@@ -160,7 +161,7 @@ void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf) {
hash_state hs;
unsigned char hash[64];
void *e = NULL, *p = NULL, *s = NULL, *r;
unsigned char key_ident[30];
char key_ident[30];
buffer *sigbuf = NULL;
TRACE(("buf_put_ecdsa_sign"))
@@ -221,7 +222,7 @@ void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf) {
}
}
snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
snprintf(key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
buf_putstring(buf, key_ident, strlen(key_ident));
/* enough for nistp521 */
sigbuf = buf_new(200);
@@ -384,12 +385,12 @@ int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf) {
goto out;
}
/* reduce */
/* reduce */
if (ltc_mp.ecc_map(mG, m, mp) != CRYPT_OK) {
goto out;
}
} else {
/* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
/* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
if (ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m) != CRYPT_OK) {
goto out;
}
@@ -408,7 +409,7 @@ int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf) {
out:
ltc_ecc_del_point(mG);
ltc_ecc_del_point(mQ);
mp_clear_multi(r, s, v, w, u1, u2, p, e, m, NULL);
ltc_deinit_multi(r, s, v, w, u1, u2, p, e, m, NULL);
if (mp != NULL) {
ltc_mp.montgomery_deinit(mp);
}

View File

@@ -1,5 +1,5 @@
#ifndef _ECDSA_H_
#define _ECDSA_H_
#ifndef DROPBEAR_ECDSA_H_
#define DROPBEAR_ECDSA_H_
#include "includes.h"
#include "buffer.h"
@@ -32,4 +32,4 @@ int signkey_is_ecdsa(enum signkey_type type);
#endif
#endif /* _ECDSA_H_ */
#endif /* DROPBEAR_ECDSA_H_ */

View File

@@ -39,8 +39,8 @@
* that ai_family is AF_INET. Don't use it for another purpose.
*/
#ifndef _FAKE_RFC2553_H
#define _FAKE_RFC2553_H
#ifndef DROPBEAR_FAKE_RFC2553_H
#define DROPBEAR_FAKE_RFC2553_H
#include "includes.h"
#include <sys/types.h>

View File

@@ -67,7 +67,7 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
static void getq(dropbear_dss_key *key) {
char buf[QSIZE];
unsigned char buf[QSIZE];
/* 160 bit prime */
genrandom(buf, QSIZE);

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _GENDSS_H_
#define _GENDSS_H_
#ifndef DROPBEAR_GENDSS_H_
#define DROPBEAR_GENDSS_H_
#include "dss.h"
@@ -33,4 +33,4 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size);
#endif /* DROPBEAR_DSS */
#endif /* _GENDSS_H_ */
#endif /* DROPBEAR_GENDSS_H_ */

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _GENRSA_H_
#define _GENRSA_H_
#ifndef DROPBEAR_GENRSA_H_
#define DROPBEAR_GENRSA_H_
#include "rsa.h"
@@ -33,4 +33,4 @@ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size);
#endif /* DROPBEAR_RSA */
#endif /* _GENRSA_H_ */
#endif /* DROPBEAR_GENRSA_H_ */

View File

@@ -41,6 +41,9 @@ static int buf_writefile(buffer * buf, const char * filename) {
out:
if (fd >= 0) {
if (fsync(fd) != 0) {
dropbear_log(LOG_ERR, "fsync of %s failed: %s", filename, strerror(errno));
}
m_close(fd);
}
return ret;
@@ -49,28 +52,28 @@ out:
/* returns 0 on failure */
static int get_default_bits(enum signkey_type keytype)
{
switch (keytype) {
switch (keytype) {
#ifdef DROPBEAR_RSA
case DROPBEAR_SIGNKEY_RSA:
return RSA_DEFAULT_SIZE;
case DROPBEAR_SIGNKEY_RSA:
return RSA_DEFAULT_SIZE;
#endif
#ifdef DROPBEAR_DSS
case DROPBEAR_SIGNKEY_DSS:
return DSS_DEFAULT_SIZE;
case DROPBEAR_SIGNKEY_DSS:
return DSS_DEFAULT_SIZE;
#endif
#ifdef DROPBEAR_ECDSA
case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
return ECDSA_DEFAULT_SIZE;
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
return 521;
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
return 384;
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
return 256;
case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
return ECDSA_DEFAULT_SIZE;
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
return 521;
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
return 384;
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
return 256;
#endif
default:
return 0;
}
default:
return 0;
}
}
int signkey_generate(enum signkey_type keytype, int bits, const char* filename)

View File

@@ -1,5 +1,5 @@
#ifndef _GENSIGNKEY_H
#define _GENSIGNKEY_H
#ifndef DROPBEAR_GENSIGNKEY_H
#define DROPBEAR_GENSIGNKEY_H
#include "signkey.h"

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _INCLUDES_H_
#define _INCLUDES_H_
#ifndef DROPBEAR_INCLUDES_H_
#define DROPBEAR_INCLUDES_H_
#include "config.h"
@@ -177,4 +177,4 @@ typedef u_int32_t uint32_t;
# define UNUSED(x) x
#endif
#endif /* _INCLUDES_H_ */
#endif /* DROPBEAR_INCLUDES_H_ */

37
kex.h
View File

@@ -22,47 +22,47 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _KEX_H_
#define _KEX_H_
#ifndef DROPBEAR_KEX_H_
#define DROPBEAR_KEX_H_
#include "includes.h"
#include "algo.h"
#include "signkey.h"
void send_msg_kexinit();
void recv_msg_kexinit();
void send_msg_newkeys();
void recv_msg_newkeys();
void kexfirstinitialise();
void send_msg_kexinit(void);
void recv_msg_kexinit(void);
void send_msg_newkeys(void);
void recv_msg_newkeys(void);
void kexfirstinitialise(void);
struct kex_dh_param *gen_kexdh_param();
struct kex_dh_param *gen_kexdh_param(void);
void free_kexdh_param(struct kex_dh_param *param);
void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
sign_key *hostkey);
#ifdef DROPBEAR_ECDH
struct kex_ecdh_param *gen_kexecdh_param();
struct kex_ecdh_param *gen_kexecdh_param(void);
void free_kexecdh_param(struct kex_ecdh_param *param);
void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
sign_key *hostkey);
#endif
#ifdef DROPBEAR_CURVE25519
struct kex_curve25519_param *gen_kexcurve25519_param();
struct kex_curve25519_param *gen_kexcurve25519_param(void);
void free_kexcurve25519_param(struct kex_curve25519_param *param);
void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *pub_them,
sign_key *hostkey);
#endif
#ifndef DISABLE_ZLIB
int is_compress_trans();
int is_compress_recv();
int is_compress_trans(void);
int is_compress_recv(void);
#endif
void recv_msg_kexdh_init(); /* server */
void recv_msg_kexdh_init(void); /* server */
void send_msg_kexdh_init(); /* client */
void recv_msg_kexdh_reply(); /* client */
void send_msg_kexdh_init(void); /* client */
void recv_msg_kexdh_reply(void); /* client */
struct KEXState {
@@ -83,11 +83,6 @@ struct KEXState {
};
#define DH_P_1_LEN 128
extern const unsigned char dh_p_1[DH_P_1_LEN];
#define DH_P_14_LEN 256
extern const unsigned char dh_p_14[DH_P_14_LEN];
struct kex_dh_param {
mp_int pub; /* e */
mp_int priv; /* x */
@@ -113,4 +108,4 @@ int curve25519_donna(unsigned char *out, const unsigned char *secret, const unsi
#define MAX_KEXHASHBUF 2000
#endif /* _KEX_H_ */
#endif /* DROPBEAR_KEX_H_ */

View File

@@ -193,14 +193,14 @@ out:
static void base64_encode_fp(FILE * fp, unsigned char *data,
int datalen, int cpl)
{
char out[100];
int n;
unsigned char out[100];
int n;
unsigned long outlen;
int rawcpl;
rawcpl = cpl * 3 / 4;
dropbear_assert((unsigned int)cpl < sizeof(out));
while (datalen > 0) {
while (datalen > 0) {
n = (datalen < rawcpl ? datalen : rawcpl);
outlen = sizeof(out);
base64_encode(data, n, out, &outlen);
@@ -208,7 +208,7 @@ static void base64_encode_fp(FILE * fp, unsigned char *data,
datalen -= n;
fwrite(out, 1, outlen, fp);
fputc('\n', fp);
}
}
}
/*
* Read an ASN.1/BER identifier and length pair.
@@ -445,7 +445,7 @@ static struct openssh_key *load_openssh_key(const char *filename)
ret->keyblob_size);
}
outlen = ret->keyblob_size - ret->keyblob_len;
if (base64_decode(buffer, len,
if (base64_decode((const unsigned char *)buffer, len,
ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){
errmsg = "Error decoding base64";
goto error;
@@ -464,17 +464,16 @@ static struct openssh_key *load_openssh_key(const char *filename)
goto error;
}
memset(buffer, 0, sizeof(buffer));
m_burn(buffer, sizeof(buffer));
return ret;
error:
memset(buffer, 0, sizeof(buffer));
m_burn(buffer, sizeof(buffer));
if (ret) {
if (ret->keyblob) {
memset(ret->keyblob, 0, ret->keyblob_size);
m_burn(ret->keyblob, ret->keyblob_size);
m_free(ret->keyblob);
}
memset(&ret, 0, sizeof(ret));
m_free(ret);
}
if (fp) {
@@ -494,9 +493,8 @@ static int openssh_encrypted(const char *filename)
if (!key)
return 0;
ret = key->encrypted;
memset(key->keyblob, 0, key->keyblob_size);
m_burn(key->keyblob, key->keyblob_size);
m_free(key->keyblob);
memset(&key, 0, sizeof(key));
m_free(key);
return ret;
}
@@ -509,7 +507,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
int i, num_integers = 0;
sign_key *retval = NULL;
char *errmsg;
char *modptr = NULL;
unsigned char *modptr = NULL;
int modlen = -9999;
enum signkey_type type;
@@ -627,7 +625,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
if (i == 0) {
/* First integer is a version indicator */
int expected;
int expected = -1;
switch (key->type) {
case OSSH_RSA:
case OSSH_DSA:
@@ -648,12 +646,12 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
*/
if (i == 1) {
/* Save the details for after we deal with number 2. */
modptr = (char *)p;
modptr = p;
modlen = len;
} else if (i >= 2 && i <= 5) {
buf_putstring(blobbuf, p, len);
buf_putstring(blobbuf, (const char*)p, len);
if (i == 2) {
buf_putstring(blobbuf, modptr, modlen);
buf_putstring(blobbuf, (const char*)modptr, modlen);
}
}
} else if (key->type == OSSH_DSA) {
@@ -661,7 +659,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
* OpenSSH key order is p, q, g, y, x,
* we want the same.
*/
buf_putstring(blobbuf, p, len);
buf_putstring(blobbuf, (const char*)p, len);
}
/* Skip past the number. */
@@ -810,7 +808,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
}
m_burn(key->keyblob, key->keyblob_size);
m_free(key->keyblob);
m_burn(key, sizeof(key));
m_burn(key, sizeof(*key));
m_free(key);
if (errmsg) {
fprintf(stderr, "Error: %s\n", errmsg);
@@ -826,7 +824,7 @@ static int openssh_write(const char *filename, sign_key *key,
unsigned char *outblob = NULL;
int outlen = -9999;
struct mpint_pos numbers[9];
int nnumbers = -1, pos, len, seqlen, i;
int nnumbers = -1, pos = 0, len = 0, seqlen, i;
char *header = NULL, *footer = NULL;
char zero[1];
int ret = 0;
@@ -1045,7 +1043,8 @@ static int openssh_write(const char *filename, sign_key *key,
int curve_oid_len = 0;
const void* curve_oid = NULL;
unsigned long pubkey_size = 2*curve_size+1;
unsigned int k_size;
int k_size;
int err = 0;
/* version. less than 10 bytes */
buf_incrwritepos(seq_buf,
@@ -1057,7 +1056,7 @@ static int openssh_write(const char *filename, sign_key *key,
dropbear_assert(k_size <= curve_size);
buf_incrwritepos(seq_buf,
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 4, k_size, 0));
mp_to_unsigned_bin((*eck)->k, buf_getwriteptr(seq_buf, k_size));
mp_to_unsigned_bin((*eck)->k, buf_getwriteptr(seq_buf, k_size));
buf_incrwritepos(seq_buf, k_size);
/* SECGCurveNames */
@@ -1091,7 +1090,7 @@ static int openssh_write(const char *filename, sign_key *key,
buf_incrwritepos(seq_buf,
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 3, 1+pubkey_size, 0));
buf_putbyte(seq_buf, 0);
int err = ecc_ansi_x963_export(*eck, buf_getwriteptr(seq_buf, pubkey_size), &pubkey_size);
err = ecc_ansi_x963_export(*eck, buf_getwriteptr(seq_buf, pubkey_size), &pubkey_size);
if (err != CRYPT_OK) {
dropbear_exit("ECC error");
}

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _KEYIMPORT_H_
#define _KEYIMPORT_H_
#ifndef DROPBEAR_KEYIMPORT_H_
#define DROPBEAR_KEYIMPORT_H_
#include "includes.h"
#include "signkey.h"
@@ -39,4 +39,4 @@ int import_write(const char *filename, sign_key *key, char *passphrase,
sign_key *import_read(const char *filename, char *passphrase, int filetype);
int import_encrypted(const char* filename, int filetype);
#endif /* _KEYIMPORT_H_ */
#endif /* DROPBEAR_KEYIMPORT_H_ */

View File

@@ -122,9 +122,10 @@ static ulong32 setup_mix2(ulong32 temp)
*/
int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
{
int i, j;
int i;
ulong32 temp, *rk;
#ifndef ENCRYPT_ONLY
int j;
ulong32 *rrk;
#endif
LTC_ARGCHK(key != NULL);
@@ -148,7 +149,9 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
LOAD32H(rk[2], key + 8);
LOAD32H(rk[3], key + 12);
if (keylen == 16) {
#ifndef ENCRYPT_ONLY
j = 44;
#endif
for (;;) {
temp = rk[3];
rk[4] = rk[0] ^ setup_mix(temp) ^ rcon[i];
@@ -161,7 +164,9 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
rk += 4;
}
} else if (keylen == 24) {
#ifndef ENCRYPT_ONLY
j = 52;
#endif
LOAD32H(rk[4], key + 16);
LOAD32H(rk[5], key + 20);
for (;;) {
@@ -182,7 +187,9 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
rk += 6;
}
} else if (keylen == 32) {
#ifndef ENCRYPT_ONLY
j = 60;
#endif
LOAD32H(rk[4], key + 16);
LOAD32H(rk[5], key + 20);
LOAD32H(rk[6], key + 24);
@@ -728,6 +735,7 @@ int ECB_TEST(void)
*/
void ECB_DONE(symmetric_key *skey)
{
(void)skey;
}

View File

@@ -1871,6 +1871,7 @@ void des_done(symmetric_key *skey)
*/
void des3_done(symmetric_key *skey)
{
(void)skey;
}

View File

@@ -684,6 +684,7 @@ int twofish_test(void)
*/
void twofish_done(symmetric_key *skey)
{
(void)skey;
}
/**

View File

@@ -25,6 +25,7 @@
int hash_file(int hash, const char *fname, unsigned char *out, unsigned long *outlen)
{
#ifdef LTC_NO_FILE
(void)hash; (void)fname; (void)out; (void)outlen;
return CRYPT_NOP;
#else
FILE *in;

View File

@@ -26,6 +26,7 @@
int hash_filehandle(int hash, FILE *in, unsigned char *out, unsigned long *outlen)
{
#ifdef LTC_NO_FILE
(void)hash; (void)in; (void)out; (void)outlen;
return CRYPT_NOP;
#else
hash_state md;

View File

@@ -4,8 +4,16 @@
#include <signal.h>
/* portability macros for compiler-specific code attributes */
#ifdef __GNUC__
#define ATTRIB_NORETURN __attribute__((noreturn))
#else
#define ATTRIB_NORETURN
#endif
/* this is the default LibTomCrypt macro */
void crypt_argchk(char *v, char *s, int d);
void crypt_argchk(char *v, char *s, int d) ATTRIB_NORETURN;
#define LTC_ARGCHK(x) if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); }
#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)

View File

@@ -1,7 +1,7 @@
#ifndef TOMCRYPT_CUSTOM_H_
#define TOMCRYPT_CUSTOM_H_
/* this will sort out which stuff based on the user-config in options.h */
/* compile options depend on Dropbear options.h */
#include "options.h"
/* macros for various libc functions you can change for embedded targets */

View File

@@ -28,7 +28,7 @@
*/
int hmac_done(hmac_state *hmac, unsigned char *out, unsigned long *outlen)
{
unsigned char *buf, *isha;
unsigned char buf[MAXBLOCKSIZE], isha[MAXBLOCKSIZE];
unsigned long hashsize, i;
int hash, err;
@@ -44,19 +44,6 @@ int hmac_done(hmac_state *hmac, unsigned char *out, unsigned long *outlen)
/* get the hash message digest size */
hashsize = hash_descriptor[hash].hashsize;
/* allocate buffers */
buf = XMALLOC(HMAC_BLOCKSIZE);
isha = XMALLOC(hashsize);
if (buf == NULL || isha == NULL) {
if (buf != NULL) {
XFREE(buf);
}
if (isha != NULL) {
XFREE(isha);
}
return CRYPT_MEM;
}
/* Get the hash of the first HMAC vector plus the data */
if ((err = hash_descriptor[hash].done(&hmac->md, isha)) != CRYPT_OK) {
goto LBL_ERR;
@@ -96,9 +83,6 @@ LBL_ERR:
zeromem(hmac, sizeof(*hmac));
#endif
XFREE(isha);
XFREE(buf);
return err;
}

View File

@@ -32,6 +32,7 @@ int hmac_file(int hash, const char *fname,
unsigned char *out, unsigned long *outlen)
{
#ifdef LTC_NO_FILE
(void)hash; (void)fname; (void)key; (void)keylen; (void)out; (void)outlen;
return CRYPT_NOP;
#else
hmac_state hmac;

View File

@@ -29,7 +29,7 @@
*/
int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned long keylen)
{
unsigned char *buf;
unsigned char buf[MAXBLOCKSIZE];
unsigned long hashsize;
unsigned long i, z;
int err;
@@ -49,16 +49,9 @@ int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned lon
return CRYPT_INVALID_KEYSIZE;
}
/* allocate ram for buf */
buf = XMALLOC(HMAC_BLOCKSIZE);
if (buf == NULL) {
return CRYPT_MEM;
}
/* allocate memory for key */
hmac->key = XMALLOC(HMAC_BLOCKSIZE);
if (hmac->key == NULL) {
XFREE(buf);
return CRYPT_MEM;
}
@@ -101,7 +94,6 @@ done:
zeromem(buf, HMAC_BLOCKSIZE);
#endif
XFREE(buf);
return err;
}

View File

@@ -21,7 +21,7 @@ void crypt_argchk(char *v, char *s, int d)
{
fprintf(stderr, "LTC_ARGCHK '%s' failure on line %d of file %s\n",
v, d, s);
(void)raise(SIGABRT);
abort();
}
#endif

View File

@@ -9,6 +9,7 @@
* Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
*/
#include "tomcrypt.h"
#include "dbhelpers.h"
/**
@file zeromem.c
@@ -22,11 +23,7 @@
*/
void zeromem(void *out, size_t outlen)
{
unsigned char *mem = out;
LTC_ARGCHKVD(out != NULL);
while (outlen-- > 0) {
*mem++ = 0;
}
m_burn(out, outlen);
}
/* $Source: /cvs/libtom/libtomcrypt/src/misc/zeromem.c,v $ */

View File

@@ -40,7 +40,7 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map)
int i, j, err;
void *mu, *mp;
unsigned long buf;
int first, bitbuf, bitcpy, bitcnt, mode, digidx;
int bitcnt, mode, digidx;
LTC_ARGCHK(k != NULL);
LTC_ARGCHK(G != NULL);
@@ -98,8 +98,6 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map)
bitcnt = 1;
buf = 0;
digidx = mp_get_digit_count(k) - 1;
bitcpy = bitbuf = 0;
first = 1;
/* perform ops */
for (;;) {

View File

@@ -8,10 +8,8 @@ VERSION=0.40
VPATH=@srcdir@
srcdir=@srcdir@
# Dropbear takes flags from the toplevel makefile
CFLAGS += -I$(srcdir)
#CFLAGS += -I./ -Wall -W -Wshadow -Wsign-compare
# So that libtommath can include Dropbear headers for options and m_burn()
CFLAGS += -I$(srcdir)/../libtomcrypt/src/headers/ -I$(srcdir)/../
ifndef IGNORE_SPEED

View File

@@ -1,4 +1,5 @@
#include <tommath.h>
#include "dbhelpers.h"
#ifdef BN_MP_CLEAR_C
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
@@ -19,17 +20,10 @@
void
mp_clear (mp_int * a)
{
volatile mp_digit *p;
int len;
/* only do anything if a hasn't been freed previously */
if (a->dp != NULL) {
/* first zero the digits */
len = a->alloc;
p = a->dp;
while (len--) {
*p++ = 0;
}
m_burn(a->dp, a->alloc * sizeof(*a->dp));
/* free ram */
XFREE(a->dp);

16
list.h
View File

@@ -1,28 +1,28 @@
#ifndef _DROPBEAR_LIST_H
#define _DROPBEAR_LIST_H
#ifndef DROPBEAR_DROPBEAR_LIST_H
#define DROPBEAR_DROPBEAR_LIST_H
struct _m_list;
struct _m_list_elem {
void *item;
void *item;
struct _m_list_elem *next;
struct _m_list_elem *prev;
struct _m_list *list;
struct _m_list *list;
};
typedef struct _m_list_elem m_list_elem;
struct _m_list {
m_list_elem *first;
m_list_elem *last;
m_list_elem *first;
m_list_elem *last;
};
typedef struct _m_list m_list;
m_list * list_new();
m_list * list_new(void);
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 */
#endif /* DROPBEAR_DROPBEAR_LIST_H */

View File

@@ -161,5 +161,14 @@ void remove_listener(struct Listener* listener) {
}
ses.listeners[listener->index] = NULL;
m_free(listener);
}
void remove_all_listeners(void) {
unsigned int i;
for (i = 0; i < ses.listensize; i++) {
if (ses.listeners[i]) {
remove_listener(ses.listeners[i]);
}
}
m_free(ses.listeners);
}

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _LISTENER_H
#define _LISTENER_H
#ifndef DROPBEAR_LISTENER_H
#define DROPBEAR_LISTENER_H
#define MAX_LISTENERS 20
#define LISTENER_EXTEND_SIZE 1
@@ -46,7 +46,7 @@ struct Listener {
};
void listeners_initialise();
void listeners_initialise(void);
void handle_listeners(fd_set * readfds);
void set_listener_fds(fd_set * readfds);
@@ -60,4 +60,6 @@ struct Listener * get_listener(int type, void* typedata,
void remove_listener(struct Listener* listener);
#endif /* _LISTENER_H */
void remove_all_listeners(void);
#endif /* DROPBEAR_LISTENER_H */

View File

@@ -305,21 +305,6 @@ login_set_current_time(struct logininfo *li)
li->tv_usec = tv.tv_usec;
}
/* copy a sockaddr_* into our logininfo */
void
login_set_addr(struct logininfo *li, const struct sockaddr *sa,
const unsigned int sa_size)
{
unsigned int bufsize = sa_size;
/* make sure we don't overrun our union */
if (sizeof(li->hostaddr) < sa_size)
bufsize = sizeof(li->hostaddr);
memcpy((void *)&(li->hostaddr.sa), (const void *)sa, bufsize);
}
/**
** login_write: Call low-level recording functions based on autoconf
** results

View File

@@ -1,5 +1,5 @@
#ifndef _HAVE_LOGINREC_H_
#define _HAVE_LOGINREC_H_
#ifndef DROPBEAR_HAVE_LOGINREC_H_
#define DROPBEAR_HAVE_LOGINREC_H_
/*
* Copyright (c) 2000 Andre Lucas. All rights reserved.
@@ -79,10 +79,10 @@
# if defined(HAVE_UTMP_H) && defined(UTMP_FILE) && !defined(DISABLE_UTMP)
# define USE_UTMP
# endif
# if defined(HAVE_WTMPX_H) && defined(WTMPX_FILE) && !defined(DISABLE_WTMPX)
# if defined(WTMPX_FILE) && !defined(DISABLE_WTMPX)
# define USE_WTMPX
# endif
# if defined(HAVE_WTMP_H) && defined(WTMP_FILE) && !defined(DISABLE_WTMP)
# if defined(WTMP_FILE) && !defined(DISABLE_WTMP)
# define USE_WTMP
# endif
@@ -173,13 +173,9 @@ int login_utmp_only(struct logininfo *li);
int login_write (struct logininfo *li);
int login_log_entry(struct logininfo *li);
/* set the network address based on network address type */
void login_set_addr(struct logininfo *li, const struct sockaddr *sa,
const unsigned int sa_size);
/* produce various forms of the line filename */
char *line_fullname(char *dst, const char *src, size_t dstsize);
char *line_stripname(char *dst, const char *src, size_t dstsize);
char *line_abbrevname(char *dst, const char *src, size_t dstsize);
#endif /* _HAVE_LOGINREC_H_ */
#endif /* DROPBEAR_HAVE_LOGINREC_H_ */

View File

@@ -123,14 +123,14 @@ int dropbear_prng_test(void)
const struct ltc_prng_descriptor dropbear_prng_desc =
{
"dropbear_prng", 0,
&dropbear_prng_start,
&dropbear_prng_add_entropy,
&dropbear_prng_ready,
&dropbear_prng_read,
&dropbear_prng_done,
&dropbear_prng_export,
&dropbear_prng_import,
&dropbear_prng_test
dropbear_prng_start,
dropbear_prng_add_entropy,
dropbear_prng_ready,
dropbear_prng_read,
dropbear_prng_done,
dropbear_prng_export,
dropbear_prng_import,
dropbear_prng_test
};

View File

@@ -1,5 +1,5 @@
#ifndef _LTC_PRNG_H_DROPBEAR
#define _LTC_PRNG_H_DROPBEAR
#ifndef DROPBEAR_LTC_PRNG_H_DROPBEAR
#define DROPBEAR_LTC_PRNG_H_DROPBEAR
#include "options.h"
#include "includes.h"
@@ -10,4 +10,4 @@ extern const struct ltc_prng_descriptor dropbear_prng_desc;
#endif /* DROPBEAR_LTC_PRNG */
#endif /* _LTC_PRNG_H_DROPBEAR */
#endif /* DROPBEAR_LTC_PRNG_H_DROPBEAR */

560
netio.c Normal file
View File

@@ -0,0 +1,560 @@
#include "netio.h"
#include "list.h"
#include "dbutil.h"
#include "session.h"
#include "debug.h"
struct dropbear_progress_connection {
struct addrinfo *res;
struct addrinfo *res_iter;
char *remotehost, *remoteport; /* For error reporting */
connect_callback cb;
void *cb_data;
struct Queue *writequeue; /* A queue of encrypted packets to send with TCP fastopen,
or NULL. */
int sock;
char* errstring;
};
/* Deallocate a progress connection. Removes from the pending list if iter!=NULL.
Does not close sockets */
static void remove_connect(struct dropbear_progress_connection *c, m_list_elem *iter) {
if (c->res) {
freeaddrinfo(c->res);
}
m_free(c->remotehost);
m_free(c->remoteport);
m_free(c->errstring);
m_free(c);
if (iter) {
list_remove(iter);
}
}
static void cancel_callback(int result, int sock, void* UNUSED(data), const char* UNUSED(errstring)) {
if (result == DROPBEAR_SUCCESS)
{
m_close(sock);
}
}
void cancel_connect(struct dropbear_progress_connection *c) {
c->cb = cancel_callback;
c->cb_data = NULL;
}
static void connect_try_next(struct dropbear_progress_connection *c) {
struct addrinfo *r;
int res = 0;
int fastopen = 0;
#ifdef DROPBEAR_CLIENT_TCP_FAST_OPEN
struct msghdr message;
#endif
for (r = c->res_iter; r; r = r->ai_next)
{
dropbear_assert(c->sock == -1);
c->sock = socket(c->res_iter->ai_family, c->res_iter->ai_socktype, c->res_iter->ai_protocol);
if (c->sock < 0) {
continue;
}
ses.maxfd = MAX(ses.maxfd, c->sock);
set_sock_nodelay(c->sock);
setnonblocking(c->sock);
#ifdef DROPBEAR_CLIENT_TCP_FAST_OPEN
fastopen = (c->writequeue != NULL);
if (fastopen) {
memset(&message, 0x0, sizeof(message));
message.msg_name = r->ai_addr;
message.msg_namelen = r->ai_addrlen;
/* 6 is arbitrary, enough to hold initial packets */
unsigned int iovlen = 6; /* Linux msg_iovlen is a size_t */
struct iovec iov[6];
packet_queue_to_iovec(c->writequeue, iov, &iovlen);
message.msg_iov = iov;
message.msg_iovlen = iovlen;
res = sendmsg(c->sock, &message, MSG_FASTOPEN);
/* Returns EINPROGRESS if FASTOPEN wasn't available */
if (res < 0) {
if (errno != EINPROGRESS) {
m_free(c->errstring);
c->errstring = m_strdup(strerror(errno));
/* Not entirely sure which kind of errors are normal - 2.6.32 seems to
return EPIPE for any (nonblocking?) sendmsg(). just fall back */
TRACE(("sendmsg tcp_fastopen failed, falling back. %s", strerror(errno)));
/* No kernel MSG_FASTOPEN support. Fall back below */
fastopen = 0;
/* Set to NULL to avoid trying again */
c->writequeue = NULL;
}
} else {
packet_queue_consume(c->writequeue, res);
}
}
#endif
/* Normal connect(), used as fallback for TCP fastopen too */
if (!fastopen) {
res = connect(c->sock, r->ai_addr, r->ai_addrlen);
}
if (res < 0 && errno != EINPROGRESS) {
/* failure */
m_free(c->errstring);
c->errstring = m_strdup(strerror(errno));
close(c->sock);
c->sock = -1;
continue;
} else {
/* new connection was successful, wait for it to complete */
break;
}
}
if (r) {
c->res_iter = r->ai_next;
} else {
c->res_iter = NULL;
}
}
/* Connect via TCP to a host. */
struct dropbear_progress_connection *connect_remote(const char* remotehost, const char* remoteport,
connect_callback cb, void* cb_data)
{
struct dropbear_progress_connection *c = NULL;
int err;
struct addrinfo hints;
c = m_malloc(sizeof(*c));
c->remotehost = m_strdup(remotehost);
c->remoteport = m_strdup(remoteport);
c->sock = -1;
c->cb = cb;
c->cb_data = cb_data;
list_append(&ses.conn_pending, c);
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_UNSPEC;
err = getaddrinfo(remotehost, remoteport, &hints, &c->res);
if (err) {
int len;
len = 100 + strlen(gai_strerror(err));
c->errstring = (char*)m_malloc(len);
snprintf(c->errstring, len, "Error resolving '%s' port '%s'. %s",
remotehost, remoteport, gai_strerror(err));
TRACE(("Error resolving: %s", gai_strerror(err)))
} else {
c->res_iter = c->res;
}
return c;
}
void remove_connect_pending() {
while (ses.conn_pending.first) {
struct dropbear_progress_connection *c = ses.conn_pending.first->item;
remove_connect(c, ses.conn_pending.first);
}
}
void set_connect_fds(fd_set *writefd) {
m_list_elem *iter;
TRACE(("enter set_connect_fds"))
iter = ses.conn_pending.first;
while (iter) {
m_list_elem *next_iter = iter->next;
struct dropbear_progress_connection *c = iter->item;
/* Set one going */
while (c->res_iter && c->sock < 0) {
connect_try_next(c);
}
if (c->sock >= 0) {
FD_SET(c->sock, writefd);
} else {
/* Final failure */
if (!c->errstring) {
c->errstring = m_strdup("unexpected failure");
}
c->cb(DROPBEAR_FAILURE, -1, c->cb_data, c->errstring);
remove_connect(c, iter);
}
iter = next_iter;
}
}
void handle_connect_fds(fd_set *writefd) {
m_list_elem *iter;
TRACE(("enter handle_connect_fds"))
for (iter = ses.conn_pending.first; iter; iter = iter->next) {
int val;
socklen_t vallen = sizeof(val);
struct dropbear_progress_connection *c = iter->item;
if (c->sock < 0 || !FD_ISSET(c->sock, writefd)) {
continue;
}
TRACE(("handling %s port %s socket %d", c->remotehost, c->remoteport, c->sock));
if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &val, &vallen) != 0) {
TRACE(("handle_connect_fds getsockopt(%d) SO_ERROR failed: %s", c->sock, strerror(errno)))
/* This isn't expected to happen - Unix has surprises though, continue gracefully. */
m_close(c->sock);
c->sock = -1;
} else if (val != 0) {
/* Connect failed */
TRACE(("connect to %s port %s failed.", c->remotehost, c->remoteport))
m_close(c->sock);
c->sock = -1;
m_free(c->errstring);
c->errstring = m_strdup(strerror(val));
} else {
/* New connection has been established */
c->cb(DROPBEAR_SUCCESS, c->sock, c->cb_data, NULL);
remove_connect(c, iter);
TRACE(("leave handle_connect_fds - success"))
/* Must return here - remove_connect() invalidates iter */
return;
}
}
TRACE(("leave handle_connect_fds - end iter"))
}
void connect_set_writequeue(struct dropbear_progress_connection *c, struct Queue *writequeue) {
c->writequeue = writequeue;
}
void packet_queue_to_iovec(struct Queue *queue, struct iovec *iov, unsigned int *iov_count) {
struct Link *l;
unsigned int i;
int len;
buffer *writebuf;
#ifndef IOV_MAX
#define IOV_MAX UIO_MAXIOV
#endif
*iov_count = MIN(MIN(queue->count, IOV_MAX), *iov_count);
for (l = queue->head, i = 0; i < *iov_count; l = l->link, i++)
{
writebuf = (buffer*)l->item;
len = writebuf->len - 1 - writebuf->pos;
dropbear_assert(len > 0);
TRACE2(("write_packet writev #%d type %d len %d/%d", i, writebuf->data[writebuf->len-1],
len, writebuf->len-1))
iov[i].iov_base = buf_getptr(writebuf, len);
iov[i].iov_len = len;
}
}
void packet_queue_consume(struct Queue *queue, ssize_t written) {
buffer *writebuf;
int len;
while (written > 0) {
writebuf = (buffer*)examine(queue);
len = writebuf->len - 1 - writebuf->pos;
if (len > written) {
/* partial buffer write */
buf_incrpos(writebuf, written);
written = 0;
} else {
written -= len;
dequeue(queue);
buf_free(writebuf);
}
}
}
void set_sock_nodelay(int sock) {
int val;
/* disable nagle */
val = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
}
#ifdef DROPBEAR_SERVER_TCP_FAST_OPEN
void set_listen_fast_open(int sock) {
int qlen = MAX(MAX_UNAUTH_PER_IP, 5);
if (setsockopt(sock, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)) != 0) {
TRACE(("set_listen_fast_open failed for socket %d: %s", sock, strerror(errno)))
}
}
#endif
void set_sock_priority(int sock, enum dropbear_prio prio) {
int rc;
#ifdef IPTOS_LOWDELAY
int iptos_val = 0;
#endif
#ifdef SO_PRIORITY
int so_prio_val = 0;
#endif
/* Don't log ENOTSOCK errors so that this can harmlessly be called
* on a client '-J' proxy pipe */
/* set the TOS bit for either ipv4 or ipv6 */
#ifdef IPTOS_LOWDELAY
if (prio == DROPBEAR_PRIO_LOWDELAY) {
iptos_val = IPTOS_LOWDELAY;
} else if (prio == DROPBEAR_PRIO_BULK) {
iptos_val = IPTOS_THROUGHPUT;
}
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
}
#endif
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
}
#endif
#ifdef SO_PRIORITY
if (prio == DROPBEAR_PRIO_LOWDELAY) {
so_prio_val = TC_PRIO_INTERACTIVE;
} else if (prio == DROPBEAR_PRIO_BULK) {
so_prio_val = TC_PRIO_BULK;
}
/* linux specific, sets QoS class. see tc-prio(8) */
rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &so_prio_val, sizeof(so_prio_val));
if (rc < 0 && errno != ENOTSOCK)
dropbear_log(LOG_WARNING, "Couldn't set SO_PRIORITY (%s)",
strerror(errno));
#endif
}
/* Listen on address:port.
* Special cases are address of "" listening on everything,
* and address of NULL listening on localhost only.
* Returns the number of sockets bound on success, or -1 on failure. On
* failure, if errstring wasn't NULL, it'll be a newly malloced error
* string.*/
int dropbear_listen(const char* address, const char* port,
int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
struct addrinfo hints, *res = NULL, *res0 = NULL;
int err;
unsigned int nsock;
struct linger linger;
int val;
int sock;
TRACE(("enter dropbear_listen"))
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
hints.ai_socktype = SOCK_STREAM;
/* for calling getaddrinfo:
address == NULL and !AI_PASSIVE: local loopback
address == NULL and AI_PASSIVE: all interfaces
address != NULL: whatever the address says */
if (!address) {
TRACE(("dropbear_listen: local loopback"))
} else {
if (address[0] == '\0') {
TRACE(("dropbear_listen: all interfaces"))
address = NULL;
}
hints.ai_flags = AI_PASSIVE;
}
err = getaddrinfo(address, port, &hints, &res0);
if (err) {
if (errstring != NULL && *errstring == NULL) {
int len;
len = 20 + strlen(gai_strerror(err));
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
}
if (res0) {
freeaddrinfo(res0);
res0 = NULL;
}
TRACE(("leave dropbear_listen: failed resolving"))
return -1;
}
nsock = 0;
for (res = res0; res != NULL && nsock < sockcount;
res = res->ai_next) {
/* Get a socket */
socks[nsock] = socket(res->ai_family, res->ai_socktype,
res->ai_protocol);
sock = socks[nsock]; /* For clarity */
if (sock < 0) {
err = errno;
TRACE(("socket() failed"))
continue;
}
/* Various useful socket options */
val = 1;
/* set to reuse, quick timeout */
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
linger.l_onoff = 1;
linger.l_linger = 5;
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
#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_nodelay(sock);
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
err = errno;
close(sock);
TRACE(("bind(%s) failed", port))
continue;
}
if (listen(sock, DROPBEAR_LISTEN_BACKLOG) < 0) {
err = errno;
close(sock);
TRACE(("listen() failed"))
continue;
}
*maxfd = MAX(*maxfd, sock);
nsock++;
}
if (res0) {
freeaddrinfo(res0);
res0 = NULL;
}
if (nsock == 0) {
if (errstring != NULL && *errstring == NULL) {
int len;
len = 20 + strlen(strerror(err));
*errstring = (char*)m_malloc(len);
snprintf(*errstring, len, "Error listening: %s", strerror(err));
}
TRACE(("leave dropbear_listen: failure, %s", strerror(err)))
return -1;
}
TRACE(("leave dropbear_listen: success, %d socks bound", nsock))
return nsock;
}
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() */
void getaddrstring(struct sockaddr_storage* addr,
char **ret_host, char **ret_port,
int host_lookup) {
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
* of the specific structure. Some older linux systems (glibc 2.1.3
* such as debian potato) have sockaddr_storage.__ss_family instead
* but we'll ignore them */
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
if (addr->ss_family == AF_INET) {
len = sizeof(struct sockaddr_in);
}
#ifdef AF_INET6
if (addr->ss_family == AF_INET6) {
len = sizeof(struct sockaddr_in6);
}
#endif
#endif
ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1,
serv, sizeof(serv)-1, flags);
if (ret != 0) {
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 (ret_host) {
*ret_host = m_strdup(host);
}
if (ret_port) {
*ret_port = m_strdup(serv);
}
}

64
netio.h Normal file
View File

@@ -0,0 +1,64 @@
#ifndef DROPBEAR_NETIO_H
#define DROPBEAR_NETIO_H
#include "includes.h"
#include "buffer.h"
#include "queue.h"
enum dropbear_prio {
DROPBEAR_PRIO_DEFAULT = 10,
DROPBEAR_PRIO_LOWDELAY = 11,
DROPBEAR_PRIO_BULK = 12,
};
void set_sock_nodelay(int sock);
void set_sock_priority(int sock, enum dropbear_prio prio);
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);
struct dropbear_progress_connection;
/* result is DROPBEAR_SUCCESS or DROPBEAR_FAILURE.
errstring is only set on DROPBEAR_FAILURE, returns failure message for the last attempted socket */
typedef void(*connect_callback)(int result, int sock, void* data, const char* errstring);
/* Always returns a progress connection, if it fails it will call the callback at a later point */
struct dropbear_progress_connection * connect_remote (const char* remotehost, const char* remoteport,
connect_callback cb, void *cb_data);
/* Sets up for select() */
void set_connect_fds(fd_set *writefd);
/* Handles ready sockets after select() */
void handle_connect_fds(fd_set *writefd);
/* Cleanup */
void remove_connect_pending(void);
/* Doesn't actually stop the connect, but adds a dummy callback instead */
void cancel_connect(struct dropbear_progress_connection *c);
void connect_set_writequeue(struct dropbear_progress_connection *c, struct Queue *writequeue);
/* TODO: writev #ifdef guard */
/* Fills out iov which contains iov_count slots, returning the number filled in iov_count */
void packet_queue_to_iovec(struct Queue *queue, struct iovec *iov, unsigned int *iov_count);
void packet_queue_consume(struct Queue *queue, ssize_t written);
#ifdef DROPBEAR_SERVER_TCP_FAST_OPEN
/* Try for any Linux builds, will fall back if the kernel doesn't support it */
void set_listen_fast_open(int sock);
/* Define values which may be supported by the kernel even if the libc is too old */
#ifndef TCP_FASTOPEN
#define TCP_FASTOPEN 23
#endif
#ifndef MSG_FASTOPEN
#define MSG_FASTOPEN 0x20000000
#endif
#endif
#endif

View File

@@ -2,8 +2,8 @@
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved. See LICENSE for the license. */
#ifndef _OPTIONS_H_
#define _OPTIONS_H_
#ifndef DROPBEAR_OPTIONS_H_
#define DROPBEAR_OPTIONS_H_
/* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
* parts are to allow for commandline -DDROPBEAR_XXX options etc. */
@@ -98,11 +98,20 @@ much traffic. */
#define DROPBEAR_TWOFISH256
#define DROPBEAR_TWOFISH128
/* Enable CBC mode for ciphers. This has security issues though
* is the most compatible with older SSH implementations */
#define DROPBEAR_ENABLE_CBC_MODE
/* Enable "Counter Mode" for ciphers. This is more secure than normal
* CBC mode against certain attacks. This adds around 1kB to binary
* size and is recommended for most cases */
* CBC mode against certain attacks. It is recommended for security
* and forwards compatibility */
#define DROPBEAR_ENABLE_CTR_MODE
/* Twofish counter mode is disabled by default because it
has not been tested for interoperability with other SSH implementations.
If you test it please contact the Dropbear author */
/* #define DROPBEAR_TWOFISH_CTR */
/* 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
@@ -123,8 +132,8 @@ much traffic. */
* 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_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
@@ -159,6 +168,11 @@ much traffic. */
* ECDSA above */
#define DROPBEAR_ECDH
/* Group14 (2048 bit) is recommended. Group1 is less secure (1024 bit) though
is the only option for interoperability with some older SSH programs */
#define DROPBEAR_DH_GROUP1 1
#define DROPBEAR_DH_GROUP14 1
/* Control the memory/performance/compression tradeoff for zlib.
* Set windowBits=8 for least memory usage, see your system's
* zlib.h for full details.
@@ -170,6 +184,11 @@ much traffic. */
#define DROPBEAR_ZLIB_WINDOW_BITS 15
#endif
/* Server won't allow zlib compression until after authentication. Prevents
flaws in the zlib library being unauthenticated exploitable flaws.
Some old ssh clients may not support the alternative zlib@openssh.com method */
#define DROPBEAR_SERVER_DELAY_ZLIB 1
/* Whether to do reverse DNS lookups. */
/*#define DO_HOST_LOOKUP */
@@ -192,7 +211,10 @@ much traffic. */
* PAM challenge/response.
* You can't enable both PASSWORD and PAM. */
/* This requires crypt() */
#ifdef HAVE_CRYPT
#define ENABLE_SVR_PASSWORD_AUTH
#endif
/* PAM requires ./configure --enable-pam */
/*#define ENABLE_SVR_PAM_AUTH */
#define ENABLE_SVR_PUBKEY_AUTH
@@ -203,9 +225,16 @@ much traffic. */
#define ENABLE_SVR_PUBKEY_OPTIONS
#endif
/* This requires getpass. */
#ifdef HAVE_GETPASS
#define ENABLE_CLI_PASSWORD_AUTH
#define ENABLE_CLI_PUBKEY_AUTH
#define ENABLE_CLI_INTERACT_AUTH
#endif
#define ENABLE_CLI_PUBKEY_AUTH
/* A default argument for dbclient -i <privatekey>.
Homedir is prepended unless path begins with / */
#define DROPBEAR_DEFAULT_CLI_AUTHKEY ".ssh/id_dropbear"
/* This variable can be used to set a password for client
* authentication on the commandline. Beware of platforms
@@ -276,7 +305,7 @@ much traffic. */
/* This is used by the scp binary when used as a client binary. If you're
* not using the Dropbear client, you'll need to change it */
#define _PATH_SSH_PROGRAM "/usr/bin/dbclient"
#define DROPBEAR_PATH_SSH_PROGRAM "/usr/bin/dbclient"
/* Whether to log commands executed by a client. This only logs the
* (single) command sent to the server, not what a user did in a
@@ -324,4 +353,4 @@ be overridden at runtime with -I. 0 disables idle timeouts */
* in sysoptions.h */
#include "sysoptions.h"
#endif /* _OPTIONS_H_ */
#endif /* DROPBEAR_OPTIONS_H_ */

166
packet.c
View File

@@ -34,12 +34,13 @@
#include "service.h"
#include "auth.h"
#include "channel.h"
#include "netio.h"
static int read_packet_init();
static int read_packet_init(void);
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();
static int checkmac(void);
/* For exact details see http://www.zlib.net/zlib_tech.html
* 5 bytes per 16kB block, plus 6 bytes for the stream.
@@ -55,14 +56,15 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len);
/* non-blocking function writing out a current encrypted packet */
void write_packet() {
int len, written;
buffer * writebuf = NULL;
unsigned packet_type;
ssize_t written;
#ifdef HAVE_WRITEV
struct iovec *iov = NULL;
int i;
struct Link *l;
int iov_max_count;
/* 50 is somewhat arbitrary */
unsigned int iov_count = 50;
struct iovec iov[50];
#else
int len;
buffer* writebuf;
int packet_type;
#endif
TRACE2(("enter write_packet"))
@@ -70,36 +72,13 @@ void write_packet() {
#if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV))
#ifndef IOV_MAX
#define IOV_MAX UIO_MAXIOV
#endif
/* Make sure the size of the iov is below the maximum allowed by the OS. */
iov_max_count = ses.writequeue.count;
if (iov_max_count > IOV_MAX)
{
iov_max_count = IOV_MAX;
}
iov = m_malloc(sizeof(*iov) * iov_max_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);
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;
}
packet_queue_to_iovec(&ses.writequeue, iov, &iov_count);
/* This may return EAGAIN. The main loop sometimes
calls write_packet() without bothering to test with select() since
it's likely to be necessary */
written = writev(ses.sock_out, iov, iov_max_count);
written = writev(ses.sock_out, iov, iov_count);
if (written < 0) {
if (errno == EINTR || errno == EAGAIN) {
m_free(iov);
TRACE2(("leave write_packet: EINTR"))
return;
} else {
@@ -107,25 +86,13 @@ void write_packet() {
}
}
packet_queue_consume(&ses.writequeue, written);
ses.writequeue_len -= written;
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 /* No writev () */
/* Get the next buffer in the queue of encrypted packets to write*/
writebuf = (buffer*)examine(&ses.writequeue);
@@ -134,6 +101,8 @@ void write_packet() {
* a cleartext packet_type indicator */
packet_type = writebuf->data[writebuf->len-1];
len = writebuf->len - 1 - writebuf->pos;
TRACE2(("write_packet type %d len %d/%d", packet_type,
len, writebuf->len-1))
dropbear_assert(len > 0);
/* Try to write as much as possible */
written = write(ses.sock_out, buf_getptr(writebuf, len), len);
@@ -151,6 +120,8 @@ void write_packet() {
ses.remoteclosed();
}
ses.writequeue_len -= written;
if (written == len) {
/* We've finished with the packet, free it */
dequeue(&ses.writequeue);
@@ -283,18 +254,18 @@ static int read_packet_init() {
}
len = buf_getint(ses.readbuf) + 4 + macsize;
TRACE2(("packet size is %d, block %d mac %d", len, blocksize, macsize))
TRACE2(("packet size is %u, block %u mac %u", len, blocksize, macsize))
/* check packet length */
if ((len > RECV_MAX_PACKET_LEN) ||
(len < MIN_PACKET_LEN + macsize) ||
((len - macsize) % blocksize != 0)) {
dropbear_exit("Integrity error (bad packet size %d)", len);
dropbear_exit("Integrity error (bad packet size %u)", len);
}
if (len > ses.readbuf->size) {
buf_resize(ses.readbuf, len);
ses.readbuf = buf_resize(ses.readbuf, len);
}
buf_setlen(ses.readbuf, len);
buf_setpos(ses.readbuf, blocksize);
@@ -342,7 +313,7 @@ void decrypt_packet() {
/* - 4 - 1 is for LEN and PADLEN values */
len = ses.readbuf->len - padlen - 4 - 1 - macsize;
if ((len > RECV_MAX_PAYLOAD_LEN+ZLIB_COMPRESS_EXPANSION) || (len < 1)) {
dropbear_exit("Bad packet size %d", len);
dropbear_exit("Bad packet size %u", len);
}
buf_setpos(ses.readbuf, PACKET_PAYLOAD_OFF);
@@ -351,18 +322,21 @@ void decrypt_packet() {
if (is_compress_recv()) {
/* decompress */
ses.payload = buf_decompress(ses.readbuf, len);
buf_setpos(ses.payload, 0);
ses.payload_beginning = 0;
buf_free(ses.readbuf);
} else
#endif
{
ses.payload = ses.readbuf;
ses.payload_beginning = ses.payload->pos;
buf_setlen(ses.payload, ses.payload->pos + len);
/* copy payload */
ses.payload = buf_new(len);
memcpy(ses.payload->data, buf_getptr(ses.readbuf, len), len);
buf_incrlen(ses.payload, len);
//ses.payload = buf_new(len);
//memcpy(ses.payload->data, buf_getptr(ses.readbuf, len), len);
//buf_incrlen(ses.payload, len);
}
buf_free(ses.readbuf);
ses.readbuf = NULL;
buf_setpos(ses.payload, 0);
ses.recvseq++;
@@ -435,7 +409,7 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) {
dropbear_exit("bad packet, oversized decompressed");
}
new_size = MIN(RECV_MAX_PAYLOAD_LEN, ret->size + ZLIB_DECOMPRESS_INCR);
buf_resize(ret, new_size);
ret = buf_resize(ret, new_size);
}
}
}
@@ -602,18 +576,15 @@ void encrypt_packet() {
}
buf_incrpos(writebuf, len);
/* stick the MAC on it */
buf_putbytes(writebuf, mac_bytes, mac_size);
/* 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);
/* stick the MAC on it */
buf_putbytes(writebuf, mac_bytes, mac_size);
/* Update counts */
ses.kexstate.datatrans += writebuf->len;
writebuf_enqueue(writebuf, packet_type);
/* Update counts */
ses.transseq++;
now = monotonic_now();
@@ -631,6 +602,16 @@ void encrypt_packet() {
TRACE2(("leave encrypt_packet()"))
}
void writebuf_enqueue(buffer * writebuf, unsigned char packet_type) {
/* 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);
ses.writequeue_len += writebuf->len-1;
}
/* Create the packet mac, and append H(seqno|clearbuf) to the output */
/* output_mac must have ses.keys->trans.algo_mac->hashsize bytes. */
@@ -664,7 +645,7 @@ static void make_mac(unsigned int seqno, const struct key_context_directional *
dropbear_exit("HMAC error");
}
bufsize = MAX_MAC_LEN;
bufsize = MAX_MAC_LEN;
if (hmac_done(&hmac, output_mac, &bufsize) != CRYPT_OK) {
dropbear_exit("HMAC error");
}
@@ -674,7 +655,8 @@ static void make_mac(unsigned int seqno, const struct key_context_directional *
#ifndef DISABLE_ZLIB
/* compresses len bytes from src, outputting to dest (starting from the
* respective current positions. */
* respective current positions. dest must have sufficient space,
* len+ZLIB_COMPRESS_EXPANSION */
static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
unsigned int endpos = src->pos + len;
@@ -682,38 +664,28 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
TRACE2(("enter buf_compress"))
while (1) {
dropbear_assert(dest->size - dest->pos >= len+ZLIB_COMPRESS_EXPANSION);
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(dest, dest->len);
if (result != Z_OK) {
dropbear_exit("zlib error");
}
if (ses.keys->trans.zstream->avail_in == 0) {
break;
}
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(),
* but it is possible */
buf_resize(dest, dest->size + ZLIB_COMPRESS_EXPANSION);
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");
}
/* fails if destination buffer wasn't large enough */
dropbear_assert(ses.keys->trans.zstream->avail_in == 0);
TRACE2(("leave buf_compress"))
}
#endif

View File

@@ -22,23 +22,27 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _PACKET_H_
#ifndef DROPBEAR_PACKET_H_
#define _PACKET_H_
#define DROPBEAR_PACKET_H_
#include "includes.h"
#include "queue.h"
#include "buffer.h"
void write_packet();
void read_packet();
void decrypt_packet();
void encrypt_packet();
void write_packet(void);
void read_packet(void);
void decrypt_packet(void);
void encrypt_packet(void);
void process_packet();
void writebuf_enqueue(buffer * writebuf, unsigned char packet_type);
void maybe_flush_reply_queue();
void process_packet(void);
void maybe_flush_reply_queue(void);
typedef struct PacketType {
unsigned char type; /* SSH_MSG_FOO */
void (*handler)();
void (*handler)(void);
} packettype;
#define PACKET_PADDING_OFF 4
@@ -46,4 +50,4 @@ typedef struct PacketType {
#define INIT_READBUF 128
#endif /* _PACKET_H_ */
#endif /* DROPBEAR_PACKET_H_ */

View File

@@ -37,7 +37,7 @@
#define MAX_UNAUTH_PACKET_TYPE SSH_MSG_USERAUTH_PK_OK
static void recv_unimplemented();
static void recv_unimplemented(void);
/* process a decrypted packet, call the appropriate handler */
void process_packet() {

View File

@@ -22,8 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef _QUEUE_H_
#define _QUEUE_H_
#ifndef DROPBEAR_QUEUE_H_
#define DROPBEAR_QUEUE_H_
struct Link {

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