XRootD
XrdDigAuth.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d D i g A u t h . c c */
4 /* */
5 /* (C) 2013 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 Deprtment 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 #include <unistd.h>
32 #include <cctype>
33 #include <fcntl.h>
34 #include <cstdio>
35 #include <cstdlib>
36 #include <strings.h>
37 #include <sys/param.h>
38 #include <sys/stat.h>
39 
40 #include "XrdDig/XrdDigAuth.hh"
41 
42 #include "XrdNet/XrdNetAddrInfo.hh"
43 
44 #include "XrdOuc/XrdOucStream.hh"
45 
46 #include "XrdSys/XrdSysE2T.hh"
47 #include "XrdSys/XrdSysError.hh"
48 
49 /******************************************************************************/
50 /* d e f i n e s */
51 /******************************************************************************/
52 
53 #define TS_Xeq(x,m) if (!strcmp(x,var)) return m(Config);
54 
55 /******************************************************************************/
56 /* G l o b a l S t a t i c O b j e c t s */
57 /******************************************************************************/
58 
59 namespace XrdDig
60 {
61  extern XrdSysError *eDest;
62 
64 };
65 
66 using namespace XrdDig;
67 
68 /******************************************************************************/
69 /* S t a t i c L o c a l V a l u e s */
70 /******************************************************************************/
71 
72 namespace
73 {
74  const char eVec[] = "nhorg";
75 
76  struct aToks {const char *aTok; XrdDigAuthEnt::aType aRef;} aTab[] =
77  {{"conf", XrdDigAuthEnt::aConf},
78  {"core", XrdDigAuthEnt::aCore},
79  {"logs", XrdDigAuthEnt::aLogs},
80  {"proc", XrdDigAuthEnt::aProc}
81  };
82 
83 };
84 
85 /******************************************************************************/
86 /* A u t h o r i z e */
87 /******************************************************************************/
88 
91  bool aVec[XrdDigAuthEnt::aNum]
92  )
93 {
94  XrdSysMutexHelper mHelp(&authMutex);
95  time_t tNow = time(0);
96  XrdDigAuthEnt *aP;
97  int rc;
98 
99 // Check if we need to refresh the auth list
100 //
101  if (tNow >= authCHK)
102  {struct stat Stat;
103  if ((rc = stat(authFN, &Stat)) && errno != ENOENT)
104  {eDest->Emsg("Config",errno,"stat dig auth file", authFN);
105  authCHK = tNow + 30;
106  } else {
107  if (rc) {if (authList) {if (!Refresh()) authCHK = tNow + 30;}
108  else authCHK = tNow + 60;
109  }
110  else if (authTOD == Stat.st_mtime) authCHK = tNow + 5;
111  else if (!Refresh()) authCHK = tNow + 30;
112  }
113  }
114 
115 // Clear aVec if so supplied (client's auth mask)
116 //
117  if (aVec) memset(aVec, false, XrdDigAuthEnt::aNum);
118 
119 // Check if we have anything to authorize with
120 //
121  if (!authList) return false;
122 
123 // Check if we are granting access to this resouce at all
124 //
125  if (aType != XrdDigAuthEnt::aNum && !accOK[aType]) return false;
126 
127 // Go through the access list and try to match the client
128 //
129  aP = authList;
130  while(aP)
131  {do {if (strcmp(client->prot, aP->prot)) break;
132  if (aP->eChk[XrdDigAuthEnt::eName] && (!client->name ||
133  strcmp(client->name, aP->eChk[XrdDigAuthEnt::eName]))) break;
134 
135  if (aP->eChk[XrdDigAuthEnt::eHost]
136  && strcmp(client->addrInfo->Name(""),
137  aP->eChk[XrdDigAuthEnt::eHost])) break;
138 
139  if (aP->eChk[XrdDigAuthEnt::eVorg] && (!client->vorg ||
140  strcmp(client->vorg, aP->eChk[XrdDigAuthEnt::eVorg]))) break;
141 
142  if (aP->eChk[XrdDigAuthEnt::eRole] && (!client->role ||
143  strcmp(client->role, aP->eChk[XrdDigAuthEnt::eRole]))) break;
144 
145  if (aP->eChk[XrdDigAuthEnt::eGrp ] && (!client->grps ||
146  !OkGrp(client->grps, aP->eChk[XrdDigAuthEnt::eGrp ]))) break;
147 
148  if (aVec) memcpy(aVec, aP->accOK, XrdDigAuthEnt::aNum);
149  return (aType == XrdDigAuthEnt::aNum ? false : aP->accOK[aType]);
150  } while(1);
151  aP = aP->next;
152  }
153 
154 // Client failed the test
155 //
156  return false;
157 }
158 
159 /******************************************************************************/
160 /* C o n f i g u r e */
161 /******************************************************************************/
162 
163 bool XrdDigAuth::Configure(const char *aFN)
164 {
165 /*
166  Function: Configure authorization (one time call).
167 
168  Input: None.
169 
170  Output: true upon success or false otherwise.
171 */
172 
173 // Establish the location of the auth file (stable string do not copy)
174 //
175  if (!aFN || !(*aFN))
176  {eDest->Emsg("Config", "Dig authorization file not specified.");
177  return false;
178  }
179 
180 // Initialize authorization
181 //
182  authFN = strdup(aFN);
183  SetupAuth(false);
184  return true;
185 }
186 
187 /******************************************************************************/
188 /* Private: F a i l u r e */
189 /******************************************************************************/
190 
191 bool XrdDigAuth::Failure(int lNum, const char *txt1, const char *txt2)
192 {
193  char buff[256];
194 
195  sprintf(buff, "Error in dig authfile line %d:", lNum);
196  eDest->Emsg("Auth", buff, txt1, txt2);
197  return false;
198 }
199 
200 /******************************************************************************/
201 /* Private: O k G r p */
202 /******************************************************************************/
203 
204 bool XrdDigAuth::OkGrp(const char *glist, const char *gname)
205 {
206  const char *ghit;
207  int glen = strlen(gname);
208 
209 // Attempt to find a match in the list
210 //
211  do {if (!(ghit = strstr(glist, gname))) return false;
212  ghit += glen;
213  if (!(*ghit) || *ghit == ' ') return true;
214  glist = ghit;
215  } while(1);
216  return false;
217 }
218 
219 /******************************************************************************/
220 /* Private: P a r s e */
221 /******************************************************************************/
222 
223 bool XrdDigAuth::Parse(XrdOucStream &aFile, int lNum)
224 {
225  struct aEntHelper
226  {XrdDigAuthEnt *eP;
227  aEntHelper() {eP = new XrdDigAuthEnt;}
228  ~aEntHelper() {if (eP) delete eP;}
229  } aEnt;
230  static const char *eCode;
231  char buff[4096];
232  char *var, *rec, *bP = buff;
233  int k, n, bLeft = sizeof(buff);
234  bool aOK = false, tfVal;
235 
236 // Get the record type tokens first
237 //
238  while((var = aFile.GetToken()) && *var)
239  { if (!strcmp(var, "all"))
240  {for (k = 0; k < (int)XrdDigAuthEnt::aNum; k++)
241  aEnt.eP->accOK[k] = true;
242  aOK = true; continue;
243  }
244  else if (!strcmp(var, "allow")) break;
245  else{if (*var == '-') {tfVal = false; var++;}
246  else tfVal = true;
247 
248  for (n = 0; n < (int)XrdDigAuthEnt::aNum; n++)
249  if (!strcmp(var, aTab[n].aTok))
250  {aEnt.eP->accOK[aTab[n].aRef] = tfVal; aOK = true; break;}
251 
252  if (n >= (int)XrdDigAuthEnt::aNum)
253  return Failure(lNum, "Invalid token -", var);
254  }
255  }
256 
257 
258 // Make sure a type has been specified
259 //
260  if (!aOK) return Failure(lNum, "Information type not specified.");
261 
262 // Now scan for the security protocol
263 //
264  if (!(var = aFile.GetToken()) || !(*var))
265  return Failure(lNum, "Auth protocol not specified.");
266 
267 // Make sure it is not too big
268 //
269  if (strlen(var) >= sizeof(aEnt.eP->prot))
270  return Failure(lNum, "Invalid auth protocol -", var);
271  strcpy(aEnt.eP->prot, var);
272 
273 // Now start getting the auth values
274 //
275  aOK = false;
276  while((var = aFile.GetToken()) && *var)
277  {if (!(eCode = index(eVec, *var))) // "nhorg" lookup
278  return Failure(lNum, "Invalid entity type -", var);
279  if (*(var+1) != '=' || !*(var+2))
280  return Failure(lNum, "Badly formed entity value in", var);
281  n = snprintf(bP, bLeft, "%s", var+2);
282  if (n < 0 || n >= bLeft) break;
283  ++n;
284  bLeft -= n;
285  if ((var = index(bP, '\\'))) Squash(var);
286  aEnt.eP->eChk[eCode-eVec] = bP; bP += n;
287  aOK = true;
288  }
289 
290 // Check if we over-ran the buffer
291 //
292  if (bLeft <= 0) return Failure(lNum, "Too many auth values.");
293 
294 // Make sure we have somthing here
295 //
296  if (!aOK) return Failure(lNum, "No entity values specified.");
297 
298 // Create composite mask (we assume no memory failures)
299 //
300  aOK = false;
301  for (n = 0; n < (int)XrdDigAuthEnt::aNum; n++)
302  if (aEnt.eP->accOK[n]) accOK[n] = aOK = true;
303  if(!aOK) return Failure(lNum, "Entity has no effective access.");
304 
305 // Allocate a new value record
306 //
307  if (!(rec = (char *)malloc(bP-buff)))
308  return Failure(lNum, "Insufficient memory.");
309  memcpy(rec, buff, bP-buff);
310  aEnt.eP->rec = rec;
311 
312 // Relocate pointers
313 //
314  for (k = (int)XrdDigAuthEnt::eName; k < (int)XrdDigAuthEnt::eNum; k++)
315  {if (aEnt.eP->eChk[k])
316  aEnt.eP->eChk[k] = rec + (aEnt.eP->eChk[k] - buff);
317  }
318 
319 // Chain this record into the record list and return success
320 //
321  aEnt.eP->next = authList;
322  authList = aEnt.eP;
323  aEnt.eP = 0;
324  return true;
325 }
326 
327 /******************************************************************************/
328 /* Private: R e f r e s h */
329 /******************************************************************************/
330 
331 bool XrdDigAuth::Refresh() // authMutex must be locked!
332 {
333  XrdDigAuthEnt *aP, *nP = authList;
334 
335 // Delete the current auth list
336 //
337  while((aP = nP)) {nP = aP->next; delete aP;}
338  authList = 0;
339 
340 // Resetup the auth list
341 //
342  return SetupAuth(true);
343 }
344 
345 /******************************************************************************/
346 /* Private: S e t u p A u t h */
347 /******************************************************************************/
348 
349 bool XrdDigAuth::SetupAuth(bool isRefresh)
350 {
351  XrdOucStream aFile(eDest);
352  struct stat Stat;
353  char *line;
354  int authFD, retc, lNum = 1;
355  bool NoGo = false;
356 
357 // Clear summary flags
358 //
359  memset(accOK, 0, sizeof(accOK));
360 
361 // Print message
362 //
363  eDest->Say("++++++ Dig ", (isRefresh ? "refreshing" : "initializing"),
364  " from ", authFN);
365 
366 // Try to open the configuration file.
367 //
368  if ( (authFD = open(authFN, O_RDONLY, 0)) < 0)
369  {NoGo = errno != ENOENT;
370  eDest->Say("Config ",XrdSysE2T(errno)," opening dig auth file ",authFN);
371  return SetupAuth(isRefresh, !NoGo);
372  }
373  aFile.Attach(authFD, 4096);
374 
375 // Get the time the file was ctreated
376 //
377  if (fstat(authFD, &Stat))
378  {eDest->Say("Config ",XrdSysE2T(errno)," stating dig auth file ",authFN);
379  close(authFD);
380  return SetupAuth(isRefresh, false);
381  }
382  authTOD = Stat.st_mtime;
383 
384 // Now start reading records until eof.
385 //
386  while((line = aFile.GetLine()))
387  {if (*line && *line != '#') NoGo |= !Parse(aFile, lNum);
388  lNum++;
389  }
390 
391 // Now check if any errors occurred during file i/o
392 //
393  if ((retc = aFile.LastError()))
394  {eDest->Say("Config ",XrdSysE2T(-retc)," reading config file ",authFN);
395  NoGo = true;
396  }
397  aFile.Close();
398 
399 // All done
400 //
401  return SetupAuth(isRefresh, !NoGo);
402 }
403 
404 /******************************************************************************/
405 
406 bool XrdDigAuth::SetupAuth(bool isRefresh, bool aOK)
407 {
408 
409 // Indicate whether we are active or not
410 //
411  if (!authList) eDest->Say("Config ","No users authorized to access digFS; "
412  "access suspended.");
413 
414 // All done
415 //
416  eDest->Say("------ Dig auth ", (isRefresh ? "refresh" : "initialization"),
417  (aOK ? " succeeded." : " encountered errors."));
418 
419  return aOK;
420 }
421 
422 /******************************************************************************/
423 /* Private: S q u a s h */
424 /******************************************************************************/
425 
426 void XrdDigAuth::Squash(char *bP)
427 {
428 
429 // Insert spaces where needed
430 //
431  do {if (*(bP+1) == 's') {*bP = ' '; strcpy(bP+1, bP+2);}
432  } while((bP = index(bP+1, '\\')));
433 }
struct stat Stat
Definition: XrdCks.cc:49
int stat(const char *path, struct stat *buf)
int open(const char *path, int oflag,...)
int fstat(int fildes, struct stat *buf)
#define close(a)
Definition: XrdPosix.hh:43
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
char prot[XrdSecPROTOIDSIZE]
Definition: XrdDigAuth.hh:48
char * eChk[eNum]
Definition: XrdDigAuth.hh:51
XrdDigAuthEnt * next
Definition: XrdDigAuth.hh:46
bool accOK[aNum]
Definition: XrdDigAuth.hh:54
bool Authorize(const XrdSecEntity *client, XrdDigAuthEnt::aType aType, bool aVec[XrdDigAuthEnt::aNum]=0)
Definition: XrdDigAuth.cc:89
bool Configure(const char *aFN)
Definition: XrdDigAuth.cc:163
const char * Name(const char *eName=0, const char **eText=0)
char * GetLine()
int Attach(int FileDescriptor, int bsz=2047)
void Close(int hold=0)
char * GetToken(int lowcase=0)
char * vorg
Entity's virtual organization(s)
Definition: XrdSecEntity.hh:71
XrdNetAddrInfo * addrInfo
Entity's connection details.
Definition: XrdSecEntity.hh:80
char prot[XrdSecPROTOIDSIZE]
Auth protocol used (e.g. krb5)
Definition: XrdSecEntity.hh:67
char * grps
Entity's group name(s)
Definition: XrdSecEntity.hh:73
char * name
Entity's name.
Definition: XrdSecEntity.hh:69
char * role
Entity's role(s)
Definition: XrdSecEntity.hh:72
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
XrdDigAuth Auth
Definition: XrdDigAuth.cc:63
XrdSysError * eDest
Definition: XrdDigConfig.cc:68
void * Refresh(void *parg)