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