CernVM-FS  2.11.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
swissknife_letter.cc
Go to the documentation of this file.
1 
7 #include "cvmfs_config.h"
8 #include "swissknife_letter.h"
9 
10 #include <inttypes.h>
11 #include <termios.h>
12 
13 #include <cassert>
14 
15 #include "crypto/hash.h"
16 #include "crypto/signature.h"
17 #include "download.h"
18 #include "letter.h"
19 #include "util/string.h"
20 #include "whitelist.h"
21 
22 using namespace std; // NOLINT
23 
24 
25 static void ReadStdinBytes(unsigned char *buf, const uint16_t num_bytes) {
26  int read_chunk;
27  unsigned read_all = 0;
28 
29  do {
30  if ((read_chunk = read(0, buf+read_all, num_bytes-read_all)) <= 0)
31  break;
32  read_all += read_chunk;
33  } while (read_all < num_bytes);
34 
35  if (read_chunk == 0) exit(0);
36  assert(read_all == num_bytes);
37 }
38 
39 
40 static void WriteStdoutBytes(const unsigned char *buf,
41  const uint16_t num_bytes)
42 {
43  int wrote_chunk;
44  unsigned wrote_all = 0;
45 
46  do {
47  if ((wrote_chunk = write(1, buf+wrote_all, num_bytes-wrote_all)) <= 0)
48  break;
49  wrote_all += wrote_chunk;
50  } while (wrote_all < num_bytes);
51 
52  assert(wrote_all == num_bytes);
53 }
54 
55 
56 static uint16_t ReadErlang(unsigned char *buf) {
57  int len;
58 
59  ReadStdinBytes(buf, 2);
60  len = (buf[0] << 8) | buf[1];
61  if (len > 0)
62  ReadStdinBytes(buf, len);
63  return len;
64 }
65 
66 
67 static void WriteErlang(const unsigned char *buf, int len) {
68  unsigned char li;
69 
70  li = (len >> 8) & 0xff;
71  WriteStdoutBytes(&li, 1);
72  li = len & 0xff;
73  WriteStdoutBytes(&li, 1);
74 
75  WriteStdoutBytes(buf, len);
76 }
77 
78 
80  bool verify = false;
81  if (args.find('v') != args.end()) verify = true;
82  if ((args.find('s') != args.end()) && verify) {
84  "invalid option combination (sign + verify)");
85  return 1;
86  }
87 
88  bool erlang = false;
89  string repository_url;
90  string certificate_path;
91  string certificate_password;
92  shash::Algorithms hash_algorithm = shash::kSha1;
93  uint64_t max_age = kDefaultMaxAge;
94  if (verify) {
95  repository_url = *args.find('r')->second;
96  max_age = String2Uint64(*args.find('m')->second);
97  if (args.find('e') != args.end()) erlang = true;
98  } else {
99  certificate_path = *args.find('c')->second;
100  if (args.find('p') != args.end())
101  certificate_password = *args.find('p')->second;
102  if (args.find('a') != args.end()) {
103  hash_algorithm = shash::ParseHashAlgorithm(*args.find('a')->second);
104  if (hash_algorithm == shash::kAny) {
105  LogCvmfs(kLogCvmfs, kLogStderr, "unknown hash algorithm");
106  return 1;
107  }
108  }
109  }
110  string fqrn;
111  string text;
112  string key_path;
113  string cacrl_path;
114  fqrn = *args.find('f')->second;
115  key_path = *args.find('k')->second;
116  if (args.find('t') != args.end()) text = *args.find('t')->second;
117  if (args.find('z') != args.end()) cacrl_path = *args.find('z')->second;
118 
119  whitelist::Failures retval_wl;
120  letter::Failures retval_ltr;
121 
122  if (verify) {
123  if (!InitVerifyingSignatureManager(key_path, cacrl_path)) {
124  return 2;
125  }
126 
127  const bool follow_redirects = false;
128  const unsigned max_pool_handles = 2;
129  const string proxy =
130  (args.find('@') != args.end()) ? *args.find('@')->second : "";
131  if (!this->InitDownloadManager(follow_redirects, proxy, max_pool_handles)) {
132  LogCvmfs(kLogCvmfs, kLogStderr, "failed to init repo connection");
133  return 2;
134  }
135 
136  whitelist::Whitelist whitelist(fqrn, download_manager(),
137  signature_manager());
138  retval_wl = whitelist.LoadUrl(repository_url);
139  if (retval_wl != whitelist::kFailOk) {
140  LogCvmfs(kLogCvmfs, kLogStderr, "failed to load whitelist (%d): %s",
141  retval_wl, whitelist::Code2Ascii(retval_wl));
142  return 2;
143  }
144 
145  if (erlang) {
146  const char *ready = "ready";
147  WriteErlang(reinterpret_cast<const unsigned char *>(ready), 5);
148  }
149 
150  char exit_code = 0;
151  do {
152  if (erlang) {
153  unsigned char buf[65000];
154  int length = ReadErlang(buf);
155  text = string(reinterpret_cast<char *>(buf), length);
156  } else {
157  if (text == "") {
158  char c;
159  int num_read;
160  while ((num_read = read(0, &c, 1)) == 1) {
161  if (c == '\n')
162  break;
163  text.push_back(c);
164  }
165  if (num_read != 1) return exit_code;
166  }
167  }
168 
169  if ((time(NULL) + 3600*24*3) > whitelist.expires()) {
170  LogCvmfs(kLogCvmfs, kLogStderr, "reloading whitelist");
171  whitelist::Whitelist refresh(fqrn, download_manager(),
172  signature_manager());
173  retval_wl = refresh.LoadUrl(repository_url);
174  if (retval_wl == whitelist::kFailOk)
175  whitelist = refresh;
176  }
177 
178  string message;
179  string cert;
180  letter::Letter letter(fqrn, text, signature_manager());
181  retval_ltr = letter.Verify(max_age, &message, &cert);
182  if (retval_ltr != letter::kFailOk) {
183  exit_code = 3;
184  LogCvmfs(kLogCvmfs, kLogStderr, "%s", letter::Code2Ascii(retval_ltr));
185  } else {
186  if (whitelist.IsExpired()) {
187  exit_code = 4;
188  LogCvmfs(kLogCvmfs, kLogStderr, "whitelist expired");
189  } else {
190  retval_wl = whitelist.VerifyLoadedCertificate();
191  if (retval_wl == whitelist::kFailOk) {
192  exit_code = 0;
193  } else {
194  exit_code = 5;
196  whitelist::Code2Ascii(retval_wl));
197  }
198  }
199  }
200 
201  if (erlang) {
202  if ((exit_code == 0) && (message.length() > 60000))
203  exit_code = 6;
204  WriteErlang(reinterpret_cast<unsigned char *>(&exit_code), 1);
205  if (exit_code == 0)
206  WriteErlang(reinterpret_cast<const unsigned char *>(message.data()),
207  message.length());
208  } else {
209  if (exit_code == 0)
211  message.c_str());
212  }
213  text = "";
214  } while (erlang);
215 
216  return exit_code;
217  }
218 
219  if (!InitSigningSignatureManager(certificate_path,
220  key_path,
221  certificate_password)) {
222  return 2;
223  }
224 
225  if (text == "") {
226  char c;
227  while (read(0, &c, 1) == 1) {
228  if (c == '\n')
229  break;
230  text.push_back(c);
231  }
232  }
233 
234  letter::Letter text_letter(fqrn, text, signature_manager());
236  text_letter.Sign(hash_algorithm).c_str());
237 
238  return 0;
239 }
#define LogCvmfs(source, mask,...)
Definition: logging.h:22
Failures
Definition: letter.h:18
Failures LoadUrl(const std::string &base_url)
Definition: whitelist.cc:216
Failures VerifyLoadedCertificate() const
Definition: whitelist.cc:95
Failures Verify(uint64_t max_age, std::string *msg, std::string *cert)
Definition: letter.cc:64
assert((mem||(size==0))&&"Out Of Memory")
Algorithms
Definition: hash.h:41
static void ReadStdinBytes(unsigned char *buf, const uint16_t num_bytes)
std::string Sign(const shash::Algorithms hash_algorithm)
Definition: letter.cc:30
const char * Code2Ascii(const Failures error)
Definition: whitelist.h:49
static void WriteStdoutBytes(const unsigned char *buf, const uint16_t num_bytes)
int Main(const ArgumentList &args)
const whitelist::Whitelist * whitelist() const
Definition: repository.h:124
time_t expires() const
Definition: whitelist.cc:83
uint64_t String2Uint64(const string &value)
Definition: string.cc:228
std::map< char, SharedPtr< std::string > > ArgumentList
Definition: swissknife.h:72
bool IsExpired() const
Definition: whitelist.cc:89
Algorithms ParseHashAlgorithm(const string &algorithm_option)
Definition: hash.cc:72
const char * Code2Ascii(const Failures error)
Definition: letter.h:30
static void WriteErlang(const unsigned char *buf, int len)
static uint16_t ReadErlang(unsigned char *buf)