XRootD
Loading...
Searching...
No Matches
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"
52#include "XrdSys/XrdSysE2T.hh"
53
56 kEnds = 2,
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//__________________________________________________________________________
64static 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//
90extern "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//
163int 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//
292int 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
#define DEBUG(x)
static XrdSysError eDest(0,"crypto_")
#define PRINT(y)
XrdOucGMap * XrdOucgetGMap(XrdOucGMapArgs)
Definition XrdOucGMap.cc:92
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
#define XrdOucGMapArgs
Definition XrdOucGMap.hh:89
#define STR_NPOS
#define access(a, b)
Definition XrdPosix.hh:39
#define open
Definition XrdPosix.hh:71
#define stat(a, b)
Definition XrdPosix.hh:96
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:104
@ xs_Exclusive
@ xs_Shared
XrdOucGMap(XrdOucGMapArgs)
bool isValid() const
Validity checker.
virtual int dn2user(const char *dn, char *user, int ulen, time_t now=0)
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)
const char * c_str() const
XrdOucString user
Definition XrdOucGMap.hh:44
XrdOucString val
Definition XrdOucGMap.hh:43
void Lock(const XrdSysXS_Type usage)
void UnLock(const XrdSysXS_Type usage=xs_None)