diff --git a/sshuttle/client.py b/sshuttle/client.py index a1578df..875f1f5 100644 --- a/sshuttle/client.py +++ b/sshuttle/client.py @@ -226,7 +226,10 @@ class FirewallClient: argv_tries.append(argvbase) # runas_path = which("runas") # if runas_path: - # argv_tries.append(['runas' , '/noprofile', '/user:Administrator', 'python']) + # argv_tries.append([runas_path , '/noprofile', '/user:Administrator', 'python']) + # XXX:attempt to elevate privilege using 'runas' in windows seems not working. + # This is due to underlying ShellExecute() Windows api does not allow child process to inherit stdio. + # TODO(nom3ad): try to implement another way to achieve this. else: # Linux typically uses sudo; OpenBSD uses doas. However, some # Linux distributions are starting to use doas. @@ -303,7 +306,6 @@ class FirewallClient: socket_share_data = s1.share(self.p.pid) s1.close() socket_share_data_b64 = base64.b64encode(socket_share_data) - # debug3(f"{socket_share_data_b64=}") self.p.stdin.write(socket_share_data_b64 + b'\n') self.p.stdin.flush() return s2.makefile('rwb') diff --git a/sshuttle/firewall.py b/sshuttle/firewall.py index 5193b15..4134e3d 100644 --- a/sshuttle/firewall.py +++ b/sshuttle/firewall.py @@ -328,6 +328,8 @@ def main(method_name, syslog): user, group, tmark) try: + # For some methods (eg: windivert) firewall setup will be differed / will run asynchronously. + # Such method implements wait_for_firewall_ready() to wait until firewall is up and running. method.wait_for_firewall_ready() except NotImplementedError: pass @@ -347,9 +349,7 @@ def main(method_name, syslog): # authentication at shutdown time - that cleanup is important! while 1: try: - debug3("===================================================") line = stdin.readline(128) - debug3("===================================================" + str(line)) except IOError as e: debug3('read from stdin failed: %s' % (e,)) return diff --git a/sshuttle/helpers.py b/sshuttle/helpers.py index 4dca60e..979c131 100644 --- a/sshuttle/helpers.py +++ b/sshuttle/helpers.py @@ -227,8 +227,8 @@ def which(file, mode=os.F_OK | os.X_OK): def is_admin_user(): if sys.platform == 'win32': - import ctypes # https://stackoverflow.com/questions/130763/request-uac-elevation-from-within-a-python-script/41930586#41930586 + import ctypes try: return ctypes.windll.shell32.IsUserAnAdmin() except Exception: diff --git a/sshuttle/ssh.py b/sshuttle/ssh.py index bede68a..3ffb045 100644 --- a/sshuttle/ssh.py +++ b/sshuttle/ssh.py @@ -206,11 +206,11 @@ def connect(ssh_cmd, rhostport, python, stderr, add_cmd_delimiter, options): if sys.platform != 'win32': (s1, s2) = socket.socketpair() + pstdin, pstdout = os.dup(s1.fileno()), os.dup(s1.fileno()) def preexec_fn(): # runs in the child process s2.close() - pstdin, pstdout = os.dup(s1.fileno()), os.dup(s1.fileno()) s1.close() def get_serversock(): @@ -218,11 +218,18 @@ def connect(ssh_cmd, rhostport, python, stderr, add_cmd_delimiter, options): os.close(pstdout) return s2 else: + # In Windows python implementation it seems not possible to use sockets as subprocess stdio + # Also select.select() won't work on pipes. + # So we have to use both socketpair and pipes together along with reader/writer threads to + # stream data between them + # NOTE: Their can be a way to use sockets as stdio with some hacks. + # https://stackoverflow.com/questions/4993119/redirect-io-of-process-to-windows-socket (s1, s2) = socket.socketpair() - preexec_fn = None pstdin = ssubprocess.PIPE pstdout = ssubprocess.PIPE + preexec_fn = None + def get_serversock(): import threading @@ -231,7 +238,7 @@ def connect(ssh_cmd, rhostport, python, stderr, add_cmd_delimiter, options): fd = p.stdout.fileno() for data in iter(lambda: os.read(fd, 16384), b''): s1.sendall(data) - debug3(f"<<<<< p.stdout.read() {len(data)} {data[:min(32,len(data))]}...") + # debug3(f"<<<<< p.stdout.read() {len(data)} {data[:min(32,len(data))]}...") finally: debug2("Thread 'stream_stdout_to_sock' exiting") s1.close() @@ -240,7 +247,7 @@ def connect(ssh_cmd, rhostport, python, stderr, add_cmd_delimiter, options): def stream_sock_to_stdin(): try: for data in iter(lambda: s1.recv(16384), b''): - debug3(f">>>>> p.stdout.write() {len(data)} {data[:min(32,len(data))]}...") + # debug3(f">>>>> p.stdout.write() {len(data)} {data[:min(32,len(data))]}...") while data: n = p.stdin.write(data) data = data[n:] @@ -251,7 +258,6 @@ def connect(ssh_cmd, rhostport, python, stderr, add_cmd_delimiter, options): threading.Thread(target=stream_stdout_to_sock, name='stream_stdout_to_sock', daemon=True).start() threading.Thread(target=stream_sock_to_stdin, name='stream_sock_to_stdin', daemon=True).start() - # s2.setblocking(False) return s2 # https://stackoverflow.com/questions/48671215/howto-workaround-of-close-fds-true-and-redirect-stdout-stderr-on-windows