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
52static void __dead2
53usage(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
64static void
65printsig(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
81static void
82nosig(char *name)
83{
84
85	warnx("unknown signal %s; valid signals:", name);
86	printsig(stderr);
87	exit(1);
88}
89
90int
91main(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