diff options
author | Max Laier <mlaier@FreeBSD.org> | 2008-12-10 19:31:42 +0000 |
---|---|---|
committer | Max Laier <mlaier@FreeBSD.org> | 2008-12-10 19:31:42 +0000 |
commit | 551100331fc59409c6c0f7738ab22eb197b8df20 (patch) | |
tree | 09e9a4440c1d3bcf750c0336d5e4aa12640d2a77 /contrib/pf/authpf | |
parent | 67ecd4f3a477a0ca5b76a1694f89755df27a8679 (diff) | |
download | src-551100331fc59409c6c0f7738ab22eb197b8df20.tar.gz src-551100331fc59409c6c0f7738ab22eb197b8df20.zip |
Flatten out the pf userland vendor area
Notes
Notes:
svn path=/vendor/pf/dist/; revision=185872
Diffstat (limited to 'contrib/pf/authpf')
-rw-r--r-- | contrib/pf/authpf/authpf.8 | 527 | ||||
-rw-r--r-- | contrib/pf/authpf/authpf.c | 830 | ||||
-rw-r--r-- | contrib/pf/authpf/pathnames.h | 38 |
3 files changed, 0 insertions, 1395 deletions
diff --git a/contrib/pf/authpf/authpf.8 b/contrib/pf/authpf/authpf.8 deleted file mode 100644 index ee0dcaa423b3..000000000000 --- a/contrib/pf/authpf/authpf.8 +++ /dev/null @@ -1,527 +0,0 @@ -.\" $OpenBSD: authpf.8,v 1.43 2007/02/24 17:21:04 beck Exp $ -.\" -.\" Copyright (c) 1998-2007 Bob Beck (beck@openbsd.org>. All rights reserved. -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd January 10, 2002 -.Dt AUTHPF 8 -.Os -.Sh NAME -.Nm authpf -.Nd authenticating gateway user shell -.Sh SYNOPSIS -.Nm authpf -.Sh DESCRIPTION -.Nm -is a user shell for authenticating gateways. -It is used to change -.Xr pf 4 -rules when a user authenticates and starts a session with -.Xr sshd 8 -and to undo these changes when the user's session exits. -It is designed for changing filter and translation rules for an individual -source IP address as long as a user maintains an active -.Xr ssh 1 -session. -Typical use would be for a gateway that authenticates users before -allowing them Internet use, or a gateway that allows different users into -different places. -.Nm -logs the successful start and end of a session to -.Xr syslogd 8 . -This, combined with properly set up filter rules and secure switches, -can be used to ensure users are held accountable for their network traffic. -.Pp -.Nm -can add filter and translation rules using the syntax described in -.Xr pf.conf 5 . -.Nm -requires that the -.Xr pf 4 -system be enabled before use. -.Nm -can also maintain the list of IP address of connected users -in the "authpf_users" -.Pa table . -.Pp -.Nm -is meant to be used with users who can connect via -.Xr ssh 1 -only. -On startup, -.Nm -retrieves the client's connecting IP address via the -.Ev SSH_CLIENT -environment variable and, after performing additional access checks, -reads a template file to determine what filter and translation rules -(if any) to add. -On session exit the same rules that were added at startup are removed. -.Pp -Each -.Nm -process stores its rules in a separate ruleset inside a -.Xr pf 4 -.Pa anchor -shared by all -.Nm -processes. -By default, the -.Pa anchor -name "authpf" is used, and the ruleset names equal the username and PID of the -.Nm -processes as "username(pid)". -The following rules need to be added to the main ruleset -.Pa /etc/pf.conf -in order to cause evaluation of any -.Nm -rules: -.Bd -literal -offset indent -nat-anchor "authpf/*" -rdr-anchor "authpf/*" -binat-anchor "authpf/*" -anchor "authpf/*" -.Ed -.Pp -The "/*" at the end of the anchor name is required for -.Xr pf 4 -to process the rulesets attached to the anchor by -.Nm authpf . -.Sh FILTER AND TRANSLATION RULES -Filter and translation rules for -.Nm -use the same format described in -.Xr pf.conf 5 . -The only difference is that these rules may (and probably should) use -the macro -.Em user_ip , -which is assigned the connecting IP address whenever -.Nm -is run. -Additionally, the macro -.Em user_id -is assigned the user name. -.Pp -Filter and translation rules are stored in a file called -.Pa authpf.rules . -This file will first be searched for in -.Pa /etc/authpf/users/$USER/ -and then in -.Pa /etc/authpf/ . -Only one of these files will be used if both are present. -.Pp -Per-user rules from the -.Pa /etc/authpf/users/$USER/ -directory are intended to be used when non-default rules -are needed on an individual user basis. -It is important to ensure that a user can not write or change -these configuration files. -.Pp -The -.Pa authpf.rules -file must exist in one of the above locations for -.Nm -to run. -.Sh CONFIGURATION -Options are controlled by the -.Pa /etc/authpf/authpf.conf -file. -If the file is empty, defaults are used for all -configuration options. -The file consists of pairs of the form -.Li name=value , -one per line. -Currently, the allowed values are as follows: -.Bl -tag -width Ds -.It anchor=name -Use the specified -.Pa anchor -name instead of "authpf". -.It table=name -Use the specified -.Pa table -name instead of "authpf_users". -.El -.Sh USER MESSAGES -On successful invocation, -.Nm -displays a message telling the user he or she has been authenticated. -It will additionally display the contents of the file -.Pa /etc/authpf/authpf.message -if the file exists and is readable. -.Pp -There exist two methods for providing additional granularity to the control -offered by -.Nm -- it is possible to set the gateway to explicitly allow users who have -authenticated to -.Xr ssh 1 -and deny access to only a few troublesome individuals. -This is done by creating a file with the banned user's login name as the -filename in -.Pa /etc/authpf/banned/ . -The contents of this file will be displayed to a banned user, thus providing -a method for informing the user that they have been banned, and where they can -go and how to get there if they want to have their service restored. -This is the default behaviour. -.Pp -It is also possible to configure -.Nm -to only allow specific users access. -This is done by listing their login names, one per line, in -.Pa /etc/authpf/authpf.allow . -If "*" is found on a line, then all usernames match. -If -.Nm -is unable to verify the user's permission to use the gateway, it will -print a brief message and die. -It should be noted that a ban takes precedence over an allow. -.Pp -On failure, messages will be logged to -.Xr syslogd 8 -for the system administrator. -The user does not see these, but will be told the system is unavailable due to -technical difficulties. -The contents of the file -.Pa /etc/authpf/authpf.problem -will also be displayed if the file exists and is readable. -.Sh CONFIGURATION ISSUES -.Nm -maintains the changed filter rules as long as the user maintains an -active session. -It is important to remember however, that the existence -of this session means the user is authenticated. -Because of this, it is important to configure -.Xr sshd 8 -to ensure the security of the session, and to ensure that the network -through which users connect is secure. -.Xr sshd 8 -should be configured to use the -.Ar ClientAliveInterval -and -.Ar ClientAliveCountMax -parameters to ensure that a ssh session is terminated quickly if -it becomes unresponsive, or if arp or address spoofing is used to -hijack the session. -Note that TCP keepalives are not sufficient for -this, since they are not secure. -Also note that the various SSH tunnelling mechanisms, -such as -.Ar AllowTcpForwarding -and -.Ar PermitTunnel , -should be disabled for -.Nm -users to prevent them from circumventing restrictions imposed by the -packet filter ruleset. -.Pp -.Nm -will remove state table entries that were created during a user's -session. -This ensures that there will be no unauthenticated traffic -allowed to pass after the controlling -.Xr ssh 1 -session has been closed. -.Pp -.Nm -is designed for gateway machines which typically do not have regular -(non-administrative) users using the machine. -An administrator must remember that -.Nm -can be used to modify the filter rules through the environment in -which it is run, and as such could be used to modify the filter rules -(based on the contents of the configuration files) by regular -users. -In the case where a machine has regular users using it, as well -as users with -.Nm -as their shell, the regular users should be prevented from running -.Nm -by using the -.Pa /etc/authpf/authpf.allow -or -.Pa /etc/authpf/banned/ -facilities. -.Pp -.Nm -modifies the packet filter and address translation rules, and because -of this it needs to be configured carefully. -.Nm -will not run and will exit silently if the -.Pa /etc/authpf/authpf.conf -file does not exist. -After considering the effect -.Nm -may have on the main packet filter rules, the system administrator may -enable -.Nm -by creating an appropriate -.Pa /etc/authpf/authpf.conf -file. -.Sh EXAMPLES -.Sy Control Files -\- To illustrate the user-specific access control -mechanisms, let us consider a typical user named bob. -Normally, as long as bob can authenticate himself, the -.Nm -program will load the appropriate rules. -Enter the -.Pa /etc/authpf/banned/ -directory. -If bob has somehow fallen from grace in the eyes of the -powers-that-be, they can prohibit him from using the gateway by creating -the file -.Pa /etc/authpf/banned/bob -containing a message about why he has been banned from using the network. -Once bob has done suitable penance, his access may be restored by moving or -removing the file -.Pa /etc/authpf/banned/bob . -.Pp -Now consider a workgroup containing alice, bob, carol and dave. -They have a -wireless network which they would like to protect from unauthorized use. -To accomplish this, they create the file -.Pa /etc/authpf/authpf.allow -which lists their login ids, one per line. -At this point, even if eve could authenticate to -.Xr sshd 8 , -she would not be allowed to use the gateway. -Adding and removing users from -the work group is a simple matter of maintaining a list of allowed userids. -If bob once again manages to annoy the powers-that-be, they can ban him from -using the gateway by creating the familiar -.Pa /etc/authpf/banned/bob -file. -Though bob is listed in the allow file, he is prevented from using -this gateway due to the existence of a ban file. -.Pp -.Sy Distributed Authentication -\- It is often desirable to interface with a -distributed password system rather than forcing the sysadmins to keep a large -number of local password files in sync. -The -.Xr login.conf 5 -mechanism in -.Ox -can be used to fork the right shell. -To make that happen, -.Xr login.conf 5 -should have entries that look something like this: -.Bd -literal -offset indent -shell-default:shell=/bin/csh - -default:\e - ... - :shell=/usr/sbin/authpf - -daemon:\e - ... - :shell=/bin/csh:\e - :tc=default: - -staff:\e - ... - :shell=/bin/csh:\e - :tc=default: -.Ed -.Pp -Using a default password file, all users will get -.Nm -as their shell except for root who will get -.Pa /bin/csh . -.Pp -.Sy SSH Configuration -\- As stated earlier, -.Xr sshd 8 -must be properly configured to detect and defeat network attacks. -To that end, the following options should be added to -.Xr sshd_config 5 : -.Bd -literal -offset indent -Protocol 2 -ClientAliveInterval 15 -ClientAliveCountMax 3 -.Ed -.Pp -This ensures that unresponsive or spoofed sessions are terminated within a -minute, since a hijacker should not be able to spoof ssh keepalive messages. -.Pp -.Sy Banners -\- Once authenticated, the user is shown the contents of -.Pa /etc/authpf/authpf.message . -This message may be a screen-full of the appropriate use policy, the contents -of -.Pa /etc/motd -or something as simple as the following: -.Bd -literal -offset indent -This means you will be held accountable by the powers that be -for traffic originating from your machine, so please play nice. -.Ed -.Pp -To tell the user where to go when the system is broken, -.Pa /etc/authpf/authpf.problem -could contain something like this: -.Bd -literal -offset indent -Sorry, there appears to be some system problem. To report this -problem so we can fix it, please phone 1-900-314-1597 or send -an email to remove@bulkmailerz.net. -.Ed -.Pp -.Sy Packet Filter Rules -\- In areas where this gateway is used to protect a -wireless network (a hub with several hundred ports), the default rule set as -well as the per-user rules should probably allow very few things beyond -encrypted protocols like -.Xr ssh 1 , -.Xr ssl 8 , -or -.Xr ipsec 4 . -On a securely switched network, with plug-in jacks for visitors who are -given authentication accounts, you might want to allow out everything. -In this context, a secure switch is one that tries to prevent address table -overflow attacks. -.Pp -Example -.Pa /etc/pf.conf : -.Bd -literal -# by default we allow internal clients to talk to us using -# ssh and use us as a dns server. -internal_if="fxp1" -gateway_addr="10.0.1.1" -nat-anchor "authpf/*" -rdr-anchor "authpf/*" -binat-anchor "authpf/*" -block in on $internal_if from any to any -pass in quick on $internal_if proto tcp from any to $gateway_addr \e - port = ssh -pass in quick on $internal_if proto udp from any to $gateway_addr \e - port = domain -anchor "authpf/*" -.Ed -.Pp -.Sy For a switched, wired net -\- This example -.Pa /etc/authpf/authpf.rules -makes no real restrictions; it turns the IP address on and off, logging -TCP connections. -.Bd -literal -external_if = "xl0" -internal_if = "fxp0" - -pass in log quick on $internal_if proto tcp from $user_ip to any -pass in quick on $internal_if from $user_ip to any -.Ed -.Pp -.Sy For a wireless or shared net -\- This example -.Pa /etc/authpf/authpf.rules -could be used for an insecure network (such as a public wireless network) where -we might need to be a bit more restrictive. -.Bd -literal -internal_if="fxp1" -ipsec_gw="10.2.3.4" - -# rdr ftp for proxying by ftp-proxy(8) -rdr on $internal_if proto tcp from $user_ip to any port 21 \e - -> 127.0.0.1 port 8021 - -# allow out ftp, ssh, www and https only, and allow user to negotiate -# ipsec with the ipsec server. -pass in log quick on $internal_if proto tcp from $user_ip to any \e - port { 21, 22, 80, 443 } -pass in quick on $internal_if proto tcp from $user_ip to any \e - port { 21, 22, 80, 443 } -pass in quick proto udp from $user_ip to $ipsec_gw port = isakmp -pass in quick proto esp from $user_ip to $ipsec_gw -.Ed -.Pp -.Sy Dealing with NAT -\- The following -.Pa /etc/authpf/authpf.rules -shows how to deal with NAT, using tags: -.Bd -literal -ext_if = "fxp1" -ext_addr = 129.128.11.10 -int_if = "fxp0" -# nat and tag connections... -nat on $ext_if from $user_ip to any tag $user_ip -> $ext_addr -pass in quick on $int_if from $user_ip to any -pass out log quick on $ext_if tagged $user_ip -.Ed -.Pp -With the above rules added by -.Nm , -outbound connections corresponding to each users NAT'ed connections -will be logged as in the example below, where the user may be identified -from the ruleset name. -.Bd -literal -# tcpdump -n -e -ttt -i pflog0 -Oct 31 19:42:30.296553 rule 0.bbeck(20267).1/0(match): pass out on fxp1: \e -129.128.11.10.60539 > 198.137.240.92.22: S 2131494121:2131494121(0) win \e -16384 <mss 1460,nop,nop,sackOK> (DF) -.Ed -.Pp -.Sy Using the authpf_users table -\- Simple -.Nm -settings can be implemented without an anchor by just using the "authpf_users" -.Pa table . -For example, the following -.Xr pf.conf 5 -lines will give SMTP and IMAP access to logged in users: -.Bd -literal -table <authpf_users> persist -pass in on $ext_if proto tcp from <authpf_users> \e - to port { smtp imap } -.Ed -.Pp -It is also possible to use the "authpf_users" -.Pa table -in combination with anchors. -For example, -.Xr pf 4 -processing can be sped up by looking up the anchor -only for packets coming from logged in users: -.Bd -literal -table <authpf_users> persist -anchor "authpf/*" from <authpf_users> -rdr-anchor "authpf/*" from <authpf_users> -.Ed -.Sh FILES -.Bl -tag -width "/etc/authpf/authpf.conf" -compact -.It Pa /etc/authpf/authpf.conf -.It Pa /etc/authpf/authpf.allow -.It Pa /etc/authpf/authpf.rules -.It Pa /etc/authpf/authpf.message -.It Pa /etc/authpf/authpf.problem -.El -.Sh SEE ALSO -.Xr pf 4 , -.Xr pf.conf 5 , -.Xr securelevel 7 , -.Xr ftp-proxy 8 -.Sh HISTORY -The -.Nm -program first appeared in -.Ox 3.1 . -.Sh BUGS -Configuration issues are tricky. -The authenticating -.Xr ssh 1 -connection may be secured, but if the network is not secured the user may -expose insecure protocols to attackers on the same network, or enable other -attackers on the network to pretend to be the user by spoofing their IP -address. -.Pp -.Nm -is not designed to prevent users from denying service to other users. diff --git a/contrib/pf/authpf/authpf.c b/contrib/pf/authpf/authpf.c deleted file mode 100644 index 68adcd258eef..000000000000 --- a/contrib/pf/authpf/authpf.c +++ /dev/null @@ -1,830 +0,0 @@ -/* $OpenBSD: authpf.c,v 1.104 2007/02/24 17:35:08 beck Exp $ */ - -/* - * Copyright (C) 1998 - 2007 Bob Beck (beck@openbsd.org). - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/types.h> -#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> -#include <arpa/inet.h> - -#include <err.h> -#include <errno.h> -#include <login_cap.h> -#include <pwd.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> - -#include "pathnames.h" - -static int read_config(FILE *); -static void print_message(char *); -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 *); -static void authpf_kill_states(void); - -int dev; /* pf device */ -char anchorname[PF_ANCHOR_NAME_SIZE] = "authpf"; -char rulesetname[MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 2]; -char tablename[PF_TABLE_NAME_SIZE] = "authpf_users"; - -FILE *pidfp; -char luser[MAXLOGNAME]; /* username */ -char ipsrc[256]; /* ip as a string */ -char pidfile[MAXPATHLEN]; /* we save pid in this file. */ - -struct timeval Tstart, Tend; /* start and end times of session */ - -volatile sig_atomic_t want_death; -static void need_death(int signo); -static __dead void do_death(int); - -/* - * User shell for authenticating gateways. Sole purpose is to allow - * a user to ssh to a gateway, and have the gateway modify packet - * filters to allow access, then remove access when the user finishes - * up. Meant to be used only from ssh(1) connections. - */ -int -main(int argc, char *argv[]) -{ - int lockcnt = 0, n, pidfd; - FILE *config; - struct in6_addr ina; - struct passwd *pw; - char *cp; - gid_t gid; - uid_t uid; - char *shell; - login_cap_t *lc; - - config = fopen(PATH_CONFFILE, "r"); - if (config == NULL) { - syslog(LOG_ERR, "can not open %s (%m)", PATH_CONFFILE); - exit(1); - } - - if ((cp = getenv("SSH_TTY")) == NULL) { - syslog(LOG_ERR, "non-interactive session connection for authpf"); - exit(1); - } - - if ((cp = getenv("SSH_CLIENT")) == NULL) { - syslog(LOG_ERR, "cannot determine connection source"); - exit(1); - } - - if (strlcpy(ipsrc, cp, sizeof(ipsrc)) >= sizeof(ipsrc)) { - syslog(LOG_ERR, "SSH_CLIENT variable too long"); - exit(1); - } - cp = strchr(ipsrc, ' '); - if (!cp) { - syslog(LOG_ERR, "corrupt SSH_CLIENT variable %s", ipsrc); - exit(1); - } - *cp = '\0'; - 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); - } - /* open the pf device */ - dev = open(PATH_DEVFILE, O_RDWR); - if (dev == -1) { - syslog(LOG_ERR, "cannot open packet filter device (%m)"); - goto die; - } - - uid = getuid(); - pw = getpwuid(uid); - if (pw == NULL) { - syslog(LOG_ERR, "cannot find user for uid %u", uid); - goto die; - } - - 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. - */ - if (strlcpy(luser, pw->pw_name, sizeof(luser)) >= sizeof(luser)) { - syslog(LOG_ERR, "username too long: %s", pw->pw_name); - goto die; - } - - if ((n = snprintf(rulesetname, sizeof(rulesetname), "%s(%ld)", - 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 || (u_int)n >= sizeof(rulesetname)) { - syslog(LOG_ERR, "pid too large for ruleset name"); - goto die; - } - } - - - /* Make our entry in /var/authpf as /var/authpf/ipaddr */ - n = snprintf(pidfile, sizeof(pidfile), "%s/%s", PATH_PIDFILE, ipsrc); - if (n < 0 || (u_int)n >= sizeof(pidfile)) { - syslog(LOG_ERR, "path to pidfile too long"); - goto die; - } - - /* - * If someone else is already using this ip, then this person - * wants to switch users - so kill the old process and exit - * as well. - * - * Note, we could print a message and tell them to log out, but the - * usual case of this is that someone has left themselves logged in, - * with the authenticated connection iconized and someone else walks - * up to use and automatically logs in before using. If this just - * gets rid of the old one silently, the new user never knows they - * could have used someone else's old authentication. If we - * tell them to log out before switching users it is an invitation - * for abuse. - */ - - do { - int save_errno, otherpid = -1; - char otherluser[MAXLOGNAME]; - - if ((pidfd = open(pidfile, O_RDWR|O_CREAT, 0644)) == -1 || - (pidfp = fdopen(pidfd, "r+")) == NULL) { - if (pidfd != -1) - close(pidfd); - syslog(LOG_ERR, "cannot open or create %s: %s", pidfile, - strerror(errno)); - goto die; - } - - if (flock(fileno(pidfp), LOCK_EX|LOCK_NB) == 0) - break; - save_errno = errno; - - /* Mark our pid, and username to our file. */ - - rewind(pidfp); - /* 31 == MAXLOGNAME - 1 */ - if (fscanf(pidfp, "%d\n%31s\n", &otherpid, otherluser) != 2) - otherpid = -1; - syslog(LOG_DEBUG, "tried to lock %s, in use by pid %d: %s", - pidfile, otherpid, strerror(save_errno)); - - if (otherpid > 0) { - syslog(LOG_INFO, - "killing prior auth (pid %d) of %s by user %s", - otherpid, ipsrc, otherluser); - if (kill((pid_t) otherpid, SIGTERM) == -1) { - syslog(LOG_INFO, - "could not kill process %d: (%m)", - otherpid); - } - } - - /* - * we try to kill the previous process and acquire the lock - * for 10 seconds, trying once a second. if we can't after - * 10 attempts we log an error and give up - */ - if (++lockcnt > 10) { - syslog(LOG_ERR, "cannot kill previous authpf (pid %d)", - otherpid); - fclose(pidfp); - pidfp = NULL; - goto dogdeath; - } - sleep(1); - - /* re-open, and try again. The previous authpf process - * we killed above should unlink the file and release - * it's lock, giving us a chance to get it now - */ - fclose(pidfp); - pidfp = NULL; - } while (1); - - /* whack the group list */ - gid = getegid(); - if (setgroups(1, &gid) == -1) { - syslog(LOG_INFO, "setgroups: %s", strerror(errno)); - do_death(0); - } - - /* revoke privs */ - uid = getuid(); - if (setresuid(uid, uid, uid) == -1) { - syslog(LOG_INFO, "setresuid: %s", strerror(errno)); - do_death(0); - } - openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON); - - if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser)) { - syslog(LOG_INFO, "user %s prohibited", luser); - do_death(0); - } - - if (read_config(config)) { - syslog(LOG_ERR, "invalid config file %s", PATH_CONFFILE); - do_death(0); - } - - if (remove_stale_rulesets()) { - syslog(LOG_INFO, "error removing stale rulesets"); - do_death(0); - } - - /* We appear to be making headway, so actually mark our pid */ - rewind(pidfp); - fprintf(pidfp, "%ld\n%s\n", (long)getpid(), luser); - fflush(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, 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); - signal(SIGALRM, need_death); - signal(SIGPIPE, need_death); - signal(SIGHUP, need_death); - signal(SIGQUIT, need_death); - signal(SIGTSTP, need_death); - while (1) { - printf("\r\nHello %s. ", luser); - printf("You are authenticated from host \"%s\"\r\n", ipsrc); - setproctitle("%s@%s", luser, ipsrc); - print_message(PATH_MESSAGE); - while (1) { - sleep(10); - if (want_death) - do_death(1); - } - } - - /* NOTREACHED */ -dogdeath: - printf("\r\n\r\nSorry, this service is currently unavailable due to "); - printf("technical difficulties\r\n\r\n"); - print_message(PATH_PROBLEM); - printf("\r\nYour authentication process (pid %ld) was unable to run\n", - (long)getpid()); - sleep(180); /* them lusers read reaaaaal slow */ -die: - do_death(0); -} - -/* - * reads config file in PATH_CONFFILE to set optional behaviours up - */ -static int -read_config(FILE *f) -{ - char buf[1024]; - int i = 0; - - do { - char **ap; - char *pair[4], *cp, *tp; - int len; - - if (fgets(buf, sizeof(buf), f) == NULL) { - fclose(f); - return (0); - } - i++; - len = strlen(buf); - if (buf[len - 1] != '\n' && !feof(f)) { - syslog(LOG_ERR, "line %d too long in %s", i, - PATH_CONFFILE); - return (1); - } - buf[len - 1] = '\0'; - - for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) - ; /* nothing */ - - if (!*cp || *cp == '#' || *cp == '\n') - continue; - - for (ap = pair; ap < &pair[3] && - (*ap = strsep(&cp, "=")) != NULL; ) { - if (**ap != '\0') - ap++; - } - if (ap != &pair[2]) - goto parse_error; - - tp = pair[1] + strlen(pair[1]); - while ((*tp == ' ' || *tp == '\t') && tp >= pair[1]) - *tp-- = '\0'; - - if (strcasecmp(pair[0], "anchor") == 0) { - if (!pair[1][0] || strlcpy(anchorname, pair[1], - 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); - -parse_error: - fclose(f); - syslog(LOG_ERR, "parse error, line %d of %s", i, PATH_CONFFILE); - return (1); -} - - -/* - * splatter a file to stdout - max line length of 1024, - * used for spitting message files at users to tell them - * they've been bad or we're unavailable. - */ -static void -print_message(char *filename) -{ - char buf[1024]; - FILE *f; - - if ((f = fopen(filename, "r")) == NULL) - return; /* fail silently, we don't care if it isn't there */ - - do { - if (fgets(buf, sizeof(buf), f) == NULL) { - fflush(stdout); - fclose(f); - return; - } - } while (fputs(buf, stdout) != EOF && !feof(f)); - fflush(stdout); - fclose(f); -} - -/* - * allowed_luser checks to see if user "luser" is allowed to - * use this gateway by virtue of being listed in an allowed - * users file, namely /etc/authpf/authpf.allow . - * - * If /etc/authpf/authpf.allow does not exist, then we assume that - * all users who are allowed in by sshd(8) are permitted to - * use this gateway. If /etc/authpf/authpf.allow does exist, then a - * user must be listed if the connection is to continue, else - * the session terminates in the same manner as being banned. - */ -static int -allowed_luser(char *luser) -{ - char *buf, *lbuf; - int matched; - size_t len; - FILE *f; - - if ((f = fopen(PATH_ALLOWFILE, "r")) == NULL) { - if (errno == ENOENT) { - /* - * allowfile doesn't exist, thus this gateway - * isn't restricted to certain users... - */ - return (1); - } - - /* - * luser may in fact be allowed, but we can't open - * the file even though it's there. probably a config - * problem. - */ - syslog(LOG_ERR, "cannot open allowed users file %s (%s)", - PATH_ALLOWFILE, strerror(errno)); - return (0); - } else { - /* - * /etc/authpf/authpf.allow exists, thus we do a linear - * search to see if they are allowed. - * also, if username "*" exists, then this is a - * "public" gateway, such as it is, so let - * everyone use it. - */ - lbuf = NULL; - while ((buf = fgetln(f, &len))) { - if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; - else { - if ((lbuf = (char *)malloc(len + 1)) == NULL) - err(1, NULL); - memcpy(lbuf, buf, len); - lbuf[len] = '\0'; - buf = lbuf; - } - - matched = strcmp(luser, buf) == 0 || strcmp("*", buf) == 0; - - if (lbuf != NULL) { - free(lbuf); - lbuf = NULL; - } - - if (matched) - return (1); /* matched an allowed username */ - } - syslog(LOG_INFO, "denied access to %s: not listed in %s", - luser, PATH_ALLOWFILE); - - /* reuse buf */ - buf = "\n\nSorry, you are not allowed to use this facility!\n"; - fputs(buf, stdout); - } - fflush(stdout); - return (0); -} - -/* - * check_luser checks to see if user "luser" has been banned - * from using us by virtue of having an file of the same name - * in the "luserdir" directory. - * - * If the user has been banned, we copy the contents of the file - * to the user's screen. (useful for telling the user what to - * do to get un-banned, or just to tell them they aren't - * going to be un-banned.) - */ -static int -check_luser(char *luserdir, char *luser) -{ - FILE *f; - int n; - char tmp[MAXPATHLEN]; - - n = snprintf(tmp, sizeof(tmp), "%s/%s", luserdir, luser); - if (n < 0 || (u_int)n >= sizeof(tmp)) { - syslog(LOG_ERR, "provided banned directory line too long (%s)", - luserdir); - return (0); - } - if ((f = fopen(tmp, "r")) == NULL) { - if (errno == ENOENT) { - /* - * file or dir doesn't exist, so therefore - * this luser isn't banned.. all is well - */ - return (1); - } else { - /* - * luser may in fact be banned, but we can't open the - * file even though it's there. probably a config - * problem. - */ - syslog(LOG_ERR, "cannot open banned file %s (%s)", - tmp, strerror(errno)); - return (0); - } - } else { - /* - * luser is banned - spit the file at them to - * tell what they can do and where they can go. - */ - syslog(LOG_INFO, "denied access to %s: %s exists", - luser, tmp); - - /* reuse tmp */ - strlcpy(tmp, "\n\n-**- Sorry, you have been banned! -**-\n\n", - sizeof(tmp)); - while (fputs(tmp, stdout) != EOF && !feof(f)) { - if (fgets(tmp, sizeof(tmp), f) == NULL) { - fflush(stdout); - fclose(f); - return (0); - } - } - fclose(f); - } - fflush(stdout); - return (0); -} - -/* - * Search for rulesets left by other authpf processes (either because they - * died ungracefully or were terminated) and remove them. - */ -static int -remove_stale_rulesets(void) -{ - struct pfioc_ruleset prs; - u_int32_t nr, mnr; - - memset(&prs, 0, sizeof(prs)); - strlcpy(prs.path, anchorname, sizeof(prs.path)); - if (ioctl(dev, DIOCGETRULESETS, &prs)) { - if (errno == EINVAL) - return (0); - else - return (1); - } - - mnr = prs.nr; - nr = 0; - while (nr < mnr) { - char *s, *t; - pid_t pid; - - prs.nr = nr; - if (ioctl(dev, DIOCGETRULESET, &prs)) - return (1); - errno = 0; - if ((t = strchr(prs.name, '(')) == NULL) - t = prs.name; - else - t++; - pid = strtoul(t, &s, 10); - if (!prs.name[0] || errno || - (*s && (t == prs.name || *s != ')'))) - return (1); - if (kill(pid, 0) && errno != EPERM) { - 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++; - } - return (0); -} - -/* - * Add/remove filter entries for user "luser" from ip "ipsrc" - */ -static int -change_filter(int add, const char *luser, const char *ipsrc) -{ - 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; - gid_t gid; - int s; - - if (luser == NULL || !luser[0] || ipsrc == NULL || !ipsrc[0]) { - syslog(LOG_ERR, "invalid luser/ipsrc"); - 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) { - 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; - } - } - 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: - syslog(LOG_ERR, "fork failed"); - goto error; - case 0: - /* revoke group privs before exec */ - gid = getgid(); - if (setregid(gid, gid) == -1) { - err(1, "setregid"); - } - execvp(PATH_PFCTL, pargv); - warn("exec of %s failed", PATH_PFCTL); - _exit(1); - } - - /* parent */ - waitpid(pid, &s, 0); - if (s != 0) { - syslog(LOG_ERR, "pfctl exited abnormally"); - goto error; - } - - if (add) { - gettimeofday(&Tstart, NULL); - syslog(LOG_INFO, "allowing %s, user %s", ipsrc, luser); - } else { - gettimeofday(&Tend, NULL); - syslog(LOG_INFO, "removed %s, user %s - duration %ld seconds", - ipsrc, luser, Tend.tv_sec - Tstart.tv_sec); - } - return (0); -no_mem: - syslog(LOG_ERR, "malloc failed"); -error: - free(fdpath); - free(rsn); - free(userstr); - free(ipstr); - free(fn); - return (-1); -} - -/* - * Add/remove this IP from the "authpf_users" table. - */ -static int -change_table(int add, 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.pfrt_name)); - 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 - * longer than their ssh session. This function is based on - * pfctl_kill_states from pfctl. - */ -static void -authpf_kill_states(void) -{ - struct pfioc_state_kill psk; - struct pf_addr target; - - memset(&psk, 0, sizeof(psk)); - memset(&target, 0, sizeof(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 */ - 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 */ - memset(&psk.psk_src, 0, sizeof(psk.psk_src)); - 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)) - syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)"); -} - -/* signal handler that makes us go away properly */ -static void -need_death(int signo) -{ - want_death = 1; -} - -/* - * function that removes our stuff when we go away. - */ -static __dead void -do_death(int active) -{ - int ret = 0; - - if (active) { - change_filter(0, luser, ipsrc); - change_table(0, ipsrc); - authpf_kill_states(); - remove_stale_rulesets(); - } - if (pidfile[0] && (pidfp != NULL)) - if (unlink(pidfile) == -1) - syslog(LOG_ERR, "cannot unlink %s (%m)", pidfile); - exit(ret); -} diff --git a/contrib/pf/authpf/pathnames.h b/contrib/pf/authpf/pathnames.h deleted file mode 100644 index 358bfd0c106d..000000000000 --- a/contrib/pf/authpf/pathnames.h +++ /dev/null @@ -1,38 +0,0 @@ -/* $OpenBSD: pathnames.h,v 1.7 2004/04/25 18:40:42 beck Exp $ */ - -/* - * Copyright (C) 2002 Chris Kuethe (ckuethe@ualberta.ca) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#define PATH_CONFFILE "/etc/authpf/authpf.conf" -#define PATH_ALLOWFILE "/etc/authpf/authpf.allow" -#define PATH_PFRULES "/etc/authpf/authpf.rules" -#define PATH_PROBLEM "/etc/authpf/authpf.problem" -#define PATH_MESSAGE "/etc/authpf/authpf.message" -#define PATH_USER_DIR "/etc/authpf/users" -#define PATH_BAN_DIR "/etc/authpf/banned" -#define PATH_DEVFILE "/dev/pf" -#define PATH_PIDFILE "/var/authpf" -#define PATH_AUTHPF_SHELL "/usr/sbin/authpf" -#define PATH_PFCTL "/sbin/pfctl" |