#define _GNU_SOURCE /* asprintf */ #include #include #include #include #include #include #include #include #include #include #include #include /* Tiny code to open tap/tun device, and hand the fd to vl. Run as root, drops to given user. */ int main(int argc, char *argv[]) { struct ifreq ifr; struct passwd *p; unsigned int i; char *newargs[argc]; int fd; if (argc < 4) { fprintf(stderr, "Usage: switch user logfile vl ...\n"); exit(1); } fd = open("/dev/net/tun", O_RDWR); if (fd < 0) { perror("Could not open /dev/net/tun"); exit(1); } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strncpy(ifr.ifr_name, "tun%d", IFNAMSIZ); if (ioctl(fd, TUNSETIFF, (void *) &ifr) != 0) { perror("Could not get tun device"); exit(1); } /* Set userid. */ p = getpwnam(argv[1]); if (!p) { fprintf(stderr, "No user '%s'\n", argv[1]); exit(1); } setgroups(0, NULL); setgid(p->pw_gid); if (setuid(p->pw_uid) != 0) { perror("setting uid"); exit(1); } /* Insert -tun-fd, delete other args */ newargs[0] = argv[3]; asprintf(&newargs[1], "-tun-fd=%d", fd); for (i = 4; i <= argc; i++) newargs[i-2] = argv[i]; if (strcmp(argv[2], "-") == 0) { execvp(newargs[0], newargs); exit(1); } switch (fork()) { case 0: { close(1); close(2); open(argv[2], O_WRONLY|O_APPEND); open(argv[2], O_WRONLY|O_APPEND); close(0); execvp(newargs[0], newargs); exit(1); } case -1: perror("fork failed"); exit(1); } printf("%s\n", ifr.ifr_name); exit(0); }