http NTLM: split http_ntlm.[ch] between http_ntlm.[ch] and curl_ntlm.[ch]
For modularity purposes, huge chunks of NTLM existing code is transformed into
functions to allow future internal code reuse.
Resulting three new libcurl private functions:
- Curl_ntlm_create_type1_message()
- Curl_ntlm_create_type3_message()
- Curl_ntlm_decode_type2_message()
Changing static ntlm_sspi_cleanup() into non-static Curl_ntlm_sspi_cleanup()
This 'refactoring' has been prepared by previous commits to allow that this
specific one does not introduce any change to existing code. All existing
goodness and badness previous to this commit should remain the same once it is
applied, the only difference should be that existing code is moved into
functions.
Given the quite big portions of code being moved around, and the importance of
change traceability, this commit has been done in such a way that it is
possible to perform a three-way diff from initial http_ntlm.[ch] to resulting
http_ntlm.[ch] and curl_ntlm.[ch] to actually verify that no functional change
is introduced here.
Notice that Steve Holme has provided several patches, but these included this
refactoring along with 'extra' fixes. I really wanted this 'clean' refactoring
done first, in order to allow discussion or committing of 'extra' fixes on a
case by case basis, so, I had to bite the bullet ;-)
Comments, line adjustments, compiler warning fixes, whatever, may follow
afterwards.
2011-08-14 09:45:19 -04:00
|
|
|
/***************************************************************************
|
|
|
|
* _ _ ____ _
|
|
|
|
* Project ___| | | | _ \| |
|
|
|
|
* / __| | | | |_) | |
|
|
|
|
* | (__| |_| | _ <| |___
|
|
|
|
* \___|\___/|_| \_\_____|
|
|
|
|
*
|
|
|
|
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
|
|
|
*
|
|
|
|
* This software is licensed as described in the file COPYING, which
|
|
|
|
* you should have received as part of this distribution. The terms
|
|
|
|
* are also available at http://curl.haxx.se/docs/copyright.html.
|
|
|
|
*
|
|
|
|
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
|
|
|
* copies of the Software, and permit persons to whom the Software is
|
|
|
|
* furnished to do so, under the terms of the COPYING file.
|
|
|
|
*
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "setup.h"
|
|
|
|
|
|
|
|
/* NTLM details:
|
|
|
|
|
|
|
|
http://davenport.sourceforge.net/ntlm.html
|
|
|
|
http://www.innovation.ch/java/ntlm.html
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef CURL_DISABLE_HTTP
|
|
|
|
#ifdef USE_NTLM
|
|
|
|
|
|
|
|
#define DEBUG_ME 0
|
|
|
|
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_WAIT_H
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_SIGNAL_H
|
|
|
|
#include <signal.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
|
|
|
|
#include <netdb.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "urldata.h"
|
|
|
|
#include "non-ascii.h" /* for Curl_convert_... prototypes */
|
|
|
|
#include "sendf.h"
|
|
|
|
#include "select.h"
|
|
|
|
#include "rawstr.h"
|
|
|
|
#include "curl_base64.h"
|
|
|
|
#include "curl_ntlm.h"
|
|
|
|
#include "url.h"
|
|
|
|
#include "strerror.h"
|
|
|
|
#include "curl_gethostname.h"
|
|
|
|
#include "curl_memory.h"
|
|
|
|
|
|
|
|
#define _MPRINTF_REPLACE /* use our functions only */
|
|
|
|
#include <curl/mprintf.h>
|
|
|
|
|
|
|
|
#ifdef USE_SSLEAY
|
|
|
|
#include "ssluse.h"
|
|
|
|
# ifdef USE_OPENSSL
|
|
|
|
# include <openssl/des.h>
|
|
|
|
# ifndef OPENSSL_NO_MD4
|
|
|
|
# include <openssl/md4.h>
|
|
|
|
# endif
|
|
|
|
# include <openssl/md5.h>
|
|
|
|
# include <openssl/ssl.h>
|
|
|
|
# include <openssl/rand.h>
|
|
|
|
# else
|
|
|
|
# include <des.h>
|
|
|
|
# ifndef OPENSSL_NO_MD4
|
|
|
|
# include <md4.h>
|
|
|
|
# endif
|
|
|
|
# include <md5.h>
|
|
|
|
# include <ssl.h>
|
|
|
|
# include <rand.h>
|
|
|
|
# endif
|
|
|
|
|
|
|
|
#ifndef OPENSSL_VERSION_NUMBER
|
|
|
|
#error "OPENSSL_VERSION_NUMBER not defined"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x00907001L
|
|
|
|
#define DES_key_schedule des_key_schedule
|
|
|
|
#define DES_cblock des_cblock
|
|
|
|
#define DES_set_odd_parity des_set_odd_parity
|
|
|
|
#define DES_set_key des_set_key
|
|
|
|
#define DES_ecb_encrypt des_ecb_encrypt
|
|
|
|
|
|
|
|
/* This is how things were done in the old days */
|
|
|
|
#define DESKEY(x) x
|
|
|
|
#define DESKEYARG(x) x
|
|
|
|
#else
|
|
|
|
/* Modern version */
|
|
|
|
#define DESKEYARG(x) *x
|
|
|
|
#define DESKEY(x) &x
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef OPENSSL_NO_MD4
|
|
|
|
/* This requires MD4, but OpenSSL was compiled without it */
|
|
|
|
#define USE_NTRESPONSES 0
|
|
|
|
#define USE_NTLM2SESSION 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#elif defined(USE_GNUTLS)
|
|
|
|
|
|
|
|
#include "gtls.h"
|
|
|
|
#include <gcrypt.h>
|
|
|
|
|
|
|
|
#define MD5_DIGEST_LENGTH 16
|
|
|
|
#define MD4_DIGEST_LENGTH 16
|
|
|
|
|
|
|
|
#elif defined(USE_NSS)
|
|
|
|
|
|
|
|
#include "curl_md4.h"
|
|
|
|
#include "nssg.h"
|
|
|
|
#include <nss.h>
|
|
|
|
#include <pk11pub.h>
|
|
|
|
#include <hasht.h>
|
|
|
|
#define MD5_DIGEST_LENGTH MD5_LENGTH
|
|
|
|
|
|
|
|
#elif defined(USE_WINDOWS_SSPI)
|
|
|
|
|
|
|
|
#include "curl_sspi.h"
|
|
|
|
|
|
|
|
#else
|
|
|
|
# error "Can't compile NTLM support without a crypto library."
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* The last #include file should be: */
|
|
|
|
#include "memdebug.h"
|
|
|
|
|
|
|
|
/* Hostname buffer size */
|
|
|
|
#define HOSTNAME_MAX 1024
|
|
|
|
|
|
|
|
/* "NTLMSSP" signature is always in ASCII regardless of the platform */
|
|
|
|
#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
|
|
|
|
|
|
|
|
#ifndef USE_NTRESPONSES
|
|
|
|
/* Define this to make the type-3 message include the NT response message */
|
|
|
|
#define USE_NTRESPONSES 1
|
|
|
|
|
|
|
|
/* Define this to make the type-3 message include the NTLM2Session response
|
|
|
|
message, requires USE_NTRESPONSES. */
|
|
|
|
#define USE_NTLM2SESSION 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
|
|
|
|
#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8) & 0xff), \
|
|
|
|
(((x) >> 16) & 0xff), (((x) >> 24) & 0xff)
|
|
|
|
|
|
|
|
#if DEBUG_ME
|
|
|
|
# define DEBUG_OUT(x) x
|
|
|
|
static void ntlm_print_flags(FILE *handle, unsigned long flags)
|
|
|
|
{
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_OEM)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
|
|
|
|
if(flags & NTLMFLAG_REQUEST_TARGET)
|
|
|
|
fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
|
|
|
|
if(flags & (1<<3))
|
|
|
|
fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_SIGN)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_SEAL)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
|
|
|
|
if(flags & (1<<10))
|
|
|
|
fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
|
|
|
|
if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
|
|
|
|
fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
|
|
|
|
if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
|
|
|
|
fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
|
|
|
|
if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
|
|
|
|
fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
|
|
|
|
if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
|
|
|
|
fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
|
|
|
|
if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
|
|
|
|
fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
|
|
|
|
if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
|
|
|
|
fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
|
|
|
|
if(flags & (1<<24))
|
|
|
|
fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
|
|
|
|
if(flags & (1<<25))
|
|
|
|
fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
|
|
|
|
if(flags & (1<<26))
|
|
|
|
fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
|
|
|
|
if(flags & (1<<27))
|
|
|
|
fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
|
|
|
|
if(flags & (1<<28))
|
|
|
|
fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_128)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
|
|
|
|
if(flags & NTLMFLAG_NEGOTIATE_56)
|
|
|
|
fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
|
|
|
|
{
|
|
|
|
const char *p = buf;
|
|
|
|
fprintf(stderr, "0x");
|
|
|
|
while(len-- > 0)
|
|
|
|
fprintf(stderr, "%02.2x", (unsigned int)*p++);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
# define DEBUG_OUT(x)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#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.
|
|
|
|
* 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) |
|
|
|
|
((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
NTLM message structure notes:
|
|
|
|
|
2011-08-22 10:42:59 -04:00
|
|
|
A 'short' is a 'network short', a little-endian 16-bit unsigned value.
|
http NTLM: split http_ntlm.[ch] between http_ntlm.[ch] and curl_ntlm.[ch]
For modularity purposes, huge chunks of NTLM existing code is transformed into
functions to allow future internal code reuse.
Resulting three new libcurl private functions:
- Curl_ntlm_create_type1_message()
- Curl_ntlm_create_type3_message()
- Curl_ntlm_decode_type2_message()
Changing static ntlm_sspi_cleanup() into non-static Curl_ntlm_sspi_cleanup()
This 'refactoring' has been prepared by previous commits to allow that this
specific one does not introduce any change to existing code. All existing
goodness and badness previous to this commit should remain the same once it is
applied, the only difference should be that existing code is moved into
functions.
Given the quite big portions of code being moved around, and the importance of
change traceability, this commit has been done in such a way that it is
possible to perform a three-way diff from initial http_ntlm.[ch] to resulting
http_ntlm.[ch] and curl_ntlm.[ch] to actually verify that no functional change
is introduced here.
Notice that Steve Holme has provided several patches, but these included this
refactoring along with 'extra' fixes. I really wanted this 'clean' refactoring
done first, in order to allow discussion or committing of 'extra' fixes on a
case by case basis, so, I had to bite the bullet ;-)
Comments, line adjustments, compiler warning fixes, whatever, may follow
afterwards.
2011-08-14 09:45:19 -04:00
|
|
|
|
2011-08-22 10:42:59 -04:00
|
|
|
A 'long' is a 'network long', a little-endian, 32-bit unsigned value.
|
http NTLM: split http_ntlm.[ch] between http_ntlm.[ch] and curl_ntlm.[ch]
For modularity purposes, huge chunks of NTLM existing code is transformed into
functions to allow future internal code reuse.
Resulting three new libcurl private functions:
- Curl_ntlm_create_type1_message()
- Curl_ntlm_create_type3_message()
- Curl_ntlm_decode_type2_message()
Changing static ntlm_sspi_cleanup() into non-static Curl_ntlm_sspi_cleanup()
This 'refactoring' has been prepared by previous commits to allow that this
specific one does not introduce any change to existing code. All existing
goodness and badness previous to this commit should remain the same once it is
applied, the only difference should be that existing code is moved into
functions.
Given the quite big portions of code being moved around, and the importance of
change traceability, this commit has been done in such a way that it is
possible to perform a three-way diff from initial http_ntlm.[ch] to resulting
http_ntlm.[ch] and curl_ntlm.[ch] to actually verify that no functional change
is introduced here.
Notice that Steve Holme has provided several patches, but these included this
refactoring along with 'extra' fixes. I really wanted this 'clean' refactoring
done first, in order to allow discussion or committing of 'extra' fixes on a
case by case basis, so, I had to bite the bullet ;-)
Comments, line adjustments, compiler warning fixes, whatever, may follow
afterwards.
2011-08-14 09:45:19 -04:00
|
|
|
|
|
|
|
A 'security buffer' represents a triplet used to point to a buffer,
|
|
|
|
consisting of two shorts and one long:
|
|
|
|
|
|
|
|
1. A 'short' containing the length of the buffer content in bytes.
|
|
|
|
2. A 'short' containing the allocated space for the buffer in bytes.
|
|
|
|
3. A 'long' containing the offset to the start of the buffer in bytes,
|
|
|
|
from the beginning of the NTLM message.
|
|
|
|
*/
|
|
|
|
|
2011-08-22 10:42:59 -04:00
|
|
|
/*
|
|
|
|
* Curl_ntlm_decode_type2_message()
|
|
|
|
*
|
|
|
|
* This is used to decode a ntlm type-2 message received from a: HTTP, SMTP
|
|
|
|
* or POP3 server. 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] - Pointer to session handle.
|
|
|
|
* header [in] - Pointer to the input buffer.
|
|
|
|
* ntlm [in] - Pointer to ntlm data struct being used and modified.
|
|
|
|
*
|
|
|
|
* Returns CURLE_OK on success.
|
|
|
|
*/
|
http NTLM: split http_ntlm.[ch] between http_ntlm.[ch] and curl_ntlm.[ch]
For modularity purposes, huge chunks of NTLM existing code is transformed into
functions to allow future internal code reuse.
Resulting three new libcurl private functions:
- Curl_ntlm_create_type1_message()
- Curl_ntlm_create_type3_message()
- Curl_ntlm_decode_type2_message()
Changing static ntlm_sspi_cleanup() into non-static Curl_ntlm_sspi_cleanup()
This 'refactoring' has been prepared by previous commits to allow that this
specific one does not introduce any change to existing code. All existing
goodness and badness previous to this commit should remain the same once it is
applied, the only difference should be that existing code is moved into
functions.
Given the quite big portions of code being moved around, and the importance of
change traceability, this commit has been done in such a way that it is
possible to perform a three-way diff from initial http_ntlm.[ch] to resulting
http_ntlm.[ch] and curl_ntlm.[ch] to actually verify that no functional change
is introduced here.
Notice that Steve Holme has provided several patches, but these included this
refactoring along with 'extra' fixes. I really wanted this 'clean' refactoring
done first, in order to allow discussion or committing of 'extra' fixes on a
case by case basis, so, I had to bite the bullet ;-)
Comments, line adjustments, compiler warning fixes, whatever, may follow
afterwards.
2011-08-14 09:45:19 -04:00
|
|
|
CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data,
|
|
|
|
const char* header,
|
|
|
|
struct ntlmdata* ntlm)
|
|
|
|
{
|
|
|
|
#ifndef USE_WINDOWS_SSPI
|
|
|
|
static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
*/
|
|
|
|
|
2011-08-24 02:07:36 -04:00
|
|
|
size_t size = 0;
|
|
|
|
unsigned char *buffer = NULL;
|
|
|
|
CURLcode error;
|
http NTLM: split http_ntlm.[ch] between http_ntlm.[ch] and curl_ntlm.[ch]
For modularity purposes, huge chunks of NTLM existing code is transformed into
functions to allow future internal code reuse.
Resulting three new libcurl private functions:
- Curl_ntlm_create_type1_message()
- Curl_ntlm_create_type3_message()
- Curl_ntlm_decode_type2_message()
Changing static ntlm_sspi_cleanup() into non-static Curl_ntlm_sspi_cleanup()
This 'refactoring' has been prepared by previous commits to allow that this
specific one does not introduce any change to existing code. All existing
goodness and badness previous to this commit should remain the same once it is
applied, the only difference should be that existing code is moved into
functions.
Given the quite big portions of code being moved around, and the importance of
change traceability, this commit has been done in such a way that it is
possible to perform a three-way diff from initial http_ntlm.[ch] to resulting
http_ntlm.[ch] and curl_ntlm.[ch] to actually verify that no functional change
is introduced here.
Notice that Steve Holme has provided several patches, but these included this
refactoring along with 'extra' fixes. I really wanted this 'clean' refactoring
done first, in order to allow discussion or committing of 'extra' fixes on a
case by case basis, so, I had to bite the bullet ;-)
Comments, line adjustments, compiler warning fixes, whatever, may follow
afterwards.
2011-08-14 09:45:19 -04:00
|
|
|
|
2011-08-14 10:36:47 -04:00
|
|
|
#if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI)
|
|
|
|
(void)data;
|
|
|
|
#endif
|
|
|
|
|
2011-08-24 02:07:36 -04:00
|
|
|
error = Curl_base64_decode(header, &buffer, &size);
|
|
|
|
if(error)
|
|
|
|
return error;
|
|
|
|
|
|
|
|
if(!buffer) {
|
|
|
|
infof(data, "NTLM handshake failure (unhandled condition)\n");
|
|
|
|
return CURLE_REMOTE_ACCESS_DENIED;
|
|
|
|
}
|
http NTLM: split http_ntlm.[ch] between http_ntlm.[ch] and curl_ntlm.[ch]
For modularity purposes, huge chunks of NTLM existing code is transformed into
functions to allow future internal code reuse.
Resulting three new libcurl private functions:
- Curl_ntlm_create_type1_message()
- Curl_ntlm_create_type3_message()
- Curl_ntlm_decode_type2_message()
Changing static ntlm_sspi_cleanup() into non-static Curl_ntlm_sspi_cleanup()
This 'refactoring' has been prepared by previous commits to allow that this
specific one does not introduce any change to existing code. All existing
goodness and badness previous to this commit should remain the same once it is
applied, the only difference should be that existing code is moved into
functions.
Given the quite big portions of code being moved around, and the importance of
change traceability, this commit has been done in such a way that it is
possible to perform a three-way diff from initial http_ntlm.[ch] to resulting
http_ntlm.[ch] and curl_ntlm.[ch] to actually verify that no functional change
is introduced here.
Notice that Steve Holme has provided several patches, but these included this
refactoring along with 'extra' fixes. I really wanted this 'clean' refactoring
done first, in order to allow discussion or committing of 'extra' fixes on a
case by case basis, so, I had to bite the bullet ;-)
Comments, line adjustments, compiler warning fixes, whatever, may follow
afterwards.
2011-08-14 09:45:19 -04:00
|
|
|
|
|
|
|
#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 = (unsigned long)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);
|
|
|
|
infof(data, "NTLM handshake failure (bad type-2 message)\n");
|
|
|
|
return CURLE_REMOTE_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
ntlm->flags = readint_le(&buffer[20]);
|
|
|
|
memcpy(ntlm->nonce, &buffer[24], 8);
|
|
|
|
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
#endif
|
|
|
|
free(buffer);
|
|
|
|
|
|
|
|
return CURLE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef USE_WINDOWS_SSPI
|
|
|
|
|
|
|
|
#ifdef USE_SSLEAY
|
|
|
|
/*
|
|
|
|
* Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
|
|
|
|
* key schedule ks is also set.
|
|
|
|
*/
|
|
|
|
static void setup_des_key(const unsigned char *key_56,
|
|
|
|
DES_key_schedule DESKEYARG(ks))
|
|
|
|
{
|
|
|
|
DES_cblock key;
|
|
|
|
|
|
|
|
key[0] = key_56[0];
|
|
|
|
key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
|
|
|
|
key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
|
|
|
|
key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
|
|
|
|
key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
|
|
|
|
key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
|
|
|
|
key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
|
|
|
|
key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
|
|
|
|
|
|
|
|
DES_set_odd_parity(&key);
|
|
|
|
DES_set_key(&key, ks);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* defined(USE_SSLEAY) */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Turns a 56 bit key into the 64 bit, odd parity key. Used by GnuTLS and NSS.
|
|
|
|
*/
|
|
|
|
static void extend_key_56_to_64(const unsigned char *key_56, char *key)
|
|
|
|
{
|
|
|
|
key[0] = key_56[0];
|
|
|
|
key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
|
|
|
|
key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
|
|
|
|
key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
|
|
|
|
key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
|
|
|
|
key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
|
|
|
|
key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
|
|
|
|
key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(USE_GNUTLS)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Turns a 56 bit key into the 64 bit, odd parity key and sets the key.
|
|
|
|
*/
|
|
|
|
static void setup_des_key(const unsigned char *key_56,
|
|
|
|
gcry_cipher_hd_t *des)
|
|
|
|
{
|
|
|
|
char key[8];
|
|
|
|
extend_key_56_to_64(key_56, key);
|
|
|
|
gcry_cipher_setkey(*des, key, 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(USE_NSS)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Expands a 56 bit key KEY_56 to 64 bit and encrypts 64 bit of data, using
|
|
|
|
* the expanded key. The caller is responsible for giving 64 bit of valid
|
|
|
|
* data is IN and (at least) 64 bit large buffer as OUT.
|
|
|
|
*/
|
|
|
|
static bool encrypt_des(const unsigned char *in, unsigned char *out,
|
|
|
|
const unsigned char *key_56)
|
|
|
|
{
|
|
|
|
const CK_MECHANISM_TYPE mech = CKM_DES_ECB; /* DES cipher in ECB mode */
|
|
|
|
PK11SlotInfo *slot = NULL;
|
|
|
|
char key[8]; /* expanded 64 bit key */
|
|
|
|
SECItem key_item;
|
|
|
|
PK11SymKey *symkey = NULL;
|
|
|
|
SECItem *param = NULL;
|
|
|
|
PK11Context *ctx = NULL;
|
|
|
|
int out_len; /* not used, required by NSS */
|
|
|
|
bool rv = FALSE;
|
|
|
|
|
|
|
|
/* use internal slot for DES encryption (requires NSS to be initialized) */
|
|
|
|
slot = PK11_GetInternalKeySlot();
|
|
|
|
if(!slot)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* expand the 56 bit key to 64 bit and wrap by NSS */
|
|
|
|
extend_key_56_to_64(key_56, key);
|
|
|
|
key_item.data = (unsigned char *)key;
|
|
|
|
key_item.len = /* hard-wired */ 8;
|
|
|
|
symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_ENCRYPT,
|
|
|
|
&key_item, NULL);
|
|
|
|
if(!symkey)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
/* create DES encryption context */
|
|
|
|
param = PK11_ParamFromIV(mech, /* no IV in ECB mode */ NULL);
|
|
|
|
if(!param)
|
|
|
|
goto fail;
|
|
|
|
ctx = PK11_CreateContextBySymKey(mech, CKA_ENCRYPT, symkey, param);
|
|
|
|
if(!ctx)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
/* perform the encryption */
|
|
|
|
if(SECSuccess == PK11_CipherOp(ctx, out, &out_len, /* outbuflen */ 8,
|
|
|
|
(unsigned char *)in, /* inbuflen */ 8)
|
|
|
|
&& SECSuccess == PK11_Finalize(ctx))
|
|
|
|
rv = /* all OK */ TRUE;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
/* cleanup */
|
|
|
|
if(ctx)
|
|
|
|
PK11_DestroyContext(ctx, PR_TRUE);
|
|
|
|
if(symkey)
|
|
|
|
PK11_FreeSymKey(symkey);
|
|
|
|
if(param)
|
|
|
|
SECITEM_FreeItem(param, PR_TRUE);
|
|
|
|
PK11_FreeSlot(slot);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* defined(USE_NSS) */
|
|
|
|
|
|
|
|
#endif /* defined(USE_SSLEAY) */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* takes a 21 byte array and treats it as 3 56-bit DES keys. The
|
|
|
|
* 8 byte plaintext is encrypted with each key and the resulting 24
|
|
|
|
* bytes are stored in the results array.
|
|
|
|
*/
|
|
|
|
static void lm_resp(const unsigned char *keys,
|
|
|
|
const unsigned char *plaintext,
|
|
|
|
unsigned char *results)
|
|
|
|
{
|
|
|
|
#ifdef USE_SSLEAY
|
|
|
|
DES_key_schedule ks;
|
|
|
|
|
|
|
|
setup_des_key(keys, DESKEY(ks));
|
|
|
|
DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
|
|
|
|
DESKEY(ks), DES_ENCRYPT);
|
|
|
|
|
|
|
|
setup_des_key(keys + 7, DESKEY(ks));
|
|
|
|
DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 8),
|
|
|
|
DESKEY(ks), DES_ENCRYPT);
|
|
|
|
|
|
|
|
setup_des_key(keys + 14, DESKEY(ks));
|
|
|
|
DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 16),
|
|
|
|
DESKEY(ks), DES_ENCRYPT);
|
|
|
|
#elif defined(USE_GNUTLS)
|
|
|
|
gcry_cipher_hd_t des;
|
|
|
|
|
|
|
|
gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
|
|
|
|
setup_des_key(keys, &des);
|
|
|
|
gcry_cipher_encrypt(des, results, 8, plaintext, 8);
|
|
|
|
gcry_cipher_close(des);
|
|
|
|
|
|
|
|
gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
|
|
|
|
setup_des_key(keys + 7, &des);
|
|
|
|
gcry_cipher_encrypt(des, results + 8, 8, plaintext, 8);
|
|
|
|
gcry_cipher_close(des);
|
|
|
|
|
|
|
|
gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
|
|
|
|
setup_des_key(keys + 14, &des);
|
|
|
|
gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8);
|
|
|
|
gcry_cipher_close(des);
|
|
|
|
#elif defined(USE_NSS)
|
|
|
|
encrypt_des(plaintext, results, keys);
|
|
|
|
encrypt_des(plaintext, results + 8, keys + 7);
|
|
|
|
encrypt_des(plaintext, results + 16, keys + 14);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set up lanmanager hashed password
|
|
|
|
*/
|
|
|
|
static void mk_lm_hash(struct SessionHandle *data,
|
|
|
|
const char *password,
|
|
|
|
unsigned char *lmbuffer /* 21 bytes */)
|
|
|
|
{
|
|
|
|
CURLcode res;
|
|
|
|
unsigned char pw[14];
|
|
|
|
static const unsigned char magic[] = {
|
|
|
|
0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */
|
|
|
|
};
|
|
|
|
size_t len = CURLMIN(strlen(password), 14);
|
|
|
|
|
|
|
|
Curl_strntoupper((char *)pw, password, len);
|
|
|
|
memset(&pw[len], 0, 14 - len);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The LanManager hashed password needs to be created using the
|
|
|
|
* password in the network encoding not the host encoding.
|
|
|
|
*/
|
|
|
|
res = Curl_convert_to_network(data, (char *)pw, 14);
|
|
|
|
if(res)
|
|
|
|
return;
|
|
|
|
|
|
|
|
{
|
|
|
|
/* Create LanManager hashed password. */
|
|
|
|
|
|
|
|
#ifdef USE_SSLEAY
|
|
|
|
DES_key_schedule ks;
|
|
|
|
|
|
|
|
setup_des_key(pw, DESKEY(ks));
|
|
|
|
DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
|
|
|
|
DESKEY(ks), DES_ENCRYPT);
|
|
|
|
|
|
|
|
setup_des_key(pw + 7, DESKEY(ks));
|
|
|
|
DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer + 8),
|
|
|
|
DESKEY(ks), DES_ENCRYPT);
|
|
|
|
#elif defined(USE_GNUTLS)
|
|
|
|
gcry_cipher_hd_t des;
|
|
|
|
|
|
|
|
gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
|
|
|
|
setup_des_key(pw, &des);
|
|
|
|
gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8);
|
|
|
|
gcry_cipher_close(des);
|
|
|
|
|
|
|
|
gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
|
|
|
|
setup_des_key(pw + 7, &des);
|
|
|
|
gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8);
|
|
|
|
gcry_cipher_close(des);
|
|
|
|
#elif defined(USE_NSS)
|
|
|
|
encrypt_des(magic, lmbuffer, pw);
|
|
|
|
encrypt_des(magic, lmbuffer + 8, pw + 7);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
memset(lmbuffer + 16, 0, 21 - 16);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if USE_NTRESPONSES
|
|
|
|
static void ascii_to_unicode_le(unsigned char *dest, const char *src,
|
|
|
|
size_t srclen)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
for(i = 0; i < srclen; i++) {
|
|
|
|
dest[2 * i] = (unsigned char)src[i];
|
|
|
|
dest[2 * i + 1] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set up nt hashed passwords
|
|
|
|
*/
|
|
|
|
static CURLcode mk_nt_hash(struct SessionHandle *data,
|
|
|
|
const char *password,
|
|
|
|
unsigned char *ntbuffer /* 21 bytes */)
|
|
|
|
{
|
|
|
|
size_t len = strlen(password);
|
|
|
|
unsigned char *pw = malloc(len * 2);
|
|
|
|
CURLcode result;
|
|
|
|
if(!pw)
|
|
|
|
return CURLE_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
ascii_to_unicode_le(pw, password, len);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The NT hashed password needs to be created using the password in the
|
|
|
|
* network encoding not the host encoding.
|
|
|
|
*/
|
|
|
|
result = Curl_convert_to_network(data, (char *)pw, len * 2);
|
|
|
|
if(result)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
{
|
|
|
|
/* Create NT hashed password. */
|
|
|
|
#ifdef USE_SSLEAY
|
|
|
|
MD4_CTX MD4pw;
|
|
|
|
MD4_Init(&MD4pw);
|
|
|
|
MD4_Update(&MD4pw, pw, 2 * len);
|
|
|
|
MD4_Final(ntbuffer, &MD4pw);
|
|
|
|
#elif defined(USE_GNUTLS)
|
|
|
|
gcry_md_hd_t MD4pw;
|
|
|
|
gcry_md_open(&MD4pw, GCRY_MD_MD4, 0);
|
|
|
|
gcry_md_write(MD4pw, pw, 2 * len);
|
|
|
|
memcpy (ntbuffer, gcry_md_read (MD4pw, 0), MD4_DIGEST_LENGTH);
|
|
|
|
gcry_md_close(MD4pw);
|
|
|
|
#elif defined(USE_NSS)
|
|
|
|
Curl_md4it(ntbuffer, pw, 2 * len);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
memset(ntbuffer + 16, 0, 21 - 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(pw);
|
|
|
|
|
|
|
|
return CURLE_OK;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef USE_WINDOWS_SSPI
|
|
|
|
void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm)
|
|
|
|
{
|
|
|
|
if(ntlm->type_2) {
|
|
|
|
free(ntlm->type_2);
|
|
|
|
ntlm->type_2 = NULL;
|
|
|
|
}
|
|
|
|
if(ntlm->has_handles) {
|
|
|
|
s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
|
|
|
|
s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
|
|
|
|
ntlm->has_handles = 0;
|
|
|
|
}
|
|
|
|
if(ntlm->p_identity) {
|
|
|
|
if(ntlm->identity.User) free(ntlm->identity.User);
|
|
|
|
if(ntlm->identity.Password) free(ntlm->identity.Password);
|
|
|
|
if(ntlm->identity.Domain) free(ntlm->identity.Domain);
|
|
|
|
ntlm->p_identity = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef USE_WINDOWS_SSPI
|
|
|
|
/* copy the source to the destination and fill in zeroes in every
|
|
|
|
other destination byte! */
|
|
|
|
static void unicodecpy(unsigned char *dest,
|
|
|
|
const char *src, size_t length)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
for(i = 0; i < length; i++) {
|
|
|
|
dest[2 * i] = (unsigned char)src[i];
|
|
|
|
dest[2 * i + 1] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-08-22 10:42:59 -04:00
|
|
|
/*
|
|
|
|
* Curl_ntlm_create_type1_message()
|
|
|
|
*
|
2011-08-25 09:09:30 -04:00
|
|
|
* This is used to generate an already encoded NTLM type-1 message ready
|
|
|
|
* for sending to the recipient, be it a: HTTP, SMTP or POP3 server,
|
2011-08-22 10:42:59 -04:00
|
|
|
* using the appropriate compile time crypo API.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
*
|
|
|
|
* userp [in] - The user name in the format User or Domain\User.
|
|
|
|
* passdwp [in] - The user's password.
|
2011-08-25 09:09:30 -04:00
|
|
|
* ntlm [in/out] - The ntlm data struct being used and modified.
|
|
|
|
* outptr [in/out] - The adress where a pointer to newly allocated memory
|
|
|
|
* holding the result will be stored upon completion.
|
2011-08-22 10:42:59 -04:00
|
|
|
*
|
|
|
|
* Returns CURLE_OK on success.
|
|
|
|
*/
|
http NTLM: split http_ntlm.[ch] between http_ntlm.[ch] and curl_ntlm.[ch]
For modularity purposes, huge chunks of NTLM existing code is transformed into
functions to allow future internal code reuse.
Resulting three new libcurl private functions:
- Curl_ntlm_create_type1_message()
- Curl_ntlm_create_type3_message()
- Curl_ntlm_decode_type2_message()
Changing static ntlm_sspi_cleanup() into non-static Curl_ntlm_sspi_cleanup()
This 'refactoring' has been prepared by previous commits to allow that this
specific one does not introduce any change to existing code. All existing
goodness and badness previous to this commit should remain the same once it is
applied, the only difference should be that existing code is moved into
functions.
Given the quite big portions of code being moved around, and the importance of
change traceability, this commit has been done in such a way that it is
possible to perform a three-way diff from initial http_ntlm.[ch] to resulting
http_ntlm.[ch] and curl_ntlm.[ch] to actually verify that no functional change
is introduced here.
Notice that Steve Holme has provided several patches, but these included this
refactoring along with 'extra' fixes. I really wanted this 'clean' refactoring
done first, in order to allow discussion or committing of 'extra' fixes on a
case by case basis, so, I had to bite the bullet ;-)
Comments, line adjustments, compiler warning fixes, whatever, may follow
afterwards.
2011-08-14 09:45:19 -04:00
|
|
|
CURLcode Curl_ntlm_create_type1_message(const char *userp,
|
|
|
|
const char *passwdp,
|
|
|
|
struct ntlmdata *ntlm,
|
2011-08-25 09:09:30 -04:00
|
|
|
char **outptr)
|
http NTLM: split http_ntlm.[ch] between http_ntlm.[ch] and curl_ntlm.[ch]
For modularity purposes, huge chunks of NTLM existing code is transformed into
functions to allow future internal code reuse.
Resulting three new libcurl private functions:
- Curl_ntlm_create_type1_message()
- Curl_ntlm_create_type3_message()
- Curl_ntlm_decode_type2_message()
Changing static ntlm_sspi_cleanup() into non-static Curl_ntlm_sspi_cleanup()
This 'refactoring' has been prepared by previous commits to allow that this
specific one does not introduce any change to existing code. All existing
goodness and badness previous to this commit should remain the same once it is
applied, the only difference should be that existing code is moved into
functions.
Given the quite big portions of code being moved around, and the importance of
change traceability, this commit has been done in such a way that it is
possible to perform a three-way diff from initial http_ntlm.[ch] to resulting
http_ntlm.[ch] and curl_ntlm.[ch] to actually verify that no functional change
is introduced here.
Notice that Steve Holme has provided several patches, but these included this
refactoring along with 'extra' fixes. I really wanted this 'clean' refactoring
done first, in order to allow discussion or committing of 'extra' fixes on a
case by case basis, so, I had to bite the bullet ;-)
Comments, line adjustments, compiler warning fixes, whatever, may follow
afterwards.
2011-08-14 09:45:19 -04:00
|
|
|
{
|
|
|
|
/* 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) OS Version Structure 8 bytes (*)
|
|
|
|
(32) (40) Start of data block (*)
|
|
|
|
(*) -> Optional
|
|
|
|
*/
|
|
|
|
|
2011-08-25 09:09:30 -04:00
|
|
|
unsigned char ntlmbuf[NTLM_BUFSIZE];
|
|
|
|
size_t base64_sz = 0;
|
|
|
|
size_t size;
|
|
|
|
|
http NTLM: split http_ntlm.[ch] between http_ntlm.[ch] and curl_ntlm.[ch]
For modularity purposes, huge chunks of NTLM existing code is transformed into
functions to allow future internal code reuse.
Resulting three new libcurl private functions:
- Curl_ntlm_create_type1_message()
- Curl_ntlm_create_type3_message()
- Curl_ntlm_decode_type2_message()
Changing static ntlm_sspi_cleanup() into non-static Curl_ntlm_sspi_cleanup()
This 'refactoring' has been prepared by previous commits to allow that this
specific one does not introduce any change to existing code. All existing
goodness and badness previous to this commit should remain the same once it is
applied, the only difference should be that existing code is moved into
functions.
Given the quite big portions of code being moved around, and the importance of
change traceability, this commit has been done in such a way that it is
possible to perform a three-way diff from initial http_ntlm.[ch] to resulting
http_ntlm.[ch] and curl_ntlm.[ch] to actually verify that no functional change
is introduced here.
Notice that Steve Holme has provided several patches, but these included this
refactoring along with 'extra' fixes. I really wanted this 'clean' refactoring
done first, in order to allow discussion or committing of 'extra' fixes on a
case by case basis, so, I had to bite the bullet ;-)
Comments, line adjustments, compiler warning fixes, whatever, may follow
afterwards.
2011-08-14 09:45:19 -04:00
|
|
|
#ifdef USE_WINDOWS_SSPI
|
|
|
|
|
|
|
|
SecBuffer buf;
|
|
|
|
SecBufferDesc desc;
|
|
|
|
SECURITY_STATUS status;
|
|
|
|
ULONG attrs;
|
|
|
|
const char *dest = "";
|
|
|
|
const char *user;
|
|
|
|
const char *domain = "";
|
|
|
|
size_t userlen = 0;
|
|
|
|
size_t domlen = 0;
|
|
|
|
size_t passwdlen = 0;
|
|
|
|
TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
|
|
|
|
|
|
|
|
Curl_ntlm_sspi_cleanup(ntlm);
|
|
|
|
|
|
|
|
user = strchr(userp, '\\');
|
|
|
|
if(!user)
|
|
|
|
user = strchr(userp, '/');
|
|
|
|
|
|
|
|
if(user) {
|
|
|
|
domain = userp;
|
|
|
|
domlen = user - userp;
|
|
|
|
user++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
user = userp;
|
|
|
|
domain = "";
|
|
|
|
domlen = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(user)
|
|
|
|
userlen = strlen(user);
|
|
|
|
|
|
|
|
if(passwdp)
|
|
|
|
passwdlen = strlen(passwdp);
|
|
|
|
|
|
|
|
if(userlen > 0) {
|
|
|
|
/* note: initialize all of this before doing the mallocs so that
|
|
|
|
* it can be cleaned up later without leaking memory.
|
|
|
|
*/
|
|
|
|
ntlm->p_identity = &ntlm->identity;
|
|
|
|
memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
|
|
|
|
if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL)
|
|
|
|
return CURLE_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
ntlm->identity.UserLength = (unsigned long)userlen;
|
|
|
|
if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL)
|
|
|
|
return CURLE_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
ntlm->identity.PasswordLength = (unsigned long)strlen(passwdp);
|
|
|
|
if((ntlm->identity.Domain = malloc(domlen + 1)) == NULL)
|
|
|
|
return CURLE_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
strncpy((char *)ntlm->identity.Domain, domain, domlen);
|
|
|
|
ntlm->identity.Domain[domlen] = '\0';
|
|
|
|
ntlm->identity.DomainLength = (unsigned long)domlen;
|
|
|
|
ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ntlm->p_identity = NULL;
|
|
|
|
|
|
|
|
status = s_pSecFn->AcquireCredentialsHandleA(NULL, (void *)"NTLM",
|
|
|
|
SECPKG_CRED_OUTBOUND, NULL,
|
|
|
|
ntlm->p_identity, NULL, NULL,
|
|
|
|
&ntlm->handle, &tsDummy);
|
|
|
|
if(status != SEC_E_OK)
|
|
|
|
return CURLE_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
desc.ulVersion = SECBUFFER_VERSION;
|
|
|
|
desc.cBuffers = 1;
|
|
|
|
desc.pBuffers = &buf;
|
|
|
|
buf.cbBuffer = NTLM_BUFSIZE;
|
|
|
|
buf.BufferType = SECBUFFER_TOKEN;
|
|
|
|
buf.pvBuffer = ntlmbuf;
|
|
|
|
|
|
|
|
status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, NULL,
|
|
|
|
(void *)dest,
|
|
|
|
ISC_REQ_CONFIDENTIALITY |
|
|
|
|
ISC_REQ_REPLAY_DETECT |
|
|
|
|
ISC_REQ_CONNECTION,
|
|
|
|
0, SECURITY_NETWORK_DREP,
|
|
|
|
NULL, 0,
|
|
|
|
&ntlm->c_handle, &desc,
|
|
|
|
&attrs, &tsDummy);
|
|
|
|
|
|
|
|
if(status == SEC_I_COMPLETE_AND_CONTINUE ||
|
|
|
|
status == SEC_I_CONTINUE_NEEDED)
|
|
|
|
s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc);
|
|
|
|
else if(status != SEC_E_OK) {
|
|
|
|
s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
|
|
|
|
return CURLE_RECV_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
ntlm->has_handles = 1;
|
|
|
|
size = buf.cbBuffer;
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
const char *host = ""; /* empty */
|
|
|
|
const char *domain = ""; /* empty */
|
|
|
|
size_t hostlen = 0;
|
|
|
|
size_t domlen = 0;
|
|
|
|
size_t hostoff = 0;
|
|
|
|
size_t domoff = hostoff + hostlen; /* This is 0: remember that host and
|
|
|
|
domain are empty */
|
2011-08-14 10:36:47 -04:00
|
|
|
(void)userp;
|
|
|
|
(void)passwdp;
|
|
|
|
(void)ntlm;
|
|
|
|
|
http NTLM: split http_ntlm.[ch] between http_ntlm.[ch] and curl_ntlm.[ch]
For modularity purposes, huge chunks of NTLM existing code is transformed into
functions to allow future internal code reuse.
Resulting three new libcurl private functions:
- Curl_ntlm_create_type1_message()
- Curl_ntlm_create_type3_message()
- Curl_ntlm_decode_type2_message()
Changing static ntlm_sspi_cleanup() into non-static Curl_ntlm_sspi_cleanup()
This 'refactoring' has been prepared by previous commits to allow that this
specific one does not introduce any change to existing code. All existing
goodness and badness previous to this commit should remain the same once it is
applied, the only difference should be that existing code is moved into
functions.
Given the quite big portions of code being moved around, and the importance of
change traceability, this commit has been done in such a way that it is
possible to perform a three-way diff from initial http_ntlm.[ch] to resulting
http_ntlm.[ch] and curl_ntlm.[ch] to actually verify that no functional change
is introduced here.
Notice that Steve Holme has provided several patches, but these included this
refactoring along with 'extra' fixes. I really wanted this 'clean' refactoring
done first, in order to allow discussion or committing of 'extra' fixes on a
case by case basis, so, I had to bite the bullet ;-)
Comments, line adjustments, compiler warning fixes, whatever, may follow
afterwards.
2011-08-14 09:45:19 -04:00
|
|
|
#if USE_NTLM2SESSION
|
|
|
|
#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
|
|
|
|
#else
|
|
|
|
#define NTLM2FLAG 0
|
|
|
|
#endif
|
|
|
|
snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
|
|
|
|
NTLMSSP_SIGNATURE "%c"
|
|
|
|
"\x01%c%c%c" /* 32-bit type = 1 */
|
|
|
|
"%c%c%c%c" /* 32-bit NTLM flag field */
|
|
|
|
"%c%c" /* domain length */
|
|
|
|
"%c%c" /* domain allocated space */
|
|
|
|
"%c%c" /* domain name offset */
|
|
|
|
"%c%c" /* 2 zeroes */
|
|
|
|
"%c%c" /* host length */
|
|
|
|
"%c%c" /* host allocated space */
|
|
|
|
"%c%c" /* host name offset */
|
|
|
|
"%c%c" /* 2 zeroes */
|
|
|
|
"%s" /* host name */
|
|
|
|
"%s", /* domain string */
|
|
|
|
0, /* trailing zero */
|
|
|
|
0, 0, 0, /* part of type-1 long */
|
|
|
|
|
|
|
|
LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
|
|
|
|
NTLMFLAG_REQUEST_TARGET |
|
|
|
|
NTLMFLAG_NEGOTIATE_NTLM_KEY |
|
|
|
|
NTLM2FLAG |
|
|
|
|
NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
|
|
|
|
SHORTPAIR(domlen),
|
|
|
|
SHORTPAIR(domlen),
|
|
|
|
SHORTPAIR(domoff),
|
|
|
|
0, 0,
|
|
|
|
SHORTPAIR(hostlen),
|
|
|
|
SHORTPAIR(hostlen),
|
|
|
|
SHORTPAIR(hostoff),
|
|
|
|
0, 0,
|
|
|
|
host, /* this is empty */
|
|
|
|
domain /* this is empty */);
|
|
|
|
|
|
|
|
/* Initial packet length */
|
|
|
|
size = 32 + hostlen + domlen;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
DEBUG_OUT({
|
|
|
|
fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x "
|
|
|
|
"0x%08.8x ",
|
|
|
|
LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
|
|
|
|
NTLMFLAG_REQUEST_TARGET |
|
|
|
|
NTLMFLAG_NEGOTIATE_NTLM_KEY |
|
|
|
|
NTLM2FLAG |
|
|
|
|
NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
|
|
|
|
NTLMFLAG_NEGOTIATE_OEM |
|
|
|
|
NTLMFLAG_REQUEST_TARGET |
|
|
|
|
NTLMFLAG_NEGOTIATE_NTLM_KEY |
|
|
|
|
NTLM2FLAG |
|
|
|
|
NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
|
|
|
|
ntlm_print_flags(stderr,
|
|
|
|
NTLMFLAG_NEGOTIATE_OEM |
|
|
|
|
NTLMFLAG_REQUEST_TARGET |
|
|
|
|
NTLMFLAG_NEGOTIATE_NTLM_KEY |
|
|
|
|
NTLM2FLAG |
|
|
|
|
NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
|
|
|
|
fprintf(stderr, "\n****\n");
|
|
|
|
});
|
|
|
|
|
2011-08-25 09:09:30 -04:00
|
|
|
/* Return with binary blob encoded into base64 */
|
|
|
|
return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, &base64_sz);
|
http NTLM: split http_ntlm.[ch] between http_ntlm.[ch] and curl_ntlm.[ch]
For modularity purposes, huge chunks of NTLM existing code is transformed into
functions to allow future internal code reuse.
Resulting three new libcurl private functions:
- Curl_ntlm_create_type1_message()
- Curl_ntlm_create_type3_message()
- Curl_ntlm_decode_type2_message()
Changing static ntlm_sspi_cleanup() into non-static Curl_ntlm_sspi_cleanup()
This 'refactoring' has been prepared by previous commits to allow that this
specific one does not introduce any change to existing code. All existing
goodness and badness previous to this commit should remain the same once it is
applied, the only difference should be that existing code is moved into
functions.
Given the quite big portions of code being moved around, and the importance of
change traceability, this commit has been done in such a way that it is
possible to perform a three-way diff from initial http_ntlm.[ch] to resulting
http_ntlm.[ch] and curl_ntlm.[ch] to actually verify that no functional change
is introduced here.
Notice that Steve Holme has provided several patches, but these included this
refactoring along with 'extra' fixes. I really wanted this 'clean' refactoring
done first, in order to allow discussion or committing of 'extra' fixes on a
case by case basis, so, I had to bite the bullet ;-)
Comments, line adjustments, compiler warning fixes, whatever, may follow
afterwards.
2011-08-14 09:45:19 -04:00
|
|
|
}
|
|
|
|
|
2011-08-22 10:42:59 -04:00
|
|
|
/*
|
|
|
|
* Curl_ntlm_create_type3_message()
|
|
|
|
*
|
2011-08-25 09:09:30 -04:00
|
|
|
* This is used to generate an already encoded NTLM type-3 message ready
|
|
|
|
* for sending to the recipient, be it a: HTTP, SMTP or POP3 server,
|
2011-08-22 10:42:59 -04:00
|
|
|
* using the appropriate compile time crypo API.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
*
|
|
|
|
* data [in] - The session handle.
|
|
|
|
* userp [in] - The user name in the format User or Domain\User.
|
|
|
|
* passdwp [in] - The user's password.
|
2011-08-25 09:09:30 -04:00
|
|
|
* ntlm [in/out] - The ntlm data struct being used and modified.
|
|
|
|
* outptr [in/out] - The adress where a pointer to newly allocated memory
|
|
|
|
* holding the result will be stored upon completion.
|
2011-08-22 10:42:59 -04:00
|
|
|
*
|
|
|
|
* Returns CURLE_OK on success.
|
|
|
|
*/
|
http NTLM: split http_ntlm.[ch] between http_ntlm.[ch] and curl_ntlm.[ch]
For modularity purposes, huge chunks of NTLM existing code is transformed into
functions to allow future internal code reuse.
Resulting three new libcurl private functions:
- Curl_ntlm_create_type1_message()
- Curl_ntlm_create_type3_message()
- Curl_ntlm_decode_type2_message()
Changing static ntlm_sspi_cleanup() into non-static Curl_ntlm_sspi_cleanup()
This 'refactoring' has been prepared by previous commits to allow that this
specific one does not introduce any change to existing code. All existing
goodness and badness previous to this commit should remain the same once it is
applied, the only difference should be that existing code is moved into
functions.
Given the quite big portions of code being moved around, and the importance of
change traceability, this commit has been done in such a way that it is
possible to perform a three-way diff from initial http_ntlm.[ch] to resulting
http_ntlm.[ch] and curl_ntlm.[ch] to actually verify that no functional change
is introduced here.
Notice that Steve Holme has provided several patches, but these included this
refactoring along with 'extra' fixes. I really wanted this 'clean' refactoring
done first, in order to allow discussion or committing of 'extra' fixes on a
case by case basis, so, I had to bite the bullet ;-)
Comments, line adjustments, compiler warning fixes, whatever, may follow
afterwards.
2011-08-14 09:45:19 -04:00
|
|
|
CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data,
|
|
|
|
const char *userp,
|
|
|
|
const char *passwdp,
|
|
|
|
struct ntlmdata *ntlm,
|
2011-08-25 09:09:30 -04:00
|
|
|
char **outptr)
|
http NTLM: split http_ntlm.[ch] between http_ntlm.[ch] and curl_ntlm.[ch]
For modularity purposes, huge chunks of NTLM existing code is transformed into
functions to allow future internal code reuse.
Resulting three new libcurl private functions:
- Curl_ntlm_create_type1_message()
- Curl_ntlm_create_type3_message()
- Curl_ntlm_decode_type2_message()
Changing static ntlm_sspi_cleanup() into non-static Curl_ntlm_sspi_cleanup()
This 'refactoring' has been prepared by previous commits to allow that this
specific one does not introduce any change to existing code. All existing
goodness and badness previous to this commit should remain the same once it is
applied, the only difference should be that existing code is moved into
functions.
Given the quite big portions of code being moved around, and the importance of
change traceability, this commit has been done in such a way that it is
possible to perform a three-way diff from initial http_ntlm.[ch] to resulting
http_ntlm.[ch] and curl_ntlm.[ch] to actually verify that no functional change
is introduced here.
Notice that Steve Holme has provided several patches, but these included this
refactoring along with 'extra' fixes. I really wanted this 'clean' refactoring
done first, in order to allow discussion or committing of 'extra' fixes on a
case by case basis, so, I had to bite the bullet ;-)
Comments, line adjustments, compiler warning fixes, whatever, may follow
afterwards.
2011-08-14 09:45:19 -04:00
|
|
|
{
|
|
|
|
/* 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 Target 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
|
|
|
|
*/
|
|
|
|
|
2011-08-25 09:09:30 -04:00
|
|
|
unsigned char ntlmbuf[NTLM_BUFSIZE];
|
|
|
|
size_t base64_sz = 0;
|
http NTLM: split http_ntlm.[ch] between http_ntlm.[ch] and curl_ntlm.[ch]
For modularity purposes, huge chunks of NTLM existing code is transformed into
functions to allow future internal code reuse.
Resulting three new libcurl private functions:
- Curl_ntlm_create_type1_message()
- Curl_ntlm_create_type3_message()
- Curl_ntlm_decode_type2_message()
Changing static ntlm_sspi_cleanup() into non-static Curl_ntlm_sspi_cleanup()
This 'refactoring' has been prepared by previous commits to allow that this
specific one does not introduce any change to existing code. All existing
goodness and badness previous to this commit should remain the same once it is
applied, the only difference should be that existing code is moved into
functions.
Given the quite big portions of code being moved around, and the importance of
change traceability, this commit has been done in such a way that it is
possible to perform a three-way diff from initial http_ntlm.[ch] to resulting
http_ntlm.[ch] and curl_ntlm.[ch] to actually verify that no functional change
is introduced here.
Notice that Steve Holme has provided several patches, but these included this
refactoring along with 'extra' fixes. I really wanted this 'clean' refactoring
done first, in order to allow discussion or committing of 'extra' fixes on a
case by case basis, so, I had to bite the bullet ;-)
Comments, line adjustments, compiler warning fixes, whatever, may follow
afterwards.
2011-08-14 09:45:19 -04:00
|
|
|
size_t size;
|
|
|
|
|
|
|
|
#ifdef USE_WINDOWS_SSPI
|
|
|
|
const char *dest = "";
|
|
|
|
SecBuffer type_2;
|
|
|
|
SecBuffer type_3;
|
|
|
|
SecBufferDesc type_2_desc;
|
|
|
|
SecBufferDesc type_3_desc;
|
|
|
|
SECURITY_STATUS status;
|
|
|
|
ULONG attrs;
|
|
|
|
TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
|
|
|
|
|
2011-08-14 10:36:47 -04:00
|
|
|
(void)passwdp;
|
|
|
|
(void)userp;
|
|
|
|
(void)data;
|
|
|
|
|
http NTLM: split http_ntlm.[ch] between http_ntlm.[ch] and curl_ntlm.[ch]
For modularity purposes, huge chunks of NTLM existing code is transformed into
functions to allow future internal code reuse.
Resulting three new libcurl private functions:
- Curl_ntlm_create_type1_message()
- Curl_ntlm_create_type3_message()
- Curl_ntlm_decode_type2_message()
Changing static ntlm_sspi_cleanup() into non-static Curl_ntlm_sspi_cleanup()
This 'refactoring' has been prepared by previous commits to allow that this
specific one does not introduce any change to existing code. All existing
goodness and badness previous to this commit should remain the same once it is
applied, the only difference should be that existing code is moved into
functions.
Given the quite big portions of code being moved around, and the importance of
change traceability, this commit has been done in such a way that it is
possible to perform a three-way diff from initial http_ntlm.[ch] to resulting
http_ntlm.[ch] and curl_ntlm.[ch] to actually verify that no functional change
is introduced here.
Notice that Steve Holme has provided several patches, but these included this
refactoring along with 'extra' fixes. I really wanted this 'clean' refactoring
done first, in order to allow discussion or committing of 'extra' fixes on a
case by case basis, so, I had to bite the bullet ;-)
Comments, line adjustments, compiler warning fixes, whatever, may follow
afterwards.
2011-08-14 09:45:19 -04:00
|
|
|
type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION;
|
|
|
|
type_2_desc.cBuffers = type_3_desc.cBuffers = 1;
|
|
|
|
type_2_desc.pBuffers = &type_2;
|
|
|
|
type_3_desc.pBuffers = &type_3;
|
|
|
|
|
|
|
|
type_2.BufferType = SECBUFFER_TOKEN;
|
|
|
|
type_2.pvBuffer = ntlm->type_2;
|
|
|
|
type_2.cbBuffer = ntlm->n_type_2;
|
|
|
|
type_3.BufferType = SECBUFFER_TOKEN;
|
|
|
|
type_3.pvBuffer = ntlmbuf;
|
|
|
|
type_3.cbBuffer = NTLM_BUFSIZE;
|
|
|
|
|
|
|
|
status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle,
|
|
|
|
&ntlm->c_handle,
|
|
|
|
(void *)dest,
|
|
|
|
ISC_REQ_CONFIDENTIALITY |
|
|
|
|
ISC_REQ_REPLAY_DETECT |
|
|
|
|
ISC_REQ_CONNECTION,
|
|
|
|
0, SECURITY_NETWORK_DREP,
|
|
|
|
&type_2_desc,
|
|
|
|
0, &ntlm->c_handle,
|
|
|
|
&type_3_desc,
|
|
|
|
&attrs, &tsDummy);
|
|
|
|
if(status != SEC_E_OK)
|
|
|
|
return CURLE_RECV_ERROR;
|
|
|
|
|
|
|
|
size = type_3.cbBuffer;
|
|
|
|
|
|
|
|
Curl_ntlm_sspi_cleanup(ntlm);
|
|
|
|
|
|
|
|
#else
|
|
|
|
int lmrespoff;
|
|
|
|
unsigned char lmresp[24]; /* fixed-size */
|
|
|
|
#if USE_NTRESPONSES
|
|
|
|
int ntrespoff;
|
|
|
|
unsigned char ntresp[24]; /* fixed-size */
|
|
|
|
#endif
|
|
|
|
bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
|
|
|
|
char host[HOSTNAME_MAX + 1] = "";
|
|
|
|
const char *user;
|
|
|
|
const char *domain = "";
|
|
|
|
size_t hostoff = 0;
|
|
|
|
size_t useroff = 0;
|
|
|
|
size_t domoff = 0;
|
|
|
|
size_t hostlen = 0;
|
|
|
|
size_t userlen = 0;
|
|
|
|
size_t domlen = 0;
|
|
|
|
CURLcode res;
|
|
|
|
|
|
|
|
user = strchr(userp, '\\');
|
|
|
|
if(!user)
|
|
|
|
user = strchr(userp, '/');
|
|
|
|
|
|
|
|
if(user) {
|
|
|
|
domain = userp;
|
|
|
|
domlen = (user - domain);
|
|
|
|
user++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
user = userp;
|
|
|
|
|
|
|
|
if(user)
|
|
|
|
userlen = strlen(user);
|
|
|
|
|
|
|
|
if(Curl_gethostname(host, HOSTNAME_MAX)) {
|
|
|
|
infof(data, "gethostname() failed, continuing without!");
|
|
|
|
hostlen = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* If the workstation if configured with a full DNS name (i.e.
|
|
|
|
* workstation.somewhere.net) gethostname() returns the fully qualified
|
|
|
|
* name, which NTLM doesn't like.
|
|
|
|
*/
|
|
|
|
char *dot = strchr(host, '.');
|
|
|
|
if(dot)
|
|
|
|
*dot = '\0';
|
|
|
|
hostlen = strlen(host);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(unicode) {
|
|
|
|
domlen = domlen * 2;
|
|
|
|
userlen = userlen * 2;
|
|
|
|
hostlen = hostlen * 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if USE_NTLM2SESSION
|
|
|
|
/* We don't support NTLM2 if we don't have USE_NTRESPONSES */
|
|
|
|
if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
|
|
|
|
unsigned char ntbuffer[0x18];
|
|
|
|
unsigned char tmp[0x18];
|
|
|
|
unsigned char md5sum[MD5_DIGEST_LENGTH];
|
|
|
|
unsigned char entropy[8];
|
|
|
|
|
|
|
|
/* Need to create 8 bytes random data */
|
|
|
|
#ifdef USE_SSLEAY
|
|
|
|
MD5_CTX MD5pw;
|
|
|
|
Curl_ossl_seed(data); /* Initiate the seed if not already done */
|
|
|
|
RAND_bytes(entropy, 8);
|
|
|
|
#elif defined(USE_GNUTLS)
|
|
|
|
gcry_md_hd_t MD5pw;
|
|
|
|
Curl_gtls_seed(data); /* Initiate the seed if not already done */
|
|
|
|
gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM);
|
|
|
|
#elif defined(USE_NSS)
|
|
|
|
PK11Context *MD5pw;
|
|
|
|
unsigned int outlen;
|
|
|
|
Curl_nss_seed(data); /* Initiate the seed if not already done */
|
|
|
|
PK11_GenerateRandom(entropy, 8);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* 8 bytes random data as challenge in lmresp */
|
|
|
|
memcpy(lmresp, entropy, 8);
|
|
|
|
|
|
|
|
/* Pad with zeros */
|
|
|
|
memset(lmresp + 8, 0, 0x10);
|
|
|
|
|
|
|
|
/* Fill tmp with challenge(nonce?) + entropy */
|
|
|
|
memcpy(tmp, &ntlm->nonce[0], 8);
|
|
|
|
memcpy(tmp + 8, entropy, 8);
|
|
|
|
|
|
|
|
#ifdef USE_SSLEAY
|
|
|
|
MD5_Init(&MD5pw);
|
|
|
|
MD5_Update(&MD5pw, tmp, 16);
|
|
|
|
MD5_Final(md5sum, &MD5pw);
|
|
|
|
#elif defined(USE_GNUTLS)
|
|
|
|
gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
|
|
|
|
gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH);
|
|
|
|
memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH);
|
|
|
|
gcry_md_close(MD5pw);
|
|
|
|
#elif defined(USE_NSS)
|
|
|
|
MD5pw = PK11_CreateDigestContext(SEC_OID_MD5);
|
|
|
|
PK11_DigestOp(MD5pw, tmp, 16);
|
|
|
|
PK11_DigestFinal(MD5pw, md5sum, &outlen, MD5_DIGEST_LENGTH);
|
|
|
|
PK11_DestroyContext(MD5pw, PR_TRUE);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* We shall only use the first 8 bytes of md5sum,
|
|
|
|
but the des code in lm_resp only encrypt the first 8 bytes */
|
|
|
|
if(mk_nt_hash(data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY)
|
|
|
|
return CURLE_OUT_OF_MEMORY;
|
|
|
|
lm_resp(ntbuffer, md5sum, ntresp);
|
|
|
|
|
|
|
|
/* End of NTLM2 Session code */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
|
|
|
|
#if USE_NTRESPONSES
|
|
|
|
unsigned char ntbuffer[0x18];
|
|
|
|
#endif
|
|
|
|
unsigned char lmbuffer[0x18];
|
|
|
|
|
|
|
|
#if USE_NTRESPONSES
|
|
|
|
if(mk_nt_hash(data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY)
|
|
|
|
return CURLE_OUT_OF_MEMORY;
|
|
|
|
lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
mk_lm_hash(data, passwdp, lmbuffer);
|
|
|
|
lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
|
|
|
|
/* A safer but less compatible alternative is:
|
|
|
|
* lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
|
|
|
|
* See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
|
|
|
|
}
|
|
|
|
|
|
|
|
lmrespoff = 64; /* size of the message header */
|
|
|
|
#if USE_NTRESPONSES
|
|
|
|
ntrespoff = lmrespoff + 0x18;
|
|
|
|
domoff = ntrespoff + 0x18;
|
|
|
|
#else
|
|
|
|
domoff = lmrespoff + 0x18;
|
|
|
|
#endif
|
|
|
|
useroff = domoff + domlen;
|
|
|
|
hostoff = useroff + userlen;
|
|
|
|
|
|
|
|
/* Create the big type-3 message binary blob */
|
|
|
|
size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
|
|
|
|
NTLMSSP_SIGNATURE "%c"
|
|
|
|
"\x03%c%c%c" /* 32-bit type = 3 */
|
|
|
|
|
|
|
|
"%c%c" /* LanManager length */
|
|
|
|
"%c%c" /* LanManager allocated space */
|
|
|
|
"%c%c" /* LanManager offset */
|
|
|
|
"%c%c" /* 2 zeroes */
|
|
|
|
|
|
|
|
"%c%c" /* NT-response length */
|
|
|
|
"%c%c" /* NT-response allocated space */
|
|
|
|
"%c%c" /* NT-response offset */
|
|
|
|
"%c%c" /* 2 zeroes */
|
|
|
|
|
|
|
|
"%c%c" /* domain length */
|
|
|
|
"%c%c" /* domain allocated space */
|
|
|
|
"%c%c" /* domain name offset */
|
|
|
|
"%c%c" /* 2 zeroes */
|
|
|
|
|
|
|
|
"%c%c" /* user length */
|
|
|
|
"%c%c" /* user allocated space */
|
|
|
|
"%c%c" /* user offset */
|
|
|
|
"%c%c" /* 2 zeroes */
|
|
|
|
|
|
|
|
"%c%c" /* host length */
|
|
|
|
"%c%c" /* host allocated space */
|
|
|
|
"%c%c" /* host offset */
|
|
|
|
"%c%c" /* 2 zeroes */
|
|
|
|
|
|
|
|
"%c%c" /* session key length (unknown purpose) */
|
|
|
|
"%c%c" /* session key allocated space (unknown purpose) */
|
|
|
|
"%c%c" /* session key offset (unknown purpose) */
|
|
|
|
"%c%c" /* 2 zeroes */
|
|
|
|
|
|
|
|
"%c%c%c%c", /* flags */
|
|
|
|
|
|
|
|
/* domain string */
|
|
|
|
/* user string */
|
|
|
|
/* host string */
|
|
|
|
/* LanManager response */
|
|
|
|
/* NT response */
|
|
|
|
|
|
|
|
0, /* zero termination */
|
|
|
|
0, 0, 0, /* type-3 long, the 24 upper bits */
|
|
|
|
|
|
|
|
SHORTPAIR(0x18), /* LanManager response length, twice */
|
|
|
|
SHORTPAIR(0x18),
|
|
|
|
SHORTPAIR(lmrespoff),
|
|
|
|
0x0, 0x0,
|
|
|
|
|
|
|
|
#if USE_NTRESPONSES
|
|
|
|
SHORTPAIR(0x18), /* NT-response length, twice */
|
|
|
|
SHORTPAIR(0x18),
|
|
|
|
SHORTPAIR(ntrespoff),
|
|
|
|
0x0, 0x0,
|
|
|
|
#else
|
|
|
|
0x0, 0x0,
|
|
|
|
0x0, 0x0,
|
|
|
|
0x0, 0x0,
|
|
|
|
0x0, 0x0,
|
|
|
|
#endif
|
|
|
|
SHORTPAIR(domlen),
|
|
|
|
SHORTPAIR(domlen),
|
|
|
|
SHORTPAIR(domoff),
|
|
|
|
0x0, 0x0,
|
|
|
|
|
|
|
|
SHORTPAIR(userlen),
|
|
|
|
SHORTPAIR(userlen),
|
|
|
|
SHORTPAIR(useroff),
|
|
|
|
0x0, 0x0,
|
|
|
|
|
|
|
|
SHORTPAIR(hostlen),
|
|
|
|
SHORTPAIR(hostlen),
|
|
|
|
SHORTPAIR(hostoff),
|
|
|
|
0x0, 0x0,
|
|
|
|
|
|
|
|
0x0, 0x0,
|
|
|
|
0x0, 0x0,
|
|
|
|
0x0, 0x0,
|
|
|
|
0x0, 0x0,
|
|
|
|
|
|
|
|
LONGQUARTET(ntlm->flags));
|
|
|
|
|
|
|
|
DEBUGASSERT(size == 64);
|
|
|
|
DEBUGASSERT(size == (size_t)lmrespoff);
|
|
|
|
|
|
|
|
/* We append the binary hashes */
|
|
|
|
if(size < (NTLM_BUFSIZE - 0x18)) {
|
|
|
|
memcpy(&ntlmbuf[size], lmresp, 0x18);
|
|
|
|
size += 0x18;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG_OUT({
|
|
|
|
fprintf(stderr, "**** TYPE3 header lmresp=");
|
|
|
|
ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
|
|
|
|
});
|
|
|
|
|
|
|
|
#if USE_NTRESPONSES
|
|
|
|
if(size < (NTLM_BUFSIZE - 0x18)) {
|
|
|
|
DEBUGASSERT(size == (size_t)ntrespoff);
|
|
|
|
memcpy(&ntlmbuf[size], ntresp, 0x18);
|
|
|
|
size += 0x18;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG_OUT({
|
|
|
|
fprintf(stderr, "\n ntresp=");
|
|
|
|
ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
|
|
|
|
});
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
DEBUG_OUT({
|
|
|
|
fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
|
|
|
|
LONGQUARTET(ntlm->flags), ntlm->flags);
|
|
|
|
ntlm_print_flags(stderr, ntlm->flags);
|
|
|
|
fprintf(stderr, "\n****\n");
|
|
|
|
});
|
|
|
|
|
|
|
|
/* Make sure that the domain, user and host strings fit in the
|
|
|
|
buffer before we copy them there. */
|
|
|
|
if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
|
|
|
|
failf(data, "user + domain + host name too big");
|
|
|
|
return CURLE_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUGASSERT(size == domoff);
|
|
|
|
if(unicode)
|
|
|
|
unicodecpy(&ntlmbuf[size], domain, domlen / 2);
|
|
|
|
else
|
|
|
|
memcpy(&ntlmbuf[size], domain, domlen);
|
|
|
|
|
|
|
|
size += domlen;
|
|
|
|
|
|
|
|
DEBUGASSERT(size == useroff);
|
|
|
|
if(unicode)
|
|
|
|
unicodecpy(&ntlmbuf[size], user, userlen / 2);
|
|
|
|
else
|
|
|
|
memcpy(&ntlmbuf[size], user, userlen);
|
|
|
|
|
|
|
|
size += userlen;
|
|
|
|
|
|
|
|
DEBUGASSERT(size == hostoff);
|
|
|
|
if(unicode)
|
|
|
|
unicodecpy(&ntlmbuf[size], host, hostlen / 2);
|
|
|
|
else
|
|
|
|
memcpy(&ntlmbuf[size], host, hostlen);
|
|
|
|
|
|
|
|
size += hostlen;
|
|
|
|
|
|
|
|
/* Convert domain, user, and host to ASCII but leave the rest as-is */
|
|
|
|
res = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff],
|
|
|
|
size - domoff);
|
|
|
|
if(res)
|
|
|
|
return CURLE_CONV_FAILED;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2011-08-25 09:09:30 -04:00
|
|
|
/* Return with binary blob encoded into base64 */
|
|
|
|
return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, &base64_sz);
|
http NTLM: split http_ntlm.[ch] between http_ntlm.[ch] and curl_ntlm.[ch]
For modularity purposes, huge chunks of NTLM existing code is transformed into
functions to allow future internal code reuse.
Resulting three new libcurl private functions:
- Curl_ntlm_create_type1_message()
- Curl_ntlm_create_type3_message()
- Curl_ntlm_decode_type2_message()
Changing static ntlm_sspi_cleanup() into non-static Curl_ntlm_sspi_cleanup()
This 'refactoring' has been prepared by previous commits to allow that this
specific one does not introduce any change to existing code. All existing
goodness and badness previous to this commit should remain the same once it is
applied, the only difference should be that existing code is moved into
functions.
Given the quite big portions of code being moved around, and the importance of
change traceability, this commit has been done in such a way that it is
possible to perform a three-way diff from initial http_ntlm.[ch] to resulting
http_ntlm.[ch] and curl_ntlm.[ch] to actually verify that no functional change
is introduced here.
Notice that Steve Holme has provided several patches, but these included this
refactoring along with 'extra' fixes. I really wanted this 'clean' refactoring
done first, in order to allow discussion or committing of 'extra' fixes on a
case by case basis, so, I had to bite the bullet ;-)
Comments, line adjustments, compiler warning fixes, whatever, may follow
afterwards.
2011-08-14 09:45:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* USE_NTLM */
|
|
|
|
#endif /* !CURL_DISABLE_HTTP */
|