XRootD
XrdOucUtils.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d O u c U t i l s . 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 <cctype>
32 #include <grp.h>
33 #include <cstdio>
34 #include <list>
35 #include <vector>
36 #include <unordered_set>
37 #include <algorithm>
38 
39 #include <regex.h>
40 
41 #ifdef WIN32
42 #include <direct.h>
43 #include "XrdSys/XrdWin32.hh"
44 #else
45 #include <fcntl.h>
46 #include <math.h>
47 #include <pwd.h>
48 #include <sys/stat.h>
49 #include <sys/types.h>
50 #endif
51 #include <map>
52 #include "XrdNet/XrdNetUtils.hh"
53 #include "XrdOuc/XrdOucCRC.hh"
54 #include "XrdOuc/XrdOucEnv.hh"
55 #include "XrdOuc/XrdOucSHA3.hh"
56 #include "XrdOuc/XrdOucStream.hh"
57 #include "XrdOuc/XrdOucString.hh"
58 #include "XrdOuc/XrdOucUtils.hh"
60 #include "XrdSys/XrdSysE2T.hh"
61 #include "XrdSys/XrdSysError.hh"
62 #include "XrdSys/XrdSysPlatform.hh"
63 #include "XrdSys/XrdSysPthread.hh"
64 
65 #ifndef ENODATA
66 #define ENODATA ENOATTR
67 #endif
68 
69 /******************************************************************************/
70 /* L o c a l M e t h o d s */
71 /******************************************************************************/
72 
73 namespace
74 {
75 struct idInfo
76 { time_t Expr;
77  char *Name;
78 
79  idInfo(const char *name, time_t keep)
80  : Expr(time(0)+keep), Name(strdup(name)) {}
81  ~idInfo() {free(Name);}
82 };
83 
84 typedef std::map<unsigned int, struct idInfo*> idMap_t;
85 
86 idMap_t gidMap;
87 idMap_t uidMap;
88 XrdSysMutex idMutex;
89 
90 void AddID(idMap_t &idMap, unsigned int id, const char *name, time_t keepT)
91 {
92  std::pair<idMap_t::iterator,bool> ret;
93  idInfo *infoP = new idInfo(name, keepT);
94 
95  idMutex.Lock();
96  ret = idMap.insert(std::pair<unsigned int, struct idInfo*>(id, infoP));
97  if (ret.second == false) delete infoP;
98  idMutex.UnLock();
99 }
100 
101 int LookUp(idMap_t &idMap, unsigned int id, char *buff, int blen)
102 {
103  idMap_t::iterator it;
104  int luRet = 0;
105 
106  idMutex.Lock();
107  it = idMap.find(id);
108  if (it != idMap.end())
109  {if (it->second->Expr <= time(0))
110  {delete it->second;
111  idMap.erase(it);
112  } else {
113  if (blen > 0) luRet = snprintf(buff, blen, "%s", it->second->Name);
114  }
115  }
116  idMutex.UnLock();
117  return luRet;
118 }
119 }
120 
121 /******************************************************************************/
122 /* a r g L i s t */
123 /******************************************************************************/
124 
125 int XrdOucUtils::argList(char *args, char **argV, int argC)
126 {
127  char *aP = args;
128  int j;
129 
130 // Construct the argv array based on passed command line.
131 //
132 for (j = 0; j < argC; j++)
133  {while(*aP == ' ') aP++;
134  if (!(*aP)) break;
135 
136  if (*aP == '"' || *aP == '\'')
137  {argV[j] = aP+1;
138  aP = index(aP+1, *aP);
139  if (!aP || (*(aP+1) != ' ' && *(aP+1)))
140  {if (!j) argV[0] = 0; return -EINVAL;}
141  *aP++ = '\0';
142  } else {
143  argV[j] = aP;
144  if ((aP = index(aP+1, ' '))) *aP++ = '\0';
145  else {j++; break;}
146  }
147 
148  }
149 
150 // Make sure we did not overflow the vector
151 //
152  if (j > argC-1) return -E2BIG;
153 
154 // End list with a null pointer and return the actual number of arguments
155 //
156  argV[j] = 0;
157  return j;
158 }
159 
160 /******************************************************************************/
161 /* b i n 2 h e x */
162 /******************************************************************************/
163 
164 char *XrdOucUtils::bin2hex(char *inbuff, int dlen, char *buff, int blen,
165  bool sep)
166 {
167  static const char hv[] = "0123456789abcdef";
168  char *outbuff = buff;
169  for (int i = 0; i < dlen && blen > 2; i++) {
170  *outbuff++ = hv[(inbuff[i] >> 4) & 0x0f];
171  *outbuff++ = hv[ inbuff[i] & 0x0f];
172  blen -= 2;
173  if (sep && blen > 1 && ((i & 0x03) == 0x03 || i+1 == dlen))
174  {*outbuff++ = ' '; blen--;}
175  }
176  *outbuff = '\0';
177  return buff;
178 }
179 
180 /******************************************************************************/
181 /* h e x 2 b i n */
182 /******************************************************************************/
183 
184 int XrdOucUtils::hex2bin(const char *hex, char *bin, int size)
185 {
186  int len = 0, lo = -1, hi = -1;
187 
188  while (int c = *hex++) {
189  if (c == ' ' || c == '\n')
190  break;
191 
192  switch (c) {
193  case '0' ... '9':
194  c -= '0';
195  break;
196  case 'a' ... 'f':
197  c -= 'a' - 10;
198  break;
199  case 'A' ... 'F':
200  c -= 'A' - 10;
201  break;
202  default:
203  return -EINVAL;
204  }
205 
206  if (hi == -1)
207  hi = c;
208  else
209  lo = c;
210 
211  if (lo == -1)
212  continue;
213 
214  if (len >= size)
215  return -EOVERFLOW;
216 
217  bin[len++] = (hi << 4) | lo;
218  hi = lo = -1;
219  }
220  if (hi >= 0 || lo >= 0 || len == 0)
221  return -EINVAL;
222  return len;
223 }
224 
225 /******************************************************************************/
226 /* e n d s W i t h */
227 /******************************************************************************/
228 
229 bool XrdOucUtils::endsWith(const char *text, const char *ending, int endlen)
230 {
231  int tlen = strlen(text);
232 
233  return (tlen >= endlen && !strcmp(text+(tlen-endlen), ending));
234 }
235 
236 /******************************************************************************/
237 /* e T e x t */
238 /******************************************************************************/
239 
240 // eText() returns the text associated with the error.
241 // The text buffer pointer is returned.
242 
243 char *XrdOucUtils::eText(int rc, char *eBuff, int eBlen)
244 {
245  const char *etP;
246 
247 // Get error text
248 //
249  etP = XrdSysE2T(rc);
250 
251 // Copy the text and lower case the first letter
252 //
253  strlcpy(eBuff, etP, eBlen);
254 
255 // All done
256 //
257  return eBuff;
258 }
259 
260 /******************************************************************************/
261 /* d o I f */
262 /******************************************************************************/
263 
264 // doIf() parses "if [<hostlist>] [<conds>]"
265 // conds: <cond1> | <cond2> | <cond3>
266 // cond1: defined <varlist> [&& <conds>]
267 // cond2: exec <pgmlist> [&& <cond3>]
268 // cond3: named <namelist>
269 
270 // Returning 1 if true (i.e., this machine is one of the named hosts in hostlist
271 // and is running one of the programs pgmlist and named by one of the names in
272 // namelist).
273 // Return -1 (negative truth) if an error occurred.
274 // Otherwise, returns false (0). Some combination of hostlist, pgm, and
275 // namelist, must be specified.
276 
278  const char *what, const char *hname,
279  const char *nname, const char *pname)
280 {
281  static const char *brk[] = {"defined", "exec", "named", 0};
282  XrdOucEnv *theEnv = 0;
283  char *val;
284  int hostok, isDef;
285 
286 // Make sure that at least one thing appears after the if
287 //
288  if (!(val = Config.GetWord()))
289  {if (eDest) eDest->Emsg("Config","Host name missing after 'if' in", what);
290  return -1;
291  }
292 
293 // Check if we are one of the listed hosts
294 //
295  if (!is1of(val, brk))
296  {do {hostok = XrdNetUtils::Match(hname, val);
297  val = Config.GetWord();
298  } while(!hostok && val && !is1of(val, brk));
299  if (hostok)
300  { while(val && !is1of(val, brk)) val = Config.GetWord();
301  // No more directives
302  if (!val) return 1;
303  } else return 0;
304  }
305 
306 // Check if this is a defined test
307 //
308  while(!strcmp(val, "defined"))
309  {if (!(val = Config.GetWord()) || *val != '?')
310  {if (eDest)
311  {eDest->Emsg("Config","'?var' missing after 'defined' in",what);}
312  return -1;
313  }
314  // Get environment if we have none
315  //
316  if (!theEnv && (theEnv = Config.SetEnv(0))) Config.SetEnv(theEnv);
317  if (!theEnv && *(val+1) != '~') return 0;
318 
319  // Check if any listed variable is defined.
320  //
321  isDef = 0;
322  while(val && *val == '?')
323  {if (*(val+1) == '~' ? getenv(val+2) : theEnv->Get(val+1)) isDef=1;
324  val = Config.GetWord();
325  }
326  if (!val || !isDef) return isDef;
327  if (strcmp(val, "&&"))
328  {if (eDest)
329  {eDest->Emsg("Config",val,"is invalid for defined test in",what);}
330  return -1;
331  } else {
332  if (!(val = Config.GetWord()))
333  {if (eDest)
334  {eDest->Emsg("Config","missing keyword after '&&' in",what);}
335  return -1;
336  }
337  }
338  if (!is1of(val, brk))
339  {if (eDest)
340  {eDest->Emsg("Config",val,"is invalid after '&&' in",what);}
341  return -1;
342  }
343  }
344 
345 // Check if we need to compare program names (we are here only if we either
346 // passed the hostlist test or there was no hostlist present)
347 //
348  if (!strcmp(val, "exec"))
349  {if (!(val = Config.GetWord()) || !strcmp(val, "&&"))
350  {if (eDest)
351  {eDest->Emsg("Config","Program name missing after 'if exec' in",what);}
352  return -1;
353  }
354 
355  // Check if we are one of the programs.
356  //
357  if (!pname) return 0;
358  while(val && strcmp(val, pname))
359  if (!strcmp(val, "&&")) return 0;
360  else val = Config.GetWord();
361  if (!val) return 0;
362  while(val && strcmp(val, "&&")) val = Config.GetWord();
363  if (!val) return 1;
364 
365  if (!(val = Config.GetWord()))
366  {if (eDest)
367  {eDest->Emsg("Config","Keyword missing after '&&' in",what);}
368  return -1;
369  }
370  if (strcmp(val, "named"))
371  {if (eDest)
372  {eDest->Emsg("Config",val,"is invalid after '&&' in",what);}
373  return -1;
374  }
375  }
376 
377 // Check if we need to compare net names (we are here only if we either
378 // passed the hostlist test or there was no hostlist present)
379 //
380  if (!(val = Config.GetWord()))
381  {if (eDest)
382  {eDest->Emsg("Config","Instance name missing after 'if named' in", what);}
383  return -1;
384  }
385 
386 // Check if we are one of the names
387 //
388  if (!nname) return 0;
389  while(val && strcmp(val, nname)) val = Config.GetWord();
390 
391 // All done
392 //
393  return (val != 0);
394 }
395 
396 /******************************************************************************/
397 /* f i n d P g m */
398 /******************************************************************************/
399 
400 bool XrdOucUtils::findPgm(const char *pgm, XrdOucString& path)
401 {
402  struct stat Stat;
403 
404 // Check if only executable bit needs to be checked
405 //
406  if (*pgm == '/')
407  {if (stat(pgm, &Stat) || !(Stat.st_mode & S_IXOTH)) return false;
408  path = pgm;
409  return true;
410  }
411 
412 // Make sure we have the paths to check
413 //
414  const char *pEnv = getenv("PATH");
415  if (!pEnv) return false;
416 
417 // Setup to find th executable
418 //
419  XrdOucString prog, pList(pEnv);
420  int from = 0;;
421  prog += '/'; prog += pgm;
422 
423 // Find it!
424 //
425  while((from = pList.tokenize(path, from, ':')) != -1)
426  {path += prog;
427  if (!stat(path.c_str(), &Stat) && Stat.st_mode & S_IXOTH) return true;
428  }
429  return false;
430 }
431 
432 /******************************************************************************/
433 /* f m t B y t e s */
434 /******************************************************************************/
435 
436 int XrdOucUtils::fmtBytes(long long val, char *buff, int bsz)
437 {
438  static const long long Kval = 1024LL;
439  static const long long Mval = 1024LL*1024LL;
440  static const long long Gval = 1024LL*1024LL*1024LL;
441  static const long long Tval = 1024LL*1024LL*1024LL*1024LL;
442  char sName = ' ';
443  int resid;
444 
445 // Get correct scaling
446 //
447  if (val < 1024) return snprintf(buff, bsz, "%lld", val);
448  if (val < Mval) {val = val*10/Kval; sName = 'K';}
449  else if (val < Gval) {val = val*10/Mval; sName = 'M';}
450  else if (val < Tval) {val = val*10/Gval; sName = 'G';}
451  else {val = val*10/Tval; sName = 'T';}
452  resid = val%10LL; val = val/10LL;
453 
454 // Format it
455 //
456  return snprintf(buff, bsz, "%lld.%d%c", val, resid, sName);
457 }
458 
459 /******************************************************************************/
460 /* g e n P a t h */
461 /******************************************************************************/
462 
463 char *XrdOucUtils::genPath(const char *p_path, const char *inst,
464  const char *s_path)
465 {
466  char buff[2048];
467  int i = strlcpy(buff, p_path, sizeof(buff));
468 
469  if (buff[i-1] != '/') {buff[i++] = '/'; buff[i] = '\0';}
470  if (inst) {strcpy(buff+i, inst); strcat(buff, "/");}
471  if (s_path) strcat(buff, s_path);
472 
473  i = strlen(buff);
474  if (buff[i-1] != '/') {buff[i++] = '/'; buff[i] = '\0';}
475 
476  return strdup(buff);
477 }
478 
479 /******************************************************************************/
480 
481 int XrdOucUtils::genPath(char *buff, int blen, const char *path, const char *psfx)
482 {
483  int i, j;
484 
485  i = strlen(path);
486  j = (psfx ? strlen(psfx) : 0);
487  if (i+j+3 > blen) return -ENAMETOOLONG;
488 
489  strcpy(buff, path);
490  if (psfx)
491  {if (buff[i-1] != '/') buff[i++] = '/';
492  strcpy(&buff[i], psfx);
493  if (psfx[j-1] != '/') strcat(buff, "/");
494  }
495  return 0;
496 }
497 
498 /******************************************************************************/
499 /* g e t F i l e */
500 /******************************************************************************/
501 
502 char *XrdOucUtils::getFile(const char *path, int &rc, int maxsz, bool notempty)
503 {
504  struct stat Stat;
505  struct fdHelper
506  {int fd = -1;
507  fdHelper() {}
508  ~fdHelper() {if (fd >= 0) close(fd);}
509  } file;
510  char *buff;
511  int flen;
512 
513 // Preset RC
514 //
515  rc = 0;
516 
517 // Open the file in read mode
518 //
519  if ((file.fd = open(path, O_RDONLY)) < 0) {rc = errno; return 0;}
520 
521 // Get the size of the file
522 //
523  if (fstat(file.fd, &Stat)) {rc = errno; return 0;}
524 
525 // Check if the size exceeds the maximum allowed
526 //
527  if (Stat.st_size > maxsz) {rc = EFBIG; return 0;}
528 
529 // Make sure the file is not empty if empty files are disallowed
530 //
531  if (Stat.st_size == 0 && notempty) {rc = ENODATA; return 0;}
532 
533 // Allocate a buffer
534 //
535  if ((buff = (char *)malloc(Stat.st_size+1)) == 0)
536  {rc = errno; return 0;}
537 
538 // Read the contents of the file into the buffer
539 //
540  if (Stat.st_size)
541  {if ((flen = read(file.fd, buff, Stat.st_size)) < 0)
542  {rc = errno; free(buff); return 0;}
543  } else flen = 0;
544 
545 // Add null byte. recall the buffer is bigger by one byte
546 //
547  buff[flen] = 0;
548 
549 // Return the size aand the buffer
550 //
551  rc = flen;
552  return buff;
553 }
554 
555 /******************************************************************************/
556 /* g e t G I D */
557 /******************************************************************************/
558 
559 bool XrdOucUtils::getGID(const char *gName, gid_t &gID)
560 {
561  struct group Grp, *result;
562  char buff[65536];
563 
564  getgrnam_r(gName, &Grp, buff, sizeof(buff), &result);
565  if (!result) return false;
566 
567  gID = Grp.gr_gid;
568  return true;
569 }
570 
571 /******************************************************************************/
572 /* g e t U I D */
573 /******************************************************************************/
574 
575 bool XrdOucUtils::getUID(const char *uName, uid_t &uID, gid_t *gID)
576 {
577  struct passwd pwd, *result;
578  char buff[16384];
579 
580  getpwnam_r(uName, &pwd, buff, sizeof(buff), &result);
581  if (!result) return false;
582 
583  uID = pwd.pw_uid;
584  if (gID) *gID = pwd.pw_gid;
585 
586  return true;
587 }
588 
589 /******************************************************************************/
590 /* G i d N a m e */
591 /******************************************************************************/
592 
593 int XrdOucUtils::GidName(gid_t gID, char *gName, int gNsz, time_t keepT)
594 {
595  static const int maxgBsz = 256*1024;
596  static const int addGsz = 4096;
597  struct group *gEnt, gStruct;
598  char gBuff[1024], *gBp = gBuff;
599  int glen = 0, gBsz = sizeof(gBuff), aOK = 1;
600  int n, retVal = 0;
601 
602 // Get ID from cache, if allowed
603 //
604  if (keepT)
605  {int n = LookUp(gidMap, static_cast<unsigned int>(gID),gName,gNsz);
606  if (n > 0) return (n < gNsz ? n : 0);
607  }
608 
609 // Get the the group struct. If we don't have a large enough buffer, get a
610 // larger one and try again up to the maximum buffer we will tolerate.
611 //
612  while(( retVal = getgrgid_r(gID, &gStruct, gBp, gBsz, &gEnt) ) == ERANGE)
613  {if (gBsz >= maxgBsz) {aOK = 0; break;}
614  if (gBsz > addGsz) free(gBp);
615  gBsz += addGsz;
616  if (!(gBp = (char *)malloc(gBsz))) {aOK = 0; break;}
617  }
618 
619 // Return a group name if all went well
620 //
621  if (aOK && retVal == 0 && gEnt != NULL)
622  {if (keepT)
623  AddID(gidMap, static_cast<unsigned int>(gID), gEnt->gr_name, keepT);
624  glen = strlen(gEnt->gr_name);
625  if (glen >= gNsz) glen = 0;
626  else strcpy(gName, gEnt->gr_name);
627  } else {
628  n = snprintf(gName, gNsz, "%ud", static_cast<unsigned int>(gID));
629  if (n >= gNsz) glen = 0;
630  }
631 
632 // Free any allocated buffer and return result
633 //
634  if (gBsz > addGsz && gBp) free(gBp);
635  return glen;
636 }
637 
638 /******************************************************************************/
639 /* G r o u p N a m e */
640 /******************************************************************************/
641 
642 int XrdOucUtils::GroupName(gid_t gID, char *gName, int gNsz)
643 {
644  static const int maxgBsz = 256*1024;
645  static const int addGsz = 4096;
646  struct group *gEnt, gStruct;
647  char gBuff[1024], *gBp = gBuff;
648  int glen, gBsz = sizeof(gBuff), aOK = 1;
649  int retVal = 0;
650 
651 // Get the the group struct. If we don't have a large enough buffer, get a
652 // larger one and try again up to the maximum buffer we will tolerate.
653 //
654  while(( retVal = getgrgid_r(gID, &gStruct, gBp, gBsz, &gEnt) ) == ERANGE)
655  {if (gBsz >= maxgBsz) {aOK = 0; break;}
656  if (gBsz > addGsz) free(gBp);
657  gBsz += addGsz;
658  if (!(gBp = (char *)malloc(gBsz))) {aOK = 0; break;}
659  }
660 
661 // Return a group name if all went well
662 //
663  if (aOK && retVal == 0 && gEnt != NULL)
664  {glen = strlen(gEnt->gr_name);
665  if (glen >= gNsz) glen = 0;
666  else strcpy(gName, gEnt->gr_name);
667  } else glen = 0;
668 
669 // Free any allocated buffer and return result
670 //
671  if (gBsz > addGsz && gBp) free(gBp);
672  return glen;
673 }
674 
675 /******************************************************************************/
676 /* H S i z e */
677 /******************************************************************************/
678 
679 const char *XrdOucUtils::HSize(size_t bytes, char* buff, int bsz)
680 {
681 
682 // Do fast conversion of the quantity is less than 1K
683 //
684  if (bytes < 1024)
685  {snprintf(buff, bsz, "%zu", bytes);
686  return buff;
687  }
688 
689 // Scale this down
690 //
691  const char *suffix = " KMGTPEYZ";
692  double dBytes = static_cast<double>(bytes);
693 
694 do{dBytes /= 1024.0; suffix++;
695  } while(dBytes >= 1024.0 && *(suffix+1));
696 
697 
698 // Format and return result. Include fractions only if they meaningfully exist.
699 //
700  double whole, frac = modf(dBytes, &whole);
701  if (frac >= .005) snprintf(buff, bsz, "%.02lf%c", dBytes, *suffix);
702  else snprintf(buff, bsz, "%g%c", whole, *suffix);
703  return buff;
704 }
705 
706 /******************************************************************************/
707 /* i 2 b s t r */
708 /******************************************************************************/
709 
710 const char *XrdOucUtils::i2bstr(char *buff, int blen, int val, bool pad)
711 {
712  char zo[2] = {'0', '1'};
713 
714  if (blen < 2) return "";
715 
716  buff[--blen] = 0;
717  if (!val) buff[blen--] = '0';
718  else while(val && blen >= 0)
719  {buff[blen--] = zo[val & 0x01];
720  val >>= 1;
721  }
722 
723  if (blen >= 0 && pad) while(blen >= 0) buff[blen--] = '0';
724 
725  return &buff[blen+1];
726 }
727 
728 /******************************************************************************/
729 /* I d e n t */
730 /******************************************************************************/
731 
732 namespace
733 {
734 long long genSID(char *&urSID, const char *iHost, int iPort,
735  const char *iName, const char *iProg)
736 {
737  static const XrdOucSHA3::MDLen mdLen = XrdOucSHA3::SHA3_512;
738  static const uint32_t fpOffs = 2, fpSize = 6; // 48 bit finger print
739 
740  const char *iSite = getenv("XRDSITE");
741  unsigned char mDigest[mdLen];
742  XrdOucString myID;
743  union {uint64_t mdLL; unsigned char mdUC[8];}; // Works for fpSize only!
744 
745 // Construct our unique identification
746 //
747  if (iSite) myID = iSite;
748  myID += iHost;
749  myID += iPort;
750  if (iName) myID += iName;
751  myID += iProg;
752 
753 // Generate a SHA3 digest of this string.
754 //
755  memset(mDigest, 0, sizeof(mDigest));
756  XrdOucSHA3::Calc(myID.c_str(), myID.length(), mDigest, mdLen);
757 
758 // Generate a CRC32C of the same string
759 //
760  uint32_t crc32c = XrdOucCRC::Calc32C(myID.c_str(), myID.length());
761 
762 // We need a 48-bit fingerprint that has a very low probability of collision.
763 // We accomplish this by convoluting the CRC32C checksum with the SHA3 checksum.
764 //
765  uint64_t fpPos = crc32c % (((uint32_t)mdLen) - fpSize);
766  mdLL = 0;
767  memcpy(mdUC+fpOffs, mDigest+fpPos, fpSize);
768  long long fpVal = static_cast<long long>(ntohll(mdLL));
769 
770 // Generate the character version of our fingerprint and return the binary one.
771 //
772  char fpBuff[64];
773  snprintf(fpBuff, sizeof(fpBuff), "%lld", fpVal);
774  urSID = strdup(fpBuff);
775  return fpVal;
776 }
777 }
778 
779 char *XrdOucUtils::Ident(long long &mySID, char *iBuff, int iBlen,
780  const char *iHost, const char *iProg,
781  const char *iName, int iPort)
782 {
783  static char *theSIN;
784  static long long theSID = genSID(theSIN, iHost, iPort, iName, iProg);
785  const char *sP = getenv("XRDSITE");
786  char uName[256];
787  int myPid = static_cast<int>(getpid());
788 
789 // Get our username
790 //
791  if (UserName(getuid(), uName, sizeof(uName)))
792  sprintf(uName, "%d", static_cast<int>(getuid()));
793 
794 // Create identification record
795 //
796  snprintf(iBuff,iBlen,"%s.%d:%s@%s\n&site=%s&port=%d&inst=%s&pgm=%s",
797  uName, myPid, theSIN, iHost, (sP ? sP : ""), iPort, iName, iProg);
798 
799 // Return a copy of the sid key
800 //
801  h2nll(theSID, mySID);
802  return strdup(theSIN);
803 }
804 
805 /******************************************************************************/
806 /* I n s t N a m e */
807 /******************************************************************************/
808 
809 const char *XrdOucUtils::InstName(int TranOpt)
810 {
811  const char *iName = getenv("XRDNAME");
812 
813 // If tran is zero, return what we have
814 //
815  if (!TranOpt) return iName;
816 
817 // If trans is positive then make sure iName has a value. Otherwise, make sure
818 // iName has no value if it's actually "anon".
819 //
820  if (TranOpt > 0) {if (!iName || !*iName) iName = "anon";}
821  else if (iName && !strcmp(iName, "anon")) iName = 0;
822  return iName;
823 }
824 /******************************************************************************/
825 
826 const char *XrdOucUtils::InstName(const char *name, int Fillit)
827 { return (Fillit ? name && *name ? name : "anon"
828  : name && strcmp(name,"anon") && *name ? name : 0);
829 }
830 
831 /******************************************************************************/
832 /* i s 1 o f */
833 /******************************************************************************/
834 
835 int XrdOucUtils::is1of(char *val, const char **clist)
836 {
837  int i = 0;
838  while(clist[i]) if (!strcmp(val, clist[i])) return 1;
839  else i++;
840  return 0;
841 }
842 
843 /******************************************************************************/
844 /* i s F W D */
845 /******************************************************************************/
846 
847 int XrdOucUtils::isFWD(const char *path, int *port, char *hBuff, int hBLen,
848  bool pTrim)
849 {
850  const char *hName, *hNend, *hPort, *hPend, *hP = path;
851  char *eP;
852  int n;
853 
854  if (*path == '/') hP++; // Note: It's assumed an objectid if no slash
855  if (*hP == 'x') hP++;
856  if (strncmp("root:/", hP, 6)) return 0;
857  if (hBuff == 0 || hBLen <= 0) return (hP - path) + 6;
858  hP += 6;
859 
860  if (!XrdNetUtils::Parse(hP, &hName, &hNend, &hPort, &hPend)) return 0;
861  if (*hNend == ']') hNend++;
862  else {if (!(*hNend) && !(hNend = index(hName, '/'))) return 0;
863  if (!(*hPend)) hPend = hNend;
864  }
865 
866  if (pTrim || !(*hPort)) n = hNend - hP;
867  else n = hPend - hP;
868  if (n >= hBLen) return 0;
869  strncpy(hBuff, hP, n);
870  hBuff[n] = 0;
871 
872  if (port)
873  {if (*hNend != ':') *port = 0;
874  else {*port = strtol(hPort, &eP, 10);
875  if (*port < 0 || *port > 65535 || eP != hPend) return 0;
876  }
877  }
878 
879  return hPend-path;
880 }
881 
882 /******************************************************************************/
883 /* L o g 2 */
884 /******************************************************************************/
885 
886 // Based on an algorithm produced by Todd Lehman. However, this one returns 0
887 // when passed 0 (which is invalid). The caller must check the validity of
888 // the input prior to calling Log2(). Essentially, the algorithm subtracts
889 // away progressively smaller squares in the sequence
890 // { 0 <= k <= 5: 2^(2^k) } = { 2**32, 2**16, 2**8 2**4 2**2, 2**1 } =
891 // = { 4294967296, 65536, 256, 16, 4, 2 }
892 // and sums the exponents k of the subtracted values. It is generally the
893 // fastest way to compute log2 for a wide range of possible input values.
894 
895 int XrdOucUtils::Log2(unsigned long long n)
896 {
897  int i = 0;
898 
899  #define SHFT(k) if (n >= (1ULL << k)) { i += k; n >>= k; }
900 
901  SHFT(32); SHFT(16); SHFT(8); SHFT(4); SHFT(2); SHFT(1); return i;
902 
903  #undef SHFT
904 }
905 
906 /******************************************************************************/
907 /* L o g 1 0 */
908 /******************************************************************************/
909 
910 int XrdOucUtils::Log10(unsigned long long n)
911 {
912  int i = 0;
913 
914  #define SHFT(k, m) if (n >= m) { i += k; n /= m; }
915 
916  SHFT(16,10000000000000000ULL); SHFT(8,100000000ULL);
917  SHFT(4,10000ULL); SHFT(2,100ULL); SHFT(1,10ULL);
918  return i;
919 
920  #undef SHFT
921 }
922 
923 /******************************************************************************/
924 /* m a k e H o m e */
925 /******************************************************************************/
926 
927 void XrdOucUtils::makeHome(XrdSysError &eDest, const char *inst)
928 {
929  char buff[2048];
930 
931  if (!inst || !getcwd(buff, sizeof(buff))) return;
932 
933  strcat(buff, "/"); strcat(buff, inst);
934  if (MAKEDIR(buff, pathMode) && errno != EEXIST)
935  {eDest.Emsg("Config", errno, "create home directory", buff);
936  return;
937  }
938 
939  if (chdir(buff) < 0)
940  eDest.Emsg("Config", errno, "chdir to home directory", buff);
941 }
942 
943 /******************************************************************************/
944 
945 bool XrdOucUtils::makeHome(XrdSysError &eDest, const char *inst,
946  const char *path, mode_t mode)
947 {
948  char cwDir[2048];
949  const char *slash = "", *slash2 = "";
950  int n, rc;
951 
952 // Provide backward compatibility for instance name qualification
953 //
954 
955  if (!path || !(n = strlen(path)))
956  {if (inst) makeHome(eDest, inst);
957  return true;
958  }
959 
960 // Augment the path with instance name, if need be
961 //
962  if (path[n-1] != '/') slash = "/";
963  if (!inst || !(n = strlen(inst))) inst = "";
964  else slash2 = "/";
965  n = snprintf(cwDir, sizeof(cwDir), "%s%s%s%s", path, slash, inst, slash2);
966  if (n >= (int)sizeof(cwDir))
967  {eDest.Emsg("Config", ENAMETOOLONG, "create home directory", cwDir);
968  return false;
969  }
970 
971 // Create the path if it doesn't exist
972 //
973  if ((rc = makePath(cwDir, mode, true)))
974  {eDest.Emsg("Config", rc, "create home directory", cwDir);
975  return false;
976  }
977 
978 // Switch to this directory
979 //
980  if (chdir(cwDir) < 0)
981  {eDest.Emsg("Config", errno, "chdir to home directory", cwDir);
982  return false;
983  }
984 
985 // All done
986 //
987  return true;
988 }
989 
990 /******************************************************************************/
991 /* m a k e P a t h */
992 /******************************************************************************/
993 
994 int XrdOucUtils::makePath(char *path, mode_t mode, bool reset)
995 {
996  char *next_path = path+1;
997  struct stat buf;
998  bool dochmod = false; // The 1st component stays as is
999 
1000 // Typically, the path exists. So, do a quick check before launching into it
1001 //
1002  if (!reset && !stat(path, &buf)) return 0;
1003 
1004 // Start creating directories starting with the root
1005 //
1006  while((next_path = index(next_path, int('/'))))
1007  {*next_path = '\0';
1008  if (MAKEDIR(path, mode))
1009  if (errno != EEXIST) return -errno;
1010  if (dochmod) CHMOD(path, mode);
1011  dochmod = reset;
1012  *next_path = '/';
1013  next_path = next_path+1;
1014  }
1015 
1016 // All done
1017 //
1018  return 0;
1019 }
1020 
1021 /******************************************************************************/
1022 /* m o d e 2 m a s k */
1023 /******************************************************************************/
1024 
1025 bool XrdOucUtils::mode2mask(const char *mode, mode_t &mask)
1026 {
1027  mode_t mval[3] = {0}, mbit[3] = {0x04, 0x02, 0x01};
1028  const char *mok = "rwx";
1029  char mlet;
1030 
1031 // Accept octal mode
1032 //
1033  if (isdigit(*mode))
1034  {char *eP;
1035  mask = strtol(mode, &eP, 8);
1036  return *eP == 0;
1037  }
1038 
1039 // Make sure we have the correct number of characters
1040 //
1041  int n = strlen(mode);
1042  if (!n || n > 9 || n/3*3 != n) return false;
1043 
1044 // Convert groups of three
1045 //
1046  int k = 0;
1047  do {for (int i = 0; i < 3; i++)
1048  {mlet = *mode++;
1049  if (mlet != '-')
1050  {if (mlet != mok[i]) return false;
1051  mval[k] |= mbit[i];
1052  }
1053  }
1054  } while(++k < 3 && *mode);
1055 
1056 // Combine the modes and return success
1057 //
1058  mask = mval[0]<<6 | mval[1]<<3 | mval[2];
1059  return true;
1060 }
1061 
1062 /******************************************************************************/
1063 /* p a r s e L i b */
1064 /******************************************************************************/
1065 
1067  const char *libName, char *&libPath, char **libParm)
1068 {
1069  char *val, parms[2048];
1070 
1071 // Get the next token
1072 //
1073  val = Config.GetWord();
1074 
1075 // We do not support stacking as the caller does not support stacking
1076 //
1077  if (val && !strcmp("++", val))
1078  {eDest.Say("Config warning: stacked plugins are not supported in "
1079  "this context; directive ignored!");
1080  return true;
1081  }
1082 
1083 // Now skip over any options
1084 //
1085  while(val && *val && *val == '+') val = Config.GetWord();
1086 
1087 // Check if we actually have a path
1088 //
1089  if (!val || !val[0])
1090  {eDest.Emsg("Config", libName, "not specified"); return false;}
1091 
1092 // Record the path
1093 //
1094  if (libPath) free(libPath);
1095  libPath = strdup(val);
1096 
1097 // Handle optional parameter
1098 //
1099  if (!libParm) return true;
1100  if (*libParm) free(*libParm);
1101  *libParm = 0;
1102 
1103 // Record any parms
1104 //
1105  *parms = 0;
1106  if (!Config.GetRest(parms, sizeof(parms)))
1107  {eDest.Emsg("Config", libName, "parameters too long"); return false;}
1108  if (*parms) *libParm = strdup(parms);
1109  return true;
1110 }
1111 
1112 /******************************************************************************/
1113 /* p a r s e H o m e */
1114 /******************************************************************************/
1115 
1117 {
1118  char *pval, *val, *HomePath = 0;
1119 
1120 // Get the path
1121 //
1122  pval = Config.GetWord();
1123  if (!pval || !pval[0])
1124  {eDest.Emsg("Config", "home path not specified"); return 0;}
1125 
1126 // Make sure it's an absolute path
1127 //
1128  if (*pval != '/')
1129  {eDest.Emsg("Config", "home path not absolute"); return 0;}
1130 
1131 // Record the path
1132 //
1133  HomePath = strdup(pval);
1134 
1135 // Get the optional access rights
1136 //
1137  mode = S_IRWXU;
1138  if ((val = Config.GetWord()) && val[0])
1139  {if (!strcmp("group", val)) mode |= (S_IRGRP | S_IXGRP);
1140  else {eDest.Emsg("Config", "invalid home path modifier -", val);
1141  free(HomePath);
1142  return 0;
1143  }
1144  }
1145  return HomePath;
1146 }
1147 
1148 /******************************************************************************/
1149 /* R e L i n k */
1150 /******************************************************************************/
1151 
1152 int XrdOucUtils::ReLink(const char *path, const char *target, mode_t mode)
1153 {
1154  const mode_t AMode = S_IRWXU; // Only us as a default
1155  char pbuff[MAXPATHLEN+64];
1156  int n;
1157 
1158 // Copy the path
1159 //
1160  n = strlen(path);
1161  if (n >= (int)sizeof(pbuff)) return ENAMETOOLONG;
1162  strcpy(pbuff, path);
1163 
1164 // Unlink the target, make the path, and create the symlink
1165 //
1166  unlink(path);
1167  makePath(pbuff, (mode ? mode : AMode));
1168  if (symlink(target, path)) return errno;
1169  return 0;
1170 }
1171 
1172 /******************************************************************************/
1173 /* S a n i t i z e */
1174 /******************************************************************************/
1175 
1176 void XrdOucUtils::Sanitize(char *str, char subc)
1177 {
1178 
1179 // Sanitize string according to POSIX.1-2008 stanadard using only the
1180 // Portable Filename Character Set: a-z A-Z 0-9 ._- with 1st char not being -
1181 //
1182  if (*str)
1183  {if (*str == '-') *str = subc;
1184  else if (*str == ' ') *str = subc;
1185  char *blank = rindex(str, ' ');
1186  if (blank) while(*blank == ' ') *blank-- = 0;
1187  while(*str)
1188  {if (!isalnum(*str) && index("_-.", *str) == 0) *str = subc;
1189  str++;
1190  }
1191  }
1192 }
1193 
1194 /******************************************************************************/
1195 /* s u b L o g f n */
1196 /******************************************************************************/
1197 
1198 char *XrdOucUtils::subLogfn(XrdSysError &eDest, const char *inst, char *logfn)
1199 {
1200  const mode_t lfm = S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH;
1201  char buff[2048], *sp;
1202  int rc;
1203 
1204  if (!inst || !*inst) return logfn;
1205  if (!(sp = rindex(logfn, '/'))) strcpy(buff, "./");
1206  else {*sp = '\0'; strcpy(buff, logfn); strcat(buff, "/");}
1207 
1208  strcat(buff, inst); strcat(buff, "/");
1209 
1210  if ((rc = XrdOucUtils::makePath(buff, lfm)))
1211  {eDest.Emsg("Config", rc, "create log file path", buff);
1212  return 0;
1213  }
1214 
1215  if (sp) {*sp = '/'; strcat(buff, sp+1);}
1216  else strcat(buff, logfn);
1217 
1218  free(logfn);
1219  return strdup(buff);
1220 }
1221 
1222 /******************************************************************************/
1223 /* t o L o w e r */
1224 /******************************************************************************/
1225 
1226 void XrdOucUtils::toLower(char *str)
1227 {
1228  unsigned char* ustr = (unsigned char*)str; // Avoid undefined behaviour
1229 
1230 // Change each character to lower case
1231 //
1232  while(*ustr) {*ustr = tolower(*ustr); ustr++;}
1233 }
1234 
1235 /******************************************************************************/
1236 /* T o k e n */
1237 /******************************************************************************/
1238 
1239 int XrdOucUtils::Token(const char **str, char delim, char *buff, int bsz)
1240 {
1241  const char *eP, *bP = *str;
1242  int aLen, mLen;
1243 
1244 // Trim off the delimeters. Return zero if nothing left.
1245 //
1246  while(*bP && *bP == delim) bP++;
1247  if (*bP == 0) {*buff = 0; return 0;}
1248 
1249 // Find the next delimiter
1250 //
1251  eP = bP;
1252  while(*eP && *eP != delim) eP++;
1253 
1254 // If we ended at a null, make sure next call will return zero
1255 //
1256  if (*eP == 0) *str = eP;
1257  else *str = eP+1;
1258 
1259 // Calculate length and make sure we don't overrun the buffer
1260 //
1261  aLen = eP-bP;
1262  if (aLen >= bsz) mLen = bsz-1;
1263  else mLen = aLen;
1264 
1265 // Copy token into buffer and end with null byte
1266 //
1267  strncpy(buff, bP, mLen);
1268  buff[mLen] = 0;
1269 
1270 // Return actual length
1271 //
1272  return aLen;
1273 }
1274 
1275 /******************************************************************************/
1276 /* U n d e r c o v e r */
1277 /******************************************************************************/
1278 #ifdef WIN32
1279 void XrdOucUtils::Undercover(XrdSysError &, int, int *)
1280 {
1281 }
1282 #else
1283 void XrdOucUtils::Undercover(XrdSysError &eDest, int noLog, int *pipeFD)
1284 {
1285  static const int maxFiles = 256;
1286  pid_t mypid;
1287  int myfd, logFD = eDest.baseFD();
1288 
1289 // Issue warning if there is no logfile attached
1290 //
1291  if (noLog) eDest.Emsg("Config", "Warning! No log file specified; "
1292  "backgrounding disables all logging!");
1293 
1294 // Fork so that we are not tied to a shell
1295 //
1296  if ((mypid = fork()) < 0)
1297  {eDest.Emsg("Config", errno, "fork process 1 for backgrounding");
1298  return;
1299  }
1300  else if (mypid)
1301  {
1302  // we have been given a pair of pipe descriptors to be able to read the
1303  // status of the child process
1304  if( pipeFD )
1305  {
1306  int status = 1;
1307  close( pipeFD[1] );
1308  // read will wait untill the status is communicated by the
1309  // child process, if the child process dies before being able
1310  // to comunicate the status then read will see EOF
1311  if( read( pipeFD[0], &status, sizeof(status) ) != sizeof(status) )
1312  _exit(1);
1313  _exit(status);
1314  }
1315  // no pipes given, return success
1316  else _exit(0);
1317  }
1318 
1319  if( pipeFD )
1320  close( pipeFD[0] );
1321 
1322 // Become the process group leader
1323 //
1324  if (setsid() < 0)
1325  {eDest.Emsg("Config", errno, "doing setsid() for backgrounding");
1326  return;
1327  }
1328 
1329 // Fork to that we are cannot get a controlling terminal
1330 //
1331  if ((mypid = fork()) < 0)
1332  {eDest.Emsg("Config", errno, "fork process 2 for backgrounding");
1333  return;
1334  }
1335  else if (mypid) _exit(0);
1336 
1337 // Switch stdin, stdout, and stderr to /dev/null (we can't use /dev/console
1338 // unless we are root which is unlikely).
1339 //
1340  if ((myfd = open("/dev/null", O_RDWR)) < 0)
1341  {eDest.Emsg("Config", errno, "open /dev/null for backgrounding");
1342  return;
1343  }
1344  dup2(myfd, 0); dup2(myfd, 1); dup2(myfd, 2); dup2(myfd, logFD);
1345 
1346 // Close any open file descriptors left open by the parent process
1347 // but the communication pipe and the logger's shadow file descriptor.
1348 //
1349  for (myfd = 3; myfd < maxFiles; myfd++)
1350  if( (!pipeFD || myfd != pipeFD[1]) && myfd != logFD ) close(myfd);
1351 }
1352 
1353 /******************************************************************************/
1354 /* U i d N a m e */
1355 /******************************************************************************/
1356 
1357 int XrdOucUtils::UidName(uid_t uID, char *uName, int uNsz, time_t keepT)
1358 {
1359  struct passwd *pEnt, pStruct;
1360  char pBuff[1024];
1361  int n, rc;
1362 
1363 // Get ID from cache, if allowed
1364 //
1365  if (keepT)
1366  {int n = LookUp(uidMap, static_cast<unsigned int>(uID),uName,uNsz);
1367  if (n > 0) return (n < uNsz ? n : 0);
1368  }
1369 
1370 // Try to obtain the username. We use this form to make sure we are using
1371 // the standards conforming version (compilation error otherwise).
1372 //
1373  rc = getpwuid_r(uID, &pStruct, pBuff, sizeof(pBuff), &pEnt);
1374  if (rc || !pEnt)
1375  {n = snprintf(uName, uNsz, "%ud", static_cast<unsigned int>(uID));
1376  return (n >= uNsz ? 0 : n);
1377  }
1378 
1379 // Add entry to the cache if need be
1380 //
1381  if (keepT)
1382  AddID(uidMap, static_cast<unsigned int>(uID), pEnt->pw_name, keepT);
1383 
1384 // Return length of username or zero if it is too big
1385 //
1386  n = strlen(pEnt->pw_name);
1387  if (uNsz <= (int)strlen(pEnt->pw_name)) return 0;
1388  strcpy(uName, pEnt->pw_name);
1389  return n;
1390 }
1391 
1392 /******************************************************************************/
1393 /* U s e r N a m e */
1394 /******************************************************************************/
1395 
1396 int XrdOucUtils::UserName(uid_t uID, char *uName, int uNsz)
1397 {
1398  struct passwd *pEnt, pStruct;
1399  char pBuff[1024];
1400  int rc;
1401 
1402 // Try to obtain the username. We use this form to make sure we are using
1403 // the standards conforming version (compilation error otherwise).
1404 //
1405  rc = getpwuid_r(uID, &pStruct, pBuff, sizeof(pBuff), &pEnt);
1406  if (rc) return rc;
1407  if (!pEnt) return ESRCH;
1408 
1409 // Return length of username or zero if it is too big
1410 //
1411  if (uNsz <= (int)strlen(pEnt->pw_name)) return ENAMETOOLONG;
1412  strcpy(uName, pEnt->pw_name);
1413  return 0;
1414 }
1415 
1416 /******************************************************************************/
1417 /* V a l P a t h */
1418 /******************************************************************************/
1419 
1420 const char *XrdOucUtils::ValPath(const char *path, mode_t allow, bool isdir)
1421 {
1422  static const mode_t mMask = S_IRWXU | S_IRWXG | S_IRWXO;
1423  struct stat buf;
1424 
1425 // Check if this really exists
1426 //
1427  if (stat(path, &buf))
1428  {if (errno == ENOENT) return "does not exist.";
1429  return XrdSysE2T(errno);
1430  }
1431 
1432 // Verify that this is the correct type of file
1433 //
1434  if (isdir)
1435  {if (!S_ISDIR(buf.st_mode)) return "is not a directory.";
1436  } else {
1437  if (!S_ISREG(buf.st_mode)) return "is not a file.";
1438  }
1439 
1440 // Verify that the does not have excessive privileges
1441 //
1442  if ((buf.st_mode & mMask) & ~allow) return "has excessive access rights.";
1443 
1444 // All went well
1445 //
1446  return 0;
1447 }
1448 
1449 /******************************************************************************/
1450 /* P i d F i l e */
1451 /******************************************************************************/
1452 
1453 bool XrdOucUtils::PidFile(XrdSysError &eDest, const char *path)
1454 {
1455  char buff[32];
1456  int fd;
1457 
1458  if( (fd = open( path, O_WRONLY|O_CREAT|O_TRUNC, 0644 )) < 0 )
1459  {
1460  eDest.Emsg( "Config", errno, "create pidfile" );
1461  return false;
1462  }
1463 
1464  if( write( fd, buff, snprintf( buff, sizeof(buff), "%d",
1465  static_cast<int>(getpid()) ) ) < 0 )
1466  {
1467  eDest.Emsg( "Config", errno, "write to pidfile" );
1468  close(fd);
1469  return false;
1470  }
1471 
1472  close(fd);
1473  return true;
1474 }
1475 /******************************************************************************/
1476 /* getModificationTime */
1477 /******************************************************************************/
1478 int XrdOucUtils::getModificationTime(const char *path, time_t &modificationTime) {
1479  struct stat buf;
1480  int statRet = ::stat(path,&buf);
1481  if(!statRet) {
1482  modificationTime = buf.st_mtime;
1483  }
1484  return statRet;
1485 }
1486 
1487 void XrdOucUtils::trim(std::string &str) {
1488  // Trim leading non-letters
1489  while( str.size() && !isgraph(str[0]) ) str.erase(str.begin());
1490 
1491  // Trim trailing non-letters
1492 
1493  while( str.size() && !isgraph(str[str.size()-1]) )
1494  str.resize (str.size () - 1);
1495 }
1496 
1497 void XrdOucUtils::trim(std::string_view & sv) {
1498  const auto toTrim = [](char c) { return !isgraph(c); };
1499  size_t start = 0;
1500  size_t end = sv.size();
1501 
1502  while (start < end && toTrim(sv[start])) ++start;
1503  while (end > start && toTrim(sv[end - 1])) --end;
1504 
1505  sv = sv.substr(start, end - start);
1506 }
1512 static bool is_token_character(int c)
1513 {
1514  if (isalnum(c))
1515  return true;
1516 
1517  static constexpr char token_chars[] = "-._~+/=:%";
1518 
1519  for (char ch : token_chars)
1520  if (c == ch)
1521  return true;
1522 
1523  return false;
1524 }
1525 
1534 std::string obfuscateAuth(const std::string& input)
1535 {
1536  static const regex_t auth_regex = []() {
1537  constexpr char re[] =
1538  "(authz=|(transferheader)?(www-|proxy-)?auth(orization|enticate)[[:space:]]*:[[:space:]]*)"
1539  "(Bearer([[:space:]]|%20)?(token([[:space:]]|%20)?)?)?";
1540 
1541  regex_t regex;
1542 
1543  if (regcomp(&regex, re, REG_EXTENDED | REG_ICASE) != 0)
1544  throw std::runtime_error("Failed to compile regular expression");
1545 
1546  return regex;
1547  }();
1548 
1549  regmatch_t match;
1550  size_t offset = 0;
1551  std::string redacted;
1552  const char *const text = input.c_str();
1553 
1554  while (regexec(&auth_regex, text + offset, 1, &match, 0) == 0) {
1555  redacted.append(text + offset, match.rm_eo).append("REDACTED");
1556 
1557  offset += match.rm_eo;
1558 
1559  while (offset < input.size() && is_token_character(input[offset]))
1560  ++offset;
1561  }
1562 
1563  return redacted.append(text + offset);
1564 }
1565 
1566 #endif
struct stat Stat
Definition: XrdCks.cc:49
static XrdSysError eDest(0,"crypto_")
uint32_t crc32c(uint32_t crc, void const *buf, size_t len)
#define ENODATA
Definition: XrdOucUtils.cc:66
#define SHFT(k)
static bool is_token_character(int c)
std::string obfuscateAuth(const std::string &input)
int chdir(const char *path)
int unlink(const char *path)
ssize_t write(int fildes, const void *buf, size_t nbyte)
ssize_t read(int fildes, void *buf, size_t nbyte)
#define close(a)
Definition: XrdPosix.hh:48
#define fstat(a, b)
Definition: XrdPosix.hh:62
#define open
Definition: XrdPosix.hh:76
#define stat(a, b)
Definition: XrdPosix.hh:101
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
size_t strlcpy(char *dst, const char *src, size_t sz)
#define CHMOD(path, mode)
#define MAKEDIR(path, mode)
static bool Match(const char *hName, const char *pattern)
Definition: XrdNetUtils.cc:658
static bool Parse(const char *hSpec, const char **hName, const char **hNend, const char **hPort, const char **hPend)
Definition: XrdNetUtils.cc:780
static uint32_t Calc32C(const void *data, size_t count, uint32_t prevcs=0)
Definition: XrdOucCRC.cc:190
char * Get(const char *varname)
Definition: XrdOucEnv.hh:69
MDLen
SHA3 digest lengths (bits to bytes).
Definition: XrdOucSHA3.hh:56
static void * Calc(const void *in, size_t inlen, void *md, MDLen mdlen)
Definition: XrdOucSHA3.cc:150
const char * c_str() const
int length() const
int tokenize(XrdOucString &tok, int from, char del=':')
static char * parseHome(XrdSysError &eDest, XrdOucStream &Config, int &mode)
static void Sanitize(char *instr, char subc='_')
static bool getGID(const char *gName, gid_t &gID)
Definition: XrdOucUtils.cc:559
static const mode_t pathMode
Definition: XrdOucUtils.hh:47
static const char * HSize(size_t bytes, char *buff, int bsz)
Definition: XrdOucUtils.cc:679
static int isFWD(const char *path, int *port=0, char *hBuff=0, int hBLen=0, bool pTrim=false)
Definition: XrdOucUtils.cc:847
static int UserName(uid_t uID, char *uName, int uNsz)
static char * Ident(long long &mySID, char *iBuff, int iBlen, const char *iHost, const char *iProg, const char *iName, int Port)
Definition: XrdOucUtils.cc:779
static bool getUID(const char *uName, uid_t &uID, gid_t *gID=0)
Definition: XrdOucUtils.cc:575
static int getModificationTime(const char *path, time_t &modificationTime)
static const char * ValPath(const char *path, mode_t allow, bool isdir)
static char * genPath(const char *path, const char *inst, const char *psfx=0)
Definition: XrdOucUtils.cc:463
static int Token(const char **str, char delim, char *buff, int bsz)
static int ReLink(const char *path, const char *target, mode_t mode=0)
static bool parseLib(XrdSysError &eDest, XrdOucStream &Config, const char *libName, char *&path, char **libparm)
static int hex2bin(const char *hex, char *bin, int size)
Definition: XrdOucUtils.cc:184
static int is1of(char *val, const char **clist)
Definition: XrdOucUtils.cc:835
static const char * InstName(int TranOpt=0)
Definition: XrdOucUtils.cc:809
static char * eText(int rc, char *eBuff, int eBlen)
Definition: XrdOucUtils.cc:243
static int argList(char *args, char **argV, int argC)
Definition: XrdOucUtils.cc:125
static bool mode2mask(const char *mode, mode_t &mask)
static int GidName(gid_t gID, char *gName, int gNsz, time_t keepT=0)
Definition: XrdOucUtils.cc:593
static int UidName(uid_t uID, char *uName, int uNsz, time_t keepT=0)
static char * bin2hex(char *inbuff, int dlen, char *buff, int blen, bool sep=true)
Definition: XrdOucUtils.cc:164
static int Log10(unsigned long long n)
Definition: XrdOucUtils.cc:910
static int doIf(XrdSysError *eDest, XrdOucStream &Config, const char *what, const char *hname, const char *nname, const char *pname)
Definition: XrdOucUtils.cc:277
static int makePath(char *path, mode_t mode, bool reset=false)
Definition: XrdOucUtils.cc:994
static int GroupName(gid_t gID, char *gName, int gNsz)
Definition: XrdOucUtils.cc:642
static void trim(std::string &str)
static bool findPgm(const char *pgm, XrdOucString &path)
Definition: XrdOucUtils.cc:400
static bool PidFile(XrdSysError &eDest, const char *path)
static const char * i2bstr(char *buff, int blen, int val, bool pad=false)
Definition: XrdOucUtils.cc:710
static void toLower(char *str)
static int fmtBytes(long long val, char *buff, int bsz)
Definition: XrdOucUtils.cc:436
static int Log2(unsigned long long n)
Definition: XrdOucUtils.cc:895
static void makeHome(XrdSysError &eDest, const char *inst)
Definition: XrdOucUtils.cc:927
static bool endsWith(const char *text, const char *ending, int endlen)
Definition: XrdOucUtils.cc:229
static void Undercover(XrdSysError &eDest, int noLog, int *pipeFD=0)
static char * getFile(const char *path, int &rc, int maxsz=10240, bool notempty=true)
Definition: XrdOucUtils.cc:502
static char * subLogfn(XrdSysError &eDest, const char *inst, char *logfn)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
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:141
int baseFD()
Definition: XrdSysError.cc:73
XrdCmsConfig Config
XrdOucEnv theEnv
@ hex
Definition: XrdSysTrace.hh:42