xref: /openbsd-src/usr.sbin/authpf/authpf.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: authpf.c,v 1.66 2003/07/11 08:29:34 cedric 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 	memset(&pf, 0, sizeof(pf));
615 	for (i = 0; i < PF_RULESET_MAX; ++i) {
616 		memset(&pr[i], 0, sizeof(pr[i]));
617 		pr[i].rule.action = action[i];
618 		strlcpy(pr[i].anchor, anchorname, sizeof(pr[i].anchor));
619 		strlcpy(pr[i].ruleset, rulesetname, sizeof(pr[i].ruleset));
620 		if (ioctl(dev, DIOCBEGINRULES, &pr[i])) {
621 			syslog(LOG_ERR, "DIOCBEGINRULES %m");
622 			goto error;
623 		}
624 		pf.prule[i] = &pr[i];
625 	}
626 
627 	if (add) {
628 		if (symset("user_ip", ipsrc, 0) ||
629 		    symset("user_id", luser, 0)) {
630 			syslog(LOG_ERR, "symset");
631 			goto error;
632 		}
633 
634 		pf.dev = dev;
635 		infile = fn;
636 		if (parse_rules(f, &pf) < 0) {
637 			syslog(LOG_ERR, "syntax error in rule file: "
638 			    "authpf rules not loaded");
639 			goto error;
640 		}
641 
642 		infile = NULL;
643 		fclose(f);
644 		f = NULL;
645 	}
646 
647 	for (i = 0; i < PF_RULESET_MAX; ++i)
648 		/*
649 		 * ignore EINVAL on removal, it means the anchor was
650 		 * already automatically removed by the kernel.
651 		 */
652 		if (ioctl(dev, DIOCCOMMITRULES, &pr[i]) &&
653 		    (add || errno != EINVAL)) {
654 			syslog(LOG_ERR, "DIOCCOMMITRULES %m");
655 			goto error;
656 		}
657 
658 	if (add) {
659 		gettimeofday(&Tstart, NULL);
660 		syslog(LOG_INFO, "allowing %s, user %s", ipsrc, luser);
661 	} else {
662 		gettimeofday(&Tend, NULL);
663 		syslog(LOG_INFO, "removed %s, user %s - duration %ld seconds",
664 		    ipsrc, luser, Tend.tv_sec - Tstart.tv_sec);
665 	}
666 	return (0);
667 
668 error:
669 	if (f != NULL)
670 		fclose(f);
671 
672 	infile = NULL;
673 	return (-1);
674 }
675 
676 /*
677  * This is to kill off states that would otherwise be left behind stateful
678  * rules. This means we don't need to allow in more traffic than we really
679  * want to, since we don't have to worry about any luser sessions lasting
680  * longer than their ssh session. This function is based on
681  * pfctl_kill_states from pfctl.
682  */
683 static void
684 authpf_kill_states(void)
685 {
686 	struct pfioc_state_kill	psk;
687 	struct in_addr		target;
688 
689 	memset(&psk, 0, sizeof(psk));
690 	psk.psk_af = AF_INET;
691 
692 	inet_pton(AF_INET, ipsrc, &target);
693 
694 	/* Kill all states from ipsrc */
695 	psk.psk_src.addr.v.a.addr.v4 = target;
696 	memset(&psk.psk_src.addr.v.a.mask, 0xff,
697 	    sizeof(psk.psk_src.addr.v.a.mask));
698 	if (ioctl(dev, DIOCKILLSTATES, &psk))
699 		syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)");
700 
701 	/* Kill all states to ipsrc */
702 	psk.psk_af = AF_INET;
703 	memset(&psk.psk_src, 0, sizeof(psk.psk_src));
704 	psk.psk_dst.addr.v.a.addr.v4 = target;
705 	memset(&psk.psk_dst.addr.v.a.mask, 0xff,
706 	    sizeof(psk.psk_dst.addr.v.a.mask));
707 	if (ioctl(dev, DIOCKILLSTATES, &psk))
708 		syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)");
709 }
710 
711 /* signal handler that makes us go away properly */
712 static void
713 need_death(int signo)
714 {
715 	want_death = 1;
716 }
717 
718 /*
719  * function that removes our stuff when we go away.
720  */
721 static __dead void
722 do_death(int active)
723 {
724 	int	ret = 0;
725 
726 	if (active) {
727 		change_filter(0, luser, ipsrc);
728 		authpf_kill_states();
729 		remove_stale_rulesets();
730 	}
731 	if (pidfp)
732 		ftruncate(fileno(pidfp), 0);
733 	if (pidfile[0])
734 		if (unlink(pidfile) == -1)
735 			syslog(LOG_ERR, "cannot unlink %s (%m)", pidfile);
736 	exit(ret);
737 }
738 
739 /*
740  * callbacks for parse_rules(void)
741  */
742 
743 int
744 pfctl_add_rule(struct pfctl *pf, struct pf_rule *r)
745 {
746 	struct pfioc_rule	*pr;
747 
748 	switch (r->action) {
749 	case PF_PASS:
750 	case PF_DROP:
751 		pr = pf->prule[PF_RULESET_FILTER];
752 		break;
753 	case PF_SCRUB:
754 		pr = pf->prule[PF_RULESET_SCRUB];
755 		break;
756 	case PF_NAT:
757 	case PF_NONAT:
758 		pr = pf->prule[PF_RULESET_NAT];
759 		break;
760 	case PF_RDR:
761 	case PF_NORDR:
762 		pr = pf->prule[PF_RULESET_RDR];
763 		break;
764 	case PF_BINAT:
765 	case PF_NOBINAT:
766 		pr = pf->prule[PF_RULESET_BINAT];
767 		break;
768 	default:
769 		syslog(LOG_ERR, "invalid rule action %d", r->action);
770 		return (1);
771 	}
772 	if (pfctl_add_pool(pf, &r->rpool, r->af))
773 		return (1);
774 	pr->pool_ticket = pf->paddr.ticket;
775 	memcpy(&pr->rule, r, sizeof(pr->rule));
776 	if (ioctl(pf->dev, DIOCADDRULE, pr)) {
777 		syslog(LOG_ERR, "DIOCADDRULE %m");
778 		return (1);
779 	}
780 	pfctl_clear_pool(&r->rpool);
781 	return (0);
782 }
783 
784 int
785 pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
786 {
787 	struct pf_pooladdr	*pa;
788 
789 	if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr)) {
790 		syslog(LOG_ERR, "DIOCBEGINADDRS %m");
791 		return (1);
792 	}
793 	pf->paddr.af = af;
794 	TAILQ_FOREACH(pa, &p->list, entries) {
795 		memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
796 		if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr)) {
797 			syslog(LOG_ERR, "DIOCADDADDR %m");
798 			return (1);
799 		}
800 	}
801 	return (0);
802 }
803 
804 void
805 pfctl_clear_pool(struct pf_pool *pool)
806 {
807 	struct pf_pooladdr	*pa;
808 
809 	while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
810 		TAILQ_REMOVE(&pool->list, pa, entries);
811 		free(pa);
812 	}
813 }
814 
815 int
816 pfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
817 {
818 	fprintf(stderr, "altq rules not supported in authpf\n");
819 	return (1);
820 }
821 
822 int
823 pfctl_set_optimization(struct pfctl *pf, const char *opt)
824 {
825 	fprintf(stderr, "set optimization not supported in authpf\n");
826 	return (1);
827 }
828 
829 int
830 pfctl_set_logif(struct pfctl *pf, char *ifname)
831 {
832 	fprintf(stderr, "set loginterface not supported in authpf\n");
833 	return (1);
834 }
835 
836 int
837 pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
838 {
839 	fprintf(stderr, "set timeout not supported in authpf\n");
840 	return (1);
841 }
842 
843 int
844 pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
845 {
846 	fprintf(stderr, "set limit not supported in authpf\n");
847 	return (1);
848 }
849 
850 int
851 pfctl_define_table(char *name, int flags, int addrs, const char *anchor,
852     const char *ruleset, struct pfr_buffer *ab, int ticket)
853 {
854 	fprintf(stderr, "table definitions not yet supported in authpf\n");
855 	return (1);
856 }
857 
858 int
859 pfctl_rules(int dev, char *filename, int opts, char *anchorname,
860     char *rulesetname)
861 {
862 	/* never called, no anchors inside anchors, but we need the stub */
863 	fprintf(stderr, "load anchor not supported from authpf\n");
864 	return (1);
865 }
866