blob: 278605950e0a64a58cf98038a6bf7179650460bd [file] [log] [blame]
// 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 "chromeos/cryptohome.h"
#include <openssl/sha.h>
#include <algorithm>
#include <cstring>
#include <limits>
#include <vector>
#include <base/file_util.h>
#if BASE_VER >= 242728
#include <base/strings/string_number_conversions.h>
#include <base/strings/stringprintf.h>
#else
#include <base/string_number_conversions.h>
#include <base/stringprintf.h>
#endif
#if BASE_VER >= 242728
using base::ReadFile;
using base::GetFileSize;
#else
using file_util::ReadFile;
using file_util::GetFileSize;
#endif
namespace chromeos {
namespace cryptohome {
namespace home {
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 = NULL;
static bool EnsureSystemSaltIsLoaded() {
if (salt && !salt->empty())
return true;
FilePath salt_path(g_system_salt_path);
int64 file_size;
if (!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>(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 = ReadFile(salt_path, &buf.front(), 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.front(), 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::AsciiEncodeToBuffer()
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);
}
bool IsSanitizedUserName(const std::string& sanitized) {
std::vector<uint8> 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))
strcpy(g_user_home_prefix, prefix.c_str());
}
void SetRootHomePrefix(const std::string& prefix) {
if (prefix.length() < sizeof(g_root_home_prefix))
strcpy(g_root_home_prefix, prefix.c_str());
}
void SetSystemSaltPath(const std::string& path) {
if (path.length() < sizeof(g_system_salt_path)) {
strcpy(g_system_salt_path, path.c_str());
delete salt;
salt = NULL;
}
}
std::string* GetSystemSalt() {
return salt;
}
void SetSystemSalt(std::string* value) {
salt = value;
}
} // namespace home
} // namespace cryptohome
} // namespace chromeos