| // Copyright 2019 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. |
| |
| #ifndef KERBEROS_ACCOUNT_MANAGER_H_ |
| #define KERBEROS_ACCOUNT_MANAGER_H_ |
| |
| #include <memory> |
| #include <string> |
| #include <unordered_set> |
| #include <vector> |
| |
| #include <base/callback.h> |
| #include <base/compiler_specific.h> |
| #include <base/files/file_path.h> |
| #include <base/macros.h> |
| |
| #include "bindings/kerberos_containers.pb.h" |
| #include "kerberos/config_parser.h" |
| #include "kerberos/krb5_interface.h" |
| #include "kerberos/proto_bindings/kerberos_service.pb.h" |
| #include "kerberos/tgt_renewal_scheduler.h" |
| |
| namespace password_provider { |
| class PasswordProviderInterface; |
| } |
| |
| namespace kerberos { |
| |
| class KerberosMetrics; |
| |
| // Manages Kerberos tickets for a set of accounts keyed by principal name |
| // (user@REALM.COM). |
| class AccountManager : public TgtRenewalScheduler::Delegate { |
| public: |
| using KerberosFilesChangedCallback = |
| base::RepeatingCallback<void(const std::string& principal_name)>; |
| using KerberosTicketExpiringCallback = |
| base::RepeatingCallback<void(const std::string& principal_name)>; |
| |
| // |storage_dir| is the path where configs and credential caches are stored. |
| // |kerberos_files_changed| is a callback that gets called when either the |
| // Kerberos credential cache or the configuration file changes for a specific |
| // account. Use in combination with GetKerberosFiles() to get the latest |
| // files. |kerberos_ticket_expiring| is a callback that gets called when a |
| // Kerberos TGT is about to expire. It should be used to notify the user. |
| // |krb5| interacts with lower level Kerberos libraries. It can be overridden |
| // for tests. |password_provider| is used to retrieve the login password. It |
| // can be overridden for tests. |
| AccountManager(base::FilePath storage_dir, |
| KerberosFilesChangedCallback kerberos_files_changed, |
| KerberosTicketExpiringCallback kerberos_ticket_expiring, |
| std::unique_ptr<Krb5Interface> krb5, |
| std::unique_ptr<password_provider::PasswordProviderInterface> |
| password_provider, |
| KerberosMetrics* metrics); |
| ~AccountManager() override; |
| |
| // Saves all accounts to disk. Returns ERROR_LOCAL_IO and logs on error. |
| ErrorType SaveAccounts() const; |
| |
| // Loads all accounts from disk. Returns ERROR_LOCAL_IO and logs on error. |
| // Removes all old accounts before setting the new ones. Treats a non-existent |
| // file on disk as if the file was empty, i.e. loading succeeds and the |
| // account list is empty afterwards. |
| ErrorType LoadAccounts(); |
| |
| // Adds an account keyed by |principal_name| (user@REALM.COM) to the list of |
| // accounts. |is_managed| indicates whether the account is managed by the |
| // KerberosAccounts policy. Returns |ERROR_DUPLICATE_PRINCIPAL_NAME| if the |
| // account is already present. |
| ErrorType AddAccount(const std::string& principal_name, |
| bool is_managed) WARN_UNUSED_RESULT; |
| |
| // The following methods return |ERROR_UNKNOWN_PRINCIPAL_NAME| if |
| // |principal_name| (user@REALM.COM) is not known. |
| |
| // Removes the account keyed by |principal_name| from the list of accounts. |
| ErrorType RemoveAccount(const std::string& principal_name) WARN_UNUSED_RESULT; |
| |
| // Removes account data or full accounts, depending on |mode|. Accounts in |
| // |keep_list| are not touched. |
| ErrorType ClearAccounts(ClearMode mode, |
| std::unordered_set<std::string> keep_list) |
| WARN_UNUSED_RESULT; |
| |
| // Returns a list of all existing accounts, including current status like |
| // remaining Kerberos ticket lifetime. Does a best effort returning results. |
| // See documentation of |Account| for more details. |
| std::vector<Account> ListAccounts() const; |
| |
| // Sets the Kerberos configuration (krb5.conf) used for the given |
| // |principal_name|. Validates the config before setting it. |
| ErrorType SetConfig(const std::string& principal_name, |
| const std::string& krb5conf) const WARN_UNUSED_RESULT; |
| |
| // Validates the Kerberos configuration data |krb5conf|. If the config has |
| // syntax errors or uses non-whitelisted options, returns ERROR_BAD_CONFIG |
| // and fills |error_info| with error information. |
| ErrorType ValidateConfig(const std::string& krb5conf, |
| ConfigErrorInfo* error_info) const |
| WARN_UNUSED_RESULT; |
| |
| // Acquires a Kerberos ticket-granting-ticket for the account keyed by |
| // |principal_name| using |password|. If |password| is empty, a stored |
| // password is used if available. If |remember_password| is true and |
| // |password| is not empty, the password is stored on disk. If |
| // |use_login_password| is true, the primary user's login password is used to |
| // authenticate. Both |password| and |remember_password| are ignored by the |
| // daemon in this case. |
| ErrorType AcquireTgt(const std::string& principal_name, |
| std::string password, |
| bool remember_password, |
| bool use_login_password) WARN_UNUSED_RESULT; |
| |
| // Retrieves the Kerberos credential cache and the configuration file for the |
| // account keyed by |principal_name|. Returns ERROR_NONE if both files could |
| // be retrieved or if the credential cache is missing. Returns ERROR_LOCAL_IO |
| // if any of the files failed to read. |
| ErrorType GetKerberosFiles(const std::string& principal_name, |
| KerberosFiles* files) const WARN_UNUSED_RESULT; |
| |
| // Sends KerberosTicketExpiring signals for each expired Kerberos ticket and |
| // starts scheduling renewal tasks for valid tickets. |
| void StartObservingTickets(); |
| |
| const base::FilePath& GetStorageDirForTesting() { return storage_dir_; } |
| |
| // Returns the base64-encoded |principal_name|. |
| static std::string GetSafeFilenameForTesting( |
| const std::string& principal_name); |
| |
| // Wraps |krb5_| in a Krb5JailWrapper. |
| void WrapKrb5ForTesting(); |
| |
| int last_renew_tgt_error_for_testing() const { |
| return last_renew_tgt_error_for_testing_; |
| } |
| |
| private: |
| // File path helpers. All paths are relative to |storage_dir_|. |
| |
| // TgtRenewalScheduler::Delegate: |
| ErrorType GetTgtStatus(const std::string& principal_name, |
| Krb5Interface::TgtStatus* tgt_status) override; |
| ErrorType RenewTgt(const std::string& principal_name) override; |
| void NotifyTgtExpiration( |
| const std::string& principal_name, |
| TgtRenewalScheduler::TgtExpiration expiration) override; |
| |
| // Acquires a TGT, sets |error| and returns true if the |principal_name| |
| // account has access to the password (either the login password or a |
| // remembered one). Returns false if no password is accessible. |
| bool MaybeAutoAcquireTgt(const std::string& principal_name, ErrorType* error); |
| |
| // Directory where files specific to the |principal_name| account are stored. |
| base::FilePath GetAccountDir(const std::string& principal_name) const; |
| |
| // File path of the Kerberos configuration for the given |principal_name|. |
| base::FilePath GetKrb5ConfPath(const std::string& principal_name) const; |
| |
| // File path of the Kerberos credential cache for the given |principal_name|. |
| base::FilePath GetKrb5CCPath(const std::string& principal_name) const; |
| |
| // File path of the Kerberos password for the given |principal_name|. |
| base::FilePath GetPasswordPath(const std::string& principal_name) const; |
| |
| // Deletes all files (credential cache, password etc.) for the given |
| // |principal_name|. Triggers KerberosFilesChanged if the credential cache was |
| // deleted. |
| void DeleteAllFilesFor(const std::string& principal_name); |
| |
| // Calls |kerberos_files_changed_|. |
| void TriggerKerberosFilesChanged(const std::string& principal_name) const; |
| |
| // Calls |kerberos_ticket_expiring_|. |
| void TriggerKerberosTicketExpiring(const std::string& principal_name) const; |
| |
| // Sets |password| to the login password. Removes a remembered password for |
| // |principal_name| if there is any. |
| ErrorType UpdatePasswordFromLogin(const std::string& principal_name, |
| std::string* password); |
| |
| // If |password| is empty, loads it from the password file if that exists. If |
| // |password| is not empty and |remember_password| is true, saves |password| |
| // to the password file. If |remember_password| is false, deletes the password |
| // file. |
| ErrorType UpdatePasswordFromSaved(const std::string& principal_name, |
| bool remember_password, |
| std::string* password); |
| |
| // Sends UMA stats for daily usage counts. The stats are sent at most once a |
| // day, even if this method is called more often. |
| void MaybeReportDailyUsageStats() const; |
| |
| // Directory where all account data is stored. |
| const base::FilePath storage_dir_; |
| |
| // File path where |accounts_| is stored. |
| const base::FilePath accounts_path_; |
| |
| // Gets called when the Kerberos configuration or credential cache changes for |
| // a specific account. |
| const KerberosFilesChangedCallback kerberos_files_changed_; |
| |
| // Gets called when the a Kerberos ticket is about to expire in the next |
| // couple of minutes or if it already expired. |
| const KerberosTicketExpiringCallback kerberos_ticket_expiring_; |
| |
| // Interface for Kerberos methods (may be overridden for tests). |
| std::unique_ptr<Krb5Interface> krb5_; |
| |
| // Returns the index of the account for |principal_name| or |kInvalidIndex| if |
| // the account does not exist. |
| int GetAccountIndex(const std::string& principal_name) const; |
| |
| struct InternalAccount { |
| // Account state. Gets serialized to disk. |
| AccountData data; |
| |
| // Scheduler for automatic TGT renewal. |
| std::unique_ptr<TgtRenewalScheduler> tgt_renewal_scheduler_; |
| |
| InternalAccount(AccountData&& data, |
| TgtRenewalScheduler::Delegate* delegate); |
| }; |
| |
| // Returns the InternalAccount for |principal_name| if available or nullptr |
| // otherwise. The returned pointer may lose validity if |accounts_| gets |
| // modified. |
| const InternalAccount* GetAccount(const std::string& principal_name) const; |
| InternalAccount* GetMutableAccount(const std::string& principal_name); |
| |
| enum class WhatToRemove { kNothing, kPassword, kAccount }; |
| |
| // Determines what data to remove, depending on |mode| and |account|. |
| WhatToRemove DetermineWhatToRemove(ClearMode mode, |
| const InternalAccount& account); |
| |
| // List of all accounts. Stored in a vector to keep order of addition. |
| std::vector<InternalAccount> accounts_; |
| |
| // Interface to retrieve the login password. |
| std::unique_ptr<password_provider::PasswordProviderInterface> |
| password_provider_; |
| |
| // For collecting UMA stats. Not owned. |
| KerberosMetrics* metrics_; |
| |
| // For retrieving encryption types from config and send to UMA stats. |
| ConfigParser config_parser_; |
| |
| ErrorType last_renew_tgt_error_for_testing_ = ERROR_NONE; |
| |
| DISALLOW_COPY_AND_ASSIGN(AccountManager); |
| }; |
| |
| } // namespace kerberos |
| |
| #endif // KERBEROS_ACCOUNT_MANAGER_H_ |