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
52static void __dead2
53usage(void)
54{
55
56	fprintf(stderr, "usage: killall [-delmsvz] [-help] [-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	struct kinfo_proc *procs, *newprocs;
94	struct stat	sb;
95	struct passwd	*pw;
96	regex_t		rgx;
97	regmatch_t	pmatch;
98	int		i, j;
99	char		buf[256];
100	char		*user = NULL;
101	char		*tty = NULL;
102	char		*cmd = NULL;
103	int		vflag = 0;
104	int		sflag = 0;
105	int		dflag = 0;
106	int		eflag = 0;
107	int		jflag = 0;
108	int		mflag = 0;
109	int		zflag = 0;
110	uid_t		uid = 0;
111	dev_t		tdev = 0;
112	pid_t		mypid;
113	char		thiscmd[MAXCOMLEN + 1];
114	pid_t		thispid;
115	uid_t		thisuid;
116	dev_t		thistdev;
117	int		sig = SIGTERM;
118	const char *const *p;
119	char		*ep;
120	int		errors = 0;
121	int		jid;
122	int		mib[4];
123	size_t		miblen;
124	int		st, nprocs;
125	size_t		size;
126	int		matched;
127	int		killed = 0;
128
129	setlocale(LC_ALL, "");
130
131	av++;
132	ac--;
133
134	while (ac > 0) {
135		if (strcmp(*av, "-l") == 0) {
136			printsig(stdout);
137			exit(0);
138		}
139		if (strcmp(*av, "-help") == 0)
140			usage();
141		if (**av == '-') {
142			++*av;
143			switch (**av) {
144			case 'j':
145				++*av;
146				if (**av == '\0') {
147					++av;
148					--ac;
149				}
150				jflag++;
151				if (*av == NULL)
152				    	errx(1, "must specify jail");
153				jid = jail_getid(*av);
154				if (jid < 0)
155					errx(1, "%s", jail_errmsg);
156				if (jail_attach(jid) == -1)
157					err(1, "jail_attach(%d)", jid);
158				break;
159			case 'u':
160				++*av;
161				if (**av == '\0') {
162					++av;
163					--ac;
164				}
165				if (*av == NULL)
166				    	errx(1, "must specify user");
167				user = *av;
168				break;
169			case 't':
170				++*av;
171				if (**av == '\0') {
172					++av;
173					--ac;
174				}
175				if (*av == NULL)
176				    	errx(1, "must specify tty");
177				tty = *av;
178				break;
179			case 'c':
180				++*av;
181				if (**av == '\0') {
182					++av;
183					--ac;
184				}
185				if (*av == NULL)
186				    	errx(1, "must specify procname");
187				cmd = *av;
188				break;
189			case 'v':
190				vflag++;
191				break;
192			case 's':
193				sflag++;
194				break;
195			case 'd':
196				dflag++;
197				break;
198			case 'e':
199				eflag++;
200				break;
201			case 'm':
202				mflag++;
203				break;
204			case 'z':
205				zflag++;
206				break;
207			default:
208				if (isalpha((unsigned char)**av)) {
209					if (strncasecmp(*av, "SIG", 3) == 0)
210						*av += 3;
211					for (sig = NSIG, p = sys_signame + 1;
212					     --sig; ++p)
213						if (strcasecmp(*p, *av) == 0) {
214							sig = p - sys_signame;
215							break;
216						}
217					if (!sig)
218						nosig(*av);
219				} else if (isdigit((unsigned char)**av)) {
220					sig = strtol(*av, &ep, 10);
221					if (!*av || *ep)
222						errx(1, "illegal signal number: %s", *av);
223					if (sig < 0 || sig >= NSIG)
224						nosig(*av);
225				} else
226					nosig(*av);
227			}
228			++av;
229			--ac;
230		} else {
231			break;
232		}
233	}
234
235	if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0)
236		usage();
237
238	if (tty) {
239		if (strncmp(tty, "/dev/", 5) == 0)
240			snprintf(buf, sizeof(buf), "%s", tty);
241		else if (strncmp(tty, "tty", 3) == 0)
242			snprintf(buf, sizeof(buf), "/dev/%s", tty);
243		else
244			snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
245		if (stat(buf, &sb) < 0)
246			err(1, "stat(%s)", buf);
247		if (!S_ISCHR(sb.st_mode))
248			errx(1, "%s: not a character device", buf);
249		tdev = sb.st_rdev;
250		if (dflag)
251			printf("ttydev:0x%x\n", tdev);
252	}
253	if (user) {
254		uid = strtol(user, &ep, 10);
255		if (*user == '\0' || *ep != '\0') { /* was it a number? */
256			pw = getpwnam(user);
257			if (pw == NULL)
258				errx(1, "user %s does not exist", user);
259			uid = pw->pw_uid;
260			if (dflag)
261				printf("uid:%d\n", uid);
262		}
263	} else {
264		uid = getuid();
265		if (uid != 0) {
266			pw = getpwuid(uid);
267			if (pw)
268				user = pw->pw_name;
269			if (dflag)
270				printf("uid:%d\n", uid);
271		}
272	}
273	size = 0;
274	mib[0] = CTL_KERN;
275	mib[1] = KERN_PROC;
276
277	if (user) {
278		mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID;
279		mib[3] = uid;
280		miblen = 4;
281	} else if (tty) {
282		mib[2] = KERN_PROC_TTY;
283		mib[3] = tdev;
284		miblen = 4;
285	} else {
286		mib[2] = KERN_PROC_PROC;
287		mib[3] = 0;
288		miblen = 3;
289	}
290
291	procs = NULL;
292	st = sysctl(mib, miblen, NULL, &size, NULL, 0);
293	do {
294		size += size / 10;
295		newprocs = realloc(procs, size);
296		if (newprocs == NULL) {
297			free(procs);
298			err(1, "could not reallocate memory");
299		}
300		procs = newprocs;
301		st = sysctl(mib, miblen, procs, &size, NULL, 0);
302	} while (st == -1 && errno == ENOMEM);
303	if (st == -1)
304		err(1, "could not sysctl(KERN_PROC)");
305	if (size % sizeof(struct kinfo_proc) != 0) {
306		fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n",
307			size, sizeof(struct kinfo_proc));
308		fprintf(stderr, "userland out of sync with kernel\n");
309		exit(1);
310	}
311	nprocs = size / sizeof(struct kinfo_proc);
312	if (dflag)
313		printf("nprocs %d\n", nprocs);
314	mypid = getpid();
315
316	for (i = 0; i < nprocs; i++) {
317		if (procs[i].ki_stat == SZOMB && !zflag)
318			continue;
319		thispid = procs[i].ki_pid;
320		strlcpy(thiscmd, procs[i].ki_comm, sizeof(thiscmd));
321		thistdev = procs[i].ki_tdev;
322		if (eflag)
323			thisuid = procs[i].ki_uid;	/* effective uid */
324		else
325			thisuid = procs[i].ki_ruid;	/* real uid */
326
327		if (thispid == mypid)
328			continue;
329		matched = 1;
330		if (user) {
331			if (thisuid != uid)
332				matched = 0;
333		}
334		if (tty) {
335			if (thistdev != tdev)
336				matched = 0;
337		}
338		if (cmd) {
339			if (mflag) {
340				if (regcomp(&rgx, cmd,
341				    REG_EXTENDED|REG_NOSUB) != 0) {
342					mflag = 0;
343					warnx("%s: illegal regexp", cmd);
344				}
345			}
346			if (mflag) {
347				pmatch.rm_so = 0;
348				pmatch.rm_eo = strlen(thiscmd);
349				if (regexec(&rgx, thiscmd, 0, &pmatch,
350				    REG_STARTEND) != 0)
351					matched = 0;
352				regfree(&rgx);
353			} else {
354				if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
355					matched = 0;
356			}
357		}
358		if (jflag && thispid == getpid())
359			matched = 0;
360		if (matched == 0)
361			continue;
362		if (ac > 0)
363			matched = 0;
364		for (j = 0; j < ac; j++) {
365			if (mflag) {
366				if (regcomp(&rgx, av[j],
367				    REG_EXTENDED|REG_NOSUB) != 0) {
368					mflag = 0;
369					warnx("%s: illegal regexp", av[j]);
370				}
371			}
372			if (mflag) {
373				pmatch.rm_so = 0;
374				pmatch.rm_eo = strlen(thiscmd);
375				if (regexec(&rgx, thiscmd, 0, &pmatch,
376				    REG_STARTEND) == 0)
377					matched = 1;
378				regfree(&rgx);
379			} else {
380				if (strcmp(thiscmd, av[j]) == 0)
381					matched = 1;
382			}
383			if (matched)
384				break;
385		}
386		if (matched == 0)
387			continue;
388		if (dflag)
389			printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
390			    thiscmd, thispid, thistdev, thisuid);
391
392		if (vflag || sflag)
393			printf("kill -%s %d\n", sys_signame[sig], thispid);
394
395		killed++;
396		if (!dflag && !sflag) {
397			if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
398				warn("warning: kill -%s %d",
399				    sys_signame[sig], thispid);
400				errors = 1;
401			}
402		}
403	}
404	if (killed == 0) {
405		fprintf(stderr, "No matching processes %swere found\n",
406		    getuid() != 0 ? "belonging to you " : "");
407		errors = 1;
408	}
409	exit(errors);
410}
411