Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 1 | /* Copyright 2002 Jeff Dike |
| 2 | * Licensed under the GPL |
| 3 | */ |
| 4 | |
| 5 | #include <stdio.h> |
| 6 | #include <stdlib.h> |
| 7 | #include <string.h> |
| 8 | #include <errno.h> |
| 9 | #include <fcntl.h> |
| 10 | #include <unistd.h> |
| 11 | #include <pwd.h> |
| 12 | #include <grp.h> |
| 13 | #include <net/if.h> |
| 14 | #include <sys/ioctl.h> |
| 15 | #include <linux/if_tun.h> |
| 16 | |
| 17 | /* TUNSETGROUP appeared in 2.6.23 */ |
| 18 | #ifndef TUNSETGROUP |
| 19 | #define TUNSETGROUP _IOW('T', 206, int) |
| 20 | #endif |
| 21 | |
Brad Bishop | 64c979e | 2019-11-04 13:55:29 -0500 | [diff] [blame] | 22 | static void Usage(char *name, int status) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 23 | { |
| 24 | fprintf(stderr, "Create: %s [-b] [-u owner] [-g group] [-t device-name] " |
| 25 | "[-f tun-clone-device]\n", name); |
| 26 | fprintf(stderr, "Delete: %s -d device-name [-f tun-clone-device]\n\n", |
| 27 | name); |
| 28 | fprintf(stderr, "The default tun clone device is /dev/net/tun - some systems" |
| 29 | " use\n/dev/misc/net/tun instead\n\n"); |
| 30 | fprintf(stderr, "-b will result in brief output (just the device name)\n"); |
Brad Bishop | 64c979e | 2019-11-04 13:55:29 -0500 | [diff] [blame] | 31 | exit(status); |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 32 | } |
| 33 | |
| 34 | int main(int argc, char **argv) |
| 35 | { |
| 36 | struct ifreq ifr; |
| 37 | struct passwd *pw; |
| 38 | struct group *gr; |
| 39 | uid_t owner = -1; |
| 40 | gid_t group = -1; |
| 41 | int tap_fd, opt, delete = 0, brief = 0; |
| 42 | char *tun = "", *file = "/dev/net/tun", *name = argv[0], *end; |
| 43 | |
Brad Bishop | 64c979e | 2019-11-04 13:55:29 -0500 | [diff] [blame] | 44 | while((opt = getopt(argc, argv, "bd:f:t:u:g:h")) > 0){ |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 45 | switch(opt) { |
| 46 | case 'b': |
| 47 | brief = 1; |
| 48 | break; |
| 49 | case 'd': |
| 50 | delete = 1; |
| 51 | tun = optarg; |
| 52 | break; |
| 53 | case 'f': |
| 54 | file = optarg; |
| 55 | break; |
| 56 | case 'u': |
| 57 | pw = getpwnam(optarg); |
| 58 | if(pw != NULL){ |
| 59 | owner = pw->pw_uid; |
| 60 | break; |
| 61 | } |
| 62 | owner = strtol(optarg, &end, 0); |
| 63 | if(*end != '\0'){ |
| 64 | fprintf(stderr, "'%s' is neither a username nor a numeric uid.\n", |
| 65 | optarg); |
Brad Bishop | 64c979e | 2019-11-04 13:55:29 -0500 | [diff] [blame] | 66 | Usage(name, 1); |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 67 | } |
| 68 | break; |
| 69 | case 'g': |
| 70 | gr = getgrnam(optarg); |
| 71 | if(gr != NULL){ |
| 72 | group = gr->gr_gid; |
| 73 | break; |
| 74 | } |
| 75 | group = strtol(optarg, &end, 0); |
| 76 | if(*end != '\0'){ |
| 77 | fprintf(stderr, "'%s' is neither a groupname nor a numeric group.\n", |
| 78 | optarg); |
Brad Bishop | 64c979e | 2019-11-04 13:55:29 -0500 | [diff] [blame] | 79 | Usage(name, 1); |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 80 | } |
| 81 | break; |
| 82 | |
| 83 | case 't': |
| 84 | tun = optarg; |
| 85 | break; |
| 86 | case 'h': |
Brad Bishop | 64c979e | 2019-11-04 13:55:29 -0500 | [diff] [blame] | 87 | Usage(name, 0); |
| 88 | break; |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 89 | default: |
Brad Bishop | 64c979e | 2019-11-04 13:55:29 -0500 | [diff] [blame] | 90 | Usage(name, 1); |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 91 | } |
| 92 | } |
| 93 | |
| 94 | argv += optind; |
| 95 | argc -= optind; |
| 96 | |
| 97 | if(argc > 0) |
Brad Bishop | 64c979e | 2019-11-04 13:55:29 -0500 | [diff] [blame] | 98 | Usage(name, 1); |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 99 | |
| 100 | if((tap_fd = open(file, O_RDWR)) < 0){ |
| 101 | fprintf(stderr, "Failed to open '%s' : ", file); |
| 102 | perror(""); |
| 103 | exit(1); |
| 104 | } |
| 105 | |
| 106 | memset(&ifr, 0, sizeof(ifr)); |
| 107 | |
| 108 | ifr.ifr_flags = IFF_TAP | IFF_NO_PI; |
| 109 | strncpy(ifr.ifr_name, tun, sizeof(ifr.ifr_name) - 1); |
| 110 | if(ioctl(tap_fd, TUNSETIFF, (void *) &ifr) < 0){ |
| 111 | perror("TUNSETIFF"); |
| 112 | exit(1); |
| 113 | } |
| 114 | |
| 115 | if(delete){ |
| 116 | if(ioctl(tap_fd, TUNSETPERSIST, 0) < 0){ |
| 117 | perror("disabling TUNSETPERSIST"); |
| 118 | exit(1); |
| 119 | } |
| 120 | printf("Set '%s' nonpersistent\n", ifr.ifr_name); |
| 121 | } |
| 122 | else { |
| 123 | /* emulate behaviour prior to TUNSETGROUP */ |
| 124 | if(owner == -1 && group == -1) { |
| 125 | owner = geteuid(); |
| 126 | } |
| 127 | |
| 128 | if(owner != -1) { |
| 129 | if(ioctl(tap_fd, TUNSETOWNER, owner) < 0){ |
| 130 | perror("TUNSETOWNER"); |
| 131 | exit(1); |
| 132 | } |
| 133 | } |
| 134 | if(group != -1) { |
| 135 | if(ioctl(tap_fd, TUNSETGROUP, group) < 0){ |
| 136 | perror("TUNSETGROUP"); |
| 137 | exit(1); |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | if(ioctl(tap_fd, TUNSETPERSIST, 1) < 0){ |
| 142 | perror("enabling TUNSETPERSIST"); |
| 143 | exit(1); |
| 144 | } |
| 145 | |
| 146 | if(brief) |
| 147 | printf("%s\n", ifr.ifr_name); |
| 148 | else { |
| 149 | printf("Set '%s' persistent and owned by", ifr.ifr_name); |
| 150 | if(owner != -1) |
| 151 | printf(" uid %d", owner); |
| 152 | if(group != -1) |
| 153 | printf(" gid %d", group); |
| 154 | printf("\n"); |
| 155 | } |
| 156 | } |
| 157 | return(0); |
| 158 | } |