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