summaryrefslogtreecommitdiffstats
path: root/qmail-spp.c
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2013-02-05 18:24:50 +0100
committermanuel <manuel@mausz.at>2013-02-05 18:24:50 +0100
commit2b9d328bdb940511fd49caae839579835b18d8bc (patch)
tree2783b94056505b4f2b8b3e46bd51603fdfa5f81b /qmail-spp.c
parentb4d6d654e95c9ad5a019a58e69679e8dd3201dc4 (diff)
downloadqmail-2b9d328bdb940511fd49caae839579835b18d8bc.tar.gz
qmail-2b9d328bdb940511fd49caae839579835b18d8bc.tar.bz2
qmail-2b9d328bdb940511fd49caae839579835b18d8bc.zip
[PATCH] Adding SPP framework for qmail-smtpd
qmail-1.03-r17-spp
Diffstat (limited to 'qmail-spp.c')
-rw-r--r--qmail-spp.c259
1 files changed, 259 insertions, 0 deletions
diff --git a/qmail-spp.c b/qmail-spp.c
new file mode 100644
index 0000000..78ab9e7
--- /dev/null
+++ b/qmail-spp.c
@@ -0,0 +1,259 @@
1/*
2 * Copyright (C) 2004-2005 Pawel Foremski <pjf@asn.pl>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later
8 * version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 *** Note
20 *
21 * This is the core of qmail-spp patch for qmail
22 *
23 * Why I made it a separate file? Because I wanted qmail-spp to apply more
24 * cleanly on heavily patched qmail sources and to make it bit simpler to
25 * maintain, so don't treat it as a library.
26 *
27 * "..." comments marks places where code for other SMTP commands should be
28 * added, if needed.
29 *
30 */
31
32#include "readwrite.h"
33#include "stralloc.h"
34#include "substdio.h"
35#include "control.h"
36#include "str.h"
37#include "byte.h"
38#include "env.h"
39#include "exit.h"
40#include "wait.h"
41#include "fork.h"
42#include "fd.h"
43#include "fmt.h"
44#include "getln.h"
45
46/* stuff needed from qmail-smtpd */
47extern void flush();
48extern void out();
49extern void die_nomem();
50extern stralloc addr;
51/* *** */
52
53stralloc sppheaders = {0};
54static int spprun = 0;
55static int sppfok = 0;
56static int sppret;
57static stralloc sppf = {0};
58static stralloc plugins_dummy = {0}, plugins_connect = {0}, plugins_helo = {0}, plugins_mail = {0},
59 plugins_rcpt = {0}, plugins_data = {0}, plugins_auth = {0}; /* ... */
60static stralloc error_mail = {0}, error_rcpt = {0}, error_data = {0}; /* ... */
61static stralloc sppmsg = {0};
62static char rcptcountstr[FMT_ULONG];
63static unsigned long rcptcount;
64static unsigned long rcptcountall;
65static substdio ssdown;
66static char downbuf[128];
67
68static void err_spp(s1, s2) char *s1, *s2; { out("451 qmail-spp failure: "); out(s1); out(": "); out(s2); out(" (#4.3.0)\r\n"); }
69
70int spp_init()
71{
72 int i, len = 0;
73 stralloc *plugins_to;
74 char *x, *conffile = "control/smtpplugins";
75
76 if (!env_get("NOSPP")) {
77 spprun = 1;
78 plugins_to = &plugins_dummy;
79 x = env_get("SPPCONFFILE");
80 if (x && *x) conffile = x;
81 sppfok = control_readfile(&sppf, conffile, 0);
82 if (sppfok != 1) return -1;
83 for (i = 0; i < sppf.len; i += len) {
84 len = str_len(sppf.s + i) + 1;
85 if (sppf.s[i] == '[')
86 switch (sppf.s[i + 1]) {
87 case 'c': plugins_to = &plugins_connect; break;
88 case 'h': plugins_to = &plugins_helo; break;
89 case 'm': plugins_to = &plugins_mail; break;
90 case 'r': plugins_to = &plugins_rcpt; break;
91 case 'd': plugins_to = &plugins_data; break;
92 case 'a': plugins_to = &plugins_auth; break;
93 /* ... */
94 default: plugins_to = &plugins_dummy;
95 }
96 else
97 if (!stralloc_catb(plugins_to, sppf.s + i, len)) die_nomem();
98 }
99 }
100
101 return 0;
102}
103
104void sppout() { if (sppmsg.len) out(sppmsg.s); out("\r\n"); }
105
106int spp(plugins, addrenv) stralloc *plugins; char *addrenv;
107{
108 static int pipes[2];
109 static int i, pid, wstat, match, last;
110 static stralloc data = {0};
111 static char *(args[4]);
112 static stralloc *errors_to;
113
114 if (!spprun) return 1;
115 if (addrenv) if (!env_put2(addrenv, addr.s)) die_nomem();
116 last = 0;
117
118 for (i = 0; i < plugins->len; i += str_len(plugins->s + i) + 1) {
119 if (plugins->s[i] == ':')
120 { args[0] = "/bin/sh"; args[1] = "-c"; args[2] = plugins->s + i + 1; args[3] = 0; }
121 else
122 { args[0] = plugins->s + i; args[1] = 0; }
123
124 if (pipe(pipes) == -1)
125 { err_spp(plugins->s + i, "can't pipe()"); return 0; }
126
127 switch (pid = vfork()) {
128 case -1:
129 err_spp(plugins->s + i, "vfork() failed");
130 return 0;
131 case 0:
132 close(0); close(pipes[0]); fd_move(1, pipes[1]);
133 execv(*args, args);
134 _exit(120);
135 }
136
137 close(pipes[1]);
138 substdio_fdbuf(&ssdown, read, pipes[0], downbuf, sizeof(downbuf));
139 do {
140 if (getln(&ssdown, &data, &match, '\n') == -1) die_nomem();
141 if (data.len > 1) {
142 data.s[data.len - 1] = 0;
143 switch (data.s[0]) {
144 case 'H':
145 if (!stralloc_catb(&sppheaders, data.s + 1, data.len - 2)) die_nomem();
146 if (!stralloc_append(&sppheaders, "\n")) die_nomem();
147 break;
148 case 'C':
149 if (addrenv) {
150 if (!stralloc_copyb(&addr, data.s + 1, data.len - 1)) die_nomem();
151 if (!env_put2(addrenv, addr.s)) die_nomem();
152 }
153 break;
154 case 'S': if (!env_put(data.s + 1)) die_nomem(); break;
155 case 'U': if (!env_unset(data.s + 1)) die_nomem(); break;
156 case 'A': spprun = 0;
157 case 'O':
158 case 'N':
159 case 'D': last = 1; match = 0; break;
160 case 'E':
161 case 'R': last = 1; match = 0;
162 case 'P': out(data.s + 1); out("\r\n"); break;
163 case 'L':
164 switch (data.s[1]) {
165 case 'M': errors_to = &error_mail; break;
166 case 'R': errors_to = &error_rcpt; break;
167 case 'D': errors_to = &error_data; break;
168 /* ... */
169 default: errors_to = 0;
170 }
171 if (errors_to) {
172 if (!stralloc_catb(errors_to, data.s + 2, data.len - 3)) die_nomem();
173 if (!stralloc_catb(errors_to, "\r\n", 2)) die_nomem();
174 }
175 break;
176 }
177 }
178 } while (match);
179
180 close(pipes[0]);
181 if (wait_pid(&wstat,pid) == -1) { err_spp(plugins->s + i, "wait_pid() failed"); return 0; }
182 if (wait_crashed(wstat)) { err_spp(plugins->s + i, "child crashed"); return 0; }
183 if (wait_exitcode(wstat) == 120) { err_spp(plugins->s + i, "can't execute"); return 0; }
184
185 if (last)
186 switch (*data.s) {
187 case 'E': return 0;
188 case 'A':
189 case 'N': return 1;
190 case 'O': return 2;
191 case 'R':
192 case 'D': flush(); _exit(0);
193 }
194 }
195
196 return 1;
197}
198
199int spp_errors(errors) stralloc *errors;
200{
201 if (!errors->len) return 1;
202 if (!stralloc_0(errors)) die_nomem();
203 out(errors->s);
204 return 0;
205}
206
207int spp_connect() { return spp(&plugins_connect, 0); }
208
209int spp_helo(arg) char *arg;
210{
211 if (!env_put2("SMTPHELOHOST", arg)) die_nomem();
212 return spp(&plugins_helo, 0);
213}
214
215void spp_rset()
216{
217 if (!stralloc_copys(&sppheaders, "")) die_nomem();
218 if (!stralloc_copys(&error_mail, "")) die_nomem();
219 if (!stralloc_copys(&error_rcpt, "")) die_nomem();
220 if (!stralloc_copys(&error_data, "")) die_nomem();
221 /* ... */
222 rcptcount = rcptcountall = 0;
223}
224
225int spp_mail()
226{
227 if (!spp_errors(&error_mail)) return 0;
228 rcptcount = rcptcountall = 0;
229 return spp(&plugins_mail, "SMTPMAILFROM");
230}
231
232int spp_rcpt(allowed) int allowed;
233{
234 if (!spp_errors(&error_rcpt)) return 0;
235 rcptcountstr[fmt_ulong(rcptcountstr, rcptcount)] = 0;
236 if (!env_put2("SMTPRCPTCOUNT", rcptcountstr)) die_nomem();
237 rcptcountstr[fmt_ulong(rcptcountstr, ++rcptcountall)] = 0;
238 if (!env_put2("SMTPRCPTCOUNTALL", rcptcountstr)) die_nomem();
239 if (!env_put2("SMTPRCPTHOSTSOK", allowed ? "1" : "0")) die_nomem();
240 sppret = spp(&plugins_rcpt, "SMTPRCPTTO");
241 return sppret;
242}
243
244void spp_rcpt_accepted() { rcptcount++; }
245
246int spp_data()
247{
248 if (!spp_errors(&error_data)) return 0;
249 return spp(&plugins_data, 0);
250}
251
252int spp_auth(method, user) char *method, *user;
253{
254 if (!env_put2("SMTPAUTHMETHOD", method)) die_nomem();
255 if (!env_put2("SMTPAUTHUSER", user)) die_nomem();
256 return spp(&plugins_auth, 0);
257}
258
259/* ... */