/******************************************************************************/
/* */
/* X r d S u t A u x . c c */
/* */
/* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
/* Produced by Gerri Ganis for CERN */
/* */
/* This file is part of the XRootD software suite. */
/* */
/* XRootD is free software: you can redistribute it and/or modify it under */
/* the terms of the GNU Lesser General Public License as published by the */
/* Free Software Foundation, either version 3 of the License, or (at your */
/* option) any later version. */
/* */
/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
/* COPYING (GPL license). If not, see . */
/* */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without */
/* specific prior written permission of the institution or contributor. */
/******************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "XrdSys/XrdSysLogger.hh"
#include "XrdSys/XrdSysError.hh"
#include "XrdSys/XrdSysPwd.hh"
#include "XrdOuc/XrdOucString.hh"
#include "XrdSut/XrdSutAux.hh"
#include "XrdSut/XrdSutRndm.hh"
#include "XrdSut/XrdSutTrace.hh"
static const char *gXRSBucketTypes[] = {
"kXRS_none",
"kXRS_inactive",
"kXRS_cryptomod",
"kXRS_main",
"kXRS_srv_seal",
"kXRS_clnt_seal",
"kXRS_puk",
"kXRS_cipher",
"kXRS_rtag",
"kXRS_signed_rtag",
"kXRS_user",
"kXRS_host",
"kXRS_creds",
"kXRS_message",
"kXRS_srvID",
"kXRS_sessionID",
"kXRS_version",
"kXRS_status",
"kXRS_localstatus",
"kXRS_othercreds",
"kXRS_cache_idx",
"kXRS_clnt_opts",
"kXRS_error_code",
"kXRS_timestamp",
"kXRS_x509",
"kXRS_issuer_hash",
"kXRS_x509_req",
"kXRS_cipher_alg",
"kXRS_md_alg",
"kXRS_afsinfo",
"kXRS_reserved"
};
//
// For error logging and tracing
static XrdSysLogger Logger;
static XrdSysError eDest(0,"sut_");
XrdOucTrace *sutTrace = 0;
/******************************************************************************/
/* X r d S u t S e t T r a c e */
/******************************************************************************/
//______________________________________________________________________________
void XrdSutSetTrace(kXR_int32 trace)
{
// Set trace flags according to 'trace'
//
// Initiate error logging and tracing
eDest.logger(&Logger);
if (!sutTrace)
sutTrace = new XrdOucTrace(&eDest);
if (sutTrace) {
// Set debug mask
sutTrace->What = 0;
// Low level only
if ((trace & sutTRACE_Notify))
sutTrace->What |= sutTRACE_Notify;
// Medium level
if ((trace & sutTRACE_Debug))
sutTrace->What |= (sutTRACE_Notify | sutTRACE_Debug);
// High level
if ((trace & sutTRACE_Dump))
sutTrace->What |= sutTRACE_ALL;
}
}
/******************************************************************************/
/* X r d S u t B u c k S t r */
/******************************************************************************/
//______________________________________________________________________________
const char *XrdSutBuckStr(int kbck)
{
// Return bucket string
static const char *ukn = "Unknown";
kbck = (kbck < 0) ? 0 : kbck;
kbck = (kbck > kXRS_reserved) ? 0 : kbck;
kbck = (kbck >= kXRS_cryptomod) ? (kbck - kXRS_cryptomod + 2) : kbck;
if (kbck < 0 || kbck > (kXRS_reserved - kXRS_cryptomod + 2))
return ukn;
else
return gXRSBucketTypes[kbck];
}
/******************************************************************************/
/* X r d S u t M e m S e t */
/******************************************************************************/
//______________________________________________________________________________
volatile void *XrdSutMemSet(volatile void *dst, int c, int len)
{
// To avoid problems due to compiler optmization
// Taken from Viega&Messier, "Secure Programming Cookbook", O'Really, #13.2
// (see discussion there)
volatile char *buf;
for (buf = (volatile char *)dst; len; buf[--len] = c) {}
return dst;
}
#ifndef USE_EXTERNAL_GETPASS
/******************************************************************************/
/* X r d S u t G e t P a s s */
/******************************************************************************/
//_____________________________________________________________________________
int XrdSutGetPass(const char *prompt, XrdOucString &passwd)
{
// Get password from command line using getpass
// *** Use only if you cannot provide a better alternative ***
// User will be prompted for 'prompt'; the entered password
// is returned in 'passwd'.
// Returns 0 if ok, -1 if any error occurs.
EPNAME("GetPass");
char *pw = getpass(prompt);
if (pw) {
// Get rid of special chars, if any
int k = 0, i = 0, len = strlen(pw);
for (; i 0x20) pw[k++] = pw[i];
pw[k] = 0;
passwd = pw;
XrdSutMemSet((volatile void *)pw,0,len);
} else {
DEBUG("error from getpass");
return -1;
}
return 0;
}
#endif
/******************************************************************************/
/* X r d S u t G e t L i n e */
/******************************************************************************/
int XrdSutGetLine(XrdOucString &line, const char *prompt)
{
// Get line from main input stream.
// Prompt 'prompt' if this is defined.
// Returns number of chars entered.
// NB: at most XrdSutMAXBUF-1 chars will be accepted
char bin[XrdSutMAXBUF] = {0};
// Print prompt, if requested
if (prompt)
cout << prompt;
// Get line
cin.getline(bin,XrdSutMAXBUF-1);
// Fill input
line = bin;
return line.length();
}
/******************************************************************************/
/* X r d S u t A s k C o n f i r m */
/******************************************************************************/
bool XrdSutAskConfirm(const char *msg1, bool defact, const char *msg2)
{
// Prompt for confirmation of action
// If defined, msg1 is printed as prompt, followed by the default action
// ( [y] == do-act, for defact = true;
// [n] == do-not-act, for defact = false)
// If defined, msg2 is printed before prompting.
bool rc = defact;
if (msg2)
cout << msg2;
XrdOucString ask;
XrdOucString prompt = defact ? " [y]: " : " [n]: ";
if (msg1)
prompt.insert(msg1,0);
XrdSutGetLine(ask,prompt.c_str());
ask.lower(0);
if (ask.length()) {
if (defact && (ask == 'n' || ask == "no")) {
rc = 0;
} else if (!defact && (ask == 'y' || ask == "yes")) {
rc = 1;
}
}
// we are done
return rc;
}
/******************************************************************************/
/* X r d S u t T o H e x */
/******************************************************************************/
int XrdSutToHex(const char *in, int lin, char *out)
{
// Content of lin bytes at in are transformed into an hexadecimal,
// null-terminated, string of length 2*lin; the result is returned
// in the buffer pointed by out, which must be allocated by the caller
// to contain at least 2*lin+1 bytes.
// Return 0 in case of success, -1 in case of error (errno set to EINVAL if
// any of in or out are not defined).
if (!in || !out) {
errno = EINVAL;
return -1;
}
int lbuf = 2*lin+1;
int i = 0;
out[0] = 0;
for ( ; i < lin; i++)
{
char buff[3];
sprintf(buff, "%02x", (0xFF & in[i]));
strncat(out, buff, 3);
}
// Null termination
out[lbuf-1] = 0;
// ok
return 0;
}
/******************************************************************************/
/* X r d S u t F r o m H e x */
/******************************************************************************/
int XrdSutFromHex(const char *in, char *out, int &lout)
{
// Content of the hexadecimal, null-terminated, string at in, is
// transformed into lout bytes returned in out.
// The output buffer should be allocated by the caller to contain
// at least lin/2 bytes if lin=strlen(in) is even, and lin/2+1 bytes
// if lin is odd (in this case an additional char equal 0 is appended
// to in).
// Return 0 in case of success, -1 in case of error (errno set to EINVAL if
// any of in or out are not defined).
lout = 0;
if (!in || !out) {
errno = EINVAL;
return -1;
}
int lin = strlen(in);
char st[3] = {0};
int i = 0, k = 0;
for ( ; i 1)
unam.assign(path, 1, iu-1);
sdir.erase(0, iu);
} else
sdir = '/';
if (unam.length() > 0) {
struct passwd *pw;
XrdSysPwd thePwd(unam.c_str(), &pw);
if (!pw) {
DEBUG("cannot pwnam information for local user "<<
((unam.length() > 0) ? unam : XrdOucString("")));
return -errno;
}
home = pw->pw_dir;
} else
home = XrdSutHome();
if (home.length() > 0) {
sdir.insert(home.c_str(),0);
path = sdir;
}
} else {
// relative path, add local dir
char *pwd = getenv("PWD");
if (pwd) {
path.insert('/',0);
path.insert(pwd,0);
path.erase("//");
} else {
DEBUG("PWD undefined ");
return -ENOENT;
}
}
return 0;
}
/******************************************************************************/
/* X r d S u t R e s o l v e */
/******************************************************************************/
int XrdSutResolve(XrdOucString &path,
const char *ho, const char *vo, const char *gr, const char *us)
{
// Resolve templates , , , (if any)
// Returns 0 in case of success, -EINVAL if path is not defined.
// Path must be defined
if (!path.length())
return -EINVAL;
// No templates, nothing to do
if (path.find("<") == STR_NPOS)
return 0;
// Replace , if defined
if (ho && strlen(ho) > 0) path.replace("", ho);
// Replace , if defined
if (vo && strlen(vo) > 0) path.replace("", vo);
// Replace , if defined
if (gr && strlen(gr) > 0) path.replace("", gr);
// Replace , if defined
if (us && strlen(us) > 0) path.replace("", us);
// Replace , if defined
if (path.find("") != STR_NPOS) {
XrdOucString rtag;
XrdSutRndm::GetString(2,6,rtag);
path.replace("", rtag);
}
// Done
return 0;
}
/******************************************************************************/
/* X r d S u t H o m e */
/******************************************************************************/
const char *XrdSutHome()
{
// Gets the home directory preferentially from HOME or from pwd entry
EPNAME("Home");
// Use the save value, if any
static XrdOucString homedir;
if (homedir.length() <= 0) {
// Check the HOME environment variable
if (getenv("HOME"))
homedir = getenv("HOME");
if (homedir.length() <= 0) {
struct passwd *pw;
XrdSysPwd thePwd(getuid(), &pw);
if (pw) homedir = pw->pw_dir;
}
if (homedir.length() <= 0)
DEBUG("Warning: home directory undefined! ");
}
// Done
return homedir.c_str();
}
/******************************************************************************/
/* X r d S u t M k d i r */
/* */
/******************************************************************************/
int XrdSutMkdir(const char *dir, unsigned int mode, const char *opt)
{
// Make directory dir
// mode specifies permissions
// opt == "-p" : make parent directories as needed
if (!dir) {
errno = EINVAL;
return -1;
}
if (!strncmp(opt,"-p",2)) {
//
// make also parent directories, if needed
XrdOucString dd(dir);
XrdSutExpand(dd);
if (dd[dd.length()-1] != '/')
dd.append('/');
int lsl = dd.find('/',1);
while (lsl > -1) {
XrdOucString pd(dd,0,lsl-1);
struct stat st;
if (stat(pd.c_str(),&st) == -1) {
if (errno == ENOENT) {
// path does not exists: create it
if (mkdir(pd.c_str(),mode) != 0)
return -1;
} else {
return -1;
}
}
// Go to next
lsl = dd.find('/',lsl+1);
}
} else {
return mkdir(dir,mode);
}
return 0;
}
/******************************************************************************/
/* X r d S u t P a r s e T i m e */
/* */
/******************************************************************************/
//______________________________________________________________________
int XrdSutParseTime(const char *tstr, int opt)
{
// Parse time string of the form "::..."
// with any integer and one of the following chars:
// 'y' for years
// 'd' for days
// 'h' for hours
// 'm' for minutes
// 's' for seconds
// (e.g. "34d:10h:20s")
// If opt == 1, assume a string in the form ".hh"[:[:]]"
// (e.g. "12:24:35" for 12 hours, 24 minutes and 35 secs)
// Return the corresponding number of seconds
EPNAME("ParseTime");
XrdOucString ts = tstr;
XrdOucString fr = "";
int i = 0;
int tsec = 0;
// Parse list
if (ts.length()) {
int ls = 0;
int ld = ts.find(':',1);
ld = (ld == -1) ? ts.length() - 1 : ld;
while (ld >= ls) {
fr.assign(ts, ls, ld);
fr.erase(":");
// Check this fraction
if (opt == 0) {
if (fr.length() > 1) {
// The unit must be known
char u = fr[fr.length()-1];
fr.erase(fr.length()-1);
if (u == 'y') {
tsec += atoi(fr.c_str())*31536000;
} else if (u == 'd') {
tsec += atoi(fr.c_str())*86400;
} else if (u == 'h') {
tsec += atoi(fr.c_str())*3600;
} else if (u == 'm') {
tsec += atoi(fr.c_str())*60;
} else if (u == 's') {
tsec += atoi(fr.c_str());
} else {
DEBUG("unknown unit: "<