Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TAuthenticate.cxx
Go to the documentation of this file.
1 // @(#)root/auth:$Id: f2cfa663e232707e1201467b5805ff1d13575326 $
2 // Author: Fons Rademakers 26/11/2000
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 //////////////////////////////////////////////////////////////////////////
13 // //
14 // TAuthenticate //
15 // //
16 // An authentication module for ROOT based network services, like rootd //
17 // and proofd. //
18 // //
19 //////////////////////////////////////////////////////////////////////////
20 
21 #include "RConfigure.h"
22 
23 #include "TAuthenticate.h"
24 #include "TApplication.h"
25 #include "THostAuth.h"
26 #include "TRootSecContext.h"
27 #include "TPluginManager.h"
28 #include "TNetFile.h"
29 #include "TPSocket.h"
30 #include "TMessage.h"
31 #include "TSystem.h"
32 #include "TError.h"
33 #include "Getline.h"
34 #include "TROOT.h"
35 #include "TEnv.h"
36 #include "TList.h"
37 #include "NetErrors.h"
38 #include "TRegexp.h"
39 #include "TVirtualMutex.h"
40 #include "TTimer.h"
41 #include "TBase64.h"
42 
43 #include "rsafun.h"
44 
45 #ifndef R__LYNXOS
46 #include <sys/stat.h>
47 #endif
48 #include <errno.h>
49 #include <sys/types.h>
50 #include <time.h>
51 #if !defined(R__WIN32) && !defined(R__MACOSX) && !defined(R__FBSD) && \
52  !defined(R__OBSD)
53 #include <crypt.h>
54 #endif
55 #ifdef WIN32
56 # include <io.h>
57 #endif /* WIN32 */
58 #if defined(R__LINUX) || defined(R__FBSD) || defined(R__OBSD)
59 # include <unistd.h>
60 #endif
61 #include <stdlib.h>
62 #ifndef WIN32
63 # include <sys/time.h>
64 #endif /* WIN32 */
65 
66 #if defined(R__MACOSX)
67 extern "C" char *crypt(const char *, const char *);
68 #endif
69 
70 #ifdef R__SSL
71 // SSL specific headers
72 # include <openssl/bio.h>
73 # include <openssl/err.h>
74 # include <openssl/pem.h>
75 # include <openssl/rand.h>
76 # include <openssl/rsa.h>
77 # include <openssl/ssl.h>
78 # include <openssl/blowfish.h>
79 #endif
80 
81 struct R__rsa_KEY: rsa_KEY { R__rsa_KEY(): rsa_KEY() {} };
82 struct R__rsa_KEY_export: rsa_KEY_export {};
83 struct R__rsa_NUMBER: rsa_NUMBER {};
84 
85 #ifdef R__SSL
86  static BF_KEY fgBFKey; // Blowfish symmetric key
87 #endif
88 
89 // Statics initialization
90 TList *TAuthenticate::fgAuthInfo = 0;
91 TString TAuthenticate::fgAuthMeth[] = { "UsrPwd", "Unsupported", "Unsupported",
92  "Unsupported", "Unsupported", "Unsupported" };
93 Bool_t TAuthenticate::fgAuthReUse;
94 TString TAuthenticate::fgDefaultUser;
95 TDatime TAuthenticate::fgExpDate;
96 TDatime TAuthenticate::fgLastAuthrc; // Time of last reading of fgRootAuthrc
97 TString TAuthenticate::fgPasswd;
98 TPluginHandler *TAuthenticate::fgPasswdDialog = (TPluginHandler *)(-1);
99 Bool_t TAuthenticate::fgPromptUser;
100 TList *TAuthenticate::fgProofAuthInfo = 0;
101 Bool_t TAuthenticate::fgPwHash;
102 Bool_t TAuthenticate::fgReadHomeAuthrc = kTRUE; // on/off search for $HOME/.rootauthrc
103 TString TAuthenticate::fgRootAuthrc; // Path to last rootauthrc-like file read
104 Int_t TAuthenticate::fgRSAKey = -1; // Default RSA key type to be used
105 Int_t TAuthenticate::fgRSAInit = 0;
106 R__rsa_KEY TAuthenticate::fgRSAPriKey;
107 R__rsa_KEY_export R__fgRSAPubExport[2] = {{}, {}};
108 R__rsa_KEY_export* TAuthenticate::fgRSAPubExport = R__fgRSAPubExport;
109 R__rsa_KEY TAuthenticate::fgRSAPubKey;
110 SecureAuth_t TAuthenticate::fgSecAuthHook;
111 TString TAuthenticate::fgUser;
112 Bool_t TAuthenticate::fgUsrPwdCrypt;
113 Int_t TAuthenticate::fgLastError = -1;
114 Int_t TAuthenticate::fgAuthTO = -2; // Timeout value
115 
116 // ID of the main thread as unique identifier
117 Int_t TAuthenticate::fgProcessID = -1;
118 
119 TVirtualMutex *gAuthenticateMutex = 0;
120 
121 // Standard version of Sec Context match checking
122 Int_t StdCheckSecCtx(const char *, TRootSecContext *);
123 
124 
125 ClassImp(TAuthenticate);
126 
127 ////////////////////////////////////////////////////////////////////////////////
128 /// rand() implementation using /udev/random or /dev/random, if available
129 
130 static int auth_rand()
131 {
132 #ifndef WIN32
133  int frnd = open("/dev/urandom", O_RDONLY);
134  if (frnd < 0) frnd = open("/dev/random", O_RDONLY);
135  int r;
136  if (frnd >= 0) {
137  ssize_t rs = read(frnd, (void *) &r, sizeof(int));
138  close(frnd);
139  if (r < 0) r = -r;
140  if (rs == sizeof(int)) return r;
141  }
142  Printf("+++ERROR+++ : auth_rand: neither /dev/urandom nor /dev/random are available or readable!");
143  struct timeval tv;
144  if (gettimeofday(&tv,0) == 0) {
145  int t1, t2;
146  memcpy((void *)&t1, (void *)&tv.tv_sec, sizeof(int));
147  memcpy((void *)&t2, (void *)&tv.tv_usec, sizeof(int));
148  r = t1 + t2;
149  if (r < 0) r = -r;
150  return r;
151  }
152  return -1;
153 #else
154  // No special random device available: use rand()
155  return rand();
156 #endif
157 }
158 
159 ////////////////////////////////////////////////////////////////////////////////
160 /// Create authentication object.
161 
162 TAuthenticate::TAuthenticate(TSocket *sock, const char *remote,
163  const char *proto, const char *user)
164 {
165  if (gDebug > 2 && gAuthenticateMutex)
166  Info("Authenticate", "locking mutex (pid: %d)",gSystem->GetPid());
167  R__LOCKGUARD2(gAuthenticateMutex);
168 
169  // In PROOF decode the buffer sent by the client, if any
170  if (gROOT->IsProofServ())
171  ProofAuthSetup();
172 
173  // Use the ID of the starting thread as unique identifier
174  if (fgProcessID < 0)
175  fgProcessID = gSystem->GetPid();
176 
177  if (fgAuthTO == -2)
178  fgAuthTO = gEnv->GetValue("Auth.Timeout",-1);
179 
180  fSocket = sock;
181  fRemote = remote;
182  fHostAuth = 0;
183  fVersion = 5; // The latest, by default
184  fSecContext = 0;
185 
186  if (gDebug > 2)
187  Info("TAuthenticate", "Enter: local host: %s, user is: %s (proto: %s)",
188  gSystem->HostName(), user, proto);
189 
190  // Set protocol string.
191  // Check if version should be different ...
192  char *pdd;
193  Int_t servtype = TSocket::kSOCKD;
194  if (proto && strlen(proto) > 0) {
195  char *sproto = StrDup(proto);
196  if ((pdd = strstr(sproto, ":")) != 0) {
197  int rproto = atoi(pdd + 1);
198  *pdd = '\0';
199  if (strstr(sproto, "root") != 0) {
200  if (rproto < 12 ) {
201  fVersion = 4;
202  if (rproto < 11 ) {
203  fVersion = 3;
204  if (rproto < 9 ) {
205  fVersion = 2;
206  if (rproto < 8) {
207  fVersion = 1;
208  if (rproto < 6)
209  fVersion = 0;
210  }
211  }
212  }
213  }
214  servtype = TSocket::kROOTD;
215  }
216  if (strstr(sproto, "proof") != 0) {
217  if (rproto < 11) {
218  fVersion = 4;
219  if (rproto < 10) {
220  fVersion = 3;
221  if (rproto < 8) {
222  fVersion = 2;
223  if (rproto < 7)
224  fVersion = 1;
225  }
226  }
227  }
228  servtype = TSocket::kPROOFD;
229  }
230  if (gDebug > 3)
231  Info("TAuthenticate",
232  "service: %s (remote protocol: %d): fVersion: %d", sproto,
233  rproto, fVersion);
234  }
235  fProtocol = sproto;
236  delete [] sproto;
237  }
238 
239  // Check or get user name
240  fUser = "";
241  TString checkUser;
242  if (user && strlen(user) > 0) {
243  fUser = user;
244  checkUser = user;
245  } else {
246  UserGroup_t *u = gSystem->GetUserInfo();
247  if (u)
248  checkUser = u->fUser;
249  delete u;
250  }
251  fPasswd = "";
252  fPwHash = kFALSE;
253 
254  // Type of RSA key
255  if (fgRSAKey < 0) {
256  fgRSAKey = 0; // Default key
257 #ifdef R__SSL
258  // Another choice possible: check user preferences
259  if (gEnv->GetValue("RSA.KeyType",0) == 1)
260  fgRSAKey = 1;
261 #endif
262  }
263  // This is the key actually used: we propose the default
264  // to the server, and behave according to its reply
265  fRSAKey = fgRSAKey;
266  if (gDebug > 3)
267  Info("TAuthenticate","RSA key: default type %d", fgRSAKey);
268 
269  // RSA key generation (one per session)
270  if (!fgRSAInit) {
271  GenRSAKeys();
272  fgRSAInit = 1;
273  }
274 
275  // Check and save the host FQDN ...
276  TString fqdn;
277  TInetAddress addr = gSystem->GetHostByName(fRemote);
278  if (addr.IsValid())
279  fqdn = addr.GetHostName();
280  TString fqdnsrv;
281  fqdnsrv.Form("%s:%d",fqdn.Data(),servtype);
282 
283  // Read directives from files; re-read if files have changed
284  TAuthenticate::ReadRootAuthrc();
285 
286  if (gDebug > 3) {
287  Info("TAuthenticate",
288  "number of HostAuth Instantiations in memory: %d",
289  GetAuthInfo()->GetSize());
290  TAuthenticate::Show("H");
291  TAuthenticate::Show("P");
292  }
293 
294  // Check the list of auth info for already loaded info about this host
295  fHostAuth = GetHostAuth(fqdnsrv, checkUser);
296 
297  //
298  // If generic THostAuth (i.e. with wild card or user == any)
299  // make a personalized memory copy of this THostAuth
300  if (strchr(fHostAuth->GetHost(),'*') || strchr(fHostAuth->GetHost(),'*') ||
301  fHostAuth->GetServer() == -1 ) {
302  fHostAuth = new THostAuth(*fHostAuth);
303  fHostAuth->SetHost(fqdn);
304  fHostAuth->SetUser(checkUser);
305  fHostAuth->SetServer(servtype);
306  }
307 
308  // If a specific method has been requested via the protocol
309  // set it as first
310  Int_t sec = -1;
311  TString tmp = fProtocol;
312  tmp.ReplaceAll("root",4,"",0);
313  tmp.ReplaceAll("proof",5,"",0);
314  tmp.ReplaceAll("sock",4,"",0);
315  if (!strncmp(tmp.Data(),"up",2))
316  sec = 0;
317  else if (!strncmp(tmp.Data(),"s",1))
318  sec = 1;
319  else if (!strncmp(tmp.Data(),"k",1))
320  sec = 2;
321  else if (!strncmp(tmp.Data(),"g",1))
322  sec = 3;
323  else if (!strncmp(tmp.Data(),"h",1))
324  sec = 4;
325  else if (!strncmp(tmp.Data(),"ug",2))
326  sec = 5;
327  if (sec > -1 && sec < kMAXSEC) {
328  if (fHostAuth->HasMethod(sec)) {
329  fHostAuth->SetFirst(sec);
330  } else {
331  char *dtmp = GetDefaultDetails(sec, 1, checkUser);
332  TString det(dtmp);
333  fHostAuth->AddFirst(sec, det);
334  if (dtmp)
335  delete [] dtmp;
336  }
337  }
338 
339  // This is what we have in memory
340  if (gDebug > 3) {
341  TIter next(fHostAuth->Established());
342  TRootSecContext *ctx;
343  while ((ctx = (TRootSecContext *) next()))
344  ctx->Print("0");
345  }
346 }
347 
348 ////////////////////////////////////////////////////////////////////////////////
349 /// Called in connection with a timer timeout
350 
351 void TAuthenticate::CatchTimeOut()
352 {
353  Info("CatchTimeOut", "%d sec timeout expired (protocol: %s)",
354  fgAuthTO, fgAuthMeth[fSecurity].Data());
355 
356  fTimeOut = 1;
357  if (fSocket)
358  fSocket->Close("force");
359 
360  return;
361 }
362 
363 ////////////////////////////////////////////////////////////////////////////////
364 /// Authenticate to remote rootd or proofd server. Return kTRUE if
365 /// authentication succeeded.
366 
367 Bool_t TAuthenticate::Authenticate()
368 {
369  if (gDebug > 2 && gAuthenticateMutex)
370  Info("Authenticate", "locking mutex (pid: %d)",gSystem->GetPid());
371  R__LOCKGUARD2(gAuthenticateMutex);
372 
373  Bool_t rc = kFALSE;
374  Int_t st = -1;
375  Int_t remMeth = 0, rMth[kMAXSEC], tMth[kMAXSEC] = {0};
376  Int_t meth = 0;
377  char noSupport[80] = { 0 };
378  char triedMeth[80] = { 0 };
379  Int_t ntry = 0;
380 
381  TString user, passwd;
382  Bool_t pwhash;
383 
384  if (gDebug > 2)
385  Info("Authenticate", "enter: fUser: %s", fUser.Data());
386 
387  //
388  // Setup timeout timer, if required
389  TTimer *alarm = 0;
390  if (fgAuthTO > 0) {
391  alarm = new TTimer(0, kFALSE);
392  alarm->SetInterruptSyscalls();
393  // The method CatchTimeOut will be called at timeout
394  alarm->Connect("Timeout()", "TAuthenticate", this, "CatchTimeOut()");
395  }
396 
397 negotia:
398  st = -1;
399  tMth[meth] = 1;
400  ntry++;
401  if (gDebug > 2)
402  Info("Authenticate", "try #: %d", ntry);
403 
404  user = "";
405  passwd = "";
406  pwhash = kFALSE;
407 
408  // Security level from the list (if not in cleanup mode ...)
409  fSecurity = (ESecurity) fHostAuth->GetMethod(meth);
410  fDetails = fHostAuth->GetDetails((Int_t) fSecurity);
411  if (gDebug > 2)
412  Info("Authenticate",
413  "trying authentication: method:%d, default details:%s",
414  fSecurity, fDetails.Data());
415 
416  // Keep track of tried methods in a list
417  if (triedMeth[0] != '\0')
418  (void) strlcat(triedMeth, " ", sizeof(triedMeth) - 1);
419 
420  (void) strlcat(triedMeth, fgAuthMeth[fSecurity].Data(), sizeof(triedMeth) - 1);
421 
422  // Set environments
423  SetEnvironment();
424 
425  st = -1;
426 
427  //
428  // Reset timeout variables and start timer
429  fTimeOut = 0;
430  if (fgAuthTO > 0 && alarm) {
431  alarm->Start(fgAuthTO*1000, kTRUE);
432  }
433 
434  // Auth calls depend of fSec
435  if (fSecurity == kClear) {
436 
437  rc = kFALSE;
438 
439  // UsrPwd Authentication
440  user = fgDefaultUser;
441  if (user != "")
442  CheckNetrc(user, passwd, pwhash, kFALSE);
443  if (passwd == "") {
444  if (fgPromptUser) {
445  char *u = PromptUser(fRemote);
446  user = u;
447  delete[] u;
448  }
449  rc = GetUserPasswd(user, passwd, pwhash, kFALSE);
450  }
451  fUser = user;
452  fPasswd = passwd;
453 
454  if (!rc) {
455 
456  if (fUser != "root")
457  st = ClearAuth(user, passwd, pwhash);
458  } else {
459  Error("Authenticate",
460  "unable to get user name for UsrPwd authentication");
461  }
462 
463  }
464 
465  // Stop timer
466  if (alarm) alarm->Stop();
467 
468  // Flag timeout condition
469  st = (fTimeOut > 0) ? -3 : st;
470 
471  //
472  // Analyse the result now ...
473  // Type of action after the analysis:
474  // 0 = return, 1 = negotiation, 2 = send kROOTD_BYE + 3,
475  // 3 = print failure and return
476  Int_t action = 0;
477  Int_t nmet = fHostAuth->NumMethods();
478  Int_t remloc = nmet - ntry;
479  if (gDebug > 0)
480  Info("Authenticate","remloc: %d, ntry: %d, meth: %d, fSecurity: %d",
481  remloc, ntry, meth, fSecurity);
482  Int_t kind, stat;
483  switch (st) {
484 
485  case 1:
486  //
487  // Success
488  fHostAuth->CountSuccess((Int_t)fSecurity);
489  if (gDebug > 2)
490  fSecContext->Print();
491  if (fSecContext->IsActive())
492  fSecContext->AddForCleanup(fSocket->GetPort(),
493  fSocket->GetRemoteProtocol(),fSocket->GetServType());
494  rc = kTRUE;
495  break;
496 
497  case 0:
498  //
499  // Failure
500  fHostAuth->CountFailure((Int_t)fSecurity);
501  if (fVersion < 2) {
502  //
503  // Negotiation not supported by old daemons ...
504  if (gDebug > 2)
505  Info("Authenticate",
506  "negotiation not supported remotely: try next method, if any");
507  if (meth < nmet - 1) {
508  meth++;
509  action = 1;
510  } else {
511  action = 2;
512  }
513  rc = kFALSE;
514  break;
515  }
516  //
517  // Attempt negotiation ...
518  if (fSocket->Recv(stat, kind) < 0) {
519  action = 0;
520  rc = kFALSE;
521  }
522  if (gDebug > 2)
523  Info("Authenticate",
524  "after failed attempt: kind= %d, stat= %d", kind, stat);
525  if (kind == kROOTD_ERR) {
526  action = 2;
527  rc = kFALSE;
528  } else if (kind == kROOTD_NEGOTIA) {
529  if (stat > 0) {
530  int len = 3 * stat;
531  char *answer = new char[len];
532  int nrec = fSocket->Recv(answer, len, kind); // returns user
533  if (nrec < 0) {
534  action = 0;
535  rc = kFALSE;
536  break;
537  }
538  if (kind != kMESS_STRING)
539  Warning("Authenticate",
540  "strings with accepted methods not received (%d:%d)",
541  kind, nrec);
542  remMeth =
543  sscanf(answer, "%d %d %d %d %d %d", &rMth[0], &rMth[1],
544  &rMth[2], &rMth[3], &rMth[4], &rMth[5]);
545  if (gDebug > 0 && remloc > 0)
546  Info("Authenticate",
547  "remotely allowed methods not yet tried: %s",
548  answer);
549  delete[] answer;
550  } else if (stat == 0) {
551  Info("Authenticate",
552  "no more methods accepted remotely to be tried");
553  action = 3;
554  rc = kFALSE;
555  break;
556  }
557  // If no more local methods, return
558  if (remloc < 1) {
559  action = 2;
560  rc = kFALSE;
561  break;
562  }
563  // Look if a non-tried method matches
564  int i, j;
565  std::string available{};
566  Bool_t methfound = kFALSE;
567  for (i = 0; i < remMeth; i++) {
568  for (j = 0; j < nmet; j++) {
569  if (fHostAuth->GetMethod(j) == rMth[i] && tMth[j] == 0) {
570  meth = j;
571  action = 1;
572  methfound = kTRUE;
573  break;
574  }
575  if (i == 0)
576  available += " " + std::to_string(fHostAuth->GetMethod(j));
577  }
578  if (methfound) break;
579  }
580  if (methfound) break;
581  //
582  // No method left to be tried: notify and exit
583  if (gDebug > 0)
584  Warning("Authenticate", "no match with those locally available: %s", available.c_str());
585  action = 2;
586  rc = kFALSE;
587  break;
588  } else { // unknown message code at this stage
589  action = 3;
590  rc = kFALSE;
591  break;
592  }
593  break;
594 
595  case -1:
596  //
597  // Method not supported
598  fHostAuth->CountFailure((Int_t)fSecurity);
599  if (gDebug > 2)
600  Info("Authenticate",
601  "method not even started: insufficient or wrong info: %s",
602  "try with next method, if any");
603  fHostAuth->RemoveMethod(fSecurity);
604  nmet--;
605  if (nmet > 0) {
606  action = 1;
607  } else
608  action = 2;
609 
610  break;
611 
612  case -2:
613  //
614  // Remote host does not accepts connections from local host
615  fHostAuth->CountFailure((Int_t)fSecurity);
616  if (fVersion <= 2)
617  if (gDebug > 2)
618  Warning("Authenticate",
619  "status code -2 not expected from old daemons");
620  rc = kFALSE;
621  break;
622 
623  case -3:
624  //
625  // Timeout: we set the method as last one, should the caller
626  // decide to retry, if it will attempt first something else.
627  // (We can not retry directly, because the server will not be
628  // synchronized ...)
629  fHostAuth->CountFailure((Int_t)fSecurity);
630  if (gDebug > 2)
631  Info("Authenticate", "got a timeout");
632  fHostAuth->SetLast(fSecurity);
633  if (meth < nmet - 1) {
634  fTimeOut = 2;
635  } else
636  fTimeOut = 1;
637  rc = kFALSE;
638  break;
639 
640  default:
641  fHostAuth->CountFailure((Int_t)fSecurity);
642  if (gDebug > 2)
643  Info("Authenticate", "unknown status code: %d - assume failure",st);
644  rc = kFALSE;
645  action = 0;
646  break;
647  }
648 
649  switch (action) {
650  case 1:
651  goto negotia;
652  // No break but we go away anyhow
653  case 2:
654  fSocket->Send("0", kROOTD_BYE);
655  // fallthrough
656  case 3:
657  if (strlen(noSupport) > 0)
658  Info("Authenticate", "attempted methods %s are not supported"
659  " by remote server version", noSupport);
660  Info("Authenticate",
661  "failure: list of attempted methods: %s", triedMeth);
662  AuthError("Authenticate",-1);
663  rc = kFALSE;
664  break;
665  default:
666  break;
667  }
668 
669  // Cleanup timer
670  SafeDelete(alarm);
671 
672  return rc;
673 
674 }
675 
676 ////////////////////////////////////////////////////////////////////////////////
677 /// Set default authentication environment. The values are inferred
678 /// from fSecurity and fDetails.
679 
680 void TAuthenticate::SetEnvironment()
681 {
682  R__LOCKGUARD2(gAuthenticateMutex);
683 
684  if (gDebug > 2)
685  Info("SetEnvironment",
686  "setting environment: fSecurity:%d, fDetails:%s", fSecurity,
687  fDetails.Data());
688 
689  // Defaults
690  fgDefaultUser = fgUser;
691  fgAuthReUse = kTRUE;
692  fgPromptUser = kFALSE;
693 
694  // Decode fDetails, is non empty ...
695  if (fDetails != "") {
696  char usdef[kMAXPATHLEN] = { 0 };
697  char pt[5] = { 0 }, ru[5] = { 0 };
698  Int_t hh = 0, mm = 0;
699  char us[kMAXPATHLEN] = {0}, cp[kMAXPATHLEN] = {0};
700  const char *ptr;
701 
702  TString usrPromptDef = TString(GetAuthMethod(fSecurity)) + ".LoginPrompt";
703  if ((ptr = strstr(fDetails, "pt:")) != 0) {
704  sscanf(ptr + 3, "%4s %8191s", pt, usdef);
705  } else {
706  if (!strncasecmp(gEnv->GetValue(usrPromptDef,""),"no",2) ||
707  !strncmp(gEnv->GetValue(usrPromptDef,""),"0",1))
708  strncpy(pt,"0",2);
709  else
710  strncpy(pt,"1",2);
711  }
712  TString usrReUseDef = TString(GetAuthMethod(fSecurity)) + ".ReUse";
713  if ((ptr = strstr(fDetails, "ru:")) != 0) {
714  sscanf(ptr + 3, "%4s %8191s", ru, usdef);
715  } else {
716  if (!strncasecmp(gEnv->GetValue(usrReUseDef,""),"no",2) ||
717  !strncmp(gEnv->GetValue(usrReUseDef,""),"0",1))
718  strncpy(ru,"0",2);
719  else
720  strncpy(ru,"1",2);
721  }
722  TString usrValidDef = TString(GetAuthMethod(fSecurity)) + ".Valid";
723  TString hours(gEnv->GetValue(usrValidDef,"24:00"));
724  Int_t pd = 0;
725  if ((pd = hours.Index(":")) > -1) {
726  TString minutes = hours;
727  hours.Resize(pd);
728  minutes.Replace(0,pd+1,"");
729  hh = atoi(hours.Data());
730  mm = atoi(minutes.Data());
731  } else {
732  hh = atoi(hours.Data());
733  mm = 0;
734  }
735 
736  // Now action depends on method ...
737  if (fSecurity == kClear) {
738  if ((ptr = strstr(fDetails, "us:")) != 0)
739  sscanf(ptr + 3, "%8191s %8191s", us, usdef);
740  if ((ptr = strstr(fDetails, "cp:")) != 0)
741  sscanf(ptr + 3, "%8191s %8191s", cp, usdef);
742  if (gDebug > 2)
743  Info("SetEnvironment", "details:%s, pt:%s, ru:%s, us:%s cp:%s",
744  fDetails.Data(), pt, ru, us, cp);
745  } else {
746  if ((ptr = strstr(fDetails, "us:")) != 0)
747  sscanf(ptr + 3, "%8191s %8191s", us, usdef);
748  if (gDebug > 2)
749  Info("SetEnvironment", "details:%s, pt:%s, ru:%s, us:%s",
750  fDetails.Data(), pt, ru, us);
751  }
752 
753  // Set Prompt flag
754  if (!strncasecmp(pt, "yes",3) || !strncmp(pt, "1", 1))
755  fgPromptUser = kTRUE;
756 
757  // Set ReUse flag
758  if (!gROOT->IsProofServ()) {
759  fgAuthReUse = kTRUE;
760  if (!strncasecmp(ru, "no",2) || !strncmp(ru, "0",1))
761  fgAuthReUse = kFALSE;
762  }
763 
764  // Set Expiring date
765  fgExpDate = TDatime();
766  fgExpDate.Set(fgExpDate.Convert() + hh*3600 + mm*60);
767 
768  // UnSet Crypt flag for UsrPwd, if requested
769  if (fSecurity == kClear) {
770  fgUsrPwdCrypt = kTRUE;
771  if (!strncmp(cp, "no", 2) || !strncmp(cp, "0", 1))
772  fgUsrPwdCrypt = kFALSE;
773  }
774  // Build UserDefaults
775  usdef[0] = '\0';
776  // give highest priority to command-line specification
777  if (fUser == "") {
778  if (strlen(us) > 0) snprintf(usdef, kMAXPATHLEN, "%s", us);
779  } else {
780  snprintf(usdef, kMAXPATHLEN, "%s", fUser.Data());
781  }
782 
783  if (strlen(usdef) > 0) {
784  fgDefaultUser = usdef;
785  } else {
786  if (fgUser != "") {
787  fgDefaultUser = fgUser;
788  } else {
789  UserGroup_t *u = gSystem->GetUserInfo();
790  if (u)
791  fgDefaultUser = u->fUser;
792  delete u;
793  }
794  }
795  if (fgDefaultUser == "anonymous" || fgDefaultUser == "rootd" ||
796  fgUser != "" || fUser != "") {
797  // when set by user don't prompt for it anymore
798  fgPromptUser = kFALSE;
799  }
800 
801  if (gDebug > 2)
802  Info("SetEnvironment", "usdef:%s", fgDefaultUser.Data());
803  }
804 }
805 
806 ////////////////////////////////////////////////////////////////////////////////
807 /// Try to get user name and passwd from several sources.
808 
809 Bool_t TAuthenticate::GetUserPasswd(TString &user, TString &passwd,
810  Bool_t &pwhash, Bool_t srppwd)
811 {
812  if (srppwd) {
813  Error("GetUserPasswd", "SRP no longer supported by ROOT");
814  return 1;
815  }
816 
817  if (gDebug > 3)
818  Info("GetUserPasswd", "Enter: User: '%s' Hash:%d SRP:%d",
819  user.Data(),(Int_t)pwhash,(Int_t)false);
820 
821  // Get user and passwd set via static functions SetUser and SetPasswd.
822  if (user == "" && fgUser != "")
823  user = fgUser;
824 
825  if (fgUser != "" && user == fgUser) {
826  if (passwd == "" && fgPasswd != "") {
827  passwd = fgPasswd;
828  pwhash = fgPwHash;
829  }
830  }
831 
832  if (gDebug > 3)
833  Info("GetUserPasswd", "In memory: User: '%s' Hash:%d",
834  user.Data(),(Int_t)pwhash);
835 
836  // Check system info for user if still not defined
837  if (user == "") {
838  UserGroup_t *u = gSystem->GetUserInfo();
839  if (u)
840  user = u->fUser;
841  delete u;
842  if (gDebug > 3)
843  Info("GetUserPasswd", "In memory: User: '%s' Hash:%d",
844  user.Data(),(Int_t)pwhash);
845  }
846 
847  // Check ~/.rootnetrc and ~/.netrc files if user was not set via
848  // the static SetUser() method.
849  if (user == "" || passwd == "") {
850  if (gDebug > 3)
851  Info("GetUserPasswd", "Checking .netrc family ...");
852  CheckNetrc(user, passwd, pwhash, /* srppwd */ false);
853  }
854  if (gDebug > 3)
855  Info("GetUserPasswd", "From .netrc family: User: '%s' Hash:%d",
856  user.Data(),(Int_t)pwhash);
857 
858  // If user also not set via ~/.rootnetrc or ~/.netrc ask user.
859  if (user == "") {
860  char *p = PromptUser(fRemote);
861  user = p;
862  delete [] p;
863  if (user == "") {
864  Error("GetUserPasswd", "user name not set");
865  return 1;
866  }
867  }
868 
869  return 0;
870 }
871 
872 ////////////////////////////////////////////////////////////////////////////////
873 /// Try to get user name and passwd from the ~/.rootnetrc or
874 /// ~/.netrc files. For more info see the version with 4 arguments.
875 /// This version is maintained for backward compatability reasons.
876 
877 Bool_t TAuthenticate::CheckNetrc(TString &user, TString &passwd)
878 {
879  Bool_t hash = false;
880  return CheckNetrc(user, passwd, hash, /* srppwd */ false);
881 }
882 
883 ////////////////////////////////////////////////////////////////////////////////
884 /// Try to get user name and passwd from the ~/.rootnetrc or
885 /// ~/.netrc files. First ~/.rootnetrc is tried, after that ~/.netrc.
886 /// These files will only be used when their access masks are 0600.
887 /// Returns kTRUE if user and passwd were found for the machine
888 /// specified in the URL. If kFALSE, user and passwd are "".
889 /// The boolean pwhash is set to kTRUE if the returned passwd is to
890 /// be understood as password hash, i.e. if the 'password-hash' keyword
891 /// is found in the 'machine' lines; not implemented for 'secure'
892 /// and the .netrc file.
893 /// The format of these files are:
894 ///
895 /// # this is a comment line
896 /// machine <machine fqdn> login <user> password <passwd>
897 /// machine <machine fqdn> login <user> password-hash <passwd>
898 ///
899 /// and in addition ~/.rootnetrc also supports:
900 ///
901 /// secure <machine fqdn> login <user> password <passwd>
902 ///
903 /// <machine fqdn> may be a domain name or contain the wild card '*'.
904 ///
905 /// for the secure protocols. All lines must start in the first column.
906 
907 Bool_t TAuthenticate::CheckNetrc(TString &user, TString &passwd,
908  Bool_t &pwhash, Bool_t srppwd)
909 {
910  if (srppwd) {
911  Error("CheckNetrc", "SRP no longer supported by ROOT");
912  return 1;
913  }
914 
915  Bool_t result = kFALSE;
916  Bool_t first = kTRUE;
917  TString remote = fRemote;
918 
919  passwd = "";
920  pwhash = kFALSE;
921 
922  char *net =
923  gSystem->ConcatFileName(gSystem->HomeDirectory(), ".rootnetrc");
924 
925  // Determine FQDN of the host ...
926  TInetAddress addr = gSystem->GetHostByName(fRemote);
927  if (addr.IsValid())
928  remote = addr.GetHostName();
929 
930 again:
931  // Only use file when its access rights are 0600
932  FileStat_t buf;
933  if (gSystem->GetPathInfo(net, buf) == 0) {
934 #ifdef WIN32
935  // Since Win32 does not have proper protections use file always
936  bool mode0600 = true;
937 #else
938  bool mode0600 = (buf.fMode & 0777) == (kS_IRUSR | kS_IWUSR);
939 #endif
940  if (R_ISREG(buf.fMode) && !R_ISDIR(buf.fMode) && mode0600) {
941  FILE *fd = fopen(net, "r");
942  char line[256];
943  while (fgets(line, sizeof(line), fd) != 0) {
944  if (line[0] == '#')
945  continue;
946  char word[6][64];
947  int nword = sscanf(line, "%63s %63s %63s %63s %63s %63s",
948  word[0], word[1], word[2], word[3], word[4], word[5]);
949  if (nword != 6)
950  continue;
951  if (strcmp(word[0], "machine"))
952  continue;
953  if (strcmp(word[2], "login"))
954  continue;
955  if (strcmp(word[4], "password") && strcmp(word[4], "password-hash"))
956  continue;
957 
958  // Treat the host name found in file as a regular expression
959  // with '*' as a wild card
960  TString href(word[1]);
961  href.ReplaceAll("*",".*");
962  TRegexp rg(href);
963  if (remote.Index(rg) != kNPOS) {
964  if (user == "") {
965  user = word[3];
966  passwd = word[5];
967  if (!strcmp(word[4], "password-hash"))
968  pwhash = kTRUE;
969  result = kTRUE;
970  break;
971  } else {
972  if (!strcmp(word[3], user.Data())) {
973  passwd = word[5];
974  if (!strcmp(word[4], "password-hash"))
975  pwhash = kTRUE;
976  result = kTRUE;
977  break;
978  }
979  }
980  }
981  }
982  fclose(fd);
983  } else
984  Warning("CheckNetrc",
985  "file %s exists but has not 0600 permission", net);
986  }
987  delete [] net;
988 
989  if (first && !result) {
990  net = gSystem->ConcatFileName(gSystem->HomeDirectory(), ".netrc");
991  first = kFALSE;
992  goto again;
993  }
994 
995  return result;
996  }
997 
998 ////////////////////////////////////////////////////////////////////////////////
999 /// Static method returning the global user.
1000 
1001 const char *TAuthenticate::GetGlobalUser()
1002 {
1003  return fgUser;
1004 }
1005 
1006 ////////////////////////////////////////////////////////////////////////////////
1007 /// Static method returning the global password hash flag.
1008 
1009 Bool_t TAuthenticate::GetGlobalPwHash()
1010 {
1011  return fgPwHash;
1012 }
1013 
1014 ////////////////////////////////////////////////////////////////////////////////
1015 /// Static method returning the global SRP password flag.
1016 
1017 Bool_t TAuthenticate::GetGlobalSRPPwd()
1018 {
1019  return false;
1020 }
1021 
1022 ////////////////////////////////////////////////////////////////////////////////
1023 /// Static method returning default expiring date for new validity contexts
1024 
1025 TDatime TAuthenticate::GetGlobalExpDate()
1026 {
1027  return fgExpDate;
1028 }
1029 
1030 ////////////////////////////////////////////////////////////////////////////////
1031 /// Static method returning the default user information.
1032 
1033 const char *TAuthenticate::GetDefaultUser()
1034 {
1035  return fgDefaultUser;
1036 }
1037 
1038 ////////////////////////////////////////////////////////////////////////////////
1039 /// Static method returning the principal to be used to init Krb5 tickets.
1040 
1041 const char *TAuthenticate::GetKrb5Principal()
1042 {
1043  ::Error("Krb5Auth", "Kerberos5 is no longer supported by ROOT");
1044  return nullptr;
1045 }
1046 
1047 ////////////////////////////////////////////////////////////////////////////////
1048 /// Static method returning the authentication reuse settings.
1049 
1050 Bool_t TAuthenticate::GetAuthReUse()
1051 {
1052  return fgAuthReUse;
1053 }
1054 
1055 ////////////////////////////////////////////////////////////////////////////////
1056 /// Static method returning the prompt user settings.
1057 
1058 Bool_t TAuthenticate::GetPromptUser()
1059 {
1060  return fgPromptUser;
1061 }
1062 
1063 ////////////////////////////////////////////////////////////////////////////////
1064 /// Static method returning the method corresponding to idx.
1065 
1066 const char *TAuthenticate::GetAuthMethod(Int_t idx)
1067 {
1068  R__LOCKGUARD2(gAuthenticateMutex);
1069 
1070  if (idx < 0 || idx > kMAXSEC-1) {
1071  ::Error("Authenticate::GetAuthMethod", "idx out of bounds (%d)", idx);
1072  idx = 0;
1073  }
1074  return fgAuthMeth[idx];
1075 }
1076 
1077 ////////////////////////////////////////////////////////////////////////////////
1078 /// Static method returning the method index (which can be used to find
1079 /// the method in GetAuthMethod()). Returns -1 in case meth is not found.
1080 
1081 Int_t TAuthenticate::GetAuthMethodIdx(const char *meth)
1082 {
1083  R__LOCKGUARD2(gAuthenticateMutex);
1084 
1085  if (meth && meth[0]) {
1086  for (Int_t i = 0; i < kMAXSEC; i++) {
1087  if (!fgAuthMeth[i].CompareTo(meth, TString::kIgnoreCase))
1088  return i;
1089  }
1090  }
1091 
1092  return -1;
1093 }
1094 
1095 ////////////////////////////////////////////////////////////////////////////////
1096 /// Static method to prompt for the user name to be used for authentication
1097 /// to rootd or proofd. User is asked to type user name.
1098 /// Returns user name (which must be deleted by caller) or 0.
1099 /// If non-interactive run (eg ProofServ) returns default user.
1100 
1101 char *TAuthenticate::PromptUser(const char *remote)
1102 {
1103  R__LOCKGUARD2(gAuthenticateMutex);
1104 
1105  const char *user;
1106  if (fgDefaultUser != "")
1107  user = fgDefaultUser;
1108  else
1109  user = gSystem->Getenv("USER");
1110 #ifdef R__WIN32
1111  if (!user)
1112  user = gSystem->Getenv("USERNAME");
1113 #endif
1114  if (isatty(0) == 0 || isatty(1) == 0) {
1115  ::Warning("TAuthenticate::PromptUser",
1116  "not tty: cannot prompt for user, returning default");
1117  if (strlen(user))
1118  return StrDup(user);
1119  else
1120  return StrDup("None");
1121  }
1122 
1123  const char *usrIn = Getline(Form("Name (%s:%s): ", remote, user));
1124  if (usrIn[0]) {
1125  TString usr(usrIn);
1126  usr.Remove(usr.Length() - 1); // get rid of \n
1127  if (!usr.IsNull())
1128  return StrDup(usr);
1129  else
1130  return StrDup(user);
1131  }
1132  return 0;
1133 }
1134 
1135 ////////////////////////////////////////////////////////////////////////////////
1136 /// Static method to prompt for the user's passwd to be used for
1137 /// authentication to rootd or proofd. Uses non-echoing command line
1138 /// to get passwd. Returns passwd (which must de deleted by caller) or 0.
1139 /// If non-interactive run (eg ProofServ) returns -1
1140 
1141 char *TAuthenticate::PromptPasswd(const char *prompt)
1142 {
1143  if (isatty(0) == 0 || isatty(1) == 0) {
1144  ::Warning("TAuthenticate::PromptPasswd",
1145  "not tty: cannot prompt for passwd, returning -1");
1146  static char noint[4] = {"-1"};
1147  return StrDup(noint);
1148  }
1149 
1150  char buf[128];
1151  const char *pw = buf;
1152  // Get the plugin for the passwd dialog box, if needed
1153  if (!gROOT->IsBatch() && (fgPasswdDialog == (TPluginHandler *)(-1)) &&
1154  gEnv->GetValue("Auth.UsePasswdDialogBox", 1) == 1) {
1155  if ((fgPasswdDialog =
1156  gROOT->GetPluginManager()->FindHandler("TGPasswdDialog"))) {
1157  if (fgPasswdDialog->LoadPlugin() == -1) {
1158  fgPasswdDialog = 0;
1159  ::Warning("TAuthenticate",
1160  "could not load plugin for the password dialog box");
1161  }
1162  }
1163  }
1164  if (fgPasswdDialog && (fgPasswdDialog != (TPluginHandler *)(-1))) {
1165 
1166  // Use graphic dialog
1167  fgPasswdDialog->ExecPlugin(3, prompt, buf, 128);
1168 
1169  // Wait until the user is done
1170  while (gROOT->IsInterrupted())
1171  gSystem->DispatchOneEvent(kFALSE);
1172 
1173  } else {
1174  Gl_config("noecho", 1);
1175  pw = Getline(prompt);
1176  Gl_config("noecho", 0);
1177  }
1178 
1179  // Final checks
1180  if (pw[0]) {
1181  TString spw(pw);
1182  if (spw.EndsWith("\n"))
1183  spw.Remove(spw.Length() - 1); // get rid of \n
1184  char *rpw = StrDup(spw);
1185  return rpw;
1186  }
1187  return 0;
1188 }
1189 
1190 ////////////////////////////////////////////////////////////////////////////////
1191 /// Static method returning the globus authorization hook (no longer supported)
1192 
1193 GlobusAuth_t TAuthenticate::GetGlobusAuthHook()
1194 {
1195  return nullptr;
1196 }
1197 
1198 ////////////////////////////////////////////////////////////////////////////////
1199 /// Static method returning the RSA public keys.
1200 
1201 const char *TAuthenticate::GetRSAPubExport(Int_t key)
1202 {
1203  key = (key >= 0 && key <= 1) ? key : 0;
1204  return fgRSAPubExport[key].keys;
1205 }
1206 
1207 ////////////////////////////////////////////////////////////////////////////////
1208 /// Static method returning the RSA initialization flag.
1209 
1210 Int_t TAuthenticate::GetRSAInit()
1211 {
1212  return fgRSAInit;
1213 }
1214 
1215 ////////////////////////////////////////////////////////////////////////////////
1216 /// Static method setting the default type of RSA key.
1217 
1218 void TAuthenticate::SetDefaultRSAKeyType(Int_t key)
1219 {
1220  if (key >= 0 && key <= 1)
1221  fgRSAKey = key;
1222 }
1223 
1224 ////////////////////////////////////////////////////////////////////////////////
1225 /// Static method setting RSA initialization flag.
1226 
1227 void TAuthenticate::SetRSAInit(Int_t init)
1228 {
1229  fgRSAInit = init;
1230 }
1231 
1232 ////////////////////////////////////////////////////////////////////////////////
1233 /// Static method returning the list with authentication details.
1234 
1235 TList *TAuthenticate::GetAuthInfo()
1236 {
1237  R__LOCKGUARD2(gAuthenticateMutex);
1238 
1239  if (!fgAuthInfo)
1240  fgAuthInfo = new TList;
1241  return fgAuthInfo;
1242 }
1243 
1244 ////////////////////////////////////////////////////////////////////////////////
1245 /// Static method returning the list with authentication directives
1246 /// to be sent to proof.
1247 
1248 TList *TAuthenticate::GetProofAuthInfo()
1249 {
1250  R__LOCKGUARD2(gAuthenticateMutex);
1251 
1252  if (!fgProofAuthInfo)
1253  fgProofAuthInfo = new TList;
1254  return fgProofAuthInfo;
1255 }
1256 
1257 ////////////////////////////////////////////////////////////////////////////////
1258 /// Print error string depending on error code.
1259 
1260 void TAuthenticate::AuthError(const char *where, Int_t err)
1261 {
1262  R__LOCKGUARD2(gAuthenticateMutex);
1263 
1264  // Make sure it is in range
1265  err = (err < kErrError) ? ((err > -1) ? err : -1) : kErrError;
1266 
1267  Int_t erc = err;
1268  Bool_t forceprint = kFALSE;
1269  TString lasterr = "";
1270  if (err == -1) {
1271  forceprint = kTRUE;
1272  erc = fgLastError;
1273  lasterr = "(last error only; re-run with gDebug > 0 for more details)";
1274  }
1275 
1276  if (erc > -1)
1277  if (gDebug > 0 || forceprint) {
1278  if (gRootdErrStr[erc])
1279  ::Error(Form("TAuthenticate::%s", where), "%s %s",
1280  gRootdErrStr[erc], lasterr.Data());
1281  else
1282  ::Error(Form("TAuthenticate::%s", where),
1283  "unknown error code: server must be running a newer ROOT version %s",
1284  lasterr.Data());
1285  }
1286 
1287  // Update last error code
1288  fgLastError = err;
1289 }
1290 
1291 ////////////////////////////////////////////////////////////////////////////////
1292 /// Set global user name to be used for authentication to rootd or proofd.
1293 
1294 void TAuthenticate::SetGlobalUser(const char *user)
1295 {
1296  R__LOCKGUARD2(gAuthenticateMutex);
1297 
1298  if (fgUser != "")
1299  fgUser = "";
1300 
1301  if (user && user[0])
1302  fgUser = user;
1303 }
1304 
1305 ////////////////////////////////////////////////////////////////////////////////
1306 /// Set global passwd to be used for authentication to rootd or proofd.
1307 
1308 void TAuthenticate::SetGlobalPasswd(const char *passwd)
1309 {
1310  R__LOCKGUARD2(gAuthenticateMutex);
1311 
1312  if (fgPasswd != "")
1313  fgPasswd = "";
1314 
1315  if (passwd && passwd[0])
1316  fgPasswd = passwd;
1317 }
1318 
1319 ////////////////////////////////////////////////////////////////////////////////
1320 /// Set global passwd hash flag to be used for authentication to rootd or proofd.
1321 
1322 void TAuthenticate::SetGlobalPwHash(Bool_t pwhash)
1323 {
1324  fgPwHash = pwhash;
1325 }
1326 
1327 ////////////////////////////////////////////////////////////////////////////////
1328 /// Set global SRP passwd flag to be used for authentication to rootd or proofd.
1329 
1330 void TAuthenticate::SetGlobalSRPPwd(Bool_t)
1331 {
1332  ::Error("SetGlobalSRPPwd", "SRP no longer supported by ROOT");
1333 }
1334 
1335 ////////////////////////////////////////////////////////////////////////////////
1336 /// Set flag controlling the reading of $HOME/.rootauthrc.
1337 /// In PROOF the administrator may want to switch off private settings.
1338 /// Always true, may only be set false via option to proofd.
1339 
1340 void TAuthenticate::SetReadHomeAuthrc(Bool_t readhomeauthrc)
1341 {
1342  fgReadHomeAuthrc = readhomeauthrc;
1343 }
1344 
1345 ////////////////////////////////////////////////////////////////////////////////
1346 /// Set default expiring date for new validity contexts
1347 
1348 void TAuthenticate::SetGlobalExpDate(TDatime expdate)
1349 {
1350  fgExpDate = expdate;
1351 }
1352 
1353 ////////////////////////////////////////////////////////////////////////////////
1354 /// Set default user name.
1355 
1356 void TAuthenticate::SetDefaultUser(const char *defaultuser)
1357 {
1358  if (fgDefaultUser != "")
1359  fgDefaultUser = "";
1360 
1361  if (defaultuser && defaultuser[0])
1362  fgDefaultUser = defaultuser;
1363 }
1364 
1365 ////////////////////////////////////////////////////////////////////////////////
1366 /// Set timeout (active if > 0)
1367 
1368 void TAuthenticate::SetTimeOut(Int_t to)
1369 {
1370  fgAuthTO = (to <= 0) ? -1 : to;
1371 }
1372 
1373 ////////////////////////////////////////////////////////////////////////////////
1374 /// Set global AuthReUse flag
1375 
1376 void TAuthenticate::SetAuthReUse(Bool_t authreuse)
1377 {
1378  fgAuthReUse = authreuse;
1379 }
1380 
1381 ////////////////////////////////////////////////////////////////////////////////
1382 /// Set global PromptUser flag
1383 
1384 void TAuthenticate::SetPromptUser(Bool_t promptuser)
1385 {
1386  fgPromptUser = promptuser;
1387 }
1388 
1389 ////////////////////////////////////////////////////////////////////////////////
1390 /// Set secure authorization function.
1391 
1392 void TAuthenticate::SetSecureAuthHook(SecureAuth_t func)
1393 {
1394  fgSecAuthHook = func;
1395 }
1396 
1397 ////////////////////////////////////////////////////////////////////////////////
1398 /// Set kerberos5 authorization function. Automatically called when
1399 /// libKrb5Auth is loaded.
1400 
1401 void TAuthenticate::SetKrb5AuthHook(Krb5Auth_t)
1402 {
1403  ::Error("Krb5Auth", "Kerberos5 is no longer supported by ROOT");
1404 }
1405 
1406 ////////////////////////////////////////////////////////////////////////////////
1407 /// Set Globus authorization function. Automatically called when
1408 /// libGlobusAuth is loaded.
1409 
1410 void TAuthenticate::SetGlobusAuthHook(GlobusAuth_t)
1411 {
1412  ::Error("GlobusAuth", "Globus is no longer supported by ROOT");
1413 }
1414 
1415 ////////////////////////////////////////////////////////////////////////////////
1416 /// SSH client authentication code (no longer supported)
1417 
1418 Int_t TAuthenticate::SshAuth(TString & /* user */)
1419 {
1420  ::Error("SshAuth", "SSH is no longer supported by ROOT");
1421  return 1;
1422 }
1423 
1424 ////////////////////////////////////////////////////////////////////////////////
1425 /// Method returning the user to be used for the ssh login (no longer supported)
1426 
1427 const char *TAuthenticate::GetSshUser(TString /* user */) const
1428 {
1429  ::Error("GetSshUser", "SSH is no longer supported by ROOT");
1430  return nullptr;
1431 }
1432 
1433 ////////////////////////////////////////////////////////////////////////////////
1434 /// Check if 'host' matches 'href':
1435 /// this means either equal or "containing" it, even with wild cards *
1436 /// in the first field (in the case 'href' is a name, ie not IP address)
1437 /// Returns kTRUE if the two matches.
1438 
1439 Bool_t TAuthenticate::CheckHost(const char *host, const char *href)
1440 {
1441  R__LOCKGUARD2(gAuthenticateMutex);
1442 
1443  Bool_t retval = kTRUE;
1444 
1445  // Both strings should have been defined
1446  if (!host || !href)
1447  return kFALSE;
1448 
1449  // 'href' == '*' indicates any 'host' ...
1450  if (!strcmp(href,"*"))
1451  return kTRUE;
1452 
1453  // If 'href' contains at a letter or an hyphen it is assumed to be
1454  // a host name. Otherwise a name.
1455  // Check also for wild cards
1456  Bool_t name = kFALSE;
1457  TRegexp rename("[+a-zA-Z]");
1458  Int_t len;
1459  if (rename.Index(href,&len) != -1 || strstr(href,"-"))
1460  name = kTRUE;
1461 
1462  // Check also for wild cards
1463  Bool_t wild = kFALSE;
1464  if (strstr(href,"*"))
1465  wild = kTRUE;
1466 
1467  // Now build the regular expression for final checking
1468  TRegexp rehost(href,wild);
1469 
1470  // host to check
1471  TString theHost(host);
1472  if (!name) {
1473  TInetAddress addr = gSystem->GetHostByName(host);
1474  theHost = addr.GetHostAddress();
1475  if (gDebug > 2)
1476  ::Info("TAuthenticate::CheckHost", "checking host IP: %s", theHost.Data());
1477  }
1478 
1479  // Check 'host' against 'rehost'
1480  Ssiz_t pos = rehost.Index(theHost,&len);
1481  if (pos == -1)
1482  retval = kFALSE;
1483 
1484  // If IP and no wilds, it should match either
1485  // the beginning or the end of the string
1486  if (!wild) {
1487  if (pos > 0 && pos != (Ssiz_t)(theHost.Length()-strlen(href)))
1488  retval = kFALSE;
1489  }
1490 
1491  return retval;
1492 }
1493 
1494 ////////////////////////////////////////////////////////////////////////////////
1495 /// RFIO authentication (no longer supported)
1496 
1497 Int_t TAuthenticate::RfioAuth(TString &)
1498 {
1499  ::Error("RfioAuth", "RfioAuth is no longer supported by ROOT");
1500  return -1;
1501 }
1502 
1503 ////////////////////////////////////////////////////////////////////////////////
1504 /// UsrPwd client authentication code.
1505 /// Returns 0 in case authentication failed
1506 /// 1 in case of success
1507 
1508 Int_t TAuthenticate::ClearAuth(TString &user, TString &passwd, Bool_t &pwdhash)
1509 {
1510  R__LOCKGUARD2(gAuthenticateMutex);
1511 
1512  if (gDebug > 2)
1513  Info("ClearAuth", "enter: user: %s (passwd hashed?: %d)",
1514  user.Data(),(Int_t)pwdhash);
1515 
1516  Int_t reuse = fgAuthReUse;
1517  Int_t prompt = fgPromptUser;
1518  Int_t cryptopt = fgUsrPwdCrypt;
1519  Int_t needsalt = 1;
1520  if (pwdhash)
1521  needsalt = 0;
1522  fDetails = TString::Format("pt:%d ru:%d cp:%d us:",
1523  fgPromptUser, fgAuthReUse, fgUsrPwdCrypt) + user;
1524  if (gDebug > 2)
1525  Info("ClearAuth", "ru:%d pt:%d cp:%d ns:%d rk:%d",
1526  fgAuthReUse,fgPromptUser,fgUsrPwdCrypt,needsalt,fgRSAKey);
1527 #ifdef R__WIN32
1528  needsalt = 0;
1529 #endif
1530  Int_t stat, kind;
1531 
1532  if (fVersion > 1) {
1533 
1534  //
1535  // New protocol
1536  //
1537  Int_t anon = 0;
1538  TString salt = "";
1539  TString pashash = "";
1540 
1541  // Get effective user (fro remote checks in $HOME/.rhosts)
1542  UserGroup_t *pw = gSystem->GetUserInfo(gSystem->GetEffectiveUid());
1543  TString effUser;
1544  if (pw) {
1545  effUser = TString(pw->fUser);
1546  delete pw;
1547  } else
1548  effUser = user;
1549 
1550  // Create options string
1551  int opt = (reuse * kAUTH_REUSE_MSK) + (cryptopt * kAUTH_CRYPT_MSK) +
1552  (needsalt * kAUTH_SSALT_MSK) + (fRSAKey * kAUTH_RSATY_MSK);
1553  TString options;
1554  options.Form("%d %ld %s %ld %s", opt,
1555  (Long_t)user.Length(), user.Data(),
1556  (Long_t)effUser.Length(), effUser.Data());
1557 
1558  // Check established authentications
1559  kind = kROOTD_USER;
1560  stat = reuse;
1561  Int_t rc = 0;
1562  if ((rc = AuthExists(user, (Int_t) TAuthenticate::kClear, options,
1563  &kind, &stat, &StdCheckSecCtx)) == 1) {
1564  // A valid authentication exists: we are done ...
1565  return 1;
1566  }
1567  if (rc == -2) {
1568  return rc;
1569  }
1570  if (stat == kErrNotAllowed && kind == kROOTD_ERR) {
1571  return 0;
1572  }
1573 
1574  if (kind == kROOTD_AUTH && stat == -1) {
1575  if (gDebug > 3)
1576  Info("ClearAuth", "anonymous user");
1577  anon = 1;
1578  cryptopt = 0;
1579  reuse = 0;
1580  needsalt = 0;
1581  }
1582 
1583  // The random tag in hex representation
1584  // Protection against reply attacks
1585  char ctag[11] = {0};
1586  if (anon == 0 && cryptopt == 1) {
1587 
1588  // Check that we got the right thing ..
1589  if (kind != kROOTD_RSAKEY || stat < 1 || stat > 2 ) {
1590  // Check for errors
1591  if (kind != kROOTD_ERR) {
1592  Warning("ClearAuth",
1593  "problems recvn RSA key flag: got message %d, flag: %d",
1594  kind, stat);
1595  }
1596  return 0;
1597  }
1598  if (gDebug > 3)
1599  Info("ClearAuth", "get key request ...");
1600 
1601  // Save type of key
1602  fRSAKey = stat - 1;
1603 
1604  // Send the key securely
1605  if (SendRSAPublicKey(fSocket,fRSAKey) < 0)
1606  return 0;
1607 
1608  int slen = 0;
1609  if (needsalt) {
1610  // Receive password salt
1611  char *tmpsalt = 0;
1612  if ((slen = SecureRecv(fSocket, 1, fRSAKey, &tmpsalt)) == -1) {
1613  Warning("ClearAuth", "problems secure-receiving salt -"
1614  " may result in corrupted salt");
1615  Warning("ClearAuth", "switch off reuse for this session");
1616  needsalt = 0;
1617  return 0;
1618  }
1619  if (slen) {
1620  // Extract random tag, if there
1621  if (slen > 9) {
1622  int ltmp = slen;
1623  while (ltmp && tmpsalt[ltmp-1] != '#') ltmp--;
1624  if (ltmp) {
1625  if (tmpsalt[ltmp-1] == '#' &&
1626  tmpsalt[ltmp-10] == '#') {
1627  strlcpy(ctag,&tmpsalt[ltmp-10],11);
1628  // We drop the random tag
1629  ltmp -= 10;
1630  tmpsalt[ltmp] = 0;
1631  // Update salt length
1632  slen -= 10;
1633  }
1634  }
1635  if (!tmpsalt[0]) {
1636  // No salt left
1637  needsalt = 0;
1638  slen = 0;
1639  }
1640  }
1641  if (slen)
1642  salt = TString(tmpsalt);
1643  delete [] tmpsalt;
1644  }
1645  if (gDebug > 2)
1646  Info("ClearAuth", "got salt: '%s' (len: %d)", salt.Data(), slen);
1647  } else {
1648  if (gDebug > 2)
1649  Info("ClearAuth", "Salt not required");
1650  char *tmptag = 0;
1651  if (SecureRecv(fSocket, 1, fRSAKey, &tmptag) == -1) {
1652  Warning("ClearAuth", "problems secure-receiving rndmtag -"
1653  " may result in corrupted rndmtag");
1654  }
1655  if (tmptag) {
1656  strlcpy(ctag, tmptag, 11);
1657  delete [] tmptag;
1658  }
1659  }
1660  // We may not have got a salt (if the server may not access it
1661  // or if it needs the full password, like for AFS ...)
1662  if (!slen)
1663  needsalt = 0;
1664  }
1665  // Now get the password either from prompt or from memory, if saved already
1666  if (anon == 1) {
1667 
1668  if (fgPasswd.Contains("@")) {
1669  // Anonymous like login with user chosen passwd ...
1670  passwd = fgPasswd;
1671  } else {
1672  // Anonymous like login with automatic passwd generation ...
1673  TString localuser;
1674  pw = gSystem->GetUserInfo();
1675  if (pw) {
1676  char *u = StrDup(pw->fUser);
1677  localuser = u;
1678  delete[] u;
1679  }
1680  delete pw;
1681  static TString localFQDN;
1682  if (localFQDN == "") {
1683  TInetAddress addr = gSystem->GetHostByName(gSystem->HostName());
1684  if (addr.IsValid())
1685  localFQDN = addr.GetHostName();
1686  }
1687  passwd.Form("%s@%s", localuser.Data(), localFQDN.Data());
1688  if (gDebug > 2)
1689  Info("ClearAuth",
1690  "automatically generated anonymous passwd: %s",
1691  passwd.Data());
1692  }
1693 
1694  } else {
1695 
1696  if (prompt == 1 || pashash.Length() == 0) {
1697 
1698  if (passwd == "") {
1699  TString xp;
1700  xp.Form("%s@%s password: ", user.Data(),fRemote.Data());
1701  char *pwd = PromptPasswd(xp);
1702  passwd = TString(pwd);
1703  delete [] pwd;
1704  if (passwd == "") {
1705  Error("ClearAuth", "password not set");
1706  fSocket->Send("-1", kROOTD_PASS); // Needs this for consistency
1707  return 0;
1708  }
1709  }
1710  if (needsalt && !pwdhash) {
1711 #ifndef R__WIN32
1712  pashash = TString(crypt(passwd, salt));
1713  if (!pashash.BeginsWith(salt)) {
1714  // not the right version of the crypt function:
1715  // do not send hash
1716  pashash = passwd;
1717  }
1718 #else
1719  pashash = passwd;
1720 #endif
1721  } else {
1722  pashash = passwd;
1723  }
1724  }
1725 
1726  }
1727 
1728  // Store password for later use
1729  fgUser = fUser;
1730  fgPwHash = kFALSE;
1731  fPwHash = kFALSE;
1732  fgPasswd = passwd;
1733  fPasswd = passwd;
1734 
1735  // Send it to server
1736  if (anon == 0 && cryptopt == 1) {
1737 
1738  // Needs to send this for consistency
1739  if (fSocket->Send("\0", kROOTD_PASS) < 0)
1740  return 0;
1741 
1742  // Add the random tag received from the server
1743  // (if any); makes packets non re-usable
1744  if (strlen(ctag))
1745  pashash += ctag;
1746 
1747  if (SecureSend(fSocket, 1, fRSAKey, pashash.Data()) == -1) {
1748  Warning("ClearAuth", "problems secure-sending pass hash"
1749  " - may result in authentication failure");
1750  return 0;
1751  }
1752  } else {
1753 
1754  // Standard technique: invert passwd
1755  if (passwd != "") {
1756  for (int i = 0; i < passwd.Length(); i++) {
1757  char inv = ~passwd(i);
1758  passwd.Replace(i, 1, inv);
1759  }
1760  }
1761  if (fSocket->Send(passwd.Data(), kROOTD_PASS) < 0)
1762  return 0;
1763  }
1764 
1765  Int_t nrec = 0;
1766  // Receive username used for login
1767  if ((nrec = fSocket->Recv(stat, kind)) < 0 ) // returns user
1768  return 0;
1769  if (gDebug > 3)
1770  Info("ClearAuth", "after kROOTD_PASS: kind= %d, stat= %d", kind,
1771  stat);
1772 
1773  // Check for errors
1774  if (kind == kROOTD_ERR) {
1775  AuthError("ClearAuth", stat);
1776  fgPasswd = "";
1777  return 0;
1778  }
1779 
1780  if (kind != kROOTD_PASS || stat < 1)
1781  Warning("ClearAuth",
1782  "problems recvn (user,offset) length (%d:%d bytes:%d)",
1783  kind, stat, nrec);
1784 
1785  // Get user and offset
1786  char answer[256];
1787  int reclen = (stat+1 > 256) ? 256 : stat+1;
1788  if ((nrec = fSocket->Recv(answer, reclen, kind)) < 0)
1789  return 0;
1790  if (kind != kMESS_STRING)
1791  Warning("ClearAuth",
1792  "username and offset not received (%d:%d)", kind,
1793  nrec);
1794 
1795  // Parse answer
1796  char lUser[128];
1797  Int_t offset = -1;
1798  sscanf(answer, "%127s %d", lUser, &offset);
1799  if (gDebug > 3)
1800  Info("ClearAuth",
1801  "received from server: user: %s, offset: %d (%s)", lUser,
1802  offset, answer);
1803 
1804  // Return username
1805  user = lUser;
1806 
1807  char *token = 0;
1808  if (reuse == 1 && offset > -1) {
1809  // Receive token
1810  if (cryptopt == 1) {
1811  if (SecureRecv(fSocket, 1, fRSAKey, &token) == -1) {
1812  Warning("ClearAuth",
1813  "problems secure-receiving token -"
1814  " may result in corrupted token");
1815  return 0;
1816  }
1817  } else {
1818  Int_t tlen = 9;
1819  token = new char[tlen];
1820  if (fSocket->Recv(token, tlen, kind) < 0) {
1821  delete [] token;
1822  return 0;
1823  }
1824  if (kind != kMESS_STRING)
1825  Warning("ClearAuth", "token not received (%d:%d)", kind,
1826  nrec);
1827  // Invert token
1828  for (int i = 0; i < (int) strlen(token); i++) {
1829  token[i] = ~token[i];
1830  }
1831 
1832  }
1833  if (gDebug > 3)
1834  Info("ClearAuth", "received from server: token: '%s' ",
1835  token);
1836  }
1837  TPwdCtx *pwdctx = new TPwdCtx(fPasswd,fPwHash);
1838  // Create SecContext object
1839  fSecContext = fHostAuth->CreateSecContext((const char *)lUser, fRemote,
1840  kClear, offset, fDetails, (const char *)token,
1841  fgExpDate, (void *)pwdctx, fRSAKey);
1842 
1843  // Release allocated memory ...
1844  if (token)
1845  delete [] token;
1846 
1847  // This from remote login
1848  if (fSocket->Recv(stat, kind) < 0)
1849  return 0;
1850 
1851 
1852  if (kind == kROOTD_AUTH && stat >= 1) {
1853  if (stat == 5 && fSocket->GetServType() == TSocket::kPROOFD)
1854  // AFS: we cannot reuse the token because remotely the
1855  // daemon token must be re-initialized; for PROOF, we
1856  // just flag the entry as AFS; this allows to skip reusing
1857  // but to keep the session key for password forwarding
1858  fSecContext->SetID("AFS authentication");
1859  return 1;
1860  } else {
1861  fgPasswd = "";
1862  if (kind == kROOTD_ERR)
1863  AuthError("ClearAuth", stat);
1864  return 0;
1865  }
1866 
1867  } else {
1868 
1869  // Old Protocol
1870 
1871  // Send username
1872  if (fSocket->Send(user.Data(), kROOTD_USER) < 0)
1873  return 0;
1874 
1875  // Get replay from server
1876  if (fSocket->Recv(stat, kind) < 0)
1877  return 0;
1878 
1879  // This check should guarantee backward compatibility with a private
1880  // version of rootd used by CDF
1881  if (kind == kROOTD_AUTH && stat == 1) {
1882  fSecContext =
1883  fHostAuth->CreateSecContext(user,fRemote,kClear,-1,fDetails,0);
1884  return 1;
1885  }
1886 
1887  if (kind == kROOTD_ERR) {
1888  TString server = "sockd";
1889  if (fProtocol.Contains("root"))
1890  server = "rootd";
1891  if (fProtocol.Contains("proof"))
1892  server = "proofd";
1893  if (stat == kErrConnectionRefused) {
1894  if (gDebug > 0)
1895  Error("ClearAuth",
1896  "%s@%s does not accept connections from %s@%s",
1897  server.Data(),fRemote.Data(),
1898  fUser.Data(),gSystem->HostName());
1899  return -2;
1900  } else if (stat == kErrNotAllowed) {
1901  if (gDebug > 0)
1902  Error("ClearAuth",
1903  "%s@%s does not accept %s authentication from %s@%s",
1904  server.Data(),fRemote.Data(),
1905  TAuthenticate::fgAuthMeth[0].Data(),
1906  fUser.Data(),gSystem->HostName());
1907  } else
1908  AuthError("ClearAuth", stat);
1909  return 0;
1910  }
1911  // Prepare passwd to send
1912  badpass1:
1913  if (passwd == "") {
1914  TString xp;
1915  xp.Form("%s@%s password: ", user.Data(),fRemote.Data());
1916  char *p = PromptPasswd(xp);
1917  passwd = p;
1918  delete [] p;
1919  if (passwd == "")
1920  Error("ClearAuth", "password not set");
1921  }
1922  if (fUser == "anonymous" || fUser == "rootd") {
1923  if (!passwd.Contains("@")) {
1924  Warning("ClearAuth",
1925  "please use passwd of form: user@host.do.main");
1926  passwd = "";
1927  goto badpass1;
1928  }
1929  }
1930 
1931  fgPasswd = passwd;
1932  fPasswd = passwd;
1933 
1934  // Invert passwd
1935  if (passwd != "") {
1936  for (int i = 0; i < passwd.Length(); i++) {
1937  char inv = ~passwd(i);
1938  passwd.Replace(i, 1, inv);
1939  }
1940  }
1941  // Send it over the net
1942  if (fSocket->Send(passwd, kROOTD_PASS) < 0)
1943  return 0;
1944 
1945  // Get result of attempt
1946  if (fSocket->Recv(stat, kind) < 0) // returns user
1947  return 0;
1948  if (gDebug > 3)
1949  Info("ClearAuth", "after kROOTD_PASS: kind= %d, stat= %d", kind,
1950  stat);
1951 
1952  if (kind == kROOTD_AUTH && stat == 1) {
1953  fSecContext =
1954  fHostAuth->CreateSecContext(user,fRemote,kClear,-1,fDetails,0);
1955  return 1;
1956  } else {
1957  if (kind == kROOTD_ERR)
1958  AuthError("ClearAuth", stat);
1959  return 0;
1960  }
1961  }
1962  return 0;
1963 }
1964 
1965 ////////////////////////////////////////////////////////////////////////////////
1966 /// Sets fUser=user and search fgAuthInfo for the entry pertaining to
1967 /// (host,user), setting fHostAuth accordingly.
1968 /// If opt = "P" use fgProofAuthInfo list instead
1969 /// If no entry is found fHostAuth is not changed
1970 
1971 THostAuth *TAuthenticate::GetHostAuth(const char *host, const char *user,
1972  Option_t *opt, Int_t *exact)
1973 {
1974  if (exact)
1975  *exact = 0;
1976 
1977  if (gDebug > 2)
1978  ::Info("TAuthenticate::GetHostAuth", "enter ... %s ... %s", host, user);
1979 
1980  // Strip off the servertype, if any
1981  Int_t srvtyp = -1;
1982  TString hostname = host;
1983  if (hostname.Contains(":")) {
1984  char *ps = (char *)strstr(host,":");
1985  if (ps)
1986  srvtyp = atoi(ps+1);
1987  hostname.Remove(hostname.Index(":"));
1988  }
1989  TString hostFQDN = hostname;
1990  if (strncmp(host,"default",7) && !hostFQDN.Contains("*")) {
1991  TInetAddress addr = gSystem->GetHostByName(hostFQDN);
1992  if (addr.IsValid())
1993  hostFQDN = addr.GetHostName();
1994  }
1995  TString usr = user;
1996  if (!usr.Length())
1997  usr = "*";
1998  THostAuth *rHA = 0;
1999 
2000  // Check list of auth info for already loaded info about this host
2001  TIter *next = new TIter(GetAuthInfo());
2002  if (!strncasecmp(opt,"P",1)) {
2003  SafeDelete(next);
2004  next = new TIter(GetProofAuthInfo());
2005  }
2006 
2007  THostAuth *ai;
2008  Bool_t notFound = kTRUE;
2009  Bool_t serverOK = kTRUE;
2010  while ((ai = (THostAuth *) (*next)())) {
2011  if (gDebug > 3)
2012  ai->Print("Authenticate::GetHostAuth");
2013 
2014  // server
2015  if (!(serverOK = (ai->GetServer() == -1) ||
2016  (ai->GetServer() == srvtyp)))
2017  continue;
2018 
2019  // Use default entry if existing and nothing more specific is found
2020  if (!strcmp(ai->GetHost(),"default") && serverOK && notFound)
2021  rHA = ai;
2022 
2023  // Check
2024  if (CheckHost(hostFQDN,ai->GetHost()) &&
2025  CheckHost(usr,ai->GetUser()) && serverOK) {
2026  rHA = ai;
2027  notFound = kFALSE;
2028  }
2029 
2030  if (hostFQDN == ai->GetHost() &&
2031  usr == ai->GetUser() && srvtyp == ai->GetServer() ) {
2032  rHA = ai;
2033  if (exact)
2034  *exact = 1;
2035  break;
2036  }
2037  }
2038  SafeDelete(next);
2039  return rHA;
2040 }
2041 
2042 ////////////////////////////////////////////////////////////////////////////////
2043 /// Checks if a THostAuth with exact match for {host,user} exists
2044 /// in the fgAuthInfo list
2045 /// If opt = "P" use ProofAuthInfo list instead
2046 /// Returns pointer to it or 0
2047 
2048 THostAuth *TAuthenticate::HasHostAuth(const char *host, const char *user,
2049  Option_t *opt)
2050 {
2051  if (gDebug > 2)
2052  ::Info("TAuthenticate::HasHostAuth", "enter ... %s ... %s", host, user);
2053 
2054  // Strip off the servertype, if any
2055  Int_t srvtyp = -1;
2056  TString hostFQDN = host;
2057  if (hostFQDN.Contains(":")) {
2058  char *ps = (char *)strstr(host,":");
2059  if (ps)
2060  srvtyp = atoi(ps+1);
2061  hostFQDN.Remove(hostFQDN.Index(":"));
2062  }
2063  if (strncmp(host,"default",7) && !hostFQDN.Contains("*")) {
2064  TInetAddress addr = gSystem->GetHostByName(hostFQDN);
2065  if (addr.IsValid())
2066  hostFQDN = addr.GetHostName();
2067  }
2068 
2069  TIter *next = new TIter(GetAuthInfo());
2070  if (!strncasecmp(opt,"P",1)) {
2071  SafeDelete(next);
2072  next = new TIter(GetProofAuthInfo());
2073  }
2074  THostAuth *ai;
2075  while ((ai = (THostAuth *) (*next)())) {
2076 
2077  if (hostFQDN == ai->GetHost() &&
2078  !strcmp(user, ai->GetUser()) && srvtyp == ai->GetServer()) {
2079  SafeDelete(next);
2080  return ai;
2081  }
2082  }
2083  SafeDelete(next);
2084  return 0;
2085 }
2086 
2087 ////////////////////////////////////////////////////////////////////////////////
2088 /// Expands include directives found in fexp files
2089 /// The expanded, temporary file, is pointed to by 'ftmp'
2090 /// and should be already open. To be called recursively.
2091 
2092 void TAuthenticate::FileExpand(const char *fexp, FILE *ftmp)
2093 {
2094  FILE *fin;
2095  char line[kMAXPATHLEN];
2096  char cinc[20], fileinc[kMAXPATHLEN];
2097 
2098  if (gDebug > 2)
2099  ::Info("TAuthenticate::FileExpand", "enter ... '%s' ... 0x%lx", fexp, (Long_t)ftmp);
2100 
2101  fin = fopen(fexp, "r");
2102  if (fin == 0)
2103  return;
2104 
2105  while (fgets(line, sizeof(line), fin) != 0) {
2106  // Skip comment lines
2107  if (line[0] == '#')
2108  continue;
2109  if (line[strlen(line) - 1] == '\n')
2110  line[strlen(line) - 1] = '\0';
2111  if (gDebug > 2)
2112  ::Info("TAuthenticate::FileExpand", "read line ... '%s'", line);
2113  int nw = sscanf(line, "%19s %8191s", cinc, fileinc);
2114  if (nw < 1)
2115  continue; // Not enough info in this line
2116  if (strcmp(cinc, "include") != 0) {
2117  // copy line in temporary file
2118  fprintf(ftmp, "%s\n", line);
2119  } else {
2120 
2121  // Drop quotes or double quotes, if any
2122  TString ln(line);
2123  ln.ReplaceAll("\"",1,"",0);
2124  ln.ReplaceAll("'",1,"",0);
2125  sscanf(ln.Data(), "%19s %8191s", cinc, fileinc);
2126 
2127  // support environment directories ...
2128  if (fileinc[0] == '$') {
2129  TString finc(fileinc);
2130  TString edir(fileinc);
2131  if (edir.Contains("/")) {
2132  edir.Remove(edir.Index("/"));
2133  edir.Remove(0,1);
2134  if (gSystem->Getenv(edir.Data())) {
2135  finc.Remove(0,1);
2136  finc.ReplaceAll(edir.Data(),gSystem->Getenv(edir.Data()));
2137  fileinc[0] = '\0';
2138  strncpy(fileinc,finc.Data(),kMAXPATHLEN);
2139  fileinc[kMAXPATHLEN-1] = '\0';
2140  }
2141  }
2142  }
2143 
2144  // open (expand) file in temporary file ...
2145  if (fileinc[0] == '~') {
2146  // needs to expand
2147  int flen =
2148  strlen(fileinc) + strlen(gSystem->HomeDirectory()) + 10;
2149  char *ffull = new char[flen];
2150  snprintf(ffull, flen, "%s/%s", gSystem->HomeDirectory(), fileinc + 1);
2151  if (strlen(ffull) < kMAXPATHLEN - 1) strlcpy(fileinc, ffull,kMAXPATHLEN);
2152  delete [] ffull;
2153  }
2154  // Check if file exist and can be read ... ignore if not ...
2155  if (!gSystem->AccessPathName(fileinc, kReadPermission)) {
2156  FileExpand(fileinc, ftmp);
2157  } else {
2158  ::Warning("TAuthenticate::FileExpand",
2159  "file specified by 'include' cannot be open or read (%s)",
2160  fileinc);
2161  }
2162  }
2163  }
2164  fclose(fin);
2165 }
2166 
2167 ////////////////////////////////////////////////////////////////////////////////
2168 /// Determine default authentication details for method 'sec' and user 'usr'.
2169 /// Checks .rootrc family files. Returned string must be deleted by the user.
2170 
2171 char *TAuthenticate::GetDefaultDetails(int sec, int opt, const char *usr)
2172 {
2173  char temp[kMAXPATHLEN] = { 0 };
2174  const char copt[2][5] = { "no", "yes" };
2175 
2176  if (gDebug > 2)
2177  ::Info("TAuthenticate::GetDefaultDetails",
2178  "enter ... %d ...pt:%d ... '%s'", sec, opt, usr);
2179 
2180  if (opt < 0 || opt > 1)
2181  opt = 1;
2182 
2183  // UsrPwd
2184  if (sec == TAuthenticate::kClear) {
2185  if (!usr[0] || !strncmp(usr,"*",1))
2186  usr = gEnv->GetValue("UsrPwd.Login", "");
2187  snprintf(temp, kMAXPATHLEN, "pt:%s ru:%s cp:%s us:%s",
2188  gEnv->GetValue("UsrPwd.LoginPrompt", copt[opt]),
2189  gEnv->GetValue("UsrPwd.ReUse", "1"),
2190  gEnv->GetValue("UsrPwd.Crypt", "1"), usr);
2191  }
2192 
2193  if (gDebug > 2)
2194  ::Info("TAuthenticate::GetDefaultDetails", "returning ... %s", temp);
2195 
2196  return StrDup(temp);
2197 }
2198 
2199 ////////////////////////////////////////////////////////////////////////////////
2200 /// Remove THostAuth instance from the list
2201 
2202 void TAuthenticate::RemoveHostAuth(THostAuth * ha, Option_t *opt)
2203 {
2204  if (!strncasecmp(opt,"P",1))
2205  GetProofAuthInfo()->Remove(ha);
2206  else
2207  GetAuthInfo()->Remove(ha);
2208  // ... destroy it
2209  delete ha;
2210 }
2211 
2212 ////////////////////////////////////////////////////////////////////////////////
2213 /// Print info about the authentication sector.
2214 /// If 'opt' contains 's' or 'S' prints information about established TSecContext,
2215 /// else prints information about THostAuth (if 'opt' is 'p' or 'P', prints
2216 /// Proof related information)
2217 
2218 void TAuthenticate::Show(Option_t *opt)
2219 {
2220  TString sopt(opt);
2221 
2222  if (sopt.Contains("s",TString::kIgnoreCase)) {
2223 
2224  // Print established security contexts
2225  TIter next(gROOT->GetListOfSecContexts());
2226  TSecContext *sc = 0;
2227  while ((sc = (TSecContext *)next()))
2228  sc->Print();
2229 
2230  } else {
2231 
2232  ::Info("::Print",
2233  " +--------------------------- BEGIN --------------------------------+");
2234  ::Info("::Print",
2235  " + +");
2236  if (sopt.Contains("p",TString::kIgnoreCase)) {
2237  ::Info("::Print",
2238  " + List fgProofAuthInfo has %4d members +",
2239  GetProofAuthInfo()->GetSize());
2240  ::Info("::Print",
2241  " + +");
2242  ::Info("::Print",
2243  " +------------------------------------------------------------------+");
2244  TIter next(GetProofAuthInfo());
2245  THostAuth *ai;
2246  while ((ai = (THostAuth *) next())) {
2247  ai->Print();
2248  }
2249  } else {
2250  ::Info("::Print",
2251  " + List fgAuthInfo has %4d members +",
2252  GetAuthInfo()->GetSize());
2253  ::Info("::Print",
2254  " + +");
2255  ::Info("::Print",
2256  " +------------------------------------------------------------------+");
2257  TIter next(GetAuthInfo());
2258  THostAuth *ai;
2259  while ((ai = (THostAuth *) next())) {
2260  ai->Print();
2261  ai->PrintEstablished();
2262  }
2263  }
2264  ::Info("::Print",
2265  " +---------------------------- END ---------------------------------+");
2266  }
2267 }
2268 
2269 ////////////////////////////////////////////////////////////////////////////////
2270 /// Check if we have a valid established sec context in memory
2271 /// Retrieves relevant info and negotiates with server.
2272 /// options = "Opt,strlen(username),username.Data()"
2273 /// message = kROOTD_USER, ...
2274 
2275 Int_t TAuthenticate::AuthExists(TString username, Int_t method, const char *options,
2276  Int_t *message, Int_t *rflag,
2277  CheckSecCtx_t checksecctx)
2278 {
2279  // Welcome message, if requested ...
2280  if (gDebug > 2)
2281  Info("AuthExists","%d: enter: msg: %d options: '%s'",
2282  method,*message, options);
2283 
2284  // Look for an existing security context matching this request
2285  Bool_t notHA = kFALSE;
2286 
2287  // First in the local list
2288  TIter next(fHostAuth->Established());
2289  TRootSecContext *secctx;
2290  while ((secctx = (TRootSecContext *)next())) {
2291  if (secctx->GetMethod() == method) {
2292  if (fRemote == secctx->GetHost()) {
2293  if (checksecctx &&
2294  (*checksecctx)(username,secctx) == 1)
2295  break;
2296  }
2297  }
2298  }
2299 
2300  // If nothing found, try the all list
2301  if (!secctx) {
2302  next = TIter(gROOT->GetListOfSecContexts());
2303  while ((secctx = (TRootSecContext *)next())) {
2304  if (secctx->GetMethod() == method) {
2305  if (fRemote == secctx->GetHost()) {
2306  if (checksecctx &&
2307  (*checksecctx)(username,secctx) == 1) {
2308  notHA = kTRUE;
2309  break;
2310  }
2311  }
2312  }
2313  }
2314  }
2315 
2316  // If we have been given a valid sec context retrieve some info
2317  Int_t offset = -1;
2318  TString token;
2319  if (secctx) {
2320  offset = secctx->GetOffSet();
2321  token = secctx->GetToken();
2322  if (gDebug > 2)
2323  Info("AuthExists",
2324  "found valid TSecContext: offset: %d token: '%s'",
2325  offset, token.Data());
2326  }
2327 
2328  // Prepare string to be sent to the server
2329  TString sstr;
2330  sstr.Form("%d %d %s", fgProcessID, offset, options);
2331 
2332  // Send message
2333  if (fSocket->Send(sstr, *message) < 0)
2334  return -2;
2335 
2336  Int_t reuse = *rflag;
2337  if (reuse == 1 && offset > -1) {
2338 
2339  // Receive result of checking offset
2340  // But only for recent servers
2341  // NB: not backward compatible with dev version 4.00.02: switch
2342  // off 'reuse' for such servers to avoid hanging at this point.
2343  Int_t rproto = fSocket->GetRemoteProtocol();
2344  Bool_t oldsrv = ((fProtocol.BeginsWith("root") && rproto == 9) ||
2345  (fProtocol.BeginsWith("proof") && rproto == 8));
2346  Int_t stat = 1, kind;
2347  if (!oldsrv) {
2348  if (fSocket->Recv(stat, kind) < 0)
2349  return -2;
2350  if (kind != kROOTD_AUTH)
2351  Warning("AuthExists","protocol error: expecting %d got %d"
2352  " (value: %d)",kROOTD_AUTH,kind,stat);
2353  }
2354 
2355  if (stat > 0) {
2356  if (gDebug > 2)
2357  Info("AuthExists","offset OK");
2358 
2359  Int_t rsaKey = secctx->GetRSAKey();
2360  if (gDebug > 2)
2361  Info("AuthExists", "key type: %d", rsaKey);
2362 
2363  if (rsaKey > -1) {
2364 
2365  // Recent servers send a random tag in stat
2366  // It has to be signed too
2367  if (stat > 1) {
2368  // Create hex from tag
2369  char tag[9] = {0};
2370  snprintf(tag, 9, "%08x",stat);
2371  // Add to token
2372  token += tag;
2373  }
2374 
2375  // Send token encrypted
2376  if (SecureSend(fSocket, 1, rsaKey, token) == -1) {
2377  Warning("AuthExists", "problems secure-sending token %s",
2378  "- may trigger problems in proofing Id ");
2379  return -2;
2380  }
2381  } else {
2382  // Send inverted
2383  for (int i = 0; i < token.Length(); i++) {
2384  char inv = ~token(i);
2385  token.Replace(i, 1, inv);
2386  }
2387  if (fSocket->Send(token, kMESS_STRING) < 0)
2388  return -2;
2389  }
2390  } else {
2391  if (gDebug > 0)
2392  Info("AuthExists","offset not OK - rerun authentication");
2393  // If the sec context was not valid, deactivate it ...
2394  if (secctx)
2395  secctx->DeActivate("");
2396  }
2397  }
2398 
2399  Int_t stat, kind;
2400  if (fSocket->Recv(stat, kind) < 0)
2401  return -2;
2402  if (gDebug > 3)
2403  Info("AuthExists","%d: after msg %d: kind= %d, stat= %d",
2404  method,*message, kind, stat);
2405 
2406  // Return flags
2407  *message = kind;
2408  *rflag = stat;
2409 
2410  if (kind == kROOTD_ERR) {
2411  TString server = "sockd";
2412  if (fSocket->GetServType() == TSocket::kROOTD)
2413  server = "rootd";
2414  if (fSocket->GetServType() == TSocket::kPROOFD)
2415  server = "proofd";
2416  if (stat == kErrConnectionRefused) {
2417  Error("AuthExists","%s@%s does not accept connections from %s@%s",
2418  server.Data(),fRemote.Data(),fUser.Data(),gSystem->HostName());
2419  return -2;
2420  } else if (stat == kErrNotAllowed) {
2421  if (gDebug > 0)
2422  Info("AuthExists",
2423  "%s@%s does not accept %s authentication from %s@%s",
2424  server.Data(),fRemote.Data(), fgAuthMeth[method].Data(),
2425  fUser.Data(),gSystem->HostName());
2426  } else
2427  AuthError("AuthExists", stat);
2428 
2429  // If the sec context was not valid, deactivate it ...
2430  if (secctx)
2431  secctx->DeActivate("");
2432  return 0;
2433  }
2434 
2435  if (kind == kROOTD_AUTH && stat >= 1) {
2436  if (!secctx)
2437  secctx =
2438  fHostAuth->CreateSecContext(fUser,fRemote,method,-stat,fDetails,0);
2439  if (gDebug > 3) {
2440  if (stat == 1)
2441  Info("AuthExists", "valid authentication exists");
2442  if (stat == 2)
2443  Info("AuthExists", "valid authentication exists: offset changed");
2444  if (stat == 3)
2445  Info("AuthExists", "remote access authorized by /etc/hosts.equiv");
2446  if (stat == 4)
2447  Info("AuthExists", "no authentication required remotely");
2448  }
2449 
2450  if (stat == 2) {
2451  int newOffSet;
2452  // Receive new offset ...
2453  if (fSocket->Recv(newOffSet, kind) < 0)
2454  return -2;
2455  // ... and save it
2456  secctx->SetOffSet(newOffSet);
2457  }
2458 
2459  fSecContext = secctx;
2460  // Add it to local list for later use (if not already there)
2461  if (notHA)
2462  fHostAuth->Established()->Add(secctx);
2463  return 1;
2464  }
2465  return 0;
2466 }
2467 
2468 ////////////////////////////////////////////////////////////////////////////////
2469 /// Initialize random machine using seed from /dev/urandom
2470 /// (or current time if /dev/urandom not available).
2471 
2472 void TAuthenticate::InitRandom()
2473 {
2474  static Bool_t notinit = kTRUE;
2475 
2476  if (notinit) {
2477  const char *randdev = "/dev/urandom";
2478  Int_t fd;
2479  UInt_t seed;
2480  if ((fd = open(randdev, O_RDONLY)) != -1) {
2481  if (gDebug > 2)
2482  ::Info("InitRandom", "taking seed from %s", randdev);
2483  if (read(fd, &seed, sizeof(seed)) != sizeof(seed))
2484  ::Warning("InitRandom", "could not read seed from %s", randdev);
2485  close(fd);
2486  } else {
2487  if (gDebug > 2)
2488  ::Info("InitRandom", "%s not available: using time()", randdev);
2489  seed = time(0); //better use times() + win32 equivalent
2490  }
2491  srand(seed);
2492  notinit = kFALSE;
2493  }
2494 }
2495 
2496 ////////////////////////////////////////////////////////////////////////////////
2497 /// Generate a valid pair of private/public RSA keys to protect for
2498 /// authentication token exchange
2499 
2500 Int_t TAuthenticate::GenRSAKeys()
2501 {
2502  if (gDebug > 2)
2503  Info("GenRSAKeys", "enter");
2504 
2505  if (fgRSAInit == 1) {
2506  if (gDebug > 2)
2507  Info("GenRSAKeys", "Keys prviously generated - return");
2508  }
2509 
2510  // This is for dynamic loads ...
2511  TString lib = "libRsa";
2512 
2513  // This is the local RSA implementation
2514  if (!TRSA_fun::RSA_genprim()) {
2515  char *p;
2516  if ((p = gSystem->DynamicPathName(lib, kTRUE))) {
2517  delete [] p;
2518  gSystem->Load(lib);
2519  }
2520  }
2521 
2522  // Init random machine
2523  TAuthenticate::InitRandom();
2524 
2525 #ifdef R__SSL
2526  if (fgRSAKey == 1) {
2527  // Generate also the SSL key
2528  if (gDebug > 2)
2529  Info("GenRSAKeys","SSL: Generate Blowfish key");
2530 
2531  // Init SSL ...
2532  SSL_library_init();
2533 
2534  // ... and its error strings
2535  SSL_load_error_strings();
2536 
2537  // Load Ciphers
2538  OpenSSL_add_all_ciphers();
2539 
2540  // Number of bits for key
2541  Int_t nbits = gEnv->GetValue("SSL.BFBits",256);
2542 
2543  // Minimum is 128
2544  nbits = (nbits >= 128) ? nbits : 128;
2545 
2546  // Max to limit size of buffers to 15912 (internal limitation)
2547  nbits = (nbits <= 15912) ? nbits : 15912;
2548 
2549  // Closer Number of chars
2550  Int_t klen = nbits / 8 ;
2551 
2552  // Init random engine
2553  char *rbuf = GetRandString(0,klen);
2554  RAND_seed(rbuf,strlen(rbuf));
2555 
2556  // This is what we export
2557  fgRSAPubExport[1].len = klen;
2558  fgRSAPubExport[1].keys = rbuf;
2559  if (gDebug > 2)
2560  Info("GenRSAKeys","SSL: BF key length: %d", fgRSAPubExport[1].len);
2561 
2562  // Now set the key locally in BF form
2563  BF_set_key(&fgBFKey, klen, (const unsigned char *)rbuf);
2564  }
2565 #endif
2566 
2567  // Sometimes some bunch is not decrypted correctly
2568  // That's why we make retries to make sure that encryption/decryption
2569  // works as expected
2570  Bool_t notOk = 1;
2571  rsa_NUMBER p1, p2, rsa_n, rsa_e, rsa_d;
2572  Int_t l_n = 0, l_d = 0;
2573  char buf_n[rsa_STRLEN], buf_e[rsa_STRLEN], buf_d[rsa_STRLEN];
2574 #if R__RSADE
2575  Int_t l_e;
2576  char buf[rsa_STRLEN];
2577 #endif
2578 
2579  Int_t nAttempts = 0;
2580  Int_t thePrimeLen = kPRIMELENGTH;
2581  Int_t thePrimeExp = kPRIMEEXP; // Prime probability = 1-0.5^thePrimeExp
2582  while (notOk && nAttempts < kMAXRSATRIES) {
2583 
2584  nAttempts++;
2585  if (gDebug > 2 && nAttempts > 1) {
2586  Info("GenRSAKeys", "retry no. %d",nAttempts);
2587  srand(auth_rand());
2588  }
2589 
2590  // Valid pair of primes
2591  p1 = TRSA_fun::RSA_genprim()(thePrimeLen, thePrimeExp);
2592  p2 = TRSA_fun::RSA_genprim()(thePrimeLen+1, thePrimeExp);
2593 
2594  // Retry if equal
2595  Int_t nPrimes = 0;
2596  while (TRSA_fun::RSA_cmp()(&p1, &p2) == 0 && nPrimes < kMAXRSATRIES) {
2597  nPrimes++;
2598  if (gDebug > 2)
2599  Info("GenRSAKeys", "equal primes: regenerate (%d times)",nPrimes);
2600  srand(auth_rand());
2601  p1 = TRSA_fun::RSA_genprim()(thePrimeLen, thePrimeExp);
2602  p2 = TRSA_fun::RSA_genprim()(thePrimeLen+1, thePrimeExp);
2603  }
2604 #if R__RSADEB
2605  if (gDebug > 3) {
2606  TRSA_fun::RSA_num_sput()(&p1, buf, rsa_STRLEN);
2607  Info("GenRSAKeys", "local: p1: '%s' ", buf);
2608  TRSA_fun::RSA_num_sput()(&p2, buf, rsa_STRLEN);
2609  Info("GenRSAKeys", "local: p2: '%s' ", buf);
2610  }
2611 #endif
2612  // Generate keys
2613  if (TRSA_fun::RSA_genrsa()(p1, p2, &rsa_n, &rsa_e, &rsa_d)) {
2614  if (gDebug > 2 && nAttempts > 1)
2615  Info("GenRSAKeys"," genrsa: unable to generate keys (%d)",
2616  nAttempts);
2617  continue;
2618  }
2619 
2620  // Get equivalent strings and determine their lengths
2621  TRSA_fun::RSA_num_sput()(&rsa_n, buf_n, rsa_STRLEN);
2622  l_n = strlen(buf_n);
2623  TRSA_fun::RSA_num_sput()(&rsa_e, buf_e, rsa_STRLEN);
2624 #if R__RSADEB
2625  l_e = strlen(buf_e);
2626 #endif
2627  TRSA_fun::RSA_num_sput()(&rsa_d, buf_d, rsa_STRLEN);
2628  l_d = strlen(buf_d);
2629 
2630 #if R__RSADEB
2631  if (gDebug > 3) {
2632  Info("GenRSAKeys", "local: n: '%s' length: %d", buf_n, l_n);
2633  Info("GenRSAKeys", "local: e: '%s' length: %d", buf_e, l_e);
2634  Info("GenRSAKeys", "local: d: '%s' length: %d", buf_d, l_d);
2635  }
2636 #endif
2637  if (TRSA_fun::RSA_cmp()(&rsa_n, &rsa_e) <= 0)
2638  continue;
2639  if (TRSA_fun::RSA_cmp()(&rsa_n, &rsa_d) <= 0)
2640  continue;
2641 
2642  // Now we try the keys
2643  char test[2 * rsa_STRLEN] = "ThisIsTheStringTest01203456-+/";
2644  Int_t lTes = 31;
2645  char *tdum = GetRandString(0, lTes - 1);
2646  strlcpy(test, tdum, lTes+1);
2647  delete [] tdum;
2648  char buf[2 * rsa_STRLEN];
2649  if (gDebug > 3)
2650  Info("GenRSAKeys", "local: test string: '%s' ", test);
2651 
2652  // Private/Public
2653  strlcpy(buf, test, lTes+1);
2654 
2655  // Try encryption with private key
2656  int lout = TRSA_fun::RSA_encode()(buf, lTes, rsa_n, rsa_e);
2657  if (gDebug > 3)
2658  Info("GenRSAKeys",
2659  "local: length of crypted string: %d bytes", lout);
2660 
2661  // Try decryption with public key
2662  TRSA_fun::RSA_decode()(buf, lout, rsa_n, rsa_d);
2663  buf[lTes] = 0;
2664  if (gDebug > 3)
2665  Info("GenRSAKeys", "local: after private/public : '%s' ", buf);
2666 
2667  if (strncmp(test, buf, lTes))
2668  continue;
2669 
2670  // Public/Private
2671  strlcpy(buf, test, lTes+1);
2672 
2673  // Try encryption with public key
2674  lout = TRSA_fun::RSA_encode()(buf, lTes, rsa_n, rsa_d);
2675  if (gDebug > 3)
2676  Info("GenRSAKeys", "local: length of crypted string: %d bytes ",
2677  lout);
2678 
2679  // Try decryption with private key
2680  TRSA_fun::RSA_decode()(buf, lout, rsa_n, rsa_e);
2681  buf[lTes] = 0;
2682  if (gDebug > 3)
2683  Info("GenRSAKeys", "local: after public/private : '%s' ", buf);
2684 
2685  if (strncmp(test, buf, lTes))
2686  continue;
2687 
2688  notOk = 0;
2689  }
2690 
2691  // Save Private key
2692  TRSA_fun::RSA_assign()(&fgRSAPriKey.n, &rsa_n);
2693  TRSA_fun::RSA_assign()(&fgRSAPriKey.e, &rsa_e);
2694 
2695  // Save Public key
2696  TRSA_fun::RSA_assign()(&fgRSAPubKey.n, &rsa_n);
2697  TRSA_fun::RSA_assign()(&fgRSAPubKey.e, &rsa_d);
2698 
2699 #if R__RSADEB
2700  if (gDebug > 2) {
2701  // Determine their lengths
2702  Info("GenRSAKeys", "local: generated keys are:");
2703  Info("GenRSAKeys", "local: n: '%s' length: %d", buf_n, l_n);
2704  Info("GenRSAKeys", "local: e: '%s' length: %d", buf_e, l_e);
2705  Info("GenRSAKeys", "local: d: '%s' length: %d", buf_d, l_d);
2706  }
2707 #endif
2708  // Export form
2709  if (fgRSAPubExport[0].keys) {
2710  delete [] fgRSAPubExport[0].keys;
2711  fgRSAPubExport[0].len = 0;
2712  }
2713  fgRSAPubExport[0].len = l_n + l_d + 4;
2714  fgRSAPubExport[0].keys = new char[fgRSAPubExport[0].len];
2715 
2716  fgRSAPubExport[0].keys[0] = '#';
2717  memcpy(fgRSAPubExport[0].keys + 1, buf_n, l_n);
2718  fgRSAPubExport[0].keys[l_n + 1] = '#';
2719  memcpy(fgRSAPubExport[0].keys + l_n + 2, buf_d, l_d);
2720  fgRSAPubExport[0].keys[l_n + l_d + 2] = '#';
2721  fgRSAPubExport[0].keys[l_n + l_d + 3] = 0;
2722 #if R__RSADEB
2723  if (gDebug > 2)
2724  Info("GenRSAKeys", "local: export pub: '%s'", fgRSAPubExport[0].keys);
2725 #else
2726  if (gDebug > 2)
2727  Info("GenRSAKeys", "local: export pub length: %d bytes", fgRSAPubExport[0].len);
2728 #endif
2729 
2730  // Set availability flag
2731  fgRSAInit = 1;
2732 
2733  return 0;
2734 }
2735 
2736 ////////////////////////////////////////////////////////////////////////////////
2737 /// Allocates and fills a 0 terminated buffer of length len+1 with
2738 /// len random characters.
2739 /// Returns pointer to the buffer (to be deleted by the caller)
2740 /// opt = 0 any non dangerous char
2741 /// 1 letters and numbers (upper and lower case)
2742 /// 2 hex characters (upper and lower case)
2743 
2744 char *TAuthenticate::GetRandString(Int_t opt, Int_t len)
2745 {
2746  unsigned int iimx[4][4] = {
2747  {0x0, 0xffffff08, 0xafffffff, 0x2ffffffe}, // opt = 0
2748  {0x0, 0x3ff0000, 0x7fffffe, 0x7fffffe}, // opt = 1
2749  {0x0, 0x3ff0000, 0x7e, 0x7e}, // opt = 2
2750  {0x0, 0x3ffc000, 0x7fffffe, 0x7fffffe} // opt = 3
2751  };
2752 
2753  const char *cOpt[4] = { "Any", "LetNum", "Hex", "Crypt" };
2754 
2755  // Default option 0
2756  if (opt < 0 || opt > 2) {
2757  opt = 0;
2758  if (gDebug > 2)
2759  Info("GetRandString", "unknown option: %d : assume 0", opt);
2760  }
2761  if (gDebug > 2)
2762  Info("GetRandString", "enter ... len: %d %s", len, cOpt[opt]);
2763 
2764  // Allocate buffer
2765  char *buf = new char[len + 1];
2766 
2767  // Init random machine (if needed)
2768  TAuthenticate::InitRandom();
2769 
2770  // randomize
2771  Int_t k = 0;
2772  Int_t i, j, l, m, frnd;
2773  while (k < len) {
2774  frnd = auth_rand();
2775  for (m = 7; m < 32; m += 7) {
2776  i = 0x7F & (frnd >> m);
2777  j = i / 32;
2778  l = i - j * 32;
2779  if ((iimx[opt][j] & (1 << l))) {
2780  buf[k] = i;
2781  k++;
2782  }
2783  if (k == len)
2784  break;
2785  }
2786  }
2787 
2788  // null terminated
2789  buf[len] = 0;
2790  if (gDebug > 3)
2791  Info("GetRandString", "got '%s' ", buf);
2792 
2793  return buf;
2794 }
2795 
2796 ////////////////////////////////////////////////////////////////////////////////
2797 /// Encode null terminated str using the session private key indicated by enc
2798 /// and sends it over the network
2799 /// Returns number of bytes sent, or -1 in case of error.
2800 /// enc = 1 for private encoding, enc = 2 for public encoding
2801 
2802 Int_t TAuthenticate::SecureSend(TSocket *sock, Int_t enc,
2803  Int_t key, const char *str)
2804 {
2805  char buftmp[kMAXSECBUF];
2806  char buflen[20];
2807 
2808  if (gDebug > 2)
2809  ::Info("TAuthenticate::SecureSend", "local: enter ... (enc: %d)", enc);
2810 
2811  Int_t slen = strlen(str) + 1;
2812  Int_t ttmp = 0;
2813  Int_t nsen = -1;
2814 
2815  if (key == 0) {
2816  strlcpy(buftmp, str, slen+1);
2817 
2818  if (enc == 1)
2819  ttmp = TRSA_fun::RSA_encode()(buftmp, slen, fgRSAPriKey.n,
2820  fgRSAPriKey.e);
2821  else if (enc == 2)
2822  ttmp = TRSA_fun::RSA_encode()(buftmp, slen, fgRSAPubKey.n,
2823  fgRSAPubKey.e);
2824  else
2825  return nsen;
2826  } else if (key == 1) {
2827 
2828 #ifdef R__SSL
2829  ttmp = strlen(str);
2830  if ((ttmp % 8) > 0) // It should be a multiple of 8!
2831  ttmp = ((ttmp + 8)/8) * 8;
2832  unsigned char iv[8];
2833  memset((void *)&iv[0],0,8);
2834  BF_cbc_encrypt((const unsigned char *)str, (unsigned char *)buftmp,
2835  strlen(str), &fgBFKey, iv, BF_ENCRYPT);
2836 #else
2837  if (gDebug > 0)
2838  ::Info("TAuthenticate::SecureSend","not compiled with SSL support:"
2839  " you should not have got here!");
2840 #endif
2841  } else {
2842  if (gDebug > 0)
2843  ::Info("TAuthenticate::SecureSend","unknown key type (%d)",key);
2844  return nsen;
2845  }
2846 
2847  snprintf(buflen,20,"%d",ttmp);
2848  if (sock->Send(buflen, kROOTD_ENCRYPT) < 0)
2849  return -1;
2850  nsen = sock->SendRaw(buftmp, ttmp);
2851  if (gDebug > 3)
2852  ::Info("TAuthenticate::SecureSend",
2853  "local: sent %d bytes (expected: %d)", nsen,ttmp);
2854 
2855  return nsen;
2856 }
2857 
2858 ////////////////////////////////////////////////////////////////////////////////
2859 /// Receive str from sock and decode it using key indicated by key type
2860 /// Return number of received bytes or -1 in case of error.
2861 /// dec = 1 for private decoding, dec = 2 for public decoding
2862 
2863 Int_t TAuthenticate::SecureRecv(TSocket *sock, Int_t dec, Int_t key, char **str)
2864 {
2865 
2866  char buftmp[kMAXSECBUF];
2867  char buflen[20];
2868 
2869  Int_t nrec = -1;
2870  // We must get a pointer ...
2871  if (!str)
2872  return nrec;
2873 
2874  Int_t kind;
2875  if (sock->Recv(buflen, 20, kind) < 0)
2876  return -1;
2877  Int_t len = atoi(buflen);
2878  if (gDebug > 3)
2879  ::Info("TAuthenticate::SecureRecv", "got len '%s' %d (msg kind: %d)",
2880  buflen, len, kind);
2881  if (len == 0) {
2882  return len;
2883  }
2884  if (!strncmp(buflen, "-1", 2))
2885  return nrec;
2886 
2887  // Receive buffer
2888  if ((nrec = sock->RecvRaw(buftmp, len)) < 0)
2889  return nrec;
2890  if (key == 0) {
2891  if (dec == 1)
2892  TRSA_fun::RSA_decode()(buftmp, len, fgRSAPriKey.n, fgRSAPriKey.e);
2893  else if (dec == 2)
2894  TRSA_fun::RSA_decode()(buftmp, len, fgRSAPubKey.n, fgRSAPubKey.e);
2895  else
2896  return -1;
2897 
2898  // Prepare output
2899  const size_t strSize = strlen(buftmp) + 1;
2900  *str = new char[strSize];
2901  strlcpy(*str, buftmp, strSize);
2902 
2903  } else if (key == 1) {
2904 #ifdef R__SSL
2905  unsigned char iv[8];
2906  memset((void *)&iv[0],0,8);
2907  *str = new char[nrec + 1];
2908  BF_cbc_encrypt((const unsigned char *)buftmp, (unsigned char *)(*str),
2909  nrec, &fgBFKey, iv, BF_DECRYPT);
2910  (*str)[nrec] = '\0';
2911 #else
2912  if (gDebug > 0)
2913  ::Info("TAuthenticate::SecureRecv","not compiled with SSL support:"
2914  " you should not have got here!");
2915 #endif
2916  } else {
2917  if (gDebug > 0)
2918  ::Info("TAuthenticate::SecureRecv","unknown key type (%d)",key);
2919  return -1;
2920  }
2921 
2922  nrec= strlen(*str);
2923 
2924  return nrec;
2925 }
2926 
2927 ////////////////////////////////////////////////////////////////////////////////
2928 /// Store RSA public keys from export string rsaPubExport.
2929 
2930 Int_t TAuthenticate::DecodeRSAPublic(const char *rsaPubExport, R__rsa_NUMBER &rsa_n,
2931  R__rsa_NUMBER &rsa_d, char **rsassl)
2932 {
2933  if (!rsaPubExport)
2934  return -1;
2935 
2936  if (gDebug > 2)
2937  ::Info("TAuthenticate::DecodeRSAPublic",
2938  "enter: string length: %ld bytes", (Long_t)strlen(rsaPubExport));
2939 
2940  char str[kMAXPATHLEN] = { 0 };
2941  Int_t klen = strlen(rsaPubExport);
2942  if (klen > kMAXPATHLEN - 1) {
2943  ::Info("TAuthenticate::DecodeRSAPublic",
2944  "key too long (%d): truncate to %d",klen,kMAXPATHLEN);
2945  klen = kMAXPATHLEN - 1;
2946  }
2947  memcpy(str, rsaPubExport, klen);
2948  str[klen] ='\0';
2949 
2950  Int_t keytype = -1;
2951 
2952  if (klen > 0) {
2953 
2954  // Skip spaces at beginning, if any
2955  int k = 0;
2956  while (str[k] == 32) k++;
2957 
2958  if (str[k] == '#') {
2959 
2960  keytype = 0;
2961 
2962  // The format is #<hex_n>#<hex_d>#
2963  char *pd1 = strstr(str, "#");
2964  char *pd2 = pd1 ? strstr(pd1 + 1, "#") : (char *)0;
2965  char *pd3 = pd2 ? strstr(pd2 + 1, "#") : (char *)0;
2966  if (pd1 && pd2 && pd3) {
2967  // Get <hex_n> ...
2968  int l1 = (int) (pd2 - pd1 - 1);
2969  char *rsa_n_exp = new char[l1 + 1];
2970  strlcpy(rsa_n_exp, pd1 + 1, l1+1);
2971  if (gDebug > 2)
2972  ::Info("TAuthenticate::DecodeRSAPublic",
2973  "got %ld bytes for rsa_n_exp", (Long_t)strlen(rsa_n_exp));
2974  // Now <hex_d>
2975  int l2 = (int) (pd3 - pd2 - 1);
2976  char *rsa_d_exp = new char[l2 + 1];
2977  strlcpy(rsa_d_exp, pd2 + 1, 13);
2978  if (gDebug > 2)
2979  ::Info("TAuthenticate::DecodeRSAPublic",
2980  "got %ld bytes for rsa_d_exp", (Long_t)strlen(rsa_d_exp));
2981 
2982  TRSA_fun::RSA_num_sget()(&rsa_n, rsa_n_exp);
2983  TRSA_fun::RSA_num_sget()(&rsa_d, rsa_d_exp);
2984 
2985  delete[] rsa_n_exp;
2986  delete[] rsa_d_exp;
2987 
2988  } else
2989  ::Info("TAuthenticate::DecodeRSAPublic","bad format for input string");
2990 #ifdef R__SSL
2991  } else {
2992  // try SSL
2993  keytype = 1;
2994 
2995  RSA *rsatmp;
2996 
2997  // Bio for exporting the pub key
2998  BIO *bpub = BIO_new(BIO_s_mem());
2999 
3000  // Write key from kbuf to BIO
3001  BIO_write(bpub,(void *)str,strlen(str));
3002 
3003  // Read pub key from BIO
3004  if (!(rsatmp = PEM_read_bio_RSAPublicKey(bpub, 0, 0, 0))) {
3005  if (gDebug > 0)
3006  ::Info("TAuthenticate::DecodeRSAPublic",
3007  "unable to read pub key from bio");
3008  } else
3009  if (rsassl)
3010  *rsassl = (char *)rsatmp;
3011  else
3012  ::Info("TAuthenticate::DecodeRSAPublic",
3013  "no space allocated for output variable");
3014  BIO_free(bpub);
3015  }
3016 #else
3017  } else {
3018  if (rsassl) { } // To avoid compiler complains
3019  if (gDebug > 0)
3020  ::Info("TAuthenticate::DecodeRSAPublic","not compiled with SSL support:"
3021  " you should not have got here!");
3022  }
3023 #endif
3024  }
3025 
3026  return keytype;
3027 }
3028 
3029 ////////////////////////////////////////////////////////////////////////////////
3030 /// Store RSA public keys from export string rsaPubExport.
3031 /// Returns type of stored key, or -1 is not recognized
3032 
3033 Int_t TAuthenticate::SetRSAPublic(const char *rsaPubExport, Int_t klen)
3034 {
3035  if (gDebug > 2)
3036  ::Info("TAuthenticate::SetRSAPublic",
3037  "enter: string length %ld bytes", (Long_t)strlen(rsaPubExport));
3038 
3039  Int_t rsakey = -1;
3040  if (!rsaPubExport)
3041  return rsakey;
3042 
3043  if (klen > 0) {
3044 
3045  // Skip spaces at beginning, if any
3046  int k0 = 0;
3047  while (rsaPubExport[k0] == 32) k0++;
3048  int k2 = klen - 1;
3049 
3050  // Parse rsaPubExport
3051  // Type 0 is in the form
3052  //
3053  // #< gt 10 exa chars >#< gt 10 exa chars >#
3054  //
3055  rsakey = 1;
3056  if (rsaPubExport[k0] == '#' && rsaPubExport[k2] == '#') {
3057  char *p0 = (char *)&rsaPubExport[k0];
3058  char *p2 = (char *)&rsaPubExport[k2];
3059  char *p1 = strchr(p0+1,'#');
3060  if (p1 > p0 && p1 < p2) {
3061  Int_t l01 = (Int_t)(p1-p0)-1;
3062  Int_t l12 = (Int_t)(p2-p1)-1;
3063  if (l01 >= kPRIMELENGTH*2 && l12 >= kPRIMELENGTH*2) {
3064  // Require exadecimal chars in between
3065  char *c = p0+1;
3066  while (c < p1 && ((*c < 58 && *c > 47) || (*c < 91 && *c > 64)))
3067  c++;
3068  if (c == p1) {
3069  c++;
3070  while (c < p2 && ((*c < 58 && *c > 47) || (*c < 91 && *c > 64)))
3071  c++;
3072  if (c == p2)
3073  rsakey = 0;
3074  }
3075  }
3076  }
3077  }
3078  if (gDebug > 3)
3079  ::Info("TAuthenticate::SetRSAPublic"," Key type: %d",rsakey);
3080  if (rsakey == 0) {
3081 
3082  // Decode input string
3083  R__rsa_NUMBER rsa_n, rsa_d;
3084  rsakey = TAuthenticate::DecodeRSAPublic(rsaPubExport,rsa_n,rsa_d);
3085 
3086  // Save Public key
3087  TRSA_fun::RSA_assign()(&fgRSAPubKey.n, &rsa_n);
3088  TRSA_fun::RSA_assign()(&fgRSAPubKey.e, &rsa_d);
3089 
3090  } else {
3091  rsakey = 1;
3092 #ifdef R__SSL
3093  // Now set the key locally in BF form
3094  BF_set_key(&fgBFKey, klen, (const unsigned char *)rsaPubExport);
3095 #else
3096  if (gDebug > 0)
3097  ::Info("TAuthenticate::SetRSAPublic",
3098  "not compiled with SSL support:"
3099  " you should not have got here!");
3100 #endif
3101  }
3102  }
3103 
3104  return rsakey;
3105 }
3106 
3107 ////////////////////////////////////////////////////////////////////////////////
3108 /// Receives server RSA Public key
3109 /// Sends local RSA public key encoded
3110 
3111 Int_t TAuthenticate::SendRSAPublicKey(TSocket *socket, Int_t key)
3112 {
3113  // Receive server public key
3114  char serverPubKey[kMAXSECBUF];
3115  int kind, nr = 0;
3116  if ((nr = socket->Recv(serverPubKey, kMAXSECBUF, kind)) < 0)
3117  return nr;
3118  if (gDebug > 3)
3119  ::Info("TAuthenticate::SendRSAPublicKey",
3120  "received key from server %ld bytes", (Long_t)strlen(serverPubKey));
3121 
3122  // Decode it
3123  R__rsa_NUMBER rsa_n, rsa_d;
3124 #ifdef R__SSL
3125  char *tmprsa = 0;
3126  if (TAuthenticate::DecodeRSAPublic(serverPubKey,rsa_n,rsa_d,
3127  &tmprsa) != key) {
3128  if (tmprsa)
3129  RSA_free((RSA *)tmprsa);
3130  return -1;
3131  }
3132  RSA *RSASSLServer = (RSA *)tmprsa;
3133 #else
3134  if (TAuthenticate::DecodeRSAPublic(serverPubKey,rsa_n,rsa_d) != key)
3135  return -1;
3136 #endif
3137 
3138  // Send local public key, encodes
3139  char buftmp[kMAXSECBUF] = {0};
3140  char buflen[20] = {0};
3141  Int_t slen = fgRSAPubExport[key].len;
3142  Int_t ttmp = 0;
3143  if (key == 0) {
3144  strlcpy(buftmp,fgRSAPubExport[key].keys,slen+1);
3145  ttmp = TRSA_fun::RSA_encode()(buftmp, slen, rsa_n, rsa_d);
3146  snprintf(buflen, 20, "%d", ttmp);
3147  } else if (key == 1) {
3148 #ifdef R__SSL
3149  Int_t lcmax = RSA_size(RSASSLServer) - 11;
3150  Int_t kk = 0;
3151  Int_t ke = 0;
3152  Int_t ns = slen;
3153  while (ns > 0) {
3154  Int_t lc = (ns > lcmax) ? lcmax : ns ;
3155  if ((ttmp = RSA_public_encrypt(lc,
3156  (unsigned char *)&fgRSAPubExport[key].keys[kk],
3157  (unsigned char *)&buftmp[ke],
3158  RSASSLServer,RSA_PKCS1_PADDING)) < 0) {
3159  char errstr[120];
3160  ERR_error_string(ERR_get_error(), errstr);
3161  ::Info("TAuthenticate::SendRSAPublicKey","SSL: error: '%s' ",errstr);
3162  }
3163  kk += lc;
3164  ke += ttmp;
3165  ns -= lc;
3166  }
3167  ttmp = ke;
3168  snprintf(buflen, 20, "%d", ttmp);
3169 #else
3170  if (gDebug > 0)
3171  ::Info("TAuthenticate::SendRSAPublicKey","not compiled with SSL support:"
3172  " you should not have got here!");
3173  return -1;
3174 #endif
3175  } else {
3176  if (gDebug > 0)
3177  ::Info("TAuthenticate::SendRSAPublicKey","unknown key type (%d)",key);
3178 #ifdef R__SSL
3179  if (RSASSLServer)
3180  RSA_free(RSASSLServer);
3181 #endif
3182  return -1;
3183  }
3184 
3185  // Send length first
3186  if ((nr = socket->Send(buflen, kROOTD_ENCRYPT)) < 0)
3187  return nr;
3188  // Send Key. second ...
3189  Int_t nsen = socket->SendRaw(buftmp, ttmp);
3190  if (gDebug > 3)
3191  ::Info("TAuthenticate::SendRSAPublicKey",
3192  "local: sent %d bytes (expected: %d)", nsen,ttmp);
3193 #ifdef R__SSL
3194  if (RSASSLServer)
3195  RSA_free(RSASSLServer);
3196 #endif
3197  return nsen;
3198 }
3199 
3200 ////////////////////////////////////////////////////////////////////////////////
3201 /// Read authentication directives from $ROOTAUTHRC, $HOME/.rootauthrc or
3202 /// <Root_etc_dir>/system.rootauthrc and create related THostAuth objects.
3203 /// Files are read only if they changed since last reading
3204 /// If 'proofconf' is defined, check also file proofconf for directives
3205 
3206 Int_t TAuthenticate::ReadRootAuthrc()
3207 {
3208  // rootauthrc family
3209  char *authrc = 0;
3210  if (gSystem->Getenv("ROOTAUTHRC") != 0) {
3211  authrc = StrDup(gSystem->Getenv("ROOTAUTHRC"));
3212  } else {
3213  if (fgReadHomeAuthrc)
3214  authrc = gSystem->ConcatFileName(gSystem->HomeDirectory(), ".rootauthrc");
3215  }
3216  if (authrc && gDebug > 2)
3217  ::Info("TAuthenticate::ReadRootAuthrc", "Checking file: %s", authrc);
3218  if (!authrc || gSystem->AccessPathName(authrc, kReadPermission)) {
3219  if (authrc && gDebug > 1)
3220  ::Info("TAuthenticate::ReadRootAuthrc",
3221  "file %s cannot be read (errno: %d)", authrc, errno);
3222  delete [] authrc;
3223  authrc = gSystem->ConcatFileName(TROOT::GetEtcDir(), "system.rootauthrc");
3224  if (gDebug > 2)
3225  ::Info("TAuthenticate::ReadRootAuthrc", "Checking system file: %s", authrc);
3226  if (gSystem->AccessPathName(authrc, kReadPermission)) {
3227  if (gDebug > 1)
3228  ::Info("TAuthenticate::ReadRootAuthrc",
3229  "file %s cannot be read (errno: %d)", authrc, errno);
3230  delete [] authrc;
3231  return 0;
3232  }
3233  }
3234 
3235  // Check if file has changed since last read
3236  TString tRootAuthrc = authrc;
3237  if (tRootAuthrc == fgRootAuthrc) {
3238  struct stat si;
3239  stat(tRootAuthrc, &si);
3240  if ((UInt_t)si.st_mtime < fgLastAuthrc.Convert()) {
3241  if (gDebug > 1)
3242  ::Info("TAuthenticate::ReadRootAuthrc",
3243  "file %s already read", authrc);
3244  delete [] authrc;
3245  return 0;
3246  }
3247  }
3248 
3249  // Save filename in static variable
3250  fgRootAuthrc = tRootAuthrc;
3251  fgLastAuthrc = TDatime();
3252 
3253  // THostAuth lists
3254  TList *authinfo = TAuthenticate::GetAuthInfo();
3255  TList *proofauthinfo = TAuthenticate::GetProofAuthInfo();
3256 
3257  // Expand File into temporary file name and open it
3258  int expand = 1;
3259  TString filetmp = "rootauthrc";
3260  FILE *ftmp = gSystem->TempFileName(filetmp);
3261  if (gDebug > 2)
3262  ::Info("TAuthenticate::ReadRootAuthrc", "got tmp file: %s open at 0x%lx",
3263  filetmp.Data(), (Long_t)ftmp);
3264  if (ftmp == 0)
3265  expand = 0; // Problems opening temporary file: ignore 'include's ...
3266 
3267  FILE *fd = 0;
3268  // If the temporary file is open, copy everything to the new file ...
3269  if (expand == 1) {
3270  TAuthenticate::FileExpand(authrc, ftmp);
3271  fd = ftmp;
3272  rewind(fd);
3273  } else {
3274  // Open file
3275  fd = fopen(authrc, "r");
3276  if (fd == 0) {
3277  if (gDebug > 2)
3278  ::Info("TAuthenticate::ReadRootAuthrc",
3279  "file %s cannot be open (errno: %d)", authrc, errno);
3280  delete [] authrc;
3281  return 0;
3282  }
3283  }
3284 
3285  // Now scan file for meaningful directives
3286  TList tmpAuthInfo;
3287  char line[kMAXPATHLEN];
3288  Bool_t cont = kFALSE;
3289  TString proofserv;
3290  while (fgets(line, sizeof(line), fd) != 0) {
3291 
3292  // Skip comment lines
3293  if (line[0] == '#')
3294  continue;
3295 
3296  // Get rid of end of line '\n', if there ...
3297  if (line[strlen(line) - 1] == '\n')
3298  line[strlen(line) - 1] = '\0';
3299 
3300  // Skip empty lines
3301  if (!line[0])
3302  continue;
3303 
3304  // Now scan
3305  const size_t tmpSize = strlen(line) + 1;
3306  char *tmp = new char[tmpSize];
3307  if (!tmp) {
3308  ::Error("TAuthenticate::ReadRootAuthrc",
3309  "could not allocate temporary buffer");
3310  fclose(fd);
3311  return 0;
3312  }
3313  strlcpy(tmp, line, tmpSize);
3314  char *nxt = strtok(tmp," ");
3315 
3316  if (!strcmp(nxt, "proofserv") || cont) {
3317 
3318  // Building the list of data servers for proof (analyzed at the end)
3319  char *ph = 0;
3320  if (cont)
3321  ph = nxt;
3322  else
3323  ph = strtok(0," ");
3324  while (ph) {
3325  if (*ph != 92) {
3326  proofserv += TString((const char *)ph);
3327  proofserv += TString(" ");
3328  cont = kFALSE;
3329  } else {
3330  cont = kTRUE;
3331  }
3332  ph = strtok(0," ");
3333  }
3334 
3335  } else {
3336 
3337  TString hostsrv = nxt;
3338  TString host = hostsrv;
3339  TString server = "";
3340  if (hostsrv.Contains(":")) {
3341  server = hostsrv;
3342  host.Remove(host.Index(":"));
3343  server.Remove(0,server.Index(":")+1);
3344  }
3345  Int_t srvtyp = -1;
3346  if (server.Length()) {
3347  if (server == "0" || server.BeginsWith("sock"))
3348  srvtyp = TSocket::kSOCKD;
3349  else if (server == "1" || server.BeginsWith("root"))
3350  srvtyp = TSocket::kROOTD;
3351  else if (server == "2" || server.BeginsWith("proof"))
3352  srvtyp = TSocket::kPROOFD;
3353  }
3354 
3355  // Line with host info directives
3356  TString user = "*";
3357 
3358  nxt = strtok(0," ");
3359  if (!strncmp(nxt,"user",4)) {
3360  nxt = strtok(0," ");
3361  if (strncmp(nxt,"list",4) && strncmp(nxt,"method",6)) {
3362  user = TString(nxt);
3363  nxt = strtok(0," ");
3364  }
3365  }
3366 
3367  // Get related THostAuth, if exists in the tmp list,
3368  TIter next(&tmpAuthInfo);
3369  THostAuth *ha;
3370  while ((ha = (THostAuth *)next())) {
3371  if (host == ha->GetHost() && user == ha->GetUser() &&
3372  srvtyp == ha->GetServer())
3373  break;
3374  }
3375  if (!ha) {
3376  // Create a new one
3377  ha = new THostAuth(host,srvtyp,user);
3378  tmpAuthInfo.Add(ha);
3379  }
3380 
3381  if (!strncmp(nxt,"list",4)) {
3382  // list of methods for {host,usr}
3383  Int_t nm = 0, me[kMAXSEC] = {0};
3384  char *mth = strtok(0," ");
3385  while (mth) {
3386  Int_t met = -1;
3387  if (strlen(mth) > 1) {
3388  // Method passed as string: translate it to number
3389  met = GetAuthMethodIdx(mth);
3390  if (met == -1 && gDebug > 2)
3391  ::Info("TAuthenticate::ReadRootAuthrc",
3392  "unrecognized method (%s): ", mth);
3393  } else {
3394  met = atoi(mth);
3395  }
3396  if (met > -1 && met < kMAXSEC)
3397  me[nm++] = met;
3398  mth = strtok(0," ");
3399  }
3400  if (nm)
3401  ha->ReOrder(nm,me);
3402 
3403  } else if (!strncmp(nxt,"method",6)) {
3404 
3405  // details for {host,usr,method}
3406  char *mth = strtok(0," ");
3407  Int_t met = -1;
3408  if (strlen(mth) > 1) {
3409  // Method passed as string: translate it to number
3410  met = GetAuthMethodIdx(mth);
3411  if (met == -1 && gDebug > 2)
3412  ::Info("TAuthenticate::ReadRootAuthrc",
3413  "unrecognized method (%s): ", mth);
3414  } else {
3415  met = atoi(mth);
3416  }
3417  if (met > -1 && met < kMAXSEC) {
3418  const char *det = 0;
3419  nxt = strtok(0," ");
3420  if (nxt) {
3421  det = (const char *)strstr(line,nxt);
3422  }
3423  if (ha->HasMethod(met))
3424  ha->SetDetails(met,det);
3425  else
3426  ha->AddMethod(met,det);
3427  }
3428  }
3429  }
3430  if (tmp) delete [] tmp;
3431  }
3432  // Close file and remove it if temporary
3433  fclose(fd);
3434  if (expand == 1)
3435  gSystem->Unlink(filetmp);
3436  // Cleanup allocated memory
3437  delete [] authrc;
3438 
3439  // Update authinfo with new info found
3440  TAuthenticate::MergeHostAuthList(authinfo,&tmpAuthInfo);
3441 
3442  // Print those left, if requested ...
3443  if (gDebug > 2)
3444  TAuthenticate::Show();
3445 
3446  // Now create the list of THostAuth to be sent over to
3447  // the Master/Slaves, if requested ...
3448  TList tmpproofauthinfo;
3449  if (proofserv.Length() > 0) {
3450  char *tmps = new char[proofserv.Length()+1];
3451  strlcpy(tmps,proofserv.Data(),proofserv.Length()+1);
3452  char *nxt = strtok(tmps," ");
3453  while (nxt) {
3454  TString tmp((const char *)nxt);
3455  Int_t pdd = -1;
3456  // host
3457  TString host;
3458  if ((pdd = tmp.Index(":")) == -1) {
3459  host = tmp;
3460  } else {
3461  host = tmp;
3462  host.Resize(pdd);
3463  if (!host.Length())
3464  host = "*";
3465  tmp.Remove(0,pdd+1);
3466  }
3467  // user
3468  TString user;
3469  if ((pdd = tmp.Index(":")) == -1) {
3470  user = tmp;
3471  } else {
3472  user = tmp;
3473  user.Resize(pdd);
3474  if (!user.Length())
3475  user = "*";
3476  tmp.Remove(0,pdd+1);
3477  }
3478  // method(s)
3479  TString meth;
3480  Int_t nm = 0, me[kMAXSEC] = {0}, met = -1;
3481  while (tmp.Length() > 0) {
3482  meth = tmp;
3483  if ((pdd = tmp.Index(":")) > -1)
3484  meth.Resize(pdd);
3485  if (meth.Length() > 1) {
3486  // Method passed as string: translate it to number
3487  met = GetAuthMethodIdx(meth.Data());
3488  if (met == -1 && gDebug > 2)
3489  ::Info("TAuthenticate::ReadRootAuthrc",
3490  "unrecognized method (%s): ",meth.Data());
3491  } else if (meth.Length() == 1) {
3492  met = atoi(meth.Data());
3493  if (met > -1 && met < kMAXSEC)
3494  me[nm++] = met;
3495  }
3496  if (pdd > -1)
3497  tmp.Remove(0,pdd+1);
3498  else
3499  tmp.Resize(0);
3500  }
3501 
3502  // Get related THostAuth, if exists, or create a new one
3503  THostAuth *ha = 0;
3504  THostAuth *hatmp = TAuthenticate::GetHostAuth(host,user);
3505  if (!hatmp) {
3506  ha = new THostAuth(host,user,nm,me,0);
3507  } else {
3508  // Create an empty THostAuth
3509  ha = new THostAuth(host,user);
3510  // Update with hatmp info
3511  ha->Update(hatmp);
3512  // ReOrder following new directives
3513  ha->ReOrder(nm,me);
3514  }
3515  // Add to the tmp list
3516  tmpproofauthinfo.Add(ha);
3517  // Go to next
3518  nxt = strtok(0," ");
3519  }
3520  delete [] tmps;
3521  }
3522 
3523  // Update proofauthinfo with new info found
3524  TAuthenticate::MergeHostAuthList(proofauthinfo,&tmpproofauthinfo,"P");
3525  // Print those, if requested ...
3526  if (gDebug > 2)
3527  TAuthenticate::Show("P");
3528 
3529  return authinfo->GetSize();
3530 }
3531 
3532 ////////////////////////////////////////////////////////////////////////////////
3533 /// Check if the authentication method can be attempted for the client.
3534 
3535 Bool_t TAuthenticate::CheckProofAuth(Int_t cSec, TString &out)
3536 {
3537  Bool_t rc = kFALSE;
3538  const char netrc[2][20] = { "/.netrc", "/.rootnetrc" };
3539  TString user;
3540 
3541  // Get user logon name
3542  UserGroup_t *pw = gSystem->GetUserInfo();
3543  if (pw) {
3544  user = TString(pw->fUser);
3545  delete pw;
3546  } else {
3547  ::Info("CheckProofAuth",
3548  "not properly logged on (getpwuid unable to find relevant info)!");
3549  out = "";
3550  return rc;
3551  }
3552 
3553  // UsrPwd
3554  if (cSec == (Int_t) TAuthenticate::kClear) {
3555  Int_t i = 0;
3556  for (; i < 2; i++) {
3557  TString infofile = TString(gSystem->HomeDirectory())+TString(netrc[i]);
3558  if (!gSystem->AccessPathName(infofile, kReadPermission))
3559  rc = kTRUE;
3560  }
3561  if (rc)
3562  out.Form("pt:0 ru:1 us:%s",user.Data());
3563  }
3564 
3565  if (gDebug > 3) {
3566  if (strlen(out) > 0)
3567  ::Info("CheckProofAuth",
3568  "meth: %d ... is available: details: %s", cSec, out.Data());
3569  else
3570  ::Info("CheckProofAuth",
3571  "meth: %d ... is NOT available", cSec);
3572  }
3573 
3574  // return
3575  return rc;
3576 }
3577 
3578 ////////////////////////////////////////////////////////////////////////////////
3579 /// Standard version of CheckSecCtx to be passed to TAuthenticate::AuthExists
3580 /// Check if User is matches the one in Ctx
3581 /// Returns: 1 if ok, 0 if not
3582 /// Deactivates Ctx is not valid
3583 
3584 Int_t StdCheckSecCtx(const char *user, TRootSecContext *ctx)
3585 {
3586  Int_t rc = 0;
3587 
3588  if (ctx->IsActive()) {
3589  if (!strcmp(user,ctx->GetUser()) &&
3590  strncmp("AFS", ctx->GetID(), 3))
3591  rc = 1;
3592  }
3593  return rc;
3594 }
3595 
3596 ////////////////////////////////////////////////////////////////////////////////
3597 /// Tool for updating fgAuthInfo or fgProofAuthInfo
3598 /// 'nin' contains list of last input information through (re)reading
3599 /// of a rootauthrc-alike file. 'nin' info has priority.
3600 /// 'std' is cleaned from inactive members.
3601 /// 'nin' members used to update existing members in 'std' are
3602 /// removed from 'nin', do that they do not leak
3603 /// opt = "P" for proofauthinfo.
3604 
3605 void TAuthenticate::MergeHostAuthList(TList *std, TList *nin, Option_t *opt)
3606 {
3607  // Remove inactive from the 'std'
3608  TIter nxstd(std);
3609  THostAuth *ha;
3610  while ((ha = (THostAuth *) nxstd())) {
3611  if (!ha->IsActive()) {
3612  std->Remove(ha);
3613  SafeDelete(ha);
3614  }
3615  }
3616 
3617  // Merge 'nin' info in 'std'
3618  TIter nxnew(nin);
3619  THostAuth *hanew;
3620  while ((hanew = (THostAuth *)nxnew())) {
3621  if (hanew->NumMethods()) {
3622  TString hostsrv;
3623  hostsrv.Form("%s:%d",hanew->GetHost(),hanew->GetServer());
3624  THostAuth *hastd =
3625  TAuthenticate::HasHostAuth(hostsrv,hanew->GetUser(),opt);
3626  if (hastd) {
3627  // Update with new info
3628  hastd->Update(hanew);
3629  // Flag for removal
3630  hanew->DeActivate();
3631  } else {
3632  // Add new ThostAuth to std
3633  std->Add(hanew);
3634  }
3635  } else
3636  // Flag for removal empty objects
3637  hanew->DeActivate();
3638  }
3639 
3640  // Cleanup memory before quitting
3641  nxnew.Reset();
3642  while ((hanew = (THostAuth *)nxnew())) {
3643  if (!hanew->IsActive()) {
3644  nin->Remove(hanew);
3645  SafeDelete(hanew);
3646  }
3647  }
3648 
3649 }
3650 
3651 ////////////////////////////////////////////////////////////////////////////////
3652 /// Tool for removing SecContext ctx from THostAuth listed in
3653 /// fgAuthInfo or fgProofAuthInfo
3654 
3655 void TAuthenticate::RemoveSecContext(TRootSecContext *ctx)
3656 {
3657  THostAuth *ha = 0;
3658 
3659  // authinfo first
3660  TIter nxai(GetAuthInfo());
3661  while ((ha = (THostAuth *)nxai())) {
3662  TIter next(ha->Established());
3663  TRootSecContext *lctx = 0;
3664  while ((lctx = (TRootSecContext *) next())) {
3665  if (lctx == ctx) {
3666  ha->Established()->Remove(ctx);
3667  break;
3668  }
3669  }
3670  }
3671 
3672  // proofauthinfo second
3673  TIter nxpa(GetProofAuthInfo());
3674  while ((ha = (THostAuth *)nxpa())) {
3675  TIter next(ha->Established());
3676  TRootSecContext *lctx = 0;
3677  while ((lctx = (TRootSecContext *) next())) {
3678  if (lctx == ctx) {
3679  ha->Established()->Remove(ctx);
3680  break;
3681  }
3682  }
3683  }
3684 
3685 }
3686 
3687 ////////////////////////////////////////////////////////////////////////////////
3688 /// Authentication related stuff setup in TProofServ.
3689 /// This is the place where the buffer send by the client / master is
3690 /// decoded. It contains also password information, if the case requires.
3691 /// Return 0 on success, -1 on failure.
3692 
3693 Int_t TAuthenticate::ProofAuthSetup()
3694 {
3695  static Bool_t done = kFALSE;
3696 
3697  // Only once
3698  if (done)
3699  return 0;
3700  done = kTRUE;
3701 
3702  // Localise the buffer and decode it
3703  const char *p = gSystem->Getenv("ROOTPROOFAUTHSETUP");
3704  if (!p) {
3705  if (gDebug > 2)
3706  Info("ProofAuthSetup","Buffer not found: nothing to do");
3707  return 0;
3708  }
3709  TString mbuf = TBase64::Decode(p);
3710 
3711  // Create the message
3712  TMessage *mess = new TMessage((void*)mbuf.Data(), mbuf.Length()+sizeof(UInt_t));
3713 
3714  // Extract the information
3715  TString user = "";
3716  TString passwd = "";
3717  Bool_t pwhash = kFALSE;
3718  Bool_t srppwd = kFALSE;
3719  Int_t rsakey = -1;
3720  *mess >> user >> passwd >> pwhash >> srppwd >> rsakey;
3721 
3722  // Set Globals for later use
3723  TAuthenticate::SetGlobalUser(user);
3724  TAuthenticate::SetGlobalPasswd(passwd);
3725  TAuthenticate::SetGlobalPwHash(pwhash);
3726  TAuthenticate::SetDefaultRSAKeyType(rsakey);
3727  const char *h = gSystem->Getenv("ROOTHOMEAUTHRC");
3728  if (h) {
3729  Bool_t rha = (Bool_t)(strtol(h, (char **)0, 10));
3730  TAuthenticate::SetReadHomeAuthrc(rha);
3731  }
3732 
3733  // Extract the list of THostAuth
3734  TList *pha = (TList *)mess->ReadObject(TList::Class());
3735  if (!pha) {
3736  if (gDebug > 0)
3737  Info("ProofAuthSetup","List of THostAuth not found");
3738  return 0;
3739  }
3740 
3741  Bool_t master = gROOT->IsProofServ();
3742  TIter next(pha);
3743  THostAuth *ha = 0;
3744  while ((ha = (THostAuth *)next())) {
3745 
3746  // Check if there is already one compatible
3747  Int_t kExact = 0;
3748  THostAuth *haex = 0;
3749  Bool_t fromProofAI = kFALSE;
3750  if (master) {
3751  // Look first in the proof list
3752  haex = TAuthenticate::GetHostAuth(ha->GetHost(),ha->GetUser(),"P",&kExact);
3753  // If nothing found, look also in the standard list
3754  if (!haex) {
3755  haex =
3756  TAuthenticate::GetHostAuth(ha->GetHost(),ha->GetUser(),"R",&kExact);
3757  } else
3758  fromProofAI = kTRUE;
3759  } else {
3760  // For slaves look first in the standard list only
3761  haex = TAuthenticate::GetHostAuth(ha->GetHost(),ha->GetUser(),"R",&kExact);
3762  }
3763 
3764  if (haex) {
3765  // If yes, action depends on whether it matches exactly or not
3766  if (kExact == 1) {
3767  // Update info in authinfo if Slave or in proofauthinfo
3768  // if Master and the entry was already in proofauthinfo
3769  if (!master || fromProofAI) {
3770  // update this existing one with the information found in
3771  // in the new one, if needed
3772  haex->Update(ha);
3773  // Delete temporary THostAuth
3774  SafeDelete(ha);
3775  } else
3776  // Master, entry not already in proofauthinfo,
3777  // Add it to the list
3778  TAuthenticate::GetProofAuthInfo()->Add(ha);
3779  } else {
3780  // update this new one with the information found in
3781  // in the existing one (if needed) and ...
3782  Int_t i = 0;
3783  for (; i < haex->NumMethods(); i++) {
3784  Int_t met = haex->GetMethod(i);
3785  if (!ha->HasMethod(met))
3786  ha->AddMethod(met,haex->GetDetails(met));
3787  }
3788  if (master)
3789  // ... add the new one to the list
3790  TAuthenticate::GetProofAuthInfo()->Add(ha);
3791  else
3792  // We add this one to the standard list
3793  TAuthenticate::GetAuthInfo()->Add(ha);
3794  }
3795  } else {
3796  if (master)
3797  // We add this one to the list for forwarding
3798  TAuthenticate::GetProofAuthInfo()->Add(ha);
3799  else
3800  // We add this one to the standard list
3801  TAuthenticate::GetAuthInfo()->Add(ha);
3802  }
3803  }
3804 
3805  // We are done
3806  return 0;
3807 }
3808 
3809 ////////////////////////////////////////////////////////////////////////////////
3810 /// Setup of authetication related stuff in PROOF run after a
3811 /// successful authentication.
3812 /// Return 0 on success, -1 on failure.
3813 
3814 Int_t TAuthenticate::ProofAuthSetup(TSocket *sock, Bool_t /* client */)
3815 {
3816  // Fill some useful info
3817  TSecContext *sc = sock->GetSecContext();
3818  TString user = sc->GetUser();
3819  Int_t remoteOffSet = sc->GetOffSet();
3820 
3821  // send user name to remote host
3822  // for UsrPwd method send also passwd, rsa encoded
3823  TMessage pubkey;
3824  TString passwd = "";
3825  Bool_t pwhash = kFALSE;
3826  Bool_t srppwd = kFALSE;
3827 
3828  Bool_t upwd = sc->IsA("UsrPwd");
3829 
3830  TPwdCtx *pwdctx = 0;
3831  if (remoteOffSet > -1 && upwd)
3832  pwdctx = (TPwdCtx *)(sc->GetContext());
3833 
3834  if (upwd && pwdctx) {
3835  passwd = pwdctx->GetPasswd();
3836  pwhash = pwdctx->IsPwHash();
3837  }
3838 
3839  Int_t keytyp = ((TRootSecContext *)sc)->GetRSAKey();
3840 
3841  // Prepare buffer
3842  TMessage mess;
3843  mess << user << passwd << pwhash << srppwd << keytyp;
3844 
3845  // Add THostAuth info
3846  mess.WriteObject(TAuthenticate::GetProofAuthInfo());
3847 
3848  // Get buffer as a base 64 string
3849  char *mbuf = mess.Buffer();
3850  Int_t mlen = mess.Length();
3851  TString messb64 = TBase64::Encode(mbuf, mlen);
3852 
3853  if (gDebug > 2)
3854  ::Info("ProofAuthSetup","sending %d bytes", messb64.Length());
3855 
3856  // Send it over
3857  if (remoteOffSet > -1) {
3858  if (TAuthenticate::SecureSend(sock, 1, keytyp, messb64.Data()) == -1) {
3859  ::Error("ProofAuthSetup","problems secure-sending message buffer");
3860  return -1;
3861  }
3862  } else {
3863  // There is no encryption key: send it plain
3864  char buflen[20];
3865  snprintf(buflen,20, "%d", messb64.Length());
3866  if (sock->Send(buflen, kMESS_ANY) < 0) {
3867  ::Error("ProofAuthSetup","plain: problems sending message length");
3868  return -1;
3869  }
3870  if (sock->SendRaw(messb64.Data(), messb64.Length()) < 0) {
3871  ::Error("ProofAuthSetup","problems sending message buffer");
3872  return -1;
3873  }
3874  }
3875 
3876  // We are done
3877  return 0;
3878 }
3879 
3880 ////////////////////////////////////////////////////////////////////////////////
3881 /// Static method returning supported client protocol.
3882 
3883 Int_t TAuthenticate::GetClientProtocol()
3884 {
3885  return TSocket::GetClientProtocol();
3886 }
3887 
3888 //
3889 // The code below is needed by TSlave and TProofServ for backward
3890 // compatibility.
3891 //
3892 
3893 ////////////////////////////////////////////////////////////////////////////////
3894 /// Sends the list of the relevant THostAuth objects to the master or
3895 /// to the active slaves, typically data servers external to the proof
3896 /// cluster. The list is of THostAuth to be sent is specified by
3897 /// TAuthenticate::fgProofAuthInfo after directives found in the
3898 /// .rootauthrc family files ('proofserv' key)
3899 /// Returns -1 if a problem sending THostAuth has occured, -2 in case
3900 /// of problems closing the transmission.
3901 
3902 static Int_t SendHostAuth(TSocket *s)
3903 {
3904  Int_t retval = 0, ns = 0;
3905 
3906  if (!s) {
3907  Error("SendHostAuth","invalid input: socket undefined");
3908  return -1;
3909  }
3910 
3911 
3912  TIter next(TAuthenticate::GetProofAuthInfo());
3913  THostAuth *ha;
3914  while ((ha = (THostAuth *)next())) {
3915  TString buf;
3916  ha->AsString(buf);
3917  if((ns = s->Send(buf, kPROOF_HOSTAUTH)) < 1) {
3918  retval = -1;
3919  break;
3920  }
3921  if (gDebug > 2)
3922  Info("SendHostAuth","sent %d bytes (%s)",ns,buf.Data());
3923  }
3924 
3925  // End of transmission ...
3926  if ((ns = s->Send("END", kPROOF_HOSTAUTH)) < 1)
3927  retval = -2;
3928  if (gDebug > 2)
3929  Info("SendHostAuth","sent %d bytes for closing",ns);
3930 
3931  return retval;
3932 }
3933 
3934 ////////////////////////////////////////////////////////////////////////////////
3935 /// Receive from client/master directives for authentications, create
3936 /// related THostAuth and add them to the TAuthenticate::ProofAuthInfo
3937 /// list. Opt = "M" or "m" if Master, "S" or "s" if Proof slave.
3938 /// The 'proofconf' file is read only if Master
3939 
3940 static Int_t RecvHostAuth(TSocket *s, Option_t *opt)
3941 {
3942  if (!s) {
3943  Error("RecvHostAuth","invalid input: socket undefined");
3944  return -1;
3945  }
3946 
3947  // Check if Master
3948  Bool_t master = !strncasecmp(opt,"M",1) ? kTRUE : kFALSE;
3949 
3950  // First read directives from <rootauthrc>, <proofconf> and alike files
3951  TAuthenticate::ReadRootAuthrc();
3952 
3953  // Receive buffer
3954  Int_t kind;
3955  char buf[kMAXSECBUF];
3956  Int_t nr = s->Recv(buf, kMAXSECBUF, kind);
3957  if (nr < 0 || kind != kPROOF_HOSTAUTH) {
3958  Error("RecvHostAuth", "received: kind: %d (%d bytes)", kind, nr);
3959  return -1;
3960  }
3961  if (gDebug > 2)
3962  Info("RecvHostAuth","received %d bytes (%s)",nr,buf);
3963 
3964  while (strcmp(buf, "END")) {
3965  // Clean buffer
3966  Int_t nc = (nr >= kMAXSECBUF) ? kMAXSECBUF - 1 : nr ;
3967  buf[nc] = '\0';
3968 
3969  // Create THostAuth
3970  THostAuth *ha = new THostAuth((const char *)&buf);
3971 
3972  // Check if there is already one compatible
3973  Int_t kExact = 0;
3974  THostAuth *haex = 0;
3975  Bool_t fromProofAI = kFALSE;
3976  if (master) {
3977  // Look first in the proof list
3978  haex = TAuthenticate::GetHostAuth(ha->GetHost(),ha->GetUser(),"P",&kExact);
3979  // If nothing found, look also in the standard list
3980  if (!haex) {
3981  haex =
3982  TAuthenticate::GetHostAuth(ha->GetHost(),ha->GetUser(),"R",&kExact);
3983  } else
3984  fromProofAI = kTRUE;
3985  } else {
3986  // For slaves look first in the standard list only
3987  haex = TAuthenticate::GetHostAuth(ha->GetHost(),ha->GetUser(),"R",&kExact);
3988  }
3989 
3990  if (haex) {
3991  // If yes, action depends on whether it matches exactly or not
3992  if (kExact == 1) {
3993  // Update info in authinfo if Slave or in proofauthinfo
3994  // if master and the entry was already in proofauthinfo
3995  if (!master || fromProofAI) {
3996  // update this existing one with the information found in
3997  // in the new one, if needed
3998  haex->Update(ha);
3999  // Delete temporary THostAuth
4000  SafeDelete(ha);
4001  } else
4002  // master, entry not already in proofauthinfo,
4003  // Add it to the list
4004  TAuthenticate::GetProofAuthInfo()->Add(ha);
4005  } else {
4006  // update this new one with the information found in
4007  // in the existing one (if needed) and ...
4008  Int_t i = 0;
4009  for (; i < haex->NumMethods(); i++) {
4010  Int_t met = haex->GetMethod(i);
4011  if (!ha->HasMethod(met))
4012  ha->AddMethod(met,haex->GetDetails(met));
4013  }
4014  if (master)
4015  // ... add the new one to the list
4016  TAuthenticate::GetProofAuthInfo()->Add(ha);
4017  else
4018  // We add this one to the standard list
4019  TAuthenticate::GetAuthInfo()->Add(ha);
4020  }
4021  } else {
4022  if (master)
4023  // We add this one to the list for forwarding
4024  TAuthenticate::GetProofAuthInfo()->Add(ha);
4025  else
4026  // We add this one to the standard list
4027  TAuthenticate::GetAuthInfo()->Add(ha);
4028  }
4029 
4030 
4031  // Get the next one
4032  nr = s->Recv(buf, kMAXSECBUF, kind);
4033  if (nr < 0 || kind != kPROOF_HOSTAUTH) {
4034  Info("RecvHostAuth","Error: received: kind: %d (%d bytes)", kind, nr);
4035  return -1;
4036  }
4037  if (gDebug > 2)
4038  Info("RecvHostAuth","received %d bytes (%s)",nr,buf);
4039  }
4040 
4041  return 0;
4042 }
4043 
4044 extern "C" {
4045 
4046 ////////////////////////////////////////////////////////////////////////////////
4047 /// Setup of authetication in PROOF run after successful opening
4048 /// of the socket. Provided for backward compatibility.
4049 /// Return 0 on success, -1 on failure.
4050 
4051 Int_t OldSlaveAuthSetup(TSocket *sock,
4052  Bool_t /* master */, TString ord, TString conf)
4053 {
4054 
4055  // Fill some useful info
4056  TSecContext *sc = sock->GetSecContext();
4057  TString user = sc->GetUser();
4058  Int_t proofdProto = sock->GetRemoteProtocol();
4059  Int_t remoteOffSet = sc->GetOffSet();
4060 
4061  // send user name to remote host
4062  // for UsrPwd method send also passwd, rsa encoded
4063  TMessage pubkey;
4064  TString passwd = "";
4065  Bool_t pwhash = kFALSE;
4066  Bool_t srppwd = kFALSE;
4067 
4068  Bool_t upwd = sc->IsA("UsrPwd");
4069 
4070  TPwdCtx *pwdctx = 0;
4071  if (remoteOffSet > -1 && upwd)
4072  pwdctx = (TPwdCtx *)(sc->GetContext());
4073 
4074  if (upwd && pwdctx) {
4075 
4076  // Send offset to identify remotely the public part of RSA key
4077  if (sock->Send(remoteOffSet, kROOTD_RSAKEY) != 2*sizeof(Int_t)) {
4078  Error("OldAuthSetup", "failed to send offset in RSA key");
4079  return -1;
4080  }
4081 
4082  if (pwdctx) {
4083  passwd = pwdctx->GetPasswd();
4084  pwhash = pwdctx->IsPwHash();
4085  }
4086 
4087  Int_t keytyp = ((TRootSecContext *)sc)->GetRSAKey();
4088  if (TAuthenticate::SecureSend(sock, 1, keytyp, passwd.Data()) == -1) {
4089  if (remoteOffSet > -1)
4090  Warning("OldAuthSetup","problems secure-sending pass hash %s",
4091  "- may result in failures");
4092  // If non RSA encoding available try passwd inversion
4093  if (upwd) {
4094  for (int i = 0; i < passwd.Length(); i++) {
4095  char inv = ~passwd(i);
4096  passwd.Replace(i, 1, inv);
4097  }
4098  TMessage mess;
4099  mess << passwd;
4100  if (sock->Send(mess) < 0) {
4101  Error("OldAuthSetup", "failed to send inverted password");
4102  return -1;
4103  }
4104  }
4105  }
4106 
4107  } else {
4108 
4109  // Send notification of no offset to be sent ...
4110  if (sock->Send(-2, kROOTD_RSAKEY) != 2*sizeof(Int_t)) {
4111  Error("OldAuthSetup", "failed to send no offset notification in RSA key");
4112  return -1;
4113  }
4114  }
4115 
4116  // Send ordinal (and config) info to slave (or master)
4117  TMessage mess;
4118  mess << user << pwhash << srppwd << ord << conf;
4119 
4120  if (sock->Send(mess) < 0) {
4121  Error("OldAuthSetup", "failed to send ordinal and config info");
4122  return -1;
4123  }
4124 
4125  if (proofdProto > 6) {
4126  // Now we send authentication details to access, e.g., data servers
4127  // not in the proof cluster and to be propagated to slaves.
4128  // This is triggered by the 'proofserv <dserv1> <dserv2> ...'
4129  // line in .rootauthrc
4130  if (SendHostAuth(sock) < 0) {
4131  Error("OldAuthSetup", "failed to send HostAuth info");
4132  return -1;
4133  }
4134  }
4135 
4136  // We are done
4137  return 0;
4138 }
4139 
4140 ////////////////////////////////////////////////////////////////////////////////
4141 /// Authentication related setup in TProofServ run after successful
4142 /// startup. Provided for backward compatibility.
4143 /// Return 0 on success, -1 on failure.
4144 
4145 Int_t OldProofServAuthSetup(TSocket *sock, Bool_t master, Int_t protocol,
4146  TString &user, TString &ord, TString &conf)
4147 {
4148  // First receive, decode and store the public part of RSA key
4149  Int_t retval, kind;
4150  if (sock->Recv(retval, kind) != 2*sizeof(Int_t)) {
4151  //other side has closed connection
4152  Info("OldProofServAuthSetup",
4153  "socket has been closed due to protocol mismatch - Exiting");
4154  return -1;
4155  }
4156 
4157  Int_t rsakey = 0;
4158  TString passwd;
4159  if (kind == kROOTD_RSAKEY) {
4160 
4161  if (retval > -1) {
4162  if (gSystem->Getenv("ROOTKEYFILE")) {
4163 
4164  TString keyfile = gSystem->Getenv("ROOTKEYFILE");
4165  keyfile += retval;
4166 
4167  FILE *fKey = 0;
4168  char pubkey[kMAXPATHLEN] = { 0 };
4169  if (!gSystem->AccessPathName(keyfile.Data(), kReadPermission)) {
4170  if ((fKey = fopen(keyfile.Data(), "r"))) {
4171  Int_t klen = fread((void *)pubkey,1,sizeof(pubkey),fKey);
4172  if (klen <= 0) {
4173  Error("OldProofServAuthSetup",
4174  "failed to read public key from '%s'", keyfile.Data());
4175  fclose(fKey);
4176  return -1;
4177  }
4178  pubkey[klen] = 0;
4179  // Set RSA key
4180  rsakey = TAuthenticate::SetRSAPublic(pubkey,klen);
4181  fclose(fKey);
4182  } else {
4183  Error("OldProofServAuthSetup", "failed to open '%s'", keyfile.Data());
4184  return -1;
4185  }
4186  }
4187  }
4188 
4189  // Receive passwd
4190  char *pwd = 0;
4191  if (TAuthenticate::SecureRecv(sock, 2, rsakey, &pwd) < 0) {
4192  Error("OldProofServAuthSetup", "failed to receive password");
4193  return -1;
4194  }
4195  passwd = pwd;
4196  delete[] pwd;
4197 
4198  } else if (retval == -1) {
4199 
4200  // Receive inverted passwd
4201  TMessage *mess;
4202  if ((sock->Recv(mess) <= 0) || !mess) {
4203  Error("OldProofServAuthSetup", "failed to receive inverted password");
4204  return -1;
4205  }
4206  (*mess) >> passwd;
4207  delete mess;
4208 
4209  for (Int_t i = 0; i < passwd.Length(); i++) {
4210  char inv = ~passwd(i);
4211  passwd.Replace(i, 1, inv);
4212  }
4213 
4214  }
4215  }
4216 
4217  // Receive final information
4218  TMessage *mess;
4219  if ((sock->Recv(mess) <= 0) || !mess) {
4220  Error("OldProofServAuthSetup", "failed to receive ordinal and config info");
4221  return -1;
4222  }
4223 
4224  // Decode it
4225  Bool_t pwhash, srppwd;
4226  if (master) {
4227  if (protocol < 4) {
4228  (*mess) >> user >> pwhash >> srppwd >> conf;
4229  ord = "0";
4230  } else {
4231  (*mess) >> user >> pwhash >> srppwd >> ord >> conf;
4232  }
4233  } else {
4234  if (protocol < 4) {
4235  Int_t iord;
4236  (*mess) >> user >> pwhash >> srppwd >> iord;
4237  ord = "0.";
4238  ord += iord;
4239  } else {
4240  (*mess) >> user >> pwhash >> srppwd >> ord >> conf;
4241  }
4242  }
4243  delete mess;
4244 
4245  // Set Globals for later use
4246  TAuthenticate::SetGlobalUser(user);
4247  TAuthenticate::SetGlobalPasswd(passwd);
4248  TAuthenticate::SetGlobalPwHash(pwhash);
4249  TAuthenticate::SetDefaultRSAKeyType(rsakey);
4250  const char *h = gSystem->Getenv("ROOTHOMEAUTHRC");
4251  if (h) {
4252  Bool_t rha = (Bool_t)(strtol(h, (char **)0, 10));
4253  TAuthenticate::SetReadHomeAuthrc(rha);
4254  }
4255 
4256  // Read user or system authentication directives and
4257  // receive auth info transmitted from the client
4258  Int_t harc = master ? RecvHostAuth(sock, "M") : RecvHostAuth(sock, "S");
4259 
4260  if (harc < 0) {
4261  Error("OldProofServAuthSetup", "failed to receive HostAuth info");
4262  return -1;
4263  }
4264 
4265  // We are done
4266  return 0;
4267 }
4268 
4269 } // extern "C"