diff --git a/src/XProtocol/XProtocol.cc b/src/XProtocol/XProtocol.cc index 51961db07fa..90fa9342cc8 100644 --- a/src/XProtocol/XProtocol.cc +++ b/src/XProtocol/XProtocol.cc @@ -55,6 +55,9 @@ #include #include #include +#include +#include +#include #include "XProtocol/XProtocol.hh" diff --git a/src/XProtocol/XProtocol.hh b/src/XProtocol/XProtocol.hh index 686280a89ac..dee4c45a944 100644 --- a/src/XProtocol/XProtocol.hh +++ b/src/XProtocol/XProtocol.hh @@ -960,6 +960,8 @@ struct ALIGN_CHECK {char chkszreq[25-sizeof(ClientRequest)]; #ifndef ENOATTR #define ENOATTR ENODATA #endif + +struct stat; class XProtocol { @@ -1035,5 +1037,6 @@ static int toErrno( int xerr ) static const char *errName(kXR_int32 errCode); static const char *reqName(kXR_unt16 reqCode); -}; + +}; // XProtocol #endif diff --git a/src/XrdCms/XrdCmsReq.cc b/src/XrdCms/XrdCmsReq.cc deleted file mode 100644 index 4985abf71e6..00000000000 --- a/src/XrdCms/XrdCmsReq.cc +++ /dev/null @@ -1,424 +0,0 @@ -/******************************************************************************/ -/* */ -/* X r d C m s R e q . c c */ -/* */ -/* (c) 2006 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 -#include -#include -#include - -#include "XrdCms/XrdCmsNode.hh" -#include "XrdCms/XrdCmsReq.hh" -#include "XrdCms/XrdCmsRRQ.hh" -#include "XrdCms/XrdCmsRTable.hh" -#include "XrdCms/XrdCmsTrace.hh" -#include "XrdSys/XrdSysError.hh" -#include "XrdSys/XrdSysPlatform.hh" -#include "XrdSys/XrdSysPthread.hh" - -#include "XProtocol/XProtocol.hh" -#include "XProtocol/YProtocol.hh" - -using namespace XrdCms; - -/******************************************************************************/ -/* C o n s t r u c t o r # 1 */ -/******************************************************************************/ - -XrdCmsReq::XrdCmsReq(XrdCmsNode *nP, unsigned int reqid, char adv) -{ - NodeP = nP; - ReqID = reqid; - ReqNnum = nP->getSlot(); - ReqNins = nP->Inst(); - ReqAdv = adv; -} - -/******************************************************************************/ -/* C o n s t r u c t o r # 2 */ -/******************************************************************************/ - -XrdCmsReq::XrdCmsReq(XrdCmsReq *Req, unsigned int rn) -{ - NodeP = 0; - ReqID = rn; - ReqNnum = Req->ReqNnum; - ReqNins = Req->ReqNins; - ReqAdv = 0; -} - -/******************************************************************************/ -/* R e p l y _ E r r o r */ -/******************************************************************************/ - -void XrdCmsReq::Reply_Error(const char *emsg, int elen) -{ - -// Make sure that elen includes a null byte -// - if (!elen) elen = strlen(emsg)+1; - else if (emsg[elen]) elen++; - -// Send off the reply -// - Reply(kYR_error, kYR_EINVAL, emsg, elen); -} - -/******************************************************************************/ -/* R e p l y _ E r r o r */ -/******************************************************************************/ - -void XrdCmsReq::Reply_Error(const char *ecode, const char *emsg, int elen) -{ - unsigned int eval; - -// Translate the error name -// - if (!strcmp("ENOENT", ecode)) eval = kYR_ENOENT; - else if (!strcmp("EPERM", ecode)) eval = kYR_EPERM; - else if (!strcmp("EACCES", ecode)) eval = kYR_EACCES; - else if (!strcmp("EIO", ecode)) eval = kYR_EIO; - else if (!strcmp("ENOMEM", ecode)) eval = kYR_ENOMEM; - else if (!strcmp("ENOSPC", ecode)) eval = kYR_ENOSPC; - else if (!strcmp("ENAMETOOLONG", ecode)) eval = kYR_ENAMETOOLONG; - else if (!strcmp("ENETUNREACH", ecode)) eval = kYR_ENETUNREACH; - else if (!strcmp("ENOTBLK", ecode)) eval = kYR_ENOTBLK; - else if (!strcmp("EISDIR", ecode)) eval = kYR_EISDIR; - else eval = kYR_EINVAL; - -// Make sure that elen includes a null byte -// - if (!elen) elen = strlen(emsg)+1; - else if (emsg[elen]) elen++; - -// Send off the reply -// - Reply(kYR_error, eval, emsg, elen); -} - -/******************************************************************************/ - -void XrdCmsReq::Reply_Error(int ecode, const char *emsg, int elen) -{ - unsigned int eval; - -// Translate the error name -// - switch(ecode) - {case ENOENT: eval = kYR_ENOENT; - break; - case EPERM: eval = kYR_EPERM; - break; - case EACCES: eval = kYR_EACCES; - break; - case EIO: eval = kYR_EIO; - break; - case ENOMEM: eval = kYR_ENOMEM; - break; - case ENOSPC: eval = kYR_ENOSPC; - break; - case ENAMETOOLONG: eval = kYR_ENAMETOOLONG; - break; - case ENETUNREACH: eval = kYR_ENETUNREACH; - break; - case ENOTBLK: eval = kYR_ENOTBLK; - break; - case EISDIR: eval = kYR_EISDIR; - break; - default: eval = kYR_EINVAL; - break; - }; - -// Make sure that elen includes a null byte -// - if (!elen) elen = strlen(emsg)+1; - else if (emsg[elen]) elen++; - -// Send off the reply -// - Reply(kYR_error, eval, emsg, elen); -} - -/******************************************************************************/ -/* R e p l y _ O K */ -/******************************************************************************/ - -void XrdCmsReq::Reply_OK() -{ - -// Send off the reply (this object may be deleted so make a fast exit) -// - Reply(kYR_data, 0, "", 1); -} - -/******************************************************************************/ - -void XrdCmsReq::Reply_OK(const char *data, int dlen) -{ - -// Make sure that elen includes a null byte -// - if (!dlen) dlen = strlen(data)+1; - else if (data[dlen]) dlen++; - -// Send off the reply (this object may be deleted so make a fast exit) -// - Reply(kYR_data, 0, data, dlen); -} - -/******************************************************************************/ - -void XrdCmsReq::Reply_OK(struct stat &buf) -{ - char sbuff[256]; - - Reply_OK(sbuff, StatGen(buf, sbuff)); -} - -/******************************************************************************/ -/* R e p l y _ R e d i r e c t */ -/******************************************************************************/ - -void XrdCmsReq::Reply_Redirect(const char *sname, - const char *lcgi, const char *ocgi) -{ - char hbuff[256], *colon; - const char *hP = hbuff; - int hlen, Port; - -// Find the port number in the host name -// - if (!(colon = (char *) index(sname, ':'))) - {Port = 0; - hP = sname; - } else { - Port = atoi(colon+1); - hlen = colon-sname+1; - if (hlen >= (int)sizeof(hbuff)) hlen = sizeof(hbuff); - strlcpy(hbuff, sname, hlen); - } - -// Send off the request -// - Reply_Redirect(hP, Port, lcgi, ocgi); -} - -/******************************************************************************/ - -void XrdCmsReq::Reply_Redirect(const char *sname, int Port, - const char *lcgi, const char *ocgi) -{ - struct iovec iov[8]; - int iovnum, hlen = strlen(sname); - -// Fill out the iovec -// - iov[1].iov_base = (char *)sname; - iov[1].iov_len = strlen(sname); - hlen = iov[1].iov_len; - -// Now we need to see if we have any cgi info to pass -// - if (!lcgi && !ocgi) iovnum = 2; - else {if (ocgi) - {iov[2].iov_base = (char *)"?"; - iov[2].iov_len = 1; - iov[3].iov_base = (char *)ocgi; - iov[3].iov_len = strlen(ocgi); - hlen += iov[3].iov_len + 1; - if (lcgi) - {iov[4].iov_base = (char *)"?"; - iov[4].iov_len = 1; - iov[5].iov_base = (char *)lcgi; - iov[5].iov_len = strlen(lcgi); - hlen += iov[5].iov_len + 1; - iovnum = 6; - } else iovnum = 4; - } else { - iov[2].iov_base = (char *)"??"; - iov[2].iov_len = 2; - iov[3].iov_base = (char *)lcgi; - iov[3].iov_len = strlen(lcgi); - hlen += iov[3].iov_len + 2; - iovnum = 4; - } - } - -// Make sure that last iov element and hlen includes the terminating null byte -// - iov[iovnum-1].iov_len++; hlen++; - -// Send off the reply -// - Reply(kYR_redirect, (unsigned int)Port, 0, hlen, iov, iovnum); -} - -/******************************************************************************/ -/* R e p l y _ W a i t */ -/******************************************************************************/ - -void XrdCmsReq::Reply_Wait(int sec) -{ - -// Send off the reply -// - Reply(kYR_wait, (unsigned int)sec, "", 1); -} - -/******************************************************************************/ -/* R e p l y _ W a i t R e s p */ -/******************************************************************************/ - -XrdCmsReq *XrdCmsReq::Reply_WaitResp(int sec) -{ - static XrdSysMutex rnMutex; - static unsigned int RequestNum = 0; - unsigned int rnum; - XrdCmsReq *newReq; - -// If this is already a waitresp object then we cannot do this again. So, -// just return a null pointer indicating an invalid call. -// - if (!NodeP) return (XrdCmsReq *)0; - -// Generate a request number unless no reply is needed -// - if (ReqID) - {rnMutex.Lock(); - RequestNum++; - rnum = RequestNum; - rnMutex.UnLock(); - } else rnum = 0; - -// Construct a new request object. This object will be used to actually effect -// the reply. We need to do this because the server may disappear before we -// actually reply. In which case the reply gets deep-sixed. -// - newReq = new XrdCmsReq(this, rnum); - -// Reply to the requestor mapping our ID to their ID -// - if (rnum) - { - Reply(kYR_waitresp, rnum); - } - -// Return an object to affect an asynchronous reply -// - return newReq; -} - -/******************************************************************************/ -/* P r i v a t e M e t h o d s */ -/******************************************************************************/ - -#define XRDXROOTD_STAT_CLASSNAME XrdCmsReq -#include "XrdXrootd/XrdXrootdStat.icc" - -/******************************************************************************/ -/* n o R e p l y */ -/******************************************************************************/ - -void XrdCmsReq::noReply() -{ - static int nrNum = 255; - -// We always issue a message about double object use otherwise issue warning -// as this is indicative of an improper configuration. -// - if (ReqNnum < 0) - Say.Emsg("Req", "Attempted reply to twice to a 2way async request."); - else {nrNum++; - if (!(nrNum & 255)) Say.Emsg("Req", - "Attempted reply to a 1way request; " - "probably incorrect ofs forward directive."); - } -} - -/******************************************************************************/ -/* R e p l y */ -/******************************************************************************/ - -void XrdCmsReq::Reply( int respCode, unsigned int respVal, - const char *respData, int respLen, - struct iovec *iov, int iovnum) -{ - EPNAME("Reply"); - CmsResponse Resp = {{ReqID, (kXR_char)respCode, 0, 0}, htonl(respVal)}; - struct iovec myiov[2], *iovP; - XrdCmsNode *nP; - -// Set the actual data length -// - Resp.Hdr.datalen = htons(static_cast(respLen+sizeof(int))); - -// Complete iovec -// - if (iov) - { iov->iov_base = (char *)&Resp; - iov->iov_len = sizeof(Resp); - iovP = iov; - } else { - myiov[0].iov_base = (char *)&Resp; - myiov[0].iov_len = sizeof(Resp); - if (respData) - {myiov[1].iov_base = (char *)respData; - myiov[1].iov_len = respLen; - iovnum = 2; - } else iovnum = 1; - iovP = myiov; - } - -// Reply format differs depending on whether this is a sync or async reply -// - if (NodeP) - {if (ReqID) NodeP->Send(iovP, iovnum); - else noReply(); - return; - } - -// Async replies are more complicated here since we must find the server using -// a logical address that may no longer be valid. -// - RTable.Lock(); - if ((nP = RTable.Find(ReqNnum, ReqNins))) - {Resp.Hdr.modifier |= CmsResponse::kYR_async; - nP->Send(iovP, iovnum); - } - else {DEBUG("Async resp " <. */ -/* */ -/* 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. */ -/******************************************************************************/ - -class XrdCmsRRQInfo; -class XrdCmsNode; -struct stat; - -class XrdCmsReq -{ -public: - -// Use this to determine if the call is advisory in nature -// -inline int Advisory() {return ReqAdv;} - -// Reply with an eror message to the request. An optional length may be given. -// -void Reply_Error(const char *emsg, int emsglen = 0); - -// Reply with an error code and an error message to the request. The error -// is a string corresponding to an errno.h error code symbol. Valid names are: -// ENOENT, EPERM, EACCES, EIO, ENOMEM, ENOSPC, ENAMETOOLONG, ENETUNREACH, -// ENOTBLK, EISDIR, and ENOTEMPTY. Any other strings are converted to EINVAL. -// This mechanism supports cross platform error number delivery. The second -// takes the errno.h error number directly. -// -void Reply_Error(const char *ecode, const char *emsg, int emsglen = 0); - -void Reply_Error(int ecode, const char *emsg, int emsglen = 0); - -// Reply by telling the client everything was successfully completed. No data -// is to be sent (do not use Reply_OK() with a data length of zero). -// -void Reply_OK(); - -// Reply with success and an ASCII text message to the request. An optional data -// length may be given. -// -void Reply_OK(const char *data, int datalen = 0); - -// Reply with with success along with file stat information -// -void Reply_OK(struct stat &buf); - -// Reply by redirecting the client to a different server -// -void Reply_Redirect(const char *sname, // DNS name:port of server - const char *logincgi=0, // CGI tokens for login - const char *opencgi=0); // CGI tokens for open - -void Reply_Redirect(const char *sname, // DNS name of server - int port, // Server port number - const char *logincgi=0, // CGI tokens for login - const char *opencgi=0); // CGI tokens for open - -// Reply by forcing the client to wait the indicated number of seconds -// -void Reply_Wait(int sec); - -// Reply by telling the client to wait up to "sec" seconds for a response. This -// method returns a new XrdCmsReq object that must be used to actually provide -// the final response. It is automatically deleted when any Reply_xxx() method -// is called since the object is only valid for a single reply. -// -XrdCmsReq *Reply_WaitResp(int sec=0); - - XrdCmsReq(XrdCmsNode *nP, unsigned int id, char adv=0); - XrdCmsReq(XrdCmsReq *rP, unsigned int rn); - ~XrdCmsReq() {} - -private: - -int StatGen(struct stat &sbuf, char *xbuf); -void noReply(); -void Reply(int respCode, unsigned int respVal, const char *respData=0, - int respLen=0, struct iovec *iov=0, int iovnum=0); - -XrdCmsNode *NodeP; -unsigned int ReqID; -int ReqNins; // Node instance -short ReqNnum; // Node number -char ReqAdv; -}; -#endif diff --git a/src/XrdOuc/XrdOucUtils.cc b/src/XrdOuc/XrdOucUtils.cc index f01c24e4087..6fd860c1992 100644 --- a/src/XrdOuc/XrdOucUtils.cc +++ b/src/XrdOuc/XrdOucUtils.cc @@ -42,13 +42,67 @@ #include #include #endif +#include #include "XrdNet/XrdNetUtils.hh" #include "XrdOuc/XrdOucEnv.hh" #include "XrdOuc/XrdOucUtils.hh" #include "XrdSys/XrdSysError.hh" #include "XrdSys/XrdSysPlatform.hh" +#include "XrdSys/XrdSysPthread.hh" #include "XrdOuc/XrdOucStream.hh" +/******************************************************************************/ +/* L o c a l M e t h o d s */ +/******************************************************************************/ + +namespace +{ +struct idInfo +{ time_t Expr; + char *Name; + + idInfo(const char *name, time_t keep) + : Expr(time(0)+keep), Name(strdup(name)) {} + ~idInfo() {free(Name);} +}; + +typedef std::map idMap_t; + +idMap_t gidMap; +idMap_t uidMap; +XrdSysMutex idMutex; + +void AddID(idMap_t &idMap, unsigned int id, const char *name, time_t keepT) +{ + std::pair ret; + idInfo *infoP = new idInfo(name, keepT); + + idMutex.Lock(); + ret = idMap.insert(std::pair(id, infoP)); + if (ret.second == false) delete infoP; + idMutex.UnLock(); +} + +int LookUp(idMap_t &idMap, unsigned int id, char *buff, int blen) +{ + idMap_t::iterator it; + int luRet = 0; + + idMutex.Lock(); + it = idMap.find(id); + if (it != idMap.end()) + {if (it->second->Expr <= time(0)) + {delete it->second; + idMap.erase(it); + } else { + if (blen > 0) luRet = snprintf(buff, blen, it->second->Name); + } + } + idMutex.UnLock(); + return luRet; +} +} + /******************************************************************************/ /* e n d s W i t h */ /******************************************************************************/ @@ -288,7 +342,56 @@ int XrdOucUtils::genPath(char *buff, int blen, const char *path, const char *psf } /******************************************************************************/ -/* G r o u p s */ +/* G i d N a m e */ +/******************************************************************************/ + +int XrdOucUtils::GidName(gid_t gID, char *gName, int gNsz, time_t keepT) +{ + static const int maxgBsz = 256*1024; + static const int addGsz = 4096; + struct group *gEnt, gStruct; + char gBuff[1024], *gBp = gBuff; + int glen, gBsz = sizeof(gBuff), aOK = 1; + int n, retVal = 0; + +// Get ID from cache, if allowed +// + if (keepT) + {int n = LookUp(gidMap, static_cast(gID),gName,gNsz); + if (n > 0) return (n < gNsz ? n : 0); + } + +// Get the the group struct. If we don't have a large enough buffer, get a +// larger one and try again up to the maximum buffer we will tolerate. +// + while(( retVal = getgrgid_r(gID, &gStruct, gBp, gBsz, &gEnt) ) == ERANGE) + {if (gBsz >= maxgBsz) {aOK = 0; break;} + if (gBsz > addGsz) free(gBp); + gBsz += addGsz; + if (!(gBp = (char *)malloc(gBsz))) {aOK = 0; break;} + } + +// Return a group name if all went well +// + if (aOK && retVal == 0 && gEnt != NULL) + {if (keepT) + AddID(gidMap, static_cast(gID), gEnt->gr_name, keepT); + glen = strlen(gEnt->gr_name); + if (glen >= gNsz) glen = 0; + else strcpy(gName, gEnt->gr_name); + } else { + n = snprintf(gName, gNsz, "%ud", static_cast(gID)); + if (n >= gNsz) glen = 0; + } + +// Free any allocated buffer and return result +// + if (gBsz > addGsz && gBp) free(gBp); + return glen; +} + +/******************************************************************************/ +/* G r o u p N a m e */ /******************************************************************************/ int XrdOucUtils::GroupName(gid_t gID, char *gName, int gNsz) @@ -789,6 +892,45 @@ void XrdOucUtils::Undercover(XrdSysError &eDest, int noLog, int *pipeFD) for (myfd = 3; myfd < maxFiles; myfd++) if( (!pipeFD || myfd != pipeFD[1]) && myfd != logFD ) close(myfd); } + +/******************************************************************************/ +/* U i d N a m e */ +/******************************************************************************/ + +int XrdOucUtils::UidName(uid_t uID, char *uName, int uNsz, time_t keepT) +{ + struct passwd *pEnt, pStruct; + char pBuff[1024]; + int n, rc; + +// Get ID from cache, if allowed +// + if (keepT) + {int n = LookUp(uidMap, static_cast(uID),uName,uNsz); + if (n > 0) return (n < uNsz ? n : 0); + } + +// Try to obtain the username. We use this form to make sure we are using +// the standards conforming version (compilation error otherwise). +// + rc = getpwuid_r(uID, &pStruct, pBuff, sizeof(pBuff), &pEnt); + if (rc || !pEnt) + {n = snprintf(uName, uNsz, "%ud", static_cast(uID)); + return (n >= uNsz ? 0 : n); + } + +// Add entry to the cache if need be +// + if (keepT) + AddID(uidMap, static_cast(uID), pEnt->pw_name, keepT); + +// Return length of username or zero if it is too big +// + n = strlen(pEnt->pw_name); + if (uNsz <= (int)strlen(pEnt->pw_name)) return 0; + strcpy(uName, pEnt->pw_name); + return n; +} /******************************************************************************/ /* U s e r N a m e */ diff --git a/src/XrdOuc/XrdOucUtils.hh b/src/XrdOuc/XrdOucUtils.hh index 5fd829b3d11..bfef0d533f6 100644 --- a/src/XrdOuc/XrdOucUtils.hh +++ b/src/XrdOuc/XrdOucUtils.hh @@ -56,6 +56,8 @@ static char *genPath(const char *path, const char *inst, const char *psfx=0); static int genPath(char *buff, int blen, const char *path, const char *psfx=0); +static int GidName(gid_t gID, char *gName, int gNsz, time_t keepT=0); + static int GroupName(gid_t gID, char *gName, int gNsz); static char *Ident(long long &mySID, char *iBuff, int iBlen, @@ -94,6 +96,8 @@ static int Token(const char **str, char delim, char *buff, int bsz); static void Undercover(XrdSysError &eDest, int noLog, int *pipeFD = 0); +static int UidName(uid_t uID, char *uName, int uNsz, time_t keepT=0); + static int UserName(uid_t uID, char *uName, int uNsz); static bool PidFile(XrdSysError &eDest, const char *path); diff --git a/src/XrdServer.cmake b/src/XrdServer.cmake index d002b0c4eb9..a3d254c3a70 100644 --- a/src/XrdServer.cmake +++ b/src/XrdServer.cmake @@ -38,7 +38,6 @@ add_library( XrdXrootd/XrdXrootdPrepare.cc XrdXrootd/XrdXrootdPrepare.hh XrdXrootd/XrdXrootdProtocol.cc XrdXrootd/XrdXrootdProtocol.hh XrdXrootd/XrdXrootdResponse.cc XrdXrootd/XrdXrootdResponse.hh - XrdXrootd/XrdXrootdStat.icc XrdXrootd/XrdXrootdStats.cc XrdXrootd/XrdXrootdStats.hh XrdXrootd/XrdXrootdTransit.cc XrdXrootd/XrdXrootdTransit.hh XrdXrootd/XrdXrootdTransPend.cc XrdXrootd/XrdXrootdTransPend.hh @@ -150,7 +149,6 @@ add_library( XrdCms/XrdCmsFinder.cc XrdCms/XrdCmsFinder.hh XrdCms/XrdCmsClient.cc XrdCms/XrdCmsClient.hh XrdCms/XrdCmsResp.cc XrdCms/XrdCmsResp.hh - XrdCms/XrdCmsReq.cc XrdCms/XrdCmsReq.hh XrdCms/XrdCmsRTable.cc XrdCms/XrdCmsRTable.hh XrdCms/XrdCmsTypes.hh XrdCms/XrdCmsUtils.cc XrdCms/XrdCmsUtils.hh diff --git a/src/XrdXrootd/XrdXrootdConfig.cc b/src/XrdXrootd/XrdXrootdConfig.cc index 21f7ae8db84..1c18ffa5bfd 100644 --- a/src/XrdXrootd/XrdXrootdConfig.cc +++ b/src/XrdXrootd/XrdXrootdConfig.cc @@ -565,6 +565,24 @@ void XrdXrootdProtocol::PidFile() int XrdXrootdProtocol::ConfigSecurity(XrdOucEnv &xEnv, const char *cfn) { XrdSecGetProt_t secGetProt = 0; + char idBuff[256]; + int n; + +// Obtain our uid and username +// + myUID = geteuid(); + if ((n = XrdOucUtils::UidName(myUID, idBuff, sizeof(idBuff)))) + {myUName = strdup(idBuff); + myUNLen = n; + } + +// Obtain our gid and groupname +// + myGID = getegid(); + if ((n = XrdOucUtils::GidName(myGID, idBuff, sizeof(idBuff)))) + {myGName = strdup(idBuff); + myGNLen = n; + } // Check if we need to loadanything // diff --git a/src/XrdXrootd/XrdXrootdProtocol.cc b/src/XrdXrootd/XrdXrootdProtocol.cc index 6ad09cda9ef..4a84caf5d19 100644 --- a/src/XrdXrootd/XrdXrootdProtocol.cc +++ b/src/XrdXrootd/XrdXrootdProtocol.cc @@ -29,12 +29,15 @@ #include "XrdVersion.hh" -#include "XrdSfs/XrdSfsInterface.hh" +#include "XProtocol/XProtocol.hh" + #include "Xrd/XrdBuffer.hh" #include "Xrd/XrdLink.hh" -#include "XProtocol/XProtocol.hh" #include "XrdOuc/XrdOucStream.hh" +#include "XrdOuc/XrdOucUtils.hh" #include "XrdSec/XrdSecProtect.hh" +#include "XrdSfs/XrdSfsFlags.hh" +#include "XrdSfs/XrdSfsInterface.hh" #include "XrdSys/XrdSysTimer.hh" #include "XrdXrootd/XrdXrootdAio.hh" #include "XrdXrootd/XrdXrootdFile.hh" @@ -118,6 +121,14 @@ int XrdXrootdProtocol::myPID = static_cast(getpid()); int XrdXrootdProtocol::myRole = 0; int XrdXrootdProtocol::myRolf = 0; +gid_t XrdXrootdProtocol::myGID = 0; +uid_t XrdXrootdProtocol::myUID = 0; +int XrdXrootdProtocol::myGNLen= 1; +int XrdXrootdProtocol::myUNLen= 1; +const char *XrdXrootdProtocol::myGName= "?"; +const char *XrdXrootdProtocol::myUName= "?"; +time_t XrdXrootdProtocol::keepT = 86400; // 24 hours + int XrdXrootdProtocol::PrepareLimit = -1; bool XrdXrootdProtocol::PrepareAlt = false; bool XrdXrootdProtocol::LimitError = true; @@ -666,6 +677,113 @@ void XrdXrootdProtocol::Recycle(XrdLink *lp, int csec, const char *reason) if (Response.isOurs()) ProtStack.Push(&ProtLink); } +/******************************************************************************/ +/* S t a t G e n */ +/******************************************************************************/ + +int XrdXrootdProtocol::StatGen(struct stat &buf, char *xxBuff, int xxLen, + bool xtnd) +{ + const mode_t isReadable = (S_IRUSR | S_IRGRP | S_IROTH); + const mode_t isWritable = (S_IWUSR | S_IWGRP | S_IWOTH); + const mode_t isExecable = (S_IXUSR | S_IXGRP | S_IXOTH); + uid_t theuid; + gid_t thegid; + union {long long uuid; struct {int hi; int lo;} id;} Dev; + long long fsz; + int m, n, flags = 0; + +// Get the right uid/gid +// + theuid = (Client && Client->uid ? Client->uid : myUID); + thegid = (Client && Client->gid ? Client->gid : myGID); + +// Compute the unique id +// + Dev.id.lo = buf.st_ino; + Dev.id.hi = buf.st_dev; + +// Compute correct setting of the readable flag +// + if (buf.st_mode & isReadable + &&((buf.st_mode & S_IRUSR && theuid == buf.st_uid) + || (buf.st_mode & S_IRGRP && thegid == buf.st_gid) + || buf.st_mode & S_IROTH)) flags |= kXR_readable; + +// Compute correct setting of the writable flag +// + if (buf.st_mode & isWritable + &&((buf.st_mode & S_IWUSR && theuid == buf.st_uid) + || (buf.st_mode & S_IWGRP && thegid == buf.st_gid) + || buf.st_mode & S_IWOTH)) flags |= kXR_writable; + +// Compute correct setting of the execable flag +// + if (buf.st_mode & isExecable + &&((buf.st_mode & S_IXUSR && theuid == buf.st_uid) + || (buf.st_mode & S_IXGRP && thegid == buf.st_gid) + || buf.st_mode & S_IXOTH)) flags |= kXR_xset; + +// Compute the other flag settings +// + if (!Dev.uuid) flags |= kXR_offline; + if (S_ISDIR(buf.st_mode)) flags |= kXR_isDir; + else if (!S_ISREG(buf.st_mode)) flags |= kXR_other; + else{if (buf.st_mode & XRDSFS_POSCPEND) flags |= kXR_poscpend; + if ((buf.st_rdev & XRDSFS_RDVMASK) == 0) + {if (buf.st_rdev & XRDSFS_OFFLINE) flags |= kXR_offline; + if (buf.st_rdev & XRDSFS_HASBKUP) flags |= kXR_bkpexist; + } + } + fsz = static_cast(buf.st_size); + +// Format the default response: +// + m = snprintf(xxBuff, xxLen, "%lld %lld %d %ld", + Dev.uuid, fsz, flags, buf.st_mtime); +// if (!xtnd || m >= xxLen) return xxLen; +// + +// Format extended response: +// + char *origP = xxBuff; + char *nullP = xxBuff + m++; + xxBuff += m; xxLen -= m; + n = snprintf(xxBuff, xxLen, "%ld %ld 0%o ", + buf.st_ctime, buf.st_atime, buf.st_mode&07777); + if (n >= xxLen) return m; + xxBuff += n; xxLen -= n; + +// Tack on owner +// + if (theuid == myUID) + {if (myUNLen >= xxLen) return m; + strcpy(xxBuff, myUName); + n = myUNLen; + } else { + if (!(n = XrdOucUtils::UidName(theuid, xxBuff, xxLen, keepT))) return m; + } + xxBuff += n; + *xxBuff++ = ' '; + xxLen -= (n+1); + +// Tack on group +// + if (thegid == myGID) + {if (myGNLen >= xxLen) return m; + strcpy(xxBuff, myGName); + n = myUNLen; + } else { + if (!(n = XrdOucUtils::GidName(thegid, xxBuff, xxLen, keepT))) return m; + } + xxBuff += n+1; + +// All done, return full response +// + *nullP = ' '; + return xxBuff - origP; +} + /******************************************************************************/ /* S t a t s */ /******************************************************************************/ diff --git a/src/XrdXrootd/XrdXrootdProtocol.hh b/src/XrdXrootd/XrdXrootdProtocol.hh index ee46e504643..edb4b4e074a 100644 --- a/src/XrdXrootd/XrdXrootdProtocol.hh +++ b/src/XrdXrootd/XrdXrootdProtocol.hh @@ -121,8 +121,6 @@ static int Configure(char *parms, XrdProtocol_Config *pi); int Stats(char *buff, int blen, int do_sync=0); -static int StatGen(struct stat &buf, char *xxBuff); - // XrdXrootdProtocol operator =(const XrdXrootdProtocol &rhs) = delete; XrdXrootdProtocol& operator =(const XrdXrootdProtocol &rhs); XrdXrootdProtocol(); @@ -210,6 +208,7 @@ static int rpCheck(char *fn, char **opaque); int rpEmsg(const char *op, char *fn); int vpEmsg(const char *op, char *fn); static int Squash(char *); + int StatGen(struct stat &buf, char *xxBuff, int xxLen, bool xa=false); static int xapath(XrdOucStream &Config); static int xasync(XrdOucStream &Config); static int xcksum(XrdOucStream &Config); @@ -266,6 +265,14 @@ static int myPID; static int myRole; // Role for kXR_protocol (>= 2.9.7) static int myRolf; // Role for kXR_protocol (< 2.9.7) +static gid_t myGID; +static uid_t myUID; +static int myGNLen; +static int myUNLen; +static const char *myGName; +static const char *myUName; +static time_t keepT; + // Admin control area // static XrdNetSocket *AdminSock; diff --git a/src/XrdXrootd/XrdXrootdStat.icc b/src/XrdXrootd/XrdXrootdStat.icc deleted file mode 100644 index 0aafdf2e2ad..00000000000 --- a/src/XrdXrootd/XrdXrootdStat.icc +++ /dev/null @@ -1,98 +0,0 @@ -/******************************************************************************/ -/* */ -/* X r d X r o o t d S t a t . i c c */ -/* */ -/* (c) 2006 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. */ -/******************************************************************************/ - -// This method has been extracted from this file so that it can be easily -// included in other parts of the system that need to generate a protocol -// version of the stat response. The XRD_CLASS_NAME must be defined prior -// to inclusion (this file undefines it at the end). Be sure to include - -// - -/******************************************************************************/ -/* S t a t G e n */ -/******************************************************************************/ - -#include "XrdSfs/XrdSfsFlags.hh" - -int XRDXROOTD_STAT_CLASSNAME::StatGen(struct stat &buf, char *xxBuff) -{ - const mode_t isReadable = (S_IRUSR | S_IRGRP | S_IROTH); - const mode_t isWritable = (S_IWUSR | S_IWGRP | S_IWOTH); - const mode_t isExecable = (S_IXUSR | S_IXGRP | S_IXOTH); - static uid_t myuid = getuid(); - static gid_t mygid = getgid(); - union {long long uuid; struct {int hi; int lo;} id;} Dev; - long long fsz; - int flags = 0; - -// Compute the unique id -// - Dev.id.lo = buf.st_ino; - Dev.id.hi = buf.st_dev; - -// Compute correct setting of the readable flag -// - if (buf.st_mode & isReadable - &&((buf.st_mode & S_IRUSR && myuid == buf.st_uid) - || (buf.st_mode & S_IRGRP && mygid == buf.st_gid) - || buf.st_mode & S_IROTH)) flags |= kXR_readable; - -// Compute correct setting of the writable flag -// - if (buf.st_mode & isWritable - &&((buf.st_mode & S_IWUSR && myuid == buf.st_uid) - || (buf.st_mode & S_IWGRP && mygid == buf.st_gid) - || buf.st_mode & S_IWOTH)) flags |= kXR_writable; - -// Compute correct setting of the execable flag -// - if (buf.st_mode & isExecable - &&((buf.st_mode & S_IXUSR && myuid == buf.st_uid) - || (buf.st_mode & S_IXGRP && mygid == buf.st_gid) - || buf.st_mode & S_IXOTH)) flags |= kXR_xset; - -// Compute the other flag settings -// - if (!Dev.uuid) flags |= kXR_offline; - if (S_ISDIR(buf.st_mode)) flags |= kXR_isDir; - else if (!S_ISREG(buf.st_mode)) flags |= kXR_other; - else{if (buf.st_mode & XRDSFS_POSCPEND) flags |= kXR_poscpend; - if ((buf.st_rdev & XRDSFS_RDVMASK) == 0) - {if (buf.st_rdev & XRDSFS_OFFLINE) flags |= kXR_offline; - if (buf.st_rdev & XRDSFS_HASBKUP) flags |= kXR_bkpexist; - } - } - fsz = static_cast(buf.st_size); - -// Format the results and return them -// - return sprintf(xxBuff,"%lld %lld %d %ld",Dev.uuid,fsz,flags,buf.st_mtime)+1; -} -#undef XRDXROOTD_STAT_CLASSNAME diff --git a/src/XrdXrootd/XrdXrootdXeq.cc b/src/XrdXrootd/XrdXrootdXeq.cc index 6f1eb648d3e..e388eb0588b 100644 --- a/src/XrdXrootd/XrdXrootdXeq.cc +++ b/src/XrdXrootd/XrdXrootdXeq.cc @@ -650,8 +650,9 @@ int XrdXrootdProtocol::do_DirStat(XrdSfsDirectory *dp, char *pbuff, struct stat Stat; static const int statSz = 80; int bleft, rc = 0, dlen, cnt = 0; - char *buff, *dLoc, ebuff[8192]; + char *buff, *dLoc; const char *dname; + struct {char ebuff[8192]; char epad[512];} XB; // Construct the path to the directory as we will be asking for stat calls // if the interface does not support autostat. @@ -668,8 +669,8 @@ int XrdXrootdProtocol::do_DirStat(XrdSfsDirectory *dp, char *pbuff, // client to issue individual stat requests in that case. // memset(&Stat, 0, sizeof(Stat)); - strcpy(ebuff, ".\n0 0 0 0\n"); - buff = ebuff+10; bleft = sizeof(ebuff)-10; + strcpy(XB.ebuff, ".\n0 0 0 0\n"); + buff = XB.ebuff+10; bleft = sizeof(XB.ebuff)-10; // Start retreiving each entry and place in a local buffer with a trailing new // line character (the last entry will have a null byte). If we cannot fit a @@ -691,23 +692,23 @@ int XrdXrootdProtocol::do_DirStat(XrdSfsDirectory *dp, char *pbuff, return fsError(rc, XROOTD_MON_STAT, myError, argp->buff, opaque); } - dlen = StatGen(Stat, buff); + dlen = StatGen(Stat, buff, sizeof(XB.epad)); bleft -= dlen; buff += (dlen-1); *buff = '\n'; buff++; } dname = 0; } if (dname) - {rc = Response.Send(kXR_oksofar, ebuff, buff-ebuff); - buff = ebuff; bleft = sizeof(ebuff); + {rc = Response.Send(kXR_oksofar, XB.ebuff, buff-XB.ebuff); + buff = XB.ebuff; bleft = sizeof(XB.ebuff); } } while(!rc && dname); // Send the ending packet if we actually have one to send // if (!rc) - {if (ebuff == buff) rc = Response.Send(); + {if (XB.ebuff == buff) rc = Response.Send(); else {*(buff-1) = '\0'; - rc = Response.Send((void *)ebuff, buff-ebuff); + rc = Response.Send((void *)XB.ebuff, buff-XB.ebuff); } } @@ -1474,7 +1475,7 @@ int XrdXrootdProtocol::do_Open() // If client wants a stat in open, return the stat information // if (retStat) - {retStat = StatGen(statbuf, ebuff); + {retStat = StatGen(statbuf, ebuff, sizeof(ebuff)); IOResp[1].iov_base = (char *)&myResp; IOResp[1].iov_len = sizeof(myResp); IOResp[2].iov_base = ebuff; IOResp[2].iov_len = retStat; resplen = sizeof(myResp) + retStat; @@ -2627,7 +2628,7 @@ int XrdXrootdProtocol::do_Stat() static const int fsctl_cmd = SFS_FSCTL_STATFS; bool doDig; int rc; - char *opaque, xxBuff[256]; + char *opaque, xxBuff[1024]; struct stat buf; XrdOucErrInfo myError(Link->ID,&statCB,ReqID.getID(),Monitor.Did,clientPV); @@ -2649,7 +2650,8 @@ int XrdXrootdProtocol::do_Stat() "stat does not refer to an open file"); rc = fp->XrdSfsp->stat(&buf); TRACEP(FS, "stat rc=" <buff); - if (rc == SFS_OK) return Response.Send(xxBuff, StatGen(buf, xxBuff)); + if (rc == SFS_OK) return Response.Send(xxBuff, + StatGen(buf,xxBuff,sizeof(xxBuff))); } return fsError(rc, (doDig ? 0 : XROOTD_MON_STAT),myError,argp->buff,opaque); } @@ -3771,13 +3774,6 @@ int XrdXrootdProtocol::Squash(char *fn) return XPList.Validate(fn, ofn-fn); } -/******************************************************************************/ -/* S t a t G e n */ -/******************************************************************************/ - -#define XRDXROOTD_STAT_CLASSNAME XrdXrootdProtocol -#include "XrdXrootd/XrdXrootdStat.icc" - /******************************************************************************/ /* v p E m s g */ /******************************************************************************/