00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "curl_setup.h"
00027
00028 #if defined(HAVE_GSSAPI) && defined(USE_KERBEROS5)
00029
00030 #include <curl/curl.h>
00031
00032 #include "vauth/vauth.h"
00033 #include "curl_sasl.h"
00034 #include "urldata.h"
00035 #include "curl_base64.h"
00036 #include "curl_gssapi.h"
00037 #include "sendf.h"
00038 #include "curl_printf.h"
00039
00040
00041 #include "curl_memory.h"
00042 #include "memdebug.h"
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 bool Curl_auth_is_gssapi_supported(void)
00054 {
00055 return TRUE;
00056 }
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082 CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
00083 const char *userp,
00084 const char *passwdp,
00085 const char *service,
00086 const char *host,
00087 const bool mutual_auth,
00088 const char *chlg64,
00089 struct kerberos5data *krb5,
00090 char **outptr, size_t *outlen)
00091 {
00092 CURLcode result = CURLE_OK;
00093 size_t chlglen = 0;
00094 unsigned char *chlg = NULL;
00095 OM_uint32 major_status;
00096 OM_uint32 minor_status;
00097 OM_uint32 unused_status;
00098 gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
00099 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
00100 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
00101
00102 (void) userp;
00103 (void) passwdp;
00104
00105 if(!krb5->spn) {
00106
00107 char *spn = Curl_auth_build_spn(service, NULL, host);
00108 if(!spn)
00109 return CURLE_OUT_OF_MEMORY;
00110
00111
00112 spn_token.value = spn;
00113 spn_token.length = strlen(spn);
00114
00115
00116 major_status = gss_import_name(&minor_status, &spn_token,
00117 GSS_C_NT_HOSTBASED_SERVICE, &krb5->spn);
00118 if(GSS_ERROR(major_status)) {
00119 Curl_gss_log_error(data, "gss_import_name() failed: ",
00120 major_status, minor_status);
00121
00122 free(spn);
00123
00124 return CURLE_OUT_OF_MEMORY;
00125 }
00126
00127 free(spn);
00128 }
00129
00130 if(chlg64 && *chlg64) {
00131
00132 if(*chlg64 != '=') {
00133 result = Curl_base64_decode(chlg64, &chlg, &chlglen);
00134 if(result)
00135 return result;
00136 }
00137
00138
00139 if(!chlg) {
00140 infof(data, "GSSAPI handshake failure (empty challenge message)\n");
00141
00142 return CURLE_BAD_CONTENT_ENCODING;
00143 }
00144
00145
00146 input_token.value = chlg;
00147 input_token.length = chlglen;
00148 }
00149
00150 major_status = Curl_gss_init_sec_context(data,
00151 &minor_status,
00152 &krb5->context,
00153 krb5->spn,
00154 &Curl_krb5_mech_oid,
00155 GSS_C_NO_CHANNEL_BINDINGS,
00156 &input_token,
00157 &output_token,
00158 mutual_auth,
00159 NULL);
00160
00161
00162 free(input_token.value);
00163
00164 if(GSS_ERROR(major_status)) {
00165 if(output_token.value)
00166 gss_release_buffer(&unused_status, &output_token);
00167
00168 Curl_gss_log_error(data, "gss_init_sec_context() failed: ",
00169 major_status, minor_status);
00170
00171 return CURLE_RECV_ERROR;
00172 }
00173
00174 if(output_token.value && output_token.length) {
00175
00176 result = Curl_base64_encode(data, (char *) output_token.value,
00177 output_token.length, outptr, outlen);
00178
00179 gss_release_buffer(&unused_status, &output_token);
00180 }
00181 else if(mutual_auth) {
00182 *outptr = strdup("");
00183 if(!*outptr)
00184 result = CURLE_OUT_OF_MEMORY;
00185 }
00186
00187 return result;
00188 }
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207 CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
00208 const char *chlg64,
00209 struct kerberos5data *krb5,
00210 char **outptr,
00211 size_t *outlen)
00212 {
00213 CURLcode result = CURLE_OK;
00214 size_t chlglen = 0;
00215 size_t messagelen = 0;
00216 unsigned char *chlg = NULL;
00217 unsigned char *message = NULL;
00218 OM_uint32 major_status;
00219 OM_uint32 minor_status;
00220 OM_uint32 unused_status;
00221 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
00222 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
00223 unsigned int indata = 0;
00224 unsigned int outdata = 0;
00225 gss_qop_t qop = GSS_C_QOP_DEFAULT;
00226 unsigned int sec_layer = 0;
00227 unsigned int max_size = 0;
00228 gss_name_t username = GSS_C_NO_NAME;
00229 gss_buffer_desc username_token;
00230
00231
00232 if(strlen(chlg64) && *chlg64 != '=') {
00233 result = Curl_base64_decode(chlg64, &chlg, &chlglen);
00234 if(result)
00235 return result;
00236 }
00237
00238
00239 if(!chlg) {
00240 infof(data, "GSSAPI handshake failure (empty security message)\n");
00241
00242 return CURLE_BAD_CONTENT_ENCODING;
00243 }
00244
00245
00246 major_status = gss_inquire_context(&minor_status, krb5->context,
00247 &username, NULL, NULL, NULL, NULL,
00248 NULL, NULL);
00249 if(GSS_ERROR(major_status)) {
00250 Curl_gss_log_error(data, "gss_inquire_context() failed: ",
00251 major_status, minor_status);
00252
00253 free(chlg);
00254
00255 return CURLE_OUT_OF_MEMORY;
00256 }
00257
00258
00259 major_status = gss_display_name(&minor_status, username,
00260 &username_token, NULL);
00261 if(GSS_ERROR(major_status)) {
00262 Curl_gss_log_error(data, "gss_display_name() failed: ",
00263 major_status, minor_status);
00264
00265 free(chlg);
00266
00267 return CURLE_OUT_OF_MEMORY;
00268 }
00269
00270
00271 input_token.value = chlg;
00272 input_token.length = chlglen;
00273
00274
00275 major_status = gss_unwrap(&minor_status, krb5->context, &input_token,
00276 &output_token, NULL, &qop);
00277 if(GSS_ERROR(major_status)) {
00278 Curl_gss_log_error(data, "gss_unwrap() failed: ",
00279 major_status, minor_status);
00280
00281 gss_release_buffer(&unused_status, &username_token);
00282 free(chlg);
00283
00284 return CURLE_BAD_CONTENT_ENCODING;
00285 }
00286
00287
00288 if(output_token.length != 4) {
00289 infof(data, "GSSAPI handshake failure (invalid security data)\n");
00290
00291 gss_release_buffer(&unused_status, &username_token);
00292 free(chlg);
00293
00294 return CURLE_BAD_CONTENT_ENCODING;
00295 }
00296
00297
00298 memcpy(&indata, output_token.value, 4);
00299 gss_release_buffer(&unused_status, &output_token);
00300 free(chlg);
00301
00302
00303 sec_layer = indata & 0x000000FF;
00304 if(!(sec_layer & GSSAUTH_P_NONE)) {
00305 infof(data, "GSSAPI handshake failure (invalid security layer)\n");
00306
00307 gss_release_buffer(&unused_status, &username_token);
00308
00309 return CURLE_BAD_CONTENT_ENCODING;
00310 }
00311
00312
00313 max_size = ntohl(indata & 0xFFFFFF00);
00314 if(max_size > 0) {
00315
00316
00317
00318 max_size = 0;
00319 }
00320
00321
00322 messagelen = sizeof(outdata) + username_token.length + 1;
00323 message = malloc(messagelen);
00324 if(!message) {
00325 gss_release_buffer(&unused_status, &username_token);
00326
00327 return CURLE_OUT_OF_MEMORY;
00328 }
00329
00330
00331
00332
00333
00334
00335 outdata = htonl(max_size) | sec_layer;
00336 memcpy(message, &outdata, sizeof(outdata));
00337 memcpy(message + sizeof(outdata), username_token.value,
00338 username_token.length);
00339 message[messagelen - 1] = '\0';
00340
00341
00342 gss_release_buffer(&unused_status, &username_token);
00343
00344
00345 input_token.value = message;
00346 input_token.length = messagelen;
00347
00348
00349 major_status = gss_wrap(&minor_status, krb5->context, 0,
00350 GSS_C_QOP_DEFAULT, &input_token, NULL,
00351 &output_token);
00352 if(GSS_ERROR(major_status)) {
00353 Curl_gss_log_error(data, "gss_wrap() failed: ",
00354 major_status, minor_status);
00355
00356 free(message);
00357
00358 return CURLE_OUT_OF_MEMORY;
00359 }
00360
00361
00362 result = Curl_base64_encode(data, (char *) output_token.value,
00363 output_token.length, outptr, outlen);
00364
00365
00366 gss_release_buffer(&unused_status, &output_token);
00367
00368
00369 free(message);
00370
00371 return result;
00372 }
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384 void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5)
00385 {
00386 OM_uint32 minor_status;
00387
00388
00389 if(krb5->context != GSS_C_NO_CONTEXT) {
00390 gss_delete_sec_context(&minor_status, &krb5->context, GSS_C_NO_BUFFER);
00391 krb5->context = GSS_C_NO_CONTEXT;
00392 }
00393
00394
00395 if(krb5->spn != GSS_C_NO_NAME) {
00396 gss_release_name(&minor_status, &krb5->spn);
00397 krb5->spn = GSS_C_NO_NAME;
00398 }
00399 }
00400
00401 #endif