s/qmail 4.3.20
Next generation secure email transport
Loading...
Searching...
No Matches
qmail-popup.c
Go to the documentation of this file.
1#include <unistd.h>
2#include "commands.h"
3#include "fd.h"
4#include "sig.h"
5#include "stralloc.h"
6#include "buffer.h"
7#include "alloc.h"
8#include "wait.h"
9#include "str.h"
10#include "byte.h"
11#include "now.h"
12#include "fmt.h"
13#include "case.h"
14#include "exit.h"
15#include "timeout.h"
16#include "env.h"
17#include "tls_start.h"
18#include "ip.h"
19#include "qmail.h"
20
21#define PORT_POP3S "995" // string
22#define FDIN 0
23#define FDOUT 1
24#define FDAUTH 3
25#define FDLOG 5
26#define POP3_TIMEOUT 1200
27
28static void done() { _exit(0); }
29
30static ssize_t saferead(int fd,char *buf,int len)
31{
32 int r;
33 r = timeoutread(POP3_TIMEOUT,fd,buf,len);
34 if (r <= 0) done();
35 return r;
36}
37
38static ssize_t safewrite(int fd,char *buf,int len)
39{
40 int r;
41 r = timeoutwrite(POP3_TIMEOUT,fd,buf,len);
42 if (r <= 0) done();
43 return r;
44}
45
47buffer bi = BUFFER_INIT(saferead,FDIN,inbuf,sizeof(inbuf));
48
50buffer bo = BUFFER_INIT(safewrite,FDOUT,outbuf,sizeof(outbuf));
51
52static void outs(char *s)
53{
54 buffer_puts(&bo,s);
55}
56static void flush()
57{
58 buffer_flush(&bo);
59}
60static void err(char *s)
61{
62 outs("-ERR ");
63 outs(s);
64 outs("\r\n");
65 flush();
66}
67
68/* Logging */
69
70stralloc protocol = {0};
71stralloc auth = {0};
75
76char strnum[FMT_ULONG];
78buffer bl = BUFFER_INIT(safewrite,FDLOG,logbuf,sizeof(logbuf));
79
80static void logs(char *s) { if (buffer_puts(&bl,s) == -1) _exit(1); }
81static void logp(char *s) { logs(" P:"); logs(s); }
82static void logh(char *s1, char *s2) { logs(" S:"); logs(s1); logs(":"); logs(s2); }
83static void logu(char *s) { logs(" ?~ '"); logs(s); logs("'"); }
84static void logn(char *s) { if (buffer_puts(&bl,s) == -1) _exit(1); if (buffer_flush(&bl) == -1) _exit(1); }
85static void logpid() { strnum[fmt_ulong(strnum,getpid())] = 0; logs("qmail-popup: pid "); logs(strnum); logs(" "); }
86static void log_pop(char *s1,char *s2,char *s3,char *s4,char *s5,char *s6)
87 { logpid(); logs(s1); logs(s2); logp(s3); logh(s4,s5), logu(s6), logn("\n"); }
88
89static void die_usage() { err("usage: popup hostname subprogram"); done(); }
90static void die_nomem() { err("out of memory"); done(); }
91static void die_pipe() { err("unable to open pipe"); done(); }
92static void die_write() { err("unable to write pipe"); done(); }
93static void die_fork() { err("unable to fork"); done(); }
94static void die_childcrashed() { err("aack, child crashed"); }
95static void die_badauth() { err("authorization failed"); }
96static void die_tls() { err("TLS startup failed"); done(); }
97static void die_notls() {
98 err("TLS required but not negotiated");
99 log_pop("Reject::STLS::","Any","POP3",remoteip,remotehost,"unknown");
100 done();
101}
102
103static void err_syntax() { err("syntax error"); }
104static void err_wantuser() { err("USER first"); }
105static void err_authoriz() { err("authorization first"); }
106
107static void okay() { outs("+OK \r\n"); flush(); }
108static void pop3_quit() { okay(); done(); }
109
110static void poplog_init()
111{
112 if (!stralloc_copys(&protocol,"POP3")) die_nomem();
113 localport = env_get("TCP6LOCALPORT");
114 if (!localport) localport = env_get("TCPLOCALPORT");
115 if (!localport) localport = "unknown";
116 if (!case_diffs(localport,PORT_POP3S))
117 if (!stralloc_cats(&protocol,"S")) die_nomem();
118 remoteip = env_get("TCP6REMOTEIP");
119 if (remoteip && byte_equal(remoteip,7,V4MAPPREFIX)) remoteip = remoteip + 7;
120 if (!remoteip) remoteip = env_get("TCPREMOTEIP");
121 if (!remoteip) remoteip = "unknown";
122 remotehost = env_get("TCP6REMOTEHOST");
123 if (!remotehost) remotehost = env_get("TCPREMOTEHOST");
124 if (!remotehost) remotehost = "unknown";
125}
126
127char unique[FMT_ULONG + FMT_ULONG + 3];
129stralloc username = {0};
130int seenuser = 0;
133buffer ba;
134int stls = 0;
135int seenstls = 0;
136int apop = 0;
137
138static void doanddone(char *user,unsigned int userlen,char *pass) /* userlen: including 0 byte */
139{
140 int child;
141 int wstat;
142 int pi[2];
143
144 if (fd_copy(2,1) == -1) die_pipe();
145 close(FDAUTH);
146 if (pipe(pi) == -1) die_pipe();
147 if (pi[0] != FDAUTH) die_pipe();
148 switch (child = fork()) {
149 case -1:
150 die_fork();
151 case 0:
152 close(pi[1]);
153 sig_pipedefault();
154 execvp(*childargs,childargs);
155 _exit(1);
156 }
157 close(pi[0]);
158 buffer_init(&ba,write,pi[1],authbuf,sizeof(authbuf));
159 if (buffer_put(&ba,user,userlen) == -1) die_write();
160 if (buffer_put(&ba,pass,str_len(pass) + 1) == -1) die_write();
161 if (buffer_puts(&ba,"<") == -1) die_write();
162 if (buffer_puts(&ba,unique) == -1) die_write();
163 if (buffer_puts(&ba,hostname) == -1) die_write();
164 if (buffer_put(&ba,">",2) == -1) die_write();
165 if (buffer_flush(&ba) == -1) die_write();
166 close(pi[1]);
167 byte_zero(pass,str_len(pass));
168 byte_zero(authbuf,sizeof(authbuf));
169 if (wait_pid(&wstat,child) == -1) done();
170 if (wait_crashed(wstat)) die_childcrashed();
171 if (!stralloc_0(&auth)) die_nomem();
172 if (!stralloc_0(&protocol)) die_nomem();
173 if (wait_exitcode(wstat)) {
174 die_badauth();
175 log_pop("Reject::AUTH::",auth.s,protocol.s,remoteip,remotehost,user);
176 }
177 else
178 log_pop("Accept::AUTH::",auth.s,protocol.s,remoteip,remotehost,user);
179 done();
180}
181
182static void pop3_greet()
183{
184 char *s;
185 s = unique;
186 s += fmt_uint(s,getpid());
187 *s++ = '.';
188 s += fmt_ulong(s,(unsigned long) now());
189 *s++ = '@';
190 *s++ = 0;
191
192 if (!apop)
193 outs("+OK\r\n");
194 else {
195 outs("+OK <");
196 outs(unique);
197 outs(hostname);
198 outs(">\r\n");
199 }
200 flush();
201}
202
203static void pop3_user(char *arg)
204{
205 if (stls == 2 && !seenstls) die_notls();
206 if (!*arg) { err_syntax(); return; }
207 okay();
208 seenuser = 1;
209 if (!stralloc_copys(&username,arg)) die_nomem();
210 if (!stralloc_0(&username)) die_nomem();
211}
212
213static void pop3_pass(char *arg)
214{
215 if (!seenuser) { err_wantuser(); return; }
216 if (!*arg) { err_syntax(); return; }
217 if (!stralloc_copys(&auth,"User")) die_nomem();
218 doanddone(username.s,username.len,arg);
219}
220
221static void pop3_apop(char *arg)
222{
223 char *space;
224
225 if (stls == 2 && !seenstls) die_notls();
226 space = arg + str_chr(arg,' ');
227 if (!*space) { err_syntax(); return; }
228 *space++ = 0;
229 if (!stralloc_copys(&auth,"Apop")) die_nomem();
230 doanddone(arg,space - arg,space);
231}
232
233static void pop3_capa(char *arg)
234{
235 outs("+OK capability list follows\r\n");
236 outs("TOP\r\n");
237 outs("USER\r\n");
238 outs("UIDL\r\n");
239 if (apop)
240 outs("APOP\r\n");
241 if (stls > 0)
242 outs("STLS\r\n");
243 outs(".\r\n");
244 flush();
245}
246
247static void pop3_stls(char *arg)
248{
249 if (stls == 0 || seenstls == 1)
250 return err("STLS not available");
251 outs("+OK starting TLS negotiation\r\n");
252 flush();
253
254 if (!starttls_init()) die_tls();
255 buffer_init(&bi,saferead,FDIN,inbuf,sizeof(inbuf));
256 seenstls = 1;
257
258/* reset state */
259 seenuser = 0;
260 if (!stralloc_cats(&protocol,"S")) die_nomem();
261}
262
264 { "user", pop3_user, 0 }
265, { "pass", pop3_pass, 0 }
266, { "apop", pop3_apop, 0 }
267, { "quit", pop3_quit, 0 }
268, { "capa", pop3_capa, 0 }
269, { "stls", pop3_stls, 0 }
270, { "noop", okay, 0 }
271, { 0, err_authoriz, 0 }
272};
273
274int main(int argc,char * const *argv)
275{
276 char *pop3auth;
277 char *ucspitls;
278
279 sig_alarmcatch(done);
280 sig_pipeignore();
281
282 hostname = argv[1];
283 if (!hostname) die_usage();
284 childargs = argv + 2;
285 if (!*childargs) die_usage();
286
287 ucspitls = env_get("UCSPITLS");
288 if (ucspitls) {
289 stls = 1;
290 if (!case_diffs(ucspitls,"-")) stls = 0;
291 if (!case_diffs(ucspitls,"!")) stls = 2;
292 }
293
294 pop3auth = env_get("POP3AUTH");
295 if (pop3auth) {
296 if (case_starts(pop3auth,"apop")) apop = 2;
297 if (case_starts(pop3auth,"+apop")) apop = 1;
298 }
299 poplog_init();
300 pop3_greet();
302 done();
303}
void outs(char *s)
Definition: auto-gid.c:12
int main()
Definition: chkshsgr.c:6
void die_write()
Definition: columnt.c:17
int stralloc_copys(stralloc *, char const *)
void _exit(int)
strset done
Definition: fastforward.c:75
char buf[100+FMT_ULONG]
Definition: hier.c:11
datetime_sec now()
Definition: now.c:5
stralloc user
int fd
buffer ba
Definition: qmail-popup.c:133
int seenuser
Definition: qmail-popup.c:130
char authbuf[BUFSIZE_AUTH]
Definition: qmail-popup.c:132
char strnum[FMT_ULONG]
Definition: qmail-popup.c:76
char ** childargs
Definition: qmail-popup.c:131
char outbuf[BUFSIZE_AUTH]
Definition: qmail-popup.c:49
stralloc protocol
Definition: qmail-popup.c:70
char * remoteip
Definition: qmail-popup.c:73
buffer bl
Definition: qmail-popup.c:78
#define FDAUTH
Definition: qmail-popup.c:24
stralloc username
Definition: qmail-popup.c:129
char unique[FMT_ULONG+FMT_ULONG+3]
Definition: qmail-popup.c:127
char * localport
Definition: qmail-popup.c:72
buffer bi
Definition: qmail-popup.c:47
int apop
Definition: qmail-popup.c:136
int stls
Definition: qmail-popup.c:134
#define FDOUT
Definition: qmail-popup.c:23
#define PORT_POP3S
Definition: qmail-popup.c:21
int seenstls
Definition: qmail-popup.c:135
char * remotehost
Definition: qmail-popup.c:74
stralloc auth
Definition: qmail-popup.c:71
#define FDLOG
Definition: qmail-popup.c:25
#define FDIN
Definition: qmail-popup.c:22
buffer bo
Definition: qmail-popup.c:50
char * hostname
Definition: qmail-popup.c:128
struct commands pop3commands[]
Definition: qmail-popup.c:263
char inbuf[BUFSIZE_AUTH]
Definition: qmail-popup.c:46
#define POP3_TIMEOUT
Definition: qmail-popup.c:26
char logbuf[BUFSIZE_LOG]
Definition: qmail-popup.c:77
char * ucspitls
Definition: qmail-qmtpd.c:101
stralloc pass
Definition: qmail-remote.c:676
#define BUFSIZE_LOG
Definition: qmail.h:11
#define BUFSIZE_AUTH
Definition: qmail.h:9
ssize_t safewrite(int, char *, int)
Definition: qmail-qmqpc.c:49
void flush(void)
Definition: qmail-smtpd.c:91
void err_syntax(void)
Definition: smtpdlog.c:73
void die_nomem(void)
Definition: qreceipt.c:23
void die_tls()
Definition: smtpdlog.c:69
int starttls_init(void)
Definition: tls_start.c:14
void write()