1 // compile with gcc -o proxyspace proxyspace.c -Wall -std=gnu99
7 #include <sys/socket.h>
9 #include <netinet/in.h>
10 #include <netinet/tcp.h>
20 #define eprintf(...) fprintf(stderr, __VA_ARGS__)
22 const struct addrinfo tcp_hints = {
23 .ai_flags = AI_ADDRCONFIG,
24 .ai_family = AF_UNSPEC,
25 .ai_socktype = SOCK_STREAM,
29 int netopen(const char *node, const char *service) {
30 struct addrinfo *addrs;
31 if (getaddrinfo(node, service, &tcp_hints, &addrs))
32 errx(1, "unable to resolve address");
34 int s = socket(addrs[0].ai_family, addrs[0].ai_socktype, addrs[0].ai_protocol);
36 err(1, "unable to create socket");
38 if (connect(s, addrs[0].ai_addr, addrs[0].ai_addrlen))
39 err(1, "unable to connect");
45 pid_t fork_nofail(void) {
48 err(1, "fork failed");
52 void write_file(char *path, char *data) {
53 int fd = open(path, O_WRONLY);
55 err(1, "unable to open \"%s\" for writing", path);
56 ssize_t r = write(fd, data, strlen(data));
58 err(1, "write to \"%s\" failed", path);
59 if (r != strlen(data))
60 errx(1, "write to \"%s\" failed", path);
62 err(1, "close failed");
65 char *xasprintf(char *fmt, ...) {
69 if (vasprintf(&ret, fmt, ap) == -1)
70 errx(1, "memory allocation failed");
75 int main(int argc, char **argv) {
76 // invocation: ./proxyspace <sshhost-tcp> <sshport-tcp> <sshtarget-name> <localcommand> [<arg1> ...]
77 char *sshhost = argv[1];
78 char *sshport = argv[2];
79 char *sshtarget = argv[3];
80 char **next_argv = argv+4;
82 eprintf("connecting...\n");
83 int netfd = netopen(sshhost, sshport);
84 eprintf("TCP connection successful\n");
86 uid_t outer_uid = getuid();
87 gid_t outer_gid = getgid();
89 // This is the point of no return: After this, we don't have access to the normal
91 if (unshare(CLONE_NEWUSER|CLONE_NEWNET))
92 err(1, "unable to unshare (maybe unprivileged user namespaces are disabled)");
94 // Annoying. Fix up our mapped uid and gid to zero.
95 write_file("/proc/self/setgroups", "deny");
96 write_file("/proc/self/uid_map", xasprintf("0 %d 1\n", outer_uid));
97 write_file("/proc/self/gid_map", xasprintf("0 %d 1\n", outer_gid));
99 eprintf("launching ssh...\n");
100 pid_t ssh_pid = fork_nofail();
102 // -f -n doesn't seem to be working here...
103 execlp("ssh", "ssh", "-w", "0",
104 "-o", xasprintf("ProxyCommand /proc/%d/exe --stage2 %d", (int)getppid(), netfd),
106 err(1, "execlp for ssh failed");
111 waitres = wait(&ssh_status);
112 } while (waitres != -1 && waitres != ssh_pid);
114 err(1, "unable to wait for ssh???");
115 if (!WIFEXITED(ssh_status))
116 errx(1, "uh... looks like ssh exited in a weird way?");
117 if (WEXITSTATUS(ssh_status) != 0)
118 errx(1, "ssh exited with exit code %d", (int)WEXITSTATUS(ssh_status));
119 eprintf("ssh seems to be connected!\n");
121 execvp(next_argv[0], next_argv);
122 err(1, "unable to execute specified next command \"%s\"", next_argv[0]);