OSDN Git Service

Migrate CA certificates to all users
authorRobin Lee <rgl@google.com>
Tue, 7 Oct 2014 15:55:02 +0000 (16:55 +0100)
committerRobin Lee <rgl@google.com>
Wed, 15 Oct 2014 19:04:33 +0000 (19:04 +0000)
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

cmds/installd/installd.c
cmds/installd/installd.h
cmds/installd/utils.c

index 3078f20..933338f 100644 (file)
@@ -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);
             }
         }
 
index a5cad45..36c3e8c 100644 (file)
@@ -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();
index 60d20de..e381aef 100644 (file)
@@ -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);