blob: 28e99b372d5430580a6fb1988cd982dcd3a19b54 [file] [log] [blame]
Ben Gruver4efe9402013-04-02 21:18:41 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.firewall;
18
19import android.content.ComponentName;
20import android.content.Intent;
Ben Gruver4efe9402013-04-02 21:18:41 -070021import android.net.Uri;
22import android.os.PatternMatcher;
23import org.xmlpull.v1.XmlPullParser;
24import org.xmlpull.v1.XmlPullParserException;
25
26import java.io.IOException;
27import java.util.regex.Pattern;
28
29abstract class StringFilter implements Filter {
30 private static final String ATTR_EQUALS = "equals";
31 private static final String ATTR_STARTS_WITH = "startsWith";
32 private static final String ATTR_CONTAINS = "contains";
33 private static final String ATTR_PATTERN = "pattern";
34 private static final String ATTR_REGEX = "regex";
35 private static final String ATTR_IS_NULL = "isNull";
36
37 private final ValueProvider mValueProvider;
38
39 private StringFilter(ValueProvider valueProvider) {
40 this.mValueProvider = valueProvider;
41 }
42
43 /**
44 * Constructs a new StringFilter based on the string filter attribute on the current
45 * element, and the given StringValueMatcher.
46 *
47 * The current node should contain exactly 1 string filter attribute. E.g. equals,
48 * contains, etc. Otherwise, an XmlPullParserException will be thrown.
49 *
50 * @param parser An XmlPullParser object positioned at an element that should
51 * contain a string filter attribute
52 * @return This StringFilter object
53 */
54 public static StringFilter readFromXml(ValueProvider valueProvider, XmlPullParser parser)
55 throws IOException, XmlPullParserException {
56 StringFilter filter = null;
57
58 for (int i=0; i<parser.getAttributeCount(); i++) {
59 StringFilter newFilter = getFilter(valueProvider, parser, i);
60 if (newFilter != null) {
61 if (filter != null) {
62 throw new XmlPullParserException("Multiple string filter attributes found");
63 }
64 filter = newFilter;
65 }
66 }
67
68 if (filter == null) {
69 // if there are no string filter attributes, we default to isNull="false" so that an
70 // empty filter is equivalent to an existence check
71 filter = new IsNullFilter(valueProvider, false);
72 }
73
74 return filter;
75 }
76
77 private static StringFilter getFilter(ValueProvider valueProvider, XmlPullParser parser,
78 int attributeIndex) {
79 String attributeName = parser.getAttributeName(attributeIndex);
80
81 switch (attributeName.charAt(0)) {
82 case 'e':
83 if (!attributeName.equals(ATTR_EQUALS)) {
84 return null;
85 }
86 return new EqualsFilter(valueProvider, parser.getAttributeValue(attributeIndex));
87 case 'i':
88 if (!attributeName.equals(ATTR_IS_NULL)) {
89 return null;
90 }
91 return new IsNullFilter(valueProvider, parser.getAttributeValue(attributeIndex));
92 case 's':
93 if (!attributeName.equals(ATTR_STARTS_WITH)) {
94 return null;
95 }
96 return new StartsWithFilter(valueProvider,
97 parser.getAttributeValue(attributeIndex));
98 case 'c':
99 if (!attributeName.equals(ATTR_CONTAINS)) {
100 return null;
101 }
102 return new ContainsFilter(valueProvider, parser.getAttributeValue(attributeIndex));
103 case 'p':
104 if (!attributeName.equals(ATTR_PATTERN)) {
105 return null;
106 }
107 return new PatternStringFilter(valueProvider,
108 parser.getAttributeValue(attributeIndex));
109 case 'r':
110 if (!attributeName.equals(ATTR_REGEX)) {
111 return null;
112 }
113 return new RegexFilter(valueProvider, parser.getAttributeValue(attributeIndex));
114 }
115 return null;
116 }
117
118 protected abstract boolean matchesValue(String value);
119
120 @Override
Ben Gruverf5323fe2013-07-31 15:09:51 -0700121 public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
Ben Gruver49660c72013-08-06 19:54:08 -0700122 int callerUid, int callerPid, String resolvedType, int receivingUid) {
123 String value = mValueProvider.getValue(resolvedComponent, intent, resolvedType);
Ben Gruver4efe9402013-04-02 21:18:41 -0700124 return matchesValue(value);
125 }
126
127 private static abstract class ValueProvider extends FilterFactory {
128 protected ValueProvider(String tag) {
129 super(tag);
130 }
131
132 public Filter newFilter(XmlPullParser parser)
133 throws IOException, XmlPullParserException {
134 return StringFilter.readFromXml(this, parser);
135 }
136
Ben Gruverf5323fe2013-07-31 15:09:51 -0700137 public abstract String getValue(ComponentName resolvedComponent, Intent intent,
Ben Gruver49660c72013-08-06 19:54:08 -0700138 String resolvedType);
Ben Gruver4efe9402013-04-02 21:18:41 -0700139 }
140
141 private static class EqualsFilter extends StringFilter {
142 private final String mFilterValue;
143
144 public EqualsFilter(ValueProvider valueProvider, String attrValue) {
145 super(valueProvider);
146 mFilterValue = attrValue;
147 }
148
149 @Override
150 public boolean matchesValue(String value) {
151 return value != null && value.equals(mFilterValue);
152 }
153 }
154
155 private static class ContainsFilter extends StringFilter {
156 private final String mFilterValue;
157
158 public ContainsFilter(ValueProvider valueProvider, String attrValue) {
159 super(valueProvider);
160 mFilterValue = attrValue;
161 }
162
163 @Override
164 public boolean matchesValue(String value) {
165 return value != null && value.contains(mFilterValue);
166 }
167 }
168
169 private static class StartsWithFilter extends StringFilter {
170 private final String mFilterValue;
171
172 public StartsWithFilter(ValueProvider valueProvider, String attrValue) {
173 super(valueProvider);
174 mFilterValue = attrValue;
175 }
176
177 @Override
178 public boolean matchesValue(String value) {
179 return value != null && value.startsWith(mFilterValue);
180 }
181 }
182
183 private static class PatternStringFilter extends StringFilter {
184 private final PatternMatcher mPattern;
185
186 public PatternStringFilter(ValueProvider valueProvider, String attrValue) {
187 super(valueProvider);
188 mPattern = new PatternMatcher(attrValue, PatternMatcher.PATTERN_SIMPLE_GLOB);
189 }
190
191 @Override
192 public boolean matchesValue(String value) {
193 return value != null && mPattern.match(value);
194 }
195 }
196
197 private static class RegexFilter extends StringFilter {
198 private final Pattern mPattern;
199
200 public RegexFilter(ValueProvider valueProvider, String attrValue) {
201 super(valueProvider);
202 this.mPattern = Pattern.compile(attrValue);
203 }
204
205 @Override
206 public boolean matchesValue(String value) {
207 return value != null && mPattern.matcher(value).matches();
208 }
209 }
210
211 private static class IsNullFilter extends StringFilter {
212 private final boolean mIsNull;
213
214 public IsNullFilter(ValueProvider valueProvider, String attrValue) {
215 super(valueProvider);
216 mIsNull = Boolean.parseBoolean(attrValue);
217 }
218
219 public IsNullFilter(ValueProvider valueProvider, boolean isNull) {
220 super(valueProvider);
221 mIsNull = isNull;
222 }
223
224 @Override
225 public boolean matchesValue(String value) {
226 return (value == null) == mIsNull;
227 }
228 }
229
230 public static final ValueProvider COMPONENT = new ValueProvider("component") {
231 @Override
Ben Gruver49660c72013-08-06 19:54:08 -0700232 public String getValue(ComponentName resolvedComponent, Intent intent,
233 String resolvedType) {
Ben Gruverf5323fe2013-07-31 15:09:51 -0700234 if (resolvedComponent != null) {
235 return resolvedComponent.flattenToString();
Ben Gruver4efe9402013-04-02 21:18:41 -0700236 }
237 return null;
238 }
239 };
240
241 public static final ValueProvider COMPONENT_NAME = new ValueProvider("component-name") {
242 @Override
Ben Gruver49660c72013-08-06 19:54:08 -0700243 public String getValue(ComponentName resolvedComponent, Intent intent,
244 String resolvedType) {
Ben Gruverf5323fe2013-07-31 15:09:51 -0700245 if (resolvedComponent != null) {
246 return resolvedComponent.getClassName();
Ben Gruver4efe9402013-04-02 21:18:41 -0700247 }
248 return null;
249 }
250 };
251
252 public static final ValueProvider COMPONENT_PACKAGE = new ValueProvider("component-package") {
253 @Override
Ben Gruver49660c72013-08-06 19:54:08 -0700254 public String getValue(ComponentName resolvedComponent, Intent intent,
255 String resolvedType) {
Ben Gruverf5323fe2013-07-31 15:09:51 -0700256 if (resolvedComponent != null) {
257 return resolvedComponent.getPackageName();
Ben Gruver4efe9402013-04-02 21:18:41 -0700258 }
259 return null;
260 }
261 };
262
Ben Gruver4efe9402013-04-02 21:18:41 -0700263 public static final FilterFactory ACTION = new ValueProvider("action") {
264 @Override
Ben Gruver49660c72013-08-06 19:54:08 -0700265 public String getValue(ComponentName resolvedComponent, Intent intent,
266 String resolvedType) {
Ben Gruver4efe9402013-04-02 21:18:41 -0700267 return intent.getAction();
268 }
269 };
270
271 public static final ValueProvider DATA = new ValueProvider("data") {
272 @Override
Ben Gruver49660c72013-08-06 19:54:08 -0700273 public String getValue(ComponentName resolvedComponent, Intent intent,
274 String resolvedType) {
Ben Gruver4efe9402013-04-02 21:18:41 -0700275 Uri data = intent.getData();
276 if (data != null) {
277 return data.toString();
278 }
279 return null;
280 }
281 };
282
283 public static final ValueProvider MIME_TYPE = new ValueProvider("mime-type") {
284 @Override
Ben Gruver49660c72013-08-06 19:54:08 -0700285 public String getValue(ComponentName resolvedComponent, Intent intent,
286 String resolvedType) {
Ben Gruver4efe9402013-04-02 21:18:41 -0700287 return resolvedType;
288 }
289 };
290
291 public static final ValueProvider SCHEME = new ValueProvider("scheme") {
292 @Override
Ben Gruver49660c72013-08-06 19:54:08 -0700293 public String getValue(ComponentName resolvedComponent, Intent intent,
294 String resolvedType) {
Ben Gruver4efe9402013-04-02 21:18:41 -0700295 Uri data = intent.getData();
296 if (data != null) {
297 return data.getScheme();
298 }
299 return null;
300 }
301 };
302
303 public static final ValueProvider SSP = new ValueProvider("scheme-specific-part") {
304 @Override
Ben Gruver49660c72013-08-06 19:54:08 -0700305 public String getValue(ComponentName resolvedComponent, Intent intent,
306 String resolvedType) {
Ben Gruver4efe9402013-04-02 21:18:41 -0700307 Uri data = intent.getData();
308 if (data != null) {
309 return data.getSchemeSpecificPart();
310 }
311 return null;
312 }
313 };
314
315 public static final ValueProvider HOST = new ValueProvider("host") {
316 @Override
Ben Gruver49660c72013-08-06 19:54:08 -0700317 public String getValue(ComponentName resolvedComponent, Intent intent,
318 String resolvedType) {
Ben Gruver4efe9402013-04-02 21:18:41 -0700319 Uri data = intent.getData();
320 if (data != null) {
321 return data.getHost();
322 }
323 return null;
324 }
325 };
326
327 public static final ValueProvider PATH = new ValueProvider("path") {
328 @Override
Ben Gruver49660c72013-08-06 19:54:08 -0700329 public String getValue(ComponentName resolvedComponent, Intent intent,
330 String resolvedType) {
Ben Gruver4efe9402013-04-02 21:18:41 -0700331 Uri data = intent.getData();
332 if (data != null) {
333 return data.getPath();
334 }
335 return null;
336 }
337 };
338}