XRootD
Loading...
Searching...
No Matches
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
45#include "XrdOuc/XrdOucEnv.hh"
50
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{
65public:
66
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);
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
98namespace
99{
100XrdSysMutex 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
110XrdSecPMask_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
255XrdSecProtList *XrdSecPManager::Add(XrdOucErrInfo *eMsg, const char *pid,
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
308XrdSecProtList *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;
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
389XrdSecProtList *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}
#define DEBUG(x)
static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION)
XrdSecProtocol * XrdSecGetProtocol(const char *hostname, XrdNetAddrInfo &endPoint, XrdSecParameters &parms, XrdOucErrInfo *einfo)
#define XrdSecPROTOIDSIZE
#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)
char * Get(const char *varname)
Definition XrdOucEnv.hh:69
static int Export(const char *Var, const char *Val)
Definition XrdOucEnv.cc:170
XrdOucEnv * getEnv()
const char * getErrText()
int setErrInfo(int code, const char *emsg)
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)
XrdSecPMask_t protnum
char protid[XrdSecPROTOIDSIZE+1]
XrdSecProtocol *(* ep)(PROTPARMS)
XrdSecProtList * Next
XrdSecProtList(const char *pid, const char *parg, bool tls)
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.