diff --git a/README.md b/README.md index 9be677f..8a709d7 100644 --- a/README.md +++ b/README.md @@ -107,15 +107,18 @@ file to edit is in the `dom0` of the target Qubes OS machine, path You can also integrate this plugin with SaltStack's `salt-ssh` program, by: -1. placing the `bombshell-client`, `qrun`, `qssh` and `qscp` commands +1. placing the `bombshell-client`, `qrun` and `qssh` commands in some directory of your path, then -2. symlinking `ssh` to `qssh` and `scp` to `qscp`. +2. symlinking `ssh` to `qssh` and `scp` to `qssh` again, then +3. adding the `host:` attribute to the roster entry of each one of your + VMs as follows: `.__qubes__`. -These commands will transparently attempt to SSH into a host unless it is -unresolvable, in which case they will assume it's a VM and fall back to -using the `bombshell-client` to communicate with said presumed VM. -SaltStack's SSH-based `salt-ssh` automator will pick these fake SSH and -SCP clients, and they will work transparently. +These fake `ssh` and `scp` commands will transparently attempt to SSH +into a host unless the host name ends with `.__qubes__`, in which case +they will assume it's a VM and fall back to using the `bombshell-client` +to communicate with said presumed VM. SaltStack's SSH-based `salt-ssh` +automator will pick these fake SSH and SCP clients based on the path, +and they will work transparently. Bug bounties ------------ diff --git a/bin/qscp b/bin/qscp deleted file mode 100755 index f7838a1..0000000 --- a/bin/qscp +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python - -import sys -import os -import subprocess -import socket - -parms = sys.argv[1:] - -try: - parmwithcolons = [x for x in parms if ":" in x][-1] - ipaddr = parmwithcolons.split(":",1)[0] - socket.inet_aton(ipaddr) - os.execv("/usr/bin/scp", ["/usr/bin/scp"] + parms) -except socket.error: - pass - -path_to_this_file = os.path.dirname(__file__) -path_to_ssh = os.path.join(path_to_this_file, "qssh") -path_to_ssh = os.path.abspath(path_to_ssh) - -scmd = ["/usr/bin/scp"] + ["-S", path_to_ssh] + parms - -os.execvp(scmd[0], scmd) diff --git a/bin/qscp b/bin/qscp new file mode 120000 index 0000000..55c9241 --- /dev/null +++ b/bin/qscp @@ -0,0 +1 @@ +qssh \ No newline at end of file diff --git a/bin/qssh b/bin/qssh index a05391a..edb7116 100755 --- a/bin/qssh +++ b/bin/qssh @@ -4,43 +4,70 @@ import sys import os import subprocess import socket +import urllib + + +def find_hostname_and_command(parms): + host = None + rest = parms + while True: + if not rest: + break + if rest[0] == "--": + if host is None: + _, host, rest = rest[0], rest[1], rest[2:] + else: + _, rest = rest[0], rest[1:] + break + elif rest[0].startswith("-o") and len(rest[0]) > 2: + _, rest = rest[0], rest[1:] + elif rest[0].startswith("-o"): + _, rest = rest[0:1], rest[2:] + elif rest[0].startswith("-"): + _, rest = rest[0], rest[1:] + else: + if host is None: + host, rest = rest[0], rest[1:] + else: + break + host, port = urllib.splitport(host) + return host, rest + + +def is_qubes_host(host): + return host.endswith(".__qubes__") + + +def get_vmname_and_management_proxy(host): + host = host[:-len(".__qubes__")] + if host.endswith("__"): + host, proxy, _ = host.rsplit("__", 2) + return host, proxy + return host, None + parms = sys.argv[1:] +host, rest = find_hostname_and_command(parms) -try: - socket.inet_aton(parms[0]) - os.execv("/usr/bin/ssh", ["/usr/bin/ssh"] + parms) -except socket.error: - pass +if os.path.basename(sys.argv[0]) in ("scp", "qscp"): + if not is_qubes_host(host): + os.execv("/usr/bin/scp", ["/usr/bin/scp"] + parms) -path_to_bombshell = os.path.abspath(os.path.join(os.path.dirname(__file__), "bombshell-client")) + path_to_ssh = os.path.join(path_to_this_file, "qssh") + scmd = ["/usr/bin/scp"] + ["-S", path_to_ssh] + parms + os.execvp(scmd[0], scmd) -host = None -rest = parms -while True: - if not rest: - break - if rest[0] == "--": - if host is None: - _, host, rest = rest[0], rest[1], rest[2:] - else: - _, rest = rest[0], rest[1:] - break - elif rest[0].startswith("-o") and len(rest[0]) > 2: - _, rest = rest[0], rest[1:] - elif rest[0].startswith("-o"): - _, rest = rest[0:1], rest[2:] - elif rest[0].startswith("-"): - _, rest = rest[0], rest[1:] - else: - if host is None: - host, rest = rest[0], rest[1:] - else: - break +else: + if not is_qubes_host(host): + os.execv("/usr/bin/ssh", ["/usr/bin/ssh"] + parms) -cmd = [ + path_to_bombshell = os.path.abspath(os.path.join(os.path.dirname(__file__), "bombshell-client")) + vmname, proxy = get_vmname_and_management_proxy(host) + if proxy: + assert 0, "While connecting to %s (VM name %s): management proxy not supported yet" % (host, vmname) + + cmd = [ path_to_bombshell, - host, + vmname, ] + ["sh", "-c", " ".join(rest)] - -os.execvp(cmd[0], cmd) + os.execvp(cmd[0], cmd)