CernVM-FS  2.12.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 "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) 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  fqrn = *args.find('f')->second;
114  key_path = *args.find('k')->second;
115  if (args.find('t') != args.end()) text = *args.find('t')->second;
116 
117  whitelist::Failures retval_wl;
118  letter::Failures retval_ltr;
119 
120  if (verify) {
121  if (!InitVerifyingSignatureManager(key_path)) {
122  return 2;
123  }
124 
125  const bool follow_redirects = false;
126  const unsigned max_pool_handles = 2;
127  const string proxy =
128  (args.find('@') != args.end()) ? *args.find('@')->second : "";
129  if (!this->InitDownloadManager(follow_redirects, proxy, max_pool_handles)) {
130  LogCvmfs(kLogCvmfs, kLogStderr, "failed to init repo connection");
131  return 2;
132  }
133 
134  whitelist::Whitelist whitelist(fqrn, download_manager(),
135  signature_manager());
136  retval_wl = whitelist.LoadUrl(repository_url);
137  if (retval_wl != whitelist::kFailOk) {
138  LogCvmfs(kLogCvmfs, kLogStderr, "failed to load whitelist (%d): %s",
139  retval_wl, whitelist::Code2Ascii(retval_wl));
140  return 2;
141  }
142 
143  if (erlang) {
144  const char *ready = "ready";
145  WriteErlang(reinterpret_cast<const unsigned char *>(ready), 5);
146  }
147 
148  char exit_code = 0;
149  do {
150  if (erlang) {
151  unsigned char buf[65000];
152  int length = ReadErlang(buf);
153  text = string(reinterpret_cast<char *>(buf), length);
154  } else {
155  if (text == "") {
156  char c;
157  int num_read;
158  while ((num_read = read(0, &c, 1)) == 1) {
159  if (c == '\n')
160  break;
161  text.push_back(c);
162  }
163  if (num_read != 1) return exit_code;
164  }
165  }
166 
167  if ((time(NULL) + 3600*24*3) > whitelist.expires()) {
168  LogCvmfs(kLogCvmfs, kLogStderr, "reloading whitelist");
169  whitelist::Whitelist refresh(fqrn, download_manager(),
170  signature_manager());
171  retval_wl = refresh.LoadUrl(repository_url);
172  if (retval_wl == whitelist::kFailOk)
173  whitelist = refresh;
174  }
175 
176  string message;
177  string cert;
178  letter::Letter letter(fqrn, text, signature_manager());
179  retval_ltr = letter.Verify(max_age, &message, &cert);
180  if (retval_ltr != letter::kFailOk) {
181  exit_code = 3;
182  LogCvmfs(kLogCvmfs, kLogStderr, "%s", letter::Code2Ascii(retval_ltr));
183  } else {
184  if (whitelist.IsExpired()) {
185  exit_code = 4;
186  LogCvmfs(kLogCvmfs, kLogStderr, "whitelist expired");
187  } else {
188  retval_wl = whitelist.VerifyLoadedCertificate();
189  if (retval_wl == whitelist::kFailOk) {
190  exit_code = 0;
191  } else {
192  exit_code = 5;
194  whitelist::Code2Ascii(retval_wl));
195  }
196  }
197  }
198 
199  if (erlang) {
200  if ((exit_code == 0) && (message.length() > 60000))
201  exit_code = 6;
202  WriteErlang(reinterpret_cast<unsigned char *>(&exit_code), 1);
203  if (exit_code == 0)
204  WriteErlang(reinterpret_cast<const unsigned char *>(message.data()),
205  message.length());
206  } else {
207  if (exit_code == 0)
209  message.c_str());
210  }
211  text = "";
212  } while (erlang);
213 
214  return exit_code;
215  }
216 
217  if (!InitSigningSignatureManager(certificate_path,
218  key_path,
219  certificate_password)) {
220  return 2;
221  }
222 
223  if (text == "") {
224  char c;
225  while (read(0, &c, 1) == 1) {
226  if (c == '\n')
227  break;
228  text.push_back(c);
229  }
230  }
231 
232  letter::Letter text_letter(fqrn, text, signature_manager());
234  text_letter.Sign(hash_algorithm).c_str());
235 
236  return 0;
237 }
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)
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:528