    // @(#)root/net:$Name:  $:$Id: TSecContext.cxx,v 1.8 2005/06/23 10:51:12 rdm Exp $
    // Author: G. Ganis   19/03/2003

    /*************************************************************************
     * 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.             *
     *************************************************************************/

    //////////////////////////////////////////////////////////////////////////
    //                                                                      //
    // TSecContext                                                          //
    //                                                                      //
    // Contains details about an established security context               //
    // Used by THostAuth                                                    //
    //                                                                      //
    //////////////////////////////////////////////////////////////////////////

    #ifdef HAVE_CONFIG
    #include "config.h"
    #endif

    #include <stdlib.h>

    #include "TSecContext.h"
    #include "TUrl.h"
    #include "TROOT.h"
    #include "TError.h"
    #include "TVirtualMutex.h"

    ClassImp(TSecContext)
    ClassImp(TSecContextCleanup)

    //______________________________________________________________________________
     TSecContext::TSecContext(const char *user, const char *host, Int_t meth,
                             Int_t offset, const char *details,
                             const char *token, TDatime expdate, void *ctx, Int_t key)
                : TObject()
    {
       // Ctor for SecContext object.
       Assert(gROOT);

       fContext = ctx;
       fCleanup = new TList;
       fDetails = details;
       fExpDate = expdate;
       if (offset > -1) {
          if (fExpDate < TDatime()) {
             // This means expdate was not initialized
             // We set it to default, ie 1 day from now
             fExpDate.Set(TDatime().GetDate() + 1, TDatime().GetTime());
          }
       }
       fHost    = host;
       fMethod  = meth;
       fOffSet  = offset;
       fRSAKey  = key;
       fToken   = token;
       fUser    = user;

       // Keep official list updated with active TSecContexts
       if (fOffSet > -1) {
          R__LOCKGUARD2(gROOTMutex);
          gROOT->GetListOfSecContexts()->Add(this);
       }
    }

    //______________________________________________________________________________
     TSecContext::TSecContext(const char *url, Int_t meth, Int_t offset,
                             const char *details, const char *token,
                             TDatime expdate, void *ctx, Int_t key)
                : TObject()
    {
       // Ctor for SecContext object.
       // User and host from url = user@host .
       Assert(gROOT);

       fContext = ctx;
       fCleanup = new TList;
       fDetails = details;
       fExpDate = expdate;
       if (offset > -1) {
          if (fExpDate < TDatime()) {
             // This means expdate was not initialized
             // We set it to default, ie 1 day from now
             fExpDate.Set(TDatime().GetDate() + 1, TDatime().GetTime());
          }
       }
       fHost    = TUrl(url).GetHost();
       fMethod  = meth;
       fOffSet  = offset;
       fRSAKey  = key;
       fToken   = token;
       fUser    = TUrl(url).GetUser();

       // Keep official list updated with active TSecContexts
       if (fOffSet > -1) {
          R__LOCKGUARD2(gROOTMutex);
          gROOT->GetListOfSecContexts()->Add(this);
       }
    }

    //______________________________________________________________________________
     TSecContext::~TSecContext()
    {
       // Dtor: DeActivate (local/remote cleanup, list removal),
       // if still Active

       if (IsActive())
          DeActivate();

       // Delete the cleanup list
       if (fCleanup) {
          fCleanup->Delete();
          delete fCleanup;
       }
    }

    //______________________________________________________________________________
     void TSecContext::AddForCleanup(Int_t port, Int_t proto, Int_t type)
    {
       // Create a new TSecContextCleanup
       // Internally is added to the list

       TSecContextCleanup *tscc = new TSecContextCleanup(port, proto, type);
       fCleanup->Add(tscc);

    }

    //______________________________________________________________________________
     void TSecContext::Cleanup()
    {
       // Ask remote cleanup of this context

       TAuthenticate::CleanupSecContext(this,kFALSE);
    }

    //______________________________________________________________________________
     void TSecContext::DeActivate(Option_t *Opt)
    {
       // Set OffSet to -1 and expiring Date to default
       // Remove from the list
       // If globus, cleanup local stuff
       // If Opt contains "C" or "c", ask for remote cleanup
       // If Opt contains "R" or "r", remove from the list
       // Default Opt="CR"

       // Ask remote cleanup of this context
       Bool_t clean = (strstr(Opt,"C") || strstr(Opt,"c"));
       if (clean && fOffSet > -1)
          Cleanup();

       // Cleanup TPwdCtx object fro UsrPwd and SRP
       if (fMethod == TAuthenticate::kClear ||
           fMethod == TAuthenticate::kSRP)
          if (fContext) {
             delete (TPwdCtx *)fContext;
             fContext = 0;
          }

       // Cleanup globus security context if needed
       if (fMethod == TAuthenticate::kGlobus && fContext) {
          GlobusAuth_t GlobusAuthHook = TAuthenticate::GetGlobusAuthHook();
          if (GlobusAuthHook != 0) {
             TString det("context");
             TString us("-1");
             (*GlobusAuthHook)((TAuthenticate *)fContext,us,det);
             fContext = 0;
          }
       }

       Bool_t remove = (strstr(Opt,"R") || strstr(Opt,"r"));
       if (remove && fOffSet > -1){
          R__LOCKGUARD2(gROOTMutex);
          // Remove from the global list
          gROOT->GetListOfSecContexts()->Remove(this);
          // Remove also from local lists in THostAuth objects
          TAuthenticate::RemoveSecContext(this);
       }

       // Set inactive
       fOffSet  = -1;
       fExpDate = kROOTTZERO;

    }

    //______________________________________________________________________________
     Bool_t TSecContext::IsA(const char *methname) const
    {
       // Checks if this security context is for method named 'methname'
       // Valid names: UsrPwd, SRP, Krb5, Globus, SSH, UidGid
       // (Case sensitive)
       // (see TAuthenticate.cxx for updated list)

       TString ThisMethod(TAuthenticate::GetAuthMethod(fMethod));
       return (ThisMethod == methname);
    }

    //______________________________________________________________________________
     Bool_t TSecContext::IsActive() const
    {
       // Check remote OffSet and expiring Date

       if (fOffSet > -1 && fExpDate > TDatime())
          return kTRUE;
       // Invalid
       return kFALSE;
    }

    //______________________________________________________________________________
     void TSecContext::Print(Option_t *opt) const
    {
       // If opt is "F" (default) print object content.
       // If opt is "<number>" print in special form for calls within THostAuth
       // with cardinality <number>
       // If opt is "S" prints short in-line form for calls within TFTP,
       // TSlave, TProof ...

       char Ord[10] = {0};
       char Spc[10] = {0};

       // Check if option is numeric
       Int_t ord = -1, i = 0;
       for (; i < (Int_t)strlen(opt); i++) {
          if (opt[i] < 48 || opt[i] > 57) {
             ord = -2;
             break;
          }
       }
       // If numeric get the cardinality and prepare the strings
       if (ord == -1)
          ord = atoi(opt);

       // If asked to print ordinal number, preapre the string
       if (ord > -1) {
          sprintf(Ord,"%d)",ord);
          // and take care of alignment
          Int_t len=strlen(Ord);
          while (len--)
             strcat(Spc," ");
       }

       if (!strncasecmp(opt,"F",1)) {
          Info("Print",
               "+------------------------------------------------------+");
          Info("Print",
               "+ Host:%s Method:%d (%s) User:'%s'",
                GetHost(),fMethod,TAuthenticate::GetAuthMethod(fMethod),
                fUser.Data());
          Info("Print",
               "+         OffSet:%d Details: '%s'",
                          fOffSet,fDetails.Data());
          if (fOffSet > -1)
             Info("Print",
               "+         Expiration time: %s",fExpDate.AsString());
          Info("Print",
               "+------------------------------------------------------+");
       } else if (!strncasecmp(opt,"S",1)) {
          if (fOffSet > -1) {
             if (fDetails.BeginsWith("AFS"))
                Printf("Security context:     Method: AFS, not reusable");
             else
                Printf("Security context:     Method: %d (%s) expiring on %s",
                       fMethod,TAuthenticate::GetAuthMethod(fMethod),
                       fExpDate.AsString());
          } else {
             Printf("Security context:     Method: %d (%s) not reusable",
                    fMethod,TAuthenticate::GetAuthMethod(fMethod));
          }
       } else {
          // special printing form for THostAuth
          Info("PrintEstblshed","+ %s h:%s met:%d (%s) us:'%s'",
                Ord, GetHost(), fMethod, TAuthenticate::GetAuthMethod(fMethod),
                fUser.Data());
          Info("PrintEstblshed","+ %s offset:%d det: '%s'",
                Spc,fOffSet,fDetails.Data());
          if (fOffSet > -1)
             Info("PrintEstblshed","+ %s expiring: %s",Spc,fExpDate.AsString());
       }
    }

    //______________________________________________________________________________
     const char *TSecContext::AsString(TString &out) const
    {
       // Returns short string with relevant information about this
       // security context

       if (fOffSet > -1) {
          if (fDetails.BeginsWith("AFS"))
             out = Form("Method: AFS, not reusable");
          else {
             char expdate[32];
             out = Form("Method: %d (%s) expiring on %s",
                        fMethod, TAuthenticate::GetAuthMethod(fMethod),
                        fExpDate.AsString(expdate));
          }
       } else {
          if (fOffSet == -1)
             out = Form("Method: %d (%s) not reusable",
                        fMethod, TAuthenticate::GetAuthMethod(fMethod));
          else if (fOffSet == -3)
             out = Form("Method: %d (%s) authorized by /etc/hosts.equiv or $HOME/.rhosts",
                        fMethod, TAuthenticate::GetAuthMethod(fMethod));
          else if (fOffSet == -4)
             out = Form("No authentication required remotely");
       }
       return out.Data();
    }