GlobusAuth.cxx

Go to the documentation of this file.
00001 // @(#)root/globus:$Id: GlobusAuth.cxx 31509 2009-12-02 19:54:36Z rdm $
00002 // Author: Gerardo Ganis  15/01/2003
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2002, 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 /* Parts of this file are adapted from the Globus Tool Kit version 2.2.3
00013  * are subject to related licenses.
00014  * Please refer to www.globus.org for details
00015  */
00016 
00017 #include "RConfigure.h"
00018 
00019 #include <errno.h>
00020 #include <signal.h>
00021 #include <string.h>
00022 // #include <stdlib.h>
00023 
00024 #include "TSocket.h"
00025 #include "TAuthenticate.h"
00026 #include "THostAuth.h"
00027 #include "TDatime.h"
00028 #include "TError.h"
00029 #include "TSystem.h"
00030 #include "TROOT.h"
00031 #include "TApplication.h"
00032 #include "TEnv.h"
00033 #include "Getline.h"
00034 #include "NetErrors.h"
00035 
00036 #define HAVE_MEMMOVE 1
00037 extern "C" {
00038 #ifdef IOV_MAX
00039 #undef IOV_MAX
00040 #endif
00041 #include <globus_common.h>
00042 #include <globus_gss_assist.h>
00043 #include <openssl/x509.h>
00044 #include <openssl/pem.h>
00045 #include <sys/ipc.h>
00046 #include <sys/shm.h>
00047 }
00048 
00049 static gss_cred_id_t gGlbCredHandle = GSS_C_NO_CREDENTIAL;
00050 static gss_cred_id_t gGlbDelCredHandle = GSS_C_NO_CREDENTIAL;
00051 static int gShmIdCred = -1;
00052 
00053 Int_t GlobusAuthenticate(TAuthenticate *, TString &, TString &);
00054 Int_t GlobusCheckSecContext(const char *, gss_ctx_id_t);
00055 Int_t GlobusCheckSecCtx(const char *, TRootSecContext *);
00056 Int_t GlobusCleanupContext(gss_ctx_id_t);
00057 void  GlobusCleanupShm();
00058 Int_t GlobusIssuerName(TString &);
00059 void  GlobusError(const char *, OM_uint32, OM_uint32, Int_t);
00060 Int_t GlobusGetCredHandle(Int_t, gss_cred_id_t *);
00061 Int_t GlobusGetDelCred();
00062 void  GlobusGetDetails(Int_t, Int_t, TString &);
00063 Int_t GlobusGetLocalEnv(Int_t *, TString);
00064 Int_t GlobusGetSecContLifeTime(gss_ctx_id_t);
00065 Int_t GlobusNameFromCred(gss_cred_id_t, TString &);
00066 
00067 class GlobusAuthInit {
00068  public:
00069    GlobusAuthInit() {
00070       TAuthenticate::SetGlobusAuthHook(&GlobusAuthenticate);
00071 }};
00072 static GlobusAuthInit globusauth_init;
00073 
00074 //______________________________________________________________________________
00075 Int_t GlobusAuthenticate(TAuthenticate * tAuth, TString & user,
00076                          TString & details)
00077 {
00078    // Globus authentication code.
00079    // Returns 0 in case authentication failed
00080    //         1 in case of success
00081    //         2 in case of the remote node doesn not seem to support
00082    //           Globus Authentication
00083    //         3 in case of the remote node doesn not seem to have
00084    //           certificates for our CA or is unable to init credentials
00085 
00086    int auth = 0, rc;
00087    int retval = 0, kind = 0, type = 0, server_auth = 0, brcv = 0, bsnd = 0;
00088    gss_ctx_id_t glbContextHandle = GSS_C_NO_CONTEXT;
00089    OM_uint32 majStat = 0;
00090    OM_uint32 minStat = 0;
00091    OM_uint32 gssRetFlags = 0;
00092    OM_uint32 gssReqFlags = 0;
00093    int glbTokenStatus = 0;
00094    char *host_subj = 0;
00095    TDatime expDate = TDatime();
00096 
00097    // Check if called for cleanup
00098    if (user == "-1") {
00099       if (gDebug > 2)
00100          Info("GlobusAuthenticate", " cleanup call (%s)",details.Data());
00101 
00102       if (details == "context") {
00103          // Security context cleaning
00104          GlobusCleanupContext((gss_ctx_id_t)tAuth);
00105       } else if (details == "shm") {
00106          // Shared memory cleaning (TProofServ)
00107          GlobusCleanupShm();
00108       }
00109       return 1;
00110    }
00111 
00112    // From the calling TAuthenticate
00113    TSocket *sock = tAuth->GetSocket();
00114    TString protocol = tAuth->GetProtocol();
00115 
00116    if (gDebug > 2)
00117       Info("GlobusAuthenticate", " enter: protocol:'%s' user:'%s'", protocol.Data(),
00118            user.Data());
00119 
00120    // The host FQDN ... for debugging
00121    const char *hostFQDN = sock->GetInetAddress().GetHostName();
00122 
00123    // Determine local calling environment ...
00124    Int_t localCallEnv = -1;
00125    if ((rc = GlobusGetLocalEnv(&localCallEnv, protocol))) {
00126       if (gDebug > 0)
00127           Error("GlobusAuthenticate",
00128             "unable to set relevant environment variables (rc=%d)",
00129             rc);
00130       return -1;
00131    }
00132    if (gDebug > 3)
00133       Info("GlobusAuthenticate", " localCallEnv is %d", localCallEnv);
00134 
00135    // Get credential handle ... either genuine or delegated
00136    if (GlobusGetCredHandle(localCallEnv, &gGlbCredHandle)) {
00137       if (gDebug > 0)
00138          Error("GlobusAuthenticate", "unable to acquire valid credentials");
00139       return -1;
00140    }
00141    if (gDebug > 3)
00142       Info("GlobusAuthenticate", " Credential Handle is 0x%x",
00143            gGlbCredHandle);
00144 
00145    // Inquire credentials for subject name and convert it in human readable form ...
00146    TString ssuj;
00147    if ((rc = GlobusNameFromCred(gGlbCredHandle, ssuj))) {
00148       if (gDebug > 0)
00149          Error("GlobusAuthenticate",
00150                "PROOF Master: unable to determine name from cred (rc=%d)", rc);
00151       return -1;
00152    }
00153 
00154    // Create Options string
00155    Int_t opt = TAuthenticate::GetAuthReUse() * kAUTH_REUSE_MSK +
00156                tAuth->GetRSAKeyType() * kAUTH_RSATY_MSK;
00157    TString options(Form("%d %d %s", opt, ssuj.Length(), ssuj.Data()));
00158 
00159    // Check established authentications
00160    kind = kROOTD_GLOBUS;
00161    retval = TAuthenticate::GetAuthReUse();
00162    if ((rc = tAuth->AuthExists(ssuj, TAuthenticate::kGlobus, options,
00163              &kind, &retval, &GlobusCheckSecCtx)) == 1) {
00164       // A valid authentication exists: we are done ...
00165       return 1;
00166    }
00167 
00168    if (rc == -2) {
00169       return rc;
00170    }
00171    if (kind == kROOTD_ERR) {
00172       return 0;
00173    }
00174    // If server does not support Globus authentication we can't continue ...
00175    if (retval == 0 || kind != kROOTD_GLOBUS) {
00176       if (gDebug > 2)
00177          Info("GlobusAuthenticate", "server does not support Globus authentication");
00178       return -1;
00179    }
00180 
00181    if (sock->GetRemoteProtocol() < 18) {
00182       TString isuj;
00183       if (GlobusIssuerName(isuj)) {
00184          if (gDebug > 0)
00185             Error("GlobusAuthenticate",
00186                   "unable to determine issuer name from certificate");
00187          return 0;
00188       }
00189       // Now we send the issuer to the server daemon
00190       char buf[20];
00191       sprintf(buf, "%d", (int) (isuj.Length() + 1));
00192       if ((bsnd = sock->Send(buf, kMESS_STRING)) != (int) (strlen(buf)+1)) {
00193          if (gDebug > 0)
00194             Error("GlobusAuthenticate",
00195                   "Length of Issuer name not send correctly: bytes sent: %d (tot len: %d)",
00196                   bsnd - 1, strlen(buf));
00197          return 0;
00198       }
00199       // Now we send it to the server daemon
00200       if ((bsnd = sock->Send(isuj.Data(), kMESS_STRING)) < (Int_t)(isuj.Length()+1)) {
00201          if (gDebug > 0)
00202             Error("GlobusAuthenticate",
00203                   "Issuer name not send correctly: bytes sent: %d (tot len: %d)",
00204                   bsnd - 1, isuj.Length());
00205          return 0;
00206       }
00207    }
00208    // Now we wait for the replay from the server ...
00209    sock->Recv(retval, kind);
00210    if (kind == kROOTD_ERR) {
00211       if (gDebug > 0)
00212          Error("GlobusAuthenticate",
00213                "recv host subj: host unable init credentials");
00214       return 3;
00215    }
00216    if (kind != kROOTD_GLOBUS) {
00217       if (gDebug > 0)
00218          Error("GlobusAuthenticate",
00219             "recv host subj: unexpected message from daemon:"
00220             " kind: %d (expecting: %d)",kind, kROOTD_GLOBUS);
00221    } else {
00222       if (retval == 0) {
00223          if (gDebug > 0)
00224             Error("GlobusAuthenticate",
00225                "recv host subj: host not able to authenticate this CA");
00226          return 0;
00227       } else {
00228          if (gDebug > 3)
00229             Info("GlobusAuthenticate",
00230                  "recv host subj: buffer length is: %d", retval);
00231          host_subj = new char[retval + 1];
00232          brcv = sock->Recv(host_subj, retval, kind);
00233          if (gDebug > 3)
00234             Info("GlobusAuthenticate",
00235                  "received host_subj: %s: (%d)", host_subj, brcv);
00236          if (strlen(host_subj) < (UInt_t)(retval - 1) ||
00237              retval <= 1) {
00238             if (gDebug > 0) {
00239                Error("GlobusAuthenticate",
00240                   "recv host subj: did not receive all the bytes"
00241                   " (recv: %d, due >%d)", brcv, retval);
00242                Error("GlobusAuthenticate", "recv host subj: (%d) %s",
00243                   strlen(host_subj), host_subj);
00244             }
00245             if (host_subj) delete[] host_subj;
00246             return 0;
00247          }
00248       }
00249    }
00250    // Now we have a valid subject name for the host ...
00251    if (gDebug > 2)
00252       Info("GlobusAuthenticate", "Host subject: %s", host_subj);
00253 
00254    // We need to associate a FILE* stream with the socket
00255    // It will automatically closed when the socket will be closed ...
00256    int sockFd = sock->GetDescriptor();
00257    FILE *sockStream = fdopen(sockFd, "w+");
00258 
00259    // Type of request for credentials depend on calling environment
00260    gssReqFlags =
00261        localCallEnv >
00262        0 ? (GSS_C_DELEG_FLAG | GSS_C_MUTUAL_FLAG) : GSS_C_MUTUAL_FLAG;
00263    if (gDebug > 3)
00264       Info("GlobusAuthenticate",
00265            " gssReqFlags: %p, GlbCredentials: %p", gssReqFlags, gGlbCredHandle);
00266 
00267    // Now we are ready to start negotiating with the Server
00268    if ((majStat =
00269         globus_gss_assist_init_sec_context(&minStat, gGlbCredHandle,
00270                                            &glbContextHandle, host_subj,
00271                                            gssReqFlags, &gssRetFlags,
00272                                            &glbTokenStatus,
00273                                            globus_gss_assist_token_get_fd,
00274                                            (void *) sockStream,
00275                                            globus_gss_assist_token_send_fd,
00276                                            (void *) sockStream)) !=
00277        GSS_S_COMPLETE) {
00278       if (gDebug > 0)
00279          GlobusError("GlobusAuthenticate: gss_assist_init_sec_context",
00280                   majStat, minStat, glbTokenStatus);
00281       if (host_subj) delete[] host_subj;
00282       sock->Send(0,kROOTD_ERR);
00283       return 0;
00284    } else {
00285       // Set expiration date
00286       expDate.Set(expDate.Convert() + GlobusGetSecContLifeTime(glbContextHandle));
00287       if (gDebug > 2) {
00288          Info("GlobusAuthenticate", "authenticated to host %s", hostFQDN);
00289          Info("GlobusAuthenticate", "expiring on '%s'", expDate.AsString());
00290       }
00291       if (fflush(sockStream) != 0) {
00292          Warning("GlobusAuthenticate", "unable to fflush socket:"
00293                  " may cause authentication problems on server side");
00294       }
00295       auth = 1;
00296    }
00297 
00298    // Now we have the subject and we can release some resources ...
00299    if (host_subj) delete[] host_subj;
00300 
00301    // Receive username used for login or key request info and type of key
00302    int nrec = sock->Recv(retval, type);  // returns user
00303 
00304    Int_t rsaKey = 0;
00305    if (type == kROOTD_RSAKEY) {
00306       if (retval <= 0 || retval > 2)
00307          Warning("GlobusAuthenticate",
00308                  "problems recvn RSA key flag: got message %d, retval: %d",
00309                  type, retval);
00310       rsaKey = retval - 1;
00311 
00312       // Send the key securely
00313       TAuthenticate::SendRSAPublicKey(sock,rsaKey);
00314 
00315       // Receive username used for login
00316       nrec = sock->Recv(retval, type);  // returns user
00317    }
00318 
00319    if (type != kROOTD_GLOBUS || retval < 1)
00320       Warning("GlobusAuthenticate",
00321               "problems recvn (user,offset) length (%d:%d bytes:%d)", type,
00322               retval, nrec);
00323    char *rfrm = new char[retval + 1];
00324    nrec = sock->Recv(rfrm, retval + 1, type);  // returns user
00325    if (type != kMESS_STRING)
00326       Warning("GlobusAuthenticate",
00327               "username and offset not received (%d:%d)", type, nrec);
00328    else if (gDebug > 2)
00329       Info("GlobusAuthenticate", "logging remotely as %s ", rfrm);
00330 
00331    // Parse answer
00332    char *lUser = new char[retval];
00333    Int_t offSet = -1;
00334    sscanf(rfrm, "%s %d", lUser, &offSet);
00335 
00336    // Return username
00337    user = lUser;
00338 
00339    // Receive token
00340    char *token = 0;
00341    if (TAuthenticate::GetAuthReUse() == 1 && offSet > -1) {
00342       if (TAuthenticate::SecureRecv(sock, 1, rsaKey, &token) == -1) {
00343          Warning("GlobusAuthenticate",
00344                  "Problems secure-receiving token -"
00345                  " may result in corrupted token");
00346       }
00347       if (gDebug > 3)
00348          Info("GlobusAuthenticate", "received from server: token: '%s' ",
00349               token);
00350    } else {
00351       token = StrDup("");
00352    }
00353 
00354    // Create SecContext object
00355    GlobusGetDetails(localCallEnv, 0, details);
00356    TRootSecContext *ctx =
00357       tAuth->GetHostAuth()->CreateSecContext((const char *)lUser,
00358           hostFQDN, (Int_t)TAuthenticate::kGlobus, offSet,
00359           details, (const char *)token, expDate,
00360           (void *)glbContextHandle, rsaKey);
00361    // Transmit it to TAuthenticate
00362    tAuth->SetSecContext(ctx);
00363 
00364    // receive status from server
00365    sock->Recv(server_auth, kind);
00366    if (gDebug > 2)
00367       Info("GlobusAuthenticate", "received auth status from server: %d (%d)",
00368            server_auth, kind);
00369 
00370    if (auth && !server_auth) {
00371       Warning("GlobusAuthenticate",
00372               " it looks like server did not authenticate: probably a problem with mapping");
00373       auth = 0;
00374    }
00375 
00376    // free allocated memory ...
00377    if (rfrm) delete[] rfrm;
00378    if (lUser) delete[] lUser;
00379    if (token) delete[] token;
00380 
00381    // return result
00382    return auth;
00383 }
00384 
00385 //______________________________________________________________________________
00386 int GlobusGetDelCred()
00387 {
00388    // This function fetchs from the shared memory segment created by 'proofd'.
00389    // the delegated credentials needed to autheticate the slaves ...
00390    // The shared memory segment is destroyed.
00391 
00392    struct shmid_ds shm_ds;
00393    OM_uint32 majStat = 0;
00394    OM_uint32 minStat = 0;
00395 
00396    if (gDebug > 2)
00397       Info("GlobusGetDelCred:", "Enter ...");
00398 
00399    // Attach segment to address
00400    gss_buffer_t databuf = (gss_buffer_t) shmat(gShmIdCred, 0, 0);
00401 
00402    // Import credentials
00403    //    credential= (gss_buffer_t)malloc(sizeof(gss_buffer_desc)+databuf->length);
00404    gss_buffer_t credential =
00405        (gss_buffer_t) new char[sizeof(gss_buffer_desc) + databuf->length];
00406    credential->length = databuf->length;
00407    credential->value =
00408        (void *) ((char *) credential + sizeof(size_t) + sizeof(void *));
00409    void *dbufval =
00410        (void *) ((char *) databuf + sizeof(size_t) + sizeof(void *));
00411    memmove(credential->value, dbufval, credential->length);
00412    if ((majStat =
00413         gss_import_cred(&minStat, &gGlbDelCredHandle, 0, 0, credential, 0,
00414                         0)) != GSS_S_COMPLETE) {
00415       if (gDebug > 0)
00416          GlobusError("GlobusGetDelCred: gss_import_cred", majStat, minStat, 0);
00417       return 1;
00418    } else if (gDebug > 3)
00419       Info("GlobusGetDelCred:",
00420            "Globus Credentials successfully imported (0x%x)",
00421            gGlbDelCredHandle);
00422 
00423    if (credential) delete[] credential;
00424 
00425    // Detach from shared memory segment
00426    int rc = shmdt((const void *) databuf);
00427    if (rc != 0) {
00428       if (gDebug > 0)
00429          Info("GlobusGetDelCred:",
00430               "unable to detach from shared memory segment (rc=%d)", rc);
00431    }
00432    if (gDebug > 3) {
00433       rc = shmctl(gShmIdCred, IPC_STAT, &shm_ds);
00434       Info("GlobusGetDelCred:",
00435            "Process: uid: %d, euid: %d - Buffer: uid: %d, cuid: %d",
00436            getuid(), geteuid(), shm_ds.shm_perm.uid, shm_ds.shm_perm.cuid);
00437    }
00438 
00439    rc = shmctl(gShmIdCred, IPC_RMID, &shm_ds);
00440    if (rc == 0) {
00441       if (gDebug > 2)
00442          Info("GlobusGetDelCred:",
00443               "shared memory segment successfully marked as destroyed");
00444    } else {
00445       Warning("GlobusGetDelCred:",
00446               "unable to mark segment %d as destroyed", gShmIdCred);
00447    }
00448 
00449    return 0;
00450 }
00451 
00452 //______________________________________________________________________________
00453 void GlobusError(const char *mess, OM_uint32 majs, OM_uint32 mins, int toks)
00454 {
00455    // Handle error ...
00456 
00457    char *glbErr = 0;
00458 
00459    if (!globus_gss_assist_display_status_str
00460        (&glbErr, (char *)mess, majs, mins, toks)) {
00461         Error("GlobusError:","%s (majst=%d,minst=%d,tokst:%d)",
00462                              glbErr, majs, mins, toks);
00463    } else {
00464       Error("GlobusError:","%s (not resolved) (majst=%d,minst=%d,tokst:%d)",
00465                            mess, majs, mins, toks);
00466    }
00467 
00468    if (glbErr) delete[] glbErr;
00469 }
00470 
00471 //______________________________________________________________________________
00472 Int_t GlobusGetLocalEnv(Int_t *localEnv, TString protocol)
00473 {
00474    // Determines calling environment.
00475    // Returns 0 if successful; 1 otherwise.
00476 
00477    int retval = 0;
00478 
00479    // Calling application
00480    TApplication *lApp = gROOT->GetApplication();
00481    if (gDebug > 2) {
00482       int i = 0;
00483       for (; i < lApp->Argc(); i++) {
00484          Info("GlobusGetLocalEnv", "application arguments: %d: %s", i,
00485               lApp->Argv(i));
00486       }
00487    }
00488 
00489    *localEnv = 0;
00490    if (lApp != 0) {
00491       if (gROOT->IsProofServ()) {
00492          // This is PROOF ... either Master or Slave ...
00493          if (gDebug > 3) {
00494             Info("GlobusGetLocalEnv",
00495                  "PROOF environment, called by the MASTER/SLAVE");
00496             Info("GlobusGetLocalEnv",
00497                  "string with pointer to del cred is 0x%x",
00498                  gGlbDelCredHandle);
00499          }
00500          *localEnv = 2;
00501          gShmIdCred = -1;
00502          const char *p = gSystem->Getenv("ROOTSHMIDCRED");
00503          if (p)
00504             gShmIdCred = strtol(p, (char **)0, 10);
00505          if (gShmIdCred <= 0) {
00506             Info("GlobusGetLocalEnv",
00507                     "delegate credentials undefined");
00508             retval = 1;
00509          }
00510       } else {
00511          if (strstr(protocol.Data(), "proof") != 0) {
00512             if (gDebug > 3)
00513                Info("GlobusGetLocalEnv",
00514                     "PROOF environment, called by the CLIENT");
00515             *localEnv = 1;
00516          } else if (strstr(protocol.Data(), "root") != 0 ||
00517                     strstr(protocol.Data(), "sock") != 0) {
00518             if (gDebug > 3)
00519                Info("GlobusGetLocalEnv",
00520                     "ROOT environment (%s)", protocol.Data());
00521          } else {
00522             if (gDebug > 0)
00523                Info("GlobusGetLocalEnv",
00524                     "unable to recognize the environment"
00525                     " (protocol: %s)-> assume ROOT",protocol.Data());
00526          }
00527       }
00528    } else {
00529       if (gDebug > 0)
00530          Info("GlobusGetLocalEnv",
00531               "unable to get pointer to current application"
00532               " -> assume ROOT environment");
00533    }
00534 
00535    return retval;
00536 }
00537 
00538 //______________________________________________________________________________
00539 Int_t GlobusNameFromCred(gss_cred_id_t cred, TString &subjName)
00540 {
00541    // Get subject name from credential handle cred.
00542    // Returns 0 is successfull, 1 otherwise.
00543 
00544    if (gDebug > 2)
00545       Info("GlobusNamesFromCred", "Enter: Handle: 0x%p", cred);
00546 
00547    // Inquire credentials for Subject name and convert it in human readable form ...
00548    OM_uint32 majStat = 0;
00549    OM_uint32 minStat = 0;
00550    gss_name_t name;
00551    OM_uint32 lifeTime;
00552    gss_cred_usage_t credUsage;
00553    gss_OID_set mech;
00554    if ((majStat = gss_inquire_cred(&minStat, cred, &name,
00555                   &lifeTime, &credUsage, &mech)) != GSS_S_COMPLETE) {
00556       if (gDebug > 0)
00557          GlobusError("GlobusNameFromCred: gss_inquire_cred",
00558                      majStat, minStat,0);
00559       return 1;
00560    }
00561    gss_buffer_desc outBuf;
00562    gss_OID nameType;
00563    if ((majStat = gss_display_name(&minStat, name, &outBuf,
00564                   &nameType)) != GSS_S_COMPLETE) {
00565       if (gDebug > 0)
00566          GlobusError("GlobusNameFromCred: gss_display_name",
00567                      majStat, minStat, 0);
00568       return 2;
00569    } else
00570       subjName = TString((const char *)outBuf.value);
00571 
00572    // Notify
00573    if (gDebug > 2)
00574       Info("GlobusNameFromCred", "subject name: %s", subjName.Data());
00575 
00576    // Successful
00577    return 0;
00578 }
00579 
00580 //______________________________________________________________________________
00581 Int_t GlobusGetSecContLifeTime(gss_ctx_id_t ctx)
00582 {
00583    // Returns lifetime of established sec context 'ctx'
00584 
00585    OM_uint32 majStat = 0;
00586    OM_uint32 minStat = 0;
00587    OM_uint32 gssRetFlags = 0;
00588    OM_uint32 glbContLifeTime = 0;
00589    gss_OID   mechType;
00590    gss_name_t *targName = 0, *name = 0;
00591    int       dum1, dum2;
00592 
00593    if (ctx != 0 && ctx != GSS_C_NO_CONTEXT) {
00594       if ((majStat = gss_inquire_context(&minStat, ctx, name,
00595                      targName, &glbContLifeTime, &mechType, &gssRetFlags,
00596                      &dum1, &dum2)) != GSS_S_COMPLETE) {
00597          if (gDebug > 0)
00598             GlobusError("GlobusGetSecContLifeTime: gss_inquire_context",
00599                           majStat, minStat, 0);
00600          return 0;
00601       } else {
00602          if (gDebug > 3)
00603             Info("GlobusGetSecContLifeTime"," remaining lifetime: %d sec",
00604                   glbContLifeTime);
00605          return (Int_t)glbContLifeTime;
00606       }
00607    }
00608    return 0;
00609 }
00610 
00611 //______________________________________________________________________________
00612 Int_t GlobusCleanupContext(gss_ctx_id_t ctx)
00613 {
00614    // This function cleans up security context ctx
00615 
00616    OM_uint32 majStat = 0;
00617    OM_uint32 minStat = 0;
00618 
00619    // Delete context
00620    if ((majStat = gss_delete_sec_context(&minStat, &ctx,
00621                   GSS_C_NO_BUFFER)) != GSS_S_COMPLETE) {
00622       if (gDebug > 0)
00623          GlobusError("GlobusCleanupContext: gss_delete_sec_context",
00624                      majStat,minStat, 0);
00625       return 0;
00626    }
00627 
00628    return 1;
00629 }
00630 
00631 //______________________________________________________________________________
00632 Int_t GlobusCheckSecCtx(const char *subj, TRootSecContext *ctx)
00633 {
00634    // Globus version of CheckSecCtx to be passed to TAuthenticate::AuthExists
00635    // Check if Subj matches the one in Ctx
00636    // Returns: 1 if ok, 0 if not
00637    // Deactivates Ctx is not valid
00638 
00639    Int_t rc = 0;
00640 
00641    if (ctx->IsActive())
00642       rc = GlobusCheckSecContext(subj,(gss_ctx_id_t)(ctx->GetContext()));
00643 
00644    return rc;
00645 }
00646 
00647 //______________________________________________________________________________
00648 void GlobusCleanupShm()
00649 {
00650    // This function cleans up shared memories associated with Globus
00651 
00652    if (gROOT->IsProofServ()) {
00653       struct shmid_ds shm_ds;
00654       int rc;
00655       // Delegated Credentials
00656       gShmIdCred = -1;
00657       const char *p = gSystem->Getenv("ROOTSHMIDCRED");
00658       if (p)
00659          gShmIdCred = strtol(p, (char **)0, 10);
00660       if (gShmIdCred != -1) {
00661          if ((rc = shmctl(gShmIdCred, IPC_RMID, &shm_ds)) != 0) {
00662             if ((rc == EINVAL) || (rc == EIDRM)) {
00663                if (gDebug > 3)
00664                   Info("GlobusCleanupShm:",
00665                        "credentials shared memory segment %s"
00666                        "already marked as destroyed");
00667             } else {
00668                Warning("GlobusCleanupShm:",
00669                        "unable to mark segment as destroyed (error: 0x%x)",
00670                        rc);
00671             }
00672          } else if (gDebug > 3)
00673             Info("GlobusCleanupShm:",
00674                  "shared memory segment %d marked for destruction",
00675                  gShmIdCred);
00676       } else if (gDebug > 3) {
00677          Info("GlobusCleanupShm:",
00678               "gShmIdCred not defined in this session");
00679       }
00680    }
00681 }
00682 
00683 //______________________________________________________________________________
00684 Int_t GlobusCheckSecContext(const char *subjName, gss_ctx_id_t ctx)
00685 {
00686    // Checks if SubjName match the one assigned to sec context Ctx
00687    // Check also validity of Ctx.
00688    // Returns 1 if everything is ok, 0 if non-matching
00689    // -1 if Ctx is no more valid and should be discarded
00690 
00691    if (!ctx)
00692       return 0;
00693 
00694    int rc = 0;
00695    OM_uint32 majStat = 0;
00696    OM_uint32 minStat = 0;
00697    OM_uint32 gssRetFlags = 0;
00698    OM_uint32 glbContLifeTime = 0;
00699 
00700    if (gDebug > 2)
00701       Info("GlobusCheckSecContext", "checking subj:%s", subjName);
00702 
00703    // Check validity of the retrieved context ...
00704    Int_t dum1, dum2;
00705    gss_OID mechType;
00706    gss_name_t *targName = 0;
00707    gss_name_t name;
00708    if (ctx != 0 && ctx != GSS_C_NO_CONTEXT) {
00709 
00710       if ((majStat = gss_inquire_context(&minStat, ctx, &name,
00711                      targName, &glbContLifeTime, &mechType,
00712                      &gssRetFlags, &dum1, &dum2)) != GSS_S_COMPLETE) {
00713          if (gDebug > 0)
00714             GlobusError("GlobusCheckSecContext: gss_inquire_context",
00715                                                 majStat, minStat, 0);
00716          rc = -1;
00717       } else {
00718          gss_buffer_desc nameBuffer;
00719          // Get the subject name now
00720          if ((majStat = gss_display_name(&minStat, name, &nameBuffer,
00721                                         GLOBUS_NULL)) != GSS_S_COMPLETE) {
00722             if (gDebug > 0)
00723                GlobusError("GlobusCheckSecContext: gss_display_name",
00724                                                  majStat, minStat, 0);
00725             nameBuffer.length = 0;
00726             nameBuffer.value = GLOBUS_NULL;
00727          } else {
00728             char *theName = new char[nameBuffer.length+1];
00729             strncpy(theName,(char *)(nameBuffer.value),(Int_t)(nameBuffer.length));
00730             theName[nameBuffer.length]= '\0';
00731             if (gDebug > 2)
00732                Info("GlobusCheckSecContext","with subject name: %s (%d)",
00733                                              theName, nameBuffer.length);
00734             if (!strcmp(theName, subjName)) {
00735                if (gDebug > 2)
00736                   Info("GlobusCheckSecContext",
00737                        "client already authenticated (remaining lifetime: %d sec)",
00738                         glbContLifeTime);
00739                rc = 1;
00740             }
00741             // Release allocated space
00742             if (theName)
00743                delete[] theName;
00744             if ((majStat = gss_release_name(&minStat, &name))
00745                                           != GSS_S_COMPLETE) {
00746                if (gDebug > 0)
00747                    GlobusError("GlobusCheckSecContext: gss_release_name",
00748                                                       majStat, minStat, 0);
00749             }
00750          }
00751       }
00752 
00753    } else {
00754       rc = -1;
00755    }
00756 
00757    return rc;
00758 }
00759 
00760 //______________________________________________________________________________
00761 int GlobusGetCredHandle(Int_t localEnv, gss_cred_id_t * credHandle)
00762 {
00763    // Get Credential Handle, either from scratch, or from delegated info ...
00764    // Returns 0 is successfull, 1 otherwise.
00765 
00766    int retval = 0;
00767    OM_uint32 majStat = 0;
00768    OM_uint32 minStat = 0;
00769 
00770    if (gDebug > 2)
00771       Info("GlobusGetCredHandle", "Enter: LocalEnv: %d", localEnv);
00772 
00773    if (localEnv == 2) {
00774       // If we are a PROOF Master autheticating vs Slaves
00775       // we only need to fetch the delegated credentials
00776       // from the shared memory segment the first time we are called ...
00777       if (gGlbDelCredHandle == GSS_C_NO_CREDENTIAL) {
00778          if (GlobusGetDelCred()) {
00779             if (gDebug > 0)
00780                Error("GlobusGetCredHandle",
00781                   "unable to fetch valid credentials from the shared memory segment");
00782             retval = 1;
00783             goto exit;
00784          }
00785       }
00786       *credHandle = gGlbDelCredHandle;
00787    } else {
00788 
00789       // Inquire Globus credentials:
00790       // This is looking to file X509_USER_PROXY for valid a X509 cert
00791       // (default /tmp/x509up_u<uid> )
00792       if ((majStat =
00793            globus_gss_assist_acquire_cred(&minStat, GSS_C_INITIATE,
00794                                           credHandle)) != GSS_S_COMPLETE) {
00795 
00796          // Check if interactive session
00797          if (isatty(0) && isatty(1)) {
00798 
00799            // Check special settings for the certificates
00800            TString det;
00801            GlobusGetDetails(localEnv, 1, det);
00802 
00803            if (gDebug > 3) {
00804                GlobusError("GlobusNameFromCred: gss_display_name",
00805                      majStat, minStat, 0);
00806                Info("GlobusGetCredHandle",
00807                     "Failed to acquire credentials: trying to initialize proxies ...");
00808             }
00809 
00810             // Try to get credentials with usual command line ...
00811             // First check if there are special requests for proxy duration ...
00812             TString initDur(gEnv->GetValue("Globus.ProxyDuration", "default"));
00813             if (!initDur.Contains("default")) {
00814                initDur.Insert(0,"-hours ");
00815                if (gDebug > 2)
00816                   Info("GlobusGetCredHandle", "initDur: %s (%s)", initDur.Data(),
00817                       gEnv->GetValue("Globus.ProxyDuration", "default"));
00818             } else
00819                initDur = TString("");
00820 
00821             // ... and for number of bits in key ...
00822             TString initBit(gEnv->GetValue("Globus.ProxyKeyBits", "default"));
00823             if (!initBit.Contains("default")) {
00824                initBit.Insert(0,"-bits ");
00825                if (gDebug > 2)
00826                   Info("GlobusGetCredHandle", "initBit: %s (%s)", initBit.Data(),
00827                       gEnv->GetValue("Globus.ProxyKeyBits", "default"));
00828             } else
00829                initBit = TString("");
00830 
00831             // ... and the proxy ...
00832             TString initPxy;
00833             if (gSystem->Getenv("X509_USER_PROXY")) {
00834                initPxy = Form("-out %s", gSystem->Getenv("X509_USER_PROXY"));
00835                if (gDebug > 3)
00836                   Info("GlobusGetCredHandle", "initPxy: %s", initPxy.Data());
00837             }
00838 
00839             // ... and environment variables
00840             TString initEnv(Form("export X509_CERT_DIR=%s",
00841                gSystem->Getenv("X509_CERT_DIR")));
00842             initEnv += TString(Form("; export X509_USER_CERT=%s",
00843                gSystem->Getenv("X509_USER_CERT")));
00844             initEnv += TString(Form("; export X509_USER_KEY=%s",
00845                gSystem->Getenv("X509_USER_KEY")));
00846             if (gDebug > 3)
00847                Info("GlobusGetCredHandle", "initEnv: %s", initEnv.Data());
00848 
00849             // to execute command to initiate the proxies one needs
00850             // to source the globus shell environment
00851             TString proxyInit;
00852             if (gSystem->Getenv("GLOBUS_LOCATION"))
00853                proxyInit = TString("source $GLOBUS_LOCATION/etc/globus-user-env.sh; ");
00854             proxyInit += initEnv;
00855             proxyInit += Form("; grid-proxy-init %s %s %s",
00856                                initDur.Data(), initBit.Data(), initPxy.Data());
00857             gSystem->Exec(proxyInit);
00858 
00859             //  retry now
00860             if ((majStat =
00861                  globus_gss_assist_acquire_cred(&minStat, GSS_C_INITIATE,
00862                                                 credHandle)) !=
00863                 GSS_S_COMPLETE) {
00864                if (gDebug > 0)
00865                   GlobusError("GlobusGetCredHandle: gss_assist_acquire_cred",
00866                            majStat, minStat, 0);
00867                retval = 3;
00868                goto exit;
00869             }
00870          } else {
00871             Warning("GlobusGetCredHandle",
00872                     "not a tty: cannot prompt for credentials, returning failure");
00873             retval = 3;
00874             goto exit;
00875          }
00876       }
00877    }
00878 
00879  exit:
00880    return retval;
00881 }
00882 
00883 //______________________________________________________________________________
00884 void GlobusGetDetails(Int_t localEnv, Int_t opt, TString &details)
00885 {
00886    // Resolve the details string from localEnv. If opt == 0 just fill the string,
00887    // otherwise initialize the envs, prompting the user, if needed
00888    // Returns 0 is successfull, 1 otherwise.
00889 
00890    if (localEnv < 2) {
00891 
00892       // User settings
00893       Int_t reUse = TAuthenticate::GetAuthReUse();
00894       Int_t prompt = TAuthenticate::GetPromptUser();
00895       if (gDebug > 2)
00896          Info("GlobusGetDetails", "prompt: %d, reUse: %d", prompt, reUse);
00897 
00898       // System defaults
00899       TString ddir = "~/.globus";
00900       TString dcer = "usercert.pem";
00901       TString dkey = "userkey.pem";
00902       TString dadi = "/etc/grid-security/certificates";
00903 
00904       // User defaults
00905       if (strlen(TAuthenticate::GetDefaultUser()) > 0) {
00906          TString dets = TAuthenticate::GetDefaultUser();
00907          TString t;
00908          Int_t from = 0;
00909          while (dets.Tokenize(t,from," ")) {
00910             if (t.BeginsWith("cd:"))
00911                ddir = t.ReplaceAll("cd:", "");
00912             else if (t.BeginsWith("cf:"))
00913                dcer = t.ReplaceAll("cf:", "");
00914             else if (t.BeginsWith("kf:"))
00915                dkey = t.ReplaceAll("kf:", "");
00916             else if (t.BeginsWith("ad:"))
00917                dadi = t.ReplaceAll("ad:", "");
00918          }
00919       }
00920 
00921       // Check if needs to prompt the client
00922       if (TAuthenticate::GetPromptUser()) {
00923          TString ppt(Form(" Local Globus settings (%s %s %s %s)\n"
00924                           " Enter <key>:<new value> to change: ",
00925                           ddir.Data(), dcer.Data(), dkey.Data(), dadi.Data()));
00926 
00927          TString indet;
00928          if (!gROOT->IsProofServ()) {
00929             indet = Getline(ppt);
00930             // get rid of \n
00931             indet.Remove(TString::kTrailing, '\n');
00932             if (indet.Length() > 0) {
00933                TString t;
00934                Int_t from = 0;
00935                while (indet.Tokenize(t,from," ")) {
00936                   if (t.BeginsWith("cd:"))
00937                      ddir = t.ReplaceAll("cd:", "");
00938                   else if (t.BeginsWith("cf:"))
00939                      dcer = t.ReplaceAll("cf:", "");
00940                   else if (t.BeginsWith("kf:"))
00941                      dkey = t.ReplaceAll("kf:", "");
00942                   else if (t.BeginsWith("ad:"))
00943                      dadi = t.ReplaceAll("ad:", "");
00944                }
00945             }
00946          } else {
00947             Warning("GlobusGetDetails",
00948                     "proofserv: cannot prompt for info");
00949          }
00950       }
00951 
00952       // Build Details
00953       details = Form("pt:%d ru:%d %s %s %s %s",
00954                      TAuthenticate::GetPromptUser(),
00955                      TAuthenticate::GetAuthReUse(),
00956                      ddir.Data(), dcer.Data(), dkey.Data(), dadi.Data());
00957 
00958       // Set the envs, if required
00959       if (opt > 0) {
00960 
00961          // Perform "~" expansion ...
00962          gSystem->ExpandPathName(ddir);
00963          gSystem->ExpandPathName(dcer);
00964          gSystem->ExpandPathName(dkey);
00965          gSystem->ExpandPathName(dadi);
00966 
00967          // or allow for paths relative to .globus
00968          if (!ddir.BeginsWith("/"))
00969             ddir.Insert(0, Form("%s/.globus/", gSystem->HomeDirectory()));
00970          if (!dcer.BeginsWith("/"))
00971             dcer.Insert(0, Form("%s/", ddir.Data()));
00972          if (!dkey.BeginsWith("/"))
00973             dkey.Insert(0, Form("%s/", ddir.Data()));
00974          if (!dadi.BeginsWith("/"))
00975             dadi.Insert(0, Form("%s/.globus/", gSystem->HomeDirectory()));
00976 
00977          if (gDebug > 3)
00978             Info("GlobusSetCertificates", "after expansion: %s %s %s",
00979                  dcer.Data(), dkey.Data(), dadi.Data());
00980          // Save them
00981          gSystem->Setenv("X509_CERT_DIR", dadi);
00982          gSystem->Setenv("X509_USER_CERT", dcer);
00983          gSystem->Setenv("X509_USER_KEY", dkey);
00984       }
00985    }
00986 
00987    // Done
00988    return;
00989 }
00990 
00991 //______________________________________________________________________________
00992 Int_t GlobusIssuerName(TString &issuerName)
00993 {
00994    // Get issuer name from the certificate read either from the
00995    // certificate file or from the proxy file.
00996    // Returns 0 is successfull, 1 otherwise.
00997 
00998    if (gDebug > 2)
00999       Info("GlobusIssuerName", "enter");
01000 
01001    // Locate the relevant file
01002    TString fn = gSystem->Getenv("X509_USER_PROXY");
01003    if (fn.Length() <= 0)
01004       fn = Form("/tmp/x509up_u%d",gSystem->GetUid());
01005    if (gSystem->AccessPathName(fn, kReadPermission)) {
01006       TString emsg = Form("cannot read requested file(s): %s ", fn.Data());
01007       // Not available: try the certificate file itself
01008       fn = gSystem->Getenv("X509_USER_CERT");
01009       if (fn.Length() <= 0)
01010          fn = Form("%s/.globus/usercert.pem",gSystem->HomeDirectory());
01011       if (gSystem->AccessPathName(fn, kReadPermission)) {
01012          emsg += fn;
01013          Error("GlobusIssuerName", emsg.Data());
01014          return 1;
01015       }
01016    }
01017 
01018    // Load the certificate ...
01019    X509 *xcert = 0;
01020    FILE *fcert = fopen(fn.Data(), "r");
01021    if (!fcert) {
01022       Error("GlobusIssuerName", "unable to open file %s", fn.Data());
01023       return 1;
01024    }
01025 
01026    // Read certificate(s) from the file
01027    Bool_t notfound = kTRUE;
01028    while (notfound && PEM_read_X509(fcert, &xcert, 0, 0)) {
01029       // Retrieve issuer name
01030       char *in = X509_NAME_oneline(X509_get_issuer_name(xcert), 0, 0);
01031       // Retrieve subject name
01032       char *cn = X509_NAME_oneline(X509_get_subject_name(xcert), 0, 0);
01033       if (strncmp(in, cn, strlen(in))) {
01034          // This is the certificate
01035          issuerName = in;
01036          notfound = kFALSE;
01037       }
01038       free(in); free(cn);
01039    }
01040    fclose(fcert);
01041 
01042    // Notify failure
01043    if (notfound) {
01044       Error("GlobusIssuerName", "certificate not found in file %s", fn.Data());
01045       return 1;
01046    }
01047 
01048    // Notify
01049    if (gDebug > 2)
01050       Info("GlobusIssuerName", "issuer name: %s", issuerName.Data());
01051 
01052    // Successful
01053    return 0;
01054 }

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