45 bool XrdVomsMapfile::tried_configure =
false;
46 std::unique_ptr<XrdVomsMapfile> XrdVomsMapfile::mapper;
51 PathToString(
const std::vector<std::string> &path)
53 if (path.empty()) {
return "/";}
55 for (
const auto &entry : path) {
62 uint64_t monotonic_time_s() {
64 clock_gettime(CLOCK_MONOTONIC, &tp);
65 return tp.tv_sec + (tp.tv_nsec >= 500000000);
72 const std::string &mapfile)
73 : m_mapfile(mapfile), m_edest(erp)
76 if (-1 ==
stat(m_mapfile.c_str(), &statbuf)) {
77 m_edest->Emsg(
"XrdVomsMapfile", errno,
"Error checking the mapfile", m_mapfile.c_str());
80 memcpy(&m_mapfile_ctime, &statbuf.st_ctim,
sizeof(decltype(m_mapfile_ctime)));
82 if (!ParseMapfile(m_mapfile)) {
return;}
86 static_cast<void*
>(
this), 0,
"VOMS Mapfile refresh");
88 m_edest->Emsg(
"XrdVomsMapfile",
"Failed to launch VOMS mapfile monitoring thread");
100 XrdVomsMapfile::ParseMapfile(
const std::string &mapfile)
102 std::ifstream fstr(mapfile);
103 if (!fstr.is_open()) {
104 m_edest->
Emsg(
"ParseMapfile",
"Failed to open file", mapfile.c_str(), strerror(errno));
107 std::shared_ptr<std::vector<MapfileEntry>> entries(
new std::vector<MapfileEntry>());
110 if (ParseLine(line, entry.m_path, entry.m_target) && !entry.m_path.empty()) {
112 m_edest->
Log(
LogMask::Debug,
"ParseMapfile", PathToString(entry.m_path).c_str(),
"->", entry.m_target.c_str());
114 entries->emplace_back(entry);
123 XrdVomsMapfile::ParseLine(
const std::string &line, std::vector<std::string> &entry, std::string &target)
125 bool began_entry =
false;
126 bool finish_entry =
false;
127 bool began_target =
false;
130 for (
size_t idx=0; idx<line.size(); idx++) {
131 auto txt = line[idx];
132 if (!began_entry && !finish_entry) {
133 if (txt ==
'#') {
return false;}
134 else if (txt ==
'"') {began_entry =
true;}
135 else if (!isspace(txt)) {
return false;}
137 }
else if (began_entry && !finish_entry) {
139 if (idx + 1 == line.size()) {
return false;}
141 auto escaped_char = line[idx];
142 switch (escaped_char) {
167 }
else if (txt ==
'"') {
168 if (!element.empty()) entry.push_back(element);
170 }
else if (txt ==
'/') {
171 if (!element.empty()) entry.push_back(element);
173 }
else if (isprint(txt)) {
178 }
else if (!began_target) {
179 if (isspace(txt)) {
continue;}
185 }
else if (isspace(txt)) {
197 XrdVomsMapfile::Map(
const std::vector<std::string> &fqan)
199 decltype(m_entries) entries = m_entries;
200 if (!entries) {
return "";}
203 m_edest->
Log(
LogMask::Debug,
"VOMSMapfile",
"Mapping VOMS FQAN", PathToString(fqan).c_str());
206 for (
const auto &entry : *entries) {
207 if (Compare(entry, fqan)) {
209 m_edest->
Log(
LogMask::Debug,
"VOMSMapfile",
"Mapped FQAN to target", entry.m_target.c_str());
211 return entry.m_target;
219 XrdVomsMapfile::Compare(
const MapfileEntry &entry,
const std::vector<std::string> &fqan)
221 if (entry.m_path.empty()) {
return false;}
224 if (fqan.size() < entry.m_path.size()) {
return false;}
227 for (
size_t idx=0; idx<entry.m_path.size(); idx++) {
228 fqan_element.
assign(fqan[idx].c_str(), 0);
229 const auto &path_element = entry.m_path[idx];
230 if (!fqan_element.
matches(path_element.c_str())) {
return false;}
232 if (fqan.size() == entry.m_path.size()) {
return true;}
233 if (entry.m_path.back() ==
"*") {
return true;}
238 std::vector<std::string>
243 std::vector<std::string> path;
248 while ((from =
const_cast<XrdOucString&
>(group).tokenize(entry, from,
'/')) != -1) {
249 if (entry.
length() == 0)
continue;
250 path.emplace_back(entry.
c_str());
264 std::string gridmap_name;
265 auto gridmap_success = entity.
eaAPI->
Get(
"gridmap.name", gridmap_name);
266 if (gridmap_success && gridmap_name ==
"1") {
270 int from_vorg = 0, from_role = 0, from_grps = 0;
274 if (m_edest) m_edest->
Log(
LogMask::Debug,
"VOMSMapfile",
"Applying VOMS mapfile to incoming credential");
275 while (((from_vorg = vorg.
tokenize(entry_vorg, from_vorg,
' ')) != -1) &&
276 ((role ==
"") || (from_role = role.
tokenize(entry_role, from_role,
' ')) != -1) &&
277 ((from_grps = grps.
tokenize(entry_grps, from_grps,
' ')) != -1))
279 auto fqan = MakePath(entry_grps);
280 if (fqan.empty()) {
continue;}
284 if (strcmp(fqan[0].c_str(), entry_vorg.c_str())) {
continue;}
286 fqan.emplace_back(std::string(
"Role=") + entry_role.c_str());
287 fqan.emplace_back(
"Capability=NULL");
288 std::string username;
289 if (!(username = Map(fqan)).empty()) {
290 if (entity.
name) {free(entity.
name);}
291 entity.
name = strdup(username.c_str());
310 if (tried_configure) {
311 auto result = mapper.get();
313 result->SetErrorStream(erp);
318 tried_configure =
true;
323 char *config_filename =
nullptr;
328 XrdOucStream stream(erp, getenv(
"XRDINSTANCE"), &myEnv,
"=====> ");
331 if ((cfg_fd =
open(config_filename, O_RDONLY, 0)) < 0) {
332 if (erp) erp->
Emsg(
"Config", errno,
"open config file", config_filename);
337 std::string map_filename;
339 if (!strcmp(var,
"voms.mapfile")) {
341 if (!val || !val[0]) {
342 if (erp) erp->
Emsg(
"Config",
"VOMS mapfile not specified");
346 }
else if (!strcmp(var,
"voms.trace")) {
348 if (!val || !val[0]) {
349 if (erp) erp->
Emsg(
"Config",
"VOMS logging level not specified");
359 else if (!strcmp(val,
"none")) {erp->
setMsgMask(0);}
360 else {erp->
Emsg(
"Config",
"voms.trace encountered an unknown directive:", val);}
366 if (!map_filename.empty()) {
367 if (erp) erp->
Emsg(
"Config",
"Will initialize VOMS mapfile", map_filename.c_str());
369 if (!mapper->IsValid()) {
370 mapper.reset(
nullptr);
380 XrdVomsMapfile::MaintenanceThread(
void *myself_raw)
384 auto now = monotonic_time_s();
385 auto next_update = now + m_update_interval;
387 now = monotonic_time_s();
388 auto remaining = next_update - now;
389 auto rval = sleep(remaining);
394 next_update = monotonic_time_s() + m_update_interval;
396 if (-1 ==
stat(myself->m_mapfile.c_str(), &statbuf)) {
397 myself->m_edest->Emsg(
"XrdVomsMapfile", errno,
"Error checking the mapfile",
398 myself->m_mapfile.c_str());
399 myself->m_mapfile_ctime.tv_sec = 0;
400 myself->m_mapfile_ctime.tv_nsec = 0;
401 myself->m_is_valid =
false;
410 if ((myself->m_mapfile_ctime.tv_sec == statbuf.st_ctim.tv_sec) &&
411 (myself->m_mapfile_ctime.tv_nsec == statbuf.st_ctim.tv_nsec))
413 myself->m_edest->Log(
LogMask::Debug,
"Maintenance",
"Not reloading VOMS mapfile; "
414 "no changes detected.");
417 memcpy(&myself->m_mapfile_ctime, &statbuf.st_ctim,
sizeof(decltype(statbuf.st_ctim)));
419 myself->m_edest->Log(
LogMask::Debug,
"Maintenance",
"Reloading VOMS mapfile now");
420 if ( !(myself->m_is_valid = myself->ParseMapfile(myself->m_mapfile)) ) {
421 myself->m_edest->Log(
LogMask::Error,
"Maintenance",
"Failed to reload VOMS mapfile");
int stat(const char *path, struct stat *buf)
int open(const char *path, int oflag,...)
void getline(uchar *buff, int blen)
static bool Import(const char *var, char *&val)
char * GetMyFirstWord(int lowcase=0)
char * GetWord(int lowcase=0)
int Attach(int FileDescriptor, int bsz=2047)
const char * c_str() const
void assign(const char *s, int j, int k=-1)
int matches(const char *s, char wch=' *')
int tokenize(XrdOucString &tok, int from, char del=':')
XrdSecAttr * Get(const void *sigkey)
char * vorg
Entity's virtual organization(s)
XrdSecEntityAttr * eaAPI
non-const API to attributes
char * grps
Entity's group name(s)
char * name
Entity's name.
char * role
Entity's role(s)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
void setMsgMask(int mask)
void Log(int mask, const char *esfx, const char *text1, const char *text2=0, const char *text3=0)
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)
static XrdVomsMapfile * Get()
static XrdVomsMapfile * Configure(XrdSysError *)
virtual ~XrdVomsMapfile()
int Apply(XrdSecEntity &)