greylist initializer.
[apps/pfixtools.git] / main-srsd.c
1 /******************************************************************************/
2 /*          pfixtools: a collection of postfix related tools                  */
3 /*          ~~~~~~~~~                                                         */
4 /*  ________________________________________________________________________  */
5 /*                                                                            */
6 /*  Redistribution and use in source and binary forms, with or without        */
7 /*  modification, are permitted provided that the following conditions        */
8 /*  are met:                                                                  */
9 /*                                                                            */
10 /*  1. Redistributions of source code must retain the above copyright         */
11 /*     notice, this list of conditions and the following disclaimer.          */
12 /*  2. Redistributions in binary form must reproduce the above copyright      */
13 /*     notice, this list of conditions and the following disclaimer in the    */
14 /*     documentation and/or other materials provided with the distribution.   */
15 /*  3. The names of its contributors may not be used to endorse or promote    */
16 /*     products derived from this software without specific prior written     */
17 /*     permission.                                                            */
18 /*                                                                            */
19 /*  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND   */
20 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE     */
21 /*  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR        */
22 /*  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS    */
23 /*  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR    */
24 /*  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF      */
25 /*  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  */
26 /*  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN   */
27 /*  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)   */
28 /*  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF    */
29 /*  THE POSSIBILITY OF SUCH DAMAGE.                                           */
30 /******************************************************************************/
31
32 /*
33  * Copyright © 2005-2007 Pierre Habouzit
34  */
35
36 #include "common.h"
37
38 #include <srs2.h>
39
40 #include "epoll.h"
41 #include "mem.h"
42 #include "buffer.h"
43
44 #define DAEMON_NAME             "pfix-srsd"
45 #define DEFAULT_ENCODER_PORT    10000
46 #define DEFAULT_DECODER_PORT    10001
47 #define RUNAS_USER              "nobody"
48 #define RUNAS_GROUP             "nogroup"
49
50 #define __tostr(x)  #x
51 #define STR(x)      __tostr(x)
52
53 /* srs encoder/decoder/listener worker {{{ */
54
55 typedef struct srsd_t {
56     unsigned listener : 1;
57     unsigned decoder  : 1;
58     unsigned watchwr  : 1;
59     int fd;
60     buffer_t ibuf;
61     buffer_t obuf;
62 } srsd_t;
63
64 static srsd_t *srsd_new(void)
65 {
66     srsd_t *srsd = p_new(srsd_t, 1);
67     srsd->fd = -1;
68     return srsd;
69 }
70
71 static void srsd_delete(srsd_t **srsd)
72 {
73     if (*srsd) {
74         if ((*srsd)->fd >= 0)
75             close((*srsd)->fd);
76         buffer_wipe(&(*srsd)->ibuf);
77         buffer_wipe(&(*srsd)->obuf);
78         p_delete(srsd);
79     }
80 }
81
82 void urldecode(char *s, char *end)
83 {
84     char *p = s;
85
86     while (*p) {
87         if (*p == '%' && end - p >= 3) {
88             int h = (hexval(p[1]) << 4) | hexval(p[2]);
89
90             if (h >= 0) {
91                 *s++ = h;
92                 p += 3;
93                 continue;
94             }
95         }
96
97         *s++ = *p++;
98     }
99     *s++ = '\0';
100 }
101
102 int process_srs(srs_t *srs, const char *domain, srsd_t *srsd)
103 {
104     while (srsd->ibuf.len > 4) {
105         char buf[BUFSIZ], *p, *q, *nl;
106         int err;
107
108         nl = strchr(srsd->ibuf.data + 4, '\n');
109         if (!nl) {
110             if (srsd->ibuf.len > BUFSIZ) {
111                 syslog(LOG_ERR, "unreasonnable amount of data without a \\n");
112                 return -1;
113             }
114             return 0;
115         }
116
117         if (strncmp("get ", srsd->ibuf.data, 4)) {
118             syslog(LOG_ERR, "bad request, not starting with \"get \"");
119             return -1;
120         }
121
122         for (p = srsd->ibuf.data + 4; p < nl && isspace(*p); p++);
123         for (q = nl++; q >= p && isspace(*q); *q-- = '\0');
124
125         if (p == q) {
126             buffer_addstr(&srsd->obuf, "400 empty request ???\n");
127             syslog(LOG_WARNING, "empty request");
128             goto skip;
129         }
130
131         urldecode(p, q);
132
133         if (srsd->decoder) {
134             err = srs_reverse(srs, buf, ssizeof(buf), p);
135         } else {
136             err = srs_forward(srs, buf, ssizeof(buf), p, domain);
137         }
138
139         if (err == 0) {
140             buffer_addstr(&srsd->obuf, "200 ");
141             buffer_addstr(&srsd->obuf, buf);
142         } else {
143             switch (SRS_ERROR_TYPE(err)) {
144               case SRS_ERRTYPE_SRS:
145               case SRS_ERRTYPE_SYNTAX:
146                 buffer_addstr(&srsd->obuf, "500 ");
147                 break;
148               default:
149                 buffer_addstr(&srsd->obuf, "400 ");
150                 break;
151             }
152             buffer_addstr(&srsd->obuf, srs_strerror(err));
153         }
154         buffer_addch(&srsd->obuf, '\n');
155
156       skip:
157         buffer_consume(&srsd->ibuf, nl - srsd->ibuf.data);
158     }
159
160     return 0;
161 }
162
163 int start_listener(int port, bool decoder)
164 {
165     struct sockaddr_in addr = {
166         .sin_family = AF_INET,
167         .sin_addr   = { htonl(INADDR_LOOPBACK) },
168     };
169     struct epoll_event evt = { .events = EPOLLIN };
170     srsd_t *tmp;
171     int sock;
172
173     addr.sin_port = htons(port);
174     sock = tcp_listen_nonblock((const struct sockaddr *)&addr, sizeof(addr));
175     if (sock < 0) {
176         return -1;
177     }
178
179     evt.data.ptr  = tmp = srsd_new();
180     tmp->fd       = sock;
181     tmp->decoder  = decoder;
182     tmp->listener = true;
183     if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sock, &evt) < 0) {
184         UNIXERR("epoll_ctl");
185         return -1;
186     }
187     return 0;
188 }
189
190 /* }}} */
191 /* administrivia {{{ */
192
193 static int main_initialize(void)
194 {
195     openlog(DAEMON_NAME, LOG_PID, LOG_MAIL);
196     signal(SIGPIPE, SIG_IGN);
197     signal(SIGINT,  &common_sighandler);
198     signal(SIGTERM, &common_sighandler);
199     signal(SIGHUP,  &common_sighandler);
200     signal(SIGSEGV, &common_sighandler);
201     syslog(LOG_INFO, "Starting...");
202     return 0;
203 }
204
205 static void main_shutdown(void)
206 {
207     closelog();
208 }
209
210 module_init(main_initialize);
211 module_exit(main_shutdown);
212
213 void usage(void)
214 {
215     fputs("usage: "DAEMON_NAME" [options] domain secrets\n"
216           "\n"
217           "Options:\n"
218           "    -e <port>    port to listen to for encoding requests\n"
219           "                 (default: "STR(DEFAULT_ENCODER_PORT)")\n"
220           "    -d <port>    port to listen to for decoding requests\n"
221           "                 (default: "STR(DEFAULT_DECODER_PORT)")\n"
222           "    -p <pidfile> file to write our pid to\n"
223           "    -u           unsafe mode: don't drop privilegies\n"
224          , stderr);
225 }
226
227 /* }}} */
228
229 int main_loop(srs_t *srs, const char *domain, int port_enc, int port_dec)
230 {
231     if (start_listener(port_enc, false) < 0)
232         return EXIT_FAILURE;
233     if (start_listener(port_dec, true) < 0)
234         return EXIT_FAILURE;
235
236     while (!sigint) {
237         struct epoll_event evts[1024];
238         int n;
239
240         n = epoll_wait(epollfd, evts, countof(evts), -1);
241         if (n < 0) {
242             if (errno != EAGAIN && errno != EINTR) {
243                 UNIXERR("epoll_wait");
244                 return EXIT_FAILURE;
245             }
246             continue;
247         }
248
249         while (--n >= 0) {
250             srsd_t *srsd = evts[n].data.ptr;
251
252             if (srsd->listener) {
253                 struct epoll_event evt = { .events = EPOLLIN };
254                 srsd_t *tmp;
255                 int sock;
256
257                 sock = accept_nonblock(srsd->fd);
258                 if (sock < 0) {
259                     UNIXERR("accept");
260                     continue;
261                 }
262
263                 evt.data.ptr = tmp = srsd_new();
264                 tmp->decoder = srsd->decoder;
265                 tmp->fd      = sock;
266                 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sock, &evt) < 0) {
267                     UNIXERR("epoll_ctl");
268                     srsd_delete(&tmp);
269                     close(sock);
270                 }
271                 continue;
272             }
273
274             if (evts[n].events & EPOLLIN) {
275                 int res = buffer_read(&srsd->ibuf, srsd->fd, -1);
276
277                 if ((res < 0 && errno != EINTR && errno != EAGAIN)
278                 ||  res == 0)
279                 {
280                     srsd_delete(&srsd);
281                     continue;
282                 }
283
284                 if (process_srs(srs, domain, srsd) < 0) {
285                     srsd_delete(&srsd);
286                     continue;
287                 }
288             }
289
290             if ((evts[n].events & EPOLLOUT) && srsd->obuf.len) {
291                 int res = write(srsd->fd, srsd->obuf.data, srsd->obuf.len);
292
293                 if (res < 0 && errno != EINTR && errno != EAGAIN) {
294                     srsd_delete(&srsd);
295                     continue;
296                 }
297
298                 if (res > 0) {
299                     buffer_consume(&srsd->obuf, res);
300                 }
301             }
302
303             if (srsd->watchwr == !srsd->obuf.len) {
304                 struct epoll_event evt = {
305                     .events   = EPOLLIN | (srsd->obuf.len ? EPOLLOUT : 0),
306                     .data.ptr = srsd,
307                 };
308                 if (epoll_ctl(epollfd, EPOLL_CTL_MOD, srsd->fd, &evt) < 0) {
309                     UNIXERR("epoll_ctl");
310                     srsd_delete(&srsd);
311                     continue;
312                 }
313                 srsd->watchwr = srsd->obuf.len != 0;
314             }
315         }
316     }
317
318     return EXIT_SUCCESS;
319 }
320
321 static srs_t *srs_read_secrets(const char *sfile)
322 {
323     srs_t *srs;
324     char buf[BUFSIZ];
325     FILE *f;
326     int lineno = 0;
327
328     f = fopen(sfile, "r");
329     if (!f) {
330         UNIXERR("fopen");
331         return NULL;
332     }
333
334     srs = srs_new();
335
336     while (fgets(buf, sizeof(buf), f)) {
337         int n = strlen(buf);
338
339         ++lineno;
340         if (n == sizeof(buf) - 1 && buf[n - 1] != '\n') {
341             syslog(LOG_CRIT, "%s:%d: line too long", sfile, lineno);
342             goto error;
343         }
344         m_strrtrim(buf);
345         srs_add_secret(srs, skipspaces(buf));
346     }
347
348     if (!lineno) {
349         syslog(LOG_CRIT, "%s: empty file, no secrets", sfile);
350         goto error;
351     }
352
353     fclose(f);
354     return srs;
355
356   error:
357     fclose(f);
358     srs_free(srs);
359     return NULL;
360 }
361
362 int main(int argc, char *argv[])
363 {
364     bool unsafe  = false;
365     int port_enc = DEFAULT_ENCODER_PORT;
366     int port_dec = DEFAULT_DECODER_PORT;
367     const char *pidfile = NULL;
368
369     int res;
370     srs_t *srs;
371
372     for (int c = 0; (c = getopt(argc, argv, "hu" "e:d:p:")) >= 0; ) {
373         switch (c) {
374           case 'e':
375             port_enc = atoi(optarg);
376             break;
377           case 'd':
378             port_dec = atoi(optarg);
379             break;
380           case 'p':
381             pidfile = optarg;
382             break;
383           case 'u':
384             unsafe = true;
385             break;
386           default:
387             usage();
388             return EXIT_FAILURE;
389         }
390     }
391
392     if (argc - optind != 2) {
393         usage();
394         return EXIT_FAILURE;
395     }
396
397     srs = srs_read_secrets(argv[optind + 1]);
398     if (!srs) {
399         return EXIT_FAILURE;
400     }
401
402     if (pidfile_open(pidfile) < 0) {
403         syslog(LOG_CRIT, "unable to write pidfile %s", pidfile);
404         return EXIT_FAILURE;
405     }
406
407     if (!unsafe && drop_privileges(RUNAS_USER, RUNAS_GROUP) < 0) {
408         syslog(LOG_CRIT, "unable to drop privileges");
409         return EXIT_FAILURE;
410     }
411
412     if (daemon_detach() < 0) {
413         syslog(LOG_CRIT, "unable to fork");
414         return EXIT_FAILURE;
415     }
416
417     pidfile_refresh();
418     res = main_loop(srs, argv[optind], port_enc, port_dec);
419     syslog(LOG_INFO, "Stopping...");
420     return res;
421 }