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