/******************************************************************************/
/* */
/* X r d S e c P r o t e c t o r . c c */
/* */
/* (c) 2016 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
#include
#include
#include "XrdVersion.hh"
#include "XrdNet/XrdNetIF.hh"
#include "XrdSec/XrdSecInterface.hh"
#include "XrdSec/XrdSecProtect.hh"
#include "XrdSec/XrdSecProtector.hh"
#include "XrdSys/XrdSysError.hh"
/******************************************************************************/
/* L i b r a r y L i n k a g e */
/******************************************************************************/
namespace
{
class protoProtector : public XrdSecProtector
{
public:
protoProtector() {}
~protoProtector() {}
};
protoProtector baseProtector;
}
XrdSecProtector *XrdSecProtObjectP = &baseProtector;
XrdVERSIONINFO(XrdSecProtObjectP,"secProt");
/******************************************************************************/
/* S e r v e r - S i d e C o n f i g u r a t i o n */
/******************************************************************************/
namespace
{
struct ProtInfo {XrdSecProtect *theProt;
ServerResponseReqs_Protocol reqs;
bool relaxed;
bool force;
ProtInfo() : theProt(0), relaxed(false), force(false)
{reqs.theTag = 'S';
reqs.rsvd = 0;
reqs.secver = kXR_secver_0;
reqs.secopt = 0;
reqs.seclvl = kXR_secNone;
reqs.secvsz = 0;
}
} lrTab[XrdSecProtector::isLR];
bool lrSame = true;
bool noProt = true;
}
/******************************************************************************/
/* S e r v e r - S i d e E r r o r M e s s a g e R o u t i n g */
/******************************************************************************/
namespace
{
XrdSysError Say(0, "sec_");
}
/******************************************************************************/
/* C o n f i g */
/******************************************************************************/
bool XrdSecProtector::Config(const XrdSecProtectParms &lclParms,
const XrdSecProtectParms &rmtParms,
XrdSysLogger &logr)
{
// Set the logger right off
//
Say.logger(&logr);
// Setup local protection
//
if (lclParms.level != XrdSecProtectParms::secNone)
{Config(lclParms, lrTab[isLcl].reqs);
lrTab[isLcl].theProt = new XrdSecProtect;
lrTab[isLcl].theProt->SetProtection(lrTab[isLcl].reqs);
}
// Setup remote protection (check for reuse of local protection)
//
if (rmtParms.level == lclParms.level)
{lrTab[isRmt] = lrTab[isLcl];
lrSame = true;
} else {
lrSame = false;
if (rmtParms.level != XrdSecProtectParms::secNone)
{Config(rmtParms, lrTab[isRmt].reqs);
lrTab[isRmt].theProt = new XrdSecProtect;
lrTab[isRmt].theProt->SetProtection(lrTab[isRmt].reqs);
}
}
// Record relax flags
//
lrTab[isLcl].relaxed = (lclParms.opts & XrdSecProtectParms::relax) != 0;
lrTab[isLcl].force = (lclParms.opts & XrdSecProtectParms::force) != 0;
lrTab[isRmt].relaxed = (rmtParms.opts & XrdSecProtectParms::relax) != 0;
lrTab[isRmt].force = (rmtParms.opts & XrdSecProtectParms::force) != 0;
// Setup shortcut flag
//
noProt = (lrTab[isLcl].theProt == 0) && (lrTab[isRmt].theProt == 0);
// All done
//
return true;
}
/******************************************************************************/
void XrdSecProtector::Config(const XrdSecProtectParms &parms,
ServerResponseReqs_Protocol &reqs)
{
unsigned int lvl;
// Setup options
//
if ((parms.opts & XrdSecProtectParms::doData) != 0)
reqs.secopt |= kXR_secOData;
if ((parms.opts & XrdSecProtectParms::force) != 0)
reqs.secopt |= kXR_secOFrce;
// Setup level
//
switch(parms.level)
{case XrdSecProtectParms::secCompatible: lvl = kXR_secCompatible;
break;
case XrdSecProtectParms::secStandard: lvl = kXR_secStandard;
break;
case XrdSecProtectParms::secIntense: lvl = kXR_secIntense;
break;
case XrdSecProtectParms::secPedantic: lvl = kXR_secPedantic;
break;
default: lvl = kXR_secNone;
break;
}
reqs.seclvl = lvl;
}
/******************************************************************************/
/* L N a m e */
/******************************************************************************/
const char *XrdSecProtector::LName(XrdSecProtectParms::secLevel level)
{
static const char *lvlVec[] = {"none", "compatible", "standard",
"intense", "pedantic"};
// Validate the level
//
if (level < XrdSecProtectParms::secNone) level = XrdSecProtectParms::secNone;
else if (level > XrdSecProtectParms::secPedantic)
level = XrdSecProtectParms::secPedantic;
// Return the level name
//
return lvlVec[level];
}
/******************************************************************************/
/* N e w 4 C l i e n t */
/******************************************************************************/
XrdSecProtect *XrdSecProtector::New4Client(XrdSecProtocol &aprot,
const ServerResponseReqs_Protocol &inReqs,
unsigned int reqLen)
{
static const unsigned int hdrLen = sizeof(ServerResponseBody_Protocol)
- sizeof(ServerResponseSVec_Protocol);
XrdSecProtect *secP;
unsigned int vLen = static_cast(inReqs.secvsz)
* sizeof(ServerResponseSVec_Protocol);
bool okED;
// Validate the incomming struct (if it's bad skip the security) and that any
// security is actually wanted.
//
if (vLen+hdrLen > reqLen
|| (inReqs.secvsz == 0 && inReqs.seclvl == kXR_secNone)) return 0;
// If the auth protocol doesn't support encryption, see if we still need to
// send off signed requests (mostly for testng)
//
okED = aprot.getKey() > 0;
if (!okED && (inReqs.secopt & kXR_secOFrce) == 0) return 0;
// Get a new security object and set its security level
//
secP = new XrdSecProtect(&aprot, okED);
secP->SetProtection(inReqs);
// All done
//
return secP;
}
/******************************************************************************/
/* N e w 4 S e r v e r */
/******************************************************************************/
XrdSecProtect *XrdSecProtector::New4Server(XrdSecProtocol &aprot, int plvl)
{
static const char *wFrc = "authentication can't encrypt; "
"continuing without it!";
static const char *wIgn = "authentication can't encrypt; "
"allowing unsigned requests!";
XrdSecProtect *secP;
lrType theLR;
bool okED;
// Check if we need any security at all
//
if (noProt) return 0;
// Now we need to see whether this is local or remote of if it matters
//
if (lrSame) theLR = isLcl;
else theLR = (XrdNetIF::InDomain(aprot.Entity.addrInfo) ? isLcl : isRmt);
// Now check again, as may not need any protection for the domain
//
if (lrTab[theLR].theProt == 0) return 0;
// Check for relaxed processing
//
if (plvl < kXR_PROTSIGNVERSION && lrTab[theLR].relaxed) return 0;
// Check if protocol supports encryption
//
okED = aprot.getKey() > 0;
if (!okED)
{char pName[XrdSecPROTOIDSIZE+1];
const char *action;
strncpy(pName, aprot.Entity.prot, XrdSecPROTOIDSIZE);
pName[XrdSecPROTOIDSIZE] = 0;
action = (lrTab[theLR].force ? wFrc : wIgn);
Say.Emsg("Protect", aprot.Entity.tident, pName, action);
if (!lrTab[theLR].force) return 0;
}
// Get a new security object and make it a clone of this right one
//
secP = new XrdSecProtect(&aprot, *lrTab[theLR].theProt, okED);
// All done
//
return secP;
}
/******************************************************************************/
/* P r o t R e s p */
/******************************************************************************/
int XrdSecProtector::ProtResp(ServerResponseReqs_Protocol &resp,
XrdNetAddrInfo &nai, int pver)
{
static const int rsplen = sizeof(ServerResponseReqs_Protocol)
- sizeof(ServerResponseSVec_Protocol);
ServerResponseReqs_Protocol *myResp;
// Check if we need any response at all
//
if (noProt) return 0;
// Get the right response
//
if (lrSame || XrdNetIF::InDomain(&nai)) myResp = &lrTab[isLcl].reqs;
else myResp = &lrTab[isRmt].reqs;
// Return result
//
memcpy(&resp, myResp, rsplen);
return rsplen;
}