Commit 08dbbe2a 08dbbe2a422ee12fc9b80f2b7bd5d209b0812272 by Sergey Poznyakoff

Improve transcript stream.

* include/mailutils/stream.h (MU_IOCTL_LEVEL): New ioctl op.
(XSCRIPT_NORMAL, XSCRIPT_SECURE, XSCRIPT_PAYLOAD): New constants.
* include/mailutils/sys/xscript-stream.h (_mu_xscript_stream)
<level>: New member.
* mailbox/xscript-stream.c (TRANS_DISABLED): New flag.
(print_transcript): Amount of output varies depending on the
current output level.  For secure data, try to recognize passwords
and to replace them with *** on output.
(_xscript_ctl): Support MU_IOCTL_LEVEL.
* pop3d/extra.c (set_xscript_level): New function.
* pop3d/pop3d.h (set_xscript_level): New proto.
* pop3d/retr.c (pop3d_retr): Set XSCRIPT_PAYLOAD level before
sending actual data and reset it to XSCRIPT_NORMAL afterwards.
* pop3d/top.c (pop3d_top): Likewise.
* pop3d/user.c: Set XSCRIPT_SECURE level while expecting the
PASS command.

* imap4d/fetch.c (imap4d_fetch): Run imap4d_fetch0 in XSCRIPT_PAYLOAD
level.
* imap4d/uid.c (imap4d_uid): Likewise.
* imap4d/imap4d.c (imap4d_mainloop): Unless started in preauth mode,
select XSCRIPT_SECURE mode until authentication has been passed.
* imap4d/imap4d.h (set_xscript_level): New proto.
* imap4d/io.c (io_format_completion_response): Switch to XSCRIPT_NORMAL
level when changing to the authenticated state.
(imap4d_readline): Read literals in XSCRIPT_PAYLOAD level.
* imap4d/util.c (set_xscript_level): New function.

* include/mailutils/pop3.h (mu_pop3_trace_mask): New prototype.
(MU_POP3_XSCRIPT_MASK): New macro.
(_mu_pop3_xscript_level): New proto.
* libproto/pop/pop3_pass.c (mu_pop3_pass): Set XSCRIPT_SECURE
while sending the password.
* libproto/pop/pop3_retr.c (mu_pop3_retr): Set XSCRIPT_PAYLOAD before
going to MU_POP3_RETR_RX state.
* libproto/pop/pop3_stream.c (_pop3_event_cb): Set XSCRIPT_NORMAL.
* libproto/pop/pop3_top.c (mu_pop3_top): Set XSCRIPT_PAYLOAD before
going to MU_POP3_TOP_RX state.
* libproto/pop/pop3_trace.c (mu_pop3_trace_mask)
(_mu_pop3_xscript_level): New functions.
* libproto/pop/mbox.c (pop_open): Set trace masks depending on the
trace6 and trace7 debug levels.

* examples/pop3client.c (com_verbose): Allow to mask/unmask transcript
levels.
1 parent 7bfe0ed9
...@@ -131,8 +131,8 @@ COMMAND commands[] = { ...@@ -131,8 +131,8 @@ COMMAND commands[] = {
131 "Get the unique id of message: UIDL [msgno]" }, 131 "Get the unique id of message: UIDL [msgno]" },
132 { "user", 2, 2, com_user, 132 { "user", 2, 2, com_user,
133 "send login: USER user" }, 133 "send login: USER user" },
134 { "verbose", 1, 2, com_verbose, 134 { "verbose", 1, 4, com_verbose,
135 "Enable Protocol tracing: verbose [on|off]" }, 135 "Enable Protocol tracing: verbose [on|off|mask|unmask] [x1 [x2]]" },
136 #ifdef WITH_READLINE 136 #ifdef WITH_READLINE
137 { "history", 1, 1, com_history, 137 { "history", 1, 1, com_history,
138 "Show command history" }, 138 "Show command history" },
...@@ -145,6 +145,14 @@ mu_pop3_t pop3; ...@@ -145,6 +145,14 @@ mu_pop3_t pop3;
145 145
146 /* Flag if verbosity is needed. */ 146 /* Flag if verbosity is needed. */
147 int verbose; 147 int verbose;
148 #define VERBOSE_MASK(n) (1<<((n)+1))
149 #define SET_VERBOSE_MASK(n) (verbose |= VERBOSE_MASK (n))
150 #define CLR_VERBOSE_MASK(n) (verbose &= VERBOSE_MASK (n))
151 #define QRY_VERBOSE_MASK(n) (verbose & VERBOSE_MASK (n))
152 #define HAS_VERBOSE_MASK(n) (verbose & ~1)
153 #define SET_VERBOSE() (verbose |= 1)
154 #define CLR_VERBOSE() (verbose &= ~1)
155 #define QRY_VERBOSE() (verbose & 1)
148 156
149 /* When non-zero, this global means the user is done using this program. */ 157 /* When non-zero, this global means the user is done using this program. */
150 int done; 158 int done;
...@@ -408,10 +416,8 @@ get_bool (const char *str, int *pb) ...@@ -408,10 +416,8 @@ get_bool (const char *str, int *pb)
408 || mu_c_strcasecmp (str, "false") == 0) 416 || mu_c_strcasecmp (str, "false") == 0)
409 *pb = 0; 417 *pb = 0;
410 else 418 else
411 {
412 mu_error ("not a boolean: %s", str);
413 return 1; 419 return 1;
414 } 420
415 return 0; 421 return 0;
416 } 422 }
417 423
...@@ -509,13 +515,91 @@ find_command (char *name) ...@@ -509,13 +515,91 @@ find_command (char *name)
509 return NULL; 515 return NULL;
510 } 516 }
511 517
518 static int
519 string_to_xlev (const char *name, int *pv)
520 {
521 if (strcmp (name, "secure") == 0)
522 *pv = XSCRIPT_SECURE;
523 else if (strcmp (name, "payload") == 0)
524 *pv = XSCRIPT_PAYLOAD;
525 else
526 return 1;
527 return 0;
528 }
529
530 static int
531 change_verbose_mask (int set, int argc, char **argv)
532 {
533 int i;
534
535 for (i = 0; i < argc; i++)
536 {
537 int lev;
538
539 if (string_to_xlev (argv[i], &lev))
540 {
541 mu_error ("unknown level: %s", argv[i]);
542 return 1;
543 }
544 if (set)
545 SET_VERBOSE_MASK (lev);
546 else
547 CLR_VERBOSE_MASK (lev);
548 }
549 return 0;
550 }
551
552 void
553 set_verbose (mu_pop3_t p)
554 {
555 if (p)
556 {
557 if (QRY_VERBOSE ())
558 {
559 mu_pop3_trace (p, MU_POP3_TRACE_SET);
560 }
561 else
562 mu_pop3_trace (p, MU_POP3_TRACE_CLR);
563 }
564 }
565
566 void
567 set_verbose_mask (mu_pop3_t p)
568 {
569 if (p)
570 {
571 mu_pop3_trace_mask (p, QRY_VERBOSE_MASK (XSCRIPT_SECURE)
572 ? MU_POP3_TRACE_SET : MU_POP3_TRACE_CLR,
573 XSCRIPT_SECURE);
574 mu_pop3_trace_mask (p, QRY_VERBOSE_MASK (XSCRIPT_PAYLOAD)
575 ? MU_POP3_TRACE_SET : MU_POP3_TRACE_CLR,
576 XSCRIPT_PAYLOAD);
577 }
578 }
579
512 int 580 int
513 com_verbose (int argc, char **argv) 581 com_verbose (int argc, char **argv)
514 { 582 {
515 if (argc == 1) 583 if (argc == 1)
516 { 584 {
517 if (verbose) 585 if (QRY_VERBOSE ())
518 printf ("verbose is on\n"); 586 {
587 printf ("verbose is on");
588 if (HAS_VERBOSE_MASK ())
589 {
590 char *delim = " (";
591
592 if (QRY_VERBOSE_MASK (XSCRIPT_SECURE))
593 {
594 printf("%ssecure", delim);
595 delim = ", ";
596 }
597 if (QRY_VERBOSE_MASK (XSCRIPT_PAYLOAD))
598 printf("%spayload", delim);
599 printf (")");
600 }
601 printf ("\n");
602 }
519 else 603 else
520 printf ("verbose is off\n"); 604 printf ("verbose is off\n");
521 } 605 }
...@@ -525,16 +609,20 @@ com_verbose (int argc, char **argv) ...@@ -525,16 +609,20 @@ com_verbose (int argc, char **argv)
525 609
526 if (get_bool (argv[1], &bv) == 0) 610 if (get_bool (argv[1], &bv) == 0)
527 { 611 {
528 verbose = bv; 612 verbose |= bv;
529 if (pop3 != NULL) 613 if (argc > 2)
530 { 614 change_verbose_mask (verbose, argc - 2, argv + 2);
531 if (verbose == 1) 615 set_verbose (pop3);
532 mu_pop3_trace (pop3, MU_POP3_TRACE_SET);
533 else
534 mu_pop3_trace (pop3, MU_POP3_TRACE_CLR);
535 }
536 } 616 }
617 else if (strcmp (argv[1], "mask") == 0)
618 change_verbose_mask (1, argc - 2, argv + 2);
619 else if (strcmp (argv[1], "unmask") == 0)
620 change_verbose_mask (0, argc - 2, argv + 2);
621 else
622 mu_error ("unknown subcommand");
623 set_verbose_mask (pop3);
537 } 624 }
625
538 return 0; 626 return 0;
539 } 627 }
540 628
...@@ -929,8 +1017,11 @@ com_connect (int argc, char **argv) ...@@ -929,8 +1017,11 @@ com_connect (int argc, char **argv)
929 { 1017 {
930 mu_stream_t tcp; 1018 mu_stream_t tcp;
931 1019
932 if (verbose) 1020 if (QRY_VERBOSE ())
933 mu_pop3_trace (pop3, MU_POP3_TRACE_SET); 1021 {
1022 set_verbose (pop3);
1023 set_verbose_mask (pop3);
1024 }
934 status = mu_tcp_stream_create (&tcp, argv[0], n, MU_STREAM_READ); 1025 status = mu_tcp_stream_create (&tcp, argv[0], n, MU_STREAM_READ);
935 if (status == 0) 1026 if (status == 0)
936 { 1027 {
......
...@@ -1679,7 +1679,8 @@ imap4d_fetch (struct imap4d_command *command, imap4d_tokbuf_t tok) ...@@ -1679,7 +1679,8 @@ imap4d_fetch (struct imap4d_command *command, imap4d_tokbuf_t tok)
1679 { 1679 {
1680 int rc; 1680 int rc;
1681 char *err_text = "Completed"; 1681 char *err_text = "Completed";
1682 1682 int xlev = set_xscript_level (XSCRIPT_PAYLOAD);
1683 rc = imap4d_fetch0 (tok, 0, &err_text); 1683 rc = imap4d_fetch0 (tok, 0, &err_text);
1684 set_xscript_level (xlev);
1684 return io_completion_response (command, rc, "%s", err_text); 1685 return io_completion_response (command, rc, "%s", err_text);
1685 } 1686 }
......
...@@ -422,6 +422,8 @@ imap4d_mainloop (int fd, FILE *infile, FILE *outfile) ...@@ -422,6 +422,8 @@ imap4d_mainloop (int fd, FILE *infile, FILE *outfile)
422 RESP_PREAUTH : RESP_OK, "%s", text); 422 RESP_PREAUTH : RESP_OK, "%s", text);
423 io_flush (); 423 io_flush ();
424 424
425 set_xscript_level ((state == STATE_AUTH) ? XSCRIPT_NORMAL : XSCRIPT_SECURE);
426
425 tokp = imap4d_tokbuf_init (); 427 tokp = imap4d_tokbuf_init ();
426 while (1) 428 while (1)
427 { 429 {
......
...@@ -382,6 +382,8 @@ int is_atom (const char *s); ...@@ -382,6 +382,8 @@ int is_atom (const char *s);
382 int util_isdelim (const char *str); 382 int util_isdelim (const char *str);
383 int util_trim_nl (char *s, size_t len); 383 int util_trim_nl (char *s, size_t len);
384 384
385 int set_xscript_level (int xlev);
386
385 #ifdef WITH_TLS 387 #ifdef WITH_TLS
386 int imap4d_init_tls_server (void); 388 int imap4d_init_tls_server (void);
387 #endif /* WITH_TLS */ 389 #endif /* WITH_TLS */
......
...@@ -241,7 +241,11 @@ io_format_completion_response (mu_stream_t str, ...@@ -241,7 +241,11 @@ io_format_completion_response (mu_stream_t str,
241 new_state = STATE_NONE; 241 new_state = STATE_NONE;
242 242
243 if (new_state != STATE_NONE) 243 if (new_state != STATE_NONE)
244 {
245 if (new_state == STATE_AUTH)
246 set_xscript_level (XSCRIPT_NORMAL);
244 state = new_state; 247 state = new_state;
248 }
245 249
246 return status; 250 return status;
247 } 251 }
...@@ -570,6 +574,7 @@ imap4d_readline (struct imap4d_tokbuf *tok) ...@@ -570,6 +574,7 @@ imap4d_readline (struct imap4d_tokbuf *tok)
570 char *sp = NULL; 574 char *sp = NULL;
571 char *buf; 575 char *buf;
572 size_t len; 576 size_t len;
577 int xlev = set_xscript_level (XSCRIPT_PAYLOAD);
573 578
574 number = strtoul (last_arg + 1, &sp, 10); 579 number = strtoul (last_arg + 1, &sp, 10);
575 /* Client can ask for non-synchronised literal, 580 /* Client can ask for non-synchronised literal,
...@@ -595,6 +600,7 @@ imap4d_readline (struct imap4d_tokbuf *tok) ...@@ -595,6 +600,7 @@ imap4d_readline (struct imap4d_tokbuf *tok)
595 tok->level += len; 600 tok->level += len;
596 tok->buffer[tok->level++] = 0; 601 tok->buffer[tok->level++] = 0;
597 tok->argp[tok->argc - 1] = off; 602 tok->argp[tok->argc - 1] = off;
603 set_xscript_level (xlev);
598 } 604 }
599 else 605 else
600 break; 606 break;
......
...@@ -37,7 +37,11 @@ imap4d_uid (struct imap4d_command *command, imap4d_tokbuf_t tok) ...@@ -37,7 +37,11 @@ imap4d_uid (struct imap4d_command *command, imap4d_tokbuf_t tok)
37 cmd = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1); 37 cmd = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
38 38
39 if (mu_c_strcasecmp (cmd, "FETCH") == 0) 39 if (mu_c_strcasecmp (cmd, "FETCH") == 0)
40 {
41 int xlev = set_xscript_level (XSCRIPT_PAYLOAD);
40 rc = imap4d_fetch0 (tok, 1, &err_text); 42 rc = imap4d_fetch0 (tok, 1, &err_text);
43 set_xscript_level (xlev);
44 }
41 else if (mu_c_strcasecmp (cmd, "COPY") == 0) 45 else if (mu_c_strcasecmp (cmd, "COPY") == 0)
42 rc = imap4d_copy0 (tok, 1, &err_text); 46 rc = imap4d_copy0 (tok, 1, &err_text);
43 else if (mu_c_strcasecmp (cmd, "STORE") == 0) 47 else if (mu_c_strcasecmp (cmd, "STORE") == 0)
......
...@@ -672,3 +672,22 @@ is_atom (const char *s) ...@@ -672,3 +672,22 @@ is_atom (const char *s)
672 return 1; 672 return 1;
673 } 673 }
674 674
675 int
676 set_xscript_level (int xlev)
677 {
678 if (imap4d_transcript)
679 {
680 if (xlev != XSCRIPT_NORMAL)
681 {
682 mu_log_level_t n = xlev == XSCRIPT_SECURE ?
683 MU_DEBUG_TRACE6 : MU_DEBUG_TRACE7;
684
685 if (mu_global_debug_level ("imap4") & MU_DEBUG_LEVEL_MASK (n))
686 return XSCRIPT_NORMAL;
687 }
688
689 if (mu_stream_ioctl (iostream, MU_IOCTL_LEVEL, &xlev) == 0)
690 return xlev;
691 }
692 return 0;
693 }
......
...@@ -50,6 +50,7 @@ int mu_pop3_get_timeout (mu_pop3_t pop3, int *timeout); ...@@ -50,6 +50,7 @@ int mu_pop3_get_timeout (mu_pop3_t pop3, int *timeout);
50 #define MU_POP3_TRACE_SET 1 50 #define MU_POP3_TRACE_SET 1
51 #define MU_POP3_TRACE_QRY 2 51 #define MU_POP3_TRACE_QRY 2
52 int mu_pop3_trace (mu_pop3_t pop3, int op); 52 int mu_pop3_trace (mu_pop3_t pop3, int op);
53 int mu_pop3_trace_mask (mu_pop3_t pop3, int op, int lev);
53 54
54 int mu_pop3_apop (mu_pop3_t pop3, const char *name, const char *digest); 55 int mu_pop3_apop (mu_pop3_t pop3, const char *name, const char *digest);
55 56
......
...@@ -63,6 +63,9 @@ enum mu_buffer_type ...@@ -63,6 +63,9 @@ enum mu_buffer_type
63 #define MU_IOCTL_SET_TRANSPORT 6 63 #define MU_IOCTL_SET_TRANSPORT 6
64 #define MU_IOCTL_SWAP_STREAM 7 64 #define MU_IOCTL_SWAP_STREAM 7
65 65
66 #define MU_IOCTL_LEVEL 8
67
68
66 void mu_stream_ref (mu_stream_t stream); 69 void mu_stream_ref (mu_stream_t stream);
67 void mu_stream_unref (mu_stream_t stream); 70 void mu_stream_unref (mu_stream_t stream);
68 void mu_stream_destroy (mu_stream_t *pstream); 71 void mu_stream_destroy (mu_stream_t *pstream);
...@@ -153,9 +156,15 @@ int mu_tcp_stream_create_with_source_host (mu_stream_t *stream, ...@@ -153,9 +156,15 @@ int mu_tcp_stream_create_with_source_host (mu_stream_t *stream,
153 int mu_tcp_stream_create (mu_stream_t *stream, const char *host, int port, 156 int mu_tcp_stream_create (mu_stream_t *stream, const char *host, int port,
154 int flags); 157 int flags);
155 158
159 /* Transcript output levels */
160 #define XSCRIPT_NORMAL 0 /* Normal transcript */
161 #define XSCRIPT_SECURE 1 /* Security-related data are being sent/received */
162 #define XSCRIPT_PAYLOAD 2 /* Actual payload (may be copious) */
163
156 int mu_xscript_stream_create(mu_stream_t *pref, mu_stream_t transport, 164 int mu_xscript_stream_create(mu_stream_t *pref, mu_stream_t transport,
157 mu_stream_t logstr, 165 mu_stream_t logstr,
158 const char *prefix[]); 166 const char *prefix[]);
167
159 int mu_iostream_create (mu_stream_t *pref, mu_stream_t in, mu_stream_t out); 168 int mu_iostream_create (mu_stream_t *pref, mu_stream_t in, mu_stream_t out);
160 int mu_dbgstream_create(mu_stream_t *pref, mu_debug_t debug, 169 int mu_dbgstream_create(mu_stream_t *pref, mu_debug_t debug,
161 mu_log_level_t level, int flags); 170 mu_log_level_t level, int flags);
......
...@@ -59,6 +59,7 @@ enum mu_pop3_state ...@@ -59,6 +59,7 @@ enum mu_pop3_state
59 59
60 #define MU_POP3_ACK 0x01 60 #define MU_POP3_ACK 0x01
61 #define MU_POP3_TRACE 0x02 61 #define MU_POP3_TRACE 0x02
62 #define MU_POP3_XSCRIPT_MASK(n) (1<<((n)+1))
62 63
63 /* Structure to hold things general to POP3 mailbox, like its state, etc ... */ 64 /* Structure to hold things general to POP3 mailbox, like its state, etc ... */
64 struct _mu_pop3 65 struct _mu_pop3
...@@ -90,6 +91,8 @@ extern int mu_pop3_stream_create (mu_pop3_t pop3, mu_stream_t *pstream); ...@@ -90,6 +91,8 @@ extern int mu_pop3_stream_create (mu_pop3_t pop3, mu_stream_t *pstream);
90 extern int mu_pop3_carrier_is_ready (mu_stream_t carrier, int flag, 91 extern int mu_pop3_carrier_is_ready (mu_stream_t carrier, int flag,
91 int timeout); 92 int timeout);
92 93
94 int _mu_pop3_xscript_level (mu_pop3_t pop3, int xlev);
95
93 int _mu_pop3_trace_enable (mu_pop3_t pop3); 96 int _mu_pop3_trace_enable (mu_pop3_t pop3);
94 int _mu_pop3_trace_disable (mu_pop3_t pop3); 97 int _mu_pop3_trace_disable (mu_pop3_t pop3);
95 98
......
...@@ -27,6 +27,7 @@ struct _mu_xscript_stream ...@@ -27,6 +27,7 @@ struct _mu_xscript_stream
27 mu_stream_t transport; 27 mu_stream_t transport;
28 mu_stream_t logstr; 28 mu_stream_t logstr;
29 int flags; 29 int flags;
30 int level;
30 char *prefix[2]; 31 char *prefix[2];
31 }; 32 };
32 33
......
...@@ -161,6 +161,10 @@ pop_open (mu_mailbox_t mbox, int flags) ...@@ -161,6 +161,10 @@ pop_open (mu_mailbox_t mbox, int flags)
161 161
162 if (mu_debug_check_level (mbox->debug, MU_DEBUG_PROT)) 162 if (mu_debug_check_level (mbox->debug, MU_DEBUG_PROT))
163 mu_pop3_trace (mpd->pop3, MU_POP3_TRACE_SET); 163 mu_pop3_trace (mpd->pop3, MU_POP3_TRACE_SET);
164 if (mu_debug_check_level (mbox->debug, MU_DEBUG_TRACE6))
165 mu_pop3_trace_mask (mpd->pop3, MU_POP3_TRACE_SET, XSCRIPT_SECURE);
166 if (mu_debug_check_level (mbox->debug, MU_DEBUG_TRACE7))
167 mu_pop3_trace_mask (mpd->pop3, MU_POP3_TRACE_SET, XSCRIPT_PAYLOAD);
164 168
165 do 169 do
166 { 170 {
...@@ -214,7 +218,7 @@ pop_destroy (mu_mailbox_t mbox) ...@@ -214,7 +218,7 @@ pop_destroy (mu_mailbox_t mbox)
214 { 218 {
215 size_t i; 219 size_t i;
216 mu_monitor_wrlock (mbox->monitor); 220 mu_monitor_wrlock (mbox->monitor);
217 /* Destroy the pop messages and ressources associated to them. */ 221 /* Destroy the pop messages and resources associated to them. */
218 for (i = 0; i < mpd->msg_count; i++) 222 for (i = 0; i < mpd->msg_count; i++)
219 { 223 {
220 if (mpd->msg[i]) 224 if (mpd->msg[i])
...@@ -291,7 +295,7 @@ pop_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount) ...@@ -291,7 +295,7 @@ pop_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount)
291 if (mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD, 295 if (mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD,
292 &tmp) != 0) 296 &tmp) != 0)
293 break; 297 break;
294 if (((i +1) % 10) == 0) 298 if (((i + 1) % 10) == 0)
295 { 299 {
296 mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_PROGRESS, 300 mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_PROGRESS,
297 NULL); 301 NULL);
......
...@@ -35,7 +35,10 @@ mu_pop3_pass (mu_pop3_t pop3, const char *passwd) ...@@ -35,7 +35,10 @@ mu_pop3_pass (mu_pop3_t pop3, const char *passwd)
35 switch (pop3->state) 35 switch (pop3->state)
36 { 36 {
37 case MU_POP3_NO_STATE: 37 case MU_POP3_NO_STATE:
38 if (mu_pop3_trace_mask (pop3, MU_POP3_TRACE_QRY, XSCRIPT_SECURE))
39 _mu_pop3_xscript_level (pop3, XSCRIPT_SECURE);
38 status = mu_pop3_writeline (pop3, "PASS %s\r\n", passwd); 40 status = mu_pop3_writeline (pop3, "PASS %s\r\n", passwd);
41 _mu_pop3_xscript_level (pop3, XSCRIPT_NORMAL);
39 MU_POP3_CHECK_ERROR (pop3, status); 42 MU_POP3_CHECK_ERROR (pop3, status);
40 /* FIXME: how to obscure the passwd in the stream buffer? */ 43 /* FIXME: how to obscure the passwd in the stream buffer? */
41 MU_POP3_FCLR (pop3, MU_POP3_ACK); 44 MU_POP3_FCLR (pop3, MU_POP3_ACK);
......
...@@ -50,6 +50,8 @@ mu_pop3_retr (mu_pop3_t pop3, unsigned int msgno, mu_stream_t *pstream) ...@@ -50,6 +50,8 @@ mu_pop3_retr (mu_pop3_t pop3, unsigned int msgno, mu_stream_t *pstream)
50 MU_POP3_CHECK_OK (pop3); 50 MU_POP3_CHECK_OK (pop3);
51 status = mu_pop3_stream_create (pop3, pstream); 51 status = mu_pop3_stream_create (pop3, pstream);
52 MU_POP3_CHECK_ERROR (pop3, status); 52 MU_POP3_CHECK_ERROR (pop3, status);
53 if (mu_pop3_trace_mask (pop3, MU_POP3_TRACE_QRY, XSCRIPT_PAYLOAD))
54 _mu_pop3_xscript_level (pop3, XSCRIPT_PAYLOAD);
53 pop3->state = MU_POP3_RETR_RX; 55 pop3->state = MU_POP3_RETR_RX;
54 56
55 case MU_POP3_RETR_RX: 57 case MU_POP3_RETR_RX:
......
...@@ -185,6 +185,7 @@ _pop3_event_cb (mu_stream_t str, int ev, int flags) ...@@ -185,6 +185,7 @@ _pop3_event_cb (mu_stream_t str, int ev, int flags)
185 if (mu_stream_ioctl (str, MU_IOCTL_GET_TRANSPORT, trans) == 0) 185 if (mu_stream_ioctl (str, MU_IOCTL_GET_TRANSPORT, trans) == 0)
186 { 186 {
187 struct mu_pop3_stream *sp = (struct mu_pop3_stream *) trans[0]; 187 struct mu_pop3_stream *sp = (struct mu_pop3_stream *) trans[0];
188 _mu_pop3_xscript_level (sp->pop3, XSCRIPT_NORMAL);
188 sp->pop3->state = MU_POP3_NO_STATE; 189 sp->pop3->state = MU_POP3_NO_STATE;
189 } 190 }
190 } 191 }
......
...@@ -50,6 +50,8 @@ mu_pop3_top (mu_pop3_t pop3, unsigned msgno, unsigned int lines, ...@@ -50,6 +50,8 @@ mu_pop3_top (mu_pop3_t pop3, unsigned msgno, unsigned int lines,
50 MU_POP3_CHECK_OK (pop3); 50 MU_POP3_CHECK_OK (pop3);
51 status = mu_pop3_stream_create (pop3, pstream); 51 status = mu_pop3_stream_create (pop3, pstream);
52 MU_POP3_CHECK_ERROR (pop3, status); 52 MU_POP3_CHECK_ERROR (pop3, status);
53 if (mu_pop3_trace_mask (pop3, MU_POP3_TRACE_QRY, XSCRIPT_PAYLOAD))
54 _mu_pop3_xscript_level (pop3, XSCRIPT_PAYLOAD);
53 pop3->state = MU_POP3_TOP_RX; 55 pop3->state = MU_POP3_TOP_RX;
54 56
55 case MU_POP3_TOP_RX: 57 case MU_POP3_TOP_RX:
......
...@@ -115,4 +115,36 @@ mu_pop3_trace (mu_pop3_t pop3, int op) ...@@ -115,4 +115,36 @@ mu_pop3_trace (mu_pop3_t pop3, int op)
115 return EINVAL; 115 return EINVAL;
116 } 116 }
117 117
118 int
119 mu_pop3_trace_mask (mu_pop3_t pop3, int op, int lev)
120 {
121 switch (op)
122 {
123 case MU_POP3_TRACE_SET:
124 pop3->flags |= MU_POP3_XSCRIPT_MASK(lev);
125 break;
126
127 case MU_POP3_TRACE_CLR:
128 pop3->flags &= ~MU_POP3_XSCRIPT_MASK(lev);
129 break;
130
131 case MU_POP3_TRACE_QRY:
132 if (pop3->flags & MU_POP3_XSCRIPT_MASK(lev))
133 break;
134 return MU_ERR_NOENT;
135
136 default:
137 return EINVAL;
138 }
139 return 0;
140 }
141
142 int
143 _mu_pop3_xscript_level (mu_pop3_t pop3, int xlev)
144 {
145 if (mu_stream_ioctl (pop3->carrier, MU_IOCTL_LEVEL, &xlev) == 0)
146 return xlev;
147 return XSCRIPT_NORMAL;
148 }
149
118 150
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
30 #include <mailutils/stream.h> 30 #include <mailutils/stream.h>
31 #include <mailutils/sys/stream.h> 31 #include <mailutils/sys/stream.h>
32 #include <mailutils/sys/xscript-stream.h> 32 #include <mailutils/sys/xscript-stream.h>
33 #include <mailutils/cctype.h>
34 #include <mailutils/cstr.h>
33 35
34 /* A "transcript stream" transparently writes data to and reads data from 36 /* A "transcript stream" transparently writes data to and reads data from
35 an underlying transport stream, writing each lineful of data to a "log 37 an underlying transport stream, writing each lineful of data to a "log
...@@ -40,8 +42,50 @@ ...@@ -40,8 +42,50 @@
40 42
41 #define TRANS_READ 0x1 43 #define TRANS_READ 0x1
42 #define TRANS_WRITE 0x2 44 #define TRANS_WRITE 0x2
45 #define TRANS_DISABLED 0x4
43 #define FLAG_TO_PFX(c) ((c) - 1) 46 #define FLAG_TO_PFX(c) ((c) - 1)
44 47
48 static int
49 word_match (const char *buf, size_t len, int n, const char *word,
50 size_t *pos)
51 {
52 size_t i = 0;
53 size_t wl = strlen (word);
54
55 for (;; n--)
56 {
57 /* Skip whitespace separator */
58 for (; i < len && mu_isspace (buf[i]); i++)
59 ;
60
61 if (n == 0)
62 break;
63
64 /* Skip the argument */
65 if (buf[i] == '"')
66 {
67 for (i++; i < len && buf[i] != '"'; i++)
68 if (buf[i] == '\'')
69 i++;
70 }
71 else
72 {
73 for (; i < len && !mu_isspace (buf[i]); i++)
74 ;
75 }
76 }
77
78 if (i + wl <= len &&
79 mu_c_strncasecmp (buf + i, word, wl) == 0 &&
80 mu_isblank (buf[i + wl]))
81 {
82 *pos = i + wl;
83 return 1;
84 }
85
86 return 0;
87 }
88
45 static void 89 static void
46 print_transcript (struct _mu_xscript_stream *str, int flag, 90 print_transcript (struct _mu_xscript_stream *str, int flag,
47 const char *buf, size_t size) 91 const char *buf, size_t size)
...@@ -57,14 +101,56 @@ print_transcript (struct _mu_xscript_stream *str, int flag, ...@@ -57,14 +101,56 @@ print_transcript (struct _mu_xscript_stream *str, int flag,
57 str->prefix[FLAG_TO_PFX(flag)], 101 str->prefix[FLAG_TO_PFX(flag)],
58 strlen (str->prefix[FLAG_TO_PFX (flag)]), 102 strlen (str->prefix[FLAG_TO_PFX (flag)]),
59 NULL); 103 NULL);
60 str->flags &= ~flag; 104 str->flags &= ~(flag | TRANS_DISABLED);
105 }
106
107 if (str->flags & TRANS_DISABLED)
108 return;
109
110 if (str->level == XSCRIPT_PAYLOAD)
111 {
112 mu_stream_printf (str->logstr, "(data...)\n");
113 str->flags |= TRANS_DISABLED;
114 return;
61 } 115 }
116
62 p = memchr (buf, '\n', size); 117 p = memchr (buf, '\n', size);
63 if (p) 118 if (p)
64 { 119 {
65 len = p - buf; 120 len = p - buf;
66 if (p > buf && p[-1] == '\r') 121 if (p > buf && p[-1] == '\r')
67 len--; 122 len--;
123
124 if (str->level == XSCRIPT_SECURE)
125 {
126 size_t i;
127
128 if (word_match (buf, len, 0, "PASS", &i))
129 mu_stream_printf (str->logstr, "PASS ***");
130 else if (word_match (buf, len, 1, "LOGIN", &i))
131 {
132 /* Skip the whitespace separator */
133 for (; i < len && mu_isspace (buf[i]); i++)
134 ;
135 /* Skip the first argument (presumably the user name) */
136 if (buf[i] == '"')
137 {
138 for (i++; i < len && buf[i] != '"'; i++)
139 if (buf[i] == '\'')
140 i++;
141 }
142 else
143 {
144 for (; i < len && !mu_isspace (buf[i]); i++)
145 ;
146 }
147 mu_stream_write (str->logstr, buf, i, NULL);
148 mu_stream_write (str->logstr, " \"***\"", 6, NULL);
149 }
150 else
151 mu_stream_write (str->logstr, buf, len, NULL);
152 }
153 else
68 mu_stream_write (str->logstr, buf, len, NULL); 154 mu_stream_write (str->logstr, buf, len, NULL);
69 mu_stream_write (str->logstr, "\n", 1, NULL); 155 mu_stream_write (str->logstr, "\n", 1, NULL);
70 str->flags |= flag; 156 str->flags |= flag;
...@@ -229,6 +315,18 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg) ...@@ -229,6 +315,18 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg)
229 } 315 }
230 break; 316 break;
231 317
318 case MU_IOCTL_LEVEL:
319 if (!arg)
320 return EINVAL;
321 else
322 {
323 int oldlev = sp->level;
324 sp->level = *(int*)arg;
325 sp->flags = TRANS_READ | TRANS_WRITE;
326 *(int*)arg = oldlev;
327 }
328 break;
329
232 default: 330 default:
233 return mu_stream_ioctl (sp->transport, op, arg); 331 return mu_stream_ioctl (sp->transport, op, arg);
234 } 332 }
......
...@@ -338,3 +338,23 @@ pop3d_undelete_all () ...@@ -338,3 +338,23 @@ pop3d_undelete_all ()
338 mu_attribute_unset_deleted (attr); 338 mu_attribute_unset_deleted (attr);
339 } 339 }
340 } 340 }
341
342 int
343 set_xscript_level (int xlev)
344 {
345 if (pop3d_transcript)
346 {
347 if (xlev != XSCRIPT_NORMAL)
348 {
349 mu_log_level_t n = xlev == XSCRIPT_SECURE ?
350 MU_DEBUG_TRACE6 : MU_DEBUG_TRACE7;
351
352 if (mu_global_debug_level ("pop3") & MU_DEBUG_LEVEL_MASK (n))
353 return XSCRIPT_NORMAL;
354 }
355
356 if (mu_stream_ioctl (iostream, MU_IOCTL_LEVEL, &xlev) == 0)
357 return xlev;
358 }
359 return 0;
360 }
......
...@@ -265,4 +265,6 @@ extern int set_bulletin_source (const char *source); ...@@ -265,4 +265,6 @@ extern int set_bulletin_source (const char *source);
265 extern int pop3d_begin_session (void); 265 extern int pop3d_begin_session (void);
266 extern const char *pop3d_error_string (int code); 266 extern const char *pop3d_error_string (int code);
267 267
268 extern int set_xscript_level (int xlev);
269
268 #endif /* _POP3D_H */ 270 #endif /* _POP3D_H */
......
...@@ -26,6 +26,7 @@ pop3d_retr (char *arg) ...@@ -26,6 +26,7 @@ pop3d_retr (char *arg)
26 mu_message_t msg = NULL; 26 mu_message_t msg = NULL;
27 mu_attribute_t attr = NULL; 27 mu_attribute_t attr = NULL;
28 mu_stream_t stream; 28 mu_stream_t stream;
29 int xscript_level;
29 30
30 if ((strlen (arg) == 0) || (strchr (arg, ' ') != NULL)) 31 if ((strlen (arg) == 0) || (strchr (arg, ' ') != NULL))
31 return ERR_BAD_ARGS; 32 return ERR_BAD_ARGS;
...@@ -46,6 +47,7 @@ pop3d_retr (char *arg) ...@@ -46,6 +47,7 @@ pop3d_retr (char *arg)
46 return ERR_UNKNOWN; 47 return ERR_UNKNOWN;
47 48
48 pop3d_outf ("+OK\n"); 49 pop3d_outf ("+OK\n");
50 xscript_level = set_xscript_level (XSCRIPT_PAYLOAD);
49 mu_stream_copy (iostream, stream, 0, NULL); 51 mu_stream_copy (iostream, stream, 0, NULL);
50 mu_stream_destroy (&stream); 52 mu_stream_destroy (&stream);
51 53
...@@ -56,5 +58,7 @@ pop3d_retr (char *arg) ...@@ -56,5 +58,7 @@ pop3d_retr (char *arg)
56 58
57 pop3d_outf (".\n"); 59 pop3d_outf (".\n");
58 60
61 set_xscript_level (xscript_level);
62
59 return OK; 63 return OK;
60 } 64 }
......
...@@ -30,6 +30,7 @@ pop3d_top (char *arg) ...@@ -30,6 +30,7 @@ pop3d_top (char *arg)
30 mu_body_t body; 30 mu_body_t body;
31 mu_stream_t stream; 31 mu_stream_t stream;
32 char *mesgc, *linesc, *p; 32 char *mesgc, *linesc, *p;
33 int xscript_level;
33 34
34 if (strlen (arg) == 0) 35 if (strlen (arg) == 0)
35 return ERR_BAD_ARGS; 36 return ERR_BAD_ARGS;
...@@ -62,6 +63,8 @@ pop3d_top (char *arg) ...@@ -62,6 +63,8 @@ pop3d_top (char *arg)
62 return ERR_UNKNOWN; 63 return ERR_UNKNOWN;
63 pop3d_outf ("+OK\n"); 64 pop3d_outf ("+OK\n");
64 65
66 xscript_level = set_xscript_level (XSCRIPT_PAYLOAD);
67
65 mu_stream_copy (iostream, stream, 0, NULL); 68 mu_stream_copy (iostream, stream, 0, NULL);
66 pop3d_outf ("\n"); 69 pop3d_outf ("\n");
67 mu_stream_destroy (&stream); 70 mu_stream_destroy (&stream);
...@@ -85,5 +88,7 @@ pop3d_top (char *arg) ...@@ -85,5 +88,7 @@ pop3d_top (char *arg)
85 88
86 pop3d_outf (".\n"); 89 pop3d_outf (".\n");
87 90
91 set_xscript_level (xscript_level);
92
88 return OK; 93 return OK;
89 } 94 }
......
...@@ -91,6 +91,7 @@ pop3d_user (char *arg) ...@@ -91,6 +91,7 @@ pop3d_user (char *arg)
91 { 91 {
92 char *buf, *pass, *cmd; 92 char *buf, *pass, *cmd;
93 char buffer[512]; 93 char buffer[512];
94 int xscript_level;
94 95
95 if (state != AUTHORIZATION) 96 if (state != AUTHORIZATION)
96 return ERR_WRONG_STATE; 97 return ERR_WRONG_STATE;
...@@ -101,8 +102,10 @@ pop3d_user (char *arg) ...@@ -101,8 +102,10 @@ pop3d_user (char *arg)
101 pop3d_outf ("+OK\n"); 102 pop3d_outf ("+OK\n");
102 pop3d_flush_output (); 103 pop3d_flush_output ();
103 104
105 xscript_level = set_xscript_level (XSCRIPT_SECURE);
104 buf = pop3d_readline (buffer, sizeof (buffer)); 106 buf = pop3d_readline (buffer, sizeof (buffer));
105 pop3d_parse_command (buf, &cmd, &pass); 107 pop3d_parse_command (buf, &cmd, &pass);
108 set_xscript_level (xscript_level);
106 109
107 if (mu_c_strcasecmp (cmd, "PASS") == 0) 110 if (mu_c_strcasecmp (cmd, "PASS") == 0)
108 { 111 {
......