1 // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "brillo/cryptohome.h" 6 7 #include <openssl/sha.h> 8 #include <stdint.h> 9 10 #include <algorithm> 11 #include <cstring> 12 #include <limits> 13 #include <vector> 14 15 #include <base/files/file_util.h> 16 #include <base/strings/string_number_conversions.h> 17 #include <base/strings/stringprintf.h> 18 19 using base::FilePath; 20 21 namespace brillo { 22 namespace cryptohome { 23 namespace home { 24 25 const char kGuestUserName[] = "$guest"; 26 27 // Path to user homes mounted with the mount_hidden option. The user home mount 28 // will be located at: 29 // kHiddenUserHomeBaseDir/<sanitized_user_name>/kHiddenUserHomeMountSubdir 30 const char kHiddenUserHomeBaseDir[] = "/home/.shadow"; 31 const char kHiddenUserHomeMountSubdir[] = "mount"; 32 33 // Subdirectory of a user home mount where daemon-specific data is stored. 34 // This is used to assemble daemon data storage paths for hidden user home 35 // mounts. 36 const char kHiddenUserHomeRootSubdir[] = "root"; 37 38 static char g_user_home_prefix[PATH_MAX] = "/home/user/"; 39 static char g_root_home_prefix[PATH_MAX] = "/home/root/"; 40 static char g_system_salt_path[PATH_MAX] = "/home/.shadow/salt"; 41 42 static std::string* salt = nullptr; 43 44 static bool EnsureSystemSaltIsLoaded() { 45 if (salt && !salt->empty()) 46 return true; 47 FilePath salt_path(g_system_salt_path); 48 int64_t file_size; 49 if (!base::GetFileSize(salt_path, &file_size)) { 50 PLOG(ERROR) << "Could not get size of system salt: " << g_system_salt_path; 51 return false; 52 } 53 if (file_size > static_cast<int64_t>(std::numeric_limits<int>::max())) { 54 LOG(ERROR) << "System salt too large: " << file_size; 55 return false; 56 } 57 std::vector<char> buf; 58 buf.resize(file_size); 59 unsigned int data_read = base::ReadFile(salt_path, buf.data(), file_size); 60 if (data_read != file_size) { 61 PLOG(ERROR) << "Could not read entire file: " << data_read 62 << " != " << file_size; 63 return false; 64 } 65 66 if (!salt) 67 salt = new std::string(); 68 salt->assign(buf.data(), file_size); 69 return true; 70 } 71 72 std::string SanitizeUserName(const std::string& username) { 73 if (!EnsureSystemSaltIsLoaded()) 74 return std::string(); 75 76 unsigned char binmd[SHA_DIGEST_LENGTH]; 77 std::string lowercase(username); 78 std::transform( 79 lowercase.begin(), lowercase.end(), lowercase.begin(), ::tolower); 80 SHA_CTX ctx; 81 SHA1_Init(&ctx); 82 SHA1_Update(&ctx, salt->data(), salt->size()); 83 SHA1_Update(&ctx, lowercase.data(), lowercase.size()); 84 SHA1_Final(binmd, &ctx); 85 std::string final = base::HexEncode(binmd, sizeof(binmd)); 86 // Stay compatible with CryptoLib::HexEncodeToBuffer() 87 std::transform(final.begin(), final.end(), final.begin(), ::tolower); 88 return final; 89 } 90 91 FilePath GetUserPathPrefix() { 92 return FilePath(g_user_home_prefix); 93 } 94 95 FilePath GetRootPathPrefix() { 96 return FilePath(g_root_home_prefix); 97 } 98 99 FilePath GetHashedUserPath(const std::string& hashed_username) { 100 return FilePath( 101 base::StringPrintf("%s%s", g_user_home_prefix, hashed_username.c_str())); 102 } 103 104 FilePath GetUserPath(const std::string& username) { 105 if (!EnsureSystemSaltIsLoaded()) 106 return FilePath(); 107 return GetHashedUserPath(SanitizeUserName(username)); 108 } 109 110 FilePath GetRootPath(const std::string& username) { 111 if (!EnsureSystemSaltIsLoaded()) 112 return FilePath(); 113 return FilePath(base::StringPrintf( 114 "%s%s", g_root_home_prefix, SanitizeUserName(username).c_str())); 115 } 116 117 FilePath GetDaemonPath(const std::string& username, const std::string& daemon) { 118 if (!EnsureSystemSaltIsLoaded()) 119 return FilePath(); 120 return GetRootPath(username).Append(daemon); 121 } 122 123 FilePath GetDaemonPathForHiddenUserHome(const std::string& username, 124 const std::string& daemon) { 125 if (!EnsureSystemSaltIsLoaded()) 126 return FilePath(); 127 128 return FilePath(kHiddenUserHomeBaseDir) 129 .Append(SanitizeUserName(username)) 130 .Append(kHiddenUserHomeMountSubdir) 131 .Append(kHiddenUserHomeRootSubdir) 132 .Append(daemon); 133 } 134 135 bool IsSanitizedUserName(const std::string& sanitized) { 136 std::vector<uint8_t> bytes; 137 return (sanitized.length() == 2 * SHA_DIGEST_LENGTH) && 138 base::HexStringToBytes(sanitized, &bytes); 139 } 140 141 void SetUserHomePrefix(const std::string& prefix) { 142 if (prefix.length() < sizeof(g_user_home_prefix)) { 143 snprintf( 144 g_user_home_prefix, sizeof(g_user_home_prefix), "%s", prefix.c_str()); 145 } 146 } 147 148 void SetRootHomePrefix(const std::string& prefix) { 149 if (prefix.length() < sizeof(g_root_home_prefix)) { 150 snprintf( 151 g_root_home_prefix, sizeof(g_root_home_prefix), "%s", prefix.c_str()); 152 } 153 } 154 155 std::string* GetSystemSalt() { 156 return salt; 157 } 158 159 void SetSystemSalt(std::string* value) { 160 salt = value; 161 } 162 163 } // namespace home 164 } // namespace cryptohome 165 } // namespace brillo 166