// @(#)root/net:$Name:  $:$Id: TAuthenticate.cxx,v 1.34 2003/12/01 07:18:07 rdm Exp $
// Author: Fons Rademakers   26/11/2000

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TAuthenticate                                                        //
//                                                                      //
// An authentication module for ROOT based network services, like rootd //
// and proofd.                                                          //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "config.h"

#include "TAuthenticate.h"
#include "THostAuth.h"
#include "TAuthDetails.h"
#include "TNetFile.h"
#include "TSocket.h"
#include "TSystem.h"
#include "TError.h"
#include "Getline.h"
#include "TROOT.h"
#include "TEnv.h"
#include "TList.h"
#include "NetErrors.h"
#include "TRegexp.h"

#ifndef R__LYNXOS
#include <sys/stat.h>
#endif
#include <errno.h>
#include <sys/types.h>
#include <time.h>
#if !defined(R__WIN32) && !defined(R__MACOSX) && !defined(R__FBSD)
#include <crypt.h>
#endif
#ifdef WIN32
#  include <io.h>
#endif /* WIN32 */
#if defined(R__FBSD)
#  include <unistd.h>
#endif

#if defined(R__ALPHA) || defined(R__SGI) || defined(R__MACOSX)
extern "C" char *crypt(const char *, const char *);
#endif


Int_t TAuthenticate::fgRSAInit = 0;
rsa_KEY TAuthenticate::fgRSAPriKey;
rsa_KEY TAuthenticate::fgRSAPubKey;
rsa_KEY_export TAuthenticate::fgRSAPubExport = { 0, 0 };

TString TAuthenticate::fgUser;
TString TAuthenticate::fgPasswd;
Bool_t TAuthenticate::fgPwHash;
Bool_t TAuthenticate::fgSRPPwd;
SecureAuth_t TAuthenticate::fgSecAuthHook;
Krb5Auth_t TAuthenticate::fgKrb5AuthHook;
GlobusAuth_t TAuthenticate::fgGlobusAuthHook;
TString TAuthenticate::fgDefaultUser;
Bool_t TAuthenticate::fgAuthReUse;
Bool_t TAuthenticate::fgPromptUser;
Bool_t TAuthenticate::fgUsrPwdCrypt;

TList *TAuthenticate::fgAuthInfo = 0;

TString TAuthenticate::fgAuthMeth[] = { "UsrPwd", "SRP", "Krb5", "Globus", "SSH", "UidGid" };

ClassImp(TAuthenticate)

//______________________________________________________________________________
 TAuthenticate::TAuthenticate(TSocket *sock, const char *remote,
                             const char *proto, const char *user)
{
   // Create authentication object.

   fSocket   = sock;
   fRemote   = remote;
   fHostAuth = 0;
   fVersion  = 3;                // The latest, by default
   fRSAKey   = 0;

   if (gDebug > 2)
      Info("TAuthenticate", "Enter: local host: %s, user is: %s (proto: %s)",
           gSystem->HostName(), user, proto);

   // Set protocol string.
   // Check if version should be different ...
   char *pdd;
   if (proto && strlen(proto) > 0) {
      char *sproto = StrDup(proto);
      if ((pdd = strstr(sproto, ":")) != 0) {
         int rproto = atoi(pdd + 1);
         *pdd = '0';
         if (strstr(sproto, "root") != 0) {
            if (rproto < 9 ) {
               fVersion = 2;
               if (rproto < 8) {
                  fVersion = 1;
                  if (rproto < 6)
                     fVersion = 0;
               }
            }
         }
         if (strstr(sproto, "proof") != 0) {
            if (rproto < 8) {
               fVersion = 2;
               if (rproto < 7)
                  fVersion = 1;
            }
         }
         if (gDebug > 3)
            Info("TAuthenticate",
                 "service: %s (remote protocol: %d): fVersion: %d", sproto,
                 rproto, fVersion);
      }
      fProtocol = sproto;
   }

   // Check or get user name
   fUser = "";
   TString CheckUser;
   if (user && strlen(user) > 0) {
      fUser = user;
      CheckUser = user;
   } else {
      UserGroup_t *u = gSystem->GetUserInfo();
      if (u)
         CheckUser = u->fUser;
      delete u;
   }
   fPasswd = "";
   fPwHash = kFALSE;
   fSRPPwd = kFALSE;

   // RSA key generation (one per session)
   if (!fgRSAInit) {
      GenRSAKeys();
      fgRSAInit = 1;
   }

   // Check and save the host FQDN ...
   TString fqdn;
   TInetAddress addr = gSystem->GetHostByName(fRemote);
   if (addr.IsValid()) {
      fqdn = addr.GetHostName();
      if (fqdn == "UnNamedHost")
         fqdn = addr.GetHostAddress();
   }
   if (gDebug > 3)
      Info("TAuthenticate",
           "number of HostAuth Instantiations in memory: %d",
           GetAuthInfo()->GetSize());

   // Check list of auth info for already loaded info about this host
   fHostAuth = GetHostAuth(fqdn, CheckUser);

   // If we did not find a good THostAuth instantiation, create one
   if (fHostAuth == 0) {
      // Determine applicable auth methods from client choices
      Int_t *nmeth;
      Int_t *security[kMAXSEC];
      char **details[kMAXSEC];
      char **usr = new char *[1];
      usr[0] = StrDup(fUser);
      GetAuthMeth(fqdn, fProtocol, &usr, &nmeth, security, details);

      // Translate to Input for THostAuth
      int i, nm = nmeth[0], am[kMAXSEC];
      char *det[kMAXSEC];
      for (i = 0; i < kMAXSEC; i++) {
         if (i < nm) {
            am[i] = security[i][0];
            det[i] = StrDup(details[i][0]);
         } else {
            am[i] = -1;
            det[i] = 0;
         }
      }
      if (gDebug > 3) {
         Info("TAuthenticate", "got %d methods", nmeth[0]);
         for (i = 0; i < nmeth[0]; i++) {
            Info("TAuthenticate", "got (%d,0) security:%d details:%s", i,
                 security[i][0], details[i][0]);
         }
      }
      // Create THostAuth object
      fHostAuth = new THostAuth(fqdn, fUser, nm, am, det);
      // ... and add it to the list
      GetAuthInfo()->Add(fHostAuth);
      if (gDebug > 3)
         fHostAuth->Print();
      for (i = 0; i < nmeth[0]; i++) {   // what if nu > 0? (rdm)
         if (security[i]) delete[] security[i];
         if (details[i][0]) delete[] details[i][0];
         if (det[i]) delete[] det[i];
      }
      if (nmeth) delete [] nmeth;
      if (usr[0]) delete[] usr[0];
   }

   // If a secific method has been requested via the protocol
   // set it as first
   Int_t Sec = -1;
   if (fProtocol.Contains("roots") || fProtocol.Contains("proofs")) {
      Sec = TAuthenticate::kSRP;
   } else if (fProtocol.Contains("rootk") || fProtocol.Contains("proofk")) {
      Sec = TAuthenticate::kKrb5;
   }
   if (Sec > -1 && Sec < kMAXSEC) {
      if (fHostAuth->HasMethod(Sec)) {
         fHostAuth->SetFirst(Sec);
      } else {
         TString Det(GetDefaultDetails(Sec, 1, CheckUser));
         fHostAuth->SetFirst(Sec, Det);
      }
   }

   // This is what we have in memory
   if (gDebug > 3) {
      TIter next(fHostAuth->Established());
      TAuthDetails *ad;
      while ((ad = (TAuthDetails *) next()))
         ad->Print("0");
   }
}

//______________________________________________________________________________
 Bool_t TAuthenticate::Authenticate()
{
   // Authenticate to remote rootd or proofd server. Return kTRUE if
   // authentication succeeded.

   Int_t RemMeth = 0, rMth[kMAXSEC], tMth[kMAXSEC] = {0};
   Int_t meth = 0;
   char NoSupport[80] = { 0 };
   char TriedMeth[80] = { 0 };

   TString user, passwd;
   Bool_t pwhash;

   Int_t ntry = 0;
   if (gDebug > 2)
      Info("Authenticate", "enter: fUser: %s", fUser.Data());
   NoSupport[0] = 0;

 negotia:
   tMth[meth] = 1;
   if (gDebug > 2) {
      ntry++;
      Info("Authenticate", "try #: %d", ntry);
   }

   user = "";
   passwd = "";
   pwhash = kFALSE;

   // Security level from the list (if not in cleanup mode ...)
   fSecurity = (ESecurity) fHostAuth->GetMethods(meth);
   fDetails = fHostAuth->GetDetails((Int_t) fSecurity);
   if (gDebug > 2)
      Info("Authenticate",
           "trying authentication: method:%d, default details:%s",
           fSecurity, fDetails.Data());

   // Keep track of tried methods in a list
   if (strlen(TriedMeth) > 0)
      sprintf(TriedMeth, "%s/%s", TriedMeth, fgAuthMeth[fSecurity].Data());
   else
      sprintf(TriedMeth, "%s", fgAuthMeth[fSecurity].Data());

   // Set environments
   SetEnvironment();

   // This is for dynamic loads ...
#ifdef ROOTLIBDIR
   TString RootDir = TString(ROOTLIBDIR);
#else
   TString RootDir = TString(gRootDir) + "/lib";
#endif

   // Auth calls depend of fSec
   Int_t st = -1;
   if (fSecurity == kClear) {

      Bool_t rc = kFALSE;

      // UsrPwd Authentication
      user = fgDefaultUser;
      if (user != "")
         CheckNetrc(user, passwd, pwhash, (Bool_t &)kFALSE);
      if (passwd == "") {
         if (fgPromptUser)
            user = PromptUser(fRemote);
         rc = GetUserPasswd(user, passwd, pwhash, (Bool_t &)kFALSE);
      }
      fUser = user;
      fPasswd = passwd;

      if (!rc) {

         if (fUser != "root")
            st = ClearAuth(user, passwd, pwhash);
      } else {
         Error("Authenticate",
               "unable to get user name for UsrPwd authentication");
      }

   } else if (fSecurity == kSRP) {

      Bool_t rc = kFALSE;

      // SRP Authentication
      user = fgDefaultUser;
      if (user != "")
         CheckNetrc(user, passwd, pwhash, (Bool_t &)kTRUE);
      if (passwd == "") {
         if (fgPromptUser)
            user = PromptUser(fRemote);
         rc = GetUserPasswd(user, passwd, pwhash, (Bool_t &)kTRUE);
      }
      fUser = user;
      fPasswd = passwd;

      if (!fgSecAuthHook) {

         char *p;
         TString lib = RootDir + "/libSRPAuth";
         if ((p = gSystem->DynamicPathName(lib, kTRUE))) {
            delete[]p;
            gSystem->Load(lib);
         }
      }
      if (!rc && fgSecAuthHook) {

         st = (*fgSecAuthHook) (this, user, passwd, fRemote, fDetails,
                                fVersion);
      } else {
         if (!fgSecAuthHook)
            Error("Authenticate",
                  "no support for SRP authentication available");
         if (rc)
            Error("Authenticate",
                  "unable to get user name for SRP authentication");
      }
      // Fill present user info ...
      if (st == 1) {
         fPwHash = kFALSE;
         fSRPPwd = kTRUE;
      }

   } else if (fSecurity == kKrb5) {

      if (fVersion > 0) {

         // Kerberos 5 Authentication
         if (!fgKrb5AuthHook) {
            char *p;
            TString lib = RootDir + "/libKrb5Auth";
            if ((p = gSystem->DynamicPathName(lib, kTRUE))) {
               delete[]p;
               gSystem->Load(lib);
            }
         }
         if (fgKrb5AuthHook) {
            fUser = fgDefaultUser;
            st = (*fgKrb5AuthHook) (this, fUser, fDetails, fVersion);
         } else {
            Error("Authenticate",
                  "support for kerberos5 auth locally unavailable");
         }
      } else {
         if (gDebug > 0)
            Info("Authenticate",
                 "remote daemon does not support Kerberos authentication");
         if (strlen(NoSupport) > 0)
            sprintf(NoSupport, "%s/Krb5", NoSupport);
         else
            sprintf(NoSupport, "Krb5");
      }

   } else if (fSecurity == kGlobus) {
      if (fVersion > 1) {

         // Globus Authentication
         if (!fgGlobusAuthHook) {
            char *p;
            TString lib = RootDir + "/libGlobusAuth";
            if ((p = gSystem->DynamicPathName(lib, kTRUE))) {
               delete[]p;
               gSystem->Load(lib);
            }
         }
         if (fgGlobusAuthHook) {
            st = (*fgGlobusAuthHook) (this, fUser, fDetails);
         } else {
            Error("Authenticate",
                  "no support for Globus authentication available");
         }
      } else {
         if (gDebug > 0)
            Info("Authenticate",
                 "remote daemon does not support Globus authentication");
         if (strlen(NoSupport) > 0)
            sprintf(NoSupport, "%s/Globus", NoSupport);
         else
            sprintf(NoSupport, "Globus");
      }


   } else if (fSecurity == kSSH) {

      if (fVersion > 1) {

         // SSH Authentication
         st = SshAuth(fUser);

      } else {
         if (gDebug > 0)
            Info("Authenticate",
                 "remote daemon does not support SSH authentication");
         if (strlen(NoSupport) > 0)
            sprintf(NoSupport, "%s/SSH", NoSupport);
         else
            sprintf(NoSupport, "SSH");
      }

   } else if (fSecurity == kRfio) {

      if (fVersion > 1) {

         // UidGid Authentication
         st = RfioAuth(fUser);

      } else {
         if (gDebug > 0)
            Info("Authenticate",
                 "remote daemon does not support UidGid authentication");
         if (strlen(NoSupport) > 0)
            sprintf(NoSupport, "%s/UidGid", NoSupport);
         else
            sprintf(NoSupport, "UidGid");
      }
   }
   // Analyse the result now ...
   Int_t kind, stat;
   if (st == 1) {
      return kTRUE;
   } else {
      if (fVersion > 2) {
         if (st == -2) {
            // Remote host does not accepts connections from local host
            return kFALSE;
         }
      }
      Int_t nmet = fHostAuth->NumMethods();
      Int_t remloc = nmet - meth - 1;
      if (gDebug > 2)
         Info("Authenticate",
              "got st=%d: still %d methods locally available",
              st, remloc);
      if (st == -1) {
         if (gDebug > 2)
            Info("Authenticate",
                 "method not even started: insufficient or wrong info: %s",
                 "try with next method, if any");
         if (meth < nmet - 1) {
            meth++;
            goto negotia;
         } else if (strlen(NoSupport) > 0)
            Info("Authenticate",
                 "attempted methods %s are not supported by remote server version",
                 NoSupport);
         Info("Authenticate",
              "failure: list of attempted methods: %s", TriedMeth);
         return kFALSE;
      } else {
         if (fVersion < 2) {
            if (gDebug > 2)
               Info("Authenticate",
                    "negotiation not supported remotely: try next method, if any");
            if (meth < nmet - 1) {
               meth++;
               goto negotia;
            } else if (strlen(NoSupport) > 0)
               Info("Authenticate",
                    "attempted methods %s are not supported by remote server version",
                    NoSupport);
            Info("Authenticate",
                 "failure: list of attempted methods: %s", TriedMeth);
            return kFALSE;
         }
         // Attempt negotiation ...
         fSocket->Recv(stat, kind);
         if (gDebug > 2)
            Info("Authenticate",
                 "after failed attempt: kind= %d, stat= %d", kind, stat);
         if (kind == kROOTD_ERR) {
            if (gDebug > 0)
               AuthError("Authenticate", stat);
            Info("Authenticate",
                 "failure: list of attempted methods: %s", TriedMeth);
            return kFALSE;
         } else if (kind == kROOTD_NEGOTIA) {
            if (stat > 0) {
               int len = 3 * stat;
               char *answer = new char[len];
               int nrec = fSocket->Recv(answer, len, kind);  // returns user
               if (kind != kMESS_STRING)
                  Warning("Authenticate",
                          "strings with accepted methods not received (%d:%d)",
                          kind, nrec);
               RemMeth =
                   sscanf(answer, "%d %d %d %d %d %d", &rMth[0], &rMth[1],
                          &rMth[2], &rMth[3], &rMth[4], &rMth[5]);
               if (gDebug > 0 && remloc > 0)
                  Info("Authenticate",
                       "remotely allowed methods not yet tried: %s",
                       answer);
            } else if (stat == 0) {
               if (strlen(NoSupport) > 0)
                  Info("Authenticate",
                       "attempted methods %s are not supported by remote server version",
                       NoSupport);
               Info("Authenticate",
                    "failure: list of attempted methods: %s", TriedMeth);
               return kFALSE;
            }
            // If no more local methods, exit
            if (remloc < 1) {
               if (strlen(NoSupport) > 0)
                  Info("Authenticate",
                       "attempted methods %s are not supported by remote server version",
                       NoSupport);
               Info("Authenticate",
                    "failure: list of attempted methods: %s", TriedMeth);
               return kFALSE;
            }
            // Look if a non tried method matches
            int i, j;
            char lav[40] = { 0 };
            for (i = 0; i < RemMeth; i++) {
               for (j = 0; j < nmet; j++) {
                  if (fHostAuth->GetMethods(j) == rMth[i] && tMth[j] == 0) {
                     meth = j;
                     goto negotia;
                  }
                  if (i == 0)
                     sprintf(lav, "%s %d", lav, fHostAuth->GetMethods(j));
               }
            }
            if (gDebug > 0)
               Warning("Authenticate",
                       "no match with those locally available: %s",
                       lav);
            if (strlen(NoSupport) > 0)
               Info("Authenticate",
                    "attempted methods %s are not supported by remote server version",
                    NoSupport);
            Info("Authenticate",
                 "failure: list of attempted methods: %s", TriedMeth);
            return kFALSE;
         } else                 // unknown message code at this stage
         if (strlen(NoSupport) > 0)
            Info("Authenticate",
                 "attempted methods %s are not supported by remote server version",
                 NoSupport);
            Info("Authenticate",
                 "failure: list of attempted methods: %s", TriedMeth);
         return kFALSE;
      }
   }
}

//______________________________________________________________________________
 void TAuthenticate::SetEnvironment()
{
   // Set default authentication environment. The values are inferred
   // from fSecurity and fDetails.

   if (gDebug > 2)
      Info("SetEnvironment",
           "setting environment: fSecurity:%d, fDetails:%s", fSecurity,
           fDetails.Data());

   // Defaults
   fgDefaultUser = fgUser;
   if (fSecurity == kKrb5)
      fgAuthReUse = kFALSE;
   else
      fgAuthReUse = kTRUE;
   fgPromptUser = kFALSE;

   // Decode fDetails, is non empty ...
   if (fDetails != "") {
      char UsDef[kMAXPATHLEN] = { 0 };
      int lDet = strlen(fDetails.Data()) + 2;
      char Pt[5] = { 0 }, Ru[5] = { 0 };
      char *Us = 0, *Cd = 0, *Cf = 0, *Kf = 0, *Ad = 0, *Cp = 0;
      const char *ptr;

      TString UsrPromptDef = TString(GetAuthMethod(fSecurity)) + ".LoginPrompt";
      if ((ptr = strstr(fDetails, "pt:")) != 0) {
         sscanf(ptr + 3, "%s %s", Pt, UsDef);
      } else {
         if (!strncasecmp(gEnv->GetValue(UsrPromptDef,""),"no",2) ||
             !strncmp(gEnv->GetValue(UsrPromptDef,""),"0",1))
            strcpy(Pt,"0");
         else
            strcpy(Pt,"1");
      }
      TString UsrReUseDef = TString(GetAuthMethod(fSecurity)) + ".ReUse";
      if ((ptr = strstr(fDetails, "ru:")) != 0) {
         sscanf(ptr + 3, "%s %s", Ru, UsDef);
      } else {
         if (!strncasecmp(gEnv->GetValue(UsrReUseDef,""),"no",2) ||
             !strncmp(gEnv->GetValue(UsrReUseDef,""),"0",1))
            strcpy(Ru,"0");
         else
            strcpy(Ru,"1");
      }

      // Now action depends on method ...
      if (fSecurity == kGlobus) {
         Cd = new char[lDet];
         Cf = new char[lDet];
         Kf = new char[lDet];
         Ad = new char[lDet];
         Cd[0] = '0';
         Cf[0] = '0';
         Kf[0] = '0';
         Ad[0] = '0';
         if ((ptr = strstr(fDetails, "cd:")) != 0)
            sscanf(ptr, "%s %s", Cd, UsDef);
         if ((ptr = strstr(fDetails, "cf:")) != 0)
            sscanf(ptr, "%s %s", Cf, UsDef);
         if ((ptr = strstr(fDetails, "kf:")) != 0)
            sscanf(ptr, "%s %s", Kf, UsDef);
         if ((ptr = strstr(fDetails, "ad:")) != 0)
            sscanf(ptr, "%s %s", Ad, UsDef);
         if (gDebug > 2) {
            Info("SetEnvironment",
                 "details:%s, Pt:%s, Ru:%s, Cd:%s, Cf:%s, Kf:%s, Ad:%s",
                 fDetails.Data(), Pt, Ru, Cd, Cf, Kf, Ad);
         }
      } else if (fSecurity == kClear) {
         Us = new char[lDet];
         Us[0] = '0';
         Cp = new char[lDet];
         Cp[0] = '0';
         if ((ptr = strstr(fDetails, "us:")) != 0)
            sscanf(ptr + 3, "%s %s", Us, UsDef);
         if ((ptr = strstr(fDetails, "cp:")) != 0)
            sscanf(ptr + 3, "%s %s", Cp, UsDef);
         if (gDebug > 2)
            Info("SetEnvironment", "details:%s, Pt:%s, Ru:%s, Us:%s Cp:%s",
                 fDetails.Data(), Pt, Ru, Us, Cp);
      } else {
         Us = new char[lDet];
         Us[0] = '0';
         if ((ptr = strstr(fDetails, "us:")) != 0)
            sscanf(ptr + 3, "%s %s", Us, UsDef);
         if (gDebug > 2)
            Info("SetEnvironment", "details:%s, Pt:%s, Ru:%s, Us:%s",
                 fDetails.Data(), Pt, Ru, Us);
      }

      // Set Prompt flag
      if (!strncasecmp(Pt, "yes",3) || !strncmp(Pt, "1", 1))
         fgPromptUser = kTRUE;

      // Set ReUse flag
      if (fSecurity == kKrb5) {
         fgAuthReUse = kFALSE;
         if (!strncasecmp(Ru, "yes",3) || !strncmp(Ru, "1",1))
            fgAuthReUse = kTRUE;
      } else {
         fgAuthReUse = kTRUE;
         if (!strncasecmp(Ru, "no",2) || !strncmp(Ru, "0",1))
            fgAuthReUse = kFALSE;
      }

      // UnSet Crypt flag for UsrPwd, if requested
      if (fSecurity == kClear) {
         fgUsrPwdCrypt = kTRUE;
         if (!strncmp(Cp, "no", 2) || !strncmp(Cp, "0", 1))
            fgUsrPwdCrypt = kFALSE;
      }
      // Build UserDefaults
      if (fSecurity == kGlobus) {
         UsDef[0] = '0';
         if (Cd != 0) {
            strcat(UsDef," ");
            strcat(UsDef,Cd);
            delete[] Cd;
         }
         if (Cf != 0) {
            strcat(UsDef," ");
            strcat(UsDef,Cf);
            delete[] Cf;
         }
         if (Kf != 0) {
            strcat(UsDef," ");
            strcat(UsDef,Kf);
            delete[] Kf;
         }
         if (Ad != 0) {
            strcat(UsDef," ");
            strcat(UsDef,Ad);
            delete[] Ad;
         }
      } else {
         if (fUser == "") {
            if (Us != 0) {
               sprintf(UsDef, "%s", Us);
               delete[] Us;
            }
         } else {
            if (fSecurity == kKrb5) {
               if (Us != 0) {
                  char *pat = strstr(Us, "@");
                  if (pat != 0)
                     sprintf(UsDef, "%s%s", fUser.Data(), pat);
                  else
                     sprintf(UsDef, "%s", fUser.Data());
               } else {
                  sprintf(UsDef, "%s", fUser.Data());
               }
            } else {
               sprintf(UsDef, "%s", fUser.Data());
            }
         }
      }
      if (strlen(UsDef) > 0) {
         fgDefaultUser = UsDef;
      } else {
         if (fgUser != "") {
            fgDefaultUser = fgUser;
         } else {
            UserGroup_t *u = gSystem->GetUserInfo();
            if (u)
               fgDefaultUser = u->fUser;
            delete u;
         }
      }
      if (fgDefaultUser == "anonymous" || fgDefaultUser == "rootd" ||
          fgUser != "")  // when set by user don't prompt for it anymore
         fgPromptUser = kFALSE;

      if (gDebug > 2)
         Info("SetEnvironment", "UsDef:%s", fgDefaultUser.Data());
   }
}

//______________________________________________________________________________
 Bool_t TAuthenticate::GetUserPasswd(TString &user, TString &passwd,
                                    Bool_t &pwhash, Bool_t &srppwd)
{
   // Try to get user name and passwd from several sources.

   if (gDebug > 3)
      Info("GetUserPasswd", "Enter: User: '%s' Hash:%d SRP:%d",
            user.Data(),(Int_t)pwhash,(Int_t)srppwd);

   // Get user and passwd set via static functions SetUser and SetPasswd.
   if (user == "") {
      if (fgUser != "")
         user = fgUser;
      if (passwd == "" && fgPasswd != "" && srppwd == fgSRPPwd) {
         passwd = fgPasswd;
         pwhash = fgPwHash;
      }
   } else {
      if (fgUser != "" && user == fgUser) {
         if (passwd == "" && fgPasswd != "" && srppwd == fgSRPPwd) {
             passwd = fgPasswd;
             pwhash = fgPwHash;
         }
      }
   }
   if (gDebug > 3)
      Info("GetUserPasswd", "In memory: User: '%s' Hash:%d",
            user.Data(),(Int_t)pwhash);

   // Check system info for user if still not defined
   if (user == "") {
      UserGroup_t *u = gSystem->GetUserInfo();
      if (u)
         user = u->fUser;
      delete u;
      if (gDebug > 3)
         Info("GetUserPasswd", "In memory: User: '%s' Hash:%d",
            user.Data(),(Int_t)pwhash);
   }

   // Check ~/.rootnetrc and ~/.netrc files if user was not set via
   // the static SetUser() method.
   if (user == "" || passwd == "") {
      if (gDebug > 3)
         Info("GetUserPasswd", "Checking .netrc family ...");
      CheckNetrc(user, passwd, pwhash, srppwd);
   }
   if (gDebug > 3)
      Info("GetUserPasswd", "From .netrc family: User: '%s' Hash:%d",
            user.Data(),(Int_t)pwhash);

   // If user also not set via  ~/.rootnetrc or ~/.netrc ask user.
   if (user == "") {
      user = PromptUser(fRemote);
      if (user == "") {
         Error("GetUserPasswd", "user name not set");
         return 1;
      }
   }

   return 0;
}

//______________________________________________________________________________
 Bool_t TAuthenticate::CheckNetrc(TString &user, TString &passwd)
{
   // Try to get user name and passwd from the ~/.rootnetrc or
   // ~/.netrc files. For more info see the version with 4 arguments.
   // This version is maintained for backward compatability reasons.

   Bool_t hash, srppwd;

   // Set srppwd flag
   srppwd = (fSecurity == kSRP) ? kTRUE : kFALSE;

   return CheckNetrc(user, passwd, hash, srppwd);
}

//______________________________________________________________________________
 Bool_t TAuthenticate::CheckNetrc(TString &user, TString &passwd,
                                 Bool_t &pwhash, Bool_t &srppwd)
{
   // Try to get user name and passwd from the ~/.rootnetrc or
   // ~/.netrc files. First ~/.rootnetrc is tried, after that ~/.netrc.
   // These files will only be used when their access masks are 0600.
   // Returns kTRUE if user and passwd were found for the machine
   // specified in the URL. If kFALSE, user and passwd are "".
   // If srppwd == kTRUE then a SRP ('secure') pwd is searched for in
   // the files.
   // The boolean pwhash is set to kTRUE if the returned passwd is to
   // be understood as password hash, i.e. if the 'password-hash' keyword
   // is found in the 'machine' lines; not implemented for 'secure'
   // and the .netrc file.
   // The format of these files are:
   //
   // # this is a comment line
   // machine <machine fqdn> login <user> password <passwd>
   // machine <machine fqdn> login <user> password-hash <passwd>
   //
   // and in addition ~/.rootnetrc also supports:
   //
   // secure <machine fqdn> login <user> password <passwd>
   //
   // for the secure protocols. All lines must start in the first column.

   Bool_t result = kFALSE;
   Bool_t first = kTRUE;
   TString remote = fRemote;

   passwd = "";
   pwhash = kFALSE;

   char *net =
       gSystem->ConcatFileName(gSystem->HomeDirectory(), ".rootnetrc");

   // Determine FQDN of the host ...
   TInetAddress addr = gSystem->GetHostByName(fRemote);
   if (addr.IsValid()) {
      remote = addr.GetHostName();
      if (remote == "UnNamedHost")
         remote = addr.GetHostAddress();
   }

 again:
#ifdef WIN32
   // Since Win32 does not have proper protections use file always
   FILE * fd1;
   if ((fd1 = fopen(net, "r"))) {
      fclose(fd1);
      if (1) {
#else
   // Only use file when its access rights are 0600
   struct stat buf;
   if (stat(net, &buf) == 0) {
      if (S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode) &&
          (buf.st_mode & 0777) == (S_IRUSR | S_IWUSR)) {
#endif
         FILE *fd = fopen(net, "r");
         char line[256];
         while (fgets(line, sizeof(line), fd) != 0) {
            if (line[0] == '#')
               continue;
            char word[6][64];
            int nword = sscanf(line, "%s %s %s %s %s %s", word[0], word[1],
                               word[2], word[3], word[4], word[5]);
            if (nword != 6)
               continue;
            if (srppwd && strcmp(word[0], "secure"))
               continue;
            if (!srppwd && strcmp(word[0], "machine"))
               continue;
            if (strcmp(word[2], "login"))
               continue;
            if (srppwd && strcmp(word[4], "password"))
               continue;
            if (!srppwd &&
               strcmp(word[4], "password") && strcmp(word[4], "password-hash"))
               continue;

            // Determine FQDN of the host name found in the file ...
            TString host_tmp = word[1];
            TInetAddress addr = gSystem->GetHostByName(word[1]);
            if (addr.IsValid()) {
               host_tmp = addr.GetHostName();
               if (host_tmp == "UnNamedHost")
                  host_tmp = addr.GetHostAddress();
            }

            if (host_tmp == remote) {
               if (user == "") {
                  user = word[3];
                  passwd = word[5];
                  if (!strcmp(word[4], "password-hash"))
                     pwhash = kTRUE;
                  result = kTRUE;
                  break;
               } else {
                  if (!strcmp(word[3], user.Data())) {
                     passwd = word[5];
                     if (!strcmp(word[4], "password-hash"))
                        pwhash = kTRUE;
                     result = kTRUE;
                     break;
                  }
               }
            }
         }
         fclose(fd);
      } else
         Warning("CheckNetrc",
                 "file %s exists but has not 0600 permission", net);
   }
   delete[]net;

   if (first && !srppwd && !result) {
      net = gSystem->ConcatFileName(gSystem->HomeDirectory(), ".netrc");
      first = kFALSE;
      goto again;
   }

   return result;
}

//______________________________________________________________________________
 const char *TAuthenticate::GetGlobalUser()
{
   // Static method returning the global user.

   return fgUser;
}

//______________________________________________________________________________
 const char *TAuthenticate::GetGlobalPasswd()
{
   // Static method returning the global global password.

   return fgPasswd;
}

//______________________________________________________________________________
 Bool_t TAuthenticate::GetGlobalPwHash()
{
   // Static method returning the global password hash flag.

   return fgPwHash;
}

//______________________________________________________________________________
 Bool_t TAuthenticate::GetGlobalSRPPwd()
{
   // Static method returning the global SRP password flag.

   return fgSRPPwd;
}

//______________________________________________________________________________
 const char *TAuthenticate::GetDefaultUser()
{
   // Static method returning the default user information.

   return fgDefaultUser;
}

//______________________________________________________________________________
 Bool_t TAuthenticate::GetAuthReUse()
{
   // Static method returning the authentication reuse settings.

   return fgAuthReUse;
}

//______________________________________________________________________________
 Bool_t TAuthenticate::GetPromptUser()
{
   // Static method returning the prompt user settings.

   return fgPromptUser;
}

//______________________________________________________________________________
 const char *TAuthenticate::GetAuthMethod(Int_t idx)
{
   // Static method returning the method corresponding to idx.

   if (idx < 0 || idx > kMAXSEC-1) {
      ::Error("Authenticate::GetAuthMethod", "idx out of bounds (%d)", idx);
      idx = 0;
   }
   return fgAuthMeth[idx];
}

//______________________________________________________________________________
 Int_t TAuthenticate::GetAuthMethodIdx(const char *meth)
{
   // Static method returning the method index (which can be used to find
   // the method in GetAuthMethod()). Returns -1 in case meth is not found.

   if (meth && meth[0]) {
      for (Int_t i = 0; i < kMAXSEC; i++) {
         if (!fgAuthMeth[i].CompareTo(meth, TString::kIgnoreCase))
            return i;
      }
   }

   return -1;
}

//______________________________________________________________________________
 char *TAuthenticate::PromptUser(const char *remote)
{
   // Static method to prompt for the user name to be used for authentication
   // to rootd or proofd. User is asked to type user name.
   // Returns user name (which must be deleted by caller) or 0.
   // If non-interactive run (eg ProofServ) returns default user.

   const char *user;
   if (fgDefaultUser != "")
      user = fgDefaultUser;
   else
      user = gSystem->Getenv("USER");
#ifdef R__WIN32
   if (!user)
      user = gSystem->Getenv("USERNAME");
#endif
   if (isatty(0) == 0 || isatty(1) == 0) {
      ::Warning("TAuthenticate::PromptUser",
                "not tty: cannot prompt for user, returning default");
      if (strlen(user))
         return StrDup(user);
      else
         return StrDup("None");
   }

   char *usr = Getline(Form("Name (%s:%s): ", remote, user));
   if (usr[0]) {
      usr[strlen(usr) - 1] = 0; // get rid of \n
      if (strlen(usr))
         return StrDup(usr);
      else
         return StrDup(user);
   }
   return 0;
}

//______________________________________________________________________________
 char *TAuthenticate::PromptPasswd(const char *prompt)
{
   // Static method to prompt for the user's passwd to be used for
   // authentication to rootd or proofd. Uses non-echoing command line
   // to get passwd. Returns passwd (which must de deleted by caller) or 0.
   // If non-interactive run (eg ProofServ) returns -1

   if (isatty(0) == 0 || isatty(1) == 0) {
      ::Warning("TAuthenticate::PromptPasswd",
                "not tty: cannot prompt for passwd, returning -1");
      return StrDup("-1");
   }

   Gl_config("noecho", 1);
   char *pw = Getline((char *) prompt);
   Gl_config("noecho", 0);
   if (pw[0]) {
      pw[strlen(pw) - 1] = 0;   // get rid of n
      return StrDup(pw);
   }
   return 0;
}

//______________________________________________________________________________
 GlobusAuth_t TAuthenticate::GetGlobusAuthHook()
{
   // Static method returning the globus authorization hook.

   return fgGlobusAuthHook;
}

//______________________________________________________________________________
 const char *TAuthenticate::GetRSAPubExport()
{
   // Static method returning the RSA public keys.

   return fgRSAPubExport.keys;
}

//______________________________________________________________________________
 Int_t TAuthenticate::GetRSAInit()
{
   // Static method returning the RSA initialization flag.

   return fgRSAInit;
}

//______________________________________________________________________________
 void TAuthenticate::SetRSAInit()
{
   // Static method setting RSA initialization flag.

   fgRSAInit = 1;
}

//______________________________________________________________________________
 TList *TAuthenticate::GetAuthInfo()
{
   // Static method returning the list with authentication details.

   if (!fgAuthInfo)
      fgAuthInfo = new TList;
   return fgAuthInfo;
}

//______________________________________________________________________________
 void TAuthenticate::AuthError(const char *where, Int_t err)
{
   // Print error string depending on error code.

   ::Error(Form("TAuthenticate::%s", where), gRootdErrStr[err]);
}

//______________________________________________________________________________
 void TAuthenticate::SetGlobalUser(const char *user)
{
   // Set global user name to be used for authentication to rootd or proofd.

   if (fgUser != "")
      fgUser = "";

   if (user && user[0])
      fgUser = user;
}

//______________________________________________________________________________
 void TAuthenticate::SetGlobalPasswd(const char *passwd)
{
   // Set global passwd to be used for authentication to rootd or proofd.

   if (fgPasswd != "")
      fgPasswd = "";

   if (passwd && passwd[0])
      fgPasswd = passwd;
}

//______________________________________________________________________________
 void TAuthenticate::SetGlobalPwHash(Bool_t pwhash)
{
   // Set global passwd hash flag to be used for authentication to rootd or proofd.

   fgPwHash = pwhash;
}

//______________________________________________________________________________
 void TAuthenticate::SetGlobalSRPPwd(Bool_t srppwd)
{
   // Set global SRP passwd flag to be used for authentication to rootd or proofd.

   fgSRPPwd = srppwd;
}

//______________________________________________________________________________
 void TAuthenticate::SetDefaultUser(const char *defaultuser)
{
   // Set default user name.

   if (fgDefaultUser != "")
      fgDefaultUser = "";

   if (defaultuser && defaultuser[0])
      fgDefaultUser = defaultuser;
}

//______________________________________________________________________________
 void TAuthenticate::SetAuthReUse(Bool_t authreuse)
{
   // Set global AuthReUse flag

   fgAuthReUse = authreuse;
}

//______________________________________________________________________________
 void TAuthenticate::SetPromptUser(Bool_t promptuser)
{
   // Set global PromptUser flag

   fgPromptUser = promptuser;
}

//______________________________________________________________________________
 void TAuthenticate::SetSecureAuthHook(SecureAuth_t func)
{
   // Set secure authorization function. Automatically called when libSRPAuth
   // is loaded.

   fgSecAuthHook = func;
}

//______________________________________________________________________________
 void TAuthenticate::SetKrb5AuthHook(Krb5Auth_t func)
{
   // Set kerberos5 authorization function. Automatically called when
   // libKrb5Auth is loaded.

   fgKrb5AuthHook = func;
}

//______________________________________________________________________________
 void TAuthenticate::SetGlobusAuthHook(GlobusAuth_t func)
{
   // Set Globus authorization function. Automatically called when
   // libGlobusAuth is loaded.

   fgGlobusAuthHook = func;
}

//______________________________________________________________________________
 Int_t TAuthenticate::SshAuth(TString &User)
{
   // SSH client authentication code.

   // Check First if a 'ssh' executable exists ...
   char *gSshExe =
       gSystem->Which(gSystem->Getenv("PATH"), "ssh", kExecutePermission);

   if (!gSshExe) {
      if (gDebug > 2)
         Info("SshAuth", "ssh not found in $PATH");
      return -1;
   }

   if (gDebug > 2)
      Info("SshAuth", "ssh is %s", gSshExe);

   // Still allow for client definition of the ssh location ...
   if (strcmp(gEnv->GetValue("SSH.ExecDir", "-1"), "-1")) {
      if (gSshExe) delete[] gSshExe;
      gSshExe =
          StrDup(Form
                 ("%s/ssh", (char *) gEnv->GetValue("SSH.ExecDir", "")));
      if (gSystem->AccessPathName(gSshExe, kExecutePermission)) {
         Info("SshAuth", "%s not executable", gSshExe);
         if (gSshExe) delete[] gSshExe;
         return -1;
      }
   }
   // SSH-like authentication code.
   // Returns 0 in case authentication failed
   //         1 in case of success
   //        -1 in case of the remote node does not seem to support SSH-like Authentication
   //        -2 in case of the remote node does not seem to allow connections from this node

   char SecName[kMAXPATHLEN] = { 0 };

   // Determine user name ...
   User = GetSshUser();

   // Check ReUse
   Int_t ReUse = (int)fgAuthReUse;
   fDetails = TString(Form("pt:%d ru:%d us:",(int)fgPromptUser,(int)fgAuthReUse))
            + User;

   int retval, kind;

   // Create Options string
   char *Options = new char[strlen(User.Data()) + 40];
   int Opt = ReUse * kAUTH_REUSE_MSK;
   sprintf(Options, "%d none %ld %s", Opt, (Long_t)strlen(User.Data()),
           User.Data());

   // Check established authentications
   kind = kROOTD_SSH;
   retval = ReUse;
   Int_t rc = 0;
   if ((rc =
        AuthExists(this, (Int_t) TAuthenticate::kSSH, fDetails, Options,
                   &kind, &retval)) == 1) {
      // A valid authentication exists: we are done ...
      if (Options) delete[] Options;
      return 1;
   }
   if (Options) delete[] Options;
   if (rc == -2) {
      return rc;
   }
   if (retval == kErrNotAllowed && kind == kROOTD_ERR) {
      return 0;
   }
   // Check return flags
   if (kind != kROOTD_SSH)
      return 0;                 // something went wrong
   if (retval == 0)
      return 0;                 // no remote support for SSH
   if (retval == -2)
      return 0;                 // user unkmown to remote host

   // Wait for the server to communicate remote pid and location of command to execute
   char *CmdInfo = new char[retval + 1];
   fSocket->Recv(CmdInfo, retval + 1, kind);
   if (kind != kROOTD_SSH)
      return 0;                 // something went wrong
   if (gDebug > 3)
      Info("SshAuth", "received from server command info: %s", CmdInfo);

   int rport = -1;
   char *pp = 0;
   if ((pp = strstr(CmdInfo, "port")) != 0) {
      int clen = (int) (pp - CmdInfo);
      rport = atoi(pp + 5);
      CmdInfo[clen] = '0';
      if (gDebug > 3)
         Info("SshAuth", "using port: %d, command info: %s", rport,
              CmdInfo);
   }

   // If we are a non-interactive session we cannot reply
   TString noPrompt = "";
   if (isatty(0) == 0 || isatty(1) == 0) {
     noPrompt  = TString("-o 'PasswordAuthentication no' ");
     noPrompt += TString("-o 'StrictHostKeyChecking no' ");
     if (gDebug > 3)
        Info("SshAuth", "using noprompt options: %s", noPrompt.Data());
   }

   // Send authentication request to remote sshd
   // Create command
   char sshcmd[kMAXPATHLEN] = { 0 };
   if (rport == -1) {
      // Remote server did not specify a specific port ... use our default, whatever it is ...
      sprintf(sshcmd, "%s -x -l %s %s %s %s", gSshExe, User.Data(),
              noPrompt.Data(), fRemote.Data(), CmdInfo);
   } else {
      // Remote server did specify a specific port ...
      sprintf(sshcmd, "%s -x -l %s -p %d %s %s %s", gSshExe, User.Data(),
              rport, noPrompt.Data(), fRemote.Data(), CmdInfo);
   }

   // Execute command
   int ssh_rc = gSystem->Exec(sshcmd);
   if (gDebug > 3)
      Info("SshAuth", "system return code: %d", ssh_rc);

   if (ssh_rc) {
      // This is bad ... needs to notify rootd by other means ...
      TSocket *newsock =
          new TSocket(fRemote.Data(), fSocket->GetInetAddress().GetPort(),
                      -1);
      newsock->SetOption(kNoDelay, 1);  // Set some socket options
      newsock->Send((Int_t) 0, (Int_t) 0);  // Tell rootd we do not want parallel connection
      char cd1[1024], pipe[1024];
      int id1, id2, id3;
      sscanf(CmdInfo, "%s %d %s %d %d", cd1, &id3, pipe, &id1, &id2);
      sprintf(SecName, "%d -1 0 %s %ld %s None", -gSystem->GetPid(), pipe,
              (Long_t)strlen(User), User.Data());
      newsock->Send(SecName, kROOTD_SSH);
      // Receive error message
      fSocket->Recv(retval, kind);  // for consistency
      if (kind == kROOTD_ERR) {
         if (gDebug > 0)
            AuthError("SshAuth", retval);
      }
      SafeDelete(newsock);

      return 0;
   }

   // Receive key request info and type of key (if ok, error otherwise)
   int nrec = fSocket->Recv(retval, kind);  // returns user
   if (gDebug > 3)
      Info("SshAuth", "got message %d, flag: %d", kind, retval);

   // Check if an error occured
   if (kind == kROOTD_ERR) {
      if (gDebug > 0)
         AuthError("SshAuth", retval);
      return 0;
   }

   if (ReUse == 1) {

      // Save type of key
      if (kind != kROOTD_RSAKEY)
         Warning("SshAuth",
                 "problems recvn RSA key flag: got message %d, flag: %d",
                 kind, fRSAKey);

      fRSAKey = 1;

      // Send the key securely
      SendRSAPublicKey(fSocket);

      // Receive username used for login
      nrec = fSocket->Recv(retval, kind);  // returns user
      if (gDebug > 3)
         Info("SshAuth", "got message %d, flag: %d", kind, retval);
   }

   if (kind != kROOTD_SSH || retval < 1)
      Warning("SshAuth",
              "problems recvn (user,offset) length (%d:%d bytes:%d)", kind,
              retval, nrec);

   char *answer = new char[retval + 1];
   nrec = fSocket->Recv(answer, retval + 1, kind);  // returns user
   if (kind != kMESS_STRING)
      Warning("SshAuth", "username and offset not received (%d:%d)", kind,
              nrec);

   // Parse answer
   char *lUser = new char[retval];
   int OffSet = -1;
   sscanf(answer, "%s %d", lUser, &OffSet);
   if (gDebug > 3)
      Info("SshAuth", "received from server: user: %s, offset: %d", lUser,
           OffSet);

   // Receive Token
   char *Token = 0;
   if (ReUse == 1 && OffSet > -1) {
      if (SecureRecv(fSocket, 1, &Token) == -1) {
         Warning("SshAuth",
                 "problems secure-receiving token - may result in corrupted token");
      }
      if (gDebug > 3)
         Info("SshAuth", "received from server: token: '%s' ", Token);
   } else {
      Token = StrDup("");
   }

   // Create and save AuthDetails object
   SaveAuthDetails(this, (Int_t) TAuthenticate::kSSH, OffSet, ReUse,
                   fDetails, lUser, fRSAKey, Token);

   // Release allocated memory ...
   if (answer) delete[] answer;
   if (lUser) delete[] lUser;
   if (Token) delete[] Token;

   // Get and Analyse the reply
   fSocket->Recv(retval, kind);
   if (gDebug > 3)
      Info("SshAuth", "received from server: kind: %d, retval: %d", kind,
           retval);

   if (kind != kROOTD_AUTH) {
      return 0;
   } else {
      return retval;
   }
}

//______________________________________________________________________________
 const char *TAuthenticate::GetSshUser() const
{
   // Method returning the User to be used for the ssh login.
   // Looks first at SSH.Login and finally at env USER.
   // If SSH.LoginPrompt is set to 'yes' it prompts for the 'login name'

   static TString user = "";

   if (fgPromptUser) {
      user = PromptUser(fRemote);
   } else {
      user = fgDefaultUser;
      if (user == "")
         user = PromptUser(fRemote);
   }

   return user;
}

//______________________________________________________________________________
 Int_t TAuthenticate::GetAuthMeth(const char *Host, const char *Proto,
                                 char ***User, Int_t **NumMeth,
                                 Int_t **AuthMeth, char ***Details)
{
   // This method looks for the available methods (as chosen by the user)
   // for authentication vis-a-vis of host 'Host' and depending on protocol
   // Proto (either root - rootd, roots, rootk - or proof - proofd, proofs,
   // proofk - families).
   // Information is looked for in ~/.rootauthrc and in the .rootrc family
   // of files via Rootd.Authentication and Proofd.Authentication variables.
   // Return number of methods, their codes in AuthMeth and strings with
   // auth details in Details (login name, principals, etc ...).
   // Space for AuthMeth and Details must be allocated outside
   // Default method is SSH.

   Int_t i;

   if (gDebug > 2)
      ::Info("TAuthenticate::GetAuthMeth", "enter: h:%s p:%s u:%s (0x%lx 0x%lx) ",
              Host, Proto, *User[0], (Long_t) (*User), (Long_t) (*User[0]));

   if (*User[0] == 0)
      *User[0] = StrDup("");

   // Check then .rootauthrc (if there)
   char temp[kMAXPATHLEN];
   Int_t *am[kMAXSEC], *nh, nu = 0, j = 0;
   char **det[kMAXSEC];
   if ((nu = CheckRootAuthrc(Host, User, &nh, am, det)) > 0) {
      if (gDebug > 3)
         ::Info("TAuthenticate::GetAuthMeth", "found %d users - nh: %d 0x%lx %s ", nu,
                nh[0], (Long_t) (*User[0]), *User[0]);
      *NumMeth = new int[nu];
      for (i = 0; i < kMAXSEC; i++) {
         AuthMeth[i] = new int[nu];
         Details[i] = new char *[nu];
         for (j = 0; j < nu; j++) {
            (*NumMeth)[j] = nh[j];
            Details[i][j] = 0;
            AuthMeth[i][j] = -1;
            if (i < nh[j]) {
               AuthMeth[i][j] = am[i][j];
               if (det[i][j] == 0 || strlen(det[i][j]) == 0) {
                  strcpy(temp, "");
                  // Set user
                  char *usr = StrDup((*User)[j]);
                  // Check env variables for more details, if any ...
                  Details[i][j] = GetDefaultDetails(am[i][j], 1, usr);
                  if (usr) delete[] usr;
               } else {
                  Details[i][j] = det[i][j];
               }
            }
         }
      }
      if (gDebug > 3) {
         ::Info("TAuthenticate::GetAuthMeth", "found %d users", nu);
         for (j = 0; j < nu; j++) {
            ::Info("TAuthenticate::GetAuthMeth", "returning %d ", nh[j]);
            for (i = 0; i < nh[j]; i++) {
               ::Info("TAuthenticate::GetAuthMeth", "method[%d]: %d - details[%d]: %s ",
                      i, AuthMeth[i][j], i, Details[i][j]);
            }
         }
      }
      return nu;
   }
   // Check globals in .rootrc family of files ...
   char auth[40] = { 0 };
   if (strstr(Proto, "proof") != 0) {
      sprintf(auth, "%s", gEnv->GetValue("Proofd.Authentication", "4"));
   } else if (strstr(Proto, "root") != 0) {
      sprintf(auth, "%s", gEnv->GetValue("Rootd.Authentication", "4"));
   }
   if (gDebug > 3)
      ::Info("TAuthenticate::GetAuthMeth",
             "Found method(s) '%s' from globals in .rootrc (User[0]=%s)",
              auth,(*User)[0]);
   nh = new int;
   nh[0] = 0;
   for (i = 0; i < kMAXSEC; i++) {
      am[i] = new int[1];
   }
   if (strlen(auth) > 0) {
      nh[0] =
          sscanf(auth, "%d %d %d %d %d %d", &am[0][0], &am[1][0],
                 &am[2][0], &am[3][0], &am[4][0], &am[5][0]);
   }
   if (nh[0] > 0) {
      nu = 1;
      *NumMeth = new int[1];
      *NumMeth[0] = nh[0];
      for (i = 0; i < kMAXSEC; i++) {
         AuthMeth[i] = new int[1];
         Details[i] = new char *[nh[0]];
         if (i < nh[0]) {
            AuthMeth[i][0] = am[i][0];
            strcpy(temp, "");
            Details[i][0] = GetDefaultDetails(am[i][0], 1, (*User)[0]);
         } else {
            AuthMeth[i][0] = -1;
            Details[i][0] = 0;
         }
      }
   }
   if (gDebug > 2) {
      ::Info("TAuthenticate::GetAuthMeth", "for user '%s' returning %d methods",
             (*User)[0], nh[0]);
      for (i = 0; i < nh[0]; i++) {
         ::Info("TAuthenticate::GetAuthMeth", "   method[%d]: %d - details[%d]: %s ", i,
                AuthMeth[i][0], i, Details[i][0]);
      }
   }
   return nu;
}

//______________________________________________________________________________
 Int_t TAuthenticate::CheckRootAuthrc(const char *Host, char ***user,
                                     Int_t **nh, Int_t **am, char ***det)
{
   // Try to get info about authetication policies for Host

   int Nuser = 0, CheckUser = 0;
   int nmeth = 0, found = 0;
   Bool_t retval = kFALSE;
   char *net, *UserRq = 0;

   if (gSystem->Getenv("ROOTAUTHRC") != 0) {
      net = (char *) gSystem->Getenv("ROOTAUTHRC");
   } else {
      net = gSystem->ConcatFileName(gSystem->HomeDirectory(), ".rootauthrc");
   }
   if (gDebug > 2)
      ::Info("TAuthenticate::CheckRootAuthrc", "enter: host:%s user:%s file:%s", Host,
             (*user)[0], net);

   // Check if file can be read ...
   if (gSystem->AccessPathName(net, kReadPermission)) {
      if (gDebug > 1)
         ::Info("TAuthenticate::CheckRootAuthrc",
                "file %s cannot be read (errno: %d)", net, errno);
      return 0;
   }
   // Variables for scan ...
   char line[kMAXPATHLEN], rest[kMAXPATHLEN];

   // Generate temporary file name and open it
   int expand = 1;
   TString filetmp = "rootauthrc";
   FILE *ftmp = gSystem->TempFileName(filetmp);

   if (gDebug > 2)
      ::Info("TAuthenticate::CheckRootAuthrc", "got tmp file: %s open at 0x%lx",
              filetmp.Data(), (Long_t)ftmp);
   if (ftmp == 0)
      expand = 0;  // Problems opening temporary file: ignore 'include' directives ...

   FILE *fd = 0;
   // If the temporary file is open, copy everything to the new file ...
   if (expand == 1) {

      TAuthenticate::FileExpand(net, ftmp);
      fd = ftmp;
      rewind(fd);

   } else {
      // Open file
      fd = fopen(net, "r");
      if (fd == 0) {
         if (gDebug > 2)
            ::Info("TAuthenticate::CheckRootAuthrc",
                   "file %s cannot be opened (errno: %d)",
                    net, errno);
         return 0;
      }
   }
   // If empty user you need first to count how many entries are to be read
   char host[kMAXPATHLEN], info[kMAXPATHLEN];
   if ((*user)[0] == 0 || strlen((*user)[0]) == 0) {
      char usrtmp[256];
      unsigned int tlen = kMAXPATHLEN;
      char *Temp = new char[tlen];
      Temp[0] = '0';
      while (fgets(line, sizeof(line), fd) != 0) {
         // Skip comment lines
         if (line[0] == '#')
            continue;
         if (!strncmp(line,"proofserv",9))
            continue;
         char *pstr = 0;
         char *pdef = strstr(line, "default");
         sscanf(line,"%s %s",host,info);
         if (CheckHost(Host, host) || (pdef != 0 && pdef == line)) {

            unsigned int hlen = strlen(Host);
            if (strstr(Temp, Host) == 0) {
               if ((strlen(Temp) + hlen + 2) > tlen) {
                  char *NewTemp = StrDup(Temp);
                  if (Temp) delete[] Temp;
                  tlen += kMAXPATHLEN;
                  Temp = new char[tlen];
                  strcpy(Temp, NewTemp);
                  if (NewTemp) delete[] NewTemp;
               }
               sprintf(Temp, "%s %s", Temp, Host);
               Nuser++;
            } else {
               pstr = strstr(line, "user");
               if (pstr != 0) {
                  sscanf(pstr + 4, "%s %s", usrtmp, rest);
                  if (strstr(Temp, usrtmp) == 0) {
                     if ((strlen(Temp) + strlen(usrtmp) + 2) > tlen) {
                        char *NewTemp = StrDup(Temp);
                        if (Temp) delete[] Temp;
                        tlen += kMAXPATHLEN;
                        Temp = new char[tlen];
                        strcpy(Temp, NewTemp);
                        if (NewTemp) delete[] NewTemp;
                     }
                     sprintf(Temp, "%s %s", Temp, usrtmp);
                     Nuser++;
                  }
               }
            }
         }
      }
      if (Temp) delete[] Temp;
      if (gDebug > 3)
         ::Info("TAuthenticate::CheckRootAuthrc",
                "found %d different entries for host %s", Nuser, Host);

      if (Nuser) {
         if ((*user)[0]) delete[] (*user)[0];
         (*user) = new char *[Nuser];
         *nh = new int[Nuser];
         int i;
         for (i = 0; i < kMAXSEC; i++) {
            am[i] = new int[Nuser];
            det[i] = new char *[Nuser];
         }
         UserRq = StrDup("-1");
      } else {
         UserRq = StrDup("none");
         if ((*user)[0]) delete[] (*user)[0];
         (*user)[0] = StrDup("-1");
      }
   } else {
      CheckUser = 1;
      UserRq = StrDup((*user)[0]);
      *nh = new int[1];
      int i;
      for (i = 0; i < kMAXSEC; i++) {
         am[i] = new int[1];
         det[i] = new char *[1];
      }
   }

   // If nothing found return ...
   if (!strncmp(UserRq,"none",4)) {
      fclose(fd);
      if (net) delete[] net;
      if (UserRq) delete[] UserRq;
      if (expand == 1)
         gSystem->Unlink(filetmp);
      return 0;
   } else
     // rewind the file and start scanning it ...
      rewind(fd);

   // Scan it ...
   char opt[20];
   int mth[6] = { 0 }, meth;
   int ju = 0, nu = 0;
   while (fgets(line, sizeof(line), fd) != 0) {
      int i;
      // Skip comment lines
      if (line[0] == '#')
         continue;

      // Get rid of end of line 'n', if there ...
      if (line[strlen(line) - 1] == 'n')
         line[strlen(line) - 1] = '0';

      // scan line
      int nw = sscanf(line, "%s %s %s", host, opt, rest);

      // no useful info provided for this host
      if (nw < 2)
         continue;

      // Notify
      if (gDebug > 3)
         ::Info("TAuthenticate::CheckRootAuthrc", "found line ... %s ", line);

      // The list of data servers for proof is analyzed elsewhere (TProof ...)
      if (!strcmp(host, "proofserv"))
         continue;

      if (strcmp(host, "default")) {
         if (!CheckHost(Host, host))
            continue;
      } else {
         // This is a default entry: ignore it if a host-specific entry was already
         // found, analyse it otherwise ...
         if (found == 1)
            continue;
      }

      // Make sure that 'rest' contains all the rest ...
      strcpy(rest, strstr(line, opt) + strlen(opt) + 1);

      // Is there a user specified?
      if (!strcmp(opt, "user")) {
         // Yes: check if already entered ...
         char *usr = new char[strlen(rest) + 5];
         sscanf(rest, "%s %s", usr, rest);
         if (gDebug > 3)
            ::Info("TAuthenticate::CheckRootAuthrc",
                   "found 'user': %s requested: "%s" (%d,%d) (rest:%s)",
                   usr, UserRq, CheckUser, nu, rest);

         if (CheckUser == 1) {
            if (strcmp(UserRq, usr))
               continue;
         }
         int newu = 1;
         if (nu > 0) {
            int j;
            for (j = 0; j < nu; j++) {
               if (!strcmp((*user)[j], usr)) {
                  ju = j;
                  newu = 0;
               }
            }
         }
         if (newu == 1) {
            if (CheckUser == 0) {
               ju = nu++;
            } else {
               ju = 0;
               nu = 1;
               if ((*user)[ju]) delete[] (*user)[ju];
            }
            (*user)[ju] = StrDup(usr);
            (*nh)[ju] = 0;
            for (i = 0; i < kMAXSEC; i++) {
               am[i][ju] = -1;
               det[i][ju] = 0;
            }
         }
         if (usr) delete[] usr;
         // Now reposition opt and rest ...
         sscanf(rest, "%s %s", opt, rest);
         strcpy(rest, strstr(line, opt) + strlen(opt) + 1);
      } else {
         // No: record an anonymous entry ...
         int newu = 1;
         if (nu > 0) {
            int j;
            for (j = 0; j < nu; j++) {
               if (!strcmp((*user)[j], "-1")) {
                  ju = j;
                  newu = 0;
               }
            }
         }
         if (newu == 1) {
            if (CheckUser == 0) {
               ju = nu++;
            } else {
               ju = 0;
               nu = 1;
               if ((*user)[ju]) delete[] (*user)[ju];
            }
            (*user)[ju] = StrDup("-1");
            (*nh)[ju] = 0;
            for (i = 0; i < kMAXSEC; i++) {
               am[i][ju] = -1;
               det[i][ju] = 0;
            }
         }
      }

      // get rid of opt keyword
      strcpy(rest, strstr(line, opt) + strlen(opt) + 1);
      if (!strcmp(opt, "list")) {
         if (gDebug > 3)
            ::Info("TAuthenticate::CheckRootAuthrc", "found 'list': rest:%s", rest);
         char cmth[kMAXSEC][20];
         int nw =
             sscanf(rest, "%s %s %s %s %s %s", cmth[0], cmth[1], cmth[2],
                    cmth[3], cmth[4], cmth[5]);
         nmeth = 0;
         for (i = 0; i < nw; i++) {
            int met = -1;
            if (strlen(cmth[i]) > 1) {
               // Method passed as string: translate it to number
               met = GetAuthMethodIdx(cmth[i]);
               if (met == -1 && gDebug > 2)
                  ::Info("TAuthenticate::CheckRootAuthrc",
                         "unrecognized method (%s): ", cmth[i]);
            } else {
               met = atoi(cmth[i]);
            }
            if (met >= 0 && met < kMAXSEC) {
               mth[nmeth] = met;
               nmeth++;
            } else if (gDebug > 2)
               ::Info("TAuthenticate::CheckRootAuthrc", "unrecognized method (%d): ",
                      met);
         }
         int *tmp_am = 0;
         char **tmp_det = 0;
         if ((*nh)[ju] > 0) {
            tmp_am = new int[(*nh)[ju]];
            tmp_det = new char *[(*nh)[ju]];
            for (i = 0; i < (*nh)[ju]; i++) {
               tmp_am[i] = am[i][ju];
               tmp_det[i] = StrDup(det[i][i]);
            }
         }
         int k, j = nmeth;
         for (i = 0; i < kMAXSEC; i++) {
            if (i < nmeth) {
               am[i][ju] = mth[i];
               for (k = 0; k < (*nh)[ju]; k++) {
                  if (tmp_am[k] == mth[i]) {
                     det[i][ju] = StrDup(tmp_det[k]);
                     if (tmp_det[k]) delete[] tmp_det[k];
                     tmp_det[k] = 0;
                  }
               }
            } else {
               k = 0;
               while (k < (*nh)[ju] && am[i][ju] == -1) {
                  if (tmp_det[k] != 0) {
                     j++;
                     am[i][ju] = mth[k];
                     det[i][ju] = StrDup(tmp_det[k]);
                     delete[] tmp_det[k];
                     tmp_det[k] = 0;
                  }
                  k++;
               }
            }
         }
         if (tmp_am) delete[] tmp_am;
         if (tmp_det) delete[] tmp_det;
         (*nh)[ju] = nmeth;
      } else {

         if (!strcmp(opt, "method")) {
            if (gDebug > 3)
               ::Info("TAuthenticate::CheckRootAuthrc", "found 'method': rest:%s", rest);

            //         nw= sscanf(rest,"%d %s",&meth,info);
            char cmeth[20];
            nw = sscanf(rest, "%s %s", cmeth, info);
            meth = -1;
            if (strlen(cmeth) > 1) {
               // Method passed as string: translate it to number
               meth = GetAuthMethodIdx(cmeth);
               if (meth == -1 && gDebug > 2)
                  ::Info("TAuthenticate::CheckRootAuthrc",
                         "unrecognized method (%s): ", cmeth);
            } else {
               meth = atoi(cmeth);
            }
            if (meth < 0 || meth > (kMAXSEC - 1)) {
               if (gDebug > 2)
                  ::Info("TAuthenticate::CheckRootAuthrc", "unrecognized method (%d): ",
                         meth);
               continue;
            }

            if (nw > 1) {
               char *pinfo = strstr(rest, info);
               strncpy(info, pinfo, strlen(rest));
            } else
               info[0] = '0';

            if (found == 0) {
               for (i = 0; i < kMAXSEC; i++) {
                  am[i][ju] = -1;
               }
            }
            int j = -1;
            for (i = 0; i < (*nh)[ju]; i++) {
               if (am[i][ju] == meth) {
                  j = i;
                  if (strlen(info) > 0)
                     det[i][ju] = StrDup(info);
               }
            }
            if (j == -1) {
               if ((*nh)[ju] < kMAXSEC) {
                  am[(*nh)[ju]][ju] = meth;
                  if (strlen(info) > 0)
                     det[(*nh)[ju]][ju] = StrDup(info);
                  ((*nh)[ju])++;
               } else {
                  char *ostr = new char[4 * kMAXSEC];
                  ostr[4 * kMAXSEC] = '0';
                  for (i = 0; i < kMAXSEC; i++) {
                     sprintf(ostr, "%s %d", ostr, am[i][ju]);
                  }
                  if (gDebug > 0)
                     ::Warning("TAuthenticate::CheckRootAuthrc",
                               "output am badly filled: %s", ostr);
                  if (ostr) delete[] ostr;
               }
            }
            if (gDebug > 3)
               ::Info("TAuthenticate::CheckRootAuthrc",
                      "method with info : %s has been recorded (ju:%d, nh:%d)",
                      info, ju, (*nh)[ju]);
         } else {               // Unknown option
            ::Warning("TAuthenticate::CheckRootAuthrc", "found unknown option: %s", opt);
            continue;
         }
      }
      // Found new entry matching: superseed previous result
      found = 1;
      retval = kTRUE;
   }

   if (CheckUser == 1 && nu == 1) {
      if (!strcmp((*user)[0], "-1")) {
         if ((*user)[0]) delete[] (*user)[0];
         (*user)[0] = StrDup(UserRq);
      }
   }

   if (gDebug > 3) {
      rewind(fd);
      ::Info("TAuthenticate::CheckRootAuthrc",
             "+----------- temporary file: %s -------------------------+",
             filetmp.Data());
      ::Info("TAuthenticate::CheckRootAuthrc", "+");
      while (fgets(line, sizeof(line), fd) != 0) {
         if (line[strlen(line) - 1] == 'n')
            line[strlen(line) - 1] = '0';
         ::Info("TAuthenticate::CheckRootAuthrc", "+ %s", line);
      }
      ::Info("TAuthenticate::CheckRootAuthrc", "+");
      ::Info("TAuthenticate::CheckRootAuthrc",
             "+---------------------------------------------------------------------+");
      ::Info("TAuthenticate::CheckRootAuthrc",
             "+----------- Valid info fetched for this call ------------------------+");
      ::Info("TAuthenticate::CheckRootAuthrc", "+");
      ::Info("TAuthenticate::CheckRootAuthrc", "+   Host: %s - Number of users found: %d",
             Host, nu);
      for (ju = 0; ju < nu; ju++) {
         ::Info("TAuthenticate::CheckRootAuthrc", "+");
         ::Info("TAuthenticate::CheckRootAuthrc",
                "+      Dumping user: %s ( %d methods found)", (*user)[ju],
                (*nh)[ju]);
         int i;
         for (i = 0; i < (*nh)[ju]; i++) {
            ::Info("TAuthenticate::CheckRootAuthrc", "+        %d: method: %d  det:'%s'",
                   i, am[i][ju], det[i][ju]);
         }
      }
      ::Info("TAuthenticate::CheckRootAuthrc", "+");
      ::Info("TAuthenticate::CheckRootAuthrc",
             "+---------------------------------------------------------------------+");
   }

   fclose(fd);
   if (net) delete[] net;
   if (UserRq) delete[] UserRq;
   if (expand == 1)
      gSystem->Unlink(filetmp);

   return nu;
}

//______________________________________________________________________________
 Bool_t TAuthenticate::CheckHost(const char *Host, const char *host)
{
   // Check if 'Host' matches 'host':
   // this means either equal or "containing" it, even with wild cards *
   // in the first field (in the case 'host' is a name, ie not IP address)
   // Returns kTRUE if the two matches.

   Bool_t retval = kTRUE;

   // Both strings should have been defined
   if (!Host || !host)
      return kFALSE;

   // 'host' == '*' indicates any 'Host' ...
   if (!strcmp(host,"*"))
      return kTRUE;

   // If 'host' contains at a letter or an hyphen it is assumed to be
   // a host name. Otherwise a name.
   // Check also for wild cards
   Bool_t name = kFALSE;
   TRegexp rename("[+a-zA-Z]");
   Int_t len;
   if (rename.Index(host,&len) != -1 || strstr(host,"-"))
      name = kTRUE;

   // Check also for wild cards
   Bool_t wild = kFALSE;
   if (strstr(host,"*"))
      wild = kTRUE;

   // Now build the regular expression for final checking
   TRegexp rehost(host,wild);

   // Host to check
   TString theHost(Host);
   if (!name) {
      TInetAddress addr = gSystem->GetHostByName(Host);
      theHost = addr.GetHostAddress();
      if (gDebug > 2)
         ::Info("TAuthenticate::CheckHost", "checking host IP: %s", theHost.Data());
   }

   // Check 'Host' against 'rehost'
   Ssiz_t pos = rehost.Index(theHost,&len);
   if (pos == -1)
      retval = kFALSE;

   // If IP and no wilds, it should match either
   // the beginning or the end of the string
   if (!wild) {
      if (pos > 0 && pos != (Ssiz_t)(theHost.Length()-strlen(host)))
         retval = kFALSE;
   }

   return retval;
}

//______________________________________________________________________________
 Int_t TAuthenticate::RfioAuth(TString &User)
{
   // UidGid client authentication code.
   // Returns 0 in case authentication failed
   //         1 in case of success
   //        <0 in case of system error

   if (gDebug > 2)
      Info("RfioAuth", "enter ... User %s", User.Data());

   // Get user info ... ...
   UserGroup_t *pw = gSystem->GetUserInfo(gSystem->GetEffectiveUid());
   if (pw) {

      // These are the details to be saved in case of success ...
      User = pw->fUser;
      fDetails = TString("pt:0 ru:0 us:") + User;

      // Check that we are not root ...
      if (strcmp(pw->fUser, "root")) {

         // Get group ID associated with the current process ...
         Int_t uid = pw->fUid;
         Int_t gid = pw->fGid;

         // Send request ....
         char *sstr = new char[40];
         sprintf(sstr, "%d %d", uid, gid);
         if (gDebug > 3)
            Info("RfioAuth", "sending ... %s", sstr);
         int ns = fSocket->Send(sstr, kROOTD_RFIO);
         if (gDebug > 3)
            Info("RfioAuth", "sent ... %d bytes (expected > %d)", ns,
                 strlen(sstr));

         // Get answer
         Int_t stat, kind;
         fSocket->Recv(stat, kind);
         if (gDebug > 3)
            Info("RfioAuth", "after kROOTD_RFIO: kind= %d, stat= %d", kind,
                 stat);

         // Query result ...
         if (kind == kROOTD_AUTH && stat >= 1) {
            // Authentication OK ...
            SaveAuthDetails(this, (Int_t) TAuthenticate::kRfio, -1, 0,
                            fDetails, pw->fUser, 0, 0);
            return 1;
         } else {
            TString Server = "sockd";
            if (fProtocol.Contains("root"))
               Server = "rootd";
            if (fProtocol.Contains("proof"))
               Server = "proofd";

            // Authentication failed
            if (stat == kErrConnectionRefused) {
               if (gDebug > 0)
                  Error("RfioAuth",
                     "%s@%s does not accept connections from %s%s",
                     Server.Data(),fRemote.Data(),
                     fUser.Data(),gSystem->HostName());
               return -2;
            } else if (stat == kErrNotAllowed) {
               if (gDebug > 0)
                  Error("RfioAuth",
                     "%s@%s does not accept %s authentication from %s@%s",
                     Server.Data(),fRemote.Data(),
                     TAuthenticate::fgAuthMeth[5].Data(),
                     fUser.Data(),gSystem->HostName());
            } else {
              if (gDebug > 0)
                 AuthError("RfioAuth", stat);
            }
            return 0;
         }
      } else {
         Warning("RfioAuth", "UidGid login as "root" not allowed");
         return -1;
      }
   }
   delete pw;
   return -1;
}

//______________________________________________________________________________
 Int_t TAuthenticate::ClearAuth(TString &User, TString &Passwd, Bool_t &PwHash)
{
   // UsrPwd client authentication code.
   // Returns 0 in case authentication failed
   //         1 in case of success

   if (gDebug > 2)
      Info("ClearAuth", "enter: User: %s (passwd hashed?: %d)", User.Data(),(Int_t)PwHash);

   Int_t ReUse    = fgAuthReUse;
   Int_t Prompt   = fgPromptUser;
   Int_t Crypt    = fgUsrPwdCrypt;
   Int_t NeedSalt = 1;
   if (PwHash)
     NeedSalt = 0;
   fDetails = TString(Form("pt:%d ru:%d cp:%d us:",
                           fgPromptUser, fgAuthReUse, fgUsrPwdCrypt)) + User;
   if (gDebug > 2)
      Info("ClearAuth", "ru:%d pt:%d cp:%d ns:%d",
           fgAuthReUse,fgPromptUser,fgUsrPwdCrypt,NeedSalt);
#ifdef R__WIN32
   Crypt = 0;
#endif


   Int_t stat, kind;

   if (fVersion > 1) {

      // New protocol

      Int_t Anon = 0;
      Int_t OffSet = -1;
      char *Salt = 0;
      char *PasHash = 0;

      // Create Options string
      char *Options = new char[strlen(User.Data()) + 40];
      int Opt = (ReUse * kAUTH_REUSE_MSK) + (Crypt * kAUTH_CRYPT_MSK) +
                (NeedSalt * kAUTH_SSALT_MSK);
      sprintf(Options, "%d %ld %s", Opt, (Long_t)strlen(User), User.Data());

      // Check established authentications
      kind = kROOTD_USER;
      stat = ReUse;
      Int_t rc = 0;
      if ((rc =
           AuthExists(this, (Int_t) TAuthenticate::kClear, fDetails,
                      Options, &kind, &stat)) == 1) {
         // A valid authentication exists: we are done ...
         if (Options) delete[] Options;
         if (gDebug > 3)
            Info("ClearAuth", "valid authentication exists: return 1");
         return 1;
      }
      if (Options) delete[] Options;
      if (rc == -2) {
         return rc;
      }
      if (stat == kErrNotAllowed && kind == kROOTD_ERR) {
         return 0;
      }

      if (kind == kROOTD_AUTH && stat == -1) {
         if (gDebug > 3)
            Info("ClearAuth", "anonymous user", kind, stat);
         Anon  = 1;
         Crypt = 0;
         ReUse = 0;
      }

      if (OffSet == -1 && Anon == 0 && Crypt == 1) {

         // Check that we got the right thing ..
         if (kind != kROOTD_RSAKEY) {
            // Check for errors
            if (kind == kROOTD_ERR) {
               AuthError("ClearAuth", stat);
            } else {
               Warning("ClearAuth",
                       "problems recvn RSA key flag: got message %d, flag: %d",
                       kind, stat);
            }
            return 0;
         }
         if (gDebug > 3)
            Info("ClearAuth", "get key request ...");

         // Save type of key
         fRSAKey = 1;

         // Send the key securely
         SendRSAPublicKey(fSocket);

         if (NeedSalt) {
            // Receive password salt
            if (SecureRecv(fSocket, 1, &Salt) == -1) {
               Warning("ClearAuth",
                       "problems secure-receiving salt - may result in corrupted salt");
               Warning("ClearAuth", "switch off reuse for this session");
               Crypt = 0;
            }
            if (gDebug > 2)
               Info("ClearAuth", "got salt: '%s'", Salt);
         } else {
            if (gDebug > 2)
               Info("ClearAuth", "Salt not required");
            fSocket->Recv(stat, kind);
            if (kind != kMESS_ANY || stat != 0) {
               Warning("ClearAuth",
                  "Potential problems: got msg type: %d value: %d (expecting: %d 0)",
                   kind,stat,(Int_t)kMESS_ANY);
            }
         }
      }
      // Now get the password either from prompt or from memory, if saved already
      if (Anon == 1) {

         if (fgPasswd.Contains("@")) {
            // Anonymous like login with user chosen passwd ...
            Passwd = fgPasswd;
         } else {
           // Anonymous like login with automatic passwd generation ...
           TString LocalUser;
           UserGroup_t *pw = gSystem->GetUserInfo();
           if (pw)
              LocalUser = StrDup(pw->fUser);
           delete pw;
           static TString LocalFQDN;
           if (LocalFQDN == "") {
              TInetAddress addr = gSystem->GetHostByName(gSystem->HostName());
              if (addr.IsValid()) {
                 LocalFQDN = addr.GetHostName();
                 if (LocalFQDN == "UnNamedHost")
                    LocalFQDN = addr.GetHostAddress();
              }
           }
           Passwd = Form("%s@%s", LocalUser.Data(), LocalFQDN.Data());
           if (gDebug > 2)
              Info("ClearAuth",
                   "automatically generated anonymous passwd: %s",
                   Passwd.Data());
           }

      } else {

         if (Prompt == 1 || PasHash == 0) {

            if (Passwd == "") {
               Passwd =
                 PromptPasswd(Form("%s@%s password: ",User.Data(),fRemote.Data()));
               if (Passwd == "") {
                  Error("ClearAuth", "password not set");
                  if (PasHash) delete[] PasHash;
                  if (Salt) delete[] Salt;
                  fSocket->Send("-1", kROOTD_PASS);  // Needs this for consistency
                  return 0;
               }
            }
            if (Crypt == 1) {
               // Get hash (only if not already hashed ...)
               //if (strncmp(Passwd,Salt,strlen(Salt))) {
               if (!PwHash) {
#ifndef R__WIN32
                  PasHash = StrDup(crypt(Passwd, Salt));
#endif
               } else {
                  PasHash = StrDup(Passwd);
               }
            }
         }

      }

      // Send it to server
      if (Anon == 0 && Crypt == 1) {

         // Store for later use
         fgPasswd = PasHash;
         fPasswd = PasHash;
         fgPwHash = kTRUE;
         fPwHash = kTRUE;
         fSRPPwd = kFALSE;
         fgSRPPwd = kFALSE;

         fSocket->Send("0", kROOTD_PASS);  // Needs this for consistency
         if (SecureSend(fSocket, 1, PasHash) == -1) {
            Warning("ClearAuth",
                    "problems secure-sending pass hash - may result in authentication failure");
         }
      } else {

         // Store for later use
         fgPasswd = Passwd;
         fPasswd = Passwd;
         fgPwHash = kFALSE;
         fPwHash = kFALSE;
         fSRPPwd = kFALSE;
         fgSRPPwd = kFALSE;

         // Standard technique: invert passwd
         if (Passwd != "") {
            for (int i = 0; i < Passwd.Length(); i++) {
               char inv = ~Passwd(i);
               Passwd.Replace(i, 1, inv);
            }
         }
         fSocket->Send(Passwd.Data(), kROOTD_PASS);
      }

      // Receive username used for login
      int nrec = fSocket->Recv(stat, kind);  // returns user
      if (gDebug > 3)
         Info("ClearAuth", "after kROOTD_PASS: kind= %d, stat= %d", kind,
              stat);

      // Check for errors
      if (kind == kROOTD_ERR) {
         if (gDebug > 0)
            AuthError("ClearAuth", stat);
         fgPasswd = "";
         return 0;
      }
      if (OffSet == -1) {

         if (kind != kROOTD_PASS || stat < 1)
            Warning("ClearAuth",
                    "problems recvn (user,offset) length (%d:%d bytes:%d)",
                    kind, stat, nrec);

         // Get user and offset
         char *answer = new char[stat + 1];
         nrec = fSocket->Recv(answer, stat + 1, kind);
         if (kind != kMESS_STRING)
            Warning("ClearAuth",
                    "username and offset not received (%d:%d)", kind,
                    nrec);

         // Parse answer
         char *lUser = new char[stat];
         sscanf(answer, "%s %d", lUser, &OffSet);
         if (gDebug > 3)
            Info("ClearAuth",
                 "received from server: user: %s, offset: %d (%s)", lUser,
                 OffSet, answer);

         // Return username
         User = lUser;

         char *Token = 0;
         if (ReUse == 1) {
            // Receive Token
            if (Crypt == 1) {
               if (SecureRecv(fSocket, 1, &Token) == -1) {
                  Warning("ClearAuth",
                          "problems secure-receiving token - may result in corrupted token");
               }
            } else {
               Int_t Tlen = 9;
               Token = new char[Tlen];
               fSocket->Recv(Token, Tlen, kind);
               if (kind != kMESS_STRING)
                  Warning("ClearAuth", "token not received (%d:%d)", kind,
                          nrec);
               // Invert Token
               for (int i = 0; i < (int) strlen(Token); i++) {
                  Token[i] = ~Token[i];
               }

            }
            if (gDebug > 3)
               Info("ClearAuth", "received from server: token: '%s' ",
                    Token);
         }
         // Create and save AuthDetails object
         SaveAuthDetails(this, (Int_t) TAuthenticate::kClear, OffSet,
                         ReUse, fDetails, lUser, fRSAKey, Token);

         // This from remote login
         fSocket->Recv(stat, kind);

         if (answer) delete[] answer;
         if (lUser) delete[] lUser;
      }
      // Release allocated memory ...
      if (Salt) delete[] Salt;
      if (PasHash) delete[] PasHash;


      if (kind == kROOTD_AUTH && stat >= 1) {
         if (stat == 2) {
            int newOffSet;
            // Receive new offset ...
            fSocket->Recv(newOffSet, kind);
            // ... and save it
            SetOffSet(fHostAuth, (Int_t) TAuthenticate::kClear, fDetails,
                      newOffSet);
         }
         return 1;
      } else {
         fgPasswd = "";
         if (kind == kROOTD_ERR)
            if (gDebug > 0)
               AuthError("ClearAuth", stat);
         return 0;
      }

   } else {

      // Old Protocol

      // Send username
      fSocket->Send(User.Data(), kROOTD_USER);

      // Get replay from server
      fSocket->Recv(stat, kind);
      if (kind == kROOTD_ERR) {
         TString Server = "sockd";
         if (fProtocol.Contains("root"))
            Server = "rootd";
         if (fProtocol.Contains("proof"))
            Server = "proofd";
         if (stat == kErrConnectionRefused) {
            if (gDebug > 0)
               Error("ClearAuth",
                  "%s@%s does not accept connections from %s@%s",
                  Server.Data(),fRemote.Data(),
                  fUser.Data(),gSystem->HostName());
            return -2;
         } else if (stat == kErrNotAllowed) {
            if (gDebug > 0)
               Error("ClearAuth",
                  "%s@%s does not accept %s authentication from %s@%s",
                  Server.Data(),fRemote.Data(),
                  TAuthenticate::fgAuthMeth[0].Data(),
                  fUser.Data(),gSystem->HostName());
         } else {
           if (gDebug > 0)
              AuthError("ClearAuth", stat);
         }
         return 0;
      }
      // Prepare Passwd to send
    badpass1:
      if (Passwd == "") {
         Passwd = PromptPasswd(
                  Form("%s@%s password: ",User.Data(),fRemote.Data()));
         if (Passwd == "")
            Error("ClearAuth", "password not set");
      }
      if (fUser == "anonymous" || fUser == "rootd") {
         if (!Passwd.Contains("@")) {
            Warning("ClearAuth",
                    "please use passwd of form: user@host.do.main");
            Passwd = "";
            goto badpass1;
         }
      }

      fgPasswd = Passwd;
      fPasswd = Passwd;

      // Invert passwd
      if (Passwd != "") {
         for (int i = 0; i < Passwd.Length(); i++) {
            char inv = ~Passwd(i);
            Passwd.Replace(i, 1, inv);
         }
      }
      // Send it over the net
      fSocket->Send(Passwd, kROOTD_PASS);

      // Get result of attempt
      fSocket->Recv(stat, kind);  // returns user
      if (gDebug > 3)
         Info("ClearAuth", "after kROOTD_PASS: kind= %d, stat= %d", kind,
              stat);

      if (kind == kROOTD_AUTH && stat == 1) {
         return 1;
      } else {
         if (kind == kROOTD_ERR)
            if (gDebug > 0)
               AuthError("ClearAuth", stat);
         return 0;
      }
   }
}

//______________________________________________________________________________
 Int_t TAuthenticate::GetOffSet(TAuthenticate *Auth, Int_t Method,
                               TString &Details, char **Token)
{
   // Check if already authenticated for Method with Details
   // Return OffSet in the affirmative case or -1.

   Int_t OffSet = -1;

   if (gDebug > 2)
      ::Info("TAuthenticate::GetOffSet", "analyzing: Method:%d, Details:%s", Method,
             Details.Data());

   THostAuth *HostAuth = Auth->GetHostAuth();
   int Nw = 0, i = 0;
   char Pt[5] = { 0 }, Ru[5] = {
   0}, *Wd[4] = {
   0};

   if (Method == TAuthenticate::kGlobus) {
      DecodeDetailsGlobus((char *) Details.Data(), Pt, Ru, &Wd[0], &Wd[1],
                          &Wd[2], &Wd[3]);
      Nw = 0;
      for (i = 0; i < 4; i++) {
         if (Wd[i] != 0 && strlen(Wd[i]) > 0)
            Nw++;
      }
   } else {
      DecodeDetails((char *) Details.Data(), Pt, Ru, &Wd[0]);
      Nw = 0;
      if (Wd[0] != 0 && strlen(Wd[0]) > 0)
         Nw++;
   }
   if (gDebug > 3)
      ::Info("TAuthenticate::GetOffSet", "found Nw: %d, Wd: %s %s %s %s", Nw, Wd[0],
             Wd[1], Wd[2], Wd[3]);
   if (Nw == 0) {
      if (gDebug > 3)
         ::Info("TAuthenticate::GetOffSet", "nothing to compare: return");
      return OffSet;
   }
   // Check we already authenticated
   TIter next(HostAuth->Established());
   TAuthDetails *ai;
   while ((ai = (TAuthDetails *) next())) {
      if (gDebug > 3)
         ::Info("TAuthenticate::GetOffSet", "found entry: met:%d det:%s off:%d",
                ai->GetMethod(), ai->GetDetails(), ai->GetOffSet());
      if (ai->GetMethod() == Method) {
         int match = 1;
         for (i = 0; i < Nw; i++) {
            if (strstr(ai->GetDetails(), Wd[i]) == 0)
               match = 0;
         }
         if (match == 1) {
            OffSet = ai->GetOffSet();
            //strcpy(*Token,ai->GetToken());
            if (OffSet > -1) {
               *Token = StrDup(ai->GetToken());
               Auth->SetRSAKey(ai->GetRSAKey());
            }
         }
      }
   }
   if (gDebug > 2)
      ::Info("TAuthenticate::GetOffSet", "returning: %d", OffSet);
   for (i = 0; i < Nw; i++) {
      if (Wd[i] != 0)
         delete[] Wd[i];
   }
   if (*Token == 0) {
      Auth->SetRSAKey(0);
   }
   return OffSet;
}

//______________________________________________________________________________
 void TAuthenticate::SetOffSet(THostAuth *HostAuth, Int_t Method,
                              TString &Details, Int_t OffSet)
{
   // Save new offset

   TIter next(HostAuth->Established());
   TAuthDetails *ai;
   while ((ai = (TAuthDetails *) next())) {
      if (ai->GetMethod() == Method) {
         if (strstr(ai->GetDetails(), Details) != 0)
            ai->SetOffSet(OffSet);
      }
   }
}

//______________________________________________________________________________
 char *TAuthenticate::GetRemoteLogin(THostAuth *HostAuth, Int_t Method,
                                    const char *Details)
{
   // Check if already authenticated for Method with Details
   // Return remote user login name in the affirmative case or 0
   // The string should be freed by the caller with 'delete'.

   char *rlogin = 0;

   int Nw = 0, i = 0;
   char Pt[5] = { 0 }, Ru[5] = {
   0}, *Wd[4] = {
   0};

   if (Method == TAuthenticate::kGlobus) {
      DecodeDetailsGlobus((char *) Details, Pt, Ru, &Wd[0], &Wd[1], &Wd[2],
                          &Wd[3]);
      Nw = 0;
      for (i = 0; i < 4; i++) {
         if (Wd[i] != 0 && strlen(Wd[i]) > 0)
            Nw++;
      }
   } else {
      DecodeDetails((char *) Details, Pt, Ru, &Wd[0]);
      Nw = 0;
      if (Wd[0] != 0 && strlen(Wd[0]) > 0)
         Nw++;
   }
   if (gDebug > 2)
      ::Info("TAuthenticate::GetRemoteLogin", "details:%s", Details);

   // Check we already authenticated
   TIter next(HostAuth->Established());
   TAuthDetails *ai;
   while ((ai = (TAuthDetails *) next())) {
      if (ai->GetMethod() == Method) {
         int match = 1;
         for (i = 0; i < Nw; i++) {
            if (strstr(ai->GetDetails(), Wd[i]) == 0)
               match = 0;
         }
         if (match == 1) {
            rlogin = StrDup(ai->GetLogin());
         }
      }
   }
   if (gDebug > 2)
      ::Info("TAuthenticate::GetRemoteLogin", "returning: %s", rlogin);

   for (i = 0; i < Nw; i++) {
      if (Wd[i] != 0)
         delete[] Wd[i];
   }
   return rlogin;
}

//______________________________________________________________________________
 void TAuthenticate::SaveAuthDetails(TAuthenticate *Auth, Int_t Method,
                                    Int_t OffSet, Int_t ReUse,
                                    TString &Details, const char *rlogin,
                                    Int_t key, const char *token)
{
   THostAuth *HostAuth = Auth->GetHostAuth();
   TSocket *Socket = Auth->GetSocket();
   const char *Protocol = Auth->GetProtocol();

   const char *remote = HostAuth->GetHost();
   int port = Socket->GetPort();
   int service = 1;
   if (strstr(Protocol, "proof") != 0)
      service = 2;

   // If no meaningful offset is passed, then check if a
   // similar entry already exist; if so, we do not need
   // to create duplicates ...
   if (OffSet == -1) {

      TIter next(HostAuth->Established());
      TAuthDetails *ai;
      while ((ai = (TAuthDetails *) next())) {
         if (ai->GetMethod() == Method) {
            if (strstr(ai->GetDetails(), Details) != 0) {
               if (ai->GetOffSet() == -1)
                  return;
            }
         }
      }
   }

   // Create AuthDetails object
   TAuthDetails *fAuthDetails =
       new TAuthDetails(Form("%s:%d:%d", remote, port, service),
                        Method, OffSet, ReUse, (char *) Details.Data(),
                        token, key, rlogin);
   // Add it to the list
   HostAuth->Established()->Add(fAuthDetails);

   return;
}

//______________________________________________________________________________
 void TAuthenticate::DecodeDetails(char *details, char *Pt, char *Ru, char **Us)
{
   // Parse details looking for user info

   if (gDebug > 2)
      ::Info("TAuthenticate::DecodeDetails", "analyzing ... %s", details);

   *Us = 0;

   if (Pt == 0 || Ru == 0) {
      ::Error("TAuthenticate::DecodeDetails",
              "memory for Pt and Ru must be allocated elsewhere (Pt:0x%lx, Ru:0x%lx)",
              (Long_t) Pt, (Long_t) Ru);
      return;
   }

   if (strlen(details) > 0) {
      int lDet = strlen(details) + 2;
      char *ptr, *Temp = new char[lDet];
      if ((ptr = strstr(details, "pt:")) != 0)
         sscanf(ptr + 3, "%s %s", Pt, Temp);
      if ((ptr = strstr(details, "ru:")) != 0)
         sscanf(ptr + 3, "%s %s", Ru, Temp);
      if ((ptr = strstr(details, "us:")) != 0) {
         *Us = new char[lDet];
         *Us[0] = '0';
         sscanf(ptr + 3, "%s %s", *Us, Temp);
      }
      if (gDebug > 3)
         ::Info("TAuthenticate::DecodeDetails", "Pt:%s, Ru:%s, Us:%s", Pt, Ru, *Us);
      if (Temp) delete[] Temp;
   }
}

//______________________________________________________________________________
 void TAuthenticate::DecodeDetailsGlobus(char *details, char *Pt, char *Ru,
                                        char **Cd, char **Cf, char **Kf,
                                        char **Ad)
{
   // Parse details looking for globus authentication info

   if (gDebug > 2)
      ::Info("TAuthenticate::DecodeDetailsGlobus", "analyzing ... %s", details);

   *Cd = 0, *Cf = 0, *Kf = 0, *Ad = 0;

   if (Pt == 0 || Ru == 0) {
      ::Error("TAuthenticate::DecodeDetailsGlobus",
              "memory for Pt and Ru must be allocated elsewhere (Pt:0x%lx, Ru:0x%lx)",
              (Long_t) Pt, (Long_t) Ru);
      return;
   }

   if (strlen(details) > 0) {
      int lDet = strlen(details) + 2;
      char *ptr, *Temp = new char[lDet];
      if ((ptr = strstr(details, "pt:")) != 0)
         sscanf(ptr + 3, "%s %s", Pt, Temp);
      if ((ptr = strstr(details, "ru:")) != 0)
         sscanf(ptr + 3, "%s %s", Ru, Temp);
      if ((ptr = strstr(details, "cd:")) != 0) {
         *Cd = new char[lDet];
         *Cd[0] = '0';
         sscanf(ptr, "%s %s", *Cd, Temp);
      }
      if ((ptr = strstr(details, "cf:")) != 0) {
         *Cf = new char[lDet];
         *Cf[0] = '0';
         sscanf(ptr, "%s %s", *Cf, Temp);
      }
      if ((ptr = strstr(details, "kf:")) != 0) {
         *Kf = new char[lDet];
         *Kf[0] = '0';
         sscanf(ptr, "%s %s", *Kf, Temp);
      }
      if ((ptr = strstr(details, "ad:")) != 0) {
         *Ad = new char[lDet];
         *Ad[0] = '0';
         sscanf(ptr, "%s %s", *Ad, Temp);
      }

      if (gDebug > 3)
         ::Info("TAuthenticate::DecodeDetailsGlobus", "Pt:%s, Ru:%s, %s, %s, %s, %s", Pt,
                Ru, *Cd, *Cf, *Kf, *Ad);

      if (Temp) delete[] Temp;
   }
}

//______________________________________________________________________________
 void TAuthenticate::SetHostAuth(const char *host, const char *user)
{
   // Sets fUser=user and search fgAuthInfo for the entry pertaining to
   // (host,user), setting fHostAuth accordingly.
   // If no entry is found fHostAuth is not changed

   if (gDebug > 2)
      Info("SetHostAuth", "enter ... %s ... %s", host, user);

   // Set fUser
   SetUser(user);

   // Check list of auth info for already loaded info about this host
   TIter next(GetAuthInfo());
   THostAuth *ai;
   while ((ai = (THostAuth *) next())) {
      if (gDebug > 3)
         ai->Print("Authenticate:SetHostAuth");
      if (!strcmp(host, ai->GetHost()) && !strcmp(user, ai->GetUser())) {
         fHostAuth = ai;
         break;
      }
   }
}

//______________________________________________________________________________
 THostAuth *TAuthenticate::GetHostAuth(const char *host, const char *user)
{
   // Sets fUser=user and search fgAuthInfo for the entry pertaining to
   // (host,user), setting fHostAuth accordingly.
   // If no entry is found fHostAuth is not changed

   if (gDebug > 2)
      ::Info("TAuthenticate::GetHostAuth", "enter ... %s ... %s", host, user);
   int ulen = strlen(user);
   THostAuth *rHA = 0;

   // Check and save the host FQDN ...
   TString lHost = host;
   TInetAddress addr = gSystem->GetHostByName(lHost);
   if (addr.IsValid()) {
      lHost = addr.GetHostName();
      if (lHost == "UnNamedHost")
         lHost = addr.GetHostAddress();
   }

   // Check list of auth info for already loaded info about this host
   TIter next(GetAuthInfo());
   THostAuth *ai;
   Bool_t NotFound = kTRUE;
   while ((ai = (THostAuth *) next())) {
      if (gDebug > 3)
         ai->Print("Authenticate:GetHostAuth");

      // Use default entry if existing and nothing more specific is found
      if (!strcmp(ai->GetHost(),"default") && NotFound)
         rHA = ai;

      // Check
      if (ulen > 0) {
         if (CheckHost(lHost,ai->GetHost()) && !strcmp(user, ai->GetUser())) {
            rHA = ai;
            NotFound = kFALSE;
         }
      } else {
         if (CheckHost(lHost,ai->GetHost())) {
            rHA = ai;
            NotFound = kFALSE;
         }
      }

      if (ulen > 0) {
         if (lHost == ai->GetHost() && !strcmp(user, ai->GetUser())) {
            rHA = ai;
            break;
         }
      } else {
         if (lHost == ai->GetHost()) {
            rHA = ai;
            break;
         }
      }
   }
   return rHA;
}

//______________________________________________________________________________
 void TAuthenticate::FileExpand(const char *fexp, FILE *ftmp)
{
   // Expands include directives found in fexp files
   // The expanded, temporary file, is pointed to by 'ftmp'
   // and should be already open. To be called recursively.

   FILE *fin;
   char line[kMAXPATHLEN];
   char cinc[20], fileinc[kMAXPATHLEN];

   if (gDebug > 2)
     ::Info("TAuthenticate::FileExpand", "enter ... '%s' ... 0x%lx", fexp, (Long_t)ftmp);

   fin = fopen(fexp, "r");
   if (fin == 0)
      return;

   while (fgets(line, sizeof(line), fin) != 0) {
      // Skip comment lines
      if (line[0] == '#')
         continue;
      if (line[strlen(line) - 1] == 'n')
         line[strlen(line) - 1] = '0';
      if (gDebug > 2)
         ::Info("TAuthenticate::FileExpand", "read line ... '%s'", line);
      int nw = sscanf(line, "%s %s", cinc, fileinc);
      if (nw < 2)
         continue;              // Not enough info in this line
      if (strcmp(cinc, "include") != 0) {
         // copy line in temporary file
         fprintf(ftmp, "%sn", line);
      } else {
         // open (expand) file in temporary file ...
         if (fileinc[0] == '~') {
            // needs to expand
            int flen =
                strlen(fileinc) + strlen(gSystem->Getenv("HOME")) + 10;
            char *ffull = new char[flen];
            sprintf(ffull, "%s/%s", gSystem->Getenv("HOME"), fileinc + 1);
            strcpy(fileinc, ffull);
         }
         // Check if file exist and can be read ... ignore if not ...
         if (!gSystem->AccessPathName(fileinc, kReadPermission)) {
            FileExpand(fileinc, ftmp);
         } else {
            ::Warning("TAuthenticate::FileExpand",
                      "file specified by 'include' cannot be open or read (%s)",
                      fileinc);
         }
      }
   }
   fclose(fin);
}

//______________________________________________________________________________
 char *TAuthenticate::GetDefaultDetails(int sec, int opt, const char *usr)
{
   // Determine default authentication details for method 'sec' and user 'usr'.
   // Checks .rootrc family files. Returned string must be deleted by the user.

   char temp[kMAXPATHLEN] = { 0 };
   const char copt[2][5] = { "no", "yes" };

   if (gDebug > 2)
      ::Info("TAuthenticate::GetDefaultDetails", "enter ... %d ...pt:%d ... '%s'", sec,
             opt, usr);

   if (opt < 0 || opt > 1)
      opt = 1;

   // UsrPwd
   if (sec == TAuthenticate::kClear) {
      if (strlen(usr) == 0 || !strcmp(usr,"-1"))
         usr = gEnv->GetValue("UsrPwd.Login", "");
      sprintf(temp, "pt:%s ru:%s cp:%s us:%s",
              gEnv->GetValue("UsrPwd.LoginPrompt", copt[opt]),
              gEnv->GetValue("UsrPwd.ReUse", "1"),
              gEnv->GetValue("UsrPwd.Crypt", "1"), usr);

      // SRP
   } else if (sec == TAuthenticate::kSRP) {
      if (strlen(usr) == 0 || !strcmp(usr,"-1"))
         usr = gEnv->GetValue("SRP.Login", "");
      sprintf(temp, "pt:%s ru:%s us:%s",
              gEnv->GetValue("SRP.LoginPrompt", copt[opt]),
              gEnv->GetValue("SRP.ReUse", "0"), usr);

      // Kerberos
   } else if (sec == TAuthenticate::kKrb5) {
      if (strlen(usr) == 0 || !strcmp(usr,"-1"))
         usr = gEnv->GetValue("Krb5.Login", "");
      sprintf(temp, "pt:%s ru:%s us:%s",
              gEnv->GetValue("Krb5.LoginPrompt", copt[opt]),
              gEnv->GetValue("Krb5.ReUse", "0"), usr);

      // Globus
   } else if (sec == TAuthenticate::kGlobus) {
      sprintf(temp, "pt:%s ru:%s %s",
              gEnv->GetValue("Globus.LoginPrompt", copt[opt]),
              gEnv->GetValue("Globus.ReUse", "1"),
              gEnv->GetValue("Globus.Login", ""));

      // SSH
   } else if (sec == TAuthenticate::kSSH) {
      if (strlen(usr) == 0 || !strcmp(usr,"-1"))
         usr = gEnv->GetValue("SSH.Login", "");
      sprintf(temp, "pt:%s ru:%s us:%s",
              gEnv->GetValue("SSH.LoginPrompt", copt[opt]),
              gEnv->GetValue("SSH.ReUse", "1"), usr);

      // Uid/Gid
   } else if (sec == TAuthenticate::kRfio) {
      if (strlen(usr) == 0 || !strcmp(usr,"-1"))
         usr = gEnv->GetValue("UidGid.Login", "");
      sprintf(temp, "pt:%s us:%s",
              gEnv->GetValue("UidGid.LoginPrompt", copt[opt]), usr);
   }
   if (gDebug > 2)
      ::Info("TAuthenticate::GetDefaultDetails", "returning ... %s", temp);

   return StrDup(temp);
}

//______________________________________________________________________________
 void TAuthenticate::RemoveHostAuth(THostAuth *ha)
{
   // Remove THostAuth instance from the list

   // Remove from the list ...
   GetAuthInfo()->Remove(ha);

   // ... destroy it
   delete ha;
}

//______________________________________________________________________________
 void TAuthenticate::ReadAuthRc(const char *host, const char *user)
{
   // Read methods for a given host (and user) from .rootauthrc

   if (gDebug > 2)
      ::Info("TAuthenticate::ReadAuthRc", "enter: host: '%s', user: '%s'", host, user);

   // Check and save the host FQDN ...
   TString fqdn;
   TInetAddress addr = gSystem->GetHostByName(host);
   if (addr.IsValid()) {
      fqdn = addr.GetHostName();
      if (fqdn == "UnNamedHost")
         fqdn = addr.GetHostAddress();
   }
   if (gDebug > 3)
      ::Info("TAuthenticate::ReadAuthRc",
             "number of HostAuth Instantiations in memory: %d",
             GetAuthInfo()->GetSize());

   // Determine applicable auth methods from client choices
   Int_t *nmeth, *security[kMAXSEC];
   char **details[kMAXSEC];
   char **usr = new char *[1];
   if (strlen(user) > 0)
      usr[0] = StrDup(user);
   else
      usr[0] = StrDup("");

   int nu =
       GetAuthMeth(fqdn.Data(), "rootd", &usr, &nmeth, security, details);
   if (gDebug > 3)
      ::Info("TAuthenticate::ReadAuthRc", "found %d users", nu);

   int ju = 0, i, j;
   for (ju = 0; ju < nu; ju++) {

      // Translate to Input for THostAuth
      int nm = nmeth[ju], am[kMAXSEC];
      char *det[kMAXSEC];
      for (i = 0; i < kMAXSEC; i++) {
         if (i < nm) {
            am[i] = security[i][ju];
            det[i] = StrDup(details[i][ju]);
         } else {
            am[i] = -1;
            det[i] = 0;
         }
      }
      if (gDebug > 3) {
         ::Info("TAuthenticate::ReadAuthRc", "got %d methods (ju: %d)", nm, ju);
         for (i = 0; i < nm; i++) {
            ::Info("TAuthenticate::ReadAuthRc", "got (%d,0) security:%d details:%s", i,
                   am[i], det[i]);
         }
      }
      // Check list of auth info for already loaded info about this (host,user)
      THostAuth *hostAuth = 0;
      TIter next(GetAuthInfo());
      THostAuth *ai;
      while ((ai = (THostAuth *) next())) {
         if (gDebug > 3)
            ai->Print();
         if (fqdn == ai->GetHost() && !strcmp(usr[ju], ai->GetUser())) {
            hostAuth = ai;
            break;
         }
      }

      if (hostAuth == 0) {
         // Create THostAuth object
         hostAuth = new THostAuth(fqdn, usr[ju], nm, am, det);
         // ... and add it to the list
         GetAuthInfo()->Add(hostAuth);
      } else {
         // Modify existing entry ...
         Bool_t *RemoveMethod = new Bool_t[hostAuth->NumMethods()];
         for (i = 0; i < hostAuth->NumMethods(); i++)
            RemoveMethod[i] = kTRUE;
         for (i = 0; i < nmeth[0]; i++) {
            int j, jm = -1;
            for (j = 0; j < hostAuth->NumMethods(); j++) {
               if (am[i] == hostAuth->GetMethods(j)) {
                  hostAuth->SetDetails(am[i], det[i]);
                  jm = j;
                  RemoveMethod[j] = kFALSE;
               }
            }
            if (jm == -1)
               hostAuth->AddMethod(am[i], det[i]);
         }
         for (i = 0; i < hostAuth->NumMethods(); i++)
            if (RemoveMethod[i])
               hostAuth->RemoveMethod(hostAuth->GetMethods(i));
      }
      if (gDebug > 3)
         hostAuth->Print();
      for (i = 0; i < nm; i++) {
         if (det[i] != 0)
            delete[] det[i];
      }
   }
   for (i = 0; i < kMAXSEC; i++) {
      if (security[i] != 0)
         delete[] security[i];
      if (details[i] != 0) {
         for (j = 0; j < nu; j++) {
            if (details[i][j] != 0)
               delete[] details[i][j];
         }
      }
   }
   for (i = 0; i < nu; i++) {
      if (usr[i]) delete[] usr[i];
   }
   if (nmeth) delete[] nmeth;
   if (usr) delete[] usr;
}

//______________________________________________________________________________
 void TAuthenticate::PrintHostAuth()
{
   // Print info abour existing HostAuth instantiations

   TIter next(GetAuthInfo());
   THostAuth *ai;
   while ((ai = (THostAuth *) next())) {
      ai->Print();
      ai->PrintEstablished();
   }
}

//______________________________________________________________________________
 Int_t TAuthenticate::AuthExists(TAuthenticate *Auth, Int_t Sec,
                                TString &Details, const char *Options,
                                Int_t *Message, Int_t *Rflag)
{
   // Check if we have a valid established sec context in memory
   // Retrieves relevant info and negotiates with server.
   // Options = "Opt,strlen(User),User.Data()"
   // Message = kROOTD_USER, ...

   THostAuth *HostAuth = Auth->GetHostAuth();
   TSocket *Socket = Auth->GetSocket();

   if (gDebug > 2)
      ::Info("TAuthenticate::AuthExists", "%d: enter: msg: %d options: '%s'", Sec,
             *Message, Options);


   // Check we already authenticated
   Int_t OffSet = -1;
   char *Token = 0;
   //   char   *eTkn = 0;
   Int_t ReUse = *Rflag;
   //   Int_t  Len   = 0;
   if (ReUse == 1) {

      // Get OffSet and token, if any ...
      OffSet = GetOffSet(Auth, Sec, Details, &Token);
      if (gDebug > 3)
         ::Info("TAuthenticate::AuthExists", "%d: offset in memory is: %d ('%s')", Sec,
                OffSet, Token);
   }
   // Prepare string to be sent to the server
   char *sstr = new char[strlen(Options) + 20];
   sprintf(sstr, "%d %d %s", gSystem->GetPid(), OffSet, Options);

   // Send Message
   Socket->Send(sstr, *Message);

   if (ReUse == 1 && OffSet > -1) {

      Int_t RSAKey = Auth->GetRSAKey();
      if (gDebug > 2)
         ::Info("TAuthenticate::AuthExists", "key type: %d", RSAKey);

      if (RSAKey > 0) {
         // Send Token encrypted
         if (SecureSend(Socket, 1, Token) == -1) {
            ::Warning("TAuthenticate::AuthExists",
                      "problems secure-sending Token - may trigger problems in proofing Id ");
         }
      } else {
         // Send Token inverted
         for (int i = 0; i < (int) strlen(Token); i++) {
            Token[i] = ~Token[i];
         }
         Socket->Send(Token, kMESS_STRING);
      }

   }
   // Release allocated memory
   if (Token) delete[] Token;
   if (sstr) delete[] sstr;

   Int_t stat, kind;
   Socket->Recv(stat, kind);
   if (gDebug > 3)
      ::Info("TAuthenticate::AuthExists", "%d: after msg %d: kind= %d, stat= %d", Sec,
             *Message, kind, stat);

   // Return flags
   *Message = kind;
   *Rflag = stat;

   if (kind == kROOTD_ERR) {
      TString Server = "sockd";
      if (strstr(Auth->GetProtocol(),"root"))
         Server = "rootd";
      if (strstr(Auth->GetProtocol(),"proof"))
         Server = "proofd";
      if (stat == kErrConnectionRefused) {
         ::Error("TAuthenticate::AuthExists",
                 "%s@%s does not accept connections from %s@%s",
                 Server.Data(),Auth->GetRemoteHost(),
                 Auth->GetUser(),gSystem->HostName());
         return -2;
      } else if (stat == kErrNotAllowed) {
         if (gDebug > 0)
            ::Info("TAuthenticate::AuthExists",
                   "%s@%s does not accept %s authentication from %s@%s",
                   Server.Data(),Auth->GetRemoteHost(),
                   TAuthenticate::fgAuthMeth[Sec].Data(),
                   Auth->GetUser(),gSystem->HostName());
      } else {
        if (gDebug > 0)
           AuthError("AuthExists", stat);
      }
      return 0;
   }

   if (kind == kROOTD_AUTH && stat >= 1) {
      if (stat == 2) {
         int newOffSet;
         // Receive new offset ...
         Socket->Recv(newOffSet, kind);
         // ... and save it
         SetOffSet(HostAuth, Sec, Details, newOffSet);
      }
      return 1;
   }
   return 0;
}

//______________________________________________________________________________
 Int_t TAuthenticate::GenRSAKeys()
{
   // Generate a valid pair of private/public RSA keys to protect for authentication
   // token exchange

   if (gDebug > 2)
      Info("GenRSAKeys", "enter");

   if (fgRSAInit == 1) {
      if (gDebug > 2)
         Info("GenRSAKeys", "Keys prviously generated - return");
   }

   // This is for dynamic loads ...
#ifdef ROOTLIBDIR
   TString lib = TString(ROOTLIBDIR) + "/libRsa";
#else
   TString lib = TString(gRootDir) + "/lib/libRsa";
#endif

   // This is the local RSA implementation
   if (!rsa_fun::fg_rsa_genprim) {
      char *p;
      if ((p = gSystem->DynamicPathName(lib, kTRUE))) {
         delete[]p;
         gSystem->Load(lib);
      }
   }

   // Init random machine
   Int_t seed = 1;
   if (!gSystem->AccessPathName("/dev/random", kReadPermission)) {
      if (gDebug > 2)
         Info("GenRSAKeys", "taking seed from /dev/random");
      char brnd[4];
      FILE *frnd = fopen("/dev/random","r");
      fread(brnd,1,4,frnd);
      seed = *((int *)brnd);
      fclose(frnd);
   } else {
      if (gDebug > 2)
         Info("GenRSAKeys", "/dev/random not available: using time()");
      seed = time(0);
   }
   srand(seed);

   // Sometimes some bunch is not decrypted correctly
   // That's why we make retries to make sure that encryption/decryption works as expected
   Bool_t NotOk = 1;
   rsa_NUMBER p1, p2, rsa_n, rsa_e, rsa_d;
   Int_t l_n = 0, l_e = 0, l_d = 0;
   char buf_n[rsa_STRLEN], buf_e[rsa_STRLEN], buf_d[rsa_STRLEN];
#if 0
   char buf[rsa_STRLEN];
#endif

   Int_t NAttempts = 0;
   Int_t thePrimeLen = 20;
   Int_t thePrimeExp = 40;   // Prime probability = 1-0.5^thePrimeExp
   while (NotOk && NAttempts < kMAXRSATRIES) {

      NAttempts++;
      if (gDebug > 2 && NAttempts > 1) {
         Info("GenRSAKeys", "retry no. %d",NAttempts);
         srand(rand());
      }

      // Valid pair of primes
      p1 = rsa_fun::fg_rsa_genprim(thePrimeLen, thePrimeExp);
      p2 = rsa_fun::fg_rsa_genprim(thePrimeLen+1, thePrimeExp);

      // Retry if equal
      Int_t NPrimes = 0;
      while (rsa_fun::fg_rsa_cmp(&p1, &p2) == 0 && NPrimes < kMAXRSATRIES) {
         NPrimes++;
         if (gDebug > 2)
            Info("GenRSAKeys", "equal primes: regenerate (%d times)",NPrimes);
         srand(rand());
         p1 = rsa_fun::fg_rsa_genprim(thePrimeLen, thePrimeExp);
         p2 = rsa_fun::fg_rsa_genprim(thePrimeLen+1, thePrimeExp);
      }
#if 0
      if (gDebug > 3) {
         rsa_fun::fg_rsa_num_sput(&p1, buf, rsa_STRLEN);
         Info("GenRSAKeys", "local: p1: '%s' ", buf);
         rsa_fun::fg_rsa_num_sput(&p2, buf, rsa_STRLEN);
         Info("GenRSAKeys", "local: p2: '%s' ", buf);
      }
#endif
      // Generate keys
      if (rsa_fun::fg_rsa_genrsa(p1, p2, &rsa_n, &rsa_e, &rsa_d)) {
         if (gDebug > 2 && NAttempts > 1)
            Info("GenRSAKeys"," genrsa: unable to generate keys (%d)",
                 NAttempts);
         continue;
      }

      // Get equivalent strings and determine their lengths
      rsa_fun::fg_rsa_num_sput(&rsa_n, buf_n, rsa_STRLEN);
      l_n = strlen(buf_n);
      rsa_fun::fg_rsa_num_sput(&rsa_e, buf_e, rsa_STRLEN);
      l_e = strlen(buf_e);
      rsa_fun::fg_rsa_num_sput(&rsa_d, buf_d, rsa_STRLEN);
      l_d = strlen(buf_d);

#if 0
      if (gDebug > 3) {
         Info("GenRSAKeys", "local: n: '%s' length: %d", buf_n, l_n);
         Info("GenRSAKeys", "local: e: '%s' length: %d", buf_e, l_e);
         Info("GenRSAKeys", "local: d: '%s' length: %d", buf_d, l_d);
      }
#endif
      if (rsa_fun::fg_rsa_cmp(&rsa_n, &rsa_e) <= 0)
         continue;
      if (rsa_fun::fg_rsa_cmp(&rsa_n, &rsa_d) <= 0)
         continue;

      // Now we try the keys
      char Test[2 * rsa_STRLEN] = "ThisIsTheStringTest01203456-+/";
      Int_t lTes = 31;
      char *Tdum = GetRandString(0, lTes - 1);
      strncpy(Test, Tdum, lTes);
      delete[]Tdum;
      char buf[2 * rsa_STRLEN];
      if (gDebug > 3)
         Info("GenRSAKeys", "local: test string: '%s' ", Test);

      // Private/Public
      strncpy(buf, Test, lTes);
      buf[lTes] = 0;

      // Try encryption with private key
      int lout = rsa_fun::fg_rsa_encode(buf, lTes, rsa_n, rsa_e);
      if (gDebug > 3)
         Info("GenRSAKeys",
              "local: length of crypted string: %d bytes", lout);

      // Try decryption with public key
      rsa_fun::fg_rsa_decode(buf, lout, rsa_n, rsa_d);
      buf[lTes] = 0;
      if (gDebug > 3)
         Info("GenRSAKeys", "local: after private/public : '%s' ", buf);

      if (strncmp(Test, buf, lTes))
         continue;

      // Public/Private
      strncpy(buf, Test, lTes);
      buf[lTes] = 0;

      // Try encryption with public key
      lout = rsa_fun::fg_rsa_encode(buf, lTes, rsa_n, rsa_d);
      if (gDebug > 3)
         Info("GenRSAKeys", "local: length of crypted string: %d bytes ",
              lout);

      // Try decryption with private key
      rsa_fun::fg_rsa_decode(buf, lout, rsa_n, rsa_e);
      buf[lTes] = 0;
      if (gDebug > 3)
         Info("GenRSAKeys", "local: after public/private : '%s' ", buf);

      if (strncmp(Test, buf, lTes))
         continue;

      NotOk = 0;
   }

   // Save Private key
   rsa_fun::fg_rsa_assign(&fgRSAPriKey.n, &rsa_n);
   rsa_fun::fg_rsa_assign(&fgRSAPriKey.e, &rsa_e);

   // Save Public key
   rsa_fun::fg_rsa_assign(&fgRSAPubKey.n, &rsa_n);
   rsa_fun::fg_rsa_assign(&fgRSAPubKey.e, &rsa_d);

#if 0
   if (gDebug > 2) {
      // Determine their lengths
      Info("GenRSAKeys", "local: generated keys are:");
      Info("GenRSAKeys", "local: n: '%s' length: %d", buf_n, l_n);
      Info("GenRSAKeys", "local: e: '%s' length: %d", buf_e, l_e);
      Info("GenRSAKeys", "local: d: '%s' length: %d", buf_d, l_d);
   }
#endif
   // Export form
   fgRSAPubExport.len = l_n + l_d + 4;
   fgRSAPubExport.keys = new char[fgRSAPubExport.len];

   fgRSAPubExport.keys[0] = '#';
   memcpy(fgRSAPubExport.keys + 1, buf_n, l_n);
   fgRSAPubExport.keys[l_n + 1] = '#';
   memcpy(fgRSAPubExport.keys + l_n + 2, buf_d, l_d);
   fgRSAPubExport.keys[l_n + l_d + 2] = '#';
   fgRSAPubExport.keys[l_n + l_d + 3] = 0;
#if 0
   if (gDebug > 2)
      Info("GenRSAKeys", "local: export pub: '%s'", fgRSAPubExport.keys);
#else
   if (gDebug > 2)
      Info("GenRSAKeys", "local: export pub length: %d bytes", fgRSAPubExport.len);
#endif

   // Set availability flag
   fgRSAInit = 1;

   return 0;
}

//______________________________________________________________________________
 char *TAuthenticate::GetRandString(Int_t Opt, Int_t Len)
{
   // Allocates and fills a 0 terminated buffer of length Len+1 with
   // Len random characters.
   // Returns pointer to the buffer (to be deleted by the caller)
   // Opt = 0      any non dangerous char
   //       1      letters and numbers  (upper and lower case)
   //       2      hex characters       (upper and lower case)

   int iimx[4][4] = { {0x0, 0xffffff08, 0xafffffff, 0x2ffffffe}, // Opt = 0
                      {0x0, 0x3ff0000, 0x7fffffe, 0x7fffffe},    // Opt = 1
                      {0x0, 0x3ff0000, 0x7e, 0x7e},              // Opt = 2
                      {0x0, 0x3ffc000, 0x7fffffe, 0x7fffffe}     // Opt = 3
                    };

   const char *cOpt[4] = { "Any", "LetNum", "Hex", "Crypt" };

   //  Default option 0
   if (Opt < 0 || Opt > 2) {
      Opt = 0;
      if (gDebug > 2)
         Info("GetRandString", "unknown option: %d : assume 0", Opt);
   }
   if (gDebug > 2)
      Info("GetRandString", "enter ... Len: %d %s", Len, cOpt[Opt]);

   // Allocate buffer
   char *Buf = new char[Len + 1];

   // Get current time as seed for rand().
   time_t curtime;
   time(&curtime);
   int seed = (int) curtime;

   // feed seed
   if (seed)
      srand(seed);

   // randomize
   Int_t k = 0;
   Int_t i, j, l, m, frnd;
   while (k < Len) {
      frnd = rand();
      for (m = 7; m < 32; m += 7) {
         i = 0x7F & (frnd >> m);
         j = i / 32;
         l = i - j * 32;
         if ((iimx[Opt][j] & (1 << l))) {
            Buf[k] = i;
            k++;
         }
         if (k == Len)
            break;
      }
   }

   // null terminated
   Buf[Len] = 0;
   if (gDebug > 3)
      Info("GetRandString", "got '%s' ", Buf);

   return Buf;
}

//______________________________________________________________________________
 Int_t TAuthenticate::SecureSend(TSocket *Socket, Int_t Key, const char *Str)
{
   // Encode null terminated Str using the session private key indcated by Key
   // and sends it over the network
   // Returns number of bytes sent, or -1 in case of error.
   // Key = 1 for private encoding, Key = 2 for public encoding

   char BufTmp[kMAXSECBUF];
   char BufLen[20];

   if (gDebug > 2)
      ::Info("TAuthenticate::SecureSend", "local: enter ... (key: %d)", Key);

   Int_t sLen = strlen(Str) + 1;
   Int_t Ttmp = 0;
   Int_t Nsen = -1;

   if (Key == 1) {
      strncpy(BufTmp, Str, sLen);
      BufTmp[sLen] = 0;
      Ttmp =
          rsa_fun::fg_rsa_encode(BufTmp, sLen, fgRSAPriKey.n,
                                 fgRSAPriKey.e);
      sprintf(BufLen, "%d", Ttmp);
      Socket->Send(BufLen, kROOTD_ENCRYPT);
      Nsen = Socket->SendRaw(BufTmp, Ttmp);
      if (gDebug > 3)
         ::Info("TAuthenticate::SecureSend",
                "local: sent %d bytes (expected: %d)", Nsen,Ttmp);
   } else if (Key == 2) {
      strncpy(BufTmp, Str, sLen);
      BufTmp[sLen] = 0;
      Ttmp =
          rsa_fun::fg_rsa_encode(BufTmp, sLen, fgRSAPubKey.n,
                                 fgRSAPubKey.e);
      sprintf(BufLen, "%d", Ttmp);
      Socket->Send(BufLen, kROOTD_ENCRYPT);
      Nsen = Socket->SendRaw(BufTmp, Ttmp);
      if (gDebug > 3)
         ::Info("TAuthenticate::SecureSend",
                "local: sent %d bytes (expected: %d)", Nsen,Ttmp);
   } else {
      ::Info("TAuthenticate::SecureSend", "unknown key option (%d) - return", Key);
   }
   return Nsen;
}

//______________________________________________________________________________
 Int_t TAuthenticate::SecureRecv(TSocket *Socket, Int_t Key, char **Str)
{
   // Receive Len bytes from Socket and decode them in Str using key indicated by Key type
   // Return number of received bytes or -1 in case of error.
   // Key = 1 for private decoding, Key = 2 for public decoding

   char BufTmp[kMAXSECBUF];
   char BufLen[20];

   Int_t Nrec = -1;
   // We must get a pointer ...
   if (!Str)
      return Nrec;

   Int_t kind;
   Socket->Recv(BufLen, 20, kind);
   Int_t Len = atoi(BufLen);
   if (gDebug > 3)
      ::Info("TAuthenticate::SecureRecv", "got len '%s' %d (msg kind: %d)",
             BufLen, Len, kind);
   if (!strncmp(BufLen, "-1", 2))
      return Nrec;

   // Now proceed
   if (Key == 1) {
      Nrec = Socket->RecvRaw(BufTmp, Len);
      rsa_fun::fg_rsa_decode(BufTmp, Len, fgRSAPriKey.n, fgRSAPriKey.e);
      if (gDebug > 3)
         ::Info("TAuthenticate::SecureRecv", "local: decoded string is %d bytes long ", strlen(BufTmp));
   } else if (Key == 2) {
      Nrec = Socket->RecvRaw(BufTmp, Len);
      rsa_fun::fg_rsa_decode(BufTmp, Len, fgRSAPubKey.n, fgRSAPubKey.e);
      if (gDebug > 3)
         ::Info("TAuthenticate::SecureRecv", "local: decoded string is %d bytes long ", strlen(BufTmp));
   } else {
      ::Info("TAuthenticate::SecureRecv", "unknown key option (%d) - return", Key);
   }

   *Str = new char[strlen(BufTmp) + 1];
   strcpy(*Str, BufTmp);

   return Nrec;
}

//______________________________________________________________________________
 void TAuthenticate::DecodeRSAPublic(const char *RSAPubExport, rsa_NUMBER &RSA_n,
                                    rsa_NUMBER &RSA_d)
{
   // Store RSA public keys from export string RSAPubExport.

   if (!RSAPubExport)
      return;

   if (gDebug > 2)
      ::Info("TAuthenticate::DecodeRSAPublic","enter: string length: %d bytes", strlen(RSAPubExport));

   char Str[kMAXPATHLEN] = { 0 };
   strcpy(Str, RSAPubExport);

   if (strlen(Str) > 0) {
      // The format is #<hex_n>#<hex_d>#
      char *pd1 = strstr(Str, "#");
      char *pd2 = strstr(pd1 + 1, "#");
      char *pd3 = strstr(pd2 + 1, "#");
      if (pd1 && pd2 && pd3) {
         // Get <hex_n> ...
         int l1 = (int) (pd2 - pd1 - 1);
         char *RSA_n_exp = new char[l1 + 1];
         strncpy(RSA_n_exp, pd1 + 1, l1);
         RSA_n_exp[l1] = 0;
         if (gDebug > 2)
            ::Info("TAuthenticate::DecodeRSAPublic","got %d bytes for RSA_n_exp", strlen(RSA_n_exp));
         // Now <hex_d>
         int l2 = (int) (pd3 - pd2 - 1);
         char *RSA_d_exp = new char[l2 + 1];
         strncpy(RSA_d_exp, pd2 + 1, l2);
         RSA_d_exp[l2] = 0;
         if (gDebug > 2)
            ::Info("TAuthenticate::DecodeRSAPublic","got %d bytes for RSA_d_exp", strlen(RSA_d_exp));

         rsa_fun::fg_rsa_num_sget(&RSA_n, RSA_n_exp);
         rsa_fun::fg_rsa_num_sget(&RSA_d, RSA_d_exp);

         if (RSA_n_exp)
            if (RSA_n_exp) delete[] RSA_n_exp;
         if (RSA_d_exp)
            if (RSA_d_exp) delete[] RSA_d_exp;

      } else
         ::Info("TAuthenticate::DecodeRSAPublic","bad format for input string");
   }
}

//______________________________________________________________________________
 void TAuthenticate::SetRSAPublic(const char *RSAPubExport)
{
   // Store RSA public keys from export string RSAPubExport.

   if (gDebug > 2)
      ::Info("TAuthenticate::SetRSAPublic","enter: string length %d bytes", strlen(RSAPubExport));

   if (!RSAPubExport)
      return;

   // Decode input string
   rsa_NUMBER RSA_n, RSA_d;
   TAuthenticate::DecodeRSAPublic(RSAPubExport,RSA_n,RSA_d);

   // Save Public key
   rsa_fun::fg_rsa_assign(&fgRSAPubKey.n, &RSA_n);
   rsa_fun::fg_rsa_assign(&fgRSAPubKey.e, &RSA_d);
}

//______________________________________________________________________________
 void TAuthenticate::SendRSAPublicKey(TSocket *Socket)
{
   // Receives Server RSA Public key
   // Sends local RSA public key encodded

   // Receive server public key
   char ServerPubKey[kMAXSECBUF];
   int kind;
   Socket->Recv(ServerPubKey, kMAXSECBUF, kind);
   if (gDebug > 3)
      ::Info("TAuthenticate::SendRSAPublicKey", "received key from server %d bytes",
            strlen(ServerPubKey));

   // Decode it
   rsa_NUMBER RSA_n, RSA_d;
   TAuthenticate::DecodeRSAPublic(ServerPubKey,RSA_n,RSA_d);

   // Send local public key, encodes
   char BufTmp[kMAXSECBUF];
   Int_t sLen = fgRSAPubExport.len;
   strncpy(BufTmp,fgRSAPubExport.keys,sLen);
   BufTmp[sLen] = 0;
   Int_t Ttmp =
        rsa_fun::fg_rsa_encode(BufTmp, sLen, RSA_n, RSA_d);

   // Send length first
   char BufLen[20];
   sprintf(BufLen, "%d", Ttmp);
   Socket->Send(BufLen, kROOTD_ENCRYPT);
   // Send Key. second ...
   Int_t Nsen = Socket->SendRaw(BufTmp, Ttmp);
   if (gDebug > 3)
         ::Info("TAuthenticate::SendRSAPublicKey",
                "local: sent %d bytes (expected: %d)", Nsen,Ttmp);
}


ROOT page - Class index - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.