~ubuntu-branches/ubuntu/vivid/curl/vivid

« back to all changes in this revision

Viewing changes to lib/socks_sspi.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Schuldei
  • Date: 2009-04-02 23:35:45 UTC
  • mto: (1.2.1 upstream) (3.2.3 sid)
  • mto: This revision was merged to the branch mainline in revision 38.
  • Revision ID: james.westby@ubuntu.com-20090402233545-geixkwhe3izccjt7
Tags: upstream-7.19.4
ImportĀ upstreamĀ versionĀ 7.19.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *                                  _   _ ____  _
 
3
 *  Project                     ___| | | |  _ \| |
 
4
 *                             / __| | | | |_) | |
 
5
 *                            | (__| |_| |  _ <| |___
 
6
 *                             \___|\___/|_| \_\_____|
 
7
 *
 
8
 * Copyright (C) 2009, Markus Moeller, <markus_moeller@compuserve.com>
 
9
 *
 
10
 * This software is licensed as described in the file COPYING, which
 
11
 * you should have received as part of this distribution. The terms
 
12
 * are also available at http://curl.haxx.se/docs/copyright.html.
 
13
 *
 
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 
15
 * copies of the Software, and permit persons to whom the Software is
 
16
 * furnished to do so, under the terms of the COPYING file.
 
17
 *
 
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 
19
 * KIND, either express or implied.
 
20
 *
 
21
 * $Id: socks_sspi.c,v 1.6 2009-02-23 01:04:18 yangtse Exp $
 
22
 ***************************************************************************/
 
23
 
 
24
 
 
25
#include "setup.h"
 
26
 
 
27
#ifdef USE_WINDOWS_SSPI
 
28
 
 
29
#include <string.h>
 
30
 
 
31
#ifdef NEED_MALLOC_H
 
32
#include <malloc.h>
 
33
#endif
 
34
#ifdef HAVE_STDLIB_H
 
35
#include <stdlib.h>
 
36
#endif
 
37
 
 
38
#include "urldata.h"
 
39
#include "sendf.h"
 
40
#include "connect.h"
 
41
#include "timeval.h"
 
42
#include "socks.h"
 
43
#include "curl_sspi.h"
 
44
 
 
45
#define _MPRINTF_REPLACE /* use the internal *printf() functions */
 
46
#include <curl/mprintf.h>
 
47
 
 
48
/* The last #include file should be: */
 
49
#include "memdebug.h"
 
50
 
 
51
/*
 
52
 * Definitions required from ntsecapi.h are directly provided below this point
 
53
 * to avoid including ntsecapi.h due to a conflict with OpenSSL's safestack.h
 
54
 */
 
55
#define KERB_WRAP_NO_ENCRYPT 0x80000001
 
56
 
 
57
/*
 
58
 * Helper sspi error functions.
 
59
 */
 
60
static int check_sspi_err(struct SessionHandle *data,
 
61
                          SECURITY_STATUS major_status,
 
62
                          SECURITY_STATUS minor_status,
 
63
                          const char* function)
 
64
{
 
65
  const char *txt;
 
66
  (void)minor_status;
 
67
 
 
68
  if(major_status != SEC_E_OK &&
 
69
     major_status != SEC_I_COMPLETE_AND_CONTINUE &&
 
70
     major_status != SEC_I_COMPLETE_NEEDED &&
 
71
     major_status != SEC_I_CONTINUE_NEEDED) {
 
72
    failf(data, "SSPI error: %s failed: %d\n", function, major_status);
 
73
    switch (major_status) {
 
74
    case SEC_I_COMPLETE_AND_CONTINUE:
 
75
      txt="SEC_I_COMPLETE_AND_CONTINUE";
 
76
      break;
 
77
    case SEC_I_COMPLETE_NEEDED:
 
78
      txt="SEC_I_COMPLETE_NEEDED";
 
79
      break;
 
80
    case SEC_I_CONTINUE_NEEDED:
 
81
      txt="SEC_I_CONTINUE_NEEDED";
 
82
      break;
 
83
    case SEC_I_CONTEXT_EXPIRED:
 
84
      txt="SEC_I_CONTEXT_EXPIRED";
 
85
      break;
 
86
    case SEC_I_INCOMPLETE_CREDENTIALS:
 
87
      txt="SEC_I_INCOMPLETE_CREDENTIALS";
 
88
      break;
 
89
    case SEC_I_RENEGOTIATE:
 
90
      txt="SEC_I_RENEGOTIATE";
 
91
      break;
 
92
    case SEC_E_BUFFER_TOO_SMALL:
 
93
      txt="SEC_E_BUFFER_TOO_SMALL";
 
94
      break;
 
95
    case SEC_E_CONTEXT_EXPIRED:
 
96
      txt="SEC_E_CONTEXT_EXPIRED";
 
97
      break;
 
98
    case SEC_E_CRYPTO_SYSTEM_INVALID:
 
99
      txt="SEC_E_CRYPTO_SYSTEM_INVALID";
 
100
      break;
 
101
    case SEC_E_INCOMPLETE_MESSAGE:
 
102
      txt="SEC_E_INCOMPLETE_MESSAGE";
 
103
      break;
 
104
    case SEC_E_INSUFFICIENT_MEMORY:
 
105
      txt="SEC_E_INSUFFICIENT_MEMORY";
 
106
      break;
 
107
    case SEC_E_INTERNAL_ERROR:
 
108
      txt="SEC_E_INTERNAL_ERROR";
 
109
      break;
 
110
    case SEC_E_INVALID_HANDLE:
 
111
      txt="SEC_E_INVALID_HANDLE";
 
112
      break;
 
113
    case SEC_E_INVALID_TOKEN:
 
114
      txt="SEC_E_INVALID_TOKEN";
 
115
      break;
 
116
    case SEC_E_LOGON_DENIED:
 
117
      txt="SEC_E_LOGON_DENIED";
 
118
      break;
 
119
    case SEC_E_MESSAGE_ALTERED:
 
120
      txt="SEC_E_MESSAGE_ALTERED";
 
121
      break;
 
122
    case SEC_E_NO_AUTHENTICATING_AUTHORITY:
 
123
      txt="SEC_E_NO_AUTHENTICATING_AUTHORITY";
 
124
      break;
 
125
    case SEC_E_NO_CREDENTIALS:
 
126
      txt="SEC_E_NO_CREDENTIALS";
 
127
      break;
 
128
    case SEC_E_NOT_OWNER:
 
129
      txt="SEC_E_NOT_OWNER";
 
130
      break;
 
131
    case SEC_E_OUT_OF_SEQUENCE:
 
132
      txt="SEC_E_OUT_OF_SEQUENCE";
 
133
      break;
 
134
    case SEC_E_QOP_NOT_SUPPORTED:
 
135
      txt="SEC_E_QOP_NOT_SUPPORTED";
 
136
      break;
 
137
    case SEC_E_SECPKG_NOT_FOUND:
 
138
      txt="SEC_E_SECPKG_NOT_FOUND";
 
139
      break;
 
140
    case SEC_E_TARGET_UNKNOWN:
 
141
      txt="SEC_E_TARGET_UNKNOWN";
 
142
      break;
 
143
    case SEC_E_UNKNOWN_CREDENTIALS:
 
144
      txt="SEC_E_UNKNOWN_CREDENTIALS";
 
145
      break;
 
146
    case SEC_E_UNSUPPORTED_FUNCTION:
 
147
      txt="SEC_E_UNSUPPORTED_FUNCTION";
 
148
      break;
 
149
    case SEC_E_WRONG_PRINCIPAL:
 
150
      txt="SEC_E_WRONG_PRINCIPAL";
 
151
      break;
 
152
    default:
 
153
      txt="Unknown error";
 
154
 
 
155
    }
 
156
    failf(data, "SSPI error: %s failed: %s\n", function, txt);
 
157
    return 1;
 
158
  }
 
159
  return 0;
 
160
}
 
161
 
 
162
/* This is the SSPI-using version of this function */
 
163
CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
 
164
                                      struct connectdata *conn)
 
165
{
 
166
  struct SessionHandle *data = conn->data;
 
167
  curl_socket_t sock = conn->sock[sockindex];
 
168
  CURLcode code;
 
169
  ssize_t actualread;
 
170
  ssize_t written;
 
171
  int result;
 
172
  long timeout;
 
173
  /* Needs GSSAPI authentication */
 
174
  SECURITY_STATUS sspi_major_status, sspi_minor_status=0;
 
175
  unsigned long sspi_ret_flags=0;
 
176
  int gss_enc;
 
177
  SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3];
 
178
  SecBufferDesc input_desc, output_desc, wrap_desc;
 
179
  SecPkgContext_Sizes sspi_sizes;
 
180
  CredHandle cred_handle;
 
181
  CtxtHandle sspi_context;
 
182
  PCtxtHandle context_handle = NULL;
 
183
  SecPkgCredentials_Names names;
 
184
  TimeStamp expiry;
 
185
  char *service_name=NULL;
 
186
  u_short us_length;
 
187
  ULONG qop;
 
188
  unsigned char socksreq[4]; /* room for gssapi exchange header only */
 
189
  char *service = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE];
 
190
 
 
191
  /* get timeout */
 
192
  timeout = Curl_timeleft(conn, NULL, TRUE);
 
193
 
 
194
  /*   GSSAPI request looks like
 
195
   * +----+------+-----+----------------+
 
196
   * |VER | MTYP | LEN |     TOKEN      |
 
197
   * +----+------+----------------------+
 
198
   * | 1  |  1   |  2  | up to 2^16 - 1 |
 
199
   * +----+------+-----+----------------+
 
200
   */
 
201
 
 
202
  /* prepare service name */
 
203
  if (strchr(service, '/')) {
 
204
    service_name = malloc(strlen(service));
 
205
    if(!service_name)
 
206
      return CURLE_OUT_OF_MEMORY;
 
207
    memcpy(service_name, service, strlen(service));
 
208
  }
 
209
  else {
 
210
    service_name = malloc(strlen(service) + strlen(conn->proxy.name) + 2);
 
211
    if(!service_name)
 
212
      return CURLE_OUT_OF_MEMORY;
 
213
    snprintf(service_name,strlen(service) +strlen(conn->proxy.name)+2,"%s/%s",
 
214
             service,conn->proxy.name);
 
215
  }
 
216
 
 
217
  input_desc.cBuffers = 1;
 
218
  input_desc.pBuffers = &sspi_recv_token;
 
219
  input_desc.ulVersion = SECBUFFER_VERSION;
 
220
 
 
221
  sspi_recv_token.BufferType = SECBUFFER_TOKEN;
 
222
  sspi_recv_token.cbBuffer = 0;
 
223
  sspi_recv_token.pvBuffer = NULL;
 
224
 
 
225
  output_desc.cBuffers = 1;
 
226
  output_desc.pBuffers = &sspi_send_token;
 
227
  output_desc.ulVersion = SECBUFFER_VERSION;
 
228
 
 
229
  sspi_send_token.BufferType = SECBUFFER_TOKEN;
 
230
  sspi_send_token.cbBuffer = 0;
 
231
  sspi_send_token.pvBuffer = NULL;
 
232
 
 
233
  wrap_desc.cBuffers = 3;
 
234
  wrap_desc.pBuffers = sspi_w_token;
 
235
  wrap_desc.ulVersion = SECBUFFER_VERSION;
 
236
 
 
237
  cred_handle.dwLower = 0;
 
238
  cred_handle.dwUpper = 0;
 
239
 
 
240
  sspi_major_status = s_pSecFn->AcquireCredentialsHandleA( NULL,
 
241
                                                           (char *)"Kerberos",
 
242
                                                           SECPKG_CRED_OUTBOUND,
 
243
                                                           NULL,
 
244
                                                           NULL,
 
245
                                                           NULL,
 
246
                                                           NULL,
 
247
                                                           &cred_handle,
 
248
                                                           &expiry);
 
249
 
 
250
  if(check_sspi_err(data, sspi_major_status,sspi_minor_status,
 
251
                    "AcquireCredentialsHandleA") ) {
 
252
    failf(data, "Failed to acquire credentials.");
 
253
    free(service_name);
 
254
    service_name=NULL;
 
255
    s_pSecFn->FreeCredentialsHandle(&cred_handle);
 
256
    return CURLE_COULDNT_CONNECT;
 
257
  }
 
258
 
 
259
  /* As long as we need to keep sending some context info, and there's no  */
 
260
  /* errors, keep sending it...                                            */
 
261
  for(;;) {
 
262
 
 
263
    sspi_major_status = s_pSecFn->InitializeSecurityContextA(
 
264
                                    &cred_handle,
 
265
                                    context_handle,
 
266
                                    service_name,
 
267
                                    ISC_REQ_MUTUAL_AUTH |
 
268
                                    ISC_REQ_ALLOCATE_MEMORY |
 
269
                                    ISC_REQ_CONFIDENTIALITY |
 
270
                                    ISC_REQ_REPLAY_DETECT,
 
271
                                    0,
 
272
                                    SECURITY_NATIVE_DREP,
 
273
                                    &input_desc,
 
274
                                    0,
 
275
                                    &sspi_context,
 
276
                                    &output_desc,
 
277
                                    &sspi_ret_flags,
 
278
                                    &expiry);
 
279
 
 
280
    if(sspi_recv_token.pvBuffer) {
 
281
      s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
 
282
      sspi_recv_token.pvBuffer = NULL;
 
283
      sspi_recv_token.cbBuffer = 0;
 
284
    }
 
285
 
 
286
    if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
 
287
                      "InitializeSecurityContextA") ){
 
288
      free(service_name);
 
289
      service_name=NULL;
 
290
      s_pSecFn->FreeCredentialsHandle(&cred_handle);
 
291
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
292
      s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
 
293
      failf(data, "Failed to initialise security context.");
 
294
      return CURLE_COULDNT_CONNECT;
 
295
    }
 
296
 
 
297
    if(sspi_send_token.cbBuffer != 0) {
 
298
      socksreq[0] = 1;    /* gssapi subnegotiation version */
 
299
      socksreq[1] = 1;    /* authentication message type */
 
300
      us_length = htons((short)sspi_send_token.cbBuffer);
 
301
      memcpy(socksreq+2, &us_length, sizeof(short));
 
302
 
 
303
      code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
 
304
      if((code != CURLE_OK) || (4 != written)) {
 
305
        failf(data, "Failed to send SSPI authentication request.");
 
306
        free(service_name);
 
307
        service_name=NULL;
 
308
        s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
 
309
        s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
 
310
        s_pSecFn->FreeCredentialsHandle(&cred_handle);
 
311
        s_pSecFn->DeleteSecurityContext(&sspi_context);
 
312
        return CURLE_COULDNT_CONNECT;
 
313
      }
 
314
 
 
315
      code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer,
 
316
                              sspi_send_token.cbBuffer, &written);
 
317
      if((code != CURLE_OK) || (sspi_send_token.cbBuffer != (size_t)written)) {
 
318
        failf(data, "Failed to send SSPI authentication token.");
 
319
        free(service_name);
 
320
        service_name=NULL;
 
321
        s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
 
322
        s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
 
323
        s_pSecFn->FreeCredentialsHandle(&cred_handle);
 
324
        s_pSecFn->DeleteSecurityContext(&sspi_context);
 
325
        return CURLE_COULDNT_CONNECT;
 
326
      }
 
327
 
 
328
    }
 
329
 
 
330
    s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
 
331
    sspi_send_token.pvBuffer = NULL;
 
332
    sspi_send_token.cbBuffer = 0;
 
333
    s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
 
334
    sspi_recv_token.pvBuffer = NULL;
 
335
    sspi_recv_token.cbBuffer = 0;
 
336
    if(sspi_major_status != SEC_I_CONTINUE_NEEDED)  break;
 
337
 
 
338
    /* analyse response */
 
339
 
 
340
    /*   GSSAPI response looks like
 
341
     * +----+------+-----+----------------+
 
342
     * |VER | MTYP | LEN |     TOKEN      |
 
343
     * +----+------+----------------------+
 
344
     * | 1  |  1   |  2  | up to 2^16 - 1 |
 
345
     * +----+------+-----+----------------+
 
346
     */
 
347
 
 
348
    result=Curl_blockread_all(conn, sock, (char *)socksreq, 4,
 
349
                              &actualread, timeout);
 
350
    if(result != CURLE_OK || actualread != 4) {
 
351
      failf(data, "Failed to receive SSPI authentication response.");
 
352
      free(service_name);
 
353
      service_name=NULL;
 
354
      s_pSecFn->FreeCredentialsHandle(&cred_handle);
 
355
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
356
      return CURLE_COULDNT_CONNECT;
 
357
    }
 
358
 
 
359
    /* ignore the first (VER) byte */
 
360
    if(socksreq[1] == 255) { /* status / message type */
 
361
      failf(data, "User was rejected by the SOCKS5 server (%d %d).",
 
362
            socksreq[0], socksreq[1]);
 
363
      free(service_name);
 
364
      service_name=NULL;
 
365
      s_pSecFn->FreeCredentialsHandle(&cred_handle);
 
366
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
367
      return CURLE_COULDNT_CONNECT;
 
368
    }
 
369
 
 
370
    if(socksreq[1] != 1) { /* status / messgae type */
 
371
      failf(data, "Invalid SSPI authentication response type (%d %d).",
 
372
            socksreq[0], socksreq[1]);
 
373
      free(service_name);
 
374
      service_name=NULL;
 
375
      s_pSecFn->FreeCredentialsHandle(&cred_handle);
 
376
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
377
      return CURLE_COULDNT_CONNECT;
 
378
    }
 
379
 
 
380
    memcpy(&us_length, socksreq+2, sizeof(short));
 
381
    us_length = ntohs(us_length);
 
382
 
 
383
    sspi_recv_token.cbBuffer = us_length;
 
384
    sspi_recv_token.pvBuffer = malloc(us_length);
 
385
 
 
386
    if(!sspi_recv_token.pvBuffer) {
 
387
      free(service_name);
 
388
      service_name=NULL;
 
389
      s_pSecFn->FreeCredentialsHandle(&cred_handle);
 
390
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
391
      return CURLE_OUT_OF_MEMORY;
 
392
    }
 
393
    result = Curl_blockread_all(conn, sock, (char *)sspi_recv_token.pvBuffer,
 
394
                                sspi_recv_token.cbBuffer,
 
395
                                &actualread, timeout);
 
396
 
 
397
    if(result != CURLE_OK || actualread != us_length) {
 
398
      failf(data, "Failed to receive SSPI authentication token.");
 
399
      free(service_name);
 
400
      service_name=NULL;
 
401
      s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
 
402
      s_pSecFn->FreeCredentialsHandle(&cred_handle);
 
403
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
404
      return CURLE_COULDNT_CONNECT;
 
405
    }
 
406
 
 
407
    context_handle = &sspi_context;
 
408
  }
 
409
 
 
410
  free(service_name);
 
411
  service_name=NULL;
 
412
 
 
413
  /* Everything is good so far, user was authenticated! */
 
414
  sspi_major_status = s_pSecFn->QueryCredentialsAttributes( &cred_handle,
 
415
                                                            SECPKG_CRED_ATTR_NAMES,
 
416
                                                            &names);
 
417
  s_pSecFn->FreeCredentialsHandle(&cred_handle);
 
418
  if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
 
419
                    "QueryCredentialAttributes") ){
 
420
    s_pSecFn->DeleteSecurityContext(&sspi_context);
 
421
    s_pSecFn->FreeContextBuffer(names.sUserName);
 
422
    failf(data, "Failed to determine user name.");
 
423
    return CURLE_COULDNT_CONNECT;
 
424
  }
 
425
  infof(data, "SOCKS5 server authencticated user %s with gssapi.\n",
 
426
        names.sUserName);
 
427
  s_pSecFn->FreeContextBuffer(names.sUserName);
 
428
 
 
429
  /* Do encryption */
 
430
  socksreq[0] = 1;    /* gssapi subnegotiation version */
 
431
  socksreq[1] = 2;    /* encryption message type */
 
432
 
 
433
  gss_enc = 0; /* no data protection */
 
434
  /* do confidentiality protection if supported */
 
435
  if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY)
 
436
    gss_enc = 2;
 
437
  /* else do integrity protection */
 
438
  else if(sspi_ret_flags & ISC_REQ_INTEGRITY)
 
439
    gss_enc = 1;
 
440
 
 
441
  infof(data, "SOCKS5 server supports gssapi %s data protection.\n",
 
442
        (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality") );
 
443
  /* force to no data protection, avoid encryption/decryption for now */
 
444
  gss_enc = 0;
 
445
  /*
 
446
   * Sending the encryption type in clear seems wrong. It should be
 
447
   * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
 
448
   * The NEC reference implementations on which this is based is
 
449
   * therefore at fault
 
450
   *
 
451
   *  +------+------+------+.......................+
 
452
   *  + ver  | mtyp | len  |   token               |
 
453
   *  +------+------+------+.......................+
 
454
   *  + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
 
455
   *  +------+------+------+.......................+
 
456
   *
 
457
   *   Where:
 
458
   *
 
459
   *  - "ver" is the protocol version number, here 1 to represent the
 
460
   *    first version of the SOCKS/GSS-API protocol
 
461
   *
 
462
   *  - "mtyp" is the message type, here 2 to represent a protection
 
463
   *    -level negotiation message
 
464
   *
 
465
   *  - "len" is the length of the "token" field in octets
 
466
   *
 
467
   *  - "token" is the GSS-API encapsulated protection level
 
468
   *
 
469
   * The token is produced by encapsulating an octet containing the
 
470
   * required protection level using gss_seal()/gss_wrap() with conf_req
 
471
   * set to FALSE.  The token is verified using gss_unseal()/
 
472
   * gss_unwrap().
 
473
   *
 
474
   */
 
475
 
 
476
  if(data->set.socks5_gssapi_nec) {
 
477
    us_length = htons((short)1);
 
478
    memcpy(socksreq+2, &us_length, sizeof(short));
 
479
  }
 
480
  else {
 
481
    sspi_major_status = s_pSecFn->QueryContextAttributesA( &sspi_context,
 
482
                                                           SECPKG_ATTR_SIZES,
 
483
                                                           &sspi_sizes);
 
484
    if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
 
485
                      "QueryContextAttributesA")) {
 
486
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
487
      failf(data, "Failed to query security context attributes.");
 
488
      return CURLE_COULDNT_CONNECT;
 
489
    }
 
490
 
 
491
    sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer;
 
492
    sspi_w_token[0].BufferType = SECBUFFER_TOKEN;
 
493
    sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer);
 
494
 
 
495
    if(!sspi_w_token[0].pvBuffer) {
 
496
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
497
      return CURLE_OUT_OF_MEMORY;
 
498
    }
 
499
 
 
500
    sspi_w_token[1].cbBuffer = 1;
 
501
    sspi_w_token[1].pvBuffer = malloc(1);
 
502
    if(!sspi_w_token[1].pvBuffer){
 
503
      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
 
504
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
505
      return CURLE_OUT_OF_MEMORY;
 
506
    }
 
507
 
 
508
    memcpy(sspi_w_token[1].pvBuffer,&gss_enc,1);
 
509
    sspi_w_token[2].BufferType = SECBUFFER_PADDING;
 
510
    sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize;
 
511
    sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize);
 
512
    if(!sspi_w_token[2].pvBuffer) {
 
513
      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
 
514
      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
 
515
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
516
      return CURLE_OUT_OF_MEMORY;
 
517
    }
 
518
    sspi_major_status = s_pSecFn->EncryptMessage( &sspi_context,
 
519
                                                  KERB_WRAP_NO_ENCRYPT,
 
520
                                                  &wrap_desc,
 
521
                                                  0);
 
522
    if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
 
523
                      "EncryptMessage") ) {
 
524
      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
 
525
      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
 
526
      s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
 
527
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
528
      failf(data, "Failed to query security context attributes.");
 
529
      return CURLE_COULDNT_CONNECT;
 
530
    }
 
531
    sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer
 
532
      + sspi_w_token[1].cbBuffer
 
533
      + sspi_w_token[2].cbBuffer;
 
534
    sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer);
 
535
    if(!sspi_send_token.pvBuffer) {
 
536
      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
 
537
      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
 
538
      s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
 
539
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
540
      return CURLE_OUT_OF_MEMORY;
 
541
    }
 
542
 
 
543
    memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer,
 
544
           sspi_w_token[0].cbBuffer);
 
545
    memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer,
 
546
           sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer);
 
547
    memcpy((PUCHAR) sspi_send_token.pvBuffer
 
548
           +sspi_w_token[0].cbBuffer
 
549
           +sspi_w_token[1].cbBuffer,
 
550
           sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer);
 
551
 
 
552
    s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
 
553
    sspi_w_token[0].pvBuffer = NULL;
 
554
    sspi_w_token[0].cbBuffer = 0;
 
555
    s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
 
556
    sspi_w_token[1].pvBuffer = NULL;
 
557
    sspi_w_token[1].cbBuffer = 0;
 
558
    s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
 
559
    sspi_w_token[2].pvBuffer = NULL;
 
560
    sspi_w_token[2].cbBuffer = 0;
 
561
 
 
562
    us_length = htons((short)sspi_send_token.cbBuffer);
 
563
    memcpy(socksreq+2,&us_length,sizeof(short));
 
564
  }
 
565
 
 
566
  code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
 
567
  if((code != CURLE_OK) || (4 != written)) {
 
568
    failf(data, "Failed to send SSPI encryption request.");
 
569
    s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
 
570
    s_pSecFn->DeleteSecurityContext(&sspi_context);
 
571
    return CURLE_COULDNT_CONNECT;
 
572
  }
 
573
 
 
574
  if(data->set.socks5_gssapi_nec) {
 
575
    memcpy(socksreq,&gss_enc,1);
 
576
    code = Curl_write_plain(conn, sock, (char *)socksreq, 1, &written);
 
577
    if((code != CURLE_OK) || (1 != written)) {
 
578
      failf(data, "Failed to send SSPI encryption type.");
 
579
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
580
      return CURLE_COULDNT_CONNECT;
 
581
    }
 
582
  } else {
 
583
    code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer,
 
584
                            sspi_send_token.cbBuffer, &written);
 
585
    if((code != CURLE_OK) || (sspi_send_token.cbBuffer != (size_t)written)) {
 
586
      failf(data, "Failed to send SSPI encryption type.");
 
587
      s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
 
588
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
589
      return CURLE_COULDNT_CONNECT;
 
590
    }
 
591
    s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
 
592
  }
 
593
 
 
594
  result=Curl_blockread_all(conn, sock, (char *)socksreq, 4,
 
595
                            &actualread, timeout);
 
596
  if(result != CURLE_OK || actualread != 4) {
 
597
    failf(data, "Failed to receive SSPI encryption response.");
 
598
    s_pSecFn->DeleteSecurityContext(&sspi_context);
 
599
    return CURLE_COULDNT_CONNECT;
 
600
  }
 
601
 
 
602
  /* ignore the first (VER) byte */
 
603
  if(socksreq[1] == 255) { /* status / message type */
 
604
    failf(data, "User was rejected by the SOCKS5 server (%d %d).",
 
605
          socksreq[0], socksreq[1]);
 
606
    s_pSecFn->DeleteSecurityContext(&sspi_context);
 
607
    return CURLE_COULDNT_CONNECT;
 
608
  }
 
609
 
 
610
  if(socksreq[1] != 2) { /* status / message type */
 
611
    failf(data, "Invalid SSPI encryption response type (%d %d).",
 
612
          socksreq[0], socksreq[1]);
 
613
    s_pSecFn->DeleteSecurityContext(&sspi_context);
 
614
    return CURLE_COULDNT_CONNECT;
 
615
  }
 
616
 
 
617
  memcpy(&us_length, socksreq+2, sizeof(short));
 
618
  us_length = ntohs(us_length);
 
619
 
 
620
  sspi_w_token[0].cbBuffer = us_length;
 
621
  sspi_w_token[0].pvBuffer = malloc(us_length);
 
622
  if(!sspi_w_token[0].pvBuffer) {
 
623
    s_pSecFn->DeleteSecurityContext(&sspi_context);
 
624
    return CURLE_OUT_OF_MEMORY;
 
625
  }
 
626
 
 
627
  result=Curl_blockread_all(conn, sock, (char *)sspi_w_token[0].pvBuffer,
 
628
                            sspi_w_token[0].cbBuffer,
 
629
                            &actualread, timeout);
 
630
 
 
631
  if(result != CURLE_OK || actualread != us_length) {
 
632
    failf(data, "Failed to receive SSPI encryption type.");
 
633
    s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
 
634
    s_pSecFn->DeleteSecurityContext(&sspi_context);
 
635
    return CURLE_COULDNT_CONNECT;
 
636
  }
 
637
 
 
638
 
 
639
  if(!data->set.socks5_gssapi_nec) {
 
640
    wrap_desc.cBuffers = 2;
 
641
    sspi_w_token[0].BufferType = SECBUFFER_STREAM;
 
642
    sspi_w_token[1].BufferType = SECBUFFER_DATA;
 
643
    sspi_w_token[1].cbBuffer = 0;
 
644
    sspi_w_token[1].pvBuffer = NULL;
 
645
 
 
646
    sspi_major_status = s_pSecFn->DecryptMessage( &sspi_context,
 
647
                                                  &wrap_desc,
 
648
                                                  0,
 
649
                                                  &qop);
 
650
 
 
651
    if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
 
652
                      "DecryptMessage")) {
 
653
      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
 
654
      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
 
655
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
656
      failf(data, "Failed to query security context attributes.");
 
657
      return CURLE_COULDNT_CONNECT;
 
658
    }
 
659
 
 
660
    if(sspi_w_token[1].cbBuffer != 1) {
 
661
      failf(data, "Invalid SSPI encryption response length (%d).",
 
662
            sspi_w_token[1].cbBuffer);
 
663
      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
 
664
      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
 
665
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
666
      return CURLE_COULDNT_CONNECT;
 
667
    }
 
668
 
 
669
    memcpy(socksreq,sspi_w_token[1].pvBuffer,sspi_w_token[1].cbBuffer);
 
670
    s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
 
671
    s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
 
672
  } else {
 
673
    if(sspi_w_token[0].cbBuffer != 1) {
 
674
      failf(data, "Invalid SSPI encryption response length (%d).",
 
675
            sspi_w_token[0].cbBuffer);
 
676
      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
 
677
      s_pSecFn->DeleteSecurityContext(&sspi_context);
 
678
      return CURLE_COULDNT_CONNECT;
 
679
    }
 
680
    memcpy(socksreq,sspi_w_token[0].pvBuffer,sspi_w_token[0].cbBuffer);
 
681
    s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
 
682
  }
 
683
 
 
684
  infof(data, "SOCKS5 access with%s protection granted.\n",
 
685
        (socksreq[0]==0)?"out gssapi data":
 
686
        ((socksreq[0]==1)?" gssapi integrity":" gssapi confidentiality"));
 
687
 
 
688
  /* For later use if encryption is required
 
689
     conn->socks5_gssapi_enctype = socksreq[0];
 
690
     if (socksreq[0] != 0)
 
691
     conn->socks5_sspi_context = sspi_context;
 
692
     else {
 
693
     s_pSecFn->DeleteSecurityContext(&sspi_context);
 
694
     conn->socks5_sspi_context = sspi_context;
 
695
     }
 
696
  */
 
697
  return CURLE_OK;
 
698
}
 
699
#endif