# # # patch "NEWS" # from [c250beffa9fecd94d00db49663e5003df8b1cfee] # to [7e6d551ae34801bc4b83d5caace9a3bf3365bbb6] # # patch "cmd_key_cert.cc" # from [fe9654113e9b63bb18c522de16c12426e7ee4e1d] # to [992b4e94b38c2ed75c0da7f2d50a70f90b7cd453] # # patch "database.cc" # from [27dd44bf7bef33308521db47e629700d050c0a8d] # to [4f6657888f951f1cb46c0ebb12ed8d349faad3d3] # # patch "file_io.cc" # from [f4da4a09b6bc7aafd0baa56609b0119c53b8fbac] # to [e5d92fb08e11877f33eff25ee7a0f719a168c4ae] # # patch "testlib.lua" # from [11466ecc001e65e8904099f698c18c2034d1183d] # to [ebf6812c6bf774e2bdd3ba494090d0418357408d] # # patch "tests/ssh_agent/__driver__.lua" # from [ab2aa35c08886878f31dcccd54f76e55e04a8bc5] # to [7ce418b605182f4e700c45da0df5f317172c67eb] # ============================================================ --- NEWS c250beffa9fecd94d00db49663e5003df8b1cfee +++ NEWS 7e6d551ae34801bc4b83d5caace9a3bf3365bbb6 @@ -27,6 +27,13 @@ to select() on the file handle, as recommended by the select_tut man page. + - If given a filename, `mtn ssh_agent_export' now creates that + file with the correct permissions (i.e. mode 600), creates + directories as necessary, and does not throw an internal + error if creation or writing fails. (You're still on your + own for directory creation and permissions if you take the + key on standard output and redirect it to a file.) + New features - The `mtn_automate' lua function now correctly parses and sets ============================================================ --- cmd_key_cert.cc fe9654113e9b63bb18c522de16c12426e7ee4e1d +++ cmd_key_cert.cc 992b4e94b38c2ed75c0da7f2d50a70f90b7cd453 @@ -10,13 +10,13 @@ #include "base.hh" #include #include -#include #include #include "charset.hh" #include "cmd.hh" #include "app_state.hh" #include "database.hh" +#include "file_io.hh" #include "project.hh" #include "keys.hh" #include "key_store.hh" @@ -28,7 +28,6 @@ using std::string; using std::ostringstream; using std::set; using std::string; -using std::ofstream; CMD(genkey, "genkey", "", CMD_REF(key_and_cert), N_("KEYID"), N_("Generates an RSA key-pair"), @@ -127,9 +126,12 @@ CMD(ssh_agent_export, "ssh_agent_export" keys.export_key_for_agent(id, cout); else { - string external_path = system_path(idx(args, 0)).as_external(); - ofstream fout(external_path.c_str(), ofstream::out); + ostringstream fout; keys.export_key_for_agent(id, fout); + data keydat(fout.str(), origin::system); + + system_path fname(idx(args, 0)); + write_data_userprivate(fname, keydat, fname.dirname()); } } ============================================================ --- database.cc 27dd44bf7bef33308521db47e629700d050c0a8d +++ database.cc 4f6657888f951f1cb46c0ebb12ed8d349faad3d3 @@ -70,7 +70,6 @@ using std::istream; using std::deque; using std::istream; -using std::ifstream; using std::make_pair; using std::map; using std::multimap; ============================================================ --- file_io.cc f4da4a09b6bc7aafd0baa56609b0119c53b8fbac +++ file_io.cc e5d92fb08e11877f33eff25ee7a0f719a168c4ae @@ -28,7 +28,6 @@ using std::ios_base; using std::cin; using std::ifstream; using std::ios_base; -using std::ofstream; using std::logic_error; using std::string; using std::vector; ============================================================ --- testlib.lua 11466ecc001e65e8904099f698c18c2034d1183d +++ testlib.lua ebf6812c6bf774e2bdd3ba494090d0418357408d @@ -859,8 +859,9 @@ function run_tests(debugging, list_only, set_env(name,"C") end - -- no test suite should touch the user's ssh agent + -- no test suite should touch the user's ssh agent or display unset_env("SSH_AUTH_SOCK") + unset_env("DISPLAY") logfile = io.open(logname, "w") chdir(run_dir); ============================================================ --- tests/ssh_agent/__driver__.lua ab2aa35c08886878f31dcccd54f76e55e04a8bc5 +++ tests/ssh_agent/__driver__.lua 7ce418b605182f4e700c45da0df5f317172c67eb @@ -26,6 +26,9 @@ check(mtn("ssh_agent_export"), 0, false, -- * (ok) export monotone key with passphrase check(mtn("ssh_agent_export"), 0, false, false, tkey .. "\n" .. tkey .. "\n") +-- * (ok) export monotone key without passphrase +check(mtn("ssh_agent_export"), 0, false, false) + -- * (ok) export in workspace exports to subdir mkdir("subdir") mkdir("subdir/anotherdir") @@ -36,25 +39,36 @@ check(mtn("ssh_agent_export", "id_monoto check(mtn("add", "-R", "anotherdir"), 0, false, false) check(mtn("ssh_agent_export", "id_monotone"), 0, false, false) -skip_if(not existsonpath("chmod")) -check({"chmod", "600", "id_monotone"}, 0, false, false) +check(exists("id_monotone")) chdir("..") +check(not exists("id_monotone")) ---commit() ---rev = base_revision() --- ---check(mtn("checkout", "--revision", rev, "codir"), 0, false, false) ---check(samefile("subdir/foo", "codir/subdir/foo")) ---check(samefile("subdir/anotherdir/bar", "codir/subdir/anotherdir/bar")) +-- * (ok) export to subdirectory named on command line +check(mtn("ssh_agent_export", "subdir/id_monotone2"), 0, false, false) +check(exists("subdir/id_monotone2")) +check(not exists("id_monotone2")) +-- * (ok) export to path containing a nonexistent directory - creates it +check(not exists("nonexistent")) +check(mtn("ssh_agent_export", "nonexistent/id_monotone3"), 0, false, false) +check(exists("nonexistent/id_monotone3")) +check(not exists("id_monotone3")) --- * (ok) export monotone key without passphrase -check(mtn("ssh_agent_export", "id_monotone"), 0, false, false) +-- * (E) export to path that's not writable skip_if(not existsonpath("chmod")) -check({"chmod", "600", "id_monotone"}, 0, false, false) +mkdir("unwritable") +check({"chmod", "555", "unwritable"}, 0, false, false) +check(mtn("ssh_agent_export", "unwritable/id_monotone4"), 1, false, false) +check(not exists("unwritable/id_monotone3")) +check(not exists("id_monotone3")) + +-- set up for tests of the agent itself +-- we don't know how to do this on windows + +skip_if(ostype == "Windows") skip_if(not existsonpath("ssh-agent")) -skip_if(ostype == "Windows") +skip_if(not existsonpath("ssh-add")) function cleanup() check({"kill", os.getenv("SSH_AGENT_PID")}, 0, false, false) @@ -149,8 +163,6 @@ end end end -skip_if(not existsonpath("ssh-add")) - -- * (ok) mtn ci with ssh-agent running with non-monotone rsa key check(get("id_rsa")) check({"chmod", "600", "id_rsa"}, 0, false, false) @@ -176,11 +188,51 @@ check(mtn("ci", "--message", "commit msg check(mtn("ci", "--message", "commit msg"), 0, false, false) -- * (ok) export key with password -check(mtn("ssh_agent_export", "id_monotone_pass"), 0, false, false, "\npass\npass\n") -skip_if(not existsonpath("chmod")) -check({"chmod", "600", "id_monotone_pass"}, 0, false, false) +check(mtn("ssh_agent_export", "id_monotone_pass"), 0, false, false, + "pass\npass\n") +-- without any password, or the wrong password, ssh-add should not add +-- this key; the DISPLAY/SSH_ASKPASS subterfuge is necessary to get +-- ssh-add to read the password from somewhere other than /dev/tty. +save_env() +set_env("DISPLAY", "not-a-real-display") +set_env("SSH_ASKPASS", "report_pass") + +check({"ssh-add", "-D"}, 0, false, false) + +-- * (E) no password at all +writefile("report_pass", "#!/bin/sh\nexit 0") +check({"chmod", "700", "report_pass"}, 0, false, false) +check({"ssh-add", "id_monotone_pass"}, 1, false, false) + +-- * (E) wrong password (note that ssh-add will retry indefinitely as long +-- as ssh-askpass keeps giving it (success, wrong password)) +writefile("report_pass", + "#!/bin/sh\n".. + "if [ -f report_pass_retried ]; then\n".. + " exit 1\n".. + "else\n".. + " echo notpass\n".. + " touch report_pass_retried\n".. + " exit 0\n".. + "fi\n") +check({"chmod", "700", "report_pass"}, 0, false, false) +check({"ssh-add", "id_monotone_pass"}, 1, false, false) + +-- * (ok) correct password +writefile("report_pass", "#!/bin/sh\necho pass\nexit 0") +check({"chmod", "700", "report_pass"}, 0, false, false) +check({"ssh-add", "id_monotone_pass"}, 0, false, false) + +restore_env() + +-- * (E) export key with mismatched passwords +check(mtn("ssh_agent_export", "id_mismatched_pass"), 1, false, false, + "this\nthat\nthis\nthat\nthis\nthat") +check(not exists("id_mismatched_pass")) + -- * (ok) add password-less exported key with ssh-add +check(mtn("ssh_agent_export", "id_monotone"), 0, false, false) check({"ssh-add", "-D"}, 0, false, false) check({"ssh-add", "id_monotone"}, 0, false, false) @@ -224,8 +276,6 @@ check(mtn("ssh_agent_export", "--key", " -- * (ok) export monotone key with -k check(mtn("ssh_agent_export", "--key", "address@hidden", "id_monotone2"), 0, false, false) -skip_if(not existsonpath("chmod")) -check({"chmod", "600", "id_monotone2"}, 0, false, false) -- * (ok) mtn ssh_agent_add with -k adds key to agent check({"ssh-add", "-D"}, 0, false, false)