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