| Directory: | cvmfs/ |
|---|---|
| File: | cvmfs/server_tool.cc |
| Date: | 2026-08-23 02:40:52 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 19 | 81 | 23.5% |
| Branches: | 12 | 102 | 11.8% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * This file is part of the CernVM File System. | ||
| 3 | */ | ||
| 4 | |||
| 5 | #include "server_tool.h" | ||
| 6 | |||
| 7 | #include "util/posix.h" | ||
| 8 | |||
| 9 |
1/2✓ Branch 3 taken 685 times.
✗ Branch 4 not taken.
|
685 | ServerTool::ServerTool() { } |
| 10 | |||
| 11 | 1516 | ServerTool::~ServerTool() { | |
| 12 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 684 times.
|
1368 | if (signature_manager_.get() != nullptr) { |
| 13 | ✗ | signature_manager_->Fini(); | |
| 14 | } | ||
| 15 | 1516 | } | |
| 16 | |||
| 17 | 685 | bool ServerTool::InitDownloadManager(const bool follow_redirects, | |
| 18 | const std::string &proxy, | ||
| 19 | const unsigned max_pool_handles) { | ||
| 20 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 685 times.
|
685 | if (download_manager_.get() != nullptr) { |
| 21 | ✗ | return true; | |
| 22 | } | ||
| 23 | |||
| 24 |
1/2✓ Branch 1 taken 685 times.
✗ Branch 2 not taken.
|
2055 | download_manager_ = std::unique_ptr<download::DownloadManager>( |
| 25 | new download::DownloadManager( | ||
| 26 | max_pool_handles, | ||
| 27 |
4/8✓ Branch 3 taken 685 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 685 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 685 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 685 times.
✗ Branch 14 not taken.
|
2740 | perf::StatisticsTemplate("download", statistics()))); |
| 28 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 685 times.
|
685 | assert(download_manager_.get() != nullptr); |
| 29 | |||
| 30 | 685 | download_manager_->SetTimeout(kDownloadTimeout, kDownloadTimeout); | |
| 31 | 685 | download_manager_->SetRetryParameters(kDownloadRetries, 2000, 5000); | |
| 32 | 685 | download_manager_->UseSystemCertificatePath(); | |
| 33 | |||
| 34 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 685 times.
|
685 | if (proxy != "") { |
| 35 | ✗ | download_manager_->SetProxyChain(proxy, "", | |
| 36 | download::DownloadManager::kSetProxyBoth); | ||
| 37 | } | ||
| 38 | |||
| 39 |
1/2✓ Branch 0 taken 685 times.
✗ Branch 1 not taken.
|
685 | if (follow_redirects) { |
| 40 | 685 | download_manager_->EnableRedirects(); | |
| 41 | } | ||
| 42 | |||
| 43 | 685 | return true; | |
| 44 | } | ||
| 45 | |||
| 46 | ✗ | bool ServerTool::InitSignatureManager(const std::string &pubkey_path, | |
| 47 | const std::string &certificate_path, | ||
| 48 | const std::string &private_key_path) { | ||
| 49 | ✗ | if (signature_manager_.get() != nullptr) { | |
| 50 | ✗ | return true; | |
| 51 | } | ||
| 52 | |||
| 53 | ✗ | signature_manager_ = std::unique_ptr<signature::SignatureManager>( | |
| 54 | ✗ | new signature::SignatureManager()); | |
| 55 | ✗ | assert(signature_manager_.get() != nullptr); | |
| 56 | ✗ | signature_manager_->Init(); | |
| 57 | |||
| 58 | // We may not have a public key. In this case, the signature manager | ||
| 59 | // can only be used for signing, not for verification. | ||
| 60 | ✗ | if (!pubkey_path.empty()) { | |
| 61 | ✗ | if (!signature_manager_->LoadPublicRsaKeys(pubkey_path)) { | |
| 62 | ✗ | LogCvmfs(kLogCvmfs, kLogStderr, "failed to load public repo key '%s'", | |
| 63 | pubkey_path.c_str()); | ||
| 64 | ✗ | return false; | |
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | // We may not have a certificate and key. In this case, the signature manager | ||
| 69 | // can only be used for verification, not for signing. | ||
| 70 | ✗ | if (certificate_path.empty()) | |
| 71 | ✗ | return true; | |
| 72 | |||
| 73 | ✗ | if (!signature_manager_->LoadCertificatePath(certificate_path)) { | |
| 74 | ✗ | LogCvmfs(kLogCvmfs, kLogStderr, "failed to load certificate '%s'", | |
| 75 | certificate_path.c_str()); | ||
| 76 | ✗ | return false; | |
| 77 | } | ||
| 78 | |||
| 79 | // Load private key | ||
| 80 | ✗ | if (!signature_manager_->LoadPrivateKeyPath(private_key_path, "")) { | |
| 81 | ✗ | LogCvmfs(kLogCvmfs, kLogStderr, "failed to load private key '%s' (%s)", | |
| 82 | private_key_path.c_str(), | ||
| 83 | ✗ | signature_manager_->GetCryptoError().c_str()); | |
| 84 | ✗ | return false; | |
| 85 | } | ||
| 86 | |||
| 87 | ✗ | if (!signature_manager_->KeysMatch()) { | |
| 88 | ✗ | LogCvmfs(kLogCvmfs, kLogStderr, | |
| 89 | "the private key '%s' doesn't seem to match certificate '%s' (%s)", | ||
| 90 | private_key_path.c_str(), certificate_path.c_str(), | ||
| 91 | ✗ | signature_manager_->GetCryptoError().c_str()); | |
| 92 | ✗ | signature_manager_->UnloadPrivateKey(); | |
| 93 | ✗ | return false; | |
| 94 | } | ||
| 95 | |||
| 96 | ✗ | return true; | |
| 97 | } | ||
| 98 | |||
| 99 | 834 | download::DownloadManager *ServerTool::download_manager() const { | |
| 100 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 834 times.
|
834 | assert(download_manager_.get() != nullptr); |
| 101 | 834 | return download_manager_.get(); | |
| 102 | } | ||
| 103 | |||
| 104 | ✗ | signature::SignatureManager *ServerTool::signature_manager() const { | |
| 105 | ✗ | assert(signature_manager_.get() != nullptr); | |
| 106 | ✗ | return signature_manager_.get(); | |
| 107 | } | ||
| 108 | |||
| 109 | ✗ | manifest::Manifest *ServerTool::OpenLocalManifest( | |
| 110 | const std::string path) const { | ||
| 111 | ✗ | return manifest::Manifest::LoadFile(path); | |
| 112 | } | ||
| 113 | |||
| 114 | ✗ | manifest::Failures ServerTool::FetchRemoteManifestEnsemble( | |
| 115 | const std::string &repository_url, const std::string &repository_name, | ||
| 116 | manifest::ManifestEnsemble *ensemble) const { | ||
| 117 | ✗ | const uint64_t minimum_timestamp = 0; | |
| 118 | ✗ | const shash::Any *base_catalog = NULL; | |
| 119 | ✗ | return manifest::Fetch(repository_url, repository_name, minimum_timestamp, | |
| 120 | base_catalog, signature_manager(), download_manager(), | ||
| 121 | ✗ | ensemble); | |
| 122 | } | ||
| 123 | |||
| 124 | ✗ | manifest::Manifest *ServerTool::FetchRemoteManifest( | |
| 125 | const std::string &repository_url, const std::string &repository_name, | ||
| 126 | const shash::Any &base_hash) const { | ||
| 127 | ✗ | manifest::ManifestEnsemble manifest_ensemble; | |
| 128 | ✗ | std::unique_ptr<manifest::Manifest> manifest; | |
| 129 | |||
| 130 | // fetch (and verify) the manifest | ||
| 131 | ✗ | const manifest::Failures retval = FetchRemoteManifestEnsemble( | |
| 132 | repository_url, repository_name, &manifest_ensemble); | ||
| 133 | |||
| 134 | ✗ | if (retval != manifest::kFailOk) { | |
| 135 | ✗ | LogCvmfs(kLogCvmfs, kLogStderr, | |
| 136 | "failed to fetch repository manifest " | ||
| 137 | "(%d - %s)", | ||
| 138 | retval, manifest::Code2Ascii(retval)); | ||
| 139 | ✗ | return NULL; | |
| 140 | } else { | ||
| 141 | // copy-construct a fresh manifest object because ManifestEnsemble will | ||
| 142 | // free manifest_ensemble.manifest when it goes out of scope | ||
| 143 | ✗ | manifest = std::unique_ptr<manifest::Manifest>( | |
| 144 | ✗ | new manifest::Manifest(*manifest_ensemble.manifest)); | |
| 145 | } | ||
| 146 | |||
| 147 | // check if manifest fetching was successful | ||
| 148 | ✗ | if (manifest.get() == nullptr) { | |
| 149 | ✗ | LogCvmfs(kLogCvmfs, kLogStderr, "failed to load repository manifest"); | |
| 150 | ✗ | return NULL; | |
| 151 | } | ||
| 152 | |||
| 153 | // check the provided base hash of the repository if provided | ||
| 154 | ✗ | if (!base_hash.IsNull() && manifest->catalog_hash() != base_hash) { | |
| 155 | ✗ | LogCvmfs(kLogCvmfs, kLogStderr, | |
| 156 | "base hash does not match manifest " | ||
| 157 | "(found: %s expected: %s)", | ||
| 158 | ✗ | manifest->catalog_hash().ToString().c_str(), | |
| 159 | ✗ | base_hash.ToString().c_str()); | |
| 160 | ✗ | return NULL; | |
| 161 | } | ||
| 162 | |||
| 163 | // return the fetched manifest (releasing pointer ownership) | ||
| 164 | ✗ | return manifest.release(); | |
| 165 | } | ||
| 166 | |||
| 167 | ✗ | manifest::Reflog *ServerTool::CreateEmptyReflog( | |
| 168 | const std::string &temp_directory, const std::string &repo_name) { | ||
| 169 | // create a new Reflog if there was none found yet | ||
| 170 | ✗ | const std::string tmp_path_prefix = temp_directory + "/new_reflog"; | |
| 171 | ✗ | const std::string tmp_path = CreateTempPath(tmp_path_prefix, 0600); | |
| 172 | |||
| 173 | ✗ | LogCvmfs(kLogCvmfs, kLogDebug, "creating new reflog '%s' for %s", | |
| 174 | tmp_path.c_str(), repo_name.c_str()); | ||
| 175 | ✗ | return manifest::Reflog::Create(tmp_path, repo_name); | |
| 176 | } | ||
| 177 |