CernVM-FS  2.13.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
signing_tool.cc
Go to the documentation of this file.
1 
5 #include "signing_tool.h"
6 
7 #include <string>
8 
9 #include "manifest.h"
10 #include "object_fetcher.h"
11 #include "reflog.h"
12 #include "server_tool.h"
13 #include "upload.h"
14 #include "util/exception.h"
15 #include "util/pointer.h"
16 
17 namespace {
18 
20 
21 } // namespace
22 
24  : server_tool_(server_tool) { }
25 
27 
29  const std::string &manifest_path, const std::string &repo_url,
30  const std::string &spooler_definition, const std::string &temp_dir,
31  const std::string &certificate, const std::string &priv_key,
32  const std::string &repo_name, const std::string &pwd,
33  const std::string &meta_info, const std::string &reflog_chksum_path,
34  const std::string &proxy, const bool garbage_collectable,
35  const bool bootstrap_shortcuts, const bool return_early,
36  const std::vector<shash::Any> reflog_catalogs) {
37  shash::Any reflog_hash;
38  if (reflog_chksum_path != "") {
39  if (!manifest::Reflog::ReadChecksum(reflog_chksum_path, &reflog_hash)) {
40  LogCvmfs(kLogCvmfs, kLogStderr, "Could not read reflog checksum");
42  }
43  }
44 
47 
48  if (!DirectoryExists(temp_dir)) {
49  LogCvmfs(kLogCvmfs, kLogStderr, "%s does not exist", temp_dir.c_str());
50  return kError;
51  }
52 
53  // prepare global manager modules
54  const bool follow_redirects = false;
55  if (!server_tool_->InitDownloadManager(follow_redirects, proxy)
56  || !server_tool_->InitSignatureManager("", certificate, priv_key)) {
57  LogCvmfs(kLogCvmfs, kLogStderr, "failed to init repo connection");
58  return kInitError;
59  }
60 
61  // init the download helper
62  ObjectFetcher object_fetcher(repo_name, repo_url, temp_dir,
65 
66  // Load Manifest
67  manifest = manifest::Manifest::LoadFile(manifest_path);
68  if (!manifest.IsValid()) {
69  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to parse manifest");
70  return kError;
71  }
72 
73  // reflog_chksum_path wasn't given, the reflog checksum can possibly be
74  // obtained from the manifest
75  if (reflog_chksum_path.empty()) {
76  reflog_hash = manifest->reflog_hash();
77  }
78 
79  // Connect to the spooler
80  const upload::SpoolerDefinition sd(spooler_definition,
81  manifest->GetHashAlgorithm());
82  spooler = upload::Spooler::Construct(sd);
83  if (!spooler.IsValid()) {
84  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to setup upload spooler");
85  return kInitError;
86  }
87 
89  if (!reflog_hash.IsNull()) {
90  reflog = server_tool_->FetchReflog(&object_fetcher, repo_name, reflog_hash);
91  if (!reflog.IsValid()) {
92  LogCvmfs(kLogCvmfs, kLogStderr, "reflog missing");
93  return kReflogMissing;
94  }
95  } else {
96  LogCvmfs(kLogCvmfs, kLogVerboseMsg, "no reflog (ignoring)");
97  if (spooler->Peek(".cvmfsreflog")) {
99  "no reflog hash specified but reflog is present");
100  return kError;
101  }
102  }
103 
104  // From here on things are potentially put in backend storage
105 
106  // Register callback for retrieving the certificate hash
107  upload::Spooler::CallbackPtr callback = spooler->RegisterListener(
109 
110  // Safe certificate (and wait for the upload through a Future)
111  spooler->ProcessCertificate(certificate);
112  const shash::Any certificate_hash = certificate_hash_.Get();
113  spooler->UnregisterListener(callback);
114 
115  if (certificate_hash.IsNull()) {
116  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to upload certificate");
117  return kError;
118  }
119 
120  // Safe repository meta info file
121  shash::Any metainfo_hash = manifest->meta_info();
122  if (!meta_info.empty()) {
123  upload::Spooler::CallbackPtr callback = spooler->RegisterListener(
125  spooler->ProcessMetainfo(meta_info);
126  metainfo_hash = metainfo_hash_.Get();
127  spooler->UnregisterListener(callback);
128 
129  if (metainfo_hash.IsNull()) {
130  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to upload meta info");
131  return kError;
132  }
133  }
134 
135  // Update Reflog database
136  if (reflog.IsValid()) {
137  reflog->BeginTransaction();
138 
139  if (!reflog->AddCatalog(manifest->catalog_hash())) {
140  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to add catalog to Reflog");
141  return kError;
142  }
143 
144  if (!reflog->AddCertificate(certificate_hash)) {
145  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to add certificate to Reflog");
146  return kError;
147  }
148 
149  if (!manifest->history().IsNull()) {
150  if (!reflog->AddHistory(manifest->history())) {
151  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to add history to Reflog");
152  return kError;
153  }
154  }
155 
156  if (!metainfo_hash.IsNull()) {
157  if (!reflog->AddMetainfo(metainfo_hash)) {
158  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to add meta info to Reflog");
159  return kError;
160  }
161  }
162 
163  // Callers of SigningTool may provide a list of additional catalogs that
164  // need to be added to reflog (e. g. for later garbage collection)
165  std::vector<shash::Any>::const_iterator i = reflog_catalogs.begin();
166  std::vector<shash::Any>::const_iterator iend = reflog_catalogs.end();
167  for (; i != iend; ++i) {
168  if (!reflog->AddCatalog(*i)) {
170  "Failed to add additional catalog %s to Reflog",
171  (*i).ToString().c_str());
172  return kError;
173  }
174  }
175 
176  reflog->CommitTransaction();
177 
178  // upload Reflog database
179  reflog->DropDatabaseFileOwnership();
180  const std::string reflog_db_file = reflog->database_file();
181  reflog.Destroy();
182  spooler->UploadReflog(reflog_db_file);
183  spooler->WaitForUpload();
184  reflog_hash.algorithm = manifest->GetHashAlgorithm();
185  manifest::Reflog::HashDatabase(reflog_db_file, &reflog_hash);
186  unlink(reflog_db_file.c_str());
187  if (spooler->GetNumberOfErrors()) {
188  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to upload Reflog (errors: %d)",
189  spooler->GetNumberOfErrors());
190  return kError;
191  }
192  if (!reflog_chksum_path.empty())
193  manifest::Reflog::WriteChecksum(reflog_chksum_path, reflog_hash);
194  }
195 
196  // Don't activate new manifest, just make sure all its references are uploaded
197  // and entered into the reflog
198  if (return_early) {
199  return kSuccess;
200  }
201 
202  // Update manifest
203  manifest->set_certificate(certificate_hash);
204  manifest->set_repository_name(repo_name);
205  manifest->set_publish_timestamp(time(NULL));
206  manifest->set_garbage_collectability(garbage_collectable);
207  manifest->set_has_alt_catalog_path(bootstrap_shortcuts);
208  if (!metainfo_hash.IsNull()) {
209  manifest->set_meta_info(metainfo_hash);
210  }
211  if (!reflog_hash.IsNull()) {
212  manifest->set_reflog_hash(reflog_hash);
213  }
214 
215  std::string signed_manifest = manifest->ExportString();
216  shash::Any published_hash(manifest->GetHashAlgorithm());
218  reinterpret_cast<const unsigned char *>(signed_manifest.data()),
219  signed_manifest.length(), &published_hash);
220  signed_manifest += "--\n" + published_hash.ToString() + "\n";
221 
222  // Create alternative bootstrapping symlinks for VOMS secured repos
223  if (manifest->has_alt_catalog_path()) {
224  const bool success = spooler->PlaceBootstrappingShortcut(
225  manifest->certificate())
226  && spooler->PlaceBootstrappingShortcut(
227  manifest->catalog_hash())
228  && (manifest->history().IsNull()
229  || spooler->PlaceBootstrappingShortcut(
230  manifest->history()))
231  && (metainfo_hash.IsNull()
232  || spooler->PlaceBootstrappingShortcut(
233  metainfo_hash));
234 
235  if (!success) {
237  "failed to place VOMS bootstrapping "
238  "symlinks");
239  return kError;
240  }
241  }
242 
243  // Sign manifest
244  unsigned char *sig;
245  unsigned sig_size;
246  const bool manifest_was_signed = server_tool_->signature_manager()->Sign(
247  reinterpret_cast<const unsigned char *>(published_hash.ToString().data()),
248  published_hash.GetHexSize(), &sig, &sig_size);
249  if (!manifest_was_signed) {
250  PANIC(kLogStderr, "Failed to sign manifest");
251  }
252 
253  // Write new manifest
254  signed_manifest += std::string(reinterpret_cast<char *>(sig), sig_size);
255  free(sig);
256  if (!SafeWriteToFile(signed_manifest, manifest_path, 0664)) {
257  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to write manifest (errno: %d)",
258  errno);
259  return kError;
260  }
261 
262  // Upload manifest
263  spooler->UploadManifest(manifest_path);
264  spooler->WaitForUpload();
265  unlink(manifest_path.c_str());
266  if (spooler->GetNumberOfErrors()) {
267  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to commit manifest (errors: %d)",
268  spooler->GetNumberOfErrors());
269  return kError;
270  }
271 
272  return kSuccess;
273 }
274 
276  const upload::SpoolerResult &result) {
277  shash::Any certificate_hash;
278  if (result.return_code == 0) {
279  certificate_hash = result.content_hash;
280  } else {
282  "Failed to upload certificate "
283  "(retcode: %d)",
284  result.return_code);
285  }
286  certificate_hash_.Set(certificate_hash);
287 }
288 
290  shash::Any metainfo_hash;
291  if (result.return_code == 0) {
292  metainfo_hash = result.content_hash;
293  } else {
294  LogCvmfs(kLogCvmfs, kLogStderr, "Failed to upload meta info (retcode: %d)",
295  result.return_code);
296  }
297  metainfo_hash_.Set(metainfo_hash);
298 }
int return_code
the return value of the spooler operation
Future< shash::Any > metainfo_hash_
Definition: signing_tool.h:55
std::string database_file() const
Definition: reflog.cc:321
bool IsNull() const
Definition: hash.h:371
const manifest::Manifest * manifest() const
Definition: repository.h:125
bool AddHistory(const shash::Any &history)
Definition: reflog.cc:134
Result Run(const std::string &manifest_path, const std::string &repo_url, const std::string &spooler_definition, const std::string &temp_dir, const std::string &certificate="", const std::string &priv_key="", const std::string &repo_name="", const std::string &pwd="", const std::string &meta_info="", const std::string &reflog_chksum_path="", const std::string &proxy="", const bool garbage_collectable=false, const bool bootstrap_shortcuts=false, const bool return_early=false, const std::vector< shash::Any > reflog_catalogs=std::vector< shash::Any >())
Definition: signing_tool.cc:28
HttpObjectFetcher ObjectFetcher
static bool ReadChecksum(const std::string &path, shash::Any *checksum)
Definition: reflog.cc:48
#define PANIC(...)
Definition: exception.h:29
manifest::Reflog * FetchReflog(ObjectFetcherT *object_fetcher, const std::string &repo_name, const shash::Any &reflog_hash)
void CertificateUploadCallback(const upload::SpoolerResult &result)
bool SafeWriteToFile(const std::string &content, const std::string &path, int mode)
Definition: posix.cc:2136
Algorithms algorithm
Definition: hash.h:122
void Set(const T &object)
Definition: future.h:53
bool AddCatalog(const shash::Any &catalog)
Definition: reflog.cc:128
signature::SignatureManager * signature_manager() const
Definition: server_tool.cc:101
T & Get()
Definition: future.h:66
download::DownloadManager * download_manager() const
Definition: server_tool.cc:96
bool AddMetainfo(const shash::Any &metainfo)
Definition: reflog.cc:140
bool Sign(const unsigned char *buffer, const unsigned buffer_size, unsigned char **signature, unsigned *signature_size)
Definition: signature.cc:780
Future< shash::Any > certificate_hash_
Definition: signing_tool.h:54
void BeginTransaction()
Definition: reflog.cc:281
static void HashDatabase(const std::string &database_path, shash::Any *hash_reflog)
Definition: reflog.cc:308
void DropDatabaseFileOwnership()
Definition: reflog.cc:299
ServerTool * server_tool_
Definition: signing_tool.h:53
bool DirectoryExists(const std::string &path)
Definition: posix.cc:824
bool AddCertificate(const shash::Any &certificate)
Definition: reflog.cc:121
void HashMem(const unsigned char *buffer, const unsigned buffer_size, Any *any_digest)
Definition: hash.cc:257
virtual ~SigningTool()
Definition: signing_tool.cc:26
bool InitSignatureManager(const std::string &pubkey_path, const std::string &certificate_path="", const std::string &private_key_path="")
Definition: server_tool.cc:44
void CommitTransaction()
Definition: reflog.cc:287
std::string meta_info() const
Definition: repository.h:128
const int kLogVerboseMsg
static bool WriteChecksum(const std::string &path, const shash::Any &value)
Definition: reflog.cc:65
bool InitDownloadManager(const bool follow_redirects, const std::string &proxy, const unsigned max_pool_handles=1)
Definition: server_tool.cc:17
void MetainfoUploadCallback(const upload::SpoolerResult &result)
static Manifest * LoadFile(const std::string &path)
Definition: manifest.cc:91
SigningTool(ServerTool *server_tool)
Definition: signing_tool.cc:23
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:545