diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/curl_sasl.c | 331 | ||||
| -rw-r--r-- | lib/curl_sasl.h | 54 | ||||
| -rw-r--r-- | lib/imap.c | 838 | ||||
| -rw-r--r-- | lib/imap.h | 15 | ||||
| -rw-r--r-- | lib/pop3.c | 849 | ||||
| -rw-r--r-- | lib/pop3.h | 15 | ||||
| -rw-r--r-- | lib/smtp.c | 812 | ||||
| -rw-r--r-- | lib/smtp.h | 15 | 
8 files changed, 577 insertions, 2352 deletions
| diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c index 7cb575b33..6a648f0ae 100644 --- a/lib/curl_sasl.c +++ b/lib/curl_sasl.c @@ -43,6 +43,7 @@  #include "strtok.h"  #include "strequal.h"  #include "rawstr.h" +#include "sendf.h"  #include "non-ascii.h" /* included for Curl_convert_... prototypes */  #define _MPRINTF_REPLACE /* use our functions only */ @@ -1271,11 +1272,339 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,   *   * Initializes an SASL structure.   */ -void Curl_sasl_init(struct SASL *sasl) +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->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) */ +  sasl->force_ir = FALSE;          /* Respect external option */ +} + +/* + * state() + * + * This is the ONLY way to change SASL state! + */ +static void state(struct SASL *sasl, +                  struct connectdata *conn, saslstate newstate) +{ +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) +  /* for debug purposes */ +  static const char * const names[]={ +    "STOP", +    "PLAIN", +    "LOGIN", +    "LOGIN_PASSWD", +    "CRAMMD5", +    "DIGESTMD5", +    "DIGESTMD5_RESP", +    "NTLM", +    "NTLM_TYPE2MSG", +    "GSSAPI", +    "GSSAPI_TOKEN", +    "GSSAPI_NO_DATA", +    "XOAUTH2", +    "CANCEL", +    "FINAL", +    /* LAST */ +  }; + +  if(sasl->state != newstate) +    infof(conn->data, "SASL %p state change from %s to %s\n", +          (void *)sasl, names[sasl->state], names[newstate]); +#endif + +  sasl->state = newstate; +} + +/* + * Curl_sasl_start() + * + * Calculate the required login details for SASL authentication. + */ +CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, +                         bool force_ir, saslprogress *progress) +{ +  CURLcode result = CURLE_OK; +  struct SessionHandle *data = conn->data; +  unsigned int enabledmechs; +  const char *mech = NULL; +  char *resp = NULL; +  size_t len = 0; +  saslstate state1 = SASL_STOP; +  saslstate state2 = SASL_FINAL; + +  sasl->force_ir = force_ir;    /* Latch for future use */ +  sasl->authused = 0;           /* No mechanism used yet */ +  enabledmechs = sasl->authmechs & sasl->prefmech; +  *progress = SASL_IDLE; + +  /* Calculate the supported authentication mechanism, by decreasing order of +   *      security, as well as the initial response where appropriate */ +#if defined(USE_KERBEROS5) +  if(enabledmechs & SASL_MECH_GSSAPI) { +    sasl->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */ +    mech = SASL_MECH_STRING_GSSAPI; +    state1 = SASL_GSSAPI; +    state2 = SASL_GSSAPI_TOKEN; +    sasl->authused = SASL_MECH_GSSAPI; + +    if(force_ir || data->set.sasl_ir) +      result = Curl_sasl_create_gssapi_user_message(data, conn->user, +                                                    conn->passwd, +                                                    sasl->params->service, +                                                    sasl->mutual_auth, +                                                    NULL, &conn->krb5, +                                                    &resp, &len); +  } +  else +#endif +#ifndef CURL_DISABLE_CRYPTO_AUTH +  if(enabledmechs & SASL_MECH_DIGEST_MD5) { +    mech = SASL_MECH_STRING_DIGEST_MD5; +    state1 = SASL_DIGESTMD5; +    sasl->authused = SASL_MECH_DIGEST_MD5; +  } +  else if(enabledmechs & SASL_MECH_CRAM_MD5) { +    mech = SASL_MECH_STRING_CRAM_MD5; +    state1 = SASL_CRAMMD5; +    sasl->authused = SASL_MECH_CRAM_MD5; +  } +  else +#endif +#ifdef USE_NTLM +  if(enabledmechs & SASL_MECH_NTLM) { +    mech = SASL_MECH_STRING_NTLM; +    state1 = SASL_NTLM; +    state2 = SASL_NTLM_TYPE2MSG; +    sasl->authused = SASL_MECH_NTLM; + +    if(force_ir || data->set.sasl_ir) +      result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, +                                                   &conn->ntlm, &resp, &len); +    } +  else +#endif +  if((((enabledmechs & SASL_MECH_XOAUTH2) && +      sasl->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) { +    mech = SASL_MECH_STRING_XOAUTH2; +    state1 = SASL_XOAUTH2; +    sasl->authused = SASL_MECH_XOAUTH2; + +    if(force_ir || data->set.sasl_ir) +      result = Curl_sasl_create_xoauth2_message(data, conn->user, +                                                conn->xoauth2_bearer, +                                                &resp, &len); +  } +  else if(enabledmechs & SASL_MECH_LOGIN) { +    mech = SASL_MECH_STRING_LOGIN; +    state1 = SASL_LOGIN; +    state2 = SASL_LOGIN_PASSWD; +    sasl->authused = SASL_MECH_LOGIN; + +    if(force_ir || data->set.sasl_ir) +      result = Curl_sasl_create_login_message(data, conn->user, &resp, &len); +  } +  else if(enabledmechs & SASL_MECH_PLAIN) { +    mech = SASL_MECH_STRING_PLAIN; +    state1 = SASL_PLAIN; +    sasl->authused = SASL_MECH_PLAIN; + +    if(force_ir || data->set.sasl_ir) +      result = Curl_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 && +       strlen(mech) + len > sasl->params->maxirlen) { +      Curl_safefree(resp); +      resp = NULL; +    } +    if(mech) { +      result = sasl->params->sendauth(conn, mech, resp); +      if(!result) { +        *progress = SASL_INPROGRESS; +        state(sasl, conn, resp? state2: state1); +      } +    } +  } + +  Curl_safefree(resp); +  return result; +} + +/* + * Curl_sasl_continue() + * + * Continue an SASL authentication. + */ +CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, +                         int code, saslprogress *progress) +{ +  CURLcode result = CURLE_OK; +  struct SessionHandle *data = conn->data; +  saslstate newstate = SASL_FINAL; +  char *chlg = NULL; +  char *resp = NULL; +  char *serverdata; +  size_t len = 0; +  size_t chlglen = 0; + +  *progress = SASL_INPROGRESS; + +  if(sasl->state == SASL_FINAL) { +    if(code != sasl->params->finalcode) +      result = CURLE_LOGIN_DENIED; +    *progress = SASL_DONE; +    state(sasl, conn, SASL_STOP); +    return result; +  } + +  if(sasl->state != SASL_CANCEL && code != sasl->params->contcode) { +    *progress = SASL_DONE; +    state(sasl, conn, SASL_STOP); +    return CURLE_LOGIN_DENIED; +  } + +  switch(sasl->state) { +  case SASL_STOP: +    *progress = SASL_DONE; +    return result; +  case SASL_PLAIN: +    result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, +                                            &resp, &len); +    break; +  case SASL_LOGIN: +    result = Curl_sasl_create_login_message(data, conn->user, &resp, &len); +    newstate = SASL_LOGIN_PASSWD; +    break; +  case SASL_LOGIN_PASSWD: +    result = Curl_sasl_create_login_message(data, conn->passwd, &resp, &len); +    break; + +#ifndef CURL_DISABLE_CRYPTO_AUTH +  case SASL_CRAMMD5: +    sasl->params->getmessage(data->state.buffer, &serverdata); +    result = Curl_sasl_decode_cram_md5_message(serverdata, &chlg, &chlglen); +    if(!result) +      result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user, +                                                 conn->passwd, &resp, &len); +    Curl_safefree(chlg); +    break; +  case SASL_DIGESTMD5: +    sasl->params->getmessage(data->state.buffer, &serverdata); +    result = Curl_sasl_create_digest_md5_message(data, serverdata, +                                                 conn->user, conn->passwd, +                                                 sasl->params->service, +                                                 &resp, &len); +    newstate = SASL_DIGESTMD5_RESP; +    break; +  case SASL_DIGESTMD5_RESP: +    if(!(resp = strdup(""))) +      result = CURLE_OUT_OF_MEMORY; +    break; +#endif + +#ifdef USE_NTLM +  case SASL_NTLM: +    /* Create the type-1 message */ +    result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, +                                                 &conn->ntlm, +                                                 &resp, &len); +    newstate = SASL_NTLM_TYPE2MSG; +    break; +  case SASL_NTLM_TYPE2MSG: +    /* Decode the type-2 message */ +    sasl->params->getmessage(data->state.buffer, &serverdata); +    result = Curl_sasl_decode_ntlm_type2_message(data, +                                                 serverdata, &conn->ntlm); +    if(!result) +      result = Curl_sasl_create_ntlm_type3_message(data, conn->user, +                                                   conn->passwd, &conn->ntlm, +                                                   &resp, &len); +    break; +#endif + +#if defined(USE_KERBEROS5) +  case SASL_GSSAPI: +    result = Curl_sasl_create_gssapi_user_message(data, conn->user, +                                                  conn->passwd, +                                                  sasl->params->service, +                                                  sasl->mutual_auth, NULL, +                                                  &conn->krb5, +                                                  &resp, &len); +    newstate = SASL_GSSAPI_TOKEN; +    break; +  case SASL_GSSAPI_TOKEN: +    sasl->params->getmessage(data->state.buffer, &serverdata); +    if(sasl->mutual_auth) { +      /* Decode the user token challenge and create the optional response +         message */ +      result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL, +                                                    sasl->mutual_auth, +                                                    serverdata, &conn->krb5, +                                                    &resp, &len); +      newstate = SASL_GSSAPI_NO_DATA; +    } +    else +      /* Decode the security challenge and create the response message */ +      result = Curl_sasl_create_gssapi_security_message(data, serverdata, +                                                        &conn->krb5, +                                                        &resp, &len); +    break; +  case SASL_GSSAPI_NO_DATA: +    sasl->params->getmessage(data->state.buffer, &serverdata); +    /* Decode the security challenge and create the response message */ +    result = Curl_sasl_create_gssapi_security_message(data, serverdata, +                                                      &conn->krb5, +                                                      &resp, &len); +    break; +#endif + +  case SASL_XOAUTH2: +    /* Create the authorisation message */ +    result = Curl_sasl_create_xoauth2_message(data, conn->user, +                                              conn->xoauth2_bearer, +                                              &resp, &len); +    break; +  case SASL_CANCEL: +    /* Remove the offending mechanism from the supported list */ +    sasl->authmechs ^= sasl->authused; + +    /* Start an alternative SASL authentication */ +    result = Curl_sasl_start(sasl, conn, sasl->force_ir, progress); +    newstate = sasl->state;   /* Use state from Curl_sasl_start() */ +    break; +  default: +    failf(data, "Unsupported SASL authentication mechanism"); +    result = CURLE_UNSUPPORTED_PROTOCOL;  /* Should not happen */ +    break; +  } + +  switch(result) { +  case CURLE_BAD_CONTENT_ENCODING: +    /* Cancel dialog */ +    result = sasl->params->sendcont(conn, "*"); +    newstate = SASL_CANCEL; +    break; +  case CURLE_OK: +    if(resp) +      result = sasl->params->sendcont(conn, resp); +    break; +  default: +    newstate = SASL_STOP;    /* Stop on error */ +    *progress = SASL_DONE; +    break; +  } + +  Curl_safefree(resp); +  state(sasl, conn, newstate); +  return result;  } diff --git a/lib/curl_sasl.h b/lib/curl_sasl.h index e043449db..19fa239e4 100644 --- a/lib/curl_sasl.h +++ b/lib/curl_sasl.h @@ -68,13 +68,57 @@ enum {    CURLDIGESTALGO_MD5SESS  }; +/* SASL machine states */ +typedef enum { +  SASL_STOP, +  SASL_PLAIN, +  SASL_LOGIN, +  SASL_LOGIN_PASSWD, +  SASL_CRAMMD5, +  SASL_DIGESTMD5, +  SASL_DIGESTMD5_RESP, +  SASL_NTLM, +  SASL_NTLM_TYPE2MSG, +  SASL_GSSAPI, +  SASL_GSSAPI_TOKEN, +  SASL_GSSAPI_NO_DATA, +  SASL_XOAUTH2, +  SASL_CANCEL, +  SASL_FINAL +} saslstate; + +/* Progress indicator */ +typedef enum { +  SASL_IDLE, +  SASL_INPROGRESS, +  SASL_DONE +} saslprogress; + +/* Protocol dependent SASL parameters */ +struct SASLproto { +  const char *service;     /* The service name */ +  int contcode;            /* Code to receive when continuation is expected */ +  int finalcode;           /* Code to receive upon authentication success */ +  size_t maxirlen;         /* Maximum initial response length */ +  CURLcode (*sendauth)(struct connectdata *conn, +                       const char *mech, const char *ir); +                           /* Send authentication command */ +  CURLcode (*sendcont)(struct connectdata *conn, const char *contauth); +                           /* Send authentication continuation */ +  void (*getmessage)(char *buffer, char **outptr); +                           /* Get SASL response message */ +}; +  /* Per-connection parameters */  struct SASL { +  const struct SASLproto *params; /* Protocol dependent parameters */ +  saslstate state;         /* Current machine state */    unsigned int authmechs;  /* Accepted authentication mechanisms */    unsigned int prefmech;   /* Preferred authentication mechanism */    unsigned int authused;   /* Auth mechanism used for the connection */    bool resetprefs;         /* For URL auth option parsing. */    bool mutual_auth;        /* Mutual authentication enabled (GSSAPI only) */ +  bool force_ir;           /* Protocol always supports initial response */  };  /* This is used to test whether the line starts with the given mechanism */ @@ -211,6 +255,14 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,                                           const char *value, size_t len);  /* Initializes an SASL structure */ -void Curl_sasl_init(struct SASL *sasl); +void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params); + +/* Calculate the required login details for SASL authentication  */ +CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, +                         bool force_ir, saslprogress *progress); + +/* Continue an SASL authentication  */ +CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, +                         int code, saslprogress *progress);  #endif /* HEADER_CURL_SASL_H */ diff --git a/lib/imap.c b/lib/imap.c index 965efdf8a..c5c8e4aea 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -105,10 +105,12 @@ static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...);  static CURLcode imap_parse_url_options(struct connectdata *conn);  static CURLcode imap_parse_url_path(struct connectdata *conn);  static CURLcode imap_parse_custom_request(struct connectdata *conn); -static CURLcode imap_calc_sasl_details(struct connectdata *conn, -                                       const char **mech, -                                       char **initresp, size_t *len, -                                       imapstate *state1, imapstate *state2); +static CURLcode imap_perform_authenticate(struct connectdata *conn, +                                          const char *mech, +                                          const char *initresp); +static CURLcode imap_continue_authenticate(struct connectdata *conn, +                                           const char *resp); +static void imap_get_message(char *buffer, char** outptr);  /*   * IMAP protocol handler. @@ -213,6 +215,18 @@ static const struct Curl_handler Curl_handler_imaps_proxy = {  #endif  #endif +/* SASL parameters for the imap protocol */ +static const struct SASLproto saslimap = { +  "imap",                     /* The service name */ +  '+',                        /* Code received when continuation is expected */ +  'O',                        /* Code to receive upon authentication success */ +  0,                          /* Maximum initial response length (no max) */ +  imap_perform_authenticate,  /* Send authentication command */ +  imap_continue_authenticate, /* Send authentication continuation */ +  imap_get_message            /* Get SASL response message */ +}; + +  #ifdef USE_SSL  static void imap_to_imaps(struct connectdata *conn)  { @@ -353,16 +367,7 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,       (len >= 2 && !memcmp("+ ", line, 2))) {      switch(imapc->state) {        /* States which are interested in continuation responses */ -      case IMAP_AUTHENTICATE_PLAIN: -      case IMAP_AUTHENTICATE_LOGIN: -      case IMAP_AUTHENTICATE_LOGIN_PASSWD: -      case IMAP_AUTHENTICATE_CRAMMD5: -      case IMAP_AUTHENTICATE_DIGESTMD5: -      case IMAP_AUTHENTICATE_DIGESTMD5_RESP: -      case IMAP_AUTHENTICATE_NTLM: -      case IMAP_AUTHENTICATE_NTLM_TYPE2MSG: -      case IMAP_AUTHENTICATE_XOAUTH2: -      case IMAP_AUTHENTICATE_FINAL: +      case IMAP_AUTHENTICATE:        case IMAP_APPEND:          *resp = '+';          break; @@ -425,20 +430,7 @@ static void state(struct connectdata *conn, imapstate newstate)      "CAPABILITY",      "STARTTLS",      "UPGRADETLS", -    "AUTHENTICATE_PLAIN", -    "AUTHENTICATE_LOGIN", -    "AUTHENTICATE_LOGIN_PASSWD", -    "AUTHENTICATE_CRAMMD5", -    "AUTHENTICATE_DIGESTMD5", -    "AUTHENTICATE_DIGESTMD5_RESP", -    "AUTHENTICATE_NTLM", -    "AUTHENTICATE_NTLM_TYPE2MSG", -    "AUTHENTICATE_GSSAPI", -    "AUTHENTICATE_GSSAPI_TOKEN", -    "AUTHENTICATE_GSSAPI_NO_DATA", -    "AUTHENTICATE_XOAUTH2", -    "AUTHENTICATE_CANCEL", -    "AUTHENTICATE_FINAL", +    "AUTHENTICATE",      "LOGIN",      "LIST",      "SELECT", @@ -576,24 +568,17 @@ static CURLcode imap_perform_login(struct connectdata *conn)   */  static CURLcode imap_perform_authenticate(struct connectdata *conn,                                            const char *mech, -                                          const char *initresp, -                                          imapstate state1, imapstate state2) +                                          const char *initresp)  {    CURLcode result = CURLE_OK;    if(initresp) {      /* Send the AUTHENTICATE command with the initial response */      result = imap_sendf(conn, "AUTHENTICATE %s %s", mech, initresp); - -    if(!result) -      state(conn, state2);    }    else {      /* Send the AUTHENTICATE command */      result = imap_sendf(conn, "AUTHENTICATE %s", mech); - -    if(!result) -      state(conn, state1);    }    return result; @@ -601,6 +586,20 @@ static CURLcode imap_perform_authenticate(struct connectdata *conn,  /***********************************************************************   * + * imap_continue_authenticate() + * + * Sends SASL continuation data or cancellation. + */ +static CURLcode imap_continue_authenticate(struct connectdata *conn, +                                           const char *resp) +{ +  struct imap_conn *imapc = &conn->proto.imapc; + +  return Curl_pp_sendf(&imapc->pp, "%s", resp); +} + +/*********************************************************************** + *   * imap_perform_authentication()   *   * Initiates the authentication sequence, with the appropriate SASL @@ -611,31 +610,22 @@ static CURLcode imap_perform_authentication(struct connectdata *conn)  {    CURLcode result = CURLE_OK;    struct imap_conn *imapc = &conn->proto.imapc; -  const char *mech = NULL; -  char *initresp = NULL; -  size_t len = 0; -  imapstate state1 = IMAP_STOP; -  imapstate state2 = IMAP_STOP; +  saslprogress progress;    /* Check we have a username and password to authenticate with and end the       connect phase if we don't */    if(!conn->bits.user_passwd) {      state(conn, IMAP_STOP); -      return result;    }    /* Calculate the SASL login details */ -  result = imap_calc_sasl_details(conn, &mech, &initresp, &len, &state1, -                                  &state2); +  result = Curl_sasl_start(&imapc->sasl, conn, imapc->ir_supported, &progress);    if(!result) { -    if(mech && (imapc->preftype & IMAP_TYPE_SASL)) { -      /* Perform SASL based authentication */ -      result = imap_perform_authenticate(conn, mech, initresp, state1, state2); -    } -    else if((!imapc->login_disabled) && -            (imapc->preftype & IMAP_TYPE_CLEARTEXT)) +    if(progress == SASL_INPROGRESS) +      state(conn, IMAP_AUTHENTICATE); +    else if(!imapc->login_disabled && (imapc->preftype & IMAP_TYPE_CLEARTEXT))        /* Perform clear text authentication */        result = imap_perform_login(conn);      else { @@ -645,8 +635,6 @@ static CURLcode imap_perform_authentication(struct connectdata *conn)      }    } -  Curl_safefree(initresp); -    return result;  } @@ -976,569 +964,36 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn,    return result;  } -/* For AUTHENTICATE PLAIN (without initial response) responses */ -static CURLcode imap_state_auth_plain_resp(struct connectdata *conn, -                                           int imapcode, -                                           imapstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  size_t len = 0; -  char *plainauth = NULL; - -  (void)instate; /* no use for this yet */ - -  if(imapcode != '+') { -    failf(data, "Access denied. %c", imapcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the authorisation message */ -    result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, -                                            &plainauth, &len); -    if(!result && plainauth) { -      /* Send the message */ -      result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", plainauth); - -      if(!result) -        state(conn, IMAP_AUTHENTICATE_FINAL); -    } -  } - -  Curl_safefree(plainauth); - -  return result; -} - -/* For AUTHENTICATE LOGIN (without initial response) responses */ -static CURLcode imap_state_auth_login_resp(struct connectdata *conn, -                                           int imapcode, -                                           imapstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  size_t len = 0; -  char *authuser = NULL; - -  (void)instate; /* no use for this yet */ - -  if(imapcode != '+') { -    failf(data, "Access denied: %d", imapcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the user message */ -    result = Curl_sasl_create_login_message(data, conn->user, -                                            &authuser, &len); -    if(!result && authuser) { -      /* Send the user */ -      result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", authuser); - -      if(!result) -        state(conn, IMAP_AUTHENTICATE_LOGIN_PASSWD); -    } -  } - -  Curl_safefree(authuser); - -  return result; -} - -/* For AUTHENTICATE LOGIN user entry responses */ -static CURLcode imap_state_auth_login_password_resp(struct connectdata *conn, -                                                    int imapcode, -                                                    imapstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  size_t len = 0; -  char *authpasswd = NULL; - -  (void)instate; /* no use for this yet */ - -  if(imapcode != '+') { -    failf(data, "Access denied: %d", imapcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the password message */ -    result = Curl_sasl_create_login_message(data, conn->passwd, -                                            &authpasswd, &len); -    if(!result && authpasswd) { -      /* Send the password */ -      result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", authpasswd); - -      if(!result) -        state(conn, IMAP_AUTHENTICATE_FINAL); -    } -  } - -  Curl_safefree(authpasswd); - -  return result; -} - -#ifndef CURL_DISABLE_CRYPTO_AUTH -/* For AUTHENTICATE CRAM-MD5 responses */ -static CURLcode imap_state_auth_cram_resp(struct connectdata *conn, -                                          int imapcode, -                                          imapstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  char *chlg = NULL; -  char *chlg64 = NULL; -  char *rplyb64 = NULL; -  size_t len = 0; - -  (void)instate; /* no use for this yet */ - -  if(imapcode != '+') { -    failf(data, "Access denied: %d", imapcode); -    return CURLE_LOGIN_DENIED; -  } - -  /* Get the challenge message */ -  imap_get_message(data->state.buffer, &chlg64); - -  /* Decode the challenge message */ -  result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len); -  if(result) { -    /* Send the cancellation */ -    result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "*"); - -    if(!result) -      state(conn, IMAP_AUTHENTICATE_CANCEL); -  } -  else { -    /* Create the response message */ -    result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user, -                                               conn->passwd, &rplyb64, &len); -    if(!result && rplyb64) { -      /* Send the response */ -      result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", rplyb64); - -      if(!result) -        state(conn, IMAP_AUTHENTICATE_FINAL); -    } -  } - -  Curl_safefree(chlg); -  Curl_safefree(rplyb64); - -  return result; -} - -/* For AUTHENTICATE DIGEST-MD5 challenge responses */ -static CURLcode imap_state_auth_digest_resp(struct connectdata *conn, -                                            int imapcode, -                                            imapstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  char *chlg64 = NULL; -  char *rplyb64 = NULL; -  size_t len = 0; - -  (void)instate; /* no use for this yet */ - -  if(imapcode != '+') { -    failf(data, "Access denied: %d", imapcode); -    return CURLE_LOGIN_DENIED; -  } - -  /* Get the challenge message */ -  imap_get_message(data->state.buffer, &chlg64); - -  /* Create the response message */ -  result = Curl_sasl_create_digest_md5_message(data, chlg64, -                                               conn->user, conn->passwd, -                                               "imap", &rplyb64, &len); -  if(result) { -    if(result == CURLE_BAD_CONTENT_ENCODING) { -      /* Send the cancellation */ -      result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "*"); - -      if(!result) -        state(conn, IMAP_AUTHENTICATE_CANCEL); -    } -  } -  else { -    /* Send the response */ -    result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", rplyb64); - -    if(!result) -      state(conn, IMAP_AUTHENTICATE_DIGESTMD5_RESP); -  } - -  Curl_safefree(rplyb64); - -  return result; -} - -/* For AUTHENTICATE DIGEST-MD5 challenge-response responses */ -static CURLcode imap_state_auth_digest_resp_resp(struct connectdata *conn, -                                                 int imapcode, -                                                 imapstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; - -  (void)instate; /* no use for this yet */ - -  if(imapcode != '+') { -    failf(data, "Authentication failed: %d", imapcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Send an empty response */ -    result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", ""); - -    if(!result) -      state(conn, IMAP_AUTHENTICATE_FINAL); -  } - -  return result; -} -#endif - -#ifdef USE_NTLM -/* For AUTHENTICATE NTLM (without initial response) responses */ -static CURLcode imap_state_auth_ntlm_resp(struct connectdata *conn, -                                          int imapcode, -                                          imapstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  size_t len = 0; -  char *type1msg = NULL; - -  (void)instate; /* no use for this yet */ - -  if(imapcode != '+') { -    failf(data, "Access denied: %d", imapcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the type-1 message */ -    result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, -                                                 &conn->ntlm, -                                                 &type1msg, &len); -    if(!result && type1msg) { -      /* Send the message */ -      result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", type1msg); - -      if(!result) -        state(conn, IMAP_AUTHENTICATE_NTLM_TYPE2MSG); -    } -  } - -  Curl_safefree(type1msg); - -  return result; -} - -/* For NTLM type-2 responses (sent in reponse to our type-1 message) */ -static CURLcode imap_state_auth_ntlm_type2msg_resp(struct connectdata *conn, -                                                   int imapcode, -                                                   imapstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  char *type2msg = NULL; -  char *type3msg = NULL; -  size_t len = 0; - -  (void)instate; /* no use for this yet */ - -  if(imapcode != '+') { -    failf(data, "Access denied: %d", imapcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Get the challenge message */ -    imap_get_message(data->state.buffer, &type2msg); - -    /* Decode the type-2 message */ -    result = Curl_sasl_decode_ntlm_type2_message(data, type2msg, &conn->ntlm); -    if(result) { -      /* Send the cancellation */ -      result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "*"); - -      if(!result) -        state(conn, IMAP_AUTHENTICATE_CANCEL); -    } -    else { -      /* Create the type-3 message */ -      result = Curl_sasl_create_ntlm_type3_message(data, conn->user, -                                                   conn->passwd, &conn->ntlm, -                                                   &type3msg, &len); -      if(!result && type3msg) { -        /* Send the message */ -        result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", type3msg); - -        if(!result) -          state(conn, IMAP_AUTHENTICATE_FINAL); -      } -    } -  } - -  Curl_safefree(type3msg); - -  return result; -} -#endif - -#if defined(USE_KERBEROS5) -/* For AUTHENTICATE GSSAPI (without initial response) responses */ -static CURLcode imap_state_auth_gssapi_resp(struct connectdata *conn, -                                            int imapcode, -                                            imapstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  struct imap_conn *imapc = &conn->proto.imapc; -  size_t len = 0; -  char *respmsg = NULL; - -  (void)instate; /* no use for this yet */ - -  if(imapcode != '+') { -    failf(data, "Access denied: %d", imapcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the initial response message */ -    result = Curl_sasl_create_gssapi_user_message(data, conn->user, -                                                  conn->passwd, "imap", -                                                  imapc->sasl.mutual_auth, -                                                  NULL, &conn->krb5, -                                                  &respmsg, &len); -    if(!result && respmsg) { -      /* Send the message */ -      result = Curl_pp_sendf(&imapc->pp, "%s", respmsg); - -      if(!result) -        state(conn, IMAP_AUTHENTICATE_GSSAPI_TOKEN); -    } -  } - -  Curl_safefree(respmsg); - -  return result; -} - -/* For AUTHENTICATE GSSAPI user token responses */ -static CURLcode imap_state_auth_gssapi_token_resp(struct connectdata *conn, -                                                  int imapcode, -                                                  imapstate instate) +/* For SASL authentication responses */ +static CURLcode imap_state_auth_resp(struct connectdata *conn, +                                     int imapcode, +                                     imapstate instate)  {    CURLcode result = CURLE_OK;    struct SessionHandle *data = conn->data;    struct imap_conn *imapc = &conn->proto.imapc; -  char *chlgmsg = NULL; -  char *respmsg = NULL; -  size_t len = 0; +  saslprogress progress;    (void)instate; /* no use for this yet */ -  if(imapcode != '+') { -    failf(data, "Access denied: %d", imapcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Get the challenge message */ -    imap_get_message(data->state.buffer, &chlgmsg); - -    if(imapc->sasl.mutual_auth) -      /* Decode the user token challenge and create the optional response -         message */ -      result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL, -                                                    imapc->sasl.mutual_auth, -                                                    chlgmsg, &conn->krb5, -                                                    &respmsg, &len); -    else -      /* Decode the security challenge and create the response message */ -      result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, -                                                        &conn->krb5, -                                                        &respmsg, &len); - -    if(result) { -      if(result == CURLE_BAD_CONTENT_ENCODING) { -        /* Send the cancellation */ -        result = Curl_pp_sendf(&imapc->pp, "%s", "*"); - -        if(!result) -          state(conn, IMAP_AUTHENTICATE_CANCEL); -      } -    } -    else { -      /* Send the response */ -      if(respmsg) -        result = Curl_pp_sendf(&imapc->pp, "%s", respmsg); -      else -        result = Curl_pp_sendf(&imapc->pp, "%s", ""); - -      if(!result) -        state(conn, imapc->sasl.mutual_auth? IMAP_AUTHENTICATE_GSSAPI_NO_DATA: -                                             IMAP_AUTHENTICATE_FINAL); -    } -  } - -  Curl_safefree(respmsg); - -  return result; -} - -/* For AUTHENTICATE GSSAPI no data responses */ -static CURLcode imap_state_auth_gssapi_no_data_resp(struct connectdata *conn, -                                                    int imapcode, -                                                    imapstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  char *chlgmsg = NULL; -  char *respmsg = NULL; -  size_t len = 0; - -  (void)instate; /* no use for this yet */ - -  if(imapcode != '+') { -    failf(data, "Access denied: %d", imapcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Get the challenge message */ -    imap_get_message(data->state.buffer, &chlgmsg); - -    /* Decode the security challenge and create the response message */ -    result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, -                                                      &conn->krb5, -                                                      &respmsg, &len); -    if(result) { -      if(result == CURLE_BAD_CONTENT_ENCODING) { -        /* Send the cancellation */ -        result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "*"); - -        if(!result) -          state(conn, IMAP_AUTHENTICATE_CANCEL); -      } -    } -    else { -      /* Send the response */ -      if(respmsg) { -        result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", respmsg); - -        if(!result) -          state(conn, IMAP_AUTHENTICATE_FINAL); +  result = Curl_sasl_continue(&imapc->sasl, conn, imapcode, &progress); +  if(!result) +    switch(progress) { +    case SASL_DONE: +      state(conn, IMAP_STOP);  /* Authenticated */ +      break; +    case SASL_IDLE:            /* No mechanism left after cancellation */ +      if((!imapc->login_disabled) && (imapc->preftype & IMAP_TYPE_CLEARTEXT)) +        /* Perform clear text authentication */ +        result = imap_perform_login(conn); +      else { +        failf(data, "Authentication cancelled"); +        result = CURLE_LOGIN_DENIED;        } +      break; +    default: +      break;      } -  } - -  Curl_safefree(respmsg); - -  return result; -} -#endif - -/* For AUTHENTICATE XOAUTH2 (without initial response) responses */ -static CURLcode imap_state_auth_xoauth2_resp(struct connectdata *conn, -                                             int imapcode, -                                             imapstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  size_t len = 0; -  char *xoauth = NULL; - -  (void)instate; /* no use for this yet */ - -  if(imapcode != '+') { -    failf(data, "Access denied: %d", imapcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the authorisation message */ -    result = Curl_sasl_create_xoauth2_message(conn->data, conn->user, -                                              conn->xoauth2_bearer, -                                              &xoauth, &len); -    if(!result && xoauth) { -      /* Send the message */ -      result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", xoauth); - -      if(!result) -        state(conn, IMAP_AUTHENTICATE_FINAL); -    } -  } - -  Curl_safefree(xoauth); - -  return result; -} - -/* For AUTHENTICATE cancellation responses */ -static CURLcode imap_state_auth_cancel_resp(struct connectdata *conn, -                                            int imapcode, -                                            imapstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  struct imap_conn *imapc = &conn->proto.imapc; -  const char *mech = NULL; -  char *initresp = NULL; -  size_t len = 0; -  imapstate state1 = IMAP_STOP; -  imapstate state2 = IMAP_STOP; - -  (void)imapcode; -  (void)instate; /* no use for this yet */ - -  /* Remove the offending mechanism from the supported list */ -  imapc->sasl.authmechs ^= imapc->sasl.authused; - -  /* Calculate alternative SASL login details */ -  result = imap_calc_sasl_details(conn, &mech, &initresp, &len, &state1, -                                  &state2); - -  if(!result) { -    /* Do we have any mechanisms left or can we fallback to clear text? */ -    if(mech) { -      /* Retry SASL based authentication */ -      result = imap_perform_authenticate(conn, mech, initresp, state1, state2); - -      Curl_safefree(initresp); -    } -    else if((!imapc->login_disabled) && -            (imapc->preftype & IMAP_TYPE_CLEARTEXT)) -      /* Perform clear text authentication */ -      result = imap_perform_login(conn); -    else { -      failf(data, "Authentication cancelled"); - -      result = CURLE_LOGIN_DENIED; -    } -  } - -  return result; -} - -/* For final responses in the AUTHENTICATE sequence */ -static CURLcode imap_state_auth_final_resp(struct connectdata *conn, -                                           int imapcode, -                                           imapstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; - -  (void)instate; /* no use for this yet */ - -  if(imapcode != 'O') { -    failf(data, "Authentication failed: %d", imapcode); -    result = CURLE_LOGIN_DENIED; -  } -  else -    /* End of connect phase */ -    state(conn, IMAP_STOP);    return result;  } @@ -1862,69 +1317,8 @@ static CURLcode imap_statemach_act(struct connectdata *conn)        result = imap_state_starttls_resp(conn, imapcode, imapc->state);        break; -    case IMAP_AUTHENTICATE_PLAIN: -      result = imap_state_auth_plain_resp(conn, imapcode, imapc->state); -      break; - -    case IMAP_AUTHENTICATE_LOGIN: -      result = imap_state_auth_login_resp(conn, imapcode, imapc->state); -      break; - -    case IMAP_AUTHENTICATE_LOGIN_PASSWD: -      result = imap_state_auth_login_password_resp(conn, imapcode, -                                                   imapc->state); -      break; - -#ifndef CURL_DISABLE_CRYPTO_AUTH -    case IMAP_AUTHENTICATE_CRAMMD5: -      result = imap_state_auth_cram_resp(conn, imapcode, imapc->state); -      break; - -    case IMAP_AUTHENTICATE_DIGESTMD5: -      result = imap_state_auth_digest_resp(conn, imapcode, imapc->state); -      break; - -    case IMAP_AUTHENTICATE_DIGESTMD5_RESP: -      result = imap_state_auth_digest_resp_resp(conn, imapcode, imapc->state); -      break; -#endif - -#ifdef USE_NTLM -    case IMAP_AUTHENTICATE_NTLM: -      result = imap_state_auth_ntlm_resp(conn, imapcode, imapc->state); -      break; - -    case IMAP_AUTHENTICATE_NTLM_TYPE2MSG: -      result = imap_state_auth_ntlm_type2msg_resp(conn, imapcode, -                                                  imapc->state); -      break; -#endif - -#if defined(USE_KERBEROS5) -    case IMAP_AUTHENTICATE_GSSAPI: -      result = imap_state_auth_gssapi_resp(conn, imapcode, imapc->state); -      break; - -    case IMAP_AUTHENTICATE_GSSAPI_TOKEN: -      result = imap_state_auth_gssapi_token_resp(conn, imapcode, imapc->state); -      break; - -    case IMAP_AUTHENTICATE_GSSAPI_NO_DATA: -      result = imap_state_auth_gssapi_no_data_resp(conn, imapcode, -                                                   imapc->state); -      break; -#endif - -    case IMAP_AUTHENTICATE_XOAUTH2: -      result = imap_state_auth_xoauth2_resp(conn, imapcode, imapc->state); -      break; - -    case IMAP_AUTHENTICATE_CANCEL: -      result = imap_state_auth_cancel_resp(conn, imapcode, imapc->state); -      break; - -    case IMAP_AUTHENTICATE_FINAL: -      result = imap_state_auth_final_resp(conn, imapcode, imapc->state); +    case IMAP_AUTHENTICATE: +      result = imap_state_auth_resp(conn, imapcode, imapc->state);        break;      case IMAP_LOGIN: @@ -2051,7 +1445,7 @@ static CURLcode imap_connect(struct connectdata *conn, bool *done)    /* Set the default preferred authentication type and mechanism */    imapc->preftype = IMAP_TYPE_ANY; -  Curl_sasl_init(&imapc->sasl); +  Curl_sasl_init(&imapc->sasl, &saslimap);    /* Initialise the pingpong layer */    Curl_pp_init(pp); @@ -2748,108 +2142,4 @@ static CURLcode imap_parse_custom_request(struct connectdata *conn)    return result;  } -/*********************************************************************** - * - * imap_calc_sasl_details() - * - * Calculate the required login details for SASL authentication. - */ -static CURLcode imap_calc_sasl_details(struct connectdata *conn, -                                       const char **mech, -                                       char **initresp, size_t *len, -                                       imapstate *state1, imapstate *state2) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  struct imap_conn *imapc = &conn->proto.imapc; - -  /* Calculate the supported authentication mechanism, by decreasing order of -     security, as well as the initial response where appropriate */ -#if defined(USE_KERBEROS5) -    if((imapc->sasl.authmechs & SASL_MECH_GSSAPI) && -       (imapc->sasl.prefmech & SASL_MECH_GSSAPI)) { -    imapc->sasl.mutual_auth = FALSE; /* TODO: Calculate mutual auth. */ - -    *mech = SASL_MECH_STRING_GSSAPI; -    *state1 = IMAP_AUTHENTICATE_GSSAPI; -    *state2 = IMAP_AUTHENTICATE_GSSAPI_TOKEN; -    imapc->sasl.authused = SASL_MECH_GSSAPI; - -    if(imapc->ir_supported || data->set.sasl_ir) -      result = Curl_sasl_create_gssapi_user_message(data, conn->user, -                                                    conn->passwd, "imap", -                                                    imapc->sasl.mutual_auth, -                                                    NULL, &conn->krb5, -                                                    initresp, len); -  } -  else -#endif -#ifndef CURL_DISABLE_CRYPTO_AUTH -  if((imapc->sasl.authmechs & SASL_MECH_DIGEST_MD5) && -     (imapc->sasl.prefmech & SASL_MECH_DIGEST_MD5)) { -    *mech = SASL_MECH_STRING_DIGEST_MD5; -    *state1 = IMAP_AUTHENTICATE_DIGESTMD5; -    imapc->sasl.authused = SASL_MECH_DIGEST_MD5; -  } -  else if((imapc->sasl.authmechs & SASL_MECH_CRAM_MD5) && -          (imapc->sasl.prefmech & SASL_MECH_CRAM_MD5)) { -    *mech = SASL_MECH_STRING_CRAM_MD5; -    *state1 = IMAP_AUTHENTICATE_CRAMMD5; -    imapc->sasl.authused = SASL_MECH_CRAM_MD5; -  } -  else -#endif -#ifdef USE_NTLM -    if((imapc->sasl.authmechs & SASL_MECH_NTLM) && -       (imapc->sasl.prefmech & SASL_MECH_NTLM)) { -    *mech = SASL_MECH_STRING_NTLM; -    *state1 = IMAP_AUTHENTICATE_NTLM; -    *state2 = IMAP_AUTHENTICATE_NTLM_TYPE2MSG; -    imapc->sasl.authused = SASL_MECH_NTLM; - -    if(imapc->ir_supported || data->set.sasl_ir) -      result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, -                                                   &conn->ntlm, -                                                   initresp, len); -  } -  else -#endif -  if(((imapc->sasl.authmechs & SASL_MECH_XOAUTH2) && -      (imapc->sasl.prefmech & SASL_MECH_XOAUTH2) && -      (imapc->sasl.prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) { -    *mech = SASL_MECH_STRING_XOAUTH2; -    *state1 = IMAP_AUTHENTICATE_XOAUTH2; -    *state2 = IMAP_AUTHENTICATE_FINAL; -    imapc->sasl.authused = SASL_MECH_XOAUTH2; - -    if(imapc->ir_supported || data->set.sasl_ir) -      result = Curl_sasl_create_xoauth2_message(data, conn->user, -                                                conn->xoauth2_bearer, -                                                initresp, len); -  } -  else if((imapc->sasl.authmechs & SASL_MECH_LOGIN) && -          (imapc->sasl.prefmech & SASL_MECH_LOGIN)) { -    *mech = SASL_MECH_STRING_LOGIN; -    *state1 = IMAP_AUTHENTICATE_LOGIN; -    *state2 = IMAP_AUTHENTICATE_LOGIN_PASSWD; -    imapc->sasl.authused = SASL_MECH_LOGIN; - -    if(imapc->ir_supported || data->set.sasl_ir) -      result = Curl_sasl_create_login_message(data, conn->user, initresp, len); -  } -  else if((imapc->sasl.authmechs & SASL_MECH_PLAIN) && -          (imapc->sasl.prefmech & SASL_MECH_PLAIN)) { -    *mech = SASL_MECH_STRING_PLAIN; -    *state1 = IMAP_AUTHENTICATE_PLAIN; -    *state2 = IMAP_AUTHENTICATE_FINAL; -    imapc->sasl.authused = SASL_MECH_PLAIN; - -    if(imapc->ir_supported || data->set.sasl_ir) -      result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, -                                              initresp, len); -  } - -  return result; -} -  #endif /* CURL_DISABLE_IMAP */ diff --git a/lib/imap.h b/lib/imap.h index 22e6ada1c..3189daa3c 100644 --- a/lib/imap.h +++ b/lib/imap.h @@ -36,20 +36,7 @@ typedef enum {    IMAP_STARTTLS,    IMAP_UPGRADETLS,   /* asynchronously upgrade the connection to SSL/TLS                         (multi mode only) */ -  IMAP_AUTHENTICATE_PLAIN, -  IMAP_AUTHENTICATE_LOGIN, -  IMAP_AUTHENTICATE_LOGIN_PASSWD, -  IMAP_AUTHENTICATE_CRAMMD5, -  IMAP_AUTHENTICATE_DIGESTMD5, -  IMAP_AUTHENTICATE_DIGESTMD5_RESP, -  IMAP_AUTHENTICATE_NTLM, -  IMAP_AUTHENTICATE_NTLM_TYPE2MSG, -  IMAP_AUTHENTICATE_GSSAPI, -  IMAP_AUTHENTICATE_GSSAPI_TOKEN, -  IMAP_AUTHENTICATE_GSSAPI_NO_DATA, -  IMAP_AUTHENTICATE_XOAUTH2, -  IMAP_AUTHENTICATE_CANCEL, -  IMAP_AUTHENTICATE_FINAL, +  IMAP_AUTHENTICATE,    IMAP_LOGIN,    IMAP_LIST,    IMAP_SELECT, diff --git a/lib/pop3.c b/lib/pop3.c index f5828e515..a7213a44e 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -106,10 +106,10 @@ static CURLcode pop3_setup_connection(struct connectdata *conn);  static CURLcode pop3_parse_url_options(struct connectdata *conn);  static CURLcode pop3_parse_url_path(struct connectdata *conn);  static CURLcode pop3_parse_custom_request(struct connectdata *conn); -static CURLcode pop3_calc_sasl_details(struct connectdata *conn, -                                       const char **mech, -                                       char **initresp, size_t *len, -                                       pop3state *state1, pop3state *state2); +static CURLcode pop3_perform_auth(struct connectdata *conn, const char *mech, +                                  const char *initresp); +static CURLcode pop3_continue_auth(struct connectdata *conn, const char *resp); +static void pop3_get_message(char *buffer, char** outptr);  /*   * POP3 protocol handler. @@ -214,6 +214,17 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = {  #endif  #endif +/* SASL parameters for the pop3 protocol */ +static const struct SASLproto saslpop3 = { +  "pop",                      /* The service name */ +  '+',                        /* Code received when continuation is expected */ +  '+',                        /* Code to receive upon authentication success */ +  255 - 8,                    /* Maximum initial response length (no max) */ +  pop3_perform_auth,          /* Send authentication command */ +  pop3_continue_auth,         /* Send authentication continuation */ +  pop3_get_message            /* Get SASL response message */ +}; +  #ifdef USE_SSL  static void pop3_to_pop3s(struct connectdata *conn)  { @@ -312,20 +323,7 @@ static void state(struct connectdata *conn, pop3state newstate)      "CAPA",      "STARTTLS",      "UPGRADETLS", -    "AUTH_PLAIN", -    "AUTH_LOGIN", -    "AUTH_LOGIN_PASSWD", -    "AUTH_CRAMMD5", -    "AUTH_DIGESTMD5", -    "AUTH_DIGESTMD5_RESP", -    "AUTH_NTLM", -    "AUTH_NTLM_TYPE2MSG", -    "AUTH_GSSAPI", -    "AUTH_GSSAPI_TOKEN", -    "AUTH_GSSAPI_NO_DATA", -    "AUTH_XOAUTH2", -    "AUTH_CANCEL", -    "AUTH_FINAL", +    "AUTH",      "APOP",      "USER",      "PASS", @@ -500,25 +498,18 @@ static CURLcode pop3_perform_apop(struct connectdata *conn)   */  static CURLcode pop3_perform_auth(struct connectdata *conn,                                    const char *mech, -                                  const char *initresp, size_t len, -                                  pop3state state1, pop3state state2) +                                  const char *initresp)  {    CURLcode result = CURLE_OK;    struct pop3_conn *pop3c = &conn->proto.pop3c; -  if(initresp && 8 + strlen(mech) + len <= 255) { /* AUTH <mech> ...<crlf> */ +  if(initresp) {                                  /* AUTH <mech> ...<crlf> */      /* Send the AUTH command with the initial response */      result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp); - -    if(!result) -      state(conn, state2);    }    else {      /* Send the AUTH command */      result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech); - -    if(!result) -      state(conn, state1);    }    return result; @@ -526,6 +517,20 @@ static CURLcode pop3_perform_auth(struct connectdata *conn,  /***********************************************************************   * + * pop3_continue_auth() + * + * Sends SASL continuation data or cancellation. + */ +static CURLcode pop3_continue_auth(struct connectdata *conn, +                                   const char *resp) +{ +  struct pop3_conn *pop3c = &conn->proto.pop3c; + +  return Curl_pp_sendf(&pop3c->pp, "%s", resp); +} + +/*********************************************************************** + *   * pop3_perform_authentication()   *   * Initiates the authentication sequence, with the appropriate SASL @@ -536,38 +541,32 @@ static CURLcode pop3_perform_authentication(struct connectdata *conn)  {    CURLcode result = CURLE_OK;    struct pop3_conn *pop3c = &conn->proto.pop3c; -  const char *mech = NULL; -  char *initresp = NULL; -  size_t len = 0; -  pop3state state1 = POP3_STOP; -  pop3state state2 = POP3_STOP; +  saslprogress progress = SASL_IDLE;    /* Check we have a username and password to authenticate with and end the       connect phase if we don't */    if(!conn->bits.user_passwd) {      state(conn, POP3_STOP); -      return result;    } -  /* Calculate the SASL login details */ -  if(pop3c->authtypes & POP3_TYPE_SASL) -    result = pop3_calc_sasl_details(conn, &mech, &initresp, &len, &state1, -                                    &state2); +  if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) { +    /* Calculate the SASL login details */ +    result = Curl_sasl_start(&pop3c->sasl, conn, FALSE, &progress); -  if(!result) { -    if(mech && (pop3c->preftype & POP3_TYPE_SASL)) { -      /* Perform SASL based authentication */ -      result = pop3_perform_auth(conn, mech, initresp, len, state1, state2); -    } +    if(!result) +      if(progress == SASL_INPROGRESS) +        state(conn, POP3_AUTH); +  } + +  if(!result && progress == SASL_IDLE) {  #ifndef CURL_DISABLE_CRYPTO_AUTH -    else if((pop3c->authtypes & POP3_TYPE_APOP) && -            (pop3c->preftype & POP3_TYPE_APOP)) +    if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)        /* Perform APOP authentication */        result = pop3_perform_apop(conn); +    else  #endif -    else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) && -            (pop3c->preftype & POP3_TYPE_CLEARTEXT)) +    if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT)        /* Perform clear text authentication */        result = pop3_perform_user(conn);      else { @@ -577,8 +576,6 @@ static CURLcode pop3_perform_authentication(struct connectdata *conn)      }    } -  Curl_safefree(initresp); -    return result;  } @@ -807,575 +804,42 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn,    return result;  } -/* For AUTH PLAIN (without initial response) responses */ -static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn, -                                           int pop3code, -                                           pop3state instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  size_t len = 0; -  char *plainauth = NULL; - -  (void)instate; /* no use for this yet */ - -  if(pop3code != '+') { -    failf(data, "Access denied. %c", pop3code); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the authorisation message */ -    result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, -                                            &plainauth, &len); -    if(!result && plainauth) { -      /* Send the message */ -      result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", plainauth); - -      if(!result) -        state(conn, POP3_AUTH_FINAL); -    } -  } - -  Curl_safefree(plainauth); - -  return result; -} - -/* For AUTH LOGIN (without initial response) responses */ -static CURLcode pop3_state_auth_login_resp(struct connectdata *conn, -                                           int pop3code, -                                           pop3state instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  size_t len = 0; -  char *authuser = NULL; - -  (void)instate; /* no use for this yet */ - -  if(pop3code != '+') { -    failf(data, "Access denied: %d", pop3code); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the user message */ -    result = Curl_sasl_create_login_message(data, conn->user, -                                            &authuser, &len); -    if(!result && authuser) { -      /* Send the user */ -      result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authuser); - -      if(!result) -        state(conn, POP3_AUTH_LOGIN_PASSWD); -    } -  } - -  Curl_safefree(authuser); - -  return result; -} - -/* For AUTH LOGIN user entry responses */ -static CURLcode pop3_state_auth_login_password_resp(struct connectdata *conn, -                                                    int pop3code, -                                                    pop3state instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  size_t len = 0; -  char *authpasswd = NULL; - -  (void)instate; /* no use for this yet */ - -  if(pop3code != '+') { -    failf(data, "Access denied: %d", pop3code); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the password message */ -    result = Curl_sasl_create_login_message(data, conn->passwd, -                                            &authpasswd, &len); -    if(!result && authpasswd) { -      /* Send the password */ -      result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authpasswd); - -      if(!result) -        state(conn, POP3_AUTH_FINAL); -    } -  } - -  Curl_safefree(authpasswd); - -  return result; -} - -#ifndef CURL_DISABLE_CRYPTO_AUTH -/* For AUTH CRAM-MD5 responses */ -static CURLcode pop3_state_auth_cram_resp(struct connectdata *conn, -                                          int pop3code, -                                          pop3state instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  char *chlg = NULL; -  char *chlg64 = NULL; -  char *rplyb64 = NULL; -  size_t len = 0; - -  (void)instate; /* no use for this yet */ - -  if(pop3code != '+') { -    failf(data, "Access denied: %d", pop3code); -    return CURLE_LOGIN_DENIED; -  } - -  /* Get the challenge message */ -  pop3_get_message(data->state.buffer, &chlg64); - -  /* Decode the challenge message */ -  result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len); -  if(result) { -    /* Send the cancellation */ -    result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*"); - -    if(!result) -      state(conn, POP3_AUTH_CANCEL); -  } -  else { -    /* Create the response message */ -    result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user, -                                               conn->passwd, &rplyb64, &len); -    if(!result && rplyb64) { -      /* Send the response */ -      result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64); - -      if(!result) -        state(conn, POP3_AUTH_FINAL); -    } -  } - -  Curl_safefree(chlg); -  Curl_safefree(rplyb64); - -  return result; -} - -/* For AUTH DIGEST-MD5 challenge responses */ -static CURLcode pop3_state_auth_digest_resp(struct connectdata *conn, -                                            int pop3code, -                                            pop3state instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  char *chlg64 = NULL; -  char *rplyb64 = NULL; -  size_t len = 0; - -  (void)instate; /* no use for this yet */ - -  if(pop3code != '+') { -    failf(data, "Access denied: %d", pop3code); -    return CURLE_LOGIN_DENIED; -  } - -  /* Get the challenge message */ -  pop3_get_message(data->state.buffer, &chlg64); - -  /* Create the response message */ -  result = Curl_sasl_create_digest_md5_message(data, chlg64, -                                               conn->user, conn->passwd, -                                               "pop", &rplyb64, &len); -  if(result) { -    if(result == CURLE_BAD_CONTENT_ENCODING) { -      /* Send the cancellation */ -      result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*"); - -      if(!result) -        state(conn, POP3_AUTH_CANCEL); -    } -  } -  else { -    /* Send the response */ -    result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64); - -    if(!result) -      state(conn, POP3_AUTH_DIGESTMD5_RESP); -  } - -  Curl_safefree(rplyb64); - -  return result; -} - -/* For AUTH DIGEST-MD5 challenge-response responses */ -static CURLcode pop3_state_auth_digest_resp_resp(struct connectdata *conn, -                                                 int pop3code, -                                                 pop3state instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; - -  (void)instate; /* no use for this yet */ - -  if(pop3code != '+') { -    failf(data, "Authentication failed: %d", pop3code); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Send an empty response */ -    result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", ""); - -    if(!result) -      state(conn, POP3_AUTH_FINAL); -  } - -  return result; -} -#endif - -#ifdef USE_NTLM -/* For AUTH NTLM (without initial response) responses */ -static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn, -                                          int pop3code, -                                          pop3state instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  size_t len = 0; -  char *type1msg = NULL; - -  (void)instate; /* no use for this yet */ - -  if(pop3code != '+') { -    failf(data, "Access denied: %d", pop3code); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the type-1 message */ -    result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, -                                                 &conn->ntlm, -                                                 &type1msg, &len); -    if(!result && type1msg) { -      /* Send the message */ -      result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type1msg); - -      if(!result) -        state(conn, POP3_AUTH_NTLM_TYPE2MSG); -    } -  } - -  Curl_safefree(type1msg); - -  return result; -} - -/* For NTLM type-2 responses (sent in reponse to our type-1 message) */ -static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn, -                                                   int pop3code, -                                                   pop3state instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  char *type2msg = NULL; -  char *type3msg = NULL; -  size_t len = 0; - -  (void)instate; /* no use for this yet */ - -  if(pop3code != '+') { -    failf(data, "Access denied: %d", pop3code); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Get the type-2 message */ -    pop3_get_message(data->state.buffer, &type2msg); - -    /* Decode the type-2 message */ -    result = Curl_sasl_decode_ntlm_type2_message(data, type2msg, &conn->ntlm); -    if(result) { -      /* Send the cancellation */ -      result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*"); - -      if(!result) -        state(conn, POP3_AUTH_CANCEL); -    } -    else { -      /* Create the type-3 message */ -      result = Curl_sasl_create_ntlm_type3_message(data, conn->user, -                                                   conn->passwd, &conn->ntlm, -                                                   &type3msg, &len); -      if(!result && type3msg) { -        /* Send the message */ -        result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type3msg); - -        if(!result) -          state(conn, POP3_AUTH_FINAL); -      } -    } -  } - -  Curl_safefree(type3msg); - -  return result; -} -#endif - -#if defined(USE_KERBEROS5) -/* For AUTH GSSAPI (without initial response) responses */ -static CURLcode pop3_state_auth_gssapi_resp(struct connectdata *conn, -                                            int pop3code, -                                            pop3state instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  struct pop3_conn *pop3c = &conn->proto.pop3c; -  size_t len = 0; -  char *respmsg = NULL; - -  (void)instate; /* no use for this yet */ - -  if(pop3code != '+') { -    failf(data, "Access denied: %d", pop3code); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the initial response message */ -    result = Curl_sasl_create_gssapi_user_message(data, conn->user, -                                                  conn->passwd, "pop", -                                                  pop3c->sasl.mutual_auth, -                                                  NULL, &conn->krb5, -                                                  &respmsg, &len); -    if(!result && respmsg) { -      /* Send the message */ -      result = Curl_pp_sendf(&pop3c->pp, "%s", respmsg); - -      if(!result) -        state(conn, POP3_AUTH_GSSAPI_TOKEN); -    } -  } - -  Curl_safefree(respmsg); - -  return result; -} - -/* For AUTH GSSAPI user token responses */ -static CURLcode pop3_state_auth_gssapi_token_resp(struct connectdata *conn, -                                                  int pop3code, -                                                  pop3state instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  struct pop3_conn *pop3c = &conn->proto.pop3c; -  char *chlgmsg = NULL; -  char *respmsg = NULL; -  size_t len = 0; - -  (void)instate; /* no use for this yet */ - -  if(pop3code != '+') { -    failf(data, "Access denied: %d", pop3code); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Get the challenge message */ -    pop3_get_message(data->state.buffer, &chlgmsg); - -    if(pop3c->sasl.mutual_auth) -      /* Decode the user token challenge and create the optional response -         message */ -      result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL, -                                                    pop3c->sasl.mutual_auth, -                                                    chlgmsg, &conn->krb5, -                                                    &respmsg, &len); -    else -      /* Decode the security challenge and create the response message */ -      result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, -                                                        &conn->krb5, -                                                        &respmsg, &len); - -    if(result) { -      if(result == CURLE_BAD_CONTENT_ENCODING) { -        /* Send the cancellation */ -        result = Curl_pp_sendf(&pop3c->pp, "%s", "*"); - -        if(!result) -          state(conn, POP3_AUTH_CANCEL); -      } -    } -    else { -      /* Send the response */ -      if(respmsg) -        result = Curl_pp_sendf(&pop3c->pp, "%s", respmsg); -      else -        result = Curl_pp_sendf(&pop3c->pp, "%s", ""); - -      if(!result) -        state(conn, (pop3c->sasl.mutual_auth ? POP3_AUTH_GSSAPI_NO_DATA : -                                               POP3_AUTH_FINAL)); -    } -  } - -  Curl_safefree(respmsg); - -  return result; -} - -/* For AUTH GSSAPI no data responses */ -static CURLcode pop3_state_auth_gssapi_no_data_resp(struct connectdata *conn, -                                                    int pop3code, -                                                    pop3state instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  char *chlgmsg = NULL; -  char *respmsg = NULL; -  size_t len = 0; - -  (void)instate; /* no use for this yet */ - -  if(pop3code != '+') { -    failf(data, "Access denied: %d", pop3code); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Get the challenge message */ -    pop3_get_message(data->state.buffer, &chlgmsg); - -    /* Decode the security challenge and create the security message */ -    result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, -                                                      &conn->krb5, -                                                      &respmsg, &len); -    if(result) { -      if(result == CURLE_BAD_CONTENT_ENCODING) { -        /* Send the cancellation */ -        result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*"); - -        if(!result) -          state(conn, POP3_AUTH_CANCEL); -      } -    } -    else { -      /* Send the response */ -      if(respmsg) { -        result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", respmsg); - -        if(!result) -          state(conn, POP3_AUTH_FINAL); -      } -    } -  } - -  Curl_safefree(respmsg); - -  return result; -} -#endif - -/* For AUTH XOAUTH2 (without initial response) responses */ -static CURLcode pop3_state_auth_xoauth2_resp(struct connectdata *conn, -                                             int pop3code, pop3state instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  size_t len = 0; -  char *xoauth = NULL; - -  (void)instate; /* no use for this yet */ - -  if(pop3code != '+') { -    failf(data, "Access denied: %d", pop3code); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the authorisation message */ -    result = Curl_sasl_create_xoauth2_message(conn->data, conn->user, -                                              conn->xoauth2_bearer, -                                              &xoauth, &len); -    if(!result && xoauth) { -      /* Send the message */ -      result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", xoauth); - -      if(!result) -        state(conn, POP3_AUTH_FINAL); -    } -  } - -  Curl_safefree(xoauth); - -  return result; -} - -/* For AUTH cancellation responses */ -static CURLcode pop3_state_auth_cancel_resp(struct connectdata *conn, -                                            int pop3code, -                                            pop3state instate) +/* For SASL authentication responses */ +static CURLcode pop3_state_auth_resp(struct connectdata *conn, +                                     int pop3code, +                                     pop3state instate)  {    CURLcode result = CURLE_OK;    struct SessionHandle *data = conn->data;    struct pop3_conn *pop3c = &conn->proto.pop3c; -  const char *mech = NULL; -  char *initresp = NULL; -  size_t len = 0; -  pop3state state1 = POP3_STOP; -  pop3state state2 = POP3_STOP; +  saslprogress progress; -  (void)pop3code;    (void)instate; /* no use for this yet */ -  /* Remove the offending mechanism from the supported list */ -  pop3c->sasl.authmechs ^= pop3c->sasl.authused; - -  /* Calculate alternative SASL login details */ -  result = pop3_calc_sasl_details(conn, &mech, &initresp, &len, &state1, -                                  &state2); - -  if(!result) { -    /* Do we have any mechanisms left or can we fallback to another -       authentication type? */ -    if(mech) { -      /* Retry SASL based authentication */ -      result = pop3_perform_auth(conn, mech, initresp, len, state1, state2); - -      Curl_safefree(initresp); -    } +  result = Curl_sasl_continue(&pop3c->sasl, conn, pop3code, &progress); +  if(!result) +    switch(progress) { +    case SASL_DONE: +      state(conn, POP3_STOP);  /* Authenticated */ +      break; +    case SASL_IDLE:            /* No mechanism left after cancellation */  #ifndef CURL_DISABLE_CRYPTO_AUTH -    else if((pop3c->authtypes & POP3_TYPE_APOP) && -            (pop3c->preftype & POP3_TYPE_APOP)) -      /* Perform APOP authentication */ -      result = pop3_perform_apop(conn); +      if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) +        /* Perform APOP authentication */ +        result = pop3_perform_apop(conn); +      else  #endif -    else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) && -            (pop3c->preftype & POP3_TYPE_CLEARTEXT)) -      /* Perform clear text authentication */ -      result = pop3_perform_user(conn); -    else { -      failf(data, "Authentication cancelled"); - -      result = CURLE_LOGIN_DENIED; +      if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) +        /* Perform clear text authentication */ +        result = pop3_perform_user(conn); +      else { +        failf(data, "Authentication cancelled"); +        result = CURLE_LOGIN_DENIED; +      } +      break; +    default: +      break;      } -  } - -  return result; -} - -/* For final responses in the AUTH sequence */ -static CURLcode pop3_state_auth_final_resp(struct connectdata *conn, -                                           int pop3code, -                                           pop3state instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; - -  (void)instate; /* no use for this yet */ - -  if(pop3code != '+') { -    failf(data, "Authentication failed: %d", pop3code); -    result = CURLE_LOGIN_DENIED; -  } -  else -    /* End of connect phase */ -    state(conn, POP3_STOP);    return result;  } @@ -1542,69 +1006,8 @@ static CURLcode pop3_statemach_act(struct connectdata *conn)        result = pop3_state_starttls_resp(conn, pop3code, pop3c->state);        break; -    case POP3_AUTH_PLAIN: -      result = pop3_state_auth_plain_resp(conn, pop3code, pop3c->state); -      break; - -    case POP3_AUTH_LOGIN: -      result = pop3_state_auth_login_resp(conn, pop3code, pop3c->state); -      break; - -    case POP3_AUTH_LOGIN_PASSWD: -      result = pop3_state_auth_login_password_resp(conn, pop3code, -                                                   pop3c->state); -      break; - -#ifndef CURL_DISABLE_CRYPTO_AUTH -    case POP3_AUTH_CRAMMD5: -      result = pop3_state_auth_cram_resp(conn, pop3code, pop3c->state); -      break; - -    case POP3_AUTH_DIGESTMD5: -      result = pop3_state_auth_digest_resp(conn, pop3code, pop3c->state); -      break; - -    case POP3_AUTH_DIGESTMD5_RESP: -      result = pop3_state_auth_digest_resp_resp(conn, pop3code, pop3c->state); -      break; -#endif - -#ifdef USE_NTLM -    case POP3_AUTH_NTLM: -      result = pop3_state_auth_ntlm_resp(conn, pop3code, pop3c->state); -      break; - -    case POP3_AUTH_NTLM_TYPE2MSG: -      result = pop3_state_auth_ntlm_type2msg_resp(conn, pop3code, -                                                  pop3c->state); -      break; -#endif - -#if defined(USE_KERBEROS5) -    case POP3_AUTH_GSSAPI: -      result = pop3_state_auth_gssapi_resp(conn, pop3code, pop3c->state); -      break; - -    case POP3_AUTH_GSSAPI_TOKEN: -      result = pop3_state_auth_gssapi_token_resp(conn, pop3code, pop3c->state); -      break; - -    case POP3_AUTH_GSSAPI_NO_DATA: -      result = pop3_state_auth_gssapi_no_data_resp(conn, pop3code, -                                                   pop3c->state); -      break; -#endif - -    case POP3_AUTH_XOAUTH2: -      result = pop3_state_auth_xoauth2_resp(conn, pop3code, pop3c->state); -      break; - -    case POP3_AUTH_CANCEL: -      result = pop3_state_auth_cancel_resp(conn, pop3code, pop3c->state); -      break; - -    case POP3_AUTH_FINAL: -      result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state); +    case POP3_AUTH: +      result = pop3_state_auth_resp(conn, pop3code, pop3c->state);        break;  #ifndef CURL_DISABLE_CRYPTO_AUTH @@ -1717,7 +1120,7 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done)    /* Set the default preferred authentication type and mechanism */    pop3c->preftype = POP3_TYPE_ANY; -  Curl_sasl_init(&pop3c->sasl); +  Curl_sasl_init(&pop3c->sasl, &saslpop3);    /* Initialise the pingpong layer */    Curl_pp_init(pp); @@ -2072,110 +1475,6 @@ static CURLcode pop3_parse_custom_request(struct connectdata *conn)  /***********************************************************************   * - * pop3_calc_sasl_details() - * - * Calculate the required login details for SASL authentication. - */ -static CURLcode pop3_calc_sasl_details(struct connectdata *conn, -                                       const char **mech, -                                       char **initresp, size_t *len, -                                       pop3state *state1, pop3state *state2) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  struct pop3_conn *pop3c = &conn->proto.pop3c; - -  /* Calculate the supported authentication mechanism, by decreasing order of -     security, as well as the initial response where appropriate */ -#if defined(USE_KERBEROS5) -  if((pop3c->sasl.authmechs & SASL_MECH_GSSAPI) && -      (pop3c->sasl.prefmech & SASL_MECH_GSSAPI)) { -    pop3c->sasl.mutual_auth = FALSE; /* TODO: Calculate mutual auth. */ - -    *mech = SASL_MECH_STRING_GSSAPI; -    *state1 = POP3_AUTH_GSSAPI; -    *state2 = POP3_AUTH_GSSAPI_TOKEN; -    pop3c->sasl.authused = SASL_MECH_GSSAPI; - -    if(data->set.sasl_ir) -      result = Curl_sasl_create_gssapi_user_message(data, conn->user, -                                                    conn->passwd, "pop", -                                                    pop3c->sasl.mutual_auth, -                                                    NULL, &conn->krb5, -                                                    initresp, len); -  } -  else -#endif -#ifndef CURL_DISABLE_CRYPTO_AUTH -  if((pop3c->sasl.authmechs & SASL_MECH_DIGEST_MD5) && -      (pop3c->sasl.prefmech & SASL_MECH_DIGEST_MD5)) { -    *mech = SASL_MECH_STRING_DIGEST_MD5; -    *state1 = POP3_AUTH_DIGESTMD5; -    pop3c->sasl.authused = SASL_MECH_DIGEST_MD5; -  } -  else if((pop3c->sasl.authmechs & SASL_MECH_CRAM_MD5) && -          (pop3c->sasl.prefmech & SASL_MECH_CRAM_MD5)) { -    *mech = SASL_MECH_STRING_CRAM_MD5; -    *state1 = POP3_AUTH_CRAMMD5; -    pop3c->sasl.authused = SASL_MECH_CRAM_MD5; -  } -  else -#endif -#ifdef USE_NTLM -  if((pop3c->sasl.authmechs & SASL_MECH_NTLM) && -      (pop3c->sasl.prefmech & SASL_MECH_NTLM)) { -    *mech = SASL_MECH_STRING_NTLM; -    *state1 = POP3_AUTH_NTLM; -    *state2 = POP3_AUTH_NTLM_TYPE2MSG; -    pop3c->sasl.authused = SASL_MECH_NTLM; - -    if(data->set.sasl_ir) -      result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, -                                                    &conn->ntlm, -                                                    initresp, len); -  } -  else -#endif -  if(((pop3c->sasl.authmechs & SASL_MECH_XOAUTH2) && -      (pop3c->sasl.prefmech & SASL_MECH_XOAUTH2) && -      (pop3c->sasl.prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) { -    *mech = SASL_MECH_STRING_XOAUTH2; -    *state1 = POP3_AUTH_XOAUTH2; -    *state2 = POP3_AUTH_FINAL; -    pop3c->sasl.authused = SASL_MECH_XOAUTH2; - -    if(data->set.sasl_ir) -      result = Curl_sasl_create_xoauth2_message(data, conn->user, -                                                conn->xoauth2_bearer, -                                                initresp, len); -  } -  else if((pop3c->sasl.authmechs & SASL_MECH_LOGIN) && -          (pop3c->sasl.prefmech & SASL_MECH_LOGIN)) { -    *mech = SASL_MECH_STRING_LOGIN; -    *state1 = POP3_AUTH_LOGIN; -    *state2 = POP3_AUTH_LOGIN_PASSWD; -    pop3c->sasl.authused = SASL_MECH_LOGIN; - -    if(data->set.sasl_ir) -      result = Curl_sasl_create_login_message(data, conn->user, initresp, len); -  } -  else if((pop3c->sasl.authmechs & SASL_MECH_PLAIN) && -          (pop3c->sasl.prefmech & SASL_MECH_PLAIN)) { -    *mech = SASL_MECH_STRING_PLAIN; -    *state1 = POP3_AUTH_PLAIN; -    *state2 = POP3_AUTH_FINAL; -    pop3c->sasl.authused = SASL_MECH_PLAIN; - -    if(data->set.sasl_ir) -      result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, -                                              initresp, len); -  } - -  return result; -} - -/*********************************************************************** - *   * Curl_pop3_write()   *   * This function scans the body after the end-of-body and writes everything diff --git a/lib/pop3.h b/lib/pop3.h index 0cb5852d8..7bc53aaf5 100644 --- a/lib/pop3.h +++ b/lib/pop3.h @@ -36,20 +36,7 @@ typedef enum {    POP3_STARTTLS,    POP3_UPGRADETLS,   /* asynchronously upgrade the connection to SSL/TLS                         (multi mode only) */ -  POP3_AUTH_PLAIN, -  POP3_AUTH_LOGIN, -  POP3_AUTH_LOGIN_PASSWD, -  POP3_AUTH_CRAMMD5, -  POP3_AUTH_DIGESTMD5, -  POP3_AUTH_DIGESTMD5_RESP, -  POP3_AUTH_NTLM, -  POP3_AUTH_NTLM_TYPE2MSG, -  POP3_AUTH_GSSAPI, -  POP3_AUTH_GSSAPI_TOKEN, -  POP3_AUTH_GSSAPI_NO_DATA, -  POP3_AUTH_XOAUTH2, -  POP3_AUTH_CANCEL, -  POP3_AUTH_FINAL, +  POP3_AUTH,    POP3_APOP,    POP3_USER,    POP3_PASS, diff --git a/lib/smtp.c b/lib/smtp.c index e5ddedb02..ca1ab2cec 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -105,10 +105,10 @@ static CURLcode smtp_setup_connection(struct connectdata *conn);  static CURLcode smtp_parse_url_options(struct connectdata *conn);  static CURLcode smtp_parse_url_path(struct connectdata *conn);  static CURLcode smtp_parse_custom_request(struct connectdata *conn); -static CURLcode smtp_calc_sasl_details(struct connectdata *conn, -                                       const char **mech, -                                       char **initresp, size_t *len, -                                       smtpstate *state1, smtpstate *state2); +static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech, +                                  const char *initresp); +static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp); +static void smtp_get_message(char *buffer, char** outptr);  /*   * SMTP protocol handler. @@ -213,6 +213,17 @@ static const struct Curl_handler Curl_handler_smtps_proxy = {  #endif  #endif +/* SASL parameters for the smtp protocol */ +static const struct SASLproto saslsmtp = { +  "smtp",                     /* The service name */ +  334,                        /* Code received when continuation is expected */ +  235,                        /* Code to receive upon authentication success */ +  512 - 8,                    /* Maximum initial response length (no max) */ +  smtp_perform_auth,          /* Send authentication command */ +  smtp_continue_auth,         /* Send authentication continuation */ +  smtp_get_message            /* Get SASL response message */ +}; +  #ifdef USE_SSL  static void smtp_to_smtps(struct connectdata *conn)  { @@ -309,20 +320,7 @@ static void state(struct connectdata *conn, smtpstate newstate)      "HELO",      "STARTTLS",      "UPGRADETLS", -    "AUTH_PLAIN", -    "AUTH_LOGIN", -    "AUTH_LOGIN_PASSWD", -    "AUTH_CRAMMD5", -    "AUTH_DIGESTMD5", -    "AUTH_DIGESTMD5_RESP", -    "AUTH_NTLM", -    "AUTH_NTLM_TYPE2MSG", -    "AUTH_GSSAPI", -    "AUTH_GSSAPI_TOKEN", -    "AUTH_GSSAPI_NO_DATA", -    "AUTH_XOAUTH2", -    "AUTH_CANCEL", -    "AUTH_FINAL", +    "AUTH",      "COMMAND",      "MAIL",      "RCPT", @@ -445,25 +443,18 @@ static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn)   */  static CURLcode smtp_perform_auth(struct connectdata *conn,                                    const char *mech, -                                  const char *initresp, size_t len, -                                  smtpstate state1, smtpstate state2) +                                  const char *initresp)  {    CURLcode result = CURLE_OK;    struct smtp_conn *smtpc = &conn->proto.smtpc; -  if(initresp && 8 + strlen(mech) + len <= 512) { /* AUTH <mech> ...<crlf> */ +  if(initresp) {                                  /* AUTH <mech> ...<crlf> */      /* Send the AUTH command with the initial response */      result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp); - -    if(!result) -      state(conn, state2);    }    else {      /* Send the AUTH command */      result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech); - -    if(!result) -      state(conn, state1);    }    return result; @@ -471,6 +462,19 @@ static CURLcode smtp_perform_auth(struct connectdata *conn,  /***********************************************************************   * + * smtp_continue_auth() + * + * Sends SASL continuation data or cancellation. + */ +static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp) +{ +  struct smtp_conn *smtpc = &conn->proto.smtpc; + +  return Curl_pp_sendf(&smtpc->pp, "%s", resp); +} + +/*********************************************************************** + *   * smtp_perform_authentication()   *   * Initiates the authentication sequence, with the appropriate SASL @@ -480,31 +484,21 @@ static CURLcode smtp_perform_authentication(struct connectdata *conn)  {    CURLcode result = CURLE_OK;    struct smtp_conn *smtpc = &conn->proto.smtpc; -  const char *mech = NULL; -  char *initresp = NULL; -  size_t len = 0; -  smtpstate state1 = SMTP_STOP; -  smtpstate state2 = SMTP_STOP; +  saslprogress progress;    /* Check we have a username and password to authenticate with, and the       server supports authentiation, and end the connect phase if not */    if(!conn->bits.user_passwd || !smtpc->auth_supported) {      state(conn, SMTP_STOP); -      return result;    }    /* Calculate the SASL login details */ -  result = smtp_calc_sasl_details(conn, &mech, &initresp, &len, &state1, -                                  &state2); +  result = Curl_sasl_start(&smtpc->sasl, conn, FALSE, &progress);    if(!result) { -    if(mech) { -      /* Perform SASL based authentication */ -      result = smtp_perform_auth(conn, mech, initresp, len, state1, state2); - -      Curl_safefree(initresp); -    } +    if(progress == SASL_INPROGRESS) +      state(conn, SMTP_AUTH);      else {        /* Other mechanisms not supported */        infof(conn->data, "No known authentication mechanisms supported!\n"); @@ -825,566 +819,31 @@ static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode,    return result;  } -/* For AUTH PLAIN (without initial response) responses */ -static CURLcode smtp_state_auth_plain_resp(struct connectdata *conn, -                                           int smtpcode, -                                           smtpstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  size_t len = 0; -  char *plainauth = NULL; - -  (void)instate; /* no use for this yet */ - -  if(smtpcode != 334) { -    failf(data, "Access denied: %d", smtpcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the authorisation message */ -    result = Curl_sasl_create_plain_message(conn->data, conn->user, -                                            conn->passwd, &plainauth, &len); -    if(!result && plainauth) { -      /* Send the message */ -      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth); - -      if(!result) -        state(conn, SMTP_AUTH_FINAL); -    } -  } - -  Curl_safefree(plainauth); - -  return result; -} - -/* For AUTH LOGIN (without initial response) responses */ -static CURLcode smtp_state_auth_login_resp(struct connectdata *conn, -                                           int smtpcode, -                                           smtpstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  size_t len = 0; -  char *authuser = NULL; - -  (void)instate; /* no use for this yet */ - -  if(smtpcode != 334) { -    failf(data, "Access denied: %d", smtpcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the user message */ -    result = Curl_sasl_create_login_message(conn->data, conn->user, -                                            &authuser, &len); -    if(!result && authuser) { -      /* Send the user */ -      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser); - -      if(!result) -        state(conn, SMTP_AUTH_LOGIN_PASSWD); -    } -  } - -  Curl_safefree(authuser); - -  return result; -} - -/* For AUTH LOGIN user entry responses */ -static CURLcode smtp_state_auth_login_password_resp(struct connectdata *conn, -                                                    int smtpcode, -                                                    smtpstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  size_t len = 0; -  char *authpasswd = NULL; - -  (void)instate; /* no use for this yet */ - -  if(smtpcode != 334) { -    failf(data, "Access denied: %d", smtpcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the password message */ -    result = Curl_sasl_create_login_message(conn->data, conn->passwd, -                                            &authpasswd, &len); -    if(!result && authpasswd) { -      /* Send the password */ -      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd); - -      if(!result) -        state(conn, SMTP_AUTH_FINAL); -    } -  } - -  Curl_safefree(authpasswd); - -  return result; -} - -#ifndef CURL_DISABLE_CRYPTO_AUTH -/* For AUTH CRAM-MD5 responses */ -static CURLcode smtp_state_auth_cram_resp(struct connectdata *conn, -                                          int smtpcode, -                                          smtpstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  char *chlg = NULL; -  char *chlg64 = NULL; -  char *rplyb64 = NULL; -  size_t len = 0; - -  (void)instate; /* no use for this yet */ - -  if(smtpcode != 334) { -    failf(data, "Access denied: %d", smtpcode); -    return CURLE_LOGIN_DENIED; -  } - -  /* Get the challenge message */ -  smtp_get_message(data->state.buffer, &chlg64); - -  /* Decode the challenge message */ -  result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len); -  if(result) { -    /* Send the cancellation */ -    result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*"); - -    if(!result) -      state(conn, SMTP_AUTH_CANCEL); -  } -  else { -    /* Create the response message */ -    result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user, -                                               conn->passwd, &rplyb64, &len); -    if(!result && rplyb64) { -      /* Send the response */ -      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64); - -      if(!result) -        state(conn, SMTP_AUTH_FINAL); -    } -  } - -  Curl_safefree(chlg); -  Curl_safefree(rplyb64); - -  return result; -} - -/* For AUTH DIGEST-MD5 challenge responses */ -static CURLcode smtp_state_auth_digest_resp(struct connectdata *conn, -                                            int smtpcode, -                                            smtpstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  char *chlg64 = NULL; -  char *rplyb64 = NULL; -  size_t len = 0; - -  (void)instate; /* no use for this yet */ - -  if(smtpcode != 334) { -    failf(data, "Access denied: %d", smtpcode); -    return CURLE_LOGIN_DENIED; -  } - -  /* Get the challenge message */ -  smtp_get_message(data->state.buffer, &chlg64); - -  /* Create the response message */ -  result = Curl_sasl_create_digest_md5_message(data, chlg64, -                                               conn->user, conn->passwd, -                                               "smtp", &rplyb64, &len); -  if(result) { -    if(result == CURLE_BAD_CONTENT_ENCODING) { -      /* Send the cancellation */ -      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*"); - -      if(!result) -        state(conn, SMTP_AUTH_CANCEL); -    } -  } -  else { -    /* Send the response */ -    result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64); - -    if(!result) -      state(conn, SMTP_AUTH_DIGESTMD5_RESP); -  } - -  Curl_safefree(rplyb64); - -  return result; -} - -/* For AUTH DIGEST-MD5 challenge-response responses */ -static CURLcode smtp_state_auth_digest_resp_resp(struct connectdata *conn, -                                                 int smtpcode, -                                                 smtpstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; - -  (void)instate; /* no use for this yet */ - -  if(smtpcode != 334) { -    failf(data, "Authentication failed: %d", smtpcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Send an empty response */ -    result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", ""); - -    if(!result) -      state(conn, SMTP_AUTH_FINAL); -  } - -  return result; -} - -#endif - -#ifdef USE_NTLM -/* For AUTH NTLM (without initial response) responses */ -static CURLcode smtp_state_auth_ntlm_resp(struct connectdata *conn, -                                          int smtpcode, -                                          smtpstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  char *type1msg = NULL; -  size_t len = 0; - -  (void)instate; /* no use for this yet */ - -  if(smtpcode != 334) { -    failf(data, "Access denied: %d", smtpcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the type-1 message */ -    result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, -                                                 &conn->ntlm, -                                                 &type1msg, &len); -    if(!result && type1msg) { -      /* Send the message */ -      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type1msg); - -      if(!result) -        state(conn, SMTP_AUTH_NTLM_TYPE2MSG); -    } -  } - -  Curl_safefree(type1msg); - -  return result; -} - -/* For NTLM type-2 responses (sent in reponse to our type-1 message) */ -static CURLcode smtp_state_auth_ntlm_type2msg_resp(struct connectdata *conn, -                                                   int smtpcode, -                                                   smtpstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  char *type2msg = NULL; -  char *type3msg = NULL; -  size_t len = 0; - -  (void)instate; /* no use for this yet */ - -  if(smtpcode != 334) { -    failf(data, "Access denied: %d", smtpcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Get the type-2 message */ -    smtp_get_message(data->state.buffer, &type2msg); - -    /* Decode the type-2 message */ -    result = Curl_sasl_decode_ntlm_type2_message(data, type2msg, &conn->ntlm); -    if(result) { -      /* Send the cancellation */ -      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*"); - -      if(!result) -        state(conn, SMTP_AUTH_CANCEL); -    } -    else { -      /* Create the type-3 message */ -      result = Curl_sasl_create_ntlm_type3_message(data, conn->user, -                                                   conn->passwd, &conn->ntlm, -                                                   &type3msg, &len); -      if(!result && type3msg) { -        /* Send the message */ -        result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type3msg); - -        if(!result) -          state(conn, SMTP_AUTH_FINAL); -      } -    } -  } - -  Curl_safefree(type3msg); - -  return result; -} -#endif - -#if defined(USE_KERBEROS5) -/* For AUTH GSSAPI (without initial response) responses */ -static CURLcode smtp_state_auth_gssapi_resp(struct connectdata *conn, -                                            int smtpcode, -                                            smtpstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  struct smtp_conn *smtpc = &conn->proto.smtpc; -  char *respmsg = NULL; -  size_t len = 0; - -  (void)instate; /* no use for this yet */ - -  if(smtpcode != 334) { -    failf(data, "Access denied: %d", smtpcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the initial response message */ -    result = Curl_sasl_create_gssapi_user_message(data, conn->user, -                                                  conn->passwd, "smtp", -                                                  smtpc->sasl.mutual_auth, -                                                  NULL, -                                                  &conn->krb5, -                                                  &respmsg, &len); -    if(!result && respmsg) { -      /* Send the message */ -      result = Curl_pp_sendf(&smtpc->pp, "%s", respmsg); - -      if(!result) -        state(conn, SMTP_AUTH_GSSAPI_TOKEN); -    } -  } - -  Curl_safefree(respmsg); - -  return result; -} - -/* For AUTH GSSAPI user token responses */ -static CURLcode smtp_state_auth_gssapi_token_resp(struct connectdata *conn, -                                                  int smtpcode, -                                                  smtpstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  struct smtp_conn *smtpc = &conn->proto.smtpc; -  char *chlgmsg = NULL; -  char *respmsg = NULL; -  size_t len = 0; - -  (void)instate; /* no use for this yet */ - -  if(smtpcode != 334) { -    failf(data, "Access denied: %d", smtpcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Get the challenge message */ -    smtp_get_message(data->state.buffer, &chlgmsg); - -    if(smtpc->sasl.mutual_auth) -      /* Decode the user token challenge and create the optional response -         message */ -      result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL, -                                                    smtpc->sasl.mutual_auth, -                                                    chlgmsg, &conn->krb5, -                                                    &respmsg, &len); -    else -      /* Decode the security challenge and create the response message */ -      result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, -                                                        &conn->krb5, -                                                        &respmsg, &len); - -    if(result) { -      if(result == CURLE_BAD_CONTENT_ENCODING) { -        /* Send the cancellation */ -        result = Curl_pp_sendf(&smtpc->pp, "%s", "*"); - -        if(!result) -          state(conn, SMTP_AUTH_CANCEL); -      } -    } -    else { -      /* Send the response */ -      if(respmsg) -        result = Curl_pp_sendf(&smtpc->pp, "%s", respmsg); -      else -        result = Curl_pp_sendf(&smtpc->pp, "%s", ""); - -      if(!result) -        state(conn, (smtpc->sasl.mutual_auth ? SMTP_AUTH_GSSAPI_NO_DATA : -                                          SMTP_AUTH_FINAL)); -    } -  } - -  Curl_safefree(respmsg); - -  return result; -} - -/* For AUTH GSSAPI no data responses */ -static CURLcode smtp_state_auth_gssapi_no_data_resp(struct connectdata *conn, -                                                    int smtpcode, -                                                    smtpstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  char *chlgmsg = NULL; -  char *respmsg = NULL; -  size_t len = 0; - -  (void)instate; /* no use for this yet */ - -  if(smtpcode != 334) { -    failf(data, "Access denied: %d", smtpcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Get the challenge message */ -    smtp_get_message(data->state.buffer, &chlgmsg); - -    /* Decode the security challenge and create the response message */ -    result = Curl_sasl_create_gssapi_security_message(data, chlgmsg, -                                                      &conn->krb5, -                                                      &respmsg, &len); -    if(result) { -      if(result == CURLE_BAD_CONTENT_ENCODING) { -        /* Send the cancellation */ -        result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "*"); - -        if(!result) -          state(conn, SMTP_AUTH_CANCEL); -      } -    } -    else { -      /* Send the response */ -      if(respmsg) { -        result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", respmsg); - -        if(!result) -          state(conn, SMTP_AUTH_FINAL); -      } -    } -  } - -  Curl_safefree(respmsg); - -  return result; -} -#endif - -/* For AUTH XOAUTH2 (without initial response) responses */ -static CURLcode smtp_state_auth_xoauth2_resp(struct connectdata *conn, -                                             int smtpcode, smtpstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  size_t len = 0; -  char *xoauth = NULL; - -  (void)instate; /* no use for this yet */ - -  if(smtpcode != 334) { -    failf(data, "Access denied: %d", smtpcode); -    result = CURLE_LOGIN_DENIED; -  } -  else { -    /* Create the authorisation message */ -    result = Curl_sasl_create_xoauth2_message(conn->data, conn->user, -                                              conn->xoauth2_bearer, -                                              &xoauth, &len); -    if(!result && xoauth) { -      /* Send the message */ -      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", xoauth); - -      if(!result) -        state(conn, SMTP_AUTH_FINAL); -    } -  } - -  Curl_safefree(xoauth); - -  return result; -} - -/* For AUTH cancellation responses */ -static CURLcode smtp_state_auth_cancel_resp(struct connectdata *conn, -                                            int smtpcode, -                                            smtpstate instate) +/* For SASL authentication responses */ +static CURLcode smtp_state_auth_resp(struct connectdata *conn, +                                     int smtpcode, +                                     smtpstate instate)  {    CURLcode result = CURLE_OK;    struct SessionHandle *data = conn->data;    struct smtp_conn *smtpc = &conn->proto.smtpc; -  const char *mech = NULL; -  char *initresp = NULL; -  size_t len = 0; -  smtpstate state1 = SMTP_STOP; -  smtpstate state2 = SMTP_STOP; +  saslprogress progress; -  (void)smtpcode;    (void)instate; /* no use for this yet */ -  /* Remove the offending mechanism from the supported list */ -  smtpc->sasl.authmechs ^= smtpc->sasl.authused; - -  /* Calculate alternative SASL login details */ -  result = smtp_calc_sasl_details(conn, &mech, &initresp, &len, &state1, -                                  &state2); - -  if(!result) { -    /* Do we have any mechanisms left? */ -    if(mech) { -      /* Retry SASL based authentication */ -      result = smtp_perform_auth(conn, mech, initresp, len, state1, state2); - -      Curl_safefree(initresp); -    } -    else { +  result = Curl_sasl_continue(&smtpc->sasl, conn, smtpcode, &progress); +  if(!result) +    switch(progress) { +    case SASL_DONE: +      state(conn, SMTP_STOP);  /* Authenticated */ +      break; +    case SASL_IDLE:            /* No mechanism left after cancellation */        failf(data, "Authentication cancelled"); -        result = CURLE_LOGIN_DENIED; +      break; +    default: +      break;      } -  } - -  return result; -} - -/* For final responses in the AUTH sequence */ -static CURLcode smtp_state_auth_final_resp(struct connectdata *conn, -                                           int smtpcode, -                                           smtpstate instate) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; - -  (void)instate; /* no use for this yet */ - -  if(smtpcode != 235) { -    failf(data, "Authentication failed: %d", smtpcode); -    result = CURLE_LOGIN_DENIED; -  } -  else -    /* End of connect phase */ -    state(conn, SMTP_STOP);    return result;  } @@ -1582,69 +1041,8 @@ static CURLcode smtp_statemach_act(struct connectdata *conn)        result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state);        break; -    case SMTP_AUTH_PLAIN: -      result = smtp_state_auth_plain_resp(conn, smtpcode, smtpc->state); -      break; - -    case SMTP_AUTH_LOGIN: -      result = smtp_state_auth_login_resp(conn, smtpcode, smtpc->state); -      break; - -    case SMTP_AUTH_LOGIN_PASSWD: -      result = smtp_state_auth_login_password_resp(conn, smtpcode, -                                                   smtpc->state); -      break; - -#ifndef CURL_DISABLE_CRYPTO_AUTH -    case SMTP_AUTH_CRAMMD5: -      result = smtp_state_auth_cram_resp(conn, smtpcode, smtpc->state); -      break; - -    case SMTP_AUTH_DIGESTMD5: -      result = smtp_state_auth_digest_resp(conn, smtpcode, smtpc->state); -      break; - -    case SMTP_AUTH_DIGESTMD5_RESP: -      result = smtp_state_auth_digest_resp_resp(conn, smtpcode, smtpc->state); -      break; -#endif - -#ifdef USE_NTLM -    case SMTP_AUTH_NTLM: -      result = smtp_state_auth_ntlm_resp(conn, smtpcode, smtpc->state); -      break; - -    case SMTP_AUTH_NTLM_TYPE2MSG: -      result = smtp_state_auth_ntlm_type2msg_resp(conn, smtpcode, -                                                  smtpc->state); -      break; -#endif - -#if defined(USE_KERBEROS5) -    case SMTP_AUTH_GSSAPI: -      result = smtp_state_auth_gssapi_resp(conn, smtpcode, smtpc->state); -      break; - -    case SMTP_AUTH_GSSAPI_TOKEN: -      result = smtp_state_auth_gssapi_token_resp(conn, smtpcode, smtpc->state); -      break; - -    case SMTP_AUTH_GSSAPI_NO_DATA: -      result = smtp_state_auth_gssapi_no_data_resp(conn, smtpcode, -                                                   smtpc->state); -      break; -#endif - -    case SMTP_AUTH_XOAUTH2: -      result = smtp_state_auth_xoauth2_resp(conn, smtpcode, smtpc->state); -      break; - -    case SMTP_AUTH_CANCEL: -      result = smtp_state_auth_cancel_resp(conn, smtpcode, smtpc->state); -      break; - -    case SMTP_AUTH_FINAL: -      result = smtp_state_auth_final_resp(conn, smtpcode, smtpc->state); +    case SMTP_AUTH: +      result = smtp_state_auth_resp(conn, smtpcode, smtpc->state);        break;      case SMTP_COMMAND: @@ -1758,7 +1156,7 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done)    pp->conn = conn;    /* Initialize the SASL storage */ -  Curl_sasl_init(&smtpc->sasl); +  Curl_sasl_init(&smtpc->sasl, &saslsmtp);    /* Initialise the pingpong layer */    Curl_pp_init(pp); @@ -2172,110 +1570,6 @@ static CURLcode smtp_parse_custom_request(struct connectdata *conn)    return result;  } -/*********************************************************************** - * - * smtp_calc_sasl_details() - * - * Calculate the required login details for SASL authentication. - */ -static CURLcode smtp_calc_sasl_details(struct connectdata *conn, -                                       const char **mech, -                                       char **initresp, size_t *len, -                                       smtpstate *state1, smtpstate *state2) -{ -  CURLcode result = CURLE_OK; -  struct SessionHandle *data = conn->data; -  struct smtp_conn *smtpc = &conn->proto.smtpc; - -  /* Calculate the supported authentication mechanism, by decreasing order of -     security, as well as the initial response where appropriate */ -#if defined(USE_KERBEROS5) -  if((smtpc->sasl.authmechs & SASL_MECH_GSSAPI) && -     (smtpc->sasl.prefmech & SASL_MECH_GSSAPI)) { -    smtpc->sasl.mutual_auth = FALSE; /* TODO: Calculate mutual auth. */ - -    *mech = SASL_MECH_STRING_GSSAPI; -    *state1 = SMTP_AUTH_GSSAPI; -    *state2 = SMTP_AUTH_GSSAPI_TOKEN; -    smtpc->sasl.authused = SASL_MECH_GSSAPI; - -    if(data->set.sasl_ir) -      result = Curl_sasl_create_gssapi_user_message(data, conn->user, -                                                    conn->passwd, "smtp", -                                                    smtpc->sasl.mutual_auth, -                                                    NULL, &conn->krb5, -                                                    initresp, len); -    } -  else -#endif -#ifndef CURL_DISABLE_CRYPTO_AUTH -  if((smtpc->sasl.authmechs & SASL_MECH_DIGEST_MD5) && -     (smtpc->sasl.prefmech & SASL_MECH_DIGEST_MD5)) { -    *mech = SASL_MECH_STRING_DIGEST_MD5; -    *state1 = SMTP_AUTH_DIGESTMD5; -    smtpc->sasl.authused = SASL_MECH_DIGEST_MD5; -  } -  else if((smtpc->sasl.authmechs & SASL_MECH_CRAM_MD5) && -          (smtpc->sasl.prefmech & SASL_MECH_CRAM_MD5)) { -    *mech = SASL_MECH_STRING_CRAM_MD5; -    *state1 = SMTP_AUTH_CRAMMD5; -    smtpc->sasl.authused = SASL_MECH_CRAM_MD5; -  } -  else -#endif -#ifdef USE_NTLM -  if((smtpc->sasl.authmechs & SASL_MECH_NTLM) && -     (smtpc->sasl.prefmech & SASL_MECH_NTLM)) { -    *mech = SASL_MECH_STRING_NTLM; -    *state1 = SMTP_AUTH_NTLM; -    *state2 = SMTP_AUTH_NTLM_TYPE2MSG; -    smtpc->sasl.authused = SASL_MECH_NTLM; - -    if(data->set.sasl_ir) -      result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, -                                                   &conn->ntlm, -                                                   initresp, len); -    } -  else -#endif -  if(((smtpc->sasl.authmechs & SASL_MECH_XOAUTH2) && -      (smtpc->sasl.prefmech & SASL_MECH_XOAUTH2) && -      (smtpc->sasl.prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) { -    *mech = SASL_MECH_STRING_XOAUTH2; -    *state1 = SMTP_AUTH_XOAUTH2; -    *state2 = SMTP_AUTH_FINAL; -    smtpc->sasl.authused = SASL_MECH_XOAUTH2; - -    if(data->set.sasl_ir) -      result = Curl_sasl_create_xoauth2_message(data, conn->user, -                                                conn->xoauth2_bearer, -                                                initresp, len); -  } -  else if((smtpc->sasl.authmechs & SASL_MECH_LOGIN) && -          (smtpc->sasl.prefmech & SASL_MECH_LOGIN)) { -    *mech = SASL_MECH_STRING_LOGIN; -    *state1 = SMTP_AUTH_LOGIN; -    *state2 = SMTP_AUTH_LOGIN_PASSWD; -    smtpc->sasl.authused = SASL_MECH_LOGIN; - -    if(data->set.sasl_ir) -      result = Curl_sasl_create_login_message(data, conn->user, initresp, len); -  } -  else if((smtpc->sasl.authmechs & SASL_MECH_PLAIN) && -          (smtpc->sasl.prefmech & SASL_MECH_PLAIN)) { -    *mech = SASL_MECH_STRING_PLAIN; -    *state1 = SMTP_AUTH_PLAIN; -    *state2 = SMTP_AUTH_FINAL; -    smtpc->sasl.authused = SASL_MECH_PLAIN; - -    if(data->set.sasl_ir) -      result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd, -                                              initresp, len); -  } - -  return result; -} -  CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)  {    /* When sending a SMTP payload we must detect CRLF. sequences making sure diff --git a/lib/smtp.h b/lib/smtp.h index a237d3e5c..9fbe0c5bf 100644 --- a/lib/smtp.h +++ b/lib/smtp.h @@ -37,20 +37,7 @@ typedef enum {    SMTP_STARTTLS,    SMTP_UPGRADETLS,  /* asynchronously upgrade the connection to SSL/TLS                         (multi mode only) */ -  SMTP_AUTH_PLAIN, -  SMTP_AUTH_LOGIN, -  SMTP_AUTH_LOGIN_PASSWD, -  SMTP_AUTH_CRAMMD5, -  SMTP_AUTH_DIGESTMD5, -  SMTP_AUTH_DIGESTMD5_RESP, -  SMTP_AUTH_NTLM, -  SMTP_AUTH_NTLM_TYPE2MSG, -  SMTP_AUTH_GSSAPI, -  SMTP_AUTH_GSSAPI_TOKEN, -  SMTP_AUTH_GSSAPI_NO_DATA, -  SMTP_AUTH_XOAUTH2, -  SMTP_AUTH_CANCEL, -  SMTP_AUTH_FINAL, +  SMTP_AUTH,    SMTP_COMMAND,     /* VRFY, EXPN, NOOP, RSET and HELP */    SMTP_MAIL,        /* MAIL FROM */    SMTP_RCPT,        /* RCPT TO */ | 
