cryptohome: Add new platform functions
This is first in a series of CLs to add opencryptoki initialization to cryptohome.
This ones adds new platform functions for
1) changing file/path ownership recursively.
2) creating symlinks.
3) getting group id on a path.
4) executing a binary as a specific effective uid/gid.
(Original patchset by fes@chromium.org. This ones fixes some
minor bugs and contains documentation fixes.)
Change-Id: I424ca11fcb74ca5d3b040dccf0cf82ed8da766cc
BUG=chromium-os:12295
TEST=emerge-x86-mario chromeos-base/chromeos-cryptohome
Review URL: http://codereview.chromium.org/6729012
diff --git a/mock_platform.h b/mock_platform.h
index e8a9be3..31ee451 100644
--- a/mock_platform.h
+++ b/mock_platform.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -36,8 +36,13 @@
MOCK_METHOD2(TerminatePidsWithOpenFiles, bool(const std::string&, bool));
MOCK_METHOD2(TerminatePidsForUser, bool(const uid_t, bool));
MOCK_METHOD3(SetOwnership, bool(const std::string&, uid_t, gid_t));
+ MOCK_METHOD3(SetOwnershipRecursive, bool(const std::string&, uid_t, gid_t));
MOCK_METHOD3(GetUserId, bool(const std::string&, uid_t*, gid_t*));
+ MOCK_METHOD3(GetGroupId, bool(const std::string&, gid_t*));
MOCK_CONST_METHOD1(AmountOfFreeDiskSpace, int64(const std::string&));
+ MOCK_METHOD2(Symlink, bool(const std::string&, const std::string&));
+ MOCK_METHOD4(Exec, bool(const std::string&, const std::vector<std::string>&,
+ uid_t, gid_t));
private:
bool MockGetUserId(const std::string& user, uid_t* user_id, gid_t* group_id) {
diff --git a/platform.cc b/platform.cc
index 7e9155f..22db6b6 100644
--- a/platform.cc
+++ b/platform.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,6 +7,7 @@
#include "platform.h"
#include <errno.h>
+#include <grp.h>
#include <limits.h>
#include <pwd.h>
#include <signal.h>
@@ -14,6 +15,7 @@
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <base/file_util.h>
#include <base/string_util.h>
@@ -337,14 +339,55 @@
}
}
-bool Platform::SetOwnership(const std::string& directory, uid_t user_id,
+bool Platform::SetOwnership(const std::string& path, uid_t user_id,
gid_t group_id) {
- if (chown(directory.c_str(), user_id, group_id)) {
+ if (chown(path.c_str(), user_id, group_id)) {
return false;
}
return true;
}
+bool Platform::SetOwnershipRecursive(const std::string& directory,
+ uid_t user_id,
+ gid_t group_id) {
+ std::vector<std::string> to_recurse;
+ to_recurse.push_back(directory);
+ while (to_recurse.size()) {
+ std::string current_dir = to_recurse.back();
+ to_recurse.pop_back();
+
+ FilePath next_path;
+
+ // Push the subdirectories to the back of the vector
+ file_util::FileEnumerator dir_enumerator(
+ FilePath(current_dir),
+ false, // do not recurse into subdirectories.
+ file_util::FileEnumerator::DIRECTORIES);
+ while (!(next_path = dir_enumerator.Next()).empty()) {
+ to_recurse.push_back(next_path.value());
+ }
+
+ // Handle the files
+ file_util::FileEnumerator file_enumerator(FilePath(current_dir), false,
+ file_util::FileEnumerator::FILES);
+ while (!(next_path = file_enumerator.Next()).empty()) {
+ if (!SetOwnership(next_path.value(), user_id, group_id)) {
+ LOG(ERROR) << "Couldn't change owner (" << user_id << ":" << group_id
+ << ") of path: " << next_path.value().c_str();
+ return false;
+ }
+ }
+
+ // Set permissions on the directory itself
+ if (!SetOwnership(current_dir, user_id, group_id)) {
+ LOG(ERROR) << "Couldn't change owner (" << user_id << ":" << group_id
+ << ") of path: " << current_dir.c_str();
+ return false;
+ }
+ }
+ return true;
+}
+
int Platform::SetMask(int new_mask) {
return umask(new_mask);
}
@@ -353,7 +396,7 @@
gid_t* group_id) {
// Load the passwd entry
long user_name_length = sysconf(_SC_GETPW_R_SIZE_MAX);
- if(user_name_length == -1) {
+ if (user_name_length == -1) {
user_name_length = kDefaultPwnameLength;
}
struct passwd user_info, *user_infop;
@@ -367,6 +410,22 @@
return true;
}
+bool Platform::GetGroupId(const std::string& group, gid_t* group_id) {
+ // Load the group entry
+ long group_name_length = sysconf(_SC_GETGR_R_SIZE_MAX);
+ if (group_name_length == -1) {
+ group_name_length = kDefaultPwnameLength;
+ }
+ struct group group_info, *group_infop;
+ std::vector<char> group_name_buf(group_name_length);
+ if (getgrnam_r(group.c_str(), &group_info, &group_name_buf[0],
+ group_name_length, &group_infop)) {
+ return false;
+ }
+ *group_id = group_info.gr_gid;
+ return true;
+}
+
int64 Platform::AmountOfFreeDiskSpace(const string& path) const {
struct statvfs stats;
if (statvfs(path.c_str(), &stats) != 0) {
@@ -379,4 +438,61 @@
keyctl(KEYCTL_CLEAR, KEY_SPEC_USER_KEYRING);
}
+bool Platform::Symlink(const std::string& from, const std::string& to) {
+ int rc = symlink(from.c_str(), to.c_str());
+ if (rc && rc != EEXIST) {
+ PLOG(ERROR) << "Error creating symbolic link from " << from << " to " << to
+ << ".";
+ return false;
+ }
+ return true;
+}
+
+bool Platform::Exec(const std::string& command,
+ const std::vector<std::string>& args,
+ uid_t uid,
+ gid_t gid) {
+ pid_t child_pid = -1;
+ child_pid = vfork();
+ if (child_pid == 0) {
+ if (gid != static_cast<gid_t>(-1)) {
+ if (setresgid(gid, gid, gid)) {
+ _exit(2);
+ }
+ }
+ if (uid != static_cast<uid_t>(-1)) {
+ if (setresuid(uid, uid, uid)) {
+ _exit(1);
+ }
+ }
+ const char** local_args = (const char**) calloc(args.size() + 1,
+ sizeof(char*));
+ int index = 0;
+ std::vector<std::string>::const_iterator it;
+ for (it = args.begin(); it != args.end(); ++it, ++index) {
+ local_args[index] = const_cast<char*>(it->c_str());
+ }
+ execve(command.c_str(), const_cast<char* const*>(local_args), NULL);
+ PLOG(ERROR) << "Couldn't start the command subprocess.";
+ _exit(3);
+ } else if (child_pid != -1) {
+ int status = 0;
+ do {
+ pid_t term_pid = waitpid(child_pid, &status, WUNTRACED | WCONTINUED);
+ if (term_pid == -1) {
+ return false;
+ }
+ } while (!WIFEXITED(status) && !WIFSIGNALED(status));
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ return true;
+ }
+ PLOG(ERROR) << "Command subprocess exited with a non-zero status. ("
+ << "status = " << WEXITSTATUS(status) << " )";
+ }
+ else {
+ PLOG(ERROR) << "Couldn't spawn a subprocess for command execution.";
+ }
+ return false;
+}
+
} // namespace cryptohome
diff --git a/platform.h b/platform.h
index ee6d862..fad1144 100644
--- a/platform.h
+++ b/platform.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -130,14 +130,26 @@
// pids (OUT) - the list of PIDs
void GetPidsForUser(uid_t uid, std::vector<pid_t>* pids);
+ // Calls the platform chown() function on the given path.
+ //
+ // The path may be a directory or a file.
+ //
+ // Parameters
+ // path - The path to set ownership on
+ // user_id - The user_id to assign ownership to
+ // group_id - The group_id to assign ownership to
+ virtual bool SetOwnership(const std::string& directory, uid_t user_id,
+ gid_t group_id);
+
// Calls the platform chown() function recursively on the directory
//
// Parameters
// directory - The directory to set ownership on
// user_id - The user_id to assign ownership to
// group_id - The group_id to assign ownership to
- virtual bool SetOwnership(const std::string& directory, uid_t user_id,
- gid_t group_id);
+ virtual bool SetOwnershipRecursive(const std::string& directory,
+ uid_t user_id,
+ gid_t group_id);
// Sets the current umask, returning the old mask
//
@@ -154,6 +166,13 @@
virtual bool GetUserId(const std::string& user, uid_t* user_id,
gid_t* group_id);
+ // Returns the group id for a group
+ //
+ // Parameters
+ // group - The group name to query for
+ // group_id (OUT) - The group ID on success
+ virtual bool GetGroupId(const std::string& group, gid_t* group_id);
+
// Return the available disk space in bytes on the volume containing |path|,
// or -1 on failure.
// Code duplicated from Chrome's base::SysInfo::AmountOfFreeDiskSpace().
@@ -165,6 +184,25 @@
// Clears the user keyring
static void ClearUserKeyring();
+ // Creates a symbolic link from one path to the other
+ //
+ // Parameters
+ // from - source path that the symlink points to
+ // to - symlink to create which points to the source path
+ virtual bool Symlink(const std::string& from, const std::string& to);
+
+ // Executes a command with the specified arguments and waits for it to finish
+ //
+ // Parameters
+ // command - string containing the filename of the binary to execute
+ // args - list of arguments to pass to the run the command with
+ // uid - effective user id to run the command with
+ // gid - effective group id to run the command with
+ bool Exec(const std::string& command,
+ const std::vector<std::string>& args,
+ uid_t uid,
+ gid_t gid);
+
// Overrides the default mount options
void set_mount_options(int value) {
mount_options_ = value;