// @(#)root/auth:$Id$
// Author: G. Ganis   08/07/2005

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

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TRootSecContext                                                      //
//                                                                      //
// Special implementation of TSecContext                                //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "RConfigure.h"

#include <stdlib.h>

#include "TError.h"
#include "TRootSecContext.h"
#include "TROOT.h"
#include "TSocket.h"
#include "TUrl.h"
#include "TVirtualMutex.h"

ClassImp(TRootSecContext)

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

   fRSAKey  = key;
   fMethodName = TAuthenticate::GetAuthMethod(fMethod);
}

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

   fRSAKey  = key;
   fMethodName = TAuthenticate::GetAuthMethod(fMethod);
}

//______________________________________________________________________________
TRootSecContext::~TRootSecContext()
{
   // Dtor: delete (deActivate, local/remote cleanup, list removal)
   // all what is still active

   TSecContext::Cleanup();
}

//______________________________________________________________________________
void TRootSecContext::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)
      CleanupSecContext(kFALSE);

   // 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 TRootSecContext::CleanupSecContext(Bool_t all)
{
   // Ask remote client to cleanup security context 'ctx'
   // If 'all', all sec context with the same host as ctx
   // are cleaned.
   Bool_t cleaned = kFALSE;

   // Nothing to do if inactive ...
   if (!IsActive())
      return kTRUE;

   // Contact remote services that used this context,
   // starting from the last ...
   TIter last(fCleanup,kIterBackward);
   TSecContextCleanup *nscc = 0;
   while ((nscc = (TSecContextCleanup *)last()) && !cleaned) {

      // First check if remote daemon supports cleaning
      Int_t srvtyp = nscc->GetType();
      Int_t rproto = nscc->GetProtocol();
      Int_t level = 2;
      if ((srvtyp == TSocket::kROOTD && rproto < 10) ||
          (srvtyp == TSocket::kPROOFD && rproto < 9))
         level = 1;
      if ((srvtyp == TSocket::kROOTD && rproto < 8) ||
          (srvtyp == TSocket::kPROOFD && rproto < 7))
         level = 0;
      if (level) {
         Int_t port = nscc->GetPort();

         TSocket *news = new TSocket(fHost.Data(),port,-1);

         if (news && news->IsValid()) {
            if (srvtyp == TSocket::kPROOFD) {
               news->SetOption(kNoDelay, 1);
               news->Send("cleaning request");
            } else
               news->SetOption(kNoDelay, 0);

            // Backward compatibility: send socket size
            if (srvtyp == TSocket::kROOTD && level == 1)
               news->Send((Int_t)0, (Int_t)0);

            if (all || level == 1) {
               news->Send(Form("%d",TAuthenticate::fgProcessID), kROOTD_CLEANUP);
               cleaned = kTRUE;
            } else {
               news->Send(Form("%d %d %d %s", TAuthenticate::fgProcessID, fMethod,
                               fOffSet, fUser.Data()), kROOTD_CLEANUP);
               if (TAuthenticate::SecureSend(news, 1, fRSAKey,
                                             (char *)(fToken.Data())) == -1) {
                  Info("CleanupSecContext", "problems secure-sending token");
               } else {
                  cleaned = kTRUE;
               }
            }
            if (cleaned && gDebug > 2) {
               char srvname[3][10] = {"sockd", "rootd", "proofd"};
               Info("CleanupSecContext",
                    "remote %s notified for cleanup (%s,%d)",
                    srvname[srvtyp],fHost.Data(),port);
            }
         }
         SafeDelete(news);
      }
   }

   if (!cleaned)
      if (gDebug > 2)
         Info("CleanupSecContext",
              "unable to open valid socket for cleanup for %s", fHost.Data());

   return cleaned;
}

//______________________________________________________________________________
void TRootSecContext::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 ...

   // 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 (!strncasecmp(opt,"F",1)) {
      Info("Print",
           "+------------------------------------------------------+");
      Info("Print",
           "+ Host:%s Method:%d (%s) User:'%s'",
           GetHost(), fMethod, GetMethodName(),
           fUser.Data());
      Info("Print",
           "+         OffSet:%d Id: '%s'", fOffSet, fID.Data());
      if (fOffSet > -1)
         Info("Print",
              "+         Expiration time: %s",fExpDate.AsString());
      Info("Print",
           "+------------------------------------------------------+");
   } else if (!strncasecmp(opt,"S",1)) {
      if (fOffSet > -1) {
         if (fID.BeginsWith("AFS"))
            Printf("Security context:     Method: AFS, not reusable");
         else
            Printf("Security context:     Method: %d (%s) expiring on %s",
                   fMethod, GetMethodName(),
                   fExpDate.AsString());
      } else {
         Printf("Security context:     Method: %d (%s) not reusable",
                fMethod, GetMethodName());
      }
   } else {
      // special printing form for THostAuth
      Info("PrintEstblshed","+ %d \t h:%s met:%d (%s) us:'%s'",
                               ord, GetHost(), fMethod, GetMethodName(),
                               fUser.Data());
      Info("PrintEstblshed","+ \t offset:%d id: '%s'", fOffSet, fID.Data());
      if (fOffSet > -1)
         Info("PrintEstblshed","+ \t expiring: %s",fExpDate.AsString());
   }
}

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

   if (fOffSet > -1) {
      if (fID.BeginsWith("AFS"))
         out = Form("Method: AFS, not reusable");
      else {
         char expdate[32];
         out = Form("Method: %d (%s) expiring on %s",
                    fMethod, GetMethodName(), fExpDate.AsString(expdate));
      }
   } else {
      if (fOffSet == -1)
         out = Form("Method: %d (%s) not reusable", fMethod, GetMethodName());
      else if (fOffSet == -3)
         out = Form("Method: %d (%s) authorized by /etc/hosts.equiv or $HOME/.rhosts",
                    fMethod, GetMethodName());
      else if (fOffSet == -4)
         out = Form("No authentication required remotely");
   }
   return out.Data();
}
 TRootSecContext.cxx:1
 TRootSecContext.cxx:2
 TRootSecContext.cxx:3
 TRootSecContext.cxx:4
 TRootSecContext.cxx:5
 TRootSecContext.cxx:6
 TRootSecContext.cxx:7
 TRootSecContext.cxx:8
 TRootSecContext.cxx:9
 TRootSecContext.cxx:10
 TRootSecContext.cxx:11
 TRootSecContext.cxx:12
 TRootSecContext.cxx:13
 TRootSecContext.cxx:14
 TRootSecContext.cxx:15
 TRootSecContext.cxx:16
 TRootSecContext.cxx:17
 TRootSecContext.cxx:18
 TRootSecContext.cxx:19
 TRootSecContext.cxx:20
 TRootSecContext.cxx:21
 TRootSecContext.cxx:22
 TRootSecContext.cxx:23
 TRootSecContext.cxx:24
 TRootSecContext.cxx:25
 TRootSecContext.cxx:26
 TRootSecContext.cxx:27
 TRootSecContext.cxx:28
 TRootSecContext.cxx:29
 TRootSecContext.cxx:30
 TRootSecContext.cxx:31
 TRootSecContext.cxx:32
 TRootSecContext.cxx:33
 TRootSecContext.cxx:34
 TRootSecContext.cxx:35
 TRootSecContext.cxx:36
 TRootSecContext.cxx:37
 TRootSecContext.cxx:38
 TRootSecContext.cxx:39
 TRootSecContext.cxx:40
 TRootSecContext.cxx:41
 TRootSecContext.cxx:42
 TRootSecContext.cxx:43
 TRootSecContext.cxx:44
 TRootSecContext.cxx:45
 TRootSecContext.cxx:46
 TRootSecContext.cxx:47
 TRootSecContext.cxx:48
 TRootSecContext.cxx:49
 TRootSecContext.cxx:50
 TRootSecContext.cxx:51
 TRootSecContext.cxx:52
 TRootSecContext.cxx:53
 TRootSecContext.cxx:54
 TRootSecContext.cxx:55
 TRootSecContext.cxx:56
 TRootSecContext.cxx:57
 TRootSecContext.cxx:58
 TRootSecContext.cxx:59
 TRootSecContext.cxx:60
 TRootSecContext.cxx:61
 TRootSecContext.cxx:62
 TRootSecContext.cxx:63
 TRootSecContext.cxx:64
 TRootSecContext.cxx:65
 TRootSecContext.cxx:66
 TRootSecContext.cxx:67
 TRootSecContext.cxx:68
 TRootSecContext.cxx:69
 TRootSecContext.cxx:70
 TRootSecContext.cxx:71
 TRootSecContext.cxx:72
 TRootSecContext.cxx:73
 TRootSecContext.cxx:74
 TRootSecContext.cxx:75
 TRootSecContext.cxx:76
 TRootSecContext.cxx:77
 TRootSecContext.cxx:78
 TRootSecContext.cxx:79
 TRootSecContext.cxx:80
 TRootSecContext.cxx:81
 TRootSecContext.cxx:82
 TRootSecContext.cxx:83
 TRootSecContext.cxx:84
 TRootSecContext.cxx:85
 TRootSecContext.cxx:86
 TRootSecContext.cxx:87
 TRootSecContext.cxx:88
 TRootSecContext.cxx:89
 TRootSecContext.cxx:90
 TRootSecContext.cxx:91
 TRootSecContext.cxx:92
 TRootSecContext.cxx:93
 TRootSecContext.cxx:94
 TRootSecContext.cxx:95
 TRootSecContext.cxx:96
 TRootSecContext.cxx:97
 TRootSecContext.cxx:98
 TRootSecContext.cxx:99
 TRootSecContext.cxx:100
 TRootSecContext.cxx:101
 TRootSecContext.cxx:102
 TRootSecContext.cxx:103
 TRootSecContext.cxx:104
 TRootSecContext.cxx:105
 TRootSecContext.cxx:106
 TRootSecContext.cxx:107
 TRootSecContext.cxx:108
 TRootSecContext.cxx:109
 TRootSecContext.cxx:110
 TRootSecContext.cxx:111
 TRootSecContext.cxx:112
 TRootSecContext.cxx:113
 TRootSecContext.cxx:114
 TRootSecContext.cxx:115
 TRootSecContext.cxx:116
 TRootSecContext.cxx:117
 TRootSecContext.cxx:118
 TRootSecContext.cxx:119
 TRootSecContext.cxx:120
 TRootSecContext.cxx:121
 TRootSecContext.cxx:122
 TRootSecContext.cxx:123
 TRootSecContext.cxx:124
 TRootSecContext.cxx:125
 TRootSecContext.cxx:126
 TRootSecContext.cxx:127
 TRootSecContext.cxx:128
 TRootSecContext.cxx:129
 TRootSecContext.cxx:130
 TRootSecContext.cxx:131
 TRootSecContext.cxx:132
 TRootSecContext.cxx:133
 TRootSecContext.cxx:134
 TRootSecContext.cxx:135
 TRootSecContext.cxx:136
 TRootSecContext.cxx:137
 TRootSecContext.cxx:138
 TRootSecContext.cxx:139
 TRootSecContext.cxx:140
 TRootSecContext.cxx:141
 TRootSecContext.cxx:142
 TRootSecContext.cxx:143
 TRootSecContext.cxx:144
 TRootSecContext.cxx:145
 TRootSecContext.cxx:146
 TRootSecContext.cxx:147
 TRootSecContext.cxx:148
 TRootSecContext.cxx:149
 TRootSecContext.cxx:150
 TRootSecContext.cxx:151
 TRootSecContext.cxx:152
 TRootSecContext.cxx:153
 TRootSecContext.cxx:154
 TRootSecContext.cxx:155
 TRootSecContext.cxx:156
 TRootSecContext.cxx:157
 TRootSecContext.cxx:158
 TRootSecContext.cxx:159
 TRootSecContext.cxx:160
 TRootSecContext.cxx:161
 TRootSecContext.cxx:162
 TRootSecContext.cxx:163
 TRootSecContext.cxx:164
 TRootSecContext.cxx:165
 TRootSecContext.cxx:166
 TRootSecContext.cxx:167
 TRootSecContext.cxx:168
 TRootSecContext.cxx:169
 TRootSecContext.cxx:170
 TRootSecContext.cxx:171
 TRootSecContext.cxx:172
 TRootSecContext.cxx:173
 TRootSecContext.cxx:174
 TRootSecContext.cxx:175
 TRootSecContext.cxx:176
 TRootSecContext.cxx:177
 TRootSecContext.cxx:178
 TRootSecContext.cxx:179
 TRootSecContext.cxx:180
 TRootSecContext.cxx:181
 TRootSecContext.cxx:182
 TRootSecContext.cxx:183
 TRootSecContext.cxx:184
 TRootSecContext.cxx:185
 TRootSecContext.cxx:186
 TRootSecContext.cxx:187
 TRootSecContext.cxx:188
 TRootSecContext.cxx:189
 TRootSecContext.cxx:190
 TRootSecContext.cxx:191
 TRootSecContext.cxx:192
 TRootSecContext.cxx:193
 TRootSecContext.cxx:194
 TRootSecContext.cxx:195
 TRootSecContext.cxx:196
 TRootSecContext.cxx:197
 TRootSecContext.cxx:198
 TRootSecContext.cxx:199
 TRootSecContext.cxx:200
 TRootSecContext.cxx:201
 TRootSecContext.cxx:202
 TRootSecContext.cxx:203
 TRootSecContext.cxx:204
 TRootSecContext.cxx:205
 TRootSecContext.cxx:206
 TRootSecContext.cxx:207
 TRootSecContext.cxx:208
 TRootSecContext.cxx:209
 TRootSecContext.cxx:210
 TRootSecContext.cxx:211
 TRootSecContext.cxx:212
 TRootSecContext.cxx:213
 TRootSecContext.cxx:214
 TRootSecContext.cxx:215
 TRootSecContext.cxx:216
 TRootSecContext.cxx:217
 TRootSecContext.cxx:218
 TRootSecContext.cxx:219
 TRootSecContext.cxx:220
 TRootSecContext.cxx:221
 TRootSecContext.cxx:222
 TRootSecContext.cxx:223
 TRootSecContext.cxx:224
 TRootSecContext.cxx:225
 TRootSecContext.cxx:226
 TRootSecContext.cxx:227
 TRootSecContext.cxx:228
 TRootSecContext.cxx:229
 TRootSecContext.cxx:230
 TRootSecContext.cxx:231
 TRootSecContext.cxx:232
 TRootSecContext.cxx:233
 TRootSecContext.cxx:234
 TRootSecContext.cxx:235
 TRootSecContext.cxx:236
 TRootSecContext.cxx:237
 TRootSecContext.cxx:238
 TRootSecContext.cxx:239
 TRootSecContext.cxx:240
 TRootSecContext.cxx:241
 TRootSecContext.cxx:242
 TRootSecContext.cxx:243
 TRootSecContext.cxx:244
 TRootSecContext.cxx:245
 TRootSecContext.cxx:246
 TRootSecContext.cxx:247
 TRootSecContext.cxx:248
 TRootSecContext.cxx:249
 TRootSecContext.cxx:250
 TRootSecContext.cxx:251
 TRootSecContext.cxx:252
 TRootSecContext.cxx:253
 TRootSecContext.cxx:254
 TRootSecContext.cxx:255
 TRootSecContext.cxx:256
 TRootSecContext.cxx:257
 TRootSecContext.cxx:258
 TRootSecContext.cxx:259
 TRootSecContext.cxx:260
 TRootSecContext.cxx:261
 TRootSecContext.cxx:262
 TRootSecContext.cxx:263
 TRootSecContext.cxx:264
 TRootSecContext.cxx:265
 TRootSecContext.cxx:266
 TRootSecContext.cxx:267
 TRootSecContext.cxx:268
 TRootSecContext.cxx:269
 TRootSecContext.cxx:270
 TRootSecContext.cxx:271
 TRootSecContext.cxx:272
 TRootSecContext.cxx:273
 TRootSecContext.cxx:274
 TRootSecContext.cxx:275
 TRootSecContext.cxx:276
 TRootSecContext.cxx:277