XRootD
XrdSecPManager.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d S e c P M a n a g e r . c c */
4 /* */
5 /* (c) 2003 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* All Rights Reserved */
7 /* Produced by Andrew Hanushevsky for Stanford University under contract */
8 /* DE-AC02-76-SFO0515 with the Department of Energy */
9 /* */
10 /* This file is part of the XRootD software suite. */
11 /* */
12 /* XRootD is free software: you can redistribute it and/or modify it under */
13 /* the terms of the GNU Lesser General Public License as published by the */
14 /* Free Software Foundation, either version 3 of the License, or (at your */
15 /* option) any later version. */
16 /* */
17 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20 /* License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25 /* */
26 /* The copyright holder's institutional names and contributor's names may not */
27 /* be used to endorse or promote products derived from this software without */
28 /* specific prior written permission of the institution or contributor. */
29 /******************************************************************************/
30 
31 #include <string>
32 #include <cstring>
33 #include <strings.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <cerrno>
37 
38 #include "XrdVersion.hh"
39 #include "XrdVersionPlugin.hh"
40 
41 #include "XrdSys/XrdSysHeaders.hh"
43 #include "XrdSec/XrdSecPManager.hh"
45 #include "XrdOuc/XrdOucEnv.hh"
46 #include "XrdOuc/XrdOucErrInfo.hh"
48 #include "XrdOuc/XrdOucVerName.hh"
49 #include "XrdNet/XrdNetAddrInfo.hh"
50 
51 #include "XrdSys/XrdSysPlatform.hh"
52 
53 /******************************************************************************/
54 /* M i s c e l l a n e o u s D e f i n e s */
55 /******************************************************************************/
56 
57 #define DEBUG(x) {if (DebugON) std::cerr <<"sec_PM: " <<x <<std::endl;}
58 
59 /******************************************************************************/
60 /* L o c a l C l a s s e s */
61 /******************************************************************************/
62 
64 {
65 public:
66 
68 bool needTLS;
70 char *protargs;
73 
74  XrdSecProtList(const char *pid, const char *parg, bool tls)
75  : needTLS(tls), ep(0), Next(0)
76  {strncpy(protid, pid, sizeof(protid)-1);
77  protid[XrdSecPROTOIDSIZE] = '\0';
78  protargs = (parg ? strdup(parg): (char *)"");
79  }
80  ~XrdSecProtList() {} // ProtList objects never get freed!
81 };
82 
83 /******************************************************************************/
84 /* V e r s i o n N u m b e r */
85 /******************************************************************************/
86 
87 // Note that these would properly belong in XrdSecClient.cc and XrdSecServer.cc
88 // However, as this is the object common to both, we consolidate them here.
89 
91 
93 
94 /******************************************************************************/
95 /* S t a t i c I t e m s */
96 /******************************************************************************/
97 
98 namespace
99 {
100 XrdSysMutex pmMutex;
101 }
102 
103 /******************************************************************************/
104 /* X r d S e c P M a n a g e r M e t h o d s */
105 /******************************************************************************/
106 /******************************************************************************/
107 /* F i n d */
108 /******************************************************************************/
109 
110 XrdSecPMask_t XrdSecPManager::Find(const char *pid, char **parg)
111 {
112  XrdSecProtList *plp;
113 
114  if ((plp = Lookup(pid)))
115  {if (parg) *parg = plp->protargs;
116  return plp->protnum;
117  }
118  return 0;
119 }
120 
121 /******************************************************************************/
122 /* G e t */
123 /******************************************************************************/
124 
126  XrdNetAddrInfo &endPoint,
127  const char *pname,
128  XrdOucErrInfo *erp)
129 {
130  XrdSecProtList *pl;
131  const char *msgv[2];
132 
133 // Find the protocol and get an instance of the protocol object
134 //
135  if ((pl = Lookup(pname)))
136  {DEBUG("Using " <<pname <<" protocol, args='"
137  <<(pl->protargs ? pl->protargs : "") <<"'");
138  return pl->ep('s', hname, endPoint, 0, erp);
139  }
140 
141 // Protocol is not supported
142 //
143  msgv[0] = pname;
144  msgv[1] = " security protocol is not supported.";
145  erp->setErrInfo(EPROTONOSUPPORT, msgv, 2);
146  return 0;
147 }
148 
150  XrdNetAddrInfo &endPoint,
151  XrdSecParameters &secparm,
152  XrdOucErrInfo *eri)
153 {
154  char secbuff[4096], *nscan, *pname, *pargs, *bp = secbuff;
155  char pcomp[XrdSecPROTOIDSIZE+4], *compProt;
156  XrdSecProtList *pl;
157  XrdSecProtocol *pp;
158  XrdOucErrInfo ei;
159  XrdOucErrInfo *erp;
160  char *wp;
161  int i;
162 
163 // We support passing the list of protocols via Url parameter unless this is
164 // a proxy server as the url should be merely passed hrough. If the proxy is
165 // not forwarding creds, then we use our error object to prevent security
166 // yet from using anything but the proxy's credentials.
167 // to become more clever
168 //
169  if (isProxy)
170  {wp = 0;
171  if (!fwdCreds) eri = 0;
172  } else {
173  XrdOucEnv *envP;
174  if (!eri || (envP = eri->getEnv()) == 0) wp = 0;
175  else wp = envP->Get("xrd.wantprot");
176  }
177 
178 // Get the appropriate protocol list as well as the right error object
179 //
180  const char *wantProt = wp ? (const char *)wp : getenv("XrdSecPROTOCOL");
181  erp = (eri) ? eri : &ei;
182 
183 // We only scan the buffer once
184 //
185  if (secparm.size <= 0) return (XrdSecProtocol *)0;
186 
187 // Copy out the wanted protocols and frame them for easy comparison
188 //
189  if (wantProt)
190  {i = strlen(wantProt);
191  compProt = (char *)malloc(i+3);
192  *compProt = ',';
193  strcpy(compProt+1, wantProt);
194  compProt[i+1] = ','; compProt[i+2] = 0; *pcomp = ',';
195  } else compProt = 0;
196 
197 // Copy the string into a local buffer so that we can simplify some comparisons
198 // and isolate ourselves from server protocol errors.
199 //
200  if (secparm.size < (int)sizeof(secbuff)) i = secparm.size;
201  else i = sizeof(secbuff)-1;
202  strncpy(secbuff, secparm.buffer, i);
203  secbuff[i] = '\0';
204 
205 // Find a protocol marker in the info block and check if acceptable
206 //
207  while(*bp)
208  {if (*bp != '&') {bp++; continue;}
209  else if (!*(++bp) || *bp != 'P' || !*(++bp) || *bp != '=') continue;
210  bp++; pname = bp; pargs = 0;
211  while(*bp && *bp != ',' && *bp != '&') bp++;
212  if (!*bp) nscan = 0;
213  else {if (*bp == '&') {*bp = '\0'; pargs = 0; nscan = bp;}
214  else {*bp = '\0'; pargs = ++bp;
215  while (*bp && *bp != '&') bp++;
216  if (*bp) {*bp ='\0'; nscan = bp;}
217  else nscan = 0;
218  }
219  }
220  if (wantProt)
221  {strncpy(pcomp+1, pname, XrdSecPROTOIDSIZE);
222  pcomp[XrdSecPROTOIDSIZE+1] = 0;
223  strcat(pcomp, ",");
224  }
225  if (!wantProt || strstr(compProt, pcomp))
226  {XrdSysMutexHelper pmHelper(pmMutex);
227  if ((pl = Lookup(pname)) || (pl = ldPO(erp, 'c', pname)))
228  {DEBUG("Using " <<pname <<" protocol, args='"
229  <<(pargs ? pargs : "") <<"'");
230  if ((pp = pl->ep('c', hname, endPoint, pargs, erp)))
231  {if (nscan) {i = nscan - secbuff;
232  secparm.buffer += i; secparm.size -= i;
233  } else secparm.size = -1;
234  if (compProt) free(compProt);
235  return pp;
236  }
237  }
238  if (erp->getErrInfo() != ENOENT) std::cerr <<erp->getErrText() <<std::endl;
239  } else {DEBUG("Skipping " <<pname <<" only want " <<wantProt);}
240  if (!nscan) break;
241  *nscan = '&'; bp = nscan;
242  }
243  secparm.size = -1;
244  if (compProt) free(compProt);
245  return (XrdSecProtocol *)0;
246 }
247 
248 /******************************************************************************/
249 /* P r i v a t e M e t h o d s */
250 /******************************************************************************/
251 /******************************************************************************/
252 /* A d d */
253 /******************************************************************************/
254 
255 XrdSecProtList *XrdSecPManager::Add(XrdOucErrInfo *eMsg, const char *pid,
256  XrdSecProtocol *(*ep)(PROTPARMS),
257  const char *parg)
258 {
259  XrdSecProtList *plp;
260  bool reqTLS = false;
261 
262 // Make sure we did not overflow the protocol stack
263 //
264  if (!protnum)
265  {eMsg->setErrInfo(-1, "XrdSec: Too many protocols defined.");
266  return 0;
267  }
268 
269 // Check if this protocol need TLS
270 //
271  if (parg && !strncmp(parg, "TLS:",4))
272  {char pBuff[XrdSecPROTOIDSIZE+2];
273  *pBuff = ' ';
274  strcpy(pBuff+1, pid); // We know it fits
275  if (!tlsProt) tlsProt = strdup(pBuff);
276  else {std::string tmp(tlsProt);
277  tmp.append(pBuff);
278  free(tlsProt);
279  tlsProt = strdup(tmp.c_str());
280  }
281  parg += 4; // Skip 'TLS:'
282  reqTLS = true;
283  }
284 
285 // Add this protocol to our protocol stack
286 //
287  plp = new XrdSecProtList((char *)pid, parg, reqTLS);
288  plp->ep = ep;
289  myMutex.Lock();
290  if (Last) {Last->Next = plp; Last = plp;}
291  else First = Last = plp;
292  plp->protnum = protnum;
293  if (protnum & 0x40000000) protnum = 0;
294  else protnum = protnum<<1;
295  myMutex.UnLock();
296 
297 // All went well
298 //
299  return plp;
300 }
301 
302 /******************************************************************************/
303 /* l d P O */
304 /******************************************************************************/
305 
306 #define INITPARMS const char, const char *, XrdOucErrInfo *
307 
308 XrdSecProtList *XrdSecPManager::ldPO(XrdOucErrInfo *eMsg, // In
309  const char pmode, // In 'c' | 's'
310  const char *pid, // In
311  const char *parg, // In
312  const char *spath) // In
313 {
315  static XrdVERSIONINFODEF(clVer, SecClnt, XrdVNUMBER, XrdVERSION);
316  static XrdVERSIONINFODEF(srVer, SecSrvr, XrdVNUMBER, XrdVERSION);
317  XrdVersionInfo *myVer = (pmode == 'c' ? &clVer : &srVer);
318  XrdOucPinLoader *secLib;
319  XrdSecProtocol *(*ep)(PROTPARMS);
320  char *(*ip)(INITPARMS);
321  const char *sep, *libloc;
322  char poname[80], libpath[2048], *newargs, *bP;
323  int i;
324 
325 // Set plugin debugging if needed (this only applies to client calls)
326 //
327  if (DebugON && pmode == 'c' && !DebugON) XrdOucEnv::Export("XRDPIHUSH", "1");
328 
329 // The "host" protocol is builtin.
330 //
331  if (!strcmp(pid, "host")) return Add(eMsg,pid,XrdSecProtocolhostObject,0);
332 
333 // Form library name (versioned) and object creator name and bundle id
334 //
335  snprintf(poname, sizeof(poname), "libXrdSec%s.so", pid);
336  i = (spath ? strlen(spath) : 0);
337  if (!i) {spath = ""; sep = "";}
338  else sep = (spath[i-1] == '/' ? "" : "/");
339  snprintf(libpath, sizeof(libpath), "%s%s%s", spath, sep, poname);
340  libloc = libpath;
341 
342 // Get the plugin loader.
343 //
344  if (errP) secLib = new XrdOucPinLoader(errP, myVer, "sec.protocol", libloc);
345  else {bP = eMsg->getMsgBuff(i);
346  secLib = new XrdOucPinLoader(bP,i,myVer, "sec.protocol", libloc);
347  }
348 
349 // Get the protocol object creator.
350 //
351  if (eMsg) eMsg->setErrInfo(0, "");
352  snprintf(poname, sizeof(poname), "XrdSecProtocol%sObject", pid);
353  if (!(ep = (XrdSecProtocol *(*)(PROTPARMS))secLib->Resolve(poname)))
354  {secLib->Unload(true); return 0;}
355 
356 // Get the protocol initializer
357 //
358  sprintf(poname, "XrdSecProtocol%sInit", pid);
359  if (!(ip = (char *(*)(INITPARMS))secLib->Resolve(poname)))
360  {secLib->Unload(true); return 0;}
361 
362 // Get the true path and do some debugging
363 //
364  libloc = secLib->Path();
365  DEBUG("Loaded " <<pid <<" protocol object from " <<libpath);
366 
367 // Invoke the one-time initialization
368 //
369  if (!(newargs = ip(pmode, (pmode == 'c' ? 0 : parg), eMsg)))
370  {if (!*(eMsg->getErrText()))
371  {const char *eTxt[] = {"XrdSec: ", pid,
372  " initialization failed in sec.protocol ", libloc};
373  eMsg->setErrInfo(-1, eTxt, sizeof(eTxt));
374  }
375  secLib->Unload(true);
376  return 0;
377  }
378 
379 // Add this protocol to our protocol stack
380 //
381  delete secLib;
382  return Add(eMsg, pid, ep, newargs);
383 }
384 
385 /******************************************************************************/
386 /* L o o k u p */
387 /******************************************************************************/
388 
389 XrdSecProtList *XrdSecPManager::Lookup(const char *pid) // In
390 {
391  XrdSecProtList *plp;
392 
393 // Since we only add protocols and never remove them, we need only to lock
394 // the protocol list to get the first item.
395 //
396  myMutex.Lock();
397  plp = First;
398  myMutex.UnLock();
399 
400 // Now we can go and find a matching protocol
401 //
402  while(plp && strcmp(plp->protid, pid)) plp = plp->Next;
403 
404  return plp;
405 }
XrdSecProtocol * XrdSecGetProtocol(const char *hostname, XrdNetAddrInfo &endPoint, XrdSecParameters &parms, XrdOucErrInfo *einfo)
Definition: XrdSecClient.cc:86
#define XrdSecPROTOIDSIZE
Definition: XrdSecEntity.hh:47
#define DEBUG(x)
#define INITPARMS
XrdVERSIONINFO(XrdSecGetProtocol, secprot)
int XrdSecPMask_t
#define PROTPARMS
XrdSecProtocol * XrdSecProtocolhostObject(const char who, const char *hostname, XrdNetAddrInfo &endPoint, const char *parms, XrdOucErrInfo *einfo)
XrdSecService * XrdSecgetService(XrdSysLogger *lp, const char *cfn)
#define eMsg(x)
static int Export(const char *Var, const char *Val)
Definition: XrdOucEnv.cc:188
char * Get(const char *varname)
Definition: XrdOucEnv.hh:69
const char * getErrText()
int setErrInfo(int code, const char *emsg)
XrdOucEnv * getEnv()
void * Resolve(const char *symbl, int mcnt=1)
void Unload(bool dodel=false)
const char * Path()
XrdSecPMask_t Find(const char *pid, char **parg=0)
XrdSecProtocol * Get(const char *hname, XrdNetAddrInfo &endPoint, const char *pname, XrdOucErrInfo *erp)
XrdSecProtocol *(* ep)(PROTPARMS)
XrdSecPMask_t protnum
char protid[XrdSecPROTOIDSIZE+1]
XrdSecProtList * Next
XrdSecProtList(const char *pid, const char *parg, bool tls)
XrdVERSIONINFODEF(myVersion, cmsclient, XrdVNUMBER, XrdVERSION)
XrdOucEnv * envP
Definition: XrdPss.cc:109
Generic structure to pass security information back and forth.
char * buffer
Pointer to the buffer.
int size
Size of the buffer or length of data in the buffer.