dtms
changeset 4:db4bb4b5905a tip
security fixes:
- refuse to run as root
- drop privileges without an explicit -u argument when running setuid-root
fixed argument parsing
fixed mem leak
added install and uninstall rules (Makefile)
author | Eleni Maria Stea <eleni@mutantstargoat.com> |
---|---|
date | Sun, 15 May 2016 00:15:45 +0300 |
parents | bf6dda0e9daf |
children | |
files | Makefile src/main.c |
diffstat | 2 files changed, 79 insertions(+), 43 deletions(-) [+] |
line diff
1.1 --- a/Makefile Fri May 13 23:02:26 2016 +0300 1.2 +++ b/Makefile Sun May 15 00:15:45 2016 +0300 1.3 @@ -1,3 +1,6 @@ 1.4 +# change the following line to install to a different prefix 1.5 +PREFIX = /usr/local 1.6 + 1.7 src = $(wildcard src/*.c) 1.8 obj = $(src:.c=.o) 1.9 dep = $(obj:.o=.d) 1.10 @@ -6,10 +9,7 @@ 1.11 dbg = -g 1.12 opt = -O0 1.13 1.14 -CC = gcc 1.15 -INCLUDE = -I/usr/include 1.16 -CFLAGS = -pedantic -Wall -std=c99 -D_XOPEN_SOURCE=600 $(dbg) $(INCLUDE) 1.17 -LDFLAGS = -L/usr/lib $(libs) 1.18 +CFLAGS = -pedantic -Wall -std=gnu99 -DPREFIX=\"$(PREFIX)\" $(dbg) 1.19 1.20 $(bin): $(obj) 1.21 $(CC) -o $@ $(obj) $(LDFLAGS) 1.22 @@ -22,3 +22,19 @@ 1.23 .PHONY: clean 1.24 clean: 1.25 rm -f $(obj) $(bin) $(dep) 1.26 + 1.27 +.PHONY: install 1.28 +install: $(bin) 1.29 + mkdir -p $(PREFIX)/bin $(PREFIX)/share/dtms 1.30 + cp $(bin) $(PREFIX)/bin/$(bin) 1.31 + chown root $(PREFIX)/bin/$(bin) 1.32 + chmod +s $(PREFIX)/bin/$(bin) 1.33 + cp data/dtms.mp3 $(PREFIX)/share/dtms/dtms.mp3 1.34 + 1.35 +.PHONY: uninstall 1.36 +uninstall: 1.37 + rm -f $(PREFIX)/bin/$(bin) 1.38 + rm -f $(PREFIX)/share/dtms/dtms.mp3 1.39 + rmdir $(PREFIX)/share/dtms 1.40 + 1.41 +
2.1 --- a/src/main.c Fri May 13 23:02:26 2016 +0300 2.2 +++ b/src/main.c Sun May 15 00:15:45 2016 +0300 2.3 @@ -29,41 +29,58 @@ 2.4 2.5 static int parse_args(int argc, char **argv); 2.6 static void print_help(); 2.7 -static void check_device(char *device_path); 2.8 -static char* concatenate(char *mp_path, char *data_path); 2.9 +static int check_device(char *device_path); 2.10 2.11 -static int uid; 2.12 -static char *path; 2.13 +static int uid = -1; 2.14 +static char *player_path; 2.15 static char *dev_path; 2.16 2.17 +#ifdef PREFIX 2.18 +static const char* player_arg = PREFIX "/share/dtms/dtms.mp3"; 2.19 +#else 2.20 +static const char* player_arg = "data/dtms.mp3"; 2.21 +#endif 2.22 + 2.23 int main(int argc, char **argv) 2.24 { 2.25 time_t last_touch_time = 0; 2.26 int fd; 2.27 2.28 - if(parse_args(argc, argv)) 2.29 + if(parse_args(argc, argv) == -1) 2.30 return 1; 2.31 2.32 - check_device(dev_path); 2.33 + if(getuid() == 0 && uid == -1) { 2.34 + fprintf(stderr, "It's a bad idea to run this program as root, either make it setuid-root, or use the -u option to specify an unprivileged user.\n"); 2.35 + return 1; 2.36 + } 2.37 + 2.38 + if(check_device(dev_path) == -1) 2.39 + return 1; 2.40 2.41 if((fd = open(dev_path, O_RDONLY | O_NONBLOCK)) == -1) { 2.42 fprintf(stderr, "Failed to open device: %s, error: %s\n", dev_path, strerror(errno)); 2.43 return 1; 2.44 } 2.45 2.46 + if(uid == -1) { 2.47 + uid = getuid(); 2.48 + } 2.49 + 2.50 if(seteuid(uid) == -1) { 2.51 perror("Set uid failed"); 2.52 - uid = 0; 2.53 + return 1; 2.54 } 2.55 2.56 if(!uid) { 2.57 - const char *st = "/"; 2.58 - if(strncmp(path, st, 1) != 0) { 2.59 + if(player_path[0] != '/') { 2.60 fprintf(stderr, "If you run this program as root you should pass the absolute path to a valid mp3 player.\n"); 2.61 return 1; 2.62 } 2.63 } 2.64 2.65 + char *cmd = malloc(strlen(player_path) + 1 + strlen(player_arg) + 1); 2.66 + sprintf(cmd, "%s %s", player_path, player_arg); 2.67 + 2.68 while(1) { 2.69 fd_set read_set; 2.70 FD_ZERO(&read_set); 2.71 @@ -83,13 +100,16 @@ 2.72 time_t now = time(0); 2.73 while(read(fd, buf, sizeof buf) > 0); 2.74 if (now - last_touch_time > 2) { 2.75 - char *cmd = concatenate(path, "data/dtms.mp3"); 2.76 system(cmd); 2.77 last_touch_time = now; 2.78 } 2.79 } 2.80 } 2.81 + 2.82 + free(cmd); 2.83 close(fd); 2.84 + 2.85 + return 0; 2.86 } 2.87 2.88 static int parse_args(int argc, char **argv) 2.89 @@ -99,39 +119,48 @@ 2.90 print_help(); 2.91 exit(0); 2.92 } 2.93 - if((strcmp(argv[i], "-p") == 0)) { 2.94 - if(argv[i+1]) { 2.95 - path = argv[i+1]; 2.96 + 2.97 + else if((strcmp(argv[i], "-p") == 0)) { 2.98 + if(argv[++i]) { 2.99 + player_path = argv[i]; 2.100 } 2.101 else { 2.102 fprintf(stderr, "Invalid path. Please give the absolute path to an mp3 player.\n"); 2.103 - exit(1); 2.104 + return -1; 2.105 } 2.106 } 2.107 2.108 - if((strcmp(argv[i], "-u") == 0)) { 2.109 - if(argv[i+1]) { 2.110 - struct passwd *passwd = getpwnam(argv[i+1]); 2.111 + else if((strcmp(argv[i], "-u") == 0)) { 2.112 + if(argv[++i]) { 2.113 + struct passwd *passwd = getpwnam(argv[i]); 2.114 if(!passwd) { 2.115 - fprintf(stderr, "Failed to get uid for: %s : %s.\n", argv[i+1], strerror(errno)); 2.116 - exit(1); 2.117 + fprintf(stderr, "Failed to get uid for: %s : %s.\n", argv[i], strerror(errno)); 2.118 + return -1; 2.119 } 2.120 uid = passwd->pw_uid; 2.121 + if(uid == 0) { 2.122 + fprintf(stderr, "You should pass an unprivileged username.\n"); 2.123 + return -1; 2.124 + } 2.125 } 2.126 else { 2.127 - fprintf(stderr, "Invalid username. Type -u `whoami`.\n"); 2.128 - exit(1); 2.129 + fprintf(stderr, "Missing username.\n"); 2.130 + return -1; 2.131 } 2.132 } 2.133 - if((strcmp(argv[i], "-d") == 0)) { 2.134 - if(argv[i+1]) { 2.135 - dev_path = argv[i+1]; 2.136 + else if((strcmp(argv[i], "-d") == 0)) { 2.137 + if(argv[++i]) { 2.138 + dev_path = argv[i]; 2.139 } 2.140 else { 2.141 fprintf(stderr, "Invalid device file.\n"); 2.142 - exit(1); 2.143 + return -1; 2.144 } 2.145 } 2.146 + else { 2.147 + fprintf(stderr, "Unknown argument: %s\n", argv[i]); 2.148 + return -1; 2.149 + } 2.150 } 2.151 return 0; 2.152 } 2.153 @@ -149,25 +178,16 @@ 2.154 printf("./dtms -d /dev/usb/hiddev0 -u eleni -p /usr/bin/mpv\n"); 2.155 } 2.156 2.157 -static void check_device(char *device_path) 2.158 +static int check_device(char *device_path) 2.159 { 2.160 struct stat sb; 2.161 if(stat(dev_path, &sb) == -1) { 2.162 perror("stat"); 2.163 - exit(0); 2.164 + return -1; 2.165 } 2.166 if(((sb.st_mode & S_IFMT) != S_IFBLK) && ((sb.st_mode & S_IFMT) != S_IFCHR)) { 2.167 - fprintf(stderr, "Invalid device file.\n"); 2.168 - exit(0); 2.169 + fprintf(stderr, "%s is not a device file.\n", device_path); 2.170 + return -1; 2.171 } 2.172 + return 0; 2.173 } 2.174 - 2.175 -static char *concatenate(char *mp_path, char *data_path) 2.176 -{ 2.177 - char *res = malloc(strlen(mp_path) + 1 + strlen(data_path) + 1); 2.178 - strcpy(res, mp_path); 2.179 - strcat(res, " "); 2.180 - strcat(res, data_path); 2.181 - 2.182 - return res; 2.183 -}