Commit 0d24f644 authored by Patrick Monnerat's avatar Patrick Monnerat
Browse files

sasl: implement EXTERNAL authentication mechanism.

  Its use is only enabled by explicit requirement in URL (;AUTH=EXTERNAL) and
by not setting the password.
parent e1bb13c0
Loading
Loading
Loading
Loading
+121 −67
Original line number Diff line number Diff line
@@ -368,6 +368,30 @@ static CURLcode sasl_create_login_message(struct SessionHandle *data,
  return Curl_base64_encode(data, valuep, vlen, outptr, outlen);
}

/*
 * sasl_create_external_message()
 *
 * This is used to generate an already encoded EXTERNAL message containing
 * the user name ready for sending to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * user    [in]     - The user name.
 * outptr  [in/out] - The address where a pointer to newly allocated memory
 *                    holding the result will be stored upon completion.
 * outlen  [out]    - The length of the output message.
 *
 * Returns CURLE_OK on success.
 */
static CURLcode sasl_create_external_message(struct SessionHandle *data,
                                          const char *user, char **outptr,
                                          size_t *outlen)
{
  /* This is the same formatting as the login message. */
  return sasl_create_login_message(data, user, outptr, outlen);
}

#ifndef CURL_DISABLE_CRYPTO_AUTH
 /*
 * sasl_decode_cram_md5_message()
@@ -1257,7 +1281,7 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
    }

    if(strnequal(value, "*", len))
      sasl->prefmech = SASL_AUTH_ANY;
      sasl->prefmech = SASL_AUTH_DEFAULT;
    else if((mechbit = Curl_sasl_decode_mech(value, len, &mechlen)) &&
            mechlen == len)
      sasl->prefmech |= mechbit;
@@ -1277,7 +1301,7 @@ void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params)
  sasl->params = params;           /* Set protocol dependent parameters */
  sasl->state = SASL_STOP;         /* Not yet running */
  sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */
  sasl->prefmech = SASL_AUTH_ANY;  /* Prefer all mechanisms */
  sasl->prefmech = SASL_AUTH_DEFAULT; /* Prefer all mechanisms */
  sasl->authused = SASL_AUTH_NONE; /* No the authentication mechanism used */
  sasl->resetprefs = TRUE;         /* Reset prefmech upon AUTH parsing. */
  sasl->mutual_auth = FALSE;       /* No mutual authentication (GSSAPI only) */
@@ -1299,6 +1323,7 @@ static void state(struct SASL *sasl,
    "PLAIN",
    "LOGIN",
    "LOGIN_PASSWD",
    "EXTERNAL",
    "CRAMMD5",
    "DIGESTMD5",
    "DIGESTMD5_RESP",
@@ -1321,6 +1346,23 @@ static void state(struct SASL *sasl,
  sasl->state = newstate;
}

/*
 * Curl_sasl_can_authenticate()
 *
 * Check if we have enough auth data and capabilities to authenticate.
 */

bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn)
{
  if(conn->bits.user_passwd)
    return TRUE;        /* Credentials provided */

  if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL)
    return TRUE;        /* Can authenticate without password */

  return FALSE;
}

/*
 * Curl_sasl_start()
 *
@@ -1345,6 +1387,15 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,

  /* Calculate the supported authentication mechanism, by decreasing order of
   *      security, as well as the initial response where appropriate */
  if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) {
    mech = SASL_MECH_STRING_EXTERNAL;
    state1 = SASL_EXTERNAL;
    sasl->authused = SASL_MECH_EXTERNAL;

    if(force_ir || data->set.sasl_ir)
      result = sasl_create_external_message(data, conn->user, &resp, &len);
  }
  else if(conn->bits.user_passwd) {
#if defined(USE_KERBEROS5)
    if(enabledmechs & SASL_MECH_GSSAPI) {
      sasl->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */
@@ -1390,14 +1441,15 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
    else
#endif
    if((((enabledmechs & SASL_MECH_XOAUTH2) &&
      sasl->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) {
        sasl->prefmech != SASL_AUTH_DEFAULT)) || conn->xoauth2_bearer) {
      mech = SASL_MECH_STRING_XOAUTH2;
      state1 = SASL_XOAUTH2;
      sasl->authused = SASL_MECH_XOAUTH2;

      if(force_ir || data->set.sasl_ir)
        result = sasl_create_xoauth2_message(data, conn->user,
                                           conn->xoauth2_bearer, &resp, &len);
                                             conn->xoauth2_bearer,
                                             &resp, &len);
    }
    else if(enabledmechs & SASL_MECH_LOGIN) {
      mech = SASL_MECH_STRING_LOGIN;
@@ -1417,8 +1469,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
        result = sasl_create_plain_message(data, conn->user, conn->passwd,
                                           &resp, &len);
    }
  else
    state2 = SASL_STOP;    /* No authentication started */
  }

  if(!result) {
    if(resp && sasl->params->maxirlen &&
@@ -1490,6 +1541,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
  case SASL_LOGIN_PASSWD:
    result = sasl_create_login_message(data, conn->passwd, &resp, &len);
    break;
  case SASL_EXTERNAL:
    result = sasl_create_external_message(data, conn->user, &resp, &len);
    break;

#ifndef CURL_DISABLE_CRYPTO_AUTH
  case SASL_CRAMMD5:
+9 −4
Original line number Diff line number Diff line
@@ -39,10 +39,6 @@ struct ntlmdata;
struct kerberos5data;
#endif

/* Authentication mechanism values */
#define SASL_AUTH_NONE          0
#define SASL_AUTH_ANY           ~0U

/* Authentication mechanism flags */
#define SASL_MECH_LOGIN             (1 << 0)
#define SASL_MECH_PLAIN             (1 << 1)
@@ -53,6 +49,11 @@ struct kerberos5data;
#define SASL_MECH_NTLM              (1 << 6)
#define SASL_MECH_XOAUTH2           (1 << 7)

/* Authentication mechanism values */
#define SASL_AUTH_NONE          0
#define SASL_AUTH_ANY           ~0U
#define SASL_AUTH_DEFAULT       (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL)

/* Authentication mechanism strings */
#define SASL_MECH_STRING_LOGIN      "LOGIN"
#define SASL_MECH_STRING_PLAIN      "PLAIN"
@@ -74,6 +75,7 @@ typedef enum {
  SASL_PLAIN,
  SASL_LOGIN,
  SASL_LOGIN_PASSWD,
  SASL_EXTERNAL,
  SASL_CRAMMD5,
  SASL_DIGESTMD5,
  SASL_DIGESTMD5_RESP,
@@ -228,6 +230,9 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
/* Initializes an SASL structure */
void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params);

/* Check if we have enough auth data and capabilities to authenticate */
bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn);

/* Calculate the required login details for SASL authentication  */
CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
                         bool force_ir, saslprogress *progress);
+3 −3
Original line number Diff line number Diff line
@@ -612,9 +612,9 @@ static CURLcode imap_perform_authentication(struct connectdata *conn)
  struct imap_conn *imapc = &conn->proto.imapc;
  saslprogress progress;

  /* Check we have a username and password to authenticate with and end the
  /* Check we have enough data to authenticate with and end the
     connect phase if we don't */
  if(!conn->bits.user_passwd) {
  if(!Curl_sasl_can_authenticate(&imapc->sasl, conn)) {
    state(conn, IMAP_STOP);
    return result;
  }
@@ -1962,7 +1962,7 @@ static CURLcode imap_parse_url_options(struct connectdata *conn)
  case SASL_AUTH_NONE:
    imapc->preftype = IMAP_TYPE_NONE;
    break;
  case SASL_AUTH_ANY:
  case SASL_AUTH_DEFAULT:
    imapc->preftype = IMAP_TYPE_ANY;
    break;
  default:
+3 −3
Original line number Diff line number Diff line
@@ -543,9 +543,9 @@ static CURLcode pop3_perform_authentication(struct connectdata *conn)
  struct pop3_conn *pop3c = &conn->proto.pop3c;
  saslprogress progress = SASL_IDLE;

  /* Check we have a username and password to authenticate with and end the
  /* Check we have enough data to authenticate with and end the
     connect phase if we don't */
  if(!conn->bits.user_passwd) {
  if(!Curl_sasl_can_authenticate(&pop3c->sasl, conn)) {
    state(conn, POP3_STOP);
    return result;
  }
@@ -1425,7 +1425,7 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn)
    case SASL_AUTH_NONE:
      pop3c->preftype = POP3_TYPE_NONE;
      break;
    case SASL_AUTH_ANY:
    case SASL_AUTH_DEFAULT:
      pop3c->preftype = POP3_TYPE_ANY;
      break;
    default:
+3 −2
Original line number Diff line number Diff line
@@ -486,9 +486,10 @@ static CURLcode smtp_perform_authentication(struct connectdata *conn)
  struct smtp_conn *smtpc = &conn->proto.smtpc;
  saslprogress progress;

  /* Check we have a username and password to authenticate with, and the
  /* Check we have enough data to authenticate with, and the
     server supports authentiation, and end the connect phase if not */
  if(!conn->bits.user_passwd || !smtpc->auth_supported) {
  if(!smtpc->auth_supported ||
      !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
    state(conn, SMTP_STOP);
    return result;
  }