XrdSecsssKT.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                        X r d S e c s s s K T . c c                         */
00004 /*                                                                            */
00005 /* (c) 2008 by the Board of Trustees of the Leland Stanford, Jr., University  */
00006 /*                            All Rights Reserved                             */
00007 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00008 /*              DE-AC02-76-SFO0515 with the Department of Energy              */
00009 /******************************************************************************/
00010   
00011 //       $Id: XrdSecsssKT.cc 38011 2011-02-08 18:35:57Z ganis $
00012 
00013 const char *XrdSecsssKTCVSID = "$Id: XrdSecsssKT.cc 38011 2011-02-08 18:35:57Z ganis $";
00014 
00015 #include <fcntl.h>
00016 #include <stdio.h>
00017 #include <stddef.h>
00018 #include <stdlib.h>
00019 #include <string.h>
00020 #include <sys/time.h>
00021 #include <sys/types.h>
00022 #include <sys/stat.h>
00023 
00024 #include "XrdSecsss/XrdSecsssKT.hh"
00025 
00026 #include "XrdOuc/XrdOucErrInfo.hh"
00027 #include "XrdOuc/XrdOucStream.hh"
00028 #include "XrdOuc/XrdOucUtils.hh"
00029 #include "XrdSys/XrdSysHeaders.hh"
00030   
00031 /******************************************************************************/
00032 /*                    S t a t i c   D e f i n i t i o n s                     */
00033 /******************************************************************************/
00034 
00035 int XrdSecsssKT::randFD = -1;
00036   
00037 /******************************************************************************/
00038 /*                       X r d S e c s s s K T R e f r                        */
00039 /******************************************************************************/
00040   
00041 void *XrdSecsssKTRefresh(void *Data)
00042 {
00043    XrdSecsssKT *theKT = (XrdSecsssKT *)Data;
00044    struct timespec naptime = {theKT->RefrTime(), 0};
00045 
00046 // Loop and check if keytab has changed
00047 //
00048    while(1) {nanosleep(&naptime, 0); theKT->Refresh();}
00049 
00050    return (void *)0;
00051 }
00052 
00053 /******************************************************************************/
00054 /*                           C o n s t r u c t o r                            */
00055 /******************************************************************************/
00056   
00057 XrdSecsssKT::XrdSecsssKT(XrdOucErrInfo *eInfo, const char *kPath,
00058                          xMode oMode, int refrInt)
00059 {
00060    static const char *eText = "Unable to start keytab refresh thread";
00061    const char *devRand = "/dev/urandom";
00062    struct stat sbuf;
00063    pthread_t pid;
00064    int retc;
00065 
00066 // Do some common initialization
00067 //
00068    ktPath = (kPath ? strdup(kPath) : 0);
00069    ktList = 0; kthiID = 0; ktMode = oMode; ktRefT = (time_t)refrInt;
00070    if (eInfo) eInfo->setErrCode(0);
00071 
00072 // Prepare /dev/random if we have it
00073 //
00074    if (stat(devRand, &sbuf)) devRand = "/dev/random";
00075    if ((randFD = open(devRand, O_RDONLY)) < 0
00076    && oMode != isClient && errno != ENOENT)
00077       eMsg("sssKT",errno,"Unable to generate random key"," opening ",devRand);
00078 
00079 // First get the stat information for the file
00080 //
00081    if (!kPath)
00082       {if (oMode != isAdmin)
00083           {eMsg("sssKT", -1, "Keytable path not specified.");
00084            if (eInfo) eInfo->setErrInfo(EINVAL, "Keytable path missing.");
00085            return;
00086           }
00087        sbuf.st_mtime = 0; sbuf.st_mode = S_IRWXU;
00088       } else if (stat(kPath, &sbuf))
00089                 {if (eInfo) eInfo->setErrInfo(errno, "Keytable not found");
00090                  if (errno != ENOENT || oMode != isAdmin)
00091                     eMsg("sssKT",errno,"Unable process keytable ",kPath);
00092                  return;
00093                 }
00094 
00095 // Now read in the whole key table and start possible refresh thread
00096 //
00097    if ((ktList = getKeyTab(eInfo, sbuf.st_mtime, sbuf.st_mode))
00098    && (oMode != isAdmin) && (!eInfo || eInfo->getErrInfo() == 0))
00099       {if ((retc = XrdSysThread::Run(&pid,XrdSecsssKTRefresh,(void *)this)))
00100           {eMsg("sssKT", errno, eText); eInfo->setErrInfo(-1, eText);}
00101       }
00102 }
00103 
00104 /******************************************************************************/
00105 /*                            D e s t r u c t o r                             */
00106 /******************************************************************************/
00107 
00108 XrdSecsssKT::~XrdSecsssKT()
00109 {
00110    ktEnt *ktP;
00111 
00112    myMutex.Lock();
00113    if (ktPath) {free(ktPath); ktPath = 0;}
00114 
00115    while((ktP = ktList)) {ktList = ktList->Next; delete ktP;}
00116    myMutex.UnLock();
00117 }
00118   
00119 /******************************************************************************/
00120 /*                               a d d K e y                                  */
00121 /******************************************************************************/
00122   
00123 void XrdSecsssKT::addKey(ktEnt &ktNew)
00124 {
00125    ktEnt *ktPP = 0, *ktP;
00126 
00127 // Generate a key for this entry
00128 //
00129    genKey(ktNew.Data.Val, ktNew.Data.Len);
00130    ktNew.Data.Crt = time(0);
00131    ktNew.Data.ID  = static_cast<long long>(ktNew.Data.Crt & 0x7fffffff) << 32L
00132                   | static_cast<long long>(++kthiID);
00133 
00134 // Locate place to insert this key
00135 //
00136    ktP = ktList;
00137    while(ktP && !isKey(*ktP, &ktNew, 0)) {ktPP = ktP; ktP = ktP->Next;}
00138 
00139 // Now chain in the entry
00140 //
00141    if (ktPP) ktPP->Next = &ktNew;
00142       else   ktList     = &ktNew;
00143    ktNew.Next = ktP;
00144 }
00145 
00146 /******************************************************************************/
00147 /*                                d e l K e y                                 */
00148 /******************************************************************************/
00149   
00150 int XrdSecsssKT::delKey(ktEnt &ktDel)
00151 {
00152    ktEnt *ktN, *ktPP = 0, *ktP = ktList;
00153    int nDel = 0;
00154 
00155 // Remove all matching keys
00156 //
00157    while(ktP)
00158         {if (isKey(ktDel, ktP))
00159             {if (ktPP) ktPP->Next = ktP->Next;
00160                 else   ktList     = ktP->Next;
00161              ktN = ktP; ktP = ktP->Next; delete ktN; nDel++;
00162             } else {ktPP = ktP; ktP = ktP->Next;}
00163         }
00164 
00165    return nDel;
00166 }
00167 
00168 /******************************************************************************/
00169 /*                                g e t K e y                                 */
00170 /******************************************************************************/
00171   
00172 int XrdSecsssKT::getKey(ktEnt &theEnt)
00173 {
00174    ktEnt *ktP, *ktN;
00175 
00176 // Lock the keytab to prevent modification
00177 //
00178    myMutex.Lock();
00179    ktP = ktList;
00180 
00181 // Find first key by key name (used normally by clients) or by keyID
00182 //
00183    if (!*theEnt.Data.Name)
00184       {if (theEnt.Data.ID >= 0) 
00185           while(ktP && ktP->Data.ID != theEnt.Data.ID)  ktP = ktP->Next;
00186       }
00187       else {while(ktP && strcmp(ktP->Data.Name,theEnt.Data.Name)) ktP=ktP->Next;
00188             while(ktP && ktP->Data.Exp <= time(0))
00189                  {if (!(ktN=ktP->Next) 
00190                   ||  strcmp(ktN->Data.Name,theEnt.Data.Name)) break;
00191                   ktP = ktN;
00192                  }
00193            }
00194 
00195 // If we found a match, export it
00196 //
00197    if (ktP) theEnt = *ktP;
00198    myMutex.UnLock();
00199 
00200 // Indicate if key expired
00201 //
00202    if (!ktP) return ENOENT;
00203    return (theEnt.Data.Exp && theEnt.Data.Exp <= time(0) ? -1 : 0);
00204 }
00205 
00206 /******************************************************************************/
00207 /*                                 g e n F N                                  */
00208 /******************************************************************************/
00209   
00210 char *XrdSecsssKT::genFN()
00211 {
00212    static char fnbuff[1040];
00213    const char *pfx;
00214 
00215 // Get the path prefix
00216 //
00217    if (!(pfx = getenv("HOME")) || !*pfx) pfx = "";
00218 
00219 // Format the name
00220 //
00221    snprintf(fnbuff, sizeof(fnbuff), "%s/.xrd/sss.keytab", pfx);
00222    return fnbuff;
00223 }
00224   
00225 /******************************************************************************/
00226 /*                                g e n K e y                                 */
00227 /******************************************************************************/
00228   
00229 void XrdSecsssKT::genKey(char *kBP, int kLen)
00230 {
00231    struct timeval tval;
00232    int kTemp;
00233 
00234 // See if we can directly service the key. Make sure that we get some entropy
00235 // because some /dev/random devices start out really cold.
00236 //
00237    if (randFD >= 0) 
00238       {char *buffP = kBP;
00239        int i, Got, Want = kLen, zcnt = 0, maxZ = kLen*25/100;
00240        while(Want)
00241        do { {do {Got = read(randFD, buffP, Want);}
00242                 while(Got < 0 && errno == EINTR);
00243              if (Got > 0) {buffP += Got; Want -= Got;}
00244             }
00245           } while(Got > 0 && Want);
00246        if (!Want)
00247           {for (i = 0; i < kLen; i++) if (!kBP[i]) zcnt++;
00248            if (zcnt <= maxZ) return;
00249           }
00250       }
00251 
00252 // Generate a seed
00253 //
00254    gettimeofday(&tval, 0);
00255    if (tval.tv_usec == 0) tval.tv_usec = tval.tv_sec;
00256    tval.tv_usec = tval.tv_usec ^ getpid();
00257    srand48(static_cast<long>(tval.tv_usec));
00258 
00259 // Now generate the key (we ignore he fact that longs may be 4 or 8 bytes)
00260 //
00261    while(kLen > 0)
00262         {kTemp = mrand48();
00263          memcpy(kBP, &kTemp, (4 > kLen ? kLen : 4));
00264          kBP += 4; kLen -= 4;
00265         }
00266 }
00267 
00268 /******************************************************************************/
00269 /*                               R e f r e s h                                */
00270 /******************************************************************************/
00271   
00272 void XrdSecsssKT::Refresh()
00273 {
00274    XrdOucErrInfo eInfo;
00275    ktEnt *ktNew, *ktOld, *ktNext;
00276    struct stat sbuf;
00277    int retc = 0;
00278 
00279 // Get change time of keytable and if changed, update it
00280 //
00281    if (stat(ktPath, &sbuf) == 0)
00282       {if (sbuf.st_mtime == ktMtime) return;
00283        if ((ktNew = getKeyTab(&eInfo, sbuf.st_mtime, sbuf.st_mode))
00284        && eInfo.getErrInfo() == 0)
00285           {myMutex.Lock(); ktOld = ktList; ktList = ktNew; myMutex.UnLock();
00286           } else ktOld = ktNew;
00287        while(ktOld) {ktNext = ktOld->Next; delete ktOld; ktOld = ktNext;}
00288        if ((retc == eInfo.getErrInfo()) == 0) return;
00289       } else retc = errno;
00290 
00291 // Refresh failed
00292 //
00293    eMsg("Refresh",retc,"Unable to refresh keytable",ktPath);
00294 }
00295 
00296 /******************************************************************************/
00297 /*                               R e w r i t e                                */
00298 /******************************************************************************/
00299   
00300 int XrdSecsssKT::Rewrite(int Keep, int &numKeys, int &numTot, int &numExp)
00301 {
00302    char tmpFN[1024], buff[2048], kbuff[4096], *Slash;
00303    int ktFD, numID = 0, n, retc = 0;
00304    ktEnt ktCurr, *ktP, *ktN;
00305    mode_t theMode = fileMode(ktPath);
00306 
00307 // Invoke mkpath in case the path is missing
00308 //
00309    strcpy(tmpFN, ktPath);
00310    if ((Slash = rindex(tmpFN, '/'))) *Slash = '\0';
00311    retc = XrdOucUtils::makePath(tmpFN,S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
00312    if (retc) return (retc < 0 ? -retc : retc);
00313    if (Slash) *Slash = '/';
00314 
00315 // Construct temporary filename
00316 //
00317    sprintf(buff, ".%d", static_cast<int>(getpid()));
00318    strcat(tmpFN, buff);
00319 
00320 // Open the file for output
00321 //
00322    if ((ktFD = open(tmpFN, O_WRONLY|O_CREAT|O_TRUNC, theMode)) < 0)
00323       return errno;
00324 
00325 // Write all of the keytable
00326 //
00327    ktCurr.Data.Name[0] = ktCurr.Data.User[0] = ktCurr.Data.Grup[0] = 3;
00328    ktN = ktList; numKeys = numTot = numExp = 0;
00329    while((ktP = ktN))
00330         {ktN = ktN->Next; numTot++;
00331          if (ktP->Data.Name[0] == '\0') continue;
00332          if (ktP->Data.Exp && ktP->Data.Exp <= time(0)) {numExp++; continue;}
00333          if (!isKey(ktCurr, ktP, 0)) {ktCurr.NUG(ktP); numID = 0;}
00334             else if (Keep && numID >= Keep) continue;
00335          n = sprintf(buff, "%s0 u:%s g:%s n:%s N:%lld c:%ld e:%ld k:",
00336                     (numKeys ? "\n" : ""),
00337                      ktP->Data.User,ktP->Data.Grup,ktP->Data.Name,ktP->Data.ID,
00338                      ktP->Data.Crt, ktP->Data.Exp);
00339          numID++; numKeys++; keyB2X(ktP, kbuff);
00340          if (write(ktFD, buff, n) < 0
00341          ||  write(ktFD, kbuff, ktP->Data.Len*2) < 0) break;
00342         }
00343 
00344 // Check for errors
00345 //
00346    if (ktP) retc = errno;
00347       else if (!numKeys) retc = ENODATA;
00348 
00349 // Atomically trounce the original file if we can
00350 //
00351    close(ktFD);
00352    if (!retc && rename(tmpFN, ktPath) < 0) retc = errno;
00353 
00354 // All done
00355 //
00356    unlink(tmpFN); 
00357    return retc;
00358 }
00359 
00360 /******************************************************************************/
00361 /*                       P r i v a t e   M e t h o d s                        */
00362 /******************************************************************************/
00363 /******************************************************************************/
00364 /*                                  e M s g                                   */
00365 /******************************************************************************/
00366 
00367 int XrdSecsssKT::eMsg(const char *epname, int rc,
00368                       const char *txt1, const char *txt2,
00369                       const char *txt3, const char *txt4)
00370 {
00371               cerr <<"Secsss (" << epname <<"): ";
00372               cerr <<txt1;
00373    if (txt2)  cerr <<txt2;
00374    if (txt3)  cerr <<txt3;
00375    if (txt4)  cerr <<txt4;
00376    if (rc>0)  cerr <<"; " <<strerror(rc);
00377               cerr <<endl;
00378 
00379    return (rc ? (rc < 0 ? rc : -rc) : -1);
00380 }
00381 
00382 /******************************************************************************/
00383 /*                             g e t K e y T a b                              */
00384 /******************************************************************************/
00385   
00386 XrdSecsssKT::ktEnt* XrdSecsssKT::getKeyTab(XrdOucErrInfo *eInfo,
00387                                            time_t Mtime, mode_t Amode)
00388 {
00389    static const int altMode = S_IRWXG | S_IRWXO;
00390    XrdOucStream myKT;
00391    int ktFD, retc, tmpID, recno = 0, NoGo = 0;
00392    const char *What = 0, *ktFN;
00393    char *lp, *tp, rbuff[64];
00394    ktEnt *ktP, *ktPP, *ktNew, *ktBase = 0;
00395 
00396 // Verify that the keytable is only readable by us
00397 //
00398    ktMtime = Mtime;
00399    if ((Amode & altMode) & ~fileMode(ktPath))
00400       {if (eInfo) eInfo->setErrInfo(EACCES, "Keytab file is not secure!");
00401        eMsg("getKeyTab",-1,"Unable to process ",ktPath,"; file is not secure!");
00402        return 0;
00403       }
00404 
00405 // Open the file
00406 //
00407    if (ktPath)
00408       {if ((ktFD = open(ktPath, O_RDONLY)) < 0)
00409           {if (eInfo) eInfo->setErrInfo(errno, "Unable to open keytab file.");
00410            eMsg("getKeyTab", errno, "Unable to open ", ktPath);
00411            return 0;
00412           } else ktFN = ktPath;
00413       } else {ktFD = dup(STDIN_FILENO); ktFN = "stdin";}
00414 
00415 // Attach the fd to the stream
00416 //
00417    myKT.Attach(ktFD);
00418 
00419 // Now start reading the keytable which always has the form:
00420 //
00421 // <format> <whatever data based on format>
00422 //
00423 do{while((lp = myKT.GetLine()))
00424         {recno++; What = 0;
00425          if (!*lp) continue;
00426          if (!(tp = myKT.GetToken()) || strcmp("0", tp))
00427             {What = "keytable format missing or unsupported";      break;}
00428          if (!(ktNew = ktDecode0(myKT, eInfo)))
00429             {What = (eInfo ? eInfo->getErrText(): "invalid data"); break;}
00430          if (ktMode!=isAdmin && ktNew->Data.Exp && ktNew->Data.Exp <= time(0))
00431             {delete ktNew; continue;}
00432          tmpID = static_cast<int>(ktNew->Data.ID & 0x7fffffff);
00433          if (tmpID > kthiID) kthiID = tmpID;
00434          
00435          ktP = ktBase; ktPP = 0;
00436          while(ktP && !isKey(*ktP, ktNew, 0)) {ktPP=ktP; ktP=ktP->Next;}
00437          if (!ktP) {ktNew->Next = ktBase; ktBase = ktNew;}
00438             else {if (ktMode == isClient)
00439                      {if ((ktNew->Data.Exp == 0 && ktP->Data.Exp != 0)
00440                       ||  (ktP->Data.Exp!=0 && ktP->Data.Exp < ktNew->Data.Exp))
00441                           ktP->Set(*ktNew);
00442                       delete ktNew;
00443                      } else {
00444                       while(ktNew->Data.Crt < ktP->Data.Crt)
00445                            {ktPP = ktP; ktP = ktP->Next;
00446                             if (!ktP || !isKey(*ktP, ktNew, 0)) break;
00447                            }
00448                       if (ktPP) {ktPP->Next = ktNew; ktNew->Next = ktP;}
00449                          else   {ktNew->Next= ktBase; ktBase = ktNew;}
00450                      }
00451                  }
00452         }
00453    if (What)
00454       {sprintf(rbuff, "; line %d in ", recno);
00455        NoGo = eMsg("getKeyTab", -1, What, rbuff, ktFN);
00456       }
00457   } while(lp);
00458 
00459 // Check for problems
00460 //
00461         if (NoGo) {if (eInfo) eInfo->setErrInfo(EINVAL,"Invalid keytab file.");}
00462    else if ((retc = myKT.LastError()))
00463            {if (eInfo) eInfo->setErrInfo(retc,"Unable to read keytab file.");
00464             NoGo = eMsg("getKeyTab", retc, "Unable to read keytab ",ktFN);
00465            }
00466    else if (!ktBase)
00467            {if (eInfo) eInfo->setErrInfo(ESRCH,"Keytable is empty.");
00468             NoGo = eMsg("getKeyTab",-1,"No keys found in ",ktFN);
00469            }
00470 
00471 
00472 // Check if an error should be returned
00473 //
00474    if (!NoGo) eInfo->setErrCode(0);
00475 
00476 // All done
00477 //
00478    myKT.Close();
00479    return ktBase;
00480 }
00481 
00482 /******************************************************************************/
00483 /*                               g r p F i l e                                */
00484 /******************************************************************************/
00485   
00486 mode_t XrdSecsssKT::fileMode(const char *Path)
00487 {
00488    int n;
00489 
00490    return (!Path || (n = strlen(Path)) < 5 || strcmp(".grp", &Path[n-4])
00491         ? S_IRUSR|S_IWUSR : S_IRUSR|S_IWUSR|S_IRGRP);
00492 }
00493 
00494 /******************************************************************************/
00495 /*                                 i s K e y                                  */
00496 /******************************************************************************/
00497 
00498 int  XrdSecsssKT::isKey(ktEnt &ktRef, ktEnt *ktP, int Full)
00499 {
00500    if (*ktRef.Data.Name && strcmp(ktP->Data.Name, ktRef.Data.Name)) return 0;
00501    if (*ktRef.Data.User && strcmp(ktP->Data.User, ktRef.Data.User)) return 0;
00502    if (*ktRef.Data.Grup && strcmp(ktP->Data.Grup, ktRef.Data.Grup)) return 0;
00503    if (Full && ktRef.Data.ID > 0
00504    && (ktP->Data.ID & 0x7fffffff) != ktRef.Data.ID) return 0;
00505    return 1;
00506 }
00507   
00508 /******************************************************************************/
00509 /*                                k e y B 2 X                                 */
00510 /******************************************************************************/
00511 
00512 void XrdSecsssKT::keyB2X(ktEnt *theKT, char *buff)
00513 {
00514    static const char xTab[] = "0123456789abcdef";
00515    int  kLen = theKT->Data.Len;
00516    char *kP  = theKT->Data.Val, Val;
00517 
00518 // Convert
00519 //
00520    while(kLen--)
00521         {Val = *kP++;
00522          *buff++ = xTab[(Val>>4) & 0x0f];
00523          *buff++ = xTab[ Val     & 0x0f];
00524         }
00525    *buff = '\0';
00526 }
00527   
00528 /******************************************************************************/
00529 /*                                k e y X 2 B                                 */
00530 /******************************************************************************/
00531   
00532 void XrdSecsssKT::keyX2B(ktEnt *theKT, char *xKey)
00533 {
00534 //                              0   1   2   3   4   5   6   7
00535    static const char xtab[] = {10, 10, 11, 12, 13, 14, 15, 15};
00536    int n = strlen(xKey);
00537    char *kp, kByte;
00538 
00539 // Make sure we don't overflow
00540 //
00541    n = (n%2 ? (n+1)/2 : n/2);
00542    if (n > ktEnt::maxKLen) n = ktEnt::maxKLen;
00543    kp = theKT->Data.Val;
00544    theKT->Data.Val[n-1] = 0;
00545 
00546 // Now convert (we need this to be just consistent not necessarily correct)
00547 //
00548    while(*xKey)
00549         {if (*xKey <= '9') kByte  = (*xKey & 0x0f) << 4;
00550             else kByte = xtab[*xKey & 0x07] << 4;
00551          xKey++;
00552          if (*xKey <= '9') kByte |= (*xKey & 0x0f);
00553             else kByte |= xtab[*xKey & 0x07];
00554          *kp++ = kByte; xKey++;
00555         }
00556 
00557 // Return data via the structure
00558 //
00559    theKT->Data.Len = n;
00560 }
00561 
00562 /******************************************************************************/
00563 /*                             k t D e c o d e 0                              */
00564 /******************************************************************************/
00565   
00566 XrdSecsssKT::ktEnt *XrdSecsssKT::ktDecode0(XrdOucStream  &kTab,
00567                                            XrdOucErrInfo *eInfo)
00568 {
00569    static const short haveCRT = 0x0001;
00570    static const short haveEXP = 0x0002;
00571    static const short isTIMET = 0x0003;
00572    static const short haveGRP = 0x0004;
00573    static const short haveKEY = 0x0008;
00574    static const short haveNAM = 0x0010;
00575    static const short haveNUM = 0x0020;
00576    static const short haveUSR = 0x0040;
00577 
00578    static struct 
00579           {const char *Name; size_t Offset; int Ctl; short What; char Tag;}
00580           ktDesc[] = {
00581    {"crtdt",   offsetof(ktEnt::ktData,Crt),  0,                haveCRT, 'c'},
00582    {"expdt",   offsetof(ktEnt::ktData,Exp),  0,                haveEXP, 'e'},
00583    {"group",   offsetof(ktEnt::ktData,Grup), ktEnt::GrupSZ,    haveGRP, 'g'},
00584    {"keyval",  offsetof(ktEnt::ktData,Val),  ktEnt::maxKLen*2, haveKEY, 'k'},
00585    {"keyname", offsetof(ktEnt::ktData,Name), ktEnt::NameSZ,    haveNAM, 'n'},
00586    {"keynum",  offsetof(ktEnt::ktData,ID),   0,                haveNUM, 'N'},
00587    {"user",    offsetof(ktEnt::ktData,User), ktEnt::UserSZ,    haveUSR, 'u'}
00588    };
00589    static const int ktDnum = sizeof(ktDesc)/sizeof(ktDesc[0]);
00590 
00591    ktEnt *ktNew = new ktEnt;
00592    const char *Prob = 0, *What = "Whatever";
00593    char Tag, *Dest, *ep, *tp;
00594    long long nVal;
00595    short Have = 0;
00596    int i = 0;
00597 
00598 // Decode the record using the tags described in the above table
00599 //
00600 while((tp = kTab.GetToken()) && !Prob)
00601      {Tag = *tp++;
00602       if (*tp++ == ':')
00603          for (i = 0; i < ktDnum; i++)
00604              if (ktDesc[i].Tag == Tag)
00605                 {Dest = (char *)&(ktNew->Data) + ktDesc[i].Offset;
00606                  Have |= ktDesc[i].What; What = ktDesc[i].Name;
00607                  if (ktDesc[i].Ctl)
00608                     {if ((int)strlen(tp) >= ktDesc[i].Ctl) Prob=" is too long";
00609                         else if (Tag == 'k') keyX2B(ktNew, tp);
00610                                 else strcpy(Dest, tp);
00611                     } else {
00612                      nVal = strtoll(tp, &ep, 10);
00613                      if (ep && *ep) Prob = " has invalid value";
00614                         else if (ktDesc[i].What & isTIMET)
00615                                  *(time_t *)Dest = static_cast<time_t>(nVal);
00616                                 else *(long long *)Dest = nVal;
00617                     }
00618                 }
00619      }
00620 
00621 // If no problem, make sure we have the essential elements
00622 //
00623    if (!Prob)
00624       {if (!(Have & haveGRP)) strcpy(ktNew->Data.Grup, "nogroup");
00625        if (!(Have & haveNAM)) strcpy(ktNew->Data.Name, "nowhere");
00626        if (!(Have & haveUSR)) strcpy(ktNew->Data.User, "nobody");
00627             if (!(Have & haveKEY)) {What = "keyval"; Prob = " not found";}
00628        else if (!(Have & haveNUM)) {What = "keynum"; Prob = " not found";}
00629       }
00630 
00631 // Check if we have a problem
00632 //
00633    if (Prob)
00634       {const char *eVec[] = {What, Prob};
00635        if (eInfo) eInfo->setErrInfo(-1, eVec, 2);
00636        delete ktNew;
00637        return 0;
00638       }
00639 
00640 // Set special value options
00641 //
00642    if (!strcmp(ktNew->Data.Grup, "anygroup"))       
00643       ktNew->Data.Opts|=ktEnt::anyGRP;
00644       else if (!strcmp(ktNew->Data.Grup, "usrgroup"))
00645               ktNew->Data.Opts|=ktEnt::usrGRP;
00646    if (!strcmp(ktNew->Data.User, "anybody"))
00647       ktNew->Data.Opts|=ktEnt::anyUSR;
00648 
00649 // All done
00650 //
00651    return ktNew;
00652 }

Generated on Tue Jul 5 14:47:02 2011 for ROOT_528-00b_version by  doxygen 1.5.1