Index: platform.cc |
diff --git a/platform.cc b/platform.cc |
index 7e9155f7907febc1d1223346d423ca0612476e09..22db6b6c9bfb4139b51289a5db5dcc5829d830fb 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 @@ void Platform::GetPidsForUser(uid_t uid, std::vector<pid_t>* pids) { |
} |
} |
-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 @@ bool Platform::GetUserId(const std::string& user, uid_t* user_id, |
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 @@ bool Platform::GetUserId(const std::string& user, uid_t* user_id, |
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 @@ void Platform::ClearUserKeyring() { |
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 |