1 #include "base64.h"
2 #include "buf.h"
3 #include "auth.h"
4 #include "token.h"
5 #include "io.h"
6 #include "sasl_plain.h"
7 #include "managesieve.h"
8 #include "managesieve_in.h"
9 #include "managesieve_write.h"
10 #include "acap_token.h"
11 #include "queue_func.h"
12 #include "unused.h"
13 #include "options.h"
14
15 #ifdef WITH_PAM_SUPPORT
16 /**********************************************************************
17 * managesieve_in_authenticate
18 * Authenticate an incoming session
19 * Not really needed if we are going to authenticate with a real-server,
20 * but it may be useful in some cases
21 * pre: auth: login credentials
22 * io: io_t to write any errors to
23 * tag: ignored
24 * post: An attemped is made to authenticate the user locally.
25 * If this fails then an error message is written to io
26 * Else there is no output to io
27 * return: 1 if authentication is successful
28 * 0 if authentication is unsuccessful
29 * -1 on error
30 **********************************************************************/
31
managesieve_in_authenticate(const struct auth * UNUSED (auth),io_t * UNUSED (io),const token_t * UNUSED (tag))32 int managesieve_in_authenticate(const struct auth *UNUSED(auth),
33 io_t *UNUSED(io), const token_t *UNUSED(tag))
34 {
35 return -1;
36 }
37 #endif /* WITH_PAM_SUPPORT */
38
39 struct managesieve_in_auth_status {
40 struct auth auth;
41 int status;
42 };
43
44 #define STRUCT_MANAGESIEVE_IN_AUTH_STATUS(name) \
45 struct managesieve_in_auth_status (name) = { .status = -3 }
46
47 /**********************************************************************
48 * managesieve_in_sasl_plain
49 * Handle a NOOP command
50 * pre: io: io_t to write to and read from
51 * q: queue of tokens read from client.
52 * post: q is destroyed
53 * return: .auth: seeded auth structure
54 * .status: 0 on MANAGESIEVE_OK (password structure is filled in)
55 * -1 on MANAGESIEVE_NO
56 * -2 on MANAGESIEVE_BYE
57 * -3 on internal error
58 **********************************************************************/
59
60 static struct managesieve_in_auth_status
managesieve_in_sasl_plain(io_t * io,vanessa_queue_t * q)61 managesieve_in_sasl_plain(io_t *io, vanessa_queue_t *q)
62 {
63 STRUCT_AUTH_STATUS(as);
64 STRUCT_MANAGESIEVE_IN_AUTH_STATUS(auth_status);
65 STRUCT_ACAP_TOKEN_WRAPPER_STATUS(wrapper_status);
66
67 if (vanessa_queue_length(q) != 1) {
68 if (managesieve_no(io, NULL, "Incorrect argument count, "
69 "expected AUTHENTICATE \"PLAIN\" <challenge>, "
70 "mate") < 0) {
71 VANESSA_LOGGER_DEBUG("managesieve_no");
72 goto err;
73 }
74 auth_status.status = -1;
75 goto err;
76 }
77
78 wrapper_status = acap_token_wrapper(io, PERDITION_CLIENT, q);
79 vanessa_queue_destroy(wrapper_status.q);
80 q = NULL; /* acap_token_wrapper() consumes q */
81
82 if (wrapper_status.status == -2) {
83 VANESSA_LOGGER_DEBUG("acap_token_wrapper");
84 goto err;
85 }
86 if (wrapper_status.status ||
87 !acap_token_wrapper_status_is_eol(&wrapper_status) ||
88 wrapper_status.type == acap_atom) {
89 if (managesieve_no(io, NULL, "Invalid AUTHENTICATE \"PLAIN\" "
90 "challenge, mate") < 0) {
91 VANESSA_LOGGER_DEBUG("managesieve_no");
92 goto err;
93 }
94 auth_status.status = -1;
95 goto err;
96 }
97
98 as = sasl_plain_challenge_decode(wrapper_status.str);
99 switch (as.status) {
100 case auth_status_ok:
101 break;
102 case auth_status_invalid:
103 if (managesieve_no(io, NULL, as.reason) < 0) {
104 VANESSA_LOGGER_DEBUG("managesieve_no");
105 goto err;
106 }
107 case auth_status_error:
108 auth_status.status = -1;
109 goto err;
110 }
111
112 auth_status.auth = as.auth;
113 auth_status.status = 0;
114 err:
115 free(wrapper_status.str);
116 vanessa_queue_destroy(q);
117 return auth_status;
118 }
119
120 /**********************************************************************
121 * managesieve_in_authenticate_cmd
122 * Handle a NOOP command
123 * pre: io: io_t to write to and read from
124 * q: queue of tokens read from client.
125 * post: q is destroyed
126 * return: .auth: seeded auth structure
127 * .status: 0 on MANAGESIEVE_OK (password structure is filled in)
128 * -1 on MANAGESIEVE_NO
129 * -2 on MANAGESIEVE_BYE
130 * -3 on internal error
131 **********************************************************************/
132
133 static struct managesieve_in_auth_status
managesieve_in_authenticate_cmd(io_t * io,vanessa_queue_t * q)134 managesieve_in_authenticate_cmd(io_t *io, vanessa_queue_t *q)
135 {
136 token_t *t = NULL;
137 STRUCT_MANAGESIEVE_IN_AUTH_STATUS(auth_status);
138
139 if (vanessa_queue_length(q) == 0 || vanessa_queue_length(q) > 2) {
140 if (managesieve_no(io, NULL, "Incorrect argument count, "
141 "expected AUTHENTICATE <mechanism> [<challenge>], "
142 "mate") < 0) {
143 VANESSA_LOGGER_DEBUG("managesieve_no");
144 goto err;
145 }
146 auth_status.status = -1;
147 goto err;
148 }
149
150 q = vanessa_queue_pop(q, (void **)&t);
151 if (!q) {
152 VANESSA_LOGGER_DEBUG("vanessa_queue_pop");
153 goto err;
154 }
155
156 if (token_casecmp_string(t, "\"" SASL_MECHANISM_PLAIN "\"")) {
157 auth_status = managesieve_in_sasl_plain(io, q);
158 q = NULL; /* managesieve_in_sasl_plain consumes q */
159 if (!auth_status.status)
160 auth_status.status = 1;
161 goto err;
162 } else {
163 if (managesieve_no(io, NULL,
164 "Unknown SASL mechanism, mate") < 0) {
165 VANESSA_LOGGER_DEBUG("managesieve_no");
166 goto err;
167 }
168 auth_status.status = -1;
169 goto err;
170 }
171
172 auth_status.status = 0;
173 err:
174 vanessa_queue_destroy(q);
175 token_destroy(&t);
176 return auth_status;
177 }
178
179 /**********************************************************************
180 * managesieve_in_capability_cmd
181 * Handle a CAPABILITY command
182 * pre: io: io_t to write to and read from
183 * q: queue of tokens read from client.
184 * tls_flags: the encryption flags that have been set
185 * tls_state: the current state of encryption for the session
186 * post: q is destroyed
187 * return: 0 on MANAGESIEVE_OK
188 * -1 on MANAGESIEVE_NO
189 * -2 on MANAGESIEVE_BYE
190 * -3 on internal error
191 **********************************************************************/
192
managesieve_in_capability_cmd(io_t * io,vanessa_queue_t * q,flag_t tls_flags,flag_t tls_state)193 static int managesieve_in_capability_cmd(io_t *io, vanessa_queue_t *q,
194 flag_t tls_flags, flag_t tls_state)
195 {
196 int status = -3;
197 char *msg = NULL;
198
199 if (vanessa_queue_length(q) != 0) {
200 if (managesieve_no(io, NULL, "Too many arguments, "
201 "expected CAPABILITY, mate") < 0) {
202 VANESSA_LOGGER_DEBUG("managesieve_no");
203 goto err;
204 }
205 status = -1;
206 goto err;
207 }
208
209 msg = managesieve_capability_msg(tls_flags, tls_state,
210 "CAPABILITY completed, mate");
211 if (!msg) {
212 VANESSA_LOGGER_DEBUG("managesieve_capability_msg");
213 goto err;
214 }
215
216 if (managesieve_write_raw(io, msg) < 0) {
217 VANESSA_LOGGER_DEBUG("managesieve_write_raw");
218 goto err;
219 }
220
221 status = 0;
222 err:
223 vanessa_queue_destroy(q);
224 free(msg);
225 return status;
226 }
227
228 /**********************************************************************
229 * managesieve_in_logout_cmd
230 * Handle a LOGOUT command
231 * pre: io: io_t to write to and read from
232 * q: queue of tokens read from client.
233 * post: q is destroyed
234 * return: 0 on MANAGESIEVE_OK
235 * -1 on MANAGESIEVE_NO
236 * -2 on MANAGESIEVE_BYE
237 * -3 on internal error
238 **********************************************************************/
239
managesieve_in_logout_cmd(io_t * io,vanessa_queue_t * q)240 static int managesieve_in_logout_cmd(io_t *io, vanessa_queue_t *q)
241 {
242 int status = -3;
243
244 if (vanessa_queue_length(q) == 0) {
245 if (managesieve_ok(io, NULL, "LOGOUT completed, mate") < 0) {
246 VANESSA_LOGGER_DEBUG("managesieve_ok");
247 goto err;
248 }
249 } else {
250 if (managesieve_no(io, NULL, "Too many arguments, "
251 "expected LOGOUT, mate") < 0) {
252 VANESSA_LOGGER_DEBUG("managesieve_no");
253 goto err;
254 }
255 status = -1;
256 goto err;
257 }
258
259 status = 0;
260 err:
261 vanessa_queue_destroy(q);
262 return status;
263 }
264
265 /**********************************************************************
266 * managesieve_in_noop_cmd_str
267 * Handle the string argument of a NOOP command
268 * pre: io: io_t to write to and read from
269 * q: queue of tokens read from client.
270 * post: q is destroyed
271 * return: 0 on MANAGESIEVE_OK
272 * -1 on MANAGESIEVE_NO
273 * -2 on MANAGESIEVE_BYE
274 * -3 on internal error
275 **********************************************************************/
276
managesieve_in_noop_cmd_str(io_t * io,vanessa_queue_t * q)277 static int managesieve_in_noop_cmd_str(io_t *io, vanessa_queue_t *q)
278 {
279 int status = -3;
280 token_t *t = NULL;
281 char *rc_arg[2];
282 STRUCT_MANAGESIEVE_RESPONSE_CODE(rc);
283 STRUCT_ACAP_TOKEN_WRAPPER_STATUS(wrapper_status);
284
285 wrapper_status = acap_token_wrapper(io, PERDITION_CLIENT, q);
286 vanessa_queue_destroy(wrapper_status.q);
287 q = NULL; /* acap_token_wrapper() consumes q */
288
289 if (wrapper_status.status == -2) {
290 VANESSA_LOGGER_DEBUG("acap_token_wrapper");
291 goto err;
292 }
293 if (wrapper_status.status ||
294 !acap_token_wrapper_status_is_eol(&wrapper_status) ||
295 wrapper_status.type == acap_atom) {
296 if (managesieve_no(io, NULL, "Invalid AUTHENTICATE PLAIN "
297 "challenge, mate") < 0) {
298 VANESSA_LOGGER_DEBUG("managesieve_no");
299 goto err;
300 }
301 status = -1;
302 goto err;
303 }
304
305 rc_arg[0] = wrapper_status.str;
306 rc_arg[1] = NULL;
307 rc.atom = "TAG";
308 rc.arg = rc_arg;
309 if (managesieve_ok(io, &rc, "NOOP completed, mate") < 0) {
310 VANESSA_LOGGER_DEBUG("managesieve_no");
311 goto err;
312 }
313
314 status = 0;
315 err:
316 vanessa_queue_destroy(q);
317 token_destroy(&t);
318 free(wrapper_status.str);
319 return status;
320 }
321
322 /**********************************************************************
323 * managesieve_in_noop_cmd
324 * Handle a NOOP command
325 * pre: io: io_t to write to and read from
326 * q: queue of tokens read from client.
327 * post: q is destroyed
328 * return: 0 on MANAGESIEVE_OK
329 * -1 on MANAGESIEVE_NO
330 * -2 on MANAGESIEVE_BYE
331 * -3 on internal error
332 **********************************************************************/
333
managesieve_in_noop_cmd(io_t * io,vanessa_queue_t * q)334 static int managesieve_in_noop_cmd(io_t *io, vanessa_queue_t *q)
335 {
336 int status = -3;
337
338 if (vanessa_queue_length(q) == 0) {
339 if (managesieve_ok(io, NULL, "NOOP completed, mate") < 0) {
340 VANESSA_LOGGER_DEBUG("managesieve_ok");
341 goto err;
342 }
343 } else if (vanessa_queue_length(q) == 1) {
344 status = managesieve_in_noop_cmd_str(io, q);
345 q = NULL; /* managesieve_in_noop_cmd_str consumes q */
346 if (status < 0) {
347 VANESSA_LOGGER_DEBUG("managesieve_in_noop_cmd_str");
348 goto err;
349 }
350 } else {
351 if (managesieve_no(io, NULL,
352 "Too many arguments, expected NOOP "
353 "[String], mate") < 0) {
354 VANESSA_LOGGER_DEBUG("managesieve_no");
355 goto err;
356 }
357 status = -1;
358 goto err;
359 }
360
361 status = 0;
362 err:
363 vanessa_queue_destroy(q);
364 return status;
365 }
366
367 #ifdef WITH_SSL_SUPPORT
368 /**********************************************************************
369 * managesieve_in_starttls_cmd
370 * Handle a STARTTLS command
371 * pre: io: io_t to write to and read from
372 * q: queue of tokens read from client.
373 * post: q is destroyed
374 * return: 0 on MANAGESIEVE_OK
375 * -1 on MANAGESIEVE_NO
376 * -2 on MANAGESIEVE_BYE
377 * -3 on internal error
378 **********************************************************************/
379
managesieve_in_starttls_cmd(io_t * io,vanessa_queue_t * q)380 static int managesieve_in_starttls_cmd(io_t *io, vanessa_queue_t *q)
381 {
382 int status = -3;
383
384 if (vanessa_queue_length(q) != 0) {
385 if (managesieve_no(io, NULL, "Too many arguments, "
386 "expected STARTTLS, mate") < 0) {
387 VANESSA_LOGGER_DEBUG("managesieve_no");
388 goto err;
389 }
390 status = -1;
391 goto err;
392 }
393
394 if (managesieve_ok(io, NULL, "Begin TLS negotiation, mate") < 0) {
395 VANESSA_LOGGER_DEBUG("managesieve_ok");
396 goto err;
397 }
398
399 status = 0;
400 err:
401 vanessa_queue_destroy(q);
402 return status;
403 }
404
managesieve_starttls_post(io_t * io,int tls_flags,int tls_state)405 static int managesieve_starttls_post(io_t *io, int tls_flags, int tls_state)
406 {
407 char *msg;
408 int status = -1;
409
410 if (!(tls_state & SSL_MODE_TLS_LISTEN))
411 return 0;
412
413 msg = managesieve_capability_msg(tls_flags, tls_state,
414 "TLS negotiation completed, mate");
415 if (!msg) {
416 VANESSA_LOGGER_DEBUG("managesieve_capability_msg");
417 goto err;
418 }
419
420 if (managesieve_write_raw(io, msg) < 0) {
421 VANESSA_LOGGER_DEBUG("managesieve_write_raw");
422 goto err;
423 }
424
425 status = 0;
426 err:
427 free(msg);
428 return status;
429 }
430 #else
managesieve_starttls_post(io_t * UNUSED (io),int UNUSED (tls_flags),int UNUSED (tls_state))431 static int managesieve_starttls_post(io_t *UNUSED(io), int UNUSED(tls_flags),
432 int UNUSED(tls_state))
433 {
434 return 0;
435 }
436 #endif
437
438 /**********************************************************************
439 * managesieve_in_get_auth_loop
440 * allocated by this function
441 * pre: io: io_t to write to and read from
442 * tls_flags: the encryption flags that have been set
443 * tls_state: the current state of encryption for the session
444 * post: auth_return is seeded
445 * return: 3 starttls
446 * 2 logout
447 * 1 auth obtained
448 * 0 on MANAGESIEVE_OK
449 * -1 on MANAGESIEVE_NO
450 * -2 on MANAGESIEVE_BYE
451 * -3 on internal error
452 **********************************************************************/
453
454 static struct managesieve_in_auth_status
managesieve_in_get_auth_loop(io_t * io,flag_t tls_flags,flag_t tls_state)455 managesieve_in_get_auth_loop(io_t *io, flag_t tls_flags, flag_t tls_state)
456 {
457 vanessa_queue_t *q = NULL;
458 token_t *t = NULL;
459 STRUCT_MANAGESIEVE_IN_AUTH_STATUS(as);
460
461 q = read_line(io, NULL, NULL, TOKEN_MANAGESIEVE, 0,
462 PERDITION_LOG_STR_CLIENT);
463 if (!q) {
464 VANESSA_LOGGER_DEBUG("read_line");
465 goto err;;
466 }
467
468 q = vanessa_queue_pop(q, (void **)&t);
469 if (!q) {
470 VANESSA_LOGGER_DEBUG("vanessa_queue_pop");
471 goto err;
472 }
473
474 if (token_casecmp_string(t, MANAGESIEVE_CMD_AUTHENTICATE)) {
475 as = managesieve_in_authenticate_cmd(io, q);
476 q = NULL; /* managesieve_in_logout_cmd consumes q */
477 if (!as.status)
478 as.status = 1;
479 goto err;
480 } else if (token_casecmp_string(t, MANAGESIEVE_CMD_CAPABILITY)) {
481 as.status = managesieve_in_capability_cmd(io, q, tls_flags,
482 tls_state);
483 q = NULL; /* managesieve_in_capability_cmd consumes q */
484 if (as.status < 0)
485 goto err;
486 } else if (token_casecmp_string(t, MANAGESIEVE_CMD_LOGOUT)) {
487 as.status = managesieve_in_logout_cmd(io, q);
488 q = NULL; /* managesieve_in_logout_cmd consumes q */
489 if (!as.status)
490 as.status = 2;
491 goto err;
492 } else if (token_casecmp_string(t, MANAGESIEVE_CMD_NOOP)) {
493 as.status = managesieve_in_noop_cmd(io, q);
494 q = NULL; /* managesieve_in_noop_cmd consumes q */
495 if (as.status < 0)
496 goto err;
497 #ifdef WITH_SSL_SUPPORT
498 } else if (tls_flags & SSL_MODE_TLS_LISTEN &&
499 io_get_type(io) != io_type_ssl &&
500 token_casecmp_string(t, MANAGESIEVE_CMD_STARTTLS)) {
501 as.status = managesieve_in_starttls_cmd(io, q);
502 q = NULL; /* managesieve_in_starttls_cmd consumes q */
503 if (!as.status)
504 as.status = 3;
505 goto err;
506 #endif
507 } else if (managesieve_no(io, NULL, "Unknown command, mate") < 0) {
508 VANESSA_LOGGER_DEBUG("managesieve_no");
509 as.status = -1;
510 goto err;
511 }
512
513 as.status = 0;
514 err:
515 vanessa_queue_destroy(q);
516 token_destroy(&t);
517 return as;
518 }
519
520 /**********************************************************************
521 * managesieve_in_get_auth
522 * allocated by this function
523 * pre: io: io_t to write to and read from
524 * tls_flags: the encryption flags that have been set
525 * tls_state: the current state of encryption for the session
526 * return_auth: pointer to an allocated struct auth,
527 * where login credentials will be returned
528 * return_tag: ignored
529 * post: auth_return is seeded
530 * return: 0 on success
531 * 1 if user quits (LOGOUT command)
532 * 2 if TLS negotiation should be done
533 * -1 on error
534 **********************************************************************/
535
managesieve_in_get_auth(io_t * io,flag_t tls_flags,flag_t tls_state,struct auth * return_auth,token_t ** UNUSED (return_tag))536 int managesieve_in_get_auth(io_t *io, flag_t tls_flags, flag_t tls_state,
537 struct auth *return_auth,
538 token_t **UNUSED(return_tag))
539 {
540 struct managesieve_in_auth_status as;
541
542 if (managesieve_starttls_post(io, tls_flags, tls_state) < 0)
543 {
544 VANESSA_LOGGER_DEBUG("managesieve_starttls_post");
545 return -1;
546 }
547
548 while (1) {
549 as = managesieve_in_get_auth_loop(io, tls_flags, tls_state);
550 if (as.status != 0 && as.status != -1)
551 break;
552 }
553
554 if (as.status > 0)
555 as.status--;
556 if (!as.status)
557 *return_auth = as.auth;
558
559 return as.status;
560 }
561