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