/******************************************************************************/
/* */
/* X r d S e c L o a d S e c u r i t y . c c */
/* */
/* (c) 2014 by the Board of Trustees of the Leland Stanford, Jr., University */
/* 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 "XrdVersion.hh"
#include "XProtocol/XProtocol.hh"
#include "XrdOuc/XrdOucPinLoader.hh"
#include "XrdSec/XrdSecLoadSecurity.hh"
#include "XrdSec/XrdSecProtector.hh"
#include "XrdSys/XrdSysError.hh"
#include "XrdSys/XrdSysPlatform.hh"
#include "XrdSys/XrdSysPthread.hh"
/******************************************************************************/
/* G l o b a l s */
/******************************************************************************/
namespace
{
static XrdVERSIONINFODEF(myVersion, XrdSecLoader, XrdVNUMBER, XrdVERSION);
XrdSysMutex protMutex;
}
namespace XrdSecProtection
{
XrdSecProtector *theProtector = 0;
int protRC = 0;
}
/******************************************************************************/
/* P l u g */
/******************************************************************************/
namespace
{
int Plug(XrdOucPinLoader *piP, XrdSecGetProt_t *getP, XrdSecGetServ_t *ep)
{
// If we need to load the protocol factory do so now
//
if (getP && !(*getP=(XrdSecGetProt_t)piP->Resolve("XrdSecGetProtocol")))
return 1;
// If we do not need to load the security service we are done
//
if (!ep) return 0;
// Load the security service creator
//
if ((*ep = (XrdSecGetServ_t)piP->Resolve("XrdSecgetService"))) return 0;
// We failed this is eiter soft or hard depending on what else we loaded
//
return (getP ? -1 : 1);
}
}
/******************************************************************************/
/* Private: L o a d */
/******************************************************************************/
namespace
{
int Load( char *eBuff, int eBlen,
const char *cfn, const char *seclib,
XrdSecGetProt_t *getP, XrdSecService **secP=0,
XrdSysError *eDest=0)
{
XrdSecGetServ_t ep;
XrdOucPinLoader *piP;
const char *mySecLib = "libXrdSec.so";
int rc;
// Check for default path
//
if (!seclib) seclib = mySecLib;
// Get a plugin loader object
//
if (eDest) piP = new XrdOucPinLoader(eDest,
&myVersion, "seclib", seclib);
else piP = new XrdOucPinLoader(eBuff, eBlen,
&myVersion, "seclib", seclib);
// Load the appropriate pointers and get required objects.
//
rc = Plug(piP, getP, &ep);
if (rc == 0)
{if (secP && !(*secP = (*ep)(eDest->logger(), cfn))) rc = 1;
if (!rc) {delete piP; return 0;}
}
// We failed, so bail out
//
if (eDest)
eDest->Say("Config ","Unable to create security framework via ", seclib);
piP->Unload(true);
return 1;
}
}
/******************************************************************************/
namespace
{
int Load( char *eBuff, int eBlen,
const char *protlib, XrdSysError *eDest=0)
{
XrdSecProtector **protPP;
XrdOucPinLoader *piP;
const char *myProtLib = "libXrdSecProt.so";
// Check for default path
//
if (!protlib) protlib = myProtLib;
// Get a plugin loader object
//
if (eDest) piP = new XrdOucPinLoader(eDest,
&myVersion, "protlib", protlib);
else piP = new XrdOucPinLoader(eBuff, eBlen,
&myVersion, "protlib", protlib);
// Get the protection object which also is a factory object.
//
protPP = (XrdSecProtector **)piP->Resolve("XrdSecProtObjectP");
if (protPP)
{XrdSecProtection::theProtector = *protPP;
delete piP;
return 0;
}
return 1;
// We failed, so bail out
//
if (eDest)
eDest->Say("Config ","Unable to create protection framework via ",protlib);
piP->Unload(true);
return ENOENT;
}
}
/******************************************************************************/
/* X r d S e c L o a d F a c t o r y */
/******************************************************************************/
XrdSecGetProt_t XrdSecLoadSecFactory(char *eBuff, int eBlen, const char *seclib)
{
XrdSecGetProt_t getP;
int rc;
// Load required plugin nd obtain pointers
//
rc = Load(eBuff, eBlen, 0, seclib, &getP);
if (!rc) return getP;
// Issue correct error message, if any
//
if (!seclib) seclib = "default";
if (rc < 0)
snprintf(eBuff, eBlen,
"Unable to create security framework via %s; invalid path.",
seclib);
else if (!(*eBuff))
snprintf(eBuff, eBlen,
"Unable to create security framework via %s", seclib);
return 0;
}
/******************************************************************************/
/* X r d S e c G e t P r o t e c t i o n */
/******************************************************************************/
// This is used client-side only
int XrdSecGetProtection(XrdSecProtect *&protP,
XrdSecProtocol &aprot,
ServerResponseBody_Protocol &resp,
unsigned int resplen)
{
static const unsigned int hdrLen = sizeof(ServerResponseReqs_Protocol) - 2;
static const unsigned int minLen = kXR_ShortProtRespLen + hdrLen;
XrdSecProtector *pObj;
unsigned int vLen;
int rc;
// First validate the response before passing it to anyone
//
protP = 0;
if (resplen <= kXR_ShortProtRespLen) return 0;
if (resplen < minLen) return -EINVAL;
vLen = static_cast(resp.secreq.secvsz)
* sizeof(ServerResponseSVec_Protocol);
if (vLen + minLen > resplen) return -EINVAL;
// Our first step is to see if any protection is required
//
if (vLen == 0 && resp.secreq.seclvl == kXR_secNone) return 0;
// The next step is to see if we have a protector object. If we do not then
// we need to load the library that provides such objects. This needs to be
// MT-safe as it may be called at any time by any thread.
//
protMutex.Lock();
if (!(pObj = XrdSecProtection::theProtector))
{if (!XrdSecProtection::protRC)
{char eBuff[2048];
if ((XrdSecProtection::protRC = Load(eBuff, sizeof(eBuff), 0)))
std::cerr <<"SecLoad: " <New4Client(aprot, resp.secreq, resplen-kXR_ShortProtRespLen);
return (protP ? 1 : 0);
}
/******************************************************************************/
/* X r d S e c L o a d P r o t e c t i o n */
/******************************************************************************/
// This is a one-time server-side call
XrdSecProtector *XrdSecLoadProtection(XrdSysError &erP)
{
// Load the protection object. This is done in the main thread do no mutex
//
XrdSecProtection::protRC = Load(0, 0, 0, &erP);
// All done, return result
//
return (XrdSecProtection::protRC ? 0 : XrdSecProtection::theProtector);
}
/******************************************************************************/
/* X r d S e c L o a d S e c S e r v i c e */
/******************************************************************************/
XrdSecService *XrdSecLoadSecService(XrdSysError *eDest,
const char *cfn,
const char *seclib,
XrdSecGetProt_t *getP,
XrdSecProtector**proP)
{
XrdSecService *CIA;
// Load required plugin nd obtain pointers
//
if (Load(0, 0, cfn, seclib, getP, &CIA, eDest)) return 0;
// Set the protectorobject. Note that the securityservice will load it if
// is needed and we will havecaptured its pointer. This sort of a hack but
// we can't change the SecService object as it is a public interface.
//
if (proP) *proP = XrdSecProtection::theProtector;
return CIA;
}