summaryrefslogtreecommitdiff
path: root/usr.sbin/authpf/authpf.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/authpf/authpf.c')
-rw-r--r--usr.sbin/authpf/authpf.c96
1 files changed, 77 insertions, 19 deletions
diff --git a/usr.sbin/authpf/authpf.c b/usr.sbin/authpf/authpf.c
index 4b8fafefa59..6c8d0547d0a 100644
--- a/usr.sbin/authpf/authpf.c
+++ b/usr.sbin/authpf/authpf.c
@@ -45,6 +45,8 @@
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <libgen.h>
+#include <login_cap.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
@@ -90,6 +92,7 @@ static int changefilter(int, char *, char *);
static void authpf_kill_states(void);
static void terminator(int s);
static __dead void go_away(void);
+static int secure_fullpath(char *);
/*
* authpf:
@@ -296,6 +299,10 @@ read_config(void)
if (f == NULL)
exit(1); /* exit silently if we have no config file */
+ if (secure_fullpath(configfile) != 0)
+ /* config file exists, but is not secure */
+ exit(1);
+
openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON);
do {
@@ -600,17 +607,22 @@ changefilter(int add, char *luser, char *ipsrc)
if (unlink(template) == -1)
syslog(LOG_ERR, "can't unlink %s", template);
goto error;
- }
+ }
}
- snprintf(rulesfile, sizeof rulesfile, PATH_PFRULES);
- if (from_fd == -1 &&
- (from_fd = open(rulesfile, O_RDONLY, 0)) == -1) {
- syslog(LOG_ERR, "can't open %s (%m)", rulesfile);
- if (unlink(template) == -1)
- syslog(LOG_ERR, "can't unlink %s", template);
- goto error;
+ if (from_fd == -1) {
+ snprintf(rulesfile, sizeof rulesfile, PATH_PFRULES);
+ if ((from_fd = open(rulesfile, O_RDONLY, 0)) == -1) {
+ syslog(LOG_ERR, "can't open %s (%m)", rulesfile);
+ if (unlink(template) == -1)
+ syslog(LOG_ERR, "can't unlink %s", template);
+ goto error;
+ }
}
+ if (secure_fullpath(rulesfile) != 0)
+ /* rules file exists, but is not secure */
+ goto error;
+
while ((rcount = read(from_fd, buf, sizeof(buf))) > 0) {
wcount = write(tmpfile, buf, rcount);
if (rcount != wcount || wcount == -1) {
@@ -660,7 +672,6 @@ changefilter(int add, char *luser, char *ipsrc)
}
/* now, for NAT, if we have some */
-
if ((cp = getenv("HOME")) == NULL) {
syslog(LOG_ERR, "No Home Directory!");
goto error;
@@ -679,18 +690,24 @@ changefilter(int add, char *luser, char *ipsrc)
goto error;
}
}
- snprintf(natfile, sizeof natfile, PATH_NATRULES);
- if (from_fd == -1 &&
- (from_fd = open(natfile, O_RDONLY, 0)) == -1) {
- if (errno == ENOENT)
- goto out; /* NAT is optional */
- else {
- syslog(LOG_ERR, "can't open %s (%m)", natfile);
- if (unlink(template) == -1)
- syslog(LOG_ERR, "can't unlink %s", template);
- goto error;
+ if (from_fd == -1) {
+ snprintf(natfile, sizeof natfile, PATH_NATRULES);
+ if ((from_fd = open(natfile, O_RDONLY, 0)) == -1) {
+ if (errno == ENOENT)
+ goto out; /* NAT is optional */
+ else {
+ syslog(LOG_ERR, "can't open %s (%m)", natfile);
+ if (unlink(template) == -1)
+ syslog(LOG_ERR, "can't unlink %s",
+ template);
+ goto error;
+ }
}
}
+ if (from_fd != -1 && secure_fullpath(natfile) != 0)
+ /* nat file exists, but is not secure */
+ goto error;
+
tmpfile = mkstemp(template2);
if (tmpfile == -1) {
syslog(LOG_ERR, "Can't open temp file %s (%m)",
@@ -838,6 +855,47 @@ go_away(void)
}
/*
+ * secure_fullpath:
+ * akin to secure_path, but for a directory - needed to ensure
+ * users can't get something they aren't supposed to by moveing
+ * files aside or linking other directories, such as the default
+ * one.
+ */
+static int
+secure_fullpath(char *path)
+{
+ struct stat sb;
+ char *cp;
+
+ if (secure_path(path) < 0)
+ return(-1);
+
+ cp = path;
+
+ do {
+ cp = dirname(cp);
+ memset(&sb, 0, sizeof(sb));
+ /*
+ * if it's owned or writable by someone
+ * other than root, it's bad. since these are directories,
+ * not the end path, they are allowed to be symbolic links
+ * and other such things (unlike the file itself).
+ */
+ if (lstat(cp, &sb) < 0) {
+ syslog(LOG_ERR, "cannot stat %s: %m", cp);
+ return (-1);
+ } else if (sb.st_uid != 0) {
+ syslog(LOG_ERR, "%s: not owned by root", cp);
+ return (-1);
+ } else if (sb.st_mode & (S_IWGRP | S_IWOTH)) {
+ syslog(LOG_ERR, "%s: writeable by non-root", cp);
+ return (-1);
+ }
+ } while (strlen(cp) > 1);
+ return (0);
+}
+
+/*
* pfctl_add_rules:
* callback for rule add, used by parser in parse_rules
*/