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, 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  myKT.Attach(ktFD);
458 
459 // Now start reading the keytable which always has the form:
460 //
461 // <format> <whatever data based on format>
462 //
463 do{while((lp = myKT.GetLine()))
464  {recno++; What = 0;
465  if (!*lp) continue;
466  if (!(tp = myKT.GetToken()) || (strcmp("0", tp) && strcmp("1", tp)))
467  {What = "keytable format missing or unsupported"; break;}
468  if (!(ktNew = ktDecode0(myKT, eInfo)))
469  {What = (eInfo ? eInfo->getErrText(): "invalid data"); break;}
470  if (ktMode!=isAdmin && ktNew->Data.Exp && ktNew->Data.Exp <= time(0))
471  {delete ktNew; continue;}
472  tmpID = static_cast<int>(ktNew->Data.ID & 0x7fffffff);
473  if (tmpID > kthiID) kthiID = tmpID;
474 
475  ktP = ktBase; ktPP = 0;
476  while(ktP && !isKey(*ktP, ktNew, 0)) {ktPP=ktP; ktP=ktP->Next;}
477  if (!ktP) {ktNew->Next = ktBase; ktBase = ktNew;}
478  else {if (ktMode == isClient)
479  {if ((ktNew->Data.Exp == 0 && ktP->Data.Exp != 0)
480  || (ktP->Data.Exp!=0 && ktP->Data.Exp < ktNew->Data.Exp))
481  ktP->Set(*ktNew);
482  delete ktNew;
483  } else {
484  while(ktNew->Data.Crt < ktP->Data.Crt)
485  {ktPP = ktP; ktP = ktP->Next;
486  if (!ktP || !isKey(*ktP, ktNew, 0)) break;
487  }
488  if (ktPP) {ktPP->Next = ktNew; ktNew->Next = ktP;}
489  else {ktNew->Next= ktBase; ktBase = ktNew;}
490  }
491  }
492  }
493  if (What)
494  {sprintf(rbuff, "; line %d in ", recno);
495  NoGo = eMsg("getKeyTab", -1, What, rbuff, ktFN);
496  }
497  } while(lp);
498 
499 // Check for problems
500 //
501  if (NoGo) {if (eInfo) eInfo->setErrInfo(EINVAL,"Invalid keytab file.");}
502  else if ((retc = myKT.LastError()))
503  {if (eInfo) eInfo->setErrInfo(retc,"Unable to read keytab file.");
504  NoGo = eMsg("getKeyTab", retc, "Unable to read keytab ",ktFN);
505  }
506  else if (!ktBase)
507  {if (eInfo) eInfo->setErrInfo(ESRCH,"Keytable is empty.");
508  NoGo = eMsg("getKeyTab",-1,"No keys found in ",ktFN);
509  }
510 
511 
512 // Check if an error should be returned
513 //
514  if (!NoGo) eInfo->setErrCode(0);
515 
516 // All done
517 //
518  myKT.Close();
519  return ktBase;
520 }
521 
522 /******************************************************************************/
523 /* g r p F i l e */
524 /******************************************************************************/
525 
526 mode_t XrdSecsssKT::fileMode(const char *Path)
527 {
528  int n;
529 
530  return (!Path || (n = strlen(Path)) < 5 || strcmp(".grp", &Path[n-4])
531  ? S_IRUSR|S_IWUSR : S_IRUSR|S_IWUSR|S_IRGRP);
532 }
533 
534 /******************************************************************************/
535 /* i s K e y */
536 /******************************************************************************/
537 
538 int XrdSecsssKT::isKey(ktEnt &ktRef, ktEnt *ktP, int Full)
539 {
540  if (*ktRef.Data.Name && strcmp(ktP->Data.Name, ktRef.Data.Name)) return 0;
541  if (*ktRef.Data.User && strcmp(ktP->Data.User, ktRef.Data.User)) return 0;
542  if (*ktRef.Data.Grup && strcmp(ktP->Data.Grup, ktRef.Data.Grup)) return 0;
543  if (Full && ktRef.Data.ID > 0
544  && (ktP->Data.ID & 0x7fffffff) != ktRef.Data.ID) return 0;
545  return 1;
546 }
547 
548 /******************************************************************************/
549 /* k e y B 2 X */
550 /******************************************************************************/
551 
552 void XrdSecsssKT::keyB2X(ktEnt *theKT, char *buff)
553 {
554  static const char xTab[] = "0123456789abcdef";
555  int kLen = theKT->Data.Len;
556  char *kP = theKT->Data.Val, Val;
557 
558 // Convert
559 //
560  while(kLen--)
561  {Val = *kP++;
562  *buff++ = xTab[(Val>>4) & 0x0f];
563  *buff++ = xTab[ Val & 0x0f];
564  }
565  *buff = '\0';
566 }
567 
568 /******************************************************************************/
569 /* k e y X 2 B */
570 /******************************************************************************/
571 
572 void XrdSecsssKT::keyX2B(ktEnt *theKT, char *xKey)
573 {
574 // 0 1 2 3 4 5 6 7
575  static const char xtab[] = {10, 10, 11, 12, 13, 14, 15, 15};
576  int n = strlen(xKey);
577  char *kp, kByte;
578 
579 // Make sure we don't overflow
580 //
581  n = (n%2 ? (n+1)/2 : n/2);
582  if (n > ktEnt::maxKLen) n = ktEnt::maxKLen;
583  kp = theKT->Data.Val;
584  theKT->Data.Val[n-1] = 0;
585 
586 // Now convert (we need this to be just consistent not necessarily correct)
587 //
588  while(*xKey)
589  {if (*xKey <= '9') kByte = (*xKey & 0x0f) << 4;
590  else kByte = xtab[*xKey & 0x07] << 4;
591  xKey++;
592  if (*xKey <= '9') kByte |= (*xKey & 0x0f);
593  else kByte |= xtab[*xKey & 0x07];
594  *kp++ = kByte; xKey++;
595  }
596 
597 // Return data via the structure
598 //
599  theKT->Data.Len = n;
600 }
601 
602 /******************************************************************************/
603 /* k t D e c o d e 0 */
604 /******************************************************************************/
605 
606 XrdSecsssKT::ktEnt *XrdSecsssKT::ktDecode0(XrdOucStream &kTab,
607  XrdOucErrInfo *eInfo)
608 {
609  static const short haveCRT = 0x0001;
610  static const short haveEXP = 0x0002;
611  static const short isTIMET = 0x0003;
612  static const short haveGRP = 0x0004;
613  static const short haveKEY = 0x0008;
614  static const short haveNAM = 0x0010;
615  static const short haveNUM = 0x0020;
616  static const short haveUSR = 0x0040;
617  static const short haveFLG = 0x0080;
618 
619  static struct
620  {const char *Name; size_t Offset; int Ctl; short What; char Tag;}
621  ktDesc[] = {
622  {"crtdt", offsetof(ktEnt::ktData,Crt), 0, haveCRT, 'c'},
623  {"expdt", offsetof(ktEnt::ktData,Exp), 0, haveEXP, 'e'},
624  {"flags", offsetof(ktEnt::ktData,Flags),0, haveFLG, 'f'},
625  {"group", offsetof(ktEnt::ktData,Grup), ktEnt::GrupSZ, haveGRP, 'g'},
626  {"keyval", offsetof(ktEnt::ktData,Val), ktEnt::maxKLen*2, haveKEY, 'k'},
627  {"keyname", offsetof(ktEnt::ktData,Name), ktEnt::NameSZ, haveNAM, 'n'},
628  {"keynum", offsetof(ktEnt::ktData,ID), 0, haveNUM, 'N'},
629  {"user", offsetof(ktEnt::ktData,User), ktEnt::UserSZ, haveUSR, 'u'}
630  };
631  static const int ktDnum = sizeof(ktDesc)/sizeof(ktDesc[0]);
632 
633  ktEnt *ktNew = new ktEnt;
634  const char *Prob = 0, *What = "Whatever";
635  char Tag, *Dest, *ep, *tp;
636  long long nVal;
637  short Have = 0;
638  int i = 0;
639 
640 // Decode the record using the tags described in the above table
641 //
642 while((tp = kTab.GetToken()) && !Prob)
643  {Tag = *tp++;
644  if (*tp++ == ':')
645  for (i = 0; i < ktDnum; i++)
646  if (ktDesc[i].Tag == Tag)
647  {Dest = (char *)&(ktNew->Data) + ktDesc[i].Offset;
648  Have |= ktDesc[i].What; What = ktDesc[i].Name;
649  if (ktDesc[i].Ctl)
650  {if ((int)strlen(tp) > ktDesc[i].Ctl) Prob=" is too long";
651  else if (Tag == 'k') keyX2B(ktNew, tp);
652  else strcpy(Dest, tp);
653  } else {
654  nVal = strtoll(tp, &ep, 10);
655  if (ep && *ep) Prob = " has invalid value";
656  else if (ktDesc[i].What & isTIMET)
657  *(time_t *)Dest = static_cast<time_t>(nVal);
658  else *(long long *)Dest = nVal;
659  }
660  }
661  }
662 
663 // If no problem, make sure we have the essential elements
664 //
665  if (!Prob)
666  {if (!(Have & haveGRP)) strcpy(ktNew->Data.Grup, "nogroup");
667  if (!(Have & haveNAM)) strcpy(ktNew->Data.Name, "nowhere");
668  else {int n = strlen(ktNew->Data.Name);
669  if (ktNew->Data.Name[n-1] == '+')
670  ktNew->Data.Opts |= ktEnt::noIPCK;
671  }
672  if (!(Have & haveUSR)) strcpy(ktNew->Data.User, "nobody");
673  if (!(Have & haveKEY)) {What = "keyval"; Prob = " not found";}
674  else if (!(Have & haveNUM)) {What = "keynum"; Prob = " not found";}
675  }
676 
677 // Check if we have a problem
678 //
679  if (Prob)
680  {const char *eVec[] = {What, Prob};
681  if (eInfo) eInfo->setErrInfo(-1, eVec, 2);
682  delete ktNew;
683  return 0;
684  }
685 
686 // Set special value options
687 //
688  if (!strcmp(ktNew->Data.Grup, "anygroup"))
689  ktNew->Data.Opts|=ktEnt::anyGRP;
690  else if (!strcmp(ktNew->Data.Grup, "usrgroup"))
691  ktNew->Data.Opts|=ktEnt::usrGRP;
692  if (!strcmp(ktNew->Data.User, "anybody"))
693  ktNew->Data.Opts|=ktEnt::anyUSR;
694  else if (!strcmp(ktNew->Data.User, "allusers"))
695  ktNew->Data.Opts|=ktEnt::allUSR;
696 
697 // All done
698 //
699  return ktNew;
700 }
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:43
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:917
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)