DaemonUtils.cxx

Go to the documentation of this file.
00001 // @(#)root/auth:$Id: DaemonUtils.cxx 36126 2010-10-06 15:14:52Z ganis $
00002 // Author: Gerri Ganis   19/1/2004
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2003, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // DaemonUtils                                                          //
00015 //                                                                      //
00016 // This file defines wrappers to client utils calls used by server      //
00017 // authentication daemons                                               //
00018 //                                                                      //
00019 //////////////////////////////////////////////////////////////////////////
00020 
00021 #include <stdio.h>
00022 #include <string.h>
00023 #include <stdlib.h>
00024 #include <unistd.h>
00025 #include <signal.h>
00026 #include <sys/socket.h>
00027 #include <netinet/in.h>
00028 #include <netinet/tcp.h>
00029 #include <arpa/inet.h>
00030 #include <netdb.h>
00031 #include <errno.h>
00032 
00033 #if defined(linux)
00034 #   include <features.h>
00035 #   if __GNU_LIBRARY__ == 6
00036 #      ifndef R__GLIBC
00037 #         define R__GLIBC
00038 #      endif
00039 #   endif
00040 #endif
00041 #if defined(__MACH__) && !defined(__APPLE__)
00042 #   define R__GLIBC
00043 #endif
00044 
00045 #ifdef __sun
00046 #   ifndef _REENTRANT
00047 #      if __SUNPRO_CC > 0x420
00048 #         define GLOBAL_ERRNO
00049 #      endif
00050 #   endif
00051 #endif
00052 
00053 #include "Rtypes.h"
00054 #include "Varargs.h"
00055 #include "DaemonUtils.h"
00056 #include "TAuthenticate.h"
00057 #include "TSecContext.h"
00058 #include "TEnv.h"
00059 #include "TROOT.h"
00060 
00061 //________________________________________________________________________
00062 
00063 // --- Globals --------------------------------------------------------
00064 static TSocket *gSocket;
00065 
00066 // This is to be changed whenever something is changed
00067 // in non-backward compatible way
00068 // 0 -> 1: support for SSH authentication via SSH tunnel
00069 static Int_t gSrvProtocol = 1;
00070 static EService gService = kSOCKD;
00071 static Int_t gReuseAllow = 0x1F;
00072 
00073 using namespace std;
00074 using namespace ROOT;
00075 
00076 extern "C" {
00077    Int_t SrvAuthenticate(TSocket *socket,
00078                          const char *confdir, const char *tmpdir,
00079                          string &user, Int_t &meth, Int_t &type, string &ctkn,
00080                          TSeqCollection *secctxlist) {
00081       return SrvAuthImpl(socket, confdir, tmpdir, user, meth, type, ctkn, secctxlist);
00082    }
00083 }
00084 
00085 extern "C" {
00086    Int_t SrvAuthCleanup(TSeqCollection *sls) {
00087       return SrvClupImpl(sls);
00088    }
00089 }
00090 
00091 //__________________________________________________________________
00092 static Int_t SrvSetVars(string confdir)
00093 {
00094    // Set relevant environment variables
00095 
00096    // Executables and conf dirs
00097 
00098    string execdir, etcdir;
00099 #ifdef ROOTBINDIR
00100    execdir = string(ROOTBINDIR);
00101 #endif
00102 #ifdef ROOTETCDIR
00103    etcdir = string(ROOTETCDIR);
00104 #endif
00105 
00106    // Define rootbindir if not done already
00107    if (!execdir.length())
00108       execdir = string(confdir).append("/bin");
00109    // Make it available to all the session via env
00110    if (execdir.length()) {
00111       int len = 15 + execdir.length();
00112       char *tmp = new char[len+1];
00113       if (tmp) {
00114          snprintf(tmp,len+1, "ROOTBINDIR=%.*s", len, execdir.c_str());
00115          putenv(tmp);
00116       } else
00117          return -1;
00118    }
00119 
00120    // Define rootetcdir if not done already
00121    if (!etcdir.length())
00122       etcdir = string(confdir).append("/etc");
00123    // Make it available to all the session via env
00124    if (etcdir.length()) {
00125       int len = 15 + etcdir.length();
00126       char *tmp = new char[len+1];
00127       if (tmp) {
00128          snprintf(tmp, len+1, "ROOTETCDIR=%.*s", len, etcdir.c_str());
00129          putenv(tmp);
00130       } else
00131          return -1;
00132    }
00133 
00134    // If specified, set the special daemonrc file to be used
00135    string daemonrc = string(gEnv->GetValue("SrvAuth.DaemonRc",""));
00136    if (daemonrc.length()) {
00137       int len = 15 + daemonrc.length();
00138       char *tmp = new char[len+1];
00139       if (tmp) {
00140          snprintf(tmp, len+1, "ROOTDAEMONRC=%.*s", len, daemonrc.c_str());
00141          putenv(tmp);
00142       } else
00143          return -1;
00144    }
00145 
00146    // If specified, set the special gridmap file to be used
00147    string gridmap = string(gEnv->GetValue("SrvAuth.GridMap",""));
00148    if (gridmap.length()) {
00149       int len = 15 + gridmap.length();
00150       char *tmp = new char[len+1];
00151       if (tmp) {
00152          snprintf(tmp, len+1, "GRIDMAP=%.*s", len, gridmap.c_str());
00153          putenv(tmp);
00154       } else
00155          return -1;
00156    }
00157 
00158    // If specified, set the special hostcert.conf file to be used
00159    string hcconf = string(gEnv->GetValue("SrvAuth.HostCert",""));
00160    if (hcconf.length()) {
00161       int len = 15 + hcconf.length();
00162       char *tmp = new char[len+1];
00163       if (tmp) {
00164          snprintf(tmp, len+1, "ROOTHOSTCERT=%.*s", len, hcconf.c_str());
00165          putenv(tmp);
00166       } else
00167          return -1;
00168    }
00169 
00170    return 0;
00171 }
00172 
00173 
00174 //______________________________________________________________________________
00175 void Err(int level, const char *msg, int size)
00176 {
00177    Perror((char *)msg, size);
00178    if (level > -1) NetSend(level, kROOTD_ERR);
00179 }
00180 
00181 //______________________________________________________________________________
00182 void ErrFatal(int level, const char *msg, int size)
00183 {
00184    Perror((char *)msg, size);
00185    if (level > -1) NetSend(msg, kMESS_STRING);
00186 }
00187 
00188 //______________________________________________________________________________
00189 void ErrSys(int level, const char *msg, int size)
00190 {
00191    Perror((char *)msg, size);
00192    ErrFatal(level, msg, size);
00193 }
00194 
00195 //______________________________________________________________________________
00196 Int_t SrvClupImpl(TSeqCollection *secls)
00197 {
00198    // Wrapper to cleanup code
00199    TIter next(secls);
00200    TSecContext *nsc ;
00201    while ((nsc = (TSecContext *)next())) {
00202       if (!strncmp(nsc->GetID(),"server",6)) {
00203          int rc = RpdCleanupAuthTab(nsc->GetToken());
00204          if (gDebug > 0 && rc < 0)
00205             ErrorInfo("SrvClupImpl: operation unsuccessful (rc: %d, ctkn: %s)",
00206                       rc, nsc->GetToken());
00207       }
00208    }
00209    return 0;
00210 }
00211 
00212 //______________________________________________________________________________
00213 Int_t SrvAuthImpl(TSocket *socket, const char *confdir, const char *tmpdir,
00214                   string &user, Int_t &meth, Int_t &type, string &ctoken,
00215                   TSeqCollection *secctxlist)
00216 {
00217    // Server authentication code.
00218    // Returns 0 in case authentication failed
00219    //         1 in case of success
00220    // On success, returns authenticated username in user
00221    Int_t rc = 0;
00222 
00223    // Check if hosts equivalence is required
00224    Bool_t hequiv = gEnv->GetValue("SrvAuth.CheckHostsEquivalence",0);
00225 
00226    // Pass file for SRP
00227    string altSRPpass = string(gEnv->GetValue("SrvAuth.SRPpassfile",""));
00228 
00229    // Port for the SSH daemon
00230    Int_t sshdport = gEnv->GetValue("SrvAuth.SshdPort",22);
00231 
00232    // Set envs
00233    if (SrvSetVars(string(confdir)) == -1)
00234       // Problems setting environment
00235       return rc;
00236 
00237    // Parent ID
00238    int parentid = getpid(); // Process identifier
00239 
00240    // default job options
00241    unsigned int options = kDMN_RQAUTH | kDMN_HOSTEQ;
00242    if (!hequiv)
00243       options &= ~kDMN_HOSTEQ;
00244 
00245    // Init error handlers
00246    RpdSetErrorHandler(Err, ErrSys, ErrFatal);
00247 
00248    // Init daemon code
00249    RpdInit(gService, parentid, gSrvProtocol, options,
00250            gReuseAllow, sshdport,
00251            tmpdir, altSRPpass.c_str());
00252 
00253    // Generate Local RSA keys for the session
00254    if (RpdGenRSAKeys(0))
00255       // Problems generating keys
00256       return rc;
00257 
00258    // Reset check of the available method list
00259    RpdSetMethInitFlag(0);
00260 
00261    // Trasmit relevant socket details
00262    SrvSetSocket(socket);
00263 
00264    // Init Session (get protocol, run authentication, ...)
00265    // type of authentication:
00266    //    0 (new), 1 (existing), 2 (updated offset)
00267    int clientprotocol = 0;
00268    rc = RpdInitSession(gService, user, clientprotocol, meth, type, ctoken);
00269 
00270    TSecContext *seccontext = 0;
00271    if (rc > 0) {
00272       string openhost(socket->GetInetAddress().GetHostName());
00273 
00274       if (type == 1) {
00275          // An existing authentication has been re-used: retrieve
00276          // the related security context
00277          TIter next(gROOT->GetListOfSecContexts());
00278          while ((seccontext = (TSecContext *)next())) {
00279             if (!(strncmp(seccontext->GetID(),"server",6))) {
00280                if (seccontext->GetMethod() == meth) {
00281                   if (!strcmp(openhost.c_str(),seccontext->GetHost())) {
00282                      if (!strcmp(user.c_str(),seccontext->GetUser()))
00283                         break;
00284                   }
00285                }
00286             }
00287          }
00288       }
00289 
00290       if (!seccontext) {
00291          // New authentication: Fill a SecContext for cleanup
00292          // in case of interrupt
00293          seccontext = new TSecContext(user.c_str(), openhost.c_str(), meth, -1,
00294                                       "server", ctoken.c_str());
00295          if (seccontext) {
00296             // Add to the list
00297             secctxlist->Add(seccontext);
00298             // Store SecContext
00299             socket->SetSecContext(seccontext);
00300          } else {
00301             if (gDebug > 0)
00302                ErrorInfo("SrvAuthImpl: could not create sec context object"
00303                          ": potential problems in cleaning");
00304          }
00305       }
00306    }
00307 
00308 
00309    // Done
00310    return rc;
00311 }
00312 
00313 
00314 namespace ROOT {
00315 
00316    static int gSockFd = -1;
00317 
00318 //______________________________________________________________________________
00319    void SrvSetSocket(TSocket *Socket)
00320    {
00321       // Fill socket parameters
00322 
00323       gSocket = Socket;
00324       gSockFd = Socket->GetDescriptor();
00325    }
00326 
00327 //______________________________________________________________________________
00328    static int Recvn(int sock, void *buffer, int length)
00329    {
00330       // Receive exactly length bytes into buffer. Returns number of bytes
00331       // received. Returns -1 in case of error.
00332 
00333       if (sock < 0) return -1;
00334 
00335       int n, nrecv = 0;
00336       char *buf = (char *)buffer;
00337 
00338       for (n = 0; n < length; n += nrecv) {
00339          while ((nrecv = recv(sock, buf+n, length-n, 0)) == -1
00340                 && GetErrno() == EINTR)
00341             ResetErrno();   // probably a SIGCLD that was caught
00342          if (nrecv < 0) {
00343             Error(gErrFatal,-1,
00344                   "Recvn: error (sock: %d): errno: %d",sock,GetErrno());
00345             return nrecv;
00346          } else if (nrecv == 0)
00347             break;         // EOF
00348       }
00349 
00350       return n;
00351    }
00352 
00353 //________________________________________________________________________
00354    void NetClose()
00355    {
00356       // Empty call, for consistency
00357       return;
00358    }
00359 
00360 //______________________________________________________________________________
00361    int NetGetSockFd()
00362    {
00363       // return open socket descriptor
00364       return gSockFd;
00365    }
00366 
00367 //________________________________________________________________________
00368    int NetParOpen(int port, int size)
00369    {
00370       // Empty call, for consistency
00371       if (port+size)
00372          return (port+size);
00373       else
00374          return 1;
00375    }
00376 
00377 //________________________________________________________________________
00378    int NetRecv(char *msg, int max)
00379    {
00380       // Receive a string of maximum length max.
00381 
00382       return gSocket->Recv(msg, max);
00383    }
00384 
00385 //________________________________________________________________________
00386    int NetRecv(char *msg, int len, EMessageTypes &kind)
00387    {
00388       // Receive a string of maximum len length. Returns message type in kind.
00389       // Return value is msg length.
00390 
00391       Int_t tmpkind;
00392       Int_t rc = gSocket->Recv(msg, len, tmpkind);
00393       kind = (EMessageTypes)tmpkind;
00394       return rc;
00395    }
00396 
00397 //________________________________________________________________________
00398    int NetRecv(void *&buf, int &len, EMessageTypes &kind)
00399    {
00400       // Receive a buffer. Returns the newly allocated buffer, the length
00401       // of the buffer and message type in kind.
00402 
00403       int hdr[2];
00404 
00405       if (NetRecvRaw(hdr, sizeof(hdr)) < 0)
00406          return -1;
00407 
00408       len = ntohl(hdr[0]) - sizeof(int);
00409       kind = (EMessageTypes) ntohl(hdr[1]);
00410       if (len) {
00411          buf = new char* [len];
00412          return NetRecvRaw(buf, len);
00413       }
00414       buf = 0;
00415       return 0;
00416 
00417    }
00418 
00419 //________________________________________________________________________
00420    int NetRecvRaw(void *buf, int len)
00421    {
00422       // Receive a buffer of maximum len bytes.
00423 
00424       return gSocket->RecvRaw(buf,len);
00425    }
00426 
00427 //________________________________________________________________________
00428    int NetRecvRaw(int sock, void *buf, int len)
00429    {
00430       // Receive a buffer of maximum len bytes from generic socket sock.
00431 
00432       if (sock == -1) return -1;
00433 
00434       if (Recvn(sock, buf, len) < 0) {
00435          Error(gErrFatal,-1,
00436                "NetRecvRaw: Recvn error (sock: %d, errno: %d)",sock,GetErrno());
00437       }
00438 
00439       return len;
00440    }
00441 
00442 //________________________________________________________________________
00443    int NetSend(int code, EMessageTypes kind)
00444    {
00445       // Send integer. Message will be of type "kind".
00446 
00447       int hdr[3];
00448       int hlen = sizeof(int) + sizeof(int);
00449       hdr[0] = htonl(hlen);
00450       hdr[1] = htonl(kind);
00451       hdr[2] = htonl(code);
00452 
00453       return gSocket->SendRaw(hdr, sizeof(hdr));
00454    }
00455 
00456 //________________________________________________________________________
00457    int NetSend(const char *msg, EMessageTypes kind)
00458    {
00459       // Send a string. Message will be of type "kind".
00460 
00461       return gSocket->Send(msg, kind);
00462    }
00463 
00464 //________________________________________________________________________
00465    int NetSend(const void *buf, int len, EMessageTypes kind)
00466    {
00467       // Send buffer of len bytes. Message will be of type "kind".
00468 
00469       int hdr[2];
00470       int hlen = sizeof(int) + len;
00471       hdr[0] = htonl(hlen);
00472       hdr[1] = htonl(kind);
00473       if (gSocket->SendRaw(hdr, sizeof(hdr)) < 0)
00474          return -1;
00475 
00476       return gSocket->SendRaw(buf, len);
00477    }
00478 
00479 //________________________________________________________________________
00480    int NetSendAck()
00481    {
00482       // Send acknowledge code
00483 
00484       return NetSend(0, kROOTD_ACK);
00485    }
00486 
00487 //________________________________________________________________________
00488    int NetSendError(ERootdErrors err)
00489    {
00490       // Send error code
00491 
00492       return NetSend(err, kROOTD_ERR);
00493    }
00494 
00495 //________________________________________________________________________
00496    int NetSendRaw(const void *buf, int len)
00497    {
00498       // Send buffer of len bytes.
00499 
00500       return gSocket->SendRaw(buf, len);
00501    }
00502 
00503 //______________________________________________________________________________
00504    void NetGetRemoteHost(std::string &openhost)
00505    {
00506       // Return name of connected host
00507 
00508       // Get Host name
00509       openhost = string(gSocket->GetInetAddress().GetHostName());
00510    }
00511 
00512 //________________________________________________________________________
00513    int GetErrno()
00514    {
00515       // return errno
00516 #ifdef GLOBAL_ERRNO
00517       return ::errno;
00518 #else
00519       return errno;
00520 #endif
00521    }
00522 //________________________________________________________________________
00523    void ResetErrno()
00524    {
00525       // reset errno
00526 #ifdef GLOBAL_ERRNO
00527       ::errno = 0;
00528 #else
00529       errno = 0;
00530 #endif
00531    }
00532 
00533 //______________________________________________________________________________
00534    void Perror(char *buf, int size)
00535    {
00536       // Return in buf the message belonging to errno.
00537 
00538       int len = strlen(buf);
00539 #if (defined(__sun) && defined (__SVR4)) || defined (__linux) || \
00540    defined(_AIX) || defined(__MACH__)
00541       snprintf(buf+len, size, " (%s)", strerror(GetErrno()));
00542 #else
00543       if (GetErrno() >= 0 && GetErrno() < sys_nerr)
00544          snprintf(buf+len, size, " (%s)", sys_errlist[GetErrno()]);
00545 #endif
00546    }
00547 
00548 //________________________________________________________________________
00549    void ErrorInfo(const char *va_(fmt), ...)
00550    {
00551       // Formats a string in a circular formatting buffer and prints the string.
00552       // Appends a newline.
00553       // Cut & Paste from Printf in base/src/TString.cxx
00554 
00555       char    buf[1024];
00556       va_list ap;
00557       va_start(ap,va_(fmt));
00558       vsprintf(buf, fmt, ap);
00559       va_end(ap);
00560       printf("%s\n", buf);
00561       fflush(stdout);
00562    }
00563 
00564 //________________________________________________________________________
00565    void Error(ErrorHandler_t func,int code,const char *va_(fmt), ...)
00566    {
00567       // Write error message and call a handler, if required
00568 
00569       char    buf[1024];
00570       va_list ap;
00571       va_start(ap,va_(fmt));
00572       vsprintf(buf, fmt, ap);
00573       va_end(ap);
00574       printf("%s\n", buf);
00575       fflush(stdout);
00576 
00577       // Actions are defined by the specific error handler (
00578       // see rootd.cxx and proofd.cxx)
00579       if (func) (*func)(code,(const char *)buf, sizeof(buf));
00580    }
00581 
00582 } // namespace ROOT

Generated on Tue Jul 5 14:45:30 2011 for ROOT_528-00b_version by  doxygen 1.5.1