Commit f16c0de4 authored by Steve Holme's avatar Steve Holme
Browse files

smtp: Moved EHLO response handling to smtp_state_ehlo_resp()

Similar to the processing of untagged CAPABILITY responses in IMAP moved
the processing of multiline EHLO responses to smtp_state_ehlo_resp() and
introduced an internal response code of one to differentiate a multiline
continuation from the end of command. This also allows for the separate
processing of multiline responses from commands such as VRFY and EXPN.
parent 786cba1a
Loading
Loading
Loading
Loading
+93 −79
Original line number Diff line number Diff line
@@ -230,78 +230,27 @@ static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
{
  struct smtp_conn *smtpc = &conn->proto.smtpc;
  bool result = FALSE;
  size_t wordlen;

  /* Nothing for us */
  if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
    return FALSE;       /* Nothing for us */
    return FALSE;

  /* Do we have a command response? This should be the response code followed
     by a space and optionally some text as per RFC-5321 and as outlined in
     Section 4. Examples of RFC-4954 but some e-mail servers ignore this and
     only send the response code instead. */
  result = (line[3] == ' ' || len == 5) ? TRUE : FALSE;
  if(result)
     only send the response code instead as per Section 4.2. */
  if(line[3] == ' ' || len == 5) {
    result = TRUE;
    *resp = curlx_sltosi(strtol(line, NULL, 10));

  /* Are we processing EHLO command data? */
  if(smtpc->state == SMTP_EHLO && (!result || (result && *resp/100 == 2))) {
    line += 4;
    len -= 4;

    /* Does the server support the STARTTLS capability? */
    if(len >= 8 && !memcmp(line, "STARTTLS", 8))
      smtpc->tls_supported = TRUE;

    /* Does the server support the SIZE capability? */
    else if(len >= 4 && !memcmp(line, "SIZE", 4))
      smtpc->size_supported = TRUE;

    /* Do we have the authentication mechanism list? */
    else if(len >= 5 && !memcmp(line, "AUTH ", 5)) {
      line += 5;
      len -= 5;

      /* Loop through the data line */
      for(;;) {
        while(len &&
              (*line == ' ' || *line == '\t' ||
               *line == '\r' || *line == '\n')) {

          line++;
          len--;
        }

        if(!len)
          break;

        /* Extract the word */
        for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
              line[wordlen] != '\t' && line[wordlen] != '\r' &&
              line[wordlen] != '\n';)
          wordlen++;

        /* Test the word for a matching authentication mechanism */
        if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
          smtpc->authmechs |= SASL_MECH_LOGIN;
        else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
          smtpc->authmechs |= SASL_MECH_PLAIN;
        else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
          smtpc->authmechs |= SASL_MECH_CRAM_MD5;
        else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
          smtpc->authmechs |= SASL_MECH_DIGEST_MD5;
        else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
          smtpc->authmechs |= SASL_MECH_GSSAPI;
        else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
          smtpc->authmechs |= SASL_MECH_EXTERNAL;
        else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
          smtpc->authmechs |= SASL_MECH_NTLM;
        else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
          smtpc->authmechs |= SASL_MECH_XOAUTH2;

        line += wordlen;
        len -= wordlen;
      }
    /* Make sure real server never sends internal value */
    if(*resp == 1)
      *resp = 0;
  }
  /* Do we have a multiline (continuation) response? */
  else if(line[3] == '-') {
    result = TRUE;
    *resp = 1;  /* Internal response code */
  }

  return result;
@@ -774,10 +723,13 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
  CURLcode result = CURLE_OK;
  struct SessionHandle *data = conn->data;
  struct smtp_conn *smtpc = &conn->proto.smtpc;
  const char *line = data->state.buffer;
  size_t len = strlen(line);
  size_t wordlen;

  (void)instate; /* no use for this yet */

  if(smtpcode/100 != 2) {
  if(smtpcode/100 != 2 && smtpcode != 1) {
    if((data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use) &&
     !conn->bits.user_passwd)
      result = smtp_perform_helo(conn);
@@ -786,7 +738,67 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
      result = CURLE_REMOTE_ACCESS_DENIED;
    }
  }
  else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
  else {
    line += 4;
    len -= 4;

    /* Does the server support the STARTTLS capability? */
    if(len >= 8 && !memcmp(line, "STARTTLS", 8))
      smtpc->tls_supported = TRUE;

    /* Does the server support the SIZE capability? */
    else if(len >= 4 && !memcmp(line, "SIZE", 4))
      smtpc->size_supported = TRUE;

    /* Do we have the authentication mechanism list? */
    else if(len >= 5 && !memcmp(line, "AUTH ", 5)) {
      line += 5;
      len -= 5;

      /* Loop through the data line */
      for(;;) {
        while(len &&
              (*line == ' ' || *line == '\t' ||
               *line == '\r' || *line == '\n')) {

          line++;
          len--;
        }

        if(!len)
          break;

        /* Extract the word */
        for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
              line[wordlen] != '\t' && line[wordlen] != '\r' &&
              line[wordlen] != '\n';)
          wordlen++;

        /* Test the word for a matching authentication mechanism */
        if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
          smtpc->authmechs |= SASL_MECH_LOGIN;
        else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
          smtpc->authmechs |= SASL_MECH_PLAIN;
        else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
          smtpc->authmechs |= SASL_MECH_CRAM_MD5;
        else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
          smtpc->authmechs |= SASL_MECH_DIGEST_MD5;
        else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
          smtpc->authmechs |= SASL_MECH_GSSAPI;
        else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
          smtpc->authmechs |= SASL_MECH_EXTERNAL;
        else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
          smtpc->authmechs |= SASL_MECH_NTLM;
        else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
          smtpc->authmechs |= SASL_MECH_XOAUTH2;

        line += wordlen;
        len -= wordlen;
      }
    }

    if(smtpcode != 1) {
      if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
        /* We don't have a SSL/TLS connection yet, but SSL is requested */
        if(smtpc->tls_supported)
          /* Switch to TLS connection now */
@@ -801,6 +813,8 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
      }
      else
        result = smtp_perform_authenticate(conn);
    }
  }

  return result;
}
@@ -1344,7 +1358,7 @@ static CURLcode smtp_statemach_act(struct connectdata *conn)
    return result;

  /* Store the latest response for later retrieval */
  if(smtpc->state != SMTP_QUIT)
  if(smtpc->state != SMTP_QUIT && smtpcode != 1)
    data->info.httpcode = smtpcode;

  if(smtpcode) {