mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00
Fix #80751: Comma in recipient name breaks email delivery
So far, `SendText()` simply separates potential email address lists at any comma, disregarding that commas inside a quoted-string do not delimit addresses. We fix that by introducing an own variant of `strtok_r()` which caters to quoted-strings. We also make `FormatEmailAddress()` aware of quoted strings. We do not cater to email address comments, and potentially other quirks of RFC 5322 email addresses, but catering to quoted-strings is supposed to solve almost all practical use cases. Co-authored-by: Nikita Popov <nikita.ppv@gmail.com> Closes GH-6735.
This commit is contained in:
parent
2c508c4d40
commit
71297a254b
2 changed files with 179 additions and 16 deletions
102
win32/sendmail.c
102
win32/sendmail.c
|
@ -333,6 +333,37 @@ PHPAPI char *GetSMErrorText(int index)
|
|||
}
|
||||
}
|
||||
|
||||
/* strtok_r like, but recognizes quoted-strings */
|
||||
static char *find_address(char *list, char **state)
|
||||
{
|
||||
zend_bool in_quotes = 0;
|
||||
char *p = list;
|
||||
|
||||
if (list == NULL) {
|
||||
if (*state == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
p = list = *state;
|
||||
}
|
||||
*state = NULL;
|
||||
while ((p = strpbrk(p, ",\"\\")) != NULL) {
|
||||
if (*p == '\\' && in_quotes) {
|
||||
if (p[1] == '\0') {
|
||||
/* invalid address; let SMTP server deal with it */
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
} else if (*p == '"') {
|
||||
in_quotes = !in_quotes;
|
||||
} else if (*p == ',' && !in_quotes) {
|
||||
*p = '\0';
|
||||
*state = p + 1;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
// Name: SendText
|
||||
|
@ -357,7 +388,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
|
|||
{
|
||||
int res;
|
||||
char *p;
|
||||
char *tempMailTo, *token, *pos1, *pos2;
|
||||
char *tempMailTo, *token, *token_state, *pos1, *pos2;
|
||||
char *server_response = NULL;
|
||||
char *stripped_header = NULL;
|
||||
zend_string *data_cln;
|
||||
|
@ -410,7 +441,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
|
|||
|
||||
tempMailTo = estrdup(mailTo);
|
||||
/* Send mail to all rcpt's */
|
||||
token = strtok(tempMailTo, ",");
|
||||
token = find_address(tempMailTo, &token_state);
|
||||
while (token != NULL)
|
||||
{
|
||||
SMTP_SKIP_SPACE(token);
|
||||
|
@ -424,14 +455,14 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
|
|||
efree(tempMailTo);
|
||||
return (res);
|
||||
}
|
||||
token = strtok(NULL, ",");
|
||||
token = find_address(NULL, &token_state);
|
||||
}
|
||||
efree(tempMailTo);
|
||||
|
||||
if (mailCc && *mailCc) {
|
||||
tempMailTo = estrdup(mailCc);
|
||||
/* Send mail to all rcpt's */
|
||||
token = strtok(tempMailTo, ",");
|
||||
token = find_address(tempMailTo, &token_state);
|
||||
while (token != NULL)
|
||||
{
|
||||
SMTP_SKIP_SPACE(token);
|
||||
|
@ -445,7 +476,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
|
|||
efree(tempMailTo);
|
||||
return (res);
|
||||
}
|
||||
token = strtok(NULL, ",");
|
||||
token = find_address(NULL, &token_state);
|
||||
}
|
||||
efree(tempMailTo);
|
||||
}
|
||||
|
@ -471,7 +502,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
|
|||
tempMailTo = estrndup(pos1, pos2 - pos1);
|
||||
}
|
||||
|
||||
token = strtok(tempMailTo, ",");
|
||||
token = find_address(tempMailTo, &token_state);
|
||||
while (token != NULL)
|
||||
{
|
||||
SMTP_SKIP_SPACE(token);
|
||||
|
@ -485,7 +516,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
|
|||
efree(tempMailTo);
|
||||
return (res);
|
||||
}
|
||||
token = strtok(NULL, ",");
|
||||
token = find_address(NULL,&token_state);
|
||||
}
|
||||
efree(tempMailTo);
|
||||
}
|
||||
|
@ -496,7 +527,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
|
|||
if (mailBcc && *mailBcc) {
|
||||
tempMailTo = estrdup(mailBcc);
|
||||
/* Send mail to all rcpt's */
|
||||
token = strtok(tempMailTo, ",");
|
||||
token = find_address(tempMailTo, &token_state);
|
||||
while (token != NULL)
|
||||
{
|
||||
SMTP_SKIP_SPACE(token);
|
||||
|
@ -510,7 +541,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
|
|||
efree(tempMailTo);
|
||||
return (res);
|
||||
}
|
||||
token = strtok(NULL, ",");
|
||||
token = find_address(NULL, &token_state);
|
||||
}
|
||||
efree(tempMailTo);
|
||||
}
|
||||
|
@ -544,7 +575,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
|
|||
}
|
||||
}
|
||||
|
||||
token = strtok(tempMailTo, ",");
|
||||
token = find_address(tempMailTo, &token_state);
|
||||
while (token != NULL)
|
||||
{
|
||||
SMTP_SKIP_SPACE(token);
|
||||
|
@ -558,7 +589,7 @@ static int SendText(char *RPath, char *Subject, char *mailTo, char *mailCc, char
|
|||
efree(tempMailTo);
|
||||
return (res);
|
||||
}
|
||||
token = strtok(NULL, ",");
|
||||
token = find_address(NULL, &token_state);
|
||||
}
|
||||
efree(tempMailTo);
|
||||
|
||||
|
@ -978,6 +1009,46 @@ static unsigned long GetAddr(LPSTR szHost)
|
|||
return (lAddr);
|
||||
} /* end GetAddr() */
|
||||
|
||||
/* returns the contents of an angle-addr (caller needs to efree) or NULL */
|
||||
static char *get_angle_addr(char *address)
|
||||
{
|
||||
zend_bool in_quotes = 0;
|
||||
char *p1 = address, *p2;
|
||||
|
||||
while ((p1 = strpbrk(p1, "<\"\\")) != NULL) {
|
||||
if (*p1 == '\\' && in_quotes) {
|
||||
if (p1[1] == '\0') {
|
||||
/* invalid address; let SMTP server deal with it */
|
||||
return NULL;
|
||||
}
|
||||
p1++;
|
||||
} else if (*p1 == '"') {
|
||||
in_quotes = !in_quotes;
|
||||
} else if (*p1 == '<' && !in_quotes) {
|
||||
break;
|
||||
}
|
||||
p1++;
|
||||
}
|
||||
if (p1 == NULL) return NULL;
|
||||
p2 = ++p1;
|
||||
while ((p2 = strpbrk(p2, ">\"\\")) != NULL) {
|
||||
if (*p2 == '\\' && in_quotes) {
|
||||
if (p2[1] == '\0') {
|
||||
/* invalid address; let SMTP server deal with it */
|
||||
return NULL;
|
||||
}
|
||||
p2++;
|
||||
} else if (*p2 == '"') {
|
||||
in_quotes = !in_quotes;
|
||||
} else if (*p2 == '>' && !in_quotes) {
|
||||
break;
|
||||
}
|
||||
p2++;
|
||||
}
|
||||
if (p2 == NULL) return NULL;
|
||||
|
||||
return estrndup(p1, p2 - p1);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
// Name: int FormatEmailAddress
|
||||
|
@ -993,13 +1064,12 @@ static unsigned long GetAddr(LPSTR szHost)
|
|||
// History:
|
||||
//********************************************************************/
|
||||
static int FormatEmailAddress(char* Buf, char* EmailAddress, char* FormatString) {
|
||||
char *tmpAddress1, *tmpAddress2;
|
||||
char *tmpAddress;
|
||||
int result;
|
||||
|
||||
if( (tmpAddress1 = strchr(EmailAddress, '<')) && (tmpAddress2 = strchr(tmpAddress1, '>')) ) {
|
||||
*tmpAddress2 = 0; // terminate the string temporarily.
|
||||
result = snprintf(Buf, MAIL_BUFFER_SIZE, FormatString , tmpAddress1+1);
|
||||
*tmpAddress2 = '>'; // put it back the way it was.
|
||||
if ((tmpAddress = get_angle_addr(EmailAddress)) != NULL) {
|
||||
result = snprintf(Buf, MAIL_BUFFER_SIZE, FormatString, tmpAddress);
|
||||
efree(tmpAddress);
|
||||
return result;
|
||||
}
|
||||
return snprintf(Buf, MAIL_BUFFER_SIZE , FormatString , EmailAddress );
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue