qrexec_binds/
lib.rs

1#[cfg(target_arch = "x86_64")]
2
3pub mod errors;
4mod header;
5
6use std::{
7    io::{
8        Write, 
9        Read,
10        Stdin,
11        Stdout,
12        self,
13    },
14    process::{
15        Command,
16        Child,
17        ChildStdout,
18        ChildStdin,
19        ChildStderr,
20        Stdio,
21    },
22};
23use anyhow::anyhow;
24use crate::{
25    errors::*,
26    header::*,
27};
28
29pub trait QIO {
30    /// returns the number of bytes read into the buffer 
31    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize>;
32
33    /// returns the number of bytes written from the buffer.
34    /// You cannot send more data than BUF_LEN - 8 in a 
35    /// single call to this function as this would result in an  
36    /// overflow. 
37    fn write(&mut self, buf: &[u8]) -> io::Result<usize>;
38}
39
40#[inline(always)]
41fn inner_read(read: &mut impl Read, buf: &mut [u8]) -> io::Result<usize> {
42    let mut hbuf = [0u8; HEADER_LEN];
43    read.read_exact(&mut hbuf)?;
44
45    let msg_len = header_len(&hbuf) as usize;
46    read.read_exact(&mut buf[..msg_len])?;
47
48    return Ok(msg_len);
49} 
50
51#[inline(always)]
52fn inner_write(
53    written: &mut impl Write,
54    data_buf: &[u8],
55) -> io::Result<usize> {
56    let header = header(data_buf);
57    written.write_all(&header)?;
58    written.write_all(&data_buf)?;
59    written.flush()?;
60    return Ok(data_buf.len() + HEADER_LEN);
61}
62
63#[derive(Debug)]
64pub struct QrexecServer {
65    pub read: Stdin,
66    pub written: Stdout,
67}
68
69impl QIO for QrexecServer {
70    #[inline(always)]
71    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
72        return inner_read(&mut self.read, buf);
73    }
74
75    #[inline(always)]
76    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
77        return inner_write(&mut self.written, buf);
78    }
79}
80
81impl QrexecServer {
82    pub fn new() -> Self {
83        let read = io::stdin();  
84        let written = io::stdout();
85        Self {
86            read, written,
87        }
88    } 
89}
90
91/// BUF_LEN is the size of the buffer used with the 
92/// qrexec-client-vm call, --buffer-size=BUF_LEN, argument, 
93/// and the size of the buffer used to write into the 
94/// qrexec-client-vm file descriptors behind the scenes. 
95/// The only thing you need to know when you set this is that 
96/// 8 extra bytes are taken up by the header therefore you cannot 
97/// send more data than <BUF_LEN - 8> in a single write call.  
98#[derive(Debug)]
99pub struct QrexecClient { 
100    pub child: Child,
101    pub read: ChildStdout,
102    pub written: ChildStdin,
103    pub stderr: ChildStderr,
104}
105
106impl QrexecClient {
107    /// Calls qrexec-client-vm with the arguments provided through the args parameter.
108    /// Arguments:
109    ///
110    /// target_vmname: 
111    /// self explanatory 
112    ///
113    /// rpc_service: 
114    /// the service you are calling on the target vm, this can include 
115    /// an argument for the service using this syntax: some.service+argument. 
116    ///
117    /// local_program: 
118    /// Full path to local program to be connected with remote service.
119    ///
120    /// local_program_args: 
121    /// Arguments for the local program.
122    pub fn new<const BUF_LEN: usize>(
123        target_vmname: &str, 
124        rpc_service: &str,
125        local_program: Option<&str>,
126        local_program_args: Option<&[&str]>,
127    ) -> QRXRes<Self> {
128        let mut child = Command::new("qrexec-client-vm");
129        child.stdout(Stdio::piped())
130            .stdin(Stdio::piped())
131            .stderr(Stdio::piped());
132
133        child.args([
134            &format!("--buffer-size={}", &BUF_LEN.to_string()),
135            target_vmname, rpc_service]);
136
137        if let Some(local_program) = local_program {
138            child.arg(local_program);
139        }
140
141        if let Some(args) = local_program_args {
142            child.args(args);
143        }
144
145        let mut child = child.spawn()?;
146
147        return Ok(Self {
148            read: child.stdout.take().ok_or(
149                anyhow!(STDOUT_ERR))?,
150            written: child.stdin.take().ok_or(
151                anyhow!(STDIN_ERR))?,
152            stderr: child.stderr.take().ok_or(
153                anyhow!(STDERR_ERR))?,
154            child,
155        })
156    }
157}
158
159impl QIO for QrexecClient {
160    #[inline(always)]
161    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
162        return inner_read(&mut self.read, buf);
163    }  
164
165    #[inline(always)]
166    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
167        return inner_write(&mut self.written, buf);
168    }
169}
170
171impl Drop for QrexecClient { 
172    fn drop(&mut self) {
173        let _ = self.child.kill();   
174    }
175}