ntlm: Updated comments for the addition of SASL support to IMAP in v7.29
[platform/upstream/curl.git] / lib / curl_ntlm_msgs.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2013, 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 "sslgen.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 #endif
162
163 /*
164   NTLM message structure notes:
165
166   A 'short' is a 'network short', a little-endian 16-bit unsigned value.
167
168   A 'long' is a 'network long', a little-endian, 32-bit unsigned value.
169
170   A 'security buffer' represents a triplet used to point to a buffer,
171   consisting of two shorts and one long:
172
173     1. A 'short' containing the length of the buffer content in bytes.
174     2. A 'short' containing the allocated space for the buffer in bytes.
175     3. A 'long' containing the offset to the start of the buffer in bytes,
176        from the beginning of the NTLM message.
177 */
178
179 /*
180  * Curl_ntlm_decode_type2_message()
181  *
182  * This is used to decode a ntlm type-2 message received from a HTTP or SASL
183  * based (such as SMTP, POP3 or IMAP) server. The message is first decoded
184  * from a base64 string into a raw ntlm message and checked for validity
185  * before the appropriate data for creating a type-3 message is written to
186  * the given ntlm data structure.
187  *
188  * Parameters:
189  *
190  * data    [in]     - Pointer to session handle.
191  * header  [in]     - Pointer to the input buffer.
192  * ntlm    [in]     - Pointer to ntlm data struct being used and modified.
193  *
194  * Returns CURLE_OK on success.
195  */
196 CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data,
197                                         const char* header,
198                                         struct ntlmdata* ntlm)
199 {
200 #ifndef USE_WINDOWS_SSPI
201   static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
202 #endif
203
204   /* NTLM type-2 message structure:
205
206           Index  Description            Content
207             0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
208                                         (0x4e544c4d53535000)
209             8    NTLM Message Type      long (0x02000000)
210            12    Target Name            security buffer
211            20    Flags                  long
212            24    Challenge              8 bytes
213           (32)   Context                8 bytes (two consecutive longs) (*)
214           (40)   Target Information     security buffer (*)
215           (48)   OS Version Structure   8 bytes (*)
216   32 (48) (56)   Start of data block    (*)
217                                         (*) -> Optional
218   */
219
220   size_t size = 0;
221   unsigned char *buffer = NULL;
222   CURLcode error;
223
224 #if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI)
225   (void)data;
226 #endif
227
228   error = Curl_base64_decode(header, &buffer, &size);
229   if(error)
230     return error;
231
232   if(!buffer) {
233     infof(data, "NTLM handshake failure (unhandled condition)\n");
234     return CURLE_REMOTE_ACCESS_DENIED;
235   }
236
237 #ifdef USE_WINDOWS_SSPI
238   ntlm->type_2 = malloc(size + 1);
239   if(ntlm->type_2 == NULL) {
240     free(buffer);
241     return CURLE_OUT_OF_MEMORY;
242   }
243   ntlm->n_type_2 = curlx_uztoul(size);
244   memcpy(ntlm->type_2, buffer, size);
245 #else
246   ntlm->flags = 0;
247
248   if((size < 32) ||
249      (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) ||
250      (memcmp(buffer + 8, type2_marker, sizeof(type2_marker)) != 0)) {
251     /* This was not a good enough type-2 message */
252     free(buffer);
253     infof(data, "NTLM handshake failure (bad type-2 message)\n");
254     return CURLE_REMOTE_ACCESS_DENIED;
255   }
256
257   ntlm->flags = readint_le(&buffer[20]);
258   memcpy(ntlm->nonce, &buffer[24], 8);
259
260   DEBUG_OUT({
261     fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
262     ntlm_print_flags(stderr, ntlm->flags);
263     fprintf(stderr, "\n                  nonce=");
264     ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
265     fprintf(stderr, "\n****\n");
266     fprintf(stderr, "**** Header %s\n ", header);
267   });
268 #endif
269   free(buffer);
270
271   return CURLE_OK;
272 }
273
274 #ifdef USE_WINDOWS_SSPI
275 void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm)
276 {
277   Curl_safefree(ntlm->type_2);
278   if(ntlm->has_handles) {
279     s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
280     s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
281     ntlm->has_handles = 0;
282   }
283   if(ntlm->p_identity) {
284     Curl_safefree(ntlm->identity.User);
285     Curl_safefree(ntlm->identity.Password);
286     Curl_safefree(ntlm->identity.Domain);
287     ntlm->p_identity = NULL;
288   }
289 }
290 #endif
291
292 #ifndef USE_WINDOWS_SSPI
293 /* copy the source to the destination and fill in zeroes in every
294    other destination byte! */
295 static void unicodecpy(unsigned char *dest,
296                        const char *src, size_t length)
297 {
298   size_t i;
299   for(i = 0; i < length; i++) {
300     dest[2 * i] = (unsigned char)src[i];
301     dest[2 * i + 1] = '\0';
302   }
303 }
304 #endif
305
306 /*
307  * Curl_ntlm_create_type1_message()
308  *
309  * This is used to generate an already encoded NTLM type-1 message ready for
310  * sending to the recipient, be it a HTTP or SASL based (such as SMTP, POP3
311  * or IMAP) server, using the appropriate compile time crypo API.
312  *
313  * Parameters:
314  *
315  * userp   [in]     - The user name in the format User or Domain\User.
316  * passdwp [in]     - The user's password.
317  * ntlm    [in/out] - The ntlm data struct being used and modified.
318  * outptr  [in/out] - The address where a pointer to newly allocated memory
319  *                    holding the result will be stored upon completion.
320  * outlen  [out]    - The length of the output message.
321  *
322  * Returns CURLE_OK on success.
323  */
324 CURLcode Curl_ntlm_create_type1_message(const char *userp,
325                                         const char *passwdp,
326                                         struct ntlmdata *ntlm,
327                                         char **outptr,
328                                         size_t *outlen)
329 {
330   /* NTLM type-1 message structure:
331
332        Index  Description            Content
333          0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
334                                      (0x4e544c4d53535000)
335          8    NTLM Message Type      long (0x01000000)
336         12    Flags                  long
337        (16)   Supplied Domain        security buffer (*)
338        (24)   Supplied Workstation   security buffer (*)
339        (32)   OS Version Structure   8 bytes (*)
340   (32) (40)   Start of data block    (*)
341                                      (*) -> Optional
342   */
343
344   unsigned char ntlmbuf[NTLM_BUFSIZE];
345   size_t size;
346
347 #ifdef USE_WINDOWS_SSPI
348
349   SecBuffer buf;
350   SecBufferDesc desc;
351   SECURITY_STATUS status;
352   unsigned long attrs;
353   xcharp_u useranddomain;
354   xcharp_u user, dup_user;
355   xcharp_u domain, dup_domain;
356   xcharp_u passwd, dup_passwd;
357   size_t domlen = 0;
358   TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
359
360   domain.const_tchar_ptr = TEXT("");
361
362   Curl_ntlm_sspi_cleanup(ntlm);
363
364   if(userp && *userp) {
365
366     /* null initialize ntlm identity's data to allow proper cleanup */
367     ntlm->p_identity = &ntlm->identity;
368     memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
369
370     useranddomain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)userp);
371     if(!useranddomain.tchar_ptr)
372       return CURLE_OUT_OF_MEMORY;
373
374     user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\'));
375     if(!user.const_tchar_ptr)
376       user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/'));
377
378     if(user.tchar_ptr) {
379       domain.tchar_ptr = useranddomain.tchar_ptr;
380       domlen = user.tchar_ptr - useranddomain.tchar_ptr;
381       user.tchar_ptr++;
382     }
383     else {
384       user.tchar_ptr = useranddomain.tchar_ptr;
385       domain.const_tchar_ptr = TEXT("");
386       domlen = 0;
387     }
388
389     /* setup ntlm identity's user and length */
390     dup_user.tchar_ptr = _tcsdup(user.tchar_ptr);
391     if(!dup_user.tchar_ptr) {
392       Curl_unicodefree(useranddomain.tchar_ptr);
393       return CURLE_OUT_OF_MEMORY;
394     }
395     ntlm->identity.User = dup_user.tbyte_ptr;
396     ntlm->identity.UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr));
397     dup_user.tchar_ptr = NULL;
398
399     /* setup ntlm identity's domain and length */
400     dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1));
401     if(!dup_domain.tchar_ptr) {
402       Curl_unicodefree(useranddomain.tchar_ptr);
403       return CURLE_OUT_OF_MEMORY;
404     }
405     _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen);
406     *(dup_domain.tchar_ptr + domlen) = TEXT('\0');
407     ntlm->identity.Domain = dup_domain.tbyte_ptr;
408     ntlm->identity.DomainLength = curlx_uztoul(domlen);
409     free(dup_domain.tchar_ptr);
410     dup_domain.tchar_ptr = NULL;
411
412     Curl_unicodefree(useranddomain.tchar_ptr);
413
414     /* setup ntlm identity's password and length */
415     passwd.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)passwdp);
416     if(!passwd.tchar_ptr)
417       return CURLE_OUT_OF_MEMORY;
418     dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr);
419     if(!dup_passwd.tchar_ptr) {
420       Curl_unicodefree(passwd.tchar_ptr);
421       return CURLE_OUT_OF_MEMORY;
422     }
423     ntlm->identity.Password = dup_passwd.tbyte_ptr;
424     ntlm->identity.PasswordLength =
425       curlx_uztoul(_tcslen(dup_passwd.tchar_ptr));
426     dup_passwd.tchar_ptr = NULL;
427
428     Curl_unicodefree(passwd.tchar_ptr);
429
430     /* setup ntlm identity's flags */
431     ntlm->identity.Flags = SECFLAG_WINNT_AUTH_IDENTITY;
432   }
433   else
434     ntlm->p_identity = NULL;
435
436   status = s_pSecFn->AcquireCredentialsHandle(NULL,
437                                               (TCHAR *) TEXT("NTLM"),
438                                               SECPKG_CRED_OUTBOUND, NULL,
439                                               ntlm->p_identity, NULL, NULL,
440                                               &ntlm->handle, &tsDummy);
441   if(status != SEC_E_OK)
442     return CURLE_OUT_OF_MEMORY;
443
444   desc.ulVersion = SECBUFFER_VERSION;
445   desc.cBuffers  = 1;
446   desc.pBuffers  = &buf;
447   buf.cbBuffer   = NTLM_BUFSIZE;
448   buf.BufferType = SECBUFFER_TOKEN;
449   buf.pvBuffer   = ntlmbuf;
450
451   status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, NULL,
452                                                (TCHAR *) TEXT(""),
453                                                ISC_REQ_CONFIDENTIALITY |
454                                                ISC_REQ_REPLAY_DETECT |
455                                                ISC_REQ_CONNECTION,
456                                                0, SECURITY_NETWORK_DREP,
457                                                NULL, 0,
458                                                &ntlm->c_handle, &desc,
459                                                &attrs, &tsDummy);
460
461   if(status == SEC_I_COMPLETE_AND_CONTINUE ||
462      status == SEC_I_CONTINUE_NEEDED)
463     s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc);
464   else if(status != SEC_E_OK) {
465     s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
466     return CURLE_RECV_ERROR;
467   }
468
469   ntlm->has_handles = 1;
470   size = buf.cbBuffer;
471
472 #else
473
474   const char *host = "";              /* empty */
475   const char *domain = "";            /* empty */
476   size_t hostlen = 0;
477   size_t domlen = 0;
478   size_t hostoff = 0;
479   size_t domoff = hostoff + hostlen;  /* This is 0: remember that host and
480                                          domain are empty */
481   (void)userp;
482   (void)passwdp;
483   (void)ntlm;
484
485 #if USE_NTLM2SESSION
486 #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
487 #else
488 #define NTLM2FLAG 0
489 #endif
490   snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
491            NTLMSSP_SIGNATURE "%c"
492            "\x01%c%c%c" /* 32-bit type = 1 */
493            "%c%c%c%c"   /* 32-bit NTLM flag field */
494            "%c%c"       /* domain length */
495            "%c%c"       /* domain allocated space */
496            "%c%c"       /* domain name offset */
497            "%c%c"       /* 2 zeroes */
498            "%c%c"       /* host length */
499            "%c%c"       /* host allocated space */
500            "%c%c"       /* host name offset */
501            "%c%c"       /* 2 zeroes */
502            "%s"         /* host name */
503            "%s",        /* domain string */
504            0,           /* trailing zero */
505            0, 0, 0,     /* part of type-1 long */
506
507            LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
508                        NTLMFLAG_REQUEST_TARGET |
509                        NTLMFLAG_NEGOTIATE_NTLM_KEY |
510                        NTLM2FLAG |
511                        NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
512            SHORTPAIR(domlen),
513            SHORTPAIR(domlen),
514            SHORTPAIR(domoff),
515            0, 0,
516            SHORTPAIR(hostlen),
517            SHORTPAIR(hostlen),
518            SHORTPAIR(hostoff),
519            0, 0,
520            host,  /* this is empty */
521            domain /* this is empty */);
522
523   /* Initial packet length */
524   size = 32 + hostlen + domlen;
525
526 #endif
527
528   DEBUG_OUT({
529     fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x "
530             "0x%08.8x ",
531             LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
532                         NTLMFLAG_REQUEST_TARGET |
533                         NTLMFLAG_NEGOTIATE_NTLM_KEY |
534                         NTLM2FLAG |
535                         NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
536             NTLMFLAG_NEGOTIATE_OEM |
537             NTLMFLAG_REQUEST_TARGET |
538             NTLMFLAG_NEGOTIATE_NTLM_KEY |
539             NTLM2FLAG |
540             NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
541     ntlm_print_flags(stderr,
542                      NTLMFLAG_NEGOTIATE_OEM |
543                      NTLMFLAG_REQUEST_TARGET |
544                      NTLMFLAG_NEGOTIATE_NTLM_KEY |
545                      NTLM2FLAG |
546                      NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
547     fprintf(stderr, "\n****\n");
548   });
549
550   /* Return with binary blob encoded into base64 */
551   return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
552 }
553
554 /*
555  * Curl_ntlm_create_type3_message()
556  *
557  * This is used to generate an already encoded NTLM type-3 message ready for
558  * sending to the recipient, be it a HTTP or SASL based (such as SMTP, POP3
559  * or IMAP) server, using the appropriate compile time crypo API.
560  *
561  * Parameters:
562  *
563  * data    [in]     - The session handle.
564  * userp   [in]     - The user name in the format User or Domain\User.
565  * passdwp [in]     - The user's password.
566  * ntlm    [in/out] - The ntlm data struct being used and modified.
567  * outptr  [in/out] - The address where a pointer to newly allocated memory
568  *                    holding the result will be stored upon completion.
569  * outlen  [out]    - The length of the output message.
570  *
571  * Returns CURLE_OK on success.
572  */
573 CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data,
574                                         const char *userp,
575                                         const char *passwdp,
576                                         struct ntlmdata *ntlm,
577                                         char **outptr,
578                                         size_t *outlen)
579 {
580   /* NTLM type-3 message structure:
581
582           Index  Description            Content
583             0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
584                                         (0x4e544c4d53535000)
585             8    NTLM Message Type      long (0x03000000)
586            12    LM/LMv2 Response       security buffer
587            20    NTLM/NTLMv2 Response   security buffer
588            28    Target Name            security buffer
589            36    User Name              security buffer
590            44    Workstation Name       security buffer
591           (52)   Session Key            security buffer (*)
592           (60)   Flags                  long (*)
593           (64)   OS Version Structure   8 bytes (*)
594   52 (64) (72)   Start of data block
595                                           (*) -> Optional
596   */
597
598   unsigned char ntlmbuf[NTLM_BUFSIZE];
599   size_t size;
600
601 #ifdef USE_WINDOWS_SSPI
602   SecBuffer type_2;
603   SecBuffer type_3;
604   SecBufferDesc type_2_desc;
605   SecBufferDesc type_3_desc;
606   SECURITY_STATUS status;
607   unsigned long attrs;
608   TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
609
610   (void)passwdp;
611   (void)userp;
612   (void)data;
613
614   type_2_desc.ulVersion = type_3_desc.ulVersion  = SECBUFFER_VERSION;
615   type_2_desc.cBuffers  = type_3_desc.cBuffers   = 1;
616   type_2_desc.pBuffers  = &type_2;
617   type_3_desc.pBuffers  = &type_3;
618
619   type_2.BufferType = SECBUFFER_TOKEN;
620   type_2.pvBuffer   = ntlm->type_2;
621   type_2.cbBuffer   = ntlm->n_type_2;
622   type_3.BufferType = SECBUFFER_TOKEN;
623   type_3.pvBuffer   = ntlmbuf;
624   type_3.cbBuffer   = NTLM_BUFSIZE;
625
626   status = s_pSecFn->InitializeSecurityContext(&ntlm->handle,
627                                                &ntlm->c_handle,
628                                                (TCHAR *) TEXT(""),
629                                                ISC_REQ_CONFIDENTIALITY |
630                                                ISC_REQ_REPLAY_DETECT |
631                                                ISC_REQ_CONNECTION,
632                                                0, SECURITY_NETWORK_DREP,
633                                                &type_2_desc,
634                                                0, &ntlm->c_handle,
635                                                &type_3_desc,
636                                                &attrs, &tsDummy);
637   if(status != SEC_E_OK)
638     return CURLE_RECV_ERROR;
639
640   size = type_3.cbBuffer;
641
642   Curl_ntlm_sspi_cleanup(ntlm);
643
644 #else
645   int lmrespoff;
646   unsigned char lmresp[24]; /* fixed-size */
647 #if USE_NTRESPONSES
648   int ntrespoff;
649   unsigned char ntresp[24]; /* fixed-size */
650 #endif
651   bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
652   char host[HOSTNAME_MAX + 1] = "";
653   const char *user;
654   const char *domain = "";
655   size_t hostoff = 0;
656   size_t useroff = 0;
657   size_t domoff = 0;
658   size_t hostlen = 0;
659   size_t userlen = 0;
660   size_t domlen = 0;
661   CURLcode res;
662
663   user = strchr(userp, '\\');
664   if(!user)
665     user = strchr(userp, '/');
666
667   if(user) {
668     domain = userp;
669     domlen = (user - domain);
670     user++;
671   }
672   else
673     user = userp;
674
675   if(user)
676     userlen = strlen(user);
677
678   /* Get the machine's un-qualified host name as NTLM doesn't like the fully
679      qualified domain name */
680   if(Curl_gethostname(host, sizeof(host))) {
681     infof(data, "gethostname() failed, continuing without!\n");
682     hostlen = 0;
683   }
684   else {
685     hostlen = strlen(host);
686   }
687
688   if(unicode) {
689     domlen = domlen * 2;
690     userlen = userlen * 2;
691     hostlen = hostlen * 2;
692   }
693
694 #if USE_NTLM2SESSION
695   /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
696   if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
697     unsigned char ntbuffer[0x18];
698     unsigned char tmp[0x18];
699     unsigned char md5sum[MD5_DIGEST_LENGTH];
700     unsigned char entropy[8];
701
702     /* Need to create 8 bytes random data */
703     Curl_ssl_random(data, entropy, sizeof(entropy));
704
705     /* 8 bytes random data as challenge in lmresp */
706     memcpy(lmresp, entropy, 8);
707
708     /* Pad with zeros */
709     memset(lmresp + 8, 0, 0x10);
710
711     /* Fill tmp with challenge(nonce?) + entropy */
712     memcpy(tmp, &ntlm->nonce[0], 8);
713     memcpy(tmp + 8, entropy, 8);
714
715     Curl_ssl_md5sum(tmp, 16, md5sum, MD5_DIGEST_LENGTH);
716
717     /* We shall only use the first 8 bytes of md5sum, but the des
718        code in Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */
719     if(CURLE_OUT_OF_MEMORY ==
720        Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer))
721       return CURLE_OUT_OF_MEMORY;
722     Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp);
723
724     /* End of NTLM2 Session code */
725   }
726   else
727 #endif
728   {
729
730 #if USE_NTRESPONSES
731     unsigned char ntbuffer[0x18];
732 #endif
733     unsigned char lmbuffer[0x18];
734
735 #if USE_NTRESPONSES
736     if(CURLE_OUT_OF_MEMORY ==
737        Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer))
738       return CURLE_OUT_OF_MEMORY;
739     Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
740 #endif
741
742     Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer);
743     Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
744     /* A safer but less compatible alternative is:
745      *   Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
746      * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
747   }
748
749   lmrespoff = 64; /* size of the message header */
750 #if USE_NTRESPONSES
751   ntrespoff = lmrespoff + 0x18;
752   domoff = ntrespoff + 0x18;
753 #else
754   domoff = lmrespoff + 0x18;
755 #endif
756   useroff = domoff + domlen;
757   hostoff = useroff + userlen;
758
759   /* Create the big type-3 message binary blob */
760   size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
761                   NTLMSSP_SIGNATURE "%c"
762                   "\x03%c%c%c"  /* 32-bit type = 3 */
763
764                   "%c%c"  /* LanManager length */
765                   "%c%c"  /* LanManager allocated space */
766                   "%c%c"  /* LanManager offset */
767                   "%c%c"  /* 2 zeroes */
768
769                   "%c%c"  /* NT-response length */
770                   "%c%c"  /* NT-response allocated space */
771                   "%c%c"  /* NT-response offset */
772                   "%c%c"  /* 2 zeroes */
773
774                   "%c%c"  /* domain length */
775                   "%c%c"  /* domain allocated space */
776                   "%c%c"  /* domain name offset */
777                   "%c%c"  /* 2 zeroes */
778
779                   "%c%c"  /* user length */
780                   "%c%c"  /* user allocated space */
781                   "%c%c"  /* user offset */
782                   "%c%c"  /* 2 zeroes */
783
784                   "%c%c"  /* host length */
785                   "%c%c"  /* host allocated space */
786                   "%c%c"  /* host offset */
787                   "%c%c"  /* 2 zeroes */
788
789                   "%c%c"  /* session key length (unknown purpose) */
790                   "%c%c"  /* session key allocated space (unknown purpose) */
791                   "%c%c"  /* session key offset (unknown purpose) */
792                   "%c%c"  /* 2 zeroes */
793
794                   "%c%c%c%c",  /* flags */
795
796                   /* domain string */
797                   /* user string */
798                   /* host string */
799                   /* LanManager response */
800                   /* NT response */
801
802                   0,                /* zero termination */
803                   0, 0, 0,          /* type-3 long, the 24 upper bits */
804
805                   SHORTPAIR(0x18),  /* LanManager response length, twice */
806                   SHORTPAIR(0x18),
807                   SHORTPAIR(lmrespoff),
808                   0x0, 0x0,
809
810 #if USE_NTRESPONSES
811                   SHORTPAIR(0x18),  /* NT-response length, twice */
812                   SHORTPAIR(0x18),
813                   SHORTPAIR(ntrespoff),
814                   0x0, 0x0,
815 #else
816                   0x0, 0x0,
817                   0x0, 0x0,
818                   0x0, 0x0,
819                   0x0, 0x0,
820 #endif
821                   SHORTPAIR(domlen),
822                   SHORTPAIR(domlen),
823                   SHORTPAIR(domoff),
824                   0x0, 0x0,
825
826                   SHORTPAIR(userlen),
827                   SHORTPAIR(userlen),
828                   SHORTPAIR(useroff),
829                   0x0, 0x0,
830
831                   SHORTPAIR(hostlen),
832                   SHORTPAIR(hostlen),
833                   SHORTPAIR(hostoff),
834                   0x0, 0x0,
835
836                   0x0, 0x0,
837                   0x0, 0x0,
838                   0x0, 0x0,
839                   0x0, 0x0,
840
841                   LONGQUARTET(ntlm->flags));
842
843   DEBUGASSERT(size == 64);
844   DEBUGASSERT(size == (size_t)lmrespoff);
845
846   /* We append the binary hashes */
847   if(size < (NTLM_BUFSIZE - 0x18)) {
848     memcpy(&ntlmbuf[size], lmresp, 0x18);
849     size += 0x18;
850   }
851
852   DEBUG_OUT({
853     fprintf(stderr, "**** TYPE3 header lmresp=");
854     ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
855   });
856
857 #if USE_NTRESPONSES
858   if(size < (NTLM_BUFSIZE - 0x18)) {
859     DEBUGASSERT(size == (size_t)ntrespoff);
860     memcpy(&ntlmbuf[size], ntresp, 0x18);
861     size += 0x18;
862   }
863
864   DEBUG_OUT({
865     fprintf(stderr, "\n   ntresp=");
866     ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
867   });
868
869 #endif
870
871   DEBUG_OUT({
872     fprintf(stderr, "\n   flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
873             LONGQUARTET(ntlm->flags), ntlm->flags);
874     ntlm_print_flags(stderr, ntlm->flags);
875     fprintf(stderr, "\n****\n");
876   });
877
878   /* Make sure that the domain, user and host strings fit in the
879      buffer before we copy them there. */
880   if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
881     failf(data, "user + domain + host name too big");
882     return CURLE_OUT_OF_MEMORY;
883   }
884
885   DEBUGASSERT(size == domoff);
886   if(unicode)
887     unicodecpy(&ntlmbuf[size], domain, domlen / 2);
888   else
889     memcpy(&ntlmbuf[size], domain, domlen);
890
891   size += domlen;
892
893   DEBUGASSERT(size == useroff);
894   if(unicode)
895     unicodecpy(&ntlmbuf[size], user, userlen / 2);
896   else
897     memcpy(&ntlmbuf[size], user, userlen);
898
899   size += userlen;
900
901   DEBUGASSERT(size == hostoff);
902   if(unicode)
903     unicodecpy(&ntlmbuf[size], host, hostlen / 2);
904   else
905     memcpy(&ntlmbuf[size], host, hostlen);
906
907   size += hostlen;
908
909   /* Convert domain, user, and host to ASCII but leave the rest as-is */
910   res = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff],
911                                 size - domoff);
912   if(res)
913     return CURLE_CONV_FAILED;
914
915 #endif
916
917   /* Return with binary blob encoded into base64 */
918   return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
919 }
920
921 #endif /* USE_NTLM */