1d316f7c9SJohn Marino /* $OpenBSD: authpf.c,v 1.112 2009/01/10 19:08:53 miod Exp $ */
295cc27f0SJoerg Sonnenberger
395cc27f0SJoerg Sonnenberger /*
470224baaSJan Lentfer * Copyright (C) 1998 - 2007 Bob Beck (beck@openbsd.org).
595cc27f0SJoerg Sonnenberger *
6d316f7c9SJohn Marino * Permission to use, copy, modify, and distribute this software for any
7d316f7c9SJohn Marino * purpose with or without fee is hereby granted, provided that the above
8d316f7c9SJohn Marino * copyright notice and this permission notice appear in all copies.
995cc27f0SJoerg Sonnenberger *
10d316f7c9SJohn Marino * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11d316f7c9SJohn Marino * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12d316f7c9SJohn Marino * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13d316f7c9SJohn Marino * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14d316f7c9SJohn Marino * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15d316f7c9SJohn Marino * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16d316f7c9SJohn Marino * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17d316f7c9SJohn Marino *
18d316f7c9SJohn Marino * $FreeBSD: head/contrib/pf/authpf/authpf.c 223637 2011-06-28 11:57:25Z bz $
1995cc27f0SJoerg Sonnenberger */
2095cc27f0SJoerg Sonnenberger
2195cc27f0SJoerg Sonnenberger #include <sys/param.h>
2295cc27f0SJoerg Sonnenberger #include <sys/types.h>
2395cc27f0SJoerg Sonnenberger #include <sys/ioctl.h>
2495cc27f0SJoerg Sonnenberger #include <sys/socket.h>
2570224baaSJan Lentfer #include <sys/stat.h>
2695cc27f0SJoerg Sonnenberger #include <sys/time.h>
2770224baaSJan Lentfer #include <sys/wait.h>
2895cc27f0SJoerg Sonnenberger
2995cc27f0SJoerg Sonnenberger #include <net/if.h>
3095cc27f0SJoerg Sonnenberger #include <net/pf/pfvar.h>
3195cc27f0SJoerg Sonnenberger #include <arpa/inet.h>
3295cc27f0SJoerg Sonnenberger
3395cc27f0SJoerg Sonnenberger #include <err.h>
3495cc27f0SJoerg Sonnenberger #include <errno.h>
35*2c3b1d1bSSascha Wildner #include <fcntl.h>
3670224baaSJan Lentfer #include <login_cap.h>
3795cc27f0SJoerg Sonnenberger #include <pwd.h>
3895cc27f0SJoerg Sonnenberger #include <signal.h>
3995cc27f0SJoerg Sonnenberger #include <stdio.h>
4095cc27f0SJoerg Sonnenberger #include <stdlib.h>
4195cc27f0SJoerg Sonnenberger #include <string.h>
4295cc27f0SJoerg Sonnenberger #include <syslog.h>
4395cc27f0SJoerg Sonnenberger #include <unistd.h>
4495cc27f0SJoerg Sonnenberger
4595cc27f0SJoerg Sonnenberger #include "pathnames.h"
4695cc27f0SJoerg Sonnenberger
4795cc27f0SJoerg Sonnenberger #define __dead __dead2
4895cc27f0SJoerg Sonnenberger
4995cc27f0SJoerg Sonnenberger static int read_config(FILE *);
5095cc27f0SJoerg Sonnenberger static void print_message(const char *);
5195cc27f0SJoerg Sonnenberger static int allowed_luser(const char *);
5295cc27f0SJoerg Sonnenberger static int check_luser(const char *, const char *);
5395cc27f0SJoerg Sonnenberger static int remove_stale_rulesets(void);
5495cc27f0SJoerg Sonnenberger static int change_filter(int, const char *, const char *);
5570224baaSJan Lentfer static int change_table(int, const char *);
5695cc27f0SJoerg Sonnenberger static void authpf_kill_states(void);
5795cc27f0SJoerg Sonnenberger
5895cc27f0SJoerg Sonnenberger int dev_fd; /* pf device */
5995cc27f0SJoerg Sonnenberger char anchorname[PF_ANCHOR_NAME_SIZE] = "authpf";
6070224baaSJan Lentfer char rulesetname[MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 2];
6170224baaSJan Lentfer char tablename[PF_TABLE_NAME_SIZE] = "authpf_users";
6295cc27f0SJoerg Sonnenberger
6395cc27f0SJoerg Sonnenberger FILE *pidfp;
6495cc27f0SJoerg Sonnenberger char luser[MAXLOGNAME]; /* username */
6595cc27f0SJoerg Sonnenberger char ipsrc[256]; /* ip as a string */
6695cc27f0SJoerg Sonnenberger char pidfile[MAXPATHLEN]; /* we save pid in this file. */
6795cc27f0SJoerg Sonnenberger
6895cc27f0SJoerg Sonnenberger struct timeval Tstart, Tend; /* start and end times of session */
6995cc27f0SJoerg Sonnenberger
7095cc27f0SJoerg Sonnenberger volatile sig_atomic_t want_death;
7195cc27f0SJoerg Sonnenberger static void need_death(int signo);
7295cc27f0SJoerg Sonnenberger static __dead void do_death(int);
7395cc27f0SJoerg Sonnenberger
7495cc27f0SJoerg Sonnenberger /*
7595cc27f0SJoerg Sonnenberger * User shell for authenticating gateways. Sole purpose is to allow
7695cc27f0SJoerg Sonnenberger * a user to ssh to a gateway, and have the gateway modify packet
7795cc27f0SJoerg Sonnenberger * filters to allow access, then remove access when the user finishes
7895cc27f0SJoerg Sonnenberger * up. Meant to be used only from ssh(1) connections.
7995cc27f0SJoerg Sonnenberger */
8095cc27f0SJoerg Sonnenberger int
main(int argc __unused,char ** argv __unused)8195cc27f0SJoerg Sonnenberger main(int argc __unused, char **argv __unused)
8295cc27f0SJoerg Sonnenberger {
8395cc27f0SJoerg Sonnenberger int lockcnt = 0, n, pidfd;
8495cc27f0SJoerg Sonnenberger FILE *config;
8570224baaSJan Lentfer struct in6_addr ina;
8695cc27f0SJoerg Sonnenberger struct passwd *pw;
8795cc27f0SJoerg Sonnenberger char *cp;
8870224baaSJan Lentfer gid_t gid;
8995cc27f0SJoerg Sonnenberger uid_t uid;
90d316f7c9SJohn Marino const char *shell;
9170224baaSJan Lentfer login_cap_t *lc;
9295cc27f0SJoerg Sonnenberger
9395cc27f0SJoerg Sonnenberger config = fopen(PATH_CONFFILE, "r");
9470224baaSJan Lentfer if (config == NULL) {
9570224baaSJan Lentfer syslog(LOG_ERR, "cannot open %s (%m)", PATH_CONFFILE);
9670224baaSJan Lentfer exit(1);
9770224baaSJan Lentfer }
9895cc27f0SJoerg Sonnenberger
9995cc27f0SJoerg Sonnenberger if ((cp = getenv("SSH_TTY")) == NULL) {
10095cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "non-interactive session connection for authpf");
10195cc27f0SJoerg Sonnenberger exit(1);
10295cc27f0SJoerg Sonnenberger }
10395cc27f0SJoerg Sonnenberger
10495cc27f0SJoerg Sonnenberger if ((cp = getenv("SSH_CLIENT")) == NULL) {
10595cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "cannot determine connection source");
10695cc27f0SJoerg Sonnenberger exit(1);
10795cc27f0SJoerg Sonnenberger }
10895cc27f0SJoerg Sonnenberger
10995cc27f0SJoerg Sonnenberger if (strlcpy(ipsrc, cp, sizeof(ipsrc)) >= sizeof(ipsrc)) {
11095cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "SSH_CLIENT variable too long");
11195cc27f0SJoerg Sonnenberger exit(1);
11295cc27f0SJoerg Sonnenberger }
11395cc27f0SJoerg Sonnenberger cp = strchr(ipsrc, ' ');
11495cc27f0SJoerg Sonnenberger if (!cp) {
11595cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "corrupt SSH_CLIENT variable %s", ipsrc);
11695cc27f0SJoerg Sonnenberger exit(1);
11795cc27f0SJoerg Sonnenberger }
11895cc27f0SJoerg Sonnenberger *cp = '\0';
11970224baaSJan Lentfer if (inet_pton(AF_INET, ipsrc, &ina) != 1 &&
12070224baaSJan Lentfer inet_pton(AF_INET6, ipsrc, &ina) != 1) {
12195cc27f0SJoerg Sonnenberger syslog(LOG_ERR,
12295cc27f0SJoerg Sonnenberger "cannot determine IP from SSH_CLIENT %s", ipsrc);
12395cc27f0SJoerg Sonnenberger exit(1);
12495cc27f0SJoerg Sonnenberger }
12595cc27f0SJoerg Sonnenberger /* open the pf device */
12695cc27f0SJoerg Sonnenberger dev_fd = open(PATH_DEVFILE, O_RDWR);
12795cc27f0SJoerg Sonnenberger if (dev_fd == -1) {
12895cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "cannot open packet filter device (%m)");
12995cc27f0SJoerg Sonnenberger goto die;
13095cc27f0SJoerg Sonnenberger }
13195cc27f0SJoerg Sonnenberger
13295cc27f0SJoerg Sonnenberger uid = getuid();
13395cc27f0SJoerg Sonnenberger pw = getpwuid(uid);
13495cc27f0SJoerg Sonnenberger if (pw == NULL) {
13595cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "cannot find user for uid %u", uid);
13695cc27f0SJoerg Sonnenberger goto die;
13795cc27f0SJoerg Sonnenberger }
13870224baaSJan Lentfer
13970224baaSJan Lentfer if ((lc = login_getclass(pw->pw_class)) != NULL)
14070224baaSJan Lentfer shell = login_getcapstr(lc, "shell", pw->pw_shell,
14170224baaSJan Lentfer pw->pw_shell);
14270224baaSJan Lentfer else
14370224baaSJan Lentfer shell = pw->pw_shell;
14470224baaSJan Lentfer
145d316f7c9SJohn Marino
14670224baaSJan Lentfer
14770224baaSJan Lentfer if (strcmp(shell, PATH_AUTHPF_SHELL)) {
14895cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "wrong shell for user %s, uid %u",
14995cc27f0SJoerg Sonnenberger pw->pw_name, pw->pw_uid);
150d316f7c9SJohn Marino login_close(lc);
15195cc27f0SJoerg Sonnenberger goto die;
15295cc27f0SJoerg Sonnenberger }
15395cc27f0SJoerg Sonnenberger
154d316f7c9SJohn Marino login_close(lc);
15570224baaSJan Lentfer
15695cc27f0SJoerg Sonnenberger /*
15795cc27f0SJoerg Sonnenberger * Paranoia, but this data _does_ come from outside authpf, and
15895cc27f0SJoerg Sonnenberger * truncation would be bad.
15995cc27f0SJoerg Sonnenberger */
16095cc27f0SJoerg Sonnenberger if (strlcpy(luser, pw->pw_name, sizeof(luser)) >= sizeof(luser)) {
16195cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "username too long: %s", pw->pw_name);
16295cc27f0SJoerg Sonnenberger goto die;
16395cc27f0SJoerg Sonnenberger }
16495cc27f0SJoerg Sonnenberger
16595cc27f0SJoerg Sonnenberger if ((n = snprintf(rulesetname, sizeof(rulesetname), "%s(%ld)",
166d316f7c9SJohn Marino luser, (long)getpid())) < 0 || (u_int)n >= sizeof(rulesetname)) {
16795cc27f0SJoerg Sonnenberger syslog(LOG_INFO, "%s(%ld) too large, ruleset name will be %ld",
16895cc27f0SJoerg Sonnenberger luser, (long)getpid(), (long)getpid());
16995cc27f0SJoerg Sonnenberger if ((n = snprintf(rulesetname, sizeof(rulesetname), "%ld",
170d316f7c9SJohn Marino (long)getpid())) < 0 || (u_int)n >= sizeof(rulesetname)) {
17195cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "pid too large for ruleset name");
17295cc27f0SJoerg Sonnenberger goto die;
17395cc27f0SJoerg Sonnenberger }
17495cc27f0SJoerg Sonnenberger }
17595cc27f0SJoerg Sonnenberger
17695cc27f0SJoerg Sonnenberger
17795cc27f0SJoerg Sonnenberger /* Make our entry in /var/authpf as /var/authpf/ipaddr */
17895cc27f0SJoerg Sonnenberger n = snprintf(pidfile, sizeof(pidfile), "%s/%s", PATH_PIDFILE, ipsrc);
17995cc27f0SJoerg Sonnenberger if (n < 0 || (u_int)n >= sizeof(pidfile)) {
18095cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "path to pidfile too long");
18195cc27f0SJoerg Sonnenberger goto die;
18295cc27f0SJoerg Sonnenberger }
18395cc27f0SJoerg Sonnenberger
18495cc27f0SJoerg Sonnenberger /*
18595cc27f0SJoerg Sonnenberger * If someone else is already using this ip, then this person
18695cc27f0SJoerg Sonnenberger * wants to switch users - so kill the old process and exit
18795cc27f0SJoerg Sonnenberger * as well.
18895cc27f0SJoerg Sonnenberger *
18995cc27f0SJoerg Sonnenberger * Note, we could print a message and tell them to log out, but the
19095cc27f0SJoerg Sonnenberger * usual case of this is that someone has left themselves logged in,
19195cc27f0SJoerg Sonnenberger * with the authenticated connection iconized and someone else walks
19295cc27f0SJoerg Sonnenberger * up to use and automatically logs in before using. If this just
19395cc27f0SJoerg Sonnenberger * gets rid of the old one silently, the new user never knows they
19495cc27f0SJoerg Sonnenberger * could have used someone else's old authentication. If we
19595cc27f0SJoerg Sonnenberger * tell them to log out before switching users it is an invitation
19695cc27f0SJoerg Sonnenberger * for abuse.
19795cc27f0SJoerg Sonnenberger */
19895cc27f0SJoerg Sonnenberger
19995cc27f0SJoerg Sonnenberger do {
20095cc27f0SJoerg Sonnenberger int save_errno, otherpid = -1;
20195cc27f0SJoerg Sonnenberger char otherluser[MAXLOGNAME];
20295cc27f0SJoerg Sonnenberger
20395cc27f0SJoerg Sonnenberger if ((pidfd = open(pidfile, O_RDWR|O_CREAT, 0644)) == -1 ||
20495cc27f0SJoerg Sonnenberger (pidfp = fdopen(pidfd, "r+")) == NULL) {
20595cc27f0SJoerg Sonnenberger if (pidfd != -1)
20695cc27f0SJoerg Sonnenberger close(pidfd);
20795cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "cannot open or create %s: %s", pidfile,
20895cc27f0SJoerg Sonnenberger strerror(errno));
20995cc27f0SJoerg Sonnenberger goto die;
21095cc27f0SJoerg Sonnenberger }
21195cc27f0SJoerg Sonnenberger
21295cc27f0SJoerg Sonnenberger if (flock(fileno(pidfp), LOCK_EX|LOCK_NB) == 0)
21395cc27f0SJoerg Sonnenberger break;
21495cc27f0SJoerg Sonnenberger save_errno = errno;
21595cc27f0SJoerg Sonnenberger
21695cc27f0SJoerg Sonnenberger /* Mark our pid, and username to our file. */
21795cc27f0SJoerg Sonnenberger
21895cc27f0SJoerg Sonnenberger rewind(pidfp);
21995cc27f0SJoerg Sonnenberger /* 31 == MAXLOGNAME - 1 */
22095cc27f0SJoerg Sonnenberger if (fscanf(pidfp, "%d\n%31s\n", &otherpid, otherluser) != 2)
22195cc27f0SJoerg Sonnenberger otherpid = -1;
22295cc27f0SJoerg Sonnenberger syslog(LOG_DEBUG, "tried to lock %s, in use by pid %d: %s",
22395cc27f0SJoerg Sonnenberger pidfile, otherpid, strerror(save_errno));
22495cc27f0SJoerg Sonnenberger
22595cc27f0SJoerg Sonnenberger if (otherpid > 0) {
22695cc27f0SJoerg Sonnenberger syslog(LOG_INFO,
22795cc27f0SJoerg Sonnenberger "killing prior auth (pid %d) of %s by user %s",
22895cc27f0SJoerg Sonnenberger otherpid, ipsrc, otherluser);
22995cc27f0SJoerg Sonnenberger if (kill((pid_t) otherpid, SIGTERM) == -1) {
23095cc27f0SJoerg Sonnenberger syslog(LOG_INFO,
23195cc27f0SJoerg Sonnenberger "could not kill process %d: (%m)",
23295cc27f0SJoerg Sonnenberger otherpid);
23395cc27f0SJoerg Sonnenberger }
23495cc27f0SJoerg Sonnenberger }
23595cc27f0SJoerg Sonnenberger
23695cc27f0SJoerg Sonnenberger /*
237d316f7c9SJohn Marino * We try to kill the previous process and acquire the lock
23895cc27f0SJoerg Sonnenberger * for 10 seconds, trying once a second. if we can't after
239d316f7c9SJohn Marino * 10 attempts we log an error and give up.
24095cc27f0SJoerg Sonnenberger */
24195cc27f0SJoerg Sonnenberger if (++lockcnt > 10) {
24295cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "cannot kill previous authpf (pid %d)",
24395cc27f0SJoerg Sonnenberger otherpid);
24470224baaSJan Lentfer fclose(pidfp);
24570224baaSJan Lentfer pidfp = NULL;
24695cc27f0SJoerg Sonnenberger goto dogdeath;
24795cc27f0SJoerg Sonnenberger }
24895cc27f0SJoerg Sonnenberger sleep(1);
24995cc27f0SJoerg Sonnenberger
25095cc27f0SJoerg Sonnenberger /* re-open, and try again. The previous authpf process
25195cc27f0SJoerg Sonnenberger * we killed above should unlink the file and release
25295cc27f0SJoerg Sonnenberger * it's lock, giving us a chance to get it now
25395cc27f0SJoerg Sonnenberger */
25495cc27f0SJoerg Sonnenberger fclose(pidfp);
25570224baaSJan Lentfer pidfp = NULL;
25695cc27f0SJoerg Sonnenberger } while (1);
25795cc27f0SJoerg Sonnenberger
25870224baaSJan Lentfer /* whack the group list */
25970224baaSJan Lentfer gid = getegid();
26070224baaSJan Lentfer if (setgroups(1, &gid) == -1) {
26170224baaSJan Lentfer syslog(LOG_INFO, "setgroups: %s", strerror(errno));
26270224baaSJan Lentfer do_death(0);
26370224baaSJan Lentfer }
26495cc27f0SJoerg Sonnenberger
26570224baaSJan Lentfer /* revoke privs */
26670224baaSJan Lentfer uid = getuid();
26770224baaSJan Lentfer if (setresuid(uid, uid, uid) == -1) {
26870224baaSJan Lentfer syslog(LOG_INFO, "setresuid: %s", strerror(errno));
26970224baaSJan Lentfer do_death(0);
27070224baaSJan Lentfer }
27195cc27f0SJoerg Sonnenberger openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON);
27295cc27f0SJoerg Sonnenberger
27395cc27f0SJoerg Sonnenberger if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser)) {
27495cc27f0SJoerg Sonnenberger syslog(LOG_INFO, "user %s prohibited", luser);
27595cc27f0SJoerg Sonnenberger do_death(0);
27695cc27f0SJoerg Sonnenberger }
27795cc27f0SJoerg Sonnenberger
27870224baaSJan Lentfer if (read_config(config)) {
27970224baaSJan Lentfer syslog(LOG_ERR, "invalid config file %s", PATH_CONFFILE);
28095cc27f0SJoerg Sonnenberger do_death(0);
28195cc27f0SJoerg Sonnenberger }
28295cc27f0SJoerg Sonnenberger
28395cc27f0SJoerg Sonnenberger if (remove_stale_rulesets()) {
28495cc27f0SJoerg Sonnenberger syslog(LOG_INFO, "error removing stale rulesets");
28595cc27f0SJoerg Sonnenberger do_death(0);
28695cc27f0SJoerg Sonnenberger }
28795cc27f0SJoerg Sonnenberger
28895cc27f0SJoerg Sonnenberger /* We appear to be making headway, so actually mark our pid */
28995cc27f0SJoerg Sonnenberger rewind(pidfp);
29095cc27f0SJoerg Sonnenberger fprintf(pidfp, "%ld\n%s\n", (long)getpid(), luser);
29195cc27f0SJoerg Sonnenberger fflush(pidfp);
29271126e33SSascha Wildner ftruncate(fileno(pidfp), ftell(pidfp));
29395cc27f0SJoerg Sonnenberger
29495cc27f0SJoerg Sonnenberger if (change_filter(1, luser, ipsrc) == -1) {
29595cc27f0SJoerg Sonnenberger printf("Unable to modify filters\r\n");
29695cc27f0SJoerg Sonnenberger do_death(0);
29795cc27f0SJoerg Sonnenberger }
29870224baaSJan Lentfer if (change_table(1, ipsrc) == -1) {
29970224baaSJan Lentfer printf("Unable to modify table\r\n");
30070224baaSJan Lentfer change_filter(0, luser, ipsrc);
30170224baaSJan Lentfer do_death(0);
30270224baaSJan Lentfer }
30395cc27f0SJoerg Sonnenberger
30495cc27f0SJoerg Sonnenberger signal(SIGTERM, need_death);
30595cc27f0SJoerg Sonnenberger signal(SIGINT, need_death);
30695cc27f0SJoerg Sonnenberger signal(SIGALRM, need_death);
30795cc27f0SJoerg Sonnenberger signal(SIGPIPE, need_death);
30895cc27f0SJoerg Sonnenberger signal(SIGHUP, need_death);
30970224baaSJan Lentfer signal(SIGQUIT, need_death);
31095cc27f0SJoerg Sonnenberger signal(SIGTSTP, need_death);
31195cc27f0SJoerg Sonnenberger while (1) {
31270224baaSJan Lentfer printf("\r\nHello %s. ", luser);
31395cc27f0SJoerg Sonnenberger printf("You are authenticated from host \"%s\"\r\n", ipsrc);
31495cc27f0SJoerg Sonnenberger setproctitle("%s@%s", luser, ipsrc);
31595cc27f0SJoerg Sonnenberger print_message(PATH_MESSAGE);
31695cc27f0SJoerg Sonnenberger while (1) {
31795cc27f0SJoerg Sonnenberger sleep(10);
31895cc27f0SJoerg Sonnenberger if (want_death)
31995cc27f0SJoerg Sonnenberger do_death(1);
32095cc27f0SJoerg Sonnenberger }
32195cc27f0SJoerg Sonnenberger }
32295cc27f0SJoerg Sonnenberger
32395cc27f0SJoerg Sonnenberger /* NOTREACHED */
32495cc27f0SJoerg Sonnenberger dogdeath:
32595cc27f0SJoerg Sonnenberger printf("\r\n\r\nSorry, this service is currently unavailable due to ");
32695cc27f0SJoerg Sonnenberger printf("technical difficulties\r\n\r\n");
32795cc27f0SJoerg Sonnenberger print_message(PATH_PROBLEM);
32895cc27f0SJoerg Sonnenberger printf("\r\nYour authentication process (pid %ld) was unable to run\n",
32995cc27f0SJoerg Sonnenberger (long)getpid());
33095cc27f0SJoerg Sonnenberger sleep(180); /* them lusers read reaaaaal slow */
33195cc27f0SJoerg Sonnenberger die:
33295cc27f0SJoerg Sonnenberger do_death(0);
33395cc27f0SJoerg Sonnenberger }
33495cc27f0SJoerg Sonnenberger
33595cc27f0SJoerg Sonnenberger /*
33695cc27f0SJoerg Sonnenberger * reads config file in PATH_CONFFILE to set optional behaviours up
33795cc27f0SJoerg Sonnenberger */
33895cc27f0SJoerg Sonnenberger static int
read_config(FILE * f)33995cc27f0SJoerg Sonnenberger read_config(FILE *f)
34095cc27f0SJoerg Sonnenberger {
34195cc27f0SJoerg Sonnenberger char buf[1024];
34295cc27f0SJoerg Sonnenberger int i = 0;
34395cc27f0SJoerg Sonnenberger
34495cc27f0SJoerg Sonnenberger do {
34595cc27f0SJoerg Sonnenberger char **ap;
34695cc27f0SJoerg Sonnenberger char *pair[4], *cp, *tp;
34795cc27f0SJoerg Sonnenberger int len;
34895cc27f0SJoerg Sonnenberger
34995cc27f0SJoerg Sonnenberger if (fgets(buf, sizeof(buf), f) == NULL) {
35095cc27f0SJoerg Sonnenberger fclose(f);
35195cc27f0SJoerg Sonnenberger return (0);
35295cc27f0SJoerg Sonnenberger }
35395cc27f0SJoerg Sonnenberger i++;
35495cc27f0SJoerg Sonnenberger len = strlen(buf);
355d316f7c9SJohn Marino if (len == 0)
356d316f7c9SJohn Marino continue;
35795cc27f0SJoerg Sonnenberger if (buf[len - 1] != '\n' && !feof(f)) {
35895cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "line %d too long in %s", i,
35995cc27f0SJoerg Sonnenberger PATH_CONFFILE);
36095cc27f0SJoerg Sonnenberger return (1);
36195cc27f0SJoerg Sonnenberger }
36295cc27f0SJoerg Sonnenberger buf[len - 1] = '\0';
36395cc27f0SJoerg Sonnenberger
36495cc27f0SJoerg Sonnenberger for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
36595cc27f0SJoerg Sonnenberger ; /* nothing */
36695cc27f0SJoerg Sonnenberger
36795cc27f0SJoerg Sonnenberger if (!*cp || *cp == '#' || *cp == '\n')
36895cc27f0SJoerg Sonnenberger continue;
36995cc27f0SJoerg Sonnenberger
37095cc27f0SJoerg Sonnenberger for (ap = pair; ap < &pair[3] &&
37195cc27f0SJoerg Sonnenberger (*ap = strsep(&cp, "=")) != NULL; ) {
37295cc27f0SJoerg Sonnenberger if (**ap != '\0')
37395cc27f0SJoerg Sonnenberger ap++;
37495cc27f0SJoerg Sonnenberger }
37595cc27f0SJoerg Sonnenberger if (ap != &pair[2])
37695cc27f0SJoerg Sonnenberger goto parse_error;
37795cc27f0SJoerg Sonnenberger
37895cc27f0SJoerg Sonnenberger tp = pair[1] + strlen(pair[1]);
37995cc27f0SJoerg Sonnenberger while ((*tp == ' ' || *tp == '\t') && tp >= pair[1])
38095cc27f0SJoerg Sonnenberger *tp-- = '\0';
38195cc27f0SJoerg Sonnenberger
38295cc27f0SJoerg Sonnenberger if (strcasecmp(pair[0], "anchor") == 0) {
38395cc27f0SJoerg Sonnenberger if (!pair[1][0] || strlcpy(anchorname, pair[1],
38495cc27f0SJoerg Sonnenberger sizeof(anchorname)) >= sizeof(anchorname))
38595cc27f0SJoerg Sonnenberger goto parse_error;
38695cc27f0SJoerg Sonnenberger }
38770224baaSJan Lentfer if (strcasecmp(pair[0], "table") == 0) {
38870224baaSJan Lentfer if (!pair[1][0] || strlcpy(tablename, pair[1],
38970224baaSJan Lentfer sizeof(tablename)) >= sizeof(tablename))
39070224baaSJan Lentfer goto parse_error;
39170224baaSJan Lentfer }
39295cc27f0SJoerg Sonnenberger } while (!feof(f) && !ferror(f));
39395cc27f0SJoerg Sonnenberger fclose(f);
39495cc27f0SJoerg Sonnenberger return (0);
39595cc27f0SJoerg Sonnenberger
39695cc27f0SJoerg Sonnenberger parse_error:
39795cc27f0SJoerg Sonnenberger fclose(f);
39895cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "parse error, line %d of %s", i, PATH_CONFFILE);
39995cc27f0SJoerg Sonnenberger return (1);
40095cc27f0SJoerg Sonnenberger }
40195cc27f0SJoerg Sonnenberger
40295cc27f0SJoerg Sonnenberger
40395cc27f0SJoerg Sonnenberger /*
40495cc27f0SJoerg Sonnenberger * splatter a file to stdout - max line length of 1024,
40595cc27f0SJoerg Sonnenberger * used for spitting message files at users to tell them
40695cc27f0SJoerg Sonnenberger * they've been bad or we're unavailable.
40795cc27f0SJoerg Sonnenberger */
40895cc27f0SJoerg Sonnenberger static void
print_message(const char * filename)40995cc27f0SJoerg Sonnenberger print_message(const char *filename)
41095cc27f0SJoerg Sonnenberger {
41195cc27f0SJoerg Sonnenberger char buf[1024];
41295cc27f0SJoerg Sonnenberger FILE *f;
41395cc27f0SJoerg Sonnenberger
41495cc27f0SJoerg Sonnenberger if ((f = fopen(filename, "r")) == NULL)
41595cc27f0SJoerg Sonnenberger return; /* fail silently, we don't care if it isn't there */
41695cc27f0SJoerg Sonnenberger
41795cc27f0SJoerg Sonnenberger do {
41895cc27f0SJoerg Sonnenberger if (fgets(buf, sizeof(buf), f) == NULL) {
41995cc27f0SJoerg Sonnenberger fflush(stdout);
42095cc27f0SJoerg Sonnenberger fclose(f);
42195cc27f0SJoerg Sonnenberger return;
42295cc27f0SJoerg Sonnenberger }
42395cc27f0SJoerg Sonnenberger } while (fputs(buf, stdout) != EOF && !feof(f));
42495cc27f0SJoerg Sonnenberger fflush(stdout);
42595cc27f0SJoerg Sonnenberger fclose(f);
42695cc27f0SJoerg Sonnenberger }
42795cc27f0SJoerg Sonnenberger
42895cc27f0SJoerg Sonnenberger /*
42995cc27f0SJoerg Sonnenberger * allowed_luser checks to see if user "luser" is allowed to
43095cc27f0SJoerg Sonnenberger * use this gateway by virtue of being listed in an allowed
43195cc27f0SJoerg Sonnenberger * users file, namely /etc/authpf/authpf.allow .
43295cc27f0SJoerg Sonnenberger *
43395cc27f0SJoerg Sonnenberger * If /etc/authpf/authpf.allow does not exist, then we assume that
43495cc27f0SJoerg Sonnenberger * all users who are allowed in by sshd(8) are permitted to
43595cc27f0SJoerg Sonnenberger * use this gateway. If /etc/authpf/authpf.allow does exist, then a
43695cc27f0SJoerg Sonnenberger * user must be listed if the connection is to continue, else
43795cc27f0SJoerg Sonnenberger * the session terminates in the same manner as being banned.
43895cc27f0SJoerg Sonnenberger */
43995cc27f0SJoerg Sonnenberger static int
allowed_luser(const char * user)44095cc27f0SJoerg Sonnenberger allowed_luser(const char *user)
44195cc27f0SJoerg Sonnenberger {
44295cc27f0SJoerg Sonnenberger char *buf, *lbuf;
44395cc27f0SJoerg Sonnenberger int matched;
44495cc27f0SJoerg Sonnenberger size_t len;
44595cc27f0SJoerg Sonnenberger FILE *f;
44695cc27f0SJoerg Sonnenberger
44795cc27f0SJoerg Sonnenberger if ((f = fopen(PATH_ALLOWFILE, "r")) == NULL) {
44895cc27f0SJoerg Sonnenberger if (errno == ENOENT) {
44995cc27f0SJoerg Sonnenberger /*
45095cc27f0SJoerg Sonnenberger * allowfile doesn't exist, thus this gateway
45195cc27f0SJoerg Sonnenberger * isn't restricted to certain users...
45295cc27f0SJoerg Sonnenberger */
45395cc27f0SJoerg Sonnenberger return (1);
45495cc27f0SJoerg Sonnenberger }
45595cc27f0SJoerg Sonnenberger
45695cc27f0SJoerg Sonnenberger /*
45795cc27f0SJoerg Sonnenberger * user may in fact be allowed, but we can't open
45895cc27f0SJoerg Sonnenberger * the file even though it's there. probably a config
45995cc27f0SJoerg Sonnenberger * problem.
46095cc27f0SJoerg Sonnenberger */
46195cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "cannot open allowed users file %s (%s)",
46295cc27f0SJoerg Sonnenberger PATH_ALLOWFILE, strerror(errno));
46395cc27f0SJoerg Sonnenberger return (0);
46495cc27f0SJoerg Sonnenberger } else {
46595cc27f0SJoerg Sonnenberger /*
46695cc27f0SJoerg Sonnenberger * /etc/authpf/authpf.allow exists, thus we do a linear
46795cc27f0SJoerg Sonnenberger * search to see if they are allowed.
46895cc27f0SJoerg Sonnenberger * also, if username "*" exists, then this is a
46995cc27f0SJoerg Sonnenberger * "public" gateway, such as it is, so let
47095cc27f0SJoerg Sonnenberger * everyone use it.
47195cc27f0SJoerg Sonnenberger */
47295cc27f0SJoerg Sonnenberger lbuf = NULL;
47395cc27f0SJoerg Sonnenberger while ((buf = fgetln(f, &len))) {
47495cc27f0SJoerg Sonnenberger if (buf[len - 1] == '\n')
47595cc27f0SJoerg Sonnenberger buf[len - 1] = '\0';
47695cc27f0SJoerg Sonnenberger else {
47795cc27f0SJoerg Sonnenberger if ((lbuf = (char *)malloc(len + 1)) == NULL)
47895cc27f0SJoerg Sonnenberger err(1, NULL);
47995cc27f0SJoerg Sonnenberger memcpy(lbuf, buf, len);
48095cc27f0SJoerg Sonnenberger lbuf[len] = '\0';
48195cc27f0SJoerg Sonnenberger buf = lbuf;
48295cc27f0SJoerg Sonnenberger }
48395cc27f0SJoerg Sonnenberger
48495cc27f0SJoerg Sonnenberger matched = strcmp(user, buf) == 0 || strcmp("*", buf) == 0;
48595cc27f0SJoerg Sonnenberger
48695cc27f0SJoerg Sonnenberger if (lbuf != NULL) {
48795cc27f0SJoerg Sonnenberger free(lbuf);
48895cc27f0SJoerg Sonnenberger lbuf = NULL;
48995cc27f0SJoerg Sonnenberger }
49095cc27f0SJoerg Sonnenberger
49195cc27f0SJoerg Sonnenberger if (matched)
49295cc27f0SJoerg Sonnenberger return (1); /* matched an allowed username */
49395cc27f0SJoerg Sonnenberger }
49495cc27f0SJoerg Sonnenberger syslog(LOG_INFO, "denied access to %s: not listed in %s",
49595cc27f0SJoerg Sonnenberger user, PATH_ALLOWFILE);
49695cc27f0SJoerg Sonnenberger
49795cc27f0SJoerg Sonnenberger fputs("\n\nSorry, you are not allowed to use this facility!\n",
49895cc27f0SJoerg Sonnenberger stdout);
49995cc27f0SJoerg Sonnenberger }
50095cc27f0SJoerg Sonnenberger fflush(stdout);
50195cc27f0SJoerg Sonnenberger return (0);
50295cc27f0SJoerg Sonnenberger }
50395cc27f0SJoerg Sonnenberger
50495cc27f0SJoerg Sonnenberger /*
50595cc27f0SJoerg Sonnenberger * check_luser checks to see if user "luser" has been banned
50695cc27f0SJoerg Sonnenberger * from using us by virtue of having an file of the same name
50795cc27f0SJoerg Sonnenberger * in the "luserdir" directory.
50895cc27f0SJoerg Sonnenberger *
50995cc27f0SJoerg Sonnenberger * If the user has been banned, we copy the contents of the file
51095cc27f0SJoerg Sonnenberger * to the user's screen. (useful for telling the user what to
51195cc27f0SJoerg Sonnenberger * do to get un-banned, or just to tell them they aren't
51295cc27f0SJoerg Sonnenberger * going to be un-banned.)
51395cc27f0SJoerg Sonnenberger */
51495cc27f0SJoerg Sonnenberger static int
check_luser(const char * userdir,const char * user)51595cc27f0SJoerg Sonnenberger check_luser(const char *userdir, const char *user)
51695cc27f0SJoerg Sonnenberger {
51795cc27f0SJoerg Sonnenberger FILE *f;
51895cc27f0SJoerg Sonnenberger int n;
51995cc27f0SJoerg Sonnenberger char tmp[MAXPATHLEN];
52095cc27f0SJoerg Sonnenberger
52195cc27f0SJoerg Sonnenberger n = snprintf(tmp, sizeof(tmp), "%s/%s", userdir, user);
52295cc27f0SJoerg Sonnenberger if (n < 0 || (u_int)n >= sizeof(tmp)) {
52395cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "provided banned directory line too long (%s)",
52495cc27f0SJoerg Sonnenberger userdir);
52595cc27f0SJoerg Sonnenberger return (0);
52695cc27f0SJoerg Sonnenberger }
52795cc27f0SJoerg Sonnenberger if ((f = fopen(tmp, "r")) == NULL) {
52895cc27f0SJoerg Sonnenberger if (errno == ENOENT) {
52995cc27f0SJoerg Sonnenberger /*
53095cc27f0SJoerg Sonnenberger * file or dir doesn't exist, so therefore
53195cc27f0SJoerg Sonnenberger * this luser isn't banned.. all is well
53295cc27f0SJoerg Sonnenberger */
53395cc27f0SJoerg Sonnenberger return (1);
53495cc27f0SJoerg Sonnenberger } else {
53595cc27f0SJoerg Sonnenberger /*
53695cc27f0SJoerg Sonnenberger * user may in fact be banned, but we can't open the
53795cc27f0SJoerg Sonnenberger * file even though it's there. probably a config
53895cc27f0SJoerg Sonnenberger * problem.
53995cc27f0SJoerg Sonnenberger */
54095cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "cannot open banned file %s (%s)",
54195cc27f0SJoerg Sonnenberger tmp, strerror(errno));
54295cc27f0SJoerg Sonnenberger return (0);
54395cc27f0SJoerg Sonnenberger }
54495cc27f0SJoerg Sonnenberger } else {
54595cc27f0SJoerg Sonnenberger /*
54695cc27f0SJoerg Sonnenberger * user is banned - spit the file at them to
54795cc27f0SJoerg Sonnenberger * tell what they can do and where they can go.
54895cc27f0SJoerg Sonnenberger */
54995cc27f0SJoerg Sonnenberger syslog(LOG_INFO, "denied access to %s: %s exists",
55095cc27f0SJoerg Sonnenberger luser, tmp);
55195cc27f0SJoerg Sonnenberger
55295cc27f0SJoerg Sonnenberger /* reuse tmp */
55395cc27f0SJoerg Sonnenberger strlcpy(tmp, "\n\n-**- Sorry, you have been banned! -**-\n\n",
55495cc27f0SJoerg Sonnenberger sizeof(tmp));
55595cc27f0SJoerg Sonnenberger while (fputs(tmp, stdout) != EOF && !feof(f)) {
55695cc27f0SJoerg Sonnenberger if (fgets(tmp, sizeof(tmp), f) == NULL) {
55795cc27f0SJoerg Sonnenberger fflush(stdout);
55870224baaSJan Lentfer fclose(f);
55995cc27f0SJoerg Sonnenberger return (0);
56095cc27f0SJoerg Sonnenberger }
56195cc27f0SJoerg Sonnenberger }
56270224baaSJan Lentfer fclose(f);
56395cc27f0SJoerg Sonnenberger }
56495cc27f0SJoerg Sonnenberger fflush(stdout);
56595cc27f0SJoerg Sonnenberger return (0);
56695cc27f0SJoerg Sonnenberger }
56795cc27f0SJoerg Sonnenberger
56895cc27f0SJoerg Sonnenberger /*
56995cc27f0SJoerg Sonnenberger * Search for rulesets left by other authpf processes (either because they
57095cc27f0SJoerg Sonnenberger * died ungracefully or were terminated) and remove them.
57195cc27f0SJoerg Sonnenberger */
57295cc27f0SJoerg Sonnenberger static int
remove_stale_rulesets(void)57395cc27f0SJoerg Sonnenberger remove_stale_rulesets(void)
57495cc27f0SJoerg Sonnenberger {
57595cc27f0SJoerg Sonnenberger struct pfioc_ruleset prs;
57695cc27f0SJoerg Sonnenberger u_int32_t nr, mnr;
57795cc27f0SJoerg Sonnenberger
57895cc27f0SJoerg Sonnenberger memset(&prs, 0, sizeof(prs));
57970224baaSJan Lentfer strlcpy(prs.path, anchorname, sizeof(prs.path));
58095cc27f0SJoerg Sonnenberger if (ioctl(dev_fd, DIOCGETRULESETS, &prs)) {
58195cc27f0SJoerg Sonnenberger if (errno == EINVAL)
58295cc27f0SJoerg Sonnenberger return (0);
58395cc27f0SJoerg Sonnenberger else
58495cc27f0SJoerg Sonnenberger return (1);
58595cc27f0SJoerg Sonnenberger }
58695cc27f0SJoerg Sonnenberger
58795cc27f0SJoerg Sonnenberger mnr = prs.nr;
58895cc27f0SJoerg Sonnenberger nr = 0;
58995cc27f0SJoerg Sonnenberger while (nr < mnr) {
59095cc27f0SJoerg Sonnenberger char *s, *t;
59195cc27f0SJoerg Sonnenberger pid_t pid;
59295cc27f0SJoerg Sonnenberger
59395cc27f0SJoerg Sonnenberger prs.nr = nr;
59495cc27f0SJoerg Sonnenberger if (ioctl(dev_fd, DIOCGETRULESET, &prs))
59595cc27f0SJoerg Sonnenberger return (1);
59695cc27f0SJoerg Sonnenberger errno = 0;
59795cc27f0SJoerg Sonnenberger if ((t = strchr(prs.name, '(')) == NULL)
59895cc27f0SJoerg Sonnenberger t = prs.name;
59995cc27f0SJoerg Sonnenberger else
60095cc27f0SJoerg Sonnenberger t++;
60195cc27f0SJoerg Sonnenberger pid = strtoul(t, &s, 10);
60295cc27f0SJoerg Sonnenberger if (!prs.name[0] || errno ||
60395cc27f0SJoerg Sonnenberger (*s && (t == prs.name || *s != ')')))
60495cc27f0SJoerg Sonnenberger return (1);
60595cc27f0SJoerg Sonnenberger if (kill(pid, 0) && errno != EPERM) {
60695cc27f0SJoerg Sonnenberger int i;
60770224baaSJan Lentfer struct pfioc_trans_e t_e[PF_RULESET_MAX+1];
60870224baaSJan Lentfer struct pfioc_trans t_local;
60995cc27f0SJoerg Sonnenberger
6108f14f35fSzrj bzero(&t_local, sizeof(t_local));
61170224baaSJan Lentfer bzero(t_e, sizeof(t_e));
61270224baaSJan Lentfer t_local.size = PF_RULESET_MAX+1;
61370224baaSJan Lentfer t_local.esize = sizeof(t_e[0]);
61470224baaSJan Lentfer t_local.array = t_e;
61570224baaSJan Lentfer for (i = 0; i < PF_RULESET_MAX+1; ++i) {
61670224baaSJan Lentfer t_e[i].rs_num = i;
61770224baaSJan Lentfer snprintf(t_e[i].anchor, sizeof(t_e[i].anchor),
61870224baaSJan Lentfer "%s/%s", anchorname, prs.name);
61995cc27f0SJoerg Sonnenberger }
62095cc27f0SJoerg Sonnenberger mnr--;
62195cc27f0SJoerg Sonnenberger } else
62295cc27f0SJoerg Sonnenberger nr++;
62395cc27f0SJoerg Sonnenberger }
62495cc27f0SJoerg Sonnenberger return (0);
62595cc27f0SJoerg Sonnenberger }
62695cc27f0SJoerg Sonnenberger
62795cc27f0SJoerg Sonnenberger /*
62895cc27f0SJoerg Sonnenberger * Add/remove filter entries for user "luser" from ip "ipsrc"
62995cc27f0SJoerg Sonnenberger */
63095cc27f0SJoerg Sonnenberger static int
change_filter(int add,const char * user,const char * his_ipsrc)63195cc27f0SJoerg Sonnenberger change_filter(int add, const char *user, const char *his_ipsrc)
63295cc27f0SJoerg Sonnenberger {
63370224baaSJan Lentfer const char *pargv[13] = {
63470224baaSJan Lentfer "pfctl", "-p", "/dev/pf", "-q", "-a", "anchor/ruleset",
63570224baaSJan Lentfer "-D", "user_ip=X", "-D", "user_id=X", "-f",
63670224baaSJan Lentfer "file", NULL
63770224baaSJan Lentfer };
63870224baaSJan Lentfer char *fdpath = NULL, *userstr = NULL, *ipstr = NULL;
63970224baaSJan Lentfer char *rsn = NULL, *fn = NULL;
64070224baaSJan Lentfer pid_t pid;
64170224baaSJan Lentfer gid_t gid;
64270224baaSJan Lentfer int s;
64395cc27f0SJoerg Sonnenberger
64495cc27f0SJoerg Sonnenberger if (user == NULL || !user[0] || his_ipsrc == NULL || !his_ipsrc[0]) {
64570224baaSJan Lentfer syslog(LOG_ERR, "invalid user/ipsrc");
64695cc27f0SJoerg Sonnenberger goto error;
64795cc27f0SJoerg Sonnenberger }
64895cc27f0SJoerg Sonnenberger
64970224baaSJan Lentfer if (asprintf(&rsn, "%s/%s", anchorname, rulesetname) == -1)
65070224baaSJan Lentfer goto no_mem;
65170224baaSJan Lentfer if (asprintf(&fdpath, "/dev/fd/%d", dev_fd) == -1)
65270224baaSJan Lentfer goto no_mem;
65370224baaSJan Lentfer if (asprintf(&ipstr, "user_ip=%s", his_ipsrc) == -1)
65470224baaSJan Lentfer goto no_mem;
65570224baaSJan Lentfer if (asprintf(&userstr, "user_id=%s", user) == -1)
65670224baaSJan Lentfer goto no_mem;
65770224baaSJan Lentfer
65895cc27f0SJoerg Sonnenberger if (add) {
65970224baaSJan Lentfer struct stat sb;
66070224baaSJan Lentfer
66170224baaSJan Lentfer if (asprintf(&fn, "%s/%s/authpf.rules", PATH_USER_DIR, user)
66270224baaSJan Lentfer == -1)
66370224baaSJan Lentfer goto no_mem;
66470224baaSJan Lentfer if (stat(fn, &sb) == -1) {
66570224baaSJan Lentfer free(fn);
66670224baaSJan Lentfer if ((fn = strdup(PATH_PFRULES)) == NULL)
66770224baaSJan Lentfer goto no_mem;
66870224baaSJan Lentfer }
66970224baaSJan Lentfer }
67070224baaSJan Lentfer pargv[2] = fdpath;
67170224baaSJan Lentfer pargv[5] = rsn;
67270224baaSJan Lentfer pargv[7] = userstr;
67370224baaSJan Lentfer pargv[9] = ipstr;
67470224baaSJan Lentfer if (!add)
67570224baaSJan Lentfer pargv[11] = "/dev/null";
67670224baaSJan Lentfer else
67770224baaSJan Lentfer pargv[11] = fn;
67870224baaSJan Lentfer
67970224baaSJan Lentfer switch (pid = fork()) {
68070224baaSJan Lentfer case -1:
68170224baaSJan Lentfer syslog(LOG_ERR, "fork failed");
68295cc27f0SJoerg Sonnenberger goto error;
68370224baaSJan Lentfer case 0:
68470224baaSJan Lentfer /* revoke group privs before exec */
68570224baaSJan Lentfer gid = getgid();
68670224baaSJan Lentfer if (setregid(gid, gid) == -1) {
68770224baaSJan Lentfer err(1, "setregid");
68895cc27f0SJoerg Sonnenberger }
68970224baaSJan Lentfer execvp(PATH_PFCTL, __DECONST(char *const *, pargv));
69070224baaSJan Lentfer warn("exec of %s failed", PATH_PFCTL);
69170224baaSJan Lentfer _exit(1);
69295cc27f0SJoerg Sonnenberger }
69395cc27f0SJoerg Sonnenberger
69470224baaSJan Lentfer /* parent */
69570224baaSJan Lentfer waitpid(pid, &s, 0);
69670224baaSJan Lentfer if (s != 0) {
69770224baaSJan Lentfer syslog(LOG_ERR, "pfctl exited abnormally");
69895cc27f0SJoerg Sonnenberger goto error;
69995cc27f0SJoerg Sonnenberger }
70095cc27f0SJoerg Sonnenberger
70195cc27f0SJoerg Sonnenberger if (add) {
70295cc27f0SJoerg Sonnenberger gettimeofday(&Tstart, NULL);
70395cc27f0SJoerg Sonnenberger syslog(LOG_INFO, "allowing %s, user %s", his_ipsrc, user);
70495cc27f0SJoerg Sonnenberger } else {
70595cc27f0SJoerg Sonnenberger gettimeofday(&Tend, NULL);
70695cc27f0SJoerg Sonnenberger syslog(LOG_INFO, "removed %s, user %s - duration %ld seconds",
70795cc27f0SJoerg Sonnenberger his_ipsrc, user, Tend.tv_sec - Tstart.tv_sec);
70895cc27f0SJoerg Sonnenberger }
70995cc27f0SJoerg Sonnenberger return (0);
71070224baaSJan Lentfer no_mem:
71170224baaSJan Lentfer syslog(LOG_ERR, "malloc failed");
71295cc27f0SJoerg Sonnenberger error:
71370224baaSJan Lentfer free(fdpath);
71470224baaSJan Lentfer free(rsn);
71570224baaSJan Lentfer free(userstr);
71670224baaSJan Lentfer free(ipstr);
71770224baaSJan Lentfer free(fn);
71895cc27f0SJoerg Sonnenberger return (-1);
71995cc27f0SJoerg Sonnenberger }
72095cc27f0SJoerg Sonnenberger
72195cc27f0SJoerg Sonnenberger /*
72270224baaSJan Lentfer * Add/remove this IP from the "authpf_users" table.
72370224baaSJan Lentfer */
72470224baaSJan Lentfer static int
change_table(int add,const char * his_ipsrc)72570224baaSJan Lentfer change_table(int add, const char *his_ipsrc)
72670224baaSJan Lentfer {
72770224baaSJan Lentfer struct pfioc_table io;
72870224baaSJan Lentfer struct pfr_addr addr;
72970224baaSJan Lentfer
73070224baaSJan Lentfer bzero(&io, sizeof(io));
73170224baaSJan Lentfer strlcpy(io.pfrio_table.pfrt_name, tablename,
73270224baaSJan Lentfer sizeof(io.pfrio_table.pfrt_name));
73370224baaSJan Lentfer io.pfrio_buffer = &addr;
73470224baaSJan Lentfer io.pfrio_esize = sizeof(addr);
73570224baaSJan Lentfer io.pfrio_size = 1;
73670224baaSJan Lentfer
73770224baaSJan Lentfer bzero(&addr, sizeof(addr));
73870224baaSJan Lentfer if (his_ipsrc == NULL || !his_ipsrc[0])
73970224baaSJan Lentfer return (-1);
74070224baaSJan Lentfer if (inet_pton(AF_INET, his_ipsrc, &addr.pfra_ip4addr) == 1) {
74170224baaSJan Lentfer addr.pfra_af = AF_INET;
74270224baaSJan Lentfer addr.pfra_net = 32;
74370224baaSJan Lentfer } else if (inet_pton(AF_INET6, his_ipsrc, &addr.pfra_ip6addr) == 1) {
74470224baaSJan Lentfer addr.pfra_af = AF_INET6;
74570224baaSJan Lentfer addr.pfra_net = 128;
74670224baaSJan Lentfer } else {
74770224baaSJan Lentfer syslog(LOG_ERR, "invalid his_ipsrc");
74870224baaSJan Lentfer return (-1);
74970224baaSJan Lentfer }
75070224baaSJan Lentfer
75170224baaSJan Lentfer if (ioctl(dev_fd, add ? DIOCRADDADDRS : DIOCRDELADDRS, &io) &&
75270224baaSJan Lentfer errno != ESRCH) {
75370224baaSJan Lentfer syslog(LOG_ERR, "cannot %s %s from table %s: %s",
75470224baaSJan Lentfer add ? "add" : "remove", his_ipsrc, tablename,
75570224baaSJan Lentfer strerror(errno));
75670224baaSJan Lentfer return (-1);
75770224baaSJan Lentfer }
75870224baaSJan Lentfer return (0);
75970224baaSJan Lentfer }
76070224baaSJan Lentfer
76170224baaSJan Lentfer /*
76295cc27f0SJoerg Sonnenberger * This is to kill off states that would otherwise be left behind stateful
76395cc27f0SJoerg Sonnenberger * rules. This means we don't need to allow in more traffic than we really
76495cc27f0SJoerg Sonnenberger * want to, since we don't have to worry about any luser sessions lasting
76595cc27f0SJoerg Sonnenberger * longer than their ssh session. This function is based on
76695cc27f0SJoerg Sonnenberger * pfctl_kill_states from pfctl.
76795cc27f0SJoerg Sonnenberger */
76895cc27f0SJoerg Sonnenberger static void
authpf_kill_states(void)76995cc27f0SJoerg Sonnenberger authpf_kill_states(void)
77095cc27f0SJoerg Sonnenberger {
77195cc27f0SJoerg Sonnenberger struct pfioc_state_kill psk;
77270224baaSJan Lentfer struct pf_addr target;
77395cc27f0SJoerg Sonnenberger
77495cc27f0SJoerg Sonnenberger memset(&psk, 0, sizeof(psk));
77570224baaSJan Lentfer memset(&target, 0, sizeof(target));
77695cc27f0SJoerg Sonnenberger
77770224baaSJan Lentfer if (inet_pton(AF_INET, ipsrc, &target.v4) == 1)
77870224baaSJan Lentfer psk.psk_af = AF_INET;
77970224baaSJan Lentfer else if (inet_pton(AF_INET6, ipsrc, &target.v6) == 1)
78070224baaSJan Lentfer psk.psk_af = AF_INET6;
78170224baaSJan Lentfer else {
78270224baaSJan Lentfer syslog(LOG_ERR, "inet_pton(%s) failed", ipsrc);
78370224baaSJan Lentfer return;
78470224baaSJan Lentfer }
78595cc27f0SJoerg Sonnenberger
78695cc27f0SJoerg Sonnenberger /* Kill all states from ipsrc */
78770224baaSJan Lentfer memcpy(&psk.psk_src.addr.v.a.addr, &target,
78870224baaSJan Lentfer sizeof(psk.psk_src.addr.v.a.addr));
78995cc27f0SJoerg Sonnenberger memset(&psk.psk_src.addr.v.a.mask, 0xff,
79095cc27f0SJoerg Sonnenberger sizeof(psk.psk_src.addr.v.a.mask));
79195cc27f0SJoerg Sonnenberger if (ioctl(dev_fd, DIOCKILLSTATES, &psk))
79295cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)");
79395cc27f0SJoerg Sonnenberger
79495cc27f0SJoerg Sonnenberger /* Kill all states to ipsrc */
79595cc27f0SJoerg Sonnenberger memset(&psk.psk_src, 0, sizeof(psk.psk_src));
79670224baaSJan Lentfer memcpy(&psk.psk_dst.addr.v.a.addr, &target,
79770224baaSJan Lentfer sizeof(psk.psk_dst.addr.v.a.addr));
79895cc27f0SJoerg Sonnenberger memset(&psk.psk_dst.addr.v.a.mask, 0xff,
79995cc27f0SJoerg Sonnenberger sizeof(psk.psk_dst.addr.v.a.mask));
80095cc27f0SJoerg Sonnenberger if (ioctl(dev_fd, DIOCKILLSTATES, &psk))
80195cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)");
80295cc27f0SJoerg Sonnenberger }
80395cc27f0SJoerg Sonnenberger
80495cc27f0SJoerg Sonnenberger /* signal handler that makes us go away properly */
80595cc27f0SJoerg Sonnenberger static void
need_death(int signo __unused)80695cc27f0SJoerg Sonnenberger need_death(int signo __unused)
80795cc27f0SJoerg Sonnenberger {
80895cc27f0SJoerg Sonnenberger want_death = 1;
80995cc27f0SJoerg Sonnenberger }
81095cc27f0SJoerg Sonnenberger
81195cc27f0SJoerg Sonnenberger /*
81295cc27f0SJoerg Sonnenberger * function that removes our stuff when we go away.
81395cc27f0SJoerg Sonnenberger */
81495cc27f0SJoerg Sonnenberger static __dead void
do_death(int active)81595cc27f0SJoerg Sonnenberger do_death(int active)
81695cc27f0SJoerg Sonnenberger {
81795cc27f0SJoerg Sonnenberger int ret = 0;
81895cc27f0SJoerg Sonnenberger
81995cc27f0SJoerg Sonnenberger if (active) {
82095cc27f0SJoerg Sonnenberger change_filter(0, luser, ipsrc);
82170224baaSJan Lentfer change_table(0, ipsrc);
82295cc27f0SJoerg Sonnenberger authpf_kill_states();
82395cc27f0SJoerg Sonnenberger remove_stale_rulesets();
82495cc27f0SJoerg Sonnenberger }
82570224baaSJan Lentfer if (pidfile[0] && (pidfp != NULL))
82695cc27f0SJoerg Sonnenberger if (unlink(pidfile) == -1)
82795cc27f0SJoerg Sonnenberger syslog(LOG_ERR, "cannot unlink %s (%m)", pidfile);
82895cc27f0SJoerg Sonnenberger exit(ret);
82995cc27f0SJoerg Sonnenberger }
830