]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
If commands are pipelined after the login command, pass them to the
authorTimo Sirainen <tss@iki.fi>
Sat, 21 Jun 2008 09:23:08 +0000 (12:23 +0300)
committerTimo Sirainen <tss@iki.fi>
Sat, 21 Jun 2008 09:23:08 +0000 (12:23 +0300)
IMAP/POP3 process so it can process the command instead of discarding it.

--HG--
branch : HEAD

21 files changed:
src/imap-login/client-authenticate.c
src/imap-login/client.c
src/imap-login/client.h
src/imap-login/imap-proxy.c
src/imap/client.c
src/imap/client.h
src/imap/main.c
src/login-common/client-common.h
src/login-common/master.c
src/master/login-process.c
src/master/mail-process.c
src/master/mail-process.h
src/master/master-login-interface.h
src/master/master-settings.c
src/pop3-login/client-authenticate.c
src/pop3-login/client.c
src/pop3-login/client.h
src/pop3-login/pop3-proxy.c
src/pop3/client.c
src/pop3/client.h
src/pop3/main.c

index d308b5d4e7e42806ea270b73b9cc7d6d5beff26a..77d11dc4b1b20564bce7129444ac24fecb682921 100644 (file)
@@ -52,14 +52,14 @@ static void client_auth_input(struct imap_client *client)
                return;
 
        if (client->skip_line) {
-               if (i_stream_next_line(client->input) == NULL)
+               if (i_stream_next_line(client->common.input) == NULL)
                        return;
 
                client->skip_line = FALSE;
        }
 
        /* @UNSAFE */
-       line = i_stream_next_line(client->input);
+       line = i_stream_next_line(client->common.input);
        if (line == NULL)
                return;
 
index 5abea6b06d18976b297e9601cdd56b489bad44c7..19001fe145fc99fee13d2d13a2eefd63f851c215 100644 (file)
 
 #include <stdlib.h>
 
-/* max. size of one parameter in line, or max reply length in SASL
-   authentication */
-#define MAX_INBUF_SIZE 4096
-
 /* max. size of output buffer. if it gets full, the client is disconnected.
    SASL authentication gives the largest output. */
 #define MAX_OUTBUF_SIZE 4096
@@ -72,10 +68,11 @@ static void client_set_title(struct imap_client *client)
 
 static void client_open_streams(struct imap_client *client, int fd)
 {
-       client->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
+       client->common.input =
+               i_stream_create_fd(fd, LOGIN_MAX_INBUF_SIZE, FALSE);
        client->output = o_stream_create_fd(fd, MAX_OUTBUF_SIZE, FALSE);
-       client->parser = imap_parser_create(client->input, client->output,
-                                           MAX_IMAP_LINE);
+       client->parser = imap_parser_create(client->common.input,
+                                           client->output, MAX_IMAP_LINE);
 }
 
 /* Skip incoming data until newline is found,
@@ -85,11 +82,11 @@ bool client_skip_line(struct imap_client *client)
        const unsigned char *data;
        size_t i, data_size;
 
-       data = i_stream_get_data(client->input, &data_size);
+       data = i_stream_get_data(client->common.input, &data_size);
 
        for (i = 0; i < data_size; i++) {
                if (data[i] == '\n') {
-                       i_stream_skip(client->input, i+1);
+                       i_stream_skip(client->common.input, i+1);
                        return TRUE;
                }
        }
@@ -141,7 +138,7 @@ static void client_start_tls(struct imap_client *client)
        client_set_title(client);
 
        client->common.fd = fd_ssl;
-       i_stream_unref(&client->input);
+       i_stream_unref(&client->common.input);
        o_stream_unref(&client->output);
        imap_parser_destroy(&client->parser);
 
@@ -360,7 +357,9 @@ static bool client_handle_input(struct imap_client *client)
                /* not enough data */
                return FALSE;
        }
-       client->skip_line = TRUE;
+       /* we read the entire line - skip over the CRLF */
+       if (!client_skip_line(client))
+               i_unreached();
 
        if (*client->cmd_tag == '\0')
                ret = -1;
@@ -387,7 +386,7 @@ static bool client_handle_input(struct imap_client *client)
 
 bool client_read(struct imap_client *client)
 {
-       switch (i_stream_read(client->input)) {
+       switch (i_stream_read(client->common.input)) {
        case -2:
                /* buffer full */
                client_send_line(client, "* BYE Input buffer full, aborting");
@@ -557,8 +556,8 @@ void client_destroy(struct imap_client *client, const char *reason)
 
        client_unlink(&client->common);
 
-       if (client->input != NULL)
-               i_stream_close(client->input);
+       if (client->common.input != NULL)
+               i_stream_close(client->common.input);
        if (client->output != NULL)
                o_stream_close(client->output);
 
@@ -637,8 +636,8 @@ bool client_unref(struct imap_client *client)
 
        imap_parser_destroy(&client->parser);
 
-       if (client->input != NULL)
-               i_stream_unref(&client->input);
+       if (client->common.input != NULL)
+               i_stream_unref(&client->common.input);
        if (client->output != NULL)
                o_stream_unref(&client->output);
 
@@ -665,7 +664,7 @@ void client_send_line(struct imap_client *client, const char *line)
                   want this connection destroyed. however destroying it here
                   might break things if client is still tried to be accessed
                   without being referenced.. */
-               i_stream_close(client->input);
+               i_stream_close(client->common.input);
        }
 }
 
index c1c846f562f7a0349443454908fdb18820004a31..c3af585c5e9b3577cecf762b684195c54858152d 100644 (file)
@@ -12,7 +12,6 @@ struct imap_client {
        int refcount;
 
        struct io *io;
-       struct istream *input;
        struct ostream *output;
        struct imap_parser *parser;
        struct timeout *to_idle_disconnect, *to_auth_waiting;
index 4aa01ff1c6952ac0ced86050eab5b61e78bed0e2..b38e24da243066c88f77ad8012b10c963e33256a 100644 (file)
@@ -97,11 +97,11 @@ static int proxy_input_line(struct imap_client *client,
                                      login_proxy_get_port(client->proxy));
 
                (void)client_skip_line(client);
-               login_proxy_detach(client->proxy, client->input,
+               login_proxy_detach(client->proxy, client->common.input,
                                   client->output);
 
                client->proxy = NULL;
-               client->input = NULL;
+               client->common.input = NULL;
                client->output = NULL;
                client->common.fd = -1;
                client_destroy_success(client, msg);
index c9b471d56d5fa931329c11d60067b4537264bbff..3ac47092a17940c47dd62718d12b653776bee722 100644 (file)
@@ -18,8 +18,6 @@ extern struct mail_storage_callbacks mail_storage_callbacks;
 
 static struct client *my_client; /* we don't need more than one currently */
 
-static bool client_handle_input(struct client *client);
-
 static void client_idle_timeout(struct client *client)
 {
        if (client->output_lock == NULL)
@@ -684,7 +682,7 @@ static bool client_handle_next_command(struct client *client, bool *remove_io_r)
        return client_command_input(client->input_lock);
 }
 
-static bool client_handle_input(struct client *client)
+bool client_handle_input(struct client *client)
 {
        bool ret, remove_io, handled_commands = FALSE;
 
index 82b1d80d030e8b07d2e682c5b8a8e28f36c0a8a8..78d4520e1c609644e7e77cee969fcb13fa70ea95 100644 (file)
@@ -171,6 +171,7 @@ bool client_handle_unfinished_cmd(struct client_command_context *cmd);
 void client_continue_pending_input(struct client **_client);
 
 void client_input(struct client *client);
+bool client_handle_input(struct client *client);
 int client_output(struct client *client);
 
 #endif
index be3b456fa3b0fa4aef7848bad23f163c30e84fbf..167f40b07d00778550bdbbadad61692d65361b82 100644 (file)
@@ -5,6 +5,8 @@
 #include "network.h"
 #include "ostream.h"
 #include "str.h"
+#include "base64.h"
+#include "istream.h"
 #include "lib-signals.h"
 #include "restrict-access.h"
 #include "fd-close-on-exec.h"
@@ -163,6 +165,7 @@ static void drop_privileges(void)
 static void main_init(void)
 {
        struct client *client;
+       struct ostream *output;
        struct mail_namespace *ns;
        const char *user, *str;
 
@@ -238,7 +241,9 @@ static void main_init(void)
                i_fatal("Namespace initialization failed");
        client = client_create(0, 1, ns);
 
-        o_stream_cork(client->output);
+       output = client->output;
+       o_stream_ref(output);
+       o_stream_cork(output);
        if (IS_STANDALONE()) {
                client_send_line(client, t_strconcat(
                        "* PREAUTH [CAPABILITY ",
@@ -249,7 +254,18 @@ static void main_init(void)
                client_send_line(client, t_strconcat(getenv("IMAPLOGINTAG"),
                                                     " OK Logged in.", NULL));
        }
-        o_stream_uncork(client->output);
+       str = getenv("CLIENT_INPUT");
+       if (str != NULL) T_BEGIN {
+               buffer_t *buf = t_base64_decode_str(str);
+               if (buf->used > 0) {
+                       if (!i_stream_add_data(client->input, buf->data,
+                                              buf->used))
+                               i_panic("Couldn't add client input to stream");
+                       (void)client_handle_input(client);
+               }
+       } T_END;
+        o_stream_uncork(output);
+       o_stream_unref(&output);
 }
 
 static void main_deinit(void)
@@ -292,8 +308,12 @@ int main(int argc ATTR_UNUSED, char *argv[], char *envp[])
         process_title_init(argv, envp);
        ioloop = io_loop_create();
 
+       /* fake that we're running, so we know if client was destroyed
+          while initializing */
+       io_loop_set_running(ioloop);
        main_init();
-        io_loop_run(ioloop);
+       if (io_loop_is_running(ioloop))
+               io_loop_run(ioloop);
        main_deinit();
 
        io_loop_destroy(&ioloop);
index 23ea65d76979f3b74bd59d03fa957f5e1dc37467..7167aa71e913788e45b996203682b10f774c9a32 100644 (file)
@@ -5,6 +5,14 @@
 #include "master.h"
 #include "sasl-server.h"
 
+/* max. size of input buffer. this means:
+
+   SASL: Max SASL request length from client
+   IMAP: Max. length of a single parameter
+   POP3: Max. length of a command line (spec says 512 would be enough)
+*/
+#define LOGIN_MAX_INBUF_SIZE 4096
+
 struct client {
        struct client *prev, *next;
 
@@ -14,6 +22,7 @@ struct client {
        struct ssl_proxy *proxy;
 
        int fd;
+       struct istream *input;
 
        char *auth_mech_name;
        struct auth_request *auth_request;
index 93fc333990ee48c7afd5b77ea609b7131238804e..67047c132675a487dec84399d9decf9e901cdf93 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "common.h"
 #include "hash.h"
+#include "buffer.h"
 #include "ioloop.h"
 #include "network.h"
 #include "fdpass.h"
@@ -59,32 +60,50 @@ static void request_handle(struct master_login_reply *reply)
 void master_request_login(struct client *client, master_callback_t *callback,
                          unsigned int auth_pid, unsigned int auth_id)
 {
-       struct master_login_request req;
+       buffer_t *buf;
+       struct master_login_request *req;
        struct stat st;
+       const unsigned char *data;
+       size_t size;
+       ssize_t ret;
 
        i_assert(auth_pid != 0);
 
-       memset(&req, 0, sizeof(req));
-       req.version = MASTER_LOGIN_PROTOCOL_VERSION;
-       req.tag = ++master_tag_counter;
-       if (req.tag == 0)
-               req.tag = ++master_tag_counter;
-       req.auth_pid = auth_pid;
-       req.auth_id = auth_id;
-       req.local_ip = client->local_ip;
-       req.remote_ip = client->ip;
+       data = i_stream_get_data(client->input, &size);
+       buf = buffer_create_dynamic(pool_datastack_create(),
+                                   sizeof(*req) + size);
+       buffer_write(buf, sizeof(*req), data, size);
+       req = buffer_get_space_unsafe(buf, 0, sizeof(*req));
+       req->version = MASTER_LOGIN_PROTOCOL_VERSION;
+       req->tag = ++master_tag_counter;
+       if (req->tag == 0)
+               req->tag = ++master_tag_counter;
+       req->auth_pid = auth_pid;
+       req->auth_id = auth_id;
+       req->local_ip = client->local_ip;
+       req->remote_ip = client->ip;
+       req->data_size = size;
+#if LOGIN_MAX_INBUF_SIZE != MASTER_LOGIN_MAX_DATA_SIZE
+#  error buffer max sizes unsynced
+#endif
+       i_assert(req->data_size <= LOGIN_MAX_INBUF_SIZE);
 
        if (fstat(client->fd, &st) < 0)
                i_fatal("fstat(client) failed: %m");
-       req.ino = st.st_ino;
+       req->ino = st.st_ino;
 
-       if (fd_send(master_fd, client->fd, &req, sizeof(req)) != sizeof(req))
+       ret = fd_send(master_fd, client->fd, buf->data, buf->used);
+       if (ret < 0)
                i_fatal("fd_send(%d) failed: %m", client->fd);
+       if ((size_t)ret != buf->used) {
+               i_fatal("fd_send() sent only %d of %d bytes",
+                       (int)ret, (int)buf->used);
+       }
 
-       client->master_tag = req.tag;
+       client->master_tag = req->tag;
        client->master_callback = callback;
 
-       hash_insert(master_requests, POINTER_CAST(req.tag), client);
+       hash_insert(master_requests, POINTER_CAST(req->tag), client);
 }
 
 void master_request_abort(struct client *client)
index a341d201ccdfcf2b55ef86dc84774699d87628ac..333d876985f36956637e936ef283a1832533fbc6 100644 (file)
@@ -48,7 +48,9 @@ struct login_auth_request {
        unsigned int login_tag;
        int fd;
 
+       unsigned int data_size;
        struct ip_addr local_ip, remote_ip;
+       unsigned char data[];
 };
 
 static unsigned int auth_id_counter, login_pid_counter;
@@ -105,6 +107,7 @@ void auth_master_callback(const char *user, const char *const *args,
                                            group->set,
                                            request->fd, &request->local_ip,
                                            &request->remote_ip, user, args,
+                                           request->data_size, request->data,
                                            FALSE);
        } T_END;
 
@@ -304,6 +307,7 @@ static bool login_process_read_group(struct login_process *p)
 
 static int
 login_read_request(struct login_process *p, struct master_login_request *req,
+                  unsigned char data[MASTER_LOGIN_MAX_DATA_SIZE],
                   int *client_fd_r)
 {
        struct stat st;
@@ -343,6 +347,26 @@ login_read_request(struct login_process *p, struct master_login_request *req,
                }
                return 1;
        }
+       if (req->data_size != 0) {
+               if (req->data_size > MASTER_LOGIN_MAX_DATA_SIZE) {
+                       i_error("login: Too large data_size sent");
+                       return -1;
+               }
+               /* @UNSAFE */
+               ret = read(p->fd, data, req->data_size);
+               if (ret != req->data_size) {
+                       if (ret == 0) {
+                               /* disconnected */
+                       } else if (ret > 0) {
+                               /* request wasn't fully read */
+                               i_error("login: Data read partially %d/%u",
+                                       (int)ret, req->data_size);
+                       } else {
+                               i_error("login: read(data) failed: %m");
+                       }
+                       return -1;
+               }
+       }
 
        if (*client_fd_r == -1) {
                i_error("login: Login request missing a file descriptor");
@@ -353,7 +377,6 @@ login_read_request(struct login_process *p, struct master_login_request *req,
                i_error("login: fstat(mail client) failed: %m");
                return -1;
        }
-
        if (st.st_ino != req->ino) {
                i_error("login: Login request inode mismatch: %s != %s",
                        dec2str(st.st_ino), dec2str(req->ino));
@@ -367,6 +390,7 @@ static void login_process_input(struct login_process *p)
        struct auth_process *auth_process;
        struct login_auth_request *authreq;
        struct master_login_request req;
+       unsigned char data[MASTER_LOGIN_MAX_DATA_SIZE];
        int client_fd;
        ssize_t ret;
 
@@ -377,7 +401,7 @@ static void login_process_input(struct login_process *p)
                return;
        }
 
-       ret = login_read_request(p, &req, &client_fd);
+       ret = login_read_request(p, &req, data, &client_fd);
        if (ret == 0)
                return;
        if (ret < 0) {
@@ -412,7 +436,7 @@ static void login_process_input(struct login_process *p)
        fd_close_on_exec(client_fd, TRUE);
 
        /* ask the cookie from the auth process */
-       authreq = i_new(struct login_auth_request, 1);
+       authreq = i_malloc(sizeof(*authreq) + req.data_size);
        p->refcount++;
        authreq->process = p;
        authreq->tag = ++auth_id_counter;
@@ -420,6 +444,8 @@ static void login_process_input(struct login_process *p)
        authreq->fd = client_fd;
        authreq->local_ip = req.local_ip;
        authreq->remote_ip = req.remote_ip;
+       authreq->data_size = req.data_size;
+       memcpy(authreq->data, data, req.data_size);
 
        auth_process = auth_process_find(req.auth_pid);
        if (auth_process == NULL) {
index 8cb9109e37a063189e7fce766f047bfccfa68cb3..254873798cc3a4e8774d803c4ced91504b62b3ea 100644 (file)
@@ -5,6 +5,7 @@
 #include "hash.h"
 #include "fd-close-on-exec.h"
 #include "env-util.h"
+#include "base64.h"
 #include "str.h"
 #include "network.h"
 #include "mountpoint.h"
@@ -524,6 +525,7 @@ create_mail_process(enum process_type process_type, struct settings *set,
                    int socket_fd, const struct ip_addr *local_ip,
                    const struct ip_addr *remote_ip,
                    const char *user, const char *const *args,
+                   unsigned int input_size, const unsigned char *input,
                    bool dump_capability)
 {
        const struct var_expand_table *var_expand_table;
@@ -832,6 +834,13 @@ create_mail_process(enum process_type process_type, struct settings *set,
        addr = net_ip2addr(remote_ip);
        env_put(t_strconcat("IP=", addr, NULL));
 
+       if (input_size > 0) {
+               str_truncate(str, 0);
+               str_append(str, "CLIENT_INPUT=");
+               base64_encode(input, input_size, str);
+               env_put(str_c(str));
+       }
+
        if (!set->verbose_proctitle)
                title[0] = '\0';
        else {
index 98c187e21a26db39dd708ec31ad958743cb18953..b13a5560bd6996d5891f7b4268daed4c597eb9be 100644 (file)
@@ -13,6 +13,7 @@ create_mail_process(enum process_type process_type, struct settings *set,
                    int socket_fd, const struct ip_addr *local_ip,
                    const struct ip_addr *remote_ip,
                    const char *user, const char *const *args,
+                   unsigned int input_size, const unsigned char *input,
                    bool dump_capability);
 
 void mail_processes_init(void);
index 0fcb06ec6e730345da69d601768b2e444e1289c2..b5fb6d7d55dd0457612339d9c46b33f1f0fc42ce 100644 (file)
@@ -9,6 +9,9 @@
    (or something else) is changed. */
 #define MASTER_LOGIN_PROTOCOL_VERSION 3
 
+/* This should be kept in sync with LOGIN_MAX_INBUF_SIZE */
+#define MASTER_LOGIN_MAX_DATA_SIZE 4096
+
 enum master_login_state {
        /* process is accepting new connections */
        LOGIN_STATE_LISTENING = 0,
@@ -28,6 +31,8 @@ struct master_login_request {
 
        uint32_t auth_pid;
        uint32_t auth_id;
+       /* request follows this many bytes of client input */
+       uint32_t data_size;
 
        ino_t ino;
 
index 83f1728abd4a8dec0fb51228d4e844b16531cc8f..ae1b28bbc0dd0f51f6db40e15369419896f3a10f 100644 (file)
@@ -647,7 +647,7 @@ static bool get_imap_capability(struct settings *set)
        fd_close_on_exec(fd[1], TRUE);
        login_status = create_mail_process(PROCESS_TYPE_IMAP, set, fd[1],
                                           &ip, &ip, "dump-capability",
-                                          args, TRUE);
+                                          args, 0, NULL, TRUE);
        if (login_status != MASTER_LOGIN_STATUS_OK) {
                (void)close(fd[0]);
                (void)close(fd[1]);
index 3fc2bd93c87f28ed080da140f52f39f6e9098490..7c072c25c6597cb67f9c8bc35fa1a57911276f31 100644 (file)
@@ -66,7 +66,7 @@ static void client_auth_input(struct pop3_client *client)
                return;
 
        /* @UNSAFE */
-       line = i_stream_next_line(client->input);
+       line = i_stream_next_line(client->common.input);
        if (line == NULL)
                return;
 
index bf5fe0ef249af23833163e5b47b5105a67dba81f..d047a7a9b122dbcc0017d48ef55e93e4e87f3979 100644 (file)
 #include "pop3-proxy.h"
 #include "hostpid.h"
 
-/* max. length of input command line (spec says 512), or max reply length in
-   SASL authentication */
-#define MAX_INBUF_SIZE 4096
-
 /* max. size of output buffer. if it gets full, the client is disconnected.
    SASL authentication gives the largest output. */
 #define MAX_OUTBUF_SIZE 4096
@@ -59,7 +55,8 @@ static void client_set_title(struct pop3_client *client)
 
 static void client_open_streams(struct pop3_client *client, int fd)
 {
-       client->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
+       client->common.input =
+               i_stream_create_fd(fd, LOGIN_MAX_INBUF_SIZE, FALSE);
        client->output = o_stream_create_fd(fd, MAX_OUTBUF_SIZE, FALSE);
 }
 
@@ -87,7 +84,7 @@ static void client_start_tls(struct pop3_client *client)
 
        client->common.fd = fd_ssl;
 
-       i_stream_unref(&client->input);
+       i_stream_unref(&client->common.input);
        o_stream_unref(&client->output);
 
        client_open_streams(client, fd_ssl);
@@ -180,7 +177,7 @@ static bool client_command_execute(struct pop3_client *client, const char *cmd,
 
 bool client_read(struct pop3_client *client)
 {
-       switch (i_stream_read(client->input)) {
+       switch (i_stream_read(client->common.input)) {
        case -2:
                /* buffer full */
                client_send_line(client, "-ERR Input line too long, aborting");
@@ -208,8 +205,8 @@ void client_input(struct pop3_client *client)
        client_ref(client);
 
        o_stream_cork(client->output);
-       while (!client->output->closed &&
-              (line = i_stream_next_line(client->input)) != NULL) {
+       while (!client->output->closed && !client->common.authenticating &&
+              (line = i_stream_next_line(client->common.input)) != NULL) {
                args = strchr(line, ' ');
                if (args != NULL)
                        *args++ = '\0';
@@ -363,8 +360,8 @@ void client_destroy(struct pop3_client *client, const char *reason)
 
        client_unlink(&client->common);
 
-       if (client->input != NULL)
-               i_stream_close(client->input);
+       if (client->common.input != NULL)
+               i_stream_close(client->common.input);
        if (client->output != NULL)
                o_stream_close(client->output);
 
@@ -433,8 +430,8 @@ bool client_unref(struct pop3_client *client)
 
        i_assert(client->destroyed);
 
-       if (client->input != NULL)
-               i_stream_unref(&client->input);
+       if (client->common.input != NULL)
+               i_stream_unref(&client->common.input);
        if (client->output != NULL)
                o_stream_unref(&client->output);
 
@@ -463,7 +460,7 @@ void client_send_line(struct pop3_client *client, const char *line)
                   want this connection destroyed. however destroying it here
                   might break things if client is still tried to be accessed
                   without being referenced.. */
-               i_stream_close(client->input);
+               i_stream_close(client->common.input);
        }
 }
 
index 34815fab465faa6989ce7d412bc6eb4b465ce739..dcebfe41fe32f9bf9a7cddcb3ca412ba0dc27118 100644 (file)
@@ -13,7 +13,6 @@ struct pop3_client {
        int refcount;
 
        struct io *io;
-       struct istream *input;
        struct ostream *output;
        struct timeout *to_idle_disconnect;
 
@@ -29,7 +28,6 @@ struct pop3_client {
        struct auth_connect_id auth_id;
 
        unsigned int login_success:1;
-       unsigned int authenticating:1;
        unsigned int auth_connected:1;
        unsigned int destroyed:1;
 };
index 7a7a25e1fe64ee6f50db542a6a2d55c6c9774994..30a68c16b4637a8892a9a4997b0fdfd447640b3c 100644 (file)
@@ -107,11 +107,11 @@ static void proxy_input(struct istream *input, struct ostream *output,
                                      login_proxy_get_host(client->proxy),
                                      login_proxy_get_port(client->proxy));
 
-               login_proxy_detach(client->proxy, client->input,
+               login_proxy_detach(client->proxy, client->common.input,
                                   client->output);
 
                client->proxy = NULL;
-               client->input = NULL;
+               client->common.input = NULL;
                client->output = NULL;
                client->common.fd = -1;
                client_destroy_success(client, msg);
index b8c4359077cbacd3dcfaf55a4dda71de6e69547a..40f1fbe745841b68285beb28b7324bfdd724f5d3 100644 (file)
@@ -375,35 +375,11 @@ void client_send_storage_error(struct client *client)
                                                     &error));
 }
 
-static void client_input(struct client *client)
+bool client_handle_input(struct client *client)
 {
        char *line, *args;
        int ret;
 
-       if (client->cmd != NULL) {
-               /* we're still processing a command. wait until it's
-                  finished. */
-               io_remove(&client->io);
-               client->waiting_input = TRUE;
-               return;
-       }
-
-       client->waiting_input = FALSE;
-       client->last_input = ioloop_time;
-       timeout_reset(client->to_idle);
-
-       switch (i_stream_read(client->input)) {
-       case -1:
-               /* disconnected */
-               client_destroy(client, NULL);
-               return;
-       case -2:
-               /* line too long, kill it */
-               client_send_line(client, "-ERR Input line too long.");
-               client_destroy(client, "Input line too long");
-               return;
-       }
-
        o_stream_cork(client->output);
        while (!client->output->closed &&
               (line = i_stream_next_line(client->input)) != NULL) {
@@ -430,8 +406,40 @@ static void client_input(struct client *client)
        }
        o_stream_uncork(client->output);
 
-       if (client->output->closed)
+       if (client->output->closed) {
                client_destroy(client, NULL);
+               return FALSE;
+       }
+       return TRUE;
+}
+
+static void client_input(struct client *client)
+{
+       if (client->cmd != NULL) {
+               /* we're still processing a command. wait until it's
+                  finished. */
+               io_remove(&client->io);
+               client->waiting_input = TRUE;
+               return;
+       }
+
+       client->waiting_input = FALSE;
+       client->last_input = ioloop_time;
+       timeout_reset(client->to_idle);
+
+       switch (i_stream_read(client->input)) {
+       case -1:
+               /* disconnected */
+               client_destroy(client, NULL);
+               return;
+       case -2:
+               /* line too long, kill it */
+               client_send_line(client, "-ERR Input line too long.");
+               client_destroy(client, "Input line too long");
+               return;
+       }
+
+       (void)client_handle_input(client);
 }
 
 static int client_output(struct client *client)
index cf40afb5b999ab9d569500d8e47392a922f8b02b..35cb285e772783a01d2e21d2f8289fc861e72ce1 100644 (file)
@@ -61,6 +61,8 @@ int client_send_line(struct client *client, const char *fmt, ...)
        ATTR_FORMAT(2, 3);
 void client_send_storage_error(struct client *client);
 
+bool client_handle_input(struct client *client);
+
 void clients_init(void);
 void clients_deinit(void);
 
index 083eae0050977a91c81046858fef5e65ec9018c0..67574f90b336cc6628aa06028437efe3fab20c0a 100644 (file)
@@ -7,6 +7,9 @@
 #include "lib-signals.h"
 #include "restrict-access.h"
 #include "fd-close-on-exec.h"
+#include "base64.h"
+#include "buffer.h"
+#include "istream.h"
 #include "process-title.h"
 #include "randgen.h"
 #include "module-dir.h"
@@ -180,9 +183,12 @@ static void drop_privileges(void)
        restrict_access_by_env(!IS_STANDALONE());
 }
 
-static int main_init(void)
+static bool main_init(void)
 {
        struct mail_namespace *ns;
+       struct client *client;
+       const char *str;
+       bool ret = TRUE;
 
        lib_signals_init();
         lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
@@ -232,7 +238,21 @@ static int main_init(void)
        namespace_pool = pool_alloconly_create("namespaces", 1024);
        if (mail_namespaces_init(namespace_pool, getenv("USER"), &ns) < 0)
                i_fatal("Namespace initialization failed");
-       return client_create(0, 1, ns) != NULL;
+       client = client_create(0, 1, ns);
+       if (client == NULL)
+               return FALSE;
+
+       str = getenv("CLIENT_INPUT");
+       if (str != NULL) T_BEGIN {
+               buffer_t *buf = t_base64_decode_str(str);
+               if (buf->used > 0) {
+                       if (!i_stream_add_data(client->input, buf->data,
+                                              buf->used))
+                               i_panic("Couldn't add client input to stream");
+                       ret = client_handle_input(client);
+               }
+       } T_END;
+       return ret;
 }
 
 static void main_deinit(void)