1 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "llist.h"
5 #include "strescape.h"
6 #include "istream.h"
7 #include "ostream.h"
8 #include "master-service.h"
9 #include "mail-session.h"
10 #include "mail-user.h"
11 #include "mail-command.h"
12 #include "fifo-input-connection.h"
13 
14 #include <unistd.h>
15 
16 #define MAX_INBUF_SIZE (PIPE_BUF*2)
17 
18 struct fifo_input_connection {
19 	struct fifo_input_connection *prev, *next;
20 
21 	int fd;
22 	struct istream *input;
23 	struct io *io;
24 };
25 
26 static struct fifo_input_connection *fifo_conns = NULL;
27 
28 static int
fifo_input_connection_request(const char * const * args,const char ** error_r)29 fifo_input_connection_request(const char *const *args, const char **error_r)
30 {
31 	const char *cmd = args[0];
32 
33 	if (cmd == NULL) {
34 		*error_r = "Missing command";
35 		return -1;
36 	}
37 	args++;
38 
39 	if (strcmp(cmd, "CONNECT") == 0)
40 		return mail_session_connect_parse(args, error_r);
41 	if (strcmp(cmd, "DISCONNECT") == 0)
42 		return mail_session_disconnect_parse(args, error_r);
43 	if (strcmp(cmd, "UPDATE-SESSION") == 0)
44 		return mail_session_update_parse(args, error_r);
45 	if (strcmp(cmd, "ADD-USER") == 0)
46 		return mail_user_add_parse(args, error_r);
47 	if (strcmp(cmd, "UPDATE-CMD") == 0)
48 		return mail_command_update_parse(args, error_r);
49 
50 	*error_r = "Unknown command";
51 	return -1;
52 }
53 
fifo_input_connection_input(struct fifo_input_connection * conn)54 static void fifo_input_connection_input(struct fifo_input_connection *conn)
55 {
56 	const char *line, *const *args, *error;
57 
58 	switch (i_stream_read(conn->input)) {
59 	case -2:
60 		i_error("BUG: Mail server sent too much data");
61 		fifo_input_connection_destroy(&conn);
62 		return;
63 	case -1:
64 		fifo_input_connection_destroy(&conn);
65 		return;
66 	}
67 
68 	while ((line = i_stream_next_line(conn->input)) != NULL) T_BEGIN {
69 		args = t_strsplit_tabescaped(line);
70 		if (fifo_input_connection_request(args, &error) < 0)
71 			i_error("FIFO input error: %s", error);
72 	} T_END;
73 }
74 
fifo_input_connection_create(int fd)75 struct fifo_input_connection *fifo_input_connection_create(int fd)
76 {
77 	struct fifo_input_connection *conn;
78 
79 	conn = i_new(struct fifo_input_connection, 1);
80 	conn->fd = fd;
81 	conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE);
82 	conn->io = io_add(fd, IO_READ, fifo_input_connection_input, conn);
83 	DLLIST_PREPEND(&fifo_conns, conn);
84 	return conn;
85 }
86 
fifo_input_connection_destroy(struct fifo_input_connection ** _conn)87 void fifo_input_connection_destroy(struct fifo_input_connection **_conn)
88 {
89 	struct fifo_input_connection *conn = *_conn;
90 
91 	*_conn = NULL;
92 
93 	DLLIST_REMOVE(&fifo_conns, conn);
94 	io_remove(&conn->io);
95 	i_stream_destroy(&conn->input);
96 	if (close(conn->fd) < 0)
97 		i_error("close(conn) failed: %m");
98 	i_free(conn);
99 }
100 
fifo_input_connections_destroy_all(void)101 void fifo_input_connections_destroy_all(void)
102 {
103 	while (fifo_conns != NULL) {
104 		struct fifo_input_connection *conn = fifo_conns;
105 
106 		fifo_input_connection_destroy(&conn);
107 	}
108 }
109