/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "net.h"
#include "str.h"
#include "strescape.h"
#include "smtp-parser.h"
#include <ctype.h>
/* Character definitions from RFC 5321/5322:
textstring = 1*(%d09 / %d32-126) ; HT, SP, Printable US-ASCII
= 1*(%x09 / %x20-7e)
ehlo-param = 1*(%d33-126)
= 1*(%x21-7e)
ehlo-greet = 1*(%d0-9 / %d11-12 / %d14-127)
= 1*(%x00-09 / %x0b-0c / %x0e-7f)
qtext = %d32-33 / %d35-91 / %d93-126
= %x20-21 / %x23-5B / %x5d-7e
quoted-pair = %d92 %d32-126
= %x5c %x20-7e
atext = ALPHA / DIGIT / ; Printable US-ASCII
"!" / "#" / ; characters not including
"$" / "%" / ; specials. Used for atoms.
"&" / "'" /
"*" / "+" /
"-" / "/" /
"=" / "?" /
"^" / "_" /
"`" / "{" /
"|" / "}" /
"~"
= %x21 / %x23-27 / %x2a-2b / %x2d / %x2f-39 / %x3d /
%d3f / %x41-5a / %x5e-7e /
esmtp-value = 1*(%d33-60 / %d62-126)
= 1*(%x21-3c / %x3e-7e)
dcontent = %d33-90 / ; Printable US-ASCII
%d94-126 ; excl. "[", "\", "]"
= %x21-5a / %x5e-7e
xchar = any ASCII CHAR between "!" (33) and "~" (126) inclusive,
except for "+" and "=". [RFC 3461]
= %x21-2a / %2c-3c / %x3e-7e
Bit mappings (FIXME: rearrange):
(1<<0) => %x21-2a / %2c-3c / %x3e-7e (xtext)
(1<<1) => %x21 / %x23-27 / %x2a-2b / %x2d / %x2f-39 / %x3d /
%d3f / %x41-5a / %x5e-7e /
(1<<2) => %x28-29 / %x2c / %x2e / %x3a-3c / %x3e / %x40
(1<<8) => %x00-09 / %x0b-0c / %x0e-20 / %x7f
(1<<5) => %x09 / %5b-5d
(1<<4) => %x5b / %x5d
(1<<3) => %x20
(1<<9) => %x22
(1<<6) => %x2b
(1<<7) => %x3d
*/
/* xtext */
/* atext */
/* dcontent */
/* qtext */
/* textstring */
/* esmtp-value */
/* ehlo-param */
/* ehlo-greet */
/* quoted-pair */
0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, // 00
0x100, 0x120, 0x000, 0x100, 0x100, 0x000, 0x100, 0x100, // 08
0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, // 10
0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, // 18
0x108, 0x003, 0x201, 0x003, 0x003, 0x003, 0x003, 0x003, // 20
0x005, 0x005, 0x003, 0x042, 0x005, 0x003, 0x005, 0x003, // 28
0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, // 30
0x003, 0x003, 0x005, 0x005, 0x005, 0x082, 0x005, 0x003, // 38
0x005, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, // 40
0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, // 48
0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, // 50
0x003, 0x003, 0x003, 0x031, 0x021, 0x031, 0x003, 0x003, // 58
0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, // 60
0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, // 68
0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, // 70
0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x100, // 78
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // 80
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // 88
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // 90
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // 98
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // a0
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // a8
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // b0
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // b8
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // c0
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // c8
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // d0
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // d8
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // e0
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // e8
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // f0
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // f8
};
/*
* Parser
*/
{
}
/*
* Common syntax
*/
static int
{
/* Ldh-str = *( ALPHA / DIGIT / "-" ) Let-dig
Let-dig = ALPHA / DIGIT
*/
/* Ldh-str */
break;
}
return 0;
}
return 1;
}
const char **value_r)
{
/* Domain = sub-domain *("." sub-domain)
sub-domain = Let-dig [Ldh-str]
Let-dig = ALPHA / DIGIT
Ldh-str = *( ALPHA / DIGIT / "-" ) Let-dig
NOTE: A more generic syntax is accepted to be lenient towards
systems that don't adhere to the standards. It allows
'-' and '_' to occur anywhere in a sub-domain.
*/
/* Let-dig (first) (nope) */
return 0;
for (;;) {
/* Let-dig (nope) */
return -1;
}
return -1;
}
/* Ldh-str (nope) */
break;
}
/* *("." sub-domain) */
break;
}
return 1;
}
static int
{
/* Snum = 1*3DIGIT
; representing a decimal integer
; value in the range 0 through 255
*/
return 0;
do {
return -1;
return -1;
}
return 1;
}
static int
{
int ret;
int i;
/* IPv4-address-literal = Snum 3("." Snum) */
return ret;
return -1;
return -1;
}
return 1;
}
{
const unsigned char *pblock;
int ret;
/* address-literal = "[" ( IPv4-address-literal /
IPv6-address-literal /
General-address-literal ) "]"
; See Section 4.1.3
IPv6-address-literal = "IPv6:" IPv6-addr
General-address-literal = Standardized-tag ":" 1*dcontent
Standardized-tag = Ldh-str
; Standardized-tag MUST be specified in a
; Standards-Track RFC and registered with
; IANA
dcontent = %d33-90 / ; Printable US-ASCII
%d94-126 ; excl. "[", "\", "]"
*/
/* "[" */
return 0;
}
/* IPv4-address-literal / ... */
if (ret < 0) {
return -1;
}
}
/* ... / IPv6-address-literal / General-address-literal */
} else {
/* IPv6-address-literal = "IPv6:" IPv6-addr
General-address-literal = Standardized-tag ":" 1*dcontent
Standardized-tag = Ldh-str
*/
} else {
}
return -1;
}
"Unsupported %s address literal",
return -1;
}
/* 1*dcontent */
return -1;
}
if (ipv6) {
return -1;
}
}
}
}
/* ']' */
return -1;
return -1;
}
}
return 1;
}
const char **value_r)
{
const unsigned char *pbegin;
/* Quoted-string = DQUOTE *QcontentSMTP DQUOTE
QcontentSMTP = qtextSMTP / quoted-pairSMTP
quoted-pairSMTP = %d92 %d32-126
; i.e., backslash followed by any ASCII
; graphic (including itself) or SPace
qtextSMTP = %d32-33 / %d35-91 / %d93-126
; i.e., within a quoted string, any
; ASCII graphic or space is permitted
; without blackslash-quoting except
; double-quote and the backslash itself.
*/
/* DQUOTE */
return 0;
/* *QcontentSMTP */
/* qtextSMTP */
}
break;
/* quoted-pairSMTP */
"Invalid character after '\\' in quoted string";
return -1;
}
}
/* DQUOTE */
return -1;
}
return -1;
}
return 1;
}
static int
{
/* Atom = 1*atext */
return 0;
return 1;
}
const char **value_r)
{
int ret;
return ret;
return 1;
}
const char **value_r)
{
int ret;
/* String = Atom / Quoted-string */
return ret;
}
static bool
unsigned char *hexvalue)
{
switch (digit) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
break;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
break;
default:
return FALSE;
}
return TRUE;
}
{
unsigned char hexchar;
/* xtext = *( xchar / hexchar )
xchar = any ASCII CHAR between "!" (33) and "~" (126) inclusive,
except for "+" and "=".
hexchar = ASCII "+" immediately followed by two upper case
hexadecimal digits
*/
return 0;
break;
hexchar = 0;
continue;
}
}
return -1;
}
return 1;
}