Revert "Update to 7.40.1"
[platform/upstream/curl.git] / lib / curl_sasl.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 2012 - 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  * RFC2195 CRAM-MD5 authentication
22  * RFC2831 DIGEST-MD5 authentication
23  * RFC4422 Simple Authentication and Security Layer (SASL)
24  * RFC4616 PLAIN authentication
25  * RFC6749 OAuth 2.0 Authorization Framework
26  * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
27  *
28  ***************************************************************************/
29
30 #include "curl_setup.h"
31
32 #include <curl/curl.h>
33 #include "urldata.h"
34
35 #include "curl_base64.h"
36 #include "curl_md5.h"
37 #include "vtls/vtls.h"
38 #include "curl_hmac.h"
39 #include "curl_ntlm_msgs.h"
40 #include "curl_sasl.h"
41 #include "warnless.h"
42 #include "curl_memory.h"
43 #include "strtok.h"
44 #include "rawstr.h"
45
46 #ifdef USE_NSS
47 #include "vtls/nssg.h" /* for Curl_nss_force_init() */
48 #endif
49
50 #define _MPRINTF_REPLACE /* use our functions only */
51 #include <curl/mprintf.h>
52
53 /* The last #include file should be: */
54 #include "memdebug.h"
55
56 #if !defined(CURL_DISABLE_CRYPTO_AUTH) && !defined(USE_WINDOWS_SSPI)
57 #define DIGEST_QOP_VALUE_AUTH             (1 << 0)
58 #define DIGEST_QOP_VALUE_AUTH_INT         (1 << 1)
59 #define DIGEST_QOP_VALUE_AUTH_CONF        (1 << 2)
60
61 #define DIGEST_QOP_VALUE_STRING_AUTH      "auth"
62 #define DIGEST_QOP_VALUE_STRING_AUTH_INT  "auth-int"
63 #define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf"
64
65 /* Retrieves the value for a corresponding key from the challenge string
66  * returns TRUE if the key could be found, FALSE if it does not exists
67  */
68 static bool sasl_digest_get_key_value(const char *chlg,
69                                       const char *key,
70                                       char *value,
71                                       size_t max_val_len,
72                                       char end_char)
73 {
74   char *find_pos;
75   size_t i;
76
77   find_pos = strstr(chlg, key);
78   if(!find_pos)
79     return FALSE;
80
81   find_pos += strlen(key);
82
83   for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i)
84     value[i] = *find_pos++;
85   value[i] = '\0';
86
87   return TRUE;
88 }
89
90 static CURLcode sasl_digest_get_qop_values(const char *options, int *value)
91 {
92   char *tmp;
93   char *token;
94   char *tok_buf;
95
96   /* Initialise the output */
97   *value = 0;
98
99   /* Tokenise the list of qop values. Use a temporary clone of the buffer since
100      strtok_r() ruins it. */
101   tmp = strdup(options);
102   if(!tmp)
103     return CURLE_OUT_OF_MEMORY;
104
105   token = strtok_r(tmp, ",", &tok_buf);
106   while(token != NULL) {
107     if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH))
108       *value |= DIGEST_QOP_VALUE_AUTH;
109     else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT))
110       *value |= DIGEST_QOP_VALUE_AUTH_INT;
111     else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF))
112       *value |= DIGEST_QOP_VALUE_AUTH_CONF;
113
114     token = strtok_r(NULL, ",", &tok_buf);
115   }
116
117   Curl_safefree(tmp);
118
119   return CURLE_OK;
120 }
121 #endif
122
123 /*
124  * Curl_sasl_create_plain_message()
125  *
126  * This is used to generate an already encoded PLAIN message ready
127  * for sending to the recipient.
128  *
129  * Parameters:
130  *
131  * data    [in]     - The session handle.
132  * userp   [in]     - The user name.
133  * passdwp [in]     - The user's password.
134  * outptr  [in/out] - The address where a pointer to newly allocated memory
135  *                    holding the result will be stored upon completion.
136  * outlen  [out]    - The length of the output message.
137  *
138  * Returns CURLE_OK on success.
139  */
140 CURLcode Curl_sasl_create_plain_message(struct SessionHandle *data,
141                                         const char *userp,
142                                         const char *passwdp,
143                                         char **outptr, size_t *outlen)
144 {
145   CURLcode result;
146   char *plainauth;
147   size_t ulen;
148   size_t plen;
149
150   ulen = strlen(userp);
151   plen = strlen(passwdp);
152
153   plainauth = malloc(2 * ulen + plen + 2);
154   if(!plainauth) {
155     *outlen = 0;
156     *outptr = NULL;
157     return CURLE_OUT_OF_MEMORY;
158   }
159
160   /* Calculate the reply */
161   memcpy(plainauth, userp, ulen);
162   plainauth[ulen] = '\0';
163   memcpy(plainauth + ulen + 1, userp, ulen);
164   plainauth[2 * ulen + 1] = '\0';
165   memcpy(plainauth + 2 * ulen + 2, passwdp, plen);
166
167   /* Base64 encode the reply */
168   result = Curl_base64_encode(data, plainauth, 2 * ulen + plen + 2, outptr,
169                               outlen);
170   Curl_safefree(plainauth);
171   return result;
172 }
173
174 /*
175  * Curl_sasl_create_login_message()
176  *
177  * This is used to generate an already encoded LOGIN message containing the
178  * user name or password ready for sending to the recipient.
179  *
180  * Parameters:
181  *
182  * data    [in]     - The session handle.
183  * valuep  [in]     - The user name or user's password.
184  * outptr  [in/out] - The address where a pointer to newly allocated memory
185  *                    holding the result will be stored upon completion.
186  * outlen  [out]    - The length of the output message.
187  *
188  * Returns CURLE_OK on success.
189  */
190 CURLcode Curl_sasl_create_login_message(struct SessionHandle *data,
191                                         const char *valuep, char **outptr,
192                                         size_t *outlen)
193 {
194   size_t vlen = strlen(valuep);
195
196   if(!vlen) {
197     /* Calculate an empty reply */
198     *outptr = strdup("=");
199     if(*outptr) {
200       *outlen = (size_t) 1;
201       return CURLE_OK;
202     }
203
204     *outlen = 0;
205     return CURLE_OUT_OF_MEMORY;
206   }
207
208   /* Base64 encode the value */
209   return Curl_base64_encode(data, valuep, vlen, outptr, outlen);
210 }
211
212 #ifndef CURL_DISABLE_CRYPTO_AUTH
213  /*
214  * Curl_sasl_decode_cram_md5_message()
215  *
216  * This is used to decode an already encoded CRAM-MD5 challenge message.
217  *
218  * Parameters:
219  *
220  * chlg64  [in]     - Pointer to the base64 encoded challenge message.
221  * outptr  [in/out] - The address where a pointer to newly allocated memory
222  *                    holding the result will be stored upon completion.
223  * outlen  [out]    - The length of the output message.
224  *
225  * Returns CURLE_OK on success.
226  */
227 CURLcode Curl_sasl_decode_cram_md5_message(const char *chlg64, char **outptr,
228                                            size_t *outlen)
229 {
230   CURLcode result = CURLE_OK;
231   size_t chlg64len = strlen(chlg64);
232
233   *outptr = NULL;
234   *outlen = 0;
235
236   /* Decode the challenge if necessary */
237   if(chlg64len && *chlg64 != '=')
238     result = Curl_base64_decode(chlg64, (unsigned char **) outptr, outlen);
239
240     return result;
241  }
242
243  /*
244  * Curl_sasl_create_cram_md5_message()
245  *
246  * This is used to generate an already encoded CRAM-MD5 response message ready
247  * for sending to the recipient.
248  *
249  * Parameters:
250  *
251  * data    [in]     - The session handle.
252  * chlg    [in]     - The challenge.
253  * userp   [in]     - The user name.
254  * passdwp [in]     - The user's password.
255  * outptr  [in/out] - The address where a pointer to newly allocated memory
256  *                    holding the result will be stored upon completion.
257  * outlen  [out]    - The length of the output message.
258  *
259  * Returns CURLE_OK on success.
260  */
261 CURLcode Curl_sasl_create_cram_md5_message(struct SessionHandle *data,
262                                            const char *chlg,
263                                            const char *userp,
264                                            const char *passwdp,
265                                            char **outptr, size_t *outlen)
266 {
267   CURLcode result = CURLE_OK;
268   size_t chlglen = 0;
269   HMAC_context *ctxt;
270   unsigned char digest[MD5_DIGEST_LEN];
271   char *response;
272
273   if(chlg)
274     chlglen = strlen(chlg);
275
276   /* Compute the digest using the password as the key */
277   ctxt = Curl_HMAC_init(Curl_HMAC_MD5,
278                         (const unsigned char *) passwdp,
279                         curlx_uztoui(strlen(passwdp)));
280   if(!ctxt)
281     return CURLE_OUT_OF_MEMORY;
282
283   /* Update the digest with the given challenge */
284   if(chlglen > 0)
285     Curl_HMAC_update(ctxt, (const unsigned char *) chlg,
286                      curlx_uztoui(chlglen));
287
288   /* Finalise the digest */
289   Curl_HMAC_final(ctxt, digest);
290
291   /* Generate the response */
292   response = aprintf(
293       "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
294            userp, digest[0], digest[1], digest[2], digest[3], digest[4],
295            digest[5], digest[6], digest[7], digest[8], digest[9], digest[10],
296            digest[11], digest[12], digest[13], digest[14], digest[15]);
297   if(!response)
298     return CURLE_OUT_OF_MEMORY;
299
300   /* Base64 encode the response */
301   result = Curl_base64_encode(data, response, 0, outptr, outlen);
302
303   Curl_safefree(response);
304
305   return result;
306 }
307
308 #ifndef USE_WINDOWS_SSPI
309 /*
310  * sasl_decode_digest_md5_message()
311  *
312  * This is used internally to decode an already encoded DIGEST-MD5 challenge
313  * message into the seperate attributes.
314  *
315  * Parameters:
316  *
317  * chlg64  [in]     - Pointer to the base64 encoded challenge message.
318  * nonce   [in/out] - The buffer where the nonce will be stored.
319  * nlen    [in]     - The length of the nonce buffer.
320  * realm   [in/out] - The buffer where the realm will be stored.
321  * rlen    [in]     - The length of the realm buffer.
322  * alg     [in/out] - The buffer where the algorithm will be stored.
323  * alen    [in]     - The length of the algorithm buffer.
324  * qop     [in/out] - The buffer where the qop-options will be stored.
325  * qlen    [in]     - The length of the qop buffer.
326  *
327  * Returns CURLE_OK on success.
328  */
329 static CURLcode sasl_decode_digest_md5_message(const char *chlg64,
330                                                char *nonce, size_t nlen,
331                                                char *realm, size_t rlen,
332                                                char *alg, size_t alen,
333                                                char *qop, size_t qlen)
334 {
335   CURLcode result = CURLE_OK;
336   unsigned char *chlg = NULL;
337   size_t chlglen = 0;
338   size_t chlg64len = strlen(chlg64);
339
340   /* Decode the base-64 encoded challenge message */
341   if(chlg64len && *chlg64 != '=') {
342     result = Curl_base64_decode(chlg64, &chlg, &chlglen);
343     if(result)
344       return result;
345   }
346
347   /* Ensure we have a valid challenge message */
348   if(!chlg)
349     return CURLE_BAD_CONTENT_ENCODING;
350
351   /* Retrieve nonce string from the challenge */
352   if(!sasl_digest_get_key_value((char *)chlg, "nonce=\"", nonce, nlen, '\"')) {
353     Curl_safefree(chlg);
354     return CURLE_BAD_CONTENT_ENCODING;
355   }
356
357   /* Retrieve realm string from the challenge */
358   if(!sasl_digest_get_key_value((char *)chlg, "realm=\"", realm, rlen, '\"')) {
359     /* Challenge does not have a realm, set empty string [RFC2831] page 6 */
360     strcpy(realm, "");
361   }
362
363   /* Retrieve algorithm string from the challenge */
364   if(!sasl_digest_get_key_value((char *)chlg, "algorithm=", alg, alen, ',')) {
365     Curl_safefree(chlg);
366     return CURLE_BAD_CONTENT_ENCODING;
367   }
368
369   /* Retrieve qop-options string from the challenge */
370   if(!sasl_digest_get_key_value((char *)chlg, "qop=\"", qop, qlen, '\"')) {
371     Curl_safefree(chlg);
372     return CURLE_BAD_CONTENT_ENCODING;
373   }
374
375   Curl_safefree(chlg);
376
377   return CURLE_OK;
378 }
379
380 /*
381  * Curl_sasl_create_digest_md5_message()
382  *
383  * This is used to generate an already encoded DIGEST-MD5 response message
384  * ready for sending to the recipient.
385  *
386  * Parameters:
387  *
388  * data    [in]     - The session handle.
389  * chlg64  [in]     - Pointer to the base64 encoded challenge message.
390  * userp   [in]     - The user name.
391  * passdwp [in]     - The user's password.
392  * service [in]     - The service type such as www, smtp, pop or imap.
393  * outptr  [in/out] - The address where a pointer to newly allocated memory
394  *                    holding the result will be stored upon completion.
395  * outlen  [out]    - The length of the output message.
396  *
397  * Returns CURLE_OK on success.
398  */
399 CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
400                                              const char *chlg64,
401                                              const char *userp,
402                                              const char *passwdp,
403                                              const char *service,
404                                              char **outptr, size_t *outlen)
405 {
406   CURLcode result = CURLE_OK;
407   size_t i;
408   MD5_context *ctxt;
409   char *response = NULL;
410   unsigned char digest[MD5_DIGEST_LEN];
411   char HA1_hex[2 * MD5_DIGEST_LEN + 1];
412   char HA2_hex[2 * MD5_DIGEST_LEN + 1];
413   char resp_hash_hex[2 * MD5_DIGEST_LEN + 1];
414   char nonce[64];
415   char realm[128];
416   char algorithm[64];
417   char qop_options[64];
418   int qop_values;
419   char cnonce[33];
420   unsigned int entropy[4];
421   char nonceCount[] = "00000001";
422   char method[]     = "AUTHENTICATE";
423   char qop[]        = DIGEST_QOP_VALUE_STRING_AUTH;
424   char uri[128];
425
426   /* Decode the challange message */
427   result = sasl_decode_digest_md5_message(chlg64, nonce, sizeof(nonce),
428                                           realm, sizeof(realm),
429                                           algorithm, sizeof(algorithm),
430                                           qop_options, sizeof(qop_options));
431   if(result)
432     return result;
433
434   /* We only support md5 sessions */
435   if(strcmp(algorithm, "md5-sess") != 0)
436     return CURLE_BAD_CONTENT_ENCODING;
437
438   /* Get the qop-values from the qop-options */
439   result = sasl_digest_get_qop_values(qop_options, &qop_values);
440   if(result)
441     return result;
442
443   /* We only support auth quality-of-protection */
444   if(!(qop_values & DIGEST_QOP_VALUE_AUTH))
445     return CURLE_BAD_CONTENT_ENCODING;
446
447   /* Generate 16 bytes of random data */
448   entropy[0] = Curl_rand(data);
449   entropy[1] = Curl_rand(data);
450   entropy[2] = Curl_rand(data);
451   entropy[3] = Curl_rand(data);
452
453   /* Convert the random data into a 32 byte hex string */
454   snprintf(cnonce, sizeof(cnonce), "%08x%08x%08x%08x",
455            entropy[0], entropy[1], entropy[2], entropy[3]);
456
457   /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */
458   ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
459   if(!ctxt)
460     return CURLE_OUT_OF_MEMORY;
461
462   Curl_MD5_update(ctxt, (const unsigned char *) userp,
463                   curlx_uztoui(strlen(userp)));
464   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
465   Curl_MD5_update(ctxt, (const unsigned char *) realm,
466                   curlx_uztoui(strlen(realm)));
467   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
468   Curl_MD5_update(ctxt, (const unsigned char *) passwdp,
469                   curlx_uztoui(strlen(passwdp)));
470   Curl_MD5_final(ctxt, digest);
471
472   ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
473   if(!ctxt)
474     return CURLE_OUT_OF_MEMORY;
475
476   Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN);
477   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
478   Curl_MD5_update(ctxt, (const unsigned char *) nonce,
479                   curlx_uztoui(strlen(nonce)));
480   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
481   Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
482                   curlx_uztoui(strlen(cnonce)));
483   Curl_MD5_final(ctxt, digest);
484
485   /* Convert calculated 16 octet hex into 32 bytes string */
486   for(i = 0; i < MD5_DIGEST_LEN; i++)
487     snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]);
488
489   /* Prepare the URL string */
490   snprintf(uri, sizeof(uri), "%s/%s", service, realm);
491
492   /* Calculate H(A2) */
493   ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
494   if(!ctxt)
495     return CURLE_OUT_OF_MEMORY;
496
497   Curl_MD5_update(ctxt, (const unsigned char *) method,
498                   curlx_uztoui(strlen(method)));
499   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
500   Curl_MD5_update(ctxt, (const unsigned char *) uri,
501                   curlx_uztoui(strlen(uri)));
502   Curl_MD5_final(ctxt, digest);
503
504   for(i = 0; i < MD5_DIGEST_LEN; i++)
505     snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]);
506
507   /* Now calculate the response hash */
508   ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
509   if(!ctxt)
510     return CURLE_OUT_OF_MEMORY;
511
512   Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN);
513   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
514   Curl_MD5_update(ctxt, (const unsigned char *) nonce,
515                   curlx_uztoui(strlen(nonce)));
516   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
517
518   Curl_MD5_update(ctxt, (const unsigned char *) nonceCount,
519                   curlx_uztoui(strlen(nonceCount)));
520   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
521   Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
522                   curlx_uztoui(strlen(cnonce)));
523   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
524   Curl_MD5_update(ctxt, (const unsigned char *) qop,
525                   curlx_uztoui(strlen(qop)));
526   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
527
528   Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN);
529   Curl_MD5_final(ctxt, digest);
530
531   for(i = 0; i < MD5_DIGEST_LEN; i++)
532     snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]);
533
534   /* Generate the response */
535   response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\","
536                      "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s,"
537                      "qop=%s",
538                      userp, realm, nonce,
539                      cnonce, nonceCount, uri, resp_hash_hex, qop);
540   if(!response)
541     return CURLE_OUT_OF_MEMORY;
542
543   /* Base64 encode the response */
544   result = Curl_base64_encode(data, response, 0, outptr, outlen);
545
546   free(response);
547   return result;
548 }
549 #endif  /* USE_WINDOWS_SSPI */
550
551 #endif  /* CURL_DISABLE_CRYPTO_AUTH */
552
553 #ifdef USE_NTLM
554 /*
555  * Curl_sasl_create_ntlm_type1_message()
556  *
557  * This is used to generate an already encoded NTLM type-1 message ready for
558  * sending to the recipient.
559  *
560  * Note: This is a simple wrapper of the NTLM function which means that any
561  * SASL based protocols don't have to include the NTLM functions directly.
562  *
563  * Parameters:
564  *
565  * userp   [in]     - The user name in the format User or Domain\User.
566  * passdwp [in]     - The user's password.
567  * ntlm    [in/out] - The ntlm data struct being used and modified.
568  * outptr  [in/out] - The address where a pointer to newly allocated memory
569  *                    holding the result will be stored upon completion.
570  * outlen  [out]    - The length of the output message.
571  *
572  * Returns CURLE_OK on success.
573  */
574 CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp,
575                                              const char *passwdp,
576                                              struct ntlmdata *ntlm,
577                                              char **outptr, size_t *outlen)
578 {
579   return Curl_ntlm_create_type1_message(userp, passwdp, ntlm, outptr, outlen);
580 }
581
582 /*
583  * Curl_sasl_decode_ntlm_type2_message()
584  *
585  * This is used to decode an already encoded NTLM type-2 message.
586  *
587  * Parameters:
588  *
589  * data     [in]     - Pointer to session handle.
590  * type2msg [in]     - Pointer to the base64 encoded type-2 message.
591  * ntlm     [in/out] - The ntlm data struct being used and modified.
592  *
593  * Returns CURLE_OK on success.
594  */
595 CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data,
596                                              const char *type2msg,
597                                              struct ntlmdata *ntlm)
598 {
599 #ifdef USE_NSS
600   CURLcode result;
601
602   /* make sure the crypto backend is initialized */
603   result = Curl_nss_force_init(data);
604   if(result)
605     return result;
606 #endif
607
608   return Curl_ntlm_decode_type2_message(data, type2msg, ntlm);
609 }
610
611 /*
612  * Curl_sasl_create_ntlm_type3_message()
613  *
614  * This is used to generate an already encoded NTLM type-3 message ready for
615  * sending to the recipient.
616  *
617  * Parameters:
618  *
619  * data    [in]     - Pointer to session handle.
620  * userp   [in]     - The user name in the format User or Domain\User.
621  * passdwp [in]     - The user's password.
622  * ntlm    [in/out] - The ntlm data struct being used and modified.
623  * outptr  [in/out] - The address where a pointer to newly allocated memory
624  *                    holding the result will be stored upon completion.
625  * outlen  [out]    - The length of the output message.
626  *
627  * Returns CURLE_OK on success.
628  */
629 CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data,
630                                              const char *userp,
631                                              const char *passwdp,
632                                              struct ntlmdata *ntlm,
633                                              char **outptr, size_t *outlen)
634 {
635   return Curl_ntlm_create_type3_message(data, userp, passwdp, ntlm, outptr,
636                                         outlen);
637 }
638 #endif /* USE_NTLM */
639
640 /*
641  * Curl_sasl_create_xoauth2_message()
642  *
643  * This is used to generate an already encoded OAuth 2.0 message ready for
644  * sending to the recipient.
645  *
646  * Parameters:
647  *
648  * data    [in]     - The session handle.
649  * user    [in]     - The user name.
650  * bearer  [in]     - The bearer token.
651  * outptr  [in/out] - The address where a pointer to newly allocated memory
652  *                    holding the result will be stored upon completion.
653  * outlen  [out]    - The length of the output message.
654  *
655  * Returns CURLE_OK on success.
656  */
657 CURLcode Curl_sasl_create_xoauth2_message(struct SessionHandle *data,
658                                           const char *user,
659                                           const char *bearer,
660                                           char **outptr, size_t *outlen)
661 {
662   CURLcode result = CURLE_OK;
663   char *xoauth = NULL;
664
665   /* Generate the message */
666   xoauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer);
667   if(!xoauth)
668     return CURLE_OUT_OF_MEMORY;
669
670   /* Base64 encode the reply */
671   result = Curl_base64_encode(data, xoauth, strlen(xoauth), outptr, outlen);
672
673   Curl_safefree(xoauth);
674
675   return result;
676 }
677
678 /*
679  * Curl_sasl_cleanup()
680  *
681  * This is used to cleanup any libraries or curl modules used by the sasl
682  * functions.
683  *
684  * Parameters:
685  *
686  * conn     [in]     - Pointer to the connection data.
687  * authused [in]     - The authentication mechanism used.
688  */
689 void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
690 {
691 #ifdef USE_NTLM
692   /* Cleanup the ntlm structure */
693   if(authused == SASL_MECH_NTLM) {
694     Curl_ntlm_sspi_cleanup(&conn->ntlm);
695   }
696   (void)conn;
697 #else
698   /* Reserved for future use */
699   (void)conn;
700   (void)authused;
701 #endif
702 }