Logo ROOT   6.08/07
Reference Guide
TKSocket.cxx
Go to the documentation of this file.
1 // @(#)root/krb5auth:$Id$
2 // Author: Maarten Ballintijn 27/10/2003
3 
4 #include <stdlib.h>
5 #include <errno.h>
6 #include <sys/types.h>
7 #include <netinet/in.h>
8 #ifndef WIN32
9 # include <unistd.h>
10 #endif
11 
12 #include "TKSocket.h"
13 #include "TSocket.h"
14 #include "TError.h"
15 
16 
17 extern "C" {
18 // missing from "krb5.h"
19 extern int krb5_net_read(/*IN*/ krb5_context context, int fd,
20  /*OUT*/ char *buf,/*IN*/ int len);
21 
22 extern int krb5_net_write(/*IN*/ krb5_context context, int fd,
23  const char *buf, int len);
24 }
25 
26 #ifdef __APPLE__
27 #define SOCKET int
28 #define SOCKET_ERRNO errno
29 #define SOCKET_EINTR EINTR
30 #define SOCKET_READ(a,b,c) read(a,b,c)
31 #define SOCKET_WRITE(a,b,c) write(a,b,c)
32 /*
33  * lib/krb5/os/net_read.c
34  *
35  * Copyright 1987, 1988, 1990 by the Massachusetts Institute of Technology.
36  * All Rights Reserved.
37  *
38  * Export of this software from the United States of America may
39  * require a specific license from the United States Government.
40  * It is the responsibility of any person or organization contemplating
41  * export to obtain such a license before exporting.
42  *
43  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
44  * distribute this software and its documentation for any purpose and
45  * without fee is hereby granted, provided that the above copyright
46  * notice appear in all copies and that both that copyright notice and
47  * this permission notice appear in supporting documentation, and that
48  * the name of M.I.T. not be used in advertising or publicity pertaining
49  * to distribution of the software without specific, written prior
50  * permission. Furthermore if you modify this software you must label
51  * your software as modified software and not distribute it in such a
52  * fashion that it might be confused with the original M.I.T. software.
53  * M.I.T. makes no representations about the suitability of
54  * this software for any purpose. It is provided "as is" without express
55  * or implied warranty.
56  *
57  */
58 
59 /*
60  * krb5_net_read() reads from the file descriptor "fd" to the buffer
61  * "buf", until either 1) "len" bytes have been read or 2) cannot
62  * read anymore from "fd". It returns the number of bytes read
63  * or a read() error. (The calling interface is identical to
64  * read(2).)
65  *
66  * XXX must not use non-blocking I/O
67  */
68 
69 int krb5_net_read(krb5_context /*context*/, int fd, register char *buf, register int len)
70 {
71  int cc, len2 = 0;
72 
73  do {
74  cc = SOCKET_READ((SOCKET)fd, buf, len);
75  if (cc < 0) {
76  if (SOCKET_ERRNO == SOCKET_EINTR)
77  continue;
78 
79  /* XXX this interface sucks! */
80  errno = SOCKET_ERRNO;
81 
82  return(cc); /* errno is already set */
83  } else if (cc == 0) {
84  return(len2);
85  } else {
86  buf += cc;
87  len2 += cc;
88  len -= cc;
89  }
90  } while (len > 0);
91  return(len2);
92 }
93 /*
94  * lib/krb5/os/net_write.c
95  *
96  * Copyright 1987, 1988, 1990 by the Massachusetts Institute of Technology.
97  * All Rights Reserved.
98  *
99  * Export of this software from the United States of America may
100  * require a specific license from the United States Government.
101  * It is the responsibility of any person or organization contemplating
102  * export to obtain such a license before exporting.
103  *
104  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
105  * distribute this software and its documentation for any purpose and
106  * without fee is hereby granted, provided that the above copyright
107  * notice appear in all copies and that both that copyright notice and
108  * this permission notice appear in supporting documentation, and that
109  * the name of M.I.T. not be used in advertising or publicity pertaining
110  * to distribution of the software without specific, written prior
111  * permission. Furthermore if you modify this software you must label
112  * your software as modified software and not distribute it in such a
113  * fashion that it might be confused with the original M.I.T. software.
114  * M.I.T. makes no representations about the suitability of
115  * this software for any purpose. It is provided "as is" without express
116  * or implied warranty.
117  *
118  */
119 
120 /*
121  * krb5_net_write() writes "len" bytes from "buf" to the file
122  * descriptor "fd". It returns the number of bytes written or
123  * a write() error. (The calling interface is identical to
124  * write(2).)
125  *
126  * XXX must not use non-blocking I/O
127  */
128 
129 int krb5_net_write(krb5_context /*context*/, int fd, register const char *buf, int len)
130 {
131  int cc;
132  int wrlen = len;
133  do {
134  cc = SOCKET_WRITE((SOCKET)fd, buf, wrlen);
135  if (cc < 0) {
136  if (SOCKET_ERRNO == SOCKET_EINTR)
137  continue;
138 
139  /* XXX this interface sucks! */
140  errno = SOCKET_ERRNO;
141 
142  return(cc);
143  } else {
144  buf += cc;
145  wrlen -= cc;
146  }
147  } while (wrlen > 0);
148  return(len);
149 }
150 #endif
151 
153 
154 
155 krb5_context TKSocket::fgContext = 0;
156 krb5_ccache TKSocket::fgCCDef = 0;
157 krb5_principal TKSocket::fgClient = 0;
158 
159 ////////////////////////////////////////////////////////////////////////////////
160 /// Constructor
161 
163  : fSocket(s), fServer(0), fAuthContext(0)
164 {
165 }
166 
167 ////////////////////////////////////////////////////////////////////////////////
168 /// Destructor
169 
171 {
172  krb5_free_principal(fgContext, fServer);
173  krb5_auth_con_free(fgContext, fAuthContext);
174  delete fSocket;
175 }
176 
177 ////////////////////////////////////////////////////////////////////////////////
178 /// Connect to 'server' on 'port'
179 
180 TKSocket *TKSocket::Connect(const char *server, Int_t port)
181 {
182  Int_t rc;
183 
184  if (fgContext == 0) {
185  rc = krb5_init_context(&fgContext);
186  if (rc != 0) {
187  ::Error("TKSocket::Connect","while initializing krb5 (%d), %s",
188  rc, error_message(rc));
189  return 0;
190  }
191 
192  rc = krb5_cc_default(fgContext, &fgCCDef);
193  if (rc != 0) {
194  ::Error("TKSocket::Connect","while getting default credential cache (%d), %s",
195  rc, error_message(rc));
196  krb5_free_context(fgContext); fgContext = 0;
197  return 0;
198  }
199 
200  rc = krb5_cc_get_principal(fgContext, fgCCDef, &fgClient);
201  if (rc != 0) {
202  ::Error("TKSocket::Connect","while getting client principal from %s (%d), %s",
203  krb5_cc_get_name(fgContext,fgCCDef), rc, error_message(rc));
204  krb5_cc_close(fgContext,fgCCDef); fgCCDef = 0;
205  krb5_free_context(fgContext); fgContext = 0;
206  return 0;
207  }
208  }
209 
210  TSocket *s = new TSocket(server, port);
211 
212  if (!s->IsValid()) {
213  ::SysError("TKSocket::Connect","Cannot connect to %s:%d", server, port);
214  delete s;
215  return 0;
216  }
217 
218  TKSocket *ks = new TKSocket(s);
219 
220  rc = krb5_sname_to_principal(fgContext, server, "host", KRB5_NT_SRV_HST, &ks->fServer);
221  if (rc != 0) {
222  ::Error("TKSocket::Connect","while getting server principal (%d), %s",
223  rc, error_message(rc));
224  delete ks;
225  return 0;
226  }
227 
228  krb5_data cksum_data;
229  cksum_data.data = StrDup(server);
230  cksum_data.length = strlen(server);
231 
232  krb5_error *err_ret;
233  krb5_ap_rep_enc_part *rep_ret;
234 
235  int sock = ks->fSocket->GetDescriptor();
236  rc = krb5_sendauth(fgContext, &ks->fAuthContext, (krb5_pointer) &sock,
237  (char *)"KRB5_TCP_Python_v1.0", fgClient, ks->fServer,
238  AP_OPTS_MUTUAL_REQUIRED,
239  &cksum_data,
240  0, /* no creds, use ccache instead */
241  fgCCDef, &err_ret, &rep_ret, 0);
242 
243  delete [] cksum_data.data;
244 
245  if (rc != 0) {
246  ::Error("TKSocket::Connect","while sendauth (%d), %s",
247  rc, error_message(rc));
248  delete ks;
249  return 0;
250  }
251 
252  return ks;
253 }
254 
255 ////////////////////////////////////////////////////////////////////////////////
256 /// Read block on information from server. The result is stored in buf.
257 /// The number of read bytes is returned; -1 is returned in case of error.
258 
260 {
261  Int_t rc;
262  Desc_t desc;
263  Int_t fd = fSocket->GetDescriptor();
264 
265  rc = krb5_net_read(fgContext, fd, (char *)&desc, sizeof(desc));
266  if (rc == 0) errno = ECONNABORTED;
267 
268  if (rc <= 0) {
269  SysError("BlockRead","reading descriptor (%d), %s",
270  rc, error_message(rc));
271  return -1;
272  }
273 
274  type = static_cast<EEncoding>(ntohs(desc.fType));
275 
276  krb5_data enc;
277  enc.length = ntohs(desc.fLength);
278  enc.data = new char[enc.length+1];
279 
280  rc = krb5_net_read(fgContext, fd, enc.data, enc.length);
281  enc.data[enc.length] = 0;
282 
283  if (rc == 0) errno = ECONNABORTED;
284 
285  if (rc <= 0) {
286  SysError("BlockRead","reading data (%d), %s",
287  rc, error_message(rc));
288  delete [] enc.data;
289  return -1;
290  }
291 
292  krb5_data out;
293  switch (type) {
294  case kNone:
295  buf = enc.data;
296  rc = enc.length;
297  break;
298  case kSafe:
299  rc = krb5_rd_safe(fgContext, fAuthContext, &enc, &out, 0);
300  break;
301  case kPriv:
302  rc = krb5_rd_priv(fgContext, fAuthContext, &enc, &out, 0);
303  break;
304  default:
305  Error("BlockWrite","unknown encoding type (%d)", type);
306  return -1;
307  }
308 
309  if (type != kNone) {
310  // copy data to buffer that is new'ed
311  buf = new char[out.length+1];
312  memcpy(buf, out.data, out.length);
313  buf[out.length] = 0;
314  free(out.data);
315  delete [] enc.data;
316  rc = out.length;
317  }
318 
319  return rc;
320 }
321 
322 ////////////////////////////////////////////////////////////////////////////////
323 /// Block-send 'length' bytes to server from 'buf'.
324 
325 Int_t TKSocket::BlockWrite(const char *buf, Int_t length, EEncoding type)
326 {
327  Desc_t desc;
328  krb5_data in;
329  krb5_data enc;
330  Int_t rc;
331  in.data = const_cast<char*>(buf);
332  in.length = length;
333 
334  switch (type) {
335  case kNone:
336  enc.data = in.data;
337  enc.length = in.length;
338  break;
339  case kSafe:
340  rc = krb5_mk_safe(fgContext, fAuthContext, &in, &enc, 0);
341  break;
342  case kPriv:
343  rc = krb5_mk_priv(fgContext, fAuthContext, &in, &enc, 0);
344  break;
345  default:
346  Error("BlockWrite","unknown encoding type (%d)", type);
347  return -1;
348  }
349 
350  desc.fLength = htons(enc.length);
351  desc.fType = htons(type);
352 
353  Int_t fd = fSocket->GetDescriptor();
354  rc = krb5_net_write(fgContext, fd, (char *)&desc, sizeof(desc));
355  if (rc <= 0) {
356  Error("BlockWrite","writing descriptor (%d), %s",
357  rc, error_message(rc));
358  return -1;
359  }
360 
361  rc = krb5_net_write(fgContext, fd, (char *)enc.data, enc.length);
362  if (rc <= 0) {
363  Error("BlockWrite","writing data (%d), %s",
364  rc, error_message(rc));
365  return -1;
366  }
367 
368  if (type != kNone) free(enc.data);
369 
370  return rc;
371 }
virtual void SysError(const char *method, const char *msgfmt,...) const
Issue system error message.
Definition: TObject.cxx:939
static krb5_principal fgClient
Definition: TKSocket.h:40
krb5_principal fServer
Definition: TKSocket.h:35
virtual Bool_t IsValid() const
Definition: TSocket.h:162
static krb5_ccache fgCCDef
Definition: TKSocket.h:39
Short_t fType
Definition: TKSocket.h:51
int Int_t
Definition: RtypesCore.h:41
int krb5_net_read(krb5_context context, int fd, char *buf, int len)
Int_t BlockRead(char *&buf, EEncoding &type)
Read block on information from server.
Definition: TKSocket.cxx:259
krb5_auth_context fAuthContext
Definition: TKSocket.h:36
int SOCKET
Definition: civetweb.c:464
Short_t fLength
Definition: TKSocket.h:50
static krb5_context fgContext
Definition: TKSocket.h:38
static TKSocket * Connect(const char *server, Int_t port)
Connect to &#39;server&#39; on &#39;port&#39;.
Definition: TKSocket.cxx:180
TSocket * fSocket
Definition: TKSocket.h:34
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:925
char * StrDup(const char *str)
Duplicate the string str.
Definition: TString.cxx:2514
#define ClassImp(name)
Definition: Rtypes.h:279
int type
Definition: TGX11.cxx:120
#define free
Definition: civetweb.c:821
~TKSocket()
Destructor.
Definition: TKSocket.cxx:170
virtual Int_t GetDescriptor() const
Definition: TSocket.h:142
Int_t BlockWrite(const char *buf, Int_t len, EEncoding type)
Block-send &#39;length&#39; bytes to server from &#39;buf&#39;.
Definition: TKSocket.cxx:325
int krb5_net_write(krb5_context context, int fd, const char *buf, int len)
TKSocket(TSocket *s=0)
Constructor.
Definition: TKSocket.cxx:162