// @(#)root/krb5auth:$Id$
// Author: Maarten Ballintijn   27/10/2003

#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <netinet/in.h>
#ifndef WIN32
#   include <unistd.h>
#endif

#include "TKSocket.h"
#include "TSocket.h"
#include "TError.h"


extern "C" {
// missing from "krb5.h"
extern int krb5_net_read(/*IN*/ krb5_context context, int fd,
                         /*OUT*/ char *buf,/*IN*/ int len);

extern int krb5_net_write(/*IN*/ krb5_context context, int fd,
                          const char *buf, int len);
}

#ifdef __APPLE__
#define SOCKET int
#define SOCKET_ERRNO errno
#define SOCKET_EINTR EINTR
#define SOCKET_READ(a,b,c) read(a,b,c)
#define SOCKET_WRITE(a,b,c) write(a,b,c)
/*
 * lib/krb5/os/net_read.c
 *
 * Copyright 1987, 1988, 1990 by the Massachusetts Institute of Technology.
 * All Rights Reserved.
 *
 * Export of this software from the United States of America may
 *   require a specific license from the United States Government.
 *   It is the responsibility of any person or organization contemplating
 *   export to obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 * distribute this software and its documentation for any purpose and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of M.I.T. not be used in advertising or publicity pertaining
 * to distribution of the software without specific, written prior
 * permission.  Furthermore if you modify this software you must label
 * your software as modified software and not distribute it in such a
 * fashion that it might be confused with the original M.I.T. software.
 * M.I.T. makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is" without express
 * or implied warranty.
 *
 */

/*
 * krb5_net_read() reads from the file descriptor "fd" to the buffer
 * "buf", until either 1) "len" bytes have been read or 2) cannot
 * read anymore from "fd".  It returns the number of bytes read
 * or a read() error.  (The calling interface is identical to
 * read(2).)
 *
 * XXX must not use non-blocking I/O
 */

int krb5_net_read(krb5_context /*context*/, int fd, register char *buf, register int len)
{
   int cc, len2 = 0;

   do {
      cc = SOCKET_READ((SOCKET)fd, buf, len);
      if (cc < 0) {
         if (SOCKET_ERRNO == SOCKET_EINTR)
            continue;

         /* XXX this interface sucks! */
	      errno = SOCKET_ERRNO;

         return(cc);          /* errno is already set */
      } else if (cc == 0) {
         return(len2);
      } else {
         buf += cc;
         len2 += cc;
         len -= cc;
      }
   } while (len > 0);
   return(len2);
}
/*
 * lib/krb5/os/net_write.c
 *
 * Copyright 1987, 1988, 1990 by the Massachusetts Institute of Technology.
 * All Rights Reserved.
 *
 * Export of this software from the United States of America may
 *   require a specific license from the United States Government.
 *   It is the responsibility of any person or organization contemplating
 *   export to obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 * distribute this software and its documentation for any purpose and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of M.I.T. not be used in advertising or publicity pertaining
 * to distribution of the software without specific, written prior
 * permission.  Furthermore if you modify this software you must label
 * your software as modified software and not distribute it in such a
 * fashion that it might be confused with the original M.I.T. software.
 * M.I.T. makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is" without express
 * or implied warranty.
 *
 */

/*
 * krb5_net_write() writes "len" bytes from "buf" to the file
 * descriptor "fd".  It returns the number of bytes written or
 * a write() error.  (The calling interface is identical to
 * write(2).)
 *
 * XXX must not use non-blocking I/O
 */

int krb5_net_write(krb5_context /*context*/, int fd, register const char *buf, int len)
{
   int cc;
   int wrlen = len;
   do {
      cc = SOCKET_WRITE((SOCKET)fd, buf, wrlen);
      if (cc < 0) {
         if (SOCKET_ERRNO == SOCKET_EINTR)
            continue;

         /* XXX this interface sucks! */
         errno = SOCKET_ERRNO;

         return(cc);
      } else {
         buf += cc;
         wrlen -= cc;
      }
   } while (wrlen > 0);
   return(len);
}
#endif

ClassImp(TKSocket)


krb5_context TKSocket::fgContext = 0;
krb5_ccache TKSocket::fgCCDef = 0;
krb5_principal TKSocket::fgClient = 0;

//______________________________________________________________________________
TKSocket::TKSocket(TSocket *s)
   : fSocket(s), fServer(0), fAuthContext(0)
{
   // Constructor

}

//______________________________________________________________________________
TKSocket::~TKSocket()
{
   // Destructor

   krb5_free_principal(fgContext, fServer);
   krb5_auth_con_free(fgContext, fAuthContext);
   delete fSocket;
}

//______________________________________________________________________________
TKSocket *TKSocket::Connect(const char *server, Int_t port)
{
   // Connect to 'server' on 'port'

   Int_t rc;

   if (fgContext == 0) {
      rc = krb5_init_context(&fgContext);
      if (rc != 0) {
         ::Error("TKSocket::Connect","while initializing krb5 (%d), %s",
                 rc, error_message(rc));
         return 0;
      }

      rc = krb5_cc_default(fgContext, &fgCCDef);
      if (rc != 0) {
         ::Error("TKSocket::Connect","while getting default credential cache (%d), %s",
                 rc, error_message(rc));
         krb5_free_context(fgContext); fgContext = 0;
         return 0;
      }

      rc = krb5_cc_get_principal(fgContext, fgCCDef, &fgClient);
      if (rc != 0) {
         ::Error("TKSocket::Connect","while getting client principal from %s (%d), %s",
                 krb5_cc_get_name(fgContext,fgCCDef), rc, error_message(rc));
         krb5_cc_close(fgContext,fgCCDef); fgCCDef = 0;
         krb5_free_context(fgContext); fgContext = 0;
         return 0;
      }
   }

   TSocket  *s = new TSocket(server, port);

   if (!s->IsValid()) {
      ::SysError("TKSocket::Connect","Cannot connect to %s:%d", server, port);
      delete s;
      return 0;
   }

   TKSocket *ks = new TKSocket(s);

   rc = krb5_sname_to_principal(fgContext, server, "host", KRB5_NT_SRV_HST, &ks->fServer);
   if (rc != 0) {
      ::Error("TKSocket::Connect","while getting server principal (%d), %s",
              rc, error_message(rc));
      delete ks;
      return 0;
   }

   krb5_data cksum_data;
   cksum_data.data = StrDup(server);
   cksum_data.length = strlen(server);

   krb5_error *err_ret;
   krb5_ap_rep_enc_part *rep_ret;

   int sock = ks->fSocket->GetDescriptor();
   rc = krb5_sendauth(fgContext, &ks->fAuthContext, (krb5_pointer) &sock,
                      (char *)"KRB5_TCP_Python_v1.0", fgClient, ks->fServer,
                      AP_OPTS_MUTUAL_REQUIRED,
                      &cksum_data,
                      0,           /* no creds, use ccache instead */
                      fgCCDef, &err_ret, &rep_ret, 0);

   delete [] cksum_data.data;

   if (rc != 0) {
      ::Error("TKSocket::Connect","while sendauth (%d), %s",
              rc, error_message(rc));
      delete ks;
      return 0;
   }

   return ks;
}

//______________________________________________________________________________
Int_t TKSocket::BlockRead(char *&buf, EEncoding &type)
{
   // Read block on information from server. The result is stored in buf.
   // The number of read bytes is returned; -1 is returned in case of error.

   Int_t rc;
   Desc_t desc;
   Int_t fd = fSocket->GetDescriptor();

   rc = krb5_net_read(fgContext, fd, (char *)&desc, sizeof(desc));
   if (rc == 0) errno = ECONNABORTED;

   if (rc <= 0) {
      SysError("BlockRead","reading descriptor (%d), %s",
               rc, error_message(rc));
      return -1;
   }

   type = static_cast<EEncoding>(ntohs(desc.fType));

   krb5_data enc;
   enc.length = ntohs(desc.fLength);
   enc.data = new char[enc.length+1];

   rc = krb5_net_read(fgContext, fd, enc.data, enc.length);
   enc.data[enc.length] = 0;

   if (rc == 0) errno = ECONNABORTED;

   if (rc <= 0) {
      SysError("BlockRead","reading data (%d), %s",
               rc, error_message(rc));
      delete [] enc.data;
      return -1;
   }

   krb5_data out;
   switch (type) {
   case kNone:
      buf = enc.data;
      rc = enc.length;
      break;
   case kSafe:
      rc = krb5_rd_safe(fgContext, fAuthContext, &enc, &out, 0);
      break;
   case kPriv:
      rc = krb5_rd_priv(fgContext, fAuthContext, &enc, &out, 0);
      break;
   default:
      Error("BlockWrite","unknown encoding type (%d)", type);
      return -1;
   }

   if (type != kNone) {
      // copy data to buffer that is new'ed
      buf = new char[out.length+1];
      memcpy(buf, out.data, out.length);
      buf[out.length] = 0;
      free(out.data);
      delete [] enc.data;
      rc = out.length;
   }

   return rc;
}

//______________________________________________________________________________
Int_t TKSocket::BlockWrite(const char *buf, Int_t length, EEncoding type)
{
   // Block-send 'length' bytes to server from 'buf'.

   Desc_t desc;
   krb5_data in;
   krb5_data enc;
   Int_t rc;
   in.data = const_cast<char*>(buf);
   in.length = length;

   switch (type) {
   case kNone:
      enc.data = in.data;
      enc.length = in.length;
      break;
   case kSafe:
      rc = krb5_mk_safe(fgContext, fAuthContext, &in, &enc, 0);
      break;
   case kPriv:
      rc = krb5_mk_priv(fgContext, fAuthContext, &in, &enc, 0);
      break;
   default:
      Error("BlockWrite","unknown encoding type (%d)", type);
      return -1;
   }

   desc.fLength = htons(enc.length);
   desc.fType = htons(type);

   Int_t fd = fSocket->GetDescriptor();
   rc = krb5_net_write(fgContext, fd, (char *)&desc, sizeof(desc));
   if (rc <= 0) {
      Error("BlockWrite","writing descriptor (%d), %s",
            rc, error_message(rc));
      return -1;
   }

   rc = krb5_net_write(fgContext, fd, (char *)enc.data, enc.length);
   if (rc <= 0) {
      Error("BlockWrite","writing data (%d), %s",
            rc, error_message(rc));
      return -1;
   }

   if (type != kNone) free(enc.data);

   return rc;
}
 TKSocket.cxx:1
 TKSocket.cxx:2
 TKSocket.cxx:3
 TKSocket.cxx:4
 TKSocket.cxx:5
 TKSocket.cxx:6
 TKSocket.cxx:7
 TKSocket.cxx:8
 TKSocket.cxx:9
 TKSocket.cxx:10
 TKSocket.cxx:11
 TKSocket.cxx:12
 TKSocket.cxx:13
 TKSocket.cxx:14
 TKSocket.cxx:15
 TKSocket.cxx:16
 TKSocket.cxx:17
 TKSocket.cxx:18
 TKSocket.cxx:19
 TKSocket.cxx:20
 TKSocket.cxx:21
 TKSocket.cxx:22
 TKSocket.cxx:23
 TKSocket.cxx:24
 TKSocket.cxx:25
 TKSocket.cxx:26
 TKSocket.cxx:27
 TKSocket.cxx:28
 TKSocket.cxx:29
 TKSocket.cxx:30
 TKSocket.cxx:31
 TKSocket.cxx:32
 TKSocket.cxx:33
 TKSocket.cxx:34
 TKSocket.cxx:35
 TKSocket.cxx:36
 TKSocket.cxx:37
 TKSocket.cxx:38
 TKSocket.cxx:39
 TKSocket.cxx:40
 TKSocket.cxx:41
 TKSocket.cxx:42
 TKSocket.cxx:43
 TKSocket.cxx:44
 TKSocket.cxx:45
 TKSocket.cxx:46
 TKSocket.cxx:47
 TKSocket.cxx:48
 TKSocket.cxx:49
 TKSocket.cxx:50
 TKSocket.cxx:51
 TKSocket.cxx:52
 TKSocket.cxx:53
 TKSocket.cxx:54
 TKSocket.cxx:55
 TKSocket.cxx:56
 TKSocket.cxx:57
 TKSocket.cxx:58
 TKSocket.cxx:59
 TKSocket.cxx:60
 TKSocket.cxx:61
 TKSocket.cxx:62
 TKSocket.cxx:63
 TKSocket.cxx:64
 TKSocket.cxx:65
 TKSocket.cxx:66
 TKSocket.cxx:67
 TKSocket.cxx:68
 TKSocket.cxx:69
 TKSocket.cxx:70
 TKSocket.cxx:71
 TKSocket.cxx:72
 TKSocket.cxx:73
 TKSocket.cxx:74
 TKSocket.cxx:75
 TKSocket.cxx:76
 TKSocket.cxx:77
 TKSocket.cxx:78
 TKSocket.cxx:79
 TKSocket.cxx:80
 TKSocket.cxx:81
 TKSocket.cxx:82
 TKSocket.cxx:83
 TKSocket.cxx:84
 TKSocket.cxx:85
 TKSocket.cxx:86
 TKSocket.cxx:87
 TKSocket.cxx:88
 TKSocket.cxx:89
 TKSocket.cxx:90
 TKSocket.cxx:91
 TKSocket.cxx:92
 TKSocket.cxx:93
 TKSocket.cxx:94
 TKSocket.cxx:95
 TKSocket.cxx:96
 TKSocket.cxx:97
 TKSocket.cxx:98
 TKSocket.cxx:99
 TKSocket.cxx:100
 TKSocket.cxx:101
 TKSocket.cxx:102
 TKSocket.cxx:103
 TKSocket.cxx:104
 TKSocket.cxx:105
 TKSocket.cxx:106
 TKSocket.cxx:107
 TKSocket.cxx:108
 TKSocket.cxx:109
 TKSocket.cxx:110
 TKSocket.cxx:111
 TKSocket.cxx:112
 TKSocket.cxx:113
 TKSocket.cxx:114
 TKSocket.cxx:115
 TKSocket.cxx:116
 TKSocket.cxx:117
 TKSocket.cxx:118
 TKSocket.cxx:119
 TKSocket.cxx:120
 TKSocket.cxx:121
 TKSocket.cxx:122
 TKSocket.cxx:123
 TKSocket.cxx:124
 TKSocket.cxx:125
 TKSocket.cxx:126
 TKSocket.cxx:127
 TKSocket.cxx:128
 TKSocket.cxx:129
 TKSocket.cxx:130
 TKSocket.cxx:131
 TKSocket.cxx:132
 TKSocket.cxx:133
 TKSocket.cxx:134
 TKSocket.cxx:135
 TKSocket.cxx:136
 TKSocket.cxx:137
 TKSocket.cxx:138
 TKSocket.cxx:139
 TKSocket.cxx:140
 TKSocket.cxx:141
 TKSocket.cxx:142
 TKSocket.cxx:143
 TKSocket.cxx:144
 TKSocket.cxx:145
 TKSocket.cxx:146
 TKSocket.cxx:147
 TKSocket.cxx:148
 TKSocket.cxx:149
 TKSocket.cxx:150
 TKSocket.cxx:151
 TKSocket.cxx:152
 TKSocket.cxx:153
 TKSocket.cxx:154
 TKSocket.cxx:155
 TKSocket.cxx:156
 TKSocket.cxx:157
 TKSocket.cxx:158
 TKSocket.cxx:159
 TKSocket.cxx:160
 TKSocket.cxx:161
 TKSocket.cxx:162
 TKSocket.cxx:163
 TKSocket.cxx:164
 TKSocket.cxx:165
 TKSocket.cxx:166
 TKSocket.cxx:167
 TKSocket.cxx:168
 TKSocket.cxx:169
 TKSocket.cxx:170
 TKSocket.cxx:171
 TKSocket.cxx:172
 TKSocket.cxx:173
 TKSocket.cxx:174
 TKSocket.cxx:175
 TKSocket.cxx:176
 TKSocket.cxx:177
 TKSocket.cxx:178
 TKSocket.cxx:179
 TKSocket.cxx:180
 TKSocket.cxx:181
 TKSocket.cxx:182
 TKSocket.cxx:183
 TKSocket.cxx:184
 TKSocket.cxx:185
 TKSocket.cxx:186
 TKSocket.cxx:187
 TKSocket.cxx:188
 TKSocket.cxx:189
 TKSocket.cxx:190
 TKSocket.cxx:191
 TKSocket.cxx:192
 TKSocket.cxx:193
 TKSocket.cxx:194
 TKSocket.cxx:195
 TKSocket.cxx:196
 TKSocket.cxx:197
 TKSocket.cxx:198
 TKSocket.cxx:199
 TKSocket.cxx:200
 TKSocket.cxx:201
 TKSocket.cxx:202
 TKSocket.cxx:203
 TKSocket.cxx:204
 TKSocket.cxx:205
 TKSocket.cxx:206
 TKSocket.cxx:207
 TKSocket.cxx:208
 TKSocket.cxx:209
 TKSocket.cxx:210
 TKSocket.cxx:211
 TKSocket.cxx:212
 TKSocket.cxx:213
 TKSocket.cxx:214
 TKSocket.cxx:215
 TKSocket.cxx:216
 TKSocket.cxx:217
 TKSocket.cxx:218
 TKSocket.cxx:219
 TKSocket.cxx:220
 TKSocket.cxx:221
 TKSocket.cxx:222
 TKSocket.cxx:223
 TKSocket.cxx:224
 TKSocket.cxx:225
 TKSocket.cxx:226
 TKSocket.cxx:227
 TKSocket.cxx:228
 TKSocket.cxx:229
 TKSocket.cxx:230
 TKSocket.cxx:231
 TKSocket.cxx:232
 TKSocket.cxx:233
 TKSocket.cxx:234
 TKSocket.cxx:235
 TKSocket.cxx:236
 TKSocket.cxx:237
 TKSocket.cxx:238
 TKSocket.cxx:239
 TKSocket.cxx:240
 TKSocket.cxx:241
 TKSocket.cxx:242
 TKSocket.cxx:243
 TKSocket.cxx:244
 TKSocket.cxx:245
 TKSocket.cxx:246
 TKSocket.cxx:247
 TKSocket.cxx:248
 TKSocket.cxx:249
 TKSocket.cxx:250
 TKSocket.cxx:251
 TKSocket.cxx:252
 TKSocket.cxx:253
 TKSocket.cxx:254
 TKSocket.cxx:255
 TKSocket.cxx:256
 TKSocket.cxx:257
 TKSocket.cxx:258
 TKSocket.cxx:259
 TKSocket.cxx:260
 TKSocket.cxx:261
 TKSocket.cxx:262
 TKSocket.cxx:263
 TKSocket.cxx:264
 TKSocket.cxx:265
 TKSocket.cxx:266
 TKSocket.cxx:267
 TKSocket.cxx:268
 TKSocket.cxx:269
 TKSocket.cxx:270
 TKSocket.cxx:271
 TKSocket.cxx:272
 TKSocket.cxx:273
 TKSocket.cxx:274
 TKSocket.cxx:275
 TKSocket.cxx:276
 TKSocket.cxx:277
 TKSocket.cxx:278
 TKSocket.cxx:279
 TKSocket.cxx:280
 TKSocket.cxx:281
 TKSocket.cxx:282
 TKSocket.cxx:283
 TKSocket.cxx:284
 TKSocket.cxx:285
 TKSocket.cxx:286
 TKSocket.cxx:287
 TKSocket.cxx:288
 TKSocket.cxx:289
 TKSocket.cxx:290
 TKSocket.cxx:291
 TKSocket.cxx:292
 TKSocket.cxx:293
 TKSocket.cxx:294
 TKSocket.cxx:295
 TKSocket.cxx:296
 TKSocket.cxx:297
 TKSocket.cxx:298
 TKSocket.cxx:299
 TKSocket.cxx:300
 TKSocket.cxx:301
 TKSocket.cxx:302
 TKSocket.cxx:303
 TKSocket.cxx:304
 TKSocket.cxx:305
 TKSocket.cxx:306
 TKSocket.cxx:307
 TKSocket.cxx:308
 TKSocket.cxx:309
 TKSocket.cxx:310
 TKSocket.cxx:311
 TKSocket.cxx:312
 TKSocket.cxx:313
 TKSocket.cxx:314
 TKSocket.cxx:315
 TKSocket.cxx:316
 TKSocket.cxx:317
 TKSocket.cxx:318
 TKSocket.cxx:319
 TKSocket.cxx:320
 TKSocket.cxx:321
 TKSocket.cxx:322
 TKSocket.cxx:323
 TKSocket.cxx:324
 TKSocket.cxx:325
 TKSocket.cxx:326
 TKSocket.cxx:327
 TKSocket.cxx:328
 TKSocket.cxx:329
 TKSocket.cxx:330
 TKSocket.cxx:331
 TKSocket.cxx:332
 TKSocket.cxx:333
 TKSocket.cxx:334
 TKSocket.cxx:335
 TKSocket.cxx:336
 TKSocket.cxx:337
 TKSocket.cxx:338
 TKSocket.cxx:339
 TKSocket.cxx:340
 TKSocket.cxx:341
 TKSocket.cxx:342
 TKSocket.cxx:343
 TKSocket.cxx:344
 TKSocket.cxx:345
 TKSocket.cxx:346
 TKSocket.cxx:347
 TKSocket.cxx:348
 TKSocket.cxx:349
 TKSocket.cxx:350
 TKSocket.cxx:351
 TKSocket.cxx:352
 TKSocket.cxx:353
 TKSocket.cxx:354
 TKSocket.cxx:355
 TKSocket.cxx:356
 TKSocket.cxx:357
 TKSocket.cxx:358
 TKSocket.cxx:359
 TKSocket.cxx:360
 TKSocket.cxx:361
 TKSocket.cxx:362
 TKSocket.cxx:363
 TKSocket.cxx:364
 TKSocket.cxx:365
 TKSocket.cxx:366
 TKSocket.cxx:367
 TKSocket.cxx:368
 TKSocket.cxx:369
 TKSocket.cxx:370
 TKSocket.cxx:371