| // Copyright 2017 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 <stdlib.h> |
| |
| #include <memory> |
| |
| #include <base/bind.h> |
| #include <base/files/file_util.h> |
| #include <base/time/default_tick_clock.h> |
| #include <brillo/daemons/dbus_daemon.h> |
| #include <brillo/syslog_logging.h> |
| #include <install_attributes/libinstallattributes.h> |
| |
| #include "smbprovider/authpolicy_kerberos_artifact_client.h" |
| #include "smbprovider/constants.h" |
| #include "smbprovider/kerberos_artifact_synchronizer.h" |
| #include "smbprovider/kerberos_kerberos_artifact_client.h" |
| #include "smbprovider/mount_manager.h" |
| #include "smbprovider/samba_interface_impl.h" |
| #include "smbprovider/smbprovider.h" |
| |
| namespace smbprovider { |
| |
| namespace { |
| |
| constexpr char kDaemonStoreRoot[] = "/run/daemon-store/smbproviderd"; |
| |
| // Helper method to set $HOME variable to a temporary path that only |
| // smbproviderd user can access. |
| bool SetHomeEnvironmentVariable() { |
| if (setenv(kHomeEnvironmentVariable, kSmbProviderHome, 1 /* overwrite */) != |
| 0) { |
| PLOG(ERROR) << "Failed to set $HOME variable"; |
| return false; |
| } |
| return true; |
| } |
| |
| std::string GetKrb5ConfLocation() { |
| return std::string(kSmbProviderHome) + kKrb5ConfLocation; |
| } |
| |
| std::string GetCCacheLocation() { |
| return std::string(kSmbProviderHome) + kCCacheLocation; |
| } |
| |
| std::string GetKrb5TraceLocation() { |
| return std::string(kSmbProviderHome) + kKrbTraceLocation; |
| } |
| |
| std::string GetKrb5ConfPath() { |
| return GetKrb5ConfLocation() + kKrb5ConfFile; |
| } |
| |
| std::string GetCCachePath() { |
| return GetCCacheLocation() + kCCacheFile; |
| } |
| |
| std::string GetKrb5TracePath() { |
| return GetKrb5TraceLocation() + kKrbTraceFile; |
| } |
| |
| bool SetKrb5ConfigEnviornmentVariable() { |
| if (setenv(kKrb5ConfigEnvironmentVariable, GetKrb5ConfPath().c_str(), |
| 1 /* overwrite */) != 0) { |
| PLOG(ERROR) << "Failed to set $KRB5_CONFIG variable"; |
| return false; |
| } |
| return true; |
| } |
| |
| bool SetKrb5CCNameEnvironmentVariable() { |
| if (setenv(kKrb5CCNameEnvironmentVariable, GetCCachePath().c_str(), |
| 1 /* overwrite */) != 0) { |
| PLOG(ERROR) << "Failed to set $KRB5CCNAME variable"; |
| return false; |
| } |
| return true; |
| } |
| |
| bool SetKrb5TraceEnvironmentVariable() { |
| if (setenv(kKrb5TraceEnvironmentVariable, GetKrb5TracePath().c_str(), |
| 1 /* overwrite */) != 0) { |
| PLOG(ERROR) << "Failed to set $KRB5_TRACE variable"; |
| return false; |
| } |
| return true; |
| } |
| |
| bool SetKerberosEnvironmentVariables() { |
| return SetKrb5ConfigEnviornmentVariable() && |
| SetKrb5CCNameEnvironmentVariable() && |
| SetKrb5TraceEnvironmentVariable(); |
| } |
| |
| // Creates a directory at |path|. Logs and returns an error on failure. |
| bool CreateDirectory(const std::string& path) { |
| base::File::Error ferror; |
| if (!base::CreateDirectoryAndGetError(base::FilePath(path), &ferror)) { |
| LOG(ERROR) << "Failed to create directory '" << path |
| << "': " << base::File::ErrorToString(ferror); |
| return false; |
| } |
| return true; |
| } |
| |
| bool CreateKerberosDirectories() { |
| return CreateDirectory(GetKrb5ConfLocation()) && |
| CreateDirectory(GetCCacheLocation()) && |
| CreateDirectory(GetKrb5TraceLocation()); |
| } |
| |
| void InitLog() { |
| brillo::InitLog(brillo::kLogToSyslog | brillo::kLogToStderrIfTty); |
| logging::SetLogItems(true /* enable_process_id */, |
| true /* enable_thread_id */, true /* enable_timestamp */, |
| true /* enable_tickcount */); |
| } |
| |
| // Creates smb configuration file in $HOME/.smb/smb.conf. |
| bool CreateSmbConfFile() { |
| const std::string smb_conf_directory(std::string(kSmbProviderHome) + |
| kSmbConfLocation); |
| if (!CreateDirectory(smb_conf_directory)) { |
| return false; |
| } |
| |
| const int data_size = strlen(kSmbConfData); |
| return base::WriteFile(base::FilePath(smb_conf_directory + kSmbConfFile), |
| kSmbConfData, data_size) == data_size; |
| } |
| |
| std::unique_ptr<SambaInterface> SambaInterfaceFactoryFunction( |
| MountManager* mount_manager, const MountConfig& mount_config) { |
| return SambaInterfaceImpl::Create( |
| base::Bind(base::IgnoreResult(&MountManager::GetAuthentication), |
| mount_manager->AsWeakPtr()), |
| mount_config); |
| } |
| |
| } // namespace |
| |
| class SmbProviderDaemon : public brillo::DBusServiceDaemon { |
| public: |
| SmbProviderDaemon() : DBusServiceDaemon(kSmbProviderServiceName) {} |
| |
| protected: |
| void RegisterDBusObjectsAsync( |
| brillo::dbus_utils::AsyncEventSequencer* sequencer) override { |
| auto dbus_object = std::make_unique<brillo::dbus_utils::DBusObject>( |
| nullptr, bus_, org::chromium::SmbProviderAdaptor::GetObjectPath()); |
| |
| // Check if this is Active Directory managed devices. |
| const bool is_active_directory = |
| InstallAttributesReader().GetAttribute( |
| InstallAttributesReader::kAttrMode) == |
| InstallAttributesReader::kDeviceModeEnterpriseAD; |
| |
| // If this is Active Directory managed devices, Kerberos artifact |
| // synchronizing happens between SmbProvider and AuthPolicy daemeon using |
| // AuthPolicyKerberosArtifactClient, otherwise with Kerberos daemon using |
| // KerberosKerberosArtifactClient. |
| // Note that, we allow to update credentials for Kerberos daemon if |
| // !is_active_directory. |
| auto kerberos_artifact_client = |
| is_active_directory |
| ? std::unique_ptr<KerberosArtifactClientInterface>( |
| std::make_unique<AuthPolicyKerberosArtifactClient>(bus_)) |
| : std::unique_ptr<KerberosArtifactClientInterface>( |
| std::make_unique<KerberosKerberosArtifactClient>(bus_)); |
| auto kerberos_artifact_synchronizer = |
| std::make_unique<KerberosArtifactSynchronizer>( |
| GetKrb5ConfPath(), GetCCachePath(), |
| std::move(kerberos_artifact_client), !is_active_directory); |
| |
| auto tick_clock = std::make_unique<base::DefaultTickClock>(); |
| |
| auto mount_tracker = std::make_unique<MountTracker>( |
| std::move(tick_clock), true /* enable_metadata_cache*/); |
| |
| auto samba_interface_factory = base::Bind(&SambaInterfaceFactoryFunction); |
| |
| auto mount_manager = std::make_unique<MountManager>( |
| std::move(mount_tracker), std::move(samba_interface_factory)); |
| |
| smb_provider_ = std::make_unique<SmbProvider>( |
| std::move(dbus_object), std::move(mount_manager), |
| std::move(kerberos_artifact_synchronizer), |
| base::FilePath(kDaemonStoreRoot)); |
| smb_provider_->RegisterAsync( |
| sequencer->GetHandler("SmbProvider.RegisterAsync() failed.", true)); |
| } |
| |
| void OnShutdown(int* return_code) override { |
| DBusServiceDaemon::OnShutdown(return_code); |
| smb_provider_.reset(); |
| } |
| |
| private: |
| std::unique_ptr<SmbProvider> smb_provider_; |
| DISALLOW_COPY_AND_ASSIGN(SmbProviderDaemon); |
| }; |
| |
| // Runs SmbProviderDaemon. |
| int RunDaemon() { |
| SmbProviderDaemon daemon; |
| int res = daemon.Run(); |
| LOG(INFO) << "smbproviderd stopping with exit code " << res; |
| return res; |
| } |
| |
| } // namespace smbprovider |
| |
| int main(int argc, char* argv[]) { |
| smbprovider::InitLog(); |
| // Smb configuration file must be written before the daemon is started because |
| // the check for smb.conf happens when the context is set. |
| if (!(smbprovider::SetHomeEnvironmentVariable() && |
| smbprovider::SetKerberosEnvironmentVariables() && |
| smbprovider::CreateSmbConfFile() && |
| smbprovider::CreateKerberosDirectories())) { |
| LOG(ERROR) << "Failed to set configuration files, exiting"; |
| return EXIT_FAILURE; |
| } |
| return smbprovider::RunDaemon(); |
| } |