| // Copyright 2017 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "login_manager/validator_utils.h" | |
| #include <base/strings/string_util.h> | |
| #include <brillo/cryptohome.h> | |
| #include <login_manager/proto_bindings/policy_descriptor.pb.h> | |
| #include <login_manager/session_manager_impl.h> | |
| namespace { | |
| // Magic user name strings. | |
| constexpr char kDemoUser[] = "demouser@"; | |
| // Constants used in email validation. | |
| constexpr char kEmailSeparator = '@'; | |
| constexpr char kEmailLegalCharacters[] = | |
| "abcdefghijklmnopqrstuvwxyz" | |
| "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
| ".@1234567890!#$%&'*+-/=?^_`{|}~"; | |
| // Should match chromium AccountId::kKeyGaiaIdPrefix . | |
| constexpr char kGaiaIdKeyPrefix[] = "g-"; | |
| // Should match chromium AccountId::kKeyAdIdPrefix . | |
| constexpr char kActiveDirectoryPrefix[] = "a-"; | |
| constexpr char kAccountIdKeyLegalCharacters[] = | |
| "-0123456789" | |
| "abcdefghijklmnopqrstuvwxyz" | |
| "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | |
| } // namespace | |
| namespace login_manager { | |
| bool ValidateAccountIdKey(const std::string& account_id) { | |
| if (account_id.find_first_not_of(kAccountIdKeyLegalCharacters) != | |
| std::string::npos) | |
| return false; | |
| return base::StartsWith(account_id, kGaiaIdKeyPrefix, | |
| base::CompareCase::SENSITIVE) || | |
| base::StartsWith(account_id, kActiveDirectoryPrefix, | |
| base::CompareCase::SENSITIVE); | |
| } | |
| bool ValidateEmail(const std::string& email_address) { | |
| if (email_address.find_first_not_of(kEmailLegalCharacters) != | |
| std::string::npos) { | |
| return false; | |
| } | |
| size_t at = email_address.find(kEmailSeparator); | |
| // it has NO @. | |
| if (at == std::string::npos) | |
| return false; | |
| // it has more than one @. | |
| if (email_address.find(kEmailSeparator, at + 1) != std::string::npos) | |
| return false; | |
| return true; | |
| } | |
| bool ValidateExtensionId(const std::string& id) { | |
| if (id.size() != 32) | |
| return false; | |
| std::string temp = base::ToLowerASCII(id); | |
| for (size_t n = 0; n < id.size(); n++) { | |
| char ch = base::ToLowerASCII(id[n]); | |
| if (ch < 'a' || ch > 'p') | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool IsIncognitoAccountId(const std::string& account_id) { | |
| using brillo::cryptohome::home::GetGuestUsername; | |
| const std::string lower_case_id(base::ToLowerASCII(account_id)); | |
| return lower_case_id == *GetGuestUsername() || lower_case_id == kDemoUser; | |
| } | |
| bool ValidateAccountId(const std::string& account_id, | |
| std::string* normalized_account_id) { | |
| if (IsIncognitoAccountId(account_id) || ValidateAccountIdKey(account_id)) { | |
| if (normalized_account_id) | |
| *normalized_account_id = account_id; | |
| return true; | |
| } | |
| // Support legacy email addresses. | |
| // TODO(alemate): remove this after ChromeOS will stop using email as | |
| // cryptohome identifier. | |
| if (ValidateEmail(account_id)) { | |
| if (normalized_account_id) | |
| *normalized_account_id = base::ToLowerASCII(account_id); | |
| return true; | |
| } | |
| if (normalized_account_id) | |
| normalized_account_id->clear(); | |
| return false; | |
| } | |
| bool ValidatePolicyDescriptor(const PolicyDescriptor& descriptor, | |
| PolicyDescriptorUsage usage) { | |
| if (!PolicyAccountType_IsValid(descriptor.account_type())) | |
| return false; | |
| switch (descriptor.account_type()) { | |
| case ACCOUNT_TYPE_DEVICE: | |
| if (!descriptor.account_id().empty()) | |
| return false; | |
| break; | |
| case ACCOUNT_TYPE_USER: | |
| if (!ValidateAccountId(descriptor.account_id(), nullptr)) | |
| return false; | |
| break; | |
| case ACCOUNT_TYPE_DEVICE_LOCAL_ACCOUNT: | |
| // Device local accounts are specified via policy, but don't have further | |
| // restrictions, so nothing to validate. | |
| if (descriptor.account_id().empty()) | |
| return false; | |
| break; | |
| } | |
| if (!PolicyDomain_IsValid(descriptor.domain())) | |
| return false; | |
| switch (descriptor.domain()) { | |
| case POLICY_DOMAIN_CHROME: | |
| if (usage == PolicyDescriptorUsage::kList) | |
| return false; | |
| if (!descriptor.component_id().empty()) | |
| return false; | |
| break; | |
| case POLICY_DOMAIN_EXTENSIONS: | |
| case POLICY_DOMAIN_SIGNIN_EXTENSIONS: | |
| if (usage == PolicyDescriptorUsage::kList) { | |
| if (!descriptor.component_id().empty()) | |
| return false; | |
| } else { | |
| if (!ValidateExtensionId(descriptor.component_id())) | |
| return false; | |
| } | |
| break; | |
| } | |
| return true; | |
| } | |
| } // namespace login_manager |