summaryrefslogtreecommitdiffstats
path: root/src/login-common/client-common.h
blob: 1bc57f08afa71b4dcd3fb33f79b7a0a595ae3337 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
#ifndef CLIENT_COMMON_H
#define CLIENT_COMMON_H

struct module;

#include "net.h"
#include "login-proxy.h"
#include "sasl-server.h"
#include "master-login.h" /* for LOGIN_MAX_SESSION_ID_LEN */

#define LOGIN_MAX_SESSION_ID_LEN 64
#define LOGIN_MAX_MASTER_PREFIX_LEN 128
#define LOGIN_MAX_CLIENT_ID_LEN 256

/* max. size of input buffer. this means:

   IMAP: Max. length of command's all parameters. SASL-IR is read into
         a separate larger buffer.
   POP3: Max. length of a command line (spec says 512 would be enough)
*/
#define LOGIN_MAX_INBUF_SIZE \
	(MASTER_AUTH_MAX_DATA_SIZE - LOGIN_MAX_MASTER_PREFIX_LEN - \
	 LOGIN_MAX_SESSION_ID_LEN)
/* max. size of output buffer. if it gets full, the client is disconnected.
   SASL authentication gives the largest output. */
#define LOGIN_MAX_OUTBUF_SIZE 4096

/* Max. length of SASL authentication buffer. */
#define LOGIN_MAX_AUTH_BUF_SIZE 8192

/* Disconnect client after this many milliseconds if it hasn't managed
   to log in yet. */
#define CLIENT_LOGIN_TIMEOUT_MSECS (MASTER_LOGIN_TIMEOUT_SECS*1000)

#define AUTH_SERVER_WAITING_MSG \
	"Waiting for authentication process to respond.."
#define AUTH_MASTER_WAITING_MSG \
	"Waiting for authentication master process to respond.."

/* Client logged out without having successfully authenticated. */
#define CLIENT_UNAUTHENTICATED_LOGOUT_MSG \
	"Aborted login by logging out"

struct master_service_connection;

enum client_disconnect_reason {
	CLIENT_DISCONNECT_TIMEOUT,
	CLIENT_DISCONNECT_SYSTEM_SHUTDOWN,
	CLIENT_DISCONNECT_RESOURCE_CONSTRAINT,
	CLIENT_DISCONNECT_INTERNAL_ERROR
};

enum client_auth_fail_code {
	CLIENT_AUTH_FAIL_CODE_NONE = 0,
	CLIENT_AUTH_FAIL_CODE_AUTHZFAILED,
	CLIENT_AUTH_FAIL_CODE_TEMPFAIL,
	CLIENT_AUTH_FAIL_CODE_USER_DISABLED,
	CLIENT_AUTH_FAIL_CODE_PASS_EXPIRED,
	CLIENT_AUTH_FAIL_CODE_INVALID_BASE64,
	CLIENT_AUTH_FAIL_CODE_LOGIN_DISABLED,
	CLIENT_AUTH_FAIL_CODE_MECH_INVALID,
	CLIENT_AUTH_FAIL_CODE_MECH_SSL_REQUIRED,
	CLIENT_AUTH_FAIL_CODE_ANONYMOUS_DENIED,
};

enum client_auth_result {
	CLIENT_AUTH_RESULT_SUCCESS,
	CLIENT_AUTH_RESULT_REFERRAL_SUCCESS,
	CLIENT_AUTH_RESULT_REFERRAL_NOLOGIN,
	CLIENT_AUTH_RESULT_ABORTED,
	CLIENT_AUTH_RESULT_AUTHFAILED,
	CLIENT_AUTH_RESULT_AUTHFAILED_REASON,
	CLIENT_AUTH_RESULT_AUTHZFAILED,
	CLIENT_AUTH_RESULT_TEMPFAIL,
	CLIENT_AUTH_RESULT_PASS_EXPIRED,
	CLIENT_AUTH_RESULT_SSL_REQUIRED,
	CLIENT_AUTH_RESULT_INVALID_BASE64,
	CLIENT_AUTH_RESULT_LOGIN_DISABLED,
	CLIENT_AUTH_RESULT_MECH_INVALID,
	CLIENT_AUTH_RESULT_MECH_SSL_REQUIRED,
	CLIENT_AUTH_RESULT_ANONYMOUS_DENIED
};

enum client_list_type {
	CLIENT_LIST_TYPE_NONE = 0,
	/* clients (disconnected=FALSE, fd_proxying=FALSE, destroyed=FALSE) */
	CLIENT_LIST_TYPE_ACTIVE,
	/* destroyed_clients (destroyed=TRUE, fd_proxying=FALSE). Either the
	   client will soon be freed or it's only referenced via
	   "login_proxies". */
	CLIENT_LIST_TYPE_DESTROYED,
	/* client_fd_proxies (fd_proxying=TRUE) */
	CLIENT_LIST_TYPE_FD_PROXY,
};

struct client_auth_reply {
	const char *master_user, *reason;
	enum client_auth_fail_code fail_code;

	/* for proxying */
	const char *host, *hostip, *source_ip;
	const char *destuser, *password, *proxy_mech;
	in_port_t port;
	unsigned int proxy_timeout_msecs;
	unsigned int proxy_refresh_secs;
	unsigned int proxy_host_immediate_failure_after_secs;
	enum login_proxy_ssl_flags ssl_flags;

	/* all the key=value fields returned by passdb */
	const char *const *all_fields;

	bool proxy:1;
	bool proxy_noauth:1;
	bool proxy_nopipelining:1;
	bool proxy_not_trusted:1;
	bool nologin:1;
};

struct client_vfuncs {
	struct client *(*alloc)(pool_t pool);
	void (*create)(struct client *client, void **other_sets);
	void (*destroy)(struct client *client);
	void (*notify_auth_ready)(struct client *client);
	void (*notify_disconnect)(struct client *client,
				  enum client_disconnect_reason reason,
				  const char *text);
	void (*notify_status)(struct client *client,
			      bool bad, const char *text);
	void (*notify_starttls)(struct client *client,
				bool success, const char *text);
	void (*starttls)(struct client *client);

	/* Called just before client iostreams are changed (e.g. STARTTLS).
	   iostream_change_post() is guaranteed to be called. */
	void (*iostream_change_pre)(struct client *client);
	/* Called just after client iostreams may have changed. Nothing may
	   have happened in case of unexpected errors. */
	void (*iostream_change_post)(struct client *client);

	void (*input)(struct client *client);
	bool (*sasl_filter_mech)(struct client *client,
				 struct auth_mech_desc *mech);
	bool (*sasl_check_login)(struct client *client);
	void (*auth_send_challenge)(struct client *client, const char *data);
	void (*auth_parse_response)(struct client *client);
	void (*auth_result)(struct client *client,
			    enum client_auth_result result,
			    const struct client_auth_reply *reply,
			    const char *text);
	void (*proxy_reset)(struct client *client);
	int (*proxy_parse_line)(struct client *client, const char *line);
	void (*proxy_failed)(struct client *client,
			     enum login_proxy_failure_type type,
			     const char *reason, bool reconnecting);
	const char *(*proxy_get_state)(struct client *client);
	void (*send_raw_data)(struct client *client,
			      const void *data, size_t size);
	bool (*input_next_cmd)(struct client *client);
	void (*free)(struct client *client);
};

struct client {
	struct client *prev, *next;
	/* Specifies which linked list the client is in */
	enum client_list_type list_type;

	pool_t pool;
	/* this pool gets free'd once proxying starts */
	pool_t preproxy_pool;
	struct client_vfuncs v;
	struct client_vfuncs *vlast;

	struct timeval created;
	int refcount;
	struct event *event;

	struct ip_addr local_ip;
	struct ip_addr ip;
	struct ip_addr real_remote_ip, real_local_ip;
	in_port_t local_port, remote_port;
	in_port_t real_local_port, real_remote_port;
	struct ssl_iostream *ssl_iostream;
	const struct login_settings *set;
	const struct master_service_ssl_settings *ssl_set;
	const struct master_service_ssl_server_settings *ssl_server_set;
	const char *session_id, *listener_name, *postlogin_socket_path;
	const char *local_name;
	const char *client_cert_common_name;

	string_t *client_id;
	string_t *forward_fields;

	int fd;
	struct istream *input;
	struct ostream *output;
	struct io *io;
	struct iostream_proxy *iostream_fd_proxy;
	struct timeout *to_auth_waiting;
	struct timeout *to_disconnect;

	unsigned char *master_data_prefix;
	unsigned int master_data_prefix_len;

	struct login_proxy *login_proxy;
	char *proxy_user, *proxy_master_user, *proxy_password;
	const struct dsasl_client_mech *proxy_mech;
	struct dsasl_client *proxy_sasl_client;
	unsigned int proxy_ttl;

	char *auth_mech_name;
	enum sasl_server_auth_flags auth_flags;
	struct auth_client_request *auth_request;
	string_t *auth_response;
	time_t auth_first_started, auth_finished;
	const char *sasl_final_resp;
	const char *sasl_final_delayed_resp;
	enum sasl_server_reply delayed_final_reply;
	const char *const *final_args;
	const char *const *auth_passdb_args;
	struct anvil_query *anvil_query;
	struct anvil_request *anvil_request;

	unsigned int master_auth_id;
	unsigned int master_tag;
	sasl_server_callback_t *sasl_callback;

	unsigned int bad_counter;
	unsigned int auth_attempts, auth_successes;
	enum client_auth_fail_code last_auth_fail;
	pid_t mail_pid;

	/* Module-specific contexts. */
	ARRAY(union login_client_module_context *) module_contexts;

	char *virtual_user, *virtual_user_orig, *virtual_auth_user;
	/* passdb user_* fields are set here after a successful auth.
	   This is a NULL-terminated array where fields are in the same order
	   as in global_alt_usernames. If some field doesn't exist, it's "".
	   Can also be NULL if there are no user_* fields. */
	const char **alt_usernames;
	/* director_username_hash cached, if non-zero */
	unsigned int director_username_hash_cache;

	bool create_finished:1;
	bool disconnected:1;
	bool destroyed:1;
	bool input_blocked:1;
	bool login_success:1;
	bool no_extra_disconnect_reason:1;
	bool starttls:1;
	bool tls:1;
	bool proxied_ssl:1;
	bool secured:1;
	bool ssl_secured:1;
	bool trusted:1;
	bool ssl_servername_settings_read:1;
	bool banner_sent:1;
	bool authenticating:1;
	bool auth_client_continue_pending:1;
	bool auth_try_aborted:1;
	bool auth_initializing:1;
	bool auth_process_comm_fail:1;
	bool auth_anonymous:1;
	bool proxy_auth_failed:1;
	bool proxy_noauth:1;
	bool proxy_nopipelining:1;
	bool proxy_not_trusted:1;
	bool auth_waiting:1;
	bool notified_auth_ready:1;
	bool notified_disconnect:1;
	bool fd_proxying:1;
	bool final_response:1;
	/* ... */
};

union login_client_module_context {
	struct client_vfuncs super;
	struct login_module_register *reg;
};

struct login_client_hooks {
	void (*client_allocated)(struct client *client);
};

extern struct client *clients;

typedef void login_client_allocated_func_t(struct client *client);

void login_client_hooks_add(struct module *module,
			    const struct login_client_hooks *hooks);
void login_client_hooks_remove(const struct login_client_hooks *hooks);

struct client *
client_alloc(int fd, pool_t pool,
	     const struct master_service_connection *conn,
	     const struct login_settings *set,
	     const struct master_service_ssl_settings *ssl_set,
	     const struct master_service_ssl_server_settings *ssl_server_set);
void client_init(struct client *client, void **other_sets);
void client_disconnect(struct client *client, const char *reason,
		       bool add_disconnected_prefix);
void client_destroy(struct client *client, const char *reason);
void client_destroy_iostream_error(struct client *client);
/* Destroy the client after a successful login. Either the client fd was
   sent to the post-login process, or the connection will be proxied. */
void client_destroy_success(struct client *client, const char *reason);

void client_ref(struct client *client);
bool client_unref(struct client **client) ATTR_NOWARN_UNUSED_RESULT;

int client_init_ssl(struct client *client);
void client_cmd_starttls(struct client *client);

int client_get_plaintext_fd(struct client *client, int *fd_r, bool *close_fd_r);

unsigned int clients_get_count(void) ATTR_PURE;
unsigned int clients_get_fd_proxies_count(void);
struct client *clients_get_first_fd_proxy(void);

void client_add_forward_field(struct client *client, const char *key,
			      const char *value);
void client_set_title(struct client *client);
const char *client_get_extra_disconnect_reason(struct client *client);

void client_auth_respond(struct client *client, const char *response);
void client_auth_abort(struct client *client);
bool client_is_tls_enabled(struct client *client);
void client_auth_fail(struct client *client, const char *text);
const char *client_get_session_id(struct client *client);

bool client_read(struct client *client);

void client_input(struct client *client);

static inline bool
client_does_custom_io(struct client *client)
{
	return (client->v.input == NULL);
}

void client_notify_auth_ready(struct client *client);
void client_notify_status(struct client *client, bool bad, const char *text);
void client_notify_disconnect(struct client *client,
			      enum client_disconnect_reason reason,
			      const char *text);

void client_send_raw_data(struct client *client, const void *data, size_t size);
void client_send_raw(struct client *client, const char *data);
void client_common_send_raw_data(struct client *client,
				 const void *data, size_t size);
void client_common_default_free(struct client *client);
void client_common_proxy_failed(struct client *client,
				enum login_proxy_failure_type type,
				const char *reason, bool reconnecting);

void client_set_auth_waiting(struct client *client);
void client_auth_send_challenge(struct client *client, const char *data);
void client_auth_parse_response(struct client *client);
int client_auth_begin(struct client *client, const char *mech_name,
		      const char *init_resp);
int client_auth_begin_private(struct client *client, const char *mech_name,
			      const char *init_resp);
int client_auth_begin_implicit(struct client *client, const char *mech_name,
			       const char *init_resp);
bool client_check_plaintext_auth(struct client *client, bool pass_sent);
int client_auth_read_line(struct client *client);

void client_proxy_finish_destroy_client(struct client *client);
void client_proxy_log_failure(struct client *client, const char *line);
const char *client_proxy_get_state(struct client *client);

void clients_notify_auth_connected(void);
bool client_destroy_oldest(bool kill, struct timeval *created_r);
void clients_destroy_all(void);
void clients_destroy_all_reason(const char *reason);

void client_destroy_fd_proxies(void);
void client_common_init(void);
void client_common_deinit(void);

#endif