authpf.c (22ac3ead26f49483410317f82ce328741b1cf975) authpf.c (61a1372b419ef876d7a8948241bc561a1866448c)
1/* $OpenBSD: authpf.c,v 1.75 2004/01/29 01:55:10 deraadt Exp $ */
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 unchanged lines hidden (view full) ---

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
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 unchanged lines hidden (view full) ---

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$");
30
31#include <sys/param.h>
28#include <sys/types.h>
32#include <sys/file.h>
33#include <sys/ioctl.h>
34#include <sys/socket.h>
29#include <sys/file.h>
30#include <sys/ioctl.h>
31#include <sys/socket.h>
32#include <sys/stat.h>
35#include <sys/time.h>
33#include <sys/time.h>
34#include <sys/wait.h>
36
37#include <net/if.h>
38#include <net/pfvar.h>
39#include <arpa/inet.h>
40
41#include <err.h>
42#include <errno.h>
35
36#include <net/if.h>
37#include <net/pfvar.h>
38#include <arpa/inet.h>
39
40#include <err.h>
41#include <errno.h>
42#include <login_cap.h>
43#include <pwd.h>
44#include <signal.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <syslog.h>
49#include <unistd.h>
50
43#include <pwd.h>
44#include <signal.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <syslog.h>
49#include <unistd.h>
50
51#include <pfctl_parser.h>
52#include <pfctl.h>
53
54#include "pathnames.h"
55
56extern int symset(const char *, const char *, int);
57
58static int read_config(FILE *);
59static void print_message(char *);
60static int allowed_luser(char *);
61static int check_luser(char *, char *);
62static int remove_stale_rulesets(void);
63static int change_filter(int, const char *, const char *);
51#include "pathnames.h"
52
53extern int symset(const char *, const char *, int);
54
55static int read_config(FILE *);
56static void print_message(char *);
57static int allowed_luser(char *);
58static int check_luser(char *, char *);
59static int remove_stale_rulesets(void);
60static int change_filter(int, const char *, const char *);
61static int change_table(int, const char *, const char *);
64static void authpf_kill_states(void);
65
66int dev; /* pf device */
67char anchorname[PF_ANCHOR_NAME_SIZE] = "authpf";
62static void authpf_kill_states(void);
63
64int dev; /* pf device */
65char anchorname[PF_ANCHOR_NAME_SIZE] = "authpf";
68char rulesetname[PF_RULESET_NAME_SIZE];
66char rulesetname[MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 2];
67char tablename[PF_TABLE_NAME_SIZE] = "authpf_users";
69
70FILE *pidfp;
71char *infile; /* file name printed by yyerror() in parse.y */
72char luser[MAXLOGNAME]; /* username */
73char ipsrc[256]; /* ip as a string */
74char pidfile[MAXPATHLEN]; /* we save pid in this file. */
75
76struct timeval Tstart, Tend; /* start and end times of session */
77
78volatile sig_atomic_t want_death;
79static void need_death(int signo);
68
69FILE *pidfp;
70char *infile; /* file name printed by yyerror() in parse.y */
71char luser[MAXLOGNAME]; /* username */
72char ipsrc[256]; /* ip as a string */
73char pidfile[MAXPATHLEN]; /* we save pid in this file. */
74
75struct timeval Tstart, Tend; /* start and end times of session */
76
77volatile sig_atomic_t want_death;
78static void need_death(int signo);
80#ifdef __FreeBSD__
81static __dead2 void do_death(int);
82#else
83static __dead void do_death(int);
79static __dead void do_death(int);
84#endif
85
86/*
87 * User shell for authenticating gateways. Sole purpose is to allow
88 * a user to ssh to a gateway, and have the gateway modify packet
89 * filters to allow access, then remove access when the user finishes
90 * up. Meant to be used only from ssh(1) connections.
91 */
92int
93main(int argc, char *argv[])
94{
95 int lockcnt = 0, n, pidfd;
96 FILE *config;
80
81/*
82 * User shell for authenticating gateways. Sole purpose is to allow
83 * a user to ssh to a gateway, and have the gateway modify packet
84 * filters to allow access, then remove access when the user finishes
85 * up. Meant to be used only from ssh(1) connections.
86 */
87int
88main(int argc, char *argv[])
89{
90 int lockcnt = 0, n, pidfd;
91 FILE *config;
97 struct in_addr ina;
92 struct in6_addr ina;
98 struct passwd *pw;
99 char *cp;
100 uid_t uid;
93 struct passwd *pw;
94 char *cp;
95 uid_t uid;
96 char *shell;
97 login_cap_t *lc;
101
102 config = fopen(PATH_CONFFILE, "r");
103
104 if ((cp = getenv("SSH_TTY")) == NULL) {
105 syslog(LOG_ERR, "non-interactive session connection for authpf");
106 exit(1);
107 }
108

--- 7 unchanged lines hidden (view full) ---

116 exit(1);
117 }
118 cp = strchr(ipsrc, ' ');
119 if (!cp) {
120 syslog(LOG_ERR, "corrupt SSH_CLIENT variable %s", ipsrc);
121 exit(1);
122 }
123 *cp = '\0';
98
99 config = fopen(PATH_CONFFILE, "r");
100
101 if ((cp = getenv("SSH_TTY")) == NULL) {
102 syslog(LOG_ERR, "non-interactive session connection for authpf");
103 exit(1);
104 }
105

--- 7 unchanged lines hidden (view full) ---

113 exit(1);
114 }
115 cp = strchr(ipsrc, ' ');
116 if (!cp) {
117 syslog(LOG_ERR, "corrupt SSH_CLIENT variable %s", ipsrc);
118 exit(1);
119 }
120 *cp = '\0';
124 if (inet_pton(AF_INET, ipsrc, &ina) != 1) {
121 if (inet_pton(AF_INET, ipsrc, &ina) != 1 &&
122 inet_pton(AF_INET6, ipsrc, &ina) != 1) {
125 syslog(LOG_ERR,
126 "cannot determine IP from SSH_CLIENT %s", ipsrc);
127 exit(1);
128 }
129 /* open the pf device */
130 dev = open(PATH_DEVFILE, O_RDWR);
131 if (dev == -1) {
132 syslog(LOG_ERR, "cannot open packet filter device (%m)");
133 goto die;
134 }
135
136 uid = getuid();
137 pw = getpwuid(uid);
123 syslog(LOG_ERR,
124 "cannot determine IP from SSH_CLIENT %s", ipsrc);
125 exit(1);
126 }
127 /* open the pf device */
128 dev = open(PATH_DEVFILE, O_RDWR);
129 if (dev == -1) {
130 syslog(LOG_ERR, "cannot open packet filter device (%m)");
131 goto die;
132 }
133
134 uid = getuid();
135 pw = getpwuid(uid);
136 endpwent();
138 if (pw == NULL) {
139 syslog(LOG_ERR, "cannot find user for uid %u", uid);
140 goto die;
141 }
137 if (pw == NULL) {
138 syslog(LOG_ERR, "cannot find user for uid %u", uid);
139 goto die;
140 }
142 if (strcmp(pw->pw_shell, PATH_AUTHPF_SHELL)) {
141
142 if ((lc = login_getclass(pw->pw_class)) != NULL)
143 shell = login_getcapstr(lc, "shell", pw->pw_shell,
144 pw->pw_shell);
145 else
146 shell = pw->pw_shell;
147
148 login_close(lc);
149
150 if (strcmp(shell, PATH_AUTHPF_SHELL)) {
143 syslog(LOG_ERR, "wrong shell for user %s, uid %u",
144 pw->pw_name, pw->pw_uid);
151 syslog(LOG_ERR, "wrong shell for user %s, uid %u",
152 pw->pw_name, pw->pw_uid);
153 if (shell != pw->pw_shell)
154 free(shell);
145 goto die;
146 }
147
155 goto die;
156 }
157
158 if (shell != pw->pw_shell)
159 free(shell);
160
148 /*
149 * Paranoia, but this data _does_ come from outside authpf, and
150 * truncation would be bad.
151 */
152 if (strlcpy(luser, pw->pw_name, sizeof(luser)) >= sizeof(luser)) {
153 syslog(LOG_ERR, "username too long: %s", pw->pw_name);
154 goto die;
155 }
156
157 if ((n = snprintf(rulesetname, sizeof(rulesetname), "%s(%ld)",
161 /*
162 * Paranoia, but this data _does_ come from outside authpf, and
163 * truncation would be bad.
164 */
165 if (strlcpy(luser, pw->pw_name, sizeof(luser)) >= sizeof(luser)) {
166 syslog(LOG_ERR, "username too long: %s", pw->pw_name);
167 goto die;
168 }
169
170 if ((n = snprintf(rulesetname, sizeof(rulesetname), "%s(%ld)",
158 luser, (long)getpid())) < 0 || n >= sizeof(rulesetname)) {
171 luser, (long)getpid())) < 0 || (u_int)n >= sizeof(rulesetname)) {
159 syslog(LOG_INFO, "%s(%ld) too large, ruleset name will be %ld",
160 luser, (long)getpid(), (long)getpid());
161 if ((n = snprintf(rulesetname, sizeof(rulesetname), "%ld",
172 syslog(LOG_INFO, "%s(%ld) too large, ruleset name will be %ld",
173 luser, (long)getpid(), (long)getpid());
174 if ((n = snprintf(rulesetname, sizeof(rulesetname), "%ld",
162 (long)getpid())) < 0 || n >= sizeof(rulesetname)) {
175 (long)getpid())) < 0 || (u_int)n >= sizeof(rulesetname)) {
163 syslog(LOG_ERR, "pid too large for ruleset name");
164 goto die;
165 }
166 }
167
168
169 /* Make our entry in /var/authpf as /var/authpf/ipaddr */
170 n = snprintf(pidfile, sizeof(pidfile), "%s/%s", PATH_PIDFILE, ipsrc);

--- 93 unchanged lines hidden (view full) ---

264 syslog(LOG_INFO, "error removing stale rulesets");
265 do_death(0);
266 }
267
268 /* We appear to be making headway, so actually mark our pid */
269 rewind(pidfp);
270 fprintf(pidfp, "%ld\n%s\n", (long)getpid(), luser);
271 fflush(pidfp);
176 syslog(LOG_ERR, "pid too large for ruleset name");
177 goto die;
178 }
179 }
180
181
182 /* Make our entry in /var/authpf as /var/authpf/ipaddr */
183 n = snprintf(pidfile, sizeof(pidfile), "%s/%s", PATH_PIDFILE, ipsrc);

--- 93 unchanged lines hidden (view full) ---

277 syslog(LOG_INFO, "error removing stale rulesets");
278 do_death(0);
279 }
280
281 /* We appear to be making headway, so actually mark our pid */
282 rewind(pidfp);
283 fprintf(pidfp, "%ld\n%s\n", (long)getpid(), luser);
284 fflush(pidfp);
272 (void) ftruncate(fileno(pidfp), ftell(pidfp));
285 (void) ftruncate(fileno(pidfp), ftello(pidfp));
273
274 if (change_filter(1, luser, ipsrc) == -1) {
275 printf("Unable to modify filters\r\n");
276 do_death(0);
277 }
286
287 if (change_filter(1, luser, ipsrc) == -1) {
288 printf("Unable to modify filters\r\n");
289 do_death(0);
290 }
291 if (change_table(1, luser, ipsrc) == -1) {
292 printf("Unable to modify table\r\n");
293 change_filter(0, luser, ipsrc);
294 do_death(0);
295 }
278
279 signal(SIGTERM, need_death);
280 signal(SIGINT, need_death);
281 signal(SIGALRM, need_death);
282 signal(SIGPIPE, need_death);
283 signal(SIGHUP, need_death);
284 signal(SIGSTOP, need_death);
285 signal(SIGTSTP, need_death);
286 while (1) {
296
297 signal(SIGTERM, need_death);
298 signal(SIGINT, need_death);
299 signal(SIGALRM, need_death);
300 signal(SIGPIPE, need_death);
301 signal(SIGHUP, need_death);
302 signal(SIGSTOP, need_death);
303 signal(SIGTSTP, need_death);
304 while (1) {
287 printf("\r\nHello %s, ", luser);
305 printf("\r\nHello %s. ", luser);
288 printf("You are authenticated from host \"%s\"\r\n", ipsrc);
289 setproctitle("%s@%s", luser, ipsrc);
290 print_message(PATH_MESSAGE);
291 while (1) {
292 sleep(10);
293 if (want_death)
294 do_death(1);
295 }

--- 4 unchanged lines hidden (view full) ---

300 printf("\r\n\r\nSorry, this service is currently unavailable due to ");
301 printf("technical difficulties\r\n\r\n");
302 print_message(PATH_PROBLEM);
303 printf("\r\nYour authentication process (pid %ld) was unable to run\n",
304 (long)getpid());
305 sleep(180); /* them lusers read reaaaaal slow */
306die:
307 do_death(0);
306 printf("You are authenticated from host \"%s\"\r\n", ipsrc);
307 setproctitle("%s@%s", luser, ipsrc);
308 print_message(PATH_MESSAGE);
309 while (1) {
310 sleep(10);
311 if (want_death)
312 do_death(1);
313 }

--- 4 unchanged lines hidden (view full) ---

318 printf("\r\n\r\nSorry, this service is currently unavailable due to ");
319 printf("technical difficulties\r\n\r\n");
320 print_message(PATH_PROBLEM);
321 printf("\r\nYour authentication process (pid %ld) was unable to run\n",
322 (long)getpid());
323 sleep(180); /* them lusers read reaaaaal slow */
324die:
325 do_death(0);
308
309 /* NOTREACHED */
310}
311
312/*
313 * reads config file in PATH_CONFFILE to set optional behaviours up
314 */
315static int
316read_config(FILE *f)
317{

--- 36 unchanged lines hidden (view full) ---

354 while ((*tp == ' ' || *tp == '\t') && tp >= pair[1])
355 *tp-- = '\0';
356
357 if (strcasecmp(pair[0], "anchor") == 0) {
358 if (!pair[1][0] || strlcpy(anchorname, pair[1],
359 sizeof(anchorname)) >= sizeof(anchorname))
360 goto parse_error;
361 }
326}
327
328/*
329 * reads config file in PATH_CONFFILE to set optional behaviours up
330 */
331static int
332read_config(FILE *f)
333{

--- 36 unchanged lines hidden (view full) ---

370 while ((*tp == ' ' || *tp == '\t') && tp >= pair[1])
371 *tp-- = '\0';
372
373 if (strcasecmp(pair[0], "anchor") == 0) {
374 if (!pair[1][0] || strlcpy(anchorname, pair[1],
375 sizeof(anchorname)) >= sizeof(anchorname))
376 goto parse_error;
377 }
378 if (strcasecmp(pair[0], "table") == 0) {
379 if (!pair[1][0] || strlcpy(tablename, pair[1],
380 sizeof(tablename)) >= sizeof(tablename))
381 goto parse_error;
382 }
362 } while (!feof(f) && !ferror(f));
363 fclose(f);
364 return (0);
365
366parse_error:
367 fclose(f);
368 syslog(LOG_ERR, "parse error, line %d of %s", i, PATH_CONFFILE);
369 return (1);

--- 167 unchanged lines hidden (view full) ---

537/*
538 * Search for rulesets left by other authpf processes (either because they
539 * died ungracefully or were terminated) and remove them.
540 */
541static int
542remove_stale_rulesets(void)
543{
544 struct pfioc_ruleset prs;
383 } while (!feof(f) && !ferror(f));
384 fclose(f);
385 return (0);
386
387parse_error:
388 fclose(f);
389 syslog(LOG_ERR, "parse error, line %d of %s", i, PATH_CONFFILE);
390 return (1);

--- 167 unchanged lines hidden (view full) ---

558/*
559 * Search for rulesets left by other authpf processes (either because they
560 * died ungracefully or were terminated) and remove them.
561 */
562static int
563remove_stale_rulesets(void)
564{
565 struct pfioc_ruleset prs;
545 const int action[PF_RULESET_MAX] = { PF_SCRUB,
546 PF_PASS, PF_NAT, PF_BINAT, PF_RDR };
547 u_int32_t nr, mnr;
548
549 memset(&prs, 0, sizeof(prs));
566 u_int32_t nr, mnr;
567
568 memset(&prs, 0, sizeof(prs));
550 strlcpy(prs.anchor, anchorname, sizeof(prs.anchor));
569 strlcpy(prs.path, anchorname, sizeof(prs.path));
551 if (ioctl(dev, DIOCGETRULESETS, &prs)) {
552 if (errno == EINVAL)
553 return (0);
554 else
555 return (1);
556 }
557
558 mnr = prs.nr;

--- 10 unchanged lines hidden (view full) ---

569 t = prs.name;
570 else
571 t++;
572 pid = strtoul(t, &s, 10);
573 if (!prs.name[0] || errno ||
574 (*s && (t == prs.name || *s != ')')))
575 return (1);
576 if (kill(pid, 0) && errno != EPERM) {
570 if (ioctl(dev, DIOCGETRULESETS, &prs)) {
571 if (errno == EINVAL)
572 return (0);
573 else
574 return (1);
575 }
576
577 mnr = prs.nr;

--- 10 unchanged lines hidden (view full) ---

588 t = prs.name;
589 else
590 t++;
591 pid = strtoul(t, &s, 10);
592 if (!prs.name[0] || errno ||
593 (*s && (t == prs.name || *s != ')')))
594 return (1);
595 if (kill(pid, 0) && errno != EPERM) {
577 int i;
596 int i;
597 struct pfioc_trans_e t_e[PF_RULESET_MAX+1];
598 struct pfioc_trans t;
578
599
579 for (i = 0; i < PF_RULESET_MAX; ++i) {
580 struct pfioc_rule pr;
581
582 memset(&pr, 0, sizeof(pr));
583 memcpy(pr.anchor, prs.anchor, sizeof(pr.anchor));
584 memcpy(pr.ruleset, prs.name, sizeof(pr.ruleset));
585 pr.rule.action = action[i];
586 if ((ioctl(dev, DIOCBEGINRULES, &pr) ||
587 ioctl(dev, DIOCCOMMITRULES, &pr)) &&
588 errno != EINVAL)
589 return (1);
600 bzero(&t, sizeof(t));
601 bzero(t_e, sizeof(t_e));
602 t.size = PF_RULESET_MAX+1;
603 t.esize = sizeof(t_e[0]);
604 t.array = t_e;
605 for (i = 0; i < PF_RULESET_MAX+1; ++i) {
606 t_e[i].rs_num = i;
607 snprintf(t_e[i].anchor, sizeof(t_e[i].anchor),
608 "%s/%s", anchorname, prs.name);
590 }
609 }
610 t_e[PF_RULESET_MAX].rs_num = PF_RULESET_TABLE;
611 if ((ioctl(dev, DIOCXBEGIN, &t) ||
612 ioctl(dev, DIOCXCOMMIT, &t)) &&
613 errno != EINVAL)
614 return (1);
591 mnr--;
592 } else
593 nr++;
594 }
595 return (0);
596}
597
598/*
599 * Add/remove filter entries for user "luser" from ip "ipsrc"
600 */
601static int
602change_filter(int add, const char *luser, const char *ipsrc)
603{
615 mnr--;
616 } else
617 nr++;
618 }
619 return (0);
620}
621
622/*
623 * Add/remove filter entries for user "luser" from ip "ipsrc"
624 */
625static int
626change_filter(int add, const char *luser, const char *ipsrc)
627{
604 char fn[MAXPATHLEN];
605 FILE *f = NULL;
606 struct pfctl pf;
607 struct pfr_buffer t;
608 int i;
628 char *pargv[13] = {
629 "pfctl", "-p", "/dev/pf", "-q", "-a", "anchor/ruleset",
630 "-D", "user_ip=X", "-D", "user_id=X", "-f",
631 "file", NULL
632 };
633 char *fdpath = NULL, *userstr = NULL, *ipstr = NULL;
634 char *rsn = NULL, *fn = NULL;
635 pid_t pid;
636 int s;
609
610 if (luser == NULL || !luser[0] || ipsrc == NULL || !ipsrc[0]) {
611 syslog(LOG_ERR, "invalid luser/ipsrc");
612 goto error;
613 }
614
637
638 if (luser == NULL || !luser[0] || ipsrc == NULL || !ipsrc[0]) {
639 syslog(LOG_ERR, "invalid luser/ipsrc");
640 goto error;
641 }
642
643 if (asprintf(&rsn, "%s/%s", anchorname, rulesetname) == -1)
644 goto no_mem;
645 if (asprintf(&fdpath, "/dev/fd/%d", dev) == -1)
646 goto no_mem;
647 if (asprintf(&ipstr, "user_ip=%s", ipsrc) == -1)
648 goto no_mem;
649 if (asprintf(&userstr, "user_id=%s", luser) == -1)
650 goto no_mem;
651
615 if (add) {
652 if (add) {
616 if ((i = snprintf(fn, sizeof(fn), "%s/%s/authpf.rules",
617 PATH_USER_DIR, luser)) < 0 || i >= sizeof(fn)) {
618 syslog(LOG_ERR, "user rule path too long");
619 goto error;
653 struct stat sb;
654
655 if (asprintf(&fn, "%s/%s/authpf.rules", PATH_USER_DIR, luser)
656 == -1)
657 goto no_mem;
658 if (stat(fn, &sb) == -1) {
659 free(fn);
660 if ((fn = strdup(PATH_PFRULES)) == NULL)
661 goto no_mem;
620 }
662 }
621 if ((f = fopen(fn, "r")) == NULL && errno != ENOENT) {
622 syslog(LOG_ERR, "cannot open %s (%m)", fn);
623 goto error;
624 }
625 if (f == NULL) {
626 if (strlcpy(fn, PATH_PFRULES, sizeof(fn)) >=
627 sizeof(fn)) {
628 syslog(LOG_ERR, "rule path too long");
629 goto error;
630 }
631 if ((f = fopen(fn, "r")) == NULL) {
632 syslog(LOG_ERR, "cannot open %s (%m)", fn);
633 goto error;
634 }
635 }
636 }
663 }
664 pargv[2] = fdpath;
665 pargv[5] = rsn;
666 pargv[7] = userstr;
667 pargv[9] = ipstr;
668 if (!add)
669 pargv[11] = "/dev/null";
670 else
671 pargv[11] = fn;
637
672
638 if (pfctl_load_fingerprints(dev, 0)) {
639 syslog(LOG_ERR, "unable to load kernel's OS fingerprints");
640 goto error;
673 switch (pid = fork()) {
674 case -1:
675 err(1, "fork failed");
676 case 0:
677 execvp(PATH_PFCTL, pargv);
678 warn("exec of %s failed", PATH_PFCTL);
679 _exit(1);
641 }
680 }
642 bzero(&t, sizeof(t));
643 t.pfrb_type = PFRB_TRANS;
644 memset(&pf, 0, sizeof(pf));
645 for (i = 0; i < PF_RULESET_MAX; ++i) {
646 if (pfctl_add_trans(&t, i, anchorname, rulesetname)) {
647 syslog(LOG_ERR, "pfctl_add_trans %m");
648 goto error;
649 }
650 }
651 if (pfctl_trans(dev, &t, DIOCXBEGIN, 0)) {
652 syslog(LOG_ERR, "DIOCXBEGIN (%s) %m", add?"add":"remove");
653 goto error;
654 }
655
681
656 if (add) {
657 if (symset("user_ip", ipsrc, 0) ||
658 symset("user_id", luser, 0)) {
659 syslog(LOG_ERR, "symset");
682 /* parent */
683 waitpid(pid, &s, 0);
684 if (s != 0) {
685 if (WIFEXITED(s)) {
686 syslog(LOG_ERR, "pfctl exited abnormally");
660 goto error;
661 }
687 goto error;
688 }
662
663 pf.dev = dev;
664 pf.trans = &t;
665 pf.anchor = anchorname;
666 pf.ruleset = rulesetname;
667
668 infile = fn;
669 if (parse_rules(f, &pf) < 0) {
670 syslog(LOG_ERR, "syntax error in rule file: "
671 "authpf rules not loaded");
672 goto error;
673 }
674
675 infile = NULL;
676 fclose(f);
677 f = NULL;
678 }
679
689 }
690
680 if (pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) {
681 syslog(LOG_ERR, "DIOCXCOMMIT (%s) %m", add?"add":"remove");
682 goto error;
683 }
684
685 if (add) {
686 gettimeofday(&Tstart, NULL);
687 syslog(LOG_INFO, "allowing %s, user %s", ipsrc, luser);
688 } else {
689 gettimeofday(&Tend, NULL);
690 syslog(LOG_INFO, "removed %s, user %s - duration %ld seconds",
691 ipsrc, luser, Tend.tv_sec - Tstart.tv_sec);
692 }
693 return (0);
691 if (add) {
692 gettimeofday(&Tstart, NULL);
693 syslog(LOG_INFO, "allowing %s, user %s", ipsrc, luser);
694 } else {
695 gettimeofday(&Tend, NULL);
696 syslog(LOG_INFO, "removed %s, user %s - duration %ld seconds",
697 ipsrc, luser, Tend.tv_sec - Tstart.tv_sec);
698 }
699 return (0);
694
700no_mem:
701 syslog(LOG_ERR, "malloc failed");
695error:
702error:
696 if (f != NULL)
697 fclose(f);
698 if (pfctl_trans(dev, &t, DIOCXROLLBACK, 0))
699 syslog(LOG_ERR, "DIOCXROLLBACK (%s) %m", add?"add":"remove");
700
703 free(fdpath);
704 fdpath = NULL;
705 free(rsn);
706 rsn = NULL;
707 free(userstr);
708 userstr = NULL;
709 free(ipstr);
710 ipstr = NULL;
711 free(fn);
712 fn = NULL;
701 infile = NULL;
702 return (-1);
703}
704
705/*
713 infile = NULL;
714 return (-1);
715}
716
717/*
718 * Add/remove this IP from the "authpf_users" table.
719 */
720static int
721change_table(int add, const char *luser, const char *ipsrc)
722{
723 struct pfioc_table io;
724 struct pfr_addr addr;
725
726 bzero(&io, sizeof(io));
727 strlcpy(io.pfrio_table.pfrt_name, tablename, sizeof(io.pfrio_table));
728 io.pfrio_buffer = &addr;
729 io.pfrio_esize = sizeof(addr);
730 io.pfrio_size = 1;
731
732 bzero(&addr, sizeof(addr));
733 if (ipsrc == NULL || !ipsrc[0])
734 return (-1);
735 if (inet_pton(AF_INET, ipsrc, &addr.pfra_ip4addr) == 1) {
736 addr.pfra_af = AF_INET;
737 addr.pfra_net = 32;
738 } else if (inet_pton(AF_INET6, ipsrc, &addr.pfra_ip6addr) == 1) {
739 addr.pfra_af = AF_INET6;
740 addr.pfra_net = 128;
741 } else {
742 syslog(LOG_ERR, "invalid ipsrc");
743 return (-1);
744 }
745
746 if (ioctl(dev, add ? DIOCRADDADDRS : DIOCRDELADDRS, &io) &&
747 errno != ESRCH) {
748 syslog(LOG_ERR, "cannot %s %s from table %s: %s",
749 add ? "add" : "remove", ipsrc, tablename,
750 strerror(errno));
751 return (-1);
752 }
753 return (0);
754}
755
756/*
706 * This is to kill off states that would otherwise be left behind stateful
707 * rules. This means we don't need to allow in more traffic than we really
708 * want to, since we don't have to worry about any luser sessions lasting
709 * longer than their ssh session. This function is based on
710 * pfctl_kill_states from pfctl.
711 */
712static void
713authpf_kill_states(void)
714{
715 struct pfioc_state_kill psk;
757 * This is to kill off states that would otherwise be left behind stateful
758 * rules. This means we don't need to allow in more traffic than we really
759 * want to, since we don't have to worry about any luser sessions lasting
760 * longer than their ssh session. This function is based on
761 * pfctl_kill_states from pfctl.
762 */
763static void
764authpf_kill_states(void)
765{
766 struct pfioc_state_kill psk;
716 struct in_addr target;
767 struct pf_addr target;
717
718 memset(&psk, 0, sizeof(psk));
768
769 memset(&psk, 0, sizeof(psk));
719 psk.psk_af = AF_INET;
770 memset(&target, 0, sizeof(target));
720
771
721 inet_pton(AF_INET, ipsrc, &target);
772 if (inet_pton(AF_INET, ipsrc, &target.v4) == 1)
773 psk.psk_af = AF_INET;
774 else if (inet_pton(AF_INET6, ipsrc, &target.v6) == 1)
775 psk.psk_af = AF_INET6;
776 else {
777 syslog(LOG_ERR, "inet_pton(%s) failed", ipsrc);
778 return;
779 }
722
723 /* Kill all states from ipsrc */
780
781 /* Kill all states from ipsrc */
724 psk.psk_src.addr.v.a.addr.v4 = target;
782 memcpy(&psk.psk_src.addr.v.a.addr, &target,
783 sizeof(psk.psk_src.addr.v.a.addr));
725 memset(&psk.psk_src.addr.v.a.mask, 0xff,
726 sizeof(psk.psk_src.addr.v.a.mask));
727 if (ioctl(dev, DIOCKILLSTATES, &psk))
728 syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)");
729
730 /* Kill all states to ipsrc */
784 memset(&psk.psk_src.addr.v.a.mask, 0xff,
785 sizeof(psk.psk_src.addr.v.a.mask));
786 if (ioctl(dev, DIOCKILLSTATES, &psk))
787 syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)");
788
789 /* Kill all states to ipsrc */
731 psk.psk_af = AF_INET;
732 memset(&psk.psk_src, 0, sizeof(psk.psk_src));
790 memset(&psk.psk_src, 0, sizeof(psk.psk_src));
733 psk.psk_dst.addr.v.a.addr.v4 = target;
791 memcpy(&psk.psk_dst.addr.v.a.addr, &target,
792 sizeof(psk.psk_dst.addr.v.a.addr));
734 memset(&psk.psk_dst.addr.v.a.mask, 0xff,
735 sizeof(psk.psk_dst.addr.v.a.mask));
736 if (ioctl(dev, DIOCKILLSTATES, &psk))
737 syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)");
738}
739
740/* signal handler that makes us go away properly */
741static void
742need_death(int signo)
743{
744 want_death = 1;
745}
746
747/*
748 * function that removes our stuff when we go away.
749 */
793 memset(&psk.psk_dst.addr.v.a.mask, 0xff,
794 sizeof(psk.psk_dst.addr.v.a.mask));
795 if (ioctl(dev, DIOCKILLSTATES, &psk))
796 syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)");
797}
798
799/* signal handler that makes us go away properly */
800static void
801need_death(int signo)
802{
803 want_death = 1;
804}
805
806/*
807 * function that removes our stuff when we go away.
808 */
750#ifdef __FreeBSD__
751static __dead2 void
752#else
753static __dead void
809static __dead void
754#endif
755do_death(int active)
756{
757 int ret = 0;
758
759 if (active) {
760 change_filter(0, luser, ipsrc);
810do_death(int active)
811{
812 int ret = 0;
813
814 if (active) {
815 change_filter(0, luser, ipsrc);
816 change_table(0, luser, ipsrc);
761 authpf_kill_states();
762 remove_stale_rulesets();
763 }
764 if (pidfp)
765 ftruncate(fileno(pidfp), 0);
766 if (pidfile[0])
767 if (unlink(pidfile) == -1)
768 syslog(LOG_ERR, "cannot unlink %s (%m)", pidfile);
769 exit(ret);
770}
817 authpf_kill_states();
818 remove_stale_rulesets();
819 }
820 if (pidfp)
821 ftruncate(fileno(pidfp), 0);
822 if (pidfile[0])
823 if (unlink(pidfile) == -1)
824 syslog(LOG_ERR, "cannot unlink %s (%m)", pidfile);
825 exit(ret);
826}
771
772/*
773 * callbacks for parse_rules(void)
774 */
775
776int
777pfctl_add_rule(struct pfctl *pf, struct pf_rule *r)
778{
779 u_int8_t rs_num;
780 struct pfioc_rule pr;
781
782 switch (r->action) {
783 case PF_PASS:
784 case PF_DROP:
785 rs_num = PF_RULESET_FILTER;
786 break;
787 case PF_SCRUB:
788 rs_num = PF_RULESET_SCRUB;
789 break;
790 case PF_NAT:
791 case PF_NONAT:
792 rs_num = PF_RULESET_NAT;
793 break;
794 case PF_RDR:
795 case PF_NORDR:
796 rs_num = PF_RULESET_RDR;
797 break;
798 case PF_BINAT:
799 case PF_NOBINAT:
800 rs_num = PF_RULESET_BINAT;
801 break;
802 default:
803 syslog(LOG_ERR, "invalid rule action %d", r->action);
804 return (1);
805 }
806
807 bzero(&pr, sizeof(pr));
808 strlcpy(pr.anchor, pf->anchor, sizeof(pr.anchor));
809 strlcpy(pr.ruleset, pf->ruleset, sizeof(pr.ruleset));
810 if (pfctl_add_pool(pf, &r->rpool, r->af))
811 return (1);
812 pr.ticket = pfctl_get_ticket(pf->trans, rs_num, pf->anchor,
813 pf->ruleset);
814 pr.pool_ticket = pf->paddr.ticket;
815 memcpy(&pr.rule, r, sizeof(pr.rule));
816 if (ioctl(pf->dev, DIOCADDRULE, &pr)) {
817 syslog(LOG_ERR, "DIOCADDRULE %m");
818 return (1);
819 }
820 pfctl_clear_pool(&r->rpool);
821 return (0);
822}
823
824int
825pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
826{
827 struct pf_pooladdr *pa;
828
829 if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr)) {
830 syslog(LOG_ERR, "DIOCBEGINADDRS %m");
831 return (1);
832 }
833 pf->paddr.af = af;
834 TAILQ_FOREACH(pa, &p->list, entries) {
835 memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
836 if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr)) {
837 syslog(LOG_ERR, "DIOCADDADDR %m");
838 return (1);
839 }
840 }
841 return (0);
842}
843
844void
845pfctl_clear_pool(struct pf_pool *pool)
846{
847 struct pf_pooladdr *pa;
848
849 while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
850 TAILQ_REMOVE(&pool->list, pa, entries);
851 free(pa);
852 }
853}
854
855int
856pfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
857{
858 fprintf(stderr, "altq rules not supported in authpf\n");
859 return (1);
860}
861
862int
863pfctl_set_optimization(struct pfctl *pf, const char *opt)
864{
865 fprintf(stderr, "set optimization not supported in authpf\n");
866 return (1);
867}
868
869int
870pfctl_set_logif(struct pfctl *pf, char *ifname)
871{
872 fprintf(stderr, "set loginterface not supported in authpf\n");
873 return (1);
874}
875
876int
877pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
878{
879 fprintf(stderr, "set hostid not supported in authpf\n");
880 return (1);
881}
882
883int
884pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
885{
886 fprintf(stderr, "set timeout not supported in authpf\n");
887 return (1);
888}
889
890int
891pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
892{
893 fprintf(stderr, "set limit not supported in authpf\n");
894 return (1);
895}
896
897int
898pfctl_set_debug(struct pfctl *pf, char *d)
899{
900 fprintf(stderr, "set debug not supported in authpf\n");
901 return (1);
902}
903
904int
905pfctl_define_table(char *name, int flags, int addrs, const char *anchor,
906 const char *ruleset, struct pfr_buffer *ab, u_int32_t ticket)
907{
908 fprintf(stderr, "table definitions not yet supported in authpf\n");
909 return (1);
910}
911
912int
913pfctl_rules(int dev, char *filename, int opts, char *anchorname,
914 char *rulesetname, struct pfr_buffer *t)
915{
916 /* never called, no anchors inside anchors, but we need the stub */
917 fprintf(stderr, "load anchor not supported from authpf\n");
918 return (1);
919}
920
921void
922pfctl_print_title(char *title)
923{
924}