blob: 28e99b372d5430580a6fb1988cd982dcd3a19b54 [file] [log] [blame]
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.firewall;
import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
import android.os.PatternMatcher;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.regex.Pattern;
abstract class StringFilter implements Filter {
private static final String ATTR_EQUALS = "equals";
private static final String ATTR_STARTS_WITH = "startsWith";
private static final String ATTR_CONTAINS = "contains";
private static final String ATTR_PATTERN = "pattern";
private static final String ATTR_REGEX = "regex";
private static final String ATTR_IS_NULL = "isNull";
private final ValueProvider mValueProvider;
private StringFilter(ValueProvider valueProvider) {
this.mValueProvider = valueProvider;
}
/**
* Constructs a new StringFilter based on the string filter attribute on the current
* element, and the given StringValueMatcher.
*
* The current node should contain exactly 1 string filter attribute. E.g. equals,
* contains, etc. Otherwise, an XmlPullParserException will be thrown.
*
* @param parser An XmlPullParser object positioned at an element that should
* contain a string filter attribute
* @return This StringFilter object
*/
public static StringFilter readFromXml(ValueProvider valueProvider, XmlPullParser parser)
throws IOException, XmlPullParserException {
StringFilter filter = null;
for (int i=0; i<parser.getAttributeCount(); i++) {
StringFilter newFilter = getFilter(valueProvider, parser, i);
if (newFilter != null) {
if (filter != null) {
throw new XmlPullParserException("Multiple string filter attributes found");
}
filter = newFilter;
}
}
if (filter == null) {
// if there are no string filter attributes, we default to isNull="false" so that an
// empty filter is equivalent to an existence check
filter = new IsNullFilter(valueProvider, false);
}
return filter;
}
private static StringFilter getFilter(ValueProvider valueProvider, XmlPullParser parser,
int attributeIndex) {
String attributeName = parser.getAttributeName(attributeIndex);
switch (attributeName.charAt(0)) {
case 'e':
if (!attributeName.equals(ATTR_EQUALS)) {
return null;
}
return new EqualsFilter(valueProvider, parser.getAttributeValue(attributeIndex));
case 'i':
if (!attributeName.equals(ATTR_IS_NULL)) {
return null;
}
return new IsNullFilter(valueProvider, parser.getAttributeValue(attributeIndex));
case 's':
if (!attributeName.equals(ATTR_STARTS_WITH)) {
return null;
}
return new StartsWithFilter(valueProvider,
parser.getAttributeValue(attributeIndex));
case 'c':
if (!attributeName.equals(ATTR_CONTAINS)) {
return null;
}
return new ContainsFilter(valueProvider, parser.getAttributeValue(attributeIndex));
case 'p':
if (!attributeName.equals(ATTR_PATTERN)) {
return null;
}
return new PatternStringFilter(valueProvider,
parser.getAttributeValue(attributeIndex));
case 'r':
if (!attributeName.equals(ATTR_REGEX)) {
return null;
}
return new RegexFilter(valueProvider, parser.getAttributeValue(attributeIndex));
}
return null;
}
protected abstract boolean matchesValue(String value);
@Override
public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
int callerUid, int callerPid, String resolvedType, int receivingUid) {
String value = mValueProvider.getValue(resolvedComponent, intent, resolvedType);
return matchesValue(value);
}
private static abstract class ValueProvider extends FilterFactory {
protected ValueProvider(String tag) {
super(tag);
}
public Filter newFilter(XmlPullParser parser)
throws IOException, XmlPullParserException {
return StringFilter.readFromXml(this, parser);
}
public abstract String getValue(ComponentName resolvedComponent, Intent intent,
String resolvedType);
}
private static class EqualsFilter extends StringFilter {
private final String mFilterValue;
public EqualsFilter(ValueProvider valueProvider, String attrValue) {
super(valueProvider);
mFilterValue = attrValue;
}
@Override
public boolean matchesValue(String value) {
return value != null && value.equals(mFilterValue);
}
}
private static class ContainsFilter extends StringFilter {
private final String mFilterValue;
public ContainsFilter(ValueProvider valueProvider, String attrValue) {
super(valueProvider);
mFilterValue = attrValue;
}
@Override
public boolean matchesValue(String value) {
return value != null && value.contains(mFilterValue);
}
}
private static class StartsWithFilter extends StringFilter {
private final String mFilterValue;
public StartsWithFilter(ValueProvider valueProvider, String attrValue) {
super(valueProvider);
mFilterValue = attrValue;
}
@Override
public boolean matchesValue(String value) {
return value != null && value.startsWith(mFilterValue);
}
}
private static class PatternStringFilter extends StringFilter {
private final PatternMatcher mPattern;
public PatternStringFilter(ValueProvider valueProvider, String attrValue) {
super(valueProvider);
mPattern = new PatternMatcher(attrValue, PatternMatcher.PATTERN_SIMPLE_GLOB);
}
@Override
public boolean matchesValue(String value) {
return value != null && mPattern.match(value);
}
}
private static class RegexFilter extends StringFilter {
private final Pattern mPattern;
public RegexFilter(ValueProvider valueProvider, String attrValue) {
super(valueProvider);
this.mPattern = Pattern.compile(attrValue);
}
@Override
public boolean matchesValue(String value) {
return value != null && mPattern.matcher(value).matches();
}
}
private static class IsNullFilter extends StringFilter {
private final boolean mIsNull;
public IsNullFilter(ValueProvider valueProvider, String attrValue) {
super(valueProvider);
mIsNull = Boolean.parseBoolean(attrValue);
}
public IsNullFilter(ValueProvider valueProvider, boolean isNull) {
super(valueProvider);
mIsNull = isNull;
}
@Override
public boolean matchesValue(String value) {
return (value == null) == mIsNull;
}
}
public static final ValueProvider COMPONENT = new ValueProvider("component") {
@Override
public String getValue(ComponentName resolvedComponent, Intent intent,
String resolvedType) {
if (resolvedComponent != null) {
return resolvedComponent.flattenToString();
}
return null;
}
};
public static final ValueProvider COMPONENT_NAME = new ValueProvider("component-name") {
@Override
public String getValue(ComponentName resolvedComponent, Intent intent,
String resolvedType) {
if (resolvedComponent != null) {
return resolvedComponent.getClassName();
}
return null;
}
};
public static final ValueProvider COMPONENT_PACKAGE = new ValueProvider("component-package") {
@Override
public String getValue(ComponentName resolvedComponent, Intent intent,
String resolvedType) {
if (resolvedComponent != null) {
return resolvedComponent.getPackageName();
}
return null;
}
};
public static final FilterFactory ACTION = new ValueProvider("action") {
@Override
public String getValue(ComponentName resolvedComponent, Intent intent,
String resolvedType) {
return intent.getAction();
}
};
public static final ValueProvider DATA = new ValueProvider("data") {
@Override
public String getValue(ComponentName resolvedComponent, Intent intent,
String resolvedType) {
Uri data = intent.getData();
if (data != null) {
return data.toString();
}
return null;
}
};
public static final ValueProvider MIME_TYPE = new ValueProvider("mime-type") {
@Override
public String getValue(ComponentName resolvedComponent, Intent intent,
String resolvedType) {
return resolvedType;
}
};
public static final ValueProvider SCHEME = new ValueProvider("scheme") {
@Override
public String getValue(ComponentName resolvedComponent, Intent intent,
String resolvedType) {
Uri data = intent.getData();
if (data != null) {
return data.getScheme();
}
return null;
}
};
public static final ValueProvider SSP = new ValueProvider("scheme-specific-part") {
@Override
public String getValue(ComponentName resolvedComponent, Intent intent,
String resolvedType) {
Uri data = intent.getData();
if (data != null) {
return data.getSchemeSpecificPart();
}
return null;
}
};
public static final ValueProvider HOST = new ValueProvider("host") {
@Override
public String getValue(ComponentName resolvedComponent, Intent intent,
String resolvedType) {
Uri data = intent.getData();
if (data != null) {
return data.getHost();
}
return null;
}
};
public static final ValueProvider PATH = new ValueProvider("path") {
@Override
public String getValue(ComponentName resolvedComponent, Intent intent,
String resolvedType) {
Uri data = intent.getData();
if (data != null) {
return data.getPath();
}
return null;
}
};
}