CernVM-FS  2.13.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
swissknife_letter.cc
Go to the documentation of this file.
1 
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 "letter.h"
18 #include "network/download.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)
36  exit(0);
37  assert(read_all == num_bytes);
38 }
39 
40 
41 static void WriteStdoutBytes(const unsigned char *buf,
42  const uint16_t num_bytes) {
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())
82  verify = true;
83  if ((args.find('s') != args.end()) && verify) {
85  "invalid option combination (sign + verify)");
86  return 1;
87  }
88 
89  bool erlang = false;
90  string repository_url;
91  string certificate_path;
92  string certificate_password;
93  shash::Algorithms hash_algorithm = shash::kSha1;
94  uint64_t max_age = kDefaultMaxAge;
95  if (verify) {
96  repository_url = *args.find('r')->second;
97  max_age = String2Uint64(*args.find('m')->second);
98  if (args.find('e') != args.end())
99  erlang = true;
100  } else {
101  certificate_path = *args.find('c')->second;
102  if (args.find('p') != args.end())
103  certificate_password = *args.find('p')->second;
104  if (args.find('a') != args.end()) {
105  hash_algorithm = shash::ParseHashAlgorithm(*args.find('a')->second);
106  if (hash_algorithm == shash::kAny) {
107  LogCvmfs(kLogCvmfs, kLogStderr, "unknown hash algorithm");
108  return 1;
109  }
110  }
111  }
112  string fqrn;
113  string text;
114  string key_path;
115  fqrn = *args.find('f')->second;
116  key_path = *args.find('k')->second;
117  if (args.find('t') != args.end())
118  text = *args.find('t')->second;
119 
120  whitelist::Failures retval_wl;
121  letter::Failures retval_ltr;
122 
123  if (verify) {
124  if (!InitSignatureManager(key_path)) {
125  return 2;
126  }
127 
128  const bool follow_redirects = false;
129  const unsigned max_pool_handles = 2;
130  const string proxy = (args.find('@') != args.end())
131  ? *args.find('@')->second
132  : "";
133  if (!this->InitDownloadManager(follow_redirects, proxy, max_pool_handles)) {
134  LogCvmfs(kLogCvmfs, kLogStderr, "failed to init repo connection");
135  return 2;
136  }
137 
138  whitelist::Whitelist whitelist(fqrn, download_manager(),
139  signature_manager());
140  retval_wl = whitelist.LoadUrl(repository_url);
141  if (retval_wl != whitelist::kFailOk) {
142  LogCvmfs(kLogCvmfs, kLogStderr, "failed to load whitelist (%d): %s",
143  retval_wl, whitelist::Code2Ascii(retval_wl));
144  return 2;
145  }
146 
147  if (erlang) {
148  const char *ready = "ready";
149  WriteErlang(reinterpret_cast<const unsigned char *>(ready), 5);
150  }
151 
152  char exit_code = 0;
153  do {
154  if (erlang) {
155  unsigned char buf[65000];
156  const int length = ReadErlang(buf);
157  text = string(reinterpret_cast<char *>(buf), length);
158  } else {
159  if (text == "") {
160  char c;
161  int num_read;
162  while ((num_read = read(0, &c, 1)) == 1) {
163  if (c == '\n')
164  break;
165  text.push_back(c);
166  }
167  if (num_read != 1)
168  return exit_code;
169  }
170  }
171 
172  if ((time(NULL) + 3600 * 24 * 3) > whitelist.expires()) {
173  LogCvmfs(kLogCvmfs, kLogStderr, "reloading whitelist");
174  whitelist::Whitelist refresh(fqrn, download_manager(),
175  signature_manager());
176  retval_wl = refresh.LoadUrl(repository_url);
177  if (retval_wl == whitelist::kFailOk)
178  whitelist = refresh;
179  }
180 
181  string message;
182  string cert;
183  letter::Letter letter(fqrn, text, signature_manager());
184  retval_ltr = letter.Verify(max_age, &message, &cert);
185  if (retval_ltr != letter::kFailOk) {
186  exit_code = 3;
187  LogCvmfs(kLogCvmfs, kLogStderr, "%s", letter::Code2Ascii(retval_ltr));
188  } else {
189  if (whitelist.IsExpired()) {
190  exit_code = 4;
191  LogCvmfs(kLogCvmfs, kLogStderr, "whitelist expired");
192  } else {
193  retval_wl = whitelist.VerifyLoadedCertificate();
194  if (retval_wl == whitelist::kFailOk) {
195  exit_code = 0;
196  } else {
197  exit_code = 5;
199  whitelist::Code2Ascii(retval_wl));
200  }
201  }
202  }
203 
204  if (erlang) {
205  if ((exit_code == 0) && (message.length() > 60000))
206  exit_code = 6;
207  WriteErlang(reinterpret_cast<unsigned char *>(&exit_code), 1);
208  if (exit_code == 0)
209  WriteErlang(reinterpret_cast<const unsigned char *>(message.data()),
210  message.length());
211  } else {
212  if (exit_code == 0)
214  message.c_str());
215  }
216  text = "";
217  } while (erlang);
218 
219  return exit_code;
220  }
221 
222  if (!InitSignatureManager("", certificate_path, key_path)) {
223  return 2;
224  }
225 
226  if (text == "") {
227  char c;
228  while (read(0, &c, 1) == 1) {
229  if (c == '\n')
230  break;
231  text.push_back(c);
232  }
233  }
234 
235  letter::Letter text_letter(fqrn, text, signature_manager());
237  text_letter.Sign(hash_algorithm).c_str());
238 
239  return 0;
240 }
Failures
Definition: letter.h:18
Failures LoadUrl(const std::string &base_url)
Definition: whitelist.cc:214
Failures VerifyLoadedCertificate() const
Definition: whitelist.cc:94
Failures Verify(uint64_t max_age, std::string *msg, std::string *cert)
Definition: letter.cc:57
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:26
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:82
uint64_t String2Uint64(const string &value)
Definition: string.cc:240
std::map< char, SharedPtr< std::string > > ArgumentList
Definition: swissknife.h:72
bool IsExpired() const
Definition: whitelist.cc:88
Algorithms ParseHashAlgorithm(const string &algorithm_option)
Definition: hash.cc:71
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)
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:545