CURLcode Curl_input_ntlm(struct connectdata *conn, bool proxy, /* if proxy or not */ const char *header) /* rest of the www-authenticate: header */ { /* point to the correct struct with this */ struct ntlmdata *ntlm; CURLcode result = CURLE_OK; #ifdef USE_NSS result = Curl_nss_force_init(conn->data); if(result) return result; #endif ntlm = proxy ? &conn->proxyntlm : &conn->ntlm; /* skip initial whitespaces */ while(*header && ISSPACE(*header)) header++; if(checkprefix("NTLM", header)) { header += strlen("NTLM"); while(*header && ISSPACE(*header)) header++; if(*header) { result = Curl_ntlm_decode_type2_message(conn->data, header, ntlm); if(CURLE_OK != result) return result; ntlm->state = NTLMSTATE_TYPE2; /* We got a type-2 message */ } else { if(ntlm->state == NTLMSTATE_TYPE3) { infof(conn->data, "NTLM handshake rejected\n"); Curl_http_ntlm_cleanup(conn); ntlm->state = NTLMSTATE_NONE; return CURLE_REMOTE_ACCESS_DENIED; } else if(ntlm->state >= NTLMSTATE_TYPE1) { infof(conn->data, "NTLM handshake failure (internal error)\n"); return CURLE_REMOTE_ACCESS_DENIED; } ntlm->state = NTLMSTATE_TYPE1; /* We should send away a type-1 */ } } return result; }
/* * Curl_sasl_decode_ntlm_type2_message() * * This is used to decode an already encoded NTLM type-2 message. * * Parameters: * * data [in] - Pointer to session handle. * type2msg [in] - Pointer to the base64 encoded type-2 message. * ntlm [in/out] - The ntlm data struct being used and modified. * * Returns CURLE_OK on success. */ CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data, const char *type2msg, struct ntlmdata *ntlm) { #ifdef USE_NSS CURLcode result; /* make sure the crypto backend is initialized */ result = Curl_nss_force_init(data); if(result) return result; #endif return Curl_ntlm_decode_type2_message(data, type2msg, ntlm); }
/* * This is for creating ntlm header output */ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) { char *base64 = NULL; size_t len = 0; CURLcode error; /* point to the address of the pointer that holds the string to send to the server, which is for a plain host or for a HTTP proxy */ char **allocuserpwd; /* point to the name and password for this */ const char *userp; const char *passwdp; /* point to the correct struct with this */ struct ntlmdata *ntlm; struct auth *authp; DEBUGASSERT(conn); DEBUGASSERT(conn->data); #ifdef USE_NSS if(CURLE_OK != Curl_nss_force_init(conn->data)) return CURLE_OUT_OF_MEMORY; #endif if(proxy) { allocuserpwd = &conn->allocptr.proxyuserpwd; userp = conn->proxyuser; passwdp = conn->proxypasswd; ntlm = &conn->proxyntlm; authp = &conn->data->state.authproxy; } else { allocuserpwd = &conn->allocptr.userpwd; userp = conn->user; passwdp = conn->passwd; ntlm = &conn->ntlm; authp = &conn->data->state.authhost; } authp->done = FALSE; /* not set means empty */ if(!userp) userp = ""; if(!passwdp) passwdp = ""; #ifdef USE_WINDOWS_SSPI if(s_hSecDll == NULL) { /* not thread safe and leaks - use curl_global_init() to avoid */ CURLcode err = Curl_sspi_global_init(); if(s_hSecDll == NULL) return err; } #endif switch(ntlm->state) { case NTLMSTATE_TYPE1: default: /* for the weird cases we (re)start here */ /* Create a type-1 message */ error = Curl_ntlm_create_type1_message(userp, passwdp, ntlm, &base64, &len); if(error) return error; if(base64) { Curl_safefree(*allocuserpwd); *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", proxy ? "Proxy-" : "", base64); free(base64); if(!*allocuserpwd) return CURLE_OUT_OF_MEMORY; DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); } break; case NTLMSTATE_TYPE2: /* We already received the type-2 message, create a type-3 message */ error = Curl_ntlm_create_type3_message(conn->data, userp, passwdp, ntlm, &base64, &len); if(error) return error; if(base64) { Curl_safefree(*allocuserpwd); *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", proxy ? "Proxy-" : "", base64); free(base64); if(!*allocuserpwd) return CURLE_OUT_OF_MEMORY; DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); ntlm->state = NTLMSTATE_TYPE3; /* we send a type-3 */ authp->done = TRUE; } break; case NTLMSTATE_TYPE3: /* connection is already authenticated, * don't send a header in future requests */ Curl_safefree(*allocuserpwd); authp->done = TRUE; break; } return CURLE_OK; }
/* * Curl_auth_decode_ntlm_type2_message() * * This is used to decode an already encoded NTLM type-2 message. The message * is first decoded from a base64 string into a raw NTLM message and checked * for validity before the appropriate data for creating a type-3 message is * written to the given NTLM data structure. * * Parameters: * * data [in] - The session handle. * type2msg [in] - The base64 encoded type-2 message. * ntlm [in/out] - The NTLM data struct being used and modified. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, const char *type2msg, struct ntlmdata *ntlm) { static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; /* NTLM type-2 message structure: Index Description Content 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" (0x4e544c4d53535000) 8 NTLM Message Type long (0x02000000) 12 Target Name security buffer 20 Flags long 24 Challenge 8 bytes (32) Context 8 bytes (two consecutive longs) (*) (40) Target Information security buffer (*) (48) OS Version Structure 8 bytes (*) 32 (48) (56) Start of data block (*) (*) -> Optional */ CURLcode result = CURLE_OK; unsigned char *type2 = NULL; size_t type2_len = 0; #if defined(NTLM_NEEDS_NSS_INIT) /* Make sure the crypto backend is initialized */ result = Curl_nss_force_init(data); if(result) return result; #elif defined(CURL_DISABLE_VERBOSE_STRINGS) (void)data; #endif /* Decode the base-64 encoded type-2 message */ if(strlen(type2msg) && *type2msg != '=') { result = Curl_base64_decode(type2msg, &type2, &type2_len); if(result) return result; } /* Ensure we have a valid type-2 message */ if(!type2) { infof(data, "NTLM handshake failure (empty type-2 message)\n"); return CURLE_BAD_CONTENT_ENCODING; } ntlm->flags = 0; if((type2_len < 32) || (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) || (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) { /* This was not a good enough type-2 message */ free(type2); infof(data, "NTLM handshake failure (bad type-2 message)\n"); return CURLE_BAD_CONTENT_ENCODING; } ntlm->flags = Curl_read32_le(&type2[20]); memcpy(ntlm->nonce, &type2[24], 8); if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) { result = ntlm_decode_type2_target(data, type2, type2_len, ntlm); if(result) { free(type2); infof(data, "NTLM handshake failure (bad type-2 message)\n"); return result; } } DEBUG_OUT({ fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); ntlm_print_flags(stderr, ntlm->flags); fprintf(stderr, "\n nonce="); ntlm_print_hex(stderr, (char *)ntlm->nonce, 8); fprintf(stderr, "\n****\n"); fprintf(stderr, "**** Header %s\n ", header); });
CURLntlm Curl_input_ntlm(struct connectdata *conn, bool proxy, /* if proxy or not */ const char *header) /* rest of the www-authenticate: header */ { /* point to the correct struct with this */ struct ntlmdata *ntlm; #ifndef USE_WINDOWS_SSPI static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; #endif #ifdef USE_NSS if(CURLE_OK != Curl_nss_force_init(conn->data)) return CURLNTLM_BAD; #endif ntlm = proxy?&conn->proxyntlm:&conn->ntlm; /* skip initial whitespaces */ while(*header && ISSPACE(*header)) header++; if(checkprefix("NTLM", header)) { header += strlen("NTLM"); while(*header && ISSPACE(*header)) header++; if(*header) { /* We got a type-2 message here: Index Description Content 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" (0x4e544c4d53535000) 8 NTLM Message Type long (0x02000000) 12 Target Name security buffer(*) 20 Flags long 24 Challenge 8 bytes (32) Context (optional) 8 bytes (two consecutive longs) (40) Target Information (optional) security buffer(*) 32 (48) start of data block */ size_t size; unsigned char *buffer; size = Curl_base64_decode(header, &buffer); if(!buffer) return CURLNTLM_BAD; ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */ #ifdef USE_WINDOWS_SSPI ntlm->type_2 = malloc(size+1); if(ntlm->type_2 == NULL) { free(buffer); return CURLE_OUT_OF_MEMORY; } ntlm->n_type_2 = size; memcpy(ntlm->type_2, buffer, size); #else ntlm->flags = 0; if((size < 32) || (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) || (memcmp(buffer+8, type2_marker, sizeof(type2_marker)) != 0)) { /* This was not a good enough type-2 message */ free(buffer); return CURLNTLM_BAD; } ntlm->flags = readint_le(&buffer[20]); memcpy(ntlm->nonce, &buffer[24], 8); DEBUG_OUT({ fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); print_flags(stderr, ntlm->flags); fprintf(stderr, "\n nonce="); print_hex(stderr, (char *)ntlm->nonce, 8); fprintf(stderr, "\n****\n"); fprintf(stderr, "**** Header %s\n ", header); }); #endif free(buffer); }
/* * This is for creating ntlm header output */ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) { char *base64 = NULL; size_t len = 0; CURLcode result; /* point to the address of the pointer that holds the string to send to the server, which is for a plain host or for a HTTP proxy */ char **allocuserpwd; /* point to the username, password, service and host */ const char *userp; const char *passwdp; const char *service = NULL; const char *hostname = NULL; /* point to the correct struct with this */ struct ntlmdata *ntlm; struct auth *authp; DEBUGASSERT(conn); DEBUGASSERT(conn->data); #if defined(NTLM_NEEDS_NSS_INIT) if(CURLE_OK != Curl_nss_force_init(conn->data)) return CURLE_OUT_OF_MEMORY; #endif if(proxy) { allocuserpwd = &conn->allocptr.proxyuserpwd; userp = conn->http_proxy.user; passwdp = conn->http_proxy.passwd; service = conn->data->set.str[STRING_PROXY_SERVICE_NAME] ? conn->data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP"; hostname = conn->http_proxy.host.name; ntlm = &conn->proxyntlm; authp = &conn->data->state.authproxy; } else { allocuserpwd = &conn->allocptr.userpwd; userp = conn->user; passwdp = conn->passwd; service = conn->data->set.str[STRING_SERVICE_NAME] ? conn->data->set.str[STRING_SERVICE_NAME] : "HTTP"; hostname = conn->host.name; ntlm = &conn->ntlm; authp = &conn->data->state.authhost; } authp->done = FALSE; /* not set means empty */ if(!userp) userp = ""; if(!passwdp) passwdp = ""; #ifdef USE_WINDOWS_SSPI if(s_hSecDll == NULL) { /* not thread safe and leaks - use curl_global_init() to avoid */ CURLcode err = Curl_sspi_global_init(); if(s_hSecDll == NULL) return err; } #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS ntlm->sslContext = conn->sslContext; #endif #endif switch(ntlm->state) { case NTLMSTATE_TYPE1: default: /* for the weird cases we (re)start here */ /* Create a type-1 message */ result = Curl_auth_create_ntlm_type1_message(conn->data, userp, passwdp, service, hostname, ntlm, &base64, &len); if(result) return result; if(base64) { free(*allocuserpwd); *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", proxy ? "Proxy-" : "", base64); free(base64); if(!*allocuserpwd) return CURLE_OUT_OF_MEMORY; DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); } break; case NTLMSTATE_TYPE2: /* We already received the type-2 message, create a type-3 message */ result = Curl_auth_create_ntlm_type3_message(conn->data, userp, passwdp, ntlm, &base64, &len); if(result) return result; if(base64) { free(*allocuserpwd); *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", proxy ? "Proxy-" : "", base64); free(base64); if(!*allocuserpwd) return CURLE_OUT_OF_MEMORY; DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); ntlm->state = NTLMSTATE_TYPE3; /* we send a type-3 */ authp->done = TRUE; } break; case NTLMSTATE_TYPE3: /* connection is already authenticated, * don't send a header in future requests */ ntlm->state = NTLMSTATE_LAST; /* FALLTHROUGH */ case NTLMSTATE_LAST: Curl_safefree(*allocuserpwd); authp->done = TRUE; break; } return CURLE_OK; }
int Curl_nss_seed(struct SessionHandle *data) { /* make sure that NSS is initialized */ return !!Curl_nss_force_init(data); }