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 unsigned short mechs = SASL_AUTH_NONE; 209 210 /* If some usable http authentication options have been set, determine 211 new defaults from them. */ 212 if(auth & CURLAUTH_BASIC) 213 mechs |= SASL_MECH_PLAIN | SASL_MECH_LOGIN; 214 if(auth & CURLAUTH_DIGEST) 215 mechs |= SASL_MECH_DIGEST_MD5; 216 if(auth & CURLAUTH_NTLM) 217 mechs |= SASL_MECH_NTLM; 218 if(auth & CURLAUTH_BEARER) 219 mechs |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2; 220 if(auth & CURLAUTH_GSSAPI) 221 mechs |= SASL_MECH_GSSAPI; 222 223 if(mechs != SASL_AUTH_NONE) 224 sasl->prefmech = mechs; 225 } 226} 227 228/* 229 * sasl_state() 230 * 231 * This is the ONLY way to change SASL state! 232 */ 233static void sasl_state(struct SASL *sasl, struct Curl_easy *data, 234 saslstate newstate) 235{ 236#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) 237 /* for debug purposes */ 238 static const char * const names[]={ 239 "STOP", 240 "PLAIN", 241 "LOGIN", 242 "LOGIN_PASSWD", 243 "EXTERNAL", 244 "CRAMMD5", 245 "DIGESTMD5", 246 "DIGESTMD5_RESP", 247 "NTLM", 248 "NTLM_TYPE2MSG", 249 "GSSAPI", 250 "GSSAPI_TOKEN", 251 "GSSAPI_NO_DATA", 252 "OAUTH2", 253 "OAUTH2_RESP", 254 "GSASL", 255 "CANCEL", 256 "FINAL", 257 /* LAST */ 258 }; 259 260 if(sasl->state != newstate) 261 infof(data, "SASL %p state change from %s to %s", 262 (void *)sasl, names[sasl->state], names[newstate]); 263#else 264 (void) data; 265#endif 266 267 sasl->state = newstate; 268} 269 270#if defined(USE_NTLM) || defined(USE_GSASL) || defined(USE_KERBEROS5) || \ 271 !defined(CURL_DISABLE_DIGEST_AUTH) 272/* Get the SASL server message and convert it to binary. */ 273static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data, 274 struct bufref *out) 275{ 276 CURLcode result = CURLE_OK; 277 278 result = sasl->params->getmessage(data, out); 279 if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) { 280 unsigned char *msg; 281 size_t msglen; 282 const char *serverdata = (const char *) Curl_bufref_ptr(out); 283 284 if(!*serverdata || *serverdata == '=') 285 Curl_bufref_set(out, NULL, 0, NULL); 286 else { 287 result = Curl_base64_decode(serverdata, &msg, &msglen); 288 if(!result) 289 Curl_bufref_set(out, msg, msglen, curl_free); 290 } 291 } 292 return result; 293} 294#endif 295 296/* Encode the outgoing SASL message. */ 297static CURLcode build_message(struct SASL *sasl, struct bufref *msg) 298{ 299 CURLcode result = CURLE_OK; 300 301 if(sasl->params->flags & SASL_FLAG_BASE64) { 302 if(!Curl_bufref_ptr(msg)) /* Empty message. */ 303 Curl_bufref_set(msg, "", 0, NULL); 304 else if(!Curl_bufref_len(msg)) /* Explicit empty response. */ 305 Curl_bufref_set(msg, "=", 1, NULL); 306 else { 307 char *base64; 308 size_t base64len; 309 310 result = Curl_base64_encode((const char *) Curl_bufref_ptr(msg), 311 Curl_bufref_len(msg), &base64, &base64len); 312 if(!result) 313 Curl_bufref_set(msg, base64, base64len, curl_free); 314 } 315 } 316 317 return result; 318} 319 320/* 321 * Curl_sasl_can_authenticate() 322 * 323 * Check if we have enough auth data and capabilities to authenticate. 324 */ 325bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data) 326{ 327 /* Have credentials been provided? */ 328 if(data->state.aptr.user) 329 return TRUE; 330 331 /* EXTERNAL can authenticate without a user name and/or password */ 332 if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL) 333 return TRUE; 334 335 return FALSE; 336} 337 338/* 339 * Curl_sasl_start() 340 * 341 * Calculate the required login details for SASL authentication. 342 */ 343CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data, 344 bool force_ir, saslprogress *progress) 345{ 346 CURLcode result = CURLE_OK; 347 struct connectdata *conn = data->conn; 348 unsigned short enabledmechs; 349 const char *mech = NULL; 350 struct bufref resp; 351 saslstate state1 = SASL_STOP; 352 saslstate state2 = SASL_FINAL; 353 const char *hostname, *disp_hostname; 354 int port; 355#if defined(USE_KERBEROS5) || defined(USE_NTLM) 356 const char *service = data->set.str[STRING_SERVICE_NAME] ? 357 data->set.str[STRING_SERVICE_NAME] : 358 sasl->params->service; 359#endif 360 const char *oauth_bearer = data->set.str[STRING_BEARER]; 361 struct bufref nullmsg; 362 363 Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port); 364 Curl_bufref_init(&nullmsg); 365 Curl_bufref_init(&resp); 366 sasl->force_ir = force_ir; /* Latch for future use */ 367 sasl->authused = 0; /* No mechanism used yet */ 368 enabledmechs = sasl->authmechs & sasl->prefmech; 369 *progress = SASL_IDLE; 370 371 /* Calculate the supported authentication mechanism, by decreasing order of 372 security, as well as the initial response where appropriate */ 373 if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) { 374 mech = SASL_MECH_STRING_EXTERNAL; 375 state1 = SASL_EXTERNAL; 376 sasl->authused = SASL_MECH_EXTERNAL; 377 378 if(force_ir || data->set.sasl_ir) 379 result = Curl_auth_create_external_message(conn->user, &resp); 380 } 381 else if(data->state.aptr.user) { 382#if defined(USE_KERBEROS5) 383 if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() && 384 Curl_auth_user_contains_domain(conn->user)) { 385 sasl->mutual_auth = FALSE; 386 mech = SASL_MECH_STRING_GSSAPI; 387 state1 = SASL_GSSAPI; 388 state2 = SASL_GSSAPI_TOKEN; 389 sasl->authused = SASL_MECH_GSSAPI; 390 391 if(force_ir || data->set.sasl_ir) 392 result = Curl_auth_create_gssapi_user_message(data, conn->user, 393 conn->passwd, 394 service, 395 conn->host.name, 396 sasl->mutual_auth, 397 NULL, &conn->krb5, 398 &resp); 399 } 400 else 401#endif 402#ifdef USE_GSASL 403 if((enabledmechs & SASL_MECH_SCRAM_SHA_256) && 404 Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256, 405 &conn->gsasl)) { 406 mech = SASL_MECH_STRING_SCRAM_SHA_256; 407 sasl->authused = SASL_MECH_SCRAM_SHA_256; 408 state1 = SASL_GSASL; 409 state2 = SASL_GSASL; 410 411 result = Curl_auth_gsasl_start(data, conn->user, 412 conn->passwd, &conn->gsasl); 413 if(result == CURLE_OK && (force_ir || data->set.sasl_ir)) 414 result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp); 415 } 416 else if((enabledmechs & SASL_MECH_SCRAM_SHA_1) && 417 Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1, 418 &conn->gsasl)) { 419 mech = SASL_MECH_STRING_SCRAM_SHA_1; 420 sasl->authused = SASL_MECH_SCRAM_SHA_1; 421 state1 = SASL_GSASL; 422 state2 = SASL_GSASL; 423 424 result = Curl_auth_gsasl_start(data, conn->user, 425 conn->passwd, &conn->gsasl); 426 if(result == CURLE_OK && (force_ir || data->set.sasl_ir)) 427 result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp); 428 } 429 else 430#endif 431#ifndef CURL_DISABLE_DIGEST_AUTH 432 if((enabledmechs & SASL_MECH_DIGEST_MD5) && 433 Curl_auth_is_digest_supported()) { 434 mech = SASL_MECH_STRING_DIGEST_MD5; 435 state1 = SASL_DIGESTMD5; 436 sasl->authused = SASL_MECH_DIGEST_MD5; 437 } 438 else if(enabledmechs & SASL_MECH_CRAM_MD5) { 439 mech = SASL_MECH_STRING_CRAM_MD5; 440 state1 = SASL_CRAMMD5; 441 sasl->authused = SASL_MECH_CRAM_MD5; 442 } 443 else 444#endif 445#ifdef USE_NTLM 446 if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) { 447 mech = SASL_MECH_STRING_NTLM; 448 state1 = SASL_NTLM; 449 state2 = SASL_NTLM_TYPE2MSG; 450 sasl->authused = SASL_MECH_NTLM; 451 452 if(force_ir || data->set.sasl_ir) 453 result = Curl_auth_create_ntlm_type1_message(data, 454 conn->user, conn->passwd, 455 service, 456 hostname, 457 &conn->ntlm, &resp); 458 } 459 else 460#endif 461 if((enabledmechs & SASL_MECH_OAUTHBEARER) && oauth_bearer) { 462 mech = SASL_MECH_STRING_OAUTHBEARER; 463 state1 = SASL_OAUTH2; 464 state2 = SASL_OAUTH2_RESP; 465 sasl->authused = SASL_MECH_OAUTHBEARER; 466 467 if(force_ir || data->set.sasl_ir) 468 result = Curl_auth_create_oauth_bearer_message(conn->user, 469 hostname, 470 port, 471 oauth_bearer, 472 &resp); 473 } 474 else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) { 475 mech = SASL_MECH_STRING_XOAUTH2; 476 state1 = SASL_OAUTH2; 477 sasl->authused = SASL_MECH_XOAUTH2; 478 479 if(force_ir || data->set.sasl_ir) 480 result = Curl_auth_create_xoauth_bearer_message(conn->user, 481 oauth_bearer, 482 &resp); 483 } 484 else if(enabledmechs & SASL_MECH_PLAIN) { 485 mech = SASL_MECH_STRING_PLAIN; 486 state1 = SASL_PLAIN; 487 sasl->authused = SASL_MECH_PLAIN; 488 489 if(force_ir || data->set.sasl_ir) 490 result = Curl_auth_create_plain_message(conn->sasl_authzid, 491 conn->user, conn->passwd, 492 &resp); 493 } 494 else if(enabledmechs & SASL_MECH_LOGIN) { 495 mech = SASL_MECH_STRING_LOGIN; 496 state1 = SASL_LOGIN; 497 state2 = SASL_LOGIN_PASSWD; 498 sasl->authused = SASL_MECH_LOGIN; 499 500 if(force_ir || data->set.sasl_ir) 501 result = Curl_auth_create_login_message(conn->user, &resp); 502 } 503 } 504 505 if(!result && mech) { 506 sasl->curmech = mech; 507 if(Curl_bufref_ptr(&resp)) 508 result = build_message(sasl, &resp); 509 510 if(sasl->params->maxirlen && 511 strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen) 512 Curl_bufref_free(&resp); 513 514 if(!result) 515 result = sasl->params->sendauth(data, mech, &resp); 516 517 if(!result) { 518 *progress = SASL_INPROGRESS; 519 sasl_state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1); 520 } 521 } 522 523 Curl_bufref_free(&resp); 524 return result; 525} 526 527/* 528 * Curl_sasl_continue() 529 * 530 * Continue the authentication. 531 */ 532CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, 533 int code, saslprogress *progress) 534{ 535 CURLcode result = CURLE_OK; 536 struct connectdata *conn = data->conn; 537 saslstate newstate = SASL_FINAL; 538 struct bufref resp; 539 const char *hostname, *disp_hostname; 540 int port; 541#if defined(USE_KERBEROS5) || defined(USE_NTLM) \ 542 || !defined(CURL_DISABLE_DIGEST_AUTH) 543 const char *service = data->set.str[STRING_SERVICE_NAME] ? 544 data->set.str[STRING_SERVICE_NAME] : 545 sasl->params->service; 546#endif 547 const char *oauth_bearer = data->set.str[STRING_BEARER]; 548 struct bufref serverdata; 549 550 Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port); 551 Curl_bufref_init(&serverdata); 552 Curl_bufref_init(&resp); 553 *progress = SASL_INPROGRESS; 554 555 if(sasl->state == SASL_FINAL) { 556 if(code != sasl->params->finalcode) 557 result = CURLE_LOGIN_DENIED; 558 *progress = SASL_DONE; 559 sasl_state(sasl, data, SASL_STOP); 560 return result; 561 } 562 563 if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP && 564 code != sasl->params->contcode) { 565 *progress = SASL_DONE; 566 sasl_state(sasl, data, SASL_STOP); 567 return CURLE_LOGIN_DENIED; 568 } 569 570 switch(sasl->state) { 571 case SASL_STOP: 572 *progress = SASL_DONE; 573 return result; 574 case SASL_PLAIN: 575 result = Curl_auth_create_plain_message(conn->sasl_authzid, 576 conn->user, conn->passwd, &resp); 577 break; 578 case SASL_LOGIN: 579 result = Curl_auth_create_login_message(conn->user, &resp); 580 newstate = SASL_LOGIN_PASSWD; 581 break; 582 case SASL_LOGIN_PASSWD: 583 result = Curl_auth_create_login_message(conn->passwd, &resp); 584 break; 585 case SASL_EXTERNAL: 586 result = Curl_auth_create_external_message(conn->user, &resp); 587 break; 588#ifdef USE_GSASL 589 case SASL_GSASL: 590 result = get_server_message(sasl, data, &serverdata); 591 if(!result) 592 result = Curl_auth_gsasl_token(data, &serverdata, &conn->gsasl, &resp); 593 if(!result && Curl_bufref_len(&resp) > 0) 594 newstate = SASL_GSASL; 595 break; 596#endif 597#ifndef CURL_DISABLE_DIGEST_AUTH 598 case SASL_CRAMMD5: 599 result = get_server_message(sasl, data, &serverdata); 600 if(!result) 601 result = Curl_auth_create_cram_md5_message(&serverdata, conn->user, 602 conn->passwd, &resp); 603 break; 604 case SASL_DIGESTMD5: 605 result = get_server_message(sasl, data, &serverdata); 606 if(!result) 607 result = Curl_auth_create_digest_md5_message(data, &serverdata, 608 conn->user, conn->passwd, 609 service, &resp); 610 if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) 611 newstate = SASL_DIGESTMD5_RESP; 612 break; 613 case SASL_DIGESTMD5_RESP: 614 /* Keep response NULL to output an empty line. */ 615 break; 616#endif 617 618#ifdef USE_NTLM 619 case SASL_NTLM: 620 /* Create the type-1 message */ 621 result = Curl_auth_create_ntlm_type1_message(data, 622 conn->user, conn->passwd, 623 service, hostname, 624 &conn->ntlm, &resp); 625 newstate = SASL_NTLM_TYPE2MSG; 626 break; 627 case SASL_NTLM_TYPE2MSG: 628 /* Decode the type-2 message */ 629 result = get_server_message(sasl, data, &serverdata); 630 if(!result) 631 result = Curl_auth_decode_ntlm_type2_message(data, &serverdata, 632 &conn->ntlm); 633 if(!result) 634 result = Curl_auth_create_ntlm_type3_message(data, conn->user, 635 conn->passwd, &conn->ntlm, 636 &resp); 637 break; 638#endif 639 640#if defined(USE_KERBEROS5) 641 case SASL_GSSAPI: 642 result = Curl_auth_create_gssapi_user_message(data, conn->user, 643 conn->passwd, 644 service, 645 conn->host.name, 646 sasl->mutual_auth, NULL, 647 &conn->krb5, 648 &resp); 649 newstate = SASL_GSSAPI_TOKEN; 650 break; 651 case SASL_GSSAPI_TOKEN: 652 result = get_server_message(sasl, data, &serverdata); 653 if(!result) { 654 if(sasl->mutual_auth) { 655 /* Decode the user token challenge and create the optional response 656 message */ 657 result = Curl_auth_create_gssapi_user_message(data, NULL, NULL, 658 NULL, NULL, 659 sasl->mutual_auth, 660 &serverdata, 661 &conn->krb5, 662 &resp); 663 newstate = SASL_GSSAPI_NO_DATA; 664 } 665 else 666 /* Decode the security challenge and create the response message */ 667 result = Curl_auth_create_gssapi_security_message(data, 668 conn->sasl_authzid, 669 &serverdata, 670 &conn->krb5, 671 &resp); 672 } 673 break; 674 case SASL_GSSAPI_NO_DATA: 675 /* Decode the security challenge and create the response message */ 676 result = get_server_message(sasl, data, &serverdata); 677 if(!result) 678 result = Curl_auth_create_gssapi_security_message(data, 679 conn->sasl_authzid, 680 &serverdata, 681 &conn->krb5, 682 &resp); 683 break; 684#endif 685 686 case SASL_OAUTH2: 687 /* Create the authorization message */ 688 if(sasl->authused == SASL_MECH_OAUTHBEARER) { 689 result = Curl_auth_create_oauth_bearer_message(conn->user, 690 hostname, 691 port, 692 oauth_bearer, 693 &resp); 694 695 /* Failures maybe sent by the server as continuations for OAUTHBEARER */ 696 newstate = SASL_OAUTH2_RESP; 697 } 698 else 699 result = Curl_auth_create_xoauth_bearer_message(conn->user, 700 oauth_bearer, 701 &resp); 702 break; 703 704 case SASL_OAUTH2_RESP: 705 /* The continuation is optional so check the response code */ 706 if(code == sasl->params->finalcode) { 707 /* Final response was received so we are done */ 708 *progress = SASL_DONE; 709 sasl_state(sasl, data, SASL_STOP); 710 return result; 711 } 712 else if(code == sasl->params->contcode) { 713 /* Acknowledge the continuation by sending a 0x01 response. */ 714 Curl_bufref_set(&resp, "\x01", 1, NULL); 715 break; 716 } 717 else { 718 *progress = SASL_DONE; 719 sasl_state(sasl, data, SASL_STOP); 720 return CURLE_LOGIN_DENIED; 721 } 722 723 case SASL_CANCEL: 724 /* Remove the offending mechanism from the supported list */ 725 sasl->authmechs ^= sasl->authused; 726 727 /* Start an alternative SASL authentication */ 728 return Curl_sasl_start(sasl, data, sasl->force_ir, progress); 729 default: 730 failf(data, "Unsupported SASL authentication mechanism"); 731 result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */ 732 break; 733 } 734 735 Curl_bufref_free(&serverdata); 736 737 switch(result) { 738 case CURLE_BAD_CONTENT_ENCODING: 739 /* Cancel dialog */ 740 result = sasl->params->cancelauth(data, sasl->curmech); 741 newstate = SASL_CANCEL; 742 break; 743 case CURLE_OK: 744 result = build_message(sasl, &resp); 745 if(!result) 746 result = sasl->params->contauth(data, sasl->curmech, &resp); 747 break; 748 default: 749 newstate = SASL_STOP; /* Stop on error */ 750 *progress = SASL_DONE; 751 break; 752 } 753 754 Curl_bufref_free(&resp); 755 756 sasl_state(sasl, data, newstate); 757 758 return result; 759} 760#endif /* protocols are enabled that use SASL */ 761