ezmlmx 0.68
ezmlmx
Loading...
Searching...
No Matches
ezmlm-confirm.c
Go to the documentation of this file.
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <unistd.h>
4#include "error.h"
5#include "case.h"
6#include "stralloc.h"
7#include "str.h"
8#include "env.h"
9#include "error.h"
10#include "sig.h"
11#include "wait.h"
12#include "readclose.h"
13#include "getconf.h"
14#include "byte.h"
15#include "getln.h"
16#include "qmail.h"
17#include "buffer.h"
18#include "readwrite.h"
19#include "seek.h"
20#include "quote.h"
21#include "datetime.h"
22#include "now.h"
23#include "fmt.h"
24#include "getoptb.h"
25#include "auto_bin.h"
26#include "cookie.h"
27#include "errtxt.h"
28#include "ezcopy.h"
29#include "open.h"
30#include "lock.h"
31#include "wrap.h"
32#include "idx.h"
33#include "mime.h"
34#include "auto_version.h"
35#include "logmsg.h"
36#include "lockfile.h"
37#include "ezmlm.h"
38
39#define WHO "ezmlm-confirm"
40
46
47static int flagmime = MOD_MIME; /* default is message as attachment */
48
49static void die_usage() { logmsg(WHO,100,USAGE,B("ezmlm-confirm [-cCmMrRvV] dir [/path/ezmlm-send]")); }
50static void die_nomem() { logmsg(WHO,111,FATAL,ERR_NOMEM); }
52
53static stralloc key = {0};
54static stralloc mailinglist = {0};
55static stralloc to = {0};
56static stralloc sendopt = {0};
57static datetime_sec when;
58
59static char hash[COOKIE];
60static stralloc line = {0};
61static stralloc fnbase = {0};
62static stralloc fnmsg = {0};
63
64static const char *dir;
65static struct stat st;
66
67struct qmail qq;
68stralloc outhost = {0};
69stralloc outlocal = {0};
70
81
82static int checkfile(const char *fn)
83{
84 if (!stralloc_copys(&fnmsg,"mod/unconfirmed/")) die_nomem();
85 if (!stralloc_cats(&fnmsg,fn)) die_nomem();
86 if (!stralloc_0(&fnmsg)) die_nomem();
87 if (stat(fnmsg.s,&st) == 0) return 1;
88 if (errno != ENOENT)
89 logmsg(WHO,111,FATAL,B(ERR_STAT,dir,"/",fnmsg.s));
90
91 return 0;
92}
93
94static ssize_t qqwrite(int fd,char *buf,unsigned int len)
95{
97 return len;
98}
99static char qqbuf[256];
100buffer bq = BUFFER_INIT(qqwrite,-1,qqbuf,sizeof(qqbuf));
101
102static buffer bt;
103static char textbuf[1024];
104
112
113static void maketo(void)
114{
115 unsigned int x, y;
116
117 if (case_startb(line.s,line.len,"return-path:")) {
118 x = 12 + byte_chr(line.s + 12,line.len - 12,'<');
119 if (x != line.len) {
120 y = byte_rchr(line.s + x,line.len - x,'>');
121 if (y + x != line.len) {
122 if (!stralloc_copyb(&to,line.s + x + 1,y - 1)) die_nomem();
123 if (!stralloc_0(&to)) die_nomem();
124 } /* no return path-> no addressee. A NUL in the sender */
125 } /* is no worse than a faked sender, so no problem */
126 }
127}
128
129int main(int argc, char **argv)
130{
131 const char *sender;
132 const char *def;
133 const char *local;
134 const char *action;
135 int fd;
136 int match;
137 char szchar[2] = "-";
138 const char *replyto = (char *) 0;
139 unsigned int start,confnum;
140 int child;
141 int opt;
142 const char *cp;
143
144 (void) umask(022);
145 sig_pipeignore();
146 when = now();
147
148 if (!stralloc_copys(&sendopt,"-")) die_nomem();
149 while ((opt = getopt(argc,argv,"cCmMrRt:T:vV")) != opteof)
150 switch(opt) { /* pass on ezmlm-send options */
151 case 'c': /* ezmlm-send flags */
152 case 'C':
153 case 'r':
154 case 'R': szchar[0] = (char) opt & 0xff;
155 if (!stralloc_append(&sendopt,szchar)) die_nomem();
156 break;
157 case 'm': flagmime = 1; break;
158 case 'M': flagmime = 0; break;
159 case 't':
160 case 'T': if (optarg) replyto = optarg; break;
161 case 'v':
162 case 'V': logmsg(WHO,0,VERSION,auto_version);
163 default: die_usage();
164 }
165
166 dir = argv[optind++];
167 if (!dir) die_usage();
168
169 sender = env_get("SENDER");
170 if (!sender) logmsg(WHO,100,FATAL,ERR_NOSENDER);
171 local = env_get("LOCAL");
172 if (!local) logmsg(WHO,100,FATAL,ERR_NOLOCAL);
173 def = env_get("DEFAULT");
174 if (!def) logmsg(WHO,100,FATAL,ERR_NODEFAULT);
175
176 if (!*sender)
177 logmsg(WHO,100,FATAL,ERR_BOUNCE);
178 if (!sender[str_chr(sender,'@')])
179 logmsg(WHO,100,FATAL,ERR_ANONYMOUS);
180 if (str_equal(sender,"#@[]"))
181 logmsg(WHO,100,FATAL,ERR_BOUNCE);
182
183 if (chdir(dir) == -1)
184 logmsg(WHO,111,FATAL,B(ERR_SWITCH,dir));
185
186 switch (openreadclose("key",&key,32)) {
187 case -1: logmsg(WHO,111,FATAL,B(ERR_READ,dir,"/key"));
188 case 0:
189 logmsg(WHO,100,FATAL,B(dir,"/key",ERR_NOEXIST));
190 }
191 getconf_line(&mailinglist,"mailinglist",1,dir);
192 getconf_line(&outhost,"outhost",1,dir);
193 getconf_line(&outlocal,"outlocal",1,dir);
194 set_cpoutlocal(&outlocal); /* for ezcopy() */
195 set_cpouthost(&outhost); /* for ezcopy() */
196
197 /* local should be >= def, but who knows ... */
198 cp = local + str_len(local) - str_len(def) - 2;
199 if (cp < local) die_badformat();
200 action = local + byte_rchr(local,cp - local,'-');
201 if (action == cp) die_badformat();
202 action++;
203
204 if (!action[0]) die_badformat();
205 if (!str_start(action,ACTION_CONFIRM) && !str_start(action,ACTION_DISCARD))
207 start = str_chr(action,'-');
208 if (!action[start]) die_badformat();
209 confnum = 1 + start + str_chr(action + start + 1,'.');
210 if (!action[confnum]) die_badformat();
211 confnum += 1 + str_chr(action + confnum + 1,'.');
212 if (!action[confnum]) die_badformat();
213 if (!stralloc_copyb(&fnbase,action+start+1,confnum-start-1)) die_nomem();
214 if (!stralloc_0(&fnbase)) die_nomem();
215 cookie(hash,key.s,key.len,fnbase.s,"","a");
216 if (byte_diff(hash,COOKIE,action+confnum+1))
218
219 lockfile("mod/confirmlock");
220
221 if (!checkfile(fnbase.s)) logmsg(WHO,100,FATAL,ERR_MOD_TIMEOUT);
222
223/* Here, we have an existing filename in fnbase with the complete path */
224/* from the current dir in fnmsg. */
225
226 if (str_start(action,ACTION_DISCARD)) {
227 unlink(fnmsg.s);
228 logmsg(WHO,0,INFO,"info: post rejected");
229 } else if (str_start(action,ACTION_CONFIRM)) {
230 fd = open_read(fnmsg.s);
231 if (fd == -1) {
232 if (errno !=ENOENT)
233 logmsg(WHO,111,FATAL,B(ERR_OPEN,fnmsg.s));
234 else /* shouldn't happen since we've got lock */
235 logmsg(WHO,100,FATAL,B(fnmsg.s,ERR_MOD_TIMEOUT));
236 }
237
238 buffer_init(&bt,buffer_unixread,fd,textbuf,sizeof(textbuf));
239 /* read "Return-Path:" line */
240 if (getln(&bt,&line,&match,'\n') == -1 || !match)
241 logmsg(WHO,111,FATAL,ERR_READ_INPUT);
242 maketo(); /* extract SENDER to "to" */
243 env_put2("SENDER",to.s); /* set SENDER */
244 if (seek_begin(fd) == -1) /* rewind, since we read an entire buffer */
245 logmsg(WHO,111,FATAL,B(ERR_SEEK,fnmsg.s));
246
247 if ((child = wrap_fork()) == 0) {
248 close(0);
249 dup(fd); /* make fnmsg.s stdin */
250 if (argc > optind)
251 wrap_execsh(argv[optind]);
252 else
253 wrap_execbin("/ezmlm-send", &sendopt, dir);
254 }
255 /* parent */
256 close(fd);
258
259 unlink(fnmsg.s);
260 _exit(0);
261 }
262
263 return 0;
264}
datetime_sec now(void)
Definition now.c:5
#define COOKIE
Definition cookie.h:4
#define MOD_MIME
Definition idx.h:173
#define ACTION_CONFIRM
Definition idx.h:198
#define ACTION_DISCARD
Definition idx.h:199
const char auto_version[]
void wrap_execsh(const char *command)
Definition wrap_execsh.c:9
void wrap_exitcode(int pid)
int wrap_fork(void)
Definition wrap_fork.c:15
void wrap_execbin(const char *program, struct stralloc *opts, const char *dir)
Error messages. If you translate these, I would urge you to keep the English version as well....
#define ERR_NOMEM
Definition errtxt.h:14
#define ERR_OPEN
Definition errtxt.h:30
#define ERR_NOLOCAL
Definition errtxt.h:34
#define ERR_BAD_REQUEST
Definition errtxt.h:52
#define ERR_NOEXIST
Definition errtxt.h:40
#define ERR_ANONYMOUS
Definition errtxt.h:44
#define ERR_READ_INPUT
Definition errtxt.h:26
#define ERR_SEEK
Definition errtxt.h:21
#define ERR_READ
Definition errtxt.h:18
#define ERR_NODEFAULT
Definition errtxt.h:35
#define ERR_MOD_TIMEOUT
Definition errtxt.h:99
#define ERR_SWITCH
Definition errtxt.h:42
#define ERR_STAT
Definition errtxt.h:24
#define ERR_NOSENDER
Definition errtxt.h:37
#define ERR_BOUNCE
Definition errtxt.h:38
int lockfile(const char *)
Definition lockfile.c:15
long datetime_sec
Definition datetime.h:15
void qmail_put(struct qmail *, const char *, int)
Definition qmail.c:87
charset, outhost, outlocal and flagcd are shared
void die_nomem()
Definition getconf.c:17
int getconf_line(stralloc *sa, const char *fn, int flagrequired, const char *dir)
Definition getconf.c:53
void set_cpoutlocal(const stralloc *ln)
Definition ezcopy.c:67
void set_cpouthost(const stralloc *ln)
Definition ezcopy.c:73
#define WHO
Definition author.c:1
stralloc fn
char * dir
int main()
Definition ezmlm-weed.c:69
void cookie(char *hash, const char *key, unsigned int keylen, const char *date, const char *addr, const char *action)
Definition cookie.c:14
int opt
Definition ezmlm-cron.c:53
const char * cp
Definition ezmlm-cron.c:76
unsigned int len
Definition ezmlm-cron.c:68
char szchar[2]
Definition ezmlm-gate.c:40
char buf[256]
Definition install.c:113
char * local
Definition ezmlm-cgi.c:106
int child
Definition ezmlm-cgi.c:143
int fd
Definition ezmlm-cgi.c:141
datetime_sec when
Definition ezmlm-cgi.c:173
int match
Definition ezmlm-cgi.c:140
unsigned int flagmime
Definition ezmlm-cgi.c:145
void die_badformat()
buffer bq
Definition ezmlm-clean.c:81
stralloc mailinglist
Definition ezmlm-clean.c:93
ssize_t qqwrite(int fd, char *buf, unsigned int len)
Definition ezmlm-clean.c:75
stralloc fnmsg
Definition ezmlm-clean.c:60
stralloc to
Definition ezmlm-clean.c:97
struct qmail qq
Definition ezmlm-clean.c:73
void maketo()
expects line to be a return-path line. If it is and the format is valid to is set to to the sender....
stralloc action
Definition ezmlm-store.c:84
Definition qmail.h:10
const char * logmsg(const char *dir, unsigned long num, unsigned long listno, unsigned long subs, int done)
Definition loginfo.c:32