ssh.cxx

Go to the documentation of this file.
00001 // @(#)root/rpdutils:$Id: ssh.cxx 36141 2010-10-07 08:03:16Z ganis $
00002 // Author: Gerardo Ganis    7/4/2003
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, 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 // Set of utilities for rootd/proofd daemon SSH authentication.         //
00015 //                                                                      //
00016 //////////////////////////////////////////////////////////////////////////
00017 
00018 #include "RConfig.h"
00019 
00020 #include <stdio.h>
00021 #include <string.h>
00022 #include <stdlib.h>
00023 #include <unistd.h>
00024 #include <sys/socket.h>
00025 #include <sys/un.h>
00026 #include <fcntl.h>
00027 #include <sys/stat.h>
00028 #include <errno.h>
00029 #include <sys/types.h>
00030 #include <time.h>
00031 #include <netinet/in.h>
00032 #include <netinet/tcp.h>
00033 #include <arpa/inet.h>
00034 #include <netdb.h>
00035 
00036 #if (defined(R__AIX) && !defined(_AIX43)) || \
00037     (defined(R__SUNGCC3) && !defined(__arch64__))
00038 #   define USE_SIZE_T
00039 #elif defined(R__GLIBC) || defined(R__FBSD) || \
00040       (defined(R__SUNGCC3) && defined(__arch64__)) || \
00041       defined(R__OBSD) || defined(MAC_OS_X_VERSION_10_4) || \
00042       (defined(R__AIX) && defined(_AIX43))
00043 #   define USE_SOCKLEN_T
00044 #endif
00045 
00046 #include "rpdp.h"
00047 
00048 extern int gDebug;
00049 
00050 namespace ROOT {
00051 
00052 //______________________________________________________________________________
00053 int SshToolAllocateSocket(unsigned int Uid, unsigned int Gid, char **pipe)
00054 {
00055    // Allocates internal UNIX socket for SSH-like authentication.
00056    // Sets socket ownership to user for later use.
00057    // On success returns ID of allocated socket and related pipe, -1 otherwise.
00058 
00059    if (gDebug > 2)
00060       ErrorInfo("SshToolAllocateSocket: enter: Uid:%d Gid:%d", Uid, Gid);
00061 
00062    // Open socket
00063    int sd;
00064    if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
00065       ErrorInfo("SshToolAllocateSocket: error opening socket");
00066       return -1;
00067    }
00068    // Prepare binding ...
00069    struct sockaddr_un servAddr;
00070    servAddr.sun_family = AF_UNIX;
00071 
00072    int nAtt0 = 0;
00073 
00074 tryagain:
00075    // Determine unique pipe path: try with /tmp/rootdSSH_<random_string>
00076    char fsun[25] = {0};
00077    if (access("/tmp",W_OK) == 0) {
00078       strncpy(fsun, "/tmp/rootdSSH_XXXXXX", 24);
00079    } else {
00080       strncpy(fsun, "rootdSSH_XXXXXX", 24);
00081    }
00082    mode_t oldumask = umask(0700);
00083    int itmp = mkstemp(fsun);
00084    Int_t nAtt = 0;
00085    while (itmp == -1 && nAtt < kMAXRSATRIES) {
00086       nAtt++;
00087       if (gDebug > 0)
00088          ErrorInfo("SshToolAllocateSocket: mkstemp failure (nAtt: %d, errno: %d)",
00089                    nAtt,errno);
00090       itmp = mkstemp(fsun);
00091    }
00092    umask(oldumask);
00093    if (itmp == -1) {
00094       ErrorInfo("SshToolAllocateSocket: mkstemp failed %d times - return",
00095                 kMAXRSATRIES);
00096       return -1;
00097    } else {
00098       close(itmp);
00099       unlink(fsun);
00100    }
00101    nAtt0++;
00102    if (gDebug > 2)
00103       ErrorInfo("SshToolAllocateSocket: unique pipe name is %s (try: %d)",
00104                  fsun, nAtt0);
00105 
00106    // Save path ...
00107    strncpy(servAddr.sun_path, fsun, 104);
00108 
00109    // bind to socket
00110    if (bind(sd, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0) {
00111       if (errno == EADDRINUSE && nAtt0 < kMAXRSATRIES) {
00112          if (gDebug > 2)
00113             ErrorInfo
00114                 ("SshToolAllocateSocket: address in use: try again (try: %d)");
00115          goto tryagain;
00116       } else {
00117          ErrorInfo
00118               ("SshToolAllocateSocket: unable to bind to socket %d (errno: %d)",
00119                 sd, errno);
00120          return -1;
00121       }
00122    }
00123    // Activate listening
00124    if (listen(sd, 5)) {
00125       ErrorInfo
00126           ("SshToolAllocateSocket: can't activate listening (errno: %d)",
00127            errno);
00128       return -1;
00129    }
00130 
00131    // Change ownerships:
00132    // This operaton is possible only as root ... but not always is needed
00133    // so, do not stop in case of failure.
00134    struct stat sst;
00135 
00136    // The socket ...
00137    fstat(sd, &sst);
00138    if ((unsigned int)sst.st_uid != Uid || (unsigned int)sst.st_gid != Gid) {
00139       if (fchown(sd, Uid, Gid)) {
00140          if (gDebug > 0) {
00141             ErrorInfo("SshToolAllocateSocket: fchown: could not change socket"
00142                       " %d ownership (errno= %d) ",sd, errno);
00143             ErrorInfo("SshToolAllocateSocket: socket (uid,gid) are: %d %d",
00144                       sst.st_uid, sst.st_gid);
00145             ErrorInfo("SshToolAllocateSocket: may follow authentication problems");
00146          }
00147       }
00148    }
00149    // The path ...
00150    if (chown(fsun, Uid, Gid) != 0) {
00151       if (gDebug > 0) {
00152          ErrorInfo("SshToolAllocateSocket: chown: could not change path"
00153                      " '%s' ownership (errno= %d)",fsun, errno);
00154          ErrorInfo("SshToolAllocateSocket: path (uid,gid) are: %d %d",
00155                      sst.st_uid, sst.st_gid);
00156          ErrorInfo("SshToolAllocateSocket: may follow authentication problems");
00157       }
00158       return -1;
00159    }
00160 
00161    // Change permissions to access pipe to avoid hacking from a different
00162    // user account.
00163    // This is essential for security, so stop if you can't do it
00164    if (chmod(fsun, 0600)) {
00165       if (gDebug > 0) {
00166          ErrorInfo("SshToolAllocateSocket: chmod: could not change"
00167                    " '%s' permission (errno= %d)",fsun, errno);
00168          ErrorInfo("SshToolAllocateSocket: path (uid,gid) are: %d %d",
00169                    sst.st_uid, sst.st_gid);
00170          SshToolDiscardSocket(fsun,sd);
00171          return -1;
00172       }
00173    }
00174 
00175    // Fill output
00176    *pipe = strdup(fsun);
00177 
00178    // return socket fd
00179    return sd;
00180 }
00181 
00182 
00183 //______________________________________________________________________________
00184 void SshToolDiscardSocket(const char *pipe, int sockfd)
00185 {
00186    // Discards socket.
00187 
00188    if (gDebug > 2)
00189       ErrorInfo
00190           ("SshToolDiscardSocket: discarding socket: pipe: %s, fd: %d",
00191            pipe, sockfd);
00192 
00193    // Unlink pipe
00194    if (unlink(pipe) == -1) {
00195       if (GetErrno() != ENOENT) {
00196          ErrorInfo("SshToolDiscardSocket: unable to unlink %s"
00197                    "(errno: %d, ENOENT= %d)", pipe, GetErrno(), ENOENT);
00198       }
00199    }
00200    // close socket
00201    close(sockfd);
00202 }
00203 
00204 //______________________________________________________________________________
00205 int SshToolNotifyFailure(const char *Pipe)
00206 {
00207    // Notifies failure of SSH authentication to relevant rootd/proofd process.
00208 
00209    if (gDebug > 2)
00210       ErrorInfo("SshToolNotifyFailure: notifying failure to pipe %s\n",
00211                 Pipe);
00212 
00213    // Preparing socket connection
00214    int sd;
00215    struct sockaddr_un servAddr;
00216    servAddr.sun_family = AF_UNIX;
00217    memcpy((void *) servAddr.sun_path, (void *) Pipe, 108);
00218    servAddr.sun_path[107] = '\0';
00219    if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
00220       ErrorInfo("SshToolNotifyFailure: cannot open socket: exiting ");
00221       return 1;
00222    }
00223    // Connecting to socket
00224    int rc;
00225    if ((rc =
00226         connect(sd, (struct sockaddr *) &servAddr,
00227                 sizeof(servAddr))) < 0) {
00228       ErrorInfo("SshToolNotifyFailure: cannot connect socket: exiting ");
00229       return 1;
00230    }
00231    // Sending "KO" ...
00232    const char *okbuf = "KO";
00233    rc = send(sd, okbuf, strlen(okbuf), 0);
00234    if (rc != 2) {
00235       ErrorInfo
00236           ("SshToolNotifyFailure: sending might have been unsuccessful (bytes send: %d)",
00237            rc);
00238    }
00239 
00240    return 0;
00241 }
00242 
00243 //______________________________________________________________________________
00244 int SshToolGetAuth(int UnixFd, const char *User)
00245 {
00246    int auth = 0;
00247 
00248    if (gDebug > 2)
00249       ErrorInfo("SshToolGetAuth: accepting connections on socket %d"
00250                 " for user %s",UnixFd,User);
00251 
00252    // Wait for verdict form sshd (via ssh2rpd ...)
00253    struct sockaddr sunAddr;
00254 #if defined(USE_SIZE_T)
00255    size_t sunAddrLen = sizeof(sunAddr);
00256 #elif defined(USE_SOCKLEN_T)
00257    socklen_t sunAddrLen = sizeof(sunAddr);
00258 #else
00259    int sunAddrLen = sizeof(sunAddr);
00260 #endif
00261    int newUnixFd =
00262        accept(UnixFd, (struct sockaddr *) &sunAddr, &sunAddrLen);
00263    if (newUnixFd < 0) {
00264       ErrorInfo
00265          ("SshToolGetAuth: problems while accepting new connection (errno: %d)", (int) errno);
00266       return auth;
00267    }
00268 
00269    int lenr[1], nr, len = 0;
00270    if ((nr = NetRecvRaw(newUnixFd, lenr, sizeof(lenr))) < 0) {
00271       ErrorInfo
00272          ("SshToolGetAuth: incorrect recv from ssh2rpd: bytes:%d, buffer:%d",
00273            nr, lenr[0]);
00274       return auth;
00275    }
00276 
00277    // Transform in human readable form
00278    len = ntohl(lenr[0]) + 1;
00279    char *sshAuth = 0;
00280    if (len > 0) {
00281       sshAuth = new char[len];
00282       if (sshAuth) {
00283          if ((nr = NetRecvRaw(newUnixFd, sshAuth, len)) != len) {
00284             ErrorInfo
00285              ("SshToolGetAuth: incorrect recv from ssh2rpd: nr:%d, buf:%s",
00286               nr, sshAuth);
00287          } else
00288             sshAuth[len-1] = 0;
00289          if (gDebug > 2)
00290             ErrorInfo("SshToolGetAuth: got: %s",sshAuth);
00291 
00292          // Check authentication and notify to client
00293          if (strncmp(sshAuth, "OK", 2) != 0) {
00294             ErrorInfo("SshToolGetAuth: user did not authenticate to sshd: %s (%d)",
00295                        sshAuth, strncmp(sshAuth, "OK", 2));
00296          } else {
00297             if (len > 3) {
00298                if (strcmp((const char *)(sshAuth+3), User) != 0) {
00299                   ErrorInfo("SshToolGetAuth: authenticated user not the same"
00300                             " as requested login username: %s (%s)",
00301                             sshAuth+3, User);
00302                   auth = -1;
00303                } else {
00304                   auth = 1;
00305                }
00306             } else
00307                auth = -1;
00308          }
00309          delete[] sshAuth;
00310       }
00311    }
00312 
00313    // Close local socket
00314    close(newUnixFd);
00315 
00316    return auth;
00317 }
00318 
00319 } // namespace ROOT

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