-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
EAI support for notqmail #197
base: main
Are you sure you want to change the base?
Changes from 1 commit
27a8ecb
a731d82
f802f92
132f09e
c6bc474
7ebc35b
fbb80e7
88a2973
97157ba
4e1ba81
44a00c9
9764a86
dae3b88
6b6f5fe
aac711a
777df37
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -371,3 +371,7 @@ forgeries.0 | |
setup | ||
qtmp.h | ||
qmail-send.service | ||
trysmtputf8 | ||
idn2.lib | ||
hassmtputf8.h | ||
utf8read.o |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
-DSMTPUTF8 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,12 @@ | |
#include "timeoutconn.h" | ||
#include "timeoutread.h" | ||
#include "timeoutwrite.h" | ||
#include "hassmtputf8.h" | ||
#ifdef SMTPUTF8 | ||
#include <idn2.h> | ||
#include "utf8read.h" | ||
#include "env.h" | ||
#endif | ||
|
||
#define HUGESMTPTEXT 5000 | ||
|
||
|
@@ -47,6 +53,13 @@ saa reciplist = {0}; | |
|
||
struct ip_address partner; | ||
|
||
#ifdef SMTPUTF8 | ||
static stralloc idnhost = { 0 }; | ||
static int smtputf8 = 0; /*- if remote has SMTPUTF8 capability */ | ||
static char *enable_utf8 = 0; /*- enable utf8 */ | ||
int flagutf8; | ||
#endif | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These variables don't cost much to have, so we could lose this ifdef. Another function of the ifdef is to document that these are EAI-specific; we could accomplish that by putting them in a new |
||
void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); } | ||
void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); } | ||
void zerodie() { zero(); substdio_flush(subfdoutsmall); _exit(0); } | ||
|
@@ -118,36 +131,50 @@ substdio smtpfrom = SUBSTDIO_FDBUF(saferead,-1,smtpfrombuf,sizeof(smtpfrombuf)); | |
|
||
stralloc smtptext = {0}; | ||
|
||
static void get(unsigned char *uc) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Haven't checked, just guessing we should probably retain the old name as a synonym in case patches call it. |
||
static void get1(unsigned char *uc) | ||
{ | ||
char *ch = (char *)uc; | ||
substdio_get(&smtpfrom,ch,1); | ||
if (*ch != '\r') | ||
if (smtptext.len < HUGESMTPTEXT) | ||
if (!stralloc_append(&smtptext,ch)) temp_nomem(); | ||
if (*ch != '\r' && smtptext.len < HUGESMTPTEXT && | ||
!stralloc_append(&smtptext,ch)) | ||
temp_nomem(); | ||
} | ||
|
||
static unsigned long get3() | ||
{ | ||
char str[4]; | ||
int i; | ||
unsigned long code; | ||
|
||
substdio_get(&smtpfrom,str,3); | ||
str[3] = 0; | ||
for (i = 0;i < 3;i++) { | ||
if (str[i] == '\r') continue; | ||
if (smtptext.len < HUGESMTPTEXT && | ||
!stralloc_append(&smtptext,str+i)) | ||
temp_nomem(); | ||
} | ||
scan_ulong(str,&code); | ||
return code; | ||
} | ||
|
||
unsigned long smtpcode() | ||
{ | ||
unsigned char ch; | ||
unsigned long code; | ||
unsigned char ch; | ||
unsigned long code; | ||
int err = 0; | ||
|
||
if (!stralloc_copys(&smtptext,"")) temp_nomem(); | ||
|
||
get(&ch); code = ch - '0'; | ||
get(&ch); code = code * 10 + (ch - '0'); | ||
get(&ch); code = code * 10 + (ch - '0'); | ||
if ((code = get3()) < 200) err = 1; | ||
for (;;) { | ||
get(&ch); | ||
get1((char *)&ch); | ||
if (ch != ' ' && ch != '-') err = 1; | ||
if (ch != '-') break; | ||
while (ch != '\n') get(&ch); | ||
get(&ch); | ||
get(&ch); | ||
get(&ch); | ||
while (ch != '\n') get1((char *)&ch); | ||
if (get3() != code) err = 1; | ||
} | ||
while (ch != '\n') get(&ch); | ||
|
||
return code; | ||
while (ch != '\n') get1((char *)&ch); | ||
return err ? 400 : code; | ||
} | ||
|
||
void outsmtptext() | ||
|
@@ -211,6 +238,33 @@ void blast() | |
substdio_flush(&smtpto); | ||
} | ||
|
||
#ifdef SMTPUTF8 | ||
/* | ||
* this function is general purpose | ||
* we could use it when we add AUTH, | ||
* STARTTLS, SIZE extensions | ||
*/ | ||
int get_capability(const char *capa) | ||
{ | ||
int i = 0, len; | ||
|
||
/* e.g. | ||
* 250-PIPELINING | ||
* 250-8BITMIME | ||
* 250-SIZE 10000000 | ||
* 250-ETRN | ||
* 250-STARTTLS | ||
* 250-SMTPUTF8 | ||
* 250 HELP | ||
*/ | ||
len = str_len(capa); | ||
for (i = 0; i < smtptext.len-len; ++i) | ||
if (case_starts(smtptext.s+i,capa)) return 1; | ||
|
||
return 0; | ||
} | ||
#endif | ||
|
||
stralloc recip = {0}; | ||
|
||
void smtp() | ||
|
@@ -221,14 +275,44 @@ void smtp() | |
|
||
if (smtpcode() != 220) quit("ZConnected to "," but greeting failed"); | ||
|
||
#ifdef SMTPUTF8 | ||
/*- | ||
* this part of the code is general purpose | ||
* it can be used for | ||
* checking other extensions like | ||
* AUTH, STARTTLS, SIZE, etc | ||
*/ | ||
substdio_puts(&smtpto,"EHLO "); | ||
substdio_put(&smtpto,helohost.s,helohost.len); | ||
substdio_puts(&smtpto,"\r\n"); | ||
substdio_flush(&smtpto); | ||
|
||
if (smtpcode() != 250) { /*- do a HELO if EHLO fails */ | ||
substdio_puts(&smtpto,"HELO "); | ||
substdio_put(&smtpto,helohost.s,helohost.len); | ||
substdio_puts(&smtpto,"\r\n"); | ||
substdio_flush(&smtpto); | ||
|
||
code = smtpcode(); | ||
if (code >= 500) quit("DConnected to "," but my name was rejected"); | ||
if (code != 250) quit("ZConnected to "," but my name was rejected"); | ||
} else /* EHLO succeeded. Let's check SMTPUTF8 capa */ | ||
smtputf8 = get_capability("SMTPUTF8"); /*- did the remote server advertize SMTPUTF8 */ | ||
#else | ||
substdio_puts(&smtpto,"HELO "); | ||
substdio_put(&smtpto,helohost.s,helohost.len); | ||
substdio_puts(&smtpto,"\r\n"); | ||
substdio_flush(&smtpto); | ||
if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected"); | ||
#endif | ||
|
||
substdio_puts(&smtpto,"MAIL FROM:<"); | ||
substdio_put(&smtpto,sender.s,sender.len); | ||
#ifdef SMTPUTF8 | ||
if (enable_utf8 && (flagutf8 || utf8read())) | ||
substdio_puts(&smtpto,"> SMTPUTF8\r\n"); | ||
else | ||
#endif | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's cheap to check these variables even in the case where we built without EAI. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if we #ifdef enable_utf8 to 0 then this comes for free as the compiler would optimize it away. |
||
substdio_puts(&smtpto,">\r\n"); | ||
substdio_flush(&smtpto); | ||
code = smtpcode(); | ||
|
@@ -262,6 +346,9 @@ void smtp() | |
if (code >= 500) quit("D"," failed on DATA command"); | ||
if (code >= 400) quit("Z"," failed on DATA command"); | ||
|
||
#ifdef SMTPUTF8 | ||
if (enable_utf8 && header.len) substdio_put(&smtpto, header.s, header.len); | ||
#endif | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as previous |
||
blast(); | ||
code = smtpcode(); | ||
flagcritical = 0; | ||
|
@@ -276,7 +363,12 @@ stralloc canonbox = {0}; | |
void addrmangle(stralloc *saout, char *s) | ||
{ | ||
int j; | ||
|
||
|
||
#ifdef SMTPUTF8 | ||
if (enable_utf8 && !flagutf8) | ||
flagutf8 = containsutf8(s,str_len(s)); | ||
#endif | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as previous |
||
j = str_rchr(s,'@'); | ||
if (!s[j]) { | ||
if (!stralloc_copys(saout,s)) temp_nomem(); | ||
|
@@ -325,6 +417,9 @@ int main(int argc, char **argv) | |
if (chdir(auto_qmail) == -1) temp_chdir(); | ||
getcontrols(); | ||
|
||
#ifdef SMTPUTF8 | ||
enable_utf8 = env_get("UTF8"); | ||
#endif | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as previous. Regarding the environment variable, I'm familiar with setting env vars to control my locale settings, but is this an idiomatic way for a sysadmin to control mail server config? Assuming we're built with EAI, I'm wondering whether EAI should be enabled/disabled systemwide, per domain (incoming and outgoing), or some other level of granularity? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And even if all of this is fine this variable name is a bit too generic. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should SMTPUTF8 be ok instead of just UTF8. We can have a control file to have the setting per domain. We could add a line in getcontrols() to read a control file. |
||
|
||
if (!stralloc_copys(&host,argv[1])) temp_nomem(); | ||
|
||
|
@@ -342,6 +437,18 @@ int main(int argc, char **argv) | |
relayhost[i] = 0; | ||
} | ||
if (!stralloc_copys(&host,relayhost)) temp_nomem(); | ||
#ifdef SMTPUTF8 | ||
} else | ||
if (enable_utf8) { | ||
char *asciihost = 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be NULL as it's a pointer variable |
||
if (!stralloc_0(&host)) temp_nomem(); | ||
switch (idn2_lookup_u8(host.s,(uint8_t**)&asciihost,IDN2_NFC_INPUT)) { | ||
case IDN2_OK: break; | ||
case IDN2_MALLOC: temp_nomem(); | ||
default: perm_dns(); | ||
} | ||
if (!stralloc_copys(&idnhost,asciihost)) temp_nomem(); | ||
#endif | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This ifdef is a little extra tricky! It's only really needed around the |
||
} | ||
|
||
|
||
|
@@ -361,7 +468,11 @@ int main(int argc, char **argv) | |
|
||
|
||
random = now() + (getpid() << 16); | ||
#ifdef SMTPUTF8 | ||
switch (relayhost ? dns_ip(&ip,&host) : dns_mxip(&ip,enable_utf8 ? &idnhost : &host,random)) { | ||
#else | ||
switch (relayhost ? dns_ip(&ip,&host) : dns_mxip(&ip,&host,random)) { | ||
#endif | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line 472 is enough all by itself :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And I would put it on a line distinct from the switch to make the code less convoluted. |
||
case DNS_MEM: temp_nomem(); | ||
case DNS_SOFT: temp_dns(); | ||
case DNS_HARD: perm_dns(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm seeing a lot of new ifdefs and it makes me a little uneasy about how "glanceable" our code is. We need some ifdefs for EAI because it's compile-time optional, but they can be (1) more isolated and (2) fewer in number. I'll give some examples of changes I'd like to see.