rawlog.c revision d4545f88331bb06244505cef10e96174c5c19ed4
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include "lib.h"
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "ioloop.h"
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include "fd-set-nonblock.h"
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include "network.h"
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include "str.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "write-full.h"
dce5a2719df4fc64a8762d2aa94ba98dcf9cd6feTimo Sirainen#include "istream.h"
e54512a5189192fe72d1e2c53927c98c5ac920b4Timo Sirainen#include "ostream.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "process-title.h"
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include "restrict-access.h"
645f258ea29afaf09b673fc65d1bd788dfec8db8Timo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include <stdlib.h>
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include <unistd.h>
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen#include <fcntl.h>
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen#include <sys/stat.h>
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen#include <sys/socket.h>
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen#define OUTBUF_THRESHOLD IO_BLOCK_SIZE
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainenstatic struct ioloop *ioloop;
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainenenum rawlog_flags {
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen RAWLOG_FLAG_LOG_INPUT = 0x01,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen RAWLOG_FLAG_LOG_OUTPUT = 0x02,
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen RAWLOG_FLAG_LOG_TIMESTAMPS = 0x04,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen RAWLOG_FLAG_LOG_BOUNDARIES = 0X10
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen};
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainenstruct rawlog_proxy {
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen int client_in_fd, client_out_fd, server_fd;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct io *client_io, *server_io;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen struct ostream *client_output, *server_output;
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen int fd_in, fd_out;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen enum rawlog_flags flags;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen bool prev_lf_in, prev_lf_out;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen};
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainenstatic void rawlog_proxy_destroy(struct rawlog_proxy *proxy)
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen{
8fb1e3e2349c9940732b5bb77a2a4053b8f72a4fTimo Sirainen if (proxy->fd_in != -1) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (close(proxy->fd_in) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_error("close(in) failed: %m");
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (proxy->fd_out != -1) {
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen if (close(proxy->fd_out) < 0)
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen i_error("close(out) failed: %m");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen if (proxy->client_io != NULL)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen io_remove(&proxy->client_io);
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen if (proxy->server_io != NULL)
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen io_remove(&proxy->server_io);
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen o_stream_destroy(&proxy->client_output);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen o_stream_destroy(&proxy->server_output);
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen if (close(proxy->client_in_fd) < 0)
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen i_error("close(client_in_fd) failed: %m");
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen if (close(proxy->client_out_fd) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_error("close(client_out_fd) failed: %m");
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen if (close(proxy->server_fd) < 0)
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen i_error("close(server_fd) failed: %m");
5cda0bfea032000c4a51134c748d9efe6614870bTimo Sirainen i_free(proxy);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen io_loop_stop(ioloop);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainenstatic int
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainenwrite_with_timestamps(int fd, bool *prev_lf,
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen const unsigned char *data, size_t size)
8b12e7b44abca3bd51a1c46e19ca504f3b55e723Timo Sirainen{
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen int ret;
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen T_BEGIN {
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen const char *timestamp = t_strdup_printf("%ld.%06lu ",
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen (long)ioloop_timeval.tv_sec,
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen (unsigned long)ioloop_timeval.tv_usec);
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen string_t *str = t_str_new(size + 128);
8b12e7b44abca3bd51a1c46e19ca504f3b55e723Timo Sirainen size_t i;
8b12e7b44abca3bd51a1c46e19ca504f3b55e723Timo Sirainen
8b12e7b44abca3bd51a1c46e19ca504f3b55e723Timo Sirainen if (*prev_lf)
8b12e7b44abca3bd51a1c46e19ca504f3b55e723Timo Sirainen str_append(str, timestamp);
8b12e7b44abca3bd51a1c46e19ca504f3b55e723Timo Sirainen
8b12e7b44abca3bd51a1c46e19ca504f3b55e723Timo Sirainen for (i = 0; i < size; i++) {
872b8fd8a8db97dc54067b7ab25bda96ec0aac0dTimo Sirainen str_append_c(str, data[i]);
872b8fd8a8db97dc54067b7ab25bda96ec0aac0dTimo Sirainen if (data[i] == '\n' && i+1 != size)
872b8fd8a8db97dc54067b7ab25bda96ec0aac0dTimo Sirainen str_append(str, timestamp);
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen }
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen *prev_lf = data[i-1] == '\n';
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ret = write_full(fd, str_data(str), str_len(str));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } T_END;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return ret;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainenstatic int proxy_write_data(struct rawlog_proxy *proxy, int fd,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen bool *prev_lf, const void *data, size_t size)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen if (fd == -1 || size == 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 0;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if ((proxy->flags & RAWLOG_FLAG_LOG_BOUNDARIES) != 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (write_full(fd, "<<<\n", 4) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return -1;
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if ((proxy->flags & RAWLOG_FLAG_LOG_TIMESTAMPS) != 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (write_with_timestamps(fd, prev_lf, data, size) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } else {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (write_full(fd, data, size) < 0)
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen return -1;
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if ((proxy->flags & RAWLOG_FLAG_LOG_BOUNDARIES) != 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (write_full(fd, ">>>\n", 4) < 0)
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen return -1;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 0;
5cda0bfea032000c4a51134c748d9efe6614870bTimo Sirainen}
5cda0bfea032000c4a51134c748d9efe6614870bTimo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainenstatic void proxy_write_in(struct rawlog_proxy *proxy,
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen const void *data, size_t size)
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen{
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen if (proxy_write_data(proxy, proxy->fd_in, &proxy->prev_lf_in,
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen data, size) < 0) {
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen /* failed, disable logging */
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen i_error("write(in) failed: %m");
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen (void)close(proxy->fd_in);
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen proxy->fd_in = -1;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen }
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen}
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainenstatic void proxy_write_out(struct rawlog_proxy *proxy,
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen const void *data, size_t size)
70612e07102b75a8511aa7f9de60771176b18de0Timo Sirainen{
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen if (proxy_write_data(proxy, proxy->fd_out, &proxy->prev_lf_out,
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen data, size) < 0) {
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen /* failed, disable logging */
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen i_error("write(out) failed: %m");
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen (void)close(proxy->fd_out);
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen proxy->fd_out = -1;
5df33e9ee65eec194105b338c55dedbf8422f695Timo Sirainen }
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen}
5df33e9ee65eec194105b338c55dedbf8422f695Timo Sirainen
5df33e9ee65eec194105b338c55dedbf8422f695Timo Sirainenstatic void server_input(struct rawlog_proxy *proxy)
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen{
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen unsigned char buf[OUTBUF_THRESHOLD];
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen ssize_t ret;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen if (o_stream_get_buffer_used_size(proxy->client_output) >
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen OUTBUF_THRESHOLD) {
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen /* client's output buffer is already quite full.
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen don't send more until we're below threshold. */
77af0bd168cf3e3ddc3ae68abc82bfad7e9b5ff4Timo Sirainen io_remove(&proxy->server_io);
77af0bd168cf3e3ddc3ae68abc82bfad7e9b5ff4Timo Sirainen return;
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen }
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen ret = net_receive(proxy->server_fd, buf, sizeof(buf));
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (ret > 0) {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen (void)o_stream_send(proxy->client_output, buf, ret);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen proxy_write_out(proxy, buf, ret);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen } else if (ret <= 0)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen rawlog_proxy_destroy(proxy);
77af0bd168cf3e3ddc3ae68abc82bfad7e9b5ff4Timo Sirainen}
77af0bd168cf3e3ddc3ae68abc82bfad7e9b5ff4Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenstatic void client_input(struct rawlog_proxy *proxy)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen{
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen unsigned char buf[OUTBUF_THRESHOLD];
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen ssize_t ret;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (o_stream_get_buffer_used_size(proxy->server_output) >
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen OUTBUF_THRESHOLD) {
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen /* proxy's output buffer is already quite full.
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen don't send more until we're below threshold. */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen io_remove(&proxy->client_io);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen ret = net_receive(proxy->client_in_fd, buf, sizeof(buf));
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (ret > 0) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen (void)o_stream_send(proxy->server_output, buf, ret);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen proxy_write_in(proxy, buf, ret);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen } else if (ret < 0)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen rawlog_proxy_destroy(proxy);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen}
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic int server_output(struct rawlog_proxy *proxy)
a4f09749814b93e8ad3ec8a0dc18885b874d6f8cTimo Sirainen{
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen if (o_stream_flush(proxy->server_output) < 0) {
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen rawlog_proxy_destroy(proxy);
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen return 1;
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen if (proxy->client_io == NULL &&
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen o_stream_get_buffer_used_size(proxy->server_output) <
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen OUTBUF_THRESHOLD) {
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen /* there's again space in proxy's output buffer, so we can
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen read more from client. */
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen proxy->client_io = io_add(proxy->client_in_fd, IO_READ,
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen client_input, proxy);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 1;
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen}
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainenstatic int client_output(struct rawlog_proxy *proxy)
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen{
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen if (o_stream_flush(proxy->client_output) < 0) {
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen rawlog_proxy_destroy(proxy);
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen return 1;
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen }
1952eb389b8aba39195380970f905dcebea38dfcTimo Sirainen
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen if (proxy->server_io == NULL &&
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen o_stream_get_buffer_used_size(proxy->client_output) <
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen OUTBUF_THRESHOLD) {
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen /* there's again space in client's output buffer, so we can
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen read more from proxy. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen proxy->server_io =
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen io_add(proxy->server_fd, IO_READ, server_input, proxy);
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return 1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainenstatic void proxy_open_logs(struct rawlog_proxy *proxy, const char *path)
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen time_t now;
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen struct tm *tm;
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen const char *fname;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen char timestamp[50];
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen now = time(NULL);
45b2a27617d8475f71fdfc870690e46cd63849f2Timo Sirainen tm = localtime(&now);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen if (strftime(timestamp, sizeof(timestamp), "%Y%m%d-%H%M%S", tm) <= 0)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen i_fatal("strftime() failed");
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen if ((proxy->flags & RAWLOG_FLAG_LOG_INPUT) != 0) {
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen fname = t_strdup_printf("%s/%s-%s.in", path, timestamp,
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen dec2str(getpid()));
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen proxy->fd_in = open(fname, O_CREAT|O_EXCL|O_WRONLY, 0600);
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen if (proxy->fd_in == -1) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen i_error("rawlog_open: open() failed for %s: %m", fname);
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen return;
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen }
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen }
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen if ((proxy->flags & RAWLOG_FLAG_LOG_OUTPUT) != 0) {
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen fname = t_strdup_printf("%s/%s-%s.out", path, timestamp,
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen dec2str(getpid()));
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen proxy->fd_out = open(fname, O_CREAT|O_EXCL|O_WRONLY, 0600);
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen if (proxy->fd_out == -1) {
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen i_error("rawlog_open: open() failed for %s: %m", fname);
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen (void)close(proxy->fd_in);
e217d6fce33746e198ecc21bff0bc658664c9ef4Timo Sirainen proxy->fd_in = -1;
70612e07102b75a8511aa7f9de60771176b18de0Timo Sirainen return;
70612e07102b75a8511aa7f9de60771176b18de0Timo Sirainen }
70612e07102b75a8511aa7f9de60771176b18de0Timo Sirainen }
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen}
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic struct rawlog_proxy *
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainenrawlog_proxy_create(int client_in_fd, int client_out_fd, int server_fd,
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen const char *path, enum rawlog_flags flags)
469a6cf705835ade57dcb59979b6e054207ae5d7Timo Sirainen{
469a6cf705835ade57dcb59979b6e054207ae5d7Timo Sirainen struct rawlog_proxy *proxy;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen proxy = i_new(struct rawlog_proxy, 1);
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen proxy->server_fd = server_fd;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen proxy->server_output = o_stream_create_fd(server_fd, (size_t)-1, FALSE);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen proxy->server_io = io_add(server_fd, IO_READ, server_input, proxy);
644268f7848a7c4221146d0b11feb8ed5bbed233Timo Sirainen o_stream_set_flush_callback(proxy->server_output, server_output, proxy);
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen proxy->client_in_fd = client_in_fd;
469a6cf705835ade57dcb59979b6e054207ae5d7Timo Sirainen proxy->client_out_fd = client_out_fd;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen proxy->client_output =
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen o_stream_create_fd(client_out_fd, (size_t)-1, FALSE);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen proxy->client_io = io_add(proxy->client_in_fd, IO_READ,
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen client_input, proxy);
d2b94d25f842cd1b7acaf4dd7de858f7c6a821c9Timo Sirainen o_stream_set_flush_callback(proxy->client_output, client_output, proxy);
d2b94d25f842cd1b7acaf4dd7de858f7c6a821c9Timo Sirainen
d2b94d25f842cd1b7acaf4dd7de858f7c6a821c9Timo Sirainen fd_set_nonblock(client_in_fd, TRUE);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen fd_set_nonblock(client_out_fd, TRUE);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen proxy->flags = flags;
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen
38d7db318188c4ac9cdc8c6cdb936b36a5258e19Timo Sirainen proxy->prev_lf_in = proxy->prev_lf_out = TRUE;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen proxy->fd_in = proxy->fd_out = -1;
70612e07102b75a8511aa7f9de60771176b18de0Timo Sirainen proxy_open_logs(proxy, path);
70612e07102b75a8511aa7f9de60771176b18de0Timo Sirainen return proxy;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
645f258ea29afaf09b673fc65d1bd788dfec8db8Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void rawlog_open(enum rawlog_flags flags)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen const char *chroot_dir, *home, *path;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct stat st;
645f258ea29afaf09b673fc65d1bd788dfec8db8Timo Sirainen int sfd[2];
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen pid_t pid;
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen chroot_dir = getenv("RESTRICT_CHROOT");
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen home = getenv("HOME");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (chroot_dir != NULL)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen home = t_strconcat(chroot_dir, home, NULL);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen else if (home == NULL)
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen home = ".";
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen /* see if we want rawlog */
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen path = t_strconcat(home, "/dovecot.rawlog", NULL);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (lstat(path, &st) < 0) {
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen if (errno != ENOENT)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen i_warning("lstat() failed for %s: %m", path);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen else if (getenv("DEBUG") != NULL)
eed20b28dd9039d21f5c2770beef2e8b19f7c2f9Timo Sirainen i_info("rawlog: %s doesn't exist", path);
eed20b28dd9039d21f5c2770beef2e8b19f7c2f9Timo Sirainen return;
eed20b28dd9039d21f5c2770beef2e8b19f7c2f9Timo Sirainen }
eed20b28dd9039d21f5c2770beef2e8b19f7c2f9Timo Sirainen if (!S_ISDIR(st.st_mode)) {
eed20b28dd9039d21f5c2770beef2e8b19f7c2f9Timo Sirainen if (getenv("DEBUG") != NULL)
d2b94d25f842cd1b7acaf4dd7de858f7c6a821c9Timo Sirainen i_info("rawlog: %s is not a directory", path);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen return;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen if (chroot_dir != NULL) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen /* we'll chroot soon. skip over the chroot in the path. */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen path += strlen(chroot_dir);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) < 0)
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen i_fatal("socketpair() failed: %m");
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen fd_set_nonblock(sfd[0], TRUE);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen fd_set_nonblock(sfd[1], TRUE);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen pid = fork();
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen if (pid < 0)
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen i_fatal("fork() failed: %m");
d2b94d25f842cd1b7acaf4dd7de858f7c6a821c9Timo Sirainen
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen if (pid > 0) {
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen /* parent */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (dup2(sfd[1], 0) < 0)
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen i_fatal("dup2(sfd, 0)");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (dup2(sfd[1], 1) < 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_fatal("dup2(sfd, 1)");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen (void)close(sfd[0]);
60576cd64e6a537413cd90104f7e862f71d48c81Timo Sirainen (void)close(sfd[1]);
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen return;
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen }
7fc0f80480063a9d4cb9e8c07b50db2a5627799eTimo Sirainen (void)close(sfd[1]);
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen
203560029e3ad8687c2c759e6a81ecdb8b37ebe6Timo Sirainen restrict_access_by_env(getenv("HOME"), TRUE);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen process_title_set(t_strdup_printf("[%s:%s rawlog]", getenv("USER"),
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen dec2str(getppid())));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ioloop = io_loop_create();
cf52b37d807553e91a2d6fb7cb2c8b4c34589e1dTimo Sirainen rawlog_proxy_create(0, 1, sfd[0], path, flags);
644268f7848a7c4221146d0b11feb8ed5bbed233Timo Sirainen io_loop_run(ioloop);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen io_loop_destroy(&ioloop);
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen lib_deinit();
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen exit(0);
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen}
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen
80cdfe47daf6129410bafcecbe5c9faf09f2721bTimo Sirainenint main(int argc, char *argv[])
d2b94d25f842cd1b7acaf4dd7de858f7c6a821c9Timo Sirainen{
80cdfe47daf6129410bafcecbe5c9faf09f2721bTimo Sirainen char *executable, *p;
80cdfe47daf6129410bafcecbe5c9faf09f2721bTimo Sirainen enum rawlog_flags flags;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen int c;
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen flags = RAWLOG_FLAG_LOG_INPUT | RAWLOG_FLAG_LOG_OUTPUT;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen lib_init();
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_set_failure_internal();
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen process_title_init(&argv);
7a54d58280aad8a64f266c61273ea1e8dff511a3Timo Sirainen
7a54d58280aad8a64f266c61273ea1e8dff511a3Timo Sirainen while ((c = getopt(argc, argv, "iobt")) > 0) {
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen switch (c) {
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen case 'i':
e54512a5189192fe72d1e2c53927c98c5ac920b4Timo Sirainen flags &= ~RAWLOG_FLAG_LOG_OUTPUT;
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen break;
6f6f3dc5b33b09097192124bce17b7017d6bbfcfTimo Sirainen case 'o':
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen flags &= ~RAWLOG_FLAG_LOG_INPUT;
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen break;
4d0d535efdfc4aad3bd48b74adfafecf58094e0aTimo Sirainen case 'b':
4d0d535efdfc4aad3bd48b74adfafecf58094e0aTimo Sirainen flags |= RAWLOG_FLAG_LOG_BOUNDARIES;
4d0d535efdfc4aad3bd48b74adfafecf58094e0aTimo Sirainen break;
4d0d535efdfc4aad3bd48b74adfafecf58094e0aTimo Sirainen case 't':
4d0d535efdfc4aad3bd48b74adfafecf58094e0aTimo Sirainen flags |= RAWLOG_FLAG_LOG_TIMESTAMPS;
4d0d535efdfc4aad3bd48b74adfafecf58094e0aTimo Sirainen break;
6f6f3dc5b33b09097192124bce17b7017d6bbfcfTimo Sirainen default:
6f6f3dc5b33b09097192124bce17b7017d6bbfcfTimo Sirainen argc = 0;
6f6f3dc5b33b09097192124bce17b7017d6bbfcfTimo Sirainen break;
e54512a5189192fe72d1e2c53927c98c5ac920b4Timo Sirainen }
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen }
49be238e250e99af8c69321264a461d8f6ceef62Timo Sirainen argc -= optind;
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen argv += optind;
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen if (argc < 1)
e54512a5189192fe72d1e2c53927c98c5ac920b4Timo Sirainen i_fatal("Usage: rawlog [-i | -o] [-b] [-t] <binary> <arguments>");
e54512a5189192fe72d1e2c53927c98c5ac920b4Timo Sirainen
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen executable = argv[0];
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen rawlog_open(flags);
dd0dea1fdd913a04bae16e82dd66d67571a5f6c2Timo Sirainen
dd0dea1fdd913a04bae16e82dd66d67571a5f6c2Timo Sirainen /* hide the executable path, it's ugly */
dd0dea1fdd913a04bae16e82dd66d67571a5f6c2Timo Sirainen p = strrchr(argv[0], '/');
992118a50af940482b6cf884a89be56d7015580aTimo Sirainen if (p != NULL) argv[0] = p+1;
8b5b1f6cb19253dfd7821fcef8e9b7e95e6caf3aTimo Sirainen execv(executable, argv);
dd0dea1fdd913a04bae16e82dd66d67571a5f6c2Timo Sirainen
49be238e250e99af8c69321264a461d8f6ceef62Timo Sirainen i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", executable);
49be238e250e99af8c69321264a461d8f6ceef62Timo Sirainen
8b5b1f6cb19253dfd7821fcef8e9b7e95e6caf3aTimo Sirainen /* not reached */
8b5b1f6cb19253dfd7821fcef8e9b7e95e6caf3aTimo Sirainen return FATAL_EXEC;
8b5b1f6cb19253dfd7821fcef8e9b7e95e6caf3aTimo Sirainen}
8b5b1f6cb19253dfd7821fcef8e9b7e95e6caf3aTimo Sirainen