summaryrefslogtreecommitdiffstats
path: root/contrib/pf/authpf/authpf.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/pf/authpf/authpf.c')
-rw-r--r--contrib/pf/authpf/authpf.c439
1 files changed, 177 insertions, 262 deletions
diff --git a/contrib/pf/authpf/authpf.c b/contrib/pf/authpf/authpf.c
index 515cf8e..1ae6aa4 100644
--- a/contrib/pf/authpf/authpf.c
+++ b/contrib/pf/authpf/authpf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: authpf.c,v 1.75 2004/01/29 01:55:10 deraadt Exp $ */
+/* $OpenBSD: authpf.c,v 1.89 2005/02/10 04:24:15 joel Exp $ */
/*
* Copyright (C) 1998 - 2002 Bob Beck (beck@openbsd.org).
@@ -29,7 +29,9 @@
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
+#include <sys/stat.h>
#include <sys/time.h>
+#include <sys/wait.h>
#include <net/if.h>
#include <net/pfvar.h>
@@ -37,6 +39,7 @@
#include <err.h>
#include <errno.h>
+#include <login_cap.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
@@ -45,9 +48,6 @@
#include <syslog.h>
#include <unistd.h>
-#include <pfctl_parser.h>
-#include <pfctl.h>
-
#include "pathnames.h"
extern int symset(const char *, const char *, int);
@@ -58,11 +58,13 @@ static int allowed_luser(char *);
static int check_luser(char *, char *);
static int remove_stale_rulesets(void);
static int change_filter(int, const char *, const char *);
+static int change_table(int, const char *, const char *);
static void authpf_kill_states(void);
int dev; /* pf device */
char anchorname[PF_ANCHOR_NAME_SIZE] = "authpf";
-char rulesetname[PF_RULESET_NAME_SIZE];
+char rulesetname[MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 2];
+char tablename[PF_TABLE_NAME_SIZE] = "authpf_users";
FILE *pidfp;
char *infile; /* file name printed by yyerror() in parse.y */
@@ -87,10 +89,12 @@ main(int argc, char *argv[])
{
int lockcnt = 0, n, pidfd;
FILE *config;
- struct in_addr ina;
+ struct in6_addr ina;
struct passwd *pw;
char *cp;
uid_t uid;
+ char *shell;
+ login_cap_t *lc;
config = fopen(PATH_CONFFILE, "r");
@@ -114,7 +118,8 @@ main(int argc, char *argv[])
exit(1);
}
*cp = '\0';
- if (inet_pton(AF_INET, ipsrc, &ina) != 1) {
+ if (inet_pton(AF_INET, ipsrc, &ina) != 1 &&
+ inet_pton(AF_INET6, ipsrc, &ina) != 1) {
syslog(LOG_ERR,
"cannot determine IP from SSH_CLIENT %s", ipsrc);
exit(1);
@@ -128,16 +133,31 @@ main(int argc, char *argv[])
uid = getuid();
pw = getpwuid(uid);
+ endpwent();
if (pw == NULL) {
syslog(LOG_ERR, "cannot find user for uid %u", uid);
goto die;
}
- if (strcmp(pw->pw_shell, PATH_AUTHPF_SHELL)) {
+
+ if ((lc = login_getclass(pw->pw_class)) != NULL)
+ shell = login_getcapstr(lc, "shell", pw->pw_shell,
+ pw->pw_shell);
+ else
+ shell = pw->pw_shell;
+
+ login_close(lc);
+
+ if (strcmp(shell, PATH_AUTHPF_SHELL)) {
syslog(LOG_ERR, "wrong shell for user %s, uid %u",
pw->pw_name, pw->pw_uid);
+ if (shell != pw->pw_shell)
+ free(shell);
goto die;
}
+ if (shell != pw->pw_shell)
+ free(shell);
+
/*
* Paranoia, but this data _does_ come from outside authpf, and
* truncation would be bad.
@@ -148,11 +168,11 @@ main(int argc, char *argv[])
}
if ((n = snprintf(rulesetname, sizeof(rulesetname), "%s(%ld)",
- luser, (long)getpid())) < 0 || n >= sizeof(rulesetname)) {
+ luser, (long)getpid())) < 0 || (u_int)n >= sizeof(rulesetname)) {
syslog(LOG_INFO, "%s(%ld) too large, ruleset name will be %ld",
luser, (long)getpid(), (long)getpid());
if ((n = snprintf(rulesetname, sizeof(rulesetname), "%ld",
- (long)getpid())) < 0 || n >= sizeof(rulesetname)) {
+ (long)getpid())) < 0 || (u_int)n >= sizeof(rulesetname)) {
syslog(LOG_ERR, "pid too large for ruleset name");
goto die;
}
@@ -262,12 +282,17 @@ main(int argc, char *argv[])
rewind(pidfp);
fprintf(pidfp, "%ld\n%s\n", (long)getpid(), luser);
fflush(pidfp);
- (void) ftruncate(fileno(pidfp), ftell(pidfp));
+ (void) ftruncate(fileno(pidfp), ftello(pidfp));
if (change_filter(1, luser, ipsrc) == -1) {
printf("Unable to modify filters\r\n");
do_death(0);
}
+ if (change_table(1, luser, ipsrc) == -1) {
+ printf("Unable to modify table\r\n");
+ change_filter(0, luser, ipsrc);
+ do_death(0);
+ }
signal(SIGTERM, need_death);
signal(SIGINT, need_death);
@@ -277,7 +302,7 @@ main(int argc, char *argv[])
signal(SIGSTOP, need_death);
signal(SIGTSTP, need_death);
while (1) {
- printf("\r\nHello %s, ", luser);
+ printf("\r\nHello %s. ", luser);
printf("You are authenticated from host \"%s\"\r\n", ipsrc);
setproctitle("%s@%s", luser, ipsrc);
print_message(PATH_MESSAGE);
@@ -350,6 +375,11 @@ read_config(FILE *f)
sizeof(anchorname)) >= sizeof(anchorname))
goto parse_error;
}
+ if (strcasecmp(pair[0], "table") == 0) {
+ if (!pair[1][0] || strlcpy(tablename, pair[1],
+ sizeof(tablename)) >= sizeof(tablename))
+ goto parse_error;
+ }
} while (!feof(f) && !ferror(f));
fclose(f);
return (0);
@@ -533,12 +563,10 @@ static int
remove_stale_rulesets(void)
{
struct pfioc_ruleset prs;
- const int action[PF_RULESET_MAX] = { PF_SCRUB,
- PF_PASS, PF_NAT, PF_BINAT, PF_RDR };
u_int32_t nr, mnr;
memset(&prs, 0, sizeof(prs));
- strlcpy(prs.anchor, anchorname, sizeof(prs.anchor));
+ strlcpy(prs.path, anchorname, sizeof(prs.path));
if (ioctl(dev, DIOCGETRULESETS, &prs)) {
if (errno == EINVAL)
return (0);
@@ -565,20 +593,25 @@ remove_stale_rulesets(void)
(*s && (t == prs.name || *s != ')')))
return (1);
if (kill(pid, 0) && errno != EPERM) {
- int i;
-
- for (i = 0; i < PF_RULESET_MAX; ++i) {
- struct pfioc_rule pr;
-
- memset(&pr, 0, sizeof(pr));
- memcpy(pr.anchor, prs.anchor, sizeof(pr.anchor));
- memcpy(pr.ruleset, prs.name, sizeof(pr.ruleset));
- pr.rule.action = action[i];
- if ((ioctl(dev, DIOCBEGINRULES, &pr) ||
- ioctl(dev, DIOCCOMMITRULES, &pr)) &&
- errno != EINVAL)
- return (1);
+ int i;
+ struct pfioc_trans_e t_e[PF_RULESET_MAX+1];
+ struct pfioc_trans t;
+
+ bzero(&t, sizeof(t));
+ bzero(t_e, sizeof(t_e));
+ t.size = PF_RULESET_MAX+1;
+ t.esize = sizeof(t_e[0]);
+ t.array = t_e;
+ for (i = 0; i < PF_RULESET_MAX+1; ++i) {
+ t_e[i].rs_num = i;
+ snprintf(t_e[i].anchor, sizeof(t_e[i].anchor),
+ "%s/%s", anchorname, prs.name);
}
+ t_e[PF_RULESET_MAX].rs_num = PF_RULESET_TABLE;
+ if ((ioctl(dev, DIOCXBEGIN, &t) ||
+ ioctl(dev, DIOCXCOMMIT, &t)) &&
+ errno != EINVAL)
+ return (1);
mnr--;
} else
nr++;
@@ -592,85 +625,67 @@ remove_stale_rulesets(void)
static int
change_filter(int add, const char *luser, const char *ipsrc)
{
- char fn[MAXPATHLEN];
- FILE *f = NULL;
- struct pfctl pf;
- struct pfr_buffer t;
- int i;
+ char *pargv[13] = {
+ "pfctl", "-p", "/dev/pf", "-q", "-a", "anchor/ruleset",
+ "-D", "user_ip=X", "-D", "user_id=X", "-f",
+ "file", NULL
+ };
+ char *fdpath = NULL, *userstr = NULL, *ipstr = NULL;
+ char *rsn = NULL, *fn = NULL;
+ pid_t pid;
+ int s;
if (luser == NULL || !luser[0] || ipsrc == NULL || !ipsrc[0]) {
syslog(LOG_ERR, "invalid luser/ipsrc");
goto error;
}
- if (add) {
- if ((i = snprintf(fn, sizeof(fn), "%s/%s/authpf.rules",
- PATH_USER_DIR, luser)) < 0 || i >= sizeof(fn)) {
- syslog(LOG_ERR, "user rule path too long");
- goto error;
- }
- if ((f = fopen(fn, "r")) == NULL && errno != ENOENT) {
- syslog(LOG_ERR, "cannot open %s (%m)", fn);
- goto error;
- }
- if (f == NULL) {
- if (strlcpy(fn, PATH_PFRULES, sizeof(fn)) >=
- sizeof(fn)) {
- syslog(LOG_ERR, "rule path too long");
- goto error;
- }
- if ((f = fopen(fn, "r")) == NULL) {
- syslog(LOG_ERR, "cannot open %s (%m)", fn);
- goto error;
- }
- }
- }
-
- if (pfctl_load_fingerprints(dev, 0)) {
- syslog(LOG_ERR, "unable to load kernel's OS fingerprints");
- goto error;
- }
- bzero(&t, sizeof(t));
- t.pfrb_type = PFRB_TRANS;
- memset(&pf, 0, sizeof(pf));
- for (i = 0; i < PF_RULESET_MAX; ++i) {
- if (pfctl_add_trans(&t, i, anchorname, rulesetname)) {
- syslog(LOG_ERR, "pfctl_add_trans %m");
- goto error;
- }
- }
- if (pfctl_trans(dev, &t, DIOCXBEGIN, 0)) {
- syslog(LOG_ERR, "DIOCXBEGIN (%s) %m", add?"add":"remove");
- goto error;
- }
+ if (asprintf(&rsn, "%s/%s", anchorname, rulesetname) == -1)
+ goto no_mem;
+ if (asprintf(&fdpath, "/dev/fd/%d", dev) == -1)
+ goto no_mem;
+ if (asprintf(&ipstr, "user_ip=%s", ipsrc) == -1)
+ goto no_mem;
+ if (asprintf(&userstr, "user_id=%s", luser) == -1)
+ goto no_mem;
if (add) {
- if (symset("user_ip", ipsrc, 0) ||
- symset("user_id", luser, 0)) {
- syslog(LOG_ERR, "symset");
- goto error;
+ struct stat sb;
+
+ if (asprintf(&fn, "%s/%s/authpf.rules", PATH_USER_DIR, luser)
+ == -1)
+ goto no_mem;
+ if (stat(fn, &sb) == -1) {
+ free(fn);
+ if ((fn = strdup(PATH_PFRULES)) == NULL)
+ goto no_mem;
}
-
- pf.dev = dev;
- pf.trans = &t;
- pf.anchor = anchorname;
- pf.ruleset = rulesetname;
-
- infile = fn;
- if (parse_rules(f, &pf) < 0) {
- syslog(LOG_ERR, "syntax error in rule file: "
- "authpf rules not loaded");
+ }
+ pargv[2] = fdpath;
+ pargv[5] = rsn;
+ pargv[7] = userstr;
+ pargv[9] = ipstr;
+ if (!add)
+ pargv[11] = "/dev/null";
+ else
+ pargv[11] = fn;
+
+ switch (pid = fork()) {
+ case -1:
+ err(1, "fork failed");
+ case 0:
+ execvp(PATH_PFCTL, pargv);
+ warn("exec of %s failed", PATH_PFCTL);
+ _exit(1);
+ }
+
+ /* parent */
+ waitpid(pid, &s, 0);
+ if (s != 0) {
+ if (WIFEXITED(s)) {
+ syslog(LOG_ERR, "pfctl exited abnormally");
goto error;
}
-
- infile = NULL;
- fclose(f);
- f = NULL;
- }
-
- if (pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) {
- syslog(LOG_ERR, "DIOCXCOMMIT (%s) %m", add?"add":"remove");
- goto error;
}
if (add) {
@@ -682,18 +697,63 @@ change_filter(int add, const char *luser, const char *ipsrc)
ipsrc, luser, Tend.tv_sec - Tstart.tv_sec);
}
return (0);
-
+no_mem:
+ syslog(LOG_ERR, "malloc failed");
error:
- if (f != NULL)
- fclose(f);
- if (pfctl_trans(dev, &t, DIOCXROLLBACK, 0))
- syslog(LOG_ERR, "DIOCXROLLBACK (%s) %m", add?"add":"remove");
-
+ free(fdpath);
+ fdpath = NULL;
+ free(rsn);
+ rsn = NULL;
+ free(userstr);
+ userstr = NULL;
+ free(ipstr);
+ ipstr = NULL;
+ free(fn);
+ fn = NULL;
infile = NULL;
return (-1);
}
/*
+ * Add/remove this IP from the "authpf_users" table.
+ */
+static int
+change_table(int add, const char *luser, const char *ipsrc)
+{
+ struct pfioc_table io;
+ struct pfr_addr addr;
+
+ bzero(&io, sizeof(io));
+ strlcpy(io.pfrio_table.pfrt_name, tablename, sizeof(io.pfrio_table));
+ io.pfrio_buffer = &addr;
+ io.pfrio_esize = sizeof(addr);
+ io.pfrio_size = 1;
+
+ bzero(&addr, sizeof(addr));
+ if (ipsrc == NULL || !ipsrc[0])
+ return (-1);
+ if (inet_pton(AF_INET, ipsrc, &addr.pfra_ip4addr) == 1) {
+ addr.pfra_af = AF_INET;
+ addr.pfra_net = 32;
+ } else if (inet_pton(AF_INET6, ipsrc, &addr.pfra_ip6addr) == 1) {
+ addr.pfra_af = AF_INET6;
+ addr.pfra_net = 128;
+ } else {
+ syslog(LOG_ERR, "invalid ipsrc");
+ return (-1);
+ }
+
+ if (ioctl(dev, add ? DIOCRADDADDRS : DIOCRDELADDRS, &io) &&
+ errno != ESRCH) {
+ syslog(LOG_ERR, "cannot %s %s from table %s: %s",
+ add ? "add" : "remove", ipsrc, tablename,
+ strerror(errno));
+ return (-1);
+ }
+ return (0);
+}
+
+/*
* This is to kill off states that would otherwise be left behind stateful
* rules. This means we don't need to allow in more traffic than we really
* want to, since we don't have to worry about any luser sessions lasting
@@ -704,24 +764,32 @@ static void
authpf_kill_states(void)
{
struct pfioc_state_kill psk;
- struct in_addr target;
+ struct pf_addr target;
memset(&psk, 0, sizeof(psk));
- psk.psk_af = AF_INET;
+ memset(&target, 0, sizeof(target));
- inet_pton(AF_INET, ipsrc, &target);
+ if (inet_pton(AF_INET, ipsrc, &target.v4) == 1)
+ psk.psk_af = AF_INET;
+ else if (inet_pton(AF_INET6, ipsrc, &target.v6) == 1)
+ psk.psk_af = AF_INET6;
+ else {
+ syslog(LOG_ERR, "inet_pton(%s) failed", ipsrc);
+ return;
+ }
/* Kill all states from ipsrc */
- psk.psk_src.addr.v.a.addr.v4 = target;
+ memcpy(&psk.psk_src.addr.v.a.addr, &target,
+ sizeof(psk.psk_src.addr.v.a.addr));
memset(&psk.psk_src.addr.v.a.mask, 0xff,
sizeof(psk.psk_src.addr.v.a.mask));
if (ioctl(dev, DIOCKILLSTATES, &psk))
syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)");
/* Kill all states to ipsrc */
- psk.psk_af = AF_INET;
memset(&psk.psk_src, 0, sizeof(psk.psk_src));
- psk.psk_dst.addr.v.a.addr.v4 = target;
+ memcpy(&psk.psk_dst.addr.v.a.addr, &target,
+ sizeof(psk.psk_dst.addr.v.a.addr));
memset(&psk.psk_dst.addr.v.a.mask, 0xff,
sizeof(psk.psk_dst.addr.v.a.mask));
if (ioctl(dev, DIOCKILLSTATES, &psk))
@@ -745,6 +813,7 @@ do_death(int active)
if (active) {
change_filter(0, luser, ipsrc);
+ change_table(0, luser, ipsrc);
authpf_kill_states();
remove_stale_rulesets();
}
@@ -755,157 +824,3 @@ do_death(int active)
syslog(LOG_ERR, "cannot unlink %s (%m)", pidfile);
exit(ret);
}
-
-/*
- * callbacks for parse_rules(void)
- */
-
-int
-pfctl_add_rule(struct pfctl *pf, struct pf_rule *r)
-{
- u_int8_t rs_num;
- struct pfioc_rule pr;
-
- switch (r->action) {
- case PF_PASS:
- case PF_DROP:
- rs_num = PF_RULESET_FILTER;
- break;
- case PF_SCRUB:
- rs_num = PF_RULESET_SCRUB;
- break;
- case PF_NAT:
- case PF_NONAT:
- rs_num = PF_RULESET_NAT;
- break;
- case PF_RDR:
- case PF_NORDR:
- rs_num = PF_RULESET_RDR;
- break;
- case PF_BINAT:
- case PF_NOBINAT:
- rs_num = PF_RULESET_BINAT;
- break;
- default:
- syslog(LOG_ERR, "invalid rule action %d", r->action);
- return (1);
- }
-
- bzero(&pr, sizeof(pr));
- strlcpy(pr.anchor, pf->anchor, sizeof(pr.anchor));
- strlcpy(pr.ruleset, pf->ruleset, sizeof(pr.ruleset));
- if (pfctl_add_pool(pf, &r->rpool, r->af))
- return (1);
- pr.ticket = pfctl_get_ticket(pf->trans, rs_num, pf->anchor,
- pf->ruleset);
- pr.pool_ticket = pf->paddr.ticket;
- memcpy(&pr.rule, r, sizeof(pr.rule));
- if (ioctl(pf->dev, DIOCADDRULE, &pr)) {
- syslog(LOG_ERR, "DIOCADDRULE %m");
- return (1);
- }
- pfctl_clear_pool(&r->rpool);
- return (0);
-}
-
-int
-pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
-{
- struct pf_pooladdr *pa;
-
- if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr)) {
- syslog(LOG_ERR, "DIOCBEGINADDRS %m");
- return (1);
- }
- pf->paddr.af = af;
- TAILQ_FOREACH(pa, &p->list, entries) {
- memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
- if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr)) {
- syslog(LOG_ERR, "DIOCADDADDR %m");
- return (1);
- }
- }
- return (0);
-}
-
-void
-pfctl_clear_pool(struct pf_pool *pool)
-{
- struct pf_pooladdr *pa;
-
- while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
- TAILQ_REMOVE(&pool->list, pa, entries);
- free(pa);
- }
-}
-
-int
-pfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
-{
- fprintf(stderr, "altq rules not supported in authpf\n");
- return (1);
-}
-
-int
-pfctl_set_optimization(struct pfctl *pf, const char *opt)
-{
- fprintf(stderr, "set optimization not supported in authpf\n");
- return (1);
-}
-
-int
-pfctl_set_logif(struct pfctl *pf, char *ifname)
-{
- fprintf(stderr, "set loginterface not supported in authpf\n");
- return (1);
-}
-
-int
-pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
-{
- fprintf(stderr, "set hostid not supported in authpf\n");
- return (1);
-}
-
-int
-pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
-{
- fprintf(stderr, "set timeout not supported in authpf\n");
- return (1);
-}
-
-int
-pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
-{
- fprintf(stderr, "set limit not supported in authpf\n");
- return (1);
-}
-
-int
-pfctl_set_debug(struct pfctl *pf, char *d)
-{
- fprintf(stderr, "set debug not supported in authpf\n");
- return (1);
-}
-
-int
-pfctl_define_table(char *name, int flags, int addrs, const char *anchor,
- const char *ruleset, struct pfr_buffer *ab, u_int32_t ticket)
-{
- fprintf(stderr, "table definitions not yet supported in authpf\n");
- return (1);
-}
-
-int
-pfctl_rules(int dev, char *filename, int opts, char *anchorname,
- char *rulesetname, struct pfr_buffer *t)
-{
- /* never called, no anchors inside anchors, but we need the stub */
- fprintf(stderr, "load anchor not supported from authpf\n");
- return (1);
-}
-
-void
-pfctl_print_title(char *title)
-{
-}
OpenPOWER on IntegriCloud