diff options
| -rw-r--r-- | lib/smtp.c | 172 | 
1 files changed, 93 insertions, 79 deletions
diff --git a/lib/smtp.c b/lib/smtp.c index 02af49560..77d36e909 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -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,21 +738,83 @@ 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) { -    /* We don't have a SSL/TLS connection yet, but SSL is requested */ -    if(smtpc->tls_supported) -      /* Switch to TLS connection now */ -      result = smtp_perform_starttls(conn); -    else if(data->set.use_ssl == CURLUSESSL_TRY) -      /* Fallback and carry on with authentication */ -      result = smtp_perform_authenticate(conn); -    else { -      failf(data, "STARTTLS not supported."); -      result = CURLE_USE_SSL_FAILED; +  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 */ +          result = smtp_perform_starttls(conn); +        else if(data->set.use_ssl == CURLUSESSL_TRY) +          /* Fallback and carry on with authentication */ +          result = smtp_perform_authenticate(conn); +        else { +          failf(data, "STARTTLS not supported."); +          result = CURLE_USE_SSL_FAILED; +        } +      } +      else +        result = smtp_perform_authenticate(conn);      }    } -  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) {  | 
