xref: /netbsd-src/dist/pf/usr.sbin/authpf/authpf.c (revision 5dd7ea59adb8b4a7b03dc0f4a092bc52e52d737b)
1*5dd7ea59Schristos /*	$NetBSD: authpf.c,v 1.7 2008/12/29 04:13:28 christos Exp $	*/
2fff57c55Syamt /*	$OpenBSD: authpf.c,v 1.104 2007/02/24 17:35:08 beck Exp $	*/
3c03eb6b8Sitojun 
4c03eb6b8Sitojun /*
5fff57c55Syamt  * Copyright (C) 1998 - 2007 Bob Beck (beck@openbsd.org).
6c03eb6b8Sitojun  *
7fff57c55Syamt  * Permission to use, copy, modify, and distribute this software for any
8fff57c55Syamt  * purpose with or without fee is hereby granted, provided that the above
9fff57c55Syamt  * copyright notice and this permission notice appear in all copies.
10c03eb6b8Sitojun  *
11fff57c55Syamt  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12fff57c55Syamt  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13fff57c55Syamt  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14fff57c55Syamt  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15fff57c55Syamt  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16fff57c55Syamt  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17fff57c55Syamt  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18c03eb6b8Sitojun  */
19c03eb6b8Sitojun 
20c03eb6b8Sitojun #include <sys/types.h>
21c03eb6b8Sitojun #include <sys/file.h>
22c03eb6b8Sitojun #include <sys/ioctl.h>
23c03eb6b8Sitojun #include <sys/socket.h>
2423c8222eSyamt #include <sys/stat.h>
25c03eb6b8Sitojun #include <sys/time.h>
2623c8222eSyamt #include <sys/wait.h>
27c03eb6b8Sitojun 
28c03eb6b8Sitojun #include <net/if.h>
29c03eb6b8Sitojun #include <net/pfvar.h>
30c03eb6b8Sitojun #include <arpa/inet.h>
31c03eb6b8Sitojun 
32c03eb6b8Sitojun #include <err.h>
33c03eb6b8Sitojun #include <errno.h>
3423c8222eSyamt #include <login_cap.h>
35c03eb6b8Sitojun #include <pwd.h>
36c03eb6b8Sitojun #include <signal.h>
37c03eb6b8Sitojun #include <stdio.h>
38c03eb6b8Sitojun #include <stdlib.h>
39c03eb6b8Sitojun #include <string.h>
40c03eb6b8Sitojun #include <syslog.h>
41c03eb6b8Sitojun #include <unistd.h>
42c03eb6b8Sitojun 
43c03eb6b8Sitojun #include "pathnames.h"
44c03eb6b8Sitojun 
45c03eb6b8Sitojun static int	read_config(FILE *);
46c03eb6b8Sitojun static void	print_message(char *);
47c03eb6b8Sitojun static int	allowed_luser(char *);
48c03eb6b8Sitojun static int	check_luser(char *, char *);
49c03eb6b8Sitojun static int	remove_stale_rulesets(void);
50c03eb6b8Sitojun static int	change_filter(int, const char *, const char *);
51fff57c55Syamt static int	change_table(int, const char *);
52c03eb6b8Sitojun static void	authpf_kill_states(void);
53c03eb6b8Sitojun 
54c03eb6b8Sitojun int	dev;			/* pf device */
55c03eb6b8Sitojun char	anchorname[PF_ANCHOR_NAME_SIZE] = "authpf";
5623c8222eSyamt char	rulesetname[MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 2];
5723c8222eSyamt char	tablename[PF_TABLE_NAME_SIZE] = "authpf_users";
58c03eb6b8Sitojun 
59c03eb6b8Sitojun FILE	*pidfp;
60c03eb6b8Sitojun char	 luser[MAXLOGNAME];	/* username */
61c03eb6b8Sitojun char	 ipsrc[256];		/* ip as a string */
62c03eb6b8Sitojun char	 pidfile[MAXPATHLEN];	/* we save pid in this file. */
63c03eb6b8Sitojun 
64c03eb6b8Sitojun struct timeval	Tstart, Tend;	/* start and end times of session */
65c03eb6b8Sitojun 
66c03eb6b8Sitojun volatile sig_atomic_t	want_death;
67c03eb6b8Sitojun static void		need_death(int signo);
68c03eb6b8Sitojun static __dead void	do_death(int);
69c03eb6b8Sitojun 
70c03eb6b8Sitojun /*
71c03eb6b8Sitojun  * User shell for authenticating gateways. Sole purpose is to allow
72c03eb6b8Sitojun  * a user to ssh to a gateway, and have the gateway modify packet
73c03eb6b8Sitojun  * filters to allow access, then remove access when the user finishes
74c03eb6b8Sitojun  * up. Meant to be used only from ssh(1) connections.
75c03eb6b8Sitojun  */
76c03eb6b8Sitojun int
main(int argc,char * argv[])77c03eb6b8Sitojun main(int argc, char *argv[])
78c03eb6b8Sitojun {
79c03eb6b8Sitojun 	int		 lockcnt = 0, n, pidfd;
80c03eb6b8Sitojun 	FILE		*config;
8123c8222eSyamt 	struct in6_addr	 ina;
82c03eb6b8Sitojun 	struct passwd	*pw;
83c03eb6b8Sitojun 	char		*cp;
84fff57c55Syamt 	gid_t		 gid;
85c03eb6b8Sitojun 	uid_t		 uid;
8623c8222eSyamt 	char		*shell;
8723c8222eSyamt 	login_cap_t	*lc;
88c03eb6b8Sitojun 
89c03eb6b8Sitojun 	config = fopen(PATH_CONFFILE, "r");
90fff57c55Syamt 	if (config == NULL) {
91fff57c55Syamt 		syslog(LOG_ERR, "can not open %s (%m)", PATH_CONFFILE);
92fff57c55Syamt 		exit(1);
93fff57c55Syamt 	}
94c03eb6b8Sitojun 
95c03eb6b8Sitojun 	if ((cp = getenv("SSH_TTY")) == NULL) {
96c03eb6b8Sitojun 		syslog(LOG_ERR, "non-interactive session connection for authpf");
97c03eb6b8Sitojun 		exit(1);
98c03eb6b8Sitojun 	}
99c03eb6b8Sitojun 
100c03eb6b8Sitojun 	if ((cp = getenv("SSH_CLIENT")) == NULL) {
101c03eb6b8Sitojun 		syslog(LOG_ERR, "cannot determine connection source");
102c03eb6b8Sitojun 		exit(1);
103c03eb6b8Sitojun 	}
104c03eb6b8Sitojun 
105c03eb6b8Sitojun 	if (strlcpy(ipsrc, cp, sizeof(ipsrc)) >= sizeof(ipsrc)) {
106c03eb6b8Sitojun 		syslog(LOG_ERR, "SSH_CLIENT variable too long");
107c03eb6b8Sitojun 		exit(1);
108c03eb6b8Sitojun 	}
109c03eb6b8Sitojun 	cp = strchr(ipsrc, ' ');
110c03eb6b8Sitojun 	if (!cp) {
111c03eb6b8Sitojun 		syslog(LOG_ERR, "corrupt SSH_CLIENT variable %s", ipsrc);
112c03eb6b8Sitojun 		exit(1);
113c03eb6b8Sitojun 	}
114c03eb6b8Sitojun 	*cp = '\0';
11523c8222eSyamt 	if (inet_pton(AF_INET, ipsrc, &ina) != 1 &&
11623c8222eSyamt 	    inet_pton(AF_INET6, ipsrc, &ina) != 1) {
117c03eb6b8Sitojun 		syslog(LOG_ERR,
118c03eb6b8Sitojun 		    "cannot determine IP from SSH_CLIENT %s", ipsrc);
119c03eb6b8Sitojun 		exit(1);
120c03eb6b8Sitojun 	}
121c03eb6b8Sitojun 	/* open the pf device */
122c03eb6b8Sitojun 	dev = open(PATH_DEVFILE, O_RDWR);
123c03eb6b8Sitojun 	if (dev == -1) {
124c03eb6b8Sitojun 		syslog(LOG_ERR, "cannot open packet filter device (%m)");
125c03eb6b8Sitojun 		goto die;
126c03eb6b8Sitojun 	}
127c03eb6b8Sitojun 
128c03eb6b8Sitojun 	uid = getuid();
129c03eb6b8Sitojun 	pw = getpwuid(uid);
130c03eb6b8Sitojun 	if (pw == NULL) {
131c03eb6b8Sitojun 		syslog(LOG_ERR, "cannot find user for uid %u", uid);
132c03eb6b8Sitojun 		goto die;
133c03eb6b8Sitojun 	}
13423c8222eSyamt 
13523c8222eSyamt 	if ((lc = login_getclass(pw->pw_class)) != NULL)
13623c8222eSyamt 		shell = login_getcapstr(lc, "shell", pw->pw_shell,
13723c8222eSyamt 		    pw->pw_shell);
13823c8222eSyamt 	else
13923c8222eSyamt 		shell = pw->pw_shell;
14023c8222eSyamt 
14123c8222eSyamt 	login_close(lc);
14223c8222eSyamt 
14323c8222eSyamt 	if (strcmp(shell, PATH_AUTHPF_SHELL)) {
144c03eb6b8Sitojun 		syslog(LOG_ERR, "wrong shell for user %s, uid %u",
145c03eb6b8Sitojun 		    pw->pw_name, pw->pw_uid);
14623c8222eSyamt 		if (shell != pw->pw_shell)
14723c8222eSyamt 			free(shell);
148c03eb6b8Sitojun 		goto die;
149c03eb6b8Sitojun 	}
150c03eb6b8Sitojun 
15123c8222eSyamt 	if (shell != pw->pw_shell)
15223c8222eSyamt 		free(shell);
15323c8222eSyamt 
154c03eb6b8Sitojun 	/*
155c03eb6b8Sitojun 	 * Paranoia, but this data _does_ come from outside authpf, and
156c03eb6b8Sitojun 	 * truncation would be bad.
157c03eb6b8Sitojun 	 */
158c03eb6b8Sitojun 	if (strlcpy(luser, pw->pw_name, sizeof(luser)) >= sizeof(luser)) {
159c03eb6b8Sitojun 		syslog(LOG_ERR, "username too long: %s", pw->pw_name);
160c03eb6b8Sitojun 		goto die;
161c03eb6b8Sitojun 	}
162c03eb6b8Sitojun 
163c03eb6b8Sitojun 	if ((n = snprintf(rulesetname, sizeof(rulesetname), "%s(%ld)",
164f9967d10Speter 	    luser, (long)getpid())) < 0 || (u_int)n >= sizeof(rulesetname)) {
165c03eb6b8Sitojun 		syslog(LOG_INFO, "%s(%ld) too large, ruleset name will be %ld",
166c03eb6b8Sitojun 		    luser, (long)getpid(), (long)getpid());
167c03eb6b8Sitojun 		if ((n = snprintf(rulesetname, sizeof(rulesetname), "%ld",
168f9967d10Speter 		    (long)getpid())) < 0 || (u_int)n >= sizeof(rulesetname)) {
169c03eb6b8Sitojun 			syslog(LOG_ERR, "pid too large for ruleset name");
170c03eb6b8Sitojun 			goto die;
171c03eb6b8Sitojun 		}
172c03eb6b8Sitojun 	}
173c03eb6b8Sitojun 
174c03eb6b8Sitojun 
175c03eb6b8Sitojun 	/* Make our entry in /var/authpf as /var/authpf/ipaddr */
176c03eb6b8Sitojun 	n = snprintf(pidfile, sizeof(pidfile), "%s/%s", PATH_PIDFILE, ipsrc);
177c03eb6b8Sitojun 	if (n < 0 || (u_int)n >= sizeof(pidfile)) {
178c03eb6b8Sitojun 		syslog(LOG_ERR, "path to pidfile too long");
179c03eb6b8Sitojun 		goto die;
180c03eb6b8Sitojun 	}
181c03eb6b8Sitojun 
182c03eb6b8Sitojun 	/*
183c03eb6b8Sitojun 	 * If someone else is already using this ip, then this person
184c03eb6b8Sitojun 	 * wants to switch users - so kill the old process and exit
185c03eb6b8Sitojun 	 * as well.
186c03eb6b8Sitojun 	 *
187c03eb6b8Sitojun 	 * Note, we could print a message and tell them to log out, but the
188c03eb6b8Sitojun 	 * usual case of this is that someone has left themselves logged in,
189c03eb6b8Sitojun 	 * with the authenticated connection iconized and someone else walks
190c03eb6b8Sitojun 	 * up to use and automatically logs in before using. If this just
191c03eb6b8Sitojun 	 * gets rid of the old one silently, the new user never knows they
192c03eb6b8Sitojun 	 * could have used someone else's old authentication. If we
193c03eb6b8Sitojun 	 * tell them to log out before switching users it is an invitation
194c03eb6b8Sitojun 	 * for abuse.
195c03eb6b8Sitojun 	 */
196c03eb6b8Sitojun 
197c03eb6b8Sitojun 	do {
198c03eb6b8Sitojun 		int	save_errno, otherpid = -1;
199c03eb6b8Sitojun 		char	otherluser[MAXLOGNAME];
200c03eb6b8Sitojun 
201c03eb6b8Sitojun 		if ((pidfd = open(pidfile, O_RDWR|O_CREAT, 0644)) == -1 ||
202c03eb6b8Sitojun 		    (pidfp = fdopen(pidfd, "r+")) == NULL) {
203c03eb6b8Sitojun 			if (pidfd != -1)
204c03eb6b8Sitojun 				close(pidfd);
205c03eb6b8Sitojun 			syslog(LOG_ERR, "cannot open or create %s: %s", pidfile,
206c03eb6b8Sitojun 			    strerror(errno));
207c03eb6b8Sitojun 			goto die;
208c03eb6b8Sitojun 		}
209c03eb6b8Sitojun 
210c03eb6b8Sitojun 		if (flock(fileno(pidfp), LOCK_EX|LOCK_NB) == 0)
211c03eb6b8Sitojun 			break;
212c03eb6b8Sitojun 		save_errno = errno;
213c03eb6b8Sitojun 
214c03eb6b8Sitojun 		/* Mark our pid, and username to our file. */
215c03eb6b8Sitojun 
216c03eb6b8Sitojun 		rewind(pidfp);
217c03eb6b8Sitojun 		/* 31 == MAXLOGNAME - 1 */
218c03eb6b8Sitojun 		if (fscanf(pidfp, "%d\n%31s\n", &otherpid, otherluser) != 2)
219c03eb6b8Sitojun 			otherpid = -1;
220c03eb6b8Sitojun 		syslog(LOG_DEBUG, "tried to lock %s, in use by pid %d: %s",
221c03eb6b8Sitojun 		    pidfile, otherpid, strerror(save_errno));
222c03eb6b8Sitojun 
223c03eb6b8Sitojun 		if (otherpid > 0) {
224c03eb6b8Sitojun 			syslog(LOG_INFO,
225c03eb6b8Sitojun 			    "killing prior auth (pid %d) of %s by user %s",
226c03eb6b8Sitojun 			    otherpid, ipsrc, otherluser);
227c03eb6b8Sitojun 			if (kill((pid_t) otherpid, SIGTERM) == -1) {
228c03eb6b8Sitojun 				syslog(LOG_INFO,
229c03eb6b8Sitojun 				    "could not kill process %d: (%m)",
230c03eb6b8Sitojun 				    otherpid);
231c03eb6b8Sitojun 			}
232c03eb6b8Sitojun 		}
233c03eb6b8Sitojun 
234c03eb6b8Sitojun 		/*
235c03eb6b8Sitojun 		 * we try to kill the previous process and acquire the lock
236c03eb6b8Sitojun 		 * for 10 seconds, trying once a second. if we can't after
237c03eb6b8Sitojun 		 * 10 attempts we log an error and give up
238c03eb6b8Sitojun 		 */
239c03eb6b8Sitojun 		if (++lockcnt > 10) {
240c03eb6b8Sitojun 			syslog(LOG_ERR, "cannot kill previous authpf (pid %d)",
241c03eb6b8Sitojun 			    otherpid);
242fff57c55Syamt 			fclose(pidfp);
243fff57c55Syamt 			pidfp = NULL;
244c03eb6b8Sitojun 			goto dogdeath;
245c03eb6b8Sitojun 		}
246c03eb6b8Sitojun 		sleep(1);
247c03eb6b8Sitojun 
248c03eb6b8Sitojun 		/* re-open, and try again. The previous authpf process
249c03eb6b8Sitojun 		 * we killed above should unlink the file and release
250c03eb6b8Sitojun 		 * it's lock, giving us a chance to get it now
251c03eb6b8Sitojun 		 */
252c03eb6b8Sitojun 		fclose(pidfp);
253fff57c55Syamt 		pidfp = NULL;
254c03eb6b8Sitojun 	} while (1);
255c03eb6b8Sitojun 
256fff57c55Syamt 	/* whack the group list */
257fff57c55Syamt 	gid = getegid();
258fff57c55Syamt 	if (setgroups(1, &gid) == -1) {
259fff57c55Syamt 		syslog(LOG_INFO, "setgroups: %s", strerror(errno));
260fff57c55Syamt 		do_death(0);
261fff57c55Syamt 	}
262c03eb6b8Sitojun 
263fff57c55Syamt 	/* revoke privs */
264fff57c55Syamt 	uid = getuid();
265fff57c55Syamt #if defined(__OpenBSD__)
266fff57c55Syamt 	if (setresuid(uid, uid, uid) == -1) {
267fff57c55Syamt 		syslog(LOG_INFO, "setresuid: %s", strerror(errno));
268fff57c55Syamt 		do_death(0);
269fff57c55Syamt 	}
270fff57c55Syamt #else /* defined(__OpenBSD__) */
271fff57c55Syamt 	/* NetBSD */
272fff57c55Syamt 	if (setuid(uid) == -1) {
273fff57c55Syamt 		syslog(LOG_INFO, "setresuid: %s", strerror(errno));
274fff57c55Syamt 		do_death(0);
275fff57c55Syamt 	}
276fff57c55Syamt #endif /* defined(__OpenBSD__) */
277c03eb6b8Sitojun 	openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON);
278c03eb6b8Sitojun 
279c03eb6b8Sitojun 	if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser)) {
280c03eb6b8Sitojun 		syslog(LOG_INFO, "user %s prohibited", luser);
281c03eb6b8Sitojun 		do_death(0);
282c03eb6b8Sitojun 	}
283c03eb6b8Sitojun 
284fff57c55Syamt 	if (read_config(config)) {
285fff57c55Syamt 		syslog(LOG_ERR, "invalid config file %s", PATH_CONFFILE);
286c03eb6b8Sitojun 		do_death(0);
287c03eb6b8Sitojun 	}
288c03eb6b8Sitojun 
289c03eb6b8Sitojun 	if (remove_stale_rulesets()) {
290c03eb6b8Sitojun 		syslog(LOG_INFO, "error removing stale rulesets");
291c03eb6b8Sitojun 		do_death(0);
292c03eb6b8Sitojun 	}
293c03eb6b8Sitojun 
294c03eb6b8Sitojun 	/* We appear to be making headway, so actually mark our pid */
295c03eb6b8Sitojun 	rewind(pidfp);
296c03eb6b8Sitojun 	fprintf(pidfp, "%ld\n%s\n", (long)getpid(), luser);
297c03eb6b8Sitojun 	fflush(pidfp);
298f9967d10Speter 	(void) ftruncate(fileno(pidfp), ftello(pidfp));
299c03eb6b8Sitojun 
300c03eb6b8Sitojun 	if (change_filter(1, luser, ipsrc) == -1) {
301c03eb6b8Sitojun 		printf("Unable to modify filters\r\n");
302c03eb6b8Sitojun 		do_death(0);
303c03eb6b8Sitojun 	}
304fff57c55Syamt 	if (change_table(1, ipsrc) == -1) {
30523c8222eSyamt 		printf("Unable to modify table\r\n");
30623c8222eSyamt 		change_filter(0, luser, ipsrc);
30723c8222eSyamt 		do_death(0);
30823c8222eSyamt 	}
309c03eb6b8Sitojun 
310c03eb6b8Sitojun 	signal(SIGTERM, need_death);
311c03eb6b8Sitojun 	signal(SIGINT, need_death);
312c03eb6b8Sitojun 	signal(SIGALRM, need_death);
313c03eb6b8Sitojun 	signal(SIGPIPE, need_death);
314c03eb6b8Sitojun 	signal(SIGHUP, need_death);
315fff57c55Syamt 	signal(SIGQUIT, need_death);
316c03eb6b8Sitojun 	signal(SIGTSTP, need_death);
317c03eb6b8Sitojun 	while (1) {
318f9967d10Speter 		printf("\r\nHello %s. ", luser);
319c03eb6b8Sitojun 		printf("You are authenticated from host \"%s\"\r\n", ipsrc);
320c03eb6b8Sitojun 		setproctitle("%s@%s", luser, ipsrc);
321c03eb6b8Sitojun 		print_message(PATH_MESSAGE);
322c03eb6b8Sitojun 		while (1) {
323c03eb6b8Sitojun 			sleep(10);
324c03eb6b8Sitojun 			if (want_death)
325c03eb6b8Sitojun 				do_death(1);
326c03eb6b8Sitojun 		}
327c03eb6b8Sitojun 	}
328c03eb6b8Sitojun 
329c03eb6b8Sitojun 	/* NOTREACHED */
330c03eb6b8Sitojun dogdeath:
331c03eb6b8Sitojun 	printf("\r\n\r\nSorry, this service is currently unavailable due to ");
332c03eb6b8Sitojun 	printf("technical difficulties\r\n\r\n");
333c03eb6b8Sitojun 	print_message(PATH_PROBLEM);
334c03eb6b8Sitojun 	printf("\r\nYour authentication process (pid %ld) was unable to run\n",
335c03eb6b8Sitojun 	    (long)getpid());
336c03eb6b8Sitojun 	sleep(180); /* them lusers read reaaaaal slow */
337c03eb6b8Sitojun die:
338c03eb6b8Sitojun 	do_death(0);
339e3e62063Sitojun 	return (0);
340c03eb6b8Sitojun }
341c03eb6b8Sitojun 
342c03eb6b8Sitojun /*
343c03eb6b8Sitojun  * reads config file in PATH_CONFFILE to set optional behaviours up
344c03eb6b8Sitojun  */
345c03eb6b8Sitojun static int
read_config(FILE * f)346c03eb6b8Sitojun read_config(FILE *f)
347c03eb6b8Sitojun {
348c03eb6b8Sitojun 	char	buf[1024];
349c03eb6b8Sitojun 	int	i = 0;
350c03eb6b8Sitojun 
351c03eb6b8Sitojun 	do {
352c03eb6b8Sitojun 		char	**ap;
353c03eb6b8Sitojun 		char	 *pair[4], *cp, *tp;
354c03eb6b8Sitojun 		int	  len;
355c03eb6b8Sitojun 
356c03eb6b8Sitojun 		if (fgets(buf, sizeof(buf), f) == NULL) {
357c03eb6b8Sitojun 			fclose(f);
358c03eb6b8Sitojun 			return (0);
359c03eb6b8Sitojun 		}
360c03eb6b8Sitojun 		i++;
361c03eb6b8Sitojun 		len = strlen(buf);
362c03eb6b8Sitojun 		if (buf[len - 1] != '\n' && !feof(f)) {
363c03eb6b8Sitojun 			syslog(LOG_ERR, "line %d too long in %s", i,
364c03eb6b8Sitojun 			    PATH_CONFFILE);
365c03eb6b8Sitojun 			return (1);
366c03eb6b8Sitojun 		}
367c03eb6b8Sitojun 		buf[len - 1] = '\0';
368c03eb6b8Sitojun 
369c03eb6b8Sitojun 		for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
370c03eb6b8Sitojun 			; /* nothing */
371c03eb6b8Sitojun 
372c03eb6b8Sitojun 		if (!*cp || *cp == '#' || *cp == '\n')
373c03eb6b8Sitojun 			continue;
374c03eb6b8Sitojun 
375c03eb6b8Sitojun 		for (ap = pair; ap < &pair[3] &&
376c03eb6b8Sitojun 		    (*ap = strsep(&cp, "=")) != NULL; ) {
377c03eb6b8Sitojun 			if (**ap != '\0')
378c03eb6b8Sitojun 				ap++;
379c03eb6b8Sitojun 		}
380c03eb6b8Sitojun 		if (ap != &pair[2])
381c03eb6b8Sitojun 			goto parse_error;
382c03eb6b8Sitojun 
383c03eb6b8Sitojun 		tp = pair[1] + strlen(pair[1]);
384c03eb6b8Sitojun 		while ((*tp == ' ' || *tp == '\t') && tp >= pair[1])
385c03eb6b8Sitojun 			*tp-- = '\0';
386c03eb6b8Sitojun 
387c03eb6b8Sitojun 		if (strcasecmp(pair[0], "anchor") == 0) {
388c03eb6b8Sitojun 			if (!pair[1][0] || strlcpy(anchorname, pair[1],
389c03eb6b8Sitojun 			    sizeof(anchorname)) >= sizeof(anchorname))
390c03eb6b8Sitojun 				goto parse_error;
391c03eb6b8Sitojun 		}
39223c8222eSyamt 		if (strcasecmp(pair[0], "table") == 0) {
39323c8222eSyamt 			if (!pair[1][0] || strlcpy(tablename, pair[1],
39423c8222eSyamt 			    sizeof(tablename)) >= sizeof(tablename))
39523c8222eSyamt 				goto parse_error;
39623c8222eSyamt 		}
397c03eb6b8Sitojun 	} while (!feof(f) && !ferror(f));
398c03eb6b8Sitojun 	fclose(f);
399c03eb6b8Sitojun 	return (0);
400c03eb6b8Sitojun 
401c03eb6b8Sitojun parse_error:
402c03eb6b8Sitojun 	fclose(f);
403c03eb6b8Sitojun 	syslog(LOG_ERR, "parse error, line %d of %s", i, PATH_CONFFILE);
404c03eb6b8Sitojun 	return (1);
405c03eb6b8Sitojun }
406c03eb6b8Sitojun 
407c03eb6b8Sitojun 
408c03eb6b8Sitojun /*
409c03eb6b8Sitojun  * splatter a file to stdout - max line length of 1024,
410c03eb6b8Sitojun  * used for spitting message files at users to tell them
411c03eb6b8Sitojun  * they've been bad or we're unavailable.
412c03eb6b8Sitojun  */
413c03eb6b8Sitojun static void
print_message(char * filename)414c03eb6b8Sitojun print_message(char *filename)
415c03eb6b8Sitojun {
416c03eb6b8Sitojun 	char	 buf[1024];
417c03eb6b8Sitojun 	FILE	*f;
418c03eb6b8Sitojun 
419c03eb6b8Sitojun 	if ((f = fopen(filename, "r")) == NULL)
420c03eb6b8Sitojun 		return; /* fail silently, we don't care if it isn't there */
421c03eb6b8Sitojun 
422c03eb6b8Sitojun 	do {
423c03eb6b8Sitojun 		if (fgets(buf, sizeof(buf), f) == NULL) {
424c03eb6b8Sitojun 			fflush(stdout);
425c03eb6b8Sitojun 			fclose(f);
426c03eb6b8Sitojun 			return;
427c03eb6b8Sitojun 		}
428c03eb6b8Sitojun 	} while (fputs(buf, stdout) != EOF && !feof(f));
429c03eb6b8Sitojun 	fflush(stdout);
430c03eb6b8Sitojun 	fclose(f);
431c03eb6b8Sitojun }
432c03eb6b8Sitojun 
433c03eb6b8Sitojun /*
434c03eb6b8Sitojun  * allowed_luser checks to see if user "luser" is allowed to
435c03eb6b8Sitojun  * use this gateway by virtue of being listed in an allowed
436c03eb6b8Sitojun  * users file, namely /etc/authpf/authpf.allow .
437c03eb6b8Sitojun  *
438c03eb6b8Sitojun  * If /etc/authpf/authpf.allow does not exist, then we assume that
439c03eb6b8Sitojun  * all users who are allowed in by sshd(8) are permitted to
440c03eb6b8Sitojun  * use this gateway. If /etc/authpf/authpf.allow does exist, then a
441c03eb6b8Sitojun  * user must be listed if the connection is to continue, else
442c03eb6b8Sitojun  * the session terminates in the same manner as being banned.
443c03eb6b8Sitojun  */
444c03eb6b8Sitojun static int
allowed_luser(char * luser)445c03eb6b8Sitojun allowed_luser(char *luser)
446c03eb6b8Sitojun {
447c03eb6b8Sitojun 	char	*buf, *lbuf;
448c03eb6b8Sitojun 	int	 matched;
449c03eb6b8Sitojun 	size_t	 len;
450c03eb6b8Sitojun 	FILE	*f;
451c03eb6b8Sitojun 
452c03eb6b8Sitojun 	if ((f = fopen(PATH_ALLOWFILE, "r")) == NULL) {
453c03eb6b8Sitojun 		if (errno == ENOENT) {
454c03eb6b8Sitojun 			/*
455c03eb6b8Sitojun 			 * allowfile doesn't exist, thus this gateway
456c03eb6b8Sitojun 			 * isn't restricted to certain users...
457c03eb6b8Sitojun 			 */
458c03eb6b8Sitojun 			return (1);
459c03eb6b8Sitojun 		}
460c03eb6b8Sitojun 
461c03eb6b8Sitojun 		/*
462c03eb6b8Sitojun 		 * luser may in fact be allowed, but we can't open
463c03eb6b8Sitojun 		 * the file even though it's there. probably a config
464c03eb6b8Sitojun 		 * problem.
465c03eb6b8Sitojun 		 */
466c03eb6b8Sitojun 		syslog(LOG_ERR, "cannot open allowed users file %s (%s)",
467c03eb6b8Sitojun 		    PATH_ALLOWFILE, strerror(errno));
468c03eb6b8Sitojun 		return (0);
469c03eb6b8Sitojun 	} else {
470c03eb6b8Sitojun 		/*
471c03eb6b8Sitojun 		 * /etc/authpf/authpf.allow exists, thus we do a linear
472c03eb6b8Sitojun 		 * search to see if they are allowed.
473c03eb6b8Sitojun 		 * also, if username "*" exists, then this is a
474c03eb6b8Sitojun 		 * "public" gateway, such as it is, so let
475c03eb6b8Sitojun 		 * everyone use it.
476c03eb6b8Sitojun 		 */
477c03eb6b8Sitojun 		lbuf = NULL;
478c03eb6b8Sitojun 		while ((buf = fgetln(f, &len))) {
479c03eb6b8Sitojun 			if (buf[len - 1] == '\n')
480c03eb6b8Sitojun 				buf[len - 1] = '\0';
481c03eb6b8Sitojun 			else {
482c03eb6b8Sitojun 				if ((lbuf = (char *)malloc(len + 1)) == NULL)
483c03eb6b8Sitojun 					err(1, NULL);
484c03eb6b8Sitojun 				memcpy(lbuf, buf, len);
485c03eb6b8Sitojun 				lbuf[len] = '\0';
486c03eb6b8Sitojun 				buf = lbuf;
487c03eb6b8Sitojun 			}
488c03eb6b8Sitojun 
489c03eb6b8Sitojun 			matched = strcmp(luser, buf) == 0 || strcmp("*", buf) == 0;
490c03eb6b8Sitojun 
491c03eb6b8Sitojun 			if (lbuf != NULL) {
492c03eb6b8Sitojun 				free(lbuf);
493c03eb6b8Sitojun 				lbuf = NULL;
494c03eb6b8Sitojun 			}
495c03eb6b8Sitojun 
496c03eb6b8Sitojun 			if (matched)
497c03eb6b8Sitojun 				return (1); /* matched an allowed username */
498c03eb6b8Sitojun 		}
499c03eb6b8Sitojun 		syslog(LOG_INFO, "denied access to %s: not listed in %s",
500c03eb6b8Sitojun 		    luser, PATH_ALLOWFILE);
501c03eb6b8Sitojun 
502c03eb6b8Sitojun 		/* reuse buf */
503c03eb6b8Sitojun 		buf = "\n\nSorry, you are not allowed to use this facility!\n";
504c03eb6b8Sitojun 		fputs(buf, stdout);
505c03eb6b8Sitojun 	}
506c03eb6b8Sitojun 	fflush(stdout);
507c03eb6b8Sitojun 	return (0);
508c03eb6b8Sitojun }
509c03eb6b8Sitojun 
510c03eb6b8Sitojun /*
511c03eb6b8Sitojun  * check_luser checks to see if user "luser" has been banned
512c03eb6b8Sitojun  * from using us by virtue of having an file of the same name
513c03eb6b8Sitojun  * in the "luserdir" directory.
514c03eb6b8Sitojun  *
515c03eb6b8Sitojun  * If the user has been banned, we copy the contents of the file
516c03eb6b8Sitojun  * to the user's screen. (useful for telling the user what to
517c03eb6b8Sitojun  * do to get un-banned, or just to tell them they aren't
518c03eb6b8Sitojun  * going to be un-banned.)
519c03eb6b8Sitojun  */
520c03eb6b8Sitojun static int
check_luser(char * luserdir,char * luser)521c03eb6b8Sitojun check_luser(char *luserdir, char *luser)
522c03eb6b8Sitojun {
523c03eb6b8Sitojun 	FILE	*f;
524c03eb6b8Sitojun 	int	 n;
525c03eb6b8Sitojun 	char	 tmp[MAXPATHLEN];
526c03eb6b8Sitojun 
527c03eb6b8Sitojun 	n = snprintf(tmp, sizeof(tmp), "%s/%s", luserdir, luser);
528c03eb6b8Sitojun 	if (n < 0 || (u_int)n >= sizeof(tmp)) {
529c03eb6b8Sitojun 		syslog(LOG_ERR, "provided banned directory line too long (%s)",
530c03eb6b8Sitojun 		    luserdir);
531c03eb6b8Sitojun 		return (0);
532c03eb6b8Sitojun 	}
533c03eb6b8Sitojun 	if ((f = fopen(tmp, "r")) == NULL) {
534c03eb6b8Sitojun 		if (errno == ENOENT) {
535c03eb6b8Sitojun 			/*
536c03eb6b8Sitojun 			 * file or dir doesn't exist, so therefore
537c03eb6b8Sitojun 			 * this luser isn't banned..  all is well
538c03eb6b8Sitojun 			 */
539c03eb6b8Sitojun 			return (1);
540c03eb6b8Sitojun 		} else {
541c03eb6b8Sitojun 			/*
542c03eb6b8Sitojun 			 * luser may in fact be banned, but we can't open the
543c03eb6b8Sitojun 			 * file even though it's there. probably a config
544c03eb6b8Sitojun 			 * problem.
545c03eb6b8Sitojun 			 */
546c03eb6b8Sitojun 			syslog(LOG_ERR, "cannot open banned file %s (%s)",
547c03eb6b8Sitojun 			    tmp, strerror(errno));
548c03eb6b8Sitojun 			return (0);
549c03eb6b8Sitojun 		}
550c03eb6b8Sitojun 	} else {
551c03eb6b8Sitojun 		/*
552c03eb6b8Sitojun 		 * luser is banned - spit the file at them to
553c03eb6b8Sitojun 		 * tell what they can do and where they can go.
554c03eb6b8Sitojun 		 */
555c03eb6b8Sitojun 		syslog(LOG_INFO, "denied access to %s: %s exists",
556c03eb6b8Sitojun 		    luser, tmp);
557c03eb6b8Sitojun 
558c03eb6b8Sitojun 		/* reuse tmp */
559c03eb6b8Sitojun 		strlcpy(tmp, "\n\n-**- Sorry, you have been banned! -**-\n\n",
560c03eb6b8Sitojun 		    sizeof(tmp));
561c03eb6b8Sitojun 		while (fputs(tmp, stdout) != EOF && !feof(f)) {
562c03eb6b8Sitojun 			if (fgets(tmp, sizeof(tmp), f) == NULL) {
563c03eb6b8Sitojun 				fflush(stdout);
564fff57c55Syamt 				fclose(f);
565c03eb6b8Sitojun 				return (0);
566c03eb6b8Sitojun 			}
567c03eb6b8Sitojun 		}
56811f7fb17Speter 		fclose(f);
569c03eb6b8Sitojun 	}
570c03eb6b8Sitojun 	fflush(stdout);
571c03eb6b8Sitojun 	return (0);
572c03eb6b8Sitojun }
573c03eb6b8Sitojun 
574c03eb6b8Sitojun /*
575c03eb6b8Sitojun  * Search for rulesets left by other authpf processes (either because they
576c03eb6b8Sitojun  * died ungracefully or were terminated) and remove them.
577c03eb6b8Sitojun  */
578c03eb6b8Sitojun static int
remove_stale_rulesets(void)579c03eb6b8Sitojun remove_stale_rulesets(void)
580c03eb6b8Sitojun {
581c03eb6b8Sitojun 	struct pfioc_ruleset	 prs;
582c03eb6b8Sitojun 	u_int32_t		 nr, mnr;
583c03eb6b8Sitojun 
584c03eb6b8Sitojun 	memset(&prs, 0, sizeof(prs));
58523c8222eSyamt 	strlcpy(prs.path, anchorname, sizeof(prs.path));
586c03eb6b8Sitojun 	if (ioctl(dev, DIOCGETRULESETS, &prs)) {
587c03eb6b8Sitojun 		if (errno == EINVAL)
588c03eb6b8Sitojun 			return (0);
589c03eb6b8Sitojun 		else
590c03eb6b8Sitojun 			return (1);
591c03eb6b8Sitojun 	}
592c03eb6b8Sitojun 
593c03eb6b8Sitojun 	mnr = prs.nr;
594c03eb6b8Sitojun 	nr = 0;
595c03eb6b8Sitojun 	while (nr < mnr) {
596c03eb6b8Sitojun 		char	*s, *t;
597c03eb6b8Sitojun 		pid_t	 pid;
598c03eb6b8Sitojun 
599c03eb6b8Sitojun 		prs.nr = nr;
600c03eb6b8Sitojun 		if (ioctl(dev, DIOCGETRULESET, &prs))
601c03eb6b8Sitojun 			return (1);
602c03eb6b8Sitojun 		errno = 0;
603c03eb6b8Sitojun 		if ((t = strchr(prs.name, '(')) == NULL)
604c03eb6b8Sitojun 			t = prs.name;
605c03eb6b8Sitojun 		else
606c03eb6b8Sitojun 			t++;
607c03eb6b8Sitojun 		pid = strtoul(t, &s, 10);
608c03eb6b8Sitojun 		if (!prs.name[0] || errno ||
609c03eb6b8Sitojun 		    (*s && (t == prs.name || *s != ')')))
610c03eb6b8Sitojun 			return (1);
611c03eb6b8Sitojun 		if (kill(pid, 0) && errno != EPERM) {
612c03eb6b8Sitojun 			int			i;
61323c8222eSyamt 			struct pfioc_trans_e	t_e[PF_RULESET_MAX+1];
61423c8222eSyamt 			struct pfioc_trans	t;
615c03eb6b8Sitojun 
61623c8222eSyamt 			bzero(&t, sizeof(t));
61723c8222eSyamt 			bzero(t_e, sizeof(t_e));
61823c8222eSyamt 			t.size = PF_RULESET_MAX+1;
61923c8222eSyamt 			t.esize = sizeof(t_e[0]);
62023c8222eSyamt 			t.array = t_e;
62123c8222eSyamt 			for (i = 0; i < PF_RULESET_MAX+1; ++i) {
62223c8222eSyamt 				t_e[i].rs_num = i;
62323c8222eSyamt 				snprintf(t_e[i].anchor, sizeof(t_e[i].anchor),
62423c8222eSyamt 				    "%s/%s", anchorname, prs.name);
62523c8222eSyamt 			}
62623c8222eSyamt 			t_e[PF_RULESET_MAX].rs_num = PF_RULESET_TABLE;
62723c8222eSyamt 			if ((ioctl(dev, DIOCXBEGIN, &t) ||
62823c8222eSyamt 			    ioctl(dev, DIOCXCOMMIT, &t)) &&
629c03eb6b8Sitojun 			    errno != EINVAL)
630c03eb6b8Sitojun 				return (1);
631c03eb6b8Sitojun 			mnr--;
632c03eb6b8Sitojun 		} else
633c03eb6b8Sitojun 			nr++;
634c03eb6b8Sitojun 	}
635c03eb6b8Sitojun 	return (0);
636c03eb6b8Sitojun }
637c03eb6b8Sitojun 
638c03eb6b8Sitojun /*
639c03eb6b8Sitojun  * Add/remove filter entries for user "luser" from ip "ipsrc"
640c03eb6b8Sitojun  */
641c03eb6b8Sitojun static int
change_filter(int add,const char * luser,const char * ipsrc)642c03eb6b8Sitojun change_filter(int add, const char *luser, const char *ipsrc)
643c03eb6b8Sitojun {
64423c8222eSyamt 	char	*pargv[13] = {
64523c8222eSyamt 		"pfctl", "-p", "/dev/pf", "-q", "-a", "anchor/ruleset",
64623c8222eSyamt 		"-D", "user_ip=X", "-D", "user_id=X", "-f",
64723c8222eSyamt 		"file", NULL
64823c8222eSyamt 	};
64923c8222eSyamt 	char	*fdpath = NULL, *userstr = NULL, *ipstr = NULL;
65023c8222eSyamt 	char	*rsn = NULL, *fn = NULL;
65123c8222eSyamt 	pid_t	pid;
652fff57c55Syamt 	gid_t   gid;
65323c8222eSyamt 	int	s;
654c03eb6b8Sitojun 
655c03eb6b8Sitojun 	if (luser == NULL || !luser[0] || ipsrc == NULL || !ipsrc[0]) {
656c03eb6b8Sitojun 		syslog(LOG_ERR, "invalid luser/ipsrc");
657c03eb6b8Sitojun 		goto error;
658c03eb6b8Sitojun 	}
659c03eb6b8Sitojun 
66023c8222eSyamt 	if (asprintf(&rsn, "%s/%s", anchorname, rulesetname) == -1)
66123c8222eSyamt 		goto no_mem;
66223c8222eSyamt 	if (asprintf(&fdpath, "/dev/fd/%d", dev) == -1)
66323c8222eSyamt 		goto no_mem;
66423c8222eSyamt 	if (asprintf(&ipstr, "user_ip=%s", ipsrc) == -1)
66523c8222eSyamt 		goto no_mem;
66623c8222eSyamt 	if (asprintf(&userstr, "user_id=%s", luser) == -1)
66723c8222eSyamt 		goto no_mem;
668c03eb6b8Sitojun 
669c03eb6b8Sitojun 	if (add) {
67023c8222eSyamt 		struct stat sb;
67123c8222eSyamt 
67223c8222eSyamt 		if (asprintf(&fn, "%s/%s/authpf.rules", PATH_USER_DIR, luser)
67323c8222eSyamt 		    == -1)
67423c8222eSyamt 			goto no_mem;
67523c8222eSyamt 		if (stat(fn, &sb) == -1) {
67623c8222eSyamt 			free(fn);
67723c8222eSyamt 			if ((fn = strdup(PATH_PFRULES)) == NULL)
67823c8222eSyamt 				goto no_mem;
67923c8222eSyamt 		}
68023c8222eSyamt 	}
68123c8222eSyamt 	pargv[2] = fdpath;
68223c8222eSyamt 	pargv[5] = rsn;
68323c8222eSyamt 	pargv[7] = userstr;
68423c8222eSyamt 	pargv[9] = ipstr;
68523c8222eSyamt 	if (!add)
68623c8222eSyamt 		pargv[11] = "/dev/null";
68723c8222eSyamt 	else
68823c8222eSyamt 		pargv[11] = fn;
68923c8222eSyamt 
69023c8222eSyamt 	switch (pid = fork()) {
69123c8222eSyamt 	case -1:
692fff57c55Syamt 		syslog(LOG_ERR, "fork failed");
693fff57c55Syamt 		goto error;
69423c8222eSyamt 	case 0:
695fff57c55Syamt 		/* revoke group privs before exec */
696fff57c55Syamt 		gid = getgid();
697fff57c55Syamt 		if (setregid(gid, gid) == -1) {
698fff57c55Syamt 			err(1, "setregid");
699fff57c55Syamt 		}
70023c8222eSyamt 		execvp(PATH_PFCTL, pargv);
701f9967d10Speter 		warn("exec of %s failed", PATH_PFCTL);
702f9967d10Speter 		_exit(1);
703c03eb6b8Sitojun 	}
704c03eb6b8Sitojun 
70523c8222eSyamt 	/* parent */
70623c8222eSyamt 	waitpid(pid, &s, 0);
70723c8222eSyamt 	if (s != 0) {
70823c8222eSyamt 		syslog(LOG_ERR, "pfctl exited abnormally");
709c03eb6b8Sitojun 		goto error;
710c03eb6b8Sitojun 	}
711c03eb6b8Sitojun 
712c03eb6b8Sitojun 	if (add) {
713c03eb6b8Sitojun 		gettimeofday(&Tstart, NULL);
714c03eb6b8Sitojun 		syslog(LOG_INFO, "allowing %s, user %s", ipsrc, luser);
715c03eb6b8Sitojun 	} else {
716c03eb6b8Sitojun 		gettimeofday(&Tend, NULL);
717*5dd7ea59Schristos 		syslog(LOG_INFO, "removed %s, user %s - duration %lld seconds",
718*5dd7ea59Schristos 		    ipsrc, luser, (long long)(Tend.tv_sec - Tstart.tv_sec));
719c03eb6b8Sitojun 	}
720c03eb6b8Sitojun 	return (0);
72123c8222eSyamt no_mem:
72223c8222eSyamt 	syslog(LOG_ERR, "malloc failed");
723c03eb6b8Sitojun error:
72423c8222eSyamt 	free(fdpath);
72523c8222eSyamt 	free(rsn);
72623c8222eSyamt 	free(userstr);
72723c8222eSyamt 	free(ipstr);
72823c8222eSyamt 	free(fn);
729c03eb6b8Sitojun 	return (-1);
730c03eb6b8Sitojun }
731c03eb6b8Sitojun 
732c03eb6b8Sitojun /*
73323c8222eSyamt  * Add/remove this IP from the "authpf_users" table.
73423c8222eSyamt  */
73523c8222eSyamt static int
change_table(int add,const char * ipsrc)736fff57c55Syamt change_table(int add, const char *ipsrc)
73723c8222eSyamt {
73823c8222eSyamt 	struct pfioc_table	io;
73923c8222eSyamt 	struct pfr_addr		addr;
74023c8222eSyamt 
74123c8222eSyamt 	bzero(&io, sizeof(io));
742fff57c55Syamt 	strlcpy(io.pfrio_table.pfrt_name, tablename,
743fff57c55Syamt 	    sizeof(io.pfrio_table.pfrt_name));
74423c8222eSyamt 	io.pfrio_buffer = &addr;
74523c8222eSyamt 	io.pfrio_esize = sizeof(addr);
74623c8222eSyamt 	io.pfrio_size = 1;
74723c8222eSyamt 
74823c8222eSyamt 	bzero(&addr, sizeof(addr));
74923c8222eSyamt 	if (ipsrc == NULL || !ipsrc[0])
75023c8222eSyamt 		return (-1);
75123c8222eSyamt 	if (inet_pton(AF_INET, ipsrc, &addr.pfra_ip4addr) == 1) {
75223c8222eSyamt 		addr.pfra_af = AF_INET;
75323c8222eSyamt 		addr.pfra_net = 32;
75423c8222eSyamt 	} else if (inet_pton(AF_INET6, ipsrc, &addr.pfra_ip6addr) == 1) {
75523c8222eSyamt 		addr.pfra_af = AF_INET6;
75623c8222eSyamt 		addr.pfra_net = 128;
75723c8222eSyamt 	} else {
75823c8222eSyamt 		syslog(LOG_ERR, "invalid ipsrc");
75923c8222eSyamt 		return (-1);
76023c8222eSyamt 	}
76123c8222eSyamt 
76223c8222eSyamt 	if (ioctl(dev, add ? DIOCRADDADDRS : DIOCRDELADDRS, &io) &&
76323c8222eSyamt 	    errno != ESRCH) {
76423c8222eSyamt 		syslog(LOG_ERR, "cannot %s %s from table %s: %s",
76523c8222eSyamt 		    add ? "add" : "remove", ipsrc, tablename,
76623c8222eSyamt 		    strerror(errno));
76723c8222eSyamt 		return (-1);
76823c8222eSyamt 	}
76923c8222eSyamt 	return (0);
77023c8222eSyamt }
77123c8222eSyamt 
77223c8222eSyamt /*
773c03eb6b8Sitojun  * This is to kill off states that would otherwise be left behind stateful
774c03eb6b8Sitojun  * rules. This means we don't need to allow in more traffic than we really
775c03eb6b8Sitojun  * want to, since we don't have to worry about any luser sessions lasting
776c03eb6b8Sitojun  * longer than their ssh session. This function is based on
777c03eb6b8Sitojun  * pfctl_kill_states from pfctl.
778c03eb6b8Sitojun  */
779c03eb6b8Sitojun static void
authpf_kill_states(void)780c03eb6b8Sitojun authpf_kill_states(void)
781c03eb6b8Sitojun {
782c03eb6b8Sitojun 	struct pfioc_state_kill	psk;
78323c8222eSyamt 	struct pf_addr target;
784c03eb6b8Sitojun 
785c03eb6b8Sitojun 	memset(&psk, 0, sizeof(psk));
78623c8222eSyamt 	memset(&target, 0, sizeof(target));
787c03eb6b8Sitojun 
78823c8222eSyamt 	if (inet_pton(AF_INET, ipsrc, &target.v4) == 1)
78923c8222eSyamt 		psk.psk_af = AF_INET;
79023c8222eSyamt 	else if (inet_pton(AF_INET6, ipsrc, &target.v6) == 1)
79123c8222eSyamt 		psk.psk_af = AF_INET6;
79223c8222eSyamt 	else {
79323c8222eSyamt 		syslog(LOG_ERR, "inet_pton(%s) failed", ipsrc);
79423c8222eSyamt 		return;
79523c8222eSyamt 	}
796c03eb6b8Sitojun 
797c03eb6b8Sitojun 	/* Kill all states from ipsrc */
79823c8222eSyamt 	memcpy(&psk.psk_src.addr.v.a.addr, &target,
79923c8222eSyamt 	    sizeof(psk.psk_src.addr.v.a.addr));
800c03eb6b8Sitojun 	memset(&psk.psk_src.addr.v.a.mask, 0xff,
801c03eb6b8Sitojun 	    sizeof(psk.psk_src.addr.v.a.mask));
802c03eb6b8Sitojun 	if (ioctl(dev, DIOCKILLSTATES, &psk))
803c03eb6b8Sitojun 		syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)");
804c03eb6b8Sitojun 
805c03eb6b8Sitojun 	/* Kill all states to ipsrc */
806c03eb6b8Sitojun 	memset(&psk.psk_src, 0, sizeof(psk.psk_src));
80723c8222eSyamt 	memcpy(&psk.psk_dst.addr.v.a.addr, &target,
80823c8222eSyamt 	    sizeof(psk.psk_dst.addr.v.a.addr));
809c03eb6b8Sitojun 	memset(&psk.psk_dst.addr.v.a.mask, 0xff,
810c03eb6b8Sitojun 	    sizeof(psk.psk_dst.addr.v.a.mask));
811c03eb6b8Sitojun 	if (ioctl(dev, DIOCKILLSTATES, &psk))
812c03eb6b8Sitojun 		syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)");
813c03eb6b8Sitojun }
814c03eb6b8Sitojun 
815c03eb6b8Sitojun /* signal handler that makes us go away properly */
816c03eb6b8Sitojun static void
need_death(int signo)817c03eb6b8Sitojun need_death(int signo)
818c03eb6b8Sitojun {
819c03eb6b8Sitojun 	want_death = 1;
820c03eb6b8Sitojun }
821c03eb6b8Sitojun 
822c03eb6b8Sitojun /*
823c03eb6b8Sitojun  * function that removes our stuff when we go away.
824c03eb6b8Sitojun  */
825c03eb6b8Sitojun static __dead void
do_death(int active)826c03eb6b8Sitojun do_death(int active)
827c03eb6b8Sitojun {
828c03eb6b8Sitojun 	int	ret = 0;
829c03eb6b8Sitojun 
830c03eb6b8Sitojun 	if (active) {
831c03eb6b8Sitojun 		change_filter(0, luser, ipsrc);
832fff57c55Syamt 		change_table(0, ipsrc);
833c03eb6b8Sitojun 		authpf_kill_states();
834c03eb6b8Sitojun 		remove_stale_rulesets();
835c03eb6b8Sitojun 	}
836fff57c55Syamt 	if (pidfile[0] && (pidfp != NULL))
837c03eb6b8Sitojun 		if (unlink(pidfile) == -1)
838c03eb6b8Sitojun 			syslog(LOG_ERR, "cannot unlink %s (%m)", pidfile);
839c03eb6b8Sitojun 	exit(ret);
840c03eb6b8Sitojun }
841