Find documentation etc. on this patch under http://free.acrconsulting.co.uk/ diff -Nru mess822-0.58/base64.c mess822-0.58_ofmipd-plus-1.1/base64.c --- mess822-0.58/base64.c 1970-01-01 01:00:00.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/base64.c 2010-07-22 18:25:48.000000000 +0100 @@ -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 -Nru mess822-0.58/base64.h mess822-0.58_ofmipd-plus-1.1/base64.h --- mess822-0.58/base64.h 1970-01-01 01:00:00.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/base64.h 2010-07-22 18:25:48.000000000 +0100 @@ -0,0 +1,7 @@ +#ifndef BASE64_H +#define BASE64_H + +extern int b64decode(); +extern int b64encode(); + +#endif diff -Nru mess822-0.58/byte.h mess822-0.58_ofmipd-plus-1.1/byte.h --- mess822-0.58/byte.h 1998-09-05 03:33:37.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/byte.h 2010-07-22 18:25:48.000000000 +0100 @@ -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 -Nru mess822-0.58/byte_zero.c mess822-0.58_ofmipd-plus-1.1/byte_zero.c --- mess822-0.58/byte_zero.c 1970-01-01 01:00:00.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/byte_zero.c 2010-07-22 18:25:48.000000000 +0100 @@ -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 -Nru mess822-0.58/conf-cc mess822-0.58_ofmipd-plus-1.1/conf-cc --- mess822-0.58/conf-cc 1998-09-05 03:33:37.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/conf-cc 2010-07-22 18:25:48.000000000 +0100 @@ -1,3 +1,3 @@ -gcc -O2 +gcc -O2 -include /usr/include/errno.h This will be used to compile .c files. diff -Nru mess822-0.58/env.c mess822-0.58_ofmipd-plus-1.1/env.c --- mess822-0.58/env.c 1998-09-05 03:33:37.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/env.c 2010-07-22 18:25:48.000000000 +0100 @@ -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() { - int i; - unsigned int len; + 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); +} - 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_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 -Nru mess822-0.58/env.h mess822-0.58_ofmipd-plus-1.1/env.h --- mess822-0.58/env.h 1998-09-05 03:33:37.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/env.h 2010-07-22 18:25:48.000000000 +0100 @@ -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 -Nru mess822-0.58/envread.c mess822-0.58_ofmipd-plus-1.1/envread.c --- mess822-0.58/envread.c 1970-01-01 01:00:00.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/envread.c 2010-07-22 18:25:48.000000000 +0100 @@ -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 -Nru mess822-0.58/envset.c mess822-0.58_ofmipd-plus-1.1/envset.c --- mess822-0.58/envset.c 1970-01-01 01:00:00.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/envset.c 2010-07-22 18:25:48.000000000 +0100 @@ -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 -Nru mess822-0.58/errbits.c mess822-0.58_ofmipd-plus-1.1/errbits.c --- mess822-0.58/errbits.c 1970-01-01 01:00:00.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/errbits.c 2010-07-22 18:25:48.000000000 +0100 @@ -0,0 +1,62 @@ +#include "stralloc.h" +#include "readwrite.h" +#include "errbits.h" +#include "substdio.h" +#include "fmt.h" +#include "exit.h" + +char sserrbuf[512]; +static substdio sserr = SUBSTDIO_FDBUF(write,2,sserrbuf,sizeof sserrbuf); +static stralloc foo = {0}; + +static char pid_str[FMT_ULONG]="?PID?"; + +void esetfd(fd) int fd; { sserr.fd=fd; } + +void eout(s1) char *s1; {substdio_puts(&sserr,s1);} +void eout2(s1,s2) char *s1,*s2; {substdio_puts(&sserr,s1);substdio_puts(&sserr,s2);} +void eout3(s1,s2,s3) char *s1,*s2,*s3; {substdio_puts(&sserr,s1);substdio_puts(&sserr,s2);substdio_puts(&sserr,s3);} + +void epid() +{ + if (*pid_str == '?') /* not yet set from getpid() */ + pid_str[fmt_ulong(pid_str,getpid())] = 0; + eout(pid_str); +} +void eflush() { substdio_flush(&sserr); } + +/* The functions below here come from qsutil.c with minor changes */ +void eoutsa(sa) stralloc *sa; { substdio_putflush(&sserr,sa->s,sa->len); } + +static void nomem() { substdio_putsflush(&sserr,"Out Of Memory: quitting.\n"); _exit(1); } + +static int issafe(ch) char ch; +{ /* Differs from qsutil.c version: space and % permitted */ + if (ch == ':') return 0; /* Replace since used as delimiter in logs */ + if (ch == '<') return 0; /* Replace since used around addresses in logs */ + if (ch == '>') return 0; /* Replace since used around addresses in logs */ + if (ch < 32) return 0; /* Note that space (32) is permitted */ + if (ch > 126) return 0; + return 1; +} + +void eoutclean(s) char *s; +{ + int i; + while (!stralloc_copys(&foo,s)) nomem(); + for (i = 0;i < foo.len;++i) + if (foo.s[i] == '\n') + foo.s[i] = '/'; + else + if (!issafe(foo.s[i])) + foo.s[i] = '_'; + eoutsa(&foo); +} + +static char ulongstr[FMT_ULONG]; +void eoutulong(u) unsigned long u; +{ + ulongstr[fmt_ulong(ulongstr,u)] = 0; + eout(ulongstr); +} + diff -Nru mess822-0.58/errbits.h mess822-0.58_ofmipd-plus-1.1/errbits.h --- mess822-0.58/errbits.h 1970-01-01 01:00:00.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/errbits.h 2010-07-22 18:25:48.000000000 +0100 @@ -0,0 +1,15 @@ +extern void esetfd(); /* functions in this module default to FD 2 (stderr) for output, change with esetfd */ +extern void eout(); +extern void eout2(); +extern void eout3(); +#define eout4(s1,s2,s3,s4) { eout3(s1,s2,s3); eout(s4); } +#define eout5(s1,s2,s3,s4,s5) { eout3(s1,s2,s3); eout2(s4,s5); } +#define eout6(s1,s2,s3,s4,s5,s6) { eout3(s1,s2,s3); eout3(s4,s5,s6); } +#define eout7(s1,s2,s3,s4,s5,s6,s7) { eout3(s1,s2,s3); eout4(s4,s5,s6,s7); } +#define eout8(s1,s2,s3,s4,s5,s6,s7,s8) { eout3(s1,s2,s3); eout5(s4,s5,s6,s7,s8); } +#define eout9(s1,s2,s3,s4,s5,s6,s7,s8,s9) { eout3(s1,s2,s3); eout6(s4,s5,s6,s7,s8,s9); } +extern void eoutsa(); +extern void epid(); +extern void eflush(); +extern void eoutclean(); +extern void eoutulong(); diff -Nru mess822-0.58/fmt.h mess822-0.58_ofmipd-plus-1.1/fmt.h --- mess822-0.58/fmt.h 1970-01-01 01:00:00.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/fmt.h 2010-07-22 18:25:48.000000000 +0100 @@ -0,0 +1,25 @@ +#ifndef FMT_H +#define FMT_H + +#define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */ +#define FMT_LEN ((char *) 0) /* convenient abbreviation */ + +extern unsigned int fmt_uint(char *,unsigned int); +extern unsigned int fmt_uint0(char *,unsigned int,unsigned int); +extern unsigned int fmt_xint(char *,unsigned int); +extern unsigned int fmt_nbbint(char *,unsigned int,unsigned int,unsigned int,unsigned int); +extern unsigned int fmt_ushort(char *,unsigned short); +extern unsigned int fmt_xshort(char *,unsigned short); +extern unsigned int fmt_nbbshort(char *,unsigned int,unsigned int,unsigned int,unsigned short); +extern unsigned int fmt_ulong(char *,unsigned long); +extern unsigned int fmt_xlong(char *,unsigned long); +extern unsigned int fmt_nbblong(char *,unsigned int,unsigned int,unsigned int,unsigned long); + +extern unsigned int fmt_plusminus(char *,int); +extern unsigned int fmt_minus(char *,int); +extern unsigned int fmt_0x(char *,int); + +extern unsigned int fmt_str(char *,char *); +extern unsigned int fmt_strn(char *,char *,unsigned int); + +#endif diff -Nru mess822-0.58/fmt_ulong.c mess822-0.58_ofmipd-plus-1.1/fmt_ulong.c --- mess822-0.58/fmt_ulong.c 1970-01-01 01:00:00.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/fmt_ulong.c 2010-07-22 18:25:48.000000000 +0100 @@ -0,0 +1,13 @@ +#include "fmt.h" + +unsigned int fmt_ulong(register char *s,register unsigned long u) +{ + register unsigned int len; register unsigned long q; + len = 1; q = u; + while (q > 9) { ++len; q /= 10; } + if (s) { + s += len; + do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */ + } + return len; +} diff -Nru mess822-0.58/Makefile mess822-0.58_ofmipd-plus-1.1/Makefile --- mess822-0.58/Makefile 1998-09-05 03:33:37.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/Makefile 2010-07-22 18:25:48.000000000 +0100 @@ -240,6 +240,10 @@ it instcheck ./instcheck +clean: \ +TARGETS + rm -f `cat TARGETS` + commands.o: \ compile commands.c commands.h substdio.h stralloc.h gen_alloc.h str.h \ case.h @@ -261,13 +265,21 @@ ./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 + +errbits.o: \ +compile errbits.c errbits.h stralloc.h gen_alloc.h fmt.h exit.h fmt.h + ./compile errbits.c + error.a: \ makelib error.o error_str.o ./makelib error.a error.o error_str.o @@ -297,6 +309,10 @@ cat auto-ccld.sh find-systype.sh > find-systype chmod 755 find-systype +fmt_ulong.o: \ +compile fmt_ulong.c fmt.h + ./compile fmt_ulong.c + fork.h: \ compile load tryvfork.c fork.h1 fork.h2 ( ( ./compile tryvfork.c && ./load tryvfork ) >/dev/null \ @@ -540,11 +556,13 @@ ofmipd: \ load ofmipd.o rewritehost.o rwhconfig.o config.o qmail.o auto_qmail.o \ +base64.o byte_zero.o errbits.o fmt_ulong.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 errbits.o fmt_ulong.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 @@ -558,7 +576,7 @@ readwrite.h timeoutread.h timeoutwrite.h stralloc.h gen_alloc.h \ substdio.h config.h stralloc.h env.h exit.h error.h str.h mess822.h \ stralloc.h caltime.h caldate.h tai.h uint64.h caltime.h cdb.h \ -uint32.h +uint32.h errbits.h fmt.h ./compile ofmipd.c ofmipname: \ @@ -735,15 +753,19 @@ 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 ./compile str_diff.c diff -Nru mess822-0.58/ofmipd.8 mess822-0.58_ofmipd-plus-1.1/ofmipd.8 --- mess822-0.58/ofmipd.8 1998-09-05 03:33:37.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/ofmipd.8 2010-07-22 18:25:48.000000000 +0100 @@ -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 -Nru mess822-0.58/ofmipd.c mess822-0.58_ofmipd-plus-1.1/ofmipd.c --- mess822-0.58/ofmipd.c 1998-09-05 03:33:37.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/ofmipd.c 2010-07-22 18:25:48.000000000 +0100 @@ -16,14 +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" +#include "errbits.h" + +#undef AUTHCRAM /* don't define, not fully implemented */ int timeout = 1200; +char *remoteip="(not yet set)"; +char *relayclient; + +/* Choose your log format by selecting an enew() here, */ +/* void enew() { eout3("ofmipd: ",remoteip," pid "); epid(); eout(": "); } */ +void enew() { eout("ofmipd: pid "); epid(); eout2(" from ", remoteip); eout(": "); } + int safewrite(fd,buf,len) int fd; char *buf; int len; { int r; r = timeoutwrite(timeout,fd,buf,len); - if (r <= 0) _exit(1); + if (r <= 0) + { + enew(); eout("Write error (disconnect?): quitting\n"); eflush(); + _exit(1); + } return r; } @@ -33,26 +52,120 @@ void flush() { substdio_flush(&ssout); } void out(s) char *s; { substdio_puts(&ssout,s); } -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 smtp_quit() { out("221 ofmipd.local\r\n"); flush(); _exit(0); } +stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */ +stralloc rwaddr = {0}; + +void die_read() +{ + enew(); eout("Read error (disconnect?): quitting\n"); eflush(); + _exit(1); +} +void nomem() +{ + enew(); eout("Out of memory: quitting\n"); eflush(); + out("451 out of memory (#4.3.0)\r\n"); flush(); _exit(1); +} +void die_config() +{ + enew(); eout("Unable to read configuration: quitting\n"); eflush(); + out("451 unable to read configuration (#4.3.0)\r\n"); flush(); _exit(1); +} +void smtp_quit() +{ + enew(); eout("Remote end QUIT: quitting\n"); eflush(); + 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"); } -void smtp_vrfy() { out("252 send some mail, i'll try my best\r\n"); } -void smtp_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); } -void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); } -void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); } -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"); } +void smtp_noop() +{ + enew(); eout("NOOP\n"); eflush(); + out("250 ok\r\n"); +} +void smtp_vrfy() +{ + enew(); eout("VRFY requested\n"); eflush(); + out("252 send some mail, I'll try my best\r\n"); +} +void smtp_unimpl() +{ + enew(); eout("Unimplemented command\n"); eflush(); + out("502 unimplemented (#5.5.1)\r\n"); +} +void err_syntax(cmd) char *cmd; +{ + enew(); eout2(cmd," with too long address ("); eoutulong(addr.len); eout(" bytes) given\n"); eflush(); + out("555 syntax error (#5.5.4)\r\n"); +} +void err_wantmail() +{ + enew(); eout("Attempted RCPT or DATA before MAIL\n"); eflush(); + out("503 MAIL first (#5.5.1)\r\n"); +} +void err_wantrcpt() +{ + enew(); eout("Attempted DATA before RCPT\n"); eflush(); + out("503 RCPT first (#5.5.1)\r\n"); +} +void err_qqt() +{ + enew(); eout("qqt failure\n"); eflush(); + out("451 qqt failure (#4.3.0)\r\n"); +} +void err_cdb() +{ + enew(); eout("Unable to read cdb\n"); eflush(); + out("451 unable to read cdb (#4.3.0)\r\n"); +} +int err_child() +{ + enew(); eout("problem with child, can't auth\n"); eflush(); + out("454 oops, problem with child and I can't auth (#4.3.0)\r\n"); return -1; +} +int err_fork() +{ + enew(); eout("child won't start, can't auth\n"); eflush(); + out("454 oops, child won't start and I can't auth (#4.3.0)\r\n"); return -1; +} +int err_pipe() +{ + enew(); eout("can't setup pipe for auth\n"); eflush(); + out("454 oops, unable to open pipe and I can't auth (#4.3.0)\r\n"); return -1; +} +int err_write() +{ + enew(); eout("can't write pipe for auth\n"); eflush(); + out("454 oops, unable to write pipe and I can't auth (#4.3.0)\r\n"); return -1; +} +void err_authd() +{ + enew(); eout("auth requested but already authenticated\n"); eflush(); + out("503 you're already authenticated (#5.5.0)\r\n"); +} +void err_authmail() +{ + enew(); eout("auth requested during mail transaction\n"); eflush(); + out("503 no auth during mail transaction (#5.5.0)\r\n"); +} +int err_noauth() +{ + enew(); eout("Unsupported auth type requested\n"); eflush(); + out("504 auth type unimplemented (#5.5.1)\r\n"); return -1; +} +int err_authabrt() +{ + enew(); eout("auth auth exchange cancelled\n"); eflush(); + 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() +{ + enew(); eout("Attempted mail/rcpt before authenticating\n"); eflush(); + out("503 authorize or check your mail before sending (#5.5.1)\r\n"); return -1; +} config_str rewrite = CONFIG_STR; stralloc idappend = {0}; -stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */ -stralloc rwaddr = {0}; - int addrparse(arg) char *arg; { @@ -107,25 +220,38 @@ stralloc mailfrom = {0}; stralloc rcptto = {0}; +int rcptcount; void smtp_helo(arg) char *arg; { seenmail = 0; + enew(); eout("Received HELO "); eoutclean(arg); eout("\n"); eflush(); out("250 ofmipd.local\r\n"); } void smtp_ehlo(arg) char *arg; { seenmail = 0; - out("250-ofmipd.local\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); + enew(); eout("Received EHLO "); eoutclean(arg); eout("\n"); eflush(); + 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() { seenmail = 0; + enew(); eout("Session RSET\n"); eflush(); out("250 flushed\r\n"); } void smtp_mail(arg) char *arg; { - if (!addrparse(arg)) { err_syntax(); return; } + if (!relayclient) { err_notauth(); return; } + if (!addrparse(arg)) { err_syntax(arg); return; } name = 0; if (fncdb) { @@ -149,21 +275,27 @@ if (!stralloc_0(&mailfrom)) nomem(); if (!stralloc_copys(&rcptto,"")) nomem(); seenmail = 1; + rcptcount = 0; + enew(); eout("Sender <"); eoutclean(mailfrom.s); eout(">\n"); eflush(); 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 (!addrparse(arg)) { err_syntax(arg); return; } if (!stralloc_0(&rwaddr)) nomem(); if (!stralloc_cats(&rcptto,"T")) nomem(); if (!stralloc_cats(&rcptto,rwaddr.s)) nomem(); if (!stralloc_0(&rcptto)) nomem(); + ++rcptcount; + enew(); eout("Recipient <"); eoutclean(addr.s); eout(">\n"); eflush(); out("250 ok\r\n"); } +unsigned int messagebytes = 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); } +void put(buf,len) char *buf; int len; { qmail_put(&qqt,buf,len); messagebytes+=len; } +void puts(buf) char *buf; { qmail_puts(&qqt,buf); messagebytes+=str_len(buf); } stralloc tmp = {0}; stralloc tmp2 = {0}; @@ -345,10 +477,44 @@ 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(); +/* Uncomment this section if you want auth_user@IP instead of just IP in headers, + x = remoteinfo; + if (x) { + safecats(&received,x); + if (!stralloc_append(&received,"@")) nomem(); + } +*/ + safecats(&received,remoteip); + if (!stralloc_cats(&received,"); ")) nomem(); +} void smtp_data() { struct tai now; + unsigned long qp; char *qqx; tai_now(&now); @@ -356,62 +522,276 @@ 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; + messagebytes = 0; if (qmail_open(&qqt) == -1) { err_qqt(); return; } + qp = qmail_qp(&qqt); out("354 go ahead\r\n"); - qmail_put(&qqt,received.s,received.len); - qmail_put(&qqt,datastamp.s,datastamp.len); - qmail_puts(&qqt,"\n"); + received_init(); +/* messagebytes calculations below relate to the 'Received:' header line added * + * by ofmipd; remove them if you just want to log the incoming messagebytes, */ + qmail_put(&qqt,received.s,received.len); messagebytes+=received.len; + qmail_put(&qqt,datastamp.s,datastamp.len); messagebytes+=datastamp.len; + qmail_puts(&qqt,"\n"); messagebytes+=1; blast(); qmail_from(&qqt,mailfrom.s); qmail_put(&qqt,rcptto.s,rcptto.len); qqx = qmail_close(&qqt); - if (!*qqx) { out("250 ok\r\n"); return; } + enew(); + if (!*qqx) + { + eout("Message accepted, qp "); eoutulong(qp); + eout(" ("); eoutulong((unsigned long)rcptcount); eout(" recipients, "); + eoutulong(messagebytes); eout(" bytes)\n"); + eflush(); + out("250 ok\r\n"); return; + } if (*qqx == 'D') out("554 "); else out("451 "); out(qqx + 1); out("\r\n"); + eout("Message rejected ("); + if (*qqx == 'D') eout("554 "); else eout("451 "); + eoutclean(qqx + 1); eout(")\n"); + eflush(); +} + +#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(2); return 1; } /* no */ + return 0; /* yes */ } -void safecats(out,in) -stralloc *out; -char *in; +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; +{ + 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; char *x; - if (!stralloc_copys(&received,"Received: (ofmipd ")) nomem(); - x = env_get("TCPREMOTEINFO"); - if (x) { - safecats(&received,x); - if (!stralloc_append(&received,"@")) nomem(); + if (!hostname || !*childargs) + { + out("503 auth not available (#5.3.3)\r\n"); + enew(); eout("Authentication requested but not available - hostname or child args missing"); eflush(); + 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"); + enew(); eout3("auth ",cmd," succeeded for user '"); eoutclean(user.s); eout("'\n"); eflush(); + break; + + case 1: + out("535 authorization failed (#5.7.0)\r\n"); + enew(); eout3("auth ",cmd," failed for user '"); eoutclean(user.s); eout("'.\n"); eflush(); + break; + + case -1: + enew(); eout("malformed auth input"); + if (user.len) { eout(" for user '"); eoutclean(user.s); eout("'"); } + eout("\n"); eflush(); } - 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 } @@ -428,13 +808,21 @@ { sig_pipeignore(); + remoteip = env_get("TCPREMOTEIP"); + if (!remoteip) remoteip = "unknown"; + esetfd(7); /* Can't use fd 2 (stderr) cos of how checkpassword called at present */ + 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(); @@ -443,3 +831,4 @@ commands(&ssin,&smtpcommands); nomem(); } + diff -Nru mess822-0.58/qmail.c mess822-0.58_ofmipd-plus-1.1/qmail.c --- mess822-0.58/qmail.c 1998-09-05 03:33:37.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/qmail.c 2010-07-22 18:25:48.000000000 +0100 @@ -6,8 +6,17 @@ #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; @@ -15,6 +24,8 @@ 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 -Nru mess822-0.58/str_cpy.c mess822-0.58_ofmipd-plus-1.1/str_cpy.c --- mess822-0.58/str_cpy.c 1970-01-01 01:00:00.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/str_cpy.c 2010-07-22 18:25:48.000000000 +0100 @@ -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 -Nru mess822-0.58/TARGETS mess822-0.58_ofmipd-plus-1.1/TARGETS --- mess822-0.58/TARGETS 1998-09-05 03:33:37.000000000 +0100 +++ mess822-0.58_ofmipd-plus-1.1/TARGETS 2010-07-22 18:25:48.000000000 +0100 @@ -8,6 +8,8 @@ iftocc.o make-makelib makelib +fmt_ulong.o +errbits.o mess822_date.o mess822_quote.o mess822_fold.o @@ -153,6 +155,10 @@ quote.o quote parsedate.o +base64.o +byte_zero.o +envread.o +str_cpy.o parsedate prog iftocc.0