summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Lee <rgl@google.com>2014-10-07 16:55:02 +0100
committerRobin Lee <rgl@google.com>2014-10-15 19:04:33 +0000
commit60fd3feecab4336d964ca8e31c7c3220e1afb558 (patch)
tree8f04ab1dbdc80c85f80f0db88bce4e2c25d87195
parent3454f123d0a10bd0ce0760828996aa26c80a8fd4 (diff)
downloadnative-60fd3feecab4336d964ca8e31c7c3220e1afb558.tar.gz
Migrate CA certificates to all users
Copies the /data/misc/keychain/cacert-* directories to all users on the device, whereas previously they were simply copied to user 0. This is a shallow copy so anything that wasn't supposed to be there will disappear. Bug: 17811821 Change-Id: Iae5909ab8d5efdb83c9c8fdf0e10ab7060d022cc
-rw-r--r--cmds/installd/installd.c75
-rw-r--r--cmds/installd/installd.h2
-rw-r--r--cmds/installd/utils.c102
3 files changed, 144 insertions, 35 deletions
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 3078f202ae..933338f908 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -511,52 +511,61 @@ int initialize_directories() {
if (version == 2) {
ALOGD("Upgrading to /data/misc/user directories");
+ char misc_dir[PATH_MAX];
+ snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.path);
+
+ char keychain_added_dir[PATH_MAX];
+ snprintf(keychain_added_dir, PATH_MAX, "%s/keychain/cacerts-added", misc_dir);
+
+ char keychain_removed_dir[PATH_MAX];
+ snprintf(keychain_removed_dir, PATH_MAX, "%s/keychain/cacerts-removed", misc_dir);
+
DIR *dir;
struct dirent *dirent;
- char user_data_dir[PATH_MAX];
-
dir = opendir(user_data_dir);
if (dir != NULL) {
while ((dirent = readdir(dir))) {
- if (dirent->d_type == DT_DIR) {
- const char *name = dirent->d_name;
+ const char *name = dirent->d_name;
- // skip "." and ".."
- if (name[0] == '.') {
- if (name[1] == 0) continue;
- if ((name[1] == '.') && (name[2] == 0)) continue;
- }
+ // skip "." and ".."
+ if (name[0] == '.') {
+ if (name[1] == 0) continue;
+ if ((name[1] == '.') && (name[2] == 0)) continue;
+ }
- // /data/misc/user/<user_id>
- if (ensure_config_user_dirs(atoi(name)) == -1) {
- goto fail;
+ uint32_t user_id = atoi(name);
+
+ // /data/misc/user/<user_id>
+ if (ensure_config_user_dirs(user_id) == -1) {
+ goto fail;
+ }
+
+ char misc_added_dir[PATH_MAX];
+ snprintf(misc_added_dir, PATH_MAX, "%s/user/%s/cacerts-added", misc_dir, name);
+
+ char misc_removed_dir[PATH_MAX];
+ snprintf(misc_removed_dir, PATH_MAX, "%s/user/%s/cacerts-removed", misc_dir, name);
+
+ uid_t uid = multiuser_get_uid(user_id, AID_SYSTEM);
+ gid_t gid = uid;
+ if (access(keychain_added_dir, F_OK) == 0) {
+ if (copy_dir_files(keychain_added_dir, misc_added_dir, uid, gid) != 0) {
+ ALOGE("Some files failed to copy");
+ }
+ }
+ if (access(keychain_removed_dir, F_OK) == 0) {
+ if (copy_dir_files(keychain_removed_dir, misc_removed_dir, uid, gid) != 0) {
+ ALOGE("Some files failed to copy");
}
}
}
closedir(dir);
- }
-
- // Just rename keychain files into user/0; they should already have the right permissions
- char misc_dir[PATH_MAX];
- char keychain_added_dir[PATH_MAX];
- char keychain_removed_dir[PATH_MAX];
- char config_added_dir[PATH_MAX];
- char config_removed_dir[PATH_MAX];
- snprintf(misc_dir, PATH_MAX, "%s/misc", android_data_dir.path);
- snprintf(keychain_added_dir, PATH_MAX, "%s/keychain/cacerts-added", misc_dir);
- snprintf(keychain_removed_dir, PATH_MAX, "%s/keychain/cacerts-removed", misc_dir);
- snprintf(config_added_dir, PATH_MAX, "%s/user/0/cacerts-added", misc_dir);
- snprintf(config_removed_dir, PATH_MAX, "%s/user/0/cacerts-removed", misc_dir);
-
- if (access(keychain_added_dir, F_OK) == 0) {
- if (rename(keychain_added_dir, config_added_dir) != 0) {
- goto fail;
+ if (access(keychain_added_dir, F_OK) == 0) {
+ delete_dir_contents(keychain_added_dir, 1, 0);
}
- }
- if (access(keychain_removed_dir, F_OK) == 0) {
- if (rename(keychain_removed_dir, config_removed_dir) != 0) {
- goto fail;
+ if (access(keychain_removed_dir, F_OK) == 0) {
+ delete_dir_contents(keychain_removed_dir, 1, 0);
}
}
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index a5cad45fde..36c3e8c3f5 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -165,6 +165,8 @@ int delete_dir_contents(const char *pathname,
int delete_dir_contents_fd(int dfd, const char *name);
+int copy_dir_files(const char *srcname, const char *dstname, uid_t owner, gid_t group);
+
int lookup_media_dir(char basepath[PATH_MAX], const char *dir);
int64_t data_disk_free();
diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c
index 60d20de5ba..e381aefe11 100644
--- a/cmds/installd/utils.c
+++ b/cmds/installd/utils.c
@@ -324,6 +324,104 @@ int delete_dir_contents_fd(int dfd, const char *name)
return res;
}
+static int _copy_owner_permissions(int srcfd, int dstfd)
+{
+ struct stat st;
+ if (fstat(srcfd, &st) != 0) {
+ return -1;
+ }
+ if (fchmod(dstfd, st.st_mode) != 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static int _copy_dir_files(int sdfd, int ddfd, uid_t owner, gid_t group)
+{
+ int result = 0;
+ if (_copy_owner_permissions(sdfd, ddfd) != 0) {
+ ALOGE("_copy_dir_files failed to copy dir permissions\n");
+ }
+ if (fchown(ddfd, owner, group) != 0) {
+ ALOGE("_copy_dir_files failed to change dir owner\n");
+ }
+
+ DIR *ds = fdopendir(sdfd);
+ if (ds == NULL) {
+ ALOGE("Couldn't fdopendir: %s\n", strerror(errno));
+ return -1;
+ }
+ struct dirent *de;
+ while ((de = readdir(ds))) {
+ if (de->d_type != DT_REG) {
+ continue;
+ }
+
+ const char *name = de->d_name;
+ int fsfd = openat(sdfd, name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
+ int fdfd = openat(ddfd, name, O_WRONLY | O_NOFOLLOW | O_CLOEXEC | O_CREAT, 0600);
+ if (fsfd == -1 || fdfd == -1) {
+ ALOGW("Couldn't copy %s: %s\n", name, strerror(errno));
+ } else {
+ if (_copy_owner_permissions(fsfd, fdfd) != 0) {
+ ALOGE("Failed to change file permissions\n");
+ }
+ if (fchown(fdfd, owner, group) != 0) {
+ ALOGE("Failed to change file owner\n");
+ }
+
+ char buf[8192];
+ ssize_t size;
+ while ((size = read(fsfd, buf, sizeof(buf))) > 0) {
+ write(fdfd, buf, size);
+ }
+ if (size < 0) {
+ ALOGW("Couldn't copy %s: %s\n", name, strerror(errno));
+ result = -1;
+ }
+ }
+ close(fdfd);
+ close(fsfd);
+ }
+
+ return result;
+}
+
+int copy_dir_files(const char *srcname,
+ const char *dstname,
+ uid_t owner,
+ uid_t group)
+{
+ int res = 0;
+ DIR *ds = NULL;
+ DIR *dd = NULL;
+
+ ds = opendir(srcname);
+ if (ds == NULL) {
+ ALOGE("Couldn't opendir %s: %s\n", srcname, strerror(errno));
+ return -errno;
+ }
+
+ mkdir(dstname, 0600);
+ dd = opendir(dstname);
+ if (dd == NULL) {
+ ALOGE("Couldn't opendir %s: %s\n", dstname, strerror(errno));
+ closedir(ds);
+ return -errno;
+ }
+
+ int sdfd = dirfd(ds);
+ int ddfd = dirfd(dd);
+ if (sdfd != -1 && ddfd != -1) {
+ res = _copy_dir_files(sdfd, ddfd, owner, group);
+ } else {
+ res = -errno;
+ }
+ closedir(dd);
+ closedir(ds);
+ return res;
+}
+
int lookup_media_dir(char basepath[PATH_MAX], const char *dir)
{
DIR *d;
@@ -1019,8 +1117,8 @@ int ensure_config_user_dirs(userid_t userid) {
char path[PATH_MAX];
// writable by system, readable by any app within the same user
- const int uid = (userid * AID_USER) + AID_SYSTEM;
- const int gid = (userid * AID_USER) + AID_EVERYBODY;
+ const int uid = multiuser_get_uid(userid, AID_SYSTEM);
+ const int gid = multiuser_get_uid(userid, AID_EVERYBODY);
// Ensure /data/misc/user/<userid> exists
create_user_config_path(config_user_path, userid);