miniroon

Simplistic macaroon-based authorization for Unix systems
git clone https://ccx.te2000.cz/git/miniroon
Log | Files | Refs

commit b3c2bdef477a6d069b7bd73d3f0d6150d3e5bfbf
parent 3b759a5229fcfaaf3732f296bdda279507ef1081
Author: Jan Pobrislo <ccx@te2000.cz>
Date:   Fri,  8 Nov 2024 12:39:58 +0000

Remove files unrelated to miniroon

Diffstat:
A.gitignore | 1+
Msrc/Makefile | 21++-------------------
Dsrc/applyuidgid-caps.c | 97-------------------------------------------------------------------------------
Dsrc/argv0exec.c | 17-----------------
Dsrc/fdrecv.c | 55-------------------------------------------------------
Dsrc/fdrecvto.c | 57---------------------------------------------------------
Dsrc/fdsend.c | 45---------------------------------------------
Dsrc/mtime_to_uuidv7.c | 63---------------------------------------------------------------
Dsrc/nosuid.c | 22----------------------
Dsrc/pidns_run.c | 110-------------------------------------------------------------------------------
Dsrc/ptsname.c | 30------------------------------
Dsrc/safelink.c | 120-------------------------------------------------------------------------------
Dsrc/socketpair.c | 32--------------------------------
Dsrc/socks.h | 53-----------------------------------------------------
Dsrc/spawn-pty.c | 139-------------------------------------------------------------------------------
Dsrc/test-fdsend | 13-------------
Dsrc/ucspi-socksserver-access.c | 229-------------------------------------------------------------------------------
Dsrc/ucspi-socksserver-connected.c | 152-------------------------------------------------------------------------------
Dsrc/ucspi-socksserver.c | 358-------------------------------------------------------------------------------
19 files changed, 3 insertions(+), 1611 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +*.o diff --git a/src/Makefile b/src/Makefile @@ -1,11 +1,7 @@ -tools_simple:=argv0exec nosuid pidns_run safelink spawn-pty fdsend fdrecv fdrecvto socketpair ptsname mtime_to_uuidv7 ucspi-socksserver ucspi-socksserver-connected miniroon +tools_simple:=miniroon -tools_libcap:=applyuidgid-caps - -tools_libs6:=ucspi-socksserver-access - -tools=$(tools_simple) $(tools_libcap) $(tools_libs6) +tools=$(tools_simple) all: $(tools) .PHONY: all @@ -22,16 +18,3 @@ $(1): $(1).o ../link ../link -o '$$@' '$(1).o' endef $(foreach var,$(tools_simple),$(eval $(call link_simple,$(var)))) - -define link_libcap = -$(1): $(1).o ../link - ../link -o '$$@' '$(1).o' -lcap -endef -$(foreach var,$(tools_libcap),$(eval $(call link_libcap,$(var)))) - -define link_libs6 = -$(1): $(1).o ../link - ../link -o '$$@' '$(1).o' -ls6 -endef -$(foreach var,$(tools_libs6),$(eval $(call link_libs6,$(var)))) - diff --git a/src/applyuidgid-caps.c b/src/applyuidgid-caps.c @@ -1,97 +0,0 @@ -/* ISC license. */ - -#include <unistd.h> -#include <grp.h> -#include <limits.h> -#include <stdlib.h> -#include <sys/prctl.h> -#include <sys/capability.h> -#include <linux/securebits.h> - -#include <skalibs/types.h> -#include <skalibs/setgroups.h> -#include <skalibs/strerr.h> -#include <skalibs/sgetopt.h> -#include <skalibs/djbunix.h> -#include <skalibs/exec.h> - -#define USAGE "applyuidgid-caps [ -z ] [ -u uid ] [ -g gid ] [ -G gidlist ] [ -U ] iab_caps prog..." -#define dieusage() strerr_dieusage(100, USAGE) - -int main (int argc, char const *const *argv) -{ - uid_t uid = 0 ; - gid_t gid = 0 ; - gid_t gids[NGROUPS_MAX+1] ; - size_t gidn = (size_t)-1 ; - int unexport = 0 ; - PROG = "s6-applyuidgid" ; - { - subgetopt l = SUBGETOPT_ZERO ; - for (;;) - { - int opt = subgetopt_r(argc, argv, "zUu:g:G:", &l) ; - if (opt == -1) break ; - switch (opt) - { - case 'z' : unexport = 1 ; break ; - case 'u' : if (!uid0_scan(l.arg, &uid)) dieusage() ; break ; - case 'g' : if (!gid0_scan(l.arg, &gid)) dieusage() ; break ; - case 'G' : if (!gid_scanlist(gids, NGROUPS_MAX, l.arg, &gidn) && *l.arg) dieusage() ; break ; - case 'U' : - { - char const *x = getenv("UID") ; - if (!x) strerr_dienotset(100, "UID") ; - if (!uid0_scan(x, &uid)) strerr_dieinvalid(100, "UID") ; - x = getenv("GID") ; - if (!x) strerr_dienotset(100, "GID") ; - if (!gid0_scan(x, &gid)) strerr_dieinvalid(100, "GID") ; - x = getenv("GIDLIST") ; - if (!x) strerr_dienotset(100, "GIDLIST") ; - if (!gid_scanlist(gids, NGROUPS_MAX+1, x, &gidn) && *x) - strerr_dieinvalid(100, "GIDLIST") ; - break ; - } - default : dieusage() ; - } - } - argc -= l.ind ; argv += l.ind ; - } - if (argc < 2) dieusage() ; - - /* - The IAB 3-tuple of capability vectors (Inh, Amb and Bound), - captured in type cap_iab_t combine to pass capabilities - from one process to another through execve(2) system calls. - */ - - /* parse the first argument to obtain a set of capabilities */ - cap_iab_t new_iab; - new_iab = cap_iab_from_text(argv[0]); - if (new_iab == NULL) { - strerr_dieinvalid(100, "caps") ; - // strerr_dief1sys(100, "requested capabilities were not recognized"); - } - - if (prctl(PR_SET_SECUREBITS, - SECBIT_KEEP_CAPS | /* unneeded as NO_SETUID_FIXUP is superset */ - SECBIT_NO_SETUID_FIXUP | - SECBIT_NOROOT | /* disables suid and filecap privilege gain */ - SECBIT_NOROOT_LOCKED) < 0) { - strerr_dief1sys(111, "Failed to set securebits via prctl()"); - } - /* set these capabilities for the current process */ - if (cap_iab_set_proc(new_iab) != 0) { - strerr_dief1sys(111, "Failed to set capabilities via cap_set_proc()"); - } - - if (gidn != (size_t)-1 && setgroups_and_gid(gid ? gid : getegid(), gidn, gids) < 0) - strerr_diefu1sys(111, "set supplementary group list") ; - if (gid && setgid(gid) < 0) - strerr_diefu1sys(111, "setgid") ; - if (uid && setuid(uid) < 0) - strerr_diefu1sys(111, "setuid") ; - - if (unexport) xmexec_n(argv, "UID\0GID\0GIDLIST", 16, 3) ; - else xexec(&argv[1]) ; -} diff --git a/src/argv0exec.c b/src/argv0exec.c @@ -1,17 +0,0 @@ -#include <skalibs/exec.h> - -int main (int argc, const char const **argv) -{ - const char *new_argv[argc + 1]; - for(size_t i = 0; i < argc; i++) { - new_argv[i] = argv[i]; - } - new_argv[argc] = 0; - - for(size_t i = 0; argv[0][i]; i++) { - if(argv[0][i] == '/') { - new_argv[0] = &argv[0][i+1]; - } - } - xexec(new_argv); -} diff --git a/src/fdrecv.c b/src/fdrecv.c @@ -1,55 +0,0 @@ -#include <errno.h> -#include <fcntl.h> -#include <sys/select.h> - -#include <skalibs/types.h> -#include <skalibs/strerr.h> -#include <skalibs/djbunix.h> -#include <skalibs/exec.h> -#include <skalibs/ancil.h> - -#define USAGE "fdrecv socket_fd fd_env_var prog..." -#define PROG "fdrecv" - -void wait_readable(int fd) { - fd_set rfds, xfds; - int retval = 0; - FD_ZERO(&rfds); - FD_ZERO(&xfds); - while(retval < 1) { - FD_SET(fd, &rfds); - FD_SET(fd, &xfds); - retval = select(fd+1, &rfds, NULL, &xfds, NULL); - if (retval == -1 && errno != EINTR) { - strerr_dief1sys(111, "select()"); - } - } -} - -int main (int argc, char const *const *argv) -{ - unsigned int socket_fd; - int fd = -1; - if ((argc < 4)) strerr_dieusage(100, USAGE) ; - if (!uint0_scan(argv[1], &socket_fd)) strerr_dieusage(100, USAGE) ; - - while(fd < 0) { - wait_readable(socket_fd); - fd = ancil_recv_fd(socket_fd, 42); - if(fd < 0 && errno != EAGAIN) { - strerr_dief1sys(111, "recvmsg()"); - } - } - - /* disable close-on-exec flag if present on fd */ - if(fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, NULL) & ~FD_CLOEXEC) == -1) { - strerr_dief1sys(111, "fcntl() disabling FD_CLOEXEC"); - } - - size_t env_size = strlen(argv[2]) + uint_fmt(0, fd) + 2; - char envstr[env_size]; - char *p = stpncpy(envstr, argv[2], env_size); - *p++ = '='; - uint_fmt(p, fd); - xmexec_n(argv+3, envstr, env_size-1, 1); -} diff --git a/src/fdrecvto.c b/src/fdrecvto.c @@ -1,57 +0,0 @@ -#include <errno.h> -#include <unistd.h> -#include <sys/select.h> - -#include <skalibs/types.h> -#include <skalibs/strerr.h> -#include <skalibs/djbunix.h> -#include <skalibs/exec.h> -#include <skalibs/ancil.h> - -#define USAGE "fdrecv socket_fd fd_env_var prog..." -#define PROG "fdrecv" - -void wait_readable(int fd) { - fd_set rfds, xfds; - int retval = 0; - FD_ZERO(&rfds); - FD_ZERO(&xfds); - while(retval < 1) { - FD_SET(fd, &rfds); - FD_SET(fd, &xfds); - retval = select(fd+1, &rfds, NULL, &xfds, NULL); - if (retval == -1 && errno != EINTR) { - strerr_dief1sys(111, "select()"); - } - } -} - -int main (int argc, char const *const *argv) -{ - unsigned int socket_fd, target_fd; - int fd = -1; - if ((argc < 4)) strerr_dieusage(100, USAGE) ; - if (!uint0_scan(argv[1], &socket_fd)) strerr_dieusage(100, USAGE) ; - if (!uint0_scan(argv[2], &target_fd)) strerr_dieusage(100, USAGE) ; - - while(fd < 0) { - wait_readable(socket_fd); - fd = ancil_recv_fd(socket_fd, 42); - if(fd < 0 && errno != EAGAIN) { - strerr_dief1sys(111, "recvmsg()"); - } - } - if(fd == target_fd) { - int tmp_fd = dup(fd); - if(tmp_fd < 0) { - strerr_dief1sys(111, "dup()"); - } - close(fd); - fd = tmp_fd; - } - if(dup2(fd, target_fd) < 0) { - strerr_dief1sys(111, "dup2()"); - } - - xexec(argv+3) ; -} diff --git a/src/fdsend.c b/src/fdsend.c @@ -1,45 +0,0 @@ -#include <errno.h> -#include <sys/select.h> - -#include <skalibs/types.h> -#include <skalibs/strerr.h> -#include <skalibs/djbunix.h> -#include <skalibs/exec.h> -#include <skalibs/ancil.h> - -#define USAGE "fdsend socket_fd fd_to_send prog..." -#define PROG "fdsend" - -void wait_writable(int fd) { - fd_set wfds, xfds; - int retval = 0; - FD_ZERO(&wfds); - FD_ZERO(&xfds); - while(retval < 1) { - FD_SET(fd, &wfds); - FD_SET(fd, &xfds); - retval = select(fd+1, NULL, &wfds, &xfds, NULL); - if (retval == -1 && errno != EINTR) { - strerr_dief1sys(111, "select()"); - } - } -} - - -int main (int argc, char const *const *argv) -{ - unsigned int socket_fd, fd_to_send ; - if ((argc < 4)) strerr_dieusage(100, USAGE) ; - if (!uint0_scan(argv[1], &socket_fd)) strerr_dieusage(100, USAGE) ; - if (!uint0_scan(argv[2], &fd_to_send)) strerr_dieusage(100, USAGE) ; - - wait_writable(socket_fd); - while(!ancil_send_fd(socket_fd, fd_to_send, 42)) { - if(errno != EAGAIN) { - strerr_dief1sys(111, "sendmsg()"); - } - wait_writable(socket_fd); - } - - xexec(argv+3) ; -} diff --git a/src/mtime_to_uuidv7.c b/src/mtime_to_uuidv7.c @@ -1,63 +0,0 @@ -#include <stdint.h> -#include <sys/stat.h> /* for stat(), struct stat */ -#include <unistd.h> /* for getentropy() */ -#include <stdio.h> /* for printf() */ -#include <fcntl.h> /* Definition of AT_* constants */ - -#include <skalibs/strerr.h> - -#define PROG "mtime_to_uuidv7" -#define USAGE "mtime_to_uuidv7 [filename]" - - -void uuidv7(struct timespec *ts, uint8_t* value) { - // timestamp in ms - uint64_t timestamp = (uint64_t)ts->tv_sec * 1000 + ts->tv_nsec / 1000000; - - // random bytes - if(getentropy(value, 16)) { - strerr_dief1sys(111, "getentropy()"); - } - - // timestamp - value[0] = (timestamp >> 40) & 0xFF; - value[1] = (timestamp >> 32) & 0xFF; - value[2] = (timestamp >> 24) & 0xFF; - value[3] = (timestamp >> 16) & 0xFF; - value[4] = (timestamp >> 8) & 0xFF; - value[5] = timestamp & 0xFF; - - // version and variant - value[6] = (value[6] & 0x0F) | 0x70; - value[8] = (value[8] & 0x3F) | 0x80; -} - - -int main (int argc, char const *const *argv) -{ - if (argc > 2) { - strerr_dieusage(100, USAGE); - } - struct stat statinfo; - if(argc == 2) { - if(stat(argv[1], &statinfo)) { - strerr_diefu2sys(111, "stat(): ", argv[1]); - } - } else { - if(fstatat(0, "", &statinfo, AT_EMPTY_PATH)) { - strerr_diefu1sys(111, "fstatat(stdin)"); - } - } - - uint8_t uuid_val[16]; - uuidv7(&statinfo.st_mtim, uuid_val); - - for (size_t i = 0; i < 16; i++) { - printf("%02x", uuid_val[i]); - } - printf("\n"); - - return 0; -} -/* vim: sw=4 sts=4 et -*/ diff --git a/src/nosuid.c b/src/nosuid.c @@ -1,22 +0,0 @@ -/* ISC license. */ - -#include <sys/prctl.h> -#include <linux/securebits.h> - -#include <skalibs/exec.h> -#include <skalibs/djbunix.h> -#include <skalibs/strerr.h> - -#define USAGE "nosuid prog..." -#define dieusage() strerr_dieusage(100, USAGE) - -int main (int argc, char const *const *argv) -{ - if (argc < 2) dieusage() ; - - if (prctl(PR_SET_SECUREBITS, SECBIT_NOROOT | SECBIT_NOROOT_LOCKED) < 0) { - strerr_dief1sys(111, "Failed to set securebits via prctl()"); - } - - else xexec(&argv[1]) ; -} diff --git a/src/pidns_run.c b/src/pidns_run.c @@ -1,110 +0,0 @@ -#include <fcntl.h> -#include <errno.h> -#include <sched.h> /* Definition of CLONE_* constants & unshare */ -#include <unistd.h> /* fork(), getpid() */ -#include <sys/wait.h> -#include <sys/select.h> -#include <assert.h> -#include <stdlib.h> /* exit() */ - -#include <skalibs/exec.h> -#include <skalibs/djbunix.h> -#include <skalibs/strerr.h> - -#define PROG "pidns_run" - -void fd_cloexec(int fd) { - int flags = fcntl(fd, F_GETFD); - if(flags == -1) { - strerr_dief1sys(111, "fcntl() getfd"); - } - if(fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { - strerr_dief1sys(111, "fcntl() setfd"); - } -} - -void fd_nonblock(int fd) { - int flags = fcntl(fd, F_GETFL); - if(flags == -1) { - strerr_dief1sys(111, "fcntl() getfd"); - } - if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { - strerr_dief1sys(111, "fcntl() setfd"); - } -} - -void nonblock_cloexec(int fd) { - fd_cloexec(fd); - fd_nonblock(fd); -} - -int main(const int argc, const char **argv) { - int piperw[2]; - #define parent_rfd piperw[0] - #define parent_wfd piperw[1] - /* returns EINVAL for some reason - if(pipe2(piperw, O_NONBLOCK | FD_CLOEXEC) != 0) { - strerr_dief1sys(111, "pipe2()"); - } - */ - if(pipe(piperw) != 0) { - strerr_dief1sys(111, "pipe()"); - } - nonblock_cloexec(parent_rfd); - nonblock_cloexec(parent_wfd); - if(unshare(CLONE_NEWPID) != 0) { - strerr_dief1sys(111, "unshare()"); - } - int fork1_pid = fork(); - if(fork1_pid < 0) { - strerr_dief1sys(111, "first fork()"); - } - if(fork1_pid == 0) { - /* child */ - assert(getpid() == 1); - if(close(parent_wfd) != 0) { - strerr_dief1sys(111, "close(parent_wfd)"); - } - int fork2_pid = fork(); - if(fork2_pid < 0) { - strerr_dief1sys(111, "second fork()"); - } - if(fork2_pid == 0) { - /* child */ - exec(&argv[1]); - } else { - /* parent */ - fd_set rfds; - struct timeval tv = {1, 0}; - int retval, wstatus; - pid_t pid; - FD_ZERO(&rfds); - FD_SET(parent_rfd, &rfds); - while(1) { - pid = waitpid(0, &wstatus, WNOHANG); - if(pid == fork2_pid) { - exit(wait_estatus(wstatus)); - } - retval = select(1, &rfds, NULL, NULL, &tv); - if (retval == -1 && errno != EINTR) { - strerr_dief1sys(111, "select()"); - } - if(retval > 0) { - const char term_msg[] = "pidns_run: parent died, terminating\n"; - write(2, "pidns_run: parent died, terminating\n", sizeof(term_msg)); - exit(111); - } - tv.tv_sec = 1; - tv.tv_usec = 0; - } - } - } else { - /* parent */ - if(close(parent_rfd) != 0) { - strerr_dief1sys(111, "close(parent_rfd)"); - } - int wstatus; - pid_t pid = waitpid(fork1_pid, &wstatus, 0); - exit(wait_estatus(wstatus)); - } -} diff --git a/src/ptsname.c b/src/ptsname.c @@ -1,30 +0,0 @@ -#include <unistd.h> /* write() */ -#include <stdlib.h> /* ptsname() */ -#include <string.h> - -#include <skalibs/types.h> -#include <skalibs/strerr.h> - -#define USAGE "ptsname ptmx_fd" -#define PROG "ptsname" - - -int main (int argc, char const *const *argv) -{ - unsigned int ptmx_fd; - const char *pts_name; - if ((argc != 2)) strerr_dieusage(100, USAGE) ; - if (!uint0_scan(argv[1], &ptmx_fd)) strerr_dieusage(100, USAGE) ; - - pts_name = ptsname(ptmx_fd); - if (pts_name == NULL) { - strerr_dief1sys(111, "ptsname()"); - } - - if (write(1, pts_name, strlen(pts_name)) <= 0) { - strerr_dief1sys(111, "write()"); - } - if (write(1, "\n", 1) <= 0) { - strerr_dief1sys(111, "write()"); - } -} diff --git a/src/safelink.c b/src/safelink.c @@ -1,120 +0,0 @@ -#include <errno.h> /* for errno */ -#include <fcntl.h> /* for mkdirat() openat() */ -#include <unistd.h> /* for linkat() */ -#include <stdio.h> /* for renameat() */ -#include <stdbool.h> /* for bool */ - -#include <skalibs/strerr.h> -#include <skalibs/random.h> - -#define PROG "safelink" -#define USAGE "safelink oldpath newpath" -#define BUFLEN 260 - -const char* opendir_nofollow(const char *pathname, int *fd, bool create_dirs) -{ - char next[BUFLEN]; - int fd1, fd2; - const char *base; /* final part (basename) to return */ - const char *s1 = pathname; - char *s2 = next; - - if(pathname[0] == '/') { - fd1 = open("/", O_NOFOLLOW | O_DIRECTORY | O_RDONLY); - if(fd1 < 0) { - strerr_diefu1sys(111, "open() root"); - } - s1++; - } else { - fd1 = open(".", O_NOFOLLOW | O_DIRECTORY | O_RDONLY); - if(fd1 < 0) { - strerr_diefu1sys(111, "open() CWD"); - } - } - base = s1; - while (*s1) { - /* Copy character by character from pathname[] to next[]. */ - *(s2++) = *(s1++); - if (s2 >= &next[BUFLEN]) { - strerr_dief1x(100, "filename exceeded buffer size"); - } - if(*s1 == 0) { - /* end of string, return dir fd and final path component */ - *fd = fd1; - return base; - } - if(*s1 == '/') { - if(*s1) { s1++; } - if(s2 == next) { continue; } /* skip empty filename or trailing slash */ - *s2 = 0; /* null-terminate the string in next[] */ - s2 = next; /* reset s2 pointer to the start of next[] for next dirname */ - - /* Try opening the directory in next[]. */ - fd2 = openat(fd1, next, O_NOFOLLOW | O_DIRECTORY | O_RDONLY); - if(fd2 < 1) { - if(errno == ENOENT) { - if(!create_dirs) { - strerr_dief2x(111, "directory does not exist: ", next); - } - /* Create the missing directory. */ - if(mkdirat(fd1, next, 0777) != 0) { - strerr_diefu2sys(111, "mkdirat(): ", next); - } - /* Open the newly created directory. */ - fd2 = openat(fd1, next, O_NOFOLLOW | O_DIRECTORY | O_RDONLY); - if(fd2 < 1) { - strerr_diefu2sys(111, "openat(): ", next); - } - } else { - strerr_diefu2sys(111, "openat(): ", next); - } - } - - /* Close the parent directory and replace reference to it with the newly opened one. */ - close(fd1); - fd1 = fd2; - base = s1; - } - } -} - -int main (int argc, char const *const *argv) -{ - if (argc != 3) { - strerr_dieusage(100, USAGE); - } - int old_fd, new_fd; - const char *old_base, *new_base; - old_base = opendir_nofollow(argv[1], &old_fd, false); - if(old_base[0] == 0) { - strerr_dief2x(100, "malformed path: ", argv[1]); - } - new_base = opendir_nofollow(argv[2], &new_fd, true); - if(new_base[0] == 0) { - strerr_dief2x(100, "malformed path: ", argv[2]); - } - if(linkat(old_fd, old_base, new_fd, new_base, 0) == 0) { - return 0; /* created hardlink at the correct location */ - } - if(errno != EEXIST) { - strerr_diefu1sys(111, "linkat()"); - } - /* file with such name already exists, so try again with different one and atomically replace */ - char tmp_base[BUFLEN]; - tmp_base[0] = '.'; - tmp_base[1] = 't'; - tmp_base[2] = 'm'; - tmp_base[3] = 'p'; - tmp_base[4] = '.'; - random_name(&tmp_base[5], 58); - tmp_base[64] = 0; - if(linkat(old_fd, old_base, new_fd, tmp_base, 0) != 0) { - strerr_diefu2sys(111, "linkat() to temporary name: ", tmp_base); - } - if(renameat(new_fd, tmp_base, new_fd, new_base) != 0) { - strerr_diefu4sys(111, "renameat() from temporary name: ", tmp_base, " to:", new_base); - } - return 0; -} -/* vim: sw=2 sts=2 et -*/ diff --git a/src/socketpair.c b/src/socketpair.c @@ -1,32 +0,0 @@ -#include <unistd.h> - -#include <skalibs/types.h> -#include <skalibs/strerr.h> -#include <skalibs/djbunix.h> -#include <skalibs/exec.h> -#include <skalibs/socket.h> - -#define USAGE "socketpair fd0 fd1 prog..." -#define PROG "socketpair" - -int main (int argc, char const *const *argv) -{ - int fd0, fd1; - int sv[2]; - if ((argc < 4) - || !uint0_scan(argv[1], (unsigned int *)&fd0) - || !uint0_scan(argv[2], (unsigned int *)&fd1) - || (fd0 == fd1)) - strerr_dieusage(100, USAGE) ; - - if (ipc_pair_b(sv) != 0) { - strerr_diefu1sys(111, "create socketpair") ; - } - - if (sv[1] == fd0) sv[1] = dup(sv[1]) ; - if ((sv[1] == -1) - || (fd_move(fd0, sv[0]) == -1) - || (fd_move(fd1, sv[1]) == -1)) - strerr_diefu1sys(111, "move fds") ; - xexec(argv+3) ; -} diff --git a/src/socks.h b/src/socks.h @@ -1,53 +0,0 @@ - -#define SOCKS_RESERVED 0x00 -#define SOCKS_VERSION_4 0x04 -#define SOCKS_VERSION_5 0x05 - -typedef unsigned char socks5_auth_mode_t; -#define SOCKS5_AUTH_METHOD_NOAUTH 0x00 -#define SOCKS5_AUTH_METHOD_USERPASS 0x02 -#define SOCKS5_AUTH_METHOD_NOMETHOD 0xff - -#define SOCKS5_AUTH_OK 0x00 -#define SOCKS5_AUTH_VERSION 0x01 -#define SOCKS5_AUTH_FAIL 0xff - -typedef unsigned char socks5_command_t; -#define SOCKS5_CMD_CONNECT 0x01 -#define SOCKS5_BIND 0x02 -#define SOCKS5_UDP_ASSOCIATE 0x03 - -typedef unsigned char socks5_addr_type_t; -#define SOCKS5_ADDR_TYPE_IP4 0x01 -#define SOCKS5_ADDR_TYPE_DOMAIN 0x03 -#define SOCKS5_ADDR_TYPE_IP6 0x04 - -typedef unsigned char socks5_reply_t; -#define SOCKS5_REPLY_OK 0x00 // succeeded -#define SOCKS5_REPLY_ERR_GENERAL 0x01 // general SOCKS server failure -#define SOCKS5_REPLY_ERR_FORBIDDEN 0x02 // connection not allowed by ruleset -#define SOCKS5_REPLY_ERR_NET_UNREACH 0x03 // Network unreachable -#define SOCKS5_REPLY_ERR_HOST_UNREACH 0x04 // Host unreachable -#define SOCKS5_REPLY_ERR_CONN_REFUSED 0x05 // Connection refused -#define SOCKS5_REPLY_ERR_TTL 0x06 // TTL expired -#define SOCKS5_REPLY_ERR_CMD 0x07 // Command not supported -#define SOCKS5_REPLY_ERR_ATYPE 0x08 // Address type not supported - -#define SOCKS4_STATUS_OK 0x5a -#define SOCKS4_STATUS_FAILED 0x5b - -typedef struct socks_header_s { - unsigned char version; - unsigned char methods; -} socks_header; - - -typedef struct socks5_request_header_s { - unsigned char version; - socks5_command_t cmd; - unsigned char reserved; - socks5_addr_type_t atyp; -} socks5_request_header; - -/* vim: sw=4 sts=4 et -*/ diff --git a/src/spawn-pty.c b/src/spawn-pty.c @@ -1,139 +0,0 @@ -#include <pty.h> -#include <fcntl.h> -#include <signal.h> -#include <errno.h> -#include <unistd.h> /* fork(), getpid(), setsid(), tcsetpgrp() */ -#include <stdlib.h> /* grantpt(), unlockpt(), ptsname() */ - -#include <skalibs/exec.h> -#include <skalibs/djbunix.h> -#include <skalibs/strerr.h> - -#define PROG "spawn-pty" -#define USAGE "spawn-pty term_name { pty-prog ... } ptmx-prog ..." -#define dieusage() strerr_dieusage(100, USAGE) - -#define resetsig(S) if(signal(S, SIG_DFL) == SIG_ERR) { \ - strerr_dief1sys(111, "resetting signal handler"); \ - } - -void exec_terminal(const char *term_env, const char **ptmx_argv, const char **pty_argv) { - int ptmx_fd; - const char *pts_name; - - ptmx_fd = posix_openpt(O_RDWR | O_NOCTTY); - if (ptmx_fd < 0) { - strerr_dief1sys(111, "posix_openpt()"); - } - if (grantpt(ptmx_fd) != 0) { - strerr_dief1sys(111, "grantpt()"); - } - if (unlockpt(ptmx_fd) != 0) { - strerr_dief1sys(111, "unlockpt()"); - } - pts_name = ptsname(ptmx_fd); - if (pts_name == NULL) { - strerr_dief1sys(111, "ptsname()"); - } - - int fork_pid = fork(); - if(fork_pid < 0) { - strerr_dief1sys(111, "fork()"); - } - if(fork_pid == 0) { - /* child */ - int pty_fd; - - resetsig(SIGHUP); - resetsig(SIGINT); - resetsig(SIGQUIT); - resetsig(SIGPIPE); - resetsig(SIGALRM); - resetsig(SIGTERM); - resetsig(SIGCHLD); - resetsig(SIGCONT); - resetsig(SIGTSTP); - resetsig(SIGTTIN); - resetsig(SIGTTOU); - - if(close(ptmx_fd) != 0) { - strerr_dief1sys(111, "close(ptmx_fd) in child"); - } - - if(setsid() < 0) { /* create new session */ - strerr_dief1sys(111, "setsid"); - } - /* open without O_NOCTTY so controlling terminal gets set */ - pty_fd = open(pts_name, O_RDWR); - if (pty_fd < 0) { - strerr_dief1sys(111, "open(pty)"); - } - if (tcsetpgrp(pty_fd, getpid()) < 0) { /* set controlling terminal */ - strerr_dief1sys(111, "tcsetpgrp"); - } - - if(dup2(pty_fd, 0) < 0) { - strerr_dief1sys(111, "dup2(pty_fd, 0) in child"); - } - if(dup2(pty_fd, 1) < 0) { - strerr_dief1sys(111, "dup2(pty_fd, 1) in child"); - } - if(dup2(pty_fd, 2) < 0) { - strerr_dief1sys(111, "dup2(pty_fd, 2) in child"); - } - if(close(pty_fd) != 0) { - strerr_dief1sys(111, "close(pty_fd) in child"); - } - char envstr[6 + strlen(term_env)]; - memcpy(envstr, "TERM=", 5); - strcpy(&envstr[5], term_env); - xmexec_n(pty_argv, envstr, strlen(envstr), 1); - } else { - /* parent */ - if(dup2(ptmx_fd, 0) < 0) { - strerr_dief1sys(111, "dup2(ptmx_fd, 0) in parent"); - } - if(close(ptmx_fd) != 0) { - strerr_dief1sys(111, "close(ptmx_fd) in parent"); - } - char envstr[9 + strlen(pts_name)]; - memcpy(envstr, "PTS_NAME=", 9); - strcpy(&envstr[8], term_env); - xmexec_n(ptmx_argv, envstr, strlen(envstr), 1); - } -} - -typedef const char * arg_t; - -int main(const int argc, const char **argv) { - if(argc < 2) { - dieusage(); - } - arg_t pty_argv[argc]; - const char *term_env = argv[1]; - int n = 2; - if(term_env[0] == ' ') { - dieusage(); - } - if(argv[2][0] != ' ') { - strerr_dieusage(100, USAGE "\nerror: missing block"); - } - for(int n = 2; n < argc - 1; n++) { - switch(argv[n][0]) { - case 0: - pty_argv[n - 2] = 0; - exec_terminal(term_env, &argv[n + 1], pty_argv); - return 111; - case ' ': - pty_argv[n - 2] = &argv[n][1]; - break; - default: - strerr_dieusage(100, USAGE "\nerror: improperly terminated block"); - return 100; - } - } - strerr_dieusage(100, USAGE "\nerror: unterminated block"); -} - -/* vim: ft=c sts=2 sw=2 et -*/ diff --git a/src/test-fdsend b/src/test-fdsend @@ -1,13 +0,0 @@ -#!/bin/execlineb -P -./socketpair 3 4 -#if { filan } -background { - fdclose 4 - redirfd -r 0 ./fdsend.c ./fdsend 3 0 true -} -fdclose 3 -# ./fdrecvto 4 0 cat -./fdrecv 4 FD -importas -i FD FD -fdmove 0 $FD -cat diff --git a/src/ucspi-socksserver-access.c b/src/ucspi-socksserver-access.c @@ -1,229 +0,0 @@ -#include <string.h> -#include <stdint.h> -#include <unistd.h> -#include <errno.h> -#include <stdlib.h> -#include <assert.h> - -#include <skalibs/exec.h> -#include <skalibs/sgetopt.h> -#include <skalibs/strerr.h> -#include <skalibs/cdb.h> -#include <skalibs/ip46.h> - -#include <s6/accessrules.h> - -#include "socks.h" - -#define PROG "ucspi-socksserver-access" -#define USAGE "ucspi-socksserve-access [ -i rulesdir | -x rulesfile ] prog..." -#define dieusage() strerr_dieusage(100, USAGE) -#define X() strerr_dief1x(101, "internal error") - -typedef struct app_options_s { - unsigned int rulestype; - char const * rules; - char const * port; - char const * addr_type; - char const * addr; - unsigned char socks_version; -} app_options; - -const app_options const * options = NULL; - -typedef struct check_result_s { - s6_accessrules_result_t accepted; - s6_accessrules_params_t params; -} check_result; - - -char * required_getenv(const char *name){ - char *x = getenv(name); - if (!x) { - strerr_dienotset(100, name); - } - return x; -} - -void write1(const void *buf, ssize_t n) -{ - ssize_t nwrite, left = n; - while (left > 0) { - if ((nwrite = write(STDOUT_FILENO, buf, left)) < 0) { - if (errno == EINTR || errno == EAGAIN) { - continue; - } - strerr_diefu1sys(111, "write(stdout)"); - } else { - assert(left >= nwrite); - left -= nwrite; - buf += nwrite; - } - } -} - -void socks5_reply_fail(socks5_reply_t status) -{ - char reply[] = { - SOCKS_VERSION_5, - status, - SOCKS_RESERVED, - SOCKS5_ADDR_TYPE_DOMAIN, - 0, /* domain length */ - 0, /* port MSB */ - 0 /* port LSB */ - }; - write1(reply, sizeof(reply)); - close(1); -} - -void socks4_reply_fail() -{ - const char resp[8] = {0x00, SOCKS4_STATUS_FAILED, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - write1(resp, sizeof(resp)); - close(1); -} - -void socks_reply_fail_generic(socks5_reply_t status) { - if (options->socks_version == 5) { - socks5_reply_fail(status); - } else { - socks4_reply_fail(); - } -} - -void check_access_ip(check_result *result) { - ip46 ip; - if (!ip46_scan(options->addr, &ip)) { - strerr_dieinvalid(100, "SOCKS_ADDR") ; - } - switch (options->rulestype) - { - case 1 : - result->accepted = s6_accessrules_ip46_fs(&ip, (void *)options->rules, &result->params); - break; - case 2 : - { - cdb c = CDB_ZERO ; - if (!cdb_init(&c, options->rules)) { - strerr_diefu2sys(111, "cdb_init ", options->rules); - } - result->accepted = s6_accessrules_ip46_cdb(&ip, &c, &result->params); - if (result->accepted == S6_ACCESSRULES_ALLOW) { - cdb_free(&c); - } - } - break; - default : X(); - } -} - -s6_accessrules_result_t check_access_dns(check_result *result) { - switch (options->rulestype) - { - case 1 : - result->accepted = s6_accessrules_reversedns_fs(options->addr, (void *)options->rules, &result->params); - break; - case 2 : - { - cdb c = CDB_ZERO ; - if (!cdb_init(&c, options->rules)) { - strerr_diefu2sys(111, "cdb_init ", options->rules); - } - result->accepted = s6_accessrules_reversedns_cdb(options->addr, &c, &result->params); - if (result->accepted == S6_ACCESSRULES_ALLOW) { - cdb_free(&c); - } - } - break; - default : X(); - } -} - - - -int main (int argc, char const *const *argv) -{ - char const *rulestypestr[3] = { "no", "fs", "cdb" } ; - app_options opt; - opt.rulestype = 0; - opt.rules = 0; - - subgetopt l = SUBGETOPT_ZERO ; - for (;;) - { - int o = subgetopt_r(argc, argv, "i:x:", &l) ; - if (o == -1) break ; - switch (o) - { - case 'i' : opt.rules = l.arg ; opt.rulestype = 1 ; break ; - case 'x' : opt.rules = l.arg ; opt.rulestype = 2 ; break ; - default : dieusage() ; - } - } - argc -= l.ind ; argv += l.ind ; - if (!argc) dieusage() ; - if (!*argv[0]) dieusage() ; - - char const * env_socks_version = required_getenv("SOCKS_VERSION"); - if(strcmp(env_socks_version, "4") == 0) { - opt.socks_version = 5; - } else if (strcmp(env_socks_version, "5") == 0) { - opt.socks_version = 5; - } else { - strerr_dieinvalid(100, "SOCKS_VERSION") ; - } - - opt.port = required_getenv("SOCKS_PORT"); - opt.addr_type = required_getenv("SOCKS_ADDR_TYPE"); - opt.addr = required_getenv("SOCKS_ADDR"); - - options = &opt; - - if(opt.rulestype == 0) { - xexec(argv); - } - - check_result result = { S6_ACCESSRULES_ALLOW, S6_ACCESSRULES_PARAMS_ZERO }; - - if(strcmp(opt.addr_type, "dns") == 0) { - check_access_dns(&result); - } else if ( strcmp(opt.addr_type, "ip4") == 0 || strcmp(opt.addr_type, "ip6") == 0) { - check_access_ip(&result); - } else { - strerr_dieinvalid(100, "SOCKS_ADDR_TYPE") ; - } - - switch (result.accepted) { - case S6_ACCESSRULES_ERROR: - socks_reply_fail_generic(SOCKS5_REPLY_ERR_GENERAL); - strerr_diefu6sys(111, "check ", rulestypestr[opt.rulestype], " ruleset for ", opt.addr_type, " in ", opt.rules); - case S6_ACCESSRULES_ALLOW: - break ; - case S6_ACCESSRULES_DENY: - socks_reply_fail_generic(SOCKS5_REPLY_ERR_FORBIDDEN); - // if (verbosity >= 2) log_deny(getpid(), &remoteip) ; - return 1; - case S6_ACCESSRULES_NOTFOUND: - socks_reply_fail_generic(SOCKS5_REPLY_ERR_FORBIDDEN); - // if (flagdnslookup) { - // break; - // } - // if (verbosity >= 2) { - // log_deny(getpid(), opt.addr); - // } - return 1 ; - default: X() ; - } - - if (result.params.exec.len) - { - char *specialargv[4] = { "execlineb", "-c", result.params.exec.s, 0 } ; - xmexec_m((char const *const *)specialargv, result.params.env.s, result.params.env.len) ; - } - xexec(argv); - -} - -/* vim: sw=4 sts=4 et -*/ diff --git a/src/ucspi-socksserver-connected.c b/src/ucspi-socksserver-connected.c @@ -1,152 +0,0 @@ -#include <assert.h> -#include <errno.h> -#include <stdlib.h> -#include <fcntl.h> -#include <unistd.h> -#include <sys/socket.h> -#include <netinet/in.h> - -#include <skalibs/exec.h> -#include <skalibs/strerr.h> -#include <skalibs/types.h> - -#include "socks.h" - -#define PROG "ucspi-socketserver-connect" - -#define SOCKS_RESERVED 0x00 -#define SOCKS_VERSION_4 0x04 -#define SOCKS_VERSION_5 0x05 - -typedef unsigned char socks5_addr_type_t; -#define SOCKS5_ADDR_TYPE_IP4 0x01 -#define SOCKS5_ADDR_TYPE_DOMAIN 0x03 -#define SOCKS5_ADDR_TYPE_IP6 0x04 - -typedef unsigned char socks5_reply_t; -#define SOCKS5_REPLY_OK 0x00 // succeeded -#define SOCKS5_REPLY_ERR_GENERAL 0x01 // general SOCKS server failure -#define SOCKS5_REPLY_ERR_FORBIDDEN 0x02 // connection not allowed by ruleset -#define SOCKS5_REPLY_ERR_NET_UNREACH 0x03 // Network unreachable -#define SOCKS5_REPLY_ERR_HOST_UNREACH 0x04 // Host unreachable -#define SOCKS5_REPLY_ERR_CONN_REFUSED 0x05 // Connection refused -#define SOCKS5_REPLY_ERR_TTL 0x06 // TTL expired -#define SOCKS5_REPLY_ERR_CMD 0x07 // Command not supported -#define SOCKS5_REPLY_ERR_ATYPE 0x08 // Address type not supported - -void fd_block(int fd) -{ - int flags = fcntl(fd, F_GETFL); - if(flags == -1) { - strerr_dief1sys(111, "fcntl() getfd"); - } - if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { - strerr_dief1sys(111, "fcntl() setfd"); - } -} - -void write1(const void *buf, ssize_t n) -{ - ssize_t nwrite, left = n; - while (left > 0) { - if ((nwrite = write(STDOUT_FILENO, buf, left)) < 0) { - if (errno == EINTR || errno == EAGAIN) { - continue; - } - strerr_diefu1sys(111, "write(stdout)"); - } else { - assert(left >= nwrite); - left -= nwrite; - buf += nwrite; - } - } -} - -void socks5_reply_ok(socks5_addr_type_t addr_type, void *addr, in_port_t port) -{ - size_t size; - switch(addr_type) { - case SOCKS5_ADDR_TYPE_IP4: - size = 4; - break; - case SOCKS5_ADDR_TYPE_IP6: - size = 16; - break; - case SOCKS5_ADDR_TYPE_DOMAIN: - size = strlen(addr); - if(size > 0xff) { - strerr_dieinvalid(110, "local hostname too long") ; - } - break; - } - - char reply[] = { - SOCKS_VERSION_5, - SOCKS5_REPLY_OK, - SOCKS_RESERVED, - addr_type, - }; - write1(reply, sizeof(reply)); - - if (addr_type == SOCKS5_ADDR_TYPE_DOMAIN) { - /* prefix domain by length */ - unsigned char domain_len = size; - write1(&domain_len, 1); - } - write1(addr, size); - - /* should be already in network byte order (from sin_port) */ - write1(&port, sizeof(port)); -} - -void socks4_send_reply(int status) -{ - char resp[8] = {0x00, (char)status, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - write1(resp, sizeof(resp)); -} - -int main (int argc, char const *const *argv) -{ - char const *env_socks_version = getenv("SOCKS_VERSION"); - if (!env_socks_version) { - strerr_dienotset(100, "SOCKS_VERSION"); - } - - /* fd_block(STDIN_FILENO); */ - fd_block(STDOUT_FILENO); - - if (strcmp(env_socks_version, "5") == 0) { - - struct sockaddr_storage local_addr; - socklen_t addrlen = sizeof(local_addr); - if(getsockname(6, (struct sockaddr *)&local_addr, &addrlen) != 0) { - strerr_diefu1sys(111, "getsockname(6, ...)"); - } - assert(addrlen <= sizeof(local_addr)); - switch(local_addr.ss_family) { - case AF_INET: - struct sockaddr_in *in_addr = (struct sockaddr_in *)&local_addr; - socks5_reply_ok(SOCKS5_ADDR_TYPE_IP4, &in_addr->sin_addr, in_addr->sin_port); - break; - case AF_INET6: - struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)&local_addr; - socks5_reply_ok(SOCKS5_ADDR_TYPE_IP6, &in6_addr->sin6_addr, in6_addr->sin6_port); - break; - default: - socks5_reply_ok(SOCKS5_ADDR_TYPE_DOMAIN, "localhost", 0); - break; - } - - } else if (strcmp(env_socks_version, "4") == 0) { - socks4_send_reply(SOCKS4_STATUS_OK); - - } else { - strerr_dieinvalid(100, "SOCKS_VERSION") ; - - } - xexec(argv+1); - return 110; -} - -/* vim: sw=4 sts=4 et -*/ diff --git a/src/ucspi-socksserver.c b/src/ucspi-socksserver.c @@ -1,358 +0,0 @@ -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdbool.h> -#include <stdio.h> /* for log_message */ -#include <stdarg.h> /* for log_message */ -#include <assert.h> -#include <arpa/inet.h> - -#include <skalibs/exec.h> -#include <skalibs/strerr.h> - -#include "socks.h" - -#define PROG "ucspi-socketserver" - -#define MAX_DOMAIN_LENGTH 256 - -void fd_block(int fd); -void read0(void *buf, ssize_t n); -void write1(const void *buf, ssize_t n); -void socks_read_header(socks_header *hdr); -unsigned short socks_read_port(void); -void interact(void); -void handle_socks5(char methods); -void socks5_auth(int methods_count, socks5_auth_mode_t supported_auth_method); -void socks5_auth_userpass(void); -void socks5_auth_noauth(void); -void socks5_auth_notsupported(void); -void socks5_command(socks5_request_header *rhdr); -void handle_socks4(void); -void do_connect(unsigned char socks_version, socks5_addr_type_t addr_type, char *buf, unsigned short int port); - -char const *const *new_argv = NULL; - -int main (int argc, char const *const *argv) -{ - fd_block(STDIN_FILENO); - fd_block(STDOUT_FILENO); - new_argv = argv+1; - interact(); -} - -// TODO: get rid of stdio dependency -void log_message(const char *message, ...) -{ - int ret; - va_list args; - va_start(args, message); - ret = vdprintf(STDERR_FILENO, message, args); - va_end(args); - if (ret < 0) { - strerr_dief1sys(111, "log_message() failed"); - } - write(2, "\n", 1); -} - -void fd_block(int fd) -{ - int flags = fcntl(fd, F_GETFL); - if(flags == -1) { - strerr_dief1sys(111, "fcntl() getfd"); - } - if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { - strerr_dief1sys(111, "fcntl() setfd"); - } -} - -void read0(void *buf, ssize_t n) -{ - ssize_t nread, left = n; - while (left > 0) { - if ((nread = read(STDIN_FILENO, buf, left)) < 0) { - if (errno == EINTR || errno == EAGAIN) { - continue; - } - strerr_diefu1sys(111, "read(stdin)"); - } else { - if (nread == 0) { - strerr_diefu1x(111, "read(stdin): end of file"); - } else { - assert(left >= nread); - left -= nread; - buf += nread; - } - } - } -} - -void write1(const void *buf, ssize_t n) -{ - ssize_t nwrite, left = n; - while (left > 0) { - if ((nwrite = write(STDOUT_FILENO, buf, left)) < 0) { - if (errno == EINTR || errno == EAGAIN) { - continue; - } - strerr_diefu1sys(111, "write(stdout)"); - } else { - assert(left >= nwrite); - left -= nwrite; - buf += nwrite; - } - } -} - -void read0_cstring(char *buf, size_t n) -{ - size_t left = n; - while (left > 0) { - read0(buf, 1); - if(*buf == 0) { - return; - } - left--; - buf++; - } - strerr_diefu1x(0, "read0_cstring: exceeded maximum buffer size"); -} - -/* start here */ -void interact(void) -{ - socks_header hdr; - socks_read_header(&hdr); - - switch (hdr.version) { - case SOCKS_VERSION_5: - handle_socks5(hdr.methods); - break; - case SOCKS_VERSION_4: - if (hdr.methods == 1) { - handle_socks4(); - } else { - strerr_dief1x(0, "Unsupported SOCKS4 mode"); - } - break; - } -} - -void socks_read_header(socks_header *hdr) -{ - read0(hdr, sizeof(socks_header)); - // log_message("Received header: 0x%hhX 0x%hhX", hdr->version, hdr->method); - if (hdr->version != SOCKS_VERSION_5 && hdr->version != SOCKS_VERSION_4) { - strerr_dief1x(0, "Incompatible version!"); - } -} - -unsigned short socks_read_port(void) { - unsigned short port; - read0(&port, sizeof(port)); - return ntohs(port); -} - -void handle_socks5(char methods) -{ - socks5_auth(methods, SOCKS5_AUTH_METHOD_NOAUTH); /* TODO: authentication support */ - socks5_request_header rhdr; - socks5_command(&rhdr); - unsigned short port; - - switch (rhdr.atyp) { - case SOCKS5_ADDR_TYPE_IP4: - char ip4[4]; - read0(ip4, sizeof(ip4)); - port = socks_read_port(); - - do_connect(5, SOCKS5_ADDR_TYPE_IP4, ip4, port); - break; - case SOCKS5_ADDR_TYPE_IP6: - char ip6[16]; - read0(ip6, sizeof(ip6)); - port = socks_read_port(); - - do_connect(5, SOCKS5_ADDR_TYPE_IP6, ip6, port); - break; - case SOCKS5_ADDR_TYPE_DOMAIN: - unsigned char size; - char domain[MAX_DOMAIN_LENGTH]; - read0(&size, sizeof(size)); - assert(size < MAX_DOMAIN_LENGTH); - read0(domain, size); - domain[size] = 0; - port = socks_read_port(); - - do_connect(5, SOCKS5_ADDR_TYPE_DOMAIN, domain, port); - break; - default: - strerr_dief1x(1, "Unsupported SOCKS5 command"); - break; - } -} - -void socks5_auth(int methods_count, socks5_auth_mode_t supported_auth_method) -{ - bool supported = false; - for (int i = 0; i < methods_count; i++) { - char type; - read0(&type, 1); - // log_message("Method AUTH 0x%hhX", type); - if (type == supported_auth_method) { - supported = true; - } - } - if (!supported) { - socks5_auth_notsupported(); - strerr_dief1x(1, "No supported authentication method"); - } - switch (supported_auth_method) { - case SOCKS5_AUTH_METHOD_NOAUTH: - socks5_auth_noauth(); - break; - case SOCKS5_AUTH_METHOD_USERPASS: - socks5_auth_userpass(); - break; - default: - strerr_dief1x(110, "Internal error: unhandled authentication method"); - break; - } -} - -void socks5_auth_userpass(void) -{ - strerr_dief1x(110, "TODO: userpass auth"); -} - -void socks5_auth_noauth(void) -{ - const char answer[2] = { SOCKS_VERSION_5, SOCKS5_AUTH_METHOD_NOAUTH }; - write1(answer, sizeof(answer)); -} - -void socks5_auth_notsupported(void) -{ - const char answer[2] = { SOCKS_VERSION_5, SOCKS5_AUTH_METHOD_NOMETHOD }; - write1(answer, sizeof(answer)); -} - -void socks5_command(socks5_request_header *rhdr) -{ - read0(rhdr, sizeof(socks5_request_header)); - // log_message("Command %02hhX %02hhX %02hhX %02hhX", - // rhdr->version, rhdr->cmd, rhdr->reserved, rhdr->atyp); - assert(rhdr->version == SOCKS_VERSION_5); - assert(rhdr->cmd == SOCKS5_CMD_CONNECT); -} - - -void handle_socks4(void) -{ - char ident[255]; - unsigned short int port; - char ip[4]; - - port = socks_read_port(); - read0(&ip, sizeof(ip)); - read0_cstring(ident, sizeof(ident)); - - if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] != 0) { - char domain[MAX_DOMAIN_LENGTH]; - read0_cstring(domain, sizeof(domain)); - // log_message("Socks4A: ident:%s; domain:%s;", ident, domain); - do_connect(4, SOCKS5_ADDR_TYPE_DOMAIN, domain, port); - } else { - // log_message("Socks4: connect by ip & port"); - do_connect(4, SOCKS5_ADDR_TYPE_IP4, ip, port); - } - -} - -void xenv(char const *s, char const *t) { - if (!env_mexec(s, t)) { - strerr_diefu1sys(111, "env_mexec"); - } -} - -void socks_env_ip4(const char *ip) { - char v4_address[16]; - snprintf(v4_address, sizeof(v4_address), "%hhu.%hhu.%hhu.%hhu", - ip[0], ip[1], ip[2], ip[3]); - xenv("SOCKS_ADDR", v4_address); - xenv("SOCKS_ADDR_TYPE", "ip4"); -} - -void socks_env_ip6(const char *ip) { - char v6_address[41]; - snprintf(v6_address, sizeof(v6_address), - "%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx", - ip[0x0], ip[0x1], ip[0x2], ip[0x3], ip[0x4], ip[0x5], ip[0x6], ip[0x7], - ip[0x8], ip[0x9], ip[0xa], ip[0xb], ip[0xc], ip[0xd], ip[0xe], ip[0xf]); - xenv("SOCKS_ADDR", v6_address); - xenv("SOCKS_ADDR_TYPE", "ip6"); -} - -void socks_env_dns(const char *domain) { - xenv("SOCKS_ADDR", domain); - xenv("SOCKS_ADDR_TYPE", "dns"); -} - -void log_connect(unsigned char socks_version, socks5_addr_type_t addr_type, char *buf, unsigned short int port) { - char address[43]; - switch (addr_type) { - case SOCKS5_ADDR_TYPE_IP4: - snprintf(address, sizeof(address), "%hhu.%hhu.%hhu.%hhu", - buf[0], buf[1], buf[2], buf[3]); - break; - case SOCKS5_ADDR_TYPE_IP6: - snprintf(address, sizeof(address), - "[%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx]", - buf[0x0], buf[0x1], buf[0x2], buf[0x3], buf[0x4], buf[0x5], buf[0x6], buf[0x7], - buf[0x8], buf[0x9], buf[0xa], buf[0xb], buf[0xc], buf[0xd], buf[0xe], buf[0xf]); - break; - case SOCKS5_ADDR_TYPE_DOMAIN: - break; - default: - strerr_dief1x(110, "Internal error: unhandled address type"); - } - log_message("SOCKS%hhd %s:%hd", socks_version, addr_type == SOCKS5_ADDR_TYPE_DOMAIN ? buf : address, port); -} - -void do_connect(unsigned char socks_version, socks5_addr_type_t addr_type, char *buf, unsigned short int port) { - switch(socks_version) { - case 4: - xenv("SOCKS_VERSION", "4"); - break; - case 5: - xenv("SOCKS_VERSION", "5"); - break; - default: - strerr_dief1x(110, "Internal error: unhandled protocol version"); - break; - } - - char port_string[6]; - snprintf(port_string, sizeof(port_string), "%d", port); - xenv("SOCKS_PORT", port_string); - - switch (addr_type) { - case SOCKS5_ADDR_TYPE_IP4: - socks_env_ip4(buf); - break; - case SOCKS5_ADDR_TYPE_IP6: - socks_env_ip6(buf); - break; - case SOCKS5_ADDR_TYPE_DOMAIN: - socks_env_dns(buf); - break; - default: - strerr_dief1x(110, "Internal error: unhandled address type"); - } - - log_connect(socks_version, addr_type, buf, port); - xmexec(new_argv); -} - -/* vim: sw=4 sts=4 et -*/