1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 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 https://curl.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 * SPDX-License-Identifier: curl
22 *
23 * RFC2195 CRAM-MD5 authentication
24 * RFC2617 Basic and Digest Access Authentication
25 * RFC2831 DIGEST-MD5 authentication
26 * RFC4422 Simple Authentication and Security Layer (SASL)
27 * RFC4616 PLAIN authentication
28 * RFC5802 SCRAM-SHA-1 authentication
29 * RFC7677 SCRAM-SHA-256 authentication
30 * RFC6749 OAuth 2.0 Authorization Framework
31 * RFC7628 A Set of SASL Mechanisms for OAuth
32 * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
33 *
34 ***************************************************************************/
35
36#include "curl_setup.h"
37
38#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) || \
39 !defined(CURL_DISABLE_POP3) || \
40 (!defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP))
41
42#include <curl/curl.h>
43#include "urldata.h"
44
45#include "curl_base64.h"
46#include "curl_md5.h"
47#include "vauth/vauth.h"
48#include "cfilters.h"
49#include "vtls/vtls.h"
50#include "curl_hmac.h"
51#include "curl_sasl.h"
52#include "warnless.h"
53#include "strtok.h"
54#include "sendf.h"
55/* The last 3 #include files should be in this order */
56#include "curl_printf.h"
57#include "curl_memory.h"
58#include "memdebug.h"
59
60/* Supported mechanisms */
61static const struct {
62 const char *name; /* Name */
63 size_t len; /* Name length */
64 unsigned short bit; /* Flag bit */
65} mechtable[] = {
66 { "LOGIN", 5, SASL_MECH_LOGIN },
67 { "PLAIN", 5, SASL_MECH_PLAIN },
68 { "CRAM-MD5", 8, SASL_MECH_CRAM_MD5 },
69 { "DIGEST-MD5", 10, SASL_MECH_DIGEST_MD5 },
70 { "GSSAPI", 6, SASL_MECH_GSSAPI },
71 { "EXTERNAL", 8, SASL_MECH_EXTERNAL },
72 { "NTLM", 4, SASL_MECH_NTLM },
73 { "XOAUTH2", 7, SASL_MECH_XOAUTH2 },
74 { "OAUTHBEARER", 11, SASL_MECH_OAUTHBEARER },
75 { "SCRAM-SHA-1", 11, SASL_MECH_SCRAM_SHA_1 },
76 { "SCRAM-SHA-256",13, SASL_MECH_SCRAM_SHA_256 },
77 { ZERO_NULL, 0, 0 }
78};
79
80/*
81 * Curl_sasl_cleanup()
82 *
83 * This is used to cleanup any libraries or curl modules used by the sasl
84 * functions.
85 *
86 * Parameters:
87 *
88 * conn [in] - The connection data.
89 * authused [in] - The authentication mechanism used.
90 */
91void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused)
92{
93 (void)conn;
94 (void)authused;
95
96#if defined(USE_KERBEROS5)
97 /* Cleanup the gssapi structure */
98 if(authused == SASL_MECH_GSSAPI) {
99 Curl_auth_cleanup_gssapi(&conn->krb5);
100 }
101#endif
102
103#if defined(USE_GSASL)
104 /* Cleanup the GSASL structure */
105 if(authused & (SASL_MECH_SCRAM_SHA_1 | SASL_MECH_SCRAM_SHA_256)) {
106 Curl_auth_gsasl_cleanup(&conn->gsasl);
107 }
108#endif
109
110#if defined(USE_NTLM)
111 /* Cleanup the NTLM structure */
112 if(authused == SASL_MECH_NTLM) {
113 Curl_auth_cleanup_ntlm(&conn->ntlm);
114 }
115#endif
116}
117
118/*
119 * Curl_sasl_decode_mech()
120 *
121 * Convert a SASL mechanism name into a token.
122 *
123 * Parameters:
124 *
125 * ptr [in] - The mechanism string.
126 * maxlen [in] - Maximum mechanism string length.
127 * len [out] - If not NULL, effective name length.
128 *
129 * Returns the SASL mechanism token or 0 if no match.
130 */
131unsigned short Curl_sasl_decode_mech(const char *ptr, size_t maxlen,
132 size_t *len)
133{
134 unsigned int i;
135 char c;
136
137 for(i = 0; mechtable[i].name; i++) {
138 if(maxlen >= mechtable[i].len &&
139 !memcmp(ptr, mechtable[i].name, mechtable[i].len)) {
140 if(len)
141 *len = mechtable[i].len;
142
143 if(maxlen == mechtable[i].len)
144 return mechtable[i].bit;
145
146 c = ptr[mechtable[i].len];
147 if(!ISUPPER(c) && !ISDIGIT(c) && c != '-' && c != '_')
148 return mechtable[i].bit;
149 }
150 }
151
152 return 0;
153}
154
155/*
156 * Curl_sasl_parse_url_auth_option()
157 *
158 * Parse the URL login options.
159 */
160CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
161 const char *value, size_t len)
162{
163 CURLcode result = CURLE_OK;
164 size_t mechlen;
165
166 if(!len)
167 return CURLE_URL_MALFORMAT;
168
169 if(sasl->resetprefs) {
170 sasl->resetprefs = FALSE;
171 sasl->prefmech = SASL_AUTH_NONE;
172 }
173
174 if(!strncmp(value, "*", len))
175 sasl->prefmech = SASL_AUTH_DEFAULT;
176 else {
177 unsigned short mechbit = Curl_sasl_decode_mech(value, len, &mechlen);
178 if(mechbit && mechlen == len)
179 sasl->prefmech |= mechbit;
180 else
181 result = CURLE_URL_MALFORMAT;
182 }
183
184 return result;
185}
186
187/*
188 * Curl_sasl_init()
189 *
190 * Initializes the SASL structure.
191 */
192void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
193 const struct SASLproto *params)
194{
195 unsigned long auth = data->set.httpauth;
196
197 sasl->params = params; /* Set protocol dependent parameters */
198 sasl->state = SASL_STOP; /* Not yet running */
199 sasl->curmech = NULL; /* No mechanism yet. */
200 sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */
201 sasl->prefmech = params->defmechs; /* Default preferred mechanisms */
202 sasl->authused = SASL_AUTH_NONE; /* The authentication mechanism used */
203 sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */
204 sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */
205 sasl->force_ir = FALSE; /* Respect external option */
206
207 if(auth != CURLAUTH_BASIC) {
208 sasl->resetprefs = FALSE;
209 sasl->prefmech = SASL_AUTH_NONE;
210 if(auth & CURLAUTH_BASIC)
211 sasl->prefmech |= SASL_MECH_PLAIN | SASL_MECH_LOGIN;
212 if(auth & CURLAUTH_DIGEST)
213 sasl->prefmech |= SASL_MECH_DIGEST_MD5;
214 if(auth & CURLAUTH_NTLM)
215 sasl->prefmech |= SASL_MECH_NTLM;
216 if(auth & CURLAUTH_BEARER)
217 sasl->prefmech |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2;
218 if(auth & CURLAUTH_GSSAPI)
219 sasl->prefmech |= SASL_MECH_GSSAPI;
220 }
221}
222
223/*
224 * sasl_state()
225 *
226 * This is the ONLY way to change SASL state!
227 */
228static void sasl_state(struct SASL *sasl, struct Curl_easy *data,
229 saslstate newstate)
230{
231#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
232 /* for debug purposes */
233 static const char * const names[]={
234 "STOP",
235 "PLAIN",
236 "LOGIN",
237 "LOGIN_PASSWD",
238 "EXTERNAL",
239 "CRAMMD5",
240 "DIGESTMD5",
241 "DIGESTMD5_RESP",
242 "NTLM",
243 "NTLM_TYPE2MSG",
244 "GSSAPI",
245 "GSSAPI_TOKEN",
246 "GSSAPI_NO_DATA",
247 "OAUTH2",
248 "OAUTH2_RESP",
249 "GSASL",
250 "CANCEL",
251 "FINAL",
252 /* LAST */
253 };
254
255 if(sasl->state != newstate)
256 infof(data, "SASL %p state change from %s to %s",
257 (void *)sasl, names[sasl->state], names[newstate]);
258#else
259 (void) data;
260#endif
261
262 sasl->state = newstate;
263}
264
265/* Get the SASL server message and convert it to binary. */
266static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
267 struct bufref *out)
268{
269 CURLcode result = CURLE_OK;
270
271 result = sasl->params->getmessage(data, out);
272 if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) {
273 unsigned char *msg;
274 size_t msglen;
275 const char *serverdata = (const char *) Curl_bufref_ptr(out);
276
277 if(!*serverdata || *serverdata == '=')
278 Curl_bufref_set(out, NULL, 0, NULL);
279 else {
280 result = Curl_base64_decode(serverdata, &msg, &msglen);
281 if(!result)
282 Curl_bufref_set(out, msg, msglen, curl_free);
283 }
284 }
285 return result;
286}
287
288/* Encode the outgoing SASL message. */
289static CURLcode build_message(struct SASL *sasl, struct bufref *msg)
290{
291 CURLcode result = CURLE_OK;
292
293 if(sasl->params->flags & SASL_FLAG_BASE64) {
294 if(!Curl_bufref_ptr(msg)) /* Empty message. */
295 Curl_bufref_set(msg, "", 0, NULL);
296 else if(!Curl_bufref_len(msg)) /* Explicit empty response. */
297 Curl_bufref_set(msg, "=", 1, NULL);
298 else {
299 char *base64;
300 size_t base64len;
301
302 result = Curl_base64_encode((const char *) Curl_bufref_ptr(msg),
303 Curl_bufref_len(msg), &base64, &base64len);
304 if(!result)
305 Curl_bufref_set(msg, base64, base64len, curl_free);
306 }
307 }
308
309 return result;
310}
311
312/*
313 * Curl_sasl_can_authenticate()
314 *
315 * Check if we have enough auth data and capabilities to authenticate.
316 */
317bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data)
318{
319 /* Have credentials been provided? */
320 if(data->state.aptr.user)
321 return TRUE;
322
323 /* EXTERNAL can authenticate without a user name and/or password */
324 if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL)
325 return TRUE;
326
327 return FALSE;
328}
329
330/*
331 * Curl_sasl_start()
332 *
333 * Calculate the required login details for SASL authentication.
334 */
335CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
336 bool force_ir, saslprogress *progress)
337{
338 CURLcode result = CURLE_OK;
339 struct connectdata *conn = data->conn;
340 unsigned short enabledmechs;
341 const char *mech = NULL;
342 struct bufref resp;
343 saslstate state1 = SASL_STOP;
344 saslstate state2 = SASL_FINAL;
345 const char *hostname, *disp_hostname;
346 int port;
347#if defined(USE_KERBEROS5) || defined(USE_NTLM)
348 const char *service = data->set.str[STRING_SERVICE_NAME] ?
349 data->set.str[STRING_SERVICE_NAME] :
350 sasl->params->service;
351#endif
352 const char *oauth_bearer = data->set.str[STRING_BEARER];
353 struct bufref nullmsg;
354
355 Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
356 Curl_bufref_init(&nullmsg);
357 Curl_bufref_init(&resp);
358 sasl->force_ir = force_ir; /* Latch for future use */
359 sasl->authused = 0; /* No mechanism used yet */
360 enabledmechs = sasl->authmechs & sasl->prefmech;
361 *progress = SASL_IDLE;
362
363 /* Calculate the supported authentication mechanism, by decreasing order of
364 security, as well as the initial response where appropriate */
365 if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) {
366 mech = SASL_MECH_STRING_EXTERNAL;
367 state1 = SASL_EXTERNAL;
368 sasl->authused = SASL_MECH_EXTERNAL;
369
370 if(force_ir || data->set.sasl_ir)
371 result = Curl_auth_create_external_message(conn->user, &resp);
372 }
373 else if(data->state.aptr.user) {
374#if defined(USE_KERBEROS5)
375 if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() &&
376 Curl_auth_user_contains_domain(conn->user)) {
377 sasl->mutual_auth = FALSE;
378 mech = SASL_MECH_STRING_GSSAPI;
379 state1 = SASL_GSSAPI;
380 state2 = SASL_GSSAPI_TOKEN;
381 sasl->authused = SASL_MECH_GSSAPI;
382
383 if(force_ir || data->set.sasl_ir)
384 result = Curl_auth_create_gssapi_user_message(data, conn->user,
385 conn->passwd,
386 service,
387 conn->host.name,
388 sasl->mutual_auth,
389 NULL, &conn->krb5,
390 &resp);
391 }
392 else
393#endif
394#ifdef USE_GSASL
395 if((enabledmechs & SASL_MECH_SCRAM_SHA_256) &&
396 Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256,
397 &conn->gsasl)) {
398 mech = SASL_MECH_STRING_SCRAM_SHA_256;
399 sasl->authused = SASL_MECH_SCRAM_SHA_256;
400 state1 = SASL_GSASL;
401 state2 = SASL_GSASL;
402
403 result = Curl_auth_gsasl_start(data, conn->user,
404 conn->passwd, &conn->gsasl);
405 if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
406 result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
407 }
408 else if((enabledmechs & SASL_MECH_SCRAM_SHA_1) &&
409 Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1,
410 &conn->gsasl)) {
411 mech = SASL_MECH_STRING_SCRAM_SHA_1;
412 sasl->authused = SASL_MECH_SCRAM_SHA_1;
413 state1 = SASL_GSASL;
414 state2 = SASL_GSASL;
415
416 result = Curl_auth_gsasl_start(data, conn->user,
417 conn->passwd, &conn->gsasl);
418 if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
419 result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
420 }
421 else
422#endif
423#ifndef CURL_DISABLE_DIGEST_AUTH
424 if((enabledmechs & SASL_MECH_DIGEST_MD5) &&
425 Curl_auth_is_digest_supported()) {
426 mech = SASL_MECH_STRING_DIGEST_MD5;
427 state1 = SASL_DIGESTMD5;
428 sasl->authused = SASL_MECH_DIGEST_MD5;
429 }
430 else if(enabledmechs & SASL_MECH_CRAM_MD5) {
431 mech = SASL_MECH_STRING_CRAM_MD5;
432 state1 = SASL_CRAMMD5;
433 sasl->authused = SASL_MECH_CRAM_MD5;
434 }
435 else
436#endif
437#ifdef USE_NTLM
438 if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) {
439 mech = SASL_MECH_STRING_NTLM;
440 state1 = SASL_NTLM;
441 state2 = SASL_NTLM_TYPE2MSG;
442 sasl->authused = SASL_MECH_NTLM;
443
444 if(force_ir || data->set.sasl_ir)
445 result = Curl_auth_create_ntlm_type1_message(data,
446 conn->user, conn->passwd,
447 service,
448 hostname,
449 &conn->ntlm, &resp);
450 }
451 else
452#endif
453 if((enabledmechs & SASL_MECH_OAUTHBEARER) && oauth_bearer) {
454 mech = SASL_MECH_STRING_OAUTHBEARER;
455 state1 = SASL_OAUTH2;
456 state2 = SASL_OAUTH2_RESP;
457 sasl->authused = SASL_MECH_OAUTHBEARER;
458
459 if(force_ir || data->set.sasl_ir)
460 result = Curl_auth_create_oauth_bearer_message(conn->user,
461 hostname,
462 port,
463 oauth_bearer,
464 &resp);
465 }
466 else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) {
467 mech = SASL_MECH_STRING_XOAUTH2;
468 state1 = SASL_OAUTH2;
469 sasl->authused = SASL_MECH_XOAUTH2;
470
471 if(force_ir || data->set.sasl_ir)
472 result = Curl_auth_create_xoauth_bearer_message(conn->user,
473 oauth_bearer,
474 &resp);
475 }
476 else if(enabledmechs & SASL_MECH_PLAIN) {
477 mech = SASL_MECH_STRING_PLAIN;
478 state1 = SASL_PLAIN;
479 sasl->authused = SASL_MECH_PLAIN;
480
481 if(force_ir || data->set.sasl_ir)
482 result = Curl_auth_create_plain_message(conn->sasl_authzid,
483 conn->user, conn->passwd,
484 &resp);
485 }
486 else if(enabledmechs & SASL_MECH_LOGIN) {
487 mech = SASL_MECH_STRING_LOGIN;
488 state1 = SASL_LOGIN;
489 state2 = SASL_LOGIN_PASSWD;
490 sasl->authused = SASL_MECH_LOGIN;
491
492 if(force_ir || data->set.sasl_ir)
493 result = Curl_auth_create_login_message(conn->user, &resp);
494 }
495 }
496
497 if(!result && mech) {
498 sasl->curmech = mech;
499 if(Curl_bufref_ptr(&resp))
500 result = build_message(sasl, &resp);
501
502 if(sasl->params->maxirlen &&
503 strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen)
504 Curl_bufref_free(&resp);
505
506 if(!result)
507 result = sasl->params->sendauth(data, mech, &resp);
508
509 if(!result) {
510 *progress = SASL_INPROGRESS;
511 sasl_state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1);
512 }
513 }
514
515 Curl_bufref_free(&resp);
516 return result;
517}
518
519/*
520 * Curl_sasl_continue()
521 *
522 * Continue the authentication.
523 */
524CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
525 int code, saslprogress *progress)
526{
527 CURLcode result = CURLE_OK;
528 struct connectdata *conn = data->conn;
529 saslstate newstate = SASL_FINAL;
530 struct bufref resp;
531 const char *hostname, *disp_hostname;
532 int port;
533#if defined(USE_KERBEROS5) || defined(USE_NTLM) \
534 || !defined(CURL_DISABLE_DIGEST_AUTH)
535 const char *service = data->set.str[STRING_SERVICE_NAME] ?
536 data->set.str[STRING_SERVICE_NAME] :
537 sasl->params->service;
538#endif
539 const char *oauth_bearer = data->set.str[STRING_BEARER];
540 struct bufref serverdata;
541
542 Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
543 Curl_bufref_init(&serverdata);
544 Curl_bufref_init(&resp);
545 *progress = SASL_INPROGRESS;
546
547 if(sasl->state == SASL_FINAL) {
548 if(code != sasl->params->finalcode)
549 result = CURLE_LOGIN_DENIED;
550 *progress = SASL_DONE;
551 sasl_state(sasl, data, SASL_STOP);
552 return result;
553 }
554
555 if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP &&
556 code != sasl->params->contcode) {
557 *progress = SASL_DONE;
558 sasl_state(sasl, data, SASL_STOP);
559 return CURLE_LOGIN_DENIED;
560 }
561
562 switch(sasl->state) {
563 case SASL_STOP:
564 *progress = SASL_DONE;
565 return result;
566 case SASL_PLAIN:
567 result = Curl_auth_create_plain_message(conn->sasl_authzid,
568 conn->user, conn->passwd, &resp);
569 break;
570 case SASL_LOGIN:
571 result = Curl_auth_create_login_message(conn->user, &resp);
572 newstate = SASL_LOGIN_PASSWD;
573 break;
574 case SASL_LOGIN_PASSWD:
575 result = Curl_auth_create_login_message(conn->passwd, &resp);
576 break;
577 case SASL_EXTERNAL:
578 result = Curl_auth_create_external_message(conn->user, &resp);
579 break;
580#ifdef USE_GSASL
581 case SASL_GSASL:
582 result = get_server_message(sasl, data, &serverdata);
583 if(!result)
584 result = Curl_auth_gsasl_token(data, &serverdata, &conn->gsasl, &resp);
585 if(!result && Curl_bufref_len(&resp) > 0)
586 newstate = SASL_GSASL;
587 break;
588#endif
589#ifndef CURL_DISABLE_DIGEST_AUTH
590 case SASL_CRAMMD5:
591 result = get_server_message(sasl, data, &serverdata);
592 if(!result)
593 result = Curl_auth_create_cram_md5_message(&serverdata, conn->user,
594 conn->passwd, &resp);
595 break;
596 case SASL_DIGESTMD5:
597 result = get_server_message(sasl, data, &serverdata);
598 if(!result)
599 result = Curl_auth_create_digest_md5_message(data, &serverdata,
600 conn->user, conn->passwd,
601 service, &resp);
602 if(!result && (sasl->params->flags & SASL_FLAG_BASE64))
603 newstate = SASL_DIGESTMD5_RESP;
604 break;
605 case SASL_DIGESTMD5_RESP:
606 /* Keep response NULL to output an empty line. */
607 break;
608#endif
609
610#ifdef USE_NTLM
611 case SASL_NTLM:
612 /* Create the type-1 message */
613 result = Curl_auth_create_ntlm_type1_message(data,
614 conn->user, conn->passwd,
615 service, hostname,
616 &conn->ntlm, &resp);
617 newstate = SASL_NTLM_TYPE2MSG;
618 break;
619 case SASL_NTLM_TYPE2MSG:
620 /* Decode the type-2 message */
621 result = get_server_message(sasl, data, &serverdata);
622 if(!result)
623 result = Curl_auth_decode_ntlm_type2_message(data, &serverdata,
624 &conn->ntlm);
625 if(!result)
626 result = Curl_auth_create_ntlm_type3_message(data, conn->user,
627 conn->passwd, &conn->ntlm,
628 &resp);
629 break;
630#endif
631
632#if defined(USE_KERBEROS5)
633 case SASL_GSSAPI:
634 result = Curl_auth_create_gssapi_user_message(data, conn->user,
635 conn->passwd,
636 service,
637 conn->host.name,
638 sasl->mutual_auth, NULL,
639 &conn->krb5,
640 &resp);
641 newstate = SASL_GSSAPI_TOKEN;
642 break;
643 case SASL_GSSAPI_TOKEN:
644 result = get_server_message(sasl, data, &serverdata);
645 if(!result) {
646 if(sasl->mutual_auth) {
647 /* Decode the user token challenge and create the optional response
648 message */
649 result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
650 NULL, NULL,
651 sasl->mutual_auth,
652 &serverdata,
653 &conn->krb5,
654 &resp);
655 newstate = SASL_GSSAPI_NO_DATA;
656 }
657 else
658 /* Decode the security challenge and create the response message */
659 result = Curl_auth_create_gssapi_security_message(data,
660 conn->sasl_authzid,
661 &serverdata,
662 &conn->krb5,
663 &resp);
664 }
665 break;
666 case SASL_GSSAPI_NO_DATA:
667 /* Decode the security challenge and create the response message */
668 result = get_server_message(sasl, data, &serverdata);
669 if(!result)
670 result = Curl_auth_create_gssapi_security_message(data,
671 conn->sasl_authzid,
672 &serverdata,
673 &conn->krb5,
674 &resp);
675 break;
676#endif
677
678 case SASL_OAUTH2:
679 /* Create the authorization message */
680 if(sasl->authused == SASL_MECH_OAUTHBEARER) {
681 result = Curl_auth_create_oauth_bearer_message(conn->user,
682 hostname,
683 port,
684 oauth_bearer,
685 &resp);
686
687 /* Failures maybe sent by the server as continuations for OAUTHBEARER */
688 newstate = SASL_OAUTH2_RESP;
689 }
690 else
691 result = Curl_auth_create_xoauth_bearer_message(conn->user,
692 oauth_bearer,
693 &resp);
694 break;
695
696 case SASL_OAUTH2_RESP:
697 /* The continuation is optional so check the response code */
698 if(code == sasl->params->finalcode) {
699 /* Final response was received so we are done */
700 *progress = SASL_DONE;
701 sasl_state(sasl, data, SASL_STOP);
702 return result;
703 }
704 else if(code == sasl->params->contcode) {
705 /* Acknowledge the continuation by sending a 0x01 response. */
706 Curl_bufref_set(&resp, "\x01", 1, NULL);
707 break;
708 }
709 else {
710 *progress = SASL_DONE;
711 sasl_state(sasl, data, SASL_STOP);
712 return CURLE_LOGIN_DENIED;
713 }
714
715 case SASL_CANCEL:
716 /* Remove the offending mechanism from the supported list */
717 sasl->authmechs ^= sasl->authused;
718
719 /* Start an alternative SASL authentication */
720 return Curl_sasl_start(sasl, data, sasl->force_ir, progress);
721 default:
722 failf(data, "Unsupported SASL authentication mechanism");
723 result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */
724 break;
725 }
726
727 Curl_bufref_free(&serverdata);
728
729 switch(result) {
730 case CURLE_BAD_CONTENT_ENCODING:
731 /* Cancel dialog */
732 result = sasl->params->cancelauth(data, sasl->curmech);
733 newstate = SASL_CANCEL;
734 break;
735 case CURLE_OK:
736 result = build_message(sasl, &resp);
737 if(!result)
738 result = sasl->params->contauth(data, sasl->curmech, &resp);
739 break;
740 default:
741 newstate = SASL_STOP; /* Stop on error */
742 *progress = SASL_DONE;
743 break;
744 }
745
746 Curl_bufref_free(&resp);
747
748 sasl_state(sasl, data, newstate);
749
750 return result;
751}
752#endif /* protocols are enabled that use SASL */
753