]> git.proxmox.com Git - pve-xtermjs.git/commitdiff
termproxy: split out CLI stuff to own module
authorThomas Lamprecht <t.lamprecht@proxmox.com>
Mon, 23 Oct 2023 08:12:12 +0000 (10:12 +0200)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Mon, 23 Oct 2023 08:12:12 +0000 (10:12 +0200)
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
termproxy/src/cli.rs [new file with mode: 0644]
termproxy/src/main.rs

diff --git a/termproxy/src/cli.rs b/termproxy/src/cli.rs
new file mode 100644 (file)
index 0000000..cc44655
--- /dev/null
@@ -0,0 +1,102 @@
+use std::ffi::OsString;
+use std::os::fd::RawFd;
+
+use anyhow::{bail, Result};
+
+const CMD_HELP: &str = "\
+Usage: proxmox-termproxy [OPTIONS] --path <path> <listen-port> -- <terminal-cmd>...
+
+Arguments:
+  <listen-port>           Port or file descriptor to listen for TCP connections
+  <terminal-cmd>...       The command to run connected via a proxied PTY
+
+Options:
+      --authport <authport>       Port to relay auth-request, default 85
+      --port-as-fd                Use <listen-port> as file descriptor.
+      --path <path>               ACL object path to test <perm> on.
+      --perm <perm>               Permission to test.
+      -h, --help                  Print help
+";
+
+#[derive(Debug)]
+pub enum PortOrFd {
+    Port(u16),
+    Fd(RawFd),
+}
+
+impl PortOrFd {
+    fn from_cli(value: u64, use_as_fd: bool) -> Result<PortOrFd> {
+        if use_as_fd {
+            if value > RawFd::MAX as u64 {
+                bail!("FD value too big");
+            }
+            Ok(Self::Fd(value as RawFd))
+        } else {
+            if value > u16::MAX as u64 {
+                bail!("invalid port number");
+            }
+            Ok(Self::Port(value as u16))
+        }
+    }
+}
+
+#[derive(Debug)]
+pub struct Options {
+    /// The actual command to run proxied in a pseudo terminal.
+    pub terminal_command: Vec<OsString>,
+    /// The port or FD that termproxy will listen on for an incoming conection
+    pub listen_port: PortOrFd,
+    /// The port of the local privileged daemon that authentication is relayed to. Defaults to `85`
+    pub api_daemon_port: u16,
+    /// The ACL object path the 'acl_permission' is checked on
+    pub acl_path: String,
+    /// The ACL permission that the ticket, read from the stream, is required to have on 'acl_path'
+    pub acl_permission: Option<String>,
+}
+
+impl Options {
+    pub fn from_env() -> Result<Self> {
+        let mut args: Vec<_> = std::env::args_os().collect();
+        args.remove(0); // remove the executable path.
+
+        // handle finding command after `--` first so that we only parse our options later
+        let terminal_command = if let Some(dash_dash) = args.iter().position(|arg| arg == "--") {
+            let later_args = args.drain(dash_dash + 1..).collect();
+            args.pop(); // .. then remove the `--`
+            Some(later_args)
+        } else {
+            None
+        };
+
+        // Now pass the remaining arguments through to `pico_args`.
+        let mut args = pico_args::Arguments::from_vec(args);
+
+        if args.contains(["-h", "--help"]) {
+            print!("{CMD_HELP}");
+            std::process::exit(0);
+        } else if terminal_command.is_none() {
+            bail!("missing terminal command or -- option-end marker, see '-h' for usage");
+        }
+
+        let options = Self {
+            terminal_command: terminal_command.unwrap(), // checked above
+            listen_port: PortOrFd::from_cli(args.free_from_str()?, args.contains("--port-as-fd"))?,
+            api_daemon_port: args.opt_value_from_str("--authport")?.unwrap_or(85),
+            acl_path: args.value_from_str("--path")?,
+            acl_permission: args.opt_value_from_str("--perm")?,
+        };
+
+        if !args.finish().is_empty() {
+            bail!("unexpected extra arguments, use '-h' for usage");
+        }
+
+        Ok(options)
+    }
+
+    pub fn use_listen_port_as_fd(&self) -> bool {
+        match self.listen_port {
+            PortOrFd::Fd(_) => true,
+            _ => false,
+        }
+    }
+}
index 6962da64924034179c5d6288f4f8734a40852fae..cb72ef61d04c4942fdda7de3e4752dca291ab47f 100644 (file)
@@ -2,7 +2,6 @@ use std::cmp::min;
 use std::collections::HashMap;
 use std::ffi::OsString;
 use std::io::{ErrorKind, Write};
-use std::os::fd::RawFd;
 use std::os::unix::io::{AsRawFd, FromRawFd};
 use std::os::unix::process::CommandExt;
 use std::process::Command;
@@ -17,6 +16,9 @@ use proxmox_io::ByteBuffer;
 use proxmox_lang::error::io_err_other;
 use proxmox_sys::linux::pty::{make_controlling_terminal, PTY};
 
+mod cli;
+use crate::cli::{Options, PortOrFd};
+
 const MSG_TYPE_DATA: u8 = 0;
 const MSG_TYPE_RESIZE: u8 = 1;
 //const MSG_TYPE_PING: u8 = 2;
@@ -153,7 +155,7 @@ fn authenticate(username: &[u8], ticket: &[u8], options: &Options, listen_port:
     // if the listen-port was passed indirectly via an FD, it's encoded also in the ticket so that
     // the access system can enforce that the users actually can access that port.
     let port_str;
-    if options.listen_port.is_fd() {
+    if options.use_listen_port_as_fd() {
         port_str = listen_port.to_string();
         post_fields.push(("port", &port_str));
     }
@@ -247,104 +249,8 @@ fn run_pty<'a>(mut full_cmd: impl Iterator<Item = &'a OsString>) -> Result<PTY>
 const TCP: Token = Token(0);
 const PTY: Token = Token(1);
 
-const CMD_HELP: &str = "\
-Usage: proxmox-termproxy [OPTIONS] --path <path> <listen-port> -- <terminal-cmd>...
-
-Arguments:
-  <listen-port>           Port or file descriptor to listen for TCP connections
-  <terminal-cmd>...       The command to run connected via a proxied PTY
-
-Options:
-      --authport <authport>       Port to relay auth-request, default 85
-      --port-as-fd                Use <listen-port> as file descriptor.
-      --path <path>               ACL object path to test <perm> on.
-      --perm <perm>               Permission to test.
-      -h, --help                  Print help
-";
-
-#[derive(Debug)]
-enum PortOrFd {
-    Port(u16),
-    Fd(RawFd),
-}
-
-impl PortOrFd {
-    fn from_cli(value: u64, use_as_fd: bool) -> Result<PortOrFd> {
-        if use_as_fd {
-            if value > RawFd::MAX as u64 {
-                bail!("FD value too big");
-            }
-            Ok(Self::Fd(value as RawFd))
-        } else {
-            if value > u16::MAX as u64 {
-                bail!("invalid port number");
-            }
-            Ok(Self::Port(value as u16))
-        }
-    }
-
-    fn is_fd(&self) -> bool {
-        match self {
-            Self::Fd(_) => true,
-            _ => false,
-        }
-    }
-}
-
-#[derive(Debug)]
-struct Options {
-    /// The actual command to run proxied in a pseudo terminal.
-    terminal_command: Vec<OsString>,
-    /// The port or FD that termproxy will listen on for an incoming conection
-    listen_port: PortOrFd,
-    /// The port of the local privileged daemon that authentication is relayed to. Defaults to `85`
-    api_daemon_port: u16,
-    /// The ACL object path the 'acl_permission' is checked on
-    acl_path: String,
-    /// The ACL permission that the ticket, read from the stream, is required to have on 'acl_path'
-    acl_permission: Option<String>,
-}
-
-fn parse_args() -> Result<Options> {
-    let mut args: Vec<_> = std::env::args_os().collect();
-    args.remove(0); // remove the executable path.
-
-    // handle finding command after `--` first so that we only parse our options later
-    let terminal_command = if let Some(dash_dash) = args.iter().position(|arg| arg == "--") {
-        let later_args = args.drain(dash_dash + 1..).collect();
-        args.pop(); // .. then remove the `--`
-        Some(later_args)
-    } else {
-        None
-    };
-
-    // Now pass the remaining arguments through to `pico_args`.
-    let mut args = pico_args::Arguments::from_vec(args);
-
-    if args.contains(["-h", "--help"]) {
-        print!("{CMD_HELP}");
-        std::process::exit(0);
-    } else if terminal_command.is_none() {
-        bail!("missing terminal command or -- option-end marker, see '-h' for usage");
-    }
-
-    let options = Options {
-        terminal_command: terminal_command.unwrap(), // checked above
-        listen_port: PortOrFd::from_cli(args.free_from_str()?, args.contains("--port-as-fd"))?,
-        api_daemon_port: args.opt_value_from_str("--authport")?.unwrap_or(85),
-        acl_path: args.value_from_str("--path")?,
-        acl_permission: args.opt_value_from_str("--perm")?,
-    };
-
-    if !args.finish().is_empty() {
-        bail!("unexpected extra arguments, use '-h' for usage");
-    }
-
-    Ok(options)
-}
-
 fn do_main() -> Result<()> {
-    let options = parse_args()?;
+    let options = Options::from_env()?;
 
     let (mut tcp_handle, listen_port) =
         listen_and_accept("localhost", &options.listen_port, Duration::new(10, 0))