dtms

view src/main.c @ 4:db4bb4b5905a

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
line source
1 /*
2 * DTMS Copyright (C) 2016 Eleni Maria Stea <elene.mst@gmail.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 * */
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <pwd.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/select.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <time.h>
28 #include <unistd.h>
30 static int parse_args(int argc, char **argv);
31 static void print_help();
32 static int check_device(char *device_path);
34 static int uid = -1;
35 static char *player_path;
36 static char *dev_path;
38 #ifdef PREFIX
39 static const char* player_arg = PREFIX "/share/dtms/dtms.mp3";
40 #else
41 static const char* player_arg = "data/dtms.mp3";
42 #endif
44 int main(int argc, char **argv)
45 {
46 time_t last_touch_time = 0;
47 int fd;
49 if(parse_args(argc, argv) == -1)
50 return 1;
52 if(getuid() == 0 && uid == -1) {
53 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");
54 return 1;
55 }
57 if(check_device(dev_path) == -1)
58 return 1;
60 if((fd = open(dev_path, O_RDONLY | O_NONBLOCK)) == -1) {
61 fprintf(stderr, "Failed to open device: %s, error: %s\n", dev_path, strerror(errno));
62 return 1;
63 }
65 if(uid == -1) {
66 uid = getuid();
67 }
69 if(seteuid(uid) == -1) {
70 perror("Set uid failed");
71 return 1;
72 }
74 if(!uid) {
75 if(player_path[0] != '/') {
76 fprintf(stderr, "If you run this program as root you should pass the absolute path to a valid mp3 player.\n");
77 return 1;
78 }
79 }
81 char *cmd = malloc(strlen(player_path) + 1 + strlen(player_arg) + 1);
82 sprintf(cmd, "%s %s", player_path, player_arg);
84 while(1) {
85 fd_set read_set;
86 FD_ZERO(&read_set);
87 FD_SET(fd, &read_set);
89 int res;
90 while((res = select(fd + 1, &read_set, 0, 0, 0)) == -1 && errno == EINTR);
91 if(res < 0) {
92 perror("Select failed");
93 break;
94 }
95 if(res == 0) //nothing to read
96 continue;
98 if(FD_ISSET(fd, &read_set)) {
99 char buf[1024];
100 time_t now = time(0);
101 while(read(fd, buf, sizeof buf) > 0);
102 if (now - last_touch_time > 2) {
103 system(cmd);
104 last_touch_time = now;
105 }
106 }
107 }
109 free(cmd);
110 close(fd);
112 return 0;
113 }
115 static int parse_args(int argc, char **argv)
116 {
117 for(int i=1; i<argc; i++) {
118 if((strcmp(argv[i], "-h") == 0)) {
119 print_help();
120 exit(0);
121 }
123 else if((strcmp(argv[i], "-p") == 0)) {
124 if(argv[++i]) {
125 player_path = argv[i];
126 }
127 else {
128 fprintf(stderr, "Invalid path. Please give the absolute path to an mp3 player.\n");
129 return -1;
130 }
131 }
133 else if((strcmp(argv[i], "-u") == 0)) {
134 if(argv[++i]) {
135 struct passwd *passwd = getpwnam(argv[i]);
136 if(!passwd) {
137 fprintf(stderr, "Failed to get uid for: %s : %s.\n", argv[i], strerror(errno));
138 return -1;
139 }
140 uid = passwd->pw_uid;
141 if(uid == 0) {
142 fprintf(stderr, "You should pass an unprivileged username.\n");
143 return -1;
144 }
145 }
146 else {
147 fprintf(stderr, "Missing username.\n");
148 return -1;
149 }
150 }
151 else if((strcmp(argv[i], "-d") == 0)) {
152 if(argv[++i]) {
153 dev_path = argv[i];
154 }
155 else {
156 fprintf(stderr, "Invalid device file.\n");
157 return -1;
158 }
159 }
160 else {
161 fprintf(stderr, "Unknown argument: %s\n", argv[i]);
162 return -1;
163 }
164 }
165 return 0;
166 }
168 static void print_help()
169 {
170 printf("Options:\n");
171 printf("-h, prints this help\n");
172 printf("-d, path to the device\n");
173 printf("-p, path to the mp3 player\n");
174 printf("-u. username of the user that runs the program\n");
175 printf("--------\n");
176 printf("Examples:\n");
177 printf("--------\n");
178 printf("./dtms -d /dev/usb/hiddev0 -u eleni -p /usr/bin/mpv\n");
179 }
181 static int check_device(char *device_path)
182 {
183 struct stat sb;
184 if(stat(dev_path, &sb) == -1) {
185 perror("stat");
186 return -1;
187 }
188 if(((sb.st_mode & S_IFMT) != S_IFBLK) && ((sb.st_mode & S_IFMT) != S_IFCHR)) {
189 fprintf(stderr, "%s is not a device file.\n", device_path);
190 return -1;
191 }
192 return 0;
193 }