static void auth_register(ne_session *sess, int isproxy, const struct auth_class *ahc, const char *id, ne_auth_creds creds, void *userdata) { auth_session *ahs = ne_calloc(sizeof *ahs); ahs->creds = creds; ahs->userdata = userdata; ahs->sess = sess; ahs->spec = ahc; if (strcmp(ne_get_scheme(sess), "https") == 0) { ahs->context = isproxy ? AUTH_CONNECT : AUTH_NOTCONNECT; #ifdef HAVE_GSSAPI { get_gss_name(&ahs->gssname, (isproxy ? sess->proxy.hostname : sess->server.hostname)); ahs->gssctx = GSS_C_NO_CONTEXT; ahs->gssmech = GSS_C_NO_OID; } #endif } else { ahs->context = AUTH_ANY; } /* Register hooks */ ne_hook_create_request(sess, ah_create, ahs); ne_hook_pre_send(sess, ah_pre_send, ahs); ne_hook_post_send(sess, ah_post_send, ahs); ne_hook_destroy_request(sess, ah_destroy, ahs); ne_hook_destroy_session(sess, free_auth, ahs); ne_set_session_private(sess, id, ahs); }
int Curl_input_negotiate(struct connectdata *conn, char *header) { struct negotiatedata *neg_ctx = &conn->data->state.negotiate; OM_uint32 major_status, minor_status, minor_status2; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; int ret; size_t len; bool gss; const char* protocol; while(*header && ISSPACE(*header)) header++; if(checkprefix("GSS-Negotiate", header)) { protocol = "GSS-Negotiate"; gss = TRUE; } else if (checkprefix("Negotiate", header)) { protocol = "Negotiate"; gss = FALSE; } else return -1; if (neg_ctx->context) { if (neg_ctx->gss != gss) { return -1; } } else { neg_ctx->protocol = protocol; neg_ctx->gss = gss; } if (neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) { /* We finished succesfully our part of authentication, but server * rejected it (since we're again here). Exit with an error since we * can't invent anything better */ Curl_cleanup_negotiate(conn->data); return -1; } if (neg_ctx->server_name == NULL && (ret = get_gss_name(conn, &neg_ctx->server_name))) return ret; header += strlen(neg_ctx->protocol); while(*header && ISSPACE(*header)) header++; len = strlen(header); if (len > 0) { int rawlen = Curl_base64_decode(header, (unsigned char **)&input_token.value); if (rawlen < 0) return -1; input_token.length = rawlen; #ifdef HAVE_SPNEGO /* Handle SPNEGO */ if (checkprefix("Negotiate", header)) { ASN1_OBJECT * object = NULL; int rc = 1; unsigned char * spnegoToken = NULL; size_t spnegoTokenLength = 0; unsigned char * mechToken = NULL; size_t mechTokenLength = 0; spnegoToken = malloc(input_token.length); if (input_token.value == NULL) return ENOMEM; spnegoTokenLength = input_token.length; object = OBJ_txt2obj ("1.2.840.113554.1.2.2", 1); if (!parseSpnegoTargetToken(spnegoToken, spnegoTokenLength, NULL, NULL, &mechToken, &mechTokenLength, NULL, NULL)) { free(spnegoToken); spnegoToken = NULL; infof(conn->data, "Parse SPNEGO Target Token failed\n"); } else { free(input_token.value); input_token.value = NULL; input_token.value = malloc(mechTokenLength); memcpy(input_token.value, mechToken,mechTokenLength); input_token.length = mechTokenLength; free(mechToken); mechToken = NULL; infof(conn->data, "Parse SPNEGO Target Token succeeded\n"); } } #endif } major_status = gss_init_sec_context(&minor_status, GSS_C_NO_CREDENTIAL, &neg_ctx->context, neg_ctx->server_name, GSS_C_NO_OID, GSS_C_DELEG_FLAG, 0, GSS_C_NO_CHANNEL_BINDINGS, &input_token, NULL, &output_token, NULL, NULL); if (input_token.length > 0) gss_release_buffer(&minor_status2, &input_token); neg_ctx->status = major_status; if (GSS_ERROR(major_status)) { /* Curl_cleanup_negotiate(conn->data) ??? */ log_gss_error(conn, minor_status, (char *)"gss_init_sec_context() failed: "); return -1; } if (output_token.length == 0) { return -1; } neg_ctx->output_token = output_token; /* conn->bits.close = FALSE; */ return 0; }
/* returning zero (0) means success, everything else is treated as "failure" with no care exactly what the failure was */ int Curl_input_negotiate(struct connectdata *conn, bool proxy, const char *header) { struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: &conn->data->state.negotiate; BYTE *input_token = 0; SecBufferDesc out_buff_desc; SecBuffer out_sec_buff; SecBufferDesc in_buff_desc; SecBuffer in_sec_buff; unsigned long context_attributes; TimeStamp lifetime; TCHAR *sname; int ret; size_t len = 0, input_token_len = 0; bool gss = FALSE; const char* protocol; CURLcode error; while(*header && ISSPACE(*header)) header++; if(checkprefix("GSS-Negotiate", header)) { protocol = "GSS-Negotiate"; gss = TRUE; } else if(checkprefix("Negotiate", header)) { protocol = "Negotiate"; gss = FALSE; } else return -1; if(neg_ctx->context) { if(neg_ctx->gss != gss) { return -1; } } else { neg_ctx->protocol = protocol; neg_ctx->gss = gss; } if(neg_ctx->context && neg_ctx->status == SEC_E_OK) { /* We finished successfully our part of authentication, but server * rejected it (since we're again here). Exit with an error since we * can't invent anything better */ Curl_cleanup_negotiate(conn->data); return -1; } if(0 == strlen(neg_ctx->server_name)) { ret = get_gss_name(conn, proxy, neg_ctx); if(ret) return ret; } if(!neg_ctx->output_token) { PSecPkgInfo SecurityPackage; ret = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT("Negotiate"), &SecurityPackage); if(ret != SEC_E_OK) return -1; /* Allocate input and output buffers according to the max token size as indicated by the security package */ neg_ctx->max_token_length = SecurityPackage->cbMaxToken; neg_ctx->output_token = malloc(neg_ctx->max_token_length); s_pSecFn->FreeContextBuffer(SecurityPackage); } /* Obtain the input token, if any */ header += strlen(neg_ctx->protocol); while(*header && ISSPACE(*header)) header++; len = strlen(header); if(!len) { /* first call in a new negotation, we have to acquire credentials, and allocate memory for the context */ neg_ctx->credentials = malloc(sizeof(CredHandle)); neg_ctx->context = malloc(sizeof(CtxtHandle)); if(!neg_ctx->credentials || !neg_ctx->context) return -1; neg_ctx->status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *) TEXT("Negotiate"), SECPKG_CRED_OUTBOUND, NULL, NULL, NULL, NULL, neg_ctx->credentials, &lifetime); if(neg_ctx->status != SEC_E_OK) return -1; } else { input_token = malloc(neg_ctx->max_token_length); if(!input_token) return -1; error = Curl_base64_decode(header, (unsigned char **)&input_token, &input_token_len); if(error || input_token_len == 0) return -1; } /* prepare the output buffers, and input buffers if present */ out_buff_desc.ulVersion = 0; out_buff_desc.cBuffers = 1; out_buff_desc.pBuffers = &out_sec_buff; out_sec_buff.cbBuffer = curlx_uztoul(neg_ctx->max_token_length); out_sec_buff.BufferType = SECBUFFER_TOKEN; out_sec_buff.pvBuffer = neg_ctx->output_token; if(input_token) { in_buff_desc.ulVersion = 0; in_buff_desc.cBuffers = 1; in_buff_desc.pBuffers = &in_sec_buff; in_sec_buff.cbBuffer = curlx_uztoul(input_token_len); in_sec_buff.BufferType = SECBUFFER_TOKEN; in_sec_buff.pvBuffer = input_token; } sname = Curl_convert_UTF8_to_tchar(neg_ctx->server_name); if(!sname) return CURLE_OUT_OF_MEMORY; neg_ctx->status = s_pSecFn->InitializeSecurityContext( neg_ctx->credentials, input_token ? neg_ctx->context : 0, sname, ISC_REQ_CONFIDENTIALITY, 0, SECURITY_NATIVE_DREP, input_token ? &in_buff_desc : 0, 0, neg_ctx->context, &out_buff_desc, &context_attributes, &lifetime); Curl_unicodefree(sname); if(GSS_ERROR(neg_ctx->status)) return -1; if(neg_ctx->status == SEC_I_COMPLETE_NEEDED || neg_ctx->status == SEC_I_COMPLETE_AND_CONTINUE) { neg_ctx->status = s_pSecFn->CompleteAuthToken(neg_ctx->context, &out_buff_desc); if(GSS_ERROR(neg_ctx->status)) return -1; } neg_ctx->output_token_length = out_sec_buff.cbBuffer; return 0; }
/* returning zero (0) means success, everything else is treated as "failure" with no care exactly what the failure was */ int Curl_input_negotiate(struct connectdata *conn, bool proxy, const char *header) { struct SessionHandle *data = conn->data; struct negotiatedata *neg_ctx = proxy?&data->state.proxyneg: &data->state.negotiate; OM_uint32 major_status, minor_status, discard_st, min_stat; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; int ret; size_t len; size_t rawlen = 0; bool gss; const char* protocol; CURLcode error; while(*header && ISSPACE(*header)) header++; if(checkprefix("GSS-Negotiate", header)) { protocol = "GSS-Negotiate"; gss = TRUE; } else if(checkprefix("Negotiate", header)) { protocol = "Negotiate"; gss = FALSE; } else return -1; if(neg_ctx->context) { if(neg_ctx->gss != gss) { return -1; } } else { neg_ctx->protocol = protocol; neg_ctx->gss = gss; } if(neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) { /* We finished successfully our part of authentication, but server * rejected it (since we're again here). Exit with an error since we * can't invent anything better */ Curl_cleanup_negotiate(data); return -1; } if(neg_ctx->server_name == NULL && (ret = get_gss_name(conn, proxy, &neg_ctx->server_name))) return ret; header += strlen(neg_ctx->protocol); while(*header && ISSPACE(*header)) header++; len = strlen(header); if(len > 0) { error = Curl_base64_decode(header, (unsigned char **)&input_token.value, &rawlen); if(error || rawlen == 0) return -1; input_token.length = rawlen; DEBUGASSERT(input_token.value != NULL); #ifdef HAVE_SPNEGO /* Handle SPNEGO */ if(checkprefix("Negotiate", header)) { unsigned char *spnegoToken = NULL; size_t spnegoTokenLength = 0; gss_buffer_desc mechToken = GSS_C_EMPTY_BUFFER; spnegoToken = malloc(input_token.length); if(spnegoToken == NULL) { Curl_safefree(input_token.value); return CURLE_OUT_OF_MEMORY; } memcpy(spnegoToken, input_token.value, input_token.length); spnegoTokenLength = input_token.length; if(!parseSpnegoTargetToken(spnegoToken, spnegoTokenLength, NULL, NULL, (unsigned char**)&mechToken.value, &mechToken.length, NULL, NULL)) { Curl_safefree(spnegoToken); infof(data, "Parse SPNEGO Target Token failed\n"); } else if(!mechToken.value || !mechToken.length) { Curl_safefree(spnegoToken); if(mechToken.value) gss_release_buffer(&discard_st, &mechToken); infof(data, "Parse SPNEGO Target Token succeeded (NULL token)\n"); } else { Curl_safefree(spnegoToken); Curl_safefree(input_token.value); input_token.value = malloc(mechToken.length); if(input_token.value == NULL) { gss_release_buffer(&discard_st, &mechToken); return CURLE_OUT_OF_MEMORY; } memcpy(input_token.value, mechToken.value, mechToken.length); input_token.length = mechToken.length; gss_release_buffer(&discard_st, &mechToken); infof(data, "Parse SPNEGO Target Token succeeded\n"); } } #endif } major_status = Curl_gss_init_sec_context(conn, &minor_status, &neg_ctx->context, neg_ctx->server_name, GSS_C_NO_CHANNEL_BINDINGS, &input_token, &output_token, NULL); gss_release_cred(&min_stat, &conn->data->curl_gss_creds); Curl_safefree(input_token.value); /*To remove the memory leak issue*/ if(neg_ctx->server_name != GSS_C_NO_NAME) gss_release_name(&min_stat, &neg_ctx->server_name); neg_ctx->status = major_status; if(GSS_ERROR(major_status)) { if(output_token.value) gss_release_buffer(&discard_st, &output_token); log_gss_error(conn, minor_status, "KRB5_ERROR: gss_init_sec_context() failed: "); printf("\n KRB5_ERROR: gss_init_sec_context() failed error code : %d", minor_status); return -1; } if(!output_token.value || !output_token.length) { if(output_token.value) gss_release_buffer(&discard_st, &output_token); return -1; } neg_ctx->output_token = output_token; return 0; }