comparison src/director/login-connection.c @ 18675:52cdf321fa07

director: Added "authreply" socket type. This allows defining a socket, which receives auth replies. Director then adds the "host" field to it if it's missing and returns back the original string. The idea is that eventually a director ring could be running independently from Dovecot proxies.
author Timo Sirainen <tss@iki.fi>
date Wed, 13 May 2015 16:22:27 +0300
parents d54dc360cd3c
children aabfe48db1cf
comparison
equal deleted inserted replaced
18674:c97d10467b62 18675:52cdf321fa07
1 /* Copyright (c) 2010-2015 Dovecot authors, see the included COPYING file */ 1 /* Copyright (c) 2010-2015 Dovecot authors, see the included COPYING file */
2 2
3 #include "lib.h" 3 #include "lib.h"
4 #include "ioloop.h" 4 #include "ioloop.h"
5 #include "net.h" 5 #include "net.h"
6 #include "istream.h"
6 #include "ostream.h" 7 #include "ostream.h"
7 #include "llist.h" 8 #include "llist.h"
8 #include "master-service.h" 9 #include "master-service.h"
9 #include "director.h" 10 #include "director.h"
10 #include "director-request.h" 11 #include "director-request.h"
11 #include "auth-connection.h" 12 #include "auth-connection.h"
12 #include "login-connection.h" 13 #include "login-connection.h"
13 14
14 #include <unistd.h> 15 #include <unistd.h>
15 16
17 #define AUTHREPLY_PROTOCOL_MAJOR_VERSION 1
18 #define AUTHREPLY_PROTOCOL_MINOR_VERSION 0
19
16 struct login_connection { 20 struct login_connection {
17 struct login_connection *prev, *next; 21 struct login_connection *prev, *next;
18 22
19 int refcount; 23 int refcount;
24 enum login_connection_type type;
20 25
21 int fd; 26 int fd;
22 struct io *io; 27 struct io *io;
28 struct istream *input;
23 struct ostream *output; 29 struct ostream *output;
24 struct auth_connection *auth; 30 struct auth_connection *auth;
25 struct director *dir; 31 struct director *dir;
26 32
33 unsigned int handshaked:1;
27 unsigned int destroyed:1; 34 unsigned int destroyed:1;
28 unsigned int userdb:1;
29 }; 35 };
30 36
31 struct login_host_request { 37 struct login_host_request {
32 struct login_connection *conn; 38 struct login_connection *conn;
33 char *line, *username; 39 char *line, *username;
38 bool director_proxy_maybe; 44 bool director_proxy_maybe;
39 }; 45 };
40 46
41 static struct login_connection *login_connections; 47 static struct login_connection *login_connections;
42 48
49 static void auth_input_line(const char *line, void *context);
43 static void login_connection_unref(struct login_connection **_conn); 50 static void login_connection_unref(struct login_connection **_conn);
44 51
45 static void login_connection_input(struct login_connection *conn) 52 static void login_connection_input(struct login_connection *conn)
46 { 53 {
47 struct ostream *output; 54 struct ostream *output;
59 login_connection_deinit(&conn); 66 login_connection_deinit(&conn);
60 return; 67 return;
61 } 68 }
62 output = auth_connection_get_output(conn->auth); 69 output = auth_connection_get_output(conn->auth);
63 o_stream_nsend(output, buf, ret); 70 o_stream_nsend(output, buf, ret);
71 }
72
73 static void login_connection_authreply_input(struct login_connection *conn)
74 {
75 const char *line;
76
77 while ((line = i_stream_read_next_line(conn->input)) != NULL) T_BEGIN {
78 if (!conn->handshaked) {
79 if (!version_string_verify(line, "director-authreply-client",
80 AUTHREPLY_PROTOCOL_MAJOR_VERSION)) {
81 i_error("authreply client sent invalid handshake: %s", line);
82 login_connection_deinit(&conn);
83 return;
84 }
85 conn->handshaked = TRUE;
86 } else {
87 auth_input_line(line, conn);
88 }
89 } T_END;
90 if (conn->input->eof) {
91 if (conn->input->stream_errno != 0 &&
92 conn->input->stream_errno != ECONNRESET) {
93 i_error("read(authreply connection) failed: %s",
94 i_stream_get_error(conn->input));
95 }
96 login_connection_deinit(&conn);
97 }
64 } 98 }
65 99
66 static void 100 static void
67 login_connection_send_line(struct login_connection *conn, const char *line) 101 login_connection_send_line(struct login_connection *conn, const char *line)
68 { 102 {
136 if (line == NULL) { 170 if (line == NULL) {
137 /* auth connection died -> kill also this login connection */ 171 /* auth connection died -> kill also this login connection */
138 login_connection_deinit(&conn); 172 login_connection_deinit(&conn);
139 return; 173 return;
140 } 174 }
141 if (!conn->userdb && strncmp(line, "OK\t", 3) == 0) 175 if (conn->type != LOGIN_CONNECTION_TYPE_USERDB &&
176 strncmp(line, "OK\t", 3) == 0)
142 line_params = line + 3; 177 line_params = line + 3;
143 else if (conn->userdb && strncmp(line, "PASS\t", 5) == 0) 178 else if (conn->type == LOGIN_CONNECTION_TYPE_USERDB &&
179 strncmp(line, "PASS\t", 5) == 0)
144 line_params = line + 5; 180 line_params = line + 5;
145 else { 181 else {
146 login_connection_send_line(conn, line); 182 login_connection_send_line(conn, line);
147 return; 183 return;
148 } 184 }
206 director_request(conn->dir, username, tag, login_host_callback, request); 242 director_request(conn->dir, username, tag, login_host_callback, request);
207 } 243 }
208 244
209 struct login_connection * 245 struct login_connection *
210 login_connection_init(struct director *dir, int fd, 246 login_connection_init(struct director *dir, int fd,
211 struct auth_connection *auth, bool userdb) 247 struct auth_connection *auth,
248 enum login_connection_type type)
212 { 249 {
213 struct login_connection *conn; 250 struct login_connection *conn;
214 251
215 conn = i_new(struct login_connection, 1); 252 conn = i_new(struct login_connection, 1);
216 conn->refcount = 1; 253 conn->refcount = 1;
217 conn->fd = fd; 254 conn->fd = fd;
218 conn->auth = auth;
219 conn->dir = dir; 255 conn->dir = dir;
220 conn->output = o_stream_create_fd(conn->fd, (size_t)-1, FALSE); 256 conn->output = o_stream_create_fd(conn->fd, (size_t)-1, FALSE);
221 o_stream_set_no_error_handling(conn->output, TRUE); 257 o_stream_set_no_error_handling(conn->output, TRUE);
222 conn->io = io_add(conn->fd, IO_READ, login_connection_input, conn); 258 if (type != LOGIN_CONNECTION_TYPE_AUTHREPLY) {
223 conn->userdb = userdb; 259 i_assert(auth != NULL);
224 260 conn->auth = auth;
225 auth_connection_set_callback(conn->auth, auth_input_line, conn); 261 conn->io = io_add(conn->fd, IO_READ,
262 login_connection_input, conn);
263 auth_connection_set_callback(conn->auth, auth_input_line, conn);
264 } else {
265 i_assert(auth == NULL);
266 conn->input = i_stream_create_fd(conn->fd, IO_BLOCK_SIZE, FALSE);
267 conn->io = io_add(conn->fd, IO_READ,
268 login_connection_authreply_input, conn);
269 o_stream_nsend_str(conn->output, t_strdup_printf(
270 "VERSION\tdirector-authreply-server\t%d\t%d\n",
271 AUTHREPLY_PROTOCOL_MAJOR_VERSION,
272 AUTHREPLY_PROTOCOL_MINOR_VERSION));
273 }
274 conn->type = type;
275
226 DLLIST_PREPEND(&login_connections, conn); 276 DLLIST_PREPEND(&login_connections, conn);
227 return conn; 277 return conn;
228 } 278 }
229 279
230 void login_connection_deinit(struct login_connection **_conn) 280 void login_connection_deinit(struct login_connection **_conn)
237 return; 287 return;
238 conn->destroyed = TRUE; 288 conn->destroyed = TRUE;
239 289
240 DLLIST_REMOVE(&login_connections, conn); 290 DLLIST_REMOVE(&login_connections, conn);
241 io_remove(&conn->io); 291 io_remove(&conn->io);
292 if (conn->input != NULL)
293 i_stream_destroy(&conn->input);
242 o_stream_destroy(&conn->output); 294 o_stream_destroy(&conn->output);
243 if (close(conn->fd) < 0) 295 if (close(conn->fd) < 0)
244 i_error("close(login connection) failed: %m"); 296 i_error("close(login connection) failed: %m");
245 conn->fd = -1; 297 conn->fd = -1;
246 298
247 auth_connection_deinit(&conn->auth); 299 if (conn->auth != NULL)
300 auth_connection_deinit(&conn->auth);
248 login_connection_unref(&conn); 301 login_connection_unref(&conn);
249 302
250 master_service_client_connection_destroyed(master_service); 303 master_service_client_connection_destroyed(master_service);
251 } 304 }
252 305