http NTLM: more adjustments in preparation of code refactoring

Use preprocessor symbol NTLM_BUFSIZE to define private NTLM buffer fixed size.

Use a SessionHandle 'data' pointer variable to ease refactoring.

Update NTLM type-* message structure descriptions.

Fix some more spacing and typos (Steve Holme).
This commit is contained in:
Yang Tse 2011-08-12 19:51:50 +02:00
parent 784971743d
commit 3293150da2
2 changed files with 91 additions and 72 deletions

View File

@ -237,10 +237,12 @@ static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
#endif #endif
#ifndef USE_WINDOWS_SSPI #ifndef USE_WINDOWS_SSPI
/* this function converts from the little endian format used in the incoming /*
package to whatever endian format we're using natively */ * This function converts from the little endian format used in the
static unsigned int readint_le(unsigned char *buf) /* must point to a * incoming package to whatever endian format we're using natively.
4 bytes buffer*/ * Argument is a pointer to a 4 byte buffer.
*/
static unsigned int readint_le(unsigned char *buf)
{ {
return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) | return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24); ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
@ -258,7 +260,7 @@ static unsigned int readint_le(unsigned char *buf) /* must point to a
*/ */
CURLntlm Curl_input_ntlm(struct connectdata *conn, CURLntlm Curl_input_ntlm(struct connectdata *conn,
bool proxy, /* if proxy or not */ bool proxy, /* if proxy or not */
const char *header) /* rest of the www-authenticate: const char *header) /* rest of the www-authenticate:
header */ header */
{ {
@ -286,18 +288,21 @@ CURLntlm Curl_input_ntlm(struct connectdata *conn,
header++; header++;
if(*header) { if(*header) {
/* We got a type-2 message here: /* We got a type-2 message */
/* NTLM type-2 message structure:
Index Description Content Index Description Content
0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
(0x4e544c4d53535000) (0x4e544c4d53535000)
8 NTLM Message Type long (0x02000000) 8 NTLM Message Type long (0x02000000)
12 Target Name security buffer(*) 12 Target Name security buffer
20 Flags long 20 Flags long
24 Challenge 8 bytes 24 Challenge 8 bytes
(32) Context (optional) 8 bytes (two consecutive longs) (32) Context (optional) 8 bytes (two consecutive longs) (*)
(40) Target Information (optional) security buffer(*) (40) Target Information security buffer (*)
32 (48) start of data block (48) OS Version Structure 8 bytes (*)
32 (48) (56) Start of data block (*)
(*) -> Optional
*/ */
size_t size; size_t size;
unsigned char *buffer; unsigned char *buffer;
@ -487,7 +492,7 @@ static void lm_resp(const unsigned char *keys,
DESKEY(ks), DES_ENCRYPT); DESKEY(ks), DES_ENCRYPT);
setup_des_key(keys + 7, DESKEY(ks)); setup_des_key(keys + 7, DESKEY(ks));
DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8), DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 8),
DESKEY(ks), DES_ENCRYPT); DESKEY(ks), DES_ENCRYPT);
setup_des_key(keys + 14, DESKEY(ks)); setup_des_key(keys + 14, DESKEY(ks));
@ -511,8 +516,8 @@ static void lm_resp(const unsigned char *keys,
gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8); gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8);
gcry_cipher_close(des); gcry_cipher_close(des);
#elif defined(USE_NSS) #elif defined(USE_NSS)
encrypt_des(plaintext, results, keys); encrypt_des(plaintext, results, keys);
encrypt_des(plaintext, results + 8, keys + 7); encrypt_des(plaintext, results + 8, keys + 7);
encrypt_des(plaintext, results + 16, keys + 14); encrypt_des(plaintext, results + 16, keys + 14);
#endif #endif
} }
@ -568,7 +573,7 @@ static void mk_lm_hash(struct SessionHandle *data,
gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8); gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8);
gcry_cipher_close(des); gcry_cipher_close(des);
#elif defined(USE_NSS) #elif defined(USE_NSS)
encrypt_des(magic, lmbuffer, pw); encrypt_des(magic, lmbuffer, pw);
encrypt_des(magic, lmbuffer + 8, pw + 7); encrypt_des(magic, lmbuffer + 8, pw + 7);
#endif #endif
@ -889,8 +894,10 @@ done:
return CURLE_REMOTE_ACCESS_DENIED; return CURLE_REMOTE_ACCESS_DENIED;
} }
/*this is for creating ntlm header output by delegating challenge/response /*
*to a Samba's daemon helper ntlm_auth */ * This is for creating ntlm header output by delegating challenge/response
* to a Samba's daemon helper ntlm_auth
*/
CURLcode Curl_output_ntlm_sso(struct connectdata *conn, CURLcode Curl_output_ntlm_sso(struct connectdata *conn,
bool proxy) bool proxy)
{ {
@ -952,7 +959,7 @@ CURLcode Curl_output_ntlm_sso(struct connectdata *conn,
Curl_safefree(*allocuserpwd); Curl_safefree(*allocuserpwd);
*allocuserpwd = aprintf("%sAuthorization: %s\r\n", *allocuserpwd = aprintf("%sAuthorization: %s\r\n",
proxy?"Proxy-":"", proxy ? "Proxy-" : "",
conn->response_header); conn->response_header);
DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
Curl_safefree(conn->response_header); Curl_safefree(conn->response_header);
@ -972,7 +979,7 @@ CURLcode Curl_output_ntlm_sso(struct connectdata *conn,
Curl_safefree(*allocuserpwd); Curl_safefree(*allocuserpwd);
*allocuserpwd = aprintf("%sAuthorization: %s\r\n", *allocuserpwd = aprintf("%sAuthorization: %s\r\n",
proxy?"Proxy-":"", proxy ? "Proxy-" : "",
conn->response_header); conn->response_header);
DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */ ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
@ -994,14 +1001,15 @@ CURLcode Curl_output_ntlm_sso(struct connectdata *conn,
} }
#endif /* WINBIND_NTLM_AUTH_ENABLED */ #endif /* WINBIND_NTLM_AUTH_ENABLED */
/* this is for creating ntlm header output */ /*
* This is for creating ntlm header output
*/
CURLcode Curl_output_ntlm(struct connectdata *conn, CURLcode Curl_output_ntlm(struct connectdata *conn,
bool proxy) bool proxy)
{ {
size_t size; size_t size;
char *base64 = NULL; char *base64 = NULL;
unsigned char ntlmbuf[1024]; /* enough, unless the user + host + domain is unsigned char ntlmbuf[NTLM_BUFSIZE];
very long */
/* point to the address of the pointer that holds the string to sent to the /* point to the address of the pointer that holds the string to sent to the
server, which is for a plain host or for a HTTP proxy */ server, which is for a plain host or for a HTTP proxy */
@ -1015,9 +1023,13 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
struct ntlmdata *ntlm; struct ntlmdata *ntlm;
struct auth *authp; struct auth *authp;
struct SessionHandle *data;
DEBUGASSERT(conn); DEBUGASSERT(conn);
DEBUGASSERT(conn->data); DEBUGASSERT(conn->data);
data = conn->data;
#ifdef USE_NSS #ifdef USE_NSS
if(CURLE_OK != Curl_nss_force_init(conn->data)) if(CURLE_OK != Curl_nss_force_init(conn->data))
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
@ -1059,17 +1071,19 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
case NTLMSTATE_TYPE1: case NTLMSTATE_TYPE1:
default: /* for the weird cases we (re)start here */ default: /* for the weird cases we (re)start here */
/* Create and send a type-1 message: /* Create a type-1 message */
/* NTLM type-1 message structure:
Index Description Content
0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
(0x4e544c4d53535000)
8 NTLM Message Type long (0x01000000)
12 Flags long
16 Supplied Domain security buffer(*)
24 Supplied Workstation security buffer(*)
32 start of data block
Index Description Content
0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
(0x4e544c4d53535000)
8 NTLM Message Type long (0x01000000)
12 Flags long
(16) Supplied Domain security buffer (*)
(24) Supplied Workstation security buffer (*)
(32) OS Version Structure 8 bytes (*)
(32) (40) Start of data block (*)
(*) -> Optional
*/ */
#ifdef USE_WINDOWS_SSPI #ifdef USE_WINDOWS_SSPI
{ {
@ -1127,7 +1141,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
strncpy((char *)ntlm->identity.Domain, domain, domlen); strncpy((char *)ntlm->identity.Domain, domain, domlen);
ntlm->identity.Domain[domlen] = '\0'; ntlm->identity.Domain[domlen] = '\0';
ntlm->identity.DomainLength = (unsigned long)domlen; ntlm->identity.DomainLength = (unsigned long)domlen;
ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
} }
else else
@ -1143,7 +1157,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
desc.ulVersion = SECBUFFER_VERSION; desc.ulVersion = SECBUFFER_VERSION;
desc.cBuffers = 1; desc.cBuffers = 1;
desc.pBuffers = &buf; desc.pBuffers = &buf;
buf.cbBuffer = sizeof(ntlmbuf); buf.cbBuffer = NTLM_BUFSIZE;
buf.BufferType = SECBUFFER_TOKEN; buf.BufferType = SECBUFFER_TOKEN;
buf.pvBuffer = ntlmbuf; buf.pvBuffer = ntlmbuf;
@ -1183,7 +1197,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
#else #else
#define NTLM2FLAG 0 #define NTLM2FLAG 0
#endif #endif
snprintf((char *)ntlmbuf, sizeof(ntlmbuf), snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
NTLMSSP_SIGNATURE "%c" NTLMSSP_SIGNATURE "%c"
"\x01%c%c%c" /* 32-bit type = 1 */ "\x01%c%c%c" /* 32-bit type = 1 */
"%c%c%c%c" /* 32-bit NTLM flag field */ "%c%c%c%c" /* 32-bit NTLM flag field */
@ -1216,7 +1230,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
host, /* this is empty */ host, /* this is empty */
domain /* this is empty */); domain /* this is empty */);
/* initial packet length */ /* Initial packet length */
size = 32 + hostlen + domlen; size = 32 + hostlen + domlen;
} }
#endif #endif
@ -1260,21 +1274,23 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
break; break;
case NTLMSTATE_TYPE2: case NTLMSTATE_TYPE2:
/* We received the type-2 message already, create a type-3 message: /* We already received the type-2 message, create a type-3 message */
/* NTLM type-3 message structure:
Index Description Content
0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
(0x4e544c4d53535000)
8 NTLM Message Type long (0x03000000)
12 LM/LMv2 Response security buffer(*)
20 NTLM/NTLMv2 Response security buffer(*)
28 Domain Name security buffer(*)
36 User Name security buffer(*)
44 Workstation Name security buffer(*)
(52) Session Key (optional) security buffer(*)
(60) Flags (optional) long
52 (64) start of data block
Index Description Content
0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
(0x4e544c4d53535000)
8 NTLM Message Type long (0x03000000)
12 LM/LMv2 Response security buffer
20 NTLM/NTLMv2 Response security buffer
28 Domain Name security buffer
36 User Name security buffer
44 Workstation Name security buffer
(52) Session Key security buffer (*)
(60) Flags long (*)
(64) OS Version Structure 8 bytes (*)
52 (64) (72) Start of data block (*)
(*) -> Optional
*/ */
{ {
@ -1298,7 +1314,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
type_2.cbBuffer = ntlm->n_type_2; type_2.cbBuffer = ntlm->n_type_2;
type_3.BufferType = SECBUFFER_TOKEN; type_3.BufferType = SECBUFFER_TOKEN;
type_3.pvBuffer = ntlmbuf; type_3.pvBuffer = ntlmbuf;
type_3.cbBuffer = sizeof(ntlmbuf); type_3.cbBuffer = NTLM_BUFSIZE;
status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle,
&ntlm->c_handle, &ntlm->c_handle,
@ -1353,7 +1369,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
userlen = strlen(user); userlen = strlen(user);
if(Curl_gethostname(host, HOSTNAME_MAX)) { if(Curl_gethostname(host, HOSTNAME_MAX)) {
infof(conn->data, "gethostname() failed, continuing without!"); infof(data, "gethostname() failed, continuing without!");
hostlen = 0; hostlen = 0;
} }
else { else {
@ -1384,16 +1400,16 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
/* Need to create 8 bytes random data */ /* Need to create 8 bytes random data */
#ifdef USE_SSLEAY #ifdef USE_SSLEAY
MD5_CTX MD5pw; MD5_CTX MD5pw;
Curl_ossl_seed(conn->data); /* Initiate the seed if not already done */ Curl_ossl_seed(data); /* Initiate the seed if not already done */
RAND_bytes(entropy, 8); RAND_bytes(entropy, 8);
#elif defined(USE_GNUTLS) #elif defined(USE_GNUTLS)
gcry_md_hd_t MD5pw; gcry_md_hd_t MD5pw;
Curl_gtls_seed(conn->data); /* Initiate the seed if not already done */ Curl_gtls_seed(data); /* Initiate the seed if not already done */
gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM); gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM);
#elif defined(USE_NSS) #elif defined(USE_NSS)
PK11Context *MD5pw; PK11Context *MD5pw;
unsigned int outlen; unsigned int outlen;
Curl_nss_seed(conn->data); /* Initiate the seed if not already done */ Curl_nss_seed(data); /* Initiate the seed if not already done */
PK11_GenerateRandom(entropy, 8); PK11_GenerateRandom(entropy, 8);
#endif #endif
@ -1425,7 +1441,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
/* We shall only use the first 8 bytes of md5sum, /* We shall only use the first 8 bytes of md5sum,
but the des code in lm_resp only encrypt the first 8 bytes */ but the des code in lm_resp only encrypt the first 8 bytes */
if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY) if(mk_nt_hash(data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
lm_resp(ntbuffer, md5sum, ntresp); lm_resp(ntbuffer, md5sum, ntresp);
@ -1441,12 +1457,12 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
unsigned char lmbuffer[0x18]; unsigned char lmbuffer[0x18];
#if USE_NTRESPONSES #if USE_NTRESPONSES
if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY) if(mk_nt_hash(data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
#endif #endif
mk_lm_hash(conn->data, passwdp, lmbuffer); mk_lm_hash(data, passwdp, lmbuffer);
lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
/* A safer but less compatible alternative is: /* A safer but less compatible alternative is:
* lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); * lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
@ -1464,7 +1480,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
hostoff = useroff + userlen; hostoff = useroff + userlen;
/* Create the big type-3 message binary blob */ /* Create the big type-3 message binary blob */
size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf), size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
NTLMSSP_SIGNATURE "%c" NTLMSSP_SIGNATURE "%c"
"\x03%c%c%c" /* 32-bit type = 3 */ "\x03%c%c%c" /* 32-bit type = 3 */
@ -1551,7 +1567,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
DEBUGASSERT(size == (size_t)lmrespoff); DEBUGASSERT(size == (size_t)lmrespoff);
/* We append the binary hashes */ /* We append the binary hashes */
if(size < (sizeof(ntlmbuf) - 0x18)) { if(size < (NTLM_BUFSIZE - 0x18)) {
memcpy(&ntlmbuf[size], lmresp, 0x18); memcpy(&ntlmbuf[size], lmresp, 0x18);
size += 0x18; size += 0x18;
} }
@ -1562,7 +1578,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
}); });
#if USE_NTRESPONSES #if USE_NTRESPONSES
if(size < (sizeof(ntlmbuf) - 0x18)) { if(size < (NTLM_BUFSIZE - 0x18)) {
DEBUGASSERT(size == (size_t)ntrespoff); DEBUGASSERT(size == (size_t)ntrespoff);
memcpy(&ntlmbuf[size], ntresp, 0x18); memcpy(&ntlmbuf[size], ntresp, 0x18);
size += 0x18; size += 0x18;
@ -1584,8 +1600,8 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
/* Make sure that the domain, user and host strings fit in the /* Make sure that the domain, user and host strings fit in the
buffer before we copy them there. */ buffer before we copy them there. */
if(size + userlen + domlen + hostlen >= sizeof(ntlmbuf)) { if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
failf(conn->data, "user + domain + host name too big"); failf(data, "user + domain + host name too big");
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
@ -1613,9 +1629,9 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
size += hostlen; size += hostlen;
/* convert domain, user, and host to ASCII but leave the rest as-is */ /* Convert domain, user, and host to ASCII but leave the rest as-is */
res = Curl_convert_to_network(conn->data, (char *)&ntlmbuf[domoff], res = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff],
size-domoff); size - domoff);
if(res) if(res)
return CURLE_CONV_FAILED; return CURLE_CONV_FAILED;
@ -1638,7 +1654,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */ ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
authp->done = TRUE; authp->done = TRUE;
} }
break; break;
case NTLMSTATE_TYPE3: case NTLMSTATE_TYPE3:
/* connection is already authenticated, /* connection is already authenticated,

View File

@ -50,6 +50,9 @@ void Curl_http_ntlm_cleanup(struct connectdata *conn);
#define Curl_http_ntlm_cleanup(x) #define Curl_http_ntlm_cleanup(x)
#endif #endif
/* NTLM buffer fixed size, large enough for long user + host + domain */
#define NTLM_BUFSIZE 1024
/* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */ /* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */
#define NTLMFLAG_NEGOTIATE_UNICODE (1<<0) #define NTLMFLAG_NEGOTIATE_UNICODE (1<<0)