// @(#)root/net:$Name:  $:$Id: TAuthenticate.cxx,v 1.9 2002/03/20 18:47:30 rdm Exp $
// Author: Fons Rademakers   26/11/2000

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

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

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

#ifndef R__LYNXOS
#include <sys/stat.h>
#endif
#include <errno.h>

#include "TAuthenticate.h"
#include "TNetFile.h"
#include "TSocket.h"
#include "TSystem.h"
#include "TError.h"
#include "Getline.h"


TString      TAuthenticate::fgUser;
TString      TAuthenticate::fgPasswd;
SecureAuth_t TAuthenticate::fgSecAuthHook;
Krb5Auth_t   TAuthenticate::fgKrb5AuthHook;


ClassImp(TAuthenticate)

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

   fSocket   = sock;
   fRemote   = remote;
   fProtocol = proto;
   fSecurity = (ESecurity) security;
}

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

   Bool_t result = kFALSE;

   // if not anonymous login try to use kerberos5 authentication
   if (fSecurity == kKrb5 && fUser != "anonymous" && fUser != "rootd") {
      if (!fgKrb5AuthHook) {
         char *p;
#ifdef ROOTLIBDIR
         TString lib = TString(ROOTLIBDIR) + "/libKrb5Auth";
#else
         TString lib = TString(gRootDir) + "/lib/libKrb5Auth";
#endif
         if ((p = gSystem->DynamicPathName(lib, kTRUE))) {
            delete [] p;
            gSystem->Load(lib);
         }
      }
      if (fgKrb5AuthHook) {
         Int_t st = (*fgKrb5AuthHook)(fSocket, fUser);
         if (st == 0)
            return kFALSE;
         if (st == 1)
            return kTRUE;
         if (st == 2) {
            Warning("Authenticate", "remote %s does not support kerberos5 authentication",
                    fProtocol.Data());
            return kFALSE;
         }
      } else {
         Error("Authenticate", "no support for kerberos5 authentication available");
         return kFALSE;
      }
   }

   TString user;
   TString passwd;

   // Get user and passwd set via static functions SetUser and SetPasswd.
   if (fgUser != "")
      user = fgUser;
   if (fgPasswd != "")
      passwd = fgPasswd;

   // Check ~/.rootnetrc and ~/.netrc files if user was not set via
   // the static SetUser() method.
   if (user == "")
      CheckNetrc(user, passwd);

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

   fUser   = user;
   fPasswd = passwd;

   // if not anonymous login try to use secure authentication
   if (fSecurity == kSRP && fUser != "anonymous" && fUser != "rootd") {
      if (!fgSecAuthHook) {
         char *p;
#ifdef ROOTLIBDIR
         TString lib = TString(ROOTLIBDIR) + "/libSRPAuth";
#else
         TString lib = TString(gRootDir) + "/lib/libSRPAuth";
#endif
         if ((p = gSystem->DynamicPathName(lib, kTRUE))) {
            delete [] p;
            gSystem->Load(lib);
         }
      }
      if (fgSecAuthHook) {
         Int_t st = (*fgSecAuthHook)(fSocket, user, passwd, fRemote);
         if (st == 0)
            return kFALSE;
         if (st == 1)
            return kTRUE;
         if (st == 2) {
            Warning("Authenticate", "remote %s does not support secure authentication",
                    fProtocol.Data());
            return kFALSE;
         }
      } else {
         Error("Authenticate", "no support for secure authentication available");
         return kFALSE;
      }
   }

   fSocket->Send(user, kROOTD_USER);

   Int_t stat, kind;

   fSocket->Recv(stat, kind);

   if (kind == kROOTD_ERR) {
      AuthError("Authenticate", stat);
      return result;
   }
   if (kind == kROOTD_AUTH && stat == 1) {
      result = kTRUE;
      return result;
   }

badpass:
   if (passwd == "") {
      passwd = PromptPasswd();
      if (passwd == "")
         Error("Authenticate", "password not set");
   }

   if (fUser == "anonymous" || fUser == "rootd") {
      if (!passwd.Contains("@")) {
         Warning("Authenticate", "please use passwd of form: user@host.do.main");
         passwd = "";
         goto badpass;
      }
   }

   fPasswd = passwd;

   if (passwd != "") {
      for (int i = 0; i < passwd.Length(); i++) {
         char inv = ~passwd(i);
         passwd.Replace(i, 1, inv);
      }
   }

   fSocket->Send(passwd, kROOTD_PASS);

   fSocket->Recv(stat, kind);
   if (kind == kROOTD_ERR)
      AuthError("Authenticate", stat);
   if (kind == kROOTD_AUTH && stat == 1)
      result = kTRUE;

   return result;
}

//______________________________________________________________________________
 Bool_t TAuthenticate::CheckNetrc(TString &user, TString &passwd)
{
   // Try to get user name and passwd from the ~/.rootnetrc or
   // ~/.netrc files. First ~/.rootnetrc is tried, after that ~/.netrc.
   // These files will only be used when their access masks are 0600.
   // Returns kTRUE if user and passwd were found for the machine
   // specified in the URL. If kFALSE, user and passwd are "".
   // The format of these files are:
   //
   // # this is a comment line
   // machine <machine fqdn> login <user> password <passwd>
   //
   // and in addition ~/.rootnetrc also supports:
   //
   // secure <machine fqdn> login <user> password <passwd>
   //
   // for the secure protocols. All lines must start in the first column.

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

   user = passwd = "";

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

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

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

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

   return result;
}

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

   return fgUser;
}

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

   return fgPasswd;
}

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

   const char *user = gSystem->Getenv("USER");
#ifdef R__WIN32
   if (!user)
      user = gSystem->Getenv("USERNAME");
#endif
   char *usr = Getline(Form("Name (%s:%s): ", remote, user));
   if (usr[0]) {
      usr[strlen(usr)-1] = 0;   // get rid of \n
      if (strlen(usr))
         return StrDup(usr);
      else
         return StrDup(user);
   }
   return 0;
}

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

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

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

   ::Error(where, gRootdErrStr[err]);
}

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

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

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

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

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

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

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

   fgSecAuthHook = func;
}

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

   fgKrb5AuthHook = func;
}


ROOT page - Class index - Top of the page

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