TKSocket.cxx

Go to the documentation of this file.
00001 // @(#)root/krb5auth:$Id: TKSocket.cxx 35173 2010-09-06 14:47:56Z rdm $
00002 // Author: Maarten Ballintijn   27/10/2003
00003 
00004 #include <stdlib.h>
00005 #include <errno.h>
00006 #include <sys/types.h>
00007 #include <netinet/in.h>
00008 
00009 #include "TKSocket.h"
00010 #include "TSocket.h"
00011 #include "TError.h"
00012 
00013 
00014 extern "C" {
00015 // missing from "krb5.h"
00016 extern int krb5_net_read(/*IN*/ krb5_context context, int fd,
00017                          /*OUT*/ char *buf,/*IN*/ int len);
00018 
00019 extern int krb5_net_write(/*IN*/ krb5_context context, int fd,
00020                           const char *buf, int len);
00021 }
00022 
00023 
00024 ClassImp(TKSocket)
00025 
00026 
00027 krb5_context TKSocket::fgContext = 0;
00028 krb5_ccache TKSocket::fgCCDef = 0;
00029 krb5_principal TKSocket::fgClient = 0;
00030 
00031 //______________________________________________________________________________
00032 TKSocket::TKSocket(TSocket *s)
00033    : fSocket(s), fServer(0), fAuthContext(0)
00034 {
00035    // Constructor
00036 
00037 }
00038 
00039 //______________________________________________________________________________
00040 TKSocket::~TKSocket()
00041 {
00042    // Destructor
00043 
00044    krb5_free_principal(fgContext, fServer);
00045    krb5_auth_con_free(fgContext, fAuthContext);
00046    delete fSocket;
00047 }
00048 
00049 //______________________________________________________________________________
00050 TKSocket *TKSocket::Connect(const char *server, Int_t port)
00051 {
00052    // Connect to 'server' on 'port'
00053 
00054    Int_t rc;
00055 
00056    if (fgContext == 0) {
00057       rc = krb5_init_context(&fgContext);
00058       if (rc != 0) {
00059          ::Error("TKSocket::Connect","while initializing krb5 (%d), %s",
00060                  rc, error_message(rc));
00061          return 0;
00062       }
00063 
00064       rc = krb5_cc_default(fgContext, &fgCCDef);
00065       if (rc != 0) {
00066          ::Error("TKSocket::Connect","while getting default credential cache (%d), %s",
00067                  rc, error_message(rc));
00068          krb5_free_context(fgContext); fgContext = 0;
00069          return 0;
00070       }
00071 
00072       rc = krb5_cc_get_principal(fgContext, fgCCDef, &fgClient);
00073       if (rc != 0) {
00074          ::Error("TKSocket::Connect","while getting client principal from %s (%d), %s",
00075                  krb5_cc_get_name(fgContext,fgCCDef), rc, error_message(rc));
00076          krb5_cc_close(fgContext,fgCCDef); fgCCDef = 0;
00077          krb5_free_context(fgContext); fgContext = 0;
00078          return 0;
00079       }
00080    }
00081 
00082    TSocket  *s = new TSocket(server, port);
00083 
00084    if (!s->IsValid()) {
00085       ::SysError("TKSocket::Connect","Cannot connect to %s:%d", server, port);
00086       delete s;
00087       return 0;
00088    }
00089 
00090    TKSocket *ks = new TKSocket(s);
00091 
00092    rc = krb5_sname_to_principal(fgContext, server, "host", KRB5_NT_SRV_HST, &ks->fServer);
00093    if (rc != 0) {
00094       ::Error("TKSocket::Connect","while getting server principal (%d), %s",
00095               rc, error_message(rc));
00096       delete ks;
00097       return 0;
00098    }
00099 
00100    krb5_data cksum_data;
00101    cksum_data.data = StrDup(server);
00102    cksum_data.length = strlen(server);
00103 
00104    krb5_error *err_ret;
00105    krb5_ap_rep_enc_part *rep_ret;
00106 
00107    int sock = ks->fSocket->GetDescriptor();
00108    rc = krb5_sendauth(fgContext, &ks->fAuthContext, (krb5_pointer) &sock,
00109                       (char *)"KRB5_TCP_Python_v1.0", fgClient, ks->fServer,
00110                       AP_OPTS_MUTUAL_REQUIRED,
00111                       &cksum_data,
00112                       0,           /* no creds, use ccache instead */
00113                       fgCCDef, &err_ret, &rep_ret, 0);
00114 
00115    delete [] cksum_data.data;
00116 
00117    if (rc != 0) {
00118       ::Error("TKSocket::Connect","while sendauth (%d), %s",
00119               rc, error_message(rc));
00120       delete ks;
00121       return 0;
00122    }
00123 
00124    return ks;
00125 }
00126 
00127 //______________________________________________________________________________
00128 Int_t TKSocket::BlockRead(char *&buf, EEncoding &type)
00129 {
00130    // Read block on information from server. The result is stored in buf.
00131    // The number of read bytes is returned; -1 is returned in case of error.
00132 
00133    Int_t rc;
00134    Desc_t desc;
00135    Int_t fd = fSocket->GetDescriptor();
00136 
00137    rc = krb5_net_read(fgContext, fd, (char *)&desc, sizeof(desc));
00138    if (rc == 0) errno = ECONNABORTED;
00139 
00140    if (rc <= 0) {
00141       SysError("BlockRead","reading descriptor (%d), %s",
00142                rc, error_message(rc));
00143       return -1;
00144    }
00145 
00146    type = static_cast<EEncoding>(ntohs(desc.fType));
00147 
00148    krb5_data enc;
00149    enc.length = ntohs(desc.fLength);
00150    enc.data = new char[enc.length+1];
00151 
00152    rc = krb5_net_read(fgContext, fd, enc.data, enc.length);
00153    enc.data[enc.length] = 0;
00154 
00155    if (rc == 0) errno = ECONNABORTED;
00156 
00157    if (rc <= 0) {
00158       SysError("BlockRead","reading data (%d), %s",
00159                rc, error_message(rc));
00160       return -1;
00161    }
00162 
00163    krb5_data out;
00164    switch (type) {
00165    case kNone:
00166       buf = enc.data;
00167       rc = enc.length;
00168       break;
00169    case kSafe:
00170       rc = krb5_rd_safe(fgContext, fAuthContext, &enc, &out, 0);
00171       break;
00172    case kPriv:
00173       rc = krb5_rd_priv(fgContext, fAuthContext, &enc, &out, 0);
00174       break;
00175    default:
00176       Error("BlockWrite","unknown encoding type (%d)", type);
00177       return -1;
00178    }
00179 
00180    if (type != kNone) {
00181       // copy data to buffer that is new'ed
00182       buf = new char[out.length+1];
00183       memcpy(buf, out.data, out.length);
00184       buf[out.length] = 0;
00185       free(out.data);
00186       delete [] enc.data;
00187       rc = out.length;
00188    }
00189 
00190    return rc;
00191 }
00192 
00193 //______________________________________________________________________________
00194 Int_t TKSocket::BlockWrite(const char *buf, Int_t length, EEncoding type)
00195 {
00196    // Block-send 'length' bytes to server from 'buf'.
00197 
00198    Desc_t desc;
00199    krb5_data in;
00200    krb5_data enc;
00201    Int_t rc;
00202    in.data = const_cast<char*>(buf);
00203    in.length = length;
00204 
00205    switch (type) {
00206    case kNone:
00207       enc.data = in.data;
00208       enc.length = in.length;
00209       break;
00210    case kSafe:
00211       rc = krb5_mk_safe(fgContext, fAuthContext, &in, &enc, 0);
00212       break;
00213    case kPriv:
00214       rc = krb5_mk_priv(fgContext, fAuthContext, &in, &enc, 0);
00215       break;
00216    default:
00217       Error("BlockWrite","unknown encoding type (%d)", type);
00218       return -1;
00219    }
00220 
00221    desc.fLength = htons(enc.length);
00222    desc.fType = htons(type);
00223 
00224    Int_t fd = fSocket->GetDescriptor();
00225    rc = krb5_net_write(fgContext, fd, (char *)&desc, sizeof(desc));
00226    if (rc <= 0) {
00227       Error("BlockWrite","writing descriptor (%d), %s",
00228             rc, error_message(rc));
00229       return -1;
00230    }
00231 
00232    rc = krb5_net_write(fgContext, fd, (char *)enc.data, enc.length);
00233    if (rc <= 0) {
00234       Error("BlockWrite","writing data (%d), %s",
00235             rc, error_message(rc));
00236       return -1;
00237    }
00238 
00239    if (type != kNone) free(enc.data);
00240 
00241    return rc;
00242 }

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