/* products derived from this software without specific prior written */
/* permission. */
/* */
-/* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND */
-/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE */
-/* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
-/* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS */
-/* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR */
-/* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF */
-/* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS */
-/* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN */
-/* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */
-/* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF */
-/* THE POSSIBILITY OF SUCH DAMAGE. */
+/* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS */
+/* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
+/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
+/* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY */
+/* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */
+/* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS */
+/* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) */
+/* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, */
+/* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN */
+/* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */
+/* POSSIBILITY OF SUCH DAMAGE. */
+/* */
+/* Copyright (c) 2006-2008 the Authors */
+/* see AUTHORS and source files for details */
/******************************************************************************/
/*
#include <srs2.h>
-#include "epoll.h"
#include "mem.h"
#include "buffer.h"
#include "server.h"
#define DAEMON_NAME "pfix-srsd"
-#define DAEMON_VERSION "0.1"
+#define DAEMON_VERSION "0.5"
#define DEFAULT_ENCODER_PORT 10001
#define DEFAULT_DECODER_PORT 10002
#define RUNAS_USER "nobody"
typedef struct srs_config_t {
srs_t* srs;
const char* domain;
+ int domainlen;
+ int ignore_ext;
} srs_config_t;
/* Server {{{1
*/
-static const char* const decoder_ptr = "decoder";
-static const char* const encoder_ptr = "encoder";
+static listener_t *decoder_ptr = NULL;
+static listener_t *encoder_ptr = NULL;
-static void *srsd_new_decoder(void)
+static void *srsd_starter(listener_t *server)
{
- return (void*)decoder_ptr;
-}
-
-static void *srsd_new_encoder(void)
-{
- return (void*)encoder_ptr;
-}
-
-static void *srsd_starter(server_t *server)
-{
- return server->data;
-}
-
-int start_listener(int port, bool decoder)
-{
- return start_server(port, decoder ? srsd_new_decoder : srsd_new_encoder, NULL);
+ return server;
}
/* Processing {{{1
*/
-void urldecode(char *s, char *end)
+char *urldecode(char *s, char *end)
{
char *p = s;
*s++ = *p++;
}
- *s++ = '\0';
+ *s = '\0';
+ return s;
}
-int process_srs(server_t *srsd, void* vconfig)
+int process_srs(client_t *srsd, void* vconfig)
{
srs_config_t* config = vconfig;
- int res = buffer_read(&srsd->ibuf, srsd->fd, -1);
+ buffer_t *ibuf = client_input_buffer(srsd);
+ buffer_t *obuf = client_output_buffer(srsd);
+ bool decoder = (client_data(srsd) == decoder_ptr);
+ int res = client_read(srsd);
if ((res < 0 && errno != EINTR && errno != EAGAIN) || res == 0)
return -1;
- while (srsd->ibuf.len > 4) {
+ while (ibuf->len > 4) {
char buf[BUFSIZ], *p, *q, *nl;
int err;
- nl = strchr(srsd->ibuf.data + 4, '\n');
+ nl = strchr(ibuf->data + 4, '\n');
if (!nl) {
- if (srsd->ibuf.len > BUFSIZ) {
+ if (ibuf->len > BUFSIZ) {
err("unreasonnable amount of data without a \\n");
return -1;
}
- if (srsd->obuf.len) {
- epoll_modify(srsd->fd, EPOLLIN | EPOLLOUT, srsd);
+ if (obuf->len) {
+ client_io_rw(srsd);
}
return 0;
}
- if (strncmp("get ", srsd->ibuf.data, 4)) {
- err("bad request, not starting with \"get \"");
+ if (strncmp("get ", ibuf->data, 4)) {
+ err("bad request, not starting with \"get \"");
return -1;
}
- for (p = srsd->ibuf.data + 4; p < nl && isspace(*p); p++);
+ for (p = ibuf->data + 4; p < nl && isspace(*p); p++);
for (q = nl++; q >= p && isspace(*q); *q-- = '\0');
if (p == q) {
- buffer_addstr(&srsd->obuf, "400 empty request ???\n");
+ buffer_addstr(obuf, "400 empty request ???\n");
warn("empty request");
goto skip;
}
- urldecode(p, q);
+ q = urldecode(p, q);
- if (srsd->data == (void*)decoder_ptr) {
+ if (decoder) {
+ if (config->ignore_ext) {
+ int dlen = config->domainlen;
+
+ if (q - p <= dlen || q[-1 - dlen] != '@' ||
+ memcmp(q - dlen, config->domain, dlen))
+ {
+ buffer_addstr(obuf, "200 ");
+ buffer_add(obuf, p, q - p);
+ buffer_addch(obuf, '\n');
+ goto skip;
+ }
+ }
err = srs_reverse(config->srs, buf, ssizeof(buf), p);
} else {
err = srs_forward(config->srs, buf, ssizeof(buf), p, config->domain);
}
if (err == 0) {
- buffer_addstr(&srsd->obuf, "200 ");
- buffer_addstr(&srsd->obuf, buf);
+ buffer_addstr(obuf, "200 ");
+ buffer_addstr(obuf, buf);
} else {
switch (SRS_ERROR_TYPE(err)) {
case SRS_ERRTYPE_SRS:
case SRS_ERRTYPE_SYNTAX:
- buffer_addstr(&srsd->obuf, "500 ");
+ buffer_addstr(obuf, "500 ");
break;
default:
- buffer_addstr(&srsd->obuf, "400 ");
+ buffer_addstr(obuf, "400 ");
break;
}
- buffer_addstr(&srsd->obuf, srs_strerror(err));
+ buffer_addstr(obuf, srs_strerror(err));
}
- buffer_addch(&srsd->obuf, '\n');
+ buffer_addch(obuf, '\n');
skip:
- buffer_consume(&srsd->ibuf, nl - srsd->ibuf.data);
+ buffer_consume(ibuf, nl - ibuf->data);
}
- if (srsd->obuf.len) {
- epoll_modify(srsd->fd, EPOLLIN | EPOLLOUT, srsd);
+ if (obuf->len) {
+ client_io_rw(srsd);
}
return 0;
}
" (default: "STR(DEFAULT_DECODER_PORT)")\n"
" -p <pidfile> file to write our pid to\n"
" -u unsafe mode: don't drop privilegies\n"
+ " -I do not touch mails outside of \"domain\" in decoding mode\n"
" -f stay in foreground\n"
, stderr);
}
int port_dec = DEFAULT_DECODER_PORT;
const char *pidfile = NULL;
- for (int c = 0; (c = getopt(argc, argv, "hfu" "e:d:p:")) >= 0; ) {
+ for (int c = 0; (c = getopt(argc, argv, "hfuI" "e:d:p:")) >= 0; ) {
switch (c) {
case 'e':
port_enc = atoi(optarg);
case 'u':
unsafe = true;
break;
+ case 'I':
+ config.ignore_ext = true;
+ break;
default:
usage();
return EXIT_FAILURE;
return EXIT_FAILURE;
}
- info("starting %s v%s...", DAEMON_NAME, DAEMON_VERSION);
+ info("%s v%s...", DAEMON_NAME, DAEMON_VERSION);
config.domain = argv[optind];
+ config.domainlen = strlen(config.domain);
config.srs = srs_read_secrets(argv[optind + 1]);
if (!config.srs
|| common_setup(pidfile, unsafe, RUNAS_USER, RUNAS_GROUP,
daemonize) != EXIT_SUCCESS
- || start_listener(port_enc, false) < 0
- || start_listener(port_dec, true) < 0) {
+ || (encoder_ptr = start_listener(port_enc)) == NULL
+ || (decoder_ptr = start_listener(port_dec)) == NULL) {
return EXIT_FAILURE;
}
return server_loop(srsd_starter, NULL, process_srs, NULL, &config);