Patch to add SMTP AUTH to ofmipd in the mess822-0.58 package, adapted from SMTP AUTH patches for qmail-1.03. It also includes the QMAILQUEUE patch. This patch supports LOGIN and PLAIN authorization. The code for CRAM authorization is present but commented out. This patch includes a variety of small library files borrowed from qmail-1.03. For CRAM to work, you'll need to borrow a lot more libraries from qmail-1.03. IMPORTANT: Read the updated ofmipd.0 man page to see the changes to ofmipd. If you have local clients that are allowed to inject mail without logging in, you must arrange for tcpserver to set the RELAYCLIENT variable for them, like it does for qmail-smtpd. I have been using this patched version of ofmipd for several months and it appears to work reliably, but bug reports (particularly if they include the fix) are welcome. - John Levine, johnl@iecc.com, April 2004 diff -c mess822-0.58-dist/Makefile mess822-0.58-patched/Makefile *** mess822-0.58-dist/Makefile Fri Sep 4 22:33:37 1998 --- mess822-0.58-patched/Makefile Tue Nov 11 09:25:32 2003 *************** *** 261,273 **** ./compile constmap.c env.a: \ ! makelib env.o ! ./makelib env.a env.o env.o: \ ! compile env.c str.h env.h ./compile env.c error.a: \ makelib error.o error_str.o ./makelib error.a error.o error_str.o --- 261,277 ---- ./compile constmap.c env.a: \ ! makelib env.o envread.o ! ./makelib env.a env.o envread.o env.o: \ ! compile env.c str.h alloc.h env.h ./compile env.c + envread.o: \ + compile envread.c env.h str.h + ./compile envread.c + error.a: \ makelib error.o error_str.o ./makelib error.a error.o error_str.o *************** *** 540,550 **** --- 544,556 ---- ofmipd: \ load ofmipd.o rewritehost.o rwhconfig.o config.o qmail.o auto_qmail.o \ + base64.o byte_zero.o \ timeoutread.o timeoutwrite.o commands.o env.a cdb.a mess822.a \ libtai.a getln.a strerr.a substdio.a stralloc.a alloc.a error.a \ case.a str.a fs.a open.a wait.a sig.a fd.a ./load ofmipd rewritehost.o rwhconfig.o config.o qmail.o \ auto_qmail.o timeoutread.o timeoutwrite.o commands.o env.a \ + base64.o byte_zero.o \ cdb.a mess822.a libtai.a getln.a strerr.a substdio.a \ stralloc.a alloc.a error.a case.a str.a fs.a open.a wait.a \ sig.a fd.a *************** *** 735,748 **** str.a: \ makelib str_len.o str_diff.o str_diffn.o str_chr.o str_rchr.o \ ! str_start.o byte_chr.o byte_rchr.o byte_copy.o byte_cr.o ./makelib str.a str_len.o str_diff.o str_diffn.o str_chr.o \ str_rchr.o str_start.o byte_chr.o byte_rchr.o byte_copy.o \ ! byte_cr.o str_chr.o: \ compile str_chr.c str.h ./compile str_chr.c str_diff.o: \ compile str_diff.c str.h --- 741,758 ---- str.a: \ makelib str_len.o str_diff.o str_diffn.o str_chr.o str_rchr.o \ ! str_start.o byte_chr.o byte_rchr.o byte_copy.o byte_cr.o str_cpy.o ./makelib str.a str_len.o str_diff.o str_diffn.o str_chr.o \ str_rchr.o str_start.o byte_chr.o byte_rchr.o byte_copy.o \ ! byte_cr.o str_cpy.o str_chr.o: \ compile str_chr.c str.h ./compile str_chr.c + + str_cpy.o: \ + compile str_cpy.c str.h + ./compile str_cpy.c str_diff.o: \ compile str_diff.c str.h diff -c mess822-0.58-dist/base64.c mess822-0.58-patched/base64.c *** mess822-0.58-dist/base64.c Wed Apr 7 23:21:09 2004 --- mess822-0.58-patched/base64.c Mon Nov 10 23:39:30 2003 *************** *** 0 **** --- 1,90 ---- + #include "base64.h" + #include "stralloc.h" + #include "substdio.h" + #include "str.h" + + static char *b64alpha = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + #define B64PAD '=' + + /* returns 0 ok, 1 illegal, -1 problem */ + + int b64decode(in,l,out) + const unsigned char *in; + int l; + stralloc *out; /* not null terminated */ + { + int i, j; + unsigned char a[4]; + unsigned char b[3]; + char *s; + + if (l == 0) + { + if (!stralloc_copys(out,"")) return -1; + return 0; + } + + if (!stralloc_ready(out,l + 2)) return -1; /* XXX generous */ + s = out->s; + + for (i = 0;i < l;i += 4) { + for (j = 0;j < 4;j++) + if ((i + j) < l && in[i + j] != B64PAD) + { + a[j] = str_chr(b64alpha,in[i + j]); + if (a[j] > 63) return 1; + } + else a[j] = 0; + + b[0] = (a[0] << 2) | (a[1] >> 4); + b[1] = (a[1] << 4) | (a[2] >> 2); + b[2] = (a[2] << 6) | (a[3]); + + *s++ = b[0]; + + if (in[i + 1] == B64PAD) break; + *s++ = b[1]; + + if (in[i + 2] == B64PAD) break; + *s++ = b[2]; + } + out->len = s - out->s; + while (out->len && !out->s[out->len - 1]) --out->len; /* XXX avoid? */ + return 0; + } + + int b64encode(in,out) + stralloc *in; + stralloc *out; /* not null terminated */ + { + unsigned char a, b, c; + int i; + char *s; + + if (in->len == 0) + { + if (!stralloc_copys(out,"")) return -1; + return 0; + } + + if (!stralloc_ready(out,in->len / 3 * 4 + 4)) return -1; + s = out->s; + + for (i = 0;i < in->len;i += 3) { + a = in->s[i]; + b = i + 1 < in->len ? in->s[i + 1] : 0; + c = i + 2 < in->len ? in->s[i + 2] : 0; + + *s++ = b64alpha[a >> 2]; + *s++ = b64alpha[((a & 3 ) << 4) | (b >> 4)]; + + if (i + 1 >= in->len) *s++ = B64PAD; + else *s++ = b64alpha[((b & 15) << 2) | (c >> 6)]; + + if (i + 2 >= in->len) *s++ = B64PAD; + else *s++ = b64alpha[c & 63]; + } + out->len = s - out->s; + return 0; + } diff -c mess822-0.58-dist/base64.h mess822-0.58-patched/base64.h *** mess822-0.58-dist/base64.h Wed Apr 7 23:21:12 2004 --- mess822-0.58-patched/base64.h Mon Nov 10 23:39:46 2003 *************** *** 0 **** --- 1,7 ---- + #ifndef BASE64_H + #define BASE64_H + + extern int b64decode(); + extern int b64encode(); + + #endif diff -c mess822-0.58-dist/byte.h mess822-0.58-patched/byte.h *** mess822-0.58-dist/byte.h Fri Sep 4 22:33:37 1998 --- mess822-0.58-patched/byte.h Tue Nov 11 00:06:19 2003 *************** *** 1,13 **** #ifndef BYTE_H #define BYTE_H - extern unsigned int byte_chr(); - extern unsigned int byte_rchr(); - extern void byte_copy(); - extern void byte_copyr(); - extern int byte_diff(); extern void byte_zero(); - - #define byte_equal(s,n,t) (!byte_diff((s),(n),(t))) #endif --- 1,6 ---- diff -c mess822-0.58-dist/byte_zero.c mess822-0.58-patched/byte_zero.c *** mess822-0.58-dist/byte_zero.c Wed Apr 7 23:21:05 2004 --- mess822-0.58-patched/byte_zero.c Tue Nov 11 00:05:34 2003 *************** *** 0 **** --- 1,13 ---- + #include "byte.h" + + void byte_zero(s,n) + char *s; + register unsigned int n; + { + for (;;) { + if (!n) break; *s++ = 0; --n; + if (!n) break; *s++ = 0; --n; + if (!n) break; *s++ = 0; --n; + if (!n) break; *s++ = 0; --n; + } + } diff -c mess822-0.58-dist/env.c mess822-0.58-patched/env.c *** mess822-0.58-dist/env.c Fri Sep 4 22:33:37 1998 --- mess822-0.58-patched/env.c Tue Nov 11 09:20:17 2003 *************** *** 1,16 **** #include "str.h" #include "env.h" ! extern /*@null@*/char *env_get(s) ! char *s; { ! int i; ! unsigned int len; ! if (!s) return 0; ! len = str_len(s); ! for (i = 0;environ[i];++i) ! if (str_start(environ[i],s) && (environ[i][len] == '=')) ! return environ[i] + len + 1; ! return 0; } --- 1,113 ---- + /* env.c, envread.c, env.h: environ library + Daniel J. Bernstein, djb@silverton.berkeley.edu. + Depends on str.h, alloc.h. + Requires environ. + 19960113: rewrite. warning: interface is different. + No known patent problems. + */ + #include "str.h" + #include "alloc.h" #include "env.h" ! int env_isinit = 0; /* if env_isinit: */ ! static int ea; /* environ is a pointer to ea+1 char*'s. */ ! static int en; /* the first en of those are ALLOCATED. environ[en] is 0. */ ! ! static void env_goodbye(i) int i; ! { ! alloc_free(environ[i]); ! environ[i] = environ[--en]; ! environ[en] = 0; ! } ! ! static char *null = 0; ! ! void env_clear() ! { ! if (env_isinit) while (en) env_goodbye(0); ! else environ = &null; ! } ! ! static void env_unsetlen(s,len) char *s; int len; ! { ! int i; ! for (i = en - 1;i >= 0;--i) ! if (!str_diffn(s,environ[i],len)) ! if (environ[i][len] == '=') ! env_goodbye(i); ! } ! ! int env_unset(s) char *s; ! { ! if (!env_isinit) if (!env_init()) return 0; ! env_unsetlen(s,str_len(s)); ! return 1; ! } ! ! static int env_add(s) char *s; ! { ! char *t; ! t = env_findeq(s); ! if (t) env_unsetlen(s,t - s); ! if (en == ea) ! { ! ea += 30; ! if (!alloc_re(&environ,(en + 1) * sizeof(char *),(ea + 1) * sizeof(char *))) ! { ea = en; return 0; } ! } ! environ[en++] = s; ! environ[en] = 0; ! return 1; ! } ! ! int env_put(s) char *s; ! { ! char *u; ! if (!env_isinit) if (!env_init()) return 0; ! u = alloc(str_len(s) + 1); ! if (!u) return 0; ! str_copy(u,s); ! if (!env_add(u)) { alloc_free(u); return 0; } ! return 1; ! } ! ! int env_put2(s,t) char *s; char *t; { ! char *u; ! int slen; ! if (!env_isinit) if (!env_init()) return 0; ! slen = str_len(s); ! u = alloc(slen + str_len(t) + 2); ! if (!u) return 0; ! str_copy(u,s); ! u[slen] = '='; ! str_copy(u + slen + 1,t); ! if (!env_add(u)) { alloc_free(u); return 0; } ! return 1; ! } ! int env_init() ! { ! char **newenviron; ! int i; ! for (en = 0;environ[en];++en) ; ! ea = en + 10; ! newenviron = (char **) alloc((ea + 1) * sizeof(char *)); ! if (!newenviron) return 0; ! for (en = 0;environ[en];++en) ! { ! newenviron[en] = alloc(str_len(environ[en]) + 1); ! if (!newenviron[en]) ! { ! for (i = 0;i < en;++i) alloc_free(newenviron[i]); ! alloc_free(newenviron); ! return 0; ! } ! str_copy(newenviron[en],environ[en]); ! } ! newenviron[en] = 0; ! environ = newenviron; ! env_isinit = 1; ! return 1; } diff -c mess822-0.58-dist/env.h mess822-0.58-patched/env.h *** mess822-0.58-dist/env.h Fri Sep 4 22:33:37 1998 --- mess822-0.58-patched/env.h Tue Nov 11 09:20:17 2003 *************** *** 1,8 **** #ifndef ENV_H #define ENV_H ! extern char **environ; extern /*@null@*/char *env_get(); #endif --- 1,17 ---- #ifndef ENV_H #define ENV_H ! extern int env_isinit; + extern int env_init(); + extern int env_put(); + extern int env_put2(); + extern int env_unset(); extern /*@null@*/char *env_get(); + extern char *env_pick(); + extern void env_clear(); + extern char *env_findeq(); + + extern char **environ; #endif diff -c mess822-0.58-dist/envread.c mess822-0.58-patched/envread.c *** mess822-0.58-dist/envread.c Wed Apr 7 23:20:35 2004 --- mess822-0.58-patched/envread.c Wed Apr 7 22:52:09 2004 *************** *** 0 **** --- 1,30 ---- + #include "env.h" + #include "str.h" + + extern /*@null@*/char *env_get(s) + char *s; + { + int i; + unsigned int slen; + char *envi; + + slen = str_len(s); + for (i = 0;envi = environ[i];++i) + if ((!str_diffn(s,envi,slen)) && (envi[slen] == '=')) + return envi + slen + 1; + return 0; + } + + extern char *env_pick() + { + return environ[0]; + } + + extern char *env_findeq(s) + char *s; + { + for (;*s;++s) + if (*s == '=') + return s; + return 0; + } diff -c mess822-0.58-dist/envset.c mess822-0.58-patched/envset.c *** mess822-0.58-dist/envset.c Wed Apr 7 23:20:58 2004 --- mess822-0.58-patched/envset.c Tue Nov 11 09:17:53 2003 *************** *** 0 **** --- 1,113 ---- + /* env.c, envread.c, env.h: environ library + Daniel J. Bernstein, djb@silverton.berkeley.edu. + Depends on str.h, alloc.h. + Requires environ. + 19960113: rewrite. warning: interface is different. + No known patent problems. + */ + + #include "str.h" + #include "alloc.h" + #include "env.h" + + int env_isinit = 0; /* if env_isinit: */ + static int ea; /* environ is a pointer to ea+1 char*'s. */ + static int en; /* the first en of those are ALLOCATED. environ[en] is 0. */ + + static void env_goodbye(i) int i; + { + alloc_free(environ[i]); + environ[i] = environ[--en]; + environ[en] = 0; + } + + static char *null = 0; + + void env_clear() + { + if (env_isinit) while (en) env_goodbye(0); + else environ = &null; + } + + static void env_unsetlen(s,len) char *s; int len; + { + int i; + for (i = en - 1;i >= 0;--i) + if (!str_diffn(s,environ[i],len)) + if (environ[i][len] == '=') + env_goodbye(i); + } + + int env_unset(s) char *s; + { + if (!env_isinit) if (!env_init()) return 0; + env_unsetlen(s,str_len(s)); + return 1; + } + + static int env_add(s) char *s; + { + char *t; + t = env_findeq(s); + if (t) env_unsetlen(s,t - s); + if (en == ea) + { + ea += 30; + if (!alloc_re(&environ,(en + 1) * sizeof(char *),(ea + 1) * sizeof(char *))) + { ea = en; return 0; } + } + environ[en++] = s; + environ[en] = 0; + return 1; + } + + int env_put(s) char *s; + { + char *u; + if (!env_isinit) if (!env_init()) return 0; + u = alloc(str_len(s) + 1); + if (!u) return 0; + str_copy(u,s); + if (!env_add(u)) { alloc_free(u); return 0; } + return 1; + } + + int env_put2(s,t) char *s; char *t; + { + char *u; + int slen; + if (!env_isinit) if (!env_init()) return 0; + slen = str_len(s); + u = alloc(slen + str_len(t) + 2); + if (!u) return 0; + str_copy(u,s); + u[slen] = '='; + str_copy(u + slen + 1,t); + if (!env_add(u)) { alloc_free(u); return 0; } + return 1; + } + + int env_init() + { + char **newenviron; + int i; + for (en = 0;environ[en];++en) ; + ea = en + 10; + newenviron = (char **) alloc((ea + 1) * sizeof(char *)); + if (!newenviron) return 0; + for (en = 0;environ[en];++en) + { + newenviron[en] = alloc(str_len(environ[en]) + 1); + if (!newenviron[en]) + { + for (i = 0;i < en;++i) alloc_free(newenviron[i]); + alloc_free(newenviron); + return 0; + } + str_copy(newenviron[en],environ[en]); + } + newenviron[en] = 0; + environ = newenviron; + env_isinit = 1; + return 1; + } diff -c mess822-0.58-dist/ofmipd.8 mess822-0.58-patched/ofmipd.8 *** mess822-0.58-dist/ofmipd.8 Fri Sep 4 22:33:37 1998 --- mess822-0.58-patched/ofmipd.8 Wed Apr 7 23:19:20 2004 *************** *** 3,10 **** ofmipd \- accept outgoing mail through OFMIP .SH SYNOPSIS .B ofmipd - [ .I name.cdb ] .SH DESCRIPTION .B ofmipd --- 3,13 ---- ofmipd \- accept outgoing mail through OFMIP .SH SYNOPSIS .B ofmipd .I name.cdb + [ + .I hostname + .I checkpasswd + .I truepgm ] .SH DESCRIPTION .B ofmipd *************** *** 31,45 **** Some sites use port 26. Some sites use port 25 on an IP address that does not receive incoming mail. ! Note that .B ofmipd will relay messages to any destination. ! It should be invoked ! only for connections from preauthorized users. With .B tcpserver ! you can deny connections ! that do not come from preauthorized IP addresses such as 127.0.0.1. Most MUAs that claim to be ``SMTP clients'' are actually OFMIP clients. --- 34,66 ---- Some sites use port 26. Some sites use port 25 on an IP address that does not receive incoming mail. ! The ! .I hostname ! argument is the name of the mail host, intended to create CRAM password ! challenges but currently ignored. ! The ! .I checkpasswd ! argument ! is the name of a password checker that uses the same calling conventions as ! the qmail POP3 checkpasswd. ! The ! .I truepgm ! argument is the name a program that succeeds, such as ! .B /bin/true\c ! , for POP3 checkpasswd compatibility. ! ! If the environment variable RELAYCLIENT is set, ! or the client logs in with AUTH, .B ofmipd will relay messages to any destination. ! If not, it will reject any MAIL FROM, RCPT TO, or DATA command with a 503 ! error. With .B tcpserver ! you can set RELAYCLIENT for ! preauthorized IP addresses such as 127.0.0.1. ! The contents of RELAYCLIENT are ignored; in particular, they are not ! appended to destnation mail addresses. Most MUAs that claim to be ``SMTP clients'' are actually OFMIP clients. *************** *** 92,97 **** --- 113,122 ---- See .BR ofmipname (8) for further details. + The + .I name.cdb + argument must be supplied but may be a null string of no name + transformation file is to be used. .B ofmipd accepts LF and CR LF as line terminators inside messages. diff -c mess822-0.58-dist/ofmipd.c mess822-0.58-patched/ofmipd.c *** mess822-0.58-dist/ofmipd.c Fri Sep 4 22:33:37 1998 --- mess822-0.58-patched/ofmipd.c Wed Apr 7 23:11:33 2004 *************** *** 16,24 **** --- 16,33 ---- #include "tai.h" #include "caltime.h" #include "cdb.h" + #include "base64.h" + #include "wait.h" + #include "fd.h" + #include "byte.h" + #include "case.h" + + #undef AUTHCRAM /* don't define, not fully implemented */ int timeout = 1200; + char *relayclient; + int safewrite(fd,buf,len) int fd; char *buf; int len; { int r; *************** *** 46,51 **** --- 55,70 ---- void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); } void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); } void err_cdb() { out("451 unable to read cdb (#4.3.0)\r\n"); } + int err_child() { out("454 oops, problem with child and I can't auth (#4.3.0)\r\n"); return -1; } + int err_fork() { out("454 oops, child won't start and I can't auth (#4.3.0)\r\n"); return -1; } + int err_pipe() { out("454 oops, unable to open pipe and I can't auth (#4.3.0)\r\n"); return -1; } + int err_write() { out("454 oops, unable to write pipe and I can't auth (#4.3.0)\r\n"); return -1; } + void err_authd() { out("503 you're already authenticated (#5.5.0)\r\n"); } + void err_authmail() { out("503 no auth during mail transaction (#5.5.0)\r\n"); } + int err_noauth() { out("504 auth type unimplemented (#5.5.1)\r\n"); return -1; } + int err_authabrt() { out("501 auth exchange cancelled (#5.0.0)\r\n"); return -1; } + int err_input() { out("501 malformed auth input (#5.5.4)\r\n"); return -1; } + int err_notauth() { out("503 authorize or check your mail before sending (#5.5.1)\r\n"); return -1; } config_str rewrite = CONFIG_STR; stralloc idappend = {0}; *************** *** 116,122 **** void smtp_ehlo(arg) char *arg; { seenmail = 0; ! out("250-ofmipd.local\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); } void smtp_rset() { --- 135,149 ---- void smtp_ehlo(arg) char *arg; { seenmail = 0; ! out("250-ofmipd.local"); ! #ifdef AUTHCRAM ! out("\r\n250-AUTH LOGIN CRAM-MD5 PLAIN"); ! out("\r\n250-AUTH=LOGIN CRAM-MD5 PLAIN"); ! #else ! out("\r\n250-AUTH LOGIN PLAIN"); ! out("\r\n250-AUTH=LOGIN PLAIN"); ! #endif ! out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); } void smtp_rset() { *************** *** 125,130 **** --- 152,158 ---- } void smtp_mail(arg) char *arg; { + if (!relayclient) { err_notauth(); return; } if (!addrparse(arg)) { err_syntax(); return; } name = 0; *************** *** 152,157 **** --- 180,186 ---- out("250 ok\r\n"); } void smtp_rcpt(arg) char *arg; { + if (!relayclient) { err_notauth(); return; } if (!seenmail) { err_wantmail(); return; } if (!addrparse(arg)) { err_syntax(); return; } if (!stralloc_0(&rwaddr)) nomem(); *************** *** 345,351 **** --- 374,413 ---- finishheader(); } + void safecats(out,in) + stralloc *out; + char *in; + { + char ch; + while (ch = *in++) { + if (ch < 33) ch = '?'; + if (ch > 126) ch = '?'; + if (ch == '(') ch = '?'; + if (ch == ')') ch = '?'; + if (ch == '@') ch = '?'; + if (ch == '\\') ch = '?'; + if (!stralloc_append(out,&ch)) nomem(); + } + } + stralloc received = {0}; + char *remoteinfo; + + void received_init() + { + char *x; + + if (!stralloc_copys(&received,"Received: (ofmipd ")) nomem(); + x = remoteinfo; + if (x) { + safecats(&received,x); + if (!stralloc_append(&received,"@")) nomem(); + } + x = env_get("TCPREMOTEIP"); + if (!x) x = "unknown"; + safecats(&received,x); + if (!stralloc_cats(&received,"); ")) nomem(); + } void smtp_data() { struct tai now; *************** *** 356,367 **** --- 418,431 ---- datastart.known = 1; if (!mess822_date(&datastamp,&datastart)) nomem(); + if (!relayclient) { err_notauth(); return; } if (!seenmail) { err_wantmail(); return; } if (!rcptto.len) { err_wantrcpt(); return; } seenmail = 0; if (qmail_open(&qqt) == -1) { err_qqt(); return; } out("354 go ahead\r\n"); + received_init(); qmail_put(&qqt,received.s,received.len); qmail_put(&qqt,datastamp.s,datastamp.len); qmail_puts(&qqt,"\n"); *************** *** 376,417 **** out("\r\n"); } ! void safecats(out,in) ! stralloc *out; ! char *in; { ! char ch; ! while (ch = *in++) { ! if (ch < 33) ch = '?'; ! if (ch > 126) ch = '?'; ! if (ch == '(') ch = '?'; ! if (ch == ')') ch = '?'; ! if (ch == '@') ch = '?'; ! if (ch == '\\') ch = '?'; ! if (!stralloc_append(out,&ch)) nomem(); } } ! void received_init() { ! char *x; ! if (!stralloc_copys(&received,"Received: (ofmipd ")) nomem(); ! x = env_get("TCPREMOTEINFO"); ! if (x) { ! safecats(&received,x); ! if (!stralloc_append(&received,"@")) nomem(); } - x = env_get("TCPREMOTEIP"); - if (!x) x = "unknown"; - safecats(&received,x); - if (!stralloc_cats(&received,"); ")) nomem(); } struct commands smtpcommands[] = { { "rcpt", smtp_rcpt, 0 } , { "mail", smtp_mail, 0 } , { "data", smtp_data, flush } , { "quit", smtp_quit, flush } , { "helo", smtp_helo, flush } , { "ehlo", smtp_ehlo, flush } --- 440,666 ---- out("\r\n"); } ! #ifdef AUTHCRAM ! char unique[FMT_ULONG + FMT_ULONG + 3]; ! #endif ! static stralloc authin = {0}; ! static stralloc user = {0}; ! static stralloc pass = {0}; ! static stralloc resp = {0}; ! static stralloc slop = {0}; ! char *hostname; ! char **childargs; ! substdio ssup; ! char upbuf[128]; ! int authd = 0; ! ! int authgetl(void) { ! int i; ! ! if (!stralloc_copys(&authin, "")) nomem(); ! ! for (;;) { ! if (!stralloc_readyplus(&authin,1)) nomem(); /* XXX */ ! i = substdio_get(&ssin,authin.s + authin.len,1); ! if (i != 1) die_read(); ! if (authin.s[authin.len] == '\n') break; ! ++authin.len; ! } ! ! if (authin.len > 0) if (authin.s[authin.len - 1] == '\r') --authin.len; ! authin.s[authin.len] = 0; ! ! if (*authin.s == '*' && *(authin.s + 1) == 0) { return err_authabrt(); } ! if (authin.len == 0) { return err_input(); } ! return authin.len; ! } ! ! int authenticate(void) ! { ! int child; ! int wstat; ! int pi[2]; ! ! if (!stralloc_0(&user)) nomem(); ! if (!stralloc_0(&pass)) nomem(); ! if (!stralloc_0(&resp)) nomem(); ! ! if (fd_copy(2,1) == -1) return err_pipe(); ! close(3); ! if (pipe(pi) == -1) return err_pipe(); ! if (pi[0] != 3) return err_pipe(); ! switch(child = fork()) { ! case -1: ! return err_fork(); ! case 0: ! close(pi[1]); ! sig_pipedefault(); ! execvp(*childargs, childargs); ! _exit(1); ! } ! close(pi[0]); ! ! substdio_fdbuf(&ssup,write,pi[1],upbuf,sizeof upbuf); ! if (substdio_put(&ssup,user.s,user.len) == -1) return err_write(); ! if (substdio_put(&ssup,pass.s,pass.len) == -1) return err_write(); ! if (substdio_put(&ssup,resp.s,resp.len) == -1) return err_write(); ! if (substdio_flush(&ssup) == -1) return err_write(); ! ! close(pi[1]); ! byte_zero(pass.s,pass.len); ! byte_zero(upbuf,sizeof upbuf); ! if (wait_pid(&wstat,child) == -1) return err_child(); ! if (wait_crashed(wstat)) return err_child(); ! if (wait_exitcode(wstat)) { sleep(5); return 1; } /* no */ ! return 0; /* yes */ ! } ! ! int auth_login(arg) char *arg; { ! int r; ! ! if (*arg) { ! if (r = b64decode(arg,str_len(arg),&user) == 1) return err_input(); ! } ! else { ! out("334 VXNlcm5hbWU6\r\n"); flush(); /* Username: */ ! if (authgetl() < 0) return -1; ! if (r = b64decode(authin.s,authin.len,&user) == 1) return err_input(); } + if (r == -1) nomem(); + + out("334 UGFzc3dvcmQ6\r\n"); flush(); /* Password: */ + + if (authgetl() < 0) return -1; + if (r = b64decode(authin.s,authin.len,&pass) == 1) return err_input(); + if (r == -1) nomem(); + + if (!user.len || !pass.len) return err_input(); + return authenticate(); } ! int auth_plain(arg) char *arg; { ! int r, id = 0; ! if (*arg) { ! if (r = b64decode(arg,str_len(arg),&slop) == 1) return err_input(); ! } ! else { ! out("334 \r\n"); flush(); ! if (authgetl() < 0) return -1; ! if (r = b64decode(authin.s,authin.len,&slop) == 1) return err_input(); ! } ! if (r == -1 || !stralloc_0(&slop)) nomem(); ! while (slop.s[id]) id++; /* ignore authorize-id */ ! ! if (slop.len > id + 1) ! if (!stralloc_copys(&user,slop.s + id + 1)) nomem(); ! if (slop.len > id + user.len + 2) ! if (!stralloc_copys(&pass,slop.s + id + user.len + 2)) nomem(); ! ! if (!user.len || !pass.len) return err_input(); ! return authenticate(); ! } ! ! #ifdef AUTHCRAM ! int auth_cram() ! { ! int i, r; ! char *s; ! ! s = unique; ! s += fmt_uint(s,getpid()); ! *s++ = '.'; ! s += fmt_ulong(s,(unsigned long) now()); ! *s++ = '@'; ! *s++ = 0; ! ! if (!stralloc_copys(&pass,"<")) nomem(); ! if (!stralloc_cats(&pass,unique)) nomem(); ! if (!stralloc_cats(&pass,hostname)) nomem(); ! if (!stralloc_cats(&pass,">")) nomem(); ! if (b64encode(&pass,&slop) < 0) nomem(); ! if (!stralloc_0(&slop)) nomem(); ! ! out("334 "); ! out(slop.s); ! out("\r\n"); ! flush(); ! ! if (authgetl() < 0) return -1; ! if (r = b64decode(authin.s,authin.len,&slop) == 1) return err_input(); ! if (r == -1 || !stralloc_0(&slop)) nomem(); ! ! i = str_chr(slop.s,' '); ! s = slop.s + i; ! while (*s == ' ') ++s; ! slop.s[i] = 0; ! if (!stralloc_copys(&user,slop.s)) nomem(); ! if (!stralloc_copys(&resp,s)) nomem(); ! ! if (!user.len || !resp.len) return err_input(); ! return authenticate(); ! } ! #endif ! ! struct authcmd { ! char *text; ! int (*fun)(); ! } authcmds[] = { ! { "login", auth_login } ! , { "plain", auth_plain } ! #ifdef AUTHCRAM ! , { "cram-md5", auth_cram } ! #endif ! , { 0, err_noauth } ! }; ! ! void smtp_auth(arg) ! char *arg; ! { ! int i; ! char *cmd = arg; ! ! if (!hostname || !*childargs) ! { ! out("503 auth not available (#5.3.3)\r\n"); ! return; ! } ! if (authd) { err_authd(); return; } ! if (seenmail) { err_authmail(); return; } ! ! if (!stralloc_copys(&user,"")) nomem(); ! if (!stralloc_copys(&pass,"")) nomem(); ! if (!stralloc_copys(&resp,"")) nomem(); ! ! i = str_chr(cmd,' '); ! arg = cmd + i; ! while (*arg == ' ') ++arg; ! cmd[i] = 0; ! ! for (i = 0;authcmds[i].text;++i) ! if (case_equals(authcmds[i].text,cmd)) break; ! ! switch (authcmds[i].fun(arg)) { ! case 0: ! authd = 1; ! relayclient = ""; ! remoteinfo = user.s; ! if (!env_unset("TCPREMOTEINFO")) die_read(); ! if (!env_put2("TCPREMOTEINFO",remoteinfo)) nomem(); ! out("235 ok, go ahead (#2.0.0)\r\n"); ! break; ! case 1: ! out("535 authorization failed (#5.7.0)\r\n"); } } struct commands smtpcommands[] = { { "rcpt", smtp_rcpt, 0 } , { "mail", smtp_mail, 0 } , { "data", smtp_data, flush } + , { "auth", smtp_auth, flush } , { "quit", smtp_quit, flush } , { "helo", smtp_helo, flush } , { "ehlo", smtp_ehlo, flush } *************** *** 429,440 **** sig_pipeignore(); fncdb = argv[1]; ! if (fncdb) { fdcdb = open_read(fncdb); if (fdcdb == -1) die_config(); ! } - received_init(); if (leapsecs_init() == -1) die_config(); if (chdir(auto_qmail) == -1) die_config(); if (rwhconfig(&rewrite,&idappend) == -1) die_config(); --- 678,693 ---- sig_pipeignore(); fncdb = argv[1]; ! if (fncdb && *fncdb) { fdcdb = open_read(fncdb); if (fdcdb == -1) die_config(); ! } else fncdb = 0; ! ! hostname = argv[2]; ! childargs = argv + 3; ! remoteinfo = env_get("TCPREMOTEINFO"); ! relayclient = env_get("RELAYCLIENT"); if (leapsecs_init() == -1) die_config(); if (chdir(auto_qmail) == -1) die_config(); if (rwhconfig(&rewrite,&idappend) == -1) die_config(); *************** *** 443,445 **** --- 696,699 ---- commands(&ssin,&smtpcommands); nomem(); } + diff -c mess822-0.58-dist/qmail.c mess822-0.58-patched/qmail.c *** mess822-0.58-dist/qmail.c Fri Sep 4 22:33:37 1998 --- mess822-0.58-patched/qmail.c Sat Apr 5 23:30:10 2003 *************** *** 6,19 **** #include "fd.h" #include "qmail.h" #include "auto_qmail.h" ! static char *binqqargs[2] = { "bin/qmail-queue", 0 } ; int qmail_open(qq) struct qmail *qq; { int pim[2]; int pie[2]; if (pipe(pim) == -1) return -1; if (pipe(pie) == -1) { close(pim[0]); close(pim[1]); return -1; } --- 6,30 ---- #include "fd.h" #include "qmail.h" #include "auto_qmail.h" + #include "env.h" ! static char *binqqargs[2] = { 0, 0 } ; ! ! static void setup_qqargs() ! { ! if(!binqqargs[0]) ! binqqargs[0] = env_get("QMAILQUEUE"); ! if(!binqqargs[0]) ! binqqargs[0] = "bin/qmail-queue"; ! } int qmail_open(qq) struct qmail *qq; { int pim[2]; int pie[2]; + + setup_qqargs(); if (pipe(pim) == -1) return -1; if (pipe(pie) == -1) { close(pim[0]); close(pim[1]); return -1; } diff -c mess822-0.58-dist/str_cpy.c mess822-0.58-patched/str_cpy.c *** mess822-0.58-dist/str_cpy.c Wed Apr 7 23:20:49 2004 --- mess822-0.58-patched/str_cpy.c Tue Nov 11 09:24:00 2003 *************** *** 0 **** --- 1,16 ---- + #include "str.h" + + unsigned int str_copy(s,t) + register char *s; + register char *t; + { + register int len; + + len = 0; + for (;;) { + if (!(*s = *t)) return len; ++s; ++t; ++len; + if (!(*s = *t)) return len; ++s; ++t; ++len; + if (!(*s = *t)) return len; ++s; ++t; ++len; + if (!(*s = *t)) return len; ++s; ++t; ++len; + } + }