From ed9ca11a8dc24bed5f8e69e2a62169e7a484d8fb Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Thu, 6 Mar 2014 21:22:57 +0100 Subject: enable large file support this should make some tests for LFS happy; we don't use sizes of or offsets in files here --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 378c33d..1ed7804 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,7 @@ CXXFLAGS ?= -g -O2 -Wall -Wold-style-cast +CPPFLAGS += -D_FILE_OFFSET_BITS=64 CXXFLAGS += -std=c++11 LDLIBS = -lstdc++ -lboost_program_options -lboost_filesystem -lboost_system -lboost_iostreams -lnettle -- cgit v1.2.3 From f4343c2060ea70639dfc7c9a5eeb70f0b5ec5697 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Sat, 22 Mar 2014 22:34:35 +0100 Subject: tab align auth_data_ssh dissection for readability --- ssh-agent-filter.C | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ssh-agent-filter.C b/ssh-agent-filter.C index 8ee6aaf..d1ccf2c 100644 --- a/ssh-agent-filter.C +++ b/ssh-agent-filter.C @@ -302,14 +302,14 @@ bool dissect_auth_data_ssh (rfc4251string const & data, std::string & request_de datastream.exceptions(std::ios::badbit | std::ios::failbit); // Format specified in RFC 4252 Section 7 - rfc4251string session_identifier; datastream >> session_identifier; - rfc4251byte requesttype; datastream >> requesttype; - rfc4251string username; datastream >> username; - rfc4251string servicename; datastream >> servicename; - rfc4251string publickeystring; datastream >> publickeystring; - rfc4251bool shouldbetrue; datastream >> shouldbetrue; - rfc4251string publickeyalgorithm; datastream >> publickeyalgorithm; - rfc4251string publickey; datastream >> publickey; + rfc4251string session_identifier; datastream >> session_identifier; + rfc4251byte requesttype; datastream >> requesttype; + rfc4251string username; datastream >> username; + rfc4251string servicename; datastream >> servicename; + rfc4251string publickeystring; datastream >> publickeystring; + rfc4251bool shouldbetrue; datastream >> shouldbetrue; + rfc4251string publickeyalgorithm; datastream >> publickeyalgorithm; + rfc4251string publickey; datastream >> publickey; request_description = "The request is for an ssh connection as user '" + std::string{username} + "' with service name '" + std::string{servicename} + "'."; -- cgit v1.2.3 From 7d0f47c171b716b7e138157f8165ebf790227582 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Sun, 23 Mar 2014 23:40:49 +0100 Subject: rfc4251string: add more operators this adds <= > >= != --- rfc4251.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rfc4251.h b/rfc4251.h index b2f9658..74bdc34 100644 --- a/rfc4251.h +++ b/rfc4251.h @@ -35,6 +35,7 @@ #include #include // ntohl() / htonl() #include +#include struct rfc4251byte { union { @@ -136,7 +137,7 @@ inline std::ostream & operator<< (std::ostream & os, rfc4251uint64 const & x) { } -struct rfc4251string { +struct rfc4251string : boost::totally_ordered { std::vector value; rfc4251string () = default; -- cgit v1.2.3 From 26b246ac93d59a7f7ba29cff36ad1a3e61306a58 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Mon, 14 Apr 2014 21:08:54 +0200 Subject: cosmetic: fix double semicolons --- rfc4251.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rfc4251.h b/rfc4251.h index 74bdc34..98734bf 100644 --- a/rfc4251.h +++ b/rfc4251.h @@ -54,7 +54,7 @@ inline std::istream & operator>> (std::istream & is, rfc4251byte & x) { } inline std::ostream & operator<< (std::ostream & os, rfc4251byte const & x) { - return os.write(x.buf, sizeof(x.buf));; + return os.write(x.buf, sizeof(x.buf)); } @@ -75,7 +75,7 @@ inline std::istream & operator>> (std::istream & is, rfc4251bool & x) { } inline std::ostream & operator<< (std::ostream & os, rfc4251bool const & x) { - return os.write(x.buf, sizeof(x.buf));; + return os.write(x.buf, sizeof(x.buf)); } @@ -96,7 +96,7 @@ inline std::istream & operator>> (std::istream & is, rfc4251uint32 & x) { } inline std::ostream & operator<< (std::ostream & os, rfc4251uint32 const & x) { - return os.write(x.buf, sizeof(x.buf));; + return os.write(x.buf, sizeof(x.buf)); } @@ -133,7 +133,7 @@ inline std::istream & operator>> (std::istream & is, rfc4251uint64 & x) { } inline std::ostream & operator<< (std::ostream & os, rfc4251uint64 const & x) { - return os.write(x.buf, sizeof(x.buf));; + return os.write(x.buf, sizeof(x.buf)); } -- cgit v1.2.3 From ca4c9a28590919b6c0fc49cefdaf967758d5e4a0 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Mon, 14 Apr 2014 21:10:11 +0200 Subject: do clean exit after receiving signal --- ssh-agent-filter.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssh-agent-filter.C b/ssh-agent-filter.C index d1ccf2c..46d9f94 100644 --- a/ssh-agent-filter.C +++ b/ssh-agent-filter.C @@ -446,7 +446,7 @@ void sighandler (int sig) { break; default: remove(path); - std::abort(); + std::exit(0); } } -- cgit v1.2.3 From afc8cbf6fad71317ee11b6e6374f8f3ce4816197 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Mon, 14 Apr 2014 21:38:45 +0200 Subject: rfc4251*: add constructors from std::istream and use them --- rfc4251.h | 21 +++++++++++++++++ ssh-agent-filter.C | 67 +++++++++++++++++++++--------------------------------- 2 files changed, 47 insertions(+), 41 deletions(-) diff --git a/rfc4251.h b/rfc4251.h index 98734bf..2d01215 100644 --- a/rfc4251.h +++ b/rfc4251.h @@ -45,6 +45,7 @@ struct rfc4251byte { rfc4251byte () = default; explicit rfc4251byte (uint8_t v) : value(v) {} + inline explicit rfc4251byte (std::istream &); operator uint8_t () const { return value; } }; @@ -57,6 +58,9 @@ inline std::ostream & operator<< (std::ostream & os, rfc4251byte const & x) { return os.write(x.buf, sizeof(x.buf)); } +inline rfc4251byte::rfc4251byte (std::istream & is) { + is >> *this; +} struct rfc4251bool { union { @@ -66,6 +70,7 @@ struct rfc4251bool { rfc4251bool () = default; explicit rfc4251bool (uint8_t v) : value(v) {} + inline explicit rfc4251bool (std::istream &); operator uint8_t () const { return value; } }; @@ -78,6 +83,9 @@ inline std::ostream & operator<< (std::ostream & os, rfc4251bool const & x) { return os.write(x.buf, sizeof(x.buf)); } +inline rfc4251bool::rfc4251bool (std::istream & is) { + is >> *this; +} struct rfc4251uint32 { union { @@ -87,6 +95,7 @@ struct rfc4251uint32 { rfc4251uint32 () = default; explicit rfc4251uint32 (uint32_t v) { value = htonl(v); } + inline explicit rfc4251uint32 (std::istream &); operator uint32_t () const { return ntohl(value); } }; @@ -99,6 +108,9 @@ inline std::ostream & operator<< (std::ostream & os, rfc4251uint32 const & x) { return os.write(x.buf, sizeof(x.buf)); } +inline rfc4251uint32::rfc4251uint32 (std::istream & is) { + is >> *this; +} struct rfc4251uint64 { union { @@ -108,6 +120,7 @@ struct rfc4251uint64 { rfc4251uint64 () = default; inline explicit rfc4251uint64 (uint64_t v); + inline explicit rfc4251uint64 (std::istream &); inline explicit operator uint64_t () const; }; @@ -136,6 +149,9 @@ inline std::ostream & operator<< (std::ostream & os, rfc4251uint64 const & x) { return os.write(x.buf, sizeof(x.buf)); } +inline rfc4251uint64::rfc4251uint64 (std::istream & is) { + is >> *this; +} struct rfc4251string : boost::totally_ordered { std::vector value; @@ -147,6 +163,7 @@ struct rfc4251string : boost::totally_ordered { explicit rfc4251string (std::vector const &); explicit rfc4251string (mpz_srcptr); explicit rfc4251string (mpz_class const & x) : rfc4251string{x.get_mpz_t()} {} + inline explicit rfc4251string (std::istream &); operator std::string () const { return {value.begin(), value.end()}; } operator std::vector () const; @@ -213,6 +230,10 @@ inline std::ostream & operator<< (std::ostream & os, rfc4251string const & s) { return os; } +inline rfc4251string::rfc4251string (std::istream & is) { + is >> *this; +} + inline bool operator== (rfc4251string const & l, rfc4251string const & r) { return l.value == r.value; } diff --git a/ssh-agent-filter.C b/ssh-agent-filter.C index 46d9f94..17090e9 100644 --- a/ssh-agent-filter.C +++ b/ssh-agent-filter.C @@ -209,20 +209,15 @@ void setup_filters () { agent.exceptions(std::ios::badbit | std::ios::failbit); agent << rfc4251string{std::string{SSH2_AGENTC_REQUEST_IDENTITIES}}; - rfc4251string answer; - agent >> answer; - std::istringstream answer_iss{answer}; + std::istringstream answer_iss{rfc4251string{agent}}; answer_iss.exceptions(std::ios::badbit | std::ios::failbit); - rfc4251byte resp_code; - answer_iss >> resp_code; + rfc4251byte resp_code{answer_iss}; if (resp_code != SSH2_AGENT_IDENTITIES_ANSWER) throw std::runtime_error{"unexpected answer from ssh-agent"}; - rfc4251uint32 keycount; - answer_iss >> keycount; + rfc4251uint32 keycount{answer_iss}; for (uint32_t i = keycount; i; --i) { - rfc4251string key; - rfc4251string comment; - answer_iss >> key >> comment; + rfc4251string key{answer_iss}; + rfc4251string comment{answer_iss}; auto b64 = base64_encode(key); if (debug) std::clog << b64 << std::endl; @@ -302,14 +297,14 @@ bool dissect_auth_data_ssh (rfc4251string const & data, std::string & request_de datastream.exceptions(std::ios::badbit | std::ios::failbit); // Format specified in RFC 4252 Section 7 - rfc4251string session_identifier; datastream >> session_identifier; - rfc4251byte requesttype; datastream >> requesttype; - rfc4251string username; datastream >> username; - rfc4251string servicename; datastream >> servicename; - rfc4251string publickeystring; datastream >> publickeystring; - rfc4251bool shouldbetrue; datastream >> shouldbetrue; - rfc4251string publickeyalgorithm; datastream >> publickeyalgorithm; - rfc4251string publickey; datastream >> publickey; + rfc4251string session_identifier{datastream}; + rfc4251byte requesttype{datastream}; + rfc4251string username{datastream}; + rfc4251string servicename{datastream}; + rfc4251string publickeystring{datastream}; + rfc4251bool shouldbetrue{datastream}; + rfc4251string publickeyalgorithm{datastream}; + rfc4251string publickey{datastream}; request_description = "The request is for an ssh connection as user '" + std::string{username} + "' with service name '" + std::string{servicename} + "'."; @@ -323,31 +318,26 @@ rfc4251string handle_request (rfc4251string const & r) { std::ostringstream answer; request.exceptions(std::ios::badbit | std::ios::failbit); answer.exceptions(std::ios::badbit | std::ios::failbit); - rfc4251byte request_code; - request >> request_code; + rfc4251byte request_code{request}; switch (request_code) { case SSH2_AGENTC_REQUEST_IDENTITIES: { io::stream_buffer agent_filebuf{make_upstream_agent_conn(), io::close_handle}; std::iostream agent{&agent_filebuf}; agent.exceptions(std::ios::badbit | std::ios::failbit); - rfc4251string agent_answer; agent << rfc4251string{std::string{SSH2_AGENTC_REQUEST_IDENTITIES}}; - agent >> agent_answer; // temp to test key filtering when signing - //return agent_answer; - std::istringstream agent_answer_iss{agent_answer}; + //return rfc4251string{agent}; + std::istringstream agent_answer_iss{rfc4251string{agent}}; agent_answer_iss.exceptions(std::ios::badbit | std::ios::failbit); - rfc4251byte answer_code; - rfc4251uint32 keycount; - agent_answer_iss >> answer_code >> keycount; + rfc4251byte answer_code{agent_answer_iss}; + rfc4251uint32 keycount{agent_answer_iss}; if (answer_code != SSH2_AGENT_IDENTITIES_ANSWER) throw std::runtime_error{"unexpected answer from ssh-agent"}; std::vector> keys; for (uint32_t i = keycount; i; --i) { - rfc4251string key; - rfc4251string comment; - agent_answer_iss >> key >> comment; + rfc4251string key{agent_answer_iss}; + rfc4251string comment{agent_answer_iss}; if (allowed_pubkeys.count(key) or confirmed_pubkeys.count(key)) keys.emplace_back(std::move(key), std::move(comment)); } @@ -358,10 +348,9 @@ rfc4251string handle_request (rfc4251string const & r) { break; case SSH2_AGENTC_SIGN_REQUEST: { - rfc4251string key; - rfc4251string data; - rfc4251uint32 flags; - request >> key >> data >> flags; + rfc4251string key{request}; + rfc4251string data{request}; + rfc4251uint32 flags{request}; bool allow{false}; if (allowed_pubkeys.count(key)) @@ -392,8 +381,7 @@ rfc4251string handle_request (rfc4251string const & r) { rfc4251string agent_answer; agent << r; - agent >> agent_answer; - return agent_answer; + return rfc4251string{agent}; } else answer << rfc4251byte{SSH_AGENT_FAILURE}; } @@ -432,11 +420,8 @@ void handle_client (int const sock) try { std::iostream client{&client_filebuf}; client.exceptions(std::ios::badbit | std::ios::failbit); - for (;;) { - rfc4251string request; - client >> request; - client << handle_request(request) << std::flush; - } + for (;;) + client << handle_request(rfc4251string{client}) << std::flush; } catch (...) { } -- cgit v1.2.3 From ec5920ac2ed11b29135acb834ce6d633259aad75 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Tue, 15 Apr 2014 20:09:21 +0200 Subject: rfc4251: move remaining non-inline functions to impl file --- Makefile | 2 +- rfc4251.C | 32 ++++++++++++++++++++++++++++++++ rfc4251.h | 31 ------------------------------- 3 files changed, 33 insertions(+), 32 deletions(-) create mode 100644 rfc4251.C diff --git a/Makefile b/Makefile index 1ed7804..fcecbaa 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ ssh-agent-filter.1: ssh-agent-filter ssh-agent-filter: ssh-agent-filter.o ssh-agent-filter.o: ssh-agent-filter.C rfc4251.h ssh-agent.h version.h - +rfc4251.o: rfc4251.C rfc4251.h rfc4251_gmp.o: rfc4251_gmp.C rfc4251.h version.h: diff --git a/rfc4251.C b/rfc4251.C new file mode 100644 index 0000000..0d59420 --- /dev/null +++ b/rfc4251.C @@ -0,0 +1,32 @@ +#include "rfc4251.h" + +rfc4251string::rfc4251string (std::vector const & v) { + for (auto it = v.begin(); it != v.end();) { + if (it->size() == 0) + throw std::length_error{"name of zero length"}; + if (value.size() + it->size() > std::numeric_limits::max()) + throw std::length_error{"32-bit limit for rfc4251string exceeded"}; + value.insert(value.end(), it->data(), it->data() + it->size()); + ++it; + if (it == v.end()) + break; + value.push_back(','); + } +} + +rfc4251string::operator std::vector () const { + std::vector ret; + auto name_start = value.begin(); + if (name_start != value.end()) + for (auto it = name_start; ; ++it) { + if (it == value.end() or *it == ',') { + if (it == name_start) + throw std::length_error{"name of zero length"}; + ret.emplace_back(name_start, it); + name_start = it + 1; + } + if (it == value.end()) + break; + } + return ret; +} diff --git a/rfc4251.h b/rfc4251.h index 2d01215..e9b94f2 100644 --- a/rfc4251.h +++ b/rfc4251.h @@ -181,37 +181,6 @@ inline rfc4251string::rfc4251string (char const * s, size_t l) { value.insert(value.end(), s, s + l); } -rfc4251string::rfc4251string (std::vector const & v) { - for (auto it = v.begin(); it != v.end();) { - if (it->size() == 0) - throw std::length_error{"name of zero length"}; - if (value.size() + it->size() > std::numeric_limits::max()) - throw std::length_error{"32-bit limit for rfc4251string exceeded"}; - value.insert(value.end(), it->data(), it->data() + it->size()); - ++it; - if (it == v.end()) - break; - value.push_back(','); - } -} - -rfc4251string::operator std::vector () const { - std::vector ret; - auto name_start = value.begin(); - if (name_start != value.end()) - for (auto it = name_start; ; ++it) { - if (it == value.end() or *it == ',') { - if (it == name_start) - throw std::length_error{"name of zero length"}; - ret.emplace_back(name_start, it); - name_start = it + 1; - } - if (it == value.end()) - break; - } - return ret; -} - inline std::istream & operator>> (std::istream & is, rfc4251string & s) { s.value.clear(); rfc4251uint32 len; -- cgit v1.2.3 From 185d1b9525cb132bc802cdecbc6901ed30d58555 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Thu, 17 Apr 2014 21:30:27 +0200 Subject: rfc4251string: drop unused and dangerous constructor from just a pointer better use std::istringstream or boost::iostream::array_source --- rfc4251.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/rfc4251.h b/rfc4251.h index e9b94f2..876db07 100644 --- a/rfc4251.h +++ b/rfc4251.h @@ -157,7 +157,6 @@ struct rfc4251string : boost::totally_ordered { std::vector value; rfc4251string () = default; - inline explicit rfc4251string (char const *); inline explicit rfc4251string (char const *, size_t); explicit rfc4251string (std::string const & s) : rfc4251string{s.data(), s.size()} {} explicit rfc4251string (std::vector const &); @@ -170,11 +169,6 @@ struct rfc4251string : boost::totally_ordered { operator mpz_class () const; }; -inline rfc4251string::rfc4251string (char const * s) { - auto len = ntohl(*reinterpret_cast(s)); - value.insert(value.begin(), s + 4, s + 4 + len); -} - inline rfc4251string::rfc4251string (char const * s, size_t l) { if (l > std::numeric_limits::max()) throw std::length_error{"32-bit limit for rfc4251string exceeded"}; -- cgit v1.2.3 From a7f6e0c1d8553df678aa7b401eb374cf179210f7 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Fri, 18 Apr 2014 13:55:30 +0200 Subject: use a boost stream directly instead of declaring an intermediate stream_buffer --- ssh-agent-filter.C | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/ssh-agent-filter.C b/ssh-agent-filter.C index 17090e9..a7844f9 100644 --- a/ssh-agent-filter.C +++ b/ssh-agent-filter.C @@ -25,7 +25,7 @@ namespace po = boost::program_options; #include namespace fs = boost::filesystem; -#include +#include #include namespace io = boost::iostreams; @@ -204,8 +204,7 @@ void parse_cmdline (int const argc, char const * const * const argv) { } void setup_filters () { - io::stream_buffer agent_filebuf{make_upstream_agent_conn(), io::close_handle}; - std::iostream agent{&agent_filebuf}; + io::stream agent{make_upstream_agent_conn(), io::close_handle}; agent.exceptions(std::ios::badbit | std::ios::failbit); agent << rfc4251string{std::string{SSH2_AGENTC_REQUEST_IDENTITIES}}; @@ -322,8 +321,7 @@ rfc4251string handle_request (rfc4251string const & r) { switch (request_code) { case SSH2_AGENTC_REQUEST_IDENTITIES: { - io::stream_buffer agent_filebuf{make_upstream_agent_conn(), io::close_handle}; - std::iostream agent{&agent_filebuf}; + io::stream agent{make_upstream_agent_conn(), io::close_handle}; agent.exceptions(std::ios::badbit | std::ios::failbit); agent << rfc4251string{std::string{SSH2_AGENTC_REQUEST_IDENTITIES}}; // temp to test key filtering when signing @@ -375,8 +373,7 @@ rfc4251string handle_request (rfc4251string const & r) { } if (allow) { - io::stream_buffer agent_filebuf{make_upstream_agent_conn(), io::close_handle}; - std::iostream agent{&agent_filebuf}; + io::stream agent{make_upstream_agent_conn(), io::close_handle}; agent.exceptions(std::ios::badbit | std::ios::failbit); rfc4251string agent_answer; @@ -416,8 +413,7 @@ rfc4251string handle_request (rfc4251string const & r) { } void handle_client (int const sock) try { - io::stream_buffer client_filebuf{sock, io::close_handle}; - std::iostream client{&client_filebuf}; + io::stream client{sock, io::close_handle}; client.exceptions(std::ios::badbit | std::ios::failbit); for (;;) -- cgit v1.2.3 From a257a44837e78d283f1735b4685618c270aa54bc Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Sun, 20 Apr 2014 23:35:04 +0200 Subject: use boost::iostreams instead of std::stringstreams boost::iostreams::array_source instead of istringstream boost::iostreams::back_insert_device instead of ostringstream this should save at least one copy each and still has length checks (input) or dynamic growth (output) --- rfc4251.h | 4 ++++ ssh-agent-filter.C | 19 ++++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/rfc4251.h b/rfc4251.h index 876db07..3c291a2 100644 --- a/rfc4251.h +++ b/rfc4251.h @@ -164,6 +164,10 @@ struct rfc4251string : boost::totally_ordered { explicit rfc4251string (mpz_class const & x) : rfc4251string{x.get_mpz_t()} {} inline explicit rfc4251string (std::istream &); + size_t size () const { return value.size(); } + char const * data () const { return value.data(); } + char * data () { return value.data(); } + operator std::string () const { return {value.begin(), value.end()}; } operator std::vector () const; operator mpz_class () const; diff --git a/ssh-agent-filter.C b/ssh-agent-filter.C index a7844f9..ff28601 100644 --- a/ssh-agent-filter.C +++ b/ssh-agent-filter.C @@ -26,6 +26,8 @@ namespace po = boost::program_options; namespace fs = boost::filesystem; #include +#include +#include #include namespace io = boost::iostreams; @@ -33,7 +35,6 @@ namespace io = boost::iostreams; #include #include #include -#include #include #include @@ -208,7 +209,8 @@ void setup_filters () { agent.exceptions(std::ios::badbit | std::ios::failbit); agent << rfc4251string{std::string{SSH2_AGENTC_REQUEST_IDENTITIES}}; - std::istringstream answer_iss{rfc4251string{agent}}; + rfc4251string answer{agent}; + io::stream answer_iss{answer.data(), answer.size()}; answer_iss.exceptions(std::ios::badbit | std::ios::failbit); rfc4251byte resp_code{answer_iss}; if (resp_code != SSH2_AGENT_IDENTITIES_ANSWER) @@ -292,7 +294,7 @@ bool confirm (std::string const & question) { } bool dissect_auth_data_ssh (rfc4251string const & data, std::string & request_description) try { - std::istringstream datastream{data}; + io::stream datastream{data.data(), data.size()}; datastream.exceptions(std::ios::badbit | std::ios::failbit); // Format specified in RFC 4252 Section 7 @@ -313,8 +315,9 @@ bool dissect_auth_data_ssh (rfc4251string const & data, std::string & request_de } rfc4251string handle_request (rfc4251string const & r) { - std::istringstream request{r}; - std::ostringstream answer; + io::stream request{r.data(), r.size()}; + rfc4251string ret; + io::stream>> answer{ret.value}; request.exceptions(std::ios::badbit | std::ios::failbit); answer.exceptions(std::ios::badbit | std::ios::failbit); rfc4251byte request_code{request}; @@ -326,7 +329,8 @@ rfc4251string handle_request (rfc4251string const & r) { agent << rfc4251string{std::string{SSH2_AGENTC_REQUEST_IDENTITIES}}; // temp to test key filtering when signing //return rfc4251string{agent}; - std::istringstream agent_answer_iss{rfc4251string{agent}}; + rfc4251string agent_answer{agent}; + io::stream agent_answer_iss{agent_answer.data(), agent_answer.size()}; agent_answer_iss.exceptions(std::ios::badbit | std::ios::failbit); rfc4251byte answer_code{agent_answer_iss}; rfc4251uint32 keycount{agent_answer_iss}; @@ -409,7 +413,8 @@ rfc4251string handle_request (rfc4251string const & r) { break; } - return rfc4251string{answer.str()}; + answer << std::flush; + return ret; } void handle_client (int const sock) try { -- cgit v1.2.3 From b7d43361c44a214fa1b891fba7ea096650a6adca Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Wed, 7 May 2014 21:34:53 +0200 Subject: add more #include's, add using's for often-used names --- ssh-agent-filter.C | 131 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 75 insertions(+), 56 deletions(-) diff --git a/ssh-agent-filter.C b/ssh-agent-filter.C index ff28601..3307de8 100644 --- a/ssh-agent-filter.C +++ b/ssh-agent-filter.C @@ -32,10 +32,29 @@ namespace fs = boost::filesystem; namespace io = boost::iostreams; #include +using std::string; + #include +using std::vector; + #include +#include #include +using std::cout; +using std::clog; +using std::endl; +using std::flush; + #include +using std::runtime_error; + +#include +using std::pair; +using std::move; + +#include +using std::count; + #include #include @@ -59,21 +78,21 @@ namespace io = boost::iostreams; #define SOCK_CLOEXEC 0 #endif -std::vector allowed_b64; -std::vector allowed_md5; -std::vector allowed_comment; -std::vector confirmed_b64; -std::vector confirmed_md5; -std::vector confirmed_comment; +vector allowed_b64; +vector allowed_md5; +vector allowed_comment; +vector confirmed_b64; +vector confirmed_md5; +vector confirmed_comment; std::set allowed_pubkeys; -std::map confirmed_pubkeys; +std::map confirmed_pubkeys; bool debug{false}; bool all_confirmed{false}; -std::string saf_name; +string saf_name; fs::path path; -std::string md5_hex (std::string const & s) { +string md5_hex (string const & s) { struct md5_ctx ctx; md5_init(&ctx); md5_update(&ctx, s.size(), reinterpret_cast(s.data())); @@ -84,7 +103,7 @@ std::string md5_hex (std::string const & s) { return {reinterpret_cast(hex), sizeof(hex)}; } -std::string base64_encode (std::string const & s) { +string base64_encode (string const & s) { struct base64_encode_ctx ctx; base64_encode_init(&ctx); uint8_t b64[BASE64_ENCODE_LENGTH(s.size())]; @@ -99,7 +118,7 @@ int make_upstream_agent_conn () { struct sockaddr_un addr; if (!(path = getenv("SSH_AUTH_SOCK"))) { - std::clog << "no $SSH_AUTH_SOCK" << std::endl; + clog << "no $SSH_AUTH_SOCK" << endl; exit(EX_UNAVAILABLE); } @@ -115,7 +134,7 @@ int make_upstream_agent_conn () { addr.sun_family = AF_UNIX; if (strlen(path) >= sizeof(addr.sun_path)) { - std::clog << "$SSH_AUTH_SOCK too long" << std::endl; + clog << "$SSH_AUTH_SOCK too long" << endl; exit(EX_UNAVAILABLE); } @@ -145,7 +164,7 @@ int make_listen_sock () { addr.sun_family = AF_UNIX; if (path.native().length() >= sizeof(addr.sun_path)) { - std::clog << "path for listen socket too long" << std::endl; + clog << "path for listen socket too long" << endl; exit(EX_UNAVAILABLE); } @@ -184,13 +203,13 @@ void parse_cmdline (int const argc, char const * const * const argv) { notify(config); if (config.count("help")) { - std::cout << "Invocation: ssh-agent-filter [ OPTIONS ]" << std::endl; - std::cout << opts << std::endl; + cout << "Invocation: ssh-agent-filter [ OPTIONS ]" << endl; + cout << opts << endl; exit(EX_OK); } if (config.count("version")) { - std::cout << SSH_AGENT_FILTER_VERSION << std::endl; + cout << SSH_AGENT_FILTER_VERSION << endl; exit(EX_OK); } @@ -208,77 +227,77 @@ void setup_filters () { io::stream agent{make_upstream_agent_conn(), io::close_handle}; agent.exceptions(std::ios::badbit | std::ios::failbit); - agent << rfc4251string{std::string{SSH2_AGENTC_REQUEST_IDENTITIES}}; + agent << rfc4251string{string{SSH2_AGENTC_REQUEST_IDENTITIES}}; rfc4251string answer{agent}; io::stream answer_iss{answer.data(), answer.size()}; answer_iss.exceptions(std::ios::badbit | std::ios::failbit); rfc4251byte resp_code{answer_iss}; if (resp_code != SSH2_AGENT_IDENTITIES_ANSWER) - throw std::runtime_error{"unexpected answer from ssh-agent"}; + throw runtime_error{"unexpected answer from ssh-agent"}; rfc4251uint32 keycount{answer_iss}; for (uint32_t i = keycount; i; --i) { rfc4251string key{answer_iss}; rfc4251string comment{answer_iss}; auto b64 = base64_encode(key); - if (debug) std::clog << b64 << std::endl; + if (debug) clog << b64 << endl; auto md5 = md5_hex(key); - if (debug) std::clog << md5 << std::endl; + if (debug) clog << md5 << endl; - std::string comm(comment); - if (debug) std::clog << comm << std::endl; + string comm(comment); + if (debug) clog << comm << endl; bool allow{false}; - if (std::count(allowed_b64.begin(), allowed_b64.end(), b64)) { + if (count(allowed_b64.begin(), allowed_b64.end(), b64)) { allow = true; - if (debug) std::clog << "key allowed by equal base64 representation" << std::endl; + if (debug) clog << "key allowed by equal base64 representation" << endl; } - if (std::count(allowed_md5.begin(), allowed_md5.end(), md5)) { + if (count(allowed_md5.begin(), allowed_md5.end(), md5)) { allow = true; - if (debug) std::clog << "key allowed by matching md5 fingerprint" << std::endl; + if (debug) clog << "key allowed by matching md5 fingerprint" << endl; } - if (std::count(allowed_comment.begin(), allowed_comment.end(), comm)) { + if (count(allowed_comment.begin(), allowed_comment.end(), comm)) { allow = true; - if (debug) std::clog << "key allowed by matching comment" << std::endl; + if (debug) clog << "key allowed by matching comment" << endl; } - if (allow) allowed_pubkeys.emplace(std::move(key)); + if (allow) allowed_pubkeys.emplace(move(key)); else { bool confirm{false}; - if (std::count(confirmed_b64.begin(), confirmed_b64.end(), b64)) { + if (count(confirmed_b64.begin(), confirmed_b64.end(), b64)) { confirm = true; - if (debug) std::clog << "key allowed with confirmation by equal base64 representation" << std::endl; + if (debug) clog << "key allowed with confirmation by equal base64 representation" << endl; } - if (std::count(confirmed_md5.begin(), confirmed_md5.end(), md5)) { + if (count(confirmed_md5.begin(), confirmed_md5.end(), md5)) { confirm = true; - if (debug) std::clog << "key allowed with confirmation by matching md5 fingerprint" << std::endl; + if (debug) clog << "key allowed with confirmation by matching md5 fingerprint" << endl; } - if (std::count(confirmed_comment.begin(), confirmed_comment.end(), comm)) { + if (count(confirmed_comment.begin(), confirmed_comment.end(), comm)) { confirm = true; - if (debug) std::clog << "key allowed with confirmation by matching comment" << std::endl; + if (debug) clog << "key allowed with confirmation by matching comment" << endl; } if (all_confirmed) { confirm = true; - if (debug) std::clog << "key allowed with confirmation by catch-all (-A)" << std::endl; + if (debug) clog << "key allowed with confirmation by catch-all (-A)" << endl; } - if (confirm) confirmed_pubkeys.emplace(std::move(key), std::move(comm)); + if (confirm) confirmed_pubkeys.emplace(move(key), move(comm)); } - if (debug) std::clog << std::endl; + if (debug) clog << endl; } } -bool confirm (std::string const & question) { +bool confirm (string const & question) { char const * sap; if (!(sap = getenv("SSH_ASKPASS"))) sap = "ssh-askpass"; pid_t pid = fork(); if (pid < 0) - throw std::runtime_error("fork()"); + throw runtime_error("fork()"); if (pid == 0) { // child char const * args[3] = { sap, question.c_str(), nullptr }; @@ -293,7 +312,7 @@ bool confirm (std::string const & question) { } } -bool dissect_auth_data_ssh (rfc4251string const & data, std::string & request_description) try { +bool dissect_auth_data_ssh (rfc4251string const & data, string & request_description) try { io::stream datastream{data.data(), data.size()}; datastream.exceptions(std::ios::badbit | std::ios::failbit); @@ -307,7 +326,7 @@ bool dissect_auth_data_ssh (rfc4251string const & data, std::string & request_de rfc4251string publickeyalgorithm{datastream}; rfc4251string publickey{datastream}; - request_description = "The request is for an ssh connection as user '" + std::string{username} + "' with service name '" + std::string{servicename} + "'."; + request_description = "The request is for an ssh connection as user '" + string{username} + "' with service name '" + string{servicename} + "'."; return true; } catch (...) { @@ -317,7 +336,7 @@ bool dissect_auth_data_ssh (rfc4251string const & data, std::string & request_de rfc4251string handle_request (rfc4251string const & r) { io::stream request{r.data(), r.size()}; rfc4251string ret; - io::stream>> answer{ret.value}; + io::stream>> answer{ret.value}; request.exceptions(std::ios::badbit | std::ios::failbit); answer.exceptions(std::ios::badbit | std::ios::failbit); rfc4251byte request_code{request}; @@ -326,7 +345,7 @@ rfc4251string handle_request (rfc4251string const & r) { { io::stream agent{make_upstream_agent_conn(), io::close_handle}; agent.exceptions(std::ios::badbit | std::ios::failbit); - agent << rfc4251string{std::string{SSH2_AGENTC_REQUEST_IDENTITIES}}; + agent << rfc4251string{string{SSH2_AGENTC_REQUEST_IDENTITIES}}; // temp to test key filtering when signing //return rfc4251string{agent}; rfc4251string agent_answer{agent}; @@ -335,13 +354,13 @@ rfc4251string handle_request (rfc4251string const & r) { rfc4251byte answer_code{agent_answer_iss}; rfc4251uint32 keycount{agent_answer_iss}; if (answer_code != SSH2_AGENT_IDENTITIES_ANSWER) - throw std::runtime_error{"unexpected answer from ssh-agent"}; - std::vector> keys; + throw runtime_error{"unexpected answer from ssh-agent"}; + vector> keys; for (uint32_t i = keycount; i; --i) { rfc4251string key{agent_answer_iss}; rfc4251string comment{agent_answer_iss}; if (allowed_pubkeys.count(key) or confirmed_pubkeys.count(key)) - keys.emplace_back(std::move(key), std::move(comment)); + keys.emplace_back(move(key), move(comment)); } answer << answer_code << rfc4251uint32{static_cast(keys.size())}; for (auto const & k : keys) @@ -360,14 +379,14 @@ rfc4251string handle_request (rfc4251string const & r) { else { auto it = confirmed_pubkeys.find(key); if (it != confirmed_pubkeys.end()) { - std::string request_description; + string request_description; bool dissect_ok{false}; if (!dissect_ok) dissect_ok = dissect_auth_data_ssh(data, request_description); if (!dissect_ok) request_description = "The request format is unknown."; - std::string question = "Something behind the ssh-agent-filter"; + string question = "Something behind the ssh-agent-filter"; if (saf_name.length()) question += " named '" + saf_name + "'"; question += " requested use of the key named '" + it->second + "'.\n"; @@ -413,7 +432,7 @@ rfc4251string handle_request (rfc4251string const & r) { break; } - answer << std::flush; + answer << flush; return ret; } @@ -422,7 +441,7 @@ void handle_client (int const sock) try { client.exceptions(std::ios::badbit | std::ios::failbit); for (;;) - client << handle_request(rfc4251string{client}) << std::flush; + client << handle_request(rfc4251string{client}) << flush; } catch (...) { } @@ -451,9 +470,9 @@ int main (int const argc, char const * const * const argv) { exit(EX_OSERR); } if (pid > 0) { - std::cout << "SSH_AUTH_SOCK='" << path.native() << "'; export SSH_AUTH_SOCK;" << std::endl; - std::cout << "SSH_AGENT_PID='" << pid << "'; export SSH_AGENT_PID;" << std::endl; - std::cout << "echo 'Agent pid " << pid << "';" << std::endl; + cout << "SSH_AUTH_SOCK='" << path.native() << "'; export SSH_AUTH_SOCK;" << endl; + cout << "SSH_AGENT_PID='" << pid << "'; export SSH_AGENT_PID;" << endl; + cout << "echo 'Agent pid " << pid << "';" << endl; exit(EX_OK); } @@ -465,8 +484,8 @@ int main (int const argc, char const * const * const argv) { dup2(devnull, 2); close(devnull); } else { - std::cout << "copy this to another terminal:" << std::endl; - std::cout << "SSH_AUTH_SOCK='" << path.native() << "'; export SSH_AUTH_SOCK;" << std::endl; + cout << "copy this to another terminal:" << endl; + cout << "SSH_AUTH_SOCK='" << path.native() << "'; export SSH_AUTH_SOCK;" << endl; } signal(SIGINT, sighandler); -- cgit v1.2.3 From 823dba2ac91f84a4ae75372c5636ad49d6cef1ba Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Fri, 9 May 2014 21:42:10 +0200 Subject: factor out cloexec setting and stream exception arming --- ssh-agent-filter.C | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/ssh-agent-filter.C b/ssh-agent-filter.C index 3307de8..36677f9 100644 --- a/ssh-agent-filter.C +++ b/ssh-agent-filter.C @@ -112,6 +112,17 @@ string base64_encode (string const & s) { return {reinterpret_cast(b64), len}; } +void cloexec (int fd) { + if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC)) { + perror("fcntl"); + exit(EX_UNAVAILABLE); + } +} + +void arm(std::ios & stream) { + stream.exceptions(stream.badbit | stream.failbit); +} + int make_upstream_agent_conn () { char const * path; int sock; @@ -126,10 +137,7 @@ int make_upstream_agent_conn () { perror("socket"); exit(EX_UNAVAILABLE); } - if (fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC)) { - perror("fcntl"); - exit(EX_UNAVAILABLE); - } + cloexec(sock); addr.sun_family = AF_UNIX; @@ -156,10 +164,7 @@ int make_listen_sock () { perror("socket"); exit(EX_UNAVAILABLE); } - if (fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC)) { - perror("fcntl"); - exit(EX_UNAVAILABLE); - } + cloexec(sock); addr.sun_family = AF_UNIX; @@ -225,12 +230,12 @@ void parse_cmdline (int const argc, char const * const * const argv) { void setup_filters () { io::stream agent{make_upstream_agent_conn(), io::close_handle}; - agent.exceptions(std::ios::badbit | std::ios::failbit); + arm(agent); agent << rfc4251string{string{SSH2_AGENTC_REQUEST_IDENTITIES}}; rfc4251string answer{agent}; io::stream answer_iss{answer.data(), answer.size()}; - answer_iss.exceptions(std::ios::badbit | std::ios::failbit); + arm(answer_iss); rfc4251byte resp_code{answer_iss}; if (resp_code != SSH2_AGENT_IDENTITIES_ANSWER) throw runtime_error{"unexpected answer from ssh-agent"}; @@ -314,7 +319,7 @@ bool confirm (string const & question) { bool dissect_auth_data_ssh (rfc4251string const & data, string & request_description) try { io::stream datastream{data.data(), data.size()}; - datastream.exceptions(std::ios::badbit | std::ios::failbit); + arm(datastream); // Format specified in RFC 4252 Section 7 rfc4251string session_identifier{datastream}; @@ -337,20 +342,20 @@ rfc4251string handle_request (rfc4251string const & r) { io::stream request{r.data(), r.size()}; rfc4251string ret; io::stream>> answer{ret.value}; - request.exceptions(std::ios::badbit | std::ios::failbit); - answer.exceptions(std::ios::badbit | std::ios::failbit); + arm(request); + arm(answer); rfc4251byte request_code{request}; switch (request_code) { case SSH2_AGENTC_REQUEST_IDENTITIES: { io::stream agent{make_upstream_agent_conn(), io::close_handle}; - agent.exceptions(std::ios::badbit | std::ios::failbit); + arm(agent); agent << rfc4251string{string{SSH2_AGENTC_REQUEST_IDENTITIES}}; // temp to test key filtering when signing //return rfc4251string{agent}; rfc4251string agent_answer{agent}; io::stream agent_answer_iss{agent_answer.data(), agent_answer.size()}; - agent_answer_iss.exceptions(std::ios::badbit | std::ios::failbit); + arm(agent_answer_iss); rfc4251byte answer_code{agent_answer_iss}; rfc4251uint32 keycount{agent_answer_iss}; if (answer_code != SSH2_AGENT_IDENTITIES_ANSWER) @@ -397,7 +402,7 @@ rfc4251string handle_request (rfc4251string const & r) { if (allow) { io::stream agent{make_upstream_agent_conn(), io::close_handle}; - agent.exceptions(std::ios::badbit | std::ios::failbit); + arm(agent); rfc4251string agent_answer; agent << r; @@ -438,7 +443,7 @@ rfc4251string handle_request (rfc4251string const & r) { void handle_client (int const sock) try { io::stream client{sock, io::close_handle}; - client.exceptions(std::ios::badbit | std::ios::failbit); + arm(client); for (;;) client << handle_request(rfc4251string{client}) << flush; -- cgit v1.2.3 From 655b6084a5133d01a513c976b8b2567a71ba30c4 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Fri, 9 May 2014 22:21:52 +0200 Subject: throw system_error instead of calling perror, exit --- ssh-agent-filter.C | 50 ++++++++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/ssh-agent-filter.C b/ssh-agent-filter.C index 36677f9..e2777c7 100644 --- a/ssh-agent-filter.C +++ b/ssh-agent-filter.C @@ -48,6 +48,10 @@ using std::flush; #include using std::runtime_error; +#include +using std::system_error; +using std::system_category; + #include using std::pair; using std::move; @@ -57,6 +61,7 @@ using std::count; #include +#include #include #include #include @@ -113,10 +118,8 @@ string base64_encode (string const & s) { } void cloexec (int fd) { - if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC)) { - perror("fcntl"); - exit(EX_UNAVAILABLE); - } + if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC)) + throw system_error(errno, system_category(), "fcntl"); } void arm(std::ios & stream) { @@ -133,10 +136,8 @@ int make_upstream_agent_conn () { exit(EX_UNAVAILABLE); } - if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) { - perror("socket"); - exit(EX_UNAVAILABLE); - } + if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) + throw system_error(errno, system_category(), "socket"); cloexec(sock); addr.sun_family = AF_UNIX; @@ -148,10 +149,8 @@ int make_upstream_agent_conn () { strcpy(addr.sun_path, path); - if (connect(sock, reinterpret_cast(&addr), sizeof(addr))) { - perror("connect"); - exit(EX_UNAVAILABLE); - } + if (connect(sock, reinterpret_cast(&addr), sizeof(addr))) + throw system_error(errno, system_category(), "connect"); return sock; } @@ -160,10 +159,8 @@ int make_listen_sock () { int sock; struct sockaddr_un addr; - if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) { - perror("socket"); - exit(EX_UNAVAILABLE); - } + if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) + throw system_error(errno, system_category(), "socket"); cloexec(sock); addr.sun_family = AF_UNIX; @@ -175,15 +172,11 @@ int make_listen_sock () { strcpy(addr.sun_path, path.c_str()); - if (bind(sock, reinterpret_cast(&addr), sizeof(addr))) { - perror("bind"); - exit(EX_UNAVAILABLE); - } + if (bind(sock, reinterpret_cast(&addr), sizeof(addr))) + throw system_error(errno, system_category(), "bind"); - if (listen(sock, 0)) { - perror("listen"); - exit(EX_UNAVAILABLE); - } + if (listen(sock, 0)) + throw system_error(errno, system_category(), "listen"); return sock; } @@ -308,8 +301,7 @@ bool confirm (string const & question) { char const * args[3] = { sap, question.c_str(), nullptr }; // see execvp(3p) for cast rationale execvp(sap, const_cast(args)); - perror("exec"); - exit(EX_UNAVAILABLE); + throw system_error(errno, system_category(), "exec"); } else { // parent int status; @@ -470,10 +462,8 @@ int main (int const argc, char const * const * const argv) { if (not debug) { pid_t pid = fork(); - if (pid == -1) { - perror("fork"); - exit(EX_OSERR); - } + if (pid == -1) + throw system_error(errno, system_category(), "fork"); if (pid > 0) { cout << "SSH_AUTH_SOCK='" << path.native() << "'; export SSH_AUTH_SOCK;" << endl; cout << "SSH_AGENT_PID='" << pid << "'; export SSH_AGENT_PID;" << endl; -- cgit v1.2.3 From 38a60755c7fa8e90b08273c6f2a0563ffc433f75 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Sat, 10 May 2014 00:48:36 +0200 Subject: also replace custom fatal errors with exceptions --- ssh-agent-filter.C | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/ssh-agent-filter.C b/ssh-agent-filter.C index e2777c7..ed0d7a7 100644 --- a/ssh-agent-filter.C +++ b/ssh-agent-filter.C @@ -47,6 +47,8 @@ using std::flush; #include using std::runtime_error; +using std::length_error; +using std::invalid_argument; #include using std::system_error; @@ -131,10 +133,8 @@ int make_upstream_agent_conn () { int sock; struct sockaddr_un addr; - if (!(path = getenv("SSH_AUTH_SOCK"))) { - clog << "no $SSH_AUTH_SOCK" << endl; - exit(EX_UNAVAILABLE); - } + if (!(path = getenv("SSH_AUTH_SOCK"))) + throw invalid_argument("no $SSH_AUTH_SOCK"); if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) throw system_error(errno, system_category(), "socket"); @@ -142,10 +142,8 @@ int make_upstream_agent_conn () { addr.sun_family = AF_UNIX; - if (strlen(path) >= sizeof(addr.sun_path)) { - clog << "$SSH_AUTH_SOCK too long" << endl; - exit(EX_UNAVAILABLE); - } + if (strlen(path) >= sizeof(addr.sun_path)) + throw length_error("$SSH_AUTH_SOCK too long"); strcpy(addr.sun_path, path); @@ -165,10 +163,8 @@ int make_listen_sock () { addr.sun_family = AF_UNIX; - if (path.native().length() >= sizeof(addr.sun_path)) { - clog << "path for listen socket too long" << endl; - exit(EX_UNAVAILABLE); - } + if (path.native().length() >= sizeof(addr.sun_path)) + throw length_error("path for listen socket too long"); strcpy(addr.sun_path, path.c_str()); -- cgit v1.2.3 From 023a56e7d7483531219280af2e17760168cfaf7e Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Mon, 12 May 2014 21:39:42 +0200 Subject: use a mutex for fd creation and forks so we can have the CLOEXEC flag applied before a concurrent fork&exec. use select() to avoid blocking while holding the mutex. --- ssh-agent-filter.C | 50 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/ssh-agent-filter.C b/ssh-agent-filter.C index ed0d7a7..5aedb35 100644 --- a/ssh-agent-filter.C +++ b/ssh-agent-filter.C @@ -62,6 +62,9 @@ using std::move; using std::count; #include +#include +using std::mutex; +using std::lock_guard; #include #include @@ -70,6 +73,7 @@ using std::count; #include #include #include +#include #include #include #include @@ -97,6 +101,7 @@ bool debug{false}; bool all_confirmed{false}; string saf_name; fs::path path; +mutex fd_fork_mutex; string md5_hex (string const & s) { @@ -136,9 +141,12 @@ int make_upstream_agent_conn () { if (!(path = getenv("SSH_AUTH_SOCK"))) throw invalid_argument("no $SSH_AUTH_SOCK"); - if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) - throw system_error(errno, system_category(), "socket"); - cloexec(sock); + { + lock_guard lock{fd_fork_mutex}; + if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) + throw system_error(errno, system_category(), "socket"); + cloexec(sock); + } addr.sun_family = AF_UNIX; @@ -157,9 +165,15 @@ int make_listen_sock () { int sock; struct sockaddr_un addr; - if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) - throw system_error(errno, system_category(), "socket"); - cloexec(sock); + { + lock_guard lock{fd_fork_mutex}; + if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) + throw system_error(errno, system_category(), "socket"); + cloexec(sock); + } + + if (fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK)) + throw system_error(errno, system_category(), "fcntl"); addr.sun_family = AF_UNIX; @@ -289,7 +303,11 @@ bool confirm (string const & question) { char const * sap; if (!(sap = getenv("SSH_ASKPASS"))) sap = "ssh-askpass"; - pid_t pid = fork(); + pid_t pid; + { + lock_guard lock{fd_fork_mutex}; + pid = fork(); + } if (pid < 0) throw runtime_error("fork()"); if (pid == 0) { @@ -484,8 +502,22 @@ int main (int const argc, char const * const * const argv) { signal(SIGHUP, sighandler); signal(SIGTERM, sighandler); - int client_sock; - while ((client_sock = accept(listen_sock, nullptr, nullptr)) != -1) { + for (;;) { + fd_set fds; + FD_ZERO(&fds); + FD_SET(listen_sock, &fds); + select(listen_sock + 1, &fds, nullptr, nullptr, nullptr); + int client_sock; + { + lock_guard lock{fd_fork_mutex}; + if ((client_sock = accept(listen_sock, nullptr, nullptr)) == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + continue; + else + break; + } + cloexec(client_sock); + } std::thread t{handle_client, client_sock}; t.detach(); } -- cgit v1.2.3 From 5cc6f72612187001f70255f6097437381cf49bba Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Mon, 26 May 2014 20:41:08 +0200 Subject: rfc4251uint64: fix byte order conversion --- rfc4251.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfc4251.h b/rfc4251.h index 3c291a2..35f97fb 100644 --- a/rfc4251.h +++ b/rfc4251.h @@ -135,8 +135,8 @@ inline rfc4251uint64::rfc4251uint64 (uint64_t v) { inline rfc4251uint64::operator uint64_t () const { uint64_t ret{0}; for (uint_fast8_t i{0}; i < 8; ++i) { - ret |= buf[i]; ret <<= 8; + ret |= static_cast(buf[i]); } return ret; } -- cgit v1.2.3 From 4318a9a998f78f1d6ee4d32facd0fc8e1e231179 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Mon, 26 May 2014 23:36:33 +0200 Subject: add dissection of pam_ssh_agent_auth data --- ssh-agent-filter.C | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/ssh-agent-filter.C b/ssh-agent-filter.C index 5aedb35..7ac2687 100644 --- a/ssh-agent-filter.C +++ b/ssh-agent-filter.C @@ -66,6 +66,8 @@ using std::count; using std::mutex; using std::lock_guard; +#include + #include #include #include @@ -339,6 +341,55 @@ bool dissect_auth_data_ssh (rfc4251string const & data, string & request_descrip request_description = "The request is for an ssh connection as user '" + string{username} + "' with service name '" + string{servicename} + "'."; + if (string{servicename} == "pam_ssh_agent_auth") try { + clog << base64_encode(session_identifier) << endl; + io::stream idstream{session_identifier.data(), session_identifier.size()}; + arm(idstream); + + rfc4251uint32 type{idstream}; + if (type == 101) { + // PAM_SSH_AGENT_AUTH_REQUESTv1 + rfc4251string cookie{idstream}; + rfc4251string user{idstream}; + rfc4251string ruser{idstream}; + rfc4251string pam_service{idstream}; + rfc4251string pwd{idstream}; + rfc4251string action{idstream}; + rfc4251string hostname{idstream}; + rfc4251uint64 timestamp{idstream}; + + string singleuser{user}; + if (user != ruser) + singleuser += " (" + string{ruser} + ")"; + + string additional; + additional += "User '" + singleuser + "' wants to use '" + string{pam_service}; + additional += "' in '" + string{pwd}; + + io::stream actionstream{action.data(), action.size()}; + arm(actionstream); + + rfc4251uint32 argc{actionstream}; + + if (argc) { + additional += " to run"; + for (uint32_t i = argc; i; --i) { + rfc4251string argv{actionstream}; + additional += ' ' + string{argv}; + } + } + + additional += " on " + string{hostname} + ".\n"; + + auto now = std::chrono::system_clock::now(); + auto req_time = std::chrono::system_clock::from_time_t(static_cast(timestamp)); + auto timediff = std::chrono::duration_cast(now - req_time).count(); + + additional += "The request was generated " + std::to_string(timediff) + " seconds ago.\n"; + request_description = move(additional); + } + } catch (...) {} + return true; } catch (...) { return false; -- cgit v1.2.3 From 57f385d44cdc4eec0d0d2de7ea04ade6f4154dbf Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Tue, 27 May 2014 00:16:40 +0200 Subject: update copyright --- rfc4251.C | 24 ++++++++++++++++++++++++ rfc4251.h | 2 +- ssh-agent-filter.C | 2 +- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/rfc4251.C b/rfc4251.C index 0d59420..8ca5f2b 100644 --- a/rfc4251.C +++ b/rfc4251.C @@ -1,3 +1,27 @@ +/* + * rfc4251.C -- support for name-list type from RFC 4251, section 5 + * + * These are the conversions between an rfc4251string containing a name-list + * and vector. + * + * Copyright (C) 2013 Timo Weingärtner + * + * This file is part of ssh-agent-filter. + * + * ssh-agent-filter is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ssh-agent-filter is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ssh-agent-filter. If not, see . + */ + #include "rfc4251.h" rfc4251string::rfc4251string (std::vector const & v) { diff --git a/rfc4251.h b/rfc4251.h index 35f97fb..d9ac93e 100644 --- a/rfc4251.h +++ b/rfc4251.h @@ -10,7 +10,7 @@ * those structs contain the objects in their RFC 4251 representation, * conversions are provided via constructors and cast operators * - * Copyright (C) 2013 Timo Weingärtner + * Copyright (C) 2013-2014 Timo Weingärtner * * This file is part of ssh-agent-filter. * diff --git a/ssh-agent-filter.C b/ssh-agent-filter.C index 7ac2687..faa31f9 100644 --- a/ssh-agent-filter.C +++ b/ssh-agent-filter.C @@ -1,7 +1,7 @@ /* * ssh-agent-filter.C -- filtering proxy for ssh-agent meant to be forwarded to untrusted servers * - * Copyright (C) 2013 Timo Weingärtner + * Copyright (C) 2013-2014 Timo Weingärtner * * This file is part of ssh-agent-filter. * -- cgit v1.2.3 From d9ffc789b1c7e781acbdd8310aef871dc3a41c13 Mon Sep 17 00:00:00 2001 From: Timo Weingärtner Date: Mon, 26 May 2014 23:47:02 +0200 Subject: release 0.4 --- changelog | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ version.h | 2 +- 2 files changed, 126 insertions(+), 1 deletion(-) diff --git a/changelog b/changelog index f0e6f8e..57f7e7e 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,128 @@ +commit 4318a9a998f78f1d6ee4d32facd0fc8e1e231179 +Author: Timo Weingärtner +Date: 2014-05-26 23:36:33 +0200 + + add dissection of pam_ssh_agent_auth data + +commit 5cc6f72612187001f70255f6097437381cf49bba +Author: Timo Weingärtner +Date: 2014-05-26 20:41:08 +0200 + + rfc4251uint64: fix byte order conversion + +commit 023a56e7d7483531219280af2e17760168cfaf7e +Author: Timo Weingärtner +Date: 2014-05-12 21:39:42 +0200 + + use a mutex for fd creation and forks + + so we can have the CLOEXEC flag applied before a concurrent fork&exec. + use select() to avoid blocking while holding the mutex. + +commit 38a60755c7fa8e90b08273c6f2a0563ffc433f75 +Author: Timo Weingärtner +Date: 2014-05-10 00:48:36 +0200 + + also replace custom fatal errors with exceptions + +commit 655b6084a5133d01a513c976b8b2567a71ba30c4 +Author: Timo Weingärtner +Date: 2014-05-09 22:21:52 +0200 + + throw system_error instead of calling perror, exit + +commit 823dba2ac91f84a4ae75372c5636ad49d6cef1ba +Author: Timo Weingärtner +Date: 2014-05-09 21:42:10 +0200 + + factor out cloexec setting and stream exception arming + +commit b7d43361c44a214fa1b891fba7ea096650a6adca +Author: Timo Weingärtner +Date: 2014-05-07 21:34:53 +0200 + + add more #include's, add using's for often-used names + +commit a257a44837e78d283f1735b4685618c270aa54bc +Author: Timo Weingärtner +Date: 2014-04-20 23:35:04 +0200 + + use boost::iostreams instead of std::stringstreams + + boost::iostreams::array_source instead of istringstream + boost::iostreams::back_insert_device instead of ostringstream + + this should save at least one copy each and still has length checks (input) + or dynamic growth (output) + +commit a7f6e0c1d8553df678aa7b401eb374cf179210f7 +Author: Timo Weingärtner +Date: 2014-04-18 13:55:30 +0200 + + use a boost stream directly + + instead of declaring an intermediate stream_buffer + +commit 185d1b9525cb132bc802cdecbc6901ed30d58555 +Author: Timo Weingärtner +Date: 2014-04-17 21:30:27 +0200 + + rfc4251string: drop unused and dangerous constructor from just a pointer + + better use std::istringstream or boost::iostream::array_source + +commit ec5920ac2ed11b29135acb834ce6d633259aad75 +Author: Timo Weingärtner +Date: 2014-04-15 20:09:21 +0200 + + rfc4251: move remaining non-inline functions to impl file + +commit afc8cbf6fad71317ee11b6e6374f8f3ce4816197 +Author: Timo Weingärtner +Date: 2014-04-14 21:38:45 +0200 + + rfc4251*: add constructors from std::istream and use them + +commit ca4c9a28590919b6c0fc49cefdaf967758d5e4a0 +Author: Timo Weingärtner +Date: 2014-04-14 21:10:11 +0200 + + do clean exit after receiving signal + +commit 26b246ac93d59a7f7ba29cff36ad1a3e61306a58 +Author: Timo Weingärtner +Date: 2014-04-14 21:08:54 +0200 + + cosmetic: fix double semicolons + +commit 7d0f47c171b716b7e138157f8165ebf790227582 +Author: Timo Weingärtner +Date: 2014-03-23 23:40:49 +0100 + + rfc4251string: add more operators + + this adds <= > >= != + +commit f4343c2060ea70639dfc7c9a5eeb70f0b5ec5697 +Author: Timo Weingärtner +Date: 2014-03-22 22:34:35 +0100 + + tab align auth_data_ssh dissection for readability + +commit ed9ca11a8dc24bed5f8e69e2a62169e7a484d8fb +Author: Timo Weingärtner +Date: 2014-03-06 21:22:57 +0100 + + enable large file support + + this should make some tests for LFS happy; we don't use sizes of or offsets in files here + +commit 477a0a0f1507413be7a5d2882aba28d01f7e6111 (tag: 0.3.1) +Author: Timo Weingärtner +Date: 2013-12-19 15:47:43 +0100 + + release 0.3.1 + commit a8c1ef855655e7419e54317a8e782f3993d99f7d Author: Timo Weingärtner Date: 2013-11-13 23:42:46 +0100 diff --git a/version.h b/version.h index 9572eb4..70a2285 100644 --- a/version.h +++ b/version.h @@ -1 +1 @@ -#define SSH_AGENT_FILTER_VERSION "ssh-agent-filter 0.3.1" +#define SSH_AGENT_FILTER_VERSION "ssh-agent-filter 0.4" -- cgit v1.2.3