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