diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-08-30 00:08:31 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-08-30 00:08:31 +0300 |
commit | 286657e78705d061fc68c000cd3823608c522c04 (patch) | |
tree | cbb2cc2834a17d56f3a9332aee2da80c2e0f1921 | |
parent | f4e67b5e949b324617b7c737d63455f0c0da1371 (diff) | |
download | mailutils-286657e78705d061fc68c000cd3823608c522c04.tar.gz mailutils-286657e78705d061fc68c000cd3823608c522c04.tar.bz2 |
Re-implement server TLS support.
STLS in pop3d is already working.
* include/mailutils/sys/tls-stream.h: New header.
* include/mailutils/tls.h (mu_tls_stream_create)
(mu_tls_stream_create_client)
(mu_tls_stream_create_client_from_tcp): Remove.
(mu_tls_server_stream_create, mu_tls_client_stream_create): New
protos.
* libmu_auth/tls.c: Rewrite.
* imap4d/util.c: Use mu_tls_server_stream_create.
* libproto/pop/mbox.c: Use mu_tls_server_stream_create/
mu_tls_client_stream_create.
* libproto/pop/pop3_stls.c: Use mu_tls_client_stream_create.
* libproto/imap/folder.c: Use mu_tls_client_stream_create.
* pop3d/capa.c (pop3d_capa): CAPA is allowed in both states.
* pop3d/extra.c (pop3d_setio): Rewrite.
-rw-r--r-- | imap4d/util.c | 2 | ||||
-rw-r--r-- | include/mailutils/sys/Makefile.am | 1 | ||||
-rw-r--r-- | include/mailutils/sys/tls-stream.h | 57 | ||||
-rw-r--r-- | include/mailutils/tls.h | 11 | ||||
-rw-r--r-- | libmu_auth/tls.c | 541 | ||||
-rw-r--r-- | libproto/imap/folder.c | 6 | ||||
-rw-r--r-- | libproto/pop/mbox.c | 14 | ||||
-rw-r--r-- | libproto/pop/pop3_stls.c | 4 | ||||
-rw-r--r-- | pop3d/capa.c | 3 | ||||
-rw-r--r-- | pop3d/extra.c | 28 |
10 files changed, 391 insertions, 276 deletions
diff --git a/imap4d/util.c b/imap4d/util.c index 26a1a8db3..294782370 100644 --- a/imap4d/util.c +++ b/imap4d/util.c @@ -893,7 +893,7 @@ imap4d_init_tls_server () mu_stream_t stream; int rc; - rc = mu_tls_stream_create (&stream, istream, ostream, 0); + rc = mu_tls_server_stream_create (&stream, istream, ostream, 0); if (rc) return 0; diff --git a/include/mailutils/sys/Makefile.am b/include/mailutils/sys/Makefile.am index 79d94cd41..34f995b59 100644 --- a/include/mailutils/sys/Makefile.am +++ b/include/mailutils/sys/Makefile.am @@ -34,5 +34,6 @@ sysinclude_HEADERS = \ streamref.h\ streamtrans.h\ stream.h\ + tls-stream.h\ pop3.h\ nntp.h diff --git a/include/mailutils/sys/tls-stream.h b/include/mailutils/sys/tls-stream.h new file mode 100644 index 000000000..8a903b947 --- /dev/null +++ b/include/mailutils/sys/tls-stream.h @@ -0,0 +1,57 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2010 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _MAILUTILS_SYS_TLS_STREAM_H +# define _MAILUTILS_SYS_TLS_STREAM_H + +# include <mailutils/types.h> +# include <mailutils/stream.h> +# include <mailutils/sys/stream.h> + +enum _mu_tls_stream_state + { + state_init, + state_open, + state_closed, + state_destroyed + }; + +struct _mu_tls_io_stream +{ + struct _mu_stream stream; + mu_stream_t transport; + struct _mu_tls_stream *up; +}; + +struct _mu_tls_stream +{ + struct _mu_stream stream; + enum _mu_tls_stream_state state; + gnutls_session session; + int tls_err; + mu_stream_t transport[2]; +}; + +struct _mu_tls_stream_s +{ + struct _mu_stream stream; + enum _mu_tls_stream_state state; + gnutls_session session; + int tls_err; + mu_stream_t transport; +}; + +#endif diff --git a/include/mailutils/tls.h b/include/mailutils/tls.h index 9848f824c..856e474d7 100644 --- a/include/mailutils/tls.h +++ b/include/mailutils/tls.h @@ -36,15 +36,12 @@ struct mu_tls_module_config extern int mu_tls_module_init (enum mu_gocs_op, void *); -extern int mu_tls_stream_create (mu_stream_t *stream, - mu_stream_t strin, mu_stream_t strout, - int flags); -extern int mu_tls_stream_create_client (mu_stream_t *stream, +extern int mu_tls_server_stream_create (mu_stream_t *stream, + mu_stream_t strin, mu_stream_t strout, + int flags); +extern int mu_tls_client_stream_create (mu_stream_t *stream, mu_stream_t strin, mu_stream_t strout, int flags); -extern int mu_tls_stream_create_client_from_tcp (mu_stream_t *stream, - mu_stream_t tcp_str, - int flags); extern int mu_check_tls_environment (void); extern int mu_init_tls_libs (void); diff --git a/libmu_auth/tls.c b/libmu_auth/tls.c index 5ce9bc7ff..7dff47858 100644 --- a/libmu_auth/tls.c +++ b/libmu_auth/tls.c @@ -35,8 +35,6 @@ #include <mailutils/stream.h> #include <mailutils/errno.h> -#include <lbuf.h> - struct mu_tls_module_config mu_tls_module_config = { 1, NULL, NULL, NULL }; int @@ -48,7 +46,7 @@ mu_tls_module_init (enum mu_gocs_op op, void *data) if (data) memcpy (&mu_tls_module_config, data, sizeof mu_tls_module_config); break; - + case mu_gocs_op_flush: #ifdef WITH_TLS mu_init_tls_libs (); @@ -61,6 +59,7 @@ mu_tls_module_init (enum mu_gocs_op op, void *data) #ifdef WITH_TLS #include <gnutls/gnutls.h> +#include <mailutils/sys/tls-stream.h> #define DH_BITS 768 @@ -170,7 +169,7 @@ mu_tls_begin (void *iodata, for (i = 0; keywords[i]; i++) { switch (i) - { + { case 0: /* * Send STLS/STARTTLS @@ -190,10 +189,10 @@ mu_tls_begin (void *iodata, } stream_ctl (iodata, &oldstr, NULL); - status = mu_tls_stream_create_client_from_tcp (&newstr, oldstr, 0); + status = mu_tls_client_stream_create (&newstr, oldstr, oldstr, 0); if (status != 0) { - mu_error ("mu_tls_begin: mu_tls_stream_create_client_from_tcp (0): %s", + mu_error ("mu_tls_begin: mu_tls_client_stream_create(0): %s", mu_strerror (status)); return status; } @@ -228,124 +227,67 @@ mu_tls_begin (void *iodata, } break; - default: - return 1; - } + default: + return 1; + } } return 0; } - + /* ************************* TLS Stream Support **************************** */ -enum tls_stream_state { - state_init, - state_open, - state_closed, - state_destroyed -}; - -struct _tls_stream { - mu_stream_t strin; /* Input stream */ - mu_stream_t strout; /* Output stream */ - int last_err; - struct _line_buffer *lb; - enum tls_stream_state state; - gnutls_session session; -}; - - -static void -_tls_destroy (mu_stream_t stream) +static int +_tls_io_close (mu_stream_t stream) { - struct _tls_stream *s = mu_stream_get_owner (stream); - int flags; + struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; - if (x509_cred) - gnutls_certificate_free_credentials (x509_cred); - if (s->session && s->state == state_closed) - { - gnutls_deinit (s->session); - s->state = state_destroyed; - } - _auth_lb_destroy (&s->lb); + if (!(sp->stream.flags & MU_STREAM_NO_CLOSE)) + return mu_stream_close (sp->transport); + return 0; +} - mu_stream_get_flags (stream, &flags); - if (!(flags & MU_STREAM_NO_CLOSE)) - { - int same_stream = s->strin == s->strout; - mu_stream_destroy (&s->strin, mu_stream_get_owner (s->strin)); - if (!same_stream) - mu_stream_destroy (&s->strout, mu_stream_get_owner (s->strout)); - } - free (s); +static void +_tls_io_done (struct _mu_stream *stream) +{ + struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; + if (!(sp->stream.flags & MU_STREAM_NO_CLOSE)) + mu_stream_unref (sp->transport); } - + static int -_tls_read (mu_stream_t stream, char *optr, size_t osize, - mu_off_t offset, size_t *nbytes) +_tls_io_flush (struct _mu_stream *stream) { - struct _tls_stream *s = mu_stream_get_owner (stream); - int rc; - - if (!stream || s->state != state_open) - return EINVAL; - rc = gnutls_record_recv (s->session, optr, osize); - if (rc >= 0) - { - *nbytes = rc; - return 0; - } - s->last_err = rc; - return EIO; + struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; + return mu_stream_flush (sp->transport); } static int -_tls_readline (mu_stream_t stream, char *optr, size_t osize, - mu_off_t offset, size_t *nbytes) +_tls_io_read (struct _mu_stream *stream, char *buf, size_t bufsize, + size_t *pnread) { - struct _tls_stream *s = mu_stream_get_owner (stream); + struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; int rc; - char *ptr; - size_t rdsize; - if (!stream || s->state != state_open || osize < 2) + if (sp->up->state != state_open) return EINVAL; - - if (_auth_lb_level (s->lb) == 0) + rc = gnutls_record_recv (sp->up->session, buf, bufsize); + if (rc >= 0) { - ptr = optr; - rdsize = 0; - do - { - rc = gnutls_record_recv (s->session, ptr + rdsize, osize - rdsize); - if (rc < 0) - { - s->last_err = rc; - return EIO; - } - rdsize += rc; - } - while (osize > rdsize && rc > 0 && ptr[rdsize-1] != '\n'); - - _auth_lb_grow (s->lb, ptr, rdsize); + *pnread = rc; + return 0; } - - osize--; /* Allow for terminating zero */ - rdsize = _auth_lb_readline (s->lb, optr, osize); - optr[rdsize] = 0; - if (nbytes) - *nbytes = rdsize; - return 0; + sp->up->tls_err = rc; + return EIO; } static int -_tls_write (mu_stream_t stream, const char *iptr, size_t isize, - mu_off_t offset, size_t *nbytes) +_tls_io_write (struct _mu_stream *stream, const char *buf, size_t bufsize, + size_t *pnwrite) { - struct _tls_stream *s = mu_stream_get_owner (stream); + struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; int rc; - if (!stream || s->state != state_open) + if (sp->up->state != state_open) return EINVAL; /* gnutls_record_send() docs say: @@ -356,53 +298,103 @@ _tls_write (mu_stream_t stream, const char *iptr, size_t isize, corrupted and the connection will be terminated. */ do - rc = gnutls_record_send (s->session, iptr, isize); + rc = gnutls_record_send (sp->up->session, buf, bufsize); while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN); if (rc < 0) { - s->last_err = rc; + sp->up->tls_err = rc; return EIO; } - if (nbytes) - *nbytes = rc; + *pnwrite = rc; return 0; } static int -_tls_flush (mu_stream_t stream) +_tls_rd_wait (struct _mu_stream *stream, int *pflags, struct timeval *tvp) { - struct _tls_stream *s = mu_stream_get_owner (stream); - return mu_stream_flush (s->strout); + struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; + int rc = EINVAL; + + if (*pflags == MU_STREAM_READY_RD) + rc = mu_stream_wait (sp->transport, pflags, tvp); + return rc; } static int -_tls_close (mu_stream_t stream) +_tls_wr_wait (struct _mu_stream *stream, int *pflags, struct timeval *tvp) { - struct _tls_stream *s = mu_stream_get_owner (stream); - int flags; + struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; + int rc = EINVAL; - if (s->session && s->state == state_open) + if (*pflags == MU_STREAM_READY_WR) + rc = mu_stream_wait (sp->transport, pflags, tvp); + return rc; +} + +static int +_tls_io_ioctl (struct _mu_stream *stream, int op, void *arg) +{ + struct _mu_tls_io_stream *sp = (struct _mu_tls_io_stream *) stream; + mu_transport_t *ptrans; + + switch (op) + { + case MU_IOCTL_GET_TRANSPORT: + if (!arg) + return EINVAL; + ptrans = arg; + ptrans[0] = (mu_transport_t) sp->transport; + ptrans[1] = NULL; + break; + + default: + return EINVAL; + } + return 0; +} + +static int +_mu_tls_io_stream_create (mu_stream_t *pstream, + mu_stream_t transport, int flags, + struct _mu_tls_stream *master) +{ + struct _mu_tls_io_stream *sp; + + sp = (struct _mu_tls_io_stream *) + _mu_stream_create (sizeof (*sp), + flags & (MU_STREAM_RDWR | MU_STREAM_NO_CLOSE)); + if (!sp) + return ENOMEM; + + if (flags & MU_STREAM_READ) { - gnutls_bye (s->session, GNUTLS_SHUT_RDWR); - s->state = state_closed; + sp->stream.read = _tls_io_read; + sp->stream.wait = _tls_rd_wait; + mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_full, 1024); } - - mu_stream_get_flags (stream, &flags); - if (!(flags & MU_STREAM_NO_CLOSE)) + else { - mu_stream_close (s->strin); - if (s->strin != s->strout) - mu_stream_close (s->strout); + sp->stream.write = _tls_io_write; + sp->stream.wait = _tls_wr_wait; + mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_line, 1024); } + sp->stream.flush = _tls_io_flush; + sp->stream.close = _tls_io_close; + sp->stream.done = _tls_io_done; + sp->stream.ctl = _tls_io_ioctl; + /* FIXME: + sp->stream.error_string = _tls_error_string;*/ + + sp->transport = transport; + sp->up = master; + *pstream = (mu_stream_t) sp; return 0; } -/* Push & pull functions */ - static ssize_t _tls_stream_pull (gnutls_transport_ptr fd, void *buf, size_t size) { @@ -424,7 +416,7 @@ _tls_stream_push (gnutls_transport_ptr fd, const void *buf, size_t size) mu_stream_t stream = fd; int rc; - rc = mu_stream_write (stream, buf, size); + rc = mu_stream_write (stream, buf, size, &size); if (rc) { mu_error ("_tls_stream_push: %s", mu_strerror (rc)); /* FIXME */ @@ -435,14 +427,14 @@ _tls_stream_push (gnutls_transport_ptr fd, const void *buf, size_t size) } - static int -_tls_open (mu_stream_t stream) +_tls_server_open (mu_stream_t stream) { - struct _tls_stream *s = mu_stream_get_owner (stream); + struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; int rc = 0; + mu_transport_t transport[2]; - if (!stream || s->state != state_init) + if (!stream || sp->state != state_init) return EINVAL; gnutls_certificate_allocate_credentials (&x509_cred); @@ -451,40 +443,41 @@ _tls_open (mu_stream_t stream) gnutls_certificate_set_x509_trust_file (x509_cred, mu_tls_module_config.ssl_cafile, GNUTLS_X509_FMT_PEM); - + rc = gnutls_certificate_set_x509_key_file (x509_cred, mu_tls_module_config.ssl_cert, mu_tls_module_config.ssl_key, GNUTLS_X509_FMT_PEM); if (rc < 0) { - s->last_err = rc; + sp->tls_err = rc; return EIO; } generate_dh_params (); gnutls_certificate_set_dh_params (x509_cred, dh_params); - s->session = initialize_tls_session (); - gnutls_transport_set_ptr2 (s->session, - (gnutls_transport_ptr) s->strin, - (gnutls_transport_ptr) s->strout); - gnutls_transport_set_pull_function (s->session, _tls_stream_pull); - gnutls_transport_set_push_function (s->session, _tls_stream_push); + sp->session = initialize_tls_session (); + mu_stream_ioctl (stream, MU_IOCTL_GET_TRANSPORT, transport); + gnutls_transport_set_ptr2 (sp->session, + (gnutls_transport_ptr) transport[0], + (gnutls_transport_ptr) transport[1]); + gnutls_transport_set_pull_function (sp->session, _tls_stream_pull); + gnutls_transport_set_push_function (sp->session, _tls_stream_push); - rc = gnutls_handshake (s->session); + rc = gnutls_handshake (sp->session); if (rc < 0) { - gnutls_deinit (s->session); - s->last_err = rc; + gnutls_deinit (sp->session); + sp->tls_err = rc; return EIO; } - s->state = state_open; + sp->state = state_open; return 0; } static int -prepare_client_session (struct _tls_stream *s) +prepare_client_session (struct _mu_tls_stream *sp) { int rc; static int protocol_priority[] = {GNUTLS_TLS1, GNUTLS_SSL3, 0}; @@ -495,12 +488,12 @@ prepare_client_session (struct _tls_stream *s) static int comp_priority[] = {GNUTLS_COMP_NULL, 0}; static int mac_priority[] = {GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0}; - gnutls_init (&s->session, GNUTLS_CLIENT); - gnutls_protocol_set_priority (s->session, protocol_priority); - gnutls_cipher_set_priority (s->session, cipher_priority); - gnutls_compression_set_priority (s->session, comp_priority); - gnutls_kx_set_priority (s->session, kx_priority); - gnutls_mac_set_priority (s->session, mac_priority); + gnutls_init (&sp->session, GNUTLS_CLIENT); + gnutls_protocol_set_priority (sp->session, protocol_priority); + gnutls_cipher_set_priority (sp->session, cipher_priority); + gnutls_compression_set_priority (sp->session, comp_priority); + gnutls_kx_set_priority (sp->session, kx_priority); + gnutls_mac_set_priority (sp->session, mac_priority); gnutls_certificate_allocate_credentials (&x509_cred); if (mu_tls_module_config.ssl_cafile) @@ -510,44 +503,44 @@ prepare_client_session (struct _tls_stream *s) GNUTLS_X509_FMT_PEM); if (rc < 0) { - s->last_err = rc; + sp->tls_err = rc; return -1; } } - gnutls_credentials_set (s->session, GNUTLS_CRD_CERTIFICATE, x509_cred); + gnutls_credentials_set (sp->session, GNUTLS_CRD_CERTIFICATE, x509_cred); - gnutls_transport_set_ptr2 (s->session, - (gnutls_transport_ptr) s->strin, - (gnutls_transport_ptr) s->strout); - gnutls_transport_set_pull_function (s->session, _tls_stream_pull); - gnutls_transport_set_push_function (s->session, _tls_stream_push); + gnutls_transport_set_ptr2 (sp->session, + (gnutls_transport_ptr) sp->transport[0], + (gnutls_transport_ptr) sp->transport[1]); + gnutls_transport_set_pull_function (sp->session, _tls_stream_pull); + gnutls_transport_set_push_function (sp->session, _tls_stream_push); return 0; } - + static int -_tls_open_client (mu_stream_t stream) +_tls_client_open (mu_stream_t stream) { - struct _tls_stream *s = mu_stream_get_owner (stream); + struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; int rc = 0; - switch (s->state) + switch (sp->state) { case state_closed: gnutls_certificate_free_credentials (x509_cred); - if (s->session) - gnutls_deinit (s->session); + if (sp->session) + gnutls_deinit (sp->session); /* FALLTHROUGH */ case state_init: - prepare_client_session (s); - rc = gnutls_handshake (s->session); + prepare_client_session (sp); + rc = gnutls_handshake (sp->session); if (rc < 0) { - s->last_err = rc; - gnutls_deinit (s->session); - s->state = state_init; + sp->tls_err = rc; + gnutls_deinit (sp->session); + sp->state = state_init; return MU_ERR_FAILURE; } break; @@ -557,133 +550,181 @@ _tls_open_client (mu_stream_t stream) } /* FIXME: if (ssl_cafile) verify_certificate (s->session); */ - s->state = state_open; + sp->state = state_open; return 0; } -int -_tls_strerror (mu_stream_t stream, const char **pstr) +static int +_tls_read (struct _mu_stream *str, char *buf, size_t bufsize, + size_t *pnread) { - struct _tls_stream *s = mu_stream_get_owner (stream); - *pstr = gnutls_strerror (s->last_err); - return 0; + struct _mu_tls_stream *sp = (struct _mu_tls_stream *)str; + return mu_stream_read (sp->transport[0], buf, bufsize, pnread); } -int -_tls_get_transport2 (mu_stream_t stream, - mu_transport_t *pin, mu_transport_t *pout) +static int +_tls_write (struct _mu_stream *str, const char *buf, size_t bufsize, + size_t *pnwrite) { - struct _tls_stream *s = mu_stream_get_owner (stream); - *pin = (mu_transport_t) s->strin; - *pout = (mu_transport_t) s->strout; - return 0; + struct _mu_tls_stream *sp = (struct _mu_tls_stream *)str; + return mu_stream_write (sp->transport[1], buf, bufsize, pnwrite); } -int -_tls_wait (mu_stream_t stream, int *pflags, struct timeval *tvp) +static int +_tls_ioctl (struct _mu_stream *stream, int op, void *arg) { - struct _tls_stream *s = mu_stream_get_owner (stream); - if ((*pflags & (MU_STREAM_READY_RD|MU_STREAM_READY_WR)) - == (MU_STREAM_READY_RD|MU_STREAM_READY_WR)) - return EINVAL; /* Sorry, can't wait for both input and output. */ - if (*pflags & MU_STREAM_READY_RD) - return mu_stream_wait (s->strin, pflags, tvp); - if (*pflags & MU_STREAM_READY_WR) - return mu_stream_wait (s->strout, pflags, tvp); - return EINVAL; -} + struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; + mu_transport_t *ptrans, trans[2]; -/* FIXME: if strin == strout sequential reads may intefere with - sequential writes (they would share stream->offset). This should - be fixed either in stream.c or here. In particular, - mu_tls_stream_create_client will malfunction */ -int -mu_tls_stream_create (mu_stream_t *stream, - mu_stream_t strin, mu_stream_t strout, int flags) -{ - struct _tls_stream *s; - int rc; + switch (op) + { + case MU_IOCTL_GET_TRANSPORT: + if (!arg) + return EINVAL; + ptrans = arg; + mu_stream_ioctl (sp->transport[0], MU_IOCTL_GET_TRANSPORT, trans); + ptrans[0] = trans[0]; + mu_stream_ioctl (sp->transport[1], MU_IOCTL_GET_TRANSPORT, trans); + ptrans[1] = trans[0]; + break; - if (stream == NULL) - return MU_ERR_OUT_PTR_NULL; + default: + return EINVAL; + } + return 0; +} - s = calloc (1, sizeof (*s)); - if (s == NULL) - return ENOMEM; +static int +_tls_wait (struct _mu_stream *stream, int *pflags, struct timeval *tvp) +{ + struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; + int rc = EINVAL; + + if (*pflags == MU_STREAM_READY_RD) + rc = mu_stream_wait (sp->transport[0], pflags, tvp); + else if (*pflags == MU_STREAM_READY_WR) + rc = mu_stream_wait (sp->transport[1], pflags, tvp); + return rc; +} - s->strin = strin; - s->strout = strout; +static int +_tls_flush (struct _mu_stream *stream) +{ + struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; + return mu_stream_flush (sp->transport[1]); +} - rc = mu_stream_create (stream, flags|MU_STREAM_NO_CHECK, s); - if (rc) +static int +_tls_close (mu_stream_t stream) +{ + struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; + + if (sp->session && sp->state == state_open) { - free (s); - return rc; + gnutls_bye (sp->session, GNUTLS_SHUT_RDWR); + sp->state = state_closed; } - - mu_stream_set_open (*stream, _tls_open, s); - mu_stream_set_close (*stream, _tls_close, s); - mu_stream_set_read (*stream, _tls_read, s); - mu_stream_set_readline (*stream, _tls_readline, s); - mu_stream_set_write (*stream, _tls_write, s); - mu_stream_set_flush (*stream, _tls_flush, s); - mu_stream_set_destroy (*stream, _tls_destroy, s); - mu_stream_set_strerror (*stream, _tls_strerror, s); - mu_stream_set_get_transport2 (*stream, _tls_get_transport2, s); - mu_stream_set_wait (*stream, _tls_wait, s); - _auth_lb_create (&s->lb); - s->state = state_init; + if (!(sp->stream.flags & MU_STREAM_NO_CLOSE)) + { + mu_stream_close (sp->transport[0]); + mu_stream_close (sp->transport[1]); + } return 0; } -int -mu_tls_stream_create_client (mu_stream_t *stream, - mu_stream_t strin, mu_stream_t strout, int flags) +static void +_tls_done (struct _mu_stream *stream) { - struct _tls_stream *s; - int rc; + struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; + + if (x509_cred) + gnutls_certificate_free_credentials (x509_cred); + if (sp->session && sp->state == state_closed) + { + gnutls_deinit (sp->session); + sp->state = state_destroyed; + } - if (stream == NULL) - return MU_ERR_OUT_PTR_NULL; + if (!(sp->stream.flags & MU_STREAM_NO_CLOSE)) + { + mu_stream_unref (sp->transport[0]); + mu_stream_unref (sp->transport[1]); + } +} - s = calloc (1, sizeof (*s)); - if (s == NULL) +static int +_mu_tls_stream_create (mu_stream_t *pstream, + int (*openfn) (mu_stream_t stream), + mu_stream_t strin, mu_stream_t strout, int flags) +{ + struct _mu_tls_stream *sp; + int noclose = flags & MU_STREAM_NO_CLOSE; + int rc; + + sp = (struct _mu_tls_stream *) + _mu_stream_create (sizeof (*sp), + MU_STREAM_RDWR | noclose); + if (!sp) return ENOMEM; - s->strin = strin; - s->strout = strout; - - rc = mu_stream_create (stream, flags|MU_STREAM_NO_CHECK, s); + sp->stream.read = _tls_read; + sp->stream.write = _tls_write; + sp->stream.flush = _tls_flush; + sp->stream.open = openfn; + sp->stream.close = _tls_close; + sp->stream.done = _tls_done; + sp->stream.ctl = _tls_ioctl; + sp->stream.wait = _tls_wait; + /* FIXME: + sp->stream.error_string = _tls_error_string;*/ + + if (!noclose && strin == strout) + mu_stream_ref (strin); + + mu_stream_set_buffer (strin, mu_buffer_none, 0); + mu_stream_set_buffer (strout, mu_buffer_none, 0); + rc = _mu_tls_io_stream_create (&sp->transport[0], strin, + MU_STREAM_READ | noclose, sp); if (rc) { - free (s); + free (sp); + return rc; + } + + rc = _mu_tls_io_stream_create (&sp->transport[1], strout, + MU_STREAM_WRITE | noclose, sp); + if (rc) + { + free (sp); + free (sp->transport[0]); return rc; } - - mu_stream_set_open (*stream, _tls_open_client, s); - mu_stream_set_close (*stream, _tls_close, s); - mu_stream_set_read (*stream, _tls_read, s); - mu_stream_set_readline (*stream, _tls_readline, s); - mu_stream_set_write (*stream, _tls_write, s); - mu_stream_set_flush (*stream, _tls_flush, s); - mu_stream_set_destroy (*stream, _tls_destroy, s); - mu_stream_set_strerror (*stream, _tls_strerror, s); - mu_stream_set_get_transport2 (*stream, _tls_get_transport2, s); - mu_stream_set_wait (*stream, _tls_wait, s); - _auth_lb_create (&s->lb); - s->state = state_init; + mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_line, 1024); + *pstream = (mu_stream_t) sp; return 0; } int -mu_tls_stream_create_client_from_tcp (mu_stream_t *stream, mu_stream_t tcp_str, - int flags) +mu_tls_server_stream_create (mu_stream_t *pstream, + mu_stream_t strin, mu_stream_t strout, int flags) +{ + return _mu_tls_stream_create (pstream, + _tls_server_open, + strin, strout, flags); +} + +int +mu_tls_client_stream_create (mu_stream_t *pstream, + mu_stream_t strin, mu_stream_t strout, int flags) { - return mu_tls_stream_create_client (stream, tcp_str, tcp_str, flags); + return _mu_tls_stream_create (pstream, + _tls_client_open, + strin, strout, flags); } + #endif /* WITH_TLS */ /* EOF */ diff --git a/libproto/imap/folder.c b/libproto/imap/folder.c index 77e791971..e974ced0a 100644 --- a/libproto/imap/folder.c +++ b/libproto/imap/folder.c @@ -688,10 +688,12 @@ folder_imap_open (mu_folder_t folder, int flags) CHECK_EAGAIN (f_imap, status); CHECK_ERROR_CLOSE (folder, f_imap, status); - status = mu_tls_stream_create_client_from_tcp (&newstr, folder->stream, 0); + status = mu_tls_client_stream_create (&newstr, + folder->stream, + folder->stream, 0); if (status != 0) { - mu_error ("folder_imap_open: mu_tls_stream_create_client_from_tcp: %s", + mu_error ("folder_imap_open: mu_tls_client_stream_create: %s", mu_strerror (status)); return status; } diff --git a/libproto/pop/mbox.c b/libproto/pop/mbox.c index a9e28d5bf..b9a21d682 100644 --- a/libproto/pop/mbox.c +++ b/libproto/pop/mbox.c @@ -824,8 +824,11 @@ pop_open (mu_mailbox_t mbox, int flags) /* Create the networking stack. */ if (mbox->stream == NULL) { - status = mu_tcp_stream_create (&mbox->stream, host, port, mbox->flags); + status = mu_tcp_stream_create (&mbox->stream, host, port, + mbox->flags); CHECK_ERROR (mpd, status); + /* FIXME: How to configure the buffer size? */ + mu_stream_set_buffer (mbox->stream, mu_buffer_line, 1024); #ifdef WITH_TLS if (mpd->pops) @@ -836,19 +839,18 @@ pop_open (mu_mailbox_t mbox, int flags) CHECK_EAGAIN (mpd, status); CHECK_ERROR_CLOSE (mbox, mpd, status); - status = mu_tls_stream_create_client_from_tcp (&newstr, mbox->stream, 0); + status = mu_tls_client_stream_create (&newstr, + mbox->stream, + mbox->stream, 0); if (status != 0) { - mu_error ("pop_open: mu_tls_stream_create_client_from_tcp: %s", + mu_error ("pop_open: mu_tls_client_stream_create: %s", mu_strerror (status)); return status; } mbox->stream = newstr; } #endif /* WITH_TLS */ - - /* Using the awkward mu_stream_t buffering. */ - mu_stream_setbufsiz (mbox->stream, BUFSIZ); } else { diff --git a/libproto/pop/pop3_stls.c b/libproto/pop/pop3_stls.c index b9984f66f..2c09222cc 100644 --- a/libproto/pop/pop3_stls.c +++ b/libproto/pop/pop3_stls.c @@ -66,7 +66,9 @@ mu_pop3_stls (mu_pop3_t pop3) MU_POP3_CHECK_EAGAIN (pop3, status); mu_pop3_debug_ack (pop3); MU_POP3_CHECK_OK (pop3); - status = mu_tls_stream_create_client_from_tcp (&tls_stream, pop3->carrier, 0); + status = mu_tls_client_stream_create (&tls_stream, + pop3->carrier, + pop3->carrier, 0); MU_POP3_CHECK_ERROR (pop3, status); pop3->carrier = tls_stream; pop3->state = MU_POP3_STLS_CONNECT; diff --git a/pop3d/capa.c b/pop3d/capa.c index ca58512e6..38d5fed12 100644 --- a/pop3d/capa.c +++ b/pop3d/capa.c @@ -32,9 +32,6 @@ pop3d_capa (char *arg) if (strlen (arg) != 0) return ERR_BAD_ARGS; - if (state != initial_state && state != TRANSACTION) - return ERR_WRONG_STATE; - pop3d_outf ("+OK Capability list follows\n"); pop3d_outf ("TOP\n"); pop3d_outf ("USER\n"); diff --git a/pop3d/extra.c b/pop3d/extra.c index ca5089e25..2ab0f8a96 100644 --- a/pop3d/extra.c +++ b/pop3d/extra.c @@ -126,6 +126,14 @@ pop3d_abquit (int reason) exit (code); } +/* Keeps the *real* output stream. Ostream is a RFC822 filter built over + real_ostream, or even over a TLS stream, which in turn is based on this + real_ostream. + FIXME: This is sorta kludge: we could use MU_IOCTL_GET_TRANSPORT call + to retrieve the bottom-level stream, if filter streams supported it. +*/ +static mu_stream_t real_ostream; + void pop3d_setio (FILE *in, FILE *out) { @@ -136,14 +144,17 @@ pop3d_setio (FILE *in, FILE *out) if (!out) pop3d_abquit (ERR_NO_OFILE); |