curl_ntlm_msgs.c: Removed unused variable passwd
[platform/upstream/curl.git] / lib / curl_ntlm_msgs.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2012, 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_WINDOWS_SSPI
37 #  include <tchar.h>
38 #endif
39
40 #include "urldata.h"
41 #include "non-ascii.h"
42 #include "sendf.h"
43 #include "curl_base64.h"
44 #include "curl_ntlm_core.h"
45 #include "curl_gethostname.h"
46 #include "curl_multibyte.h"
47 #include "curl_memory.h"
48
49 #ifdef USE_WINDOWS_SSPI
50 #  include "curl_sspi.h"
51 #endif
52
53 #include "sslgen.h"
54
55 #define BUILDING_CURL_NTLM_MSGS_C
56 #include "curl_ntlm_msgs.h"
57
58 #define _MPRINTF_REPLACE /* use our functions only */
59 #include <curl/mprintf.h>
60
61 /* The last #include file should be: */
62 #include "memdebug.h"
63
64 /* "NTLMSSP" signature is always in ASCII regardless of the platform */
65 #define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
66
67 #define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
68 #define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8) & 0xff), \
69   (((x) >> 16) & 0xff), (((x) >> 24) & 0xff)
70
71 #if DEBUG_ME
72 # define DEBUG_OUT(x) x
73 static void ntlm_print_flags(FILE *handle, unsigned long flags)
74 {
75   if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
76     fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
77   if(flags & NTLMFLAG_NEGOTIATE_OEM)
78     fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
79   if(flags & NTLMFLAG_REQUEST_TARGET)
80     fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
81   if(flags & (1<<3))
82     fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
83   if(flags & NTLMFLAG_NEGOTIATE_SIGN)
84     fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
85   if(flags & NTLMFLAG_NEGOTIATE_SEAL)
86     fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
87   if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
88     fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
89   if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
90     fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
91   if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
92     fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
93   if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
94     fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
95   if(flags & (1<<10))
96     fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
97   if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
98     fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
99   if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
100     fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
101   if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
102     fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
103   if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
104     fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
105   if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
106     fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
107   if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
108     fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
109   if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
110     fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
111   if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
112     fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
113   if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
114     fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
115   if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
116     fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
117   if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
118     fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
119   if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
120     fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
121   if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
122     fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
123   if(flags & (1<<24))
124     fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
125   if(flags & (1<<25))
126     fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
127   if(flags & (1<<26))
128     fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
129   if(flags & (1<<27))
130     fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
131   if(flags & (1<<28))
132     fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
133   if(flags & NTLMFLAG_NEGOTIATE_128)
134     fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
135   if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
136     fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
137   if(flags & NTLMFLAG_NEGOTIATE_56)
138     fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
139 }
140
141 static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
142 {
143   const char *p = buf;
144   (void)handle;
145   fprintf(stderr, "0x");
146   while(len-- > 0)
147     fprintf(stderr, "%02.2x", (unsigned int)*p++);
148 }
149 #else
150 # define DEBUG_OUT(x) Curl_nop_stmt
151 #endif
152
153 #ifndef USE_WINDOWS_SSPI
154 /*
155  * This function converts from the little endian format used in the
156  * incoming package to whatever endian format we're using natively.
157  * Argument is a pointer to a 4 byte buffer.
158  */
159 static unsigned int readint_le(unsigned char *buf)
160 {
161   return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
162     ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
163 }
164 #endif
165
166 /*
167   NTLM message structure notes:
168
169   A 'short' is a 'network short', a little-endian 16-bit unsigned value.
170
171   A 'long' is a 'network long', a little-endian, 32-bit unsigned value.
172
173   A 'security buffer' represents a triplet used to point to a buffer,
174   consisting of two shorts and one long:
175
176     1. A 'short' containing the length of the buffer content in bytes.
177     2. A 'short' containing the allocated space for the buffer in bytes.
178     3. A 'long' containing the offset to the start of the buffer in bytes,
179        from the beginning of the NTLM message.
180 */
181
182 /*
183  * Curl_ntlm_decode_type2_message()
184  *
185  * This is used to decode a ntlm type-2 message received from a: HTTP, SMTP
186  * or POP3 server. The message is first decoded from a base64 string into a
187  * raw ntlm message and checked for validity before the appropriate data for
188  * creating a type-3 message is written to the given ntlm data structure.
189  *
190  * Parameters:
191  *
192  * data    [in]     - Pointer to session handle.
193  * header  [in]     - Pointer to the input buffer.
194  * ntlm    [in]     - Pointer to ntlm data struct being used and modified.
195  *
196  * Returns CURLE_OK on success.
197  */
198 CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data,
199                                         const char* header,
200                                         struct ntlmdata* ntlm)
201 {
202 #ifndef USE_WINDOWS_SSPI
203   static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
204 #endif
205
206   /* NTLM type-2 message structure:
207
208           Index  Description            Content
209             0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
210                                         (0x4e544c4d53535000)
211             8    NTLM Message Type      long (0x02000000)
212            12    Target Name            security buffer
213            20    Flags                  long
214            24    Challenge              8 bytes
215           (32)   Context                8 bytes (two consecutive longs) (*)
216           (40)   Target Information     security buffer (*)
217           (48)   OS Version Structure   8 bytes (*)
218   32 (48) (56)   Start of data block    (*)
219                                         (*) -> Optional
220   */
221
222   size_t size = 0;
223   unsigned char *buffer = NULL;
224   CURLcode error;
225
226 #if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI)
227   (void)data;
228 #endif
229
230   error = Curl_base64_decode(header, &buffer, &size);
231   if(error)
232     return error;
233
234   if(!buffer) {
235     infof(data, "NTLM handshake failure (unhandled condition)\n");
236     return CURLE_REMOTE_ACCESS_DENIED;
237   }
238
239 #ifdef USE_WINDOWS_SSPI
240   ntlm->type_2 = malloc(size + 1);
241   if(ntlm->type_2 == NULL) {
242     free(buffer);
243     return CURLE_OUT_OF_MEMORY;
244   }
245   ntlm->n_type_2 = (unsigned long)size;
246   memcpy(ntlm->type_2, buffer, size);
247 #else
248   ntlm->flags = 0;
249
250   if((size < 32) ||
251      (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) ||
252      (memcmp(buffer + 8, type2_marker, sizeof(type2_marker)) != 0)) {
253     /* This was not a good enough type-2 message */
254     free(buffer);
255     infof(data, "NTLM handshake failure (bad type-2 message)\n");
256     return CURLE_REMOTE_ACCESS_DENIED;
257   }
258
259   ntlm->flags = readint_le(&buffer[20]);
260   memcpy(ntlm->nonce, &buffer[24], 8);
261
262   DEBUG_OUT({
263     fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
264     ntlm_print_flags(stderr, ntlm->flags);
265     fprintf(stderr, "\n                  nonce=");
266     ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
267     fprintf(stderr, "\n****\n");
268     fprintf(stderr, "**** Header %s\n ", header);
269   });
270 #endif
271   free(buffer);
272
273   return CURLE_OK;
274 }
275
276 #ifdef USE_WINDOWS_SSPI
277 void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm)
278 {
279   if(ntlm->type_2) {
280     free(ntlm->type_2);
281     ntlm->type_2 = NULL;
282   }
283   if(ntlm->has_handles) {
284     s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
285     s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
286     ntlm->has_handles = 0;
287   }
288   if(ntlm->p_identity) {
289     if(ntlm->identity.User) free(ntlm->identity.User);
290     if(ntlm->identity.Password) free(ntlm->identity.Password);
291     if(ntlm->identity.Domain) free(ntlm->identity.Domain);
292     ntlm->p_identity = NULL;
293   }
294 }
295 #endif
296
297 #ifndef USE_WINDOWS_SSPI
298 /* copy the source to the destination and fill in zeroes in every
299    other destination byte! */
300 static void unicodecpy(unsigned char *dest,
301                        const char *src, size_t length)
302 {
303   size_t i;
304   for(i = 0; i < length; i++) {
305     dest[2 * i] = (unsigned char)src[i];
306     dest[2 * i + 1] = '\0';
307   }
308 }
309 #endif
310
311 /*
312  * Curl_ntlm_create_type1_message()
313  *
314  * This is used to generate an already encoded NTLM type-1 message ready
315  * for sending to the recipient, be it a: HTTP, SMTP or POP3 server,
316  * using the appropriate compile time crypo API.
317  *
318  * Parameters:
319  *
320  * userp   [in]     - The user name in the format User or Domain\User.
321  * passdwp [in]     - The user's password.
322  * ntlm    [in/out] - The ntlm data struct being used and modified.
323  * outptr  [in/out] - The address where a pointer to newly allocated memory
324  *                    holding the result will be stored upon completion.
325  * outlen  [out]    - The length of the output message.
326  *
327  * Returns CURLE_OK on success.
328  */
329 CURLcode Curl_ntlm_create_type1_message(const char *userp,
330                                         const char *passwdp,
331                                         struct ntlmdata *ntlm,
332                                         char **outptr,
333                                         size_t *outlen)
334 {
335   /* NTLM type-1 message structure:
336
337        Index  Description            Content
338          0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
339                                      (0x4e544c4d53535000)
340          8    NTLM Message Type      long (0x01000000)
341         12    Flags                  long
342        (16)   Supplied Domain        security buffer (*)
343        (24)   Supplied Workstation   security buffer (*)
344        (32)   OS Version Structure   8 bytes (*)
345   (32) (40)   Start of data block    (*)
346                                      (*) -> Optional
347   */
348
349   unsigned char ntlmbuf[NTLM_BUFSIZE];
350   size_t size;
351
352 #ifdef USE_WINDOWS_SSPI
353
354   SecBuffer buf;
355   SecBufferDesc desc;
356   SECURITY_STATUS status;
357   unsigned long attrs;
358   const TCHAR *useranddomain;
359   const TCHAR *user;
360   const TCHAR *domain = TEXT("");
361   size_t domlen = 0;
362   TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
363
364   Curl_ntlm_sspi_cleanup(ntlm);
365
366   if(userp && *userp) {
367 #ifdef UNICODE
368     useranddomain = Curl_convert_UTF8_to_wchar(userp);
369     if(useranddomain == NULL)
370       return CURLE_OUT_OF_MEMORY;
371 #else
372     useranddomain = userp;
373 #endif
374
375     user = _tcschr(useranddomain, TEXT('\\'));
376     if(!user)
377       user = _tcschr(useranddomain, TEXT('/'));
378
379     if(user) {
380       domain = useranddomain;
381       domlen = user - useranddomain;
382       user++;
383     }
384     else {
385       user = useranddomain;
386       domain = TEXT("");
387       domlen = 0;
388     }
389
390     /* note: initialize all of this before doing the mallocs so that
391      * it can be cleaned up later without leaking memory.
392      */
393     ntlm->p_identity = &ntlm->identity;
394     memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
395
396 #ifdef UNICODE
397     if((ntlm->identity.User = (unsigned short *)_wcsdup(user)) == NULL) {
398       free((void *)useranddomain);
399       return CURLE_OUT_OF_MEMORY;
400     }
401 #else
402     if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL)
403       return CURLE_OUT_OF_MEMORY;
404 #endif
405     ntlm->identity.UserLength = (unsigned long)_tcslen(user);
406
407     ntlm->identity.Domain = malloc(sizeof(TCHAR) * (domlen + 1));
408     if(ntlm->identity.Domain == NULL) {
409 #ifdef UNICODE
410       free((void *)useranddomain);
411 #endif
412       return CURLE_OUT_OF_MEMORY;
413     }
414     _tcsncpy((TCHAR *)ntlm->identity.Domain, domain, domlen);
415     ntlm->identity.Domain[domlen] = TEXT('\0');
416     ntlm->identity.DomainLength = (unsigned long)domlen;
417
418 #ifdef UNICODE
419     free((void *)useranddomain);
420 #endif
421
422 #ifdef UNICODE
423     ntlm->identity.Password = (unsigned short *)
424       Curl_convert_UTF8_to_wchar(passwdp);
425     if(ntlm->identity.Password == NULL)
426       return CURLE_OUT_OF_MEMORY;
427 #else
428     if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL)
429       return CURLE_OUT_OF_MEMORY;
430 #endif
431     ntlm->identity.PasswordLength =
432       (unsigned long)_tcslen((TCHAR *)ntlm->identity.Password);
433
434 #ifdef UNICODE
435     ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
436 #else
437     ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
438 #endif
439   }
440   else
441     ntlm->p_identity = NULL;
442
443   status = s_pSecFn->AcquireCredentialsHandle(NULL,
444                                               (TCHAR *) TEXT("NTLM"),
445                                               SECPKG_CRED_OUTBOUND, NULL,
446                                               ntlm->p_identity, NULL, NULL,
447                                               &ntlm->handle, &tsDummy);
448   if(status != SEC_E_OK)
449     return CURLE_OUT_OF_MEMORY;
450
451   desc.ulVersion = SECBUFFER_VERSION;
452   desc.cBuffers  = 1;
453   desc.pBuffers  = &buf;
454   buf.cbBuffer   = NTLM_BUFSIZE;
455   buf.BufferType = SECBUFFER_TOKEN;
456   buf.pvBuffer   = ntlmbuf;
457
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, &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, &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 = 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
565  * for sending to the recipient, be it a: HTTP, SMTP or POP3 server,
566  * 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;
610   SecBuffer type_3;
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   type_2_desc.ulVersion = type_3_desc.ulVersion  = SECBUFFER_VERSION;
622   type_2_desc.cBuffers  = type_3_desc.cBuffers   = 1;
623   type_2_desc.pBuffers  = &type_2;
624   type_3_desc.pBuffers  = &type_3;
625
626   type_2.BufferType = SECBUFFER_TOKEN;
627   type_2.pvBuffer   = ntlm->type_2;
628   type_2.cbBuffer   = ntlm->n_type_2;
629   type_3.BufferType = SECBUFFER_TOKEN;
630   type_3.pvBuffer   = ntlmbuf;
631   type_3.cbBuffer   = NTLM_BUFSIZE;
632
633   status = s_pSecFn->InitializeSecurityContext(&ntlm->handle,
634                                                &ntlm->c_handle,
635                                                (TCHAR *) TEXT(""),
636                                                ISC_REQ_CONFIDENTIALITY |
637                                                ISC_REQ_REPLAY_DETECT |
638                                                ISC_REQ_CONNECTION,
639                                                0, SECURITY_NETWORK_DREP,
640                                                &type_2_desc,
641                                                0, &ntlm->c_handle,
642                                                &type_3_desc,
643                                                &attrs, &tsDummy);
644   if(status != SEC_E_OK)
645     return CURLE_RECV_ERROR;
646
647   size = type_3.cbBuffer;
648
649   Curl_ntlm_sspi_cleanup(ntlm);
650
651 #else
652   int lmrespoff;
653   unsigned char lmresp[24]; /* fixed-size */
654 #if USE_NTRESPONSES
655   int ntrespoff;
656   unsigned char ntresp[24]; /* fixed-size */
657 #endif
658   bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
659   char host[HOSTNAME_MAX + 1] = "";
660   const char *user;
661   const char *domain = "";
662   size_t hostoff = 0;
663   size_t useroff = 0;
664   size_t domoff = 0;
665   size_t hostlen = 0;
666   size_t userlen = 0;
667   size_t domlen = 0;
668   CURLcode res;
669
670   user = strchr(userp, '\\');
671   if(!user)
672     user = strchr(userp, '/');
673
674   if(user) {
675     domain = userp;
676     domlen = (user - domain);
677     user++;
678   }
679   else
680     user = userp;
681
682   if(user)
683     userlen = strlen(user);
684
685   /* Get the machine's un-qualified host name as NTLM doesn't like the fully
686      qualified domain name */
687   if(Curl_gethostname(host, sizeof(host))) {
688     infof(data, "gethostname() failed, continuing without!\n");
689     hostlen = 0;
690   }
691   else {
692     hostlen = strlen(host);
693   }
694
695   if(unicode) {
696     domlen = domlen * 2;
697     userlen = userlen * 2;
698     hostlen = hostlen * 2;
699   }
700
701 #if USE_NTLM2SESSION
702   /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
703   if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
704     unsigned char ntbuffer[0x18];
705     unsigned char tmp[0x18];
706     unsigned char md5sum[MD5_DIGEST_LENGTH];
707     unsigned char entropy[8];
708
709     /* Need to create 8 bytes random data */
710     Curl_ssl_random(data, entropy, sizeof(entropy));
711
712     /* 8 bytes random data as challenge in lmresp */
713     memcpy(lmresp, entropy, 8);
714
715     /* Pad with zeros */
716     memset(lmresp + 8, 0, 0x10);
717
718     /* Fill tmp with challenge(nonce?) + entropy */
719     memcpy(tmp, &ntlm->nonce[0], 8);
720     memcpy(tmp + 8, entropy, 8);
721
722     Curl_ssl_md5sum(tmp, 16, md5sum, MD5_DIGEST_LENGTH);
723
724     /* We shall only use the first 8 bytes of md5sum, but the des
725        code in Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */
726     if(CURLE_OUT_OF_MEMORY ==
727        Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer))
728       return CURLE_OUT_OF_MEMORY;
729     Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp);
730
731     /* End of NTLM2 Session code */
732   }
733   else
734 #endif
735   {
736
737 #if USE_NTRESPONSES
738     unsigned char ntbuffer[0x18];
739 #endif
740     unsigned char lmbuffer[0x18];
741
742 #if USE_NTRESPONSES
743     if(CURLE_OUT_OF_MEMORY ==
744        Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer))
745       return CURLE_OUT_OF_MEMORY;
746     Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
747 #endif
748
749     Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer);
750     Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
751     /* A safer but less compatible alternative is:
752      *   Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
753      * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
754   }
755
756   lmrespoff = 64; /* size of the message header */
757 #if USE_NTRESPONSES
758   ntrespoff = lmrespoff + 0x18;
759   domoff = ntrespoff + 0x18;
760 #else
761   domoff = lmrespoff + 0x18;
762 #endif
763   useroff = domoff + domlen;
764   hostoff = useroff + userlen;
765
766   /* Create the big type-3 message binary blob */
767   size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
768                   NTLMSSP_SIGNATURE "%c"
769                   "\x03%c%c%c"  /* 32-bit type = 3 */
770
771                   "%c%c"  /* LanManager length */
772                   "%c%c"  /* LanManager allocated space */
773                   "%c%c"  /* LanManager offset */
774                   "%c%c"  /* 2 zeroes */
775
776                   "%c%c"  /* NT-response length */
777                   "%c%c"  /* NT-response allocated space */
778                   "%c%c"  /* NT-response offset */
779                   "%c%c"  /* 2 zeroes */
780
781                   "%c%c"  /* domain length */
782                   "%c%c"  /* domain allocated space */
783                   "%c%c"  /* domain name offset */
784                   "%c%c"  /* 2 zeroes */
785
786                   "%c%c"  /* user length */
787                   "%c%c"  /* user allocated space */
788                   "%c%c"  /* user offset */
789                   "%c%c"  /* 2 zeroes */
790
791                   "%c%c"  /* host length */
792                   "%c%c"  /* host allocated space */
793                   "%c%c"  /* host offset */
794                   "%c%c"  /* 2 zeroes */
795
796                   "%c%c"  /* session key length (unknown purpose) */
797                   "%c%c"  /* session key allocated space (unknown purpose) */
798                   "%c%c"  /* session key offset (unknown purpose) */
799                   "%c%c"  /* 2 zeroes */
800
801                   "%c%c%c%c",  /* flags */
802
803                   /* domain string */
804                   /* user string */
805                   /* host string */
806                   /* LanManager response */
807                   /* NT response */
808
809                   0,                /* zero termination */
810                   0, 0, 0,          /* type-3 long, the 24 upper bits */
811
812                   SHORTPAIR(0x18),  /* LanManager response length, twice */
813                   SHORTPAIR(0x18),
814                   SHORTPAIR(lmrespoff),
815                   0x0, 0x0,
816
817 #if USE_NTRESPONSES
818                   SHORTPAIR(0x18),  /* NT-response length, twice */
819                   SHORTPAIR(0x18),
820                   SHORTPAIR(ntrespoff),
821                   0x0, 0x0,
822 #else
823                   0x0, 0x0,
824                   0x0, 0x0,
825                   0x0, 0x0,
826                   0x0, 0x0,
827 #endif
828                   SHORTPAIR(domlen),
829                   SHORTPAIR(domlen),
830                   SHORTPAIR(domoff),
831                   0x0, 0x0,
832
833                   SHORTPAIR(userlen),
834                   SHORTPAIR(userlen),
835                   SHORTPAIR(useroff),
836                   0x0, 0x0,
837
838                   SHORTPAIR(hostlen),
839                   SHORTPAIR(hostlen),
840                   SHORTPAIR(hostoff),
841                   0x0, 0x0,
842
843                   0x0, 0x0,
844                   0x0, 0x0,
845                   0x0, 0x0,
846                   0x0, 0x0,
847
848                   LONGQUARTET(ntlm->flags));
849
850   DEBUGASSERT(size == 64);
851   DEBUGASSERT(size == (size_t)lmrespoff);
852
853   /* We append the binary hashes */
854   if(size < (NTLM_BUFSIZE - 0x18)) {
855     memcpy(&ntlmbuf[size], lmresp, 0x18);
856     size += 0x18;
857   }
858
859   DEBUG_OUT({
860     fprintf(stderr, "**** TYPE3 header lmresp=");
861     ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
862   });
863
864 #if USE_NTRESPONSES
865   if(size < (NTLM_BUFSIZE - 0x18)) {
866     DEBUGASSERT(size == (size_t)ntrespoff);
867     memcpy(&ntlmbuf[size], ntresp, 0x18);
868     size += 0x18;
869   }
870
871   DEBUG_OUT({
872     fprintf(stderr, "\n   ntresp=");
873     ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
874   });
875
876 #endif
877
878   DEBUG_OUT({
879     fprintf(stderr, "\n   flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
880             LONGQUARTET(ntlm->flags), ntlm->flags);
881     ntlm_print_flags(stderr, ntlm->flags);
882     fprintf(stderr, "\n****\n");
883   });
884
885   /* Make sure that the domain, user and host strings fit in the
886      buffer before we copy them there. */
887   if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
888     failf(data, "user + domain + host name too big");
889     return CURLE_OUT_OF_MEMORY;
890   }
891
892   DEBUGASSERT(size == domoff);
893   if(unicode)
894     unicodecpy(&ntlmbuf[size], domain, domlen / 2);
895   else
896     memcpy(&ntlmbuf[size], domain, domlen);
897
898   size += domlen;
899
900   DEBUGASSERT(size == useroff);
901   if(unicode)
902     unicodecpy(&ntlmbuf[size], user, userlen / 2);
903   else
904     memcpy(&ntlmbuf[size], user, userlen);
905
906   size += userlen;
907
908   DEBUGASSERT(size == hostoff);
909   if(unicode)
910     unicodecpy(&ntlmbuf[size], host, hostlen / 2);
911   else
912     memcpy(&ntlmbuf[size], host, hostlen);
913
914   size += hostlen;
915
916   /* Convert domain, user, and host to ASCII but leave the rest as-is */
917   res = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff],
918                                 size - domoff);
919   if(res)
920     return CURLE_CONV_FAILED;
921
922 #endif
923
924   /* Return with binary blob encoded into base64 */
925   return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
926 }
927
928 #endif /* USE_NTLM */