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