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
19using base::FilePath;
20
21namespace brillo {
22namespace cryptohome {
23namespace home {
24
25const char kGuestUserName[] = "$guest";
26
27static char g_user_home_prefix[PATH_MAX] = "/home/user/";
28static char g_root_home_prefix[PATH_MAX] = "/home/root/";
29static char g_system_salt_path[PATH_MAX] = "/home/.shadow/salt";
30
31static std::string* salt = nullptr;
32
33static 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
61std::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
80FilePath GetUserPathPrefix() {
81  return FilePath(g_user_home_prefix);
82}
83
84FilePath GetRootPathPrefix() {
85  return FilePath(g_root_home_prefix);
86}
87
88FilePath GetHashedUserPath(const std::string& hashed_username) {
89  return FilePath(
90      base::StringPrintf("%s%s", g_user_home_prefix, hashed_username.c_str()));
91}
92
93FilePath GetUserPath(const std::string& username) {
94  if (!EnsureSystemSaltIsLoaded())
95    return FilePath("");
96  return GetHashedUserPath(SanitizeUserName(username));
97}
98
99FilePath 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
106FilePath GetDaemonPath(const std::string& username, const std::string& daemon) {
107  if (!EnsureSystemSaltIsLoaded())
108    return FilePath("");
109  return GetRootPath(username).Append(daemon);
110}
111
112bool 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
118void 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
125void 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
132std::string* GetSystemSalt() {
133  return salt;
134}
135
136void SetSystemSalt(std::string* value) {
137  salt = value;
138}
139
140}  // namespace home
141}  // namespace cryptohome
142}  // namespace brillo
143