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