XRootD
Loading...
Searching...
No Matches
XrdCmsBlackList.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d C m s B l a c k L i s t . c c */
4/* */
5/* (c) 2014 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 <cstdio>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <fcntl.h>
35
36#include "Xrd/XrdScheduler.hh"
37
40#include "XrdCms/XrdCmsTrace.hh"
41#include "XrdCms/XrdCmsUtils.hh"
42
43#include "XrdNet/XrdNetAddr.hh"
44
45#include "XrdOuc/XrdOucEnv.hh"
46#include "XrdOuc/XrdOucTList.hh"
49
50#include "XrdSys/XrdSysError.hh"
53
54/******************************************************************************/
55/* L o c a l C l a s s e s */
56/******************************************************************************/
57
59 {public:
60 void Add(XrdOucTList *tP)
61 {if (last) last->next = tP;
62 else first = tP;
63 last = tP;
64 }
65
66 XrdOucTList **Array(int &anum)
67 {XrdOucTList *tP = first;
68 anum = Count();
69 if (!anum) return 0;
70 XrdOucTList **vec = new XrdOucTList *[anum];
71 for (int i = 0; i < anum; i++) {vec[i] = tP; tP = tP->next;}
72 first = last = 0;
73 return vec;
74 }
75
76 int Count()
77 {XrdOucTList *tP = first;
78 int n = 0;
79 while(tP) {tP=tP->next; n++;}
80 return n;
81 }
82
84 {XrdOucTList *tP = first;
85 first = last = 0;
86 return tP;
87 }
88
89 bool Include(const char *item, int &i)
90 {XrdOucTList *tP = first;
91 i = 0;
92 while(tP && strcmp(item,tP->text)) {tP=tP->next; i++;}
93 if (!tP) {Add(new XrdOucTList(item)); return false;}
94 return true;
95 }
96
97 BL_Grip() : first(0), last(0) {}
98
100 while((tP = first)) {first = tP->next; delete tP;}
101 last = 0;
102 }
103
104 private:
105 XrdOucTList *first;
106 XrdOucTList *last;
107 };
108
110 {long long info;
111 struct {short flags;
112 short pfxLen;
113 short sfxLen;
114 short totLen;
115 } v;
116 enum {exact = 0x8000,
117 redir = 0x4000,
118 rmask = 0x00ff
119 };
120 };
121
122/******************************************************************************/
123/* G l o b a l O b j e c t s */
124/******************************************************************************/
125
126namespace XrdCms
127{
129
131
133 {public:
134 void Ring();
137 };
139
141
143
146
147 char *blFN;
148
149 time_t blTime = 0;
150
151 int blChk;
152 int blRcnt = 0;
153 bool isWList=false;
154
155 extern XrdSysError Say;
156};
157
158using namespace XrdCms;
159
160/******************************************************************************/
161/* Private: A d d B L */
162/******************************************************************************/
163
164bool XrdCmsBlackList::AddBL(BL_Grip &bAnchor, char *hSpec,
165 BL_Grip *rAnchor, char *rSpec)
166{
167 const char *bwTag = (isWList ? "whitelist '" : "blacklist '");
168 XrdNetAddr blAddr;
169 XrdOucTList *bP;
170 BL_Info Hdr;
171 const char *eText;
172 char *Ast, blBuff[512];
173
174// Initialize the header
175//
176 Hdr.info = 0;
177
178// Check if we are processing a redirect
179//
180 if (rSpec)
181 {int i = AddRD(rAnchor, rSpec, hSpec);
182 if (i < 0) return false;
183 Hdr.v.flags |= BL_Info::redir | i;
184 }
185
186// Get the full name if this is not generic
187//
188 if (!(Ast = index(hSpec, '*')))
189 {if ((eText = blAddr.Set(hSpec,0)))
190 {snprintf(blBuff, sizeof(blBuff), "'; %s", eText);
191 Say.Say("Config ", "Unable to ", bwTag, hSpec, blBuff);
192 return false;
193 }
194 blAddr.Format(blBuff, sizeof(blBuff), XrdNetAddrInfo::fmtName,
196 hSpec = blBuff;
197 Hdr.v.flags |= BL_Info::exact;
198 } else {
199 Hdr.v.pfxLen = Ast - hSpec;
200 Hdr.v.sfxLen = strlen(hSpec + Hdr.v.pfxLen + 1);
201 Hdr.v.totLen = Hdr.v.pfxLen + Hdr.v.sfxLen;
202 }
203
204// Add specification to the list
205//
206 bP = new XrdOucTList(hSpec, &Hdr.info);
207 bAnchor.Add(bP);
208 return true;
209}
210
211/******************************************************************************/
212/* A d d R D */
213/******************************************************************************/
214
215int XrdCmsBlackList::AddRD(BL_Grip *rAnchor, char *rSpec, char *hSpec)
216{
217 XrdOucTList *rP, *rList = 0;
218 char *rTarg;
219 int ival;
220 bool aOK = true;
221
222// First see if we have this entry already
223//
224 if (rAnchor[0].Include(rSpec, ival)) return ival;
225
226// Make sure we did not exceed the maximum number of redirect entries
227//
228 if (ival > BL_Info::rmask)
229 {Say.Say("Config ", "Too many different redirects at ", hSpec,
230 "redirect", rSpec);
231 return -1;
232 }
233
234// We now ned to tokenize the specification
235//
236 XrdOucTokenizer rToks(rSpec);
237 rToks.GetLine();
238
239// Process each item
240//
241 while((rTarg = rToks.GetToken()) && *rTarg) aOK &= AddRD(&rList,rTarg,hSpec);
242 if (!aOK) return -1;
243
244// Flatten the list and add it to out list of redirect targets
245//
246 rP = Flatten(rList, rList->val);
247 rAnchor[1].Add(rP);
248
249// Delete the rlist
250//
251 while((rP = rList)) {rList = rList->next; delete rP;}
252
253// All done
254//
255 return ival;
256}
257
258/******************************************************************************/
259
260bool XrdCmsBlackList::AddRD(XrdOucTList **rList, char *rSpec, char *hSpec)
261{
262 char *rPort;
263
264// Screen out IPV6 specifications
265//
266 if (*rSpec == '[')
267 {if (!(rPort = index(rSpec, ']')))
268 {Say.Say("Config ","Invalid ",hSpec," redirect specification - ",rSpec);
269 return -1;
270 }
271 } else rPort = rSpec;
272
273// Grab the port number
274//
275 if ((rPort = index(rPort, ':')))
276 {if (!(*(rPort+1))) rPort = 0;
277 else *rPort++ = '\0';
278 }
279
280// We should have a port specification now
281//
282 if (!rPort) {Say.Say("Config ", "redirect port not specified for ", hSpec);
283 return -1;
284 }
285
286// Convert this to a list of redirect targets
287//
288 return XrdCmsUtils::ParseMan(&Say, rList, rSpec, rPort, 0, true);
289}
290
291/******************************************************************************/
292/* D o I t */
293/******************************************************************************/
294
296{
297 struct stat Stat;
298 XrdOucTList **blOldRedr = 0, **blNewRedr = 0, *blNewReal = 0, *tP = 0, *nP;
299 int rc, blOldRcnt = 0, blNewRcnt;
300 bool doUpdt = false, doPrt = false;
301
302// Check if the black list file was modified
303//
304 rc = stat(blFN, &Stat);
305 if ((!rc && blTime != Stat.st_mtime) || (rc && blTime && errno == ENOENT))
306 {blTime = (rc ? 0 : Stat.st_mtime);
307 if (GetBL(blNewReal, blNewRedr, blNewRcnt))
308 {blMutex.Lock();
309 tP = blReal; blReal = blNewReal;
310 blOldRedr = blRedr; blRedr = blNewRedr;
311 blOldRcnt = blRcnt; blRcnt = blNewRcnt;
312 blMutex.UnLock();
313 if (!blReal && tP) doPrt = !isWList;
314 else blMN.Ring();
315 doUpdt = true;
316 }
317 }
318
319// Delete any list we need to release
320//
321 while(tP)
322 {if (doPrt) Say.Say("Config ", tP->text, " removed from blacklist.");
323 nP = tP->next; delete tP; tP = nP;
324 }
325
326// Delete the old redirect array
327//
328 if (blOldRedr)
329 {for (int i = 0; i < blOldRcnt; i++) delete blOldRedr[i];
330 delete [] blOldRedr;
331 }
332
333// Do real-time update if need be
334//
335 if (doUpdt) blCluster->BlackList(blReal);
336
337// Reschedule this to check any modifications
338//
339 blSched->Schedule((XrdJob *)&BlackList, time(0) + blChk);
340}
341
342/******************************************************************************/
343/* Private: F l a t t e n */
344/******************************************************************************/
345
346XrdOucTList *XrdCmsBlackList::Flatten(XrdOucTList *tList, int tPort)
347{
348 XrdOucTList *tP = tList;
349 char buff[4096], bPort[8], *bP = buff;
350 int n, pLen, bleft = sizeof(buff);
351 short xdata[4] = {0};
352
353// Convert port to a suffix
354//
355 pLen = sprintf(bPort, ":%d", tPort);
356 *buff = 0;
357
358// Fill the buffer and truncate as necessary
359//
360 while(tP)
361 {n = strlen(tP->text)+pLen+2;
362 if (n >= bleft) break;
363 n = sprintf(bP, " %s%s", tP->text, bPort);
364 bP += n; bleft -= n;
365 tP = tP->next;
366 }
367
368// Get actual length including null byte
369//
370 xdata[0] = strlen(buff+1) + 1;
371 xdata[1] = xdata[0] + sizeof(short);
372 xdata[2] = htons(xdata[0]);
373
374// Create a new tlist item
375//
376 tP = new XrdOucTList(buff+1, xdata);
377 return tP;
378}
379
380/******************************************************************************/
381/* Private: G e t B L */
382/******************************************************************************/
383
384bool XrdCmsBlackList::GetBL(XrdOucTList *&bList,
385 XrdOucTList **&rList, int &rcnt, bool isInit)
386{
387 static int msgCnt = 0;
388 XrdOucEnv myEnv;
389 XrdOucStream blFile(&Say, getenv("XRDINSTANCE"), &myEnv, "=====> ");
390 BL_Grip bAnchor, rAnchor[2];
391 const char *fType, *oEmsg, *rEmsg;
392 char *hsp, *rsp, hspBuff[512], rSpec[4096];
393 int blFD, retc;
394 bool aOK = true;
395
396// Setup message plugins
397//
398 if (isWList)
399 {oEmsg = "open whitelist file";
400 rEmsg = "read whitelist file";
401 fType = "whitelist";
402 } else {
403 oEmsg = "open blacklist file";
404 rEmsg = "read blacklist file";
405 fType = "blacklist";
406 }
407
408// Open the config file
409//
410 if ( (blFD = open(blFN, O_RDONLY, 0)) < 0)
411 {if (errno == ENOENT) return true;
412 if (!(msgCnt & 0x03)) Say.Emsg("GetBL", errno, oEmsg, blFN);
413 return false;
414 }
415 blFile.Attach(blFD, 4096);
416
417// Trace this now
418//
419 Say.Say("Config processing ", fType, " file ", blFN);
420
421// Start reading the black list
422//
423 while((hsp = blFile.GetMyFirstWord()))
424 {if (strlen(hsp) >= sizeof(hspBuff))
425 {Say.Say("Config ", hsp, " is too long."); aOK = false; continue;}
426 strcpy(hspBuff, hsp); hsp = hspBuff;
427 if ( (rsp = blFile.GetWord()) && *rsp)
428 {if (strcmp("redirect", rsp))
429 {Say.Say("Config ", rsp, " is an invalid modifier for ", hsp);
430 aOK = false;
431 continue;
432 }
433 *rSpec = 0; rsp = rSpec;
434 if (!blFile.GetRest(rSpec, sizeof(rSpec)))
435 {Say.Say("Config ", "redirect target too long ", hsp);
436 aOK = false;
437 continue;
438 }
439 if (!(*rSpec))
440 {Say.Say("Config ", "redirect target missing for ", hsp);
441 aOK = false;
442 continue;
443 }
444 } else rsp = 0;
445 blFile.noEcho();
446 if (!AddBL(bAnchor, hsp, rAnchor, rsp)) aOK = false;
447 }
448
449// Now check if any errors occurred during file i/o
450//
451 if ((retc = blFile.LastError()))
452 {Say.Emsg("GetBL", retc, rEmsg, blFN); aOK = false;}
453 else if (!aOK) Say.Emsg("GetBL", "Error(s) encountered in",fType,"file!");
454
455// Return ending status
456//
457 blFile.Close();
458 bList = ((aOK || isInit) ? bAnchor.Export() : nullptr);
459 rList = rAnchor[1].Array(rcnt);
460 return aOK;
461}
462
463/******************************************************************************/
464/* I n i t */
465/******************************************************************************/
466
468 const char *blfn, int chkt)
469{
470 struct stat Stat;
471 const char *cfn;
472
473// Copy out the scheduler and cluster pointers
474//
475 blSched = sP;
476 blCluster = cP;
477
478// Determine if this is a black or white list
479//
480 if (chkt < 0) {isWList = true; chkt = -chkt;}
481
482// Copy the file path (this is a one time call during config)
483//
484 if (blfn) blFN = strdup(blfn);
485 else if (!(cfn = getenv("XRDCONFIGFN"))) return;
486 else {char pBuff[2048], *Slash;
487 strcpy(pBuff, cfn);
488 if (!(Slash = rindex(pBuff, '/'))) return;
489 strcpy(Slash+1, (isWList ? "cms.whitelist" : "cms.blacklist"));
490 blFN = strdup(pBuff);
491 }
492
493// Check if the black list file exists, it might not. If it does, process it
494//
495 if (!stat(blFN, &Stat))
496 {blTime = Stat.st_mtime;
497 GetBL(blReal, blRedr, blRcnt, /* isInit = */ true);
498 if (blReal) blMN.Ring();
499 }
500
501// Schedule this to recheck any modifications
502//
503 blChk = chkt;
504 blSched->Schedule((XrdJob *)&BlackList, time(0) + chkt);
505
506// Add ourselves to the midnight run list
507//
509}
510
511/******************************************************************************/
512/* P r e s e n t */
513/******************************************************************************/
514
515int XrdCmsBlackList::Present(const char *hName, XrdOucTList *bList,
516 char *rBuff, int rBLen)
517{
518 BL_Info Hdr;
519 int hLen, retval;
520 bool doUnLk;
521
522// Check if we really have a name here
523//
524 if (!hName || !blSched) return 0;
525
526// Check if we need to supply our list
527//
528 if (bList) doUnLk = false;
529 else {doUnLk = true;
530 blMutex.Lock();
531 bList = blReal;
532 }
533
534// By definition, if there is no list at all then everybody is allowed
535//
536 if (!bList)
537 {if (doUnLk) blMutex.UnLock();
538 return 0;
539 }
540
541// Run through the list and try to compare
542//
543 hLen = strlen(hName);
544 while(bList)
545 {Hdr.info = bList->dval;
546 if (Hdr.v.flags & BL_Info::exact)
547 {if (!strcmp(hName, bList->text)) break;}
548 else if (hLen >= Hdr.v.totLen)
549 {if (!Hdr.v.pfxLen
550 || !strncmp(bList->text, hName, Hdr.v.pfxLen))
551 {if (!Hdr.v.sfxLen
552 || !strncmp(bList->text+Hdr.v.pfxLen+1,
553 hName + (hLen - Hdr.v.sfxLen),
554 Hdr.v.sfxLen)) break;
555 }
556 }
557 bList = bList->next;
558 }
559
560// If we have a black list check if we should redirect
561//
562 if (bList)
563 {if (!(Hdr.v.flags & BL_Info::redir)) retval = (isWList ? 0 : -1);
564 else {XrdOucTList *rP = blRedr[Hdr.v.flags & BL_Info::rmask];
565 if (rP)
566 {retval = rP->sval[1];
567 if (!rBuff || retval > rBLen) retval = -retval;
568 else {memcpy(rBuff, &(rP->sval[2]), sizeof(short));
569 memcpy(rBuff+sizeof(short), rP->text, rP->sval[0]);
570 }
571 } else retval = -1;
572 }
573 } else retval = (isWList ? -1 : 0);
574
575// Unlock ourselves if need be and return result
576//
577 if (doUnLk) blMutex.UnLock();
578 return retval;
579}
580
581/******************************************************************************/
582/* R i n g */
583/******************************************************************************/
584
586{
587 BL_Info Hdr;
588 XrdOucTList *tP;
589 const char *bwTag = (isWList ? "Whitelisting " : "Blacklisting ");
590
591// Get the list lock
592//
593 blMutex.Lock();
594 tP = blReal;
595
596// Print the list
597//
598 while(tP)
599 {Hdr.info = tP->dval;
600 if (!(Hdr.v.flags & BL_Info::redir))
601 Say.Say("Config ", bwTag, tP->text);
602 else {XrdOucTList *rP = blRedr[Hdr.v.flags & BL_Info::rmask];
603 Say.Say("Config Blacklisting ",tP->text," redirect ",rP->text);
604 }
605 tP = tP->next;
606 }
607
608// All done
609//
610 blMutex.UnLock();
611}
struct stat Stat
Definition XrdCks.cc:49
#define open
Definition XrdPosix.hh:71
#define stat(a, b)
Definition XrdPosix.hh:96
void Add(XrdOucTList *tP)
XrdOucTList ** Array(int &anum)
XrdOucTList * Export()
bool Include(const char *item, int &i)
void DoIt()
Time driven method for checking black list file.
static int Present(const char *hName, XrdOucTList *bList=0, char *rbuff=0, int rblen=0)
static void Init(XrdScheduler *sP, XrdCmsCluster *cP, const char *blfn, int chkt=600)
virtual void BlackList(XrdOucTList *blP)
static bool ParseMan(XrdSysError *eDest, XrdOucTList **oldMans, char *hSpec, char *hPort, int *sPort=0, bool hush=false)
void Ring()
This method gets called at midnight.
static const int noPort
Do not add port number.
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
@ fmtName
Hostname if it is resolvable o/w use fmtAddr.
const char * Set(const char *hSpec, int pNum=PortInSpec)
XrdOucTList * next
void Schedule(XrdJob *jp)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
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)
XrdSysLogger * logger(XrdSysLogger *lp=0)
void AtMidnight(Task *mnTask)
XrdCmsBlackList BlackList
XrdSysError Say
XrdCmsCluster * blCluster
XrdOucTList * blReal
XrdOucTList ** blRedr
time_t blTime
XrdSysMutex blMutex
MidNightTask blMN
XrdScheduler * blSched
struct BL_Info::@81 v
long long info