authpf.c revision 130617
1130617Smlaier/* $OpenBSD: authpf.c,v 1.75 2004/01/29 01:55:10 deraadt Exp $ */ 2126353Smlaier 3126353Smlaier/* 4126353Smlaier * Copyright (C) 1998 - 2002 Bob Beck (beck@openbsd.org). 5126353Smlaier * 6126353Smlaier * Redistribution and use in source and binary forms, with or without 7126353Smlaier * modification, are permitted provided that the following conditions 8126353Smlaier * are met: 9126353Smlaier * 1. Redistributions of source code must retain the above copyright 10126353Smlaier * notice, this list of conditions and the following disclaimer. 11126353Smlaier * 2. Redistributions in binary form must reproduce the above copyright 12126353Smlaier * notice, this list of conditions and the following disclaimer in the 13126353Smlaier * documentation and/or other materials provided with the distribution. 14126353Smlaier * 15126353Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16126353Smlaier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17126353Smlaier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18126353Smlaier * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19126353Smlaier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20126353Smlaier * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21126353Smlaier * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22126353Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23126353Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24126353Smlaier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25126353Smlaier * SUCH DAMAGE. 26126353Smlaier */ 27126353Smlaier 28127082Sobrien#include <sys/cdefs.h> 29127082Sobrien__FBSDID("$FreeBSD: head/contrib/pf/authpf/authpf.c 130617 2004-06-16 23:39:33Z mlaier $"); 30127082Sobrien 31127024Smlaier#include <sys/param.h> 32126353Smlaier#include <sys/file.h> 33126353Smlaier#include <sys/ioctl.h> 34126353Smlaier#include <sys/socket.h> 35126353Smlaier#include <sys/time.h> 36126353Smlaier 37126353Smlaier#include <net/if.h> 38126353Smlaier#include <net/pfvar.h> 39126353Smlaier#include <arpa/inet.h> 40126353Smlaier 41126353Smlaier#include <err.h> 42126353Smlaier#include <errno.h> 43126353Smlaier#include <pwd.h> 44126353Smlaier#include <signal.h> 45126353Smlaier#include <stdio.h> 46126353Smlaier#include <stdlib.h> 47126353Smlaier#include <string.h> 48126353Smlaier#include <syslog.h> 49126353Smlaier#include <unistd.h> 50126353Smlaier 51126353Smlaier#include <pfctl_parser.h> 52130617Smlaier#include <pfctl.h> 53126353Smlaier 54126353Smlaier#include "pathnames.h" 55126353Smlaier 56126353Smlaierextern int symset(const char *, const char *, int); 57126353Smlaier 58126353Smlaierstatic int read_config(FILE *); 59126353Smlaierstatic void print_message(char *); 60126353Smlaierstatic int allowed_luser(char *); 61126353Smlaierstatic int check_luser(char *, char *); 62126353Smlaierstatic int remove_stale_rulesets(void); 63126353Smlaierstatic int change_filter(int, const char *, const char *); 64126353Smlaierstatic void authpf_kill_states(void); 65126353Smlaier 66126353Smlaierint dev; /* pf device */ 67126353Smlaierchar anchorname[PF_ANCHOR_NAME_SIZE] = "authpf"; 68126353Smlaierchar rulesetname[PF_RULESET_NAME_SIZE]; 69126353Smlaier 70126353SmlaierFILE *pidfp; 71126353Smlaierchar *infile; /* file name printed by yyerror() in parse.y */ 72126353Smlaierchar luser[MAXLOGNAME]; /* username */ 73126353Smlaierchar ipsrc[256]; /* ip as a string */ 74126353Smlaierchar pidfile[MAXPATHLEN]; /* we save pid in this file. */ 75126353Smlaier 76126353Smlaierstruct timeval Tstart, Tend; /* start and end times of session */ 77126353Smlaier 78126353Smlaiervolatile sig_atomic_t want_death; 79126353Smlaierstatic void need_death(int signo); 80127024Smlaier#ifdef __FreeBSD__ 81127024Smlaierstatic __dead2 void do_death(int); 82127024Smlaier#else 83126353Smlaierstatic __dead void do_death(int); 84127024Smlaier#endif 85126353Smlaier 86126353Smlaier/* 87126353Smlaier * User shell for authenticating gateways. Sole purpose is to allow 88126353Smlaier * a user to ssh to a gateway, and have the gateway modify packet 89126353Smlaier * filters to allow access, then remove access when the user finishes 90126353Smlaier * up. Meant to be used only from ssh(1) connections. 91126353Smlaier */ 92126353Smlaierint 93126353Smlaiermain(int argc, char *argv[]) 94126353Smlaier{ 95126353Smlaier int lockcnt = 0, n, pidfd; 96126353Smlaier FILE *config; 97126353Smlaier struct in_addr ina; 98126353Smlaier struct passwd *pw; 99126353Smlaier char *cp; 100126353Smlaier uid_t uid; 101126353Smlaier 102126353Smlaier config = fopen(PATH_CONFFILE, "r"); 103126353Smlaier 104126353Smlaier if ((cp = getenv("SSH_TTY")) == NULL) { 105126353Smlaier syslog(LOG_ERR, "non-interactive session connection for authpf"); 106126353Smlaier exit(1); 107126353Smlaier } 108126353Smlaier 109126353Smlaier if ((cp = getenv("SSH_CLIENT")) == NULL) { 110126353Smlaier syslog(LOG_ERR, "cannot determine connection source"); 111126353Smlaier exit(1); 112126353Smlaier } 113126353Smlaier 114126353Smlaier if (strlcpy(ipsrc, cp, sizeof(ipsrc)) >= sizeof(ipsrc)) { 115126353Smlaier syslog(LOG_ERR, "SSH_CLIENT variable too long"); 116126353Smlaier exit(1); 117126353Smlaier } 118126353Smlaier cp = strchr(ipsrc, ' '); 119126353Smlaier if (!cp) { 120126353Smlaier syslog(LOG_ERR, "corrupt SSH_CLIENT variable %s", ipsrc); 121126353Smlaier exit(1); 122126353Smlaier } 123126353Smlaier *cp = '\0'; 124126353Smlaier if (inet_pton(AF_INET, ipsrc, &ina) != 1) { 125126353Smlaier syslog(LOG_ERR, 126126353Smlaier "cannot determine IP from SSH_CLIENT %s", ipsrc); 127126353Smlaier exit(1); 128126353Smlaier } 129126353Smlaier /* open the pf device */ 130126353Smlaier dev = open(PATH_DEVFILE, O_RDWR); 131126353Smlaier if (dev == -1) { 132126353Smlaier syslog(LOG_ERR, "cannot open packet filter device (%m)"); 133126353Smlaier goto die; 134126353Smlaier } 135126353Smlaier 136126353Smlaier uid = getuid(); 137126353Smlaier pw = getpwuid(uid); 138126353Smlaier if (pw == NULL) { 139126353Smlaier syslog(LOG_ERR, "cannot find user for uid %u", uid); 140126353Smlaier goto die; 141126353Smlaier } 142126353Smlaier if (strcmp(pw->pw_shell, PATH_AUTHPF_SHELL)) { 143126353Smlaier syslog(LOG_ERR, "wrong shell for user %s, uid %u", 144126353Smlaier pw->pw_name, pw->pw_uid); 145126353Smlaier goto die; 146126353Smlaier } 147126353Smlaier 148126353Smlaier /* 149126353Smlaier * Paranoia, but this data _does_ come from outside authpf, and 150126353Smlaier * truncation would be bad. 151126353Smlaier */ 152126353Smlaier if (strlcpy(luser, pw->pw_name, sizeof(luser)) >= sizeof(luser)) { 153126353Smlaier syslog(LOG_ERR, "username too long: %s", pw->pw_name); 154126353Smlaier goto die; 155126353Smlaier } 156126353Smlaier 157130617Smlaier if ((n = snprintf(rulesetname, sizeof(rulesetname), "%s(%ld)", 158130617Smlaier luser, (long)getpid())) < 0 || n >= sizeof(rulesetname)) { 159130617Smlaier syslog(LOG_INFO, "%s(%ld) too large, ruleset name will be %ld", 160130617Smlaier luser, (long)getpid(), (long)getpid()); 161130617Smlaier if ((n = snprintf(rulesetname, sizeof(rulesetname), "%ld", 162130617Smlaier (long)getpid())) < 0 || n >= sizeof(rulesetname)) { 163130617Smlaier syslog(LOG_ERR, "pid too large for ruleset name"); 164130617Smlaier goto die; 165130617Smlaier } 166130617Smlaier } 167130617Smlaier 168130617Smlaier 169126353Smlaier /* Make our entry in /var/authpf as /var/authpf/ipaddr */ 170126353Smlaier n = snprintf(pidfile, sizeof(pidfile), "%s/%s", PATH_PIDFILE, ipsrc); 171126353Smlaier if (n < 0 || (u_int)n >= sizeof(pidfile)) { 172126353Smlaier syslog(LOG_ERR, "path to pidfile too long"); 173126353Smlaier goto die; 174126353Smlaier } 175126353Smlaier 176126353Smlaier /* 177126353Smlaier * If someone else is already using this ip, then this person 178126353Smlaier * wants to switch users - so kill the old process and exit 179126353Smlaier * as well. 180126353Smlaier * 181126353Smlaier * Note, we could print a message and tell them to log out, but the 182126353Smlaier * usual case of this is that someone has left themselves logged in, 183126353Smlaier * with the authenticated connection iconized and someone else walks 184126353Smlaier * up to use and automatically logs in before using. If this just 185126353Smlaier * gets rid of the old one silently, the new user never knows they 186126353Smlaier * could have used someone else's old authentication. If we 187126353Smlaier * tell them to log out before switching users it is an invitation 188126353Smlaier * for abuse. 189126353Smlaier */ 190126353Smlaier 191126353Smlaier do { 192126353Smlaier int save_errno, otherpid = -1; 193126353Smlaier char otherluser[MAXLOGNAME]; 194126353Smlaier 195126353Smlaier if ((pidfd = open(pidfile, O_RDWR|O_CREAT, 0644)) == -1 || 196126353Smlaier (pidfp = fdopen(pidfd, "r+")) == NULL) { 197126353Smlaier if (pidfd != -1) 198126353Smlaier close(pidfd); 199126353Smlaier syslog(LOG_ERR, "cannot open or create %s: %s", pidfile, 200126353Smlaier strerror(errno)); 201126353Smlaier goto die; 202126353Smlaier } 203126353Smlaier 204126353Smlaier if (flock(fileno(pidfp), LOCK_EX|LOCK_NB) == 0) 205126353Smlaier break; 206126353Smlaier save_errno = errno; 207126353Smlaier 208126353Smlaier /* Mark our pid, and username to our file. */ 209126353Smlaier 210126353Smlaier rewind(pidfp); 211126353Smlaier /* 31 == MAXLOGNAME - 1 */ 212126353Smlaier if (fscanf(pidfp, "%d\n%31s\n", &otherpid, otherluser) != 2) 213126353Smlaier otherpid = -1; 214126353Smlaier syslog(LOG_DEBUG, "tried to lock %s, in use by pid %d: %s", 215126353Smlaier pidfile, otherpid, strerror(save_errno)); 216126353Smlaier 217126353Smlaier if (otherpid > 0) { 218126353Smlaier syslog(LOG_INFO, 219126353Smlaier "killing prior auth (pid %d) of %s by user %s", 220126353Smlaier otherpid, ipsrc, otherluser); 221126353Smlaier if (kill((pid_t) otherpid, SIGTERM) == -1) { 222126353Smlaier syslog(LOG_INFO, 223126353Smlaier "could not kill process %d: (%m)", 224126353Smlaier otherpid); 225126353Smlaier } 226126353Smlaier } 227126353Smlaier 228126353Smlaier /* 229126353Smlaier * we try to kill the previous process and acquire the lock 230126353Smlaier * for 10 seconds, trying once a second. if we can't after 231126353Smlaier * 10 attempts we log an error and give up 232126353Smlaier */ 233126353Smlaier if (++lockcnt > 10) { 234126353Smlaier syslog(LOG_ERR, "cannot kill previous authpf (pid %d)", 235126353Smlaier otherpid); 236126353Smlaier goto dogdeath; 237126353Smlaier } 238126353Smlaier sleep(1); 239126353Smlaier 240126353Smlaier /* re-open, and try again. The previous authpf process 241126353Smlaier * we killed above should unlink the file and release 242126353Smlaier * it's lock, giving us a chance to get it now 243126353Smlaier */ 244126353Smlaier fclose(pidfp); 245126353Smlaier } while (1); 246126353Smlaier 247126353Smlaier /* revoke privs */ 248126353Smlaier seteuid(getuid()); 249126353Smlaier setuid(getuid()); 250126353Smlaier 251130617Smlaier openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON); 252130617Smlaier 253130617Smlaier if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser)) { 254130617Smlaier syslog(LOG_INFO, "user %s prohibited", luser); 255126353Smlaier do_death(0); 256130617Smlaier } 257126353Smlaier 258130617Smlaier if (config == NULL || read_config(config)) { 259130617Smlaier syslog(LOG_INFO, "bad or nonexistent %s", PATH_CONFFILE); 260126353Smlaier do_death(0); 261130617Smlaier } 262126353Smlaier 263130617Smlaier if (remove_stale_rulesets()) { 264130617Smlaier syslog(LOG_INFO, "error removing stale rulesets"); 265126353Smlaier do_death(0); 266130617Smlaier } 267126353Smlaier 268126353Smlaier /* We appear to be making headway, so actually mark our pid */ 269126353Smlaier rewind(pidfp); 270126353Smlaier fprintf(pidfp, "%ld\n%s\n", (long)getpid(), luser); 271126353Smlaier fflush(pidfp); 272126353Smlaier (void) ftruncate(fileno(pidfp), ftell(pidfp)); 273126353Smlaier 274126353Smlaier if (change_filter(1, luser, ipsrc) == -1) { 275126353Smlaier printf("Unable to modify filters\r\n"); 276130617Smlaier do_death(0); 277126353Smlaier } 278126353Smlaier 279126353Smlaier signal(SIGTERM, need_death); 280126353Smlaier signal(SIGINT, need_death); 281126353Smlaier signal(SIGALRM, need_death); 282126353Smlaier signal(SIGPIPE, need_death); 283126353Smlaier signal(SIGHUP, need_death); 284126353Smlaier signal(SIGSTOP, need_death); 285126353Smlaier signal(SIGTSTP, need_death); 286126353Smlaier while (1) { 287126353Smlaier printf("\r\nHello %s, ", luser); 288126353Smlaier printf("You are authenticated from host \"%s\"\r\n", ipsrc); 289126353Smlaier setproctitle("%s@%s", luser, ipsrc); 290126353Smlaier print_message(PATH_MESSAGE); 291126353Smlaier while (1) { 292126353Smlaier sleep(10); 293126353Smlaier if (want_death) 294126353Smlaier do_death(1); 295126353Smlaier } 296126353Smlaier } 297126353Smlaier 298126353Smlaier /* NOTREACHED */ 299126353Smlaierdogdeath: 300126353Smlaier printf("\r\n\r\nSorry, this service is currently unavailable due to "); 301126353Smlaier printf("technical difficulties\r\n\r\n"); 302126353Smlaier print_message(PATH_PROBLEM); 303126353Smlaier printf("\r\nYour authentication process (pid %ld) was unable to run\n", 304126353Smlaier (long)getpid()); 305126353Smlaier sleep(180); /* them lusers read reaaaaal slow */ 306126353Smlaierdie: 307126353Smlaier do_death(0); 308127024Smlaier 309127024Smlaier /* NOTREACHED */ 310126353Smlaier} 311126353Smlaier 312126353Smlaier/* 313126353Smlaier * reads config file in PATH_CONFFILE to set optional behaviours up 314126353Smlaier */ 315126353Smlaierstatic int 316126353Smlaierread_config(FILE *f) 317126353Smlaier{ 318126353Smlaier char buf[1024]; 319126353Smlaier int i = 0; 320126353Smlaier 321126353Smlaier do { 322126353Smlaier char **ap; 323126353Smlaier char *pair[4], *cp, *tp; 324126353Smlaier int len; 325126353Smlaier 326126353Smlaier if (fgets(buf, sizeof(buf), f) == NULL) { 327126353Smlaier fclose(f); 328126353Smlaier return (0); 329126353Smlaier } 330126353Smlaier i++; 331126353Smlaier len = strlen(buf); 332126353Smlaier if (buf[len - 1] != '\n' && !feof(f)) { 333126353Smlaier syslog(LOG_ERR, "line %d too long in %s", i, 334126353Smlaier PATH_CONFFILE); 335126353Smlaier return (1); 336126353Smlaier } 337126353Smlaier buf[len - 1] = '\0'; 338126353Smlaier 339126353Smlaier for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) 340126353Smlaier ; /* nothing */ 341126353Smlaier 342126353Smlaier if (!*cp || *cp == '#' || *cp == '\n') 343126353Smlaier continue; 344126353Smlaier 345126353Smlaier for (ap = pair; ap < &pair[3] && 346126353Smlaier (*ap = strsep(&cp, "=")) != NULL; ) { 347126353Smlaier if (**ap != '\0') 348126353Smlaier ap++; 349126353Smlaier } 350126353Smlaier if (ap != &pair[2]) 351126353Smlaier goto parse_error; 352126353Smlaier 353126353Smlaier tp = pair[1] + strlen(pair[1]); 354126353Smlaier while ((*tp == ' ' || *tp == '\t') && tp >= pair[1]) 355126353Smlaier *tp-- = '\0'; 356126353Smlaier 357126353Smlaier if (strcasecmp(pair[0], "anchor") == 0) { 358126353Smlaier if (!pair[1][0] || strlcpy(anchorname, pair[1], 359126353Smlaier sizeof(anchorname)) >= sizeof(anchorname)) 360126353Smlaier goto parse_error; 361126353Smlaier } 362126353Smlaier } while (!feof(f) && !ferror(f)); 363126353Smlaier fclose(f); 364126353Smlaier return (0); 365126353Smlaier 366126353Smlaierparse_error: 367126353Smlaier fclose(f); 368126353Smlaier syslog(LOG_ERR, "parse error, line %d of %s", i, PATH_CONFFILE); 369126353Smlaier return (1); 370126353Smlaier} 371126353Smlaier 372126353Smlaier 373126353Smlaier/* 374126353Smlaier * splatter a file to stdout - max line length of 1024, 375126353Smlaier * used for spitting message files at users to tell them 376126353Smlaier * they've been bad or we're unavailable. 377126353Smlaier */ 378126353Smlaierstatic void 379126353Smlaierprint_message(char *filename) 380126353Smlaier{ 381126353Smlaier char buf[1024]; 382126353Smlaier FILE *f; 383126353Smlaier 384126353Smlaier if ((f = fopen(filename, "r")) == NULL) 385126353Smlaier return; /* fail silently, we don't care if it isn't there */ 386126353Smlaier 387126353Smlaier do { 388126353Smlaier if (fgets(buf, sizeof(buf), f) == NULL) { 389126353Smlaier fflush(stdout); 390126353Smlaier fclose(f); 391126353Smlaier return; 392126353Smlaier } 393126353Smlaier } while (fputs(buf, stdout) != EOF && !feof(f)); 394126353Smlaier fflush(stdout); 395126353Smlaier fclose(f); 396126353Smlaier} 397126353Smlaier 398126353Smlaier/* 399126353Smlaier * allowed_luser checks to see if user "luser" is allowed to 400126353Smlaier * use this gateway by virtue of being listed in an allowed 401126353Smlaier * users file, namely /etc/authpf/authpf.allow . 402126353Smlaier * 403126353Smlaier * If /etc/authpf/authpf.allow does not exist, then we assume that 404126353Smlaier * all users who are allowed in by sshd(8) are permitted to 405126353Smlaier * use this gateway. If /etc/authpf/authpf.allow does exist, then a 406126353Smlaier * user must be listed if the connection is to continue, else 407126353Smlaier * the session terminates in the same manner as being banned. 408126353Smlaier */ 409126353Smlaierstatic int 410126353Smlaierallowed_luser(char *luser) 411126353Smlaier{ 412126353Smlaier char *buf, *lbuf; 413126353Smlaier int matched; 414126353Smlaier size_t len; 415126353Smlaier FILE *f; 416126353Smlaier 417126353Smlaier if ((f = fopen(PATH_ALLOWFILE, "r")) == NULL) { 418126353Smlaier if (errno == ENOENT) { 419126353Smlaier /* 420126353Smlaier * allowfile doesn't exist, thus this gateway 421126353Smlaier * isn't restricted to certain users... 422126353Smlaier */ 423126353Smlaier return (1); 424126353Smlaier } 425126353Smlaier 426126353Smlaier /* 427126353Smlaier * luser may in fact be allowed, but we can't open 428126353Smlaier * the file even though it's there. probably a config 429126353Smlaier * problem. 430126353Smlaier */ 431126353Smlaier syslog(LOG_ERR, "cannot open allowed users file %s (%s)", 432126353Smlaier PATH_ALLOWFILE, strerror(errno)); 433126353Smlaier return (0); 434126353Smlaier } else { 435126353Smlaier /* 436126353Smlaier * /etc/authpf/authpf.allow exists, thus we do a linear 437126353Smlaier * search to see if they are allowed. 438126353Smlaier * also, if username "*" exists, then this is a 439126353Smlaier * "public" gateway, such as it is, so let 440126353Smlaier * everyone use it. 441126353Smlaier */ 442126353Smlaier lbuf = NULL; 443126353Smlaier while ((buf = fgetln(f, &len))) { 444126353Smlaier if (buf[len - 1] == '\n') 445126353Smlaier buf[len - 1] = '\0'; 446126353Smlaier else { 447126353Smlaier if ((lbuf = (char *)malloc(len + 1)) == NULL) 448126353Smlaier err(1, NULL); 449126353Smlaier memcpy(lbuf, buf, len); 450126353Smlaier lbuf[len] = '\0'; 451126353Smlaier buf = lbuf; 452126353Smlaier } 453126353Smlaier 454126353Smlaier matched = strcmp(luser, buf) == 0 || strcmp("*", buf) == 0; 455126353Smlaier 456126353Smlaier if (lbuf != NULL) { 457126353Smlaier free(lbuf); 458126353Smlaier lbuf = NULL; 459126353Smlaier } 460126353Smlaier 461126353Smlaier if (matched) 462126353Smlaier return (1); /* matched an allowed username */ 463126353Smlaier } 464126353Smlaier syslog(LOG_INFO, "denied access to %s: not listed in %s", 465126353Smlaier luser, PATH_ALLOWFILE); 466126353Smlaier 467126353Smlaier /* reuse buf */ 468126353Smlaier buf = "\n\nSorry, you are not allowed to use this facility!\n"; 469126353Smlaier fputs(buf, stdout); 470126353Smlaier } 471126353Smlaier fflush(stdout); 472126353Smlaier return (0); 473126353Smlaier} 474126353Smlaier 475126353Smlaier/* 476126353Smlaier * check_luser checks to see if user "luser" has been banned 477126353Smlaier * from using us by virtue of having an file of the same name 478126353Smlaier * in the "luserdir" directory. 479126353Smlaier * 480126353Smlaier * If the user has been banned, we copy the contents of the file 481126353Smlaier * to the user's screen. (useful for telling the user what to 482126353Smlaier * do to get un-banned, or just to tell them they aren't 483126353Smlaier * going to be un-banned.) 484126353Smlaier */ 485126353Smlaierstatic int 486126353Smlaiercheck_luser(char *luserdir, char *luser) 487126353Smlaier{ 488126353Smlaier FILE *f; 489126353Smlaier int n; 490126353Smlaier char tmp[MAXPATHLEN]; 491126353Smlaier 492126353Smlaier n = snprintf(tmp, sizeof(tmp), "%s/%s", luserdir, luser); 493126353Smlaier if (n < 0 || (u_int)n >= sizeof(tmp)) { 494126353Smlaier syslog(LOG_ERR, "provided banned directory line too long (%s)", 495126353Smlaier luserdir); 496126353Smlaier return (0); 497126353Smlaier } 498126353Smlaier if ((f = fopen(tmp, "r")) == NULL) { 499126353Smlaier if (errno == ENOENT) { 500126353Smlaier /* 501126353Smlaier * file or dir doesn't exist, so therefore 502126353Smlaier * this luser isn't banned.. all is well 503126353Smlaier */ 504126353Smlaier return (1); 505126353Smlaier } else { 506126353Smlaier /* 507126353Smlaier * luser may in fact be banned, but we can't open the 508126353Smlaier * file even though it's there. probably a config 509126353Smlaier * problem. 510126353Smlaier */ 511126353Smlaier syslog(LOG_ERR, "cannot open banned file %s (%s)", 512126353Smlaier tmp, strerror(errno)); 513126353Smlaier return (0); 514126353Smlaier } 515126353Smlaier } else { 516126353Smlaier /* 517126353Smlaier * luser is banned - spit the file at them to 518126353Smlaier * tell what they can do and where they can go. 519126353Smlaier */ 520126353Smlaier syslog(LOG_INFO, "denied access to %s: %s exists", 521126353Smlaier luser, tmp); 522126353Smlaier 523126353Smlaier /* reuse tmp */ 524126353Smlaier strlcpy(tmp, "\n\n-**- Sorry, you have been banned! -**-\n\n", 525126353Smlaier sizeof(tmp)); 526126353Smlaier while (fputs(tmp, stdout) != EOF && !feof(f)) { 527126353Smlaier if (fgets(tmp, sizeof(tmp), f) == NULL) { 528126353Smlaier fflush(stdout); 529126353Smlaier return (0); 530126353Smlaier } 531126353Smlaier } 532126353Smlaier } 533126353Smlaier fflush(stdout); 534126353Smlaier return (0); 535126353Smlaier} 536126353Smlaier 537126353Smlaier/* 538126353Smlaier * Search for rulesets left by other authpf processes (either because they 539126353Smlaier * died ungracefully or were terminated) and remove them. 540126353Smlaier */ 541126353Smlaierstatic int 542126353Smlaierremove_stale_rulesets(void) 543126353Smlaier{ 544126353Smlaier struct pfioc_ruleset prs; 545126353Smlaier const int action[PF_RULESET_MAX] = { PF_SCRUB, 546126353Smlaier PF_PASS, PF_NAT, PF_BINAT, PF_RDR }; 547126353Smlaier u_int32_t nr, mnr; 548126353Smlaier 549126353Smlaier memset(&prs, 0, sizeof(prs)); 550126353Smlaier strlcpy(prs.anchor, anchorname, sizeof(prs.anchor)); 551126353Smlaier if (ioctl(dev, DIOCGETRULESETS, &prs)) { 552126353Smlaier if (errno == EINVAL) 553126353Smlaier return (0); 554126353Smlaier else 555126353Smlaier return (1); 556126353Smlaier } 557126353Smlaier 558126353Smlaier mnr = prs.nr; 559126353Smlaier nr = 0; 560126353Smlaier while (nr < mnr) { 561130617Smlaier char *s, *t; 562126353Smlaier pid_t pid; 563126353Smlaier 564126353Smlaier prs.nr = nr; 565126353Smlaier if (ioctl(dev, DIOCGETRULESET, &prs)) 566126353Smlaier return (1); 567126353Smlaier errno = 0; 568130617Smlaier if ((t = strchr(prs.name, '(')) == NULL) 569130617Smlaier t = prs.name; 570130617Smlaier else 571130617Smlaier t++; 572130617Smlaier pid = strtoul(t, &s, 10); 573130617Smlaier if (!prs.name[0] || errno || 574130617Smlaier (*s && (t == prs.name || *s != ')'))) 575126353Smlaier return (1); 576126353Smlaier if (kill(pid, 0) && errno != EPERM) { 577126353Smlaier int i; 578126353Smlaier 579126353Smlaier for (i = 0; i < PF_RULESET_MAX; ++i) { 580126353Smlaier struct pfioc_rule pr; 581126353Smlaier 582126353Smlaier memset(&pr, 0, sizeof(pr)); 583126353Smlaier memcpy(pr.anchor, prs.anchor, sizeof(pr.anchor)); 584126353Smlaier memcpy(pr.ruleset, prs.name, sizeof(pr.ruleset)); 585126353Smlaier pr.rule.action = action[i]; 586126353Smlaier if ((ioctl(dev, DIOCBEGINRULES, &pr) || 587126353Smlaier ioctl(dev, DIOCCOMMITRULES, &pr)) && 588126353Smlaier errno != EINVAL) 589126353Smlaier return (1); 590126353Smlaier } 591126353Smlaier mnr--; 592126353Smlaier } else 593126353Smlaier nr++; 594126353Smlaier } 595126353Smlaier return (0); 596126353Smlaier} 597126353Smlaier 598126353Smlaier/* 599126353Smlaier * Add/remove filter entries for user "luser" from ip "ipsrc" 600126353Smlaier */ 601126353Smlaierstatic int 602126353Smlaierchange_filter(int add, const char *luser, const char *ipsrc) 603126353Smlaier{ 604126353Smlaier char fn[MAXPATHLEN]; 605126353Smlaier FILE *f = NULL; 606126353Smlaier struct pfctl pf; 607130617Smlaier struct pfr_buffer t; 608126353Smlaier int i; 609126353Smlaier 610130617Smlaier if (luser == NULL || !luser[0] || ipsrc == NULL || !ipsrc[0]) { 611126353Smlaier syslog(LOG_ERR, "invalid luser/ipsrc"); 612126353Smlaier goto error; 613126353Smlaier } 614126353Smlaier 615126353Smlaier if (add) { 616126353Smlaier if ((i = snprintf(fn, sizeof(fn), "%s/%s/authpf.rules", 617126353Smlaier PATH_USER_DIR, luser)) < 0 || i >= sizeof(fn)) { 618126353Smlaier syslog(LOG_ERR, "user rule path too long"); 619126353Smlaier goto error; 620126353Smlaier } 621126353Smlaier if ((f = fopen(fn, "r")) == NULL && errno != ENOENT) { 622126353Smlaier syslog(LOG_ERR, "cannot open %s (%m)", fn); 623126353Smlaier goto error; 624126353Smlaier } 625126353Smlaier if (f == NULL) { 626126353Smlaier if (strlcpy(fn, PATH_PFRULES, sizeof(fn)) >= 627126353Smlaier sizeof(fn)) { 628126353Smlaier syslog(LOG_ERR, "rule path too long"); 629126353Smlaier goto error; 630126353Smlaier } 631126353Smlaier if ((f = fopen(fn, "r")) == NULL) { 632126353Smlaier syslog(LOG_ERR, "cannot open %s (%m)", fn); 633126353Smlaier goto error; 634126353Smlaier } 635126353Smlaier } 636126353Smlaier } 637126353Smlaier 638126353Smlaier if (pfctl_load_fingerprints(dev, 0)) { 639126353Smlaier syslog(LOG_ERR, "unable to load kernel's OS fingerprints"); 640126353Smlaier goto error; 641126353Smlaier } 642130617Smlaier bzero(&t, sizeof(t)); 643130617Smlaier t.pfrb_type = PFRB_TRANS; 644126353Smlaier memset(&pf, 0, sizeof(pf)); 645126353Smlaier for (i = 0; i < PF_RULESET_MAX; ++i) { 646130617Smlaier if (pfctl_add_trans(&t, i, anchorname, rulesetname)) { 647130617Smlaier syslog(LOG_ERR, "pfctl_add_trans %m"); 648126353Smlaier goto error; 649126353Smlaier } 650126353Smlaier } 651130617Smlaier if (pfctl_trans(dev, &t, DIOCXBEGIN, 0)) { 652130617Smlaier syslog(LOG_ERR, "DIOCXBEGIN (%s) %m", add?"add":"remove"); 653130617Smlaier goto error; 654130617Smlaier } 655126353Smlaier 656126353Smlaier if (add) { 657126353Smlaier if (symset("user_ip", ipsrc, 0) || 658126353Smlaier symset("user_id", luser, 0)) { 659126353Smlaier syslog(LOG_ERR, "symset"); 660126353Smlaier goto error; 661126353Smlaier } 662126353Smlaier 663126353Smlaier pf.dev = dev; 664130617Smlaier pf.trans = &t; 665130617Smlaier pf.anchor = anchorname; 666130617Smlaier pf.ruleset = rulesetname; 667130617Smlaier 668126353Smlaier infile = fn; 669126353Smlaier if (parse_rules(f, &pf) < 0) { 670126353Smlaier syslog(LOG_ERR, "syntax error in rule file: " 671126353Smlaier "authpf rules not loaded"); 672126353Smlaier goto error; 673126353Smlaier } 674126353Smlaier 675126353Smlaier infile = NULL; 676126353Smlaier fclose(f); 677126353Smlaier f = NULL; 678126353Smlaier } 679126353Smlaier 680130617Smlaier if (pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) { 681130617Smlaier syslog(LOG_ERR, "DIOCXCOMMIT (%s) %m", add?"add":"remove"); 682130617Smlaier goto error; 683130617Smlaier } 684126353Smlaier 685126353Smlaier if (add) { 686126353Smlaier gettimeofday(&Tstart, NULL); 687126353Smlaier syslog(LOG_INFO, "allowing %s, user %s", ipsrc, luser); 688126353Smlaier } else { 689126353Smlaier gettimeofday(&Tend, NULL); 690126353Smlaier syslog(LOG_INFO, "removed %s, user %s - duration %ld seconds", 691126353Smlaier ipsrc, luser, Tend.tv_sec - Tstart.tv_sec); 692126353Smlaier } 693126353Smlaier return (0); 694126353Smlaier 695126353Smlaiererror: 696126353Smlaier if (f != NULL) 697126353Smlaier fclose(f); 698130617Smlaier if (pfctl_trans(dev, &t, DIOCXROLLBACK, 0)) 699130617Smlaier syslog(LOG_ERR, "DIOCXROLLBACK (%s) %m", add?"add":"remove"); 700126353Smlaier 701126353Smlaier infile = NULL; 702126353Smlaier return (-1); 703126353Smlaier} 704126353Smlaier 705126353Smlaier/* 706126353Smlaier * This is to kill off states that would otherwise be left behind stateful 707126353Smlaier * rules. This means we don't need to allow in more traffic than we really 708126353Smlaier * want to, since we don't have to worry about any luser sessions lasting 709126353Smlaier * longer than their ssh session. This function is based on 710126353Smlaier * pfctl_kill_states from pfctl. 711126353Smlaier */ 712126353Smlaierstatic void 713126353Smlaierauthpf_kill_states(void) 714126353Smlaier{ 715126353Smlaier struct pfioc_state_kill psk; 716126353Smlaier struct in_addr target; 717126353Smlaier 718126353Smlaier memset(&psk, 0, sizeof(psk)); 719126353Smlaier psk.psk_af = AF_INET; 720126353Smlaier 721126353Smlaier inet_pton(AF_INET, ipsrc, &target); 722126353Smlaier 723126353Smlaier /* Kill all states from ipsrc */ 724126353Smlaier psk.psk_src.addr.v.a.addr.v4 = target; 725126353Smlaier memset(&psk.psk_src.addr.v.a.mask, 0xff, 726126353Smlaier sizeof(psk.psk_src.addr.v.a.mask)); 727126353Smlaier if (ioctl(dev, DIOCKILLSTATES, &psk)) 728126353Smlaier syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)"); 729126353Smlaier 730126353Smlaier /* Kill all states to ipsrc */ 731126353Smlaier psk.psk_af = AF_INET; 732126353Smlaier memset(&psk.psk_src, 0, sizeof(psk.psk_src)); 733126353Smlaier psk.psk_dst.addr.v.a.addr.v4 = target; 734126353Smlaier memset(&psk.psk_dst.addr.v.a.mask, 0xff, 735126353Smlaier sizeof(psk.psk_dst.addr.v.a.mask)); 736126353Smlaier if (ioctl(dev, DIOCKILLSTATES, &psk)) 737126353Smlaier syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)"); 738126353Smlaier} 739126353Smlaier 740126353Smlaier/* signal handler that makes us go away properly */ 741126353Smlaierstatic void 742126353Smlaierneed_death(int signo) 743126353Smlaier{ 744126353Smlaier want_death = 1; 745126353Smlaier} 746126353Smlaier 747126353Smlaier/* 748126353Smlaier * function that removes our stuff when we go away. 749126353Smlaier */ 750127024Smlaier#ifdef __FreeBSD__ 751127024Smlaierstatic __dead2 void 752127024Smlaier#else 753126353Smlaierstatic __dead void 754127024Smlaier#endif 755126353Smlaierdo_death(int active) 756126353Smlaier{ 757126353Smlaier int ret = 0; 758126353Smlaier 759126353Smlaier if (active) { 760126353Smlaier change_filter(0, luser, ipsrc); 761126353Smlaier authpf_kill_states(); 762126353Smlaier remove_stale_rulesets(); 763126353Smlaier } 764126353Smlaier if (pidfp) 765126353Smlaier ftruncate(fileno(pidfp), 0); 766126353Smlaier if (pidfile[0]) 767126353Smlaier if (unlink(pidfile) == -1) 768126353Smlaier syslog(LOG_ERR, "cannot unlink %s (%m)", pidfile); 769126353Smlaier exit(ret); 770126353Smlaier} 771126353Smlaier 772126353Smlaier/* 773126353Smlaier * callbacks for parse_rules(void) 774126353Smlaier */ 775126353Smlaier 776126353Smlaierint 777126353Smlaierpfctl_add_rule(struct pfctl *pf, struct pf_rule *r) 778126353Smlaier{ 779130617Smlaier u_int8_t rs_num; 780130617Smlaier struct pfioc_rule pr; 781126353Smlaier 782126353Smlaier switch (r->action) { 783126353Smlaier case PF_PASS: 784126353Smlaier case PF_DROP: 785130617Smlaier rs_num = PF_RULESET_FILTER; 786126353Smlaier break; 787126353Smlaier case PF_SCRUB: 788130617Smlaier rs_num = PF_RULESET_SCRUB; 789126353Smlaier break; 790126353Smlaier case PF_NAT: 791126353Smlaier case PF_NONAT: 792130617Smlaier rs_num = PF_RULESET_NAT; 793126353Smlaier break; 794126353Smlaier case PF_RDR: 795126353Smlaier case PF_NORDR: 796130617Smlaier rs_num = PF_RULESET_RDR; 797126353Smlaier break; 798126353Smlaier case PF_BINAT: 799126353Smlaier case PF_NOBINAT: 800130617Smlaier rs_num = PF_RULESET_BINAT; 801126353Smlaier break; 802126353Smlaier default: 803126353Smlaier syslog(LOG_ERR, "invalid rule action %d", r->action); 804126353Smlaier return (1); 805126353Smlaier } 806130617Smlaier 807130617Smlaier bzero(&pr, sizeof(pr)); 808130617Smlaier strlcpy(pr.anchor, pf->anchor, sizeof(pr.anchor)); 809130617Smlaier strlcpy(pr.ruleset, pf->ruleset, sizeof(pr.ruleset)); 810126353Smlaier if (pfctl_add_pool(pf, &r->rpool, r->af)) 811126353Smlaier return (1); 812130617Smlaier pr.ticket = pfctl_get_ticket(pf->trans, rs_num, pf->anchor, 813130617Smlaier pf->ruleset); 814130617Smlaier pr.pool_ticket = pf->paddr.ticket; 815130617Smlaier memcpy(&pr.rule, r, sizeof(pr.rule)); 816130617Smlaier if (ioctl(pf->dev, DIOCADDRULE, &pr)) { 817126353Smlaier syslog(LOG_ERR, "DIOCADDRULE %m"); 818126353Smlaier return (1); 819126353Smlaier } 820126353Smlaier pfctl_clear_pool(&r->rpool); 821126353Smlaier return (0); 822126353Smlaier} 823126353Smlaier 824126353Smlaierint 825126353Smlaierpfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af) 826126353Smlaier{ 827126353Smlaier struct pf_pooladdr *pa; 828126353Smlaier 829126353Smlaier if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr)) { 830126353Smlaier syslog(LOG_ERR, "DIOCBEGINADDRS %m"); 831126353Smlaier return (1); 832126353Smlaier } 833126353Smlaier pf->paddr.af = af; 834126353Smlaier TAILQ_FOREACH(pa, &p->list, entries) { 835126353Smlaier memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr)); 836126353Smlaier if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr)) { 837126353Smlaier syslog(LOG_ERR, "DIOCADDADDR %m"); 838126353Smlaier return (1); 839126353Smlaier } 840126353Smlaier } 841126353Smlaier return (0); 842126353Smlaier} 843126353Smlaier 844126353Smlaiervoid 845126353Smlaierpfctl_clear_pool(struct pf_pool *pool) 846126353Smlaier{ 847126353Smlaier struct pf_pooladdr *pa; 848126353Smlaier 849126353Smlaier while ((pa = TAILQ_FIRST(&pool->list)) != NULL) { 850126353Smlaier TAILQ_REMOVE(&pool->list, pa, entries); 851126353Smlaier free(pa); 852126353Smlaier } 853126353Smlaier} 854126353Smlaier 855126353Smlaierint 856126353Smlaierpfctl_add_altq(struct pfctl *pf, struct pf_altq *a) 857126353Smlaier{ 858126353Smlaier fprintf(stderr, "altq rules not supported in authpf\n"); 859126353Smlaier return (1); 860126353Smlaier} 861126353Smlaier 862126353Smlaierint 863126353Smlaierpfctl_set_optimization(struct pfctl *pf, const char *opt) 864126353Smlaier{ 865126353Smlaier fprintf(stderr, "set optimization not supported in authpf\n"); 866126353Smlaier return (1); 867126353Smlaier} 868126353Smlaier 869126353Smlaierint 870126353Smlaierpfctl_set_logif(struct pfctl *pf, char *ifname) 871126353Smlaier{ 872126353Smlaier fprintf(stderr, "set loginterface not supported in authpf\n"); 873126353Smlaier return (1); 874126353Smlaier} 875126353Smlaier 876126353Smlaierint 877130617Smlaierpfctl_set_hostid(struct pfctl *pf, u_int32_t hostid) 878130617Smlaier{ 879130617Smlaier fprintf(stderr, "set hostid not supported in authpf\n"); 880130617Smlaier return (1); 881130617Smlaier} 882130617Smlaier 883130617Smlaierint 884126353Smlaierpfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet) 885126353Smlaier{ 886126353Smlaier fprintf(stderr, "set timeout not supported in authpf\n"); 887126353Smlaier return (1); 888126353Smlaier} 889126353Smlaier 890126353Smlaierint 891126353Smlaierpfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit) 892126353Smlaier{ 893126353Smlaier fprintf(stderr, "set limit not supported in authpf\n"); 894126353Smlaier return (1); 895126353Smlaier} 896126353Smlaier 897126353Smlaierint 898130617Smlaierpfctl_set_debug(struct pfctl *pf, char *d) 899130617Smlaier{ 900130617Smlaier fprintf(stderr, "set debug not supported in authpf\n"); 901130617Smlaier return (1); 902130617Smlaier} 903130617Smlaier 904130617Smlaierint 905126353Smlaierpfctl_define_table(char *name, int flags, int addrs, const char *anchor, 906126353Smlaier const char *ruleset, struct pfr_buffer *ab, u_int32_t ticket) 907126353Smlaier{ 908126353Smlaier fprintf(stderr, "table definitions not yet supported in authpf\n"); 909126353Smlaier return (1); 910126353Smlaier} 911126353Smlaier 912126353Smlaierint 913126353Smlaierpfctl_rules(int dev, char *filename, int opts, char *anchorname, 914130617Smlaier char *rulesetname, struct pfr_buffer *t) 915126353Smlaier{ 916126353Smlaier /* never called, no anchors inside anchors, but we need the stub */ 917126353Smlaier fprintf(stderr, "load anchor not supported from authpf\n"); 918126353Smlaier return (1); 919126353Smlaier} 920126353Smlaier 921130617Smlaiervoid 922130617Smlaierpfctl_print_title(char *title) 923130617Smlaier{ 924130617Smlaier} 925