00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "curl_setup.h"
00025
00026 #if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_PROXY)
00027
00028 #include "curl_gssapi.h"
00029 #include "urldata.h"
00030 #include "sendf.h"
00031 #include "connect.h"
00032 #include "timeval.h"
00033 #include "socks.h"
00034 #include "warnless.h"
00035
00036
00037 #include "curl_printf.h"
00038 #include "curl_memory.h"
00039 #include "memdebug.h"
00040
00041 static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
00042
00043
00044
00045
00046 static int check_gss_err(struct Curl_easy *data,
00047 OM_uint32 major_status,
00048 OM_uint32 minor_status,
00049 const char *function)
00050 {
00051 if(GSS_ERROR(major_status)) {
00052 OM_uint32 maj_stat, min_stat;
00053 OM_uint32 msg_ctx = 0;
00054 gss_buffer_desc status_string;
00055 char buf[1024];
00056 size_t len;
00057
00058 len = 0;
00059 msg_ctx = 0;
00060 while(!msg_ctx) {
00061
00062 maj_stat = gss_display_status(&min_stat, major_status,
00063 GSS_C_GSS_CODE,
00064 GSS_C_NULL_OID,
00065 &msg_ctx, &status_string);
00066 if(maj_stat == GSS_S_COMPLETE) {
00067 if(sizeof(buf) > len + status_string.length + 1) {
00068 strcpy(buf+len, (char *) status_string.value);
00069 len += status_string.length;
00070 }
00071 gss_release_buffer(&min_stat, &status_string);
00072 break;
00073 }
00074 gss_release_buffer(&min_stat, &status_string);
00075 }
00076 if(sizeof(buf) > len + 3) {
00077 strcpy(buf+len, ".\n");
00078 len += 2;
00079 }
00080 msg_ctx = 0;
00081 while(!msg_ctx) {
00082
00083 maj_stat = gss_display_status(&min_stat, minor_status,
00084 GSS_C_MECH_CODE,
00085 GSS_C_NULL_OID,
00086 &msg_ctx, &status_string);
00087 if(maj_stat == GSS_S_COMPLETE) {
00088 if(sizeof(buf) > len + status_string.length)
00089 strcpy(buf+len, (char *) status_string.value);
00090 gss_release_buffer(&min_stat, &status_string);
00091 break;
00092 }
00093 gss_release_buffer(&min_stat, &status_string);
00094 }
00095 failf(data, "GSS-API error: %s failed:\n%s", function, buf);
00096 return 1;
00097 }
00098
00099 return 0;
00100 }
00101
00102 CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
00103 struct connectdata *conn)
00104 {
00105 struct Curl_easy *data = conn->data;
00106 curl_socket_t sock = conn->sock[sockindex];
00107 CURLcode code;
00108 ssize_t actualread;
00109 ssize_t written;
00110 int result;
00111 OM_uint32 gss_major_status, gss_minor_status, gss_status;
00112 OM_uint32 gss_ret_flags;
00113 int gss_conf_state, gss_enc;
00114 gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
00115 gss_buffer_desc gss_send_token = GSS_C_EMPTY_BUFFER;
00116 gss_buffer_desc gss_recv_token = GSS_C_EMPTY_BUFFER;
00117 gss_buffer_desc gss_w_token = GSS_C_EMPTY_BUFFER;
00118 gss_buffer_desc* gss_token = GSS_C_NO_BUFFER;
00119 gss_name_t server = GSS_C_NO_NAME;
00120 gss_name_t gss_client_name = GSS_C_NO_NAME;
00121 unsigned short us_length;
00122 char *user=NULL;
00123 unsigned char socksreq[4];
00124 const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ?
00125 data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd";
00126 const size_t serviceptr_length = strlen(serviceptr);
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 if(strchr(serviceptr, '/')) {
00138 service.length = serviceptr_length;
00139 service.value = malloc(service.length);
00140 if(!service.value)
00141 return CURLE_OUT_OF_MEMORY;
00142 memcpy(service.value, serviceptr, service.length);
00143
00144 gss_major_status = gss_import_name(&gss_minor_status, &service,
00145 (gss_OID) GSS_C_NULL_OID, &server);
00146 }
00147 else {
00148 service.value = malloc(serviceptr_length +
00149 strlen(conn->socks_proxy.host.name)+2);
00150 if(!service.value)
00151 return CURLE_OUT_OF_MEMORY;
00152 service.length = serviceptr_length + strlen(conn->socks_proxy.host.name)+1;
00153 snprintf(service.value, service.length+1, "%s@%s",
00154 serviceptr, conn->socks_proxy.host.name);
00155
00156 gss_major_status = gss_import_name(&gss_minor_status, &service,
00157 GSS_C_NT_HOSTBASED_SERVICE, &server);
00158 }
00159
00160 gss_release_buffer(&gss_status, &service);
00161
00162 if(check_gss_err(data, gss_major_status,
00163 gss_minor_status, "gss_import_name()")) {
00164 failf(data, "Failed to create service name.");
00165 gss_release_name(&gss_status, &server);
00166 return CURLE_COULDNT_CONNECT;
00167 }
00168
00169
00170
00171 for(;;) {
00172 gss_major_status = Curl_gss_init_sec_context(data,
00173 &gss_minor_status,
00174 &gss_context,
00175 server,
00176 &Curl_krb5_mech_oid,
00177 NULL,
00178 gss_token,
00179 &gss_send_token,
00180 TRUE,
00181 &gss_ret_flags);
00182
00183 if(gss_token != GSS_C_NO_BUFFER)
00184 gss_release_buffer(&gss_status, &gss_recv_token);
00185 if(check_gss_err(data, gss_major_status,
00186 gss_minor_status, "gss_init_sec_context")) {
00187 gss_release_name(&gss_status, &server);
00188 gss_release_buffer(&gss_status, &gss_recv_token);
00189 gss_release_buffer(&gss_status, &gss_send_token);
00190 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00191 failf(data, "Failed to initial GSS-API token.");
00192 return CURLE_COULDNT_CONNECT;
00193 }
00194
00195 if(gss_send_token.length != 0) {
00196 socksreq[0] = 1;
00197 socksreq[1] = 1;
00198 us_length = htons((short)gss_send_token.length);
00199 memcpy(socksreq+2, &us_length, sizeof(short));
00200
00201 code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
00202 if(code || (4 != written)) {
00203 failf(data, "Failed to send GSS-API authentication request.");
00204 gss_release_name(&gss_status, &server);
00205 gss_release_buffer(&gss_status, &gss_recv_token);
00206 gss_release_buffer(&gss_status, &gss_send_token);
00207 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00208 return CURLE_COULDNT_CONNECT;
00209 }
00210
00211 code = Curl_write_plain(conn, sock, (char *)gss_send_token.value,
00212 gss_send_token.length, &written);
00213
00214 if(code || ((ssize_t)gss_send_token.length != written)) {
00215 failf(data, "Failed to send GSS-API authentication token.");
00216 gss_release_name(&gss_status, &server);
00217 gss_release_buffer(&gss_status, &gss_recv_token);
00218 gss_release_buffer(&gss_status, &gss_send_token);
00219 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00220 return CURLE_COULDNT_CONNECT;
00221 }
00222
00223 }
00224
00225 gss_release_buffer(&gss_status, &gss_send_token);
00226 gss_release_buffer(&gss_status, &gss_recv_token);
00227 if(gss_major_status != GSS_S_CONTINUE_NEEDED) break;
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239 result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
00240 if(result || (actualread != 4)) {
00241 failf(data, "Failed to receive GSS-API authentication response.");
00242 gss_release_name(&gss_status, &server);
00243 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00244 return CURLE_COULDNT_CONNECT;
00245 }
00246
00247
00248 if(socksreq[1] == 255) {
00249 failf(data, "User was rejected by the SOCKS5 server (%d %d).",
00250 socksreq[0], socksreq[1]);
00251 gss_release_name(&gss_status, &server);
00252 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00253 return CURLE_COULDNT_CONNECT;
00254 }
00255
00256 if(socksreq[1] != 1) {
00257 failf(data, "Invalid GSS-API authentication response type (%d %d).",
00258 socksreq[0], socksreq[1]);
00259 gss_release_name(&gss_status, &server);
00260 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00261 return CURLE_COULDNT_CONNECT;
00262 }
00263
00264 memcpy(&us_length, socksreq+2, sizeof(short));
00265 us_length = ntohs(us_length);
00266
00267 gss_recv_token.length=us_length;
00268 gss_recv_token.value=malloc(us_length);
00269 if(!gss_recv_token.value) {
00270 failf(data,
00271 "Could not allocate memory for GSS-API authentication "
00272 "response token.");
00273 gss_release_name(&gss_status, &server);
00274 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00275 return CURLE_OUT_OF_MEMORY;
00276 }
00277
00278 result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
00279 gss_recv_token.length, &actualread);
00280
00281 if(result || (actualread != us_length)) {
00282 failf(data, "Failed to receive GSS-API authentication token.");
00283 gss_release_name(&gss_status, &server);
00284 gss_release_buffer(&gss_status, &gss_recv_token);
00285 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00286 return CURLE_COULDNT_CONNECT;
00287 }
00288
00289 gss_token = &gss_recv_token;
00290 }
00291
00292 gss_release_name(&gss_status, &server);
00293
00294
00295 gss_major_status = gss_inquire_context(&gss_minor_status, gss_context,
00296 &gss_client_name, NULL, NULL, NULL,
00297 NULL, NULL, NULL);
00298 if(check_gss_err(data, gss_major_status,
00299 gss_minor_status, "gss_inquire_context")) {
00300 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00301 gss_release_name(&gss_status, &gss_client_name);
00302 failf(data, "Failed to determine user name.");
00303 return CURLE_COULDNT_CONNECT;
00304 }
00305 gss_major_status = gss_display_name(&gss_minor_status, gss_client_name,
00306 &gss_send_token, NULL);
00307 if(check_gss_err(data, gss_major_status,
00308 gss_minor_status, "gss_display_name")) {
00309 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00310 gss_release_name(&gss_status, &gss_client_name);
00311 gss_release_buffer(&gss_status, &gss_send_token);
00312 failf(data, "Failed to determine user name.");
00313 return CURLE_COULDNT_CONNECT;
00314 }
00315 user=malloc(gss_send_token.length+1);
00316 if(!user) {
00317 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00318 gss_release_name(&gss_status, &gss_client_name);
00319 gss_release_buffer(&gss_status, &gss_send_token);
00320 return CURLE_OUT_OF_MEMORY;
00321 }
00322
00323 memcpy(user, gss_send_token.value, gss_send_token.length);
00324 user[gss_send_token.length] = '\0';
00325 gss_release_name(&gss_status, &gss_client_name);
00326 gss_release_buffer(&gss_status, &gss_send_token);
00327 infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n",user);
00328 free(user);
00329 user=NULL;
00330
00331
00332 socksreq[0] = 1;
00333 socksreq[1] = 2;
00334
00335 gss_enc = 0;
00336
00337 if(gss_ret_flags & GSS_C_CONF_FLAG)
00338 gss_enc = 2;
00339
00340 else if(gss_ret_flags & GSS_C_INTEG_FLAG)
00341 gss_enc = 1;
00342
00343 infof(data, "SOCKS5 server supports GSS-API %s data protection.\n",
00344 (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality"));
00345
00346 gss_enc = 0;
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377 if(data->set.socks5_gssapi_nec) {
00378 us_length = htons((short)1);
00379 memcpy(socksreq+2, &us_length, sizeof(short));
00380 }
00381 else {
00382 gss_send_token.length = 1;
00383 gss_send_token.value = malloc(1);
00384 if(!gss_send_token.value) {
00385 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00386 return CURLE_OUT_OF_MEMORY;
00387 }
00388 memcpy(gss_send_token.value, &gss_enc, 1);
00389
00390 gss_major_status = gss_wrap(&gss_minor_status, gss_context, 0,
00391 GSS_C_QOP_DEFAULT, &gss_send_token,
00392 &gss_conf_state, &gss_w_token);
00393
00394 if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_wrap")) {
00395 gss_release_buffer(&gss_status, &gss_send_token);
00396 gss_release_buffer(&gss_status, &gss_w_token);
00397 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00398 failf(data, "Failed to wrap GSS-API encryption value into token.");
00399 return CURLE_COULDNT_CONNECT;
00400 }
00401 gss_release_buffer(&gss_status, &gss_send_token);
00402
00403 us_length = htons((short)gss_w_token.length);
00404 memcpy(socksreq+2, &us_length, sizeof(short));
00405 }
00406
00407 code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
00408 if(code || (4 != written)) {
00409 failf(data, "Failed to send GSS-API encryption request.");
00410 gss_release_buffer(&gss_status, &gss_w_token);
00411 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00412 return CURLE_COULDNT_CONNECT;
00413 }
00414
00415 if(data->set.socks5_gssapi_nec) {
00416 memcpy(socksreq, &gss_enc, 1);
00417 code = Curl_write_plain(conn, sock, socksreq, 1, &written);
00418 if(code || ( 1 != written)) {
00419 failf(data, "Failed to send GSS-API encryption type.");
00420 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00421 return CURLE_COULDNT_CONNECT;
00422 }
00423 }
00424 else {
00425 code = Curl_write_plain(conn, sock, (char *)gss_w_token.value,
00426 gss_w_token.length, &written);
00427 if(code || ((ssize_t)gss_w_token.length != written)) {
00428 failf(data, "Failed to send GSS-API encryption type.");
00429 gss_release_buffer(&gss_status, &gss_w_token);
00430 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00431 return CURLE_COULDNT_CONNECT;
00432 }
00433 gss_release_buffer(&gss_status, &gss_w_token);
00434 }
00435
00436 result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
00437 if(result || (actualread != 4)) {
00438 failf(data, "Failed to receive GSS-API encryption response.");
00439 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00440 return CURLE_COULDNT_CONNECT;
00441 }
00442
00443
00444 if(socksreq[1] == 255) {
00445 failf(data, "User was rejected by the SOCKS5 server (%d %d).",
00446 socksreq[0], socksreq[1]);
00447 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00448 return CURLE_COULDNT_CONNECT;
00449 }
00450
00451 if(socksreq[1] != 2) {
00452 failf(data, "Invalid GSS-API encryption response type (%d %d).",
00453 socksreq[0], socksreq[1]);
00454 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00455 return CURLE_COULDNT_CONNECT;
00456 }
00457
00458 memcpy(&us_length, socksreq+2, sizeof(short));
00459 us_length = ntohs(us_length);
00460
00461 gss_recv_token.length= us_length;
00462 gss_recv_token.value=malloc(gss_recv_token.length);
00463 if(!gss_recv_token.value) {
00464 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00465 return CURLE_OUT_OF_MEMORY;
00466 }
00467 result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
00468 gss_recv_token.length, &actualread);
00469
00470 if(result || (actualread != us_length)) {
00471 failf(data, "Failed to receive GSS-API encryptrion type.");
00472 gss_release_buffer(&gss_status, &gss_recv_token);
00473 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00474 return CURLE_COULDNT_CONNECT;
00475 }
00476
00477 if(!data->set.socks5_gssapi_nec) {
00478 gss_major_status = gss_unwrap(&gss_minor_status, gss_context,
00479 &gss_recv_token, &gss_w_token,
00480 0, GSS_C_QOP_DEFAULT);
00481
00482 if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_unwrap")) {
00483 gss_release_buffer(&gss_status, &gss_recv_token);
00484 gss_release_buffer(&gss_status, &gss_w_token);
00485 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00486 failf(data, "Failed to unwrap GSS-API encryption value into token.");
00487 return CURLE_COULDNT_CONNECT;
00488 }
00489 gss_release_buffer(&gss_status, &gss_recv_token);
00490
00491 if(gss_w_token.length != 1) {
00492 failf(data, "Invalid GSS-API encryption response length (%d).",
00493 gss_w_token.length);
00494 gss_release_buffer(&gss_status, &gss_w_token);
00495 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00496 return CURLE_COULDNT_CONNECT;
00497 }
00498
00499 memcpy(socksreq, gss_w_token.value, gss_w_token.length);
00500 gss_release_buffer(&gss_status, &gss_w_token);
00501 }
00502 else {
00503 if(gss_recv_token.length != 1) {
00504 failf(data, "Invalid GSS-API encryption response length (%d).",
00505 gss_recv_token.length);
00506 gss_release_buffer(&gss_status, &gss_recv_token);
00507 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00508 return CURLE_COULDNT_CONNECT;
00509 }
00510
00511 memcpy(socksreq, gss_recv_token.value, gss_recv_token.length);
00512 gss_release_buffer(&gss_status, &gss_recv_token);
00513 }
00514
00515 infof(data, "SOCKS5 access with%s protection granted.\n",
00516 (socksreq[0]==0)?"out GSS-API data":
00517 ((socksreq[0]==1)?" GSS-API integrity":" GSS-API confidentiality"));
00518
00519 conn->socks5_gssapi_enctype = socksreq[0];
00520 if(socksreq[0] == 0)
00521 gss_delete_sec_context(&gss_status, &gss_context, NULL);
00522
00523 return CURLE_OK;
00524 }
00525
00526 #endif