XRootD
XrdMacaroonsConfigure.cc
Go to the documentation of this file.
1 #include "XrdMacaroonsHandler.hh"
2 
3 #include "XrdOuc/XrdOucStream.hh"
4 #include "XrdSys/XrdSysE2T.hh"
5 
6 #include <cerrno>
7 
8 #include <fcntl.h>
9 #include <openssl/bio.h>
10 #include <openssl/evp.h>
11 
12 using namespace Macaroons;
13 
14 static bool xonmissing(XrdOucStream &config_obj, XrdSysError *log, Handler::AuthzBehavior &behavior)
15 {
16  char *val = config_obj.GetWord();
17  if (!val || !val[0])
18  {
19  log->Emsg("Config", "macaroons.onmissing requires a value (valid values: passthrough [default], allow, deny)");
20  return false;
21  }
22  if (!strcasecmp(val, "passthrough")) {
23  behavior = Handler::AuthzBehavior::PASSTHROUGH;
24  } else if (!strcasecmp(val, "allow")) {
25  behavior = Handler::AuthzBehavior::ALLOW;
26  } else if (!strcasecmp(val, "deny")) {
27  behavior = Handler::AuthzBehavior::DENY;
28  } else
29  {
30  log->Emsg("Config", "macaroons.onmissing is invalid (valid values: passthrough [default], allow, deny)! Provided value:", val);
31  return false;
32  }
33  return true;
34 }
35 
36 bool Handler::Config(const char *config, XrdOucEnv *env, XrdSysError *log,
37  std::string &location, std::string &secret, ssize_t &max_duration,
38  AuthzBehavior &behavior)
39 {
40  XrdOucStream config_obj(log, getenv("XRDINSTANCE"), env, "=====> ");
41 
42  // Open and attach the config file
43  //
44  int cfg_fd;
45  if ((cfg_fd = open(config, O_RDONLY, 0)) < 0) {
46  return log->Emsg("Config", errno, "open config file", config);
47  }
48  config_obj.Attach(cfg_fd);
49  static const char *cvec[] = { "*** macaroons plugin config:", 0 };
50  config_obj.Capture(cvec);
51 
52  // Set default mask for logging.
54 
55  // Set default maximum duration (24 hours).
56  max_duration = 24*3600;
57 
58  // Process items
59  //
60  char *orig_var, *var;
61  bool success = true, ismine;
62  while ((orig_var = config_obj.GetMyFirstWord())) {
63  var = orig_var;
64  if ((ismine = !strncmp("all.sitename", var, 12))) var += 4;
65  else if ((ismine = !strncmp("macaroons.", var, 10)) && var[10]) var += 10;
66 
67 
68 
69  if (!ismine) {continue;}
70 
71  if (!strcmp("secretkey", var)) {success = xsecretkey(config_obj, log, secret);}
72  else if (!strcmp("sitename", var)) {success = xsitename(config_obj, log, location);}
73  else if (!strcmp("trace", var)) {success = xtrace(config_obj, log);}
74  else if (!strcmp("maxduration", var)) {success = xmaxduration(config_obj, log, max_duration);}
75  else if (!strcmp("onmissing", var)) {success = xonmissing(config_obj, log, behavior);}
76  else {
77  log->Say("Config warning: ignoring unknown directive '", orig_var, "'.");
78  config_obj.Echo();
79  continue;
80  }
81  if (!success) {
82  config_obj.Echo();
83  break;
84  }
85  }
86 
87  if (success && !location.size())
88  {
89  log->Emsg("Config", "all.sitename must be specified to use macaroons.");
90  return false;
91  }
92 
93  return success;
94 }
95 
96 bool Handler::xtrace(XrdOucStream &Config, XrdSysError *log)
97 {
98  static struct traceopts { const char *opname; enum LogMask opval; } tropts[] = {
99  { "all", LogMask::All },
100  { "error", LogMask::Error },
101  { "warning", LogMask::Warning },
102  { "info", LogMask::Info },
103  { "debug", LogMask::Debug }
104  };
105 
106  int i, neg, trval = 0, numopts = sizeof(tropts)/sizeof(struct traceopts);
107 
108  char *val = Config.GetWord();
109 
110  if (!val || !*val) {
111  log->Emsg("Config", "macaroons.trace requires at least one directive"
112  " [ all | error | warning | info | debug | none | off ]");
113  return false;
114  }
115 
116  while (val && *val) {
117  if (strcmp(val, "off") == 0 || strcmp(val, "none") == 0) {
118  trval = 0;
119  } else {
120  if ((neg = (val[0] == '-' && val[1])))
121  val++;
122  for (i = 0; i < numopts; i++) {
123  if (!strcmp(val, tropts[i].opname)) {
124  if (neg)
125  trval &= ~tropts[i].opval;
126  else
127  trval |= tropts[i].opval;
128  break;
129  }
130  }
131  if (neg) --val;
132  if (i >= numopts)
133  log->Emsg("Config", "macaroons.trace: ignoring invalid trace option:", val);
134  }
135  val = Config.GetWord();
136  }
137 
138  log->setMsgMask(trval);
139 
140  return true;
141 }
142 
143 bool Handler::xmaxduration(XrdOucStream &config_obj, XrdSysError *log, ssize_t &max_duration)
144 {
145  char *val = config_obj.GetWord();
146  if (!val || !val[0])
147  {
148  log->Emsg("Config", "macaroons.maxduration requires a value");
149  return false;
150  }
151  char *endptr = nullptr;
152  long int max_duration_parsed = strtoll(val, &endptr, 10);
153  if (endptr == val)
154  {
155  log->Emsg("Config", "Unable to parse macaroons.maxduration as an integer", val);
156  return false;
157  }
158  if (errno != 0)
159  {
160  log->Emsg("Config", errno, "parse macaroons.maxduration as an integer.");
161  }
162  max_duration = max_duration_parsed;
163 
164  return true;
165 }
166 
167 bool Handler::xsitename(XrdOucStream &config_obj, XrdSysError *log, std::string &location)
168 {
169  char *val = config_obj.GetWord();
170  if (!val || !val[0])
171  {
172  log->Emsg("Config", "all.sitename requires a name");
173  return false;
174  }
175 
176  location = val;
177  return true;
178 }
179 
180 bool Handler::xsecretkey(XrdOucStream &config_obj, XrdSysError *log, std::string &secret)
181 {
182  char *val = config_obj.GetWord();
183 
184  if (!val || !val[0]) {
185  log->Emsg("Config", "Shared secret key not specified");
186  return false;
187  }
188 
189  BIO *bio = BIO_new_file(val, "rb");
190  if (!bio) {
191  log->Emsg("Config", "Failed to open shared secret key file", val);
192  return false;
193  }
194 
195  BIO *b64 = BIO_new(BIO_f_base64());
196  if (!b64) {
197  BIO_free(bio);
198  log->Emsg("Config", "Failed to allocate base64 filter");
199  return false;
200  }
201 
202  BIO *bio_out = BIO_new(BIO_s_mem());
203  if (!bio_out) {
204  BIO_free(b64);
205  BIO_free(bio);
206  log->Emsg("Config", "Failed to allocate BIO output");
207  return false;
208  }
209 
210  BIO_push(b64, bio);
211 
212  int inlen;
213  char inbuf[512];
214 
215  while ((inlen = BIO_read(b64, inbuf, 512)) > 0) {
216  if (inlen < 0) {
217  if (errno == EINTR) continue;
218  break;
219  } else {
220  BIO_write(bio_out, inbuf, inlen);
221  }
222  }
223 
224  if (inlen < 0) {
225  BIO_free_all(bio_out);
226  BIO_free_all(b64);
227  log->Emsg("Config", errno, "read secret key.");
228  return false;
229  }
230 
231  if (!BIO_flush(bio_out)) {
232  BIO_free_all(bio_out);
233  BIO_free_all(b64);
234  log->Emsg("Config", errno, "flush secret key.");
235  return false;
236  }
237 
238  char *decoded;
239  long data_len = BIO_get_mem_data(bio_out, &decoded);
240 
241  secret = std::string(decoded, data_len);
242 
243  BIO_free_all(bio_out);
244  BIO_free_all(b64);
245 
246  if (secret.size() < 32) {
247  log->Emsg("Config", "Secret key is too short; must be 32 bytes long. Try running 'openssl rand -base64 -out", val, "64' to generate a new key");
248  return false;
249  }
250 
251  return true;
252 }
static bool xonmissing(XrdOucStream &config_obj, XrdSysError *log, Handler::AuthzBehavior &behavior)
#define open
Definition: XrdPosix.hh:76
bool Debug
@ Error
static bool Config(const char *config, XrdOucEnv *env, XrdSysError *log, std::string &location, std::string &secret, ssize_t &max_duration, AuthzBehavior &behavior)
char * GetMyFirstWord(int lowcase=0)
char * GetWord(int lowcase=0)
int Attach(int FileDescriptor, int bsz=2047)
static void Capture(const char **cVec=0, bool linefeed=true)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
void Say(const char *text1, const char *text2=0, const char *txt3=0, const char *text4=0, const char *text5=0, const char *txt6=0)
Definition: XrdSysError.cc:141
void setMsgMask(int mask)
Definition: XrdSysError.hh:154
@ Warning
XrdCmsConfig Config