/******************************************************************************/
/* */
/* X r d O f s T P C A u t h . c c */
/* */
/* (c) 2012 by the Board of Trustees of the Leland Stanford, Jr., University */
/* All Rights Reserved */
/* Produced by Andrew Hanushevsky for Stanford University under contract */
/* DE-AC02-76-SFO0515 with the Department of Energy */
/* */
/* This file is part of the XRootD software suite. */
/* */
/* XRootD is free software: you can redistribute it and/or modify it under */
/* the terms of the GNU Lesser General Public License as published by the */
/* Free Software Foundation, either version 3 of the License, or (at your */
/* option) any later version. */
/* */
/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
/* COPYING (GPL license). If not, see . */
/* */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without */
/* specific prior written permission of the institution or contributor. */
/******************************************************************************/
#include
#include
#include
#include "XrdOfs/XrdOfsStats.hh"
#include "XrdOfs/XrdOfsTPCAuth.hh"
#include "XrdOuc/XrdOucCallBack.hh"
#include "XrdSfs/XrdSfsInterface.hh"
#include "XrdSys/XrdSysError.hh"
#include "XrdSys/XrdSysTimer.hh"
/******************************************************************************/
/* G l o b a l O b j e c t s */
/******************************************************************************/
extern XrdSysError OfsEroute;
extern XrdOfsStats OfsStats;
/******************************************************************************/
/* S t a t i c V a r i a b l e s */
/******************************************************************************/
XrdSysMutex XrdOfsTPCAuth::authMutex;
XrdOfsTPCAuth *XrdOfsTPCAuth::authQ = 0;
/******************************************************************************/
/* E x t e r n a l L i n k a g e s */
/******************************************************************************/
void *XrdOfsTPCAuthttl(void *pp)
{
XrdOfsTPCAuth::RunTTL(0);
return (void *)0;
}
/******************************************************************************/
/* A d d */
/******************************************************************************/
int XrdOfsTPCAuth::Add(XrdOfsTPC::Facts &Args)
{
XrdOfsTPCAuth *aP;
const char *eMsg;
char Buff[512];
// Generate the origin information
//
if (!genOrg(Args.Usr, Buff, sizeof(Buff))) return Fatal(Args, Buff, EINVAL);
Args.Org = Buff;
// Check if there is a matching authorization in the queue. If this is for a
// pending authorization, indicated that we now have one. Otherwise, consider
// this a potential security breach and cancel both autorizations.
//
authMutex.Lock();
if ((aP = Find(Args)))
{if (aP->Info.cbP)
{aP->expT = expT;
aP->Next = authQ; authQ = aP;
aP->Info.Reply(SFS_OK, 0, "", &authMutex);
return 1;
} else {
authMutex.UnLock();
return Fatal(Args, "duplicate athorization", EPROTO);
}
}
// Set the copy authorization information
//
if ((eMsg = Info.Set(Args.Key, Buff, Args.Lfn, Args.Dst)))
{
authMutex.UnLock();
return Fatal(Args, eMsg, EINVAL);
}
// Add this to queue
//
Next = authQ; authQ = this; inQ = 1;
// All done
//
authMutex.UnLock();
return 1;
}
/******************************************************************************/
/* D e l */
/******************************************************************************/
void XrdOfsTPCAuth::Del()
{
XrdOfsTPCAuth *pP;
// Remove from queue if we are still in the queue
//
authMutex.Lock();
if (inQ)
{if (this == authQ) authQ = Next;
else {pP = authQ;
while(pP && pP->Next != this) pP = pP->Next;
if (pP) pP->Next = Next;
}
inQ = 0;
}
// Delete the element if possible
//
if (Refs <= 1) delete this;
else Refs--;
authMutex.UnLock();
}
/******************************************************************************/
/* E x p i r e d */
/******************************************************************************/
int XrdOfsTPCAuth::Expired(const char *Dst, int cnt)
{
char Buff[1024];
// If there is a callback, tell the client they are no longer wanted
//
if (Info.cbP) Info.Reply(SFS_ERROR, EACCES, "tpc authorization expired");
// Log this event
//
snprintf(Buff, sizeof(Buff), "tpc grant by %s expired for", Info.Org);
Buff[sizeof(Buff)-1] = 0;
OfsEroute.Emsg("TPC", Dst, Buff, Info.Lfn);
// Count stats and return
//
if (cnt) OfsStats.Add(OfsStats.Data.numTPCexpr);
return 0;
}
/******************************************************************************/
/* Private: F i n d */
/******************************************************************************/
XrdOfsTPCAuth *XrdOfsTPCAuth::Find(XrdOfsTPC::Facts &Args)
{
XrdOfsTPCAuth *cP, *pP = 0;
// Find matching entry
//
cP = authQ;
while(cP && !(cP->Info.Match(Args.Key, Args.Org, Args.Lfn, Args.Dst)))
{pP = cP; cP = cP->Next;}
// Remove from queue if found
//
if (cP) {if (pP) pP->Next = cP->Next;
else authQ = cP->Next;
cP->inQ = 0;
}
// Return result
//
return cP;
}
/******************************************************************************/
/* G e t */
/******************************************************************************/
int XrdOfsTPCAuth::Get(XrdOfsTPC::Facts &Args, XrdOfsTPCAuth **theTPC)
{
XrdSysMutexHelper authMon(&authMutex);
XrdOfsTPCAuth *aP;
const char *eMsg;
// Check if there is a matching authorization in the queue. If this is for a
// pending authorization, then consider this a potential security breach and
// cancel both requests. Otherwise, indicate that authorization is present.
//
if ((aP = Find(Args)))
{if (aP->Info.cbP)
{aP->Info.Reply(SFS_ERROR, EPROTO, "duplicate tpc auth request");
return Fatal(Args, "duplicate tpc auth request", EPROTO);
} else {
aP->Refs++;
*theTPC = aP;
return SFS_OK;
}
}
// Add this request as a pending authorization to the queue
//
if (!(aP = new XrdOfsTPCAuth(maxTTL)))
return Fatal(Args, "insufficient memory", ENOMEM);
// Set the copy authorization information
//
if ((eMsg = aP->Info.Set(Args.Key, Args.Org, Args.Lfn, Args.Dst)))
{delete aP;
return Fatal(Args, eMsg, EINVAL);
}
// Create a callback
//
if (aP->Info.SetCB(Args.eRR)) {delete aP; return SFS_ERROR;}
// Add it to the queue
//
aP->Next = authQ; authQ = aP;
// Return result
//
*theTPC = aP;
aP->Refs = 0;
aP->Info.Engage();
return SFS_STARTED;
}
/******************************************************************************/
/* R u n T T L */
/******************************************************************************/
int XrdOfsTPCAuth::RunTTL(int Init)
{
XrdOfsTPCAuth *cP, *pP, *nP;
time_t eNow;
int eWait, eDiff, numExp;
// Start the expiration thread
//
if (Init)
{pthread_t tid;
int rc;
if ((rc = XrdSysThread::Run(&tid,XrdOfsTPCAuthttl,0,0,"TPC ttl runner")))
OfsEroute.Emsg("TPC", rc, "create tpc ttl runner thread");
return (rc ? 0 : 1);
}
// Find all expired entries and remove them
//
do{authMutex.Lock();
cP = authQ; pP = 0;
eNow = time(0); eWait = maxTTL; numExp = 0;
while(cP)
{if (eNow < cP->expT)
{eDiff = cP->expT - eNow;
if (eDiff < eWait) eWait = eDiff;
pP = cP; cP = cP->Next;
}
else {if (pP) pP->Next = cP->Next;
else authQ = cP->Next;
cP->Expired("localhost", 0); numExp++;
nP = cP->Next;
if (cP->Refs < 1) delete cP;
cP = nP;
}
}
authMutex.UnLock();
// Add number of expirations to statistics
//
if (numExp)
{OfsStats.sdMutex.Lock();
OfsStats.Data.numTPCexpr += numExp;
OfsStats.sdMutex.UnLock();
}
// Wait as long as possible for a recan
//
XrdSysTimer::Snooze(eWait);
} while(1);
}