Skip to content

imap capability tokens must be treated case-insensitively #19089

@MegaManSec

Description

@MegaManSec

I did this

Sorry, quick copy-paste because I'm in a rush but,

curl/lib/imap.c

Lines 1024 to 1104 in c37ed9a

static CURLcode imap_state_capability_resp(struct Curl_easy *data,
struct imap_conn *imapc,
int imapcode,
imapstate instate)
{
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
const char *line = curlx_dyn_ptr(&imapc->pp.recvbuf);
(void)instate;
/* Do we have an untagged response? */
if(imapcode == '*') {
line += 2;
/* Loop through the data line */
for(;;) {
size_t wordlen;
while(*line &&
(*line == ' ' || *line == '\t' ||
*line == '\r' || *line == '\n')) {
line++;
}
if(!*line)
break;
/* Extract the word */
for(wordlen = 0; line[wordlen] && line[wordlen] != ' ' &&
line[wordlen] != '\t' && line[wordlen] != '\r' &&
line[wordlen] != '\n';)
wordlen++;
/* Does the server support the STARTTLS capability? */
if(wordlen == 8 && !memcmp(line, "STARTTLS", 8))
imapc->tls_supported = TRUE;
/* Has the server explicitly disabled clear text authentication? */
else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13))
imapc->login_disabled = TRUE;
/* Does the server support the SASL-IR capability? */
else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7))
imapc->ir_supported = TRUE;
/* Do we have a SASL based authentication mechanism? */
else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) {
size_t llen;
unsigned short mechbit;
line += 5;
wordlen -= 5;
/* Test the word for a matching authentication mechanism */
mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
if(mechbit && llen == wordlen)
imapc->sasl.authmechs |= mechbit;
}
line += wordlen;
}
}
else if(data->set.use_ssl && !Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
/* PREAUTH is not compatible with STARTTLS. */
if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) {
/* Switch to TLS connection now */
result = imap_perform_starttls(data, imapc);
}
else if(data->set.use_ssl <= CURLUSESSL_TRY)
result = imap_perform_authentication(data, imapc);
else {
failf(data, "STARTTLS not available.");
result = CURLE_USE_SSL_FAILED;
}
}
else
result = imap_perform_authentication(data, imapc);
return result;
}
..

(Chatgpt generated description):

  • IMAP keywords and atoms are case-insensitive by default. RFC 3501's formal syntax section states: "Except as noted otherwise, all alphabetic characters are case-insensitive... Implementations MUST accept these strings in a case-insensitive fashion." IETF Datatracker

    • The CAPABILITY response is a space-separated list of capability names. It must include IMAP4rev1, and it uses atoms for items like STARTTLS, LOGINDISABLED, and AUTH=<mechanism>. Clients MUST NOT issue LOGIN if LOGINDISABLED is advertised. Since these are atoms, the case-insensitive rule applies when matching them. IETF Datatracker

    • The grammar explicitly defines auth-type = atom, which again inherits the case-insensitive rule. That means AUTH=plain and AUTH=PLAIN must be treated the same by a client. IETF Datatracker

    • The STARTTLS extension for IMAP is advertised as the STARTTLS capability and invoked with the STARTTLS command. Whether a server prints STARTTLS or starttls, a conforming client has to recognize it. IETF Datatracker

    • The SASL-IR capability (initial client response) is defined by RFC 4959. Like all capability atoms, it is matched case-insensitively.

I expected the following

used a server which uses lowercase keywords in imap

curl/libcurl version

all

operating system

all

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions