You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
166 lines
4.8 KiB
166 lines
4.8 KiB
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "brillo/cryptohome.h"
|
|
|
|
#include <openssl/sha.h>
|
|
#include <stdint.h>
|
|
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
#include <limits>
|
|
#include <vector>
|
|
|
|
#include <base/files/file_util.h>
|
|
#include <base/strings/string_number_conversions.h>
|
|
#include <base/strings/stringprintf.h>
|
|
|
|
using base::FilePath;
|
|
|
|
namespace brillo {
|
|
namespace cryptohome {
|
|
namespace home {
|
|
|
|
const char kGuestUserName[] = "$guest";
|
|
|
|
// Path to user homes mounted with the mount_hidden option. The user home mount
|
|
// will be located at:
|
|
// kHiddenUserHomeBaseDir/<sanitized_user_name>/kHiddenUserHomeMountSubdir
|
|
const char kHiddenUserHomeBaseDir[] = "/home/.shadow";
|
|
const char kHiddenUserHomeMountSubdir[] = "mount";
|
|
|
|
// Subdirectory of a user home mount where daemon-specific data is stored.
|
|
// This is used to assemble daemon data storage paths for hidden user home
|
|
// mounts.
|
|
const char kHiddenUserHomeRootSubdir[] = "root";
|
|
|
|
static char g_user_home_prefix[PATH_MAX] = "/home/user/";
|
|
static char g_root_home_prefix[PATH_MAX] = "/home/root/";
|
|
static char g_system_salt_path[PATH_MAX] = "/home/.shadow/salt";
|
|
|
|
static std::string* salt = nullptr;
|
|
|
|
bool EnsureSystemSaltIsLoaded() {
|
|
if (salt && !salt->empty())
|
|
return true;
|
|
FilePath salt_path(g_system_salt_path);
|
|
int64_t file_size;
|
|
if (!base::GetFileSize(salt_path, &file_size)) {
|
|
PLOG(ERROR) << "Could not get size of system salt: " << g_system_salt_path;
|
|
return false;
|
|
}
|
|
if (file_size > static_cast<int64_t>(std::numeric_limits<int>::max())) {
|
|
LOG(ERROR) << "System salt too large: " << file_size;
|
|
return false;
|
|
}
|
|
std::vector<char> buf;
|
|
buf.resize(file_size);
|
|
unsigned int data_read = base::ReadFile(salt_path, buf.data(), file_size);
|
|
if (data_read != file_size) {
|
|
PLOG(ERROR) << "Could not read entire file: " << data_read
|
|
<< " != " << file_size;
|
|
return false;
|
|
}
|
|
|
|
if (!salt)
|
|
salt = new std::string();
|
|
salt->assign(buf.data(), file_size);
|
|
return true;
|
|
}
|
|
|
|
std::string SanitizeUserName(const std::string& username) {
|
|
if (!EnsureSystemSaltIsLoaded())
|
|
return std::string();
|
|
|
|
unsigned char binmd[SHA_DIGEST_LENGTH];
|
|
std::string lowercase(username);
|
|
std::transform(
|
|
lowercase.begin(), lowercase.end(), lowercase.begin(), ::tolower);
|
|
SHA_CTX ctx;
|
|
SHA1_Init(&ctx);
|
|
SHA1_Update(&ctx, salt->data(), salt->size());
|
|
SHA1_Update(&ctx, lowercase.data(), lowercase.size());
|
|
SHA1_Final(binmd, &ctx);
|
|
std::string final = base::HexEncode(binmd, sizeof(binmd));
|
|
// Stay compatible with CryptoLib::HexEncodeToBuffer()
|
|
std::transform(final.begin(), final.end(), final.begin(), ::tolower);
|
|
return final;
|
|
}
|
|
|
|
FilePath GetUserPathPrefix() {
|
|
return FilePath(g_user_home_prefix);
|
|
}
|
|
|
|
FilePath GetRootPathPrefix() {
|
|
return FilePath(g_root_home_prefix);
|
|
}
|
|
|
|
FilePath GetHashedUserPath(const std::string& hashed_username) {
|
|
return FilePath(
|
|
base::StringPrintf("%s%s", g_user_home_prefix, hashed_username.c_str()));
|
|
}
|
|
|
|
FilePath GetUserPath(const std::string& username) {
|
|
if (!EnsureSystemSaltIsLoaded())
|
|
return FilePath();
|
|
return GetHashedUserPath(SanitizeUserName(username));
|
|
}
|
|
|
|
FilePath GetRootPath(const std::string& username) {
|
|
if (!EnsureSystemSaltIsLoaded())
|
|
return FilePath();
|
|
return FilePath(base::StringPrintf(
|
|
"%s%s", g_root_home_prefix, SanitizeUserName(username).c_str()));
|
|
}
|
|
|
|
FilePath GetDaemonPath(const std::string& username, const std::string& daemon) {
|
|
if (!EnsureSystemSaltIsLoaded())
|
|
return FilePath();
|
|
return GetRootPath(username).Append(daemon);
|
|
}
|
|
|
|
FilePath GetDaemonPathForHiddenUserHome(const std::string& username,
|
|
const std::string& daemon) {
|
|
if (!EnsureSystemSaltIsLoaded())
|
|
return FilePath();
|
|
|
|
return FilePath(kHiddenUserHomeBaseDir)
|
|
.Append(SanitizeUserName(username))
|
|
.Append(kHiddenUserHomeMountSubdir)
|
|
.Append(kHiddenUserHomeRootSubdir)
|
|
.Append(daemon);
|
|
}
|
|
|
|
bool IsSanitizedUserName(const std::string& sanitized) {
|
|
std::vector<uint8_t> bytes;
|
|
return (sanitized.length() == 2 * SHA_DIGEST_LENGTH) &&
|
|
base::HexStringToBytes(sanitized, &bytes);
|
|
}
|
|
|
|
void SetUserHomePrefix(const std::string& prefix) {
|
|
if (prefix.length() < sizeof(g_user_home_prefix)) {
|
|
snprintf(
|
|
g_user_home_prefix, sizeof(g_user_home_prefix), "%s", prefix.c_str());
|
|
}
|
|
}
|
|
|
|
void SetRootHomePrefix(const std::string& prefix) {
|
|
if (prefix.length() < sizeof(g_root_home_prefix)) {
|
|
snprintf(
|
|
g_root_home_prefix, sizeof(g_root_home_prefix), "%s", prefix.c_str());
|
|
}
|
|
}
|
|
|
|
std::string* GetSystemSalt() {
|
|
return salt;
|
|
}
|
|
|
|
void SetSystemSalt(std::string* value) {
|
|
salt = value;
|
|
}
|
|
|
|
} // namespace home
|
|
} // namespace cryptohome
|
|
} // namespace brillo
|