XRootD
XrdSecServer.cc
Go to the documentation of this file.
1 /***************************************************************************/
2 /* */
3 /* X r d S e c S e r v e r . c c */
4 /* */
5 /* (c) 2005 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 <unistd.h>
32 #include <cctype>
33 #include <cerrno>
34 #include <fcntl.h>
35 #include <netdb.h>
36 #include <cstdlib>
37 #include <strings.h>
38 #include <cstdio>
39 #include <sys/param.h>
40 
41 #include "XrdVersion.hh"
42 
43 #include "XrdSys/XrdSysLogger.hh"
44 #include "XrdSys/XrdSysHeaders.hh"
45 #include "XrdSys/XrdSysError.hh"
46 #include "XrdOuc/XrdOucEnv.hh"
47 #include "XrdOuc/XrdOucErrInfo.hh"
48 #include "XrdOuc/XrdOucPinKing.hh"
49 #include "XrdNet/XrdNetAddr.hh"
50 
54 #include "XrdSec/XrdSecServer.hh"
55 #include "XrdSec/XrdSecTrace.hh"
56 
57 #ifndef EAUTH
58 #define EAUTH EBADE
59 #endif
60 
61 /******************************************************************************/
62 /* S e c u r i t y L e v e l s */
63 /******************************************************************************/
64 
65 namespace
66 {
67 XrdSecProtectParms lclParms;
68 XrdSecProtectParms rmtParms;
69 
70 XrdVERSIONINFODEF(myVer, XrdSec, XrdVNUMBER, XrdVERSION);
71 }
72 
73 /******************************************************************************/
74 /* X r d S e c P i n I n f o */
75 /******************************************************************************/
76 
78 {
79 public:
80 
82 
83  XrdSecPinInfo(const char *drctv, const char *cfn, XrdSysError &errR)
84  : KingPin(drctv, theEnv, errR, &myVer)
85  {theEnv.Put("configFN", cfn);}
86 
88 
90 };
91 
92 /******************************************************************************/
93 /* X r d S e c P r o t B i n d */
94 /******************************************************************************/
95 
97 {
98 public:
100 char *thost;
102 char *thostsfx;
106 
107 XrdSecProtBind *Find(const char *hname);
108 
109 int Match(const char *hname);
110 
111  XrdSecProtBind(char *th, char *st, XrdSecPMask_t pmask=0);
113  {free(thost);
114  if (SecToken.buffer) free(SecToken.buffer);
115  }
116 };
117 
118 /******************************************************************************/
119 /* C o n s t r u c t o r */
120 /******************************************************************************/
121 
123 {
124  char *starp;
125  next = 0;
126  thost = th;
127  if (!(starp = index(thost, '*')))
128  {tsfxlen = -1;
129  thostsfx = (char *)0;
130  tpfxlen = 0;
131  } else {
132  *starp = '\0';
133  tpfxlen = strlen(thost);
134  thostsfx = starp+1;
135  tsfxlen = strlen(thostsfx);
136  }
137  if (st) {SecToken.buffer = strdup(st); SecToken.size = strlen(st);}
138  else {SecToken.buffer = 0; SecToken.size = 0;}
139  ValidProts = (pmask ? pmask : ~(XrdSecPMask_t)0);
140 }
141 
142 /******************************************************************************/
143 /* F i n d */
144 /******************************************************************************/
145 
147 {
148  XrdSecProtBind *bp = this;
149 
150  while(bp && !bp->Match(hname)) bp = bp->next;
151 
152  return bp;
153 }
154 
155 /******************************************************************************/
156 /* M a t c h */
157 /******************************************************************************/
158 
159 int XrdSecProtBind::Match(const char *hname)
160 {
161  int i;
162 
163 // If an exact match wanted, return the result
164 //
165  if (tsfxlen < 0) return !strcmp(thost, hname);
166 
167 // Try to match the prefix
168 //
169  if (tpfxlen && strncmp(thost, hname, tpfxlen)) return 0;
170 
171 // If no suffix matching is wanted, then we have succeeded
172 //
173  if (!(thostsfx)) return 1;
174 
175 // Try to match the suffix
176 //
177  if ((i = (strlen(hname) - tsfxlen)) < 0) return 0;
178  return !strcmp(&hname[i], thostsfx);
179 }
180 
181 /******************************************************************************/
182 /* X r d S e c P r o t P a r m */
183 /******************************************************************************/
184 
186 {
187 public:
188 
189  void Add() {Next = First; First = this;}
190 
191  int Cat(char *token);
192 
193 static XrdSecProtParm *Find(char *pid, int remove=0);
194 
195  int Insert(char oct);
196 
197  int isProto(char *proto) {return !strcmp(ProtoID, proto);}
198 
199  char *Result(int &size) {size = bp-buff; return buff;}
200 
201  void setProt(char *pid) {strcpy(ProtoID, pid);}
202 
205 
207 
208  XrdSecProtParm(XrdSysError *erp, const char *cid) : who(cid)
209  {*ProtoID = '\0';
210  bsize = 4096;
211  buff = (char *)malloc(bsize);
212  *buff = '\0';
213  bp = buff;
214  eDest = erp;
215  Next = 0;
216  }
217  ~XrdSecProtParm() {free(buff);}
218 private:
219 
220 XrdSysError *eDest;
221 int bsize;
222 char *buff;
223 char *bp;
224 const char *who;
225 };
226 
228 
229 /******************************************************************************/
230 /* C a t */
231 /******************************************************************************/
232 
233 int XrdSecProtParm::Cat(char *token)
234 {
235  int alen;
236  alen = strlen(token);
237  if (alen+1 > bsize-(bp-buff))
238  {eDest->Emsg("Config",who,ProtoID,"argument string too long");
239  return 0;
240  }
241  *bp++ = ' ';
242  strcpy(bp, token);
243  bp += alen;
244  return 1;
245 }
246 
247 /******************************************************************************/
248 /* F i n d */
249 /******************************************************************************/
250 
251 XrdSecProtParm *XrdSecProtParm::Find(char *pid, int remove)
252 {
253  XrdSecProtParm *mp, *pp;
254 
255  mp = 0; pp = First;
256  while(pp && !pp->isProto(pid)){mp = pp; pp = pp->Next;}
257  if (pp && remove)
258  {if (mp) mp->Next = pp->Next;
259  else First = pp->Next;
260  }
261  return pp;
262 }
263 
264 /******************************************************************************/
265 /* I n s e r t */
266 /******************************************************************************/
267 
269 {
270  if (bsize-(bp-buff) < 1)
271  {eDest->Emsg("Config",who,ProtoID,"argument string too long");
272  return 0;
273  }
274  *bp++ = oct;
275  return 1;
276 }
277 
278 /******************************************************************************/
279 /* X r d S e c S e r v e r */
280 /******************************************************************************/
281 
282 XrdSecPManager XrdSecServer::PManager;
283 
284 /******************************************************************************/
285 /* C o n s t r u c t o r */
286 /******************************************************************************/
287 
289 {
290 
291 // Set default values
292 //
293  PManager.setErrP(&eDest);
294  configFN = "";
295  bpFirst = 0;
296  bpLast = 0;
297  bpDefault = 0;
298  pinInfo = 0;
299  pidList = 0;
300  STBlen = 4096;
301  STBuff = (char *)malloc(STBlen);
302  *STBuff = '\0';
303  SToken = STBuff;
304  SecTrace = new XrdOucTrace(&eDest);
305  if (getenv("XRDDEBUG") || getenv("XrdSecDEBUG"))
306  {SecTrace->What = TRACE_ALL;
307  PManager.setDebug(1);
308  }
309  Enforce = false;
310  implauth = false;
311 }
312 
313 /******************************************************************************/
314 /* g e t P a r m s */
315 /******************************************************************************/
316 
317 const char *XrdSecServer::getParms(int &size, XrdNetAddrInfo *endPoint)
318 {
319  EPNAME("getParms")
320  XrdSecProtBind *bp;
321  char buff[256];
322 
323 // Try to find a specific token binding for a host or return default binding
324 //
325  if (!endPoint || !bpFirst) bp = 0;
326  else {const char *hname = endPoint->Name("*unknown*");
327  bp = bpFirst;
328  do {if (bp->Match(hname)) break;} while((bp = bp->next));
329  }
330 
331 // Get endpoint info if we are debugging
332 //
333  if (endPoint && QTRACE(Debug))
334  endPoint->Format(buff, sizeof(buff), XrdNetAddrInfo::fmtAuto,
336  else *buff = 0;
337 
338 // If we have a binding, return that else return the default
339 //
340  if (!bp) bp = bpDefault;
341  if (bp->SecToken.buffer)
342  {DEBUG(buff <<" sectoken=" <<bp->SecToken.buffer);
343  size = bp->SecToken.size;
344  return bp->SecToken.buffer;
345  }
346 
347  DEBUG(buff <<" sectoken=''");
348  size = 0;
349  return (const char *)0;
350 }
351 
352 /******************************************************************************/
353 /* g e t P r o t o c o l */
354 /******************************************************************************/
355 
357  XrdNetAddrInfo &endPoint,
358  const XrdSecCredentials *cred,
359  XrdOucErrInfo &einfo)
360 {
361  XrdSecProtBind *bp;
362  XrdSecPMask_t pnum;
363  XrdSecCredentials myCreds;
364  const char *msgv[8];
365 
366 // If null credentials supplied, default to host protocol otherwise make sure
367 // credentials data is actually supplied.
368 //
369  if (!cred) {myCreds.buffer=(char *)"host"; myCreds.size = 4; cred=&myCreds;}
370  else if (cred->size < 1 || !(cred->buffer))
371  {einfo.setErrInfo(EACCES,"No authentication credentials supplied.");
372  return 0;
373  }
374 
375 // If protocol binding must be enforced, make sure the host is not using a
376 // disallowed protocol.
377 //
378  if (Enforce)
379  {if ((pnum = PManager.Find(cred->buffer)))
380  {if (bpFirst && (bp = bpFirst->Find(host))
381  && !(bp->ValidProts & pnum))
382  {msgv[0] = host;
383  msgv[1] = " not allowed to authenticate using ";
384  msgv[2] = cred->buffer;
385  msgv[3] = " protocol.";
386  einfo.setErrInfo(EACCES, msgv, 4);
387  return 0;
388  }
389  }
390  else {msgv[0] = cred->buffer;
391  msgv[1] = " security protocol is not supported.";
392  einfo.setErrInfo(EPROTONOSUPPORT, msgv, 2);
393  return 0;
394  }
395  }
396 
397 // If we passed the protocol binding check, try to get an instance of the
398 // protocol the host is using
399 //
400  return PManager.Get(host, endPoint, cred->buffer, &einfo);
401 }
402 
403 /******************************************************************************/
404 /* P o s t P r o c e s s */
405 /******************************************************************************/
406 
408 {
409 // Return correct result. Make sure there is some kind of message returned.
410 //
411  if (secEntityPin && !secEntityPin->Process(entity, einfo))
412  {if (*einfo.getErrText() == '\0')
413  einfo.setErrInfo(EAUTH, "rejected by auth post processing");
414  return false;
415  }
416 
417  return true;
418 }
419 
420 /******************************************************************************/
421 /* C o n f i g F i l e P r o c e s s i n g M e t h o d s */
422 /******************************************************************************/
423 /******************************************************************************/
424 /* d e f i n e s */
425 /******************************************************************************/
426 
427 #define TS_Xeq(x,m) if (!strcmp(x,var)) return m(Config,Eroute);
428 
429 #define TS_Str(x,m) if (!strcmp(x,var)) {free(m); m = strdup(val); return 0;}
430 
431 #define TS_Chr(x,m) if (!strcmp(x,var)) {m = val[0]; return 0;}
432 
433 #define TS_Bit(x,m,v) if (!strcmp(x,var)) {m = v; return 0;}
434 
435 #define Max(x,y) (x > y ? x : y)
436 
437 /******************************************************************************/
438 /* C o n f i g u r e */
439 /******************************************************************************/
440 
441 int XrdSecServer::Configure(const char *cfn)
442 /*
443  Function: Establish default values using a configuration file.
444 
445  Input: None.
446 
447  Output: 0 upon success or !0 otherwise.
448 */
449 {
451  static const int isRlx = XrdSecProtectParms::relax;
452  static const int isFrc = XrdSecProtectParms::force;
453  XrdSecProtector *protObj;
454  const char *lName = "none", *rName = "none";
455  char *var;
456  int NoGo;
457 
458 // Print warm-up message
459 //
460  eDest.Say("++++++ Authentication system initialization started.");
461 
462 // Perform initialization
463 //
464  NoGo = ConfigFile(cfn);
465 
466 // Load the entity post processing plugin if we have one
467 //
468  if (pinInfo && !NoGo)
469  {XrdSecEntityPin *secPin = pinInfo->KingPin.Load("SecEntityPin");
470  delete pinInfo;
471  secEntityPin = secPin;
472  if (!secPin) return 1;
473  }
474 
475 // Export the list of security protocols that are available
476 //
477  if (pidList) XrdOucEnv::Export("XRDSECPROTOCOLS", pidList);
478 
479 // Almost done
480 //
481  var = (NoGo > 0 ? (char *)"failed." : (char *)"completed.");
482  eDest.Say("------ Authentication system initialization ", var);
483 
484 // No need to configure protect system if authentication failed
485 //
486  if (NoGo) return 1;
487 
488 // Put out another banner
489 //
490  eDest.Say("++++++ Protection system initialization started.");
491 
492 // If local level if greater than remote level, issue a warning
493 //
494  if (lclParms.level > rmtParms.level)
495  eDest.Say("Config warning: local protection level greater than "
496  "remote level; are you sure?");
497 
498 // Check if we need to initialize protection services
499 //
500  if (lclParms.level == XrdSecProtectParms::secNone
501  && rmtParms.level == XrdSecProtectParms::secNone)
502  {eDest.Say("Config warning: Security level is set to none; "
503  "request protection disabled!");
504  } else {
505  if (!(protObj = XrdSecLoadProtection(eDest))
506  || !(protObj->Config(lclParms, rmtParms, *eDest.logger()))) NoGo = 1;
507  else {lName = protObj->LName(lclParms.level);
508  rName = protObj->LName(rmtParms.level);
509  }
510  }
511 
512 // Blurt out what we have
513 //
514  if (!NoGo)
515  {eDest.Say("Config ","Local protection level: ",
516  (lclParms.opts & isRlx ? "relaxed " : 0), lName,
517  (lclParms.opts & isFrc ? " force" : 0));
518  eDest.Say("Config ","Remote protection level: ",
519  (rmtParms.opts & isRlx ? "relaxed " : 0), rName,
520  (rmtParms.opts & isFrc ? " force" : 0));
521  }
522 
523 // Now we are done
524 //
525  var = (NoGo > 0 ? (char *)"failed." : (char *)"completed.");
526  eDest.Say("------ Protection system initialization ", var);
527  return (NoGo > 0);
528 }
529 
530 /******************************************************************************/
531 /* C o n f i g F i l e */
532 /******************************************************************************/
533 
534 int XrdSecServer::ConfigFile(const char *ConfigFN)
535 /*
536  Function: Establish default values using a configuration file.
537 
538  Input: None.
539 
540  Output: 1 - Initialization failed.
541  0 - Initialization succeeded.
542 */
543 {
544  char *var;
545  int cfgFD, retc, NoGo = 0, recs = 0;
546  XrdOucEnv myEnv;
547  XrdOucStream Config(&eDest, getenv("XRDINSTANCE"), &myEnv, "=====> ");
548  XrdSecProtParm *pp;
549 
550 // If there is no config file, return with the defaults sets.
551 //
552  if (!ConfigFN || !*ConfigFN)
553  {eDest.Emsg("Config", "Authentication configuration file not specified.");
554  return 1;
555  }
556  configFN = ConfigFN;
557 
558 // Try to open the configuration file.
559 //
560  if ( (cfgFD = open(ConfigFN, O_RDONLY, 0)) < 0)
561  {eDest.Emsg("Config", errno, "opening config file", ConfigFN);
562  return 1;
563  }
564 
565 // Now start reading records until eof.
566 //
567  Config.Attach(cfgFD); Config.Tabs(0);
568  static const char *cvec[] = { "*** sec plugin config:", 0 };
569  Config.Capture(cvec);
570  while((var = Config.GetMyFirstWord()))
571  {if (!strncmp(var, "sec.", 4))
572  {recs++;
573  if (ConfigXeq(var+4, Config, eDest)) {Config.Echo(); NoGo = 1;}
574  }
575  }
576 
577 // Now check if any errors occurred during file i/o
578 //
579  if ((retc = Config.LastError()))
580  NoGo = eDest.Emsg("Config",-retc,"reading config file", ConfigFN);
581  else {char buff[128];
582  snprintf(buff, sizeof(buff),
583  " %d authentication directives processed in ", recs);
584  eDest.Say("Config", buff, ConfigFN);
585  }
586  Config.Close();
587 
588 // Determine whether we should initialize security
589 //
590  if (NoGo || ProtBind_Complete(eDest) ) NoGo = 1;
591  else if ((pp = XrdSecProtParm::First))
592  {NoGo = 1;
593  while(pp) {eDest.Emsg("Config", "protparm", pp->ProtoID,
594  "does not have a matching protocol.");
595  pp = pp->Next;
596  }
597  }
598 
599 // All done
600 //
601  return NoGo;
602 }
603 
604 /******************************************************************************/
605 /* P r i v a t e M e t h o d s */
606 /******************************************************************************/
607 /******************************************************************************/
608 /* C o n f i g X e q */
609 /******************************************************************************/
610 
611 int XrdSecServer::ConfigXeq(char *var, XrdOucStream &Config, XrdSysError &Eroute)
612 {
613 
614  // Fan out based on the variable
615  //
616  TS_Xeq("entitylib", xenlib);
617  TS_Xeq("level", xlevel);
618  TS_Xeq("protbind", xpbind);
619  TS_Xeq("protocol", xprot);
620  TS_Xeq("protparm", xpparm);
621  TS_Xeq("trace", xtrace);
622 
623  // No match found, complain.
624  //
625  Eroute.Say("Config warning: ignoring unknown directive '",var,"'.");
626  Config.Echo();
627  return 0;
628 }
629 
630 /******************************************************************************/
631 /* x e n l i b */
632 /******************************************************************************/
633 
634 /* Function: xenlib
635 
636  Purpose: To parse the directive: entitylib [++] <path> [<parms>]
637 
638  <path> absolute path to the entity plugin.
639  <parms> optional parameters passed to the plugin.
640 
641  Output: 0 upon success or !0 upon failure.
642 */
643 
644 int XrdSecServer::xenlib(XrdOucStream &Config, XrdSysError &Eroute)
645 {
646  std::string path;
647  char *val, parms[2048];
648  bool push = false;
649 
650 // Get the path or the push token
651 //
652  if ((val = Config.GetWord()))
653  {if (!strcmp(val, "++"))
654  {push = true;
655  val = Config.GetWord();
656  }
657  }
658 
659 // Make sure a path was specified
660 //
661  if (!val || !*val)
662  {Eroute.Emsg("Config", "entitylib not specified"); return 1;}
663 
664 // Make sure the path is absolute
665 //
666  if (*val != '/')
667  {Eroute.Emsg("Config", "entitylib path is not absolute"); return 1;}
668 
669 // Sequester the path as we will get additional tokens
670 //
671  path = val;
672 
673 // Record any parms
674 //
675  if (!Config.GetRest(parms, sizeof(parms)))
676  {Eroute.Emsg("Config", "entitylib parameters too long"); return 1;}
677 
678 // Check if we have a plugin info object (we will need one for this)
679 //
680  if (!pinInfo) pinInfo = new XrdSecPinInfo("sec.entitylib",configFN,Eroute);
681 
682 // Add the plugin
683 //
684  pinInfo->KingPin.Add(path.c_str(), (*parms ? parms : 0), push);
685 
686 // All done
687 //
688  return 0;
689 }
690 
691 /******************************************************************************/
692 /* x l e v e l */
693 /******************************************************************************/
694 
695 /* Function: xlevel
696 
697  Purpose: To parse the directive: level [<type>] [relaxed] <level> [force]
698 
699  <type> all | local | remote
700  <level> none | compatible | standard | intense | pedantic
701 
702  Output: 0 upon success or !0 upon failure.
703 */
704 
705 int XrdSecServer::xlevel(XrdOucStream &Config, XrdSysError &Eroute)
706 {
707  struct lvltab {const char *lname; XrdSecProtectParms::secLevel lvl;} ltab[] =
708  {{"none", XrdSecProtectParms::secNone},
709  {"compatible", XrdSecProtectParms::secCompatible},
710  {"standard", XrdSecProtectParms::secStandard},
711  {"intense", XrdSecProtectParms::secIntense},
712  {"pedantic", XrdSecProtectParms::secPedantic}
713  };
714  int i, numopts = sizeof(ltab)/sizeof(struct lvltab);
715  bool isLcl = true, isRmt = true, isSpec = false, isRlx = false, isFRC=false;
716  char *val;
717 
718 // Get the template host
719 //
720  val = Config.GetWord();
721  if (!val || !val[0])
722  {Eroute.Emsg("Config","level not specified"); return 1;}
723 
724 // Check for optional keyword
725 //
726  if (!strcmp(val, "all")) isSpec = true;
727  else if (!strcmp(val, "local")) {isSpec = true; isRmt = false;}
728  else if (!strcmp(val, "remote")){isSpec = true; isLcl = false;}
729 
730 // Check if we need another token
731 //
732  if (isSpec)
733  {val = Config.GetWord();
734  if (!val || !val[0])
735  {Eroute.Emsg("Config","level not specified"); return 1;}
736  }
737 
738 // Check for optional relaxed keyword
739 //
740  if (!strcmp(val, "relaxed"))
741  {isRlx = true;
742  val = Config.GetWord();
743  if (!val || !val[0])
744  {Eroute.Emsg("Config","level not specified"); return 1;}
745  }
746 
747 // Get the level
748 //
749  for (i = 0; i < numopts; i++) if (!strcmp(ltab[i].lname, val)) break;
750  if (i >= numopts)
751  {Eroute.Emsg("Config", "invalid level option -", val); return 1;}
752 
753 // Check for final keyword
754 //
755  val = Config.GetWord();
756  if (val && val[0])
757  {if (strcmp(val, "force"))
758  {Eroute.Emsg("Config","invalid level modifier - ", val); return 1;}
759  isFRC = true;
760  }
761 
762 // Set appropriate levels
763 //
764  if (isLcl)
765  {lclParms.level = ltab[i].lvl;
766  if (isRlx) lclParms.opts |= XrdSecProtectParms::relax;
767  else lclParms.opts &= ~XrdSecProtectParms::relax;
768  if (isFRC) lclParms.opts |= XrdSecProtectParms::force;
769  else lclParms.opts &= ~XrdSecProtectParms::force;
770  }
771  if (isRmt)
772  {rmtParms.level = ltab[i].lvl;
773  if (isRlx) rmtParms.opts |= XrdSecProtectParms::relax;
774  else rmtParms.opts &= ~XrdSecProtectParms::relax;
775  if (isFRC) rmtParms.opts |= XrdSecProtectParms::force;
776  else rmtParms.opts &= ~XrdSecProtectParms::force;
777  }
778  return 0;
779 }
780 
781 /******************************************************************************/
782 /* x p b i n d */
783 /******************************************************************************/
784 
785 /* Function: xpbind
786 
787  Purpose: To parse the directive: protbind <thost> [none | [only] <plist>]
788 
789  <thost> is a templated host name (e.g., bronco*.slac.stanford.edu)
790  <plist> are the protocols to be bound to the <thost>. A special
791  protocol, none, indicates that no token is to be passed.
792 
793  Output: 0 upon success or !0 upon failure.
794 */
795 
796 int XrdSecServer::xpbind(XrdOucStream &Config, XrdSysError &Eroute)
797 {
798  EPNAME("xpbind")
799  char *val, *thost;
800  XrdSecProtBind *bnow;
801  char sectoken[4096], *secbuff = sectoken;
802  int isdflt = 0, only = 0, anyprot = 0, noprot = 0, phost = 0;
803  int sectlen = sizeof(sectoken)-1;
804  XrdSecPMask_t PMask = 0;
805  *secbuff = '\0';
806 
807 // Get the template host
808 //
809  val = Config.GetWord();
810  if (!val || !val[0])
811  {Eroute.Emsg("Config","protbind host not specified"); return 1;}
812 
813 // Verify that this host has not been bound before
814 //
815  if ((isdflt = !strcmp("*", val))) bnow = bpDefault;
816  else {bnow = bpFirst;
817  while(bnow) if (!strcmp(bnow->thost, val)) break;
818  else bnow = bnow->next;
819  }
820  if (bnow) {Eroute.Emsg("Config","duplicate protbind definition - ", val);
821  return 1;
822  }
823  thost = strdup(val);
824 
825 // Now get each protocol to be used (there must be one).
826 //
827  while((val = Config.GetWord()))
828  {if (!strcmp(val, "none")) {noprot = 1; break;}
829  if (!strcmp(val, "only")) {only = 1; Enforce = true;}
830  else if (!strcmp(val, "host")) {phost = 1; anyprot = 1;}
831  else if (!PManager.Find(val))
832  {Eroute.Emsg("Config","protbind", val,
833  "protocol not previously defined.");
834  return 1;
835  }
836  else if (add2token(Eroute, val, &secbuff, sectlen, PMask))
837  {Eroute.Emsg("Config","Unable to bind protocols to",thost);
838  return 1;
839  } else anyprot = 1;
840  }
841 
842 // Verify that no conflicts arose
843 //
844  if (val && (val = Config.GetWord()))
845  {Eroute.Emsg("Config","conflicting protbind:", thost, val);
846  return 1;
847  }
848 
849 // Make sure we have some protocols bound to this host
850 //
851  if (!(anyprot || noprot))
852  {Eroute.Emsg("Config","no protocols bound to", thost); return 1;}
853  DEBUG("XrdSecConfig: Bound "<< thost<< " to "
854  << (noprot ? "none" : (phost ? "host" : sectoken)));
855 
856 // Issue warning if the host protocol was bound to this host but other
857 // protocols were also bound, making them rather useless.
858 //
859  if (phost && *sectoken)
860  {Eroute.Say("Config warning: 'protbind", thost,
861  "host' negates all other bound protocols.");
862  *sectoken = '\0';
863  }
864 
865 // Translate "localhost" to our local hostname, if possible.
866 //
867  if (!strcmp("localhost", thost))
868  {XrdNetAddr myIPAddr(0);
869  free(thost);
870  thost = strdup(myIPAddr.Name("localhost"));
871  } else if (!strcmp("=localhost", thost) || !strcmp("loopback", thost))
872  {free(thost);
873  thost = strdup("localhost");
874  }
875 
876 // Create new bind object
877 //
878  bnow = new XrdSecProtBind(thost,(noprot ? 0:sectoken),(only ? PMask:0));
879 
880 // Push the entry onto our bindings
881 //
882  if (isdflt) bpDefault = bnow;
883  else {if (bpLast) bpLast->next = bnow;
884  else bpFirst = bnow;
885  bpLast = bnow;
886  }
887 
888 // All done
889 //
890  return 0;
891 }
892 
893 /******************************************************************************/
894 /* x p r o t */
895 /******************************************************************************/
896 
897 /* Function: xprot
898 
899  Purpose: To parse the directive: protocol [<path>] <pid> [ <opts> ]
900 
901  <path> is the absolute path where the protocol library resides
902  <pid> is the 1-to-8 character protocol id.
903  <opts> are the associated protocol specific options such as:
904  noipcheck - don't check ip address origin
905  keyfile <kfn> - the key file associated with protocol
906  args <args> - associated non-blank arguments
907  Additional arguments may be passed to the protocol using the
908  protargs directive. ALl protargs directives must appear
909  prior to the protocol directive for the given protocol.
910 
911  Output: 0 upon success or !0 upon failure.
912 */
913 
914 int XrdSecServer::xprot(XrdOucStream &Config, XrdSysError &Eroute)
915 {
916  XrdSecProtParm *pp, myParms(&Eroute, "protocol");
917  char *pap, *val, pid[XrdSecPROTOIDSIZE+1], *args = 0;
918  char pathbuff[1024], *path = 0;
919  int psize;
920  XrdOucErrInfo erp;
921  XrdSecPMask_t mymask = 0;
922 
923 // Get the protocol id
924 //
925  val = Config.GetWord();
926  if (val && *val == '/')
927  {strlcpy(pathbuff, val, sizeof(pathbuff)); path = pathbuff;
928  val = Config.GetWord();
929  }
930  if (!val || !val[0])
931  {Eroute.Emsg("Config","protocol id not specified"); return 1;}
932 
933 // Verify that we don't have this protocol
934 //
935  if (strlen(val) > XrdSecPROTOIDSIZE)
936  {Eroute.Emsg("Config","protocol id too long - ", val); return 1;}
937 
938  if (PManager.Find(val))
939  {Eroute.Say("Config warning: protocol ",val," previously defined.");
940  strcpy(pid, val);
941  return add2token(Eroute, pid, &STBuff, STBlen, mymask);
942  }
943 
944 // Add this protocol to the list of protocols that have been defined
945 //
946  char pName[XrdSecPROTOIDSIZE+2];
947  *pName = ':';
948  strcpy(pName+1, val);
949  if (!pidList) pidList = strdup(pName);
950  else {std::string pids = pidList;
951  pids.append(pName);
952  free(pidList);
953  pidList = strdup(pids.c_str());
954  }
955 
956 // The builtin host protocol does not accept any parameters. Additionally, the
957 // host protocol negates any other protocols we may have in the default set.
958 //
959  if (!strcmp("host", val))
960  {if (Config.GetWord())
961  {Eroute.Emsg("Config", "Builtin host protocol does not accept parms.");
962  return 1;
963  }
964  implauth = true;
965  return 0;
966  }
967 
968 // Grab additional parameters that we here and that we have accumulated
969 //
970  strcpy(pid, val);
971  while((args = Config.GetWord())) if (!myParms.Cat(args)) return 1;
972  if ((pp = myParms.Find(pid, 1)))
973  {if ((*myParms.Result(psize) && !myParms.Insert('\n'))
974  || !myParms.Cat(pp->Result(psize))) return 1;
975  else delete pp;
976  }
977 
978 // Load this protocol
979 //
980  pap = myParms.Result(psize);
981  if (!PManager.Load(&erp, 's', pid, (psize ? pap : 0), path))
982  {if (*(erp.getErrText())) Eroute.Say(erp.getErrText());
983  Eroute.Say("Config Failed to load ", pid, " authentication protocol!");
984  return 1;
985  }
986 
987 // Add this protocol to the default security token
988 //
989  return add2token(Eroute, pid, &STBuff, STBlen, mymask);
990 }
991 
992 /******************************************************************************/
993 /* x p p a r m */
994 /******************************************************************************/
995 
996 /* Function: xpparm
997 
998  Purpose: To parse the directive: protparm <prot> <args>
999 
1000  <prot> is the name of the protocol to which these args apply.
1001  <args> are the protocol specific parameters. The remaing tokens
1002  on the line will be passed to the protocol at during
1003  protocol initialization. Each such line is separated by
1004  a new line character.
1005 
1006  Output: 0 upon success or !0 upon failure.
1007 */
1008 
1009 int XrdSecServer::xpparm(XrdOucStream &Config, XrdSysError &Eroute)
1010 {
1011  XrdSecProtParm *pp;
1012  char *val, pid[XrdSecPROTOIDSIZE+1];
1013 
1014 // Get the protocol name
1015 //
1016  val = Config.GetWord();
1017  if (!val || !val[0])
1018  {Eroute.Emsg("Config","protparm protocol not specified"); return 1;}
1019 
1020 // The builtin host protocol does not accept any parameters
1021 //
1022  if (!strcmp("host", val))
1023  {Eroute.Emsg("Config", "Builtin host protocol does not accept protparms.");
1024  return 1;
1025  }
1026 
1027 // Verify that we don't have this protocol
1028 //
1029  if (strlen(val) > XrdSecPROTOIDSIZE)
1030  {Eroute.Emsg("Config","protocol id too long - ", val); return 1;}
1031 
1032  if (PManager.Find(val))
1033  {Eroute.Emsg("Config warning: protparm protocol ",val," already defined.");
1034  return 0;
1035  }
1036 
1037  strcpy(pid, val);
1038 
1039 // Make sure we have at least one parameter here
1040 //
1041  if (!(val = Config.GetWord()))
1042  {Eroute.Emsg("Config","protparm", pid, "parameter not specified");
1043  return 1;
1044  }
1045 
1046 // Try to find a previous incarnation of this parm
1047 //
1048  if ((pp = XrdSecProtParm::Find(pid))) {if (!pp->Insert('\n')) return 1;}
1049  else {pp = new XrdSecProtParm(&Eroute, "protparm");
1050  pp->setProt(pid);
1051  pp->Add();
1052  }
1053 
1054 // Grab the options for the protocol. They are pretty much opaque to us here
1055 //
1056  do {if (!pp->Cat(val)) return 1;} while((val = Config.GetWord()));
1057  return 0;
1058 }
1059 
1060 /******************************************************************************/
1061 /* x t r a c e */
1062 /******************************************************************************/
1063 
1064 /* Function: xtrace
1065 
1066  Purpose: To parse the directive: trace <events>
1067 
1068  <events> the blank separated list of events to trace. Trace
1069  directives are cummalative.
1070 
1071  Output: 0 upon success or !0 upon failure.
1072 */
1073 
1074 int XrdSecServer::xtrace(XrdOucStream &Config, XrdSysError &Eroute)
1075 {
1076  static struct traceopts {const char *opname; int opval;} tropts[] =
1077  {
1078  {"all", TRACE_ALL},
1079  {"debug", TRACE_Debug},
1080  {"auth", TRACE_Authen},
1081  {"authentication", TRACE_Authen}
1082  };
1083  int i, neg, trval = 0, numopts = sizeof(tropts)/sizeof(struct traceopts);
1084  char *val;
1085 
1086  val = Config.GetWord();
1087  if (!val || !val[0])
1088  {Eroute.Emsg("Config", "trace option not specified"); return 1;}
1089  while (val && val[0])
1090  {if (!strcmp(val, "off")) trval = 0;
1091  else {if ((neg = (val[0] == '-' && val[1]))) val++;
1092  for (i = 0; i < numopts; i++)
1093  {if (!strcmp(val, tropts[i].opname))
1094  {if (neg) trval &= ~tropts[i].opval;
1095  else trval |= tropts[i].opval;
1096  break;
1097  }
1098  }
1099  if (i >= numopts)
1100  Eroute.Say("Config warning: ignoring invalid trace option '", val, "'.");
1101  }
1102  val = Config.GetWord();
1103  }
1104 
1105  SecTrace->What = (SecTrace->What & ~TRACE_Authenxx) | trval;
1106 
1107 // Propogate the debug option
1108 //
1109 #ifndef NODEBUG
1110  if (QTRACE(Debug)) PManager.setDebug(1);
1111  else PManager.setDebug(0);
1112 #endif
1113  return 0;
1114 }
1115 
1116 /******************************************************************************/
1117 /* M i s c e l l a n e o u s */
1118 /******************************************************************************/
1119 /******************************************************************************/
1120 /* a d d 2 t o k e n */
1121 /******************************************************************************/
1122 
1123 int XrdSecServer::add2token(XrdSysError &Eroute, char *pid,
1124  char **tokbuff, int &toklen, XrdSecPMask_t &pmask)
1125 {
1126  int i;
1127  char *pargs;
1128  XrdSecPMask_t protnum;
1129 
1130 // Find the protocol argument string
1131 //
1132  if (!(protnum = PManager.Find(pid, &pargs)))
1133  {Eroute.Emsg("Config","Protocol",pid,"not found after being added!");
1134  return 1;
1135  }
1136 
1137 // Make sure we have enough room to add
1138 //
1139  i = 4+strlen(pid)+strlen(pargs);
1140  if (i >= toklen)
1141  {Eroute.Emsg("Config","Protocol",pid,"parms exceed overall maximum!");
1142  return 1;
1143  }
1144 
1145 // Insert protocol specification (we already checked for an overflow)
1146 //
1147  i = sprintf(*tokbuff, "&P=%s%s%s", pid, (*pargs ? "," : ""), pargs);
1148  toklen -= i;
1149  *tokbuff += i;
1150  pmask |= protnum;
1151  return 0;
1152 }
1153 
1154 /******************************************************************************/
1155 /* P r o t B i n d _ C o m p l e t e */
1156 /******************************************************************************/
1157 
1158 int XrdSecServer::ProtBind_Complete(XrdSysError &Eroute)
1159 {
1160  EPNAME("ProtBind_Complete")
1161  XrdOucErrInfo erp;
1162 
1163 // Check if we have a default token, create one otherwise
1164 //
1165  if (!bpDefault)
1166  {if (!*SToken) {Eroute.Say("Config warning: No protocols defined; "
1167  "only host authentication available.");
1168  implauth = true;
1169  }
1170  else if (implauth)
1171  {Eroute.Say("Config warning: enabled builtin host "
1172  "protocol negates default use of any other protocols.");
1173  *SToken = '\0';
1174  }
1175  bpDefault = new XrdSecProtBind(strdup("*"), SToken);
1176  DEBUG("Default sectoken built: '" <<SToken <<"'");
1177  }
1178 
1179 // Add the host protocol to the set at this point to allow clients to
1180 // actually give use "host" as a protocol id if it's allowed. We do this so
1181 // that the right error message is generated. Otherwise, it ignored.
1182 //
1183  if (implauth && !PManager.Load(&erp, 's', "host", 0, 0))
1184  {Eroute.Emsg("Config", erp.getErrText()); return 1;}
1185 
1186 // Free up the constructed default sectoken
1187 //
1188  free(SToken); SToken = STBuff = 0; STBlen = 0;
1189  return 0;
1190 }
1191 
1192 /******************************************************************************/
1193 /* X r d S e c g e t S e r v i c e */
1194 /******************************************************************************/
1195 
1196 extern "C"
1197 {
1199 {
1200  XrdSecServer *SecServer = new XrdSecServer(lp);
1201 
1202 // Configure the server object
1203 //
1204  if (SecServer->Configure(cfn)) return 0;
1205 
1206 // Return the server object
1207 //
1208  return (XrdSecService *)SecServer;
1209 }
1210 }
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
#define EPNAME(x)
Definition: XrdBwmTrace.hh:56
#define TRACE_Debug
Definition: XrdCmsTrace.hh:37
#define QTRACE(act)
Definition: XrdCmsTrace.hh:49
XrdSysError eDest(0, "HttpMon")
#define open
Definition: XrdPosix.hh:78
#define XrdSecPROTOIDSIZE
Definition: XrdSecEntity.hh:47
XrdSecProtector * XrdSecLoadProtection(XrdSysError &erP)
int XrdSecPMask_t
#define EAUTH
Definition: XrdSecServer.cc:58
#define TS_Xeq(x, m)
XrdSecService * XrdSecgetService(XrdSysLogger *lp, const char *cfn)
#define TRACE_Authen
Definition: XrdSecTrace.hh:62
#define TRACE_Authenxx
Definition: XrdSecTrace.hh:61
bool Debug
if(Avsz)
size_t strlcpy(char *dst, const char *src, size_t sz)
#define TRACE_ALL
Definition: XrdTrace.hh:35
static const int noPort
Do not add port number.
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
@ fmtAuto
Hostname if already resolved o/w use fmtAddr.
const char * Name(const char *eName=0, const char **eText=0)
static int Export(const char *Var, const char *Val)
Definition: XrdOucEnv.cc:188
void Put(const char *varname, const char *value)
Definition: XrdOucEnv.hh:85
const char * getErrText()
int setErrInfo(int code, const char *emsg)
XrdSecPMask_t Find(const char *pid, char **parg=0)
XrdSecProtocol * Get(const char *hname, XrdNetAddrInfo &endPoint, const char *pname, XrdOucErrInfo *erp)
int Load(XrdOucErrInfo *eMsg, const char pmode, const char *pid, const char *parg, const char *path)
void setErrP(XrdSysError *eP)
void setDebug(int dbg)
XrdOucEnv theEnv
Definition: XrdSecServer.cc:89
XrdSecPinInfo(const char *drctv, const char *cfn, XrdSysError &errR)
Definition: XrdSecServer.cc:83
XrdOucPinKing< XrdSecEntityPin > KingPin
Definition: XrdSecServer.cc:81
int Match(const char *hname)
XrdSecProtBind * next
Definition: XrdSecServer.cc:99
XrdSecPMask_t ValidProts
XrdSecProtBind(char *th, char *st, XrdSecPMask_t pmask=0)
XrdSecProtBind * Find(const char *hname)
XrdSecParameters SecToken
char ProtoID[XrdSecPROTOIDSIZE+1]
static XrdSecProtParm * Find(char *pid, int remove=0)
XrdSecProtParm(XrdSysError *erp, const char *cid)
XrdSecProtParm * Next
int Insert(char oct)
int Cat(char *token)
static XrdSecProtParm * First
int isProto(char *proto)
char * Result(int &size)
void setProt(char *pid)
static const int relax
relax old clients
secLevel level
In: The desired level.
static const int force
Allow unencryted hash.
int opts
In: Options:
virtual bool Config(const XrdSecProtectParms &lclParms, const XrdSecProtectParms &rmtParms, XrdSysLogger &logr)
virtual const char * LName(XrdSecProtectParms::secLevel level)
XrdSecProtocol * getProtocol(const char *host, XrdNetAddrInfo &endPoint, const XrdSecCredentials *cred, XrdOucErrInfo &einfo)
const char * getParms(int &size, XrdNetAddrInfo *endPoint=0)
XrdSecServer(XrdSysLogger *lp)
int Configure(const char *cfn)
bool PostProcess(XrdSecEntity &entity, XrdOucErrInfo &einfo)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:116
void Say(const char *text1, const char *text2=0, const char *txt3=0, const char *text4=0, const char *text5=0, const char *txt6=0)
Definition: XrdSysError.cc:162
XrdSysLogger * logger(XrdSysLogger *lp=0)
Definition: XrdSysError.hh:175
XrdVERSIONINFODEF(myVersion, cmsclient, XrdVNUMBER, XrdVERSION)
XrdCmsConfig Config
@ oct
Definition: XrdSysTrace.hh:42
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.