XRootD
Loading...
Searching...
No Matches
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
42
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
56int XrdSecsssKT::randFD = -1;
57
58/******************************************************************************/
59/* X r d S e c s s s K T R e f r */
60/******************************************************************************/
61
62void *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
78XrdSecsssKT::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
207int 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
268void 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
339int 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
407int 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
426XrdSecsssKT::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//
463do{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
526mode_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
538int 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
552void 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
572void 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
606XrdSecsssKT::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//
642while((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}
#define ENODATA
#define close(a)
Definition XrdPosix.hh:43
#define write(a, b, c)
Definition XrdPosix.hh:110
#define open
Definition XrdPosix.hh:71
#define unlink(a)
Definition XrdPosix.hh:108
#define stat(a, b)
Definition XrdPosix.hh:96
#define rename(a, b)
Definition XrdPosix.hh:87
#define read(a, b, c)
Definition XrdPosix.hh:77
XrdOucString Path
#define eMsg(x)
void * XrdSecsssKTRefresh(void *Data)
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:99
#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)
static const int anyUSR
static const int UserSZ
struct XrdSecsssKT::ktEnt::ktData Data
static const int noIPCK
void NUG(ktEnt *ktP)
static const int anyGRP
static const int GrupSZ
static const int maxKLen
static const int allUSR
static const int usrGRP
static const int NameSZ
int delKey(ktEnt &ktDel)
int Rewrite(int Keep, int &numKeys, int &numTot, int &numExp)
static char * genFN()
int getKey(ktEnt &ktEql, bool andKeyID=false)
time_t RefrTime()
static void genKey(char *Buff, int blen)
void addKey(ktEnt &ktNew)
XrdSecsssKT(XrdOucErrInfo *, const char *, xMode, int refr=60 *60)
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)