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
EnsureSystemSaltIsLoaded()44 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
SanitizeUserName(const std::string & username)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
GetUserPathPrefix()91 FilePath GetUserPathPrefix() {
92 return FilePath(g_user_home_prefix);
93 }
94
GetRootPathPrefix()95 FilePath GetRootPathPrefix() {
96 return FilePath(g_root_home_prefix);
97 }
98
GetHashedUserPath(const std::string & hashed_username)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
GetUserPath(const std::string & username)104 FilePath GetUserPath(const std::string& username) {
105 if (!EnsureSystemSaltIsLoaded())
106 return FilePath();
107 return GetHashedUserPath(SanitizeUserName(username));
108 }
109
GetRootPath(const std::string & username)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
GetDaemonPath(const std::string & username,const std::string & daemon)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
GetDaemonPathForHiddenUserHome(const std::string & username,const std::string & daemon)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
IsSanitizedUserName(const std::string & sanitized)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
SetUserHomePrefix(const std::string & prefix)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
SetRootHomePrefix(const std::string & prefix)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
GetSystemSalt()155 std::string* GetSystemSalt() {
156 return salt;
157 }
158
SetSystemSalt(std::string * value)159 void SetSystemSalt(std::string* value) {
160 salt = value;
161 }
162
163 } // namespace home
164 } // namespace cryptohome
165 } // namespace brillo
166