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} | |