XRootD
XrdSecsssKT Class Reference

#include <XrdSecsssKT.hh>

+ Collaboration diagram for XrdSecsssKT:

Classes

class  ktEnt
 

Public Types

enum  xMode {
  isAdmin = 0 ,
  isClient ,
  isServer
}
 

Public Member Functions

 XrdSecsssKT (XrdOucErrInfo *, const char *, xMode, int refr=60 *60)
 
 ~XrdSecsssKT ()
 
void addKey (ktEnt &ktNew)
 
int delKey (ktEnt &ktDel)
 
int getKey (ktEnt &ktEql, bool andKeyID=false)
 
ktEntkeyList ()
 
void Refresh ()
 
time_t RefrTime ()
 
int Rewrite (int Keep, int &numKeys, int &numTot, int &numExp)
 
int Same (const char *path)
 
void setPath (const char *Path)
 

Static Public Member Functions

static char * genFN ()
 
static void genKey (char *Buff, int blen)
 

Detailed Description

Definition at line 40 of file XrdSecsssKT.hh.

Member Enumeration Documentation

◆ xMode

Enumerator
isAdmin 
isClient 
isServer 

Definition at line 114 of file XrdSecsssKT.hh.

Constructor & Destructor Documentation

◆ XrdSecsssKT()

XrdSecsssKT::XrdSecsssKT ( XrdOucErrInfo eInfo,
const char *  kPath,
xMode  oMode,
int  refr = 60*60 
)

Definition at line 78 of file XrdSecsssKT.cc.

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 }
int stat(const char *path, struct stat *buf)
int open(const char *path, int oflag,...)
#define eMsg(x)
void * XrdSecsssKTRefresh(void *Data)
Definition: XrdSecsssKT.cc:62
#define XRDSYSTHREAD_HOLD
int setErrInfo(int code, const char *emsg)
int setErrCode(int code)
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)

References eMsg, XrdOucErrInfo::getErrInfo(), isAdmin, isClient, open(), XrdSysThread::Run(), XrdOucErrInfo::setErrCode(), XrdOucErrInfo::setErrInfo(), stat(), XrdSecsssKTRefresh(), and XRDSYSTHREAD_HOLD.

+ Here is the call graph for this function:

◆ ~XrdSecsssKT()

XrdSecsssKT::~XrdSecsssKT ( )

Definition at line 130 of file XrdSecsssKT.cc.

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 }
static int Join(pthread_t tid, void **ret)
static int Kill(pthread_t tid)

References XrdSysThread::Join(), XrdSysThread::Kill(), XrdSysMutex::Lock(), XrdSecsssKT::ktEnt::Next, and XrdSysMutex::UnLock().

+ Here is the call graph for this function:

Member Function Documentation

◆ addKey()

void XrdSecsssKT::addKey ( ktEnt ktNew)

Definition at line 158 of file XrdSecsssKT.cc.

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 }
static void genKey(char *Buff, int blen)
Definition: XrdSecsssKT.cc:268

References XrdSecsssKT::ktEnt::ktData::Crt, XrdSecsssKT::ktEnt::Data, genKey(), XrdSecsssKT::ktEnt::ktData::ID, XrdSecsssKT::ktEnt::ktData::Len, XrdSecsssKT::ktEnt::Next, and XrdSecsssKT::ktEnt::ktData::Val.

Referenced by XrdSecsssAdmin_addKey().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ delKey()

int XrdSecsssKT::delKey ( ktEnt ktDel)

Definition at line 185 of file XrdSecsssKT.cc.

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 }

References XrdSecsssKT::ktEnt::Next.

Referenced by XrdSecsssAdmin_delKey().

+ Here is the caller graph for this function:

◆ genFN()

char * XrdSecsssKT::genFN ( )
static

Definition at line 249 of file XrdSecsssKT.cc.

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 }

Referenced by XrdSecProtocolsss::Load_Client(), XrdSecProtocolsss::Load_Server(), and main().

+ Here is the caller graph for this function:

◆ genKey()

void XrdSecsssKT::genKey ( char *  Buff,
int  blen 
)
static

Definition at line 268 of file XrdSecsssKT.cc.

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 }
ssize_t read(int fildes, void *buf, size_t nbyte)

References read().

Referenced by addKey().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getKey()

int XrdSecsssKT::getKey ( ktEnt ktEql,
bool  andKeyID = false 
)

Definition at line 207 of file XrdSecsssKT.cc.

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 }

References XrdSecsssKT::ktEnt::Data, XrdSecsssKT::ktEnt::ktData::Exp, XrdSecsssKT::ktEnt::ktData::ID, XrdSysMutex::Lock(), XrdSecsssKT::ktEnt::ktData::Name, XrdSecsssKT::ktEnt::Next, and XrdSysMutex::UnLock().

Referenced by XrdSecProtocolsss::getCredentials().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ keyList()

ktEnt* XrdSecsssKT::keyList ( )
inline

Definition at line 101 of file XrdSecsssKT.hh.

101 {return ktList;}

Referenced by XrdSecsssAdmin_delKey(), XrdSecsssAdmin_insKey(), and XrdSecsssAdmin_lstKey().

+ Here is the caller graph for this function:

◆ Refresh()

void XrdSecsssKT::Refresh ( )

Definition at line 311 of file XrdSecsssKT.cc.

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 }

References eMsg, XrdOucErrInfo::getErrInfo(), XrdSysMutex::Lock(), XrdSecsssKT::ktEnt::Next, stat(), and XrdSysMutex::UnLock().

Referenced by XrdSecsssKTRefresh().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ RefrTime()

time_t XrdSecsssKT::RefrTime ( )
inline

Definition at line 105 of file XrdSecsssKT.hh.

105 {return ktRefT;}

Referenced by XrdSecsssKTRefresh().

+ Here is the caller graph for this function:

◆ Rewrite()

int XrdSecsssKT::Rewrite ( int  Keep,
int &  numKeys,
int &  numTot,
int &  numExp 
)

Definition at line 339 of file XrdSecsssKT.cc.

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 }
int unlink(const char *path)
int rename(const char *oldpath, const char *newpath)
ssize_t write(int fildes, const void *buf, size_t nbyte)
#define close(a)
Definition: XrdPosix.hh:43
#define ENODATA
Definition: XrdSecsssKT.cc:49
static int makePath(char *path, mode_t mode, bool reset=false)
Definition: XrdOucUtils.cc:917
void NUG(ktEnt *ktP)
Definition: XrdSecsssKT.hh:72

References close, XrdSecsssKT::ktEnt::ktData::Crt, XrdSecsssKT::ktEnt::Data, ENODATA, XrdSecsssKT::ktEnt::ktData::Exp, XrdSecsssKT::ktEnt::ktData::Flags, XrdSecsssKT::ktEnt::ktData::Grup, XrdSecsssKT::ktEnt::ktData::ID, XrdSecsssKT::ktEnt::ktData::Len, XrdOucUtils::makePath(), XrdSecsssKT::ktEnt::ktData::Name, XrdSecsssKT::ktEnt::Next, XrdSecsssKT::ktEnt::NUG(), open(), rename(), unlink(), XrdSecsssKT::ktEnt::ktData::User, and write().

Referenced by XrdSecsssAdmin_addKey(), XrdSecsssAdmin_delKey(), and XrdSecsssAdmin_insKey().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ Same()

int XrdSecsssKT::Same ( const char *  path)
inline

Definition at line 109 of file XrdSecsssKT.hh.

109 {return (ktPath && !strcmp(ktPath, path));}

Referenced by XrdSecProtocolsss::Init_Client().

+ Here is the caller graph for this function:

◆ setPath()

void XrdSecsssKT::setPath ( const char *  Path)
inline

Definition at line 111 of file XrdSecsssKT.hh.

112  {if (ktPath) free(ktPath); ktPath = strdup(Path);}
XrdOucString Path

References Path.

Referenced by XrdSecsssAdmin_insKey().

+ Here is the caller graph for this function:

The documentation for this class was generated from the following files: