1 /*-
2 * Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org>
3 * Copyright (c) 2000 Paul Saab <ps@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/jail.h>
33 #include <sys/stat.h>
34 #include <sys/uio.h>
35 #include <sys/user.h>
36 #include <sys/sysctl.h>
37 #include <fcntl.h>
38 #include <dirent.h>
39 #include <jail.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <pwd.h>
44 #include <signal.h>
45 #include <regex.h>
46 #include <ctype.h>
47 #include <err.h>
48 #include <errno.h>
49 #include <unistd.h>
50 #include <locale.h>
51
52 static void __dead2
usage(void)53 usage(void)
54 {
55
56 fprintf(stderr, "usage: killall [-delmsqvz] [-help] [-I] [-j jail]\n");
57 fprintf(stderr,
58 " [-u user] [-t tty] [-c cmd] [-SIGNAL] [cmd]...\n");
59 fprintf(stderr, "At least one option or argument to specify processes must be given.\n");
60 exit(1);
61 }
62
63
64 static void
printsig(FILE * fp)65 printsig(FILE *fp)
66 {
67 const char *const * p;
68 int cnt;
69 int offset = 0;
70
71 for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) {
72 offset += fprintf(fp, "%s ", *p);
73 if (offset >= 75 && cnt > 1) {
74 offset = 0;
75 fprintf(fp, "\n");
76 }
77 }
78 fprintf(fp, "\n");
79 }
80
81 static void
nosig(char * name)82 nosig(char *name)
83 {
84
85 warnx("unknown signal %s; valid signals:", name);
86 printsig(stderr);
87 exit(1);
88 }
89
90 int
main(int ac,char ** av)91 main(int ac, char **av)
92 {
93 char **saved_av;
94 struct kinfo_proc *procs, *newprocs;
95 struct stat sb;
96 struct passwd *pw;
97 regex_t rgx;
98 regmatch_t pmatch;
99 int i, j, ch;
100 char buf[256];
101 char first;
102 char *user = NULL;
103 char *tty = NULL;
104 char *cmd = NULL;
105 int qflag = 0;
106 int vflag = 0;
107 int sflag = 0;
108 int dflag = 0;
109 int eflag = 0;
110 int Iflag = 0;
111 int jflag = 0;
112 int mflag = 0;
113 int zflag = 0;
114 uid_t uid = 0;
115 dev_t tdev = 0;
116 pid_t mypid;
117 char thiscmd[MAXCOMLEN + 1];
118 pid_t thispid;
119 uid_t thisuid;
120 dev_t thistdev;
121 int sig = SIGTERM;
122 const char *const *p;
123 char *ep;
124 int errors = 0;
125 int jid;
126 int mib[4];
127 size_t miblen;
128 int st, nprocs;
129 size_t size;
130 int matched;
131 int killed = 0;
132
133 setlocale(LC_ALL, "");
134
135 av++;
136 ac--;
137
138 while (ac > 0) {
139 if (strcmp(*av, "-l") == 0) {
140 printsig(stdout);
141 exit(0);
142 }
143 if (strcmp(*av, "-help") == 0)
144 usage();
145 if (**av == '-') {
146 ++*av;
147 switch (**av) {
148 case 'j':
149 ++*av;
150 if (**av == '\0') {
151 ++av;
152 --ac;
153 }
154 jflag++;
155 if (*av == NULL)
156 errx(1, "must specify jail");
157 jid = jail_getid(*av);
158 if (jid < 0)
159 errx(1, "%s", jail_errmsg);
160 if (jail_attach(jid) == -1)
161 err(1, "jail_attach(%d)", jid);
162 break;
163 case 'u':
164 ++*av;
165 if (**av == '\0') {
166 ++av;
167 --ac;
168 }
169 if (*av == NULL)
170 errx(1, "must specify user");
171 user = *av;
172 break;
173 case 't':
174 ++*av;
175 if (**av == '\0') {
176 ++av;
177 --ac;
178 }
179 if (*av == NULL)
180 errx(1, "must specify tty");
181 tty = *av;
182 break;
183 case 'c':
184 ++*av;
185 if (**av == '\0') {
186 ++av;
187 --ac;
188 }
189 if (*av == NULL)
190 errx(1, "must specify procname");
191 cmd = *av;
192 break;
193 case 'q':
194 qflag++;
195 break;
196 case 'v':
197 vflag++;
198 break;
199 case 's':
200 sflag++;
201 break;
202 case 'd':
203 dflag++;
204 break;
205 case 'e':
206 eflag++;
207 break;
208 case 'm':
209 mflag++;
210 break;
211 case 'z':
212 zflag++;
213 break;
214 default:
215 saved_av = av;
216 if (isalpha((unsigned char)**av)) {
217 if (strncasecmp(*av, "SIG", 3) == 0)
218 *av += 3;
219 for (sig = NSIG, p = sys_signame + 1;
220 --sig; ++p)
221 if (strcasecmp(*p, *av) == 0) {
222 sig = p - sys_signame;
223 break;
224 }
225 if (!sig) {
226 if (**saved_av == 'I') {
227 av = saved_av;
228 Iflag = 1;
229 break;
230 } else
231 nosig(*av);
232 }
233 } else if (isdigit((unsigned char)**av)) {
234 sig = strtol(*av, &ep, 10);
235 if (!*av || *ep)
236 errx(1, "illegal signal number: %s", *av);
237 if (sig < 0 || sig >= NSIG)
238 nosig(*av);
239 } else
240 nosig(*av);
241 }
242 ++av;
243 --ac;
244 } else {
245 break;
246 }
247 }
248
249 if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0)
250 usage();
251
252 if (tty) {
253 if (strncmp(tty, "/dev/", 5) == 0)
254 snprintf(buf, sizeof(buf), "%s", tty);
255 else if (strncmp(tty, "tty", 3) == 0)
256 snprintf(buf, sizeof(buf), "/dev/%s", tty);
257 else
258 snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
259 if (stat(buf, &sb) < 0)
260 err(1, "stat(%s)", buf);
261 if (!S_ISCHR(sb.st_mode))
262 errx(1, "%s: not a character device", buf);
263 tdev = sb.st_rdev;
264 if (dflag)
265 printf("ttydev:0x%x\n", tdev);
266 }
267 if (user) {
268 uid = strtol(user, &ep, 10);
269 if (*user == '\0' || *ep != '\0') { /* was it a number? */
270 pw = getpwnam(user);
271 if (pw == NULL)
272 errx(1, "user %s does not exist", user);
273 uid = pw->pw_uid;
274 if (dflag)
275 printf("uid:%d\n", uid);
276 }
277 } else {
278 uid = getuid();
279 if (uid != 0) {
280 pw = getpwuid(uid);
281 if (pw)
282 user = pw->pw_name;
283 if (dflag)
284 printf("uid:%d\n", uid);
285 }
286 }
287 size = 0;
288 mib[0] = CTL_KERN;
289 mib[1] = KERN_PROC;
290
291 if (user) {
292 mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID;
293 mib[3] = uid;
294 miblen = 4;
295 } else if (tty) {
296 mib[2] = KERN_PROC_TTY;
297 mib[3] = tdev;
298 miblen = 4;
299 } else {
300 mib[2] = KERN_PROC_PROC;
301 mib[3] = 0;
302 miblen = 3;
303 }
304
305 procs = NULL;
306 st = sysctl(mib, miblen, NULL, &size, NULL, 0);
307 do {
308 size += size / 10;
309 newprocs = realloc(procs, size);
310 if (newprocs == NULL) {
311 free(procs);
312 err(1, "could not reallocate memory");
313 }
314 procs = newprocs;
315 st = sysctl(mib, miblen, procs, &size, NULL, 0);
316 } while (st == -1 && errno == ENOMEM);
317 if (st == -1)
318 err(1, "could not sysctl(KERN_PROC)");
319 if (size % sizeof(struct kinfo_proc) != 0) {
320 fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n",
321 size, sizeof(struct kinfo_proc));
322 fprintf(stderr, "userland out of sync with kernel\n");
323 exit(1);
324 }
325 nprocs = size / sizeof(struct kinfo_proc);
326 if (dflag)
327 printf("nprocs %d\n", nprocs);
328 mypid = getpid();
329
330 for (i = 0; i < nprocs; i++) {
331 if (procs[i].ki_stat == SZOMB && !zflag)
332 continue;
333 thispid = procs[i].ki_pid;
334 strlcpy(thiscmd, procs[i].ki_comm, sizeof(thiscmd));
335 thistdev = procs[i].ki_tdev;
336 if (eflag)
337 thisuid = procs[i].ki_uid; /* effective uid */
338 else
339 thisuid = procs[i].ki_ruid; /* real uid */
340
341 if (thispid == mypid)
342 continue;
343 matched = 1;
344 if (user) {
345 if (thisuid != uid)
346 matched = 0;
347 }
348 if (tty) {
349 if (thistdev != tdev)
350 matched = 0;
351 }
352 if (cmd) {
353 if (mflag) {
354 if (regcomp(&rgx, cmd,
355 REG_EXTENDED|REG_NOSUB) != 0) {
356 mflag = 0;
357 warnx("%s: illegal regexp", cmd);
358 }
359 }
360 if (mflag) {
361 pmatch.rm_so = 0;
362 pmatch.rm_eo = strlen(thiscmd);
363 if (regexec(&rgx, thiscmd, 0, &pmatch,
364 REG_STARTEND) != 0)
365 matched = 0;
366 regfree(&rgx);
367 } else {
368 if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
369 matched = 0;
370 }
371 }
372 if (jflag && thispid == getpid())
373 matched = 0;
374 if (matched == 0)
375 continue;
376 if (ac > 0)
377 matched = 0;
378 for (j = 0; j < ac; j++) {
379 if (mflag) {
380 if (regcomp(&rgx, av[j],
381 REG_EXTENDED|REG_NOSUB) != 0) {
382 mflag = 0;
383 warnx("%s: illegal regexp", av[j]);
384 }
385 }
386 if (mflag) {
387 pmatch.rm_so = 0;
388 pmatch.rm_eo = strlen(thiscmd);
389 if (regexec(&rgx, thiscmd, 0, &pmatch,
390 REG_STARTEND) == 0)
391 matched = 1;
392 regfree(&rgx);
393 } else {
394 if (strcmp(thiscmd, av[j]) == 0)
395 matched = 1;
396 }
397 if (matched)
398 break;
399 }
400 if (matched != 0 && Iflag) {
401 printf("Send signal %d to %s (pid %d uid %d)? ",
402 sig, thiscmd, thispid, thisuid);
403 fflush(stdout);
404 first = ch = getchar();
405 while (ch != '\n' && ch != EOF)
406 ch = getchar();
407 if (first != 'y' && first != 'Y')
408 matched = 0;
409 }
410 if (matched == 0)
411 continue;
412 if (dflag)
413 printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
414 thiscmd, thispid, thistdev, thisuid);
415
416 if (vflag || sflag)
417 printf("kill -%s %d\n", sys_signame[sig], thispid);
418
419 killed++;
420 if (!dflag && !sflag) {
421 if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
422 warn("warning: kill -%s %d",
423 sys_signame[sig], thispid);
424 errors = 1;
425 }
426 }
427 }
428 if (killed == 0) {
429 if (!qflag)
430 fprintf(stderr, "No matching processes %swere found\n",
431 getuid() != 0 ? "belonging to you " : "");
432 errors = 1;
433 }
434 exit(errors);
435 }
436