mirror of
https://github.com/clearml/dropbear
synced 2025-06-26 18:17:32 +00:00
Compare commits
186 Commits
DROPBEAR_0
...
DROPBEAR_2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9cdd5e99a4 | ||
|
|
897ed7125b | ||
|
|
459d259185 | ||
|
|
aac6336e49 | ||
|
|
fc1155f974 | ||
|
|
6a09fa23d0 | ||
|
|
142a0f8a83 | ||
|
|
d1dec41f76 | ||
|
|
69a165db86 | ||
|
|
dffb33cecf | ||
|
|
e7917c16c9 | ||
|
|
e05b7f0b76 | ||
|
|
aeea70f95f | ||
|
|
ded40babb5 | ||
|
|
e355f69401 | ||
|
|
c2b1327deb | ||
|
|
f7ba7444e8 | ||
|
|
a57947c513 | ||
|
|
372e81a842 | ||
|
|
49263b5314 | ||
|
|
57166b400c | ||
|
|
3ea9068e18 | ||
|
|
e4c672bdbb | ||
|
|
791a78ad1f | ||
|
|
6da90b34fe | ||
|
|
43769b5bb3 | ||
|
|
f98eb5808b | ||
|
|
3525cabf48 | ||
|
|
54a76342f5 | ||
|
|
154a65fc31 | ||
|
|
bd7a46f514 | ||
|
|
79a307bca2 | ||
|
|
38f42a0fa2 | ||
|
|
b4cdfcb506 | ||
|
|
d3cef72f26 | ||
|
|
ef151888fb | ||
|
|
ba15bbfe33 | ||
|
|
3bdfae61a2 | ||
|
|
4404126501 | ||
|
|
adeb372a66 | ||
|
|
c0d7c6693f | ||
|
|
3ec4670478 | ||
|
|
2fdb5fd6ce | ||
|
|
7f42096d0f | ||
|
|
e2c813df4d | ||
|
|
a2f70a3751 | ||
|
|
286fa93a8d | ||
|
|
557d86aa79 | ||
|
|
8e68d5e2d5 | ||
|
|
1a16da38d5 | ||
|
|
cbd3d5e3a5 | ||
|
|
78fbed8c3e | ||
|
|
f267ca1f3a | ||
|
|
a6eb824950 | ||
|
|
dcd1527a11 | ||
|
|
f8a92d1eed | ||
|
|
e55e468754 | ||
|
|
ff2aa20565 | ||
|
|
90b5691183 | ||
|
|
5af0d33164 | ||
|
|
e5072c6b12 | ||
|
|
90cf7f012c | ||
|
|
484516da51 | ||
|
|
5abe22d1a5 | ||
|
|
f6b304250b | ||
|
|
36526700a9 | ||
|
|
32294978a3 | ||
|
|
a0e931005b | ||
|
|
9c7485331a | ||
|
|
99d9cf500b | ||
|
|
4f62da0f0d | ||
|
|
9be0d6b53d | ||
|
|
bbf6d5f2f5 | ||
|
|
c4861340e9 | ||
|
|
5996c3824c | ||
|
|
c172fb3b32 | ||
|
|
03a0d11c4d | ||
|
|
156e0187bf | ||
|
|
fcaaa7b4c2 | ||
|
|
2f098325f8 | ||
|
|
9dc30fbd2a | ||
|
|
024d268d8c | ||
|
|
eaa737fecd | ||
|
|
845ad0be39 | ||
|
|
2259ce4cdf | ||
|
|
34f9b2a8f7 | ||
|
|
d37dcc636f | ||
|
|
804a1e69f2 | ||
|
|
f7b1222073 | ||
|
|
4fd4fbc255 | ||
|
|
8393c5f016 | ||
|
|
5ff341206e | ||
|
|
da59afe798 | ||
|
|
6270ed2f8a | ||
|
|
80e77b5e6d | ||
|
|
58c7d4474c | ||
|
|
3af964304f | ||
|
|
4289324c4b | ||
|
|
9f3c817491 | ||
|
|
a9cf0ca25f | ||
|
|
72a5612a29 | ||
|
|
d7f2153631 | ||
|
|
26b07ccafc | ||
|
|
1205fa68df | ||
|
|
f5be0fb218 | ||
|
|
88fc38c8f0 | ||
|
|
545de7a3a1 | ||
|
|
6ba2b2b384 | ||
|
|
d5ccc32b4d | ||
|
|
e719a9ef6f | ||
|
|
a02d38072a | ||
|
|
f2cd610750 | ||
|
|
db34044c7f | ||
|
|
036edd6206 | ||
|
|
f40ed8bad7 | ||
|
|
41f50057f1 | ||
|
|
c62e53807f | ||
|
|
10d7a35841 | ||
|
|
6b4105ffe6 | ||
|
|
2713445e91 | ||
|
|
1984aabc95 | ||
|
|
f4c4ca64a8 | ||
|
|
2a02c4084a | ||
|
|
e242b2820c | ||
|
|
6467b8d903 | ||
|
|
3e2b6a1821 | ||
|
|
4d009daaa0 | ||
|
|
d4a14fcb3d | ||
|
|
49b79fa02d | ||
|
|
c957edbe75 | ||
|
|
33ae2be52e | ||
|
|
496c1db974 | ||
|
|
f381274278 | ||
|
|
398339218e | ||
|
|
4dda424f74 | ||
|
|
f403c1f18b | ||
|
|
ff5d94a7a4 | ||
|
|
a15fc009da | ||
|
|
6c4390c848 | ||
|
|
a3188b44f0 | ||
|
|
aaa72ddbfc | ||
|
|
bcf3a3ab93 | ||
|
|
5feebd300e | ||
|
|
aec23e5f79 | ||
|
|
52a466b8af | ||
|
|
baa32218b0 | ||
|
|
fd0b05943d | ||
|
|
2e0145fb95 | ||
|
|
c894ea4ea2 | ||
|
|
88278dee74 | ||
|
|
d0fadd992f | ||
|
|
eb45ce0e8a | ||
|
|
194b700592 | ||
|
|
5454c2a7f1 | ||
|
|
a6568626a5 | ||
|
|
59943acffe | ||
|
|
d4e7654ed0 | ||
|
|
68b458ece9 | ||
|
|
1119ad3a2f | ||
|
|
29e68e9d79 | ||
|
|
c1fe2ec5ae | ||
|
|
81cacd9f15 | ||
|
|
6def0ab5f1 | ||
|
|
d20627585a | ||
|
|
2bcb60fe56 | ||
|
|
0f83379dc0 | ||
|
|
ca6d5fd05c | ||
|
|
b9e21e2367 | ||
|
|
665b768cef | ||
|
|
b272b967e2 | ||
|
|
22c16a8b71 | ||
|
|
f924aa18f2 | ||
|
|
72c446f160 | ||
|
|
2028b1b517 | ||
|
|
72a82cc0ac | ||
|
|
eef35883b7 | ||
|
|
8028e07815 | ||
|
|
3fc6569d46 | ||
|
|
2303d0fd09 | ||
|
|
9a007c30d4 | ||
|
|
1912439526 | ||
|
|
800810a181 | ||
|
|
3301bad391 | ||
|
|
f5d75b099b | ||
|
|
ba869e5601 | ||
|
|
1632bd4a18 |
6
.hgsigs
Normal file
6
.hgsigs
Normal file
@@ -0,0 +1,6 @@
|
||||
aa2f51a6b81d33de5e9898a7f27c792a173d9b26 0 iD8DBQBOuADmjPn4sExkf7wRAv/fAJ9FJFvjDoF+wd1ipDx1wkzdeBQNqgCgykUrSbXv76FBbxKntVbk9oS3GjI=
|
||||
3f12086c2ef2b9ffe36a822fdb3ff647fcec1831 0 iD8DBQBOuSlQjPn4sExkf7wRAvkbAKCgE1e8xEMQ16CGeoywhIQ0QR4eNgCfZdYYlzjb/+521Uvh5/7FRYEmrho=
|
||||
85f835f2fe0ac2c503c50a414de127222fb0a57c 0 iD8DBQBPRkMUjPn4sExkf7wRAvM4AJ9mw2OAkyjhSbamM1MizlEJUX18HACgoFKQkYf6BnYxN34Nv2HhM0cmzUc=
|
||||
9b80981212fe6c01b7c16b3ca7c4e66af56f12f1 0 iEYEABECAAYFAlFLKKcACgkQjPn4sExkf7xK7wCfcioCmJPsysSbQO6+4qZMVe0mmLwAn2/o+wRf4MrUXlohrr7aXEF9vdSB
|
||||
095b46180bbc412b029420587736a6185afc17e1 0 iEYEABECAAYFAlFsCnkACgkQjPn4sExkf7xLrwCfeMWjUaSmfU/fvseT5TdrYRqBEVQAoLz5SFLEA40C5f8zE8Ma/vgVJVIC
|
||||
f168962bab857ca030829e4cd73d9b32c868c874 0 iEYEABECAAYFAlFwDNwACgkQjPn4sExkf7wJ6QCePVovn/avKXUyNwNBYCcov6JLYqkAnRCPQdkXgv20N3t10r6PRMBBo1/S
|
||||
40
.hgtags
Normal file
40
.hgtags
Normal file
@@ -0,0 +1,40 @@
|
||||
03f65e461915a940939e4cc689fc89721ffc40de DROPBEAR_0.48.1
|
||||
0f967bfef5cd0056b7ec60e2305d917e51cbf30d DROPBEAR_0.44
|
||||
170329dc8ce5dfcf6298e1ad6699f109bf78e73d DROPBEAR_0.51
|
||||
1dbd2473482f320ea59f76ce961385cb3a0150a9 DROPBEAR_0.46
|
||||
2098857ab826dd42ae05a9a22c3ce2cc835b9844 DROPBEAR_0.45
|
||||
36160290a1b27451178be36752ed038840f59cdd LTC_DB_0.46
|
||||
39d5d58461d6e93337636e69d4cdf184a09c8d24 LTC_1.05
|
||||
55a99934db873be2e63b5968fb6532e5d9bd02e4 DROPBEAR_0.48
|
||||
59400faa4b44708c5d0b595e81193bc621e752d3 libtomcrypt-1.05
|
||||
66087d87c3555c78b47cf01f32bb5a32054c3ceb DROPBEAR_0.44test4
|
||||
677843bfa734238a67636b461a02c110c462ffaf DROPBEAR_0.44test1
|
||||
7faae8f46238e23975430876547b8950b4e75481 t:ltc-0.95-orig
|
||||
8220862baae829ebc762587b99c662480d57bb23 DROPBEAR_0.53
|
||||
86e0b50a9b588239c3fc9cc9cfe255ef586df17b ltm-0.30-orig
|
||||
88e0a1ad951add46b795511dc2698e36b4aee922 DROPBEAR_0.44test3
|
||||
8e94663164c6e106ccc5c9e997dedf6e04d77dd2 LTM_DB_0.44
|
||||
91fbc376f01084037cd5f6a5bf2e2db4903e8e99 libtommath-0.35
|
||||
97db060d0ef5f8cf8e67eb602ef037055a185ca9 libtommath-0.40
|
||||
aa2f51a6b81d33de5e9898a7f27c792a173d9b26 DROPBEAR_0.53.1
|
||||
ab370c629d363f8c9a3eca512bfa86e362034654 DROPBEAR_0.49
|
||||
c2ac796b130eeb6fa840873d8c230544c8ec7e4b DROPBEAR_0.44test2
|
||||
cd1143579f00b0248c79f63ca70efee4a35a57e8 LTC_DB_0.44
|
||||
ce104c8b0be1ff3f2c2590b7cdc3fd6870c865cd DROPBEAR_0.52
|
||||
d5faf4814ddbc5abd9e209409bb9e7a4686c8cd7 libtomcrypt-1.16
|
||||
d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1
|
||||
d8254fc979e99560c93ca2cece77a6df31927ea5 LTM_0.35
|
||||
e109027b9edfb02f0bdf96ec45bb1cd9ad41e7da LTM_DB_0.46
|
||||
e109027b9edfb02f0bdf96ec45bb1cd9ad41e7da LTM_DB_0.47
|
||||
e37b160c414cab6466622f63b0c4dcbf6ebc47a9 DROPBEAR_0.47
|
||||
e430a26064ee86ab79aef372118d6d03b2441996 DROPBEAR_0.50
|
||||
e5d119ea4c63656bc54ecfd865d04591ac2ed225 LTC_DB_0.47
|
||||
3f12086c2ef2b9ffe36a822fdb3ff647fcec1831 DROPBEAR_2011.54
|
||||
d354464b2aa6f6ba0bf44d43bcae5aa798435393 DROPBEAR_2012.55
|
||||
7faae8f46238e23975430876547b8950b4e75481 t:ltc-0.95-orig
|
||||
0000000000000000000000000000000000000000 t:ltc-0.95-orig
|
||||
d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1
|
||||
0000000000000000000000000000000000000000 t:ltc-0.95-db-merge1
|
||||
1b8b2b9d6e94bc3cc5e61b620476ea36cc466e1b DROPBEAR_2013.56
|
||||
96b8bcb88017815040949a417caa55686271e8a9 DROPBEAR_2013.57
|
||||
e76614145aea67f66e4a4257685c771efba21aa1 DROPBEAR_2013.58
|
||||
171
CHANGES
171
CHANGES
@@ -1,3 +1,170 @@
|
||||
2013.59 - Friday 4 October 2013
|
||||
|
||||
- Fix crash from -J command
|
||||
Thanks to Lluís Batlle i Rossell and Arnaud Mouiche for patches
|
||||
|
||||
- Avoid reading too much from /proc/net/rt_cache since that causes
|
||||
system slowness.
|
||||
|
||||
- Improve EOF handling for half-closed connections
|
||||
Thanks to Catalin Patulea
|
||||
|
||||
- Send a banner message to report PAM error messages intended for the user
|
||||
Patch from Martin Donnelly
|
||||
|
||||
- Limit the size of decompressed payloads, avoids memory exhaustion denial
|
||||
of service
|
||||
Thanks to Logan Lamb for reporting and investigating it
|
||||
|
||||
- Avoid disclosing existence of valid users through inconsistent delays
|
||||
Thanks to Logan Lamb for reporting
|
||||
|
||||
- Update config.guess and config.sub for newer architectures
|
||||
|
||||
- Avoid segfault in server for locked accounts
|
||||
|
||||
- "make install" now installs manpages
|
||||
dropbearkey.8 has been renamed to dropbearkey.1
|
||||
manpage added for dropbearconvert
|
||||
|
||||
- Get rid of one second delay when running non-interactive commands
|
||||
|
||||
|
||||
2013.58 - Thursday 18 April 2013
|
||||
|
||||
- Fix building with Zlib disabled, thanks to Hans Harder and cuma@freetz
|
||||
|
||||
- Use % as a separator for ports, fixes scp in multihop mode, from Hans Harder
|
||||
|
||||
- Reject logins for other users when running as non-root, from Hans Harder
|
||||
|
||||
- Disable client immediate authentication request by default, it prevents
|
||||
passwordless logins from working
|
||||
|
||||
2013.57 - Monday 15 April 2013
|
||||
|
||||
- Decreased connection setup time particularly with high latency connections,
|
||||
the number of round trips has been reduced for both client and server.
|
||||
CPU time hasn't been changed.
|
||||
|
||||
- Client will send an initial key exchange guess to save a round trip.
|
||||
Dropbear implements an extension kexguess2@matt.ucc.asn.au to allow the first
|
||||
packet guess to succeed in wider circumstances than the standard behaviour.
|
||||
When communicating with other implementations the standard behaviour is used.
|
||||
|
||||
- Client side: when public key or password authentication with
|
||||
$DROPBEAR_PASSWORD is used an initial authentication request will
|
||||
be sent immediately rather than querying the list of available methods.
|
||||
This behaviour is enabled by CLI_IMMEDIATE_AUTH option (on by default),
|
||||
please let the Dropbear author know if it causes any interoperability
|
||||
problems.
|
||||
|
||||
- Implement client escape characters ~. (terminate session) and
|
||||
~^Z (background session)
|
||||
|
||||
- Server will more reliably clean up utmp when connection is closed, reported by
|
||||
Mattias Walström
|
||||
|
||||
- Don't crash if /dev/urandom isn't writable (RHEL5), thanks to Scott Case
|
||||
|
||||
- Add "-y -y" client option to skip host key checking, thanks to Hans Harder
|
||||
|
||||
- scp didn't work properly on systems using vfork(), thanks to Frank Van Uffelen
|
||||
|
||||
- Added IUTF8 terminal mode support (Linux and Mac OS). Not standardised yet
|
||||
though probably will be soon
|
||||
|
||||
- Some verbose DROPBEAR_TRACE output is now hidden unless $DROPBEAR_TRACE2
|
||||
enviroment variable is set
|
||||
|
||||
- Fix using asymmetric MAC algorithms (broke in )
|
||||
|
||||
- Renamed configure.in to configure.ac to quieten autoconf, from Mike Frysinger
|
||||
|
||||
2013.56 - Thursday 21 March 2013
|
||||
|
||||
- Allow specifying cipher (-c) and MAC (-m) lists for dbclient
|
||||
|
||||
- Allow using 'none' cipher or MAC (off by default, use options.h). Encryption
|
||||
is used during authentication then disabled, similar to OpenSSH HPN mode
|
||||
|
||||
- Allow a user in immediately if the account has a blank password and blank
|
||||
passwords are enabled
|
||||
|
||||
- Include a few extra sources of entropy from /proc on Linux, hash private keys
|
||||
as well. Dropbear will also write gathered entropy back into /dev/urandom
|
||||
|
||||
- Added hmac-sha2-256 and hmac-sha2-512 support (off by default, use options.h)
|
||||
|
||||
- Don't sent bad address "localhost" for -R forward connections,
|
||||
reported by Denis Bider
|
||||
|
||||
- Add "-B" runtime option to allow blank passwords
|
||||
|
||||
- Allow using IPv6 bracket notation for addresses in server "-p" option, from Ben Jencks
|
||||
|
||||
- A few improvements for Android from Reimar Döffinger
|
||||
|
||||
- Fix memory leak for TCP forwarded connections to hosts that timed out,
|
||||
reported by Norbert Benczúr. Appears to be a very long-standing bug.
|
||||
|
||||
- Fix "make clean" for out of tree builds
|
||||
|
||||
- Fix compilation when ENABLE_{SVR,CLI}_AGENTFWD are unset
|
||||
|
||||
2012.55 - Wednesday 22 February 2012
|
||||
|
||||
- Security: Fix use-after-free bug that could be triggered if command="..."
|
||||
authorized_keys restrictions are used. Could allow arbitrary code execution
|
||||
or bypass of the command="..." restriction to an authenticated user.
|
||||
This bug affects releases 0.52 onwards. Ref CVE-2012-0920.
|
||||
Thanks to Danny Fullerton of Mantor Organization for reporting
|
||||
the bug.
|
||||
|
||||
- Compile fix, only apply IPV6 socket options if they are available in headers
|
||||
Thanks to Gustavo Zacarias for the patch
|
||||
|
||||
- Overwrite session key memory on exit
|
||||
|
||||
- Fix minor memory leak in unusual PAM authentication configurations.
|
||||
Thanks to Stathis Voukelatos
|
||||
|
||||
- Other small code cleanups
|
||||
|
||||
2011.54 - Tuesday 8 November 2011
|
||||
|
||||
- Building statically works again, broke in 0.53 and 0.53.1
|
||||
|
||||
- Fix crash when forwarding with -R
|
||||
|
||||
- Fixed various leaks found by Klocwork analysis software, thanks to them for
|
||||
running it
|
||||
|
||||
- Set IPTOS_LOWDELAY for IPv6, thanks to Dave Taht
|
||||
|
||||
- Bind to sockets with IPV6_V6ONLY so that it works properly on systems
|
||||
regardless of the system-wide setting
|
||||
|
||||
- Added ALLOW_BLANK_PASSWORD option. Dropbear also now allows public key logins
|
||||
to accounts with a blank password. Thanks to Rob Landley
|
||||
|
||||
- Fixed case where "-K 1" keepalive for dbclient would cause a SSH_MSG_IGNORE
|
||||
packet to be sent
|
||||
|
||||
- Avoid some memory allocations in big number maths routines, improves
|
||||
performance slightly
|
||||
|
||||
- Fix symlink target for installdropbearmulti with DESTDIR set, thanks to
|
||||
Scottie Shore
|
||||
|
||||
- When requesting server allocated remote ports (-R 0:host:port) print a
|
||||
message informing what the port is, thanks to Ali Onur Uyar.
|
||||
|
||||
- New version numbering scheme.
|
||||
|
||||
Source repository has now migrated to Mercurial at
|
||||
https://secure.ucc.asn.au/hg/dropbear/graph/default
|
||||
|
||||
0.53.1 - Wednesday 2 March 2011
|
||||
|
||||
- -lcrypt needs to be before object files for static linking
|
||||
@@ -565,7 +732,7 @@
|
||||
Lobenstock and Mihnea Stoenescu
|
||||
|
||||
- Use daemon() function if available (or our own copy) rather than separate
|
||||
code (thanks to Frédéric Lavernhe for the report and debugging, and Bernard
|
||||
code (thanks to Frédéric Lavernhe for the report and debugging, and Bernard
|
||||
Blackham for his suggestion on what to look at)
|
||||
|
||||
- Fixed up support for first_kex_packet_follows, required to talk to ssh.com
|
||||
@@ -684,7 +851,7 @@
|
||||
- Various signedness fixes
|
||||
- Can listen on multiple ports
|
||||
- added option to disable openpty with configure script,
|
||||
(from K.-P. Kirchdörfer <kapeka at epost.de>)
|
||||
(from K.-P. Kirchdörfer <kapeka at epost.de>)
|
||||
- Various cleanups to bignum code
|
||||
(thanks to Tom St Denis <tomstdenis at iahu.ca>)
|
||||
- Fix compile error when disabling RSA
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -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-2008 Matt Johnston
|
||||
Copyright (c) 2002-2013 Matt Johnston
|
||||
Portions copyright (c) 2004 Mihnea Stoenescu
|
||||
All rights reserved.
|
||||
|
||||
|
||||
45
Makefile.in
45
Makefile.in
@@ -28,13 +28,13 @@ COMMONOBJS=dbutil.o buffer.o \
|
||||
queue.o \
|
||||
atomicio.o compat.o fake-rfc2553.o
|
||||
|
||||
SVROBJS=@CRYPTLIB@ svr-kex.o svr-algo.o svr-auth.o sshpty.o \
|
||||
SVROBJS=svr-kex.o svr-auth.o sshpty.o \
|
||||
svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
|
||||
svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\
|
||||
svr-tcpfwd.o svr-authpam.o
|
||||
|
||||
CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
|
||||
cli-session.o cli-service.o cli-runopts.o cli-chansession.o \
|
||||
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
|
||||
|
||||
@@ -56,7 +56,7 @@ HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \
|
||||
loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \
|
||||
listener.h fake-rfc2553.h
|
||||
|
||||
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
|
||||
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) @CRYPTLIB@
|
||||
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
|
||||
dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
|
||||
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
|
||||
@@ -66,9 +66,10 @@ VPATH=@srcdir@
|
||||
srcdir=@srcdir@
|
||||
|
||||
prefix=@prefix@
|
||||
exec_prefix=${prefix}
|
||||
bindir=${exec_prefix}/bin
|
||||
sbindir=${exec_prefix}/sbin
|
||||
datarootdir = @datarootdir@
|
||||
bindir=@bindir@
|
||||
sbindir=@sbindir@
|
||||
mandir=@mandir@
|
||||
|
||||
CC=@CC@
|
||||
AR=@AR@
|
||||
@@ -123,31 +124,31 @@ install: $(addprefix inst_, $(TARGETS))
|
||||
installdropbearmulti: insdbmulti $(addprefix insmulti, $(PROGRAMS))
|
||||
|
||||
insdbmulti: dropbearmulti
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -m 755 dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)
|
||||
-chown root $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT)
|
||||
-chgrp 0 $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
$(INSTALL) dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)
|
||||
|
||||
insmultidropbear: dropbearmulti
|
||||
$(INSTALL) -d $(DESTDIR)$(sbindir)
|
||||
-rm -f $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
|
||||
-ln -s $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
|
||||
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
|
||||
|
||||
insmulti%: dropbearmulti
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
-rm -f $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
-ln -s $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
|
||||
# dropbear should go in sbin, so it needs a seperate rule
|
||||
inst_dropbear: dropbear
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) -m 755 dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
|
||||
-chown root $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
|
||||
-chgrp 0 $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
|
||||
$(INSTALL) -m 644 dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
|
||||
|
||||
inst_%: $*
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -m 755 $*$(EXEEXT) $(DESTDIR)$(bindir)
|
||||
-chown root $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
-chgrp 0 $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
$(INSTALL) $*$(EXEEXT) $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
|
||||
$(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1
|
||||
|
||||
|
||||
# for some reason the rule further down doesn't like $($@objs) as a prereq.
|
||||
@@ -167,7 +168,7 @@ scp: $(SCPOBJS) $(HEADERS) Makefile
|
||||
# multi-binary compilation.
|
||||
MULTIOBJS=
|
||||
ifeq ($(MULTI),1)
|
||||
MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs)))
|
||||
MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs))) @CRYPTLIB@
|
||||
CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
|
||||
endif
|
||||
|
||||
|
||||
6
README
6
README
@@ -1,4 +1,5 @@
|
||||
This is Dropbear, a smallish SSH 2 server and client.
|
||||
This is Dropbear, a smallish SSH server and client.
|
||||
https://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
|
||||
INSTALL has compilation instructions.
|
||||
|
||||
@@ -27,8 +28,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAwVa6M6cGVmUcLl2cFzkxEoJd06Ub4bVDsYrWvXhvUV+Z
|
||||
You must make sure that ~/.ssh, and the key file, are only writable by the
|
||||
user. Beware of editors that split the key into multiple lines.
|
||||
|
||||
NOTE: Dropbear ignores authorized_keys options such as those described in the
|
||||
OpenSSH sshd manpage, and will not allow a login for these keys.
|
||||
Dropbear supports some options for authorized_keys entries, see the manpage.
|
||||
|
||||
============================================================================
|
||||
|
||||
|
||||
17
agentfwd.h
17
agentfwd.h
@@ -30,22 +30,19 @@
|
||||
#include "auth.h"
|
||||
#include "list.h"
|
||||
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
|
||||
/* An agent reply can be reasonably large, as it can
|
||||
* contain a list of all public keys held by the agent.
|
||||
* 10000 is arbitrary */
|
||||
#define MAX_AGENT_REPLY 10000
|
||||
|
||||
int svr_agentreq(struct ChanSess * chansess);
|
||||
void svr_agentcleanup(struct ChanSess * chansess);
|
||||
void svr_agentset(struct ChanSess *chansess);
|
||||
|
||||
/* client functions */
|
||||
void cli_load_agent_keys(m_list * ret_list);
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
const unsigned char *data, unsigned int len);
|
||||
void cli_setup_agent(struct Channel *channel);
|
||||
|
||||
|
||||
#ifdef __hpux
|
||||
#define seteuid(a) setresuid(-1, (a), -1)
|
||||
#define setegid(a) setresgid(-1, (a), -1)
|
||||
@@ -53,4 +50,14 @@ void cli_setup_agent(struct Channel *channel);
|
||||
|
||||
extern const struct ChanType cli_chan_agent;
|
||||
|
||||
#endif /* ENABLE_CLI_AGENTFWD */
|
||||
|
||||
#ifdef ENABLE_SVR_AGENTFWD
|
||||
|
||||
int svr_agentreq(struct ChanSess * chansess);
|
||||
void svr_agentcleanup(struct ChanSess * chansess);
|
||||
void svr_agentset(struct ChanSess *chansess);
|
||||
|
||||
#endif /* ENABLE_SVR_AGENTFWD */
|
||||
|
||||
#endif /* _AGENTFWD_H_ */
|
||||
|
||||
23
algo.h
23
algo.h
@@ -83,9 +83,24 @@ void crypto_init();
|
||||
int have_algo(char* algo, size_t algolen, algo_type algos[]);
|
||||
void buf_put_algolist(buffer * buf, algo_type localalgos[]);
|
||||
|
||||
algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
int *goodguess);
|
||||
algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
int *goodguess);
|
||||
enum kexguess2_used {
|
||||
KEXGUESS2_LOOK,
|
||||
KEXGUESS2_NO,
|
||||
KEXGUESS2_YES,
|
||||
};
|
||||
|
||||
#define KEXGUESS2_ALGO_NAME "kexguess2@matt.ucc.asn.au"
|
||||
#define KEXGUESS2_ALGO_ID 99
|
||||
|
||||
|
||||
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
enum kexguess2_used *kexguess2, int *goodguess);
|
||||
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
int check_user_algos(const char* user_algo_list, algo_type * algos,
|
||||
const char *algo_desc);
|
||||
char * algolist_string(algo_type algos[]);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _ALGO_H_ */
|
||||
|
||||
4
auth.h
4
auth.h
@@ -36,6 +36,7 @@ void cli_authinitialise();
|
||||
void recv_msg_userauth_request();
|
||||
void send_msg_userauth_failure(int partial, int incrfail);
|
||||
void send_msg_userauth_success();
|
||||
void send_msg_userauth_banner(buffer *msg);
|
||||
void svr_auth_password();
|
||||
void svr_auth_pubkey();
|
||||
void svr_auth_pam();
|
||||
@@ -67,7 +68,7 @@ void recv_msg_userauth_pk_ok();
|
||||
void recv_msg_userauth_info_request();
|
||||
void cli_get_user();
|
||||
void cli_auth_getmethods();
|
||||
void cli_auth_try();
|
||||
int cli_auth_try();
|
||||
void recv_msg_userauth_banner();
|
||||
void cli_pubkeyfail();
|
||||
void cli_auth_password();
|
||||
@@ -133,7 +134,6 @@ struct PubKeyOptions {
|
||||
int no_pty_flag;
|
||||
/* "command=" option. */
|
||||
unsigned char * forced_command;
|
||||
unsigned char * original_command;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
3
bignum.h
3
bignum.h
@@ -26,9 +26,10 @@
|
||||
#define _BIGNUM_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
void m_mp_init(mp_int *mp);
|
||||
void m_mp_init_multi(mp_int *mp, ...);
|
||||
void m_mp_init_multi(mp_int *mp, ...) ATTRIB_SENTINEL;
|
||||
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
|
||||
void sha1_process_mp(hash_state *hs, mp_int *mp);
|
||||
|
||||
|
||||
4
buffer.c
4
buffer.c
@@ -282,7 +282,7 @@ void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
|
||||
void buf_putmpint(buffer* buf, mp_int * mp) {
|
||||
|
||||
unsigned int len, pad = 0;
|
||||
TRACE(("enter buf_putmpint"))
|
||||
TRACE2(("enter buf_putmpint"))
|
||||
|
||||
dropbear_assert(mp != NULL);
|
||||
|
||||
@@ -318,7 +318,7 @@ void buf_putmpint(buffer* buf, mp_int * mp) {
|
||||
buf_incrwritepos(buf, len-pad);
|
||||
}
|
||||
|
||||
TRACE(("leave buf_putmpint"))
|
||||
TRACE2(("leave buf_putmpint"))
|
||||
}
|
||||
|
||||
/* Retrieve an mp_int from the buffer.
|
||||
|
||||
14
channel.h
14
channel.h
@@ -61,7 +61,8 @@ struct Channel {
|
||||
int readfd; /* read from insecure side, written to wire */
|
||||
int errfd; /* used like writefd or readfd, depending if it's client or server.
|
||||
Doesn't exactly belong here, but is cleaner here */
|
||||
circbuffer *writebuf; /* data from the wire, for local consumption */
|
||||
circbuffer *writebuf; /* data from the wire, for local consumption. Can be
|
||||
initially NULL */
|
||||
circbuffer *extrabuf; /* extended-data for the program - used like writebuf
|
||||
but for stderr */
|
||||
|
||||
@@ -69,6 +70,10 @@ struct Channel {
|
||||
int sent_close, recv_close;
|
||||
int recv_eof, sent_eof;
|
||||
|
||||
/* Set after running the ChanType-specific close hander
|
||||
* to ensure we don't run it twice (nor type->checkclose()). */
|
||||
int close_handler_done;
|
||||
|
||||
int initconn; /* used for TCP forwarding, whether the channel has been
|
||||
fully initialised */
|
||||
|
||||
@@ -78,8 +83,10 @@ struct Channel {
|
||||
|
||||
int flushing;
|
||||
|
||||
const struct ChanType* type;
|
||||
/* Used by client chansession to handle ~ escaping, NULL ignored otherwise */
|
||||
void (*read_mangler)(struct Channel*, unsigned char* bytes, int *len);
|
||||
|
||||
const struct ChanType* type;
|
||||
};
|
||||
|
||||
struct ChanType {
|
||||
@@ -98,9 +105,6 @@ void chancleanup();
|
||||
void setchannelfds(fd_set *readfd, fd_set *writefd);
|
||||
void channelio(fd_set *readfd, fd_set *writefd);
|
||||
struct Channel* getchannel();
|
||||
struct Channel* newchannel(unsigned int remotechan,
|
||||
const struct ChanType *type,
|
||||
unsigned int transwindow, unsigned int transmaxpacket);
|
||||
|
||||
void recv_msg_channel_open();
|
||||
void recv_msg_channel_request();
|
||||
|
||||
@@ -69,6 +69,10 @@ struct ChanSess {
|
||||
char * agentfile;
|
||||
char * agentdir;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
|
||||
char *original_command;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ChildPid {
|
||||
|
||||
@@ -37,7 +37,9 @@ circbuffer * cbuf_new(unsigned int size) {
|
||||
}
|
||||
|
||||
cbuf = (circbuffer*)m_malloc(sizeof(circbuffer));
|
||||
cbuf->data = (unsigned char*)m_malloc(size);
|
||||
if (size > 0) {
|
||||
cbuf->data = (unsigned char*)m_malloc(size);
|
||||
}
|
||||
cbuf->used = 0;
|
||||
cbuf->readpos = 0;
|
||||
cbuf->writepos = 0;
|
||||
@@ -48,6 +50,7 @@ circbuffer * cbuf_new(unsigned int size) {
|
||||
|
||||
void cbuf_free(circbuffer * cbuf) {
|
||||
|
||||
m_burn(cbuf->data, cbuf->size);
|
||||
m_free(cbuf->data);
|
||||
m_free(cbuf);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ static int new_agent_chan(struct Channel * channel) {
|
||||
return SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
|
||||
|
||||
fd = connect_agent();
|
||||
if (cli_opts.agent_fd < 0) {
|
||||
if (fd < 0) {
|
||||
return SSH_OPEN_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
@@ -156,8 +156,6 @@ static buffer * agent_request(unsigned char type, buffer *data) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
TRACE(("agent_request readlen is %d", readlen))
|
||||
|
||||
buf_resize(inbuf, readlen);
|
||||
buf_setpos(inbuf, 0);
|
||||
ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen);
|
||||
@@ -167,7 +165,6 @@ static buffer * agent_request(unsigned char type, buffer *data) {
|
||||
}
|
||||
buf_incrwritepos(inbuf, readlen);
|
||||
buf_setpos(inbuf, 0);
|
||||
TRACE(("agent_request success, length %d", readlen))
|
||||
|
||||
out:
|
||||
if (payload)
|
||||
@@ -258,9 +255,9 @@ void cli_load_agent_keys(m_list *ret_list) {
|
||||
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
const unsigned char *data, unsigned int len) {
|
||||
buffer *request_data = buf_new(MAX_PUBKEY_SIZE + len + 12);
|
||||
buffer *response;
|
||||
unsigned int keylen, siglen;
|
||||
buffer *request_data = NULL;
|
||||
buffer *response = NULL;
|
||||
unsigned int siglen;
|
||||
int packet_type;
|
||||
|
||||
/* Request format
|
||||
@@ -269,19 +266,13 @@ void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
string data
|
||||
uint32 flags
|
||||
*/
|
||||
/* We write the key, then figure how long it was and write that */
|
||||
//buf_putint(request_data, 0);
|
||||
request_data = buf_new(MAX_PUBKEY_SIZE + len + 12);
|
||||
buf_put_pub_key(request_data, key, key->type);
|
||||
keylen = request_data->len - 4;
|
||||
//buf_setpos(request_data, 0);
|
||||
//buf_putint(request_data, keylen);
|
||||
|
||||
//buf_setpos(request_data, request_data->len);
|
||||
buf_putstring(request_data, data, len);
|
||||
buf_putint(request_data, 0);
|
||||
|
||||
response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);
|
||||
buf_free(request_data);
|
||||
|
||||
if (!response) {
|
||||
goto fail;
|
||||
@@ -298,14 +289,21 @@ void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
*/
|
||||
siglen = buf_getint(response);
|
||||
buf_putbytes(sigblob, buf_getptr(response, siglen), siglen);
|
||||
buf_free(response);
|
||||
goto cleanup;
|
||||
|
||||
return;
|
||||
fail:
|
||||
/* XXX don't fail badly here. instead propagate a failure code back up to
|
||||
the cli auth pubkey code, and just remove this key from the list of
|
||||
ones to try. */
|
||||
dropbear_exit("Agent failed signing key");
|
||||
|
||||
cleanup:
|
||||
if (request_data) {
|
||||
buf_free(request_data);
|
||||
}
|
||||
if (response) {
|
||||
buf_free(response);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
99
cli-algo.c
99
cli-algo.c
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
* SSH client implementation
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2004 by Mihnea Stoenescu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "algo.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
|
||||
/*
|
||||
* The chosen [encryption | MAC | compression] algorithm to each
|
||||
* direction MUST be the first algorithm on the client's list
|
||||
* that is also on the server's list.
|
||||
*/
|
||||
algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
int *goodguess) {
|
||||
|
||||
unsigned char * algolist = NULL;
|
||||
unsigned char * remotealgos[MAX_PROPOSED_ALGO];
|
||||
unsigned int len;
|
||||
unsigned int count, i, j;
|
||||
algo_type * ret = NULL;
|
||||
|
||||
*goodguess = 0;
|
||||
|
||||
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
|
||||
algolist = buf_getstring(buf, &len);
|
||||
TRACE(("cli_buf_match_algo: %s", algolist))
|
||||
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
goto out; /* just a sanity check, no other use */
|
||||
}
|
||||
|
||||
/* remotealgos will contain a list of the strings parsed out */
|
||||
/* We will have at least one string (even if it's just "") */
|
||||
remotealgos[0] = algolist;
|
||||
count = 1;
|
||||
/* Iterate through, replacing ','s with NULs, to split it into
|
||||
* words. */
|
||||
for (i = 0; i < len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
goto out;
|
||||
}
|
||||
if (algolist[i] == ',') {
|
||||
algolist[i] = '\0';
|
||||
remotealgos[count] = &algolist[i+1];
|
||||
count++;
|
||||
}
|
||||
if (count == MAX_PROPOSED_ALGO) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* iterate and find the first match */
|
||||
|
||||
for (j = 0; localalgos[j].name != NULL; j++) {
|
||||
if (localalgos[j].usable) {
|
||||
len = strlen(localalgos[j].name);
|
||||
for (i = 0; i < count; i++) {
|
||||
if (len == strlen(remotealgos[i])
|
||||
&& strncmp(localalgos[j].name,
|
||||
remotealgos[i], len) == 0) {
|
||||
if (i == 0 && j == 0) {
|
||||
/* was a good guess */
|
||||
*goodguess = 1;
|
||||
}
|
||||
ret = &localalgos[j];
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
m_free(algolist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
53
cli-auth.c
53
cli-auth.c
@@ -40,11 +40,18 @@ void cli_authinitialise() {
|
||||
|
||||
/* Send a "none" auth request to get available methods */
|
||||
void cli_auth_getmethods() {
|
||||
|
||||
TRACE(("enter cli_auth_getmethods"))
|
||||
|
||||
#ifdef CLI_IMMEDIATE_AUTH
|
||||
ses.authstate.authtypes = AUTH_TYPE_PUBKEY;
|
||||
if (getenv(DROPBEAR_PASSWORD_ENV)) {
|
||||
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT;
|
||||
}
|
||||
if (cli_auth_try() == DROPBEAR_SUCCESS) {
|
||||
TRACE(("skipped initial none auth query"))
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
|
||||
buf_putstring(ses.writepayload, cli_opts.username,
|
||||
strlen(cli_opts.username));
|
||||
@@ -54,7 +61,6 @@ void cli_auth_getmethods() {
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave cli_auth_getmethods"))
|
||||
|
||||
}
|
||||
|
||||
void recv_msg_userauth_banner() {
|
||||
@@ -240,7 +246,7 @@ void recv_msg_userauth_success() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void cli_auth_try() {
|
||||
int cli_auth_try() {
|
||||
|
||||
int finished = 0;
|
||||
TRACE(("enter cli_auth_try"))
|
||||
@@ -256,33 +262,40 @@ void cli_auth_try() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_INTERACT_AUTH
|
||||
if (!finished && ses.authstate.authtypes & AUTH_TYPE_INTERACT) {
|
||||
if (cli_ses.auth_interact_failed) {
|
||||
finished = 0;
|
||||
#ifdef ENABLE_CLI_PASSWORD_AUTH
|
||||
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_PASSWORD)) {
|
||||
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
|
||||
fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n");
|
||||
} else {
|
||||
cli_auth_interactive();
|
||||
cli_ses.lastauthtype = AUTH_TYPE_INTERACT;
|
||||
cli_auth_password();
|
||||
finished = 1;
|
||||
cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_PASSWORD_AUTH
|
||||
if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
|
||||
cli_auth_password();
|
||||
finished = 1;
|
||||
cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
|
||||
#ifdef ENABLE_CLI_INTERACT_AUTH
|
||||
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_INTERACT)) {
|
||||
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
|
||||
fprintf(stderr, "Sorry, I won't let you use interactive auth unencrypted.\n");
|
||||
} else {
|
||||
if (!cli_ses.auth_interact_failed) {
|
||||
cli_auth_interactive();
|
||||
cli_ses.lastauthtype = AUTH_TYPE_INTERACT;
|
||||
finished = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype))
|
||||
|
||||
if (!finished) {
|
||||
dropbear_exit("No auth methods could be used.");
|
||||
if (finished) {
|
||||
TRACE(("leave cli_auth_try success"))
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
TRACE(("leave cli_auth_try"))
|
||||
TRACE(("leave cli_auth_try failure"))
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* A helper for getpass() that exits if the user cancels. The returned
|
||||
|
||||
@@ -131,6 +131,7 @@ void recv_msg_userauth_info_request() {
|
||||
response_len = strlen(response);
|
||||
buf_putstring(ses.writepayload, response, response_len);
|
||||
m_burn(response, response_len);
|
||||
m_free(prompt);
|
||||
m_free(response);
|
||||
}
|
||||
|
||||
|
||||
@@ -123,6 +123,7 @@ void recv_msg_userauth_pk_ok() {
|
||||
void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
const unsigned char *data, unsigned int len)
|
||||
{
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
if (key->source == SIGNKEY_SOURCE_AGENT) {
|
||||
/* Format the agent signature ourselves, as buf_put_sign would. */
|
||||
buffer *sigblob;
|
||||
@@ -133,10 +134,11 @@ void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
sigblob->len);
|
||||
|
||||
buf_free(sigblob);
|
||||
} else {
|
||||
} else
|
||||
#endif /* ENABLE_CLI_AGENTFWD */
|
||||
{
|
||||
buf_put_sign(buf, key, type, data, len);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* TODO: make it take an agent reference to use as well */
|
||||
@@ -187,11 +189,13 @@ int cli_auth_pubkey() {
|
||||
|
||||
TRACE(("enter cli_auth_pubkey"))
|
||||
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
if (!cli_opts.agent_keys_loaded) {
|
||||
/* get the list of available keys from the agent */
|
||||
cli_load_agent_keys(cli_opts.privkeys);
|
||||
cli_opts.agent_keys_loaded = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cli_opts.privkeys->first) {
|
||||
sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
|
||||
|
||||
@@ -38,9 +38,10 @@
|
||||
static void cli_closechansess(struct Channel *channel);
|
||||
static int cli_initchansess(struct Channel *channel);
|
||||
static void cli_chansessreq(struct Channel *channel);
|
||||
|
||||
static void send_chansess_pty_req(struct Channel *channel);
|
||||
static void send_chansess_shell_req(struct Channel *channel);
|
||||
static void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len);
|
||||
|
||||
|
||||
static void cli_tty_setup();
|
||||
|
||||
@@ -70,7 +71,9 @@ static void cli_chansessreq(struct Channel *channel) {
|
||||
TRACE(("got exit-signal, ignoring it"))
|
||||
} else {
|
||||
TRACE(("unknown request '%s'", type))
|
||||
send_msg_channel_failure(channel);
|
||||
if (wantreply) {
|
||||
send_msg_channel_failure(channel);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -81,14 +84,12 @@ out:
|
||||
|
||||
/* If the main session goes, we close it up */
|
||||
static void cli_closechansess(struct Channel *UNUSED(channel)) {
|
||||
cli_tty_cleanup(); /* Restore tty modes etc */
|
||||
|
||||
/* This channel hasn't gone yet, so we have > 1 */
|
||||
if (ses.chancount > 1) {
|
||||
dropbear_log(LOG_INFO, "Waiting for other channels to close...");
|
||||
}
|
||||
|
||||
cli_tty_cleanup(); /* Restore tty modes etc */
|
||||
|
||||
}
|
||||
|
||||
void cli_start_send_channel_request(struct Channel *channel,
|
||||
@@ -374,7 +375,9 @@ static int cli_initchansess(struct Channel *channel) {
|
||||
|
||||
if (cli_opts.wantpty) {
|
||||
cli_tty_setup();
|
||||
}
|
||||
channel->read_mangler = cli_escape_handler;
|
||||
cli_ses.last_char = '\r';
|
||||
}
|
||||
|
||||
return 0; /* Success */
|
||||
}
|
||||
@@ -429,3 +432,59 @@ void cli_send_chansess_request() {
|
||||
TRACE(("leave cli_send_chansess_request"))
|
||||
|
||||
}
|
||||
|
||||
// returns 1 if the character should be consumed, 0 to pass through
|
||||
static int
|
||||
do_escape(unsigned char c) {
|
||||
switch (c) {
|
||||
case '.':
|
||||
dropbear_exit("Terminated");
|
||||
return 1;
|
||||
break;
|
||||
case 0x1a:
|
||||
// ctrl-z
|
||||
cli_tty_cleanup();
|
||||
kill(getpid(), SIGTSTP);
|
||||
// after continuation
|
||||
cli_tty_setup();
|
||||
cli_ses.winchange = 1;
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len) {
|
||||
char c;
|
||||
int skip_char = 0;
|
||||
|
||||
// only handle escape characters if they are read one at a time. simplifies
|
||||
// the code and avoids nasty people putting ~. at the start of a line to paste
|
||||
if (*len != 1) {
|
||||
cli_ses.last_char = 0x0;
|
||||
return;
|
||||
}
|
||||
|
||||
c = buf[0];
|
||||
|
||||
if (cli_ses.last_char == DROPBEAR_ESCAPE_CHAR) {
|
||||
skip_char = do_escape(c);
|
||||
cli_ses.last_char = 0x0;
|
||||
} else {
|
||||
if (c == DROPBEAR_ESCAPE_CHAR) {
|
||||
if (cli_ses.last_char == '\r') {
|
||||
cli_ses.last_char = DROPBEAR_ESCAPE_CHAR;
|
||||
skip_char = 1;
|
||||
} else {
|
||||
cli_ses.last_char = 0x0;
|
||||
}
|
||||
} else {
|
||||
cli_ses.last_char = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip_char) {
|
||||
*len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
32
cli-kex.c
32
cli-kex.c
@@ -42,18 +42,27 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen);
|
||||
#define MAX_KNOWNHOSTS_LINE 4500
|
||||
|
||||
void send_msg_kexdh_init() {
|
||||
TRACE(("send_msg_kexdh_init()"))
|
||||
if ((cli_ses.dh_e && cli_ses.dh_x
|
||||
&& cli_ses.dh_val_algo == ses.newkeys->algo_kex)) {
|
||||
TRACE(("reusing existing dh_e from first_kex_packet_follows"))
|
||||
} else {
|
||||
if (!cli_ses.dh_e || !cli_ses.dh_e) {
|
||||
cli_ses.dh_e = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
cli_ses.dh_x = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
|
||||
}
|
||||
|
||||
cli_ses.dh_e = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
cli_ses.dh_x = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
|
||||
|
||||
gen_kexdh_vals(cli_ses.dh_e, cli_ses.dh_x);
|
||||
gen_kexdh_vals(cli_ses.dh_e, cli_ses.dh_x);
|
||||
cli_ses.dh_val_algo = ses.newkeys->algo_kex;
|
||||
}
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
|
||||
buf_putmpint(ses.writepayload, cli_ses.dh_e);
|
||||
encrypt_packet();
|
||||
ses.requirenext = SSH_MSG_KEXDH_REPLY;
|
||||
ses.requirenext[0] = SSH_MSG_KEXDH_REPLY;
|
||||
ses.requirenext[1] = SSH_MSG_KEXINIT;
|
||||
}
|
||||
|
||||
/* Handle a diffie-hellman key exchange reply. */
|
||||
@@ -98,6 +107,7 @@ void recv_msg_kexdh_reply() {
|
||||
mp_clear_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
|
||||
m_free(cli_ses.dh_e);
|
||||
m_free(cli_ses.dh_x);
|
||||
cli_ses.dh_val_algo = DROPBEAR_KEX_NONE;
|
||||
|
||||
if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
@@ -108,7 +118,8 @@ void recv_msg_kexdh_reply() {
|
||||
hostkey = NULL;
|
||||
|
||||
send_msg_newkeys();
|
||||
ses.requirenext = SSH_MSG_NEWKEYS;
|
||||
ses.requirenext[0] = SSH_MSG_NEWKEYS;
|
||||
ses.requirenext[1] = 0;
|
||||
TRACE(("leave recv_msg_kexdh_init"))
|
||||
}
|
||||
|
||||
@@ -217,6 +228,11 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
buffer * line = NULL;
|
||||
int ret;
|
||||
|
||||
if (cli_opts.no_hostkey_check) {
|
||||
fprintf(stderr, "Caution, skipping hostkey check for %s\n", cli_opts.remotehost);
|
||||
return;
|
||||
}
|
||||
|
||||
hostsfile = open_known_hosts_file(&readonly);
|
||||
if (!hostsfile) {
|
||||
ask_to_confirm(keyblob, keybloblen);
|
||||
@@ -246,7 +262,6 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
/* Compare hostnames */
|
||||
if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen),
|
||||
hostlen) != 0) {
|
||||
TRACE(("hosts don't match"))
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -309,7 +324,6 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
buf_putbytes(line, algoname, algolen);
|
||||
buf_putbyte(line, ' ');
|
||||
len = line->size - line->pos;
|
||||
TRACE(("keybloblen %d, len %d", keybloblen, len))
|
||||
/* The only failure with base64 is buffer_overflow, but buf_getwriteptr
|
||||
* will die horribly in the case anyway */
|
||||
base64_encode(keyblob, keybloblen, buf_getwriteptr(line, len), &len);
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "runopts.h"
|
||||
#include "session.h"
|
||||
|
||||
static void cli_dropbear_exit(int exitcode, const char* format, va_list param);
|
||||
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
|
||||
static void cli_dropbear_log(int priority, const char* format, va_list param);
|
||||
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
@@ -98,8 +98,7 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
|
||||
}
|
||||
|
||||
/* Do the cleanup first, since then the terminal will be reset */
|
||||
cli_session_cleanup();
|
||||
common_session_cleanup();
|
||||
session_cleanup();
|
||||
|
||||
_dropbear_log(LOG_INFO, fmtbuf, param);
|
||||
|
||||
|
||||
@@ -49,13 +49,12 @@ static void add_netcat(const char *str);
|
||||
|
||||
static void printhelp() {
|
||||
|
||||
fprintf(stderr, "Dropbear client v%s\n"
|
||||
fprintf(stderr, "Dropbear SSH client v%s https://matt.ucc.asn.au/dropbear/dropbear.html\n"
|
||||
#ifdef ENABLE_CLI_MULTIHOP
|
||||
"Usage: %s [options] [user@]host[/port][,[user@]host/port],...] [command]\n"
|
||||
#else
|
||||
"Usage: %s [options] [user@]host[/port] [command]\n"
|
||||
#endif
|
||||
"Options are:\n"
|
||||
"-p <remoteport>\n"
|
||||
"-l <username>\n"
|
||||
"-t Allocate a pty\n"
|
||||
@@ -63,7 +62,8 @@ static void printhelp() {
|
||||
"-N Don't run a remote command\n"
|
||||
"-f Run in background after auth\n"
|
||||
"-y Always accept remote host key if unknown\n"
|
||||
"-s Request a subsystem (use for sftp)\n"
|
||||
"-y -y Don't perform any remote host key checking (caution)\n"
|
||||
"-s Request a subsystem (use by external sftp)\n"
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
"-i <identityfile> (multiple allowed)\n"
|
||||
#endif
|
||||
@@ -86,6 +86,10 @@ static void printhelp() {
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
"-J <proxy_program> Use program pipe rather than TCP connection\n"
|
||||
#endif
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
"-c <cipher list> Specify preferred ciphers ('-c help' to list options)\n"
|
||||
"-m <MAC list> Specify preferred MACs for packet verification (or '-m help')\n"
|
||||
#endif
|
||||
#ifdef DEBUG_TRACE
|
||||
"-v verbose (compiled with DEBUG_TRACE)\n"
|
||||
#endif
|
||||
@@ -127,6 +131,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
cli_opts.backgrounded = 0;
|
||||
cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */
|
||||
cli_opts.always_accept_key = 0;
|
||||
cli_opts.no_hostkey_check = 0;
|
||||
cli_opts.is_subsystem = 0;
|
||||
#ifdef ENABLE_CLI_PUBKEY_AUTH
|
||||
cli_opts.privkeys = list_new();
|
||||
@@ -140,6 +145,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
cli_opts.agent_fwd = 0;
|
||||
cli_opts.agent_fd = -1;
|
||||
cli_opts.agent_keys_loaded = 0;
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_PROXYCMD
|
||||
@@ -147,6 +153,10 @@ void cli_getopts(int argc, char ** argv) {
|
||||
#endif
|
||||
#ifndef DISABLE_ZLIB
|
||||
opts.enable_compress = 1;
|
||||
#endif
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
opts.cipher_list = NULL;
|
||||
opts.mac_list = NULL;
|
||||
#endif
|
||||
/* not yet
|
||||
opts.ipv4 = 1;
|
||||
@@ -205,6 +215,10 @@ void cli_getopts(int argc, char ** argv) {
|
||||
|
||||
switch (argv[i][1]) {
|
||||
case 'y': /* always accept the remote hostkey */
|
||||
if (cli_opts.always_accept_key) {
|
||||
// twice means no checking at all
|
||||
cli_opts.no_hostkey_check = 1;
|
||||
}
|
||||
cli_opts.always_accept_key = 1;
|
||||
break;
|
||||
case 'p': /* remoteport */
|
||||
@@ -282,6 +296,14 @@ void cli_getopts(int argc, char ** argv) {
|
||||
cli_opts.agent_fwd = 1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
case 'c':
|
||||
next = &opts.cipher_list;
|
||||
break;
|
||||
case 'm':
|
||||
next = &opts.mac_list;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DEBUG_TRACE
|
||||
case 'v':
|
||||
debug_trace = 1;
|
||||
@@ -289,8 +311,10 @@ void cli_getopts(int argc, char ** argv) {
|
||||
#endif
|
||||
case 'F':
|
||||
case 'e':
|
||||
#ifndef ENABLE_USER_ALGO_LIST
|
||||
case 'c':
|
||||
case 'm':
|
||||
#endif
|
||||
case 'D':
|
||||
#ifndef ENABLE_CLI_REMOTETCPFWD
|
||||
case 'R':
|
||||
@@ -350,11 +374,22 @@ void cli_getopts(int argc, char ** argv) {
|
||||
|
||||
/* And now a few sanity checks and setup */
|
||||
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
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 */
|
||||
cli_opts.proxycmd = m_strdup(cli_opts.proxycmd);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cli_opts.remoteport == NULL) {
|
||||
cli_opts.remoteport = "22";
|
||||
}
|
||||
@@ -439,20 +474,31 @@ multihop_passthrough_args() {
|
||||
int total;
|
||||
unsigned int len = 0;
|
||||
m_list_elem *iter;
|
||||
/* Fill out -i and -W options that make sense for all
|
||||
/* Fill out -i, -y, -W options that make sense for all
|
||||
* the intermediate processes */
|
||||
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
|
||||
{
|
||||
sign_key * key = (sign_key*)iter->item;
|
||||
len += 3 + strlen(key->filename);
|
||||
}
|
||||
len += 20; // space for -W <size>, terminator.
|
||||
len += 30; // space for -W <size>, terminator.
|
||||
ret = m_malloc(len);
|
||||
total = 0;
|
||||
|
||||
if (cli_opts.no_hostkey_check)
|
||||
{
|
||||
int written = snprintf(ret+total, len-total, "-y -y ");
|
||||
total += written;
|
||||
}
|
||||
else if (cli_opts.always_accept_key)
|
||||
{
|
||||
int written = snprintf(ret+total, len-total, "-y ");
|
||||
total += written;
|
||||
}
|
||||
|
||||
if (opts.recv_window != DEFAULT_RECV_WINDOW)
|
||||
{
|
||||
int written = snprintf(ret+total, len-total, "-W %d", opts.recv_window);
|
||||
int written = snprintf(ret+total, len-total, "-W %d ", opts.recv_window);
|
||||
total += written;
|
||||
}
|
||||
|
||||
@@ -460,11 +506,17 @@ multihop_passthrough_args() {
|
||||
{
|
||||
sign_key * key = (sign_key*)iter->item;
|
||||
const size_t size = len - total;
|
||||
int written = snprintf(ret+total, size, "-i %s", key->filename);
|
||||
int written = snprintf(ret+total, size, "-i %s ", key->filename);
|
||||
dropbear_assert((unsigned int)written < size);
|
||||
total += written;
|
||||
}
|
||||
|
||||
/* if args were passed, total will be not zero, and it will have a space at the end, so remove that */
|
||||
if (total > 0)
|
||||
{
|
||||
total--;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -565,7 +617,11 @@ static void parse_hostname(const char* orighostarg) {
|
||||
cli_opts.username = m_strdup(cli_opts.own_user);
|
||||
}
|
||||
|
||||
port = strchr(cli_opts.remotehost, '/');
|
||||
port = strchr(cli_opts.remotehost, '%');
|
||||
if (!port) {
|
||||
// legacy separator
|
||||
port = strchr(cli_opts.remotehost, '/');
|
||||
}
|
||||
if (port) {
|
||||
*port = '\0';
|
||||
cli_opts.remoteport = port+1;
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2004 by Mihnea Stoenescu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "service.h"
|
||||
#include "dbutil.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "session.h"
|
||||
#include "ssh.h"
|
||||
|
||||
void send_msg_service_request(char* servicename) {
|
||||
|
||||
TRACE(("enter send_msg_service_request: servicename='%s'", servicename))
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST);
|
||||
buf_putstring(ses.writepayload, servicename, strlen(servicename));
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave send_msg_service_request"))
|
||||
}
|
||||
|
||||
/* This just sets up the state variables right for the main client session loop
|
||||
* to deal with */
|
||||
void recv_msg_service_accept() {
|
||||
|
||||
unsigned char* servicename;
|
||||
unsigned int len;
|
||||
|
||||
TRACE(("enter recv_msg_service_accept"))
|
||||
|
||||
servicename = buf_getstring(ses.payload, &len);
|
||||
|
||||
/* ssh-userauth */
|
||||
if (cli_ses.state == SERVICE_AUTH_REQ_SENT
|
||||
&& len == SSH_SERVICE_USERAUTH_LEN
|
||||
&& strncmp(SSH_SERVICE_USERAUTH, servicename, len) == 0) {
|
||||
|
||||
cli_ses.state = SERVICE_AUTH_ACCEPT_RCVD;
|
||||
m_free(servicename);
|
||||
TRACE(("leave recv_msg_service_accept: done ssh-userauth"))
|
||||
return;
|
||||
}
|
||||
|
||||
/* ssh-connection */
|
||||
if (cli_ses.state == SERVICE_CONN_REQ_SENT
|
||||
&& len == SSH_SERVICE_CONNECTION_LEN
|
||||
&& strncmp(SSH_SERVICE_CONNECTION, servicename, len) == 0) {
|
||||
|
||||
if (ses.authstate.authdone != 1) {
|
||||
dropbear_exit("Request for connection before auth");
|
||||
}
|
||||
|
||||
cli_ses.state = SERVICE_CONN_ACCEPT_RCVD;
|
||||
m_free(servicename);
|
||||
TRACE(("leave recv_msg_service_accept: done ssh-connection"))
|
||||
return;
|
||||
}
|
||||
|
||||
dropbear_exit("Unrecognised service accept");
|
||||
}
|
||||
107
cli-session.c
107
cli-session.c
@@ -41,6 +41,8 @@ static void cli_remoteclosed();
|
||||
static void cli_sessionloop();
|
||||
static void cli_session_init();
|
||||
static void cli_finished();
|
||||
static void recv_msg_service_accept(void);
|
||||
static void cli_session_cleanup(void);
|
||||
|
||||
struct clientsession cli_ses; /* GLOBAL */
|
||||
|
||||
@@ -99,7 +101,7 @@ void cli_session(int sock_in, int sock_out) {
|
||||
sessinitdone = 1;
|
||||
|
||||
/* Exchange identification */
|
||||
session_identification();
|
||||
send_session_identification();
|
||||
|
||||
send_msg_kexinit();
|
||||
|
||||
@@ -109,6 +111,12 @@ void cli_session(int sock_in, int sock_out) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_KEX_FIRST_FOLLOWS
|
||||
static void cli_send_kex_first_guess() {
|
||||
send_msg_kexdh_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void cli_session_init() {
|
||||
|
||||
cli_ses.state = STATE_NOTHING;
|
||||
@@ -133,39 +141,70 @@ static void cli_session_init() {
|
||||
cli_ses.lastprivkey = NULL;
|
||||
cli_ses.lastauthtype = 0;
|
||||
|
||||
#ifdef DROPBEAR_NONE_CIPHER
|
||||
cli_ses.cipher_none_after_auth = get_algo_usable(sshciphers, "none");
|
||||
set_algo_usable(sshciphers, "none", 0);
|
||||
#else
|
||||
cli_ses.cipher_none_after_auth = 0;
|
||||
#endif
|
||||
|
||||
/* For printing "remote host closed" for the user */
|
||||
ses.remoteclosed = cli_remoteclosed;
|
||||
ses.buf_match_algo = cli_buf_match_algo;
|
||||
|
||||
ses.extra_session_cleanup = cli_session_cleanup;
|
||||
|
||||
/* packet handlers */
|
||||
ses.packettypes = cli_packettypes;
|
||||
|
||||
ses.isserver = 0;
|
||||
|
||||
#ifdef USE_KEX_FIRST_FOLLOWS
|
||||
ses.send_kex_first_guess = cli_send_kex_first_guess;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void send_msg_service_request(char* servicename) {
|
||||
|
||||
TRACE(("enter send_msg_service_request: servicename='%s'", servicename))
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST);
|
||||
buf_putstring(ses.writepayload, servicename, strlen(servicename));
|
||||
|
||||
encrypt_packet();
|
||||
TRACE(("leave send_msg_service_request"))
|
||||
}
|
||||
|
||||
static void recv_msg_service_accept(void) {
|
||||
// do nothing, if it failed then the server MUST have disconnected
|
||||
}
|
||||
|
||||
/* This function drives the progress of the session - it initiates KEX,
|
||||
* service, userauth and channel requests */
|
||||
static void cli_sessionloop() {
|
||||
|
||||
TRACE(("enter cli_sessionloop"))
|
||||
TRACE2(("enter cli_sessionloop"))
|
||||
|
||||
if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) {
|
||||
cli_ses.kex_state = KEXINIT_RCVD;
|
||||
if (ses.lastpacket == 0) {
|
||||
TRACE2(("exit cli_sessionloop: no real packets yet"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (cli_ses.kex_state == KEXINIT_RCVD) {
|
||||
|
||||
if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) {
|
||||
/* We initiate the KEXDH. If DH wasn't the correct type, the KEXINIT
|
||||
* negotiation would have failed. */
|
||||
send_msg_kexdh_init();
|
||||
cli_ses.kex_state = KEXDH_INIT_SENT;
|
||||
if (!ses.kexstate.our_first_follows_matches) {
|
||||
send_msg_kexdh_init();
|
||||
}
|
||||
cli_ses.kex_state = KEXDH_INIT_SENT;
|
||||
TRACE(("leave cli_sessionloop: done with KEXINIT_RCVD"))
|
||||
return;
|
||||
}
|
||||
|
||||
/* A KEX has finished, so we should go back to our KEX_NOTHING state */
|
||||
if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.recvkexinit == 0
|
||||
&& ses.kexstate.sentkexinit == 0) {
|
||||
if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.sentnewkeys) {
|
||||
cli_ses.kex_state = KEX_NOTHING;
|
||||
}
|
||||
|
||||
@@ -175,10 +214,10 @@ static void cli_sessionloop() {
|
||||
return;
|
||||
}
|
||||
|
||||
/* We should exit if we haven't donefirstkex: we shouldn't reach here
|
||||
* in normal operation */
|
||||
if (ses.kexstate.donefirstkex == 0) {
|
||||
TRACE(("XXX XXX might be bad! leave cli_sessionloop: haven't donefirstkex"))
|
||||
/* We might reach here if we have partial packet reads or have
|
||||
* received SSG_MSG_IGNORE etc. Just skip it */
|
||||
TRACE2(("donefirstkex false\n"))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -188,25 +227,29 @@ static void cli_sessionloop() {
|
||||
/* We've got the transport layer sorted, we now need to request
|
||||
* userauth */
|
||||
send_msg_service_request(SSH_SERVICE_USERAUTH);
|
||||
cli_ses.state = SERVICE_AUTH_REQ_SENT;
|
||||
TRACE(("leave cli_sessionloop: sent userauth service req"))
|
||||
return;
|
||||
|
||||
/* userauth code */
|
||||
case SERVICE_AUTH_ACCEPT_RCVD:
|
||||
cli_auth_getmethods();
|
||||
cli_ses.state = USERAUTH_REQ_SENT;
|
||||
TRACE(("leave cli_sessionloop: sent userauth methods req"))
|
||||
return;
|
||||
|
||||
case USERAUTH_FAIL_RCVD:
|
||||
cli_auth_try();
|
||||
if (cli_auth_try() == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("No auth methods could be used.");
|
||||
}
|
||||
cli_ses.state = USERAUTH_REQ_SENT;
|
||||
TRACE(("leave cli_sessionloop: cli_auth_try"))
|
||||
return;
|
||||
|
||||
case USERAUTH_SUCCESS_RCVD:
|
||||
|
||||
#ifdef DROPBEAR_NONE_CIPHER
|
||||
if (cli_ses.cipher_none_after_auth)
|
||||
{
|
||||
set_algo_usable(sshciphers, "none", 1);
|
||||
send_msg_kexinit();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cli_opts.backgrounded) {
|
||||
int devnull;
|
||||
/* keeping stdin open steals input from the terminal and
|
||||
@@ -223,13 +266,6 @@ static void cli_sessionloop() {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
setup_localtcp();
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
setup_remotetcp();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CLI_NETCAT
|
||||
if (cli_opts.netcat_host) {
|
||||
cli_send_netcat_request();
|
||||
@@ -238,6 +274,14 @@ static void cli_sessionloop() {
|
||||
if (!cli_opts.no_cmd) {
|
||||
cli_send_chansess_request();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CLI_LOCALTCPFWD
|
||||
setup_localtcp();
|
||||
#endif
|
||||
#ifdef ENABLE_CLI_REMOTETCPFWD
|
||||
setup_remotetcp();
|
||||
#endif
|
||||
|
||||
TRACE(("leave cli_sessionloop: running"))
|
||||
cli_ses.state = SESSION_RUNNING;
|
||||
return;
|
||||
@@ -259,11 +303,11 @@ static void cli_sessionloop() {
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE(("leave cli_sessionloop: fell out"))
|
||||
TRACE2(("leave cli_sessionloop: fell out"))
|
||||
|
||||
}
|
||||
|
||||
void cli_session_cleanup() {
|
||||
static void cli_session_cleanup(void) {
|
||||
|
||||
if (!sessinitdone) {
|
||||
return;
|
||||
@@ -281,8 +325,7 @@ void cli_session_cleanup() {
|
||||
|
||||
static void cli_finished() {
|
||||
|
||||
cli_session_cleanup();
|
||||
common_session_cleanup();
|
||||
session_cleanup();
|
||||
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
|
||||
cli_opts.remotehost, cli_opts.remoteport);
|
||||
exit(cli_ses.retval);
|
||||
|
||||
15
cli-tcpfwd.c
15
cli-tcpfwd.c
@@ -148,15 +148,26 @@ static void send_msg_global_request_remotetcp(const char *addr, int port) {
|
||||
/* The only global success/failure messages are for remotetcp.
|
||||
* Since there isn't any identifier in these messages, we have to rely on them
|
||||
* being in the same order as we sent the requests. This is the ordering
|
||||
* of the cli_opts.remotefwds list */
|
||||
* of the cli_opts.remotefwds list.
|
||||
* If the requested remote port is 0 the listen port will be
|
||||
* dynamically allocated by the server and the port number will be returned
|
||||
* to client and the port number reported to the user. */
|
||||
void cli_recv_msg_request_success() {
|
||||
/* Nothing in the packet. We just mark off that we have received the reply,
|
||||
/* We just mark off that we have received the reply,
|
||||
* so that we can report failure for later ones. */
|
||||
m_list_elem * iter = NULL;
|
||||
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
|
||||
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
|
||||
if (!fwd->have_reply) {
|
||||
fwd->have_reply = 1;
|
||||
if (fwd->listenport == 0) {
|
||||
/* The server should let us know which port was allocated if we requestd port 0 */
|
||||
int allocport = buf_getint(ses.payload);
|
||||
if (allocport > 0) {
|
||||
dropbear_log(LOG_INFO, "Allocated port %d for remote forward to %s:%d",
|
||||
allocport, fwd->connectaddr, fwd->connectport);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
267
common-algo.c
267
common-algo.c
@@ -24,6 +24,7 @@
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "algo.h"
|
||||
#include "session.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
/* This file (algo.c) organises the ciphers which can be used, and is used to
|
||||
@@ -45,8 +46,8 @@ static int void_start(int cipher, const unsigned char *IV,
|
||||
|
||||
/* Mappings for ciphers, parameters are
|
||||
{&cipher_desc, keysize, blocksize} */
|
||||
/* NOTE: if keysize > 2*SHA1_HASH_SIZE, code such as hashkeys()
|
||||
needs revisiting */
|
||||
|
||||
/* Remember to add new ciphers/hashes to regciphers/reghashes too */
|
||||
|
||||
#ifdef DROPBEAR_AES256
|
||||
static const struct dropbear_cipher dropbear_aes256 =
|
||||
@@ -106,6 +107,14 @@ static const struct dropbear_hash dropbear_sha1 =
|
||||
static const struct dropbear_hash dropbear_sha1_96 =
|
||||
{&sha1_desc, 20, 12};
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_256_HMAC
|
||||
static const struct dropbear_hash dropbear_sha2_256 =
|
||||
{&sha256_desc, 32, 32};
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_512_HMAC
|
||||
static const struct dropbear_hash dropbear_sha2_512 =
|
||||
{&sha512_desc, 64, 64};
|
||||
#endif
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
static const struct dropbear_hash dropbear_md5 =
|
||||
{&md5_desc, 16, 16};
|
||||
@@ -151,11 +160,20 @@ algo_type sshciphers[] = {
|
||||
#endif
|
||||
#ifdef DROPBEAR_BLOWFISH
|
||||
{"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#ifdef DROPBEAR_NONE_CIPHER
|
||||
{"none", 0, (void*)&dropbear_nocipher, 1, &dropbear_mode_none},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
algo_type sshhashes[] = {
|
||||
#ifdef DROPBEAR_SHA2_256_HMAC
|
||||
{"hmac-sha2-256", 0, &dropbear_sha2_256, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_512_HMAC
|
||||
{"hmac-sha2-512", 0, &dropbear_sha2_512, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA1_96_HMAC
|
||||
{"hmac-sha1-96", 0, &dropbear_sha1_96, 1, NULL},
|
||||
#endif
|
||||
@@ -163,7 +181,10 @@ algo_type sshhashes[] = {
|
||||
{"hmac-sha1", 0, &dropbear_sha1, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
{"hmac-md5", 0, &dropbear_md5, 1, NULL},
|
||||
{"hmac-md5", 0, (void*)&dropbear_md5, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_NONE_INTEGRITY
|
||||
{"none", 0, (void*)&dropbear_nohash, 1, NULL},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
@@ -195,6 +216,9 @@ algo_type sshhostkey[] = {
|
||||
algo_type sshkex[] = {
|
||||
{"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL},
|
||||
{"diffie-hellman-group14-sha1", DROPBEAR_KEX_DH_GROUP14, NULL, 1, NULL},
|
||||
#ifdef USE_KEXGUESS2
|
||||
{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
@@ -224,6 +248,12 @@ void crypto_init() {
|
||||
&sha1_desc,
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
&md5_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_256_HMAC
|
||||
&sha256_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_512_HMAC
|
||||
&sha512_desc,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
@@ -260,8 +290,6 @@ int have_algo(char* algo, size_t algolen, algo_type algos[]) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Output a comma separated list of algorithms to a buffer */
|
||||
void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
|
||||
|
||||
@@ -282,3 +310,232 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
|
||||
buf_putstring(buf, algolist->data, algolist->len);
|
||||
buf_free(algolist);
|
||||
}
|
||||
|
||||
/* match the first algorithm in the comma-separated list in buf which is
|
||||
* also in localalgos[], or return NULL on failure.
|
||||
* (*goodguess) is set to 1 if the preferred client/server algos match,
|
||||
* 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
|
||||
* guessed correctly */
|
||||
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
enum kexguess2_used *kexguess2, int *goodguess)
|
||||
{
|
||||
|
||||
unsigned char * algolist = NULL;
|
||||
const unsigned char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
|
||||
unsigned int len;
|
||||
unsigned int remotecount, localcount, clicount, servcount, i, j;
|
||||
algo_type * ret = NULL;
|
||||
const unsigned char **clinames, **servnames;
|
||||
|
||||
if (goodguess) {
|
||||
*goodguess = 0;
|
||||
}
|
||||
|
||||
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
|
||||
algolist = buf_getstring(buf, &len);
|
||||
TRACE(("buf_match_algo: %s", algolist))
|
||||
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* remotenames will contain a list of the strings parsed out */
|
||||
/* We will have at least one string (even if it's just "") */
|
||||
remotenames[0] = algolist;
|
||||
remotecount = 1;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
goto out;
|
||||
}
|
||||
if (algolist[i] == ',') {
|
||||
algolist[i] = '\0';
|
||||
remotenames[remotecount] = &algolist[i+1];
|
||||
remotecount++;
|
||||
}
|
||||
if (remotecount >= MAX_PROPOSED_ALGO) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) {
|
||||
for (i = 0; i < remotecount; i++)
|
||||
{
|
||||
if (strcmp(remotenames[i], KEXGUESS2_ALGO_NAME) == 0) {
|
||||
*kexguess2 = KEXGUESS2_YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*kexguess2 == KEXGUESS2_LOOK) {
|
||||
*kexguess2 = KEXGUESS2_NO;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; localalgos[i].name != NULL; i++) {
|
||||
if (localalgos[i].usable) {
|
||||
localnames[i] = localalgos[i].name;
|
||||
} else {
|
||||
localnames[i] = NULL;
|
||||
}
|
||||
}
|
||||
localcount = i;
|
||||
|
||||
if (IS_DROPBEAR_SERVER) {
|
||||
clinames = remotenames;
|
||||
clicount = remotecount;
|
||||
servnames = localnames;
|
||||
servcount = localcount;
|
||||
} else {
|
||||
clinames = localnames;
|
||||
clicount = localcount;
|
||||
servnames = remotenames;
|
||||
servcount = remotecount;
|
||||
}
|
||||
|
||||
/* iterate and find the first match */
|
||||
for (i = 0; i < clicount; i++) {
|
||||
for (j = 0; j < servcount; j++) {
|
||||
if (!(servnames[j] && clinames[i])) {
|
||||
// unusable algos are NULL
|
||||
continue;
|
||||
}
|
||||
if (strcmp(servnames[j], clinames[i]) == 0) {
|
||||
/* set if it was a good guess */
|
||||
if (goodguess && kexguess2) {
|
||||
if (*kexguess2 == KEXGUESS2_YES) {
|
||||
if (i == 0) {
|
||||
*goodguess = 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (i == 0 && j == 0) {
|
||||
*goodguess = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* set the algo to return */
|
||||
if (IS_DROPBEAR_SERVER) {
|
||||
ret = &localalgos[j];
|
||||
} else {
|
||||
ret = &localalgos[i];
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
m_free(algolist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_NONE_CIPHER
|
||||
|
||||
void
|
||||
set_algo_usable(algo_type algos[], const char * algo_name, int usable)
|
||||
{
|
||||
algo_type *a;
|
||||
for (a = algos; a->name != NULL; a++)
|
||||
{
|
||||
if (strcmp(a->name, algo_name) == 0)
|
||||
{
|
||||
a->usable = usable;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
get_algo_usable(algo_type algos[], const char * algo_name)
|
||||
{
|
||||
algo_type *a;
|
||||
for (a = algos; a->name != NULL; a++)
|
||||
{
|
||||
if (strcmp(a->name, algo_name) == 0)
|
||||
{
|
||||
return a->usable;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // DROPBEAR_NONE_CIPHER
|
||||
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
|
||||
char *
|
||||
algolist_string(algo_type algos[])
|
||||
{
|
||||
char *ret_list;
|
||||
buffer *b = buf_new(200);
|
||||
buf_put_algolist(b, algos);
|
||||
buf_setpos(b, b->len);
|
||||
buf_putbyte(b, '\0');
|
||||
buf_setpos(b, 4);
|
||||
ret_list = m_strdup(buf_getptr(b, b->len - b->pos));
|
||||
buf_free(b);
|
||||
return ret_list;
|
||||
}
|
||||
|
||||
static algo_type*
|
||||
check_algo(const char* algo_name, algo_type *algos)
|
||||
{
|
||||
algo_type *a;
|
||||
for (a = algos; a->name != NULL; a++)
|
||||
{
|
||||
if (strcmp(a->name, algo_name) == 0)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
try_add_algo(const char *algo_name, algo_type *algos,
|
||||
const char *algo_desc, algo_type * new_algos, int *num_ret)
|
||||
{
|
||||
algo_type *match_algo = check_algo(algo_name, algos);
|
||||
if (!match_algo)
|
||||
{
|
||||
dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", algo_name, algo_desc);
|
||||
return;
|
||||
}
|
||||
|
||||
new_algos[*num_ret] = *match_algo;
|
||||
(*num_ret)++;
|
||||
}
|
||||
|
||||
/* Checks a user provided comma-separated algorithm list for available
|
||||
* options. Any that are not acceptable are removed in-place. Returns the
|
||||
* number of valid algorithms. */
|
||||
int
|
||||
check_user_algos(const char* user_algo_list, algo_type * algos,
|
||||
const char *algo_desc)
|
||||
{
|
||||
algo_type new_algos[MAX_PROPOSED_ALGO];
|
||||
/* this has two passes. first we sweep through the given list of
|
||||
* algorithms and mark them as usable=2 in the algo_type[] array... */
|
||||
int num_ret = 0;
|
||||
char *work_list = m_strdup(user_algo_list);
|
||||
char *last_name = work_list;
|
||||
char *c;
|
||||
for (c = work_list; *c; c++)
|
||||
{
|
||||
if (*c == ',')
|
||||
{
|
||||
*c = '\0';
|
||||
try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret);
|
||||
c++;
|
||||
last_name = c;
|
||||
}
|
||||
}
|
||||
try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret);
|
||||
m_free(work_list);
|
||||
|
||||
new_algos[num_ret].name = NULL;
|
||||
|
||||
/* Copy one more as a blank delimiter */
|
||||
memcpy(algos, new_algos, sizeof(*new_algos) * (num_ret+1));
|
||||
return num_ret;
|
||||
}
|
||||
#endif // ENABLE_USER_ALGO_LIST
|
||||
|
||||
103
common-channel.c
103
common-channel.c
@@ -48,7 +48,6 @@ static void send_msg_channel_data(struct Channel *channel, int isextended);
|
||||
static void send_msg_channel_eof(struct Channel *channel);
|
||||
static void send_msg_channel_close(struct Channel *channel);
|
||||
static void remove_channel(struct Channel *channel);
|
||||
static void delete_channel(struct Channel *channel);
|
||||
static void check_in_progress(struct Channel *channel);
|
||||
static unsigned int write_pending(struct Channel * channel);
|
||||
static void check_close(struct Channel *channel);
|
||||
@@ -93,11 +92,20 @@ void chancleanup() {
|
||||
TRACE(("leave chancleanup"))
|
||||
}
|
||||
|
||||
static void
|
||||
chan_initwritebuf(struct Channel *channel)
|
||||
{
|
||||
dropbear_assert(channel->writebuf->size == 0 && channel->recvwindow == 0);
|
||||
cbuf_free(channel->writebuf);
|
||||
channel->writebuf = cbuf_new(opts.recv_window);
|
||||
channel->recvwindow = opts.recv_window;
|
||||
}
|
||||
|
||||
/* Create a new channel entry, send a reply confirm or failure */
|
||||
/* If remotechan, transwindow and transmaxpacket are not know (for a new
|
||||
* outgoing connection, with them to be filled on confirmation), they should
|
||||
* all be set to 0 */
|
||||
struct Channel* newchannel(unsigned int remotechan,
|
||||
static struct Channel* newchannel(unsigned int remotechan,
|
||||
const struct ChanType *type,
|
||||
unsigned int transwindow, unsigned int transmaxpacket) {
|
||||
|
||||
@@ -138,6 +146,7 @@ struct Channel* newchannel(unsigned int remotechan,
|
||||
newchan->index = i;
|
||||
newchan->sent_close = newchan->recv_close = 0;
|
||||
newchan->sent_eof = newchan->recv_eof = 0;
|
||||
newchan->close_handler_done = 0;
|
||||
|
||||
newchan->remotechan = remotechan;
|
||||
newchan->transwindow = transwindow;
|
||||
@@ -151,9 +160,10 @@ struct Channel* newchannel(unsigned int remotechan,
|
||||
newchan->await_open = 0;
|
||||
newchan->flushing = 0;
|
||||
|
||||
newchan->writebuf = cbuf_new(opts.recv_window);
|
||||
newchan->writebuf = cbuf_new(0); /* resized later by chan_initwritebuf */
|
||||
newchan->recvwindow = 0;
|
||||
|
||||
newchan->extrabuf = NULL; /* The user code can set it up */
|
||||
newchan->recvwindow = opts.recv_window;
|
||||
newchan->recvdonelen = 0;
|
||||
newchan->recvmaxpacket = RECV_MAX_PAYLOAD_LEN;
|
||||
|
||||
@@ -263,14 +273,16 @@ static unsigned int write_pending(struct Channel * channel) {
|
||||
static void check_close(struct Channel *channel) {
|
||||
int close_allowed = 0;
|
||||
|
||||
TRACE(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d",
|
||||
TRACE2(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d",
|
||||
channel->writefd, channel->readfd,
|
||||
channel->errfd, channel->sent_close, channel->recv_close))
|
||||
TRACE(("writebuf size %d extrabuf size %d",
|
||||
cbuf_getused(channel->writebuf),
|
||||
TRACE2(("writebuf size %d extrabuf size %d",
|
||||
channel->writebuf ? cbuf_getused(channel->writebuf) : 0,
|
||||
channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0))
|
||||
|
||||
if (!channel->flushing && channel->type->check_close
|
||||
if (!channel->flushing
|
||||
&& !channel->close_handler_done
|
||||
&& channel->type->check_close
|
||||
&& channel->type->check_close(channel))
|
||||
{
|
||||
channel->flushing = 1;
|
||||
@@ -281,7 +293,8 @@ static void check_close(struct Channel *channel) {
|
||||
channel, to ensure that the shell has exited (and the exit status
|
||||
retrieved) before we close things up. */
|
||||
if (!channel->type->check_close
|
||||
|| channel->type->check_close(channel)) {
|
||||
|| channel->close_handler_done
|
||||
|| channel->type->check_close(channel)) {
|
||||
close_allowed = 1;
|
||||
}
|
||||
|
||||
@@ -294,7 +307,9 @@ static void check_close(struct Channel *channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel->recv_eof && !write_pending(channel)) {
|
||||
if ((channel->recv_eof && !write_pending(channel))
|
||||
/* have a server "session" and child has exited */
|
||||
|| (channel->type->check_close && close_allowed)) {
|
||||
close_chan_fd(channel, channel->writefd, SHUT_WR);
|
||||
}
|
||||
|
||||
@@ -323,6 +338,7 @@ static void check_close(struct Channel *channel) {
|
||||
|
||||
/* And if we can't receive any more data from them either, close up */
|
||||
if (channel->readfd == FD_CLOSED
|
||||
&& channel->writefd == FD_CLOSED
|
||||
&& (ERRFD_IS_WRITE(channel) || channel->errfd == FD_CLOSED)
|
||||
&& !channel->sent_close
|
||||
&& close_allowed
|
||||
@@ -348,9 +364,10 @@ static void check_in_progress(struct Channel *channel) {
|
||||
send_msg_channel_open_failure(channel->remotechan,
|
||||
SSH_OPEN_CONNECT_FAILED, "", "");
|
||||
close(channel->writefd);
|
||||
delete_channel(channel);
|
||||
remove_channel(channel);
|
||||
TRACE(("leave check_in_progress: fail"))
|
||||
} else {
|
||||
chan_initwritebuf(channel);
|
||||
send_msg_channel_open_confirmation(channel, channel->recvwindow,
|
||||
channel->recvmaxpacket);
|
||||
channel->readfd = channel->writefd;
|
||||
@@ -363,9 +380,11 @@ static void check_in_progress(struct Channel *channel) {
|
||||
/* Send the close message and set the channel as closed */
|
||||
static void send_msg_channel_close(struct Channel *channel) {
|
||||
|
||||
TRACE(("enter send_msg_channel_close"))
|
||||
if (channel->type->closehandler) {
|
||||
TRACE(("enter send_msg_channel_close %p", channel))
|
||||
if (channel->type->closehandler
|
||||
&& !channel->close_handler_done) {
|
||||
channel->type->closehandler(channel);
|
||||
channel->close_handler_done = 1;
|
||||
}
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
@@ -468,13 +487,13 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
|
||||
}
|
||||
|
||||
/* Stuff from the wire */
|
||||
if ((channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0 )
|
||||
|| channel->initconn) {
|
||||
if (channel->initconn
|
||||
||(channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0)) {
|
||||
FD_SET(channel->writefd, writefds);
|
||||
}
|
||||
|
||||
if (ERRFD_IS_WRITE(channel) && channel->errfd >= 0
|
||||
&& cbuf_getused(channel->extrabuf) > 0 ) {
|
||||
&& cbuf_getused(channel->extrabuf) > 0) {
|
||||
FD_SET(channel->errfd, writefds);
|
||||
}
|
||||
|
||||
@@ -545,22 +564,18 @@ static void remove_channel(struct Channel * channel) {
|
||||
TRACE(("CLOSE errfd %d", channel->errfd))
|
||||
close(channel->errfd);
|
||||
|
||||
channel->typedata = NULL;
|
||||
|
||||
delete_channel(channel);
|
||||
|
||||
TRACE(("leave remove_channel"))
|
||||
}
|
||||
|
||||
/* Remove a channel entry */
|
||||
static void delete_channel(struct Channel *channel) {
|
||||
if (!channel->close_handler_done
|
||||
&& channel->type->closehandler) {
|
||||
channel->type->closehandler(channel);
|
||||
channel->close_handler_done = 1;
|
||||
}
|
||||
|
||||
ses.channels[channel->index] = NULL;
|
||||
m_free(channel);
|
||||
ses.chancount--;
|
||||
|
||||
}
|
||||
|
||||
TRACE(("leave remove_channel"))
|
||||
}
|
||||
|
||||
/* Handle channel specific requests, passing off to corresponding handlers
|
||||
* such as chansession or x11fwd */
|
||||
@@ -568,16 +583,17 @@ void recv_msg_channel_request() {
|
||||
|
||||
struct Channel *channel;
|
||||
|
||||
TRACE(("enter recv_msg_channel_request"))
|
||||
|
||||
channel = getchannel();
|
||||
|
||||
TRACE(("enter recv_msg_channel_request %p", channel))
|
||||
|
||||
if (channel->sent_close) {
|
||||
TRACE(("leave recv_msg_channel_request: already closed channel"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel->type->reqhandler) {
|
||||
if (channel->type->reqhandler
|
||||
&& !channel->close_handler_done) {
|
||||
channel->type->reqhandler(channel);
|
||||
} else {
|
||||
send_msg_channel_failure(channel);
|
||||
@@ -616,7 +632,7 @@ static void send_msg_channel_data(struct Channel *channel, int isextended) {
|
||||
* exttype if is extended */
|
||||
maxlen = MIN(maxlen,
|
||||
ses.writepayload->size - 1 - 4 - 4 - (isextended ? 4 : 0));
|
||||
TRACE(("maxlen %d", maxlen))
|
||||
TRACE(("maxlen %zd", maxlen))
|
||||
if (maxlen == 0) {
|
||||
TRACE(("leave send_msg_channel_data: no window"))
|
||||
return;
|
||||
@@ -634,6 +650,7 @@ static void send_msg_channel_data(struct Channel *channel, int isextended) {
|
||||
|
||||
/* read the data */
|
||||
len = read(fd, buf_getwriteptr(ses.writepayload, maxlen), maxlen);
|
||||
|
||||
if (len <= 0) {
|
||||
if (len == 0 || errno != EINTR) {
|
||||
/* This will also get hit in the case of EAGAIN. The only
|
||||
@@ -641,11 +658,23 @@ static void send_msg_channel_data(struct Channel *channel, int isextended) {
|
||||
in which case it can be treated the same as EOF */
|
||||
close_chan_fd(channel, fd, SHUT_RD);
|
||||
}
|
||||
ses.writepayload->len = ses.writepayload->pos = 0;
|
||||
buf_setpos(ses.writepayload, 0);
|
||||
buf_setlen(ses.writepayload, 0);
|
||||
TRACE(("leave send_msg_channel_data: len %d read err %d or EOF for fd %d",
|
||||
len, errno, fd))
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel->read_mangler) {
|
||||
channel->read_mangler(channel, buf_getwriteptr(ses.writepayload, len), &len);
|
||||
if (len == 0) {
|
||||
buf_setpos(ses.writepayload, 0);
|
||||
buf_setlen(ses.writepayload, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE(("send_msg_channel_data: len %d fd %d", len, fd))
|
||||
buf_incrwritepos(ses.writepayload, len);
|
||||
/* ... real size here */
|
||||
buf_setpos(ses.writepayload, size_pos);
|
||||
@@ -691,7 +720,7 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
|
||||
dropbear_exit("Received data after eof");
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
if (fd < 0 || !cbuf) {
|
||||
/* If we have encountered failed write, the far side might still
|
||||
* be sending data without having yet received our close notification.
|
||||
* We just drop the data. */
|
||||
@@ -829,12 +858,14 @@ void recv_msg_channel_open() {
|
||||
}
|
||||
if (ret > 0) {
|
||||
errtype = ret;
|
||||
delete_channel(channel);
|
||||
remove_channel(channel);
|
||||
TRACE(("inithandler returned failure %d", ret))
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
|
||||
chan_initwritebuf(channel);
|
||||
|
||||
/* success */
|
||||
send_msg_channel_open_confirmation(channel, channel->recvwindow,
|
||||
channel->recvmaxpacket);
|
||||
@@ -973,6 +1004,10 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* Outbound opened channels don't make use of in-progress connections,
|
||||
* we can set it up straight away */
|
||||
chan_initwritebuf(chan);
|
||||
|
||||
/* set fd non-blocking */
|
||||
setnonblocking(fd);
|
||||
|
||||
|
||||
258
common-kex.c
258
common-kex.c
@@ -80,9 +80,10 @@ static const unsigned char dh_p_14[DH_P_14_LEN] = {
|
||||
static const int DH_G_VAL = 2;
|
||||
|
||||
static void kexinitialise();
|
||||
void gen_new_keys();
|
||||
static void gen_new_keys();
|
||||
#ifndef DISABLE_ZLIB
|
||||
static void gen_new_zstreams();
|
||||
static void gen_new_zstream_recv();
|
||||
static void gen_new_zstream_trans();
|
||||
#endif
|
||||
static void read_kex_algos();
|
||||
/* helper function for gen_new_keys */
|
||||
@@ -118,6 +119,7 @@ void send_msg_kexinit() {
|
||||
/* mac_algorithms_server_to_client */
|
||||
buf_put_algolist(ses.writepayload, sshhashes);
|
||||
|
||||
|
||||
/* compression_algorithms_client_to_server */
|
||||
buf_put_algolist(ses.writepayload, ses.compress_algos);
|
||||
|
||||
@@ -130,8 +132,8 @@ void send_msg_kexinit() {
|
||||
/* languages_server_to_client */
|
||||
buf_putstring(ses.writepayload, "", 0);
|
||||
|
||||
/* first_kex_packet_follows - unimplemented for now */
|
||||
buf_putbyte(ses.writepayload, 0x00);
|
||||
/* first_kex_packet_follows */
|
||||
buf_putbyte(ses.writepayload, (ses.send_kex_first_guess != NULL));
|
||||
|
||||
/* reserved unit32 */
|
||||
buf_putint(ses.writepayload, 0);
|
||||
@@ -143,16 +145,60 @@ void send_msg_kexinit() {
|
||||
encrypt_packet();
|
||||
ses.dataallowed = 0; /* don't send other packets during kex */
|
||||
|
||||
ses.kexstate.sentkexinit = 1;
|
||||
|
||||
ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
|
||||
if (ses.send_kex_first_guess) {
|
||||
ses.newkeys->algo_kex = sshkex[0].val;
|
||||
ses.newkeys->algo_hostkey = sshhostkey[0].val;
|
||||
ses.send_kex_first_guess();
|
||||
}
|
||||
|
||||
TRACE(("DATAALLOWED=0"))
|
||||
TRACE(("-> KEXINIT"))
|
||||
ses.kexstate.sentkexinit = 1;
|
||||
|
||||
}
|
||||
|
||||
/* *** NOTE regarding (send|recv)_msg_newkeys ***
|
||||
* Changed by mihnea from the original kex.c to set dataallowed after a
|
||||
* completed key exchange, no matter the order in which it was performed.
|
||||
* This enables client mode without affecting server functionality.
|
||||
*/
|
||||
static void switch_keys() {
|
||||
TRACE2(("enter switch_keys"))
|
||||
if (!(ses.kexstate.sentkexinit && ses.kexstate.recvkexinit)) {
|
||||
dropbear_exit("Unexpected newkeys message");
|
||||
}
|
||||
|
||||
if (!ses.keys) {
|
||||
ses.keys = m_malloc(sizeof(*ses.newkeys));
|
||||
}
|
||||
if (ses.kexstate.recvnewkeys && ses.newkeys->recv.valid) {
|
||||
TRACE(("switch_keys recv"))
|
||||
#ifndef DISABLE_ZLIB
|
||||
gen_new_zstream_recv();
|
||||
#endif
|
||||
ses.keys->recv = ses.newkeys->recv;
|
||||
m_burn(&ses.newkeys->recv, sizeof(ses.newkeys->recv));
|
||||
ses.newkeys->recv.valid = 0;
|
||||
}
|
||||
if (ses.kexstate.sentnewkeys && ses.newkeys->trans.valid) {
|
||||
TRACE(("switch_keys trans"))
|
||||
#ifndef DISABLE_ZLIB
|
||||
gen_new_zstream_trans();
|
||||
#endif
|
||||
ses.keys->trans = ses.newkeys->trans;
|
||||
m_burn(&ses.newkeys->trans, sizeof(ses.newkeys->trans));
|
||||
ses.newkeys->trans.valid = 0;
|
||||
}
|
||||
if (ses.kexstate.sentnewkeys && ses.kexstate.recvnewkeys)
|
||||
{
|
||||
TRACE(("switch_keys done"))
|
||||
ses.keys->algo_kex = ses.newkeys->algo_kex;
|
||||
ses.keys->algo_hostkey = ses.newkeys->algo_hostkey;
|
||||
ses.keys->allow_compress = 0;
|
||||
m_free(ses.newkeys);
|
||||
ses.newkeys = NULL;
|
||||
kexinitialise();
|
||||
}
|
||||
TRACE2(("leave switch_keys"))
|
||||
}
|
||||
|
||||
/* Bring new keys into use after a key exchange, and let the client know*/
|
||||
void send_msg_newkeys() {
|
||||
@@ -163,44 +209,25 @@ void send_msg_newkeys() {
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_NEWKEYS);
|
||||
encrypt_packet();
|
||||
|
||||
|
||||
|
||||
/* set up our state */
|
||||
if (ses.kexstate.recvnewkeys) {
|
||||
TRACE(("while RECVNEWKEYS=1"))
|
||||
gen_new_keys();
|
||||
kexinitialise(); /* we've finished with this kex */
|
||||
TRACE((" -> DATAALLOWED=1"))
|
||||
ses.dataallowed = 1; /* we can send other packets again now */
|
||||
ses.kexstate.donefirstkex = 1;
|
||||
} else {
|
||||
ses.kexstate.sentnewkeys = 1;
|
||||
TRACE(("SENTNEWKEYS=1"))
|
||||
}
|
||||
ses.kexstate.sentnewkeys = 1;
|
||||
ses.kexstate.donefirstkex = 1;
|
||||
ses.dataallowed = 1; /* we can send other packets again now */
|
||||
gen_new_keys();
|
||||
switch_keys();
|
||||
|
||||
TRACE(("-> MSG_NEWKEYS"))
|
||||
TRACE(("leave send_msg_newkeys"))
|
||||
}
|
||||
|
||||
/* Bring the new keys into use after a key exchange */
|
||||
void recv_msg_newkeys() {
|
||||
|
||||
TRACE(("<- MSG_NEWKEYS"))
|
||||
TRACE(("enter recv_msg_newkeys"))
|
||||
|
||||
/* simply check if we've sent SSH_MSG_NEWKEYS, and if so,
|
||||
* switch to the new keys */
|
||||
if (ses.kexstate.sentnewkeys) {
|
||||
TRACE(("while SENTNEWKEYS=1"))
|
||||
gen_new_keys();
|
||||
kexinitialise(); /* we've finished with this kex */
|
||||
TRACE((" -> DATAALLOWED=1"))
|
||||
ses.dataallowed = 1; /* we can send other packets again now */
|
||||
ses.kexstate.donefirstkex = 1;
|
||||
} else {
|
||||
TRACE(("RECVNEWKEYS=1"))
|
||||
ses.kexstate.recvnewkeys = 1;
|
||||
}
|
||||
ses.kexstate.recvnewkeys = 1;
|
||||
switch_keys();
|
||||
|
||||
TRACE(("leave recv_msg_newkeys"))
|
||||
}
|
||||
@@ -235,11 +262,13 @@ static void kexinitialise() {
|
||||
ses.kexstate.sentnewkeys = 0;
|
||||
|
||||
/* first_packet_follows */
|
||||
ses.kexstate.firstfollows = 0;
|
||||
ses.kexstate.them_firstfollows = 0;
|
||||
|
||||
ses.kexstate.datatrans = 0;
|
||||
ses.kexstate.datarecv = 0;
|
||||
|
||||
ses.kexstate.our_first_follows_matches = 0;
|
||||
|
||||
ses.kexstate.lastkextime = time(NULL);
|
||||
|
||||
}
|
||||
@@ -248,26 +277,28 @@ static void kexinitialise() {
|
||||
* already initialised hash_state hs, which should already have processed
|
||||
* the dh_K and hash, since these are common. X is the letter 'A', 'B' etc.
|
||||
* out must have at least min(SHA1_HASH_SIZE, outlen) bytes allocated.
|
||||
* The output will only be expanded once, as we are assured that
|
||||
* outlen <= 2*SHA1_HASH_SIZE for all known hashes.
|
||||
*
|
||||
* See Section 7.2 of rfc4253 (ssh transport) for details */
|
||||
static void hashkeys(unsigned char *out, int outlen,
|
||||
const hash_state * hs, const unsigned char X) {
|
||||
|
||||
hash_state hs2;
|
||||
unsigned char k2[SHA1_HASH_SIZE]; /* used to extending */
|
||||
int offset;
|
||||
|
||||
memcpy(&hs2, hs, sizeof(hash_state));
|
||||
sha1_process(&hs2, &X, 1);
|
||||
sha1_process(&hs2, ses.session_id, SHA1_HASH_SIZE);
|
||||
sha1_done(&hs2, out);
|
||||
if (SHA1_HASH_SIZE < outlen) {
|
||||
for (offset = SHA1_HASH_SIZE;
|
||||
offset < outlen;
|
||||
offset += SHA1_HASH_SIZE)
|
||||
{
|
||||
/* need to extend */
|
||||
unsigned char k2[SHA1_HASH_SIZE];
|
||||
memcpy(&hs2, hs, sizeof(hash_state));
|
||||
sha1_process(&hs2, out, SHA1_HASH_SIZE);
|
||||
sha1_process(&hs2, out, offset);
|
||||
sha1_done(&hs2, k2);
|
||||
memcpy(&out[SHA1_HASH_SIZE], k2, outlen - SHA1_HASH_SIZE);
|
||||
memcpy(&out[offset], k2, MIN(outlen - offset, SHA1_HASH_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,8 +309,7 @@ static void hashkeys(unsigned char *out, int outlen,
|
||||
* ses.newkeys is the new set of keys which are generated, these are only
|
||||
* taken into use after both sides have sent a newkeys message */
|
||||
|
||||
/* Originally from kex.c, generalized for cli/svr mode --mihnea */
|
||||
void gen_new_keys() {
|
||||
static void gen_new_keys() {
|
||||
|
||||
unsigned char C2S_IV[MAX_IV_LEN];
|
||||
unsigned char C2S_key[MAX_KEY_LEN];
|
||||
@@ -291,7 +321,6 @@ void gen_new_keys() {
|
||||
hash_state hs;
|
||||
unsigned int C2S_keysize, S2C_keysize;
|
||||
char mactransletter, macrecvletter; /* Client or server specific */
|
||||
int recv_cipher = 0, trans_cipher = 0;
|
||||
|
||||
TRACE(("enter gen_new_keys"))
|
||||
/* the dh_K and hash are the start of all hashes, we make use of that */
|
||||
@@ -328,43 +357,50 @@ void gen_new_keys() {
|
||||
hashkeys(C2S_key, C2S_keysize, &hs, 'C');
|
||||
hashkeys(S2C_key, S2C_keysize, &hs, 'D');
|
||||
|
||||
recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
|
||||
if (recv_cipher < 0)
|
||||
dropbear_exit("Crypto error");
|
||||
if (ses.newkeys->recv.crypt_mode->start(recv_cipher,
|
||||
recv_IV, recv_key,
|
||||
ses.newkeys->recv.algo_crypt->keysize, 0,
|
||||
&ses.newkeys->recv.cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("Crypto error");
|
||||
if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) {
|
||||
int recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
|
||||
if (recv_cipher < 0)
|
||||
dropbear_exit("Crypto error");
|
||||
if (ses.newkeys->recv.crypt_mode->start(recv_cipher,
|
||||
recv_IV, recv_key,
|
||||
ses.newkeys->recv.algo_crypt->keysize, 0,
|
||||
&ses.newkeys->recv.cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
}
|
||||
|
||||
trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
|
||||
if (trans_cipher < 0)
|
||||
dropbear_exit("Crypto error");
|
||||
if (ses.newkeys->trans.crypt_mode->start(trans_cipher,
|
||||
trans_IV, trans_key,
|
||||
ses.newkeys->trans.algo_crypt->keysize, 0,
|
||||
&ses.newkeys->trans.cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("Crypto error");
|
||||
if (ses.newkeys->trans.algo_crypt->cipherdesc != NULL) {
|
||||
int trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
|
||||
if (trans_cipher < 0)
|
||||
dropbear_exit("Crypto error");
|
||||
if (ses.newkeys->trans.crypt_mode->start(trans_cipher,
|
||||
trans_IV, trans_key,
|
||||
ses.newkeys->trans.algo_crypt->keysize, 0,
|
||||
&ses.newkeys->trans.cipher_state) != CRYPT_OK) {
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
}
|
||||
|
||||
/* MAC keys */
|
||||
hashkeys(ses.newkeys->trans.mackey,
|
||||
ses.newkeys->trans.algo_mac->keysize, &hs, mactransletter);
|
||||
hashkeys(ses.newkeys->recv.mackey,
|
||||
ses.newkeys->recv.algo_mac->keysize, &hs, macrecvletter);
|
||||
ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hashdesc->name),
|
||||
ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hashdesc->name),
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
gen_new_zstreams();
|
||||
#endif
|
||||
|
||||
/* Switch over to the new keys */
|
||||
m_burn(ses.keys, sizeof(struct key_context));
|
||||
m_free(ses.keys);
|
||||
ses.keys = ses.newkeys;
|
||||
ses.newkeys = NULL;
|
||||
if (ses.newkeys->trans.algo_mac->hashdesc != NULL) {
|
||||
hashkeys(ses.newkeys->trans.mackey,
|
||||
ses.newkeys->trans.algo_mac->keysize, &hs, mactransletter);
|
||||
ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hashdesc->name);
|
||||
}
|
||||
|
||||
if (ses.newkeys->recv.algo_mac->hashdesc != NULL) {
|
||||
hashkeys(ses.newkeys->recv.mackey,
|
||||
ses.newkeys->recv.algo_mac->keysize, &hs, macrecvletter);
|
||||
ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hashdesc->name);
|
||||
}
|
||||
|
||||
/* Ready to switch over */
|
||||
ses.newkeys->trans.valid = 1;
|
||||
ses.newkeys->recv.valid = 1;
|
||||
|
||||
m_burn(C2S_IV, sizeof(C2S_IV));
|
||||
m_burn(C2S_key, sizeof(C2S_key));
|
||||
m_burn(S2C_IV, sizeof(S2C_IV));
|
||||
m_burn(S2C_key, sizeof(S2C_key));
|
||||
|
||||
TRACE(("leave gen_new_keys"))
|
||||
}
|
||||
@@ -385,7 +421,7 @@ int is_compress_recv() {
|
||||
|
||||
/* Set up new zlib compression streams, close the old ones. Only
|
||||
* called from gen_new_keys() */
|
||||
static void gen_new_zstreams() {
|
||||
static void gen_new_zstream_recv() {
|
||||
|
||||
/* create new zstreams */
|
||||
if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|
||||
@@ -400,6 +436,17 @@ static void gen_new_zstreams() {
|
||||
} else {
|
||||
ses.newkeys->recv.zstream = NULL;
|
||||
}
|
||||
/* clean up old keys */
|
||||
if (ses.keys->recv.zstream != NULL) {
|
||||
if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
|
||||
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
m_free(ses.keys->recv.zstream);
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_new_zstream_trans() {
|
||||
|
||||
if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
@@ -417,14 +464,6 @@ static void gen_new_zstreams() {
|
||||
ses.newkeys->trans.zstream = NULL;
|
||||
}
|
||||
|
||||
/* clean up old keys */
|
||||
if (ses.keys->recv.zstream != NULL) {
|
||||
if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
|
||||
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
m_free(ses.keys->recv.zstream);
|
||||
}
|
||||
if (ses.keys->trans.zstream != NULL) {
|
||||
if (deflateEnd(ses.keys->trans.zstream) == Z_STREAM_ERROR) {
|
||||
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
|
||||
@@ -507,7 +546,7 @@ void recv_msg_kexinit() {
|
||||
buf_putstring(ses.kexhashbuf,
|
||||
ses.transkexinit->data, ses.transkexinit->len);
|
||||
|
||||
ses.requirenext = SSH_MSG_KEXDH_INIT;
|
||||
ses.requirenext[0] = SSH_MSG_KEXDH_INIT;
|
||||
}
|
||||
|
||||
buf_free(ses.transkexinit);
|
||||
@@ -540,7 +579,7 @@ void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
|
||||
DEF_MP_INT(dh_q);
|
||||
DEF_MP_INT(dh_g);
|
||||
|
||||
TRACE(("enter send_msg_kexdh_reply"))
|
||||
TRACE(("enter gen_kexdh_vals"))
|
||||
|
||||
m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL);
|
||||
|
||||
@@ -663,20 +702,27 @@ static void read_kex_algos() {
|
||||
|
||||
buf_incrpos(ses.payload, 16); /* start after the cookie */
|
||||
|
||||
ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
memset(ses.newkeys, 0x0, sizeof(*ses.newkeys));
|
||||
|
||||
#ifdef USE_KEXGUESS2
|
||||
enum kexguess2_used kexguess2 = KEXGUESS2_LOOK;
|
||||
#else
|
||||
enum kexguess2_used kexguess2 = KEXGUESS2_NO;
|
||||
#endif
|
||||
|
||||
/* kex_algorithms */
|
||||
algo = ses.buf_match_algo(ses.payload, sshkex, &goodguess);
|
||||
algo = buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess);
|
||||
allgood &= goodguess;
|
||||
if (algo == NULL) {
|
||||
if (algo == NULL || algo->val == KEXGUESS2_ALGO_ID) {
|
||||
erralgo = "kex";
|
||||
goto error;
|
||||
}
|
||||
TRACE(("kexguess2 %d", kexguess2))
|
||||
TRACE(("kex algo %s", algo->name))
|
||||
ses.newkeys->algo_kex = algo->val;
|
||||
|
||||
/* server_host_key_algorithms */
|
||||
algo = ses.buf_match_algo(ses.payload, sshhostkey, &goodguess);
|
||||
algo = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess);
|
||||
allgood &= goodguess;
|
||||
if (algo == NULL) {
|
||||
erralgo = "hostkey";
|
||||
@@ -686,7 +732,7 @@ static void read_kex_algos() {
|
||||
ses.newkeys->algo_hostkey = algo->val;
|
||||
|
||||
/* encryption_algorithms_client_to_server */
|
||||
c2s_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
|
||||
c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
|
||||
if (c2s_cipher_algo == NULL) {
|
||||
erralgo = "enc c->s";
|
||||
goto error;
|
||||
@@ -694,7 +740,7 @@ static void read_kex_algos() {
|
||||
TRACE(("enc c2s is %s", c2s_cipher_algo->name))
|
||||
|
||||
/* encryption_algorithms_server_to_client */
|
||||
s2c_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
|
||||
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
|
||||
if (s2c_cipher_algo == NULL) {
|
||||
erralgo = "enc s->c";
|
||||
goto error;
|
||||
@@ -702,7 +748,7 @@ static void read_kex_algos() {
|
||||
TRACE(("enc s2c is %s", s2c_cipher_algo->name))
|
||||
|
||||
/* mac_algorithms_client_to_server */
|
||||
c2s_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
|
||||
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
|
||||
if (c2s_hash_algo == NULL) {
|
||||
erralgo = "mac c->s";
|
||||
goto error;
|
||||
@@ -710,7 +756,7 @@ static void read_kex_algos() {
|
||||
TRACE(("hash c2s is %s", c2s_hash_algo->name))
|
||||
|
||||
/* mac_algorithms_server_to_client */
|
||||
s2c_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
|
||||
s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
|
||||
if (s2c_hash_algo == NULL) {
|
||||
erralgo = "mac s->c";
|
||||
goto error;
|
||||
@@ -718,7 +764,7 @@ static void read_kex_algos() {
|
||||
TRACE(("hash s2c is %s", s2c_hash_algo->name))
|
||||
|
||||
/* compression_algorithms_client_to_server */
|
||||
c2s_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess);
|
||||
c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
|
||||
if (c2s_comp_algo == NULL) {
|
||||
erralgo = "comp c->s";
|
||||
goto error;
|
||||
@@ -726,7 +772,7 @@ static void read_kex_algos() {
|
||||
TRACE(("hash c2s is %s", c2s_comp_algo->name))
|
||||
|
||||
/* compression_algorithms_server_to_client */
|
||||
s2c_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess);
|
||||
s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
|
||||
if (s2c_comp_algo == NULL) {
|
||||
erralgo = "comp s->c";
|
||||
goto error;
|
||||
@@ -739,9 +785,10 @@ static void read_kex_algos() {
|
||||
/* languages_server_to_client */
|
||||
buf_eatstring(ses.payload);
|
||||
|
||||
/* first_kex_packet_follows */
|
||||
/* their first_kex_packet_follows */
|
||||
if (buf_getbool(ses.payload)) {
|
||||
ses.kexstate.firstfollows = 1;
|
||||
TRACE(("them kex firstfollows. allgood %d", allgood))
|
||||
ses.kexstate.them_firstfollows = 1;
|
||||
/* if the guess wasn't good, we ignore the packet sent */
|
||||
if (!allgood) {
|
||||
ses.ignorenext = 1;
|
||||
@@ -784,6 +831,11 @@ static void read_kex_algos() {
|
||||
|
||||
/* reserved for future extensions */
|
||||
buf_getint(ses.payload);
|
||||
|
||||
if (ses.send_kex_first_guess && allgood) {
|
||||
TRACE(("our_first_follows_matches 1"))
|
||||
ses.kexstate.our_first_follows_matches = 1;
|
||||
}
|
||||
return;
|
||||
|
||||
error:
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "auth.h"
|
||||
#include "algo.h"
|
||||
#include "random.h"
|
||||
|
||||
runopts opts; /* GLOBAL */
|
||||
|
||||
@@ -44,6 +46,9 @@ int readhostkey(const char * filename, sign_key * hostkey, int *type) {
|
||||
goto out;
|
||||
}
|
||||
buf_setpos(buf, 0);
|
||||
|
||||
addrandom(buf_getptr(buf, buf->len), buf->len);
|
||||
|
||||
if (buf_get_priv_key(buf, hostkey, type) == DROPBEAR_FAILURE) {
|
||||
goto out;
|
||||
}
|
||||
@@ -55,3 +60,48 @@ out:
|
||||
buf_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
void
|
||||
parse_ciphers_macs()
|
||||
{
|
||||
if (opts.cipher_list)
|
||||
{
|
||||
if (strcmp(opts.cipher_list, "help") == 0)
|
||||
{
|
||||
char *ciphers = algolist_string(sshciphers);
|
||||
dropbear_log(LOG_INFO, "Available ciphers:\n%s\n", ciphers);
|
||||
m_free(ciphers);
|
||||
dropbear_exit(".");
|
||||
}
|
||||
|
||||
if (strcmp(opts.cipher_list, "none") == 0)
|
||||
{
|
||||
/* Encryption is required during authentication */
|
||||
opts.cipher_list = "none,aes128-ctr";
|
||||
}
|
||||
|
||||
if (check_user_algos(opts.cipher_list, sshciphers, "cipher") == 0)
|
||||
{
|
||||
dropbear_exit("No valid ciphers specified for '-c'");
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.mac_list)
|
||||
{
|
||||
if (strcmp(opts.mac_list, "help") == 0)
|
||||
{
|
||||
char *macs = algolist_string(sshhashes);
|
||||
dropbear_log(LOG_INFO, "Available MACs:\n%s\n", macs);
|
||||
m_free(macs);
|
||||
dropbear_exit(".");
|
||||
}
|
||||
|
||||
if (check_user_algos(opts.mac_list, sshhashes, "MAC") == 0)
|
||||
{
|
||||
dropbear_exit("No valid MACs specified for '-m'");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -33,12 +33,12 @@
|
||||
#include "random.h"
|
||||
#include "kex.h"
|
||||
#include "channel.h"
|
||||
#include "atomicio.h"
|
||||
#include "runopts.h"
|
||||
|
||||
static void checktimeouts();
|
||||
static long select_timeout();
|
||||
static int ident_readln(int fd, char* buf, int count);
|
||||
static void read_session_identification();
|
||||
|
||||
struct sshsession ses; /* GLOBAL */
|
||||
|
||||
@@ -49,8 +49,6 @@ int sessinitdone = 0; /* GLOBAL */
|
||||
/* this is set when we get SIGINT or SIGTERM, the handler is in main.c */
|
||||
int exitflag = 0; /* GLOBAL */
|
||||
|
||||
|
||||
|
||||
/* called only at the start of a session, set up initial state */
|
||||
void common_session_init(int sock_in, int sock_out) {
|
||||
|
||||
@@ -84,7 +82,7 @@ void common_session_init(int sock_in, int sock_out) {
|
||||
|
||||
initqueue(&ses.writequeue);
|
||||
|
||||
ses.requirenext = SSH_MSG_KEXINIT;
|
||||
ses.requirenext[0] = SSH_MSG_KEXINIT;
|
||||
ses.dataallowed = 1; /* we can send data until we actually
|
||||
send the SSH_MSG_KEXINIT */
|
||||
ses.ignorenext = 0;
|
||||
@@ -141,7 +139,10 @@ void session_loop(void(*loophandler)()) {
|
||||
FD_ZERO(&writefd);
|
||||
FD_ZERO(&readfd);
|
||||
dropbear_assert(ses.payload == NULL);
|
||||
if (ses.sock_in != -1) {
|
||||
|
||||
/* during initial setup we flush out the KEXINIT packet before
|
||||
* attempting to read the remote version string, which might block */
|
||||
if (ses.sock_in != -1 && (ses.remoteident || isempty(&ses.writequeue))) {
|
||||
FD_SET(ses.sock_in, &readfd);
|
||||
}
|
||||
if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
|
||||
@@ -195,7 +196,12 @@ void session_loop(void(*loophandler)()) {
|
||||
|
||||
if (ses.sock_in != -1) {
|
||||
if (FD_ISSET(ses.sock_in, &readfd)) {
|
||||
read_packet();
|
||||
if (!ses.remoteident) {
|
||||
/* blocking read of the version string */
|
||||
read_session_identification();
|
||||
} else {
|
||||
read_packet();
|
||||
}
|
||||
}
|
||||
|
||||
/* Process the decrypted packet. After this, the read buffer
|
||||
@@ -225,7 +231,7 @@ void session_loop(void(*loophandler)()) {
|
||||
}
|
||||
|
||||
/* clean up a session on exit */
|
||||
void common_session_cleanup() {
|
||||
void session_cleanup() {
|
||||
|
||||
TRACE(("enter session_cleanup"))
|
||||
|
||||
@@ -234,6 +240,10 @@ void common_session_cleanup() {
|
||||
TRACE(("leave session_cleanup: !sessinitdone"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (ses.extra_session_cleanup) {
|
||||
ses.extra_session_cleanup();
|
||||
}
|
||||
|
||||
m_free(ses.session_id);
|
||||
m_burn(ses.keys, sizeof(struct key_context));
|
||||
@@ -244,21 +254,20 @@ void common_session_cleanup() {
|
||||
TRACE(("leave session_cleanup"))
|
||||
}
|
||||
|
||||
void send_session_identification() {
|
||||
buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
|
||||
buf_putbytes(writebuf, LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
|
||||
buf_putbyte(writebuf, 0x0); // packet type
|
||||
buf_setpos(writebuf, 0);
|
||||
enqueue(&ses.writequeue, writebuf);
|
||||
}
|
||||
|
||||
void session_identification() {
|
||||
|
||||
static void read_session_identification() {
|
||||
/* max length of 255 chars */
|
||||
char linebuf[256];
|
||||
int len = 0;
|
||||
char done = 0;
|
||||
int i;
|
||||
|
||||
/* write our version string, this blocks */
|
||||
if (atomicio(write, ses.sock_out, LOCAL_IDENT "\r\n",
|
||||
strlen(LOCAL_IDENT "\r\n")) == DROPBEAR_FAILURE) {
|
||||
ses.remoteclosed();
|
||||
}
|
||||
|
||||
/* If they send more than 50 lines, something is wrong */
|
||||
for (i = 0; i < 50; i++) {
|
||||
len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf));
|
||||
@@ -453,6 +462,20 @@ void fill_passwd(const char* username) {
|
||||
ses.authstate.pw_name = m_strdup(pw->pw_name);
|
||||
ses.authstate.pw_dir = m_strdup(pw->pw_dir);
|
||||
ses.authstate.pw_shell = m_strdup(pw->pw_shell);
|
||||
ses.authstate.pw_passwd = m_strdup(pw->pw_passwd);
|
||||
{
|
||||
char *passwd_crypt = pw->pw_passwd;
|
||||
#ifdef HAVE_SHADOW_H
|
||||
/* get the shadow password if possible */
|
||||
struct spwd *spasswd = getspnam(ses.authstate.pw_name);
|
||||
if (spasswd && spasswd->sp_pwdp) {
|
||||
passwd_crypt = spasswd->sp_pwdp;
|
||||
}
|
||||
#endif
|
||||
if (!passwd_crypt) {
|
||||
/* android supposedly returns NULL */
|
||||
passwd_crypt = "!!";
|
||||
}
|
||||
ses.authstate.pw_passwd = m_strdup(passwd_crypt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
4
compat.c
4
compat.c
@@ -193,6 +193,10 @@ int daemon(int nochdir, int noclose) {
|
||||
char *basename(const char *path) {
|
||||
|
||||
char *foo = strrchr(path, '/');
|
||||
if (!foo)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
return ++foo;
|
||||
}
|
||||
|
||||
|
||||
601
config.guess
vendored
601
config.guess
vendored
@@ -1,14 +1,12 @@
|
||||
#! /bin/sh
|
||||
# Attempt to guess a canonical system name.
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||
# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
|
||||
# Inc.
|
||||
# Copyright 1992-2013 Free Software Foundation, Inc.
|
||||
|
||||
timestamp='2007-01-15'
|
||||
timestamp='2013-04-24'
|
||||
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
@@ -17,26 +15,22 @@ timestamp='2007-01-15'
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
|
||||
# Originally written by Per Bothner <per@bothner.com>.
|
||||
# Please send patches to <config-patches@gnu.org>. Submit a context
|
||||
# diff and a properly formatted ChangeLog entry.
|
||||
# the same distribution terms that you use for the rest of that
|
||||
# program. This Exception is an additional permission under section 7
|
||||
# of the GNU General Public License, version 3 ("GPLv3").
|
||||
#
|
||||
# This script attempts to guess a canonical system name similar to
|
||||
# config.sub. If it succeeds, it prints the system name on stdout, and
|
||||
# exits with 0. Otherwise, it exits with 1.
|
||||
# Originally written by Per Bothner.
|
||||
#
|
||||
# The plan is that this can be called by configure scripts if you
|
||||
# don't specify an explicit build system type.
|
||||
# You can get the latest version of this script from:
|
||||
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
|
||||
#
|
||||
# Please send patches with a ChangeLog entry to config-patches@gnu.org.
|
||||
|
||||
|
||||
me=`echo "$0" | sed -e 's,.*/,,'`
|
||||
|
||||
@@ -56,8 +50,7 @@ version="\
|
||||
GNU config.guess ($timestamp)
|
||||
|
||||
Originally written by Per Bothner.
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
Free Software Foundation, Inc.
|
||||
Copyright 1992-2013 Free Software Foundation, Inc.
|
||||
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
@@ -144,7 +137,7 @@ UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
|
||||
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
*:NetBSD:*:*)
|
||||
# NetBSD (nbsd) targets should (where applicable) match one or
|
||||
# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
|
||||
# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
|
||||
# *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
|
||||
# switched to ELF, *-*-netbsd* would select the old
|
||||
# object file format. This provides both forward
|
||||
@@ -170,7 +163,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
arm*|i386|m68k|ns32k|sh3*|sparc|vax)
|
||||
eval $set_cc_for_build
|
||||
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
|
||||
| grep __ELF__ >/dev/null
|
||||
| grep -q __ELF__
|
||||
then
|
||||
# Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
|
||||
# Return netbsd for either. FIX?
|
||||
@@ -180,7 +173,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
os=netbsd
|
||||
os=netbsd
|
||||
;;
|
||||
esac
|
||||
# The OS release
|
||||
@@ -201,6 +194,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
|
||||
echo "${machine}-${os}${release}"
|
||||
exit ;;
|
||||
*:Bitrig:*:*)
|
||||
UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
|
||||
echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:OpenBSD:*:*)
|
||||
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
|
||||
echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
|
||||
@@ -223,7 +220,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
|
||||
;;
|
||||
*5.*)
|
||||
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
|
||||
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
|
||||
;;
|
||||
esac
|
||||
# According to Compaq, /usr/sbin/psrinfo has been available on
|
||||
@@ -269,7 +266,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
# A Xn.n version is an unreleased experimental baselevel.
|
||||
# 1.2 uses "1.2" for uname -r.
|
||||
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
|
||||
exit ;;
|
||||
# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
|
||||
exitcode=$?
|
||||
trap '' 0
|
||||
exit $exitcode ;;
|
||||
Alpha\ *:Windows_NT*:*)
|
||||
# How do we know it's Interix rather than the generic POSIX subsystem?
|
||||
# Should we change UNAME_MACHINE based on the output of uname instead
|
||||
@@ -295,12 +295,12 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
echo s390-ibm-zvmoe
|
||||
exit ;;
|
||||
*:OS400:*:*)
|
||||
echo powerpc-ibm-os400
|
||||
echo powerpc-ibm-os400
|
||||
exit ;;
|
||||
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
|
||||
echo arm-acorn-riscix${UNAME_RELEASE}
|
||||
exit ;;
|
||||
arm:riscos:*:*|arm:RISCOS:*:*)
|
||||
arm*:riscos:*:*|arm*:RISCOS:*:*)
|
||||
echo arm-unknown-riscos
|
||||
exit ;;
|
||||
SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
|
||||
@@ -324,14 +324,33 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
case `/usr/bin/uname -p` in
|
||||
sparc) echo sparc-icl-nx7; exit ;;
|
||||
esac ;;
|
||||
s390x:SunOS:*:*)
|
||||
echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit ;;
|
||||
sun4H:SunOS:5.*:*)
|
||||
echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit ;;
|
||||
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
|
||||
echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit ;;
|
||||
i86pc:SunOS:5.*:*)
|
||||
echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
|
||||
echo i386-pc-auroraux${UNAME_RELEASE}
|
||||
exit ;;
|
||||
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
|
||||
eval $set_cc_for_build
|
||||
SUN_ARCH="i386"
|
||||
# If there is a compiler, see if it is configured for 64-bit objects.
|
||||
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
|
||||
# This test works for both compilers.
|
||||
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
|
||||
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
|
||||
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
|
||||
grep IS_64BIT_ARCH >/dev/null
|
||||
then
|
||||
SUN_ARCH="x86_64"
|
||||
fi
|
||||
fi
|
||||
echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
|
||||
exit ;;
|
||||
sun4*:SunOS:6*:*)
|
||||
# According to config.sub, this is the proper way to canonicalize
|
||||
@@ -375,23 +394,23 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
# MiNT. But MiNT is downward compatible to TOS, so this should
|
||||
# be no problem.
|
||||
atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
|
||||
echo m68k-atari-mint${UNAME_RELEASE}
|
||||
echo m68k-atari-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
|
||||
echo m68k-atari-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
exit ;;
|
||||
*falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
|
||||
echo m68k-atari-mint${UNAME_RELEASE}
|
||||
echo m68k-atari-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
|
||||
echo m68k-milan-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
echo m68k-milan-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
|
||||
echo m68k-hades-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
echo m68k-hades-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
|
||||
echo m68k-unknown-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
echo m68k-unknown-mint${UNAME_RELEASE}
|
||||
exit ;;
|
||||
m68k:machten:*:*)
|
||||
echo m68k-apple-machten${UNAME_RELEASE}
|
||||
exit ;;
|
||||
@@ -461,8 +480,8 @@ EOF
|
||||
echo m88k-motorola-sysv3
|
||||
exit ;;
|
||||
AViiON:dgux:*:*)
|
||||
# DG/UX returns AViiON for all architectures
|
||||
UNAME_PROCESSOR=`/usr/bin/uname -p`
|
||||
# DG/UX returns AViiON for all architectures
|
||||
UNAME_PROCESSOR=`/usr/bin/uname -p`
|
||||
if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
|
||||
then
|
||||
if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
|
||||
@@ -475,7 +494,7 @@ EOF
|
||||
else
|
||||
echo i586-dg-dgux${UNAME_RELEASE}
|
||||
fi
|
||||
exit ;;
|
||||
exit ;;
|
||||
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
|
||||
echo m88k-dolphin-sysv3
|
||||
exit ;;
|
||||
@@ -532,7 +551,7 @@ EOF
|
||||
echo rs6000-ibm-aix3.2
|
||||
fi
|
||||
exit ;;
|
||||
*:AIX:*:[45])
|
||||
*:AIX:*:[4567])
|
||||
IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
|
||||
if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
|
||||
IBM_ARCH=rs6000
|
||||
@@ -575,52 +594,52 @@ EOF
|
||||
9000/[678][0-9][0-9])
|
||||
if [ -x /usr/bin/getconf ]; then
|
||||
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
|
||||
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
|
||||
case "${sc_cpu_version}" in
|
||||
523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
|
||||
528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
|
||||
532) # CPU_PA_RISC2_0
|
||||
case "${sc_kernel_bits}" in
|
||||
32) HP_ARCH="hppa2.0n" ;;
|
||||
64) HP_ARCH="hppa2.0w" ;;
|
||||
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
|
||||
case "${sc_cpu_version}" in
|
||||
523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
|
||||
528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
|
||||
532) # CPU_PA_RISC2_0
|
||||
case "${sc_kernel_bits}" in
|
||||
32) HP_ARCH="hppa2.0n" ;;
|
||||
64) HP_ARCH="hppa2.0w" ;;
|
||||
'') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
|
||||
esac ;;
|
||||
esac
|
||||
esac ;;
|
||||
esac
|
||||
fi
|
||||
if [ "${HP_ARCH}" = "" ]; then
|
||||
eval $set_cc_for_build
|
||||
sed 's/^ //' << EOF >$dummy.c
|
||||
sed 's/^ //' << EOF >$dummy.c
|
||||
|
||||
#define _HPUX_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#define _HPUX_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main ()
|
||||
{
|
||||
#if defined(_SC_KERNEL_BITS)
|
||||
long bits = sysconf(_SC_KERNEL_BITS);
|
||||
#endif
|
||||
long cpu = sysconf (_SC_CPU_VERSION);
|
||||
int main ()
|
||||
{
|
||||
#if defined(_SC_KERNEL_BITS)
|
||||
long bits = sysconf(_SC_KERNEL_BITS);
|
||||
#endif
|
||||
long cpu = sysconf (_SC_CPU_VERSION);
|
||||
|
||||
switch (cpu)
|
||||
{
|
||||
case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
|
||||
case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
|
||||
case CPU_PA_RISC2_0:
|
||||
#if defined(_SC_KERNEL_BITS)
|
||||
switch (bits)
|
||||
{
|
||||
case 64: puts ("hppa2.0w"); break;
|
||||
case 32: puts ("hppa2.0n"); break;
|
||||
default: puts ("hppa2.0"); break;
|
||||
} break;
|
||||
#else /* !defined(_SC_KERNEL_BITS) */
|
||||
puts ("hppa2.0"); break;
|
||||
#endif
|
||||
default: puts ("hppa1.0"); break;
|
||||
}
|
||||
exit (0);
|
||||
}
|
||||
switch (cpu)
|
||||
{
|
||||
case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
|
||||
case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
|
||||
case CPU_PA_RISC2_0:
|
||||
#if defined(_SC_KERNEL_BITS)
|
||||
switch (bits)
|
||||
{
|
||||
case 64: puts ("hppa2.0w"); break;
|
||||
case 32: puts ("hppa2.0n"); break;
|
||||
default: puts ("hppa2.0"); break;
|
||||
} break;
|
||||
#else /* !defined(_SC_KERNEL_BITS) */
|
||||
puts ("hppa2.0"); break;
|
||||
#endif
|
||||
default: puts ("hppa1.0"); break;
|
||||
}
|
||||
exit (0);
|
||||
}
|
||||
EOF
|
||||
(CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
|
||||
test -z "$HP_ARCH" && HP_ARCH=hppa
|
||||
@@ -640,7 +659,7 @@ EOF
|
||||
# => hppa64-hp-hpux11.23
|
||||
|
||||
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
|
||||
grep __LP64__ >/dev/null
|
||||
grep -q __LP64__
|
||||
then
|
||||
HP_ARCH="hppa2.0w"
|
||||
else
|
||||
@@ -711,22 +730,22 @@ EOF
|
||||
exit ;;
|
||||
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
|
||||
echo c1-convex-bsd
|
||||
exit ;;
|
||||
exit ;;
|
||||
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
|
||||
if getsysinfo -f scalar_acc
|
||||
then echo c32-convex-bsd
|
||||
else echo c2-convex-bsd
|
||||
fi
|
||||
exit ;;
|
||||
exit ;;
|
||||
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
|
||||
echo c34-convex-bsd
|
||||
exit ;;
|
||||
exit ;;
|
||||
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
|
||||
echo c38-convex-bsd
|
||||
exit ;;
|
||||
exit ;;
|
||||
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
|
||||
echo c4-convex-bsd
|
||||
exit ;;
|
||||
exit ;;
|
||||
CRAY*Y-MP:*:*:*)
|
||||
echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
|
||||
exit ;;
|
||||
@@ -750,14 +769,14 @@ EOF
|
||||
exit ;;
|
||||
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
|
||||
FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
|
||||
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
|
||||
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
|
||||
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
|
||||
exit ;;
|
||||
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
|
||||
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
|
||||
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
|
||||
exit ;;
|
||||
5000:UNIX_System_V:4.*:*)
|
||||
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
|
||||
FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
|
||||
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
|
||||
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
|
||||
FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
|
||||
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
|
||||
exit ;;
|
||||
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
|
||||
@@ -769,37 +788,51 @@ EOF
|
||||
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:FreeBSD:*:*)
|
||||
case ${UNAME_MACHINE} in
|
||||
pc98)
|
||||
echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
|
||||
UNAME_PROCESSOR=`/usr/bin/uname -p`
|
||||
case ${UNAME_PROCESSOR} in
|
||||
amd64)
|
||||
echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
|
||||
*)
|
||||
echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
|
||||
echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
|
||||
esac
|
||||
exit ;;
|
||||
i*:CYGWIN*:*)
|
||||
echo ${UNAME_MACHINE}-pc-cygwin
|
||||
exit ;;
|
||||
*:MINGW64*:*)
|
||||
echo ${UNAME_MACHINE}-pc-mingw64
|
||||
exit ;;
|
||||
*:MINGW*:*)
|
||||
echo ${UNAME_MACHINE}-pc-mingw32
|
||||
exit ;;
|
||||
i*:MSYS*:*)
|
||||
echo ${UNAME_MACHINE}-pc-msys
|
||||
exit ;;
|
||||
i*:windows32*:*)
|
||||
# uname -m includes "-pc" on this system.
|
||||
echo ${UNAME_MACHINE}-mingw32
|
||||
# uname -m includes "-pc" on this system.
|
||||
echo ${UNAME_MACHINE}-mingw32
|
||||
exit ;;
|
||||
i*:PW*:*)
|
||||
echo ${UNAME_MACHINE}-pc-pw32
|
||||
exit ;;
|
||||
x86:Interix*:[3456]*)
|
||||
echo i586-pc-interix${UNAME_RELEASE}
|
||||
exit ;;
|
||||
EM64T:Interix*:[3456]* | authenticamd:Interix*:[3456]*)
|
||||
echo x86_64-unknown-interix${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:Interix*:*)
|
||||
case ${UNAME_MACHINE} in
|
||||
x86)
|
||||
echo i586-pc-interix${UNAME_RELEASE}
|
||||
exit ;;
|
||||
authenticamd | genuineintel | EM64T)
|
||||
echo x86_64-unknown-interix${UNAME_RELEASE}
|
||||
exit ;;
|
||||
IA64)
|
||||
echo ia64-unknown-interix${UNAME_RELEASE}
|
||||
exit ;;
|
||||
esac ;;
|
||||
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
|
||||
echo i${UNAME_MACHINE}-pc-mks
|
||||
exit ;;
|
||||
8664:Windows_NT:*)
|
||||
echo x86_64-pc-mks
|
||||
exit ;;
|
||||
i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
|
||||
# How do we know it's Interix rather than the generic POSIX subsystem?
|
||||
# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
|
||||
@@ -829,85 +862,13 @@ EOF
|
||||
i*86:Minix:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-minix
|
||||
exit ;;
|
||||
arm*:Linux:*:*)
|
||||
aarch64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
avr32*:Linux:*:*)
|
||||
aarch64_be:Linux:*:*)
|
||||
UNAME_MACHINE=aarch64_be
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
cris:Linux:*:*)
|
||||
echo cris-axis-linux-gnu
|
||||
exit ;;
|
||||
crisv32:Linux:*:*)
|
||||
echo crisv32-axis-linux-gnu
|
||||
exit ;;
|
||||
frv:Linux:*:*)
|
||||
echo frv-unknown-linux-gnu
|
||||
exit ;;
|
||||
ia64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
m32r*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
m68*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
mips:Linux:*:*)
|
||||
eval $set_cc_for_build
|
||||
sed 's/^ //' << EOF >$dummy.c
|
||||
#undef CPU
|
||||
#undef mips
|
||||
#undef mipsel
|
||||
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
|
||||
CPU=mipsel
|
||||
#else
|
||||
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
|
||||
CPU=mips
|
||||
#else
|
||||
CPU=
|
||||
#endif
|
||||
#endif
|
||||
EOF
|
||||
eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
|
||||
/^CPU/{
|
||||
s: ::g
|
||||
p
|
||||
}'`"
|
||||
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
|
||||
;;
|
||||
mips64:Linux:*:*)
|
||||
eval $set_cc_for_build
|
||||
sed 's/^ //' << EOF >$dummy.c
|
||||
#undef CPU
|
||||
#undef mips64
|
||||
#undef mips64el
|
||||
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
|
||||
CPU=mips64el
|
||||
#else
|
||||
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
|
||||
CPU=mips64
|
||||
#else
|
||||
CPU=
|
||||
#endif
|
||||
#endif
|
||||
EOF
|
||||
eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
|
||||
/^CPU/{
|
||||
s: ::g
|
||||
p
|
||||
}'`"
|
||||
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
|
||||
;;
|
||||
or32:Linux:*:*)
|
||||
echo or32-unknown-linux-gnu
|
||||
exit ;;
|
||||
ppc:Linux:*:*)
|
||||
echo powerpc-unknown-linux-gnu
|
||||
exit ;;
|
||||
ppc64:Linux:*:*)
|
||||
echo powerpc64-unknown-linux-gnu
|
||||
exit ;;
|
||||
alpha:Linux:*:*)
|
||||
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
|
||||
EV5) UNAME_MACHINE=alphaev5 ;;
|
||||
@@ -917,11 +878,101 @@ EOF
|
||||
EV6) UNAME_MACHINE=alphaev6 ;;
|
||||
EV67) UNAME_MACHINE=alphaev67 ;;
|
||||
EV68*) UNAME_MACHINE=alphaev68 ;;
|
||||
esac
|
||||
objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
|
||||
esac
|
||||
objdump --private-headers /bin/sh | grep -q ld.so.1
|
||||
if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
|
||||
exit ;;
|
||||
arc:Linux:*:* | arceb:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
arm*:Linux:*:*)
|
||||
eval $set_cc_for_build
|
||||
if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
|
||||
| grep -q __ARM_EABI__
|
||||
then
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
else
|
||||
if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
|
||||
| grep -q __ARM_PCS_VFP
|
||||
then
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnueabi
|
||||
else
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnueabihf
|
||||
fi
|
||||
fi
|
||||
exit ;;
|
||||
avr32*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
cris:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-axis-linux-gnu
|
||||
exit ;;
|
||||
crisv32:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-axis-linux-gnu
|
||||
exit ;;
|
||||
frv:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
hexagon:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
i*86:Linux:*:*)
|
||||
LIBC=gnu
|
||||
eval $set_cc_for_build
|
||||
sed 's/^ //' << EOF >$dummy.c
|
||||
#ifdef __dietlibc__
|
||||
LIBC=dietlibc
|
||||
#endif
|
||||
#else
|
||||
#include <features.h>
|
||||
#ifdef __UCLIBC__
|
||||
LIBC=uclibc
|
||||
#endif
|
||||
EOF
|
||||
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
|
||||
echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
|
||||
exit ;;
|
||||
ia64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
m32r*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
m68*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
mips:Linux:*:* | mips64:Linux:*:*)
|
||||
eval $set_cc_for_build
|
||||
sed 's/^ //' << EOF >$dummy.c
|
||||
#undef CPU
|
||||
#undef ${UNAME_MACHINE}
|
||||
#undef ${UNAME_MACHINE}el
|
||||
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
|
||||
CPU=${UNAME_MACHINE}el
|
||||
#else
|
||||
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
|
||||
CPU=${UNAME_MACHINE}
|
||||
#else
|
||||
CPU=
|
||||
#endif
|
||||
#endif
|
||||
EOF
|
||||
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
|
||||
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
|
||||
;;
|
||||
or1k:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
or32:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
padre:Linux:*:*)
|
||||
echo sparc-unknown-linux-gnu
|
||||
exit ;;
|
||||
parisc64:Linux:*:* | hppa64:Linux:*:*)
|
||||
echo hppa64-unknown-linux-gnu
|
||||
exit ;;
|
||||
parisc:Linux:*:* | hppa:Linux:*:*)
|
||||
# Look for CPU level
|
||||
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
|
||||
@@ -930,14 +981,17 @@ EOF
|
||||
*) echo hppa-unknown-linux-gnu ;;
|
||||
esac
|
||||
exit ;;
|
||||
parisc64:Linux:*:* | hppa64:Linux:*:*)
|
||||
echo hppa64-unknown-linux-gnu
|
||||
ppc64:Linux:*:*)
|
||||
echo powerpc64-unknown-linux-gnu
|
||||
exit ;;
|
||||
ppc:Linux:*:*)
|
||||
echo powerpc-unknown-linux-gnu
|
||||
exit ;;
|
||||
s390:Linux:*:* | s390x:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-ibm-linux
|
||||
exit ;;
|
||||
sh64*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
sh*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
@@ -945,78 +999,20 @@ EOF
|
||||
sparc:Linux:*:* | sparc64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
tile*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
vax:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-dec-linux-gnu
|
||||
exit ;;
|
||||
x86_64:Linux:*:*)
|
||||
echo x86_64-unknown-linux-gnu
|
||||
exit ;;
|
||||
xtensa:Linux:*:*)
|
||||
echo xtensa-unknown-linux-gnu
|
||||
exit ;;
|
||||
i*86:Linux:*:*)
|
||||
# The BFD linker knows what the default object file format is, so
|
||||
# first see if it will tell us. cd to the root directory to prevent
|
||||
# problems with other programs or directories called `ld' in the path.
|
||||
# Set LC_ALL=C to ensure ld outputs messages in English.
|
||||
ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
|
||||
| sed -ne '/supported targets:/!d
|
||||
s/[ ][ ]*/ /g
|
||||
s/.*supported targets: *//
|
||||
s/ .*//
|
||||
p'`
|
||||
case "$ld_supported_targets" in
|
||||
elf32-i386)
|
||||
TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
|
||||
;;
|
||||
a.out-i386-linux)
|
||||
echo "${UNAME_MACHINE}-pc-linux-gnuaout"
|
||||
exit ;;
|
||||
coff-i386)
|
||||
echo "${UNAME_MACHINE}-pc-linux-gnucoff"
|
||||
exit ;;
|
||||
"")
|
||||
# Either a pre-BFD a.out linker (linux-gnuoldld) or
|
||||
# one that does not give us useful --help.
|
||||
echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
|
||||
exit ;;
|
||||
esac
|
||||
# Determine whether the default compiler is a.out or elf
|
||||
eval $set_cc_for_build
|
||||
sed 's/^ //' << EOF >$dummy.c
|
||||
#include <features.h>
|
||||
#ifdef __ELF__
|
||||
# ifdef __GLIBC__
|
||||
# if __GLIBC__ >= 2
|
||||
LIBC=gnu
|
||||
# else
|
||||
LIBC=gnulibc1
|
||||
# endif
|
||||
# else
|
||||
LIBC=gnulibc1
|
||||
# endif
|
||||
#else
|
||||
#if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
||||
LIBC=gnu
|
||||
#else
|
||||
LIBC=gnuaout
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __dietlibc__
|
||||
LIBC=dietlibc
|
||||
#endif
|
||||
EOF
|
||||
eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
|
||||
/^LIBC/{
|
||||
s: ::g
|
||||
p
|
||||
}'`"
|
||||
test x"${LIBC}" != x && {
|
||||
echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
|
||||
exit
|
||||
}
|
||||
test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
|
||||
;;
|
||||
test -r /lib/libc.so && od -An -S13 /lib/libc.so | grep -q __uClibc_main && LIBC=uclibc
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
xtensa*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
i*86:DYNIX/ptx:4*:*)
|
||||
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
|
||||
# earlier versions are messed up and put the nodename in both
|
||||
@@ -1024,11 +1020,11 @@ EOF
|
||||
echo i386-sequent-sysv4
|
||||
exit ;;
|
||||
i*86:UNIX_SV:4.2MP:2.*)
|
||||
# Unixware is an offshoot of SVR4, but it has its own version
|
||||
# number series starting with 2...
|
||||
# I am not positive that other SVR4 systems won't match this,
|
||||
# Unixware is an offshoot of SVR4, but it has its own version
|
||||
# number series starting with 2...
|
||||
# I am not positive that other SVR4 systems won't match this,
|
||||
# I just have to hope. -- rms.
|
||||
# Use sysv4.2uw... so that sysv4* matches it.
|
||||
# Use sysv4.2uw... so that sysv4* matches it.
|
||||
echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
|
||||
exit ;;
|
||||
i*86:OS/2:*:*)
|
||||
@@ -1045,7 +1041,7 @@ EOF
|
||||
i*86:syllable:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-syllable
|
||||
exit ;;
|
||||
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
|
||||
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
|
||||
echo i386-unknown-lynxos${UNAME_RELEASE}
|
||||
exit ;;
|
||||
i*86:*DOS:*:*)
|
||||
@@ -1060,7 +1056,7 @@ EOF
|
||||
fi
|
||||
exit ;;
|
||||
i*86:*:5:[678]*)
|
||||
# UnixWare 7.x, OpenUNIX and OpenServer 6.
|
||||
# UnixWare 7.x, OpenUNIX and OpenServer 6.
|
||||
case `/bin/uname -X | grep "^Machine"` in
|
||||
*486*) UNAME_MACHINE=i486 ;;
|
||||
*Pentium) UNAME_MACHINE=i586 ;;
|
||||
@@ -1088,10 +1084,13 @@ EOF
|
||||
exit ;;
|
||||
pc:*:*:*)
|
||||
# Left here for compatibility:
|
||||
# uname -m prints for DJGPP always 'pc', but it prints nothing about
|
||||
# the processor, so we play safe by assuming i386.
|
||||
echo i386-pc-msdosdjgpp
|
||||
exit ;;
|
||||
# uname -m prints for DJGPP always 'pc', but it prints nothing about
|
||||
# the processor, so we play safe by assuming i586.
|
||||
# Note: whatever this is, it MUST be the same as what config.sub
|
||||
# prints for the "djgpp" host, or else GDB configury will decide that
|
||||
# this is a cross-build.
|
||||
echo i586-pc-msdosdjgpp
|
||||
exit ;;
|
||||
Intel:Mach:3*:*)
|
||||
echo i386-pc-mach3
|
||||
exit ;;
|
||||
@@ -1126,8 +1125,18 @@ EOF
|
||||
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
|
||||
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
|
||||
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
|
||||
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
|
||||
&& { echo i486-ncr-sysv4; exit; } ;;
|
||||
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
|
||||
&& { echo i486-ncr-sysv4; exit; } ;;
|
||||
NCR*:*:4.2:* | MPRAS*:*:4.2:*)
|
||||
OS_REL='.3'
|
||||
test -r /etc/.relid \
|
||||
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
|
||||
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
|
||||
&& { echo i486-ncr-sysv4.3${OS_REL}; exit; }
|
||||
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
|
||||
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; }
|
||||
/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
|
||||
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
|
||||
m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
|
||||
echo m68k-unknown-lynxos${UNAME_RELEASE}
|
||||
exit ;;
|
||||
@@ -1140,7 +1149,7 @@ EOF
|
||||
rs6000:LynxOS:2.*:*)
|
||||
echo rs6000-unknown-lynxos${UNAME_RELEASE}
|
||||
exit ;;
|
||||
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
|
||||
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
|
||||
echo powerpc-unknown-lynxos${UNAME_RELEASE}
|
||||
exit ;;
|
||||
SM[BE]S:UNIX_SV:*:*)
|
||||
@@ -1160,10 +1169,10 @@ EOF
|
||||
echo ns32k-sni-sysv
|
||||
fi
|
||||
exit ;;
|
||||
PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
|
||||
# says <Richard.M.Bartel@ccMail.Census.GOV>
|
||||
echo i586-unisys-sysv4
|
||||
exit ;;
|
||||
PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
|
||||
# says <Richard.M.Bartel@ccMail.Census.GOV>
|
||||
echo i586-unisys-sysv4
|
||||
exit ;;
|
||||
*:UNIX_System_V:4*:FTX*)
|
||||
# From Gerald Hewes <hewes@openmarket.com>.
|
||||
# How about differentiating between stratus architectures? -djm
|
||||
@@ -1189,11 +1198,11 @@ EOF
|
||||
exit ;;
|
||||
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
|
||||
if [ -d /usr/nec ]; then
|
||||
echo mips-nec-sysv${UNAME_RELEASE}
|
||||
echo mips-nec-sysv${UNAME_RELEASE}
|
||||
else
|
||||
echo mips-unknown-sysv${UNAME_RELEASE}
|
||||
echo mips-unknown-sysv${UNAME_RELEASE}
|
||||
fi
|
||||
exit ;;
|
||||
exit ;;
|
||||
BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
|
||||
echo powerpc-be-beos
|
||||
exit ;;
|
||||
@@ -1203,6 +1212,12 @@ EOF
|
||||
BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
|
||||
echo i586-pc-beos
|
||||
exit ;;
|
||||
BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
|
||||
echo i586-pc-haiku
|
||||
exit ;;
|
||||
x86_64:Haiku:*:*)
|
||||
echo x86_64-unknown-haiku
|
||||
exit ;;
|
||||
SX-4:SUPER-UX:*:*)
|
||||
echo sx4-nec-superux${UNAME_RELEASE}
|
||||
exit ;;
|
||||
@@ -1230,6 +1245,16 @@ EOF
|
||||
*:Darwin:*:*)
|
||||
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
|
||||
case $UNAME_PROCESSOR in
|
||||
i386)
|
||||
eval $set_cc_for_build
|
||||
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
|
||||
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
|
||||
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
|
||||
grep IS_64BIT_ARCH >/dev/null
|
||||
then
|
||||
UNAME_PROCESSOR="x86_64"
|
||||
fi
|
||||
fi ;;
|
||||
unknown) UNAME_PROCESSOR=powerpc ;;
|
||||
esac
|
||||
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
|
||||
@@ -1245,7 +1270,10 @@ EOF
|
||||
*:QNX:*:4*)
|
||||
echo i386-pc-qnx
|
||||
exit ;;
|
||||
NSE-?:NONSTOP_KERNEL:*:*)
|
||||
NEO-?:NONSTOP_KERNEL:*:*)
|
||||
echo neo-tandem-nsk${UNAME_RELEASE}
|
||||
exit ;;
|
||||
NSE-*:NONSTOP_KERNEL:*:*)
|
||||
echo nse-tandem-nsk${UNAME_RELEASE}
|
||||
exit ;;
|
||||
NSR-?:NONSTOP_KERNEL:*:*)
|
||||
@@ -1290,13 +1318,13 @@ EOF
|
||||
echo pdp10-unknown-its
|
||||
exit ;;
|
||||
SEI:*:*:SEIUX)
|
||||
echo mips-sei-seiux${UNAME_RELEASE}
|
||||
echo mips-sei-seiux${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:DragonFly:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
|
||||
exit ;;
|
||||
*:*VMS:*:*)
|
||||
UNAME_MACHINE=`(uname -p) 2>/dev/null`
|
||||
UNAME_MACHINE=`(uname -p) 2>/dev/null`
|
||||
case "${UNAME_MACHINE}" in
|
||||
A*) echo alpha-dec-vms ; exit ;;
|
||||
I*) echo ia64-dec-vms ; exit ;;
|
||||
@@ -1311,11 +1339,14 @@ EOF
|
||||
i*86:rdos:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-rdos
|
||||
exit ;;
|
||||
i*86:AROS:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-aros
|
||||
exit ;;
|
||||
x86_64:VMkernel:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-esx
|
||||
exit ;;
|
||||
esac
|
||||
|
||||
#echo '(No uname command or uname output not recognized.)' 1>&2
|
||||
#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
|
||||
|
||||
eval $set_cc_for_build
|
||||
cat >$dummy.c <<EOF
|
||||
#ifdef _SEQUENT_
|
||||
@@ -1333,11 +1364,11 @@ main ()
|
||||
#include <sys/param.h>
|
||||
printf ("m68k-sony-newsos%s\n",
|
||||
#ifdef NEWSOS4
|
||||
"4"
|
||||
"4"
|
||||
#else
|
||||
""
|
||||
""
|
||||
#endif
|
||||
); exit (0);
|
||||
); exit (0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1471,9 +1502,9 @@ This script, last modified $timestamp, has failed to recognize
|
||||
the operating system you are using. It is advised that you
|
||||
download the most up to date version of the config scripts from
|
||||
|
||||
http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
|
||||
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
|
||||
and
|
||||
http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
|
||||
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
|
||||
|
||||
If the version you run ($0) is already up to date, please
|
||||
send the following data and any information you think might be
|
||||
|
||||
368
config.sub
vendored
368
config.sub
vendored
@@ -1,44 +1,40 @@
|
||||
#! /bin/sh
|
||||
# Configuration validation subroutine script.
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||
# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
|
||||
# Inc.
|
||||
# Copyright 1992-2013 Free Software Foundation, Inc.
|
||||
|
||||
timestamp='2007-01-18'
|
||||
timestamp='2013-04-24'
|
||||
|
||||
# This file is (in principle) common to ALL GNU software.
|
||||
# The presence of a machine in this file suggests that SOME GNU software
|
||||
# can handle that machine. It does not imply ALL GNU software can.
|
||||
#
|
||||
# This file is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
# the same distribution terms that you use for the rest of that
|
||||
# program. This Exception is an additional permission under section 7
|
||||
# of the GNU General Public License, version 3 ("GPLv3").
|
||||
|
||||
|
||||
# Please send patches to <config-patches@gnu.org>. Submit a context
|
||||
# diff and a properly formatted ChangeLog entry.
|
||||
# Please send patches with a ChangeLog entry to config-patches@gnu.org.
|
||||
#
|
||||
# Configuration subroutine to validate and canonicalize a configuration type.
|
||||
# Supply the specified configuration type as an argument.
|
||||
# If it is invalid, we print an error message on stderr and exit with code 1.
|
||||
# Otherwise, we print the canonical config type on stdout and succeed.
|
||||
|
||||
# You can get the latest version of this script from:
|
||||
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
|
||||
|
||||
# This file is supposed to be the same for all GNU packages
|
||||
# and recognize all the CPU types, system types and aliases
|
||||
# that are meaningful with *any* GNU software.
|
||||
@@ -72,8 +68,7 @@ Report bugs and patches to <config-patches@gnu.org>."
|
||||
version="\
|
||||
GNU config.sub ($timestamp)
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
Free Software Foundation, Inc.
|
||||
Copyright 1992-2013 Free Software Foundation, Inc.
|
||||
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
@@ -120,12 +115,18 @@ esac
|
||||
# Here we must recognize all the valid KERNEL-OS combinations.
|
||||
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
|
||||
case $maybe_os in
|
||||
nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
|
||||
uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
|
||||
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
|
||||
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
|
||||
knetbsd*-gnu* | netbsd*-gnu* | \
|
||||
kopensolaris*-gnu* | \
|
||||
storm-chaos* | os2-emx* | rtmk-nova*)
|
||||
os=-$maybe_os
|
||||
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
|
||||
;;
|
||||
android-linux)
|
||||
os=-linux-android
|
||||
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
|
||||
;;
|
||||
*)
|
||||
basic_machine=`echo $1 | sed 's/-[^-]*$//'`
|
||||
if [ $basic_machine != $1 ]
|
||||
@@ -148,10 +149,13 @@ case $os in
|
||||
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
|
||||
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
|
||||
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
|
||||
-apple | -axis | -knuth | -cray)
|
||||
-apple | -axis | -knuth | -cray | -microblaze*)
|
||||
os=
|
||||
basic_machine=$1
|
||||
;;
|
||||
-bluegene*)
|
||||
os=-cnk
|
||||
;;
|
||||
-sim | -cisco | -oki | -wec | -winbond)
|
||||
os=
|
||||
basic_machine=$1
|
||||
@@ -166,10 +170,10 @@ case $os in
|
||||
os=-chorusos
|
||||
basic_machine=$1
|
||||
;;
|
||||
-chorusrdb)
|
||||
os=-chorusrdb
|
||||
-chorusrdb)
|
||||
os=-chorusrdb
|
||||
basic_machine=$1
|
||||
;;
|
||||
;;
|
||||
-hiux*)
|
||||
os=-hiuxwe2
|
||||
;;
|
||||
@@ -214,6 +218,12 @@ case $os in
|
||||
-isc*)
|
||||
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
|
||||
;;
|
||||
-lynx*178)
|
||||
os=-lynxos178
|
||||
;;
|
||||
-lynx*5)
|
||||
os=-lynxos5
|
||||
;;
|
||||
-lynx*)
|
||||
os=-lynxos
|
||||
;;
|
||||
@@ -238,24 +248,34 @@ case $basic_machine in
|
||||
# Some are omitted here because they have special meanings below.
|
||||
1750a | 580 \
|
||||
| a29k \
|
||||
| aarch64 | aarch64_be \
|
||||
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
|
||||
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
|
||||
| am33_2.0 \
|
||||
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
|
||||
| arc | arceb \
|
||||
| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
|
||||
| avr | avr32 \
|
||||
| be32 | be64 \
|
||||
| bfin \
|
||||
| c4x | clipper \
|
||||
| d10v | d30v | dlx | dsp16xx \
|
||||
| epiphany \
|
||||
| fido | fr30 | frv \
|
||||
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
|
||||
| hexagon \
|
||||
| i370 | i860 | i960 | ia64 \
|
||||
| ip2k | iq2000 \
|
||||
| le32 | le64 \
|
||||
| lm32 \
|
||||
| m32c | m32r | m32rle | m68000 | m68k | m88k \
|
||||
| maxq | mb | microblaze | mcore | mep \
|
||||
| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
|
||||
| mips | mipsbe | mipseb | mipsel | mipsle \
|
||||
| mips16 \
|
||||
| mips64 | mips64el \
|
||||
| mips64vr | mips64vrel \
|
||||
| mips64octeon | mips64octeonel \
|
||||
| mips64orion | mips64orionel \
|
||||
| mips64r5900 | mips64r5900el \
|
||||
| mips64vr | mips64vrel \
|
||||
| mips64vr4100 | mips64vr4100el \
|
||||
| mips64vr4300 | mips64vr4300el \
|
||||
| mips64vr5000 | mips64vr5000el \
|
||||
@@ -266,31 +286,45 @@ case $basic_machine in
|
||||
| mipsisa64r2 | mipsisa64r2el \
|
||||
| mipsisa64sb1 | mipsisa64sb1el \
|
||||
| mipsisa64sr71k | mipsisa64sr71kel \
|
||||
| mipsr5900 | mipsr5900el \
|
||||
| mipstx39 | mipstx39el \
|
||||
| mn10200 | mn10300 \
|
||||
| moxie \
|
||||
| mt \
|
||||
| msp430 \
|
||||
| nios | nios2 \
|
||||
| nds32 | nds32le | nds32be \
|
||||
| nios | nios2 | nios2eb | nios2el \
|
||||
| ns16k | ns32k \
|
||||
| or32 \
|
||||
| open8 \
|
||||
| or1k | or32 \
|
||||
| pdp10 | pdp11 | pj | pjl \
|
||||
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
|
||||
| powerpc | powerpc64 | powerpc64le | powerpcle \
|
||||
| pyramid \
|
||||
| rl78 | rx \
|
||||
| score \
|
||||
| sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
|
||||
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
|
||||
| sh64 | sh64le \
|
||||
| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
|
||||
| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
|
||||
| spu | strongarm \
|
||||
| tahoe | thumb | tic4x | tic80 | tron \
|
||||
| v850 | v850e \
|
||||
| spu \
|
||||
| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
|
||||
| ubicom32 \
|
||||
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
|
||||
| we32k \
|
||||
| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
|
||||
| z8k)
|
||||
| x86 | xc16x | xstormy16 | xtensa \
|
||||
| z8k | z80)
|
||||
basic_machine=$basic_machine-unknown
|
||||
;;
|
||||
m6811 | m68hc11 | m6812 | m68hc12)
|
||||
# Motorola 68HC11/12.
|
||||
c54x)
|
||||
basic_machine=tic54x-unknown
|
||||
;;
|
||||
c55x)
|
||||
basic_machine=tic55x-unknown
|
||||
;;
|
||||
c6x)
|
||||
basic_machine=tic6x-unknown
|
||||
;;
|
||||
m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
|
||||
basic_machine=$basic_machine-unknown
|
||||
os=-none
|
||||
;;
|
||||
@@ -300,6 +334,21 @@ case $basic_machine in
|
||||
basic_machine=mt-unknown
|
||||
;;
|
||||
|
||||
strongarm | thumb | xscale)
|
||||
basic_machine=arm-unknown
|
||||
;;
|
||||
xgate)
|
||||
basic_machine=$basic_machine-unknown
|
||||
os=-none
|
||||
;;
|
||||
xscaleeb)
|
||||
basic_machine=armeb-unknown
|
||||
;;
|
||||
|
||||
xscaleel)
|
||||
basic_machine=armel-unknown
|
||||
;;
|
||||
|
||||
# We use `pc' rather than `unknown'
|
||||
# because (1) that's what they normally are, and
|
||||
# (2) the word "unknown" tends to confuse beginning users.
|
||||
@@ -314,29 +363,37 @@ case $basic_machine in
|
||||
# Recognize the basic CPU types with company name.
|
||||
580-* \
|
||||
| a29k-* \
|
||||
| aarch64-* | aarch64_be-* \
|
||||
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
|
||||
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
|
||||
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
|
||||
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
|
||||
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
|
||||
| avr-* | avr32-* \
|
||||
| be32-* | be64-* \
|
||||
| bfin-* | bs2000-* \
|
||||
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
|
||||
| c[123]* | c30-* | [cjt]90-* | c4x-* \
|
||||
| clipper-* | craynv-* | cydra-* \
|
||||
| d10v-* | d30v-* | dlx-* \
|
||||
| elxsi-* \
|
||||
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
|
||||
| h8300-* | h8500-* \
|
||||
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
|
||||
| hexagon-* \
|
||||
| i*86-* | i860-* | i960-* | ia64-* \
|
||||
| ip2k-* | iq2000-* \
|
||||
| le32-* | le64-* \
|
||||
| lm32-* \
|
||||
| m32c-* | m32r-* | m32rle-* \
|
||||
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
|
||||
| m88110-* | m88k-* | maxq-* | mcore-* \
|
||||
| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
|
||||
| microblaze-* | microblazeel-* \
|
||||
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
|
||||
| mips16-* \
|
||||
| mips64-* | mips64el-* \
|
||||
| mips64vr-* | mips64vrel-* \
|
||||
| mips64octeon-* | mips64octeonel-* \
|
||||
| mips64orion-* | mips64orionel-* \
|
||||
| mips64r5900-* | mips64r5900el-* \
|
||||
| mips64vr-* | mips64vrel-* \
|
||||
| mips64vr4100-* | mips64vr4100el-* \
|
||||
| mips64vr4300-* | mips64vr4300el-* \
|
||||
| mips64vr5000-* | mips64vr5000el-* \
|
||||
@@ -347,31 +404,41 @@ case $basic_machine in
|
||||
| mipsisa64r2-* | mipsisa64r2el-* \
|
||||
| mipsisa64sb1-* | mipsisa64sb1el-* \
|
||||
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
|
||||
| mipsr5900-* | mipsr5900el-* \
|
||||
| mipstx39-* | mipstx39el-* \
|
||||
| mmix-* \
|
||||
| mt-* \
|
||||
| msp430-* \
|
||||
| nios-* | nios2-* \
|
||||
| nds32-* | nds32le-* | nds32be-* \
|
||||
| nios-* | nios2-* | nios2eb-* | nios2el-* \
|
||||
| none-* | np1-* | ns16k-* | ns32k-* \
|
||||
| open8-* \
|
||||
| orion-* \
|
||||
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
|
||||
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
|
||||
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
|
||||
| pyramid-* \
|
||||
| romp-* | rs6000-* \
|
||||
| sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
|
||||
| rl78-* | romp-* | rs6000-* | rx-* \
|
||||
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
|
||||
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
|
||||
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
|
||||
| sparclite-* \
|
||||
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
|
||||
| tahoe-* | thumb-* \
|
||||
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
|
||||
| tahoe-* \
|
||||
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
|
||||
| tile*-* \
|
||||
| tron-* \
|
||||
| v850-* | v850e-* | vax-* \
|
||||
| ubicom32-* \
|
||||
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
|
||||
| vax-* \
|
||||
| we32k-* \
|
||||
| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
|
||||
| xstormy16-* | xtensa-* \
|
||||
| x86-* | x86_64-* | xc16x-* | xps100-* \
|
||||
| xstormy16-* | xtensa*-* \
|
||||
| ymp-* \
|
||||
| z8k-*)
|
||||
| z8k-* | z80-*)
|
||||
;;
|
||||
# Recognize the basic CPU types without company name, with glob match.
|
||||
xtensa*)
|
||||
basic_machine=$basic_machine-unknown
|
||||
;;
|
||||
# Recognize the various machine names and aliases which stand
|
||||
# for a CPU type and a company and sometimes even an OS.
|
||||
@@ -389,7 +456,7 @@ case $basic_machine in
|
||||
basic_machine=a29k-amd
|
||||
os=-udi
|
||||
;;
|
||||
abacus)
|
||||
abacus)
|
||||
basic_machine=abacus-unknown
|
||||
;;
|
||||
adobe68k)
|
||||
@@ -435,6 +502,10 @@ case $basic_machine in
|
||||
basic_machine=m68k-apollo
|
||||
os=-bsd
|
||||
;;
|
||||
aros)
|
||||
basic_machine=i386-pc
|
||||
os=-aros
|
||||
;;
|
||||
aux)
|
||||
basic_machine=m68k-apple
|
||||
os=-aux
|
||||
@@ -443,10 +514,35 @@ case $basic_machine in
|
||||
basic_machine=ns32k-sequent
|
||||
os=-dynix
|
||||
;;
|
||||
blackfin)
|
||||
basic_machine=bfin-unknown
|
||||
os=-linux
|
||||
;;
|
||||
blackfin-*)
|
||||
basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
os=-linux
|
||||
;;
|
||||
bluegene*)
|
||||
basic_machine=powerpc-ibm
|
||||
os=-cnk
|
||||
;;
|
||||
c54x-*)
|
||||
basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
c55x-*)
|
||||
basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
c6x-*)
|
||||
basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
c90)
|
||||
basic_machine=c90-cray
|
||||
os=-unicos
|
||||
;;
|
||||
cegcc)
|
||||
basic_machine=arm-unknown
|
||||
os=-cegcc
|
||||
;;
|
||||
convex-c1)
|
||||
basic_machine=c1-convex
|
||||
os=-bsd
|
||||
@@ -475,8 +571,8 @@ case $basic_machine in
|
||||
basic_machine=craynv-cray
|
||||
os=-unicosmp
|
||||
;;
|
||||
cr16c)
|
||||
basic_machine=cr16c-unknown
|
||||
cr16 | cr16-*)
|
||||
basic_machine=cr16-unknown
|
||||
os=-elf
|
||||
;;
|
||||
crds | unos)
|
||||
@@ -514,6 +610,10 @@ case $basic_machine in
|
||||
basic_machine=m88k-motorola
|
||||
os=-sysv3
|
||||
;;
|
||||
dicos)
|
||||
basic_machine=i686-pc
|
||||
os=-dicos
|
||||
;;
|
||||
djgpp)
|
||||
basic_machine=i586-pc
|
||||
os=-msdosdjgpp
|
||||
@@ -629,7 +729,6 @@ case $basic_machine in
|
||||
i370-ibm* | ibm*)
|
||||
basic_machine=i370-ibm
|
||||
;;
|
||||
# I'm not sure what "Sysv32" means. Should this be sysv3.2?
|
||||
i*86v32)
|
||||
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
|
||||
os=-sysv32
|
||||
@@ -668,6 +767,14 @@ case $basic_machine in
|
||||
basic_machine=m68k-isi
|
||||
os=-sysv
|
||||
;;
|
||||
m68knommu)
|
||||
basic_machine=m68k-unknown
|
||||
os=-linux
|
||||
;;
|
||||
m68knommu-*)
|
||||
basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
os=-linux
|
||||
;;
|
||||
m88k-omron*)
|
||||
basic_machine=m88k-omron
|
||||
;;
|
||||
@@ -679,10 +786,21 @@ case $basic_machine in
|
||||
basic_machine=ns32k-utek
|
||||
os=-sysv
|
||||
;;
|
||||
microblaze*)
|
||||
basic_machine=microblaze-xilinx
|
||||
;;
|
||||
mingw64)
|
||||
basic_machine=x86_64-pc
|
||||
os=-mingw64
|
||||
;;
|
||||
mingw32)
|
||||
basic_machine=i386-pc
|
||||
os=-mingw32
|
||||
;;
|
||||
mingw32ce)
|
||||
basic_machine=arm-unknown
|
||||
os=-mingw32ce
|
||||
;;
|
||||
miniframe)
|
||||
basic_machine=m68000-convergent
|
||||
;;
|
||||
@@ -711,10 +829,18 @@ case $basic_machine in
|
||||
ms1-*)
|
||||
basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
|
||||
;;
|
||||
msys)
|
||||
basic_machine=i386-pc
|
||||
os=-msys
|
||||
;;
|
||||
mvs)
|
||||
basic_machine=i370-ibm
|
||||
os=-mvs
|
||||
;;
|
||||
nacl)
|
||||
basic_machine=le32-unknown
|
||||
os=-nacl
|
||||
;;
|
||||
ncr3000)
|
||||
basic_machine=i486-ncr
|
||||
os=-sysv4
|
||||
@@ -779,6 +905,12 @@ case $basic_machine in
|
||||
np1)
|
||||
basic_machine=np1-gould
|
||||
;;
|
||||
neo-tandem)
|
||||
basic_machine=neo-tandem
|
||||
;;
|
||||
nse-tandem)
|
||||
basic_machine=nse-tandem
|
||||
;;
|
||||
nsr-tandem)
|
||||
basic_machine=nsr-tandem
|
||||
;;
|
||||
@@ -809,6 +941,14 @@ case $basic_machine in
|
||||
basic_machine=i860-intel
|
||||
os=-osf
|
||||
;;
|
||||
parisc)
|
||||
basic_machine=hppa-unknown
|
||||
os=-linux
|
||||
;;
|
||||
parisc-*)
|
||||
basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
os=-linux
|
||||
;;
|
||||
pbd)
|
||||
basic_machine=sparc-tti
|
||||
;;
|
||||
@@ -853,9 +993,10 @@ case $basic_machine in
|
||||
;;
|
||||
power) basic_machine=power-ibm
|
||||
;;
|
||||
ppc) basic_machine=powerpc-unknown
|
||||
ppc | ppcbe) basic_machine=powerpc-unknown
|
||||
;;
|
||||
ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
ppc-* | ppcbe-*)
|
||||
basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
ppcle | powerpclittle | ppc-le | powerpc-little)
|
||||
basic_machine=powerpcle-unknown
|
||||
@@ -880,7 +1021,11 @@ case $basic_machine in
|
||||
basic_machine=i586-unknown
|
||||
os=-pw32
|
||||
;;
|
||||
rdos)
|
||||
rdos | rdos64)
|
||||
basic_machine=x86_64-pc
|
||||
os=-rdos
|
||||
;;
|
||||
rdos32)
|
||||
basic_machine=i386-pc
|
||||
os=-rdos
|
||||
;;
|
||||
@@ -949,6 +1094,9 @@ case $basic_machine in
|
||||
basic_machine=i860-stratus
|
||||
os=-sysv4
|
||||
;;
|
||||
strongarm-* | thumb-*)
|
||||
basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
sun2)
|
||||
basic_machine=m68000-sun
|
||||
;;
|
||||
@@ -1005,17 +1153,9 @@ case $basic_machine in
|
||||
basic_machine=t90-cray
|
||||
os=-unicos
|
||||
;;
|
||||
tic54x | c54x*)
|
||||
basic_machine=tic54x-unknown
|
||||
os=-coff
|
||||
;;
|
||||
tic55x | c55x*)
|
||||
basic_machine=tic55x-unknown
|
||||
os=-coff
|
||||
;;
|
||||
tic6x | c6x*)
|
||||
basic_machine=tic6x-unknown
|
||||
os=-coff
|
||||
tile*)
|
||||
basic_machine=$basic_machine-unknown
|
||||
os=-linux-gnu
|
||||
;;
|
||||
tx39)
|
||||
basic_machine=mipstx39-unknown
|
||||
@@ -1084,6 +1224,9 @@ case $basic_machine in
|
||||
xps | xps100)
|
||||
basic_machine=xps100-honeywell
|
||||
;;
|
||||
xscale-* | xscalee[bl]-*)
|
||||
basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
|
||||
;;
|
||||
ymp)
|
||||
basic_machine=ymp-cray
|
||||
os=-unicos
|
||||
@@ -1092,6 +1235,10 @@ case $basic_machine in
|
||||
basic_machine=z8k-unknown
|
||||
os=-sim
|
||||
;;
|
||||
z80-*-coff)
|
||||
basic_machine=z80-unknown
|
||||
os=-sim
|
||||
;;
|
||||
none)
|
||||
basic_machine=none-none
|
||||
os=-none
|
||||
@@ -1130,7 +1277,7 @@ case $basic_machine in
|
||||
we32k)
|
||||
basic_machine=we32k-att
|
||||
;;
|
||||
sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
|
||||
sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
|
||||
basic_machine=sh-unknown
|
||||
;;
|
||||
sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
|
||||
@@ -1177,9 +1324,12 @@ esac
|
||||
if [ x"$os" != x"" ]
|
||||
then
|
||||
case $os in
|
||||
# First match some system type aliases
|
||||
# that might get confused with valid system types.
|
||||
# First match some system type aliases
|
||||
# that might get confused with valid system types.
|
||||
# -solaris* is a basic system type, with this one exception.
|
||||
-auroraux)
|
||||
os=-auroraux
|
||||
;;
|
||||
-solaris1 | -solaris1.*)
|
||||
os=`echo $os | sed -e 's|solaris1|sunos4|'`
|
||||
;;
|
||||
@@ -1200,21 +1350,23 @@ case $os in
|
||||
# Each alternative MUST END IN A *, to match a version number.
|
||||
# -sysv* is not here because it comes later, after sysvr4.
|
||||
-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
|
||||
| -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
|
||||
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
|
||||
| -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
|
||||
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
|
||||
| -sym* | -kopensolaris* | -plan9* \
|
||||
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
|
||||
| -aos* \
|
||||
| -aos* | -aros* \
|
||||
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
|
||||
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
|
||||
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
|
||||
| -openbsd* | -solidbsd* \
|
||||
| -bitrig* | -openbsd* | -solidbsd* \
|
||||
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
|
||||
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
|
||||
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
|
||||
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
|
||||
| -chorusos* | -chorusrdb* \
|
||||
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
|
||||
| -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
|
||||
| -chorusos* | -chorusrdb* | -cegcc* \
|
||||
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
|
||||
| -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
|
||||
| -linux-newlib* | -linux-musl* | -linux-uclibc* \
|
||||
| -uxpv* | -beos* | -mpeix* | -udk* \
|
||||
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
|
||||
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
|
||||
@@ -1222,7 +1374,7 @@ case $os in
|
||||
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
|
||||
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
|
||||
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
|
||||
| -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
|
||||
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
|
||||
# Remember, each alternative MUST END IN *, to match a version number.
|
||||
;;
|
||||
-qnx*)
|
||||
@@ -1261,7 +1413,7 @@ case $os in
|
||||
-opened*)
|
||||
os=-openedition
|
||||
;;
|
||||
-os400*)
|
||||
-os400*)
|
||||
os=-os400
|
||||
;;
|
||||
-wince*)
|
||||
@@ -1310,7 +1462,7 @@ case $os in
|
||||
-sinix*)
|
||||
os=-sysv4
|
||||
;;
|
||||
-tpf*)
|
||||
-tpf*)
|
||||
os=-tpf
|
||||
;;
|
||||
-triton*)
|
||||
@@ -1346,12 +1498,14 @@ case $os in
|
||||
-aros*)
|
||||
os=-aros
|
||||
;;
|
||||
-kaos*)
|
||||
os=-kaos
|
||||
;;
|
||||
-zvmoe)
|
||||
os=-zvmoe
|
||||
;;
|
||||
-dicos*)
|
||||
os=-dicos
|
||||
;;
|
||||
-nacl*)
|
||||
;;
|
||||
-none)
|
||||
;;
|
||||
*)
|
||||
@@ -1374,10 +1528,10 @@ else
|
||||
# system, and we'll never get to this point.
|
||||
|
||||
case $basic_machine in
|
||||
score-*)
|
||||
score-*)
|
||||
os=-elf
|
||||
;;
|
||||
spu-*)
|
||||
spu-*)
|
||||
os=-elf
|
||||
;;
|
||||
*-acorn)
|
||||
@@ -1389,8 +1543,20 @@ case $basic_machine in
|
||||
arm*-semi)
|
||||
os=-aout
|
||||
;;
|
||||
c4x-* | tic4x-*)
|
||||
os=-coff
|
||||
c4x-* | tic4x-*)
|
||||
os=-coff
|
||||
;;
|
||||
hexagon-*)
|
||||
os=-elf
|
||||
;;
|
||||
tic54x-*)
|
||||
os=-coff
|
||||
;;
|
||||
tic55x-*)
|
||||
os=-coff
|
||||
;;
|
||||
tic6x-*)
|
||||
os=-coff
|
||||
;;
|
||||
# This must come before the *-dec entry.
|
||||
pdp10-*)
|
||||
@@ -1410,14 +1576,11 @@ case $basic_machine in
|
||||
;;
|
||||
m68000-sun)
|
||||
os=-sunos3
|
||||
# This also exists in the configure program, but was not the
|
||||
# default.
|
||||
# os=-sunos4
|
||||
;;
|
||||
m68*-cisco)
|
||||
os=-aout
|
||||
;;
|
||||
mep-*)
|
||||
mep-*)
|
||||
os=-elf
|
||||
;;
|
||||
mips*-cisco)
|
||||
@@ -1426,6 +1589,9 @@ case $basic_machine in
|
||||
mips*-*)
|
||||
os=-elf
|
||||
;;
|
||||
or1k-*)
|
||||
os=-elf
|
||||
;;
|
||||
or32-*)
|
||||
os=-coff
|
||||
;;
|
||||
@@ -1444,7 +1610,7 @@ case $basic_machine in
|
||||
*-ibm)
|
||||
os=-aix
|
||||
;;
|
||||
*-knuth)
|
||||
*-knuth)
|
||||
os=-mmixware
|
||||
;;
|
||||
*-wec)
|
||||
@@ -1549,7 +1715,7 @@ case $basic_machine in
|
||||
-sunos*)
|
||||
vendor=sun
|
||||
;;
|
||||
-aix*)
|
||||
-cnk*|-aix*)
|
||||
vendor=ibm
|
||||
;;
|
||||
-beos*)
|
||||
|
||||
@@ -211,7 +211,7 @@ AC_ARG_ENABLE(shadow,
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h pam/pam_appl.h netinet/in_systm.h])
|
||||
AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h pam/pam_appl.h netinet/in_systm.h sys/uio.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
@@ -616,7 +616,7 @@ AC_PROG_GCC_TRADITIONAL
|
||||
AC_FUNC_MEMCMP
|
||||
AC_FUNC_SELECT_ARGTYPES
|
||||
AC_TYPE_SIGNAL
|
||||
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo])
|
||||
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev])
|
||||
|
||||
AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
|
||||
|
||||
44
dbclient.1
44
dbclient.1
@@ -1,6 +1,6 @@
|
||||
.TH dbclient 1
|
||||
.SH NAME
|
||||
dbclient \- lightweight SSH2 client
|
||||
dbclient \- lightweight SSH client
|
||||
.SH SYNOPSIS
|
||||
.B dbclient
|
||||
[\-Tt] [\-p
|
||||
@@ -15,26 +15,26 @@ dbclient \- lightweight SSH2 client
|
||||
.B dbclient
|
||||
[
|
||||
.I args ]
|
||||
.I [user1]@host1[/port1],[user2]@host2[/port2],...
|
||||
.I [user1]@host1[%port1],[user2]@host2[%port2],...
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B dbclient
|
||||
is a SSH 2 client designed to be small enough to be used in small memory
|
||||
is a SSH client designed to be small enough to be used in small memory
|
||||
environments, while still being functional and secure enough for general use.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-p \fIport
|
||||
Remote port.
|
||||
Connect to port
|
||||
Connect to
|
||||
.I port
|
||||
on the remote host.
|
||||
on the remote host. Alternatively a port can be specified as hostname%port.
|
||||
Default is 22.
|
||||
.TP
|
||||
.B \-i \fIidfile
|
||||
Identity file.
|
||||
Read the identity from file
|
||||
Read the identity key from file
|
||||
.I idfile
|
||||
(multiple allowed).
|
||||
(multiple allowed). This file is created with dropbearkey(1) or converted
|
||||
from OpenSSH with dropbearconvert(1).
|
||||
.TP
|
||||
.B \-L [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
|
||||
Local port forwarding.
|
||||
@@ -61,10 +61,10 @@ Login as
|
||||
on the remote host.
|
||||
.TP
|
||||
.B \-t
|
||||
Allocate a pty.
|
||||
Allocate a PTY.
|
||||
.TP
|
||||
.B \-T
|
||||
Don't allocate a pty.
|
||||
Don't allocate a PTY.
|
||||
.TP
|
||||
.B \-N
|
||||
Don't request a remote shell or run any commands. Any command arguments are ignored.
|
||||
@@ -80,7 +80,8 @@ by the ssh server.
|
||||
.TP
|
||||
.B \-y
|
||||
Always accept hostkeys if they are unknown. If a hostkey mismatch occurs the
|
||||
connection will abort as normal.
|
||||
connection will abort as normal. If specified a second time no host key checking
|
||||
is performed at all, this is usually undesirable.
|
||||
.TP
|
||||
.B \-A
|
||||
Forward agent connections to the remote host. dbclient will use any
|
||||
@@ -111,12 +112,22 @@ comparing saved hostkeys.
|
||||
"Netcat-alike" mode, where Dropbear will connect to the given host, then create a
|
||||
forwarded connection to \fIendhost\fR. This will then be presented as dbclient's
|
||||
standard input/output.
|
||||
.TP
|
||||
.B \-c \fIcipherlist
|
||||
Specify a comma separated list of ciphers to enable. Use \fI-c help\fR to list possibilities.
|
||||
.TP
|
||||
.B \-m \fIMAClist
|
||||
Specify a comma separated list of authentication MACs to enable. Use \fI-m help\fR to list possibilities.
|
||||
.TP
|
||||
.B \-s
|
||||
The specified command will be requested as a subsystem, used for sftp. Dropbear doesn't implement sftp itself but the OpenSSH sftp client can be used eg \fIsftp -S dbclient user@host\fR
|
||||
|
||||
.SH MULTI-HOP
|
||||
Dropbear will also allow multiple "hops" to be specified, separated by commas. In
|
||||
this case a connection will be made to the first host, then a TCP forwarded
|
||||
connection will be made through that to the second host, and so on. Hosts other than
|
||||
the final destination will not see anything other than the encrypted SSH stream.
|
||||
A port for a host can be specified with a slash (eg matt@martello/44 ).
|
||||
A port for a host can be specified with a hash (eg matt@martello%44 ).
|
||||
This syntax can also be used with scp or rsync (specifying dbclient as the
|
||||
ssh/rsh command). A file can be "bounced" through multiple SSH hops, eg
|
||||
|
||||
@@ -126,6 +137,11 @@ Note that hostnames are resolved by the prior hop (so "canyons" would be resolve
|
||||
in the example above, the same way as other -L TCP forwarded hosts are. Host keys are
|
||||
checked locally based on the given hostname.
|
||||
|
||||
.SH ESCAPE CHARACTERS
|
||||
Typing a newline followed by the key sequence \fI~.\fR (tilde, dot) will terminate a connection.
|
||||
The sequence \fI~^Z\fR (tilde, ctrl-z) will background the connection. This behaviour only
|
||||
applies when a PTY is used.
|
||||
|
||||
.SH ENVIRONMENT
|
||||
.TP
|
||||
.B DROPBEAR_PASSWORD
|
||||
@@ -146,6 +162,6 @@ Mihnea Stoenescu wrote initial Dropbear client support
|
||||
.br
|
||||
Gerrit Pape (pape@smarden.org) wrote this manual page.
|
||||
.SH SEE ALSO
|
||||
dropbear(8), dropbearkey(8)
|
||||
dropbear(8), dropbearkey(1)
|
||||
.P
|
||||
http://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
https://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
|
||||
@@ -66,7 +66,7 @@ int main(int argc, char ** argv) {
|
||||
#endif
|
||||
}
|
||||
|
||||
fprintf(stderr, "Dropbear multi-purpose version %s\n"
|
||||
fprintf(stderr, "Dropbear SSH multi-purpose v%s\n"
|
||||
"Make a symlink pointing at this binary with one of the following names:\n"
|
||||
#ifdef DBMULTI_dropbear
|
||||
"'dropbear' - the Dropbear server\n"
|
||||
|
||||
76
dbutil.c
76
dbutil.c
@@ -57,11 +57,11 @@
|
||||
#define MAX_FMT 100
|
||||
|
||||
static void generic_dropbear_exit(int exitcode, const char* format,
|
||||
va_list param);
|
||||
va_list param) ATTRIB_NORETURN;
|
||||
static void generic_dropbear_log(int priority, const char* format,
|
||||
va_list param);
|
||||
|
||||
void (*_dropbear_exit)(int exitcode, const char* format, va_list param)
|
||||
void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN
|
||||
= generic_dropbear_exit;
|
||||
void (*_dropbear_log)(int priority, const char* format, va_list param)
|
||||
= generic_dropbear_log;
|
||||
@@ -138,15 +138,39 @@ void dropbear_log(int priority, const char* format, ...) {
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
void dropbear_trace(const char* format, ...) {
|
||||
|
||||
va_list param;
|
||||
struct timeval tv;
|
||||
|
||||
if (!debug_trace) {
|
||||
return;
|
||||
}
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
va_start(param, format);
|
||||
fprintf(stderr, "TRACE (%d): ", getpid());
|
||||
fprintf(stderr, "TRACE (%d) %d.%d: ", getpid(), tv.tv_sec, tv.tv_usec);
|
||||
vfprintf(stderr, format, param);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(param);
|
||||
}
|
||||
|
||||
void dropbear_trace2(const char* format, ...) {
|
||||
static int trace_env = -1;
|
||||
va_list param;
|
||||
struct timeval tv;
|
||||
|
||||
if (trace_env == -1) {
|
||||
trace_env = getenv("DROPBEAR_TRACE2") ? 1 : 0;
|
||||
}
|
||||
|
||||
if (!(debug_trace && trace_env)) {
|
||||
return;
|
||||
}
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
va_start(param, format);
|
||||
fprintf(stderr, "TRACE2 (%d) %d.%d: ", getpid(), tv.tv_sec, tv.tv_usec);
|
||||
vfprintf(stderr, format, param);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(param);
|
||||
@@ -161,10 +185,12 @@ static void set_sock_priority(int sock) {
|
||||
val = 1;
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
|
||||
|
||||
/* set the TOS bit. note that this will fail for ipv6, I can't find any
|
||||
* equivalent. */
|
||||
/* set the TOS bit for either ipv4 or ipv6 */
|
||||
#ifdef IPTOS_LOWDELAY
|
||||
val = IPTOS_LOWDELAY;
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
|
||||
setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&val, sizeof(val));
|
||||
#endif
|
||||
setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&val, sizeof(val));
|
||||
#endif
|
||||
|
||||
@@ -254,6 +280,16 @@ int dropbear_listen(const char* address, const char* port,
|
||||
linger.l_linger = 5;
|
||||
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
|
||||
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
|
||||
if (res->ai_family == AF_INET6) {
|
||||
int on = 1;
|
||||
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
&on, sizeof(on)) == -1) {
|
||||
dropbear_log(LOG_WARNING, "Couldn't set IPV6_V6ONLY");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
set_sock_priority(sock);
|
||||
|
||||
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
@@ -311,6 +347,7 @@ int connect_unix(const char* path) {
|
||||
}
|
||||
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
TRACE(("Failed to connect to '%s' socket", path))
|
||||
m_close(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
@@ -430,7 +467,7 @@ int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef __uClinux__
|
||||
#ifdef USE_VFORK
|
||||
pid = vfork();
|
||||
#else
|
||||
pid = fork();
|
||||
@@ -712,8 +749,6 @@ int buf_getline(buffer * line, FILE * authfile) {
|
||||
|
||||
int c = EOF;
|
||||
|
||||
TRACE(("enter buf_getline"))
|
||||
|
||||
buf_setpos(line, 0);
|
||||
buf_setlen(line, 0);
|
||||
|
||||
@@ -737,10 +772,8 @@ out:
|
||||
|
||||
/* if we didn't read anything before EOF or error, exit */
|
||||
if (c == EOF && line->pos == 0) {
|
||||
TRACE(("leave buf_getline: failure"))
|
||||
return DROPBEAR_FAILURE;
|
||||
} else {
|
||||
TRACE(("leave buf_getline: success"))
|
||||
buf_setpos(line, 0);
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
@@ -787,12 +820,6 @@ void * m_strdup(const char * str) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __m_free(void* ptr) {
|
||||
if (ptr != NULL) {
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void * m_realloc(void* ptr, size_t size) {
|
||||
|
||||
void *ret;
|
||||
@@ -817,7 +844,7 @@ void m_burn(void *data, unsigned int len) {
|
||||
if (data == NULL)
|
||||
return;
|
||||
while (len--) {
|
||||
*p++ = 0x66;
|
||||
*p++ = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -857,3 +884,16 @@ int m_str_to_uint(const char* str, unsigned int *val) {
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
int constant_time_memcmp(const void* a, const void *b, size_t n)
|
||||
{
|
||||
const char *xa = a, *xb = b;
|
||||
uint8_t c = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
c |= (xa[i] ^ xb[i]);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
33
dbutil.h
33
dbutil.h
@@ -33,18 +33,33 @@
|
||||
void startsyslog();
|
||||
#endif
|
||||
|
||||
extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param);
|
||||
#ifdef __GNUC__
|
||||
#define ATTRIB_PRINTF(fmt,args) __attribute__((format(printf, fmt, args)))
|
||||
#define ATTRIB_NORETURN __attribute__((noreturn))
|
||||
#define ATTRIB_SENTINEL __attribute__((sentinel))
|
||||
#else
|
||||
#define ATTRIB_PRINTF(fmt,args)
|
||||
#define ATTRIB_NORETURN
|
||||
#define ATTRIB_SENTINEL
|
||||
#endif
|
||||
|
||||
extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
|
||||
extern void (*_dropbear_log)(int priority, const char* format, va_list param);
|
||||
|
||||
void dropbear_exit(const char* format, ...);
|
||||
void dropbear_close(const char* format, ...);
|
||||
void dropbear_log(int priority, const char* format, ...);
|
||||
void fail_assert(const char* expr, const char* file, int line);
|
||||
void dropbear_exit(const char* format, ...) ATTRIB_PRINTF(1,2) ATTRIB_NORETURN;
|
||||
|
||||
void dropbear_close(const char* format, ...) ATTRIB_PRINTF(1,2) ;
|
||||
void dropbear_log(int priority, const char* format, ...) ATTRIB_PRINTF(2,3) ;
|
||||
|
||||
void fail_assert(const char* expr, const char* file, int line) ATTRIB_NORETURN;
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
void dropbear_trace(const char* format, ...);
|
||||
void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2);
|
||||
void dropbear_trace2(const char* format, ...) ATTRIB_PRINTF(1,2);
|
||||
void printhex(const char * label, const unsigned char * buf, int len);
|
||||
extern int debug_trace;
|
||||
#endif
|
||||
|
||||
char * stripcontrol(const char * text);
|
||||
void get_socket_address(int fd, char **local_host, char **local_port,
|
||||
char **remote_host, char **remote_port, int host_lookup);
|
||||
@@ -67,8 +82,7 @@ void m_close(int fd);
|
||||
void * m_malloc(size_t size);
|
||||
void * m_strdup(const char * str);
|
||||
void * m_realloc(void* ptr, size_t size);
|
||||
#define m_free(X) __m_free(X); (X) = NULL;
|
||||
void __m_free(void* ptr);
|
||||
#define m_free(X) free(X); (X) = NULL;
|
||||
void m_burn(void* data, unsigned int len);
|
||||
void setnonblocking(int fd);
|
||||
void disallow_core();
|
||||
@@ -80,4 +94,7 @@ int m_str_to_uint(const char* str, unsigned int *val);
|
||||
/* Dropbear assertion */
|
||||
#define dropbear_assert(X) do { if (!(X)) { fail_assert(#X, __FILE__, __LINE__); } } while (0)
|
||||
|
||||
/* Returns 0 if a and b have the same contents */
|
||||
int constant_time_memcmp(const void* a, const void *b, size_t n);
|
||||
|
||||
#endif /* _DBUTIL_H_ */
|
||||
|
||||
37
debian/changelog
vendored
37
debian/changelog
vendored
@@ -1,3 +1,40 @@
|
||||
dropbear (2013.59-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
* Build with DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Fri, 4 Oct 2013 22:54:00 +0800
|
||||
|
||||
dropbear (2013.58-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Thu, 18 Apr 2013 22:54:00 +0800
|
||||
|
||||
dropbear (2013.57-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Mon, 15 Apr 2013 22:54:00 +0800
|
||||
|
||||
dropbear (2013.56-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Thu, 21 Mar 2013 22:54:00 +0800
|
||||
|
||||
dropbear (2012.55-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 22 Feb 2012 22:54:00 +0800
|
||||
|
||||
dropbear (2011.54-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Tues, 8 Nov 2011 22:54:00 +0800
|
||||
|
||||
dropbear (0.53.1-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
19
debian/rules
vendored
19
debian/rules
vendored
@@ -1,5 +1,9 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
DPKG_EXPORT_BUILDFLAGS = 1
|
||||
include /usr/share/dpkg/buildflags.mk
|
||||
|
||||
#export DH_OPTIONS
|
||||
DEB_HOST_GNU_TYPE ?=$(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
||||
DEB_BUILD_GNU_TYPE ?=$(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
|
||||
@@ -9,13 +13,6 @@ ifneq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
STRIP =: nostrip
|
||||
endif
|
||||
|
||||
CFLAGS =-Wall -g
|
||||
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
|
||||
CFLAGS +=-O0
|
||||
else
|
||||
CFLAGS +=-O2
|
||||
endif
|
||||
|
||||
CONFFLAGS =
|
||||
CC =gcc
|
||||
ifneq (,$(findstring diet,$(DEB_BUILD_OPTIONS)))
|
||||
@@ -79,12 +76,12 @@ install: deb-checkdir deb-checkuid build-stamp
|
||||
ln -s /var/log/dropbear '$(DIR)'/etc/dropbear/log/main
|
||||
# man pages
|
||||
install -d -m0755 '$(DIR)'/usr/share/man/man8
|
||||
for i in dropbear.8 dropbearkey.8; do \
|
||||
install -m644 $$i '$(DIR)'/usr/share/man/man8/ || exit 1; \
|
||||
install -d -m0755 '$(DIR)'/usr/share/man/man1
|
||||
install -m644 dropbear.8 '$(DIR)'/usr/share/man/man8/
|
||||
for i in dbclient.1 dropbearkey.1 dropbearconvert.1; do \
|
||||
install -m644 $$i '$(DIR)'/usr/share/man/man1/ || exit 1; \
|
||||
done
|
||||
gzip -9 '$(DIR)'/usr/share/man/man8/*.8
|
||||
install -d -m0755 '$(DIR)'/usr/share/man/man1
|
||||
install -m644 dbclient.1 '$(DIR)'/usr/share/man/man1/
|
||||
gzip -9 '$(DIR)'/usr/share/man/man1/*.1
|
||||
# copyright, changelog
|
||||
cat debian/copyright.in LICENSE >debian/copyright
|
||||
|
||||
4
debug.h
4
debug.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
|
||||
@@ -63,8 +63,10 @@
|
||||
/* you don't need to touch this block */
|
||||
#ifdef DEBUG_TRACE
|
||||
#define TRACE(X) dropbear_trace X;
|
||||
#define TRACE2(X) dropbear_trace2 X;
|
||||
#else /*DEBUG_TRACE*/
|
||||
#define TRACE(X)
|
||||
#define TRACE2(X)
|
||||
#endif /*DEBUG_TRACE*/
|
||||
|
||||
/* To debug with GDB it is easier to run with no forking of child processes.
|
||||
|
||||
15
dropbear.8
15
dropbear.8
@@ -1,6 +1,6 @@
|
||||
.TH dropbear 8
|
||||
.SH NAME
|
||||
dropbear \- lightweight SSH2 server
|
||||
dropbear \- lightweight SSH server
|
||||
.SH SYNOPSIS
|
||||
.B dropbear
|
||||
[\-FEmwsgjki] [\-b
|
||||
@@ -10,7 +10,7 @@ dropbear \- lightweight SSH2 server
|
||||
.IR [address:]port ]
|
||||
.SH DESCRIPTION
|
||||
.B dropbear
|
||||
is a SSH 2 server designed to be small enough to be used in small memory
|
||||
is a SSH server designed to be small enough to be used in small memory
|
||||
environments, while still being functional and secure enough for general use.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
@@ -29,7 +29,7 @@ Note that
|
||||
some SSH implementations
|
||||
use the term "DSA" rather than "DSS", they mean the same thing.
|
||||
This file is generated with
|
||||
.BR dropbearkey (8).
|
||||
.BR dropbearkey (1).
|
||||
.TP
|
||||
.B \-r \fIrsakey
|
||||
rsakeyfile.
|
||||
@@ -37,7 +37,7 @@ Use the contents of the file
|
||||
.I rsakey
|
||||
for the rsa host key (default: /etc/dropbear/dropbear_rsa_host_key).
|
||||
This file is generated with
|
||||
.BR dropbearkey (8).
|
||||
.BR dropbearkey (1).
|
||||
.TP
|
||||
.B \-F
|
||||
Don't fork into background.
|
||||
@@ -180,13 +180,14 @@ in this variable. If a shell was requested this is set to an empty value.
|
||||
.B SSH_AUTH_SOCK
|
||||
Set to a forwarded ssh-agent connection.
|
||||
|
||||
|
||||
.SH NOTES
|
||||
Dropbear only supports SSH protocol version 2.
|
||||
|
||||
.SH AUTHOR
|
||||
Matt Johnston (matt@ucc.asn.au).
|
||||
.br
|
||||
Gerrit Pape (pape@smarden.org) wrote this manual page.
|
||||
.SH SEE ALSO
|
||||
dropbearkey(8), dbclient(1)
|
||||
dropbearkey(1), dbclient(1), dropbearconvert(1)
|
||||
.P
|
||||
http://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
https://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
|
||||
50
dropbearconvert.1
Normal file
50
dropbearconvert.1
Normal file
@@ -0,0 +1,50 @@
|
||||
.TH dropbearconvert 1
|
||||
.SH NAME
|
||||
dropbearconvert \- convert between Dropbear and OpenSSH private key formats
|
||||
.SH SYNOPSIS
|
||||
.B dropbearconvert
|
||||
.I input_type
|
||||
.I output_type
|
||||
.I input_file
|
||||
.I output_file
|
||||
.SH DESCRIPTION
|
||||
.B Dropbear
|
||||
and
|
||||
.B OpenSSH
|
||||
SSH implementations have different private key formats.
|
||||
.B dropbearconvert
|
||||
can convert between the two.
|
||||
.P
|
||||
Dropbear uses the same SSH public key format as OpenSSH, it can be extracted
|
||||
from a private key by using
|
||||
.B dropbearkey \-y
|
||||
.P
|
||||
Encrypted private keys are not supported, use ssh-keygen(1) to decrypt them
|
||||
first.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B input type
|
||||
Either
|
||||
.I dropbear
|
||||
or
|
||||
.I openssh
|
||||
.TP
|
||||
.B output type
|
||||
Either
|
||||
.I dropbear
|
||||
or
|
||||
.I openssh
|
||||
.TP
|
||||
.B input file
|
||||
An existing Dropbear or OpenSSH private key file
|
||||
.TP
|
||||
.B output file
|
||||
The path to write the converted private key file
|
||||
.SH EXAMPLE
|
||||
# dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/dropbear_priv
|
||||
.SH AUTHOR
|
||||
Matt Johnston (matt@ucc.asn.au).
|
||||
.SH SEE ALSO
|
||||
dropbearkey(1), ssh-keygen(1)
|
||||
.P
|
||||
https://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
@@ -1,6 +1,6 @@
|
||||
.TH dropbearkey 8
|
||||
.TH dropbearkey 1
|
||||
.SH NAME
|
||||
dropbearkey \- create private keys for the use with dropbear(8)
|
||||
dropbearkey \- create private keys for the use with dropbear(8) or dbclient(1)
|
||||
.SH SYNOPSIS
|
||||
.B dropbearkey
|
||||
\-t
|
||||
@@ -16,8 +16,7 @@ generates a
|
||||
or
|
||||
.I DSS
|
||||
format SSH private key, and saves it to a file for the use with the
|
||||
.BR dropbear (8)
|
||||
SSH 2 server.
|
||||
Dropbear client or server.
|
||||
Note that
|
||||
some SSH implementations
|
||||
use the term "DSA" rather than "DSS", they mean the same thing.
|
||||
@@ -38,6 +37,10 @@ Write the secret key to the file
|
||||
Set the key size to
|
||||
.I bits
|
||||
bits, should be multiple of 8 (optional).
|
||||
.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
|
||||
# dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
|
||||
.SH AUTHOR
|
||||
@@ -45,6 +48,6 @@ Matt Johnston (matt@ucc.asn.au).
|
||||
.br
|
||||
Gerrit Pape (pape@smarden.org) wrote this manual page.
|
||||
.SH SEE ALSO
|
||||
dropbear(8), dbclient(1)
|
||||
dropbear(8), dbclient(1), dropbearconvert(1)
|
||||
.P
|
||||
http://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
https://matt.ucc.asn.au/dropbear/dropbear.html
|
||||
@@ -65,7 +65,6 @@ static void justprintpub(const char* filename);
|
||||
static void printhelp(char * progname) {
|
||||
|
||||
fprintf(stderr, "Usage: %s -t <type> -f <filename> [-s bits]\n"
|
||||
"Options are:\n"
|
||||
"-t type Type of key to generate. One of:\n"
|
||||
#ifdef DROPBEAR_RSA
|
||||
" rsa\n"
|
||||
|
||||
74
dss.c
74
dss.c
@@ -101,9 +101,9 @@ int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
|
||||
/* Clear and free the memory used by a public or private key */
|
||||
void dss_key_free(dropbear_dss_key *key) {
|
||||
|
||||
TRACE(("enter dsa_key_free"))
|
||||
TRACE2(("enter dsa_key_free"))
|
||||
if (key == NULL) {
|
||||
TRACE(("enter dsa_key_free: key == NULL"))
|
||||
TRACE2(("enter dsa_key_free: key == NULL"))
|
||||
return;
|
||||
}
|
||||
if (key->p) {
|
||||
@@ -127,7 +127,7 @@ void dss_key_free(dropbear_dss_key *key) {
|
||||
m_free(key->x);
|
||||
}
|
||||
m_free(key);
|
||||
TRACE(("leave dsa_key_free"))
|
||||
TRACE2(("leave dsa_key_free"))
|
||||
}
|
||||
|
||||
/* put the dss public key into the buffer in the required format:
|
||||
@@ -258,52 +258,14 @@ out:
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
#ifdef DSS_PROTOK
|
||||
/* convert an unsigned mp into an array of bytes, malloced.
|
||||
* This array must be freed after use, len contains the length of the array,
|
||||
* if len != NULL */
|
||||
static unsigned char* mptobytes(mp_int *mp, int *len) {
|
||||
|
||||
unsigned char* ret;
|
||||
int size;
|
||||
|
||||
size = mp_unsigned_bin_size(mp);
|
||||
ret = m_malloc(size);
|
||||
if (mp_to_unsigned_bin(mp, ret) != MP_OKAY) {
|
||||
dropbear_exit("Mem alloc error");
|
||||
}
|
||||
if (len != NULL) {
|
||||
*len = size;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Sign the data presented with key, writing the signature contents
|
||||
* to the buffer
|
||||
*
|
||||
* When DSS_PROTOK is #defined:
|
||||
* The alternate k generation method is based on the method used in PuTTY.
|
||||
* In particular to avoid being vulnerable to attacks using flaws in random
|
||||
* generation of k, we use the following:
|
||||
*
|
||||
* proto_k = SHA512 ( SHA512(x) || SHA160(message) )
|
||||
* k = proto_k mod q
|
||||
*
|
||||
* Now we aren't relying on the random number generation to protect the private
|
||||
* key x, which is a long term secret */
|
||||
* to the buffer */
|
||||
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
unsigned char msghash[SHA1_HASH_SIZE];
|
||||
unsigned int writelen;
|
||||
unsigned int i;
|
||||
#ifdef DSS_PROTOK
|
||||
unsigned char privkeyhash[SHA512_HASH_SIZE];
|
||||
unsigned char *privkeytmp;
|
||||
unsigned char proto_k[SHA512_HASH_SIZE];
|
||||
DEF_MP_INT(dss_protok);
|
||||
#endif
|
||||
DEF_MP_INT(dss_k);
|
||||
DEF_MP_INT(dss_m);
|
||||
DEF_MP_INT(dss_temp1);
|
||||
@@ -322,33 +284,9 @@ void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, const unsigned char* d
|
||||
|
||||
m_mp_init_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
|
||||
&dss_m, NULL);
|
||||
#ifdef DSS_PROTOK
|
||||
/* hash the privkey */
|
||||
privkeytmp = mptobytes(key->x, &i);
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs, "the quick brown fox jumped over the lazy dog", 44);
|
||||
sha512_process(&hs, privkeytmp, i);
|
||||
sha512_done(&hs, privkeyhash);
|
||||
m_burn(privkeytmp, i);
|
||||
m_free(privkeytmp);
|
||||
|
||||
/* calculate proto_k */
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs, privkeyhash, SHA512_HASH_SIZE);
|
||||
sha512_process(&hs, msghash, SHA1_HASH_SIZE);
|
||||
sha512_done(&hs, proto_k);
|
||||
|
||||
/* generate k */
|
||||
m_mp_init(&dss_protok);
|
||||
bytes_to_mp(&dss_protok, proto_k, SHA512_HASH_SIZE);
|
||||
if (mp_mod(&dss_protok, key->q, &dss_k) != MP_OKAY) {
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
mp_clear(&dss_protok);
|
||||
m_burn(proto_k, SHA512_HASH_SIZE);
|
||||
#else /* DSS_PROTOK not defined*/
|
||||
/* the random number generator's input has included the private key which
|
||||
* avoids DSS's problem of private key exposure due to low entropy */
|
||||
gen_random_mpint(key->q, &dss_k);
|
||||
#endif
|
||||
|
||||
/* now generate the actual signature */
|
||||
bytes_to_mp(&dss_m, msghash, SHA1_HASH_SIZE);
|
||||
|
||||
@@ -120,6 +120,10 @@
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#ifdef BUNDLED_LIBTOM
|
||||
#include "libtomcrypt/src/headers/tomcrypt.h"
|
||||
#include "libtommath/tommath.h"
|
||||
|
||||
9
kex.h
9
kex.h
@@ -51,19 +51,22 @@ struct KEXState {
|
||||
|
||||
unsigned sentkexinit : 1; /*set when we've sent/recv kexinit packet */
|
||||
unsigned recvkexinit : 1;
|
||||
unsigned firstfollows : 1; /* true when first_kex_packet_follows is set */
|
||||
unsigned sentnewkeys : 1; /* set once we've send/recv'ed MSG_NEWKEYS*/
|
||||
unsigned recvnewkeys : 1;
|
||||
unsigned them_firstfollows : 1; /* true when first_kex_packet_follows is set */
|
||||
unsigned sentnewkeys : 1; /* set once we've send MSG_NEWKEYS (will be cleared once we have also received */
|
||||
unsigned recvnewkeys : 1; /* set once we've received MSG_NEWKEYS (cleared once we have also sent */
|
||||
|
||||
unsigned donefirstkex : 1; /* Set to 1 after the first kex has completed,
|
||||
ie the transport layer has been set up */
|
||||
|
||||
unsigned our_first_follows_matches : 1;
|
||||
|
||||
time_t lastkextime; /* time of the last kex */
|
||||
unsigned int datatrans; /* data transmitted since last kex */
|
||||
unsigned int datarecv; /* data received since last kex */
|
||||
|
||||
};
|
||||
|
||||
|
||||
#define MAX_KEXHASHBUF 2000
|
||||
|
||||
#endif /* _KEX_H_ */
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
/* #define LTC_CLEAN_STACK */
|
||||
|
||||
/* disable all file related functions */
|
||||
/* #define LTC_NO_FILE */
|
||||
#define LTC_NO_FILE
|
||||
|
||||
/* disable all forms of ASM */
|
||||
/* #define LTC_NO_ASM */
|
||||
@@ -118,16 +118,20 @@
|
||||
#define LTC_CTR_MODE
|
||||
#endif
|
||||
|
||||
#if defined(DROPBEAR_DSS) && defined(DSS_PROTOK)
|
||||
#define SHA512
|
||||
#endif
|
||||
|
||||
#define SHA1
|
||||
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
#ifdef DROPBEAR_MD5
|
||||
#define MD5
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_SHA256
|
||||
#define SHA256
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_SHA512
|
||||
#define SHA512
|
||||
#endif
|
||||
|
||||
#define LTC_HMAC
|
||||
|
||||
/* Various tidbits of modern neatoness */
|
||||
|
||||
@@ -170,8 +170,8 @@ clean:
|
||||
rm -f *.bat *.pdf *.o *.a *.obj *.lib *.exe *.dll etclib/*.o demo/demo.o test ltmtest mpitest mtest/mtest mtest/mtest.exe \
|
||||
*.idx *.toc *.log *.aux *.dvi *.lof *.ind *.ilg *.ps *.log *.s mpi.c *.da *.dyn *.dpi tommath.tex `find . -type f | grep [~] | xargs` *.lo *.la
|
||||
rm -rf .libs
|
||||
cd etc ; MAKE=${MAKE} ${MAKE} clean
|
||||
cd pics ; MAKE=${MAKE} ${MAKE} clean
|
||||
-cd etc && MAKE=${MAKE} ${MAKE} clean
|
||||
-cd pics && MAKE=${MAKE} ${MAKE} clean
|
||||
|
||||
#zipup the project (take that!)
|
||||
no_oops: clean
|
||||
|
||||
@@ -67,13 +67,13 @@ int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode
|
||||
|
||||
/* init M array */
|
||||
/* init first cell */
|
||||
if ((err = mp_init(&M[1])) != MP_OKAY) {
|
||||
if ((err = mp_init_size(&M[1], P->alloc)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* now init the second half of the array */
|
||||
for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
|
||||
if ((err = mp_init(&M[x])) != MP_OKAY) {
|
||||
if ((err = mp_init_size(&M[x], P->alloc)) != MP_OKAY) {
|
||||
for (y = 1<<(winsize-1); y < x; y++) {
|
||||
mp_clear (&M[y]);
|
||||
}
|
||||
@@ -133,7 +133,7 @@ int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode
|
||||
}
|
||||
|
||||
/* setup result */
|
||||
if ((err = mp_init (&res)) != MP_OKAY) {
|
||||
if ((err = mp_init_size (&res, P->alloc)) != MP_OKAY) {
|
||||
goto LBL_M;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ int mp_init_copy (mp_int * a, mp_int * b)
|
||||
{
|
||||
int res;
|
||||
|
||||
if ((res = mp_init (a)) != MP_OKAY) {
|
||||
if ((res = mp_init_size (a, b->used)) != MP_OKAY) {
|
||||
return res;
|
||||
}
|
||||
return mp_copy (b, a);
|
||||
|
||||
@@ -22,7 +22,7 @@ mp_mod (mp_int * a, mp_int * b, mp_int * c)
|
||||
mp_int t;
|
||||
int res;
|
||||
|
||||
if ((res = mp_init (&t)) != MP_OKAY) {
|
||||
if ((res = mp_init_size (&t, b->used)) != MP_OKAY) {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
|
||||
int res;
|
||||
mp_int t;
|
||||
|
||||
if ((res = mp_init (&t)) != MP_OKAY) {
|
||||
if ((res = mp_init_size (&t, c->used)) != MP_OKAY) {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
2
list.c
2
list.c
@@ -46,4 +46,4 @@ void * list_remove(m_list_elem *elem) {
|
||||
}
|
||||
m_free(elem);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
2
list.h
2
list.h
@@ -25,4 +25,4 @@ void list_append(m_list *list, void *item);
|
||||
void * list_remove(m_list_elem *elem);
|
||||
|
||||
|
||||
#endif /* _DROPBEAR_LIST_H */
|
||||
#endif /* _DROPBEAR_LIST_H */
|
||||
|
||||
@@ -329,8 +329,6 @@ login_write (struct logininfo *li)
|
||||
{
|
||||
#ifndef HAVE_CYGWIN
|
||||
if ((int)geteuid() != 0) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"Attempt to write login records by non-root user (aborting)");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
63
options.h
63
options.h
@@ -80,6 +80,9 @@ much traffic. */
|
||||
* to a remote TCP-forwarded connection */
|
||||
#define ENABLE_CLI_NETCAT
|
||||
|
||||
/* Whether to support "-c" and "-m" flags to choose ciphers/MACs at runtime */
|
||||
#define ENABLE_USER_ALGO_LIST
|
||||
|
||||
/* Encryption - at least one required.
|
||||
* Protocol RFC requires 3DES and recommends AES128 for interoperability.
|
||||
* Including multiple keysize variants the same cipher
|
||||
@@ -97,12 +100,18 @@ much traffic. */
|
||||
* size and is recommended for most cases */
|
||||
#define DROPBEAR_ENABLE_CTR_MODE
|
||||
|
||||
/* You can compile with no encryption if you want. In some circumstances
|
||||
* this could be safe security-wise, though make sure you know what
|
||||
* you're doing. Anyone can see everything that goes over the wire, so
|
||||
* the only safe auth method is public key. */
|
||||
/* #define DROPBEAR_NONE_CIPHER */
|
||||
|
||||
/* Message Integrity - at least one required.
|
||||
* Protocol RFC requires sha1 and recommends sha1-96.
|
||||
* sha1-96 may be of use for slow links, as it has a smaller overhead.
|
||||
* sha1-96 is of use for slow links as it has a smaller overhead.
|
||||
*
|
||||
* Note: there's no point disabling sha1 to save space, since it's used
|
||||
* for the random number generator and public-key cryptography anyway.
|
||||
* There's no reason to disable sha1 or sha1-96 to save space since it's
|
||||
* used for the random number generator and public-key cryptography anyway.
|
||||
* Disabling it here will just stop it from being used as the integrity portion
|
||||
* of the ssh protocol.
|
||||
*
|
||||
@@ -111,8 +120,15 @@ 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_MD5_HMAC
|
||||
|
||||
/* You can also disable integrity. Don't bother disabling this if you're
|
||||
* still using a cipher, it's relatively cheap. If you disable this it's dead
|
||||
* simple to run arbitrary commands on the remote host. Beware. */
|
||||
/* #define DROPBEAR_NONE_INTEGRITY */
|
||||
|
||||
/* Hostkey/public key algorithms - at least one required, these are used
|
||||
* for hostkey as well as for verifying signatures with pubkey auth.
|
||||
* Removing either of these won't save very much space.
|
||||
@@ -125,13 +141,6 @@ much traffic. */
|
||||
* signing operations slightly slower. */
|
||||
#define RSA_BLINDING
|
||||
|
||||
/* Define DSS_PROTOK to use PuTTY's method of generating the value k for dss,
|
||||
* rather than just from the random byte source. Undefining this will save you
|
||||
* ~4k in binary size with static uclibc, but your DSS hostkey could be exposed
|
||||
* if the random number source isn't good. It happened to Sony.
|
||||
* On systems with a decent random source this isn't required. */
|
||||
/* #define DSS_PROTOK */
|
||||
|
||||
/* Control the memory/performance/compression tradeoff for zlib.
|
||||
* Set windowBits=8 for least memory usage, see your system's
|
||||
* zlib.h for full details.
|
||||
@@ -144,7 +153,7 @@ much traffic. */
|
||||
#endif
|
||||
|
||||
/* Whether to do reverse DNS lookups. */
|
||||
#define DO_HOST_LOOKUP
|
||||
//#define DO_HOST_LOOKUP
|
||||
|
||||
/* Whether to print the message of the day (MOTD). This doesn't add much code
|
||||
* size */
|
||||
@@ -158,15 +167,16 @@ much traffic. */
|
||||
/* Authentication Types - at least one required.
|
||||
RFC Draft requires pubkey auth, and recommends password */
|
||||
|
||||
/* Note: PAM auth is quite simple, and only works for PAM modules which just do
|
||||
/* Note: PAM auth is quite simple and only works for PAM modules which just do
|
||||
* a simple "Login: " "Password: " (you can edit the strings in svr-authpam.c).
|
||||
* It's useful for systems like OS X where standard password crypts don't work,
|
||||
* but there's an interface via a PAM module - don't bother using it otherwise.
|
||||
* It's useful for systems like OS X where standard password crypts don't work
|
||||
* but there's an interface via a PAM module. It won't work for more complex
|
||||
* PAM challenge/response.
|
||||
* You can't enable both PASSWORD and PAM. */
|
||||
|
||||
#define ENABLE_SVR_PASSWORD_AUTH
|
||||
/* PAM requires ./configure --enable-pam */
|
||||
/*#define ENABLE_SVR_PAM_AUTH*/
|
||||
//#define ENABLE_SVR_PAM_AUTH
|
||||
#define ENABLE_SVR_PUBKEY_AUTH
|
||||
|
||||
/* Whether to take public key options in
|
||||
@@ -194,21 +204,22 @@ much traffic. */
|
||||
* return the password on standard output */
|
||||
/*#define ENABLE_CLI_ASKPASS_HELPER*/
|
||||
|
||||
/* Random device to use - define either DROPBEAR_RANDOM_DEV or
|
||||
* DROPBEAR_PRNGD_SOCKET.
|
||||
* DROPBEAR_RANDOM_DEV is recommended on hosts with a good /dev/(u)random,
|
||||
* otherwise use run prngd (or egd if you want), specifying the socket.
|
||||
* The device will be queried for a few dozen bytes of seed a couple of times
|
||||
* per session (or more for very long-lived sessions). */
|
||||
/* Send a real auth request first rather than requesting a list of available methods.
|
||||
* It saves a network round trip at login but prevents immediate login to
|
||||
* accounts with no password, and might be rejected by some strict servers (none
|
||||
* encountered yet) - hence it isn't enabled by default. */
|
||||
/* #define CLI_IMMEDIATE_AUTH */
|
||||
|
||||
/* We'll use /dev/urandom by default, since /dev/random is too much hassle.
|
||||
* If system developers aren't keeping seeds between boots nor getting
|
||||
* any entropy from somewhere it's their own fault. */
|
||||
#define DROPBEAR_RANDOM_DEV "/dev/urandom"
|
||||
|
||||
/* prngd must be manually set up to produce output */
|
||||
/* Source for randomness. This must be able to provide hundreds of bytes per SSH
|
||||
* connection without blocking. In addition /dev/random is used for seeding
|
||||
* rsa/dss key generation */
|
||||
#define DROPBEAR_URANDOM_DEV "/dev/urandom"
|
||||
|
||||
/* Set this to use PRNGD or EGD instead of /dev/urandom or /dev/random */
|
||||
/*#define DROPBEAR_PRNGD_SOCKET "/var/run/dropbear-rng"*/
|
||||
|
||||
|
||||
/* Specify the number of clients we will allow to be connected but
|
||||
* not yet authenticated. After this limit, connections are rejected */
|
||||
/* The first setting is per-IP, to avoid denial of service */
|
||||
|
||||
151
packet.c
151
packet.c
@@ -42,7 +42,7 @@ static void make_mac(unsigned int seqno, const struct key_context_directional *
|
||||
static int checkmac();
|
||||
|
||||
#define ZLIB_COMPRESS_INCR 100
|
||||
#define ZLIB_DECOMPRESS_INCR 100
|
||||
#define ZLIB_DECOMPRESS_INCR 1024
|
||||
#ifndef DISABLE_ZLIB
|
||||
static buffer* buf_decompress(buffer* buf, unsigned int len);
|
||||
static void buf_compress(buffer * dest, buffer * src, unsigned int len);
|
||||
@@ -55,10 +55,62 @@ void write_packet() {
|
||||
buffer * writebuf = NULL;
|
||||
time_t now;
|
||||
unsigned packet_type;
|
||||
int all_ignore = 1;
|
||||
#ifdef HAVE_WRITEV
|
||||
struct iovec *iov = NULL;
|
||||
int i;
|
||||
struct Link *l;
|
||||
#endif
|
||||
|
||||
TRACE(("enter write_packet"))
|
||||
TRACE2(("enter write_packet"))
|
||||
dropbear_assert(!isempty(&ses.writequeue));
|
||||
|
||||
#ifdef HAVE_WRITEV
|
||||
iov = m_malloc(sizeof(*iov) * ses.writequeue.count);
|
||||
for (l = ses.writequeue.head, i = 0; l; l = l->link, i++)
|
||||
{
|
||||
writebuf = (buffer*)l->item;
|
||||
packet_type = writebuf->data[writebuf->len-1];
|
||||
len = writebuf->len - 1 - writebuf->pos;
|
||||
dropbear_assert(len > 0);
|
||||
all_ignore &= (packet_type == SSH_MSG_IGNORE);
|
||||
TRACE2(("write_packet writev #%d type %d len %d/%d", i, packet_type,
|
||||
len, writebuf->len-1))
|
||||
iov[i].iov_base = buf_getptr(writebuf, len);
|
||||
iov[i].iov_len = len;
|
||||
}
|
||||
written = writev(ses.sock_out, iov, ses.writequeue.count);
|
||||
if (written < 0) {
|
||||
if (errno == EINTR) {
|
||||
m_free(iov);
|
||||
TRACE2(("leave writepacket: EINTR"))
|
||||
return;
|
||||
} else {
|
||||
dropbear_exit("Error writing");
|
||||
}
|
||||
}
|
||||
|
||||
if (written == 0) {
|
||||
ses.remoteclosed();
|
||||
}
|
||||
|
||||
while (written > 0) {
|
||||
writebuf = (buffer*)examine(&ses.writequeue);
|
||||
len = writebuf->len - 1 - writebuf->pos;
|
||||
if (len > written) {
|
||||
// partial buffer write
|
||||
buf_incrpos(writebuf, written);
|
||||
written = 0;
|
||||
} else {
|
||||
written -= len;
|
||||
dequeue(&ses.writequeue);
|
||||
buf_free(writebuf);
|
||||
}
|
||||
}
|
||||
|
||||
m_free(iov);
|
||||
|
||||
#else
|
||||
/* Get the next buffer in the queue of encrypted packets to write*/
|
||||
writebuf = (buffer*)examine(&ses.writequeue);
|
||||
|
||||
@@ -72,19 +124,13 @@ void write_packet() {
|
||||
|
||||
if (written < 0) {
|
||||
if (errno == EINTR) {
|
||||
TRACE(("leave writepacket: EINTR"))
|
||||
TRACE2(("leave writepacket: EINTR"))
|
||||
return;
|
||||
} else {
|
||||
dropbear_exit("Error writing");
|
||||
}
|
||||
}
|
||||
|
||||
now = time(NULL);
|
||||
ses.last_trx_packet_time = now;
|
||||
|
||||
if (packet_type != SSH_MSG_IGNORE) {
|
||||
ses.last_packet_time = now;
|
||||
}
|
||||
all_ignore = (packet_type == SSH_MSG_IGNORE);
|
||||
|
||||
if (written == 0) {
|
||||
ses.remoteclosed();
|
||||
@@ -100,7 +146,15 @@ void write_packet() {
|
||||
buf_incrpos(writebuf, written);
|
||||
}
|
||||
|
||||
TRACE(("leave write_packet"))
|
||||
#endif
|
||||
now = time(NULL);
|
||||
ses.last_trx_packet_time = now;
|
||||
|
||||
if (!all_ignore) {
|
||||
ses.last_packet_time = now;
|
||||
}
|
||||
|
||||
TRACE2(("leave write_packet"))
|
||||
}
|
||||
|
||||
/* Non-blocking function reading available portion of a packet into the
|
||||
@@ -112,7 +166,7 @@ void read_packet() {
|
||||
unsigned int maxlen;
|
||||
unsigned char blocksize;
|
||||
|
||||
TRACE(("enter read_packet"))
|
||||
TRACE2(("enter read_packet"))
|
||||
blocksize = ses.keys->recv.algo_crypt->blocksize;
|
||||
|
||||
if (ses.readbuf == NULL || ses.readbuf->len < blocksize) {
|
||||
@@ -125,7 +179,7 @@ void read_packet() {
|
||||
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
/* didn't read enough to determine the length */
|
||||
TRACE(("leave read_packet: packetinit done"))
|
||||
TRACE2(("leave read_packet: packetinit done"))
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -133,22 +187,29 @@ void read_packet() {
|
||||
/* Attempt to read the remainder of the packet, note that there
|
||||
* mightn't be any available (EAGAIN) */
|
||||
maxlen = ses.readbuf->len - ses.readbuf->pos;
|
||||
len = read(ses.sock_in, buf_getptr(ses.readbuf, maxlen), maxlen);
|
||||
if (maxlen == 0) {
|
||||
/* Occurs when the packet is only a single block long and has all
|
||||
* been read in read_packet_init(). Usually means that MAC is disabled
|
||||
*/
|
||||
len = 0;
|
||||
} else {
|
||||
len = read(ses.sock_in, buf_getptr(ses.readbuf, maxlen), maxlen);
|
||||
|
||||
if (len == 0) {
|
||||
ses.remoteclosed();
|
||||
}
|
||||
|
||||
if (len < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
TRACE(("leave read_packet: EINTR or EAGAIN"))
|
||||
return;
|
||||
} else {
|
||||
dropbear_exit("Error reading: %s", strerror(errno));
|
||||
if (len == 0) {
|
||||
ses.remoteclosed();
|
||||
}
|
||||
}
|
||||
|
||||
buf_incrpos(ses.readbuf, len);
|
||||
if (len < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
TRACE2(("leave read_packet: EINTR or EAGAIN"))
|
||||
return;
|
||||
} else {
|
||||
dropbear_exit("Error reading: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
buf_incrpos(ses.readbuf, len);
|
||||
}
|
||||
|
||||
if ((unsigned int)len == maxlen) {
|
||||
/* The whole packet has been read */
|
||||
@@ -156,7 +217,7 @@ void read_packet() {
|
||||
/* The main select() loop process_packet() to
|
||||
* handle the packet contents... */
|
||||
}
|
||||
TRACE(("leave read_packet"))
|
||||
TRACE2(("leave read_packet"))
|
||||
}
|
||||
|
||||
/* Function used to read the initial portion of a packet, and determine the
|
||||
@@ -190,7 +251,7 @@ static int read_packet_init() {
|
||||
}
|
||||
if (slen < 0) {
|
||||
if (errno == EINTR) {
|
||||
TRACE(("leave read_packet_init: EINTR"))
|
||||
TRACE2(("leave read_packet_init: EINTR"))
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
dropbear_exit("Error reading: %s", strerror(errno));
|
||||
@@ -214,7 +275,7 @@ static int read_packet_init() {
|
||||
}
|
||||
len = buf_getint(ses.readbuf) + 4 + macsize;
|
||||
|
||||
TRACE(("packet size is %d, block %d mac %d", len, blocksize, macsize))
|
||||
TRACE2(("packet size is %d, block %d mac %d", len, blocksize, macsize))
|
||||
|
||||
|
||||
/* check packet length */
|
||||
@@ -240,7 +301,7 @@ void decrypt_packet() {
|
||||
unsigned int padlen;
|
||||
unsigned int len;
|
||||
|
||||
TRACE(("enter decrypt_packet"))
|
||||
TRACE2(("enter decrypt_packet"))
|
||||
blocksize = ses.keys->recv.algo_crypt->blocksize;
|
||||
macsize = ses.keys->recv.algo_mac->hashsize;
|
||||
|
||||
@@ -297,7 +358,7 @@ void decrypt_packet() {
|
||||
|
||||
ses.recvseq++;
|
||||
|
||||
TRACE(("leave decrypt_packet"))
|
||||
TRACE2(("leave decrypt_packet"))
|
||||
}
|
||||
|
||||
/* Checks the mac at the end of a decrypted readbuf.
|
||||
@@ -307,7 +368,7 @@ static int checkmac() {
|
||||
unsigned char mac_bytes[MAX_MAC_LEN];
|
||||
unsigned int mac_size, contents_len;
|
||||
|
||||
mac_size = ses.keys->trans.algo_mac->hashsize;
|
||||
mac_size = ses.keys->recv.algo_mac->hashsize;
|
||||
contents_len = ses.readbuf->len - mac_size;
|
||||
|
||||
buf_setpos(ses.readbuf, 0);
|
||||
@@ -315,7 +376,7 @@ static int checkmac() {
|
||||
|
||||
/* compare the hash */
|
||||
buf_setpos(ses.readbuf, contents_len);
|
||||
if (memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {
|
||||
if (constant_time_memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {
|
||||
return DROPBEAR_FAILURE;
|
||||
} else {
|
||||
return DROPBEAR_SUCCESS;
|
||||
@@ -359,7 +420,12 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) {
|
||||
}
|
||||
|
||||
if (zstream->avail_out == 0) {
|
||||
buf_resize(ret, ret->size + ZLIB_DECOMPRESS_INCR);
|
||||
int new_size = 0;
|
||||
if (ret->size >= RECV_MAX_PAYLOAD_LEN) {
|
||||
dropbear_exit("bad packet, oversized decompressed");
|
||||
}
|
||||
new_size = MIN(RECV_MAX_PAYLOAD_LEN, ret->size + ZLIB_DECOMPRESS_INCR);
|
||||
buf_resize(ret, new_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,7 +462,6 @@ static void enqueue_reply_packet() {
|
||||
ses.reply_queue_head = new_item;
|
||||
}
|
||||
ses.reply_queue_tail = new_item;
|
||||
TRACE(("leave enqueue_reply_packet"))
|
||||
}
|
||||
|
||||
void maybe_flush_reply_queue() {
|
||||
@@ -433,15 +498,15 @@ void encrypt_packet() {
|
||||
unsigned int len, encrypt_buf_size;
|
||||
unsigned char mac_bytes[MAX_MAC_LEN];
|
||||
|
||||
TRACE(("enter encrypt_packet()"))
|
||||
TRACE2(("enter encrypt_packet()"))
|
||||
|
||||
buf_setpos(ses.writepayload, 0);
|
||||
packet_type = buf_getbyte(ses.writepayload);
|
||||
buf_setpos(ses.writepayload, 0);
|
||||
|
||||
TRACE(("encrypt_packet type is %d", packet_type))
|
||||
TRACE2(("encrypt_packet type is %d", packet_type))
|
||||
|
||||
if (!ses.dataallowed && !packet_is_okay_kex(packet_type)) {
|
||||
if ((!ses.dataallowed && !packet_is_okay_kex(packet_type))) {
|
||||
/* During key exchange only particular packets are allowed.
|
||||
Since this packet_type isn't OK we just enqueue it to send
|
||||
after the KEX, see maybe_flush_reply_queue */
|
||||
@@ -546,7 +611,7 @@ void encrypt_packet() {
|
||||
ses.kexstate.datatrans += writebuf->len;
|
||||
ses.transseq++;
|
||||
|
||||
TRACE(("leave encrypt_packet()"))
|
||||
TRACE2(("leave encrypt_packet()"))
|
||||
}
|
||||
|
||||
|
||||
@@ -559,8 +624,6 @@ static void make_mac(unsigned int seqno, const struct key_context_directional *
|
||||
unsigned long bufsize;
|
||||
hmac_state hmac;
|
||||
|
||||
TRACE(("enter writemac"))
|
||||
|
||||
if (key_state->algo_mac->hashsize > 0) {
|
||||
/* calculate the mac */
|
||||
if (hmac_init(&hmac,
|
||||
@@ -589,7 +652,7 @@ static void make_mac(unsigned int seqno, const struct key_context_directional *
|
||||
dropbear_exit("HMAC error");
|
||||
}
|
||||
}
|
||||
TRACE(("leave writemac"))
|
||||
TRACE2(("leave writemac"))
|
||||
}
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
@@ -600,7 +663,7 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
|
||||
unsigned int endpos = src->pos + len;
|
||||
int result;
|
||||
|
||||
TRACE(("enter buf_compress"))
|
||||
TRACE2(("enter buf_compress"))
|
||||
|
||||
while (1) {
|
||||
|
||||
@@ -634,6 +697,6 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
|
||||
buf_resize(dest, dest->size + ZLIB_COMPRESS_INCR);
|
||||
|
||||
}
|
||||
TRACE(("leave buf_compress"))
|
||||
TRACE2(("leave buf_compress"))
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -45,10 +45,10 @@ void process_packet() {
|
||||
unsigned char type;
|
||||
unsigned int i;
|
||||
|
||||
TRACE(("enter process_packet"))
|
||||
TRACE2(("enter process_packet"))
|
||||
|
||||
type = buf_getbyte(ses.payload);
|
||||
TRACE(("process_packet: packet type = %d", type))
|
||||
TRACE(("process_packet: packet type = %d, len %d", type, ses.payload->len))
|
||||
|
||||
ses.lastpacket = type;
|
||||
|
||||
@@ -74,14 +74,15 @@ void process_packet() {
|
||||
|
||||
/* This applies for KEX, where the spec says the next packet MUST be
|
||||
* NEWKEYS */
|
||||
if (ses.requirenext != 0) {
|
||||
if (ses.requirenext != type) {
|
||||
/* TODO send disconnect? */
|
||||
dropbear_exit("Unexpected packet type %d, expected %d", type,
|
||||
ses.requirenext);
|
||||
if (ses.requirenext[0] != 0) {
|
||||
if (ses.requirenext[0] != type
|
||||
&& (ses.requirenext[1] == 0 || ses.requirenext[1] != type)) {
|
||||
dropbear_exit("Unexpected packet type %d, expected [%d,%d]", type,
|
||||
ses.requirenext[0], ses.requirenext[1]);
|
||||
} else {
|
||||
/* Got what we expected */
|
||||
ses.requirenext = 0;
|
||||
ses.requirenext[0] = 0;
|
||||
ses.requirenext[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +124,7 @@ out:
|
||||
buf_free(ses.payload);
|
||||
ses.payload = NULL;
|
||||
|
||||
TRACE(("leave process_packet"))
|
||||
TRACE2(("leave process_packet"))
|
||||
}
|
||||
|
||||
|
||||
|
||||
2
queue.c
2
queue.c
@@ -70,7 +70,6 @@ void enqueue(struct Queue* queue, void* item) {
|
||||
|
||||
struct Link* newlink;
|
||||
|
||||
TRACE(("enter enqueue"))
|
||||
newlink = (struct Link*)m_malloc(sizeof(struct Link));
|
||||
|
||||
newlink->item = item;
|
||||
@@ -85,5 +84,4 @@ void enqueue(struct Queue* queue, void* item) {
|
||||
queue->head = newlink;
|
||||
}
|
||||
queue->count++;
|
||||
TRACE(("leave enqueue"))
|
||||
}
|
||||
|
||||
2
queue.h
2
queue.h
@@ -36,7 +36,7 @@ struct Queue {
|
||||
|
||||
struct Link* head;
|
||||
struct Link* tail;
|
||||
unsigned int count; /* safety value */
|
||||
unsigned int count;
|
||||
|
||||
};
|
||||
|
||||
|
||||
241
random.c
241
random.c
@@ -26,20 +26,18 @@
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "bignum.h"
|
||||
|
||||
static int donerandinit = 0;
|
||||
#include "random.h"
|
||||
|
||||
/* this is used to generate unique output from the same hashpool */
|
||||
static uint32_t counter = 0;
|
||||
/* the max value for the counter, so it won't integer overflow */
|
||||
#define MAX_COUNTER 1<<30
|
||||
|
||||
static unsigned char hashpool[SHA1_HASH_SIZE];
|
||||
static unsigned char hashpool[SHA1_HASH_SIZE] = {0};
|
||||
static int donerandinit = 0;
|
||||
|
||||
#define INIT_SEED_SIZE 32 /* 256 bits */
|
||||
|
||||
static void readrand(unsigned char* buf, unsigned int buflen);
|
||||
|
||||
/* The basic setup is we read some data from /dev/(u)random or prngd and hash it
|
||||
* into hashpool. To read data, we hash together current hashpool contents,
|
||||
* and a counter. We feed more data in by hashing the current pool and new
|
||||
@@ -50,120 +48,199 @@ static void readrand(unsigned char* buf, unsigned int buflen);
|
||||
*
|
||||
*/
|
||||
|
||||
static void readrand(unsigned char* buf, unsigned int buflen) {
|
||||
|
||||
/* Pass len=0 to hash an entire file */
|
||||
static int
|
||||
process_file(hash_state *hs, const char *filename,
|
||||
unsigned int len, int prngd)
|
||||
{
|
||||
static int already_blocked = 0;
|
||||
int readfd;
|
||||
unsigned int readpos;
|
||||
int readlen;
|
||||
#ifdef DROPBEAR_PRNGD_SOCKET
|
||||
struct sockaddr_un egdsock;
|
||||
char egdcmd[2];
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_RANDOM_DEV
|
||||
readfd = open(DROPBEAR_RANDOM_DEV, O_RDONLY);
|
||||
if (readfd < 0) {
|
||||
dropbear_exit("Couldn't open random device");
|
||||
}
|
||||
#endif
|
||||
unsigned int readcount;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
#ifdef DROPBEAR_PRNGD_SOCKET
|
||||
readfd = connect_unix(DROPBEAR_PRNGD_SOCKET);
|
||||
|
||||
if (readfd < 0) {
|
||||
dropbear_exit("Couldn't open random device");
|
||||
if (prngd)
|
||||
{
|
||||
readfd = connect_unix(filename);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
readfd = open(filename, O_RDONLY);
|
||||
}
|
||||
|
||||
if (buflen > 255)
|
||||
dropbear_exit("Can't request more than 255 bytes from egd");
|
||||
egdcmd[0] = 0x02; /* blocking read */
|
||||
egdcmd[1] = (unsigned char)buflen;
|
||||
if (write(readfd, egdcmd, 2) < 0)
|
||||
dropbear_exit("Can't send command to egd");
|
||||
#endif
|
||||
if (readfd < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* read the actual random data */
|
||||
readpos = 0;
|
||||
do {
|
||||
readcount = 0;
|
||||
while (len == 0 || readcount < len)
|
||||
{
|
||||
int readlen, wantread;
|
||||
unsigned char readbuf[4096];
|
||||
if (!already_blocked)
|
||||
{
|
||||
int ret;
|
||||
struct timeval timeout;
|
||||
struct timeval timeout = { .tv_sec = 2, .tv_usec = 0};
|
||||
fd_set read_fds;
|
||||
|
||||
timeout.tv_sec = 2; /* two seconds should be enough */
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(readfd, &read_fds);
|
||||
ret = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
|
||||
if (ret == 0)
|
||||
{
|
||||
dropbear_log(LOG_INFO, "Warning: Reading the random source seems to have blocked.\nIf you experience problems, you probably need to find a better entropy source.");
|
||||
dropbear_log(LOG_WARNING, "Warning: Reading the randomness source '%s' seems to have blocked.\nYou may need to find a better entropy source.", filename);
|
||||
already_blocked = 1;
|
||||
}
|
||||
}
|
||||
readlen = read(readfd, &buf[readpos], buflen - readpos);
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
wantread = sizeof(readbuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
wantread = MIN(sizeof(readbuf), len-readcount);
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_PRNGD_SOCKET
|
||||
if (prngd)
|
||||
{
|
||||
char egdcmd[2];
|
||||
egdcmd[0] = 0x02; /* blocking read */
|
||||
egdcmd[1] = (unsigned char)wantread;
|
||||
if (write(readfd, egdcmd, 2) < 0)
|
||||
{
|
||||
dropbear_exit("Can't send command to egd");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
readlen = read(readfd, readbuf, wantread);
|
||||
if (readlen <= 0) {
|
||||
if (readlen < 0 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
dropbear_exit("Error reading random source");
|
||||
if (readlen == 0 && len == 0)
|
||||
{
|
||||
/* whole file was read as requested */
|
||||
break;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
readpos += readlen;
|
||||
} while (readpos < buflen);
|
||||
|
||||
close (readfd);
|
||||
sha1_process(hs, readbuf, readlen);
|
||||
readcount += readlen;
|
||||
}
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
out:
|
||||
close(readfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* initialise the prng from /dev/(u)random or prngd */
|
||||
void seedrandom() {
|
||||
|
||||
unsigned char readbuf[INIT_SEED_SIZE];
|
||||
|
||||
void addrandom(char * buf, unsigned int len)
|
||||
{
|
||||
hash_state hs;
|
||||
|
||||
/* initialise so that things won't warn about
|
||||
* hashing an undefined buffer */
|
||||
if (!donerandinit) {
|
||||
m_burn(hashpool, sizeof(hashpool));
|
||||
}
|
||||
|
||||
/* get the seed data */
|
||||
readrand(readbuf, sizeof(readbuf));
|
||||
|
||||
/* hash in the new seed data */
|
||||
sha1_init(&hs);
|
||||
/* existing state (zeroes on startup) */
|
||||
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
|
||||
sha1_process(&hs, (void*)readbuf, sizeof(readbuf));
|
||||
|
||||
/* new */
|
||||
sha1_process(&hs, buf, len);
|
||||
sha1_done(&hs, hashpool);
|
||||
}
|
||||
|
||||
static void write_urandom()
|
||||
{
|
||||
#ifndef DROPBEAR_PRNGD_SOCKET
|
||||
/* This is opportunistic, don't worry about failure */
|
||||
unsigned char buf[INIT_SEED_SIZE];
|
||||
FILE *f = fopen(DROPBEAR_URANDOM_DEV, "w");
|
||||
if (!f) {
|
||||
return;
|
||||
}
|
||||
genrandom(buf, sizeof(buf));
|
||||
fwrite(buf, sizeof(buf), 1, f);
|
||||
fclose(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Initialise the prng from /dev/urandom or prngd. This function can
|
||||
* be called multiple times */
|
||||
void seedrandom() {
|
||||
|
||||
hash_state hs;
|
||||
|
||||
pid_t pid;
|
||||
struct timeval tv;
|
||||
clock_t clockval;
|
||||
|
||||
/* hash in the new seed data */
|
||||
sha1_init(&hs);
|
||||
/* existing state */
|
||||
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
|
||||
|
||||
#ifdef DROPBEAR_PRNGD_SOCKET
|
||||
if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failure reading random device %s",
|
||||
DROPBEAR_PRNGD_SOCKET);
|
||||
}
|
||||
#else
|
||||
/* non-blocking random source (probably /dev/urandom) */
|
||||
if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failure reading random device %s",
|
||||
DROPBEAR_URANDOM_DEV);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* A few other sources to fall back on.
|
||||
* Add more here for other platforms */
|
||||
#ifdef __linux__
|
||||
/* Seems to be a reasonable source of entropy from timers. Possibly hard
|
||||
* for even local attackers to reproduce */
|
||||
process_file(&hs, "/proc/timer_list", 0, 0);
|
||||
/* Might help on systems with wireless */
|
||||
process_file(&hs, "/proc/interrupts", 0, 0);
|
||||
|
||||
process_file(&hs, "/proc/loadavg", 0, 0);
|
||||
process_file(&hs, "/proc/sys/kernel/random/entropy_avail", 0, 0);
|
||||
|
||||
/* Mostly network visible but useful in some situations.
|
||||
* Limit size to avoid slowdowns on systems with lots of routes */
|
||||
process_file(&hs, "/proc/net/netstat", 4096, 0);
|
||||
process_file(&hs, "/proc/net/dev", 4096, 0);
|
||||
process_file(&hs, "/proc/net/tcp", 4096, 0);
|
||||
/* Also includes interface lo */
|
||||
process_file(&hs, "/proc/net/rt_cache", 4096, 0);
|
||||
process_file(&hs, "/proc/vmstat", 0, 0);
|
||||
#endif
|
||||
|
||||
pid = getpid();
|
||||
sha1_process(&hs, (void*)&pid, sizeof(pid));
|
||||
|
||||
// gettimeofday() doesn't completely fill out struct timeval on
|
||||
// OS X (10.8.3), avoid valgrind warnings by clearing it first
|
||||
memset(&tv, 0x0, sizeof(tv));
|
||||
gettimeofday(&tv, NULL);
|
||||
sha1_process(&hs, (void*)&tv, sizeof(tv));
|
||||
|
||||
clockval = clock();
|
||||
sha1_process(&hs, (void*)&clockval, sizeof(clockval));
|
||||
|
||||
/* When a private key is read by the client or server it will
|
||||
* be added to the hashpool - see runopts.c */
|
||||
|
||||
sha1_done(&hs, hashpool);
|
||||
|
||||
counter = 0;
|
||||
donerandinit = 1;
|
||||
}
|
||||
|
||||
/* hash the current random pool with some unique identifiers
|
||||
* for this process and point-in-time. this is used to separate
|
||||
* the random pools for fork()ed processes. */
|
||||
void reseedrandom() {
|
||||
|
||||
pid_t pid;
|
||||
hash_state hs;
|
||||
struct timeval tv;
|
||||
|
||||
if (!donerandinit) {
|
||||
dropbear_exit("seedrandom not done");
|
||||
}
|
||||
|
||||
pid = getpid();
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
|
||||
sha1_process(&hs, (void*)&pid, sizeof(pid));
|
||||
sha1_process(&hs, (void*)&tv, sizeof(tv));
|
||||
sha1_done(&hs, hashpool);
|
||||
/* Feed it all back into /dev/urandom - this might help if Dropbear
|
||||
* is running from inetd and gets new state each time */
|
||||
write_urandom();
|
||||
}
|
||||
|
||||
/* return len bytes of pseudo-random data */
|
||||
|
||||
5
random.h
5
random.h
@@ -28,9 +28,8 @@
|
||||
struct mp_int;
|
||||
|
||||
void seedrandom();
|
||||
void reseedrandom();
|
||||
void genrandom(unsigned char* buf, int len);
|
||||
void addrandom(unsigned char* buf, int len);
|
||||
void genrandom(unsigned char* buf, unsigned int len);
|
||||
void addrandom(char * buf, unsigned int len);
|
||||
void gen_random_mpint(mp_int *max, mp_int *rand);
|
||||
|
||||
#endif /* _RANDOM_H_ */
|
||||
|
||||
6
rsa.c
6
rsa.c
@@ -139,10 +139,10 @@ out:
|
||||
/* Clear and free the memory used by a public or private key */
|
||||
void rsa_key_free(dropbear_rsa_key *key) {
|
||||
|
||||
TRACE(("enter rsa_key_free"))
|
||||
TRACE2(("enter rsa_key_free"))
|
||||
|
||||
if (key == NULL) {
|
||||
TRACE(("leave rsa_key_free: key == NULL"))
|
||||
TRACE2(("leave rsa_key_free: key == NULL"))
|
||||
return;
|
||||
}
|
||||
if (key->d) {
|
||||
@@ -166,7 +166,7 @@ void rsa_key_free(dropbear_rsa_key *key) {
|
||||
m_free(key->q);
|
||||
}
|
||||
m_free(key);
|
||||
TRACE(("leave rsa_key_free"))
|
||||
TRACE2(("leave rsa_key_free"))
|
||||
}
|
||||
|
||||
/* Put the public rsa key into the buffer in the required format:
|
||||
|
||||
10
runopts.h
10
runopts.h
@@ -47,6 +47,10 @@ typedef struct runopts {
|
||||
int enable_compress;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
char *cipher_list;
|
||||
char *mac_list;
|
||||
#endif
|
||||
|
||||
} runopts;
|
||||
|
||||
@@ -85,6 +89,7 @@ typedef struct svr_runopts {
|
||||
|
||||
int noauthpass;
|
||||
int norootpass;
|
||||
int allowblankpass;
|
||||
|
||||
#ifdef ENABLE_SVR_REMOTETCPFWD
|
||||
int noremotetcp;
|
||||
@@ -116,6 +121,7 @@ typedef struct cli_runopts {
|
||||
char *cmd;
|
||||
int wantpty;
|
||||
int always_accept_key;
|
||||
int no_hostkey_check;
|
||||
int no_cmd;
|
||||
int backgrounded;
|
||||
int is_subsystem;
|
||||
@@ -148,4 +154,8 @@ typedef struct cli_runopts {
|
||||
extern cli_runopts cli_opts;
|
||||
void cli_getopts(int argc, char ** argv);
|
||||
|
||||
#ifdef ENABLE_USER_ALGO_LIST
|
||||
void parse_ciphers_macs();
|
||||
#endif
|
||||
|
||||
#endif /* _RUNOPTS_H_ */
|
||||
|
||||
65
scp.c
65
scp.c
@@ -130,22 +130,22 @@ do_local_cmd(arglist *a)
|
||||
fprintf(stderr, " %s", a->list[i]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#ifdef __uClinux__
|
||||
#ifdef USE_VFORK
|
||||
pid = vfork();
|
||||
#else
|
||||
pid = fork();
|
||||
#endif /* __uClinux__ */
|
||||
#endif
|
||||
if (pid == -1)
|
||||
fatal("do_local_cmd: fork: %s", strerror(errno));
|
||||
|
||||
if (pid == 0) {
|
||||
execvp(a->list[0], a->list);
|
||||
perror(a->list[0]);
|
||||
#ifdef __uClinux__
|
||||
#ifdef USE_VFORK
|
||||
_exit(1);
|
||||
#else
|
||||
exit(1);
|
||||
#endif /* __uClinux__ */
|
||||
#endif
|
||||
}
|
||||
|
||||
do_cmd_pid = pid;
|
||||
@@ -171,6 +171,16 @@ do_local_cmd(arglist *a)
|
||||
* assigns the input and output file descriptors on success.
|
||||
*/
|
||||
|
||||
static void
|
||||
arg_setup(char *host, char *remuser, char *cmd)
|
||||
{
|
||||
replacearg(&args, 0, "%s", ssh_program);
|
||||
if (remuser != NULL)
|
||||
addargs(&args, "-l%s", remuser);
|
||||
addargs(&args, "%s", host);
|
||||
addargs(&args, "%s", cmd);
|
||||
}
|
||||
|
||||
int
|
||||
do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
|
||||
{
|
||||
@@ -198,22 +208,18 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
|
||||
close(reserved[0]);
|
||||
close(reserved[1]);
|
||||
|
||||
/* uClinux needs to build the args here before vforking,
|
||||
otherwise we do it later on. */
|
||||
#ifdef __uClinux__
|
||||
replacearg(&args, 0, "%s", ssh_program);
|
||||
if (remuser != NULL)
|
||||
addargs(&args, "-l%s", remuser);
|
||||
addargs(&args, "%s", host);
|
||||
addargs(&args, "%s", cmd);
|
||||
#endif /* __uClinux__ */
|
||||
/* uClinux needs to build the args here before vforking,
|
||||
otherwise we do it later on. */
|
||||
#ifdef USE_VFORK
|
||||
arg_setup(host, remuser, cmd);
|
||||
#endif
|
||||
|
||||
/* Fork a child to execute the command on the remote host using ssh. */
|
||||
#ifdef __uClinux__
|
||||
#ifdef USE_VFORK
|
||||
do_cmd_pid = vfork();
|
||||
#else
|
||||
do_cmd_pid = fork();
|
||||
#endif /* __uClinux__ */
|
||||
#endif
|
||||
|
||||
if (do_cmd_pid == 0) {
|
||||
/* Child. */
|
||||
@@ -224,27 +230,22 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
|
||||
close(pin[0]);
|
||||
close(pout[1]);
|
||||
|
||||
#ifndef __uClinux__
|
||||
replacearg(&args, 0, "%s", ssh_program);
|
||||
if (remuser != NULL)
|
||||
addargs(&args, "-l%s", remuser);
|
||||
addargs(&args, "%s", host);
|
||||
addargs(&args, "%s", cmd);
|
||||
#endif /* __uClinux__ */
|
||||
#ifndef USE_VFORK
|
||||
arg_setup(host, remuser, cmd);
|
||||
#endif
|
||||
|
||||
execvp(ssh_program, args.list);
|
||||
perror(ssh_program);
|
||||
#ifndef __uClinux__
|
||||
exit(1);
|
||||
#else
|
||||
#ifdef USE_VFORK
|
||||
_exit(1);
|
||||
#endif /* __uClinux__ */
|
||||
#else
|
||||
exit(1);
|
||||
#endif
|
||||
} else if (do_cmd_pid == -1) {
|
||||
fatal("fork: %s", strerror(errno));
|
||||
}
|
||||
|
||||
|
||||
#ifdef __uClinux__
|
||||
#ifdef USE_VFORK
|
||||
/* clean up command */
|
||||
/* pop cmd */
|
||||
xfree(args.list[args.num-1]);
|
||||
@@ -260,7 +261,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
|
||||
args.list[args.num-1]=NULL;
|
||||
args.num--;
|
||||
}
|
||||
#endif /* __uClinux__ */
|
||||
#endif
|
||||
|
||||
/* Parent. Close the other side, and return the local side. */
|
||||
close(pin[0]);
|
||||
@@ -364,12 +365,12 @@ main(int argc, char **argv)
|
||||
addargs(&args, "-v");
|
||||
verbose_mode = 1;
|
||||
break;
|
||||
#ifdef PROGRESS_METER
|
||||
case 'q':
|
||||
#ifdef PROGRESS_METER
|
||||
addargs(&args, "-q");
|
||||
showprogress = 0;
|
||||
break;
|
||||
#endif
|
||||
break;
|
||||
|
||||
/* Server options. */
|
||||
case 'd':
|
||||
@@ -773,7 +774,7 @@ bwlimit(int amount)
|
||||
{
|
||||
static struct timeval bwstart, bwend;
|
||||
static int lamt, thresh = 16384;
|
||||
u_int64_t waitlen;
|
||||
uint64_t waitlen;
|
||||
struct timespec ts, rm;
|
||||
|
||||
if (!timerisset(&bwstart)) {
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
|
||||
/*RCSID("OpenBSD: xmalloc.c,v 1.16 2001/07/23 18:21:46 stevesk Exp ");*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "includes.h"
|
||||
#include "scpmisc.h"
|
||||
|
||||
|
||||
@@ -26,7 +26,5 @@
|
||||
#define _SERVICE_H_
|
||||
|
||||
void recv_msg_service_request(); /* Server */
|
||||
void send_msg_service_request(); /* Client */
|
||||
void recv_msg_service_accept(); /* Client */
|
||||
|
||||
#endif /* _SERVICE_H_ */
|
||||
|
||||
46
session.h
46
session.h
@@ -37,14 +37,15 @@
|
||||
#include "packet.h"
|
||||
#include "tcpfwd.h"
|
||||
#include "chansession.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
extern int sessinitdone; /* Is set to 0 somewhere */
|
||||
extern int exitflag;
|
||||
|
||||
void common_session_init(int sock_in, int sock_out);
|
||||
void session_loop(void(*loophandler)());
|
||||
void common_session_cleanup();
|
||||
void session_identification();
|
||||
void session_cleanup();
|
||||
void send_session_identification();
|
||||
void send_msg_ignore();
|
||||
|
||||
const char* get_user_shell();
|
||||
@@ -52,19 +53,18 @@ void fill_passwd(const char* username);
|
||||
|
||||
/* Server */
|
||||
void svr_session(int sock, int childpipe);
|
||||
void svr_dropbear_exit(int exitcode, const char* format, va_list param);
|
||||
void svr_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
|
||||
void svr_dropbear_log(int priority, const char* format, va_list param);
|
||||
|
||||
/* Client */
|
||||
void cli_session(int sock_in, int sock_out);
|
||||
void cli_session_cleanup();
|
||||
void cleantext(unsigned char* dirtytext);
|
||||
|
||||
/* crypto parameters that are stored individually for transmit and receive */
|
||||
struct key_context_directional {
|
||||
const struct dropbear_cipher *algo_crypt; /* NULL for none */
|
||||
const struct dropbear_cipher *algo_crypt;
|
||||
const struct dropbear_cipher_mode *crypt_mode;
|
||||
const struct dropbear_hash *algo_mac; /* NULL for none */
|
||||
const struct dropbear_hash *algo_mac;
|
||||
int hash_index; /* lookup for libtomcrypt */
|
||||
char algo_comp; /* compression */
|
||||
#ifndef DISABLE_ZLIB
|
||||
@@ -77,7 +77,8 @@ struct key_context_directional {
|
||||
symmetric_CTR ctr;
|
||||
#endif
|
||||
} cipher_state;
|
||||
unsigned char mackey[MAX_MAC_KEY];
|
||||
unsigned char mackey[MAX_MAC_LEN];
|
||||
int valid;
|
||||
};
|
||||
|
||||
struct key_context {
|
||||
@@ -110,7 +111,10 @@ struct sshsession {
|
||||
int sock_in;
|
||||
int sock_out;
|
||||
|
||||
unsigned char *remoteident;
|
||||
/* remotehost will be initially NULL as we delay
|
||||
* reading the remote version string. it will be set
|
||||
* by the time any recv_() packet methods are called */
|
||||
unsigned char *remoteident;
|
||||
|
||||
int maxfd; /* the maximum file descriptor to check with select() */
|
||||
|
||||
@@ -131,8 +135,9 @@ struct sshsession {
|
||||
unsigned dataallowed : 1; /* whether we can send data packets or we are in
|
||||
the middle of a KEX or something */
|
||||
|
||||
unsigned char requirenext; /* byte indicating what packet we require next,
|
||||
or 0x00 for any */
|
||||
unsigned char requirenext[2]; /* bytes indicating what packets we require next,
|
||||
or 0x00 for any. Second option can only be
|
||||
used if the first byte is also set */
|
||||
|
||||
unsigned char ignorenext; /* whether to ignore the next packet,
|
||||
used for kex_follows stuff */
|
||||
@@ -168,15 +173,11 @@ struct sshsession {
|
||||
concluded (ie, while dataallowed was unset)*/
|
||||
struct packetlist *reply_queue_head, *reply_queue_tail;
|
||||
|
||||
algo_type*(*buf_match_algo)(buffer*buf, algo_type localalgos[],
|
||||
int *goodguess); /* The function to use to choose which algorithm
|
||||
to use from the ones presented by the remote
|
||||
side. Is specific to the client/server mode,
|
||||
hence the function-pointer callback.*/
|
||||
|
||||
void(*remoteclosed)(); /* A callback to handle closure of the
|
||||
remote connection */
|
||||
|
||||
void(*extra_session_cleanup)(); /* client or server specific cleanup */
|
||||
void(*send_kex_first_guess)();
|
||||
|
||||
struct AuthState authstate; /* Common amongst client and server, since most
|
||||
struct elements are common */
|
||||
@@ -217,7 +218,7 @@ struct serversession {
|
||||
/* The resolved remote address, used for lastlog etc */
|
||||
char *remotehost;
|
||||
|
||||
#ifdef __uClinux__
|
||||
#ifdef USE_VFORK
|
||||
pid_t server_pid;
|
||||
#endif
|
||||
|
||||
@@ -232,10 +233,6 @@ typedef enum {
|
||||
|
||||
typedef enum {
|
||||
STATE_NOTHING,
|
||||
SERVICE_AUTH_REQ_SENT,
|
||||
SERVICE_AUTH_ACCEPT_RCVD,
|
||||
SERVICE_CONN_REQ_SENT,
|
||||
SERVICE_CONN_ACCEPT_RCVD,
|
||||
USERAUTH_REQ_SENT,
|
||||
USERAUTH_FAIL_RCVD,
|
||||
USERAUTH_SUCCESS_RCVD,
|
||||
@@ -245,6 +242,7 @@ typedef enum {
|
||||
struct clientsession {
|
||||
|
||||
mp_int *dh_e, *dh_x; /* Used during KEX */
|
||||
int dh_val_algo; /* KEX algorithm corresponding to current dh_e and dh_x */
|
||||
cli_kex_state kex_state; /* Used for progressing KEX */
|
||||
cli_state state; /* Used to progress auth/channelsession etc */
|
||||
unsigned donefirstkex : 1; /* Set when we set sentnewkeys, never reset */
|
||||
@@ -258,6 +256,9 @@ struct clientsession {
|
||||
int stderrcopy;
|
||||
int stderrflags;
|
||||
|
||||
/* for escape char handling */
|
||||
int last_char;
|
||||
|
||||
int winchange; /* Set to 1 when a windowchange signal happens */
|
||||
|
||||
int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
|
||||
@@ -268,6 +269,9 @@ struct clientsession {
|
||||
int interact_request_received; /* flag whether we've received an
|
||||
info request from the server for
|
||||
interactive auth.*/
|
||||
|
||||
int cipher_none_after_auth; /* Set to 1 if the user requested "none"
|
||||
auth */
|
||||
#endif
|
||||
sign_key *lastprivkey;
|
||||
|
||||
|
||||
20
signkey.c
20
signkey.c
@@ -98,18 +98,18 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
|
||||
int keytype;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
TRACE(("enter buf_get_pub_key"))
|
||||
TRACE2(("enter buf_get_pub_key"))
|
||||
|
||||
ident = buf_getstring(buf, &len);
|
||||
keytype = signkey_type_from_name(ident, len);
|
||||
m_free(ident);
|
||||
|
||||
if (*type != DROPBEAR_SIGNKEY_ANY && *type != keytype) {
|
||||
TRACE(("buf_get_pub_key bad type - got %d, expected %d", keytype, type))
|
||||
TRACE(("buf_get_pub_key bad type - got %d, expected %d", keytype, *type))
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
TRACE(("buf_get_pub_key keytype is %d"))
|
||||
TRACE2(("buf_get_pub_key keytype is %d", keytype))
|
||||
|
||||
*type = keytype;
|
||||
|
||||
@@ -137,7 +137,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE(("leave buf_get_pub_key"))
|
||||
TRACE2(("leave buf_get_pub_key"))
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -153,7 +153,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
|
||||
int keytype;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
TRACE(("enter buf_get_priv_key"))
|
||||
TRACE2(("enter buf_get_priv_key"))
|
||||
|
||||
ident = buf_getstring(buf, &len);
|
||||
keytype = signkey_type_from_name(ident, len);
|
||||
@@ -190,7 +190,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE(("leave buf_get_priv_key"))
|
||||
TRACE2(("leave buf_get_priv_key"))
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -201,7 +201,7 @@ void buf_put_pub_key(buffer* buf, sign_key *key, int type) {
|
||||
|
||||
buffer *pubkeys;
|
||||
|
||||
TRACE(("enter buf_put_pub_key"))
|
||||
TRACE2(("enter buf_put_pub_key"))
|
||||
pubkeys = buf_new(MAX_PUBKEY_SIZE);
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
@@ -223,7 +223,7 @@ void buf_put_pub_key(buffer* buf, sign_key *key, int type) {
|
||||
pubkeys->len);
|
||||
|
||||
buf_free(pubkeys);
|
||||
TRACE(("leave buf_put_pub_key"))
|
||||
TRACE2(("leave buf_put_pub_key"))
|
||||
}
|
||||
|
||||
/* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
|
||||
@@ -251,7 +251,7 @@ void buf_put_priv_key(buffer* buf, sign_key *key, int type) {
|
||||
|
||||
void sign_key_free(sign_key *key) {
|
||||
|
||||
TRACE(("enter sign_key_free"))
|
||||
TRACE2(("enter sign_key_free"))
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
dss_key_free(key->dsskey);
|
||||
@@ -265,7 +265,7 @@ void sign_key_free(sign_key *key) {
|
||||
m_free(key->filename);
|
||||
|
||||
m_free(key);
|
||||
TRACE(("leave sign_key_free"))
|
||||
TRACE2(("leave sign_key_free"))
|
||||
}
|
||||
|
||||
static char hexdig(unsigned char x) {
|
||||
|
||||
2
sshpty.c
2
sshpty.c
@@ -133,7 +133,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
|
||||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
#ifndef HAVE_CYGWIN
|
||||
#if !defined(HAVE_CYGWIN) && defined(I_PUSH)
|
||||
/*
|
||||
* Push the appropriate streams modules, as described in Solaris pts(7).
|
||||
* HP-UX pts(7) doesn't have ttcompat module.
|
||||
|
||||
@@ -50,10 +50,7 @@ static void agentaccept(struct Listener * listener, int sock);
|
||||
/* Handles client requests to start agent forwarding, sets up listening socket.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int svr_agentreq(struct ChanSess * chansess) {
|
||||
|
||||
int fd;
|
||||
|
||||
TRACE(("enter svr_agentreq"))
|
||||
int fd = -1;
|
||||
|
||||
if (!svr_pubkey_allows_agentfwd()) {
|
||||
return DROPBEAR_FAILURE;
|
||||
@@ -91,10 +88,9 @@ int svr_agentreq(struct ChanSess * chansess) {
|
||||
}
|
||||
|
||||
return DROPBEAR_SUCCESS;
|
||||
TRACE(("success"))
|
||||
|
||||
fail:
|
||||
TRACE(("fail"))
|
||||
m_close(fd);
|
||||
/* cleanup */
|
||||
svr_agentcleanup(chansess);
|
||||
|
||||
|
||||
100
svr-algo.c
100
svr-algo.c
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
* SSH client implementation
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2004 by Mihnea Stoenescu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "algo.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
/* match the first algorithm in the comma-separated list in buf which is
|
||||
* also in localalgos[], or return NULL on failure.
|
||||
* (*goodguess) is set to 1 if the preferred client/server algos match,
|
||||
* 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
|
||||
* guessed correctly */
|
||||
algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
int *goodguess)
|
||||
{
|
||||
|
||||
unsigned char * algolist = NULL;
|
||||
unsigned char * remotealgos[MAX_PROPOSED_ALGO];
|
||||
unsigned int len;
|
||||
unsigned int count, i, j;
|
||||
algo_type * ret = NULL;
|
||||
|
||||
*goodguess = 0;
|
||||
|
||||
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
|
||||
algolist = buf_getstring(buf, &len);
|
||||
/* Debug this */
|
||||
TRACE(("buf_match_algo: %s", algolist))
|
||||
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
goto out; /* just a sanity check, no other use */
|
||||
}
|
||||
|
||||
/* remotealgos will contain a list of the strings parsed out */
|
||||
/* We will have at least one string (even if it's just "") */
|
||||
remotealgos[0] = algolist;
|
||||
count = 1;
|
||||
/* Iterate through, replacing ','s with NULs, to split it into
|
||||
* words. */
|
||||
for (i = 0; i < len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
goto out;
|
||||
}
|
||||
if (algolist[i] == ',') {
|
||||
algolist[i] = '\0';
|
||||
remotealgos[count] = &algolist[i+1];
|
||||
count++;
|
||||
}
|
||||
if (count == MAX_PROPOSED_ALGO) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* iterate and find the first match */
|
||||
for (i = 0; i < count; i++) {
|
||||
|
||||
len = strlen(remotealgos[i]);
|
||||
|
||||
for (j = 0; localalgos[j].name != NULL; j++) {
|
||||
if (localalgos[j].usable) {
|
||||
if (len == strlen(localalgos[j].name) &&
|
||||
strncmp(localalgos[j].name, remotealgos[i], len) == 0) {
|
||||
/* set if it was a good guess */
|
||||
if (i == 0 && j == 0) {
|
||||
*goodguess = 1;
|
||||
}
|
||||
/* set the algo to return */
|
||||
ret = &localalgos[j];
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
m_free(algolist);
|
||||
return ret;
|
||||
}
|
||||
109
svr-auth.c
109
svr-auth.c
@@ -37,7 +37,6 @@
|
||||
|
||||
static void authclear();
|
||||
static int checkusername(unsigned char *username, unsigned int userlen);
|
||||
static void send_msg_userauth_banner();
|
||||
|
||||
/* initialise the first time for a session, resetting all parameters */
|
||||
void svr_authinitialise() {
|
||||
@@ -82,24 +81,18 @@ static void authclear() {
|
||||
|
||||
/* Send a banner message if specified to the client. The client might
|
||||
* ignore this, but possibly serves as a legal "no trespassing" sign */
|
||||
static void send_msg_userauth_banner() {
|
||||
void send_msg_userauth_banner(buffer *banner) {
|
||||
|
||||
TRACE(("enter send_msg_userauth_banner"))
|
||||
if (svr_opts.banner == NULL) {
|
||||
TRACE(("leave send_msg_userauth_banner: banner is NULL"))
|
||||
return;
|
||||
}
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_BANNER);
|
||||
buf_putstring(ses.writepayload, buf_getptr(svr_opts.banner,
|
||||
svr_opts.banner->len), svr_opts.banner->len);
|
||||
buf_putstring(ses.writepayload, buf_getptr(banner, banner->len),
|
||||
banner->len);
|
||||
buf_putstring(ses.writepayload, "en", 2);
|
||||
|
||||
encrypt_packet();
|
||||
buf_free(svr_opts.banner);
|
||||
svr_opts.banner = NULL;
|
||||
|
||||
TRACE(("leave send_msg_userauth_banner"))
|
||||
}
|
||||
@@ -110,6 +103,7 @@ void recv_msg_userauth_request() {
|
||||
|
||||
unsigned char *username = NULL, *servicename = NULL, *methodname = NULL;
|
||||
unsigned int userlen, servicelen, methodlen;
|
||||
int valid_user = 0;
|
||||
|
||||
TRACE(("enter recv_msg_userauth_request"))
|
||||
|
||||
@@ -121,10 +115,11 @@ void recv_msg_userauth_request() {
|
||||
|
||||
/* send the banner if it exists, it will only exist once */
|
||||
if (svr_opts.banner) {
|
||||
send_msg_userauth_banner();
|
||||
send_msg_userauth_banner(svr_opts.banner);
|
||||
buf_free(svr_opts.banner);
|
||||
svr_opts.banner = NULL;
|
||||
}
|
||||
|
||||
|
||||
username = buf_getstring(ses.payload, &userlen);
|
||||
servicename = buf_getstring(ses.payload, &servicelen);
|
||||
methodname = buf_getstring(ses.payload, &methodlen);
|
||||
@@ -141,23 +136,40 @@ void recv_msg_userauth_request() {
|
||||
dropbear_exit("unknown service in auth");
|
||||
}
|
||||
|
||||
/* check username is good before continuing.
|
||||
* the 'incrfail' varies depending on the auth method to
|
||||
* avoid giving away which users exist on the system through
|
||||
* the time delay. */
|
||||
if (checkusername(username, userlen) == DROPBEAR_SUCCESS) {
|
||||
valid_user = 1;
|
||||
}
|
||||
|
||||
/* user wants to know what methods are supported */
|
||||
if (methodlen == AUTH_METHOD_NONE_LEN &&
|
||||
strncmp(methodname, AUTH_METHOD_NONE,
|
||||
AUTH_METHOD_NONE_LEN) == 0) {
|
||||
TRACE(("recv_msg_userauth_request: 'none' request"))
|
||||
send_msg_userauth_failure(0, 0);
|
||||
goto out;
|
||||
if (valid_user
|
||||
&& svr_opts.allowblankpass
|
||||
&& !svr_opts.noauthpass
|
||||
&& !(svr_opts.norootpass && ses.authstate.pw_uid == 0)
|
||||
&& ses.authstate.pw_passwd[0] == '\0')
|
||||
{
|
||||
dropbear_log(LOG_NOTICE,
|
||||
"Auth succeeded with blank password for '%s' from %s",
|
||||
ses.authstate.pw_name,
|
||||
svr_ses.addrstring);
|
||||
send_msg_userauth_success();
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 'none' has no failure delay */
|
||||
send_msg_userauth_failure(0, 0);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* check username is good before continuing */
|
||||
if (checkusername(username, userlen) == DROPBEAR_FAILURE) {
|
||||
/* username is invalid/no shell/etc - send failure */
|
||||
TRACE(("sending checkusername failure"))
|
||||
send_msg_userauth_failure(0, 1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SVR_PASSWORD_AUTH
|
||||
if (!svr_opts.noauthpass &&
|
||||
!(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) {
|
||||
@@ -165,8 +177,10 @@ void recv_msg_userauth_request() {
|
||||
if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
|
||||
strncmp(methodname, AUTH_METHOD_PASSWORD,
|
||||
AUTH_METHOD_PASSWORD_LEN) == 0) {
|
||||
svr_auth_password();
|
||||
goto out;
|
||||
if (valid_user) {
|
||||
svr_auth_password();
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -178,8 +192,10 @@ void recv_msg_userauth_request() {
|
||||
if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
|
||||
strncmp(methodname, AUTH_METHOD_PASSWORD,
|
||||
AUTH_METHOD_PASSWORD_LEN) == 0) {
|
||||
svr_auth_pam();
|
||||
goto out;
|
||||
if (valid_user) {
|
||||
svr_auth_pam();
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -189,12 +205,17 @@ void recv_msg_userauth_request() {
|
||||
if (methodlen == AUTH_METHOD_PUBKEY_LEN &&
|
||||
strncmp(methodname, AUTH_METHOD_PUBKEY,
|
||||
AUTH_METHOD_PUBKEY_LEN) == 0) {
|
||||
svr_auth_pubkey();
|
||||
if (valid_user) {
|
||||
svr_auth_pubkey();
|
||||
} else {
|
||||
/* pubkey has no failure delay */
|
||||
send_msg_userauth_failure(0, 0);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* nothing matched, we just fail */
|
||||
/* nothing matched, we just fail with a delay */
|
||||
send_msg_userauth_failure(0, 1);
|
||||
|
||||
out:
|
||||
@@ -205,13 +226,13 @@ out:
|
||||
}
|
||||
|
||||
|
||||
/* Check that the username exists, has a non-empty password, and has a valid
|
||||
* shell.
|
||||
/* Check that the username exists and isn't disallowed (root), and has a valid shell.
|
||||
* returns DROPBEAR_SUCCESS on valid username, DROPBEAR_FAILURE on failure */
|
||||
static int checkusername(unsigned char *username, unsigned int userlen) {
|
||||
|
||||
char* listshell = NULL;
|
||||
char* usershell = NULL;
|
||||
int uid;
|
||||
TRACE(("enter checkusername"))
|
||||
if (userlen > MAX_USERNAME_LEN) {
|
||||
return DROPBEAR_FAILURE;
|
||||
@@ -237,7 +258,17 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
|
||||
dropbear_log(LOG_WARNING,
|
||||
"Login attempt for nonexistent user from %s",
|
||||
svr_ses.addrstring);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* check if we are running as non-root, and login user is different from the server */
|
||||
uid = geteuid();
|
||||
if (uid != 0 && uid != ses.authstate.pw_uid) {
|
||||
TRACE(("running as nonroot, only server uid is allowed"))
|
||||
dropbear_log(LOG_WARNING,
|
||||
"Login attempt with wrong user %s from %s",
|
||||
ses.authstate.pw_name,
|
||||
svr_ses.addrstring);
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
@@ -245,16 +276,6 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
|
||||
if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) {
|
||||
TRACE(("leave checkusername: root login disabled"))
|
||||
dropbear_log(LOG_WARNING, "root login rejected");
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* check for an empty password */
|
||||
if (ses.authstate.pw_passwd[0] == '\0') {
|
||||
TRACE(("leave checkusername: empty pword"))
|
||||
dropbear_log(LOG_WARNING, "User '%s' has blank password, rejected",
|
||||
ses.authstate.pw_name);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
@@ -283,7 +304,6 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
|
||||
TRACE(("no matching shell"))
|
||||
dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected",
|
||||
ses.authstate.pw_name);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return DROPBEAR_FAILURE;
|
||||
|
||||
goodshell:
|
||||
@@ -293,7 +313,6 @@ goodshell:
|
||||
TRACE(("uid = %d", ses.authstate.pw_uid))
|
||||
TRACE(("leave checkusername"))
|
||||
return DROPBEAR_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
/* Send a failure message to the client, in responds to a userauth_request.
|
||||
@@ -340,8 +359,8 @@ void send_msg_userauth_failure(int partial, int incrfail) {
|
||||
if (incrfail) {
|
||||
unsigned int delay;
|
||||
genrandom((unsigned char*)&delay, sizeof(delay));
|
||||
/* We delay for 300ms +- 50ms, 0.1ms granularity */
|
||||
delay = 250000 + (delay % 1000)*100;
|
||||
/* We delay for 300ms +- 50ms */
|
||||
delay = 250000 + (delay % 100000);
|
||||
usleep(delay);
|
||||
ses.authstate.failcount++;
|
||||
}
|
||||
|
||||
@@ -56,11 +56,7 @@ pamConvFunc(int num_msg,
|
||||
struct UserDataS* userDatap = (struct UserDataS*) appdata_ptr;
|
||||
unsigned int msg_len = 0;
|
||||
unsigned int i = 0;
|
||||
|
||||
const char* message = (*msg)->msg;
|
||||
|
||||
/* make a copy we can strip */
|
||||
char * compare_message = m_strdup(message);
|
||||
char * compare_message = NULL;
|
||||
|
||||
TRACE(("enter pamConvFunc"))
|
||||
|
||||
@@ -71,15 +67,10 @@ pamConvFunc(int num_msg,
|
||||
dropbear_log(LOG_INFO, "pamConvFunc() called with >1 messages: not supported.");
|
||||
return PAM_CONV_ERR;
|
||||
}
|
||||
|
||||
/* make a copy we can strip */
|
||||
compare_message = m_strdup((*msg)->msg);
|
||||
|
||||
TRACE(("msg_style is %d", (*msg)->msg_style))
|
||||
if (compare_message) {
|
||||
TRACE(("message is '%s'", compare_message))
|
||||
} else {
|
||||
TRACE(("null message"))
|
||||
}
|
||||
|
||||
|
||||
/* Make the string lowercase. */
|
||||
msg_len = strlen(compare_message);
|
||||
for (i = 0; i < msg_len; i++) {
|
||||
@@ -151,6 +142,22 @@ pamConvFunc(int num_msg,
|
||||
(*respp) = resp;
|
||||
break;
|
||||
|
||||
case PAM_ERROR_MSG:
|
||||
case PAM_TEXT_INFO:
|
||||
|
||||
if (msg_len > 0) {
|
||||
buffer * pam_err = buf_new(msg_len + 4);
|
||||
buf_setpos(pam_err, 0);
|
||||
buf_putbytes(pam_err, "\r\n", 2);
|
||||
buf_putbytes(pam_err, (*msg)->msg, msg_len);
|
||||
buf_putbytes(pam_err, "\r\n", 2);
|
||||
buf_setpos(pam_err, 0);
|
||||
|
||||
send_msg_userauth_banner(pam_err);
|
||||
buf_free(pam_err);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
TRACE(("Unknown message type"))
|
||||
rc = PAM_CONV_ERR;
|
||||
@@ -205,14 +212,14 @@ void svr_auth_pam() {
|
||||
|
||||
/* Init pam */
|
||||
if ((rc = pam_start("sshd", NULL, &pamConv, &pamHandlep)) != PAM_SUCCESS) {
|
||||
dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s\n",
|
||||
dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s",
|
||||
rc, pam_strerror(pamHandlep, rc));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* just to set it to something */
|
||||
if ((rc = pam_set_item(pamHandlep, PAM_TTY, "ssh") != PAM_SUCCESS)) {
|
||||
dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s\n",
|
||||
dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s",
|
||||
rc, pam_strerror(pamHandlep, rc));
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -225,7 +232,7 @@ void svr_auth_pam() {
|
||||
/* (void) pam_set_item(pamHandlep, PAM_FAIL_DELAY, (void*) pamDelayFunc); */
|
||||
|
||||
if ((rc = pam_authenticate(pamHandlep, 0)) != PAM_SUCCESS) {
|
||||
dropbear_log(LOG_WARNING, "pam_authenticate() failed, rc=%d, %s\n",
|
||||
dropbear_log(LOG_WARNING, "pam_authenticate() failed, rc=%d, %s",
|
||||
rc, pam_strerror(pamHandlep, rc));
|
||||
dropbear_log(LOG_WARNING,
|
||||
"Bad PAM password attempt for '%s' from %s",
|
||||
@@ -236,7 +243,7 @@ void svr_auth_pam() {
|
||||
}
|
||||
|
||||
if ((rc = pam_acct_mgmt(pamHandlep, 0)) != PAM_SUCCESS) {
|
||||
dropbear_log(LOG_WARNING, "pam_acct_mgmt() failed, rc=%d, %s\n",
|
||||
dropbear_log(LOG_WARNING, "pam_acct_mgmt() failed, rc=%d, %s",
|
||||
rc, pam_strerror(pamHandlep, rc));
|
||||
dropbear_log(LOG_WARNING,
|
||||
"Bad PAM password attempt for '%s' from %s",
|
||||
|
||||
@@ -29,16 +29,25 @@
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "auth.h"
|
||||
#include "runopts.h"
|
||||
|
||||
#ifdef ENABLE_SVR_PASSWORD_AUTH
|
||||
|
||||
static int constant_time_strcmp(const char* a, const char* b) {
|
||||
size_t la = strlen(a);
|
||||
size_t lb = strlen(b);
|
||||
|
||||
if (la != lb) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return constant_time_memcmp(a, b, la);
|
||||
}
|
||||
|
||||
/* Process a password auth request, sending success or failure messages as
|
||||
* appropriate */
|
||||
void svr_auth_password() {
|
||||
|
||||
#ifdef HAVE_SHADOW_H
|
||||
struct spwd *spasswd = NULL;
|
||||
#endif
|
||||
char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */
|
||||
char * testcrypt = NULL; /* crypt generated from the user's password sent */
|
||||
unsigned char * password;
|
||||
@@ -47,29 +56,12 @@ void svr_auth_password() {
|
||||
unsigned int changepw;
|
||||
|
||||
passwdcrypt = ses.authstate.pw_passwd;
|
||||
#ifdef HAVE_SHADOW_H
|
||||
/* get the shadow password if possible */
|
||||
spasswd = getspnam(ses.authstate.pw_name);
|
||||
if (spasswd != NULL && spasswd->sp_pwdp != NULL) {
|
||||
passwdcrypt = spasswd->sp_pwdp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_HACKCRYPT
|
||||
/* debugging crypt for non-root testing with shadows */
|
||||
passwdcrypt = DEBUG_HACKCRYPT;
|
||||
#endif
|
||||
|
||||
/* check for empty password - need to do this again here
|
||||
* since the shadow password may differ to that tested
|
||||
* in auth.c */
|
||||
if (passwdcrypt[0] == '\0') {
|
||||
dropbear_log(LOG_WARNING, "User '%s' has blank password, rejected",
|
||||
ses.authstate.pw_name);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if client wants to change password */
|
||||
changepw = buf_getbool(ses.payload);
|
||||
if (changepw) {
|
||||
@@ -85,7 +77,23 @@ void svr_auth_password() {
|
||||
m_burn(password, passwordlen);
|
||||
m_free(password);
|
||||
|
||||
if (strcmp(testcrypt, passwdcrypt) == 0) {
|
||||
if (testcrypt == NULL) {
|
||||
/* crypt() with an invalid salt like "!!" */
|
||||
dropbear_log(LOG_WARNING, "User account '%s' is locked",
|
||||
ses.authstate.pw_name);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check for empty password */
|
||||
if (passwdcrypt[0] == '\0') {
|
||||
dropbear_log(LOG_WARNING, "User '%s' has blank password, rejected",
|
||||
ses.authstate.pw_name);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (constant_time_strcmp(testcrypt, passwdcrypt) == 0) {
|
||||
/* successful authentication */
|
||||
dropbear_log(LOG_NOTICE,
|
||||
"Password auth succeeded for '%s' from %s",
|
||||
@@ -99,7 +107,6 @@ void svr_auth_password() {
|
||||
svr_ses.addrstring);
|
||||
send_msg_userauth_failure(0, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -92,14 +92,15 @@ int svr_pubkey_allows_pty() {
|
||||
* by any 'command' public key option. */
|
||||
void svr_pubkey_set_forced_command(struct ChanSess *chansess) {
|
||||
if (ses.authstate.pubkey_options) {
|
||||
ses.authstate.pubkey_options->original_command = chansess->cmd;
|
||||
if (!chansess->cmd)
|
||||
{
|
||||
ses.authstate.pubkey_options->original_command = m_strdup("");
|
||||
if (chansess->cmd) {
|
||||
/* original_command takes ownership */
|
||||
chansess->original_command = chansess->cmd;
|
||||
} else {
|
||||
chansess->original_command = m_strdup("");
|
||||
}
|
||||
chansess->cmd = ses.authstate.pubkey_options->forced_command;
|
||||
chansess->cmd = m_strdup(ses.authstate.pubkey_options->forced_command);
|
||||
#ifdef LOG_COMMANDS
|
||||
dropbear_log(LOG_INFO, "Command forced to '%s'", ses.authstate.pubkey_options->original_command);
|
||||
dropbear_log(LOG_INFO, "Command forced to '%s'", chansess->original_command);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -142,7 +143,7 @@ int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filena
|
||||
ses.authstate.pubkey_options->no_port_forwarding_flag = 1;
|
||||
goto next_option;
|
||||
}
|
||||
#ifdef ENABLE_AGENTFWD
|
||||
#ifdef ENABLE_SVR_AGENTFWD
|
||||
if (match_option(options_buf, "no-agent-forwarding") == DROPBEAR_SUCCESS) {
|
||||
dropbear_log(LOG_WARNING, "Agent forwarding disabled.");
|
||||
ses.authstate.pubkey_options->no_agent_forwarding_flag = 1;
|
||||
|
||||
@@ -137,6 +137,7 @@ static void sesssigchild_handler(int UNUSED(dummy)) {
|
||||
|
||||
sa_chld.sa_handler = sesssigchild_handler;
|
||||
sa_chld.sa_flags = SA_NOCLDSTOP;
|
||||
sigemptyset(&sa_chld.sa_mask);
|
||||
sigaction(SIGCHLD, &sa_chld, NULL);
|
||||
TRACE(("leave sigchld handler"))
|
||||
}
|
||||
@@ -217,6 +218,8 @@ static int newchansess(struct Channel *channel) {
|
||||
|
||||
struct ChanSess *chansess;
|
||||
|
||||
TRACE(("new chansess %p", channel))
|
||||
|
||||
dropbear_assert(channel->typedata == NULL);
|
||||
|
||||
chansess = (struct ChanSess*)m_malloc(sizeof(struct ChanSess));
|
||||
@@ -240,7 +243,7 @@ static int newchansess(struct Channel *channel) {
|
||||
chansess->x11authcookie = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_AGENTFWD
|
||||
#ifdef ENABLE_SVR_AGENTFWD
|
||||
chansess->agentlistener = NULL;
|
||||
chansess->agentfile = NULL;
|
||||
chansess->agentdir = NULL;
|
||||
@@ -279,6 +282,10 @@ static void closechansess(struct Channel *channel) {
|
||||
m_free(chansess->cmd);
|
||||
m_free(chansess->term);
|
||||
|
||||
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
|
||||
m_free(chansess->original_command);
|
||||
#endif
|
||||
|
||||
if (chansess->tty) {
|
||||
/* write the utmp/wtmp login record */
|
||||
li = chansess_login_alloc(chansess);
|
||||
@@ -293,7 +300,7 @@ static void closechansess(struct Channel *channel) {
|
||||
x11cleanup(chansess);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_AGENTFWD
|
||||
#ifdef ENABLE_SVR_AGENTFWD
|
||||
svr_agentcleanup(chansess);
|
||||
#endif
|
||||
|
||||
@@ -351,7 +358,7 @@ static void chansessionrequest(struct Channel *channel) {
|
||||
} else if (strcmp(type, "x11-req") == 0) {
|
||||
ret = x11req(chansess);
|
||||
#endif
|
||||
#ifdef ENABLE_AGENTFWD
|
||||
#ifdef ENABLE_SVR_AGENTFWD
|
||||
} else if (strcmp(type, "auth-agent-req@openssh.com") == 0) {
|
||||
ret = svr_agentreq(chansess);
|
||||
#endif
|
||||
@@ -651,7 +658,7 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
|
||||
|
||||
/* uClinux will vfork(), so there'll be a race as
|
||||
connection_string is freed below. */
|
||||
#ifndef __uClinux__
|
||||
#ifndef USE_VFORK
|
||||
chansess->connection_string = make_connection_string();
|
||||
#endif
|
||||
|
||||
@@ -663,7 +670,7 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
|
||||
ret = ptycommand(channel, chansess);
|
||||
}
|
||||
|
||||
#ifndef __uClinux__
|
||||
#ifndef USE_VFORK
|
||||
m_free(chansess->connection_string);
|
||||
#endif
|
||||
|
||||
@@ -705,6 +712,7 @@ static int noptycommand(struct Channel *channel, struct ChanSess *chansess) {
|
||||
TRACE(("found match for lastexitpid"))
|
||||
svr_ses.childpids[i].chansess->exit = svr_ses.lastexit;
|
||||
svr_ses.lastexit.exitpid = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -735,7 +743,7 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef __uClinux__
|
||||
#ifdef USE_VFORK
|
||||
pid = vfork();
|
||||
#else
|
||||
pid = fork();
|
||||
@@ -853,15 +861,15 @@ static void execchild(void *user_data) {
|
||||
struct ChanSess *chansess = user_data;
|
||||
char *usershell = NULL;
|
||||
|
||||
/* with uClinux we'll have vfork()ed, so don't want to overwrite the
|
||||
* hostkey. can't think of a workaround to clear it */
|
||||
#ifndef __uClinux__
|
||||
/* with uClinux we'll have vfork()ed, so don't want to overwrite the
|
||||
* hostkey. can't think of a workaround to clear it */
|
||||
#ifndef USE_VFORK
|
||||
/* wipe the hostkey */
|
||||
sign_key_free(svr_opts.hostkey);
|
||||
svr_opts.hostkey = NULL;
|
||||
|
||||
/* overwrite the prng state */
|
||||
reseedrandom();
|
||||
seedrandom();
|
||||
#endif
|
||||
|
||||
/* clear environment */
|
||||
@@ -921,10 +929,8 @@ static void execchild(void *user_data) {
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
|
||||
if (ses.authstate.pubkey_options &&
|
||||
ses.authstate.pubkey_options->original_command) {
|
||||
addnewvar("SSH_ORIGINAL_COMMAND",
|
||||
ses.authstate.pubkey_options->original_command);
|
||||
if (chansess->original_command) {
|
||||
addnewvar("SSH_ORIGINAL_COMMAND", chansess->original_command);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -937,7 +943,7 @@ static void execchild(void *user_data) {
|
||||
/* set up X11 forwarding if enabled */
|
||||
x11setauth(chansess);
|
||||
#endif
|
||||
#ifdef ENABLE_AGENTFWD
|
||||
#ifdef ENABLE_SVR_AGENTFWD
|
||||
/* set up agent env variable */
|
||||
svr_agentset(chansess);
|
||||
#endif
|
||||
@@ -973,6 +979,7 @@ void svr_chansessinitialise() {
|
||||
svr_ses.lastexit.exitpid = -1; /* Nothing has exited yet */
|
||||
sa_chld.sa_handler = sesssigchild_handler;
|
||||
sa_chld.sa_flags = SA_NOCLDSTOP;
|
||||
sigemptyset(&sa_chld.sa_mask);
|
||||
if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) {
|
||||
dropbear_exit("signal() error");
|
||||
}
|
||||
|
||||
@@ -61,7 +61,8 @@ void recv_msg_kexdh_init() {
|
||||
mp_clear(&dh_e);
|
||||
|
||||
send_msg_newkeys();
|
||||
ses.requirenext = SSH_MSG_NEWKEYS;
|
||||
ses.requirenext[0] = SSH_MSG_NEWKEYS;
|
||||
ses.requirenext[1] = 0;
|
||||
TRACE(("leave recv_msg_kexdh_init"))
|
||||
}
|
||||
|
||||
|
||||
@@ -254,6 +254,8 @@ void main_noinetd() {
|
||||
goto out;
|
||||
}
|
||||
|
||||
seedrandom();
|
||||
|
||||
if (pipe(childpipe) < 0) {
|
||||
TRACE(("error creating child pipe"))
|
||||
goto out;
|
||||
@@ -267,8 +269,11 @@ void main_noinetd() {
|
||||
if (fork_ret < 0) {
|
||||
dropbear_log(LOG_WARNING, "Error forking: %s", strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
} else if (fork_ret > 0) {
|
||||
addrandom((void*)&fork_ret, sizeof(fork_ret));
|
||||
|
||||
if (fork_ret > 0) {
|
||||
|
||||
/* parent */
|
||||
childpipes[conn_idx] = childpipe[0];
|
||||
@@ -370,6 +375,7 @@ static void commonsetup() {
|
||||
/* catch and reap zombie children */
|
||||
sa_chld.sa_handler = sigchld_handler;
|
||||
sa_chld.sa_flags = SA_NOCLDSTOP;
|
||||
sigemptyset(&sa_chld.sa_mask);
|
||||
if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) {
|
||||
dropbear_exit("signal() error");
|
||||
}
|
||||
|
||||
@@ -36,9 +36,8 @@ static void addportandaddress(char* spec);
|
||||
|
||||
static void printhelp(const char * progname) {
|
||||
|
||||
fprintf(stderr, "Dropbear sshd v%s\n"
|
||||
fprintf(stderr, "Dropbear server v%s https://matt.ucc.asn.au/dropbear/dropbear.html\n"
|
||||
"Usage: %s [options]\n"
|
||||
"Options are:\n"
|
||||
"-b bannerfile Display the contents of bannerfile"
|
||||
" before user login\n"
|
||||
" (default: none)\n"
|
||||
@@ -63,6 +62,7 @@ static void printhelp(const char * progname) {
|
||||
#if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH)
|
||||
"-s Disable password logins\n"
|
||||
"-g Disable password logins for root\n"
|
||||
"-B Allow blank password logins\n"
|
||||
#endif
|
||||
#ifdef ENABLE_SVR_LOCALTCPFWD
|
||||
"-j Disable local port forwarding\n"
|
||||
@@ -81,8 +81,8 @@ static void printhelp(const char * progname) {
|
||||
"-i Start for inetd\n"
|
||||
#endif
|
||||
"-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
|
||||
"-K <keepalive> (0 is never, default %d)\n"
|
||||
"-I <idle_timeout> (0 is never, default %d)\n"
|
||||
"-K <keepalive> (0 is never, default %d, in seconds)\n"
|
||||
"-I <idle_timeout> (0 is never, default %d, in seconds)\n"
|
||||
#ifdef DEBUG_TRACE
|
||||
"-v verbose (compiled with DEBUG_TRACE)\n"
|
||||
#endif
|
||||
@@ -115,6 +115,7 @@ void svr_getopts(int argc, char ** argv) {
|
||||
svr_opts.norootlogin = 0;
|
||||
svr_opts.noauthpass = 0;
|
||||
svr_opts.norootpass = 0;
|
||||
svr_opts.allowblankpass = 0;
|
||||
svr_opts.inetdmode = 0;
|
||||
svr_opts.portcount = 0;
|
||||
svr_opts.hostkey = NULL;
|
||||
@@ -234,6 +235,9 @@ void svr_getopts(int argc, char ** argv) {
|
||||
case 'g':
|
||||
svr_opts.norootpass = 1;
|
||||
break;
|
||||
case 'B':
|
||||
svr_opts.allowblankpass = 1;
|
||||
break;
|
||||
#endif
|
||||
case 'h':
|
||||
printhelp(argv[0]);
|
||||
@@ -324,8 +328,23 @@ static void addportandaddress(char* spec) {
|
||||
/* We don't free it, it becomes part of the runopt state */
|
||||
myspec = m_strdup(spec);
|
||||
|
||||
/* search for ':', that separates address and port */
|
||||
svr_opts.ports[svr_opts.portcount] = strchr(myspec, ':');
|
||||
if (myspec[0] == '[') {
|
||||
myspec++;
|
||||
svr_opts.ports[svr_opts.portcount] = strchr(myspec, ']');
|
||||
if (svr_opts.ports[svr_opts.portcount] == NULL) {
|
||||
/* Unmatched [ -> exit */
|
||||
dropbear_exit("Bad listen address");
|
||||
}
|
||||
svr_opts.ports[svr_opts.portcount][0] = '\0';
|
||||
svr_opts.ports[svr_opts.portcount]++;
|
||||
if (svr_opts.ports[svr_opts.portcount][0] != ':') {
|
||||
/* Missing port -> exit */
|
||||
dropbear_exit("Missing port");
|
||||
}
|
||||
} else {
|
||||
/* search for ':', that separates address and port */
|
||||
svr_opts.ports[svr_opts.portcount] = strrchr(myspec, ':');
|
||||
}
|
||||
|
||||
if (svr_opts.ports[svr_opts.portcount] == NULL) {
|
||||
/* no ':' -> the whole string specifies just a port */
|
||||
|
||||
@@ -52,9 +52,7 @@ static const packettype svr_packettypes[] = {
|
||||
{SSH_MSG_KEXINIT, recv_msg_kexinit},
|
||||
{SSH_MSG_KEXDH_INIT, recv_msg_kexdh_init}, /* server */
|
||||
{SSH_MSG_NEWKEYS, recv_msg_newkeys},
|
||||
#ifdef ENABLE_SVR_REMOTETCPFWD
|
||||
{SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_remotetcp},
|
||||
#endif
|
||||
{SSH_MSG_CHANNEL_REQUEST, recv_msg_channel_request},
|
||||
{SSH_MSG_CHANNEL_OPEN, recv_msg_channel_open},
|
||||
{SSH_MSG_CHANNEL_EOF, recv_msg_channel_eof},
|
||||
@@ -74,17 +72,23 @@ static const struct ChanType *svr_chantypes[] = {
|
||||
NULL /* Null termination is mandatory. */
|
||||
};
|
||||
|
||||
static void
|
||||
svr_session_cleanup(void)
|
||||
{
|
||||
/* free potential public key options */
|
||||
svr_pubkey_options_cleanup();
|
||||
}
|
||||
|
||||
void svr_session(int sock, int childpipe) {
|
||||
char *host, *port;
|
||||
size_t len;
|
||||
reseedrandom();
|
||||
|
||||
crypto_init();
|
||||
common_session_init(sock, sock);
|
||||
|
||||
/* Initialise server specific parts of the session */
|
||||
svr_ses.childpipe = childpipe;
|
||||
#ifdef __uClinux__
|
||||
#ifdef USE_VFORK
|
||||
svr_ses.server_pid = getpid();
|
||||
#endif
|
||||
svr_authinitialise();
|
||||
@@ -106,10 +110,10 @@ void svr_session(int sock, int childpipe) {
|
||||
|
||||
/* set up messages etc */
|
||||
ses.remoteclosed = svr_remoteclosed;
|
||||
ses.extra_session_cleanup = svr_session_cleanup;
|
||||
|
||||
/* packet handlers */
|
||||
ses.packettypes = svr_packettypes;
|
||||
ses.buf_match_algo = svr_buf_match_algo;
|
||||
|
||||
ses.isserver = 1;
|
||||
|
||||
@@ -117,7 +121,7 @@ void svr_session(int sock, int childpipe) {
|
||||
sessinitdone = 1;
|
||||
|
||||
/* exchange identification, version etc */
|
||||
session_identification();
|
||||
send_session_identification();
|
||||
|
||||
/* start off with key exchange */
|
||||
send_msg_kexinit();
|
||||
@@ -157,19 +161,14 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) {
|
||||
|
||||
_dropbear_log(LOG_INFO, fmtbuf, param);
|
||||
|
||||
#ifdef __uClinux__
|
||||
/* only the main server process should cleanup - we don't want
|
||||
#ifdef USE_VFORK
|
||||
/* For uclinux only the main server process should cleanup - we don't want
|
||||
* forked children doing that */
|
||||
if (svr_ses.server_pid == getpid())
|
||||
#else
|
||||
if (1)
|
||||
#endif
|
||||
{
|
||||
/* free potential public key options */
|
||||
svr_pubkey_options_cleanup();
|
||||
|
||||
/* must be after we've done with username etc */
|
||||
common_session_cleanup();
|
||||
session_cleanup();
|
||||
}
|
||||
|
||||
exit(exitcode);
|
||||
@@ -205,7 +204,7 @@ void svr_dropbear_log(int priority, const char* format, va_list param) {
|
||||
local_tm = localtime(×ec);
|
||||
if (local_tm == NULL
|
||||
|| strftime(datestr, sizeof(datestr), "%b %d %H:%M:%S",
|
||||
localtime(×ec)) == 0)
|
||||
local_tm) == 0)
|
||||
{
|
||||
/* upon failure, just print the epoch-seconds time. */
|
||||
snprintf(datestr, sizeof(datestr), "%d", (int)timesec);
|
||||
|
||||
74
svr-tcpfwd.c
74
svr-tcpfwd.c
@@ -34,24 +34,31 @@
|
||||
#include "runopts.h"
|
||||
#include "auth.h"
|
||||
|
||||
#ifdef ENABLE_SVR_REMOTETCPFWD
|
||||
static void send_msg_request_failure();
|
||||
|
||||
static void send_msg_request_failure() {
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE);
|
||||
encrypt_packet();
|
||||
}
|
||||
|
||||
#ifndef ENABLE_SVR_REMOTETCPFWD
|
||||
|
||||
/* This is better than SSH_MSG_UNIMPLEMENTED */
|
||||
void recv_msg_global_request_remotetcp() {
|
||||
TRACE(("recv_msg_global_request_remotetcp: remote tcp forwarding not compiled in"))
|
||||
send_msg_request_failure();
|
||||
}
|
||||
|
||||
/* */
|
||||
#endif /* !ENABLE_SVR_REMOTETCPFWD */
|
||||
|
||||
static void send_msg_request_success();
|
||||
static void send_msg_request_failure();
|
||||
static int svr_cancelremotetcp();
|
||||
static int svr_remotetcpreq();
|
||||
static int newtcpdirect(struct Channel * channel);
|
||||
|
||||
|
||||
const struct ChanType svr_chan_tcpdirect = {
|
||||
1, /* sepfds */
|
||||
"direct-tcpip",
|
||||
newtcpdirect, /* init */
|
||||
NULL, /* checkclose */
|
||||
NULL, /* reqhandler */
|
||||
NULL /* closehandler */
|
||||
};
|
||||
|
||||
#ifdef ENABLE_SVR_REMOTETCPFWD
|
||||
static const struct ChanType svr_chan_tcpremote = {
|
||||
1, /* sepfds */
|
||||
"forwarded-tcpip",
|
||||
@@ -117,14 +124,6 @@ static void send_msg_request_success() {
|
||||
|
||||
}
|
||||
|
||||
static void send_msg_request_failure() {
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE);
|
||||
encrypt_packet();
|
||||
|
||||
}
|
||||
|
||||
static int matchtcp(void* typedata1, void* typedata2) {
|
||||
|
||||
const struct TCPListener *info1 = (struct TCPListener*)typedata1;
|
||||
@@ -173,14 +172,14 @@ out:
|
||||
static int svr_remotetcpreq() {
|
||||
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
unsigned char * bindaddr = NULL;
|
||||
unsigned char * request_addr = NULL;
|
||||
unsigned int addrlen;
|
||||
struct TCPListener *tcpinfo = NULL;
|
||||
unsigned int port;
|
||||
|
||||
TRACE(("enter remotetcpreq"))
|
||||
|
||||
bindaddr = buf_getstring(ses.payload, &addrlen);
|
||||
request_addr = buf_getstring(ses.payload, &addrlen);
|
||||
if (addrlen > MAX_IP_LEN) {
|
||||
TRACE(("addr len too long: %d", addrlen))
|
||||
goto out;
|
||||
@@ -210,15 +209,15 @@ static int svr_remotetcpreq() {
|
||||
tcpinfo->chantype = &svr_chan_tcpremote;
|
||||
tcpinfo->tcp_type = forwarded;
|
||||
|
||||
if (!opts.listen_fwd_all
|
||||
|| (strcmp(tcpinfo->listenaddr, "localhost") == 0) ) {
|
||||
tcpinfo->request_listenaddr = request_addr;
|
||||
if (!opts.listen_fwd_all || (strcmp(request_addr, "localhost") == 0) ) {
|
||||
// NULL means "localhost only"
|
||||
tcpinfo->listenaddr = NULL;
|
||||
tcpinfo->listenaddr = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
tcpinfo->listenaddr = request_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
tcpinfo->listenaddr = bindaddr;
|
||||
}
|
||||
|
||||
ret = listen_tcpfwd(tcpinfo);
|
||||
|
||||
@@ -226,13 +225,26 @@ out:
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
/* we only free it if a listener wasn't created, since the listener
|
||||
* has to remember it if it's to be cancelled */
|
||||
m_free(bindaddr);
|
||||
m_free(request_addr);
|
||||
m_free(tcpinfo);
|
||||
}
|
||||
TRACE(("leave remotetcpreq"))
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* ENABLE_SVR_REMOTETCPFWD */
|
||||
|
||||
#ifdef ENABLE_SVR_LOCALTCPFWD
|
||||
|
||||
const struct ChanType svr_chan_tcpdirect = {
|
||||
1, /* sepfds */
|
||||
"direct-tcpip",
|
||||
newtcpdirect, /* init */
|
||||
NULL, /* checkclose */
|
||||
NULL, /* reqhandler */
|
||||
NULL /* closehandler */
|
||||
};
|
||||
|
||||
/* Called upon creating a new direct tcp channel (ie we connect out to an
|
||||
* address */
|
||||
static int newtcpdirect(struct Channel * channel) {
|
||||
@@ -297,4 +309,4 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* ENABLE_SVR_LOCALTCPFWD */
|
||||
|
||||
@@ -175,7 +175,7 @@ void x11cleanup(struct ChanSess *chansess) {
|
||||
m_free(chansess->x11authprot);
|
||||
m_free(chansess->x11authcookie);
|
||||
|
||||
TRACE(("chansess %s", chansess))
|
||||
TRACE(("chansess %p", chansess))
|
||||
if (chansess->x11listener != NULL) {
|
||||
remove_listener(chansess->x11listener);
|
||||
chansess->x11listener = NULL;
|
||||
|
||||
68
sysoptions.h
68
sysoptions.h
@@ -4,7 +4,7 @@
|
||||
*******************************************************************/
|
||||
|
||||
#ifndef DROPBEAR_VERSION
|
||||
#define DROPBEAR_VERSION "0.53.1"
|
||||
#define DROPBEAR_VERSION "2013.59"
|
||||
#endif
|
||||
|
||||
#define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
|
||||
@@ -23,6 +23,15 @@
|
||||
#define AUTH_TIMEOUT 300 /* we choose 5 minutes */
|
||||
#endif
|
||||
|
||||
/* A client should try and send an initial key exchange packet guessing
|
||||
* the algorithm that will match - saves a round trip connecting, has little
|
||||
* overhead if the guess was "wrong". */
|
||||
#define USE_KEX_FIRST_FOLLOWS
|
||||
/* Use protocol extension to allow "first follows" to succeed more frequently.
|
||||
* This is currently Dropbear-specific but will gracefully fallback when connecting
|
||||
* to other implementations. */
|
||||
#define USE_KEXGUESS2
|
||||
|
||||
/* Minimum key sizes for DSS and RSA */
|
||||
#ifndef MIN_DSS_KEYLEN
|
||||
#define MIN_DSS_KEYLEN 512
|
||||
@@ -54,13 +63,16 @@
|
||||
|
||||
#define _PATH_CP "/bin/cp"
|
||||
|
||||
#define DROPBEAR_ESCAPE_CHAR '~'
|
||||
|
||||
/* success/failure defines */
|
||||
#define DROPBEAR_SUCCESS 0
|
||||
#define DROPBEAR_FAILURE -1
|
||||
|
||||
/* various algorithm identifiers */
|
||||
#define DROPBEAR_KEX_DH_GROUP1 0
|
||||
#define DROPBEAR_KEX_DH_GROUP14 1
|
||||
#define DROPBEAR_KEX_NONE 0
|
||||
#define DROPBEAR_KEX_DH_GROUP1 1
|
||||
#define DROPBEAR_KEX_DH_GROUP14 2
|
||||
|
||||
#define DROPBEAR_SIGNKEY_ANY 0
|
||||
#define DROPBEAR_SIGNKEY_RSA 1
|
||||
@@ -76,21 +88,20 @@
|
||||
#define DROPBEAR_SIGNKEY_VERIFY
|
||||
#endif
|
||||
|
||||
/* SHA1 is 20 bytes == 160 bits */
|
||||
#define SHA1_HASH_SIZE 20
|
||||
/* SHA512 is 64 bytes == 512 bits */
|
||||
#define SHA512_HASH_SIZE 64
|
||||
/* MD5 is 16 bytes = 128 bits */
|
||||
#define MD5_HASH_SIZE 16
|
||||
|
||||
/* largest of MD5 and SHA1 */
|
||||
#define MAX_MAC_LEN SHA1_HASH_SIZE
|
||||
|
||||
|
||||
#define MAX_KEY_LEN 32 /* 256 bits for aes256 etc */
|
||||
#define MAX_IV_LEN 20 /* must be same as max blocksize,
|
||||
and >= SHA1_HASH_SIZE */
|
||||
#define MAX_MAC_KEY 20
|
||||
|
||||
#if defined(DROPBEAR_SHA2_512_HMAC)
|
||||
#define MAX_MAC_LEN 64
|
||||
#elif defined(DROPBEAR_SHA2_256_HMAC)
|
||||
#define MAX_MAC_LEN 32
|
||||
#else
|
||||
#define MAX_MAC_LEN 20
|
||||
#endif
|
||||
|
||||
#define MAX_NAME_LEN 64 /* maximum length of a protocol name, isn't
|
||||
explicitly specified for all protocols (just
|
||||
@@ -144,6 +155,19 @@
|
||||
#define DROPBEAR_TWOFISH
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
#define DROPBEAR_MD5
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_SHA2_256_HMAC
|
||||
#define DROPBEAR_SHA256
|
||||
#endif
|
||||
|
||||
#if (defined(DROPBEAR_DSS) && defined(DSS_PROTOK)) \
|
||||
|| defined(DROPBEAR_SHA2_512_HMAC)
|
||||
#define DROPBEAR_SHA512
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_X11FWD
|
||||
#define DISABLE_X11FWD
|
||||
#endif
|
||||
@@ -162,10 +186,6 @@
|
||||
#define USING_LISTENERS
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_SVR_AGENTFWD) || defined(ENABLE_CLI_LOCALTCPFWD)
|
||||
#define ENABLE_AGENTFWD
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_CLI_NETCAT) && defined(ENABLE_CLI_PROXYCMD)
|
||||
#define ENABLE_CLI_MULTIHOP
|
||||
#endif
|
||||
@@ -186,14 +206,6 @@
|
||||
#error "You can't turn on PASSWORD and PAM auth both at once. Fix it in options.h"
|
||||
#endif
|
||||
|
||||
#if defined(DROPBEAR_RANDOM_DEV) && defined(DROPBEAR_PRNGD_SOCKET)
|
||||
#error "You can't turn on DROPBEAR_PRNGD_SOCKET and DROPBEAR_RANDOM_DEV at once"
|
||||
#endif
|
||||
|
||||
#if !defined(DROPBEAR_RANDOM_DEV) && !defined(DROPBEAR_PRNGD_SOCKET)
|
||||
#error "You must choose one of DROPBEAR_PRNGD_SOCKET or DROPBEAR_RANDOM_DEV in options.h"
|
||||
#endif
|
||||
|
||||
/* We use dropbear_client and dropbear_server as shortcuts to avoid redundant
|
||||
* code, if we're just compiling as client or server */
|
||||
#if defined(DROPBEAR_SERVER) && defined(DROPBEAR_CLIENT)
|
||||
@@ -216,4 +228,10 @@
|
||||
#define IS_DROPBEAR_SERVER 0
|
||||
#define IS_DROPBEAR_CLIENT 0
|
||||
|
||||
#endif
|
||||
#endif /* neither DROPBEAR_SERVER nor DROPBEAR_CLIENT */
|
||||
|
||||
#ifndef HAVE_FORK
|
||||
#define USE_VFORK
|
||||
#endif /* don't HAVE_FORK */
|
||||
|
||||
/* no include guard for this file */
|
||||
|
||||
@@ -40,6 +40,7 @@ static void cleanup_tcp(struct Listener *listener) {
|
||||
|
||||
m_free(tcpinfo->sendaddr);
|
||||
m_free(tcpinfo->listenaddr);
|
||||
m_free(tcpinfo->request_listenaddr);
|
||||
m_free(tcpinfo);
|
||||
}
|
||||
|
||||
@@ -61,6 +62,7 @@ static void tcp_acceptor(struct Listener *listener, int sock) {
|
||||
if (getnameinfo((struct sockaddr*)&addr, len, ipstring, sizeof(ipstring),
|
||||
portstring, sizeof(portstring),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
|
||||
m_close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -77,10 +79,13 @@ static void tcp_acceptor(struct Listener *listener, int sock) {
|
||||
dropbear_assert(tcpinfo->tcp_type == forwarded);
|
||||
/* "forwarded-tcpip" */
|
||||
/* address that was connected, port that was connected */
|
||||
addr = tcpinfo->listenaddr;
|
||||
addr = tcpinfo->request_listenaddr;
|
||||
port = tcpinfo->listenport;
|
||||
}
|
||||
|
||||
if (addr == NULL) {
|
||||
addr = "localhost";
|
||||
}
|
||||
buf_putstring(ses.writepayload, addr, strlen(addr));
|
||||
buf_putint(ses.writepayload, port);
|
||||
|
||||
|
||||
2
tcpfwd.h
2
tcpfwd.h
@@ -39,6 +39,8 @@ struct TCPListener {
|
||||
* localhost, or a normal interface name. */
|
||||
unsigned char *listenaddr;
|
||||
unsigned int listenport;
|
||||
/* The address that the remote host asked to listen on */
|
||||
unsigned char *request_listenaddr;;
|
||||
|
||||
const struct ChanType *chantype;
|
||||
enum {direct, forwarded} tcp_type;
|
||||
|
||||
@@ -107,8 +107,14 @@ const struct TermCode termcodes[MAX_TERMCODE+1] = {
|
||||
#else
|
||||
{0, 0},
|
||||
#endif
|
||||
{0, 0}, /* 42 */
|
||||
/* IUTF8 isn't standardised in rfc4254 but is likely soon.
|
||||
* Implemented by linux and darwin */
|
||||
#ifdef IUTF8
|
||||
{IUTF8, TERMCODE_INPUT},
|
||||
#else
|
||||
{0, 0},
|
||||
#endif
|
||||
{0, 0}, /* 43 */
|
||||
{0, 0},
|
||||
{0, 0},
|
||||
{0, 0},
|
||||
|
||||
Reference in New Issue
Block a user