blob: 4adb55f5f09b81ffdc6d7d19cd23ff903c86dc4d [file] [log] [blame]
Sam Hurstc7152db2016-02-29 09:35:22 -08001/*
2 * Copyright (C) 2016 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#define LOG_TAG "VehiclePropertyAccessControl"
18#include <string>
19#include <stdint.h>
20#include <sys/types.h>
21#include <IVehicleNetwork.h>
22#include "VehiclePropertyAccessControl.h"
23#include <hardware/vehicle.h>
24#include <private/android_filesystem_config.h>
25#include <vehicle-internal.h>
26
27//#define DBG_EVENT
28//#define DBG_VERBOSE
29#ifdef DBG_EVENT
30#define EVENT_LOG(x...) ALOGD(x)
31#else
32#define EVENT_LOG(x...)
33#endif
34#ifdef DBG_VERBOSE
35#define LOG_VERBOSE(x...) ALOGD(x)
36#else
37#define LOG_VERBOSE(x...)
38#endif
39
40
41namespace android {
42
43VehiclePropertyAccessControl::VehiclePropertyAccessControl() {
44}
45
46VehiclePropertyAccessControl::~VehiclePropertyAccessControl() {
47 int index;
48 int size;
49
50 for (auto& i: mVehicleAccessControlMap) {
51 delete(&i);
52 }
53
54 mVehicleAccessControlMap.clear();
55}
56
57// Returns true if the given string, s, is a hex number that starts with 0x.
58// Otherwise false is returned.
59bool VehiclePropertyAccessControl::isHexNotation(std::string const& s) {
60 return s.compare(0, 2, "0x") == 0
61 && s.size() > 2
62 && s.find_first_not_of("0123456789abcdefABCDEF", 2)
63 == std::string::npos;
64}
65
66// Converts the string representation, access, to an integer form and store it
67// in value. true is returned if the parameter, access, is "r", "w", "rw" or
68// "wr". Otherwise false is returned. The parameters property and uid are
69// only used for logging in the event that the string, access, was not
70// recognized.
71bool VehiclePropertyAccessControl::accessToInt(int32_t* const value,
72 const xmlChar* property,
73 const xmlChar* uid,
74 const xmlChar* access) {
75 if (!value || !property || !uid || !access) {
76 ALOGE("Internal Error\n");
77 return false;
78 }
79
80 if (xmlStrcmp(access, (const xmlChar *)"r") == 0) {
81 *value = VEHICLE_PROP_ACCESS_READ;
82 }
83 else if (xmlStrcmp(access, (const xmlChar *)"w") == 0) {
84 *value = VEHICLE_PROP_ACCESS_WRITE;
85 }
86 else if ((xmlStrcmp(access, (const xmlChar *)"rw") == 0)
87 || (xmlStrcmp(access, (const xmlChar *)"wr") == 0)) {
88 *value = VEHICLE_PROP_ACCESS_READ_WRITE;
89 }
90 else {
91 ALOGE("Unknown access tag %s for UID %s in PROPERTY %s\n",access, uid,
92 property);
93 return false;
94 }
95
96 return true;
97}
98
99// Adds the property/uid pair to the mVehicleAccessControlMap map if the pair
100// doesn't already exist. If the pair does exist, the access is updated.
101bool VehiclePropertyAccessControl::updateOrCreate(int32_t uid, int32_t property,
102 int32_t access) {
103 // check if property exists
104 if (mVehicleAccessControlMap.count(property) == 0) {
105 std::map<int32_t, int32_t>* uid_access =
106 new std::map<int32_t, int32_t>();
107 mVehicleAccessControlMap[property] = uid_access;
108 }
109
110 // Get the propertyAccessMap
111 std::map<int32_t, int32_t>* uidAccessMap =
112 mVehicleAccessControlMap[property];
113
114 // Now check if uid exists
115 if (uidAccessMap->count(uid) == 0) {
116 (*uidAccessMap)[uid] = access;
117 // uid was not found
118 return false;
119 }
120
121 // The Property, Uid pair exist. So update the access
122 (*uidAccessMap)[uid] = access;
123
124 return true;
125}
126
127// Start parsing the xml file and populating the mVehicleAccessControlMap
128// map. The parameter, a_node, must point to the first <PROPERTY> tag.
129// true is returned if the parsing completed else false.
130bool VehiclePropertyAccessControl::populate(xmlNode * a_node) {
131 xmlNode* cur_node = NULL;
132 xmlNode* child = NULL;
133 xmlChar* property = NULL;
134 xmlChar* property_value_str = NULL;
135 xmlChar* uid = NULL;
136 xmlChar* uid_value_str = NULL;
137 xmlChar* access = NULL;
138 int32_t property_value;
139 int32_t uid_value;
140 int32_t access_value;
141
142 if (!a_node) {
143 ALOGE("Internal Error");
144 return false;
145 }
146
147 // Loop over all the PROPERTY tags
148 for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
149 if ((xmlStrcmp(cur_node->name, (const xmlChar *)"PROPERTY") == 0) &&
150 (cur_node->type == XML_ELEMENT_NODE)) {
151 // Free the old property tag
152 xmlFree(property);
153 // get new property tag name attribute
154 property = xmlGetProp(cur_node, (const xmlChar *)"name");
155 if (!property) {
156 ALOGE("PROPERTY given without name attribute");
157 continue;
158 }
159
160 // get new property tag value attribute
161 property_value_str = xmlGetProp(cur_node, (const xmlChar*)"value");
162 if (!property_value_str) {
163 ALOGE("PROPERTY given without value attribute");
164 continue;
165 }
166
167 std::string tmp_str((const char*)property_value_str);
168 if (isHexNotation(tmp_str)) {
169 property_value = std::stoul(tmp_str, nullptr, 16);
170 } else {
171 property_value = std::stoul(tmp_str, nullptr, 10);
172 }
173
Keun-young Parkd36a9952016-05-24 10:03:59 -0700174 // property with this set to true will not call get when it is subscribed.
175 property_value_str = xmlGetProp(cur_node, (const xmlChar*)"no_auto_get");
176 if (property_value_str) {
177 if (xmlStrcmp(property_value_str, (const xmlChar*)"true")==0) {
178 mPropertiesWithNoAutoGet.insert(property_value);
179 }
180 }
181
Sam Hurstc7152db2016-02-29 09:35:22 -0800182 // Loop over all UID tags
183 for (child = cur_node->children; child; child = child->next) {
184 if ((xmlStrcmp(child->name, (const xmlChar*)"UID")==0) &&
185 (child->type == XML_ELEMENT_NODE)) {
186 if (property != NULL) {
187 // Free the old uid tag
188 xmlFree(uid);
189 // Free the old access tag
190 xmlFree(access);
191 // get new uid tag
192 uid = xmlGetProp(child, (const xmlChar*)"name");
193 // get new uid tag
194 uid_value_str = xmlGetProp(child,
195 (const xmlChar*)"value");
196 // get new access tag
197 access = xmlGetProp(child, (const xmlChar *)"access");
198
199 if (uid == NULL) {
200 ALOGE(
201 "UID tag for property %s given without name attribute\n",
202 property);
203 } else if (uid_value_str == NULL) {
204 ALOGE(
205 "UID tag for property %s given without value attribute\n",
206 property);
207 } else if (access == NULL) {
208 ALOGE(
209 "UID tag for property %s given without access attribute\n",
210 property);
211 } else {
212 std::string tmp_str((const char *)uid_value_str);
213 if (isHexNotation(tmp_str)) {
214 uid_value = std::stoul(tmp_str, nullptr, 16);
215 } else {
216 uid_value = std::stoul(tmp_str, nullptr, 10);
217 }
218
219 bool re1 = accessToInt(&access_value, property, uid,
220 access);
221 if (re1) {
222 if (!updateOrCreate(uid_value, property_value,
223 access_value)) {
Keun-young Park76eeb522016-03-08 17:59:17 -0800224 LOG_VERBOSE(
Sam Hurstc7152db2016-02-29 09:35:22 -0800225 "Property %08x was added: uid=%d access=%d\n",
226 property_value, uid_value, access_value);
227 } else {
Keun-young Park76eeb522016-03-08 17:59:17 -0800228 LOG_VERBOSE("Property %08x was updated: uid=%d access=%d\n",
Sam Hurstc7152db2016-02-29 09:35:22 -0800229 property_value, uid_value, access_value);
230 }
231 }
232 }
233 }
234 }
235 }
236 }
237 }
238
239 xmlFree(property);
240 xmlFree(uid);
241 xmlFree(access);
242
243 return true;
244}
245
246// This method initializes the class by parsing the mandatory
247// /system/etc/vns/vns_policy.xml file and then the optional
248// /system/etc/vns/vendor_vns_policy.xml if found.
249// false is returned if vns_policy.xml was not found or is
250// invalid else true is returned.
251bool VehiclePropertyAccessControl::init() {
252 static const char* default_policy = "/system/etc/vns/vns_policy.xml";
253 static const char* vendor_policy = "/system/etc/vns/vendor_vns_policy.xml";
254
255 if (!process(default_policy)) {
256 return false;
257 }
258
259 if (process(vendor_policy)) {
260 ALOGE("Vendor VNS Policy was applied\n");
261 }
262
263 return true;
264}
265
266// Processes the vns_policy.xml or vendor_vns_policy.xml files
267// and returns true on success else false is returned.
268bool VehiclePropertyAccessControl::process(const char* policy) {
269 xmlDoc* doc = NULL;
270 xmlNode* root_element = NULL;
271
272 doc = xmlReadFile(policy, NULL, 0);
273 if (doc == NULL) {
274 ALOGE("Could not find %s\n", policy);
275 return false;
276 }
277
278 root_element = xmlDocGetRootElement(doc);
279 if (!root_element) {
280 ALOGE("Not a valid config file %s\n", policy);
281 xmlFreeDoc(doc);
282 return false;
283 }
284
285 if (xmlStrcmp(root_element->name, (const xmlChar *)"ALLOW") != 0) {
286 ALOGE("Not a valid config file %s\n", policy);
287 xmlFreeDoc(doc);
288 return false;
289 }
290
291 bool ret = populate(root_element->children);
292
293 xmlFreeDoc(doc);
294
295 return ret;
296}
297
298void VehiclePropertyAccessControl::dump(String8& msg) {
299 std::string perm;
300 int32_t property;
301 int32_t uid;
302 int32_t access;
303 std::map<int32_t, int32_t> *uid_access_map;
304
305 for (auto& i: mVehicleAccessControlMap) {
306 property = i.first;
307 uid_access_map = mVehicleAccessControlMap[property];
308 for (auto& j: *uid_access_map) {
309 uid = j.first;
310 access = (*uid_access_map)[uid];
311 switch(access) {
312 case VEHICLE_PROP_ACCESS_READ: perm = "read"; break;
313 case VEHICLE_PROP_ACCESS_WRITE: perm = "write"; break;
314 case VEHICLE_PROP_ACCESS_READ_WRITE: perm = "read/write"; break;
315 default: perm="unknown";
316 }
317 msg.appendFormat("UID %d: property 0x%08x, access %s\n", uid,
318 property, perm.c_str());
319 }
320 }
321}
322
323// Test if the given uid has (read or write) access to the given property. If it
324// does, true is returned and false is returned if it doesn't have access or the
325// property or uid is unknown.
326bool VehiclePropertyAccessControl::testAccess(int32_t property, int32_t uid,
327 bool isWrite) {
328 // Check if the property exists
329 if (mVehicleAccessControlMap.count(property) == 0) {
330 // property was not found
331 return false;
332 }
333
334 // Get the uidAccessMap
335 std::map<int32_t, int32_t>* uidAccessMap =
336 mVehicleAccessControlMap[property];
337
338 // Now check if uid exists
339 if (uidAccessMap->count(uid) == 0) {
340 // uid was not found
341 return false;
342 }
343
344 // Get Access to this Property
345 int32_t access = (*uidAccessMap)[uid];
346
347 // Test if the UID has access to the property
348 if (isWrite) {
349 if ((access == VEHICLE_PROP_ACCESS_WRITE)
350 || (access == VEHICLE_PROP_ACCESS_READ_WRITE)) {
351 return true;
352 } else {
353 return false;
354 }
355 } else {
356 if ((access == VEHICLE_PROP_ACCESS_READ)
357 || (access == VEHICLE_PROP_ACCESS_READ_WRITE)) {
358 return true;
359 } else {
360 return false;
361 }
362 }
363}
364
Keun-young Parkd36a9952016-05-24 10:03:59 -0700365bool VehiclePropertyAccessControl::isAutoGetEnabled(int32_t property) {
366 return mPropertiesWithNoAutoGet.count(property) == 0;
367}
368
Sam Hurstc7152db2016-02-29 09:35:22 -0800369};