XRootD
Loading...
Searching...
No Matches
XrdMacaroonsConfigure.cc
Go to the documentation of this file.
2
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
12using namespace Macaroons;
13
14static 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")) {
24 } else if (!strcasecmp(val, "allow")) {
26 } else if (!strcasecmp(val, "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
36bool 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
96bool 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
143bool 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
167bool 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
180bool 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
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)
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)
void setMsgMask(int mask)