--- /dev/null
+/*
+ suPHP - (c)2002-2008 Sebastian Marsching <sebastian@marsching.com>
+
+ This file is part of suPHP.
+
+ suPHP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ suPHP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with suPHP; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "PathMatcher.hpp"
+#include "Util.hpp"
+
+using namespace suPHP;
+
+suPHP::PathMatcher::PathMatcher(const UserInfo& user, const GroupInfo& group) {
+ this->user = user;
+ this->group = group;
+}
+
+bool suPHP::PathMatcher::matches(std::string pattern, std::string path)
+ throw (KeyNotFoundException, ParsingException) {
+ std::string remainingPath = path;
+ std::string remainingPattern = pattern;
+
+ while (remainingPath.length() > 0 && remainingPattern.length() > 0) {
+ bool escapeNext = false;
+ for (int i = 0; i < remainingPattern.length(); i++) {
+ char c = remainingPattern.at(i);
+ if (escapeNext) {
+ escapeNext = false;
+ if (c == '\\' || c == '*' || c == '$') {
+ // Backslash was used as an escape character
+ if (remainingPath.at(i-1) == c) {
+ remainingPattern = remainingPattern.substr(i + 1);
+ remainingPath = remainingPath.substr(i);
+ break;
+ } else {
+ return false;
+ }
+ } else {
+ if (remainingPath.at(i-1) == '\\') {
+ remainingPattern = remainingPattern.substr(i);
+ remainingPath = remainingPath.substr(i);
+ break;
+ } else {
+ return false;
+ }
+ }
+ } else {
+ if (c == '\\') {
+ escapeNext = true;
+ } else if (c == '*') {
+ remainingPattern = remainingPattern.substr(i + 1);
+ remainingPath = remainingPath.substr(i);
+ if (matches(remainingPattern, remainingPath)) {
+ return true;
+ }
+ std::string testPrefix;
+ for (int j = 0; j < remainingPath.length(); j++) {
+ char c2 = remainingPath.at(j);
+ if (c2 == '/') {
+ return false;
+ }
+ if (c2 == '\\' || c2 == '*' || c2 == '$') {
+ testPrefix += "\\";
+ }
+ testPrefix += c2;
+ if (matches(testPrefix + remainingPattern,
+ remainingPath)) {
+ return true;
+ }
+ }
+ } else if (c == '$') {
+ if (remainingPattern.length() < i + 3) {
+ throw ParsingException("Incorrect use of $ in pattern \"" + pattern + "\".", __FILE__, __LINE__);
+ }
+ if (remainingPattern.at(i + 1) != '{') {
+ throw ParsingException("Incorrect use of $ in pattern \"" + pattern + "\".", __FILE__, __LINE__);
+ }
+ std::string::size_type closingBrace = remainingPattern.find('}', i);
+ if (closingBrace == std::string::npos) {
+ throw ParsingException("Incorrect use of $ in pattern \"" + pattern + "\".", __FILE__, __LINE__);
+ }
+ std::string varName = remainingPattern.substr(i + 2, closingBrace - i - 2);
+ remainingPattern = lookupVariable(varName) + remainingPattern.substr(closingBrace + 1);
+ break;
+ } else {
+ if (i >= remainingPath.length() || c != remainingPath.at(i)) {
+ return false;
+ }
+ if (i == remainingPattern.length() - 1) {
+ if (c == '/' || (i + 1 < remainingPath.length() && remainingPath.at(i + 1) == '/')) {
+ // Path represents file in subdirectory
+ return true;
+ } else if (remainingPath.length() == remainingPattern.length()) {
+ // Exact match
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+std::string suPHP::PathMatcher::lookupVariable(std::string str)
+ throw (KeyNotFoundException) {
+ std::string rv;
+ if (str == "USERNAME") {
+ rv = user.getUsername();
+ } else if (str == "UID") {
+ rv = Util::intToStr(user.getUid());
+ } else if (str == "HOME") {
+ rv = user.getHomeDirectory();
+ } else if (str == "GROUPNAME") {
+ rv = group.getGroupname();
+ } else if (str == "GID") {
+ rv = Util::intToStr(group.getGid());
+ } else {
+ throw KeyNotFoundException("Key \"" + str +
+ "\" does not represent a valid variable name", __FILE__, __LINE__);
+ }
+ return rv;
+}
+
+std::string suPHP::PathMatcher::resolveVariables(std::string str) throw (KeyNotFoundException, ParsingException) {
+ std::string out;
+ bool escapeNext = false;
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.at(i);
+ if (escapeNext) {
+ escapeNext = false;
+ if (c == '\\' || c == '$') {
+ // Backslash was used as an escape character
+ out += c;
+ } else {
+ out += '\\';
+ out += c;
+ }
+ } else {
+ if (c == '\\') {
+ escapeNext = true;
+ } else if (c == '$') {
+ if (str.length() < i + 3) {
+ throw ParsingException("Incorrect use of $ in string \"" + str + "\".", __FILE__, __LINE__);
+ }
+ if (str.at(i + 1) != '{') {
+ throw ParsingException("Incorrect use of $ in string \"" + str + "\".", __FILE__, __LINE__);
+ }
+ std::string::size_type closingBrace = str.find('}', i);
+ if (closingBrace == std::string::npos) {
+ throw ParsingException("Incorrect use of $ in string \"" + str + "\".", __FILE__, __LINE__);
+ }
+ std::string varName = str.substr(i + 2, closingBrace - i - 2);
+ out += lookupVariable(varName);
+ i = closingBrace + 1;
+ } else {
+ out += c;
+ }
+ }
+ }
+ return out;
+}