Release
[hcoop/zz_old/debian/suphp.git] / src / PathMatcher.cpp
CommitLineData
623e7ab4 1/*
2 suPHP - (c)2002-2008 Sebastian Marsching <sebastian@marsching.com>
3
4 This file is part of suPHP.
5
6 suPHP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 suPHP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with suPHP; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21#include "PathMatcher.hpp"
22#include "Util.hpp"
23
24using namespace suPHP;
25
26suPHP::PathMatcher::PathMatcher(const UserInfo& user, const GroupInfo& group) {
27 this->user = user;
28 this->group = group;
29}
30
31bool suPHP::PathMatcher::matches(std::string pattern, std::string path)
32 throw (KeyNotFoundException, ParsingException) {
33 std::string remainingPath = path;
34 std::string remainingPattern = pattern;
35
36 while (remainingPath.length() > 0 && remainingPattern.length() > 0) {
37 bool escapeNext = false;
38 for (int i = 0; i < remainingPattern.length(); i++) {
39 char c = remainingPattern.at(i);
40 if (escapeNext) {
41 escapeNext = false;
42 if (c == '\\' || c == '*' || c == '$') {
43 // Backslash was used as an escape character
44 if (remainingPath.at(i-1) == c) {
45 remainingPattern = remainingPattern.substr(i + 1);
46 remainingPath = remainingPath.substr(i);
47 break;
48 } else {
49 return false;
50 }
51 } else {
52 if (remainingPath.at(i-1) == '\\') {
53 remainingPattern = remainingPattern.substr(i);
54 remainingPath = remainingPath.substr(i);
55 break;
56 } else {
57 return false;
58 }
59 }
60 } else {
61 if (c == '\\') {
62 escapeNext = true;
63 } else if (c == '*') {
64 remainingPattern = remainingPattern.substr(i + 1);
65 remainingPath = remainingPath.substr(i);
66 if (matches(remainingPattern, remainingPath)) {
67 return true;
68 }
69 std::string testPrefix;
70 for (int j = 0; j < remainingPath.length(); j++) {
71 char c2 = remainingPath.at(j);
72 if (c2 == '/') {
73 return false;
74 }
75 if (c2 == '\\' || c2 == '*' || c2 == '$') {
76 testPrefix += "\\";
77 }
78 testPrefix += c2;
79 if (matches(testPrefix + remainingPattern,
80 remainingPath)) {
81 return true;
82 }
83 }
84 } else if (c == '$') {
85 if (remainingPattern.length() < i + 3) {
86 throw ParsingException("Incorrect use of $ in pattern \"" + pattern + "\".", __FILE__, __LINE__);
87 }
88 if (remainingPattern.at(i + 1) != '{') {
89 throw ParsingException("Incorrect use of $ in pattern \"" + pattern + "\".", __FILE__, __LINE__);
90 }
91 std::string::size_type closingBrace = remainingPattern.find('}', i);
92 if (closingBrace == std::string::npos) {
93 throw ParsingException("Incorrect use of $ in pattern \"" + pattern + "\".", __FILE__, __LINE__);
94 }
95 std::string varName = remainingPattern.substr(i + 2, closingBrace - i - 2);
96 remainingPattern = lookupVariable(varName) + remainingPattern.substr(closingBrace + 1);
97 break;
98 } else {
99 if (i >= remainingPath.length() || c != remainingPath.at(i)) {
100 return false;
101 }
102 if (i == remainingPattern.length() - 1) {
103 if (c == '/' || (i + 1 < remainingPath.length() && remainingPath.at(i + 1) == '/')) {
104 // Path represents file in subdirectory
105 return true;
106 } else if (remainingPath.length() == remainingPattern.length()) {
107 // Exact match
108 return true;
109 } else {
110 return false;
111 }
112 }
113 }
114 }
115 }
116 }
117 return false;
118}
119
120std::string suPHP::PathMatcher::lookupVariable(std::string str)
121 throw (KeyNotFoundException) {
122 std::string rv;
123 if (str == "USERNAME") {
124 rv = user.getUsername();
125 } else if (str == "UID") {
126 rv = Util::intToStr(user.getUid());
127 } else if (str == "HOME") {
128 rv = user.getHomeDirectory();
129 } else if (str == "GROUPNAME") {
130 rv = group.getGroupname();
131 } else if (str == "GID") {
132 rv = Util::intToStr(group.getGid());
133 } else {
134 throw KeyNotFoundException("Key \"" + str +
135 "\" does not represent a valid variable name", __FILE__, __LINE__);
136 }
137 return rv;
138}
139
140std::string suPHP::PathMatcher::resolveVariables(std::string str) throw (KeyNotFoundException, ParsingException) {
141 std::string out;
142 bool escapeNext = false;
143 for (int i = 0; i < str.length(); i++) {
144 char c = str.at(i);
145 if (escapeNext) {
146 escapeNext = false;
147 if (c == '\\' || c == '$') {
148 // Backslash was used as an escape character
149 out += c;
150 } else {
151 out += '\\';
152 out += c;
153 }
154 } else {
155 if (c == '\\') {
156 escapeNext = true;
157 } else if (c == '$') {
158 if (str.length() < i + 3) {
159 throw ParsingException("Incorrect use of $ in string \"" + str + "\".", __FILE__, __LINE__);
160 }
161 if (str.at(i + 1) != '{') {
162 throw ParsingException("Incorrect use of $ in string \"" + str + "\".", __FILE__, __LINE__);
163 }
164 std::string::size_type closingBrace = str.find('}', i);
165 if (closingBrace == std::string::npos) {
166 throw ParsingException("Incorrect use of $ in string \"" + str + "\".", __FILE__, __LINE__);
167 }
168 std::string varName = str.substr(i + 2, closingBrace - i - 2);
169 out += lookupVariable(varName);
170 i = closingBrace + 1;
171 } else {
172 out += c;
173 }
174 }
175 }
176 return out;
177}