XRootD
XrdOucGMap.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d O u c G M a p . h h */
4 /* */
5 /* (c) 2006 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* All Rights Reserved */
7 /* Produced by Andrew Hanushevsky for Stanford University under contract */
8 /* DE-AC02-76-SFO0515 with the Department of Energy */
9 /* */
10 /* This file is part of the XRootD software suite. */
11 /* */
12 /* XRootD is free software: you can redistribute it and/or modify it under */
13 /* the terms of the GNU Lesser General Public License as published by the */
14 /* Free Software Foundation, either version 3 of the License, or (at your */
15 /* option) any later version. */
16 /* */
17 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20 /* License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25 /* */
26 /* The copyright holder's institutional names and contributor's names may not */
27 /* be used to endorse or promote products derived from this software without */
28 /* specific prior written permission of the institution or contributor. */
29 /******************************************************************************/
30 
31 /* ************************************************************************** */
32 /* */
33 /* Interface to grid map files */
34 /* */
35 /* This code was initially in XrdSecProtocolgsi. It has been extracted */
36 /* to allow usage in other contexts, namely XrdHttp. */
37 /* */
38 /* ************************************************************************** */
39 
40 #include <cerrno>
41 #include <fcntl.h>
42 #include <sys/stat.h>
43 #include <cstdio>
44 #include <cstdlib>
45 #include <cstring>
46 
47 
48 #include "XrdOuc/XrdOucEnv.hh"
49 #include "XrdOuc/XrdOucGMap.hh"
50 #include "XrdOuc/XrdOucTrace.hh"
51 #include "XrdOuc/XrdOucStream.hh"
52 #include "XrdSys/XrdSysE2T.hh"
53 
55  kBegins = 1,
56  kEnds = 2,
57  kContains = 4
58  };
59 
60 #define PRINT(t,n,y) {if (t) {t->Beg(n); std::cerr <<y; t->End();}}
61 #define DEBUG(d,t,n,y) {if (d && t) {t->Beg(n); std::cerr <<y; t->End();}}
62 
63 //__________________________________________________________________________
64 static int FindMatchingCondition(const char *, XrdSecGMapEntry_t *mc, void *xmp)
65 {
66  // Print content of entry 'ui' and go to next
67 
69 
70  bool match = 0;
71  if (mc && mpe) {
72  if (mc->type == kContains) {
73  if (mpe->val.find(mc->val) != STR_NPOS) match = 1;
74  } else if (mc->type == kBegins) {
75  if (mpe->val.beginswith(mc->val)) match = 1;
76  } else if (mc->type == kEnds) {
77  if (mpe->val.endswith(mc->val)) match = 1;
78  } else {
79  if (mpe->val.matches(mc->val.c_str())) match = 1;
80  }
81  if (match) mpe->user = mc->user;
82  }
83 
84  // We stop if matched, otherwise we continue
85  return (match) ? 1 : 0;
86 }
87 
88 // Getter
89 //
90 extern "C"
91 {
93 {
94  // Create a XrdOucGMap object and return it if valid
95  XrdOucGMap *gm = new XrdOucGMap(eDest, mapfn, parms);
96  if (gm && gm->isValid()) return gm;
97  if (gm) delete gm;
98  return (XrdOucGMap *)0;
99 }}
100 
101 // Constructor
102 //
104  : valid(0), mf_mtime(-1), notafter(-1), timeout(600), elogger(eDest), tracer(0), dbg(0)
105 {
106  // Set tracer
107  //
108  tracer = new XrdOucTrace(eDest);
109 
110  // Parse parameters, if any
111  //
112  XrdOucString pp(parms), p;
113  if (pp.length() > 0) {
114  int from = 0;
115  while ((from = pp.tokenize(p, from, '|')) != -1) {
116  // Debug
117  if (p == "debug" || p == "dbg") {
118  dbg = 1;
119  } else if (p.beginswith("to=")) {
120  p.erasefromstart(3);
121  if (p.isdigit()) {
122  timeout = p.atoi();
123  } else {
124  PRINT(tracer, "OucGMap", "timeout value badly formatted ("<<p<<"); ignoring");
125  }
126  }
127  }
128  }
129 
130  // Set notafter is timeout is active
131  //
132  if (timeout > 0) notafter = time(0) + (time_t) timeout;
133 
134  // Set the file name
135  //
136  mf_name = mapfn;
137  if (mf_name.length() <= 0) {
138  mf_name = getenv("GRIDMAP");
139  if (mf_name.length() <= 0)
140  mf_name = "/etc/grid-security/grid-mapfile";
141  }
142  // Check if it can be read
143  //
144  if (access(mf_name.c_str(), R_OK) != 0) {
145  PRINT(tracer, "OucGMap", "cannot access grid map file '"<< mf_name
146  <<"' in read mode; " <<XrdSysE2T(errno));
147  return;
148  }
149 
150  // Load the file
151  //
152  if (load(mf_name.c_str()) != 0) {
153  PRINT(tracer, "OucGMap", "unable to load file "<<mf_name<<" - aborting");
154  return;
155  }
156 
157  // Done
158  valid = 1;
159 }
160 
161 // Loader
162 //
163 int XrdOucGMap::load(const char *mf, bool force)
164 {
165  (void)mf;
166 
167  // We need an exclusive lock here
168  xsl.Lock(xs_Exclusive);
169 
170  // Check if we need to load
171  //
172  struct stat st;
173  if (stat(mf_name.c_str(), &st) != 0) {
174  PRINT(tracer, "OucGMap::load", "cannot access grid map file '"
175  <<mf_name <<"'; " <<XrdSysE2T(errno));
176  // Delete the stored information if the file has been deleted
177  if (errno == ENOENT) mappings.Purge();
178  xsl.UnLock();
179  return -(int)errno;
180  }
181 #if defined(__APPLE__)
182  if (mf_mtime > 0 && (mf_mtime >= st.st_mtimespec.tv_sec) && !force) {
183 #else
184  if (mf_mtime > 0 && (mf_mtime >= st.st_mtim.tv_sec) && !force) {
185 #endif
186  DEBUG(dbg, tracer, "OucGMap::load", "map information up-to-date: no need to load");
187  xsl.UnLock();
188  return 0;
189  }
190 
191  // Delete the stored information
192  //
193  mappings.Purge();
194 
195  // Read the file
196  //
197  int fD, rc;
198  const char *inst = getenv("XRDINSTANCE") ? getenv("XRDINSTANCE") : "gmap config instance";
199  XrdOucEnv myEnv;
200  XrdOucStream mapf(elogger, inst, &myEnv, "");
201 
202  if ( (fD = open(mf_name.c_str(), O_RDONLY, 0)) < 0) {
203  PRINT(tracer, "OucGMap::load", "map file '"<<mf_name
204  <<"' could not be open; " <<XrdSysE2T(errno));
205  xsl.UnLock();
206  return -(int)errno;
207  }
208  mapf.Attach(fD);
209 
210  // Now start reading records until eof.
211  //
212  char *var;
213  while ((var = mapf.GetLine())) {
214  int len = strlen(var);
215  if (len < 2) continue;
216  if (var[0] == '#') continue;
217 
218  // Extract DN
219  char *p0 = &var[0];
220  char cr = ' ';
221  if (p0[0] == '"') {
222  p0 = &var[1];
223  cr = '"';
224  }
225  char *p = p0;
226  int l0 = 0;
227  while (p0[l0] != cr)
228  l0++;
229  p0 = (p0 + l0 + 1);
230  while (*p0 == ' ')
231  p0++;
232  // Check for special delimiters
233  char stype[20] = {"matching"};
234  int type = kFull;
235  if (p[0] == '^') {
236  // Starts-with
237  type = kBegins;
238  p++;
239  l0--;
240  strcpy(stype, "beginning with");
241  } else {
242  if (p[l0-1] == '$') {
243  // Ends-with
244  type = kEnds;
245  p[--l0] = '\0';
246  strcpy(stype, "ending with");
247  } else if (p[l0-1] == '+') {
248  // Contains
249  type = kContains;
250  p[--l0] = '\0';
251  strcpy(stype, "containing");
252  }
253  }
254  XrdOucString udn(p, l0);
255 
256  // Extract username
257  XrdOucString usr(p0);
258 
259  // Register
260  if (usr.length() > 0) {
261  mappings.Add(p, new XrdSecGMapEntry_t(udn.c_str(), usr.c_str(), type));
262  DEBUG(dbg, tracer, "XrdOucGMap::load", "mapping DN: '"<<udn<<"' to user: '"<< usr <<"' (type:'"<< stype <<"')");
263  } else {
264  PRINT(tracer, "OucGMap::load", "ERROR: incomplete line found in file '"
265  <<mf_name <<"': "<<var<<" - skipping");
266  }
267  }
268  // Now check if any errors occurred during file i/o
269  //
270  if ((rc = mapf.LastError())) {
271  PRINT(tracer, "OucGMap::load", "ERROR: reading file '"<<mf_name<<"'; "
272  <<XrdSysE2T(rc));
273  rc = -rc;
274  }
275  mapf.Close();
276 
277  // Store the modification time
278  //
279 #if defined(__APPLE__)
280  mf_mtime = st.st_mtimespec.tv_sec;
281 #else
282  mf_mtime = st.st_mtim.tv_sec;
283 #endif
284 
285  // Done
286  xsl.UnLock();
287  return rc;
288 }
289 
290 // Mapper
291 //
292 int XrdOucGMap::dn2user(const char *dn, char *user, int ulen, time_t now)
293 {
294 
295  int rc = -1;
296  // Reset output
297  //
298  if (user && ulen > 0) {
299  memset(user, '\0', ulen);
300  } else {
301  PRINT(tracer, "OucGMap::dn2user",
302  "buffer for the user name is undefined or has undefined length");
303  return -(int)EINVAL;
304  }
305 
306  // Check if we need to reload the information
307  //
308  if (notafter > 0) {
309  if (now <= 0) now = time(0);
310  if (notafter < now) {
311  // Reload the file
312  if (load(mf_name.c_str()) != 0) {
313  PRINT(tracer, "OucGMap::dn2user",
314  "problems loading file "<<mf_name);
315  return -(int)errno;
316  }
317  if (timeout > 0) notafter = now + (time_t) timeout;
318  }
319  }
320 
321  // A shared lock is enough
322  xsl.Lock(xs_Shared);
323 
324  // Search
325  //
326  XrdSecGMapEntry_t *mc = 0;
327  // Try the full match first
328  //
329  if ((mc = mappings.Find(dn))) {
330  // Save the associated user
331  int ul = mc->user.length();
332  strncpy(user, mc->user.c_str(), ul);
333  user[ul] = 0;
334  rc = 0;
335  } else {
336  // Else scan the available mappings
337  //
338  mc = new XrdSecGMapEntry_t(dn, "", kFull);
339  mappings.Apply(FindMatchingCondition, (void *)mc);
340  if (mc->user.length() > 0) {
341  int ul = mc->user.length();
342  strncpy(user, mc->user.c_str(), ul);
343  user[ul] = 0;
344  rc = 0;
345  }
346  if (mc) delete mc;
347  }
348  if (rc == 0) {
349  DEBUG(dbg, tracer, "XrdOucGMap::dn2user", "mapping DN '"<<dn<<"' to '"<<user<<"'");
350  } else {
351  DEBUG(dbg, tracer, "XrdOucGMap::dn2user", "no valid match found for DN '"<<dn<<"'");
352  rc = -(int)EFAULT;
353  }
354 
355  // Done
356  xsl.UnLock();
357  return rc;
358 }
359 
static XrdSysError eDest(0,"crypto_")
#define PRINT(t, n, y)
Definition: XrdOucGMap.cc:60
#define DEBUG(d, t, n, y)
Definition: XrdOucGMap.cc:61
XrdOucGMap_Match
Definition: XrdOucGMap.cc:54
@ kBegins
Definition: XrdOucGMap.cc:55
@ kEnds
Definition: XrdOucGMap.cc:56
@ kContains
Definition: XrdOucGMap.cc:57
@ kFull
Definition: XrdOucGMap.cc:54
static int FindMatchingCondition(const char *, XrdSecGMapEntry_t *mc, void *xmp)
Definition: XrdOucGMap.cc:64
XrdOucGMap * XrdOucgetGMap(XrdOucGMapArgs)
Definition: XrdOucGMap.cc:92
#define XrdOucGMapArgs
Definition: XrdOucGMap.hh:89
#define STR_NPOS
int stat(const char *path, struct stat *buf)
int open(const char *path, int oflag,...)
int access(const char *path, int amode)
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
@ xs_Exclusive
Definition: XrdSysXSLock.hh:38
@ xs_Shared
Definition: XrdSysXSLock.hh:38
XrdOucGMap(XrdOucGMapArgs)
Definition: XrdOucGMap.cc:103
bool isValid() const
Validity checker.
Definition: XrdOucGMap.hh:104
virtual int dn2user(const char *dn, char *user, int ulen, time_t now=0)
Definition: XrdOucGMap.cc:292
void Purge()
Definition: XrdOucHash.icc:193
T * Apply(int(*func)(const char *, T *, void *), void *Arg)
Definition: XrdOucHash.icc:102
T * Add(const char *KeyVal, T *KeyData, const int LifeTime=0, XrdOucHash_Options opt=Hash_default)
Definition: XrdOucHash.icc:61
T * Find(const char *KeyVal, time_t *KeyTime=0)
Definition: XrdOucHash.icc:160
const char * c_str() const
int erasefromstart(int sz=0)
bool endswith(char c)
bool beginswith(char c)
int matches(const char *s, char wch=' *')
int find(const char c, int start=0, bool forward=1)
int length() const
bool isdigit(int from=0, int to=-1)
long atoi(int from=0, int to=-1)
XrdOucString user
Definition: XrdOucGMap.hh:44
XrdOucString val
Definition: XrdOucGMap.hh:43
void Lock(const XrdSysXS_Type usage)
Definition: XrdSysXSLock.cc:55
void UnLock(const XrdSysXS_Type usage=xs_None)
Definition: XrdSysXSLock.cc:95