Esempio n. 1
0
def list_routes():
    if which('ip'):
        routes = _list_routes(['ip', 'route'], _route_iproute)
    elif which('netstat'):
        routes = _list_routes(['netstat', '-rn'], _route_netstat)
    else:
        log('WARNING: Neither "ip" nor "netstat" were found on the server. '
            '--auto-nets feature will not work.')
        routes = []

    for (family, ip, width) in routes:
        if not ip.startswith('0.') and not ip.startswith('127.'):
            yield (family, ip, width)
Esempio n. 2
0
    def __init__(self, method_name, sudo_pythonpath):
        self.auto_nets = []
        python_path = os.path.dirname(os.path.dirname(__file__))
        argvbase = ([sys.executable, sys.argv[0]] + ['-v'] *
                    (helpers.verbose or 0) + ['--method', method_name] +
                    ['--firewall'])
        if ssyslog._p:
            argvbase += ['--syslog']

        # Determine how to prefix the command in order to elevate privileges.
        if platform.platform().startswith('OpenBSD'):
            elev_prefix = ['doas']  # OpenBSD uses built in `doas`
        else:
            elev_prefix = ['sudo', '-p', '[local sudo] Password: '******'/usr/bin/env', 'PYTHONPATH=%s' % python_path]
        argv_tries = [elev_prefix + argvbase, argvbase]

        # we can't use stdin/stdout=subprocess.PIPE here, as we normally would,
        # because stupid Linux 'su' requires that stdin be attached to a tty.
        # Instead, attach a *bidirectional* socket to its stdout, and use
        # that for talking in both directions.
        (s1, s2) = socket.socketpair()

        def setup():
            # run in the child process
            s2.close()

        if os.getuid() == 0:
            argv_tries = argv_tries[-1:]  # last entry only
        for argv in argv_tries:
            try:
                if argv[0] == 'su':
                    sys.stderr.write('[local su] ')
                self.p = ssubprocess.Popen(argv, stdout=s1, preexec_fn=setup)
                # No env: Talking to `FirewallClient.start`, which has no i18n.
                break
            except OSError as e:
                log('Spawning firewall manager: %r' % argv)
                raise Fatal(e)
        self.argv = argv
        s1.close()
        self.pfile = s2.makefile('rwb')
        line = self.pfile.readline()
        self.check()
        if line[0:5] != b'READY':
            raise Fatal('%r expected READY, got %r' % (self.argv, line))
        method_name = line[6:-1]
        self.method = get_method(method_name.decode("ASCII"))
        self.method.set_firewall(self)
Esempio n. 3
0
 def is_supported(self):
     if which("ipfw"):
         return True
     debug2("ipfw method not supported because 'ipfw' command is "
            "missing.")
     return False
Esempio n. 4
0
 def is_supported(self):
     if which("nft"):
         return True
     debug2("nft method not supported because 'nft' command is missing.")
     return False
Esempio n. 5
0
 def is_supported(self):
     if which("iptables"):
         return True
     debug2("nat method not supported because 'iptables' command "
            "is missing.")
     return False
Esempio n. 6
0
def connect(ssh_cmd, rhostport, python, stderr, options):
    username, password, port, host = parse_hostport(rhostport)
    if username:
        rhost = "{}@{}".format(username, host)
    else:
        rhost = host

    z = zlib.compressobj(1)
    content = get_module_source('tshuttle.assembler')
    optdata = ''.join("%s=%r\n" % (k, v) for (k, v) in list(options.items()))
    optdata = optdata.encode("UTF8")
    content2 = (empackage(z, 'tshuttle') +
                empackage(z, 'tshuttle.cmdline_options', optdata) +
                empackage(z, 'tshuttle.helpers') +
                empackage(z, 'tshuttle.ssnet') +
                empackage(z, 'tshuttle.hostwatch') +
                empackage(z, 'tshuttle.server') +
                b"\n")

    # If the exec() program calls sys.exit(), it should exit python
    # and the sys.exit(98) call won't be reached (so we try to only
    # exit that way in the server). However, if the code that we
    # exec() simply returns from main, then we will return from
    # exec(). If the server's python process dies, it should stop
    # executing and also won't reach sys.exit(98).
    #
    # So, we shouldn't reach sys.exit(98) and we certainly shouldn't
    # reach it immediately after trying to start the server.
    pyscript = r"""
                import sys, os;
                verbosity=%d;
                sys.stdin = os.fdopen(0, "rb");
                exec(compile(sys.stdin.read(%d), "assembler.py", "exec"));
                sys.exit(98);
                """ % (helpers.verbose or 0, len(content))
    pyscript = re.sub(r'\s+', ' ', pyscript.strip())

    if not rhost:
        # ignore the --python argument when running locally; we already know
        # which python version works.
        argv = [sys.executable, '-c', pyscript]
    else:
        if ssh_cmd:
            sshl = shlex.split(ssh_cmd)
        else:
            sshl = ['ssh']
        if port is not None:
            portl = ["-p", str(port)]
        else:
            portl = []
        if python:
            pycmd = "'%s' -c '%s'" % (python, pyscript)
        else:
            # By default, we run the following code in a shell.
            # However, with restricted shells and other unusual
            # situations, there can be trouble. See the RESTRICTED
            # SHELL section in "man bash" for more information. The
            # code makes many assumptions:
            #
            # (1) That /bin/sh exists and that we can call it.
            # Restricted shells often do *not* allow you to run
            # programs specified with an absolute path like /bin/sh.
            # Either way, if there is trouble with this, it should
            # return error code 127.
            #
            # (2) python3 or python exists in the PATH and is
            # executable. If they aren't, then exec wont work (see (4)
            # below).
            #
            # (3) In /bin/sh, that we can redirect stderr in order to
            # hide the version that "python3 -V" might print (some
            # restricted shells don't allow redirection, see
            # RESTRICTED SHELL section in 'man bash'). However, if we
            # are in a restricted shell, we'd likely have trouble with
            # assumption (1) above.
            #
            # (4) The 'exec' command should work except if we failed
            # to exec python because it doesn't exist or isn't
            # executable OR if exec isn't allowed (some restricted
            # shells don't allow exec). If the exec succeeded, it will
            # not return and not get to the "exit 97" command. If exec
            # does return, we exit with code 97.
            #
            # Specifying the exact python program to run with --python
            # avoids many of the issues above. However, if
            # you have a restricted shell on remote, you may only be
            # able to run python if it is in your PATH (and you can't
            # run programs specified with an absolute path). In that
            # case, tshuttle might not work at all since it is not
            # possible to run python on the remote machine---even if
            # it is present.
            pycmd = ("P=python3; $P -V 2>%s || P=python; "
                     "exec \"$P\" -c %s; exit 97") % \
                     (os.devnull, quote(pyscript))
            pycmd = ("/bin/sh -c {}".format(quote(pycmd)))

        if password is not None:
            os.environ['SSHPASS'] = str(password)
            argv = (["sshpass", "-e"] + sshl +
                    portl +
                    [rhost, pycmd])

        else:
            argv = (sshl +
                    portl +
                    [rhost, pycmd])

    # Our which() function searches for programs in get_path()
    # directories (which include PATH). This step isn't strictly
    # necessary if ssh is already in the user's PATH, but it makes the
    # error message friendlier if the user incorrectly passes in a
    # custom ssh command that we cannot find.
    abs_path = which(argv[0])
    if abs_path is None:
        raise Fatal("Failed to find '%s' in path %s" % (argv[0], get_path()))
    argv[0] = abs_path

    (s1, s2) = socket.socketpair()

    def setup():
        # runs in the child process
        s2.close()
    s1a, s1b = os.dup(s1.fileno()), os.dup(s1.fileno())
    s1.close()

    debug2('executing: %r' % argv)
    p = ssubprocess.Popen(argv, stdin=s1a, stdout=s1b, preexec_fn=setup,
                          close_fds=True, stderr=stderr)
    os.close(s1a)
    os.close(s1b)
    s2.sendall(content)
    s2.sendall(content2)
    return p, s2
Esempio n. 7
0
 def is_supported(self):
     if which("pfctl"):
         return True
     debug2("pf method not supported because 'pfctl' command is missing.")
     return False
Esempio n. 8
0
 def is_supported(self):
     if which("iptables") and which("ip6tables"):
         return True
     debug2("tproxy method not supported because 'iptables' "
            "or 'ip6tables' commands are missing.\n")
     return False