diff -Nur mess822-0.58/Makefile mess822-0.58-auth-ucspitls/Makefile --- mess822-0.58/Makefile Sat Sep 5 04:33:37 1998 +++ mess822-0.58-auth-ucspitls/Makefile Fri Dec 2 08:56:37 2005 @@ -261,13 +261,17 @@ ./compile constmap.c env.a: \ -makelib env.o - ./makelib env.a env.o +makelib env.o envread.o + ./makelib env.a env.o envread.o env.o: \ -compile env.c str.h env.h +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,14 +544,17 @@ 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 +case.a str.a fs.a open.a wait.a sig.a fd.a \ +ucspitls.o ./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 + sig.a fd.a ucspitls.o ofmipd.0: \ ofmipd.8 @@ -735,14 +742,18 @@ 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_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 + 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 -Nur mess822-0.58/TARGETS mess822-0.58-auth-ucspitls/TARGETS --- mess822-0.58/TARGETS Sat Sep 5 04:33:37 1998 +++ mess822-0.58-auth-ucspitls/TARGETS Sun Jun 18 23:35:40 2006 @@ -184,3 +184,8 @@ instcheck.o instcheck check +base64.o +byte_zero.o +envread.o +str_cpy.o +ucspitls.o diff -Nur mess822-0.58/base64.c mess822-0.58-auth-ucspitls/base64.c --- mess822-0.58/base64.c Thu Jan 1 01:00:00 1970 +++ mess822-0.58-auth-ucspitls/base64.c Fri Dec 2 08:03:29 2005 @@ -0,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 -Nur mess822-0.58/base64.h mess822-0.58-auth-ucspitls/base64.h --- mess822-0.58/base64.h Thu Jan 1 01:00:00 1970 +++ mess822-0.58-auth-ucspitls/base64.h Fri Dec 2 08:03:29 2005 @@ -0,0 +1,7 @@ +#ifndef BASE64_H +#define BASE64_H + +extern int b64decode(); +extern int b64encode(); + +#endif diff -Nur mess822-0.58/byte.h mess822-0.58-auth-ucspitls/byte.h --- mess822-0.58/byte.h Sat Sep 5 04:33:37 1998 +++ mess822-0.58-auth-ucspitls/byte.h Fri Dec 2 08:03:29 2005 @@ -1,13 +1,6 @@ #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 diff -Nur mess822-0.58/byte_zero.c mess822-0.58-auth-ucspitls/byte_zero.c --- mess822-0.58/byte_zero.c Thu Jan 1 01:00:00 1970 +++ mess822-0.58-auth-ucspitls/byte_zero.c Fri Dec 2 08:03:29 2005 @@ -0,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 -Nur mess822-0.58/env.c mess822-0.58-auth-ucspitls/env.c --- mess822-0.58/env.c Sat Sep 5 04:33:37 1998 +++ mess822-0.58-auth-ucspitls/env.c Fri Dec 2 08:03:29 2005 @@ -1,16 +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" -extern /*@null@*/char *env_get(s) -char *s; +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; { - int i; - unsigned int len; + 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; +} - 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; +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 -Nur mess822-0.58/env.h mess822-0.58-auth-ucspitls/env.h --- mess822-0.58/env.h Sat Sep 5 04:33:37 1998 +++ mess822-0.58-auth-ucspitls/env.h Fri Dec 2 08:03:29 2005 @@ -1,8 +1,17 @@ #ifndef ENV_H #define ENV_H -extern char **environ; +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 -Nur mess822-0.58/envread.c mess822-0.58-auth-ucspitls/envread.c --- mess822-0.58/envread.c Thu Jan 1 01:00:00 1970 +++ mess822-0.58-auth-ucspitls/envread.c Fri Dec 2 08:03:29 2005 @@ -0,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 -Nur mess822-0.58/envset.c mess822-0.58-auth-ucspitls/envset.c --- mess822-0.58/envset.c Thu Jan 1 01:00:00 1970 +++ mess822-0.58-auth-ucspitls/envset.c Fri Dec 2 08:03:29 2005 @@ -0,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 -Nur mess822-0.58/hier.c mess822-0.58-auth-ucspitls/hier.c --- mess822-0.58/hier.c Sat Sep 5 04:33:37 1998 +++ mess822-0.58-auth-ucspitls/hier.c Sun Jun 18 22:30:30 2006 @@ -66,5 +66,5 @@ c(auto_home,"man/cat3","mess822_token.0",-1,-1,0644); c(auto_home,"man/cat3","mess822_when.0",-1,-1,0644); - c("/etc",".","leapsecs.dat",-1,-1,0644); + /*c("/etc",".","leapsecs.dat",-1,-1,0644);*/ } diff -Nur mess822-0.58/ofmipd.8 mess822-0.58-auth-ucspitls/ofmipd.8 --- mess822-0.58/ofmipd.8 Sat Sep 5 04:33:37 1998 +++ mess822-0.58-auth-ucspitls/ofmipd.8 Fri Dec 2 08:03:28 2005 @@ -3,8 +3,11 @@ ofmipd \- accept outgoing mail through OFMIP .SH SYNOPSIS .B ofmipd -[ .I name.cdb +[ +.I hostname +.I checkpasswd +.I truepgm ] .SH DESCRIPTION .B ofmipd @@ -31,15 +34,33 @@ Some sites use port 26. Some sites use port 25 on an IP address that does not receive incoming mail. -Note that +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. -It should be invoked -only for connections from preauthorized users. +If not, it will reject any MAIL FROM, RCPT TO, or DATA command with a 503 +error. With .B tcpserver -you can deny connections -that do not come from preauthorized IP addresses such as 127.0.0.1. +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,6 +113,10 @@ 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 -Nur mess822-0.58/ofmipd.c mess822-0.58-auth-ucspitls/ofmipd.c --- mess822-0.58/ofmipd.c Sat Sep 5 04:33:37 1998 +++ mess822-0.58-auth-ucspitls/ofmipd.c Sun Jun 18 22:39:40 2006 @@ -16,8 +16,21 @@ #include "tai.h" #include "caltime.h" #include "cdb.h" +#include "base64.h" +#include "wait.h" +#include "fd.h" +#include "byte.h" +#include "case.h" +#include "ucspitls.h" + +#undef AUTHCRAM /* don't define, not fully implemented */ int timeout = 1200; +int tls_available = 0; +int tls_force = 0; +int tls_started = 0; + +char *relayclient; int safewrite(fd,buf,len) int fd; char *buf; int len; { @@ -36,6 +49,7 @@ void die_read() { _exit(1); } void nomem() { out("451 out of memory (#4.3.0)\r\n"); flush(); _exit(1); } void die_config() { out("451 unable to read configuration (#4.3.0)\r\n"); flush(); _exit(1); } +void die_syserr() { out("421 system error (#4.3.0)\r\n"); flush(); _exit(1); } void smtp_quit() { out("221 ofmipd.local\r\n"); flush(); _exit(0); } void smtp_help() { out("214 qmail home page: http://pobox.com/~djb/qmail.html\r\n"); } void smtp_noop() { out("250 ok\r\n"); } @@ -46,6 +60,17 @@ 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; } +int err_notls() { out("530 Must issue a STARTTLS command first (#5.7.0)\r\n"); return -1; } config_str rewrite = CONFIG_STR; stralloc idappend = {0}; @@ -116,7 +141,19 @@ void smtp_ehlo(arg) char *arg; { seenmail = 0; - out("250-ofmipd.local\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); + out("250-ofmipd.local"); + if (!tls_force || (tls_force && tls_started)) { +#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 + } + if (tls_available && !tls_started) + out("\r\n250-STARTTLS"); + out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); } void smtp_rset() { @@ -125,6 +162,8 @@ } void smtp_mail(arg) char *arg; { + if (tls_force && !tls_started) { err_notls(); return; } + if (!relayclient) { err_notauth(); return; } if (!addrparse(arg)) { err_syntax(); return; } name = 0; @@ -152,6 +191,8 @@ out("250 ok\r\n"); } void smtp_rcpt(arg) char *arg; { + if (tls_force && !tls_started) { err_notls(); return; } + if (!relayclient) { err_notauth(); return; } if (!seenmail) { err_wantmail(); return; } if (!addrparse(arg)) { err_syntax(); return; } if (!stralloc_0(&rwaddr)) nomem(); @@ -161,6 +202,23 @@ out("250 ok\r\n"); } +void smtp_starttls(arg) char *arg; { + unsigned long long_fd; + int fd; + char *fdstr; + if (!tls_available || tls_started) + return smtp_unimpl(arg); + out("220 2.0.0 Ready to start TLS\r\n"); + flush(); + + if (!ucspitls()) + die_syserr(); + + tls_started = 1; + /* reset SMTP state */ + seenmail = 0; +} + struct qmail qqt; void put(buf,len) char *buf; int len; { qmail_put(&qqt,buf,len); } void puts(buf) char *buf; { qmail_puts(&qqt,buf); } @@ -345,7 +403,40 @@ 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,12 +447,15 @@ datastart.known = 1; if (!mess822_date(&datastamp,&datastart)) nomem(); + if (tls_force && !tls_started) { err_notls(); return; } + 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,48 +470,234 @@ out("\r\n"); } -void safecats(out,in) -stralloc *out; -char *in; +#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; { - 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(); + 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(); } -void received_init() +int auth_plain(arg) char *arg; { - char *x; + int r, id = 0; - if (!stralloc_copys(&received,"Received: (ofmipd ")) nomem(); - x = env_get("TCPREMOTEINFO"); - if (x) { - safecats(&received,x); - if (!stralloc_append(&received,"@")) nomem(); + 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"); } - 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 } +, { "auth", smtp_auth, flush } , { "quit", smtp_quit, flush } , { "helo", smtp_helo, flush } , { "ehlo", smtp_ehlo, flush } , { "rset", smtp_rset, 0 } , { "help", smtp_help, flush } , { "noop", smtp_noop, flush } +, { "starttls", smtp_starttls, flush } , { "vrfy", smtp_vrfy, flush } , { 0, smtp_unimpl, flush } } ; @@ -429,17 +709,26 @@ sig_pipeignore(); fncdb = argv[1]; - if (fncdb) { + 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"); - received_init(); if (leapsecs_init() == -1) die_config(); if (chdir(auto_qmail) == -1) die_config(); if (rwhconfig(&rewrite,&idappend) == -1) die_config(); + tls_available = !!env_get("UCSPITLS"); + tls_force = !!env_get("FORCETLS"); + + if (tls_force && !tls_available) die_syserr(); out("220 ofmipd.local ESMTP\r\n"); commands(&ssin,&smtpcommands); nomem(); } + diff -Nur mess822-0.58/qmail.c mess822-0.58-auth-ucspitls/qmail.c --- mess822-0.58/qmail.c Sat Sep 5 04:33:37 1998 +++ mess822-0.58-auth-ucspitls/qmail.c Fri Dec 2 08:03:29 2005 @@ -6,14 +6,25 @@ #include "fd.h" #include "qmail.h" #include "auto_qmail.h" +#include "env.h" -static char *binqqargs[2] = { "bin/qmail-queue", 0 } ; +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 -Nur mess822-0.58/str_cpy.c mess822-0.58-auth-ucspitls/str_cpy.c --- mess822-0.58/str_cpy.c Thu Jan 1 01:00:00 1970 +++ mess822-0.58-auth-ucspitls/str_cpy.c Fri Dec 2 08:03:28 2005 @@ -0,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; + } +} diff -Nur mess822-0.58/ucspitls.c mess822-0.58-auth-ucspitls/ucspitls.c --- mess822-0.58/ucspitls.c Thu Jan 1 01:00:00 1970 +++ mess822-0.58-auth-ucspitls/ucspitls.c Fri Dec 2 08:58:56 2005 @@ -0,0 +1,31 @@ +#include "scan.h" +#include "env.h" + +int ucspitls(void) +{ + unsigned long fd; + char *fdstr; + + if (!(fdstr=env_get("SSLCTLFD"))) + return 0; + if (!scan_ulong(fdstr,&fd)) + return 0; + if (write((int)fd, "y", 1) < 1) + return 0; + + if (!(fdstr=env_get("SSLREADFD"))) + return 0; + if (!scan_ulong(fdstr,&fd)) + return 0; + if (dup2((int)fd,0) == -1) + return 0; + + if (!(fdstr=env_get("SSLWRITEFD"))) + return 0; + if (!scan_ulong(fdstr,&fd)) + return 0; + if (dup2((int)fd,1) == -1) + return 0; + + return 1; +} diff -Nur mess822-0.58/ucspitls.h mess822-0.58-auth-ucspitls/ucspitls.h --- mess822-0.58/ucspitls.h Thu Jan 1 01:00:00 1970 +++ mess822-0.58-auth-ucspitls/ucspitls.h Fri Dec 2 08:58:56 2005 @@ -0,0 +1 @@ +int ucspitls(void);