00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 const char *XrdSecServerCVSID = "$Id: XrdSecServer.cc 38011 2011-02-08 18:35:57Z ganis $";
00014
00015 #include <unistd.h>
00016 #include <ctype.h>
00017 #include <errno.h>
00018 #include <fcntl.h>
00019 #include <netdb.h>
00020 #include <stdlib.h>
00021 #include <strings.h>
00022 #include <stdio.h>
00023 #include <sys/param.h>
00024
00025 #include "XrdNet/XrdNetDNS.hh"
00026 #include "XrdOuc/XrdOucEnv.hh"
00027 #include "XrdSys/XrdSysError.hh"
00028 #include "XrdOuc/XrdOucErrInfo.hh"
00029 #include "XrdSys/XrdSysLogger.hh"
00030 #include "XrdSys/XrdSysHeaders.hh"
00031
00032 #include "XrdSec/XrdSecInterface.hh"
00033 #include "XrdSec/XrdSecServer.hh"
00034 #include "XrdSec/XrdSecTrace.hh"
00035
00036
00037
00038
00039
00040 class XrdSecProtBind
00041 {
00042 public:
00043 XrdSecProtBind *next;
00044 char *thost;
00045 int tpfxlen;
00046 char *thostsfx;
00047 int tsfxlen;
00048 XrdSecParameters SecToken;
00049 XrdSecPMask_t ValidProts;
00050
00051 XrdSecProtBind *Find(const char *hname);
00052
00053 int Match(const char *hname);
00054
00055 XrdSecProtBind(char *th, char *st, XrdSecPMask_t pmask=0);
00056 ~XrdSecProtBind()
00057 {free(thost);
00058 if (SecToken.buffer) free(SecToken.buffer);
00059 }
00060 };
00061
00062
00063
00064
00065
00066 XrdSecProtBind::XrdSecProtBind(char *th, char *st, XrdSecPMask_t pmask)
00067 {
00068 char *starp;
00069 next = 0;
00070 thost = th;
00071 if (!(starp = index(thost, '*')))
00072 {tsfxlen = -1;
00073 thostsfx = (char *)0;
00074 tpfxlen = 0;
00075 } else {
00076 *starp = '\0';
00077 tpfxlen = strlen(thost);
00078 thostsfx = starp+1;
00079 tsfxlen = strlen(thostsfx);
00080 }
00081 if (st) {SecToken.buffer = strdup(st); SecToken.size = strlen(st);}
00082 else {SecToken.buffer = 0; SecToken.size = 0;}
00083 ValidProts = (pmask ? pmask : ~(XrdSecPMask_t)0);
00084 }
00085
00086
00087
00088
00089
00090 XrdSecProtBind *XrdSecProtBind::Find(const char *hname)
00091 {
00092 XrdSecProtBind *bp = this;
00093
00094 while(bp && !bp->Match(hname)) bp = bp->next;
00095
00096 return bp;
00097 }
00098
00099
00100
00101
00102
00103 int XrdSecProtBind::Match(const char *hname)
00104 {
00105 int i;
00106
00107
00108
00109 if (tsfxlen < 0) return !strcmp(thost, hname);
00110
00111
00112
00113 if (tpfxlen && strncmp(thost, hname, tpfxlen)) return 0;
00114
00115
00116
00117 if (!(thostsfx)) return 1;
00118
00119
00120
00121 if ((i = (strlen(hname) - tsfxlen)) < 0) return 0;
00122 return !strcmp(&hname[i], thostsfx);
00123 }
00124
00125
00126
00127
00128
00129 class XrdSecProtParm
00130 {
00131 public:
00132
00133 void Add() {Next = First; First = this;}
00134
00135 int Cat(char *token);
00136
00137 static XrdSecProtParm *Find(char *pid, int remove=0);
00138
00139 int Insert(char oct);
00140
00141 int isProto(char *proto) {return !strcmp(ProtoID, proto);}
00142
00143 char *Result(int &size) {size = bp-buff; return buff;}
00144
00145 void setProt(char *pid) {strcpy(ProtoID, pid);}
00146
00147 static XrdSecProtParm *First;
00148 XrdSecProtParm *Next;
00149
00150 char ProtoID[XrdSecPROTOIDSIZE+1];
00151
00152 XrdSecProtParm(XrdSysError *erp, const char *cid) : who(cid)
00153 {*ProtoID = '\0';
00154 bsize = 4096;
00155 buff = (char *)malloc(bsize);
00156 *buff = '\0';
00157 bp = buff;
00158 eDest = erp;
00159 Next = 0;
00160 }
00161 ~XrdSecProtParm() {free(buff);}
00162 private:
00163
00164 XrdSysError *eDest;
00165 int bsize;
00166 char *buff;
00167 char *bp;
00168 const char *who;
00169 };
00170
00171 XrdSecProtParm *XrdSecProtParm::First = 0;
00172
00173
00174
00175
00176
00177 int XrdSecProtParm::Cat(char *token)
00178 {
00179 int alen;
00180 alen = strlen(token);
00181 if (alen+1 > bsize-(bp-buff))
00182 {eDest->Emsg("Config",who,ProtoID,"argument string too long");
00183 return 0;
00184 }
00185 *bp++ = ' ';
00186 strcpy(bp, token);
00187 bp += alen;
00188 return 1;
00189 }
00190
00191
00192
00193
00194
00195 XrdSecProtParm *XrdSecProtParm::Find(char *pid, int remove)
00196 {
00197 XrdSecProtParm *mp, *pp;
00198
00199 mp = 0; pp = First;
00200 while(pp && !pp->isProto(pid)){mp = pp; pp = pp->Next;}
00201 if (pp && remove)
00202 {if (mp) mp->Next = pp->Next;
00203 else First = pp->Next;
00204 }
00205 return pp;
00206 }
00207
00208
00209
00210
00211
00212 int XrdSecProtParm::Insert(char oct)
00213 {
00214 if (bsize-(bp-buff) < 1)
00215 {eDest->Emsg("Config",who,ProtoID,"argument string too long");
00216 return 0;
00217 }
00218 *bp++ = oct;
00219 return 1;
00220 }
00221
00222
00223
00224
00225 XrdSecPManager XrdSecServer::PManager;
00226
00227
00228
00229 XrdSecServer::XrdSecServer(XrdSysLogger *lp) : eDest(0, "sec_")
00230 {
00231
00232
00233
00234 eDest.logger(lp);
00235 bpFirst = 0;
00236 bpLast = 0;
00237 bpDefault = 0;
00238 STBlen = 4096;
00239 STBuff = (char *)malloc(STBlen);
00240 *STBuff = '\0';
00241 SToken = STBuff;
00242 SecTrace = new XrdOucTrace(&eDest);
00243 if (getenv("XRDDEBUG") || getenv("XrdSecDEBUG")) SecTrace->What = TRACE_ALL;
00244 Enforce = 0;
00245 implauth = 0;
00246 }
00247
00248
00249
00250
00251
00252 const char *XrdSecServer::getParms(int &size, const char *hname)
00253 {
00254 EPNAME("getParms")
00255 XrdSecProtBind *bp;
00256
00257
00258
00259 if (!hname) bp = 0;
00260 else if ((bp = bpFirst)) while(bp && !bp->Match(hname)) bp = bp->next;
00261
00262
00263
00264 if (!bp) bp = bpDefault;
00265 if (bp->SecToken.buffer)
00266 {DEBUG(hname <<" sectoken=" <<bp->SecToken.buffer);
00267 size = bp->SecToken.size;
00268 return bp->SecToken.buffer;
00269 }
00270
00271 DEBUG(hname <<" sectoken=''");
00272 size = 0;
00273 return (const char *)0;
00274 }
00275
00276
00277
00278
00279
00280 XrdSecProtocol *XrdSecServer::getProtocol(const char *host,
00281 const struct sockaddr &hadr,
00282 const XrdSecCredentials *cred,
00283 XrdOucErrInfo *einfo)
00284 {
00285 XrdSecProtBind *bp;
00286 XrdSecPMask_t pnum;
00287 XrdSecCredentials myCreds;
00288 const char *msgv[8];
00289
00290
00291
00292
00293 if (!cred) {myCreds.buffer=(char *)"host"; myCreds.size = 4; cred=&myCreds;}
00294 else if (cred->size < 1 || !(cred->buffer))
00295 {einfo->setErrInfo(EACCES,
00296 (char *)"No authentication credentials supplied.");
00297 return 0;
00298 }
00299
00300
00301
00302
00303 if (Enforce)
00304 {if ((pnum = PManager.Find(cred->buffer)))
00305 {if (bpFirst && (bp = bpFirst->Find(host))
00306 && !(bp->ValidProts & pnum))
00307 {msgv[0] = host;
00308 msgv[1] = " not allowed to authenticate using ";
00309 msgv[2] = cred->buffer;
00310 msgv[3] = " protocol.";
00311 einfo->setErrInfo(EACCES, msgv, 4);
00312 return 0;
00313 }
00314 }
00315 else {msgv[0] = cred->buffer;
00316 msgv[1] = " security protocol is not supported.";
00317 einfo->setErrInfo(EPROTONOSUPPORT, msgv, 2);
00318 return 0;
00319 }
00320 }
00321
00322
00323
00324
00325 return PManager.Get(host, hadr, cred->buffer, einfo);
00326 }
00327
00328
00329
00330
00331
00332
00333
00334
00335 #define TS_Xeq(x,m) if (!strcmp(x,var)) return m(Config,Eroute);
00336
00337 #define TS_Str(x,m) if (!strcmp(x,var)) {free(m); m = strdup(val); return 0;}
00338
00339 #define TS_Chr(x,m) if (!strcmp(x,var)) {m = val[0]; return 0;}
00340
00341 #define TS_Bit(x,m,v) if (!strcmp(x,var)) {m = v; return 0;}
00342
00343 #define Max(x,y) (x > y ? x : y)
00344
00345
00346
00347
00348
00349 int XrdSecServer::Configure(const char *cfn)
00350
00351
00352
00353
00354
00355
00356
00357 {
00358 int NoGo;
00359 char *var;
00360
00361
00362
00363 eDest.Say("++++++ Authentication system initialization started.");
00364
00365
00366
00367 NoGo = ConfigFile(cfn);
00368
00369
00370
00371 var = (NoGo > 0 ? (char *)"failed." : (char *)"completed.");
00372 eDest.Say("------ Authentication system initialization ", var);
00373 return (NoGo > 0);
00374 }
00375
00376
00377
00378
00379
00380 int XrdSecServer::ConfigFile(const char *ConfigFN)
00381
00382
00383
00384
00385
00386
00387
00388
00389 {
00390 char *var;
00391 int cfgFD, retc, NoGo = 0, recs = 0;
00392 XrdOucEnv myEnv;
00393 XrdOucStream Config(&eDest, getenv("XRDINSTANCE"), &myEnv, "=====> ");
00394 XrdSecProtParm *pp;
00395
00396
00397
00398 if (!ConfigFN || !*ConfigFN)
00399 {eDest.Emsg("Config", "Authentication configuration file not specified.");
00400 return 1;
00401 }
00402
00403
00404
00405 if ( (cfgFD = open(ConfigFN, O_RDONLY, 0)) < 0)
00406 {eDest.Emsg("Config", errno, "opening config file", ConfigFN);
00407 return 1;
00408 }
00409
00410
00411
00412 Config.Attach(cfgFD); Config.Tabs(0);
00413 while((var = Config.GetMyFirstWord()))
00414 {if (!strncmp(var, "sec.", 4))
00415 {recs++;
00416 if (ConfigXeq(var+4, Config, eDest)) {Config.Echo(); NoGo = 1;}
00417 }
00418 }
00419
00420
00421
00422 if ((retc = Config.LastError()))
00423 NoGo = eDest.Emsg("Config",-retc,"reading config file", ConfigFN);
00424 else {char buff[128];
00425 snprintf(buff, sizeof(buff),
00426 " %d authentication directives processed in ", recs);
00427 eDest.Say("Config", buff, ConfigFN);
00428 }
00429 Config.Close();
00430
00431
00432
00433 if (NoGo || ProtBind_Complete(eDest) ) NoGo = 1;
00434 else if ((pp = XrdSecProtParm::First))
00435 {NoGo = 1;
00436 while(pp) {eDest.Emsg("Config", "protparm", pp->ProtoID,
00437 "does not have a matching protocol.");
00438 pp = pp->Next;
00439 }
00440 }
00441
00442
00443
00444 return NoGo;
00445 }
00446
00447
00448
00449
00450
00451
00452
00453
00454 int XrdSecServer::ConfigXeq(char *var, XrdOucStream &Config, XrdSysError &Eroute)
00455 {
00456
00457
00458
00459 TS_Xeq("protbind", xpbind);
00460 TS_Xeq("protocol", xprot);
00461 TS_Xeq("protparm", xpparm);
00462 TS_Xeq("trace", xtrace);
00463
00464
00465
00466 Eroute.Say("Config warning: ignoring unknown directive '",var,"'.");
00467 Config.Echo();
00468 return 0;
00469 }
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486 int XrdSecServer::xpbind(XrdOucStream &Config, XrdSysError &Eroute)
00487 {
00488 EPNAME("xpbind")
00489 char *val, *thost;
00490 XrdSecProtBind *bnow;
00491 char sectoken[4096], *secbuff = sectoken;
00492 int isdflt = 0, only = 0, anyprot = 0, noprot = 0, phost = 0;
00493 int sectlen = sizeof(sectoken)-1;
00494 XrdSecPMask_t PMask = 0;
00495 *secbuff = '\0';
00496
00497
00498
00499 val = Config.GetWord();
00500 if (!val || !val[0])
00501 {Eroute.Emsg("Config","protbind host not specified"); return 1;}
00502
00503
00504
00505 if ((isdflt = !strcmp("*", val))) bnow = bpDefault;
00506 else {bnow = bpFirst;
00507 while(bnow) if (!strcmp(bnow->thost, val)) break;
00508 else bnow = bnow->next;
00509 }
00510 if (bnow) {Eroute.Emsg("Config","duplicate protbind definition - ", val);
00511 return 1;
00512 }
00513 thost = strdup(val);
00514
00515
00516
00517 while((val = Config.GetWord()))
00518 {if (!strcmp(val, "none")) {noprot = 1; break;}
00519 if (!strcmp(val, "only")) {only = 1; Enforce = 1;}
00520 else if (!strcmp(val, "host")) {phost = 1; anyprot = 1;}
00521 else if (!PManager.Find(val))
00522 {Eroute.Emsg("Config","protbind", val,
00523 "protocol not previously defined.");
00524 return 1;
00525 }
00526 else if (add2token(Eroute, val, &secbuff, sectlen, PMask))
00527 {Eroute.Emsg("Config","Unable to bind protocols to",thost);
00528 return 1;
00529 } else anyprot = 1;
00530 }
00531
00532
00533
00534 if (val && (val = Config.GetWord()))
00535 {Eroute.Emsg("Config","conflicting protbind:", thost, val);
00536 return 1;
00537 }
00538
00539
00540
00541 if (!(anyprot || noprot))
00542 {Eroute.Emsg("Config","no protocols bound to", thost); return 1;}
00543 DEBUG("XrdSecConfig: Bound "<< thost<< " to "
00544 << (noprot ? "none" : (phost ? "host" : sectoken)));
00545
00546
00547
00548
00549 if (phost && *sectoken)
00550 {Eroute.Say("Config warning: 'protbind", thost,
00551 "host' negates all other bound protocols.");
00552 *sectoken = '\0';
00553 }
00554
00555
00556
00557 if (!strcmp("localhost", thost))
00558 {free(thost); thost = XrdNetDNS::getHostName();}
00559
00560
00561
00562 bnow = new XrdSecProtBind(thost,(noprot ? 0:sectoken),(only ? PMask:0));
00563
00564
00565
00566 if (isdflt) bpDefault = bnow;
00567 else {if (bpLast) bpLast->next = bnow;
00568 else bpFirst = bnow;
00569 bpLast = bnow;
00570 }
00571
00572
00573
00574 return 0;
00575 }
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598 int XrdSecServer::xprot(XrdOucStream &Config, XrdSysError &Eroute)
00599 {
00600 XrdSecProtParm *pp, myParms(&Eroute, "protocol");
00601 char *pap, *val, pid[XrdSecPROTOIDSIZE+1], *args = 0;
00602 char pathbuff[1024], *path = 0;
00603 int psize;
00604 XrdOucErrInfo erp;
00605 XrdSecPMask_t mymask = 0;
00606
00607
00608
00609 val = Config.GetWord();
00610 if (val && *val == '/')
00611 {strlcpy(pathbuff, val, sizeof(pathbuff)); path = pathbuff;
00612 val = Config.GetWord();
00613 }
00614 if (!val || !val[0])
00615 {Eroute.Emsg("Config","protocol id not specified"); return 1;}
00616
00617
00618
00619 if (strlen(val) > XrdSecPROTOIDSIZE)
00620 {Eroute.Emsg("Config","protocol id too long - ", val); return 1;}
00621
00622 if (PManager.Find(val))
00623 {Eroute.Say("Config warning: protocol ",val," previously defined.");
00624 strcpy(pid, val);
00625 return add2token(Eroute, pid, &STBuff, STBlen, mymask);}
00626
00627
00628
00629
00630 if (!strcmp("host", val))
00631 {if (Config.GetWord())
00632 {Eroute.Emsg("Config", "Builtin host protocol does not accept parms.");
00633 return 1;
00634 }
00635 implauth = 1;
00636 return 0;
00637 }
00638
00639
00640
00641 strcpy(pid, val);
00642 while((args = Config.GetWord())) if (!myParms.Cat(args)) return 1;
00643 if ((pp = myParms.Find(pid, 1)))
00644 {if ((*myParms.Result(psize) && !myParms.Insert('\n'))
00645 || !myParms.Cat(pp->Result(psize))) return 1;
00646 else delete pp;
00647 }
00648
00649
00650
00651 pap = myParms.Result(psize);
00652 if (!PManager.Load(&erp, 's', pid, (psize ? pap : 0), path))
00653 {Eroute.Emsg("Config", erp.getErrText()); return 1;}
00654
00655
00656
00657 return add2token(Eroute, pid, &STBuff, STBlen, mymask);
00658 }
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677 int XrdSecServer::xpparm(XrdOucStream &Config, XrdSysError &Eroute)
00678 {
00679 XrdSecProtParm *pp;
00680 char *val, pid[XrdSecPROTOIDSIZE+1];
00681
00682
00683
00684 val = Config.GetWord();
00685 if (!val || !val[0])
00686 {Eroute.Emsg("Config","protparm protocol not specified"); return 1;}
00687
00688
00689
00690 if (!strcmp("host", val))
00691 {Eroute.Emsg("Config", "Builtin host protocol does not accept protparms.");
00692 return 1;
00693 }
00694
00695
00696
00697 if (strlen(val) > XrdSecPROTOIDSIZE)
00698 {Eroute.Emsg("Config","protocol id too long - ", val); return 1;}
00699
00700 if (PManager.Find(val))
00701 {Eroute.Emsg("Config warning: protparm protocol ",val," already defined.");
00702 return 0;
00703 }
00704
00705 strcpy(pid, val);
00706
00707
00708
00709 if (!(val = Config.GetWord()))
00710 {Eroute.Emsg("Config","protparm", pid, "parameter not specified");
00711 return 1;
00712 }
00713
00714
00715
00716 if ((pp = XrdSecProtParm::Find(pid))) {if (!pp->Insert('\n')) return 1;}
00717 else {pp = new XrdSecProtParm(&Eroute, "protparm");
00718 pp->setProt(pid);
00719 pp->Add();
00720 }
00721
00722
00723
00724 do {if (!pp->Cat(val)) return 1;} while((val = Config.GetWord()));
00725 return 0;
00726 }
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742 int XrdSecServer::xtrace(XrdOucStream &Config, XrdSysError &Eroute)
00743 {
00744 static struct traceopts {const char *opname; int opval;} tropts[] =
00745 {
00746 {"all", TRACE_ALL},
00747 {"debug", TRACE_Debug},
00748 {"auth", TRACE_Authen},
00749 {"authentication", TRACE_Authen}
00750 };
00751 int i, neg, trval = 0, numopts = sizeof(tropts)/sizeof(struct traceopts);
00752 char *val;
00753
00754 val = Config.GetWord();
00755 if (!val || !val[0])
00756 {Eroute.Emsg("Config", "trace option not specified"); return 1;}
00757 while (val && val[0])
00758 {if (!strcmp(val, "off")) trval = 0;
00759 else {if ((neg = (val[0] == '-' && val[1]))) val++;
00760 for (i = 0; i < numopts; i++)
00761 {if (!strcmp(val, tropts[i].opname))
00762 {if (neg) trval &= ~tropts[i].opval;
00763 else trval |= tropts[i].opval;
00764 break;
00765 }
00766 }
00767 if (i >= numopts)
00768 Eroute.Say("Config warning: ignoring invalid trace option '", val, "'.");
00769 }
00770 val = Config.GetWord();
00771 }
00772
00773 SecTrace->What = (SecTrace->What & ~TRACE_Authenxx) | trval;
00774
00775
00776
00777 #ifndef NODEBUG
00778 if (QTRACE(Debug)) PManager.setDebug(1);
00779 else PManager.setDebug(0);
00780 #endif
00781 return 0;
00782 }
00783
00784
00785
00786
00787
00788
00789
00790
00791 int XrdSecServer::add2token(XrdSysError &Eroute, char *pid,
00792 char **tokbuff, int &toklen, XrdSecPMask_t &pmask)
00793 {
00794 int i;
00795 char *pargs;
00796 XrdSecPMask_t protnum;
00797
00798
00799
00800 if (!(protnum = PManager.Find(pid, &pargs)))
00801 {Eroute.Emsg("Config","Protocol",pid,"not found after being added!");
00802 return 1;
00803 }
00804
00805
00806
00807 i = 4+strlen(pid)+strlen(pargs);
00808 if (i >= toklen)
00809 {Eroute.Emsg("Config","Protocol",pid,"parms exceed overall maximum!");
00810 return 1;
00811 }
00812
00813
00814
00815 i = sprintf(*tokbuff, "&P=%s%s%s", pid, (*pargs ? "," : ""), pargs);
00816 toklen -= i;
00817 *tokbuff += i;
00818 pmask |= protnum;
00819 return 0;
00820 }
00821
00822
00823
00824
00825
00826 int XrdSecServer::ProtBind_Complete(XrdSysError &Eroute)
00827 {
00828 EPNAME("ProtBind_Complete")
00829 XrdOucErrInfo erp;
00830
00831
00832
00833 if (!bpDefault)
00834 {if (!*SToken) {Eroute.Say("Config warning: No protocols defined; "
00835 "only host authentication available.");
00836 implauth = 1;
00837 }
00838 else if (implauth)
00839 {Eroute.Say("Config warning: enabled builtin host "
00840 "protocol negates default use of any other protocols.");
00841 *SToken = '\0';
00842 }
00843 bpDefault = new XrdSecProtBind(strdup("*"), SToken);
00844 DEBUG("Default sectoken built: '" <<SToken <<"'");
00845 }
00846
00847
00848
00849
00850
00851 if (implauth && !PManager.Load(&erp, 's', "host", 0, 0))
00852 {Eroute.Emsg("Config", erp.getErrText()); return 1;}
00853
00854
00855
00856 free(SToken); SToken = STBuff = 0; STBlen = 0;
00857 return 0;
00858 }
00859
00860
00861
00862
00863
00864 extern "C"
00865 {
00866 XrdSecService *XrdSecgetService(XrdSysLogger *lp, const char *cfn)
00867 {
00868 XrdSecServer *SecServer = new XrdSecServer(lp);
00869
00870
00871
00872 if (SecServer->Configure(cfn)) return 0;
00873
00874
00875
00876 return (XrdSecService *)SecServer;
00877 }
00878 }