1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org>
5 * Copyright (c) 2000 Paul Saab <ps@FreeBSD.org>
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/param.h>
31 #include <sys/jail.h>
32 #include <sys/stat.h>
33 #include <sys/uio.h>
34 #include <sys/user.h>
35 #include <sys/sysctl.h>
36 #include <fcntl.h>
37 #include <dirent.h>
38 #include <jail.h>
39 #include <stdint.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 strncmp(tty, "pts/", 4) == 0)
257 snprintf(buf, sizeof(buf), "/dev/%s", tty);
258 else
259 snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
260 if (stat(buf, &sb) < 0)
261 err(1, "stat(%s)", buf);
262 if (!S_ISCHR(sb.st_mode))
263 errx(1, "%s: not a character device", buf);
264 tdev = sb.st_rdev;
265 if (dflag)
266 printf("ttydev:0x%jx\n", (uintmax_t)tdev);
267 }
268 if (user) {
269 uid = strtol(user, &ep, 10);
270 if (*user == '\0' || *ep != '\0') { /* was it a number? */
271 pw = getpwnam(user);
272 if (pw == NULL)
273 errx(1, "user %s does not exist", user);
274 uid = pw->pw_uid;
275 if (dflag)
276 printf("uid:%d\n", uid);
277 }
278 } else {
279 uid = getuid();
280 if (uid != 0) {
281 pw = getpwuid(uid);
282 if (pw)
283 user = pw->pw_name;
284 if (dflag)
285 printf("uid:%d\n", uid);
286 }
287 }
288 size = 0;
289 mib[0] = CTL_KERN;
290 mib[1] = KERN_PROC;
291
292 if (user) {
293 mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID;
294 mib[3] = uid;
295 miblen = 4;
296 } else if (tty) {
297 mib[2] = KERN_PROC_TTY;
298 mib[3] = tdev;
299 miblen = 4;
300 } else {
301 mib[2] = KERN_PROC_PROC;
302 mib[3] = 0;
303 miblen = 3;
304 }
305
306 procs = NULL;
307 st = sysctl(mib, miblen, NULL, &size, NULL, 0);
308 do {
309 size += size / 10;
310 newprocs = realloc(procs, size);
311 if (newprocs == NULL) {
312 free(procs);
313 err(1, "could not reallocate memory");
314 }
315 procs = newprocs;
316 st = sysctl(mib, miblen, procs, &size, NULL, 0);
317 } while (st == -1 && errno == ENOMEM);
318 if (st == -1)
319 err(1, "could not sysctl(KERN_PROC)");
320 if (size % sizeof(struct kinfo_proc) != 0) {
321 fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n",
322 size, sizeof(struct kinfo_proc));
323 fprintf(stderr, "userland out of sync with kernel\n");
324 exit(1);
325 }
326 nprocs = size / sizeof(struct kinfo_proc);
327 if (dflag)
328 printf("nprocs %d\n", nprocs);
329 mypid = getpid();
330
331 for (i = 0; i < nprocs; i++) {
332 if (procs[i].ki_stat == SZOMB && !zflag)
333 continue;
334 thispid = procs[i].ki_pid;
335 strlcpy(thiscmd, procs[i].ki_comm, sizeof(thiscmd));
336 thistdev = procs[i].ki_tdev;
337 if (eflag)
338 thisuid = procs[i].ki_uid; /* effective uid */
339 else
340 thisuid = procs[i].ki_ruid; /* real uid */
341
342 if (thispid == mypid)
343 continue;
344 matched = 1;
345 if (user) {
346 if (thisuid != uid)
347 matched = 0;
348 }
349 if (tty) {
350 if (thistdev != tdev)
351 matched = 0;
352 }
353 if (cmd) {
354 if (mflag) {
355 if (regcomp(&rgx, cmd,
356 REG_EXTENDED|REG_NOSUB) != 0) {
357 mflag = 0;
358 warnx("%s: illegal regexp", cmd);
359 }
360 }
361 if (mflag) {
362 pmatch.rm_so = 0;
363 pmatch.rm_eo = strlen(thiscmd);
364 if (regexec(&rgx, thiscmd, 0, &pmatch,
365 REG_STARTEND) != 0)
366 matched = 0;
367 regfree(&rgx);
368 } else {
369 if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
370 matched = 0;
371 }
372 }
373 if (jflag && thispid == getpid())
374 matched = 0;
375 if (matched == 0)
376 continue;
377 if (ac > 0)
378 matched = 0;
379 for (j = 0; j < ac; j++) {
380 if (mflag) {
381 if (regcomp(&rgx, av[j],
382 REG_EXTENDED|REG_NOSUB) != 0) {
383 mflag = 0;
384 warnx("%s: illegal regexp", av[j]);
385 }
386 }
387 if (mflag) {
388 pmatch.rm_so = 0;
389 pmatch.rm_eo = strlen(thiscmd);
390 if (regexec(&rgx, thiscmd, 0, &pmatch,
391 REG_STARTEND) == 0)
392 matched = 1;
393 regfree(&rgx);
394 } else {
395 if (strcmp(thiscmd, av[j]) == 0)
396 matched = 1;
397 }
398 if (matched)
399 break;
400 }
401 if (matched != 0 && Iflag) {
402 printf("Send signal %d to %s (pid %d uid %d)? ",
403 sig, thiscmd, thispid, thisuid);
404 fflush(stdout);
405 first = ch = getchar();
406 while (ch != '\n' && ch != EOF)
407 ch = getchar();
408 if (first != 'y' && first != 'Y')
409 matched = 0;
410 }
411 if (matched == 0)
412 continue;
413 if (dflag)
414 printf("sig:%d, cmd:%s, pid:%d, dev:0x%jx uid:%d\n",
415 sig, thiscmd, thispid, (uintmax_t)thistdev,
416 thisuid);
417
418 if (vflag || sflag)
419 printf("kill -%s %d\n", sys_signame[sig], thispid);
420
421 killed++;
422 if (!dflag && !sflag) {
423 if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
424 warn("warning: kill -%s %d",
425 sys_signame[sig], thispid);
426 errors = 1;
427 }
428 }
429 }
430 if (killed == 0) {
431 if (!qflag)
432 fprintf(stderr, "No matching processes %swere found\n",
433 getuid() != 0 ? "belonging to you " : "");
434 errors = 1;
435 }
436 exit(errors);
437 }
438