/******************************************************************************/ /* XrdFfsMisc.cc Miscellanies functions */ /* */ /* (c) 2010 by the Board of Trustees of the Leland Stanford, Jr., University */ /* All Rights Reserved */ /* Author: Wei Yang (SLAC National Accelerator Laboratory, 2009) */ /* Contract DE-AC02-76-SFO0515 with the Department of Energy */ /* */ /* 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. */ /******************************************************************************/ #define _FILE_OFFSET_BITS 64 #include #include //#include #include #include #include //#include #include #include #include #include #include #include #include "XrdNet/XrdNetAddr.hh" #include "XrdNet/XrdNetUtils.hh" #include "XrdPosix/XrdPosixAdmin.hh" #include "XrdSec/XrdSecEntity.hh" #include "XrdSecsss/XrdSecsssID.hh" #include "XrdFfs/XrdFfsDent.hh" #include "XrdFfs/XrdFfsFsinfo.hh" #include "XrdFfs/XrdFfsMisc.hh" #include "XrdFfs/XrdFfsPosix.hh" #include "XrdFfs/XrdFfsQueue.hh" #include "XrdPosix/XrdPosixXrootd.hh" #ifdef __cplusplus extern "C" { #endif #define MAXROOTURLLEN 1024 // this is also defined in other files #define nXrdConnPerUsr 8; short iXrdConnPerUsr = 0; pthread_mutex_t url_mlock; char XrdFfsMisc_get_current_url(const char *oldurl, char *newurl) { struct stat stbuf; /* if it is a directory, return oldurl */ if (XrdFfsPosix_stat(oldurl, &stbuf) == 0 && S_ISDIR(stbuf.st_mode)) { strcpy(newurl, oldurl); return 1; } XrdPosixAdmin adm(oldurl); if (adm.isOK() && adm.Stat()) { // We might have been redirected to a destination server. Better // to remember it and use only this one as output. // if (stat && adm->GetCurrentUrl().IsValid()) // { // strcpy(newurl, adm->GetCurrentUrl().GetUrl().c_str()); // delete adm; strcpy(newurl, oldurl); // This needs to change!!! return 1; } return 0; } char* XrdFfsMisc_getNameByAddr(char* ipaddr) { XrdNetAddr netAddr; const char *theName; if (netAddr.Set(ipaddr,0) || !(theName = netAddr.Name())) theName = ipaddr; return strdup(theName); } int XrdFfsMisc_get_all_urls_real(const char *oldurl, char **newurls, const int nnodes) { XrdPosixAdmin adm(oldurl); XrdCl::URL *uVec; int i, rval = 0; if (!adm.isOK() || !(uVec = adm.FanOut(rval))) return -1; if (rval > nnodes) rval = -1; else for (i = 0; i < rval; i++) { strncpy(newurls[i], uVec[i].GetURL().c_str(), MAXROOTURLLEN -1); newurls[i][MAXROOTURLLEN -1] = '\0'; } delete [] uVec; return rval; } /* function XrdFfsMisc_get_all_urls() has the same interface as XrdFfsMisc_get_all_urls_real(), but used a cache to reduce unnecessary queries to the redirector */ char XrdFfsMiscCururl[MAXROOTURLLEN] = ""; char *XrdFfsMiscUrlcache[XrdFfs_MAX_NUM_NODES]; int XrdFfsMiscNcachedurls = 0; time_t XrdFfsMiscUrlcachetime = 0; pthread_mutex_t XrdFfsMiscUrlcache_mutex = PTHREAD_MUTEX_INITIALIZER; time_t XrdFfsMiscUrlcachelife = 60; int XrdFfsMisc_get_number_of_data_servers() { return XrdFfsMiscNcachedurls; } void XrdFfsMisc_set_Urlcachelife(const char *urlcachelife) { int t, len; char *life = strdup(urlcachelife); char last = 's'; if (life == NULL) return; len = strlen(life); if (! isdigit(life[len-1])) { last = life[len-1]; life[len-1] = '\0'; } sscanf(life, "%d", &t); XrdFfsMiscUrlcachelife = (time_t) t; life[len-1] = last; switch (last) { case 'm': /* minute */ XrdFfsMiscUrlcachelife *= 60; break; case 'h': /* hour */ XrdFfsMiscUrlcachelife *= 3600; break; case 'd': /* day */ XrdFfsMiscUrlcachelife *= 3600*24; break; default: /* second */ ; } free(life); return; } int XrdFfsMisc_get_all_urls(const char *oldurl, char **newurls, const int nnodes) { time_t currtime; int i, nurls; pthread_mutex_lock(&XrdFfsMiscUrlcache_mutex); currtime = time(NULL); /* setting the cache to effectively not expire will let us know if a host is down */ if (XrdFfsMiscCururl[0] == '\0' || (currtime - XrdFfsMiscUrlcachetime) > XrdFfsMiscUrlcachelife || strcmp(XrdFfsMiscCururl, oldurl) != 0) { for (i = 0; i < XrdFfsMiscNcachedurls; i++) if (XrdFfsMiscUrlcache[i] != NULL) free(XrdFfsMiscUrlcache[i]); for (i = 0; i < XrdFfs_MAX_NUM_NODES; i++) XrdFfsMiscUrlcache[i] = (char*) malloc(MAXROOTURLLEN); XrdFfsMiscUrlcachetime = currtime; strcpy(XrdFfsMiscCururl, oldurl); XrdFfsMiscNcachedurls = XrdFfsMisc_get_all_urls_real(oldurl, XrdFfsMiscUrlcache, nnodes); for (i = XrdFfsMiscNcachedurls; i < XrdFfs_MAX_NUM_NODES; i++) if (XrdFfsMiscUrlcache[i] != NULL) free(XrdFfsMiscUrlcache[i]); } nurls = XrdFfsMiscNcachedurls; for (i = 0; i < nurls; i++) { newurls[i] = (char*) malloc(MAXROOTURLLEN); strncpy(newurls[i], XrdFfsMiscUrlcache[i], MAXROOTURLLEN -1); newurls[i][MAXROOTURLLEN-1] = '\0'; } pthread_mutex_unlock(&XrdFfsMiscUrlcache_mutex); return nurls; } int XrdFfsMisc_get_list_of_data_servers(char* list) { XrdNetAddr uAddr; int i, n = 0; const char *netName; const char *hName, *hNend, *hPort, *hPend; char *url, *rc, *hostip, hsep; rc = (char*)malloc(sizeof(char) * XrdFfs_MAX_NUM_NODES * MAXROOTURLLEN); rc[0] = '\0'; pthread_mutex_lock(&XrdFfsMiscUrlcache_mutex); for (i = 0; i < XrdFfsMiscNcachedurls; i++) { url = strdup(XrdFfsMiscUrlcache[i]); hostip = &url[7]; if (XrdNetUtils::Parse(hostip, &hName, &hNend, &hPort, &hPend)) {n++; hsep = *hNend; hostip[hNend-hostip] = 0; hostip[hPend-hostip] = 0; if (uAddr.Set(hName,0) || !(netName = uAddr.Name())) {hostip[hNend-hostip] = hsep; hName = hostip; hPend = hNend; } strcat(rc, hName); if (hPort != hNend) {strcat(rc, ":"); strcat(rc, hPort); } strcat(rc, "\n"); } free(url); } pthread_mutex_unlock(&XrdFfsMiscUrlcache_mutex); strcpy(list, rc); free(rc); return n; } void XrdFfsMisc_refresh_url_cache(const char* url) { int i, nurls; char *surl, **turls; turls = (char**) malloc(sizeof(char*) * XrdFfs_MAX_NUM_NODES); // invalid the cache first pthread_mutex_lock(&XrdFfsMiscUrlcache_mutex); XrdFfsMiscUrlcachetime = 0; pthread_mutex_unlock(&XrdFfsMiscUrlcache_mutex); if (url != NULL) surl = strdup(url); else surl = strdup(XrdFfsMiscCururl); nurls = XrdFfsMisc_get_all_urls(surl, turls, XrdFfs_MAX_NUM_NODES); free(surl); for (i = 0; i < nurls; i++) free(turls[i]); free(turls); } void XrdFfsMisc_logging_url_cache(const char* url) { int i; char *hostlist, *p1, *p2; if (url != NULL) XrdFfsMisc_refresh_url_cache(url); hostlist = (char*) malloc(sizeof(char) * XrdFfs_MAX_NUM_NODES * 256); i = XrdFfsMisc_get_list_of_data_servers(hostlist); syslog(LOG_INFO, "INFO: use the following %d data servers :", i); p1 = hostlist; p2 = strchr(p1, '\n'); while (p2 != NULL) { p2[0] = '\0'; syslog(LOG_INFO, " %s", p1); p1 = p2 +1; p2 = strchr(p1, '\n'); } free(hostlist); } void XrdFfsMisc_xrd_init(const char *rdrurl, const char *urlcachelife, int startQueue) { static int OneTimeInitDone = 0; // Do not execute this more than once // if (OneTimeInitDone) return; OneTimeInitDone = 1; // EnvPutInt(NAME_FIRSTCONNECTMAXCNT,2); // EnvPutInt(NAME_DATASERVERCONN_TTL, 99999999); // EnvPutInt(NAME_LBSERVERCONN_TTL, 99999999); // EnvPutInt(NAME_READAHEADSIZE,0); // EnvPutInt(NAME_READCACHESIZE,0); // EnvPutInt(NAME_REQUESTTIMEOUT, 30); XrdPosixXrootd::setEnv("WorkerThreads", 50); if (getenv("XROOTDFS_SECMOD") != NULL && !strcmp(getenv("XROOTDFS_SECMOD"), "sss")) XrdFfsMisc_xrd_secsss_init(); openlog("XrootdFS", LOG_ODELAY | LOG_PID, LOG_DAEMON); XrdFfsMisc_set_Urlcachelife(urlcachelife); XrdFfsMisc_refresh_url_cache(rdrurl); XrdFfsMisc_logging_url_cache(NULL); #ifndef NOUSE_QUEUE if (startQueue) { if (getenv("XROOTDFS_NWORKERS") != NULL) XrdFfsQueue_create_workers(atoi(getenv("XROOTDFS_NWORKERS"))); else XrdFfsQueue_create_workers(4); syslog(LOG_INFO, "INFO: Starting %d workers", XrdFfsQueue_count_workers()); } #endif pthread_mutex_init(&url_mlock, NULL); XrdFfsDent_cache_init(); } // convert an unsigned decimal int to its base24 string void toChar(unsigned int r, char *d24) { const char alpha[] = "0123456789abcdefghijklmn"; char tmp[8]; memcpy(tmp, d24, 8); memcpy(d24+1, tmp, 8); d24[0] = alpha[r]; return; } void decTo24(unsigned int d, char *d24) { unsigned int r = d % 24; toChar(r, d24); if ((d - r) != 0) decTo24((d-r)/24, d24); return; } char* ntoa24(unsigned int d) { // caller is repsonsible to free the memory char *d24 = (char*) malloc(9); memset(d24, 0, 9); decTo24(d, d24); return d24; } /* SSS security module */ XrdSecsssID *XrdFfsMiscSssid; bool XrdFfsMiscSecsss = false; void XrdFfsMisc_xrd_secsss_init() { XrdFfsMiscSecsss = true; XrdFfsMiscSssid = new XrdSecsssID(XrdSecsssID::idDynamic); /* Enforce "sss" security */ setenv("XrdSecPROTOCOL", "sss", 1); } void XrdFfsMisc_xrd_secsss_register(uid_t user_uid, gid_t user_gid, int *id) { struct passwd pw, *pwp; struct group gr, *grp; char user_num[9], *pwbuf, *grbuf, *tmp; static size_t pwbuflen = 0; static size_t grbuflen = 0; if (pwbuflen == 0) pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); if (grbuflen == 0) grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX); XrdSecEntity XrdFfsMiscUent(""); tmp = ntoa24((unsigned int)user_uid); memcpy(user_num, tmp, 9); free(tmp); if (id != NULL) { pthread_mutex_lock(&url_mlock); *id = iXrdConnPerUsr +1; // id = 1 to nXrdConnPerUsr+1 (8) iXrdConnPerUsr = (iXrdConnPerUsr +1) % nXrdConnPerUsr; pthread_mutex_unlock(&url_mlock); user_num[strlen(user_num)] = *id + 48; // this require that *id stay as single digit. } else user_num[strlen(user_num)] = 48; // id = NULL if (XrdFfsMiscSecsss) { pwbuf = (char*) malloc(pwbuflen); getpwuid_r(user_uid, &pw, pwbuf, pwbuflen, &pwp); grbuf = (char*) malloc(grbuflen); getgrgid_r(user_gid, &gr, grbuf, grbuflen, &grp); XrdFfsMiscUent.name = pw.pw_name; XrdFfsMiscUent.grps = gr.gr_name; XrdFfsMiscSssid->Register(user_num, &XrdFfsMiscUent, 0); free(pwbuf); free(grbuf); } } void XrdFfsMisc_xrd_secsss_editurl(char *url, uid_t user_uid, int *id) { char user_num[9], nurl[MAXROOTURLLEN], *tmp; // Xrootd proxy also use some of the stat()/unlink(), etc funcitons here, without user "sss". It use the default // connection login name. Don't change this behavior. (so for proxy, use no "sss", and always have *id = 0 if (id != NULL || XrdFfsMiscSecsss) { tmp = ntoa24(user_uid); memcpy(user_num, tmp, 9); free(tmp); if (id == NULL) user_num[strlen(user_num)] = 48; else user_num[strlen(user_num)] = *id + 48; nurl[0] = '\0'; strncat(nurl, "root://", 8); strncat(nurl, user_num, 9); strncat(nurl, "@", 2); strncat(nurl, &(url[7]), MAXROOTURLLEN-17); strncpy(url, nurl, MAXROOTURLLEN); } } #ifdef __cplusplus } #endif