blob: 3099b8341f6e69c4b6a2f751ad0ffd922c53ec72 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2** Copyright 2008, 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#include "installd.h"
18
Kenny Root86c95842011-03-31 13:16:12 -070019int create_pkg_path_in_dir(char path[PKG_PATH_MAX],
20 const dir_rec_t* dir,
21 const char* pkgname,
22 const char* postfix)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023{
Kenny Root86c95842011-03-31 13:16:12 -070024 const size_t postfix_len = strlen(postfix);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025
Kenny Root86c95842011-03-31 13:16:12 -070026 const size_t pkgname_len = strlen(pkgname);
27 if (pkgname_len > PKG_NAME_MAX) {
28 return -1;
29 }
30
31 if (is_valid_package_name(pkgname) < 0) {
32 return -1;
33 }
34
35 if ((pkgname_len + dir->len + postfix_len) >= PKG_PATH_MAX) {
36 return -1;
37 }
38
39 char *dst = path;
40 size_t dst_size = PKG_PATH_MAX;
41
42 if (append_and_increment(&dst, dir->path, &dst_size) < 0
43 || append_and_increment(&dst, pkgname, &dst_size) < 0
44 || append_and_increment(&dst, postfix, &dst_size) < 0) {
45 LOGE("Error building APK path");
46 return -1;
47 }
48
49 return 0;
50}
51
52/**
53 * Create the package path name for a given package name with a postfix for
54 * a certain persona. Returns 0 on success, and -1 on failure.
55 */
56int create_pkg_path(char path[PKG_PATH_MAX],
57 const char *pkgname,
58 const char *postfix,
59 uid_t persona)
60{
61 size_t uid_len;
62 char* persona_prefix;
63 if (persona == 0) {
64 persona_prefix = PRIMARY_USER_PREFIX;
65 uid_len = 0;
66 } else {
67 persona_prefix = SECONDARY_USER_PREFIX;
68 uid_len = snprintf(NULL, 0, "%d", persona);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069 }
Kenny Root86c95842011-03-31 13:16:12 -070070
71 const size_t prefix_len = android_data_dir.len + strlen(persona_prefix) + uid_len + 1 /*slash*/;
72 char prefix[prefix_len + 1];
73
74 char *dst = prefix;
75 size_t dst_size = sizeof(prefix);
76
77 if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0
78 || append_and_increment(&dst, persona_prefix, &dst_size) < 0) {
79 LOGE("Error building prefix for APK path");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 return -1;
81 }
82
Kenny Root86c95842011-03-31 13:16:12 -070083 if (persona != 0) {
84 int ret = snprintf(dst, dst_size, "%d/", persona);
85 if (ret < 0 || (size_t) ret != uid_len + 1) {
86 LOGW("Error appending UID to APK path");
87 return -1;
88 }
89 }
90
91 dir_rec_t dir;
92 dir.path = prefix;
93 dir.len = prefix_len;
94
95 return create_pkg_path_in_dir(path, &dir, pkgname, postfix);
96}
97
98/**
Amith Yamasani0b285492011-04-14 17:35:23 -070099 * Create the path name for user data for a certain persona.
100 * Returns 0 on success, and -1 on failure.
101 */
102int create_persona_path(char path[PKG_PATH_MAX],
103 uid_t persona)
104{
105 size_t uid_len;
106 char* persona_prefix;
107 if (persona == 0) {
108 persona_prefix = PRIMARY_USER_PREFIX;
109 uid_len = 0;
110 } else {
111 persona_prefix = SECONDARY_USER_PREFIX;
112 uid_len = snprintf(NULL, 0, "%d", persona);
113 }
114
115 char *dst = path;
116 size_t dst_size = PKG_PATH_MAX;
117
118 if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0
119 || append_and_increment(&dst, persona_prefix, &dst_size) < 0) {
120 LOGE("Error building prefix for user path");
121 return -1;
122 }
123
124 if (persona != 0) {
125 if (dst_size < uid_len + 1) {
126 LOGE("Error building user path");
127 return -1;
128 }
129 int ret = snprintf(dst, dst_size, "%d", persona);
130 if (ret < 0 || (size_t) ret != uid_len) {
131 LOGE("Error appending persona id to path");
132 return -1;
133 }
134 }
135 return 0;
136}
137
138/**
Kenny Root86c95842011-03-31 13:16:12 -0700139 * Checks whether the package name is valid. Returns -1 on error and
140 * 0 on success.
141 */
142int is_valid_package_name(const char* pkgname) {
143 const char *x = pkgname;
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800144 int alpha = -1;
Kenny Root86c95842011-03-31 13:16:12 -0700145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 while (*x) {
147 if (isalnum(*x) || (*x == '_')) {
148 /* alphanumeric or underscore are fine */
149 } else if (*x == '.') {
150 if ((x == pkgname) || (x[1] == '.') || (x[1] == 0)) {
151 /* periods must not be first, last, or doubled */
152 LOGE("invalid package name '%s'\n", pkgname);
153 return -1;
154 }
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800155 } else if (*x == '-') {
156 /* Suffix -X is fine to let versioning of packages.
157 But whatever follows should be alphanumeric.*/
158 alpha = 1;
Kenny Root86c95842011-03-31 13:16:12 -0700159 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 /* anything not A-Z, a-z, 0-9, _, or . is invalid */
161 LOGE("invalid package name '%s'\n", pkgname);
162 return -1;
163 }
Kenny Root86c95842011-03-31 13:16:12 -0700164
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 x++;
166 }
Kenny Root86c95842011-03-31 13:16:12 -0700167
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800168 if (alpha == 1) {
169 // Skip current character
170 x++;
171 while (*x) {
172 if (!isalnum(*x)) {
173 LOGE("invalid package name '%s' should include only numbers after -\n", pkgname);
174 return -1;
175 }
176 x++;
177 }
178 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 return 0;
181}
182
183static int _delete_dir_contents(DIR *d, const char *ignore)
184{
185 int result = 0;
186 struct dirent *de;
187 int dfd;
188
189 dfd = dirfd(d);
190
191 if (dfd < 0) return -1;
192
193 while ((de = readdir(d))) {
194 const char *name = de->d_name;
195
196 /* skip the ignore name if provided */
197 if (ignore && !strcmp(name, ignore)) continue;
198
199 if (de->d_type == DT_DIR) {
200 int r, subfd;
201 DIR *subdir;
202
203 /* always skip "." and ".." */
204 if (name[0] == '.') {
205 if (name[1] == 0) continue;
206 if ((name[1] == '.') && (name[2] == 0)) continue;
207 }
208
209 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
210 if (subfd < 0) {
Kenny Root50871522010-08-04 09:14:01 -0700211 LOGE("Couldn't openat %s: %s\n", name, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 result = -1;
213 continue;
214 }
215 subdir = fdopendir(subfd);
216 if (subdir == NULL) {
Kenny Root50871522010-08-04 09:14:01 -0700217 LOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 close(subfd);
219 result = -1;
220 continue;
221 }
222 if (_delete_dir_contents(subdir, 0)) {
223 result = -1;
224 }
225 closedir(subdir);
226 if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) {
Kenny Root50871522010-08-04 09:14:01 -0700227 LOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 result = -1;
229 }
230 } else {
231 if (unlinkat(dfd, name, 0) < 0) {
Kenny Root50871522010-08-04 09:14:01 -0700232 LOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 result = -1;
234 }
235 }
236 }
237
238 return result;
239}
240
241int delete_dir_contents(const char *pathname,
242 int also_delete_dir,
243 const char *ignore)
244{
245 int res = 0;
246 DIR *d;
247
248 d = opendir(pathname);
249 if (d == NULL) {
Kenny Root50871522010-08-04 09:14:01 -0700250 LOGE("Couldn't opendir %s: %s\n", pathname, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 return -errno;
252 }
253 res = _delete_dir_contents(d, ignore);
254 closedir(d);
255 if (also_delete_dir) {
256 if (rmdir(pathname)) {
Kenny Root50871522010-08-04 09:14:01 -0700257 LOGE("Couldn't rmdir %s: %s\n", pathname, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 res = -1;
259 }
260 }
261 return res;
262}
263
264int delete_dir_contents_fd(int dfd, const char *name)
265{
266 int fd, res;
267 DIR *d;
268
269 fd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
270 if (fd < 0) {
Kenny Root50871522010-08-04 09:14:01 -0700271 LOGE("Couldn't openat %s: %s\n", name, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 return -1;
273 }
274 d = fdopendir(fd);
275 if (d == NULL) {
Kenny Root50871522010-08-04 09:14:01 -0700276 LOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 close(fd);
278 return -1;
279 }
280 res = _delete_dir_contents(d, 0);
281 closedir(d);
282 return res;
283}
Kenny Root86c95842011-03-31 13:16:12 -0700284
285/**
286 * Checks whether a path points to a system app (.apk file). Returns 0
287 * if it is a system app or -1 if it is not.
288 */
289int validate_system_app_path(const char* path) {
290 size_t i;
291
292 for (i = 0; i < android_system_dirs.count; i++) {
293 const size_t dir_len = android_system_dirs.dirs[i].len;
294 if (!strncmp(path, android_system_dirs.dirs[i].path, dir_len)) {
295 if (path[dir_len] == '.' || strchr(path + dir_len, '/') != NULL) {
296 LOGE("invalid system apk path '%s' (trickery)\n", path);
297 return -1;
298 }
299 return 0;
300 }
301 }
302
303 return -1;
304}
305
306/**
307 * Get the contents of a environment variable that contains a path. Caller
308 * owns the string that is inserted into the directory record. Returns
309 * 0 on success and -1 on error.
310 */
311int get_path_from_env(dir_rec_t* rec, const char* var) {
312 const char* path = getenv(var);
313 int ret = get_path_from_string(rec, path);
314 if (ret < 0) {
315 LOGW("Problem finding value for environment variable %s\n", var);
316 }
317 return ret;
318}
319
320/**
321 * Puts the string into the record as a directory. Appends '/' to the end
322 * of all paths. Caller owns the string that is inserted into the directory
323 * record. A null value will result in an error.
324 *
325 * Returns 0 on success and -1 on error.
326 */
327int get_path_from_string(dir_rec_t* rec, const char* path) {
328 if (path == NULL) {
329 return -1;
330 } else {
331 const size_t path_len = strlen(path);
332 if (path_len <= 0) {
333 return -1;
334 }
335
336 // Make sure path is absolute.
337 if (path[0] != '/') {
338 return -1;
339 }
340
341 if (path[path_len - 1] == '/') {
342 // Path ends with a forward slash. Make our own copy.
343
344 rec->path = strdup(path);
345 if (rec->path == NULL) {
346 return -1;
347 }
348
349 rec->len = path_len;
350 } else {
351 // Path does not end with a slash. Generate a new string.
352 char *dst;
353
354 // Add space for slash and terminating null.
355 size_t dst_size = path_len + 2;
356
357 rec->path = malloc(dst_size);
358 if (rec->path == NULL) {
359 return -1;
360 }
361
362 dst = rec->path;
363
364 if (append_and_increment(&dst, path, &dst_size) < 0
365 || append_and_increment(&dst, "/", &dst_size)) {
366 LOGE("Error canonicalizing path");
367 return -1;
368 }
369
370 rec->len = dst - rec->path;
371 }
372 }
373 return 0;
374}
375
376int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) {
377 dst->len = src->len + strlen(suffix);
378 const size_t dstSize = dst->len + 1;
379 dst->path = (char*) malloc(dstSize);
380
381 if (dst->path == NULL
382 || snprintf(dst->path, dstSize, "%s%s", src->path, suffix)
383 != (ssize_t) dst->len) {
384 LOGE("Could not allocate memory to hold appended path; aborting\n");
385 return -1;
386 }
387
388 return 0;
389}
390
391/**
392 * Check whether path points to a valid path for an APK file. An ASEC
393 * directory is allowed to have one level of subdirectory names. Returns -1
394 * when an invalid path is encountered and 0 when a valid path is encountered.
395 */
396int validate_apk_path(const char *path)
397{
398 int allowsubdir = 0;
399 char *subdir = NULL;
400 size_t dir_len;
401 size_t path_len;
402
403 if (!strncmp(path, android_app_dir.path, android_app_dir.len)) {
404 dir_len = android_app_dir.len;
405 } else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) {
406 dir_len = android_app_private_dir.len;
407 } else if (!strncmp(path, android_asec_dir.path, android_asec_dir.len)) {
408 dir_len = android_asec_dir.len;
409 allowsubdir = 1;
410 } else {
411 LOGE("invalid apk path '%s' (bad prefix)\n", path);
412 return -1;
413 }
414
415 path_len = strlen(path);
416
417 /*
418 * Only allow the path to have a subdirectory if it's been marked as being allowed.
419 */
420 if ((subdir = strchr(path + dir_len, '/')) != NULL) {
421 ++subdir;
422 if (!allowsubdir
423 || (path_len > (size_t) (subdir - path) && (strchr(subdir, '/') != NULL))) {
424 LOGE("invalid apk path '%s' (subdir?)\n", path);
425 return -1;
426 }
427 }
428
429 /*
430 * Directories can't have a period directly after the directory markers
431 * to prevent ".."
432 */
433 if (path[dir_len] == '.'
434 || (subdir != NULL && ((*subdir == '.') || (strchr(subdir, '/') != NULL)))) {
435 LOGE("invalid apk path '%s' (trickery)\n", path);
436 return -1;
437 }
438
439 return 0;
440}
441
442int append_and_increment(char** dst, const char* src, size_t* dst_size) {
443 ssize_t ret = strlcpy(*dst, src, *dst_size);
444 if (ret < 0 || (size_t) ret >= *dst_size) {
445 return -1;
446 }
447 *dst += ret;
448 *dst_size -= ret;
449 return 0;
450}
Amith Yamasani0b285492011-04-14 17:35:23 -0700451
452char *build_string2(char *s1, char *s2) {
453 if (s1 == NULL || s2 == NULL) return NULL;
454
455 int len_s1 = strlen(s1);
456 int len_s2 = strlen(s2);
457 int len = len_s1 + len_s2 + 1;
458 char *result = malloc(len);
459 if (result == NULL) return NULL;
460
461 strcpy(result, s1);
462 strcpy(result + len_s1, s2);
463
464 return result;
465}
466
467char *build_string3(char *s1, char *s2, char *s3) {
468 if (s1 == NULL || s2 == NULL || s3 == NULL) return NULL;
469
470 int len_s1 = strlen(s1);
471 int len_s2 = strlen(s2);
472 int len_s3 = strlen(s3);
473 int len = len_s1 + len_s2 + len_s3 + 1;
474 char *result = malloc(len);
475 if (result == NULL) return NULL;
476
477 strcpy(result, s1);
478 strcpy(result + len_s1, s2);
479 strcpy(result + len_s1 + len_s2, s3);
480
481 return result;
482}