~ubuntu-branches/ubuntu/saucy/curl/saucy-security

« back to all changes in this revision

Viewing changes to lib/curl_ntlm_msgs.c

  • Committer: Package Import Robot
  • Author(s): Timo Aaltonen
  • Date: 2011-11-25 17:30:45 UTC
  • mfrom: (3.4.23 sid)
  • Revision ID: package-import@ubuntu.com-20111125173045-2l3ni88jv16kath0
Tags: 7.22.0-3ubuntu1
* Merge from Debian unstable, remaining changes:
  - Drop dependencies not in main:
    + Build-Depends: Drop stunnel4 and libssh2-1-dev.
    + Drop libssh2-1-dev from libcurl4-openssl-dev's Depends.
  - Add new libcurl3-udeb package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *                                  _   _ ____  _
 
3
 *  Project                     ___| | | |  _ \| |
 
4
 *                             / __| | | | |_) | |
 
5
 *                            | (__| |_| |  _ <| |___
 
6
 *                             \___|\___/|_| \_\_____|
 
7
 *
 
8
 * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
 
9
 *
 
10
 * This software is licensed as described in the file COPYING, which
 
11
 * you should have received as part of this distribution. The terms
 
12
 * are also available at http://curl.haxx.se/docs/copyright.html.
 
13
 *
 
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 
15
 * copies of the Software, and permit persons to whom the Software is
 
16
 * furnished to do so, under the terms of the COPYING file.
 
17
 *
 
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 
19
 * KIND, either express or implied.
 
20
 *
 
21
 ***************************************************************************/
 
22
 
 
23
#include "setup.h"
 
24
 
 
25
#ifdef USE_NTLM
 
26
 
 
27
/*
 
28
 * NTLM details:
 
29
 *
 
30
 * http://davenport.sourceforge.net/ntlm.html
 
31
 * http://www.innovation.ch/java/ntlm.html
 
32
 */
 
33
 
 
34
#define DEBUG_ME 0
 
35
 
 
36
#ifdef USE_SSLEAY
 
37
 
 
38
#  ifdef USE_OPENSSL
 
39
#    include <openssl/des.h>
 
40
#    ifndef OPENSSL_NO_MD4
 
41
#      include <openssl/md4.h>
 
42
#    endif
 
43
#    include <openssl/md5.h>
 
44
#    include <openssl/ssl.h>
 
45
#    include <openssl/rand.h>
 
46
#  else
 
47
#    include <des.h>
 
48
#    ifndef OPENSSL_NO_MD4
 
49
#      include <md4.h>
 
50
#    endif
 
51
#    include <md5.h>
 
52
#    include <ssl.h>
 
53
#    include <rand.h>
 
54
#  endif
 
55
#  include "ssluse.h"
 
56
 
 
57
#elif defined(USE_GNUTLS)
 
58
 
 
59
#  include <gcrypt.h>
 
60
#  include "gtls.h"
 
61
#  define MD5_DIGEST_LENGTH 16
 
62
#  define MD4_DIGEST_LENGTH 16
 
63
 
 
64
#elif defined(USE_NSS)
 
65
 
 
66
#  include <nss.h>
 
67
#  include <pk11pub.h>
 
68
#  include <hasht.h>
 
69
#  include "nssg.h"
 
70
#  include "curl_md4.h"
 
71
#  define MD5_DIGEST_LENGTH MD5_LENGTH
 
72
 
 
73
#elif defined(USE_WINDOWS_SSPI)
 
74
#  include "curl_sspi.h"
 
75
#else
 
76
#  error "Can't compile NTLM support without a crypto library."
 
77
#endif
 
78
 
 
79
#include "urldata.h"
 
80
#include "non-ascii.h"
 
81
#include "sendf.h"
 
82
#include "curl_base64.h"
 
83
#include "curl_ntlm_core.h"
 
84
#include "curl_gethostname.h"
 
85
#include "curl_memory.h"
 
86
 
 
87
#define BUILDING_CURL_NTLM_MSGS_C
 
88
#include "curl_ntlm_msgs.h"
 
89
 
 
90
#define _MPRINTF_REPLACE /* use our functions only */
 
91
#include <curl/mprintf.h>
 
92
 
 
93
/* The last #include file should be: */
 
94
#include "memdebug.h"
 
95
 
 
96
/* Hostname buffer size */
 
97
#define HOSTNAME_MAX 1024
 
98
 
 
99
/* "NTLMSSP" signature is always in ASCII regardless of the platform */
 
100
#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
 
101
 
 
102
#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
 
103
#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8) & 0xff), \
 
104
  (((x) >> 16) & 0xff), (((x) >> 24) & 0xff)
 
105
 
 
106
#if DEBUG_ME
 
107
# define DEBUG_OUT(x) x
 
108
static void ntlm_print_flags(FILE *handle, unsigned long flags)
 
109
{
 
110
  if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
 
111
    fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
 
112
  if(flags & NTLMFLAG_NEGOTIATE_OEM)
 
113
    fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
 
114
  if(flags & NTLMFLAG_REQUEST_TARGET)
 
115
    fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
 
116
  if(flags & (1<<3))
 
117
    fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
 
118
  if(flags & NTLMFLAG_NEGOTIATE_SIGN)
 
119
    fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
 
120
  if(flags & NTLMFLAG_NEGOTIATE_SEAL)
 
121
    fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
 
122
  if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
 
123
    fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
 
124
  if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
 
125
    fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
 
126
  if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
 
127
    fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
 
128
  if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
 
129
    fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
 
130
  if(flags & (1<<10))
 
131
    fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
 
132
  if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
 
133
    fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
 
134
  if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
 
135
    fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
 
136
  if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
 
137
    fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
 
138
  if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
 
139
    fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
 
140
  if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
 
141
    fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
 
142
  if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
 
143
    fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
 
144
  if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
 
145
    fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
 
146
  if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
 
147
    fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
 
148
  if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
 
149
    fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
 
150
  if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
 
151
    fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
 
152
  if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
 
153
    fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
 
154
  if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
 
155
    fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
 
156
  if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
 
157
    fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
 
158
  if(flags & (1<<24))
 
159
    fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
 
160
  if(flags & (1<<25))
 
161
    fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
 
162
  if(flags & (1<<26))
 
163
    fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
 
164
  if(flags & (1<<27))
 
165
    fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
 
166
  if(flags & (1<<28))
 
167
    fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
 
168
  if(flags & NTLMFLAG_NEGOTIATE_128)
 
169
    fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
 
170
  if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
 
171
    fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
 
172
  if(flags & NTLMFLAG_NEGOTIATE_56)
 
173
    fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
 
174
}
 
175
 
 
176
static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
 
177
{
 
178
  const char *p = buf;
 
179
  (void)handle;
 
180
  fprintf(stderr, "0x");
 
181
  while(len-- > 0)
 
182
    fprintf(stderr, "%02.2x", (unsigned int)*p++);
 
183
}
 
184
#else
 
185
# define DEBUG_OUT(x) Curl_nop_stmt
 
186
#endif
 
187
 
 
188
#ifndef USE_WINDOWS_SSPI
 
189
/*
 
190
 * This function converts from the little endian format used in the
 
191
 * incoming package to whatever endian format we're using natively.
 
192
 * Argument is a pointer to a 4 byte buffer.
 
193
 */
 
194
static unsigned int readint_le(unsigned char *buf)
 
195
{
 
196
  return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
 
197
    ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
 
198
}
 
199
#endif
 
200
 
 
201
/*
 
202
  NTLM message structure notes:
 
203
 
 
204
  A 'short' is a 'network short', a little-endian 16-bit unsigned value.
 
205
 
 
206
  A 'long' is a 'network long', a little-endian, 32-bit unsigned value.
 
207
 
 
208
  A 'security buffer' represents a triplet used to point to a buffer,
 
209
  consisting of two shorts and one long:
 
210
 
 
211
    1. A 'short' containing the length of the buffer content in bytes.
 
212
    2. A 'short' containing the allocated space for the buffer in bytes.
 
213
    3. A 'long' containing the offset to the start of the buffer in bytes,
 
214
       from the beginning of the NTLM message.
 
215
*/
 
216
 
 
217
/*
 
218
 * Curl_ntlm_decode_type2_message()
 
219
 *
 
220
 * This is used to decode a ntlm type-2 message received from a: HTTP, SMTP
 
221
 * or POP3 server. The message is first decoded from a base64 string into a
 
222
 * raw ntlm message and checked for validity before the appropriate data for
 
223
 * creating a type-3 message is written to the given ntlm data structure.
 
224
 *
 
225
 * Parameters:
 
226
 *
 
227
 * data    [in]     - Pointer to session handle.
 
228
 * header  [in]     - Pointer to the input buffer.
 
229
 * ntlm    [in]     - Pointer to ntlm data struct being used and modified.
 
230
 *
 
231
 * Returns CURLE_OK on success.
 
232
 */
 
233
CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data,
 
234
                                        const char* header,
 
235
                                        struct ntlmdata* ntlm)
 
236
{
 
237
#ifndef USE_WINDOWS_SSPI
 
238
  static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
 
239
#endif
 
240
 
 
241
  /* NTLM type-2 message structure:
 
242
 
 
243
          Index  Description            Content
 
244
            0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
 
245
                                        (0x4e544c4d53535000)
 
246
            8    NTLM Message Type      long (0x02000000)
 
247
           12    Target Name            security buffer
 
248
           20    Flags                  long
 
249
           24    Challenge              8 bytes
 
250
          (32)   Context                8 bytes (two consecutive longs) (*)
 
251
          (40)   Target Information     security buffer (*)
 
252
          (48)   OS Version Structure   8 bytes (*)
 
253
  32 (48) (56)   Start of data block    (*)
 
254
                                        (*) -> Optional
 
255
  */
 
256
 
 
257
  size_t size = 0;
 
258
  unsigned char *buffer = NULL;
 
259
  CURLcode error;
 
260
 
 
261
#if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI)
 
262
  (void)data;
 
263
#endif
 
264
 
 
265
  error = Curl_base64_decode(header, &buffer, &size);
 
266
  if(error)
 
267
    return error;
 
268
 
 
269
  if(!buffer) {
 
270
    infof(data, "NTLM handshake failure (unhandled condition)\n");
 
271
    return CURLE_REMOTE_ACCESS_DENIED;
 
272
  }
 
273
 
 
274
#ifdef USE_WINDOWS_SSPI
 
275
  ntlm->type_2 = malloc(size + 1);
 
276
  if(ntlm->type_2 == NULL) {
 
277
    free(buffer);
 
278
    return CURLE_OUT_OF_MEMORY;
 
279
  }
 
280
  ntlm->n_type_2 = (unsigned long)size;
 
281
  memcpy(ntlm->type_2, buffer, size);
 
282
#else
 
283
  ntlm->flags = 0;
 
284
 
 
285
  if((size < 32) ||
 
286
     (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) ||
 
287
     (memcmp(buffer + 8, type2_marker, sizeof(type2_marker)) != 0)) {
 
288
    /* This was not a good enough type-2 message */
 
289
    free(buffer);
 
290
    infof(data, "NTLM handshake failure (bad type-2 message)\n");
 
291
    return CURLE_REMOTE_ACCESS_DENIED;
 
292
  }
 
293
 
 
294
  ntlm->flags = readint_le(&buffer[20]);
 
295
  memcpy(ntlm->nonce, &buffer[24], 8);
 
296
 
 
297
  DEBUG_OUT({
 
298
    fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
 
299
    ntlm_print_flags(stderr, ntlm->flags);
 
300
    fprintf(stderr, "\n                  nonce=");
 
301
    ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
 
302
    fprintf(stderr, "\n****\n");
 
303
    fprintf(stderr, "**** Header %s\n ", header);
 
304
  });
 
305
#endif
 
306
  free(buffer);
 
307
 
 
308
  return CURLE_OK;
 
309
}
 
310
 
 
311
#ifdef USE_WINDOWS_SSPI
 
312
void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm)
 
313
{
 
314
  if(ntlm->type_2) {
 
315
    free(ntlm->type_2);
 
316
    ntlm->type_2 = NULL;
 
317
  }
 
318
  if(ntlm->has_handles) {
 
319
    s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
 
320
    s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
 
321
    ntlm->has_handles = 0;
 
322
  }
 
323
  if(ntlm->p_identity) {
 
324
    if(ntlm->identity.User) free(ntlm->identity.User);
 
325
    if(ntlm->identity.Password) free(ntlm->identity.Password);
 
326
    if(ntlm->identity.Domain) free(ntlm->identity.Domain);
 
327
    ntlm->p_identity = NULL;
 
328
  }
 
329
}
 
330
#endif
 
331
 
 
332
#ifndef USE_WINDOWS_SSPI
 
333
/* copy the source to the destination and fill in zeroes in every
 
334
   other destination byte! */
 
335
static void unicodecpy(unsigned char *dest,
 
336
                       const char *src, size_t length)
 
337
{
 
338
  size_t i;
 
339
  for(i = 0; i < length; i++) {
 
340
    dest[2 * i] = (unsigned char)src[i];
 
341
    dest[2 * i + 1] = '\0';
 
342
  }
 
343
}
 
344
#endif
 
345
 
 
346
/*
 
347
 * Curl_ntlm_create_type1_message()
 
348
 *
 
349
 * This is used to generate an already encoded NTLM type-1 message ready
 
350
 * for sending to the recipient, be it a: HTTP, SMTP or POP3 server,
 
351
 * using the appropriate compile time crypo API.
 
352
 *
 
353
 * Parameters:
 
354
 *
 
355
 * userp   [in]     - The user name in the format User or Domain\User.
 
356
 * passdwp [in]     - The user's password.
 
357
 * ntlm    [in/out] - The ntlm data struct being used and modified.
 
358
 * outptr  [in/out] - The adress where a pointer to newly allocated memory
 
359
 *                    holding the result will be stored upon completion.
 
360
 *
 
361
 * Returns CURLE_OK on success.
 
362
 */
 
363
CURLcode Curl_ntlm_create_type1_message(const char *userp,
 
364
                                        const char *passwdp,
 
365
                                        struct ntlmdata *ntlm,
 
366
                                        char **outptr)
 
367
{
 
368
  /* NTLM type-1 message structure:
 
369
 
 
370
       Index  Description            Content
 
371
         0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
 
372
                                     (0x4e544c4d53535000)
 
373
         8    NTLM Message Type      long (0x01000000)
 
374
        12    Flags                  long
 
375
       (16)   Supplied Domain        security buffer (*)
 
376
       (24)   Supplied Workstation   security buffer (*)
 
377
       (32)   OS Version Structure   8 bytes (*)
 
378
  (32) (40)   Start of data block    (*)
 
379
                                     (*) -> Optional
 
380
  */
 
381
 
 
382
  unsigned char ntlmbuf[NTLM_BUFSIZE];
 
383
  size_t base64_sz = 0;
 
384
  size_t size;
 
385
 
 
386
#ifdef USE_WINDOWS_SSPI
 
387
 
 
388
  SecBuffer buf;
 
389
  SecBufferDesc desc;
 
390
  SECURITY_STATUS status;
 
391
  ULONG attrs;
 
392
  const char *dest = "";
 
393
  const char *user;
 
394
  const char *domain = "";
 
395
  size_t userlen = 0;
 
396
  size_t domlen = 0;
 
397
  size_t passwdlen = 0;
 
398
  TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
 
399
 
 
400
  Curl_ntlm_sspi_cleanup(ntlm);
 
401
 
 
402
  user = strchr(userp, '\\');
 
403
  if(!user)
 
404
    user = strchr(userp, '/');
 
405
 
 
406
  if(user) {
 
407
    domain = userp;
 
408
    domlen = user - userp;
 
409
    user++;
 
410
  }
 
411
  else {
 
412
    user = userp;
 
413
    domain = "";
 
414
    domlen = 0;
 
415
  }
 
416
 
 
417
  if(user)
 
418
    userlen = strlen(user);
 
419
 
 
420
  if(passwdp)
 
421
    passwdlen = strlen(passwdp);
 
422
 
 
423
  if(userlen > 0) {
 
424
    /* note: initialize all of this before doing the mallocs so that
 
425
     * it can be cleaned up later without leaking memory.
 
426
     */
 
427
    ntlm->p_identity = &ntlm->identity;
 
428
    memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
 
429
    if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL)
 
430
      return CURLE_OUT_OF_MEMORY;
 
431
 
 
432
    ntlm->identity.UserLength = (unsigned long)userlen;
 
433
    if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL)
 
434
      return CURLE_OUT_OF_MEMORY;
 
435
 
 
436
    ntlm->identity.PasswordLength = (unsigned long)strlen(passwdp);
 
437
    if((ntlm->identity.Domain = malloc(domlen + 1)) == NULL)
 
438
      return CURLE_OUT_OF_MEMORY;
 
439
 
 
440
    strncpy((char *)ntlm->identity.Domain, domain, domlen);
 
441
    ntlm->identity.Domain[domlen] = '\0';
 
442
    ntlm->identity.DomainLength = (unsigned long)domlen;
 
443
    ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
 
444
  }
 
445
  else
 
446
    ntlm->p_identity = NULL;
 
447
 
 
448
  status = s_pSecFn->AcquireCredentialsHandleA(NULL, (void *)"NTLM",
 
449
                                               SECPKG_CRED_OUTBOUND, NULL,
 
450
                                               ntlm->p_identity, NULL, NULL,
 
451
                                               &ntlm->handle, &tsDummy);
 
452
  if(status != SEC_E_OK)
 
453
    return CURLE_OUT_OF_MEMORY;
 
454
 
 
455
  desc.ulVersion = SECBUFFER_VERSION;
 
456
  desc.cBuffers  = 1;
 
457
  desc.pBuffers  = &buf;
 
458
  buf.cbBuffer   = NTLM_BUFSIZE;
 
459
  buf.BufferType = SECBUFFER_TOKEN;
 
460
  buf.pvBuffer   = ntlmbuf;
 
461
 
 
462
  status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, NULL,
 
463
                                                (void *)dest,
 
464
                                                ISC_REQ_CONFIDENTIALITY |
 
465
                                                ISC_REQ_REPLAY_DETECT |
 
466
                                                ISC_REQ_CONNECTION,
 
467
                                                0, SECURITY_NETWORK_DREP,
 
468
                                                NULL, 0,
 
469
                                                &ntlm->c_handle, &desc,
 
470
                                                &attrs, &tsDummy);
 
471
 
 
472
  if(status == SEC_I_COMPLETE_AND_CONTINUE ||
 
473
     status == SEC_I_CONTINUE_NEEDED)
 
474
    s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc);
 
475
  else if(status != SEC_E_OK) {
 
476
    s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
 
477
    return CURLE_RECV_ERROR;
 
478
  }
 
479
 
 
480
  ntlm->has_handles = 1;
 
481
  size = buf.cbBuffer;
 
482
 
 
483
#else
 
484
 
 
485
  const char *host = "";              /* empty */
 
486
  const char *domain = "";            /* empty */
 
487
  size_t hostlen = 0;
 
488
  size_t domlen = 0;
 
489
  size_t hostoff = 0;
 
490
  size_t domoff = hostoff + hostlen;  /* This is 0: remember that host and
 
491
                                         domain are empty */
 
492
  (void)userp;
 
493
  (void)passwdp;
 
494
  (void)ntlm;
 
495
 
 
496
#if USE_NTLM2SESSION
 
497
#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
 
498
#else
 
499
#define NTLM2FLAG 0
 
500
#endif
 
501
  snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
 
502
           NTLMSSP_SIGNATURE "%c"
 
503
           "\x01%c%c%c" /* 32-bit type = 1 */
 
504
           "%c%c%c%c"   /* 32-bit NTLM flag field */
 
505
           "%c%c"       /* domain length */
 
506
           "%c%c"       /* domain allocated space */
 
507
           "%c%c"       /* domain name offset */
 
508
           "%c%c"       /* 2 zeroes */
 
509
           "%c%c"       /* host length */
 
510
           "%c%c"       /* host allocated space */
 
511
           "%c%c"       /* host name offset */
 
512
           "%c%c"       /* 2 zeroes */
 
513
           "%s"         /* host name */
 
514
           "%s",        /* domain string */
 
515
           0,           /* trailing zero */
 
516
           0, 0, 0,     /* part of type-1 long */
 
517
 
 
518
           LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
 
519
                       NTLMFLAG_REQUEST_TARGET |
 
520
                       NTLMFLAG_NEGOTIATE_NTLM_KEY |
 
521
                       NTLM2FLAG |
 
522
                       NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
 
523
           SHORTPAIR(domlen),
 
524
           SHORTPAIR(domlen),
 
525
           SHORTPAIR(domoff),
 
526
           0, 0,
 
527
           SHORTPAIR(hostlen),
 
528
           SHORTPAIR(hostlen),
 
529
           SHORTPAIR(hostoff),
 
530
           0, 0,
 
531
           host,  /* this is empty */
 
532
           domain /* this is empty */);
 
533
 
 
534
  /* Initial packet length */
 
535
  size = 32 + hostlen + domlen;
 
536
 
 
537
#endif
 
538
 
 
539
  DEBUG_OUT({
 
540
    fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x "
 
541
            "0x%08.8x ",
 
542
            LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
 
543
                        NTLMFLAG_REQUEST_TARGET |
 
544
                        NTLMFLAG_NEGOTIATE_NTLM_KEY |
 
545
                        NTLM2FLAG |
 
546
                        NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
 
547
            NTLMFLAG_NEGOTIATE_OEM |
 
548
            NTLMFLAG_REQUEST_TARGET |
 
549
            NTLMFLAG_NEGOTIATE_NTLM_KEY |
 
550
            NTLM2FLAG |
 
551
            NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
 
552
    ntlm_print_flags(stderr,
 
553
                     NTLMFLAG_NEGOTIATE_OEM |
 
554
                     NTLMFLAG_REQUEST_TARGET |
 
555
                     NTLMFLAG_NEGOTIATE_NTLM_KEY |
 
556
                     NTLM2FLAG |
 
557
                     NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
 
558
    fprintf(stderr, "\n****\n");
 
559
  });
 
560
 
 
561
  /* Return with binary blob encoded into base64 */
 
562
  return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, &base64_sz);
 
563
}
 
564
 
 
565
/*
 
566
 * Curl_ntlm_create_type3_message()
 
567
 *
 
568
 * This is used to generate an already encoded NTLM type-3 message ready
 
569
 * for sending to the recipient, be it a: HTTP, SMTP or POP3 server,
 
570
 * using the appropriate compile time crypo API.
 
571
 *
 
572
 * Parameters:
 
573
 *
 
574
 * data    [in]     - The session handle.
 
575
 * userp   [in]     - The user name in the format User or Domain\User.
 
576
 * passdwp [in]     - The user's password.
 
577
 * ntlm    [in/out] - The ntlm data struct being used and modified.
 
578
 * outptr  [in/out] - The adress where a pointer to newly allocated memory
 
579
 *                    holding the result will be stored upon completion.
 
580
 *
 
581
 * Returns CURLE_OK on success.
 
582
 */
 
583
CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data,
 
584
                                        const char *userp,
 
585
                                        const char *passwdp,
 
586
                                        struct ntlmdata *ntlm,
 
587
                                        char **outptr)
 
588
{
 
589
  /* NTLM type-3 message structure:
 
590
 
 
591
          Index  Description            Content
 
592
            0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
 
593
                                        (0x4e544c4d53535000)
 
594
            8    NTLM Message Type      long (0x03000000)
 
595
           12    LM/LMv2 Response       security buffer
 
596
           20    NTLM/NTLMv2 Response   security buffer
 
597
           28    Target Name            security buffer
 
598
           36    User Name              security buffer
 
599
           44    Workstation Name       security buffer
 
600
          (52)   Session Key            security buffer (*)
 
601
          (60)   Flags                  long (*)
 
602
          (64)   OS Version Structure   8 bytes (*)
 
603
  52 (64) (72)   Start of data block
 
604
                                          (*) -> Optional
 
605
  */
 
606
 
 
607
  unsigned char ntlmbuf[NTLM_BUFSIZE];
 
608
  size_t base64_sz = 0;
 
609
  size_t size;
 
610
 
 
611
#ifdef USE_WINDOWS_SSPI
 
612
  const char *dest = "";
 
613
  SecBuffer type_2;
 
614
  SecBuffer type_3;
 
615
  SecBufferDesc type_2_desc;
 
616
  SecBufferDesc type_3_desc;
 
617
  SECURITY_STATUS status;
 
618
  ULONG attrs;
 
619
  TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
 
620
 
 
621
  (void)passwdp;
 
622
  (void)userp;
 
623
  (void)data;
 
624
 
 
625
  type_2_desc.ulVersion = type_3_desc.ulVersion  = SECBUFFER_VERSION;
 
626
  type_2_desc.cBuffers  = type_3_desc.cBuffers   = 1;
 
627
  type_2_desc.pBuffers  = &type_2;
 
628
  type_3_desc.pBuffers  = &type_3;
 
629
 
 
630
  type_2.BufferType = SECBUFFER_TOKEN;
 
631
  type_2.pvBuffer   = ntlm->type_2;
 
632
  type_2.cbBuffer   = ntlm->n_type_2;
 
633
  type_3.BufferType = SECBUFFER_TOKEN;
 
634
  type_3.pvBuffer   = ntlmbuf;
 
635
  type_3.cbBuffer   = NTLM_BUFSIZE;
 
636
 
 
637
  status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle,
 
638
                                                &ntlm->c_handle,
 
639
                                                (void *)dest,
 
640
                                                ISC_REQ_CONFIDENTIALITY |
 
641
                                                ISC_REQ_REPLAY_DETECT |
 
642
                                                ISC_REQ_CONNECTION,
 
643
                                                0, SECURITY_NETWORK_DREP,
 
644
                                                &type_2_desc,
 
645
                                                0, &ntlm->c_handle,
 
646
                                                &type_3_desc,
 
647
                                                &attrs, &tsDummy);
 
648
  if(status != SEC_E_OK)
 
649
    return CURLE_RECV_ERROR;
 
650
 
 
651
  size = type_3.cbBuffer;
 
652
 
 
653
  Curl_ntlm_sspi_cleanup(ntlm);
 
654
 
 
655
#else
 
656
  int lmrespoff;
 
657
  unsigned char lmresp[24]; /* fixed-size */
 
658
#if USE_NTRESPONSES
 
659
  int ntrespoff;
 
660
  unsigned char ntresp[24]; /* fixed-size */
 
661
#endif
 
662
  bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
 
663
  char host[HOSTNAME_MAX + 1] = "";
 
664
  const char *user;
 
665
  const char *domain = "";
 
666
  size_t hostoff = 0;
 
667
  size_t useroff = 0;
 
668
  size_t domoff = 0;
 
669
  size_t hostlen = 0;
 
670
  size_t userlen = 0;
 
671
  size_t domlen = 0;
 
672
  CURLcode res;
 
673
 
 
674
  user = strchr(userp, '\\');
 
675
  if(!user)
 
676
    user = strchr(userp, '/');
 
677
 
 
678
  if(user) {
 
679
    domain = userp;
 
680
    domlen = (user - domain);
 
681
    user++;
 
682
  }
 
683
  else
 
684
    user = userp;
 
685
 
 
686
  if(user)
 
687
    userlen = strlen(user);
 
688
 
 
689
  if(Curl_gethostname(host, HOSTNAME_MAX)) {
 
690
    infof(data, "gethostname() failed, continuing without!");
 
691
    hostlen = 0;
 
692
  }
 
693
  else {
 
694
    /* If the workstation if configured with a full DNS name (i.e.
 
695
     * workstation.somewhere.net) gethostname() returns the fully qualified
 
696
     * name, which NTLM doesn't like.
 
697
     */
 
698
    char *dot = strchr(host, '.');
 
699
    if(dot)
 
700
      *dot = '\0';
 
701
    hostlen = strlen(host);
 
702
  }
 
703
 
 
704
  if(unicode) {
 
705
    domlen = domlen * 2;
 
706
    userlen = userlen * 2;
 
707
    hostlen = hostlen * 2;
 
708
  }
 
709
 
 
710
#if USE_NTLM2SESSION
 
711
  /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
 
712
  if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
 
713
    unsigned char ntbuffer[0x18];
 
714
    unsigned char tmp[0x18];
 
715
    unsigned char md5sum[MD5_DIGEST_LENGTH];
 
716
    unsigned char entropy[8];
 
717
 
 
718
    /* Need to create 8 bytes random data */
 
719
#ifdef USE_SSLEAY
 
720
    MD5_CTX MD5pw;
 
721
    Curl_ossl_seed(data); /* Initiate the seed if not already done */
 
722
    RAND_bytes(entropy, 8);
 
723
#elif defined(USE_GNUTLS)
 
724
    gcry_md_hd_t MD5pw;
 
725
    Curl_gtls_seed(data); /* Initiate the seed if not already done */
 
726
    gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM);
 
727
#elif defined(USE_NSS)
 
728
    PK11Context *MD5pw;
 
729
    unsigned int outlen;
 
730
    Curl_nss_seed(data);  /* Initiate the seed if not already done */
 
731
    PK11_GenerateRandom(entropy, 8);
 
732
#endif
 
733
 
 
734
    /* 8 bytes random data as challenge in lmresp */
 
735
    memcpy(lmresp, entropy, 8);
 
736
 
 
737
    /* Pad with zeros */
 
738
    memset(lmresp + 8, 0, 0x10);
 
739
 
 
740
    /* Fill tmp with challenge(nonce?) + entropy */
 
741
    memcpy(tmp, &ntlm->nonce[0], 8);
 
742
    memcpy(tmp + 8, entropy, 8);
 
743
 
 
744
#ifdef USE_SSLEAY
 
745
    MD5_Init(&MD5pw);
 
746
    MD5_Update(&MD5pw, tmp, 16);
 
747
    MD5_Final(md5sum, &MD5pw);
 
748
#elif defined(USE_GNUTLS)
 
749
    gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
 
750
    gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH);
 
751
    memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH);
 
752
    gcry_md_close(MD5pw);
 
753
#elif defined(USE_NSS)
 
754
    MD5pw = PK11_CreateDigestContext(SEC_OID_MD5);
 
755
    PK11_DigestOp(MD5pw, tmp, 16);
 
756
    PK11_DigestFinal(MD5pw, md5sum, &outlen, MD5_DIGEST_LENGTH);
 
757
    PK11_DestroyContext(MD5pw, PR_TRUE);
 
758
#endif
 
759
 
 
760
    /* We shall only use the first 8 bytes of md5sum, but the des
 
761
       code in Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */
 
762
    if(CURLE_OUT_OF_MEMORY ==
 
763
       Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer))
 
764
      return CURLE_OUT_OF_MEMORY;
 
765
    Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp);
 
766
 
 
767
    /* End of NTLM2 Session code */
 
768
  }
 
769
  else
 
770
#endif
 
771
  {
 
772
 
 
773
#if USE_NTRESPONSES
 
774
    unsigned char ntbuffer[0x18];
 
775
#endif
 
776
    unsigned char lmbuffer[0x18];
 
777
 
 
778
#if USE_NTRESPONSES
 
779
    if(CURLE_OUT_OF_MEMORY ==
 
780
       Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer))
 
781
      return CURLE_OUT_OF_MEMORY;
 
782
    Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
 
783
#endif
 
784
 
 
785
    Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer);
 
786
    Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
 
787
    /* A safer but less compatible alternative is:
 
788
     *   Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
 
789
     * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
 
790
  }
 
791
 
 
792
  lmrespoff = 64; /* size of the message header */
 
793
#if USE_NTRESPONSES
 
794
  ntrespoff = lmrespoff + 0x18;
 
795
  domoff = ntrespoff + 0x18;
 
796
#else
 
797
  domoff = lmrespoff + 0x18;
 
798
#endif
 
799
  useroff = domoff + domlen;
 
800
  hostoff = useroff + userlen;
 
801
 
 
802
  /* Create the big type-3 message binary blob */
 
803
  size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
 
804
                  NTLMSSP_SIGNATURE "%c"
 
805
                  "\x03%c%c%c"  /* 32-bit type = 3 */
 
806
 
 
807
                  "%c%c"  /* LanManager length */
 
808
                  "%c%c"  /* LanManager allocated space */
 
809
                  "%c%c"  /* LanManager offset */
 
810
                  "%c%c"  /* 2 zeroes */
 
811
 
 
812
                  "%c%c"  /* NT-response length */
 
813
                  "%c%c"  /* NT-response allocated space */
 
814
                  "%c%c"  /* NT-response offset */
 
815
                  "%c%c"  /* 2 zeroes */
 
816
 
 
817
                  "%c%c"  /* domain length */
 
818
                  "%c%c"  /* domain allocated space */
 
819
                  "%c%c"  /* domain name offset */
 
820
                  "%c%c"  /* 2 zeroes */
 
821
 
 
822
                  "%c%c"  /* user length */
 
823
                  "%c%c"  /* user allocated space */
 
824
                  "%c%c"  /* user offset */
 
825
                  "%c%c"  /* 2 zeroes */
 
826
 
 
827
                  "%c%c"  /* host length */
 
828
                  "%c%c"  /* host allocated space */
 
829
                  "%c%c"  /* host offset */
 
830
                  "%c%c"  /* 2 zeroes */
 
831
 
 
832
                  "%c%c"  /* session key length (unknown purpose) */
 
833
                  "%c%c"  /* session key allocated space (unknown purpose) */
 
834
                  "%c%c"  /* session key offset (unknown purpose) */
 
835
                  "%c%c"  /* 2 zeroes */
 
836
 
 
837
                  "%c%c%c%c",  /* flags */
 
838
 
 
839
                  /* domain string */
 
840
                  /* user string */
 
841
                  /* host string */
 
842
                  /* LanManager response */
 
843
                  /* NT response */
 
844
 
 
845
                  0,                /* zero termination */
 
846
                  0, 0, 0,          /* type-3 long, the 24 upper bits */
 
847
 
 
848
                  SHORTPAIR(0x18),  /* LanManager response length, twice */
 
849
                  SHORTPAIR(0x18),
 
850
                  SHORTPAIR(lmrespoff),
 
851
                  0x0, 0x0,
 
852
 
 
853
#if USE_NTRESPONSES
 
854
                  SHORTPAIR(0x18),  /* NT-response length, twice */
 
855
                  SHORTPAIR(0x18),
 
856
                  SHORTPAIR(ntrespoff),
 
857
                  0x0, 0x0,
 
858
#else
 
859
                  0x0, 0x0,
 
860
                  0x0, 0x0,
 
861
                  0x0, 0x0,
 
862
                  0x0, 0x0,
 
863
#endif
 
864
                  SHORTPAIR(domlen),
 
865
                  SHORTPAIR(domlen),
 
866
                  SHORTPAIR(domoff),
 
867
                  0x0, 0x0,
 
868
 
 
869
                  SHORTPAIR(userlen),
 
870
                  SHORTPAIR(userlen),
 
871
                  SHORTPAIR(useroff),
 
872
                  0x0, 0x0,
 
873
 
 
874
                  SHORTPAIR(hostlen),
 
875
                  SHORTPAIR(hostlen),
 
876
                  SHORTPAIR(hostoff),
 
877
                  0x0, 0x0,
 
878
 
 
879
                  0x0, 0x0,
 
880
                  0x0, 0x0,
 
881
                  0x0, 0x0,
 
882
                  0x0, 0x0,
 
883
 
 
884
                  LONGQUARTET(ntlm->flags));
 
885
 
 
886
  DEBUGASSERT(size == 64);
 
887
  DEBUGASSERT(size == (size_t)lmrespoff);
 
888
 
 
889
  /* We append the binary hashes */
 
890
  if(size < (NTLM_BUFSIZE - 0x18)) {
 
891
    memcpy(&ntlmbuf[size], lmresp, 0x18);
 
892
    size += 0x18;
 
893
  }
 
894
 
 
895
  DEBUG_OUT({
 
896
    fprintf(stderr, "**** TYPE3 header lmresp=");
 
897
    ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
 
898
  });
 
899
 
 
900
#if USE_NTRESPONSES
 
901
  if(size < (NTLM_BUFSIZE - 0x18)) {
 
902
    DEBUGASSERT(size == (size_t)ntrespoff);
 
903
    memcpy(&ntlmbuf[size], ntresp, 0x18);
 
904
    size += 0x18;
 
905
  }
 
906
 
 
907
  DEBUG_OUT({
 
908
    fprintf(stderr, "\n   ntresp=");
 
909
    ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
 
910
  });
 
911
 
 
912
#endif
 
913
 
 
914
  DEBUG_OUT({
 
915
    fprintf(stderr, "\n   flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
 
916
            LONGQUARTET(ntlm->flags), ntlm->flags);
 
917
    ntlm_print_flags(stderr, ntlm->flags);
 
918
    fprintf(stderr, "\n****\n");
 
919
  });
 
920
 
 
921
  /* Make sure that the domain, user and host strings fit in the
 
922
     buffer before we copy them there. */
 
923
  if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
 
924
    failf(data, "user + domain + host name too big");
 
925
    return CURLE_OUT_OF_MEMORY;
 
926
  }
 
927
 
 
928
  DEBUGASSERT(size == domoff);
 
929
  if(unicode)
 
930
    unicodecpy(&ntlmbuf[size], domain, domlen / 2);
 
931
  else
 
932
    memcpy(&ntlmbuf[size], domain, domlen);
 
933
 
 
934
  size += domlen;
 
935
 
 
936
  DEBUGASSERT(size == useroff);
 
937
  if(unicode)
 
938
    unicodecpy(&ntlmbuf[size], user, userlen / 2);
 
939
  else
 
940
    memcpy(&ntlmbuf[size], user, userlen);
 
941
 
 
942
  size += userlen;
 
943
 
 
944
  DEBUGASSERT(size == hostoff);
 
945
  if(unicode)
 
946
    unicodecpy(&ntlmbuf[size], host, hostlen / 2);
 
947
  else
 
948
    memcpy(&ntlmbuf[size], host, hostlen);
 
949
 
 
950
  size += hostlen;
 
951
 
 
952
  /* Convert domain, user, and host to ASCII but leave the rest as-is */
 
953
  res = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff],
 
954
                                size - domoff);
 
955
  if(res)
 
956
    return CURLE_CONV_FAILED;
 
957
 
 
958
#endif
 
959
 
 
960
  /* Return with binary blob encoded into base64 */
 
961
  return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, &base64_sz);
 
962
}
 
963
 
 
964
#endif /* USE_NTLM */