xref: /freebsd/contrib/pf/authpf/authpf.c (revision bfc3fb6cc26e5c48f54e90814d39d9f07160763c)
1 /*	$OpenBSD: authpf.c,v 1.68 2003/08/21 19:13:23 frantzen Exp $	*/
2 
3 /*
4  * Copyright (C) 1998 - 2002 Bob Beck (beck@openbsd.org).
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/types.h>
29 #include <sys/file.h>
30 #include <sys/ioctl.h>
31 #include <sys/socket.h>
32 #include <sys/time.h>
33 
34 #include <net/if.h>
35 #include <net/pfvar.h>
36 #include <arpa/inet.h>
37 
38 #include <err.h>
39 #include <errno.h>
40 #include <pwd.h>
41 #include <signal.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <syslog.h>
46 #include <unistd.h>
47 
48 #include <pfctl_parser.h>
49 
50 #include "pathnames.h"
51 
52 extern int	symset(const char *, const char *, int);
53 
54 static int	read_config(FILE *);
55 static void	print_message(char *);
56 static int	allowed_luser(char *);
57 static int	check_luser(char *, char *);
58 static int	remove_stale_rulesets(void);
59 static int	change_filter(int, const char *, const char *);
60 static void	authpf_kill_states(void);
61 
62 int	dev;			/* pf device */
63 char	anchorname[PF_ANCHOR_NAME_SIZE] = "authpf";
64 char	rulesetname[PF_RULESET_NAME_SIZE];
65 
66 FILE	*pidfp;
67 char	*infile;		/* file name printed by yyerror() in parse.y */
68 char	 luser[MAXLOGNAME];	/* username */
69 char	 ipsrc[256];		/* ip as a string */
70 char	 pidfile[MAXPATHLEN];	/* we save pid in this file. */
71 
72 struct timeval	Tstart, Tend;	/* start and end times of session */
73 
74 volatile sig_atomic_t	want_death;
75 static void		need_death(int signo);
76 static __dead void	do_death(int);
77 
78 /*
79  * User shell for authenticating gateways. Sole purpose is to allow
80  * a user to ssh to a gateway, and have the gateway modify packet
81  * filters to allow access, then remove access when the user finishes
82  * up. Meant to be used only from ssh(1) connections.
83  */
84 int
85 main(int argc, char *argv[])
86 {
87 	int		 lockcnt = 0, n, pidfd;
88 	FILE		*config;
89 	struct in_addr	 ina;
90 	struct passwd	*pw;
91 	char		*cp;
92 	uid_t		 uid;
93 
94 	if ((n = snprintf(rulesetname, sizeof(rulesetname), "%ld",
95 	    (long)getpid())) < 0 || n >= sizeof(rulesetname)) {
96 		syslog(LOG_ERR, "pid too large for ruleset name");
97 		exit(1);
98 	}
99 
100 	config = fopen(PATH_CONFFILE, "r");
101 
102 	if ((cp = getenv("SSH_TTY")) == NULL) {
103 		syslog(LOG_ERR, "non-interactive session connection for authpf");
104 		exit(1);
105 	}
106 
107 	if ((cp = getenv("SSH_CLIENT")) == NULL) {
108 		syslog(LOG_ERR, "cannot determine connection source");
109 		exit(1);
110 	}
111 
112 	if (strlcpy(ipsrc, cp, sizeof(ipsrc)) >= sizeof(ipsrc)) {
113 		syslog(LOG_ERR, "SSH_CLIENT variable too long");
114 		exit(1);
115 	}
116 	cp = strchr(ipsrc, ' ');
117 	if (!cp) {
118 		syslog(LOG_ERR, "corrupt SSH_CLIENT variable %s", ipsrc);
119 		exit(1);
120 	}
121 	*cp = '\0';
122 	if (inet_pton(AF_INET, ipsrc, &ina) != 1) {
123 		syslog(LOG_ERR,
124 		    "cannot determine IP from SSH_CLIENT %s", ipsrc);
125 		exit(1);
126 	}
127 
128 	/* open the pf device */
129 	dev = open(PATH_DEVFILE, O_RDWR);
130 	if (dev == -1) {
131 		syslog(LOG_ERR, "cannot open packet filter device (%m)");
132 		goto die;
133 	}
134 
135 	uid = getuid();
136 	pw = getpwuid(uid);
137 	if (pw == NULL) {
138 		syslog(LOG_ERR, "cannot find user for uid %u", uid);
139 		goto die;
140 	}
141 	if (strcmp(pw->pw_shell, PATH_AUTHPF_SHELL)) {
142 		syslog(LOG_ERR, "wrong shell for user %s, uid %u",
143 		    pw->pw_name, pw->pw_uid);
144 		goto die;
145 	}
146 
147 	/*
148 	 * Paranoia, but this data _does_ come from outside authpf, and
149 	 * truncation would be bad.
150 	 */
151 	if (strlcpy(luser, pw->pw_name, sizeof(luser)) >= sizeof(luser)) {
152 		syslog(LOG_ERR, "username too long: %s", pw->pw_name);
153 		goto die;
154 	}
155 
156 	/* Make our entry in /var/authpf as /var/authpf/ipaddr */
157 	n = snprintf(pidfile, sizeof(pidfile), "%s/%s", PATH_PIDFILE, ipsrc);
158 	if (n < 0 || (u_int)n >= sizeof(pidfile)) {
159 		syslog(LOG_ERR, "path to pidfile too long");
160 		goto die;
161 	}
162 
163 	/*
164 	 * If someone else is already using this ip, then this person
165 	 * wants to switch users - so kill the old process and exit
166 	 * as well.
167 	 *
168 	 * Note, we could print a message and tell them to log out, but the
169 	 * usual case of this is that someone has left themselves logged in,
170 	 * with the authenticated connection iconized and someone else walks
171 	 * up to use and automatically logs in before using. If this just
172 	 * gets rid of the old one silently, the new user never knows they
173 	 * could have used someone else's old authentication. If we
174 	 * tell them to log out before switching users it is an invitation
175 	 * for abuse.
176 	 */
177 
178 	do {
179 		int	save_errno, otherpid = -1;
180 		char	otherluser[MAXLOGNAME];
181 
182 		if ((pidfd = open(pidfile, O_RDWR|O_CREAT, 0644)) == -1 ||
183 		    (pidfp = fdopen(pidfd, "r+")) == NULL) {
184 			if (pidfd != -1)
185 				close(pidfd);
186 			syslog(LOG_ERR, "cannot open or create %s: %s", pidfile,
187 			    strerror(errno));
188 			goto die;
189 		}
190 
191 		if (flock(fileno(pidfp), LOCK_EX|LOCK_NB) == 0)
192 			break;
193 		save_errno = errno;
194 
195 		/* Mark our pid, and username to our file. */
196 
197 		rewind(pidfp);
198 		/* 31 == MAXLOGNAME - 1 */
199 		if (fscanf(pidfp, "%d\n%31s\n", &otherpid, otherluser) != 2)
200 			otherpid = -1;
201 		syslog(LOG_DEBUG, "tried to lock %s, in use by pid %d: %s",
202 		    pidfile, otherpid, strerror(save_errno));
203 
204 		if (otherpid > 0) {
205 			syslog(LOG_INFO,
206 			    "killing prior auth (pid %d) of %s by user %s",
207 			    otherpid, ipsrc, otherluser);
208 			if (kill((pid_t) otherpid, SIGTERM) == -1) {
209 				syslog(LOG_INFO,
210 				    "could not kill process %d: (%m)",
211 				    otherpid);
212 			}
213 		}
214 
215 		/*
216 		 * we try to kill the previous process and acquire the lock
217 		 * for 10 seconds, trying once a second. if we can't after
218 		 * 10 attempts we log an error and give up
219 		 */
220 		if (++lockcnt > 10) {
221 			syslog(LOG_ERR, "cannot kill previous authpf (pid %d)",
222 			    otherpid);
223 			goto dogdeath;
224 		}
225 		sleep(1);
226 
227 		/* re-open, and try again. The previous authpf process
228 		 * we killed above should unlink the file and release
229 		 * it's lock, giving us a chance to get it now
230 		 */
231 		fclose(pidfp);
232 	} while (1);
233 
234 	/* revoke privs */
235 	seteuid(getuid());
236 	setuid(getuid());
237 
238 	if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser))
239 		do_death(0);
240 
241 	openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON);
242 	if (config == NULL || read_config(config))
243 		do_death(0);
244 
245 	if (remove_stale_rulesets())
246 		do_death(0);
247 
248 	/* We appear to be making headway, so actually mark our pid */
249 	rewind(pidfp);
250 	fprintf(pidfp, "%ld\n%s\n", (long)getpid(), luser);
251 	fflush(pidfp);
252 	(void) ftruncate(fileno(pidfp), ftell(pidfp));
253 
254 	if (change_filter(1, luser, ipsrc) == -1) {
255 		printf("Unable to modify filters\r\n");
256 		do_death(1);
257 	}
258 
259 	signal(SIGTERM, need_death);
260 	signal(SIGINT, need_death);
261 	signal(SIGALRM, need_death);
262 	signal(SIGPIPE, need_death);
263 	signal(SIGHUP, need_death);
264 	signal(SIGSTOP, need_death);
265 	signal(SIGTSTP, need_death);
266 	while (1) {
267 		printf("\r\nHello %s, ", luser);
268 		printf("You are authenticated from host \"%s\"\r\n", ipsrc);
269 		setproctitle("%s@%s", luser, ipsrc);
270 		print_message(PATH_MESSAGE);
271 		while (1) {
272 			sleep(10);
273 			if (want_death)
274 				do_death(1);
275 		}
276 	}
277 
278 	/* NOTREACHED */
279 dogdeath:
280 	printf("\r\n\r\nSorry, this service is currently unavailable due to ");
281 	printf("technical difficulties\r\n\r\n");
282 	print_message(PATH_PROBLEM);
283 	printf("\r\nYour authentication process (pid %ld) was unable to run\n",
284 	    (long)getpid());
285 	sleep(180); /* them lusers read reaaaaal slow */
286 die:
287 	do_death(0);
288 }
289 
290 /*
291  * reads config file in PATH_CONFFILE to set optional behaviours up
292  */
293 static int
294 read_config(FILE *f)
295 {
296 	char	buf[1024];
297 	int	i = 0;
298 
299 	do {
300 		char	**ap;
301 		char	 *pair[4], *cp, *tp;
302 		int	  len;
303 
304 		if (fgets(buf, sizeof(buf), f) == NULL) {
305 			fclose(f);
306 			return (0);
307 		}
308 		i++;
309 		len = strlen(buf);
310 		if (buf[len - 1] != '\n' && !feof(f)) {
311 			syslog(LOG_ERR, "line %d too long in %s", i,
312 			    PATH_CONFFILE);
313 			return (1);
314 		}
315 		buf[len - 1] = '\0';
316 
317 		for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
318 			; /* nothing */
319 
320 		if (!*cp || *cp == '#' || *cp == '\n')
321 			continue;
322 
323 		for (ap = pair; ap < &pair[3] &&
324 		    (*ap = strsep(&cp, "=")) != NULL; ) {
325 			if (**ap != '\0')
326 				ap++;
327 		}
328 		if (ap != &pair[2])
329 			goto parse_error;
330 
331 		tp = pair[1] + strlen(pair[1]);
332 		while ((*tp == ' ' || *tp == '\t') && tp >= pair[1])
333 			*tp-- = '\0';
334 
335 		if (strcasecmp(pair[0], "anchor") == 0) {
336 			if (!pair[1][0] || strlcpy(anchorname, pair[1],
337 			    sizeof(anchorname)) >= sizeof(anchorname))
338 				goto parse_error;
339 		}
340 	} while (!feof(f) && !ferror(f));
341 	fclose(f);
342 	return (0);
343 
344 parse_error:
345 	fclose(f);
346 	syslog(LOG_ERR, "parse error, line %d of %s", i, PATH_CONFFILE);
347 	return (1);
348 }
349 
350 
351 /*
352  * splatter a file to stdout - max line length of 1024,
353  * used for spitting message files at users to tell them
354  * they've been bad or we're unavailable.
355  */
356 static void
357 print_message(char *filename)
358 {
359 	char	 buf[1024];
360 	FILE	*f;
361 
362 	if ((f = fopen(filename, "r")) == NULL)
363 		return; /* fail silently, we don't care if it isn't there */
364 
365 	do {
366 		if (fgets(buf, sizeof(buf), f) == NULL) {
367 			fflush(stdout);
368 			fclose(f);
369 			return;
370 		}
371 	} while (fputs(buf, stdout) != EOF && !feof(f));
372 	fflush(stdout);
373 	fclose(f);
374 }
375 
376 /*
377  * allowed_luser checks to see if user "luser" is allowed to
378  * use this gateway by virtue of being listed in an allowed
379  * users file, namely /etc/authpf/authpf.allow .
380  *
381  * If /etc/authpf/authpf.allow does not exist, then we assume that
382  * all users who are allowed in by sshd(8) are permitted to
383  * use this gateway. If /etc/authpf/authpf.allow does exist, then a
384  * user must be listed if the connection is to continue, else
385  * the session terminates in the same manner as being banned.
386  */
387 static int
388 allowed_luser(char *luser)
389 {
390 	char	*buf, *lbuf;
391 	int	 matched;
392 	size_t	 len;
393 	FILE	*f;
394 
395 	if ((f = fopen(PATH_ALLOWFILE, "r")) == NULL) {
396 		if (errno == ENOENT) {
397 			/*
398 			 * allowfile doesn't exist, thus this gateway
399 			 * isn't restricted to certain users...
400 			 */
401 			return (1);
402 		}
403 
404 		/*
405 		 * luser may in fact be allowed, but we can't open
406 		 * the file even though it's there. probably a config
407 		 * problem.
408 		 */
409 		syslog(LOG_ERR, "cannot open allowed users file %s (%s)",
410 		    PATH_ALLOWFILE, strerror(errno));
411 		return (0);
412 	} else {
413 		/*
414 		 * /etc/authpf/authpf.allow exists, thus we do a linear
415 		 * search to see if they are allowed.
416 		 * also, if username "*" exists, then this is a
417 		 * "public" gateway, such as it is, so let
418 		 * everyone use it.
419 		 */
420 		lbuf = NULL;
421 		while ((buf = fgetln(f, &len))) {
422 			if (buf[len - 1] == '\n')
423 				buf[len - 1] = '\0';
424 			else {
425 				if ((lbuf = (char *)malloc(len + 1)) == NULL)
426 					err(1, NULL);
427 				memcpy(lbuf, buf, len);
428 				lbuf[len] = '\0';
429 				buf = lbuf;
430 			}
431 
432 			matched = strcmp(luser, buf) == 0 || strcmp("*", buf) == 0;
433 
434 			if (lbuf != NULL) {
435 				free(lbuf);
436 				lbuf = NULL;
437 			}
438 
439 			if (matched)
440 				return (1); /* matched an allowed username */
441 		}
442 		syslog(LOG_INFO, "denied access to %s: not listed in %s",
443 		    luser, PATH_ALLOWFILE);
444 
445 		/* reuse buf */
446 		buf = "\n\nSorry, you are not allowed to use this facility!\n";
447 		fputs(buf, stdout);
448 	}
449 	fflush(stdout);
450 	return (0);
451 }
452 
453 /*
454  * check_luser checks to see if user "luser" has been banned
455  * from using us by virtue of having an file of the same name
456  * in the "luserdir" directory.
457  *
458  * If the user has been banned, we copy the contents of the file
459  * to the user's screen. (useful for telling the user what to
460  * do to get un-banned, or just to tell them they aren't
461  * going to be un-banned.)
462  */
463 static int
464 check_luser(char *luserdir, char *luser)
465 {
466 	FILE	*f;
467 	int	 n;
468 	char	 tmp[MAXPATHLEN];
469 
470 	n = snprintf(tmp, sizeof(tmp), "%s/%s", luserdir, luser);
471 	if (n < 0 || (u_int)n >= sizeof(tmp)) {
472 		syslog(LOG_ERR, "provided banned directory line too long (%s)",
473 		    luserdir);
474 		return (0);
475 	}
476 	if ((f = fopen(tmp, "r")) == NULL) {
477 		if (errno == ENOENT) {
478 			/*
479 			 * file or dir doesn't exist, so therefore
480 			 * this luser isn't banned..  all is well
481 			 */
482 			return (1);
483 		} else {
484 			/*
485 			 * luser may in fact be banned, but we can't open the
486 			 * file even though it's there. probably a config
487 			 * problem.
488 			 */
489 			syslog(LOG_ERR, "cannot open banned file %s (%s)",
490 			    tmp, strerror(errno));
491 			return (0);
492 		}
493 	} else {
494 		/*
495 		 * luser is banned - spit the file at them to
496 		 * tell what they can do and where they can go.
497 		 */
498 		syslog(LOG_INFO, "denied access to %s: %s exists",
499 		    luser, tmp);
500 
501 		/* reuse tmp */
502 		strlcpy(tmp, "\n\n-**- Sorry, you have been banned! -**-\n\n",
503 		    sizeof(tmp));
504 		while (fputs(tmp, stdout) != EOF && !feof(f)) {
505 			if (fgets(tmp, sizeof(tmp), f) == NULL) {
506 				fflush(stdout);
507 				return (0);
508 			}
509 		}
510 	}
511 	fflush(stdout);
512 	return (0);
513 }
514 
515 /*
516  * Search for rulesets left by other authpf processes (either because they
517  * died ungracefully or were terminated) and remove them.
518  */
519 static int
520 remove_stale_rulesets(void)
521 {
522 	struct pfioc_ruleset	 prs;
523 	const int		 action[PF_RULESET_MAX] = { PF_SCRUB,
524 				    PF_PASS, PF_NAT, PF_BINAT, PF_RDR };
525 	u_int32_t		 nr, mnr;
526 
527 	memset(&prs, 0, sizeof(prs));
528 	strlcpy(prs.anchor, anchorname, sizeof(prs.anchor));
529 	if (ioctl(dev, DIOCGETRULESETS, &prs)) {
530 		if (errno == EINVAL)
531 			return (0);
532 		else
533 			return (1);
534 	}
535 
536 	mnr = prs.nr;
537 	nr = 0;
538 	while (nr < mnr) {
539 		char	*s;
540 		pid_t	 pid;
541 
542 		prs.nr = nr;
543 		if (ioctl(dev, DIOCGETRULESET, &prs))
544 			return (1);
545 		errno = 0;
546 		pid = strtoul(prs.name, &s, 10);
547 		if (!prs.name[0] || errno || *s)
548 			return (1);
549 		if (kill(pid, 0) && errno != EPERM) {
550 			int i;
551 
552 			for (i = 0; i < PF_RULESET_MAX; ++i) {
553 				struct pfioc_rule pr;
554 
555 				memset(&pr, 0, sizeof(pr));
556 				memcpy(pr.anchor, prs.anchor, sizeof(pr.anchor));
557 				memcpy(pr.ruleset, prs.name, sizeof(pr.ruleset));
558 				pr.rule.action = action[i];
559 				if ((ioctl(dev, DIOCBEGINRULES, &pr) ||
560 				    ioctl(dev, DIOCCOMMITRULES, &pr)) &&
561 				    errno != EINVAL)
562 					return (1);
563 			}
564 			mnr--;
565 		} else
566 			nr++;
567 	}
568 	return (0);
569 }
570 
571 /*
572  * Add/remove filter entries for user "luser" from ip "ipsrc"
573  */
574 static int
575 change_filter(int add, const char *luser, const char *ipsrc)
576 {
577 	char			 fn[MAXPATHLEN];
578 	FILE			*f = NULL;
579 	const int		 action[PF_RULESET_MAX] = { PF_SCRUB,
580 				    PF_PASS, PF_NAT, PF_BINAT, PF_RDR };
581 	struct pfctl		 pf;
582 	struct pfioc_rule	 pr[PF_RULESET_MAX];
583 	int			 i;
584 
585 	if (luser == NULL || !luser[0] || strlen(luser) >=
586 	    PF_RULESET_NAME_SIZE || ipsrc == NULL || !ipsrc[0]) {
587 		syslog(LOG_ERR, "invalid luser/ipsrc");
588 		goto error;
589 	}
590 
591 	if (add) {
592 		if ((i = snprintf(fn, sizeof(fn), "%s/%s/authpf.rules",
593 		    PATH_USER_DIR, luser)) < 0 || i >= sizeof(fn)) {
594 			syslog(LOG_ERR, "user rule path too long");
595 			goto error;
596 		}
597 		if ((f = fopen(fn, "r")) == NULL && errno != ENOENT) {
598 			syslog(LOG_ERR, "cannot open %s (%m)", fn);
599 			goto error;
600 		}
601 		if (f == NULL) {
602 			if (strlcpy(fn, PATH_PFRULES, sizeof(fn)) >=
603 			    sizeof(fn)) {
604 				syslog(LOG_ERR, "rule path too long");
605 				goto error;
606 			}
607 			if ((f = fopen(fn, "r")) == NULL) {
608 				syslog(LOG_ERR, "cannot open %s (%m)", fn);
609 				goto error;
610 			}
611 		}
612 	}
613 
614 	if (pfctl_load_fingerprints(dev, 0)) {
615 		syslog(LOG_ERR, "unable to load kernel's OS fingerprints");
616 		goto error;
617 	}
618 
619 	memset(&pf, 0, sizeof(pf));
620 	for (i = 0; i < PF_RULESET_MAX; ++i) {
621 		memset(&pr[i], 0, sizeof(pr[i]));
622 		pr[i].rule.action = action[i];
623 		strlcpy(pr[i].anchor, anchorname, sizeof(pr[i].anchor));
624 		strlcpy(pr[i].ruleset, rulesetname, sizeof(pr[i].ruleset));
625 		if (ioctl(dev, DIOCBEGINRULES, &pr[i])) {
626 			syslog(LOG_ERR, "DIOCBEGINRULES %m");
627 			goto error;
628 		}
629 		pf.prule[i] = &pr[i];
630 	}
631 
632 	if (add) {
633 		if (symset("user_ip", ipsrc, 0) ||
634 		    symset("user_id", luser, 0)) {
635 			syslog(LOG_ERR, "symset");
636 			goto error;
637 		}
638 
639 		pf.dev = dev;
640 		infile = fn;
641 		if (parse_rules(f, &pf) < 0) {
642 			syslog(LOG_ERR, "syntax error in rule file: "
643 			    "authpf rules not loaded");
644 			goto error;
645 		}
646 
647 		infile = NULL;
648 		fclose(f);
649 		f = NULL;
650 	}
651 
652 	for (i = 0; i < PF_RULESET_MAX; ++i)
653 		/*
654 		 * ignore EINVAL on removal, it means the anchor was
655 		 * already automatically removed by the kernel.
656 		 */
657 		if (ioctl(dev, DIOCCOMMITRULES, &pr[i]) &&
658 		    (add || errno != EINVAL)) {
659 			syslog(LOG_ERR, "DIOCCOMMITRULES %m");
660 			goto error;
661 		}
662 
663 	if (add) {
664 		gettimeofday(&Tstart, NULL);
665 		syslog(LOG_INFO, "allowing %s, user %s", ipsrc, luser);
666 	} else {
667 		gettimeofday(&Tend, NULL);
668 		syslog(LOG_INFO, "removed %s, user %s - duration %ld seconds",
669 		    ipsrc, luser, Tend.tv_sec - Tstart.tv_sec);
670 	}
671 	return (0);
672 
673 error:
674 	if (f != NULL)
675 		fclose(f);
676 
677 	infile = NULL;
678 	return (-1);
679 }
680 
681 /*
682  * This is to kill off states that would otherwise be left behind stateful
683  * rules. This means we don't need to allow in more traffic than we really
684  * want to, since we don't have to worry about any luser sessions lasting
685  * longer than their ssh session. This function is based on
686  * pfctl_kill_states from pfctl.
687  */
688 static void
689 authpf_kill_states(void)
690 {
691 	struct pfioc_state_kill	psk;
692 	struct in_addr		target;
693 
694 	memset(&psk, 0, sizeof(psk));
695 	psk.psk_af = AF_INET;
696 
697 	inet_pton(AF_INET, ipsrc, &target);
698 
699 	/* Kill all states from ipsrc */
700 	psk.psk_src.addr.v.a.addr.v4 = target;
701 	memset(&psk.psk_src.addr.v.a.mask, 0xff,
702 	    sizeof(psk.psk_src.addr.v.a.mask));
703 	if (ioctl(dev, DIOCKILLSTATES, &psk))
704 		syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)");
705 
706 	/* Kill all states to ipsrc */
707 	psk.psk_af = AF_INET;
708 	memset(&psk.psk_src, 0, sizeof(psk.psk_src));
709 	psk.psk_dst.addr.v.a.addr.v4 = target;
710 	memset(&psk.psk_dst.addr.v.a.mask, 0xff,
711 	    sizeof(psk.psk_dst.addr.v.a.mask));
712 	if (ioctl(dev, DIOCKILLSTATES, &psk))
713 		syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)");
714 }
715 
716 /* signal handler that makes us go away properly */
717 static void
718 need_death(int signo)
719 {
720 	want_death = 1;
721 }
722 
723 /*
724  * function that removes our stuff when we go away.
725  */
726 static __dead void
727 do_death(int active)
728 {
729 	int	ret = 0;
730 
731 	if (active) {
732 		change_filter(0, luser, ipsrc);
733 		authpf_kill_states();
734 		remove_stale_rulesets();
735 	}
736 	if (pidfp)
737 		ftruncate(fileno(pidfp), 0);
738 	if (pidfile[0])
739 		if (unlink(pidfile) == -1)
740 			syslog(LOG_ERR, "cannot unlink %s (%m)", pidfile);
741 	exit(ret);
742 }
743 
744 /*
745  * callbacks for parse_rules(void)
746  */
747 
748 int
749 pfctl_add_rule(struct pfctl *pf, struct pf_rule *r)
750 {
751 	struct pfioc_rule	*pr;
752 
753 	switch (r->action) {
754 	case PF_PASS:
755 	case PF_DROP:
756 		pr = pf->prule[PF_RULESET_FILTER];
757 		break;
758 	case PF_SCRUB:
759 		pr = pf->prule[PF_RULESET_SCRUB];
760 		break;
761 	case PF_NAT:
762 	case PF_NONAT:
763 		pr = pf->prule[PF_RULESET_NAT];
764 		break;
765 	case PF_RDR:
766 	case PF_NORDR:
767 		pr = pf->prule[PF_RULESET_RDR];
768 		break;
769 	case PF_BINAT:
770 	case PF_NOBINAT:
771 		pr = pf->prule[PF_RULESET_BINAT];
772 		break;
773 	default:
774 		syslog(LOG_ERR, "invalid rule action %d", r->action);
775 		return (1);
776 	}
777 	if (pfctl_add_pool(pf, &r->rpool, r->af))
778 		return (1);
779 	pr->pool_ticket = pf->paddr.ticket;
780 	memcpy(&pr->rule, r, sizeof(pr->rule));
781 	if (ioctl(pf->dev, DIOCADDRULE, pr)) {
782 		syslog(LOG_ERR, "DIOCADDRULE %m");
783 		return (1);
784 	}
785 	pfctl_clear_pool(&r->rpool);
786 	return (0);
787 }
788 
789 int
790 pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
791 {
792 	struct pf_pooladdr	*pa;
793 
794 	if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr)) {
795 		syslog(LOG_ERR, "DIOCBEGINADDRS %m");
796 		return (1);
797 	}
798 	pf->paddr.af = af;
799 	TAILQ_FOREACH(pa, &p->list, entries) {
800 		memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
801 		if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr)) {
802 			syslog(LOG_ERR, "DIOCADDADDR %m");
803 			return (1);
804 		}
805 	}
806 	return (0);
807 }
808 
809 void
810 pfctl_clear_pool(struct pf_pool *pool)
811 {
812 	struct pf_pooladdr	*pa;
813 
814 	while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
815 		TAILQ_REMOVE(&pool->list, pa, entries);
816 		free(pa);
817 	}
818 }
819 
820 int
821 pfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
822 {
823 	fprintf(stderr, "altq rules not supported in authpf\n");
824 	return (1);
825 }
826 
827 int
828 pfctl_set_optimization(struct pfctl *pf, const char *opt)
829 {
830 	fprintf(stderr, "set optimization not supported in authpf\n");
831 	return (1);
832 }
833 
834 int
835 pfctl_set_logif(struct pfctl *pf, char *ifname)
836 {
837 	fprintf(stderr, "set loginterface not supported in authpf\n");
838 	return (1);
839 }
840 
841 int
842 pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
843 {
844 	fprintf(stderr, "set timeout not supported in authpf\n");
845 	return (1);
846 }
847 
848 int
849 pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
850 {
851 	fprintf(stderr, "set limit not supported in authpf\n");
852 	return (1);
853 }
854 
855 int
856 pfctl_define_table(char *name, int flags, int addrs, const char *anchor,
857     const char *ruleset, struct pfr_buffer *ab, u_int32_t ticket)
858 {
859 	fprintf(stderr, "table definitions not yet supported in authpf\n");
860 	return (1);
861 }
862 
863 int
864 pfctl_rules(int dev, char *filename, int opts, char *anchorname,
865     char *rulesetname)
866 {
867 	/* never called, no anchors inside anchors, but we need the stub */
868 	fprintf(stderr, "load anchor not supported from authpf\n");
869 	return (1);
870 }
871 
872