XRootD
XrdSecsssKT.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d S e c s s s K T . c c */
4 /* */
5 /* (c) 2008 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 #include <fcntl.h>
32 #include <iostream>
33 #include <cstdio>
34 #include <stddef.h>
35 #include <cstdlib>
36 #include <cstring>
37 #include <sys/time.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 
41 #include "XrdSecsss/XrdSecsssKT.hh"
42 
43 #include "XrdOuc/XrdOucErrInfo.hh"
44 #include "XrdOuc/XrdOucStream.hh"
45 #include "XrdOuc/XrdOucUtils.hh"
46 #include "XrdSys/XrdSysE2T.hh"
47 
48 #ifndef ENODATA
49 #define ENODATA ENOATTR
50 #endif
51 
52 /******************************************************************************/
53 /* S t a t i c D e f i n i t i o n s */
54 /******************************************************************************/
55 
56 int XrdSecsssKT::randFD = -1;
57 
58 /******************************************************************************/
59 /* X r d S e c s s s K T R e f r */
60 /******************************************************************************/
61 
62 void *XrdSecsssKTRefresh(void *Data)
63 {
64  XrdSecsssKT *theKT = (XrdSecsssKT *)Data;
65  struct timespec naptime = {theKT->RefrTime(), 0};
66 
67 // Loop and check if keytab has changed
68 //
69  while(1) {nanosleep(&naptime, 0); theKT->Refresh();}
70 
71  return (void *)0;
72 }
73 
74 /******************************************************************************/
75 /* C o n s t r u c t o r */
76 /******************************************************************************/
77 
78 XrdSecsssKT::XrdSecsssKT(XrdOucErrInfo *eInfo, const char *kPath,
79  xMode oMode, int refrInt)
80 {
81  static const char *eText = "Unable to start keytab refresh thread";
82  const char *devRand = "/dev/urandom";
83  struct stat sbuf;
84  int retc;
85 
86 // Do some common initialization
87 //
88  ktRefID= 0;
89  ktPath = (kPath ? strdup(kPath) : 0);
90  ktList = 0; kthiID = 0; ktMode = oMode; ktRefT = (time_t)refrInt;
91  if (eInfo) eInfo->setErrCode(0);
92 
93 // Prepare /dev/random if we have it
94 //
95  if (stat(devRand, &sbuf)) devRand = "/dev/random";
96  if ((randFD = open(devRand, O_RDONLY)) < 0
97  && oMode != isClient && errno != ENOENT)
98  eMsg("sssKT",errno,"Unable to generate random key"," opening ",devRand);
99 
100 // First get the stat information for the file
101 //
102  if (!kPath)
103  {if (oMode != isAdmin)
104  {eMsg("sssKT", -1, "Keytable path not specified.");
105  if (eInfo) eInfo->setErrInfo(EINVAL, "Keytable path missing.");
106  return;
107  }
108  sbuf.st_mtime = 0; sbuf.st_mode = S_IRWXU;
109  } else if (stat(kPath, &sbuf))
110  {if (eInfo) eInfo->setErrInfo(errno, "Keytable not found");
111  if (errno != ENOENT || oMode != isAdmin)
112  eMsg("sssKT",errno,"Unable process keytable ",kPath);
113  return;
114  }
115 
116 // Now read in the whole key table and start possible refresh thread
117 //
118  if ((ktList = getKeyTab(eInfo, sbuf.st_mtime, sbuf.st_mode))
119  && (oMode != isAdmin) && (!eInfo || eInfo->getErrInfo() == 0))
120  {if ((retc = XrdSysThread::Run(&ktRefID,XrdSecsssKTRefresh, (void *)this,
122  {eMsg("sssKT", errno, eText); eInfo->setErrInfo(-1, eText);}
123  }
124 }
125 
126 /******************************************************************************/
127 /* D e s t r u c t o r */
128 /******************************************************************************/
129 
131 {
132  ktEnt *ktP;
133  void *Dummy;
134 
135 // Lock against others
136 //
137  myMutex.Lock();
138 
139 // Kill the refresh thread first
140 //
141  if (ktRefID && !XrdSysThread::Kill(ktRefID))
142  XrdSysThread::Join(ktRefID, &Dummy);
143  ktRefID= 0;
144 
145 // Now we can safely clean up
146 //
147  if (ktPath) {free(ktPath); ktPath = 0;}
148 
149  while((ktP = ktList)) {ktList = ktList->Next; delete ktP;}
150 
151  myMutex.UnLock();
152 }
153 
154 /******************************************************************************/
155 /* a d d K e y */
156 /******************************************************************************/
157 
159 {
160  ktEnt *ktPP = 0, *ktP;
161 
162 // Generate a key for this entry
163 //
164  genKey(ktNew.Data.Val, ktNew.Data.Len);
165  ktNew.Data.Crt = time(0);
166  ktNew.Data.ID = static_cast<long long>(ktNew.Data.Crt & 0x7fffffff) << 32L
167  | static_cast<long long>(++kthiID);
168 
169 // Locate place to insert this key
170 //
171  ktP = ktList;
172  while(ktP && !isKey(*ktP, &ktNew, 0)) {ktPP = ktP; ktP = ktP->Next;}
173 
174 // Now chain in the entry
175 //
176  if (ktPP) ktPP->Next = &ktNew;
177  else ktList = &ktNew;
178  ktNew.Next = ktP;
179 }
180 
181 /******************************************************************************/
182 /* d e l K e y */
183 /******************************************************************************/
184 
186 {
187  ktEnt *ktN, *ktPP = 0, *ktP = ktList;
188  int nDel = 0;
189 
190 // Remove all matching keys
191 //
192  while(ktP)
193  {if (isKey(ktDel, ktP))
194  {if (ktPP) ktPP->Next = ktP->Next;
195  else ktList = ktP->Next;
196  ktN = ktP; ktP = ktP->Next; delete ktN; nDel++;
197  } else {ktPP = ktP; ktP = ktP->Next;}
198  }
199 
200  return nDel;
201 }
202 
203 /******************************************************************************/
204 /* g e t K e y */
205 /******************************************************************************/
206 
207 int XrdSecsssKT::getKey(ktEnt &theEnt, bool andKeyID)
208 {
209  ktEnt *ktP, *ktN;
210 
211 // Lock the keytab to prevent modification
212 //
213  myMutex.Lock();
214  ktP = ktList;
215 
216 // Find first key by key name (used normally by clients), by keyID, or both
217 //
218  if (!*theEnt.Data.Name)
219  {if (theEnt.Data.ID >= 0)
220  while(ktP && ktP->Data.ID != theEnt.Data.ID) ktP = ktP->Next;
221  }
222  else if (andKeyID)
223  {while((ktP && ktP->Data.ID != theEnt.Data.ID)
224  || strcmp(ktP->Data.Name,theEnt.Data.Name)) ktP=ktP->Next;
225  }
226  else {while(ktP && strcmp(ktP->Data.Name,theEnt.Data.Name)) ktP=ktP->Next;
227  while(ktP && ktP->Data.Exp <= time(0))
228  {if (!(ktN=ktP->Next)
229  || strcmp(ktN->Data.Name,theEnt.Data.Name)) break;
230  ktP = ktN;
231  }
232  }
233 
234 // If we found a match, export it
235 //
236  if (ktP) theEnt = *ktP;
237  myMutex.UnLock();
238 
239 // Indicate if key expired
240 //
241  if (!ktP) return ENOENT;
242  return (theEnt.Data.Exp && theEnt.Data.Exp <= time(0) ? -1 : 0);
243 }
244 
245 /******************************************************************************/
246 /* g e n F N */
247 /******************************************************************************/
248 
250 {
251  static char fnbuff[1040];
252  const char *pfx;
253 
254 // Get the path prefix
255 //
256  if (!(pfx = getenv("HOME")) || !*pfx) pfx = "";
257 
258 // Format the name
259 //
260  snprintf(fnbuff, sizeof(fnbuff), "%s/.xrd/sss.keytab", pfx);
261  return fnbuff;
262 }
263 
264 /******************************************************************************/
265 /* g e n K e y */
266 /******************************************************************************/
267 
268 void XrdSecsssKT::genKey(char *kBP, int kLen)
269 {
270  struct timeval tval;
271  int kTemp;
272 
273 // See if we can directly service the key. Make sure that we get some entropy
274 // because some /dev/random devices start out really cold.
275 //
276  if (randFD >= 0)
277  {char *buffP = kBP;
278  int i, Got, Want = kLen, zcnt = 0, maxZ = kLen*25/100;
279  while(Want)
280  do { {do {Got = read(randFD, buffP, Want);}
281  while(Got < 0 && errno == EINTR);
282  if (Got > 0) {buffP += Got; Want -= Got;}
283  }
284  } while(Got > 0 && Want);
285  if (!Want)
286  {for (i = 0; i < kLen; i++) if (!kBP[i]) zcnt++;
287  if (zcnt <= maxZ) return;
288  }
289  }
290 
291 // Generate a seed
292 //
293  gettimeofday(&tval, 0);
294  if (tval.tv_usec == 0) tval.tv_usec = tval.tv_sec;
295  tval.tv_usec = tval.tv_usec ^ getpid();
296  srand48(static_cast<long>(tval.tv_usec));
297 
298 // Now generate the key (we ignore he fact that longs may be 4 or 8 bytes)
299 //
300  while(kLen > 0)
301  {kTemp = mrand48();
302  memcpy(kBP, &kTemp, (4 > kLen ? kLen : 4));
303  kBP += 4; kLen -= 4;
304  }
305 }
306 
307 /******************************************************************************/
308 /* R e f r e s h */
309 /******************************************************************************/
310 
312 {
313  XrdOucErrInfo eInfo;
314  ktEnt *ktNew, *ktOld, *ktNext;
315  struct stat sbuf;
316  int retc = 0;
317 
318 // Get change time of keytable and if changed, update it
319 //
320  if (stat(ktPath, &sbuf) == 0)
321  {if (sbuf.st_mtime == ktMtime) return;
322  if ((ktNew = getKeyTab(&eInfo, sbuf.st_mtime, sbuf.st_mode))
323  && eInfo.getErrInfo() == 0)
324  {myMutex.Lock(); ktOld = ktList; ktList = ktNew; myMutex.UnLock();
325  } else ktOld = ktNew;
326  while(ktOld) {ktNext = ktOld->Next; delete ktOld; ktOld = ktNext;}
327  if ((retc == eInfo.getErrInfo()) == 0) return;
328  } else retc = errno;
329 
330 // Refresh failed
331 //
332  eMsg("Refresh",retc,"Unable to refresh keytable",ktPath);
333 }
334 
335 /******************************************************************************/
336 /* R e w r i t e */
337 /******************************************************************************/
338 
339 int XrdSecsssKT::Rewrite(int Keep, int &numKeys, int &numTot, int &numExp)
340 {
341  char tmpFN[2048], buff[2048], kbuff[4096], *Slash;
342  int ktFD, numID = 0, n, retc = 0;
343  ktEnt ktCurr, *ktP, *ktN;
344  mode_t theMode = fileMode(ktPath);
345 
346 // Invoke mkpath in case the path is missing
347 //
348  strcpy(tmpFN, ktPath);
349  if ((Slash = rindex(tmpFN, '/'))) *Slash = '\0';
350  retc = XrdOucUtils::makePath(tmpFN,S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
351  if (retc) return (retc < 0 ? -retc : retc);
352  if (Slash) *Slash = '/';
353 
354 // Construct temporary filename
355 //
356  sprintf(buff, ".%d", static_cast<int>(getpid()));
357  strcat(tmpFN, buff);
358 
359 // Open the file for output
360 //
361  if ((ktFD = open(tmpFN, O_WRONLY|O_CREAT|O_TRUNC, theMode)) < 0)
362  return errno;
363 
364 // Write all of the keytable
365 //
366  ktCurr.Data.Name[0] = ktCurr.Data.User[0] = ktCurr.Data.Grup[0] = 3;
367  ktN = ktList; numKeys = numTot = numExp = 0;
368  while((ktP = ktN))
369  {ktN = ktN->Next; numTot++;
370  if (ktP->Data.Name[0] == '\0') continue;
371  if (ktP->Data.Exp && ktP->Data.Exp <= time(0)) {numExp++; continue;}
372  if (!isKey(ktCurr, ktP, 0)) {ktCurr.NUG(ktP); numID = 0;}
373  else if (Keep && numID >= Keep) continue;
374  n = sprintf(buff, "%s0 u:%s g:%s n:%s N:%lld c:%lld e:%lld f:%lld k:",
375  (numKeys ? "\n" : ""),
376  ktP->Data.User,ktP->Data.Grup,ktP->Data.Name,ktP->Data.ID,
377  (long long) ktP->Data.Crt, (long long) ktP->Data.Exp,
378  ktP->Data.Flags);
379  numID++; numKeys++; keyB2X(ktP, kbuff);
380  if (write(ktFD, buff, n) < 0
381  || write(ktFD, kbuff, ktP->Data.Len*2) < 0) break;
382  }
383 
384 // Check for errors
385 //
386  if (ktP) retc = errno;
387  else if (!numKeys) retc = ENODATA;
388 
389 // Atomically trounce the original file if we can
390 //
391  close(ktFD);
392  if (!retc && rename(tmpFN, ktPath) < 0) retc = errno;
393 
394 // All done
395 //
396  unlink(tmpFN);
397  return retc;
398 }
399 
400 /******************************************************************************/
401 /* P r i v a t e M e t h o d s */
402 /******************************************************************************/
403 /******************************************************************************/
404 /* e M s g */
405 /******************************************************************************/
406 
407 int XrdSecsssKT::eMsg(const char *epname, int rc,
408  const char *txt1, const char *txt2,
409  const char *txt3, const char *txt4)
410 {
411  std::cerr <<"Secsss (" << epname <<"): ";
412  std::cerr <<txt1;
413  if (txt2) std::cerr <<txt2;
414  if (txt3) std::cerr <<txt3;
415  if (txt4) std::cerr <<txt4;
416  {if (rc>0) {std::cerr <<"; " <<XrdSysE2T(rc);}}
417  std::cerr <<"\n" <<std::endl;
418 
419  return (rc ? (rc < 0 ? rc : -rc) : -1);
420 }
421 
422 /******************************************************************************/
423 /* g e t K e y T a b */
424 /******************************************************************************/
425 
426 XrdSecsssKT::ktEnt* XrdSecsssKT::getKeyTab(XrdOucErrInfo *eInfo,
427  time_t Mtime, mode_t Amode)
428 {
429  static const int altMode = S_IRWXG | S_IRWXO;
430  XrdOucStream myKT;
431  int ktFD = -1, retc, tmpID, recno = 0, NoGo = 0;
432  const char *What = 0, *ktFN;
433  char *lp, *tp, rbuff[64];
434  ktEnt *ktP, *ktPP, *ktNew, *ktBase = 0;
435 
436 // Verify that the keytable is only readable by us
437 //
438  ktMtime = Mtime;
439  if ((Amode & altMode) & ~fileMode(ktPath))
440  {if (eInfo) eInfo->setErrInfo(EACCES, "Keytab file is not secure!");
441  eMsg("getKeyTab",-1,"Unable to process ",ktPath,"; file is not secure!");
442  return 0;
443  }
444 
445 // Open the file
446 //
447  if (ktPath)
448  {if ((ktFD = open(ktPath, O_RDONLY)) < 0)
449  {if (eInfo) eInfo->setErrInfo(errno, "Unable to open keytab file.");
450  eMsg("getKeyTab", errno, "Unable to open ", ktPath);
451  return 0;
452  } else ktFN = ktPath;
453  } else {ktFD = dup(STDIN_FILENO); ktFN = "stdin";}
454 
455 // Attach the fd to the stream
456 //
457  if (ktFD < 0 || myKT.Attach(ktFD) != 0)
458  {if (eInfo) eInfo->setErrInfo(EBADF, "Unable to attach to keytab file descriptor for reading.");
459  eMsg("getKeyTab", -1, "Unable to attach to keytab file descriptor.");
460  return nullptr;
461  }
462 
463 // Now start reading the keytable which always has the form:
464 //
465 // <format> <whatever data based on format>
466 //
467 do{while((lp = myKT.GetLine()))
468  {recno++; What = 0;
469  if (!*lp) continue;
470  if (!(tp = myKT.GetToken()) || (strcmp("0", tp) && strcmp("1", tp)))
471  {What = "keytable format missing or unsupported"; break;}
472  if (!(ktNew = ktDecode0(myKT, eInfo)))
473  {What = (eInfo ? eInfo->getErrText(): "invalid data"); break;}
474  if (ktMode!=isAdmin && ktNew->Data.Exp && ktNew->Data.Exp <= time(0))
475  {delete ktNew; continue;}
476  tmpID = static_cast<int>(ktNew->Data.ID & 0x7fffffff);
477  if (tmpID > kthiID) kthiID = tmpID;
478 
479  ktP = ktBase; ktPP = 0;
480  while(ktP && !isKey(*ktP, ktNew, 0)) {ktPP=ktP; ktP=ktP->Next;}
481  if (!ktP) {ktNew->Next = ktBase; ktBase = ktNew;}
482  else {if (ktMode == isClient)
483  {if ((ktNew->Data.Exp == 0 && ktP->Data.Exp != 0)
484  || (ktP->Data.Exp!=0 && ktP->Data.Exp < ktNew->Data.Exp))
485  ktP->Set(*ktNew);
486  delete ktNew;
487  } else {
488  while(ktNew->Data.Crt < ktP->Data.Crt)
489  {ktPP = ktP; ktP = ktP->Next;
490  if (!ktP || !isKey(*ktP, ktNew, 0)) break;
491  }
492  if (ktPP) {ktPP->Next = ktNew; ktNew->Next = ktP;}
493  else {ktNew->Next= ktBase; ktBase = ktNew;}
494  }
495  }
496  }
497  if (What)
498  {sprintf(rbuff, "; line %d in ", recno);
499  NoGo = eMsg("getKeyTab", -1, What, rbuff, ktFN);
500  }
501  } while(lp);
502 
503 // Check for problems
504 //
505  if (NoGo) {if (eInfo) eInfo->setErrInfo(EINVAL,"Invalid keytab file.");}
506  else if ((retc = myKT.LastError()))
507  {if (eInfo) eInfo->setErrInfo(retc,"Unable to read keytab file.");
508  NoGo = eMsg("getKeyTab", retc, "Unable to read keytab ",ktFN);
509  }
510  else if (!ktBase)
511  {if (eInfo) eInfo->setErrInfo(ESRCH,"Keytable is empty.");
512  NoGo = eMsg("getKeyTab",-1,"No keys found in ",ktFN);
513  }
514 
515 
516 // Check if an error should be returned
517 //
518  if (eInfo && !NoGo) eInfo->setErrCode(0);
519 
520 // All done
521 //
522  myKT.Close();
523  return ktBase;
524 }
525 
526 /******************************************************************************/
527 /* g r p F i l e */
528 /******************************************************************************/
529 
530 mode_t XrdSecsssKT::fileMode(const char *Path)
531 {
532  int n;
533 
534  return (!Path || (n = strlen(Path)) < 5 || strcmp(".grp", &Path[n-4])
535  ? S_IRUSR|S_IWUSR : S_IRUSR|S_IWUSR|S_IRGRP);
536 }
537 
538 /******************************************************************************/
539 /* i s K e y */
540 /******************************************************************************/
541 
542 int XrdSecsssKT::isKey(ktEnt &ktRef, ktEnt *ktP, int Full)
543 {
544  if (*ktRef.Data.Name && strcmp(ktP->Data.Name, ktRef.Data.Name)) return 0;
545  if (*ktRef.Data.User && strcmp(ktP->Data.User, ktRef.Data.User)) return 0;
546  if (*ktRef.Data.Grup && strcmp(ktP->Data.Grup, ktRef.Data.Grup)) return 0;
547  if (Full && ktRef.Data.ID > 0
548  && (ktP->Data.ID & 0x7fffffff) != ktRef.Data.ID) return 0;
549  return 1;
550 }
551 
552 /******************************************************************************/
553 /* k e y B 2 X */
554 /******************************************************************************/
555 
556 void XrdSecsssKT::keyB2X(ktEnt *theKT, char *buff)
557 {
558  static const char xTab[] = "0123456789abcdef";
559  int kLen = theKT->Data.Len;
560  char *kP = theKT->Data.Val, Val;
561 
562 // Convert
563 //
564  while(kLen--)
565  {Val = *kP++;
566  *buff++ = xTab[(Val>>4) & 0x0f];
567  *buff++ = xTab[ Val & 0x0f];
568  }
569  *buff = '\0';
570 }
571 
572 /******************************************************************************/
573 /* k e y X 2 B */
574 /******************************************************************************/
575 
576 void XrdSecsssKT::keyX2B(ktEnt *theKT, char *xKey)
577 {
578 // 0 1 2 3 4 5 6 7
579  static const char xtab[] = {10, 10, 11, 12, 13, 14, 15, 15};
580  int n = strlen(xKey);
581  char *kp, kByte;
582 
583 // Make sure we don't overflow
584 //
585  n = (n%2 ? (n+1)/2 : n/2);
586  if (n > ktEnt::maxKLen) n = ktEnt::maxKLen;
587  kp = theKT->Data.Val;
588  theKT->Data.Val[n-1] = 0;
589 
590 // Now convert (we need this to be just consistent not necessarily correct)
591 //
592  while(*xKey)
593  {if (*xKey <= '9') kByte = (*xKey & 0x0f) << 4;
594  else kByte = xtab[*xKey & 0x07] << 4;
595  xKey++;
596  if (*xKey <= '9') kByte |= (*xKey & 0x0f);
597  else kByte |= xtab[*xKey & 0x07];
598  *kp++ = kByte; xKey++;
599  }
600 
601 // Return data via the structure
602 //
603  theKT->Data.Len = n;
604 }
605 
606 /******************************************************************************/
607 /* k t D e c o d e 0 */
608 /******************************************************************************/
609 
610 XrdSecsssKT::ktEnt *XrdSecsssKT::ktDecode0(XrdOucStream &kTab,
611  XrdOucErrInfo *eInfo)
612 {
613  static const short haveCRT = 0x0001;
614  static const short haveEXP = 0x0002;
615  static const short isTIMET = 0x0003;
616  static const short haveGRP = 0x0004;
617  static const short haveKEY = 0x0008;
618  static const short haveNAM = 0x0010;
619  static const short haveNUM = 0x0020;
620  static const short haveUSR = 0x0040;
621  static const short haveFLG = 0x0080;
622 
623  static struct
624  {const char *Name; size_t Offset; int Ctl; short What; char Tag;}
625  ktDesc[] = {
626  {"crtdt", offsetof(ktEnt::ktData,Crt), 0, haveCRT, 'c'},
627  {"expdt", offsetof(ktEnt::ktData,Exp), 0, haveEXP, 'e'},
628  {"flags", offsetof(ktEnt::ktData,Flags),0, haveFLG, 'f'},
629  {"group", offsetof(ktEnt::ktData,Grup), ktEnt::GrupSZ, haveGRP, 'g'},
630  {"keyval", offsetof(ktEnt::ktData,Val), ktEnt::maxKLen*2, haveKEY, 'k'},
631  {"keyname", offsetof(ktEnt::ktData,Name), ktEnt::NameSZ, haveNAM, 'n'},
632  {"keynum", offsetof(ktEnt::ktData,ID), 0, haveNUM, 'N'},
633  {"user", offsetof(ktEnt::ktData,User), ktEnt::UserSZ, haveUSR, 'u'}
634  };
635  static const int ktDnum = sizeof(ktDesc)/sizeof(ktDesc[0]);
636 
637  ktEnt *ktNew = new ktEnt;
638  const char *Prob = 0, *What = "Whatever";
639  char Tag, *Dest, *ep, *tp;
640  long long nVal;
641  short Have = 0;
642  int i = 0;
643 
644 // Decode the record using the tags described in the above table
645 //
646 while((tp = kTab.GetToken()) && !Prob)
647  {Tag = *tp++;
648  if (*tp++ == ':')
649  for (i = 0; i < ktDnum; i++)
650  if (ktDesc[i].Tag == Tag)
651  {Dest = (char *)&(ktNew->Data) + ktDesc[i].Offset;
652  Have |= ktDesc[i].What; What = ktDesc[i].Name;
653  if (ktDesc[i].Ctl)
654  {if ((int)strlen(tp) > ktDesc[i].Ctl) Prob=" is too long";
655  else if (Tag == 'k') keyX2B(ktNew, tp);
656  else strcpy(Dest, tp);
657  } else {
658  nVal = strtoll(tp, &ep, 10);
659  if (ep && *ep) Prob = " has invalid value";
660  else if (ktDesc[i].What & isTIMET)
661  *(time_t *)Dest = static_cast<time_t>(nVal);
662  else *(long long *)Dest = nVal;
663  }
664  }
665  }
666 
667 // If no problem, make sure we have the essential elements
668 //
669  if (!Prob)
670  {if (!(Have & haveGRP)) strcpy(ktNew->Data.Grup, "nogroup");
671  if (!(Have & haveNAM)) strcpy(ktNew->Data.Name, "nowhere");
672  else {int n = strlen(ktNew->Data.Name);
673  if (ktNew->Data.Name[n-1] == '+')
674  ktNew->Data.Opts |= ktEnt::noIPCK;
675  }
676  if (!(Have & haveUSR)) strcpy(ktNew->Data.User, "nobody");
677  if (!(Have & haveKEY)) {What = "keyval"; Prob = " not found";}
678  else if (!(Have & haveNUM)) {What = "keynum"; Prob = " not found";}
679  }
680 
681 // Check if we have a problem
682 //
683  if (Prob)
684  {const char *eVec[] = {What, Prob};
685  if (eInfo) eInfo->setErrInfo(-1, eVec, 2);
686  delete ktNew;
687  return 0;
688  }
689 
690 // Set special value options
691 //
692  if (!strcmp(ktNew->Data.Grup, "anygroup"))
693  ktNew->Data.Opts|=ktEnt::anyGRP;
694  else if (!strcmp(ktNew->Data.Grup, "usrgroup"))
695  ktNew->Data.Opts|=ktEnt::usrGRP;
696  if (!strcmp(ktNew->Data.User, "anybody"))
697  ktNew->Data.Opts|=ktEnt::anyUSR;
698  else if (!strcmp(ktNew->Data.User, "allusers"))
699  ktNew->Data.Opts|=ktEnt::allUSR;
700 
701 // All done
702 //
703  return ktNew;
704 }
int stat(const char *path, struct stat *buf)
int open(const char *path, int oflag,...)
int unlink(const char *path)
int rename(const char *oldpath, const char *newpath)
ssize_t write(int fildes, const void *buf, size_t nbyte)
ssize_t read(int fildes, void *buf, size_t nbyte)
#define close(a)
Definition: XrdPosix.hh:48
XrdOucString Path
#define eMsg(x)
#define ENODATA
Definition: XrdSecsssKT.cc:49
void * XrdSecsssKTRefresh(void *Data)
Definition: XrdSecsssKT.cc:62
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
#define XRDSYSTHREAD_HOLD
#define ID
const char * getErrText()
int setErrInfo(int code, const char *emsg)
int setErrCode(int code)
char * GetLine()
int Attach(int FileDescriptor, int bsz=2047)
void Close(int hold=0)
char * GetToken(int lowcase=0)
static int makePath(char *path, mode_t mode, bool reset=false)
Definition: XrdOucUtils.cc:949
static const int anyUSR
Definition: XrdSecsssKT.hh:67
static const int UserSZ
Definition: XrdSecsssKT.hh:50
struct XrdSecsssKT::ktEnt::ktData Data
static const int noIPCK
Definition: XrdSecsssKT.hh:70
void NUG(ktEnt *ktP)
Definition: XrdSecsssKT.hh:72
static const int anyGRP
Definition: XrdSecsssKT.hh:68
static const int GrupSZ
Definition: XrdSecsssKT.hh:51
static const int maxKLen
Definition: XrdSecsssKT.hh:48
static const int allUSR
Definition: XrdSecsssKT.hh:66
static const int usrGRP
Definition: XrdSecsssKT.hh:69
static const int NameSZ
Definition: XrdSecsssKT.hh:49
int delKey(ktEnt &ktDel)
Definition: XrdSecsssKT.cc:185
int Rewrite(int Keep, int &numKeys, int &numTot, int &numExp)
Definition: XrdSecsssKT.cc:339
static char * genFN()
Definition: XrdSecsssKT.cc:249
void Refresh()
Definition: XrdSecsssKT.cc:311
int getKey(ktEnt &ktEql, bool andKeyID=false)
Definition: XrdSecsssKT.cc:207
time_t RefrTime()
Definition: XrdSecsssKT.hh:105
static void genKey(char *Buff, int blen)
Definition: XrdSecsssKT.cc:268
void addKey(ktEnt &ktNew)
Definition: XrdSecsssKT.cc:158
XrdSecsssKT(XrdOucErrInfo *, const char *, xMode, int refr=60 *60)
Definition: XrdSecsssKT.cc:78
static int Join(pthread_t tid, void **ret)
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)
static int Kill(pthread_t tid)