Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(552)

Side by Side Diff: mount.cc

Issue 2645008: Update on feedback, update dbus API, add unit tests. TEST=manual,unit,BVT BUG=3628 323 (Closed) Base URL: ssh://git@chromiumos-git/cryptohome.git
Patch Set: Address second round of feedback. Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « mount.h ('k') | mount_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved. 1 // Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // Contains the implementation of class Mount 5 // Contains the implementation of class Mount
6 6
7 // TODO(fes): Use correct ordering of file includes once the platform-specific 7 #include "mount.h"
8 // calls are moved into a separate file. Right now, this is required in order
9 // to avoid redefinitions.
10 #include "base/file_util.h"
11 #include "base/logging.h"
12 #include "base/platform_thread.h"
13 #include "base/time.h"
14 #include "base/string_util.h"
15 #include "chromeos/utility.h"
16 #include "cryptohome/cryptohome_common.h"
17 #include "cryptohome/mount.h"
18 #include "cryptohome/username_passkey.h"
19 8
20 extern "C" {
21 #include <ecryptfs.h>
22 #include <keyutils.h>
23 }
24 #include <dirent.h>
25 #include <errno.h> 9 #include <errno.h>
26 #include <openssl/err.h> 10
27 #include <openssl/evp.h> 11 #include <base/file_util.h>
28 #include <openssl/rand.h> 12 #include <base/logging.h>
29 #include <openssl/sha.h> 13 #include <base/platform_thread.h>
30 #include <pwd.h> 14 #include <base/time.h>
31 #include <signal.h> 15 #include <base/string_util.h>
32 #include <sys/mount.h> 16 #include <chromeos/utility.h>
33 #include <sys/stat.h> 17
34 #include <sys/types.h> 18 #include "crypto.h"
19 #include "cryptohome_common.h"
20 #include "platform.h"
21 #include "username_passkey.h"
35 22
36 using std::string; 23 using std::string;
37 24
38 namespace cryptohome { 25 namespace cryptohome {
39 26
40 const string kDefaultEntropySource = "/dev/urandom"; 27 const std::string kDefaultHomeDir = "/home/chronos/user";
41 const string kDefaultHomeDir = "/home/chronos/user"; 28 const std::string kDefaultShadowRoot = "/home/.shadow";
42 const int kDefaultMountOptions = MS_NOEXEC | MS_NOSUID | MS_NODEV; 29 const std::string kDefaultSharedUser = "chronos";
43 const string kDefaultShadowRoot = "/home/.shadow"; 30 const std::string kDefaultSkeletonSource = "/etc/skel";
44 const string kDefaultSharedUser = "chronos"; 31 // TODO(fes): Remove once UI for BWSI switches to MountGuest()
45 const string kDefaultSkeletonSource = "/etc/skel"; 32 const std::string kIncognitoUser = "incognito";
46 const string kIncognitoUser = "incognito";
47 const string kMtab = "/etc/mtab";
48 const string kOpenSSLMagic = "Salted__";
49 const std::string kProcDir = "/proc";
50 33
51 Mount::Mount() 34 Mount::Mount()
52 : default_user_(-1), 35 : default_user_(-1),
53 default_group_(-1), 36 default_group_(-1),
54 default_username_(kDefaultSharedUser), 37 default_username_(kDefaultSharedUser),
55 entropy_source_(kDefaultEntropySource),
56 home_dir_(kDefaultHomeDir), 38 home_dir_(kDefaultHomeDir),
57 shadow_root_(kDefaultShadowRoot), 39 shadow_root_(kDefaultShadowRoot),
58 skel_source_(kDefaultSkeletonSource), 40 skel_source_(kDefaultSkeletonSource),
59 system_salt_(), 41 system_salt_(),
60 set_vault_ownership_(true) { 42 set_vault_ownership_(true),
61 } 43 default_crypto_(new Crypto()),
62 44 crypto_(default_crypto_.get()),
63 Mount::Mount(const std::string& username, const std::string& entropy_source, 45 default_platform_(new Platform()),
64 const std::string& home_dir, const std::string& shadow_root, 46 platform_(default_platform_.get()) {
65 const std::string& skel_source)
66 : default_user_(-1),
67 default_group_(-1),
68 default_username_(username),
69 entropy_source_(entropy_source),
70 home_dir_(home_dir),
71 shadow_root_(shadow_root),
72 skel_source_(skel_source),
73 system_salt_(),
74 set_vault_ownership_(true) {
75 } 47 }
76 48
77 Mount::~Mount() { 49 Mount::~Mount() {
78 } 50 }
79 51
80 bool Mount::Init() { 52 bool Mount::Init() {
81 bool result = true; 53 bool result = true;
82 54
83 // Load the passwd entry for the shared user 55 // Get the user id and group id of the default user
84 struct passwd* user_info = getpwnam(default_username_.c_str()); 56 if (!platform_->GetUserId(default_username_, &default_user_,
85 if (user_info) { 57 &default_group_)) {
86 // Store the user's uid/gid for later use in changing vault ownership
87 default_user_ = user_info->pw_uid;
88 default_group_ = user_info->pw_gid;
89 } else {
90 result = false; 58 result = false;
91 } 59 }
92 60
93 // One-time load of the global system salt (used in generating username 61 // One-time load of the global system salt (used in generating username
94 // hashes) 62 // hashes)
95 if (!LoadFileBytes(FilePath(StringPrintf("%s/salt", shadow_root_.c_str())), 63 if (!LoadFileBytes(FilePath(StringPrintf("%s/salt", shadow_root_.c_str())),
96 system_salt_)) { 64 &system_salt_)) {
97 result = false; 65 result = false;
98 } 66 }
99 67
100 return result; 68 return result;
101 } 69 }
102 70
103 bool Mount::EnsureCryptohome(const Credentials& credentials, bool* created) { 71 bool Mount::EnsureCryptohome(const Credentials& credentials, bool* created) {
104 // If the user has an old-style cryptohome, delete it 72 // If the user has an old-style cryptohome, delete it
105 FilePath old_image_path(StringPrintf("%s/image", 73 FilePath old_image_path(StringPrintf("%s/image",
106 GetUserDirectory(credentials).c_str())); 74 GetUserDirectory(credentials).c_str()));
(...skipping 12 matching lines...) Expand all
119 return result; 87 return result;
120 } 88 }
121 if (created) { 89 if (created) {
122 *created = false; 90 *created = false;
123 } 91 }
124 return true; 92 return true;
125 } 93 }
126 94
127 bool Mount::MountCryptohome(const Credentials& credentials, int index, 95 bool Mount::MountCryptohome(const Credentials& credentials, int index,
128 MountError* mount_error) { 96 MountError* mount_error) {
129 std::string username = credentials.GetFullUsername(); 97 std::string username = credentials.GetFullUsernameString();
130 if (username.compare(kIncognitoUser) == 0) { 98 if (username.compare(kIncognitoUser) == 0) {
131 // TODO(fes): Have incognito set error conditions? 99 // TODO(fes): Have guest set error conditions?
132 if (mount_error) { 100 if (mount_error) {
133 *mount_error = MOUNT_ERROR_NONE; 101 *mount_error = MOUNT_ERROR_NONE;
134 } 102 }
135 return MountIncognitoCryptohome(); 103 return MountGuestCryptohome();
136 } 104 }
137 105
138 bool created = false; 106 bool created = false;
139 if (!EnsureCryptohome(credentials, &created)) { 107 if (!EnsureCryptohome(credentials, &created)) {
140 LOG(ERROR) << "Error creating cryptohome."; 108 LOG(ERROR) << "Error creating cryptohome.";
141 if (mount_error) { 109 if (mount_error) {
142 *mount_error = MOUNT_ERROR_FATAL; 110 *mount_error = MOUNT_ERROR_FATAL;
143 } 111 }
144 return false; 112 return false;
145 } 113 }
146 114
147 FilePath user_key_file(GetUserKeyFile(credentials, index)); 115 // Attempt to unwrap the vault keyset with the specified credentials
148
149 // Retrieve the user's salt for the key index
150 SecureBlob user_salt = GetUserSalt(credentials, index);
151
152 // Generate the passkey wrapper (key encryption key)
153 SecureBlob passkey_wrapper =
154 PasskeyToWrapper(credentials.GetPasskey(), user_salt, 1);
155
156 // Attempt to unwrap the master key at the index with the passkey wrapper
157 VaultKeyset vault_keyset; 116 VaultKeyset vault_keyset;
158 bool mount_result = UnwrapMasterKey(user_key_file, passkey_wrapper, 117 if (!UnwrapVaultKeyset(credentials, index, &vault_keyset, mount_error)) {
159 &vault_keyset);
160
161 if (!mount_result) {
162 if (mount_error) {
163 *mount_error = Mount::MOUNT_ERROR_KEY_FAILURE;
164 }
165 return false; 118 return false;
166 } 119 }
167 120
121 crypto_->ClearKeyset();
122
168 // Add the decrypted key to the keyring so that ecryptfs can use it 123 // Add the decrypted key to the keyring so that ecryptfs can use it
169 string key_signature, fnek_signature; 124 string key_signature, fnek_signature;
170 if (!AddKeyToEcryptfsKeyring(vault_keyset, &key_signature, &fnek_signature)) { 125 if (!crypto_->AddKeyset(vault_keyset, &key_signature, &fnek_signature)) {
171 LOG(ERROR) << "Cryptohome mount failed because of keyring failure."; 126 LOG(INFO) << "Cryptohome mount failed because of keyring failure.";
172 if (mount_error) { 127 if (mount_error) {
173 *mount_error = MOUNT_ERROR_FATAL; 128 *mount_error = MOUNT_ERROR_FATAL;
174 } 129 }
175 return false; 130 return false;
176 } 131 }
177 132
178 // Specify the ecryptfs options for mounting the user's cryptohome 133 // Specify the ecryptfs options for mounting the user's cryptohome
179 string ecryptfs_options = StringPrintf("ecryptfs_cipher=aes" 134 string ecryptfs_options = StringPrintf("ecryptfs_cipher=aes"
180 ",ecryptfs_key_bytes=%d" 135 ",ecryptfs_key_bytes=%d"
181 ",ecryptfs_fnek_sig=%s,ecryptfs_sig=%s" 136 ",ecryptfs_fnek_sig=%s,ecryptfs_sig=%s"
182 ",ecryptfs_unlink_sigs", 137 ",ecryptfs_unlink_sigs",
183 CRYPTOHOME_AES_KEY_BYTES, 138 CRYPTOHOME_AES_KEY_BYTES,
184 fnek_signature.c_str(), 139 fnek_signature.c_str(),
185 key_signature.c_str()); 140 key_signature.c_str());
186 141
187 // TODO(fes): mount(1) -> mount(2): how to issue "user" 142 // Mount cryptohome
188 string vault_path = GetUserVaultPath(credentials); 143 string vault_path = GetUserVaultPath(credentials);
189 // Attempt to mount the user's cryptohome 144 if (!platform_->Mount(vault_path, home_dir_, "ecryptfs", ecryptfs_options)) {
190 if (mount(vault_path.c_str(), home_dir_.c_str(), 145 LOG(INFO) << "Cryptohome mount failed: " << errno << " for vault: "
191 "ecryptfs", kDefaultMountOptions, ecryptfs_options.c_str())) {
192 LOG(ERROR) << "Cryptohome mount failed: " << errno << " for vault: "
193 << vault_path; 146 << vault_path;
194 if (mount_error) { 147 if (mount_error) {
195 *mount_error = MOUNT_ERROR_FATAL; 148 *mount_error = MOUNT_ERROR_FATAL;
196 } 149 }
197 return false; 150 return false;
198 } 151 }
199 152
200 if (created) { 153 if (created) {
201 CopySkeletonForUser(credentials); 154 CopySkeletonForUser(credentials);
202 } 155 }
203 156
204 if (mount_error) { 157 if (mount_error) {
205 *mount_error = MOUNT_ERROR_NONE; 158 *mount_error = MOUNT_ERROR_NONE;
206 } 159 }
207 return true; 160 return true;
208 } 161 }
209 162
210 bool Mount::UnmountCryptohome() { 163 bool Mount::UnmountCryptohome() {
211 // Try an immediate unmount 164 // Try an immediate unmount
212 bool was_busy; 165 bool was_busy;
213 if (!Unmount(home_dir_.c_str(), false, &was_busy)) { 166 if (!platform_->Unmount(home_dir_, false, &was_busy)) {
214 // If the unmount fails, do a lazy unmount
215 Unmount(home_dir_.c_str(), true, NULL);
216 if (was_busy) { 167 if (was_busy) {
217 // Signal processes to close 168 // Signal processes to close
218 if (TerminatePidsWithOpenFiles(home_dir_, false)) { 169 if (platform_->TerminatePidsWithOpenFiles(home_dir_, false)) {
219 // Then we had to send a SIGINT to some processes with open files. Give 170 // Then we had to send a SIGINT to some processes with open files. Give
220 // a "grace" period before killing with a SIGKILL. 171 // a "grace" period before killing with a SIGKILL.
221 // TODO(fes): This isn't ideal, nor is it accurate (a static sleep can't 172 // TODO(fes): This isn't ideal, nor is it accurate (a static sleep can't
222 // guarantee that processes will clean up in time). If we switch to VFS 173 // guarantee that processes will clean up in time). If we switch to VFS
223 // namespace-based mounts, then we can get away from this construct. 174 // namespace-based mounts, then we can get away from this construct.
224 PlatformThread::Sleep(100); 175 PlatformThread::Sleep(100);
225 sync(); 176 sync();
226 if (TerminatePidsWithOpenFiles(home_dir_, true)) { 177 if (platform_->TerminatePidsWithOpenFiles(home_dir_, true)) {
227 PlatformThread::Sleep(100); 178 PlatformThread::Sleep(100);
228 } 179 }
229 } 180 }
230 } 181 }
182 // Failed to unmount immediately, do a lazy unmount
183 platform_->Unmount(home_dir_, true, NULL);
231 sync(); 184 sync();
232 // TODO(fes): This should return an error condition if it is still mounted. 185 // TODO(fes): This should return an error condition if it is still mounted.
233 // Right now it doesn't, since it should get cleaned up outside of 186 // Right now it doesn't, since it should get cleaned up outside of
234 // cryptohome since we failed over to a lazy unmount 187 // cryptohome since we failed over to a lazy unmount
235 } 188 }
236 189
237 // TODO(fes): Do we need to keep this behavior? 190 // TODO(fes): Do we need to keep this behavior?
238 //TerminatePidsForUser(default_user_, true); 191 //TerminatePidsForUser(default_user_, true);
239 192
240 // Clear the user keyring if the unmount was successful 193 // Clear the user keyring if the unmount was successful
241 keyctl(KEYCTL_CLEAR, KEY_SPEC_USER_KEYRING); 194 crypto_->ClearKeyset();
242 195
243 return true; 196 return true;
244 } 197 }
245 198
246 bool Mount::RemoveCryptohome(const Credentials& credentials) { 199 bool Mount::RemoveCryptohome(const Credentials& credentials) {
247 std::string user_dir = GetUserDirectory(credentials); 200 std::string user_dir = GetUserDirectory(credentials);
248 CHECK(user_dir.length() > (shadow_root_.length() + 1)); 201 CHECK(user_dir.length() > (shadow_root_.length() + 1));
249 202
250 return file_util::Delete(FilePath(user_dir), true); 203 return file_util::Delete(FilePath(user_dir), true);
251 } 204 }
252 205
253 bool Mount::IsCryptohomeMounted() { 206 bool Mount::IsCryptohomeMounted() {
254 // Trivial string match from /etc/mtab to see if the cryptohome mount point is 207 return platform_->IsDirectoryMounted(home_dir_);
255 // listed. This works because Chrome OS is a controlled environment and the
256 // only way /home/chronos/user should be mounted is if cryptohome mounted it.
257 string contents;
258 if (file_util::ReadFileToString(FilePath(kMtab), &contents)) {
259 if (contents.find(StringPrintf(" %s ", home_dir_.c_str()).c_str())
260 != string::npos) {
261 return true;
262 }
263 }
264 return false;
265 } 208 }
266 209
267 bool Mount::IsCryptohomeMountedForUser(const Credentials& credentials) { 210 bool Mount::IsCryptohomeMountedForUser(const Credentials& credentials) {
268 // Trivial string match from /etc/mtab to see if the cryptohome mount point 211 return platform_->IsDirectoryMountedWith(home_dir_,
269 // and the user's vault path are present. Assumes this user is mounted if it 212 GetUserVaultPath(credentials));
270 // finds both. This will need to change if simultaneous login is implemented.
271 string contents;
272 if (file_util::ReadFileToString(FilePath(kMtab), &contents)) {
273 FilePath vault_path(GetUserVaultPath(credentials));
274 if ((contents.find(StringPrintf(" %s ", home_dir_.c_str()).c_str())
275 != string::npos)
276 && (contents.find(StringPrintf("%s ",
277 vault_path.value().c_str()).c_str())
278 != string::npos)) {
279 return true;
280 }
281 }
282 return false;
283 } 213 }
284 214
285 bool Mount::CreateCryptohome(const Credentials& credentials, int index) { 215 bool Mount::CreateCryptohome(const Credentials& credentials, int index) {
286 // Save the current umask 216 int original_mask = platform_->SetMask(kDefaultUmask);
287 mode_t original_mask = umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH
288 | S_IXOTH);
289 217
290 // Create the user's entry in the shadow root 218 // Create the user's entry in the shadow root
291 FilePath user_dir(GetUserDirectory(credentials)); 219 FilePath user_dir(GetUserDirectory(credentials));
292 file_util::CreateDirectory(user_dir); 220 file_util::CreateDirectory(user_dir);
293 221
294 // Generates a new master key and salt at the given index 222 // Generates a new master key and salt at the given index
295 if (!CreateMasterKey(credentials, index)) { 223 if (!CreateMasterKey(credentials, index)) {
296 umask(original_mask); 224 platform_->SetMask(original_mask);
297 return false; 225 return false;
298 } 226 }
299 227
300 // Create the user's path and set the proper ownership 228 // Create the user's path and set the proper ownership
301 FilePath vault_path(GetUserVaultPath(credentials)); 229 std::string vault_path = GetUserVaultPath(credentials);
302 if (!file_util::CreateDirectory(vault_path)) { 230 if (!file_util::CreateDirectory(FilePath(vault_path))) {
303 LOG(ERROR) << "Couldn't create vault path: " << vault_path.value().c_str(); 231 LOG(ERROR) << "Couldn't create vault path: " << vault_path.c_str();
304 umask(original_mask); 232 platform_->SetMask(original_mask);
305 return false; 233 return false;
306 } 234 }
307 if (set_vault_ownership_) { 235 if (set_vault_ownership_) {
308 // TODO(fes): Move platform-specific calls to a separate class 236 if (!platform_->SetOwnership(vault_path, default_user_, default_group_)) {
309 if (chown(vault_path.value().c_str(), default_user_, default_group_)) {
310 LOG(ERROR) << "Couldn't change owner (" << default_user_ << ":" 237 LOG(ERROR) << "Couldn't change owner (" << default_user_ << ":"
311 << default_group_ << ") of vault path: " 238 << default_group_ << ") of vault path: "
312 << vault_path.value().c_str(); 239 << vault_path.c_str();
313 umask(original_mask); 240 platform_->SetMask(original_mask);
314 return false; 241 return false;
315 } 242 }
316 } 243 }
317 244
318 // Restore the umask 245 // Restore the umask
319 umask(original_mask); 246 platform_->SetMask(original_mask);
320 return true; 247 return true;
321 } 248 }
322 249
323 bool Mount::TestCredentials(const Credentials& credentials) { 250 bool Mount::TestCredentials(const Credentials& credentials) {
324 // Iterate over the keys in the user's entry in the shadow root to see if 251 // Iterate over the keys in the user's entry in the shadow root to see if
325 // these credentials successfully decrypt any 252 // these credentials successfully decrypt any
326 for (int index = 0; /* loop forever */; index++) { 253 for (int index = 0; /* loop forever */; index++) {
327 FilePath user_key_file(GetUserKeyFile(credentials, index)); 254 MountError mount_error;
328 if (!file_util::AbsolutePath(&user_key_file)) { 255 VaultKeyset vault_keyset;
256 if (UnwrapVaultKeyset(credentials, index, &vault_keyset, &mount_error)) {
257 return true;
258 } else if (mount_error != Mount::MOUNT_ERROR_KEY_FAILURE) {
329 break; 259 break;
330 } 260 }
331
332 SecureBlob user_salt = GetUserSalt(credentials, index);
333
334 SecureBlob passkey_wrapper = PasskeyToWrapper(credentials.GetPasskey(),
335 user_salt, 1);
336
337 VaultKeyset vault_keyset;
338 if (UnwrapMasterKey(user_key_file, passkey_wrapper, &vault_keyset)) {
339 return true;
340 }
341 } 261 }
342 return false; 262 return false;
343 } 263 }
344 264
265 bool Mount::UnwrapVaultKeyset(const Credentials& credentials, int index,
266 VaultKeyset* vault_keyset, MountError* error) {
267 // Generate the passkey wrapper (key encryption key)
268 SecureBlob user_salt;
269 GetUserSalt(credentials, index, false, &user_salt);
270 if (user_salt.size() == 0) {
271 if (error) {
272 *error = MOUNT_ERROR_FATAL;
273 }
274 return false;
275 }
276 SecureBlob passkey;
277 credentials.GetPasskey(&passkey);
278 SecureBlob passkey_wrapper;
279 crypto_->PasskeyToWrapper(passkey, user_salt, 1, &passkey_wrapper);
280
281 // Load the encrypted keyset
282 FilePath user_key_file(GetUserKeyFile(credentials, index));
283 if (!file_util::PathExists(user_key_file)) {
284 if (error) {
285 *error = MOUNT_ERROR_NO_SUCH_FILE;
286 }
287 return false;
288 }
289 SecureBlob cipher_text;
290 if (!LoadFileBytes(user_key_file, &cipher_text)) {
291 if (error) {
292 *error = MOUNT_ERROR_FATAL;
293 }
294 return false;
295 }
296
297 // Attempt to unwrap the master key at the index with the passkey wrapper
298 if (!crypto_->UnwrapVaultKeyset(cipher_text, passkey_wrapper, vault_keyset)) {
299 if (error) {
300 *error = Mount::MOUNT_ERROR_KEY_FAILURE;
301 }
302 return false;
303 }
304
305 return true;
306 }
307
345 bool Mount::MigratePasskey(const Credentials& credentials, 308 bool Mount::MigratePasskey(const Credentials& credentials,
346 const char* old_key) { 309 const char* old_key) {
347 // Iterate over the keys in the user's entry in the shadow root to see if 310 // Iterate over the keys in the user's entry in the shadow root to see if
348 // these credentials successfully decrypt any 311 // these credentials successfully decrypt any
349 std::string username = credentials.GetFullUsername(); 312 std::string username = credentials.GetFullUsernameString();
350 UsernamePasskey old_credentials(username.c_str(), username.length(), 313 UsernamePasskey old_credentials(username.c_str(),
351 old_key, strlen(old_key)); 314 SecureBlob(old_key, strlen(old_key)));
352 for (int index = 0; /* loop forever */; index++) { 315 for (int index = 0; /* loop forever */; index++) {
353 FilePath user_key_file(GetUserKeyFile(old_credentials, index)); 316 // Attempt to unwrap the vault keyset with the specified credentials
354 if (!file_util::AbsolutePath(&user_key_file)) { 317 MountError mount_error;
355 break;
356 }
357
358 SecureBlob user_salt = GetUserSalt(old_credentials, index);
359
360 SecureBlob passkey_wrapper = PasskeyToWrapper(old_credentials.GetPasskey(),
361 user_salt, 1);
362
363 VaultKeyset vault_keyset; 318 VaultKeyset vault_keyset;
364 if (UnwrapMasterKey(user_key_file, passkey_wrapper, &vault_keyset)) { 319 if (UnwrapVaultKeyset(old_credentials, index, &vault_keyset,
320 &mount_error)) {
365 // Save to the next key index first so that if there is a failure, we 321 // Save to the next key index first so that if there is a failure, we
366 // don't delete the existing working keyset. 322 // don't delete the existing working keyset.
367 bool save_result = SaveVaultKeyset(credentials, vault_keyset, index + 1); 323 bool save_result = SaveVaultKeyset(credentials, vault_keyset, index + 1);
368 if (save_result) { 324 if (save_result) {
369 // Saved okay, move to index 0. 325 // Saved okay, move to index 0.
370 if (!file_util::ReplaceFile(FilePath(GetUserKeyFile(credentials, 326 if (!file_util::ReplaceFile(FilePath(GetUserKeyFile(credentials,
371 index + 1)), 327 index + 1)),
372 FilePath(GetUserKeyFile(credentials, 0)))) { 328 FilePath(GetUserKeyFile(credentials, 0)))) {
373 return false; 329 return false;
374 } 330 }
(...skipping 14 matching lines...) Expand all
389 } 345 }
390 return true; 346 return true;
391 } else { 347 } else {
392 // Couldn't save the vault keyset, delete it 348 // Couldn't save the vault keyset, delete it
393 file_util::Delete(FilePath(GetUserKeyFile(credentials, index + 1)), 349 file_util::Delete(FilePath(GetUserKeyFile(credentials, index + 1)),
394 false); 350 false);
395 file_util::Delete(FilePath(GetUserSaltFile(credentials, index + 1)), 351 file_util::Delete(FilePath(GetUserSaltFile(credentials, index + 1)),
396 false); 352 false);
397 return false; 353 return false;
398 } 354 }
355 } else if (mount_error != Mount::MOUNT_ERROR_KEY_FAILURE) {
356 break;
399 } 357 }
400 } 358 }
401 return false; 359 return false;
402 } 360 }
403 361
404 bool Mount::MountIncognitoCryptohome() { 362 bool Mount::MountGuestCryptohome() {
405 // Attempt to mount incognitofs 363 // Attempt to mount guestfs
406 if (mount("incognitofs", home_dir_.c_str(), "tmpfs", 364 if (!platform_->Mount("guestfs", home_dir_, "tmpfs", "")) {
407 kDefaultMountOptions, "")) { 365 LOG(ERROR) << "Cryptohome mount failed: " << errno << " for guestfs";
408 LOG(ERROR) << "Cryptohome mount failed: " << errno << " for incognitofs";
409 return false; 366 return false;
410 } 367 }
411 if (set_vault_ownership_) { 368 if (set_vault_ownership_) {
412 if (chown(home_dir_.c_str(), default_user_, default_group_)) { 369 if (!platform_->SetOwnership(home_dir_, default_user_, default_group_)) {
413 LOG(ERROR) << "Couldn't change owner (" << default_user_ << ":" 370 LOG(ERROR) << "Couldn't change owner (" << default_user_ << ":"
414 << default_group_ << ") of incognitofs path: " 371 << default_group_ << ") of guestfs path: "
415 << home_dir_.c_str(); 372 << home_dir_.c_str();
416 bool was_busy; 373 bool was_busy;
417 Unmount(home_dir_.c_str(), false, &was_busy); 374 platform_->Unmount(home_dir_.c_str(), false, &was_busy);
418 return false; 375 return false;
419 } 376 }
420 } 377 }
421 CopySkeleton(); 378 CopySkeleton();
422 return true; 379 return true;
423 } 380 }
424 381
425 string Mount::GetUserDirectory(const Credentials& credentials) { 382 string Mount::GetUserDirectory(const Credentials& credentials) {
426 return StringPrintf("%s/%s", 383 return StringPrintf("%s/%s",
427 shadow_root_.c_str(), 384 shadow_root_.c_str(),
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
488 if (IsCryptohomeMountedForUser(credentials)) { 445 if (IsCryptohomeMountedForUser(credentials)) {
489 CopySkeleton(); 446 CopySkeleton();
490 } 447 }
491 } 448 }
492 449
493 void Mount::CopySkeleton() { 450 void Mount::CopySkeleton() {
494 RecursiveCopy(FilePath(home_dir_), FilePath(skel_source_)); 451 RecursiveCopy(FilePath(home_dir_), FilePath(skel_source_));
495 } 452 }
496 453
497 void Mount::GetSecureRandom(unsigned char *rand, int length) const { 454 void Mount::GetSecureRandom(unsigned char *rand, int length) const {
498 // TODO(fes): Get assistance from the TPM when it is available 455 crypto_->GetSecureRandom(rand, length);
499 // Seed the OpenSSL random number generator until it is happy
500 while (!RAND_status()) {
501 char buffer[256];
502 file_util::ReadFile(FilePath(entropy_source_), buffer, sizeof(buffer));
503 RAND_add(buffer, sizeof(buffer), sizeof(buffer));
504 }
505
506 // Have OpenSSL generate the random bytes
507 RAND_bytes(rand, length);
508 }
509
510 bool Mount::Unmount(const std::string& path, bool lazy, bool* was_busy) {
511 if (lazy) {
512 // TODO(fes): Place platform-specific calls in a separate class so that
513 // they can be mocked.
514 if (umount2(path.c_str(), MNT_DETACH)) {
515 if (was_busy) {
516 *was_busy = (errno == EBUSY);
517 }
518 return false;
519 }
520 } else {
521 if (umount(path.c_str())) {
522 if (was_busy) {
523 *was_busy = (errno == EBUSY);
524 }
525 return false;
526 }
527 }
528 if (was_busy) {
529 *was_busy = false;
530 }
531 return true;
532 }
533
534 bool Mount::UnwrapMasterKey(const FilePath& path,
535 const chromeos::Blob& passkey,
536 VaultKeyset* vault_keyset) {
537 // TODO(fes): Update this with openssl/tpm_engine or opencryptoki once
538 // available
539 // Load the encrypted master key
540 SecureBlob cipher_text;
541 if (!LoadFileBytes(path, cipher_text)) {
542 LOG(ERROR) << "Unable to read master key file";
543 return false;
544 }
545
546 unsigned int header_size = kOpenSSLMagic.length() + PKCS5_SALT_LEN;
547
548 if (cipher_text.size() < header_size) {
549 LOG(ERROR) << "Master key file too short";
550 return false;
551 }
552
553 // Grab the salt used in converting the passkey to a key (OpenSSL
554 // passkey-encrypted files have the format:
555 // Salted__<8-byte-salt><ciphertext>)
556 unsigned char salt[PKCS5_SALT_LEN];
557 memcpy(salt, &cipher_text[kOpenSSLMagic.length()], PKCS5_SALT_LEN);
558
559 cipher_text.erase(cipher_text.begin(), cipher_text.begin() + header_size);
560
561 unsigned char wrapper_key[EVP_MAX_KEY_LENGTH];
562 unsigned char iv[EVP_MAX_IV_LENGTH];
563
564 // Convert the passkey to a key encryption key
565 if (!EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, &passkey[0],
566 passkey.size(), 1, wrapper_key, iv)) {
567 LOG(ERROR) << "Failure converting bytes to key";
568 return false;
569 }
570
571 SecureBlob plain_text(cipher_text.size());
572
573 int final_size = 0;
574 int decrypt_size = plain_text.size();
575
576 // Do the actual decryption
577 EVP_CIPHER_CTX d_ctx;
578 EVP_CIPHER_CTX_init(&d_ctx);
579 EVP_DecryptInit_ex(&d_ctx, EVP_aes_256_ecb(), NULL, wrapper_key, iv);
580 if (!EVP_DecryptUpdate(&d_ctx, &plain_text[0], &decrypt_size,
581 &cipher_text[0],
582 cipher_text.size())) {
583 LOG(ERROR) << "DecryptUpdate failed";
584 return false;
585 }
586 if (!EVP_DecryptFinal_ex(&d_ctx, &plain_text[decrypt_size], &final_size)) {
587 unsigned long err = ERR_get_error();
588 ERR_load_ERR_strings();
589 ERR_load_crypto_strings();
590
591 LOG(ERROR) << "DecryptFinal Error: " << err
592 << ": " << ERR_lib_error_string(err)
593 << ", " << ERR_func_error_string(err)
594 << ", " << ERR_reason_error_string(err);
595
596 return false;
597 }
598 final_size += decrypt_size;
599
600 plain_text.resize(final_size);
601
602 if (plain_text.size() != VaultKeyset::SerializedSize()) {
603 LOG(ERROR) << "Plain text was not the correct size: " << plain_text.size()
604 << ", expected: " << VaultKeyset::SerializedSize();
605 return false;
606 }
607
608 (*vault_keyset).AssignBuffer(plain_text);
609
610 return true;
611 } 456 }
612 457
613 bool Mount::CreateMasterKey(const Credentials& credentials, int index) { 458 bool Mount::CreateMasterKey(const Credentials& credentials, int index) {
614 VaultKeyset vault_keyset; 459 VaultKeyset vault_keyset;
615 vault_keyset.CreateRandom(*this); 460 vault_keyset.CreateRandom(*this);
616 return SaveVaultKeyset(credentials, vault_keyset, index); 461 return SaveVaultKeyset(credentials, vault_keyset, index);
617 } 462 }
618 463
619 bool Mount::SaveVaultKeyset(const Credentials& credentials, 464 bool Mount::SaveVaultKeyset(const Credentials& credentials,
620 const VaultKeyset& vault_keyset, 465 const VaultKeyset& vault_keyset,
621 int index) { 466 int index) {
622 unsigned char wrapper_key[EVP_MAX_KEY_LENGTH]; 467 // Get the vault keyset wrapper
623 unsigned char iv[EVP_MAX_IV_LENGTH]; 468 SecureBlob user_salt;
624 unsigned char salt[PKCS5_SALT_LEN]; 469 GetUserSalt(credentials, index, true, &user_salt);
470 SecureBlob passkey;
471 credentials.GetPasskey(&passkey);
472 SecureBlob passkey_wrapper;
473 crypto_->PasskeyToWrapper(passkey, user_salt, 1, &passkey_wrapper);
625 474
626 // Create a salt for this master key 475 // Wrap the vault keyset
627 GetSecureRandom(salt, sizeof(salt)); 476 SecureBlob salt(CRYPTOHOME_DEFAULT_KEY_SALT_SIZE);
628 SecureBlob user_salt = GetUserSalt(credentials, index, true); 477 SecureBlob cipher_text;
629 478 crypto_->GetSecureRandom(static_cast<unsigned char*>(salt.data()),
630 // Convert the passkey to a passkey wrapper 479 salt.size());
631 SecureBlob passkey_wrapper = 480 if (!crypto_->WrapVaultKeyset(vault_keyset, passkey_wrapper, salt,
632 PasskeyToWrapper(credentials.GetPasskey(), user_salt, 1); 481 &cipher_text)) {
633 482 LOG(ERROR) << "Wrapping vault keyset failed";
634 // Convert the passkey wrapper to a key encryption key
635 if (!EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, &passkey_wrapper[0],
636 passkey_wrapper.size(), 1, wrapper_key, iv)) {
637 LOG(ERROR) << "Failure converting bytes to key";
638 return false; 483 return false;
639 } 484 }
640 485
641 SecureBlob keyset_blob = vault_keyset.ToBuffer();
642
643 // Store the salt and encrypt the master key
644 unsigned int header_size = kOpenSSLMagic.length() + PKCS5_SALT_LEN;
645 SecureBlob cipher_text(header_size
646 + keyset_blob.size()
647 + EVP_CIPHER_block_size(EVP_aes_256_ecb()));
648 memcpy(&cipher_text[0], kOpenSSLMagic.c_str(), kOpenSSLMagic.length());
649 memcpy(&cipher_text[kOpenSSLMagic.length()], salt, PKCS5_SALT_LEN);
650
651 int current_size = header_size;
652 int encrypt_size = 0;
653 EVP_CIPHER_CTX e_ctx;
654 EVP_CIPHER_CTX_init(&e_ctx);
655
656 // Encrypt the keyset
657 EVP_EncryptInit_ex(&e_ctx, EVP_aes_256_ecb(), NULL, wrapper_key, iv);
658 if (!EVP_EncryptUpdate(&e_ctx, &cipher_text[current_size], &encrypt_size,
659 &keyset_blob[0],
660 keyset_blob.size())) {
661 LOG(ERROR) << "EncryptUpdate failed";
662 return false;
663 }
664 current_size += encrypt_size;
665 encrypt_size = 0;
666
667 // Finish the encryption
668 if (!EVP_EncryptFinal_ex(&e_ctx, &cipher_text[current_size], &encrypt_size)) {
669 LOG(ERROR) << "EncryptFinal failed";
670 return false;
671 }
672 current_size += encrypt_size;
673 cipher_text.resize(current_size);
674
675 chromeos::SecureMemset(wrapper_key, sizeof(wrapper_key), 0);
676
677 // Save the master key 486 // Save the master key
678 unsigned int data_written = file_util::WriteFile( 487 unsigned int data_written = file_util::WriteFile(
679 FilePath(GetUserKeyFile(credentials, index)), 488 FilePath(GetUserKeyFile(credentials, index)),
680 reinterpret_cast<const char*>(&cipher_text[0]), 489 static_cast<const char*>(cipher_text.const_data()),
681 cipher_text.size()); 490 cipher_text.size());
682 491
683 if (data_written != cipher_text.size()) { 492 if (data_written != cipher_text.size()) {
684 LOG(ERROR) << "Write to master key failed"; 493 LOG(ERROR) << "Write to master key failed";
685 return false; 494 return false;
686 } 495 }
687 return true; 496 return true;
688 } 497 }
689 498
690 SecureBlob Mount::PasskeyToWrapper(const chromeos::Blob& passkey, 499 void Mount::GetSystemSalt(chromeos::Blob* salt) {
691 const chromeos::Blob& salt, int iters) { 500 *salt = system_salt_;
692 // TODO(fes): Update this when TPM support is available, or use a memory-
693 // bound strengthening algorithm.
694 int update_length = passkey.size();
695 SecureBlob holder(CRYPTOHOME_MAX(update_length, SHA_DIGEST_LENGTH));
696 memcpy(&holder[0], &passkey[0], update_length);
697
698 // Repeatedly hash the user passkey and salt to generate the wrapper
699 for (int i = 0; i < iters; ++i) {
700 SHA_CTX ctx;
701 unsigned char md_value[SHA_DIGEST_LENGTH];
702
703 SHA1_Init(&ctx);
704 SHA1_Update(&ctx, &salt[0], salt.size());
705 SHA1_Update(&ctx, &holder[0], update_length);
706 SHA1_Final(md_value, &ctx);
707
708 memcpy(&holder[0], md_value, SHA_DIGEST_LENGTH);
709 update_length = SHA_DIGEST_LENGTH;
710 }
711
712 holder.resize(update_length);
713 SecureBlob wrapper(update_length * 2);
714 AsciiEncodeToBuffer(holder, reinterpret_cast<char*>(&wrapper[0]),
715 wrapper.size());
716 return wrapper;
717 } 501 }
718 502
719 SecureBlob Mount::GetSystemSalt() { 503 void Mount::GetUserSalt(const Credentials& credentials, int index, bool force,
720 return system_salt_; 504 SecureBlob* salt) {
721 }
722
723 SecureBlob Mount::GetUserSalt(const Credentials& credentials, int index,
724 bool force) {
725 FilePath path(GetUserSaltFile(credentials, index)); 505 FilePath path(GetUserSaltFile(credentials, index));
726 return GetOrCreateSalt(path, CRYPTOHOME_DEFAULT_SALT_LENGTH, force); 506 crypto_->GetOrCreateSalt(path, CRYPTOHOME_DEFAULT_SALT_LENGTH, force, salt);
727 }
728
729 SecureBlob Mount::GetOrCreateSalt(const FilePath& path, int length,
730 bool force) {
731 SecureBlob salt;
732 if (force || !file_util::PathExists(path)) {
733 // If this salt doesn't exist, automatically create it
734 salt.resize(length);
735 GetSecureRandom(&salt[0], salt.size());
736 int data_written = file_util::WriteFile(path,
737 reinterpret_cast<const char*>(&salt[0]),
738 length);
739 if (data_written != length) {
740 LOG(ERROR) << "Could not write user salt";
741 return SecureBlob();
742 }
743 } else {
744 // Otherwise just load the contents of the salt
745 int64 file_size;
746 if (!file_util::GetFileSize(path, &file_size)) {
747 LOG(ERROR) << "Could not get size of " << path.value();
748 return SecureBlob();
749 }
750 if (file_size > INT_MAX) {
751 LOG(ERROR) << "File " << path.value() << " is too large: " << file_size;
752 return SecureBlob();
753 }
754 salt.resize(file_size);
755 int data_read = file_util::ReadFile(path, reinterpret_cast<char*>(&salt[0]),
756 file_size);
757 if (data_read != file_size) {
758 LOG(ERROR) << "Could not read entire file " << file_size;
759 return SecureBlob();
760 }
761 }
762 return salt;
763 }
764
765 void Mount::AsciiEncodeToBuffer(const chromeos::Blob& blob, char* buffer,
766 int buffer_length) {
767 const char hex_chars[] = "0123456789abcdef";
768 int i = 0;
769 for (chromeos::Blob::const_iterator it = blob.begin();
770 it < blob.end() && (i + 1) < buffer_length; ++it) {
771 buffer[i++] = hex_chars[((*it) >> 4) & 0x0f];
772 buffer[i++] = hex_chars[(*it) & 0x0f];
773 }
774 if (i < buffer_length) {
775 buffer[i] = '\0';
776 }
777 }
778
779 bool Mount::AddKeyToEcryptfsKeyring(const VaultKeyset& vault_keyset,
780 string* key_signature,
781 string* fnek_signature) {
782 // Clear the user keyring
783 keyctl(KEYCTL_CLEAR, KEY_SPEC_USER_KEYRING);
784
785 // Add the FEK
786 *key_signature = chromeos::AsciiEncode(vault_keyset.FEK_SIG());
787 if (!PushVaultKey(vault_keyset.FEK(), *key_signature,
788 vault_keyset.FEK_SALT())) {
789 LOG(ERROR) << "Couldn't add ecryptfs key to keyring";
790 return false;
791 }
792
793 // Add the FNEK
794 *fnek_signature = chromeos::AsciiEncode(vault_keyset.FNEK_SIG());
795 if (!PushVaultKey(vault_keyset.FNEK(), *fnek_signature,
796 vault_keyset.FNEK_SALT())) {
797 LOG(ERROR) << "Couldn't add ecryptfs fnek key to keyring";
798 return false;
799 }
800
801 return true;
802 }
803
804 bool Mount::PushVaultKey(const SecureBlob& key, const std::string& key_sig,
805 const SecureBlob& salt) {
806 DCHECK(key.size() == ECRYPTFS_MAX_KEY_BYTES);
807 DCHECK(key_sig.length() == (ECRYPTFS_SIG_SIZE * 2));
808 DCHECK(salt.size() == ECRYPTFS_SALT_SIZE);
809
810 struct ecryptfs_auth_tok auth_token;
811
812 generate_payload(&auth_token, const_cast<char*>(key_sig.c_str()),
813 const_cast<char*>(reinterpret_cast<const char*>(&salt[0])),
814 const_cast<char*>(reinterpret_cast<const char*>(&key[0])));
815
816 if (ecryptfs_add_auth_tok_to_keyring(&auth_token,
817 const_cast<char*>(key_sig.c_str())) < 0) {
818 LOG(ERROR) << "PushVaultKey failed";
819 }
820
821 return true;
822 } 507 }
823 508
824 bool Mount::LoadFileBytes(const FilePath& path, 509 bool Mount::LoadFileBytes(const FilePath& path,
825 SecureBlob& blob) { 510 SecureBlob* blob) {
826 int64 file_size; 511 int64 file_size;
827 if (!file_util::PathExists(path)) { 512 if (!file_util::PathExists(path)) {
828 LOG(ERROR) << path.value() << " does not exist!"; 513 LOG(INFO) << path.value() << " does not exist!";
829 return false; 514 return false;
830 } 515 }
831 if (!file_util::GetFileSize(path, &file_size)) { 516 if (!file_util::GetFileSize(path, &file_size)) {
832 LOG(ERROR) << "Could not get size of " << path.value(); 517 LOG(ERROR) << "Could not get size of " << path.value();
833 return false; 518 return false;
834 } 519 }
835 if (file_size > INT_MAX) { 520 if (file_size > INT_MAX) {
836 LOG(ERROR) << "File " << path.value() << " is too large: " << file_size; 521 LOG(ERROR) << "File " << path.value() << " is too large: " << file_size;
837 return false; 522 return false;
838 } 523 }
839 SecureBlob buf(file_size); 524 SecureBlob buf(file_size);
840 int data_read = file_util::ReadFile(path, reinterpret_cast<char*>(&buf[0]), 525 int data_read = file_util::ReadFile(path, reinterpret_cast<char*>(&buf[0]),
841 file_size); 526 file_size);
842 // Cast is okay because of comparison to INT_MAX above 527 // Cast is okay because of comparison to INT_MAX above
843 if (data_read != static_cast<int>(file_size)) { 528 if (data_read != static_cast<int>(file_size)) {
844 LOG(ERROR) << "Could not read entire file " << file_size; 529 LOG(ERROR) << "Could not read entire file " << file_size;
845 return false; 530 return false;
846 } 531 }
847 blob.swap(buf); 532 blob->swap(buf);
848 return true; 533 return true;
849 } 534 }
850 535
851 bool Mount::TerminatePidsWithOpenFiles(const std::string& path, bool hard) { 536 } // namespace cryptohome
852 std::vector<pid_t> pids = LookForOpenFiles(path);
853 for (std::vector<pid_t>::iterator it = pids.begin(); it != pids.end(); it++) {
854 pid_t pid = static_cast<pid_t>(*it);
855 if (pid != getpid()) {
856 if (hard) {
857 kill(pid, SIGTERM);
858 } else {
859 kill(pid, SIGKILL);
860 }
861 }
862 }
863 return (pids.size() != 0);
864 }
865
866 std::vector<pid_t> Mount::LookForOpenFiles(const std::string& path_in) {
867 // Make sure that if we get a directory, it has a trailing separator
868 FilePath file_path(path_in);
869 file_util::EnsureEndsWithSeparator(&file_path);
870 std::string path = file_path.value();
871
872 std::vector<pid_t> pids;
873
874 // Open /proc
875 DIR* proc_dir = opendir(kProcDir.c_str());
876
877 if (!proc_dir) {
878 return pids;
879 }
880
881 int linkbuf_length = path.length();
882 std::vector<char> linkbuf(linkbuf_length);
883
884 // List PIDs in /proc
885 while (struct dirent* pid_dirent = readdir(proc_dir)) {
886 pid_t pid = static_cast<pid_t>(atoi(pid_dirent->d_name));
887 // Ignore PID 1 and errors
888 if (pid <= 1) {
889 continue;
890 }
891 // Open /proc/<pid>/fd
892 std::string fd_dirname = StringPrintf("%s/%d/fd", kProcDir.c_str(), pid);
893 DIR* fd_dir = opendir(fd_dirname.c_str());
894 if (!fd_dir) {
895 continue;
896 }
897
898 // List open file descriptors
899 while (struct dirent* fd_dirent = readdir(fd_dir)) {
900 std::string fd_path = StringPrintf("%s/%s", fd_dirname.c_str(),
901 fd_dirent->d_name);
902 ssize_t link_length = readlink(fd_path.c_str(), &linkbuf[0],
903 linkbuf.size());
904 if (link_length > 0) {
905 std::string open_file(&linkbuf[0], link_length);
906 if (open_file.length() >= path.length()) {
907 if (open_file.substr(0, path.length()).compare(path) == 0) {
908 pids.push_back(pid);
909 break;
910 }
911 }
912 }
913 }
914
915 closedir(fd_dir);
916 }
917
918 closedir(proc_dir);
919
920 return pids;
921 }
922
923 bool Mount::TerminatePidsForUser(const uid_t uid, bool hard) {
924 std::vector<pid_t> pids = GetPidsForUser(uid);
925 for (std::vector<pid_t>::iterator it = pids.begin(); it != pids.end(); it++) {
926 pid_t pid = static_cast<pid_t>(*it);
927 if (pid != getpid()) {
928 if (hard) {
929 kill(pid, SIGTERM);
930 } else {
931 kill(pid, SIGKILL);
932 }
933 }
934 }
935 return (pids.size() != 0);
936 }
937
938 // TODO(fes): Pull this into a separate helper class
939 std::vector<pid_t> Mount::GetPidsForUser(uid_t uid) {
940 std::vector<pid_t> pids;
941
942 // Open /proc
943 DIR* proc_dir = opendir(kProcDir.c_str());
944
945 if (!proc_dir) {
946 return pids;
947 }
948
949 // List PIDs in /proc
950 while (struct dirent* pid_dirent = readdir(proc_dir)) {
951 pid_t pid = static_cast<pid_t>(atoi(pid_dirent->d_name));
952 if (pid <= 0) {
953 continue;
954 }
955 // Open /proc/<pid>/status
956 std::string stat_path = StringPrintf("%s/%d/status", kProcDir.c_str(),
957 pid);
958 string contents;
959 if (!file_util::ReadFileToString(FilePath(stat_path), &contents)) {
960 continue;
961 }
962
963 size_t uid_loc = contents.find("Uid:");
964 if (!uid_loc) {
965 continue;
966 }
967 uid_loc += 4;
968
969 size_t uid_end = contents.find("\n", uid_loc);
970 if (!uid_end) {
971 continue;
972 }
973
974 contents = contents.substr(uid_loc, uid_end - uid_loc);
975
976 std::vector<std::string> tokens;
977 Tokenize(contents, " \t", &tokens);
978
979 for (std::vector<std::string>::iterator it = tokens.begin();
980 it != tokens.end(); it++) {
981 std::string& value = *it;
982 if (value.length() == 0) {
983 continue;
984 }
985 uid_t check_uid = static_cast<uid_t>(atoi(value.c_str()));
986 if (check_uid == uid) {
987 pids.push_back(pid);
988 break;
989 }
990 }
991 }
992
993 closedir(proc_dir);
994
995 return pids;
996 }
997
998 } // cryptohome
OLDNEW
« no previous file with comments | « mount.h ('k') | mount_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698