XRootD
XrdCmsRedirLocal.cc
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
2 // Copyright (c) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH
3 // Author: Paul-Niklas Kramp <p.n.kramp@gsi.de>
4 // Jan Knedlik <j.knedlik@gsi.de>
5 //------------------------------------------------------------------------------
6 // XRootD is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU Lesser General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // XRootD is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public License
17 // along with XRootD. If not, see <http://www.gnu.org/licenses/>.
18 //------------------------------------------------------------------------------
19 
21 
22 //------------------------------------------------------------------------------
24 //------------------------------------------------------------------------------
26  int myPort, XrdOss *theSS) {
27  XrdCmsRedirLocal *plugin = new XrdCmsRedirLocal(Logger, opMode, myPort, theSS);
28  return plugin;
29 }
30 
31 //------------------------------------------------------------------------------
33 //------------------------------------------------------------------------------
35  XrdOss *theSS) : XrdCmsClient(amLocal),
36  nativeCmsFinder(new XrdCmsFinderRMT(Logger, opMode, myPort)),
37  readOnlyredirect(true),
38  httpRedirect(false),
39  Say(0,"cms_") {
40  Say.logger(Logger);
41 }
42 //------------------------------------------------------------------------------
44 //------------------------------------------------------------------------------
46 
47 //------------------------------------------------------------------------------
49 //------------------------------------------------------------------------------
50 int XrdCmsRedirLocal::Configure(const char *cfn, char *Parms, XrdOucEnv *EnvInfo) {
51  loadConfig(cfn);
52  if(localroot.empty())
53  {
54  Say.Emsg("RedirLocal", "oss.localroot (replaced by xrdcmsredirlocal for localredirect) " \
55  "and xrdcmsredirlocal.localroot are undefined, define xrdcmsredirlocal.localroot");
56  return 0;
57  }
58  if(localroot[0] != '/')
59  {
60  Say.Emsg("RedirLocal", "oss.localroot or xrdcmsredirlocal.localroot needs to be an absolute path");
61  return 0;
62  }
63  if (nativeCmsFinder)
64  return nativeCmsFinder->Configure(cfn, Parms, EnvInfo);
65  return 0; // means false
66 }
67 
68 void XrdCmsRedirLocal::loadConfig(const char *filename) {
70  int cfgFD;
71  char *word;
72 
73  if ((cfgFD = open(filename, O_RDONLY, 0)) < 0) {
74  return;
75  }
76  Config.Attach(cfgFD);
77  while ((word = Config.GetFirstWord(true))) { //get word in lower case
78  // search for readonlyredirect,
79  // which only allows read calls to be redirected to local
80  if (strcmp(word, "xrdcmsredirlocal.readonlyredirect") == 0){
81  readOnlyredirect = std::string(Config.GetWord(true)).find("true") != std::string::npos;
82  }
83  // search for httpredirect,
84  // which allows http(s) calls to be redirected to local
85  else if (strcmp(word, "xrdcmsredirlocal.httpredirect") == 0){
86  httpRedirect = std::string(Config.GetWord(true)).find("true") != std::string::npos;
87  }
88  // search for newer localroot, overwrite given oss.localroot if defined,
89  // which manually sets localroot to prepend
90  else if (strcmp(word, "xrdcmsredirlocal.localroot") == 0){
91  localroot = std::string(Config.GetWord(false));
92  }
93  // search for oss.localroot,
94  // which manually sets localroot to prepend
95  else if (strcmp(word, "oss.localroot") == 0 && localroot.empty()){
96  localroot = std::string(Config.GetWord(false));
97  }
98  }
99  Config.Close();
100 }
101 
102 //------------------------------------------------------------------------------
121 //------------------------------------------------------------------------------
122 int XrdCmsRedirLocal::Locate(XrdOucErrInfo &Resp, const char *path, int flags,
123  XrdOucEnv *EnvInfo) {
124  int rcode = 0;
125  if (nativeCmsFinder) {
126  // check if path contains localroot to know if potential redirection loop
127  // is happening. If yes, remove localroot from path, then rerun default
128  // locate with regular path and return to client
129  // localroot must be larger than 1 to avoid always being triggered by "/"
130  if (localroot.size() > 1 && strncmp(path, localroot.c_str(), localroot.size()) == 0)
131  {
132  // now check if localhost was tried before, to make sure we're handling
133  // the redirection loop
134  int param = 0; // need it to get Env
135  //EnvInfo->Env(param) gets already tried hosts
136  if(strstr(EnvInfo->Env(param), "tried=localhost") != nullptr)
137  {
138  std::string newPath(path);
139  // remove localroot
140  newPath = "//" + newPath.substr(localroot.size());
141  // get regular target host
142  rcode = nativeCmsFinder->Locate(Resp, newPath.c_str(), flags, EnvInfo);
143  // set new error message to full url:port//newPath
144  const std::string errText { std::string(Resp.getErrText()) + ':' + std::to_string(Resp.getErrInfo()) + newPath};
145  Resp.setErrInfo(0, errText.c_str());
146  // now have normal redirection to dataserver at url:port
147  return rcode;
148  }
149  }
150  std::string dialect = EnvInfo->secEnv()->addrInfo->Dialect();
151  // get regular target host
152  rcode = nativeCmsFinder->Locate(Resp, path, flags, EnvInfo);
153 
154  // check if http redirect to local filesystem is allowed
155  if (strncmp(dialect.c_str(), "http", 4) == 0 && !httpRedirect)
156  return rcode;
157 
158  // define target host from locate result
159  XrdNetAddr target(-1); // port is necessary, but can be any
160  target.Set(Resp.getErrText());
161  // does the target host have a private IP?
162  if (!target.isPrivate())
163  return rcode;
164  // does the client host have a private IP?
165  if (!EnvInfo->secEnv()->addrInfo->isPrivate())
166  return rcode;
167 
168  // as we can't rely on the flags from http clients, we do not perform the below
169  if (strncmp(dialect.c_str(), "http", 4) != 0)
170  {
171  // get client url redirect capability
172  int urlRedirSupport = Resp.getUCap();
173  urlRedirSupport &= XrdOucEI::uUrlOK;
174  if (!urlRedirSupport)
175  return rcode;
176 
177  // get client localredirect capability
178  int clientLRedirSupport = Resp.getUCap();
179  clientLRedirSupport &= XrdOucEI::uLclF;
180  if (!clientLRedirSupport)
181  return rcode;
182  }
183 
184  // http gets SFS_O_STAT flag when opening to read, instead of SFS_O_RDONLY
185  // in case of http dialect and stat, we do not perform the checks below
186  if (!(strncmp(dialect.c_str(), "http", 4) == 0 && flags == 0x20000000))
187  {
188  // only allow simple (but most prominent) operations to avoid complications
189  // RDONLY, WRONLY, RDWR, CREAT, TRUNC are allowed
190  if (flags > 0x202)
191  return rcode;
192  // always use native function if readOnlyredirect is configured and a
193  // non readonly flag is passed
194  if (readOnlyredirect && !(flags == SFS_O_RDONLY))
195  return rcode;
196  }
197  // passed all checks, now to actual business
198  // prepend manually configured localroot
199  std::string ppath = "file://" + localroot + path;
200  if (strncmp(dialect.c_str(), "http", 4) == 0)
201  {
202  // set info which will be sent to client
203  // eliminate the resource name so it is not doubled in XrdHttpReq::Redir.
204  Resp.setErrInfo(-1, ppath.substr(0, ppath.find(path)).c_str());
205  }
206  else{
207  // set info which will be sent to client
208  Resp.setErrInfo(-1, ppath.c_str());
209  }
210  return SFS_REDIRECT;
211  }
212  return rcode;
213 }
214 
215 //------------------------------------------------------------------------------
218 //------------------------------------------------------------------------------
219 int XrdCmsRedirLocal::Space(XrdOucErrInfo &Resp, const char *path,
220  XrdOucEnv *EnvInfo) {
221  if (nativeCmsFinder)
222  return nativeCmsFinder->Space(Resp, path, EnvInfo);
223  return 0;
224 }
225 
XrdVERSIONINFO(XrdCmsGetClient, XrdCmsRedirLocal)
XrdCmsClient * XrdCmsGetClient(XrdSysLogger *Logger, int opMode, int myPort, XrdOss *theSS)
Necessary implementation for XRootD to get the Plug-in.
int open(const char *path, int oflag,...)
#define SFS_REDIRECT
#define SFS_O_RDONLY
virtual int Configure(const char *cfn, char *Parms, XrdOucEnv *EnvInfo)=0
virtual int Space(XrdOucErrInfo &Resp, const char *path, XrdOucEnv *Info=0)=0
virtual int Locate(XrdOucErrInfo &Resp, const char *path, int flags, XrdOucEnv *Info=0)=0
int Configure(const char *cfn, char *Parms, XrdOucEnv *EnvInfo)
Configure the nativeCmsFinder.
~XrdCmsRedirLocal()
Destructor.
XrdCmsClient * nativeCmsFinder
used to forward requests to CmsFinder with regular implementation
void loadConfig(const char *filename)
int Locate(XrdOucErrInfo &Resp, const char *path, int flags, XrdOucEnv *EnvInfo)
std::string localroot
XrdCmsRedirLocal(XrdSysLogger *Logger, int opMode, int myPort, XrdOss *theSS)
Constructor.
int Space(XrdOucErrInfo &Resp, const char *path, XrdOucEnv *EnvInfo)
const char * Dialect()
const char * Set(const char *hSpec, int pNum=PortInSpec)
Definition: XrdNetAddr.cc:216
const XrdSecEntity * secEnv() const
Definition: XrdOucEnv.hh:107
char * Env(int &envlen)
Definition: XrdOucEnv.hh:48
const char * getErrText()
int setErrInfo(int code, const char *emsg)
XrdNetAddrInfo * addrInfo
Entity's connection details.
Definition: XrdSecEntity.hh:80
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
XrdSysLogger * logger(XrdSysLogger *lp=0)
Definition: XrdSysError.hh:141
XrdSysError Say
XrdCmsConfig Config
XrdSysLogger Logger
Definition: XrdGlobals.cc:47
static const int uUrlOK
ucap: Supports async responses
static const int uLclF
ucap: Client is on a private net