• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.server.firewall;
18 
19 import android.content.ComponentName;
20 import android.content.Intent;
21 import android.content.pm.ApplicationInfo;
22 import android.net.Uri;
23 import android.os.PatternMatcher;
24 import org.xmlpull.v1.XmlPullParser;
25 import org.xmlpull.v1.XmlPullParserException;
26 
27 import java.io.IOException;
28 import java.util.regex.Pattern;
29 
30 abstract class StringFilter implements Filter {
31     private static final String ATTR_EQUALS = "equals";
32     private static final String ATTR_STARTS_WITH = "startsWith";
33     private static final String ATTR_CONTAINS = "contains";
34     private static final String ATTR_PATTERN = "pattern";
35     private static final String ATTR_REGEX = "regex";
36     private static final String ATTR_IS_NULL = "isNull";
37 
38     private final ValueProvider mValueProvider;
39 
StringFilter(ValueProvider valueProvider)40     private StringFilter(ValueProvider valueProvider) {
41         this.mValueProvider = valueProvider;
42     }
43 
44     /**
45      * Constructs a new StringFilter based on the string filter attribute on the current
46      * element, and the given StringValueMatcher.
47      *
48      * The current node should contain exactly 1 string filter attribute. E.g. equals,
49      * contains, etc. Otherwise, an XmlPullParserException will be thrown.
50      *
51      * @param parser      An XmlPullParser object positioned at an element that should
52      *                    contain a string filter attribute
53      * @return This StringFilter object
54      */
readFromXml(ValueProvider valueProvider, XmlPullParser parser)55     public static StringFilter readFromXml(ValueProvider valueProvider, XmlPullParser parser)
56             throws IOException, XmlPullParserException {
57         StringFilter filter = null;
58 
59         for (int i=0; i<parser.getAttributeCount(); i++) {
60             StringFilter newFilter = getFilter(valueProvider, parser, i);
61             if (newFilter != null) {
62                 if (filter != null) {
63                     throw new XmlPullParserException("Multiple string filter attributes found");
64                 }
65                 filter = newFilter;
66             }
67         }
68 
69         if (filter == null) {
70             // if there are no string filter attributes, we default to isNull="false" so that an
71             // empty filter is equivalent to an existence check
72             filter = new IsNullFilter(valueProvider, false);
73         }
74 
75         return filter;
76     }
77 
getFilter(ValueProvider valueProvider, XmlPullParser parser, int attributeIndex)78     private static StringFilter getFilter(ValueProvider valueProvider, XmlPullParser parser,
79             int attributeIndex) {
80         String attributeName = parser.getAttributeName(attributeIndex);
81 
82         switch (attributeName.charAt(0)) {
83             case 'e':
84                 if (!attributeName.equals(ATTR_EQUALS)) {
85                     return null;
86                 }
87                 return new EqualsFilter(valueProvider, parser.getAttributeValue(attributeIndex));
88             case 'i':
89                 if (!attributeName.equals(ATTR_IS_NULL)) {
90                     return null;
91                 }
92                 return new IsNullFilter(valueProvider, parser.getAttributeValue(attributeIndex));
93             case 's':
94                 if (!attributeName.equals(ATTR_STARTS_WITH)) {
95                     return null;
96                 }
97                 return new StartsWithFilter(valueProvider,
98                         parser.getAttributeValue(attributeIndex));
99             case 'c':
100                 if (!attributeName.equals(ATTR_CONTAINS)) {
101                     return null;
102                 }
103                 return new ContainsFilter(valueProvider, parser.getAttributeValue(attributeIndex));
104             case 'p':
105                 if (!attributeName.equals(ATTR_PATTERN)) {
106                     return null;
107                 }
108                 return new PatternStringFilter(valueProvider,
109                         parser.getAttributeValue(attributeIndex));
110             case 'r':
111                 if (!attributeName.equals(ATTR_REGEX)) {
112                     return null;
113                 }
114                 return new RegexFilter(valueProvider, parser.getAttributeValue(attributeIndex));
115         }
116         return null;
117     }
118 
matchesValue(String value)119     protected abstract boolean matchesValue(String value);
120 
121     @Override
matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp, int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp)122     public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
123             int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
124         String value = mValueProvider.getValue(intent, callerApp, resolvedType, resolvedApp);
125         return matchesValue(value);
126     }
127 
128     private static abstract class ValueProvider extends FilterFactory {
ValueProvider(String tag)129         protected ValueProvider(String tag) {
130             super(tag);
131         }
132 
newFilter(XmlPullParser parser)133         public Filter newFilter(XmlPullParser parser)
134                 throws IOException, XmlPullParserException {
135             return StringFilter.readFromXml(this, parser);
136         }
137 
getValue(Intent intent, ApplicationInfo callerApp, String resolvedType, ApplicationInfo resolvedApp)138         public abstract String getValue(Intent intent, ApplicationInfo callerApp,
139                 String resolvedType, ApplicationInfo resolvedApp);
140     }
141 
142     private static class EqualsFilter extends StringFilter {
143         private final String mFilterValue;
144 
EqualsFilter(ValueProvider valueProvider, String attrValue)145         public EqualsFilter(ValueProvider valueProvider, String attrValue) {
146             super(valueProvider);
147             mFilterValue = attrValue;
148         }
149 
150         @Override
matchesValue(String value)151         public boolean matchesValue(String value) {
152             return value != null && value.equals(mFilterValue);
153         }
154     }
155 
156     private static class ContainsFilter extends StringFilter {
157         private final String mFilterValue;
158 
ContainsFilter(ValueProvider valueProvider, String attrValue)159         public ContainsFilter(ValueProvider valueProvider, String attrValue) {
160             super(valueProvider);
161             mFilterValue = attrValue;
162         }
163 
164         @Override
matchesValue(String value)165         public boolean matchesValue(String value) {
166             return value != null && value.contains(mFilterValue);
167         }
168     }
169 
170     private static class StartsWithFilter extends StringFilter {
171         private final String mFilterValue;
172 
StartsWithFilter(ValueProvider valueProvider, String attrValue)173         public StartsWithFilter(ValueProvider valueProvider, String attrValue) {
174             super(valueProvider);
175             mFilterValue = attrValue;
176         }
177 
178         @Override
matchesValue(String value)179         public boolean matchesValue(String value) {
180             return value != null && value.startsWith(mFilterValue);
181         }
182     }
183 
184     private static class PatternStringFilter extends StringFilter {
185         private final PatternMatcher mPattern;
186 
PatternStringFilter(ValueProvider valueProvider, String attrValue)187         public PatternStringFilter(ValueProvider valueProvider, String attrValue) {
188             super(valueProvider);
189             mPattern = new PatternMatcher(attrValue, PatternMatcher.PATTERN_SIMPLE_GLOB);
190         }
191 
192         @Override
matchesValue(String value)193         public boolean matchesValue(String value) {
194             return value != null && mPattern.match(value);
195         }
196     }
197 
198     private static class RegexFilter extends StringFilter {
199         private final Pattern mPattern;
200 
RegexFilter(ValueProvider valueProvider, String attrValue)201         public RegexFilter(ValueProvider valueProvider, String attrValue) {
202             super(valueProvider);
203             this.mPattern = Pattern.compile(attrValue);
204         }
205 
206         @Override
matchesValue(String value)207         public boolean matchesValue(String value) {
208             return value != null && mPattern.matcher(value).matches();
209         }
210     }
211 
212     private static class IsNullFilter extends StringFilter {
213         private final boolean mIsNull;
214 
IsNullFilter(ValueProvider valueProvider, String attrValue)215         public IsNullFilter(ValueProvider valueProvider, String attrValue) {
216             super(valueProvider);
217             mIsNull = Boolean.parseBoolean(attrValue);
218         }
219 
IsNullFilter(ValueProvider valueProvider, boolean isNull)220         public IsNullFilter(ValueProvider valueProvider, boolean isNull) {
221             super(valueProvider);
222             mIsNull = isNull;
223         }
224 
225         @Override
matchesValue(String value)226         public boolean matchesValue(String value) {
227             return (value == null) == mIsNull;
228         }
229     }
230 
231     public static final ValueProvider COMPONENT = new ValueProvider("component") {
232         @Override
233         public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
234                 ApplicationInfo resolvedApp) {
235             ComponentName cn = intent.getComponent();
236             if (cn != null) {
237                 return cn.flattenToString();
238             }
239             return null;
240         }
241     };
242 
243     public static final ValueProvider COMPONENT_NAME = new ValueProvider("component-name") {
244         @Override
245         public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
246                 ApplicationInfo resolvedApp) {
247             ComponentName cn = intent.getComponent();
248             if (cn != null) {
249                 return cn.getClassName();
250             }
251             return null;
252         }
253     };
254 
255     public static final ValueProvider COMPONENT_PACKAGE = new ValueProvider("component-package") {
256         @Override
257         public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
258                 ApplicationInfo resolvedApp) {
259             ComponentName cn = intent.getComponent();
260             if (cn != null) {
261                 return cn.getPackageName();
262             }
263             return null;
264         }
265     };
266 
267     public static final FilterFactory ACTION = new ValueProvider("action") {
268         @Override
269         public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
270                 ApplicationInfo resolvedApp) {
271             return intent.getAction();
272         }
273     };
274 
275     public static final ValueProvider DATA = new ValueProvider("data") {
276         @Override
277         public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
278                 ApplicationInfo resolvedApp) {
279             Uri data = intent.getData();
280             if (data != null) {
281                 return data.toString();
282             }
283             return null;
284         }
285     };
286 
287     public static final ValueProvider MIME_TYPE = new ValueProvider("mime-type") {
288         @Override
289         public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
290                 ApplicationInfo resolvedApp) {
291             return resolvedType;
292         }
293     };
294 
295     public static final ValueProvider SCHEME = new ValueProvider("scheme") {
296         @Override
297         public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
298                 ApplicationInfo resolvedApp) {
299             Uri data = intent.getData();
300             if (data != null) {
301                 return data.getScheme();
302             }
303             return null;
304         }
305     };
306 
307     public static final ValueProvider SSP = new ValueProvider("scheme-specific-part") {
308         @Override
309         public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
310                 ApplicationInfo resolvedApp) {
311             Uri data = intent.getData();
312             if (data != null) {
313                 return data.getSchemeSpecificPart();
314             }
315             return null;
316         }
317     };
318 
319     public static final ValueProvider HOST = new ValueProvider("host") {
320         @Override
321         public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
322                 ApplicationInfo resolvedApp) {
323             Uri data = intent.getData();
324             if (data != null) {
325                 return data.getHost();
326             }
327             return null;
328         }
329     };
330 
331     public static final ValueProvider PATH = new ValueProvider("path") {
332         @Override
333         public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
334                 ApplicationInfo resolvedApp) {
335             Uri data = intent.getData();
336             if (data != null) {
337                 return data.getPath();
338             }
339             return null;
340         }
341     };
342 }
343