Index: head/crypto/openssh/ChangeLog =================================================================== --- head/crypto/openssh/ChangeLog (revision 294495) +++ head/crypto/openssh/ChangeLog (revision 294496) @@ -1,9146 +1,7615 @@ +commit c88ac102f0eb89f2eaa314cb2e2e0ca3c890c443 +Author: Damien Miller +Date: Thu Jan 14 11:08:19 2016 +1100 + + bump version numbers + +commit 302bc21e6fadacb04b665868cd69b625ef69df90 +Author: Damien Miller +Date: Thu Jan 14 11:04:04 2016 +1100 + + openssh-7.1p2 + +commit 6b33763242c063e4e0593877e835eeb1fd1b60aa +Author: Damien Miller +Date: Thu Jan 14 11:02:58 2016 +1100 + + forcibly disable roaming support in the client + +commit 34d364f0d2e1e30a444009f0e04299bb7c94ba13 +Author: djm@openbsd.org +Date: Mon Oct 5 17:11:21 2015 +0000 + + upstream commit + + some more bzero->explicit_bzero, from Michael McConville + + Upstream-ID: 17f19545685c33327db2efdc357c1c9225ff00d0 + +commit 8f5b93026797b9f7fba90d0c717570421ccebbd3 +Author: guenther@openbsd.org +Date: Fri Sep 11 08:50:04 2015 +0000 + + upstream commit + + Use explicit_bzero() when zeroing before free() + + from Michael McConville (mmcconv1 (at) sccs.swarthmore.edu) + ok millert@ djm@ + + Upstream-ID: 2e3337db046c3fe70c7369ee31515ac73ec00f50 + +commit d77148e3a3ef6c29b26ec74331455394581aa257 +Author: djm@openbsd.org +Date: Sun Nov 8 21:59:11 2015 +0000 + + upstream commit + + fix OOB read in packet code caused by missing return + statement found by Ben Hawkes; ok markus@ deraadt@ + + Upstream-ID: a3e3a85434ebfa0690d4879091959591f30efc62 + +commit 076d849e17ab12603627f87b301e2dca71bae518 +Author: Damien Miller +Date: Sat Nov 14 18:44:49 2015 +1100 + + read back from libcrypto RAND when privdropping + + makes certain libcrypto implementations cache a /dev/urandom fd + in preparation of sandboxing. Based on patch by Greg Hartman. + +commit f72adc0150011a28f177617a8456e1f83733099d +Author: djm@openbsd.org +Date: Sun Dec 13 22:42:23 2015 +0000 + + upstream commit + + unbreak connections with peers that set + first_kex_follows; fix from Matt Johnston va bz#2515 + + Upstream-ID: decc88ec4fc7515594fdb42b04aa03189a44184b + +commit 04bd8d019ccd906cac1a2b362517b8505f3759e6 +Author: djm@openbsd.org +Date: Tue Jan 12 23:42:54 2016 +0000 + + upstream commit + + use explicit_bzero() more liberally in the buffer code; ok + deraadt + + Upstream-ID: 0ece37069fd66bc6e4f55eb1321f93df372b65bf + +commit e91346dc2bbf460246df2ab591b7613908c1b0ad +Author: Damien Miller +Date: Fri Aug 21 14:49:03 2015 +1000 + + we don't use Github for issues/pull-requests + +commit a4f5b507c708cc3dc2c8dd2d02e4416d7514dc23 +Author: Damien Miller +Date: Fri Aug 21 14:43:55 2015 +1000 + + fix URL for connect.c + +commit d026a8d3da0f8186598442997c7d0a28e7275414 +Author: Damien Miller +Date: Fri Aug 21 13:47:10 2015 +1000 + + update version numbers for 7.1 + +commit 78f8f589f0ca1c9f41e5a9bae3cda5ce8a6b42ed +Author: djm@openbsd.org +Date: Fri Aug 21 03:45:26 2015 +0000 + + upstream commit + + openssh-7.1 + + Upstream-ID: ff7b1ef4b06caddfb45e08ba998128c88be3d73f + +commit 32a181980c62fce94f7f9ffaf6a79d90f0c309cf +Author: djm@openbsd.org +Date: Fri Aug 21 03:42:19 2015 +0000 + + upstream commit + + fix inverted logic that broke PermitRootLogin; reported + by Mantas Mikulenas; ok markus@ + + Upstream-ID: 260dd6a904c1bb7e43267e394b1c9cf70bdd5ea5 + +commit ce445b0ed927e45bd5bdce8f836eb353998dd65c +Author: deraadt@openbsd.org +Date: Thu Aug 20 22:32:42 2015 +0000 + + upstream commit + + Do not cast result of malloc/calloc/realloc* if stdlib.h + is in scope ok krw millert + + Upstream-ID: 5e50ded78cadf3841556649a16cc4b1cb6c58667 + +commit 05291e5288704d1a98bacda269eb5a0153599146 +Author: naddy@openbsd.org +Date: Thu Aug 20 19:20:06 2015 +0000 + + upstream commit + + In the certificates section, be consistent about using + "host_key" and "user_key" for the respective key types. ok sthen@ deraadt@ + + Upstream-ID: 9e037ea3b15577b238604c5533e082a3947f13cb + +commit 8543d4ef6f2e9f98c3e6b77c894ceec30c5e4ae4 +Author: djm@openbsd.org +Date: Wed Aug 19 23:21:42 2015 +0000 + + upstream commit + + Better compat matching for WinSCP, add compat matching + for FuTTY (fork of PuTTY); ok markus@ deraadt@ + + Upstream-ID: 24001d1ac115fa3260fbdc329a4b9aeb283c5389 + +commit ec6eda16ebab771aa3dfc90629b41953b999cb1e +Author: djm@openbsd.org +Date: Wed Aug 19 23:19:01 2015 +0000 + + upstream commit + + fix double-free() in error path of DSA key generation + reported by Mateusz Kocielski; ok markus@ + + Upstream-ID: 4735d8f888b10599a935fa1b374787089116713c + +commit 45b0eb752c94954a6de046bfaaf129e518ad4b5b +Author: djm@openbsd.org +Date: Wed Aug 19 23:18:26 2015 +0000 + + upstream commit + + fix free() of uninitialised pointer reported by Mateusz + Kocielski; ok markus@ + + Upstream-ID: 519552b050618501a06b7b023de5cb104e2c5663 + +commit c837643b93509a3ef538cb6624b678c5fe32ff79 +Author: djm@openbsd.org +Date: Wed Aug 19 23:17:51 2015 +0000 + + upstream commit + + fixed unlink([uninitialised memory]) reported by Mateusz + Kocielski; ok markus@ + + Upstream-ID: 14a0c4e7d891f5a8dabc4b89d4f6b7c0d5a20109 + +commit 1f8d3d629cd553031021068eb9c646a5f1e50994 +Author: jmc@openbsd.org +Date: Fri Aug 14 15:32:41 2015 +0000 + + upstream commit + + match myproposal.h order; from brian conway (i snuck in a + tweak while here) + + ok dtucker + + Upstream-ID: 35174a19b5237ea36aa3798f042bf5933b772c67 + commit 1dc8d93ce69d6565747eb44446ed117187621b26 Author: deraadt@openbsd.org Date: Thu Aug 6 14:53:21 2015 +0000 upstream commit add prohibit-password as a synonymn for without-password, since the without-password is causing too many questions. Harden it to ban all but pubkey, hostbased, and GSSAPI auth (when the latter is enabled) from djm, ok markus Upstream-ID: d53317d7b28942153e6236d3fd6e12ceb482db7a commit 90a95a4745a531b62b81ce3b025e892bdc434de5 Author: Damien Miller Date: Tue Aug 11 13:53:41 2015 +1000 update version in README commit 318c37743534b58124f1bab37a8a0087a3a9bd2f Author: Damien Miller Date: Tue Aug 11 13:53:09 2015 +1000 update versions in *.spec commit 5e75f5198769056089fb06c4d738ab0e5abc66f7 Author: Damien Miller Date: Tue Aug 11 13:34:12 2015 +1000 set sshpam_ctxt to NULL after free Avoids use-after-free in monitor when privsep child is compromised. Reported by Moritz Jodeit; ok dtucker@ commit d4697fe9a28dab7255c60433e4dd23cf7fce8a8b Author: Damien Miller Date: Tue Aug 11 13:33:24 2015 +1000 Don't resend username to PAM; it already has it. Pointed out by Moritz Jodeit; ok dtucker@ commit 88763a6c893bf3dfe951ba9271bf09715e8d91ca Author: Darren Tucker Date: Mon Jul 27 12:14:25 2015 +1000 Import updated moduli file from OpenBSD. commit 55b263fb7cfeacb81aaf1c2036e0394c881637da Author: Damien Miller Date: Mon Aug 10 11:13:44 2015 +1000 let principals-command.sh work for noexec /var/run commit 2651e34cd11b1aac3a0fe23b86d8c2ff35c07897 Author: Damien Miller Date: Thu Aug 6 11:43:42 2015 +1000 work around echo -n / sed behaviour in tests commit d85dad81778c1aa8106acd46930b25fdf0d15b2a Author: djm@openbsd.org Date: Wed Aug 5 05:27:33 2015 +0000 upstream commit adjust for RSA minimum modulus switch; ok deraadt@ Upstream-Regress-ID: 5a72c83431b96224d583c573ca281cd3a3ebfdae commit 57e8e229bad5fe6056b5f1199665f5f7008192c6 Author: djm@openbsd.org Date: Tue Aug 4 05:23:06 2015 +0000 upstream commit backout SSH_RSA_MINIMUM_MODULUS_SIZE increase for this release; problems spotted by sthen@ ok deraadt@ markus@ Upstream-ID: d0bd60dde9e8c3cd7030007680371894c1499822 commit f097d0ea1e0889ca0fa2e53a00214e43ab7fa22a Author: djm@openbsd.org Date: Sun Aug 2 09:56:42 2015 +0000 upstream commit openssh 7.0; ok deraadt@ Upstream-ID: c63afdef537f57f28ae84145c5a8e29e9250221f commit 3d5728a0f6874ce4efb16913a12963595070f3a9 Author: chris@openbsd.org Date: Fri Jul 31 15:38:09 2015 +0000 upstream commit Allow PermitRootLogin to be overridden by config ok markus@ deeradt@ Upstream-ID: 5cf3e26ed702888de84e2dc9d0054ccf4d9125b4 commit 6f941396b6835ad18018845f515b0c4fe20be21a Author: djm@openbsd.org Date: Thu Jul 30 23:09:15 2015 +0000 upstream commit fix pty permissions; patch from Nikolay Edigaryev; ok deraadt Upstream-ID: 40ff076d2878b916fbfd8e4f45dbe5bec019e550 commit f4373ed1e8fbc7c8ce3fc4ea97d0ba2e0c1d7ef0 Author: deraadt@openbsd.org Date: Thu Jul 30 19:23:02 2015 +0000 upstream commit change default: PermitRootLogin without-password matching install script changes coming as well ok djm markus Upstream-ID: 0e2a6c4441daf5498b47a61767382bead5eb8ea6 commit 0c30ba91f87fcda7e975e6ff8a057f624e87ea1c Author: Damien Miller Date: Thu Jul 30 12:31:39 2015 +1000 downgrade OOM adjustment logging: verbose -> debug commit f9eca249d4961f28ae4b09186d7dc91de74b5895 Author: djm@openbsd.org Date: Thu Jul 30 00:01:34 2015 +0000 upstream commit Allow ssh_config and sshd_config kex parameters options be prefixed by a '+' to indicate that the specified items be appended to the default rather than replacing it. approach suggested by dtucker@, feedback dlg@, ok markus@ Upstream-ID: 0f901137298fc17095d5756ff1561a7028e8882a commit 5cefe769105a2a2e3ca7479d28d9a325d5ef0163 Author: djm@openbsd.org Date: Wed Jul 29 08:34:54 2015 +0000 upstream commit fix bug in previous; was printing incorrect string for failed host key algorithms negotiation Upstream-ID: 22c0dc6bc61930513065d92e11f0753adc4c6e6e commit f319912b0d0e1675b8bb051ed8213792c788bcb2 Author: djm@openbsd.org Date: Wed Jul 29 04:43:06 2015 +0000 upstream commit include the peer's offer when logging a failure to negotiate a mutual set of algorithms (kex, pubkey, ciphers, etc.) ok markus@ Upstream-ID: bbb8caabf5c01790bb845f5ce135565248d7c796 commit b6ea0e573042eb85d84defb19227c89eb74cf05a Author: djm@openbsd.org Date: Tue Jul 28 23:20:42 2015 +0000 upstream commit add Cisco to the list of clients that choke on the hostkeys update extension. Pointed out by Howard Kash Upstream-ID: c9eadde28ecec056c73d09ee10ba4570dfba7e84 commit 3f628c7b537291c1019ce86af90756fb4e66d0fd Author: guenther@openbsd.org Date: Mon Jul 27 16:29:23 2015 +0000 upstream commit Permit kbind(2) use in the sandbox now, to ease testing of ld.so work using it reminded by miod@, ok deraadt@ Upstream-ID: 523922e4d1ba7a091e3824e77a8a3c818ee97413 commit ebe27ebe520098bbc0fe58945a87ce8490121edb Author: millert@openbsd.org Date: Mon Jul 20 18:44:12 2015 +0000 upstream commit Move .Pp before .Bl, not after to quiet mandoc -Tlint. Noticed by jmc@ Upstream-ID: 59fadbf8407cec4e6931e50c53cfa0214a848e23 commit d5d91d0da819611167782c66ab629159169d94d4 Author: millert@openbsd.org Date: Mon Jul 20 18:42:35 2015 +0000 upstream commit Sync usage with SYNOPSIS Upstream-ID: 7a321a170181a54f6450deabaccb6ef60cf3f0b7 commit 79ec2142fbc68dd2ed9688608da355fc0b1ed743 Author: millert@openbsd.org Date: Mon Jul 20 15:39:52 2015 +0000 upstream commit Better desciption of Unix domain socket forwarding. bz#2423; ok jmc@ Upstream-ID: 85e28874726897e3f26ae50dfa2e8d2de683805d commit d56fd1828074a4031b18b8faa0bf949669eb18a0 Author: Damien Miller Date: Mon Jul 20 11:19:51 2015 +1000 make realpath.c compile -Wsign-compare clean commit c63c9a691dca26bb7648827f5a13668832948929 Author: djm@openbsd.org Date: Mon Jul 20 00:30:01 2015 +0000 upstream commit mention that the default of UseDNS=no implies that hostnames cannot be used for host matching in sshd_config and authorized_keys; bz#2045, ok dtucker@ Upstream-ID: 0812705d5f2dfa59aab01f2764ee800b1741c4e1 commit 63ebcd0005e9894fcd6871b7b80aeea1fec0ff76 Author: djm@openbsd.org Date: Sat Jul 18 08:02:17 2015 +0000 upstream commit don't ignore PKCS#11 hosted keys that return empty CKA_ID; patch by Jakub Jelen via bz#2429; ok markus Upstream-ID: 2f7c94744eb0342f8ee8bf97b2351d4e00116485 commit b15fd989c8c62074397160147a8d5bc34b3f3c63 Author: djm@openbsd.org Date: Sat Jul 18 08:00:21 2015 +0000 upstream commit skip uninitialised PKCS#11 slots; patch from Jakub Jelen in bz#2427 ok markus@ Upstream-ID: 744c1e7796e237ad32992d0d02148e8a18f27d29 commit 5b64f85bb811246c59ebab70aed331f26ba37b18 Author: djm@openbsd.org Date: Sat Jul 18 07:57:14 2015 +0000 upstream commit only query each keyboard-interactive device once per authentication request regardless of how many times it is listed; ok markus@ Upstream-ID: d73fafba6e86030436ff673656ec1f33d9ffeda1 commit cd7324d0667794eb5c236d8a4e0f236251babc2d Author: djm@openbsd.org Date: Fri Jul 17 03:34:27 2015 +0000 upstream commit remove -u flag to diff (only used for error output) to make things easier for -portable Upstream-Regress-ID: a5d6777d2909540d87afec3039d9bb2414ade548 commit deb8d99ecba70b67f4af7880b11ca8768df9ec3a Author: djm@openbsd.org Date: Fri Jul 17 03:09:19 2015 +0000 upstream commit direct-streamlocal@openssh.com Unix domain foward messages do not contain a "reserved for future use" field and in fact, serverloop.c checks that there isn't one. Remove erroneous mention from PROTOCOL description. bz#2421 from Daniel Black Upstream-ID: 3d51a19e64f72f764682f1b08f35a8aa810a43ac commit 356b61f365405b5257f5b2ab446e5d7bd33a7b52 Author: djm@openbsd.org Date: Fri Jul 17 03:04:27 2015 +0000 upstream commit describe magic for setting up Unix domain socket fowards via the mux channel; bz#2422 patch from Daniel Black Upstream-ID: 943080fe3864715c423bdeb7c920bb30c4eee861 commit d3e2aee41487d55b8d7d40f538b84ff1db7989bc Author: Darren Tucker Date: Fri Jul 17 12:52:34 2015 +1000 Check if realpath works on nonexistent files. On some platforms the native realpath doesn't work with non-existent files (this is actually specified in some versions of POSIX), however the sftp spec says its realpath with "canonicalize any given path name". On those platforms, use realpath from the compat library. In addition, when compiling with -DFORTIFY_SOURCE, glibc redefines the realpath symbol to the checked version, so redefine ours to something else so we pick up the compat version we want. bz#2428, ok djm@ commit 25b14610dab655646a109db5ef8cb4c4bf2a48a0 Author: djm@openbsd.org Date: Fri Jul 17 02:47:45 2015 +0000 upstream commit fix incorrect test for SSH1 keys when compiled without SSH1 support Upstream-ID: 6004d720345b8e481c405e8ad05ce2271726e451 commit df56a8035d429b2184ee94aaa7e580c1ff67f73a Author: djm@openbsd.org Date: Wed Jul 15 08:00:11 2015 +0000 upstream commit fix NULL-deref when SSH1 reenabled Upstream-ID: f22fd805288c92b3e9646782d15b48894b2d5295 commit 41e38c4d49dd60908484e6703316651333f16b93 Author: djm@openbsd.org Date: Wed Jul 15 07:19:50 2015 +0000 upstream commit regen RSA1 test keys; the last batch was missing their private parts Upstream-Regress-ID: 7ccf437305dd63ff0b48dd50c5fd0f4d4230c10a commit 5bf0933184cb622ca3f96d224bf3299fd2285acc Author: markus@openbsd.org Date: Fri Jul 10 06:23:25 2015 +0000 upstream commit Adapt tests, now that DSA if off by default; use PubkeyAcceptedKeyTypes and PubkeyAcceptedKeyTypes to test DSA. Upstream-Regress-ID: 0ff2a3ff5ac1ce5f92321d27aa07b98656efcc5c commit 7a6e3fd7b41dbd3756b6bf9acd67954c0b1564cc Author: markus@openbsd.org Date: Tue Jul 7 14:54:16 2015 +0000 upstream commit regen test data after mktestdata.sh changes Upstream-Regress-ID: 3495ecb082b9a7c048a2d7c5c845d3bf181d25a4 commit 7c8c174c69f681d4910fa41c37646763692b28e2 Author: markus@openbsd.org Date: Tue Jul 7 14:53:30 2015 +0000 upstream commit adapt tests to new minimum RSA size and default FP format Upstream-Regress-ID: a4b30afd174ce82b96df14eb49fb0b81398ffd0e commit 6a977a4b68747ade189e43d302f33403fd4a47ac Author: djm@openbsd.org Date: Fri Jul 3 04:39:23 2015 +0000 upstream commit legacy v00 certificates are gone; adapt and don't try to test them; "sure" markus@ dtucker@ Upstream-Regress-ID: c57321e69b3cd4a3b3396dfcc43f0803d047da12 commit 0c4123ad5e93fb90fee9c6635b13a6cdabaac385 Author: djm@openbsd.org Date: Wed Jul 1 23:11:18 2015 +0000 upstream commit don't expect SSH v.1 in unittests Upstream-Regress-ID: f8812b16668ba78e6a698646b2a652b90b653397 commit 3c099845798a817cdde513c39074ec2063781f18 Author: djm@openbsd.org Date: Mon Jun 15 06:38:50 2015 +0000 upstream commit turn SSH1 back on to match src/usr.bin/ssh being tested Upstream-Regress-ID: 6c4f763a2f0cc6893bf33983919e9030ae638333 commit b1dc2b33689668c75e95f873a42d5aea1f4af1db Author: dtucker@openbsd.org Date: Mon Jul 13 04:57:14 2015 +0000 upstream commit Add "PuTTY_Local:" to the clients to which we do not offer DH-GEX. This was the string that was used for development versions prior to September 2014 and they don't do RFC4419 DH-GEX, but unfortunately there are some extant products based on those versions. bx2424 from Jay Rouman, ok markus@ djm@ Upstream-ID: be34d41e18b966832fe09ca243d275b81882e1d5 commit 3a1638dda19bbc73d0ae02b4c251ce08e564b4b9 Author: markus@openbsd.org Date: Fri Jul 10 06:21:53 2015 +0000 upstream commit Turn off DSA by default; add HostKeyAlgorithms to the server and PubkeyAcceptedKeyTypes to the client side, so it still can be tested or turned back on; feedback and ok djm@ Upstream-ID: 8450a9e6d83f80c9bfed864ff061dfc9323cec21 commit 16db0a7ee9a87945cc594d13863cfcb86038db59 Author: markus@openbsd.org Date: Thu Jul 9 09:49:46 2015 +0000 upstream commit re-enable ed25519-certs if compiled w/o openssl; ok djm Upstream-ID: e10c90808b001fd2c7a93778418e9b318f5c4c49 commit c355bf306ac33de6545ce9dac22b84a194601e2f Author: markus@openbsd.org Date: Wed Jul 8 20:24:02 2015 +0000 upstream commit no need to include the old buffer/key API Upstream-ID: fb13c9f7c0bba2545f3eb0a0e69cb0030819f52b commit a3cc48cdf9853f1e832d78cb29bedfab7adce1ee Author: markus@openbsd.org Date: Wed Jul 8 19:09:25 2015 +0000 upstream commit typedefs for Cipher&CipherContext are unused Upstream-ID: 50e6a18ee92221d23ad173a96d5b6c42207cf9a7 commit a635bd06b5c427a57c3ae760d3a2730bb2c863c0 Author: markus@openbsd.org Date: Wed Jul 8 19:04:21 2015 +0000 upstream commit xmalloc.h is unused Upstream-ID: afb532355b7fa7135a60d944ca1e644d1d63cb58 commit 2521cf0e36c7f3f6b19f206da0af134f535e4a31 Author: markus@openbsd.org Date: Wed Jul 8 19:01:15 2015 +0000 upstream commit compress.c is gone Upstream-ID: 174fa7faa9b9643cba06164b5e498591356fbced commit c65a7aa6c43aa7a308ee1ab8a96f216169ae9615 Author: djm@openbsd.org Date: Fri Jul 3 04:05:54 2015 +0000 upstream commit another SSH_RSA_MINIMUM_MODULUS_SIZE that needed cranking Upstream-ID: 9d8826cafe96aab4ae8e2f6fd22800874b7ffef1 commit b1f383da5cd3cb921fc7776f17a14f44b8a31757 Author: djm@openbsd.org Date: Fri Jul 3 03:56:25 2015 +0000 upstream commit add an XXX reminder for getting correct key paths from sshd_config Upstream-ID: feae52b209d7782ad742df04a4260e9fe41741db commit 933935ce8d093996c34d7efa4d59113163080680 Author: djm@openbsd.org Date: Fri Jul 3 03:49:45 2015 +0000 upstream commit refuse to generate or accept RSA keys smaller than 1024 bits; feedback and ok dtucker@ Upstream-ID: 7ea3d31271366ba264f06e34a3539bf1ac30f0ba commit bdfd29f60b74f3e678297269dc6247a5699583c1 Author: djm@openbsd.org Date: Fri Jul 3 03:47:00 2015 +0000 upstream commit turn off 1024 bit diffie-hellman-group1-sha1 key exchange method (already off in server, this turns it off in the client by default too) ok dtucker@ Upstream-ID: f59b88f449210ab7acf7d9d88f20f1daee97a4fa commit c28fc62d789d860c75e23a9fa9fb250eb2beca57 Author: djm@openbsd.org Date: Fri Jul 3 03:43:18 2015 +0000 upstream commit delete support for legacy v00 certificates; "sure" markus@ dtucker@ Upstream-ID: b5b9bb5f9202d09e88f912989d74928601b6636f commit 564d63e1b4a9637a209d42a9d49646781fc9caef Author: djm@openbsd.org Date: Wed Jul 1 23:10:47 2015 +0000 upstream commit Compile-time disable SSH v.1 again Upstream-ID: 1d4b513a3a06232f02650b73bad25100d1b800af commit 868109b650504dd9bcccdb1f51d0906f967c20ff Author: djm@openbsd.org Date: Wed Jul 1 02:39:06 2015 +0000 upstream commit twiddle PermitRootLogin back Upstream-ID: 2bd23976305d0512e9f84d054e1fc23cd70b89f2 commit 7de4b03a6e4071d454b72927ffaf52949fa34545 Author: djm@openbsd.org Date: Wed Jul 1 02:32:17 2015 +0000 upstream commit twiddle; (this commit marks the openssh-6.9 release) Upstream-ID: 78500582819f61dd8adee36ec5cc9b9ac9351234 commit 1bf477d3cdf1a864646d59820878783d42357a1d Author: djm@openbsd.org Date: Wed Jul 1 02:26:31 2015 +0000 upstream commit better refuse ForwardX11Trusted=no connections attempted after ForwardX11Timeout expires; reported by Jann Horn Upstream-ID: bf0fddadc1b46a0334e26c080038313b4b6dea21 commit 47aa7a0f8551b471fcae0447c1d78464f6dba869 Author: djm@openbsd.org Date: Wed Jul 1 01:56:13 2015 +0000 upstream commit put back default PermitRootLogin=no Upstream-ID: 7bdedd5cead99c57ed5571f3b6b7840922d5f728 commit 984b064fe2a23733733262f88d2e1b2a1a501662 Author: djm@openbsd.org Date: Wed Jul 1 01:55:13 2015 +0000 upstream commit openssh-6.9 Upstream-ID: 6cfe8e1904812531080e6ab6e752d7001b5b2d45 commit d921082ed670f516652eeba50705e1e9f6325346 Author: djm@openbsd.org Date: Wed Jul 1 01:55:00 2015 +0000 upstream commit reset default PermitRootLogin to 'yes' (momentarily, for release) Upstream-ID: cad8513527066e65dd7a1c16363d6903e8cefa24 commit 66295e0e1ba860e527f191b6325d2d77dec4dbce Author: Damien Miller Date: Wed Jul 1 11:49:12 2015 +1000 crank version numbers for release commit 37035c07d4f26bb1fbe000d2acf78efdb008681d Author: Damien Miller Date: Wed Jul 1 10:49:37 2015 +1000 s/--with-ssh1/--without-ssh1/ commit 629df770dbadc2accfbe1c81b3f31f876d0acd84 Author: djm@openbsd.org Date: Tue Jun 30 05:25:07 2015 +0000 upstream commit fatal() when a remote window update causes the window value to overflow. Reported by Georg Wicherski, ok markus@ Upstream-ID: ead397a9aceb3bf74ebfa5fcaf259d72e569f351 commit f715afebe735d61df3fd30ad72d9ac1c8bd3b5f2 Author: djm@openbsd.org Date: Tue Jun 30 05:23:25 2015 +0000 upstream commit Fix math error in remote window calculations that causes eventual stalls for datagram channels. Reported by Georg Wicherski, ok markus@ Upstream-ID: be54059d11bf64e0d85061f7257f53067842e2ab commit 52fb6b9b034fcfd24bf88cc7be313e9c31de9889 Author: Damien Miller Date: Tue Jun 30 16:05:40 2015 +1000 skip IPv6-related portions on hosts without IPv6 with Tim Rice commit 512caddf590857af6aa12218461b5c0441028cf5 Author: djm@openbsd.org Date: Mon Jun 29 22:35:12 2015 +0000 upstream commit add getpid to sandbox, reachable by grace_alarm_handler reported by Jakub Jelen; bz#2419 Upstream-ID: d0da1117c16d4c223954995d35b0f47c8f684cd8 commit 78c2a4f883ea9aba866358e2acd9793a7f42ca93 Author: djm@openbsd.org Date: Fri Jun 26 05:13:20 2015 +0000 upstream commit Fix \-escaping bug that caused forward path parsing to skip two characters and skip past the end of the string. Based on patch by Salvador Fandino; ok dtucker@ Upstream-ID: 7b879dc446335677cbe4cb549495636a0535f3bd commit bc20205c91c9920361d12b15d253d4997dba494a Author: Damien Miller Date: Thu Jun 25 09:51:39 2015 +1000 add missing pselect6 patch from Jakub Jelen commit 9d27fb73b4a4e5e99cb880af790d5b1ce44f720a Author: djm@openbsd.org Date: Wed Jun 24 23:47:23 2015 +0000 upstream commit correct test to sshkey_sign(); spotted by Albert S. Upstream-ID: 5f7347f40f0ca6abdaca2edb3bd62f4776518933 commit 7ed01a96a1911d8b4a9ef4f3d064e1923bfad7e3 Author: dtucker@openbsd.org Date: Wed Jun 24 01:49:19 2015 +0000 upstream commit Revert previous commit. We still want to call setgroups in the case where there are zero groups to remove any that we might otherwise inherit (as pointed out by grawity at gmail.com) and since the 2nd argument to setgroups is always a static global it's always valid to dereference in this case. ok deraadt@ djm@ Upstream-ID: 895b5ac560a10befc6b82afa778641315725fd01 commit 882f8bf94f79528caa65b0ba71c185d705bb7195 Author: dtucker@openbsd.org Date: Wed Jun 24 01:49:19 2015 +0000 upstream commit Revert previous commit. We still want to call setgroups in the case where there are zero groups to remove any that we might otherwise inherit (as pointed out by grawity at gmail.com) and since the 2nd argument to setgroups is always a static global it's always valid to dereference in this case. ok deraadt@ djm@ Upstream-ID: 895b5ac560a10befc6b82afa778641315725fd01 commit 9488538a726951e82b3a4374f3c558d72c80a89b Author: djm@openbsd.org Date: Mon Jun 22 23:42:16 2015 +0000 upstream commit Don't count successful partial authentication as failures in monitor; this may have caused the monitor to refuse multiple authentications that would otherwise have successfully completed; ok markus@ Upstream-ID: eb74b8e506714d0f649bd5c300f762a527af04a3 commit 63b78d003bd8ca111a736e6cea6333da50f5f09b Author: dtucker@openbsd.org Date: Mon Jun 22 12:29:57 2015 +0000 upstream commit Don't call setgroups if we have zero groups; there's no guarantee that it won't try to deref the pointer. Based on a patch from mail at quitesimple.org, ok djm deraadt Upstream-ID: 2fff85e11d7a9a387ef7fddf41fbfaf566708ab1 commit 5c15e22c691c79a47747bcf5490126656f97cecd Author: Damien Miller Date: Thu Jun 18 15:07:56 2015 +1000 fix syntax error commit 596dbca82f3f567fb3d2d69af4b4e1d3ba1e6403 Author: jsing@openbsd.org Date: Mon Jun 15 18:44:22 2015 +0000 upstream commit If AuthorizedPrincipalsCommand is specified, however AuthorizedPrincipalsFile is not (or is set to "none"), authentication will potentially fail due to key_cert_check_authority() failing to locate a principal that matches the username, even though an authorized principal has already been matched in the output of the subprocess. Fix this by using the same logic to determine if pw->pw_name should be passed, as is used to determine if a authorized principal must be matched earlier on. ok djm@ Upstream-ID: 43b42302ec846b0ea68aceb40677245391b9409d commit aff3e94c0d75d0d0fa84ea392b50ab04f8c57905 Author: jsing@openbsd.org Date: Mon Jun 15 18:42:19 2015 +0000 upstream commit Make the arguments to match_principals_command() similar to match_principals_file(), by changing the last argument a struct sshkey_cert * and dereferencing key->cert in the caller. No functional change. ok djm@ Upstream-ID: 533f99b844b21b47342b32b62e198dfffcf8651c commit 97e2e1596c202a4693468378b16b2353fd2d6c5e Author: Damien Miller Date: Wed Jun 17 14:36:54 2015 +1000 trivial optimisation for seccomp-bpf When doing arg inspection and the syscall doesn't match, skip past the instruction that reloads the syscall into the accumulator, since the accumulator hasn't been modified at this point. commit 99f33d7304893bd9fa04d227cb6e870171cded19 Author: Damien Miller Date: Wed Jun 17 10:50:51 2015 +1000 aarch64 support for seccomp-bpf sandbox Also resort and tidy syscall list. Based on patches by Jakub Jelen bz#2361; ok dtucker@ commit 4ef702e1244633c1025ec7cfe044b9ab267097bf Author: djm@openbsd.org Date: Mon Jun 15 01:32:50 2015 +0000 upstream commit return failure on RSA signature error; reported by Albert S Upstream-ID: e61bb93dbe0349625807b0810bc213a6822121fa commit a170f22baf18af0b1acf2788b8b715605f41a1f9 Author: Tim Rice Date: Tue Jun 9 22:41:13 2015 -0700 Fix t12 rules for out of tree builds. commit ec04dc4a5515c913121bc04ed261857e68fa5c18 Author: millert@openbsd.org Date: Fri Jun 5 15:13:13 2015 +0000 upstream commit For "ssh -L 12345:/tmp/sock" don't fail with "No forward host name." (we have a path, not a host name). Based on a diff from Jared Yanovich. OK djm@ Upstream-ID: 2846b0a8c7de037e33657f95afbd282837fc213f commit 732d61f417a6aea0aa5308b59cb0f563bcd6edd6 Author: djm@openbsd.org Date: Fri Jun 5 03:44:14 2015 +0000 upstream commit typo: accidental repetition; bz#2386 Upstream-ID: 45e620d99f6bc301e5949d34a54027374991c88b commit adfb24c69d1b6f5e758db200866c711e25a2ba73 Author: Darren Tucker Date: Fri Jun 5 14:51:40 2015 +1000 Add Linux powerpc64le and powerpcle entries. Stopgap to resolve bz#2409 because we are so close to release and will update config.guess and friends shortly after the release. ok djm@ commit a1195a0fdc9eddddb04d3e9e44c4775431cb77da Merge: 6397eed d2480bc Author: Tim Rice Date: Wed Jun 3 21:43:13 2015 -0700 Merge branch 'master' of git.mindrot.org:/var/git/openssh commit 6397eedf953b2b973d2d7cbb504ab501a07f8ddc Author: Tim Rice Date: Wed Jun 3 21:41:11 2015 -0700 Remove unneeded backslashes. Patch from Ángel González commit d2480bcac1caf31b03068de877a47d6e1027bf6d Author: Darren Tucker Date: Thu Jun 4 14:10:55 2015 +1000 Remove redundant include of stdarg.h. bz#2410 commit 5e67859a623826ccdf2df284cbb37e2d8e2787eb Author: djm@openbsd.org Date: Tue Jun 2 09:10:40 2015 +0000 upstream commit mention CheckHostIP adding addresses to known_hosts; bz#1993; ok dtucker@ Upstream-ID: fd44b68440fd0dc29abf9f2d3f703d74a2396cb7 commit d7a58bbac6583e33fd5eca8e2c2cc70c57617818 Author: Darren Tucker Date: Tue Jun 2 20:15:26 2015 +1000 Replace strcpy with strlcpy. ok djm, sanity check by Corinna Vinschen. commit 51a1c2115265c6e80ede8a5c9dccada9aeed7143 Author: Damien Miller Date: Fri May 29 18:27:21 2015 +1000 skip, rather than fatal when run without SUDO set commit 599f01142a376645b15cbc9349d7e8975e1cf245 Author: Damien Miller Date: Fri May 29 18:03:15 2015 +1000 fix merge botch that left ",," in KEX algs commit 0c2a81dfc21822f2423edd30751e5ec53467b347 Author: Damien Miller Date: Fri May 29 17:08:28 2015 +1000 re-enable SSH protocol 1 at compile time commit db438f9285d64282d3ac9e8c0944f59f037c0151 Author: djm@openbsd.org Date: Fri May 29 03:05:13 2015 +0000 upstream commit make this work without SUDO set; ok dtucker@ Upstream-Regress-ID: bca88217b70bce2fe52b23b8e06bdeb82d98c715 commit 1d9a2e2849c9864fe75daabf433436341c968e14 Author: djm@openbsd.org Date: Thu May 28 07:37:31 2015 +0000 upstream commit wrap all moduli-related code in #ifdef WITH_OPENSSL. based on patch from Reuben Hawkins; bz#2388 feedback and ok dtucker@ Upstream-ID: d80cfc8be3e6ec65b3fac9e87c4466533b31b7cf commit 496aeb25bc2d6c434171292e4714771b594bd00e Author: dtucker@openbsd.org Date: Thu May 28 05:41:29 2015 +0000 upstream commit Increase the allowed length of the known host file name in the log message to be consistent with other cases. Part of bz#1993, ok deraadt. Upstream-ID: a9e97567be49f25daf286721450968251ff78397 commit dd2cfeb586c646ff8d70eb93567b2e559ace5b14 Author: dtucker@openbsd.org Date: Thu May 28 05:09:45 2015 +0000 upstream commit Fix typo (keywork->keyword) Upstream-ID: 8aacd0f4089c0a244cf43417f4f9045dfaeab534 commit 9cc6842493fbf23025ccc1edab064869640d3bec Author: djm@openbsd.org Date: Thu May 28 04:50:53 2015 +0000 upstream commit add error message on ftruncate failure; bz#2176 Upstream-ID: cbcc606e0b748520c74a210d8f3cc9718d3148cf commit d1958793a0072c22be26d136dbda5ae263e717a0 Author: djm@openbsd.org Date: Thu May 28 04:40:13 2015 +0000 upstream commit make ssh-keygen default to ed25519 keys when compiled without OpenSSL; bz#2388, ok dtucker@ Upstream-ID: 85a471fa6d3fa57a7b8e882d22cfbfc1d84cdc71 commit 3ecde664c9fc5fb3667aedf9e6671462600f6496 Author: dtucker@openbsd.org Date: Wed May 27 23:51:10 2015 +0000 upstream commit Reorder client proposal to prefer diffie-hellman-group-exchange-sha1 over diffie-hellman-group14-sha1. ok djm@ Upstream-ID: 552c08d47347c3ee1a9a57d88441ab50abe17058 commit 40f64292b907afd0a674fdbf3e4c2356d17a7d68 Author: dtucker@openbsd.org Date: Wed May 27 23:39:18 2015 +0000 upstream commit Add a stronger (4k bit) fallback group that sshd can use when the moduli file is missing or broken, sourced from RFC3526. bz#2302, ok markus@ (earlier version), djm@ Upstream-ID: b635215746a25a829d117673d5e5a76d4baee7f4 commit 5ab7d5fa03ad55bc438fab45dfb3aeb30a3c237a Author: Darren Tucker Date: Thu May 28 10:03:40 2015 +1000 New moduli file from OpenBSD, removing 1k groups. Remove 1k bit groups. ok deraadt@, markus@ commit a71ba58adf34e599f30cdda6e9b93ae6e3937eea Author: djm@openbsd.org Date: Wed May 27 05:15:02 2015 +0000 upstream commit support PKCS#11 devices with external PIN entry devices bz#2240, based on patch from Dirk-Willem van Gulik; feedback and ok dtucker@ Upstream-ID: 504568992b55a8fc984375242b1bd505ced61b0d commit b282fec1aa05246ed3482270eb70fc3ec5f39a00 Author: dtucker@openbsd.org Date: Tue May 26 23:23:40 2015 +0000 upstream commit Cap DH-GEX group size at 4kbits for Cisco implementations. Some of them will choke when asked for preferred sizes >4k instead of returning the 4k group that they do have. bz#2209, ok djm@ Upstream-ID: 54b863a19713446b7431f9d06ad0532b4fcfef8d commit 3e91b4e8b0dc2b4b7e7d42cf6e8994a32e4cb55e Author: djm@openbsd.org Date: Sun May 24 23:39:16 2015 +0000 upstream commit add missing 'c' option to getopt(), case statement was already there; from Felix Bolte Upstream-ID: 9b19b4e2e0b54d6fefa0dfac707c51cf4bae3081 commit 64a89ec07660abba4d0da7c0095b7371c98bab62 Author: jsg@openbsd.org Date: Sat May 23 14:28:37 2015 +0000 upstream commit fix a memory leak in an error path ok markus@ dtucker@ Upstream-ID: bc1da0f205494944918533d8780fde65dff6c598 commit f948737449257d2cb83ffcfe7275eb79b677fd4a Author: djm@openbsd.org Date: Fri May 22 05:28:45 2015 +0000 upstream commit mention ssh-keygen -E for comparing legacy MD5 fingerprints; bz#2332 Upstream-ID: 079a3669549041dbf10dbc072d9563f0dc3b2859 commit 0882332616e4f0272c31cc47bf2018f9cb258a4e Author: djm@openbsd.org Date: Fri May 22 04:45:52 2015 +0000 upstream commit Reorder EscapeChar option parsing to avoid a single-byte out- of-bounds read. bz#2396 from Jaak Ristioja; ok dtucker@ Upstream-ID: 1dc6b5b63d1c8d9a88619da0b27ade461d79b060 commit d7c31da4d42c115843edee2074d7d501f8804420 Author: djm@openbsd.org Date: Fri May 22 03:50:02 2015 +0000 upstream commit add knob to relax GSSAPI host credential check for multihomed hosts bz#928, patch by Simon Wilkinson; ok dtucker (kerberos/GSSAPI is not compiled by default on OpenBSD) Upstream-ID: 15ddf1c6f7fd9d98eea9962f480079ae3637285d commit aa72196a00be6e0b666215edcffbc10af234cb0e Author: Darren Tucker Date: Fri May 22 17:49:46 2015 +1000 Include signal.h for sig_atomic_t, used by kex.h. bz#2402, from tomas.kuthan at oracle com. commit 8b02481143d75e91c49d1bfae0876ac1fbf9511a Author: Darren Tucker Date: Fri May 22 12:47:24 2015 +1000 Import updated moduli file from OpenBSD. commit 4739e8d5e1c0be49624082bd9f6b077e9e758db9 Author: djm@openbsd.org Date: Thu May 21 12:01:19 2015 +0000 upstream commit Support "ssh-keygen -lF hostname" to find search known_hosts and print key hashes. Already advertised by ssh-keygen(1), but not delivered by code; ok dtucker@ Upstream-ID: 459e0e2bf39825e41b0811c336db2d56a1c23387 commit e97201feca10b5196da35819ae516d0b87cf3a50 Author: Damien Miller Date: Thu May 21 17:55:15 2015 +1000 conditionalise util.h inclusion commit 13640798c7dd011ece0a7d02841fe48e94cfa0e0 Author: djm@openbsd.org Date: Thu May 21 06:44:25 2015 +0000 upstream commit regress test for AuthorizedPrincipalsCommand Upstream-Regress-ID: c658fbf1ab6b6011dc83b73402322e396f1e1219 commit 84452c5d03c21f9bfb28c234e0dc1dc67dd817b1 Author: djm@openbsd.org Date: Thu May 21 06:40:02 2015 +0000 upstream commit regress test for AuthorizedKeysCommand arguments Upstream-Regress-ID: bbd65c13c6b3be9a442ec115800bff9625898f12 commit bcc50d816187fa9a03907ac1f3a52f04a52e10d1 Author: djm@openbsd.org Date: Thu May 21 06:43:30 2015 +0000 upstream commit add AuthorizedPrincipalsCommand that allows getting authorized_principals from a subprocess rather than a file, which is quite useful in deployments with large userbases feedback and ok markus@ Upstream-ID: aa1bdac7b16fc6d2fa3524ef08f04c7258d247f6 commit 24232a3e5ab467678a86aa67968bbb915caffed4 Author: djm@openbsd.org Date: Thu May 21 06:38:35 2015 +0000 upstream commit support arguments to AuthorizedKeysCommand bz#2081 loosely based on patch by Sami Hartikainen feedback and ok markus@ Upstream-ID: b080387a14aa67dddd8ece67c00f268d626541f7 commit d80fbe41a57c72420c87a628444da16d09d66ca7 Author: djm@openbsd.org Date: Thu May 21 04:55:51 2015 +0000 upstream commit refactor: split base64 encoding of pubkey into its own sshkey_to_base64() function and out of sshkey_write(); ok markus@ Upstream-ID: 54fc38f5832e9b91028900819bda46c3959a0c1a commit 7cc44ef74133a473734bbcbd3484f24d6a7328c5 Author: deraadt@openbsd.org Date: Mon May 18 15:06:05 2015 +0000 upstream commit getentropy() and sendsyslog() have been around long enough. openssh-portable may want the #ifdef's but not base. discussed with djm few weeks back Upstream-ID: 0506a4334de108e3fb6c66f8d6e0f9c112866926 commit 9173d0fbe44de7ebcad8a15618e13a8b8d78902e Author: dtucker@openbsd.org Date: Fri May 15 05:44:21 2015 +0000 upstream commit Use a salted hash of the lock passphrase instead of plain text and do constant-time comparisons of it. Should prevent leaking any information about it via timing, pointed out by Ryan Castellucci. Add a 0.1s incrementing delay for each failed unlock attempt up to 10s. ok markus@ (earlier version), djm@ Upstream-ID: c599fcc325aa1cc65496b25220b622d22208c85f commit d028d5d3a697c71b21e4066d8672cacab3caa0a8 Author: Damien Miller Date: Tue May 5 19:10:58 2015 +1000 upstream commit - tedu@cvs.openbsd.org 2015/01/12 03:20:04 [bcrypt_pbkdf.c] rename blocks to words. bcrypt "blocks" are unrelated to blowfish blocks, nor are they the same size. commit f6391d4e59b058984163ab28f4e317e7a72478f1 Author: Damien Miller Date: Tue May 5 19:10:23 2015 +1000 upstream commit - deraadt@cvs.openbsd.org 2015/01/08 00:30:07 [bcrypt_pbkdf.c] declare a local version of MIN(), call it MINIMUM() commit 8ac6b13cc9113eb47cd9e86c97d7b26b4b71b77f Author: Damien Miller Date: Tue May 5 19:09:46 2015 +1000 upstream commit - djm@cvs.openbsd.org 2014/12/30 01:41:43 [bcrypt_pbkdf.c] typo in comment: ouput => output commit 1f792489d5cf86a4f4e3003e6e9177654033f0f2 Author: djm@openbsd.org Date: Mon May 4 06:10:48 2015 +0000 upstream commit Remove pattern length argument from match_pattern_list(), we only ever use it for strlen(pattern). Prompted by hanno AT hboeck.de pointing an out-of-bound read error caused by an incorrect pattern length found using AFL and his own tools. ok markus@ commit 639d6bc57b1942393ed12fb48f00bc05d4e093e4 Author: djm@openbsd.org Date: Fri May 1 07:10:01 2015 +0000 upstream commit refactor ssh_dispatch_run_fatal() to use sshpkt_fatal() to better report error conditions. Teach sshpkt_fatal() about ECONNRESET. Improves error messages on TCP connection resets. bz#2257 ok dtucker@ commit 9559d7de34c572d4d3fd990ca211f8ec99f62c4d Author: djm@openbsd.org Date: Fri May 1 07:08:08 2015 +0000 upstream commit a couple of parse targets were missing activep checks, causing them to be misapplied in match context; bz#2272 diagnosis and original patch from Sami Hartikainen ok dtucker@ commit 7e8528cad04b2775c3b7db08abf8fb42e47e6b2a Author: djm@openbsd.org Date: Fri May 1 04:17:51 2015 +0000 upstream commit make handling of AuthorizedPrincipalsFile=none more consistent with other =none options; bz#2288 from Jakub Jelen; ok dtucker@ commit ca430d4d9cc0f62eca3b1fb1e2928395b7ce80f7 Author: djm@openbsd.org Date: Fri May 1 04:03:20 2015 +0000 upstream commit remove failed remote forwards established by muliplexing from the list of active forwards; bz#2363, patch mostly by Yoann Ricordel; ok dtucker@ commit 8312cfb8ad88657517b3e23ac8c56c8e38eb9792 Author: djm@openbsd.org Date: Fri May 1 04:01:58 2015 +0000 upstream commit reduce stderr spam when using ssh -S /path/mux -O forward -R 0:... ok dtucker@ commit 179be0f5e62f1f492462571944e45a3da660d82b Author: djm@openbsd.org Date: Fri May 1 03:23:51 2015 +0000 upstream commit prevent authorized_keys options picked up on public key tests without a corresponding private key authentication being applied to other authentication methods. Reported by halex@, ok markus@ commit a42d67be65b719a430b7fcaba2a4e4118382723a Author: djm@openbsd.org Date: Fri May 1 03:20:54 2015 +0000 upstream commit Don't make parsing of authorized_keys' environment= option conditional on PermitUserEnv - always parse it, but only use the result if the option is enabled. This prevents the syntax of authorized_keys changing depending on which sshd_config options were enabled. bz#2329; based on patch from coladict AT gmail.com, ok dtucker@ commit e661a86353e11592c7ed6a847e19a83609f49e77 Author: djm@openbsd.org Date: Mon May 4 06:10:48 2015 +0000 upstream commit Remove pattern length argument from match_pattern_list(), we only ever use it for strlen(pattern). Prompted by hanno AT hboeck.de pointing an out-of-bound read error caused by an incorrect pattern length found using AFL and his own tools. ok markus@ commit 0ef1de742be2ee4b10381193fe90730925b7f027 Author: dtucker@openbsd.org Date: Thu Apr 23 05:01:19 2015 +0000 upstream commit Add a simple regression test for sshd's configuration parser. Right now, all it does is run the output of sshd -T back through itself and ensure the output is valid and invariant. commit 368f83c793275faa2c52f60eaa9bdac155c4254b Author: djm@openbsd.org Date: Wed Apr 22 01:38:36 2015 +0000 upstream commit use correct key for nested certificate test commit 8d4d1bfddbbd7d21f545dc6997081d1ea1fbc99a Author: djm@openbsd.org Date: Fri May 1 07:11:47 2015 +0000 upstream commit mention that the user's shell from /etc/passwd is used for commands too; bz#1459 ok dtucker@ commit 5ab283d0016bbc9d4d71e8e5284d011bc5a930cf Author: djm@openbsd.org Date: Fri May 8 07:29:00 2015 +0000 upstream commit whitespace Upstream-Regress-ID: 6b708a3e709d5b7fd37890f874bafdff1f597519 commit 8377d5008ad260048192e1e56ad7d15a56d103dd Author: djm@openbsd.org Date: Fri May 8 07:26:13 2015 +0000 upstream commit whitespace at EOL Upstream-Regress-ID: 9c48911643d5b05173b36a012041bed4080b8554 commit c28a3436fa8737709ea88e4437f8f23a6ab50359 Author: djm@openbsd.org Date: Fri May 8 06:45:13 2015 +0000 upstream commit moar whitespace at eol Upstream-ID: 64eaf872a3ba52ed41e494287e80d40aaba4b515 commit 2b64c490468fd4ca35ac8d5cc31c0520dc1508bb Author: djm@openbsd.org Date: Fri May 8 06:41:56 2015 +0000 upstream commit whitespace at EOL Upstream-ID: 57bcf67d666c6fc1ad798aee448fdc3f70f7ec2c commit 4e636cf201ce6e7e3b9088568218f9d4e2c51712 Author: djm@openbsd.org Date: Fri May 8 03:56:51 2015 +0000 upstream commit whitespace at EOL commit 38b8272f823dc1dd4e29dbcee83943ed48bb12fa Author: dtucker@openbsd.org Date: Mon May 4 01:47:53 2015 +0000 upstream commit Use diff w/out -u for better portability commit 297060f42d5189a4065ea1b6f0afdf6371fb0507 Author: dtucker@openbsd.org Date: Fri May 8 03:25:07 2015 +0000 upstream commit Use xcalloc for permitted_adm_opens instead of xmalloc to ensure it's zeroed. Fixes post-auth crash with permitopen=none. bz#2355, ok djm@ commit 63ebf019be863b2d90492a85e248cf55a6e87403 Author: djm@openbsd.org Date: Fri May 8 03:17:49 2015 +0000 upstream commit don't choke on new-format private keys encrypted with an AEAD cipher; bz#2366, patch from Ron Frederick; ok markus@ commit f8484dac678ab3098ae522a5f03bb2530f822987 Author: dtucker@openbsd.org Date: Wed May 6 05:45:17 2015 +0000 upstream commit Clarify pseudo-terminal request behaviour and use "pseudo-terminal" consistently. bz#1716, ok jmc@ "I like it" deraadt@. commit ea139507bef8bad26e86ed99a42c7233ad115c38 Author: dtucker@openbsd.org Date: Wed May 6 04:07:18 2015 +0000 upstream commit Blacklist DH-GEX for specific PuTTY versions known to send non-RFC4419 DH-GEX messages rather than all versions of PuTTY. According to Simon Tatham, 0.65 and newer versions will send RFC4419 DH-GEX messages. ok djm@ commit b58234f00ee3872eb84f6e9e572a9a34e902e36e Author: dtucker@openbsd.org Date: Tue May 5 10:17:49 2015 +0000 upstream commit WinSCP doesn't implement RFC4419 DH-GEX so flag it so we don't offer that KEX method. ok markus@ commit d5b1507a207253b39e810e91e68f9598691b7a29 Author: jsg@openbsd.org Date: Tue May 5 02:48:17 2015 +0000 upstream commit use the sizeof the struct not the sizeof a pointer to the struct in ssh_digest_start() This file is only used if ssh is built with OPENSSL=no ok markus@ commit a647b9b8e616c231594b2710c925d31b1b8afea3 Author: Darren Tucker Date: Fri May 8 11:07:27 2015 +1000 Put brackets around mblen() compat constant. This might help with the reported problem cross compiling for Android ("error: expected identifier or '(' before numeric constant") but shouldn't hurt in any case. commit d1680d36e17244d9af3843aeb5025cb8e40d6c07 Author: Darren Tucker Date: Thu Apr 30 09:18:11 2015 +1000 xrealloc -> xreallocarray in portable code too. commit 531a57a3893f9fcd4aaaba8c312b612bbbcc021e Author: dtucker@openbsd.org Date: Wed Apr 29 03:48:56 2015 +0000 upstream commit Allow ListenAddress, Port and AddressFamily in any order. bz#68, ok djm@, jmc@ (for the man page bit). commit c1d5bcf1aaf1209af02f79e48ba1cbc76a87b56f Author: jmc@openbsd.org Date: Tue Apr 28 13:47:38 2015 +0000 upstream commit enviroment -> environment: apologies to darren for not spotting that first time round... commit 43beea053db191cac47c2cd8d3dc1930158aff1a Author: dtucker@openbsd.org Date: Tue Apr 28 10:25:15 2015 +0000 upstream commit Fix typo in previous commit 85b96ef41374f3ddc9139581f87da09b2cd9199e Author: dtucker@openbsd.org Date: Tue Apr 28 10:17:58 2015 +0000 upstream commit Document that the TERM environment variable is not subject to SendEnv and AcceptEnv. bz#2386, based loosely on a patch from jjelen at redhat, help and ok jmc@ commit 88a7c598a94ff53f76df228eeaae238d2d467565 Author: djm@openbsd.org Date: Mon Apr 27 21:42:48 2015 +0000 upstream commit Make sshd default to PermitRootLogin=no; ok deraadt@ rpe@ commit 734226b4480a6c736096c729fcf6f391400599c7 Author: djm@openbsd.org Date: Mon Apr 27 01:52:30 2015 +0000 upstream commit fix compilation with OPENSSL=no; ok dtucker@ commit a4b9d2ce1eb7703eaf0809b0c8a82ded8aa4f1c6 Author: dtucker@openbsd.org Date: Mon Apr 27 00:37:53 2015 +0000 upstream commit Include stdio.h for FILE (used in sshkey.h) so it compiles with OPENSSL=no. commit dbcc652f4ca11fe04e5930c7ef18a219318c6cda Author: djm@openbsd.org Date: Mon Apr 27 00:21:21 2015 +0000 upstream commit allow "sshd -f none" to skip reading the config file, much like "ssh -F none" does. ok dtucker commit b7ca276fca316c952f0b90f5adb1448c8481eedc Author: jmc@openbsd.org Date: Fri Apr 24 06:26:49 2015 +0000 upstream commit combine -Dd onto one line and update usage(); commit 2ea974630d7017e4c7666d14d9dc939707613e96 Author: djm@openbsd.org Date: Fri Apr 24 05:26:44 2015 +0000 upstream commit add ssh-agent -D to leave ssh-agent in foreground without enabling debug mode; bz#2381 ok dtucker@ commit 8ac2ffd7aa06042f6b924c87139f2fea5c5682f7 Author: deraadt@openbsd.org Date: Fri Apr 24 01:36:24 2015 +0000 upstream commit 2*len -> use xreallocarray() ok djm commit 657a5fbc0d0aff309079ff8fb386f17e964963c2 Author: deraadt@openbsd.org Date: Fri Apr 24 01:36:00 2015 +0000 upstream commit rename xrealloc() to xreallocarray() since it follows that form. ok djm commit 1108ae242fdd2c304307b68ddf46aebe43ebffaa Author: dtucker@openbsd.org Date: Thu Apr 23 04:59:10 2015 +0000 upstream commit Two small fixes for sshd -T: ListenAddress'es are added to a list head so reverse the order when printing them to ensure the behaviour remains the same, and print StreamLocalBindMask as octal with leading zero. ok deraadt@ commit bd902b8473e1168f19378d5d0ae68d0c203525df Author: dtucker@openbsd.org Date: Thu Apr 23 04:53:53 2015 +0000 upstream commit Check for and reject missing arguments for VersionAddendum and ForceCommand. bz#2281, patch from plautrba at redhat com, ok djm@ commit ca42c1758575e592239de1d5755140e054b91a0d Author: djm@openbsd.org Date: Wed Apr 22 01:24:01 2015 +0000 upstream commit unknown certificate extensions are non-fatal, so don't fatal when they are encountered; bz#2387 reported by Bob Van Zant; ok dtucker@ commit 39bfbf7caad231cc4bda6909fb1af0705bca04d8 Author: jsg@openbsd.org Date: Tue Apr 21 07:01:00 2015 +0000 upstream commit Add back a backslash removed in rev 1.42 so KEX_SERVER_ENCRYPT will include aes again. ok deraadt@ commit 6b0d576bb87eca3efd2b309fcfe4edfefc289f9c Author: djm@openbsd.org Date: Fri Apr 17 13:32:09 2015 +0000 upstream commit s/recommended/required/ that private keys be og-r this wording change was made a while ago but got accidentally reverted commit 44a8e7ce6f3ab4c2eb1ae49115c210b98e53c4df Author: djm@openbsd.org Date: Fri Apr 17 13:25:52 2015 +0000 upstream commit don't try to cleanup NULL KEX proposals in kex_prop_free(); found by Jukka Taimisto and Markus Hietava commit 3038a191872d2882052306098c1810d14835e704 Author: djm@openbsd.org Date: Fri Apr 17 13:19:22 2015 +0000 upstream commit use error/logit/fatal instead of fprintf(stderr, ...) and exit(0), fix a few errors that were being printed to stdout instead of stderr and a few non-errors that were going to stderr instead of stdout bz#2325; ok dtucker commit a58be33cb6cd24441fa7e634db0e5babdd56f07f Author: djm@openbsd.org Date: Fri Apr 17 13:16:48 2015 +0000 upstream commit debug log missing DISPLAY environment when X11 forwarding requested; bz#1682 ok dtucker@ commit 17d4d9d9fbc8fb80e322f94d95eecc604588a474 Author: djm@openbsd.org Date: Fri Apr 17 04:32:31 2015 +0000 upstream commit don't call record_login() in monitor when UseLogin is enabled; bz#278 reported by drk AT sgi.com; ok dtucker commit 40132ff87b6cbc3dc05fb5df2e9d8e3afa06aafd Author: dtucker@openbsd.org Date: Fri Apr 17 04:12:35 2015 +0000 upstream commit Add some missing options to sshd -T and fix the output of VersionAddendum HostCertificate. bz#2346, patch from jjelen at redhat com, ok djm. commit 6cc7cfa936afde2d829e56ee6528c7ea47a42441 Author: dtucker@openbsd.org Date: Thu Apr 16 23:25:50 2015 +0000 upstream commit Document "none" for PidFile XAuthLocation TrustedUserCAKeys and RevokedKeys. bz#2382, feedback from jmc@, ok djm@ commit 15fdfc9b1c6808b26bc54d4d61a38b54541763ed Author: dtucker@openbsd.org Date: Wed Apr 15 23:23:25 2015 +0000 upstream commit Plug leak of address passed to logging. bz#2373, patch from jjelen at redhat, ok markus@ commit bb2289e2a47d465eaaaeff3dee2a6b7777b4c291 Author: dtucker@openbsd.org Date: Tue Apr 14 04:17:03 2015 +0000 upstream commit Output remote username in debug output since with Host and Match it's not always obvious what it will be. bz#2368, ok djm@ commit 70860b6d07461906730632f9758ff1b7c98c695a Author: Darren Tucker Date: Fri Apr 17 10:56:13 2015 +1000 Format UsePAM setting when using sshd -T. Part of bz#2346, patch from jjelen at redhat com. commit ee15d9c9f0720f5a8b0b34e4b10ecf21f9824814 Author: Darren Tucker Date: Fri Apr 17 10:40:23 2015 +1000 Wrap endian.h include inside ifdef (bz#2370). commit 408f4c2ad4a4c41baa7b9b2b7423d875abbfa70b Author: Darren Tucker Date: Fri Apr 17 09:39:58 2015 +1000 Look for '${host}-ar' before 'ar'. This changes configure.ac to look for '${host}-ar' as set by AC_CANONICAL_HOST before looking for the unprefixed 'ar'. Useful when cross-compiling when all your binutils are prefixed. Patch from moben at exherbo org via astrand at lysator liu se and bz#2352. commit 673a1c16ad078d41558247ce739fe812c960acc8 Author: Damien Miller Date: Thu Apr 16 11:40:20 2015 +1000 remove dependency on arpa/telnet.h commit 202d443eeda1829d336595a3cfc07827e49f45ed Author: Darren Tucker Date: Wed Apr 15 15:59:49 2015 +1000 Remove duplicate include of pwd.h. bz#2337, patch from Mordy Ovits. commit 597986493412c499f2bc2209420cb195f97b3668 Author: Damien Miller Date: Thu Apr 9 10:14:48 2015 +1000 platform's with openpty don't need pty_release commit 318be28cda1fd9108f2e6f2f86b0b7589ba2aed0 Author: djm@openbsd.org Date: Mon Apr 13 02:04:08 2015 +0000 upstream commit deprecate ancient, pre-RFC4419 and undocumented SSH2_MSG_KEX_DH_GEX_REQUEST_OLD message; ok markus@ deraadt@ "seems reasonable" dtucker@ commit d8f391caef62378463a0e6b36f940170dadfe605 Author: dtucker@openbsd.org Date: Fri Apr 10 05:16:50 2015 +0000 upstream commit Don't send hostkey advertisments (hostkeys-00@openssh.com) to current versions of Tera Term as they can't handle them. Newer versions should be OK. Patch from Bryan Drewery and IWAMOTO Kouichi, ok djm@ commit 2c2cfe1a1c97eb9a08cc9817fd0678209680c636 Author: djm@openbsd.org Date: Fri Apr 10 00:08:55 2015 +0000 upstream commit include port number if a non-default one has been specified; based on patch from Michael Handler commit 4492a4f222da4cf1e8eab12689196322e27b08c4 Author: djm@openbsd.org Date: Tue Apr 7 23:00:42 2015 +0000 upstream commit treat Protocol=1,2|2,1 as Protocol=2 when compiled without SSH1 support; ok dtucker@ millert@ commit c265e2e6e932efc6d86f6cc885dea33637a67564 Author: miod@openbsd.org Date: Sun Apr 5 15:43:43 2015 +0000 upstream commit Do not use int for sig_atomic_t; spotted by christos@netbsd; ok markus@ commit e7bf3a5eda6a1b02bef6096fed78527ee11e54cc Author: Darren Tucker Date: Tue Apr 7 10:48:04 2015 +1000 Use do{}while(0) for no-op functions. From FreeBSD. commit bb99844abae2b6447272f79e7fa84134802eb4df Author: Darren Tucker Date: Tue Apr 7 10:47:15 2015 +1000 Wrap blf.h include in ifdef. From FreeBSD. commit d9b9b43656091cf0ad55c122f08fadb07dad0abd Author: Darren Tucker Date: Tue Apr 7 09:10:00 2015 +1000 Fix misspellings of regress CONFOPTS env variables. Patch from Bryan Drewery. commit 3f4ea3c9ab1d32d43c9222c4351f58ca11144156 Author: djm@openbsd.org Date: Fri Apr 3 22:17:27 2015 +0000 upstream commit correct return value in pubkey parsing, spotted by Ben Hawkes ok markus@ commit 7da2be0cb9601ed25460c83aa4d44052b967ba0f Author: djm@openbsd.org Date: Tue Mar 31 22:59:01 2015 +0000 upstream commit adapt to recent hostfile.c change: when parsing known_hosts without fully parsing the keys therein, hostkeys_foreach() will now correctly identify KEY_RSA1 keys; ok markus@ miod@ commit 9e1777a0d1c706714b055811c12ab8cc21033e4a Author: markus@openbsd.org Date: Tue Mar 24 20:19:15 2015 +0000 upstream commit use ${SSH} for -Q instead of installed ssh commit ce1b358ea414a2cc88e4430cd5a2ea7fecd9de57 Author: djm@openbsd.org Date: Mon Mar 16 22:46:14 2015 +0000 upstream commit make CLEANFILES clean up more of the tests' droppings commit 398f9ef192d820b67beba01ec234d66faca65775 Author: djm@openbsd.org Date: Tue Mar 31 22:57:06 2015 +0000 upstream commit downgrade error() for known_hosts parse errors to debug() to quiet warnings from ssh1 keys present when compiled !ssh1. also identify ssh1 keys when scanning, even when compiled !ssh1 ok markus@ miod@ commit 9a47ab80030a31f2d122b8fd95bd48c408b9fcd9 Author: djm@openbsd.org Date: Tue Mar 31 22:55:50 2015 +0000 upstream commit fd leak for !ssh1 case; found by unittests; ok markus@ commit c9a0805a6280681901c270755a7cd630d7c5280e Author: djm@openbsd.org Date: Tue Mar 31 22:55:24 2015 +0000 upstream commit don't fatal when a !ssh1 sshd is reexeced from a w/ssh1 listener; reported by miod@; ok miod@ markus@ commit 704d8c88988cae38fb755a6243b119731d223222 Author: tobias@openbsd.org Date: Tue Mar 31 11:06:49 2015 +0000 upstream commit Comments are only supported for RSA1 keys. If a user tried to add one and entered his passphrase, explicitly clear it before exit. This is done in all other error paths, too. ok djm commit 78de1673c05ea2c33e0d4a4b64ecb5186b6ea2e9 Author: jmc@openbsd.org Date: Mon Mar 30 18:28:37 2015 +0000 upstream commit ssh-askpass(1) is the default, overridden by SSH_ASKPASS; diff originally from jiri b; commit 26e0bcf766fadb4a44fb6199386fb1dcab65ad00 Author: djm@openbsd.org Date: Mon Mar 30 00:00:29 2015 +0000 upstream commit fix uninitialised memory read when parsing a config file consisting of a single nul byte. Found by hanno AT hboeck.de using AFL; ok dtucker commit fecede00a76fbb33a349f5121c0b2f9fbc04a777 Author: markus@openbsd.org Date: Thu Mar 26 19:32:19 2015 +0000 upstream commit sigp and lenp are not optional in ssh_agent_sign(); ok djm@ commit 1b0ef3813244c78669e6d4d54c624f600945327d Author: naddy@openbsd.org Date: Thu Mar 26 12:32:38 2015 +0000 upstream commit don't try to load .ssh/identity by default if SSH1 is disabled; ok markus@ commit f9b78852379b74a2d14e6fc94fe52af30b7e9c31 Author: djm@openbsd.org Date: Thu Mar 26 07:00:04 2015 +0000 upstream commit ban all-zero curve25519 keys as recommended by latest CFRG curves draft; ok markus commit b8afbe2c1aaf573565e4da775261dfafc8b1ba9c Author: djm@openbsd.org Date: Thu Mar 26 06:59:28 2015 +0000 upstream commit relax bits needed check to allow diffie-hellman-group1-sha1 key exchange to complete for chacha20-poly1305 was selected as symmetric cipher; ok markus commit 47842f71e31da130555353c1d57a1e5a8937f1c0 Author: markus@openbsd.org Date: Wed Mar 25 19:29:58 2015 +0000 upstream commit ignore v1 errors on ssh-add -D; only try v2 keys on -l/-L (unless WITH_SSH1) ok djm@ commit 5f57e77f91bf2230c09eca96eb5ecec39e5f2da6 Author: markus@openbsd.org Date: Wed Mar 25 19:21:48 2015 +0000 upstream commit unbreak ssh_agent_sign (lenp vs *lenp) commit 4daeb67181054f2a377677fac919ee8f9ed3490e Author: markus@openbsd.org Date: Tue Mar 24 20:10:08 2015 +0000 upstream commit don't leak 'setp' on error; noted by Nicholas Lemonias; ok djm@ commit 7d4f96f9de2a18af0d9fa75ea89a4990de0344f5 Author: markus@openbsd.org Date: Tue Mar 24 20:09:11 2015 +0000 upstream commit consistent check for NULL as noted by Nicholas Lemonias; ok djm@ commit df100be51354e447d9345cf1ec22e6013c0eed50 Author: markus@openbsd.org Date: Tue Mar 24 20:03:44 2015 +0000 upstream commit correct fmt-string for size_t as noted by Nicholas Lemonias; ok djm@ commit a22b9ef21285e81775732436f7c84a27bd3f71e0 Author: djm@openbsd.org Date: Tue Mar 24 09:17:21 2015 +0000 upstream commit promote chacha20-poly1305@openssh.com to be the default cipher; ok markus commit 2aa9da1a3b360cf7b13e96fe1521534b91501fb5 Author: djm@openbsd.org Date: Tue Mar 24 01:29:19 2015 +0000 upstream commit Compile-time disable SSH protocol 1. You can turn it back on using the Makefile.inc knob if you need it to talk to ancient devices. commit 53097b2022154edf96b4e8526af5666f979503f7 Author: djm@openbsd.org Date: Tue Mar 24 01:11:12 2015 +0000 upstream commit fix double-negative error message "ssh1 is not unsupported" commit 5c27e3b6ec2db711dfcd40e6359c0bcdd0b62ea9 Author: djm@openbsd.org Date: Mon Mar 23 06:06:38 2015 +0000 upstream commit for ssh-keygen -A, don't try (and fail) to generate ssh v.1 keys when compiled without SSH1 support RSA/DSA/ECDSA keys when compiled without OpenSSL based on patch by Mike Frysinger; bz#2369 commit 725fd22a8c41db7de73a638539a5157b7e4424ae Author: djm@openbsd.org Date: Wed Mar 18 01:44:21 2015 +0000 upstream commit KRL support doesn't need OpenSSL anymore, remove #ifdefs from around call commit b07011c18e0b2e172c5fd09d21fb159a0bf5fcc7 Author: djm@openbsd.org Date: Mon Mar 16 11:09:52 2015 +0000 upstream commit #if 0 some more arrays used only for decrypting (we don't use since we only need encrypt for AES-CTR) commit 1cb3016635898d287e9d58b50c430995652d5358 Author: jsg@openbsd.org Date: Wed Mar 11 00:48:39 2015 +0000 upstream commit add back the changes from rev 1.206, djm reverted this by mistake in rev 1.207 commit 4d24b3b6a4a6383e05e7da26d183b79fa8663697 Author: Damien Miller Date: Fri Mar 20 09:11:59 2015 +1100 remove error() accidentally inserted for debugging pointed out by Christian Hesse commit 9f82e5a9042f2d872e98f48a876fcab3e25dd9bb Author: Tim Rice Date: Mon Mar 16 22:49:20 2015 -0700 portability fix: Solaris systems may not have a grep that understands -q commit 8ef691f7d9ef500257a549d0906d78187490668f Author: Damien Miller Date: Wed Mar 11 10:35:26 2015 +1100 fix compile with clang commit 4df590cf8dc799e8986268d62019b487a8ed63ad Author: Damien Miller Date: Wed Mar 11 10:02:39 2015 +1100 make unit tests work for !OPENSSH_HAS_ECC commit 307bb40277ca2c32e97e61d70d1ed74b571fd6ba Author: djm@openbsd.org Date: Sat Mar 7 04:41:48 2015 +0000 upstream commit unbreak for w/SSH1 (default) case; ok markus@ deraadt@ commit b44ee0c998fb4c5f3c3281f2398af5ce42840b6f Author: Damien Miller Date: Thu Mar 5 18:39:20 2015 -0800 unbreak hostkeys test for w/ SSH1 case commit 55e5bdeb519cb60cc18b7ba0545be581fb8598b4 Author: djm@openbsd.org Date: Fri Mar 6 01:40:56 2015 +0000 upstream commit fix sshkey_certify() return value for unsupported key types; ok markus@ deraadt@ commit be8f658e550a434eac04256bfbc4289457a24e99 Author: Damien Miller Date: Wed Mar 4 15:38:03 2015 -0800 update version numbers to match version.h commit ac5e8acefa253eb5e5ba186e34236c0e8007afdc Author: djm@openbsd.org Date: Wed Mar 4 23:22:35 2015 +0000 upstream commit make these work with !SSH1; ok markus@ deraadt@ commit 2f04af92f036b0c87a23efb259c37da98cd81fe6 Author: djm@openbsd.org Date: Wed Mar 4 21:12:59 2015 +0000 upstream commit make ssh-add -D work with !SSH1 agent commit a05adf95d2af6abb2b7826ddaa7a0ec0cdc1726b Author: Damien Miller Date: Wed Mar 4 00:55:48 2015 -0800 netcat needs poll.h portability goop commit dad2b1892b4c1b7e58df483a8c5b983c4454e099 Author: markus@openbsd.org Date: Tue Mar 3 22:35:19 2015 +0000 upstream commit make it possible to run tests w/o ssh1 support; ok djm@ commit d48a22601bdd3eec054794c535f4ae8d8ae4c6e2 Author: djm@openbsd.org Date: Wed Mar 4 18:53:53 2015 +0000 upstream commit crank; ok markus, deraadt commit bbffb23daa0b002dd9f296e396a9ab8a5866b339 Author: Damien Miller Date: Tue Mar 3 13:50:27 2015 -0800 more --without-ssh1 fixes commit 6c2039286f503e2012a58a1d109e389016e7a99b Author: Damien Miller Date: Tue Mar 3 13:48:48 2015 -0800 fix merge both that broke --without-ssh1 compile commit 111dfb225478a76f89ecbcd31e96eaf1311b59d3 Author: djm@openbsd.org Date: Tue Mar 3 21:21:13 2015 +0000 upstream commit add SSH1 Makefile knob to make it easier to build without SSH1 support; ok markus@ commit 3f7f5e6c5d2aa3f6710289c1a30119e534e56c5c Author: djm@openbsd.org Date: Tue Mar 3 20:42:49 2015 +0000 upstream commit expand __unused to full __attribute__ for better portability commit 2fab9b0f8720baf990c931e3f68babb0bf9949c6 Author: Damien Miller Date: Wed Mar 4 07:41:27 2015 +1100 avoid warning commit d1bc844322461f882b4fd2277ba9a8d4966573d2 Author: Damien Miller Date: Wed Mar 4 06:31:45 2015 +1100 Revert "define __unused to nothing if not already defined" This reverts commit 1598419e38afbaa8aa5df8dd6b0af98301e2c908. Some system headers have objects named __unused commit 00797e86b2d98334d1bb808f65fa1fd47f328ff1 Author: Damien Miller Date: Wed Mar 4 05:02:45 2015 +1100 check for crypt and DES_crypt in openssl block fixes builds on systems that use DES_crypt; based on patch from Roumen Petrov commit 1598419e38afbaa8aa5df8dd6b0af98301e2c908 Author: Damien Miller Date: Wed Mar 4 04:59:13 2015 +1100 define __unused to nothing if not already defined fixes builds on BSD/OS commit d608a51daad4f14ad6ab43d7cf74ef4801cc3fe9 Author: djm@openbsd.org Date: Tue Mar 3 17:53:40 2015 +0000 upstream commit reorder logic for better portability; patch from Roumen Petrov commit 68d2dfc464fbcdf8d6387884260f9801f4352393 Author: djm@openbsd.org Date: Tue Mar 3 06:48:58 2015 +0000 upstream commit Allow "ssh -Q protocol-version" to list supported SSH protocol versions. Useful for detecting builds without SSH v.1 support; idea and ok markus@ commit 39e2f1229562e1195169905607bc12290d21f021 Author: millert@openbsd.org Date: Sun Mar 1 15:44:40 2015 +0000 upstream commit Make sure we only call getnameinfo() for AF_INET or AF_INET6 sockets. getpeername() of a Unix domain socket may return without error on some systems without actually setting ss_family so getnameinfo() was getting called with ss_family set to AF_UNSPEC. OK djm@ commit e47536ba9692d271b8ad89078abdecf0a1c11707 Author: Damien Miller Date: Sat Feb 28 08:20:11 2015 -0800 portability fixes for regress/netcat.c Mostly avoiding "err(1, NULL)" commit 02973ad5f6f49d8420e50a392331432b0396c100 Author: Damien Miller Date: Sat Feb 28 08:05:27 2015 -0800 twiddle another test for portability from Tom G. Christensen commit f7f3116abf2a6e2f309ab096b08c58d19613e5d0 Author: Damien Miller Date: Fri Feb 27 15:52:49 2015 -0800 twiddle test for portability commit 1ad3a77cc9d5568f5437ff99d377aa7a41859b83 Author: Damien Miller Date: Thu Feb 26 20:33:22 2015 -0800 make regress/netcat.c fd passing (more) portable commit 9e1cfca7e1fe9cf8edb634fc894e43993e4da1ea Author: Damien Miller Date: Thu Feb 26 20:32:58 2015 -0800 create OBJ/valgrind-out before running unittests commit bd58853102cee739f0e115e6d4b5334332ab1442 Author: Damien Miller Date: Wed Feb 25 16:58:22 2015 -0800 valgrind support commit f43d17269194761eded9e89f17456332f4c83824 Author: djm@openbsd.org Date: Thu Feb 26 20:45:47 2015 +0000 upstream commit don't printf NULL key comments; reported by Tom Christensen commit 6e6458b476ec854db33e3e68ebf4f489d0ab3df8 Author: djm@openbsd.org Date: Wed Feb 25 23:05:47 2015 +0000 upstream commit zero cmsgbuf before use; we initialise the bits we use but valgrind still spams warning on it commit a63cfa26864b93ab6afefad0b630e5358ed8edfa Author: djm@openbsd.org Date: Wed Feb 25 19:54:02 2015 +0000 upstream commit fix small memory leak when UpdateHostkeys=no commit e6b950341dd75baa8526f1862bca39e52f5b879b Author: Tim Rice Date: Wed Feb 25 09:56:48 2015 -0800 Revert "Work around finicky USL linker so netcat will build." This reverts commit d1db656021d0cd8c001a6692f772f1de29b67c8b. No longer needed with commit 678e473e2af2e4802f24dd913985864d9ead7fb3 commit 6f621603f9cff2a5d6016a404c96cb2f8ac2dec0 Author: djm@openbsd.org Date: Wed Feb 25 17:29:38 2015 +0000 upstream commit don't leak validity of user in "too many authentication failures" disconnect message; reported by Sebastian Reitenbach commit 6288e3a935494df12519164f52ca5c8c65fc3ca5 Author: naddy@openbsd.org Date: Tue Feb 24 15:24:05 2015 +0000 upstream commit add -v (show ASCII art) to -l's synopsis; ok djm@ commit 678e473e2af2e4802f24dd913985864d9ead7fb3 Author: Darren Tucker Date: Thu Feb 26 04:12:58 2015 +1100 Remove dependency on xmalloc. Remove ssh_get_progname's dependency on xmalloc, which should reduce link order problems. ok djm@ commit 5d5ec165c5b614b03678afdad881f10e25832e46 Author: Darren Tucker Date: Wed Feb 25 15:32:49 2015 +1100 Restrict ECDSA and ECDH tests. ifdef out some more ECDSA and ECDH tests when built against an OpenSSL that does not have eliptic curve functionality. commit 1734e276d99b17e92d4233fac7aef3a3180aaca7 Author: Darren Tucker Date: Wed Feb 25 13:40:45 2015 +1100 Move definition of _NSIG. _NSIG is only unsed in one file, so move it there prevent redefinition warnings reported by Kevin Brott. commit a47ead7c95cfbeb72721066c4da2312e5b1b9f3d Author: Darren Tucker Date: Wed Feb 25 13:17:40 2015 +1100 Add includes.h for compatibility stuff. commit 38806bda6d2e48ad32812b461eebe17672ada771 Author: Damien Miller Date: Tue Feb 24 16:50:06 2015 -0800 include netdb.h to look for MAXHOSTNAMELEN; ok tim commit d1db656021d0cd8c001a6692f772f1de29b67c8b Author: Tim Rice Date: Tue Feb 24 10:42:08 2015 -0800 Work around finicky USL linker so netcat will build. commit cb030ce25f555737e8ba97bdd7883ac43f3ff2a3 Author: Damien Miller Date: Tue Feb 24 09:23:04 2015 -0800 include includes.h to avoid build failure on AIX commit 13af342458f5064144abbb07e5ac9bbd4eb42567 Author: Tim Rice Date: Tue Feb 24 07:56:47 2015 -0800 Original portability patch from djm@ for platforms missing err.h. Fix name space clash on Solaris 10. Still more to do for Solaris 10 to deal with msghdr structure differences. ok djm@ commit 910209203d0cd60c5083901cbcc0b7b44d9f48d2 Author: Tim Rice Date: Mon Feb 23 22:06:56 2015 -0800 cleaner way fix dispatch.h portion of commit a88dd1da119052870bb2654c1a32c51971eade16 (some systems have sig_atomic_t in signal.h, some in sys/signal.h) Sounds good to me djm@ commit 676c38d7cbe65b76bbfff796861bb6615cc6a596 Author: Tim Rice Date: Mon Feb 23 21:51:33 2015 -0800 portability fix: if we can't dind a better define for HOST_NAME_MAX, use 255 commit 1221b22023dce38cbc90ba77eae4c5d78c77a5e6 Author: Tim Rice Date: Mon Feb 23 21:50:34 2015 -0800 portablity fix: s/__inline__/inline/ commit 4c356308a88d309c796325bb75dce90ca16591d5 Author: Darren Tucker Date: Tue Feb 24 13:49:31 2015 +1100 Wrap stdint.h includes in HAVE_STDINT_H. commit c9c88355c6a27a908e7d1e5003a2b35ea99c1614 Author: Darren Tucker Date: Tue Feb 24 13:43:57 2015 +1100 Add AI_NUMERICSERV to fake-rfc2553. Our getaddrinfo implementation always returns numeric values already. commit ef342ab1ce6fb9a4b30186c89c309d0ae9d0eeb4 Author: Darren Tucker Date: Tue Feb 24 13:39:57 2015 +1100 Include OpenSSL's objects.h before bn.h. Prevents compile errors on some platforms (at least old GCCs and AIX's XLC compilers). commit dcc8997d116f615195aa7c9ec019fb36c28c6228 Author: Darren Tucker Date: Tue Feb 24 12:30:59 2015 +1100 Convert two macros into functions. Convert packet_send_debug and packet_disconnect from macros to functions. Some older GCCs (2.7.x, 2.95.x) see to have problems with variadic macros with only one argument so we convert these two into functions. ok djm@ commit 2285c30d51b7e2052c6526445abe7e7cc7e170a1 Author: djm@openbsd.org Date: Mon Feb 23 22:21:21 2015 +0000 upstream commit further silence spurious error message even when -v is specified (e.g. to get visual host keys); reported by naddy@ commit 9af21979c00652029e160295e988dea40758ece2 Author: Damien Miller Date: Tue Feb 24 09:04:32 2015 +1100 don't include stdint.h unless HAVE_STDINT_H set commit 62f678dd51660d6f8aee1da33d3222c5de10a89e Author: Damien Miller Date: Tue Feb 24 09:02:54 2015 +1100 nother sys/queue.h -> sys-queue.h fix spotted by Tom Christensen commit b3c19151cba2c0ed01b27f55de0d723ad07ca98f Author: djm@openbsd.org Date: Mon Feb 23 20:32:15 2015 +0000 upstream commit fix a race condition by using a mux socket rather than an ineffectual wait statement commit a88dd1da119052870bb2654c1a32c51971eade16 Author: Damien Miller Date: Tue Feb 24 06:30:29 2015 +1100 various include fixes for portable commit 5248429b5ec524d0a65507cff0cdd6e0cb99effd Author: djm@openbsd.org Date: Mon Feb 23 16:55:51 2015 +0000 upstream commit add an XXX to remind me to improve sshkey_load_public commit e94e4b07ef2eaead38b085a60535df9981cdbcdb Author: djm@openbsd.org Date: Mon Feb 23 16:55:31 2015 +0000 upstream commit silence a spurious error message when listing fingerprints for known_hosts; bz#2342 commit f2293a65392b54ac721f66bc0b44462e8d1d81f8 Author: djm@openbsd.org Date: Mon Feb 23 16:33:25 2015 +0000 upstream commit fix setting/clearing of TTY raw mode around UpdateHostKeys=ask confirmation question; reported by Herb Goldman commit f2004cd1adf34492eae0a44b1ef84e0e31b06088 Author: Darren Tucker Date: Mon Feb 23 05:04:21 2015 +1100 Repair for non-ECC OpenSSL. Ifdef out the ECC parts when building with an OpenSSL that doesn't have it. commit 37f9220db8d1a52c75894c3de1e5f2ae5bd71b6f Author: Darren Tucker Date: Mon Feb 23 03:07:24 2015 +1100 Wrap stdint.h includes in ifdefs. commit f81f1bbc5b892c8614ea740b1f92735652eb43f0 Author: Tim Rice Date: Sat Feb 21 18:12:10 2015 -0800 out of tree build fix commit 2e13a1e4d22f3b503c3bfc878562cc7386a1d1ae Author: Tim Rice Date: Sat Feb 21 18:08:51 2015 -0800 mkdir kex unit test directory so testing out of tree builds works commit 1797f49b1ba31e8700231cd6b1d512d80bb50d2c Author: halex@openbsd.org Date: Sat Feb 21 21:46:57 2015 +0000 upstream commit make "ssh-add -d" properly remove a corresponding certificate, and also not whine and fail if there is none ok djm@ commit 7faaa32da83a609059d95dbfcb0649fdb04caaf6 Author: Damien Miller Date: Sun Feb 22 07:57:27 2015 +1100 mkdir hostkey and bitmap unit test directories commit bd49da2ef197efac5e38f5399263a8b47990c538 Author: djm@openbsd.org Date: Fri Feb 20 23:46:01 2015 +0000 upstream commit sort options useable under Match case-insensitively; prodded jmc@ commit 1a779a0dd6cd8b4a1a40ea33b5415ab8408128ac Author: djm@openbsd.org Date: Sat Feb 21 20:51:02 2015 +0000 upstream commit correct paths to configuration files being written/updated; they live in $OBJ not cwd; some by Roumen Petrov commit 28ba006c1acddff992ae946d0bc0b500b531ba6b Author: Darren Tucker Date: Sat Feb 21 15:41:07 2015 +1100 More correct checking of HAVE_DECL_AI_NUMERICSERV. commit e50e8c97a9cecae1f28febccaa6ca5ab3bc10f54 Author: Darren Tucker Date: Sat Feb 21 15:10:33 2015 +1100 Add null declaration of AI_NUMERICINFO. Some platforms (older FreeBSD and DragonFly versions) do have getaddrinfo() but do not have AI_NUMERICINFO. so define it to zero in those cases. commit 18a208d6a460d707a45916db63a571e805f5db46 Author: djm@openbsd.org Date: Fri Feb 20 22:40:32 2015 +0000 upstream commit more options that are available under Match; bz#2353 reported by calestyo AT scientia.net commit 44732de06884238049f285f1455b2181baa7dc82 Author: djm@openbsd.org Date: Fri Feb 20 22:17:21 2015 +0000 upstream commit UpdateHostKeys fixes: I accidentally changed the format of the hostkeys@openssh.com messages last week without changing the extension name, and this has been causing connection failures for people who are running -current. First reported by sthen@ s/hostkeys@openssh.com/hostkeys-00@openssh.com/ Change the name of the proof message too, and reorder it a little. Also, UpdateHostKeys=ask is incompatible with ControlPersist (no TTY available to read the response) so disable UpdateHostKeys if it is in ask mode and ControlPersist is active (and document this) commit 13a39414d25646f93e6d355521d832a03aaaffe2 Author: djm@openbsd.org Date: Tue Feb 17 00:14:05 2015 +0000 upstream commit Regression: I broke logging of public key fingerprints in 1.46. Pointed out by Pontus Lundkvist commit 773dda25e828c4c9a52f7bdce6e1e5924157beab Author: Damien Miller Date: Fri Jan 30 23:10:17 2015 +1100 repair --without-openssl; broken in refactor commit e89c780886b23600de1e1c8d74aabd1ff61f43f0 Author: Damien Miller Date: Tue Feb 17 10:04:55 2015 +1100 hook up hostkeys unittest to portable Makefiles commit 0abf41f99aa16ff09b263bead242d6cb2dbbcf99 Author: djm@openbsd.org Date: Mon Feb 16 22:21:03 2015 +0000 upstream commit enable hostkeys unit tests commit 68a5d647ccf0fb6782b2f749433a1eee5bc9044b Author: djm@openbsd.org Date: Mon Feb 16 22:20:50 2015 +0000 upstream commit check string/memory compare arguments aren't NULL commit ef575ef20d09f20722e26b45dab80b3620469687 Author: djm@openbsd.org Date: Mon Feb 16 22:18:34 2015 +0000 upstream commit unit tests for hostfile.c code, just hostkeys_foreach so far commit 8ea3365e6aa2759ccf5c76eaea62cbc8a280b0e7 Author: markus@openbsd.org Date: Sat Feb 14 12:43:16 2015 +0000 upstream commit test server rekey limit commit ce63c4b063c39b2b22d4ada449c9e3fbde788cb3 Author: djm@openbsd.org Date: Mon Feb 16 22:30:03 2015 +0000 upstream commit partial backout of: revision 1.441 date: 2015/01/31 20:30:05; author: djm; state: Exp; lines: +17 -10; commitid : x8klYPZMJSrVlt3O; Let sshd load public host keys even when private keys are missing. Allows sshd to advertise additional keys for future key rotation. Also log fingerprint of hostkeys loaded; ok markus@ hostkey updates now require access to the private key, so we can't load public keys only. The improved log messages (fingerprints of keys loaded) are kept. commit 523463a3a2a9bfc6cfc5afa01bae9147f76a37cc Author: djm@openbsd.org Date: Mon Feb 16 22:13:32 2015 +0000 upstream commit Revise hostkeys@openssh.com hostkey learning extension. The client will not ask the server to prove ownership of the private halves of any hitherto-unseen hostkeys it offers to the client. Allow UpdateHostKeys option to take an 'ask' argument to let the user manually review keys offered. ok markus@ commit 6c5c949782d86a6e7d58006599c7685bfcd01685 Author: djm@openbsd.org Date: Mon Feb 16 22:08:57 2015 +0000 upstream commit Refactor hostkeys_foreach() and dependent code Deal with IP addresses (i.e. CheckHostIP) Don't clobber known_hosts when nothing changed ok markus@ as part of larger commit commit 51b082ccbe633dc970df1d1f4c9c0497115fe721 Author: miod@openbsd.org Date: Mon Feb 16 18:26:26 2015 +0000 upstream commit Declare ge25519_base as extern, to prevent it from becoming a common. Gets us rid of ``lignment 4 of symbol `crypto_sign_ed25519_ref_ge25519_base' in mod_ge25519.o is smaller than 16 in mod_ed25519.o'' warnings at link time. commit 02db468bf7e3281a8e3c058ced571b38b6407c34 Author: markus@openbsd.org Date: Fri Feb 13 18:57:00 2015 +0000 upstream commit make rekey_limit for sshd w/privsep work; ok djm@ dtucker@ commit 8ec67d505bd23c8bf9e17b7a364b563a07a58ec8 Author: dtucker@openbsd.org Date: Thu Feb 12 20:34:19 2015 +0000 upstream commit Prevent sshd spamming syslog with "ssh_dispatch_run_fatal: disconnected". ok markus@ commit d4c0295d1afc342057ba358237acad6be8af480b Author: djm@openbsd.org Date: Wed Feb 11 01:20:38 2015 +0000 upstream commit Some packet error messages show the address of the peer, but might be generated after the socket to the peer has suffered a TCP reset. In these cases, getpeername() won't work so cache the address earlier. spotted in the wild via deraadt@ and tedu@ commit 4af1709cf774475ce5d1bc3ddcc165f6c222897d Author: jsg@openbsd.org Date: Mon Feb 9 23:22:37 2015 +0000 upstream commit fix some leaks in error paths ok markus@ commit fd36834871d06a03e1ff8d69e41992efa1bbf85f Author: millert@openbsd.org Date: Fri Feb 6 23:21:59 2015 +0000 upstream commit SIZE_MAX is standard, we should be using it in preference to the obsolete SIZE_T_MAX. OK miod@ beck@ commit 1910a286d7771eab84c0b047f31c0a17505236fa Author: millert@openbsd.org Date: Thu Feb 5 12:59:57 2015 +0000 upstream commit Include stdint.h, not limits.h to get SIZE_MAX. OK guenther@ commit ce4f59b2405845584f45e0b3214760eb0008c06c Author: deraadt@openbsd.org Date: Tue Feb 3 08:07:20 2015 +0000 upstream commit missing ; djm and mlarkin really having great interactions recently commit 5d34aa94938abb12b877a25be51862757f25d54b Author: halex@openbsd.org Date: Tue Feb 3 00:34:14 2015 +0000 upstream commit slightly extend the passphrase prompt if running with -c in order to give the user a chance to notice if unintentionally running without it wording tweak and ok djm@ commit cb3bde373e80902c7d5d0db429f85068d19b2918 Author: djm@openbsd.org Date: Mon Feb 2 22:48:53 2015 +0000 upstream commit handle PKCS#11 C_Login returning CKR_USER_ALREADY_LOGGED_IN; based on patch from Yuri Samoilenko; ok markus@ commit 15ad750e5ec3cc69765b7eba1ce90060e7083399 Author: djm@openbsd.org Date: Mon Feb 2 07:41:40 2015 +0000 upstream commit turn UpdateHostkeys off by default until I figure out mlarkin@'s warning message; requested by deraadt@ commit 3cd5103c1e1aaa59bd66f7f52f6ebbcd5deb12f9 Author: deraadt@openbsd.org Date: Mon Feb 2 01:57:44 2015 +0000 upstream commit increasing encounters with difficult DNS setups in darknets has convinced me UseDNS off by default is better ok djm commit 6049a548a8a68ff0bbe581ab1748ea6a59ecdc38 Author: djm@openbsd.org Date: Sat Jan 31 20:30:05 2015 +0000 upstream commit Let sshd load public host keys even when private keys are missing. Allows sshd to advertise additional keys for future key rotation. Also log fingerprint of hostkeys loaded; ok markus@ commit 46347ed5968f582661e8a70a45f448e0179ca0ab Author: djm@openbsd.org Date: Fri Jan 30 11:43:14 2015 +0000 upstream commit Add a ssh_config HostbasedKeyType option to control which host public key types are tried during hostbased authentication. This may be used to prevent too many keys being sent to the server, and blowing past its MaxAuthTries limit. bz#2211 based on patch by Iain Morgan; ok markus@ commit 802660cb70453fa4d230cb0233bc1bbdf8328de1 Author: djm@openbsd.org Date: Fri Jan 30 10:44:49 2015 +0000 upstream commit set a timeout to prevent hangs when talking to busted servers; ok markus@ commit 86936ec245a15c7abe71a0722610998b0a28b194 Author: djm@openbsd.org Date: Fri Jan 30 01:11:39 2015 +0000 upstream commit regression test for 'wildcard CA' serial/key ID revocations commit 4509b5d4a4fa645a022635bfa7e86d09b285001f Author: djm@openbsd.org Date: Fri Jan 30 01:13:33 2015 +0000 upstream commit avoid more fatal/exit in the packet.c paths that ssh-keyscan uses; feedback and "looks good" markus@ commit 669aee994348468af8b4b2ebd29b602cf2860b22 Author: djm@openbsd.org Date: Fri Jan 30 01:10:33 2015 +0000 upstream commit permit KRLs that revoke certificates by serial number or key ID without scoping to a particular CA; ok markus@ commit 7a2c368477e26575d0866247d3313da4256cb2b5 Author: djm@openbsd.org Date: Fri Jan 30 00:59:19 2015 +0000 upstream commit missing parentheses after if in do_convert_from() broke private key conversion from other formats some time in 2010; bz#2345 reported by jjelen AT redhat.com commit 25f5f78d8bf5c22d9cea8b49de24ebeee648a355 Author: djm@openbsd.org Date: Fri Jan 30 00:22:25 2015 +0000 upstream commit fix ssh protocol 1, spotted by miod@ commit 9ce86c926dfa6e0635161b035e3944e611cbccf0 Author: djm@openbsd.org Date: Wed Jan 28 22:36:00 2015 +0000 upstream commit update to new API (key_fingerprint => sshkey_fingerprint) check sshkey_fingerprint return values; ok markus commit 9125525c37bf73ad3ee4025520889d2ce9d10f29 Author: djm@openbsd.org Date: Wed Jan 28 22:05:31 2015 +0000 upstream commit avoid fatal() calls in packet code makes ssh-keyscan more reliable against server failures ok dtucker@ markus@ commit fae7bbe544cba7a9e5e4ab47ff6faa3d978646eb Author: djm@openbsd.org Date: Wed Jan 28 21:15:47 2015 +0000 upstream commit avoid fatal() calls in packet code makes ssh-keyscan more reliable against server failures ok dtucker@ markus@ commit 1a3d14f6b44a494037c7deab485abe6496bf2c60 Author: djm@openbsd.org Date: Wed Jan 28 11:07:25 2015 +0000 upstream commit remove obsolete comment commit 80c25b7bc0a71d75c43a4575d9a1336f589eb639 Author: okan@openbsd.org Date: Tue Jan 27 12:54:06 2015 +0000 upstream commit Since r1.2 removed the use of PRI* macros, inttypes.h is no longer required. ok djm@ commit 69ff64f69615c2a21c97cb5878a0996c21423257 Author: Damien Miller Date: Tue Jan 27 23:07:43 2015 +1100 compile on systems without TCP_MD5SIG (e.g. OSX) commit 358964f3082fb90b2ae15bcab07b6105cfad5a43 Author: Damien Miller Date: Tue Jan 27 23:07:25 2015 +1100 use ssh-keygen under test rather than system's commit a2c95c1bf33ea53038324d1fdd774bc953f98236 Author: Damien Miller Date: Tue Jan 27 23:06:59 2015 +1100 OSX lacks HOST_NAME_MAX, has _POSIX_HOST_NAME_MAX commit ade31d7b6f608a19b85bee29a7a00b1e636a2919 Author: Damien Miller Date: Tue Jan 27 23:06:23 2015 +1100 these need active_state defined to link on OSX temporary measure until active_state goes away entirely commit e56aa87502f22c5844918c10190e8b4f785f067b Author: djm@openbsd.org Date: Tue Jan 27 12:01:36 2015 +0000 upstream commit use printf instead of echo -n to reduce diff against -portable commit 9f7637f56eddfaf62ce3c0af89c25480f2cf1068 Author: jmc@openbsd.org Date: Mon Jan 26 13:55:29 2015 +0000 upstream commit sort previous; commit 3076ee7d530d5b16842fac7a6229706c7e5acd26 Author: djm@openbsd.org Date: Mon Jan 26 13:36:53 2015 +0000 upstream commit properly restore umask commit d411d395556b73ba1b9e451516a0bd6697c4b03d Author: djm@openbsd.org Date: Mon Jan 26 06:12:18 2015 +0000 upstream commit regression test for host key rotation commit fe8a3a51699afbc6407a8fae59b73349d01e49f8 Author: djm@openbsd.org Date: Mon Jan 26 06:11:28 2015 +0000 upstream commit adapt to sshkey API tweaks commit 7dd355fb1f0038a3d5cdca57ebab4356c7a5b434 Author: miod@openbsd.org Date: Sat Jan 24 10:39:21 2015 +0000 upstream commit Move -lz late in the linker commandline for things to build on static arches. commit 0dad3b806fddb93c475b30853b9be1a25d673a33 Author: miod@openbsd.org Date: Fri Jan 23 21:21:23 2015 +0000 upstream commit -Wpointer-sign is supported by gcc 4 only. commit 2b3b1c1e4bd9577b6e780c255c278542ea66c098 Author: djm@openbsd.org Date: Tue Jan 20 22:58:57 2015 +0000 upstream commit use SUBDIR to recuse into unit tests; makes "make obj" actually work commit 1d1092bff8db27080155541212b420703f8b9c92 Author: djm@openbsd.org Date: Mon Jan 26 12:16:36 2015 +0000 upstream commit correct description of UpdateHostKeys in ssh_config.5 and add it to -o lists for ssh, scp and sftp; pointed out by jmc@ commit 5104db7cbd6cdd9c5971f4358e74414862fc1022 Author: djm@openbsd.org Date: Mon Jan 26 06:10:03 2015 +0000 upstream commit correctly match ECDSA subtype (== curve) for offered/recevied host keys. Fixes connection-killing host key mismatches when a server offers multiple ECDSA keys with different curve type (an extremely unlikely configuration). ok markus, "looks mechanical" deraadt@ commit 8d4f87258f31cb6def9b3b55b6a7321d84728ff2 Author: djm@openbsd.org Date: Mon Jan 26 03:04:45 2015 +0000 upstream commit Host key rotation support. Add a hostkeys@openssh.com protocol extension (global request) for a server to inform a client of all its available host key after authentication has completed. The client may record the keys in known_hosts, allowing it to upgrade to better host key algorithms and a server to gracefully rotate its keys. The client side of this is controlled by a UpdateHostkeys config option (default on). ok markus@ commit 60b1825262b1f1e24fc72050b907189c92daf18e Author: djm@openbsd.org Date: Mon Jan 26 02:59:11 2015 +0000 upstream commit small refactor and add some convenience functions; ok markus commit a5a3e3328ddce91e76f71ff479022d53e35c60c9 Author: jmc@openbsd.org Date: Thu Jan 22 21:00:42 2015 +0000 upstream commit heirarchy -> hierarchy; commit dcff5810a11195c57e1b3343c0d6b6f2b9974c11 Author: deraadt@openbsd.org Date: Thu Jan 22 20:24:41 2015 +0000 upstream commit Provide a warning about chroot misuses (which sadly, seem to have become quite popular because shiny). sshd cannot detect/manage/do anything about these cases, best we can do is warn in the right spot in the man page. ok markus commit 087266ec33c76fc8d54ac5a19efacf2f4a4ca076 Author: deraadt@openbsd.org Date: Tue Jan 20 23:14:00 2015 +0000 upstream commit Reduce use of and transition to throughout. ok djm markus commit 57e783c8ba2c0797f93977e83b2a8644a03065d8 Author: markus@openbsd.org Date: Tue Jan 20 20:16:21 2015 +0000 upstream commit kex_setup errors are fatal() commit 1d6424a6ff94633c221297ae8f42d54e12a20912 Author: djm@openbsd.org Date: Tue Jan 20 08:02:33 2015 +0000 upstream commit this test would accidentally delete agent.sh if run without obj/ commit 12b5f50777203e12575f1b08568281e447249ed3 Author: djm@openbsd.org Date: Tue Jan 20 07:56:44 2015 +0000 upstream commit make this compile with KERBEROS5 enabled commit e2cc6bef08941256817d44d146115b3478586ad4 Author: djm@openbsd.org Date: Tue Jan 20 07:55:33 2015 +0000 upstream commit fix hostkeys in agent; ok markus@ commit 1ca3e2155aa5d3801a7ae050f85c71f41fcb95b1 Author: Damien Miller Date: Tue Jan 20 10:11:31 2015 +1100 fix kex test commit c78a578107c7e6dcf5d30a2f34cb6581bef14029 Author: markus@openbsd.org Date: Mon Jan 19 20:45:25 2015 +0000 upstream commit finally enable the KEX tests I wrote some years ago... commit 31821d7217e686667d04935aeec99e1fc4a46e7e Author: markus@openbsd.org Date: Mon Jan 19 20:42:31 2015 +0000 upstream commit adapt to new error message (SSH_ERR_MAC_INVALID) commit d3716ca19e510e95d956ae14d5b367e364bff7f1 Author: djm@openbsd.org Date: Mon Jan 19 17:31:13 2015 +0000 upstream commit this test was broken in at least two ways, such that it wasn't checking that a KRL was not excluding valid keys commit 3f797653748e7c2b037dacb57574c01d9ef3b4d3 Author: markus@openbsd.org Date: Mon Jan 19 20:32:39 2015 +0000 upstream commit switch ssh-keyscan from setjmp to multiple ssh transport layer instances ok djm@ commit f582f0e917bb0017b00944783cd5f408bf4b0b5e Author: markus@openbsd.org Date: Mon Jan 19 20:30:23 2015 +0000 upstream commit add experimental api for packet layer; ok djm@ commit 48b3b2ba75181f11fca7f327058a591f4426cade Author: markus@openbsd.org Date: Mon Jan 19 20:20:20 2015 +0000 upstream commit store compat flags in struct ssh; ok djm@ commit 57d10cbe861a235dd269c74fb2fe248469ecee9d Author: markus@openbsd.org Date: Mon Jan 19 20:16:15 2015 +0000 upstream commit adapt kex to sshbuf and struct ssh; ok djm@ commit 3fdc88a0def4f86aa88a5846ac079dc964c0546a Author: markus@openbsd.org Date: Mon Jan 19 20:07:45 2015 +0000 upstream commit move dispatch to struct ssh; ok djm@ commit 091c302829210c41e7f57c3f094c7b9c054306f0 Author: markus@openbsd.org Date: Mon Jan 19 19:52:16 2015 +0000 upstream commit update packet.c & isolate, introduce struct ssh a) switch packet.c to buffer api and isolate per-connection info into struct ssh b) (de)serialization of the state is moved from monitor to packet.c c) the old packet.c API is implemented in opacket.[ch] d) compress.c/h is removed and integrated into packet.c with and ok djm@ commit 4e62cc68ce4ba20245d208b252e74e91d3785b74 Author: djm@openbsd.org Date: Mon Jan 19 17:35:48 2015 +0000 upstream commit fix format strings in (disabled) debugging commit d85e06245907d49a2cd0cfa0abf59150ad616f42 Author: djm@openbsd.org Date: Mon Jan 19 06:01:32 2015 +0000 upstream commit be a bit more careful in these tests to ensure that known_hosts is clean commit 7947810eab5fe0ad311f32a48f4d4eb1f71be6cf Author: djm@openbsd.org Date: Sun Jan 18 22:00:18 2015 +0000 upstream commit regression test for known_host file editing using ssh-keygen (-H / -R / -F) after hostkeys_foreach() change; feedback and ok markus@ commit 3a2b09d147a565d8a47edf37491e149a02c0d3a3 Author: djm@openbsd.org Date: Sun Jan 18 19:54:46 2015 +0000 upstream commit more and better key tests test signatures and verification test certificate generation flesh out nested cert test removes most of the XXX todo markers commit 589e69fd82724cfc9738f128e4771da2e6405d0d Author: djm@openbsd.org Date: Sun Jan 18 19:53:58 2015 +0000 upstream commit make the signature fuzzing test much more rigorous: ensure that the fuzzed input cases do not match the original (using new fuzz_matches_original() function) and check that the verification fails in each case commit 80603c0daa2538c349c1c152405580b164d5475f Author: djm@openbsd.org Date: Sun Jan 18 19:52:44 2015 +0000 upstream commit add a fuzz_matches_original() function to the fuzzer to detect fuzz cases that are identical to the original data. Hacky implementation, but very useful when you need the fuzz to be different, e.g. when verifying signature commit 87d5495bd337e358ad69c524fcb9495208c0750b Author: djm@openbsd.org Date: Sun Jan 18 19:50:55 2015 +0000 upstream commit better dumps from the fuzzer (shown on errors) - include the original data as well as the fuzzed copy. commit d59ec478c453a3fff05badbbfd96aa856364f2c2 Author: djm@openbsd.org Date: Sun Jan 18 19:47:55 2015 +0000 upstream commit enable hostkey-agent.sh test commit 26b3425170bf840e4b095e1c10bf25a0a3e3a105 Author: djm@openbsd.org Date: Sat Jan 17 18:54:30 2015 +0000 upstream commit unit test for hostkeys in ssh-agent commit 9e06a0fb23ec55d9223b26a45bb63c7649e2f2f2 Author: markus@openbsd.org Date: Thu Jan 15 23:41:29 2015 +0000 upstream commit add kex unit tests commit d2099dec6da21ae627f6289aedae6bc1d41a22ce Author: deraadt@openbsd.org Date: Mon Jan 19 00:32:54 2015 +0000 upstream commit djm, your /usr/include tree is old commit 2b3c3c76c30dc5076fe09d590f5b26880f148a54 Author: djm@openbsd.org Date: Sun Jan 18 21:51:19 2015 +0000 upstream commit some feedback from markus@: comment hostkeys_foreach() context and avoid a member in it. commit cecb30bc2ba6d594366e657d664d5c494b6c8a7f Author: djm@openbsd.org Date: Sun Jan 18 21:49:42 2015 +0000 upstream commit make ssh-keygen use hostkeys_foreach(). Removes some horrendous code; ok markus@ commit ec3d065df3a9557ea96b02d061fd821a18c1a0b9 Author: djm@openbsd.org Date: Sun Jan 18 21:48:09 2015 +0000 upstream commit convert load_hostkeys() (hostkey ordering and known_host matching) to use the new hostkey_foreach() iterator; ok markus commit c29811cc480a260e42fd88849fc86a80c1e91038 Author: djm@openbsd.org Date: Sun Jan 18 21:40:23 2015 +0000 upstream commit introduce hostkeys_foreach() to allow iteration over a known_hosts file or controlled subset thereof. This will allow us to pull out some ugly and duplicated code, and will be used to implement hostkey rotation later. feedback and ok markus commit f101d8291da01bbbfd6fb8c569cfd0cc61c0d346 Author: deraadt@openbsd.org Date: Sun Jan 18 14:01:00 2015 +0000 upstream commit string truncation due to sizeof(size) ok djm markus commit 35d6022b55b7969fc10c261cb6aa78cc4a5fcc41 Author: djm@openbsd.org Date: Sun Jan 18 13:33:34 2015 +0000 upstream commit avoid trailing ',' in host key algorithms commit 7efb455789a0cb76bdcdee91c6060a3dc8f5c007 Author: djm@openbsd.org Date: Sun Jan 18 13:22:28 2015 +0000 upstream commit infer key length correctly when user specified a fully- qualified key name instead of using the -b bits option; ok markus@ commit 83f8ffa6a55ccd0ce9d8a205e3e7439ec18fedf5 Author: djm@openbsd.org Date: Sat Jan 17 18:53:34 2015 +0000 upstream commit fix hostkeys on ssh agent; found by unit test I'm about to commit commit 369d61f17657b814124268f99c033e4dc6e436c1 Author: schwarze@openbsd.org Date: Fri Jan 16 16:20:23 2015 +0000 upstream commit garbage collect empty .No macros mandoc warns about commit bb8b442d32dbdb8521d610e10d8b248d938bd747 Author: djm@openbsd.org Date: Fri Jan 16 15:55:07 2015 +0000 upstream commit regression: incorrect error message on otherwise-successful ssh-keygen -A. Reported by Dmitry Orlov, via deraadt@ commit 9010902954a40b59d0bf3df3ccbc3140a653e2bc Author: djm@openbsd.org Date: Fri Jan 16 07:19:48 2015 +0000 upstream commit when hostname canonicalisation is enabled, try to parse hostnames as addresses before looking them up for canonicalisation. fixes bz#2074 and avoids needless DNS lookups in some cases; ok markus commit 2ae4f337b2a5fb2841b6b0053b49496fef844d1c Author: deraadt@openbsd.org Date: Fri Jan 16 06:40:12 2015 +0000 upstream commit Replace with and other less dirty headers where possible. Annotate lines with their current reasons. Switch to PATH_MAX, NGROUPS_MAX, HOST_NAME_MAX+1, LOGIN_NAME_MAX, etc. Change MIN() and MAX() to local definitions of MINIMUM() and MAXIMUM() where sensible to avoid pulling in the pollution. These are the files confirmed through binary verification. ok guenther, millert, doug (helped with the verification protocol) commit 3c4726f4c24118e8f1bb80bf75f1456c76df072c Author: markus@openbsd.org Date: Thu Jan 15 21:38:50 2015 +0000 upstream commit remove xmalloc, switch to sshbuf commit e17ac01f8b763e4b83976b9e521e90a280acc097 Author: markus@openbsd.org Date: Thu Jan 15 21:37:14 2015 +0000 upstream commit switch to sshbuf commit ddef9995a1fa6c7a8ff3b38bfe6cf724bebf13d0 Author: naddy@openbsd.org Date: Thu Jan 15 18:32:54 2015 +0000 upstream commit handle UMAC128 initialization like UMAC; ok djm@ markus@ commit f14564c1f7792446bca143580aef0e7ac25dcdae Author: djm@openbsd.org Date: Thu Jan 15 11:04:36 2015 +0000 upstream commit fix regression reported by brad@ for passworded keys without agent present commit 45c0fd70bb2a88061319dfff20cb12ef7b1bc47e Author: Damien Miller Date: Thu Jan 15 22:08:23 2015 +1100 make bitmap test compile commit d333f89abf7179021e5c3f28673f469abe032062 Author: djm@openbsd.org Date: Thu Jan 15 07:36:28 2015 +0000 upstream commit unit tests for KRL bitmap commit 7613f828f49c55ff356007ae9645038ab6682556 Author: markus@openbsd.org Date: Wed Jan 14 09:58:21 2015 +0000 upstream commit re-add comment about full path commit 6c43b48b307c41cd656b415621a644074579a578 Author: markus@openbsd.org Date: Wed Jan 14 09:54:38 2015 +0000 upstream commit don't reset to the installed sshd; connect before reconfigure, too commit 771bb47a1df8b69061f09462e78aa0b66cd594bf Author: djm@openbsd.org Date: Tue Jan 13 14:51:51 2015 +0000 upstream commit implement a SIGINFO handler so we can discern a stuck fuzz test from a merely glacial one; prompted by and ok markus commit cfaa57962f8536f3cf0fd7daf4d6a55d6f6de45f Author: djm@openbsd.org Date: Tue Jan 13 08:23:26 2015 +0000 upstream commit use $SSH instead of installed ssh to allow override; spotted by markus@ commit 0920553d0aee117a596b03ed5b49b280d34a32c5 Author: djm@openbsd.org Date: Tue Jan 13 07:49:49 2015 +0000 upstream commit regress test for PubkeyAcceptedKeyTypes; ok markus@ commit 27ca1a5c0095eda151934bca39a77e391f875d17 Author: markus@openbsd.org Date: Mon Jan 12 20:13:27 2015 +0000 upstream commit unbreak parsing of pubkey comments; with gerhard; ok djm/deraadt commit 55358f0b4e0b83bc0df81c5f854c91b11e0bb4dc Author: djm@openbsd.org Date: Mon Jan 12 11:46:32 2015 +0000 upstream commit fatal if soft-PKCS11 library is missing rather (rather than continue and fail with a more cryptic error) commit c3554cdd2a1a62434b8161017aa76fa09718a003 Author: djm@openbsd.org Date: Mon Jan 12 11:12:38 2015 +0000 upstream commit let this test all supporte key types; pointed out/ok markus@ commit 1129dcfc5a3e508635004bcc05a3574cb7687167 Author: djm@openbsd.org Date: Thu Jan 15 09:40:00 2015 +0000 upstream commit sync ssh-keysign, ssh-keygen and some dependencies to the new buffer/key API; mostly mechanical, ok markus@ commit e4ebf5586452bf512da662ac277aaf6ecf0efe7c Author: djm@openbsd.org Date: Thu Jan 15 07:57:08 2015 +0000 upstream commit remove commented-out test code now that it has moved to a proper unit test commit e81cba066c1e9eb70aba0f6e7c0ff220611b370f Author: djm@openbsd.org Date: Wed Jan 14 20:54:29 2015 +0000 upstream commit whitespace commit 141efe49542f7156cdbc2e4cd0a041d8b1aab622 Author: djm@openbsd.org Date: Wed Jan 14 20:05:27 2015 +0000 upstream commit move authfd.c and its tentacles to the new buffer/key API; ok markus@ commit 0088c57af302cda278bd26d8c3ae81d5b6f7c289 Author: djm@openbsd.org Date: Wed Jan 14 19:33:41 2015 +0000 upstream commit fix small regression: ssh-agent would return a success message but an empty signature if asked to sign using an unknown key; ok markus@ commit b03ebe2c22b8166e4f64c37737f4278676e3488d Author: Damien Miller Date: Thu Jan 15 03:08:58 2015 +1100 more --without-openssl fix some regressions caused by upstream merges enable KRLs now that they no longer require BIGNUMs commit bc42cc6fe784f36df225c44c93b74830027cb5a2 Author: Damien Miller Date: Thu Jan 15 03:08:29 2015 +1100 kludge around tun API mismatch betterer commit c332110291089b624fa0951fbf2d1ee6de525b9f Author: Damien Miller Date: Thu Jan 15 02:59:51 2015 +1100 some systems lack SO_REUSEPORT commit 83b9678a62cbdc74eb2031cf1e1e4ffd58e233ae Author: Damien Miller Date: Thu Jan 15 02:35:50 2015 +1100 fix merge botch commit 0cdc5a3eb6fb383569a4da2a30705d9b90428d6b Author: Damien Miller Date: Thu Jan 15 02:35:33 2015 +1100 unbreak across API change commit 6e2549ac2b5e7f96cbc2d83a6e0784b120444b47 Author: Damien Miller Date: Thu Jan 15 02:30:18 2015 +1100 need includes.h for portable OpenSSH commit 72ef7c148c42db7d5632a29f137f8b87b579f2d9 Author: Damien Miller Date: Thu Jan 15 02:21:31 2015 +1100 support --without-openssl at configure time Disables and removes dependency on OpenSSL. Many features don't work and the set of crypto options is greatly restricted. This will only work on system with native arc4random or /dev/urandom. Considered highly experimental for now. commit 4f38c61c68ae7e3f9ee4b3c38bc86cd39f65ece9 Author: Damien Miller Date: Thu Jan 15 02:28:00 2015 +1100 add files missed in last commit commit a165bab605f7be55940bb8fae977398e8c96a46d Author: djm@openbsd.org Date: Wed Jan 14 15:02:39 2015 +0000 upstream commit avoid BIGNUM in KRL code by using a simple bitmap; feedback and ok markus commit 7d845f4a0b7ec97887be204c3760e44de8bf1f32 Author: djm@openbsd.org Date: Wed Jan 14 13:54:13 2015 +0000 upstream commit update sftp client and server to new buffer API. pretty much just mechanical changes; with & ok markus commit 139ca81866ec1b219c717d17061e5e7ad1059e2a Author: markus@openbsd.org Date: Wed Jan 14 13:09:09 2015 +0000 upstream commit switch to sshbuf/sshkey; with & ok djm@ commit 81bfbd0bd35683de5d7f2238b985e5f8150a9180 Author: Damien Miller Date: Wed Jan 14 21:48:18 2015 +1100 support --without-openssl at configure time Disables and removes dependency on OpenSSL. Many features don't work and the set of crypto options is greatly restricted. This will only work on system with native arc4random or /dev/urandom. Considered highly experimental for now. commit 54924b53af15ccdcbb9f89984512b5efef641a31 Author: djm@openbsd.org Date: Wed Jan 14 10:46:28 2015 +0000 upstream commit avoid an warning for the !OPENSSL case commit ae8b463217f7c9b66655bfc3945c050ffdaeb861 Author: markus@openbsd.org Date: Wed Jan 14 10:30:34 2015 +0000 upstream commit swith auth-options to new sshbuf/sshkey; ok djm@ commit 540e891191b98b89ee90aacf5b14a4a68635e763 Author: djm@openbsd.org Date: Wed Jan 14 10:29:45 2015 +0000 upstream commit make non-OpenSSL aes-ctr work on sshd w/ privsep; ok markus@ commit 60c2c4ea5e1ad0ddfe8b2877b78ed5143be79c53 Author: markus@openbsd.org Date: Wed Jan 14 10:24:42 2015 +0000 upstream commit remove unneeded includes, sync my copyright across files & whitespace; ok djm@ commit 128343bcdb0b60fc826f2733df8cf979ec1627b4 Author: markus@openbsd.org Date: Tue Jan 13 19:31:40 2015 +0000 upstream commit adapt mac.c to ssherr.h return codes (de-fatal) and simplify dependencies ok djm@ commit e7fd952f4ea01f09ceb068721a5431ac2fd416ed Author: djm@openbsd.org Date: Tue Jan 13 19:04:35 2015 +0000 upstream commit sync changes from libopenssh; prepared by markus@ mostly debug output tweaks, a couple of error return value changes and some other minor stuff commit 76c0480a85675f03a1376167cb686abed01a3583 Author: Damien Miller Date: Tue Jan 13 19:38:18 2015 +1100 add --without-ssh1 option to configure Allows disabling support for SSH protocol 1. commit 1f729f0614d1376c3332fa1edb6a5e5cec7e9e03 Author: djm@openbsd.org Date: Tue Jan 13 07:39:19 2015 +0000 upstream commit add sshd_config HostbasedAcceptedKeyTypes and PubkeyAcceptedKeyTypes options to allow sshd to control what public key types will be accepted. Currently defaults to all. Feedback & ok markus@ commit 816d1538c24209a93ba0560b27c4fda57c3fff65 Author: markus@openbsd.org Date: Mon Jan 12 20:13:27 2015 +0000 upstream commit unbreak parsing of pubkey comments; with gerhard; ok djm/deraadt commit 0097565f849851812df610b7b6b3c4bd414f6c62 Author: markus@openbsd.org Date: Mon Jan 12 19:22:46 2015 +0000 upstream commit missing error assigment on sshbuf_put_string() commit a7f49dcb527dd17877fcb8d5c3a9a6f550e0bba5 Author: djm@openbsd.org Date: Mon Jan 12 15:18:07 2015 +0000 upstream commit apparently memcpy(x, NULL, 0) is undefined behaviour according to C99 (cf. sections 7.21.1 and 7.1.4), so check skip memcpy calls when length==0; ok markus@ commit 905fe30fca82f38213763616d0d26eb6790bde33 Author: markus@openbsd.org Date: Mon Jan 12 14:05:19 2015 +0000 upstream commit free->sshkey_free; ok djm@ commit f067cca2bc20c86b110174c3fef04086a7f57b13 Author: markus@openbsd.org Date: Mon Jan 12 13:29:27 2015 +0000 upstream commit allow WITH_OPENSSL w/o WITH_SSH1; ok djm@ commit c4bfafcc2a9300d9cfb3c15e75572d3a7d74670d Author: djm@openbsd.org Date: Thu Jan 8 13:10:58 2015 +0000 upstream commit adjust for sshkey_load_file() API change commit e752c6d547036c602b89e9e704851463bd160e32 Author: djm@openbsd.org Date: Thu Jan 8 13:44:36 2015 +0000 upstream commit fix ssh_config FingerprintHash evaluation order; from Petr Lautrbach commit ab24ab847b0fc94c8d5e419feecff0bcb6d6d1bf Author: djm@openbsd.org Date: Thu Jan 8 10:15:45 2015 +0000 upstream commit reorder hostbased key attempts to better match the default hostkey algorithms order in myproposal.h; ok markus@ commit 1195f4cb07ef4b0405c839293c38600b3e9bdb46 Author: djm@openbsd.org Date: Thu Jan 8 10:14:08 2015 +0000 upstream commit deprecate key_load_private_pem() and sshkey_load_private_pem() interfaces. Refactor the generic key loading API to not require pathnames to be specified (they weren't really used). Fixes a few other things en passant: Makes ed25519 keys work for hostbased authentication (ssh-keysign previously used the PEM-only routines). Fixes key comment regression bz#2306: key pathnames were being lost as comment fields. ok markus@ commit febbe09e4e9aff579b0c5cc1623f756862e4757d Author: tedu@openbsd.org Date: Wed Jan 7 18:15:07 2015 +0000 upstream commit workaround for the Meyer, et al, Bleichenbacher Side Channel Attack. fake up a bignum key before RSA decryption. discussed/ok djm markus commit 5191df927db282d3123ca2f34a04d8d96153911a Author: djm@openbsd.org Date: Tue Dec 23 22:42:48 2014 +0000 upstream commit KNF and add a little more debug() commit 8abd80315d3419b20e6938f74d37e2e2b547f0b7 Author: jmc@openbsd.org Date: Mon Dec 22 09:26:31 2014 +0000 upstream commit add fingerprinthash to the options list; commit 296ef0560f60980da01d83b9f0e1a5257826536f Author: jmc@openbsd.org Date: Mon Dec 22 09:24:59 2014 +0000 upstream commit tweak previous; commit 462082eacbd37778a173afb6b84c6f4d898a18b5 Author: Damien Miller Date: Tue Dec 30 08:16:11 2014 +1100 avoid uninitialised free of ldns_res If an invalid rdclass was passed to getrrsetbyname() then this would execute a free on an uninitialised pointer. OpenSSH only ever calls this with a fixed and valid rdclass. Reported by Joshua Rogers commit 01b63498801053f131a0740eb9d13faf35d636c8 Author: Damien Miller Date: Mon Dec 29 18:10:18 2014 +1100 pull updated OpenBSD BCrypt PBKDF implementation Includes fix for 1 byte output overflow for large key length requests (not reachable in OpenSSH). Pointed out by Joshua Rogers commit c528c1b4af2f06712177b3de9b30705752f7cbcb Author: Damien Miller Date: Tue Dec 23 15:26:13 2014 +1100 fix variable name for IPv6 case in construct_utmpx patch from writeonce AT midipix.org via bz#2296 commit 293cac52dcda123244b2e594d15592e5e481c55e Author: Damien Miller Date: Mon Dec 22 16:30:42 2014 +1100 include and use OpenBSD netcat in regress/ commit 8f6784f0cb56dc4fd00af3e81a10050a5785228d Author: djm@openbsd.org Date: Mon Dec 22 09:05:17 2014 +0000 upstream commit mention ssh -Q feature to list supported { MAC, cipher, KEX, key } algorithms in more places and include the query string used to list the relevant information; bz#2288 commit 449e11b4d7847079bd0a2daa6e3e7ea03d8ef700 Author: jmc@openbsd.org Date: Mon Dec 22 08:24:17 2014 +0000 upstream commit tweak previous; commit 4bea0ab3290c0b9dd2aa199e932de8e7e18062d6 Author: djm@openbsd.org Date: Mon Dec 22 08:06:03 2014 +0000 upstream commit regression test for multiple required pubkey authentication; ok markus@ commit f1c4d8ec52158b6f57834b8cd839605b0a33e7f2 Author: djm@openbsd.org Date: Mon Dec 22 08:04:23 2014 +0000 upstream commit correct description of what will happen when a AuthorizedKeysCommand is specified but AuthorizedKeysCommandUser is not (sshd will refuse to start) commit 161cf419f412446635013ac49e8c660cadc36080 Author: djm@openbsd.org Date: Mon Dec 22 07:55:51 2014 +0000 upstream commit make internal handling of filename arguments of "none" more consistent with ssh. "none" arguments are now replaced with NULL when the configuration is finalised. Simplifies checking later on (just need to test not-NULL rather than that + strcmp) and cleans up some inconsistencies. ok markus@ commit f69b69b8625be447b8826b21d87713874dac25a6 Author: djm@openbsd.org Date: Mon Dec 22 07:51:30 2014 +0000 upstream commit remember which public keys have been used for authentication and refuse to accept previously-used keys. This allows AuthenticationMethods=publickey,publickey to require that users authenticate using two _different_ pubkeys. ok markus@ commit 46ac2ed4677968224c4ca825bc98fc68dae183f0 Author: djm@openbsd.org Date: Mon Dec 22 07:24:11 2014 +0000 upstream commit fix passing of wildcard forward bind addresses when connection multiplexing is in use; patch from Sami Hartikainen via bz#2324; ok dtucker@ commit 0d1b241a262e4d0a6bbfdd595489ab1b853c43a1 Author: djm@openbsd.org Date: Mon Dec 22 06:14:29 2014 +0000 upstream commit make this slightly easier to diff against portable commit 0715bcdddbf68953964058f17255bf54734b8737 Author: Damien Miller Date: Mon Dec 22 13:47:07 2014 +1100 add missing regress output file commit 1e30483c8ad2c2f39445d4a4b6ab20c241e40593 Author: djm@openbsd.org Date: Mon Dec 22 02:15:52 2014 +0000 upstream commit adjust for new SHA256 key fingerprints and slightly-different MD5 hex fingerprint format commit 6b40567ed722df98593ad8e6a2d2448fc2b4b151 Author: djm@openbsd.org Date: Mon Dec 22 01:14:49 2014 +0000 upstream commit poll changes to netcat (usr.bin/netcat.c r1.125) broke this test; fix it by ensuring more stdio fds are sent to devnull commit a5375ccb970f49dddf7d0ef63c9b713ede9e7260 Author: jmc@openbsd.org Date: Sun Dec 21 23:35:14 2014 +0000 upstream commit tweak previous; commit b79efde5c3badf5ce4312fe608d8307eade533c5 Author: djm@openbsd.org Date: Sun Dec 21 23:12:42 2014 +0000 upstream commit document FingerprintHash here too commit d16bdd8027dd116afa01324bb071a4016cdc1a75 Author: Damien Miller Date: Mon Dec 22 10:18:09 2014 +1100 missing include for base64 encoding commit 56d1c83cdd1ac76f1c6bd41e01e80dad834f3994 Author: djm@openbsd.org Date: Sun Dec 21 22:27:55 2014 +0000 upstream commit Add FingerprintHash option to control algorithm used for key fingerprints. Default changes from MD5 to SHA256 and format from hex to base64. Feedback and ok naddy@ markus@ commit 058f839fe15c51be8b3a844a76ab9a8db550be4f Author: djm@openbsd.org Date: Thu Dec 18 23:58:04 2014 +0000 upstream commit don't count partial authentication success as a failure against MaxAuthTries; ok deraadt@ commit c7219f4f54d64d6dde66dbcf7a2699daa782d2a1 Author: djm@openbsd.org Date: Fri Dec 12 00:02:17 2014 +0000 upstream commit revert chunk I didn't mean to commit yet; via jmc@ commit 7de5991aa3997e2981440f39c1ea01273a0a2c7b Author: Damien Miller Date: Thu Dec 18 11:44:06 2014 +1100 upstream libc change revision 1.2 date: 2014/12/08 03:45:00; author: bcook; state: Exp; lines: +2 -2; commitid: 7zWEBgJJOCZ2hvTV; avoid left shift overflow in reallocarray. Some 64-bit platforms (e.g. Windows 64) have a 32-bit long. So, shifting 1UL 32-bits to the left causes an overflow. This replaces the constant 1UL with (size_t)1 so that we get the correct constant size for the platform. discussed with tedu@ & deraadt@ commit 2048f85a5e6da8bc6e0532efe02ecfd4e63c978c Author: Damien Miller Date: Thu Dec 18 10:15:49 2014 +1100 include CFLAGS in gnome askpass targets from Fedora commit 48b68ce19ca42fa488960028048dec023f7899bb Author: djm@openbsd.org Date: Thu Dec 11 08:20:09 2014 +0000 upstream commit explicitly include sys/param.h in files that use the howmany() macro; from portable commit d663bea30a294d440fef4398e5cd816317bd4518 Author: djm@openbsd.org Date: Thu Dec 11 05:25:06 2014 +0000 upstream commit mention AuthorizedKeysCommandUser must be set for AuthorizedKeysCommand to be run; bz#2287 commit 17bf3d81e00f2abb414a4fd271118cf4913f049f Author: djm@openbsd.org Date: Thu Dec 11 05:13:28 2014 +0000 upstream commit show in debug output which hostkeys are being tried when attempting hostbased auth; patch from Iain Morgan commit da0277e3717eadf5b15e03379fc29db133487e94 Author: djm@openbsd.org Date: Thu Dec 11 04:16:14 2014 +0000 upstream commit Make manual reflect reality: sftp-server's -d option accepts a "%d" option, not a "%h" one. bz#2316; reported by Kirk Wolf commit 4cf87f4b81fa9380bce5fcff7b0f8382ae3ad996 Author: djm@openbsd.org Date: Wed Dec 10 01:24:09 2014 +0000 upstream commit better error value for invalid signature length commit 4bfad14ca56f8ae04f418997816b4ba84e2cfc3c Author: Darren Tucker Date: Wed Dec 10 02:12:51 2014 +1100 Resync more with OpenBSD's rijndael.c, in particular "#if 0"-ing out some unused code. Should fix compile error reported by plautrba at redhat. commit 642652d280499691c8212ec6b79724b50008ce09 Author: Darren Tucker Date: Wed Dec 10 01:32:23 2014 +1100 Add reallocarray to compat library commit 3dfd8d93dfcc69261f5af99df56f3ff598581979 Author: djm@openbsd.org Date: Thu Dec 4 22:31:50 2014 +0000 upstream commit add tests for new client RevokedHostKeys option; refactor to make it a bit more readable commit a31046cad1aed16a0b55171192faa6d02665ccec Author: krw@openbsd.org Date: Wed Nov 19 13:35:37 2014 +0000 upstream commit Nuke yet more obvious #include duplications. ok deraadt@ commit a7c762e5b2c1093542c0bc1df25ccec0b4cf479f Author: djm@openbsd.org Date: Thu Dec 4 20:47:36 2014 +0000 upstream commit key_in_file() wrapper is no longer used commit 5e39a49930d885aac9c76af3129332b6e772cd75 Author: djm@openbsd.org Date: Thu Dec 4 02:24:32 2014 +0000 upstream commit add RevokedHostKeys option for the client Allow textfile or KRL-based revocation of hostkeys. commit 74de254bb92c684cf53461da97f52d5ba34ded80 Author: djm@openbsd.org Date: Thu Dec 4 01:49:59 2014 +0000 upstream commit convert KRL code to new buffer API ok markus@ commit db995f2eed5fc432598626fa3e30654503bf7151 Author: millert@openbsd.org Date: Wed Nov 26 18:34:51 2014 +0000 upstream commit Prefer setvbuf() to setlinebuf() for portability; ok deraadt@ commit 72bba3d179ced8b425272efe6956a309202a91f3 Author: jsg@openbsd.org Date: Mon Nov 24 03:39:22 2014 +0000 upstream commit Fix crashes in the handling of the sshd config file found with the afl fuzzer. ok deraadt@ djm@ commit 867f49c666adcfe92bf539d9c37c1accdea08bf6 Author: Damien Miller Date: Wed Nov 26 13:22:41 2014 +1100 Avoid Cygwin ssh-host-config reading /etc/group Patch from Corinna Vinschen commit 8b66f36291a721b1ba7c44f24a07fdf39235593e Author: Damien Miller Date: Wed Nov 26 13:20:35 2014 +1100 allow custom service name for sshd on Cygwin Permits the use of multiple sshd running with different service names. Patch by Florian Friesdorf via Corinna Vinschen commit 08c0eebf55d70a9ae1964399e609288ae3186a0c Author: jmc@openbsd.org Date: Sat Nov 22 19:21:03 2014 +0000 upstream commit restore word zapped in previous, and remove some useless "No" macros; commit a1418a0033fba43f061513e992e1cbcc3343e563 Author: deraadt@openbsd.org Date: Sat Nov 22 18:15:41 2014 +0000 upstream commit /dev/random has created the same effect as /dev/arandom (and /dev/urandom) for quite some time. Mop up the last few, by using /dev/random where we actually want it, or not even mentioning arandom where it is irrelevant. commit b6de5ac9ed421362f479d1ad4fa433d2e25dad5b Author: djm@openbsd.org Date: Fri Nov 21 01:00:38 2014 +0000 upstream commit fix NULL pointer dereference crash on invalid timestamp found using Michal Zalewski's afl fuzzer commit a1f8110cd5ed818d59b3a2964fab7de76e92c18e Author: mikeb@openbsd.org Date: Tue Nov 18 22:38:48 2014 +0000 upstream commit Sync AES code to the one shipped in OpenSSL/LibreSSL. This includes a commit made by Andy Polyakov to the OpenSSL source tree on Wed, 28 Jun 2006 with the following message: "Mitigate cache-collision timing attack on last round." OK naddy, miod, djm commit 335c83d5f35d8620e16b8aa26592d4f836e09ad2 Author: krw@openbsd.org Date: Tue Nov 18 20:54:28 2014 +0000 upstream commit Nuke more obvious #include duplications. ok deraadt@ millert@ tedu@ commit 51b64e44121194ae4bf153dee391228dada2abcb Author: djm@openbsd.org Date: Mon Nov 17 00:21:40 2014 +0000 upstream commit fix KRL generation when multiple CAs are in use We would generate an invalid KRL when revoking certs by serial number for multiple CA keys due to a section being written out twice. Also extend the regress test to catch this case by having it produce a multi-CA KRL. Reported by peter AT pean.org commit d2d51003a623e21fb2b25567c4878d915e90aa2a Author: djm@openbsd.org Date: Tue Nov 18 01:02:25 2014 +0000 upstream commit fix NULL pointer dereference crash in key loading found by Michal Zalewski's AFL fuzzer commit 9f9fad0191028edc43d100d0ded39419b6895fdf Author: djm@openbsd.org Date: Mon Nov 17 00:21:40 2014 +0000 upstream commit fix KRL generation when multiple CAs are in use We would generate an invalid KRL when revoking certs by serial number for multiple CA keys due to a section being written out twice. Also extend the regress test to catch this case by having it produce a multi-CA KRL. Reported by peter AT pean.org commit da8af83d3f7ec00099963e455010e0ed1d7d0140 Author: bentley@openbsd.org Date: Sat Nov 15 14:41:03 2014 +0000 upstream commit Reduce instances of `` '' in manuals. troff displays these as typographic quotes, but nroff implementations almost always print them literally, which rarely has the intended effect with modern fonts, even in stock xterm. These uses of `` '' can be replaced either with more semantic alternatives or with Dq, which prints typographic quotes in a UTF-8 locale (but will automatically fall back to `` '' in an ASCII locale). improvements and ok schwarze@ commit fc302561369483bb755b17f671f70fb894aec01d Author: djm@openbsd.org Date: Mon Nov 10 22:25:49 2014 +0000 upstream commit mux-related manual tweaks mention ControlPersist=0 is the same as ControlPersist=yes recommend that ControlPath sockets be placed in a og-w directory commit 0e4cff5f35ed11102fe3783779960ef07e0cd381 Author: Damien Miller Date: Wed Nov 5 11:01:31 2014 +1100 Prepare scripts for next Cygwin release Makes the Cygwin-specific ssh-user-config script independent of the existence of /etc/passwd. The next Cygwin release will allow to generate passwd and group entries from the Windows account DBs, so the scripts have to adapt. from Corinna Vinschen commit 7d0ba5336651731949762eb8877ce9e3b52df436 Author: Damien Miller Date: Thu Oct 30 10:45:41 2014 +1100 include version number in OpenSSL-too-old error commit 3bcb92e04d9207e9f78d82f7918c6d3422054ce9 Author: lteo@openbsd.org Date: Fri Oct 24 02:01:20 2014 +0000 upstream commit Remove unnecessary include: netinet/in_systm.h is not needed by these programs. NB. skipped for portable ok deraadt@ millert@ commit 6fdcaeb99532e28a69f1a1599fbd540bb15b70a0 Author: djm@openbsd.org Date: Mon Oct 20 03:43:01 2014 +0000 upstream commit whitespace commit 165bc8786299e261706ed60342985f9de93a7461 Author: daniel@openbsd.org Date: Tue Oct 14 03:09:59 2014 +0000 upstream commit plug a memory leak; from Maxime Villard. ok djm@ commit b1ba15f3885947c245c2dbfaad0a04ba050abea0 Author: jmc@openbsd.org Date: Thu Oct 9 06:21:31 2014 +0000 upstream commit tweak previous; commit 259a02ebdf74ad90b41d116ecf70aa823fa4c6e7 Author: djm@openbsd.org Date: Mon Oct 13 00:38:35 2014 +0000 upstream commit whitespace commit 957fbceb0f3166e41b76fdb54075ab3b9cc84cba Author: djm@openbsd.org Date: Wed Oct 8 22:20:25 2014 +0000 upstream commit Tweak config reparsing with host canonicalisation Make the second pass through the config files always run when hostname canonicalisation is enabled. Add a "Match canonical" criteria that allows ssh_config Match blocks to trigger only in the second config pass. Add a -G option to ssh that causes it to parse its configuration and dump the result to stdout, similar to "sshd -T" Allow ssh_config Port options set in the second config parse phase to be applied (they were being ignored). bz#2267 bz#2286; ok markus commit 5c0dafd38bf66feeeb45fa0741a5baf5ad8039ba Author: djm@openbsd.org Date: Wed Oct 8 22:15:27 2014 +0000 upstream commit another -Wpointer-sign from clang commit bb005dc815ebda9af3ae4b39ca101c4da918f835 Author: djm@openbsd.org Date: Wed Oct 8 22:15:06 2014 +0000 upstream commit fix a few -Wpointer-sign warnings from clang commit 3cc1fbb4fb0e804bfb873fd363cea91b27fc8188 Author: djm@openbsd.org Date: Wed Oct 8 21:45:48 2014 +0000 upstream commit parse cert sections using nested buffers to reduce copies; ok markus commit 4a45922aebf99164e2fc83d34fe55b11ae1866ef Author: djm@openbsd.org Date: Mon Oct 6 00:47:15 2014 +0000 upstream commit correct options in usage(); from mancha1 AT zoho.com commit 48dffd5bebae6fed0556dc5c36cece0370690618 Author: djm@openbsd.org Date: Tue Sep 9 09:45:36 2014 +0000 upstream commit mention permissions on tun(4) devices in PermitTunnel documentation; bz#2273 commit a5883d4eccb94b16c355987f58f86a7dee17a0c2 Author: djm@openbsd.org Date: Wed Sep 3 18:55:07 2014 +0000 upstream commit tighten permissions on pty when the "tty" group does not exist; pointed out by Corinna Vinschen; ok markus commit 180bcb406b58bf30723c01a6b010e48ee626dda8 Author: sobrado@openbsd.org Date: Sat Aug 30 16:32:25 2014 +0000 upstream commit typo. commit f70b22bcdd52f6bf127047b3584371e6e5d45627 Author: sobrado@openbsd.org Date: Sat Aug 30 15:33:50 2014 +0000 upstream commit improve capitalization for the Ed25519 public-key signature system. ok djm@ commit 7df8818409c752cf3f0c3f8044fe9aebed8647bd Author: doug@openbsd.org Date: Thu Aug 21 01:08:52 2014 +0000 upstream commit Free resources on error in mkstemp and fdopen ok djm@ commit 40ba4c9733aaed08304714faeb61529f18da144b Author: deraadt@openbsd.org Date: Wed Aug 20 01:28:55 2014 +0000 upstream commit djm how did you make a typo like that... commit 57d378ec9278ba417a726f615daad67d157de666 Author: djm@openbsd.org Date: Tue Aug 19 23:58:28 2014 +0000 upstream commit When dumping the server configuration (sshd -T), print correct KEX, MAC and cipher defaults. Spotted by Iain Morgan commit 7ff880ede5195d0b17e7f1e3b6cfbc4cb6f85240 Author: djm@openbsd.org Date: Tue Aug 19 23:57:18 2014 +0000 upstream commit ~-expand lcd paths commit 4460a7ad0c78d4cd67c467f6e9f4254d0404ed59 Author: Damien Miller Date: Sun Oct 12 12:35:48 2014 +1100 remove duplicated KEX_DH1 entry commit c9b8426a616138d0d762176c94f51aff3faad5ff Author: Damien Miller Date: Thu Oct 9 10:34:06 2014 +1100 remove ChangeLog file Commit logs will be generated from git at release time. commit 81d18ff7c93a04affbf3903e0963859763219aed Author: Damien Miller Date: Tue Oct 7 21:24:25 2014 +1100 delete contrib/caldera directory commit 0ec9e87d3638206456968202f05bb5123670607a Author: Damien Miller Date: Tue Oct 7 19:57:27 2014 +1100 test commit commit 8fb65a44568701b779f3d77326bceae63412d28d Author: Damien Miller Date: Tue Oct 7 09:21:49 2014 +1100 - (djm) Release OpenSSH-6.7 commit e8c9f2602c46f6781df5e52e6cd8413dab4602a3 Author: Damien Miller Date: Fri Oct 3 09:24:56 2014 +1000 - (djm) [sshd_config.5] typo; from Iain Morgan commit 703b98a26706f5083801d11059486d77491342ae Author: Damien Miller Date: Wed Oct 1 09:43:07 2014 +1000 - (djm) [openbsd-compat/Makefile.in openbsd-compat/kludge-fd_set.c] [openbsd-compat/openbsd-compat.h] Kludge around bad glibc _FORTIFY_SOURCE check that doesn't grok heap-allocated fd_sets; ok dtucker@ commit 0fa0ed061bbfedb0daa705e220748154a84c3413 Author: Damien Miller Date: Wed Sep 10 08:15:34 2014 +1000 - (djm) [sandbox-seccomp-filter.c] Allow mremap and exit for DietLibc; patch from Felix von Leitner; ok dtucker commit ad7d23d461c3b7e1dcb15db13aee5f4b94dc1a95 Author: Darren Tucker Date: Tue Sep 9 12:23:10 2014 +1000 20140908 - (dtucker) [INSTALL] Update info about egd. ok djm@ commit 2a8699f37cc2515e3bc60e0c677ba060f4d48191 Author: Damien Miller Date: Thu Sep 4 03:46:05 2014 +1000 - (djm) [openbsd-compat/arc4random.c] Zero seed after keying PRNG commit 44988defb1f5e3afe576d86000365e1f07a1b494 Author: Damien Miller Date: Wed Sep 3 05:35:32 2014 +1000 - (djm) [contrib/cygwin/ssh-host-config] Fix old code leading to permissions/ACLs; from Corinna Vinschen commit 23f269562b7537b2f6f5014e50a25e5dcc55a837 Author: Damien Miller Date: Wed Sep 3 05:33:25 2014 +1000 - (djm) [defines.h sshbuf.c] Move __predict_true|false to defines.h and conditionalise to avoid duplicate definition. commit 41c8de2c0031cf59e7cf0c06b5bcfbf4852c1fda Author: Damien Miller Date: Sat Aug 30 16:23:06 2014 +1000 - (djm) [Makefile.in] Make TEST_SHELL a variable; "good idea" tim@ commit d7c81e216a7bd9eed6e239c970d9261bb1651947 Author: Damien Miller Date: Sat Aug 30 04:18:28 2014 +1000 - (djm) [openbsd-compat/openssl-compat.h] add include guard commit 4687802dda57365b984b897fc3c8e2867ea09b22 Author: Damien Miller Date: Sat Aug 30 03:29:19 2014 +1000 - (djm) [misc.c] Missing newline between functions commit 51c77e29220dee87c53be2dc47092934acab26fe Author: Damien Miller Date: Sat Aug 30 02:30:30 2014 +1000 - (djm) [openbsd-compat/openssl-compat.h] add OPENSSL_[RD]SA_MAX_MODULUS_BITS defines for OpenSSL that lacks them commit 3d673d103bad35afaec6e7ef73e5277216ce33a3 Author: Damien Miller Date: Wed Aug 27 06:32:01 2014 +1000 - (djm) [openbsd-compat/explicit_bzero.c] implement explicit_bzero() using memset_s() where possible; improve fallback to indirect bzero via a volatile pointer to give it more of a chance to avoid being optimised away. commit 146218ac11a1eb0dcade6f793d7acdef163b5ddc Author: Damien Miller Date: Wed Aug 27 04:11:55 2014 +1000 - (djm) [monitor.c sshd.c] SIGXFSZ needs to be ignored in postauth monitor, not preauth; bz#2263 commit 1b215c098b3b37e38aa4e4c91bb908eee41183b1 Author: Damien Miller Date: Wed Aug 27 04:04:40 2014 +1000 - (djm) [regress/unittests/sshbuf/test_sshbuf_getput_crypto.c] [regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c] [regress/unittests/sshkey/common.c] [regress/unittests/sshkey/test_file.c] [regress/unittests/sshkey/test_fuzz.c] [regress/unittests/sshkey/test_sshkey.c] Don't include openssl/ec.h on !ECC OpenSSL systems commit ad013944af0a19e3f612089d0099bb397cf6502d Author: Damien Miller Date: Tue Aug 26 09:27:28 2014 +1000 - (djm) [INSTALL] Recommend libcrypto be built -fPIC, mention LibreSSL, update OpenSSL version requirement. commit ed126de8ee04c66640a0ea2697c4aaf36801f100 Author: Damien Miller Date: Tue Aug 26 08:37:47 2014 +1000 - (djm) [bufec.c] Skip this file on !ECC OpenSSL commit 9c1dede005746864a4fdb36a7cdf6c51296ca909 Author: Damien Miller Date: Sun Aug 24 03:01:06 2014 +1000 - (djm) [sftp-server.c] Some systems (e.g. Irix) have prctl() but not PR_SET_DUMPABLE, so adjust ifdef; reported by Tom Christensen commit d244a5816fd1312a33404b436e4dd83594f1119e Author: Damien Miller Date: Sat Aug 23 17:06:49 2014 +1000 - (djm) [configure.ac] We now require a working vsnprintf everywhere (not just for systems that lack asprintf); check for it always and extend test to catch more brokenness. Fixes builds on Solaris <= 9 commit 4cec036362a358e398e6a2e6d19d8e5780558634 Author: Damien Miller Date: Sat Aug 23 03:11:09 2014 +1000 - (djm) [sshd.c] Ignore SIGXFSZ in preauth monitor child; can explode on lastlog writing on platforms with high UIDs; bz#2263 commit 394a60f2598d28b670d934b93942a3370b779b39 Author: Damien Miller Date: Fri Aug 22 18:06:20 2014 +1000 - (djm) [configure.ac] double braces to appease autoconf commit 4d69aeabd6e60afcdc7cca177ca751708ab79a9d Author: Damien Miller Date: Fri Aug 22 17:48:27 2014 +1000 - (djm) [openbsd-compat/bsd-snprintf.c] Fix compilation failure (prototype/ definition mismatch) and warning for broken/missing snprintf case. commit 0c11f1ac369d2c0aeb0ab0458a7cd04c72fe5e9e Author: Damien Miller Date: Fri Aug 22 17:36:56 2014 +1000 - (djm) [sshbuf-getput-crypto.c] Fix compilation when OpenSSL lacks ECC commit 6d62784b8973340b251fea6b04890f471adf28db Author: Damien Miller Date: Fri Aug 22 17:36:19 2014 +1000 - (djm) [configure.ac] include leading zero characters in OpenSSL version number; fixes test for unsupported versions commit 4f1ff1ed782117f5d5204d4e91156ed5da07cbb7 Author: Damien Miller Date: Thu Aug 21 15:54:50 2014 +1000 - (djm) [regress/unittests/test_helper/test_helper.c] Fix for systems that don't set __progname. Diagnosed by Tom Christensen. commit 005a64da0f457410045ef0bfa93c863c2450447d Author: Damien Miller Date: Thu Aug 21 10:48:41 2014 +1000 - (djm) [key.h] Fix ifdefs for no-ECC OpenSSL commit aa6598ebb3343c7380e918388e10e8ca5852b613 Author: Damien Miller Date: Thu Aug 21 10:47:54 2014 +1000 - (djm) [Makefile.in] fix reference to libtest_helper.a in sshkey test too. commit 54703e3cf63f0c80d4157e5ad7dbc2b363ee2c56 Author: Damien Miller Date: Wed Aug 20 11:10:51 2014 +1000 - (djm) [contrib/cygwin/README] Correct build instructions; from Corinna commit f0935698f0461f24d8d1f1107b476ee5fd4db1cb Author: Damien Miller Date: Wed Aug 20 11:06:50 2014 +1000 - (djm) [sshkey.h] Fix compilation when OpenSSL lacks ECC commit c5089ecaec3b2c02f014f4e67518390702a4ba14 Author: Damien Miller Date: Wed Aug 20 11:06:20 2014 +1000 - (djm) [Makefile.in] refer to libtest_helper.a by explicit path rather than -L/-l; fixes linking problems on some platforms commit 2195847e503a382f83ee969b0a8bd3dfe0e55c18 Author: Damien Miller Date: Wed Aug 20 11:05:03 2014 +1000 - (djm) [configure.ac] Check OpenSSL version is supported at configure time; suggested by Kevin Brott commit a75aca1bbc989aa9f8b1b08489d37855f3d24d1a Author: Damien Miller Date: Tue Aug 19 11:36:07 2014 +1000 - (djm) [INSTALL contrib/caldera/openssh.spec contrib/cygwin/README] [contrib/redhat/openssh.spec contrib/suse/openssh.spec] Remove mentions of TCP wrappers. commit 3f022b5a9477abceeb1bbeab04b055f3cc7ca8f6 Author: Damien Miller Date: Tue Aug 19 11:32:34 2014 +1000 - (djm) [ssh-dss.c] Include openssl/dsa.h for DSA_SIG commit 88137902632aceb923990e98cf5dc923bb3ef2f5 Author: Damien Miller Date: Tue Aug 19 11:28:11 2014 +1000 - (djm) [sshbuf.h] Fix compilation on systems without OPENSSL_HAS_ECC. commit 2f3d1e7fb2eabd3cfbfd8d0f7bdd2f9a1888690b Author: Damien Miller Date: Tue Aug 19 11:14:36 2014 +1000 - (djm) [myproposal.h] Make curve25519 KEX dependent on HAVE_EVP_SHA256 instead of OPENSSL_HAS_ECC. commit d4e7d59d01a6c7f59e8c1f94a83c086e9a33d8aa Author: Damien Miller Date: Tue Aug 19 11:14:17 2014 +1000 - (djm) [serverloop.c] Fix syntax error on Cygwin; from Corinna Vinschen commit 9eaeea2cf2b6af5f166cfa9ad3c7a90711a147a9 Author: Damien Miller Date: Sun Aug 10 11:35:05 2014 +1000 - (djm) [README contrib/caldera/openssh.spec] [contrib/redhat/openssh.spec contrib/suse/openssh.spec] Update versions commit f8988fbef0c9801d19fa2f8f4f041690412bec37 Author: Damien Miller Date: Fri Aug 1 13:31:52 2014 +1000 - (djm) [regress/multiplex.sh] Use -d (detach stdin) flag to disassociate nc from stdin, it's more portable commit 5b3879fd4b7a4e3d43bab8f40addda39bc1169d0 Author: Damien Miller Date: Fri Aug 1 12:28:31 2014 +1000 - (djm) [regress/multiplex.sh] Instruct nc not to quit as soon as stdin is closed; avoid regress failures when stdin is /dev/null commit a9c46746d266f8a1b092a72b2150682d1af8ebfc Author: Damien Miller Date: Fri Aug 1 12:26:49 2014 +1000 - (djm) [regress/multiplex.sh] Skip test for non-OpenBSD netcat. We need a better solution, but this will have to do for now. commit 426117b2e965e43f47015942b5be8dd88fe74b88 Author: Damien Miller Date: Wed Jul 30 12:33:20 2014 +1000 - schwarze@cvs.openbsd.org 2014/07/28 15:40:08 [sftp-server.8 sshd_config.5] some systems no longer need /dev/log; issue noticed by jirib; ok deraadt commit f497794b6962eaf802ab4ac2a7b22ae591cca1d5 Author: Damien Miller Date: Wed Jul 30 12:32:46 2014 +1000 - dtucker@cvs.openbsd.org 2014/07/25 21:22:03 [ssh-agent.c] Clear buffer used for handling messages. This prevents keys being left in memory after they have been expired or deleted in some cases (but note that ssh-agent is setgid so you would still need root to access them). Pointed out by Kevin Burns, ok deraadt commit a8a0f65c57c8ecba94d65948e9090da54014dfef Author: Damien Miller Date: Wed Jul 30 12:32:28 2014 +1000 - OpenBSD CVS Sync - millert@cvs.openbsd.org 2014/07/24 22:57:10 [ssh.1] Mention UNIX-domain socket forwarding too. OK jmc@ deraadt@ commit 56b840f2b81e14a2f95c203403633a72566736f8 Author: Damien Miller Date: Fri Jul 25 08:11:30 2014 +1000 - (djm) [regress/multiplex.sh] restore incorrectly deleted line; pointed out by Christian Hesse commit dd417b60d5ca220565d1014e92b7f8f43dc081eb Author: Darren Tucker Date: Wed Jul 23 10:41:21 2014 +1000 - dtucker@cvs.openbsd.org 2014/07/22 23:35:38 [regress/unittests/sshkey/testdata/*] Regenerate test keys with certs signed with ed25519 instead of ecdsa. These can be used in -portable on platforms that don't support ECDSA. commit 40e50211896369dba8f64f3b5e5fd58b76f5ac3f Author: Darren Tucker Date: Wed Jul 23 10:35:45 2014 +1000 - dtucker@cvs.openbsd.org 2014/07/22 23:57:40 [regress/unittests/sshkey/mktestdata.sh] Add $OpenBSD tag to make syncs easier commit 07e644251e809b1d4c062cf85bd1146a7e3f5a8a Author: Darren Tucker Date: Wed Jul 23 10:34:26 2014 +1000 - dtucker@cvs.openbsd.org 2014/07/22 23:23:22 [regress/unittests/sshkey/mktestdata.sh] Sign test certs with ed25519 instead of ecdsa so that they'll work in -portable on platforms that don't have ECDSA in their OpenSSL. ok djm commit cea099a7c4eaecb01b001e5453bb4e5c25006c22 Author: Darren Tucker Date: Wed Jul 23 10:04:02 2014 +1000 - djm@cvs.openbsd.org 2014/07/22 01:32:12 [regress/multiplex.sh] change the test for still-open Unix domain sockets to be robust against nc implementations that produce error messages. from -portable (Id sync only) commit 31eb78078d349b32ea41952ecc944b3ad6cb0d45 Author: Darren Tucker Date: Wed Jul 23 09:43:42 2014 +1000 - guenther@cvs.openbsd.org 2014/07/22 07:13:42 [umac.c] Convert from to the shiney new ok dtucker@, who also confirmed that -portable handles this already (ID sync only, includes.h pulls in endian.h if available.) commit 820763efef2d19d965602533036c2b4badc9d465 Author: Darren Tucker Date: Wed Jul 23 09:40:46 2014 +1000 - dtucker@cvs.openbsd.org 2014/07/22 01:18:50 [key.c] Prevent spam from key_load_private_pem during hostbased auth. ok djm@ commit c4ee219a66f3190fa96cbd45b4d11015685c6306 Author: Darren Tucker Date: Wed Jul 23 04:27:50 2014 +1000 - (dtucker) [regress/unittests/sshkey/test_{file,fuzz,sshkey}.c] Wrap ecdsa- specific tests inside OPENSSL_HAS_ECC. commit 04f4824940ea3edd60835416ececbae16438968a Author: Damien Miller Date: Tue Jul 22 11:31:47 2014 +1000 - (djm) [regress/multiplex.sh] change the test for still-open Unix domain sockets to be robust against nc implementations that produce error messages. commit 5ea4fe00d55453aaa44007330bb4c3181bd9b796 Author: Damien Miller Date: Tue Jul 22 09:39:19 2014 +1000 - (djm) [regress/multiplex.sh] ssh mux master lost -N somehow; put it back commit 948a1774a79a85f9deba6d74db95f402dee32c69 Author: Darren Tucker Date: Tue Jul 22 01:07:11 2014 +1000 - (dtucker) [sshkey.c] ifdef out unused variable when compiling without OPENSSL_HAS_ECC. commit c8f610f6cc57ae129758052439d9baf13699097b Author: Damien Miller Date: Mon Jul 21 10:23:27 2014 +1000 - (djm) [regress/multiplex.sh] Not all netcat accept the -N option. commit 0e4e95566cd95c887f69272499b8f3880b3ec0f5 Author: Damien Miller Date: Mon Jul 21 09:52:54 2014 +1000 - millert@cvs.openbsd.org 2014/07/15 15:54:15 [forwarding.sh multiplex.sh] Add support for Unix domain socket forwarding. A remote TCP port may be forwarded to a local Unix domain socket and vice versa or both ends may be a Unix domain socket. This is a reimplementation of the streamlocal patches by William Ahern from: http://www.25thandclement.com/~william/projects/streamlocal.html OK djm@ markus@ commit 93a87ab27ecdc709169fb24411133998f81e2761 Author: Darren Tucker Date: Mon Jul 21 06:30:25 2014 +1000 - (dtucker) [regress/unittests/sshkey/ {common,test_file,test_fuzz,test_sshkey}.c] Wrap stdint.h includes in ifdefs. commit 5573171352ea23df2dc6d2fe0324d023b7ba697c Author: Darren Tucker Date: Mon Jul 21 02:24:59 2014 +1000 - (dtucker) [cipher.c openbsd-compat/openssl-compat.h] Restore the bits needed to build AES CTR mode against OpenSSL 0.9.8f and above. ok djm commit 74e28682711d005026c7c8f15f96aea9d3c8b5a3 Author: Tim Rice Date: Fri Jul 18 20:00:11 2014 -0700 - (tim) [openbsd-compat/port-uw.c] Include misc.h for fwd_opts, used in servconf.h. commit d1a0421f8e5e933fee6fb58ee6b9a22c63c8a613 Author: Darren Tucker Date: Sat Jul 19 07:23:55 2014 +1000 - (dtucker) [key.c sshkey.c] Put new ecdsa bits inside ifdef OPENSSL_HAS_ECC. commit f0fe9ea1be62227c130b317769de3d1e736b6dc1 Author: Darren Tucker Date: Sat Jul 19 06:33:12 2014 +1000 - (dtucker) [Makefile.in] Add a t-exec target to run just the executable tests. commit 450bc1180d4b061434a4b733c5c8814fa30b022b Author: Darren Tucker Date: Sat Jul 19 06:23:18 2014 +1000 - (dtucker) [auth2-gss.c gss-serv-krb5.c] Include misc.h for fwd_opts, used in servconf.h. commit ab2ec586baad122ed169285c31927ccf58bc7b28 Author: Damien Miller Date: Fri Jul 18 15:04:47 2014 +1000 - djm@cvs.openbsd.org 2014/07/18 02:46:01 [ssh-agent.c] restore umask around listener socket creation (dropped in streamlocal patch merge) commit 357610d15946381ae90c271837dcdd0cdce7145f Author: Damien Miller Date: Fri Jul 18 15:04:10 2014 +1000 - djm@cvs.openbsd.org 2014/07/17 07:22:19 [mux.c ssh.c] reflect stdio-forward ("ssh -W host:port ...") failures in exit status. previously we were always returning 0. bz#2255 reported by Brendan Germain; ok dtucker commit dad9a4a0b7c2b5d78605f8df28718f116524134e Author: Damien Miller Date: Fri Jul 18 15:03:49 2014 +1000 - djm@cvs.openbsd.org 2014/07/17 00:12:03 [key.c] silence "incorrect passphrase" error spam; reported and ok dtucker@ commit f42f7684ecbeec6ce50e0310f80b3d6da2aaf533 Author: Damien Miller Date: Fri Jul 18 15:03:27 2014 +1000 - djm@cvs.openbsd.org 2014/07/17 00:10:18 [mux.c] preserve errno across syscall commit 1b83320628cb0733e3688b85bfe4d388a7c51909 Author: Damien Miller Date: Fri Jul 18 15:03:02 2014 +1000 - djm@cvs.openbsd.org 2014/07/17 00:10:56 [sandbox-systrace.c] ifdef SYS_sendsyslog so this will compile without patching on -stable commit 6d57656331bcd754d912950e4a18ad259d596e61 Author: Damien Miller Date: Fri Jul 18 15:02:06 2014 +1000 - jmc@cvs.openbsd.org 2014/07/16 14:48:57 [ssh.1] add the streamlocal* options to ssh's -o list; millert says they're irrelevant for scp/sftp; ok markus millert commit 7acefbbcbeab725420ea07397ae35992f505f702 Author: Damien Miller Date: Fri Jul 18 14:11:24 2014 +1000 - millert@cvs.openbsd.org 2014/07/15 15:54:14 [PROTOCOL auth-options.c auth-passwd.c auth-rh-rsa.c auth-rhosts.c] [auth-rsa.c auth.c auth1.c auth2-hostbased.c auth2-kbdint.c auth2-none.c] [auth2-passwd.c auth2-pubkey.c auth2.c canohost.c channels.c channels.h] [clientloop.c misc.c misc.h monitor.c mux.c packet.c readconf.c] [readconf.h servconf.c servconf.h serverloop.c session.c ssh-agent.c] [ssh.c ssh_config.5 sshconnect.c sshconnect1.c sshconnect2.c sshd.c] [sshd_config.5 sshlogin.c] Add support for Unix domain socket forwarding. A remote TCP port may be forwarded to a local Unix domain socket and vice versa or both ends may be a Unix domain socket. This is a reimplementation of the streamlocal patches by William Ahern from: http://www.25thandclement.com/~william/projects/streamlocal.html OK djm@ markus@ commit 6262d760e00714523633bd989d62e273a3dca99a Author: Damien Miller Date: Thu Jul 17 09:52:07 2014 +1000 - tedu@cvs.openbsd.org 2014/07/11 13:54:34 [myproposal.h] by popular demand, add back hamc-sha1 to server proposal for better compat with many clients still in use. ok deraadt commit 9d69d937b46ecba17f16d923e538ceda7b705c7a Author: Damien Miller Date: Thu Jul 17 09:49:37 2014 +1000 - deraadt@cvs.openbsd.org 2014/07/11 08:09:54 [sandbox-systrace.c] Permit use of SYS_sendsyslog from inside the sandbox. Clock is ticking, update your kernels and sshd soon.. libc will start using sendsyslog() in about 4 days. commit f6293a0b4129826fc2e37e4062f96825df43c326 Author: Damien Miller Date: Thu Jul 17 09:01:25 2014 +1000 - (djm) [digest-openssl.c] Preserve array order when disabling digests. Reported by Petr Lautrbach. commit 00f9cd230709c04399ef5ff80492d70a55230694 Author: Damien Miller Date: Tue Jul 15 10:41:38 2014 +1000 - (djm) [configure.ac] Delay checks for arc4random* until after libcrypto has been located; fixes builds agains libressl-portable commit 1d0df3249c87019556b83306c28d4769375c2edc Author: Damien Miller Date: Fri Jul 11 09:19:04 2014 +1000 - OpenBSD CVS Sync - benno@cvs.openbsd.org 2014/07/09 14:15:56 [ssh-add.c] fix ssh-add crash while loading more than one key ok markus@ commit 7a57eb3d105aa4ced15fb47001092c58811e6d9d Author: Damien Miller Date: Wed Jul 9 13:22:31 2014 +1000 - djm@cvs.openbsd.org 2014/07/07 08:15:26 [multiplex.sh] remove forced-fatal that I stuck in there to test the new cleanup logic and forgot to remove... commit 612f965239a30fe536b11ece1834d9f470aeb029 Author: Damien Miller Date: Wed Jul 9 13:22:03 2014 +1000 - djm@cvs.openbsd.org 2014/07/06 07:42:03 [multiplex.sh test-exec.sh] add a hook to the cleanup() function to kill $SSH_PID if it is set use it to kill the mux master started in multiplex.sh (it was being left around on fatal failures) commit d0bb950485ba121e43a77caf434115ed6417b46f Author: Damien Miller Date: Wed Jul 9 13:07:28 2014 +1000 - djm@cvs.openbsd.org 2014/07/09 03:02:15 [key.c] downgrade more error() to debug() to better match what old authfile.c did; suppresses spurious errors with hostbased authentication enabled commit 0070776a038655c57f57e70cd05e4c38a5de9d84 Author: Damien Miller Date: Wed Jul 9 13:07:06 2014 +1000 - djm@cvs.openbsd.org 2014/07/09 01:45:10 [sftp.c] more useful error message when GLOB_NOSPACE occurs; bz#2254, patch from Orion Poplawski commit 079bac2a43c74ef7cf56850afbab3b1932534c50 Author: Damien Miller Date: Wed Jul 9 13:06:25 2014 +1000 - djm@cvs.openbsd.org 2014/07/07 08:19:12 [ssh_config.5] mention that ProxyCommand is executed using shell "exec" to avoid a lingering process; bz#1977 commit 3a48cc090096cf99b9de592deb5f90e444edebfb Author: Damien Miller Date: Sun Jul 6 09:32:49 2014 +1000 - djm@cvs.openbsd.org 2014/07/05 23:11:48 [channels.c] fix remote-forward cancel regression; ok markus@ commit 48bae3a38cb578713e676708164f6e7151cc64fa Author: Damien Miller Date: Sun Jul 6 09:27:06 2014 +1000 - djm@cvs.openbsd.org 2014/07/03 23:18:35 [authfile.h] remove leakmalloc droppings commit 72e6b5c9ed5e72ca3a6ccc3177941b7c487a0826 Author: Damien Miller Date: Fri Jul 4 09:00:04 2014 +1000 - djm@cvs.openbsd.org 2014/07/03 22:40:43 [servconf.c servconf.h session.c sshd.8 sshd_config.5] Add a sshd_config PermitUserRC option to control whether ~/.ssh/rc is executed, mirroring the no-user-rc authorized_keys option; bz#2160; ok markus@ commit 602943d1179a08dfa70af94f62296ea5e3d6ebb8 Author: Damien Miller Date: Fri Jul 4 08:59:41 2014 +1000 - djm@cvs.openbsd.org 2014/07/03 22:33:41 [channels.c] allow explicit ::1 and 127.0.0.1 forwarding bind addresses when GatewayPorts=no; allows client to choose address family; bz#2222 ok markus@ commit 6b37fbb7921d156b31e2c8f39d9e1b6746c34983 Author: Damien Miller Date: Fri Jul 4 08:59:24 2014 +1000 - djm@cvs.openbsd.org 2014/07/03 22:23:46 [sshconnect.c] when rekeying, skip file/DNS lookup if it is the same as the key sent during initial key exchange. bz#2154 patch from Iain Morgan; ok markus@ commit d2c3cd5f2e47ee24cf7093ce8e948c2e79dfc3fd Author: Damien Miller Date: Fri Jul 4 08:59:01 2014 +1000 - jsing@cvs.openbsd.org 2014/07/03 12:42:16 [cipher-chachapoly.c] Call chacha_ivsetup() immediately before chacha_encrypt_bytes() - this makes it easier to verify that chacha_encrypt_bytes() is only called once per chacha_ivsetup() call. ok djm@ commit 686feb560ec43a06ba04da82b50f3c183c947309 Author: Damien Miller Date: Thu Jul 3 21:29:38 2014 +1000 - djm@cvs.openbsd.org 2014/07/03 11:16:55 [auth.c auth.h auth1.c auth2.c] make the "Too many authentication failures" message include the user, source address, port and protocol in a format similar to the authentication success / failure messages; bz#2199, ok dtucker commit 0f12341402e18fd9996ec23189b9418d2722453f Author: Damien Miller Date: Thu Jul 3 21:28:09 2014 +1000 - jmc@cvs.openbsd.org 2014/07/03 07:45:27 [ssh_config.5] escape %C since groff thinks it part of an Rs/Re block; commit 9c38643c5cd47a19db2cc28279dcc28abadc22b3 Author: Damien Miller Date: Thu Jul 3 21:27:46 2014 +1000 - djm@cvs.openbsd.org 2014/07/03 06:39:19 [ssh.c ssh_config.5] Add a %C escape sequence for LocalCommand and ControlPath that expands to a unique identifer based on a has of the tuple of (local host, remote user, hostname, port). Helps avoid exceeding sockaddr_un's miserly pathname limits for mux control paths. bz#2220, based on patch from mancha1 AT zoho.com; ok markus@ commit 49d9bfe2b2f3e90cc158a215dffa7675e57e7830 Author: Damien Miller Date: Thu Jul 3 21:26:42 2014 +1000 - djm@cvs.openbsd.org 2014/07/03 05:38:17 [ssh.1] document that -g will only work in the multiplexed case if applied to the mux master commit ef9f13ba4c58057b2166d1f2e790535da402fbe5 Author: Damien Miller Date: Thu Jul 3 21:26:21 2014 +1000 - djm@cvs.openbsd.org 2014/07/03 05:32:36 [ssh_config.5] mention '%%' escape sequence in HostName directives and how it may be used to specify IPv6 link-local addresses commit e6a407789e5432dd2e53336fb73476cc69048c54 Author: Damien Miller Date: Thu Jul 3 21:25:03 2014 +1000 - djm@cvs.openbsd.org 2014/07/03 04:36:45 [digest.h] forward-declare struct sshbuf so consumers don't need to include sshbuf.h commit 4a1d3d50f02d0a8a4ef95ea4749293cbfb89f919 Author: Damien Miller Date: Thu Jul 3 21:24:40 2014 +1000 - djm@cvs.openbsd.org 2014/07/03 03:47:27 [ssh-keygen.c] When hashing or removing hosts using ssh-keygen, don't choke on @revoked markers and don't remove @cert-authority markers; bz#2241, reported by mlindgren AT runelind.net commit e5c0d52ceb575c3db8c313e0b1aa3845943d7ba8 Author: Damien Miller Date: Thu Jul 3 21:24:19 2014 +1000 - djm@cvs.openbsd.org 2014/07/03 03:34:09 [gss-serv.c session.c ssh-keygen.c] standardise on NI_MAXHOST for gethostname() string lengths; about 1/2 the cases were using it already. Fixes bz#2239 en passant commit c174a3b7c14e0d178c61219de2aa1110e209950c Author: Damien Miller Date: Thu Jul 3 21:23:24 2014 +1000 - djm@cvs.openbsd.org 2014/07/03 03:26:43 [digest-openssl.c] use EVP_Digest() for one-shot hash instead of creating, updating, finalising and destroying a context. bz#2231, based on patch from Timo Teras commit d7ca2cd31ecc4d63a055e2dcc4bf35c13f2db4c5 Author: Damien Miller Date: Thu Jul 3 21:23:01 2014 +1000 - djm@cvs.openbsd.org 2014/07/03 03:15:01 [ssh-add.c] make stdout line-buffered; saves partial output getting lost when ssh-add fatal()s part-way through (e.g. when listing keys from an agent that supports key types that ssh-add doesn't); bz#2234, reported by Phil Pennock commit b1e967c8d7c7578dd0c172d85b3046cf54ea42ba Author: Damien Miller Date: Thu Jul 3 21:22:40 2014 +1000 - djm@cvs.openbsd.org 2014/07/03 03:11:03 [ssh-agent.c] Only cleanup agent socket in the main agent process and not in any subprocesses it may have started (e.g. forked askpass). Fixes agent sockets being zapped when askpass processes fatal(); bz#2236 patch from Dmitry V. Levin commit 61e28e55c3438d796b02ef878bcd28620d452670 Author: Damien Miller Date: Thu Jul 3 21:22:22 2014 +1000 - djm@cvs.openbsd.org 2014/07/03 01:45:38 [sshkey.c] make Ed25519 keys' title fit properly in the randomart border; bz#2247 based on patch from Christian Hesse commit 9eb4cd9a32c32d40d36450b68ed93badc6a94c68 Author: Damien Miller Date: Thu Jul 3 13:29:50 2014 +1000 - (djm) [monitor_fdpass.c] Use sys/poll.h if poll.h doesn't exist; bz#2237 commit 8da0fa24934501909408327298097b1629b89eaa Author: Damien Miller Date: Thu Jul 3 11:54:19 2014 +1000 - (djm) [digest-openssl.c configure.ac] Disable RIPEMD160 if libcrypto doesn't support it. commit 81309c857dd0dbc0a1245a16d621c490ad48cfbb Author: Damien Miller Date: Wed Jul 2 17:45:55 2014 +1000 - (djm) [regress/Makefile] fix execution of sshkey unit/fuzz test commit 82b2482ce68654815ee049b9bf021bb362a35ff2 Author: Damien Miller Date: Wed Jul 2 17:43:41 2014 +1000 - (djm) [sshkey.c] Conditionalise inclusion of util.h commit dd8b1dd7933eb6f5652641b0cdced34a387f2e80 Author: Damien Miller Date: Wed Jul 2 17:38:31 2014 +1000 - djm@cvs.openbsd.org 2014/06/24 01:14:17 [Makefile.in regress/Makefile regress/unittests/Makefile] [regress/unittests/sshkey/Makefile] [regress/unittests/sshkey/common.c] [regress/unittests/sshkey/common.h] [regress/unittests/sshkey/mktestdata.sh] [regress/unittests/sshkey/test_file.c] [regress/unittests/sshkey/test_fuzz.c] [regress/unittests/sshkey/test_sshkey.c] [regress/unittests/sshkey/tests.c] [regress/unittests/sshkey/testdata/dsa_1] [regress/unittests/sshkey/testdata/dsa_1-cert.fp] [regress/unittests/sshkey/testdata/dsa_1-cert.pub] [regress/unittests/sshkey/testdata/dsa_1.fp] [regress/unittests/sshkey/testdata/dsa_1.fp.bb] [regress/unittests/sshkey/testdata/dsa_1.param.g] [regress/unittests/sshkey/testdata/dsa_1.param.priv] [regress/unittests/sshkey/testdata/dsa_1.param.pub] [regress/unittests/sshkey/testdata/dsa_1.pub] [regress/unittests/sshkey/testdata/dsa_1_pw] [regress/unittests/sshkey/testdata/dsa_2] [regress/unittests/sshkey/testdata/dsa_2.fp] [regress/unittests/sshkey/testdata/dsa_2.fp.bb] [regress/unittests/sshkey/testdata/dsa_2.pub] [regress/unittests/sshkey/testdata/dsa_n] [regress/unittests/sshkey/testdata/dsa_n_pw] [regress/unittests/sshkey/testdata/ecdsa_1] [regress/unittests/sshkey/testdata/ecdsa_1-cert.fp] [regress/unittests/sshkey/testdata/ecdsa_1-cert.pub] [regress/unittests/sshkey/testdata/ecdsa_1.fp] [regress/unittests/sshkey/testdata/ecdsa_1.fp.bb] [regress/unittests/sshkey/testdata/ecdsa_1.param.curve] [regress/unittests/sshkey/testdata/ecdsa_1.param.priv] [regress/unittests/sshkey/testdata/ecdsa_1.param.pub] [regress/unittests/sshkey/testdata/ecdsa_1.pub] [regress/unittests/sshkey/testdata/ecdsa_1_pw] [regress/unittests/sshkey/testdata/ecdsa_2] [regress/unittests/sshkey/testdata/ecdsa_2.fp] [regress/unittests/sshkey/testdata/ecdsa_2.fp.bb] [regress/unittests/sshkey/testdata/ecdsa_2.param.curve] [regress/unittests/sshkey/testdata/ecdsa_2.param.priv] [regress/unittests/sshkey/testdata/ecdsa_2.param.pub] [regress/unittests/sshkey/testdata/ecdsa_2.pub] [regress/unittests/sshkey/testdata/ecdsa_n] [regress/unittests/sshkey/testdata/ecdsa_n_pw] [regress/unittests/sshkey/testdata/ed25519_1] [regress/unittests/sshkey/testdata/ed25519_1-cert.fp] [regress/unittests/sshkey/testdata/ed25519_1-cert.pub] [regress/unittests/sshkey/testdata/ed25519_1.fp] [regress/unittests/sshkey/testdata/ed25519_1.fp.bb] [regress/unittests/sshkey/testdata/ed25519_1.pub] [regress/unittests/sshkey/testdata/ed25519_1_pw] [regress/unittests/sshkey/testdata/ed25519_2] [regress/unittests/sshkey/testdata/ed25519_2.fp] [regress/unittests/sshkey/testdata/ed25519_2.fp.bb] [regress/unittests/sshkey/testdata/ed25519_2.pub] [regress/unittests/sshkey/testdata/pw] [regress/unittests/sshkey/testdata/rsa1_1] [regress/unittests/sshkey/testdata/rsa1_1.fp] [regress/unittests/sshkey/testdata/rsa1_1.fp.bb] [regress/unittests/sshkey/testdata/rsa1_1.param.n] [regress/unittests/sshkey/testdata/rsa1_1.pub] [regress/unittests/sshkey/testdata/rsa1_1_pw] [regress/unittests/sshkey/testdata/rsa1_2] [regress/unittests/sshkey/testdata/rsa1_2.fp] [regress/unittests/sshkey/testdata/rsa1_2.fp.bb] [regress/unittests/sshkey/testdata/rsa1_2.param.n] [regress/unittests/sshkey/testdata/rsa1_2.pub] [regress/unittests/sshkey/testdata/rsa_1] [regress/unittests/sshkey/testdata/rsa_1-cert.fp] [regress/unittests/sshkey/testdata/rsa_1-cert.pub] [regress/unittests/sshkey/testdata/rsa_1.fp] [regress/unittests/sshkey/testdata/rsa_1.fp.bb] [regress/unittests/sshkey/testdata/rsa_1.param.n] [regress/unittests/sshkey/testdata/rsa_1.param.p] [regress/unittests/sshkey/testdata/rsa_1.param.q] [regress/unittests/sshkey/testdata/rsa_1.pub] [regress/unittests/sshkey/testdata/rsa_1_pw] [regress/unittests/sshkey/testdata/rsa_2] [regress/unittests/sshkey/testdata/rsa_2.fp] [regress/unittests/sshkey/testdata/rsa_2.fp.bb] [regress/unittests/sshkey/testdata/rsa_2.param.n] [regress/unittests/sshkey/testdata/rsa_2.param.p] [regress/unittests/sshkey/testdata/rsa_2.param.q] [regress/unittests/sshkey/testdata/rsa_2.pub] [regress/unittests/sshkey/testdata/rsa_n] [regress/unittests/sshkey/testdata/rsa_n_pw] unit and fuzz tests for new key API commit c1dc24b71f087f385b92652b9673f52af64e0428 Author: Damien Miller Date: Wed Jul 2 17:02:03 2014 +1000 - djm@cvs.openbsd.org 2014/06/24 01:04:43 [regress/krl.sh] regress test for broken consecutive revoked serial number ranges commit 43d3ed2dd3feca6d0326c7dc82588d2faa115e92 Author: Damien Miller Date: Wed Jul 2 17:01:08 2014 +1000 - djm@cvs.openbsd.org 2014/05/21 07:04:21 [regress/integrity.sh] when failing because of unexpected output, show the offending output commit 5a96707ffc8d227c2e7d94fa6b0317f8a152cf4e Author: Damien Miller Date: Wed Jul 2 15:38:05 2014 +1000 - djm@cvs.openbsd.org 2014/04/30 05:32:00 [regress/Makefile] unit tests for new buffer API; including basic fuzz testing NB. Id sync only. commit 3ff92ba756aee48e4ae3e0aeff7293517b3dd185 Author: Damien Miller Date: Wed Jul 2 15:33:09 2014 +1000 - djm@cvs.openbsd.org 2014/06/30 12:54:39 [key.c] suppress spurious error message when loading key with a passphrase; reported by kettenis@ ok markus@ - djm@cvs.openbsd.org 2014/07/02 04:59:06 [cipher-3des1.c] fix ssh protocol 1 on the server that regressed with the sshkey change (sometimes fatal() after auth completed), make file return useful status codes. NB. Id sync only for these two. They were bundled into the sshkey merge above, since it was easier to sync the entire file and then apply portable-specific changed atop it. commit ec3d0e24a1e46873d80507f5cd8ee6d0d03ac5dc Author: Damien Miller Date: Wed Jul 2 15:30:00 2014 +1000 - markus@cvs.openbsd.org 2014/06/27 18:50:39 [ssh-add.c] fix loading of private keys commit 4b3ed647d5b328cf68e6a8ffbee490d8e0683e82 Author: Damien Miller Date: Wed Jul 2 15:29:40 2014 +1000 - markus@cvs.openbsd.org 2014/06/27 16:41:56 [channels.c channels.h clientloop.c ssh.c] fix remote fwding with same listen port but different listen address with gerhard@, ok djm@ commit 9e01ff28664921ce9b6500681333e42fb133b4d0 Author: Damien Miller Date: Wed Jul 2 15:29:21 2014 +1000 - deraadt@cvs.openbsd.org 2014/06/25 14:16:09 [sshbuf.c] unblock SIGSEGV before raising it ok djm commit 1845fe6bda0729e52f4c645137f4fc3070b5438a Author: Damien Miller Date: Wed Jul 2 15:29:01 2014 +1000 - djm@cvs.openbsd.org 2014/06/24 02:21:01 [scp.c] when copying local->remote fails during read, don't send uninitialised heap to the remote end. Reported by Jann Horn commit 19439e9a2a0ac0b4b3b1210e89695418beb1c883 Author: Damien Miller Date: Wed Jul 2 15:28:40 2014 +1000 - djm@cvs.openbsd.org 2014/06/24 02:19:48 [ssh.c] don't fatal() when hostname canonicalisation fails with a ProxyCommand in use; continue and allow the ProxyCommand to connect anyway (e.g. to a host with a name outside the DNS behind a bastion) commit 8668706d0f52654fe64c0ca41a96113aeab8d2b8 Author: Damien Miller Date: Wed Jul 2 15:28:02 2014 +1000 - djm@cvs.openbsd.org 2014/06/24 01:13:21 [Makefile.in auth-bsdauth.c auth-chall.c auth-options.c auth-rsa.c [auth2-none.c auth2-pubkey.c authfile.c authfile.h cipher-3des1.c [cipher-chachapoly.c cipher-chachapoly.h cipher.c cipher.h [digest-libc.c digest-openssl.c digest.h dns.c entropy.c hmac.h [hostfile.c key.c key.h krl.c monitor.c packet.c rsa.c rsa.h [ssh-add.c ssh-agent.c ssh-dss.c ssh-ecdsa.c ssh-ed25519.c [ssh-keygen.c ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c [ssh-rsa.c sshbuf-misc.c sshbuf.h sshconnect.c sshconnect1.c [sshconnect2.c sshd.c sshkey.c sshkey.h [openbsd-compat/openssl-compat.c openbsd-compat/openssl-compat.h] New key API: refactor key-related functions to be more library-like, existing API is offered as a set of wrappers. with and ok markus@ Thanks also to Ben Hawkes, David Tomaschik, Ivan Fratric, Matthew Dempsky and Ron Bowes for a detailed review a few months ago. NB. This commit also removes portable OpenSSH support for OpenSSL <0.9.8e. commit 2cd7929250cf9e9f658d70dcd452f529ba08c942 Author: Damien Miller Date: Wed Jul 2 12:48:30 2014 +1000 - djm@cvs.openbsd.org 2014/06/24 00:52:02 [krl.c] fix bug in KRL generation: multiple consecutive revoked certificate serial number ranges could be serialised to an invalid format. Readers of a broken KRL caused by this bug will fail closed, so no should-have-been-revoked key will be accepted. commit 99db840ee8dbbd2b3fbc6c45d0ee2f6a65e96898 Author: Damien Miller Date: Wed Jul 2 12:48:04 2014 +1000 - naddy@cvs.openbsd.org 2014/06/18 15:42:09 [sshbuf-getput-crypto.c] The ssh_get_bignum functions must accept the same range of bignums the corresponding ssh_put_bignum functions create. This fixes the use of 16384-bit RSA keys (bug reported by Eivind Evensen). ok djm@ commit 84a89161a9629239b64171ef3e22ef6a3e462d51 Author: Damien Miller Date: Wed Jul 2 12:47:48 2014 +1000 - matthew@cvs.openbsd.org 2014/06/18 02:59:13 [sandbox-systrace.c] Now that we have a dedicated getentropy(2) system call for arc4random(3), we can disallow __sysctl(2) in OpenSSH's systrace sandbox. ok djm commit 51504ceec627c0ad57b9f75585c7b3d277f326be Author: Damien Miller Date: Wed Jul 2 12:47:25 2014 +1000 - deraadt@cvs.openbsd.org 2014/06/13 08:26:29 [sandbox-systrace.c] permit SYS_getentropy from matthew commit a261b8df59117f7dc52abb3a34b35a40c2c9fa88 Author: Tim Rice Date: Wed Jun 18 16:17:28 2014 -0700 - (tim) [openssh/session.c] Work around to get chroot sftp working on UnixWare commit 316fac6f18f87262a315c79bcf68b9f92c9337e4 Author: Darren Tucker Date: Tue Jun 17 23:06:07 2014 +1000 - (dtucker) [entropy.c openbsd-compat/openssl-compat.{c,h} openbsd-compat/regress/{.cvsignore,Makefile.in,opensslvertest.c}] Move the OpenSSL header/library version test into its own function and add tests for it. Fix it to allow fix version upgrades (but not downgrades). Prompted by chl@ via OpenSMTPD (issue #462) and Debian (bug #748150). ok djm@ chl@ commit af665bb7b092a59104db1e65577851cf35b86e32 Author: Darren Tucker Date: Mon Jun 16 22:50:55 2014 +1000 - (dtucker) [defines.h] Fix undef of _PATH_MAILDIR. From rak at debian via OpenSMTPD and chl@ commit f9696566fb41320820f3b257ab564fa321bb3751 Author: Darren Tucker Date: Fri Jun 13 11:06:04 2014 +1000 - (dtucker) [configure.ac] Remove tcpwrappers support, support has already been removed from sshd.c. commit 5e2b8894b0b24af4ad0a2f7aa33ebf255df7a8bc Author: Tim Rice Date: Wed Jun 11 18:31:10 2014 -0700 - (tim) [regress/unittests/test_helper/test_helper.h] Add includes.h for u_intXX_t types. commit 985ee2cbc3e43bc65827c3c0d4df3faa99160c37 Author: Darren Tucker Date: Thu Jun 12 05:32:29 2014 +1000 - (dtucker) [regress/unittests/sshbuf/*.c regress/unittests/test_helper/*] Wrap stdlib.h include an ifdef for platforms that don't have it. commit cf5392c2db2bb1dbef9818511d34056404436109 Author: Darren Tucker Date: Thu Jun 12 05:22:49 2014 +1000 - (dtucker) [defines.h] Add va_copy if we don't already have it, taken from openbsd-compat/bsd-asprintf.c. commit 58538d795e0b662f2f4e5a7193f1204bbe992ddd Author: Darren Tucker Date: Wed Jun 11 13:39:24 2014 +1000 - (dtucker) [bufaux.c bufbn.c bufec.c buffer.c] Pull in includes.h for compat stuff, specifically whether or not OpenSSL has ECC. commit eb012ac581fd0abc16ee86ee3a68cf07c8ce4d08 Author: Darren Tucker Date: Wed Jun 11 13:10:00 2014 +1000 - (dtucker) [openbsd-compat/arc4random.c] Use explicit_bzero instead of an assigment that might get optimized out. ok djm@ commit b9609fd86c623d6d440e630f5f9a63295f7aea20 Author: Darren Tucker Date: Wed Jun 11 08:04:02 2014 +1000 - (dtucker) [sshbuf.h] Only declare ECC functions if building without OpenSSL or if OpenSSL has ECC. commit a54a040f66944c6e8913df8635a01a2327219be9 Author: Darren Tucker Date: Wed Jun 11 07:58:35 2014 +1000 - dtucker@cvs.openbsd.org 2014/06/10 21:46:11 [sshbuf.h] Group ECC functions together to make things a little easier in -portable. "doesn't bother me" deraadt@ commit 9f92c53bad04a89067756be8198d4ec2d8a08875 Author: Darren Tucker Date: Wed Jun 11 07:57:58 2014 +1000 - djm@cvs.openbsd.org 2014/06/05 22:17:50 [sshconnect2.c] fix inverted test that caused PKCS#11 keys that were explicitly listed not to be preferred. Reported by Dirk-Willem van Gulik commit 15c254a25394f96643da2ad0f674acdc51e89856 Author: Darren Tucker Date: Wed Jun 11 07:38:49 2014 +1000 - (dtucker) [regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c] ifdef ECC variable too. commit d7af0cc5bf273eeed0897a99420bc26841d07d8f Author: Darren Tucker Date: Wed Jun 11 07:37:25 2014 +1000 - (dtucker) [myprosal.h] Don't include curve25519-sha256@libssh.org in the proposal if the version of OpenSSL we're using doesn't support ECC. commit 67508ac2563c33d582be181a3e777c65f549d22f Author: Darren Tucker Date: Wed Jun 11 06:27:16 2014 +1000 - (dtucker) [regress/unittests/sshbuf/test_sshbuf_getput_crypto.c regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c] Only do NISTP256 curve tests if OpenSSL has them. commit 6482d90a65459a88c18c925368525855832272b3 Author: Damien Miller Date: Tue May 27 14:34:42 2014 +1000 - (djm) [configure.ac openbsd-compat/bsd-cygwin_util.c] [openbsd-compat/bsd-cygwin_util.h] On Cygwin, determine privilege separation user at runtime, since it may need to be a domain account. Patch from Corinna Vinschen. commit f9eb5e0734f7a7f6e975809eb54684d2a06a7ffc Author: Damien Miller Date: Tue May 27 14:31:58 2014 +1000 - (djm) [contrib/cygwin/ssh-host-config] Updated Cygwin ssh-host-config from Corinna Vinschen, fixing a number of bugs and preparing for Cygwin 1.7.30. commit eae88744662e6b149f43ef071657727f1a157d95 Author: Damien Miller Date: Tue May 27 14:27:02 2014 +1000 - (djm) [cipher.c] Fix merge botch. commit 564b5e253c1d95c26a00e8288f0089a2571661c3 Author: Damien Miller Date: Thu May 22 08:23:59 2014 +1000 - (djm) [Makefile.in] typo in path commit e84d10302aeaf7a1acb05c451f8718143656856a Author: Damien Miller Date: Wed May 21 17:13:36 2014 +1000 revert a diff I didn't mean to commit commit 795b86313f1f1aab9691666c4f2d5dae6e4acd50 Author: Damien Miller Date: Wed May 21 17:12:53 2014 +1000 - (djm) [misc.c] Use CLOCK_BOOTTIME in preference to CLOCK_MONOTONIC when it is available. It takes into account time spent suspended, thereby ensuring timeouts (e.g. for expiring agent keys) fire correctly. bz#2228 reported by John Haxby commit 18912775cb97c0b1e75e838d3c7d4b56648137b5 Author: Damien Miller Date: Wed May 21 17:06:46 2014 +1000 - (djm) [commit configure.ac defines.h sshpty.c] don't attempt to use vhangup on Linux. It doens't work for non-root users, and for them it just messes up the tty settings. commit 7f1c264d3049cd95234e91970ccb5406e1d15b27 Author: Damien Miller Date: Thu May 15 18:01:52 2014 +1000 - (djm) [sshbuf.c] need __predict_false commit e7429f2be8643e1100380a8a7389d85cc286c8fe Author: Damien Miller Date: Thu May 15 18:01:01 2014 +1000 - (djm) [regress/Makefile Makefile.in] [regress/unittests/sshbuf/test_sshbuf.c [regress/unittests/sshbuf/test_sshbuf_fixed.c] [regress/unittests/sshbuf/test_sshbuf_fuzz.c] [regress/unittests/sshbuf/test_sshbuf_getput_basic.c] [regress/unittests/sshbuf/test_sshbuf_getput_crypto.c] [regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c] [regress/unittests/sshbuf/test_sshbuf_misc.c] [regress/unittests/sshbuf/tests.c] [regress/unittests/test_helper/fuzz.c] [regress/unittests/test_helper/test_helper.c] Hook new unit tests into the build and "make tests" commit def1de086707b0e6b046fe7e115c60aca0227a99 Author: Damien Miller Date: Thu May 15 15:17:15 2014 +1000 - (djm) [regress/unittests/Makefile] [regress/unittests/Makefile.inc] [regress/unittests/sshbuf/Makefile] [regress/unittests/sshbuf/test_sshbuf.c] [regress/unittests/sshbuf/test_sshbuf_fixed.c] [regress/unittests/sshbuf/test_sshbuf_fuzz.c] [regress/unittests/sshbuf/test_sshbuf_getput_basic.c] [regress/unittests/sshbuf/test_sshbuf_getput_crypto.c] [regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c] [regress/unittests/sshbuf/test_sshbuf_misc.c] [regress/unittests/sshbuf/tests.c] [regress/unittests/test_helper/Makefile] [regress/unittests/test_helper/fuzz.c] [regress/unittests/test_helper/test_helper.c] [regress/unittests/test_helper/test_helper.h] Import new unit tests from OpenBSD; not yet hooked up to build. commit 167685756fde8bc213a8df2c8e1848e312db0f46 Author: Damien Miller Date: Thu May 15 15:08:40 2014 +1000 - logan@cvs.openbsd.org 2014/05/04 10:40:59 [connect-privsep.sh] Remove the Z flag from the list of malloc options as it was removed from malloc.c 10 days ago. OK from miod@ commit d0b69fe90466920d69c96069312e24b581771bd7 Author: Damien Miller Date: Thu May 15 15:08:19 2014 +1000 - dtucker@cvs.openbsd.org 2014/05/03 18:46:14 [proxy-connect.sh] Add tests for with and without compression, with and without privsep. commit edb1af50441d19fb2dd9ccb4d75bf14473fca584 Author: Damien Miller Date: Thu May 15 15:07:53 2014 +1000 - djm@cvs.openbsd.org 2014/04/21 22:15:37 [dhgex.sh integrity.sh kextype.sh rekey.sh try-ciphers.sh] repair regress tests broken by server-side default cipher/kex/mac changes by ensuring that the option under test is included in the server's algorithm list commit 54343e95c70994695f8842fb22836321350198d3 Author: Damien Miller Date: Thu May 15 15:07:33 2014 +1000 - djm@cvs.openbsd.org 2014/03/13 20:44:49 [login-timeout.sh] this test is a sorry mess of race conditions; add another sleep to avoid a failure on slow machines (at least until I find a better way) commit e5b9f0f2ee6e133894307e44e862b66426990733 Author: Damien Miller Date: Thu May 15 14:58:07 2014 +1000 - (djm) [Makefile.in configure.ac sshbuf-getput-basic.c] [sshbuf-getput-crypto.c sshbuf.c] compilation and portability fixes commit b9c566788a9ebd6a9d466f47a532124f111f0542 Author: Damien Miller Date: Thu May 15 14:43:37 2014 +1000 - (djm) [configure.ac] Unconditionally define WITH_OPENSSL until we write portability glue to support building without libcrypto commit 3dc27178b42234b653a32f7a87292d7994045ee3 Author: Damien Miller Date: Thu May 15 14:37:59 2014 +1000 - logan@cvs.openbsd.org 2014/05/05 07:02:30 [sftp.c] Zap extra whitespace. OK from djm@ and dtucker@ commit c31a0cd5b31961f01c5b731f62a6cb9d4f767472 Author: Damien Miller Date: Thu May 15 14:37:39 2014 +1000 - markus@cvs.openbsd.org 2014/05/03 17:20:34 [monitor.c packet.c packet.h] unbreak compression, by re-init-ing the compression code in the post-auth child. the new buffer code is more strict, and requires buffer_init() while the old code was happy after a bzero(); originally from djm@ commit 686c7d9ee6f44b2be4128d7860b6b37adaeba733 Author: Damien Miller Date: Thu May 15 14:37:03 2014 +1000 - djm@cvs.openbsd.org 2014/05/02 03:27:54 [chacha.h cipher-chachapoly.h digest.h hmac.h kex.h kexc25519.c] [misc.h poly1305.h ssh-pkcs11.c defines.h] revert __bounded change; it causes way more problems for portable than it solves; pointed out by dtucker@ commit 294c58a007cfb2f3bddc4fc3217e255857ffb9bf Author: Damien Miller Date: Thu May 15 14:35:03 2014 +1000 - naddy@cvs.openbsd.org 2014/04/30 19:07:48 [mac.c myproposal.h umac.c] UMAC can use our local fallback implementation of AES when OpenSSL isn't available. Glue code straight from Ted Krovetz's original umac.c. ok markus@ commit 05e82c3b963c33048128baf72a6f6b3a1c10b4c1 Author: Damien Miller Date: Thu May 15 14:33:43 2014 +1000 - djm@cvs.openbsd.org 2014/04/30 05:29:56 [bufaux.c bufbn.c bufec.c buffer.c buffer.h sshbuf-getput-basic.c] [sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c sshbuf.h ssherr.c] [ssherr.h] New buffer API; the first installment of the conversion/replacement of OpenSSH's internals to make them usable as a standalone library. This includes a set of wrappers to make it compatible with the existing buffer API so replacement can occur incrementally. With and ok markus@ Thanks also to Ben Hawkes, David Tomaschik, Ivan Fratric, Matthew Dempsky and Ron Bowes for a detailed review. commit 380948180f847a26f2d0c85b4dad3dca2ed2fd8b Author: Damien Miller Date: Thu May 15 14:25:18 2014 +1000 - dtucker@cvs.openbsd.org 2014/04/29 20:36:51 [sftp.c] Don't attempt to append a nul quote char to the filename. Should prevent fatal'ing with "el_insertstr failed" when there's a single quote char somewhere in the string. bz#2238, ok markus@ commit d7fd8bedd4619a2ec7fd02aae4c4e1db4431ad9f Author: Damien Miller Date: Thu May 15 14:24:59 2014 +1000 - dtucker@cvs.openbsd.org 2014/04/29 19:58:50 [sftp.c] Move nulling of variable next to where it's freed. ok markus@ commit 1f0311c7c7d10c94ff7f823de9c5b2ed79368b14 Author: Damien Miller Date: Thu May 15 14:24:09 2014 +1000 - markus@cvs.openbsd.org 2014/04/29 18:01:49 [auth.c authfd.c authfile.c bufaux.c cipher.c cipher.h hostfile.c] [kex.c key.c mac.c monitor.c monitor_wrap.c myproposal.h packet.c] [roaming_client.c ssh-agent.c ssh-keygen.c ssh-keyscan.c ssh-keysign.c] [ssh-pkcs11.h ssh.c sshconnect.c sshconnect2.c sshd.c] make compiling against OpenSSL optional (make OPENSSL=no); reduces algorithms to curve25519, aes-ctr, chacha, ed25519; allows us to explore further options; with and ok djm commit c5893785564498cea73cb60d2cf199490483e080 Author: Damien Miller Date: Thu May 15 13:48:49 2014 +1000 - djm@cvs.openbsd.org 2014/04/29 13:10:30 [clientloop.c serverloop.c] bz#1818 - don't send channel success/failre replies on channels that have sent a close already; analysis and patch from Simon Tatham; ok markus@ commit 633de33b192d808d87537834c316dc8b75fe1880 Author: Damien Miller Date: Thu May 15 13:48:26 2014 +1000 - djm@cvs.openbsd.org 2014/04/28 03:09:18 [authfile.c bufaux.c buffer.h channels.c krl.c mux.c packet.c packet.h] [ssh-keygen.c] buffer_get_string_ptr's return should be const to remind callers that futzing with it will futz with the actual buffer contents commit 15271907843e4ae50dcfc83b3594014cf5e9607b Author: Damien Miller Date: Thu May 15 13:47:56 2014 +1000 - djm@cvs.openbsd.org 2014/04/23 12:42:34 [readconf.c] don't record duplicate IdentityFiles commit 798a02568b13a2e46efebd81f08c8f4bb33a6dc7 Author: Damien Miller Date: Thu May 15 13:47:37 2014 +1000 - jmc@cvs.openbsd.org 2014/04/22 14:16:30 [sftp.1] zap eol whitespace; commit d875ff78d2b8436807381051de112f0ebf9b9ae1 Author: Damien Miller Date: Thu May 15 13:47:15 2014 +1000 - logan@cvs.openbsd.org 2014/04/22 12:42:04 [sftp.1] Document sftp upload resume. OK from djm@, with feedback from okan@. commit b15cd7bb097fd80dc99520f45290ef775da1ef19 Author: Damien Miller Date: Thu May 15 13:46:52 2014 +1000 - logan@cvs.openbsd.org 2014/04/22 10:07:12 [sftp.c] Sort the sftp command list. OK from djm@ commit d8accc0aa72656ba63d50937165c5ae49db1dcd6 Author: Damien Miller Date: Thu May 15 13:46:25 2014 +1000 - logan@cvs.openbsd.org 2014/04/21 14:36:16 [sftp-client.c sftp-client.h sftp.c] Implement sftp upload resume support. OK from djm@, with input from guenther@, mlarkin@ and okan@ commit 16cd3928a87d20c77b13592a74b60b08621d3ce6 Author: Damien Miller Date: Thu May 15 13:45:58 2014 +1000 - logan@cvs.openbsd.org 2014/04/20 09:24:26 [dns.c dns.h ssh-keygen.c] Add support for SSHFP DNS records for ED25519 key types. OK from djm@ commit ec0b67eb3b4e12f296ced1fafa01860c374f7eea Author: Damien Miller Date: Thu May 15 13:45:26 2014 +1000 - (djm) [rijndael.c rijndael.h] Sync with newly-ressurected versions ine OpenBSD commit f028460d0b2e5a584355321015cde69bf6fd933e Author: Darren Tucker Date: Thu May 1 02:24:35 2014 +1000 - (dtucker) [defines.h] Define __GNUC_PREREQ__ macro if we don't already have it. Only attempt to use __attribute__(__bounded__) for gcc. commit b628cc4c3e4a842bab5e4584d18c2bc5fa4d0edf Author: Damien Miller Date: Sun Apr 20 13:33:58 2014 +1000 - djm@cvs.openbsd.org 2014/04/20 02:49:32 [compat.c] add a canonical 6.6 + curve25519 bignum fix fake version that I can recommend people use ahead of the openssh-6.7 release commit 888566913933a802f3a329ace123ebcb7154cf78 Author: Damien Miller Date: Sun Apr 20 13:33:19 2014 +1000 - djm@cvs.openbsd.org 2014/04/20 02:30:25 [misc.c misc.h umac.c] use get/put_u32 to load values rather than *((UINT32 *)p) that breaks on strict-alignment architectures; reported by and ok stsp@ commit 16f85cbc7e5139950e6a38317e7c8b368beafa5d Author: Damien Miller Date: Sun Apr 20 13:29:28 2014 +1000 - tedu@cvs.openbsd.org 2014/04/19 18:42:19 [ssh.1] delete .xr to hosts.equiv. there's still an unfortunate amount of documentation referring to rhosts equivalency in here. commit 69cb24b7356ec3f0fc5ff04a68f98f2c55c766f4 Author: Damien Miller Date: Sun Apr 20 13:29:06 2014 +1000 - tedu@cvs.openbsd.org 2014/04/19 18:15:16 [sshd.8] remove some really old rsh references commit 84c1e7bca8c4ceaccf4d5557e39a833585a3c77e Author: Damien Miller Date: Sun Apr 20 13:27:53 2014 +1000 - tedu@cvs.openbsd.org 2014/04/19 14:53:48 [ssh-keysign.c sshd.c] Delete futile calls to RAND_seed. ok djm NB. Id sync only. This only applies to OpenBSD's libcrypto slashathon commit 0e6b67423b8662f9ca4c92750309e144fd637ef1 Author: Damien Miller Date: Sun Apr 20 13:27:01 2014 +1000 - djm@cvs.openbsd.org 2014/04/19 05:54:59 [compat.c] missing wildcard; pointed out by naddy@ commit 9395b28223334826837c15e8c1bb4dfb3b0d2ca5 Author: Damien Miller Date: Sun Apr 20 13:25:30 2014 +1000 - djm@cvs.openbsd.org 2014/04/18 23:52:25 [compat.c compat.h sshconnect2.c sshd.c version.h] OpenSSH 6.5 and 6.6 have a bug that causes ~0.2% of connections using the curve25519-sha256@libssh.org KEX exchange method to fail when connecting with something that implements the spec properly. Disable this KEX method when speaking to one of the affected versions. reported by Aris Adamantiadis; ok markus@ commit 8c492da58f8ceb85cf5f7066f23e26fb813a963d Author: Damien Miller Date: Sun Apr 20 13:25:09 2014 +1000 - djm@cvs.openbsd.org 2014/04/16 23:28:12 [ssh-agent.1] remove the identity files from this manpage - ssh-agent doesn't deal with them at all and the same information is duplicated in ssh-add.1 (which does deal with them); prodded by deraadt@ commit adbfdbbdccc70c9bd70d81ae096db115445c6e26 Author: Damien Miller Date: Sun Apr 20 13:24:49 2014 +1000 - djm@cvs.openbsd.org 2014/04/16 23:22:45 [bufaux.c] skip leading zero bytes in buffer_put_bignum2_from_string(); reported by jan AT mojzis.com; ok markus@ commit 75c62728dc87af6805696eeb520b9748faa136c8 Author: Damien Miller Date: Sun Apr 20 13:24:31 2014 +1000 - djm@cvs.openbsd.org 2014/04/12 04:55:53 [sshd.c] avoid crash at exit: check that pmonitor!=NULL before dereferencing; bz#2225, patch from kavi AT juniper.net commit 2a328437fb1b0976f2f4522d8645803d5a5d0967 Author: Damien Miller Date: Sun Apr 20 13:24:01 2014 +1000 - djm@cvs.openbsd.org 2014/04/01 05:32:57 [packet.c] demote a debug3 to PACKET_DEBUG; ok markus@ commit 7d6a9fb660c808882d064e152d6070ffc3844c3f Author: Damien Miller Date: Sun Apr 20 13:23:43 2014 +1000 - djm@cvs.openbsd.org 2014/04/01 03:34:10 [sshconnect.c] When using VerifyHostKeyDNS with a DNSSEC resolver, down-convert any certificate keys to plain keys and attempt SSHFP resolution. Prevents a server from skipping SSHFP lookup and forcing a new-hostkey dialog by offering only certificate keys. Reported by mcv21 AT cam.ac.uk commit fcd62c0b66b8415405ed0af29c236329eb88cc0f Author: Damien Miller Date: Sun Apr 20 13:23:21 2014 +1000 - djm@cvs.openbsd.org 2014/04/01 02:05:27 [ssh-keysign.c] include fingerprint of key not found use arc4random_buf() instead of loop+arc4random() commit 43b156cf72f900f88065b0a1c1ebd09ab733ca46 Author: Damien Miller Date: Sun Apr 20 13:23:03 2014 +1000 - jmc@cvs.openbsd.org 2014/03/31 13:39:34 [ssh-keygen.1] the text for the -K option was inserted in the wrong place in -r1.108; fix From: Matthew Clarke commit c1621c84f2dc1279065ab9fde2aa9327af418900 Author: Damien Miller Date: Sun Apr 20 13:22:46 2014 +1000 - naddy@cvs.openbsd.org 2014/03/28 05:17:11 [ssh_config.5 sshd_config.5] sync available and default algorithms, improve algorithm list formatting help from jmc@ and schwarze@, ok deraadt@ commit f2719b7c2b8a3b14d778d8a6d8dc729b5174b054 Author: Damien Miller Date: Sun Apr 20 13:22:18 2014 +1000 - tedu@cvs.openbsd.org 2014/03/26 19:58:37 [sshd.8 sshd.c] remove libwrap support. ok deraadt djm mfriedl commit 4f40209aa4060b9c066a2f0d9332ace7b8dfb391 Author: Damien Miller Date: Sun Apr 20 13:21:22 2014 +1000 - djm@cvs.openbsd.org 2014/03/26 04:55:35 [chacha.h cipher-chachapoly.h digest.h hmac.h kex.h kexc25519.c [misc.h poly1305.h ssh-pkcs11.c] use __bounded(...) attribute recently added to sys/cdefs.h instead of longform __attribute__(__bounded(...)); for brevity and a warning free compilation with llvm/clang commit 9235a030ad1b16903fb495d81544e0f7c7449523 Author: Damien Miller Date: Sun Apr 20 13:17:20 2014 +1000 Three commits in one (since they touch the same heavily-diverged file repeatedly): - markus@cvs.openbsd.org 2014/03/25 09:40:03 [myproposal.h] trimm default proposals. This commit removes the weaker pre-SHA2 hashes, the broken ciphers (arcfour), and the broken modes (CBC) from the default configuration (the patch only changes the default, all the modes are still available for the config files). ok djm@, reminded by tedu@ & naddy@ and discussed with many - deraadt@cvs.openbsd.org 2014/03/26 17:16:26 [myproposal.h] The current sharing of myproposal[] between both client and server code makes the previous diff highly unpallatable. We want to go in that direction for the server, but not for the client. Sigh. Brought up by naddy. - markus@cvs.openbsd.org 2014/03/27 23:01:27 [myproposal.h ssh-keyscan.c sshconnect2.c sshd.c] disable weak proposals in sshd, but keep them in ssh; ok djm@ commit 6e1777f592f15f4559728c78204617537b1ac076 Author: Damien Miller Date: Sun Apr 20 13:02:58 2014 +1000 - tedu@cvs.openbsd.org 2014/03/19 14:42:44 [scp.1] there is no need for rcp anymore ok deraadt millert commit eb1b7c514d2a7b1802ccee8cd50e565a4d419887 Author: Damien Miller Date: Sun Apr 20 13:02:26 2014 +1000 - tedu@cvs.openbsd.org 2014/03/17 19:44:10 [ssh.1] old descriptions of des and blowfish are old. maybe ok deraadt commit f0858de6e1324ec730752387074b111b8551081e Author: Damien Miller Date: Sun Apr 20 13:01:30 2014 +1000 - deraadt@cvs.openbsd.org 2014/03/15 17:28:26 [ssh-agent.c ssh-keygen.1 ssh-keygen.c] Improve usage() and documentation towards the standard form. In particular, this line saves a lot of man page reading time. usage: ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa | rsa1] [-N new_passphrase] [-C comment] [-f output_keyfile] ok schwarze jmc commit 94bfe0fbd6e91a56b5b0ab94ac955d2a67d101aa Author: Damien Miller Date: Sun Apr 20 13:00:51 2014 +1000 - naddy@cvs.openbsd.org 2014/03/12 13:06:59 [ssh-keyscan.1] scan for Ed25519 keys by default too commit 3819519288b2b3928c6882f5883b0f55148f4fc0 Author: Damien Miller Date: Sun Apr 20 13:00:28 2014 +1000 - djm@cvs.openbsd.org 2014/03/12 04:51:12 [authfile.c] correct test that kdf name is not "none" or "bcrypt" commit 8f9cd709c7cf0655d414306a0ed28306b33802be Author: Damien Miller Date: Sun Apr 20 13:00:11 2014 +1000 - djm@cvs.openbsd.org 2014/03/12 04:50:32 [auth-bsdauth.c ssh-keygen.c] don't count on things that accept arguments by reference to clear things for us on error; most things do, but it's unsafe form. commit 1c7ef4be83f6dec84509a312518b9df00ab491d9 Author: Damien Miller Date: Sun Apr 20 12:59:46 2014 +1000 - djm@cvs.openbsd.org 2014/03/12 04:44:58 [ssh-keyscan.c] scan for Ed25519 keys by default too commit c10bf4d051c97939b30a1616c0499310057d07da Author: Damien Miller Date: Sun Apr 20 12:58:04 2014 +1000 - djm@cvs.openbsd.org 2014/03/03 22:22:30 [session.c] ignore enviornment variables with embedded '=' or '\0' characters; spotted by Jann Horn; ok deraadt@ Id sync only - portable already has this. commit c2e49062faccbcd7135c40d1c78c5c329c58fc2e Author: Damien Miller Date: Tue Apr 1 14:42:46 2014 +1100 - (djm) Use full release (e.g. 6.5p1) in debug output rather than just version. From des@des.no commit 14928b7492abec82afa4c2b778fc03f78cd419b6 Author: Damien Miller Date: Tue Apr 1 14:38:07 2014 +1100 - (djm) On platforms that support it, use prctl() to prevent sftp-server from accessing /proc/self/{mem,maps}; patch from jann AT thejh.net commit 48abc47e60048461fe9117e108a7e99ea1ac2bb8 Author: Damien Miller Date: Mon Mar 17 14:45:56 2014 +1100 - (djm) [sandbox-seccomp-filter.c] Soft-fail stat() syscalls. Add XXX to remind myself to add sandbox violation logging via the log socket. commit 9c36698ca2f554ec221dc7ef29c7a89e97c88705 Author: Tim Rice Date: Fri Mar 14 12:45:01 2014 -0700 20140314 - (tim) [opensshd.init.in] Add support for ed25519 commit 19158b2447e35838d69b2b735fb640d1e86061ea Author: Damien Miller Date: Thu Mar 13 13:14:21 2014 +1100 - (djm) Release OpenSSH 6.6 commit 8569eba5d7f7348ce3955eeeb399f66f25c52ece Author: Damien Miller Date: Tue Mar 4 09:35:17 2014 +1100 - djm@cvs.openbsd.org 2014/03/03 22:22:30 [session.c] ignore enviornment variables with embedded '=' or '\0' characters; spotted by Jann Horn; ok deraadt@ commit 2476c31b96e89aec7d4e73cb6fbfb9a4290de3a7 Author: Damien Miller Date: Sun Mar 2 04:01:00 2014 +1100 - (djm) [regress/Makefile] Disable dhgex regress test; it breaks when no moduli file exists at the expected location. commit c83fdf30e9db865575b2521b1fe46315cf4c70ae Author: Damien Miller Date: Fri Feb 28 10:34:03 2014 +1100 - (djm) [regress/host-expand.sh] Add RCS Id commit 834aeac3555e53f7d29a6fcf3db010dfb99681c7 Author: Damien Miller Date: Fri Feb 28 10:25:16 2014 +1100 - djm@cvs.openbsd.org 2014/02/27 21:21:25 [agent-ptrace.sh agent.sh] keep return values that are printed in error messages; from portable (Id sync only) commit 4f7f1a9a0de24410c30952c7e16d433240422182 Author: Damien Miller Date: Fri Feb 28 10:24:11 2014 +1100 - djm@cvs.openbsd.org 2014/02/27 20:04:16 [login-timeout.sh] remove any existing LoginGraceTime from sshd_config before adding a specific one for the test back in commit d705d987c27f68080c8798eeb5262adbdd6b4ffd Author: Damien Miller Date: Fri Feb 28 10:23:26 2014 +1100 - djm@cvs.openbsd.org 2014/01/26 10:49:17 [scp-ssh-wrapper.sh scp.sh] make sure $SCP is tested on the remote end rather than whichever one happens to be in $PATH; from portable (Id sync only) commit 624a3ca376e3955a4b9d936c9e899e241b65d357 Author: Damien Miller Date: Fri Feb 28 10:22:37 2014 +1100 - djm@cvs.openbsd.org 2014/01/26 10:22:10 [regress/cert-hostkey.sh] automatically generate revoked keys from listed keys rather than manually specifying each type; from portable (Id sync only) commit b84392328425e4b9a71f8bde5fe6a4a4c48d3ec4 Author: Damien Miller Date: Fri Feb 28 10:21:26 2014 +1100 - dtucker@cvs.openbsd.org 2014/01/25 04:35:32 [regress/Makefile regress/dhgex.sh] Add a test for DH GEX sizes commit 1e2aa3d90472293ea19008f02336d6d68aa05793 Author: Damien Miller Date: Fri Feb 28 10:19:51 2014 +1100 - dtucker@cvs.openbsd.org 2014/01/20 00:00:30 [sftp-chroot.sh] append to rather than truncating the log file commit f483cc16fe7314e24a37aa3a4422b03c013c3213 Author: Damien Miller Date: Fri Feb 28 10:19:11 2014 +1100 - dtucker@cvs.openbsd.org 2014/01/19 23:43:02 [regress/sftp-chroot.sh] Don't use -q on sftp as it suppresses logging, instead redirect the output to the regress logfile. commit 6486f16f1c0ebd6f39286f6ab5e08286d90a994a Author: Damien Miller Date: Fri Feb 28 10:03:52 2014 +1100 - (djm) [README contrib/caldera/openssh.spec contrib/redhat/openssh.spec] [contrib/suse/openssh.spec] Crank version numbers commit 92cf5adea194140380e6af6ec32751f9ad540794 Author: Damien Miller Date: Fri Feb 28 10:01:53 2014 +1100 - djm@cvs.openbsd.org 2014/02/27 22:57:40 [version.h] openssh-6.6 commit fc5d6759aba71eb205b296b5f148010ffc828583 Author: Damien Miller Date: Fri Feb 28 10:01:28 2014 +1100 - djm@cvs.openbsd.org 2014/02/27 22:47:07 [sshd_config.5] bz#2184 clarify behaviour of a keyword that appears in multiple matching Match blocks; ok dtucker@ commit 172ec7e0af1a5f1d682f6a2dca335c6c186153d5 Author: Damien Miller Date: Fri Feb 28 10:00:57 2014 +1100 - djm@cvs.openbsd.org 2014/02/27 08:25:09 [bufbn.c] off by one in range check commit f9a9aaba437c2787e40cf7cc928281950e161678 Author: Damien Miller Date: Fri Feb 28 10:00:27 2014 +1100 - djm@cvs.openbsd.org 2014/02/27 00:41:49 [bufbn.c] fix unsigned overflow that could lead to reading a short ssh protocol 1 bignum value; found by Ben Hawkes; ok deraadt@ commit fb3423b612713d9cde67c8a75f6f51188d6a3de3 Author: Damien Miller Date: Thu Feb 27 10:20:07 2014 +1100 - markus@cvs.openbsd.org 2014/02/26 21:53:37 [sshd.c] ssh_gssapi_prepare_supported_oids needs GSSAPI commit 1348129a34f0f7728c34d86c100a32dcc8d1f922 Author: Damien Miller Date: Thu Feb 27 10:18:32 2014 +1100 - djm@cvs.openbsd.org 2014/02/26 20:29:29 [channels.c] don't assume that the socks4 username is \0 terminated; spotted by Ben Hawkes; ok markus@ commit e6a74aeeacd01d885262ff8e50eb28faee8c8039 Author: Damien Miller Date: Thu Feb 27 10:17:49 2014 +1100 - djm@cvs.openbsd.org 2014/02/26 20:28:44 [auth2-gss.c gss-serv.c ssh-gss.h sshd.c] bz#2107 - cache OIDs of supported GSSAPI mechanisms before privsep sandboxing, as running this code in the sandbox can cause violations; ok markus@ commit 08b57c67f3609340ff703fe2782d7058acf2529e Author: Damien Miller Date: Thu Feb 27 10:17:13 2014 +1100 - djm@cvs.openbsd.org 2014/02/26 20:18:37 [ssh.c] bz#2205: avoid early hostname lookups unless canonicalisation is enabled; ok dtucker@ markus@ commit 13f97b2286142fd0b8eab94e4ce84fe124eeb752 Author: Damien Miller Date: Mon Feb 24 15:57:55 2014 +1100 - djm@cvs.openbsd.org 2014/02/23 20:11:36 [readconf.c readconf.h ssh.c ssh_config.5] reparse ssh_config and ~/.ssh/config if hostname canonicalisation changes the hostname. This allows users to write configurations that always refer to canonical hostnames, e.g. CanonicalizeHostname yes CanonicalDomains int.example.org example.org CanonicalizeFallbackLocal no Host *.int.example.org Compression off Host *.example.org User djm ok markus@ commit bee3a234f3d1ad4244952bcff1b4b7c525330dc2 Author: Damien Miller Date: Mon Feb 24 15:57:22 2014 +1100 - djm@cvs.openbsd.org 2014/02/23 20:03:42 [ssh-ed25519.c] check for unsigned overflow; not reachable in OpenSSH but others might copy our code... commit 0628780abe61e7e50cba48cdafb1837f49ff23b2 Author: Damien Miller Date: Mon Feb 24 15:56:45 2014 +1100 - djm@cvs.openbsd.org 2014/02/22 01:32:19 [readconf.c] when processing Match blocks, skip 'exec' clauses if previous predicates failed to match; ok markus@ commit 0890dc8191bb201eb01c3429feec0300a9d3a930 Author: Damien Miller Date: Mon Feb 24 15:56:07 2014 +1100 - djm@cvs.openbsd.org 2014/02/15 23:05:36 [channels.c] avoid spurious "getsockname failed: Bad file descriptor" errors in ssh -W; bz#2200, debian#738692 via Colin Watson; ok dtucker@ commit d3cf67e1117c25d151d0f86396e77ee3a827045a Author: Damien Miller Date: Mon Feb 24 15:55:36 2014 +1100 - djm@cvs.openbsd.org 2014/02/07 06:55:54 [cipher.c mac.c] remove some logging that makes ssh debugging output very verbose; ok markus commit 03ae081aeaa118361c81ece76eb7cc1aaa2b40c5 Author: Tim Rice Date: Fri Feb 21 09:09:34 2014 -0800 20140221 - (tim) [configure.ac] Fix cut-and-paste error. Patch from Bryan Drewery. commit 4a20959d2e3c90e9d66897c0b4032c785672d815 Author: Darren Tucker Date: Thu Feb 13 16:38:32 2014 +1100 - (dtucker) [configure.ac openbsd-compat/openssl-compat.{c,h}] Add compat code for older OpenSSL versions that don't have EVP_MD_CTX_copy_ex. commit d1a7a9c0fd1ac2e3314cceb2891959fd2cd9eabb Author: Damien Miller Date: Fri Feb 7 09:24:33 2014 +1100 - djm@cvs.openbsd.org 2014/02/06 22:21:01 [sshconnect.c] in ssh_create_socket(), only do the getaddrinfo for BindAddress when BindAddress is actually specified. Fixes regression in 6.5 for UsePrivilegedPort=yes; patch from Corinna Vinschen commit 6ce35b6cc4ead1bf98abec34cb2e2d6ca0abb15e Author: Damien Miller Date: Fri Feb 7 09:24:14 2014 +1100 - naddy@cvs.openbsd.org 2014/02/05 20:13:25 [ssh-keygen.1 ssh-keygen.c] tweak synopsis: calling ssh-keygen without any arguments is fine; ok jmc@ while here, fix ordering in usage(); requested by jmc@ commit 6434cb2cfbbf0a46375d2d22f2ff9927feb5e478 Author: Damien Miller Date: Thu Feb 6 11:17:50 2014 +1100 - (djm) [sandbox-seccomp-filter.c] Not all Linux architectures define __NR_shutdown; some go via the socketcall(2) multiplexer. commit 8d36f9ac71eff2e9f5770c0518b73d875f270647 Author: Darren Tucker Date: Thu Feb 6 10:44:13 2014 +1100 - (dtucker) [openbsd-compat/bsd-poll.c] Don't bother checking for non-NULL before freeing since free(NULL) is a no-op. ok djm. commit a0959da3680b4ce8cf911caf3293a6d90f88eeb7 Author: Damien Miller Date: Wed Feb 5 10:33:45 2014 +1100 - (djm) [sandbox-capsicum.c] Don't fatal if Capsicum is offered by headers/libc but not supported by the kernel. Patch from Loganaden Velvindron @ AfriNIC commit 9c449bc183b256c84d8f740727b0bc54d247b15e Author: Damien Miller Date: Tue Feb 4 11:38:28 2014 +1100 - (djm) [regress/setuid-allowed.c] Missing string.h for strerror() commit bf7e0f03be661b6f5b3bfe325135ce19391f9c4d Author: Damien Miller Date: Tue Feb 4 11:37:50 2014 +1100 - (djm) [openbsd-compat/Makefile.in] Add missing explicit_bzero.o commit eb6d870a0ea8661299bb2ea8f013d3ace04e2024 Author: Damien Miller Date: Tue Feb 4 11:26:34 2014 +1100 - djm@cvs.openbsd.org 2014/02/04 00:24:29 [ssh.c] delay lowercasing of hostname until right before hostname canonicalisation to unbreak case-sensitive matching of ssh_config; reported by Ike Devolder; ok markus@ commit d56b44d2dfa093883a5c4e91be3f72d99946b170 Author: Damien Miller Date: Tue Feb 4 11:26:04 2014 +1100 - djm@cvs.openbsd.org 2014/02/04 00:24:29 [ssh.c] delay lowercasing of hostname until right before hostname canonicalisation to unbreak case-sensitive matching of ssh_config; reported by Ike Devolder; ok markus@ commit db3c595ea74ea9ccd5aa644d7e1f8dc675710731 Author: Damien Miller Date: Tue Feb 4 11:25:45 2014 +1100 - djm@cvs.openbsd.org 2014/02/02 03:44:31 [digest-libc.c digest-openssl.c] convert memset of potentially-private data to explicit_bzero() commit aae07e2e2000dd318418fd7fd4597760904cae32 Author: Damien Miller Date: Tue Feb 4 11:20:40 2014 +1100 - djm@cvs.openbsd.org 2014/02/03 23:28:00 [ssh-ecdsa.c] fix memory leak; ECDSA_SIG_new() allocates 'r' and 's' for us, unlike DSA_SIG_new. Reported by Batz Spear; ok markus@ commit a5103f413bde6f31bff85d6e1fd29799c647d765 Author: Damien Miller Date: Tue Feb 4 11:20:14 2014 +1100 - djm@cvs.openbsd.org 2014/02/02 03:44:32 [auth1.c auth2-chall.c auth2-passwd.c authfile.c bufaux.c bufbn.c] [buffer.c cipher-3des1.c cipher.c clientloop.c gss-serv.c kex.c] [kexdhc.c kexdhs.c kexecdhc.c kexgexc.c kexecdhs.c kexgexs.c key.c] [monitor.c monitor_wrap.c packet.c readpass.c rsa.c serverloop.c] [ssh-add.c ssh-agent.c ssh-dss.c ssh-ecdsa.c ssh-ed25519.c] [ssh-keygen.c ssh-rsa.c sshconnect.c sshconnect1.c sshconnect2.c] [sshd.c] convert memset of potentially-private data to explicit_bzero() commit 1d2c4564265ee827147af246a16f3777741411ed Author: Damien Miller Date: Tue Feb 4 11:18:20 2014 +1100 - tedu@cvs.openbsd.org 2014/01/31 16:39:19 [auth2-chall.c authfd.c authfile.c bufaux.c bufec.c canohost.c] [channels.c cipher-chachapoly.c clientloop.c configure.ac hostfile.c] [kexc25519.c krl.c monitor.c sandbox-systrace.c session.c] [sftp-client.c ssh-keygen.c ssh.c sshconnect2.c sshd.c sshlogin.c] [openbsd-compat/explicit_bzero.c openbsd-compat/openbsd-compat.h] replace most bzero with explicit_bzero, except a few that cna be memset ok djm dtucker commit 3928de067c286683a95fbdbdb5fdb3c78a0e5efd Author: Damien Miller Date: Tue Feb 4 11:13:54 2014 +1100 - djm@cvs.openbsd.org 2014/01/30 22:26:14 [sandbox-systrace.c] allow shutdown(2) syscall in sandbox - it may be called by packet_close() from portable (Id sync only; change is already in portable) commit e1e480aee8a9af6cfbe7188667b7b940d6b57f9f Author: Damien Miller Date: Tue Feb 4 11:13:17 2014 +1100 - jmc@cvs.openbsd.org 2014/01/29 14:04:51 [sshd_config.5] document kbdinteractiveauthentication; requested From: Ross L Richardson dtucker/markus helped explain its workings; commit 7cc194f70d4a5ec9a82d19422eaf18db4a6624c6 Author: Damien Miller Date: Tue Feb 4 11:12:56 2014 +1100 - djm@cvs.openbsd.org 2014/01/29 06:18:35 [Makefile.in auth.h auth2-jpake.c auth2.c jpake.c jpake.h monitor.c] [monitor.h monitor_wrap.c monitor_wrap.h readconf.c readconf.h] [schnorr.c schnorr.h servconf.c servconf.h ssh2.h sshconnect2.c] remove experimental, never-enabled JPAKE code; ok markus@ commit b0f26544cf6f4feeb1a4f6db09fca834f5c9867d Author: Damien Miller Date: Tue Feb 4 11:10:01 2014 +1100 - djm@cvs.openbsd.org 2014/01/29 00:19:26 [sshd.c] use kill(0, ...) instead of killpg(0, ...); on most operating systems they are equivalent, but SUSv2 describes the latter as having undefined behaviour; from portable; ok dtucker (Id sync only; change is already in portable) commit f8f35bc471500348bb262039fb1fc43175d251b0 Author: Damien Miller Date: Tue Feb 4 11:09:12 2014 +1100 - jmc@cvs.openbsd.org 2014/01/28 14:13:39 [ssh-keyscan.1] kill some bad Pa; From: Jan Stary commit 0ba85d696ae9daf66002c2e4ab0d6bb111e1a787 Author: Damien Miller Date: Tue Feb 4 11:08:38 2014 +1100 ignore a few more regress droppings commit ec93d15170b7a6ddf63fd654bd0f6a752acc19dd Author: Damien Miller Date: Tue Feb 4 11:07:13 2014 +1100 - markus@cvs.openbsd.org 2014/01/27 20:13:46 [digest.c digest-openssl.c digest-libc.c Makefile.in] rename digest.c to digest-openssl.c and add libc variant; ok djm@ commit 4a1c7aa640fb97d3472d51b215b6a0ec0fd025c7 Author: Damien Miller Date: Tue Feb 4 11:03:36 2014 +1100 - markus@cvs.openbsd.org 2014/01/27 19:18:54 [auth-rsa.c cipher.c ssh-agent.c sshconnect1.c sshd.c] replace openssl MD5 with our ssh_digest_*; ok djm@ commit 4e8d937af79ce4e253f77ec93489d098b25becc3 Author: Damien Miller Date: Tue Feb 4 11:02:42 2014 +1100 - markus@cvs.openbsd.org 2014/01/27 18:58:14 [Makefile.in digest.c digest.h hostfile.c kex.h mac.c hmac.c hmac.h] replace openssl HMAC with an implementation based on our ssh_digest_* ok and feedback djm@ commit 69d0d09f76bab5aec86fbf78489169f63bd16475 Author: Tim Rice Date: Fri Jan 31 14:25:18 2014 -0800 - (tim) [Makefile.in] build regress/setuid-allow. commit 0eeafcd76b972a3d159f3118227c149a4d7817fe Author: Darren Tucker Date: Fri Jan 31 14:18:51 2014 +1100 - (dtucker) [readconf.c] Include for the hton macros. Fixes build with HP-UX's compiler. Patch from Kevin Brott. commit 7e5cec6070673e9f9785ffc749837ada22fbe99f Author: Damien Miller Date: Fri Jan 31 09:25:34 2014 +1100 - (djm) [sandbox-seccomp-filter.c sandbox-systrace.c] Allow shutdown(2) syscall from sandboxes; it may be called by packet_close. commit cdb6c90811caa5df2df856be9b0b16db020fe31d Author: Damien Miller Date: Thu Jan 30 12:50:17 2014 +1100 - (djm) Release openssh-6.5p1 commit 996ea80b1884b676a901439f1f2681eb6ff68501 Author: Damien Miller Date: Thu Jan 30 12:49:55 2014 +1100 trim entries prior to openssh-6.0p1 commit f5bbd3b657b6340551c8a95f74a70857ff8fac79 Author: Damien Miller Date: Thu Jan 30 11:26:46 2014 +1100 - (djm) [configure.ac atomicio.c] Kludge around NetBSD offering different symbols for 'read' when various compiler flags are in use, causing atomicio.c comparisons against it to break and read/write operations to hang; ok dtucker commit c2868192ddc4e1420a50389e18c05db20b0b1f32 Author: Damien Miller Date: Thu Jan 30 10:21:19 2014 +1100 - (djm) [configure.ac] Only check for width-specified integer types in headers that actually exist. patch from Tom G. Christensen; ok dtucker@ commit c161fc90fc86e2035710570238a9e1ca7a68d2a5 Author: Damien Miller Date: Wed Jan 29 21:01:33 2014 +1100 - (djm) [configure.ac] Fix broken shell test '==' vs '='; patch from Tom G. Christensen commit 6f917ad376481995ab7d29fb53b08ec8d507eb9e Author: Tim Rice Date: Tue Jan 28 10:26:25 2014 -0800 - (tim) [regress/agent.sh regress/agent-ptrace.sh] Assign $? to a variable when used as an error message inside an if statement so we display the correct into. agent.sh patch from Petr Lautrbach. commit ab16ef4152914d44ce6f76e48167d26d22f66a06 Author: Damien Miller Date: Tue Jan 28 15:08:12 2014 +1100 - (djm) [sshd.c] Use kill(0, ...) instead of killpg(0, ...); the latter being specified to have undefined behaviour in SUSv3; ok dtucker commit ab0394905884dc6e58c3721211c6b38fb8fc2ca8 Author: Damien Miller Date: Tue Jan 28 15:07:10 2014 +1100 - (djm) [configure.ac] Search for inet_ntop in libnsl and libresovl; ok dtucker commit 4ab20a82d4d4168d62318923f62382f6ef242fcd Author: Darren Tucker Date: Mon Jan 27 17:35:04 2014 +1100 - (dtucker) [Makefile.in] Remove trailing backslash which some make implementations (eg older Solaris) do not cope with. commit e7e8b3cfe9f8665faaf0e68b33df5bbb431bd129 Author: Darren Tucker Date: Mon Jan 27 17:32:50 2014 +1100 Welcome to 2014 commit 5b447c0aac0dd444251e276f6bb3bbbe1c05331c Author: Damien Miller Date: Sun Jan 26 09:46:53 2014 +1100 - (djm) [configure.ac] correct AC_DEFINE for previous. commit 2035b2236d3b1f76c749c642a43e03c85eae76e6 Author: Damien Miller Date: Sun Jan 26 09:39:53 2014 +1100 - (djm) [configure.ac sandbox-capsicum.c sandbox-rlimit.c] Disable RLIMIT_NOFILE pseudo-sandbox on FreeBSD. In some configurations, libc will attempt to open additional file descriptors for crypto offload and crash if they cannot be opened. commit a92ac7410475fbb00383c7402aa954dc0a75ae19 Author: Damien Miller Date: Sun Jan 26 09:38:03 2014 +1100 - markus@cvs.openbsd.org 2014/01/25 20:35:37 [kex.c] dh_need needs to be set to max(seclen, blocksize, ivlen, mac_len) ok dtucker@, noted by mancha commit 76eea4ab4e658670ca6e76dd1e6d17f262208b57 Author: Damien Miller Date: Sun Jan 26 09:37:25 2014 +1100 - dtucker@cvs.openbsd.org 2014/01/25 10:12:50 [cipher.c cipher.h kex.c kex.h kexgexc.c] Add a special case for the DH group size for 3des-cbc, which has an effective strength much lower than the key size. This causes problems with some cryptlib implementations, which don't support group sizes larger than 4k but also don't use the largest group size it does support as specified in the RFC. Based on a patch from Petr Lautrbach at Redhat, reduced by me with input from Markus. ok djm@ markus@ commit 603b8f47f1cd9ed95a2017447db8e60ca6704594 Author: Damien Miller Date: Sat Jan 25 13:16:59 2014 +1100 - (djm) [configure.ac] autoconf sets finds to 'yes' not '1', so test against the correct thing. commit c96d85376d779b6ac61525b5440010d344d2f23f Author: Damien Miller Date: Sat Jan 25 13:12:28 2014 +1100 - (djm) [configure.ac] Do not attempt to use capsicum sandbox unless sys/capability.h exists and cap_rights_limit is in libc. Fixes build on FreeBSD9x which provides the header but not the libc support. commit f62ecef9939cb3dbeb10602fd705d4db3976d822 Author: Damien Miller Date: Sat Jan 25 12:34:38 2014 +1100 - (djm) [configure.ac] Fix detection of capsicum sandbox on FreeBSD commit b0e0f760b861676a3fe5c40133b270713d5321a9 Author: Damien Miller Date: Fri Jan 24 14:27:04 2014 +1100 - (djm) [Makefile.in regress/scp-ssh-wrapper.sh regress/scp.sh] Make the scp regress test actually test the built scp rather than the one in $PATH. ok dtucker@ commit 42a092530159637da9cb7f9e1b5f4679e34a85e6 Author: Darren Tucker Date: Thu Jan 23 23:14:39 2014 +1100 - (dtucker) [configure.ac] NetBSD's (and FreeBSD's) strnvis is gratuitously incompatible with OpenBSD's despite post-dating it by more than a decade. Declare it as broken, and document FreeBSD's as the same. ok djm@ commit 617da33c20cb59f9ea6c99c881d92493371ef7b8 Author: Tim Rice Date: Wed Jan 22 19:16:10 2014 -0800 - (tim) [session.c] Improve error reporting on set_id(). commit 5c2ff5e31f57d303ebb414d84a934c02728fa568 Author: Damien Miller Date: Wed Jan 22 21:30:12 2014 +1100 - (djm) [configure.ac aclocal.m4] More tests to detect fallout from platform hardening options: include some long long int arithmatic to detect missing support functions for -ftrapv in libgcc and equivalents, actually test linking when -ftrapv is supplied and set either both -pie/-fPIE or neither. feedback and ok dtucker@ commit 852472a54b8a0dc3e53786b313baaa86850a4273 Author: Damien Miller Date: Wed Jan 22 16:31:18 2014 +1100 - (djm) [configure.ac] Unless specifically requested, only attempt to build Position Independent Executables on gcc >= 4.x; ok dtucker commit ee87838786cef0194db36ae0675b3e7c4e8ec661 Author: Damien Miller Date: Wed Jan 22 16:30:15 2014 +1100 - (djm) [openbsd-compat/setproctitle.c] Don't fail to compile if a platform that is expected to use the reuse-argv style setproctitle hack surprises us by providing a setproctitle in libc; ok dtucker commit 5c96a154c7940fa67b1f11c421e390dbbc159f27 Author: Damien Miller Date: Tue Jan 21 13:10:26 2014 +1100 - (djm) [aclocal.m4] Flesh out the code run in the OSSH_CHECK_CFLAG_COMPILE and OSSH_CHECK_LDFLAG_LINK tests to give them a better chance of detecting toolchain-related problems; ok dtucker commit 9464ba6fb34bb42eb3501ec3c5143662e75674bf Author: Tim Rice Date: Mon Jan 20 17:59:28 2014 -0800 - (tim) [platform.c session.c] Fix bug affecting SVR5 platforms introduced with sftp chroot support. Move set_id call after chroot. commit a6d573caa14d490e6c42fb991bcb5c6860ec704b Author: Darren Tucker Date: Tue Jan 21 12:50:46 2014 +1100 - (dtucker) [aclocal.m4] Differentiate between compile-time and link-time tests in the configure output. ok djm. commit 096118dc73ab14810b3c12785c0b5acb01ad6123 Author: Darren Tucker Date: Tue Jan 21 12:48:51 2014 +1100 - (dtucker) [configure.ac] Make PIE a configure-time option which defaults to on platforms where it's known to be reliably detected and off elsewhere. Works around platforms such as FreeBSD 9.1 where it does not interop with -ftrapv (it seems to work but fails when trying to link ssh). ok djm@ commit f9df7f6f477792254eab33cdef71a6d66488cb88 Author: Damien Miller Date: Mon Jan 20 20:07:15 2014 +1100 - (djm) [regress/cert-hostkey.sh] Fix regress failure on platforms that skip one or more key types (e.g. RHEL/CentOS 6.5); ok dtucker@ commit c74e70eb52ccc0082bd5a70b5798bb01c114d138 Author: Darren Tucker Date: Mon Jan 20 13:18:09 2014 +1100 - (dtucker) [gss-serv-krb5.c] Fall back to krb5_cc_gen_new if the Kerberos implementation does not have krb5_cc_new_unique, similar to what we do in auth-krb5.c. commit 3510979e83b6a18ec8773c64c3fa04aa08b2e783 Author: Damien Miller Date: Mon Jan 20 12:41:53 2014 +1100 - djm@cvs.openbsd.org 2014/01/20 00:08:48 [digest.c] memleak; found by Loganaden Velvindron @ AfriNIC; ok markus@ commit 7eee358d7a6580479bee5cd7e52810ebfd03e5b2 Author: Darren Tucker Date: Sun Jan 19 22:37:02 2014 +1100 - dtucker@cvs.openbsd.org 2014/01/19 11:21:51 [addrmatch.c] Cast the sizeof to socklen_t so it'll work even if the supplied len is negative. Suggested by and ok djm, ok deraadt. commit b7e01c09b56ab26e8fac56bbce0fd25e36d12bb0 Author: Darren Tucker Date: Sun Jan 19 22:36:13 2014 +1100 - djm@cvs.openbsd.org 2014/01/19 04:48:08 [ssh_config.5] fix inverted meaning of 'no' and 'yes' for CanonicalizeFallbackLocal commit 7b1ded04adce42efa25ada7c3a39818d3109b724 Author: Darren Tucker Date: Sun Jan 19 15:30:02 2014 +1100 - dtucker@cvs.openbsd.org 2014/01/19 04:17:29 [canohost.c addrmatch.c] Cast socklen_t when comparing to size_t and use socklen_t to iterate over the ip options, both to prevent signed/unsigned comparison warnings. Patch from vinschen at redhat via portable openssh, begrudging ok deraadt. commit 293ee3c9f0796d99ebb033735f0e315f2e0180bf Author: Darren Tucker Date: Sun Jan 19 15:28:01 2014 +1100 - dtucker@cvs.openbsd.org 2014/01/18 09:36:26 [session.c] explicitly define USE_PIPES to 1 to prevent redefinition warnings in portable on platforms that use pipes for everything. From redhat @ redhat. commit 2aca159d05f9e7880d1d8f1ce49a218840057f53 Author: Darren Tucker Date: Sun Jan 19 15:25:34 2014 +1100 - dtucker@cvs.openbsd.org 2014/01/17 06:23:24 [sftp-server.c] fix log message statvfs. ok djm commit 841f7da89ae8b367bb502d61c5c41916c6e7ae4c Author: Darren Tucker Date: Sat Jan 18 22:12:15 2014 +1100 - (dtucker) [sandbox-capsicum.c] Correct some error messages and make the return value check for cap_enter() consistent with the other uses in FreeBSD. From by Loganaden Velvindron @ AfriNIC via bz#2140. commit fdce3731660699b2429e93e822f2ccbaccd163ae Author: Darren Tucker Date: Sat Jan 18 21:12:42 2014 +1100 - (dtucker) [configure.ac] On Cygwin the getopt variables (like optargs, optind) are defined in getopt.h already. Unfortunately they are defined as "declspec(dllimport)" for historical reasons, because the GNU linker didn't allow auto-import on PE/COFF targets way back when. The problem is the dllexport attributes collide with the definitions in the various source files in OpenSSH, which obviousy define the variables without declspec(dllimport). The least intrusive way to get rid of these warnings is to disable warnings for GCC compiler attributes when building on Cygwin. Patch from vinschen at redhat.com. commit 1411c9263f46e1ee49d0d302bf7258ebe69ce827 Author: Darren Tucker Date: Sat Jan 18 21:03:59 2014 +1100 - (dtucker) [openbsd-compat/bsd-cygwin_util.h] Add missing function declarations that stopped being included when we stopped including from openbsd-compat/bsd-cygwin_util.h. Patch from vinschen at redhat.com. commit 89c532d843c95a085777c66365067d64d1937eb9 Author: Darren Tucker Date: Sat Jan 18 20:43:49 2014 +1100 - (dtucker) [uidswap.c] Prevent unused variable warnings on Cygwin. Patch from vinschen at redhat.com commit 355f861022be7b23d3009fae8f3c9f6f7fc685f7 Author: Darren Tucker Date: Sat Jan 18 00:12:38 2014 +1100 - (dtucker) [defines.h] Move our definitions of uintXX_t types down to after they're defined if we have to define them ourselves. Fixes builds on old AIX. commit a3357661ee1d5d553294f36e4940e8285c7f1332 Author: Darren Tucker Date: Sat Jan 18 00:03:57 2014 +1100 - (dtucker) [readconf.c] Wrap paths.h inside an ifdef. Allows building on Solaris. commit 9edcbff46ff01c8d5dee9c1aa843f09e9ad8a80e Author: Darren Tucker Date: Fri Jan 17 21:54:32 2014 +1100 - (dtucker) [configure.ac] Have --without-toolchain-hardening not turn off stack-protector since that has a separate flag that's been around a while. commit 6d725687c490d4ba957a1bbc0ba0a2956c09fa69 Author: Darren Tucker Date: Fri Jan 17 19:17:34 2014 +1100 - (dtucker) [configure.ac] Also look in inttypes.h for uintXX_t types. commit 5055699c7f7c7ef21703a443ec73117da392f6ae Author: Darren Tucker Date: Fri Jan 17 18:48:22 2014 +1100 - (dtucker) [openbsd-compat/bsd-statvfs.h] Only start including headers if we need them to cut down on the name collisions. commit a5cf1e220def07290260e4125e74f41ac75cf88d Author: Darren Tucker Date: Fri Jan 17 18:10:58 2014 +1100 - (dtucker) [configure.ac openbsd-compat/bsd-statvfs.c openbsd-compat/bsd-statvfs.h] Implement enough of statvfs on top of statfs to be useful (and for the regression tests to pass) on platforms that have statfs and fstatfs. ok djm@ commit 1357d71d7b6d269969520aaa3e84d312ec971d5b Author: Darren Tucker Date: Fri Jan 17 18:00:40 2014 +1100 - (dtucker) Fix typo in #ifndef. commit d23a91ffb289d3553a58b7a60cec39fba9f0f506 Author: Darren Tucker Date: Fri Jan 17 17:32:30 2014 +1100 - (dtucker) [configure.ac digest.c openbsd-compat/openssl-compat.c openbsd-compat/openssl-compat.h] Add compatibility layer for older openssl versions. ok djm@ commit 868ea1ea1c1bfdbee5dbad78f81999c5983ecf31 Author: Damien Miller Date: Fri Jan 17 16:47:04 2014 +1100 - (djm) [Makefile.in configure.ac sandbox-capsicum.c sandbox-darwin.c] [sandbox-null.c sandbox-rlimit.c sandbox-seccomp-filter.c] [sandbox-systrace.c ssh-sandbox.h sshd.c] Support preauth sandboxing using the Capsicum API introduced in FreeBSD 10. Patch by Dag-Erling Smorgrav, updated by Loganaden Velvindron @ AfriNIC; ok dtucker@ commit a9d186a8b50d18869a10e9203abf71c83ddb1f79 Author: Darren Tucker Date: Fri Jan 17 16:30:49 2014 +1100 - dtucker@cvs.openbsd.org 2014/01/17 05:26:41 [digest.c] remove unused includes. ok djm@ commit 5f1c57a7a7eb39c0e4fee3367712337dbcaef024 Author: Darren Tucker Date: Fri Jan 17 16:29:45 2014 +1100 - djm@cvs.openbsd.org 2014/01/17 00:21:06 [sftp-client.c] signed/unsigned comparison warning fix; from portable (Id sync only) commit c548722361d89fb12c108528f96b306a26477b18 Author: Darren Tucker Date: Fri Jan 17 15:12:16 2014 +1100 - (dtucker) [configure.ac] Split AC_CHECK_FUNCS for OpenSSL functions into separate lines and alphabetize for easier diffing of changes. commit acad351a5b1c37de9130c9c1710445cc45a7f6b9 Author: Darren Tucker Date: Fri Jan 17 14:20:05 2014 +1100 - (dtucker) [defines.h] Add typedefs for uintXX_t types for platforms that don't have them. commit c3ed065ce8417aaa46490836648c173a5010f226 Author: Darren Tucker Date: Fri Jan 17 14:18:45 2014 +1100 - (dtucker) [openbsd-compat/bcrypt_pbkdf.c] Wrap stdlib.h include inside #ifdef HAVE_STDINT_H. commit f45f78ae437062c7d9506c5f475b7215f486be44 Author: Darren Tucker Date: Fri Jan 17 12:43:43 2014 +1100 - (dtucker) [blocks.c fe25519.c ge25519.c hash.c sc25519.c verify.c] Include includes.h to pull in all of the compatibility stuff. commit 99df369d0340caac145d57f700d830147ff18b87 Author: Darren Tucker Date: Fri Jan 17 12:42:17 2014 +1100 - (dtucker) [poly1305.c] Wrap stdlib.h include inside #ifdef HAVE_STDINT_H. commit ac413b62ea1957e80c711acbe0c11b908273fc01 Author: Darren Tucker Date: Fri Jan 17 12:31:33 2014 +1100 - (dtucker) [crypto_api.h] Wrap stdlib.h include inside #ifdef HAVE_STDINT_H. commit 1c4a011e9c939e74815346a560843e1862c300b8 Author: Darren Tucker Date: Fri Jan 17 12:23:23 2014 +1100 - (dtucker) [loginrec.c] Cast to the types specfied in the format specification to prevent warnings. commit c3d483f9a8275be1113535a1e0d0e384f605f3c4 Author: Damien Miller Date: Fri Jan 17 11:20:26 2014 +1100 - (djm) [sftp-client.c] signed/unsigned comparison fix commit fd994379dd972417d0491767f7cd9b5bf23f4975 Author: Darren Tucker Date: Fri Jan 17 09:53:24 2014 +1100 - (dtucker) [aclocal.m4 configure.ac] Add some additional compiler/toolchain hardening flags including -fstack-protector-strong. These default to on if the toolchain supports them, but there is a configure-time knob (--without-hardening) to disable them if necessary. ok djm@ commit 366224d21768ee8ec28cfbcc5fbade1b32582d58 Author: Damien Miller Date: Thu Jan 16 18:51:44 2014 +1100 - (djm) [README] update release notes URL. commit 2ae77e64f8fa82cbf25c9755e8e847709b978b40 Author: Damien Miller Date: Thu Jan 16 18:51:07 2014 +1100 - (djm) [contrib/caldera/openssh.spec contrib/redhat/openssh.spec] [contrib/suse/openssh.spec] Crank RPM spec version numbers. commit 0fa29e6d777c73a1b4ddd3b996b06ee20022ae8a Author: Damien Miller Date: Thu Jan 16 18:42:31 2014 +1100 - djm@cvs.openbsd.org 2014/01/16 07:32:00 [version.h] openssh-6.5 commit 52c371cd6d2598cc73d4e633811b3012119c47e2 Author: Damien Miller Date: Thu Jan 16 18:42:10 2014 +1100 - djm@cvs.openbsd.org 2014/01/16 07:31:09 [sftp-client.c] needless and incorrect cast to size_t can break resumption of large download; patch from tobias@ - -commit 91b580e4bec55118bf96ab3cdbe5a50839e75d0a -Author: Damien Miller -Date: Sun Jan 12 19:21:22 2014 +1100 - - - djm@cvs.openbsd.org 2014/01/12 08:13:13 - [bufaux.c buffer.h kex.c kex.h kexc25519.c kexc25519c.c kexc25519s.c] - [kexdhc.c kexdhs.c kexecdhc.c kexecdhs.c kexgexc.c kexgexs.c] - avoid use of OpenSSL BIGNUM type and functions for KEX with - Curve25519 by adding a buffer_put_bignum2_from_string() that stores - a string using the bignum encoding rules. Will make it easier to - build a reduced-feature OpenSSH without OpenSSL in the future; - ok markus@ - -commit af5d4481f4c7c8c3c746e68b961bb85ef907800e -Author: Damien Miller -Date: Sun Jan 12 19:20:47 2014 +1100 - - - djm@cvs.openbsd.org 2014/01/10 05:59:19 - [sshd_config] - the /etc/ssh/ssh_host_ed25519_key is loaded by default too - -commit 58cd63bc63038acddfb4051ed14e11179d8f4941 -Author: Damien Miller -Date: Fri Jan 10 10:59:24 2014 +1100 - - - djm@cvs.openbsd.org 2014/01/09 23:26:48 - [sshconnect.c sshd.c] - ban clients/servers that suffer from SSH_BUG_DERIVEKEY, they are ancient, - deranged and might make some attacks on KEX easier; ok markus@ - -commit b3051d01e505c9c2dc00faab472a0d06fa6b0e65 -Author: Damien Miller -Date: Fri Jan 10 10:58:53 2014 +1100 - - - djm@cvs.openbsd.org 2014/01/09 23:20:00 - [digest.c digest.h hostfile.c kex.c kex.h kexc25519.c kexc25519c.c] - [kexc25519s.c kexdh.c kexecdh.c kexecdhc.c kexecdhs.c kexgex.c kexgexc.c] - [kexgexs.c key.c key.h roaming_client.c roaming_common.c schnorr.c] - [schnorr.h ssh-dss.c ssh-ecdsa.c ssh-rsa.c sshconnect2.c] - Introduce digest API and use it to perform all hashing operations - rather than calling OpenSSL EVP_Digest* directly. Will make it easier - to build a reduced-feature OpenSSH without OpenSSL in future; - feedback, ok markus@ - -commit e00e413dd16eb747fb2c15a099971d91c13cf70f -Author: Damien Miller -Date: Fri Jan 10 10:40:45 2014 +1100 - - - guenther@cvs.openbsd.org 2014/01/09 03:26:00 - [sftp-common.c] - When formating the time for "ls -l"-style output, show dates in the future - with the year, and rearrange a comparison to avoid a potentional signed - arithmetic overflow that would give the wrong result. - - ok djm@ - -commit 3e49853650448883685cfa32fa382d0ba6d51d48 -Author: Damien Miller -Date: Fri Jan 10 10:37:05 2014 +1100 - - - tedu@cvs.openbsd.org 2014/01/04 17:50:55 - [mac.c monitor_mm.c monitor_mm.h xmalloc.c] - use standard types and formats for size_t like variables. ok dtucker - -commit a9c1e500ef609795cbc662848edb1a1dca279c81 -Author: Damien Miller -Date: Wed Jan 8 16:13:12 2014 +1100 - - - (djm) [regress/.cvsignore] Ignore regress test droppings; ok dtucker@ - -commit 324541e5264e1489ca0babfaf2b39612eb80dfb3 -Author: Damien Miller -Date: Tue Dec 31 12:25:40 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/30 23:52:28 - [auth2-hostbased.c auth2-pubkey.c compat.c compat.h ssh-rsa.c] - [sshconnect.c sshconnect2.c sshd.c] - refuse RSA keys from old proprietary clients/servers that use the - obsolete RSA+MD5 signature scheme. it will still be possible to connect - with these clients/servers but only DSA keys will be accepted, and we'll - deprecate them entirely in a future release. ok markus@ - -commit 9f4c8e797ea002a883307ca906f1f1f815010e78 -Author: Damien Miller -Date: Sun Dec 29 17:57:46 2013 +1100 - - - (djm) [regress/Makefile] Add some generated files for cleaning - -commit 106bf1ca3c7a5fdc34f9fd7a1fe651ca53085bc5 -Author: Damien Miller -Date: Sun Dec 29 17:54:03 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/29 05:57:02 - [sshconnect.c] - when showing other hostkeys, don't forget Ed25519 keys - -commit 0fa47cfb32c239117632cab41e4db7d3e6de5e91 -Author: Damien Miller -Date: Sun Dec 29 17:53:39 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/29 05:42:16 - [ssh.c] - don't forget to load Ed25519 certs too - -commit b9a95490daa04cc307589897f95bfaff324ad2c9 -Author: Damien Miller -Date: Sun Dec 29 17:50:15 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/29 04:35:50 - [authfile.c] - don't refuse to load Ed25519 certificates - -commit f72cdde6e6fabc51d2a62f4e75b8b926d9d7ee89 -Author: Damien Miller -Date: Sun Dec 29 17:49:55 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/29 04:29:25 - [authfd.c] - allow deletion of ed25519 keys from the agent - -commit 29ace1cb68cc378a464c72c0fd67aa5f9acd6b5b -Author: Damien Miller -Date: Sun Dec 29 17:49:31 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/29 04:20:04 - [key.c] - to make sure we don't omit any key types as valid CA keys again, - factor the valid key type check into a key_type_is_valid_ca() - function - -commit 9de4fcdc5a9cff48d49a3e2f6194d3fb2d7ae34d -Author: Damien Miller -Date: Sun Dec 29 17:49:13 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/29 02:49:52 - [key.c] - correct comment for key_drop_cert() - -commit 5baeacf8a80f054af40731c6f92435f9164b8e02 -Author: Damien Miller -Date: Sun Dec 29 17:48:55 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/29 02:37:04 - [key.c] - correct comment for key_to_certified() - -commit 83f2fe26cb19330712c952eddbd3c0b621674adc -Author: Damien Miller -Date: Sun Dec 29 17:48:38 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/29 02:28:10 - [key.c] - allow ed25519 keys to appear as certificate authorities - -commit 06122e9a74bb488b0fe0a8f64e1135de870f9cc0 -Author: Damien Miller -Date: Sun Dec 29 17:48:15 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/27 22:37:18 - [ssh-rsa.c] - correct comment - -commit 3e19295c3a253c8dc8660cf45baad7f45fccb969 -Author: Damien Miller -Date: Sun Dec 29 17:47:50 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/27 22:30:17 - [ssh-dss.c ssh-ecdsa.c ssh-rsa.c] - make the original RSA and DSA signing/verification code look more like - the ECDSA/Ed25519 ones: use key_type_plain() when checking the key type - rather than tediously listing all variants, use __func__ for debug/ - error messages - -commit 137977180be6254639e2c90245763e6965f8d815 -Author: Damien Miller -Date: Sun Dec 29 17:47:14 2013 +1100 - - - tedu@cvs.openbsd.org 2013/12/21 07:10:47 - [ssh-keygen.1] - small typo - -commit 339a48fe7ffb3186d22bbaa9efbbc3a053e602fd -Author: Damien Miller -Date: Sun Dec 29 17:46:49 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/19 22:57:13 - [poly1305.c poly1305.h] - use full name for author, with his permission - -commit 0b36c83148976c7c8268f4f41497359e2fb26251 -Author: Damien Miller -Date: Sun Dec 29 17:45:51 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/19 01:19:41 - [ssh-agent.c] - bz#2186: don't crash (NULL deref) when deleting PKCS#11 keys from an agent - that has a mix of normal and PKCS#11 keys; fix from jay AT slushpupie.com; - ok dtucker - -commit 4def184e9b6c36be6d965a9705632fc4c0c2a8af -Author: Damien Miller -Date: Sun Dec 29 17:45:26 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/19 01:04:36 - [channels.c] - bz#2147: fix multiple remote forwardings with dynamically assigned - listen ports. In the s->c message to open the channel we were sending - zero (the magic number to request a dynamic port) instead of the actual - listen port. The client therefore had no way of discriminating between - them. - - Diagnosis and fix by ronf AT timeheart.net - -commit bf25d114e23a803f8feca8926281b1aaedb6191b -Author: Damien Miller -Date: Sun Dec 29 17:44:56 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/19 00:27:57 - [auth-options.c] - simplify freeing of source-address certificate restriction - -commit bb3dafe7024a5b4e851252e65ee35d45b965e4a8 -Author: Damien Miller -Date: Sun Dec 29 17:44:29 2013 +1100 - - - dtucker@cvs.openbsd.org 2013/12/19 00:19:12 - [serverloop.c] - Cast client_alive_interval to u_int64_t before assinging to - max_time_milliseconds to avoid potential integer overflow in the timeout. - bz#2170, patch from Loganaden Velvindron, ok djm@ - -commit ef275ead3dcadde4db1efe7a0aa02b5e618ed40c -Author: Damien Miller -Date: Sun Dec 29 17:44:07 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/19 00:10:30 - [ssh-add.c] - skip requesting smartcard PIN when removing keys from agent; bz#2187 - patch from jay AT slushpupie.com; ok dtucker - -commit 7d97fd9a1cae778c3eacf16e09f5da3689d616c6 -Author: Damien Miller -Date: Sun Dec 29 17:40:18 2013 +1100 - - - (djm) [loginrec.c] Check for username truncation when looking up lastlog - entries - -commit 77244afe3b6d013b485e0952eaab89b9db83380f -Author: Darren Tucker -Date: Sat Dec 21 17:02:39 2013 +1100 - - 20131221 - - (dtucker) [regress/keytype.sh] Actually test ecdsa key types. - -commit 53f8e784dc431a82d31c9b0e95b144507f9330e9 -Author: Darren Tucker -Date: Thu Dec 19 11:31:44 2013 +1100 - - - (dtucker) [auth-pam.c] bz#2163: check return value from pam_get_item(). - Patch from Loganaden Velvindron. - -commit 1fcec9d4f265e38af248c4c845986ca8c174bd68 -Author: Darren Tucker -Date: Thu Dec 19 11:00:12 2013 +1100 - - - (dtucker) [configure.ac] bz#2178: Don't try to use BSM on Solaris versions - greater than 11 either rather than just 11. Patch from Tomas Kuthan. - -commit 6674eb9683afd1ea4eb35670b5e66815543a759e -Author: Damien Miller -Date: Wed Dec 18 17:50:39 2013 +1100 - - - markus@cvs.openbsd.org 2013/12/17 10:36:38 - [crypto_api.h] - I've assempled the header file by cut&pasting from generated headers - and the source files. - -commit d58a5964426ee014384d67d775d16712e93057f3 -Author: Damien Miller -Date: Wed Dec 18 17:50:13 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/15 21:42:35 - [cipher-chachapoly.c] - add some comments and constify a constant - -commit 059321d19af24d87420de3193f79dfab23556078 -Author: Damien Miller -Date: Wed Dec 18 17:49:48 2013 +1100 - - - pascal@cvs.openbsd.org 2013/12/15 18:17:26 - [ssh-add.c] - Make ssh-add also add .ssh/id_ed25519; fixes lie in manual page. - ok markus@ - -commit 155b5a5bf158767f989215479ded2a57f331e1c6 -Author: Damien Miller -Date: Wed Dec 18 17:48:32 2013 +1100 - - - markus@cvs.openbsd.org 2013/12/09 11:08:17 - [crypto_api.h] - remove unused defines - -commit 8a56dc2b6b48b05590810e7f4c3567508410000c -Author: Damien Miller -Date: Wed Dec 18 17:48:11 2013 +1100 - - - markus@cvs.openbsd.org 2013/12/09 11:03:45 - [blocks.c ed25519.c fe25519.c fe25519.h ge25519.c ge25519.h] - [ge25519_base.data hash.c sc25519.c sc25519.h verify.c] - Add Authors for the public domain ed25519/nacl code. - see also http://nacl.cr.yp.to/features.html - All of the NaCl software is in the public domain. - and http://ed25519.cr.yp.to/software.html - The Ed25519 software is in the public domain. - -commit 6575c3acf31fca117352f31f37b16ae46e664837 -Author: Damien Miller -Date: Wed Dec 18 17:47:02 2013 +1100 - - - dtucker@cvs.openbsd.org 2013/12/08 09:53:27 - [sshd_config.5] - Use a literal for the default value of KEXAlgorithms. ok deraadt jmc - -commit 8ba0ead6985ea14999265136b14ffd5aeec516f9 -Author: Damien Miller -Date: Wed Dec 18 17:46:27 2013 +1100 - - - naddy@cvs.openbsd.org 2013/12/07 11:58:46 - [ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh-keysign.8 ssh.1] - [ssh_config.5 sshd.8 sshd_config.5] - add missing mentions of ed25519; ok djm@ - -commit 4f752cf71cf44bf4bc777541156c2bf56daf9ce9 -Author: Damien Miller -Date: Wed Dec 18 17:45:35 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/07 08:08:26 - [ssh-keygen.1] - document -a and -o wrt new key format - -commit 6d6fcd14e23a9053198342bb379815b15e504084 -Author: Damien Miller -Date: Sun Dec 8 15:53:28 2013 +1100 - - - (djm) [Makefile.in regress/Makefile regress/agent-ptrace.sh] - [regress/setuid-allowed.c] Check that ssh-agent is not on a no-setuid - filesystem before running agent-ptrace.sh; ok dtucker - -commit 7e6e42fb532c7dafd7078ef5e9e2d3e47fcf6752 -Author: Damien Miller -Date: Sun Dec 8 08:23:08 2013 +1100 - - - (djm) [openbsd-compat/bsd-setres_id.c] Missing header; from Corinna - Vinschen - -commit da3ca351b49d52ae85db2e3998265dc3c6617068 -Author: Damien Miller -Date: Sat Dec 7 21:43:46 2013 +1100 - - - (djm) [Makefile.in] PATHSUBS and keygen bits for Ed25519; from - Loganaden Velvindron @ AfriNIC in bz#2179 - -commit eb401585bb8336cbf81fe4fc58eb9f7cac3ab874 -Author: Damien Miller -Date: Sat Dec 7 17:07:15 2013 +1100 - - - (djm) [regress/cert-hostkey.sh] Fix merge botch - -commit f54542af3ad07532188b10136ae302314ec69ed6 -Author: Damien Miller -Date: Sat Dec 7 16:32:44 2013 +1100 - - - markus@cvs.openbsd.org 2013/12/06 13:52:46 - [regress/Makefile regress/agent.sh regress/cert-hostkey.sh] - [regress/cert-userkey.sh regress/keytype.sh] - test ed25519 support; from djm@ - -commit f104da263de995f66b6861b4f3368264ee483d7f -Author: Damien Miller -Date: Sat Dec 7 12:37:53 2013 +1100 - - - (djm) [ed25519.c ssh-ed25519.c openbsd-compat/Makefile.in] - [openbsd-compat/bcrypt_pbkdf.c] Make ed25519/new key format compile on - Linux - -commit 1ff130dac9b7aea0628f4ad30683431fe35e0020 -Author: Damien Miller -Date: Sat Dec 7 11:51:51 2013 +1100 - - - [configure.ac openbsd-compat/Makefile.in openbsd-compat/bcrypt_pbkdf.c] - [openbsd-compat/blf.h openbsd-compat/blowfish.c] - [openbsd-compat/openbsd-compat.h] Start at supporting bcrypt_pbkdf in - portable. - -commit 4260828a2958ebe8c96f66d8301dac53f4cde556 -Author: Damien Miller -Date: Sat Dec 7 11:38:03 2013 +1100 - - - [authfile.c] Conditionalise inclusion of util.h - -commit a913442bac8a26fd296a3add51293f8f6f9b3b4c -Author: Damien Miller -Date: Sat Dec 7 11:35:36 2013 +1100 - - - [Makefile.in] Add ed25519 sources - -commit ca570a519cb846da61d002c7f46fa92e39c83e45 -Author: Damien Miller -Date: Sat Dec 7 11:29:09 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/07 00:19:15 - [key.c] - set k->cert = NULL after freeing it - -commit 3cccc0e155229a2f2d86b6df40bd4559b4f960ff -Author: Damien Miller -Date: Sat Dec 7 11:27:47 2013 +1100 - - - [blocks.c ed25519.c fe25519.c fe25519.h ge25519.c ge25519.h] - [ge25519_base.data hash.c sc25519.c sc25519.h verify.c] Fix RCS idents - -commit a7827c11b3f0380b7e593664bd62013ff9c131db -Author: Damien Miller -Date: Sat Dec 7 11:24:30 2013 +1100 - - - jmc@cvs.openbsd.org 2013/12/06 15:29:07 - [sshd.8] - missing comma; - -commit 5be9d9e3cbd9c66f24745d25bf2e809c1d158ee0 -Author: Damien Miller -Date: Sat Dec 7 11:24:01 2013 +1100 - - - markus@cvs.openbsd.org 2013/12/06 13:39:49 - [authfd.c authfile.c key.c key.h myproposal.h pathnames.h readconf.c] - [servconf.c ssh-agent.c ssh-keygen.c ssh-keyscan.1 ssh-keyscan.c] - [ssh-keysign.c ssh.c ssh_config.5 sshd.8 sshd.c verify.c ssh-ed25519.c] - [sc25519.h sc25519.c hash.c ge25519_base.data ge25519.h ge25519.c] - [fe25519.h fe25519.c ed25519.c crypto_api.h blocks.c] - support ed25519 keys (hostkeys and user identities) using the public - domain ed25519 reference code from SUPERCOP, see - http://ed25519.cr.yp.to/software.html - feedback, help & ok djm@ - -commit bcd00abd8451f36142ae2ee10cc657202149201e -Author: Damien Miller -Date: Sat Dec 7 10:41:55 2013 +1100 - - - markus@cvs.openbsd.org 2013/12/06 13:34:54 - [authfile.c authfile.h cipher.c cipher.h key.c packet.c ssh-agent.c] - [ssh-keygen.c PROTOCOL.key] new private key format, bcrypt as KDF by - default; details in PROTOCOL.key; feedback and lots help from djm; - ok djm@ - -commit f0e9060d236c0e38bec2fa1c6579fb0a2ea6458d -Author: Damien Miller -Date: Sat Dec 7 10:40:26 2013 +1100 - - - markus@cvs.openbsd.org 2013/12/06 13:30:08 - [authfd.c key.c key.h ssh-agent.c] - move private key (de)serialization to key.c; ok djm - -commit 0f8536da23a6ef26e6495177c0d8a4242b710289 -Author: Damien Miller -Date: Sat Dec 7 10:31:37 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/06 03:40:51 - [ssh-keygen.c] - remove duplicated character ('g') in getopt() string; - document the (few) remaining option characters so we don't have to - rummage next time. - -commit 393920745fd328d3fe07f739a3cf7e1e6db45b60 -Author: Damien Miller -Date: Sat Dec 7 10:31:08 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/05 22:59:45 - [sftp-client.c] - fix memory leak in error path in do_readdir(); pointed out by - Loganaden Velvindron @ AfriNIC in bz#2163 - -commit 534b2ccadea5e5e9a8b27226e6faac3ed5552e97 -Author: Damien Miller -Date: Thu Dec 5 14:07:27 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/05 01:16:41 - [servconf.c servconf.h] - bz#2161 - fix AuthorizedKeysCommand inside a Match block and - rearrange things so the same error is harder to make next time; - with and ok dtucker@ - -commit 8369c8e61a3408ec6bb75755fad4ffce29b5fdbe -Author: Darren Tucker -Date: Thu Dec 5 11:00:16 2013 +1100 - - - (dtucker) [configure.ac] bz#2173: use pkg-config --libs to include correct - -L location for libedit. Patch from Serge van den Boom. - -commit 9275df3e0a2a3bc3897f7d664ea86a425c8a092d -Author: Damien Miller -Date: Thu Dec 5 10:26:32 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/04 04:20:01 - [sftp-client.c] - bz#2171: don't leak local_fd on error; from Loganaden Velvindron @ - AfriNIC - -commit 960f6a2b5254e4da082d8aa3700302ed12dc769a -Author: Damien Miller -Date: Thu Dec 5 10:26:14 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/02 03:13:14 - [cipher.c] - correct bzero of chacha20+poly1305 key context. bz#2177 from - Loganaden Velvindron @ AfriNIC - - Also make it a memset for consistency with the rest of cipher.c - -commit f7e8a8796d661c9d6692ab837e1effd4f5ada1c2 -Author: Damien Miller -Date: Thu Dec 5 10:25:51 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/02 03:09:22 - [key.c] - make key_to_blob() return a NULL blob on failure; part of - bz#2175 from Loganaden Velvindron @ AfriNIC - -commit f1e44ea9d9a6d4c1a95a0024132e603bd1778c9c -Author: Damien Miller -Date: Thu Dec 5 10:23:21 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/02 02:56:17 - [ssh-pkcs11-helper.c] - use-after-free; bz#2175 patch from Loganaden Velvindron @ AfriNIC - -commit 114e540b15d57618f9ebf624264298f80bbd8c77 -Author: Damien Miller -Date: Thu Dec 5 10:22:57 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/02 02:50:27 - [PROTOCOL.chacha20poly1305] - typo; from Jon Cave - -commit e4870c090629e32f2cb649dc16d575eeb693f4a8 -Author: Damien Miller -Date: Thu Dec 5 10:22:39 2013 +1100 - - - djm@cvs.openbsd.org 2013/12/01 23:19:05 - [PROTOCOL] - mention curve25519-sha256@libssh.org key exchange algorithm - -commit 1d2f8804a6d33a4e908b876b2e1266b8260ec76b -Author: Damien Miller -Date: Thu Dec 5 10:22:03 2013 +1100 - - - deraadt@cvs.openbsd.org 2013/11/26 19:15:09 - [pkcs11.h] - cleanup 1 << 31 idioms. Resurrection of this issue pointed out by - Eitan Adler ok markus for ssh, implies same change in kerberosV - -commit bdb352a54f82df94a548e3874b22f2d6ae90328d -Author: Damien Miller -Date: Thu Dec 5 10:20:52 2013 +1100 - - - jmc@cvs.openbsd.org 2013/11/26 12:14:54 - [ssh.1 ssh.c] - - put -Q in the right place - - Ar was a poor choice for the arguments to -Q. i've chosen an - admittedly equally poor Cm, at least consistent with the rest - of the docs. also no need for multiple instances - - zap a now redundant Nm - - usage() sync - -commit d937dc084a087090f1cf5395822c3ac958d33759 -Author: Damien Miller -Date: Thu Dec 5 10:19:54 2013 +1100 - - - deraadt@cvs.openbsd.org 2013/11/25 18:04:21 - [ssh.1 ssh.c] - improve -Q usage and such. One usage change is that the option is now - case-sensitive - ok dtucker markus djm - -commit dec0393f7ee8aabc7d9d0fc2c5fddb4bc649112e -Author: Damien Miller -Date: Thu Dec 5 10:18:43 2013 +1100 - - - jmc@cvs.openbsd.org 2013/11/21 08:05:09 - [ssh_config.5 sshd_config.5] - no need for .Pp before displays; - -commit 8a073cf57940aabf85e49799f89f5d5e9b072c1b -Author: Damien Miller -Date: Thu Nov 21 14:26:18 2013 +1100 - - - djm@cvs.openbsd.org 2013/11/21 03:18:51 - [regress/cipher-speed.sh regress/integrity.sh regress/rekey.sh] - [regress/try-ciphers.sh] - use new "ssh -Q cipher-auth" query to obtain lists of authenticated - encryption ciphers instead of specifying them manually; ensures that - the new chacha20poly1305@openssh.com mode is tested; - - ok markus@ and naddy@ as part of the diff to add - chacha20poly1305@openssh.com - -commit ea61b2179f63d48968dd2c9617621002bb658bfe -Author: Damien Miller -Date: Thu Nov 21 14:25:15 2013 +1100 - - - djm@cvs.openbsd.org 2013/11/21 03:16:47 - [regress/modpipe.c] - use unsigned long long instead of u_int64_t here to avoid warnings - on some systems portable OpenSSH is built on. - -commit 36aba25b0409d2db6afc84d54bc47a2532d38424 -Author: Damien Miller -Date: Thu Nov 21 14:24:42 2013 +1100 - - - djm@cvs.openbsd.org 2013/11/21 03:15:46 - [regress/krl.sh] - add some reminders for additional tests that I'd like to implement - -commit fa7a20bc289f09b334808d988746bc260a2f60c9 -Author: Damien Miller -Date: Thu Nov 21 14:24:08 2013 +1100 - - - naddy@cvs.openbsd.org 2013/11/18 05:09:32 - [regress/forward-control.sh] - bump timeout to 10 seconds to allow slow machines (e.g. Alpha PC164) - to successfully run this; ok djm@ - (ID sync only; our timeouts are already longer) - -commit 0fde8acdad78a4d20cadae974376cc0165f645ee -Author: Damien Miller -Date: Thu Nov 21 14:12:23 2013 +1100 - - - djm@cvs.openbsd.org 2013/11/21 00:45:44 - [Makefile.in PROTOCOL PROTOCOL.chacha20poly1305 authfile.c chacha.c] - [chacha.h cipher-chachapoly.c cipher-chachapoly.h cipher.c cipher.h] - [dh.c myproposal.h packet.c poly1305.c poly1305.h servconf.c ssh.1] - [ssh.c ssh_config.5 sshd_config.5] Add a new protocol 2 transport - cipher "chacha20-poly1305@openssh.com" that combines Daniel - Bernstein's ChaCha20 stream cipher and Poly1305 MAC to build an - authenticated encryption mode. - - Inspired by and similar to Adam Langley's proposal for TLS: - http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03 - but differs in layout used for the MAC calculation and the use of a - second ChaCha20 instance to separately encrypt packet lengths. - Details are in the PROTOCOL.chacha20poly1305 file. - - Feedback markus@, naddy@; manpage bits Loganden Velvindron @ AfriNIC - ok markus@ naddy@ - -commit fdb2306acdc3eb2bc46b6dfdaaf6005c650af22a -Author: Damien Miller -Date: Thu Nov 21 13:57:15 2013 +1100 - - - deraadt@cvs.openbsd.org 2013/11/20 20:54:10 - [canohost.c clientloop.c match.c readconf.c sftp.c] - unsigned casts for ctype macros where neccessary - ok guenther millert markus - -commit e00167307e4d3692695441e9bd712f25950cb894 -Author: Damien Miller -Date: Thu Nov 21 13:56:49 2013 +1100 - - - deraadt@cvs.openbsd.org 2013/11/20 20:53:10 - [scp.c] - unsigned casts for ctype macros where neccessary - ok guenther millert markus - -commit 23e00aa6ba9eee0e0c218f2026bf405ad4625832 -Author: Damien Miller -Date: Thu Nov 21 13:56:28 2013 +1100 - - - djm@cvs.openbsd.org 2013/11/20 02:19:01 - [sshd.c] - delay closure of in/out fds until after "Bad protocol version - identification..." message, as get_remote_ipaddr/get_remote_port - require them open. - -commit 867e6934be6521f87f04a5ab86702e2d1b314245 -Author: Damien Miller -Date: Thu Nov 21 13:56:06 2013 +1100 - - - markus@cvs.openbsd.org 2013/11/13 13:48:20 - [ssh-pkcs11.c] - add missing braces found by pedro - -commit 0600c7020f4fe68a780bd7cf21ff541a8d4b568a -Author: Damien Miller -Date: Thu Nov 21 13:55:43 2013 +1100 - - - dtucker@cvs.openbsd.org 2013/11/08 11:15:19 - [bufaux.c bufbn.c buffer.c sftp-client.c sftp-common.c sftp-glob.c] - [uidswap.c] Include stdlib.h for free() as per the man page. - -commit b6a75b0b93b8faa6f79c3a395ab6c71f3f880b80 -Author: Darren Tucker -Date: Sun Nov 10 20:25:22 2013 +1100 - - - (dtucker) [regress/keytype.sh] Populate ECDSA key types to be tested by - querying the ones that are compiled in. - -commit 2c89430119367eb1bc96ea5ee55de83357e4c926 -Author: Darren Tucker -Date: Sun Nov 10 12:38:42 2013 +1100 - - - (dtucker) [key.c] Check for the correct defines for NID_secp521r1. - -commit dd5264db5f641dbd03186f9e5e83e4b14b3d0003 -Author: Darren Tucker -Date: Sat Nov 9 22:32:51 2013 +1100 - - - (dtucker) [configure.ac] Add missing "test". - -commit 95cb2d4eb08117be061f3ff076adef3e9a5372c3 -Author: Darren Tucker -Date: Sat Nov 9 22:02:31 2013 +1100 - - - (dtucker) [configure.ac] Fix brackets in NID_secp521r1 test. - -commit 37bcef51b3d9d496caecea6394814d2f49a1357f -Author: Darren Tucker -Date: Sat Nov 9 18:39:25 2013 +1100 - - - (dtucker) [configure.ac kex.c key.c myproposal.h] Test for the presence of - NID_X9_62_prime256v1, NID_secp384r1 and NID_secp521r1 and test that the - latter actually works before using it. Fedora (at least) has NID_secp521r1 - that doesn't work (see https://bugzilla.redhat.com/show_bug.cgi?id=1021897). - -commit 6e2fe81f926d995bae4be4a6b5b3c88c1c525187 -Author: Darren Tucker -Date: Sat Nov 9 16:55:03 2013 +1100 - - - dtucker@cvs.openbsd.org 2013/11/09 05:41:34 - [regress/test-exec.sh regress/rekey.sh] - Use smaller test data files to speed up tests. Grow test datafiles - where necessary for a specific test. - -commit aff7ef1bb8b7c1eeb1f4812129091c5adbf51848 -Author: Darren Tucker -Date: Sat Nov 9 00:19:22 2013 +1100 - - - (dtucker) [contrib/cygwin/ssh-host-config] Simplify host key generation: - rather than testing and generating each key, call ssh-keygen -A. - Patch from vinschen at redhat.com. - -commit 882abfd3fb3c98cfe70b4fc79224770468b570a5 -Author: Darren Tucker -Date: Sat Nov 9 00:17:41 2013 +1100 - - - (dtucker) [Makefile.in configure.ac] Set MALLOC_OPTIONS per platform - and pass in TEST_ENV. Unknown options cause stderr to get polluted - and the stderr-data test to fail. - -commit 8c333ec23bdf7da917aa20ac6803a2cdd79182c5 -Author: Darren Tucker -Date: Fri Nov 8 21:12:58 2013 +1100 - - - (dtucker) [openbsd-compat/bsd-poll.c] Add headers to prevent compile - warnings. - -commit d94240b2f6b376b6e9de187e4a0cd4b89dfc48cb -Author: Darren Tucker -Date: Fri Nov 8 21:10:04 2013 +1100 - - - (dtucker) [myproposal.h] Conditionally enable CURVE25519_SHA256. - -commit 1c8ce34909886288a3932dce770deec5449f7bb5 -Author: Darren Tucker -Date: Fri Nov 8 19:50:32 2013 +1100 - - - (dtucker) [kex.c] Only enable CURVE25519_SHA256 if we actually have - EVP_sha256. - -commit ccdb9bec46bcc88549b26a94aa0bae2b9f51031c -Author: Darren Tucker -Date: Fri Nov 8 18:54:38 2013 +1100 - - - (dtucker) [openbsd-compat/openbsd-compat.h] Add null implementation of - arc4random_stir for platforms that have arc4random but don't have - arc4random_stir (right now this is only OpenBSD -current). - -commit 3420a50169b52cc8d2775d51316f9f866c73398f -Author: Damien Miller -Date: Fri Nov 8 16:48:13 2013 +1100 - - - (djm) [README contrib/caldera/openssh.spec contrib/redhat/openssh.spec] - [contrib/suse/openssh.spec] Update version numbers following release. - -commit 3ac4a234df842fd8c94d9cb0ad198e1fe84b895b -Author: Damien Miller -Date: Fri Nov 8 12:39:49 2013 +1100 - - - djm@cvs.openbsd.org 2013/11/08 01:38:11 - [version.h] - openssh-6.4 - -commit 6c81fee693038de7d4a5559043350391db2a2761 -Author: Damien Miller -Date: Fri Nov 8 12:19:55 2013 +1100 - - - djm@cvs.openbsd.org 2013/11/08 00:39:15 - [auth-options.c auth2-chall.c authfd.c channels.c cipher-3des1.c] - [clientloop.c gss-genr.c monitor_mm.c packet.c schnorr.c umac.c] - [sftp-client.c sftp-glob.c] - use calloc for all structure allocations; from markus@ - -commit 690d989008e18af3603a5e03f1276c9bad090370 -Author: Damien Miller -Date: Fri Nov 8 12:16:49 2013 +1100 - - - dtucker@cvs.openbsd.org 2013/11/07 11:58:27 - [cipher.c cipher.h kex.c kex.h mac.c mac.h servconf.c ssh.c] - Output the effective values of Ciphers, MACs and KexAlgorithms when - the default has not been overridden. ok markus@ - -commit 08998c5fb9c7c1d248caa73b76e02ca0482e6d85 -Author: Darren Tucker -Date: Fri Nov 8 12:11:46 2013 +1100 - - - dtucker@cvs.openbsd.org 2013/11/08 01:06:14 - [regress/rekey.sh] - Rekey less frequently during tests to speed them up - -commit 4bf7e50e533aa956366df7402c132f202e841a48 -Author: Darren Tucker -Date: Thu Nov 7 22:33:48 2013 +1100 - - - (dtucker) [Makefile.in configure.ac] Remove TEST_SSH_SHA256 environment - variable. It's no longer used now that we get the supported MACs from - ssh -Q. - -commit 6e9d6f411288374d1dee4b7debbfa90bc7e73035 -Author: Darren Tucker -Date: Thu Nov 7 15:32:37 2013 +1100 - - - dtucker@cvs.openbsd.org 2013/11/07 04:26:56 - [regress/kextype.sh] - trailing space - -commit 74cbc22529f3e5de756e1b7677b7624efb28f62c -Author: Darren Tucker -Date: Thu Nov 7 15:26:12 2013 +1100 - - - dtucker@cvs.openbsd.org 2013/11/07 03:55:41 - [regress/kextype.sh] - Use ssh -Q to get kex types instead of a static list. - -commit a955041c930e63405159ff7d25ef14272f36eab3 -Author: Darren Tucker -Date: Thu Nov 7 15:21:19 2013 +1100 - - - dtucker@cvs.openbsd.org 2013/11/07 02:48:38 - [regress/integrity.sh regress/cipher-speed.sh regress/try-ciphers.sh] - Use ssh -Q instead of hardcoding lists of ciphers or MACs. - -commit 06595d639577577bc15d359e037a31eb83563269 -Author: Darren Tucker -Date: Thu Nov 7 15:08:02 2013 +1100 - - - dtucker@cvs.openbsd.org 2013/11/07 01:12:51 - [regress/rekey.sh] - Factor out the data transfer rekey tests - -commit 651dc8b2592202dac6b16ee3b82ce5b331be7da3 -Author: Darren Tucker -Date: Thu Nov 7 15:04:44 2013 +1100 - - - dtucker@cvs.openbsd.org 2013/11/07 00:12:05 - [regress/rekey.sh] - Test rekeying for every Cipher, MAC and KEX, plus test every KEX with - the GCM ciphers. - -commit 234557762ba1096a867ca6ebdec07efebddb5153 -Author: Darren Tucker -Date: Thu Nov 7 15:00:51 2013 +1100 - - - dtucker@cvs.openbsd.org 2013/11/04 12:27:42 - [regress/rekey.sh] - Test rekeying with all KexAlgorithms. - -commit bbfb9b0f386aab0c3e19d11f136199ef1b9ad0ef -Author: Darren Tucker -Date: Thu Nov 7 14:56:43 2013 +1100 - - - markus@cvs.openbsd.org 2013/11/02 22:39:53 - [regress/kextype.sh] - add curve25519-sha256@libssh.org - -commit aa19548a98c0f89283ebd7354abd746ca6bc4fdf -Author: Darren Tucker -Date: Thu Nov 7 14:50:09 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/09 23:44:14 - [regress/Makefile] (ID sync only) - regression test for sftp request white/blacklisting and readonly mode. - -commit c8908aabff252f5da772d4e679479c2b7d18cac1 -Author: Damien Miller -Date: Thu Nov 7 13:38:35 2013 +1100 - - - djm@cvs.openbsd.org 2013/11/06 23:05:59 - [ssh-pkcs11.c] - from portable: s/true/true_val/ to avoid name collisions on dump platforms - RCSID sync only - -commit 49c145c5e89b9d7d48e84328d6347d5ad640b567 -Author: Damien Miller -Date: Thu Nov 7 13:35:39 2013 +1100 - - - markus@cvs.openbsd.org 2013/11/06 16:52:11 - [monitor_wrap.c] - fix rekeying for AES-GCM modes; ok deraadt - -commit 67a8800f290b39fd60e379988c700656ae3f2539 -Author: Damien Miller -Date: Thu Nov 7 13:32:51 2013 +1100 - - - markus@cvs.openbsd.org 2013/11/04 11:51:16 - [monitor.c] - fix rekeying for KEX_C25519_SHA256; noted by dtucker@ - RCSID sync only; I thought this was a merge botch and fixed it already - -commit df8b030b15fcec7baf38ec7944f309f9ca8cc9a7 -Author: Damien Miller -Date: Thu Nov 7 13:28:16 2013 +1100 - - - (djm) [configure.ac defines.h] Skip arc4random_stir() calls on platforms - that lack it but have arc4random_uniform() - -commit a6fd1d3c38a562709374a70fa76423859160aa90 -Author: Damien Miller -Date: Thu Nov 7 12:03:26 2013 +1100 - - - (djm) [regress/modpipe.c regress/rekey.sh] Never intended to commit these - -commit c98319750b0bbdd0d1794420ec97d65dd9244613 -Author: Damien Miller -Date: Thu Nov 7 12:00:23 2013 +1100 - - - (djm) [Makefile.in monitor.c] Missed chunks of curve25519 KEX diff - -commit 61c5c2319e84a58210810d39b062c8b8e3321160 -Author: Damien Miller -Date: Thu Nov 7 11:34:14 2013 +1100 - - - (djm) [ssh-pkcs11.c] Bring back "non-constant initialiser" fix (rev 1.5) - that got lost in recent merge. - -commit 094003f5454a9f5a607674b2739824a7e91835f4 -Author: Damien Miller -Date: Mon Nov 4 22:59:27 2013 +1100 - - - (djm) [kexc25519.c kexc25519c.c kexc25519s.c] Import missed files from - KEX/curve25519 change - -commit ca67a7eaf8766499ba67801d0be8cdaa550b9a50 -Author: Damien Miller -Date: Mon Nov 4 09:05:17 2013 +1100 - - - djm@cvs.openbsd.org 2013/11/03 10:37:19 - [roaming_common.c] - fix a couple of function definitions foo() -> foo(void) - (-Wold-style-definition) - -commit 0bd8f1519d51af8d4229be81e8f2f4903a1d440b -Author: Damien Miller -Date: Mon Nov 4 08:55:43 2013 +1100 - - - markus@cvs.openbsd.org 2013/11/02 22:39:19 - [ssh_config.5 sshd_config.5] - the default kex is now curve25519-sha256@libssh.org - -commit 4c3ba0767fbe4a8a2a748df4035aaf86651f6b30 -Author: Damien Miller -Date: Mon Nov 4 08:40:13 2013 +1100 - - - markus@cvs.openbsd.org 2013/11/02 22:34:01 - [auth-options.c] - no need to include monitor_wrap.h and ssh-gss.h - -commit 660621b2106b987b874c2f120218bec249d0f6ba -Author: Damien Miller -Date: Mon Nov 4 08:37:51 2013 +1100 - - - markus@cvs.openbsd.org 2013/11/02 22:24:24 - [kexdhs.c kexecdhs.c] - no need to include ssh-gss.h - -commit abdca986decfbbc008c895195b85e879ed460ada -Author: Damien Miller -Date: Mon Nov 4 08:30:05 2013 +1100 - - - markus@cvs.openbsd.org 2013/11/02 22:10:15 - [kexdhs.c kexecdhs.c] - no need to include monitor_wrap.h - -commit 1e1242604eb0fd510fe93f81245c529237ffc513 -Author: Damien Miller -Date: Mon Nov 4 08:26:52 2013 +1100 - - - markus@cvs.openbsd.org 2013/11/02 21:59:15 - [kex.c kex.h myproposal.h ssh-keyscan.c sshconnect2.c sshd.c] - use curve25519 for default key exchange (curve25519-sha256@libssh.org); - initial patch from Aris Adamantiadis; ok djm@ - -commit d2252c79191d069372ed6effce7c7a2de93448cd -Author: Damien Miller -Date: Mon Nov 4 07:41:48 2013 +1100 - - - markus@cvs.openbsd.org 2013/11/02 20:03:54 - [ssh-pkcs11.c] - support pkcs#11 tokes that only provide x509 zerts instead of raw pubkeys; - fixes bz#1908; based on patch from Laurent Barbe; ok djm - -commit 007e3b357e880caa974d5adf9669298ba0751c78 -Author: Darren Tucker -Date: Sun Nov 3 18:43:55 2013 +1100 - - - (dtucker) [configure.ac defines.h] Add typedefs for intmax_t and uintmax_t - for platforms that don't have them. - -commit 710f3747352fb93a63e5b69b12379da37f5b3fa9 -Author: Darren Tucker -Date: Sun Nov 3 17:20:34 2013 +1100 - - - (dtucker) [openbsd-compat/setproctitle.c] Handle error case form the 2nd - vsnprintf. From eric at openbsd via chl@. - -commit d52770452308e5c2e99f4da6edaaa77ef078b610 -Author: Darren Tucker -Date: Sun Nov 3 16:30:46 2013 +1100 - - - (dtucker) [openbsd-compat/bsd-misc.c] Include time.h for nanosleep. - From OpenSMTPD where it prevents "implicit declaration" warnings (it's - a no-op in OpenSSH). From chl at openbsd. - -commit 63857c9340d3482746a5622ffdacc756751f6448 -Author: Damien Miller -Date: Wed Oct 30 22:31:06 2013 +1100 - - - jmc@cvs.openbsd.org 2013/10/29 18:49:32 - [sshd_config.5] - pty(4), not pty(7); - -commit 5ff30c6b68adeee767dd29bf2369763c6a13c0b3 -Author: Damien Miller -Date: Wed Oct 30 22:21:50 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/29 09:48:02 - [servconf.c servconf.h session.c sshd_config sshd_config.5] - shd_config PermitTTY to disallow TTY allocation, mirroring the - longstanding no-pty authorized_keys option; - bz#2070, patch from Teran McKinney; ok markus@ - -commit 4a3a9d4bbf8048473f5cc202cd8db7164d5e6b8d -Author: Damien Miller -Date: Wed Oct 30 22:19:47 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/29 09:42:11 - [key.c key.h] - fix potential stack exhaustion caused by nested certificates; - report by Mateusz Kocielski; ok dtucker@ markus@ - -commit 28631ceaa7acd9bc500f924614431542893c6a21 -Author: Damien Miller -Date: Sat Oct 26 10:07:56 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/25 23:04:51 - [ssh.c] - fix crash when using ProxyCommand caused by previous commit - was calling - freeaddrinfo(NULL); spotted by sthen@ and Tim Ruehsen, patch by sthen@ - -commit 26506ad29350c5681815745cc90b3952a84cf118 -Author: Damien Miller -Date: Sat Oct 26 10:05:46 2013 +1100 - - - (djm) [ssh-keygen.c ssh-keysign.c sshconnect1.c sshd.c] Remove - unnecessary arc4random_stir() calls. The only ones left are to ensure - that the PRNG gets a different state after fork() for platforms that - have broken the API. - -commit bd43e8872325e9bbb3319c89da593614709f317c -Author: Tim Rice -Date: Thu Oct 24 12:22:49 2013 -0700 - - - (tim) [regress/sftp-perm.sh] We need a shell that understands "! somecmd" - -commit a90c0338083ee0e4064c4bdf61f497293a699be0 -Author: Damien Miller -Date: Thu Oct 24 21:03:17 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/24 08:19:36 - [ssh.c] - fix bug introduced in hostname canonicalisation commit: don't try to - resolve hostnames when a ProxyCommand is set unless the user has forced - canonicalisation; spotted by Iain Morgan - -commit cf31f3863425453ffcda540fbefa9df80088c8d1 -Author: Damien Miller -Date: Thu Oct 24 21:02:56 2013 +1100 - - - dtucker@cvs.openbsd.org 2013/10/24 00:51:48 - [readconf.c servconf.c ssh_config.5 sshd_config.5] - Disallow empty Match statements and add "Match all" which matches - everything. ok djm, man page help jmc@ - -commit 4bedd4032a09ce87322ae5ea80f193f109e5c607 -Author: Damien Miller -Date: Thu Oct 24 21:02:26 2013 +1100 - - - dtucker@cvs.openbsd.org 2013/10/24 00:49:49 - [moduli.c] - Periodically print progress and, if possible, expected time to completion - when screening moduli for DH groups. ok deraadt djm - -commit 5ecb41629860687b145be63b8877fabb6bae5eda -Author: Damien Miller -Date: Thu Oct 24 21:02:02 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/23 23:35:32 - [sshd.c] - include local address and port in "Connection from ..." message (only - shown at loglevel>=verbose) - -commit 03bf2e61ad6ac59a362a1f11b105586cb755c147 -Author: Damien Miller -Date: Thu Oct 24 21:01:26 2013 +1100 - - - dtucker@cvs.openbsd.org 2013/10/23 05:40:58 - [servconf.c] - fix comment - -commit 8f1873191478847773906af961c8984d02a49dd6 -Author: Damien Miller -Date: Thu Oct 24 10:53:02 2013 +1100 - - - (djm) [auth-krb5.c] bz#2032 - use local username in krb5_kuserok check - rather than full client name which may be of form user@REALM; - patch from Miguel Sanders; ok dtucker@ - -commit 5b01b0dcb417eb615df77e7ce1b59319bf04342c -Author: Damien Miller -Date: Wed Oct 23 16:31:31 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/23 04:16:22 - [ssh-keygen.c] - Make code match documentation: relative-specified certificate expiry time - should be relative to current time and not the validity start time. - Reported by Petr Lautrbach; ok deraadt@ - -commit eff5cada589f25793dbe63a76aba9da39837a148 -Author: Damien Miller -Date: Wed Oct 23 16:31:10 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/23 03:05:19 - [readconf.c ssh.c] - comment - -commit 084bcd24e9fe874020e4df4e073e7408e1b17fb7 -Author: Damien Miller -Date: Wed Oct 23 16:30:51 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/23 03:03:07 - [readconf.c] - Hostname may have %h sequences that should be expanded prior to Match - evaluation; spotted by Iain Morgan - -commit 8e5a67f46916def40b2758bb7755350dd2eee843 -Author: Damien Miller -Date: Wed Oct 23 16:30:25 2013 +1100 - - - jmc@cvs.openbsd.org 2013/10/20 18:00:13 - [ssh_config.5] - tweak the "exec" description, as worded by djm; - -commit c0049bd0bca02890cd792babc594771c563f91f2 -Author: Damien Miller -Date: Wed Oct 23 16:29:59 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/20 09:51:26 - [scp.1 sftp.1] - add canonicalisation options to -o lists - -commit 8a04be795fc28514a09e55a54b2e67968f2e1b3a -Author: Damien Miller -Date: Wed Oct 23 16:29:40 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/20 06:19:28 - [readconf.c ssh_config.5] - rename "command" subclause of the recently-added "Match" keyword to - "exec"; it's shorter, clearer in intent and we might want to add the - ability to match against the command being executed at the remote end in - the future. - -commit 5c86ebdf83b636b6741db4b03569ef4a53b89a58 -Author: Damien Miller -Date: Wed Oct 23 16:29:12 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/20 04:39:28 - [ssh_config.5] - document % expansions performed by "Match command ..." - -commit 4502f88774edc56194707167443f94026d3c7cfa -Author: Damien Miller -Date: Fri Oct 18 10:17:36 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/17 22:08:04 - [sshd.c] - include remote port in bad banner message; bz#2162 - -commit 1edcbf65ebd2febeaf10a836468f35e519eed7ca -Author: Damien Miller -Date: Fri Oct 18 10:17:17 2013 +1100 - - - jmc@cvs.openbsd.org 2013/10/17 07:35:48 - [sftp.1 sftp.c] - tweak previous; - -commit a176e1823013dd8533a20235b3a5131f0626f46b -Author: Damien Miller -Date: Fri Oct 18 09:05:41 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/09 23:44:14 - [regress/Makefile regress/sftp-perm.sh] - regression test for sftp request white/blacklisting and readonly mode. - -commit e3ea09494dcfe7ba76536e95765c8328ecfc18fb -Author: Damien Miller -Date: Thu Oct 17 11:57:23 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/17 00:46:49 - [ssh.c] - rearrange check to reduce diff against -portable - (Id sync only) - -commit f29238e67471a7f1088a99c3c3dbafce76b790cf -Author: Damien Miller -Date: Thu Oct 17 11:48:52 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/17 00:30:13 - [PROTOCOL sftp-client.c sftp-client.h sftp-server.c sftp.1 sftp.c] - fsync@openssh.com protocol extension for sftp-server - client support to allow calling fsync() faster successful transfer - patch mostly by imorgan AT nas.nasa.gov; bz#1798 - "fine" markus@ "grumble OK" deraadt@ "doesn't sound bad to me" millert@ - -commit 51682faa599550a69d8120e5e2bdbdc0625ef4be -Author: Damien Miller -Date: Thu Oct 17 11:48:31 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/16 22:58:01 - [ssh.c ssh_config.5] - one I missed in previous: s/isation/ization/ - -commit 3850559be93f1a442ae9ed370e8c389889dd5f72 -Author: Damien Miller -Date: Thu Oct 17 11:48:13 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/16 22:49:39 - [readconf.c readconf.h ssh.1 ssh.c ssh_config.5] - s/canonicalise/canonicalize/ for consistency with existing spelling, - e.g. authorized_keys; pointed out by naddy@ - -commit 607af3434b75acc7199a5d99d5a9c11068c01f27 -Author: Damien Miller -Date: Thu Oct 17 11:47:51 2013 +1100 - - - jmc@cvs.openbsd.org 2013/10/16 06:42:25 - [ssh_config.5] - tweak previous; - -commit 0faf747e2f77f0f7083bcd59cbed30c4b5448444 -Author: Damien Miller -Date: Thu Oct 17 11:47:23 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/16 02:31:47 - [readconf.c readconf.h roaming_client.c ssh.1 ssh.c ssh_config.5] - [sshconnect.c sshconnect.h] - Implement client-side hostname canonicalisation to allow an explicit - search path of domain suffixes to use to convert unqualified host names - to fully-qualified ones for host key matching. - This is particularly useful for host certificates, which would otherwise - need to list unqualified names alongside fully-qualified ones (and this - causes a number of problems). - "looks fine" markus@ - -commit d77b81f856e078714ec6b0f86f61c20249b7ead4 -Author: Damien Miller -Date: Thu Oct 17 11:39:00 2013 +1100 - - - jmc@cvs.openbsd.org 2013/10/15 14:10:25 - [ssh.1 ssh_config.5] - tweak previous; - -commit dcd39f29ce3308dc74a0ff27a9056205a932ce05 -Author: Damien Miller -Date: Thu Oct 17 11:31:40 2013 +1100 - - - [ssh.c] g/c unused variable. - -commit 5359a628ce3763408da25d83271a8eddec597a0c -Author: Damien Miller -Date: Tue Oct 15 12:20:37 2013 +1100 - - - [ssh.c] g/c unused variable. - -commit 386feab0c4736b054585ee8ee372865d5cde8d69 -Author: Damien Miller -Date: Tue Oct 15 12:14:49 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/14 23:31:01 - [ssh.c] - whitespace at EOL; pointed out by markus@ - -commit e9fc72edd6c313b670558cd5219601c38a949b67 -Author: Damien Miller -Date: Tue Oct 15 12:14:12 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/14 23:28:23 - [canohost.c misc.c misc.h readconf.c sftp-server.c ssh.c] - refactor client config code a little: - add multistate option partsing to readconf.c, similar to servconf.c's - existing code. - move checking of options that accept "none" as an argument to readconf.c - add a lowercase() function and use it instead of explicit tolower() in - loops - part of a larger diff that was ok markus@ - -commit 194fd904d8597a274b93e075b2047afdf5a175d4 -Author: Damien Miller -Date: Tue Oct 15 12:13:05 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/14 22:22:05 - [readconf.c readconf.h ssh-keysign.c ssh.c ssh_config.5] - add a "Match" keyword to ssh_config that allows matching on hostname, - user and result of arbitrary commands. "nice work" markus@ - -commit 71df752de2a04f423b1cd18d961a79f4fbccbcee -Author: Damien Miller -Date: Tue Oct 15 12:12:02 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/14 21:20:52 - [session.c session.h] - Add logging of session starts in a useful format; ok markus@ feedback and - ok dtucker@ - -commit 6efab27109b82820e8d32a5d811adb7bfc354f65 -Author: Damien Miller -Date: Tue Oct 15 12:07:05 2013 +1100 - - - jmc@cvs.openbsd.org 2013/10/14 14:18:56 - [sftp-server.8 sftp-server.c] - tweak previous; - ok djm - -commit 61c7de8a94156f6d7e9718ded9be8c65bb902b66 -Author: Damien Miller -Date: Tue Oct 15 12:06:45 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/11 02:53:45 - [sftp-client.h] - obsolete comment - -commit 2f93d0556e4892208c9b072624caa8cc5ddd839d -Author: Damien Miller -Date: Tue Oct 15 12:06:27 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/11 02:52:23 - [sftp-client.c] - missed one arg reorder - -commit bda5c8445713ae592d969a5105ed1a65da22bc96 -Author: Damien Miller -Date: Tue Oct 15 12:05:58 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/11 02:45:36 - [sftp-client.c] - rename flag arguments to be more clear and consistent. - reorder some internal function arguments to make adding additional flags - easier. - no functional change - -commit 61ee4d68ca0fcc793a826fc7ec70f3b8ffd12ab6 -Author: Damien Miller -Date: Tue Oct 15 11:56:47 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/10 01:43:03 - [sshd.c] - bz#2139: fix re-exec fallback by ensuring that startup_pipe is correctly - updated; ok dtucker@ - -commit 73600e51af9ee734a19767e0c084bbbc5eb5b8da -Author: Damien Miller -Date: Tue Oct 15 11:56:25 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/10 00:53:25 - [sftp-server.c] - add -Q, -P and -p to usage() before jmc@ catches me - -commit 6eaeebf27d92f39a38c772aa3f20c2250af2dd29 -Author: Damien Miller -Date: Tue Oct 15 11:55:57 2013 +1100 - - - djm@cvs.openbsd.org 2013/10/09 23:42:17 - [sftp-server.8 sftp-server.c] - Add ability to whitelist and/or blacklist sftp protocol requests by name. - Refactor dispatch loop and consolidate read-only mode checks. - Make global variables static, since sftp-server is linked into sshd(8). - ok dtucker@ - -commit df62d71e64d29d1054e7a53d1a801075ef70335f -Author: Darren Tucker -Date: Thu Oct 10 10:32:39 2013 +1100 - - - dtucker@cvs.openbsd.org 2013/10/08 11:42:13 - [dh.c dh.h] - Increase the size of the Diffie-Hellman groups requested for a each - symmetric key size. New values from NIST Special Publication 800-57 with - the upper limit specified by RFC4419. Pointed out by Peter Backes, ok - djm@. - -commit e6e52f8c5dc89a6767702e65bb595aaf7bc8991c -Author: Darren Tucker -Date: Thu Oct 10 10:28:07 2013 +1100 - - - djm@cvs.openbsd.org 2013/09/19 01:26:29 - [sshconnect.c] - bz#1211: make BindAddress work with UsePrivilegedPort=yes; patch from - swp AT swp.pp.ru; ok dtucker@ - -commit 71152bc9911bc34a98810b2398dac20df3fe8de3 -Author: Darren Tucker -Date: Thu Oct 10 10:27:21 2013 +1100 - - - djm@cvs.openbsd.org 2013/09/19 01:24:46 - [channels.c] - bz#1297 - tell the client (via packet_send_debug) when their preferred - listen address has been overridden by the server's GatewayPorts; - ok dtucker@ - -commit b59aaf3c4f3f449a4b86d8528668bd979be9aa5f -Author: Darren Tucker -Date: Thu Oct 10 10:26:21 2013 +1100 - - - djm@cvs.openbsd.org 2013/09/19 00:49:12 - [sftp-client.c] - fix swapped pflag and printflag in sftp upload_dir; from Iain Morgan - -commit 5d80e4522d6238bdefe9d0c634f0e6d35a241e41 -Author: Darren Tucker -Date: Thu Oct 10 10:25:09 2013 +1100 - - - djm@cvs.openbsd.org 2013/09/19 00:24:52 - [progressmeter.c] - store the initial file offset so the progress meter doesn't freak out - when resuming sftp transfers. bz#2137; patch from Iain Morgan; ok dtucker@ - -commit ad92df7e5ed26fea85adfb3f95352d6cd8e86344 -Author: Darren Tucker -Date: Thu Oct 10 10:24:11 2013 +1100 - - - sthen@cvs.openbsd.org 2013/09/16 11:35:43 - [ssh_config] - Remove gssapi config parts from ssh_config, as was already done for - sshd_config. Req by/ok ajacoutot@ - ID SYNC ONLY for portable; kerberos/gssapi is still pretty popular - -commit 720711960b130d36dfdd3d50eb25ef482bdd000e -Author: Damien Miller -Date: Wed Oct 9 10:44:47 2013 +1100 - - - (djm) [openbsd-compat/Makefile.in openbsd-compat/arc4random.c] - [openbsd-compat/bsd-arc4random.c] Replace old RC4-based arc4random - implementation with recent OpenBSD's ChaCha-based PRNG. ok dtucker@, - tested tim@ - -commit 9159310087a218e28940a592896808b8eb76a039 -Author: Damien Miller -Date: Wed Oct 9 10:42:32 2013 +1100 - - - (djm) [openbsd-compat/arc4random.c openbsd-compat/chacha_private.h] Pull - in OpenBSD implementation of arc4random, shortly to replace the existing - bsd-arc4random.c - -commit 67f1d557a68d6fa8966a327d7b6dee3408cf0e72 -Author: Damien Miller -Date: Wed Oct 9 09:33:08 2013 +1100 - - correct incorrect years in datestamps; from des - -commit f2bf36c3eb4d969f85ec8aa342e9aecb61cc8bb1 -Author: Darren Tucker -Date: Sun Sep 22 19:02:40 2013 +1000 - - - (dtucker) [platform.c platform.h sshd.c] bz#2156: restore Linux oom_adj - setting when handling SIGHUP to maintain behaviour over retart. Patch - from Matthew Ife. - -commit e90a06ae570fd259a2f5ced873c7f17390f535a5 -Author: Darren Tucker -Date: Wed Sep 18 15:09:38 2013 +1000 - - - (dtucker) [sshd_config] Trailing whitespace; from jstjohn at purdue edu. - -commit 13840e0103946982cee2a05c40697be7e57dca41 -Author: Damien Miller -Date: Sat Sep 14 09:49:43 2013 +1000 - - - djm@cvs.openbsd.org 2013/09/13 06:54:34 - [channels.c] - avoid unaligned access in code that reused a buffer to send a - struct in_addr in a reply; simpler just use use buffer_put_int(); - from portable; spotted by and ok dtucker@ - -commit 70182522a47d283513a010338cd028cb80dac2ab -Author: Damien Miller -Date: Sat Sep 14 09:49:19 2013 +1000 - - - djm@cvs.openbsd.org 2013/09/12 01:41:12 - [clientloop.c] - fix connection crash when sending break (~B) on ControlPersist'd session; - ok dtucker@ - -commit ff9d6c2a4171ee32e8fe28fc3b86eb33bd5c845b -Author: Damien Miller -Date: Sat Sep 14 09:48:55 2013 +1000 - - - sthen@cvs.openbsd.org 2013/09/07 13:53:11 - [sshd_config] - Remove commented-out kerberos/gssapi config options from sample config, - kerberos support is currently not enabled in ssh in OpenBSD. Discussed with - various people; ok deraadt@ - ID SYNC ONLY for portable; kerberos/gssapi is still pretty popular - -commit 8bab5e7b5ff6721d926b5ebf05a3a24489889c58 -Author: Damien Miller -Date: Sat Sep 14 09:47:00 2013 +1000 - - - deraadt@cvs.openbsd.org 2013/09/02 22:00:34 - [ssh-keygen.c sshconnect1.c sshd.c] - All the instances of arc4random_stir() are bogus, since arc4random() - does this itself, inside itself, and has for a very long time.. Actually, - this was probably reducing the entropy available. - ok djm - ID SYNC ONLY for portable; we don't trust other arc4random implementations - to do this right. - -commit 61353b3208d548fab863e0e0ac5d2400ee5bb340 -Author: Damien Miller -Date: Sat Sep 14 09:45:32 2013 +1000 - - - djm@cvs.openbsd.org 2013/08/31 00:13:54 - [sftp.c] - make ^w match ksh behaviour (delete previous word instead of entire line) - -commit 660854859cad31d234edb9353fb7ca2780df8128 -Author: Damien Miller -Date: Sat Sep 14 09:45:03 2013 +1000 - - - mikeb@cvs.openbsd.org 2013/08/28 12:34:27 - [ssh-keygen.c] - improve batch processing a bit by making use of the quite flag a bit - more often and exit with a non zero code if asked to find a hostname - in a known_hosts file and it wasn't there; - originally from reyk@, ok djm - -commit 045bda5cb8acf0eb9d71c275ee1247e3154fc9e5 -Author: Damien Miller -Date: Sat Sep 14 09:44:37 2013 +1000 - - - djm@cvs.openbsd.org 2013/08/22 19:02:21 - [sshd.c] - Stir PRNG after post-accept fork. The child gets a different PRNG state - anyway via rexec and explicit privsep reseeds, but it's good to be sure. - ok markus@ - -commit ed4af412da60a084891b20412433a27966613fb8 -Author: Damien Miller -Date: Sat Sep 14 09:40:51 2013 +1000 - - add marker for 6.3p1 release at the point of the last included change - -commit 43968a8e66a0aa1afefb11665bf96f86b113f5d9 -Author: Damien Miller -Date: Wed Aug 28 14:00:54 2013 +1000 - - - (djm) [openbsd-compat/bsd-snprintf.c] #ifdef noytet for intmax_t bits - until we have configure support. - -commit 04be8b9e53f8388c94b531ebc5d1bd6e10e930d1 -Author: Damien Miller -Date: Wed Aug 28 12:49:43 2013 +1000 - - - (djm) [openbsd-compat/bsd-snprintf.c] teach our local snprintf code the - 'j' (intmax_t/uintmax_t) and 'z' (size_t/ssize_t) conversions in case we - start to use them in the future. - -commit f2f6c315a920a256937e1b6a3702757f3195a592 -Author: Damien Miller -Date: Wed Aug 21 02:44:58 2013 +1000 - - - jmc@cvs.openbsd.org 2013/08/20 06:56:07 - [ssh.1 ssh_config.5] - some proxyusefdpass tweaks; - -commit 1262b6638f7d01ab110fd373dd90d915c882fe1a -Author: Damien Miller -Date: Wed Aug 21 02:44:24 2013 +1000 - - - djm@cvs.openbsd.org 2013/08/20 00:11:38 - [readconf.c readconf.h ssh_config.5 sshconnect.c] - Add a ssh_config ProxyUseFDPass option that supports the use of - ProxyCommands that establish a connection and then pass a connected - file descriptor back to ssh(1). This allows the ProxyCommand to exit - rather than have to shuffle data back and forth and enables ssh to use - getpeername, etc. to obtain address information just like it does with - regular directly-connected sockets. ok markus@ - -commit b7727df37efde4dbe4f5a33b19cbf42022aabf66 -Author: Damien Miller -Date: Wed Aug 21 02:43:49 2013 +1000 - - - jmc@cvs.openbsd.org 2013/08/14 08:39:27 - [scp.1 ssh.1] - some Bx/Ox conversion; - From: Jan Stary - -commit d5d9d7b1fdacf0551de4c747728bd159be40590a -Author: Damien Miller -Date: Wed Aug 21 02:43:27 2013 +1000 - - - djm@cvs.openbsd.org 2013/08/13 18:33:08 - [ssh-keygen.c] - another of the same typo - -commit d234afb0b3a8de1be78cbeafed5fc86912594c3c -Author: Damien Miller -Date: Wed Aug 21 02:42:58 2013 +1000 - - - djm@cvs.openbsd.org 2013/08/13 18:32:08 - [ssh-keygen.c] - typo in error message; from Stephan Rickauer - -commit e0ee727b8281a7c2ae20630ce83f6b200b404059 -Author: Damien Miller -Date: Wed Aug 21 02:42:35 2013 +1000 - - - djm@cvs.openbsd.org 2013/08/09 03:56:42 - [sftp.c] - enable ctrl-left-arrow and ctrl-right-arrow to move forward/back a word; - matching ksh's relatively recent change. - -commit fec029f1dc2c338f3fae3fa82aabc988dc07868c -Author: Damien Miller -Date: Wed Aug 21 02:42:12 2013 +1000 - - - djm@cvs.openbsd.org 2013/08/09 03:39:13 - [sftp-client.c] - two problems found by a to-be-committed regress test: 1) msg_id was not - being initialised so was starting at a random value from the heap - (harmless, but confusing). 2) some error conditions were not being - propagated back to the caller - -commit 036d30743fc914089f9849ca52d615891d47e616 -Author: Damien Miller -Date: Wed Aug 21 02:41:46 2013 +1000 - - - djm@cvs.openbsd.org 2013/08/09 03:37:25 - [sftp.c] - do getopt parsing for all sftp commands (with an empty optstring for - commands without arguments) to ensure consistent behaviour - -commit c7dba12bf95eb1d69711881a153cc286c1987663 -Author: Damien Miller -Date: Wed Aug 21 02:41:15 2013 +1000 - - - djm@cvs.openbsd.org 2013/08/08 05:04:03 - [sftp-client.c sftp-client.h sftp.c] - add a "-l" flag for the rename command to force it to use the silly - standard SSH_FXP_RENAME command instead of the POSIX-rename- like - posix-rename@openssh.com extension. - - intended for use in regress tests, so no documentation. - -commit 034f27a0c09e69fe3589045b41f03f6e345b63f5 -Author: Damien Miller -Date: Wed Aug 21 02:40:44 2013 +1000 - - - djm@cvs.openbsd.org 2013/08/08 04:52:04 - [sftp.c] - fix two year old regression: symlinking a file would incorrectly - canonicalise the target path. bz#2129 report from delphij AT freebsd.org - -commit c6895c5c67492144dd28589e5788f783be9152ed -Author: Damien Miller -Date: Wed Aug 21 02:40:21 2013 +1000 - - - jmc@cvs.openbsd.org 2013/08/07 06:24:51 - [sftp.1 sftp.c] - sort -a; - -commit a6d6c1f38ac9b4a5e1bd4df889e1020a8370ed55 -Author: Damien Miller -Date: Wed Aug 21 02:40:01 2013 +1000 - - - djm@cvs.openbsd.org 2013/08/06 23:06:01 - [servconf.c] - add cast to avoid format warning; from portable - -commit eec840673bce3f69ad269672fba7ed8ff05f154f -Author: Damien Miller -Date: Wed Aug 21 02:39:39 2013 +1000 - - - djm@cvs.openbsd.org 2013/08/06 23:05:01 - [sftp.1] - document top-level -a option (the -a option to 'get' was already - documented) - -commit 02e878070d0eddad4e11f2c82644b275418eb112 -Author: Damien Miller -Date: Wed Aug 21 02:38:51 2013 +1000 - - - djm@cvs.openbsd.org 2013/08/06 23:03:49 - [sftp.c] - fix some whitespace at EOL - make list of commands an enum rather than a long list of defines - add -a to usage() Index: head/crypto/openssh/README =================================================================== --- head/crypto/openssh/README (revision 294495) +++ head/crypto/openssh/README (revision 294496) @@ -1,65 +1,69 @@ -See http://www.openssh.com/txt/release-7.0 for the release notes. +See http://www.openssh.com/txt/release-7.1p2 for the release notes. + +Please read http://www.openssh.com/report.html for bug reporting +instructions and note that we do not use Github for bug reporting or +patch/pull-request management. - A Japanese translation of this document and of the OpenSSH FAQ is - available at http://www.unixuser.org/~haruyama/security/openssh/index.html - Thanks to HARUYAMA Seigo This is the port of OpenBSD's excellent OpenSSH[0] to Linux and other Unices. OpenSSH is based on the last free version of Tatu Ylonen's sample implementation with all patent-encumbered algorithms removed (to external libraries), all known security bugs fixed, new features reintroduced and many other clean-ups. OpenSSH has been created by Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo de Raadt, and Dug Song. It has a homepage at http://www.openssh.com/ This port consists of the re-introduction of autoconf support, PAM support, EGD[1]/PRNGD[2] support and replacements for OpenBSD library functions that are (regrettably) absent from other unices. This port has been best tested on AIX, Cygwin, HP-UX, Linux, MacOS/X, NetBSD, OpenBSD, OpenServer, Solaris, Unicos, and UnixWare. This version actively tracks changes in the OpenBSD CVS repository. The PAM support is now more functional than the popular packages of commercial ssh-1.2.x. It checks "account" and "session" modules for all logins, not just when using password authentication. OpenSSH depends on Zlib[3], OpenSSL[4] and optionally PAM[5]. There is now several mailing lists for this port of OpenSSH. Please refer to http://www.openssh.com/list.html for details on how to join. Please send bug reports and patches to the mailing list openssh-unix-dev@mindrot.org. The list is open to posting by unsubscribed users.Code contribution are welcomed, but please follow the OpenBSD style guidelines[6]. Please refer to the INSTALL document for information on how to install OpenSSH on your system. There are a number of differences between this port of OpenSSH and F-Secure SSH 1.x, please refer to the OpenSSH FAQ[7] for details and general tips. Damien Miller Miscellania - This version of OpenSSH is based upon code retrieved from the OpenBSD CVS repository which in turn was based on the last free sample implementation released by Tatu Ylonen. References - [0] http://www.openssh.com/faq.html [1] http://www.lothar.com/tech/crypto/ [2] http://www.aet.tu-cottbus.de/personen/jaenicke/postfix_tls/prngd.html [3] http://www.gzip.org/zlib/ [4] http://www.openssl.org/ [5] http://www.openpam.org http://www.kernel.org/pub/linux/libs/pam/ (PAM also is standard on Solaris and HP-UX 11) [6] http://www.openbsd.org/cgi-bin/man.cgi?query=style&sektion=9 [7] http://www.openssh.com/faq.html $Id: README,v 1.87 2014/08/10 01:35:06 djm Exp $ Index: head/crypto/openssh/auth.c =================================================================== --- head/crypto/openssh/auth.c (revision 294495) +++ head/crypto/openssh/auth.c (revision 294496) @@ -1,776 +1,776 @@ -/* $OpenBSD: auth.c,v 1.112 2015/08/06 14:53:21 deraadt Exp $ */ +/* $OpenBSD: auth.c,v 1.113 2015/08/21 03:42:19 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" __RCSID("$FreeBSD$"); #include #include #include #include #include #ifdef HAVE_PATHS_H # include #endif #include #ifdef HAVE_LOGIN_H #include #endif #ifdef USE_SHADOW #include #endif #ifdef HAVE_LIBGEN_H #include #endif #include #include #include #include #include #include "xmalloc.h" #include "match.h" #include "groupaccess.h" #include "log.h" #include "buffer.h" #include "misc.h" #include "servconf.h" #include "key.h" #include "hostfile.h" #include "auth.h" #include "auth-options.h" #include "canohost.h" #include "uidswap.h" #include "packet.h" #include "loginrec.h" #ifdef GSSAPI #include "ssh-gss.h" #endif #include "authfile.h" #include "monitor_wrap.h" #include "authfile.h" #include "ssherr.h" #include "compat.h" /* import */ extern ServerOptions options; extern int use_privsep; extern Buffer loginmsg; extern struct passwd *privsep_pw; /* Debugging messages */ Buffer auth_debug; int auth_debug_init; /* * Check if the user is allowed to log in via ssh. If user is listed * in DenyUsers or one of user's groups is listed in DenyGroups, false * will be returned. If AllowUsers isn't empty and user isn't listed * there, or if AllowGroups isn't empty and one of user's groups isn't * listed there, false will be returned. * If the user's shell is not executable, false will be returned. * Otherwise true is returned. */ int allowed_user(struct passwd * pw) { struct stat st; const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL; u_int i; #ifdef USE_SHADOW struct spwd *spw = NULL; #endif /* Shouldn't be called if pw is NULL, but better safe than sorry... */ if (!pw || !pw->pw_name) return 0; #ifdef USE_SHADOW if (!options.use_pam) spw = getspnam(pw->pw_name); #ifdef HAS_SHADOW_EXPIRE if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw)) return 0; #endif /* HAS_SHADOW_EXPIRE */ #endif /* USE_SHADOW */ /* grab passwd field for locked account check */ passwd = pw->pw_passwd; #ifdef USE_SHADOW if (spw != NULL) #ifdef USE_LIBIAF passwd = get_iaf_password(pw); #else passwd = spw->sp_pwdp; #endif /* USE_LIBIAF */ #endif /* check for locked account */ if (!options.use_pam && passwd && *passwd) { int locked = 0; #ifdef LOCKED_PASSWD_STRING if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0) locked = 1; #endif #ifdef LOCKED_PASSWD_PREFIX if (strncmp(passwd, LOCKED_PASSWD_PREFIX, strlen(LOCKED_PASSWD_PREFIX)) == 0) locked = 1; #endif #ifdef LOCKED_PASSWD_SUBSTR if (strstr(passwd, LOCKED_PASSWD_SUBSTR)) locked = 1; #endif #ifdef USE_LIBIAF free((void *) passwd); #endif /* USE_LIBIAF */ if (locked) { logit("User %.100s not allowed because account is locked", pw->pw_name); return 0; } } /* * Deny if shell does not exist or is not executable unless we * are chrooting. */ if (options.chroot_directory == NULL || strcasecmp(options.chroot_directory, "none") == 0) { char *shell = xstrdup((pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */ if (stat(shell, &st) != 0) { logit("User %.100s not allowed because shell %.100s " "does not exist", pw->pw_name, shell); free(shell); return 0; } if (S_ISREG(st.st_mode) == 0 || (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) { logit("User %.100s not allowed because shell %.100s " "is not executable", pw->pw_name, shell); free(shell); return 0; } free(shell); } if (options.num_deny_users > 0 || options.num_allow_users > 0 || options.num_deny_groups > 0 || options.num_allow_groups > 0) { hostname = get_canonical_hostname(options.use_dns); ipaddr = get_remote_ipaddr(); } /* Return false if user is listed in DenyUsers */ if (options.num_deny_users > 0) { for (i = 0; i < options.num_deny_users; i++) if (match_user(pw->pw_name, hostname, ipaddr, options.deny_users[i])) { logit("User %.100s from %.100s not allowed " "because listed in DenyUsers", pw->pw_name, hostname); return 0; } } /* Return false if AllowUsers isn't empty and user isn't listed there */ if (options.num_allow_users > 0) { for (i = 0; i < options.num_allow_users; i++) if (match_user(pw->pw_name, hostname, ipaddr, options.allow_users[i])) break; /* i < options.num_allow_users iff we break for loop */ if (i >= options.num_allow_users) { logit("User %.100s from %.100s not allowed because " "not listed in AllowUsers", pw->pw_name, hostname); return 0; } } if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { /* Get the user's group access list (primary and supplementary) */ if (ga_init(pw->pw_name, pw->pw_gid) == 0) { logit("User %.100s from %.100s not allowed because " "not in any group", pw->pw_name, hostname); return 0; } /* Return false if one of user's groups is listed in DenyGroups */ if (options.num_deny_groups > 0) if (ga_match(options.deny_groups, options.num_deny_groups)) { ga_free(); logit("User %.100s from %.100s not allowed " "because a group is listed in DenyGroups", pw->pw_name, hostname); return 0; } /* * Return false if AllowGroups isn't empty and one of user's groups * isn't listed there */ if (options.num_allow_groups > 0) if (!ga_match(options.allow_groups, options.num_allow_groups)) { ga_free(); logit("User %.100s from %.100s not allowed " "because none of user's groups are listed " "in AllowGroups", pw->pw_name, hostname); return 0; } ga_free(); } #ifdef CUSTOM_SYS_AUTH_ALLOWED_USER if (!sys_auth_allowed_user(pw, &loginmsg)) return 0; #endif /* We found no reason not to let this user try to log on... */ return 1; } void auth_info(Authctxt *authctxt, const char *fmt, ...) { va_list ap; int i; free(authctxt->info); authctxt->info = NULL; va_start(ap, fmt); i = vasprintf(&authctxt->info, fmt, ap); va_end(ap); if (i < 0 || authctxt->info == NULL) fatal("vasprintf failed"); } void auth_log(Authctxt *authctxt, int authenticated, int partial, const char *method, const char *submethod) { void (*authlog) (const char *fmt,...) = verbose; char *authmsg; if (use_privsep && !mm_is_monitor() && !authctxt->postponed) return; /* Raise logging level */ if (authenticated == 1 || !authctxt->valid || authctxt->failures >= options.max_authtries / 2 || strcmp(method, "password") == 0) authlog = logit; if (authctxt->postponed) authmsg = "Postponed"; else if (partial) authmsg = "Partial"; else authmsg = authenticated ? "Accepted" : "Failed"; authlog("%s %s%s%s for %s%.100s from %.200s port %d %s%s%s", authmsg, method, submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod, authctxt->valid ? "" : "invalid user ", authctxt->user, get_remote_ipaddr(), get_remote_port(), compat20 ? "ssh2" : "ssh1", authctxt->info != NULL ? ": " : "", authctxt->info != NULL ? authctxt->info : ""); free(authctxt->info); authctxt->info = NULL; #ifdef CUSTOM_FAILED_LOGIN if (authenticated == 0 && !authctxt->postponed && (strcmp(method, "password") == 0 || strncmp(method, "keyboard-interactive", 20) == 0 || strcmp(method, "challenge-response") == 0)) record_failed_login(authctxt->user, get_canonical_hostname(options.use_dns), "ssh"); # ifdef WITH_AIXAUTHENTICATE if (authenticated) sys_auth_record_login(authctxt->user, get_canonical_hostname(options.use_dns), "ssh", &loginmsg); # endif #endif #ifdef SSH_AUDIT_EVENTS if (authenticated == 0 && !authctxt->postponed) audit_event(audit_classify_auth(method)); #endif } void auth_maxtries_exceeded(Authctxt *authctxt) { error("maximum authentication attempts exceeded for " "%s%.100s from %.200s port %d %s", authctxt->valid ? "" : "invalid user ", authctxt->user, get_remote_ipaddr(), get_remote_port(), compat20 ? "ssh2" : "ssh1"); packet_disconnect("Too many authentication failures"); /* NOTREACHED */ } /* * Check whether root logins are disallowed. */ int auth_root_allowed(const char *method) { switch (options.permit_root_login) { case PERMIT_YES: return 1; case PERMIT_NO_PASSWD: if (strcmp(method, "publickey") == 0 || strcmp(method, "hostbased") == 0 || - strcmp(method, "gssapi-with-mic")) + strcmp(method, "gssapi-with-mic") == 0) return 1; break; case PERMIT_FORCED_ONLY: if (forced_command) { logit("Root login accepted for forced command."); return 1; } break; } logit("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr()); return 0; } /* * Given a template and a passwd structure, build a filename * by substituting % tokenised options. Currently, %% becomes '%', * %h becomes the home directory and %u the username. * * This returns a buffer allocated by xmalloc. */ char * expand_authorized_keys(const char *filename, struct passwd *pw) { char *file, ret[PATH_MAX]; int i; file = percent_expand(filename, "h", pw->pw_dir, "u", pw->pw_name, (char *)NULL); /* * Ensure that filename starts anchored. If not, be backward * compatible and prepend the '%h/' */ if (*file == '/') return (file); i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file); if (i < 0 || (size_t)i >= sizeof(ret)) fatal("expand_authorized_keys: path too long"); free(file); return (xstrdup(ret)); } char * authorized_principals_file(struct passwd *pw) { if (options.authorized_principals_file == NULL) return NULL; return expand_authorized_keys(options.authorized_principals_file, pw); } /* return ok if key exists in sysfile or userfile */ HostStatus check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host, const char *sysfile, const char *userfile) { char *user_hostfile; struct stat st; HostStatus host_status; struct hostkeys *hostkeys; const struct hostkey_entry *found; hostkeys = init_hostkeys(); load_hostkeys(hostkeys, host, sysfile); if (userfile != NULL) { user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); if (options.strict_modes && (stat(user_hostfile, &st) == 0) && ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || (st.st_mode & 022) != 0)) { logit("Authentication refused for %.100s: " "bad owner or modes for %.200s", pw->pw_name, user_hostfile); auth_debug_add("Ignored %.200s: bad ownership or modes", user_hostfile); } else { temporarily_use_uid(pw); load_hostkeys(hostkeys, host, user_hostfile); restore_uid(); } free(user_hostfile); } host_status = check_key_in_hostkeys(hostkeys, key, &found); if (host_status == HOST_REVOKED) error("WARNING: revoked key for %s attempted authentication", found->host); else if (host_status == HOST_OK) debug("%s: key for %s found at %s:%ld", __func__, found->host, found->file, found->line); else debug("%s: key for host %s not found", __func__, host); free_hostkeys(hostkeys); return host_status; } /* * Check a given path for security. This is defined as all components * of the path to the file must be owned by either the owner of * of the file or root and no directories must be group or world writable. * * XXX Should any specific check be done for sym links ? * * Takes a file name, its stat information (preferably from fstat() to * avoid races), the uid of the expected owner, their home directory and an * error buffer plus max size as arguments. * * Returns 0 on success and -1 on failure */ int auth_secure_path(const char *name, struct stat *stp, const char *pw_dir, uid_t uid, char *err, size_t errlen) { char buf[PATH_MAX], homedir[PATH_MAX]; char *cp; int comparehome = 0; struct stat st; if (realpath(name, buf) == NULL) { snprintf(err, errlen, "realpath %s failed: %s", name, strerror(errno)); return -1; } if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL) comparehome = 1; if (!S_ISREG(stp->st_mode)) { snprintf(err, errlen, "%s is not a regular file", buf); return -1; } if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) || (stp->st_mode & 022) != 0) { snprintf(err, errlen, "bad ownership or modes for file %s", buf); return -1; } /* for each component of the canonical path, walking upwards */ for (;;) { if ((cp = dirname(buf)) == NULL) { snprintf(err, errlen, "dirname() failed"); return -1; } strlcpy(buf, cp, sizeof(buf)); if (stat(buf, &st) < 0 || (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) || (st.st_mode & 022) != 0) { snprintf(err, errlen, "bad ownership or modes for directory %s", buf); return -1; } /* If are past the homedir then we can stop */ if (comparehome && strcmp(homedir, buf) == 0) break; /* * dirname should always complete with a "/" path, * but we can be paranoid and check for "." too */ if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0)) break; } return 0; } /* * Version of secure_path() that accepts an open file descriptor to * avoid races. * * Returns 0 on success and -1 on failure */ static int secure_filename(FILE *f, const char *file, struct passwd *pw, char *err, size_t errlen) { struct stat st; /* check the open file to avoid races */ if (fstat(fileno(f), &st) < 0) { snprintf(err, errlen, "cannot stat file %s: %s", file, strerror(errno)); return -1; } return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen); } static FILE * auth_openfile(const char *file, struct passwd *pw, int strict_modes, int log_missing, char *file_type) { char line[1024]; struct stat st; int fd; FILE *f; if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) { if (log_missing || errno != ENOENT) debug("Could not open %s '%s': %s", file_type, file, strerror(errno)); return NULL; } if (fstat(fd, &st) < 0) { close(fd); return NULL; } if (!S_ISREG(st.st_mode)) { logit("User %s %s %s is not a regular file", pw->pw_name, file_type, file); close(fd); return NULL; } unset_nonblock(fd); if ((f = fdopen(fd, "r")) == NULL) { close(fd); return NULL; } if (strict_modes && secure_filename(f, file, pw, line, sizeof(line)) != 0) { fclose(f); logit("Authentication refused: %s", line); auth_debug_add("Ignored %s: %s", file_type, line); return NULL; } return f; } FILE * auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes) { return auth_openfile(file, pw, strict_modes, 1, "authorized keys"); } FILE * auth_openprincipals(const char *file, struct passwd *pw, int strict_modes) { return auth_openfile(file, pw, strict_modes, 0, "authorized principals"); } struct passwd * getpwnamallow(const char *user) { #ifdef HAVE_LOGIN_CAP extern login_cap_t *lc; #ifdef BSD_AUTH auth_session_t *as; #endif #endif struct passwd *pw; struct connection_info *ci = get_connection_info(1, options.use_dns); ci->user = user; parse_server_match_config(&options, ci); #if defined(_AIX) && defined(HAVE_SETAUTHDB) aix_setauthdb(user); #endif pw = getpwnam(user); #if defined(_AIX) && defined(HAVE_SETAUTHDB) aix_restoreauthdb(); #endif #ifdef HAVE_CYGWIN /* * Windows usernames are case-insensitive. To avoid later problems * when trying to match the username, the user is only allowed to * login if the username is given in the same case as stored in the * user database. */ if (pw != NULL && strcmp(user, pw->pw_name) != 0) { logit("Login name %.100s does not match stored username %.100s", user, pw->pw_name); pw = NULL; } #endif if (pw == NULL) { logit("Invalid user %.100s from %.100s", user, get_remote_ipaddr()); #ifdef CUSTOM_FAILED_LOGIN record_failed_login(user, get_canonical_hostname(options.use_dns), "ssh"); #endif #ifdef SSH_AUDIT_EVENTS audit_event(SSH_INVALID_USER); #endif /* SSH_AUDIT_EVENTS */ return (NULL); } if (!allowed_user(pw)) return (NULL); #ifdef HAVE_LOGIN_CAP if ((lc = login_getpwclass(pw)) == NULL) { debug("unable to get login class: %s", user); return (NULL); } #ifdef BSD_AUTH if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 || auth_approval(as, lc, pw->pw_name, "ssh") <= 0) { debug("Approval failure for %s", user); pw = NULL; } if (as != NULL) auth_close(as); #endif #endif if (pw != NULL) return (pwcopy(pw)); return (NULL); } /* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */ int auth_key_is_revoked(Key *key) { char *fp = NULL; int r; if (options.revoked_keys_file == NULL) return 0; if ((fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { r = SSH_ERR_ALLOC_FAIL; error("%s: fingerprint key: %s", __func__, ssh_err(r)); goto out; } r = sshkey_check_revoked(key, options.revoked_keys_file); switch (r) { case 0: break; /* not revoked */ case SSH_ERR_KEY_REVOKED: error("Authentication key %s %s revoked by file %s", sshkey_type(key), fp, options.revoked_keys_file); goto out; default: error("Error checking authentication key %s %s in " "revoked keys file %s: %s", sshkey_type(key), fp, options.revoked_keys_file, ssh_err(r)); goto out; } /* Success */ r = 0; out: free(fp); return r == 0 ? 0 : 1; } void auth_debug_add(const char *fmt,...) { char buf[1024]; va_list args; if (!auth_debug_init) return; va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); buffer_put_cstring(&auth_debug, buf); } void auth_debug_send(void) { char *msg; if (!auth_debug_init) return; while (buffer_len(&auth_debug)) { msg = buffer_get_string(&auth_debug, NULL); packet_send_debug("%s", msg); free(msg); } } void auth_debug_reset(void) { if (auth_debug_init) buffer_clear(&auth_debug); else { buffer_init(&auth_debug); auth_debug_init = 1; } } struct passwd * fakepw(void) { static struct passwd fake; memset(&fake, 0, sizeof(fake)); fake.pw_name = "NOUSER"; fake.pw_passwd = "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK"; #ifdef HAVE_STRUCT_PASSWD_PW_GECOS fake.pw_gecos = "NOUSER"; #endif fake.pw_uid = privsep_pw == NULL ? (uid_t)-1 : privsep_pw->pw_uid; fake.pw_gid = privsep_pw == NULL ? (gid_t)-1 : privsep_pw->pw_gid; #ifdef HAVE_STRUCT_PASSWD_PW_CLASS fake.pw_class = ""; #endif fake.pw_dir = "/nonexist"; fake.pw_shell = "/nonexist"; return (&fake); } Index: head/crypto/openssh/bitmap.c =================================================================== --- head/crypto/openssh/bitmap.c (revision 294495) +++ head/crypto/openssh/bitmap.c (revision 294496) @@ -1,212 +1,212 @@ /* * Copyright (c) 2015 Damien Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "includes.h" #include #include #include #include "bitmap.h" #define BITMAP_WTYPE u_int #define BITMAP_MAX (1<<24) #define BITMAP_BYTES (sizeof(BITMAP_WTYPE)) #define BITMAP_BITS (sizeof(BITMAP_WTYPE) * 8) #define BITMAP_WMASK ((BITMAP_WTYPE)BITMAP_BITS - 1) struct bitmap { BITMAP_WTYPE *d; size_t len; /* number of words allocated */ size_t top; /* index of top word allocated */ }; struct bitmap * bitmap_new(void) { struct bitmap *ret; if ((ret = calloc(1, sizeof(*ret))) == NULL) return NULL; if ((ret->d = calloc(1, BITMAP_BYTES)) == NULL) { free(ret); return NULL; } ret->len = 1; ret->top = 0; return ret; } void bitmap_free(struct bitmap *b) { if (b != NULL && b->d != NULL) { - memset(b->d, 0, b->len); + explicit_bzero(b->d, b->len); free(b->d); } free(b); } void bitmap_zero(struct bitmap *b) { memset(b->d, 0, b->len * BITMAP_BYTES); b->top = 0; } int bitmap_test_bit(struct bitmap *b, u_int n) { if (b->top >= b->len) return 0; /* invalid */ if (b->len == 0 || (n / BITMAP_BITS) > b->top) return 0; return (b->d[n / BITMAP_BITS] >> (n & BITMAP_WMASK)) & 1; } static int reserve(struct bitmap *b, u_int n) { BITMAP_WTYPE *tmp; size_t nlen; if (b->top >= b->len || n > BITMAP_MAX) return -1; /* invalid */ nlen = (n / BITMAP_BITS) + 1; if (b->len < nlen) { if ((tmp = reallocarray(b->d, nlen, BITMAP_BYTES)) == NULL) return -1; b->d = tmp; memset(b->d + b->len, 0, (nlen - b->len) * BITMAP_BYTES); b->len = nlen; } return 0; } int bitmap_set_bit(struct bitmap *b, u_int n) { int r; size_t offset; if ((r = reserve(b, n)) != 0) return r; offset = n / BITMAP_BITS; if (offset > b->top) b->top = offset; b->d[offset] |= (BITMAP_WTYPE)1 << (n & BITMAP_WMASK); return 0; } /* Resets b->top to point to the most significant bit set in b->d */ static void retop(struct bitmap *b) { if (b->top >= b->len) return; while (b->top > 0 && b->d[b->top] == 0) b->top--; } void bitmap_clear_bit(struct bitmap *b, u_int n) { size_t offset; if (b->top >= b->len || n > BITMAP_MAX) return; /* invalid */ offset = n / BITMAP_BITS; if (offset > b->top) return; b->d[offset] &= ~((BITMAP_WTYPE)1 << (n & BITMAP_WMASK)); /* The top may have changed as a result of the clear */ retop(b); } size_t bitmap_nbits(struct bitmap *b) { size_t bits; BITMAP_WTYPE w; retop(b); if (b->top >= b->len) return 0; /* invalid */ if (b->len == 0 || (b->top == 0 && b->d[0] == 0)) return 0; /* Find MSB set */ w = b->d[b->top]; bits = (b->top + 1) * BITMAP_BITS; while (!(w & ((BITMAP_WTYPE)1 << (BITMAP_BITS - 1)))) { w <<= 1; bits--; } return bits; } size_t bitmap_nbytes(struct bitmap *b) { return (bitmap_nbits(b) + 7) / 8; } int bitmap_to_string(struct bitmap *b, void *p, size_t l) { u_char *s = (u_char *)p; size_t i, j, k, need = bitmap_nbytes(b); if (l < need || b->top >= b->len) return -1; if (l > need) l = need; /* Put the bytes from LSB backwards */ for (i = k = 0; i < b->top + 1; i++) { for (j = 0; j < BITMAP_BYTES; j++) { if (k >= l) break; s[need - 1 - k++] = (b->d[i] >> (j * 8)) & 0xff; } } return 0; } int bitmap_from_string(struct bitmap *b, const void *p, size_t l) { int r; size_t i, offset, shift; u_char *s = (u_char *)p; if (l > BITMAP_MAX / 8) return -1; if ((r = reserve(b, l * 8)) != 0) return r; bitmap_zero(b); if (l == 0) return 0; b->top = offset = ((l + (BITMAP_BYTES - 1)) / BITMAP_BYTES) - 1; shift = ((l + (BITMAP_BYTES - 1)) % BITMAP_BYTES) * 8; for (i = 0; i < l; i++) { b->d[offset] |= (BITMAP_WTYPE)s[i] << shift; if (shift == 0) { offset--; shift = BITMAP_BITS - 8; } else shift -= 8; } retop(b); return 0; } Index: head/crypto/openssh/compat.c =================================================================== --- head/crypto/openssh/compat.c (revision 294495) +++ head/crypto/openssh/compat.c (revision 294496) @@ -1,314 +1,325 @@ -/* $OpenBSD: compat.c,v 1.96 2015/07/28 23:20:42 djm Exp $ */ +/* $OpenBSD: compat.c,v 1.97 2015/08/19 23:21:42 djm Exp $ */ /* * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" #include #include #include #include #include "xmalloc.h" #include "buffer.h" #include "packet.h" #include "compat.h" #include "log.h" #include "match.h" int compat13 = 0; int compat20 = 0; int datafellows = 0; void enable_compat20(void) { if (compat20) return; debug("Enabling compatibility mode for protocol 2.0"); compat20 = 1; } void enable_compat13(void) { debug("Enabling compatibility mode for protocol 1.3"); compat13 = 1; } /* datafellows bug compatibility */ u_int compat_datafellows(const char *version) { int i; static struct { char *pat; int bugs; } check[] = { { "OpenSSH-2.0*," "OpenSSH-2.1*," "OpenSSH_2.1*," "OpenSSH_2.2*", SSH_OLD_SESSIONID|SSH_BUG_BANNER| SSH_OLD_DHGEX|SSH_BUG_NOREKEY| SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR}, { "OpenSSH_2.3.0*", SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES| SSH_OLD_DHGEX|SSH_BUG_NOREKEY| SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR}, { "OpenSSH_2.3.*", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX| SSH_BUG_NOREKEY|SSH_BUG_EXTEOF| SSH_OLD_FORWARD_ADDR}, { "OpenSSH_2.5.0p1*," "OpenSSH_2.5.1p1*", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX| SSH_BUG_NOREKEY|SSH_BUG_EXTEOF| SSH_OLD_FORWARD_ADDR}, { "OpenSSH_2.5.0*," "OpenSSH_2.5.1*," "OpenSSH_2.5.2*", SSH_OLD_DHGEX|SSH_BUG_NOREKEY| SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR}, { "OpenSSH_2.5.3*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF| SSH_OLD_FORWARD_ADDR}, { "OpenSSH_2.*," "OpenSSH_3.0*," "OpenSSH_3.1*", SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR}, { "OpenSSH_3.*", SSH_OLD_FORWARD_ADDR }, { "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, { "OpenSSH_4*", 0 }, { "OpenSSH_5*", SSH_NEW_OPENSSH|SSH_BUG_DYNAMIC_RPORT}, { "OpenSSH_6.6.1*", SSH_NEW_OPENSSH}, { "OpenSSH_6.5*," "OpenSSH_6.6*", SSH_NEW_OPENSSH|SSH_BUG_CURVE25519PAD}, { "OpenSSH*", SSH_NEW_OPENSSH }, { "*MindTerm*", 0 }, { "2.1.0*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| SSH_OLD_SESSIONID|SSH_BUG_DEBUG| SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE| SSH_BUG_FIRSTKEX }, { "2.1 *", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| SSH_OLD_SESSIONID|SSH_BUG_DEBUG| SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE| SSH_BUG_FIRSTKEX }, { "2.0.13*," "2.0.14*," "2.0.15*," "2.0.16*," "2.0.17*," "2.0.18*," "2.0.19*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| SSH_OLD_SESSIONID|SSH_BUG_DEBUG| SSH_BUG_PKSERVICE|SSH_BUG_X11FWD| SSH_BUG_PKOK|SSH_BUG_RSASIGMD5| SSH_BUG_HBSERVICE|SSH_BUG_OPENFAILURE| SSH_BUG_DUMMYCHAN|SSH_BUG_FIRSTKEX }, { "2.0.11*," "2.0.12*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| SSH_OLD_SESSIONID|SSH_BUG_DEBUG| SSH_BUG_PKSERVICE|SSH_BUG_X11FWD| SSH_BUG_PKAUTH|SSH_BUG_PKOK| SSH_BUG_RSASIGMD5|SSH_BUG_OPENFAILURE| SSH_BUG_DUMMYCHAN|SSH_BUG_FIRSTKEX }, { "2.0.*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| SSH_OLD_SESSIONID|SSH_BUG_DEBUG| SSH_BUG_PKSERVICE|SSH_BUG_X11FWD| SSH_BUG_PKAUTH|SSH_BUG_PKOK| SSH_BUG_RSASIGMD5|SSH_BUG_OPENFAILURE| SSH_BUG_DERIVEKEY|SSH_BUG_DUMMYCHAN| SSH_BUG_FIRSTKEX }, { "2.2.0*," "2.3.0*", SSH_BUG_HMAC|SSH_BUG_DEBUG| SSH_BUG_RSASIGMD5|SSH_BUG_FIRSTKEX }, { "2.3.*", SSH_BUG_DEBUG|SSH_BUG_RSASIGMD5| SSH_BUG_FIRSTKEX }, { "2.4", SSH_OLD_SESSIONID }, /* Van Dyke */ { "2.*", SSH_BUG_DEBUG|SSH_BUG_FIRSTKEX| SSH_BUG_RFWD_ADDR }, { "3.0.*", SSH_BUG_DEBUG }, { "3.0 SecureCRT*", SSH_OLD_SESSIONID }, { "1.7 SecureFX*", SSH_OLD_SESSIONID }, { "1.2.18*," "1.2.19*," "1.2.20*," "1.2.21*," "1.2.22*", SSH_BUG_IGNOREMSG }, { "1.3.2*", /* F-Secure */ SSH_BUG_IGNOREMSG }, { "Cisco-1.*", SSH_BUG_DHGEX_LARGE| SSH_BUG_HOSTKEYS }, { "*SSH Compatible Server*", /* Netscreen */ SSH_BUG_PASSWORDPAD }, { "*OSU_0*," "OSU_1.0*," "OSU_1.1*," "OSU_1.2*," "OSU_1.3*," "OSU_1.4*," "OSU_1.5alpha1*," "OSU_1.5alpha2*," "OSU_1.5alpha3*", SSH_BUG_PASSWORDPAD }, { "*SSH_Version_Mapper*", SSH_BUG_SCANNER }, { "PuTTY_Local:*," /* dev versions < Sep 2014 */ "PuTTY-Release-0.5*," /* 0.50-0.57, DH-GEX in >=0.52 */ "PuTTY_Release_0.5*," /* 0.58-0.59 */ "PuTTY_Release_0.60*," "PuTTY_Release_0.61*," "PuTTY_Release_0.62*," "PuTTY_Release_0.63*," "PuTTY_Release_0.64*", SSH_OLD_DHGEX }, + { "FuTTY*", SSH_OLD_DHGEX }, /* Putty Fork */ { "Probe-*", SSH_BUG_PROBE }, { "TeraTerm SSH*," "TTSSH/1.5.*," "TTSSH/2.1*," "TTSSH/2.2*," "TTSSH/2.3*," "TTSSH/2.4*," "TTSSH/2.5*," "TTSSH/2.6*," "TTSSH/2.70*," "TTSSH/2.71*," "TTSSH/2.72*", SSH_BUG_HOSTKEYS }, - { "WinSCP*", SSH_OLD_DHGEX }, + { "WinSCP_release_4*," + "WinSCP_release_5.0*," + "WinSCP_release_5.1*," + "WinSCP_release_5.5*," + "WinSCP_release_5.6*," + "WinSCP_release_5.7," + "WinSCP_release_5.7.1," + "WinSCP_release_5.7.2," + "WinSCP_release_5.7.3," + "WinSCP_release_5.7.4", + SSH_OLD_DHGEX }, { NULL, 0 } }; /* process table, return first match */ for (i = 0; check[i].pat; i++) { if (match_pattern_list(version, check[i].pat, 0) == 1) { debug("match: %s pat %s compat 0x%08x", version, check[i].pat, check[i].bugs); datafellows = check[i].bugs; /* XXX for now */ return check[i].bugs; } } debug("no match: %s", version); return 0; } #define SEP "," int proto_spec(const char *spec) { char *s, *p, *q; int ret = SSH_PROTO_UNKNOWN; if (spec == NULL) return ret; q = s = strdup(spec); if (s == NULL) return ret; for ((p = strsep(&q, SEP)); p && *p != '\0'; (p = strsep(&q, SEP))) { switch (atoi(p)) { case 1: #ifdef WITH_SSH1 if (ret == SSH_PROTO_UNKNOWN) ret |= SSH_PROTO_1_PREFERRED; ret |= SSH_PROTO_1; #endif break; case 2: ret |= SSH_PROTO_2; break; default: logit("ignoring bad proto spec: '%s'.", p); break; } } free(s); return ret; } /* * Filters a proposal string, excluding any algorithm matching the 'filter' * pattern list. */ static char * filter_proposal(char *proposal, const char *filter) { Buffer b; char *orig_prop, *fix_prop; char *cp, *tmp; buffer_init(&b); tmp = orig_prop = xstrdup(proposal); while ((cp = strsep(&tmp, ",")) != NULL) { if (match_pattern_list(cp, filter, 0) != 1) { if (buffer_len(&b) > 0) buffer_append(&b, ",", 1); buffer_append(&b, cp, strlen(cp)); } else debug2("Compat: skipping algorithm \"%s\"", cp); } buffer_append(&b, "\0", 1); fix_prop = xstrdup((char *)buffer_ptr(&b)); buffer_free(&b); free(orig_prop); return fix_prop; } char * compat_cipher_proposal(char *cipher_prop) { if (!(datafellows & SSH_BUG_BIGENDIANAES)) return cipher_prop; debug2("%s: original cipher proposal: %s", __func__, cipher_prop); cipher_prop = filter_proposal(cipher_prop, "aes*"); debug2("%s: compat cipher proposal: %s", __func__, cipher_prop); if (*cipher_prop == '\0') fatal("No supported ciphers found"); return cipher_prop; } char * compat_pkalg_proposal(char *pkalg_prop) { if (!(datafellows & SSH_BUG_RSASIGMD5)) return pkalg_prop; debug2("%s: original public key proposal: %s", __func__, pkalg_prop); pkalg_prop = filter_proposal(pkalg_prop, "ssh-rsa"); debug2("%s: compat public key proposal: %s", __func__, pkalg_prop); if (*pkalg_prop == '\0') fatal("No supported PK algorithms found"); return pkalg_prop; } char * compat_kex_proposal(char *p) { if ((datafellows & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0) return p; debug2("%s: original KEX proposal: %s", __func__, p); if ((datafellows & SSH_BUG_CURVE25519PAD) != 0) p = filter_proposal(p, "curve25519-sha256@libssh.org"); if ((datafellows & SSH_OLD_DHGEX) != 0) { p = filter_proposal(p, "diffie-hellman-group-exchange-sha256"); p = filter_proposal(p, "diffie-hellman-group-exchange-sha1"); } debug2("%s: compat KEX proposal: %s", __func__, p); if (*p == '\0') fatal("No supported key exchange algorithms found"); return p; } Index: head/crypto/openssh/contrib/README =================================================================== --- head/crypto/openssh/contrib/README (revision 294495) +++ head/crypto/openssh/contrib/README (revision 294496) @@ -1,70 +1,70 @@ Other patches and addons for OpenSSH. Please send submissions to djm@mindrot.org Externally maintained --------------------- SSH Proxy Command -- connect.c Shun-ichi GOTO has written a very useful ProxyCommand which allows the use of outbound SSH from behind a SOCKS4, SOCKS5 or https CONNECT style proxy server. His page for connect.c has extensive documentation on its use as well as compiled versions for Win32. -http://www.taiyo.co.jp/~gotoh/ssh/connect.html +https://bitbucket.org/gotoh/connect/wiki/Home X11 SSH Askpass: Jim Knoble has written an excellent X11 passphrase requester. This is highly recommended: http://www.jmknoble.net/software/x11-ssh-askpass/ In this directory ----------------- ssh-copy-id: Phil Hands' shell script to automate the process of adding your public key to a remote machine's ~/.ssh/authorized_keys file. gnome-ssh-askpass[12]: A GNOME and Gtk2 passphrase requesters. Use "make gnome-ssh-askpass1" or "make gnome-ssh-askpass2" to build. sshd.pam.generic: A generic PAM config file which may be useful on your system. YMMV sshd.pam.freebsd: A PAM config file which works with FreeBSD's PAM port. Contributed by Dominik Brettnacher findssl.sh: Search for all instances of OpenSSL headers and libraries and print their versions. This is intended to help diagnose OpenSSH's "OpenSSL headers do not match your library" errors. aix: Files to build an AIX native (installp or SMIT installable) package. caldera: RPM spec file and scripts for building Caldera OpenLinuix packages cygwin: Support files for Cygwin hpux: Support files for HP-UX redhat: RPM spec file and scripts for building Redhat packages suse: RPM spec file and scripts for building SuSE packages Index: head/crypto/openssh/contrib/redhat/openssh.spec =================================================================== --- head/crypto/openssh/contrib/redhat/openssh.spec (revision 294495) +++ head/crypto/openssh/contrib/redhat/openssh.spec (revision 294496) @@ -1,811 +1,811 @@ -%define ver 7.0p1 +%define ver 7.1p2 %define rel 1 # OpenSSH privilege separation requires a user & group ID %define sshd_uid 74 %define sshd_gid 74 # Version of ssh-askpass %define aversion 1.2.4.1 # Do we want to disable building of x11-askpass? (1=yes 0=no) %define no_x11_askpass 0 # Do we want to disable building of gnome-askpass? (1=yes 0=no) %define no_gnome_askpass 0 # Do we want to link against a static libcrypto? (1=yes 0=no) %define static_libcrypto 0 # Do we want smartcard support (1=yes 0=no) %define scard 0 # Use GTK2 instead of GNOME in gnome-ssh-askpass %define gtk2 1 # Is this build for RHL 6.x? %define build6x 0 # Do we want kerberos5 support (1=yes 0=no) %define kerberos5 1 # Reserve options to override askpass settings with: # rpm -ba|--rebuild --define 'skip_xxx 1' %{?skip_x11_askpass:%define no_x11_askpass 1} %{?skip_gnome_askpass:%define no_gnome_askpass 1} # Add option to build without GTK2 for older platforms with only GTK+. # RedHat <= 7.2 and Red Hat Advanced Server 2.1 are examples. # rpm -ba|--rebuild --define 'no_gtk2 1' %{?no_gtk2:%define gtk2 0} # Is this a build for RHL 6.x or earlier? %{?build_6x:%define build6x 1} # If this is RHL 6.x, the default configuration has sysconfdir in /usr/etc. %if %{build6x} %define _sysconfdir /etc %endif # Options for static OpenSSL link: # rpm -ba|--rebuild --define "static_openssl 1" %{?static_openssl:%define static_libcrypto 1} # Options for Smartcard support: (needs libsectok and openssl-engine) # rpm -ba|--rebuild --define "smartcard 1" %{?smartcard:%define scard 1} # Is this a build for the rescue CD (without PAM, with MD5)? (1=yes 0=no) %define rescue 0 %{?build_rescue:%define rescue 1} # Turn off some stuff for resuce builds %if %{rescue} %define kerberos5 0 %endif Summary: The OpenSSH implementation of SSH protocol versions 1 and 2. Name: openssh Version: %{ver} %if %{rescue} Release: %{rel}rescue %else Release: %{rel} %endif URL: http://www.openssh.com/portable.html Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz %if ! %{no_x11_askpass} Source1: http://www.jmknoble.net/software/x11-ssh-askpass/x11-ssh-askpass-%{aversion}.tar.gz %endif License: BSD Group: Applications/Internet BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot Obsoletes: ssh %if %{build6x} PreReq: initscripts >= 5.00 %else Requires: initscripts >= 5.20 %endif BuildRequires: perl, openssl-devel BuildRequires: /bin/login %if ! %{build6x} BuildPreReq: glibc-devel, pam %else BuildRequires: /usr/include/security/pam_appl.h %endif %if ! %{no_x11_askpass} BuildRequires: /usr/include/X11/Xlib.h %endif %if ! %{no_gnome_askpass} BuildRequires: pkgconfig %endif %if %{kerberos5} BuildRequires: krb5-devel BuildRequires: krb5-libs %endif %package clients Summary: OpenSSH clients. Requires: openssh = %{version}-%{release} Group: Applications/Internet Obsoletes: ssh-clients %package server Summary: The OpenSSH server daemon. Group: System Environment/Daemons Obsoletes: ssh-server Requires: openssh = %{version}-%{release}, chkconfig >= 0.9 %if ! %{build6x} Requires: /etc/pam.d/system-auth %endif %package askpass Summary: A passphrase dialog for OpenSSH and X. Group: Applications/Internet Requires: openssh = %{version}-%{release} Obsoletes: ssh-extras %package askpass-gnome Summary: A passphrase dialog for OpenSSH, X, and GNOME. Group: Applications/Internet Requires: openssh = %{version}-%{release} Obsoletes: ssh-extras %description SSH (Secure SHell) is a program for logging into and executing commands on a remote machine. SSH is intended to replace rlogin and rsh, and to provide secure encrypted communications between two untrusted hosts over an insecure network. X11 connections and arbitrary TCP/IP ports can also be forwarded over the secure channel. OpenSSH is OpenBSD's version of the last free version of SSH, bringing it up to date in terms of security and features, as well as removing all patented algorithms to separate libraries. This package includes the core files necessary for both the OpenSSH client and server. To make this package useful, you should also install openssh-clients, openssh-server, or both. %description clients OpenSSH is a free version of SSH (Secure SHell), a program for logging into and executing commands on a remote machine. This package includes the clients necessary to make encrypted connections to SSH servers. You'll also need to install the openssh package on OpenSSH clients. %description server OpenSSH is a free version of SSH (Secure SHell), a program for logging into and executing commands on a remote machine. This package contains the secure shell daemon (sshd). The sshd daemon allows SSH clients to securely connect to your SSH server. You also need to have the openssh package installed. %description askpass OpenSSH is a free version of SSH (Secure SHell), a program for logging into and executing commands on a remote machine. This package contains an X11 passphrase dialog for OpenSSH. %description askpass-gnome OpenSSH is a free version of SSH (Secure SHell), a program for logging into and executing commands on a remote machine. This package contains an X11 passphrase dialog for OpenSSH and the GNOME GUI desktop environment. %prep %if ! %{no_x11_askpass} %setup -q -a 1 %else %setup -q %endif %build %if %{rescue} CFLAGS="$RPM_OPT_FLAGS -Os"; export CFLAGS %endif %if %{kerberos5} K5DIR=`rpm -ql krb5-devel | grep include/krb5.h | sed 's,\/include\/krb5.h,,'` echo K5DIR=$K5DIR %endif %configure \ --sysconfdir=%{_sysconfdir}/ssh \ --libexecdir=%{_libexecdir}/openssh \ --datadir=%{_datadir}/openssh \ --with-rsh=%{_bindir}/rsh \ --with-default-path=/usr/local/bin:/bin:/usr/bin \ --with-superuser-path=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin \ --with-privsep-path=%{_var}/empty/sshd \ --with-md5-passwords \ %if %{scard} --with-smartcard \ %endif %if %{rescue} --without-pam \ %else --with-pam \ %endif %if %{kerberos5} --with-kerberos5=$K5DIR \ %endif %if %{static_libcrypto} perl -pi -e "s|-lcrypto|%{_libdir}/libcrypto.a|g" Makefile %endif make %if ! %{no_x11_askpass} pushd x11-ssh-askpass-%{aversion} %configure --libexecdir=%{_libexecdir}/openssh xmkmf -a make popd %endif # Define a variable to toggle gnome1/gtk2 building. This is necessary # because RPM doesn't handle nested %if statements. %if %{gtk2} gtk2=yes %else gtk2=no %endif %if ! %{no_gnome_askpass} pushd contrib if [ $gtk2 = yes ] ; then make gnome-ssh-askpass2 mv gnome-ssh-askpass2 gnome-ssh-askpass else make gnome-ssh-askpass1 mv gnome-ssh-askpass1 gnome-ssh-askpass fi popd %endif %install rm -rf $RPM_BUILD_ROOT mkdir -p -m755 $RPM_BUILD_ROOT%{_sysconfdir}/ssh mkdir -p -m755 $RPM_BUILD_ROOT%{_libexecdir}/openssh mkdir -p -m755 $RPM_BUILD_ROOT%{_var}/empty/sshd make install DESTDIR=$RPM_BUILD_ROOT install -d $RPM_BUILD_ROOT/etc/pam.d/ install -d $RPM_BUILD_ROOT/etc/rc.d/init.d install -d $RPM_BUILD_ROOT%{_libexecdir}/openssh %if %{build6x} install -m644 contrib/redhat/sshd.pam.old $RPM_BUILD_ROOT/etc/pam.d/sshd %else install -m644 contrib/redhat/sshd.pam $RPM_BUILD_ROOT/etc/pam.d/sshd %endif install -m755 contrib/redhat/sshd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/sshd %if ! %{no_x11_askpass} install -s x11-ssh-askpass-%{aversion}/x11-ssh-askpass $RPM_BUILD_ROOT%{_libexecdir}/openssh/x11-ssh-askpass ln -s x11-ssh-askpass $RPM_BUILD_ROOT%{_libexecdir}/openssh/ssh-askpass %endif %if ! %{no_gnome_askpass} install -s contrib/gnome-ssh-askpass $RPM_BUILD_ROOT%{_libexecdir}/openssh/gnome-ssh-askpass %endif %if ! %{scard} rm -f $RPM_BUILD_ROOT/usr/share/openssh/Ssh.bin %endif %if ! %{no_gnome_askpass} install -m 755 -d $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/ install -m 755 contrib/redhat/gnome-ssh-askpass.csh $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/ install -m 755 contrib/redhat/gnome-ssh-askpass.sh $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/ %endif perl -pi -e "s|$RPM_BUILD_ROOT||g" $RPM_BUILD_ROOT%{_mandir}/man*/* %clean rm -rf $RPM_BUILD_ROOT %triggerun server -- ssh-server if [ "$1" != 0 -a -r /var/run/sshd.pid ] ; then touch /var/run/sshd.restart fi %triggerun server -- openssh-server < 2.5.0p1 # Count the number of HostKey and HostDsaKey statements we have. gawk 'BEGIN {IGNORECASE=1} /^hostkey/ || /^hostdsakey/ {sawhostkey = sawhostkey + 1} END {exit sawhostkey}' /etc/ssh/sshd_config # And if we only found one, we know the client was relying on the old default # behavior, which loaded the the SSH2 DSA host key when HostDsaKey wasn't # specified. Now that HostKey is used for both SSH1 and SSH2 keys, specifying # one nullifies the default, which would have loaded both. if [ $? -eq 1 ] ; then echo HostKey /etc/ssh/ssh_host_rsa_key >> /etc/ssh/sshd_config echo HostKey /etc/ssh/ssh_host_dsa_key >> /etc/ssh/sshd_config fi %triggerpostun server -- ssh-server if [ "$1" != 0 ] ; then /sbin/chkconfig --add sshd if test -f /var/run/sshd.restart ; then rm -f /var/run/sshd.restart /sbin/service sshd start > /dev/null 2>&1 || : fi fi %pre server %{_sbindir}/groupadd -r -g %{sshd_gid} sshd 2>/dev/null || : %{_sbindir}/useradd -d /var/empty/sshd -s /bin/false -u %{sshd_uid} \ -g sshd -M -r sshd 2>/dev/null || : %post server /sbin/chkconfig --add sshd %postun server /sbin/service sshd condrestart > /dev/null 2>&1 || : %preun server if [ "$1" = 0 ] then /sbin/service sshd stop > /dev/null 2>&1 || : /sbin/chkconfig --del sshd fi %files %defattr(-,root,root) %doc CREDITS ChangeLog INSTALL LICENCE OVERVIEW README* PROTOCOL* TODO %attr(0755,root,root) %{_bindir}/scp %attr(0644,root,root) %{_mandir}/man1/scp.1* %attr(0755,root,root) %dir %{_sysconfdir}/ssh %attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ssh/moduli %if ! %{rescue} %attr(0755,root,root) %{_bindir}/ssh-keygen %attr(0644,root,root) %{_mandir}/man1/ssh-keygen.1* %attr(0755,root,root) %dir %{_libexecdir}/openssh %attr(4711,root,root) %{_libexecdir}/openssh/ssh-keysign %attr(0755,root,root) %{_libexecdir}/openssh/ssh-pkcs11-helper %attr(0644,root,root) %{_mandir}/man8/ssh-keysign.8* %attr(0644,root,root) %{_mandir}/man8/ssh-pkcs11-helper.8* %endif %if %{scard} %attr(0755,root,root) %dir %{_datadir}/openssh %attr(0644,root,root) %{_datadir}/openssh/Ssh.bin %endif %files clients %defattr(-,root,root) %attr(0755,root,root) %{_bindir}/ssh %attr(0644,root,root) %{_mandir}/man1/ssh.1* %attr(0644,root,root) %{_mandir}/man5/ssh_config.5* %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ssh/ssh_config %attr(-,root,root) %{_bindir}/slogin %attr(-,root,root) %{_mandir}/man1/slogin.1* %if ! %{rescue} %attr(2755,root,nobody) %{_bindir}/ssh-agent %attr(0755,root,root) %{_bindir}/ssh-add %attr(0755,root,root) %{_bindir}/ssh-keyscan %attr(0755,root,root) %{_bindir}/sftp %attr(0644,root,root) %{_mandir}/man1/ssh-agent.1* %attr(0644,root,root) %{_mandir}/man1/ssh-add.1* %attr(0644,root,root) %{_mandir}/man1/ssh-keyscan.1* %attr(0644,root,root) %{_mandir}/man1/sftp.1* %endif %if ! %{rescue} %files server %defattr(-,root,root) %dir %attr(0111,root,root) %{_var}/empty/sshd %attr(0755,root,root) %{_sbindir}/sshd %attr(0755,root,root) %{_libexecdir}/openssh/sftp-server %attr(0644,root,root) %{_mandir}/man8/sshd.8* %attr(0644,root,root) %{_mandir}/man5/moduli.5* %attr(0644,root,root) %{_mandir}/man5/sshd_config.5* %attr(0644,root,root) %{_mandir}/man8/sftp-server.8* %attr(0755,root,root) %dir %{_sysconfdir}/ssh %attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ssh/sshd_config %attr(0600,root,root) %config(noreplace) /etc/pam.d/sshd %attr(0755,root,root) %config /etc/rc.d/init.d/sshd %endif %if ! %{no_x11_askpass} %files askpass %defattr(-,root,root) %doc x11-ssh-askpass-%{aversion}/README %doc x11-ssh-askpass-%{aversion}/ChangeLog %doc x11-ssh-askpass-%{aversion}/SshAskpass*.ad %attr(0755,root,root) %{_libexecdir}/openssh/ssh-askpass %attr(0755,root,root) %{_libexecdir}/openssh/x11-ssh-askpass %endif %if ! %{no_gnome_askpass} %files askpass-gnome %defattr(-,root,root) %attr(0755,root,root) %config %{_sysconfdir}/profile.d/gnome-ssh-askpass.* %attr(0755,root,root) %{_libexecdir}/openssh/gnome-ssh-askpass %endif %changelog * Wed Jul 14 2010 Tim Rice - test for skip_x11_askpass (line 77) should have been for no_x11_askpass * Mon Jun 2 2003 Damien Miller - Remove noip6 option. This may be controlled at run-time in client config file using new AddressFamily directive * Mon May 12 2003 Damien Miller - Don't install profile.d scripts when not building with GNOME/GTK askpass (patch from bet@rahul.net) * Wed Oct 01 2002 Damien Miller - Install ssh-agent setgid nobody to prevent ptrace() key theft attacks * Mon Sep 30 2002 Damien Miller - Use contrib/ Makefile for building askpass programs * Fri Jun 21 2002 Damien Miller - Merge in spec changes from seba@iq.pl (Sebastian Pachuta) - Add new {ssh,sshd}_config.5 manpages - Add new ssh-keysign program and remove setuid from ssh client * Fri May 10 2002 Damien Miller - Merge in spec changes from RedHat, reorgansie a little - Add Privsep user, group and directory * Thu Mar 7 2002 Nalin Dahyabhai 3.1p1-2 - bump and grind (through the build system) * Thu Mar 7 2002 Nalin Dahyabhai 3.1p1-1 - require sharutils for building (mindrot #137) - require db1-devel only when building for 6.x (#55105), which probably won't work anyway (3.1 requires OpenSSL 0.9.6 to build), but what the heck - require pam-devel by file (not by package name) again - add Markus's patch to compile with OpenSSL 0.9.5a (from http://bugzilla.mindrot.org/show_bug.cgi?id=141) and apply it if we're building for 6.x * Thu Mar 7 2002 Nalin Dahyabhai 3.1p1-0 - update to 3.1p1 * Tue Mar 5 2002 Nalin Dahyabhai SNAP-20020305 - update to SNAP-20020305 - drop debug patch, fixed upstream * Wed Feb 20 2002 Nalin Dahyabhai SNAP-20020220 - update to SNAP-20020220 for testing purposes (you've been warned, if there's anything to be warned about, gss patches won't apply, I don't mind) * Wed Feb 13 2002 Nalin Dahyabhai 3.0.2p1-3 - add patches from Simon Wilkinson and Nicolas Williams for GSSAPI key exchange, authentication, and named key support * Wed Jan 23 2002 Nalin Dahyabhai 3.0.2p1-2 - remove dependency on db1-devel, which has just been swallowed up whole by gnome-libs-devel * Sun Dec 29 2001 Nalin Dahyabhai - adjust build dependencies so that build6x actually works right (fix from Hugo van der Kooij) * Tue Dec 4 2001 Nalin Dahyabhai 3.0.2p1-1 - update to 3.0.2p1 * Fri Nov 16 2001 Nalin Dahyabhai 3.0.1p1-1 - update to 3.0.1p1 * Tue Nov 13 2001 Nalin Dahyabhai - update to current CVS (not for use in distribution) * Thu Nov 8 2001 Nalin Dahyabhai 3.0p1-1 - merge some of Damien Miller changes from the upstream 3.0p1 spec file and init script * Wed Nov 7 2001 Nalin Dahyabhai - update to 3.0p1 - update to x11-ssh-askpass 1.2.4.1 - change build dependency on a file from pam-devel to the pam-devel package - replace primes with moduli * Thu Sep 27 2001 Nalin Dahyabhai 2.9p2-9 - incorporate fix from Markus Friedl's advisory for IP-based authorization bugs * Thu Sep 13 2001 Bernhard Rosenkraenzer 2.9p2-8 - Merge changes to rescue build from current sysadmin survival cd * Thu Sep 6 2001 Nalin Dahyabhai 2.9p2-7 - fix scp's server's reporting of file sizes, and build with the proper preprocessor define to get large-file capable open(), stat(), etc. (sftp has been doing this correctly all along) (#51827) - configure without --with-ipv4-default on RHL 7.x and newer (#45987,#52247) - pull cvs patch to fix support for /etc/nologin for non-PAM logins (#47298) - mark profile.d scriptlets as config files (#42337) - refer to Jason Stone's mail for zsh workaround for exit-hanging quasi-bug - change a couple of log() statements to debug() statements (#50751) - pull cvs patch to add -t flag to sshd (#28611) - clear fd_sets correctly (one bit per FD, not one byte per FD) (#43221) * Mon Aug 20 2001 Nalin Dahyabhai 2.9p2-6 - add db1-devel as a BuildPrerequisite (noted by Hans Ecke) * Thu Aug 16 2001 Nalin Dahyabhai - pull cvs patch to fix remote port forwarding with protocol 2 * Thu Aug 9 2001 Nalin Dahyabhai - pull cvs patch to add session initialization to no-pty sessions - pull cvs patch to not cut off challengeresponse auth needlessly - refuse to do X11 forwarding if xauth isn't there, handy if you enable it by default on a system that doesn't have X installed (#49263) * Wed Aug 8 2001 Nalin Dahyabhai - don't apply patches to code we don't intend to build (spotted by Matt Galgoci) * Mon Aug 6 2001 Nalin Dahyabhai - pass OPTIONS correctly to initlog (#50151) * Wed Jul 25 2001 Nalin Dahyabhai - switch to x11-ssh-askpass 1.2.2 * Wed Jul 11 2001 Nalin Dahyabhai - rebuild in new environment * Mon Jun 25 2001 Nalin Dahyabhai - disable the gssapi patch * Mon Jun 18 2001 Nalin Dahyabhai - update to 2.9p2 - refresh to a new version of the gssapi patch * Thu Jun 7 2001 Nalin Dahyabhai - change Copyright: BSD to License: BSD - add Markus Friedl's unverified patch for the cookie file deletion problem so that we can verify it - drop patch to check if xauth is present (was folded into cookie patch) - don't apply gssapi patches for the errata candidate - clear supplemental groups list at startup * Fri May 25 2001 Nalin Dahyabhai - fix an error parsing the new default sshd_config - add a fix from Markus Friedl (via openssh-unix-dev) for ssh-keygen not dealing with comments right * Thu May 24 2001 Nalin Dahyabhai - add in Simon Wilkinson's GSSAPI patch to give it some testing in-house, to be removed before the next beta cycle because it's a big departure from the upstream version * Thu May 3 2001 Nalin Dahyabhai - finish marking strings in the init script for translation - modify init script to source /etc/sysconfig/sshd and pass $OPTIONS to sshd at startup (change merged from openssh.com init script, originally by Pekka Savola) - refuse to do X11 forwarding if xauth isn't there, handy if you enable it by default on a system that doesn't have X installed * Wed May 2 2001 Nalin Dahyabhai - update to 2.9 - drop various patches that came from or went upstream or to or from CVS * Wed Apr 18 2001 Nalin Dahyabhai - only require initscripts 5.00 on 6.2 (reported by Peter Bieringer) * Sun Apr 8 2001 Preston Brown - remove explicit openssl requirement, fixes builddistro issue - make initscript stop() function wait until sshd really dead to avoid races in condrestart * Mon Apr 2 2001 Nalin Dahyabhai - mention that challengereponse supports PAM, so disabling password doesn't limit users to pubkey and rsa auth (#34378) - bypass the daemon() function in the init script and call initlog directly, because daemon() won't start a daemon it detects is already running (like open connections) - require the version of openssl we had when we were built * Fri Mar 23 2001 Nalin Dahyabhai - make do_pam_setcred() smart enough to know when to establish creds and when to reinitialize them - add in a couple of other fixes from Damien for inclusion in the errata * Thu Mar 22 2001 Nalin Dahyabhai - update to 2.5.2p2 - call setcred() again after initgroups, because the "creds" could actually be group memberships * Tue Mar 20 2001 Nalin Dahyabhai - update to 2.5.2p1 (includes endianness fixes in the rijndael implementation) - don't enable challenge-response by default until we find a way to not have too many userauth requests (we may make up to six pubkey and up to three password attempts as it is) - remove build dependency on rsh to match openssh.com's packages more closely * Sat Mar 3 2001 Nalin Dahyabhai - remove dependency on openssl -- would need to be too precise * Fri Mar 2 2001 Nalin Dahyabhai - rebuild in new environment * Mon Feb 26 2001 Nalin Dahyabhai - Revert the patch to move pam_open_session. - Init script and spec file changes from Pekka Savola. (#28750) - Patch sftp to recognize '-o protocol' arguments. (#29540) * Thu Feb 22 2001 Nalin Dahyabhai - Chuck the closing patch. - Add a trigger to add host keys for protocol 2 to the config file, now that configuration file syntax requires us to specify it with HostKey if we specify any other HostKey values, which we do. * Tue Feb 20 2001 Nalin Dahyabhai - Redo patch to move pam_open_session after the server setuid()s to the user. - Rework the nopam patch to use be picked up by autoconf. * Mon Feb 19 2001 Nalin Dahyabhai - Update for 2.5.1p1. - Add init script mods from Pekka Savola. - Tweak the init script to match the CVS contrib script more closely. - Redo patch to ssh-add to try to adding both identity and id_dsa to also try adding id_rsa. * Fri Feb 16 2001 Nalin Dahyabhai - Update for 2.5.0p1. - Use $RPM_OPT_FLAGS instead of -O when building gnome-ssh-askpass - Resync with parts of Damien Miller's openssh.spec from CVS, including update of x11 askpass to 1.2.0. - Only require openssl (don't prereq) because we generate keys in the init script now. * Tue Feb 13 2001 Nalin Dahyabhai - Don't open a PAM session until we've forked and become the user (#25690). - Apply Andrew Bartlett's patch for letting pam_authenticate() know which host the user is attempting a login from. - Resync with parts of Damien Miller's openssh.spec from CVS. - Don't expose KbdInt responses in debug messages (from CVS). - Detect and handle errors in rsa_{public,private}_decrypt (from CVS). * Wed Feb 7 2001 Trond Eivind Glomsrxd - i18n-tweak to initscript. * Tue Jan 23 2001 Nalin Dahyabhai - More gettextizing. - Close all files after going into daemon mode (needs more testing). - Extract patch from CVS to handle auth banners (in the client). - Extract patch from CVS to handle compat weirdness. * Fri Jan 19 2001 Nalin Dahyabhai - Finish with the gettextizing. * Thu Jan 18 2001 Nalin Dahyabhai - Fix a bug in auth2-pam.c (#23877) - Gettextize the init script. * Wed Dec 20 2000 Nalin Dahyabhai - Incorporate a switch for using PAM configs for 6.x, just in case. * Tue Dec 5 2000 Nalin Dahyabhai - Incorporate Bero's changes for a build specifically for rescue CDs. * Wed Nov 29 2000 Nalin Dahyabhai - Don't treat pam_setcred() failure as fatal unless pam_authenticate() has succeeded, to allow public-key authentication after a failure with "none" authentication. (#21268) * Tue Nov 28 2000 Nalin Dahyabhai - Update to x11-askpass 1.1.1. (#21301) - Don't second-guess fixpaths, which causes paths to get fixed twice. (#21290) * Mon Nov 27 2000 Nalin Dahyabhai - Merge multiple PAM text messages into subsequent prompts when possible when doing keyboard-interactive authentication. * Sun Nov 26 2000 Nalin Dahyabhai - Disable the built-in MD5 password support. We're using PAM. - Take a crack at doing keyboard-interactive authentication with PAM, and enable use of it in the default client configuration so that the client will try it when the server disallows password authentication. - Build with debugging flags. Build root policies strip all binaries anyway. * Tue Nov 21 2000 Nalin Dahyabhai - Use DESTDIR instead of %%makeinstall. - Remove /usr/X11R6/bin from the path-fixing patch. * Mon Nov 20 2000 Nalin Dahyabhai - Add the primes file from the latest snapshot to the main package (#20884). - Add the dev package to the prereq list (#19984). - Remove the default path and mimic login's behavior in the server itself. * Fri Nov 17 2000 Nalin Dahyabhai - Resync with conditional options in Damien Miller's .spec file for an errata. - Change libexecdir from %%{_libexecdir}/ssh to %%{_libexecdir}/openssh. * Tue Nov 7 2000 Nalin Dahyabhai - Update to OpenSSH 2.3.0p1. - Update to x11-askpass 1.1.0. - Enable keyboard-interactive authentication. * Mon Oct 30 2000 Nalin Dahyabhai - Update to ssh-askpass-x11 1.0.3. - Change authentication related messages to be private (#19966). * Tue Oct 10 2000 Nalin Dahyabhai - Patch ssh-keygen to be able to list signatures for DSA public key files it generates. * Thu Oct 5 2000 Nalin Dahyabhai - Add BuildRequires on /usr/include/security/pam_appl.h to be sure we always build PAM authentication in. - Try setting SSH_ASKPASS if gnome-ssh-askpass is installed. - Clean out no-longer-used patches. - Patch ssh-add to try to add both identity and id_dsa, and to error only when neither exists. * Mon Oct 2 2000 Nalin Dahyabhai - Update x11-askpass to 1.0.2. (#17835) - Add BuildRequiress for /bin/login and /usr/bin/rsh so that configure will always find them in the right place. (#17909) - Set the default path to be the same as the one supplied by /bin/login, but add /usr/X11R6/bin. (#17909) - Try to handle obsoletion of ssh-server more cleanly. Package names are different, but init script name isn't. (#17865) * Wed Sep 6 2000 Nalin Dahyabhai - Update to 2.2.0p1. (#17835) - Tweak the init script to allow proper restarting. (#18023) * Wed Aug 23 2000 Nalin Dahyabhai - Update to 20000823 snapshot. - Change subpackage requirements from %%{version} to %%{version}-%%{release} - Back out the pipe patch. * Mon Jul 17 2000 Nalin Dahyabhai - Update to 2.1.1p4, which includes fixes for config file parsing problems. - Move the init script back. - Add Damien's quick fix for wackiness. * Wed Jul 12 2000 Nalin Dahyabhai - Update to 2.1.1p3, which includes fixes for X11 forwarding and strtok(). * Thu Jul 6 2000 Nalin Dahyabhai - Move condrestart to server postun. - Move key generation to init script. - Actually use the right patch for moving the key generation to the init script. - Clean up the init script a bit. * Wed Jul 5 2000 Nalin Dahyabhai - Fix X11 forwarding, from mail post by Chan Shih-Ping Richard. * Sun Jul 2 2000 Nalin Dahyabhai - Update to 2.1.1p2. - Use of strtok() considered harmful. * Sat Jul 1 2000 Nalin Dahyabhai - Get the build root out of the man pages. * Thu Jun 29 2000 Nalin Dahyabhai - Add and use condrestart support in the init script. - Add newer initscripts as a prereq. * Tue Jun 27 2000 Nalin Dahyabhai - Build in new environment (release 2) - Move -clients subpackage to Applications/Internet group * Fri Jun 9 2000 Nalin Dahyabhai - Update to 2.2.1p1 * Sat Jun 3 2000 Nalin Dahyabhai - Patch to build with neither RSA nor RSAref. - Miscellaneous FHS-compliance tweaks. - Fix for possibly-compressed man pages. * Wed Mar 15 2000 Damien Miller - Updated for new location - Updated for new gnome-ssh-askpass build * Sun Dec 26 1999 Damien Miller - Added Jim Knoble's askpass * Mon Nov 15 1999 Damien Miller - Split subpackages further based on patch from jim knoble * Sat Nov 13 1999 Damien Miller - Added 'Obsoletes' directives * Tue Nov 09 1999 Damien Miller - Use make install - Subpackages * Mon Nov 08 1999 Damien Miller - Added links for slogin - Fixed perms on manpages * Sat Oct 30 1999 Damien Miller - Renamed init script * Fri Oct 29 1999 Damien Miller - Back to old binary names * Thu Oct 28 1999 Damien Miller - Use autoconf - New binary names * Wed Oct 27 1999 Damien Miller - Initial RPMification, based on Jan "Yenya" Kasprzak's spec. Index: head/crypto/openssh/contrib/suse/openssh.spec =================================================================== --- head/crypto/openssh/contrib/suse/openssh.spec (revision 294495) +++ head/crypto/openssh/contrib/suse/openssh.spec (revision 294496) @@ -1,243 +1,243 @@ # Default values for additional components %define build_x11_askpass 1 # Define the UID/GID to use for privilege separation %define sshd_gid 65 %define sshd_uid 71 # The version of x11-ssh-askpass to use %define xversion 1.2.4.1 # Allow the ability to override defaults with -D skip_xxx=1 %{?skip_x11_askpass:%define build_x11_askpass 0} Summary: OpenSSH, a free Secure Shell (SSH) protocol implementation Name: openssh -Version: 7.0p1 +Version: 7.1p2 URL: http://www.openssh.com/ Release: 1 Source0: openssh-%{version}.tar.gz Source1: x11-ssh-askpass-%{xversion}.tar.gz License: BSD Group: Productivity/Networking/SSH BuildRoot: %{_tmppath}/openssh-%{version}-buildroot PreReq: openssl Obsoletes: ssh Provides: ssh # # (Build[ing] Prereq[uisites] only work for RPM 2.95 and newer.) # building prerequisites -- stuff for # OpenSSL (openssl-devel), # and Gnome (glibdev, gtkdev, and gnlibsd) # BuildPrereq: openssl BuildPrereq: zlib-devel #BuildPrereq: glibdev #BuildPrereq: gtkdev #BuildPrereq: gnlibsd %package askpass Summary: A passphrase dialog for OpenSSH and the X window System. Group: Productivity/Networking/SSH Requires: openssh = %{version} Obsoletes: ssh-extras Provides: openssh:${_libdir}/ssh/ssh-askpass %if %{build_x11_askpass} BuildPrereq: XFree86-devel %endif %description Ssh (Secure Shell) is a program for logging into a remote machine and for executing commands in a remote machine. It is intended to replace rlogin and rsh, and provide secure encrypted communications between two untrusted hosts over an insecure network. X11 connections and arbitrary TCP/IP ports can also be forwarded over the secure channel. OpenSSH is OpenBSD's rework of the last free version of SSH, bringing it up to date in terms of security and features, as well as removing all patented algorithms to seperate libraries (OpenSSL). This package includes all files necessary for both the OpenSSH client and server. %description askpass Ssh (Secure Shell) is a program for logging into a remote machine and for executing commands in a remote machine. It is intended to replace rlogin and rsh, and provide secure encrypted communications between two untrusted hosts over an insecure network. X11 connections and arbitrary TCP/IP ports can also be forwarded over the secure channel. OpenSSH is OpenBSD's rework of the last free version of SSH, bringing it up to date in terms of security and features, as well as removing all patented algorithms to seperate libraries (OpenSSL). This package contains an X Window System passphrase dialog for OpenSSH. %changelog * Wed Oct 26 2005 Iain Morgan - Removed accidental inclusion of --without-zlib-version-check * Tue Oct 25 2005 Iain Morgan - Overhaul to deal with newer versions of SuSE and OpenSSH * Mon Jun 12 2000 Damien Miller - Glob manpages to catch compressed files * Wed Mar 15 2000 Damien Miller - Updated for new location - Updated for new gnome-ssh-askpass build * Sun Dec 26 1999 Chris Saia - Made symlink to gnome-ssh-askpass called ssh-askpass * Wed Nov 24 1999 Chris Saia - Removed patches that included /etc/pam.d/sshd, /sbin/init.d/rc.sshd, and /var/adm/fillup-templates/rc.config.sshd, since Damien merged these into his released tarfile - Changed permissions on ssh_config in the install procedure to 644 from 600 even though it was correct in the %files section and thus right in the RPMs - Postinstall script for the server now only prints "Generating SSH host key..." if we need to actually do this, in order to eliminate a confusing message if an SSH host key is already in place - Marked all manual pages as %doc(umentation) * Mon Nov 22 1999 Chris Saia - Added flag to configure daemon with TCP Wrappers support - Added building prerequisites (works in RPM 3.0 and newer) * Thu Nov 18 1999 Chris Saia - Made this package correct for SuSE. - Changed instances of pam_pwdb.so to pam_unix.so, since it works more properly with SuSE, and lib_pwdb.so isn't installed by default. * Mon Nov 15 1999 Damien Miller - Split subpackages further based on patch from jim knoble * Sat Nov 13 1999 Damien Miller - Added 'Obsoletes' directives * Tue Nov 09 1999 Damien Miller - Use make install - Subpackages * Mon Nov 08 1999 Damien Miller - Added links for slogin - Fixed perms on manpages * Sat Oct 30 1999 Damien Miller - Renamed init script * Fri Oct 29 1999 Damien Miller - Back to old binary names * Thu Oct 28 1999 Damien Miller - Use autoconf - New binary names * Wed Oct 27 1999 Damien Miller - Initial RPMification, based on Jan "Yenya" Kasprzak's spec. %prep %if %{build_x11_askpass} %setup -q -a 1 %else %setup -q %endif %build CFLAGS="$RPM_OPT_FLAGS" \ %configure --prefix=/usr \ --sysconfdir=%{_sysconfdir}/ssh \ --mandir=%{_mandir} \ --with-privsep-path=/var/lib/empty \ --with-pam \ --libexecdir=%{_libdir}/ssh make %if %{build_x11_askpass} cd x11-ssh-askpass-%{xversion} %configure --mandir=/usr/X11R6/man \ --libexecdir=%{_libdir}/ssh xmkmf -a make cd .. %endif %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT/ install -d $RPM_BUILD_ROOT/etc/pam.d/ install -d $RPM_BUILD_ROOT/etc/init.d/ install -d $RPM_BUILD_ROOT/var/adm/fillup-templates install -m644 contrib/sshd.pam.generic $RPM_BUILD_ROOT/etc/pam.d/sshd install -m744 contrib/suse/rc.sshd $RPM_BUILD_ROOT/etc/init.d/sshd install -m744 contrib/suse/sysconfig.ssh \ $RPM_BUILD_ROOT/var/adm/fillup-templates %if %{build_x11_askpass} cd x11-ssh-askpass-%{xversion} make install install.man BINDIR=%{_libdir}/ssh DESTDIR=$RPM_BUILD_ROOT/ rm -f $RPM_BUILD_ROOT/usr/share/Ssh.bin %endif %clean rm -rf $RPM_BUILD_ROOT %pre /usr/sbin/groupadd -g %{sshd_gid} -o -r sshd 2> /dev/null || : /usr/sbin/useradd -r -o -g sshd -u %{sshd_uid} -s /bin/false -c "SSH Privilege Separation User" -d /var/lib/sshd sshd 2> /dev/null || : %post /usr/bin/ssh-keygen -A %{fillup_and_insserv -n -y ssh sshd} %run_permissions %verifyscript %verify_permissions -e /etc/ssh/sshd_config -e /etc/ssh/ssh_config -e /usr/bin/ssh %preun %stop_on_removal sshd %postun %restart_on_update sshd %{insserv_cleanup} %files %defattr(-,root,root) %doc ChangeLog OVERVIEW README* PROTOCOL* %doc TODO CREDITS LICENCE %attr(0755,root,root) %dir %{_sysconfdir}/ssh %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ssh/ssh_config %attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ssh/sshd_config %attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ssh/moduli %attr(0644,root,root) %config(noreplace) /etc/pam.d/sshd %attr(0755,root,root) %config /etc/init.d/sshd %attr(0755,root,root) %{_bindir}/ssh-keygen %attr(0755,root,root) %{_bindir}/scp %attr(0755,root,root) %{_bindir}/ssh %attr(-,root,root) %{_bindir}/slogin %attr(0755,root,root) %{_bindir}/ssh-agent %attr(0755,root,root) %{_bindir}/ssh-add %attr(0755,root,root) %{_bindir}/ssh-keyscan %attr(0755,root,root) %{_bindir}/sftp %attr(0755,root,root) %{_sbindir}/sshd %attr(0755,root,root) %dir %{_libdir}/ssh %attr(0755,root,root) %{_libdir}/ssh/sftp-server %attr(4711,root,root) %{_libdir}/ssh/ssh-keysign %attr(0755,root,root) %{_libdir}/ssh/ssh-pkcs11-helper %attr(0644,root,root) %doc %{_mandir}/man1/scp.1* %attr(0644,root,root) %doc %{_mandir}/man1/sftp.1* %attr(-,root,root) %doc %{_mandir}/man1/slogin.1* %attr(0644,root,root) %doc %{_mandir}/man1/ssh.1* %attr(0644,root,root) %doc %{_mandir}/man1/ssh-add.1* %attr(0644,root,root) %doc %{_mandir}/man1/ssh-agent.1* %attr(0644,root,root) %doc %{_mandir}/man1/ssh-keygen.1* %attr(0644,root,root) %doc %{_mandir}/man1/ssh-keyscan.1* %attr(0644,root,root) %doc %{_mandir}/man5/moduli.5* %attr(0644,root,root) %doc %{_mandir}/man5/ssh_config.5* %attr(0644,root,root) %doc %{_mandir}/man5/sshd_config.5* %attr(0644,root,root) %doc %{_mandir}/man8/sftp-server.8* %attr(0644,root,root) %doc %{_mandir}/man8/ssh-keysign.8* %attr(0644,root,root) %doc %{_mandir}/man8/ssh-pkcs11-helper.8* %attr(0644,root,root) %doc %{_mandir}/man8/sshd.8* %attr(0644,root,root) /var/adm/fillup-templates/sysconfig.ssh %if %{build_x11_askpass} %files askpass %defattr(-,root,root) %doc x11-ssh-askpass-%{xversion}/README %doc x11-ssh-askpass-%{xversion}/ChangeLog %doc x11-ssh-askpass-%{xversion}/SshAskpass*.ad %attr(0755,root,root) %{_libdir}/ssh/ssh-askpass %attr(0755,root,root) %{_libdir}/ssh/x11-ssh-askpass %attr(0644,root,root) %doc /usr/X11R6/man/man1/ssh-askpass.1x* %attr(0644,root,root) %doc /usr/X11R6/man/man1/x11-ssh-askpass.1x* %attr(0644,root,root) %config /usr/X11R6/lib/X11/app-defaults/SshAskpass %endif Index: head/crypto/openssh/dns.c =================================================================== --- head/crypto/openssh/dns.c (revision 294495) +++ head/crypto/openssh/dns.c (revision 294496) @@ -1,351 +1,351 @@ -/* $OpenBSD: dns.c,v 1.34 2015/01/28 22:36:00 djm Exp $ */ +/* $OpenBSD: dns.c,v 1.35 2015/08/20 22:32:42 deraadt Exp $ */ /* * Copyright (c) 2003 Wesley Griffin. All rights reserved. * Copyright (c) 2003 Jakob Schlyter. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" #include #include #include #include #include #include #include #include #include "xmalloc.h" #include "sshkey.h" #include "ssherr.h" #include "dns.h" #include "log.h" #include "digest.h" static const char *errset_text[] = { "success", /* 0 ERRSET_SUCCESS */ "out of memory", /* 1 ERRSET_NOMEMORY */ "general failure", /* 2 ERRSET_FAIL */ "invalid parameter", /* 3 ERRSET_INVAL */ "name does not exist", /* 4 ERRSET_NONAME */ "data does not exist", /* 5 ERRSET_NODATA */ }; static const char * dns_result_totext(unsigned int res) { switch (res) { case ERRSET_SUCCESS: return errset_text[ERRSET_SUCCESS]; case ERRSET_NOMEMORY: return errset_text[ERRSET_NOMEMORY]; case ERRSET_FAIL: return errset_text[ERRSET_FAIL]; case ERRSET_INVAL: return errset_text[ERRSET_INVAL]; case ERRSET_NONAME: return errset_text[ERRSET_NONAME]; case ERRSET_NODATA: return errset_text[ERRSET_NODATA]; default: return "unknown error"; } } /* * Read SSHFP parameters from key buffer. */ static int dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, u_char **digest, size_t *digest_len, struct sshkey *key) { int r, success = 0; int fp_alg = -1; switch (key->type) { case KEY_RSA: *algorithm = SSHFP_KEY_RSA; if (!*digest_type) *digest_type = SSHFP_HASH_SHA1; break; case KEY_DSA: *algorithm = SSHFP_KEY_DSA; if (!*digest_type) *digest_type = SSHFP_HASH_SHA1; break; case KEY_ECDSA: *algorithm = SSHFP_KEY_ECDSA; if (!*digest_type) *digest_type = SSHFP_HASH_SHA256; break; case KEY_ED25519: *algorithm = SSHFP_KEY_ED25519; if (!*digest_type) *digest_type = SSHFP_HASH_SHA256; break; default: *algorithm = SSHFP_KEY_RESERVED; /* 0 */ *digest_type = SSHFP_HASH_RESERVED; /* 0 */ } switch (*digest_type) { case SSHFP_HASH_SHA1: fp_alg = SSH_DIGEST_SHA1; break; case SSHFP_HASH_SHA256: fp_alg = SSH_DIGEST_SHA256; break; default: *digest_type = SSHFP_HASH_RESERVED; /* 0 */ } if (*algorithm && *digest_type) { if ((r = sshkey_fingerprint_raw(key, fp_alg, digest, digest_len)) != 0) fatal("%s: sshkey_fingerprint_raw: %s", __func__, ssh_err(r)); success = 1; } else { *digest = NULL; *digest_len = 0; success = 0; } return success; } /* * Read SSHFP parameters from rdata buffer. */ static int dns_read_rdata(u_int8_t *algorithm, u_int8_t *digest_type, u_char **digest, size_t *digest_len, u_char *rdata, int rdata_len) { int success = 0; *algorithm = SSHFP_KEY_RESERVED; *digest_type = SSHFP_HASH_RESERVED; if (rdata_len >= 2) { *algorithm = rdata[0]; *digest_type = rdata[1]; *digest_len = rdata_len - 2; if (*digest_len > 0) { - *digest = (u_char *) xmalloc(*digest_len); + *digest = xmalloc(*digest_len); memcpy(*digest, rdata + 2, *digest_len); } else { *digest = (u_char *)xstrdup(""); } success = 1; } return success; } /* * Check if hostname is numerical. * Returns -1 if hostname is numeric, 0 otherwise */ static int is_numeric_hostname(const char *hostname) { struct addrinfo hints, *ai; /* * We shouldn't ever get a null host but if we do then log an error * and return -1 which stops DNS key fingerprint processing. */ if (hostname == NULL) { error("is_numeric_hostname called with NULL hostname"); return -1; } memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_NUMERICHOST; if (getaddrinfo(hostname, NULL, &hints, &ai) == 0) { freeaddrinfo(ai); return -1; } return 0; } /* * Verify the given hostname, address and host key using DNS. * Returns 0 if lookup succeeds, -1 otherwise */ int verify_host_key_dns(const char *hostname, struct sockaddr *address, struct sshkey *hostkey, int *flags) { u_int counter; int result; struct rrsetinfo *fingerprints = NULL; u_int8_t hostkey_algorithm; u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED; u_char *hostkey_digest; size_t hostkey_digest_len; u_int8_t dnskey_algorithm; u_int8_t dnskey_digest_type; u_char *dnskey_digest; size_t dnskey_digest_len; *flags = 0; debug3("verify_host_key_dns"); if (hostkey == NULL) fatal("No key to look up!"); if (is_numeric_hostname(hostname)) { debug("skipped DNS lookup for numerical hostname"); return -1; } result = getrrsetbyname(hostname, DNS_RDATACLASS_IN, DNS_RDATATYPE_SSHFP, 0, &fingerprints); if (result) { verbose("DNS lookup error: %s", dns_result_totext(result)); return -1; } if (fingerprints->rri_flags & RRSET_VALIDATED) { *flags |= DNS_VERIFY_SECURE; debug("found %d secure fingerprints in DNS", fingerprints->rri_nrdatas); } else { debug("found %d insecure fingerprints in DNS", fingerprints->rri_nrdatas); } /* Initialize default host key parameters */ if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, &hostkey_digest, &hostkey_digest_len, hostkey)) { error("Error calculating host key fingerprint."); freerrset(fingerprints); return -1; } if (fingerprints->rri_nrdatas) *flags |= DNS_VERIFY_FOUND; for (counter = 0; counter < fingerprints->rri_nrdatas; counter++) { /* * Extract the key from the answer. Ignore any badly * formatted fingerprints. */ if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type, &dnskey_digest, &dnskey_digest_len, fingerprints->rri_rdatas[counter].rdi_data, fingerprints->rri_rdatas[counter].rdi_length)) { verbose("Error parsing fingerprint from DNS."); continue; } if (hostkey_digest_type != dnskey_digest_type) { hostkey_digest_type = dnskey_digest_type; free(hostkey_digest); /* Initialize host key parameters */ if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, &hostkey_digest, &hostkey_digest_len, hostkey)) { error("Error calculating key fingerprint."); freerrset(fingerprints); return -1; } } /* Check if the current key is the same as the given key */ if (hostkey_algorithm == dnskey_algorithm && hostkey_digest_type == dnskey_digest_type) { if (hostkey_digest_len == dnskey_digest_len && timingsafe_bcmp(hostkey_digest, dnskey_digest, hostkey_digest_len) == 0) *flags |= DNS_VERIFY_MATCH; } free(dnskey_digest); } free(hostkey_digest); /* from sshkey_fingerprint_raw() */ freerrset(fingerprints); if (*flags & DNS_VERIFY_FOUND) if (*flags & DNS_VERIFY_MATCH) debug("matching host key fingerprint found in DNS"); else debug("mismatching host key fingerprint found in DNS"); else debug("no host key fingerprint found in DNS"); return 0; } /* * Export the fingerprint of a key as a DNS resource record */ int export_dns_rr(const char *hostname, struct sshkey *key, FILE *f, int generic) { u_int8_t rdata_pubkey_algorithm = 0; u_int8_t rdata_digest_type = SSHFP_HASH_RESERVED; u_int8_t dtype; u_char *rdata_digest; size_t i, rdata_digest_len; int success = 0; for (dtype = SSHFP_HASH_SHA1; dtype < SSHFP_HASH_MAX; dtype++) { rdata_digest_type = dtype; if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type, &rdata_digest, &rdata_digest_len, key)) { if (generic) { fprintf(f, "%s IN TYPE%d \\# %zu %02x %02x ", hostname, DNS_RDATATYPE_SSHFP, 2 + rdata_digest_len, rdata_pubkey_algorithm, rdata_digest_type); } else { fprintf(f, "%s IN SSHFP %d %d ", hostname, rdata_pubkey_algorithm, rdata_digest_type); } for (i = 0; i < rdata_digest_len; i++) fprintf(f, "%02x", rdata_digest[i]); fprintf(f, "\n"); free(rdata_digest); /* from sshkey_fingerprint_raw() */ success = 1; } } /* No SSHFP record was generated at all */ if (success == 0) { error("%s: unsupported algorithm and/or digest_type", __func__); } return success; } Index: head/crypto/openssh/kex.c =================================================================== --- head/crypto/openssh/kex.c (revision 294495) +++ head/crypto/openssh/kex.c (revision 294496) @@ -1,915 +1,915 @@ /* $OpenBSD: kex.c,v 1.109 2015/07/30 00:01:34 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" #include /* MAX roundup */ #include #include #include #include #include #ifdef WITH_OPENSSL #include #endif #include "ssh2.h" #include "packet.h" #include "compat.h" #include "cipher.h" #include "sshkey.h" #include "kex.h" #include "log.h" #include "mac.h" #include "match.h" #include "misc.h" #include "dispatch.h" #include "monitor.h" #include "roaming.h" #include "ssherr.h" #include "sshbuf.h" #include "digest.h" #if OPENSSL_VERSION_NUMBER >= 0x00907000L # if defined(HAVE_EVP_SHA256) # define evp_ssh_sha256 EVP_sha256 # else extern const EVP_MD *evp_ssh_sha256(void); # endif #endif /* prototype */ static int kex_choose_conf(struct ssh *); static int kex_input_newkeys(int, u_int32_t, void *); struct kexalg { char *name; u_int type; int ec_nid; int hash_alg; }; static const struct kexalg kexalgs[] = { #ifdef WITH_OPENSSL { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, { KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, #ifdef HAVE_EVP_SHA256 { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, #endif /* HAVE_EVP_SHA256 */ #ifdef OPENSSL_HAS_ECC { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, SSH_DIGEST_SHA384 }, # ifdef OPENSSL_HAS_NISTP521 { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, SSH_DIGEST_SHA512 }, # endif /* OPENSSL_HAS_NISTP521 */ #endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ #if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL) { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ { NULL, -1, -1, -1}, }; char * kex_alg_list(char sep) { char *ret = NULL, *tmp; size_t nlen, rlen = 0; const struct kexalg *k; for (k = kexalgs; k->name != NULL; k++) { if (ret != NULL) ret[rlen++] = sep; nlen = strlen(k->name); if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { free(ret); return NULL; } ret = tmp; memcpy(ret + rlen, k->name, nlen + 1); rlen += nlen; } return ret; } static const struct kexalg * kex_alg_by_name(const char *name) { const struct kexalg *k; for (k = kexalgs; k->name != NULL; k++) { if (strcmp(k->name, name) == 0) return k; } return NULL; } /* Validate KEX method name list */ int kex_names_valid(const char *names) { char *s, *cp, *p; if (names == NULL || strcmp(names, "") == 0) return 0; if ((s = cp = strdup(names)) == NULL) return 0; for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { if (kex_alg_by_name(p) == NULL) { error("Unsupported KEX algorithm \"%.100s\"", p); free(s); return 0; } } debug3("kex names ok: [%s]", names); free(s); return 1; } /* * Concatenate algorithm names, avoiding duplicates in the process. * Caller must free returned string. */ char * kex_names_cat(const char *a, const char *b) { char *ret = NULL, *tmp = NULL, *cp, *p; size_t len; if (a == NULL || *a == '\0') return NULL; if (b == NULL || *b == '\0') return strdup(a); if (strlen(b) > 1024*1024) return NULL; len = strlen(a) + strlen(b) + 2; if ((tmp = cp = strdup(b)) == NULL || (ret = calloc(1, len)) == NULL) { free(tmp); return NULL; } strlcpy(ret, a, len); for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { if (match_list(ret, p, NULL) != NULL) continue; /* Algorithm already present */ if (strlcat(ret, ",", len) >= len || strlcat(ret, p, len) >= len) { free(tmp); free(ret); return NULL; /* Shouldn't happen */ } } free(tmp); return ret; } /* * Assemble a list of algorithms from a default list and a string from a * configuration file. The user-provided string may begin with '+' to * indicate that it should be appended to the default. */ int kex_assemble_names(const char *def, char **list) { char *ret; if (list == NULL || *list == NULL || **list == '\0') { *list = strdup(def); return 0; } if (**list != '+') { return 0; } if ((ret = kex_names_cat(def, *list + 1)) == NULL) return SSH_ERR_ALLOC_FAIL; free(*list); *list = ret; return 0; } /* put algorithm proposal into buffer */ int kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX]) { u_int i; int r; sshbuf_reset(b); /* * add a dummy cookie, the cookie will be overwritten by * kex_send_kexinit(), each time a kexinit is set */ for (i = 0; i < KEX_COOKIE_LEN; i++) { if ((r = sshbuf_put_u8(b, 0)) != 0) return r; } for (i = 0; i < PROPOSAL_MAX; i++) { if ((r = sshbuf_put_cstring(b, proposal[i])) != 0) return r; } if ((r = sshbuf_put_u8(b, 0)) != 0 || /* first_kex_packet_follows */ (r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */ return r; return 0; } /* parse buffer and return algorithm proposal */ int kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp) { struct sshbuf *b = NULL; u_char v; u_int i; char **proposal = NULL; int r; *propp = NULL; if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL) return SSH_ERR_ALLOC_FAIL; if ((b = sshbuf_fromb(raw)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */ goto out; /* extract kex init proposal strings */ for (i = 0; i < PROPOSAL_MAX; i++) { if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) goto out; debug2("kex_parse_kexinit: %s", proposal[i]); } /* first kex follows / reserved */ - if ((r = sshbuf_get_u8(b, &v)) != 0 || - (r = sshbuf_get_u32(b, &i)) != 0) + if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */ + (r = sshbuf_get_u32(b, &i)) != 0) /* reserved */ goto out; if (first_kex_follows != NULL) - *first_kex_follows = i; - debug2("kex_parse_kexinit: first_kex_follows %d ", v); - debug2("kex_parse_kexinit: reserved %u ", i); + *first_kex_follows = v; + debug2("first_kex_follows %d ", v); + debug2("reserved %u ", i); r = 0; *propp = proposal; out: if (r != 0 && proposal != NULL) kex_prop_free(proposal); sshbuf_free(b); return r; } void kex_prop_free(char **proposal) { u_int i; if (proposal == NULL) return; for (i = 0; i < PROPOSAL_MAX; i++) free(proposal[i]); free(proposal); } /* ARGSUSED */ static int kex_protocol_error(int type, u_int32_t seq, void *ctxt) { error("Hm, kex protocol error: type %d seq %u", type, seq); return 0; } static void kex_reset_dispatch(struct ssh *ssh) { ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN, SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); } int kex_send_newkeys(struct ssh *ssh) { int r; kex_reset_dispatch(ssh); if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 || (r = sshpkt_send(ssh)) != 0) return r; debug("SSH2_MSG_NEWKEYS sent"); debug("expecting SSH2_MSG_NEWKEYS"); ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); return 0; } static int kex_input_newkeys(int type, u_int32_t seq, void *ctxt) { struct ssh *ssh = ctxt; struct kex *kex = ssh->kex; int r; debug("SSH2_MSG_NEWKEYS received"); ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error); if ((r = sshpkt_get_end(ssh)) != 0) return r; kex->done = 1; sshbuf_reset(kex->peer); /* sshbuf_reset(kex->my); */ kex->flags &= ~KEX_INIT_SENT; free(kex->name); kex->name = NULL; return 0; } int kex_send_kexinit(struct ssh *ssh) { u_char *cookie; struct kex *kex = ssh->kex; int r; if (kex == NULL) return SSH_ERR_INTERNAL_ERROR; if (kex->flags & KEX_INIT_SENT) return 0; kex->done = 0; /* generate a random cookie */ if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) return SSH_ERR_INVALID_FORMAT; if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) return SSH_ERR_INTERNAL_ERROR; arc4random_buf(cookie, KEX_COOKIE_LEN); if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || (r = sshpkt_putb(ssh, kex->my)) != 0 || (r = sshpkt_send(ssh)) != 0) return r; debug("SSH2_MSG_KEXINIT sent"); kex->flags |= KEX_INIT_SENT; return 0; } /* ARGSUSED */ int kex_input_kexinit(int type, u_int32_t seq, void *ctxt) { struct ssh *ssh = ctxt; struct kex *kex = ssh->kex; const u_char *ptr; u_int i; size_t dlen; int r; debug("SSH2_MSG_KEXINIT received"); if (kex == NULL) return SSH_ERR_INVALID_ARGUMENT; ptr = sshpkt_ptr(ssh, &dlen); if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) return r; /* discard packet */ for (i = 0; i < KEX_COOKIE_LEN; i++) if ((r = sshpkt_get_u8(ssh, NULL)) != 0) return r; for (i = 0; i < PROPOSAL_MAX; i++) if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) return r; /* * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported * KEX method has the server move first, but a server might be using * a custom method or one that we otherwise don't support. We should * be prepared to remember first_kex_follows here so we can eat a * packet later. * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means * for cases where the server *doesn't* go first. I guess we should * ignore it when it is set for these cases, which is what we do now. */ if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */ (r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */ (r = sshpkt_get_end(ssh)) != 0) return r; if (!(kex->flags & KEX_INIT_SENT)) if ((r = kex_send_kexinit(ssh)) != 0) return r; if ((r = kex_choose_conf(ssh)) != 0) return r; if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) return (kex->kex[kex->kex_type])(ssh); return SSH_ERR_INTERNAL_ERROR; } int kex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp) { struct kex *kex; int r; *kexp = NULL; if ((kex = calloc(1, sizeof(*kex))) == NULL) return SSH_ERR_ALLOC_FAIL; if ((kex->peer = sshbuf_new()) == NULL || (kex->my = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = kex_prop2buf(kex->my, proposal)) != 0) goto out; kex->done = 0; kex_reset_dispatch(ssh); r = 0; *kexp = kex; out: if (r != 0) kex_free(kex); return r; } void kex_free_newkeys(struct newkeys *newkeys) { if (newkeys == NULL) return; if (newkeys->enc.key) { explicit_bzero(newkeys->enc.key, newkeys->enc.key_len); free(newkeys->enc.key); newkeys->enc.key = NULL; } if (newkeys->enc.iv) { explicit_bzero(newkeys->enc.iv, newkeys->enc.block_size); free(newkeys->enc.iv); newkeys->enc.iv = NULL; } free(newkeys->enc.name); explicit_bzero(&newkeys->enc, sizeof(newkeys->enc)); free(newkeys->comp.name); explicit_bzero(&newkeys->comp, sizeof(newkeys->comp)); mac_clear(&newkeys->mac); if (newkeys->mac.key) { explicit_bzero(newkeys->mac.key, newkeys->mac.key_len); free(newkeys->mac.key); newkeys->mac.key = NULL; } free(newkeys->mac.name); explicit_bzero(&newkeys->mac, sizeof(newkeys->mac)); explicit_bzero(newkeys, sizeof(*newkeys)); free(newkeys); } void kex_free(struct kex *kex) { u_int mode; #ifdef WITH_OPENSSL if (kex->dh) DH_free(kex->dh); #ifdef OPENSSL_HAS_ECC if (kex->ec_client_key) EC_KEY_free(kex->ec_client_key); #endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ for (mode = 0; mode < MODE_MAX; mode++) { kex_free_newkeys(kex->newkeys[mode]); kex->newkeys[mode] = NULL; } sshbuf_free(kex->peer); sshbuf_free(kex->my); free(kex->session_id); free(kex->client_version_string); free(kex->server_version_string); free(kex->failed_choice); free(kex); } int kex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) { int r; if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0) return r; if ((r = kex_send_kexinit(ssh)) != 0) { /* we start */ kex_free(ssh->kex); ssh->kex = NULL; return r; } return 0; } static int choose_enc(struct sshenc *enc, char *client, char *server) { char *name = match_list(client, server, NULL); if (name == NULL) return SSH_ERR_NO_CIPHER_ALG_MATCH; if ((enc->cipher = cipher_by_name(name)) == NULL) return SSH_ERR_INTERNAL_ERROR; enc->name = name; enc->enabled = 0; enc->iv = NULL; enc->iv_len = cipher_ivlen(enc->cipher); enc->key = NULL; enc->key_len = cipher_keylen(enc->cipher); enc->block_size = cipher_blocksize(enc->cipher); return 0; } static int choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) { char *name = match_list(client, server, NULL); if (name == NULL) return SSH_ERR_NO_MAC_ALG_MATCH; if (mac_setup(mac, name) < 0) return SSH_ERR_INTERNAL_ERROR; /* truncate the key */ if (ssh->compat & SSH_BUG_HMAC) mac->key_len = 16; mac->name = name; mac->key = NULL; mac->enabled = 0; return 0; } static int choose_comp(struct sshcomp *comp, char *client, char *server) { char *name = match_list(client, server, NULL); if (name == NULL) return SSH_ERR_NO_COMPRESS_ALG_MATCH; if (strcmp(name, "zlib@openssh.com") == 0) { comp->type = COMP_DELAYED; } else if (strcmp(name, "zlib") == 0) { comp->type = COMP_ZLIB; } else if (strcmp(name, "none") == 0) { comp->type = COMP_NONE; } else { return SSH_ERR_INTERNAL_ERROR; } comp->name = name; return 0; } static int choose_kex(struct kex *k, char *client, char *server) { const struct kexalg *kexalg; k->name = match_list(client, server, NULL); if (k->name == NULL) return SSH_ERR_NO_KEX_ALG_MATCH; if ((kexalg = kex_alg_by_name(k->name)) == NULL) return SSH_ERR_INTERNAL_ERROR; k->kex_type = kexalg->type; k->hash_alg = kexalg->hash_alg; k->ec_nid = kexalg->ec_nid; return 0; } static int choose_hostkeyalg(struct kex *k, char *client, char *server) { char *hostkeyalg = match_list(client, server, NULL); if (hostkeyalg == NULL) return SSH_ERR_NO_HOSTKEY_ALG_MATCH; k->hostkey_type = sshkey_type_from_name(hostkeyalg); if (k->hostkey_type == KEY_UNSPEC) return SSH_ERR_INTERNAL_ERROR; k->hostkey_nid = sshkey_ecdsa_nid_from_name(hostkeyalg); free(hostkeyalg); return 0; } static int proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) { static int check[] = { PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 }; int *idx; char *p; for (idx = &check[0]; *idx != -1; idx++) { if ((p = strchr(my[*idx], ',')) != NULL) *p = '\0'; if ((p = strchr(peer[*idx], ',')) != NULL) *p = '\0'; if (strcmp(my[*idx], peer[*idx]) != 0) { debug2("proposal mismatch: my %s peer %s", my[*idx], peer[*idx]); return (0); } } debug2("proposals match"); return (1); } static int kex_choose_conf(struct ssh *ssh) { struct kex *kex = ssh->kex; struct newkeys *newkeys; char **my = NULL, **peer = NULL; char **cprop, **sprop; int nenc, nmac, ncomp; u_int mode, ctos, need, dh_need, authlen; int r, first_kex_follows; if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0 || (r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) goto out; if (kex->server) { cprop=peer; sprop=my; } else { cprop=my; sprop=peer; } /* Check whether server offers roaming */ if (!kex->server) { char *roaming = match_list(KEX_RESUME, peer[PROPOSAL_KEX_ALGS], NULL); if (roaming) { kex->roaming = 1; free(roaming); } } /* Algorithm Negotiation */ for (mode = 0; mode < MODE_MAX; mode++) { if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } kex->newkeys[mode] = newkeys; ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; if ((r = choose_enc(&newkeys->enc, cprop[nenc], sprop[nenc])) != 0) { kex->failed_choice = peer[nenc]; peer[nenc] = NULL; goto out; } authlen = cipher_authlen(newkeys->enc.cipher); /* ignore mac for authenticated encryption */ if (authlen == 0 && (r = choose_mac(ssh, &newkeys->mac, cprop[nmac], sprop[nmac])) != 0) { kex->failed_choice = peer[nmac]; peer[nmac] = NULL; goto out; } if ((r = choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp])) != 0) { kex->failed_choice = peer[ncomp]; peer[ncomp] = NULL; goto out; } debug("kex: %s %s %s %s", ctos ? "client->server" : "server->client", newkeys->enc.name, authlen == 0 ? newkeys->mac.name : "", newkeys->comp.name); } if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS])) != 0) { kex->failed_choice = peer[PROPOSAL_KEX_ALGS]; peer[PROPOSAL_KEX_ALGS] = NULL; goto out; } if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) { kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS]; peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL; goto out; } need = dh_need = 0; for (mode = 0; mode < MODE_MAX; mode++) { newkeys = kex->newkeys[mode]; need = MAX(need, newkeys->enc.key_len); need = MAX(need, newkeys->enc.block_size); need = MAX(need, newkeys->enc.iv_len); need = MAX(need, newkeys->mac.key_len); dh_need = MAX(dh_need, cipher_seclen(newkeys->enc.cipher)); dh_need = MAX(dh_need, newkeys->enc.block_size); dh_need = MAX(dh_need, newkeys->enc.iv_len); dh_need = MAX(dh_need, newkeys->mac.key_len); } /* XXX need runden? */ kex->we_need = need; kex->dh_need = dh_need; /* ignore the next message if the proposals do not match */ if (first_kex_follows && !proposals_match(my, peer) && !(ssh->compat & SSH_BUG_FIRSTKEX)) ssh->dispatch_skip_packets = 1; r = 0; out: kex_prop_free(my); kex_prop_free(peer); return r; } static int derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, const struct sshbuf *shared_secret, u_char **keyp) { struct kex *kex = ssh->kex; struct ssh_digest_ctx *hashctx = NULL; char c = id; u_int have; size_t mdsz; u_char *digest; int r; if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) return SSH_ERR_INVALID_ARGUMENT; if ((digest = calloc(1, roundup(need, mdsz))) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } /* K1 = HASH(K || H || "A" || session_id) */ if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || ssh_digest_update_buffer(hashctx, shared_secret) != 0 || ssh_digest_update(hashctx, hash, hashlen) != 0 || ssh_digest_update(hashctx, &c, 1) != 0 || ssh_digest_update(hashctx, kex->session_id, kex->session_id_len) != 0 || ssh_digest_final(hashctx, digest, mdsz) != 0) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } ssh_digest_free(hashctx); hashctx = NULL; /* * expand key: * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) * Key = K1 || K2 || ... || Kn */ for (have = mdsz; need > have; have += mdsz) { if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || ssh_digest_update_buffer(hashctx, shared_secret) != 0 || ssh_digest_update(hashctx, hash, hashlen) != 0 || ssh_digest_update(hashctx, digest, have) != 0 || ssh_digest_final(hashctx, digest + have, mdsz) != 0) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } ssh_digest_free(hashctx); hashctx = NULL; } #ifdef DEBUG_KEX fprintf(stderr, "key '%c'== ", c); dump_digest("key", digest, need); #endif *keyp = digest; digest = NULL; r = 0; out: if (digest) free(digest); ssh_digest_free(hashctx); return r; } #define NKEYS 6 int kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen, const struct sshbuf *shared_secret) { struct kex *kex = ssh->kex; u_char *keys[NKEYS]; u_int i, j, mode, ctos; int r; for (i = 0; i < NKEYS; i++) { if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen, shared_secret, &keys[i])) != 0) { for (j = 0; j < i; j++) free(keys[j]); return r; } } for (mode = 0; mode < MODE_MAX; mode++) { ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); kex->newkeys[mode]->enc.iv = keys[ctos ? 0 : 1]; kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3]; kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5]; } return 0; } #ifdef WITH_OPENSSL int kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen, const BIGNUM *secret) { struct sshbuf *shared_secret; int r; if ((shared_secret = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0) r = kex_derive_keys(ssh, hash, hashlen, shared_secret); sshbuf_free(shared_secret); return r; } #endif #ifdef WITH_SSH1 int derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, u_int8_t cookie[8], u_int8_t id[16]) { u_int8_t hbuf[2048], sbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH]; struct ssh_digest_ctx *hashctx = NULL; size_t hlen, slen; int r; hlen = BN_num_bytes(host_modulus); slen = BN_num_bytes(server_modulus); if (hlen < (512 / 8) || (u_int)hlen > sizeof(hbuf) || slen < (512 / 8) || (u_int)slen > sizeof(sbuf)) return SSH_ERR_KEY_BITS_MISMATCH; if (BN_bn2bin(host_modulus, hbuf) <= 0 || BN_bn2bin(server_modulus, sbuf) <= 0) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if (ssh_digest_update(hashctx, hbuf, hlen) != 0 || ssh_digest_update(hashctx, sbuf, slen) != 0 || ssh_digest_update(hashctx, cookie, 8) != 0 || ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5)); r = 0; out: ssh_digest_free(hashctx); explicit_bzero(hbuf, sizeof(hbuf)); explicit_bzero(sbuf, sizeof(sbuf)); explicit_bzero(obuf, sizeof(obuf)); return r; } #endif #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) void dump_digest(char *msg, u_char *digest, int len) { fprintf(stderr, "%s\n", msg); sshbuf_dump_data(digest, len, stderr); } #endif Index: head/crypto/openssh/mux.c =================================================================== --- head/crypto/openssh/mux.c (revision 294495) +++ head/crypto/openssh/mux.c (revision 294496) @@ -1,2201 +1,2205 @@ -/* $OpenBSD: mux.c,v 1.53 2015/05/01 04:03:20 djm Exp $ */ +/* $OpenBSD: mux.c,v 1.54 2015/08/19 23:18:26 djm Exp $ */ /* * Copyright (c) 2002-2008 Damien Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* ssh session multiplexing support */ /* * TODO: * - Better signalling from master to slave, especially passing of * error messages * - Better fall-back from mux slave error to new connection. * - ExitOnForwardingFailure * - Maybe extension mechanisms for multi-X11/multi-agent forwarding * - Support ~^Z in mux slaves. * - Inspect or control sessions in master. * - If we ever support the "signal" channel request, send signals on * sessions in master. */ #include "includes.h" __RCSID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_PATHS_H #include #endif #ifdef HAVE_POLL_H #include #else # ifdef HAVE_SYS_POLL_H # include # endif #endif #ifdef HAVE_UTIL_H # include #endif #include "openbsd-compat/sys-queue.h" #include "xmalloc.h" #include "log.h" #include "ssh.h" #include "ssh2.h" #include "pathnames.h" #include "misc.h" #include "match.h" #include "buffer.h" #include "channels.h" #include "msg.h" #include "packet.h" #include "monitor_fdpass.h" #include "sshpty.h" #include "key.h" #include "readconf.h" #include "clientloop.h" /* from ssh.c */ extern int tty_flag; extern Options options; extern int stdin_null_flag; extern char *host; extern int subsystem_flag; extern Buffer command; extern volatile sig_atomic_t quit_pending; extern char *stdio_forward_host; extern int stdio_forward_port; /* Context for session open confirmation callback */ struct mux_session_confirm_ctx { u_int want_tty; u_int want_subsys; u_int want_x_fwd; u_int want_agent_fwd; Buffer cmd; char *term; struct termios tio; char **env; u_int rid; }; /* Context for stdio fwd open confirmation callback */ struct mux_stdio_confirm_ctx { u_int rid; }; /* Context for global channel callback */ struct mux_channel_confirm_ctx { u_int cid; /* channel id */ u_int rid; /* request id */ int fid; /* forward id */ }; /* fd to control socket */ int muxserver_sock = -1; /* client request id */ u_int muxclient_request_id = 0; /* Multiplexing control command */ u_int muxclient_command = 0; /* Set when signalled. */ static volatile sig_atomic_t muxclient_terminate = 0; /* PID of multiplex server */ static u_int muxserver_pid = 0; static Channel *mux_listener_channel = NULL; struct mux_master_state { int hello_rcvd; }; /* mux protocol messages */ #define MUX_MSG_HELLO 0x00000001 #define MUX_C_NEW_SESSION 0x10000002 #define MUX_C_ALIVE_CHECK 0x10000004 #define MUX_C_TERMINATE 0x10000005 #define MUX_C_OPEN_FWD 0x10000006 #define MUX_C_CLOSE_FWD 0x10000007 #define MUX_C_NEW_STDIO_FWD 0x10000008 #define MUX_C_STOP_LISTENING 0x10000009 #define MUX_S_OK 0x80000001 #define MUX_S_PERMISSION_DENIED 0x80000002 #define MUX_S_FAILURE 0x80000003 #define MUX_S_EXIT_MESSAGE 0x80000004 #define MUX_S_ALIVE 0x80000005 #define MUX_S_SESSION_OPENED 0x80000006 #define MUX_S_REMOTE_PORT 0x80000007 #define MUX_S_TTY_ALLOC_FAIL 0x80000008 /* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ #define MUX_FWD_LOCAL 1 #define MUX_FWD_REMOTE 2 #define MUX_FWD_DYNAMIC 3 static void mux_session_confirm(int, int, void *); static void mux_stdio_confirm(int, int, void *); static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *); static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *); static int process_mux_alive_check(u_int, Channel *, Buffer *, Buffer *); static int process_mux_terminate(u_int, Channel *, Buffer *, Buffer *); static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *); static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *); static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *); static int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *); static const struct { u_int type; int (*handler)(u_int, Channel *, Buffer *, Buffer *); } mux_master_handlers[] = { { MUX_MSG_HELLO, process_mux_master_hello }, { MUX_C_NEW_SESSION, process_mux_new_session }, { MUX_C_ALIVE_CHECK, process_mux_alive_check }, { MUX_C_TERMINATE, process_mux_terminate }, { MUX_C_OPEN_FWD, process_mux_open_fwd }, { MUX_C_CLOSE_FWD, process_mux_close_fwd }, { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd }, { MUX_C_STOP_LISTENING, process_mux_stop_listening }, { 0, NULL } }; /* Cleanup callback fired on closure of mux slave _session_ channel */ /* ARGSUSED */ static void mux_master_session_cleanup_cb(int cid, void *unused) { Channel *cc, *c = channel_by_id(cid); debug3("%s: entering for channel %d", __func__, cid); if (c == NULL) fatal("%s: channel_by_id(%i) == NULL", __func__, cid); if (c->ctl_chan != -1) { if ((cc = channel_by_id(c->ctl_chan)) == NULL) fatal("%s: channel %d missing control channel %d", __func__, c->self, c->ctl_chan); c->ctl_chan = -1; cc->remote_id = -1; chan_rcvd_oclose(cc); } channel_cancel_cleanup(c->self); } /* Cleanup callback fired on closure of mux slave _control_ channel */ /* ARGSUSED */ static void mux_master_control_cleanup_cb(int cid, void *unused) { Channel *sc, *c = channel_by_id(cid); debug3("%s: entering for channel %d", __func__, cid); if (c == NULL) fatal("%s: channel_by_id(%i) == NULL", __func__, cid); if (c->remote_id != -1) { if ((sc = channel_by_id(c->remote_id)) == NULL) fatal("%s: channel %d missing session channel %d", __func__, c->self, c->remote_id); c->remote_id = -1; sc->ctl_chan = -1; if (sc->type != SSH_CHANNEL_OPEN && sc->type != SSH_CHANNEL_OPENING) { debug2("%s: channel %d: not open", __func__, sc->self); chan_mark_dead(sc); } else { if (sc->istate == CHAN_INPUT_OPEN) chan_read_failed(sc); if (sc->ostate == CHAN_OUTPUT_OPEN) chan_write_failed(sc); } } channel_cancel_cleanup(c->self); } /* Check mux client environment variables before passing them to mux master. */ static int env_permitted(char *env) { int i, ret; char name[1024], *cp; if ((cp = strchr(env, '=')) == NULL || cp == env) return 0; ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env); if (ret <= 0 || (size_t)ret >= sizeof(name)) { error("env_permitted: name '%.100s...' too long", env); return 0; } for (i = 0; i < options.num_send_env; i++) if (match_pattern(name, options.send_env[i])) return 1; return 0; } /* Mux master protocol message handlers */ static int process_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r) { u_int ver; struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; if (state == NULL) fatal("%s: channel %d: c->mux_ctx == NULL", __func__, c->self); if (state->hello_rcvd) { error("%s: HELLO received twice", __func__); return -1; } if (buffer_get_int_ret(&ver, m) != 0) { malf: error("%s: malformed message", __func__); return -1; } if (ver != SSHMUX_VER) { error("Unsupported multiplexing protocol version %d " "(expected %d)", ver, SSHMUX_VER); return -1; } debug2("%s: channel %d slave version %u", __func__, c->self, ver); /* No extensions are presently defined */ while (buffer_len(m) > 0) { char *name = buffer_get_string_ret(m, NULL); char *value = buffer_get_string_ret(m, NULL); if (name == NULL || value == NULL) { free(name); free(value); goto malf; } debug2("Unrecognised slave extension \"%s\"", name); free(name); free(value); } state->hello_rcvd = 1; return 0; } static int process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r) { Channel *nc; struct mux_session_confirm_ctx *cctx; char *reserved, *cmd, *cp; u_int i, j, len, env_len, escape_char, window, packetmax; int new_fd[3]; /* Reply for SSHMUX_COMMAND_OPEN */ cctx = xcalloc(1, sizeof(*cctx)); cctx->term = NULL; cctx->rid = rid; cmd = reserved = NULL; cctx->env = NULL; env_len = 0; if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || buffer_get_int_ret(&cctx->want_tty, m) != 0 || buffer_get_int_ret(&cctx->want_x_fwd, m) != 0 || buffer_get_int_ret(&cctx->want_agent_fwd, m) != 0 || buffer_get_int_ret(&cctx->want_subsys, m) != 0 || buffer_get_int_ret(&escape_char, m) != 0 || (cctx->term = buffer_get_string_ret(m, &len)) == NULL || (cmd = buffer_get_string_ret(m, &len)) == NULL) { malf: free(cmd); free(reserved); for (j = 0; j < env_len; j++) free(cctx->env[j]); free(cctx->env); free(cctx->term); free(cctx); error("%s: malformed message", __func__); return -1; } free(reserved); reserved = NULL; while (buffer_len(m) > 0) { #define MUX_MAX_ENV_VARS 4096 if ((cp = buffer_get_string_ret(m, &len)) == NULL) goto malf; if (!env_permitted(cp)) { free(cp); continue; } cctx->env = xreallocarray(cctx->env, env_len + 2, sizeof(*cctx->env)); cctx->env[env_len++] = cp; cctx->env[env_len] = NULL; if (env_len > MUX_MAX_ENV_VARS) { error(">%d environment variables received, ignoring " "additional", MUX_MAX_ENV_VARS); break; } } debug2("%s: channel %d: request tty %d, X %d, agent %d, subsys %d, " "term \"%s\", cmd \"%s\", env %u", __func__, c->self, cctx->want_tty, cctx->want_x_fwd, cctx->want_agent_fwd, cctx->want_subsys, cctx->term, cmd, env_len); buffer_init(&cctx->cmd); buffer_append(&cctx->cmd, cmd, strlen(cmd)); free(cmd); cmd = NULL; /* Gather fds from client */ for(i = 0; i < 3; i++) { if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) { error("%s: failed to receive fd %d from slave", __func__, i); for (j = 0; j < i; j++) close(new_fd[j]); for (j = 0; j < env_len; j++) free(cctx->env[j]); free(cctx->env); free(cctx->term); buffer_free(&cctx->cmd); free(cctx); /* prepare reply */ buffer_put_int(r, MUX_S_FAILURE); buffer_put_int(r, rid); buffer_put_cstring(r, "did not receive file descriptors"); return -1; } } debug3("%s: got fds stdin %d, stdout %d, stderr %d", __func__, new_fd[0], new_fd[1], new_fd[2]); /* XXX support multiple child sessions in future */ if (c->remote_id != -1) { debug2("%s: session already open", __func__); /* prepare reply */ buffer_put_int(r, MUX_S_FAILURE); buffer_put_int(r, rid); buffer_put_cstring(r, "Multiple sessions not supported"); cleanup: close(new_fd[0]); close(new_fd[1]); close(new_fd[2]); free(cctx->term); if (env_len != 0) { for (i = 0; i < env_len; i++) free(cctx->env[i]); free(cctx->env); } buffer_free(&cctx->cmd); free(cctx); return 0; } if (options.control_master == SSHCTL_MASTER_ASK || options.control_master == SSHCTL_MASTER_AUTO_ASK) { if (!ask_permission("Allow shared connection to %s? ", host)) { debug2("%s: session refused by user", __func__); /* prepare reply */ buffer_put_int(r, MUX_S_PERMISSION_DENIED); buffer_put_int(r, rid); buffer_put_cstring(r, "Permission denied"); goto cleanup; } } /* Try to pick up ttymodes from client before it goes raw */ if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) error("%s: tcgetattr: %s", __func__, strerror(errno)); /* enable nonblocking unless tty */ if (!isatty(new_fd[0])) set_nonblock(new_fd[0]); if (!isatty(new_fd[1])) set_nonblock(new_fd[1]); if (!isatty(new_fd[2])) set_nonblock(new_fd[2]); window = CHAN_SES_WINDOW_DEFAULT; packetmax = CHAN_SES_PACKET_DEFAULT; if (cctx->want_tty) { window >>= 1; packetmax >>= 1; } nc = channel_new("session", SSH_CHANNEL_OPENING, new_fd[0], new_fd[1], new_fd[2], window, packetmax, CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); nc->ctl_chan = c->self; /* link session -> control channel */ c->remote_id = nc->self; /* link control -> session channel */ if (cctx->want_tty && escape_char != 0xffffffff) { channel_register_filter(nc->self, client_simple_escape_filter, NULL, client_filter_cleanup, client_new_escape_filter_ctx((int)escape_char)); } debug2("%s: channel_new: %d linked to control channel %d", __func__, nc->self, nc->ctl_chan); channel_send_open(nc->self); channel_register_open_confirm(nc->self, mux_session_confirm, cctx); c->mux_pause = 1; /* stop handling messages until open_confirm done */ channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); /* reply is deferred, sent by mux_session_confirm */ return 0; } static int process_mux_alive_check(u_int rid, Channel *c, Buffer *m, Buffer *r) { debug2("%s: channel %d: alive check", __func__, c->self); /* prepare reply */ buffer_put_int(r, MUX_S_ALIVE); buffer_put_int(r, rid); buffer_put_int(r, (u_int)getpid()); return 0; } static int process_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r) { debug2("%s: channel %d: terminate request", __func__, c->self); if (options.control_master == SSHCTL_MASTER_ASK || options.control_master == SSHCTL_MASTER_AUTO_ASK) { if (!ask_permission("Terminate shared connection to %s? ", host)) { debug2("%s: termination refused by user", __func__); buffer_put_int(r, MUX_S_PERMISSION_DENIED); buffer_put_int(r, rid); buffer_put_cstring(r, "Permission denied"); return 0; } } quit_pending = 1; buffer_put_int(r, MUX_S_OK); buffer_put_int(r, rid); /* XXX exit happens too soon - message never makes it to client */ return 0; } static char * format_forward(u_int ftype, struct Forward *fwd) { char *ret; switch (ftype) { case MUX_FWD_LOCAL: xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d", (fwd->listen_path != NULL) ? fwd->listen_path : (fwd->listen_host == NULL) ? (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") : fwd->listen_host, fwd->listen_port, (fwd->connect_path != NULL) ? fwd->connect_path : fwd->connect_host, fwd->connect_port); break; case MUX_FWD_DYNAMIC: xasprintf(&ret, "dynamic forward %.200s:%d -> *", (fwd->listen_host == NULL) ? (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") : fwd->listen_host, fwd->listen_port); break; case MUX_FWD_REMOTE: xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d", (fwd->listen_path != NULL) ? fwd->listen_path : (fwd->listen_host == NULL) ? "LOCALHOST" : fwd->listen_host, fwd->listen_port, (fwd->connect_path != NULL) ? fwd->connect_path : fwd->connect_host, fwd->connect_port); break; default: fatal("%s: unknown forward type %u", __func__, ftype); } return ret; } static int compare_host(const char *a, const char *b) { if (a == NULL && b == NULL) return 1; if (a == NULL || b == NULL) return 0; return strcmp(a, b) == 0; } static int compare_forward(struct Forward *a, struct Forward *b) { if (!compare_host(a->listen_host, b->listen_host)) return 0; if (!compare_host(a->listen_path, b->listen_path)) return 0; if (a->listen_port != b->listen_port) return 0; if (!compare_host(a->connect_host, b->connect_host)) return 0; if (!compare_host(a->connect_path, b->connect_path)) return 0; if (a->connect_port != b->connect_port) return 0; return 1; } static void mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) { struct mux_channel_confirm_ctx *fctx = ctxt; char *failmsg = NULL; struct Forward *rfwd; Channel *c; Buffer out; if ((c = channel_by_id(fctx->cid)) == NULL) { /* no channel for reply */ error("%s: unknown channel", __func__); return; } buffer_init(&out); if (fctx->fid >= options.num_remote_forwards || (options.remote_forwards[fctx->fid].connect_path == NULL && options.remote_forwards[fctx->fid].connect_host == NULL)) { xasprintf(&failmsg, "unknown forwarding id %d", fctx->fid); goto fail; } rfwd = &options.remote_forwards[fctx->fid]; debug("%s: %s for: listen %d, connect %s:%d", __func__, type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", rfwd->listen_port, rfwd->connect_path ? rfwd->connect_path : rfwd->connect_host, rfwd->connect_port); if (type == SSH2_MSG_REQUEST_SUCCESS) { if (rfwd->listen_port == 0) { rfwd->allocated_port = packet_get_int(); debug("Allocated port %u for mux remote forward" " to %s:%d", rfwd->allocated_port, rfwd->connect_host, rfwd->connect_port); buffer_put_int(&out, MUX_S_REMOTE_PORT); buffer_put_int(&out, fctx->rid); buffer_put_int(&out, rfwd->allocated_port); channel_update_permitted_opens(rfwd->handle, rfwd->allocated_port); } else { buffer_put_int(&out, MUX_S_OK); buffer_put_int(&out, fctx->rid); } goto out; } else { if (rfwd->listen_port == 0) channel_update_permitted_opens(rfwd->handle, -1); if (rfwd->listen_path != NULL) xasprintf(&failmsg, "remote port forwarding failed for " "listen path %s", rfwd->listen_path); else xasprintf(&failmsg, "remote port forwarding failed for " "listen port %d", rfwd->listen_port); debug2("%s: clearing registered forwarding for listen %d, " "connect %s:%d", __func__, rfwd->listen_port, rfwd->connect_path ? rfwd->connect_path : rfwd->connect_host, rfwd->connect_port); free(rfwd->listen_host); free(rfwd->listen_path); free(rfwd->connect_host); free(rfwd->connect_path); memset(rfwd, 0, sizeof(*rfwd)); } fail: error("%s: %s", __func__, failmsg); buffer_put_int(&out, MUX_S_FAILURE); buffer_put_int(&out, fctx->rid); buffer_put_cstring(&out, failmsg); free(failmsg); out: buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out)); buffer_free(&out); if (c->mux_pause <= 0) fatal("%s: mux_pause %d", __func__, c->mux_pause); c->mux_pause = 0; /* start processing messages again */ } static int process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) { struct Forward fwd; char *fwd_desc = NULL; char *listen_addr, *connect_addr; u_int ftype; u_int lport, cport; int i, ret = 0, freefwd = 1; + memset(&fwd, 0, sizeof(fwd)); + /* XXX - lport/cport check redundant */ if (buffer_get_int_ret(&ftype, m) != 0 || (listen_addr = buffer_get_string_ret(m, NULL)) == NULL || buffer_get_int_ret(&lport, m) != 0 || (connect_addr = buffer_get_string_ret(m, NULL)) == NULL || buffer_get_int_ret(&cport, m) != 0 || (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) || (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) { error("%s: malformed message", __func__); ret = -1; goto out; } if (*listen_addr == '\0') { free(listen_addr); listen_addr = NULL; } if (*connect_addr == '\0') { free(connect_addr); connect_addr = NULL; } memset(&fwd, 0, sizeof(fwd)); fwd.listen_port = lport; if (fwd.listen_port == PORT_STREAMLOCAL) fwd.listen_path = listen_addr; else fwd.listen_host = listen_addr; fwd.connect_port = cport; if (fwd.connect_port == PORT_STREAMLOCAL) fwd.connect_path = connect_addr; else fwd.connect_host = connect_addr; debug2("%s: channel %d: request %s", __func__, c->self, (fwd_desc = format_forward(ftype, &fwd))); if (ftype != MUX_FWD_LOCAL && ftype != MUX_FWD_REMOTE && ftype != MUX_FWD_DYNAMIC) { logit("%s: invalid forwarding type %u", __func__, ftype); invalid: free(listen_addr); free(connect_addr); buffer_put_int(r, MUX_S_FAILURE); buffer_put_int(r, rid); buffer_put_cstring(r, "Invalid forwarding request"); return 0; } if (ftype == MUX_FWD_DYNAMIC && fwd.listen_path) { logit("%s: streamlocal and dynamic forwards " "are mutually exclusive", __func__); goto invalid; } if (fwd.listen_port != PORT_STREAMLOCAL && fwd.listen_port >= 65536) { logit("%s: invalid listen port %u", __func__, fwd.listen_port); goto invalid; } if ((fwd.connect_port != PORT_STREAMLOCAL && fwd.connect_port >= 65536) || (ftype != MUX_FWD_DYNAMIC && ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) { logit("%s: invalid connect port %u", __func__, fwd.connect_port); goto invalid; } if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL && fwd.connect_path == NULL) { logit("%s: missing connect host", __func__); goto invalid; } /* Skip forwards that have already been requested */ switch (ftype) { case MUX_FWD_LOCAL: case MUX_FWD_DYNAMIC: for (i = 0; i < options.num_local_forwards; i++) { if (compare_forward(&fwd, options.local_forwards + i)) { exists: debug2("%s: found existing forwarding", __func__); buffer_put_int(r, MUX_S_OK); buffer_put_int(r, rid); goto out; } } break; case MUX_FWD_REMOTE: for (i = 0; i < options.num_remote_forwards; i++) { if (compare_forward(&fwd, options.remote_forwards + i)) { if (fwd.listen_port != 0) goto exists; debug2("%s: found allocated port", __func__); buffer_put_int(r, MUX_S_REMOTE_PORT); buffer_put_int(r, rid); buffer_put_int(r, options.remote_forwards[i].allocated_port); goto out; } } break; } if (options.control_master == SSHCTL_MASTER_ASK || options.control_master == SSHCTL_MASTER_AUTO_ASK) { if (!ask_permission("Open %s on %s?", fwd_desc, host)) { debug2("%s: forwarding refused by user", __func__); buffer_put_int(r, MUX_S_PERMISSION_DENIED); buffer_put_int(r, rid); buffer_put_cstring(r, "Permission denied"); goto out; } } if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) { if (!channel_setup_local_fwd_listener(&fwd, &options.fwd_opts)) { fail: logit("slave-requested %s failed", fwd_desc); buffer_put_int(r, MUX_S_FAILURE); buffer_put_int(r, rid); buffer_put_cstring(r, "Port forwarding failed"); goto out; } add_local_forward(&options, &fwd); freefwd = 0; } else { struct mux_channel_confirm_ctx *fctx; fwd.handle = channel_request_remote_forwarding(&fwd); if (fwd.handle < 0) goto fail; add_remote_forward(&options, &fwd); fctx = xcalloc(1, sizeof(*fctx)); fctx->cid = c->self; fctx->rid = rid; fctx->fid = options.num_remote_forwards - 1; client_register_global_confirm(mux_confirm_remote_forward, fctx); freefwd = 0; c->mux_pause = 1; /* wait for mux_confirm_remote_forward */ /* delayed reply in mux_confirm_remote_forward */ goto out; } buffer_put_int(r, MUX_S_OK); buffer_put_int(r, rid); out: free(fwd_desc); if (freefwd) { free(fwd.listen_host); free(fwd.listen_path); free(fwd.connect_host); free(fwd.connect_path); } return ret; } static int process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) { struct Forward fwd, *found_fwd; char *fwd_desc = NULL; const char *error_reason = NULL; char *listen_addr = NULL, *connect_addr = NULL; u_int ftype; int i, ret = 0; u_int lport, cport; + + memset(&fwd, 0, sizeof(fwd)); if (buffer_get_int_ret(&ftype, m) != 0 || (listen_addr = buffer_get_string_ret(m, NULL)) == NULL || buffer_get_int_ret(&lport, m) != 0 || (connect_addr = buffer_get_string_ret(m, NULL)) == NULL || buffer_get_int_ret(&cport, m) != 0 || (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) || (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) { error("%s: malformed message", __func__); ret = -1; goto out; } if (*listen_addr == '\0') { free(listen_addr); listen_addr = NULL; } if (*connect_addr == '\0') { free(connect_addr); connect_addr = NULL; } memset(&fwd, 0, sizeof(fwd)); fwd.listen_port = lport; if (fwd.listen_port == PORT_STREAMLOCAL) fwd.listen_path = listen_addr; else fwd.listen_host = listen_addr; fwd.connect_port = cport; if (fwd.connect_port == PORT_STREAMLOCAL) fwd.connect_path = connect_addr; else fwd.connect_host = connect_addr; debug2("%s: channel %d: request cancel %s", __func__, c->self, (fwd_desc = format_forward(ftype, &fwd))); /* make sure this has been requested */ found_fwd = NULL; switch (ftype) { case MUX_FWD_LOCAL: case MUX_FWD_DYNAMIC: for (i = 0; i < options.num_local_forwards; i++) { if (compare_forward(&fwd, options.local_forwards + i)) { found_fwd = options.local_forwards + i; break; } } break; case MUX_FWD_REMOTE: for (i = 0; i < options.num_remote_forwards; i++) { if (compare_forward(&fwd, options.remote_forwards + i)) { found_fwd = options.remote_forwards + i; break; } } break; } if (found_fwd == NULL) error_reason = "port not forwarded"; else if (ftype == MUX_FWD_REMOTE) { /* * This shouldn't fail unless we confused the host/port * between options.remote_forwards and permitted_opens. * However, for dynamic allocated listen ports we need * to use the actual listen port. */ if (channel_request_rforward_cancel(found_fwd) == -1) error_reason = "port not in permitted opens"; } else { /* local and dynamic forwards */ /* Ditto */ if (channel_cancel_lport_listener(&fwd, fwd.connect_port, &options.fwd_opts) == -1) error_reason = "port not found"; } if (error_reason == NULL) { buffer_put_int(r, MUX_S_OK); buffer_put_int(r, rid); free(found_fwd->listen_host); free(found_fwd->listen_path); free(found_fwd->connect_host); free(found_fwd->connect_path); found_fwd->listen_host = found_fwd->connect_host = NULL; found_fwd->listen_path = found_fwd->connect_path = NULL; found_fwd->listen_port = found_fwd->connect_port = 0; } else { buffer_put_int(r, MUX_S_FAILURE); buffer_put_int(r, rid); buffer_put_cstring(r, error_reason); } out: free(fwd_desc); free(listen_addr); free(connect_addr); return ret; } static int process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) { Channel *nc; char *reserved, *chost; u_int cport, i, j; int new_fd[2]; struct mux_stdio_confirm_ctx *cctx; chost = reserved = NULL; if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || (chost = buffer_get_string_ret(m, NULL)) == NULL || buffer_get_int_ret(&cport, m) != 0) { free(reserved); free(chost); error("%s: malformed message", __func__); return -1; } free(reserved); debug2("%s: channel %d: request stdio fwd to %s:%u", __func__, c->self, chost, cport); /* Gather fds from client */ for(i = 0; i < 2; i++) { if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) { error("%s: failed to receive fd %d from slave", __func__, i); for (j = 0; j < i; j++) close(new_fd[j]); free(chost); /* prepare reply */ buffer_put_int(r, MUX_S_FAILURE); buffer_put_int(r, rid); buffer_put_cstring(r, "did not receive file descriptors"); return -1; } } debug3("%s: got fds stdin %d, stdout %d", __func__, new_fd[0], new_fd[1]); /* XXX support multiple child sessions in future */ if (c->remote_id != -1) { debug2("%s: session already open", __func__); /* prepare reply */ buffer_put_int(r, MUX_S_FAILURE); buffer_put_int(r, rid); buffer_put_cstring(r, "Multiple sessions not supported"); cleanup: close(new_fd[0]); close(new_fd[1]); free(chost); return 0; } if (options.control_master == SSHCTL_MASTER_ASK || options.control_master == SSHCTL_MASTER_AUTO_ASK) { if (!ask_permission("Allow forward to %s:%u? ", chost, cport)) { debug2("%s: stdio fwd refused by user", __func__); /* prepare reply */ buffer_put_int(r, MUX_S_PERMISSION_DENIED); buffer_put_int(r, rid); buffer_put_cstring(r, "Permission denied"); goto cleanup; } } /* enable nonblocking unless tty */ if (!isatty(new_fd[0])) set_nonblock(new_fd[0]); if (!isatty(new_fd[1])) set_nonblock(new_fd[1]); nc = channel_connect_stdio_fwd(chost, cport, new_fd[0], new_fd[1]); nc->ctl_chan = c->self; /* link session -> control channel */ c->remote_id = nc->self; /* link control -> session channel */ debug2("%s: channel_new: %d linked to control channel %d", __func__, nc->self, nc->ctl_chan); channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); cctx = xcalloc(1, sizeof(*cctx)); cctx->rid = rid; channel_register_open_confirm(nc->self, mux_stdio_confirm, cctx); c->mux_pause = 1; /* stop handling messages until open_confirm done */ /* reply is deferred, sent by mux_session_confirm */ return 0; } /* Callback on open confirmation in mux master for a mux stdio fwd session. */ static void mux_stdio_confirm(int id, int success, void *arg) { struct mux_stdio_confirm_ctx *cctx = arg; Channel *c, *cc; Buffer reply; if (cctx == NULL) fatal("%s: cctx == NULL", __func__); if ((c = channel_by_id(id)) == NULL) fatal("%s: no channel for id %d", __func__, id); if ((cc = channel_by_id(c->ctl_chan)) == NULL) fatal("%s: channel %d lacks control channel %d", __func__, id, c->ctl_chan); if (!success) { debug3("%s: sending failure reply", __func__); /* prepare reply */ buffer_init(&reply); buffer_put_int(&reply, MUX_S_FAILURE); buffer_put_int(&reply, cctx->rid); buffer_put_cstring(&reply, "Session open refused by peer"); goto done; } debug3("%s: sending success reply", __func__); /* prepare reply */ buffer_init(&reply); buffer_put_int(&reply, MUX_S_SESSION_OPENED); buffer_put_int(&reply, cctx->rid); buffer_put_int(&reply, c->self); done: /* Send reply */ buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply)); buffer_free(&reply); if (cc->mux_pause <= 0) fatal("%s: mux_pause %d", __func__, cc->mux_pause); cc->mux_pause = 0; /* start processing messages again */ c->open_confirm_ctx = NULL; free(cctx); } static int process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r) { debug("%s: channel %d: stop listening", __func__, c->self); if (options.control_master == SSHCTL_MASTER_ASK || options.control_master == SSHCTL_MASTER_AUTO_ASK) { if (!ask_permission("Disable further multiplexing on shared " "connection to %s? ", host)) { debug2("%s: stop listen refused by user", __func__); buffer_put_int(r, MUX_S_PERMISSION_DENIED); buffer_put_int(r, rid); buffer_put_cstring(r, "Permission denied"); return 0; } } if (mux_listener_channel != NULL) { channel_free(mux_listener_channel); client_stop_mux(); free(options.control_path); options.control_path = NULL; mux_listener_channel = NULL; muxserver_sock = -1; } /* prepare reply */ buffer_put_int(r, MUX_S_OK); buffer_put_int(r, rid); return 0; } /* Channel callbacks fired on read/write from mux slave fd */ static int mux_master_read_cb(Channel *c) { struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; Buffer in, out; const u_char *ptr; u_int type, rid, have, i; int ret = -1; /* Setup ctx and */ if (c->mux_ctx == NULL) { state = xcalloc(1, sizeof(*state)); c->mux_ctx = state; channel_register_cleanup(c->self, mux_master_control_cleanup_cb, 0); /* Send hello */ buffer_init(&out); buffer_put_int(&out, MUX_MSG_HELLO); buffer_put_int(&out, SSHMUX_VER); /* no extensions */ buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out)); buffer_free(&out); debug3("%s: channel %d: hello sent", __func__, c->self); return 0; } buffer_init(&in); buffer_init(&out); /* Channel code ensures that we receive whole packets */ if ((ptr = buffer_get_string_ptr_ret(&c->input, &have)) == NULL) { malf: error("%s: malformed message", __func__); goto out; } buffer_append(&in, ptr, have); if (buffer_get_int_ret(&type, &in) != 0) goto malf; debug3("%s: channel %d packet type 0x%08x len %u", __func__, c->self, type, buffer_len(&in)); if (type == MUX_MSG_HELLO) rid = 0; else { if (!state->hello_rcvd) { error("%s: expected MUX_MSG_HELLO(0x%08x), " "received 0x%08x", __func__, MUX_MSG_HELLO, type); goto out; } if (buffer_get_int_ret(&rid, &in) != 0) goto malf; } for (i = 0; mux_master_handlers[i].handler != NULL; i++) { if (type == mux_master_handlers[i].type) { ret = mux_master_handlers[i].handler(rid, c, &in, &out); break; } } if (mux_master_handlers[i].handler == NULL) { error("%s: unsupported mux message 0x%08x", __func__, type); buffer_put_int(&out, MUX_S_FAILURE); buffer_put_int(&out, rid); buffer_put_cstring(&out, "unsupported request"); ret = 0; } /* Enqueue reply packet */ if (buffer_len(&out) != 0) { buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out)); } out: buffer_free(&in); buffer_free(&out); return ret; } void mux_exit_message(Channel *c, int exitval) { Buffer m; Channel *mux_chan; debug3("%s: channel %d: exit message, exitval %d", __func__, c->self, exitval); if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL) fatal("%s: channel %d missing mux channel %d", __func__, c->self, c->ctl_chan); /* Append exit message packet to control socket output queue */ buffer_init(&m); buffer_put_int(&m, MUX_S_EXIT_MESSAGE); buffer_put_int(&m, c->self); buffer_put_int(&m, exitval); buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m)); buffer_free(&m); } void mux_tty_alloc_failed(Channel *c) { Buffer m; Channel *mux_chan; debug3("%s: channel %d: TTY alloc failed", __func__, c->self); if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL) fatal("%s: channel %d missing mux channel %d", __func__, c->self, c->ctl_chan); /* Append exit message packet to control socket output queue */ buffer_init(&m); buffer_put_int(&m, MUX_S_TTY_ALLOC_FAIL); buffer_put_int(&m, c->self); buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m)); buffer_free(&m); } /* Prepare a mux master to listen on a Unix domain socket. */ void muxserver_listen(void) { mode_t old_umask; char *orig_control_path = options.control_path; char rbuf[16+1]; u_int i, r; int oerrno; if (options.control_path == NULL || options.control_master == SSHCTL_MASTER_NO) return; debug("setting up multiplex master socket"); /* * Use a temporary path before listen so we can pseudo-atomically * establish the listening socket in its final location to avoid * other processes racing in between bind() and listen() and hitting * an unready socket. */ for (i = 0; i < sizeof(rbuf) - 1; i++) { r = arc4random_uniform(26+26+10); rbuf[i] = (r < 26) ? 'a' + r : (r < 26*2) ? 'A' + r - 26 : '0' + r - 26 - 26; } rbuf[sizeof(rbuf) - 1] = '\0'; options.control_path = NULL; xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf); debug3("%s: temporary control path %s", __func__, options.control_path); old_umask = umask(0177); muxserver_sock = unix_listener(options.control_path, 64, 0); oerrno = errno; umask(old_umask); if (muxserver_sock < 0) { if (oerrno == EINVAL || oerrno == EADDRINUSE) { error("ControlSocket %s already exists, " "disabling multiplexing", options.control_path); disable_mux_master: if (muxserver_sock != -1) { close(muxserver_sock); muxserver_sock = -1; } free(orig_control_path); free(options.control_path); options.control_path = NULL; options.control_master = SSHCTL_MASTER_NO; return; } else { /* unix_listener() logs the error */ cleanup_exit(255); } } /* Now atomically "move" the mux socket into position */ if (link(options.control_path, orig_control_path) != 0) { if (errno != EEXIST) { fatal("%s: link mux listener %s => %s: %s", __func__, options.control_path, orig_control_path, strerror(errno)); } error("ControlSocket %s already exists, disabling multiplexing", orig_control_path); unlink(options.control_path); goto disable_mux_master; } unlink(options.control_path); free(options.control_path); options.control_path = orig_control_path; set_nonblock(muxserver_sock); mux_listener_channel = channel_new("mux listener", SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, options.control_path, 1); mux_listener_channel->mux_rcb = mux_master_read_cb; debug3("%s: mux listener channel %d fd %d", __func__, mux_listener_channel->self, mux_listener_channel->sock); } /* Callback on open confirmation in mux master for a mux client session. */ static void mux_session_confirm(int id, int success, void *arg) { struct mux_session_confirm_ctx *cctx = arg; const char *display; Channel *c, *cc; int i; Buffer reply; if (cctx == NULL) fatal("%s: cctx == NULL", __func__); if ((c = channel_by_id(id)) == NULL) fatal("%s: no channel for id %d", __func__, id); if ((cc = channel_by_id(c->ctl_chan)) == NULL) fatal("%s: channel %d lacks control channel %d", __func__, id, c->ctl_chan); if (!success) { debug3("%s: sending failure reply", __func__); /* prepare reply */ buffer_init(&reply); buffer_put_int(&reply, MUX_S_FAILURE); buffer_put_int(&reply, cctx->rid); buffer_put_cstring(&reply, "Session open refused by peer"); goto done; } display = getenv("DISPLAY"); if (cctx->want_x_fwd && options.forward_x11 && display != NULL) { char *proto, *data; /* Get reasonable local authentication information. */ client_x11_get_proto(display, options.xauth_location, options.forward_x11_trusted, options.forward_x11_timeout, &proto, &data); /* Request forwarding with authentication spoofing. */ debug("Requesting X11 forwarding with authentication " "spoofing."); x11_request_forwarding_with_spoofing(id, display, proto, data, 1); client_expect_confirm(id, "X11 forwarding", CONFIRM_WARN); /* XXX exit_on_forward_failure */ } if (cctx->want_agent_fwd && options.forward_agent) { debug("Requesting authentication agent forwarding."); channel_request_start(id, "auth-agent-req@openssh.com", 0); packet_send(); } client_session2_setup(id, cctx->want_tty, cctx->want_subsys, cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); debug3("%s: sending success reply", __func__); /* prepare reply */ buffer_init(&reply); buffer_put_int(&reply, MUX_S_SESSION_OPENED); buffer_put_int(&reply, cctx->rid); buffer_put_int(&reply, c->self); done: /* Send reply */ buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply)); buffer_free(&reply); if (cc->mux_pause <= 0) fatal("%s: mux_pause %d", __func__, cc->mux_pause); cc->mux_pause = 0; /* start processing messages again */ c->open_confirm_ctx = NULL; buffer_free(&cctx->cmd); free(cctx->term); if (cctx->env != NULL) { for (i = 0; cctx->env[i] != NULL; i++) free(cctx->env[i]); free(cctx->env); } free(cctx); } /* ** Multiplexing client support */ /* Exit signal handler */ static void control_client_sighandler(int signo) { muxclient_terminate = signo; } /* * Relay signal handler - used to pass some signals from mux client to * mux master. */ static void control_client_sigrelay(int signo) { int save_errno = errno; if (muxserver_pid > 1) kill(muxserver_pid, signo); errno = save_errno; } static int mux_client_read(int fd, Buffer *b, u_int need) { u_int have; ssize_t len; u_char *p; struct pollfd pfd; pfd.fd = fd; pfd.events = POLLIN; p = buffer_append_space(b, need); for (have = 0; have < need; ) { if (muxclient_terminate) { errno = EINTR; return -1; } len = read(fd, p + have, need - have); if (len < 0) { switch (errno) { #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) case EWOULDBLOCK: #endif case EAGAIN: (void)poll(&pfd, 1, -1); /* FALLTHROUGH */ case EINTR: continue; default: return -1; } } if (len == 0) { errno = EPIPE; return -1; } have += (u_int)len; } return 0; } static int mux_client_write_packet(int fd, Buffer *m) { Buffer queue; u_int have, need; int oerrno, len; u_char *ptr; struct pollfd pfd; pfd.fd = fd; pfd.events = POLLOUT; buffer_init(&queue); buffer_put_string(&queue, buffer_ptr(m), buffer_len(m)); need = buffer_len(&queue); ptr = buffer_ptr(&queue); for (have = 0; have < need; ) { if (muxclient_terminate) { buffer_free(&queue); errno = EINTR; return -1; } len = write(fd, ptr + have, need - have); if (len < 0) { switch (errno) { #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) case EWOULDBLOCK: #endif case EAGAIN: (void)poll(&pfd, 1, -1); /* FALLTHROUGH */ case EINTR: continue; default: oerrno = errno; buffer_free(&queue); errno = oerrno; return -1; } } if (len == 0) { buffer_free(&queue); errno = EPIPE; return -1; } have += (u_int)len; } buffer_free(&queue); return 0; } static int mux_client_read_packet(int fd, Buffer *m) { Buffer queue; u_int need, have; const u_char *ptr; int oerrno; buffer_init(&queue); if (mux_client_read(fd, &queue, 4) != 0) { if ((oerrno = errno) == EPIPE) debug3("%s: read header failed: %s", __func__, strerror(errno)); buffer_free(&queue); errno = oerrno; return -1; } need = get_u32(buffer_ptr(&queue)); if (mux_client_read(fd, &queue, need) != 0) { oerrno = errno; debug3("%s: read body failed: %s", __func__, strerror(errno)); buffer_free(&queue); errno = oerrno; return -1; } ptr = buffer_get_string_ptr(&queue, &have); buffer_append(m, ptr, have); buffer_free(&queue); return 0; } static int mux_client_hello_exchange(int fd) { Buffer m; u_int type, ver; buffer_init(&m); buffer_put_int(&m, MUX_MSG_HELLO); buffer_put_int(&m, SSHMUX_VER); /* no extensions */ if (mux_client_write_packet(fd, &m) != 0) fatal("%s: write packet: %s", __func__, strerror(errno)); buffer_clear(&m); /* Read their HELLO */ if (mux_client_read_packet(fd, &m) != 0) { buffer_free(&m); return -1; } type = buffer_get_int(&m); if (type != MUX_MSG_HELLO) fatal("%s: expected HELLO (%u) received %u", __func__, MUX_MSG_HELLO, type); ver = buffer_get_int(&m); if (ver != SSHMUX_VER) fatal("Unsupported multiplexing protocol version %d " "(expected %d)", ver, SSHMUX_VER); debug2("%s: master version %u", __func__, ver); /* No extensions are presently defined */ while (buffer_len(&m) > 0) { char *name = buffer_get_string(&m, NULL); char *value = buffer_get_string(&m, NULL); debug2("Unrecognised master extension \"%s\"", name); free(name); free(value); } buffer_free(&m); return 0; } static u_int mux_client_request_alive(int fd) { Buffer m; char *e; u_int pid, type, rid; debug3("%s: entering", __func__); buffer_init(&m); buffer_put_int(&m, MUX_C_ALIVE_CHECK); buffer_put_int(&m, muxclient_request_id); if (mux_client_write_packet(fd, &m) != 0) fatal("%s: write packet: %s", __func__, strerror(errno)); buffer_clear(&m); /* Read their reply */ if (mux_client_read_packet(fd, &m) != 0) { buffer_free(&m); return 0; } type = buffer_get_int(&m); if (type != MUX_S_ALIVE) { e = buffer_get_string(&m, NULL); fatal("%s: master returned error: %s", __func__, e); } if ((rid = buffer_get_int(&m)) != muxclient_request_id) fatal("%s: out of sequence reply: my id %u theirs %u", __func__, muxclient_request_id, rid); pid = buffer_get_int(&m); buffer_free(&m); debug3("%s: done pid = %u", __func__, pid); muxclient_request_id++; return pid; } static void mux_client_request_terminate(int fd) { Buffer m; char *e; u_int type, rid; debug3("%s: entering", __func__); buffer_init(&m); buffer_put_int(&m, MUX_C_TERMINATE); buffer_put_int(&m, muxclient_request_id); if (mux_client_write_packet(fd, &m) != 0) fatal("%s: write packet: %s", __func__, strerror(errno)); buffer_clear(&m); /* Read their reply */ if (mux_client_read_packet(fd, &m) != 0) { /* Remote end exited already */ if (errno == EPIPE) { buffer_free(&m); return; } fatal("%s: read from master failed: %s", __func__, strerror(errno)); } type = buffer_get_int(&m); if ((rid = buffer_get_int(&m)) != muxclient_request_id) fatal("%s: out of sequence reply: my id %u theirs %u", __func__, muxclient_request_id, rid); switch (type) { case MUX_S_OK: break; case MUX_S_PERMISSION_DENIED: e = buffer_get_string(&m, NULL); fatal("Master refused termination request: %s", e); case MUX_S_FAILURE: e = buffer_get_string(&m, NULL); fatal("%s: termination request failed: %s", __func__, e); default: fatal("%s: unexpected response from master 0x%08x", __func__, type); } buffer_free(&m); muxclient_request_id++; } static int mux_client_forward(int fd, int cancel_flag, u_int ftype, struct Forward *fwd) { Buffer m; char *e, *fwd_desc; u_int type, rid; fwd_desc = format_forward(ftype, fwd); debug("Requesting %s %s", cancel_flag ? "cancellation of" : "forwarding of", fwd_desc); free(fwd_desc); buffer_init(&m); buffer_put_int(&m, cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD); buffer_put_int(&m, muxclient_request_id); buffer_put_int(&m, ftype); if (fwd->listen_path != NULL) { buffer_put_cstring(&m, fwd->listen_path); } else { buffer_put_cstring(&m, fwd->listen_host == NULL ? "" : (*fwd->listen_host == '\0' ? "*" : fwd->listen_host)); } buffer_put_int(&m, fwd->listen_port); if (fwd->connect_path != NULL) { buffer_put_cstring(&m, fwd->connect_path); } else { buffer_put_cstring(&m, fwd->connect_host == NULL ? "" : fwd->connect_host); } buffer_put_int(&m, fwd->connect_port); if (mux_client_write_packet(fd, &m) != 0) fatal("%s: write packet: %s", __func__, strerror(errno)); buffer_clear(&m); /* Read their reply */ if (mux_client_read_packet(fd, &m) != 0) { buffer_free(&m); return -1; } type = buffer_get_int(&m); if ((rid = buffer_get_int(&m)) != muxclient_request_id) fatal("%s: out of sequence reply: my id %u theirs %u", __func__, muxclient_request_id, rid); switch (type) { case MUX_S_OK: break; case MUX_S_REMOTE_PORT: if (cancel_flag) fatal("%s: got MUX_S_REMOTE_PORT for cancel", __func__); fwd->allocated_port = buffer_get_int(&m); verbose("Allocated port %u for remote forward to %s:%d", fwd->allocated_port, fwd->connect_host ? fwd->connect_host : "", fwd->connect_port); if (muxclient_command == SSHMUX_COMMAND_FORWARD) fprintf(stdout, "%u\n", fwd->allocated_port); break; case MUX_S_PERMISSION_DENIED: e = buffer_get_string(&m, NULL); buffer_free(&m); error("Master refused forwarding request: %s", e); return -1; case MUX_S_FAILURE: e = buffer_get_string(&m, NULL); buffer_free(&m); error("%s: forwarding request failed: %s", __func__, e); return -1; default: fatal("%s: unexpected response from master 0x%08x", __func__, type); } buffer_free(&m); muxclient_request_id++; return 0; } static int mux_client_forwards(int fd, int cancel_flag) { int i, ret = 0; debug3("%s: %s forwardings: %d local, %d remote", __func__, cancel_flag ? "cancel" : "request", options.num_local_forwards, options.num_remote_forwards); /* XXX ExitOnForwardingFailure */ for (i = 0; i < options.num_local_forwards; i++) { if (mux_client_forward(fd, cancel_flag, options.local_forwards[i].connect_port == 0 ? MUX_FWD_DYNAMIC : MUX_FWD_LOCAL, options.local_forwards + i) != 0) ret = -1; } for (i = 0; i < options.num_remote_forwards; i++) { if (mux_client_forward(fd, cancel_flag, MUX_FWD_REMOTE, options.remote_forwards + i) != 0) ret = -1; } return ret; } static int mux_client_request_session(int fd) { Buffer m; char *e, *term; u_int i, rid, sid, esid, exitval, type, exitval_seen; extern char **environ; int devnull, rawmode; debug3("%s: entering", __func__); if ((muxserver_pid = mux_client_request_alive(fd)) == 0) { error("%s: master alive request failed", __func__); return -1; } signal(SIGPIPE, SIG_IGN); if (stdin_null_flag) { if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1) fatal("open(/dev/null): %s", strerror(errno)); if (dup2(devnull, STDIN_FILENO) == -1) fatal("dup2: %s", strerror(errno)); if (devnull > STDERR_FILENO) close(devnull); } term = getenv("TERM"); buffer_init(&m); buffer_put_int(&m, MUX_C_NEW_SESSION); buffer_put_int(&m, muxclient_request_id); buffer_put_cstring(&m, ""); /* reserved */ buffer_put_int(&m, tty_flag); buffer_put_int(&m, options.forward_x11); buffer_put_int(&m, options.forward_agent); buffer_put_int(&m, subsystem_flag); buffer_put_int(&m, options.escape_char == SSH_ESCAPECHAR_NONE ? 0xffffffff : (u_int)options.escape_char); buffer_put_cstring(&m, term == NULL ? "" : term); buffer_put_string(&m, buffer_ptr(&command), buffer_len(&command)); if (options.num_send_env > 0 && environ != NULL) { /* Pass environment */ for (i = 0; environ[i] != NULL; i++) { if (env_permitted(environ[i])) { buffer_put_cstring(&m, environ[i]); } } } if (mux_client_write_packet(fd, &m) != 0) fatal("%s: write packet: %s", __func__, strerror(errno)); /* Send the stdio file descriptors */ if (mm_send_fd(fd, STDIN_FILENO) == -1 || mm_send_fd(fd, STDOUT_FILENO) == -1 || mm_send_fd(fd, STDERR_FILENO) == -1) fatal("%s: send fds failed", __func__); debug3("%s: session request sent", __func__); /* Read their reply */ buffer_clear(&m); if (mux_client_read_packet(fd, &m) != 0) { error("%s: read from master failed: %s", __func__, strerror(errno)); buffer_free(&m); return -1; } type = buffer_get_int(&m); if ((rid = buffer_get_int(&m)) != muxclient_request_id) fatal("%s: out of sequence reply: my id %u theirs %u", __func__, muxclient_request_id, rid); switch (type) { case MUX_S_SESSION_OPENED: sid = buffer_get_int(&m); debug("%s: master session id: %u", __func__, sid); break; case MUX_S_PERMISSION_DENIED: e = buffer_get_string(&m, NULL); buffer_free(&m); error("Master refused session request: %s", e); return -1; case MUX_S_FAILURE: e = buffer_get_string(&m, NULL); buffer_free(&m); error("%s: session request failed: %s", __func__, e); return -1; default: buffer_free(&m); error("%s: unexpected response from master 0x%08x", __func__, type); return -1; } muxclient_request_id++; signal(SIGHUP, control_client_sighandler); signal(SIGINT, control_client_sighandler); signal(SIGTERM, control_client_sighandler); signal(SIGWINCH, control_client_sigrelay); rawmode = tty_flag; if (tty_flag) enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); /* * Stick around until the controlee closes the client_fd. * Before it does, it is expected to write an exit message. * This process must read the value and wait for the closure of * the client_fd; if this one closes early, the multiplex master will * terminate early too (possibly losing data). */ for (exitval = 255, exitval_seen = 0;;) { buffer_clear(&m); if (mux_client_read_packet(fd, &m) != 0) break; type = buffer_get_int(&m); switch (type) { case MUX_S_TTY_ALLOC_FAIL: if ((esid = buffer_get_int(&m)) != sid) fatal("%s: tty alloc fail on unknown session: " "my id %u theirs %u", __func__, sid, esid); leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); rawmode = 0; continue; case MUX_S_EXIT_MESSAGE: if ((esid = buffer_get_int(&m)) != sid) fatal("%s: exit on unknown session: " "my id %u theirs %u", __func__, sid, esid); if (exitval_seen) fatal("%s: exitval sent twice", __func__); exitval = buffer_get_int(&m); exitval_seen = 1; continue; default: e = buffer_get_string(&m, NULL); fatal("%s: master returned error: %s", __func__, e); } } close(fd); if (rawmode) leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); if (muxclient_terminate) { debug2("Exiting on signal %ld", (long)muxclient_terminate); exitval = 255; } else if (!exitval_seen) { debug2("Control master terminated unexpectedly"); exitval = 255; } else debug2("Received exit status from master %d", exitval); if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET) fprintf(stderr, "Shared connection to %s closed.\r\n", host); exit(exitval); } static int mux_client_request_stdio_fwd(int fd) { Buffer m; char *e; u_int type, rid, sid; int devnull; debug3("%s: entering", __func__); if ((muxserver_pid = mux_client_request_alive(fd)) == 0) { error("%s: master alive request failed", __func__); return -1; } signal(SIGPIPE, SIG_IGN); if (stdin_null_flag) { if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1) fatal("open(/dev/null): %s", strerror(errno)); if (dup2(devnull, STDIN_FILENO) == -1) fatal("dup2: %s", strerror(errno)); if (devnull > STDERR_FILENO) close(devnull); } buffer_init(&m); buffer_put_int(&m, MUX_C_NEW_STDIO_FWD); buffer_put_int(&m, muxclient_request_id); buffer_put_cstring(&m, ""); /* reserved */ buffer_put_cstring(&m, stdio_forward_host); buffer_put_int(&m, stdio_forward_port); if (mux_client_write_packet(fd, &m) != 0) fatal("%s: write packet: %s", __func__, strerror(errno)); /* Send the stdio file descriptors */ if (mm_send_fd(fd, STDIN_FILENO) == -1 || mm_send_fd(fd, STDOUT_FILENO) == -1) fatal("%s: send fds failed", __func__); debug3("%s: stdio forward request sent", __func__); /* Read their reply */ buffer_clear(&m); if (mux_client_read_packet(fd, &m) != 0) { error("%s: read from master failed: %s", __func__, strerror(errno)); buffer_free(&m); return -1; } type = buffer_get_int(&m); if ((rid = buffer_get_int(&m)) != muxclient_request_id) fatal("%s: out of sequence reply: my id %u theirs %u", __func__, muxclient_request_id, rid); switch (type) { case MUX_S_SESSION_OPENED: sid = buffer_get_int(&m); debug("%s: master session id: %u", __func__, sid); break; case MUX_S_PERMISSION_DENIED: e = buffer_get_string(&m, NULL); buffer_free(&m); fatal("Master refused stdio forwarding request: %s", e); case MUX_S_FAILURE: e = buffer_get_string(&m, NULL); buffer_free(&m); fatal("Stdio forwarding request failed: %s", e); default: buffer_free(&m); error("%s: unexpected response from master 0x%08x", __func__, type); return -1; } muxclient_request_id++; signal(SIGHUP, control_client_sighandler); signal(SIGINT, control_client_sighandler); signal(SIGTERM, control_client_sighandler); signal(SIGWINCH, control_client_sigrelay); /* * Stick around until the controlee closes the client_fd. */ buffer_clear(&m); if (mux_client_read_packet(fd, &m) != 0) { if (errno == EPIPE || (errno == EINTR && muxclient_terminate != 0)) return 0; fatal("%s: mux_client_read_packet: %s", __func__, strerror(errno)); } fatal("%s: master returned unexpected message %u", __func__, type); } static void mux_client_request_stop_listening(int fd) { Buffer m; char *e; u_int type, rid; debug3("%s: entering", __func__); buffer_init(&m); buffer_put_int(&m, MUX_C_STOP_LISTENING); buffer_put_int(&m, muxclient_request_id); if (mux_client_write_packet(fd, &m) != 0) fatal("%s: write packet: %s", __func__, strerror(errno)); buffer_clear(&m); /* Read their reply */ if (mux_client_read_packet(fd, &m) != 0) fatal("%s: read from master failed: %s", __func__, strerror(errno)); type = buffer_get_int(&m); if ((rid = buffer_get_int(&m)) != muxclient_request_id) fatal("%s: out of sequence reply: my id %u theirs %u", __func__, muxclient_request_id, rid); switch (type) { case MUX_S_OK: break; case MUX_S_PERMISSION_DENIED: e = buffer_get_string(&m, NULL); fatal("Master refused stop listening request: %s", e); case MUX_S_FAILURE: e = buffer_get_string(&m, NULL); fatal("%s: stop listening request failed: %s", __func__, e); default: fatal("%s: unexpected response from master 0x%08x", __func__, type); } buffer_free(&m); muxclient_request_id++; } /* Multiplex client main loop. */ void muxclient(const char *path) { struct sockaddr_un addr; socklen_t sun_len; int sock; u_int pid; if (muxclient_command == 0) { if (stdio_forward_host != NULL) muxclient_command = SSHMUX_COMMAND_STDIO_FWD; else muxclient_command = SSHMUX_COMMAND_OPEN; } switch (options.control_master) { case SSHCTL_MASTER_AUTO: case SSHCTL_MASTER_AUTO_ASK: debug("auto-mux: Trying existing master"); /* FALLTHROUGH */ case SSHCTL_MASTER_NO: break; default: return; } memset(&addr, '\0', sizeof(addr)); addr.sun_family = AF_UNIX; sun_len = offsetof(struct sockaddr_un, sun_path) + strlen(path) + 1; if (strlcpy(addr.sun_path, path, sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) fatal("ControlPath too long"); if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) fatal("%s socket(): %s", __func__, strerror(errno)); if (connect(sock, (struct sockaddr *)&addr, sun_len) == -1) { switch (muxclient_command) { case SSHMUX_COMMAND_OPEN: case SSHMUX_COMMAND_STDIO_FWD: break; default: fatal("Control socket connect(%.100s): %s", path, strerror(errno)); } if (errno == ECONNREFUSED && options.control_master != SSHCTL_MASTER_NO) { debug("Stale control socket %.100s, unlinking", path); unlink(path); } else if (errno == ENOENT) { debug("Control socket \"%.100s\" does not exist", path); } else { error("Control socket connect(%.100s): %s", path, strerror(errno)); } close(sock); return; } set_nonblock(sock); if (mux_client_hello_exchange(sock) != 0) { error("%s: master hello exchange failed", __func__); close(sock); return; } switch (muxclient_command) { case SSHMUX_COMMAND_ALIVE_CHECK: if ((pid = mux_client_request_alive(sock)) == 0) fatal("%s: master alive check failed", __func__); fprintf(stderr, "Master running (pid=%d)\r\n", pid); exit(0); case SSHMUX_COMMAND_TERMINATE: mux_client_request_terminate(sock); fprintf(stderr, "Exit request sent.\r\n"); exit(0); case SSHMUX_COMMAND_FORWARD: if (mux_client_forwards(sock, 0) != 0) fatal("%s: master forward request failed", __func__); exit(0); case SSHMUX_COMMAND_OPEN: if (mux_client_forwards(sock, 0) != 0) { error("%s: master forward request failed", __func__); return; } mux_client_request_session(sock); return; case SSHMUX_COMMAND_STDIO_FWD: mux_client_request_stdio_fwd(sock); exit(0); case SSHMUX_COMMAND_STOP: mux_client_request_stop_listening(sock); fprintf(stderr, "Stop listening request sent.\r\n"); exit(0); case SSHMUX_COMMAND_CANCEL_FWD: if (mux_client_forwards(sock, 1) != 0) error("%s: master cancel forward request failed", __func__); exit(0); default: fatal("unrecognised muxclient_command %d", muxclient_command); } } Index: head/crypto/openssh/packet.c =================================================================== --- head/crypto/openssh/packet.c (revision 294495) +++ head/crypto/openssh/packet.c (revision 294496) @@ -1,2928 +1,2929 @@ -/* $OpenBSD: packet.c,v 1.213 2015/07/29 04:43:06 djm Exp $ */ +/* $OpenBSD: packet.c,v 1.214 2015/08/20 22:32:42 deraadt Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved * This file contains code implementing the packet protocol and communication * with the other side. This same code is used both on client and server side. * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose. Any derived versions of this * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". * * * SSH2 packet format added by Markus Friedl. * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" __RCSID("$FreeBSD$"); #include /* MIN roundup */ #include #include "openbsd-compat/sys-queue.h" #include #ifdef HAVE_SYS_TIME_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "buffer.h" /* typedefs XXX */ #include "key.h" /* typedefs XXX */ #include "xmalloc.h" #include "crc32.h" #include "deattack.h" #include "compat.h" #include "ssh1.h" #include "ssh2.h" #include "cipher.h" #include "sshkey.h" #include "kex.h" #include "digest.h" #include "mac.h" #include "log.h" #include "canohost.h" #include "misc.h" #include "channels.h" #include "ssh.h" #include "packet.h" #include "roaming.h" #include "ssherr.h" #include "sshbuf.h" #ifdef PACKET_DEBUG #define DBG(x) x #else #define DBG(x) #endif #define PACKET_MAX_SIZE (256 * 1024) struct packet_state { u_int32_t seqnr; u_int32_t packets; u_int64_t blocks; u_int64_t bytes; }; struct packet { TAILQ_ENTRY(packet) next; u_char type; struct sshbuf *payload; }; struct session_state { /* * This variable contains the file descriptors used for * communicating with the other side. connection_in is used for * reading; connection_out for writing. These can be the same * descriptor, in which case it is assumed to be a socket. */ int connection_in; int connection_out; /* Protocol flags for the remote side. */ u_int remote_protocol_flags; /* Encryption context for receiving data. Only used for decryption. */ struct sshcipher_ctx receive_context; /* Encryption context for sending data. Only used for encryption. */ struct sshcipher_ctx send_context; /* Buffer for raw input data from the socket. */ struct sshbuf *input; /* Buffer for raw output data going to the socket. */ struct sshbuf *output; /* Buffer for the partial outgoing packet being constructed. */ struct sshbuf *outgoing_packet; /* Buffer for the incoming packet currently being processed. */ struct sshbuf *incoming_packet; /* Scratch buffer for packet compression/decompression. */ struct sshbuf *compression_buffer; /* Incoming/outgoing compression dictionaries */ z_stream compression_in_stream; z_stream compression_out_stream; int compression_in_started; int compression_out_started; int compression_in_failures; int compression_out_failures; /* * Flag indicating whether packet compression/decompression is * enabled. */ int packet_compression; /* default maximum packet size */ u_int max_packet_size; /* Flag indicating whether this module has been initialized. */ int initialized; /* Set to true if the connection is interactive. */ int interactive_mode; /* Set to true if we are the server side. */ int server_side; /* Set to true if we are authenticated. */ int after_authentication; int keep_alive_timeouts; /* The maximum time that we will wait to send or receive a packet */ int packet_timeout_ms; /* Session key information for Encryption and MAC */ struct newkeys *newkeys[MODE_MAX]; struct packet_state p_read, p_send; /* Volume-based rekeying */ u_int64_t max_blocks_in, max_blocks_out; u_int32_t rekey_limit; /* Time-based rekeying */ u_int32_t rekey_interval; /* how often in seconds */ time_t rekey_time; /* time of last rekeying */ /* Session key for protocol v1 */ u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; u_int ssh1_keylen; /* roundup current message to extra_pad bytes */ u_char extra_pad; /* XXX discard incoming data after MAC error */ u_int packet_discard; struct sshmac *packet_discard_mac; /* Used in packet_read_poll2() */ u_int packlen; /* Used in packet_send2 */ int rekeying; /* Used in packet_set_interactive */ int set_interactive_called; /* Used in packet_set_maxsize */ int set_maxsize_called; /* One-off warning about weak ciphers */ int cipher_warning_done; /* SSH1 CRC compensation attack detector */ struct deattack_ctx deattack; TAILQ_HEAD(, packet) outgoing; }; struct ssh * ssh_alloc_session_state(void) { struct ssh *ssh = NULL; struct session_state *state = NULL; if ((ssh = calloc(1, sizeof(*ssh))) == NULL || (state = calloc(1, sizeof(*state))) == NULL || (state->input = sshbuf_new()) == NULL || (state->output = sshbuf_new()) == NULL || (state->outgoing_packet = sshbuf_new()) == NULL || (state->incoming_packet = sshbuf_new()) == NULL) goto fail; TAILQ_INIT(&state->outgoing); TAILQ_INIT(&ssh->private_keys); TAILQ_INIT(&ssh->public_keys); state->connection_in = -1; state->connection_out = -1; state->max_packet_size = 32768; state->packet_timeout_ms = -1; state->p_send.packets = state->p_read.packets = 0; state->initialized = 1; /* * ssh_packet_send2() needs to queue packets until * we've done the initial key exchange. */ state->rekeying = 1; ssh->state = state; return ssh; fail: if (state) { sshbuf_free(state->input); sshbuf_free(state->output); sshbuf_free(state->incoming_packet); sshbuf_free(state->outgoing_packet); free(state); } free(ssh); return NULL; } /* * Sets the descriptors used for communication. Disables encryption until * packet_set_encryption_key is called. */ struct ssh * ssh_packet_set_connection(struct ssh *ssh, int fd_in, int fd_out) { struct session_state *state; const struct sshcipher *none = cipher_by_name("none"); int r; if (none == NULL) { error("%s: cannot load cipher 'none'", __func__); return NULL; } if (ssh == NULL) ssh = ssh_alloc_session_state(); if (ssh == NULL) { error("%s: cound not allocate state", __func__); return NULL; } state = ssh->state; state->connection_in = fd_in; state->connection_out = fd_out; if ((r = cipher_init(&state->send_context, none, (const u_char *)"", 0, NULL, 0, CIPHER_ENCRYPT)) != 0 || (r = cipher_init(&state->receive_context, none, (const u_char *)"", 0, NULL, 0, CIPHER_DECRYPT)) != 0) { error("%s: cipher_init failed: %s", __func__, ssh_err(r)); free(ssh); return NULL; } state->newkeys[MODE_IN] = state->newkeys[MODE_OUT] = NULL; deattack_init(&state->deattack); /* * Cache the IP address of the remote connection for use in error * messages that might be generated after the connection has closed. */ (void)ssh_remote_ipaddr(ssh); return ssh; } void ssh_packet_set_timeout(struct ssh *ssh, int timeout, int count) { struct session_state *state = ssh->state; if (timeout <= 0 || count <= 0) { state->packet_timeout_ms = -1; return; } if ((INT_MAX / 1000) / count < timeout) state->packet_timeout_ms = INT_MAX; else state->packet_timeout_ms = timeout * count * 1000; } int ssh_packet_stop_discard(struct ssh *ssh) { struct session_state *state = ssh->state; int r; if (state->packet_discard_mac) { char buf[1024]; memset(buf, 'a', sizeof(buf)); while (sshbuf_len(state->incoming_packet) < PACKET_MAX_SIZE) if ((r = sshbuf_put(state->incoming_packet, buf, sizeof(buf))) != 0) return r; (void) mac_compute(state->packet_discard_mac, state->p_read.seqnr, sshbuf_ptr(state->incoming_packet), PACKET_MAX_SIZE, NULL, 0); } logit("Finished discarding for %.200s", ssh_remote_ipaddr(ssh)); return SSH_ERR_MAC_INVALID; } static int ssh_packet_start_discard(struct ssh *ssh, struct sshenc *enc, struct sshmac *mac, u_int packet_length, u_int discard) { struct session_state *state = ssh->state; int r; if (enc == NULL || !cipher_is_cbc(enc->cipher) || (mac && mac->etm)) { if ((r = sshpkt_disconnect(ssh, "Packet corrupt")) != 0) return r; return SSH_ERR_MAC_INVALID; } if (packet_length != PACKET_MAX_SIZE && mac && mac->enabled) state->packet_discard_mac = mac; if (sshbuf_len(state->input) >= discard && (r = ssh_packet_stop_discard(ssh)) != 0) return r; state->packet_discard = discard - sshbuf_len(state->input); return 0; } /* Returns 1 if remote host is connected via socket, 0 if not. */ int ssh_packet_connection_is_on_socket(struct ssh *ssh) { struct session_state *state = ssh->state; struct sockaddr_storage from, to; socklen_t fromlen, tolen; /* filedescriptors in and out are the same, so it's a socket */ if (state->connection_in == state->connection_out) return 1; fromlen = sizeof(from); memset(&from, 0, sizeof(from)); if (getpeername(state->connection_in, (struct sockaddr *)&from, &fromlen) < 0) return 0; tolen = sizeof(to); memset(&to, 0, sizeof(to)); if (getpeername(state->connection_out, (struct sockaddr *)&to, &tolen) < 0) return 0; if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0) return 0; if (from.ss_family != AF_INET && from.ss_family != AF_INET6) return 0; return 1; } void ssh_packet_get_bytes(struct ssh *ssh, u_int64_t *ibytes, u_int64_t *obytes) { if (ibytes) *ibytes = ssh->state->p_read.bytes; if (obytes) *obytes = ssh->state->p_send.bytes; } int ssh_packet_connection_af(struct ssh *ssh) { struct sockaddr_storage to; socklen_t tolen = sizeof(to); memset(&to, 0, sizeof(to)); if (getsockname(ssh->state->connection_out, (struct sockaddr *)&to, &tolen) < 0) return 0; #ifdef IPV4_IN_IPV6 if (to.ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&to)->sin6_addr)) return AF_INET; #endif return to.ss_family; } /* Sets the connection into non-blocking mode. */ void ssh_packet_set_nonblocking(struct ssh *ssh) { /* Set the socket into non-blocking mode. */ set_nonblock(ssh->state->connection_in); if (ssh->state->connection_out != ssh->state->connection_in) set_nonblock(ssh->state->connection_out); } /* Returns the socket used for reading. */ int ssh_packet_get_connection_in(struct ssh *ssh) { return ssh->state->connection_in; } /* Returns the descriptor used for writing. */ int ssh_packet_get_connection_out(struct ssh *ssh) { return ssh->state->connection_out; } /* * Returns the IP-address of the remote host as a string. The returned * string must not be freed. */ const char * ssh_remote_ipaddr(struct ssh *ssh) { /* Check whether we have cached the ipaddr. */ if (ssh->remote_ipaddr == NULL) ssh->remote_ipaddr = ssh_packet_connection_is_on_socket(ssh) ? get_peer_ipaddr(ssh->state->connection_in) : strdup("UNKNOWN"); if (ssh->remote_ipaddr == NULL) return "UNKNOWN"; return ssh->remote_ipaddr; } /* Closes the connection and clears and frees internal data structures. */ void ssh_packet_close(struct ssh *ssh) { struct session_state *state = ssh->state; int r; u_int mode; if (!state->initialized) return; state->initialized = 0; if (state->connection_in == state->connection_out) { shutdown(state->connection_out, SHUT_RDWR); close(state->connection_out); } else { close(state->connection_in); close(state->connection_out); } sshbuf_free(state->input); sshbuf_free(state->output); sshbuf_free(state->outgoing_packet); sshbuf_free(state->incoming_packet); for (mode = 0; mode < MODE_MAX; mode++) kex_free_newkeys(state->newkeys[mode]); if (state->compression_buffer) { sshbuf_free(state->compression_buffer); if (state->compression_out_started) { z_streamp stream = &state->compression_out_stream; debug("compress outgoing: " "raw data %llu, compressed %llu, factor %.2f", (unsigned long long)stream->total_in, (unsigned long long)stream->total_out, stream->total_in == 0 ? 0.0 : (double) stream->total_out / stream->total_in); if (state->compression_out_failures == 0) deflateEnd(stream); } if (state->compression_in_started) { z_streamp stream = &state->compression_out_stream; debug("compress incoming: " "raw data %llu, compressed %llu, factor %.2f", (unsigned long long)stream->total_out, (unsigned long long)stream->total_in, stream->total_out == 0 ? 0.0 : (double) stream->total_in / stream->total_out); if (state->compression_in_failures == 0) inflateEnd(stream); } } if ((r = cipher_cleanup(&state->send_context)) != 0) error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r)); if ((r = cipher_cleanup(&state->receive_context)) != 0) error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r)); if (ssh->remote_ipaddr) { free(ssh->remote_ipaddr); ssh->remote_ipaddr = NULL; } free(ssh->state); ssh->state = NULL; } /* Sets remote side protocol flags. */ void ssh_packet_set_protocol_flags(struct ssh *ssh, u_int protocol_flags) { ssh->state->remote_protocol_flags = protocol_flags; } /* Returns the remote protocol flags set earlier by the above function. */ u_int ssh_packet_get_protocol_flags(struct ssh *ssh) { return ssh->state->remote_protocol_flags; } /* * Starts packet compression from the next packet on in both directions. * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. */ static int ssh_packet_init_compression(struct ssh *ssh) { if (!ssh->state->compression_buffer && ((ssh->state->compression_buffer = sshbuf_new()) == NULL)) return SSH_ERR_ALLOC_FAIL; return 0; } static int start_compression_out(struct ssh *ssh, int level) { if (level < 1 || level > 9) return SSH_ERR_INVALID_ARGUMENT; debug("Enabling compression at level %d.", level); if (ssh->state->compression_out_started == 1) deflateEnd(&ssh->state->compression_out_stream); switch (deflateInit(&ssh->state->compression_out_stream, level)) { case Z_OK: ssh->state->compression_out_started = 1; break; case Z_MEM_ERROR: return SSH_ERR_ALLOC_FAIL; default: return SSH_ERR_INTERNAL_ERROR; } return 0; } static int start_compression_in(struct ssh *ssh) { if (ssh->state->compression_in_started == 1) inflateEnd(&ssh->state->compression_in_stream); switch (inflateInit(&ssh->state->compression_in_stream)) { case Z_OK: ssh->state->compression_in_started = 1; break; case Z_MEM_ERROR: return SSH_ERR_ALLOC_FAIL; default: return SSH_ERR_INTERNAL_ERROR; } return 0; } int ssh_packet_start_compression(struct ssh *ssh, int level) { int r; if (ssh->state->packet_compression && !compat20) return SSH_ERR_INTERNAL_ERROR; ssh->state->packet_compression = 1; if ((r = ssh_packet_init_compression(ssh)) != 0 || (r = start_compression_in(ssh)) != 0 || (r = start_compression_out(ssh, level)) != 0) return r; return 0; } /* XXX remove need for separate compression buffer */ static int compress_buffer(struct ssh *ssh, struct sshbuf *in, struct sshbuf *out) { u_char buf[4096]; int r, status; if (ssh->state->compression_out_started != 1) return SSH_ERR_INTERNAL_ERROR; /* This case is not handled below. */ if (sshbuf_len(in) == 0) return 0; /* Input is the contents of the input buffer. */ if ((ssh->state->compression_out_stream.next_in = sshbuf_mutable_ptr(in)) == NULL) return SSH_ERR_INTERNAL_ERROR; ssh->state->compression_out_stream.avail_in = sshbuf_len(in); /* Loop compressing until deflate() returns with avail_out != 0. */ do { /* Set up fixed-size output buffer. */ ssh->state->compression_out_stream.next_out = buf; ssh->state->compression_out_stream.avail_out = sizeof(buf); /* Compress as much data into the buffer as possible. */ status = deflate(&ssh->state->compression_out_stream, Z_PARTIAL_FLUSH); switch (status) { case Z_MEM_ERROR: return SSH_ERR_ALLOC_FAIL; case Z_OK: /* Append compressed data to output_buffer. */ if ((r = sshbuf_put(out, buf, sizeof(buf) - ssh->state->compression_out_stream.avail_out)) != 0) return r; break; case Z_STREAM_ERROR: default: ssh->state->compression_out_failures++; return SSH_ERR_INVALID_FORMAT; } } while (ssh->state->compression_out_stream.avail_out == 0); return 0; } static int uncompress_buffer(struct ssh *ssh, struct sshbuf *in, struct sshbuf *out) { u_char buf[4096]; int r, status; if (ssh->state->compression_in_started != 1) return SSH_ERR_INTERNAL_ERROR; if ((ssh->state->compression_in_stream.next_in = sshbuf_mutable_ptr(in)) == NULL) return SSH_ERR_INTERNAL_ERROR; ssh->state->compression_in_stream.avail_in = sshbuf_len(in); for (;;) { /* Set up fixed-size output buffer. */ ssh->state->compression_in_stream.next_out = buf; ssh->state->compression_in_stream.avail_out = sizeof(buf); status = inflate(&ssh->state->compression_in_stream, Z_PARTIAL_FLUSH); switch (status) { case Z_OK: if ((r = sshbuf_put(out, buf, sizeof(buf) - ssh->state->compression_in_stream.avail_out)) != 0) return r; break; case Z_BUF_ERROR: /* * Comments in zlib.h say that we should keep calling * inflate() until we get an error. This appears to * be the error that we get. */ return 0; case Z_DATA_ERROR: return SSH_ERR_INVALID_FORMAT; case Z_MEM_ERROR: return SSH_ERR_ALLOC_FAIL; case Z_STREAM_ERROR: default: ssh->state->compression_in_failures++; return SSH_ERR_INTERNAL_ERROR; } } /* NOTREACHED */ } /* Serialise compression state into a blob for privsep */ static int ssh_packet_get_compress_state(struct sshbuf *m, struct ssh *ssh) { struct session_state *state = ssh->state; struct sshbuf *b; int r; if ((b = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if (state->compression_in_started) { if ((r = sshbuf_put_string(b, &state->compression_in_stream, sizeof(state->compression_in_stream))) != 0) goto out; } else if ((r = sshbuf_put_string(b, NULL, 0)) != 0) goto out; if (state->compression_out_started) { if ((r = sshbuf_put_string(b, &state->compression_out_stream, sizeof(state->compression_out_stream))) != 0) goto out; } else if ((r = sshbuf_put_string(b, NULL, 0)) != 0) goto out; r = sshbuf_put_stringb(m, b); out: sshbuf_free(b); return r; } /* Deserialise compression state from a blob for privsep */ static int ssh_packet_set_compress_state(struct ssh *ssh, struct sshbuf *m) { struct session_state *state = ssh->state; struct sshbuf *b = NULL; int r; const u_char *inblob, *outblob; size_t inl, outl; if ((r = sshbuf_froms(m, &b)) != 0) goto out; if ((r = sshbuf_get_string_direct(b, &inblob, &inl)) != 0 || (r = sshbuf_get_string_direct(b, &outblob, &outl)) != 0) goto out; if (inl == 0) state->compression_in_started = 0; else if (inl != sizeof(state->compression_in_stream)) { r = SSH_ERR_INTERNAL_ERROR; goto out; } else { state->compression_in_started = 1; memcpy(&state->compression_in_stream, inblob, inl); } if (outl == 0) state->compression_out_started = 0; else if (outl != sizeof(state->compression_out_stream)) { r = SSH_ERR_INTERNAL_ERROR; goto out; } else { state->compression_out_started = 1; memcpy(&state->compression_out_stream, outblob, outl); } r = 0; out: sshbuf_free(b); return r; } void ssh_packet_set_compress_hooks(struct ssh *ssh, void *ctx, void *(*allocfunc)(void *, u_int, u_int), void (*freefunc)(void *, void *)) { ssh->state->compression_out_stream.zalloc = (alloc_func)allocfunc; ssh->state->compression_out_stream.zfree = (free_func)freefunc; ssh->state->compression_out_stream.opaque = ctx; ssh->state->compression_in_stream.zalloc = (alloc_func)allocfunc; ssh->state->compression_in_stream.zfree = (free_func)freefunc; ssh->state->compression_in_stream.opaque = ctx; } /* * Causes any further packets to be encrypted using the given key. The same * key is used for both sending and reception. However, both directions are * encrypted independently of each other. */ void ssh_packet_set_encryption_key(struct ssh *ssh, const u_char *key, u_int keylen, int number) { #ifndef WITH_SSH1 fatal("no SSH protocol 1 support"); #else /* WITH_SSH1 */ struct session_state *state = ssh->state; const struct sshcipher *cipher = cipher_by_number(number); int r; const char *wmsg; if (cipher == NULL) fatal("%s: unknown cipher number %d", __func__, number); if (keylen < 20) fatal("%s: keylen too small: %d", __func__, keylen); if (keylen > SSH_SESSION_KEY_LENGTH) fatal("%s: keylen too big: %d", __func__, keylen); memcpy(state->ssh1_key, key, keylen); state->ssh1_keylen = keylen; if ((r = cipher_init(&state->send_context, cipher, key, keylen, NULL, 0, CIPHER_ENCRYPT)) != 0 || (r = cipher_init(&state->receive_context, cipher, key, keylen, NULL, 0, CIPHER_DECRYPT) != 0)) fatal("%s: cipher_init failed: %s", __func__, ssh_err(r)); if (!state->cipher_warning_done && ((wmsg = cipher_warning_message(&state->send_context)) != NULL || (wmsg = cipher_warning_message(&state->send_context)) != NULL)) { error("Warning: %s", wmsg); state->cipher_warning_done = 1; } #endif /* WITH_SSH1 */ } /* * Finalizes and sends the packet. If the encryption key has been set, * encrypts the packet before sending. */ int ssh_packet_send1(struct ssh *ssh) { struct session_state *state = ssh->state; u_char buf[8], *cp; int r, padding, len; u_int checksum; /* * If using packet compression, compress the payload of the outgoing * packet. */ if (state->packet_compression) { sshbuf_reset(state->compression_buffer); /* Skip padding. */ if ((r = sshbuf_consume(state->outgoing_packet, 8)) != 0) goto out; /* padding */ if ((r = sshbuf_put(state->compression_buffer, "\0\0\0\0\0\0\0\0", 8)) != 0) goto out; if ((r = compress_buffer(ssh, state->outgoing_packet, state->compression_buffer)) != 0) goto out; sshbuf_reset(state->outgoing_packet); if ((r = sshbuf_putb(state->outgoing_packet, state->compression_buffer)) != 0) goto out; } /* Compute packet length without padding (add checksum, remove padding). */ len = sshbuf_len(state->outgoing_packet) + 4 - 8; /* Insert padding. Initialized to zero in packet_start1() */ padding = 8 - len % 8; if (!state->send_context.plaintext) { cp = sshbuf_mutable_ptr(state->outgoing_packet); if (cp == NULL) { r = SSH_ERR_INTERNAL_ERROR; goto out; } arc4random_buf(cp + 8 - padding, padding); } if ((r = sshbuf_consume(state->outgoing_packet, 8 - padding)) != 0) goto out; /* Add check bytes. */ checksum = ssh_crc32(sshbuf_ptr(state->outgoing_packet), sshbuf_len(state->outgoing_packet)); POKE_U32(buf, checksum); if ((r = sshbuf_put(state->outgoing_packet, buf, 4)) != 0) goto out; #ifdef PACKET_DEBUG fprintf(stderr, "packet_send plain: "); sshbuf_dump(state->outgoing_packet, stderr); #endif /* Append to output. */ POKE_U32(buf, len); if ((r = sshbuf_put(state->output, buf, 4)) != 0) goto out; if ((r = sshbuf_reserve(state->output, sshbuf_len(state->outgoing_packet), &cp)) != 0) goto out; if ((r = cipher_crypt(&state->send_context, 0, cp, sshbuf_ptr(state->outgoing_packet), sshbuf_len(state->outgoing_packet), 0, 0)) != 0) goto out; #ifdef PACKET_DEBUG fprintf(stderr, "encrypted: "); sshbuf_dump(state->output, stderr); #endif state->p_send.packets++; state->p_send.bytes += len + sshbuf_len(state->outgoing_packet); sshbuf_reset(state->outgoing_packet); /* * Note that the packet is now only buffered in output. It won't be * actually sent until ssh_packet_write_wait or ssh_packet_write_poll * is called. */ r = 0; out: return r; } int ssh_set_newkeys(struct ssh *ssh, int mode) { struct session_state *state = ssh->state; struct sshenc *enc; struct sshmac *mac; struct sshcomp *comp; struct sshcipher_ctx *cc; u_int64_t *max_blocks; const char *wmsg; int r, crypt_type; debug2("set_newkeys: mode %d", mode); if (mode == MODE_OUT) { cc = &state->send_context; crypt_type = CIPHER_ENCRYPT; state->p_send.packets = state->p_send.blocks = 0; max_blocks = &state->max_blocks_out; } else { cc = &state->receive_context; crypt_type = CIPHER_DECRYPT; state->p_read.packets = state->p_read.blocks = 0; max_blocks = &state->max_blocks_in; } if (state->newkeys[mode] != NULL) { debug("set_newkeys: rekeying"); if ((r = cipher_cleanup(cc)) != 0) return r; enc = &state->newkeys[mode]->enc; mac = &state->newkeys[mode]->mac; comp = &state->newkeys[mode]->comp; mac_clear(mac); explicit_bzero(enc->iv, enc->iv_len); explicit_bzero(enc->key, enc->key_len); explicit_bzero(mac->key, mac->key_len); free(enc->name); free(enc->iv); free(enc->key); free(mac->name); free(mac->key); free(comp->name); free(state->newkeys[mode]); } /* move newkeys from kex to state */ if ((state->newkeys[mode] = ssh->kex->newkeys[mode]) == NULL) return SSH_ERR_INTERNAL_ERROR; ssh->kex->newkeys[mode] = NULL; enc = &state->newkeys[mode]->enc; mac = &state->newkeys[mode]->mac; comp = &state->newkeys[mode]->comp; if (cipher_authlen(enc->cipher) == 0) { if ((r = mac_init(mac)) != 0) return r; } mac->enabled = 1; DBG(debug("cipher_init_context: %d", mode)); if ((r = cipher_init(cc, enc->cipher, enc->key, enc->key_len, enc->iv, enc->iv_len, crypt_type)) != 0) return r; if (!state->cipher_warning_done && (wmsg = cipher_warning_message(cc)) != NULL) { error("Warning: %s", wmsg); state->cipher_warning_done = 1; } /* Deleting the keys does not gain extra security */ /* explicit_bzero(enc->iv, enc->block_size); explicit_bzero(enc->key, enc->key_len); explicit_bzero(mac->key, mac->key_len); */ if ((comp->type == COMP_ZLIB || (comp->type == COMP_DELAYED && state->after_authentication)) && comp->enabled == 0) { if ((r = ssh_packet_init_compression(ssh)) < 0) return r; if (mode == MODE_OUT) { if ((r = start_compression_out(ssh, 6)) != 0) return r; } else { if ((r = start_compression_in(ssh)) != 0) return r; } comp->enabled = 1; } /* * The 2^(blocksize*2) limit is too expensive for 3DES, * blowfish, etc, so enforce a 1GB limit for small blocksizes. */ if (enc->block_size >= 16) *max_blocks = (u_int64_t)1 << (enc->block_size*2); else *max_blocks = ((u_int64_t)1 << 30) / enc->block_size; if (state->rekey_limit) *max_blocks = MIN(*max_blocks, state->rekey_limit / enc->block_size); return 0; } /* * Delayed compression for SSH2 is enabled after authentication: * This happens on the server side after a SSH2_MSG_USERAUTH_SUCCESS is sent, * and on the client side after a SSH2_MSG_USERAUTH_SUCCESS is received. */ static int ssh_packet_enable_delayed_compress(struct ssh *ssh) { struct session_state *state = ssh->state; struct sshcomp *comp = NULL; int r, mode; /* * Remember that we are past the authentication step, so rekeying * with COMP_DELAYED will turn on compression immediately. */ state->after_authentication = 1; for (mode = 0; mode < MODE_MAX; mode++) { /* protocol error: USERAUTH_SUCCESS received before NEWKEYS */ if (state->newkeys[mode] == NULL) continue; comp = &state->newkeys[mode]->comp; if (comp && !comp->enabled && comp->type == COMP_DELAYED) { if ((r = ssh_packet_init_compression(ssh)) != 0) return r; if (mode == MODE_OUT) { if ((r = start_compression_out(ssh, 6)) != 0) return r; } else { if ((r = start_compression_in(ssh)) != 0) return r; } comp->enabled = 1; } } return 0; } /* * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) */ int ssh_packet_send2_wrapped(struct ssh *ssh) { struct session_state *state = ssh->state; u_char type, *cp, macbuf[SSH_DIGEST_MAX_LENGTH]; u_char padlen, pad = 0; u_int authlen = 0, aadlen = 0; u_int len; struct sshenc *enc = NULL; struct sshmac *mac = NULL; struct sshcomp *comp = NULL; int r, block_size; if (state->newkeys[MODE_OUT] != NULL) { enc = &state->newkeys[MODE_OUT]->enc; mac = &state->newkeys[MODE_OUT]->mac; comp = &state->newkeys[MODE_OUT]->comp; /* disable mac for authenticated encryption */ if ((authlen = cipher_authlen(enc->cipher)) != 0) mac = NULL; } block_size = enc ? enc->block_size : 8; aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0; type = (sshbuf_ptr(state->outgoing_packet))[5]; #ifdef PACKET_DEBUG fprintf(stderr, "plain: "); sshbuf_dump(state->outgoing_packet, stderr); #endif if (comp && comp->enabled) { len = sshbuf_len(state->outgoing_packet); /* skip header, compress only payload */ if ((r = sshbuf_consume(state->outgoing_packet, 5)) != 0) goto out; sshbuf_reset(state->compression_buffer); if ((r = compress_buffer(ssh, state->outgoing_packet, state->compression_buffer)) != 0) goto out; sshbuf_reset(state->outgoing_packet); if ((r = sshbuf_put(state->outgoing_packet, "\0\0\0\0\0", 5)) != 0 || (r = sshbuf_putb(state->outgoing_packet, state->compression_buffer)) != 0) goto out; DBG(debug("compression: raw %d compressed %zd", len, sshbuf_len(state->outgoing_packet))); } /* sizeof (packet_len + pad_len + payload) */ len = sshbuf_len(state->outgoing_packet); /* * calc size of padding, alloc space, get random data, * minimum padding is 4 bytes */ len -= aadlen; /* packet length is not encrypted for EtM modes */ padlen = block_size - (len % block_size); if (padlen < 4) padlen += block_size; if (state->extra_pad) { /* will wrap if extra_pad+padlen > 255 */ state->extra_pad = roundup(state->extra_pad, block_size); pad = state->extra_pad - ((len + padlen) % state->extra_pad); DBG(debug3("%s: adding %d (len %d padlen %d extra_pad %d)", __func__, pad, len, padlen, state->extra_pad)); padlen += pad; state->extra_pad = 0; } if ((r = sshbuf_reserve(state->outgoing_packet, padlen, &cp)) != 0) goto out; if (enc && !state->send_context.plaintext) { /* random padding */ arc4random_buf(cp, padlen); } else { /* clear padding */ explicit_bzero(cp, padlen); } /* sizeof (packet_len + pad_len + payload + padding) */ len = sshbuf_len(state->outgoing_packet); cp = sshbuf_mutable_ptr(state->outgoing_packet); if (cp == NULL) { r = SSH_ERR_INTERNAL_ERROR; goto out; } /* packet_length includes payload, padding and padding length field */ POKE_U32(cp, len - 4); cp[4] = padlen; DBG(debug("send: len %d (includes padlen %d, aadlen %d)", len, padlen, aadlen)); /* compute MAC over seqnr and packet(length fields, payload, padding) */ if (mac && mac->enabled && !mac->etm) { if ((r = mac_compute(mac, state->p_send.seqnr, sshbuf_ptr(state->outgoing_packet), len, macbuf, sizeof(macbuf))) != 0) goto out; DBG(debug("done calc MAC out #%d", state->p_send.seqnr)); } /* encrypt packet and append to output buffer. */ if ((r = sshbuf_reserve(state->output, sshbuf_len(state->outgoing_packet) + authlen, &cp)) != 0) goto out; if ((r = cipher_crypt(&state->send_context, state->p_send.seqnr, cp, sshbuf_ptr(state->outgoing_packet), len - aadlen, aadlen, authlen)) != 0) goto out; /* append unencrypted MAC */ if (mac && mac->enabled) { if (mac->etm) { /* EtM: compute mac over aadlen + cipher text */ if ((r = mac_compute(mac, state->p_send.seqnr, cp, len, macbuf, sizeof(macbuf))) != 0) goto out; DBG(debug("done calc MAC(EtM) out #%d", state->p_send.seqnr)); } if ((r = sshbuf_put(state->output, macbuf, mac->mac_len)) != 0) goto out; } #ifdef PACKET_DEBUG fprintf(stderr, "encrypted: "); sshbuf_dump(state->output, stderr); #endif /* increment sequence number for outgoing packets */ if (++state->p_send.seqnr == 0) logit("outgoing seqnr wraps around"); if (++state->p_send.packets == 0) if (!(ssh->compat & SSH_BUG_NOREKEY)) return SSH_ERR_NEED_REKEY; state->p_send.blocks += len / block_size; state->p_send.bytes += len; sshbuf_reset(state->outgoing_packet); if (type == SSH2_MSG_NEWKEYS) r = ssh_set_newkeys(ssh, MODE_OUT); else if (type == SSH2_MSG_USERAUTH_SUCCESS && state->server_side) r = ssh_packet_enable_delayed_compress(ssh); else r = 0; out: return r; } int ssh_packet_send2(struct ssh *ssh) { struct session_state *state = ssh->state; struct packet *p; u_char type; int r; type = sshbuf_ptr(state->outgoing_packet)[5]; /* during rekeying we can only send key exchange messages */ if (state->rekeying) { if ((type < SSH2_MSG_TRANSPORT_MIN) || (type > SSH2_MSG_TRANSPORT_MAX) || (type == SSH2_MSG_SERVICE_REQUEST) || (type == SSH2_MSG_SERVICE_ACCEPT)) { debug("enqueue packet: %u", type); p = calloc(1, sizeof(*p)); if (p == NULL) return SSH_ERR_ALLOC_FAIL; p->type = type; p->payload = state->outgoing_packet; TAILQ_INSERT_TAIL(&state->outgoing, p, next); state->outgoing_packet = sshbuf_new(); if (state->outgoing_packet == NULL) return SSH_ERR_ALLOC_FAIL; return 0; } } /* rekeying starts with sending KEXINIT */ if (type == SSH2_MSG_KEXINIT) state->rekeying = 1; if ((r = ssh_packet_send2_wrapped(ssh)) != 0) return r; /* after a NEWKEYS message we can send the complete queue */ if (type == SSH2_MSG_NEWKEYS) { state->rekeying = 0; state->rekey_time = monotime(); while ((p = TAILQ_FIRST(&state->outgoing))) { type = p->type; debug("dequeue packet: %u", type); sshbuf_free(state->outgoing_packet); state->outgoing_packet = p->payload; TAILQ_REMOVE(&state->outgoing, p, next); free(p); if ((r = ssh_packet_send2_wrapped(ssh)) != 0) return r; } } return 0; } /* * Waits until a packet has been received, and returns its type. Note that * no other data is processed until this returns, so this function should not * be used during the interactive session. */ int ssh_packet_read_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) { struct session_state *state = ssh->state; int len, r, ms_remain, cont; fd_set *setp; char buf[8192]; struct timeval timeout, start, *timeoutp = NULL; DBG(debug("packet_read()")); - setp = (fd_set *)calloc(howmany(state->connection_in + 1, + setp = calloc(howmany(state->connection_in + 1, NFDBITS), sizeof(fd_mask)); if (setp == NULL) return SSH_ERR_ALLOC_FAIL; /* * Since we are blocking, ensure that all written packets have * been sent. */ if ((r = ssh_packet_write_wait(ssh)) != 0) goto out; /* Stay in the loop until we have received a complete packet. */ for (;;) { /* Try to read a packet from the buffer. */ r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p); if (r != 0) break; if (!compat20 && ( *typep == SSH_SMSG_SUCCESS || *typep == SSH_SMSG_FAILURE || *typep == SSH_CMSG_EOF || *typep == SSH_CMSG_EXIT_CONFIRMATION)) if ((r = sshpkt_get_end(ssh)) != 0) break; /* If we got a packet, return it. */ if (*typep != SSH_MSG_NONE) break; /* * Otherwise, wait for some data to arrive, add it to the * buffer, and try again. */ memset(setp, 0, howmany(state->connection_in + 1, NFDBITS) * sizeof(fd_mask)); FD_SET(state->connection_in, setp); if (state->packet_timeout_ms > 0) { ms_remain = state->packet_timeout_ms; timeoutp = &timeout; } /* Wait for some data to arrive. */ for (;;) { if (state->packet_timeout_ms != -1) { ms_to_timeval(&timeout, ms_remain); gettimeofday(&start, NULL); } if ((r = select(state->connection_in + 1, setp, NULL, NULL, timeoutp)) >= 0) break; if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) break; if (state->packet_timeout_ms == -1) continue; ms_subtract_diff(&start, &ms_remain); if (ms_remain <= 0) { r = 0; break; } } if (r == 0) return SSH_ERR_CONN_TIMEOUT; /* Read data from the socket. */ do { cont = 0; len = roaming_read(state->connection_in, buf, sizeof(buf), &cont); } while (len == 0 && cont); if (len == 0) { r = SSH_ERR_CONN_CLOSED; goto out; } if (len < 0) { r = SSH_ERR_SYSTEM_ERROR; goto out; } /* Append it to the buffer. */ if ((r = ssh_packet_process_incoming(ssh, buf, len)) != 0) goto out; } out: free(setp); return r; } int ssh_packet_read(struct ssh *ssh) { u_char type; int r; if ((r = ssh_packet_read_seqnr(ssh, &type, NULL)) != 0) fatal("%s: %s", __func__, ssh_err(r)); return type; } /* * Waits until a packet has been received, verifies that its type matches * that given, and gives a fatal error and exits if there is a mismatch. */ int ssh_packet_read_expect(struct ssh *ssh, u_int expected_type) { int r; u_char type; if ((r = ssh_packet_read_seqnr(ssh, &type, NULL)) != 0) return r; if (type != expected_type) { if ((r = sshpkt_disconnect(ssh, "Protocol error: expected packet type %d, got %d", expected_type, type)) != 0) return r; return SSH_ERR_PROTOCOL_ERROR; } return 0; } /* Checks if a full packet is available in the data received so far via * packet_process_incoming. If so, reads the packet; otherwise returns * SSH_MSG_NONE. This does not wait for data from the connection. * * SSH_MSG_DISCONNECT is handled specially here. Also, * SSH_MSG_IGNORE messages are skipped by this function and are never returned * to higher levels. */ int ssh_packet_read_poll1(struct ssh *ssh, u_char *typep) { struct session_state *state = ssh->state; u_int len, padded_len; const char *emsg; const u_char *cp; u_char *p; u_int checksum, stored_checksum; int r; *typep = SSH_MSG_NONE; /* Check if input size is less than minimum packet size. */ if (sshbuf_len(state->input) < 4 + 8) return 0; /* Get length of incoming packet. */ len = PEEK_U32(sshbuf_ptr(state->input)); if (len < 1 + 2 + 2 || len > 256 * 1024) { if ((r = sshpkt_disconnect(ssh, "Bad packet length %u", len)) != 0) return r; return SSH_ERR_CONN_CORRUPT; } padded_len = (len + 8) & ~7; /* Check if the packet has been entirely received. */ if (sshbuf_len(state->input) < 4 + padded_len) return 0; /* The entire packet is in buffer. */ /* Consume packet length. */ if ((r = sshbuf_consume(state->input, 4)) != 0) goto out; /* * Cryptographic attack detector for ssh * (C)1998 CORE-SDI, Buenos Aires Argentina * Ariel Futoransky(futo@core-sdi.com) */ if (!state->receive_context.plaintext) { emsg = NULL; switch (detect_attack(&state->deattack, sshbuf_ptr(state->input), padded_len)) { case DEATTACK_OK: break; case DEATTACK_DETECTED: emsg = "crc32 compensation attack detected"; break; case DEATTACK_DOS_DETECTED: emsg = "deattack denial of service detected"; break; default: emsg = "deattack error"; break; } if (emsg != NULL) { error("%s", emsg); if ((r = sshpkt_disconnect(ssh, "%s", emsg)) != 0 || (r = ssh_packet_write_wait(ssh)) != 0) return r; return SSH_ERR_CONN_CORRUPT; } } /* Decrypt data to incoming_packet. */ sshbuf_reset(state->incoming_packet); if ((r = sshbuf_reserve(state->incoming_packet, padded_len, &p)) != 0) goto out; if ((r = cipher_crypt(&state->receive_context, 0, p, sshbuf_ptr(state->input), padded_len, 0, 0)) != 0) goto out; if ((r = sshbuf_consume(state->input, padded_len)) != 0) goto out; #ifdef PACKET_DEBUG fprintf(stderr, "read_poll plain: "); sshbuf_dump(state->incoming_packet, stderr); #endif /* Compute packet checksum. */ checksum = ssh_crc32(sshbuf_ptr(state->incoming_packet), sshbuf_len(state->incoming_packet) - 4); /* Skip padding. */ if ((r = sshbuf_consume(state->incoming_packet, 8 - len % 8)) != 0) goto out; /* Test check bytes. */ if (len != sshbuf_len(state->incoming_packet)) { error("%s: len %d != sshbuf_len %zd", __func__, len, sshbuf_len(state->incoming_packet)); if ((r = sshpkt_disconnect(ssh, "invalid packet length")) != 0 || (r = ssh_packet_write_wait(ssh)) != 0) return r; return SSH_ERR_CONN_CORRUPT; } cp = sshbuf_ptr(state->incoming_packet) + len - 4; stored_checksum = PEEK_U32(cp); if (checksum != stored_checksum) { error("Corrupted check bytes on input"); if ((r = sshpkt_disconnect(ssh, "connection corrupted")) != 0 || (r = ssh_packet_write_wait(ssh)) != 0) return r; return SSH_ERR_CONN_CORRUPT; } if ((r = sshbuf_consume_end(state->incoming_packet, 4)) < 0) goto out; if (state->packet_compression) { sshbuf_reset(state->compression_buffer); if ((r = uncompress_buffer(ssh, state->incoming_packet, state->compression_buffer)) != 0) goto out; sshbuf_reset(state->incoming_packet); if ((r = sshbuf_putb(state->incoming_packet, state->compression_buffer)) != 0) goto out; } state->p_read.packets++; state->p_read.bytes += padded_len + 4; if ((r = sshbuf_get_u8(state->incoming_packet, typep)) != 0) goto out; if (*typep < SSH_MSG_MIN || *typep > SSH_MSG_MAX) { error("Invalid ssh1 packet type: %d", *typep); if ((r = sshpkt_disconnect(ssh, "invalid packet type")) != 0 || (r = ssh_packet_write_wait(ssh)) != 0) return r; return SSH_ERR_PROTOCOL_ERROR; } r = 0; out: return r; } int ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) { struct session_state *state = ssh->state; u_int padlen, need; u_char *cp, macbuf[SSH_DIGEST_MAX_LENGTH]; u_int maclen, aadlen = 0, authlen = 0, block_size; struct sshenc *enc = NULL; struct sshmac *mac = NULL; struct sshcomp *comp = NULL; int r; *typep = SSH_MSG_NONE; if (state->packet_discard) return 0; if (state->newkeys[MODE_IN] != NULL) { enc = &state->newkeys[MODE_IN]->enc; mac = &state->newkeys[MODE_IN]->mac; comp = &state->newkeys[MODE_IN]->comp; /* disable mac for authenticated encryption */ if ((authlen = cipher_authlen(enc->cipher)) != 0) mac = NULL; } maclen = mac && mac->enabled ? mac->mac_len : 0; block_size = enc ? enc->block_size : 8; aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0; if (aadlen && state->packlen == 0) { if (cipher_get_length(&state->receive_context, &state->packlen, state->p_read.seqnr, sshbuf_ptr(state->input), sshbuf_len(state->input)) != 0) return 0; if (state->packlen < 1 + 4 || state->packlen > PACKET_MAX_SIZE) { #ifdef PACKET_DEBUG sshbuf_dump(state->input, stderr); #endif logit("Bad packet length %u.", state->packlen); if ((r = sshpkt_disconnect(ssh, "Packet corrupt")) != 0) return r; + return SSH_ERR_CONN_CORRUPT; } sshbuf_reset(state->incoming_packet); } else if (state->packlen == 0) { /* * check if input size is less than the cipher block size, * decrypt first block and extract length of incoming packet */ if (sshbuf_len(state->input) < block_size) return 0; sshbuf_reset(state->incoming_packet); if ((r = sshbuf_reserve(state->incoming_packet, block_size, &cp)) != 0) goto out; if ((r = cipher_crypt(&state->receive_context, state->p_send.seqnr, cp, sshbuf_ptr(state->input), block_size, 0, 0)) != 0) goto out; state->packlen = PEEK_U32(sshbuf_ptr(state->incoming_packet)); if (state->packlen < 1 + 4 || state->packlen > PACKET_MAX_SIZE) { #ifdef PACKET_DEBUG fprintf(stderr, "input: \n"); sshbuf_dump(state->input, stderr); fprintf(stderr, "incoming_packet: \n"); sshbuf_dump(state->incoming_packet, stderr); #endif logit("Bad packet length %u.", state->packlen); return ssh_packet_start_discard(ssh, enc, mac, state->packlen, PACKET_MAX_SIZE); } if ((r = sshbuf_consume(state->input, block_size)) != 0) goto out; } DBG(debug("input: packet len %u", state->packlen+4)); if (aadlen) { /* only the payload is encrypted */ need = state->packlen; } else { /* * the payload size and the payload are encrypted, but we * have a partial packet of block_size bytes */ need = 4 + state->packlen - block_size; } DBG(debug("partial packet: block %d, need %d, maclen %d, authlen %d," " aadlen %d", block_size, need, maclen, authlen, aadlen)); if (need % block_size != 0) { logit("padding error: need %d block %d mod %d", need, block_size, need % block_size); return ssh_packet_start_discard(ssh, enc, mac, state->packlen, PACKET_MAX_SIZE - block_size); } /* * check if the entire packet has been received and * decrypt into incoming_packet: * 'aadlen' bytes are unencrypted, but authenticated. * 'need' bytes are encrypted, followed by either * 'authlen' bytes of authentication tag or * 'maclen' bytes of message authentication code. */ if (sshbuf_len(state->input) < aadlen + need + authlen + maclen) return 0; #ifdef PACKET_DEBUG fprintf(stderr, "read_poll enc/full: "); sshbuf_dump(state->input, stderr); #endif /* EtM: compute mac over encrypted input */ if (mac && mac->enabled && mac->etm) { if ((r = mac_compute(mac, state->p_read.seqnr, sshbuf_ptr(state->input), aadlen + need, macbuf, sizeof(macbuf))) != 0) goto out; } if ((r = sshbuf_reserve(state->incoming_packet, aadlen + need, &cp)) != 0) goto out; if ((r = cipher_crypt(&state->receive_context, state->p_read.seqnr, cp, sshbuf_ptr(state->input), need, aadlen, authlen)) != 0) goto out; if ((r = sshbuf_consume(state->input, aadlen + need + authlen)) != 0) goto out; /* * compute MAC over seqnr and packet, * increment sequence number for incoming packet */ if (mac && mac->enabled) { if (!mac->etm) if ((r = mac_compute(mac, state->p_read.seqnr, sshbuf_ptr(state->incoming_packet), sshbuf_len(state->incoming_packet), macbuf, sizeof(macbuf))) != 0) goto out; if (timingsafe_bcmp(macbuf, sshbuf_ptr(state->input), mac->mac_len) != 0) { logit("Corrupted MAC on input."); if (need > PACKET_MAX_SIZE) return SSH_ERR_INTERNAL_ERROR; return ssh_packet_start_discard(ssh, enc, mac, state->packlen, PACKET_MAX_SIZE - need); } DBG(debug("MAC #%d ok", state->p_read.seqnr)); if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0) goto out; } if (seqnr_p != NULL) *seqnr_p = state->p_read.seqnr; if (++state->p_read.seqnr == 0) logit("incoming seqnr wraps around"); if (++state->p_read.packets == 0) if (!(ssh->compat & SSH_BUG_NOREKEY)) return SSH_ERR_NEED_REKEY; state->p_read.blocks += (state->packlen + 4) / block_size; state->p_read.bytes += state->packlen + 4; /* get padlen */ padlen = sshbuf_ptr(state->incoming_packet)[4]; DBG(debug("input: padlen %d", padlen)); if (padlen < 4) { if ((r = sshpkt_disconnect(ssh, "Corrupted padlen %d on input.", padlen)) != 0 || (r = ssh_packet_write_wait(ssh)) != 0) return r; return SSH_ERR_CONN_CORRUPT; } /* skip packet size + padlen, discard padding */ if ((r = sshbuf_consume(state->incoming_packet, 4 + 1)) != 0 || ((r = sshbuf_consume_end(state->incoming_packet, padlen)) != 0)) goto out; DBG(debug("input: len before de-compress %zd", sshbuf_len(state->incoming_packet))); if (comp && comp->enabled) { sshbuf_reset(state->compression_buffer); if ((r = uncompress_buffer(ssh, state->incoming_packet, state->compression_buffer)) != 0) goto out; sshbuf_reset(state->incoming_packet); if ((r = sshbuf_putb(state->incoming_packet, state->compression_buffer)) != 0) goto out; DBG(debug("input: len after de-compress %zd", sshbuf_len(state->incoming_packet))); } /* * get packet type, implies consume. * return length of payload (without type field) */ if ((r = sshbuf_get_u8(state->incoming_packet, typep)) != 0) goto out; if (*typep < SSH2_MSG_MIN || *typep >= SSH2_MSG_LOCAL_MIN) { if ((r = sshpkt_disconnect(ssh, "Invalid ssh2 packet type: %d", *typep)) != 0 || (r = ssh_packet_write_wait(ssh)) != 0) return r; return SSH_ERR_PROTOCOL_ERROR; } if (*typep == SSH2_MSG_NEWKEYS) r = ssh_set_newkeys(ssh, MODE_IN); else if (*typep == SSH2_MSG_USERAUTH_SUCCESS && !state->server_side) r = ssh_packet_enable_delayed_compress(ssh); else r = 0; #ifdef PACKET_DEBUG fprintf(stderr, "read/plain[%d]:\r\n", *typep); sshbuf_dump(state->incoming_packet, stderr); #endif /* reset for next packet */ state->packlen = 0; out: return r; } int ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) { struct session_state *state = ssh->state; u_int reason, seqnr; int r; u_char *msg; for (;;) { msg = NULL; if (compat20) { r = ssh_packet_read_poll2(ssh, typep, seqnr_p); if (r != 0) return r; if (*typep) { state->keep_alive_timeouts = 0; DBG(debug("received packet type %d", *typep)); } switch (*typep) { case SSH2_MSG_IGNORE: debug3("Received SSH2_MSG_IGNORE"); break; case SSH2_MSG_DEBUG: if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 || (r = sshpkt_get_string(ssh, NULL, NULL)) != 0) { if (msg) free(msg); return r; } debug("Remote: %.900s", msg); free(msg); break; case SSH2_MSG_DISCONNECT: if ((r = sshpkt_get_u32(ssh, &reason)) != 0 || (r = sshpkt_get_string(ssh, &msg, NULL)) != 0) return r; /* Ignore normal client exit notifications */ do_log2(ssh->state->server_side && reason == SSH2_DISCONNECT_BY_APPLICATION ? SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR, "Received disconnect from %s: %u: %.400s", ssh_remote_ipaddr(ssh), reason, msg); free(msg); return SSH_ERR_DISCONNECTED; case SSH2_MSG_UNIMPLEMENTED: if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0) return r; debug("Received SSH2_MSG_UNIMPLEMENTED for %u", seqnr); break; default: return 0; } } else { r = ssh_packet_read_poll1(ssh, typep); switch (*typep) { case SSH_MSG_NONE: return SSH_MSG_NONE; case SSH_MSG_IGNORE: break; case SSH_MSG_DEBUG: if ((r = sshpkt_get_string(ssh, &msg, NULL)) != 0) return r; debug("Remote: %.900s", msg); free(msg); break; case SSH_MSG_DISCONNECT: if ((r = sshpkt_get_string(ssh, &msg, NULL)) != 0) return r; logit("Received disconnect from %s: %.400s", ssh_remote_ipaddr(ssh), msg); free(msg); return SSH_ERR_DISCONNECTED; default: DBG(debug("received packet type %d", *typep)); return 0; } } } } /* * Buffers the given amount of input characters. This is intended to be used * together with packet_read_poll. */ int ssh_packet_process_incoming(struct ssh *ssh, const char *buf, u_int len) { struct session_state *state = ssh->state; int r; if (state->packet_discard) { state->keep_alive_timeouts = 0; /* ?? */ if (len >= state->packet_discard) { if ((r = ssh_packet_stop_discard(ssh)) != 0) return r; } state->packet_discard -= len; return 0; } if ((r = sshbuf_put(ssh->state->input, buf, len)) != 0) return r; return 0; } int ssh_packet_remaining(struct ssh *ssh) { return sshbuf_len(ssh->state->incoming_packet); } /* * Sends a diagnostic message from the server to the client. This message * can be sent at any time (but not while constructing another message). The * message is printed immediately, but only if the client is being executed * in verbose mode. These messages are primarily intended to ease debugging * authentication problems. The length of the formatted message must not * exceed 1024 bytes. This will automatically call ssh_packet_write_wait. */ void ssh_packet_send_debug(struct ssh *ssh, const char *fmt,...) { char buf[1024]; va_list args; int r; if (compat20 && (ssh->compat & SSH_BUG_DEBUG)) return; va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); if (compat20) { if ((r = sshpkt_start(ssh, SSH2_MSG_DEBUG)) != 0 || (r = sshpkt_put_u8(ssh, 0)) != 0 || /* always display */ (r = sshpkt_put_cstring(ssh, buf)) != 0 || (r = sshpkt_put_cstring(ssh, "")) != 0 || (r = sshpkt_send(ssh)) != 0) fatal("%s: %s", __func__, ssh_err(r)); } else { if ((r = sshpkt_start(ssh, SSH_MSG_DEBUG)) != 0 || (r = sshpkt_put_cstring(ssh, buf)) != 0 || (r = sshpkt_send(ssh)) != 0) fatal("%s: %s", __func__, ssh_err(r)); } if ((r = ssh_packet_write_wait(ssh)) != 0) fatal("%s: %s", __func__, ssh_err(r)); } /* * Pretty-print connection-terminating errors and exit. */ void sshpkt_fatal(struct ssh *ssh, const char *tag, int r) { switch (r) { case SSH_ERR_CONN_CLOSED: logit("Connection closed by %.200s", ssh_remote_ipaddr(ssh)); cleanup_exit(255); case SSH_ERR_CONN_TIMEOUT: logit("Connection to %.200s timed out", ssh_remote_ipaddr(ssh)); cleanup_exit(255); case SSH_ERR_DISCONNECTED: logit("Disconnected from %.200s", ssh_remote_ipaddr(ssh)); cleanup_exit(255); case SSH_ERR_SYSTEM_ERROR: if (errno == ECONNRESET) { logit("Connection reset by %.200s", ssh_remote_ipaddr(ssh)); cleanup_exit(255); } /* FALLTHROUGH */ case SSH_ERR_NO_CIPHER_ALG_MATCH: case SSH_ERR_NO_MAC_ALG_MATCH: case SSH_ERR_NO_COMPRESS_ALG_MATCH: case SSH_ERR_NO_KEX_ALG_MATCH: case SSH_ERR_NO_HOSTKEY_ALG_MATCH: if (ssh && ssh->kex && ssh->kex->failed_choice) { fatal("Unable to negotiate with %.200s: %s. " "Their offer: %s", ssh_remote_ipaddr(ssh), ssh_err(r), ssh->kex->failed_choice); } /* FALLTHROUGH */ default: fatal("%s%sConnection to %.200s: %s", tag != NULL ? tag : "", tag != NULL ? ": " : "", ssh_remote_ipaddr(ssh), ssh_err(r)); } } /* * Logs the error plus constructs and sends a disconnect packet, closes the * connection, and exits. This function never returns. The error message * should not contain a newline. The length of the formatted message must * not exceed 1024 bytes. */ void ssh_packet_disconnect(struct ssh *ssh, const char *fmt,...) { char buf[1024]; va_list args; static int disconnecting = 0; int r; if (disconnecting) /* Guard against recursive invocations. */ fatal("packet_disconnect called recursively."); disconnecting = 1; /* * Format the message. Note that the caller must make sure the * message is of limited size. */ va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); /* Display the error locally */ logit("Disconnecting: %.100s", buf); /* * Send the disconnect message to the other side, and wait * for it to get sent. */ if ((r = sshpkt_disconnect(ssh, "%s", buf)) != 0) sshpkt_fatal(ssh, __func__, r); if ((r = ssh_packet_write_wait(ssh)) != 0) sshpkt_fatal(ssh, __func__, r); /* Close the connection. */ ssh_packet_close(ssh); cleanup_exit(255); } /* * Checks if there is any buffered output, and tries to write some of * the output. */ int ssh_packet_write_poll(struct ssh *ssh) { struct session_state *state = ssh->state; int len = sshbuf_len(state->output); int cont, r; if (len > 0) { cont = 0; len = roaming_write(state->connection_out, sshbuf_ptr(state->output), len, &cont); if (len == -1) { if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) return 0; return SSH_ERR_SYSTEM_ERROR; } if (len == 0 && !cont) return SSH_ERR_CONN_CLOSED; if ((r = sshbuf_consume(state->output, len)) != 0) return r; } return 0; } /* * Calls packet_write_poll repeatedly until all pending output data has been * written. */ int ssh_packet_write_wait(struct ssh *ssh) { fd_set *setp; int ret, r, ms_remain = 0; struct timeval start, timeout, *timeoutp = NULL; struct session_state *state = ssh->state; - setp = (fd_set *)calloc(howmany(state->connection_out + 1, + setp = calloc(howmany(state->connection_out + 1, NFDBITS), sizeof(fd_mask)); if (setp == NULL) return SSH_ERR_ALLOC_FAIL; ssh_packet_write_poll(ssh); while (ssh_packet_have_data_to_write(ssh)) { memset(setp, 0, howmany(state->connection_out + 1, NFDBITS) * sizeof(fd_mask)); FD_SET(state->connection_out, setp); if (state->packet_timeout_ms > 0) { ms_remain = state->packet_timeout_ms; timeoutp = &timeout; } for (;;) { if (state->packet_timeout_ms != -1) { ms_to_timeval(&timeout, ms_remain); gettimeofday(&start, NULL); } if ((ret = select(state->connection_out + 1, NULL, setp, NULL, timeoutp)) >= 0) break; if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) break; if (state->packet_timeout_ms == -1) continue; ms_subtract_diff(&start, &ms_remain); if (ms_remain <= 0) { ret = 0; break; } } if (ret == 0) { free(setp); return SSH_ERR_CONN_TIMEOUT; } if ((r = ssh_packet_write_poll(ssh)) != 0) { free(setp); return r; } } free(setp); return 0; } /* Returns true if there is buffered data to write to the connection. */ int ssh_packet_have_data_to_write(struct ssh *ssh) { return sshbuf_len(ssh->state->output) != 0; } /* Returns true if there is not too much data to write to the connection. */ int ssh_packet_not_very_much_data_to_write(struct ssh *ssh) { if (ssh->state->interactive_mode) return sshbuf_len(ssh->state->output) < 16384; else return sshbuf_len(ssh->state->output) < 128 * 1024; } void ssh_packet_set_tos(struct ssh *ssh, int tos) { #ifndef IP_TOS_IS_BROKEN if (!ssh_packet_connection_is_on_socket(ssh)) return; switch (ssh_packet_connection_af(ssh)) { # ifdef IP_TOS case AF_INET: debug3("%s: set IP_TOS 0x%02x", __func__, tos); if (setsockopt(ssh->state->connection_in, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) error("setsockopt IP_TOS %d: %.100s:", tos, strerror(errno)); break; # endif /* IP_TOS */ # ifdef IPV6_TCLASS case AF_INET6: debug3("%s: set IPV6_TCLASS 0x%02x", __func__, tos); if (setsockopt(ssh->state->connection_in, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)) < 0) error("setsockopt IPV6_TCLASS %d: %.100s:", tos, strerror(errno)); break; # endif /* IPV6_TCLASS */ } #endif /* IP_TOS_IS_BROKEN */ } /* Informs that the current session is interactive. Sets IP flags for that. */ void ssh_packet_set_interactive(struct ssh *ssh, int interactive, int qos_interactive, int qos_bulk) { struct session_state *state = ssh->state; if (state->set_interactive_called) return; state->set_interactive_called = 1; /* Record that we are in interactive mode. */ state->interactive_mode = interactive; /* Only set socket options if using a socket. */ if (!ssh_packet_connection_is_on_socket(ssh)) return; set_nodelay(state->connection_in); ssh_packet_set_tos(ssh, interactive ? qos_interactive : qos_bulk); } /* Returns true if the current connection is interactive. */ int ssh_packet_is_interactive(struct ssh *ssh) { return ssh->state->interactive_mode; } int ssh_packet_set_maxsize(struct ssh *ssh, u_int s) { struct session_state *state = ssh->state; if (state->set_maxsize_called) { logit("packet_set_maxsize: called twice: old %d new %d", state->max_packet_size, s); return -1; } if (s < 4 * 1024 || s > 1024 * 1024) { logit("packet_set_maxsize: bad size %d", s); return -1; } state->set_maxsize_called = 1; debug("packet_set_maxsize: setting to %d", s); state->max_packet_size = s; return s; } int ssh_packet_inc_alive_timeouts(struct ssh *ssh) { return ++ssh->state->keep_alive_timeouts; } void ssh_packet_set_alive_timeouts(struct ssh *ssh, int ka) { ssh->state->keep_alive_timeouts = ka; } u_int ssh_packet_get_maxsize(struct ssh *ssh) { return ssh->state->max_packet_size; } /* * 9.2. Ignored Data Message * * byte SSH_MSG_IGNORE * string data * * All implementations MUST understand (and ignore) this message at any * time (after receiving the protocol version). No implementation is * required to send them. This message can be used as an additional * protection measure against advanced traffic analysis techniques. */ void ssh_packet_send_ignore(struct ssh *ssh, int nbytes) { u_int32_t rnd = 0; int r, i; if ((r = sshpkt_start(ssh, compat20 ? SSH2_MSG_IGNORE : SSH_MSG_IGNORE)) != 0 || (r = sshpkt_put_u32(ssh, nbytes)) != 0) fatal("%s: %s", __func__, ssh_err(r)); for (i = 0; i < nbytes; i++) { if (i % 4 == 0) rnd = arc4random(); if ((r = sshpkt_put_u8(ssh, (u_char)rnd & 0xff)) != 0) fatal("%s: %s", __func__, ssh_err(r)); rnd >>= 8; } } #define MAX_PACKETS (1U<<31) int ssh_packet_need_rekeying(struct ssh *ssh) { struct session_state *state = ssh->state; if (ssh->compat & SSH_BUG_NOREKEY) return 0; return (state->p_send.packets > MAX_PACKETS) || (state->p_read.packets > MAX_PACKETS) || (state->max_blocks_out && (state->p_send.blocks > state->max_blocks_out)) || (state->max_blocks_in && (state->p_read.blocks > state->max_blocks_in)) || (state->rekey_interval != 0 && state->rekey_time + state->rekey_interval <= monotime()); } void ssh_packet_set_rekey_limits(struct ssh *ssh, u_int32_t bytes, time_t seconds) { debug3("rekey after %lld bytes, %d seconds", (long long)bytes, (int)seconds); ssh->state->rekey_limit = bytes; ssh->state->rekey_interval = seconds; } time_t ssh_packet_get_rekey_timeout(struct ssh *ssh) { time_t seconds; seconds = ssh->state->rekey_time + ssh->state->rekey_interval - monotime(); return (seconds <= 0 ? 1 : seconds); } void ssh_packet_set_server(struct ssh *ssh) { ssh->state->server_side = 1; } void ssh_packet_set_authenticated(struct ssh *ssh) { ssh->state->after_authentication = 1; } void * ssh_packet_get_input(struct ssh *ssh) { return (void *)ssh->state->input; } void * ssh_packet_get_output(struct ssh *ssh) { return (void *)ssh->state->output; } /* XXX TODO update roaming to new API (does not work anyway) */ /* * Save the state for the real connection, and use a separate state when * resuming a suspended connection. */ void ssh_packet_backup_state(struct ssh *ssh, struct ssh *backup_state) { struct ssh *tmp; close(ssh->state->connection_in); ssh->state->connection_in = -1; close(ssh->state->connection_out); ssh->state->connection_out = -1; if (backup_state) tmp = backup_state; else tmp = ssh_alloc_session_state(); backup_state = ssh; ssh = tmp; } /* XXX FIXME FIXME FIXME */ /* * Swap in the old state when resuming a connecion. */ void ssh_packet_restore_state(struct ssh *ssh, struct ssh *backup_state) { struct ssh *tmp; u_int len; int r; tmp = backup_state; backup_state = ssh; ssh = tmp; ssh->state->connection_in = backup_state->state->connection_in; backup_state->state->connection_in = -1; ssh->state->connection_out = backup_state->state->connection_out; backup_state->state->connection_out = -1; len = sshbuf_len(backup_state->state->input); if (len > 0) { if ((r = sshbuf_putb(ssh->state->input, backup_state->state->input)) != 0) fatal("%s: %s", __func__, ssh_err(r)); sshbuf_reset(backup_state->state->input); add_recv_bytes(len); } } /* Reset after_authentication and reset compression in post-auth privsep */ static int ssh_packet_set_postauth(struct ssh *ssh) { struct sshcomp *comp; int r, mode; debug("%s: called", __func__); /* This was set in net child, but is not visible in user child */ ssh->state->after_authentication = 1; ssh->state->rekeying = 0; for (mode = 0; mode < MODE_MAX; mode++) { if (ssh->state->newkeys[mode] == NULL) continue; comp = &ssh->state->newkeys[mode]->comp; if (comp && comp->enabled && (r = ssh_packet_init_compression(ssh)) != 0) return r; } return 0; } /* Packet state (de-)serialization for privsep */ /* turn kex into a blob for packet state serialization */ static int kex_to_blob(struct sshbuf *m, struct kex *kex) { int r; if ((r = sshbuf_put_string(m, kex->session_id, kex->session_id_len)) != 0 || (r = sshbuf_put_u32(m, kex->we_need)) != 0 || (r = sshbuf_put_u32(m, kex->hostkey_type)) != 0 || (r = sshbuf_put_u32(m, kex->kex_type)) != 0 || (r = sshbuf_put_stringb(m, kex->my)) != 0 || (r = sshbuf_put_stringb(m, kex->peer)) != 0 || (r = sshbuf_put_u32(m, kex->flags)) != 0 || (r = sshbuf_put_cstring(m, kex->client_version_string)) != 0 || (r = sshbuf_put_cstring(m, kex->server_version_string)) != 0) return r; return 0; } /* turn key exchange results into a blob for packet state serialization */ static int newkeys_to_blob(struct sshbuf *m, struct ssh *ssh, int mode) { struct sshbuf *b; struct sshcipher_ctx *cc; struct sshcomp *comp; struct sshenc *enc; struct sshmac *mac; struct newkeys *newkey; int r; if ((newkey = ssh->state->newkeys[mode]) == NULL) return SSH_ERR_INTERNAL_ERROR; enc = &newkey->enc; mac = &newkey->mac; comp = &newkey->comp; cc = (mode == MODE_OUT) ? &ssh->state->send_context : &ssh->state->receive_context; if ((r = cipher_get_keyiv(cc, enc->iv, enc->iv_len)) != 0) return r; if ((b = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; /* The cipher struct is constant and shared, you export pointer */ if ((r = sshbuf_put_cstring(b, enc->name)) != 0 || (r = sshbuf_put(b, &enc->cipher, sizeof(enc->cipher))) != 0 || (r = sshbuf_put_u32(b, enc->enabled)) != 0 || (r = sshbuf_put_u32(b, enc->block_size)) != 0 || (r = sshbuf_put_string(b, enc->key, enc->key_len)) != 0 || (r = sshbuf_put_string(b, enc->iv, enc->iv_len)) != 0) goto out; if (cipher_authlen(enc->cipher) == 0) { if ((r = sshbuf_put_cstring(b, mac->name)) != 0 || (r = sshbuf_put_u32(b, mac->enabled)) != 0 || (r = sshbuf_put_string(b, mac->key, mac->key_len)) != 0) goto out; } if ((r = sshbuf_put_u32(b, comp->type)) != 0 || (r = sshbuf_put_u32(b, comp->enabled)) != 0 || (r = sshbuf_put_cstring(b, comp->name)) != 0) goto out; r = sshbuf_put_stringb(m, b); out: if (b != NULL) sshbuf_free(b); return r; } /* serialize packet state into a blob */ int ssh_packet_get_state(struct ssh *ssh, struct sshbuf *m) { struct session_state *state = ssh->state; u_char *p; size_t slen, rlen; int r, ssh1cipher; if (!compat20) { ssh1cipher = cipher_get_number(state->receive_context.cipher); slen = cipher_get_keyiv_len(&state->send_context); rlen = cipher_get_keyiv_len(&state->receive_context); if ((r = sshbuf_put_u32(m, state->remote_protocol_flags)) != 0 || (r = sshbuf_put_u32(m, ssh1cipher)) != 0 || (r = sshbuf_put_string(m, state->ssh1_key, state->ssh1_keylen)) != 0 || (r = sshbuf_put_u32(m, slen)) != 0 || (r = sshbuf_reserve(m, slen, &p)) != 0 || (r = cipher_get_keyiv(&state->send_context, p, slen)) != 0 || (r = sshbuf_put_u32(m, rlen)) != 0 || (r = sshbuf_reserve(m, rlen, &p)) != 0 || (r = cipher_get_keyiv(&state->receive_context, p, rlen)) != 0) return r; } else { if ((r = kex_to_blob(m, ssh->kex)) != 0 || (r = newkeys_to_blob(m, ssh, MODE_OUT)) != 0 || (r = newkeys_to_blob(m, ssh, MODE_IN)) != 0 || (r = sshbuf_put_u32(m, state->rekey_limit)) != 0 || (r = sshbuf_put_u32(m, state->rekey_interval)) != 0 || (r = sshbuf_put_u32(m, state->p_send.seqnr)) != 0 || (r = sshbuf_put_u64(m, state->p_send.blocks)) != 0 || (r = sshbuf_put_u32(m, state->p_send.packets)) != 0 || (r = sshbuf_put_u64(m, state->p_send.bytes)) != 0 || (r = sshbuf_put_u32(m, state->p_read.seqnr)) != 0 || (r = sshbuf_put_u64(m, state->p_read.blocks)) != 0 || (r = sshbuf_put_u32(m, state->p_read.packets)) != 0 || (r = sshbuf_put_u64(m, state->p_read.bytes)) != 0) return r; } slen = cipher_get_keycontext(&state->send_context, NULL); rlen = cipher_get_keycontext(&state->receive_context, NULL); if ((r = sshbuf_put_u32(m, slen)) != 0 || (r = sshbuf_reserve(m, slen, &p)) != 0) return r; if (cipher_get_keycontext(&state->send_context, p) != (int)slen) return SSH_ERR_INTERNAL_ERROR; if ((r = sshbuf_put_u32(m, rlen)) != 0 || (r = sshbuf_reserve(m, rlen, &p)) != 0) return r; if (cipher_get_keycontext(&state->receive_context, p) != (int)rlen) return SSH_ERR_INTERNAL_ERROR; if ((r = ssh_packet_get_compress_state(m, ssh)) != 0 || (r = sshbuf_put_stringb(m, state->input)) != 0 || (r = sshbuf_put_stringb(m, state->output)) != 0) return r; if (compat20) { if ((r = sshbuf_put_u64(m, get_sent_bytes())) != 0 || (r = sshbuf_put_u64(m, get_recv_bytes())) != 0) return r; } return 0; } /* restore key exchange results from blob for packet state de-serialization */ static int newkeys_from_blob(struct sshbuf *m, struct ssh *ssh, int mode) { struct sshbuf *b = NULL; struct sshcomp *comp; struct sshenc *enc; struct sshmac *mac; struct newkeys *newkey = NULL; size_t keylen, ivlen, maclen; int r; if ((newkey = calloc(1, sizeof(*newkey))) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = sshbuf_froms(m, &b)) != 0) goto out; #ifdef DEBUG_PK sshbuf_dump(b, stderr); #endif enc = &newkey->enc; mac = &newkey->mac; comp = &newkey->comp; if ((r = sshbuf_get_cstring(b, &enc->name, NULL)) != 0 || (r = sshbuf_get(b, &enc->cipher, sizeof(enc->cipher))) != 0 || (r = sshbuf_get_u32(b, (u_int *)&enc->enabled)) != 0 || (r = sshbuf_get_u32(b, &enc->block_size)) != 0 || (r = sshbuf_get_string(b, &enc->key, &keylen)) != 0 || (r = sshbuf_get_string(b, &enc->iv, &ivlen)) != 0) goto out; if (cipher_authlen(enc->cipher) == 0) { if ((r = sshbuf_get_cstring(b, &mac->name, NULL)) != 0) goto out; if ((r = mac_setup(mac, mac->name)) != 0) goto out; if ((r = sshbuf_get_u32(b, (u_int *)&mac->enabled)) != 0 || (r = sshbuf_get_string(b, &mac->key, &maclen)) != 0) goto out; if (maclen > mac->key_len) { r = SSH_ERR_INVALID_FORMAT; goto out; } mac->key_len = maclen; } if ((r = sshbuf_get_u32(b, &comp->type)) != 0 || (r = sshbuf_get_u32(b, (u_int *)&comp->enabled)) != 0 || (r = sshbuf_get_cstring(b, &comp->name, NULL)) != 0) goto out; if (enc->name == NULL || cipher_by_name(enc->name) != enc->cipher) { r = SSH_ERR_INVALID_FORMAT; goto out; } if (sshbuf_len(b) != 0) { r = SSH_ERR_INVALID_FORMAT; goto out; } enc->key_len = keylen; enc->iv_len = ivlen; ssh->kex->newkeys[mode] = newkey; newkey = NULL; r = 0; out: if (newkey != NULL) free(newkey); if (b != NULL) sshbuf_free(b); return r; } /* restore kex from blob for packet state de-serialization */ static int kex_from_blob(struct sshbuf *m, struct kex **kexp) { struct kex *kex; int r; if ((kex = calloc(1, sizeof(struct kex))) == NULL || (kex->my = sshbuf_new()) == NULL || (kex->peer = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = sshbuf_get_string(m, &kex->session_id, &kex->session_id_len)) != 0 || (r = sshbuf_get_u32(m, &kex->we_need)) != 0 || (r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_type)) != 0 || (r = sshbuf_get_u32(m, &kex->kex_type)) != 0 || (r = sshbuf_get_stringb(m, kex->my)) != 0 || (r = sshbuf_get_stringb(m, kex->peer)) != 0 || (r = sshbuf_get_u32(m, &kex->flags)) != 0 || (r = sshbuf_get_cstring(m, &kex->client_version_string, NULL)) != 0 || (r = sshbuf_get_cstring(m, &kex->server_version_string, NULL)) != 0) goto out; kex->server = 1; kex->done = 1; r = 0; out: if (r != 0 || kexp == NULL) { if (kex != NULL) { if (kex->my != NULL) sshbuf_free(kex->my); if (kex->peer != NULL) sshbuf_free(kex->peer); free(kex); } if (kexp != NULL) *kexp = NULL; } else { *kexp = kex; } return r; } /* * Restore packet state from content of blob 'm' (de-serialization). * Note that 'm' will be partially consumed on parsing or any other errors. */ int ssh_packet_set_state(struct ssh *ssh, struct sshbuf *m) { struct session_state *state = ssh->state; const u_char *ssh1key, *ivin, *ivout, *keyin, *keyout, *input, *output; size_t ssh1keylen, rlen, slen, ilen, olen; int r; u_int ssh1cipher = 0; u_int64_t sent_bytes = 0, recv_bytes = 0; if (!compat20) { if ((r = sshbuf_get_u32(m, &state->remote_protocol_flags)) != 0 || (r = sshbuf_get_u32(m, &ssh1cipher)) != 0 || (r = sshbuf_get_string_direct(m, &ssh1key, &ssh1keylen)) != 0 || (r = sshbuf_get_string_direct(m, &ivout, &slen)) != 0 || (r = sshbuf_get_string_direct(m, &ivin, &rlen)) != 0) return r; if (ssh1cipher > INT_MAX) return SSH_ERR_KEY_UNKNOWN_CIPHER; ssh_packet_set_encryption_key(ssh, ssh1key, ssh1keylen, (int)ssh1cipher); if (cipher_get_keyiv_len(&state->send_context) != (int)slen || cipher_get_keyiv_len(&state->receive_context) != (int)rlen) return SSH_ERR_INVALID_FORMAT; if ((r = cipher_set_keyiv(&state->send_context, ivout)) != 0 || (r = cipher_set_keyiv(&state->receive_context, ivin)) != 0) return r; } else { if ((r = kex_from_blob(m, &ssh->kex)) != 0 || (r = newkeys_from_blob(m, ssh, MODE_OUT)) != 0 || (r = newkeys_from_blob(m, ssh, MODE_IN)) != 0 || (r = sshbuf_get_u32(m, &state->rekey_limit)) != 0 || (r = sshbuf_get_u32(m, &state->rekey_interval)) != 0 || (r = sshbuf_get_u32(m, &state->p_send.seqnr)) != 0 || (r = sshbuf_get_u64(m, &state->p_send.blocks)) != 0 || (r = sshbuf_get_u32(m, &state->p_send.packets)) != 0 || (r = sshbuf_get_u64(m, &state->p_send.bytes)) != 0 || (r = sshbuf_get_u32(m, &state->p_read.seqnr)) != 0 || (r = sshbuf_get_u64(m, &state->p_read.blocks)) != 0 || (r = sshbuf_get_u32(m, &state->p_read.packets)) != 0 || (r = sshbuf_get_u64(m, &state->p_read.bytes)) != 0) return r; /* * We set the time here so that in post-auth privsep slave we * count from the completion of the authentication. */ state->rekey_time = monotime(); /* XXX ssh_set_newkeys overrides p_read.packets? XXX */ if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0 || (r = ssh_set_newkeys(ssh, MODE_OUT)) != 0) return r; } if ((r = sshbuf_get_string_direct(m, &keyout, &slen)) != 0 || (r = sshbuf_get_string_direct(m, &keyin, &rlen)) != 0) return r; if (cipher_get_keycontext(&state->send_context, NULL) != (int)slen || cipher_get_keycontext(&state->receive_context, NULL) != (int)rlen) return SSH_ERR_INVALID_FORMAT; cipher_set_keycontext(&state->send_context, keyout); cipher_set_keycontext(&state->receive_context, keyin); if ((r = ssh_packet_set_compress_state(ssh, m)) != 0 || (r = ssh_packet_set_postauth(ssh)) != 0) return r; sshbuf_reset(state->input); sshbuf_reset(state->output); if ((r = sshbuf_get_string_direct(m, &input, &ilen)) != 0 || (r = sshbuf_get_string_direct(m, &output, &olen)) != 0 || (r = sshbuf_put(state->input, input, ilen)) != 0 || (r = sshbuf_put(state->output, output, olen)) != 0) return r; if (compat20) { if ((r = sshbuf_get_u64(m, &sent_bytes)) != 0 || (r = sshbuf_get_u64(m, &recv_bytes)) != 0) return r; roam_set_bytes(sent_bytes, recv_bytes); } if (sshbuf_len(m)) return SSH_ERR_INVALID_FORMAT; debug3("%s: done", __func__); return 0; } /* NEW API */ /* put data to the outgoing packet */ int sshpkt_put(struct ssh *ssh, const void *v, size_t len) { return sshbuf_put(ssh->state->outgoing_packet, v, len); } int sshpkt_putb(struct ssh *ssh, const struct sshbuf *b) { return sshbuf_putb(ssh->state->outgoing_packet, b); } int sshpkt_put_u8(struct ssh *ssh, u_char val) { return sshbuf_put_u8(ssh->state->outgoing_packet, val); } int sshpkt_put_u32(struct ssh *ssh, u_int32_t val) { return sshbuf_put_u32(ssh->state->outgoing_packet, val); } int sshpkt_put_u64(struct ssh *ssh, u_int64_t val) { return sshbuf_put_u64(ssh->state->outgoing_packet, val); } int sshpkt_put_string(struct ssh *ssh, const void *v, size_t len) { return sshbuf_put_string(ssh->state->outgoing_packet, v, len); } int sshpkt_put_cstring(struct ssh *ssh, const void *v) { return sshbuf_put_cstring(ssh->state->outgoing_packet, v); } int sshpkt_put_stringb(struct ssh *ssh, const struct sshbuf *v) { return sshbuf_put_stringb(ssh->state->outgoing_packet, v); } #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC int sshpkt_put_ec(struct ssh *ssh, const EC_POINT *v, const EC_GROUP *g) { return sshbuf_put_ec(ssh->state->outgoing_packet, v, g); } #endif /* OPENSSL_HAS_ECC */ #ifdef WITH_SSH1 int sshpkt_put_bignum1(struct ssh *ssh, const BIGNUM *v) { return sshbuf_put_bignum1(ssh->state->outgoing_packet, v); } #endif /* WITH_SSH1 */ int sshpkt_put_bignum2(struct ssh *ssh, const BIGNUM *v) { return sshbuf_put_bignum2(ssh->state->outgoing_packet, v); } #endif /* WITH_OPENSSL */ /* fetch data from the incoming packet */ int sshpkt_get(struct ssh *ssh, void *valp, size_t len) { return sshbuf_get(ssh->state->incoming_packet, valp, len); } int sshpkt_get_u8(struct ssh *ssh, u_char *valp) { return sshbuf_get_u8(ssh->state->incoming_packet, valp); } int sshpkt_get_u32(struct ssh *ssh, u_int32_t *valp) { return sshbuf_get_u32(ssh->state->incoming_packet, valp); } int sshpkt_get_u64(struct ssh *ssh, u_int64_t *valp) { return sshbuf_get_u64(ssh->state->incoming_packet, valp); } int sshpkt_get_string(struct ssh *ssh, u_char **valp, size_t *lenp) { return sshbuf_get_string(ssh->state->incoming_packet, valp, lenp); } int sshpkt_get_string_direct(struct ssh *ssh, const u_char **valp, size_t *lenp) { return sshbuf_get_string_direct(ssh->state->incoming_packet, valp, lenp); } int sshpkt_get_cstring(struct ssh *ssh, char **valp, size_t *lenp) { return sshbuf_get_cstring(ssh->state->incoming_packet, valp, lenp); } #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC int sshpkt_get_ec(struct ssh *ssh, EC_POINT *v, const EC_GROUP *g) { return sshbuf_get_ec(ssh->state->incoming_packet, v, g); } #endif /* OPENSSL_HAS_ECC */ #ifdef WITH_SSH1 int sshpkt_get_bignum1(struct ssh *ssh, BIGNUM *v) { return sshbuf_get_bignum1(ssh->state->incoming_packet, v); } #endif /* WITH_SSH1 */ int sshpkt_get_bignum2(struct ssh *ssh, BIGNUM *v) { return sshbuf_get_bignum2(ssh->state->incoming_packet, v); } #endif /* WITH_OPENSSL */ int sshpkt_get_end(struct ssh *ssh) { if (sshbuf_len(ssh->state->incoming_packet) > 0) return SSH_ERR_UNEXPECTED_TRAILING_DATA; return 0; } const u_char * sshpkt_ptr(struct ssh *ssh, size_t *lenp) { if (lenp != NULL) *lenp = sshbuf_len(ssh->state->incoming_packet); return sshbuf_ptr(ssh->state->incoming_packet); } /* start a new packet */ int sshpkt_start(struct ssh *ssh, u_char type) { u_char buf[9]; int len; DBG(debug("packet_start[%d]", type)); len = compat20 ? 6 : 9; memset(buf, 0, len - 1); buf[len - 1] = type; sshbuf_reset(ssh->state->outgoing_packet); return sshbuf_put(ssh->state->outgoing_packet, buf, len); } /* send it */ int sshpkt_send(struct ssh *ssh) { if (compat20) return ssh_packet_send2(ssh); else return ssh_packet_send1(ssh); } int sshpkt_disconnect(struct ssh *ssh, const char *fmt,...) { char buf[1024]; va_list args; int r; va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); if (compat20) { if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 || (r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 || (r = sshpkt_put_cstring(ssh, buf)) != 0 || (r = sshpkt_put_cstring(ssh, "")) != 0 || (r = sshpkt_send(ssh)) != 0) return r; } else { if ((r = sshpkt_start(ssh, SSH_MSG_DISCONNECT)) != 0 || (r = sshpkt_put_cstring(ssh, buf)) != 0 || (r = sshpkt_send(ssh)) != 0) return r; } return 0; } /* roundup current message to pad bytes */ int sshpkt_add_padding(struct ssh *ssh, u_char pad) { ssh->state->extra_pad = pad; return 0; } Index: head/crypto/openssh/sftp-server.c =================================================================== --- head/crypto/openssh/sftp-server.c (revision 294495) +++ head/crypto/openssh/sftp-server.c (revision 294496) @@ -1,1711 +1,1711 @@ -/* $OpenBSD: sftp-server.c,v 1.106 2015/04/24 01:36:01 deraadt Exp $ */ +/* $OpenBSD: sftp-server.c,v 1.107 2015/08/20 22:32:42 deraadt Exp $ */ /* * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "includes.h" #include /* MIN */ #include #include #ifdef HAVE_SYS_TIME_H # include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif #ifdef HAVE_SYS_STATVFS_H #include #endif #ifdef HAVE_SYS_PRCTL_H #include #endif #include #include #include #include #include #include #include #include #include #include #include "xmalloc.h" #include "sshbuf.h" #include "ssherr.h" #include "log.h" #include "misc.h" #include "match.h" #include "uidswap.h" #include "sftp.h" #include "sftp-common.h" /* Our verbosity */ static LogLevel log_level = SYSLOG_LEVEL_ERROR; /* Our client */ static struct passwd *pw = NULL; static char *client_addr = NULL; /* input and output queue */ struct sshbuf *iqueue; struct sshbuf *oqueue; /* Version of client */ static u_int version; /* SSH2_FXP_INIT received */ static int init_done; /* Disable writes */ static int readonly; /* Requests that are allowed/denied */ static char *request_whitelist, *request_blacklist; /* portable attributes, etc. */ typedef struct Stat Stat; struct Stat { char *name; char *long_name; Attrib attrib; }; /* Packet handlers */ static void process_open(u_int32_t id); static void process_close(u_int32_t id); static void process_read(u_int32_t id); static void process_write(u_int32_t id); static void process_stat(u_int32_t id); static void process_lstat(u_int32_t id); static void process_fstat(u_int32_t id); static void process_setstat(u_int32_t id); static void process_fsetstat(u_int32_t id); static void process_opendir(u_int32_t id); static void process_readdir(u_int32_t id); static void process_remove(u_int32_t id); static void process_mkdir(u_int32_t id); static void process_rmdir(u_int32_t id); static void process_realpath(u_int32_t id); static void process_rename(u_int32_t id); static void process_readlink(u_int32_t id); static void process_symlink(u_int32_t id); static void process_extended_posix_rename(u_int32_t id); static void process_extended_statvfs(u_int32_t id); static void process_extended_fstatvfs(u_int32_t id); static void process_extended_hardlink(u_int32_t id); static void process_extended_fsync(u_int32_t id); static void process_extended(u_int32_t id); struct sftp_handler { const char *name; /* user-visible name for fine-grained perms */ const char *ext_name; /* extended request name */ u_int type; /* packet type, for non extended packets */ void (*handler)(u_int32_t); int does_write; /* if nonzero, banned for readonly mode */ }; struct sftp_handler handlers[] = { /* NB. SSH2_FXP_OPEN does the readonly check in the handler itself */ { "open", NULL, SSH2_FXP_OPEN, process_open, 0 }, { "close", NULL, SSH2_FXP_CLOSE, process_close, 0 }, { "read", NULL, SSH2_FXP_READ, process_read, 0 }, { "write", NULL, SSH2_FXP_WRITE, process_write, 1 }, { "lstat", NULL, SSH2_FXP_LSTAT, process_lstat, 0 }, { "fstat", NULL, SSH2_FXP_FSTAT, process_fstat, 0 }, { "setstat", NULL, SSH2_FXP_SETSTAT, process_setstat, 1 }, { "fsetstat", NULL, SSH2_FXP_FSETSTAT, process_fsetstat, 1 }, { "opendir", NULL, SSH2_FXP_OPENDIR, process_opendir, 0 }, { "readdir", NULL, SSH2_FXP_READDIR, process_readdir, 0 }, { "remove", NULL, SSH2_FXP_REMOVE, process_remove, 1 }, { "mkdir", NULL, SSH2_FXP_MKDIR, process_mkdir, 1 }, { "rmdir", NULL, SSH2_FXP_RMDIR, process_rmdir, 1 }, { "realpath", NULL, SSH2_FXP_REALPATH, process_realpath, 0 }, { "stat", NULL, SSH2_FXP_STAT, process_stat, 0 }, { "rename", NULL, SSH2_FXP_RENAME, process_rename, 1 }, { "readlink", NULL, SSH2_FXP_READLINK, process_readlink, 0 }, { "symlink", NULL, SSH2_FXP_SYMLINK, process_symlink, 1 }, { NULL, NULL, 0, NULL, 0 } }; /* SSH2_FXP_EXTENDED submessages */ struct sftp_handler extended_handlers[] = { { "posix-rename", "posix-rename@openssh.com", 0, process_extended_posix_rename, 1 }, { "statvfs", "statvfs@openssh.com", 0, process_extended_statvfs, 0 }, { "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 }, { "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 }, { "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 }, { NULL, NULL, 0, NULL, 0 } }; static int request_permitted(struct sftp_handler *h) { char *result; if (readonly && h->does_write) { verbose("Refusing %s request in read-only mode", h->name); return 0; } if (request_blacklist != NULL && ((result = match_list(h->name, request_blacklist, NULL))) != NULL) { free(result); verbose("Refusing blacklisted %s request", h->name); return 0; } if (request_whitelist != NULL && ((result = match_list(h->name, request_whitelist, NULL))) != NULL) { free(result); debug2("Permitting whitelisted %s request", h->name); return 1; } if (request_whitelist != NULL) { verbose("Refusing non-whitelisted %s request", h->name); return 0; } return 1; } static int errno_to_portable(int unixerrno) { int ret = 0; switch (unixerrno) { case 0: ret = SSH2_FX_OK; break; case ENOENT: case ENOTDIR: case EBADF: case ELOOP: ret = SSH2_FX_NO_SUCH_FILE; break; case EPERM: case EACCES: case EFAULT: ret = SSH2_FX_PERMISSION_DENIED; break; case ENAMETOOLONG: case EINVAL: ret = SSH2_FX_BAD_MESSAGE; break; case ENOSYS: ret = SSH2_FX_OP_UNSUPPORTED; break; default: ret = SSH2_FX_FAILURE; break; } return ret; } static int flags_from_portable(int pflags) { int flags = 0; if ((pflags & SSH2_FXF_READ) && (pflags & SSH2_FXF_WRITE)) { flags = O_RDWR; } else if (pflags & SSH2_FXF_READ) { flags = O_RDONLY; } else if (pflags & SSH2_FXF_WRITE) { flags = O_WRONLY; } if (pflags & SSH2_FXF_APPEND) flags |= O_APPEND; if (pflags & SSH2_FXF_CREAT) flags |= O_CREAT; if (pflags & SSH2_FXF_TRUNC) flags |= O_TRUNC; if (pflags & SSH2_FXF_EXCL) flags |= O_EXCL; return flags; } static const char * string_from_portable(int pflags) { static char ret[128]; *ret = '\0'; #define PAPPEND(str) { \ if (*ret != '\0') \ strlcat(ret, ",", sizeof(ret)); \ strlcat(ret, str, sizeof(ret)); \ } if (pflags & SSH2_FXF_READ) PAPPEND("READ") if (pflags & SSH2_FXF_WRITE) PAPPEND("WRITE") if (pflags & SSH2_FXF_APPEND) PAPPEND("APPEND") if (pflags & SSH2_FXF_CREAT) PAPPEND("CREATE") if (pflags & SSH2_FXF_TRUNC) PAPPEND("TRUNCATE") if (pflags & SSH2_FXF_EXCL) PAPPEND("EXCL") return ret; } /* handle handles */ typedef struct Handle Handle; struct Handle { int use; DIR *dirp; int fd; int flags; char *name; u_int64_t bytes_read, bytes_write; int next_unused; }; enum { HANDLE_UNUSED, HANDLE_DIR, HANDLE_FILE }; Handle *handles = NULL; u_int num_handles = 0; int first_unused_handle = -1; static void handle_unused(int i) { handles[i].use = HANDLE_UNUSED; handles[i].next_unused = first_unused_handle; first_unused_handle = i; } static int handle_new(int use, const char *name, int fd, int flags, DIR *dirp) { int i; if (first_unused_handle == -1) { if (num_handles + 1 <= num_handles) return -1; num_handles++; handles = xreallocarray(handles, num_handles, sizeof(Handle)); handle_unused(num_handles - 1); } i = first_unused_handle; first_unused_handle = handles[i].next_unused; handles[i].use = use; handles[i].dirp = dirp; handles[i].fd = fd; handles[i].flags = flags; handles[i].name = xstrdup(name); handles[i].bytes_read = handles[i].bytes_write = 0; return i; } static int handle_is_ok(int i, int type) { return i >= 0 && (u_int)i < num_handles && handles[i].use == type; } static int handle_to_string(int handle, u_char **stringp, int *hlenp) { if (stringp == NULL || hlenp == NULL) return -1; *stringp = xmalloc(sizeof(int32_t)); put_u32(*stringp, handle); *hlenp = sizeof(int32_t); return 0; } static int handle_from_string(const u_char *handle, u_int hlen) { int val; if (hlen != sizeof(int32_t)) return -1; val = get_u32(handle); if (handle_is_ok(val, HANDLE_FILE) || handle_is_ok(val, HANDLE_DIR)) return val; return -1; } static char * handle_to_name(int handle) { if (handle_is_ok(handle, HANDLE_DIR)|| handle_is_ok(handle, HANDLE_FILE)) return handles[handle].name; return NULL; } static DIR * handle_to_dir(int handle) { if (handle_is_ok(handle, HANDLE_DIR)) return handles[handle].dirp; return NULL; } static int handle_to_fd(int handle) { if (handle_is_ok(handle, HANDLE_FILE)) return handles[handle].fd; return -1; } static int handle_to_flags(int handle) { if (handle_is_ok(handle, HANDLE_FILE)) return handles[handle].flags; return 0; } static void handle_update_read(int handle, ssize_t bytes) { if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0) handles[handle].bytes_read += bytes; } static void handle_update_write(int handle, ssize_t bytes) { if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0) handles[handle].bytes_write += bytes; } static u_int64_t handle_bytes_read(int handle) { if (handle_is_ok(handle, HANDLE_FILE)) return (handles[handle].bytes_read); return 0; } static u_int64_t handle_bytes_write(int handle) { if (handle_is_ok(handle, HANDLE_FILE)) return (handles[handle].bytes_write); return 0; } static int handle_close(int handle) { int ret = -1; if (handle_is_ok(handle, HANDLE_FILE)) { ret = close(handles[handle].fd); free(handles[handle].name); handle_unused(handle); } else if (handle_is_ok(handle, HANDLE_DIR)) { ret = closedir(handles[handle].dirp); free(handles[handle].name); handle_unused(handle); } else { errno = ENOENT; } return ret; } static void handle_log_close(int handle, char *emsg) { if (handle_is_ok(handle, HANDLE_FILE)) { logit("%s%sclose \"%s\" bytes read %llu written %llu", emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ", handle_to_name(handle), (unsigned long long)handle_bytes_read(handle), (unsigned long long)handle_bytes_write(handle)); } else { logit("%s%sclosedir \"%s\"", emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ", handle_to_name(handle)); } } static void handle_log_exit(void) { u_int i; for (i = 0; i < num_handles; i++) if (handles[i].use != HANDLE_UNUSED) handle_log_close(i, "forced"); } static int get_handle(struct sshbuf *queue, int *hp) { u_char *handle; int r; size_t hlen; *hp = -1; if ((r = sshbuf_get_string(queue, &handle, &hlen)) != 0) return r; if (hlen < 256) *hp = handle_from_string(handle, hlen); free(handle); return 0; } /* send replies */ static void send_msg(struct sshbuf *m) { int r; if ((r = sshbuf_put_stringb(oqueue, m)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); sshbuf_reset(m); } static const char * status_to_message(u_int32_t status) { const char *status_messages[] = { "Success", /* SSH_FX_OK */ "End of file", /* SSH_FX_EOF */ "No such file", /* SSH_FX_NO_SUCH_FILE */ "Permission denied", /* SSH_FX_PERMISSION_DENIED */ "Failure", /* SSH_FX_FAILURE */ "Bad message", /* SSH_FX_BAD_MESSAGE */ "No connection", /* SSH_FX_NO_CONNECTION */ "Connection lost", /* SSH_FX_CONNECTION_LOST */ "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */ "Unknown error" /* Others */ }; return (status_messages[MIN(status,SSH2_FX_MAX)]); } static void send_status(u_int32_t id, u_int32_t status) { struct sshbuf *msg; int r; debug3("request %u: sent status %u", id, status); if (log_level > SYSLOG_LEVEL_VERBOSE || (status != SSH2_FX_OK && status != SSH2_FX_EOF)) logit("sent status %s", status_to_message(status)); if ((msg = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if ((r = sshbuf_put_u8(msg, SSH2_FXP_STATUS)) != 0 || (r = sshbuf_put_u32(msg, id)) != 0 || (r = sshbuf_put_u32(msg, status)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (version >= 3) { if ((r = sshbuf_put_cstring(msg, status_to_message(status))) != 0 || (r = sshbuf_put_cstring(msg, "")) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); } send_msg(msg); sshbuf_free(msg); } static void send_data_or_handle(char type, u_int32_t id, const u_char *data, int dlen) { struct sshbuf *msg; int r; if ((msg = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if ((r = sshbuf_put_u8(msg, type)) != 0 || (r = sshbuf_put_u32(msg, id)) != 0 || (r = sshbuf_put_string(msg, data, dlen)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); send_msg(msg); sshbuf_free(msg); } static void send_data(u_int32_t id, const u_char *data, int dlen) { debug("request %u: sent data len %d", id, dlen); send_data_or_handle(SSH2_FXP_DATA, id, data, dlen); } static void send_handle(u_int32_t id, int handle) { u_char *string; int hlen; handle_to_string(handle, &string, &hlen); debug("request %u: sent handle handle %d", id, handle); send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen); free(string); } static void send_names(u_int32_t id, int count, const Stat *stats) { struct sshbuf *msg; int i, r; if ((msg = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if ((r = sshbuf_put_u8(msg, SSH2_FXP_NAME)) != 0 || (r = sshbuf_put_u32(msg, id)) != 0 || (r = sshbuf_put_u32(msg, count)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug("request %u: sent names count %d", id, count); for (i = 0; i < count; i++) { if ((r = sshbuf_put_cstring(msg, stats[i].name)) != 0 || (r = sshbuf_put_cstring(msg, stats[i].long_name)) != 0 || (r = encode_attrib(msg, &stats[i].attrib)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); } send_msg(msg); sshbuf_free(msg); } static void send_attrib(u_int32_t id, const Attrib *a) { struct sshbuf *msg; int r; debug("request %u: sent attrib have 0x%x", id, a->flags); if ((msg = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if ((r = sshbuf_put_u8(msg, SSH2_FXP_ATTRS)) != 0 || (r = sshbuf_put_u32(msg, id)) != 0 || (r = encode_attrib(msg, a)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); send_msg(msg); sshbuf_free(msg); } static void send_statvfs(u_int32_t id, struct statvfs *st) { struct sshbuf *msg; u_int64_t flag; int r; flag = (st->f_flag & ST_RDONLY) ? SSH2_FXE_STATVFS_ST_RDONLY : 0; flag |= (st->f_flag & ST_NOSUID) ? SSH2_FXE_STATVFS_ST_NOSUID : 0; if ((msg = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED_REPLY)) != 0 || (r = sshbuf_put_u32(msg, id)) != 0 || (r = sshbuf_put_u64(msg, st->f_bsize)) != 0 || (r = sshbuf_put_u64(msg, st->f_frsize)) != 0 || (r = sshbuf_put_u64(msg, st->f_blocks)) != 0 || (r = sshbuf_put_u64(msg, st->f_bfree)) != 0 || (r = sshbuf_put_u64(msg, st->f_bavail)) != 0 || (r = sshbuf_put_u64(msg, st->f_files)) != 0 || (r = sshbuf_put_u64(msg, st->f_ffree)) != 0 || (r = sshbuf_put_u64(msg, st->f_favail)) != 0 || (r = sshbuf_put_u64(msg, FSID_TO_ULONG(st->f_fsid))) != 0 || (r = sshbuf_put_u64(msg, flag)) != 0 || (r = sshbuf_put_u64(msg, st->f_namemax)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); send_msg(msg); sshbuf_free(msg); } /* parse incoming */ static void process_init(void) { struct sshbuf *msg; int r; if ((r = sshbuf_get_u32(iqueue, &version)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); verbose("received client version %u", version); if ((msg = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if ((r = sshbuf_put_u8(msg, SSH2_FXP_VERSION)) != 0 || (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0 || /* POSIX rename extension */ (r = sshbuf_put_cstring(msg, "posix-rename@openssh.com")) != 0 || (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */ /* statvfs extension */ (r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 || (r = sshbuf_put_cstring(msg, "2")) != 0 || /* version */ /* fstatvfs extension */ (r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 || (r = sshbuf_put_cstring(msg, "2")) != 0 || /* version */ /* hardlink extension */ (r = sshbuf_put_cstring(msg, "hardlink@openssh.com")) != 0 || (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */ /* fsync extension */ (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 || (r = sshbuf_put_cstring(msg, "1")) != 0) /* version */ fatal("%s: buffer error: %s", __func__, ssh_err(r)); send_msg(msg); sshbuf_free(msg); } static void process_open(u_int32_t id) { u_int32_t pflags; Attrib a; char *name; int r, handle, fd, flags, mode, status = SSH2_FX_FAILURE; if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || (r = sshbuf_get_u32(iqueue, &pflags)) != 0 || /* portable flags */ (r = decode_attrib(iqueue, &a)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("request %u: open flags %d", id, pflags); flags = flags_from_portable(pflags); mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a.perm : 0666; logit("open \"%s\" flags %s mode 0%o", name, string_from_portable(pflags), mode); if (readonly && ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR)) { verbose("Refusing open request in read-only mode"); status = SSH2_FX_PERMISSION_DENIED; } else { fd = open(name, flags, mode); if (fd < 0) { status = errno_to_portable(errno); } else { handle = handle_new(HANDLE_FILE, name, fd, flags, NULL); if (handle < 0) { close(fd); } else { send_handle(id, handle); status = SSH2_FX_OK; } } } if (status != SSH2_FX_OK) send_status(id, status); free(name); } static void process_close(u_int32_t id) { int r, handle, ret, status = SSH2_FX_FAILURE; if ((r = get_handle(iqueue, &handle)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("request %u: close handle %u", id, handle); handle_log_close(handle, NULL); ret = handle_close(handle); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); } static void process_read(u_int32_t id) { u_char buf[64*1024]; u_int32_t len; int r, handle, fd, ret, status = SSH2_FX_FAILURE; u_int64_t off; if ((r = get_handle(iqueue, &handle)) != 0 || (r = sshbuf_get_u64(iqueue, &off)) != 0 || (r = sshbuf_get_u32(iqueue, &len)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug("request %u: read \"%s\" (handle %d) off %llu len %d", id, handle_to_name(handle), handle, (unsigned long long)off, len); if (len > sizeof buf) { len = sizeof buf; debug2("read change len %d", len); } fd = handle_to_fd(handle); if (fd >= 0) { if (lseek(fd, off, SEEK_SET) < 0) { error("process_read: seek failed"); status = errno_to_portable(errno); } else { ret = read(fd, buf, len); if (ret < 0) { status = errno_to_portable(errno); } else if (ret == 0) { status = SSH2_FX_EOF; } else { send_data(id, buf, ret); status = SSH2_FX_OK; handle_update_read(handle, ret); } } } if (status != SSH2_FX_OK) send_status(id, status); } static void process_write(u_int32_t id) { u_int64_t off; size_t len; int r, handle, fd, ret, status; u_char *data; if ((r = get_handle(iqueue, &handle)) != 0 || (r = sshbuf_get_u64(iqueue, &off)) != 0 || (r = sshbuf_get_string(iqueue, &data, &len)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug("request %u: write \"%s\" (handle %d) off %llu len %zu", id, handle_to_name(handle), handle, (unsigned long long)off, len); fd = handle_to_fd(handle); if (fd < 0) status = SSH2_FX_FAILURE; else { if (!(handle_to_flags(handle) & O_APPEND) && lseek(fd, off, SEEK_SET) < 0) { status = errno_to_portable(errno); error("process_write: seek failed"); } else { /* XXX ATOMICIO ? */ ret = write(fd, data, len); if (ret < 0) { error("process_write: write failed"); status = errno_to_portable(errno); } else if ((size_t)ret == len) { status = SSH2_FX_OK; handle_update_write(handle, ret); } else { debug2("nothing at all written"); status = SSH2_FX_FAILURE; } } } send_status(id, status); free(data); } static void process_do_stat(u_int32_t id, int do_lstat) { Attrib a; struct stat st; char *name; int r, status = SSH2_FX_FAILURE; if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("request %u: %sstat", id, do_lstat ? "l" : ""); verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name); r = do_lstat ? lstat(name, &st) : stat(name, &st); if (r < 0) { status = errno_to_portable(errno); } else { stat_to_attrib(&st, &a); send_attrib(id, &a); status = SSH2_FX_OK; } if (status != SSH2_FX_OK) send_status(id, status); free(name); } static void process_stat(u_int32_t id) { process_do_stat(id, 0); } static void process_lstat(u_int32_t id) { process_do_stat(id, 1); } static void process_fstat(u_int32_t id) { Attrib a; struct stat st; int fd, r, handle, status = SSH2_FX_FAILURE; if ((r = get_handle(iqueue, &handle)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug("request %u: fstat \"%s\" (handle %u)", id, handle_to_name(handle), handle); fd = handle_to_fd(handle); if (fd >= 0) { r = fstat(fd, &st); if (r < 0) { status = errno_to_portable(errno); } else { stat_to_attrib(&st, &a); send_attrib(id, &a); status = SSH2_FX_OK; } } if (status != SSH2_FX_OK) send_status(id, status); } static struct timeval * attrib_to_tv(const Attrib *a) { static struct timeval tv[2]; tv[0].tv_sec = a->atime; tv[0].tv_usec = 0; tv[1].tv_sec = a->mtime; tv[1].tv_usec = 0; return tv; } static void process_setstat(u_int32_t id) { Attrib a; char *name; int r, status = SSH2_FX_OK; if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || (r = decode_attrib(iqueue, &a)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug("request %u: setstat name \"%s\"", id, name); if (a.flags & SSH2_FILEXFER_ATTR_SIZE) { logit("set \"%s\" size %llu", name, (unsigned long long)a.size); r = truncate(name, a.size); if (r == -1) status = errno_to_portable(errno); } if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { logit("set \"%s\" mode %04o", name, a.perm); r = chmod(name, a.perm & 07777); if (r == -1) status = errno_to_portable(errno); } if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) { char buf[64]; time_t t = a.mtime; strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S", localtime(&t)); logit("set \"%s\" modtime %s", name, buf); r = utimes(name, attrib_to_tv(&a)); if (r == -1) status = errno_to_portable(errno); } if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) { logit("set \"%s\" owner %lu group %lu", name, (u_long)a.uid, (u_long)a.gid); r = chown(name, a.uid, a.gid); if (r == -1) status = errno_to_portable(errno); } send_status(id, status); free(name); } static void process_fsetstat(u_int32_t id) { Attrib a; int handle, fd, r; int status = SSH2_FX_OK; if ((r = get_handle(iqueue, &handle)) != 0 || (r = decode_attrib(iqueue, &a)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug("request %u: fsetstat handle %d", id, handle); fd = handle_to_fd(handle); if (fd < 0) status = SSH2_FX_FAILURE; else { char *name = handle_to_name(handle); if (a.flags & SSH2_FILEXFER_ATTR_SIZE) { logit("set \"%s\" size %llu", name, (unsigned long long)a.size); r = ftruncate(fd, a.size); if (r == -1) status = errno_to_portable(errno); } if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { logit("set \"%s\" mode %04o", name, a.perm); #ifdef HAVE_FCHMOD r = fchmod(fd, a.perm & 07777); #else r = chmod(name, a.perm & 07777); #endif if (r == -1) status = errno_to_portable(errno); } if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) { char buf[64]; time_t t = a.mtime; strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S", localtime(&t)); logit("set \"%s\" modtime %s", name, buf); #ifdef HAVE_FUTIMES r = futimes(fd, attrib_to_tv(&a)); #else r = utimes(name, attrib_to_tv(&a)); #endif if (r == -1) status = errno_to_portable(errno); } if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) { logit("set \"%s\" owner %lu group %lu", name, (u_long)a.uid, (u_long)a.gid); #ifdef HAVE_FCHOWN r = fchown(fd, a.uid, a.gid); #else r = chown(name, a.uid, a.gid); #endif if (r == -1) status = errno_to_portable(errno); } } send_status(id, status); } static void process_opendir(u_int32_t id) { DIR *dirp = NULL; char *path; int r, handle, status = SSH2_FX_FAILURE; if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("request %u: opendir", id); logit("opendir \"%s\"", path); dirp = opendir(path); if (dirp == NULL) { status = errno_to_portable(errno); } else { handle = handle_new(HANDLE_DIR, path, 0, 0, dirp); if (handle < 0) { closedir(dirp); } else { send_handle(id, handle); status = SSH2_FX_OK; } } if (status != SSH2_FX_OK) send_status(id, status); free(path); } static void process_readdir(u_int32_t id) { DIR *dirp; struct dirent *dp; char *path; int r, handle; if ((r = get_handle(iqueue, &handle)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug("request %u: readdir \"%s\" (handle %d)", id, handle_to_name(handle), handle); dirp = handle_to_dir(handle); path = handle_to_name(handle); if (dirp == NULL || path == NULL) { send_status(id, SSH2_FX_FAILURE); } else { struct stat st; char pathname[PATH_MAX]; Stat *stats; int nstats = 10, count = 0, i; stats = xcalloc(nstats, sizeof(Stat)); while ((dp = readdir(dirp)) != NULL) { if (count >= nstats) { nstats *= 2; stats = xreallocarray(stats, nstats, sizeof(Stat)); } /* XXX OVERFLOW ? */ snprintf(pathname, sizeof pathname, "%s%s%s", path, strcmp(path, "/") ? "/" : "", dp->d_name); if (lstat(pathname, &st) < 0) continue; stat_to_attrib(&st, &(stats[count].attrib)); stats[count].name = xstrdup(dp->d_name); stats[count].long_name = ls_file(dp->d_name, &st, 0, 0); count++; /* send up to 100 entries in one message */ /* XXX check packet size instead */ if (count == 100) break; } if (count > 0) { send_names(id, count, stats); for (i = 0; i < count; i++) { free(stats[i].name); free(stats[i].long_name); } } else { send_status(id, SSH2_FX_EOF); } free(stats); } } static void process_remove(u_int32_t id) { char *name; int r, status = SSH2_FX_FAILURE; if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("request %u: remove", id); logit("remove name \"%s\"", name); r = unlink(name); status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); free(name); } static void process_mkdir(u_int32_t id) { Attrib a; char *name; int r, mode, status = SSH2_FX_FAILURE; if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || (r = decode_attrib(iqueue, &a)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a.perm & 07777 : 0777; debug3("request %u: mkdir", id); logit("mkdir name \"%s\" mode 0%o", name, mode); r = mkdir(name, mode); status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); free(name); } static void process_rmdir(u_int32_t id) { char *name; int r, status; if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("request %u: rmdir", id); logit("rmdir name \"%s\"", name); r = rmdir(name); status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); free(name); } static void process_realpath(u_int32_t id) { char resolvedname[PATH_MAX]; char *path; int r; if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (path[0] == '\0') { free(path); path = xstrdup("."); } debug3("request %u: realpath", id); verbose("realpath \"%s\"", path); if (realpath(path, resolvedname) == NULL) { send_status(id, errno_to_portable(errno)); } else { Stat s; attrib_clear(&s.attrib); s.name = s.long_name = resolvedname; send_names(id, 1, &s); } free(path); } static void process_rename(u_int32_t id) { char *oldpath, *newpath; int r, status; struct stat sb; if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 || (r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("request %u: rename", id); logit("rename old \"%s\" new \"%s\"", oldpath, newpath); status = SSH2_FX_FAILURE; if (lstat(oldpath, &sb) == -1) status = errno_to_portable(errno); else if (S_ISREG(sb.st_mode)) { /* Race-free rename of regular files */ if (link(oldpath, newpath) == -1) { if (errno == EOPNOTSUPP || errno == ENOSYS #ifdef EXDEV || errno == EXDEV #endif #ifdef LINK_OPNOTSUPP_ERRNO || errno == LINK_OPNOTSUPP_ERRNO #endif ) { struct stat st; /* * fs doesn't support links, so fall back to * stat+rename. This is racy. */ if (stat(newpath, &st) == -1) { if (rename(oldpath, newpath) == -1) status = errno_to_portable(errno); else status = SSH2_FX_OK; } } else { status = errno_to_portable(errno); } } else if (unlink(oldpath) == -1) { status = errno_to_portable(errno); /* clean spare link */ unlink(newpath); } else status = SSH2_FX_OK; } else if (stat(newpath, &sb) == -1) { if (rename(oldpath, newpath) == -1) status = errno_to_portable(errno); else status = SSH2_FX_OK; } send_status(id, status); free(oldpath); free(newpath); } static void process_readlink(u_int32_t id) { int r, len; char buf[PATH_MAX]; char *path; if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("request %u: readlink", id); verbose("readlink \"%s\"", path); if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1) send_status(id, errno_to_portable(errno)); else { Stat s; buf[len] = '\0'; attrib_clear(&s.attrib); s.name = s.long_name = buf; send_names(id, 1, &s); } free(path); } static void process_symlink(u_int32_t id) { char *oldpath, *newpath; int r, status; if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 || (r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("request %u: symlink", id); logit("symlink old \"%s\" new \"%s\"", oldpath, newpath); /* this will fail if 'newpath' exists */ r = symlink(oldpath, newpath); status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); free(oldpath); free(newpath); } static void process_extended_posix_rename(u_int32_t id) { char *oldpath, *newpath; int r, status; if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 || (r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("request %u: posix-rename", id); logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath); r = rename(oldpath, newpath); status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); free(oldpath); free(newpath); } static void process_extended_statvfs(u_int32_t id) { char *path; struct statvfs st; int r; if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("request %u: statvfs", id); logit("statvfs \"%s\"", path); if (statvfs(path, &st) != 0) send_status(id, errno_to_portable(errno)); else send_statvfs(id, &st); free(path); } static void process_extended_fstatvfs(u_int32_t id) { int r, handle, fd; struct statvfs st; if ((r = get_handle(iqueue, &handle)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug("request %u: fstatvfs \"%s\" (handle %u)", id, handle_to_name(handle), handle); if ((fd = handle_to_fd(handle)) < 0) { send_status(id, SSH2_FX_FAILURE); return; } if (fstatvfs(fd, &st) != 0) send_status(id, errno_to_portable(errno)); else send_statvfs(id, &st); } static void process_extended_hardlink(u_int32_t id) { char *oldpath, *newpath; int r, status; if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 || (r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("request %u: hardlink", id); logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath); r = link(oldpath, newpath); status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); free(oldpath); free(newpath); } static void process_extended_fsync(u_int32_t id) { int handle, fd, r, status = SSH2_FX_OP_UNSUPPORTED; if ((r = get_handle(iqueue, &handle)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("request %u: fsync (handle %u)", id, handle); verbose("fsync \"%s\"", handle_to_name(handle)); if ((fd = handle_to_fd(handle)) < 0) status = SSH2_FX_NO_SUCH_FILE; else if (handle_is_ok(handle, HANDLE_FILE)) { r = fsync(fd); status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK; } send_status(id, status); } static void process_extended(u_int32_t id) { char *request; int i, r; if ((r = sshbuf_get_cstring(iqueue, &request, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); for (i = 0; extended_handlers[i].handler != NULL; i++) { if (strcmp(request, extended_handlers[i].ext_name) == 0) { if (!request_permitted(&extended_handlers[i])) send_status(id, SSH2_FX_PERMISSION_DENIED); else extended_handlers[i].handler(id); break; } } if (extended_handlers[i].handler == NULL) { error("Unknown extended request \"%.100s\"", request); send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */ } free(request); } /* stolen from ssh-agent */ static void process(void) { u_int msg_len; u_int buf_len; u_int consumed; u_char type; const u_char *cp; int i, r; u_int32_t id; buf_len = sshbuf_len(iqueue); if (buf_len < 5) return; /* Incomplete message. */ cp = sshbuf_ptr(iqueue); msg_len = get_u32(cp); if (msg_len > SFTP_MAX_MSG_LENGTH) { error("bad message from %s local user %s", client_addr, pw->pw_name); sftp_server_cleanup_exit(11); } if (buf_len < msg_len + 4) return; if ((r = sshbuf_consume(iqueue, 4)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); buf_len -= 4; if ((r = sshbuf_get_u8(iqueue, &type)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); switch (type) { case SSH2_FXP_INIT: process_init(); init_done = 1; break; case SSH2_FXP_EXTENDED: if (!init_done) fatal("Received extended request before init"); if ((r = sshbuf_get_u32(iqueue, &id)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); process_extended(id); break; default: if (!init_done) fatal("Received %u request before init", type); if ((r = sshbuf_get_u32(iqueue, &id)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); for (i = 0; handlers[i].handler != NULL; i++) { if (type == handlers[i].type) { if (!request_permitted(&handlers[i])) { send_status(id, SSH2_FX_PERMISSION_DENIED); } else { handlers[i].handler(id); } break; } } if (handlers[i].handler == NULL) error("Unknown message %u", type); } /* discard the remaining bytes from the current packet */ if (buf_len < sshbuf_len(iqueue)) { error("iqueue grew unexpectedly"); sftp_server_cleanup_exit(255); } consumed = buf_len - sshbuf_len(iqueue); if (msg_len < consumed) { error("msg_len %u < consumed %u", msg_len, consumed); sftp_server_cleanup_exit(255); } if (msg_len > consumed && (r = sshbuf_consume(iqueue, msg_len - consumed)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); } /* Cleanup handler that logs active handles upon normal exit */ void sftp_server_cleanup_exit(int i) { if (pw != NULL && client_addr != NULL) { handle_log_exit(); logit("session closed for local user %s from [%s]", pw->pw_name, client_addr); } _exit(i); } static void sftp_server_usage(void) { extern char *__progname; fprintf(stderr, "usage: %s [-ehR] [-d start_directory] [-f log_facility] " "[-l log_level]\n\t[-P blacklisted_requests] " "[-p whitelisted_requests] [-u umask]\n" " %s -Q protocol_feature\n", __progname, __progname); exit(1); } int sftp_server_main(int argc, char **argv, struct passwd *user_pw) { fd_set *rset, *wset; int i, r, in, out, max, ch, skipargs = 0, log_stderr = 0; ssize_t len, olen, set_size; SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; char *cp, *homedir = NULL, buf[4*4096]; long mask; extern char *optarg; extern char *__progname; __progname = ssh_get_progname(argv[0]); log_init(__progname, log_level, log_facility, log_stderr); pw = pwcopy(user_pw); while (!skipargs && (ch = getopt(argc, argv, "d:f:l:P:p:Q:u:cehR")) != -1) { switch (ch) { case 'Q': if (strcasecmp(optarg, "requests") != 0) { fprintf(stderr, "Invalid query type\n"); exit(1); } for (i = 0; handlers[i].handler != NULL; i++) printf("%s\n", handlers[i].name); for (i = 0; extended_handlers[i].handler != NULL; i++) printf("%s\n", extended_handlers[i].name); exit(0); break; case 'R': readonly = 1; break; case 'c': /* * Ignore all arguments if we are invoked as a * shell using "sftp-server -c command" */ skipargs = 1; break; case 'e': log_stderr = 1; break; case 'l': log_level = log_level_number(optarg); if (log_level == SYSLOG_LEVEL_NOT_SET) error("Invalid log level \"%s\"", optarg); break; case 'f': log_facility = log_facility_number(optarg); if (log_facility == SYSLOG_FACILITY_NOT_SET) error("Invalid log facility \"%s\"", optarg); break; case 'd': cp = tilde_expand_filename(optarg, user_pw->pw_uid); homedir = percent_expand(cp, "d", user_pw->pw_dir, "u", user_pw->pw_name, (char *)NULL); free(cp); break; case 'p': if (request_whitelist != NULL) fatal("Permitted requests already set"); request_whitelist = xstrdup(optarg); break; case 'P': if (request_blacklist != NULL) fatal("Refused requests already set"); request_blacklist = xstrdup(optarg); break; case 'u': errno = 0; mask = strtol(optarg, &cp, 8); if (mask < 0 || mask > 0777 || *cp != '\0' || cp == optarg || (mask == 0 && errno != 0)) fatal("Invalid umask \"%s\"", optarg); (void)umask((mode_t)mask); break; case 'h': default: sftp_server_usage(); } } log_init(__progname, log_level, log_facility, log_stderr); #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) /* * On Linux, we should try to avoid making /proc/self/{mem,maps} * available to the user so that sftp access doesn't automatically * imply arbitrary code execution access that will break * restricted configurations. */ if (prctl(PR_SET_DUMPABLE, 0) != 0) fatal("unable to make the process undumpable"); #endif /* defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) */ if ((cp = getenv("SSH_CONNECTION")) != NULL) { client_addr = xstrdup(cp); if ((cp = strchr(client_addr, ' ')) == NULL) { error("Malformed SSH_CONNECTION variable: \"%s\"", getenv("SSH_CONNECTION")); sftp_server_cleanup_exit(255); } *cp = '\0'; } else client_addr = xstrdup("UNKNOWN"); logit("session opened for local user %s from [%s]", pw->pw_name, client_addr); in = STDIN_FILENO; out = STDOUT_FILENO; #ifdef HAVE_CYGWIN setmode(in, O_BINARY); setmode(out, O_BINARY); #endif max = 0; if (in > max) max = in; if (out > max) max = out; if ((iqueue = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if ((oqueue = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask); - rset = (fd_set *)xmalloc(set_size); - wset = (fd_set *)xmalloc(set_size); + rset = xmalloc(set_size); + wset = xmalloc(set_size); if (homedir != NULL) { if (chdir(homedir) != 0) { error("chdir to \"%s\" failed: %s", homedir, strerror(errno)); } } for (;;) { memset(rset, 0, set_size); memset(wset, 0, set_size); /* * Ensure that we can read a full buffer and handle * the worst-case length packet it can generate, * otherwise apply backpressure by stopping reads. */ if ((r = sshbuf_check_reserve(iqueue, sizeof(buf))) == 0 && (r = sshbuf_check_reserve(oqueue, SFTP_MAX_MSG_LENGTH)) == 0) FD_SET(in, rset); else if (r != SSH_ERR_NO_BUFFER_SPACE) fatal("%s: sshbuf_check_reserve failed: %s", __func__, ssh_err(r)); olen = sshbuf_len(oqueue); if (olen > 0) FD_SET(out, wset); if (select(max+1, rset, wset, NULL, NULL) < 0) { if (errno == EINTR) continue; error("select: %s", strerror(errno)); sftp_server_cleanup_exit(2); } /* copy stdin to iqueue */ if (FD_ISSET(in, rset)) { len = read(in, buf, sizeof buf); if (len == 0) { debug("read eof"); sftp_server_cleanup_exit(0); } else if (len < 0) { error("read: %s", strerror(errno)); sftp_server_cleanup_exit(1); } else if ((r = sshbuf_put(iqueue, buf, len)) != 0) { fatal("%s: buffer error: %s", __func__, ssh_err(r)); } } /* send oqueue to stdout */ if (FD_ISSET(out, wset)) { len = write(out, sshbuf_ptr(oqueue), olen); if (len < 0) { error("write: %s", strerror(errno)); sftp_server_cleanup_exit(1); } else if ((r = sshbuf_consume(oqueue, len)) != 0) { fatal("%s: buffer error: %s", __func__, ssh_err(r)); } } /* * Process requests from client if we can fit the results * into the output buffer, otherwise stop processing input * and let the output queue drain. */ r = sshbuf_check_reserve(oqueue, SFTP_MAX_MSG_LENGTH); if (r == 0) process(); else if (r != SSH_ERR_NO_BUFFER_SPACE) fatal("%s: sshbuf_check_reserve: %s", __func__, ssh_err(r)); } } Index: head/crypto/openssh/sftp.c =================================================================== --- head/crypto/openssh/sftp.c (revision 294495) +++ head/crypto/openssh/sftp.c (revision 294496) @@ -1,2450 +1,2450 @@ -/* $OpenBSD: sftp.c,v 1.170 2015/01/20 23:14:00 deraadt Exp $ */ +/* $OpenBSD: sftp.c,v 1.171 2015/08/20 22:32:42 deraadt Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "includes.h" #include /* MIN MAX */ #include #include #ifdef HAVE_SYS_STAT_H # include #endif #include #include #include #ifdef HAVE_SYS_STATVFS_H #include #endif #include #include #ifdef HAVE_PATHS_H # include #endif #ifdef HAVE_LIBGEN_H #include #endif #ifdef HAVE_LOCALE_H # include #endif #ifdef USE_LIBEDIT #include #else typedef void EditLine; #endif #include #include #include #include #include #include #include #ifdef HAVE_UTIL_H # include #endif #include "xmalloc.h" #include "log.h" #include "pathnames.h" #include "misc.h" #include "sftp.h" #include "ssherr.h" #include "sshbuf.h" #include "sftp-common.h" #include "sftp-client.h" #define DEFAULT_COPY_BUFLEN 32768 /* Size of buffer for up/download */ #define DEFAULT_NUM_REQUESTS 64 /* # concurrent outstanding requests */ /* File to read commands from */ FILE* infile; /* Are we in batchfile mode? */ int batchmode = 0; /* PID of ssh transport process */ static pid_t sshpid = -1; /* Suppress diagnositic messages */ int quiet = 0; /* This is set to 0 if the progressmeter is not desired. */ int showprogress = 1; /* When this option is set, we always recursively download/upload directories */ int global_rflag = 0; /* When this option is set, we resume download or upload if possible */ int global_aflag = 0; /* When this option is set, the file transfers will always preserve times */ int global_pflag = 0; /* When this option is set, transfers will have fsync() called on each file */ int global_fflag = 0; /* SIGINT received during command processing */ volatile sig_atomic_t interrupted = 0; /* I wish qsort() took a separate ctx for the comparison function...*/ int sort_flag; /* Context used for commandline completion */ struct complete_ctx { struct sftp_conn *conn; char **remote_pathp; }; int remote_glob(struct sftp_conn *, const char *, int, int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */ extern char *__progname; /* Separators for interactive commands */ #define WHITESPACE " \t\r\n" /* ls flags */ #define LS_LONG_VIEW 0x0001 /* Full view ala ls -l */ #define LS_SHORT_VIEW 0x0002 /* Single row view ala ls -1 */ #define LS_NUMERIC_VIEW 0x0004 /* Long view with numeric uid/gid */ #define LS_NAME_SORT 0x0008 /* Sort by name (default) */ #define LS_TIME_SORT 0x0010 /* Sort by mtime */ #define LS_SIZE_SORT 0x0020 /* Sort by file size */ #define LS_REVERSE_SORT 0x0040 /* Reverse sort order */ #define LS_SHOW_ALL 0x0080 /* Don't skip filenames starting with '.' */ #define LS_SI_UNITS 0x0100 /* Display sizes as K, M, G, etc. */ #define VIEW_FLAGS (LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW|LS_SI_UNITS) #define SORT_FLAGS (LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT) /* Commands for interactive mode */ enum sftp_command { I_CHDIR = 1, I_CHGRP, I_CHMOD, I_CHOWN, I_DF, I_GET, I_HELP, I_LCHDIR, I_LINK, I_LLS, I_LMKDIR, I_LPWD, I_LS, I_LUMASK, I_MKDIR, I_PUT, I_PWD, I_QUIT, I_REGET, I_RENAME, I_REPUT, I_RM, I_RMDIR, I_SHELL, I_SYMLINK, I_VERSION, I_PROGRESS, }; struct CMD { const char *c; const int n; const int t; }; /* Type of completion */ #define NOARGS 0 #define REMOTE 1 #define LOCAL 2 static const struct CMD cmds[] = { { "bye", I_QUIT, NOARGS }, { "cd", I_CHDIR, REMOTE }, { "chdir", I_CHDIR, REMOTE }, { "chgrp", I_CHGRP, REMOTE }, { "chmod", I_CHMOD, REMOTE }, { "chown", I_CHOWN, REMOTE }, { "df", I_DF, REMOTE }, { "dir", I_LS, REMOTE }, { "exit", I_QUIT, NOARGS }, { "get", I_GET, REMOTE }, { "help", I_HELP, NOARGS }, { "lcd", I_LCHDIR, LOCAL }, { "lchdir", I_LCHDIR, LOCAL }, { "lls", I_LLS, LOCAL }, { "lmkdir", I_LMKDIR, LOCAL }, { "ln", I_LINK, REMOTE }, { "lpwd", I_LPWD, LOCAL }, { "ls", I_LS, REMOTE }, { "lumask", I_LUMASK, NOARGS }, { "mkdir", I_MKDIR, REMOTE }, { "mget", I_GET, REMOTE }, { "mput", I_PUT, LOCAL }, { "progress", I_PROGRESS, NOARGS }, { "put", I_PUT, LOCAL }, { "pwd", I_PWD, REMOTE }, { "quit", I_QUIT, NOARGS }, { "reget", I_REGET, REMOTE }, { "rename", I_RENAME, REMOTE }, { "reput", I_REPUT, LOCAL }, { "rm", I_RM, REMOTE }, { "rmdir", I_RMDIR, REMOTE }, { "symlink", I_SYMLINK, REMOTE }, { "version", I_VERSION, NOARGS }, { "!", I_SHELL, NOARGS }, { "?", I_HELP, NOARGS }, { NULL, -1, -1 } }; int interactive_loop(struct sftp_conn *, char *file1, char *file2); /* ARGSUSED */ static void killchild(int signo) { if (sshpid > 1) { kill(sshpid, SIGTERM); waitpid(sshpid, NULL, 0); } _exit(1); } /* ARGSUSED */ static void cmd_interrupt(int signo) { const char msg[] = "\rInterrupt \n"; int olderrno = errno; (void)write(STDERR_FILENO, msg, sizeof(msg) - 1); interrupted = 1; errno = olderrno; } static void help(void) { printf("Available commands:\n" "bye Quit sftp\n" "cd path Change remote directory to 'path'\n" "chgrp grp path Change group of file 'path' to 'grp'\n" "chmod mode path Change permissions of file 'path' to 'mode'\n" "chown own path Change owner of file 'path' to 'own'\n" "df [-hi] [path] Display statistics for current directory or\n" " filesystem containing 'path'\n" "exit Quit sftp\n" "get [-afPpRr] remote [local] Download file\n" "reget [-fPpRr] remote [local] Resume download file\n" "reput [-fPpRr] [local] remote Resume upload file\n" "help Display this help text\n" "lcd path Change local directory to 'path'\n" "lls [ls-options [path]] Display local directory listing\n" "lmkdir path Create local directory\n" "ln [-s] oldpath newpath Link remote file (-s for symlink)\n" "lpwd Print local working directory\n" "ls [-1afhlnrSt] [path] Display remote directory listing\n" "lumask umask Set local umask to 'umask'\n" "mkdir path Create remote directory\n" "progress Toggle display of progress meter\n" "put [-afPpRr] local [remote] Upload file\n" "pwd Display remote working directory\n" "quit Quit sftp\n" "rename oldpath newpath Rename remote file\n" "rm path Delete remote file\n" "rmdir path Remove remote directory\n" "symlink oldpath newpath Symlink remote file\n" "version Show SFTP version\n" "!command Execute 'command' in local shell\n" "! Escape to local shell\n" "? Synonym for help\n"); } static void local_do_shell(const char *args) { int status; char *shell; pid_t pid; if (!*args) args = NULL; if ((shell = getenv("SHELL")) == NULL || *shell == '\0') shell = _PATH_BSHELL; if ((pid = fork()) == -1) fatal("Couldn't fork: %s", strerror(errno)); if (pid == 0) { /* XXX: child has pipe fds to ssh subproc open - issue? */ if (args) { debug3("Executing %s -c \"%s\"", shell, args); execl(shell, shell, "-c", args, (char *)NULL); } else { debug3("Executing %s", shell); execl(shell, shell, (char *)NULL); } fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell, strerror(errno)); _exit(1); } while (waitpid(pid, &status, 0) == -1) if (errno != EINTR) fatal("Couldn't wait for child: %s", strerror(errno)); if (!WIFEXITED(status)) error("Shell exited abnormally"); else if (WEXITSTATUS(status)) error("Shell exited with status %d", WEXITSTATUS(status)); } static void local_do_ls(const char *args) { if (!args || !*args) local_do_shell(_PATH_LS); else { int len = strlen(_PATH_LS " ") + strlen(args) + 1; char *buf = xmalloc(len); /* XXX: quoting - rip quoting code from ftp? */ snprintf(buf, len, _PATH_LS " %s", args); local_do_shell(buf); free(buf); } } /* Strip one path (usually the pwd) from the start of another */ static char * path_strip(char *path, char *strip) { size_t len; if (strip == NULL) return (xstrdup(path)); len = strlen(strip); if (strncmp(path, strip, len) == 0) { if (strip[len - 1] != '/' && path[len] == '/') len++; return (xstrdup(path + len)); } return (xstrdup(path)); } static char * make_absolute(char *p, char *pwd) { char *abs_str; /* Derelativise */ if (p && p[0] != '/') { abs_str = path_append(pwd, p); free(p); return(abs_str); } else return(p); } static int parse_getput_flags(const char *cmd, char **argv, int argc, int *aflag, int *fflag, int *pflag, int *rflag) { extern int opterr, optind, optopt, optreset; int ch; optind = optreset = 1; opterr = 0; *aflag = *fflag = *rflag = *pflag = 0; while ((ch = getopt(argc, argv, "afPpRr")) != -1) { switch (ch) { case 'a': *aflag = 1; break; case 'f': *fflag = 1; break; case 'p': case 'P': *pflag = 1; break; case 'r': case 'R': *rflag = 1; break; default: error("%s: Invalid flag -%c", cmd, optopt); return -1; } } return optind; } static int parse_link_flags(const char *cmd, char **argv, int argc, int *sflag) { extern int opterr, optind, optopt, optreset; int ch; optind = optreset = 1; opterr = 0; *sflag = 0; while ((ch = getopt(argc, argv, "s")) != -1) { switch (ch) { case 's': *sflag = 1; break; default: error("%s: Invalid flag -%c", cmd, optopt); return -1; } } return optind; } static int parse_rename_flags(const char *cmd, char **argv, int argc, int *lflag) { extern int opterr, optind, optopt, optreset; int ch; optind = optreset = 1; opterr = 0; *lflag = 0; while ((ch = getopt(argc, argv, "l")) != -1) { switch (ch) { case 'l': *lflag = 1; break; default: error("%s: Invalid flag -%c", cmd, optopt); return -1; } } return optind; } static int parse_ls_flags(char **argv, int argc, int *lflag) { extern int opterr, optind, optopt, optreset; int ch; optind = optreset = 1; opterr = 0; *lflag = LS_NAME_SORT; while ((ch = getopt(argc, argv, "1Safhlnrt")) != -1) { switch (ch) { case '1': *lflag &= ~VIEW_FLAGS; *lflag |= LS_SHORT_VIEW; break; case 'S': *lflag &= ~SORT_FLAGS; *lflag |= LS_SIZE_SORT; break; case 'a': *lflag |= LS_SHOW_ALL; break; case 'f': *lflag &= ~SORT_FLAGS; break; case 'h': *lflag |= LS_SI_UNITS; break; case 'l': *lflag &= ~LS_SHORT_VIEW; *lflag |= LS_LONG_VIEW; break; case 'n': *lflag &= ~LS_SHORT_VIEW; *lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW; break; case 'r': *lflag |= LS_REVERSE_SORT; break; case 't': *lflag &= ~SORT_FLAGS; *lflag |= LS_TIME_SORT; break; default: error("ls: Invalid flag -%c", optopt); return -1; } } return optind; } static int parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag) { extern int opterr, optind, optopt, optreset; int ch; optind = optreset = 1; opterr = 0; *hflag = *iflag = 0; while ((ch = getopt(argc, argv, "hi")) != -1) { switch (ch) { case 'h': *hflag = 1; break; case 'i': *iflag = 1; break; default: error("%s: Invalid flag -%c", cmd, optopt); return -1; } } return optind; } static int parse_no_flags(const char *cmd, char **argv, int argc) { extern int opterr, optind, optopt, optreset; int ch; optind = optreset = 1; opterr = 0; while ((ch = getopt(argc, argv, "")) != -1) { switch (ch) { default: error("%s: Invalid flag -%c", cmd, optopt); return -1; } } return optind; } static int is_dir(char *path) { struct stat sb; /* XXX: report errors? */ if (stat(path, &sb) == -1) return(0); return(S_ISDIR(sb.st_mode)); } static int remote_is_dir(struct sftp_conn *conn, char *path) { Attrib *a; /* XXX: report errors? */ if ((a = do_stat(conn, path, 1)) == NULL) return(0); if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) return(0); return(S_ISDIR(a->perm)); } /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */ static int pathname_is_dir(char *pathname) { size_t l = strlen(pathname); return l > 0 && pathname[l - 1] == '/'; } static int process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag, int rflag, int resume, int fflag) { char *abs_src = NULL; char *abs_dst = NULL; glob_t g; char *filename, *tmp=NULL; int i, r, err = 0; abs_src = xstrdup(src); abs_src = make_absolute(abs_src, pwd); memset(&g, 0, sizeof(g)); debug3("Looking up %s", abs_src); if ((r = remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) != 0) { if (r == GLOB_NOSPACE) { error("Too many matches for \"%s\".", abs_src); } else { error("File \"%s\" not found.", abs_src); } err = -1; goto out; } /* * If multiple matches then dst must be a directory or * unspecified. */ if (g.gl_matchc > 1 && dst != NULL && !is_dir(dst)) { error("Multiple source paths, but destination " "\"%s\" is not a directory", dst); err = -1; goto out; } for (i = 0; g.gl_pathv[i] && !interrupted; i++) { tmp = xstrdup(g.gl_pathv[i]); if ((filename = basename(tmp)) == NULL) { error("basename %s: %s", tmp, strerror(errno)); free(tmp); err = -1; goto out; } if (g.gl_matchc == 1 && dst) { if (is_dir(dst)) { abs_dst = path_append(dst, filename); } else { abs_dst = xstrdup(dst); } } else if (dst) { abs_dst = path_append(dst, filename); } else { abs_dst = xstrdup(filename); } free(tmp); resume |= global_aflag; if (!quiet && resume) printf("Resuming %s to %s\n", g.gl_pathv[i], abs_dst); else if (!quiet && !resume) printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, pflag || global_pflag, 1, resume, fflag || global_fflag) == -1) err = -1; } else { if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, pflag || global_pflag, resume, fflag || global_fflag) == -1) err = -1; } free(abs_dst); abs_dst = NULL; } out: free(abs_src); globfree(&g); return(err); } static int process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag, int rflag, int resume, int fflag) { char *tmp_dst = NULL; char *abs_dst = NULL; char *tmp = NULL, *filename = NULL; glob_t g; int err = 0; int i, dst_is_dir = 1; struct stat sb; if (dst) { tmp_dst = xstrdup(dst); tmp_dst = make_absolute(tmp_dst, pwd); } memset(&g, 0, sizeof(g)); debug3("Looking up %s", src); if (glob(src, GLOB_NOCHECK | GLOB_MARK, NULL, &g)) { error("File \"%s\" not found.", src); err = -1; goto out; } /* If we aren't fetching to pwd then stash this status for later */ if (tmp_dst != NULL) dst_is_dir = remote_is_dir(conn, tmp_dst); /* If multiple matches, dst may be directory or unspecified */ if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) { error("Multiple paths match, but destination " "\"%s\" is not a directory", tmp_dst); err = -1; goto out; } for (i = 0; g.gl_pathv[i] && !interrupted; i++) { if (stat(g.gl_pathv[i], &sb) == -1) { err = -1; error("stat %s: %s", g.gl_pathv[i], strerror(errno)); continue; } tmp = xstrdup(g.gl_pathv[i]); if ((filename = basename(tmp)) == NULL) { error("basename %s: %s", tmp, strerror(errno)); free(tmp); err = -1; goto out; } if (g.gl_matchc == 1 && tmp_dst) { /* If directory specified, append filename */ if (dst_is_dir) abs_dst = path_append(tmp_dst, filename); else abs_dst = xstrdup(tmp_dst); } else if (tmp_dst) { abs_dst = path_append(tmp_dst, filename); } else { abs_dst = make_absolute(xstrdup(filename), pwd); } free(tmp); resume |= global_aflag; if (!quiet && resume) printf("Resuming upload of %s to %s\n", g.gl_pathv[i], abs_dst); else if (!quiet && !resume) printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { if (upload_dir(conn, g.gl_pathv[i], abs_dst, pflag || global_pflag, 1, resume, fflag || global_fflag) == -1) err = -1; } else { if (do_upload(conn, g.gl_pathv[i], abs_dst, pflag || global_pflag, resume, fflag || global_fflag) == -1) err = -1; } } out: free(abs_dst); free(tmp_dst); globfree(&g); return(err); } static int sdirent_comp(const void *aa, const void *bb) { SFTP_DIRENT *a = *(SFTP_DIRENT **)aa; SFTP_DIRENT *b = *(SFTP_DIRENT **)bb; int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1; #define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1)) if (sort_flag & LS_NAME_SORT) return (rmul * strcmp(a->filename, b->filename)); else if (sort_flag & LS_TIME_SORT) return (rmul * NCMP(a->a.mtime, b->a.mtime)); else if (sort_flag & LS_SIZE_SORT) return (rmul * NCMP(a->a.size, b->a.size)); fatal("Unknown ls sort type"); } /* sftp ls.1 replacement for directories */ static int do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) { int n; u_int c = 1, colspace = 0, columns = 1; SFTP_DIRENT **d; if ((n = do_readdir(conn, path, &d)) != 0) return (n); if (!(lflag & LS_SHORT_VIEW)) { u_int m = 0, width = 80; struct winsize ws; char *tmp; /* Count entries for sort and find longest filename */ for (n = 0; d[n] != NULL; n++) { if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL)) m = MAX(m, strlen(d[n]->filename)); } /* Add any subpath that also needs to be counted */ tmp = path_strip(path, strip_path); m += strlen(tmp); free(tmp); if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) width = ws.ws_col; columns = width / (m + 2); columns = MAX(columns, 1); colspace = width / columns; colspace = MIN(colspace, width); } if (lflag & SORT_FLAGS) { for (n = 0; d[n] != NULL; n++) ; /* count entries */ sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT); qsort(d, n, sizeof(*d), sdirent_comp); } for (n = 0; d[n] != NULL && !interrupted; n++) { char *tmp, *fname; if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL)) continue; tmp = path_append(path, d[n]->filename); fname = path_strip(tmp, strip_path); free(tmp); if (lflag & LS_LONG_VIEW) { if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) { char *lname; struct stat sb; memset(&sb, 0, sizeof(sb)); attrib_to_stat(&d[n]->a, &sb); lname = ls_file(fname, &sb, 1, (lflag & LS_SI_UNITS)); printf("%s\n", lname); free(lname); } else printf("%s\n", d[n]->longname); } else { printf("%-*s", colspace, fname); if (c >= columns) { printf("\n"); c = 1; } else c++; } free(fname); } if (!(lflag & LS_LONG_VIEW) && (c != 1)) printf("\n"); free_sftp_dirents(d); return (0); } /* sftp ls.1 replacement which handles path globs */ static int do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, int lflag) { char *fname, *lname; glob_t g; int err, r; struct winsize ws; u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80; memset(&g, 0, sizeof(g)); if ((r = remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT|GLOB_NOSORT, NULL, &g)) != 0 || (g.gl_pathc && !g.gl_matchc)) { if (g.gl_pathc) globfree(&g); if (r == GLOB_NOSPACE) { error("Can't ls: Too many matches for \"%s\"", path); } else { error("Can't ls: \"%s\" not found", path); } return -1; } if (interrupted) goto out; /* * If the glob returns a single match and it is a directory, * then just list its contents. */ if (g.gl_matchc == 1 && g.gl_statv[0] != NULL && S_ISDIR(g.gl_statv[0]->st_mode)) { err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag); globfree(&g); return err; } if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) width = ws.ws_col; if (!(lflag & LS_SHORT_VIEW)) { /* Count entries for sort and find longest filename */ for (i = 0; g.gl_pathv[i]; i++) m = MAX(m, strlen(g.gl_pathv[i])); columns = width / (m + 2); columns = MAX(columns, 1); colspace = width / columns; } for (i = 0; g.gl_pathv[i] && !interrupted; i++) { fname = path_strip(g.gl_pathv[i], strip_path); if (lflag & LS_LONG_VIEW) { if (g.gl_statv[i] == NULL) { error("no stat information for %s", fname); continue; } lname = ls_file(fname, g.gl_statv[i], 1, (lflag & LS_SI_UNITS)); printf("%s\n", lname); free(lname); } else { printf("%-*s", colspace, fname); if (c >= columns) { printf("\n"); c = 1; } else c++; } free(fname); } if (!(lflag & LS_LONG_VIEW) && (c != 1)) printf("\n"); out: if (g.gl_pathc) globfree(&g); return 0; } static int do_df(struct sftp_conn *conn, char *path, int hflag, int iflag) { struct sftp_statvfs st; char s_used[FMT_SCALED_STRSIZE]; char s_avail[FMT_SCALED_STRSIZE]; char s_root[FMT_SCALED_STRSIZE]; char s_total[FMT_SCALED_STRSIZE]; unsigned long long ffree; if (do_statvfs(conn, path, &st, 1) == -1) return -1; if (iflag) { ffree = st.f_files ? (100 * (st.f_files - st.f_ffree) / st.f_files) : 0; printf(" Inodes Used Avail " "(root) %%Capacity\n"); printf("%11llu %11llu %11llu %11llu %3llu%%\n", (unsigned long long)st.f_files, (unsigned long long)(st.f_files - st.f_ffree), (unsigned long long)st.f_favail, (unsigned long long)st.f_ffree, ffree); } else if (hflag) { strlcpy(s_used, "error", sizeof(s_used)); strlcpy(s_avail, "error", sizeof(s_avail)); strlcpy(s_root, "error", sizeof(s_root)); strlcpy(s_total, "error", sizeof(s_total)); fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used); fmt_scaled(st.f_bavail * st.f_frsize, s_avail); fmt_scaled(st.f_bfree * st.f_frsize, s_root); fmt_scaled(st.f_blocks * st.f_frsize, s_total); printf(" Size Used Avail (root) %%Capacity\n"); printf("%7sB %7sB %7sB %7sB %3llu%%\n", s_total, s_used, s_avail, s_root, (unsigned long long)(100 * (st.f_blocks - st.f_bfree) / st.f_blocks)); } else { printf(" Size Used Avail " "(root) %%Capacity\n"); printf("%12llu %12llu %12llu %12llu %3llu%%\n", (unsigned long long)(st.f_frsize * st.f_blocks / 1024), (unsigned long long)(st.f_frsize * (st.f_blocks - st.f_bfree) / 1024), (unsigned long long)(st.f_frsize * st.f_bavail / 1024), (unsigned long long)(st.f_frsize * st.f_bfree / 1024), (unsigned long long)(100 * (st.f_blocks - st.f_bfree) / st.f_blocks)); } return 0; } /* * Undo escaping of glob sequences in place. Used to undo extra escaping * applied in makeargv() when the string is destined for a function that * does not glob it. */ static void undo_glob_escape(char *s) { size_t i, j; for (i = j = 0;;) { if (s[i] == '\0') { s[j] = '\0'; return; } if (s[i] != '\\') { s[j++] = s[i++]; continue; } /* s[i] == '\\' */ ++i; switch (s[i]) { case '?': case '[': case '*': case '\\': s[j++] = s[i++]; break; case '\0': s[j++] = '\\'; s[j] = '\0'; return; default: s[j++] = '\\'; s[j++] = s[i++]; break; } } } /* * Split a string into an argument vector using sh(1)-style quoting, * comment and escaping rules, but with some tweaks to handle glob(3) * wildcards. * The "sloppy" flag allows for recovery from missing terminating quote, for * use in parsing incomplete commandlines during tab autocompletion. * * Returns NULL on error or a NULL-terminated array of arguments. * * If "lastquote" is not NULL, the quoting character used for the last * argument is placed in *lastquote ("\0", "'" or "\""). * * If "terminated" is not NULL, *terminated will be set to 1 when the * last argument's quote has been properly terminated or 0 otherwise. * This parameter is only of use if "sloppy" is set. */ #define MAXARGS 128 #define MAXARGLEN 8192 static char ** makeargv(const char *arg, int *argcp, int sloppy, char *lastquote, u_int *terminated) { int argc, quot; size_t i, j; static char argvs[MAXARGLEN]; static char *argv[MAXARGS + 1]; enum { MA_START, MA_SQUOTE, MA_DQUOTE, MA_UNQUOTED } state, q; *argcp = argc = 0; if (strlen(arg) > sizeof(argvs) - 1) { args_too_longs: error("string too long"); return NULL; } if (terminated != NULL) *terminated = 1; if (lastquote != NULL) *lastquote = '\0'; state = MA_START; i = j = 0; for (;;) { if ((size_t)argc >= sizeof(argv) / sizeof(*argv)){ error("Too many arguments."); return NULL; } if (isspace((unsigned char)arg[i])) { if (state == MA_UNQUOTED) { /* Terminate current argument */ argvs[j++] = '\0'; argc++; state = MA_START; } else if (state != MA_START) argvs[j++] = arg[i]; } else if (arg[i] == '"' || arg[i] == '\'') { q = arg[i] == '"' ? MA_DQUOTE : MA_SQUOTE; if (state == MA_START) { argv[argc] = argvs + j; state = q; if (lastquote != NULL) *lastquote = arg[i]; } else if (state == MA_UNQUOTED) state = q; else if (state == q) state = MA_UNQUOTED; else argvs[j++] = arg[i]; } else if (arg[i] == '\\') { if (state == MA_SQUOTE || state == MA_DQUOTE) { quot = state == MA_SQUOTE ? '\'' : '"'; /* Unescape quote we are in */ /* XXX support \n and friends? */ if (arg[i + 1] == quot) { i++; argvs[j++] = arg[i]; } else if (arg[i + 1] == '?' || arg[i + 1] == '[' || arg[i + 1] == '*') { /* * Special case for sftp: append * double-escaped glob sequence - * glob will undo one level of * escaping. NB. string can grow here. */ if (j >= sizeof(argvs) - 5) goto args_too_longs; argvs[j++] = '\\'; argvs[j++] = arg[i++]; argvs[j++] = '\\'; argvs[j++] = arg[i]; } else { argvs[j++] = arg[i++]; argvs[j++] = arg[i]; } } else { if (state == MA_START) { argv[argc] = argvs + j; state = MA_UNQUOTED; if (lastquote != NULL) *lastquote = '\0'; } if (arg[i + 1] == '?' || arg[i + 1] == '[' || arg[i + 1] == '*' || arg[i + 1] == '\\') { /* * Special case for sftp: append * escaped glob sequence - * glob will undo one level of * escaping. */ argvs[j++] = arg[i++]; argvs[j++] = arg[i]; } else { /* Unescape everything */ /* XXX support \n and friends? */ i++; argvs[j++] = arg[i]; } } } else if (arg[i] == '#') { if (state == MA_SQUOTE || state == MA_DQUOTE) argvs[j++] = arg[i]; else goto string_done; } else if (arg[i] == '\0') { if (state == MA_SQUOTE || state == MA_DQUOTE) { if (sloppy) { state = MA_UNQUOTED; if (terminated != NULL) *terminated = 0; goto string_done; } error("Unterminated quoted argument"); return NULL; } string_done: if (state == MA_UNQUOTED) { argvs[j++] = '\0'; argc++; } break; } else { if (state == MA_START) { argv[argc] = argvs + j; state = MA_UNQUOTED; if (lastquote != NULL) *lastquote = '\0'; } if ((state == MA_SQUOTE || state == MA_DQUOTE) && (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) { /* * Special case for sftp: escape quoted * glob(3) wildcards. NB. string can grow * here. */ if (j >= sizeof(argvs) - 3) goto args_too_longs; argvs[j++] = '\\'; argvs[j++] = arg[i]; } else argvs[j++] = arg[i]; } i++; } *argcp = argc; return argv; } static int parse_args(const char **cpp, int *ignore_errors, int *aflag, int *fflag, int *hflag, int *iflag, int *lflag, int *pflag, int *rflag, int *sflag, unsigned long *n_arg, char **path1, char **path2) { const char *cmd, *cp = *cpp; char *cp2, **argv; int base = 0; long l; int i, cmdnum, optidx, argc; /* Skip leading whitespace */ cp = cp + strspn(cp, WHITESPACE); /* Check for leading '-' (disable error processing) */ *ignore_errors = 0; if (*cp == '-') { *ignore_errors = 1; cp++; cp = cp + strspn(cp, WHITESPACE); } /* Ignore blank lines and lines which begin with comment '#' char */ if (*cp == '\0' || *cp == '#') return (0); if ((argv = makeargv(cp, &argc, 0, NULL, NULL)) == NULL) return -1; /* Figure out which command we have */ for (i = 0; cmds[i].c != NULL; i++) { if (argv[0] != NULL && strcasecmp(cmds[i].c, argv[0]) == 0) break; } cmdnum = cmds[i].n; cmd = cmds[i].c; /* Special case */ if (*cp == '!') { cp++; cmdnum = I_SHELL; } else if (cmdnum == -1) { error("Invalid command."); return -1; } /* Get arguments and parse flags */ *aflag = *fflag = *hflag = *iflag = *lflag = *pflag = 0; *rflag = *sflag = 0; *path1 = *path2 = NULL; optidx = 1; switch (cmdnum) { case I_GET: case I_REGET: case I_REPUT: case I_PUT: if ((optidx = parse_getput_flags(cmd, argv, argc, aflag, fflag, pflag, rflag)) == -1) return -1; /* Get first pathname (mandatory) */ if (argc - optidx < 1) { error("You must specify at least one path after a " "%s command.", cmd); return -1; } *path1 = xstrdup(argv[optidx]); /* Get second pathname (optional) */ if (argc - optidx > 1) { *path2 = xstrdup(argv[optidx + 1]); /* Destination is not globbed */ undo_glob_escape(*path2); } break; case I_LINK: if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1) return -1; goto parse_two_paths; case I_RENAME: if ((optidx = parse_rename_flags(cmd, argv, argc, lflag)) == -1) return -1; goto parse_two_paths; case I_SYMLINK: if ((optidx = parse_no_flags(cmd, argv, argc)) == -1) return -1; parse_two_paths: if (argc - optidx < 2) { error("You must specify two paths after a %s " "command.", cmd); return -1; } *path1 = xstrdup(argv[optidx]); *path2 = xstrdup(argv[optidx + 1]); /* Paths are not globbed */ undo_glob_escape(*path1); undo_glob_escape(*path2); break; case I_RM: case I_MKDIR: case I_RMDIR: case I_CHDIR: case I_LCHDIR: case I_LMKDIR: if ((optidx = parse_no_flags(cmd, argv, argc)) == -1) return -1; /* Get pathname (mandatory) */ if (argc - optidx < 1) { error("You must specify a path after a %s command.", cmd); return -1; } *path1 = xstrdup(argv[optidx]); /* Only "rm" globs */ if (cmdnum != I_RM) undo_glob_escape(*path1); break; case I_DF: if ((optidx = parse_df_flags(cmd, argv, argc, hflag, iflag)) == -1) return -1; /* Default to current directory if no path specified */ if (argc - optidx < 1) *path1 = NULL; else { *path1 = xstrdup(argv[optidx]); undo_glob_escape(*path1); } break; case I_LS: if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1) return(-1); /* Path is optional */ if (argc - optidx > 0) *path1 = xstrdup(argv[optidx]); break; case I_LLS: /* Skip ls command and following whitespace */ cp = cp + strlen(cmd) + strspn(cp, WHITESPACE); case I_SHELL: /* Uses the rest of the line */ break; case I_LUMASK: case I_CHMOD: base = 8; case I_CHOWN: case I_CHGRP: if ((optidx = parse_no_flags(cmd, argv, argc)) == -1) return -1; /* Get numeric arg (mandatory) */ if (argc - optidx < 1) goto need_num_arg; errno = 0; l = strtol(argv[optidx], &cp2, base); if (cp2 == argv[optidx] || *cp2 != '\0' || ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) || l < 0) { need_num_arg: error("You must supply a numeric argument " "to the %s command.", cmd); return -1; } *n_arg = l; if (cmdnum == I_LUMASK) break; /* Get pathname (mandatory) */ if (argc - optidx < 2) { error("You must specify a path after a %s command.", cmd); return -1; } *path1 = xstrdup(argv[optidx + 1]); break; case I_QUIT: case I_PWD: case I_LPWD: case I_HELP: case I_VERSION: case I_PROGRESS: if ((optidx = parse_no_flags(cmd, argv, argc)) == -1) return -1; break; default: fatal("Command not implemented"); } *cpp = cp; return(cmdnum); } static int parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, int err_abort) { char *path1, *path2, *tmp; int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0, iflag = 0; int lflag = 0, pflag = 0, rflag = 0, sflag = 0; int cmdnum, i; unsigned long n_arg = 0; Attrib a, *aa; char path_buf[PATH_MAX]; int err = 0; glob_t g; path1 = path2 = NULL; cmdnum = parse_args(&cmd, &ignore_errors, &aflag, &fflag, &hflag, &iflag, &lflag, &pflag, &rflag, &sflag, &n_arg, &path1, &path2); if (ignore_errors != 0) err_abort = 0; memset(&g, 0, sizeof(g)); /* Perform command */ switch (cmdnum) { case 0: /* Blank line */ break; case -1: /* Unrecognized command */ err = -1; break; case I_REGET: aflag = 1; /* FALLTHROUGH */ case I_GET: err = process_get(conn, path1, path2, *pwd, pflag, rflag, aflag, fflag); break; case I_REPUT: aflag = 1; /* FALLTHROUGH */ case I_PUT: err = process_put(conn, path1, path2, *pwd, pflag, rflag, aflag, fflag); break; case I_RENAME: path1 = make_absolute(path1, *pwd); path2 = make_absolute(path2, *pwd); err = do_rename(conn, path1, path2, lflag); break; case I_SYMLINK: sflag = 1; case I_LINK: if (!sflag) path1 = make_absolute(path1, *pwd); path2 = make_absolute(path2, *pwd); err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2); break; case I_RM: path1 = make_absolute(path1, *pwd); remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i] && !interrupted; i++) { if (!quiet) printf("Removing %s\n", g.gl_pathv[i]); err = do_rm(conn, g.gl_pathv[i]); if (err != 0 && err_abort) break; } break; case I_MKDIR: path1 = make_absolute(path1, *pwd); attrib_clear(&a); a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; a.perm = 0777; err = do_mkdir(conn, path1, &a, 1); break; case I_RMDIR: path1 = make_absolute(path1, *pwd); err = do_rmdir(conn, path1); break; case I_CHDIR: path1 = make_absolute(path1, *pwd); if ((tmp = do_realpath(conn, path1)) == NULL) { err = 1; break; } if ((aa = do_stat(conn, tmp, 0)) == NULL) { free(tmp); err = 1; break; } if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { error("Can't change directory: Can't check target"); free(tmp); err = 1; break; } if (!S_ISDIR(aa->perm)) { error("Can't change directory: \"%s\" is not " "a directory", tmp); free(tmp); err = 1; break; } free(*pwd); *pwd = tmp; break; case I_LS: if (!path1) { do_ls_dir(conn, *pwd, *pwd, lflag); break; } /* Strip pwd off beginning of non-absolute paths */ tmp = NULL; if (*path1 != '/') tmp = *pwd; path1 = make_absolute(path1, *pwd); err = do_globbed_ls(conn, path1, tmp, lflag); break; case I_DF: /* Default to current directory if no path specified */ if (path1 == NULL) path1 = xstrdup(*pwd); path1 = make_absolute(path1, *pwd); err = do_df(conn, path1, hflag, iflag); break; case I_LCHDIR: tmp = tilde_expand_filename(path1, getuid()); free(path1); path1 = tmp; if (chdir(path1) == -1) { error("Couldn't change local directory to " "\"%s\": %s", path1, strerror(errno)); err = 1; } break; case I_LMKDIR: if (mkdir(path1, 0777) == -1) { error("Couldn't create local directory " "\"%s\": %s", path1, strerror(errno)); err = 1; } break; case I_LLS: local_do_ls(cmd); break; case I_SHELL: local_do_shell(cmd); break; case I_LUMASK: umask(n_arg); printf("Local umask: %03lo\n", n_arg); break; case I_CHMOD: path1 = make_absolute(path1, *pwd); attrib_clear(&a); a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; a.perm = n_arg; remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i] && !interrupted; i++) { if (!quiet) printf("Changing mode on %s\n", g.gl_pathv[i]); err = do_setstat(conn, g.gl_pathv[i], &a); if (err != 0 && err_abort) break; } break; case I_CHOWN: case I_CHGRP: path1 = make_absolute(path1, *pwd); remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i] && !interrupted; i++) { if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) { if (err_abort) { err = -1; break; } else continue; } if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { error("Can't get current ownership of " "remote file \"%s\"", g.gl_pathv[i]); if (err_abort) { err = -1; break; } else continue; } aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; if (cmdnum == I_CHOWN) { if (!quiet) printf("Changing owner on %s\n", g.gl_pathv[i]); aa->uid = n_arg; } else { if (!quiet) printf("Changing group on %s\n", g.gl_pathv[i]); aa->gid = n_arg; } err = do_setstat(conn, g.gl_pathv[i], aa); if (err != 0 && err_abort) break; } break; case I_PWD: printf("Remote working directory: %s\n", *pwd); break; case I_LPWD: if (!getcwd(path_buf, sizeof(path_buf))) { error("Couldn't get local cwd: %s", strerror(errno)); err = -1; break; } printf("Local working directory: %s\n", path_buf); break; case I_QUIT: /* Processed below */ break; case I_HELP: help(); break; case I_VERSION: printf("SFTP protocol version %u\n", sftp_proto_version(conn)); break; case I_PROGRESS: showprogress = !showprogress; if (showprogress) printf("Progress meter enabled\n"); else printf("Progress meter disabled\n"); break; default: fatal("%d is not implemented", cmdnum); } if (g.gl_pathc) globfree(&g); free(path1); free(path2); /* If an unignored error occurs in batch mode we should abort. */ if (err_abort && err != 0) return (-1); else if (cmdnum == I_QUIT) return (1); return (0); } #ifdef USE_LIBEDIT static char * prompt(EditLine *el) { return ("sftp> "); } /* Display entries in 'list' after skipping the first 'len' chars */ static void complete_display(char **list, u_int len) { u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen; struct winsize ws; char *tmp; /* Count entries for sort and find longest */ for (y = 0; list[y]; y++) m = MAX(m, strlen(list[y])); if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) width = ws.ws_col; m = m > len ? m - len : 0; columns = width / (m + 2); columns = MAX(columns, 1); colspace = width / columns; colspace = MIN(colspace, width); printf("\n"); m = 1; for (y = 0; list[y]; y++) { llen = strlen(list[y]); tmp = llen > len ? list[y] + len : ""; printf("%-*s", colspace, tmp); if (m >= columns) { printf("\n"); m = 1; } else m++; } printf("\n"); } /* * Given a "list" of words that begin with a common prefix of "word", * attempt to find an autocompletion to extends "word" by the next * characters common to all entries in "list". */ static char * complete_ambiguous(const char *word, char **list, size_t count) { if (word == NULL) return NULL; if (count > 0) { u_int y, matchlen = strlen(list[0]); /* Find length of common stem */ for (y = 1; list[y]; y++) { u_int x; for (x = 0; x < matchlen; x++) if (list[0][x] != list[y][x]) break; matchlen = x; } if (matchlen > strlen(word)) { char *tmp = xstrdup(list[0]); tmp[matchlen] = '\0'; return tmp; } } return xstrdup(word); } /* Autocomplete a sftp command */ static int complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, int terminated) { u_int y, count = 0, cmdlen, tmplen; char *tmp, **list, argterm[3]; const LineInfo *lf; list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *)); /* No command specified: display all available commands */ if (cmd == NULL) { for (y = 0; cmds[y].c; y++) list[count++] = xstrdup(cmds[y].c); list[count] = NULL; complete_display(list, 0); for (y = 0; list[y] != NULL; y++) free(list[y]); free(list); return count; } /* Prepare subset of commands that start with "cmd" */ cmdlen = strlen(cmd); for (y = 0; cmds[y].c; y++) { if (!strncasecmp(cmd, cmds[y].c, cmdlen)) list[count++] = xstrdup(cmds[y].c); } list[count] = NULL; if (count == 0) { free(list); return 0; } /* Complete ambigious command */ tmp = complete_ambiguous(cmd, list, count); if (count > 1) complete_display(list, 0); for (y = 0; list[y]; y++) free(list[y]); free(list); if (tmp != NULL) { tmplen = strlen(tmp); cmdlen = strlen(cmd); /* If cmd may be extended then do so */ if (tmplen > cmdlen) if (el_insertstr(el, tmp + cmdlen) == -1) fatal("el_insertstr failed."); lf = el_line(el); /* Terminate argument cleanly */ if (count == 1) { y = 0; if (!terminated) argterm[y++] = quote; if (lastarg || *(lf->cursor) != ' ') argterm[y++] = ' '; argterm[y] = '\0'; if (y > 0 && el_insertstr(el, argterm) == -1) fatal("el_insertstr failed."); } free(tmp); } return count; } /* * Determine whether a particular sftp command's arguments (if any) * represent local or remote files. */ static int complete_is_remote(char *cmd) { int i; if (cmd == NULL) return -1; for (i = 0; cmds[i].c; i++) { if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c))) return cmds[i].t; } return -1; } /* Autocomplete a filename "file" */ static int complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, char *file, int remote, int lastarg, char quote, int terminated) { glob_t g; char *tmp, *tmp2, ins[8]; u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs; int clen; const LineInfo *lf; /* Glob from "file" location */ if (file == NULL) tmp = xstrdup("*"); else xasprintf(&tmp, "%s*", file); /* Check if the path is absolute. */ isabs = tmp[0] == '/'; memset(&g, 0, sizeof(g)); if (remote != LOCAL) { tmp = make_absolute(tmp, remote_path); remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); } else glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); /* Determine length of pwd so we can trim completion display */ for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) { /* Terminate counting on first unescaped glob metacharacter */ if (tmp[tmplen] == '*' || tmp[tmplen] == '?') { if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0') hadglob = 1; break; } if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0') tmplen++; if (tmp[tmplen] == '/') pwdlen = tmplen + 1; /* track last seen '/' */ } free(tmp); tmp = NULL; if (g.gl_matchc == 0) goto out; if (g.gl_matchc > 1) complete_display(g.gl_pathv, pwdlen); /* Don't try to extend globs */ if (file == NULL || hadglob) goto out; tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc); tmp = path_strip(tmp2, isabs ? NULL : remote_path); free(tmp2); if (tmp == NULL) goto out; tmplen = strlen(tmp); filelen = strlen(file); /* Count the number of escaped characters in the input string. */ cesc = isesc = 0; for (i = 0; i < filelen; i++) { if (!isesc && file[i] == '\\' && i + 1 < filelen){ isesc = 1; cesc++; } else isesc = 0; } if (tmplen > (filelen - cesc)) { tmp2 = tmp + filelen - cesc; len = strlen(tmp2); /* quote argument on way out */ for (i = 0; i < len; i += clen) { if ((clen = mblen(tmp2 + i, len - i)) < 0 || (size_t)clen > sizeof(ins) - 2) fatal("invalid multibyte character"); ins[0] = '\\'; memcpy(ins + 1, tmp2 + i, clen); ins[clen + 1] = '\0'; switch (tmp2[i]) { case '\'': case '"': case '\\': case '\t': case '[': case ' ': case '#': case '*': if (quote == '\0' || tmp2[i] == quote) { if (el_insertstr(el, ins) == -1) fatal("el_insertstr " "failed."); break; } /* FALLTHROUGH */ default: if (el_insertstr(el, ins + 1) == -1) fatal("el_insertstr failed."); break; } } } lf = el_line(el); if (g.gl_matchc == 1) { i = 0; if (!terminated && quote != '\0') ins[i++] = quote; if (*(lf->cursor - 1) != '/' && (lastarg || *(lf->cursor) != ' ')) ins[i++] = ' '; ins[i] = '\0'; if (i > 0 && el_insertstr(el, ins) == -1) fatal("el_insertstr failed."); } free(tmp); out: globfree(&g); return g.gl_matchc; } /* tab-completion hook function, called via libedit */ static unsigned char complete(EditLine *el, int ch) { char **argv, *line, quote; int argc, carg; u_int cursor, len, terminated, ret = CC_ERROR; const LineInfo *lf; struct complete_ctx *complete_ctx; lf = el_line(el); if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0) fatal("%s: el_get failed", __func__); /* Figure out which argument the cursor points to */ cursor = lf->cursor - lf->buffer; - line = (char *)xmalloc(cursor + 1); + line = xmalloc(cursor + 1); memcpy(line, lf->buffer, cursor); line[cursor] = '\0'; argv = makeargv(line, &carg, 1, "e, &terminated); free(line); /* Get all the arguments on the line */ len = lf->lastchar - lf->buffer; - line = (char *)xmalloc(len + 1); + line = xmalloc(len + 1); memcpy(line, lf->buffer, len); line[len] = '\0'; argv = makeargv(line, &argc, 1, NULL, NULL); /* Ensure cursor is at EOL or a argument boundary */ if (line[cursor] != ' ' && line[cursor] != '\0' && line[cursor] != '\n') { free(line); return ret; } if (carg == 0) { /* Show all available commands */ complete_cmd_parse(el, NULL, argc == carg, '\0', 1); ret = CC_REDISPLAY; } else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ') { /* Handle the command parsing */ if (complete_cmd_parse(el, argv[0], argc == carg, quote, terminated) != 0) ret = CC_REDISPLAY; } else if (carg >= 1) { /* Handle file parsing */ int remote = complete_is_remote(argv[0]); char *filematch = NULL; if (carg > 1 && line[cursor-1] != ' ') filematch = argv[carg - 1]; if (remote != 0 && complete_match(el, complete_ctx->conn, *complete_ctx->remote_pathp, filematch, remote, carg == argc, quote, terminated) != 0) ret = CC_REDISPLAY; } free(line); return ret; } #endif /* USE_LIBEDIT */ int interactive_loop(struct sftp_conn *conn, char *file1, char *file2) { char *remote_path; char *dir = NULL; char cmd[2048]; int err, interactive; EditLine *el = NULL; #ifdef USE_LIBEDIT History *hl = NULL; HistEvent hev; extern char *__progname; struct complete_ctx complete_ctx; if (!batchmode && isatty(STDIN_FILENO)) { if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL) fatal("Couldn't initialise editline"); if ((hl = history_init()) == NULL) fatal("Couldn't initialise editline history"); history(hl, &hev, H_SETSIZE, 100); el_set(el, EL_HIST, history, hl); el_set(el, EL_PROMPT, prompt); el_set(el, EL_EDITOR, "emacs"); el_set(el, EL_TERMINAL, NULL); el_set(el, EL_SIGNAL, 1); el_source(el, NULL); /* Tab Completion */ el_set(el, EL_ADDFN, "ftp-complete", "Context sensitive argument completion", complete); complete_ctx.conn = conn; complete_ctx.remote_pathp = &remote_path; el_set(el, EL_CLIENTDATA, (void*)&complete_ctx); el_set(el, EL_BIND, "^I", "ftp-complete", NULL); /* enable ctrl-left-arrow and ctrl-right-arrow */ el_set(el, EL_BIND, "\\e[1;5C", "em-next-word", NULL); el_set(el, EL_BIND, "\\e[5C", "em-next-word", NULL); el_set(el, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL); el_set(el, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL); /* make ^w match ksh behaviour */ el_set(el, EL_BIND, "^w", "ed-delete-prev-word", NULL); } #endif /* USE_LIBEDIT */ remote_path = do_realpath(conn, "."); if (remote_path == NULL) fatal("Need cwd"); if (file1 != NULL) { dir = xstrdup(file1); dir = make_absolute(dir, remote_path); if (remote_is_dir(conn, dir) && file2 == NULL) { if (!quiet) printf("Changing to: %s\n", dir); snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); if (parse_dispatch_command(conn, cmd, &remote_path, 1) != 0) { free(dir); free(remote_path); free(conn); return (-1); } } else { /* XXX this is wrong wrt quoting */ snprintf(cmd, sizeof cmd, "get%s %s%s%s", global_aflag ? " -a" : "", dir, file2 == NULL ? "" : " ", file2 == NULL ? "" : file2); err = parse_dispatch_command(conn, cmd, &remote_path, 1); free(dir); free(remote_path); free(conn); return (err); } free(dir); } setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(infile, NULL, _IOLBF, 0); interactive = !batchmode && isatty(STDIN_FILENO); err = 0; for (;;) { char *cp; signal(SIGINT, SIG_IGN); if (el == NULL) { if (interactive) printf("sftp> "); if (fgets(cmd, sizeof(cmd), infile) == NULL) { if (interactive) printf("\n"); break; } if (!interactive) { /* Echo command */ printf("sftp> %s", cmd); if (strlen(cmd) > 0 && cmd[strlen(cmd) - 1] != '\n') printf("\n"); } } else { #ifdef USE_LIBEDIT const char *line; int count = 0; if ((line = el_gets(el, &count)) == NULL || count <= 0) { printf("\n"); break; } history(hl, &hev, H_ENTER, line); if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) { fprintf(stderr, "Error: input line too long\n"); continue; } #endif /* USE_LIBEDIT */ } cp = strrchr(cmd, '\n'); if (cp) *cp = '\0'; /* Handle user interrupts gracefully during commands */ interrupted = 0; signal(SIGINT, cmd_interrupt); err = parse_dispatch_command(conn, cmd, &remote_path, batchmode); if (err != 0) break; } free(remote_path); free(conn); #ifdef USE_LIBEDIT if (el != NULL) el_end(el); #endif /* USE_LIBEDIT */ /* err == 1 signifies normal "quit" exit */ return (err >= 0 ? 0 : -1); } static void connect_to_server(char *path, char **args, int *in, int *out) { int c_in, c_out; #ifdef USE_PIPES int pin[2], pout[2]; if ((pipe(pin) == -1) || (pipe(pout) == -1)) fatal("pipe: %s", strerror(errno)); *in = pin[0]; *out = pout[1]; c_in = pout[0]; c_out = pin[1]; #else /* USE_PIPES */ int inout[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) fatal("socketpair: %s", strerror(errno)); *in = *out = inout[0]; c_in = c_out = inout[1]; #endif /* USE_PIPES */ if ((sshpid = fork()) == -1) fatal("fork: %s", strerror(errno)); else if (sshpid == 0) { if ((dup2(c_in, STDIN_FILENO) == -1) || (dup2(c_out, STDOUT_FILENO) == -1)) { fprintf(stderr, "dup2: %s\n", strerror(errno)); _exit(1); } close(*in); close(*out); close(c_in); close(c_out); /* * The underlying ssh is in the same process group, so we must * ignore SIGINT if we want to gracefully abort commands, * otherwise the signal will make it to the ssh process and * kill it too. Contrawise, since sftp sends SIGTERMs to the * underlying ssh, it must *not* ignore that signal. */ signal(SIGINT, SIG_IGN); signal(SIGTERM, SIG_DFL); execvp(path, args); fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); _exit(1); } signal(SIGTERM, killchild); signal(SIGINT, killchild); signal(SIGHUP, killchild); close(c_in); close(c_out); } static void usage(void) { extern char *__progname; fprintf(stderr, "usage: %s [-1246aCfpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n" " [-D sftp_server_path] [-F ssh_config] " "[-i identity_file] [-l limit]\n" " [-o ssh_option] [-P port] [-R num_requests] " "[-S program]\n" " [-s subsystem | sftp_server] host\n" " %s [user@]host[:file ...]\n" " %s [user@]host[:dir[/]]\n" " %s -b batchfile [user@]host\n", __progname, __progname, __progname, __progname); exit(1); } int main(int argc, char **argv) { int in, out, ch, err; char *host = NULL, *userhost, *cp, *file2 = NULL; int debug_level = 0, sshver = 2; char *file1 = NULL, *sftp_server = NULL; char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; const char *errstr; LogLevel ll = SYSLOG_LEVEL_INFO; arglist args; extern int optind; extern char *optarg; struct sftp_conn *conn; size_t copy_buffer_len = DEFAULT_COPY_BUFLEN; size_t num_requests = DEFAULT_NUM_REQUESTS; long long limit_kbps = 0; /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); setlocale(LC_CTYPE, ""); __progname = ssh_get_progname(argv[0]); memset(&args, '\0', sizeof(args)); args.list = NULL; addargs(&args, "%s", ssh_program); addargs(&args, "-oForwardX11 no"); addargs(&args, "-oForwardAgent no"); addargs(&args, "-oPermitLocalCommand no"); addargs(&args, "-oClearAllForwardings yes"); ll = SYSLOG_LEVEL_INFO; infile = stdin; while ((ch = getopt(argc, argv, "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { switch (ch) { /* Passed through to ssh(1) */ case '4': case '6': case 'C': addargs(&args, "-%c", ch); break; /* Passed through to ssh(1) with argument */ case 'F': case 'c': case 'i': case 'o': addargs(&args, "-%c", ch); addargs(&args, "%s", optarg); break; case 'q': ll = SYSLOG_LEVEL_ERROR; quiet = 1; showprogress = 0; addargs(&args, "-%c", ch); break; case 'P': addargs(&args, "-oPort %s", optarg); break; case 'v': if (debug_level < 3) { addargs(&args, "-v"); ll = SYSLOG_LEVEL_DEBUG1 + debug_level; } debug_level++; break; case '1': sshver = 1; if (sftp_server == NULL) sftp_server = _PATH_SFTP_SERVER; break; case '2': sshver = 2; break; case 'a': global_aflag = 1; break; case 'B': copy_buffer_len = strtol(optarg, &cp, 10); if (copy_buffer_len == 0 || *cp != '\0') fatal("Invalid buffer size \"%s\"", optarg); break; case 'b': if (batchmode) fatal("Batch file already specified."); /* Allow "-" as stdin */ if (strcmp(optarg, "-") != 0 && (infile = fopen(optarg, "r")) == NULL) fatal("%s (%s).", strerror(errno), optarg); showprogress = 0; quiet = batchmode = 1; addargs(&args, "-obatchmode yes"); break; case 'f': global_fflag = 1; break; case 'p': global_pflag = 1; break; case 'D': sftp_direct = optarg; break; case 'l': limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024, &errstr); if (errstr != NULL) usage(); limit_kbps *= 1024; /* kbps */ break; case 'r': global_rflag = 1; break; case 'R': num_requests = strtol(optarg, &cp, 10); if (num_requests == 0 || *cp != '\0') fatal("Invalid number of requests \"%s\"", optarg); break; case 's': sftp_server = optarg; break; case 'S': ssh_program = optarg; replacearg(&args, 0, "%s", ssh_program); break; case 'h': default: usage(); } } if (!isatty(STDERR_FILENO)) showprogress = 0; log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); if (sftp_direct == NULL) { if (optind == argc || argc > (optind + 2)) usage(); userhost = xstrdup(argv[optind]); file2 = argv[optind+1]; if ((host = strrchr(userhost, '@')) == NULL) host = userhost; else { *host++ = '\0'; if (!userhost[0]) { fprintf(stderr, "Missing username\n"); usage(); } addargs(&args, "-l"); addargs(&args, "%s", userhost); } if ((cp = colon(host)) != NULL) { *cp++ = '\0'; file1 = cp; } host = cleanhostname(host); if (!*host) { fprintf(stderr, "Missing hostname\n"); usage(); } addargs(&args, "-oProtocol %d", sshver); /* no subsystem if the server-spec contains a '/' */ if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) addargs(&args, "-s"); addargs(&args, "--"); addargs(&args, "%s", host); addargs(&args, "%s", (sftp_server != NULL ? sftp_server : "sftp")); connect_to_server(ssh_program, args.list, &in, &out); } else { args.list = NULL; addargs(&args, "sftp-server"); connect_to_server(sftp_direct, args.list, &in, &out); } freeargs(&args); conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps); if (conn == NULL) fatal("Couldn't initialise connection to server"); if (!quiet) { if (sftp_direct == NULL) fprintf(stderr, "Connected to %s.\n", host); else fprintf(stderr, "Attached to %s.\n", sftp_direct); } err = interactive_loop(conn, file1, file2); #if !defined(USE_PIPES) shutdown(in, SHUT_RDWR); shutdown(out, SHUT_RDWR); #endif close(in); close(out); if (batchmode) fclose(infile); while (waitpid(sshpid, NULL, 0) == -1) if (errno != EINTR) fatal("Couldn't wait for ssh process: %s", strerror(errno)); exit(err == 0 ? 0 : 1); } Index: head/crypto/openssh/ssh-keygen.1 =================================================================== --- head/crypto/openssh/ssh-keygen.1 (revision 294495) +++ head/crypto/openssh/ssh-keygen.1 (revision 294496) @@ -1,864 +1,864 @@ -.\" $OpenBSD: ssh-keygen.1,v 1.126 2015/07/03 03:49:45 djm Exp $ +.\" $OpenBSD: ssh-keygen.1,v 1.127 2015/08/20 19:20:06 naddy Exp $ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland .\" All rights reserved .\" .\" As far as I am concerned, the code I have written for this software .\" can be used freely for any purpose. Any derived versions of this .\" software must be clearly marked as such, and if the derived work is .\" incompatible with the protocol description in the RFC file, it must be .\" called by a name other than "ssh" or "Secure Shell". .\" .\" .\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. .\" Copyright (c) 1999 Aaron Campbell. All rights reserved. .\" Copyright (c) 1999 Theo de Raadt. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: July 3 2015 $ +.Dd $Mdocdate: August 20 2015 $ .Dt SSH-KEYGEN 1 .Os .Sh NAME .Nm ssh-keygen .Nd authentication key generation, management and conversion .Sh SYNOPSIS .Bk -words .Nm ssh-keygen .Op Fl q .Op Fl b Ar bits .Op Fl t Cm dsa | ecdsa | ed25519 | rsa | rsa1 .Op Fl N Ar new_passphrase .Op Fl C Ar comment .Op Fl f Ar output_keyfile .Nm ssh-keygen .Fl p .Op Fl P Ar old_passphrase .Op Fl N Ar new_passphrase .Op Fl f Ar keyfile .Nm ssh-keygen .Fl i .Op Fl m Ar key_format .Op Fl f Ar input_keyfile .Nm ssh-keygen .Fl e .Op Fl m Ar key_format .Op Fl f Ar input_keyfile .Nm ssh-keygen .Fl y .Op Fl f Ar input_keyfile .Nm ssh-keygen .Fl c .Op Fl P Ar passphrase .Op Fl C Ar comment .Op Fl f Ar keyfile .Nm ssh-keygen .Fl l .Op Fl v .Op Fl E Ar fingerprint_hash .Op Fl f Ar input_keyfile .Nm ssh-keygen .Fl B .Op Fl f Ar input_keyfile .Nm ssh-keygen .Fl D Ar pkcs11 .Nm ssh-keygen .Fl F Ar hostname .Op Fl f Ar known_hosts_file .Op Fl l .Nm ssh-keygen .Fl H .Op Fl f Ar known_hosts_file .Nm ssh-keygen .Fl R Ar hostname .Op Fl f Ar known_hosts_file .Nm ssh-keygen .Fl r Ar hostname .Op Fl f Ar input_keyfile .Op Fl g .Nm ssh-keygen .Fl G Ar output_file .Op Fl v .Op Fl b Ar bits .Op Fl M Ar memory .Op Fl S Ar start_point .Nm ssh-keygen .Fl T Ar output_file .Fl f Ar input_file .Op Fl v .Op Fl a Ar rounds .Op Fl J Ar num_lines .Op Fl j Ar start_line .Op Fl K Ar checkpt .Op Fl W Ar generator .Nm ssh-keygen .Fl s Ar ca_key .Fl I Ar certificate_identity .Op Fl h .Op Fl n Ar principals .Op Fl O Ar option .Op Fl V Ar validity_interval .Op Fl z Ar serial_number .Ar .Nm ssh-keygen .Fl L .Op Fl f Ar input_keyfile .Nm ssh-keygen .Fl A .Nm ssh-keygen .Fl k .Fl f Ar krl_file .Op Fl u .Op Fl s Ar ca_public .Op Fl z Ar version_number .Ar .Nm ssh-keygen .Fl Q .Fl f Ar krl_file .Ar .Ek .Sh DESCRIPTION .Nm generates, manages and converts authentication keys for .Xr ssh 1 . .Nm can create RSA keys for use by SSH protocol version 1 and DSA, ECDSA, Ed25519 or RSA keys for use by SSH protocol version 2. The type of key to be generated is specified with the .Fl t option. If invoked without any arguments, .Nm will generate an RSA key for use in SSH protocol 2 connections. .Pp .Nm is also used to generate groups for use in Diffie-Hellman group exchange (DH-GEX). See the .Sx MODULI GENERATION section for details. .Pp Finally, .Nm can be used to generate and update Key Revocation Lists, and to test whether given keys have been revoked by one. See the .Sx KEY REVOCATION LISTS section for details. .Pp Normally each user wishing to use SSH with public key authentication runs this once to create the authentication key in .Pa ~/.ssh/identity , .Pa ~/.ssh/id_dsa , .Pa ~/.ssh/id_ecdsa , .Pa ~/.ssh/id_ed25519 or .Pa ~/.ssh/id_rsa . Additionally, the system administrator may use this to generate host keys, as seen in .Pa /etc/rc . .Pp Normally this program generates the key and asks for a file in which to store the private key. The public key is stored in a file with the same name but .Dq .pub appended. The program also asks for a passphrase. The passphrase may be empty to indicate no passphrase (host keys must have an empty passphrase), or it may be a string of arbitrary length. A passphrase is similar to a password, except it can be a phrase with a series of words, punctuation, numbers, whitespace, or any string of characters you want. Good passphrases are 10-30 characters long, are not simple sentences or otherwise easily guessable (English prose has only 1-2 bits of entropy per character, and provides very bad passphrases), and contain a mix of upper and lowercase letters, numbers, and non-alphanumeric characters. The passphrase can be changed later by using the .Fl p option. .Pp There is no way to recover a lost passphrase. If the passphrase is lost or forgotten, a new key must be generated and the corresponding public key copied to other machines. .Pp For RSA1 keys, there is also a comment field in the key file that is only for convenience to the user to help identify the key. The comment can tell what the key is for, or whatever is useful. The comment is initialized to .Dq user@host when the key is created, but can be changed using the .Fl c option. .Pp After a key is generated, instructions below detail where the keys should be placed to be activated. .Pp The options are as follows: .Bl -tag -width Ds .It Fl A For each of the key types (rsa1, rsa, dsa, ecdsa and ed25519) for which host keys do not exist, generate the host keys with the default key file path, an empty passphrase, default bits for the key type, and default comment. This is used by .Pa /etc/rc to generate new host keys. .It Fl a Ar rounds When saving a new-format private key (i.e. an ed25519 key or any SSH protocol 2 key when the .Fl o flag is set), this option specifies the number of KDF (key derivation function) rounds used. Higher numbers result in slower passphrase verification and increased resistance to brute-force password cracking (should the keys be stolen). .Pp When screening DH-GEX candidates ( using the .Fl T command). This option specifies the number of primality tests to perform. .It Fl B Show the bubblebabble digest of specified private or public key file. .It Fl b Ar bits Specifies the number of bits in the key to create. For RSA keys, the minimum size is 1024 bits and the default is 2048 bits. Generally, 2048 bits is considered sufficient. DSA keys must be exactly 1024 bits as specified by FIPS 186-2. For ECDSA keys, the .Fl b flag determines the key length by selecting from one of three elliptic curve sizes: 256, 384 or 521 bits. Attempting to use bit lengths other than these three values for ECDSA keys will fail. Ed25519 keys have a fixed length and the .Fl b flag will be ignored. .It Fl C Ar comment Provides a new comment. .It Fl c Requests changing the comment in the private and public key files. This operation is only supported for RSA1 keys. The program will prompt for the file containing the private keys, for the passphrase if the key has one, and for the new comment. .It Fl D Ar pkcs11 Download the RSA public keys provided by the PKCS#11 shared library .Ar pkcs11 . When used in combination with .Fl s , this option indicates that a CA key resides in a PKCS#11 token (see the .Sx CERTIFICATES section for details). .It Fl E Ar fingerprint_hash Specifies the hash algorithm used when displaying key fingerprints. Valid options are: .Dq md5 and .Dq sha256 . The default is .Dq sha256 . .It Fl e This option will read a private or public OpenSSH key file and print to stdout the key in one of the formats specified by the .Fl m option. The default export format is .Dq RFC4716 . This option allows exporting OpenSSH keys for use by other programs, including several commercial SSH implementations. .It Fl F Ar hostname Search for the specified .Ar hostname in a .Pa known_hosts file, listing any occurrences found. This option is useful to find hashed host names or addresses and may also be used in conjunction with the .Fl H option to print found keys in a hashed format. .It Fl f Ar filename Specifies the filename of the key file. .It Fl G Ar output_file Generate candidate primes for DH-GEX. These primes must be screened for safety (using the .Fl T option) before use. .It Fl g Use generic DNS format when printing fingerprint resource records using the .Fl r command. .It Fl H Hash a .Pa known_hosts file. This replaces all hostnames and addresses with hashed representations within the specified file; the original content is moved to a file with a .old suffix. These hashes may be used normally by .Nm ssh and .Nm sshd , but they do not reveal identifying information should the file's contents be disclosed. This option will not modify existing hashed hostnames and is therefore safe to use on files that mix hashed and non-hashed names. .It Fl h When signing a key, create a host certificate instead of a user certificate. Please see the .Sx CERTIFICATES section for details. .It Fl I Ar certificate_identity Specify the key identity when signing a public key. Please see the .Sx CERTIFICATES section for details. .It Fl i This option will read an unencrypted private (or public) key file in the format specified by the .Fl m option and print an OpenSSH compatible private (or public) key to stdout. This option allows importing keys from other software, including several commercial SSH implementations. The default import format is .Dq RFC4716 . .It Fl J Ar num_lines Exit after screening the specified number of lines while performing DH candidate screening using the .Fl T option. .It Fl j Ar start_line Start screening at the specified line number while performing DH candidate screening using the .Fl T option. .It Fl K Ar checkpt Write the last line processed to the file .Ar checkpt while performing DH candidate screening using the .Fl T option. This will be used to skip lines in the input file that have already been processed if the job is restarted. .It Fl k Generate a KRL file. In this mode, .Nm will generate a KRL file at the location specified via the .Fl f flag that revokes every key or certificate presented on the command line. Keys/certificates to be revoked may be specified by public key file or using the format described in the .Sx KEY REVOCATION LISTS section. .It Fl L Prints the contents of a certificate. .It Fl l Show fingerprint of specified public key file. Private RSA1 keys are also supported. For RSA and DSA keys .Nm tries to find the matching public key file and prints its fingerprint. If combined with .Fl v , an ASCII art representation of the key is supplied with the fingerprint. .It Fl M Ar memory Specify the amount of memory to use (in megabytes) when generating candidate moduli for DH-GEX. .It Fl m Ar key_format Specify a key format for the .Fl i (import) or .Fl e (export) conversion options. The supported key formats are: .Dq RFC4716 (RFC 4716/SSH2 public or private key), .Dq PKCS8 (PEM PKCS8 public key) or .Dq PEM (PEM public key). The default conversion format is .Dq RFC4716 . .It Fl N Ar new_passphrase Provides the new passphrase. .It Fl n Ar principals Specify one or more principals (user or host names) to be included in a certificate when signing a key. Multiple principals may be specified, separated by commas. Please see the .Sx CERTIFICATES section for details. .It Fl O Ar option Specify a certificate option when signing a key. This option may be specified multiple times. Please see the .Sx CERTIFICATES section for details. The options that are valid for user certificates are: .Bl -tag -width Ds .It Ic clear Clear all enabled permissions. This is useful for clearing the default set of permissions so permissions may be added individually. .It Ic force-command Ns = Ns Ar command Forces the execution of .Ar command instead of any shell or command specified by the user when the certificate is used for authentication. .It Ic no-agent-forwarding Disable .Xr ssh-agent 1 forwarding (permitted by default). .It Ic no-port-forwarding Disable port forwarding (permitted by default). .It Ic no-pty Disable PTY allocation (permitted by default). .It Ic no-user-rc Disable execution of .Pa ~/.ssh/rc by .Xr sshd 8 (permitted by default). .It Ic no-x11-forwarding Disable X11 forwarding (permitted by default). .It Ic permit-agent-forwarding Allows .Xr ssh-agent 1 forwarding. .It Ic permit-port-forwarding Allows port forwarding. .It Ic permit-pty Allows PTY allocation. .It Ic permit-user-rc Allows execution of .Pa ~/.ssh/rc by .Xr sshd 8 . .It Ic permit-x11-forwarding Allows X11 forwarding. .It Ic source-address Ns = Ns Ar address_list Restrict the source addresses from which the certificate is considered valid. The .Ar address_list is a comma-separated list of one or more address/netmask pairs in CIDR format. .El .Pp At present, no options are valid for host keys. .It Fl o Causes .Nm to save SSH protocol 2 private keys using the new OpenSSH format rather than the more compatible PEM format. The new format has increased resistance to brute-force password cracking but is not supported by versions of OpenSSH prior to 6.5. Ed25519 keys always use the new private key format. .It Fl P Ar passphrase Provides the (old) passphrase. .It Fl p Requests changing the passphrase of a private key file instead of creating a new private key. The program will prompt for the file containing the private key, for the old passphrase, and twice for the new passphrase. .It Fl Q Test whether keys have been revoked in a KRL. .It Fl q Silence .Nm ssh-keygen . .It Fl R Ar hostname Removes all keys belonging to .Ar hostname from a .Pa known_hosts file. This option is useful to delete hashed hosts (see the .Fl H option above). .It Fl r Ar hostname Print the SSHFP fingerprint resource record named .Ar hostname for the specified public key file. .It Fl S Ar start Specify start point (in hex) when generating candidate moduli for DH-GEX. .It Fl s Ar ca_key Certify (sign) a public key using the specified CA key. Please see the .Sx CERTIFICATES section for details. .Pp When generating a KRL, .Fl s specifies a path to a CA public key file used to revoke certificates directly by key ID or serial number. See the .Sx KEY REVOCATION LISTS section for details. .It Fl T Ar output_file Test DH group exchange candidate primes (generated using the .Fl G option) for safety. .It Fl t Cm dsa | ecdsa | ed25519 | rsa | rsa1 Specifies the type of key to create. The possible values are .Dq rsa1 for protocol version 1 and .Dq dsa , .Dq ecdsa , .Dq ed25519 , or .Dq rsa for protocol version 2. .It Fl u Update a KRL. When specified with .Fl k , keys listed via the command line are added to the existing KRL rather than a new KRL being created. .It Fl V Ar validity_interval Specify a validity interval when signing a certificate. A validity interval may consist of a single time, indicating that the certificate is valid beginning now and expiring at that time, or may consist of two times separated by a colon to indicate an explicit time interval. The start time may be specified as a date in YYYYMMDD format, a time in YYYYMMDDHHMMSS format or a relative time (to the current time) consisting of a minus sign followed by a relative time in the format described in the TIME FORMATS section of .Xr sshd_config 5 . The end time may be specified as a YYYYMMDD date, a YYYYMMDDHHMMSS time or a relative time starting with a plus character. .Pp For example: .Dq +52w1d (valid from now to 52 weeks and one day from now), .Dq -4w:+4w (valid from four weeks ago to four weeks from now), .Dq 20100101123000:20110101123000 (valid from 12:30 PM, January 1st, 2010 to 12:30 PM, January 1st, 2011), .Dq -1d:20110101 (valid from yesterday to midnight, January 1st, 2011). .It Fl v Verbose mode. Causes .Nm to print debugging messages about its progress. This is helpful for debugging moduli generation. Multiple .Fl v options increase the verbosity. The maximum is 3. .It Fl W Ar generator Specify desired generator when testing candidate moduli for DH-GEX. .It Fl y This option will read a private OpenSSH format file and print an OpenSSH public key to stdout. .It Fl z Ar serial_number Specifies a serial number to be embedded in the certificate to distinguish this certificate from others from the same CA. The default serial number is zero. .Pp When generating a KRL, the .Fl z flag is used to specify a KRL version number. .El .Sh MODULI GENERATION .Nm may be used to generate groups for the Diffie-Hellman Group Exchange (DH-GEX) protocol. Generating these groups is a two-step process: first, candidate primes are generated using a fast, but memory intensive process. These candidate primes are then tested for suitability (a CPU-intensive process). .Pp Generation of primes is performed using the .Fl G option. The desired length of the primes may be specified by the .Fl b option. For example: .Pp .Dl # ssh-keygen -G moduli-2048.candidates -b 2048 .Pp By default, the search for primes begins at a random point in the desired length range. This may be overridden using the .Fl S option, which specifies a different start point (in hex). .Pp Once a set of candidates have been generated, they must be screened for suitability. This may be performed using the .Fl T option. In this mode .Nm will read candidates from standard input (or a file specified using the .Fl f option). For example: .Pp .Dl # ssh-keygen -T moduli-2048 -f moduli-2048.candidates .Pp By default, each candidate will be subjected to 100 primality tests. This may be overridden using the .Fl a option. The DH generator value will be chosen automatically for the prime under consideration. If a specific generator is desired, it may be requested using the .Fl W option. Valid generator values are 2, 3, and 5. .Pp Screened DH groups may be installed in .Pa /etc/moduli . It is important that this file contains moduli of a range of bit lengths and that both ends of a connection share common moduli. .Sh CERTIFICATES .Nm supports signing of keys to produce certificates that may be used for user or host authentication. Certificates consist of a public key, some identity information, zero or more principal (user or host) names and a set of options that are signed by a Certification Authority (CA) key. Clients or servers may then trust only the CA key and verify its signature on a certificate rather than trusting many user/host keys. Note that OpenSSH certificates are a different, and much simpler, format to the X.509 certificates used in .Xr ssl 8 . .Pp .Nm supports two types of certificates: user and host. User certificates authenticate users to servers, whereas host certificates authenticate server hosts to users. To generate a user certificate: .Pp .Dl $ ssh-keygen -s /path/to/ca_key -I key_id /path/to/user_key.pub .Pp The resultant certificate will be placed in .Pa /path/to/user_key-cert.pub . A host certificate requires the .Fl h option: .Pp .Dl $ ssh-keygen -s /path/to/ca_key -I key_id -h /path/to/host_key.pub .Pp The host certificate will be output to .Pa /path/to/host_key-cert.pub . .Pp It is possible to sign using a CA key stored in a PKCS#11 token by providing the token library using .Fl D and identifying the CA key by providing its public half as an argument to .Fl s : .Pp -.Dl $ ssh-keygen -s ca_key.pub -D libpkcs11.so -I key_id host_key.pub +.Dl $ ssh-keygen -s ca_key.pub -D libpkcs11.so -I key_id user_key.pub .Pp In all cases, .Ar key_id is a "key identifier" that is logged by the server when the certificate is used for authentication. .Pp Certificates may be limited to be valid for a set of principal (user/host) names. By default, generated certificates are valid for all users or hosts. To generate a certificate for a specified set of principals: .Pp .Dl $ ssh-keygen -s ca_key -I key_id -n user1,user2 user_key.pub -.Dl "$ ssh-keygen -s ca_key -I key_id -h -n host.domain user_key.pub" +.Dl "$ ssh-keygen -s ca_key -I key_id -h -n host.domain host_key.pub" .Pp Additional limitations on the validity and use of user certificates may be specified through certificate options. A certificate option may disable features of the SSH session, may be valid only when presented from particular source addresses or may force the use of a specific command. For a list of valid certificate options, see the documentation for the .Fl O option above. .Pp Finally, certificates may be defined with a validity lifetime. The .Fl V option allows specification of certificate start and end times. A certificate that is presented at a time outside this range will not be considered valid. By default, certificates are valid from .Ux Epoch to the distant future. .Pp For certificates to be used for user or host authentication, the CA public key must be trusted by .Xr sshd 8 or .Xr ssh 1 . Please refer to those manual pages for details. .Sh KEY REVOCATION LISTS .Nm is able to manage OpenSSH format Key Revocation Lists (KRLs). These binary files specify keys or certificates to be revoked using a compact format, taking as little as one bit per certificate if they are being revoked by serial number. .Pp KRLs may be generated using the .Fl k flag. This option reads one or more files from the command line and generates a new KRL. The files may either contain a KRL specification (see below) or public keys, listed one per line. Plain public keys are revoked by listing their hash or contents in the KRL and certificates revoked by serial number or key ID (if the serial is zero or not available). .Pp Revoking keys using a KRL specification offers explicit control over the types of record used to revoke keys and may be used to directly revoke certificates by serial number or key ID without having the complete original certificate on hand. A KRL specification consists of lines containing one of the following directives followed by a colon and some directive-specific information. .Bl -tag -width Ds .It Cm serial : Ar serial_number Ns Op - Ns Ar serial_number Revokes a certificate with the specified serial number. Serial numbers are 64-bit values, not including zero and may be expressed in decimal, hex or octal. If two serial numbers are specified separated by a hyphen, then the range of serial numbers including and between each is revoked. The CA key must have been specified on the .Nm command line using the .Fl s option. .It Cm id : Ar key_id Revokes a certificate with the specified key ID string. The CA key must have been specified on the .Nm command line using the .Fl s option. .It Cm key : Ar public_key Revokes the specified key. If a certificate is listed, then it is revoked as a plain public key. .It Cm sha1 : Ar public_key Revokes the specified key by its SHA1 hash. .El .Pp KRLs may be updated using the .Fl u flag in addition to .Fl k . When this option is specified, keys listed via the command line are merged into the KRL, adding to those already there. .Pp It is also possible, given a KRL, to test whether it revokes a particular key (or keys). The .Fl Q flag will query an existing KRL, testing each key specified on the commandline. If any key listed on the command line has been revoked (or an error encountered) then .Nm will exit with a non-zero exit status. A zero exit status will only be returned if no key was revoked. .Sh FILES .Bl -tag -width Ds -compact .It Pa ~/.ssh/identity Contains the protocol version 1 RSA authentication identity of the user. This file should not be readable by anyone but the user. It is possible to specify a passphrase when generating the key; that passphrase will be used to encrypt the private part of this file using 3DES. This file is not automatically accessed by .Nm but it is offered as the default file for the private key. .Xr ssh 1 will read this file when a login attempt is made. .Pp .It Pa ~/.ssh/identity.pub Contains the protocol version 1 RSA public key for authentication. The contents of this file should be added to .Pa ~/.ssh/authorized_keys on all machines where the user wishes to log in using RSA authentication. There is no need to keep the contents of this file secret. .Pp .It Pa ~/.ssh/id_dsa .It Pa ~/.ssh/id_ecdsa .It Pa ~/.ssh/id_ed25519 .It Pa ~/.ssh/id_rsa Contains the protocol version 2 DSA, ECDSA, Ed25519 or RSA authentication identity of the user. This file should not be readable by anyone but the user. It is possible to specify a passphrase when generating the key; that passphrase will be used to encrypt the private part of this file using 128-bit AES. This file is not automatically accessed by .Nm but it is offered as the default file for the private key. .Xr ssh 1 will read this file when a login attempt is made. .Pp .It Pa ~/.ssh/id_dsa.pub .It Pa ~/.ssh/id_ecdsa.pub .It Pa ~/.ssh/id_ed25519.pub .It Pa ~/.ssh/id_rsa.pub Contains the protocol version 2 DSA, ECDSA, Ed25519 or RSA public key for authentication. The contents of this file should be added to .Pa ~/.ssh/authorized_keys on all machines where the user wishes to log in using public key authentication. There is no need to keep the contents of this file secret. .Pp .It Pa /etc/moduli Contains Diffie-Hellman groups used for DH-GEX. The file format is described in .Xr moduli 5 . .El .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-add 1 , .Xr ssh-agent 1 , .Xr moduli 5 , .Xr sshd 8 .Rs .%R RFC 4716 .%T "The Secure Shell (SSH) Public Key File Format" .%D 2006 .Re .Sh AUTHORS OpenSSH is a derivative of the original and free ssh 1.2.12 release by Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo de Raadt and Dug Song removed many bugs, re-added newer features and created OpenSSH. Markus Friedl contributed the support for SSH protocol versions 1.5 and 2.0. Index: head/crypto/openssh/ssh-keygen.c =================================================================== --- head/crypto/openssh/ssh-keygen.c (revision 294495) +++ head/crypto/openssh/ssh-keygen.c (revision 294496) @@ -1,2687 +1,2688 @@ -/* $OpenBSD: ssh-keygen.c,v 1.276 2015/07/03 03:49:45 djm Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.277 2015/08/19 23:17:51 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland * All rights reserved * Identity and host key generation and maintenance. * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose. Any derived versions of this * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". */ #include "includes.h" #include #include #include #ifdef WITH_OPENSSL #include #include #include "openbsd-compat/openssl-compat.h" #endif #include #include #include #ifdef HAVE_PATHS_H # include #endif #include #include #include #include #include #include #include #include "xmalloc.h" #include "sshkey.h" #include "rsa.h" #include "authfile.h" #include "uuencode.h" #include "sshbuf.h" #include "pathnames.h" #include "log.h" #include "misc.h" #include "match.h" #include "hostfile.h" #include "dns.h" #include "ssh.h" #include "ssh2.h" #include "ssherr.h" #include "ssh-pkcs11.h" #include "atomicio.h" #include "krl.h" #include "digest.h" #ifdef WITH_OPENSSL # define DEFAULT_KEY_TYPE_NAME "rsa" #else # define DEFAULT_KEY_TYPE_NAME "ed25519" #endif /* Number of bits in the RSA/DSA key. This value can be set on the command line. */ #define DEFAULT_BITS 2048 #define DEFAULT_BITS_DSA 1024 #define DEFAULT_BITS_ECDSA 256 u_int32_t bits = 0; /* * Flag indicating that we just want to change the passphrase. This can be * set on the command line. */ int change_passphrase = 0; /* * Flag indicating that we just want to change the comment. This can be set * on the command line. */ int change_comment = 0; int quiet = 0; int log_level = SYSLOG_LEVEL_INFO; /* Flag indicating that we want to hash a known_hosts file */ int hash_hosts = 0; /* Flag indicating that we want lookup a host in known_hosts file */ int find_host = 0; /* Flag indicating that we want to delete a host from a known_hosts file */ int delete_host = 0; /* Flag indicating that we want to show the contents of a certificate */ int show_cert = 0; /* Flag indicating that we just want to see the key fingerprint */ int print_fingerprint = 0; int print_bubblebabble = 0; /* Hash algorithm to use for fingerprints. */ int fingerprint_hash = SSH_FP_HASH_DEFAULT; /* The identity file name, given on the command line or entered by the user. */ char identity_file[1024]; int have_identity = 0; /* This is set to the passphrase if given on the command line. */ char *identity_passphrase = NULL; /* This is set to the new passphrase if given on the command line. */ char *identity_new_passphrase = NULL; /* This is set to the new comment if given on the command line. */ char *identity_comment = NULL; /* Path to CA key when certifying keys. */ char *ca_key_path = NULL; /* Certificate serial number */ unsigned long long cert_serial = 0; /* Key type when certifying */ u_int cert_key_type = SSH2_CERT_TYPE_USER; /* "key ID" of signed key */ char *cert_key_id = NULL; /* Comma-separated list of principal names for certifying keys */ char *cert_principals = NULL; /* Validity period for certificates */ u_int64_t cert_valid_from = 0; u_int64_t cert_valid_to = ~0ULL; /* Certificate options */ #define CERTOPT_X_FWD (1) #define CERTOPT_AGENT_FWD (1<<1) #define CERTOPT_PORT_FWD (1<<2) #define CERTOPT_PTY (1<<3) #define CERTOPT_USER_RC (1<<4) #define CERTOPT_DEFAULT (CERTOPT_X_FWD|CERTOPT_AGENT_FWD| \ CERTOPT_PORT_FWD|CERTOPT_PTY|CERTOPT_USER_RC) u_int32_t certflags_flags = CERTOPT_DEFAULT; char *certflags_command = NULL; char *certflags_src_addr = NULL; /* Conversion to/from various formats */ int convert_to = 0; int convert_from = 0; enum { FMT_RFC4716, FMT_PKCS8, FMT_PEM } convert_format = FMT_RFC4716; int print_public = 0; int print_generic = 0; char *key_type_name = NULL; /* Load key from this PKCS#11 provider */ char *pkcs11provider = NULL; /* Use new OpenSSH private key format when writing SSH2 keys instead of PEM */ int use_new_format = 0; /* Cipher for new-format private keys */ char *new_format_cipher = NULL; /* * Number of KDF rounds to derive new format keys / * number of primality trials when screening moduli. */ int rounds = 0; /* argv0 */ extern char *__progname; char hostname[NI_MAXHOST]; #ifdef WITH_OPENSSL /* moduli.c */ int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *); int prime_test(FILE *, FILE *, u_int32_t, u_int32_t, char *, unsigned long, unsigned long); #endif static void type_bits_valid(int type, const char *name, u_int32_t *bitsp) { #ifdef WITH_OPENSSL u_int maxbits, nid; #endif if (type == KEY_UNSPEC) fatal("unknown key type %s", key_type_name); if (*bitsp == 0) { #ifdef WITH_OPENSSL if (type == KEY_DSA) *bitsp = DEFAULT_BITS_DSA; else if (type == KEY_ECDSA) { if (name != NULL && (nid = sshkey_ecdsa_nid_from_name(name)) > 0) *bitsp = sshkey_curve_nid_to_bits(nid); if (*bitsp == 0) *bitsp = DEFAULT_BITS_ECDSA; } else #endif *bitsp = DEFAULT_BITS; } #ifdef WITH_OPENSSL maxbits = (type == KEY_DSA) ? OPENSSL_DSA_MAX_MODULUS_BITS : OPENSSL_RSA_MAX_MODULUS_BITS; if (*bitsp > maxbits) fatal("key bits exceeds maximum %d", maxbits); if (type == KEY_DSA && *bitsp != 1024) fatal("DSA keys must be 1024 bits"); else if (type != KEY_ECDSA && type != KEY_ED25519 && *bitsp < 1024) fatal("Key must at least be 1024 bits"); else if (type == KEY_ECDSA && sshkey_ecdsa_bits_to_nid(*bitsp) == -1) fatal("Invalid ECDSA key length - valid lengths are " "256, 384 or 521 bits"); #endif } static void ask_filename(struct passwd *pw, const char *prompt) { char buf[1024]; char *name = NULL; if (key_type_name == NULL) name = _PATH_SSH_CLIENT_ID_RSA; else { switch (sshkey_type_from_name(key_type_name)) { case KEY_RSA1: name = _PATH_SSH_CLIENT_IDENTITY; break; case KEY_DSA_CERT: case KEY_DSA: name = _PATH_SSH_CLIENT_ID_DSA; break; #ifdef OPENSSL_HAS_ECC case KEY_ECDSA_CERT: case KEY_ECDSA: name = _PATH_SSH_CLIENT_ID_ECDSA; break; #endif case KEY_RSA_CERT: case KEY_RSA: name = _PATH_SSH_CLIENT_ID_RSA; break; case KEY_ED25519: case KEY_ED25519_CERT: name = _PATH_SSH_CLIENT_ID_ED25519; break; default: fatal("bad key type"); } } snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name); printf("%s (%s): ", prompt, identity_file); fflush(stdout); if (fgets(buf, sizeof(buf), stdin) == NULL) exit(1); buf[strcspn(buf, "\n")] = '\0'; if (strcmp(buf, "") != 0) strlcpy(identity_file, buf, sizeof(identity_file)); have_identity = 1; } static struct sshkey * load_identity(char *filename) { char *pass; struct sshkey *prv; int r; if ((r = sshkey_load_private(filename, "", &prv, NULL)) == 0) return prv; if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) fatal("Load key \"%s\": %s", filename, ssh_err(r)); if (identity_passphrase) pass = xstrdup(identity_passphrase); else pass = read_passphrase("Enter passphrase: ", RP_ALLOW_STDIN); r = sshkey_load_private(filename, pass, &prv, NULL); explicit_bzero(pass, strlen(pass)); free(pass); if (r != 0) fatal("Load key \"%s\": %s", filename, ssh_err(r)); return prv; } #define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----" #define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----" #define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----" #define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb #ifdef WITH_OPENSSL static void do_convert_to_ssh2(struct passwd *pw, struct sshkey *k) { size_t len; u_char *blob; char comment[61]; int r; if (k->type == KEY_RSA1) fatal("version 1 keys are not supported"); if ((r = sshkey_to_blob(k, &blob, &len)) != 0) fatal("key_to_blob failed: %s", ssh_err(r)); /* Comment + surrounds must fit into 72 chars (RFC 4716 sec 3.3) */ snprintf(comment, sizeof(comment), "%u-bit %s, converted by %s@%s from OpenSSH", sshkey_size(k), sshkey_type(k), pw->pw_name, hostname); fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); fprintf(stdout, "Comment: \"%s\"\n", comment); dump_base64(stdout, blob, len); fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); sshkey_free(k); free(blob); exit(0); } static void do_convert_to_pkcs8(struct sshkey *k) { switch (sshkey_type_plain(k->type)) { case KEY_RSA1: case KEY_RSA: if (!PEM_write_RSA_PUBKEY(stdout, k->rsa)) fatal("PEM_write_RSA_PUBKEY failed"); break; case KEY_DSA: if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) fatal("PEM_write_DSA_PUBKEY failed"); break; #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa)) fatal("PEM_write_EC_PUBKEY failed"); break; #endif default: fatal("%s: unsupported key type %s", __func__, sshkey_type(k)); } exit(0); } static void do_convert_to_pem(struct sshkey *k) { switch (sshkey_type_plain(k->type)) { case KEY_RSA1: case KEY_RSA: if (!PEM_write_RSAPublicKey(stdout, k->rsa)) fatal("PEM_write_RSAPublicKey failed"); break; #if notyet /* OpenSSH 0.9.8 lacks this function */ case KEY_DSA: if (!PEM_write_DSAPublicKey(stdout, k->dsa)) fatal("PEM_write_DSAPublicKey failed"); break; #endif /* XXX ECDSA? */ default: fatal("%s: unsupported key type %s", __func__, sshkey_type(k)); } exit(0); } static void do_convert_to(struct passwd *pw) { struct sshkey *k; struct stat st; int r; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); if ((r = sshkey_load_public(identity_file, &k, NULL)) != 0) k = load_identity(identity_file); switch (convert_format) { case FMT_RFC4716: do_convert_to_ssh2(pw, k); break; case FMT_PKCS8: do_convert_to_pkcs8(k); break; case FMT_PEM: do_convert_to_pem(k); break; default: fatal("%s: unknown key format %d", __func__, convert_format); } exit(0); } /* * This is almost exactly the bignum1 encoding, but with 32 bit for length * instead of 16. */ static void buffer_get_bignum_bits(struct sshbuf *b, BIGNUM *value) { u_int bytes, bignum_bits; int r; if ((r = sshbuf_get_u32(b, &bignum_bits)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); bytes = (bignum_bits + 7) / 8; if (sshbuf_len(b) < bytes) fatal("%s: input buffer too small: need %d have %zu", __func__, bytes, sshbuf_len(b)); if (BN_bin2bn(sshbuf_ptr(b), bytes, value) == NULL) fatal("%s: BN_bin2bn failed", __func__); if ((r = sshbuf_consume(b, bytes)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); } static struct sshkey * do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) { struct sshbuf *b; struct sshkey *key = NULL; char *type, *cipher; u_char e1, e2, e3, *sig = NULL, data[] = "abcde12345"; int r, rlen, ktype; u_int magic, i1, i2, i3, i4; size_t slen; u_long e; if ((b = sshbuf_from(blob, blen)) == NULL) fatal("%s: sshbuf_from failed", __func__); if ((r = sshbuf_get_u32(b, &magic)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (magic != SSH_COM_PRIVATE_KEY_MAGIC) { error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC); sshbuf_free(b); return NULL; } if ((r = sshbuf_get_u32(b, &i1)) != 0 || (r = sshbuf_get_cstring(b, &type, NULL)) != 0 || (r = sshbuf_get_cstring(b, &cipher, NULL)) != 0 || (r = sshbuf_get_u32(b, &i2)) != 0 || (r = sshbuf_get_u32(b, &i3)) != 0 || (r = sshbuf_get_u32(b, &i4)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug("ignore (%d %d %d %d)", i1, i2, i3, i4); if (strcmp(cipher, "none") != 0) { error("unsupported cipher %s", cipher); free(cipher); sshbuf_free(b); free(type); return NULL; } free(cipher); if (strstr(type, "dsa")) { ktype = KEY_DSA; } else if (strstr(type, "rsa")) { ktype = KEY_RSA; } else { sshbuf_free(b); free(type); return NULL; } if ((key = sshkey_new_private(ktype)) == NULL) fatal("key_new_private failed"); free(type); switch (key->type) { case KEY_DSA: buffer_get_bignum_bits(b, key->dsa->p); buffer_get_bignum_bits(b, key->dsa->g); buffer_get_bignum_bits(b, key->dsa->q); buffer_get_bignum_bits(b, key->dsa->pub_key); buffer_get_bignum_bits(b, key->dsa->priv_key); break; case KEY_RSA: if ((r = sshbuf_get_u8(b, &e1)) != 0 || (e1 < 30 && (r = sshbuf_get_u8(b, &e2)) != 0) || (e1 < 30 && (r = sshbuf_get_u8(b, &e3)) != 0)) fatal("%s: buffer error: %s", __func__, ssh_err(r)); e = e1; debug("e %lx", e); if (e < 30) { e <<= 8; e += e2; debug("e %lx", e); e <<= 8; e += e3; debug("e %lx", e); } if (!BN_set_word(key->rsa->e, e)) { sshbuf_free(b); sshkey_free(key); return NULL; } buffer_get_bignum_bits(b, key->rsa->d); buffer_get_bignum_bits(b, key->rsa->n); buffer_get_bignum_bits(b, key->rsa->iqmp); buffer_get_bignum_bits(b, key->rsa->q); buffer_get_bignum_bits(b, key->rsa->p); if ((r = rsa_generate_additional_parameters(key->rsa)) != 0) fatal("generate RSA parameters failed: %s", ssh_err(r)); break; } rlen = sshbuf_len(b); if (rlen != 0) error("do_convert_private_ssh2_from_blob: " "remaining bytes in key blob %d", rlen); sshbuf_free(b); /* try the key */ if (sshkey_sign(key, &sig, &slen, data, sizeof(data), 0) != 0 || sshkey_verify(key, sig, slen, data, sizeof(data), 0) != 0) { sshkey_free(key); free(sig); return NULL; } free(sig); return key; } static int get_line(FILE *fp, char *line, size_t len) { int c; size_t pos = 0; line[0] = '\0'; while ((c = fgetc(fp)) != EOF) { if (pos >= len - 1) fatal("input line too long."); switch (c) { case '\r': c = fgetc(fp); if (c != EOF && c != '\n' && ungetc(c, fp) == EOF) fatal("unget: %s", strerror(errno)); return pos; case '\n': return pos; } line[pos++] = c; line[pos] = '\0'; } /* We reached EOF */ return -1; } static void do_convert_from_ssh2(struct passwd *pw, struct sshkey **k, int *private) { int r, blen, escaped = 0; u_int len; char line[1024]; u_char blob[8096]; char encoded[8096]; FILE *fp; if ((fp = fopen(identity_file, "r")) == NULL) fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); encoded[0] = '\0'; while ((blen = get_line(fp, line, sizeof(line))) != -1) { if (blen > 0 && line[blen - 1] == '\\') escaped++; if (strncmp(line, "----", 4) == 0 || strstr(line, ": ") != NULL) { if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL) *private = 1; if (strstr(line, " END ") != NULL) { break; } /* fprintf(stderr, "ignore: %s", line); */ continue; } if (escaped) { escaped--; /* fprintf(stderr, "escaped: %s", line); */ continue; } strlcat(encoded, line, sizeof(encoded)); } len = strlen(encoded); if (((len % 4) == 3) && (encoded[len-1] == '=') && (encoded[len-2] == '=') && (encoded[len-3] == '=')) encoded[len-3] = '\0'; blen = uudecode(encoded, blob, sizeof(blob)); if (blen < 0) fatal("uudecode failed."); if (*private) *k = do_convert_private_ssh2_from_blob(blob, blen); else if ((r = sshkey_from_blob(blob, blen, k)) != 0) fatal("decode blob failed: %s", ssh_err(r)); fclose(fp); } static void do_convert_from_pkcs8(struct sshkey **k, int *private) { EVP_PKEY *pubkey; FILE *fp; if ((fp = fopen(identity_file, "r")) == NULL) fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); if ((pubkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { fatal("%s: %s is not a recognised public key format", __func__, identity_file); } fclose(fp); switch (EVP_PKEY_type(pubkey->type)) { case EVP_PKEY_RSA: if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) fatal("sshkey_new failed"); (*k)->type = KEY_RSA; (*k)->rsa = EVP_PKEY_get1_RSA(pubkey); break; case EVP_PKEY_DSA: if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) fatal("sshkey_new failed"); (*k)->type = KEY_DSA; (*k)->dsa = EVP_PKEY_get1_DSA(pubkey); break; #ifdef OPENSSL_HAS_ECC case EVP_PKEY_EC: if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) fatal("sshkey_new failed"); (*k)->type = KEY_ECDSA; (*k)->ecdsa = EVP_PKEY_get1_EC_KEY(pubkey); (*k)->ecdsa_nid = sshkey_ecdsa_key_to_nid((*k)->ecdsa); break; #endif default: fatal("%s: unsupported pubkey type %d", __func__, EVP_PKEY_type(pubkey->type)); } EVP_PKEY_free(pubkey); return; } static void do_convert_from_pem(struct sshkey **k, int *private) { FILE *fp; RSA *rsa; #ifdef notyet DSA *dsa; #endif if ((fp = fopen(identity_file, "r")) == NULL) fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); if ((rsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL)) != NULL) { if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) fatal("sshkey_new failed"); (*k)->type = KEY_RSA; (*k)->rsa = rsa; fclose(fp); return; } #if notyet /* OpenSSH 0.9.8 lacks this function */ rewind(fp); if ((dsa = PEM_read_DSAPublicKey(fp, NULL, NULL, NULL)) != NULL) { if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) fatal("sshkey_new failed"); (*k)->type = KEY_DSA; (*k)->dsa = dsa; fclose(fp); return; } /* XXX ECDSA */ #endif fatal("%s: unrecognised raw private key format", __func__); } static void do_convert_from(struct passwd *pw) { struct sshkey *k = NULL; int r, private = 0, ok = 0; struct stat st; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); switch (convert_format) { case FMT_RFC4716: do_convert_from_ssh2(pw, &k, &private); break; case FMT_PKCS8: do_convert_from_pkcs8(&k, &private); break; case FMT_PEM: do_convert_from_pem(&k, &private); break; default: fatal("%s: unknown key format %d", __func__, convert_format); } if (!private) { if ((r = sshkey_write(k, stdout)) == 0) ok = 1; if (ok) fprintf(stdout, "\n"); } else { switch (k->type) { case KEY_DSA: ok = PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL); break; #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: ok = PEM_write_ECPrivateKey(stdout, k->ecdsa, NULL, NULL, 0, NULL, NULL); break; #endif case KEY_RSA: ok = PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL); break; default: fatal("%s: unsupported key type %s", __func__, sshkey_type(k)); } } if (!ok) fatal("key write failed"); sshkey_free(k); exit(0); } #endif static void do_print_public(struct passwd *pw) { struct sshkey *prv; struct stat st; int r; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) fatal("%s: %s", identity_file, strerror(errno)); prv = load_identity(identity_file); if ((r = sshkey_write(prv, stdout)) != 0) error("key_write failed: %s", ssh_err(r)); sshkey_free(prv); fprintf(stdout, "\n"); exit(0); } static void do_download(struct passwd *pw) { #ifdef ENABLE_PKCS11 struct sshkey **keys = NULL; int i, nkeys; enum sshkey_fp_rep rep; int fptype; char *fp, *ra; fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash; rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT; pkcs11_init(0); nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys); if (nkeys <= 0) fatal("cannot read public key from pkcs11"); for (i = 0; i < nkeys; i++) { if (print_fingerprint) { fp = sshkey_fingerprint(keys[i], fptype, rep); ra = sshkey_fingerprint(keys[i], fingerprint_hash, SSH_FP_RANDOMART); if (fp == NULL || ra == NULL) fatal("%s: sshkey_fingerprint fail", __func__); printf("%u %s %s (PKCS11 key)\n", sshkey_size(keys[i]), fp, sshkey_type(keys[i])); if (log_level >= SYSLOG_LEVEL_VERBOSE) printf("%s\n", ra); free(ra); free(fp); } else { (void) sshkey_write(keys[i], stdout); /* XXX check */ fprintf(stdout, "\n"); } sshkey_free(keys[i]); } free(keys); pkcs11_terminate(); exit(0); #else fatal("no pkcs11 support"); #endif /* ENABLE_PKCS11 */ } static void do_fingerprint(struct passwd *pw) { FILE *f; struct sshkey *public; char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra; int r, i, skip = 0, num = 0, invalid = 1; enum sshkey_fp_rep rep; int fptype; struct stat st; fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash; rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) fatal("%s: %s", identity_file, strerror(errno)); if ((r = sshkey_load_public(identity_file, &public, &comment)) != 0) debug2("Error loading public key \"%s\": %s", identity_file, ssh_err(r)); else { fp = sshkey_fingerprint(public, fptype, rep); ra = sshkey_fingerprint(public, fingerprint_hash, SSH_FP_RANDOMART); if (fp == NULL || ra == NULL) fatal("%s: sshkey_fingerprint fail", __func__); printf("%u %s %s (%s)\n", sshkey_size(public), fp, comment, sshkey_type(public)); if (log_level >= SYSLOG_LEVEL_VERBOSE) printf("%s\n", ra); sshkey_free(public); free(comment); free(ra); free(fp); exit(0); } if (comment) { free(comment); comment = NULL; } if ((f = fopen(identity_file, "r")) == NULL) fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); while (fgets(line, sizeof(line), f)) { if ((cp = strchr(line, '\n')) == NULL) { error("line %d too long: %.40s...", num + 1, line); skip = 1; continue; } num++; if (skip) { skip = 0; continue; } *cp = '\0'; /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; i = strtol(cp, &ep, 10); if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { int quoted = 0; comment = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } if (!*cp) continue; *cp++ = '\0'; } ep = cp; if ((public = sshkey_new(KEY_RSA1)) == NULL) fatal("sshkey_new failed"); if ((r = sshkey_read(public, &cp)) != 0) { cp = ep; sshkey_free(public); if ((public = sshkey_new(KEY_UNSPEC)) == NULL) fatal("sshkey_new failed"); if ((r = sshkey_read(public, &cp)) != 0) { sshkey_free(public); continue; } } comment = *cp ? cp : comment; fp = sshkey_fingerprint(public, fptype, rep); ra = sshkey_fingerprint(public, fingerprint_hash, SSH_FP_RANDOMART); if (fp == NULL || ra == NULL) fatal("%s: sshkey_fingerprint fail", __func__); printf("%u %s %s (%s)\n", sshkey_size(public), fp, comment ? comment : "no comment", sshkey_type(public)); if (log_level >= SYSLOG_LEVEL_VERBOSE) printf("%s\n", ra); free(ra); free(fp); sshkey_free(public); invalid = 0; } fclose(f); if (invalid) fatal("%s is not a public key file.", identity_file); exit(0); } static void do_gen_all_hostkeys(struct passwd *pw) { struct { char *key_type; char *key_type_display; char *path; } key_types[] = { #ifdef WITH_OPENSSL #ifdef WITH_SSH1 { "rsa1", "RSA1", _PATH_HOST_KEY_FILE }, #endif /* WITH_SSH1 */ { "rsa", "RSA" ,_PATH_HOST_RSA_KEY_FILE }, { "dsa", "DSA", _PATH_HOST_DSA_KEY_FILE }, #ifdef OPENSSL_HAS_ECC { "ecdsa", "ECDSA",_PATH_HOST_ECDSA_KEY_FILE }, #endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ { "ed25519", "ED25519",_PATH_HOST_ED25519_KEY_FILE }, { NULL, NULL, NULL } }; int first = 0; struct stat st; struct sshkey *private, *public; char comment[1024]; int i, type, fd, r; FILE *f; for (i = 0; key_types[i].key_type; i++) { if (stat(key_types[i].path, &st) == 0) continue; if (errno != ENOENT) { error("Could not stat %s: %s", key_types[i].path, strerror(errno)); first = 0; continue; } if (first == 0) { first = 1; printf("%s: generating new host keys: ", __progname); } printf("%s ", key_types[i].key_type_display); fflush(stdout); type = sshkey_type_from_name(key_types[i].key_type); strlcpy(identity_file, key_types[i].path, sizeof(identity_file)); bits = 0; type_bits_valid(type, NULL, &bits); if ((r = sshkey_generate(type, bits, &private)) != 0) { error("key_generate failed: %s", ssh_err(r)); first = 0; continue; } if ((r = sshkey_from_private(private, &public)) != 0) fatal("sshkey_from_private failed: %s", ssh_err(r)); snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); if ((r = sshkey_save_private(private, identity_file, "", comment, use_new_format, new_format_cipher, rounds)) != 0) { error("Saving key \"%s\" failed: %s", identity_file, ssh_err(r)); sshkey_free(private); sshkey_free(public); first = 0; continue; } sshkey_free(private); strlcat(identity_file, ".pub", sizeof(identity_file)); fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd == -1) { error("Could not save your public key in %s", identity_file); sshkey_free(public); first = 0; continue; } f = fdopen(fd, "w"); if (f == NULL) { error("fdopen %s failed", identity_file); close(fd); sshkey_free(public); first = 0; continue; } if ((r = sshkey_write(public, f)) != 0) { error("write key failed: %s", ssh_err(r)); fclose(f); sshkey_free(public); first = 0; continue; } fprintf(f, " %s\n", comment); fclose(f); sshkey_free(public); } if (first != 0) printf("\n"); } struct known_hosts_ctx { const char *host; /* Hostname searched for in find/delete case */ FILE *out; /* Output file, stdout for find_hosts case */ int has_unhashed; /* When hashing, original had unhashed hosts */ int found_key; /* For find/delete, host was found */ int invalid; /* File contained invalid items; don't delete */ }; static int known_hosts_hash(struct hostkey_foreach_line *l, void *_ctx) { struct known_hosts_ctx *ctx = (struct known_hosts_ctx *)_ctx; char *hashed, *cp, *hosts, *ohosts; int has_wild = l->hosts && strcspn(l->hosts, "*?!") != strlen(l->hosts); switch (l->status) { case HKF_STATUS_OK: case HKF_STATUS_MATCHED: /* * Don't hash hosts already already hashed, with wildcard * characters or a CA/revocation marker. */ if ((l->match & HKF_MATCH_HOST_HASHED) != 0 || has_wild || l->marker != MRK_NONE) { fprintf(ctx->out, "%s\n", l->line); if (has_wild && !find_host) { logit("%s:%ld: ignoring host name " "with wildcard: %.64s", l->path, l->linenum, l->hosts); } return 0; } /* * Split any comma-separated hostnames from the host list, * hash and store separately. */ ohosts = hosts = xstrdup(l->hosts); while ((cp = strsep(&hosts, ",")) != NULL && *cp != '\0') { if ((hashed = host_hash(cp, NULL, 0)) == NULL) fatal("hash_host failed"); fprintf(ctx->out, "%s %s\n", hashed, l->rawkey); ctx->has_unhashed = 1; } free(ohosts); return 0; case HKF_STATUS_INVALID: /* Retain invalid lines, but mark file as invalid. */ ctx->invalid = 1; logit("%s:%ld: invalid line", l->path, l->linenum); /* FALLTHROUGH */ default: fprintf(ctx->out, "%s\n", l->line); return 0; } /* NOTREACHED */ return -1; } static int known_hosts_find_delete(struct hostkey_foreach_line *l, void *_ctx) { struct known_hosts_ctx *ctx = (struct known_hosts_ctx *)_ctx; enum sshkey_fp_rep rep; int fptype; char *fp; fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash; rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT; if (l->status == HKF_STATUS_MATCHED) { if (delete_host) { if (l->marker != MRK_NONE) { /* Don't remove CA and revocation lines */ fprintf(ctx->out, "%s\n", l->line); } else { /* * Hostname matches and has no CA/revoke * marker, delete it by *not* writing the * line to ctx->out. */ ctx->found_key = 1; if (!quiet) printf("# Host %s found: line %ld\n", ctx->host, l->linenum); } return 0; } else if (find_host) { ctx->found_key = 1; if (!quiet) { printf("# Host %s found: line %ld %s\n", ctx->host, l->linenum, l->marker == MRK_CA ? "CA" : (l->marker == MRK_REVOKE ? "REVOKED" : "")); } if (hash_hosts) known_hosts_hash(l, ctx); else if (print_fingerprint) { fp = sshkey_fingerprint(l->key, fptype, rep); printf("%s %s %s %s\n", ctx->host, sshkey_type(l->key), fp, l->comment); free(fp); } else fprintf(ctx->out, "%s\n", l->line); return 0; } } else if (delete_host) { /* Retain non-matching hosts when deleting */ if (l->status == HKF_STATUS_INVALID) { ctx->invalid = 1; logit("%s:%ld: invalid line", l->path, l->linenum); } fprintf(ctx->out, "%s\n", l->line); } return 0; } static void do_known_hosts(struct passwd *pw, const char *name) { char *cp, tmp[PATH_MAX], old[PATH_MAX]; int r, fd, oerrno, inplace = 0; struct known_hosts_ctx ctx; u_int foreach_options; if (!have_identity) { cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid); if (strlcpy(identity_file, cp, sizeof(identity_file)) >= sizeof(identity_file)) fatal("Specified known hosts path too long"); free(cp); have_identity = 1; } memset(&ctx, 0, sizeof(ctx)); ctx.out = stdout; ctx.host = name; /* * Find hosts goes to stdout, hash and deletions happen in-place * A corner case is ssh-keygen -HF foo, which should go to stdout */ if (!find_host && (hash_hosts || delete_host)) { if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) || strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) || strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) || strlcat(old, ".old", sizeof(old)) >= sizeof(old)) fatal("known_hosts path too long"); umask(077); if ((fd = mkstemp(tmp)) == -1) fatal("mkstemp: %s", strerror(errno)); if ((ctx.out = fdopen(fd, "w")) == NULL) { oerrno = errno; unlink(tmp); fatal("fdopen: %s", strerror(oerrno)); } inplace = 1; } /* XXX support identity_file == "-" for stdin */ foreach_options = find_host ? HKF_WANT_MATCH : 0; foreach_options |= print_fingerprint ? HKF_WANT_PARSE_KEY : 0; if ((r = hostkeys_foreach(identity_file, hash_hosts ? known_hosts_hash : known_hosts_find_delete, &ctx, name, NULL, foreach_options)) != 0) fatal("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r)); if (inplace) fclose(ctx.out); if (ctx.invalid) { error("%s is not a valid known_hosts file.", identity_file); if (inplace) { error("Not replacing existing known_hosts " "file because of errors"); unlink(tmp); } exit(1); } else if (delete_host && !ctx.found_key) { logit("Host %s not found in %s", name, identity_file); - unlink(tmp); + if (inplace) + unlink(tmp); } else if (inplace) { /* Backup existing file */ if (unlink(old) == -1 && errno != ENOENT) fatal("unlink %.100s: %s", old, strerror(errno)); if (link(identity_file, old) == -1) fatal("link %.100s to %.100s: %s", identity_file, old, strerror(errno)); /* Move new one into place */ if (rename(tmp, identity_file) == -1) { error("rename\"%s\" to \"%s\": %s", tmp, identity_file, strerror(errno)); unlink(tmp); unlink(old); exit(1); } printf("%s updated.\n", identity_file); printf("Original contents retained as %s\n", old); if (ctx.has_unhashed) { logit("WARNING: %s contains unhashed entries", old); logit("Delete this file to ensure privacy " "of hostnames"); } } exit (find_host && !ctx.found_key); } /* * Perform changing a passphrase. The argument is the passwd structure * for the current user. */ static void do_change_passphrase(struct passwd *pw) { char *comment; char *old_passphrase, *passphrase1, *passphrase2; struct stat st; struct sshkey *private; int r; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) fatal("%s: %s", identity_file, strerror(errno)); /* Try to load the file with empty passphrase. */ r = sshkey_load_private(identity_file, "", &private, &comment); if (r == SSH_ERR_KEY_WRONG_PASSPHRASE) { if (identity_passphrase) old_passphrase = xstrdup(identity_passphrase); else old_passphrase = read_passphrase("Enter old passphrase: ", RP_ALLOW_STDIN); r = sshkey_load_private(identity_file, old_passphrase, &private, &comment); explicit_bzero(old_passphrase, strlen(old_passphrase)); free(old_passphrase); if (r != 0) goto badkey; } else if (r != 0) { badkey: fatal("Failed to load key %s: %s", identity_file, ssh_err(r)); } if (comment) printf("Key has comment '%s'\n", comment); /* Ask the new passphrase (twice). */ if (identity_new_passphrase) { passphrase1 = xstrdup(identity_new_passphrase); passphrase2 = NULL; } else { passphrase1 = read_passphrase("Enter new passphrase (empty for no " "passphrase): ", RP_ALLOW_STDIN); passphrase2 = read_passphrase("Enter same passphrase again: ", RP_ALLOW_STDIN); /* Verify that they are the same. */ if (strcmp(passphrase1, passphrase2) != 0) { explicit_bzero(passphrase1, strlen(passphrase1)); explicit_bzero(passphrase2, strlen(passphrase2)); free(passphrase1); free(passphrase2); printf("Pass phrases do not match. Try again.\n"); exit(1); } /* Destroy the other copy. */ explicit_bzero(passphrase2, strlen(passphrase2)); free(passphrase2); } /* Save the file using the new passphrase. */ if ((r = sshkey_save_private(private, identity_file, passphrase1, comment, use_new_format, new_format_cipher, rounds)) != 0) { error("Saving key \"%s\" failed: %s.", identity_file, ssh_err(r)); explicit_bzero(passphrase1, strlen(passphrase1)); free(passphrase1); sshkey_free(private); free(comment); exit(1); } /* Destroy the passphrase and the copy of the key in memory. */ explicit_bzero(passphrase1, strlen(passphrase1)); free(passphrase1); sshkey_free(private); /* Destroys contents */ free(comment); printf("Your identification has been saved with the new passphrase.\n"); exit(0); } /* * Print the SSHFP RR. */ static int do_print_resource_record(struct passwd *pw, char *fname, char *hname) { struct sshkey *public; char *comment = NULL; struct stat st; int r; if (fname == NULL) fatal("%s: no filename", __func__); if (stat(fname, &st) < 0) { if (errno == ENOENT) return 0; fatal("%s: %s", fname, strerror(errno)); } if ((r = sshkey_load_public(fname, &public, &comment)) != 0) fatal("Failed to read v2 public key from \"%s\": %s.", fname, ssh_err(r)); export_dns_rr(hname, public, stdout, print_generic); sshkey_free(public); free(comment); return 1; } /* * Change the comment of a private key file. */ static void do_change_comment(struct passwd *pw) { char new_comment[1024], *comment, *passphrase; struct sshkey *private; struct sshkey *public; struct stat st; FILE *f; int r, fd; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) fatal("%s: %s", identity_file, strerror(errno)); if ((r = sshkey_load_private(identity_file, "", &private, &comment)) == 0) passphrase = xstrdup(""); else if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) fatal("Cannot load private key \"%s\": %s.", identity_file, ssh_err(r)); else { if (identity_passphrase) passphrase = xstrdup(identity_passphrase); else if (identity_new_passphrase) passphrase = xstrdup(identity_new_passphrase); else passphrase = read_passphrase("Enter passphrase: ", RP_ALLOW_STDIN); /* Try to load using the passphrase. */ if ((r = sshkey_load_private(identity_file, passphrase, &private, &comment)) != 0) { explicit_bzero(passphrase, strlen(passphrase)); free(passphrase); fatal("Cannot load private key \"%s\": %s.", identity_file, ssh_err(r)); } } /* XXX what about new-format keys? */ if (private->type != KEY_RSA1) { error("Comments are only supported for RSA1 keys."); explicit_bzero(passphrase, strlen(passphrase)); sshkey_free(private); exit(1); } printf("Key now has comment '%s'\n", comment); if (identity_comment) { strlcpy(new_comment, identity_comment, sizeof(new_comment)); } else { printf("Enter new comment: "); fflush(stdout); if (!fgets(new_comment, sizeof(new_comment), stdin)) { explicit_bzero(passphrase, strlen(passphrase)); sshkey_free(private); exit(1); } new_comment[strcspn(new_comment, "\n")] = '\0'; } /* Save the file using the new passphrase. */ if ((r = sshkey_save_private(private, identity_file, passphrase, new_comment, use_new_format, new_format_cipher, rounds)) != 0) { error("Saving key \"%s\" failed: %s", identity_file, ssh_err(r)); explicit_bzero(passphrase, strlen(passphrase)); free(passphrase); sshkey_free(private); free(comment); exit(1); } explicit_bzero(passphrase, strlen(passphrase)); free(passphrase); if ((r = sshkey_from_private(private, &public)) != 0) fatal("key_from_private failed: %s", ssh_err(r)); sshkey_free(private); strlcat(identity_file, ".pub", sizeof(identity_file)); fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd == -1) fatal("Could not save your public key in %s", identity_file); f = fdopen(fd, "w"); if (f == NULL) fatal("fdopen %s failed: %s", identity_file, strerror(errno)); if ((r = sshkey_write(public, f)) != 0) fatal("write key failed: %s", ssh_err(r)); sshkey_free(public); fprintf(f, " %s\n", new_comment); fclose(f); free(comment); printf("The comment in your key file has been changed.\n"); exit(0); } static const char * fmt_validity(u_int64_t valid_from, u_int64_t valid_to) { char from[32], to[32]; static char ret[64]; time_t tt; struct tm *tm; *from = *to = '\0'; if (valid_from == 0 && valid_to == 0xffffffffffffffffULL) return "forever"; if (valid_from != 0) { /* XXX revisit INT_MAX in 2038 :) */ tt = valid_from > INT_MAX ? INT_MAX : valid_from; tm = localtime(&tt); strftime(from, sizeof(from), "%Y-%m-%dT%H:%M:%S", tm); } if (valid_to != 0xffffffffffffffffULL) { /* XXX revisit INT_MAX in 2038 :) */ tt = valid_to > INT_MAX ? INT_MAX : valid_to; tm = localtime(&tt); strftime(to, sizeof(to), "%Y-%m-%dT%H:%M:%S", tm); } if (valid_from == 0) { snprintf(ret, sizeof(ret), "before %s", to); return ret; } if (valid_to == 0xffffffffffffffffULL) { snprintf(ret, sizeof(ret), "after %s", from); return ret; } snprintf(ret, sizeof(ret), "from %s to %s", from, to); return ret; } static void add_flag_option(struct sshbuf *c, const char *name) { int r; debug3("%s: %s", __func__, name); if ((r = sshbuf_put_cstring(c, name)) != 0 || (r = sshbuf_put_string(c, NULL, 0)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); } static void add_string_option(struct sshbuf *c, const char *name, const char *value) { struct sshbuf *b; int r; debug3("%s: %s=%s", __func__, name, value); if ((b = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if ((r = sshbuf_put_cstring(b, value)) != 0 || (r = sshbuf_put_cstring(c, name)) != 0 || (r = sshbuf_put_stringb(c, b)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); sshbuf_free(b); } #define OPTIONS_CRITICAL 1 #define OPTIONS_EXTENSIONS 2 static void prepare_options_buf(struct sshbuf *c, int which) { sshbuf_reset(c); if ((which & OPTIONS_CRITICAL) != 0 && certflags_command != NULL) add_string_option(c, "force-command", certflags_command); if ((which & OPTIONS_EXTENSIONS) != 0 && (certflags_flags & CERTOPT_X_FWD) != 0) add_flag_option(c, "permit-X11-forwarding"); if ((which & OPTIONS_EXTENSIONS) != 0 && (certflags_flags & CERTOPT_AGENT_FWD) != 0) add_flag_option(c, "permit-agent-forwarding"); if ((which & OPTIONS_EXTENSIONS) != 0 && (certflags_flags & CERTOPT_PORT_FWD) != 0) add_flag_option(c, "permit-port-forwarding"); if ((which & OPTIONS_EXTENSIONS) != 0 && (certflags_flags & CERTOPT_PTY) != 0) add_flag_option(c, "permit-pty"); if ((which & OPTIONS_EXTENSIONS) != 0 && (certflags_flags & CERTOPT_USER_RC) != 0) add_flag_option(c, "permit-user-rc"); if ((which & OPTIONS_CRITICAL) != 0 && certflags_src_addr != NULL) add_string_option(c, "source-address", certflags_src_addr); } static struct sshkey * load_pkcs11_key(char *path) { #ifdef ENABLE_PKCS11 struct sshkey **keys = NULL, *public, *private = NULL; int r, i, nkeys; if ((r = sshkey_load_public(path, &public, NULL)) != 0) fatal("Couldn't load CA public key \"%s\": %s", path, ssh_err(r)); nkeys = pkcs11_add_provider(pkcs11provider, identity_passphrase, &keys); debug3("%s: %d keys", __func__, nkeys); if (nkeys <= 0) fatal("cannot read public key from pkcs11"); for (i = 0; i < nkeys; i++) { if (sshkey_equal_public(public, keys[i])) { private = keys[i]; continue; } sshkey_free(keys[i]); } free(keys); sshkey_free(public); return private; #else fatal("no pkcs11 support"); #endif /* ENABLE_PKCS11 */ } static void do_ca_sign(struct passwd *pw, int argc, char **argv) { int r, i, fd; u_int n; struct sshkey *ca, *public; char *otmp, *tmp, *cp, *out, *comment, **plist = NULL; FILE *f; #ifdef ENABLE_PKCS11 pkcs11_init(1); #endif tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); if (pkcs11provider != NULL) { if ((ca = load_pkcs11_key(tmp)) == NULL) fatal("No PKCS#11 key matching %s found", ca_key_path); } else ca = load_identity(tmp); free(tmp); for (i = 0; i < argc; i++) { /* Split list of principals */ n = 0; if (cert_principals != NULL) { otmp = tmp = xstrdup(cert_principals); plist = NULL; for (; (cp = strsep(&tmp, ",")) != NULL; n++) { plist = xreallocarray(plist, n + 1, sizeof(*plist)); if (*(plist[n] = xstrdup(cp)) == '\0') fatal("Empty principal name"); } free(otmp); } tmp = tilde_expand_filename(argv[i], pw->pw_uid); if ((r = sshkey_load_public(tmp, &public, &comment)) != 0) fatal("%s: unable to open \"%s\": %s", __func__, tmp, ssh_err(r)); if (public->type != KEY_RSA && public->type != KEY_DSA && public->type != KEY_ECDSA && public->type != KEY_ED25519) fatal("%s: key \"%s\" type %s cannot be certified", __func__, tmp, sshkey_type(public)); /* Prepare certificate to sign */ if ((r = sshkey_to_certified(public)) != 0) fatal("Could not upgrade key %s to certificate: %s", tmp, ssh_err(r)); public->cert->type = cert_key_type; public->cert->serial = (u_int64_t)cert_serial; public->cert->key_id = xstrdup(cert_key_id); public->cert->nprincipals = n; public->cert->principals = plist; public->cert->valid_after = cert_valid_from; public->cert->valid_before = cert_valid_to; prepare_options_buf(public->cert->critical, OPTIONS_CRITICAL); prepare_options_buf(public->cert->extensions, OPTIONS_EXTENSIONS); if ((r = sshkey_from_private(ca, &public->cert->signature_key)) != 0) fatal("key_from_private (ca key): %s", ssh_err(r)); if (sshkey_certify(public, ca) != 0) fatal("Couldn't not certify key %s", tmp); if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) *cp = '\0'; xasprintf(&out, "%s-cert.pub", tmp); free(tmp); if ((fd = open(out, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) fatal("Could not open \"%s\" for writing: %s", out, strerror(errno)); if ((f = fdopen(fd, "w")) == NULL) fatal("%s: fdopen: %s", __func__, strerror(errno)); if ((r = sshkey_write(public, f)) != 0) fatal("Could not write certified key to %s: %s", out, ssh_err(r)); fprintf(f, " %s\n", comment); fclose(f); if (!quiet) { logit("Signed %s key %s: id \"%s\" serial %llu%s%s " "valid %s", sshkey_cert_type(public), out, public->cert->key_id, (unsigned long long)public->cert->serial, cert_principals != NULL ? " for " : "", cert_principals != NULL ? cert_principals : "", fmt_validity(cert_valid_from, cert_valid_to)); } sshkey_free(public); free(out); } #ifdef ENABLE_PKCS11 pkcs11_terminate(); #endif exit(0); } static u_int64_t parse_relative_time(const char *s, time_t now) { int64_t mul, secs; mul = *s == '-' ? -1 : 1; if ((secs = convtime(s + 1)) == -1) fatal("Invalid relative certificate time %s", s); if (mul == -1 && secs > now) fatal("Certificate time %s cannot be represented", s); return now + (u_int64_t)(secs * mul); } static u_int64_t parse_absolute_time(const char *s) { struct tm tm; time_t tt; char buf[32], *fmt; /* * POSIX strptime says "The application shall ensure that there * is white-space or other non-alphanumeric characters between * any two conversion specifications" so arrange things this way. */ switch (strlen(s)) { case 8: fmt = "%Y-%m-%d"; snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6); break; case 14: fmt = "%Y-%m-%dT%H:%M:%S"; snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s:%.2s", s, s + 4, s + 6, s + 8, s + 10, s + 12); break; default: fatal("Invalid certificate time format %s", s); } memset(&tm, 0, sizeof(tm)); if (strptime(buf, fmt, &tm) == NULL) fatal("Invalid certificate time %s", s); if ((tt = mktime(&tm)) < 0) fatal("Certificate time %s cannot be represented", s); return (u_int64_t)tt; } static void parse_cert_times(char *timespec) { char *from, *to; time_t now = time(NULL); int64_t secs; /* +timespec relative to now */ if (*timespec == '+' && strchr(timespec, ':') == NULL) { if ((secs = convtime(timespec + 1)) == -1) fatal("Invalid relative certificate life %s", timespec); cert_valid_to = now + secs; /* * Backdate certificate one minute to avoid problems on hosts * with poorly-synchronised clocks. */ cert_valid_from = ((now - 59)/ 60) * 60; return; } /* * from:to, where * from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS * to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS */ from = xstrdup(timespec); to = strchr(from, ':'); if (to == NULL || from == to || *(to + 1) == '\0') fatal("Invalid certificate life specification %s", timespec); *to++ = '\0'; if (*from == '-' || *from == '+') cert_valid_from = parse_relative_time(from, now); else cert_valid_from = parse_absolute_time(from); if (*to == '-' || *to == '+') cert_valid_to = parse_relative_time(to, now); else cert_valid_to = parse_absolute_time(to); if (cert_valid_to <= cert_valid_from) fatal("Empty certificate validity interval"); free(from); } static void add_cert_option(char *opt) { char *val; if (strcasecmp(opt, "clear") == 0) certflags_flags = 0; else if (strcasecmp(opt, "no-x11-forwarding") == 0) certflags_flags &= ~CERTOPT_X_FWD; else if (strcasecmp(opt, "permit-x11-forwarding") == 0) certflags_flags |= CERTOPT_X_FWD; else if (strcasecmp(opt, "no-agent-forwarding") == 0) certflags_flags &= ~CERTOPT_AGENT_FWD; else if (strcasecmp(opt, "permit-agent-forwarding") == 0) certflags_flags |= CERTOPT_AGENT_FWD; else if (strcasecmp(opt, "no-port-forwarding") == 0) certflags_flags &= ~CERTOPT_PORT_FWD; else if (strcasecmp(opt, "permit-port-forwarding") == 0) certflags_flags |= CERTOPT_PORT_FWD; else if (strcasecmp(opt, "no-pty") == 0) certflags_flags &= ~CERTOPT_PTY; else if (strcasecmp(opt, "permit-pty") == 0) certflags_flags |= CERTOPT_PTY; else if (strcasecmp(opt, "no-user-rc") == 0) certflags_flags &= ~CERTOPT_USER_RC; else if (strcasecmp(opt, "permit-user-rc") == 0) certflags_flags |= CERTOPT_USER_RC; else if (strncasecmp(opt, "force-command=", 14) == 0) { val = opt + 14; if (*val == '\0') fatal("Empty force-command option"); if (certflags_command != NULL) fatal("force-command already specified"); certflags_command = xstrdup(val); } else if (strncasecmp(opt, "source-address=", 15) == 0) { val = opt + 15; if (*val == '\0') fatal("Empty source-address option"); if (certflags_src_addr != NULL) fatal("source-address already specified"); if (addr_match_cidr_list(NULL, val) != 0) fatal("Invalid source-address list"); certflags_src_addr = xstrdup(val); } else fatal("Unsupported certificate option \"%s\"", opt); } static void show_options(struct sshbuf *optbuf, int in_critical) { char *name, *arg; struct sshbuf *options, *option = NULL; int r; if ((options = sshbuf_fromb(optbuf)) == NULL) fatal("%s: sshbuf_fromb failed", __func__); while (sshbuf_len(options) != 0) { sshbuf_free(option); option = NULL; if ((r = sshbuf_get_cstring(options, &name, NULL)) != 0 || (r = sshbuf_froms(options, &option)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); printf(" %s", name); if (!in_critical && (strcmp(name, "permit-X11-forwarding") == 0 || strcmp(name, "permit-agent-forwarding") == 0 || strcmp(name, "permit-port-forwarding") == 0 || strcmp(name, "permit-pty") == 0 || strcmp(name, "permit-user-rc") == 0)) printf("\n"); else if (in_critical && (strcmp(name, "force-command") == 0 || strcmp(name, "source-address") == 0)) { if ((r = sshbuf_get_cstring(option, &arg, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); printf(" %s\n", arg); free(arg); } else { printf(" UNKNOWN OPTION (len %zu)\n", sshbuf_len(option)); sshbuf_reset(option); } free(name); if (sshbuf_len(option) != 0) fatal("Option corrupt: extra data at end"); } sshbuf_free(option); sshbuf_free(options); } static void do_show_cert(struct passwd *pw) { struct sshkey *key; struct stat st; char *key_fp, *ca_fp; u_int i; int r; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); if ((r = sshkey_load_public(identity_file, &key, NULL)) != 0) fatal("Cannot load public key \"%s\": %s", identity_file, ssh_err(r)); if (!sshkey_is_cert(key)) fatal("%s is not a certificate", identity_file); key_fp = sshkey_fingerprint(key, fingerprint_hash, SSH_FP_DEFAULT); ca_fp = sshkey_fingerprint(key->cert->signature_key, fingerprint_hash, SSH_FP_DEFAULT); if (key_fp == NULL || ca_fp == NULL) fatal("%s: sshkey_fingerprint fail", __func__); printf("%s:\n", identity_file); printf(" Type: %s %s certificate\n", sshkey_ssh_name(key), sshkey_cert_type(key)); printf(" Public key: %s %s\n", sshkey_type(key), key_fp); printf(" Signing CA: %s %s\n", sshkey_type(key->cert->signature_key), ca_fp); printf(" Key ID: \"%s\"\n", key->cert->key_id); printf(" Serial: %llu\n", (unsigned long long)key->cert->serial); printf(" Valid: %s\n", fmt_validity(key->cert->valid_after, key->cert->valid_before)); printf(" Principals: "); if (key->cert->nprincipals == 0) printf("(none)\n"); else { for (i = 0; i < key->cert->nprincipals; i++) printf("\n %s", key->cert->principals[i]); printf("\n"); } printf(" Critical Options: "); if (sshbuf_len(key->cert->critical) == 0) printf("(none)\n"); else { printf("\n"); show_options(key->cert->critical, 1); } printf(" Extensions: "); if (sshbuf_len(key->cert->extensions) == 0) printf("(none)\n"); else { printf("\n"); show_options(key->cert->extensions, 0); } exit(0); } static void load_krl(const char *path, struct ssh_krl **krlp) { struct sshbuf *krlbuf; int r, fd; if ((krlbuf = sshbuf_new()) == NULL) fatal("sshbuf_new failed"); if ((fd = open(path, O_RDONLY)) == -1) fatal("open %s: %s", path, strerror(errno)); if ((r = sshkey_load_file(fd, krlbuf)) != 0) fatal("Unable to load KRL: %s", ssh_err(r)); close(fd); /* XXX check sigs */ if ((r = ssh_krl_from_blob(krlbuf, krlp, NULL, 0)) != 0 || *krlp == NULL) fatal("Invalid KRL file: %s", ssh_err(r)); sshbuf_free(krlbuf); } static void update_krl_from_file(struct passwd *pw, const char *file, int wild_ca, const struct sshkey *ca, struct ssh_krl *krl) { struct sshkey *key = NULL; u_long lnum = 0; char *path, *cp, *ep, line[SSH_MAX_PUBKEY_BYTES]; unsigned long long serial, serial2; int i, was_explicit_key, was_sha1, r; FILE *krl_spec; path = tilde_expand_filename(file, pw->pw_uid); if (strcmp(path, "-") == 0) { krl_spec = stdin; free(path); path = xstrdup("(standard input)"); } else if ((krl_spec = fopen(path, "r")) == NULL) fatal("fopen %s: %s", path, strerror(errno)); if (!quiet) printf("Revoking from %s\n", path); while (read_keyfile_line(krl_spec, path, line, sizeof(line), &lnum) == 0) { was_explicit_key = was_sha1 = 0; cp = line + strspn(line, " \t"); /* Trim trailing space, comments and strip \n */ for (i = 0, r = -1; cp[i] != '\0'; i++) { if (cp[i] == '#' || cp[i] == '\n') { cp[i] = '\0'; break; } if (cp[i] == ' ' || cp[i] == '\t') { /* Remember the start of a span of whitespace */ if (r == -1) r = i; } else r = -1; } if (r != -1) cp[r] = '\0'; if (*cp == '\0') continue; if (strncasecmp(cp, "serial:", 7) == 0) { if (ca == NULL && !wild_ca) { fatal("revoking certificates by serial number " "requires specification of a CA key"); } cp += 7; cp = cp + strspn(cp, " \t"); errno = 0; serial = strtoull(cp, &ep, 0); if (*cp == '\0' || (*ep != '\0' && *ep != '-')) fatal("%s:%lu: invalid serial \"%s\"", path, lnum, cp); if (errno == ERANGE && serial == ULLONG_MAX) fatal("%s:%lu: serial out of range", path, lnum); serial2 = serial; if (*ep == '-') { cp = ep + 1; errno = 0; serial2 = strtoull(cp, &ep, 0); if (*cp == '\0' || *ep != '\0') fatal("%s:%lu: invalid serial \"%s\"", path, lnum, cp); if (errno == ERANGE && serial2 == ULLONG_MAX) fatal("%s:%lu: serial out of range", path, lnum); if (serial2 <= serial) fatal("%s:%lu: invalid serial range " "%llu:%llu", path, lnum, (unsigned long long)serial, (unsigned long long)serial2); } if (ssh_krl_revoke_cert_by_serial_range(krl, ca, serial, serial2) != 0) { fatal("%s: revoke serial failed", __func__); } } else if (strncasecmp(cp, "id:", 3) == 0) { if (ca == NULL && !wild_ca) { fatal("revoking certificates by key ID " "requires specification of a CA key"); } cp += 3; cp = cp + strspn(cp, " \t"); if (ssh_krl_revoke_cert_by_key_id(krl, ca, cp) != 0) fatal("%s: revoke key ID failed", __func__); } else { if (strncasecmp(cp, "key:", 4) == 0) { cp += 4; cp = cp + strspn(cp, " \t"); was_explicit_key = 1; } else if (strncasecmp(cp, "sha1:", 5) == 0) { cp += 5; cp = cp + strspn(cp, " \t"); was_sha1 = 1; } else { /* * Just try to process the line as a key. * Parsing will fail if it isn't. */ } if ((key = sshkey_new(KEY_UNSPEC)) == NULL) fatal("key_new"); if ((r = sshkey_read(key, &cp)) != 0) fatal("%s:%lu: invalid key: %s", path, lnum, ssh_err(r)); if (was_explicit_key) r = ssh_krl_revoke_key_explicit(krl, key); else if (was_sha1) r = ssh_krl_revoke_key_sha1(krl, key); else r = ssh_krl_revoke_key(krl, key); if (r != 0) fatal("%s: revoke key failed: %s", __func__, ssh_err(r)); sshkey_free(key); } } if (strcmp(path, "-") != 0) fclose(krl_spec); free(path); } static void do_gen_krl(struct passwd *pw, int updating, int argc, char **argv) { struct ssh_krl *krl; struct stat sb; struct sshkey *ca = NULL; int fd, i, r, wild_ca = 0; char *tmp; struct sshbuf *kbuf; if (*identity_file == '\0') fatal("KRL generation requires an output file"); if (stat(identity_file, &sb) == -1) { if (errno != ENOENT) fatal("Cannot access KRL \"%s\": %s", identity_file, strerror(errno)); if (updating) fatal("KRL \"%s\" does not exist", identity_file); } if (ca_key_path != NULL) { if (strcasecmp(ca_key_path, "none") == 0) wild_ca = 1; else { tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0) fatal("Cannot load CA public key %s: %s", tmp, ssh_err(r)); free(tmp); } } if (updating) load_krl(identity_file, &krl); else if ((krl = ssh_krl_init()) == NULL) fatal("couldn't create KRL"); if (cert_serial != 0) ssh_krl_set_version(krl, cert_serial); if (identity_comment != NULL) ssh_krl_set_comment(krl, identity_comment); for (i = 0; i < argc; i++) update_krl_from_file(pw, argv[i], wild_ca, ca, krl); if ((kbuf = sshbuf_new()) == NULL) fatal("sshbuf_new failed"); if (ssh_krl_to_blob(krl, kbuf, NULL, 0) != 0) fatal("Couldn't generate KRL"); if ((fd = open(identity_file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) fatal("open %s: %s", identity_file, strerror(errno)); if (atomicio(vwrite, fd, (void *)sshbuf_ptr(kbuf), sshbuf_len(kbuf)) != sshbuf_len(kbuf)) fatal("write %s: %s", identity_file, strerror(errno)); close(fd); sshbuf_free(kbuf); ssh_krl_free(krl); if (ca != NULL) sshkey_free(ca); } static void do_check_krl(struct passwd *pw, int argc, char **argv) { int i, r, ret = 0; char *comment; struct ssh_krl *krl; struct sshkey *k; if (*identity_file == '\0') fatal("KRL checking requires an input file"); load_krl(identity_file, &krl); for (i = 0; i < argc; i++) { if ((r = sshkey_load_public(argv[i], &k, &comment)) != 0) fatal("Cannot load public key %s: %s", argv[i], ssh_err(r)); r = ssh_krl_check_key(krl, k); printf("%s%s%s%s: %s\n", argv[i], *comment ? " (" : "", comment, *comment ? ")" : "", r == 0 ? "ok" : "REVOKED"); if (r != 0) ret = 1; sshkey_free(k); free(comment); } ssh_krl_free(krl); exit(ret); } static void usage(void) { fprintf(stderr, "usage: ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa | rsa1]\n" " [-N new_passphrase] [-C comment] [-f output_keyfile]\n" " ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]\n" " ssh-keygen -i [-m key_format] [-f input_keyfile]\n" " ssh-keygen -e [-m key_format] [-f input_keyfile]\n" " ssh-keygen -y [-f input_keyfile]\n" " ssh-keygen -c [-P passphrase] [-C comment] [-f keyfile]\n" " ssh-keygen -l [-v] [-E fingerprint_hash] [-f input_keyfile]\n" " ssh-keygen -B [-f input_keyfile]\n"); #ifdef ENABLE_PKCS11 fprintf(stderr, " ssh-keygen -D pkcs11\n"); #endif fprintf(stderr, " ssh-keygen -F hostname [-f known_hosts_file] [-l]\n" " ssh-keygen -H [-f known_hosts_file]\n" " ssh-keygen -R hostname [-f known_hosts_file]\n" " ssh-keygen -r hostname [-f input_keyfile] [-g]\n" #ifdef WITH_OPENSSL " ssh-keygen -G output_file [-v] [-b bits] [-M memory] [-S start_point]\n" " ssh-keygen -T output_file -f input_file [-v] [-a rounds] [-J num_lines]\n" " [-j start_line] [-K checkpt] [-W generator]\n" #endif " ssh-keygen -s ca_key -I certificate_identity [-h] [-n principals]\n" " [-O option] [-V validity_interval] [-z serial_number] file ...\n" " ssh-keygen -L [-f input_keyfile]\n" " ssh-keygen -A\n" " ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n" " file ...\n" " ssh-keygen -Q -f krl_file file ...\n"); exit(1); } /* * Main program for key management. */ int main(int argc, char **argv) { char dotsshdir[PATH_MAX], comment[1024], *passphrase1, *passphrase2; char *rr_hostname = NULL, *ep, *fp, *ra; struct sshkey *private, *public; struct passwd *pw; struct stat st; int r, opt, type, fd; int gen_all_hostkeys = 0, gen_krl = 0, update_krl = 0, check_krl = 0; FILE *f; const char *errstr; #ifdef WITH_OPENSSL /* Moduli generation/screening */ char out_file[PATH_MAX], *checkpoint = NULL; u_int32_t memory = 0, generator_wanted = 0; int do_gen_candidates = 0, do_screen_candidates = 0; unsigned long start_lineno = 0, lines_to_process = 0; BIGNUM *start = NULL; #endif extern int optind; extern char *optarg; /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); __progname = ssh_get_progname(argv[0]); #ifdef WITH_OPENSSL OpenSSL_add_all_algorithms(); #endif log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1); seed_rng(); /* we need this for the home * directory. */ pw = getpwuid(getuid()); if (!pw) fatal("No user exists for uid %lu", (u_long)getuid()); if (gethostname(hostname, sizeof(hostname)) < 0) fatal("gethostname: %s", strerror(errno)); /* Remaining characters: UYdw */ while ((opt = getopt(argc, argv, "ABHLQXceghiklopquvxy" "C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:" "a:b:f:g:j:m:n:r:s:t:z:")) != -1) { switch (opt) { case 'A': gen_all_hostkeys = 1; break; case 'b': bits = (u_int32_t)strtonum(optarg, 256, 32768, &errstr); if (errstr) fatal("Bits has bad value %s (%s)", optarg, errstr); break; case 'E': fingerprint_hash = ssh_digest_alg_by_name(optarg); if (fingerprint_hash == -1) fatal("Invalid hash algorithm \"%s\"", optarg); break; case 'F': find_host = 1; rr_hostname = optarg; break; case 'H': hash_hosts = 1; break; case 'I': cert_key_id = optarg; break; case 'R': delete_host = 1; rr_hostname = optarg; break; case 'L': show_cert = 1; break; case 'l': print_fingerprint = 1; break; case 'B': print_bubblebabble = 1; break; case 'm': if (strcasecmp(optarg, "RFC4716") == 0 || strcasecmp(optarg, "ssh2") == 0) { convert_format = FMT_RFC4716; break; } if (strcasecmp(optarg, "PKCS8") == 0) { convert_format = FMT_PKCS8; break; } if (strcasecmp(optarg, "PEM") == 0) { convert_format = FMT_PEM; break; } fatal("Unsupported conversion format \"%s\"", optarg); case 'n': cert_principals = optarg; break; case 'o': use_new_format = 1; break; case 'p': change_passphrase = 1; break; case 'c': change_comment = 1; break; case 'f': if (strlcpy(identity_file, optarg, sizeof(identity_file)) >= sizeof(identity_file)) fatal("Identity filename too long"); have_identity = 1; break; case 'g': print_generic = 1; break; case 'P': identity_passphrase = optarg; break; case 'N': identity_new_passphrase = optarg; break; case 'Q': check_krl = 1; break; case 'O': add_cert_option(optarg); break; case 'Z': new_format_cipher = optarg; break; case 'C': identity_comment = optarg; break; case 'q': quiet = 1; break; case 'e': case 'x': /* export key */ convert_to = 1; break; case 'h': cert_key_type = SSH2_CERT_TYPE_HOST; certflags_flags = 0; break; case 'k': gen_krl = 1; break; case 'i': case 'X': /* import key */ convert_from = 1; break; case 'y': print_public = 1; break; case 's': ca_key_path = optarg; break; case 't': key_type_name = optarg; break; case 'D': pkcs11provider = optarg; break; case 'u': update_krl = 1; break; case 'v': if (log_level == SYSLOG_LEVEL_INFO) log_level = SYSLOG_LEVEL_DEBUG1; else { if (log_level >= SYSLOG_LEVEL_DEBUG1 && log_level < SYSLOG_LEVEL_DEBUG3) log_level++; } break; case 'r': rr_hostname = optarg; break; case 'a': rounds = (int)strtonum(optarg, 1, INT_MAX, &errstr); if (errstr) fatal("Invalid number: %s (%s)", optarg, errstr); break; case 'V': parse_cert_times(optarg); break; case 'z': errno = 0; cert_serial = strtoull(optarg, &ep, 10); if (*optarg < '0' || *optarg > '9' || *ep != '\0' || (errno == ERANGE && cert_serial == ULLONG_MAX)) fatal("Invalid serial number \"%s\"", optarg); break; #ifdef WITH_OPENSSL /* Moduli generation/screening */ case 'W': generator_wanted = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr); if (errstr) fatal("Desired generator has bad value: %s (%s)", optarg, errstr); break; case 'M': memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr); if (errstr) fatal("Memory limit is %s: %s", errstr, optarg); break; case 'G': do_gen_candidates = 1; if (strlcpy(out_file, optarg, sizeof(out_file)) >= sizeof(out_file)) fatal("Output filename too long"); break; case 'T': do_screen_candidates = 1; if (strlcpy(out_file, optarg, sizeof(out_file)) >= sizeof(out_file)) fatal("Output filename too long"); break; case 'K': if (strlen(optarg) >= PATH_MAX) fatal("Checkpoint filename too long"); checkpoint = xstrdup(optarg); break; case 'S': /* XXX - also compare length against bits */ if (BN_hex2bn(&start, optarg) == 0) fatal("Invalid start point."); break; #endif /* WITH_OPENSSL */ case '?': default: usage(); } } /* reinit */ log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1); argv += optind; argc -= optind; if (ca_key_path != NULL) { if (argc < 1 && !gen_krl) { error("Too few arguments."); usage(); } } else if (argc > 0 && !gen_krl && !check_krl) { error("Too many arguments."); usage(); } if (change_passphrase && change_comment) { error("Can only have one of -p and -c."); usage(); } if (print_fingerprint && (delete_host || hash_hosts)) { error("Cannot use -l with -H or -R."); usage(); } if (gen_krl) { do_gen_krl(pw, update_krl, argc, argv); return (0); } if (check_krl) { do_check_krl(pw, argc, argv); return (0); } if (ca_key_path != NULL) { if (cert_key_id == NULL) fatal("Must specify key id (-I) when certifying"); do_ca_sign(pw, argc, argv); } if (show_cert) do_show_cert(pw); if (delete_host || hash_hosts || find_host) do_known_hosts(pw, rr_hostname); if (pkcs11provider != NULL) do_download(pw); if (print_fingerprint || print_bubblebabble) do_fingerprint(pw); if (change_passphrase) do_change_passphrase(pw); if (change_comment) do_change_comment(pw); #ifdef WITH_OPENSSL if (convert_to) do_convert_to(pw); if (convert_from) do_convert_from(pw); #endif if (print_public) do_print_public(pw); if (rr_hostname != NULL) { unsigned int n = 0; if (have_identity) { n = do_print_resource_record(pw, identity_file, rr_hostname); if (n == 0) fatal("%s: %s", identity_file, strerror(errno)); exit(0); } else { n += do_print_resource_record(pw, _PATH_HOST_RSA_KEY_FILE, rr_hostname); n += do_print_resource_record(pw, _PATH_HOST_DSA_KEY_FILE, rr_hostname); n += do_print_resource_record(pw, _PATH_HOST_ECDSA_KEY_FILE, rr_hostname); n += do_print_resource_record(pw, _PATH_HOST_ED25519_KEY_FILE, rr_hostname); if (n == 0) fatal("no keys found."); exit(0); } } #ifdef WITH_OPENSSL if (do_gen_candidates) { FILE *out = fopen(out_file, "w"); if (out == NULL) { error("Couldn't open modulus candidate file \"%s\": %s", out_file, strerror(errno)); return (1); } if (bits == 0) bits = DEFAULT_BITS; if (gen_candidates(out, memory, bits, start) != 0) fatal("modulus candidate generation failed"); return (0); } if (do_screen_candidates) { FILE *in; FILE *out = fopen(out_file, "a"); if (have_identity && strcmp(identity_file, "-") != 0) { if ((in = fopen(identity_file, "r")) == NULL) { fatal("Couldn't open modulus candidate " "file \"%s\": %s", identity_file, strerror(errno)); } } else in = stdin; if (out == NULL) { fatal("Couldn't open moduli file \"%s\": %s", out_file, strerror(errno)); } if (prime_test(in, out, rounds == 0 ? 100 : rounds, generator_wanted, checkpoint, start_lineno, lines_to_process) != 0) fatal("modulus screening failed"); return (0); } #endif if (gen_all_hostkeys) { do_gen_all_hostkeys(pw); return (0); } if (key_type_name == NULL) key_type_name = DEFAULT_KEY_TYPE_NAME; type = sshkey_type_from_name(key_type_name); type_bits_valid(type, key_type_name, &bits); if (!quiet) printf("Generating public/private %s key pair.\n", key_type_name); if ((r = sshkey_generate(type, bits, &private)) != 0) fatal("key_generate failed"); if ((r = sshkey_from_private(private, &public)) != 0) fatal("key_from_private failed: %s\n", ssh_err(r)); if (!have_identity) ask_filename(pw, "Enter file in which to save the key"); /* Create ~/.ssh directory if it doesn't already exist. */ snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR); if (strstr(identity_file, dotsshdir) != NULL) { if (stat(dotsshdir, &st) < 0) { if (errno != ENOENT) { error("Could not stat %s: %s", dotsshdir, strerror(errno)); } else if (mkdir(dotsshdir, 0700) < 0) { error("Could not create directory '%s': %s", dotsshdir, strerror(errno)); } else if (!quiet) printf("Created directory '%s'.\n", dotsshdir); } } /* If the file already exists, ask the user to confirm. */ if (stat(identity_file, &st) >= 0) { char yesno[3]; printf("%s already exists.\n", identity_file); printf("Overwrite (y/n)? "); fflush(stdout); if (fgets(yesno, sizeof(yesno), stdin) == NULL) exit(1); if (yesno[0] != 'y' && yesno[0] != 'Y') exit(1); } /* Ask for a passphrase (twice). */ if (identity_passphrase) passphrase1 = xstrdup(identity_passphrase); else if (identity_new_passphrase) passphrase1 = xstrdup(identity_new_passphrase); else { passphrase_again: passphrase1 = read_passphrase("Enter passphrase (empty for no " "passphrase): ", RP_ALLOW_STDIN); passphrase2 = read_passphrase("Enter same passphrase again: ", RP_ALLOW_STDIN); if (strcmp(passphrase1, passphrase2) != 0) { /* * The passphrases do not match. Clear them and * retry. */ explicit_bzero(passphrase1, strlen(passphrase1)); explicit_bzero(passphrase2, strlen(passphrase2)); free(passphrase1); free(passphrase2); printf("Passphrases do not match. Try again.\n"); goto passphrase_again; } /* Clear the other copy of the passphrase. */ explicit_bzero(passphrase2, strlen(passphrase2)); free(passphrase2); } if (identity_comment) { strlcpy(comment, identity_comment, sizeof(comment)); } else { /* Create default comment field for the passphrase. */ snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); } /* Save the key with the given passphrase and comment. */ if ((r = sshkey_save_private(private, identity_file, passphrase1, comment, use_new_format, new_format_cipher, rounds)) != 0) { error("Saving key \"%s\" failed: %s", identity_file, ssh_err(r)); explicit_bzero(passphrase1, strlen(passphrase1)); free(passphrase1); exit(1); } /* Clear the passphrase. */ explicit_bzero(passphrase1, strlen(passphrase1)); free(passphrase1); /* Clear the private key and the random number generator. */ sshkey_free(private); if (!quiet) printf("Your identification has been saved in %s.\n", identity_file); strlcat(identity_file, ".pub", sizeof(identity_file)); if ((fd = open(identity_file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) fatal("Unable to save public key to %s: %s", identity_file, strerror(errno)); if ((f = fdopen(fd, "w")) == NULL) fatal("fdopen %s failed: %s", identity_file, strerror(errno)); if ((r = sshkey_write(public, f)) != 0) error("write key failed: %s", ssh_err(r)); fprintf(f, " %s\n", comment); fclose(f); if (!quiet) { fp = sshkey_fingerprint(public, fingerprint_hash, SSH_FP_DEFAULT); ra = sshkey_fingerprint(public, fingerprint_hash, SSH_FP_RANDOMART); if (fp == NULL || ra == NULL) fatal("sshkey_fingerprint failed"); printf("Your public key has been saved in %s.\n", identity_file); printf("The key fingerprint is:\n"); printf("%s %s\n", fp, comment); printf("The key's randomart image is:\n"); printf("%s\n", ra); free(ra); free(fp); } sshkey_free(public); exit(0); } Index: head/crypto/openssh/ssh-pkcs11-helper.c =================================================================== --- head/crypto/openssh/ssh-pkcs11-helper.c (revision 294495) +++ head/crypto/openssh/ssh-pkcs11-helper.c (revision 294496) @@ -1,374 +1,374 @@ -/* $OpenBSD: ssh-pkcs11-helper.c,v 1.10 2015/01/20 23:14:00 deraadt Exp $ */ +/* $OpenBSD: ssh-pkcs11-helper.c,v 1.11 2015/08/20 22:32:42 deraadt Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "includes.h" #include #ifdef HAVE_SYS_TIME_H # include #endif #include "openbsd-compat/sys-queue.h" #include #include #include #include #include "xmalloc.h" #include "buffer.h" #include "log.h" #include "misc.h" #include "key.h" #include "authfd.h" #include "ssh-pkcs11.h" #ifdef ENABLE_PKCS11 /* borrows code from sftp-server and ssh-agent */ struct pkcs11_keyinfo { Key *key; char *providername; TAILQ_ENTRY(pkcs11_keyinfo) next; }; TAILQ_HEAD(, pkcs11_keyinfo) pkcs11_keylist; #define MAX_MSG_LENGTH 10240 /*XXX*/ /* helper */ #define get_int() buffer_get_int(&iqueue); #define get_string(lenp) buffer_get_string(&iqueue, lenp); /* input and output queue */ Buffer iqueue; Buffer oqueue; static void add_key(Key *k, char *name) { struct pkcs11_keyinfo *ki; ki = xcalloc(1, sizeof(*ki)); ki->providername = xstrdup(name); ki->key = k; TAILQ_INSERT_TAIL(&pkcs11_keylist, ki, next); } static void del_keys_by_name(char *name) { struct pkcs11_keyinfo *ki, *nxt; for (ki = TAILQ_FIRST(&pkcs11_keylist); ki; ki = nxt) { nxt = TAILQ_NEXT(ki, next); if (!strcmp(ki->providername, name)) { TAILQ_REMOVE(&pkcs11_keylist, ki, next); free(ki->providername); key_free(ki->key); free(ki); } } } /* lookup matching 'private' key */ static Key * lookup_key(Key *k) { struct pkcs11_keyinfo *ki; TAILQ_FOREACH(ki, &pkcs11_keylist, next) { debug("check %p %s", ki, ki->providername); if (key_equal(k, ki->key)) return (ki->key); } return (NULL); } static void send_msg(Buffer *m) { int mlen = buffer_len(m); buffer_put_int(&oqueue, mlen); buffer_append(&oqueue, buffer_ptr(m), mlen); buffer_consume(m, mlen); } static void process_add(void) { char *name, *pin; Key **keys; int i, nkeys; u_char *blob; u_int blen; Buffer msg; buffer_init(&msg); name = get_string(NULL); pin = get_string(NULL); if ((nkeys = pkcs11_add_provider(name, pin, &keys)) > 0) { buffer_put_char(&msg, SSH2_AGENT_IDENTITIES_ANSWER); buffer_put_int(&msg, nkeys); for (i = 0; i < nkeys; i++) { if (key_to_blob(keys[i], &blob, &blen) == 0) continue; buffer_put_string(&msg, blob, blen); buffer_put_cstring(&msg, name); free(blob); add_key(keys[i], name); } free(keys); } else { buffer_put_char(&msg, SSH_AGENT_FAILURE); } free(pin); free(name); send_msg(&msg); buffer_free(&msg); } static void process_del(void) { char *name, *pin; Buffer msg; buffer_init(&msg); name = get_string(NULL); pin = get_string(NULL); del_keys_by_name(name); if (pkcs11_del_provider(name) == 0) buffer_put_char(&msg, SSH_AGENT_SUCCESS); else buffer_put_char(&msg, SSH_AGENT_FAILURE); free(pin); free(name); send_msg(&msg); buffer_free(&msg); } static void process_sign(void) { u_char *blob, *data, *signature = NULL; u_int blen, dlen, slen = 0; int ok = -1; Key *key, *found; Buffer msg; blob = get_string(&blen); data = get_string(&dlen); (void)get_int(); /* XXX ignore flags */ if ((key = key_from_blob(blob, blen)) != NULL) { if ((found = lookup_key(key)) != NULL) { #ifdef WITH_OPENSSL int ret; slen = RSA_size(key->rsa); signature = xmalloc(slen); if ((ret = RSA_private_encrypt(dlen, data, signature, found->rsa, RSA_PKCS1_PADDING)) != -1) { slen = ret; ok = 0; } #endif /* WITH_OPENSSL */ } key_free(key); } buffer_init(&msg); if (ok == 0) { buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE); buffer_put_string(&msg, signature, slen); } else { buffer_put_char(&msg, SSH_AGENT_FAILURE); } free(data); free(blob); free(signature); send_msg(&msg); buffer_free(&msg); } static void process(void) { u_int msg_len; u_int buf_len; u_int consumed; u_int type; u_char *cp; buf_len = buffer_len(&iqueue); if (buf_len < 5) return; /* Incomplete message. */ cp = buffer_ptr(&iqueue); msg_len = get_u32(cp); if (msg_len > MAX_MSG_LENGTH) { error("bad message len %d", msg_len); cleanup_exit(11); } if (buf_len < msg_len + 4) return; buffer_consume(&iqueue, 4); buf_len -= 4; type = buffer_get_char(&iqueue); switch (type) { case SSH_AGENTC_ADD_SMARTCARD_KEY: debug("process_add"); process_add(); break; case SSH_AGENTC_REMOVE_SMARTCARD_KEY: debug("process_del"); process_del(); break; case SSH2_AGENTC_SIGN_REQUEST: debug("process_sign"); process_sign(); break; default: error("Unknown message %d", type); break; } /* discard the remaining bytes from the current packet */ if (buf_len < buffer_len(&iqueue)) { error("iqueue grew unexpectedly"); cleanup_exit(255); } consumed = buf_len - buffer_len(&iqueue); if (msg_len < consumed) { error("msg_len %d < consumed %d", msg_len, consumed); cleanup_exit(255); } if (msg_len > consumed) buffer_consume(&iqueue, msg_len - consumed); } void cleanup_exit(int i) { /* XXX */ _exit(i); } int main(int argc, char **argv) { fd_set *rset, *wset; int in, out, max, log_stderr = 0; ssize_t len, olen, set_size; SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; LogLevel log_level = SYSLOG_LEVEL_ERROR; char buf[4*4096]; extern char *__progname; TAILQ_INIT(&pkcs11_keylist); pkcs11_init(0); seed_rng(); __progname = ssh_get_progname(argv[0]); log_init(__progname, log_level, log_facility, log_stderr); in = STDIN_FILENO; out = STDOUT_FILENO; max = 0; if (in > max) max = in; if (out > max) max = out; buffer_init(&iqueue); buffer_init(&oqueue); set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask); - rset = (fd_set *)xmalloc(set_size); - wset = (fd_set *)xmalloc(set_size); + rset = xmalloc(set_size); + wset = xmalloc(set_size); for (;;) { memset(rset, 0, set_size); memset(wset, 0, set_size); /* * Ensure that we can read a full buffer and handle * the worst-case length packet it can generate, * otherwise apply backpressure by stopping reads. */ if (buffer_check_alloc(&iqueue, sizeof(buf)) && buffer_check_alloc(&oqueue, MAX_MSG_LENGTH)) FD_SET(in, rset); olen = buffer_len(&oqueue); if (olen > 0) FD_SET(out, wset); if (select(max+1, rset, wset, NULL, NULL) < 0) { if (errno == EINTR) continue; error("select: %s", strerror(errno)); cleanup_exit(2); } /* copy stdin to iqueue */ if (FD_ISSET(in, rset)) { len = read(in, buf, sizeof buf); if (len == 0) { debug("read eof"); cleanup_exit(0); } else if (len < 0) { error("read: %s", strerror(errno)); cleanup_exit(1); } else { buffer_append(&iqueue, buf, len); } } /* send oqueue to stdout */ if (FD_ISSET(out, wset)) { len = write(out, buffer_ptr(&oqueue), olen); if (len < 0) { error("write: %s", strerror(errno)); cleanup_exit(1); } else { buffer_consume(&oqueue, len); } } /* * Process requests from client if we can fit the results * into the output buffer, otherwise stop processing input * and let the output queue drain. */ if (buffer_check_alloc(&oqueue, MAX_MSG_LENGTH)) process(); } } #else /* ENABLE_PKCS11 */ int main(int argc, char **argv) { extern char *__progname; __progname = ssh_get_progname(argv[0]); log_init(__progname, SYSLOG_LEVEL_ERROR, SYSLOG_FACILITY_AUTH, 0); fatal("PKCS#11 support disabled at compile time"); } #endif /* ENABLE_PKCS11 */ Index: head/crypto/openssh/ssh_config =================================================================== --- head/crypto/openssh/ssh_config (revision 294495) +++ head/crypto/openssh/ssh_config (revision 294496) @@ -1,51 +1,51 @@ # $OpenBSD: ssh_config,v 1.28 2013/09/16 11:35:43 sthen Exp $ # $FreeBSD$ # This is the ssh client system-wide configuration file. See # ssh_config(5) for more information. This file provides defaults for # users, and the values can be changed in per-user configuration files # or on the command line. # Configuration data is parsed as follows: # 1. command line options # 2. user-specific file # 3. system-wide file # Any configuration value is only changed the first time it is set. # Thus, host-specific definitions should be at the beginning of the # configuration file, and defaults at the end. # Site-wide defaults for some commonly used options. For a comprehensive # list of available options, their meanings and defaults, please see the # ssh_config(5) man page. # Host * # ForwardAgent no # ForwardX11 no # RhostsRSAAuthentication no # RSAAuthentication yes # PasswordAuthentication yes # HostbasedAuthentication no # GSSAPIAuthentication no # GSSAPIDelegateCredentials no # BatchMode no # CheckHostIP no # AddressFamily any # ConnectTimeout 0 # StrictHostKeyChecking ask # IdentityFile ~/.ssh/identity # IdentityFile ~/.ssh/id_rsa # IdentityFile ~/.ssh/id_dsa # Port 22 # Protocol 2,1 # Cipher 3des # Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc # MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160 # EscapeChar ~ # Tunnel no # TunnelDevice any:any # PermitLocalCommand no # VisualHostKey no # ProxyCommand ssh -q -W %h:%p gateway.example.com # RekeyLimit 1G 1h # VerifyHostKeyDNS yes -# VersionAddendum FreeBSD-20160119 +# VersionAddendum FreeBSD-20160121 Index: head/crypto/openssh/ssh_config.5 =================================================================== --- head/crypto/openssh/ssh_config.5 (revision 294495) +++ head/crypto/openssh/ssh_config.5 (revision 294496) @@ -1,1744 +1,1744 @@ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland .\" All rights reserved .\" .\" As far as I am concerned, the code I have written for this software .\" can be used freely for any purpose. Any derived versions of this .\" software must be clearly marked as such, and if the derived work is .\" incompatible with the protocol description in the RFC file, it must be .\" called by a name other than "ssh" or "Secure Shell". .\" .\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. .\" Copyright (c) 1999 Aaron Campbell. All rights reserved. .\" Copyright (c) 1999 Theo de Raadt. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.214 2015/07/30 00:01:34 djm Exp $ +.\" $OpenBSD: ssh_config.5,v 1.215 2015/08/14 15:32:41 jmc Exp $ .\" $FreeBSD$ -.Dd $Mdocdate: July 30 2015 $ +.Dd $Mdocdate: August 14 2015 $ .Dt SSH_CONFIG 5 .Os .Sh NAME .Nm ssh_config .Nd OpenSSH SSH client configuration files .Sh SYNOPSIS .Nm ~/.ssh/config .Nm /etc/ssh/ssh_config .Sh DESCRIPTION .Xr ssh 1 obtains configuration data from the following sources in the following order: .Pp .Bl -enum -offset indent -compact .It command-line options .It user's configuration file .Pq Pa ~/.ssh/config .It system-wide configuration file .Pq Pa /etc/ssh/ssh_config .El .Pp For each parameter, the first obtained value will be used. The configuration files contain sections separated by .Dq Host specifications, and that section is only applied for hosts that match one of the patterns given in the specification. The matched host name is usually the one given on the command line (see the .Cm CanonicalizeHostname option for exceptions.) .Pp Since the first obtained value for each parameter is used, more host-specific declarations should be given near the beginning of the file, and general defaults at the end. .Pp The configuration file has the following format: .Pp Empty lines and lines starting with .Ql # are comments. Otherwise a line is of the format .Dq keyword arguments . Configuration options may be separated by whitespace or optional whitespace and exactly one .Ql = ; the latter format is useful to avoid the need to quote whitespace when specifying configuration options using the .Nm ssh , .Nm scp , and .Nm sftp .Fl o option. Arguments may optionally be enclosed in double quotes .Pq \&" in order to represent arguments containing spaces. .Pp The possible keywords and their meanings are as follows (note that keywords are case-insensitive and arguments are case-sensitive): .Bl -tag -width Ds .It Cm Host Restricts the following declarations (up to the next .Cm Host or .Cm Match keyword) to be only for those hosts that match one of the patterns given after the keyword. If more than one pattern is provided, they should be separated by whitespace. A single .Ql * as a pattern can be used to provide global defaults for all hosts. The host is usually the .Ar hostname argument given on the command line (see the .Cm CanonicalizeHostname option for exceptions.) .Pp A pattern entry may be negated by prefixing it with an exclamation mark .Pq Sq !\& . If a negated entry is matched, then the .Cm Host entry is ignored, regardless of whether any other patterns on the line match. Negated matches are therefore useful to provide exceptions for wildcard matches. .Pp See .Sx PATTERNS for more information on patterns. .It Cm Match Restricts the following declarations (up to the next .Cm Host or .Cm Match keyword) to be used only when the conditions following the .Cm Match keyword are satisfied. Match conditions are specified using one or more critera or the single token .Cm all which always matches. The available criteria keywords are: .Cm canonical , .Cm exec , .Cm host , .Cm originalhost , .Cm user , and .Cm localuser . The .Cm all criteria must appear alone or immediately after .Cm canonical . Other criteria may be combined arbitrarily. All criteria but .Cm all and .Cm canonical require an argument. Criteria may be negated by prepending an exclamation mark .Pq Sq !\& . .Pp The .Cm canonical keyword matches only when the configuration file is being re-parsed after hostname canonicalization (see the .Cm CanonicalizeHostname option.) This may be useful to specify conditions that work with canonical host names only. The .Cm exec keyword executes the specified command under the user's shell. If the command returns a zero exit status then the condition is considered true. Commands containing whitespace characters must be quoted. The following character sequences in the command will be expanded prior to execution: .Ql %L will be substituted by the first component of the local host name, .Ql %l will be substituted by the local host name (including any domain name), .Ql %h will be substituted by the target host name, .Ql %n will be substituted by the original target host name specified on the command-line, .Ql %p the destination port, .Ql %r by the remote login username, and .Ql %u by the username of the user running .Xr ssh 1 . .Pp The other keywords' criteria must be single entries or comma-separated lists and may use the wildcard and negation operators described in the .Sx PATTERNS section. The criteria for the .Cm host keyword are matched against the target hostname, after any substitution by the .Cm Hostname or .Cm CanonicalizeHostname options. The .Cm originalhost keyword matches against the hostname as it was specified on the command-line. The .Cm user keyword matches against the target username on the remote host. The .Cm localuser keyword matches against the name of the local user running .Xr ssh 1 (this keyword may be useful in system-wide .Nm files). .It Cm AddressFamily Specifies which address family to use when connecting. Valid arguments are .Dq any , .Dq inet (use IPv4 only), or .Dq inet6 (use IPv6 only). .It Cm BatchMode If set to .Dq yes , passphrase/password querying will be disabled. This option is useful in scripts and other batch jobs where no user is present to supply the password. The argument must be .Dq yes or .Dq no . The default is .Dq no . .It Cm BindAddress Use the specified address on the local machine as the source address of the connection. Only useful on systems with more than one address. Note that this option does not work if .Cm UsePrivilegedPort is set to .Dq yes . .It Cm CanonicalDomains When .Cm CanonicalizeHostname is enabled, this option specifies the list of domain suffixes in which to search for the specified destination host. .It Cm CanonicalizeFallbackLocal Specifies whether to fail with an error when hostname canonicalization fails. The default, .Dq yes , will attempt to look up the unqualified hostname using the system resolver's search rules. A value of .Dq no will cause .Xr ssh 1 to fail instantly if .Cm CanonicalizeHostname is enabled and the target hostname cannot be found in any of the domains specified by .Cm CanonicalDomains . .It Cm CanonicalizeHostname Controls whether explicit hostname canonicalization is performed. The default, .Dq no , is not to perform any name rewriting and let the system resolver handle all hostname lookups. If set to .Dq yes then, for connections that do not use a .Cm ProxyCommand , .Xr ssh 1 will attempt to canonicalize the hostname specified on the command line using the .Cm CanonicalDomains suffixes and .Cm CanonicalizePermittedCNAMEs rules. If .Cm CanonicalizeHostname is set to .Dq always , then canonicalization is applied to proxied connections too. .Pp If this option is enabled, then the configuration files are processed again using the new target name to pick up any new configuration in matching .Cm Host and .Cm Match stanzas. .It Cm CanonicalizeMaxDots Specifies the maximum number of dot characters in a hostname before canonicalization is disabled. The default, .Dq 1 , allows a single dot (i.e. hostname.subdomain). .It Cm CanonicalizePermittedCNAMEs Specifies rules to determine whether CNAMEs should be followed when canonicalizing hostnames. The rules consist of one or more arguments of .Ar source_domain_list : Ns Ar target_domain_list , where .Ar source_domain_list is a pattern-list of domains that may follow CNAMEs in canonicalization, and .Ar target_domain_list is a pattern-list of domains that they may resolve to. .Pp For example, .Dq *.a.example.com:*.b.example.com,*.c.example.com will allow hostnames matching .Dq *.a.example.com to be canonicalized to names in the .Dq *.b.example.com or .Dq *.c.example.com domains. .It Cm ChallengeResponseAuthentication Specifies whether to use challenge-response authentication. The argument to this keyword must be .Dq yes or .Dq no . The default is .Dq yes . .It Cm CheckHostIP If this flag is set to .Dq yes , .Xr ssh 1 will additionally check the host IP address in the .Pa known_hosts file. This allows ssh to detect if a host key changed due to DNS spoofing and will add addresses of destination hosts to .Pa ~/.ssh/known_hosts in the process, regardless of the setting of .Cm StrictHostKeyChecking . If the option is set to .Dq no , the check will not be executed. The default is .Dq no . .It Cm Cipher Specifies the cipher to use for encrypting the session in protocol version 1. Currently, .Dq blowfish , .Dq 3des , and .Dq des are supported. .Ar des is only supported in the .Xr ssh 1 client for interoperability with legacy protocol 1 implementations that do not support the .Ar 3des cipher. Its use is strongly discouraged due to cryptographic weaknesses. The default is .Dq 3des . .It Cm Ciphers Specifies the ciphers allowed for protocol version 2 in order of preference. Multiple ciphers must be comma-separated. If the specified value begins with a .Sq + character, then the specified ciphers will be appended to the default set instead of replacing them. .Pp The supported ciphers are: .Pp .Bl -item -compact -offset indent .It 3des-cbc .It aes128-cbc .It aes192-cbc .It aes256-cbc .It aes128-ctr .It aes192-ctr .It aes256-ctr .It aes128-gcm@openssh.com .It aes256-gcm@openssh.com .It arcfour .It arcfour128 .It arcfour256 .It blowfish-cbc .It cast128-cbc .It chacha20-poly1305@openssh.com .El .Pp The default is: .Bd -literal -offset indent +chacha20-poly1305@openssh.com, aes128-ctr,aes192-ctr,aes256-ctr, aes128-gcm@openssh.com,aes256-gcm@openssh.com, -chacha20-poly1305@openssh.com, arcfour256,arcfour128, aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc, aes192-cbc,aes256-cbc,arcfour .Ed .Pp The list of available ciphers may also be obtained using the .Fl Q option of .Xr ssh 1 with an argument of .Dq cipher . .It Cm ClearAllForwardings Specifies that all local, remote, and dynamic port forwardings specified in the configuration files or on the command line be cleared. This option is primarily useful when used from the .Xr ssh 1 command line to clear port forwardings set in configuration files, and is automatically set by .Xr scp 1 and .Xr sftp 1 . The argument must be .Dq yes or .Dq no . The default is .Dq no . .It Cm Compression Specifies whether to use compression. The argument must be .Dq yes or .Dq no . The default is .Dq no . .It Cm CompressionLevel Specifies the compression level to use if compression is enabled. The argument must be an integer from 1 (fast) to 9 (slow, best). The default level is 6, which is good for most applications. The meaning of the values is the same as in .Xr gzip 1 . Note that this option applies to protocol version 1 only. .It Cm ConnectionAttempts Specifies the number of tries (one per second) to make before exiting. The argument must be an integer. This may be useful in scripts if the connection sometimes fails. The default is 1. .It Cm ConnectTimeout Specifies the timeout (in seconds) used when connecting to the SSH server, instead of using the default system TCP timeout. This value is used only when the target is down or really unreachable, not when it refuses the connection. .It Cm ControlMaster Enables the sharing of multiple sessions over a single network connection. When set to .Dq yes , .Xr ssh 1 will listen for connections on a control socket specified using the .Cm ControlPath argument. Additional sessions can connect to this socket using the same .Cm ControlPath with .Cm ControlMaster set to .Dq no (the default). These sessions will try to reuse the master instance's network connection rather than initiating new ones, but will fall back to connecting normally if the control socket does not exist, or is not listening. .Pp Setting this to .Dq ask will cause ssh to listen for control connections, but require confirmation using .Xr ssh-askpass 1 . If the .Cm ControlPath cannot be opened, ssh will continue without connecting to a master instance. .Pp X11 and .Xr ssh-agent 1 forwarding is supported over these multiplexed connections, however the display and agent forwarded will be the one belonging to the master connection i.e. it is not possible to forward multiple displays or agents. .Pp Two additional options allow for opportunistic multiplexing: try to use a master connection but fall back to creating a new one if one does not already exist. These options are: .Dq auto and .Dq autoask . The latter requires confirmation like the .Dq ask option. .It Cm ControlPath Specify the path to the control socket used for connection sharing as described in the .Cm ControlMaster section above or the string .Dq none to disable connection sharing. In the path, .Ql %L will be substituted by the first component of the local host name, .Ql %l will be substituted by the local host name (including any domain name), .Ql %h will be substituted by the target host name, .Ql %n will be substituted by the original target host name specified on the command line, .Ql %p the destination port, .Ql %r by the remote login username, .Ql %u by the username of the user running .Xr ssh 1 , and .Ql \&%C by a hash of the concatenation: %l%h%p%r. It is recommended that any .Cm ControlPath used for opportunistic connection sharing include at least %h, %p, and %r (or alternatively %C) and be placed in a directory that is not writable by other users. This ensures that shared connections are uniquely identified. .It Cm ControlPersist When used in conjunction with .Cm ControlMaster , specifies that the master connection should remain open in the background (waiting for future client connections) after the initial client connection has been closed. If set to .Dq no , then the master connection will not be placed into the background, and will close as soon as the initial client connection is closed. If set to .Dq yes or .Dq 0 , then the master connection will remain in the background indefinitely (until killed or closed via a mechanism such as the .Xr ssh 1 .Dq Fl O No exit option). If set to a time in seconds, or a time in any of the formats documented in .Xr sshd_config 5 , then the backgrounded master connection will automatically terminate after it has remained idle (with no client connections) for the specified time. .It Cm DynamicForward Specifies that a TCP port on the local machine be forwarded over the secure channel, and the application protocol is then used to determine where to connect to from the remote machine. .Pp The argument must be .Sm off .Oo Ar bind_address : Oc Ar port . .Sm on IPv6 addresses can be specified by enclosing addresses in square brackets. By default, the local port is bound in accordance with the .Cm GatewayPorts setting. However, an explicit .Ar bind_address may be used to bind the connection to a specific address. The .Ar bind_address of .Dq localhost indicates that the listening port be bound for local use only, while an empty address or .Sq * indicates that the port should be available from all interfaces. .Pp Currently the SOCKS4 and SOCKS5 protocols are supported, and .Xr ssh 1 will act as a SOCKS server. Multiple forwardings may be specified, and additional forwardings can be given on the command line. Only the superuser can forward privileged ports. .It Cm EnableSSHKeysign Setting this option to .Dq yes in the global client configuration file .Pa /etc/ssh/ssh_config enables the use of the helper program .Xr ssh-keysign 8 during .Cm HostbasedAuthentication . The argument must be .Dq yes or .Dq no . The default is .Dq no . This option should be placed in the non-hostspecific section. See .Xr ssh-keysign 8 for more information. .It Cm EscapeChar Sets the escape character (default: .Ql ~ ) . The escape character can also be set on the command line. The argument should be a single character, .Ql ^ followed by a letter, or .Dq none to disable the escape character entirely (making the connection transparent for binary data). .It Cm ExitOnForwardFailure Specifies whether .Xr ssh 1 should terminate the connection if it cannot set up all requested dynamic, tunnel, local, and remote port forwardings. The argument must be .Dq yes or .Dq no . The default is .Dq no . .It Cm FingerprintHash Specifies the hash algorithm used when displaying key fingerprints. Valid options are: .Dq md5 and .Dq sha256 . The default is .Dq sha256 . .It Cm ForwardAgent Specifies whether the connection to the authentication agent (if any) will be forwarded to the remote machine. The argument must be .Dq yes or .Dq no . The default is .Dq no . .Pp Agent forwarding should be enabled with caution. Users with the ability to bypass file permissions on the remote host (for the agent's Unix-domain socket) can access the local agent through the forwarded connection. An attacker cannot obtain key material from the agent, however they can perform operations on the keys that enable them to authenticate using the identities loaded into the agent. .It Cm ForwardX11 Specifies whether X11 connections will be automatically redirected over the secure channel and .Ev DISPLAY set. The argument must be .Dq yes or .Dq no . The default is .Dq no . .Pp X11 forwarding should be enabled with caution. Users with the ability to bypass file permissions on the remote host (for the user's X11 authorization database) can access the local X11 display through the forwarded connection. An attacker may then be able to perform activities such as keystroke monitoring if the .Cm ForwardX11Trusted option is also enabled. .It Cm ForwardX11Timeout Specify a timeout for untrusted X11 forwarding using the format described in the TIME FORMATS section of .Xr sshd_config 5 . X11 connections received by .Xr ssh 1 after this time will be refused. The default is to disable untrusted X11 forwarding after twenty minutes has elapsed. .It Cm ForwardX11Trusted If this option is set to .Dq yes , remote X11 clients will have full access to the original X11 display. .Pp If this option is set to .Dq no , remote X11 clients will be considered untrusted and prevented from stealing or tampering with data belonging to trusted X11 clients. Furthermore, the .Xr xauth 1 token used for the session will be set to expire after 20 minutes. Remote clients will be refused access after this time. .Pp The default is .Dq no . .Pp See the X11 SECURITY extension specification for full details on the restrictions imposed on untrusted clients. .It Cm GatewayPorts Specifies whether remote hosts are allowed to connect to local forwarded ports. By default, .Xr ssh 1 binds local port forwardings to the loopback address. This prevents other remote hosts from connecting to forwarded ports. .Cm GatewayPorts can be used to specify that ssh should bind local port forwardings to the wildcard address, thus allowing remote hosts to connect to forwarded ports. The argument must be .Dq yes or .Dq no . The default is .Dq no . .It Cm GlobalKnownHostsFile Specifies one or more files to use for the global host key database, separated by whitespace. The default is .Pa /etc/ssh/ssh_known_hosts , .Pa /etc/ssh/ssh_known_hosts2 . .It Cm GSSAPIAuthentication Specifies whether user authentication based on GSSAPI is allowed. The default is .Dq no . Note that this option applies to protocol version 2 only. .It Cm GSSAPIDelegateCredentials Forward (delegate) credentials to the server. The default is .Dq no . Note that this option applies to protocol version 2 only. .It Cm HashKnownHosts Indicates that .Xr ssh 1 should hash host names and addresses when they are added to .Pa ~/.ssh/known_hosts . These hashed names may be used normally by .Xr ssh 1 and .Xr sshd 8 , but they do not reveal identifying information should the file's contents be disclosed. The default is .Dq no . Note that existing names and addresses in known hosts files will not be converted automatically, but may be manually hashed using .Xr ssh-keygen 1 . .It Cm HostbasedAuthentication Specifies whether to try rhosts based authentication with public key authentication. The argument must be .Dq yes or .Dq no . The default is .Dq no . This option applies to protocol version 2 only and is similar to .Cm RhostsRSAAuthentication . .It Cm HostbasedKeyTypes Specifies the key types that will be used for hostbased authentication as a comma-separated pattern list. Alternately if the specified value begins with a .Sq + character, then the specified key types will be appended to the default set instead of replacing them. The default for this option is: .Bd -literal -offset 3n ecdsa-sha2-nistp256-cert-v01@openssh.com, ecdsa-sha2-nistp384-cert-v01@openssh.com, ecdsa-sha2-nistp521-cert-v01@openssh.com, ssh-ed25519-cert-v01@openssh.com, ssh-rsa-cert-v01@openssh.com, ssh-dss-cert-v01@openssh.com, ecdsa-sha2-nistp256,ecdsa-sha2-nistp384, ecdsa-sha2-nistp521,ssh-ed25519, ssh-rsa,ssh-dss .Ed .Pp The .Fl Q option of .Xr ssh 1 may be used to list supported key types. .It Cm HostKeyAlgorithms Specifies the protocol version 2 host key algorithms that the client wants to use in order of preference. Alternately if the specified value begins with a .Sq + character, then the specified key types will be appended to the default set instead of replacing them. The default for this option is: .Bd -literal -offset 3n ecdsa-sha2-nistp256-cert-v01@openssh.com, ecdsa-sha2-nistp384-cert-v01@openssh.com, ecdsa-sha2-nistp521-cert-v01@openssh.com, ssh-ed25519-cert-v01@openssh.com, ssh-rsa-cert-v01@openssh.com, ssh-dss-cert-v01@openssh.com, ecdsa-sha2-nistp256,ecdsa-sha2-nistp384, ecdsa-sha2-nistp521,ssh-ed25519, ssh-rsa,ssh-dss .Ed .Pp If hostkeys are known for the destination host then this default is modified to prefer their algorithms. .Pp The list of available key types may also be obtained using the .Fl Q option of .Xr ssh 1 with an argument of .Dq key . .It Cm HostKeyAlias Specifies an alias that should be used instead of the real host name when looking up or saving the host key in the host key database files. This option is useful for tunneling SSH connections or for multiple servers running on a single host. .It Cm HostName Specifies the real host name to log into. This can be used to specify nicknames or abbreviations for hosts. If the hostname contains the character sequence .Ql %h , then this will be replaced with the host name specified on the command line (this is useful for manipulating unqualified names). The character sequence .Ql %% will be replaced by a single .Ql % character, which may be used when specifying IPv6 link-local addresses. .Pp The default is the name given on the command line. Numeric IP addresses are also permitted (both on the command line and in .Cm HostName specifications). .It Cm IdentitiesOnly Specifies that .Xr ssh 1 should only use the authentication identity files configured in the .Nm files, even if .Xr ssh-agent 1 or a .Cm PKCS11Provider offers more identities. The argument to this keyword must be .Dq yes or .Dq no . This option is intended for situations where ssh-agent offers many different identities. The default is .Dq no . .It Cm IdentityFile Specifies a file from which the user's DSA, ECDSA, Ed25519 or RSA authentication identity is read. The default is .Pa ~/.ssh/identity for protocol version 1, and .Pa ~/.ssh/id_dsa , .Pa ~/.ssh/id_ecdsa , .Pa ~/.ssh/id_ed25519 and .Pa ~/.ssh/id_rsa for protocol version 2. Additionally, any identities represented by the authentication agent will be used for authentication unless .Cm IdentitiesOnly is set. .Xr ssh 1 will try to load certificate information from the filename obtained by appending .Pa -cert.pub to the path of a specified .Cm IdentityFile . .Pp The file name may use the tilde syntax to refer to a user's home directory or one of the following escape characters: .Ql %d (local user's home directory), .Ql %u (local user name), .Ql %l (local host name), .Ql %h (remote host name) or .Ql %r (remote user name). .Pp It is possible to have multiple identity files specified in configuration files; all these identities will be tried in sequence. Multiple .Cm IdentityFile directives will add to the list of identities tried (this behaviour differs from that of other configuration directives). .Pp .Cm IdentityFile may be used in conjunction with .Cm IdentitiesOnly to select which identities in an agent are offered during authentication. .It Cm IgnoreUnknown Specifies a pattern-list of unknown options to be ignored if they are encountered in configuration parsing. This may be used to suppress errors if .Nm contains options that are unrecognised by .Xr ssh 1 . It is recommended that .Cm IgnoreUnknown be listed early in the configuration file as it will not be applied to unknown options that appear before it. .It Cm IPQoS Specifies the IPv4 type-of-service or DSCP class for connections. Accepted values are .Dq af11 , .Dq af12 , .Dq af13 , .Dq af21 , .Dq af22 , .Dq af23 , .Dq af31 , .Dq af32 , .Dq af33 , .Dq af41 , .Dq af42 , .Dq af43 , .Dq cs0 , .Dq cs1 , .Dq cs2 , .Dq cs3 , .Dq cs4 , .Dq cs5 , .Dq cs6 , .Dq cs7 , .Dq ef , .Dq lowdelay , .Dq throughput , .Dq reliability , or a numeric value. This option may take one or two arguments, separated by whitespace. If one argument is specified, it is used as the packet class unconditionally. If two values are specified, the first is automatically selected for interactive sessions and the second for non-interactive sessions. The default is .Dq lowdelay for interactive sessions and .Dq throughput for non-interactive sessions. .It Cm KbdInteractiveAuthentication Specifies whether to use keyboard-interactive authentication. The argument to this keyword must be .Dq yes or .Dq no . The default is .Dq yes . .It Cm KbdInteractiveDevices Specifies the list of methods to use in keyboard-interactive authentication. Multiple method names must be comma-separated. The default is to use the server specified list. The methods available vary depending on what the server supports. For an OpenSSH server, it may be zero or more of: .Dq bsdauth , .Dq pam , and .Dq skey . .It Cm KexAlgorithms Specifies the available KEX (Key Exchange) algorithms. Multiple algorithms must be comma-separated. Alternately if the specified value begins with a .Sq + character, then the specified methods will be appended to the default set instead of replacing them. The default is: .Bd -literal -offset indent curve25519-sha256@libssh.org, ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521, diffie-hellman-group-exchange-sha256, diffie-hellman-group-exchange-sha1, diffie-hellman-group14-sha1 .Ed .Pp The list of available key exchange algorithms may also be obtained using the .Fl Q option of .Xr ssh 1 with an argument of .Dq kex . .It Cm LocalCommand Specifies a command to execute on the local machine after successfully connecting to the server. The command string extends to the end of the line, and is executed with the user's shell. The following escape character substitutions will be performed: .Ql %d (local user's home directory), .Ql %h (remote host name), .Ql %l (local host name), .Ql %n (host name as provided on the command line), .Ql %p (remote port), .Ql %r (remote user name) or .Ql %u (local user name) or .Ql \&%C by a hash of the concatenation: %l%h%p%r. .Pp The command is run synchronously and does not have access to the session of the .Xr ssh 1 that spawned it. It should not be used for interactive commands. .Pp This directive is ignored unless .Cm PermitLocalCommand has been enabled. .It Cm LocalForward Specifies that a TCP port on the local machine be forwarded over the secure channel to the specified host and port from the remote machine. The first argument must be .Sm off .Oo Ar bind_address : Oc Ar port .Sm on and the second argument must be .Ar host : Ns Ar hostport . IPv6 addresses can be specified by enclosing addresses in square brackets. Multiple forwardings may be specified, and additional forwardings can be given on the command line. Only the superuser can forward privileged ports. By default, the local port is bound in accordance with the .Cm GatewayPorts setting. However, an explicit .Ar bind_address may be used to bind the connection to a specific address. The .Ar bind_address of .Dq localhost indicates that the listening port be bound for local use only, while an empty address or .Sq * indicates that the port should be available from all interfaces. .It Cm LogLevel Gives the verbosity level that is used when logging messages from .Xr ssh 1 . The possible values are: QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3. The default is INFO. DEBUG and DEBUG1 are equivalent. DEBUG2 and DEBUG3 each specify higher levels of verbose output. .It Cm MACs Specifies the MAC (message authentication code) algorithms in order of preference. The MAC algorithm is used in protocol version 2 for data integrity protection. Multiple algorithms must be comma-separated. If the specified value begins with a .Sq + character, then the specified algorithms will be appended to the default set instead of replacing them. .Pp The algorithms that contain .Dq -etm calculate the MAC after encryption (encrypt-then-mac). These are considered safer and their use recommended. .Pp The default is: .Bd -literal -offset indent umac-64-etm@openssh.com,umac-128-etm@openssh.com, hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com, umac-64@openssh.com,umac-128@openssh.com, hmac-sha2-256,hmac-sha2-512, hmac-md5-etm@openssh.com,hmac-sha1-etm@openssh.com, hmac-ripemd160-etm@openssh.com, hmac-sha1-96-etm@openssh.com,hmac-md5-96-etm@openssh.com, hmac-md5,hmac-sha1,hmac-ripemd160, hmac-sha1-96,hmac-md5-96 .Ed .Pp The list of available MAC algorithms may also be obtained using the .Fl Q option of .Xr ssh 1 with an argument of .Dq mac . .It Cm NoHostAuthenticationForLocalhost This option can be used if the home directory is shared across machines. In this case localhost will refer to a different machine on each of the machines and the user will get many warnings about changed host keys. However, this option disables host authentication for localhost. The argument to this keyword must be .Dq yes or .Dq no . The default is to check the host key for localhost. .It Cm NumberOfPasswordPrompts Specifies the number of password prompts before giving up. The argument to this keyword must be an integer. The default is 3. .It Cm PasswordAuthentication Specifies whether to use password authentication. The argument to this keyword must be .Dq yes or .Dq no . The default is .Dq yes . .It Cm PermitLocalCommand Allow local command execution via the .Ic LocalCommand option or using the .Ic !\& Ns Ar command escape sequence in .Xr ssh 1 . The argument must be .Dq yes or .Dq no . The default is .Dq no . .It Cm PKCS11Provider Specifies which PKCS#11 provider to use. The argument to this keyword is the PKCS#11 shared library .Xr ssh 1 should use to communicate with a PKCS#11 token providing the user's private RSA key. .It Cm Port Specifies the port number to connect on the remote host. The default is 22. .It Cm PreferredAuthentications Specifies the order in which the client should try protocol 2 authentication methods. This allows a client to prefer one method (e.g.\& .Cm keyboard-interactive ) over another method (e.g.\& .Cm password ) . The default is: .Bd -literal -offset indent gssapi-with-mic,hostbased,publickey, keyboard-interactive,password .Ed .It Cm Protocol Specifies the protocol versions .Xr ssh 1 should support in order of preference. The possible values are .Sq 1 and .Sq 2 . Multiple versions must be comma-separated. When this option is set to .Dq 2,1 .Nm ssh will try version 2 and fall back to version 1 if version 2 is not available. The default is .Sq 2 . .It Cm ProxyCommand Specifies the command to use to connect to the server. The command string extends to the end of the line, and is executed using the user's shell .Ql exec directive to avoid a lingering shell process. .Pp In the command string, any occurrence of .Ql %h will be substituted by the host name to connect, .Ql %p by the port, and .Ql %r by the remote user name. The command can be basically anything, and should read from its standard input and write to its standard output. It should eventually connect an .Xr sshd 8 server running on some machine, or execute .Ic sshd -i somewhere. Host key management will be done using the HostName of the host being connected (defaulting to the name typed by the user). Setting the command to .Dq none disables this option entirely. Note that .Cm CheckHostIP is not available for connects with a proxy command. .Pp This directive is useful in conjunction with .Xr nc 1 and its proxy support. For example, the following directive would connect via an HTTP proxy at 192.0.2.0: .Bd -literal -offset 3n ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p .Ed .It Cm ProxyUseFdpass Specifies that .Cm ProxyCommand will pass a connected file descriptor back to .Xr ssh 1 instead of continuing to execute and pass data. The default is .Dq no . .It Cm PubkeyAcceptedKeyTypes Specifies the key types that will be used for public key authentication as a comma-separated pattern list. Alternately if the specified value begins with a .Sq + character, then the key types after it will be appended to the default instead of replacing it. The default for this option is: .Bd -literal -offset 3n ecdsa-sha2-nistp256-cert-v01@openssh.com, ecdsa-sha2-nistp384-cert-v01@openssh.com, ecdsa-sha2-nistp521-cert-v01@openssh.com, ssh-ed25519-cert-v01@openssh.com, ssh-rsa-cert-v01@openssh.com, ssh-dss-cert-v01@openssh.com, ecdsa-sha2-nistp256,ecdsa-sha2-nistp384, ecdsa-sha2-nistp521,ssh-ed25519, ssh-rsa,ssh-dss .Ed .Pp The .Fl Q option of .Xr ssh 1 may be used to list supported key types. .It Cm PubkeyAuthentication Specifies whether to try public key authentication. The argument to this keyword must be .Dq yes or .Dq no . The default is .Dq yes . This option applies to protocol version 2 only. .It Cm RekeyLimit Specifies the maximum amount of data that may be transmitted before the session key is renegotiated, optionally followed a maximum amount of time that may pass before the session key is renegotiated. The first argument is specified in bytes and may have a suffix of .Sq K , .Sq M , or .Sq G to indicate Kilobytes, Megabytes, or Gigabytes, respectively. The default is between .Sq 1G and .Sq 4G , depending on the cipher. The optional second value is specified in seconds and may use any of the units documented in the TIME FORMATS section of .Xr sshd_config 5 . The default value for .Cm RekeyLimit is .Dq default none , which means that rekeying is performed after the cipher's default amount of data has been sent or received and no time based rekeying is done. This option applies to protocol version 2 only. .It Cm RemoteForward Specifies that a TCP port on the remote machine be forwarded over the secure channel to the specified host and port from the local machine. The first argument must be .Sm off .Oo Ar bind_address : Oc Ar port .Sm on and the second argument must be .Ar host : Ns Ar hostport . IPv6 addresses can be specified by enclosing addresses in square brackets. Multiple forwardings may be specified, and additional forwardings can be given on the command line. Privileged ports can be forwarded only when logging in as root on the remote machine. .Pp If the .Ar port argument is .Ql 0 , the listen port will be dynamically allocated on the server and reported to the client at run time. .Pp If the .Ar bind_address is not specified, the default is to only bind to loopback addresses. If the .Ar bind_address is .Ql * or an empty string, then the forwarding is requested to listen on all interfaces. Specifying a remote .Ar bind_address will only succeed if the server's .Cm GatewayPorts option is enabled (see .Xr sshd_config 5 ) . .It Cm RequestTTY Specifies whether to request a pseudo-tty for the session. The argument may be one of: .Dq no (never request a TTY), .Dq yes (always request a TTY when standard input is a TTY), .Dq force (always request a TTY) or .Dq auto (request a TTY when opening a login session). This option mirrors the .Fl t and .Fl T flags for .Xr ssh 1 . .It Cm RevokedHostKeys Specifies revoked host public keys. Keys listed in this file will be refused for host authentication. Note that if this file does not exist or is not readable, then host authentication will be refused for all hosts. Keys may be specified as a text file, listing one public key per line, or as an OpenSSH Key Revocation List (KRL) as generated by .Xr ssh-keygen 1 . For more information on KRLs, see the KEY REVOCATION LISTS section in .Xr ssh-keygen 1 . .It Cm RhostsRSAAuthentication Specifies whether to try rhosts based authentication with RSA host authentication. The argument must be .Dq yes or .Dq no . The default is .Dq no . This option applies to protocol version 1 only and requires .Xr ssh 1 to be setuid root. .It Cm RSAAuthentication Specifies whether to try RSA authentication. The argument to this keyword must be .Dq yes or .Dq no . RSA authentication will only be attempted if the identity file exists, or an authentication agent is running. The default is .Dq yes . Note that this option applies to protocol version 1 only. .It Cm SendEnv Specifies what variables from the local .Xr environ 7 should be sent to the server. Note that environment passing is only supported for protocol 2. The server must also support it, and the server must be configured to accept these environment variables. Note that the .Ev TERM environment variable is always sent whenever a pseudo-terminal is requested as it is required by the protocol. Refer to .Cm AcceptEnv in .Xr sshd_config 5 for how to configure the server. Variables are specified by name, which may contain wildcard characters. Multiple environment variables may be separated by whitespace or spread across multiple .Cm SendEnv directives. The default is not to send any environment variables. .Pp See .Sx PATTERNS for more information on patterns. .It Cm ServerAliveCountMax Sets the number of server alive messages (see below) which may be sent without .Xr ssh 1 receiving any messages back from the server. If this threshold is reached while server alive messages are being sent, ssh will disconnect from the server, terminating the session. It is important to note that the use of server alive messages is very different from .Cm TCPKeepAlive (below). The server alive messages are sent through the encrypted channel and therefore will not be spoofable. The TCP keepalive option enabled by .Cm TCPKeepAlive is spoofable. The server alive mechanism is valuable when the client or server depend on knowing when a connection has become inactive. .Pp The default value is 3. If, for example, .Cm ServerAliveInterval (see below) is set to 15 and .Cm ServerAliveCountMax is left at the default, if the server becomes unresponsive, ssh will disconnect after approximately 45 seconds. This option applies to protocol version 2 only. .It Cm ServerAliveInterval Sets a timeout interval in seconds after which if no data has been received from the server, .Xr ssh 1 will send a message through the encrypted channel to request a response from the server. The default is 0, indicating that these messages will not be sent to the server. This option applies to protocol version 2 only. .It Cm StreamLocalBindMask Sets the octal file creation mode mask .Pq umask used when creating a Unix-domain socket file for local or remote port forwarding. This option is only used for port forwarding to a Unix-domain socket file. .Pp The default value is 0177, which creates a Unix-domain socket file that is readable and writable only by the owner. Note that not all operating systems honor the file mode on Unix-domain socket files. .It Cm StreamLocalBindUnlink Specifies whether to remove an existing Unix-domain socket file for local or remote port forwarding before creating a new one. If the socket file already exists and .Cm StreamLocalBindUnlink is not enabled, .Nm ssh will be unable to forward the port to the Unix-domain socket file. This option is only used for port forwarding to a Unix-domain socket file. .Pp The argument must be .Dq yes or .Dq no . The default is .Dq no . .It Cm StrictHostKeyChecking If this flag is set to .Dq yes , .Xr ssh 1 will never automatically add host keys to the .Pa ~/.ssh/known_hosts file, and refuses to connect to hosts whose host key has changed. This provides maximum protection against trojan horse attacks, though it can be annoying when the .Pa /etc/ssh/ssh_known_hosts file is poorly maintained or when connections to new hosts are frequently made. This option forces the user to manually add all new hosts. If this flag is set to .Dq no , ssh will automatically add new host keys to the user known hosts files. If this flag is set to .Dq ask , new host keys will be added to the user known host files only after the user has confirmed that is what they really want to do, and ssh will refuse to connect to hosts whose host key has changed. The host keys of known hosts will be verified automatically in all cases. The argument must be .Dq yes , .Dq no , or .Dq ask . The default is .Dq ask . .It Cm TCPKeepAlive Specifies whether the system should send TCP keepalive messages to the other side. If they are sent, death of the connection or crash of one of the machines will be properly noticed. However, this means that connections will die if the route is down temporarily, and some people find it annoying. .Pp The default is .Dq yes (to send TCP keepalive messages), and the client will notice if the network goes down or the remote host dies. This is important in scripts, and many users want it too. .Pp To disable TCP keepalive messages, the value should be set to .Dq no . .It Cm Tunnel Request .Xr tun 4 device forwarding between the client and the server. The argument must be .Dq yes , .Dq point-to-point (layer 3), .Dq ethernet (layer 2), or .Dq no . Specifying .Dq yes requests the default tunnel mode, which is .Dq point-to-point . The default is .Dq no . .It Cm TunnelDevice Specifies the .Xr tun 4 devices to open on the client .Pq Ar local_tun and the server .Pq Ar remote_tun . .Pp The argument must be .Sm off .Ar local_tun Op : Ar remote_tun . .Sm on The devices may be specified by numerical ID or the keyword .Dq any , which uses the next available tunnel device. If .Ar remote_tun is not specified, it defaults to .Dq any . The default is .Dq any:any . .It Cm UpdateHostKeys Specifies whether .Xr ssh 1 should accept notifications of additional hostkeys from the server sent after authentication has completed and add them to .Cm UserKnownHostsFile . The argument must be .Dq yes , .Dq no (the default) or .Dq ask . Enabling this option allows learning alternate hostkeys for a server and supports graceful key rotation by allowing a server to send replacement public keys before old ones are removed. Additional hostkeys are only accepted if the key used to authenticate the host was already trusted or explicity accepted by the user. If .Cm UpdateHostKeys is set to .Dq ask , then the user is asked to confirm the modifications to the known_hosts file. Confirmation is currently incompatible with .Cm ControlPersist , and will be disabled if it is enabled. .Pp Presently, only .Xr sshd 8 from OpenSSH 6.8 and greater support the .Dq hostkeys@openssh.com protocol extension used to inform the client of all the server's hostkeys. .It Cm UsePrivilegedPort Specifies whether to use a privileged port for outgoing connections. The argument must be .Dq yes or .Dq no . The default is .Dq no . If set to .Dq yes , .Xr ssh 1 must be setuid root. Note that this option must be set to .Dq yes for .Cm RhostsRSAAuthentication with older servers. .It Cm User Specifies the user to log in as. This can be useful when a different user name is used on different machines. This saves the trouble of having to remember to give the user name on the command line. .It Cm UserKnownHostsFile Specifies one or more files to use for the user host key database, separated by whitespace. The default is .Pa ~/.ssh/known_hosts , .Pa ~/.ssh/known_hosts2 . .It Cm VerifyHostKeyDNS Specifies whether to verify the remote key using DNS and SSHFP resource records. If this option is set to .Dq yes , the client will implicitly trust keys that match a secure fingerprint from DNS. Insecure fingerprints will be handled as if this option was set to .Dq ask . If this option is set to .Dq ask , information on fingerprint match will be displayed, but the user will still need to confirm new host keys according to the .Cm StrictHostKeyChecking option. The argument must be .Dq yes , .Dq no , or .Dq ask . The default is .Dq yes if compiled with LDNS and .Dq no otherwise. Note that this option applies to protocol version 2 only. .Pp See also VERIFYING HOST KEYS in .Xr ssh 1 . .It Cm VersionAddendum Specifies a string to append to the regular version string to identify OS- or site-specific modifications. The default is -.Dq FreeBSD-20160119 . +.Dq FreeBSD-20160121 . The value .Dq none may be used to disable this. .It Cm VisualHostKey If this flag is set to .Dq yes , an ASCII art representation of the remote host key fingerprint is printed in addition to the fingerprint string at login and for unknown host keys. If this flag is set to .Dq no , no fingerprint strings are printed at login and only the fingerprint string will be printed for unknown host keys. The default is .Dq no . .It Cm XAuthLocation Specifies the full pathname of the .Xr xauth 1 program. The default is .Pa /usr/local/bin/xauth . .El .Sh PATTERNS A .Em pattern consists of zero or more non-whitespace characters, .Sq * (a wildcard that matches zero or more characters), or .Sq ?\& (a wildcard that matches exactly one character). For example, to specify a set of declarations for any host in the .Dq .co.uk set of domains, the following pattern could be used: .Pp .Dl Host *.co.uk .Pp The following pattern would match any host in the 192.168.0.[0-9] network range: .Pp .Dl Host 192.168.0.? .Pp A .Em pattern-list is a comma-separated list of patterns. Patterns within pattern-lists may be negated by preceding them with an exclamation mark .Pq Sq !\& . For example, to allow a key to be used from anywhere within an organization except from the .Dq dialup pool, the following entry (in authorized_keys) could be used: .Pp .Dl from=\&"!*.dialup.example.com,*.example.com\&" .Sh FILES .Bl -tag -width Ds .It Pa ~/.ssh/config This is the per-user configuration file. The format of this file is described above. This file is used by the SSH client. Because of the potential for abuse, this file must have strict permissions: read/write for the user, and not accessible by others. .It Pa /etc/ssh/ssh_config Systemwide configuration file. This file provides defaults for those values that are not specified in the user's configuration file, and for those users who do not have a configuration file. This file must be world-readable. .El .Sh SEE ALSO .Xr ssh 1 .Sh AUTHORS OpenSSH is a derivative of the original and free ssh 1.2.12 release by Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo de Raadt and Dug Song removed many bugs, re-added newer features and created OpenSSH. Markus Friedl contributed the support for SSH protocol versions 1.5 and 2.0. Index: head/crypto/openssh/sshbuf-getput-crypto.c =================================================================== --- head/crypto/openssh/sshbuf-getput-crypto.c (revision 294495) +++ head/crypto/openssh/sshbuf-getput-crypto.c (revision 294496) @@ -1,224 +1,224 @@ -/* $OpenBSD: sshbuf-getput-crypto.c,v 1.4 2015/01/14 15:02:39 djm Exp $ */ +/* $OpenBSD: sshbuf-getput-crypto.c,v 1.5 2016/01/12 23:42:54 djm Exp $ */ /* * Copyright (c) 2011 Damien Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define SSHBUF_INTERNAL #include "includes.h" #include #include #include #include #include #ifdef OPENSSL_HAS_ECC # include #endif /* OPENSSL_HAS_ECC */ #include "ssherr.h" #include "sshbuf.h" int sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM *v) { const u_char *d; size_t len; int r; if ((r = sshbuf_get_bignum2_bytes_direct(buf, &d, &len)) != 0) return r; if (v != NULL && BN_bin2bn(d, len, v) == NULL) return SSH_ERR_ALLOC_FAIL; return 0; } int sshbuf_get_bignum1(struct sshbuf *buf, BIGNUM *v) { const u_char *d = sshbuf_ptr(buf); u_int16_t len_bits; size_t len_bytes; /* Length in bits */ if (sshbuf_len(buf) < 2) return SSH_ERR_MESSAGE_INCOMPLETE; len_bits = PEEK_U16(d); len_bytes = (len_bits + 7) >> 3; if (len_bytes > SSHBUF_MAX_BIGNUM) return SSH_ERR_BIGNUM_TOO_LARGE; if (sshbuf_len(buf) < 2 + len_bytes) return SSH_ERR_MESSAGE_INCOMPLETE; if (v != NULL && BN_bin2bn(d + 2, len_bytes, v) == NULL) return SSH_ERR_ALLOC_FAIL; if (sshbuf_consume(buf, 2 + len_bytes) != 0) { SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); SSHBUF_ABORT(); return SSH_ERR_INTERNAL_ERROR; } return 0; } #ifdef OPENSSL_HAS_ECC static int get_ec(const u_char *d, size_t len, EC_POINT *v, const EC_GROUP *g) { /* Refuse overlong bignums */ if (len == 0 || len > SSHBUF_MAX_ECPOINT) return SSH_ERR_ECPOINT_TOO_LARGE; /* Only handle uncompressed points */ if (*d != POINT_CONVERSION_UNCOMPRESSED) return SSH_ERR_INVALID_FORMAT; if (v != NULL && EC_POINT_oct2point(g, v, d, len, NULL) != 1) return SSH_ERR_INVALID_FORMAT; /* XXX assumption */ return 0; } int sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g) { const u_char *d; size_t len; int r; if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) return r; if ((r = get_ec(d, len, v, g)) != 0) return r; /* Skip string */ if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) { /* Shouldn't happen */ SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); SSHBUF_ABORT(); return SSH_ERR_INTERNAL_ERROR; } return 0; } int sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v) { EC_POINT *pt = EC_POINT_new(EC_KEY_get0_group(v)); int r; const u_char *d; size_t len; if (pt == NULL) { SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL")); return SSH_ERR_ALLOC_FAIL; } if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) { EC_POINT_free(pt); return r; } if ((r = get_ec(d, len, pt, EC_KEY_get0_group(v))) != 0) { EC_POINT_free(pt); return r; } if (EC_KEY_set_public_key(v, pt) != 1) { EC_POINT_free(pt); return SSH_ERR_ALLOC_FAIL; /* XXX assumption */ } EC_POINT_free(pt); /* Skip string */ if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) { /* Shouldn't happen */ SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); SSHBUF_ABORT(); return SSH_ERR_INTERNAL_ERROR; } return 0; } #endif /* OPENSSL_HAS_ECC */ int sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v) { u_char d[SSHBUF_MAX_BIGNUM + 1]; int len = BN_num_bytes(v), prepend = 0, r; if (len < 0 || len > SSHBUF_MAX_BIGNUM) return SSH_ERR_INVALID_ARGUMENT; *d = '\0'; if (BN_bn2bin(v, d + 1) != len) return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */ /* If MSB is set, prepend a \0 */ if (len > 0 && (d[1] & 0x80) != 0) prepend = 1; if ((r = sshbuf_put_string(buf, d + 1 - prepend, len + prepend)) < 0) { - bzero(d, sizeof(d)); + explicit_bzero(d, sizeof(d)); return r; } - bzero(d, sizeof(d)); + explicit_bzero(d, sizeof(d)); return 0; } int sshbuf_put_bignum1(struct sshbuf *buf, const BIGNUM *v) { int r, len_bits = BN_num_bits(v); size_t len_bytes = (len_bits + 7) / 8; u_char d[SSHBUF_MAX_BIGNUM], *dp; if (len_bits < 0 || len_bytes > SSHBUF_MAX_BIGNUM) return SSH_ERR_INVALID_ARGUMENT; if (BN_bn2bin(v, d) != (int)len_bytes) return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */ if ((r = sshbuf_reserve(buf, len_bytes + 2, &dp)) < 0) { - bzero(d, sizeof(d)); + explicit_bzero(d, sizeof(d)); return r; } POKE_U16(dp, len_bits); if (len_bytes != 0) memcpy(dp + 2, d, len_bytes); - bzero(d, sizeof(d)); + explicit_bzero(d, sizeof(d)); return 0; } #ifdef OPENSSL_HAS_ECC int sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g) { u_char d[SSHBUF_MAX_ECPOINT]; BN_CTX *bn_ctx; size_t len; int ret; if ((bn_ctx = BN_CTX_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((len = EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, bn_ctx)) > SSHBUF_MAX_ECPOINT) { BN_CTX_free(bn_ctx); return SSH_ERR_INVALID_ARGUMENT; } if (EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED, d, len, bn_ctx) != len) { BN_CTX_free(bn_ctx); return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */ } BN_CTX_free(bn_ctx); ret = sshbuf_put_string(buf, d, len); - bzero(d, len); + explicit_bzero(d, len); return ret; } int sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v) { return sshbuf_put_ec(buf, EC_KEY_get0_public_key(v), EC_KEY_get0_group(v)); } #endif /* OPENSSL_HAS_ECC */ Index: head/crypto/openssh/sshbuf-misc.c =================================================================== --- head/crypto/openssh/sshbuf-misc.c (revision 294495) +++ head/crypto/openssh/sshbuf-misc.c (revision 294496) @@ -1,138 +1,138 @@ -/* $OpenBSD: sshbuf-misc.c,v 1.4 2015/03/24 20:03:44 markus Exp $ */ +/* $OpenBSD: sshbuf-misc.c,v 1.5 2015/10/05 17:11:21 djm Exp $ */ /* * Copyright (c) 2011 Damien Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "includes.h" #include #include #include #include #include #ifdef HAVE_STDINT_H #include #endif #include #include #include #include #include #include "ssherr.h" #define SSHBUF_INTERNAL #include "sshbuf.h" void sshbuf_dump_data(const void *s, size_t len, FILE *f) { size_t i, j; const u_char *p = (const u_char *)s; for (i = 0; i < len; i += 16) { fprintf(f, "%.4zu: ", i); for (j = i; j < i + 16; j++) { if (j < len) fprintf(f, "%02x ", p[j]); else fprintf(f, " "); } fprintf(f, " "); for (j = i; j < i + 16; j++) { if (j < len) { if (isascii(p[j]) && isprint(p[j])) fprintf(f, "%c", p[j]); else fprintf(f, "."); } } fprintf(f, "\n"); } } void sshbuf_dump(struct sshbuf *buf, FILE *f) { fprintf(f, "buffer %p len = %zu\n", buf, sshbuf_len(buf)); sshbuf_dump_data(sshbuf_ptr(buf), sshbuf_len(buf), f); } char * sshbuf_dtob16(struct sshbuf *buf) { size_t i, j, len = sshbuf_len(buf); const u_char *p = sshbuf_ptr(buf); char *ret; const char hex[] = "0123456789abcdef"; if (len == 0) return strdup(""); if (SIZE_MAX / 2 <= len || (ret = malloc(len * 2 + 1)) == NULL) return NULL; for (i = j = 0; i < len; i++) { ret[j++] = hex[(p[i] >> 4) & 0xf]; ret[j++] = hex[p[i] & 0xf]; } ret[j] = '\0'; return ret; } char * sshbuf_dtob64(struct sshbuf *buf) { size_t len = sshbuf_len(buf), plen; const u_char *p = sshbuf_ptr(buf); char *ret; int r; if (len == 0) return strdup(""); plen = ((len + 2) / 3) * 4 + 1; if (SIZE_MAX / 2 <= len || (ret = malloc(plen)) == NULL) return NULL; if ((r = b64_ntop(p, len, ret, plen)) == -1) { - bzero(ret, plen); + explicit_bzero(ret, plen); free(ret); return NULL; } return ret; } int sshbuf_b64tod(struct sshbuf *buf, const char *b64) { size_t plen = strlen(b64); int nlen, r; u_char *p; if (plen == 0) return 0; if ((p = malloc(plen)) == NULL) return SSH_ERR_ALLOC_FAIL; if ((nlen = b64_pton(b64, p, plen)) < 0) { - bzero(p, plen); + explicit_bzero(p, plen); free(p); return SSH_ERR_INVALID_FORMAT; } if ((r = sshbuf_put(buf, p, nlen)) < 0) { - bzero(p, plen); + explicit_bzero(p, plen); free(p); return r; } - bzero(p, plen); + explicit_bzero(p, plen); free(p); return 0; } Index: head/crypto/openssh/sshbuf.c =================================================================== --- head/crypto/openssh/sshbuf.c (revision 294495) +++ head/crypto/openssh/sshbuf.c (revision 294496) @@ -1,406 +1,406 @@ -/* $OpenBSD: sshbuf.c,v 1.3 2015/01/20 23:14:00 deraadt Exp $ */ +/* $OpenBSD: sshbuf.c,v 1.4 2015/10/05 17:11:21 djm Exp $ */ /* * Copyright (c) 2011 Damien Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define SSHBUF_INTERNAL #include "includes.h" #include /* roundup */ #include #include #include #include #include #include "ssherr.h" #include "sshbuf.h" static inline int sshbuf_check_sanity(const struct sshbuf *buf) { SSHBUF_TELL("sanity"); if (__predict_false(buf == NULL || (!buf->readonly && buf->d != buf->cd) || buf->refcount < 1 || buf->refcount > SSHBUF_REFS_MAX || buf->cd == NULL || (buf->dont_free && (buf->readonly || buf->parent != NULL)) || buf->max_size > SSHBUF_SIZE_MAX || buf->alloc > buf->max_size || buf->size > buf->alloc || buf->off > buf->size)) { /* Do not try to recover from corrupted buffer internals */ SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); signal(SIGSEGV, SIG_DFL); raise(SIGSEGV); return SSH_ERR_INTERNAL_ERROR; } return 0; } static void sshbuf_maybe_pack(struct sshbuf *buf, int force) { SSHBUF_DBG(("force %d", force)); SSHBUF_TELL("pre-pack"); if (buf->off == 0 || buf->readonly || buf->refcount > 1) return; if (force || (buf->off >= SSHBUF_PACK_MIN && buf->off >= buf->size / 2)) { memmove(buf->d, buf->d + buf->off, buf->size - buf->off); buf->size -= buf->off; buf->off = 0; SSHBUF_TELL("packed"); } } struct sshbuf * sshbuf_new(void) { struct sshbuf *ret; if ((ret = calloc(sizeof(*ret), 1)) == NULL) return NULL; ret->alloc = SSHBUF_SIZE_INIT; ret->max_size = SSHBUF_SIZE_MAX; ret->readonly = 0; ret->refcount = 1; ret->parent = NULL; if ((ret->cd = ret->d = calloc(1, ret->alloc)) == NULL) { free(ret); return NULL; } return ret; } struct sshbuf * sshbuf_from(const void *blob, size_t len) { struct sshbuf *ret; if (blob == NULL || len > SSHBUF_SIZE_MAX || (ret = calloc(sizeof(*ret), 1)) == NULL) return NULL; ret->alloc = ret->size = ret->max_size = len; ret->readonly = 1; ret->refcount = 1; ret->parent = NULL; ret->cd = blob; ret->d = NULL; return ret; } int sshbuf_set_parent(struct sshbuf *child, struct sshbuf *parent) { int r; if ((r = sshbuf_check_sanity(child)) != 0 || (r = sshbuf_check_sanity(parent)) != 0) return r; child->parent = parent; child->parent->refcount++; return 0; } struct sshbuf * sshbuf_fromb(struct sshbuf *buf) { struct sshbuf *ret; if (sshbuf_check_sanity(buf) != 0) return NULL; if ((ret = sshbuf_from(sshbuf_ptr(buf), sshbuf_len(buf))) == NULL) return NULL; if (sshbuf_set_parent(ret, buf) != 0) { sshbuf_free(ret); return NULL; } return ret; } void sshbuf_init(struct sshbuf *ret) { - bzero(ret, sizeof(*ret)); + explicit_bzero(ret, sizeof(*ret)); ret->alloc = SSHBUF_SIZE_INIT; ret->max_size = SSHBUF_SIZE_MAX; ret->readonly = 0; ret->dont_free = 1; ret->refcount = 1; if ((ret->cd = ret->d = calloc(1, ret->alloc)) == NULL) ret->alloc = 0; } void sshbuf_free(struct sshbuf *buf) { int dont_free = 0; if (buf == NULL) return; /* * The following will leak on insane buffers, but this is the safest * course of action - an invalid pointer or already-freed pointer may * have been passed to us and continuing to scribble over memory would * be bad. */ if (sshbuf_check_sanity(buf) != 0) return; /* * If we are a child, the free our parent to decrement its reference * count and possibly free it. */ if (buf->parent != NULL) { sshbuf_free(buf->parent); buf->parent = NULL; } /* * If we are a parent with still-extant children, then don't free just * yet. The last child's call to sshbuf_free should decrement our * refcount to 0 and trigger the actual free. */ buf->refcount--; if (buf->refcount > 0) return; dont_free = buf->dont_free; if (!buf->readonly) { - bzero(buf->d, buf->alloc); + explicit_bzero(buf->d, buf->alloc); free(buf->d); } - bzero(buf, sizeof(*buf)); + explicit_bzero(buf, sizeof(*buf)); if (!dont_free) free(buf); } void sshbuf_reset(struct sshbuf *buf) { u_char *d; if (buf->readonly || buf->refcount > 1) { /* Nonsensical. Just make buffer appear empty */ buf->off = buf->size; return; } if (sshbuf_check_sanity(buf) == 0) - bzero(buf->d, buf->alloc); + explicit_bzero(buf->d, buf->alloc); buf->off = buf->size = 0; if (buf->alloc != SSHBUF_SIZE_INIT) { if ((d = realloc(buf->d, SSHBUF_SIZE_INIT)) != NULL) { buf->cd = buf->d = d; buf->alloc = SSHBUF_SIZE_INIT; } } } size_t sshbuf_max_size(const struct sshbuf *buf) { return buf->max_size; } size_t sshbuf_alloc(const struct sshbuf *buf) { return buf->alloc; } const struct sshbuf * sshbuf_parent(const struct sshbuf *buf) { return buf->parent; } u_int sshbuf_refcount(const struct sshbuf *buf) { return buf->refcount; } int sshbuf_set_max_size(struct sshbuf *buf, size_t max_size) { size_t rlen; u_char *dp; int r; SSHBUF_DBG(("set max buf = %p len = %zu", buf, max_size)); if ((r = sshbuf_check_sanity(buf)) != 0) return r; if (max_size == buf->max_size) return 0; if (buf->readonly || buf->refcount > 1) return SSH_ERR_BUFFER_READ_ONLY; if (max_size > SSHBUF_SIZE_MAX) return SSH_ERR_NO_BUFFER_SPACE; /* pack and realloc if necessary */ sshbuf_maybe_pack(buf, max_size < buf->size); if (max_size < buf->alloc && max_size > buf->size) { if (buf->size < SSHBUF_SIZE_INIT) rlen = SSHBUF_SIZE_INIT; else rlen = roundup(buf->size, SSHBUF_SIZE_INC); if (rlen > max_size) rlen = max_size; - bzero(buf->d + buf->size, buf->alloc - buf->size); + explicit_bzero(buf->d + buf->size, buf->alloc - buf->size); SSHBUF_DBG(("new alloc = %zu", rlen)); if ((dp = realloc(buf->d, rlen)) == NULL) return SSH_ERR_ALLOC_FAIL; buf->cd = buf->d = dp; buf->alloc = rlen; } SSHBUF_TELL("new-max"); if (max_size < buf->alloc) return SSH_ERR_NO_BUFFER_SPACE; buf->max_size = max_size; return 0; } size_t sshbuf_len(const struct sshbuf *buf) { if (sshbuf_check_sanity(buf) != 0) return 0; return buf->size - buf->off; } size_t sshbuf_avail(const struct sshbuf *buf) { if (sshbuf_check_sanity(buf) != 0 || buf->readonly || buf->refcount > 1) return 0; return buf->max_size - (buf->size - buf->off); } const u_char * sshbuf_ptr(const struct sshbuf *buf) { if (sshbuf_check_sanity(buf) != 0) return NULL; return buf->cd + buf->off; } u_char * sshbuf_mutable_ptr(const struct sshbuf *buf) { if (sshbuf_check_sanity(buf) != 0 || buf->readonly || buf->refcount > 1) return NULL; return buf->d + buf->off; } int sshbuf_check_reserve(const struct sshbuf *buf, size_t len) { int r; if ((r = sshbuf_check_sanity(buf)) != 0) return r; if (buf->readonly || buf->refcount > 1) return SSH_ERR_BUFFER_READ_ONLY; SSHBUF_TELL("check"); /* Check that len is reasonable and that max_size + available < len */ if (len > buf->max_size || buf->max_size - len < buf->size - buf->off) return SSH_ERR_NO_BUFFER_SPACE; return 0; } int sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp) { size_t rlen, need; u_char *dp; int r; if (dpp != NULL) *dpp = NULL; SSHBUF_DBG(("reserve buf = %p len = %zu", buf, len)); if ((r = sshbuf_check_reserve(buf, len)) != 0) return r; /* * If the requested allocation appended would push us past max_size * then pack the buffer, zeroing buf->off. */ sshbuf_maybe_pack(buf, buf->size + len > buf->max_size); SSHBUF_TELL("reserve"); if (len + buf->size > buf->alloc) { /* * Prefer to alloc in SSHBUF_SIZE_INC units, but * allocate less if doing so would overflow max_size. */ need = len + buf->size - buf->alloc; rlen = roundup(buf->alloc + need, SSHBUF_SIZE_INC); SSHBUF_DBG(("need %zu initial rlen %zu", need, rlen)); if (rlen > buf->max_size) rlen = buf->alloc + need; SSHBUF_DBG(("adjusted rlen %zu", rlen)); if ((dp = realloc(buf->d, rlen)) == NULL) { SSHBUF_DBG(("realloc fail")); if (dpp != NULL) *dpp = NULL; return SSH_ERR_ALLOC_FAIL; } buf->alloc = rlen; buf->cd = buf->d = dp; if ((r = sshbuf_check_reserve(buf, len)) < 0) { /* shouldn't fail */ if (dpp != NULL) *dpp = NULL; return r; } } dp = buf->d + buf->size; buf->size += len; SSHBUF_TELL("done"); if (dpp != NULL) *dpp = dp; return 0; } int sshbuf_consume(struct sshbuf *buf, size_t len) { int r; SSHBUF_DBG(("len = %zu", len)); if ((r = sshbuf_check_sanity(buf)) != 0) return r; if (len == 0) return 0; if (len > sshbuf_len(buf)) return SSH_ERR_MESSAGE_INCOMPLETE; buf->off += len; SSHBUF_TELL("done"); return 0; } int sshbuf_consume_end(struct sshbuf *buf, size_t len) { int r; SSHBUF_DBG(("len = %zu", len)); if ((r = sshbuf_check_sanity(buf)) != 0) return r; if (len == 0) return 0; if (len > sshbuf_len(buf)) return SSH_ERR_MESSAGE_INCOMPLETE; buf->size -= len; SSHBUF_TELL("done"); return 0; } Index: head/crypto/openssh/sshconnect.c =================================================================== --- head/crypto/openssh/sshconnect.c (revision 294495) +++ head/crypto/openssh/sshconnect.c (revision 294496) @@ -1,1490 +1,1490 @@ -/* $OpenBSD: sshconnect.c,v 1.262 2015/05/28 05:41:29 dtucker Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.263 2015/08/20 22:32:42 deraadt Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved * Code to connect to a remote host, and to perform the client side of the * login (authentication) dialog. * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose. Any derived versions of this * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". */ #include "includes.h" __RCSID("$FreeBSD$"); #include /* roundup */ #include #include #include #include #ifdef HAVE_SYS_TIME_H # include #endif #include #include #include #include #include #include #include #ifdef HAVE_PATHS_H #include #endif #include #include #include #include #include #include #include #include "xmalloc.h" #include "key.h" #include "hostfile.h" #include "ssh.h" #include "rsa.h" #include "buffer.h" #include "packet.h" #include "uidswap.h" #include "compat.h" #include "key.h" #include "sshconnect.h" #include "hostfile.h" #include "log.h" #include "misc.h" #include "readconf.h" #include "atomicio.h" #include "dns.h" #include "roaming.h" #include "monitor_fdpass.h" #include "ssh2.h" #include "version.h" #include "authfile.h" #include "ssherr.h" char *client_version_string = NULL; char *server_version_string = NULL; Key *previous_host_key = NULL; static int matching_host_key_dns = 0; static pid_t proxy_command_pid = 0; /* import */ extern Options options; extern char *__progname; extern uid_t original_real_uid; extern uid_t original_effective_uid; static int show_other_keys(struct hostkeys *, Key *); static void warn_changed_key(Key *); /* Expand a proxy command */ static char * expand_proxy_command(const char *proxy_command, const char *user, const char *host, int port) { char *tmp, *ret, strport[NI_MAXSERV]; snprintf(strport, sizeof strport, "%d", port); xasprintf(&tmp, "exec %s", proxy_command); ret = percent_expand(tmp, "h", host, "p", strport, "r", options.user, (char *)NULL); free(tmp); return ret; } /* * Connect to the given ssh server using a proxy command that passes a * a connected fd back to us. */ static int ssh_proxy_fdpass_connect(const char *host, u_short port, const char *proxy_command) { char *command_string; int sp[2], sock; pid_t pid; char *shell; if ((shell = getenv("SHELL")) == NULL) shell = _PATH_BSHELL; if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) < 0) fatal("Could not create socketpair to communicate with " "proxy dialer: %.100s", strerror(errno)); command_string = expand_proxy_command(proxy_command, options.user, host, port); debug("Executing proxy dialer command: %.500s", command_string); /* Fork and execute the proxy command. */ if ((pid = fork()) == 0) { char *argv[10]; /* Child. Permanently give up superuser privileges. */ permanently_drop_suid(original_real_uid); close(sp[1]); /* Redirect stdin and stdout. */ if (sp[0] != 0) { if (dup2(sp[0], 0) < 0) perror("dup2 stdin"); } if (sp[0] != 1) { if (dup2(sp[0], 1) < 0) perror("dup2 stdout"); } if (sp[0] >= 2) close(sp[0]); /* * Stderr is left as it is so that error messages get * printed on the user's terminal. */ argv[0] = shell; argv[1] = "-c"; argv[2] = command_string; argv[3] = NULL; /* * Execute the proxy command. * Note that we gave up any extra privileges above. */ execv(argv[0], argv); perror(argv[0]); exit(1); } /* Parent. */ if (pid < 0) fatal("fork failed: %.100s", strerror(errno)); close(sp[0]); free(command_string); if ((sock = mm_receive_fd(sp[1])) == -1) fatal("proxy dialer did not pass back a connection"); while (waitpid(pid, NULL, 0) == -1) if (errno != EINTR) fatal("Couldn't wait for child: %s", strerror(errno)); /* Set the connection file descriptors. */ packet_set_connection(sock, sock); return 0; } /* * Connect to the given ssh server using a proxy command. */ static int ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) { char *command_string; int pin[2], pout[2]; pid_t pid; char *shell; if ((shell = getenv("SHELL")) == NULL || *shell == '\0') shell = _PATH_BSHELL; /* Create pipes for communicating with the proxy. */ if (pipe(pin) < 0 || pipe(pout) < 0) fatal("Could not create pipes to communicate with the proxy: %.100s", strerror(errno)); command_string = expand_proxy_command(proxy_command, options.user, host, port); debug("Executing proxy command: %.500s", command_string); /* Fork and execute the proxy command. */ if ((pid = fork()) == 0) { char *argv[10]; /* Child. Permanently give up superuser privileges. */ permanently_drop_suid(original_real_uid); /* Redirect stdin and stdout. */ close(pin[1]); if (pin[0] != 0) { if (dup2(pin[0], 0) < 0) perror("dup2 stdin"); close(pin[0]); } close(pout[0]); if (dup2(pout[1], 1) < 0) perror("dup2 stdout"); /* Cannot be 1 because pin allocated two descriptors. */ close(pout[1]); /* Stderr is left as it is so that error messages get printed on the user's terminal. */ argv[0] = shell; argv[1] = "-c"; argv[2] = command_string; argv[3] = NULL; /* Execute the proxy command. Note that we gave up any extra privileges above. */ signal(SIGPIPE, SIG_DFL); execv(argv[0], argv); perror(argv[0]); exit(1); } /* Parent. */ if (pid < 0) fatal("fork failed: %.100s", strerror(errno)); else proxy_command_pid = pid; /* save pid to clean up later */ /* Close child side of the descriptors. */ close(pin[0]); close(pout[1]); /* Free the command name. */ free(command_string); /* Set the connection file descriptors. */ packet_set_connection(pout[0], pin[1]); /* Indicate OK return */ return 0; } void ssh_kill_proxy_command(void) { /* * Send SIGHUP to proxy command if used. We don't wait() in * case it hangs and instead rely on init to reap the child */ if (proxy_command_pid > 1) kill(proxy_command_pid, SIGHUP); } /* * Creates a (possibly privileged) socket for use as the ssh connection. */ static int ssh_create_socket(int privileged, struct addrinfo *ai) { int sock, r, gaierr; struct addrinfo hints, *res = NULL; sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock < 0) { error("socket: %s", strerror(errno)); return -1; } fcntl(sock, F_SETFD, FD_CLOEXEC); /* Bind the socket to an alternative local IP address */ if (options.bind_address == NULL && !privileged) return sock; if (options.bind_address) { memset(&hints, 0, sizeof(hints)); hints.ai_family = ai->ai_family; hints.ai_socktype = ai->ai_socktype; hints.ai_protocol = ai->ai_protocol; hints.ai_flags = AI_PASSIVE; gaierr = getaddrinfo(options.bind_address, NULL, &hints, &res); if (gaierr) { error("getaddrinfo: %s: %s", options.bind_address, ssh_gai_strerror(gaierr)); close(sock); return -1; } } /* * If we are running as root and want to connect to a privileged * port, bind our own socket to a privileged port. */ if (privileged) { PRIV_START; r = bindresvport_sa(sock, res ? res->ai_addr : NULL); PRIV_END; if (r < 0) { error("bindresvport_sa: af=%d %s", ai->ai_family, strerror(errno)); goto fail; } } else { if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { error("bind: %s: %s", options.bind_address, strerror(errno)); fail: close(sock); freeaddrinfo(res); return -1; } } if (res != NULL) freeaddrinfo(res); return sock; } static int timeout_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen, int *timeoutp) { fd_set *fdset; struct timeval tv, t_start; socklen_t optlen; int optval, rc, result = -1; gettimeofday(&t_start, NULL); if (*timeoutp <= 0) { result = connect(sockfd, serv_addr, addrlen); goto done; } set_nonblock(sockfd); rc = connect(sockfd, serv_addr, addrlen); if (rc == 0) { unset_nonblock(sockfd); result = 0; goto done; } if (errno != EINPROGRESS) { result = -1; goto done; } - fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS), + fdset = xcalloc(howmany(sockfd + 1, NFDBITS), sizeof(fd_mask)); FD_SET(sockfd, fdset); ms_to_timeval(&tv, *timeoutp); for (;;) { rc = select(sockfd + 1, NULL, fdset, NULL, &tv); if (rc != -1 || errno != EINTR) break; } switch (rc) { case 0: /* Timed out */ errno = ETIMEDOUT; break; case -1: /* Select error */ debug("select: %s", strerror(errno)); break; case 1: /* Completed or failed */ optval = 0; optlen = sizeof(optval); if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1) { debug("getsockopt: %s", strerror(errno)); break; } if (optval != 0) { errno = optval; break; } result = 0; unset_nonblock(sockfd); break; default: /* Should not occur */ fatal("Bogus return (%d) from select()", rc); } free(fdset); done: if (result == 0 && *timeoutp > 0) { ms_subtract_diff(&t_start, timeoutp); if (*timeoutp <= 0) { errno = ETIMEDOUT; result = -1; } } return (result); } /* * Opens a TCP/IP connection to the remote server on the given host. * The address of the remote host will be returned in hostaddr. * If port is 0, the default port will be used. If needpriv is true, * a privileged port will be allocated to make the connection. * This requires super-user privileges if needpriv is true. * Connection_attempts specifies the maximum number of tries (one per * second). If proxy_command is non-NULL, it specifies the command (with %h * and %p substituted for host and port, respectively) to use to contact * the daemon. */ static int ssh_connect_direct(const char *host, struct addrinfo *aitop, struct sockaddr_storage *hostaddr, u_short port, int family, int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv) { int on = 1; int sock = -1, attempt; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; struct addrinfo *ai; debug2("ssh_connect: needpriv %d", needpriv); for (attempt = 0; attempt < connection_attempts; attempt++) { if (attempt > 0) { /* Sleep a moment before retrying. */ sleep(1); debug("Trying again..."); } /* * Loop through addresses for this host, and try each one in * sequence until the connection succeeds. */ for (ai = aitop; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) continue; if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { error("ssh_connect: getnameinfo failed"); continue; } debug("Connecting to %.200s [%.100s] port %s.", host, ntop, strport); /* Create a socket for connecting. */ sock = ssh_create_socket(needpriv, ai); if (sock < 0) /* Any error is already output */ continue; if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, timeout_ms) >= 0) { /* Successful connection. */ memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); break; } else { debug("connect to address %s port %s: %s", ntop, strport, strerror(errno)); close(sock); sock = -1; } } if (sock != -1) break; /* Successful connection. */ } /* Return failure if we didn't get a successful connection. */ if (sock == -1) { error("ssh: connect to host %s port %s: %s", host, strport, strerror(errno)); return (-1); } debug("Connection established."); /* Set SO_KEEPALIVE if requested. */ if (want_keepalive && setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on)) < 0) error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); /* Set the connection. */ packet_set_connection(sock, sock); return 0; } int ssh_connect(const char *host, struct addrinfo *addrs, struct sockaddr_storage *hostaddr, u_short port, int family, int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv) { if (options.proxy_command == NULL) { return ssh_connect_direct(host, addrs, hostaddr, port, family, connection_attempts, timeout_ms, want_keepalive, needpriv); } else if (strcmp(options.proxy_command, "-") == 0) { packet_set_connection(STDIN_FILENO, STDOUT_FILENO); return 0; /* Always succeeds */ } else if (options.proxy_use_fdpass) { return ssh_proxy_fdpass_connect(host, port, options.proxy_command); } return ssh_proxy_connect(host, port, options.proxy_command); } static void send_client_banner(int connection_out, int minor1) { /* Send our own protocol version identification. */ xasprintf(&client_version_string, "SSH-%d.%d-%.100s%s%s%s", compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, compat20 ? PROTOCOL_MINOR_2 : minor1, SSH_VERSION, *options.version_addendum == '\0' ? "" : " ", options.version_addendum, compat20 ? "\r\n" : "\n"); if (roaming_atomicio(vwrite, connection_out, client_version_string, strlen(client_version_string)) != strlen(client_version_string)) fatal("write: %.100s", strerror(errno)); chop(client_version_string); debug("Local version string %.100s", client_version_string); } /* * Waits for the server identification string, and sends our own * identification string. */ void ssh_exchange_identification(int timeout_ms) { char buf[256], remote_version[256]; /* must be same size! */ int remote_major, remote_minor, mismatch; int connection_in = packet_get_connection_in(); int connection_out = packet_get_connection_out(); int minor1 = PROTOCOL_MINOR_1, client_banner_sent = 0; u_int i, n; size_t len; int fdsetsz, remaining, rc; struct timeval t_start, t_remaining; fd_set *fdset; fdsetsz = howmany(connection_in + 1, NFDBITS) * sizeof(fd_mask); fdset = xcalloc(1, fdsetsz); /* * If we are SSH2-only then we can send the banner immediately and * save a round-trip. */ if (options.protocol == SSH_PROTO_2) { enable_compat20(); send_client_banner(connection_out, 0); client_banner_sent = 1; } /* Read other side's version identification. */ remaining = timeout_ms; for (n = 0;;) { for (i = 0; i < sizeof(buf) - 1; i++) { if (timeout_ms > 0) { gettimeofday(&t_start, NULL); ms_to_timeval(&t_remaining, remaining); FD_SET(connection_in, fdset); rc = select(connection_in + 1, fdset, NULL, fdset, &t_remaining); ms_subtract_diff(&t_start, &remaining); if (rc == 0 || remaining <= 0) fatal("Connection timed out during " "banner exchange"); if (rc == -1) { if (errno == EINTR) continue; fatal("ssh_exchange_identification: " "select: %s", strerror(errno)); } } len = roaming_atomicio(read, connection_in, &buf[i], 1); if (len != 1 && errno == EPIPE) fatal("ssh_exchange_identification: " "Connection closed by remote host"); else if (len != 1) fatal("ssh_exchange_identification: " "read: %.100s", strerror(errno)); if (buf[i] == '\r') { buf[i] = '\n'; buf[i + 1] = 0; continue; /**XXX wait for \n */ } if (buf[i] == '\n') { buf[i + 1] = 0; break; } if (++n > 65536) fatal("ssh_exchange_identification: " "No banner received"); } buf[sizeof(buf) - 1] = 0; if (strncmp(buf, "SSH-", 4) == 0) break; debug("ssh_exchange_identification: %s", buf); } server_version_string = xstrdup(buf); free(fdset); /* * Check that the versions match. In future this might accept * several versions and set appropriate flags to handle them. */ if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, remote_version) != 3) fatal("Bad remote protocol version identification: '%.100s'", buf); debug("Remote protocol version %d.%d, remote software version %.100s", remote_major, remote_minor, remote_version); active_state->compat = compat_datafellows(remote_version); mismatch = 0; switch (remote_major) { case 1: if (remote_minor == 99 && (options.protocol & SSH_PROTO_2) && !(options.protocol & SSH_PROTO_1_PREFERRED)) { enable_compat20(); break; } if (!(options.protocol & SSH_PROTO_1)) { mismatch = 1; break; } if (remote_minor < 3) { fatal("Remote machine has too old SSH software version."); } else if (remote_minor == 3 || remote_minor == 4) { /* We speak 1.3, too. */ enable_compat13(); minor1 = 3; if (options.forward_agent) { logit("Agent forwarding disabled for protocol 1.3"); options.forward_agent = 0; } } break; case 2: if (options.protocol & SSH_PROTO_2) { enable_compat20(); break; } /* FALLTHROUGH */ default: mismatch = 1; break; } if (mismatch) fatal("Protocol major versions differ: %d vs. %d", (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, remote_major); if ((datafellows & SSH_BUG_DERIVEKEY) != 0) fatal("Server version \"%.100s\" uses unsafe key agreement; " "refusing connection", remote_version); if ((datafellows & SSH_BUG_RSASIGMD5) != 0) logit("Server version \"%.100s\" uses unsafe RSA signature " "scheme; disabling use of RSA keys", remote_version); if (!client_banner_sent) send_client_banner(connection_out, minor1); chop(server_version_string); } /* defaults to 'no' */ static int confirm(const char *prompt) { const char *msg, *again = "Please type 'yes' or 'no': "; char *p; int ret = -1; if (options.batch_mode) return 0; for (msg = prompt;;msg = again) { p = read_passphrase(msg, RP_ECHO); if (p == NULL || (p[0] == '\0') || (p[0] == '\n') || strncasecmp(p, "no", 2) == 0) ret = 0; if (p && strncasecmp(p, "yes", 3) == 0) ret = 1; free(p); if (ret != -1) return ret; } } static int check_host_cert(const char *host, const Key *host_key) { const char *reason; if (key_cert_check_authority(host_key, 1, 0, host, &reason) != 0) { error("%s", reason); return 0; } if (buffer_len(host_key->cert->critical) != 0) { error("Certificate for %s contains unsupported " "critical options(s)", host); return 0; } return 1; } static int sockaddr_is_local(struct sockaddr *hostaddr) { switch (hostaddr->sa_family) { case AF_INET: return (ntohl(((struct sockaddr_in *)hostaddr)-> sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; case AF_INET6: return IN6_IS_ADDR_LOOPBACK( &(((struct sockaddr_in6 *)hostaddr)->sin6_addr)); default: return 0; } } /* * Prepare the hostname and ip address strings that are used to lookup * host keys in known_hosts files. These may have a port number appended. */ void get_hostfile_hostname_ipaddr(char *hostname, struct sockaddr *hostaddr, u_short port, char **hostfile_hostname, char **hostfile_ipaddr) { char ntop[NI_MAXHOST]; socklen_t addrlen; switch (hostaddr == NULL ? -1 : hostaddr->sa_family) { case -1: addrlen = 0; break; case AF_INET: addrlen = sizeof(struct sockaddr_in); break; case AF_INET6: addrlen = sizeof(struct sockaddr_in6); break; default: addrlen = sizeof(struct sockaddr); break; } /* * We don't have the remote ip-address for connections * using a proxy command */ if (hostfile_ipaddr != NULL) { if (options.proxy_command == NULL) { if (getnameinfo(hostaddr, addrlen, ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0) fatal("%s: getnameinfo failed", __func__); *hostfile_ipaddr = put_host_port(ntop, port); } else { *hostfile_ipaddr = xstrdup(""); } } /* * Allow the user to record the key under a different name or * differentiate a non-standard port. This is useful for ssh * tunneling over forwarded connections or if you run multiple * sshd's on different ports on the same machine. */ if (hostfile_hostname != NULL) { if (options.host_key_alias != NULL) { *hostfile_hostname = xstrdup(options.host_key_alias); debug("using hostkeyalias: %s", *hostfile_hostname); } else { *hostfile_hostname = put_host_port(hostname, port); } } } /* * check whether the supplied host key is valid, return -1 if the key * is not valid. user_hostfile[0] will not be updated if 'readonly' is true. */ #define RDRW 0 #define RDONLY 1 #define ROQUIET 2 static int check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, Key *host_key, int readonly, char **user_hostfiles, u_int num_user_hostfiles, char **system_hostfiles, u_int num_system_hostfiles) { HostStatus host_status; HostStatus ip_status; Key *raw_key = NULL; char *ip = NULL, *host = NULL; char hostline[1000], *hostp, *fp, *ra; char msg[1024]; const char *type; const struct hostkey_entry *host_found, *ip_found; int len, cancelled_forwarding = 0; int local = sockaddr_is_local(hostaddr); int r, want_cert = key_is_cert(host_key), host_ip_differ = 0; int hostkey_trusted = 0; /* Known or explicitly accepted by user */ struct hostkeys *host_hostkeys, *ip_hostkeys; u_int i; /* * Force accepting of the host key for loopback/localhost. The * problem is that if the home directory is NFS-mounted to multiple * machines, localhost will refer to a different machine in each of * them, and the user will get bogus HOST_CHANGED warnings. This * essentially disables host authentication for localhost; however, * this is probably not a real problem. */ if (options.no_host_authentication_for_localhost == 1 && local && options.host_key_alias == NULL) { debug("Forcing accepting of host key for " "loopback/localhost."); return 0; } /* * Prepare the hostname and address strings used for hostkey lookup. * In some cases, these will have a port number appended. */ get_hostfile_hostname_ipaddr(hostname, hostaddr, port, &host, &ip); /* * Turn off check_host_ip if the connection is to localhost, via proxy * command or if we don't have a hostname to compare with */ if (options.check_host_ip && (local || strcmp(hostname, ip) == 0 || options.proxy_command != NULL)) options.check_host_ip = 0; host_hostkeys = init_hostkeys(); for (i = 0; i < num_user_hostfiles; i++) load_hostkeys(host_hostkeys, host, user_hostfiles[i]); for (i = 0; i < num_system_hostfiles; i++) load_hostkeys(host_hostkeys, host, system_hostfiles[i]); ip_hostkeys = NULL; if (!want_cert && options.check_host_ip) { ip_hostkeys = init_hostkeys(); for (i = 0; i < num_user_hostfiles; i++) load_hostkeys(ip_hostkeys, ip, user_hostfiles[i]); for (i = 0; i < num_system_hostfiles; i++) load_hostkeys(ip_hostkeys, ip, system_hostfiles[i]); } retry: /* Reload these as they may have changed on cert->key downgrade */ want_cert = key_is_cert(host_key); type = key_type(host_key); /* * Check if the host key is present in the user's list of known * hosts or in the systemwide list. */ host_status = check_key_in_hostkeys(host_hostkeys, host_key, &host_found); /* * Also perform check for the ip address, skip the check if we are * localhost, looking for a certificate, or the hostname was an ip * address to begin with. */ if (!want_cert && ip_hostkeys != NULL) { ip_status = check_key_in_hostkeys(ip_hostkeys, host_key, &ip_found); if (host_status == HOST_CHANGED && (ip_status != HOST_CHANGED || (ip_found != NULL && !key_equal(ip_found->key, host_found->key)))) host_ip_differ = 1; } else ip_status = host_status; switch (host_status) { case HOST_OK: /* The host is known and the key matches. */ debug("Host '%.200s' is known and matches the %s host %s.", host, type, want_cert ? "certificate" : "key"); debug("Found %s in %s:%lu", want_cert ? "CA key" : "key", host_found->file, host_found->line); if (want_cert && !check_host_cert(hostname, host_key)) goto fail; if (options.check_host_ip && ip_status == HOST_NEW) { if (readonly || want_cert) logit("%s host key for IP address " "'%.128s' not in list of known hosts.", type, ip); else if (!add_host_to_hostfile(user_hostfiles[0], ip, host_key, options.hash_known_hosts)) logit("Failed to add the %s host key for IP " "address '%.128s' to the list of known " "hosts (%.500s).", type, ip, user_hostfiles[0]); else logit("Warning: Permanently added the %s host " "key for IP address '%.128s' to the list " "of known hosts.", type, ip); } else if (options.visual_host_key) { fp = sshkey_fingerprint(host_key, options.fingerprint_hash, SSH_FP_DEFAULT); ra = sshkey_fingerprint(host_key, options.fingerprint_hash, SSH_FP_RANDOMART); if (fp == NULL || ra == NULL) fatal("%s: sshkey_fingerprint fail", __func__); logit("Host key fingerprint is %s\n%s\n", fp, ra); free(ra); free(fp); } hostkey_trusted = 1; break; case HOST_NEW: if (options.host_key_alias == NULL && port != 0 && port != SSH_DEFAULT_PORT) { debug("checking without port identifier"); if (check_host_key(hostname, hostaddr, 0, host_key, ROQUIET, user_hostfiles, num_user_hostfiles, system_hostfiles, num_system_hostfiles) == 0) { debug("found matching key w/out port"); break; } } if (readonly || want_cert) goto fail; /* The host is new. */ if (options.strict_host_key_checking == 1) { /* * User has requested strict host key checking. We * will not add the host key automatically. The only * alternative left is to abort. */ error("No %s host key is known for %.200s and you " "have requested strict checking.", type, host); goto fail; } else if (options.strict_host_key_checking == 2) { char msg1[1024], msg2[1024]; if (show_other_keys(host_hostkeys, host_key)) snprintf(msg1, sizeof(msg1), "\nbut keys of different type are already" " known for this host."); else snprintf(msg1, sizeof(msg1), "."); /* The default */ fp = sshkey_fingerprint(host_key, options.fingerprint_hash, SSH_FP_DEFAULT); ra = sshkey_fingerprint(host_key, options.fingerprint_hash, SSH_FP_RANDOMART); if (fp == NULL || ra == NULL) fatal("%s: sshkey_fingerprint fail", __func__); msg2[0] = '\0'; if (options.verify_host_key_dns) { if (matching_host_key_dns) snprintf(msg2, sizeof(msg2), "Matching host key fingerprint" " found in DNS.\n"); else snprintf(msg2, sizeof(msg2), "No matching host key fingerprint" " found in DNS.\n"); } snprintf(msg, sizeof(msg), "The authenticity of host '%.200s (%s)' can't be " "established%s\n" "%s key fingerprint is %s.%s%s\n%s" "Are you sure you want to continue connecting " "(yes/no)? ", host, ip, msg1, type, fp, options.visual_host_key ? "\n" : "", options.visual_host_key ? ra : "", msg2); free(ra); free(fp); if (!confirm(msg)) goto fail; hostkey_trusted = 1; /* user explicitly confirmed */ } /* * If not in strict mode, add the key automatically to the * local known_hosts file. */ if (options.check_host_ip && ip_status == HOST_NEW) { snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); hostp = hostline; if (options.hash_known_hosts) { /* Add hash of host and IP separately */ r = add_host_to_hostfile(user_hostfiles[0], host, host_key, options.hash_known_hosts) && add_host_to_hostfile(user_hostfiles[0], ip, host_key, options.hash_known_hosts); } else { /* Add unhashed "host,ip" */ r = add_host_to_hostfile(user_hostfiles[0], hostline, host_key, options.hash_known_hosts); } } else { r = add_host_to_hostfile(user_hostfiles[0], host, host_key, options.hash_known_hosts); hostp = host; } if (!r) logit("Failed to add the host to the list of known " "hosts (%.500s).", user_hostfiles[0]); else logit("Warning: Permanently added '%.200s' (%s) to the " "list of known hosts.", hostp, type); break; case HOST_REVOKED: error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("@ WARNING: REVOKED HOST KEY DETECTED! @"); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("The %s host key for %s is marked as revoked.", type, host); error("This could mean that a stolen key is being used to"); error("impersonate this host."); /* * If strict host key checking is in use, the user will have * to edit the key manually and we can only abort. */ if (options.strict_host_key_checking) { error("%s host key for %.200s was revoked and you have " "requested strict checking.", type, host); goto fail; } goto continue_unsafe; case HOST_CHANGED: if (want_cert) { /* * This is only a debug() since it is valid to have * CAs with wildcard DNS matches that don't match * all hosts that one might visit. */ debug("Host certificate authority does not " "match %s in %s:%lu", CA_MARKER, host_found->file, host_found->line); goto fail; } if (readonly == ROQUIET) goto fail; if (options.check_host_ip && host_ip_differ) { char *key_msg; if (ip_status == HOST_NEW) key_msg = "is unknown"; else if (ip_status == HOST_OK) key_msg = "is unchanged"; else key_msg = "has a different value"; error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("The %s host key for %s has changed,", type, host); error("and the key for the corresponding IP address %s", ip); error("%s. This could either mean that", key_msg); error("DNS SPOOFING is happening or the IP address for the host"); error("and its host key have changed at the same time."); if (ip_status != HOST_NEW) error("Offending key for IP in %s:%lu", ip_found->file, ip_found->line); } /* The host key has changed. */ warn_changed_key(host_key); error("Add correct host key in %.100s to get rid of this message.", user_hostfiles[0]); error("Offending %s key in %s:%lu", key_type(host_found->key), host_found->file, host_found->line); /* * If strict host key checking is in use, the user will have * to edit the key manually and we can only abort. */ if (options.strict_host_key_checking) { error("%s host key for %.200s has changed and you have " "requested strict checking.", type, host); goto fail; } continue_unsafe: /* * If strict host key checking has not been requested, allow * the connection but without MITM-able authentication or * forwarding. */ if (options.password_authentication) { error("Password authentication is disabled to avoid " "man-in-the-middle attacks."); options.password_authentication = 0; cancelled_forwarding = 1; } if (options.kbd_interactive_authentication) { error("Keyboard-interactive authentication is disabled" " to avoid man-in-the-middle attacks."); options.kbd_interactive_authentication = 0; options.challenge_response_authentication = 0; cancelled_forwarding = 1; } if (options.challenge_response_authentication) { error("Challenge/response authentication is disabled" " to avoid man-in-the-middle attacks."); options.challenge_response_authentication = 0; cancelled_forwarding = 1; } if (options.forward_agent) { error("Agent forwarding is disabled to avoid " "man-in-the-middle attacks."); options.forward_agent = 0; cancelled_forwarding = 1; } if (options.forward_x11) { error("X11 forwarding is disabled to avoid " "man-in-the-middle attacks."); options.forward_x11 = 0; cancelled_forwarding = 1; } if (options.num_local_forwards > 0 || options.num_remote_forwards > 0) { error("Port forwarding is disabled to avoid " "man-in-the-middle attacks."); options.num_local_forwards = options.num_remote_forwards = 0; cancelled_forwarding = 1; } if (options.tun_open != SSH_TUNMODE_NO) { error("Tunnel forwarding is disabled to avoid " "man-in-the-middle attacks."); options.tun_open = SSH_TUNMODE_NO; cancelled_forwarding = 1; } if (options.exit_on_forward_failure && cancelled_forwarding) fatal("Error: forwarding disabled due to host key " "check failure"); /* * XXX Should permit the user to change to use the new id. * This could be done by converting the host key to an * identifying sentence, tell that the host identifies itself * by that sentence, and ask the user if he/she wishes to * accept the authentication. */ break; case HOST_FOUND: fatal("internal error"); break; } if (options.check_host_ip && host_status != HOST_CHANGED && ip_status == HOST_CHANGED) { snprintf(msg, sizeof(msg), "Warning: the %s host key for '%.200s' " "differs from the key for the IP address '%.128s'" "\nOffending key for IP in %s:%lu", type, host, ip, ip_found->file, ip_found->line); if (host_status == HOST_OK) { len = strlen(msg); snprintf(msg + len, sizeof(msg) - len, "\nMatching host key in %s:%lu", host_found->file, host_found->line); } if (options.strict_host_key_checking == 1) { logit("%s", msg); error("Exiting, you have requested strict checking."); goto fail; } else if (options.strict_host_key_checking == 2) { strlcat(msg, "\nAre you sure you want " "to continue connecting (yes/no)? ", sizeof(msg)); if (!confirm(msg)) goto fail; } else { logit("%s", msg); } } if (!hostkey_trusted && options.update_hostkeys) { debug("%s: hostkey not known or explicitly trusted: " "disabling UpdateHostkeys", __func__); options.update_hostkeys = 0; } free(ip); free(host); if (host_hostkeys != NULL) free_hostkeys(host_hostkeys); if (ip_hostkeys != NULL) free_hostkeys(ip_hostkeys); return 0; fail: if (want_cert && host_status != HOST_REVOKED) { /* * No matching certificate. Downgrade cert to raw key and * search normally. */ debug("No matching CA found. Retry with plain key"); raw_key = key_from_private(host_key); if (key_drop_cert(raw_key) != 0) fatal("Couldn't drop certificate"); host_key = raw_key; goto retry; } if (raw_key != NULL) key_free(raw_key); free(ip); free(host); if (host_hostkeys != NULL) free_hostkeys(host_hostkeys); if (ip_hostkeys != NULL) free_hostkeys(ip_hostkeys); return -1; } /* returns 0 if key verifies or -1 if key does NOT verify */ int verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) { int r = -1, flags = 0; char *fp = NULL; struct sshkey *plain = NULL; if ((fp = sshkey_fingerprint(host_key, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { error("%s: fingerprint host key: %s", __func__, ssh_err(r)); r = -1; goto out; } debug("Server host key: %s %s", compat20 ? sshkey_ssh_name(host_key) : sshkey_type(host_key), fp); if (sshkey_equal(previous_host_key, host_key)) { debug2("%s: server host key %s %s matches cached key", __func__, sshkey_type(host_key), fp); r = 0; goto out; } /* Check in RevokedHostKeys file if specified */ if (options.revoked_host_keys != NULL) { r = sshkey_check_revoked(host_key, options.revoked_host_keys); switch (r) { case 0: break; /* not revoked */ case SSH_ERR_KEY_REVOKED: error("Host key %s %s revoked by file %s", sshkey_type(host_key), fp, options.revoked_host_keys); r = -1; goto out; default: error("Error checking host key %s %s in " "revoked keys file %s: %s", sshkey_type(host_key), fp, options.revoked_host_keys, ssh_err(r)); r = -1; goto out; } } if (options.verify_host_key_dns) { /* * XXX certs are not yet supported for DNS, so downgrade * them and try the plain key. */ if ((r = sshkey_from_private(host_key, &plain)) != 0) goto out; if (sshkey_is_cert(plain)) sshkey_drop_cert(plain); if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) { if (flags & DNS_VERIFY_FOUND) { if (options.verify_host_key_dns == 1 && flags & DNS_VERIFY_MATCH && flags & DNS_VERIFY_SECURE) { r = 0; goto out; } if (flags & DNS_VERIFY_MATCH) { matching_host_key_dns = 1; } else { warn_changed_key(plain); error("Update the SSHFP RR in DNS " "with the new host key to get rid " "of this message."); } } } } r = check_host_key(host, hostaddr, options.port, host_key, RDRW, options.user_hostfiles, options.num_user_hostfiles, options.system_hostfiles, options.num_system_hostfiles); out: sshkey_free(plain); free(fp); if (r == 0 && host_key != NULL) { key_free(previous_host_key); previous_host_key = key_from_private(host_key); } return r; } /* * Starts a dialog with the server, and authenticates the current user on the * server. This does not need any extra privileges. The basic connection * to the server must already have been established before this is called. * If login fails, this function prints an error and never returns. * This function does not require super-user privileges. */ void ssh_login(Sensitive *sensitive, const char *orighost, struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms) { char *host; char *server_user, *local_user; local_user = xstrdup(pw->pw_name); server_user = options.user ? options.user : local_user; /* Convert the user-supplied hostname into all lowercase. */ host = xstrdup(orighost); lowercase(host); /* Exchange protocol version identification strings with the server. */ ssh_exchange_identification(timeout_ms); /* Put the connection into non-blocking mode. */ packet_set_nonblocking(); /* key exchange */ /* authenticate user */ debug("Authenticating to %s:%d as '%s'", host, port, server_user); if (compat20) { ssh_kex2(host, hostaddr, port); ssh_userauth2(local_user, server_user, host, sensitive); } else { #ifdef WITH_SSH1 ssh_kex(host, hostaddr); ssh_userauth1(local_user, server_user, host, sensitive); #else fatal("ssh1 is not supported"); #endif } free(local_user); } void ssh_put_password(char *password) { int size; char *padded; if (datafellows & SSH_BUG_PASSWORDPAD) { packet_put_cstring(password); return; } size = roundup(strlen(password) + 1, 32); padded = xcalloc(1, size); strlcpy(padded, password, size); packet_put_string(padded, size); explicit_bzero(padded, size); free(padded); } /* print all known host keys for a given host, but skip keys of given type */ static int show_other_keys(struct hostkeys *hostkeys, Key *key) { int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, KEY_ECDSA, KEY_ED25519, -1 }; int i, ret = 0; char *fp, *ra; const struct hostkey_entry *found; for (i = 0; type[i] != -1; i++) { if (type[i] == key->type) continue; if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found)) continue; fp = sshkey_fingerprint(found->key, options.fingerprint_hash, SSH_FP_DEFAULT); ra = sshkey_fingerprint(found->key, options.fingerprint_hash, SSH_FP_RANDOMART); if (fp == NULL || ra == NULL) fatal("%s: sshkey_fingerprint fail", __func__); logit("WARNING: %s key found for host %s\n" "in %s:%lu\n" "%s key fingerprint %s.", key_type(found->key), found->host, found->file, found->line, key_type(found->key), fp); if (options.visual_host_key) logit("%s", ra); free(ra); free(fp); ret = 1; } return ret; } static void warn_changed_key(Key *host_key) { char *fp; fp = sshkey_fingerprint(host_key, options.fingerprint_hash, SSH_FP_DEFAULT); if (fp == NULL) fatal("%s: sshkey_fingerprint fail", __func__); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); error("It is also possible that a host key has just been changed."); error("The fingerprint for the %s key sent by the remote host is\n%s.", key_type(host_key), fp); error("Please contact your system administrator."); free(fp); } /* * Execute a local command */ int ssh_local_cmd(const char *args) { char *shell; pid_t pid; int status; void (*osighand)(int); if (!options.permit_local_command || args == NULL || !*args) return (1); if ((shell = getenv("SHELL")) == NULL || *shell == '\0') shell = _PATH_BSHELL; osighand = signal(SIGCHLD, SIG_DFL); pid = fork(); if (pid == 0) { signal(SIGPIPE, SIG_DFL); debug3("Executing %s -c \"%s\"", shell, args); execl(shell, shell, "-c", args, (char *)NULL); error("Couldn't execute %s -c \"%s\": %s", shell, args, strerror(errno)); _exit(1); } else if (pid == -1) fatal("fork failed: %.100s", strerror(errno)); while (waitpid(pid, &status, 0) == -1) if (errno != EINTR) fatal("Couldn't wait for child: %s", strerror(errno)); signal(SIGCHLD, osighand); if (!WIFEXITED(status)) return (1); return (WEXITSTATUS(status)); } Index: head/crypto/openssh/sshd.c =================================================================== --- head/crypto/openssh/sshd.c (revision 294495) +++ head/crypto/openssh/sshd.c (revision 294496) @@ -1,2692 +1,2698 @@ -/* $OpenBSD: sshd.c,v 1.457 2015/07/30 00:01:34 djm Exp $ */ +/* $OpenBSD: sshd.c,v 1.458 2015/08/20 22:32:42 deraadt Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved * This program is the ssh daemon. It listens for connections from clients, * and performs authentication, executes use commands or shell, and forwards * information to/from the application to the user client over an encrypted * connection. This can also handle forwarding of X11, TCP/IP, and * authentication agent connections. * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose. Any derived versions of this * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". * * SSH2 implementation: * Privilege Separation: * * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. * Copyright (c) 2002 Niels Provos. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" __RCSID("$FreeBSD$"); #include #include #include #include #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_SYS_TIME_H # include #endif #include "openbsd-compat/sys-tree.h" #include "openbsd-compat/sys-queue.h" #include #include #include #include #ifdef HAVE_PATHS_H #include #endif #include #include #include #include #include #include #include #include #include #ifdef WITH_OPENSSL #include #include #include #include "openbsd-compat/openssl-compat.h" #endif #ifdef HAVE_SECUREWARE #include #include #endif #ifdef __FreeBSD__ #include #if defined(GSSAPI) && defined(HAVE_GSSAPI_GSSAPI_H) #include #elif defined(GSSAPI) && defined(HAVE_GSSAPI_H) #include #endif #endif #include "xmalloc.h" #include "ssh.h" #include "ssh1.h" #include "ssh2.h" #include "rsa.h" #include "sshpty.h" #include "packet.h" #include "log.h" #include "buffer.h" #include "misc.h" #include "match.h" #include "servconf.h" #include "uidswap.h" #include "compat.h" #include "cipher.h" #include "digest.h" #include "key.h" #include "kex.h" #include "myproposal.h" #include "authfile.h" #include "pathnames.h" #include "atomicio.h" #include "canohost.h" #include "hostfile.h" #include "auth.h" #include "authfd.h" #include "msg.h" #include "dispatch.h" #include "channels.h" #include "session.h" #include "monitor_mm.h" #include "monitor.h" #ifdef GSSAPI #include "ssh-gss.h" #endif #include "monitor_wrap.h" #include "roaming.h" #include "ssh-sandbox.h" #include "version.h" #include "ssherr.h" #ifdef LIBWRAP #include #include int allow_severity; int deny_severity; #endif /* LIBWRAP */ #ifndef O_NOCTTY #define O_NOCTTY 0 #endif /* Re-exec fds */ #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) #define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2) #define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 3) #define REEXEC_MIN_FREE_FD (STDERR_FILENO + 4) extern char *__progname; /* Server configuration options. */ ServerOptions options; /* Name of the server configuration file. */ char *config_file_name = _PATH_SERVER_CONFIG_FILE; /* * Debug mode flag. This can be set on the command line. If debug * mode is enabled, extra debugging output will be sent to the system * log, the daemon will not go to background, and will exit after processing * the first connection. */ int debug_flag = 0; /* Flag indicating that the daemon should only test the configuration and keys. */ int test_flag = 0; /* Flag indicating that the daemon is being started from inetd. */ int inetd_flag = 0; /* Flag indicating that sshd should not detach and become a daemon. */ int no_daemon_flag = 0; /* debug goes to stderr unless inetd_flag is set */ int log_stderr = 0; /* Saved arguments to main(). */ char **saved_argv; int saved_argc; /* re-exec */ int rexeced_flag = 0; int rexec_flag = 1; int rexec_argc = 0; char **rexec_argv; /* * The sockets that the server is listening; this is used in the SIGHUP * signal handler. */ #define MAX_LISTEN_SOCKS 16 int listen_socks[MAX_LISTEN_SOCKS]; int num_listen_socks = 0; /* * the client's version string, passed by sshd2 in compat mode. if != NULL, * sshd will skip the version-number exchange */ char *client_version_string = NULL; char *server_version_string = NULL; /* Daemon's agent connection */ int auth_sock = -1; int have_agent = 0; /* * Any really sensitive data in the application is contained in this * structure. The idea is that this structure could be locked into memory so * that the pages do not get written into swap. However, there are some * problems. The private key contains BIGNUMs, and we do not (in principle) * have access to the internals of them, and locking just the structure is * not very useful. Currently, memory locking is not implemented. */ struct { Key *server_key; /* ephemeral server key */ Key *ssh1_host_key; /* ssh1 host key */ Key **host_keys; /* all private host keys */ Key **host_pubkeys; /* all public host keys */ Key **host_certificates; /* all public host certificates */ int have_ssh1_key; int have_ssh2_key; u_char ssh1_cookie[SSH_SESSION_KEY_LENGTH]; } sensitive_data; /* * Flag indicating whether the RSA server key needs to be regenerated. * Is set in the SIGALRM handler and cleared when the key is regenerated. */ static volatile sig_atomic_t key_do_regen = 0; /* This is set to true when a signal is received. */ static volatile sig_atomic_t received_sighup = 0; static volatile sig_atomic_t received_sigterm = 0; /* session identifier, used by RSA-auth */ u_char session_id[16]; /* same for ssh2 */ u_char *session_id2 = NULL; u_int session_id2_len = 0; /* record remote hostname or ip */ u_int utmp_len = HOST_NAME_MAX+1; /* options.max_startup sized array of fd ints */ int *startup_pipes = NULL; int startup_pipe; /* in child */ /* variables used for privilege separation */ int use_privsep = -1; struct monitor *pmonitor = NULL; int privsep_is_preauth = 1; /* global authentication context */ Authctxt *the_authctxt = NULL; /* sshd_config buffer */ Buffer cfg; /* message to be displayed after login */ Buffer loginmsg; /* Unprivileged user */ struct passwd *privsep_pw = NULL; /* Prototypes for various functions defined later in this file. */ void destroy_sensitive_data(void); void demote_sensitive_data(void); #ifdef WITH_SSH1 static void do_ssh1_kex(void); #endif static void do_ssh2_kex(void); /* * Close all listening sockets */ static void close_listen_socks(void) { int i; for (i = 0; i < num_listen_socks; i++) close(listen_socks[i]); num_listen_socks = -1; } static void close_startup_pipes(void) { int i; if (startup_pipes) for (i = 0; i < options.max_startups; i++) if (startup_pipes[i] != -1) close(startup_pipes[i]); } /* * Signal handler for SIGHUP. Sshd execs itself when it receives SIGHUP; * the effect is to reread the configuration file (and to regenerate * the server key). */ /*ARGSUSED*/ static void sighup_handler(int sig) { int save_errno = errno; received_sighup = 1; signal(SIGHUP, sighup_handler); errno = save_errno; } /* * Called from the main program after receiving SIGHUP. * Restarts the server. */ static void sighup_restart(void) { logit("Received SIGHUP; restarting."); platform_pre_restart(); close_listen_socks(); close_startup_pipes(); alarm(0); /* alarm timer persists across exec */ signal(SIGHUP, SIG_IGN); /* will be restored after exec */ execv(saved_argv[0], saved_argv); logit("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], strerror(errno)); exit(1); } /* * Generic signal handler for terminating signals in the master daemon. */ /*ARGSUSED*/ static void sigterm_handler(int sig) { received_sigterm = sig; } /* * SIGCHLD handler. This is called whenever a child dies. This will then * reap any zombies left by exited children. */ /*ARGSUSED*/ static void main_sigchld_handler(int sig) { int save_errno = errno; pid_t pid; int status; while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || (pid < 0 && errno == EINTR)) ; signal(SIGCHLD, main_sigchld_handler); errno = save_errno; } /* * Signal handler for the alarm after the login grace period has expired. */ /*ARGSUSED*/ static void grace_alarm_handler(int sig) { if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0) kill(pmonitor->m_pid, SIGALRM); /* * Try to kill any processes that we have spawned, E.g. authorized * keys command helpers. */ if (getpgid(0) == getpid()) { signal(SIGTERM, SIG_IGN); kill(0, SIGTERM); } /* Log error and exit. */ sigdie("Timeout before authentication for %s", get_remote_ipaddr()); } /* * Signal handler for the key regeneration alarm. Note that this * alarm only occurs in the daemon waiting for connections, and it does not * do anything with the private key or random state before forking. * Thus there should be no concurrency control/asynchronous execution * problems. */ static void generate_ephemeral_server_key(void) { verbose("Generating %s%d bit RSA key.", sensitive_data.server_key ? "new " : "", options.server_key_bits); if (sensitive_data.server_key != NULL) key_free(sensitive_data.server_key); sensitive_data.server_key = key_generate(KEY_RSA1, options.server_key_bits); verbose("RSA key generation complete."); arc4random_buf(sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH); } /*ARGSUSED*/ static void key_regeneration_alarm(int sig) { int save_errno = errno; signal(SIGALRM, SIG_DFL); errno = save_errno; key_do_regen = 1; } static void sshd_exchange_identification(int sock_in, int sock_out) { u_int i; int mismatch; int remote_major, remote_minor; int major, minor; char *s, *newline = "\n"; char buf[256]; /* Must not be larger than remote_version. */ char remote_version[256]; /* Must be at least as big as buf. */ if ((options.protocol & SSH_PROTO_1) && (options.protocol & SSH_PROTO_2)) { major = PROTOCOL_MAJOR_1; minor = 99; } else if (options.protocol & SSH_PROTO_2) { major = PROTOCOL_MAJOR_2; minor = PROTOCOL_MINOR_2; newline = "\r\n"; } else { major = PROTOCOL_MAJOR_1; minor = PROTOCOL_MINOR_1; } xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s", major, minor, SSH_VERSION, *options.version_addendum == '\0' ? "" : " ", options.version_addendum, newline); /* Send our protocol version identification. */ if (roaming_atomicio(vwrite, sock_out, server_version_string, strlen(server_version_string)) != strlen(server_version_string)) { logit("Could not write ident string to %s", get_remote_ipaddr()); cleanup_exit(255); } /* Read other sides version identification. */ memset(buf, 0, sizeof(buf)); for (i = 0; i < sizeof(buf) - 1; i++) { if (roaming_atomicio(read, sock_in, &buf[i], 1) != 1) { logit("Did not receive identification string from %s", get_remote_ipaddr()); cleanup_exit(255); } if (buf[i] == '\r') { buf[i] = 0; /* Kludge for F-Secure Macintosh < 1.0.2 */ if (i == 12 && strncmp(buf, "SSH-1.5-W1.0", 12) == 0) break; continue; } if (buf[i] == '\n') { buf[i] = 0; break; } } buf[sizeof(buf) - 1] = 0; client_version_string = xstrdup(buf); /* * Check that the versions match. In future this might accept * several versions and set appropriate flags to handle them. */ if (sscanf(client_version_string, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, remote_version) != 3) { s = "Protocol mismatch.\n"; (void) atomicio(vwrite, sock_out, s, strlen(s)); logit("Bad protocol version identification '%.100s' " "from %s port %d", client_version_string, get_remote_ipaddr(), get_remote_port()); close(sock_in); close(sock_out); cleanup_exit(255); } debug("Client protocol version %d.%d; client software version %.100s", remote_major, remote_minor, remote_version); active_state->compat = compat_datafellows(remote_version); if ((datafellows & SSH_BUG_PROBE) != 0) { logit("probed from %s with %s. Don't panic.", get_remote_ipaddr(), client_version_string); cleanup_exit(255); } if ((datafellows & SSH_BUG_SCANNER) != 0) { logit("scanned from %s with %s. Don't panic.", get_remote_ipaddr(), client_version_string); cleanup_exit(255); } if ((datafellows & SSH_BUG_RSASIGMD5) != 0) { logit("Client version \"%.100s\" uses unsafe RSA signature " "scheme; disabling use of RSA keys", remote_version); } if ((datafellows & SSH_BUG_DERIVEKEY) != 0) { fatal("Client version \"%.100s\" uses unsafe key agreement; " "refusing connection", remote_version); } mismatch = 0; switch (remote_major) { case 1: if (remote_minor == 99) { if (options.protocol & SSH_PROTO_2) enable_compat20(); else mismatch = 1; break; } if (!(options.protocol & SSH_PROTO_1)) { mismatch = 1; break; } if (remote_minor < 3) { packet_disconnect("Your ssh version is too old and " "is no longer supported. Please install a newer version."); } else if (remote_minor == 3) { /* note that this disables agent-forwarding */ enable_compat13(); } break; case 2: if (options.protocol & SSH_PROTO_2) { enable_compat20(); break; } /* FALLTHROUGH */ default: mismatch = 1; break; } chop(server_version_string); debug("Local version string %.200s", server_version_string); if (mismatch) { s = "Protocol major versions differ.\n"; (void) atomicio(vwrite, sock_out, s, strlen(s)); close(sock_in); close(sock_out); logit("Protocol major versions differ for %s: %.200s vs. %.200s", get_remote_ipaddr(), server_version_string, client_version_string); cleanup_exit(255); } } /* Destroy the host and server keys. They will no longer be needed. */ void destroy_sensitive_data(void) { int i; if (sensitive_data.server_key) { key_free(sensitive_data.server_key); sensitive_data.server_key = NULL; } for (i = 0; i < options.num_host_key_files; i++) { if (sensitive_data.host_keys[i]) { key_free(sensitive_data.host_keys[i]); sensitive_data.host_keys[i] = NULL; } if (sensitive_data.host_certificates[i]) { key_free(sensitive_data.host_certificates[i]); sensitive_data.host_certificates[i] = NULL; } } sensitive_data.ssh1_host_key = NULL; explicit_bzero(sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH); } /* Demote private to public keys for network child */ void demote_sensitive_data(void) { Key *tmp; int i; if (sensitive_data.server_key) { tmp = key_demote(sensitive_data.server_key); key_free(sensitive_data.server_key); sensitive_data.server_key = tmp; } for (i = 0; i < options.num_host_key_files; i++) { if (sensitive_data.host_keys[i]) { tmp = key_demote(sensitive_data.host_keys[i]); key_free(sensitive_data.host_keys[i]); sensitive_data.host_keys[i] = tmp; if (tmp->type == KEY_RSA1) sensitive_data.ssh1_host_key = tmp; } /* Certs do not need demotion */ } /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */ } static void privsep_preauth_child(void) { u_int32_t rnd[256]; gid_t gidset[1]; /* Enable challenge-response authentication for privilege separation */ privsep_challenge_enable(); #ifdef GSSAPI /* Cache supported mechanism OIDs for later use */ if (options.gss_authentication) ssh_gssapi_prepare_supported_oids(); #endif arc4random_stir(); arc4random_buf(rnd, sizeof(rnd)); #ifdef WITH_OPENSSL RAND_seed(rnd, sizeof(rnd)); + if ((RAND_bytes((u_char *)rnd, 1)) != 1) + fatal("%s: RAND_bytes failed", __func__); #endif explicit_bzero(rnd, sizeof(rnd)); /* Demote the private keys to public keys. */ demote_sensitive_data(); /* Change our root directory */ if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1) fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR, strerror(errno)); if (chdir("/") == -1) fatal("chdir(\"/\"): %s", strerror(errno)); /* Drop our privileges */ debug3("privsep user:group %u:%u", (u_int)privsep_pw->pw_uid, (u_int)privsep_pw->pw_gid); #if 0 /* XXX not ready, too heavy after chroot */ do_setusercontext(privsep_pw); #else gidset[0] = privsep_pw->pw_gid; if (setgroups(1, gidset) < 0) fatal("setgroups: %.100s", strerror(errno)); permanently_set_uid(privsep_pw); #endif } static int privsep_preauth(Authctxt *authctxt) { int status, r; pid_t pid; struct ssh_sandbox *box = NULL; /* Set up unprivileged child process to deal with network data */ pmonitor = monitor_init(); /* Store a pointer to the kex for later rekeying */ pmonitor->m_pkex = &active_state->kex; if (use_privsep == PRIVSEP_ON) box = ssh_sandbox_init(pmonitor); pid = fork(); if (pid == -1) { fatal("fork of unprivileged child failed"); } else if (pid != 0) { debug2("Network child is on pid %ld", (long)pid); pmonitor->m_pid = pid; if (have_agent) { r = ssh_get_authentication_socket(&auth_sock); if (r != 0) { error("Could not get agent socket: %s", ssh_err(r)); have_agent = 0; } } if (box != NULL) ssh_sandbox_parent_preauth(box, pid); monitor_child_preauth(authctxt, pmonitor); /* Sync memory */ monitor_sync(pmonitor); /* Wait for the child's exit status */ while (waitpid(pid, &status, 0) < 0) { if (errno == EINTR) continue; pmonitor->m_pid = -1; fatal("%s: waitpid: %s", __func__, strerror(errno)); } privsep_is_preauth = 0; pmonitor->m_pid = -1; if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) fatal("%s: preauth child exited with status %d", __func__, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) fatal("%s: preauth child terminated by signal %d", __func__, WTERMSIG(status)); if (box != NULL) ssh_sandbox_parent_finish(box); return 1; } else { /* child */ close(pmonitor->m_sendfd); close(pmonitor->m_log_recvfd); /* Arrange for logging to be sent to the monitor */ set_log_handler(mm_log_handler, pmonitor); /* Demote the child */ if (getuid() == 0 || geteuid() == 0) privsep_preauth_child(); setproctitle("%s", "[net]"); if (box != NULL) ssh_sandbox_child(box); return 0; } } static void privsep_postauth(Authctxt *authctxt) { u_int32_t rnd[256]; #ifdef DISABLE_FD_PASSING if (1) { #else if (authctxt->pw->pw_uid == 0 || options.use_login) { #endif /* File descriptor passing is broken or root login */ use_privsep = 0; goto skip; } /* New socket pair */ monitor_reinit(pmonitor); pmonitor->m_pid = fork(); if (pmonitor->m_pid == -1) fatal("fork of unprivileged child failed"); else if (pmonitor->m_pid != 0) { verbose("User child is on pid %ld", (long)pmonitor->m_pid); buffer_clear(&loginmsg); monitor_child_postauth(pmonitor); /* NEVERREACHED */ exit(0); } /* child */ close(pmonitor->m_sendfd); pmonitor->m_sendfd = -1; /* Demote the private keys to public keys. */ demote_sensitive_data(); arc4random_stir(); arc4random_buf(rnd, sizeof(rnd)); #ifdef WITH_OPENSSL RAND_seed(rnd, sizeof(rnd)); + if ((RAND_bytes((u_char *)rnd, 1)) != 1) + fatal("%s: RAND_bytes failed", __func__); #endif explicit_bzero(rnd, sizeof(rnd)); /* Drop privileges */ do_setusercontext(authctxt->pw); skip: /* It is safe now to apply the key state */ monitor_apply_keystate(pmonitor); /* * Tell the packet layer that authentication was successful, since * this information is not part of the key state. */ packet_set_authenticated(); } static char * list_hostkey_types(void) { Buffer b; const char *p; char *ret; int i; Key *key; buffer_init(&b); for (i = 0; i < options.num_host_key_files; i++) { key = sensitive_data.host_keys[i]; if (key == NULL) key = sensitive_data.host_pubkeys[i]; if (key == NULL || key->type == KEY_RSA1) continue; /* Check that the key is accepted in HostkeyAlgorithms */ if (match_pattern_list(sshkey_ssh_name(key), options.hostkeyalgorithms, 0) != 1) { debug3("%s: %s key not permitted by HostkeyAlgorithms", __func__, sshkey_ssh_name(key)); continue; } switch (key->type) { case KEY_RSA: case KEY_DSA: case KEY_ECDSA: case KEY_ED25519: if (buffer_len(&b) > 0) buffer_append(&b, ",", 1); p = key_ssh_name(key); buffer_append(&b, p, strlen(p)); break; } /* If the private key has a cert peer, then list that too */ key = sensitive_data.host_certificates[i]; if (key == NULL) continue; switch (key->type) { case KEY_RSA_CERT: case KEY_DSA_CERT: case KEY_ECDSA_CERT: case KEY_ED25519_CERT: if (buffer_len(&b) > 0) buffer_append(&b, ",", 1); p = key_ssh_name(key); buffer_append(&b, p, strlen(p)); break; } } buffer_append(&b, "\0", 1); ret = xstrdup(buffer_ptr(&b)); buffer_free(&b); debug("list_hostkey_types: %s", ret); return ret; } static Key * get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh) { int i; Key *key; for (i = 0; i < options.num_host_key_files; i++) { switch (type) { case KEY_RSA_CERT: case KEY_DSA_CERT: case KEY_ECDSA_CERT: case KEY_ED25519_CERT: key = sensitive_data.host_certificates[i]; break; default: key = sensitive_data.host_keys[i]; if (key == NULL && !need_private) key = sensitive_data.host_pubkeys[i]; break; } if (key != NULL && key->type == type && (key->type != KEY_ECDSA || key->ecdsa_nid == nid)) return need_private ? sensitive_data.host_keys[i] : key; } return NULL; } Key * get_hostkey_public_by_type(int type, int nid, struct ssh *ssh) { return get_hostkey_by_type(type, nid, 0, ssh); } Key * get_hostkey_private_by_type(int type, int nid, struct ssh *ssh) { return get_hostkey_by_type(type, nid, 1, ssh); } Key * get_hostkey_by_index(int ind) { if (ind < 0 || ind >= options.num_host_key_files) return (NULL); return (sensitive_data.host_keys[ind]); } Key * get_hostkey_public_by_index(int ind, struct ssh *ssh) { if (ind < 0 || ind >= options.num_host_key_files) return (NULL); return (sensitive_data.host_pubkeys[ind]); } int get_hostkey_index(Key *key, int compare, struct ssh *ssh) { int i; for (i = 0; i < options.num_host_key_files; i++) { if (key_is_cert(key)) { if (key == sensitive_data.host_certificates[i] || (compare && sensitive_data.host_certificates[i] && sshkey_equal(key, sensitive_data.host_certificates[i]))) return (i); } else { if (key == sensitive_data.host_keys[i] || (compare && sensitive_data.host_keys[i] && sshkey_equal(key, sensitive_data.host_keys[i]))) return (i); if (key == sensitive_data.host_pubkeys[i] || (compare && sensitive_data.host_pubkeys[i] && sshkey_equal(key, sensitive_data.host_pubkeys[i]))) return (i); } } return (-1); } /* Inform the client of all hostkeys */ static void notify_hostkeys(struct ssh *ssh) { struct sshbuf *buf; struct sshkey *key; int i, nkeys, r; char *fp; /* Some clients cannot cope with the hostkeys message, skip those. */ if (datafellows & SSH_BUG_HOSTKEYS) return; if ((buf = sshbuf_new()) == NULL) fatal("%s: sshbuf_new", __func__); for (i = nkeys = 0; i < options.num_host_key_files; i++) { key = get_hostkey_public_by_index(i, ssh); if (key == NULL || key->type == KEY_UNSPEC || key->type == KEY_RSA1 || sshkey_is_cert(key)) continue; fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); debug3("%s: key %d: %s %s", __func__, i, sshkey_ssh_name(key), fp); free(fp); if (nkeys == 0) { packet_start(SSH2_MSG_GLOBAL_REQUEST); packet_put_cstring("hostkeys-00@openssh.com"); packet_put_char(0); /* want-reply */ } sshbuf_reset(buf); if ((r = sshkey_putb(key, buf)) != 0) fatal("%s: couldn't put hostkey %d: %s", __func__, i, ssh_err(r)); packet_put_string(sshbuf_ptr(buf), sshbuf_len(buf)); nkeys++; } debug3("%s: sent %d hostkeys", __func__, nkeys); if (nkeys == 0) fatal("%s: no hostkeys", __func__); packet_send(); sshbuf_free(buf); } /* * returns 1 if connection should be dropped, 0 otherwise. * dropping starts at connection #max_startups_begin with a probability * of (max_startups_rate/100). the probability increases linearly until * all connections are dropped for startups > max_startups */ static int drop_connection(int startups) { int p, r; if (startups < options.max_startups_begin) return 0; if (startups >= options.max_startups) return 1; if (options.max_startups_rate == 100) return 1; p = 100 - options.max_startups_rate; p *= startups - options.max_startups_begin; p /= options.max_startups - options.max_startups_begin; p += options.max_startups_rate; r = arc4random_uniform(100); debug("drop_connection: p %d, r %d", p, r); return (r < p) ? 1 : 0; } static void usage(void) { if (options.version_addendum && *options.version_addendum != '\0') fprintf(stderr, "%s %s, %s\n", SSH_RELEASE, options.version_addendum, OPENSSL_VERSION); else fprintf(stderr, "%s, %s\n", SSH_RELEASE, OPENSSL_VERSION); fprintf(stderr, "usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-c host_cert_file]\n" " [-E log_file] [-f config_file] [-g login_grace_time]\n" " [-h host_key_file] [-k key_gen_time] [-o option] [-p port]\n" " [-u len]\n" ); exit(1); } static void send_rexec_state(int fd, Buffer *conf) { Buffer m; debug3("%s: entering fd = %d config len %d", __func__, fd, buffer_len(conf)); /* * Protocol from reexec master to child: * string configuration * u_int ephemeral_key_follows * bignum e (only if ephemeral_key_follows == 1) * bignum n " * bignum d " * bignum iqmp " * bignum p " * bignum q " * string rngseed (only if OpenSSL is not self-seeded) */ buffer_init(&m); buffer_put_cstring(&m, buffer_ptr(conf)); #ifdef WITH_SSH1 if (sensitive_data.server_key != NULL && sensitive_data.server_key->type == KEY_RSA1) { buffer_put_int(&m, 1); buffer_put_bignum(&m, sensitive_data.server_key->rsa->e); buffer_put_bignum(&m, sensitive_data.server_key->rsa->n); buffer_put_bignum(&m, sensitive_data.server_key->rsa->d); buffer_put_bignum(&m, sensitive_data.server_key->rsa->iqmp); buffer_put_bignum(&m, sensitive_data.server_key->rsa->p); buffer_put_bignum(&m, sensitive_data.server_key->rsa->q); } else #endif buffer_put_int(&m, 0); #if defined(WITH_OPENSSL) && !defined(OPENSSL_PRNG_ONLY) rexec_send_rng_seed(&m); #endif if (ssh_msg_send(fd, 0, &m) == -1) fatal("%s: ssh_msg_send failed", __func__); buffer_free(&m); debug3("%s: done", __func__); } static void recv_rexec_state(int fd, Buffer *conf) { Buffer m; char *cp; u_int len; debug3("%s: entering fd = %d", __func__, fd); buffer_init(&m); if (ssh_msg_recv(fd, &m) == -1) fatal("%s: ssh_msg_recv failed", __func__); if (buffer_get_char(&m) != 0) fatal("%s: rexec version mismatch", __func__); cp = buffer_get_string(&m, &len); if (conf != NULL) buffer_append(conf, cp, len + 1); free(cp); if (buffer_get_int(&m)) { #ifdef WITH_SSH1 if (sensitive_data.server_key != NULL) key_free(sensitive_data.server_key); sensitive_data.server_key = key_new_private(KEY_RSA1); buffer_get_bignum(&m, sensitive_data.server_key->rsa->e); buffer_get_bignum(&m, sensitive_data.server_key->rsa->n); buffer_get_bignum(&m, sensitive_data.server_key->rsa->d); buffer_get_bignum(&m, sensitive_data.server_key->rsa->iqmp); buffer_get_bignum(&m, sensitive_data.server_key->rsa->p); buffer_get_bignum(&m, sensitive_data.server_key->rsa->q); if (rsa_generate_additional_parameters( sensitive_data.server_key->rsa) != 0) fatal("%s: rsa_generate_additional_parameters " "error", __func__); #endif } #if defined(WITH_OPENSSL) && !defined(OPENSSL_PRNG_ONLY) rexec_recv_rng_seed(&m); #endif buffer_free(&m); debug3("%s: done", __func__); } /* Accept a connection from inetd */ static void server_accept_inetd(int *sock_in, int *sock_out) { int fd; startup_pipe = -1; if (rexeced_flag) { close(REEXEC_CONFIG_PASS_FD); *sock_in = *sock_out = dup(STDIN_FILENO); if (!debug_flag) { startup_pipe = dup(REEXEC_STARTUP_PIPE_FD); close(REEXEC_STARTUP_PIPE_FD); } } else { *sock_in = dup(STDIN_FILENO); *sock_out = dup(STDOUT_FILENO); } /* * We intentionally do not close the descriptors 0, 1, and 2 * as our code for setting the descriptors won't work if * ttyfd happens to be one of those. */ if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); if (!log_stderr) dup2(fd, STDERR_FILENO); if (fd > (log_stderr ? STDERR_FILENO : STDOUT_FILENO)) close(fd); } debug("inetd sockets after dupping: %d, %d", *sock_in, *sock_out); } /* * Listen for TCP connections */ static void server_listen(void) { int ret, listen_sock, on = 1; struct addrinfo *ai; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; int socksize; socklen_t len; for (ai = options.listen_addrs; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) continue; if (num_listen_socks >= MAX_LISTEN_SOCKS) fatal("Too many listen sockets. " "Enlarge MAX_LISTEN_SOCKS"); if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { error("getnameinfo failed: %.100s", ssh_gai_strerror(ret)); continue; } /* Create socket for listening. */ listen_sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (listen_sock < 0) { /* kernel may not support ipv6 */ verbose("socket: %.100s", strerror(errno)); continue; } if (set_nonblock(listen_sock) == -1) { close(listen_sock); continue; } /* * Set socket options. * Allow local port reuse in TIME_WAIT. */ if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) error("setsockopt SO_REUSEADDR: %s", strerror(errno)); /* Only communicate in IPv6 over AF_INET6 sockets. */ if (ai->ai_family == AF_INET6) sock_set_v6only(listen_sock); debug("Bind to port %s on %s.", strport, ntop); len = sizeof(socksize); getsockopt(listen_sock, SOL_SOCKET, SO_RCVBUF, &socksize, &len); debug("Server TCP RWIN socket size: %d", socksize); /* Bind the socket to the desired port. */ if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) { error("Bind to port %s on %s failed: %.200s.", strport, ntop, strerror(errno)); close(listen_sock); continue; } listen_socks[num_listen_socks] = listen_sock; num_listen_socks++; /* Start listening on the port. */ if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0) fatal("listen on [%s]:%s: %.100s", ntop, strport, strerror(errno)); logit("Server listening on %s port %s.", ntop, strport); } freeaddrinfo(options.listen_addrs); if (!num_listen_socks) fatal("Cannot bind any address."); } /* * The main TCP accept loop. Note that, for the non-debug case, returns * from this function are in a forked subprocess. */ static void server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) { fd_set *fdset; int i, j, ret, maxfd; int key_used = 0, startups = 0; int startup_p[2] = { -1 , -1 }; struct sockaddr_storage from; socklen_t fromlen; pid_t pid; u_char rnd[256]; /* setup fd set for accept */ fdset = NULL; maxfd = 0; for (i = 0; i < num_listen_socks; i++) if (listen_socks[i] > maxfd) maxfd = listen_socks[i]; /* pipes connected to unauthenticated childs */ startup_pipes = xcalloc(options.max_startups, sizeof(int)); for (i = 0; i < options.max_startups; i++) startup_pipes[i] = -1; /* * Stay listening for connections until the system crashes or * the daemon is killed with a signal. */ for (;;) { if (received_sighup) sighup_restart(); if (fdset != NULL) free(fdset); - fdset = (fd_set *)xcalloc(howmany(maxfd + 1, NFDBITS), + fdset = xcalloc(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask)); for (i = 0; i < num_listen_socks; i++) FD_SET(listen_socks[i], fdset); for (i = 0; i < options.max_startups; i++) if (startup_pipes[i] != -1) FD_SET(startup_pipes[i], fdset); /* Wait in select until there is a connection. */ ret = select(maxfd+1, fdset, NULL, NULL, NULL); if (ret < 0 && errno != EINTR) error("select: %.100s", strerror(errno)); if (received_sigterm) { logit("Received signal %d; terminating.", (int) received_sigterm); close_listen_socks(); if (options.pid_file != NULL) unlink(options.pid_file); exit(received_sigterm == SIGTERM ? 0 : 255); } if (key_used && key_do_regen) { generate_ephemeral_server_key(); key_used = 0; key_do_regen = 0; } if (ret < 0) continue; for (i = 0; i < options.max_startups; i++) if (startup_pipes[i] != -1 && FD_ISSET(startup_pipes[i], fdset)) { /* * the read end of the pipe is ready * if the child has closed the pipe * after successful authentication * or if the child has died */ close(startup_pipes[i]); startup_pipes[i] = -1; startups--; } for (i = 0; i < num_listen_socks; i++) { if (!FD_ISSET(listen_socks[i], fdset)) continue; fromlen = sizeof(from); *newsock = accept(listen_socks[i], (struct sockaddr *)&from, &fromlen); if (*newsock < 0) { if (errno != EINTR && errno != EWOULDBLOCK && errno != ECONNABORTED && errno != EAGAIN) error("accept: %.100s", strerror(errno)); if (errno == EMFILE || errno == ENFILE) usleep(100 * 1000); continue; } if (unset_nonblock(*newsock) == -1) { close(*newsock); continue; } if (drop_connection(startups) == 1) { debug("drop connection #%d", startups); close(*newsock); continue; } if (pipe(startup_p) == -1) { close(*newsock); continue; } if (rexec_flag && socketpair(AF_UNIX, SOCK_STREAM, 0, config_s) == -1) { error("reexec socketpair: %s", strerror(errno)); close(*newsock); close(startup_p[0]); close(startup_p[1]); continue; } for (j = 0; j < options.max_startups; j++) if (startup_pipes[j] == -1) { startup_pipes[j] = startup_p[0]; if (maxfd < startup_p[0]) maxfd = startup_p[0]; startups++; break; } /* * Got connection. Fork a child to handle it, unless * we are in debugging mode. */ if (debug_flag) { /* * In debugging mode. Close the listening * socket, and start processing the * connection without forking. */ debug("Server will not fork when running in debugging mode."); close_listen_socks(); *sock_in = *newsock; *sock_out = *newsock; close(startup_p[0]); close(startup_p[1]); startup_pipe = -1; pid = getpid(); if (rexec_flag) { send_rexec_state(config_s[0], &cfg); close(config_s[0]); } break; } /* * Normal production daemon. Fork, and have * the child process the connection. The * parent continues listening. */ platform_pre_fork(); if ((pid = fork()) == 0) { /* * Child. Close the listening and * max_startup sockets. Start using * the accepted socket. Reinitialize * logging (since our pid has changed). * We break out of the loop to handle * the connection. */ platform_post_fork_child(); startup_pipe = startup_p[1]; close_startup_pipes(); close_listen_socks(); *sock_in = *newsock; *sock_out = *newsock; log_init(__progname, options.log_level, options.log_facility, log_stderr); if (rexec_flag) close(config_s[0]); break; } /* Parent. Stay in the loop. */ platform_post_fork_parent(pid); if (pid < 0) error("fork: %.100s", strerror(errno)); else debug("Forked child %ld.", (long)pid); close(startup_p[1]); if (rexec_flag) { send_rexec_state(config_s[0], &cfg); close(config_s[0]); close(config_s[1]); } /* * Mark that the key has been used (it * was "given" to the child). */ if ((options.protocol & SSH_PROTO_1) && key_used == 0) { /* Schedule server key regeneration alarm. */ signal(SIGALRM, key_regeneration_alarm); alarm(options.key_regeneration_time); key_used = 1; } close(*newsock); /* * Ensure that our random state differs * from that of the child */ arc4random_stir(); arc4random_buf(rnd, sizeof(rnd)); #ifdef WITH_OPENSSL RAND_seed(rnd, sizeof(rnd)); + if ((RAND_bytes((u_char *)rnd, 1)) != 1) + fatal("%s: RAND_bytes failed", __func__); #endif explicit_bzero(rnd, sizeof(rnd)); } /* child process check (or debug mode) */ if (num_listen_socks < 0) break; } } /* * Main program for the daemon. */ int main(int ac, char **av) { extern char *optarg; extern int optind; int r, opt, i, j, on = 1; int sock_in = -1, sock_out = -1, newsock = -1; const char *remote_ip; int remote_port; char *fp, *line, *laddr, *logfile = NULL; int config_s[2] = { -1 , -1 }; u_int n; u_int64_t ibytes, obytes; mode_t new_umask; Key *key; Key *pubkey; int keytype; Authctxt *authctxt; struct connection_info *connection_info = get_connection_info(0, 0); #ifdef HAVE_SECUREWARE (void)set_auth_parameters(ac, av); #endif __progname = ssh_get_progname(av[0]); /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ saved_argc = ac; rexec_argc = ac; saved_argv = xcalloc(ac + 1, sizeof(*saved_argv)); for (i = 0; i < ac; i++) saved_argv[i] = xstrdup(av[i]); saved_argv[i] = NULL; #ifndef HAVE_SETPROCTITLE /* Prepare for later setproctitle emulation */ compat_init_setproctitle(ac, av); av = saved_argv; #endif if (geteuid() == 0 && setgroups(0, NULL) == -1) debug("setgroups(): %.200s", strerror(errno)); /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); /* Initialize configuration options to their default values. */ initialize_server_options(&options); /* Parse command-line arguments. */ while ((opt = getopt(ac, av, "C:E:b:c:f:g:h:k:o:p:u:46DQRTdeiqrt")) != -1) { switch (opt) { case '4': options.address_family = AF_INET; break; case '6': options.address_family = AF_INET6; break; case 'f': config_file_name = optarg; break; case 'c': if (options.num_host_cert_files >= MAX_HOSTCERTS) { fprintf(stderr, "too many host certificates.\n"); exit(1); } options.host_cert_files[options.num_host_cert_files++] = derelativise_path(optarg); break; case 'd': if (debug_flag == 0) { debug_flag = 1; options.log_level = SYSLOG_LEVEL_DEBUG1; } else if (options.log_level < SYSLOG_LEVEL_DEBUG3) options.log_level++; break; case 'D': no_daemon_flag = 1; break; case 'E': logfile = xstrdup(optarg); /* FALLTHROUGH */ case 'e': log_stderr = 1; break; case 'i': inetd_flag = 1; break; case 'r': rexec_flag = 0; break; case 'R': rexeced_flag = 1; inetd_flag = 1; break; case 'Q': /* ignored */ break; case 'q': options.log_level = SYSLOG_LEVEL_QUIET; break; case 'b': options.server_key_bits = (int)strtonum(optarg, 256, 32768, NULL); break; case 'p': options.ports_from_cmdline = 1; if (options.num_ports >= MAX_PORTS) { fprintf(stderr, "too many ports.\n"); exit(1); } options.ports[options.num_ports++] = a2port(optarg); if (options.ports[options.num_ports-1] <= 0) { fprintf(stderr, "Bad port number.\n"); exit(1); } break; case 'g': if ((options.login_grace_time = convtime(optarg)) == -1) { fprintf(stderr, "Invalid login grace time.\n"); exit(1); } break; case 'k': if ((options.key_regeneration_time = convtime(optarg)) == -1) { fprintf(stderr, "Invalid key regeneration interval.\n"); exit(1); } break; case 'h': if (options.num_host_key_files >= MAX_HOSTKEYS) { fprintf(stderr, "too many host keys.\n"); exit(1); } options.host_key_files[options.num_host_key_files++] = derelativise_path(optarg); break; case 't': test_flag = 1; break; case 'T': test_flag = 2; break; case 'C': if (parse_server_match_testspec(connection_info, optarg) == -1) exit(1); break; case 'u': utmp_len = (u_int)strtonum(optarg, 0, HOST_NAME_MAX+1+1, NULL); if (utmp_len > HOST_NAME_MAX+1) { fprintf(stderr, "Invalid utmp length.\n"); exit(1); } break; case 'o': line = xstrdup(optarg); if (process_server_config_line(&options, line, "command-line", 0, NULL, NULL) != 0) exit(1); free(line); break; case '?': default: usage(); break; } } if (rexeced_flag || inetd_flag) rexec_flag = 0; if (!test_flag && (rexec_flag && (av[0] == NULL || *av[0] != '/'))) fatal("sshd re-exec requires execution with an absolute path"); if (rexeced_flag) closefrom(REEXEC_MIN_FREE_FD); else closefrom(REEXEC_DEVCRYPTO_RESERVED_FD); #ifdef WITH_OPENSSL OpenSSL_add_all_algorithms(); #endif /* If requested, redirect the logs to the specified logfile. */ if (logfile != NULL) { log_redirect_stderr_to(logfile); free(logfile); } /* * Force logging to stderr until we have loaded the private host * key (unless started from inetd) */ log_init(__progname, options.log_level == SYSLOG_LEVEL_NOT_SET ? SYSLOG_LEVEL_INFO : options.log_level, options.log_facility == SYSLOG_FACILITY_NOT_SET ? SYSLOG_FACILITY_AUTH : options.log_facility, log_stderr || !inetd_flag); /* * Unset KRB5CCNAME, otherwise the user's session may inherit it from * root's environment */ if (getenv("KRB5CCNAME") != NULL) (void) unsetenv("KRB5CCNAME"); #ifdef _UNICOS /* Cray can define user privs drop all privs now! * Not needed on PRIV_SU systems! */ drop_cray_privs(); #endif sensitive_data.server_key = NULL; sensitive_data.ssh1_host_key = NULL; sensitive_data.have_ssh1_key = 0; sensitive_data.have_ssh2_key = 0; /* * If we're doing an extended config test, make sure we have all of * the parameters we need. If we're not doing an extended test, * do not silently ignore connection test params. */ if (test_flag >= 2 && server_match_spec_complete(connection_info) == 0) fatal("user, host and addr are all required when testing " "Match configs"); if (test_flag < 2 && server_match_spec_complete(connection_info) >= 0) fatal("Config test connection parameter (-C) provided without " "test mode (-T)"); /* Fetch our configuration */ buffer_init(&cfg); if (rexeced_flag) recv_rexec_state(REEXEC_CONFIG_PASS_FD, &cfg); else if (strcasecmp(config_file_name, "none") != 0) load_server_config(config_file_name, &cfg); parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name, &cfg, NULL); seed_rng(); /* Fill in default values for those options not explicitly set. */ fill_default_server_options(&options); /* challenge-response is implemented via keyboard interactive */ if (options.challenge_response_authentication) options.kbd_interactive_authentication = 1; /* Check that options are sensible */ if (options.authorized_keys_command_user == NULL && (options.authorized_keys_command != NULL && strcasecmp(options.authorized_keys_command, "none") != 0)) fatal("AuthorizedKeysCommand set without " "AuthorizedKeysCommandUser"); if (options.authorized_principals_command_user == NULL && (options.authorized_principals_command != NULL && strcasecmp(options.authorized_principals_command, "none") != 0)) fatal("AuthorizedPrincipalsCommand set without " "AuthorizedPrincipalsCommandUser"); /* * Check whether there is any path through configured auth methods. * Unfortunately it is not possible to verify this generally before * daemonisation in the presence of Match block, but this catches * and warns for trivial misconfigurations that could break login. */ if (options.num_auth_methods != 0) { if ((options.protocol & SSH_PROTO_1)) fatal("AuthenticationMethods is not supported with " "SSH protocol 1"); for (n = 0; n < options.num_auth_methods; n++) { if (auth2_methods_valid(options.auth_methods[n], 1) == 0) break; } if (n >= options.num_auth_methods) fatal("AuthenticationMethods cannot be satisfied by " "enabled authentication methods"); } /* set default channel AF */ channel_set_af(options.address_family); /* Check that there are no remaining arguments. */ if (optind < ac) { fprintf(stderr, "Extra argument %s.\n", av[optind]); exit(1); } debug("sshd version %s, %s", SSH_VERSION, #ifdef WITH_OPENSSL SSLeay_version(SSLEAY_VERSION) #else "without OpenSSL" #endif ); /* Store privilege separation user for later use if required. */ if ((privsep_pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) { if (use_privsep || options.kerberos_authentication) fatal("Privilege separation user %s does not exist", SSH_PRIVSEP_USER); } else { explicit_bzero(privsep_pw->pw_passwd, strlen(privsep_pw->pw_passwd)); privsep_pw = pwcopy(privsep_pw); free(privsep_pw->pw_passwd); privsep_pw->pw_passwd = xstrdup("*"); } endpwent(); /* load host keys */ sensitive_data.host_keys = xcalloc(options.num_host_key_files, sizeof(Key *)); sensitive_data.host_pubkeys = xcalloc(options.num_host_key_files, sizeof(Key *)); if (options.host_key_agent) { if (strcmp(options.host_key_agent, SSH_AUTHSOCKET_ENV_NAME)) setenv(SSH_AUTHSOCKET_ENV_NAME, options.host_key_agent, 1); if ((r = ssh_get_authentication_socket(NULL)) == 0) have_agent = 1; else error("Could not connect to agent \"%s\": %s", options.host_key_agent, ssh_err(r)); } for (i = 0; i < options.num_host_key_files; i++) { if (options.host_key_files[i] == NULL) continue; key = key_load_private(options.host_key_files[i], "", NULL); pubkey = key_load_public(options.host_key_files[i], NULL); if (pubkey == NULL && key != NULL) pubkey = key_demote(key); sensitive_data.host_keys[i] = key; sensitive_data.host_pubkeys[i] = pubkey; if (key == NULL && pubkey != NULL && pubkey->type != KEY_RSA1 && have_agent) { debug("will rely on agent for hostkey %s", options.host_key_files[i]); keytype = pubkey->type; } else if (key != NULL) { keytype = key->type; } else { error("Could not load host key: %s", options.host_key_files[i]); sensitive_data.host_keys[i] = NULL; sensitive_data.host_pubkeys[i] = NULL; continue; } switch (keytype) { case KEY_RSA1: sensitive_data.ssh1_host_key = key; sensitive_data.have_ssh1_key = 1; break; case KEY_RSA: case KEY_DSA: case KEY_ECDSA: case KEY_ED25519: if (have_agent || key != NULL) sensitive_data.have_ssh2_key = 1; break; } if ((fp = sshkey_fingerprint(pubkey, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) fatal("sshkey_fingerprint failed"); debug("%s host key #%d: %s %s", key ? "private" : "agent", i, keytype == KEY_RSA1 ? sshkey_type(pubkey) : sshkey_ssh_name(pubkey), fp); free(fp); } if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) { logit("Disabling protocol version 1. Could not load host key"); options.protocol &= ~SSH_PROTO_1; } if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { logit("Disabling protocol version 2. Could not load host key"); options.protocol &= ~SSH_PROTO_2; } if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { logit("sshd: no hostkeys available -- exiting."); exit(1); } /* * Load certificates. They are stored in an array at identical * indices to the public keys that they relate to. */ sensitive_data.host_certificates = xcalloc(options.num_host_key_files, sizeof(Key *)); for (i = 0; i < options.num_host_key_files; i++) sensitive_data.host_certificates[i] = NULL; for (i = 0; i < options.num_host_cert_files; i++) { if (options.host_cert_files[i] == NULL) continue; key = key_load_public(options.host_cert_files[i], NULL); if (key == NULL) { error("Could not load host certificate: %s", options.host_cert_files[i]); continue; } if (!key_is_cert(key)) { error("Certificate file is not a certificate: %s", options.host_cert_files[i]); key_free(key); continue; } /* Find matching private key */ for (j = 0; j < options.num_host_key_files; j++) { if (key_equal_public(key, sensitive_data.host_keys[j])) { sensitive_data.host_certificates[j] = key; break; } } if (j >= options.num_host_key_files) { error("No matching private key for certificate: %s", options.host_cert_files[i]); key_free(key); continue; } sensitive_data.host_certificates[j] = key; debug("host certificate: #%d type %d %s", j, key->type, key_type(key)); } #ifdef WITH_SSH1 /* Check certain values for sanity. */ if (options.protocol & SSH_PROTO_1) { if (options.server_key_bits < SSH_RSA_MINIMUM_MODULUS_SIZE || options.server_key_bits > OPENSSL_RSA_MAX_MODULUS_BITS) { fprintf(stderr, "Bad server key size.\n"); exit(1); } /* * Check that server and host key lengths differ sufficiently. This * is necessary to make double encryption work with rsaref. Oh, I * hate software patents. I dont know if this can go? Niels */ if (options.server_key_bits > BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) - SSH_KEY_BITS_RESERVED && options.server_key_bits < BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { options.server_key_bits = BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED; debug("Forcing server key to %d bits to make it differ from host key.", options.server_key_bits); } } #endif if (use_privsep) { struct stat st; if ((stat(_PATH_PRIVSEP_CHROOT_DIR, &st) == -1) || (S_ISDIR(st.st_mode) == 0)) fatal("Missing privilege separation directory: %s", _PATH_PRIVSEP_CHROOT_DIR); #ifdef HAVE_CYGWIN if (check_ntsec(_PATH_PRIVSEP_CHROOT_DIR) && (st.st_uid != getuid () || (st.st_mode & (S_IWGRP|S_IWOTH)) != 0)) #else if (st.st_uid != 0 || (st.st_mode & (S_IWGRP|S_IWOTH)) != 0) #endif fatal("%s must be owned by root and not group or " "world-writable.", _PATH_PRIVSEP_CHROOT_DIR); } if (test_flag > 1) { if (server_match_spec_complete(connection_info) == 1) parse_server_match_config(&options, connection_info); dump_config(&options); } /* Configuration looks good, so exit if in test mode. */ if (test_flag) exit(0); /* * Clear out any supplemental groups we may have inherited. This * prevents inadvertent creation of files with bad modes (in the * portable version at least, it's certainly possible for PAM * to create a file, and we can't control the code in every * module which might be used). */ if (setgroups(0, NULL) < 0) debug("setgroups() failed: %.200s", strerror(errno)); if (rexec_flag) { rexec_argv = xcalloc(rexec_argc + 2, sizeof(char *)); for (i = 0; i < rexec_argc; i++) { debug("rexec_argv[%d]='%s'", i, saved_argv[i]); rexec_argv[i] = saved_argv[i]; } rexec_argv[rexec_argc] = "-R"; rexec_argv[rexec_argc + 1] = NULL; } /* Ensure that umask disallows at least group and world write */ new_umask = umask(0077) | 0022; (void) umask(new_umask); /* Initialize the log (it is reinitialized below in case we forked). */ if (debug_flag && (!inetd_flag || rexeced_flag)) log_stderr = 1; log_init(__progname, options.log_level, options.log_facility, log_stderr); /* * If not in debugging mode, and not started from inetd, disconnect * from the controlling terminal, and fork. The original process * exits. */ if (!(debug_flag || inetd_flag || no_daemon_flag)) { #ifdef TIOCNOTTY int fd; #endif /* TIOCNOTTY */ if (daemon(0, 0) < 0) fatal("daemon() failed: %.200s", strerror(errno)); /* Disconnect from the controlling tty. */ #ifdef TIOCNOTTY fd = open(_PATH_TTY, O_RDWR | O_NOCTTY); if (fd >= 0) { (void) ioctl(fd, TIOCNOTTY, NULL); close(fd); } #endif /* TIOCNOTTY */ } /* Reinitialize the log (because of the fork above). */ log_init(__progname, options.log_level, options.log_facility, log_stderr); /* Avoid killing the process in high-pressure swapping environments. */ if (!inetd_flag && madvise(NULL, 0, MADV_PROTECT) != 0) debug("madvise(): %.200s", strerror(errno)); /* Chdir to the root directory so that the current disk can be unmounted if desired. */ if (chdir("/") == -1) error("chdir(\"/\"): %s", strerror(errno)); /* ignore SIGPIPE */ signal(SIGPIPE, SIG_IGN); /* Get a connection, either from inetd or a listening TCP socket */ if (inetd_flag) { server_accept_inetd(&sock_in, &sock_out); } else { platform_pre_listen(); server_listen(); if (options.protocol & SSH_PROTO_1) generate_ephemeral_server_key(); signal(SIGHUP, sighup_handler); signal(SIGCHLD, main_sigchld_handler); signal(SIGTERM, sigterm_handler); signal(SIGQUIT, sigterm_handler); /* * Write out the pid file after the sigterm handler * is setup and the listen sockets are bound */ if (options.pid_file != NULL && !debug_flag) { FILE *f = fopen(options.pid_file, "w"); if (f == NULL) { error("Couldn't create pid file \"%s\": %s", options.pid_file, strerror(errno)); } else { fprintf(f, "%ld\n", (long) getpid()); fclose(f); } } /* Accept a connection and return in a forked child */ server_accept_loop(&sock_in, &sock_out, &newsock, config_s); } /* This is the child processing a new connection. */ setproctitle("%s", "[accepted]"); /* * Create a new session and process group since the 4.4BSD * setlogin() affects the entire process group. We don't * want the child to be able to affect the parent. */ #if !defined(SSHD_ACQUIRES_CTTY) /* * If setsid is called, on some platforms sshd will later acquire a * controlling terminal which will result in "could not set * controlling tty" errors. */ if (!debug_flag && !inetd_flag && setsid() < 0) error("setsid: %.100s", strerror(errno)); #endif if (rexec_flag) { int fd; debug("rexec start in %d out %d newsock %d pipe %d sock %d", sock_in, sock_out, newsock, startup_pipe, config_s[0]); dup2(newsock, STDIN_FILENO); dup2(STDIN_FILENO, STDOUT_FILENO); if (startup_pipe == -1) close(REEXEC_STARTUP_PIPE_FD); else if (startup_pipe != REEXEC_STARTUP_PIPE_FD) { dup2(startup_pipe, REEXEC_STARTUP_PIPE_FD); close(startup_pipe); startup_pipe = REEXEC_STARTUP_PIPE_FD; } dup2(config_s[1], REEXEC_CONFIG_PASS_FD); close(config_s[1]); execv(rexec_argv[0], rexec_argv); /* Reexec has failed, fall back and continue */ error("rexec of %s failed: %s", rexec_argv[0], strerror(errno)); recv_rexec_state(REEXEC_CONFIG_PASS_FD, NULL); log_init(__progname, options.log_level, options.log_facility, log_stderr); /* Clean up fds */ close(REEXEC_CONFIG_PASS_FD); newsock = sock_out = sock_in = dup(STDIN_FILENO); if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); if (fd > STDERR_FILENO) close(fd); } debug("rexec cleanup in %d out %d newsock %d pipe %d sock %d", sock_in, sock_out, newsock, startup_pipe, config_s[0]); } /* Executed child processes don't need these. */ fcntl(sock_out, F_SETFD, FD_CLOEXEC); fcntl(sock_in, F_SETFD, FD_CLOEXEC); /* * Disable the key regeneration alarm. We will not regenerate the * key since we are no longer in a position to give it to anyone. We * will not restart on SIGHUP since it no longer makes sense. */ alarm(0); signal(SIGALRM, SIG_DFL); signal(SIGHUP, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGCHLD, SIG_DFL); signal(SIGINT, SIG_DFL); #ifdef __FreeBSD__ /* * Initialize the resolver. This may not happen automatically * before privsep chroot(). */ if ((_res.options & RES_INIT) == 0) { debug("res_init()"); res_init(); } #ifdef GSSAPI /* * Force GSS-API to parse its configuration and load any * mechanism plugins. */ { gss_OID_set mechs; OM_uint32 minor_status; gss_indicate_mechs(&minor_status, &mechs); gss_release_oid_set(&minor_status, &mechs); } #endif #endif /* * Register our connection. This turns encryption off because we do * not have a key. */ packet_set_connection(sock_in, sock_out); packet_set_server(); /* Set SO_KEEPALIVE if requested. */ if (options.tcp_keep_alive && packet_connection_is_on_socket() && setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0) error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); if ((remote_port = get_remote_port()) < 0) { debug("get_remote_port failed"); cleanup_exit(255); } /* * We use get_canonical_hostname with usedns = 0 instead of * get_remote_ipaddr here so IP options will be checked. */ (void) get_canonical_hostname(0); /* * The rest of the code depends on the fact that * get_remote_ipaddr() caches the remote ip, even if * the socket goes away. */ remote_ip = get_remote_ipaddr(); #ifdef SSH_AUDIT_EVENTS audit_connection_from(remote_ip, remote_port); #endif #ifdef LIBWRAP allow_severity = options.log_facility|LOG_INFO; deny_severity = options.log_facility|LOG_WARNING; /* Check whether logins are denied from this host. */ if (packet_connection_is_on_socket()) { struct request_info req; request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0); fromhost(&req); if (!hosts_access(&req)) { debug("Connection refused by tcp wrapper"); refuse(&req); /* NOTREACHED */ fatal("libwrap refuse returns"); } } #endif /* LIBWRAP */ /* Log the connection. */ laddr = get_local_ipaddr(sock_in); verbose("Connection from %s port %d on %s port %d", remote_ip, remote_port, laddr, get_local_port()); free(laddr); /* * We don't want to listen forever unless the other side * successfully authenticates itself. So we set up an alarm which is * cleared after successful authentication. A limit of zero * indicates no limit. Note that we don't set the alarm in debugging * mode; it is just annoying to have the server exit just when you * are about to discover the bug. */ signal(SIGALRM, grace_alarm_handler); if (!debug_flag) alarm(options.login_grace_time); sshd_exchange_identification(sock_in, sock_out); /* In inetd mode, generate ephemeral key only for proto 1 connections */ if (!compat20 && inetd_flag && sensitive_data.server_key == NULL) generate_ephemeral_server_key(); packet_set_nonblocking(); /* allocate authentication context */ authctxt = xcalloc(1, sizeof(*authctxt)); authctxt->loginmsg = &loginmsg; /* XXX global for cleanup, access from other modules */ the_authctxt = authctxt; /* prepare buffer to collect messages to display to user after login */ buffer_init(&loginmsg); auth_debug_reset(); if (use_privsep) { if (privsep_preauth(authctxt) == 1) goto authenticated; } else if (compat20 && have_agent) { if ((r = ssh_get_authentication_socket(&auth_sock)) != 0) { error("Unable to get agent socket: %s", ssh_err(r)); have_agent = 0; } } /* perform the key exchange */ /* authenticate user and start session */ if (compat20) { do_ssh2_kex(); do_authentication2(authctxt); } else { #ifdef WITH_SSH1 do_ssh1_kex(); do_authentication(authctxt); #else fatal("ssh1 not supported"); #endif } /* * If we use privilege separation, the unprivileged child transfers * the current keystate and exits */ if (use_privsep) { mm_send_keystate(pmonitor); exit(0); } authenticated: /* * Cancel the alarm we set to limit the time taken for * authentication. */ alarm(0); signal(SIGALRM, SIG_DFL); authctxt->authenticated = 1; if (startup_pipe != -1) { close(startup_pipe); startup_pipe = -1; } #ifdef SSH_AUDIT_EVENTS audit_event(SSH_AUTH_SUCCESS); #endif #ifdef GSSAPI if (options.gss_authentication) { temporarily_use_uid(authctxt->pw); ssh_gssapi_storecreds(); restore_uid(); } #endif #ifdef USE_PAM if (options.use_pam) { do_pam_setcred(1); do_pam_session(); } #endif /* * In privilege separation, we fork another child and prepare * file descriptor passing. */ if (use_privsep) { privsep_postauth(authctxt); /* the monitor process [priv] will not return */ if (!compat20) destroy_sensitive_data(); } packet_set_timeout(options.client_alive_interval, options.client_alive_count_max); /* Try to send all our hostkeys to the client */ if (compat20) notify_hostkeys(active_state); /* Start session. */ do_authenticated(authctxt); /* The connection has been terminated. */ packet_get_bytes(&ibytes, &obytes); verbose("Transferred: sent %llu, received %llu bytes", (unsigned long long)obytes, (unsigned long long)ibytes); verbose("Closing connection to %.500s port %d", remote_ip, remote_port); #ifdef USE_PAM if (options.use_pam) finish_pam(); #endif /* USE_PAM */ #ifdef SSH_AUDIT_EVENTS PRIVSEP(audit_event(SSH_CONNECTION_CLOSE)); #endif packet_close(); if (use_privsep) mm_terminate(); exit(0); } #ifdef WITH_SSH1 /* * Decrypt session_key_int using our private server key and private host key * (key with larger modulus first). */ int ssh1_session_key(BIGNUM *session_key_int) { int rsafail = 0; if (BN_cmp(sensitive_data.server_key->rsa->n, sensitive_data.ssh1_host_key->rsa->n) > 0) { /* Server key has bigger modulus. */ if (BN_num_bits(sensitive_data.server_key->rsa->n) < BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { fatal("do_connection: %s: " "server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", get_remote_ipaddr(), BN_num_bits(sensitive_data.server_key->rsa->n), BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), SSH_KEY_BITS_RESERVED); } if (rsa_private_decrypt(session_key_int, session_key_int, sensitive_data.server_key->rsa) != 0) rsafail++; if (rsa_private_decrypt(session_key_int, session_key_int, sensitive_data.ssh1_host_key->rsa) != 0) rsafail++; } else { /* Host key has bigger modulus (or they are equal). */ if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) < BN_num_bits(sensitive_data.server_key->rsa->n) + SSH_KEY_BITS_RESERVED) { fatal("do_connection: %s: " "host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d", get_remote_ipaddr(), BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), BN_num_bits(sensitive_data.server_key->rsa->n), SSH_KEY_BITS_RESERVED); } if (rsa_private_decrypt(session_key_int, session_key_int, sensitive_data.ssh1_host_key->rsa) != 0) rsafail++; if (rsa_private_decrypt(session_key_int, session_key_int, sensitive_data.server_key->rsa) != 0) rsafail++; } return (rsafail); } /* * SSH1 key exchange */ static void do_ssh1_kex(void) { int i, len; int rsafail = 0; BIGNUM *session_key_int, *fake_key_int, *real_key_int; u_char session_key[SSH_SESSION_KEY_LENGTH]; u_char fake_key_bytes[4096 / 8]; size_t fake_key_len; u_char cookie[8]; u_int cipher_type, auth_mask, protocol_flags; /* * Generate check bytes that the client must send back in the user * packet in order for it to be accepted; this is used to defy ip * spoofing attacks. Note that this only works against somebody * doing IP spoofing from a remote machine; any machine on the local * network can still see outgoing packets and catch the random * cookie. This only affects rhosts authentication, and this is one * of the reasons why it is inherently insecure. */ arc4random_buf(cookie, sizeof(cookie)); /* * Send our public key. We include in the packet 64 bits of random * data that must be matched in the reply in order to prevent IP * spoofing. */ packet_start(SSH_SMSG_PUBLIC_KEY); for (i = 0; i < 8; i++) packet_put_char(cookie[i]); /* Store our public server RSA key. */ packet_put_int(BN_num_bits(sensitive_data.server_key->rsa->n)); packet_put_bignum(sensitive_data.server_key->rsa->e); packet_put_bignum(sensitive_data.server_key->rsa->n); /* Store our public host RSA key. */ packet_put_int(BN_num_bits(sensitive_data.ssh1_host_key->rsa->n)); packet_put_bignum(sensitive_data.ssh1_host_key->rsa->e); packet_put_bignum(sensitive_data.ssh1_host_key->rsa->n); /* Put protocol flags. */ packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN); /* Declare which ciphers we support. */ packet_put_int(cipher_mask_ssh1(0)); /* Declare supported authentication types. */ auth_mask = 0; if (options.rhosts_rsa_authentication) auth_mask |= 1 << SSH_AUTH_RHOSTS_RSA; if (options.rsa_authentication) auth_mask |= 1 << SSH_AUTH_RSA; if (options.challenge_response_authentication == 1) auth_mask |= 1 << SSH_AUTH_TIS; if (options.password_authentication) auth_mask |= 1 << SSH_AUTH_PASSWORD; packet_put_int(auth_mask); /* Send the packet and wait for it to be sent. */ packet_send(); packet_write_wait(); debug("Sent %d bit server key and %d bit host key.", BN_num_bits(sensitive_data.server_key->rsa->n), BN_num_bits(sensitive_data.ssh1_host_key->rsa->n)); /* Read clients reply (cipher type and session key). */ packet_read_expect(SSH_CMSG_SESSION_KEY); /* Get cipher type and check whether we accept this. */ cipher_type = packet_get_char(); if (!(cipher_mask_ssh1(0) & (1 << cipher_type))) packet_disconnect("Warning: client selects unsupported cipher."); /* Get check bytes from the packet. These must match those we sent earlier with the public key packet. */ for (i = 0; i < 8; i++) if (cookie[i] != packet_get_char()) packet_disconnect("IP Spoofing check bytes do not match."); debug("Encryption type: %.200s", cipher_name(cipher_type)); /* Get the encrypted integer. */ if ((real_key_int = BN_new()) == NULL) fatal("do_ssh1_kex: BN_new failed"); packet_get_bignum(real_key_int); protocol_flags = packet_get_int(); packet_set_protocol_flags(protocol_flags); packet_check_eom(); /* Setup a fake key in case RSA decryption fails */ if ((fake_key_int = BN_new()) == NULL) fatal("do_ssh1_kex: BN_new failed"); fake_key_len = BN_num_bytes(real_key_int); if (fake_key_len > sizeof(fake_key_bytes)) fake_key_len = sizeof(fake_key_bytes); arc4random_buf(fake_key_bytes, fake_key_len); if (BN_bin2bn(fake_key_bytes, fake_key_len, fake_key_int) == NULL) fatal("do_ssh1_kex: BN_bin2bn failed"); /* Decrypt real_key_int using host/server keys */ rsafail = PRIVSEP(ssh1_session_key(real_key_int)); /* If decryption failed, use the fake key. Else, the real key. */ if (rsafail) session_key_int = fake_key_int; else session_key_int = real_key_int; /* * Extract session key from the decrypted integer. The key is in the * least significant 256 bits of the integer; the first byte of the * key is in the highest bits. */ (void) BN_mask_bits(session_key_int, sizeof(session_key) * 8); len = BN_num_bytes(session_key_int); if (len < 0 || (u_int)len > sizeof(session_key)) { error("do_ssh1_kex: bad session key len from %s: " "session_key_int %d > sizeof(session_key) %lu", get_remote_ipaddr(), len, (u_long)sizeof(session_key)); rsafail++; } else { explicit_bzero(session_key, sizeof(session_key)); BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len); derive_ssh1_session_id( sensitive_data.ssh1_host_key->rsa->n, sensitive_data.server_key->rsa->n, cookie, session_id); /* * Xor the first 16 bytes of the session key with the * session id. */ for (i = 0; i < 16; i++) session_key[i] ^= session_id[i]; } /* Destroy the private and public keys. No longer. */ destroy_sensitive_data(); if (use_privsep) mm_ssh1_session_id(session_id); /* Destroy the decrypted integer. It is no longer needed. */ BN_clear_free(real_key_int); BN_clear_free(fake_key_int); /* Set the session key. From this on all communications will be encrypted. */ packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, cipher_type); /* Destroy our copy of the session key. It is no longer needed. */ explicit_bzero(session_key, sizeof(session_key)); debug("Received session key; encryption turned on."); /* Send an acknowledgment packet. Note that this packet is sent encrypted. */ packet_start(SSH_SMSG_SUCCESS); packet_send(); packet_write_wait(); } #endif int sshd_hostkey_sign(Key *privkey, Key *pubkey, u_char **signature, size_t *slen, const u_char *data, size_t dlen, u_int flag) { int r; u_int xxx_slen, xxx_dlen = dlen; if (privkey) { if (PRIVSEP(key_sign(privkey, signature, &xxx_slen, data, xxx_dlen) < 0)) fatal("%s: key_sign failed", __func__); if (slen) *slen = xxx_slen; } else if (use_privsep) { if (mm_key_sign(pubkey, signature, &xxx_slen, data, xxx_dlen) < 0) fatal("%s: pubkey_sign failed", __func__); if (slen) *slen = xxx_slen; } else { if ((r = ssh_agent_sign(auth_sock, pubkey, signature, slen, data, dlen, datafellows)) != 0) fatal("%s: ssh_agent_sign failed: %s", __func__, ssh_err(r)); } return 0; } /* SSH2 key exchange */ static void do_ssh2_kex(void) { char *myproposal[PROPOSAL_MAX] = { KEX_SERVER }; struct kex *kex; int r; myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( options.kex_algorithms); myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal( options.ciphers); myproposal[PROPOSAL_ENC_ALGS_STOC] = compat_cipher_proposal( options.ciphers); myproposal[PROPOSAL_MAC_ALGS_CTOS] = myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; if (options.compression == COMP_NONE) { myproposal[PROPOSAL_COMP_ALGS_CTOS] = myproposal[PROPOSAL_COMP_ALGS_STOC] = "none"; } else if (options.compression == COMP_DELAYED) { myproposal[PROPOSAL_COMP_ALGS_CTOS] = myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com"; } if (options.rekey_limit || options.rekey_interval) packet_set_rekey_limits((u_int32_t)options.rekey_limit, (time_t)options.rekey_interval); myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( list_hostkey_types()); /* start key exchange */ if ((r = kex_setup(active_state, myproposal)) != 0) fatal("kex_setup: %s", ssh_err(r)); kex = active_state->kex; #ifdef WITH_OPENSSL kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; # ifdef OPENSSL_HAS_ECC kex->kex[KEX_ECDH_SHA2] = kexecdh_server; # endif #endif kex->kex[KEX_C25519_SHA256] = kexc25519_server; kex->server = 1; kex->client_version_string=client_version_string; kex->server_version_string=server_version_string; kex->load_host_public_key=&get_hostkey_public_by_type; kex->load_host_private_key=&get_hostkey_private_by_type; kex->host_key_index=&get_hostkey_index; kex->sign = sshd_hostkey_sign; dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); session_id2 = kex->session_id; session_id2_len = kex->session_id_len; #ifdef DEBUG_KEXDH /* send 1st encrypted/maced/compressed message */ packet_start(SSH2_MSG_IGNORE); packet_put_cstring("markus"); packet_send(); packet_write_wait(); #endif debug("KEX done"); } /* server specific fatal cleanup */ void cleanup_exit(int i) { if (the_authctxt) { do_cleanup(the_authctxt); if (use_privsep && privsep_is_preauth && pmonitor != NULL && pmonitor->m_pid > 1) { debug("Killing privsep child %d", pmonitor->m_pid); if (kill(pmonitor->m_pid, SIGKILL) != 0 && errno != ESRCH) error("%s: kill(%d): %s", __func__, pmonitor->m_pid, strerror(errno)); } } #ifdef SSH_AUDIT_EVENTS /* done after do_cleanup so it can cancel the PAM auth 'thread' */ if (!use_privsep || mm_is_monitor()) audit_event(SSH_CONNECTION_ABANDON); #endif _exit(i); } Index: head/crypto/openssh/sshd_config =================================================================== --- head/crypto/openssh/sshd_config (revision 294495) +++ head/crypto/openssh/sshd_config (revision 294496) @@ -1,136 +1,136 @@ # $OpenBSD: sshd_config,v 1.97 2015/08/06 14:53:21 deraadt Exp $ # $FreeBSD$ # This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. # This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin # The strategy used for options in the default sshd_config shipped with # OpenSSH is to specify options with their default value where # possible, but leave them commented. Uncommented options override the # default value. # Note that some of FreeBSD's defaults differ from OpenBSD's, and # FreeBSD has a few additional options. #Port 22 #AddressFamily any #ListenAddress 0.0.0.0 #ListenAddress :: # The default requires explicit activation of protocol 1 #Protocol 2 # HostKey for protocol version 1 #HostKey /etc/ssh/ssh_host_key # HostKeys for protocol version 2 #HostKey /etc/ssh/ssh_host_rsa_key #HostKey /etc/ssh/ssh_host_dsa_key #HostKey /etc/ssh/ssh_host_ecdsa_key #HostKey /etc/ssh/ssh_host_ed25519_key # Lifetime and size of ephemeral version 1 server key #KeyRegenerationInterval 1h #ServerKeyBits 1024 # Ciphers and keying #RekeyLimit default none # Logging # obsoletes QuietMode and FascistLogging #SyslogFacility AUTH #LogLevel INFO # Authentication: #LoginGraceTime 2m #PermitRootLogin prohibit-password #StrictModes yes #MaxAuthTries 6 #MaxSessions 10 #RSAAuthentication yes #PubkeyAuthentication yes # The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 #AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2 #AuthorizedPrincipalsFile none #AuthorizedKeysCommand none #AuthorizedKeysCommandUser nobody # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts #RhostsRSAAuthentication no # similar for protocol version 2 #HostbasedAuthentication no # Change to yes if you don't trust ~/.ssh/known_hosts for # RhostsRSAAuthentication and HostbasedAuthentication #IgnoreUserKnownHosts no # Don't read the user's ~/.rhosts and ~/.shosts files #IgnoreRhosts yes # Change to yes to enable built-in password authentication. #PasswordAuthentication no #PermitEmptyPasswords no # Change to no to disable PAM authentication #ChallengeResponseAuthentication yes # Kerberos options #KerberosAuthentication no #KerberosOrLocalPasswd yes #KerberosTicketCleanup yes #KerberosGetAFSToken no # GSSAPI options #GSSAPIAuthentication no #GSSAPICleanupCredentials yes # Set this to 'no' to disable PAM authentication, account processing, # and session processing. If this is enabled, PAM authentication will # be allowed through the ChallengeResponseAuthentication and # PasswordAuthentication. Depending on your PAM configuration, # PAM authentication via ChallengeResponseAuthentication may bypass # the setting of "PermitRootLogin without-password". # If you just want the PAM account and session checks to run without # PAM authentication, then enable this but set PasswordAuthentication # and ChallengeResponseAuthentication to 'no'. #UsePAM yes #AllowAgentForwarding yes #AllowTcpForwarding yes #GatewayPorts no #X11Forwarding yes #X11DisplayOffset 10 #X11UseLocalhost yes #PermitTTY yes #PrintMotd yes #PrintLastLog yes #TCPKeepAlive yes #UseLogin no #UsePrivilegeSeparation sandbox #PermitUserEnvironment no #Compression delayed #ClientAliveInterval 0 #ClientAliveCountMax 3 #UseDNS no #PidFile /var/run/sshd.pid #MaxStartups 10:30:100 #PermitTunnel no #ChrootDirectory none -#VersionAddendum FreeBSD-20160119 +#VersionAddendum FreeBSD-20160121 # no default banner path #Banner none # override default of no subsystems Subsystem sftp /usr/libexec/sftp-server # Example of overriding settings on a per-user basis #Match User anoncvs # X11Forwarding no # AllowTcpForwarding no # PermitTTY no # ForceCommand cvs server Index: head/crypto/openssh/sshd_config.5 =================================================================== --- head/crypto/openssh/sshd_config.5 (revision 294495) +++ head/crypto/openssh/sshd_config.5 (revision 294496) @@ -1,1756 +1,1756 @@ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland .\" All rights reserved .\" .\" As far as I am concerned, the code I have written for this software .\" can be used freely for any purpose. Any derived versions of this .\" software must be clearly marked as such, and if the derived work is .\" incompatible with the protocol description in the RFC file, it must be .\" called by a name other than "ssh" or "Secure Shell". .\" .\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. .\" Copyright (c) 1999 Aaron Campbell. All rights reserved. .\" Copyright (c) 1999 Theo de Raadt. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.210 2015/08/06 14:53:21 deraadt Exp $ +.\" $OpenBSD: sshd_config.5,v 1.211 2015/08/14 15:32:41 jmc Exp $ .\" $FreeBSD$ -.Dd $Mdocdate: August 6 2015 $ +.Dd $Mdocdate: August 14 2015 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME .Nm sshd_config .Nd OpenSSH SSH daemon configuration file .Sh SYNOPSIS .Nm /etc/ssh/sshd_config .Sh DESCRIPTION .Xr sshd 8 reads configuration data from .Pa /etc/ssh/sshd_config (or the file specified with .Fl f on the command line). The file contains keyword-argument pairs, one per line. Lines starting with .Ql # and empty lines are interpreted as comments. Arguments may optionally be enclosed in double quotes .Pq \&" in order to represent arguments containing spaces. .Pp The possible keywords and their meanings are as follows (note that keywords are case-insensitive and arguments are case-sensitive): .Bl -tag -width Ds .It Cm AcceptEnv Specifies what environment variables sent by the client will be copied into the session's .Xr environ 7 . See .Cm SendEnv in .Xr ssh_config 5 for how to configure the client. Note that environment passing is only supported for protocol 2, and that the .Ev TERM environment variable is always sent whenever the client requests a pseudo-terminal as it is required by the protocol. Variables are specified by name, which may contain the wildcard characters .Ql * and .Ql \&? . Multiple environment variables may be separated by whitespace or spread across multiple .Cm AcceptEnv directives. Be warned that some environment variables could be used to bypass restricted user environments. For this reason, care should be taken in the use of this directive. The default is not to accept any environment variables. .It Cm AddressFamily Specifies which address family should be used by .Xr sshd 8 . Valid arguments are .Dq any , .Dq inet (use IPv4 only), or .Dq inet6 (use IPv6 only). The default is .Dq any . .It Cm AllowAgentForwarding Specifies whether .Xr ssh-agent 1 forwarding is permitted. The default is .Dq yes . Note that disabling agent forwarding does not improve security unless users are also denied shell access, as they can always install their own forwarders. .It Cm AllowGroups This keyword can be followed by a list of group name patterns, separated by spaces. If specified, login is allowed only for users whose primary group or supplementary group list matches one of the patterns. Only group names are valid; a numerical group ID is not recognized. By default, login is allowed for all groups. The allow/deny directives are processed in the following order: .Cm DenyUsers , .Cm AllowUsers , .Cm DenyGroups , and finally .Cm AllowGroups . .Pp See PATTERNS in .Xr ssh_config 5 for more information on patterns. .It Cm AllowTcpForwarding Specifies whether TCP forwarding is permitted. The available options are .Dq yes or .Dq all to allow TCP forwarding, .Dq no to prevent all TCP forwarding, .Dq local to allow local (from the perspective of .Xr ssh 1 ) forwarding only or .Dq remote to allow remote forwarding only. The default is .Dq yes . Note that disabling TCP forwarding does not improve security unless users are also denied shell access, as they can always install their own forwarders. .It Cm AllowStreamLocalForwarding Specifies whether StreamLocal (Unix-domain socket) forwarding is permitted. The available options are .Dq yes or .Dq all to allow StreamLocal forwarding, .Dq no to prevent all StreamLocal forwarding, .Dq local to allow local (from the perspective of .Xr ssh 1 ) forwarding only or .Dq remote to allow remote forwarding only. The default is .Dq yes . Note that disabling StreamLocal forwarding does not improve security unless users are also denied shell access, as they can always install their own forwarders. .It Cm AllowUsers This keyword can be followed by a list of user name patterns, separated by spaces. If specified, login is allowed only for user names that match one of the patterns. Only user names are valid; a numerical user ID is not recognized. By default, login is allowed for all users. If the pattern takes the form USER@HOST then USER and HOST are separately checked, restricting logins to particular users from particular hosts. The allow/deny directives are processed in the following order: .Cm DenyUsers , .Cm AllowUsers , .Cm DenyGroups , and finally .Cm AllowGroups . .Pp See PATTERNS in .Xr ssh_config 5 for more information on patterns. .It Cm AuthenticationMethods Specifies the authentication methods that must be successfully completed for a user to be granted access. This option must be followed by one or more comma-separated lists of authentication method names. Successful authentication requires completion of every method in at least one of these lists. .Pp For example, an argument of .Dq publickey,password publickey,keyboard-interactive would require the user to complete public key authentication, followed by either password or keyboard interactive authentication. Only methods that are next in one or more lists are offered at each stage, so for this example, it would not be possible to attempt password or keyboard-interactive authentication before public key. .Pp For keyboard interactive authentication it is also possible to restrict authentication to a specific device by appending a colon followed by the device identifier .Dq bsdauth , .Dq pam , or .Dq skey , depending on the server configuration. For example, .Dq keyboard-interactive:bsdauth would restrict keyboard interactive authentication to the .Dq bsdauth device. .Pp If the .Dq publickey method is listed more than once, .Xr sshd 8 verifies that keys that have been used successfully are not reused for subsequent authentications. For example, an .Cm AuthenticationMethods of .Dq publickey,publickey will require successful authentication using two different public keys. .Pp This option is only available for SSH protocol 2 and will yield a fatal error if enabled if protocol 1 is also enabled. Note that each authentication method listed should also be explicitly enabled in the configuration. The default is not to require multiple authentication; successful completion of a single authentication method is sufficient. .It Cm AuthorizedKeysCommand Specifies a program to be used to look up the user's public keys. The program must be owned by root, not writable by group or others and specified by an absolute path. .Pp Arguments to .Cm AuthorizedKeysCommand may be provided using the following tokens, which will be expanded at runtime: %% is replaced by a literal '%', %u is replaced by the username being authenticated, %h is replaced by the home directory of the user being authenticated, %t is replaced with the key type offered for authentication, %f is replaced with the fingerprint of the key, and %k is replaced with the key being offered for authentication. If no arguments are specified then the username of the target user will be supplied. .Pp The program should produce on standard output zero or more lines of authorized_keys output (see AUTHORIZED_KEYS in .Xr sshd 8 ) . If a key supplied by AuthorizedKeysCommand does not successfully authenticate and authorize the user then public key authentication continues using the usual .Cm AuthorizedKeysFile files. By default, no AuthorizedKeysCommand is run. .It Cm AuthorizedKeysCommandUser Specifies the user under whose account the AuthorizedKeysCommand is run. It is recommended to use a dedicated user that has no other role on the host than running authorized keys commands. If .Cm AuthorizedKeysCommand is specified but .Cm AuthorizedKeysCommandUser is not, then .Xr sshd 8 will refuse to start. .It Cm AuthorizedKeysFile Specifies the file that contains the public keys that can be used for user authentication. The format is described in the AUTHORIZED_KEYS FILE FORMAT section of .Xr sshd 8 . .Cm AuthorizedKeysFile may contain tokens of the form %T which are substituted during connection setup. The following tokens are defined: %% is replaced by a literal '%', %h is replaced by the home directory of the user being authenticated, and %u is replaced by the username of that user. After expansion, .Cm AuthorizedKeysFile is taken to be an absolute path or one relative to the user's home directory. Multiple files may be listed, separated by whitespace. The default is .Dq .ssh/authorized_keys .ssh/authorized_keys2 . .It Cm AuthorizedPrincipalsCommand Specifies a program to be used to generate the list of allowed certificate principals as per .Cm AuthorizedPrincipalsFile . The program must be owned by root, not writable by group or others and specified by an absolute path. .Pp Arguments to .Cm AuthorizedPrincipalsCommand may be provided using the following tokens, which will be expanded at runtime: %% is replaced by a literal '%', %u is replaced by the username being authenticated and %h is replaced by the home directory of the user being authenticated. .Pp The program should produce on standard output zero or more lines of .Cm AuthorizedPrincipalsFile output. If either .Cm AuthorizedPrincipalsCommand or .Cm AuthorizedPrincipalsFile is specified, then certificates offered by the client for authentication must contain a principal that is listed. By default, no AuthorizedPrincipalsCommand is run. .It Cm AuthorizedPrincipalsCommandUser Specifies the user under whose account the AuthorizedPrincipalsCommand is run. It is recommended to use a dedicated user that has no other role on the host than running authorized principals commands. If .Cm AuthorizedPrincipalsCommand is specified but .Cm AuthorizedPrincipalsCommandUser is not, then .Xr sshd 8 will refuse to start. .It Cm AuthorizedPrincipalsFile Specifies a file that lists principal names that are accepted for certificate authentication. When using certificates signed by a key listed in .Cm TrustedUserCAKeys , this file lists names, one of which must appear in the certificate for it to be accepted for authentication. Names are listed one per line preceded by key options (as described in AUTHORIZED_KEYS FILE FORMAT in .Xr sshd 8 ) . Empty lines and comments starting with .Ql # are ignored. .Pp .Cm AuthorizedPrincipalsFile may contain tokens of the form %T which are substituted during connection setup. The following tokens are defined: %% is replaced by a literal '%', %h is replaced by the home directory of the user being authenticated, and %u is replaced by the username of that user. After expansion, .Cm AuthorizedPrincipalsFile is taken to be an absolute path or one relative to the user's home directory. .Pp The default is .Dq none , i.e. not to use a principals file \(en in this case, the username of the user must appear in a certificate's principals list for it to be accepted. Note that .Cm AuthorizedPrincipalsFile is only used when authentication proceeds using a CA listed in .Cm TrustedUserCAKeys and is not consulted for certification authorities trusted via .Pa ~/.ssh/authorized_keys , though the .Cm principals= key option offers a similar facility (see .Xr sshd 8 for details). .It Cm Banner The contents of the specified file are sent to the remote user before authentication is allowed. If the argument is .Dq none then no banner is displayed. This option is only available for protocol version 2. By default, no banner is displayed. .It Cm ChallengeResponseAuthentication Specifies whether challenge-response authentication is allowed (e.g. via PAM or through authentication styles supported in .Xr login.conf 5 ) The default is .Dq yes . .It Cm ChrootDirectory Specifies the pathname of a directory to .Xr chroot 2 to after authentication. At session startup .Xr sshd 8 checks that all components of the pathname are root-owned directories which are not writable by any other user or group. After the chroot, .Xr sshd 8 changes the working directory to the user's home directory. .Pp The pathname may contain the following tokens that are expanded at runtime once the connecting user has been authenticated: %% is replaced by a literal '%', %h is replaced by the home directory of the user being authenticated, and %u is replaced by the username of that user. .Pp The .Cm ChrootDirectory must contain the necessary files and directories to support the user's session. For an interactive session this requires at least a shell, typically .Xr sh 1 , and basic .Pa /dev nodes such as .Xr null 4 , .Xr zero 4 , .Xr stdin 4 , .Xr stdout 4 , .Xr stderr 4 , and .Xr tty 4 devices. For file transfer sessions using .Dq sftp , no additional configuration of the environment is necessary if the in-process sftp server is used, though sessions which use logging may require .Pa /dev/log inside the chroot directory on some operating systems (see .Xr sftp-server 8 for details). .Pp For safety, it is very important that the directory hierarchy be prevented from modification by other processes on the system (especially those outside the jail). Misconfiguration can lead to unsafe environments which .Xr sshd 8 cannot detect. .Pp The default is not to .Xr chroot 2 . .It Cm Ciphers Specifies the ciphers allowed for protocol version 2. Multiple ciphers must be comma-separated. If the specified value begins with a .Sq + character, then the specified ciphers will be appended to the default set instead of replacing them. .Pp The supported ciphers are: .Pp .Bl -item -compact -offset indent .It 3des-cbc .It aes128-cbc .It aes192-cbc .It aes256-cbc .It aes128-ctr .It aes192-ctr .It aes256-ctr .It aes128-gcm@openssh.com .It aes256-gcm@openssh.com .It arcfour .It arcfour128 .It arcfour256 .It blowfish-cbc .It cast128-cbc .It chacha20-poly1305@openssh.com .El .Pp The default is: .Bd -literal -offset indent +chacha20-poly1305@openssh.com, aes128-ctr,aes192-ctr,aes256-ctr, -aes128-gcm@openssh.com,aes256-gcm@openssh.com, -chacha20-poly1305@openssh.com +aes128-gcm@openssh.com,aes256-gcm@openssh.com .Ed .Pp The list of available ciphers may also be obtained using the .Fl Q option of .Xr ssh 1 with an argument of .Dq cipher . .It Cm ClientAliveCountMax Sets the number of client alive messages (see below) which may be sent without .Xr sshd 8 receiving any messages back from the client. If this threshold is reached while client alive messages are being sent, sshd will disconnect the client, terminating the session. It is important to note that the use of client alive messages is very different from .Cm TCPKeepAlive (below). The client alive messages are sent through the encrypted channel and therefore will not be spoofable. The TCP keepalive option enabled by .Cm TCPKeepAlive is spoofable. The client alive mechanism is valuable when the client or server depend on knowing when a connection has become inactive. .Pp The default value is 3. If .Cm ClientAliveInterval (see below) is set to 15, and .Cm ClientAliveCountMax is left at the default, unresponsive SSH clients will be disconnected after approximately 45 seconds. This option applies to protocol version 2 only. .It Cm ClientAliveInterval Sets a timeout interval in seconds after which if no data has been received from the client, .Xr sshd 8 will send a message through the encrypted channel to request a response from the client. The default is 0, indicating that these messages will not be sent to the client. This option applies to protocol version 2 only. .It Cm Compression Specifies whether compression is allowed, or delayed until the user has authenticated successfully. The argument must be .Dq yes , .Dq delayed , or .Dq no . The default is .Dq delayed . .It Cm DenyGroups This keyword can be followed by a list of group name patterns, separated by spaces. Login is disallowed for users whose primary group or supplementary group list matches one of the patterns. Only group names are valid; a numerical group ID is not recognized. By default, login is allowed for all groups. The allow/deny directives are processed in the following order: .Cm DenyUsers , .Cm AllowUsers , .Cm DenyGroups , and finally .Cm AllowGroups . .Pp See PATTERNS in .Xr ssh_config 5 for more information on patterns. .It Cm DenyUsers This keyword can be followed by a list of user name patterns, separated by spaces. Login is disallowed for user names that match one of the patterns. Only user names are valid; a numerical user ID is not recognized. By default, login is allowed for all users. If the pattern takes the form USER@HOST then USER and HOST are separately checked, restricting logins to particular users from particular hosts. The allow/deny directives are processed in the following order: .Cm DenyUsers , .Cm AllowUsers , .Cm DenyGroups , and finally .Cm AllowGroups . .Pp See PATTERNS in .Xr ssh_config 5 for more information on patterns. .It Cm FingerprintHash Specifies the hash algorithm used when logging key fingerprints. Valid options are: .Dq md5 and .Dq sha256 . The default is .Dq sha256 . .It Cm ForceCommand Forces the execution of the command specified by .Cm ForceCommand , ignoring any command supplied by the client and .Pa ~/.ssh/rc if present. The command is invoked by using the user's login shell with the -c option. This applies to shell, command, or subsystem execution. It is most useful inside a .Cm Match block. The command originally supplied by the client is available in the .Ev SSH_ORIGINAL_COMMAND environment variable. Specifying a command of .Dq internal-sftp will force the use of an in-process sftp server that requires no support files when used with .Cm ChrootDirectory . .It Cm GatewayPorts Specifies whether remote hosts are allowed to connect to ports forwarded for the client. By default, .Xr sshd 8 binds remote port forwardings to the loopback address. This prevents other remote hosts from connecting to forwarded ports. .Cm GatewayPorts can be used to specify that sshd should allow remote port forwardings to bind to non-loopback addresses, thus allowing other hosts to connect. The argument may be .Dq no to force remote port forwardings to be available to the local host only, .Dq yes to force remote port forwardings to bind to the wildcard address, or .Dq clientspecified to allow the client to select the address to which the forwarding is bound. The default is .Dq no . .It Cm GSSAPIAuthentication Specifies whether user authentication based on GSSAPI is allowed. The default is .Dq no . Note that this option applies to protocol version 2 only. .It Cm GSSAPICleanupCredentials Specifies whether to automatically destroy the user's credentials cache on logout. The default is .Dq yes . Note that this option applies to protocol version 2 only. .It Cm GSSAPIStrictAcceptorCheck Determines whether to be strict about the identity of the GSSAPI acceptor a client authenticates against. If set to .Dq yes then the client must authenticate against the .Pa host service on the current hostname. If set to .Dq no then the client may authenticate against any service key stored in the machine's default store. This facility is provided to assist with operation on multi homed machines. The default is .Dq yes . .It Cm HostbasedAcceptedKeyTypes Specifies the key types that will be accepted for hostbased authentication as a comma-separated pattern list. Alternately if the specified value begins with a .Sq + character, then the specified key types will be appended to the default set instead of replacing them. The default for this option is: .Bd -literal -offset 3n ecdsa-sha2-nistp256-cert-v01@openssh.com, ecdsa-sha2-nistp384-cert-v01@openssh.com, ecdsa-sha2-nistp521-cert-v01@openssh.com, ssh-ed25519-cert-v01@openssh.com, ssh-rsa-cert-v01@openssh.com, ssh-dss-cert-v01@openssh.com, ecdsa-sha2-nistp256,ecdsa-sha2-nistp384, ecdsa-sha2-nistp521,ssh-ed25519, ssh-rsa,ssh-dss .Ed .Pp The .Fl Q option of .Xr ssh 1 may be used to list supported key types. .It Cm HostbasedAuthentication Specifies whether rhosts or /etc/hosts.equiv authentication together with successful public key client host authentication is allowed (host-based authentication). This option is similar to .Cm RhostsRSAAuthentication and applies to protocol version 2 only. The default is .Dq no . .It Cm HostbasedUsesNameFromPacketOnly Specifies whether or not the server will attempt to perform a reverse name lookup when matching the name in the .Pa ~/.shosts , .Pa ~/.rhosts , and .Pa /etc/hosts.equiv files during .Cm HostbasedAuthentication . A setting of .Dq yes means that .Xr sshd 8 uses the name supplied by the client rather than attempting to resolve the name from the TCP connection itself. The default is .Dq no . .It Cm HostCertificate Specifies a file containing a public host certificate. The certificate's public key must match a private host key already specified by .Cm HostKey . The default behaviour of .Xr sshd 8 is not to load any certificates. .It Cm HostKey Specifies a file containing a private host key used by SSH. The default is .Pa /etc/ssh/ssh_host_key for protocol version 1, and .Pa /etc/ssh/ssh_host_dsa_key , .Pa /etc/ssh/ssh_host_ecdsa_key , .Pa /etc/ssh/ssh_host_ed25519_key and .Pa /etc/ssh/ssh_host_rsa_key for protocol version 2. .Pp Note that .Xr sshd 8 will refuse to use a file if it is group/world-accessible and that the .Cm HostKeyAlgorithms option restricts which of the keys are actually used by .Xr sshd 8 . .Pp It is possible to have multiple host key files. .Dq rsa1 keys are used for version 1 and .Dq dsa , .Dq ecdsa , .Dq ed25519 or .Dq rsa are used for version 2 of the SSH protocol. It is also possible to specify public host key files instead. In this case operations on the private key will be delegated to an .Xr ssh-agent 1 . .It Cm HostKeyAgent Identifies the UNIX-domain socket used to communicate with an agent that has access to the private host keys. If .Dq SSH_AUTH_SOCK is specified, the location of the socket will be read from the .Ev SSH_AUTH_SOCK environment variable. .It Cm HostKeyAlgorithms Specifies the protocol version 2 host key algorithms that the server offers. The default for this option is: .Bd -literal -offset 3n ecdsa-sha2-nistp256-cert-v01@openssh.com, ecdsa-sha2-nistp384-cert-v01@openssh.com, ecdsa-sha2-nistp521-cert-v01@openssh.com, ssh-ed25519-cert-v01@openssh.com, ssh-rsa-cert-v01@openssh.com, ssh-dss-cert-v01@openssh.com, ecdsa-sha2-nistp256,ecdsa-sha2-nistp384, ecdsa-sha2-nistp521,ssh-ed25519, ssh-rsa,ssh-dss .Ed .Pp The list of available key types may also be obtained using the .Fl Q option of .Xr ssh 1 with an argument of .Dq key . .It Cm IgnoreRhosts Specifies that .Pa .rhosts and .Pa .shosts files will not be used in .Cm RhostsRSAAuthentication or .Cm HostbasedAuthentication . .Pp .Pa /etc/hosts.equiv and .Pa /etc/ssh/shosts.equiv are still used. The default is .Dq yes . .It Cm IgnoreUserKnownHosts Specifies whether .Xr sshd 8 should ignore the user's .Pa ~/.ssh/known_hosts during .Cm RhostsRSAAuthentication or .Cm HostbasedAuthentication . The default is .Dq no . .It Cm IPQoS Specifies the IPv4 type-of-service or DSCP class for the connection. Accepted values are .Dq af11 , .Dq af12 , .Dq af13 , .Dq af21 , .Dq af22 , .Dq af23 , .Dq af31 , .Dq af32 , .Dq af33 , .Dq af41 , .Dq af42 , .Dq af43 , .Dq cs0 , .Dq cs1 , .Dq cs2 , .Dq cs3 , .Dq cs4 , .Dq cs5 , .Dq cs6 , .Dq cs7 , .Dq ef , .Dq lowdelay , .Dq throughput , .Dq reliability , or a numeric value. This option may take one or two arguments, separated by whitespace. If one argument is specified, it is used as the packet class unconditionally. If two values are specified, the first is automatically selected for interactive sessions and the second for non-interactive sessions. The default is .Dq lowdelay for interactive sessions and .Dq throughput for non-interactive sessions. .It Cm KbdInteractiveAuthentication Specifies whether to allow keyboard-interactive authentication. The argument to this keyword must be .Dq yes or .Dq no . The default is to use whatever value .Cm ChallengeResponseAuthentication is set to (by default .Dq yes ) . .It Cm KerberosAuthentication Specifies whether the password provided by the user for .Cm PasswordAuthentication will be validated through the Kerberos KDC. To use this option, the server needs a Kerberos servtab which allows the verification of the KDC's identity. The default is .Dq no . .It Cm KerberosGetAFSToken If AFS is active and the user has a Kerberos 5 TGT, attempt to acquire an AFS token before accessing the user's home directory. The default is .Dq no . .It Cm KerberosOrLocalPasswd If password authentication through Kerberos fails then the password will be validated via any additional local mechanism such as .Pa /etc/passwd . The default is .Dq yes . .It Cm KerberosTicketCleanup Specifies whether to automatically destroy the user's ticket cache file on logout. The default is .Dq yes . .It Cm KexAlgorithms Specifies the available KEX (Key Exchange) algorithms. Multiple algorithms must be comma-separated. Alternately if the specified value begins with a .Sq + character, then the specified methods will be appended to the default set instead of replacing them. The supported algorithms are: .Pp .Bl -item -compact -offset indent .It curve25519-sha256@libssh.org .It diffie-hellman-group1-sha1 .It diffie-hellman-group14-sha1 .It diffie-hellman-group-exchange-sha1 .It diffie-hellman-group-exchange-sha256 .It ecdh-sha2-nistp256 .It ecdh-sha2-nistp384 .It ecdh-sha2-nistp521 .El .Pp The default is: .Bd -literal -offset indent curve25519-sha256@libssh.org, ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521, diffie-hellman-group-exchange-sha256, diffie-hellman-group14-sha1 .Ed .Pp The list of available key exchange algorithms may also be obtained using the .Fl Q option of .Xr ssh 1 with an argument of .Dq kex . .It Cm KeyRegenerationInterval In protocol version 1, the ephemeral server key is automatically regenerated after this many seconds (if it has been used). The purpose of regeneration is to prevent decrypting captured sessions by later breaking into the machine and stealing the keys. The key is never stored anywhere. If the value is 0, the key is never regenerated. The default is 3600 (seconds). .It Cm ListenAddress Specifies the local addresses .Xr sshd 8 should listen on. The following forms may be used: .Pp .Bl -item -offset indent -compact .It .Cm ListenAddress .Sm off .Ar host | Ar IPv4_addr | Ar IPv6_addr .Sm on .It .Cm ListenAddress .Sm off .Ar host | Ar IPv4_addr : Ar port .Sm on .It .Cm ListenAddress .Sm off .Oo .Ar host | Ar IPv6_addr Oc : Ar port .Sm on .El .Pp If .Ar port is not specified, sshd will listen on the address and all .Cm Port options specified. The default is to listen on all local addresses. Multiple .Cm ListenAddress options are permitted. .It Cm LoginGraceTime The server disconnects after this time if the user has not successfully logged in. If the value is 0, there is no time limit. The default is 120 seconds. .It Cm LogLevel Gives the verbosity level that is used when logging messages from .Xr sshd 8 . The possible values are: QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3. The default is INFO. DEBUG and DEBUG1 are equivalent. DEBUG2 and DEBUG3 each specify higher levels of debugging output. Logging with a DEBUG level violates the privacy of users and is not recommended. .It Cm MACs Specifies the available MAC (message authentication code) algorithms. The MAC algorithm is used in protocol version 2 for data integrity protection. Multiple algorithms must be comma-separated. If the specified value begins with a .Sq + character, then the specified algorithms will be appended to the default set instead of replacing them. .Pp The algorithms that contain .Dq -etm calculate the MAC after encryption (encrypt-then-mac). These are considered safer and their use recommended. The supported MACs are: .Pp .Bl -item -compact -offset indent .It hmac-md5 .It hmac-md5-96 .It hmac-ripemd160 .It hmac-sha1 .It hmac-sha1-96 .It hmac-sha2-256 .It hmac-sha2-512 .It umac-64@openssh.com .It umac-128@openssh.com .It hmac-md5-etm@openssh.com .It hmac-md5-96-etm@openssh.com .It hmac-ripemd160-etm@openssh.com .It hmac-sha1-etm@openssh.com .It hmac-sha1-96-etm@openssh.com .It hmac-sha2-256-etm@openssh.com .It hmac-sha2-512-etm@openssh.com .It umac-64-etm@openssh.com .It umac-128-etm@openssh.com .El .Pp The default is: .Bd -literal -offset indent umac-64-etm@openssh.com,umac-128-etm@openssh.com, hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com, umac-64@openssh.com,umac-128@openssh.com, hmac-sha2-256,hmac-sha2-512 .Ed .Pp The list of available MAC algorithms may also be obtained using the .Fl Q option of .Xr ssh 1 with an argument of .Dq mac . .It Cm Match Introduces a conditional block. If all of the criteria on the .Cm Match line are satisfied, the keywords on the following lines override those set in the global section of the config file, until either another .Cm Match line or the end of the file. If a keyword appears in multiple .Cm Match blocks that are satisfied, only the first instance of the keyword is applied. .Pp The arguments to .Cm Match are one or more criteria-pattern pairs or the single token .Cm All which matches all criteria. The available criteria are .Cm User , .Cm Group , .Cm Host , .Cm LocalAddress , .Cm LocalPort , and .Cm Address . The match patterns may consist of single entries or comma-separated lists and may use the wildcard and negation operators described in the PATTERNS section of .Xr ssh_config 5 . .Pp The patterns in an .Cm Address criteria may additionally contain addresses to match in CIDR address/masklen format, e.g.\& .Dq 192.0.2.0/24 or .Dq 3ffe:ffff::/32 . Note that the mask length provided must be consistent with the address - it is an error to specify a mask length that is too long for the address or one with bits set in this host portion of the address. For example, .Dq 192.0.2.0/33 and .Dq 192.0.2.0/8 respectively. .Pp Only a subset of keywords may be used on the lines following a .Cm Match keyword. Available keywords are .Cm AcceptEnv , .Cm AllowAgentForwarding , .Cm AllowGroups , .Cm AllowStreamLocalForwarding , .Cm AllowTcpForwarding , .Cm AllowUsers , .Cm AuthenticationMethods , .Cm AuthorizedKeysCommand , .Cm AuthorizedKeysCommandUser , .Cm AuthorizedKeysFile , .Cm AuthorizedPrincipalsFile , .Cm Banner , .Cm ChrootDirectory , .Cm DenyGroups , .Cm DenyUsers , .Cm ForceCommand , .Cm GatewayPorts , .Cm GSSAPIAuthentication , .Cm HostbasedAcceptedKeyTypes , .Cm HostbasedAuthentication , .Cm HostbasedUsesNameFromPacketOnly , .Cm IPQoS , .Cm KbdInteractiveAuthentication , .Cm KerberosAuthentication , .Cm MaxAuthTries , .Cm MaxSessions , .Cm PasswordAuthentication , .Cm PermitEmptyPasswords , .Cm PermitOpen , .Cm PermitRootLogin , .Cm PermitTTY , .Cm PermitTunnel , .Cm PermitUserRC , .Cm PubkeyAcceptedKeyTypes , .Cm PubkeyAuthentication , .Cm RekeyLimit , .Cm RevokedKeys , .Cm RhostsRSAAuthentication , .Cm RSAAuthentication , .Cm StreamLocalBindMask , .Cm StreamLocalBindUnlink , .Cm TrustedUserCAKeys , .Cm X11DisplayOffset , .Cm X11Forwarding and .Cm X11UseLocalHost . .It Cm MaxAuthTries Specifies the maximum number of authentication attempts permitted per connection. Once the number of failures reaches half this value, additional failures are logged. The default is 6. .It Cm MaxSessions Specifies the maximum number of open sessions permitted per network connection. The default is 10. .It Cm MaxStartups Specifies the maximum number of concurrent unauthenticated connections to the SSH daemon. Additional connections will be dropped until authentication succeeds or the .Cm LoginGraceTime expires for a connection. The default is 10:30:100. .Pp Alternatively, random early drop can be enabled by specifying the three colon separated values .Dq start:rate:full (e.g. "10:30:60"). .Xr sshd 8 will refuse connection attempts with a probability of .Dq rate/100 (30%) if there are currently .Dq start (10) unauthenticated connections. The probability increases linearly and all connection attempts are refused if the number of unauthenticated connections reaches .Dq full (60). .It Cm PasswordAuthentication Specifies whether password authentication is allowed. See also .Cm UsePAM . The default is .Dq no . .It Cm PermitEmptyPasswords When password authentication is allowed, it specifies whether the server allows login to accounts with empty password strings. The default is .Dq no . .It Cm PermitOpen Specifies the destinations to which TCP port forwarding is permitted. The forwarding specification must be one of the following forms: .Pp .Bl -item -offset indent -compact .It .Cm PermitOpen .Sm off .Ar host : port .Sm on .It .Cm PermitOpen .Sm off .Ar IPv4_addr : port .Sm on .It .Cm PermitOpen .Sm off .Ar \&[ IPv6_addr \&] : port .Sm on .El .Pp Multiple forwards may be specified by separating them with whitespace. An argument of .Dq any can be used to remove all restrictions and permit any forwarding requests. An argument of .Dq none can be used to prohibit all forwarding requests. By default all port forwarding requests are permitted. .It Cm PermitRootLogin Specifies whether root can log in using .Xr ssh 1 . The argument must be .Dq yes , .Dq prohibit-password , .Dq without-password , .Dq forced-commands-only , or .Dq no . The default is .Dq prohibit-password . Note that if .Cm ChallengeResponseAuthentication is .Dq yes , the root user may be allowed in with its password even if .Cm PermitRootLogin is set to .Dq without-password . .Pp If this option is set to .Dq prohibit-password or .Dq without-password , password and keyboard-interactive authentication are disabled for root. .Pp If this option is set to .Dq forced-commands-only , root login with public key authentication will be allowed, but only if the .Ar command option has been specified (which may be useful for taking remote backups even if root login is normally not allowed). All other authentication methods are disabled for root. .Pp If this option is set to .Dq no , root is not allowed to log in. .It Cm PermitTunnel Specifies whether .Xr tun 4 device forwarding is allowed. The argument must be .Dq yes , .Dq point-to-point (layer 3), .Dq ethernet (layer 2), or .Dq no . Specifying .Dq yes permits both .Dq point-to-point and .Dq ethernet . The default is .Dq no . .Pp Independent of this setting, the permissions of the selected .Xr tun 4 device must allow access to the user. .It Cm PermitTTY Specifies whether .Xr pty 4 allocation is permitted. The default is .Dq yes . .It Cm PermitUserEnvironment Specifies whether .Pa ~/.ssh/environment and .Cm environment= options in .Pa ~/.ssh/authorized_keys are processed by .Xr sshd 8 . The default is .Dq no . Enabling environment processing may enable users to bypass access restrictions in some configurations using mechanisms such as .Ev LD_PRELOAD . .It Cm PermitUserRC Specifies whether any .Pa ~/.ssh/rc file is executed. The default is .Dq yes . .It Cm PidFile Specifies the file that contains the process ID of the SSH daemon, or .Dq none to not write one. The default is .Pa /var/run/sshd.pid . .It Cm Port Specifies the port number that .Xr sshd 8 listens on. The default is 22. Multiple options of this type are permitted. See also .Cm ListenAddress . .It Cm PrintLastLog Specifies whether .Xr sshd 8 should print the date and time of the last user login when a user logs in interactively. The default is .Dq yes . .It Cm PrintMotd Specifies whether .Xr sshd 8 should print .Pa /etc/motd when a user logs in interactively. (On some systems it is also printed by the shell, .Pa /etc/profile , or equivalent.) The default is .Dq yes . .It Cm Protocol Specifies the protocol versions .Xr sshd 8 supports. The possible values are .Sq 1 and .Sq 2 . Multiple versions must be comma-separated. The default is .Sq 2 . Note that the order of the protocol list does not indicate preference, because the client selects among multiple protocol versions offered by the server. Specifying .Dq 2,1 is identical to .Dq 1,2 . .It Cm PubkeyAcceptedKeyTypes Specifies the key types that will be accepted for public key authentication as a comma-separated pattern list. Alternately if the specified value begins with a .Sq + character, then the specified key types will be appended to the default set instead of replacing them. The default for this option is: .Bd -literal -offset 3n ecdsa-sha2-nistp256-cert-v01@openssh.com, ecdsa-sha2-nistp384-cert-v01@openssh.com, ecdsa-sha2-nistp521-cert-v01@openssh.com, ssh-ed25519-cert-v01@openssh.com, ssh-rsa-cert-v01@openssh.com, ssh-dss-cert-v01@openssh.com, ecdsa-sha2-nistp256,ecdsa-sha2-nistp384, ecdsa-sha2-nistp521,ssh-ed25519, ssh-rsa,ssh-dss .Ed .Pp The .Fl Q option of .Xr ssh 1 may be used to list supported key types. .It Cm PubkeyAuthentication Specifies whether public key authentication is allowed. The default is .Dq yes . Note that this option applies to protocol version 2 only. .It Cm RekeyLimit Specifies the maximum amount of data that may be transmitted before the session key is renegotiated, optionally followed a maximum amount of time that may pass before the session key is renegotiated. The first argument is specified in bytes and may have a suffix of .Sq K , .Sq M , or .Sq G to indicate Kilobytes, Megabytes, or Gigabytes, respectively. The default is between .Sq 1G and .Sq 4G , depending on the cipher. The optional second value is specified in seconds and may use any of the units documented in the .Sx TIME FORMATS section. The default value for .Cm RekeyLimit is .Dq default none , which means that rekeying is performed after the cipher's default amount of data has been sent or received and no time based rekeying is done. This option applies to protocol version 2 only. .It Cm RevokedKeys Specifies revoked public keys file, or .Dq none to not use one. Keys listed in this file will be refused for public key authentication. Note that if this file is not readable, then public key authentication will be refused for all users. Keys may be specified as a text file, listing one public key per line, or as an OpenSSH Key Revocation List (KRL) as generated by .Xr ssh-keygen 1 . For more information on KRLs, see the KEY REVOCATION LISTS section in .Xr ssh-keygen 1 . .It Cm RhostsRSAAuthentication Specifies whether rhosts or .Pa /etc/hosts.equiv authentication together with successful RSA host authentication is allowed. The default is .Dq no . This option applies to protocol version 1 only. .It Cm RSAAuthentication Specifies whether pure RSA authentication is allowed. The default is .Dq yes . This option applies to protocol version 1 only. .It Cm ServerKeyBits Defines the number of bits in the ephemeral protocol version 1 server key. The default and minimum value is 1024. .It Cm StreamLocalBindMask Sets the octal file creation mode mask .Pq umask used when creating a Unix-domain socket file for local or remote port forwarding. This option is only used for port forwarding to a Unix-domain socket file. .Pp The default value is 0177, which creates a Unix-domain socket file that is readable and writable only by the owner. Note that not all operating systems honor the file mode on Unix-domain socket files. .It Cm StreamLocalBindUnlink Specifies whether to remove an existing Unix-domain socket file for local or remote port forwarding before creating a new one. If the socket file already exists and .Cm StreamLocalBindUnlink is not enabled, .Nm sshd will be unable to forward the port to the Unix-domain socket file. This option is only used for port forwarding to a Unix-domain socket file. .Pp The argument must be .Dq yes or .Dq no . The default is .Dq no . .It Cm StrictModes Specifies whether .Xr sshd 8 should check file modes and ownership of the user's files and home directory before accepting login. This is normally desirable because novices sometimes accidentally leave their directory or files world-writable. The default is .Dq yes . Note that this does not apply to .Cm ChrootDirectory , whose permissions and ownership are checked unconditionally. .It Cm Subsystem Configures an external subsystem (e.g. file transfer daemon). Arguments should be a subsystem name and a command (with optional arguments) to execute upon subsystem request. .Pp The command .Xr sftp-server 8 implements the .Dq sftp file transfer subsystem. .Pp Alternately the name .Dq internal-sftp implements an in-process .Dq sftp server. This may simplify configurations using .Cm ChrootDirectory to force a different filesystem root on clients. .Pp By default no subsystems are defined. Note that this option applies to protocol version 2 only. .It Cm SyslogFacility Gives the facility code that is used when logging messages from .Xr sshd 8 . The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. The default is AUTH. .It Cm TCPKeepAlive Specifies whether the system should send TCP keepalive messages to the other side. If they are sent, death of the connection or crash of one of the machines will be properly noticed. However, this means that connections will die if the route is down temporarily, and some people find it annoying. On the other hand, if TCP keepalives are not sent, sessions may hang indefinitely on the server, leaving .Dq ghost users and consuming server resources. .Pp The default is .Dq yes (to send TCP keepalive messages), and the server will notice if the network goes down or the client host crashes. This avoids infinitely hanging sessions. .Pp To disable TCP keepalive messages, the value should be set to .Dq no . .It Cm TrustedUserCAKeys Specifies a file containing public keys of certificate authorities that are trusted to sign user certificates for authentication, or .Dq none to not use one. Keys are listed one per line; empty lines and comments starting with .Ql # are allowed. If a certificate is presented for authentication and has its signing CA key listed in this file, then it may be used for authentication for any user listed in the certificate's principals list. Note that certificates that lack a list of principals will not be permitted for authentication using .Cm TrustedUserCAKeys . For more details on certificates, see the CERTIFICATES section in .Xr ssh-keygen 1 . .It Cm UseDNS Specifies whether .Xr sshd 8 should look up the remote host name, and to check that the resolved host name for the remote IP address maps back to the very same IP address. .Pp If this option is set to .Dq no (the default) then only addresses and not host names may be used in .Pa ~/.ssh/known_hosts .Cm from and -.Xr sshd_config 5 +.Nm .Cm Match .Cm Host directives. .It Cm UseLogin Specifies whether .Xr login 1 is used for interactive login sessions. The default is .Dq no . Note that .Xr login 1 is never used for remote command execution. Note also, that if this is enabled, .Cm X11Forwarding will be disabled because .Xr login 1 does not know how to handle .Xr xauth 1 cookies. If .Cm UsePrivilegeSeparation is specified, it will be disabled after authentication. .It Cm UsePAM Enables the Pluggable Authentication Module interface. If set to .Dq yes this will enable PAM authentication using .Cm ChallengeResponseAuthentication and .Cm PasswordAuthentication in addition to PAM account and session module processing for all authentication types. .Pp Because PAM challenge-response authentication usually serves an equivalent role to password authentication, you should disable either .Cm PasswordAuthentication or .Cm ChallengeResponseAuthentication. .Pp If .Cm UsePAM is enabled, you will not be able to run .Xr sshd 8 as a non-root user. The default is .Dq yes . .It Cm UsePrivilegeSeparation Specifies whether .Xr sshd 8 separates privileges by creating an unprivileged child process to deal with incoming network traffic. After successful authentication, another process will be created that has the privilege of the authenticated user. The goal of privilege separation is to prevent privilege escalation by containing any corruption within the unprivileged processes. The default is .Dq sandbox . If .Cm UsePrivilegeSeparation is set to .Dq sandbox then the pre-authentication unprivileged process is subject to additional restrictions. .It Cm VersionAddendum Optionally specifies additional text to append to the SSH protocol banner sent by the server upon connection. The default is -.Dq FreeBSD-20160119 . +.Dq FreeBSD-20160121 . The value .Dq none may be used to disable this. .It Cm X11DisplayOffset Specifies the first display number available for .Xr sshd 8 Ns 's X11 forwarding. This prevents sshd from interfering with real X11 servers. The default is 10. .It Cm X11Forwarding Specifies whether X11 forwarding is permitted. The argument must be .Dq yes or .Dq no . The default is .Dq yes . .Pp When X11 forwarding is enabled, there may be additional exposure to the server and to client displays if the .Xr sshd 8 proxy display is configured to listen on the wildcard address (see .Cm X11UseLocalhost below), though this is not the default. Additionally, the authentication spoofing and authentication data verification and substitution occur on the client side. The security risk of using X11 forwarding is that the client's X11 display server may be exposed to attack when the SSH client requests forwarding (see the warnings for .Cm ForwardX11 in .Xr ssh_config 5 ) . A system administrator may have a stance in which they want to protect clients that may expose themselves to attack by unwittingly requesting X11 forwarding, which can warrant a .Dq no setting. .Pp Note that disabling X11 forwarding does not prevent users from forwarding X11 traffic, as users can always install their own forwarders. X11 forwarding is automatically disabled if .Cm UseLogin is enabled. .It Cm X11UseLocalhost Specifies whether .Xr sshd 8 should bind the X11 forwarding server to the loopback address or to the wildcard address. By default, sshd binds the forwarding server to the loopback address and sets the hostname part of the .Ev DISPLAY environment variable to .Dq localhost . This prevents remote hosts from connecting to the proxy display. However, some older X11 clients may not function with this configuration. .Cm X11UseLocalhost may be set to .Dq no to specify that the forwarding server should be bound to the wildcard address. The argument must be .Dq yes or .Dq no . The default is .Dq yes . .It Cm XAuthLocation Specifies the full pathname of the .Xr xauth 1 program, or .Dq none to not use one. The default is .Pa /usr/local/bin/xauth . .El .Sh TIME FORMATS .Xr sshd 8 command-line arguments and configuration file options that specify time may be expressed using a sequence of the form: .Sm off .Ar time Op Ar qualifier , .Sm on where .Ar time is a positive integer value and .Ar qualifier is one of the following: .Pp .Bl -tag -width Ds -compact -offset indent .It Aq Cm none seconds .It Cm s | Cm S seconds .It Cm m | Cm M minutes .It Cm h | Cm H hours .It Cm d | Cm D days .It Cm w | Cm W weeks .El .Pp Each member of the sequence is added together to calculate the total time value. .Pp Time format examples: .Pp .Bl -tag -width Ds -compact -offset indent .It 600 600 seconds (10 minutes) .It 10m 10 minutes .It 1h30m 1 hour 30 minutes (90 minutes) .El .Sh FILES .Bl -tag -width Ds .It Pa /etc/ssh/sshd_config Contains configuration data for .Xr sshd 8 . This file should be writable by root only, but it is recommended (though not necessary) that it be world-readable. .El .Sh SEE ALSO .Xr sshd 8 .Sh AUTHORS OpenSSH is a derivative of the original and free ssh 1.2.12 release by Tatu Ylonen. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo de Raadt and Dug Song removed many bugs, re-added newer features and created OpenSSH. Markus Friedl contributed the support for SSH protocol versions 1.5 and 2.0. Niels Provos and Markus Friedl contributed support for privilege separation. Index: head/crypto/openssh/sshkey.c =================================================================== --- head/crypto/openssh/sshkey.c (revision 294495) +++ head/crypto/openssh/sshkey.c (revision 294496) @@ -1,3896 +1,3895 @@ -/* $OpenBSD: sshkey.c,v 1.20 2015/07/03 03:43:18 djm Exp $ */ +/* $OpenBSD: sshkey.c,v 1.21 2015/08/19 23:19:01 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2008 Alexander von Gernler. All rights reserved. * Copyright (c) 2010,2011 Damien Miller. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" #include /* MIN MAX */ #include #include #ifdef WITH_OPENSSL #include #include #include #endif #include "crypto_api.h" #include #include #include #include #include #ifdef HAVE_UTIL_H #include #endif /* HAVE_UTIL_H */ #include "ssh2.h" #include "ssherr.h" #include "misc.h" #include "sshbuf.h" #include "rsa.h" #include "cipher.h" #include "digest.h" #define SSHKEY_INTERNAL #include "sshkey.h" #include "match.h" /* openssh private key file format */ #define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n" #define MARK_END "-----END OPENSSH PRIVATE KEY-----\n" #define MARK_BEGIN_LEN (sizeof(MARK_BEGIN) - 1) #define MARK_END_LEN (sizeof(MARK_END) - 1) #define KDFNAME "bcrypt" #define AUTH_MAGIC "openssh-key-v1" #define SALT_LEN 16 #define DEFAULT_CIPHERNAME "aes256-cbc" #define DEFAULT_ROUNDS 16 /* Version identification string for SSH v1 identity files. */ #define LEGACY_BEGIN "SSH PRIVATE KEY FILE FORMAT 1.1\n" static int sshkey_from_blob_internal(struct sshbuf *buf, struct sshkey **keyp, int allow_cert); /* Supported key types */ struct keytype { const char *name; const char *shortname; int type; int nid; int cert; }; static const struct keytype keytypes[] = { { "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0 }, { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT", KEY_ED25519_CERT, 0, 1 }, #ifdef WITH_OPENSSL { NULL, "RSA1", KEY_RSA1, 0, 0 }, { "ssh-rsa", "RSA", KEY_RSA, 0, 0 }, { "ssh-dss", "DSA", KEY_DSA, 0, 0 }, # ifdef OPENSSL_HAS_ECC { "ecdsa-sha2-nistp256", "ECDSA", KEY_ECDSA, NID_X9_62_prime256v1, 0 }, { "ecdsa-sha2-nistp384", "ECDSA", KEY_ECDSA, NID_secp384r1, 0 }, # ifdef OPENSSL_HAS_NISTP521 { "ecdsa-sha2-nistp521", "ECDSA", KEY_ECDSA, NID_secp521r1, 0 }, # endif /* OPENSSL_HAS_NISTP521 */ # endif /* OPENSSL_HAS_ECC */ { "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", KEY_RSA_CERT, 0, 1 }, { "ssh-dss-cert-v01@openssh.com", "DSA-CERT", KEY_DSA_CERT, 0, 1 }, # ifdef OPENSSL_HAS_ECC { "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT", KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1 }, { "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT", KEY_ECDSA_CERT, NID_secp384r1, 1 }, # ifdef OPENSSL_HAS_NISTP521 { "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT", KEY_ECDSA_CERT, NID_secp521r1, 1 }, # endif /* OPENSSL_HAS_NISTP521 */ # endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ { NULL, NULL, -1, -1, 0 } }; const char * sshkey_type(const struct sshkey *k) { const struct keytype *kt; for (kt = keytypes; kt->type != -1; kt++) { if (kt->type == k->type) return kt->shortname; } return "unknown"; } static const char * sshkey_ssh_name_from_type_nid(int type, int nid) { const struct keytype *kt; for (kt = keytypes; kt->type != -1; kt++) { if (kt->type == type && (kt->nid == 0 || kt->nid == nid)) return kt->name; } return "ssh-unknown"; } int sshkey_type_is_cert(int type) { const struct keytype *kt; for (kt = keytypes; kt->type != -1; kt++) { if (kt->type == type) return kt->cert; } return 0; } const char * sshkey_ssh_name(const struct sshkey *k) { return sshkey_ssh_name_from_type_nid(k->type, k->ecdsa_nid); } const char * sshkey_ssh_name_plain(const struct sshkey *k) { return sshkey_ssh_name_from_type_nid(sshkey_type_plain(k->type), k->ecdsa_nid); } int sshkey_type_from_name(const char *name) { const struct keytype *kt; for (kt = keytypes; kt->type != -1; kt++) { /* Only allow shortname matches for plain key types */ if ((kt->name != NULL && strcmp(name, kt->name) == 0) || (!kt->cert && strcasecmp(kt->shortname, name) == 0)) return kt->type; } return KEY_UNSPEC; } int sshkey_ecdsa_nid_from_name(const char *name) { const struct keytype *kt; for (kt = keytypes; kt->type != -1; kt++) { if (kt->type != KEY_ECDSA && kt->type != KEY_ECDSA_CERT) continue; if (kt->name != NULL && strcmp(name, kt->name) == 0) return kt->nid; } return -1; } char * key_alg_list(int certs_only, int plain_only) { char *tmp, *ret = NULL; size_t nlen, rlen = 0; const struct keytype *kt; for (kt = keytypes; kt->type != -1; kt++) { if (kt->name == NULL) continue; if ((certs_only && !kt->cert) || (plain_only && kt->cert)) continue; if (ret != NULL) ret[rlen++] = '\n'; nlen = strlen(kt->name); if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { free(ret); return NULL; } ret = tmp; memcpy(ret + rlen, kt->name, nlen + 1); rlen += nlen; } return ret; } int sshkey_names_valid2(const char *names, int allow_wildcard) { char *s, *cp, *p; const struct keytype *kt; int type; if (names == NULL || strcmp(names, "") == 0) return 0; if ((s = cp = strdup(names)) == NULL) return 0; for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { type = sshkey_type_from_name(p); if (type == KEY_RSA1) { free(s); return 0; } if (type == KEY_UNSPEC) { if (allow_wildcard) { /* * Try matching key types against the string. * If any has a positive or negative match then * the component is accepted. */ for (kt = keytypes; kt->type != -1; kt++) { if (kt->type == KEY_RSA1) continue; if (match_pattern_list(kt->name, p, 0) != 0) break; } if (kt->type != -1) continue; } free(s); return 0; } } free(s); return 1; } u_int sshkey_size(const struct sshkey *k) { switch (k->type) { #ifdef WITH_OPENSSL case KEY_RSA1: case KEY_RSA: case KEY_RSA_CERT: return BN_num_bits(k->rsa->n); case KEY_DSA: case KEY_DSA_CERT: return BN_num_bits(k->dsa->p); case KEY_ECDSA: case KEY_ECDSA_CERT: return sshkey_curve_nid_to_bits(k->ecdsa_nid); #endif /* WITH_OPENSSL */ case KEY_ED25519: case KEY_ED25519_CERT: return 256; /* XXX */ } return 0; } static int sshkey_type_is_valid_ca(int type) { switch (type) { case KEY_RSA: case KEY_DSA: case KEY_ECDSA: case KEY_ED25519: return 1; default: return 0; } } int sshkey_is_cert(const struct sshkey *k) { if (k == NULL) return 0; return sshkey_type_is_cert(k->type); } /* Return the cert-less equivalent to a certified key type */ int sshkey_type_plain(int type) { switch (type) { case KEY_RSA_CERT: return KEY_RSA; case KEY_DSA_CERT: return KEY_DSA; case KEY_ECDSA_CERT: return KEY_ECDSA; case KEY_ED25519_CERT: return KEY_ED25519; default: return type; } } #ifdef WITH_OPENSSL /* XXX: these are really begging for a table-driven approach */ int sshkey_curve_name_to_nid(const char *name) { if (strcmp(name, "nistp256") == 0) return NID_X9_62_prime256v1; else if (strcmp(name, "nistp384") == 0) return NID_secp384r1; # ifdef OPENSSL_HAS_NISTP521 else if (strcmp(name, "nistp521") == 0) return NID_secp521r1; # endif /* OPENSSL_HAS_NISTP521 */ else return -1; } u_int sshkey_curve_nid_to_bits(int nid) { switch (nid) { case NID_X9_62_prime256v1: return 256; case NID_secp384r1: return 384; # ifdef OPENSSL_HAS_NISTP521 case NID_secp521r1: return 521; # endif /* OPENSSL_HAS_NISTP521 */ default: return 0; } } int sshkey_ecdsa_bits_to_nid(int bits) { switch (bits) { case 256: return NID_X9_62_prime256v1; case 384: return NID_secp384r1; # ifdef OPENSSL_HAS_NISTP521 case 521: return NID_secp521r1; # endif /* OPENSSL_HAS_NISTP521 */ default: return -1; } } const char * sshkey_curve_nid_to_name(int nid) { switch (nid) { case NID_X9_62_prime256v1: return "nistp256"; case NID_secp384r1: return "nistp384"; # ifdef OPENSSL_HAS_NISTP521 case NID_secp521r1: return "nistp521"; # endif /* OPENSSL_HAS_NISTP521 */ default: return NULL; } } int sshkey_ec_nid_to_hash_alg(int nid) { int kbits = sshkey_curve_nid_to_bits(nid); if (kbits <= 0) return -1; /* RFC5656 section 6.2.1 */ if (kbits <= 256) return SSH_DIGEST_SHA256; else if (kbits <= 384) return SSH_DIGEST_SHA384; else return SSH_DIGEST_SHA512; } #endif /* WITH_OPENSSL */ static void cert_free(struct sshkey_cert *cert) { u_int i; if (cert == NULL) return; if (cert->certblob != NULL) sshbuf_free(cert->certblob); if (cert->critical != NULL) sshbuf_free(cert->critical); if (cert->extensions != NULL) sshbuf_free(cert->extensions); if (cert->key_id != NULL) free(cert->key_id); for (i = 0; i < cert->nprincipals; i++) free(cert->principals[i]); if (cert->principals != NULL) free(cert->principals); if (cert->signature_key != NULL) sshkey_free(cert->signature_key); explicit_bzero(cert, sizeof(*cert)); free(cert); } static struct sshkey_cert * cert_new(void) { struct sshkey_cert *cert; if ((cert = calloc(1, sizeof(*cert))) == NULL) return NULL; if ((cert->certblob = sshbuf_new()) == NULL || (cert->critical = sshbuf_new()) == NULL || (cert->extensions = sshbuf_new()) == NULL) { cert_free(cert); return NULL; } cert->key_id = NULL; cert->principals = NULL; cert->signature_key = NULL; return cert; } struct sshkey * sshkey_new(int type) { struct sshkey *k; #ifdef WITH_OPENSSL RSA *rsa; DSA *dsa; #endif /* WITH_OPENSSL */ if ((k = calloc(1, sizeof(*k))) == NULL) return NULL; k->type = type; k->ecdsa = NULL; k->ecdsa_nid = -1; k->dsa = NULL; k->rsa = NULL; k->cert = NULL; k->ed25519_sk = NULL; k->ed25519_pk = NULL; switch (k->type) { #ifdef WITH_OPENSSL case KEY_RSA1: case KEY_RSA: case KEY_RSA_CERT: if ((rsa = RSA_new()) == NULL || (rsa->n = BN_new()) == NULL || (rsa->e = BN_new()) == NULL) { if (rsa != NULL) RSA_free(rsa); free(k); return NULL; } k->rsa = rsa; break; case KEY_DSA: case KEY_DSA_CERT: if ((dsa = DSA_new()) == NULL || (dsa->p = BN_new()) == NULL || (dsa->q = BN_new()) == NULL || (dsa->g = BN_new()) == NULL || (dsa->pub_key = BN_new()) == NULL) { if (dsa != NULL) DSA_free(dsa); free(k); return NULL; } k->dsa = dsa; break; case KEY_ECDSA: case KEY_ECDSA_CERT: /* Cannot do anything until we know the group */ break; #endif /* WITH_OPENSSL */ case KEY_ED25519: case KEY_ED25519_CERT: /* no need to prealloc */ break; case KEY_UNSPEC: break; default: free(k); return NULL; break; } if (sshkey_is_cert(k)) { if ((k->cert = cert_new()) == NULL) { sshkey_free(k); return NULL; } } return k; } int sshkey_add_private(struct sshkey *k) { switch (k->type) { #ifdef WITH_OPENSSL case KEY_RSA1: case KEY_RSA: case KEY_RSA_CERT: #define bn_maybe_alloc_failed(p) (p == NULL && (p = BN_new()) == NULL) if (bn_maybe_alloc_failed(k->rsa->d) || bn_maybe_alloc_failed(k->rsa->iqmp) || bn_maybe_alloc_failed(k->rsa->q) || bn_maybe_alloc_failed(k->rsa->p) || bn_maybe_alloc_failed(k->rsa->dmq1) || bn_maybe_alloc_failed(k->rsa->dmp1)) return SSH_ERR_ALLOC_FAIL; break; case KEY_DSA: case KEY_DSA_CERT: if (bn_maybe_alloc_failed(k->dsa->priv_key)) return SSH_ERR_ALLOC_FAIL; break; #undef bn_maybe_alloc_failed case KEY_ECDSA: case KEY_ECDSA_CERT: /* Cannot do anything until we know the group */ break; #endif /* WITH_OPENSSL */ case KEY_ED25519: case KEY_ED25519_CERT: /* no need to prealloc */ break; case KEY_UNSPEC: break; default: return SSH_ERR_INVALID_ARGUMENT; } return 0; } struct sshkey * sshkey_new_private(int type) { struct sshkey *k = sshkey_new(type); if (k == NULL) return NULL; if (sshkey_add_private(k) != 0) { sshkey_free(k); return NULL; } return k; } void sshkey_free(struct sshkey *k) { if (k == NULL) return; switch (k->type) { #ifdef WITH_OPENSSL case KEY_RSA1: case KEY_RSA: case KEY_RSA_CERT: if (k->rsa != NULL) RSA_free(k->rsa); k->rsa = NULL; break; case KEY_DSA: case KEY_DSA_CERT: if (k->dsa != NULL) DSA_free(k->dsa); k->dsa = NULL; break; # ifdef OPENSSL_HAS_ECC case KEY_ECDSA: case KEY_ECDSA_CERT: if (k->ecdsa != NULL) EC_KEY_free(k->ecdsa); k->ecdsa = NULL; break; # endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ case KEY_ED25519: case KEY_ED25519_CERT: if (k->ed25519_pk) { explicit_bzero(k->ed25519_pk, ED25519_PK_SZ); free(k->ed25519_pk); k->ed25519_pk = NULL; } if (k->ed25519_sk) { explicit_bzero(k->ed25519_sk, ED25519_SK_SZ); free(k->ed25519_sk); k->ed25519_sk = NULL; } break; case KEY_UNSPEC: break; default: break; } if (sshkey_is_cert(k)) cert_free(k->cert); explicit_bzero(k, sizeof(*k)); free(k); } static int cert_compare(struct sshkey_cert *a, struct sshkey_cert *b) { if (a == NULL && b == NULL) return 1; if (a == NULL || b == NULL) return 0; if (sshbuf_len(a->certblob) != sshbuf_len(b->certblob)) return 0; if (timingsafe_bcmp(sshbuf_ptr(a->certblob), sshbuf_ptr(b->certblob), sshbuf_len(a->certblob)) != 0) return 0; return 1; } /* * Compare public portions of key only, allowing comparisons between * certificates and plain keys too. */ int sshkey_equal_public(const struct sshkey *a, const struct sshkey *b) { #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) BN_CTX *bnctx; #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ if (a == NULL || b == NULL || sshkey_type_plain(a->type) != sshkey_type_plain(b->type)) return 0; switch (a->type) { #ifdef WITH_OPENSSL case KEY_RSA1: case KEY_RSA_CERT: case KEY_RSA: return a->rsa != NULL && b->rsa != NULL && BN_cmp(a->rsa->e, b->rsa->e) == 0 && BN_cmp(a->rsa->n, b->rsa->n) == 0; case KEY_DSA_CERT: case KEY_DSA: return a->dsa != NULL && b->dsa != NULL && BN_cmp(a->dsa->p, b->dsa->p) == 0 && BN_cmp(a->dsa->q, b->dsa->q) == 0 && BN_cmp(a->dsa->g, b->dsa->g) == 0 && BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0; # ifdef OPENSSL_HAS_ECC case KEY_ECDSA_CERT: case KEY_ECDSA: if (a->ecdsa == NULL || b->ecdsa == NULL || EC_KEY_get0_public_key(a->ecdsa) == NULL || EC_KEY_get0_public_key(b->ecdsa) == NULL) return 0; if ((bnctx = BN_CTX_new()) == NULL) return 0; if (EC_GROUP_cmp(EC_KEY_get0_group(a->ecdsa), EC_KEY_get0_group(b->ecdsa), bnctx) != 0 || EC_POINT_cmp(EC_KEY_get0_group(a->ecdsa), EC_KEY_get0_public_key(a->ecdsa), EC_KEY_get0_public_key(b->ecdsa), bnctx) != 0) { BN_CTX_free(bnctx); return 0; } BN_CTX_free(bnctx); return 1; # endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ case KEY_ED25519: case KEY_ED25519_CERT: return a->ed25519_pk != NULL && b->ed25519_pk != NULL && memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0; default: return 0; } /* NOTREACHED */ } int sshkey_equal(const struct sshkey *a, const struct sshkey *b) { if (a == NULL || b == NULL || a->type != b->type) return 0; if (sshkey_is_cert(a)) { if (!cert_compare(a->cert, b->cert)) return 0; } return sshkey_equal_public(a, b); } static int to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain) { int type, ret = SSH_ERR_INTERNAL_ERROR; const char *typename; if (key == NULL) return SSH_ERR_INVALID_ARGUMENT; if (sshkey_is_cert(key)) { if (key->cert == NULL) return SSH_ERR_EXPECTED_CERT; if (sshbuf_len(key->cert->certblob) == 0) return SSH_ERR_KEY_LACKS_CERTBLOB; } type = force_plain ? sshkey_type_plain(key->type) : key->type; typename = sshkey_ssh_name_from_type_nid(type, key->ecdsa_nid); switch (type) { #ifdef WITH_OPENSSL case KEY_DSA_CERT: case KEY_ECDSA_CERT: case KEY_RSA_CERT: #endif /* WITH_OPENSSL */ case KEY_ED25519_CERT: /* Use the existing blob */ /* XXX modified flag? */ if ((ret = sshbuf_putb(b, key->cert->certblob)) != 0) return ret; break; #ifdef WITH_OPENSSL case KEY_DSA: if (key->dsa == NULL) return SSH_ERR_INVALID_ARGUMENT; if ((ret = sshbuf_put_cstring(b, typename)) != 0 || (ret = sshbuf_put_bignum2(b, key->dsa->p)) != 0 || (ret = sshbuf_put_bignum2(b, key->dsa->q)) != 0 || (ret = sshbuf_put_bignum2(b, key->dsa->g)) != 0 || (ret = sshbuf_put_bignum2(b, key->dsa->pub_key)) != 0) return ret; break; # ifdef OPENSSL_HAS_ECC case KEY_ECDSA: if (key->ecdsa == NULL) return SSH_ERR_INVALID_ARGUMENT; if ((ret = sshbuf_put_cstring(b, typename)) != 0 || (ret = sshbuf_put_cstring(b, sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 || (ret = sshbuf_put_eckey(b, key->ecdsa)) != 0) return ret; break; # endif case KEY_RSA: if (key->rsa == NULL) return SSH_ERR_INVALID_ARGUMENT; if ((ret = sshbuf_put_cstring(b, typename)) != 0 || (ret = sshbuf_put_bignum2(b, key->rsa->e)) != 0 || (ret = sshbuf_put_bignum2(b, key->rsa->n)) != 0) return ret; break; #endif /* WITH_OPENSSL */ case KEY_ED25519: if (key->ed25519_pk == NULL) return SSH_ERR_INVALID_ARGUMENT; if ((ret = sshbuf_put_cstring(b, typename)) != 0 || (ret = sshbuf_put_string(b, key->ed25519_pk, ED25519_PK_SZ)) != 0) return ret; break; default: return SSH_ERR_KEY_TYPE_UNKNOWN; } return 0; } int sshkey_putb(const struct sshkey *key, struct sshbuf *b) { return to_blob_buf(key, b, 0); } int sshkey_puts(const struct sshkey *key, struct sshbuf *b) { struct sshbuf *tmp; int r; if ((tmp = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; r = to_blob_buf(key, tmp, 0); if (r == 0) r = sshbuf_put_stringb(b, tmp); sshbuf_free(tmp); return r; } int sshkey_putb_plain(const struct sshkey *key, struct sshbuf *b) { return to_blob_buf(key, b, 1); } static int to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain) { int ret = SSH_ERR_INTERNAL_ERROR; size_t len; struct sshbuf *b = NULL; if (lenp != NULL) *lenp = 0; if (blobp != NULL) *blobp = NULL; if ((b = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((ret = to_blob_buf(key, b, force_plain)) != 0) goto out; len = sshbuf_len(b); if (lenp != NULL) *lenp = len; if (blobp != NULL) { if ((*blobp = malloc(len)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } memcpy(*blobp, sshbuf_ptr(b), len); } ret = 0; out: sshbuf_free(b); return ret; } int sshkey_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp) { return to_blob(key, blobp, lenp, 0); } int sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp) { return to_blob(key, blobp, lenp, 1); } int sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg, u_char **retp, size_t *lenp) { u_char *blob = NULL, *ret = NULL; size_t blob_len = 0; int r = SSH_ERR_INTERNAL_ERROR; if (retp != NULL) *retp = NULL; if (lenp != NULL) *lenp = 0; if (ssh_digest_bytes(dgst_alg) == 0) { r = SSH_ERR_INVALID_ARGUMENT; goto out; } if (k->type == KEY_RSA1) { #ifdef WITH_OPENSSL int nlen = BN_num_bytes(k->rsa->n); int elen = BN_num_bytes(k->rsa->e); blob_len = nlen + elen; if (nlen >= INT_MAX - elen || (blob = malloc(blob_len)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } BN_bn2bin(k->rsa->n, blob); BN_bn2bin(k->rsa->e, blob + nlen); #endif /* WITH_OPENSSL */ } else if ((r = to_blob(k, &blob, &blob_len, 1)) != 0) goto out; if ((ret = calloc(1, SSH_DIGEST_MAX_LENGTH)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = ssh_digest_memory(dgst_alg, blob, blob_len, ret, SSH_DIGEST_MAX_LENGTH)) != 0) goto out; /* success */ if (retp != NULL) { *retp = ret; ret = NULL; } if (lenp != NULL) *lenp = ssh_digest_bytes(dgst_alg); r = 0; out: free(ret); if (blob != NULL) { explicit_bzero(blob, blob_len); free(blob); } return r; } static char * fingerprint_b64(const char *alg, u_char *dgst_raw, size_t dgst_raw_len) { char *ret; size_t plen = strlen(alg) + 1; size_t rlen = ((dgst_raw_len + 2) / 3) * 4 + plen + 1; int r; if (dgst_raw_len > 65536 || (ret = calloc(1, rlen)) == NULL) return NULL; strlcpy(ret, alg, rlen); strlcat(ret, ":", rlen); if (dgst_raw_len == 0) return ret; if ((r = b64_ntop(dgst_raw, dgst_raw_len, ret + plen, rlen - plen)) == -1) { explicit_bzero(ret, rlen); free(ret); return NULL; } /* Trim padding characters from end */ ret[strcspn(ret, "=")] = '\0'; return ret; } static char * fingerprint_hex(const char *alg, u_char *dgst_raw, size_t dgst_raw_len) { char *retval, hex[5]; size_t i, rlen = dgst_raw_len * 3 + strlen(alg) + 2; if (dgst_raw_len > 65536 || (retval = calloc(1, rlen)) == NULL) return NULL; strlcpy(retval, alg, rlen); strlcat(retval, ":", rlen); for (i = 0; i < dgst_raw_len; i++) { snprintf(hex, sizeof(hex), "%s%02x", i > 0 ? ":" : "", dgst_raw[i]); strlcat(retval, hex, rlen); } return retval; } static char * fingerprint_bubblebabble(u_char *dgst_raw, size_t dgst_raw_len) { char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' }; char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' }; u_int i, j = 0, rounds, seed = 1; char *retval; rounds = (dgst_raw_len / 2) + 1; if ((retval = calloc(rounds, 6)) == NULL) return NULL; retval[j++] = 'x'; for (i = 0; i < rounds; i++) { u_int idx0, idx1, idx2, idx3, idx4; if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) { idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) + seed) % 6; idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15; idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) + (seed / 6)) % 6; retval[j++] = vowels[idx0]; retval[j++] = consonants[idx1]; retval[j++] = vowels[idx2]; if ((i + 1) < rounds) { idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15; idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15; retval[j++] = consonants[idx3]; retval[j++] = '-'; retval[j++] = consonants[idx4]; seed = ((seed * 5) + ((((u_int)(dgst_raw[2 * i])) * 7) + ((u_int)(dgst_raw[(2 * i) + 1])))) % 36; } } else { idx0 = seed % 6; idx1 = 16; idx2 = seed / 6; retval[j++] = vowels[idx0]; retval[j++] = consonants[idx1]; retval[j++] = vowels[idx2]; } } retval[j++] = 'x'; retval[j++] = '\0'; return retval; } /* * Draw an ASCII-Art representing the fingerprint so human brain can * profit from its built-in pattern recognition ability. * This technique is called "random art" and can be found in some * scientific publications like this original paper: * * "Hash Visualization: a New Technique to improve Real-World Security", * Perrig A. and Song D., 1999, International Workshop on Cryptographic * Techniques and E-Commerce (CrypTEC '99) * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf * * The subject came up in a talk by Dan Kaminsky, too. * * If you see the picture is different, the key is different. * If the picture looks the same, you still know nothing. * * The algorithm used here is a worm crawling over a discrete plane, * leaving a trace (augmenting the field) everywhere it goes. * Movement is taken from dgst_raw 2bit-wise. Bumping into walls * makes the respective movement vector be ignored for this turn. * Graphs are not unambiguous, because circles in graphs can be * walked in either direction. */ /* * Field sizes for the random art. Have to be odd, so the starting point * can be in the exact middle of the picture, and FLDBASE should be >=8 . * Else pictures would be too dense, and drawing the frame would * fail, too, because the key type would not fit in anymore. */ #define FLDBASE 8 #define FLDSIZE_Y (FLDBASE + 1) #define FLDSIZE_X (FLDBASE * 2 + 1) static char * fingerprint_randomart(const char *alg, u_char *dgst_raw, size_t dgst_raw_len, const struct sshkey *k) { /* * Chars to be used after each other every time the worm * intersects with itself. Matter of taste. */ char *augmentation_string = " .o+=*BOX@%&#/^SE"; char *retval, *p, title[FLDSIZE_X], hash[FLDSIZE_X]; u_char field[FLDSIZE_X][FLDSIZE_Y]; size_t i, tlen, hlen; u_int b; int x, y, r; size_t len = strlen(augmentation_string) - 1; if ((retval = calloc((FLDSIZE_X + 3), (FLDSIZE_Y + 2))) == NULL) return NULL; /* initialize field */ memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char)); x = FLDSIZE_X / 2; y = FLDSIZE_Y / 2; /* process raw key */ for (i = 0; i < dgst_raw_len; i++) { int input; /* each byte conveys four 2-bit move commands */ input = dgst_raw[i]; for (b = 0; b < 4; b++) { /* evaluate 2 bit, rest is shifted later */ x += (input & 0x1) ? 1 : -1; y += (input & 0x2) ? 1 : -1; /* assure we are still in bounds */ x = MAX(x, 0); y = MAX(y, 0); x = MIN(x, FLDSIZE_X - 1); y = MIN(y, FLDSIZE_Y - 1); /* augment the field */ if (field[x][y] < len - 2) field[x][y]++; input = input >> 2; } } /* mark starting point and end point*/ field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1; field[x][y] = len; /* assemble title */ r = snprintf(title, sizeof(title), "[%s %u]", sshkey_type(k), sshkey_size(k)); /* If [type size] won't fit, then try [type]; fits "[ED25519-CERT]" */ if (r < 0 || r > (int)sizeof(title)) r = snprintf(title, sizeof(title), "[%s]", sshkey_type(k)); tlen = (r <= 0) ? 0 : strlen(title); /* assemble hash ID. */ r = snprintf(hash, sizeof(hash), "[%s]", alg); hlen = (r <= 0) ? 0 : strlen(hash); /* output upper border */ p = retval; *p++ = '+'; for (i = 0; i < (FLDSIZE_X - tlen) / 2; i++) *p++ = '-'; memcpy(p, title, tlen); p += tlen; for (i += tlen; i < FLDSIZE_X; i++) *p++ = '-'; *p++ = '+'; *p++ = '\n'; /* output content */ for (y = 0; y < FLDSIZE_Y; y++) { *p++ = '|'; for (x = 0; x < FLDSIZE_X; x++) *p++ = augmentation_string[MIN(field[x][y], len)]; *p++ = '|'; *p++ = '\n'; } /* output lower border */ *p++ = '+'; for (i = 0; i < (FLDSIZE_X - hlen) / 2; i++) *p++ = '-'; memcpy(p, hash, hlen); p += hlen; for (i += hlen; i < FLDSIZE_X; i++) *p++ = '-'; *p++ = '+'; return retval; } char * sshkey_fingerprint(const struct sshkey *k, int dgst_alg, enum sshkey_fp_rep dgst_rep) { char *retval = NULL; u_char *dgst_raw; size_t dgst_raw_len; if (sshkey_fingerprint_raw(k, dgst_alg, &dgst_raw, &dgst_raw_len) != 0) return NULL; switch (dgst_rep) { case SSH_FP_DEFAULT: if (dgst_alg == SSH_DIGEST_MD5) { retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg), dgst_raw, dgst_raw_len); } else { retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg), dgst_raw, dgst_raw_len); } break; case SSH_FP_HEX: retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg), dgst_raw, dgst_raw_len); break; case SSH_FP_BASE64: retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg), dgst_raw, dgst_raw_len); break; case SSH_FP_BUBBLEBABBLE: retval = fingerprint_bubblebabble(dgst_raw, dgst_raw_len); break; case SSH_FP_RANDOMART: retval = fingerprint_randomart(ssh_digest_alg_name(dgst_alg), dgst_raw, dgst_raw_len, k); break; default: explicit_bzero(dgst_raw, dgst_raw_len); free(dgst_raw); return NULL; } explicit_bzero(dgst_raw, dgst_raw_len); free(dgst_raw); return retval; } #ifdef WITH_SSH1 /* * Reads a multiple-precision integer in decimal from the buffer, and advances * the pointer. The integer must already be initialized. This function is * permitted to modify the buffer. This leaves *cpp to point just beyond the * last processed character. */ static int read_decimal_bignum(char **cpp, BIGNUM *v) { char *cp; size_t e; int skip = 1; /* skip white space */ cp = *cpp; while (*cp == ' ' || *cp == '\t') cp++; e = strspn(cp, "0123456789"); if (e == 0) return SSH_ERR_INVALID_FORMAT; if (e > SSHBUF_MAX_BIGNUM * 3) return SSH_ERR_BIGNUM_TOO_LARGE; if (cp[e] == '\0') skip = 0; else if (index(" \t\r\n", cp[e]) == NULL) return SSH_ERR_INVALID_FORMAT; cp[e] = '\0'; if (BN_dec2bn(&v, cp) <= 0) return SSH_ERR_INVALID_FORMAT; *cpp = cp + e + skip; return 0; } #endif /* WITH_SSH1 */ /* returns 0 ok, and < 0 error */ int sshkey_read(struct sshkey *ret, char **cpp) { struct sshkey *k; int retval = SSH_ERR_INVALID_FORMAT; char *cp, *space; int r, type, curve_nid = -1; struct sshbuf *blob; #ifdef WITH_SSH1 char *ep; u_long bits; #endif /* WITH_SSH1 */ cp = *cpp; switch (ret->type) { case KEY_RSA1: #ifdef WITH_SSH1 /* Get number of bits. */ bits = strtoul(cp, &ep, 10); if (*cp == '\0' || index(" \t\r\n", *ep) == NULL || bits == 0 || bits > SSHBUF_MAX_BIGNUM * 8) return SSH_ERR_INVALID_FORMAT; /* Bad bit count... */ /* Get public exponent, public modulus. */ if ((r = read_decimal_bignum(&ep, ret->rsa->e)) < 0) return r; if ((r = read_decimal_bignum(&ep, ret->rsa->n)) < 0) return r; *cpp = ep; /* validate the claimed number of bits */ if (BN_num_bits(ret->rsa->n) != (int)bits) return SSH_ERR_KEY_BITS_MISMATCH; retval = 0; #endif /* WITH_SSH1 */ break; case KEY_UNSPEC: case KEY_RSA: case KEY_DSA: case KEY_ECDSA: case KEY_ED25519: case KEY_DSA_CERT: case KEY_ECDSA_CERT: case KEY_RSA_CERT: case KEY_ED25519_CERT: space = strchr(cp, ' '); if (space == NULL) return SSH_ERR_INVALID_FORMAT; *space = '\0'; type = sshkey_type_from_name(cp); if (sshkey_type_plain(type) == KEY_ECDSA && (curve_nid = sshkey_ecdsa_nid_from_name(cp)) == -1) return SSH_ERR_EC_CURVE_INVALID; *space = ' '; if (type == KEY_UNSPEC) return SSH_ERR_INVALID_FORMAT; cp = space+1; if (*cp == '\0') return SSH_ERR_INVALID_FORMAT; if (ret->type != KEY_UNSPEC && ret->type != type) return SSH_ERR_KEY_TYPE_MISMATCH; if ((blob = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; /* trim comment */ space = strchr(cp, ' '); if (space) { /* advance 'space': skip whitespace */ *space++ = '\0'; while (*space == ' ' || *space == '\t') space++; *cpp = space; } else *cpp = cp + strlen(cp); if ((r = sshbuf_b64tod(blob, cp)) != 0) { sshbuf_free(blob); return r; } if ((r = sshkey_from_blob(sshbuf_ptr(blob), sshbuf_len(blob), &k)) != 0) { sshbuf_free(blob); return r; } sshbuf_free(blob); if (k->type != type) { sshkey_free(k); return SSH_ERR_KEY_TYPE_MISMATCH; } if (sshkey_type_plain(type) == KEY_ECDSA && curve_nid != k->ecdsa_nid) { sshkey_free(k); return SSH_ERR_EC_CURVE_MISMATCH; } ret->type = type; if (sshkey_is_cert(ret)) { if (!sshkey_is_cert(k)) { sshkey_free(k); return SSH_ERR_EXPECTED_CERT; } if (ret->cert != NULL) cert_free(ret->cert); ret->cert = k->cert; k->cert = NULL; } #ifdef WITH_OPENSSL if (sshkey_type_plain(ret->type) == KEY_RSA) { if (ret->rsa != NULL) RSA_free(ret->rsa); ret->rsa = k->rsa; k->rsa = NULL; #ifdef DEBUG_PK RSA_print_fp(stderr, ret->rsa, 8); #endif } if (sshkey_type_plain(ret->type) == KEY_DSA) { if (ret->dsa != NULL) DSA_free(ret->dsa); ret->dsa = k->dsa; k->dsa = NULL; #ifdef DEBUG_PK DSA_print_fp(stderr, ret->dsa, 8); #endif } # ifdef OPENSSL_HAS_ECC if (sshkey_type_plain(ret->type) == KEY_ECDSA) { if (ret->ecdsa != NULL) EC_KEY_free(ret->ecdsa); ret->ecdsa = k->ecdsa; ret->ecdsa_nid = k->ecdsa_nid; k->ecdsa = NULL; k->ecdsa_nid = -1; #ifdef DEBUG_PK sshkey_dump_ec_key(ret->ecdsa); #endif } # endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ if (sshkey_type_plain(ret->type) == KEY_ED25519) { free(ret->ed25519_pk); ret->ed25519_pk = k->ed25519_pk; k->ed25519_pk = NULL; #ifdef DEBUG_PK /* XXX */ #endif } retval = 0; /*XXXX*/ sshkey_free(k); if (retval != 0) break; break; default: return SSH_ERR_INVALID_ARGUMENT; } return retval; } int sshkey_to_base64(const struct sshkey *key, char **b64p) { int r = SSH_ERR_INTERNAL_ERROR; struct sshbuf *b = NULL; char *uu = NULL; if (b64p != NULL) *b64p = NULL; if ((b = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshkey_putb(key, b)) != 0) goto out; if ((uu = sshbuf_dtob64(b)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } /* Success */ if (b64p != NULL) { *b64p = uu; uu = NULL; } r = 0; out: sshbuf_free(b); free(uu); return r; } static int sshkey_format_rsa1(const struct sshkey *key, struct sshbuf *b) { int r = SSH_ERR_INTERNAL_ERROR; #ifdef WITH_SSH1 u_int bits = 0; char *dec_e = NULL, *dec_n = NULL; if (key->rsa == NULL || key->rsa->e == NULL || key->rsa->n == NULL) { r = SSH_ERR_INVALID_ARGUMENT; goto out; } if ((dec_e = BN_bn2dec(key->rsa->e)) == NULL || (dec_n = BN_bn2dec(key->rsa->n)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } /* size of modulus 'n' */ if ((bits = BN_num_bits(key->rsa->n)) <= 0) { r = SSH_ERR_INVALID_ARGUMENT; goto out; } if ((r = sshbuf_putf(b, "%u %s %s", bits, dec_e, dec_n)) != 0) goto out; /* Success */ r = 0; out: if (dec_e != NULL) OPENSSL_free(dec_e); if (dec_n != NULL) OPENSSL_free(dec_n); #endif /* WITH_SSH1 */ return r; } static int sshkey_format_text(const struct sshkey *key, struct sshbuf *b) { int r = SSH_ERR_INTERNAL_ERROR; char *uu = NULL; if (key->type == KEY_RSA1) { if ((r = sshkey_format_rsa1(key, b)) != 0) goto out; } else { /* Unsupported key types handled in sshkey_to_base64() */ if ((r = sshkey_to_base64(key, &uu)) != 0) goto out; if ((r = sshbuf_putf(b, "%s %s", sshkey_ssh_name(key), uu)) != 0) goto out; } r = 0; out: free(uu); return r; } int sshkey_write(const struct sshkey *key, FILE *f) { struct sshbuf *b = NULL; int r = SSH_ERR_INTERNAL_ERROR; if ((b = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshkey_format_text(key, b)) != 0) goto out; if (fwrite(sshbuf_ptr(b), sshbuf_len(b), 1, f) != 1) { if (feof(f)) errno = EPIPE; r = SSH_ERR_SYSTEM_ERROR; goto out; } /* Success */ r = 0; out: sshbuf_free(b); return r; } const char * sshkey_cert_type(const struct sshkey *k) { switch (k->cert->type) { case SSH2_CERT_TYPE_USER: return "user"; case SSH2_CERT_TYPE_HOST: return "host"; default: return "unknown"; } } #ifdef WITH_OPENSSL static int rsa_generate_private_key(u_int bits, RSA **rsap) { RSA *private = NULL; BIGNUM *f4 = NULL; int ret = SSH_ERR_INTERNAL_ERROR; if (rsap == NULL || bits < SSH_RSA_MINIMUM_MODULUS_SIZE || bits > SSHBUF_MAX_BIGNUM * 8) return SSH_ERR_INVALID_ARGUMENT; *rsap = NULL; if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } if (!BN_set_word(f4, RSA_F4) || !RSA_generate_key_ex(private, bits, f4, NULL)) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } *rsap = private; private = NULL; ret = 0; out: if (private != NULL) RSA_free(private); if (f4 != NULL) BN_free(f4); return ret; } static int dsa_generate_private_key(u_int bits, DSA **dsap) { DSA *private; int ret = SSH_ERR_INTERNAL_ERROR; if (dsap == NULL || bits != 1024) return SSH_ERR_INVALID_ARGUMENT; if ((private = DSA_new()) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } *dsap = NULL; if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL, NULL, NULL) || !DSA_generate_key(private)) { - DSA_free(private); ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } *dsap = private; private = NULL; ret = 0; out: if (private != NULL) DSA_free(private); return ret; } # ifdef OPENSSL_HAS_ECC int sshkey_ecdsa_key_to_nid(EC_KEY *k) { EC_GROUP *eg; int nids[] = { NID_X9_62_prime256v1, NID_secp384r1, # ifdef OPENSSL_HAS_NISTP521 NID_secp521r1, # endif /* OPENSSL_HAS_NISTP521 */ -1 }; int nid; u_int i; BN_CTX *bnctx; const EC_GROUP *g = EC_KEY_get0_group(k); /* * The group may be stored in a ASN.1 encoded private key in one of two * ways: as a "named group", which is reconstituted by ASN.1 object ID * or explicit group parameters encoded into the key blob. Only the * "named group" case sets the group NID for us, but we can figure * it out for the other case by comparing against all the groups that * are supported. */ if ((nid = EC_GROUP_get_curve_name(g)) > 0) return nid; if ((bnctx = BN_CTX_new()) == NULL) return -1; for (i = 0; nids[i] != -1; i++) { if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL) { BN_CTX_free(bnctx); return -1; } if (EC_GROUP_cmp(g, eg, bnctx) == 0) break; EC_GROUP_free(eg); } BN_CTX_free(bnctx); if (nids[i] != -1) { /* Use the group with the NID attached */ EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE); if (EC_KEY_set_group(k, eg) != 1) { EC_GROUP_free(eg); return -1; } } return nids[i]; } static int ecdsa_generate_private_key(u_int bits, int *nid, EC_KEY **ecdsap) { EC_KEY *private; int ret = SSH_ERR_INTERNAL_ERROR; if (nid == NULL || ecdsap == NULL || (*nid = sshkey_ecdsa_bits_to_nid(bits)) == -1) return SSH_ERR_INVALID_ARGUMENT; *ecdsap = NULL; if ((private = EC_KEY_new_by_curve_name(*nid)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } if (EC_KEY_generate_key(private) != 1) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE); *ecdsap = private; private = NULL; ret = 0; out: if (private != NULL) EC_KEY_free(private); return ret; } # endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ int sshkey_generate(int type, u_int bits, struct sshkey **keyp) { struct sshkey *k; int ret = SSH_ERR_INTERNAL_ERROR; if (keyp == NULL) return SSH_ERR_INVALID_ARGUMENT; *keyp = NULL; if ((k = sshkey_new(KEY_UNSPEC)) == NULL) return SSH_ERR_ALLOC_FAIL; switch (type) { case KEY_ED25519: if ((k->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL || (k->ed25519_sk = malloc(ED25519_SK_SZ)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; break; } crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk); ret = 0; break; #ifdef WITH_OPENSSL case KEY_DSA: ret = dsa_generate_private_key(bits, &k->dsa); break; # ifdef OPENSSL_HAS_ECC case KEY_ECDSA: ret = ecdsa_generate_private_key(bits, &k->ecdsa_nid, &k->ecdsa); break; # endif /* OPENSSL_HAS_ECC */ case KEY_RSA: case KEY_RSA1: ret = rsa_generate_private_key(bits, &k->rsa); break; #endif /* WITH_OPENSSL */ default: ret = SSH_ERR_INVALID_ARGUMENT; } if (ret == 0) { k->type = type; *keyp = k; } else sshkey_free(k); return ret; } int sshkey_cert_copy(const struct sshkey *from_key, struct sshkey *to_key) { u_int i; const struct sshkey_cert *from; struct sshkey_cert *to; int ret = SSH_ERR_INTERNAL_ERROR; if (to_key->cert != NULL) { cert_free(to_key->cert); to_key->cert = NULL; } if ((from = from_key->cert) == NULL) return SSH_ERR_INVALID_ARGUMENT; if ((to = to_key->cert = cert_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((ret = sshbuf_putb(to->certblob, from->certblob)) != 0 || (ret = sshbuf_putb(to->critical, from->critical)) != 0 || (ret = sshbuf_putb(to->extensions, from->extensions) != 0)) return ret; to->serial = from->serial; to->type = from->type; if (from->key_id == NULL) to->key_id = NULL; else if ((to->key_id = strdup(from->key_id)) == NULL) return SSH_ERR_ALLOC_FAIL; to->valid_after = from->valid_after; to->valid_before = from->valid_before; if (from->signature_key == NULL) to->signature_key = NULL; else if ((ret = sshkey_from_private(from->signature_key, &to->signature_key)) != 0) return ret; if (from->nprincipals > SSHKEY_CERT_MAX_PRINCIPALS) return SSH_ERR_INVALID_ARGUMENT; if (from->nprincipals > 0) { if ((to->principals = calloc(from->nprincipals, sizeof(*to->principals))) == NULL) return SSH_ERR_ALLOC_FAIL; for (i = 0; i < from->nprincipals; i++) { to->principals[i] = strdup(from->principals[i]); if (to->principals[i] == NULL) { to->nprincipals = i; return SSH_ERR_ALLOC_FAIL; } } } to->nprincipals = from->nprincipals; return 0; } int sshkey_from_private(const struct sshkey *k, struct sshkey **pkp) { struct sshkey *n = NULL; int ret = SSH_ERR_INTERNAL_ERROR; if (pkp != NULL) *pkp = NULL; switch (k->type) { #ifdef WITH_OPENSSL case KEY_DSA: case KEY_DSA_CERT: if ((n = sshkey_new(k->type)) == NULL) return SSH_ERR_ALLOC_FAIL; if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) || (BN_copy(n->dsa->q, k->dsa->q) == NULL) || (BN_copy(n->dsa->g, k->dsa->g) == NULL) || (BN_copy(n->dsa->pub_key, k->dsa->pub_key) == NULL)) { sshkey_free(n); return SSH_ERR_ALLOC_FAIL; } break; # ifdef OPENSSL_HAS_ECC case KEY_ECDSA: case KEY_ECDSA_CERT: if ((n = sshkey_new(k->type)) == NULL) return SSH_ERR_ALLOC_FAIL; n->ecdsa_nid = k->ecdsa_nid; n->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid); if (n->ecdsa == NULL) { sshkey_free(n); return SSH_ERR_ALLOC_FAIL; } if (EC_KEY_set_public_key(n->ecdsa, EC_KEY_get0_public_key(k->ecdsa)) != 1) { sshkey_free(n); return SSH_ERR_LIBCRYPTO_ERROR; } break; # endif /* OPENSSL_HAS_ECC */ case KEY_RSA: case KEY_RSA1: case KEY_RSA_CERT: if ((n = sshkey_new(k->type)) == NULL) return SSH_ERR_ALLOC_FAIL; if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) || (BN_copy(n->rsa->e, k->rsa->e) == NULL)) { sshkey_free(n); return SSH_ERR_ALLOC_FAIL; } break; #endif /* WITH_OPENSSL */ case KEY_ED25519: case KEY_ED25519_CERT: if ((n = sshkey_new(k->type)) == NULL) return SSH_ERR_ALLOC_FAIL; if (k->ed25519_pk != NULL) { if ((n->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) { sshkey_free(n); return SSH_ERR_ALLOC_FAIL; } memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ); } break; default: return SSH_ERR_KEY_TYPE_UNKNOWN; } if (sshkey_is_cert(k)) { if ((ret = sshkey_cert_copy(k, n)) != 0) { sshkey_free(n); return ret; } } *pkp = n; return 0; } static int cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf) { struct sshbuf *principals = NULL, *crit = NULL; struct sshbuf *exts = NULL, *ca = NULL; u_char *sig = NULL; size_t signed_len = 0, slen = 0, kidlen = 0; int ret = SSH_ERR_INTERNAL_ERROR; /* Copy the entire key blob for verification and later serialisation */ if ((ret = sshbuf_putb(key->cert->certblob, certbuf)) != 0) return ret; /* Parse body of certificate up to signature */ if ((ret = sshbuf_get_u64(b, &key->cert->serial)) != 0 || (ret = sshbuf_get_u32(b, &key->cert->type)) != 0 || (ret = sshbuf_get_cstring(b, &key->cert->key_id, &kidlen)) != 0 || (ret = sshbuf_froms(b, &principals)) != 0 || (ret = sshbuf_get_u64(b, &key->cert->valid_after)) != 0 || (ret = sshbuf_get_u64(b, &key->cert->valid_before)) != 0 || (ret = sshbuf_froms(b, &crit)) != 0 || (ret = sshbuf_froms(b, &exts)) != 0 || (ret = sshbuf_get_string_direct(b, NULL, NULL)) != 0 || (ret = sshbuf_froms(b, &ca)) != 0) { /* XXX debug print error for ret */ ret = SSH_ERR_INVALID_FORMAT; goto out; } /* Signature is left in the buffer so we can calculate this length */ signed_len = sshbuf_len(key->cert->certblob) - sshbuf_len(b); if ((ret = sshbuf_get_string(b, &sig, &slen)) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } if (key->cert->type != SSH2_CERT_TYPE_USER && key->cert->type != SSH2_CERT_TYPE_HOST) { ret = SSH_ERR_KEY_CERT_UNKNOWN_TYPE; goto out; } /* Parse principals section */ while (sshbuf_len(principals) > 0) { char *principal = NULL; char **oprincipals = NULL; if (key->cert->nprincipals >= SSHKEY_CERT_MAX_PRINCIPALS) { ret = SSH_ERR_INVALID_FORMAT; goto out; } if ((ret = sshbuf_get_cstring(principals, &principal, NULL)) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } oprincipals = key->cert->principals; key->cert->principals = reallocarray(key->cert->principals, key->cert->nprincipals + 1, sizeof(*key->cert->principals)); if (key->cert->principals == NULL) { free(principal); key->cert->principals = oprincipals; ret = SSH_ERR_ALLOC_FAIL; goto out; } key->cert->principals[key->cert->nprincipals++] = principal; } /* * Stash a copies of the critical options and extensions sections * for later use. */ if ((ret = sshbuf_putb(key->cert->critical, crit)) != 0 || (exts != NULL && (ret = sshbuf_putb(key->cert->extensions, exts)) != 0)) goto out; /* * Validate critical options and extensions sections format. */ while (sshbuf_len(crit) != 0) { if ((ret = sshbuf_get_string_direct(crit, NULL, NULL)) != 0 || (ret = sshbuf_get_string_direct(crit, NULL, NULL)) != 0) { sshbuf_reset(key->cert->critical); ret = SSH_ERR_INVALID_FORMAT; goto out; } } while (exts != NULL && sshbuf_len(exts) != 0) { if ((ret = sshbuf_get_string_direct(exts, NULL, NULL)) != 0 || (ret = sshbuf_get_string_direct(exts, NULL, NULL)) != 0) { sshbuf_reset(key->cert->extensions); ret = SSH_ERR_INVALID_FORMAT; goto out; } } /* Parse CA key and check signature */ if (sshkey_from_blob_internal(ca, &key->cert->signature_key, 0) != 0) { ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; goto out; } if (!sshkey_type_is_valid_ca(key->cert->signature_key->type)) { ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; goto out; } if ((ret = sshkey_verify(key->cert->signature_key, sig, slen, sshbuf_ptr(key->cert->certblob), signed_len, 0)) != 0) goto out; /* Success */ ret = 0; out: sshbuf_free(ca); sshbuf_free(crit); sshbuf_free(exts); sshbuf_free(principals); free(sig); return ret; } static int sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp, int allow_cert) { int type, ret = SSH_ERR_INTERNAL_ERROR; char *ktype = NULL, *curve = NULL; struct sshkey *key = NULL; size_t len; u_char *pk = NULL; struct sshbuf *copy; #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) EC_POINT *q = NULL; #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ #ifdef DEBUG_PK /* XXX */ sshbuf_dump(b, stderr); #endif *keyp = NULL; if ((copy = sshbuf_fromb(b)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } if (sshbuf_get_cstring(b, &ktype, NULL) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } type = sshkey_type_from_name(ktype); if (!allow_cert && sshkey_type_is_cert(type)) { ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; goto out; } switch (type) { #ifdef WITH_OPENSSL case KEY_RSA_CERT: /* Skip nonce */ if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } /* FALLTHROUGH */ case KEY_RSA: if ((key = sshkey_new(type)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } if (sshbuf_get_bignum2(b, key->rsa->e) != 0 || sshbuf_get_bignum2(b, key->rsa->n) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } #ifdef DEBUG_PK RSA_print_fp(stderr, key->rsa, 8); #endif break; case KEY_DSA_CERT: /* Skip nonce */ if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } /* FALLTHROUGH */ case KEY_DSA: if ((key = sshkey_new(type)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } if (sshbuf_get_bignum2(b, key->dsa->p) != 0 || sshbuf_get_bignum2(b, key->dsa->q) != 0 || sshbuf_get_bignum2(b, key->dsa->g) != 0 || sshbuf_get_bignum2(b, key->dsa->pub_key) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } #ifdef DEBUG_PK DSA_print_fp(stderr, key->dsa, 8); #endif break; case KEY_ECDSA_CERT: /* Skip nonce */ if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } /* FALLTHROUGH */ # ifdef OPENSSL_HAS_ECC case KEY_ECDSA: if ((key = sshkey_new(type)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } key->ecdsa_nid = sshkey_ecdsa_nid_from_name(ktype); if (sshbuf_get_cstring(b, &curve, NULL) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } if (key->ecdsa_nid != sshkey_curve_name_to_nid(curve)) { ret = SSH_ERR_EC_CURVE_MISMATCH; goto out; } if (key->ecdsa != NULL) EC_KEY_free(key->ecdsa); if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid)) == NULL) { ret = SSH_ERR_EC_CURVE_INVALID; goto out; } if ((q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } if (sshbuf_get_ec(b, q, EC_KEY_get0_group(key->ecdsa)) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa), q) != 0) { ret = SSH_ERR_KEY_INVALID_EC_VALUE; goto out; } if (EC_KEY_set_public_key(key->ecdsa, q) != 1) { /* XXX assume it is a allocation error */ ret = SSH_ERR_ALLOC_FAIL; goto out; } #ifdef DEBUG_PK sshkey_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q); #endif break; # endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ case KEY_ED25519_CERT: /* Skip nonce */ if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } /* FALLTHROUGH */ case KEY_ED25519: if ((ret = sshbuf_get_string(b, &pk, &len)) != 0) goto out; if (len != ED25519_PK_SZ) { ret = SSH_ERR_INVALID_FORMAT; goto out; } if ((key = sshkey_new(type)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } key->ed25519_pk = pk; pk = NULL; break; case KEY_UNSPEC: if ((key = sshkey_new(type)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } break; default: ret = SSH_ERR_KEY_TYPE_UNKNOWN; goto out; } /* Parse certificate potion */ if (sshkey_is_cert(key) && (ret = cert_parse(b, key, copy)) != 0) goto out; if (key != NULL && sshbuf_len(b) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } ret = 0; *keyp = key; key = NULL; out: sshbuf_free(copy); sshkey_free(key); free(ktype); free(curve); free(pk); #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) if (q != NULL) EC_POINT_free(q); #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ return ret; } int sshkey_from_blob(const u_char *blob, size_t blen, struct sshkey **keyp) { struct sshbuf *b; int r; if ((b = sshbuf_from(blob, blen)) == NULL) return SSH_ERR_ALLOC_FAIL; r = sshkey_from_blob_internal(b, keyp, 1); sshbuf_free(b); return r; } int sshkey_fromb(struct sshbuf *b, struct sshkey **keyp) { return sshkey_from_blob_internal(b, keyp, 1); } int sshkey_froms(struct sshbuf *buf, struct sshkey **keyp) { struct sshbuf *b; int r; if ((r = sshbuf_froms(buf, &b)) != 0) return r; r = sshkey_from_blob_internal(b, keyp, 1); sshbuf_free(b); return r; } int sshkey_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, u_int compat) { if (sigp != NULL) *sigp = NULL; if (lenp != NULL) *lenp = 0; if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE) return SSH_ERR_INVALID_ARGUMENT; switch (key->type) { #ifdef WITH_OPENSSL case KEY_DSA_CERT: case KEY_DSA: return ssh_dss_sign(key, sigp, lenp, data, datalen, compat); # ifdef OPENSSL_HAS_ECC case KEY_ECDSA_CERT: case KEY_ECDSA: return ssh_ecdsa_sign(key, sigp, lenp, data, datalen, compat); # endif /* OPENSSL_HAS_ECC */ case KEY_RSA_CERT: case KEY_RSA: return ssh_rsa_sign(key, sigp, lenp, data, datalen, compat); #endif /* WITH_OPENSSL */ case KEY_ED25519: case KEY_ED25519_CERT: return ssh_ed25519_sign(key, sigp, lenp, data, datalen, compat); default: return SSH_ERR_KEY_TYPE_UNKNOWN; } } /* * ssh_key_verify returns 0 for a correct signature and < 0 on error. */ int sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen, const u_char *data, size_t dlen, u_int compat) { if (siglen == 0 || dlen > SSH_KEY_MAX_SIGN_DATA_SIZE) return SSH_ERR_INVALID_ARGUMENT; switch (key->type) { #ifdef WITH_OPENSSL case KEY_DSA_CERT: case KEY_DSA: return ssh_dss_verify(key, sig, siglen, data, dlen, compat); # ifdef OPENSSL_HAS_ECC case KEY_ECDSA_CERT: case KEY_ECDSA: return ssh_ecdsa_verify(key, sig, siglen, data, dlen, compat); # endif /* OPENSSL_HAS_ECC */ case KEY_RSA_CERT: case KEY_RSA: return ssh_rsa_verify(key, sig, siglen, data, dlen, compat); #endif /* WITH_OPENSSL */ case KEY_ED25519: case KEY_ED25519_CERT: return ssh_ed25519_verify(key, sig, siglen, data, dlen, compat); default: return SSH_ERR_KEY_TYPE_UNKNOWN; } } /* Converts a private to a public key */ int sshkey_demote(const struct sshkey *k, struct sshkey **dkp) { struct sshkey *pk; int ret = SSH_ERR_INTERNAL_ERROR; if (dkp != NULL) *dkp = NULL; if ((pk = calloc(1, sizeof(*pk))) == NULL) return SSH_ERR_ALLOC_FAIL; pk->type = k->type; pk->flags = k->flags; pk->ecdsa_nid = k->ecdsa_nid; pk->dsa = NULL; pk->ecdsa = NULL; pk->rsa = NULL; pk->ed25519_pk = NULL; pk->ed25519_sk = NULL; switch (k->type) { #ifdef WITH_OPENSSL case KEY_RSA_CERT: if ((ret = sshkey_cert_copy(k, pk)) != 0) goto fail; /* FALLTHROUGH */ case KEY_RSA1: case KEY_RSA: if ((pk->rsa = RSA_new()) == NULL || (pk->rsa->e = BN_dup(k->rsa->e)) == NULL || (pk->rsa->n = BN_dup(k->rsa->n)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto fail; } break; case KEY_DSA_CERT: if ((ret = sshkey_cert_copy(k, pk)) != 0) goto fail; /* FALLTHROUGH */ case KEY_DSA: if ((pk->dsa = DSA_new()) == NULL || (pk->dsa->p = BN_dup(k->dsa->p)) == NULL || (pk->dsa->q = BN_dup(k->dsa->q)) == NULL || (pk->dsa->g = BN_dup(k->dsa->g)) == NULL || (pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto fail; } break; case KEY_ECDSA_CERT: if ((ret = sshkey_cert_copy(k, pk)) != 0) goto fail; /* FALLTHROUGH */ # ifdef OPENSSL_HAS_ECC case KEY_ECDSA: pk->ecdsa = EC_KEY_new_by_curve_name(pk->ecdsa_nid); if (pk->ecdsa == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto fail; } if (EC_KEY_set_public_key(pk->ecdsa, EC_KEY_get0_public_key(k->ecdsa)) != 1) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto fail; } break; # endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ case KEY_ED25519_CERT: if ((ret = sshkey_cert_copy(k, pk)) != 0) goto fail; /* FALLTHROUGH */ case KEY_ED25519: if (k->ed25519_pk != NULL) { if ((pk->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto fail; } memcpy(pk->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ); } break; default: ret = SSH_ERR_KEY_TYPE_UNKNOWN; fail: sshkey_free(pk); return ret; } *dkp = pk; return 0; } /* Convert a plain key to their _CERT equivalent */ int sshkey_to_certified(struct sshkey *k) { int newtype; switch (k->type) { #ifdef WITH_OPENSSL case KEY_RSA: newtype = KEY_RSA_CERT; break; case KEY_DSA: newtype = KEY_DSA_CERT; break; case KEY_ECDSA: newtype = KEY_ECDSA_CERT; break; #endif /* WITH_OPENSSL */ case KEY_ED25519: newtype = KEY_ED25519_CERT; break; default: return SSH_ERR_INVALID_ARGUMENT; } if ((k->cert = cert_new()) == NULL) return SSH_ERR_ALLOC_FAIL; k->type = newtype; return 0; } /* Convert a certificate to its raw key equivalent */ int sshkey_drop_cert(struct sshkey *k) { if (!sshkey_type_is_cert(k->type)) return SSH_ERR_KEY_TYPE_UNKNOWN; cert_free(k->cert); k->cert = NULL; k->type = sshkey_type_plain(k->type); return 0; } /* Sign a certified key, (re-)generating the signed certblob. */ int sshkey_certify(struct sshkey *k, struct sshkey *ca) { struct sshbuf *principals = NULL; u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32]; size_t i, ca_len, sig_len; int ret = SSH_ERR_INTERNAL_ERROR; struct sshbuf *cert; if (k == NULL || k->cert == NULL || k->cert->certblob == NULL || ca == NULL) return SSH_ERR_INVALID_ARGUMENT; if (!sshkey_is_cert(k)) return SSH_ERR_KEY_TYPE_UNKNOWN; if (!sshkey_type_is_valid_ca(ca->type)) return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; if ((ret = sshkey_to_blob(ca, &ca_blob, &ca_len)) != 0) return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; cert = k->cert->certblob; /* for readability */ sshbuf_reset(cert); if ((ret = sshbuf_put_cstring(cert, sshkey_ssh_name(k))) != 0) goto out; /* -v01 certs put nonce first */ arc4random_buf(&nonce, sizeof(nonce)); if ((ret = sshbuf_put_string(cert, nonce, sizeof(nonce))) != 0) goto out; /* XXX this substantially duplicates to_blob(); refactor */ switch (k->type) { #ifdef WITH_OPENSSL case KEY_DSA_CERT: if ((ret = sshbuf_put_bignum2(cert, k->dsa->p)) != 0 || (ret = sshbuf_put_bignum2(cert, k->dsa->q)) != 0 || (ret = sshbuf_put_bignum2(cert, k->dsa->g)) != 0 || (ret = sshbuf_put_bignum2(cert, k->dsa->pub_key)) != 0) goto out; break; # ifdef OPENSSL_HAS_ECC case KEY_ECDSA_CERT: if ((ret = sshbuf_put_cstring(cert, sshkey_curve_nid_to_name(k->ecdsa_nid))) != 0 || (ret = sshbuf_put_ec(cert, EC_KEY_get0_public_key(k->ecdsa), EC_KEY_get0_group(k->ecdsa))) != 0) goto out; break; # endif /* OPENSSL_HAS_ECC */ case KEY_RSA_CERT: if ((ret = sshbuf_put_bignum2(cert, k->rsa->e)) != 0 || (ret = sshbuf_put_bignum2(cert, k->rsa->n)) != 0) goto out; break; #endif /* WITH_OPENSSL */ case KEY_ED25519_CERT: if ((ret = sshbuf_put_string(cert, k->ed25519_pk, ED25519_PK_SZ)) != 0) goto out; break; default: ret = SSH_ERR_INVALID_ARGUMENT; goto out; } if ((ret = sshbuf_put_u64(cert, k->cert->serial)) != 0 || (ret = sshbuf_put_u32(cert, k->cert->type)) != 0 || (ret = sshbuf_put_cstring(cert, k->cert->key_id)) != 0) goto out; if ((principals = sshbuf_new()) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } for (i = 0; i < k->cert->nprincipals; i++) { if ((ret = sshbuf_put_cstring(principals, k->cert->principals[i])) != 0) goto out; } if ((ret = sshbuf_put_stringb(cert, principals)) != 0 || (ret = sshbuf_put_u64(cert, k->cert->valid_after)) != 0 || (ret = sshbuf_put_u64(cert, k->cert->valid_before)) != 0 || (ret = sshbuf_put_stringb(cert, k->cert->critical)) != 0 || (ret = sshbuf_put_stringb(cert, k->cert->extensions)) != 0 || (ret = sshbuf_put_string(cert, NULL, 0)) != 0 || /* Reserved */ (ret = sshbuf_put_string(cert, ca_blob, ca_len)) != 0) goto out; /* Sign the whole mess */ if ((ret = sshkey_sign(ca, &sig_blob, &sig_len, sshbuf_ptr(cert), sshbuf_len(cert), 0)) != 0) goto out; /* Append signature and we are done */ if ((ret = sshbuf_put_string(cert, sig_blob, sig_len)) != 0) goto out; ret = 0; out: if (ret != 0) sshbuf_reset(cert); if (sig_blob != NULL) free(sig_blob); if (ca_blob != NULL) free(ca_blob); if (principals != NULL) sshbuf_free(principals); return ret; } int sshkey_cert_check_authority(const struct sshkey *k, int want_host, int require_principal, const char *name, const char **reason) { u_int i, principal_matches; time_t now = time(NULL); if (reason != NULL) *reason = NULL; if (want_host) { if (k->cert->type != SSH2_CERT_TYPE_HOST) { *reason = "Certificate invalid: not a host certificate"; return SSH_ERR_KEY_CERT_INVALID; } } else { if (k->cert->type != SSH2_CERT_TYPE_USER) { *reason = "Certificate invalid: not a user certificate"; return SSH_ERR_KEY_CERT_INVALID; } } if (now < 0) { /* yikes - system clock before epoch! */ *reason = "Certificate invalid: not yet valid"; return SSH_ERR_KEY_CERT_INVALID; } if ((u_int64_t)now < k->cert->valid_after) { *reason = "Certificate invalid: not yet valid"; return SSH_ERR_KEY_CERT_INVALID; } if ((u_int64_t)now >= k->cert->valid_before) { *reason = "Certificate invalid: expired"; return SSH_ERR_KEY_CERT_INVALID; } if (k->cert->nprincipals == 0) { if (require_principal) { *reason = "Certificate lacks principal list"; return SSH_ERR_KEY_CERT_INVALID; } } else if (name != NULL) { principal_matches = 0; for (i = 0; i < k->cert->nprincipals; i++) { if (strcmp(name, k->cert->principals[i]) == 0) { principal_matches = 1; break; } } if (!principal_matches) { *reason = "Certificate invalid: name is not a listed " "principal"; return SSH_ERR_KEY_CERT_INVALID; } } return 0; } int sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b) { int r = SSH_ERR_INTERNAL_ERROR; if ((r = sshbuf_put_cstring(b, sshkey_ssh_name(key))) != 0) goto out; switch (key->type) { #ifdef WITH_OPENSSL case KEY_RSA: if ((r = sshbuf_put_bignum2(b, key->rsa->n)) != 0 || (r = sshbuf_put_bignum2(b, key->rsa->e)) != 0 || (r = sshbuf_put_bignum2(b, key->rsa->d)) != 0 || (r = sshbuf_put_bignum2(b, key->rsa->iqmp)) != 0 || (r = sshbuf_put_bignum2(b, key->rsa->p)) != 0 || (r = sshbuf_put_bignum2(b, key->rsa->q)) != 0) goto out; break; case KEY_RSA_CERT: if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) { r = SSH_ERR_INVALID_ARGUMENT; goto out; } if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || (r = sshbuf_put_bignum2(b, key->rsa->d)) != 0 || (r = sshbuf_put_bignum2(b, key->rsa->iqmp)) != 0 || (r = sshbuf_put_bignum2(b, key->rsa->p)) != 0 || (r = sshbuf_put_bignum2(b, key->rsa->q)) != 0) goto out; break; case KEY_DSA: if ((r = sshbuf_put_bignum2(b, key->dsa->p)) != 0 || (r = sshbuf_put_bignum2(b, key->dsa->q)) != 0 || (r = sshbuf_put_bignum2(b, key->dsa->g)) != 0 || (r = sshbuf_put_bignum2(b, key->dsa->pub_key)) != 0 || (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0) goto out; break; case KEY_DSA_CERT: if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) { r = SSH_ERR_INVALID_ARGUMENT; goto out; } if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0) goto out; break; # ifdef OPENSSL_HAS_ECC case KEY_ECDSA: if ((r = sshbuf_put_cstring(b, sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 || (r = sshbuf_put_eckey(b, key->ecdsa)) != 0 || (r = sshbuf_put_bignum2(b, EC_KEY_get0_private_key(key->ecdsa))) != 0) goto out; break; case KEY_ECDSA_CERT: if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) { r = SSH_ERR_INVALID_ARGUMENT; goto out; } if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || (r = sshbuf_put_bignum2(b, EC_KEY_get0_private_key(key->ecdsa))) != 0) goto out; break; # endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ case KEY_ED25519: if ((r = sshbuf_put_string(b, key->ed25519_pk, ED25519_PK_SZ)) != 0 || (r = sshbuf_put_string(b, key->ed25519_sk, ED25519_SK_SZ)) != 0) goto out; break; case KEY_ED25519_CERT: if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) { r = SSH_ERR_INVALID_ARGUMENT; goto out; } if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || (r = sshbuf_put_string(b, key->ed25519_pk, ED25519_PK_SZ)) != 0 || (r = sshbuf_put_string(b, key->ed25519_sk, ED25519_SK_SZ)) != 0) goto out; break; default: r = SSH_ERR_INVALID_ARGUMENT; goto out; } /* success */ r = 0; out: return r; } int sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) { char *tname = NULL, *curve = NULL; struct sshkey *k = NULL; size_t pklen = 0, sklen = 0; int type, r = SSH_ERR_INTERNAL_ERROR; u_char *ed25519_pk = NULL, *ed25519_sk = NULL; #ifdef WITH_OPENSSL BIGNUM *exponent = NULL; #endif /* WITH_OPENSSL */ if (kp != NULL) *kp = NULL; if ((r = sshbuf_get_cstring(buf, &tname, NULL)) != 0) goto out; type = sshkey_type_from_name(tname); switch (type) { #ifdef WITH_OPENSSL case KEY_DSA: if ((k = sshkey_new_private(type)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = sshbuf_get_bignum2(buf, k->dsa->p)) != 0 || (r = sshbuf_get_bignum2(buf, k->dsa->q)) != 0 || (r = sshbuf_get_bignum2(buf, k->dsa->g)) != 0 || (r = sshbuf_get_bignum2(buf, k->dsa->pub_key)) != 0 || (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0) goto out; break; case KEY_DSA_CERT: if ((r = sshkey_froms(buf, &k)) != 0 || (r = sshkey_add_private(k)) != 0 || (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0) goto out; break; # ifdef OPENSSL_HAS_ECC case KEY_ECDSA: if ((k = sshkey_new_private(type)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) { r = SSH_ERR_INVALID_ARGUMENT; goto out; } if ((r = sshbuf_get_cstring(buf, &curve, NULL)) != 0) goto out; if (k->ecdsa_nid != sshkey_curve_name_to_nid(curve)) { r = SSH_ERR_EC_CURVE_MISMATCH; goto out; } k->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid); if (k->ecdsa == NULL || (exponent = BN_new()) == NULL) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if ((r = sshbuf_get_eckey(buf, k->ecdsa)) != 0 || (r = sshbuf_get_bignum2(buf, exponent))) goto out; if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa), EC_KEY_get0_public_key(k->ecdsa)) != 0) || (r = sshkey_ec_validate_private(k->ecdsa)) != 0) goto out; break; case KEY_ECDSA_CERT: if ((exponent = BN_new()) == NULL) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if ((r = sshkey_froms(buf, &k)) != 0 || (r = sshkey_add_private(k)) != 0 || (r = sshbuf_get_bignum2(buf, exponent)) != 0) goto out; if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa), EC_KEY_get0_public_key(k->ecdsa)) != 0) || (r = sshkey_ec_validate_private(k->ecdsa)) != 0) goto out; break; # endif /* OPENSSL_HAS_ECC */ case KEY_RSA: if ((k = sshkey_new_private(type)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = sshbuf_get_bignum2(buf, k->rsa->n)) != 0 || (r = sshbuf_get_bignum2(buf, k->rsa->e)) != 0 || (r = sshbuf_get_bignum2(buf, k->rsa->d)) != 0 || (r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 || (r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 || (r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 || (r = rsa_generate_additional_parameters(k->rsa)) != 0) goto out; break; case KEY_RSA_CERT: if ((r = sshkey_froms(buf, &k)) != 0 || (r = sshkey_add_private(k)) != 0 || (r = sshbuf_get_bignum2(buf, k->rsa->d) != 0) || (r = sshbuf_get_bignum2(buf, k->rsa->iqmp) != 0) || (r = sshbuf_get_bignum2(buf, k->rsa->p) != 0) || (r = sshbuf_get_bignum2(buf, k->rsa->q) != 0) || (r = rsa_generate_additional_parameters(k->rsa)) != 0) goto out; break; #endif /* WITH_OPENSSL */ case KEY_ED25519: if ((k = sshkey_new_private(type)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 || (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0) goto out; if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) { r = SSH_ERR_INVALID_FORMAT; goto out; } k->ed25519_pk = ed25519_pk; k->ed25519_sk = ed25519_sk; ed25519_pk = ed25519_sk = NULL; break; case KEY_ED25519_CERT: if ((r = sshkey_froms(buf, &k)) != 0 || (r = sshkey_add_private(k)) != 0 || (r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 || (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0) goto out; if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) { r = SSH_ERR_INVALID_FORMAT; goto out; } k->ed25519_pk = ed25519_pk; k->ed25519_sk = ed25519_sk; ed25519_pk = ed25519_sk = NULL; break; default: r = SSH_ERR_KEY_TYPE_UNKNOWN; goto out; } #ifdef WITH_OPENSSL /* enable blinding */ switch (k->type) { case KEY_RSA: case KEY_RSA_CERT: case KEY_RSA1: if (RSA_blinding_on(k->rsa, NULL) != 1) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } break; } #endif /* WITH_OPENSSL */ /* success */ r = 0; if (kp != NULL) { *kp = k; k = NULL; } out: free(tname); free(curve); #ifdef WITH_OPENSSL if (exponent != NULL) BN_clear_free(exponent); #endif /* WITH_OPENSSL */ sshkey_free(k); if (ed25519_pk != NULL) { explicit_bzero(ed25519_pk, pklen); free(ed25519_pk); } if (ed25519_sk != NULL) { explicit_bzero(ed25519_sk, sklen); free(ed25519_sk); } return r; } #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) int sshkey_ec_validate_public(const EC_GROUP *group, const EC_POINT *public) { BN_CTX *bnctx; EC_POINT *nq = NULL; BIGNUM *order, *x, *y, *tmp; int ret = SSH_ERR_KEY_INVALID_EC_VALUE; if ((bnctx = BN_CTX_new()) == NULL) return SSH_ERR_ALLOC_FAIL; BN_CTX_start(bnctx); /* * We shouldn't ever hit this case because bignum_get_ecpoint() * refuses to load GF2m points. */ if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != NID_X9_62_prime_field) goto out; /* Q != infinity */ if (EC_POINT_is_at_infinity(group, public)) goto out; if ((x = BN_CTX_get(bnctx)) == NULL || (y = BN_CTX_get(bnctx)) == NULL || (order = BN_CTX_get(bnctx)) == NULL || (tmp = BN_CTX_get(bnctx)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } /* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */ if (EC_GROUP_get_order(group, order, bnctx) != 1 || EC_POINT_get_affine_coordinates_GFp(group, public, x, y, bnctx) != 1) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if (BN_num_bits(x) <= BN_num_bits(order) / 2 || BN_num_bits(y) <= BN_num_bits(order) / 2) goto out; /* nQ == infinity (n == order of subgroup) */ if ((nq = EC_POINT_new(group)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } if (EC_POINT_mul(group, nq, NULL, public, order, bnctx) != 1) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if (EC_POINT_is_at_infinity(group, nq) != 1) goto out; /* x < order - 1, y < order - 1 */ if (!BN_sub(tmp, order, BN_value_one())) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if (BN_cmp(x, tmp) >= 0 || BN_cmp(y, tmp) >= 0) goto out; ret = 0; out: BN_CTX_free(bnctx); if (nq != NULL) EC_POINT_free(nq); return ret; } int sshkey_ec_validate_private(const EC_KEY *key) { BN_CTX *bnctx; BIGNUM *order, *tmp; int ret = SSH_ERR_KEY_INVALID_EC_VALUE; if ((bnctx = BN_CTX_new()) == NULL) return SSH_ERR_ALLOC_FAIL; BN_CTX_start(bnctx); if ((order = BN_CTX_get(bnctx)) == NULL || (tmp = BN_CTX_get(bnctx)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } /* log2(private) > log2(order)/2 */ if (EC_GROUP_get_order(EC_KEY_get0_group(key), order, bnctx) != 1) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if (BN_num_bits(EC_KEY_get0_private_key(key)) <= BN_num_bits(order) / 2) goto out; /* private < order - 1 */ if (!BN_sub(tmp, order, BN_value_one())) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if (BN_cmp(EC_KEY_get0_private_key(key), tmp) >= 0) goto out; ret = 0; out: BN_CTX_free(bnctx); return ret; } void sshkey_dump_ec_point(const EC_GROUP *group, const EC_POINT *point) { BIGNUM *x, *y; BN_CTX *bnctx; if (point == NULL) { fputs("point=(NULL)\n", stderr); return; } if ((bnctx = BN_CTX_new()) == NULL) { fprintf(stderr, "%s: BN_CTX_new failed\n", __func__); return; } BN_CTX_start(bnctx); if ((x = BN_CTX_get(bnctx)) == NULL || (y = BN_CTX_get(bnctx)) == NULL) { fprintf(stderr, "%s: BN_CTX_get failed\n", __func__); return; } if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != NID_X9_62_prime_field) { fprintf(stderr, "%s: group is not a prime field\n", __func__); return; } if (EC_POINT_get_affine_coordinates_GFp(group, point, x, y, bnctx) != 1) { fprintf(stderr, "%s: EC_POINT_get_affine_coordinates_GFp\n", __func__); return; } fputs("x=", stderr); BN_print_fp(stderr, x); fputs("\ny=", stderr); BN_print_fp(stderr, y); fputs("\n", stderr); BN_CTX_free(bnctx); } void sshkey_dump_ec_key(const EC_KEY *key) { const BIGNUM *exponent; sshkey_dump_ec_point(EC_KEY_get0_group(key), EC_KEY_get0_public_key(key)); fputs("exponent=", stderr); if ((exponent = EC_KEY_get0_private_key(key)) == NULL) fputs("(NULL)", stderr); else BN_print_fp(stderr, EC_KEY_get0_private_key(key)); fputs("\n", stderr); } #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ static int sshkey_private_to_blob2(const struct sshkey *prv, struct sshbuf *blob, const char *passphrase, const char *comment, const char *ciphername, int rounds) { u_char *cp, *key = NULL, *pubkeyblob = NULL; u_char salt[SALT_LEN]; char *b64 = NULL; size_t i, pubkeylen, keylen, ivlen, blocksize, authlen; u_int check; int r = SSH_ERR_INTERNAL_ERROR; struct sshcipher_ctx ciphercontext; const struct sshcipher *cipher; const char *kdfname = KDFNAME; struct sshbuf *encoded = NULL, *encrypted = NULL, *kdf = NULL; memset(&ciphercontext, 0, sizeof(ciphercontext)); if (rounds <= 0) rounds = DEFAULT_ROUNDS; if (passphrase == NULL || !strlen(passphrase)) { ciphername = "none"; kdfname = "none"; } else if (ciphername == NULL) ciphername = DEFAULT_CIPHERNAME; else if (cipher_number(ciphername) != SSH_CIPHER_SSH2) { r = SSH_ERR_INVALID_ARGUMENT; goto out; } if ((cipher = cipher_by_name(ciphername)) == NULL) { r = SSH_ERR_INTERNAL_ERROR; goto out; } if ((kdf = sshbuf_new()) == NULL || (encoded = sshbuf_new()) == NULL || (encrypted = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } blocksize = cipher_blocksize(cipher); keylen = cipher_keylen(cipher); ivlen = cipher_ivlen(cipher); authlen = cipher_authlen(cipher); if ((key = calloc(1, keylen + ivlen)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if (strcmp(kdfname, "bcrypt") == 0) { arc4random_buf(salt, SALT_LEN); if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, SALT_LEN, key, keylen + ivlen, rounds) < 0) { r = SSH_ERR_INVALID_ARGUMENT; goto out; } if ((r = sshbuf_put_string(kdf, salt, SALT_LEN)) != 0 || (r = sshbuf_put_u32(kdf, rounds)) != 0) goto out; } else if (strcmp(kdfname, "none") != 0) { /* Unsupported KDF type */ r = SSH_ERR_KEY_UNKNOWN_CIPHER; goto out; } if ((r = cipher_init(&ciphercontext, cipher, key, keylen, key + keylen, ivlen, 1)) != 0) goto out; if ((r = sshbuf_put(encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC))) != 0 || (r = sshbuf_put_cstring(encoded, ciphername)) != 0 || (r = sshbuf_put_cstring(encoded, kdfname)) != 0 || (r = sshbuf_put_stringb(encoded, kdf)) != 0 || (r = sshbuf_put_u32(encoded, 1)) != 0 || /* number of keys */ (r = sshkey_to_blob(prv, &pubkeyblob, &pubkeylen)) != 0 || (r = sshbuf_put_string(encoded, pubkeyblob, pubkeylen)) != 0) goto out; /* set up the buffer that will be encrypted */ /* Random check bytes */ check = arc4random(); if ((r = sshbuf_put_u32(encrypted, check)) != 0 || (r = sshbuf_put_u32(encrypted, check)) != 0) goto out; /* append private key and comment*/ if ((r = sshkey_private_serialize(prv, encrypted)) != 0 || (r = sshbuf_put_cstring(encrypted, comment)) != 0) goto out; /* padding */ i = 0; while (sshbuf_len(encrypted) % blocksize) { if ((r = sshbuf_put_u8(encrypted, ++i & 0xff)) != 0) goto out; } /* length in destination buffer */ if ((r = sshbuf_put_u32(encoded, sshbuf_len(encrypted))) != 0) goto out; /* encrypt */ if ((r = sshbuf_reserve(encoded, sshbuf_len(encrypted) + authlen, &cp)) != 0) goto out; if ((r = cipher_crypt(&ciphercontext, 0, cp, sshbuf_ptr(encrypted), sshbuf_len(encrypted), 0, authlen)) != 0) goto out; /* uuencode */ if ((b64 = sshbuf_dtob64(encoded)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } sshbuf_reset(blob); if ((r = sshbuf_put(blob, MARK_BEGIN, MARK_BEGIN_LEN)) != 0) goto out; for (i = 0; i < strlen(b64); i++) { if ((r = sshbuf_put_u8(blob, b64[i])) != 0) goto out; /* insert line breaks */ if (i % 70 == 69 && (r = sshbuf_put_u8(blob, '\n')) != 0) goto out; } if (i % 70 != 69 && (r = sshbuf_put_u8(blob, '\n')) != 0) goto out; if ((r = sshbuf_put(blob, MARK_END, MARK_END_LEN)) != 0) goto out; /* success */ r = 0; out: sshbuf_free(kdf); sshbuf_free(encoded); sshbuf_free(encrypted); cipher_cleanup(&ciphercontext); explicit_bzero(salt, sizeof(salt)); if (key != NULL) { explicit_bzero(key, keylen + ivlen); free(key); } if (pubkeyblob != NULL) { explicit_bzero(pubkeyblob, pubkeylen); free(pubkeyblob); } if (b64 != NULL) { explicit_bzero(b64, strlen(b64)); free(b64); } return r; } static int sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase, struct sshkey **keyp, char **commentp) { char *comment = NULL, *ciphername = NULL, *kdfname = NULL; const struct sshcipher *cipher = NULL; const u_char *cp; int r = SSH_ERR_INTERNAL_ERROR; size_t encoded_len; size_t i, keylen = 0, ivlen = 0, authlen = 0, slen = 0; struct sshbuf *encoded = NULL, *decoded = NULL; struct sshbuf *kdf = NULL, *decrypted = NULL; struct sshcipher_ctx ciphercontext; struct sshkey *k = NULL; u_char *key = NULL, *salt = NULL, *dp, pad, last; u_int blocksize, rounds, nkeys, encrypted_len, check1, check2; memset(&ciphercontext, 0, sizeof(ciphercontext)); if (keyp != NULL) *keyp = NULL; if (commentp != NULL) *commentp = NULL; if ((encoded = sshbuf_new()) == NULL || (decoded = sshbuf_new()) == NULL || (decrypted = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } /* check preamble */ cp = sshbuf_ptr(blob); encoded_len = sshbuf_len(blob); if (encoded_len < (MARK_BEGIN_LEN + MARK_END_LEN) || memcmp(cp, MARK_BEGIN, MARK_BEGIN_LEN) != 0) { r = SSH_ERR_INVALID_FORMAT; goto out; } cp += MARK_BEGIN_LEN; encoded_len -= MARK_BEGIN_LEN; /* Look for end marker, removing whitespace as we go */ while (encoded_len > 0) { if (*cp != '\n' && *cp != '\r') { if ((r = sshbuf_put_u8(encoded, *cp)) != 0) goto out; } last = *cp; encoded_len--; cp++; if (last == '\n') { if (encoded_len >= MARK_END_LEN && memcmp(cp, MARK_END, MARK_END_LEN) == 0) { /* \0 terminate */ if ((r = sshbuf_put_u8(encoded, 0)) != 0) goto out; break; } } } if (encoded_len == 0) { r = SSH_ERR_INVALID_FORMAT; goto out; } /* decode base64 */ if ((r = sshbuf_b64tod(decoded, (char *)sshbuf_ptr(encoded))) != 0) goto out; /* check magic */ if (sshbuf_len(decoded) < sizeof(AUTH_MAGIC) || memcmp(sshbuf_ptr(decoded), AUTH_MAGIC, sizeof(AUTH_MAGIC))) { r = SSH_ERR_INVALID_FORMAT; goto out; } /* parse public portion of key */ if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 || (r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 || (r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 || (r = sshbuf_froms(decoded, &kdf)) != 0 || (r = sshbuf_get_u32(decoded, &nkeys)) != 0 || (r = sshbuf_skip_string(decoded)) != 0 || /* pubkey */ (r = sshbuf_get_u32(decoded, &encrypted_len)) != 0) goto out; if ((cipher = cipher_by_name(ciphername)) == NULL) { r = SSH_ERR_KEY_UNKNOWN_CIPHER; goto out; } if ((passphrase == NULL || strlen(passphrase) == 0) && strcmp(ciphername, "none") != 0) { /* passphrase required */ r = SSH_ERR_KEY_WRONG_PASSPHRASE; goto out; } if (strcmp(kdfname, "none") != 0 && strcmp(kdfname, "bcrypt") != 0) { r = SSH_ERR_KEY_UNKNOWN_CIPHER; goto out; } if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) { r = SSH_ERR_INVALID_FORMAT; goto out; } if (nkeys != 1) { /* XXX only one key supported */ r = SSH_ERR_INVALID_FORMAT; goto out; } /* check size of encrypted key blob */ blocksize = cipher_blocksize(cipher); if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) { r = SSH_ERR_INVALID_FORMAT; goto out; } /* setup key */ keylen = cipher_keylen(cipher); ivlen = cipher_ivlen(cipher); authlen = cipher_authlen(cipher); if ((key = calloc(1, keylen + ivlen)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if (strcmp(kdfname, "bcrypt") == 0) { if ((r = sshbuf_get_string(kdf, &salt, &slen)) != 0 || (r = sshbuf_get_u32(kdf, &rounds)) != 0) goto out; if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen, key, keylen + ivlen, rounds) < 0) { r = SSH_ERR_INVALID_FORMAT; goto out; } } /* check that an appropriate amount of auth data is present */ if (sshbuf_len(decoded) < encrypted_len + authlen) { r = SSH_ERR_INVALID_FORMAT; goto out; } /* decrypt private portion of key */ if ((r = sshbuf_reserve(decrypted, encrypted_len, &dp)) != 0 || (r = cipher_init(&ciphercontext, cipher, key, keylen, key + keylen, ivlen, 0)) != 0) goto out; if ((r = cipher_crypt(&ciphercontext, 0, dp, sshbuf_ptr(decoded), encrypted_len, 0, authlen)) != 0) { /* an integrity error here indicates an incorrect passphrase */ if (r == SSH_ERR_MAC_INVALID) r = SSH_ERR_KEY_WRONG_PASSPHRASE; goto out; } if ((r = sshbuf_consume(decoded, encrypted_len + authlen)) != 0) goto out; /* there should be no trailing data */ if (sshbuf_len(decoded) != 0) { r = SSH_ERR_INVALID_FORMAT; goto out; } /* check check bytes */ if ((r = sshbuf_get_u32(decrypted, &check1)) != 0 || (r = sshbuf_get_u32(decrypted, &check2)) != 0) goto out; if (check1 != check2) { r = SSH_ERR_KEY_WRONG_PASSPHRASE; goto out; } /* Load the private key and comment */ if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 || (r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0) goto out; /* Check deterministic padding */ i = 0; while (sshbuf_len(decrypted)) { if ((r = sshbuf_get_u8(decrypted, &pad)) != 0) goto out; if (pad != (++i & 0xff)) { r = SSH_ERR_INVALID_FORMAT; goto out; } } /* XXX decode pubkey and check against private */ /* success */ r = 0; if (keyp != NULL) { *keyp = k; k = NULL; } if (commentp != NULL) { *commentp = comment; comment = NULL; } out: pad = 0; cipher_cleanup(&ciphercontext); free(ciphername); free(kdfname); free(comment); if (salt != NULL) { explicit_bzero(salt, slen); free(salt); } if (key != NULL) { explicit_bzero(key, keylen + ivlen); free(key); } sshbuf_free(encoded); sshbuf_free(decoded); sshbuf_free(kdf); sshbuf_free(decrypted); sshkey_free(k); return r; } #if WITH_SSH1 /* * Serialises the authentication (private) key to a blob, encrypting it with * passphrase. The identification of the blob (lowest 64 bits of n) will * precede the key to provide identification of the key without needing a * passphrase. */ static int sshkey_private_rsa1_to_blob(struct sshkey *key, struct sshbuf *blob, const char *passphrase, const char *comment) { struct sshbuf *buffer = NULL, *encrypted = NULL; u_char buf[8]; int r, cipher_num; struct sshcipher_ctx ciphercontext; const struct sshcipher *cipher; u_char *cp; /* * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting * to another cipher; otherwise use SSH_AUTHFILE_CIPHER. */ cipher_num = (strcmp(passphrase, "") == 0) ? SSH_CIPHER_NONE : SSH_CIPHER_3DES; if ((cipher = cipher_by_number(cipher_num)) == NULL) return SSH_ERR_INTERNAL_ERROR; /* This buffer is used to build the secret part of the private key. */ if ((buffer = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; /* Put checkbytes for checking passphrase validity. */ if ((r = sshbuf_reserve(buffer, 4, &cp)) != 0) goto out; arc4random_buf(cp, 2); memcpy(cp + 2, cp, 2); /* * Store the private key (n and e will not be stored because they * will be stored in plain text, and storing them also in encrypted * format would just give known plaintext). * Note: q and p are stored in reverse order to SSL. */ if ((r = sshbuf_put_bignum1(buffer, key->rsa->d)) != 0 || (r = sshbuf_put_bignum1(buffer, key->rsa->iqmp)) != 0 || (r = sshbuf_put_bignum1(buffer, key->rsa->q)) != 0 || (r = sshbuf_put_bignum1(buffer, key->rsa->p)) != 0) goto out; /* Pad the part to be encrypted to a size that is a multiple of 8. */ explicit_bzero(buf, 8); if ((r = sshbuf_put(buffer, buf, 8 - (sshbuf_len(buffer) % 8))) != 0) goto out; /* This buffer will be used to contain the data in the file. */ if ((encrypted = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } /* First store keyfile id string. */ if ((r = sshbuf_put(encrypted, LEGACY_BEGIN, sizeof(LEGACY_BEGIN))) != 0) goto out; /* Store cipher type and "reserved" field. */ if ((r = sshbuf_put_u8(encrypted, cipher_num)) != 0 || (r = sshbuf_put_u32(encrypted, 0)) != 0) goto out; /* Store public key. This will be in plain text. */ if ((r = sshbuf_put_u32(encrypted, BN_num_bits(key->rsa->n))) != 0 || (r = sshbuf_put_bignum1(encrypted, key->rsa->n) != 0) || (r = sshbuf_put_bignum1(encrypted, key->rsa->e) != 0) || (r = sshbuf_put_cstring(encrypted, comment) != 0)) goto out; /* Allocate space for the private part of the key in the buffer. */ if ((r = sshbuf_reserve(encrypted, sshbuf_len(buffer), &cp)) != 0) goto out; if ((r = cipher_set_key_string(&ciphercontext, cipher, passphrase, CIPHER_ENCRYPT)) != 0) goto out; if ((r = cipher_crypt(&ciphercontext, 0, cp, sshbuf_ptr(buffer), sshbuf_len(buffer), 0, 0)) != 0) goto out; if ((r = cipher_cleanup(&ciphercontext)) != 0) goto out; r = sshbuf_putb(blob, encrypted); out: explicit_bzero(&ciphercontext, sizeof(ciphercontext)); explicit_bzero(buf, sizeof(buf)); if (buffer != NULL) sshbuf_free(buffer); if (encrypted != NULL) sshbuf_free(encrypted); return r; } #endif /* WITH_SSH1 */ #ifdef WITH_OPENSSL /* convert SSH v2 key in OpenSSL PEM format */ static int sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *blob, const char *_passphrase, const char *comment) { int success, r; int blen, len = strlen(_passphrase); u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; #if (OPENSSL_VERSION_NUMBER < 0x00907000L) const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; #else const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; #endif const u_char *bptr; BIO *bio = NULL; if (len > 0 && len <= 4) return SSH_ERR_PASSPHRASE_TOO_SHORT; if ((bio = BIO_new(BIO_s_mem())) == NULL) return SSH_ERR_ALLOC_FAIL; switch (key->type) { case KEY_DSA: success = PEM_write_bio_DSAPrivateKey(bio, key->dsa, cipher, passphrase, len, NULL, NULL); break; #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa, cipher, passphrase, len, NULL, NULL); break; #endif case KEY_RSA: success = PEM_write_bio_RSAPrivateKey(bio, key->rsa, cipher, passphrase, len, NULL, NULL); break; default: success = 0; break; } if (success == 0) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) { r = SSH_ERR_INTERNAL_ERROR; goto out; } if ((r = sshbuf_put(blob, bptr, blen)) != 0) goto out; r = 0; out: BIO_free(bio); return r; } #endif /* WITH_OPENSSL */ /* Serialise "key" to buffer "blob" */ int sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob, const char *passphrase, const char *comment, int force_new_format, const char *new_format_cipher, int new_format_rounds) { switch (key->type) { #ifdef WITH_SSH1 case KEY_RSA1: return sshkey_private_rsa1_to_blob(key, blob, passphrase, comment); #endif /* WITH_SSH1 */ #ifdef WITH_OPENSSL case KEY_DSA: case KEY_ECDSA: case KEY_RSA: if (force_new_format) { return sshkey_private_to_blob2(key, blob, passphrase, comment, new_format_cipher, new_format_rounds); } return sshkey_private_pem_to_blob(key, blob, passphrase, comment); #endif /* WITH_OPENSSL */ case KEY_ED25519: return sshkey_private_to_blob2(key, blob, passphrase, comment, new_format_cipher, new_format_rounds); default: return SSH_ERR_KEY_TYPE_UNKNOWN; } } #ifdef WITH_SSH1 /* * Parse the public, unencrypted portion of a RSA1 key. */ int sshkey_parse_public_rsa1_fileblob(struct sshbuf *blob, struct sshkey **keyp, char **commentp) { int r; struct sshkey *pub = NULL; struct sshbuf *copy = NULL; if (keyp != NULL) *keyp = NULL; if (commentp != NULL) *commentp = NULL; /* Check that it is at least big enough to contain the ID string. */ if (sshbuf_len(blob) < sizeof(LEGACY_BEGIN)) return SSH_ERR_INVALID_FORMAT; /* * Make sure it begins with the id string. Consume the id string * from the buffer. */ if (memcmp(sshbuf_ptr(blob), LEGACY_BEGIN, sizeof(LEGACY_BEGIN)) != 0) return SSH_ERR_INVALID_FORMAT; /* Make a working copy of the keyblob and skip past the magic */ if ((copy = sshbuf_fromb(blob)) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshbuf_consume(copy, sizeof(LEGACY_BEGIN))) != 0) goto out; /* Skip cipher type, reserved data and key bits. */ if ((r = sshbuf_get_u8(copy, NULL)) != 0 || /* cipher type */ (r = sshbuf_get_u32(copy, NULL)) != 0 || /* reserved */ (r = sshbuf_get_u32(copy, NULL)) != 0) /* key bits */ goto out; /* Read the public key from the buffer. */ if ((pub = sshkey_new(KEY_RSA1)) == NULL || (r = sshbuf_get_bignum1(copy, pub->rsa->n)) != 0 || (r = sshbuf_get_bignum1(copy, pub->rsa->e)) != 0) goto out; /* Finally, the comment */ if ((r = sshbuf_get_string(copy, (u_char**)commentp, NULL)) != 0) goto out; /* The encrypted private part is not parsed by this function. */ r = 0; if (keyp != NULL) *keyp = pub; else sshkey_free(pub); pub = NULL; out: if (copy != NULL) sshbuf_free(copy); if (pub != NULL) sshkey_free(pub); return r; } static int sshkey_parse_private_rsa1(struct sshbuf *blob, const char *passphrase, struct sshkey **keyp, char **commentp) { int r; u_int16_t check1, check2; u_int8_t cipher_type; struct sshbuf *decrypted = NULL, *copy = NULL; u_char *cp; char *comment = NULL; struct sshcipher_ctx ciphercontext; const struct sshcipher *cipher; struct sshkey *prv = NULL; *keyp = NULL; if (commentp != NULL) *commentp = NULL; /* Check that it is at least big enough to contain the ID string. */ if (sshbuf_len(blob) < sizeof(LEGACY_BEGIN)) return SSH_ERR_INVALID_FORMAT; /* * Make sure it begins with the id string. Consume the id string * from the buffer. */ if (memcmp(sshbuf_ptr(blob), LEGACY_BEGIN, sizeof(LEGACY_BEGIN)) != 0) return SSH_ERR_INVALID_FORMAT; if ((prv = sshkey_new_private(KEY_RSA1)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((copy = sshbuf_fromb(blob)) == NULL || (decrypted = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = sshbuf_consume(copy, sizeof(LEGACY_BEGIN))) != 0) goto out; /* Read cipher type. */ if ((r = sshbuf_get_u8(copy, &cipher_type)) != 0 || (r = sshbuf_get_u32(copy, NULL)) != 0) /* reserved */ goto out; /* Read the public key and comment from the buffer. */ if ((r = sshbuf_get_u32(copy, NULL)) != 0 || /* key bits */ (r = sshbuf_get_bignum1(copy, prv->rsa->n)) != 0 || (r = sshbuf_get_bignum1(copy, prv->rsa->e)) != 0 || (r = sshbuf_get_cstring(copy, &comment, NULL)) != 0) goto out; /* Check that it is a supported cipher. */ cipher = cipher_by_number(cipher_type); if (cipher == NULL) { r = SSH_ERR_KEY_UNKNOWN_CIPHER; goto out; } /* Initialize space for decrypted data. */ if ((r = sshbuf_reserve(decrypted, sshbuf_len(copy), &cp)) != 0) goto out; /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ if ((r = cipher_set_key_string(&ciphercontext, cipher, passphrase, CIPHER_DECRYPT)) != 0) goto out; if ((r = cipher_crypt(&ciphercontext, 0, cp, sshbuf_ptr(copy), sshbuf_len(copy), 0, 0)) != 0) { cipher_cleanup(&ciphercontext); goto out; } if ((r = cipher_cleanup(&ciphercontext)) != 0) goto out; if ((r = sshbuf_get_u16(decrypted, &check1)) != 0 || (r = sshbuf_get_u16(decrypted, &check2)) != 0) goto out; if (check1 != check2) { r = SSH_ERR_KEY_WRONG_PASSPHRASE; goto out; } /* Read the rest of the private key. */ if ((r = sshbuf_get_bignum1(decrypted, prv->rsa->d)) != 0 || (r = sshbuf_get_bignum1(decrypted, prv->rsa->iqmp)) != 0 || (r = sshbuf_get_bignum1(decrypted, prv->rsa->q)) != 0 || (r = sshbuf_get_bignum1(decrypted, prv->rsa->p)) != 0) goto out; /* calculate p-1 and q-1 */ if ((r = rsa_generate_additional_parameters(prv->rsa)) != 0) goto out; /* enable blinding */ if (RSA_blinding_on(prv->rsa, NULL) != 1) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } r = 0; *keyp = prv; prv = NULL; if (commentp != NULL) { *commentp = comment; comment = NULL; } out: explicit_bzero(&ciphercontext, sizeof(ciphercontext)); if (comment != NULL) free(comment); if (prv != NULL) sshkey_free(prv); if (copy != NULL) sshbuf_free(copy); if (decrypted != NULL) sshbuf_free(decrypted); return r; } #endif /* WITH_SSH1 */ #ifdef WITH_OPENSSL static int sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, const char *passphrase, struct sshkey **keyp) { EVP_PKEY *pk = NULL; struct sshkey *prv = NULL; BIO *bio = NULL; int r; *keyp = NULL; if ((bio = BIO_new(BIO_s_mem())) == NULL || sshbuf_len(blob) > INT_MAX) return SSH_ERR_ALLOC_FAIL; if (BIO_write(bio, sshbuf_ptr(blob), sshbuf_len(blob)) != (int)sshbuf_len(blob)) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, (char *)passphrase)) == NULL) { r = SSH_ERR_KEY_WRONG_PASSPHRASE; goto out; } if (pk->type == EVP_PKEY_RSA && (type == KEY_UNSPEC || type == KEY_RSA)) { if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } prv->rsa = EVP_PKEY_get1_RSA(pk); prv->type = KEY_RSA; #ifdef DEBUG_PK RSA_print_fp(stderr, prv->rsa, 8); #endif if (RSA_blinding_on(prv->rsa, NULL) != 1) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } } else if (pk->type == EVP_PKEY_DSA && (type == KEY_UNSPEC || type == KEY_DSA)) { if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } prv->dsa = EVP_PKEY_get1_DSA(pk); prv->type = KEY_DSA; #ifdef DEBUG_PK DSA_print_fp(stderr, prv->dsa, 8); #endif #ifdef OPENSSL_HAS_ECC } else if (pk->type == EVP_PKEY_EC && (type == KEY_UNSPEC || type == KEY_ECDSA)) { if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk); prv->type = KEY_ECDSA; prv->ecdsa_nid = sshkey_ecdsa_key_to_nid(prv->ecdsa); if (prv->ecdsa_nid == -1 || sshkey_curve_nid_to_name(prv->ecdsa_nid) == NULL || sshkey_ec_validate_public(EC_KEY_get0_group(prv->ecdsa), EC_KEY_get0_public_key(prv->ecdsa)) != 0 || sshkey_ec_validate_private(prv->ecdsa) != 0) { r = SSH_ERR_INVALID_FORMAT; goto out; } # ifdef DEBUG_PK if (prv != NULL && prv->ecdsa != NULL) sshkey_dump_ec_key(prv->ecdsa); # endif #endif /* OPENSSL_HAS_ECC */ } else { r = SSH_ERR_INVALID_FORMAT; goto out; } r = 0; *keyp = prv; prv = NULL; out: BIO_free(bio); if (pk != NULL) EVP_PKEY_free(pk); if (prv != NULL) sshkey_free(prv); return r; } #endif /* WITH_OPENSSL */ int sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type, const char *passphrase, struct sshkey **keyp, char **commentp) { int r; *keyp = NULL; if (commentp != NULL) *commentp = NULL; switch (type) { #ifdef WITH_SSH1 case KEY_RSA1: return sshkey_parse_private_rsa1(blob, passphrase, keyp, commentp); #endif /* WITH_SSH1 */ #ifdef WITH_OPENSSL case KEY_DSA: case KEY_ECDSA: case KEY_RSA: return sshkey_parse_private_pem_fileblob(blob, type, passphrase, keyp); #endif /* WITH_OPENSSL */ case KEY_ED25519: return sshkey_parse_private2(blob, type, passphrase, keyp, commentp); case KEY_UNSPEC: if ((r = sshkey_parse_private2(blob, type, passphrase, keyp, commentp)) == 0) return 0; #ifdef WITH_OPENSSL return sshkey_parse_private_pem_fileblob(blob, type, passphrase, keyp); #else return SSH_ERR_INVALID_FORMAT; #endif /* WITH_OPENSSL */ default: return SSH_ERR_KEY_TYPE_UNKNOWN; } } int sshkey_parse_private_fileblob(struct sshbuf *buffer, const char *passphrase, const char *filename, struct sshkey **keyp, char **commentp) { int r; if (keyp != NULL) *keyp = NULL; if (commentp != NULL) *commentp = NULL; #ifdef WITH_SSH1 /* it's a SSH v1 key if the public key part is readable */ if ((r = sshkey_parse_public_rsa1_fileblob(buffer, NULL, NULL)) == 0) { return sshkey_parse_private_fileblob_type(buffer, KEY_RSA1, passphrase, keyp, commentp); } #endif /* WITH_SSH1 */ if ((r = sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC, passphrase, keyp, commentp)) == 0) return 0; return r; } Index: head/crypto/openssh/version.h =================================================================== --- head/crypto/openssh/version.h (revision 294495) +++ head/crypto/openssh/version.h (revision 294496) @@ -1,15 +1,15 @@ -/* $OpenBSD: version.h,v 1.74 2015/08/02 09:56:42 djm Exp $ */ +/* $OpenBSD: version.h,v 1.75 2015/08/21 03:45:26 djm Exp $ */ /* $FreeBSD$ */ -#define SSH_VERSION "OpenSSH_7.0" +#define SSH_VERSION "OpenSSH_7.1" -#define SSH_PORTABLE "p1" +#define SSH_PORTABLE "p2" #define SSH_RELEASE SSH_VERSION SSH_PORTABLE -#define SSH_VERSION_FREEBSD "FreeBSD-20160119" +#define SSH_VERSION_FREEBSD "FreeBSD-20160121" #ifdef WITH_OPENSSL #define OPENSSL_VERSION SSLeay_version(SSLEAY_VERSION) #else #define OPENSSL_VERSION "without OpenSSL" #endif Index: head/crypto/openssh =================================================================== --- head/crypto/openssh (revision 294495) +++ head/crypto/openssh (revision 294496) Property changes on: head/crypto/openssh ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /vendor-crypto/openssh/dist:r287158,294315