blob: 2e20937319762439d15cf58a86e253cf2754bf07 [file] [log] [blame]
// Copyright 2016 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 "authpolicy/samba_helper.h"
#include <vector>
#include <base/guid.h>
#include <base/logging.h>
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include "authpolicy/anonymizer.h"
namespace {
// Map GUID position to octet position for each byte xx.
// The bytes of the first 3 groups have to be reversed.
// GUID:
// |0 |6 |9|1114|1619|21|24 |34
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// Octet:
// |1 |10|13|16|19|22|25|28|31 |46
// \XX\XX\XX\XX\XX\XX\XX\XX\XX\XX\XX\XX\XX\XX\XX\XX
// clang-format off
const int octet_pos_map[16][2] = { // Maps GUID position to octet position.
{0, 10}, {2, 7}, {4, 4}, {6, 1}, // First group, reversed byte order.
{9, 16}, {11, 13}, // Second group, reversed byte order.
{14, 22}, {16, 19}, // Third group, reversed byte order.
{19, 25}, {21, 28}, // Fourth group, same byte order.
{24, 31}, {26, 34}, {28, 37}, {30, 40}, {32, 43}, {34, 46}}; // Last group.
// clang-format on
const size_t kGuidSize = 36; // 16 bytes, xx each byte, plus 4 '-'.
const size_t kOctetSize = 48; // 16 bytes, \XX each byte.
// Prefix for Active Directory account ids. A prefixed |account_id| is usually
// called |account_id_key|. Must match Chromium AccountId::kKeyAdIdPrefix.
const char kActiveDirectoryPrefix[] = "a-";
} // namespace
namespace authpolicy {
// Flags for parsing GPO.
const char* const kGpFlagsStr[] = {
"0 GPFLAGS_ALL_ENABLED",
"1 GPFLAGS_USER_SETTINGS_DISABLED",
"2 GPFLAGS_MACHINE_SETTINGS_DISABLED",
"3 GPFLAGS_ALL_DISABLED",
};
bool ParseUserPrincipalName(const std::string& user_principal_name,
std::string* user_name,
std::string* realm,
std::string* normalized_user_principal_name) {
std::vector<std::string> parts = base::SplitString(
user_principal_name, "@", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
if (parts.size() != 2 || parts.at(0).empty() || parts.at(1).empty()) {
// Don't log user_principal_name, it might contain sensitive data.
LOG(ERROR) << "Failed to parse user principal name. Expected form "
"'user@some.realm'.";
return false;
}
*user_name = parts.at(0);
*realm = base::ToUpperASCII(parts.at(1));
*normalized_user_principal_name = *user_name + "@" + *realm;
return true;
}
bool FindToken(const std::string& in_str,
char token_separator,
const std::string& token,
std::string* result) {
std::vector<std::string> lines = base::SplitString(
in_str, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
for (const std::string& line : lines) {
if (FindTokenInLine(line, token_separator, token, result))
return true;
}
// Don't log in_str, it might contain sensitive data.
LOG(ERROR) << "Failed to find '" << token << "' in string";
return false;
}
bool FindTokenInLine(const std::string& in_line,
char token_separator,
const std::string& token,
std::string* result) {
size_t sep_pos = in_line.find(token_separator);
if (sep_pos == std::string::npos)
return false;
std::string line_token;
base::TrimWhitespaceASCII(in_line.substr(0, sep_pos), base::TRIM_ALL,
&line_token);
if (line_token != token)
return false;
base::TrimWhitespaceASCII(in_line.substr(sep_pos + 1), base::TRIM_ALL,
result);
return !result->empty();
}
bool ParseGpoVersion(const std::string& str, unsigned int* version) {
DCHECK(version);
*version = 0;
unsigned int version_hex = 0;
if (sscanf(str.c_str(), "%u (0x%08x)", version, &version_hex) != 2 ||
*version != version_hex)
return false;
return true;
}
bool ParseGpFlags(const std::string& str, int* gp_flags) {
for (int flag = 0; flag < static_cast<int>(arraysize(kGpFlagsStr)); ++flag) {
if (str == kGpFlagsStr[flag]) {
*gp_flags = flag;
return true;
}
}
return false;
}
bool Contains(const std::string& str, const std::string& substr) {
return str.find(substr) != std::string::npos;
}
std::string GuidToOctetString(const std::string& guid) {
std::string octet_str;
if (!base::IsValidGUID(guid))
return octet_str;
DCHECK_EQ(kGuidSize, guid.size());
octet_str.assign(kOctetSize, '\\');
for (size_t n = 0; n < arraysize(octet_pos_map); ++n) {
for (int hex_digit = 0; hex_digit < 2; ++hex_digit) {
octet_str.at(octet_pos_map[n][1] + hex_digit) =
toupper(guid.at(octet_pos_map[n][0] + hex_digit));
}
}
return octet_str;
}
std::string OctetStringToGuidForTesting(const std::string& octet_str) {
std::string guid;
if (octet_str.size() != kOctetSize)
return guid;
guid.assign(kGuidSize, '-');
for (size_t n = 0; n < arraysize(octet_pos_map); ++n) {
for (int hex_digit = 0; hex_digit < 2; ++hex_digit) {
guid.at(octet_pos_map[n][0] + hex_digit) =
tolower(octet_str.at(octet_pos_map[n][1] + hex_digit));
}
}
return guid;
}
std::string GetAccountIdKey(const std::string& account_id) {
return kActiveDirectoryPrefix + account_id;
}
void LogLongString(const std::string& header,
const std::string& str,
Anonymizer* anonymizer) {
if (!LOG_IS_ON(INFO))
return;
std::string anonymized_str = anonymizer->Process(str);
std::vector<std::string> lines = base::SplitString(
anonymized_str, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
if (lines.size() <= 1) {
LOG(INFO) << header << anonymized_str;
} else {
LOG(INFO) << header;
for (const std::string& line : lines)
LOG(INFO) << " " << line;
}
}
} // namespace authpolicy