113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                                  _   _ ____  _
313498266Sopenharmony_ci *  Project                     ___| | | |  _ \| |
413498266Sopenharmony_ci *                             / __| | | | |_) | |
513498266Sopenharmony_ci *                            | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                             \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
913498266Sopenharmony_ci *
1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1313498266Sopenharmony_ci *
1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1713498266Sopenharmony_ci *
1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1913498266Sopenharmony_ci * KIND, either express or implied.
2013498266Sopenharmony_ci *
2113498266Sopenharmony_ci * SPDX-License-Identifier: curl
2213498266Sopenharmony_ci *
2313498266Sopenharmony_ci * RFC2195 CRAM-MD5 authentication
2413498266Sopenharmony_ci * RFC2617 Basic and Digest Access Authentication
2513498266Sopenharmony_ci * RFC2831 DIGEST-MD5 authentication
2613498266Sopenharmony_ci * RFC4422 Simple Authentication and Security Layer (SASL)
2713498266Sopenharmony_ci * RFC4616 PLAIN authentication
2813498266Sopenharmony_ci * RFC5802 SCRAM-SHA-1 authentication
2913498266Sopenharmony_ci * RFC7677 SCRAM-SHA-256 authentication
3013498266Sopenharmony_ci * RFC6749 OAuth 2.0 Authorization Framework
3113498266Sopenharmony_ci * RFC7628 A Set of SASL Mechanisms for OAuth
3213498266Sopenharmony_ci * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
3313498266Sopenharmony_ci *
3413498266Sopenharmony_ci ***************************************************************************/
3513498266Sopenharmony_ci
3613498266Sopenharmony_ci#include "curl_setup.h"
3713498266Sopenharmony_ci
3813498266Sopenharmony_ci#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) || \
3913498266Sopenharmony_ci  !defined(CURL_DISABLE_POP3) || \
4013498266Sopenharmony_ci  (!defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP))
4113498266Sopenharmony_ci
4213498266Sopenharmony_ci#include <curl/curl.h>
4313498266Sopenharmony_ci#include "urldata.h"
4413498266Sopenharmony_ci
4513498266Sopenharmony_ci#include "curl_base64.h"
4613498266Sopenharmony_ci#include "curl_md5.h"
4713498266Sopenharmony_ci#include "vauth/vauth.h"
4813498266Sopenharmony_ci#include "cfilters.h"
4913498266Sopenharmony_ci#include "vtls/vtls.h"
5013498266Sopenharmony_ci#include "curl_hmac.h"
5113498266Sopenharmony_ci#include "curl_sasl.h"
5213498266Sopenharmony_ci#include "warnless.h"
5313498266Sopenharmony_ci#include "strtok.h"
5413498266Sopenharmony_ci#include "sendf.h"
5513498266Sopenharmony_ci/* The last 3 #include files should be in this order */
5613498266Sopenharmony_ci#include "curl_printf.h"
5713498266Sopenharmony_ci#include "curl_memory.h"
5813498266Sopenharmony_ci#include "memdebug.h"
5913498266Sopenharmony_ci
6013498266Sopenharmony_ci/* Supported mechanisms */
6113498266Sopenharmony_cistatic const struct {
6213498266Sopenharmony_ci  const char    *name;  /* Name */
6313498266Sopenharmony_ci  size_t         len;   /* Name length */
6413498266Sopenharmony_ci  unsigned short bit;   /* Flag bit */
6513498266Sopenharmony_ci} mechtable[] = {
6613498266Sopenharmony_ci  { "LOGIN",        5,  SASL_MECH_LOGIN },
6713498266Sopenharmony_ci  { "PLAIN",        5,  SASL_MECH_PLAIN },
6813498266Sopenharmony_ci  { "CRAM-MD5",     8,  SASL_MECH_CRAM_MD5 },
6913498266Sopenharmony_ci  { "DIGEST-MD5",   10, SASL_MECH_DIGEST_MD5 },
7013498266Sopenharmony_ci  { "GSSAPI",       6,  SASL_MECH_GSSAPI },
7113498266Sopenharmony_ci  { "EXTERNAL",     8,  SASL_MECH_EXTERNAL },
7213498266Sopenharmony_ci  { "NTLM",         4,  SASL_MECH_NTLM },
7313498266Sopenharmony_ci  { "XOAUTH2",      7,  SASL_MECH_XOAUTH2 },
7413498266Sopenharmony_ci  { "OAUTHBEARER",  11, SASL_MECH_OAUTHBEARER },
7513498266Sopenharmony_ci  { "SCRAM-SHA-1",  11, SASL_MECH_SCRAM_SHA_1 },
7613498266Sopenharmony_ci  { "SCRAM-SHA-256",13, SASL_MECH_SCRAM_SHA_256 },
7713498266Sopenharmony_ci  { ZERO_NULL,      0,  0 }
7813498266Sopenharmony_ci};
7913498266Sopenharmony_ci
8013498266Sopenharmony_ci/*
8113498266Sopenharmony_ci * Curl_sasl_cleanup()
8213498266Sopenharmony_ci *
8313498266Sopenharmony_ci * This is used to cleanup any libraries or curl modules used by the sasl
8413498266Sopenharmony_ci * functions.
8513498266Sopenharmony_ci *
8613498266Sopenharmony_ci * Parameters:
8713498266Sopenharmony_ci *
8813498266Sopenharmony_ci * conn     [in]     - The connection data.
8913498266Sopenharmony_ci * authused [in]     - The authentication mechanism used.
9013498266Sopenharmony_ci */
9113498266Sopenharmony_civoid Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused)
9213498266Sopenharmony_ci{
9313498266Sopenharmony_ci  (void)conn;
9413498266Sopenharmony_ci  (void)authused;
9513498266Sopenharmony_ci
9613498266Sopenharmony_ci#if defined(USE_KERBEROS5)
9713498266Sopenharmony_ci  /* Cleanup the gssapi structure */
9813498266Sopenharmony_ci  if(authused == SASL_MECH_GSSAPI) {
9913498266Sopenharmony_ci    Curl_auth_cleanup_gssapi(&conn->krb5);
10013498266Sopenharmony_ci  }
10113498266Sopenharmony_ci#endif
10213498266Sopenharmony_ci
10313498266Sopenharmony_ci#if defined(USE_GSASL)
10413498266Sopenharmony_ci  /* Cleanup the GSASL structure */
10513498266Sopenharmony_ci  if(authused & (SASL_MECH_SCRAM_SHA_1 | SASL_MECH_SCRAM_SHA_256)) {
10613498266Sopenharmony_ci    Curl_auth_gsasl_cleanup(&conn->gsasl);
10713498266Sopenharmony_ci  }
10813498266Sopenharmony_ci#endif
10913498266Sopenharmony_ci
11013498266Sopenharmony_ci#if defined(USE_NTLM)
11113498266Sopenharmony_ci  /* Cleanup the NTLM structure */
11213498266Sopenharmony_ci  if(authused == SASL_MECH_NTLM) {
11313498266Sopenharmony_ci    Curl_auth_cleanup_ntlm(&conn->ntlm);
11413498266Sopenharmony_ci  }
11513498266Sopenharmony_ci#endif
11613498266Sopenharmony_ci}
11713498266Sopenharmony_ci
11813498266Sopenharmony_ci/*
11913498266Sopenharmony_ci * Curl_sasl_decode_mech()
12013498266Sopenharmony_ci *
12113498266Sopenharmony_ci * Convert a SASL mechanism name into a token.
12213498266Sopenharmony_ci *
12313498266Sopenharmony_ci * Parameters:
12413498266Sopenharmony_ci *
12513498266Sopenharmony_ci * ptr    [in]     - The mechanism string.
12613498266Sopenharmony_ci * maxlen [in]     - Maximum mechanism string length.
12713498266Sopenharmony_ci * len    [out]    - If not NULL, effective name length.
12813498266Sopenharmony_ci *
12913498266Sopenharmony_ci * Returns the SASL mechanism token or 0 if no match.
13013498266Sopenharmony_ci */
13113498266Sopenharmony_ciunsigned short Curl_sasl_decode_mech(const char *ptr, size_t maxlen,
13213498266Sopenharmony_ci                                     size_t *len)
13313498266Sopenharmony_ci{
13413498266Sopenharmony_ci  unsigned int i;
13513498266Sopenharmony_ci  char c;
13613498266Sopenharmony_ci
13713498266Sopenharmony_ci  for(i = 0; mechtable[i].name; i++) {
13813498266Sopenharmony_ci    if(maxlen >= mechtable[i].len &&
13913498266Sopenharmony_ci       !memcmp(ptr, mechtable[i].name, mechtable[i].len)) {
14013498266Sopenharmony_ci      if(len)
14113498266Sopenharmony_ci        *len = mechtable[i].len;
14213498266Sopenharmony_ci
14313498266Sopenharmony_ci      if(maxlen == mechtable[i].len)
14413498266Sopenharmony_ci        return mechtable[i].bit;
14513498266Sopenharmony_ci
14613498266Sopenharmony_ci      c = ptr[mechtable[i].len];
14713498266Sopenharmony_ci      if(!ISUPPER(c) && !ISDIGIT(c) && c != '-' && c != '_')
14813498266Sopenharmony_ci        return mechtable[i].bit;
14913498266Sopenharmony_ci    }
15013498266Sopenharmony_ci  }
15113498266Sopenharmony_ci
15213498266Sopenharmony_ci  return 0;
15313498266Sopenharmony_ci}
15413498266Sopenharmony_ci
15513498266Sopenharmony_ci/*
15613498266Sopenharmony_ci * Curl_sasl_parse_url_auth_option()
15713498266Sopenharmony_ci *
15813498266Sopenharmony_ci * Parse the URL login options.
15913498266Sopenharmony_ci */
16013498266Sopenharmony_ciCURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
16113498266Sopenharmony_ci                                         const char *value, size_t len)
16213498266Sopenharmony_ci{
16313498266Sopenharmony_ci  CURLcode result = CURLE_OK;
16413498266Sopenharmony_ci  size_t mechlen;
16513498266Sopenharmony_ci
16613498266Sopenharmony_ci  if(!len)
16713498266Sopenharmony_ci    return CURLE_URL_MALFORMAT;
16813498266Sopenharmony_ci
16913498266Sopenharmony_ci  if(sasl->resetprefs) {
17013498266Sopenharmony_ci    sasl->resetprefs = FALSE;
17113498266Sopenharmony_ci    sasl->prefmech = SASL_AUTH_NONE;
17213498266Sopenharmony_ci  }
17313498266Sopenharmony_ci
17413498266Sopenharmony_ci  if(!strncmp(value, "*", len))
17513498266Sopenharmony_ci    sasl->prefmech = SASL_AUTH_DEFAULT;
17613498266Sopenharmony_ci  else {
17713498266Sopenharmony_ci    unsigned short mechbit = Curl_sasl_decode_mech(value, len, &mechlen);
17813498266Sopenharmony_ci    if(mechbit && mechlen == len)
17913498266Sopenharmony_ci      sasl->prefmech |= mechbit;
18013498266Sopenharmony_ci    else
18113498266Sopenharmony_ci      result = CURLE_URL_MALFORMAT;
18213498266Sopenharmony_ci  }
18313498266Sopenharmony_ci
18413498266Sopenharmony_ci  return result;
18513498266Sopenharmony_ci}
18613498266Sopenharmony_ci
18713498266Sopenharmony_ci/*
18813498266Sopenharmony_ci * Curl_sasl_init()
18913498266Sopenharmony_ci *
19013498266Sopenharmony_ci * Initializes the SASL structure.
19113498266Sopenharmony_ci */
19213498266Sopenharmony_civoid Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
19313498266Sopenharmony_ci                    const struct SASLproto *params)
19413498266Sopenharmony_ci{
19513498266Sopenharmony_ci  unsigned long auth = data->set.httpauth;
19613498266Sopenharmony_ci
19713498266Sopenharmony_ci  sasl->params = params;           /* Set protocol dependent parameters */
19813498266Sopenharmony_ci  sasl->state = SASL_STOP;         /* Not yet running */
19913498266Sopenharmony_ci  sasl->curmech = NULL;            /* No mechanism yet. */
20013498266Sopenharmony_ci  sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */
20113498266Sopenharmony_ci  sasl->prefmech = params->defmechs; /* Default preferred mechanisms */
20213498266Sopenharmony_ci  sasl->authused = SASL_AUTH_NONE; /* The authentication mechanism used */
20313498266Sopenharmony_ci  sasl->resetprefs = TRUE;         /* Reset prefmech upon AUTH parsing. */
20413498266Sopenharmony_ci  sasl->mutual_auth = FALSE;       /* No mutual authentication (GSSAPI only) */
20513498266Sopenharmony_ci  sasl->force_ir = FALSE;          /* Respect external option */
20613498266Sopenharmony_ci
20713498266Sopenharmony_ci  if(auth != CURLAUTH_BASIC) {
20813498266Sopenharmony_ci    unsigned short mechs = SASL_AUTH_NONE;
20913498266Sopenharmony_ci
21013498266Sopenharmony_ci    /* If some usable http authentication options have been set, determine
21113498266Sopenharmony_ci       new defaults from them. */
21213498266Sopenharmony_ci    if(auth & CURLAUTH_BASIC)
21313498266Sopenharmony_ci      mechs |= SASL_MECH_PLAIN | SASL_MECH_LOGIN;
21413498266Sopenharmony_ci    if(auth & CURLAUTH_DIGEST)
21513498266Sopenharmony_ci      mechs |= SASL_MECH_DIGEST_MD5;
21613498266Sopenharmony_ci    if(auth & CURLAUTH_NTLM)
21713498266Sopenharmony_ci      mechs |= SASL_MECH_NTLM;
21813498266Sopenharmony_ci    if(auth & CURLAUTH_BEARER)
21913498266Sopenharmony_ci      mechs |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2;
22013498266Sopenharmony_ci    if(auth & CURLAUTH_GSSAPI)
22113498266Sopenharmony_ci      mechs |= SASL_MECH_GSSAPI;
22213498266Sopenharmony_ci
22313498266Sopenharmony_ci    if(mechs != SASL_AUTH_NONE)
22413498266Sopenharmony_ci      sasl->prefmech = mechs;
22513498266Sopenharmony_ci  }
22613498266Sopenharmony_ci}
22713498266Sopenharmony_ci
22813498266Sopenharmony_ci/*
22913498266Sopenharmony_ci * sasl_state()
23013498266Sopenharmony_ci *
23113498266Sopenharmony_ci * This is the ONLY way to change SASL state!
23213498266Sopenharmony_ci */
23313498266Sopenharmony_cistatic void sasl_state(struct SASL *sasl, struct Curl_easy *data,
23413498266Sopenharmony_ci                       saslstate newstate)
23513498266Sopenharmony_ci{
23613498266Sopenharmony_ci#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
23713498266Sopenharmony_ci  /* for debug purposes */
23813498266Sopenharmony_ci  static const char * const names[]={
23913498266Sopenharmony_ci    "STOP",
24013498266Sopenharmony_ci    "PLAIN",
24113498266Sopenharmony_ci    "LOGIN",
24213498266Sopenharmony_ci    "LOGIN_PASSWD",
24313498266Sopenharmony_ci    "EXTERNAL",
24413498266Sopenharmony_ci    "CRAMMD5",
24513498266Sopenharmony_ci    "DIGESTMD5",
24613498266Sopenharmony_ci    "DIGESTMD5_RESP",
24713498266Sopenharmony_ci    "NTLM",
24813498266Sopenharmony_ci    "NTLM_TYPE2MSG",
24913498266Sopenharmony_ci    "GSSAPI",
25013498266Sopenharmony_ci    "GSSAPI_TOKEN",
25113498266Sopenharmony_ci    "GSSAPI_NO_DATA",
25213498266Sopenharmony_ci    "OAUTH2",
25313498266Sopenharmony_ci    "OAUTH2_RESP",
25413498266Sopenharmony_ci    "GSASL",
25513498266Sopenharmony_ci    "CANCEL",
25613498266Sopenharmony_ci    "FINAL",
25713498266Sopenharmony_ci    /* LAST */
25813498266Sopenharmony_ci  };
25913498266Sopenharmony_ci
26013498266Sopenharmony_ci  if(sasl->state != newstate)
26113498266Sopenharmony_ci    infof(data, "SASL %p state change from %s to %s",
26213498266Sopenharmony_ci          (void *)sasl, names[sasl->state], names[newstate]);
26313498266Sopenharmony_ci#else
26413498266Sopenharmony_ci  (void) data;
26513498266Sopenharmony_ci#endif
26613498266Sopenharmony_ci
26713498266Sopenharmony_ci  sasl->state = newstate;
26813498266Sopenharmony_ci}
26913498266Sopenharmony_ci
27013498266Sopenharmony_ci#if defined(USE_NTLM) || defined(USE_GSASL) || defined(USE_KERBEROS5) || \
27113498266Sopenharmony_ci  !defined(CURL_DISABLE_DIGEST_AUTH)
27213498266Sopenharmony_ci/* Get the SASL server message and convert it to binary. */
27313498266Sopenharmony_cistatic CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
27413498266Sopenharmony_ci                                   struct bufref *out)
27513498266Sopenharmony_ci{
27613498266Sopenharmony_ci  CURLcode result = CURLE_OK;
27713498266Sopenharmony_ci
27813498266Sopenharmony_ci  result = sasl->params->getmessage(data, out);
27913498266Sopenharmony_ci  if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) {
28013498266Sopenharmony_ci    unsigned char *msg;
28113498266Sopenharmony_ci    size_t msglen;
28213498266Sopenharmony_ci    const char *serverdata = (const char *) Curl_bufref_ptr(out);
28313498266Sopenharmony_ci
28413498266Sopenharmony_ci    if(!*serverdata || *serverdata == '=')
28513498266Sopenharmony_ci      Curl_bufref_set(out, NULL, 0, NULL);
28613498266Sopenharmony_ci    else {
28713498266Sopenharmony_ci      result = Curl_base64_decode(serverdata, &msg, &msglen);
28813498266Sopenharmony_ci      if(!result)
28913498266Sopenharmony_ci        Curl_bufref_set(out, msg, msglen, curl_free);
29013498266Sopenharmony_ci    }
29113498266Sopenharmony_ci  }
29213498266Sopenharmony_ci  return result;
29313498266Sopenharmony_ci}
29413498266Sopenharmony_ci#endif
29513498266Sopenharmony_ci
29613498266Sopenharmony_ci/* Encode the outgoing SASL message. */
29713498266Sopenharmony_cistatic CURLcode build_message(struct SASL *sasl, struct bufref *msg)
29813498266Sopenharmony_ci{
29913498266Sopenharmony_ci  CURLcode result = CURLE_OK;
30013498266Sopenharmony_ci
30113498266Sopenharmony_ci  if(sasl->params->flags & SASL_FLAG_BASE64) {
30213498266Sopenharmony_ci    if(!Curl_bufref_ptr(msg))                   /* Empty message. */
30313498266Sopenharmony_ci      Curl_bufref_set(msg, "", 0, NULL);
30413498266Sopenharmony_ci    else if(!Curl_bufref_len(msg))              /* Explicit empty response. */
30513498266Sopenharmony_ci      Curl_bufref_set(msg, "=", 1, NULL);
30613498266Sopenharmony_ci    else {
30713498266Sopenharmony_ci      char *base64;
30813498266Sopenharmony_ci      size_t base64len;
30913498266Sopenharmony_ci
31013498266Sopenharmony_ci      result = Curl_base64_encode((const char *) Curl_bufref_ptr(msg),
31113498266Sopenharmony_ci                                  Curl_bufref_len(msg), &base64, &base64len);
31213498266Sopenharmony_ci      if(!result)
31313498266Sopenharmony_ci        Curl_bufref_set(msg, base64, base64len, curl_free);
31413498266Sopenharmony_ci    }
31513498266Sopenharmony_ci  }
31613498266Sopenharmony_ci
31713498266Sopenharmony_ci  return result;
31813498266Sopenharmony_ci}
31913498266Sopenharmony_ci
32013498266Sopenharmony_ci/*
32113498266Sopenharmony_ci * Curl_sasl_can_authenticate()
32213498266Sopenharmony_ci *
32313498266Sopenharmony_ci * Check if we have enough auth data and capabilities to authenticate.
32413498266Sopenharmony_ci */
32513498266Sopenharmony_cibool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data)
32613498266Sopenharmony_ci{
32713498266Sopenharmony_ci  /* Have credentials been provided? */
32813498266Sopenharmony_ci  if(data->state.aptr.user)
32913498266Sopenharmony_ci    return TRUE;
33013498266Sopenharmony_ci
33113498266Sopenharmony_ci  /* EXTERNAL can authenticate without a user name and/or password */
33213498266Sopenharmony_ci  if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL)
33313498266Sopenharmony_ci    return TRUE;
33413498266Sopenharmony_ci
33513498266Sopenharmony_ci  return FALSE;
33613498266Sopenharmony_ci}
33713498266Sopenharmony_ci
33813498266Sopenharmony_ci/*
33913498266Sopenharmony_ci * Curl_sasl_start()
34013498266Sopenharmony_ci *
34113498266Sopenharmony_ci * Calculate the required login details for SASL authentication.
34213498266Sopenharmony_ci */
34313498266Sopenharmony_ciCURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
34413498266Sopenharmony_ci                         bool force_ir, saslprogress *progress)
34513498266Sopenharmony_ci{
34613498266Sopenharmony_ci  CURLcode result = CURLE_OK;
34713498266Sopenharmony_ci  struct connectdata *conn = data->conn;
34813498266Sopenharmony_ci  unsigned short enabledmechs;
34913498266Sopenharmony_ci  const char *mech = NULL;
35013498266Sopenharmony_ci  struct bufref resp;
35113498266Sopenharmony_ci  saslstate state1 = SASL_STOP;
35213498266Sopenharmony_ci  saslstate state2 = SASL_FINAL;
35313498266Sopenharmony_ci  const char *hostname, *disp_hostname;
35413498266Sopenharmony_ci  int port;
35513498266Sopenharmony_ci#if defined(USE_KERBEROS5) || defined(USE_NTLM)
35613498266Sopenharmony_ci  const char *service = data->set.str[STRING_SERVICE_NAME] ?
35713498266Sopenharmony_ci    data->set.str[STRING_SERVICE_NAME] :
35813498266Sopenharmony_ci    sasl->params->service;
35913498266Sopenharmony_ci#endif
36013498266Sopenharmony_ci  const char *oauth_bearer = data->set.str[STRING_BEARER];
36113498266Sopenharmony_ci  struct bufref nullmsg;
36213498266Sopenharmony_ci
36313498266Sopenharmony_ci  Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
36413498266Sopenharmony_ci  Curl_bufref_init(&nullmsg);
36513498266Sopenharmony_ci  Curl_bufref_init(&resp);
36613498266Sopenharmony_ci  sasl->force_ir = force_ir;    /* Latch for future use */
36713498266Sopenharmony_ci  sasl->authused = 0;           /* No mechanism used yet */
36813498266Sopenharmony_ci  enabledmechs = sasl->authmechs & sasl->prefmech;
36913498266Sopenharmony_ci  *progress = SASL_IDLE;
37013498266Sopenharmony_ci
37113498266Sopenharmony_ci  /* Calculate the supported authentication mechanism, by decreasing order of
37213498266Sopenharmony_ci     security, as well as the initial response where appropriate */
37313498266Sopenharmony_ci  if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) {
37413498266Sopenharmony_ci    mech = SASL_MECH_STRING_EXTERNAL;
37513498266Sopenharmony_ci    state1 = SASL_EXTERNAL;
37613498266Sopenharmony_ci    sasl->authused = SASL_MECH_EXTERNAL;
37713498266Sopenharmony_ci
37813498266Sopenharmony_ci    if(force_ir || data->set.sasl_ir)
37913498266Sopenharmony_ci      result = Curl_auth_create_external_message(conn->user, &resp);
38013498266Sopenharmony_ci  }
38113498266Sopenharmony_ci  else if(data->state.aptr.user) {
38213498266Sopenharmony_ci#if defined(USE_KERBEROS5)
38313498266Sopenharmony_ci    if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() &&
38413498266Sopenharmony_ci       Curl_auth_user_contains_domain(conn->user)) {
38513498266Sopenharmony_ci      sasl->mutual_auth = FALSE;
38613498266Sopenharmony_ci      mech = SASL_MECH_STRING_GSSAPI;
38713498266Sopenharmony_ci      state1 = SASL_GSSAPI;
38813498266Sopenharmony_ci      state2 = SASL_GSSAPI_TOKEN;
38913498266Sopenharmony_ci      sasl->authused = SASL_MECH_GSSAPI;
39013498266Sopenharmony_ci
39113498266Sopenharmony_ci      if(force_ir || data->set.sasl_ir)
39213498266Sopenharmony_ci        result = Curl_auth_create_gssapi_user_message(data, conn->user,
39313498266Sopenharmony_ci                                                      conn->passwd,
39413498266Sopenharmony_ci                                                      service,
39513498266Sopenharmony_ci                                                      conn->host.name,
39613498266Sopenharmony_ci                                                      sasl->mutual_auth,
39713498266Sopenharmony_ci                                                      NULL, &conn->krb5,
39813498266Sopenharmony_ci                                                      &resp);
39913498266Sopenharmony_ci    }
40013498266Sopenharmony_ci    else
40113498266Sopenharmony_ci#endif
40213498266Sopenharmony_ci#ifdef USE_GSASL
40313498266Sopenharmony_ci    if((enabledmechs & SASL_MECH_SCRAM_SHA_256) &&
40413498266Sopenharmony_ci       Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256,
40513498266Sopenharmony_ci                                    &conn->gsasl)) {
40613498266Sopenharmony_ci      mech = SASL_MECH_STRING_SCRAM_SHA_256;
40713498266Sopenharmony_ci      sasl->authused = SASL_MECH_SCRAM_SHA_256;
40813498266Sopenharmony_ci      state1 = SASL_GSASL;
40913498266Sopenharmony_ci      state2 = SASL_GSASL;
41013498266Sopenharmony_ci
41113498266Sopenharmony_ci      result = Curl_auth_gsasl_start(data, conn->user,
41213498266Sopenharmony_ci                                     conn->passwd, &conn->gsasl);
41313498266Sopenharmony_ci      if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
41413498266Sopenharmony_ci        result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
41513498266Sopenharmony_ci    }
41613498266Sopenharmony_ci    else if((enabledmechs & SASL_MECH_SCRAM_SHA_1) &&
41713498266Sopenharmony_ci            Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1,
41813498266Sopenharmony_ci                                         &conn->gsasl)) {
41913498266Sopenharmony_ci      mech = SASL_MECH_STRING_SCRAM_SHA_1;
42013498266Sopenharmony_ci      sasl->authused = SASL_MECH_SCRAM_SHA_1;
42113498266Sopenharmony_ci      state1 = SASL_GSASL;
42213498266Sopenharmony_ci      state2 = SASL_GSASL;
42313498266Sopenharmony_ci
42413498266Sopenharmony_ci      result = Curl_auth_gsasl_start(data, conn->user,
42513498266Sopenharmony_ci                                     conn->passwd, &conn->gsasl);
42613498266Sopenharmony_ci      if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
42713498266Sopenharmony_ci        result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
42813498266Sopenharmony_ci    }
42913498266Sopenharmony_ci    else
43013498266Sopenharmony_ci#endif
43113498266Sopenharmony_ci#ifndef CURL_DISABLE_DIGEST_AUTH
43213498266Sopenharmony_ci    if((enabledmechs & SASL_MECH_DIGEST_MD5) &&
43313498266Sopenharmony_ci       Curl_auth_is_digest_supported()) {
43413498266Sopenharmony_ci      mech = SASL_MECH_STRING_DIGEST_MD5;
43513498266Sopenharmony_ci      state1 = SASL_DIGESTMD5;
43613498266Sopenharmony_ci      sasl->authused = SASL_MECH_DIGEST_MD5;
43713498266Sopenharmony_ci    }
43813498266Sopenharmony_ci    else if(enabledmechs & SASL_MECH_CRAM_MD5) {
43913498266Sopenharmony_ci      mech = SASL_MECH_STRING_CRAM_MD5;
44013498266Sopenharmony_ci      state1 = SASL_CRAMMD5;
44113498266Sopenharmony_ci      sasl->authused = SASL_MECH_CRAM_MD5;
44213498266Sopenharmony_ci    }
44313498266Sopenharmony_ci    else
44413498266Sopenharmony_ci#endif
44513498266Sopenharmony_ci#ifdef USE_NTLM
44613498266Sopenharmony_ci    if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) {
44713498266Sopenharmony_ci      mech = SASL_MECH_STRING_NTLM;
44813498266Sopenharmony_ci      state1 = SASL_NTLM;
44913498266Sopenharmony_ci      state2 = SASL_NTLM_TYPE2MSG;
45013498266Sopenharmony_ci      sasl->authused = SASL_MECH_NTLM;
45113498266Sopenharmony_ci
45213498266Sopenharmony_ci      if(force_ir || data->set.sasl_ir)
45313498266Sopenharmony_ci        result = Curl_auth_create_ntlm_type1_message(data,
45413498266Sopenharmony_ci                                                     conn->user, conn->passwd,
45513498266Sopenharmony_ci                                                     service,
45613498266Sopenharmony_ci                                                     hostname,
45713498266Sopenharmony_ci                                                     &conn->ntlm, &resp);
45813498266Sopenharmony_ci      }
45913498266Sopenharmony_ci    else
46013498266Sopenharmony_ci#endif
46113498266Sopenharmony_ci    if((enabledmechs & SASL_MECH_OAUTHBEARER) && oauth_bearer) {
46213498266Sopenharmony_ci      mech = SASL_MECH_STRING_OAUTHBEARER;
46313498266Sopenharmony_ci      state1 = SASL_OAUTH2;
46413498266Sopenharmony_ci      state2 = SASL_OAUTH2_RESP;
46513498266Sopenharmony_ci      sasl->authused = SASL_MECH_OAUTHBEARER;
46613498266Sopenharmony_ci
46713498266Sopenharmony_ci      if(force_ir || data->set.sasl_ir)
46813498266Sopenharmony_ci        result = Curl_auth_create_oauth_bearer_message(conn->user,
46913498266Sopenharmony_ci                                                       hostname,
47013498266Sopenharmony_ci                                                       port,
47113498266Sopenharmony_ci                                                       oauth_bearer,
47213498266Sopenharmony_ci                                                       &resp);
47313498266Sopenharmony_ci    }
47413498266Sopenharmony_ci    else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) {
47513498266Sopenharmony_ci      mech = SASL_MECH_STRING_XOAUTH2;
47613498266Sopenharmony_ci      state1 = SASL_OAUTH2;
47713498266Sopenharmony_ci      sasl->authused = SASL_MECH_XOAUTH2;
47813498266Sopenharmony_ci
47913498266Sopenharmony_ci      if(force_ir || data->set.sasl_ir)
48013498266Sopenharmony_ci        result = Curl_auth_create_xoauth_bearer_message(conn->user,
48113498266Sopenharmony_ci                                                        oauth_bearer,
48213498266Sopenharmony_ci                                                        &resp);
48313498266Sopenharmony_ci    }
48413498266Sopenharmony_ci    else if(enabledmechs & SASL_MECH_PLAIN) {
48513498266Sopenharmony_ci      mech = SASL_MECH_STRING_PLAIN;
48613498266Sopenharmony_ci      state1 = SASL_PLAIN;
48713498266Sopenharmony_ci      sasl->authused = SASL_MECH_PLAIN;
48813498266Sopenharmony_ci
48913498266Sopenharmony_ci      if(force_ir || data->set.sasl_ir)
49013498266Sopenharmony_ci        result = Curl_auth_create_plain_message(conn->sasl_authzid,
49113498266Sopenharmony_ci                                                conn->user, conn->passwd,
49213498266Sopenharmony_ci                                                &resp);
49313498266Sopenharmony_ci    }
49413498266Sopenharmony_ci    else if(enabledmechs & SASL_MECH_LOGIN) {
49513498266Sopenharmony_ci      mech = SASL_MECH_STRING_LOGIN;
49613498266Sopenharmony_ci      state1 = SASL_LOGIN;
49713498266Sopenharmony_ci      state2 = SASL_LOGIN_PASSWD;
49813498266Sopenharmony_ci      sasl->authused = SASL_MECH_LOGIN;
49913498266Sopenharmony_ci
50013498266Sopenharmony_ci      if(force_ir || data->set.sasl_ir)
50113498266Sopenharmony_ci        result = Curl_auth_create_login_message(conn->user, &resp);
50213498266Sopenharmony_ci    }
50313498266Sopenharmony_ci  }
50413498266Sopenharmony_ci
50513498266Sopenharmony_ci  if(!result && mech) {
50613498266Sopenharmony_ci    sasl->curmech = mech;
50713498266Sopenharmony_ci    if(Curl_bufref_ptr(&resp))
50813498266Sopenharmony_ci      result = build_message(sasl, &resp);
50913498266Sopenharmony_ci
51013498266Sopenharmony_ci    if(sasl->params->maxirlen &&
51113498266Sopenharmony_ci       strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen)
51213498266Sopenharmony_ci      Curl_bufref_free(&resp);
51313498266Sopenharmony_ci
51413498266Sopenharmony_ci    if(!result)
51513498266Sopenharmony_ci      result = sasl->params->sendauth(data, mech, &resp);
51613498266Sopenharmony_ci
51713498266Sopenharmony_ci    if(!result) {
51813498266Sopenharmony_ci      *progress = SASL_INPROGRESS;
51913498266Sopenharmony_ci      sasl_state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1);
52013498266Sopenharmony_ci    }
52113498266Sopenharmony_ci  }
52213498266Sopenharmony_ci
52313498266Sopenharmony_ci  Curl_bufref_free(&resp);
52413498266Sopenharmony_ci  return result;
52513498266Sopenharmony_ci}
52613498266Sopenharmony_ci
52713498266Sopenharmony_ci/*
52813498266Sopenharmony_ci * Curl_sasl_continue()
52913498266Sopenharmony_ci *
53013498266Sopenharmony_ci * Continue the authentication.
53113498266Sopenharmony_ci */
53213498266Sopenharmony_ciCURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
53313498266Sopenharmony_ci                            int code, saslprogress *progress)
53413498266Sopenharmony_ci{
53513498266Sopenharmony_ci  CURLcode result = CURLE_OK;
53613498266Sopenharmony_ci  struct connectdata *conn = data->conn;
53713498266Sopenharmony_ci  saslstate newstate = SASL_FINAL;
53813498266Sopenharmony_ci  struct bufref resp;
53913498266Sopenharmony_ci  const char *hostname, *disp_hostname;
54013498266Sopenharmony_ci  int port;
54113498266Sopenharmony_ci#if defined(USE_KERBEROS5) || defined(USE_NTLM) \
54213498266Sopenharmony_ci    || !defined(CURL_DISABLE_DIGEST_AUTH)
54313498266Sopenharmony_ci  const char *service = data->set.str[STRING_SERVICE_NAME] ?
54413498266Sopenharmony_ci    data->set.str[STRING_SERVICE_NAME] :
54513498266Sopenharmony_ci    sasl->params->service;
54613498266Sopenharmony_ci#endif
54713498266Sopenharmony_ci  const char *oauth_bearer = data->set.str[STRING_BEARER];
54813498266Sopenharmony_ci  struct bufref serverdata;
54913498266Sopenharmony_ci
55013498266Sopenharmony_ci  Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
55113498266Sopenharmony_ci  Curl_bufref_init(&serverdata);
55213498266Sopenharmony_ci  Curl_bufref_init(&resp);
55313498266Sopenharmony_ci  *progress = SASL_INPROGRESS;
55413498266Sopenharmony_ci
55513498266Sopenharmony_ci  if(sasl->state == SASL_FINAL) {
55613498266Sopenharmony_ci    if(code != sasl->params->finalcode)
55713498266Sopenharmony_ci      result = CURLE_LOGIN_DENIED;
55813498266Sopenharmony_ci    *progress = SASL_DONE;
55913498266Sopenharmony_ci    sasl_state(sasl, data, SASL_STOP);
56013498266Sopenharmony_ci    return result;
56113498266Sopenharmony_ci  }
56213498266Sopenharmony_ci
56313498266Sopenharmony_ci  if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP &&
56413498266Sopenharmony_ci     code != sasl->params->contcode) {
56513498266Sopenharmony_ci    *progress = SASL_DONE;
56613498266Sopenharmony_ci    sasl_state(sasl, data, SASL_STOP);
56713498266Sopenharmony_ci    return CURLE_LOGIN_DENIED;
56813498266Sopenharmony_ci  }
56913498266Sopenharmony_ci
57013498266Sopenharmony_ci  switch(sasl->state) {
57113498266Sopenharmony_ci  case SASL_STOP:
57213498266Sopenharmony_ci    *progress = SASL_DONE;
57313498266Sopenharmony_ci    return result;
57413498266Sopenharmony_ci  case SASL_PLAIN:
57513498266Sopenharmony_ci    result = Curl_auth_create_plain_message(conn->sasl_authzid,
57613498266Sopenharmony_ci                                            conn->user, conn->passwd, &resp);
57713498266Sopenharmony_ci    break;
57813498266Sopenharmony_ci  case SASL_LOGIN:
57913498266Sopenharmony_ci    result = Curl_auth_create_login_message(conn->user, &resp);
58013498266Sopenharmony_ci    newstate = SASL_LOGIN_PASSWD;
58113498266Sopenharmony_ci    break;
58213498266Sopenharmony_ci  case SASL_LOGIN_PASSWD:
58313498266Sopenharmony_ci    result = Curl_auth_create_login_message(conn->passwd, &resp);
58413498266Sopenharmony_ci    break;
58513498266Sopenharmony_ci  case SASL_EXTERNAL:
58613498266Sopenharmony_ci    result = Curl_auth_create_external_message(conn->user, &resp);
58713498266Sopenharmony_ci    break;
58813498266Sopenharmony_ci#ifdef USE_GSASL
58913498266Sopenharmony_ci  case SASL_GSASL:
59013498266Sopenharmony_ci    result = get_server_message(sasl, data, &serverdata);
59113498266Sopenharmony_ci    if(!result)
59213498266Sopenharmony_ci      result = Curl_auth_gsasl_token(data, &serverdata, &conn->gsasl, &resp);
59313498266Sopenharmony_ci    if(!result && Curl_bufref_len(&resp) > 0)
59413498266Sopenharmony_ci      newstate = SASL_GSASL;
59513498266Sopenharmony_ci    break;
59613498266Sopenharmony_ci#endif
59713498266Sopenharmony_ci#ifndef CURL_DISABLE_DIGEST_AUTH
59813498266Sopenharmony_ci  case SASL_CRAMMD5:
59913498266Sopenharmony_ci    result = get_server_message(sasl, data, &serverdata);
60013498266Sopenharmony_ci    if(!result)
60113498266Sopenharmony_ci      result = Curl_auth_create_cram_md5_message(&serverdata, conn->user,
60213498266Sopenharmony_ci                                                 conn->passwd, &resp);
60313498266Sopenharmony_ci    break;
60413498266Sopenharmony_ci  case SASL_DIGESTMD5:
60513498266Sopenharmony_ci    result = get_server_message(sasl, data, &serverdata);
60613498266Sopenharmony_ci    if(!result)
60713498266Sopenharmony_ci      result = Curl_auth_create_digest_md5_message(data, &serverdata,
60813498266Sopenharmony_ci                                                   conn->user, conn->passwd,
60913498266Sopenharmony_ci                                                   service, &resp);
61013498266Sopenharmony_ci    if(!result && (sasl->params->flags & SASL_FLAG_BASE64))
61113498266Sopenharmony_ci      newstate = SASL_DIGESTMD5_RESP;
61213498266Sopenharmony_ci    break;
61313498266Sopenharmony_ci  case SASL_DIGESTMD5_RESP:
61413498266Sopenharmony_ci    /* Keep response NULL to output an empty line. */
61513498266Sopenharmony_ci    break;
61613498266Sopenharmony_ci#endif
61713498266Sopenharmony_ci
61813498266Sopenharmony_ci#ifdef USE_NTLM
61913498266Sopenharmony_ci  case SASL_NTLM:
62013498266Sopenharmony_ci    /* Create the type-1 message */
62113498266Sopenharmony_ci    result = Curl_auth_create_ntlm_type1_message(data,
62213498266Sopenharmony_ci                                                 conn->user, conn->passwd,
62313498266Sopenharmony_ci                                                 service, hostname,
62413498266Sopenharmony_ci                                                 &conn->ntlm, &resp);
62513498266Sopenharmony_ci    newstate = SASL_NTLM_TYPE2MSG;
62613498266Sopenharmony_ci    break;
62713498266Sopenharmony_ci  case SASL_NTLM_TYPE2MSG:
62813498266Sopenharmony_ci    /* Decode the type-2 message */
62913498266Sopenharmony_ci    result = get_server_message(sasl, data, &serverdata);
63013498266Sopenharmony_ci    if(!result)
63113498266Sopenharmony_ci      result = Curl_auth_decode_ntlm_type2_message(data, &serverdata,
63213498266Sopenharmony_ci                                                   &conn->ntlm);
63313498266Sopenharmony_ci    if(!result)
63413498266Sopenharmony_ci      result = Curl_auth_create_ntlm_type3_message(data, conn->user,
63513498266Sopenharmony_ci                                                   conn->passwd, &conn->ntlm,
63613498266Sopenharmony_ci                                                   &resp);
63713498266Sopenharmony_ci    break;
63813498266Sopenharmony_ci#endif
63913498266Sopenharmony_ci
64013498266Sopenharmony_ci#if defined(USE_KERBEROS5)
64113498266Sopenharmony_ci  case SASL_GSSAPI:
64213498266Sopenharmony_ci    result = Curl_auth_create_gssapi_user_message(data, conn->user,
64313498266Sopenharmony_ci                                                  conn->passwd,
64413498266Sopenharmony_ci                                                  service,
64513498266Sopenharmony_ci                                                  conn->host.name,
64613498266Sopenharmony_ci                                                  sasl->mutual_auth, NULL,
64713498266Sopenharmony_ci                                                  &conn->krb5,
64813498266Sopenharmony_ci                                                  &resp);
64913498266Sopenharmony_ci    newstate = SASL_GSSAPI_TOKEN;
65013498266Sopenharmony_ci    break;
65113498266Sopenharmony_ci  case SASL_GSSAPI_TOKEN:
65213498266Sopenharmony_ci    result = get_server_message(sasl, data, &serverdata);
65313498266Sopenharmony_ci    if(!result) {
65413498266Sopenharmony_ci      if(sasl->mutual_auth) {
65513498266Sopenharmony_ci        /* Decode the user token challenge and create the optional response
65613498266Sopenharmony_ci           message */
65713498266Sopenharmony_ci        result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
65813498266Sopenharmony_ci                                                      NULL, NULL,
65913498266Sopenharmony_ci                                                      sasl->mutual_auth,
66013498266Sopenharmony_ci                                                      &serverdata,
66113498266Sopenharmony_ci                                                      &conn->krb5,
66213498266Sopenharmony_ci                                                      &resp);
66313498266Sopenharmony_ci        newstate = SASL_GSSAPI_NO_DATA;
66413498266Sopenharmony_ci      }
66513498266Sopenharmony_ci      else
66613498266Sopenharmony_ci        /* Decode the security challenge and create the response message */
66713498266Sopenharmony_ci        result = Curl_auth_create_gssapi_security_message(data,
66813498266Sopenharmony_ci                                                          conn->sasl_authzid,
66913498266Sopenharmony_ci                                                          &serverdata,
67013498266Sopenharmony_ci                                                          &conn->krb5,
67113498266Sopenharmony_ci                                                          &resp);
67213498266Sopenharmony_ci    }
67313498266Sopenharmony_ci    break;
67413498266Sopenharmony_ci  case SASL_GSSAPI_NO_DATA:
67513498266Sopenharmony_ci    /* Decode the security challenge and create the response message */
67613498266Sopenharmony_ci    result = get_server_message(sasl, data, &serverdata);
67713498266Sopenharmony_ci    if(!result)
67813498266Sopenharmony_ci      result = Curl_auth_create_gssapi_security_message(data,
67913498266Sopenharmony_ci                                                        conn->sasl_authzid,
68013498266Sopenharmony_ci                                                        &serverdata,
68113498266Sopenharmony_ci                                                        &conn->krb5,
68213498266Sopenharmony_ci                                                        &resp);
68313498266Sopenharmony_ci    break;
68413498266Sopenharmony_ci#endif
68513498266Sopenharmony_ci
68613498266Sopenharmony_ci  case SASL_OAUTH2:
68713498266Sopenharmony_ci    /* Create the authorization message */
68813498266Sopenharmony_ci    if(sasl->authused == SASL_MECH_OAUTHBEARER) {
68913498266Sopenharmony_ci      result = Curl_auth_create_oauth_bearer_message(conn->user,
69013498266Sopenharmony_ci                                                     hostname,
69113498266Sopenharmony_ci                                                     port,
69213498266Sopenharmony_ci                                                     oauth_bearer,
69313498266Sopenharmony_ci                                                     &resp);
69413498266Sopenharmony_ci
69513498266Sopenharmony_ci      /* Failures maybe sent by the server as continuations for OAUTHBEARER */
69613498266Sopenharmony_ci      newstate = SASL_OAUTH2_RESP;
69713498266Sopenharmony_ci    }
69813498266Sopenharmony_ci    else
69913498266Sopenharmony_ci      result = Curl_auth_create_xoauth_bearer_message(conn->user,
70013498266Sopenharmony_ci                                                      oauth_bearer,
70113498266Sopenharmony_ci                                                      &resp);
70213498266Sopenharmony_ci    break;
70313498266Sopenharmony_ci
70413498266Sopenharmony_ci  case SASL_OAUTH2_RESP:
70513498266Sopenharmony_ci    /* The continuation is optional so check the response code */
70613498266Sopenharmony_ci    if(code == sasl->params->finalcode) {
70713498266Sopenharmony_ci      /* Final response was received so we are done */
70813498266Sopenharmony_ci      *progress = SASL_DONE;
70913498266Sopenharmony_ci      sasl_state(sasl, data, SASL_STOP);
71013498266Sopenharmony_ci      return result;
71113498266Sopenharmony_ci    }
71213498266Sopenharmony_ci    else if(code == sasl->params->contcode) {
71313498266Sopenharmony_ci      /* Acknowledge the continuation by sending a 0x01 response. */
71413498266Sopenharmony_ci      Curl_bufref_set(&resp, "\x01", 1, NULL);
71513498266Sopenharmony_ci      break;
71613498266Sopenharmony_ci    }
71713498266Sopenharmony_ci    else {
71813498266Sopenharmony_ci      *progress = SASL_DONE;
71913498266Sopenharmony_ci      sasl_state(sasl, data, SASL_STOP);
72013498266Sopenharmony_ci      return CURLE_LOGIN_DENIED;
72113498266Sopenharmony_ci    }
72213498266Sopenharmony_ci
72313498266Sopenharmony_ci  case SASL_CANCEL:
72413498266Sopenharmony_ci    /* Remove the offending mechanism from the supported list */
72513498266Sopenharmony_ci    sasl->authmechs ^= sasl->authused;
72613498266Sopenharmony_ci
72713498266Sopenharmony_ci    /* Start an alternative SASL authentication */
72813498266Sopenharmony_ci    return Curl_sasl_start(sasl, data, sasl->force_ir, progress);
72913498266Sopenharmony_ci  default:
73013498266Sopenharmony_ci    failf(data, "Unsupported SASL authentication mechanism");
73113498266Sopenharmony_ci    result = CURLE_UNSUPPORTED_PROTOCOL;  /* Should not happen */
73213498266Sopenharmony_ci    break;
73313498266Sopenharmony_ci  }
73413498266Sopenharmony_ci
73513498266Sopenharmony_ci  Curl_bufref_free(&serverdata);
73613498266Sopenharmony_ci
73713498266Sopenharmony_ci  switch(result) {
73813498266Sopenharmony_ci  case CURLE_BAD_CONTENT_ENCODING:
73913498266Sopenharmony_ci    /* Cancel dialog */
74013498266Sopenharmony_ci    result = sasl->params->cancelauth(data, sasl->curmech);
74113498266Sopenharmony_ci    newstate = SASL_CANCEL;
74213498266Sopenharmony_ci    break;
74313498266Sopenharmony_ci  case CURLE_OK:
74413498266Sopenharmony_ci    result = build_message(sasl, &resp);
74513498266Sopenharmony_ci    if(!result)
74613498266Sopenharmony_ci      result = sasl->params->contauth(data, sasl->curmech, &resp);
74713498266Sopenharmony_ci    break;
74813498266Sopenharmony_ci  default:
74913498266Sopenharmony_ci    newstate = SASL_STOP;    /* Stop on error */
75013498266Sopenharmony_ci    *progress = SASL_DONE;
75113498266Sopenharmony_ci    break;
75213498266Sopenharmony_ci  }
75313498266Sopenharmony_ci
75413498266Sopenharmony_ci  Curl_bufref_free(&resp);
75513498266Sopenharmony_ci
75613498266Sopenharmony_ci  sasl_state(sasl, data, newstate);
75713498266Sopenharmony_ci
75813498266Sopenharmony_ci  return result;
75913498266Sopenharmony_ci}
76013498266Sopenharmony_ci#endif /* protocols are enabled that use SASL */
761