Krb5Auth.cxx

Go to the documentation of this file.
00001 // @(#)root/krb5auth:$Id: Krb5Auth.cxx 36145 2010-10-07 10:38:16Z ganis $
00002 // Author: Johannes Muelmenstaedt  17/03/2002
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 copied from the MIT krb5 distribution and
00013  * are subject to the following license:
00014  *
00015  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
00016  * All Rights Reserved.
00017  *
00018  * Export of this software from the United States of America may
00019  *   require a specific license from the United States Government.
00020  *   It is the responsibility of any person or organization contemplating
00021  *   export to obtain such a license before exporting.
00022  *
00023  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
00024  * distribute this software and its documentation for any purpose and
00025  * without fee is hereby granted, provided that the above copyright
00026  * notice appear in all copies and that both that copyright notice and
00027  * this permission notice appear in supporting documentation, and that
00028  * the name of M.I.T. not be used in advertising or publicity pertaining
00029  * to distribution of the software without specific, written prior
00030  * permission.  Furthermore if you modify this software you must label
00031  * your software as modified software and not distribute it in such a
00032  * fashion that it might be confused with the original M.I.T. software.
00033  * M.I.T. makes no representations about the suitability of
00034  * this software for any purpose.  It is provided "as is" without express
00035  * or implied warranty.
00036  *
00037  */
00038 
00039 #include <errno.h>
00040 #include <signal.h>
00041 #include <string.h>
00042 #include <sys/socket.h>
00043 #include <netinet/in.h>
00044 #include <netdb.h>
00045 #include <time.h>
00046 
00047 #include "Krb5Auth.h"
00048 #include "TSocket.h"
00049 #include "TAuthenticate.h"
00050 #include "TDatime.h"
00051 #include "TROOT.h"
00052 #include "THostAuth.h"
00053 #include "TError.h"
00054 #include "TSystem.h"
00055 #include "TEnv.h"
00056 #include "NetErrors.h"
00057 #include "Getline.h"
00058 
00059 #if defined(R__KRB5_NEED_VCST_DEFINE)
00060 #define krb5_c_valid_cksumtype valid_cksumtype
00061 #endif
00062 #if defined(R__KRB5_NEED_VCST_PROTO)
00063 krb5_boolean krb5_c_valid_cksumtype(krb5_cksumtype ctype);
00064 #endif
00065 
00066 Int_t Krb5Authenticate(TAuthenticate *, TString &, TString &, Int_t);
00067 
00068 static Int_t Krb5InitCred(const char *clientPrincipal, Bool_t promptPrinc = kFALSE);
00069 static Int_t Krb5CheckCred(krb5_context, krb5_ccache, TString, TDatime &);
00070 static Int_t Krb5CheckSecCtx(const char *, TRootSecContext *);
00071 
00072 class TKrb5AuthInit {
00073 public:
00074    TKrb5AuthInit() { TAuthenticate::SetKrb5AuthHook(&Krb5Authenticate); }
00075 };
00076 static TKrb5AuthInit gKrb5authInit;
00077 
00078 class TKrb5CleanUp {
00079 public:
00080    Bool_t                fSignal;
00081    krb5_context          fContext;
00082    krb5_ccache           fCcdef;
00083    krb5_principal        fClient;
00084    krb5_principal        fServer;
00085    krb5_auth_context     fAuthContext;
00086    krb5_ap_rep_enc_part *fRepRet;
00087    char                 *fData;
00088 
00089    TKrb5CleanUp() : fSignal(false), fContext(0), fCcdef(0), fClient(0),
00090       fServer(0), fAuthContext(0), fRepRet(0), fData(0) {
00091    }
00092 
00093    ~TKrb5CleanUp() {
00094       if (fSignal) gSystem->IgnoreSignal(kSigPipe, kFALSE);
00095 
00096       if (fData) free(fData);
00097       if (fRepRet) krb5_free_ap_rep_enc_part(fContext, fRepRet);
00098 
00099       if (fAuthContext) krb5_auth_con_free(fContext, fAuthContext);
00100 
00101       if (fServer) krb5_free_principal(fContext, fServer);
00102       if (fClient) krb5_free_principal(fContext, fClient);
00103 
00104 
00105       if (fCcdef)   krb5_cc_close(fContext, fCcdef);
00106       if (fContext) krb5_free_context(fContext);
00107    }
00108 };
00109 
00110 
00111 //______________________________________________________________________________
00112 Int_t Krb5Authenticate(TAuthenticate *auth, TString &user, TString &det,
00113                        Int_t version)
00114 {
00115    // Kerberos v5 authentication code. Returns 0 in case authentication
00116    // failed, 1 in case of success and 2 in case remote does not support
00117    // Kerberos5.
00118    // Protocol 'version':  3    supports alternate username
00119    //                      2    supports negotiation and auth reuse
00120    //                      1    first kerberos implementation
00121    //                      0    no kerberos support (function should not be called)
00122    // user is used to input the target username and return the name in the
00123    // principal used
00124 
00125 
00126    TKrb5CleanUp cleanup;
00127 
00128    int retval;
00129    int kind;
00130    TSocket *sock = auth->GetSocket();
00131 
00132    char answer[256];
00133    int type;
00134    Int_t nsen = 0, nrec = 0;
00135 
00136    TString targetUser(user);
00137    TString localUser;
00138    // The default will be the one related to the logged user
00139    UserGroup_t *u = gSystem->GetUserInfo();
00140    if (u) {
00141       localUser = u->fUser;
00142       delete u;
00143    } else
00144       localUser = TAuthenticate::GetDefaultUser();
00145    Bool_t promptPrinc = (targetUser != localUser);
00146 
00147    // first check if protocol version supports kerberos, krb5 support
00148    // was introduced in rootd version 6
00149    // This checked in the calling rootines and the result is contained in
00150    // the argument 'version'
00151    if (version <= 0) return 2; // ... but you shouldn't have got here ...
00152 
00153    // get a context
00154    krb5_context context;
00155    retval = krb5_init_context(&context);
00156    cleanup.fContext = context;
00157 
00158    if (retval) {
00159       Error("Krb5Authenticate","failed <krb5_init_context>: %s\n",
00160             error_message(retval));
00161       return -1;
00162    }
00163 
00164    // ignore broken connection signal handling
00165    gSystem->IgnoreSignal(kSigPipe, kTRUE);
00166    cleanup.fSignal = kTRUE;
00167 
00168    // get our credentials cache
00169    krb5_ccache ccdef;
00170    if (gDebug > 2) {
00171       if (gSystem->Getenv("KRB5CCNAME"))
00172          Info("Krb5Authenticate",
00173               "Use credential file from $KRB5CCNAME: %s\n",
00174               gSystem->Getenv("KRB5CCNAME"));
00175       else
00176          Info("Krb5Authenticate",
00177               "Use default credential file ($KRB5CCNAME undefined)");
00178    }
00179    if ((retval = krb5_cc_default(context, &ccdef))) {
00180       Error("Krb5Authenticate","failed <krb5_cc_default>: %s\n",
00181             error_message(retval));
00182       return -1;
00183    }
00184    cleanup.fCcdef = ccdef;
00185 
00186    // get our principal from the cache
00187    krb5_principal client;
00188    TString principal = TString(TAuthenticate::GetKrb5Principal());
00189    Bool_t gotPrincipal = (principal.Length() > 0) ? kTRUE : kFALSE;
00190    //
00191    // if not defined or incomplete, complete with defaults;
00192    // but only if interactive
00193    if (!principal.Length() || !principal.Contains("@")) {
00194       if (gDebug > 3)
00195          Info("Krb5Authenticate",
00196               "incomplete principal: complete using defaults");
00197       krb5_principal default_princ;
00198 
00199       if (!principal.Length()) {
00200          // Try the default user
00201          if ((retval = krb5_parse_name(context, localUser.Data(),
00202                                        &default_princ))) {
00203             Error("Krb5Authenticate","failed <krb5_parse_name>: %s\n",
00204                                         error_message(retval));
00205          }
00206       } else {
00207          // Try first the name specified
00208          if ((retval = krb5_parse_name(context, principal.Data(),
00209                                        &default_princ))) {
00210             TString errmsg = TString(Form("First: %s",error_message(retval)));
00211             // Try the default user in case of failure
00212             if ((retval = krb5_parse_name(context, localUser.Data(),
00213                                            &default_princ))) {
00214                errmsg.Append(Form("- Second: %s",error_message(retval)));
00215                Error("Krb5Authenticate","failed <krb5_parse_name>: %s\n",
00216                                         errmsg.Data());
00217             }
00218          }
00219       }
00220       //
00221       // If successful, we get the string principal
00222       if (!retval) {
00223          char *default_name;
00224          if ((retval = krb5_unparse_name(context, default_princ, &default_name))) {
00225                Error("Krb5Authenticate","failed <krb5_unparse_name>: %s\n",
00226                      error_message(retval));
00227          } else {
00228             principal = TString(default_name);
00229             free(default_name);
00230          }
00231          krb5_free_principal(context, default_princ);
00232       }
00233    }
00234    // Notify
00235    if (gDebug > 3) {
00236       if (gotPrincipal)
00237          Info("Krb5Authenticate",
00238               "user requested principal: %s", principal.Data());
00239       else
00240          Info("Krb5Authenticate",
00241               "default principal: %s", principal.Data());
00242    }
00243 
00244    if ((retval = krb5_cc_get_principal(context, ccdef, &client))) {
00245 
00246       if (isatty(0) && isatty(1)) {
00247 
00248          if (gDebug > 1)
00249             Info("Krb5Authenticate",
00250                  "valid credentials not found: try initializing (Principal: %s)",
00251                  principal.Data());
00252          if (Krb5InitCred(principal, promptPrinc)) {
00253             Error("Krb5Authenticate","error executing kinit");
00254             return -1;
00255          }
00256          if ((retval = krb5_cc_get_principal(context, ccdef, &client))) {
00257             Error("Krb5Authenticate","failed <krb5_cc_get_principal>: %s\n",
00258                   error_message(retval));
00259             return -1;
00260          }
00261       } else {
00262          Warning("Krb5Authenticate",
00263                  "not a tty: cannot prompt for credentials, returning failure");
00264          return -1;
00265       }
00266    }
00267 
00268    // If a principal was specified by the user, we must check that the
00269    // principal for which we have a cached ticket is the one that we want
00270    TString ticketPrincipal =
00271       TString(Form("%.*s@%.*s",client->data->length, client->data->data,
00272                                client->realm.length, client->realm.data));
00273    if (gotPrincipal) {
00274 
00275       // If interactive require the ticket principal to be the same as the
00276       // required or default one
00277       if (isatty(0) && isatty(1) && principal != ticketPrincipal) {
00278          if (gDebug > 3)
00279             Info("Krb5Authenticate",
00280                  "got credentials for different principal %s - try"
00281                  " initialization credentials for principal: %s",
00282                  ticketPrincipal.Data(), principal.Data());
00283          if (Krb5InitCred(principal)) {
00284             Error("Krb5Authenticate","error executing kinit");
00285             return -1;
00286          }
00287          if ((retval = krb5_cc_get_principal(context, ccdef, &client))) {
00288             Error("Krb5Authenticate","failed <krb5_cc_get_principal>: %s\n",
00289                   error_message(retval));
00290             return -1;
00291          }
00292          // This may have changed
00293          ticketPrincipal =
00294              TString(Form("%.*s@%.*s",client->data->length, client->data->data,
00295                                       client->realm.length, client->realm.data));
00296       }
00297    }
00298 
00299    cleanup.fClient = client;
00300 
00301    TDatime expDate;
00302    if (Krb5CheckCred(context, ccdef, ticketPrincipal, expDate) != 1) {
00303 
00304       // If the ticket expired we tray to re-initialize it for the same
00305       // principal, which may be different from the default
00306 
00307       if (isatty(0) && isatty(1)) {
00308 
00309          if (gDebug >2)
00310             Info("Krb5Authenticate",
00311                  "credentials found have expired: try initializing"
00312                  " (Principal: %s)", ticketPrincipal.Data());
00313          if (Krb5InitCred(ticketPrincipal)) {
00314             Error("Krb5Authenticate","error executing kinit");
00315             return -1;
00316          }
00317          if ((retval = krb5_cc_get_principal(context, ccdef, &client))) {
00318             Error("Krb5Authenticate","failed <krb5_cc_get_principal>: %s\n",
00319                   error_message(retval));
00320             return -1;
00321          }
00322          // Check credentials and get expiration time
00323          if (Krb5CheckCred(context, ccdef, ticketPrincipal, expDate) != 1) {
00324             Info("Krb5Authenticate",
00325                  "ticket re-initialization failed for principal %s",
00326                  ticketPrincipal.Data());
00327             return -1;
00328          }
00329       } else {
00330          Warning("Krb5Authenticate",
00331                  "not a tty: cannot prompt for credentials, returning failure");
00332          return -1;
00333       }
00334    }
00335    cleanup.fClient = client;
00336 
00337    // At this point we know which is the principal we will be using
00338    if (gDebug > 3)
00339       Info("Krb5Authenticate",
00340            "using valid ticket for principal: %s", ticketPrincipal.Data());
00341 
00342    // Get a normal string for user
00343    TString normUser(client->data->data, client->data->length);
00344 
00345    if (gDebug > 3) {
00346       Info("Krb5Authenticate", "cc_get_principal: client: %.*s %.*s",
00347            client->data->length, client->data->data,
00348            client->realm.length, client->realm.data);
00349    }
00350 
00351    Int_t reuse = 1, prompt = 0;
00352    TString details;
00353 
00354    if (version > 1) {
00355 
00356       // Check ReUse
00357       reuse  = TAuthenticate::GetAuthReUse();
00358       prompt = TAuthenticate::GetPromptUser();
00359 
00360       // Build auth details
00361       details = Form("pt:%d ru:%d us:%s", prompt, reuse, ticketPrincipal.Data());
00362 
00363       // Create Options string
00364       int opt = reuse * kAUTH_REUSE_MSK +
00365                 auth->GetRSAKeyType() * kAUTH_RSATY_MSK;
00366       TString options(Form("%d %d %s", opt, normUser.Length(), normUser.Data()));
00367 
00368       // Now we are ready to send a request to the rootd/proofd daemons
00369       // to check if we have already a valid security context and
00370       // eventually to start a negotiation to get one ...
00371       kind = kROOTD_KRB5;
00372       retval = reuse;
00373       int rc = 0;
00374       if ((rc = auth->AuthExists(ticketPrincipal, TAuthenticate::kKrb5,
00375                 options, &kind, &retval, &Krb5CheckSecCtx)) == 1) {
00376          // A valid authentication exists: we are done ...
00377          return 1;
00378       }
00379       if (rc == -2) {
00380          return rc;
00381       }
00382 
00383       if (kind == kROOTD_ERR) {
00384          TString serv = "sockd";
00385          if (strstr(auth->GetProtocol(),"root"))
00386             serv = "rootd";
00387          if (strstr(auth->GetProtocol(),"proof"))
00388             serv = "proofd";
00389          if (retval == kErrConnectionRefused) {
00390             if (gDebug > 0)
00391                Error("Krb5Authenticate",
00392                   "%s@%s does not accept connections from %s%s",
00393                   serv.Data(), auth->GetRemoteHost(),
00394                   auth->GetUser(), gSystem->HostName());
00395             return -2;
00396          } else if (retval == kErrNotAllowed) {
00397             if (gDebug > 0)
00398                Error("Krb5Authenticate",
00399                   "%s@%s does not accept %s authentication from %s@%s",
00400                   serv.Data(), auth->GetRemoteHost(),
00401                   TAuthenticate::GetAuthMethod(2),
00402                   auth->GetUser(), gSystem->HostName());
00403          } else
00404             TAuthenticate::AuthError("Krb5Authenticate", retval);
00405          return 0;
00406       }
00407 
00408    } else {
00409 
00410       nsen = sock->Send(kROOTD_KRB5);
00411       if (nsen <= 0) {
00412          Error("Krb5Authenticate","Sending kROOTD_KRB5");
00413          return 0;
00414       }
00415       nrec = sock->Recv(retval, kind);
00416       if (nrec <= 0) {
00417          Error("Krb5Authenticate","Receiving kROOTD_KRB5");
00418          return 0;
00419       }
00420 
00421       // retval == 0 when no Krb5 support compiled in remote rootd
00422       if (retval == 0 || kind != kROOTD_KRB5)
00423          return 2;
00424    }
00425 
00426    // ok, krb5 is supported
00427    // ignore broken connection signal handling
00428    gSystem->IgnoreSignal(kSigPipe, kTRUE);
00429    cleanup.fSignal = kFALSE;
00430 
00431    // test for CRC-32
00432    if (!krb5_c_valid_cksumtype(CKSUMTYPE_CRC32)) {
00433       Error("Krb5Authenticate","failed <krb5_c_valid_cksumtype>: %s\n",
00434                   error_message(KRB5_PROG_SUMTYPE_NOSUPP));
00435       return 0;
00436    }
00437 
00438    // get service principal from service and host names --
00439    // hard coding of service names avoids having the have these
00440    // services in the local /etc/services file
00441    TString service = TString("host");
00442 
00443    TString serv_host(sock->GetInetAddress().GetHostName());
00444    krb5_principal server;
00445 
00446    if (gDebug > 3)
00447       Info("Krb5Authenticate","serv_host: %s service: %s",
00448            serv_host.Data(),service.Data());
00449 
00450    if ((retval = krb5_sname_to_principal(context, serv_host.Data(),
00451                  service.Data(), KRB5_NT_SRV_HST, &server))) {
00452 
00453       Error("Krb5Authenticate","failed <krb5_sname_to_principal>: %s\n",
00454              error_message(retval));
00455       return 0;
00456    }
00457    cleanup.fServer = server;
00458 
00459    if (gDebug > 3) {
00460       Info("Krb5Authenticate","sname_to_principal: server: %.*s %.*s",
00461            server->data->length, server->data->data,
00462            server->realm.length, server->realm.data);
00463    }
00464 
00465    // authenticate
00466    krb5_auth_context auth_context = 0;
00467    int sockd = sock->GetDescriptor();
00468    char proto_version[100] = "krootd_v_1";
00469    krb5_data cksum_data;
00470    cksum_data.data = (char *)serv_host.Data(); // eeew yuck
00471    cksum_data.length = serv_host.Length();
00472    krb5_error *err_ret;
00473    krb5_ap_rep_enc_part *rep_ret;
00474 
00475    retval = krb5_auth_con_init(context, &auth_context);
00476    if (retval)
00477       Error("Krb5Authenticate","failed auth_con_init: %s\n",
00478             error_message(retval));
00479    cleanup.fAuthContext = auth_context;
00480 
00481    retval = krb5_auth_con_setflags(context, auth_context,
00482                                    KRB5_AUTH_CONTEXT_RET_TIME);
00483    if (retval)  Error("Krb5Authenticate","failed auth_con_setflags: %s\n",
00484                       error_message(retval));
00485 
00486    if (gDebug > 1)
00487      Info("Krb5Authenticate",
00488           "Sending kerberos authentification to %s",
00489           serv_host.Data());
00490 
00491    retval = krb5_sendauth(context, &auth_context, (krb5_pointer)&sockd,
00492                           proto_version, client, server,
00493                           AP_OPTS_MUTUAL_REQUIRED,
00494                           &cksum_data,
00495                           0, // not rolling our own creds, using ccache
00496                           ccdef, &err_ret, &rep_ret, 0); // ugh!
00497 
00498    // handle the reply (this is a verbatim copy from the kerberos
00499    // sample client source)
00500    if (retval && retval != KRB5_SENDAUTH_REJECTED) {
00501       Error("Krb5Authenticate","failed <krb5_sendauth>: %s\n",
00502              error_message(retval));
00503       return 0;
00504    }
00505    if (retval == KRB5_SENDAUTH_REJECTED) {
00506       // got an error
00507       Error("Krb5Authenticate", "sendauth rejected, error reply "
00508             "is:\n\t\"%.*s\"",
00509             err_ret->text.length, err_ret->text.data);
00510       return 0;
00511    } else if (!rep_ret) {
00512       // no reply
00513       return 0;
00514    }
00515    cleanup.fRepRet = rep_ret;
00516 
00517    if (version > 2) {
00518 
00519       // Send the targetUser name
00520 
00521      if (gDebug > 0)
00522         Info("Krb5Authenticate","client is %s target is %s",
00523                                 normUser.Data(),targetUser.Data());
00524       nsen = sock->Send(targetUser.Data(), kROOTD_KRB5);
00525       if (nsen <= 0) {
00526          Error("Krb5Authenticate","Sending <targetUser>");
00527          return 0;
00528       }
00529 
00530       // If PROOF, send credentials
00531       if (sock->GetServType() == TSocket::kPROOFD || version < 4) {
00532 
00533          krb5_data outdata;
00534          outdata.data = 0;
00535 
00536          retval = krb5_auth_con_genaddrs(context, auth_context,
00537                        sockd, KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR);
00538 
00539          if (retval) {
00540             Error("Krb5Authenticate","failed auth_con_genaddrs is: %s\n",
00541                   error_message(retval));
00542          }
00543 
00544          retval = krb5_fwd_tgt_creds(context, auth_context, 0 /*host*/,
00545                                      client, server, ccdef, true,
00546                                      &outdata);
00547          if (retval) {
00548             Error("Krb5Authenticate","fwd_tgt_creds failed: %s\n",
00549                   error_message(retval));
00550             return 0;
00551          }
00552 
00553          cleanup.fData = outdata.data;
00554 
00555          if (gDebug > 3)
00556             Info("Krb5Authenticate",
00557                  "Sending kerberos forward ticket to %s %p %d [%d,%d,%d,...]",
00558                  serv_host.Data(), outdata.data, outdata.length,
00559                  outdata.data[0], outdata.data[1], outdata.data[2]);
00560 
00561          // Send length first
00562          char buflen[20];
00563          snprintf(buflen, 20, "%d", outdata.length);
00564          nsen = sock->Send(buflen, kROOTD_KRB5);
00565          if (nsen <= 0) {
00566             Error("Krb5Authenticate","Sending <buflen>");
00567             return 0;
00568          }
00569 
00570          // Send Key. second ...
00571          nsen = sock->SendRaw(outdata.data, outdata.length);
00572          if (nsen <= 0) {
00573             Error("Krb5Authenticate","Sending <Key>");
00574             return 0;
00575          }
00576 
00577          if (gDebug>3)
00578             Info("Krb5Authenticate",
00579                  "For kerberos forward ticket sent %d bytes (expected %d)",
00580                  nsen, outdata.length);
00581       }
00582    }
00583 
00584    // restore attention to broken connection signal handling
00585    gSystem->IgnoreSignal(kSigPipe, kFALSE);
00586 
00587    // returns user@realm
00588    type = kMESS_STRING;
00589    nrec = sock->Recv(answer, 100, type);
00590 
00591    if (type == kROOTD_ERR) {
00592       TAuthenticate::AuthError("Krb5Authenticate", kErrNoHome);
00593       return 0;
00594    }
00595 
00596    if (nrec <= 0) {
00597       Error("Krb5Authenticate","Receiving <user@realm>");
00598       return 0;
00599    }
00600    if (gDebug > 3)
00601       Info("Krb5Auth","%s",answer);
00602 
00603    if (version > 1) {
00604 
00605       // Receive key request
00606       nrec = sock->Recv(retval, type);
00607       if (nrec <= 0) {
00608          Error("Krb5Authenticate","Receiving <key request>");
00609          return 0;
00610       }
00611 
00612       Int_t rsaKey = 0;
00613       if (reuse == 1) {
00614 
00615          if (type != kROOTD_RSAKEY  || retval < 1 || retval > 2 ) {
00616             Error("Krb5Auth",
00617                   "problems recvn RSA key flag: got message %d, flag: %d",
00618                   type, rsaKey);
00619             return 0;
00620          }
00621          rsaKey = retval - 1;
00622 
00623          // Send the key securely
00624          TAuthenticate::SendRSAPublicKey(sock, rsaKey);
00625 
00626          // get length of user + offset string
00627          nrec = sock->Recv(retval, type);
00628          if (nrec <= 0) {
00629             Error("Krb5Authenticate","Receiving <length of user+offset string>");
00630             return 0;
00631          }
00632       }
00633 
00634       if (type != kROOTD_KRB5 || retval < 1) {
00635          Warning("Krb5Auth",
00636                  "problems recvn (user,offset) length (%d:%d bytes:%d)",
00637                   type, retval, nrec);
00638          return 0;
00639       }
00640       char *rfrm = new char[retval+1];
00641       nrec = sock->Recv(rfrm,retval+1, type);  // receive user,offset) info
00642       if (nrec <= 0) {
00643          Error("Krb5Authenticate","Receiving <user+offset string>");
00644          delete[] rfrm;
00645          return 0;
00646       }
00647 
00648       // Parse answer
00649       char lUser[128];
00650       int offset = -1;
00651       sscanf(rfrm,"%127s %d", lUser, &offset);
00652       // Save username
00653       user = lUser;
00654 
00655       // Receive token
00656       char *token = 0;
00657       if (reuse == 1 && offset > -1) {
00658          if (TAuthenticate::SecureRecv(sock, 1, rsaKey, &token) == -1) {
00659             Warning("Krb5Auth",
00660                     "problems secure-receiving token - may result in corrupted token");
00661          }
00662          if (gDebug > 3)
00663             Info("Krb5Auth","received from server: token: '%s' ", token);
00664       } else {
00665          token = StrDup("");
00666       }
00667 
00668       // Create SecContext object
00669       TRootSecContext *ctx =
00670          auth->GetHostAuth()->CreateSecContext((const char *)lUser,
00671              auth->GetRemoteHost(), (Int_t)TAuthenticate::kKrb5, offset,
00672              details, token, expDate, 0, rsaKey);
00673       // Transmit it to TAuthenticate
00674       auth->SetSecContext(ctx);
00675 
00676       det = details;
00677       if (token) delete[] token;
00678    } else {
00679       nrec = sock->Recv(answer, 100, type);  // returns user
00680       if (nrec <= 0) {
00681          Error("Krb5Authenticate","Receiving <user string>");
00682          return 0;
00683       }
00684       user = answer;
00685 
00686       // Get a SecContext for the record and avoid problems
00687       // with fSecContext undefined in TAuthenticate
00688       TRootSecContext *ctx =
00689          auth->GetHostAuth()->CreateSecContext((const char *)user,
00690              auth->GetRemoteHost(), (Int_t)TAuthenticate::kKrb5, -1,
00691              details, 0);
00692       // Transmit it to TAuthenticate
00693       auth->SetSecContext(ctx);
00694    }
00695 
00696    // Receive auth from remote login function
00697    int authok = 0;
00698    nrec = sock->Recv(authok, kind);
00699    if (nrec <= 0) {
00700       Error("Krb5Authenticate", "Receiving <Auth flag>");
00701       return 0;
00702    }
00703 
00704    if (authok && kind == kROOTD_AUTH)
00705       return 1;
00706    return 0;
00707 }
00708 
00709 //______________________________________________________________________________
00710 Int_t Krb5InitCred(const char *clientPrincipal, Bool_t promptPrinc)
00711 {
00712    // Checks if there are valid credentials in the cache.
00713    // If not, tries to initialise them.
00714 
00715    if (gDebug > 2)
00716        Info("Krb5InitCred","enter: %s", clientPrincipal);
00717 
00718    // Check if the user wants to be prompt about principal
00719    TString principal = TString(clientPrincipal);
00720    if (TAuthenticate::GetPromptUser() || promptPrinc) {
00721       char *usr = Getline(Form("Principal (%s): ", principal.Data()));
00722       if (usr[0]) {
00723          usr[strlen(usr) - 1] = 0; // get rid of \n
00724          if (strlen(usr))
00725             principal = usr;
00726       }
00727    }
00728 
00729    // Prepare command
00730    TString cmd;
00731 
00732    if (strlen(R__KRB5INIT) <= 0)
00733       cmd = Form("/usr/kerberos/bin/kinit -f %s", principal.Data());
00734    else
00735       cmd = Form("%s -f %s",R__KRB5INIT, principal.Data());
00736 
00737    if (gDebug > 2)
00738       Info("Krb5InitCred","executing: %s", cmd.Data());
00739    Int_t rc = gSystem->Exec(cmd);
00740    if (rc)
00741       if (gDebug > 0)
00742          Info("Krb5InitCred", "error: return code: %d", rc);
00743    return rc;
00744 }
00745 
00746 //______________________________________________________________________________
00747 Int_t Krb5CheckCred(krb5_context kCont, krb5_ccache Cc,
00748                     TString principal, TDatime &expDate)
00749 {
00750    // Checks if there are valid credentials.
00751 
00752    Int_t retval;
00753    Int_t now = time(0);
00754    Int_t valid = -1;
00755 
00756    TString pdata = principal;
00757    TString prealm = principal;
00758    pdata.Resize(pdata.Index("@"));
00759    prealm.Remove(0,prealm.Index("@")+1);
00760    if (gDebug > 2)
00761       Info("Krb5CheckCred","enter: principal '%s'", principal.Data());
00762 
00763    // Init to now
00764    expDate = TDatime();
00765 
00766    krb5_cc_cursor cur;
00767    if ((retval = krb5_cc_start_seq_get(kCont, Cc, &cur))) {
00768       if (gDebug > 2)
00769          Error("Krb5Authenticate","failed <krb5_cc_start_seq_get>: %s\n",
00770                 error_message(retval));
00771       return 0;
00772    }
00773 
00774    krb5_creds creds;
00775    while (!(retval = krb5_cc_next_cred(kCont, Cc, &cur, &creds)) && valid == -1) {
00776 
00777       if (gDebug > 3) {
00778          Info("Krb5CheckCred","creds.server->length: %d",
00779                creds.server->length);
00780          Info("Krb5CheckCred","Realms data: '%.*s' '%s'",
00781                creds.server->realm.length, creds.server->realm.data,
00782                prealm.Data());
00783          Info("Krb5CheckCred","Srv data[0]: '%.*s' ",
00784                creds.server->data[0].length, creds.server->data[0].data);
00785          Info("Krb5CheckCred","Data data: '%.*s' '%s'",
00786                creds.server->data[1].length, creds.server->data[1].data,
00787                prealm.Data());
00788          Info("Krb5CheckCred","Endtime: %d ", creds.times.endtime);
00789       }
00790 
00791       if (creds.server->length == 2 &&
00792          !strncmp(creds.server->realm.data,
00793                   prealm.Data(),creds.server->realm.length) &&
00794          !strncmp((char *)creds.server->data[0].data,
00795                   "krbtgt",creds.server->data[0].length) &&
00796          !strncmp((char *)creds.server->data[1].data,
00797                   prealm.Data(),creds.server->data[1].length)) {
00798          // Check expiration time
00799          valid = (creds.times.endtime >= now) ? 1 : 0;
00800          // Return expiration time
00801          expDate.Set(creds.times.endtime);
00802       }
00803       krb5_free_cred_contents(kCont, &creds);
00804    }
00805    return valid;
00806 }
00807 
00808 //______________________________________________________________________________
00809 Int_t Krb5CheckSecCtx(const char *principal, TRootSecContext *ctx)
00810 {
00811    // Krb5 version of CheckSecCtx to be passed to TAuthenticate::AuthExists
00812    // Check if principal is matches the one used to instantiate Ctx
00813    // Returns: 1 if ok, 0 if not
00814    // Deactivates Ctx is not valid
00815 
00816    Int_t rc = 0;
00817 
00818    if (ctx->IsActive()) {
00819       if (strstr(ctx->GetID(), principal))
00820          rc = 1;
00821    }
00822    return rc;
00823 }

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