From f2755afbac8ee4439e0fef1ac6939e37652b8fc1 Mon Sep 17 00:00:00 2001
From: Grzegorz Nosek <root@localdomain.pl>
Date: Sat, 10 Mar 2007 16:18:53 +0100
Subject: Improved CGI permission logic  Symlinks are now allowed if owner
 matches

---
 fcgiwrap.c | 46 +++++++++++++++++++++++++++++++++++++---------
 1 file changed, 37 insertions(+), 9 deletions(-)

diff --git a/fcgiwrap.c b/fcgiwrap.c
index 577b13c..5e9b4fe 100644
--- a/fcgiwrap.c
+++ b/fcgiwrap.c
@@ -71,12 +71,41 @@ static void fcgi_pass(int fd_stdin, int fd_stdout, int fd_stderr)
 	}
 }
 
+int check_file_perms(const char *path)
+{
+	struct stat ls;
+	struct stat fs;
+
+	if (lstat(path, &ls) < 0) {
+		return -ENOENT;
+	} else if (S_ISREG(ls.st_mode)) {
+		if (ls.st_mode & S_IXUSR) {
+			return 0;
+		} else {
+			return -EACCES;
+		}
+	} else if (!S_ISLNK(ls.st_mode)) {
+		return -EACCES;
+	}
+
+	if (stat(path, &fs) < 0) {
+		return -ENOENT;
+	} else if (S_ISREG(fs.st_mode)) {
+		if (fs.st_mode & S_IXUSR) {
+			return 0;
+		} else {
+			return -EACCES;
+		}
+	} else {
+		return -EACCES;
+	}
+}
+
 char *get_cgi_filename()
 {
 	int buflen = 1, docrootlen;
 	char *buf;
 	char *docroot, *scriptname, *p;
-	struct stat s;
 
 	if ((p = getenv("DOCUMENT_ROOT"))) {
 		docroot = p;
@@ -99,15 +128,14 @@ char *get_cgi_filename()
 	strcpy(buf + docrootlen, scriptname);
 
 	while(1) {
-		if (lstat(buf, &s) == 0) {
-			if (!S_ISREG(s.st_mode) || ((s.st_mode & S_IXOTH) == 0))
-				return NULL; /* 403 */
-
-			return buf;
+		switch(check_file_perms(buf)) {
+			case -EACCES: return NULL;
+			case 0: return buf;
+			default:
+				p = strrchr(buf, '/');
+				if (!p) return NULL;
+				*p = 0;
 		}
-		p = strrchr(buf, '/');
-		if (!p) break;
-			*p = 0;
 	}
 
 	return NULL;
-- 
cgit v1.2.3