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

« back to all changes in this revision

Viewing changes to lib/socks_gssapi.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_gssapi.c,v 1.2 2009-01-30 19:29:25 danf Exp $
 
22
 ***************************************************************************/
 
23
 
 
24
#include "setup.h"
 
25
 
 
26
#ifndef CURL_DISABLE_PROXY
 
27
 
 
28
#ifdef HAVE_GSSAPI
 
29
#ifdef HAVE_OLD_GSSMIT
 
30
#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
 
31
#endif
 
32
#ifndef gss_nt_service_name
 
33
#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
 
34
#endif
 
35
#include <string.h>
 
36
 
 
37
#ifdef NEED_MALLOC_H
 
38
#include <malloc.h>
 
39
#endif
 
40
#ifdef HAVE_STDLIB_H
 
41
#include <stdlib.h>
 
42
#endif
 
43
 
 
44
#include "urldata.h"
 
45
#include "sendf.h"
 
46
#include "connect.h"
 
47
#include "timeval.h"
 
48
#include "socks.h"
 
49
 
 
50
static gss_ctx_id_t     gss_context = GSS_C_NO_CONTEXT;
 
51
 
 
52
#define _MPRINTF_REPLACE /* use our functions only */
 
53
#include <curl/mprintf.h>
 
54
 
 
55
/* The last #include file should be: */
 
56
#include "memdebug.h"
 
57
 
 
58
/*
 
59
 * Helper gssapi error functions.
 
60
 */
 
61
static int check_gss_err(struct SessionHandle *data,
 
62
                         OM_uint32 major_status,
 
63
                         OM_uint32 minor_status,
 
64
                         const char* function)
 
65
{
 
66
  if(GSS_ERROR(major_status)) {
 
67
    OM_uint32 maj_stat,min_stat;
 
68
    OM_uint32 msg_ctx = 0;
 
69
    gss_buffer_desc status_string;
 
70
    char buf[1024];
 
71
    size_t len;
 
72
 
 
73
    len = 0;
 
74
    msg_ctx = 0;
 
75
    while(!msg_ctx) {
 
76
      /* convert major status code (GSS-API error) to text */
 
77
      maj_stat = gss_display_status(&min_stat, major_status,
 
78
                                    GSS_C_GSS_CODE,
 
79
                                    GSS_C_NULL_OID,
 
80
                                    &msg_ctx, &status_string);
 
81
      if(maj_stat == GSS_S_COMPLETE) {
 
82
        if(sizeof(buf) > len + status_string.length + 1) {
 
83
          strcpy(buf+len, (char*) status_string.value);
 
84
          len += status_string.length;
 
85
        }
 
86
        gss_release_buffer(&min_stat, &status_string);
 
87
        break;
 
88
      }
 
89
      gss_release_buffer(&min_stat, &status_string);
 
90
    }
 
91
    if(sizeof(buf) > len + 3) {
 
92
      strcpy(buf+len, ".\n");
 
93
      len += 2;
 
94
    }
 
95
    msg_ctx = 0;
 
96
    while(!msg_ctx) {
 
97
      /* convert minor status code (underlying routine error) to text */
 
98
      maj_stat = gss_display_status(&min_stat, minor_status,
 
99
                                    GSS_C_MECH_CODE,
 
100
                                    GSS_C_NULL_OID,
 
101
                                    &msg_ctx, &status_string);
 
102
      if(maj_stat == GSS_S_COMPLETE) {
 
103
        if(sizeof(buf) > len + status_string.length) {
 
104
          strcpy(buf+len, (char*) status_string.value);
 
105
          len += status_string.length;
 
106
        }
 
107
        gss_release_buffer(&min_stat, &status_string);
 
108
        break;
 
109
      }
 
110
      gss_release_buffer(&min_stat, &status_string);
 
111
    }
 
112
    failf(data, "GSSAPI error: %s failed:\n%s\n", function, buf);
 
113
    return(1);
 
114
  }
 
115
 
 
116
  return(0);
 
117
}
 
118
 
 
119
CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
 
120
                                      struct connectdata *conn)
 
121
{
 
122
  struct SessionHandle *data = conn->data;
 
123
  curl_socket_t sock = conn->sock[sockindex];
 
124
  CURLcode code;
 
125
  ssize_t actualread;
 
126
  ssize_t written;
 
127
  int result;
 
128
  long timeout;
 
129
  OM_uint32 gss_major_status, gss_minor_status, gss_status;
 
130
  OM_uint32 gss_ret_flags;
 
131
  int gss_conf_state, gss_enc;
 
132
  gss_buffer_desc  service = GSS_C_EMPTY_BUFFER;
 
133
  gss_buffer_desc  gss_send_token = GSS_C_EMPTY_BUFFER;
 
134
  gss_buffer_desc  gss_recv_token = GSS_C_EMPTY_BUFFER;
 
135
  gss_buffer_desc  gss_w_token = GSS_C_EMPTY_BUFFER;
 
136
  gss_buffer_desc* gss_token = GSS_C_NO_BUFFER;
 
137
  gss_name_t       server = GSS_C_NO_NAME;
 
138
  gss_name_t       gss_client_name = GSS_C_NO_NAME;
 
139
  u_short          us_length;
 
140
  char             *user=NULL;
 
141
  unsigned char socksreq[4]; /* room for gssapi exchange header only */
 
142
  char *serviceptr = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE];
 
143
 
 
144
  /* get timeout */
 
145
  timeout = Curl_timeleft(conn, NULL, TRUE);
 
146
 
 
147
  /*   GSSAPI request looks like
 
148
   * +----+------+-----+----------------+
 
149
   * |VER | MTYP | LEN |     TOKEN      |
 
150
   * +----+------+----------------------+
 
151
   * | 1  |  1   |  2  | up to 2^16 - 1 |
 
152
   * +----+------+-----+----------------+
 
153
   */
 
154
 
 
155
  /* prepare service name */
 
156
  if (strchr(serviceptr,'/')) {
 
157
    service.value = malloc(strlen(serviceptr));
 
158
    if(!service.value)
 
159
      return CURLE_OUT_OF_MEMORY;
 
160
    service.length = strlen(serviceptr);
 
161
    memcpy(service.value, serviceptr, service.length);
 
162
 
 
163
    gss_major_status = gss_import_name(&gss_minor_status, &service,
 
164
                                       (gss_OID) GSS_C_NULL_OID, &server);
 
165
  }
 
166
  else {
 
167
    service.value = malloc(strlen(serviceptr) +strlen(conn->proxy.name)+2);
 
168
    if(!service.value)
 
169
      return CURLE_OUT_OF_MEMORY;
 
170
    service.length = strlen(serviceptr) +strlen(conn->proxy.name)+1;
 
171
    snprintf(service.value, service.length+1, "%s@%s",
 
172
             serviceptr, conn->proxy.name);
 
173
 
 
174
    gss_major_status = gss_import_name(&gss_minor_status, &service,
 
175
                                       gss_nt_service_name, &server);
 
176
  }
 
177
 
 
178
  gss_release_buffer(&gss_status, &service); /* clear allocated memory */
 
179
 
 
180
  if(check_gss_err(data,gss_major_status,
 
181
                   gss_minor_status,"gss_import_name()")) {
 
182
    failf(data, "Failed to create service name.");
 
183
    gss_release_name(&gss_status, &server);
 
184
    return CURLE_COULDNT_CONNECT;
 
185
  }
 
186
 
 
187
  /* As long as we need to keep sending some context info, and there's no  */
 
188
  /* errors, keep sending it...                                            */
 
189
  for(;;) {
 
190
    gss_major_status = gss_init_sec_context(&gss_minor_status,
 
191
                                            GSS_C_NO_CREDENTIAL,
 
192
                                            &gss_context, server,
 
193
                                            GSS_C_NULL_OID,
 
194
                                            GSS_C_MUTUAL_FLAG |
 
195
                                            GSS_C_REPLAY_FLAG,
 
196
                                            0,
 
197
                                            NULL,
 
198
                                            gss_token,
 
199
                                            NULL,
 
200
                                            &gss_send_token,
 
201
                                            &gss_ret_flags,
 
202
                                            NULL);
 
203
 
 
204
    if(gss_token != GSS_C_NO_BUFFER)
 
205
      gss_release_buffer(&gss_status, &gss_recv_token);
 
206
    if(check_gss_err(data,gss_major_status,
 
207
                     gss_minor_status,"gss_init_sec_context")) {
 
208
      gss_release_name(&gss_status, &server);
 
209
      gss_release_buffer(&gss_status, &gss_recv_token);
 
210
      gss_release_buffer(&gss_status, &gss_send_token);
 
211
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
212
      failf(data, "Failed to initial GSSAPI token.");
 
213
      return CURLE_COULDNT_CONNECT;
 
214
    }
 
215
 
 
216
    if(gss_send_token.length != 0) {
 
217
      socksreq[0] = 1;    /* gssapi subnegotiation version */
 
218
      socksreq[1] = 1;    /* authentication message type */
 
219
      us_length = htons((short)gss_send_token.length);
 
220
      memcpy(socksreq+2,&us_length,sizeof(short));
 
221
 
 
222
      code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
 
223
      if((code != CURLE_OK) || (4 != written)) {
 
224
        failf(data, "Failed to send GSSAPI authentication request.");
 
225
        gss_release_name(&gss_status, &server);
 
226
        gss_release_buffer(&gss_status, &gss_recv_token);
 
227
        gss_release_buffer(&gss_status, &gss_send_token);
 
228
        gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
229
        return CURLE_COULDNT_CONNECT;
 
230
      }
 
231
 
 
232
      code = Curl_write_plain(conn, sock, (char *)gss_send_token.value,
 
233
                              gss_send_token.length, &written);
 
234
 
 
235
      if((code != CURLE_OK) || ((ssize_t)gss_send_token.length != written)) {
 
236
        failf(data, "Failed to send GSSAPI authentication token.");
 
237
        gss_release_name(&gss_status, &server);
 
238
        gss_release_buffer(&gss_status, &gss_recv_token);
 
239
        gss_release_buffer(&gss_status, &gss_send_token);
 
240
        gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
241
        return CURLE_COULDNT_CONNECT;
 
242
      }
 
243
 
 
244
    }
 
245
 
 
246
    gss_release_buffer(&gss_status, &gss_send_token);
 
247
    gss_release_buffer(&gss_status, &gss_recv_token);
 
248
    if(gss_major_status != GSS_S_CONTINUE_NEEDED) break;
 
249
 
 
250
    /* analyse response */
 
251
 
 
252
    /*   GSSAPI response looks like
 
253
     * +----+------+-----+----------------+
 
254
     * |VER | MTYP | LEN |     TOKEN      |
 
255
     * +----+------+----------------------+
 
256
     * | 1  |  1   |  2  | up to 2^16 - 1 |
 
257
     * +----+------+-----+----------------+
 
258
     */
 
259
 
 
260
    result=Curl_blockread_all(conn, sock, (char *)socksreq, 4,
 
261
                              &actualread, timeout);
 
262
    if(result != CURLE_OK || actualread != 4) {
 
263
      failf(data, "Failed to receive GSSAPI authentication response.");
 
264
      gss_release_name(&gss_status, &server);
 
265
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
266
      return CURLE_COULDNT_CONNECT;
 
267
    }
 
268
 
 
269
    /* ignore the first (VER) byte */
 
270
    if(socksreq[1] == 255) { /* status / message type */
 
271
      failf(data, "User was rejected by the SOCKS5 server (%d %d).",
 
272
            socksreq[0], socksreq[1]);
 
273
      gss_release_name(&gss_status, &server);
 
274
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
275
      return CURLE_COULDNT_CONNECT;
 
276
    }
 
277
 
 
278
    if(socksreq[1] != 1) { /* status / messgae type */
 
279
      failf(data, "Invalid GSSAPI authentication response type (%d %d).",
 
280
            socksreq[0], socksreq[1]);
 
281
      gss_release_name(&gss_status, &server);
 
282
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
283
      return CURLE_COULDNT_CONNECT;
 
284
    }
 
285
 
 
286
    memcpy(&us_length, socksreq+2, sizeof(short));
 
287
    us_length = ntohs(us_length);
 
288
 
 
289
    gss_recv_token.length=us_length;
 
290
    gss_recv_token.value=malloc(us_length);
 
291
    if(!gss_recv_token.value) {
 
292
      failf(data,
 
293
            "Could not allocate memory for GSSAPI authentication "
 
294
            "response token.");
 
295
      gss_release_name(&gss_status, &server);
 
296
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
297
      return CURLE_OUT_OF_MEMORY;
 
298
    }
 
299
 
 
300
    result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
 
301
                              gss_recv_token.length,
 
302
                              &actualread, timeout);
 
303
 
 
304
    if(result != CURLE_OK || actualread != us_length) {
 
305
      failf(data, "Failed to receive GSSAPI authentication token.");
 
306
      gss_release_name(&gss_status, &server);
 
307
      gss_release_buffer(&gss_status, &gss_recv_token);
 
308
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
309
      return CURLE_COULDNT_CONNECT;
 
310
    }
 
311
 
 
312
    gss_token = &gss_recv_token;
 
313
  }
 
314
 
 
315
  gss_release_name(&gss_status, &server);
 
316
 
 
317
  /* Everything is good so far, user was authenticated! */
 
318
  gss_major_status = gss_inquire_context (&gss_minor_status, gss_context,
 
319
                                          &gss_client_name, NULL, NULL, NULL,
 
320
                                          NULL, NULL, NULL);
 
321
  if(check_gss_err(data,gss_major_status,
 
322
                   gss_minor_status,"gss_inquire_context")) {
 
323
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
324
    gss_release_name(&gss_status, &gss_client_name);
 
325
    failf(data, "Failed to determine user name.");
 
326
    return CURLE_COULDNT_CONNECT;
 
327
  }
 
328
  gss_major_status = gss_display_name(&gss_minor_status, gss_client_name,
 
329
                                      &gss_send_token, NULL);
 
330
  if(check_gss_err(data,gss_major_status,
 
331
                   gss_minor_status,"gss_display_name")) {
 
332
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
333
    gss_release_name(&gss_status, &gss_client_name);
 
334
    gss_release_buffer(&gss_status, &gss_send_token);
 
335
    failf(data, "Failed to determine user name.");
 
336
    return CURLE_COULDNT_CONNECT;
 
337
  }
 
338
  user=malloc(gss_send_token.length+1);
 
339
  if(!user) {
 
340
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
341
    gss_release_name(&gss_status, &gss_client_name);
 
342
    gss_release_buffer(&gss_status, &gss_send_token);
 
343
    return CURLE_OUT_OF_MEMORY;
 
344
  }
 
345
 
 
346
  memcpy(user, gss_send_token.value, gss_send_token.length);
 
347
  user[gss_send_token.length] = '\0';
 
348
  gss_release_name(&gss_status, &gss_client_name);
 
349
  gss_release_buffer(&gss_status, &gss_send_token);
 
350
  infof(data, "SOCKS5 server authencticated user %s with gssapi.\n",user);
 
351
  free(user);
 
352
  user=NULL;
 
353
 
 
354
  /* Do encryption */
 
355
  socksreq[0] = 1;    /* gssapi subnegotiation version */
 
356
  socksreq[1] = 2;    /* encryption message type */
 
357
 
 
358
  gss_enc = 0; /* no data protection */
 
359
  /* do confidentiality protection if supported */
 
360
  if(gss_ret_flags & GSS_C_CONF_FLAG)
 
361
    gss_enc = 2;
 
362
  /* else do integrity protection */
 
363
  else if(gss_ret_flags & GSS_C_INTEG_FLAG)
 
364
    gss_enc = 1;
 
365
 
 
366
  infof(data, "SOCKS5 server supports gssapi %s data protection.\n",
 
367
        (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality"));
 
368
  /* force for the moment to no data protection */
 
369
  gss_enc = 0;
 
370
  /*
 
371
   * Sending the encryption type in clear seems wrong. It should be
 
372
   * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
 
373
   * The NEC reference implementations on which this is based is
 
374
   * therefore at fault
 
375
   *
 
376
   *  +------+------+------+.......................+
 
377
   *  + ver  | mtyp | len  |   token               |
 
378
   *  +------+------+------+.......................+
 
379
   *  + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
 
380
   *  +------+------+------+.......................+
 
381
   *
 
382
   *   Where:
 
383
   *
 
384
   *  - "ver" is the protocol version number, here 1 to represent the
 
385
   *    first version of the SOCKS/GSS-API protocol
 
386
   *
 
387
   *  - "mtyp" is the message type, here 2 to represent a protection
 
388
   *    -level negotiation message
 
389
   *
 
390
   *  - "len" is the length of the "token" field in octets
 
391
   *
 
392
   *  - "token" is the GSS-API encapsulated protection level
 
393
   *
 
394
   * The token is produced by encapsulating an octet containing the
 
395
   * required protection level using gss_seal()/gss_wrap() with conf_req
 
396
   * set to FALSE.  The token is verified using gss_unseal()/
 
397
   * gss_unwrap().
 
398
   *
 
399
   */
 
400
  if(data->set.socks5_gssapi_nec) {
 
401
    us_length = htons((short)1);
 
402
    memcpy(socksreq+2,&us_length,sizeof(short));
 
403
  }
 
404
  else {
 
405
    gss_send_token.length = 1;
 
406
    gss_send_token.value = malloc(1);
 
407
    if(!gss_send_token.value) {
 
408
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
409
      return CURLE_OUT_OF_MEMORY;
 
410
    }
 
411
    memcpy(gss_send_token.value, &gss_enc, 1);
 
412
 
 
413
    gss_major_status = gss_wrap(&gss_minor_status, gss_context, 0,
 
414
                                GSS_C_QOP_DEFAULT, &gss_send_token,
 
415
                                &gss_conf_state, &gss_w_token);
 
416
 
 
417
    if(check_gss_err(data,gss_major_status,gss_minor_status,"gss_wrap")) {
 
418
      gss_release_buffer(&gss_status, &gss_send_token);
 
419
      gss_release_buffer(&gss_status, &gss_w_token);
 
420
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
421
      failf(data, "Failed to wrap GSSAPI encryption value into token.");
 
422
      return CURLE_COULDNT_CONNECT;
 
423
    }
 
424
    gss_release_buffer(&gss_status, &gss_send_token);
 
425
 
 
426
    us_length = htons((short)gss_w_token.length);
 
427
    memcpy(socksreq+2,&us_length,sizeof(short));
 
428
  }
 
429
 
 
430
  code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
 
431
  if((code != CURLE_OK) || (4 != written)) {
 
432
    failf(data, "Failed to send GSSAPI encryption request.");
 
433
    gss_release_buffer(&gss_status, &gss_w_token);
 
434
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
435
    return CURLE_COULDNT_CONNECT;
 
436
  }
 
437
 
 
438
  if(data->set.socks5_gssapi_nec) {
 
439
    memcpy(socksreq, &gss_enc, 1);
 
440
    code = Curl_write_plain(conn, sock, socksreq, 1, &written);
 
441
    if((code != CURLE_OK) || ( 1 != written)) {
 
442
      failf(data, "Failed to send GSSAPI encryption type.");
 
443
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
444
      return CURLE_COULDNT_CONNECT;
 
445
    }
 
446
  } else {
 
447
    code = Curl_write_plain(conn, sock, (char *)gss_w_token.value,
 
448
                            gss_w_token.length, &written);
 
449
    if((code != CURLE_OK) || ((ssize_t)gss_w_token.length != written)) {
 
450
      failf(data, "Failed to send GSSAPI encryption type.");
 
451
      gss_release_buffer(&gss_status, &gss_w_token);
 
452
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
453
      return CURLE_COULDNT_CONNECT;
 
454
    }
 
455
    gss_release_buffer(&gss_status, &gss_w_token);
 
456
  }
 
457
 
 
458
  result=Curl_blockread_all(conn, sock, (char *)socksreq, 4,
 
459
                            &actualread, timeout);
 
460
  if(result != CURLE_OK || actualread != 4) {
 
461
    failf(data, "Failed to receive GSSAPI encryption response.");
 
462
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
463
    return CURLE_COULDNT_CONNECT;
 
464
  }
 
465
 
 
466
  /* ignore the first (VER) byte */
 
467
  if(socksreq[1] == 255) { /* status / message type */
 
468
    failf(data, "User was rejected by the SOCKS5 server (%d %d).",
 
469
          socksreq[0], socksreq[1]);
 
470
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
471
    return CURLE_COULDNT_CONNECT;
 
472
  }
 
473
 
 
474
  if(socksreq[1] != 2) { /* status / messgae type */
 
475
    failf(data, "Invalid GSSAPI encryption response type (%d %d).",
 
476
          socksreq[0], socksreq[1]);
 
477
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
478
    return CURLE_COULDNT_CONNECT;
 
479
  }
 
480
 
 
481
  memcpy(&us_length, socksreq+2, sizeof(short));
 
482
  us_length = ntohs(us_length);
 
483
 
 
484
  gss_recv_token.length= us_length;
 
485
  gss_recv_token.value=malloc(gss_recv_token.length);
 
486
  if(!gss_recv_token.value) {
 
487
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
488
    return CURLE_OUT_OF_MEMORY;
 
489
  }
 
490
  result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
 
491
                            gss_recv_token.length,
 
492
                            &actualread, timeout);
 
493
 
 
494
  if(result != CURLE_OK || actualread != us_length) {
 
495
    failf(data, "Failed to receive GSSAPI encryptrion type.");
 
496
    gss_release_buffer(&gss_status, &gss_recv_token);
 
497
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
498
    return CURLE_COULDNT_CONNECT;
 
499
  }
 
500
 
 
501
  if(!data->set.socks5_gssapi_nec) {
 
502
    gss_major_status = gss_unwrap(&gss_minor_status, gss_context,
 
503
                                  &gss_recv_token, &gss_w_token,
 
504
                                  0, GSS_C_QOP_DEFAULT);
 
505
 
 
506
    if(check_gss_err(data,gss_major_status,gss_minor_status,"gss_unwrap")) {
 
507
      gss_release_buffer(&gss_status, &gss_recv_token);
 
508
      gss_release_buffer(&gss_status, &gss_w_token);
 
509
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
510
      failf(data, "Failed to unwrap GSSAPI encryption value into token.");
 
511
      return CURLE_COULDNT_CONNECT;
 
512
    }
 
513
    gss_release_buffer(&gss_status, &gss_recv_token);
 
514
 
 
515
    if(gss_w_token.length != 1) {
 
516
      failf(data, "Invalid GSSAPI encryption response length (%d).",
 
517
            gss_w_token.length);
 
518
      gss_release_buffer(&gss_status, &gss_w_token);
 
519
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
520
      return CURLE_COULDNT_CONNECT;
 
521
    }
 
522
 
 
523
    memcpy(socksreq,gss_w_token.value,gss_w_token.length);
 
524
    gss_release_buffer(&gss_status, &gss_w_token);
 
525
  }
 
526
  else {
 
527
    if(gss_recv_token.length != 1) {
 
528
      failf(data, "Invalid GSSAPI encryption response length (%d).",
 
529
            gss_recv_token.length);
 
530
      gss_release_buffer(&gss_status, &gss_recv_token);
 
531
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
532
      return CURLE_COULDNT_CONNECT;
 
533
    }
 
534
 
 
535
    memcpy(socksreq,gss_recv_token.value,gss_recv_token.length);
 
536
    gss_release_buffer(&gss_status, &gss_recv_token);
 
537
  }
 
538
 
 
539
  infof(data, "SOCKS5 access with%s protection granted.\n",
 
540
        (socksreq[0]==0)?"out gssapi data":
 
541
        ((socksreq[0]==1)?" gssapi integrity":" gssapi confidentiality"));
 
542
 
 
543
  conn->socks5_gssapi_enctype = socksreq[0];
 
544
  if(socksreq[0] == 0)
 
545
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
546
 
 
547
  return CURLE_OK;
 
548
}
 
549
#endif
 
550
 
 
551
#endif /* CURL_DISABLE_PROXY */