00001
00002
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
00016 extern int krb5_net_read( krb5_context context, int fd,
00017 char *buf, int len);
00018
00019 extern int krb5_net_write( 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
00036
00037 }
00038
00039
00040 TKSocket::~TKSocket()
00041 {
00042
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
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,
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
00131
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
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
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 }