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 static char g_user_home_prefix[PATH_MAX] = "/home/user/";
28 static char g_root_home_prefix[PATH_MAX] = "/home/root/";
29 static char g_system_salt_path[PATH_MAX] = "/home/.shadow/salt";
30
31 static std::string* salt = nullptr;
32
EnsureSystemSaltIsLoaded()33 static bool EnsureSystemSaltIsLoaded() {
34 if (salt && !salt->empty())
35 return true;
36 FilePath salt_path(g_system_salt_path);
37 int64_t file_size;
38 if (!base::GetFileSize(salt_path, &file_size)) {
39 PLOG(ERROR) << "Could not get size of system salt: " << g_system_salt_path;
40 return false;
41 }
42 if (file_size > static_cast<int64_t>(std::numeric_limits<int>::max())) {
43 LOG(ERROR) << "System salt too large: " << file_size;
44 return false;
45 }
46 std::vector<char> buf;
47 buf.resize(file_size);
48 unsigned int data_read = base::ReadFile(salt_path, buf.data(), file_size);
49 if (data_read != file_size) {
50 PLOG(ERROR) << "Could not read entire file: " << data_read
51 << " != " << file_size;
52 return false;
53 }
54
55 if (!salt)
56 salt = new std::string();
57 salt->assign(buf.data(), file_size);
58 return true;
59 }
60
SanitizeUserName(const std::string & username)61 std::string SanitizeUserName(const std::string& username) {
62 if (!EnsureSystemSaltIsLoaded())
63 return std::string();
64
65 unsigned char binmd[SHA_DIGEST_LENGTH];
66 std::string lowercase(username);
67 std::transform(
68 lowercase.begin(), lowercase.end(), lowercase.begin(), ::tolower);
69 SHA_CTX ctx;
70 SHA1_Init(&ctx);
71 SHA1_Update(&ctx, salt->data(), salt->size());
72 SHA1_Update(&ctx, lowercase.data(), lowercase.size());
73 SHA1_Final(binmd, &ctx);
74 std::string final = base::HexEncode(binmd, sizeof(binmd));
75 // Stay compatible with CryptoLib::HexEncodeToBuffer()
76 std::transform(final.begin(), final.end(), final.begin(), ::tolower);
77 return final;
78 }
79
GetUserPathPrefix()80 FilePath GetUserPathPrefix() {
81 return FilePath(g_user_home_prefix);
82 }
83
GetRootPathPrefix()84 FilePath GetRootPathPrefix() {
85 return FilePath(g_root_home_prefix);
86 }
87
GetHashedUserPath(const std::string & hashed_username)88 FilePath GetHashedUserPath(const std::string& hashed_username) {
89 return FilePath(
90 base::StringPrintf("%s%s", g_user_home_prefix, hashed_username.c_str()));
91 }
92
GetUserPath(const std::string & username)93 FilePath GetUserPath(const std::string& username) {
94 if (!EnsureSystemSaltIsLoaded())
95 return FilePath("");
96 return GetHashedUserPath(SanitizeUserName(username));
97 }
98
GetRootPath(const std::string & username)99 FilePath GetRootPath(const std::string& username) {
100 if (!EnsureSystemSaltIsLoaded())
101 return FilePath("");
102 return FilePath(base::StringPrintf(
103 "%s%s", g_root_home_prefix, SanitizeUserName(username).c_str()));
104 }
105
GetDaemonPath(const std::string & username,const std::string & daemon)106 FilePath GetDaemonPath(const std::string& username, const std::string& daemon) {
107 if (!EnsureSystemSaltIsLoaded())
108 return FilePath("");
109 return GetRootPath(username).Append(daemon);
110 }
111
IsSanitizedUserName(const std::string & sanitized)112 bool IsSanitizedUserName(const std::string& sanitized) {
113 std::vector<uint8_t> bytes;
114 return (sanitized.length() == 2 * SHA_DIGEST_LENGTH) &&
115 base::HexStringToBytes(sanitized, &bytes);
116 }
117
SetUserHomePrefix(const std::string & prefix)118 void SetUserHomePrefix(const std::string& prefix) {
119 if (prefix.length() < sizeof(g_user_home_prefix)) {
120 snprintf(
121 g_user_home_prefix, sizeof(g_user_home_prefix), "%s", prefix.c_str());
122 }
123 }
124
SetRootHomePrefix(const std::string & prefix)125 void SetRootHomePrefix(const std::string& prefix) {
126 if (prefix.length() < sizeof(g_root_home_prefix)) {
127 snprintf(
128 g_root_home_prefix, sizeof(g_root_home_prefix), "%s", prefix.c_str());
129 }
130 }
131
GetSystemSalt()132 std::string* GetSystemSalt() {
133 return salt;
134 }
135
SetSystemSalt(std::string * value)136 void SetSystemSalt(std::string* value) {
137 salt = value;
138 }
139
140 } // namespace home
141 } // namespace cryptohome
142 } // namespace brillo
143