From 5b9d6eac061ad8a1a212aaf9104af82b995836bb Mon Sep 17 00:00:00 2001 From: Andy Brandt Date: Wed, 29 Nov 2017 15:42:47 -0600 Subject: [PATCH 1/5] add windows named pipe support --- .gitignore | 1 + Cargo.lock | 47 +++++++++++++++++++++++ Cargo.toml | 5 ++- src/main.rs | 82 +++++++++++++++++++++-------------------- src/platform_unix.rs | 32 ++++++++++++++++ src/platform_windows.rs | 28 ++++++++++++++ 6 files changed, 154 insertions(+), 41 deletions(-) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 src/platform_unix.rs create mode 100644 src/platform_windows.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a6f89c2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..ceeca24 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,47 @@ +[[package]] +name = "byteorder" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "keepassxc-proxy" +version = "0.1.0" +dependencies = [ + "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "named_pipe 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "named_pipe" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum named_pipe 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "516fe2b5b1131f912a3d4e0cbfec369ca9a65f89d477c15d86ef0fc376faaa55" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml index cecbc13..635468a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,7 @@ license = "GPL-3.0" repository = "https://github.com/varjolintu/keepassxc-proxy-rust" [dependencies] -byteorder = "1.1.0" \ No newline at end of file +byteorder = "1.1.0" + +[target.'cfg(windows)'.dependencies] +named_pipe = "0.2" diff --git a/src/main.rs b/src/main.rs index 53002f1..8ee8db1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,83 +1,85 @@ extern crate byteorder; +#[cfg(windows)] +extern crate named_pipe; use std::io::{self, Read, Write}; -use std::os::unix::net::UnixStream; -use std::os::unix::net::UnixListener; -use std::str; use std::thread; -use std::time::Duration; use byteorder::{ByteOrder, NativeEndian, WriteBytesExt}; +#[cfg(not(windows))] +#[path = "platform_unix.rs"] +mod platform; + +#[cfg(windows)] +#[path = "platform_windows.rs"] +mod platform; + +use platform::ProxySocket; + fn valid_length(length: u32) -> bool { return length > 0 && length <= 4096; // 1024 ^ 2 is the maximum } -fn read_header() -> (u32) +fn read_header() -> u32 { let stdin = io::stdin(); let mut buf = vec![0; 4]; let mut handle = stdin.lock(); handle.read_exact(&mut buf).unwrap(); - let length: u32 = NativeEndian::read_u32(&buf); - return length; + NativeEndian::read_u32(&buf) } -fn read_body(length: u32, mut socket: &UnixStream) +fn read_body(length: u32, socket: &mut ProxySocket) { let mut buffer = vec![0; length as usize]; let stdin = io::stdin(); let mut handle = stdin.lock(); - match handle.read_exact(&mut buffer) { - Ok(_v) => { - if valid_length(length) { - socket.write(&buffer).unwrap(); - socket.flush().unwrap(); - read_unix_response(length, &socket); - } - }, - Err(_e) => {} + if let Ok(_) = handle.read_exact(&mut buffer) { + if valid_length(length) { + socket.write_u32::(length).unwrap(); + socket.write(&buffer).unwrap(); + socket.flush().unwrap(); + read_response(socket); + } } } -fn read_unix_response(length: u32, mut socket: &UnixStream) +fn read_response(socket: &mut ProxySocket) { - let mut buf = vec![0; length as usize]; + let mut len_buf = vec![0; 4]; - match socket.read(&mut buf) { - Ok(_length) => { - let text = str::from_utf8(&buf).unwrap(); - write_output(text); - }, - Err(_e) => {} - } + if let Ok(_) = socket.read_exact(&mut len_buf) { + let len = NativeEndian::read_u32(&len_buf); + let mut buf = vec![0; len as usize]; + if let Ok(_) = socket.read_exact(&mut buf) { + write_response(&buf, len); + } + } } -fn write_output(text: &str) -{ - let textlen = text.len(); +fn write_response(buf: &[u8], len: u32) { let stdout = io::stdout(); - let mut handle = stdout.lock(); + let mut out = stdout.lock(); - handle.write_u32::(textlen as u32).unwrap(); - handle.write(text.as_bytes()).unwrap(); + out.write_u32::(len).unwrap(); + out.write(buf).unwrap(); + out.flush().unwrap(); } fn main() { - let socket = UnixStream::connect("/tmp/kpxc_server").unwrap(); - let timeout: Option = Some(Duration::from_secs(1)); - socket.set_read_timeout(timeout).unwrap(); + let mut socket = ProxySocket::connect().unwrap(); // Start thread for user input reading - let send_socket = socket.try_clone().expect("Cannot clone socket"); + //let mut send_socket = socket.try_clone().expect("Cannot clone socket"); let ui = thread::spawn(move || { loop { let length = read_header(); - read_body(length, &send_socket); - } - }); + read_body(length, &mut socket); + } + }); - let _ui_res = ui.join(); + let _ui_res = ui.join(); } diff --git a/src/platform_unix.rs b/src/platform_unix.rs new file mode 100644 index 0000000..04ab330 --- /dev/null +++ b/src/platform_unix.rs @@ -0,0 +1,32 @@ +use std::env; +use std::io::{Read, Result, Write}; +use std::os::unix::net::UnixStream; +use std::time::Duration; + +pub struct ProxySocket(UnixStream); + +impl ProxySocket { + pub fn connect() -> Result { + let user = env::var("USER").unwrap(); + let s = UnixStream::connect(format!("/tmp/keepassxc-{}.socket", user))?; + let timeout: Option = Some(Duration::from_secs(1)); + s.set_read_timeout(timeout)?; + Ok(ProxySocket(s)) + } +} + +impl Read for ProxySocket { + fn read(&mut self, buf: &mut [u8]) -> Result { + self.0.read(buf) + } +} + +impl Write for ProxySocket { + fn write(&mut self, buf: &[u8]) -> Result { + self.0.write(buf) + } + + fn flush(&mut self) -> Result<()> { + self.0.flush() + } +} diff --git a/src/platform_windows.rs b/src/platform_windows.rs new file mode 100644 index 0000000..8a10321 --- /dev/null +++ b/src/platform_windows.rs @@ -0,0 +1,28 @@ + +use std::io::{Result, Read, Write}; +use named_pipe::PipeClient; + +pub struct ProxySocket(PipeClient); + +impl ProxySocket { + pub fn connect() -> Result { + let client = PipeClient::connect("\\\\.\\pipe\\KeePassHttp").unwrap(); + Ok(ProxySocket(client)) + } +} + +impl Read for ProxySocket { + fn read(&mut self, buf: &mut [u8]) -> Result { + self.0.read(buf) + } +} + +impl Write for ProxySocket { + fn write(&mut self, buf: &[u8]) -> Result { + self.0.write(buf) + } + + fn flush(&mut self) -> Result<()> { + self.0.flush() + } +} From 14c705359e0bfebecbc178633bd783edf55ebfac Mon Sep 17 00:00:00 2001 From: Andy Brandt Date: Thu, 30 Nov 2017 13:57:32 -0600 Subject: [PATCH 2/5] got it working in both windows & linux --- src/main.rs | 20 +++++++++----------- src/platform_unix.rs | 11 +++++++++-- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index 8ee8db1..db4b98f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,7 +39,6 @@ fn read_body(length: u32, socket: &mut ProxySocket) if let Ok(_) = handle.read_exact(&mut buffer) { if valid_length(length) { - socket.write_u32::(length).unwrap(); socket.write(&buffer).unwrap(); socket.flush().unwrap(); read_response(socket); @@ -49,22 +48,22 @@ fn read_body(length: u32, socket: &mut ProxySocket) fn read_response(socket: &mut ProxySocket) { - let mut len_buf = vec![0; 4]; - - if let Ok(_) = socket.read_exact(&mut len_buf) { - let len = NativeEndian::read_u32(&len_buf); - let mut buf = vec![0; len as usize]; - if let Ok(_) = socket.read_exact(&mut buf) { - write_response(&buf, len); + let mut buf = vec![0; 1024 * 1024]; + if let Ok(len) = socket.read(&mut buf) { + // for some reason the length is 1 byte too long in linux? + let mut adjust = 0; + if cfg!(not(windows)) { + adjust = 1; } + write_response(&buf[0..len - adjust]); } } -fn write_response(buf: &[u8], len: u32) { +fn write_response(buf: &[u8]) { let stdout = io::stdout(); let mut out = stdout.lock(); - out.write_u32::(len).unwrap(); + out.write_u32::(buf.len() as u32).unwrap(); out.write(buf).unwrap(); out.flush().unwrap(); } @@ -73,7 +72,6 @@ fn main() { let mut socket = ProxySocket::connect().unwrap(); // Start thread for user input reading - //let mut send_socket = socket.try_clone().expect("Cannot clone socket"); let ui = thread::spawn(move || { loop { let length = read_header(); diff --git a/src/platform_unix.rs b/src/platform_unix.rs index 04ab330..9eb79cd 100644 --- a/src/platform_unix.rs +++ b/src/platform_unix.rs @@ -7,8 +7,15 @@ pub struct ProxySocket(UnixStream); impl ProxySocket { pub fn connect() -> Result { - let user = env::var("USER").unwrap(); - let s = UnixStream::connect(format!("/tmp/keepassxc-{}.socket", user))?; + let socket_name = "kpxc_server"; + let socket: String; + if let Ok(xdg) = env::var("XDG_RUNTIME_DIR") { + socket = format!("{}/{}", xdg, socket_name); + } else { + socket = format!("/tmp/{}", socket_name); + } + let msg = format!("Can't connect to socket: {}", socket); + let s = UnixStream::connect(socket).expect(&msg); let timeout: Option = Some(Duration::from_secs(1)); s.set_read_timeout(timeout)?; Ok(ProxySocket(s)) From fcfc22296aa65fdee4bed9b1e792e424ff811af6 Mon Sep 17 00:00:00 2001 From: Andy Brandt Date: Thu, 30 Nov 2017 16:03:28 -0600 Subject: [PATCH 3/5] refactor with generics --- src/main.rs | 28 ++++++++-------------- src/platform_unix.rs | 39 ------------------------------- src/platform_windows.rs | 28 ---------------------- src/proxy_socket.rs | 51 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 86 deletions(-) delete mode 100644 src/platform_unix.rs delete mode 100644 src/platform_windows.rs create mode 100644 src/proxy_socket.rs diff --git a/src/main.rs b/src/main.rs index db4b98f..bd73f4e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,23 +6,15 @@ use std::io::{self, Read, Write}; use std::thread; use byteorder::{ByteOrder, NativeEndian, WriteBytesExt}; -#[cfg(not(windows))] -#[path = "platform_unix.rs"] -mod platform; +mod proxy_socket; -#[cfg(windows)] -#[path = "platform_windows.rs"] -mod platform; +use proxy_socket::ProxySocket; -use platform::ProxySocket; - -fn valid_length(length: u32) -> bool -{ - return length > 0 && length <= 4096; // 1024 ^ 2 is the maximum +fn valid_length(length: u32) -> bool { + return length > 0 && length <= 4096; // 1024 ^ 2 is the maximum } -fn read_header() -> u32 -{ +fn read_header() -> u32 { let stdin = io::stdin(); let mut buf = vec![0; 4]; let mut handle = stdin.lock(); @@ -31,8 +23,7 @@ fn read_header() -> u32 NativeEndian::read_u32(&buf) } -fn read_body(length: u32, socket: &mut ProxySocket) -{ +fn read_body(length: u32, socket: &mut ProxySocket) { let mut buffer = vec![0; length as usize]; let stdin = io::stdin(); let mut handle = stdin.lock(); @@ -46,8 +37,7 @@ fn read_body(length: u32, socket: &mut ProxySocket) } } -fn read_response(socket: &mut ProxySocket) -{ +fn read_response(socket: &mut ProxySocket) { let mut buf = vec![0; 1024 * 1024]; if let Ok(len) = socket.read(&mut buf) { // for some reason the length is 1 byte too long in linux? @@ -69,7 +59,7 @@ fn write_response(buf: &[u8]) { } fn main() { - let mut socket = ProxySocket::connect().unwrap(); + let mut socket = proxy_socket::connect().unwrap(); // Start thread for user input reading let ui = thread::spawn(move || { @@ -79,5 +69,5 @@ fn main() { } }); - let _ui_res = ui.join(); + let _ui_res = ui.join().unwrap(); } diff --git a/src/platform_unix.rs b/src/platform_unix.rs deleted file mode 100644 index 9eb79cd..0000000 --- a/src/platform_unix.rs +++ /dev/null @@ -1,39 +0,0 @@ -use std::env; -use std::io::{Read, Result, Write}; -use std::os::unix::net::UnixStream; -use std::time::Duration; - -pub struct ProxySocket(UnixStream); - -impl ProxySocket { - pub fn connect() -> Result { - let socket_name = "kpxc_server"; - let socket: String; - if let Ok(xdg) = env::var("XDG_RUNTIME_DIR") { - socket = format!("{}/{}", xdg, socket_name); - } else { - socket = format!("/tmp/{}", socket_name); - } - let msg = format!("Can't connect to socket: {}", socket); - let s = UnixStream::connect(socket).expect(&msg); - let timeout: Option = Some(Duration::from_secs(1)); - s.set_read_timeout(timeout)?; - Ok(ProxySocket(s)) - } -} - -impl Read for ProxySocket { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.0.read(buf) - } -} - -impl Write for ProxySocket { - fn write(&mut self, buf: &[u8]) -> Result { - self.0.write(buf) - } - - fn flush(&mut self) -> Result<()> { - self.0.flush() - } -} diff --git a/src/platform_windows.rs b/src/platform_windows.rs deleted file mode 100644 index 8a10321..0000000 --- a/src/platform_windows.rs +++ /dev/null @@ -1,28 +0,0 @@ - -use std::io::{Result, Read, Write}; -use named_pipe::PipeClient; - -pub struct ProxySocket(PipeClient); - -impl ProxySocket { - pub fn connect() -> Result { - let client = PipeClient::connect("\\\\.\\pipe\\KeePassHttp").unwrap(); - Ok(ProxySocket(client)) - } -} - -impl Read for ProxySocket { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.0.read(buf) - } -} - -impl Write for ProxySocket { - fn write(&mut self, buf: &[u8]) -> Result { - self.0.write(buf) - } - - fn flush(&mut self) -> Result<()> { - self.0.flush() - } -} diff --git a/src/proxy_socket.rs b/src/proxy_socket.rs new file mode 100644 index 0000000..e7899ab --- /dev/null +++ b/src/proxy_socket.rs @@ -0,0 +1,51 @@ +use std::io::{self, Read, Write}; + +#[cfg(not(windows))] +use std::os::unix::net::UnixStream; + +#[cfg(windows)] +use named_pipe::PipeClient; + +pub struct ProxySocket { + inner: T, +} + +impl Read for ProxySocket { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.read(buf) + } +} + +impl Write for ProxySocket { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +#[cfg(windows)] +pub fn connect() -> io::Result> { + let client = PipeClient::connect("\\\\.\\pipe\\KeePassHttp")?; + Ok(ProxySocket { inner: client }) +} + +#[cfg(not(windows))] +pub fn connect() -> io::Result> { + use std::env; + use std::time::Duration; + + let socket_name = "kpxc_server"; + let socket: String; + if let Ok(xdg) = env::var("XDG_RUNTIME_DIR") { + socket = format!("{}/{}", xdg, socket_name); + } else { + socket = format!("/tmp/{}", socket_name); + } + let s = UnixStream::connect(socket)?; + let timeout: Option = Some(Duration::from_secs(1)); + s.set_read_timeout(timeout)?; + Ok(ProxySocket { inner: s }) +} From c7a53e654b2d72a3ee4626a4be2ab2f642a2efac Mon Sep 17 00:00:00 2001 From: andy brandt Date: Fri, 1 Dec 2017 00:55:52 -0600 Subject: [PATCH 4/5] use kpxc pipe name in windows --- src/proxy_socket.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/proxy_socket.rs b/src/proxy_socket.rs index e7899ab..50c2ed4 100644 --- a/src/proxy_socket.rs +++ b/src/proxy_socket.rs @@ -1,3 +1,4 @@ +use std::env; use std::io::{self, Read, Write}; #[cfg(not(windows))] @@ -28,13 +29,14 @@ impl Write for ProxySocket { #[cfg(windows)] pub fn connect() -> io::Result> { - let client = PipeClient::connect("\\\\.\\pipe\\KeePassHttp")?; + let temp_path = env::var("TEMP").unwrap(); + let pipe_name = format!("\\\\.\\pipe\\{}\\kpxc_server", temp_path); + let client = PipeClient::connect(pipe_name)?; Ok(ProxySocket { inner: client }) } #[cfg(not(windows))] pub fn connect() -> io::Result> { - use std::env; use std::time::Duration; let socket_name = "kpxc_server"; From 7a2298fa129d099b9c8cf03bca8635f3a88a579b Mon Sep 17 00:00:00 2001 From: Andy Brandt Date: Fri, 1 Dec 2017 23:08:42 -0600 Subject: [PATCH 5/5] remove length fix, change max buffer size --- src/main.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index bd73f4e..ad6578c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,8 @@ mod proxy_socket; use proxy_socket::ProxySocket; +const BUFFER_SIZE: u32 = 1024 * 16; + fn valid_length(length: u32) -> bool { return length > 0 && length <= 4096; // 1024 ^ 2 is the maximum } @@ -38,14 +40,9 @@ fn read_body(length: u32, socket: &mut ProxySocket) { } fn read_response(socket: &mut ProxySocket) { - let mut buf = vec![0; 1024 * 1024]; + let mut buf = vec![0; BUFFER_SIZE as usize]; if let Ok(len) = socket.read(&mut buf) { - // for some reason the length is 1 byte too long in linux? - let mut adjust = 0; - if cfg!(not(windows)) { - adjust = 1; - } - write_response(&buf[0..len - adjust]); + write_response(&buf[0..len]); } }